Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

题目

image-20250609204423916

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <stdlib.h>

/*
This is not the challenge, just a template to answer the questions.
To get the flag, answer the questions.
There is no bug in the questionnaire.
*/

void gg(){
system("cat flag.txt");
}

void vuln(){
char buffer[0x20] = {0};
fprintf(stdout, "\nEnter payload here: ");
fgets(buffer, 0x100, stdin);
}

void main(){
vuln();
}

这道题并不需要我们去exploit任何程序,只需要回答一些关于这个程序基础的问题。

第一题

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
This is a simple questionnaire to get started with the basics.

◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
◉ ◉
◉ When compiling C/C++ source code in Linux, an ELF (Executable and Linkable Format) file is created. ◉
◉ The flags added when compiling can affect the binary in various ways, like the protections. ◉
◉ Another thing affected can be the architecture and the way it's linked. ◉
◉ ◉
◉ If the system in which the challenge is compiled is x86_64 and no flag is specified, ◉
◉ the ELF would be x86-64 / 64-bit. If it's compiled with a flag to indicate the system, ◉
◉ it can be x86 / 32-bit binary. ◉
◉ ◉
◉ To reduce its size and make debugging more difficult, the binary can be stripped or not stripped. ◉
◉ ◉
◉ Dynamic linking: ◉
◉ ◉
◉ A pointer to the linked file is included in the executable, and the file contents are not included ◉
◉ at link time. These files are used when the program is run. ◉
◉ ◉
◉ Static linking: ◉
◉ ◉
◉ The code for all the routines called by your program becomes part of the executable file. ◉
◉ ◉
◉ Stripped: ◉
◉ ◉
◉ The binary does not contain debugging information. ◉
◉ ◉
◉ Not Stripped: ◉
◉ ◉
◉ The binary contains debugging information. ◉
◉ ◉
◉ The most common protections in a binary are: ◉
◉ ◉
◉ Canary: A random value that is generated, put on the stack, and checked before that function is ◉
◉ left again. If the canary value is not correct-has been changed or overwritten, the application will ◉
◉ immediately stop. ◉
◉ ◉
◉ NX: Stands for non-executable segments, meaning we cannot write and execute code on the stack. ◉
◉ ◉
◉ PIE: Stands for Position Independent Executable, which randomizes the base address of the binary ◉
◉ as it tells the loader which virtual address it should use. ◉
◉ ◉
◉ RelRO: Stands for Relocation Read-Only. The headers of the binary are marked as read-only. ◉
◉ ◉
◉ Run the 'file' command in the terminal and 'checksec' inside the debugger. ◉
◉ ◉
◉ The output of 'file' command: ◉
◉ ◉
◉ ✗ file test
test: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, ◉
◉ interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=5a83587fbda6ad7b1aeee2d59f027a882bf2a429, ◉
for GNU/Linux 3.2.0, not stripped. ◉
◉ ◉
◉ The output of 'checksec' command: ◉
◉ ◉
◉ gef➤ checksec ◉
◉ Canary : ✘ ◉
◉ NX : ✓ ◉
◉ PIE : ✘ ◉
◉ Fortify : ✘ ◉
◉ RelRO : Partial ◉
◉ ◉
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
1
2
3
4
5
6
7
8
9
10
11
[*] Question number 0x1:

Is this a '32-bit' or '64-bit' ELF? (e.g. 1337-bit)

>> 64-bit

♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠

可以直接用IDA打开程序并且查看Exports页面,根据地址的长度判断这个程序是32位的还是64位的。这里的是64位的程序。

image-20250609205844264

第二题

1
2
3
4
5
6
7
8
9
10
11
[*] Question number 0x2:

What's the linking of the binary? (e.g. static, dynamic)

>> dynamic

♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠

可以在linux里使用file命令:

1
2
└─$ file test
test: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=5a83587fbda6ad7b1aeee2d59f027a882bf2a429, for GNU/Linux 3.2.0, not stripped

可以看到是dynamic的。

dynamically linked(动态链接)是指一个程序在运行时才加载它所依赖的共享库(通常是 .so 文件,例如 libc.so.6)。这是现代 Linux 系统中最常用的链接方式。

第三题

1
2
3
4
5
6
7
8
9
10
11
[*] Question number 0x3:

Is the binary 'stripped' or 'not stripped'?

>> not stripped

♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠

stripped 是指在编译完成后,调试符号(函数名、变量名、段名等)被移除了。目的是让程序更小、更难逆向分析。

同样可以在这个结果里看到:

1
2
└─$ file test
test: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=5a83587fbda6ad7b1aeee2d59f027a882bf2a429, for GNU/Linux 3.2.0, not stripped

同样也可以用IDA来判断。用IDA打开程序后如果能看到类似于vuln()gg()类似原始的函数名,那么说明这个程序是not stripped 的。如果看到sub_400123func_4010a0之类的函数名,说明是 stripped的。

第四题

1
2
3
4
5
6
7
8
9
10
11
[*] Question number 0x4:

Which protections are enabled (Canary, NX, PIE, Fortify)?

>> NX

♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠

可以在一开始返回的这里看到:

image-20250609210746499

或者自己用checksec命令:

1
2
3
4
5
6
7
8
9
10
└─$ checksec test
[*] '/home/test'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
SHSTK: Enabled
IBT: Enabled
Stripped: No

第五题

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
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
◉ ◉
◉ Great job so far! Now it's time to see some C code and a binary file. ◉
◉ ◉
◉ In the pwn_questionnaire.zip there are two files: ◉
◉ ◉
◉ 1. test.c ◉
◉ 2. test ◉
◉ ◉
◉ The 'test.c' is the source code and 'test' is the output binary. ◉
◉ ◉
◉ Let's start by analyzing the code. ◉
◉ First of all, let's focus on the '#include <stdio.h>' line. ◉
◉ It includes the 'stdio.h' header file to use some of the standard functions like 'printf()'. ◉
◉ The same principle applies for the '#include <stdlib.h>' line, for other functions like 'system()'. ◉
◉ ◉
◉ Now, let's take a closer look at: ◉
◉ ◉
◉ void main(){ ◉
◉ vuln(); ◉
◉ } ◉
◉ ◉
◉ By default, a binary file starts executing from the 'main()' function. ◉
◉ ◉
◉ In this case, 'main()' only calls another function, 'vuln()'. ◉
◉ The function 'vuln()' has 3 lines. ◉
◉ ◉
◉ void vuln(){ ◉
◉ char buffer[0x20] = {0}; ◉
◉ fprintf(stdout, "\nEnter payload here: "); ◉
◉ fgets(buffer, 0x100, stdin); ◉
◉ } ◉
◉ ◉
◉ The first line declares a 0x20-byte buffer of characters and fills it with zeros. ◉
◉ The second line calls 'fprintf()' to print a message to stdout. ◉
◉ Finally, the third line calls 'fgets()' to read 0x100 bytes from stdin and store them to the ◉
◉ aformentioned buffer. ◉
◉ ◉
◉ Then, there is a custom 'gg()' function which calls the standard 'system()' function to print the ◉
◉ flag. This function is never called by default. ◉
◉ ◉
◉ void gg(){ ◉
◉ system("cat flag.txt"); ◉
◉ } ◉
◉ ◉
◉ Run the 'man <function_name>' command to see the manual page of a standard function (e.g. man fgets).◉
◉ ◉
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉

1
2
3
4
5
6
7
8
9
10
11
12

[*] Question number 0x5:

What is the name of the custom function the gets called inside `main()`? (e.g. vulnerable_function())

>> vuln()

♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠

第六题

1
2
3
4
5
6
7
8
9
10
11
[*] Question number 0x6:

What is the size of the 'buffer' (in hex or decimal)?

>> 0x20

♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠

在一开始给的c代码里就可以看到:

1
2
3
4
5
void vuln(){
char buffer[0x20] = {0};
fprintf(stdout, "\nEnter payload here: ");
fgets(buffer, 0x100, stdin);
}

也可以查看用IDA查看这个程序的Stack结构:

image-20250609211344306

点击变量s:

image-20250609211359282

__saved_registers前全都是buffer的内容,即长度为

1
0000000000000020 - 0000000000000000 = 0x20

第七题

1
2
3
4
5
[*] Question number 0x7:

Which custom function is never called? (e.g. vuln())

>> gg()

可以看到main()函数中没有直接调用gg()这个函数。

第八题

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
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
◉ ◉
◉ Excellent! Now it's time to talk about Buffer Overflows. ◉
◉ ◉
◉ Buffer Overflow means there is a buffer of characters, integers or any other type of variables, ◉
◉ and someone inserts into this buffer more bytes than it can store. ◉
◉ ◉
◉ If the user inserts more bytes than the buffer's size, they will be stored somewhere in the memory ◉
◉ after the address of the buffer, overwriting important addresses for the flow of the program. ◉
◉ This, in most cases, will make the program crash. ◉
◉ ◉
◉ When a function is called, the program knows where to return because of the 'return address'. If the ◉
◉ player overwrites this address, they can redirect the flow of the program wherever they want. ◉
◉ To print a function's address, run 'p <function_name>' inside 'gdb'. (e.g. p main) ◉
◉ ◉
◉ gef➤ p gg ◉
◉ $1 = {<text variable, no debug info>} 0x401176 <gg> ◉
◉ ◉
◉ To perform a Buffer Overflow in the simplest way, we take these things into consideration. ◉
◉ ◉
◉ 1. Canary is disabled so it won't quit after the canary address is overwritten. ◉
◉ 2. PIE is disabled so the addresses of the binary functions are not randomized and the user knows ◉
where to return after overwritting the return address. ◉
◉ 3. There is a buffer with N size. ◉
◉ 4. There is a function that reads to this buffer more than N bytes. ◉
◉ ◉
◉ Run printf 'A%.0s' {1..30} | ./test to enter 30*"A" into the program. ◉
◉ ◉
◉ Run the program manually with "./test" and insert 30*A, then 39, then 40 and see what happens. ◉
◉ ◉
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
1
2
3
4
5
6
7
8
9
10
11
[*] Question number 0x8:

What is the name of the standard function that could trigger a Buffer Overflow? (e.g. fprintf())

>> fgets()

♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠

第九题

1
2
3
4
5
6
7
8
9
10
11
12
13
[*] Question number 0x9:

Insert 30, then 39, then 40 'A's in the program and see the output.

After how many bytes a Segmentation Fault occurs (in hex or decimal)?

>> 40

♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠

image-20250609211359282

通过Stack的结构可以直接计算出来:

1
0x20 + 8 = 32 + 8 = 40

第十题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[*] Question number 0xa:

What is the address of 'gg()' in hex? (e.g. 0x401337)

>> 0x401176

♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠
♠ ♠
♠ Correct ♠
♠ ♠
♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠ ♠

Great job! It's high time you solved your first challenge! Here is the flag!

HTB{l34rn_th3_b451c5_b3f0r4_u_5t4rt}

在Export页面就可以直接查看了:

image-20250609205844264