Level1

您可以使用命令“start”来启动程序,并在“main”上设置断点。您可以使用命令“starti”来启动程序,并在“_start”上设置断点。您可以使用命令“run”来启动程序,而无需设置断点。您可以使用命令“attach ”附加到其他已在运行的程序。您可以使用命令“core ”来分析已运行程序的核心转储。

启动或运行程序时,您可以以几乎与在 shell 上完全相同的方式指定参数。
例如,您可以使用 start <ARGV1> <ARGV2> <ARGVN> < <STDIN_PATH>

使用命令 continue,或简称 c,以继续执行程序。

“Start”之后”C”继续执行得到flag

Level2

您可以使用“info registers”查看所有寄存器的值。或者,您也可以使用“print”命令(简称为“p”)打印特定寄存器的值。例如,“p $rdi”将以十进制打印 $rdi 的值。您还可以使用“p/x $rdi”以十六进制打印其值。

为了解决这一关,您必须找出寄存器 r12 的当前十六进制随机值。

(gdb) p/x $r12
$3 = 0xc010c792e1fd71af
(gdb) c
Continuing.
Random value: 0xc010c792e1fd71af
You input: c010c792e1fd71af
The correct answer is: c010c792e1fd71af

Level3

您可以使用 x/<n><u><f> <address> 参数化命令检查内存的内容。在此格式中,<u> 是要显示的单元大小,<f> 是显示格式,<n> 是要显示的元素数。有效的单元大小为 b(1 字节)、h(2 字节)、w(4 字节)和 g(8 字节)。有效格式为 d(十进制)、x(十六进制)、s(字符串)和 i(指令)。可以使用寄存器名称、符号名称或绝对地址指定地址。此外,您还可以在指定地址时提供数学表达式。

例如,x/8i $rip 将从当前指令指针打印接下来的 8 条指令。x/16i main 将打印 main 的前 16 条指令。您还可以使用 disassemble main(简称 disas main)来打印 main 的所有
指令。或者,x/16gx $rsp 将打印堆栈上的前 16 个值。x/gx $rbp-0x32
将打印存储在堆栈上的局部变量。

您可能希望使用正确的汇编语法查看您的指令。您可以使用命令
set disassembly-flavor intel 来执行此操作。

为了解决这个级别,您必须找出堆栈上的随机值(从 /dev/urandom 读入的值)。
考虑一下 read 系统调用的参数是什么。

设置成intel语法之后

disass main,找到调用read的地方

   0x000058c8e2ddec52 <+428>:	call   0x58c8e2dde210 <read@plt>
0x000058c8e2ddec57 <+433>: lea rdi,[rip+0xbc2] # 0x58c8e2ddf820
0x000058c8e2ddec5e <+440>: call 0x58c8e2dde190 <puts@plt>
0x000058c8e2ddec63 <+445>: int3
0x000058c8e2ddec64 <+446>: nop
0x000058c8e2ddec65 <+447>: lea rdi,[rip+0xbd4] # 0x58c8e2ddf840
0x000058c8e2ddec6c <+454>: mov eax,0x0
0x000058c8e2ddec71 <+459>: call 0x58c8e2dde1d0 <printf@plt>
0x000058c8e2ddec76 <+464>: lea rax,[rbp-0x10]
0x000058c8e2ddec7a <+468>: mov rsi,rax
0x000058c8e2ddec7d <+471>: lea rdi,[rip+0xbcb] # 0x58c8e2ddf84f
0x000058c8e2ddec84 <+478>: mov eax,0x0
0x000058c8e2ddec89 <+483>: call 0x58c8e2dde260 <__isoc99_scanf@plt>
0x000058c8e2ddec8e <+488>: mov rax,QWORD PTR [rbp-0x10]
0x000058c8e2ddec92 <+492>: mov rsi,rax
0x000058c8e2ddec95 <+495>: lea rdi,[rip+0xbb8] # 0x58c8e2ddf854
0x000058c8e2ddec9c <+502>: mov eax,0x0
0x000058c8e2ddeca1 <+507>: call 0x58c8e2dde1d0 <printf@plt>
0x000058c8e2ddeca6 <+512>: mov rax,QWORD PTR [rbp-0x18]
0x000058c8e2ddecaa <+516>: mov rsi,rax
--Type <RET> for more, q to quit, c to continue without paging--
0x000058c8e2ddecad <+519>: lea rdi,[rip+0xbb1] # 0x58c8e2ddf865
0x000058c8e2ddecb4 <+526>: mov eax,0x0
0x000058c8e2ddecb9 <+531>: call 0x58c8e2dde1d0 <printf@plt>
0x000058c8e2ddecbe <+536>: mov rdx,QWORD PTR [rbp-0x10]
0x000058c8e2ddecc2 <+540>: mov rax,QWORD PTR [rbp-0x18]
0x000058c8e2ddecc6 <+544>: cmp rdx,rax
0x000058c8e2ddecc9 <+547>: je 0x58c8e2ddecd5 <main+559>
0x000058c8e2ddeccb <+549>: mov edi,0x1
0x000058c8e2ddecd0 <+554>: call 0x58c8e2dde280 <exit@plt>
0x000058c8e2ddecd5 <+559>: add DWORD PTR [rbp-0x1c],0x1
0x000058c8e2ddecd9 <+563>: cmp DWORD PTR [rbp-0x1c],0x0
0x000058c8e2ddecdd <+567>: jle 0x58c8e2ddec2c <main+390>
0x000058c8e2ddece3 <+573>: mov eax,0x0
0x000058c8e2ddece8 <+578>: call 0x58c8e2dde97d <win>

前面调用了read,put等一众操作,到后面有一个scanf,猜测就是让我们输入的地方,之后会对rdx和rax进行比较,如果相等,则回到main,rbp-0x10是我们输入的值的地址,那么0x18就是所进行比较的值

x/gx $rbp-0x18 即可读取随机数

Level4

动态分析的一个关键部分是让您的程序进入您想要分析的状态。到目前为止,这些挑战已经自动为您设置了断点,以便在您可能想要分析的状态暂停执行。能够自己做到这一点很重要。有很多方法可以推进程序的执行。您可以使用stepi <n>命令,或简称si <n>,以便向前推进一条指令。您可以使用nexti <n>命令,或简称ni <n>,以便向前推进一条指令,同时跳过任何函数调用。<n>参数是可选的,但允许您一次执行多个步骤。您可以使用finish命令来完成当前正在执行的函数。您可以使用break *<address>参数化命令在指定地址设置断点。您已经使用了 continue 命令,该命令将继续执行,直到程序遇到
断点。

在单步执行程序时,您可能会发现始终显示一些值很有用。有多种方法可以做到这一点。最简单的方法是使用 display/<n><u><f> 参数化命令,其格式与 x/<n><u><f> 参数化命令完全相同。例如,display/8i $rip 将始终向您显示接下来的 8 条指令。另一方面,display/4gx $rsp 将始终向您显示堆栈上的前 4 个值。
另一个选项是使用 layout regs 命令。这将使 gdb 进入其 TUI 模式并向您显示所有寄存器的内容以及附近的指令。

为了解决这个级别,您必须找出一系列将放置在堆栈上的随机值。强烈建议您尝试使用 stepinextibreakcontinuefinish 的组合,以确保您对这些命令有很好的内部理解。这些命令对于导航程序的执行都至关重要。

反汇编一下main函数

   0x00005cc656376c91 <+491>:	call   0x5cc656376250 <open@plt>
0x00005cc656376c96 <+496>: mov ecx,eax
0x00005cc656376c98 <+498>: lea rax,[rbp-0x18]
0x00005cc656376c9c <+502>: mov edx,0x8
0x00005cc656376ca1 <+507>: mov rsi,rax
0x00005cc656376ca4 <+510>: mov edi,ecx
0x00005cc656376ca6 <+512>: call 0x5cc656376210 <read@plt>
0x00005cc656376cab <+517>: lea rdi,[rip+0xe26] # 0x5cc656377ad8
0x00005cc656376cb2 <+524>: call 0x5cc656376190 <puts@plt>
0x00005cc656376cb7 <+529>: lea rdi,[rip+0xe3a] # 0x5cc656377af8
0x00005cc656376cbe <+536>: mov eax,0x0
0x00005cc656376cc3 <+541>: call 0x5cc6563761d0 <printf@plt>
--Type <RET> for more, q to quit, c to continue without paging--
0x00005cc656376cc8 <+546>: lea rax,[rbp-0x10]
0x00005cc656376ccc <+550>: mov rsi,rax
0x00005cc656376ccf <+553>: lea rdi,[rip+0xe31] # 0x5cc656377b07
0x00005cc656376cd6 <+560>: mov eax,0x0
0x00005cc656376cdb <+565>: call 0x5cc656376260 <__isoc99_scanf@plt>
0x00005cc656376ce0 <+570>: mov rax,QWORD PTR [rbp-0x10]
0x00005cc656376ce4 <+574>: mov rsi,rax
0x00005cc656376ce7 <+577>: lea rdi,[rip+0xe1e] # 0x5cc656377b0c
0x00005cc656376cee <+584>: mov eax,0x0
0x00005cc656376cf3 <+589>: call 0x5cc6563761d0 <printf@plt>
0x00005cc656376cf8 <+594>: mov rax,QWORD PTR [rbp-0x18]
0x00005cc656376cfc <+598>: mov rsi,rax
0x00005cc656376cff <+601>: lea rdi,[rip+0xe17] # 0x5cc656377b1d
0x00005cc656376d06 <+608>: mov eax,0x0
0x00005cc656376d0b <+613>: call 0x5cc6563761d0 <printf@plt>
0x00005cc656376d10 <+618>: mov rdx,QWORD PTR [rbp-0x10]
0x00005cc656376d14 <+622>: mov rax,QWORD PTR [rbp-0x18]
0x00005cc656376d18 <+626>: cmp rdx,rax
0x00005cc656376d1b <+629>: je 0x5cc656376d27 <main+641>
0x00005cc656376d1d <+631>: mov edi,0x1
0x00005cc656376d22 <+636>: call 0x5cc656376280 <exit@plt>
0x00005cc656376d27 <+641>: add DWORD PTR [rbp-0x1c],0x1
0x00005cc656376d2b <+645>: cmp DWORD PTR [rbp-0x1c],0x3
0x00005cc656376d2f <+649>: jle 0x5cc656376c80 <main+474>
0x00005cc656376d35 <+655>: mov eax,0x0
0x00005cc656376d3a <+660>: call 0x5cc65637697d <win>
0x00005cc656376d3f <+665>: mov eax,0x0
0x00005cc656376d44 <+670>: mov rcx,QWORD PTR [rbp-0x8]
0x00005cc656376d48 <+674>: xor rcx,QWORD PTR fs:0x28
0x00005cc656376d51 <+683>: je 0x5cc656376d58 <main+690>
0x00005cc656376d53 <+685>: call 0x5cc6563761c0 <__stack_chk_fail@plt>
0x00005cc656376d58 <+690>: leave

也是从open读入一个值,然后在+626的地方进行一个比较,相等的话会跳转到+641,然后将rbp-0x1c加+1操作,然后将这个值与立即数3进行比较,如果相等,就胜利。那么实际上就是上一问做3次,但是这次需要自己打断点,然后开启显示寄存器

把断点打在*main+517即可

(gdb) break *main+517
Breakpoint 2 at 0x56fd47d25cab
(gdb) display/gx $rbp-0x18
1: x/xg $rbp-0x18 0x7fff61935408: 0x000056fd47d252a0
(gdb) c
Continuing.

Breakpoint 2, 0x000056fd47d25cab in main ()
1: x/xg $rbp-0x18 0x7fff61935408: 0x605ca109adea03e1
(gdb) c
Continuing.
The random value has been set!

Random value: 0x605ca109adea03e1
You input: 605ca109adea03e1
The correct answer is: 605ca109adea03e1

Breakpoint 2, 0x000056fd47d25cab in main ()
1: x/xg $rbp-0x18 0x7fff61935408: 0x573a3fb67e992595
(gdb) c
Continuing.
The random value has been set!

Random value: 0x573a3fb67e992595
You input: 573a3fb67e992595
The correct answer is: 573a3fb67e992595

Breakpoint 2, 0x000056fd47d25cab in main ()
1: x/xg $rbp-0x18 0x7fff61935408: 0xf46c781569d3ff45
(gdb) c
Continuing.
The random value has been set!

Random value: 0xf46c781569d3ff45
You input: f46c781569d3ff45
The correct answer is: f46c781569d3ff45

Breakpoint 2, 0x000056fd47d25cab in main ()
1: x/xg $rbp-0x18 0x7fff61935408: 0x0f1f943fa43faaa4
(gdb) c
Continuing.
The random value has been set!

Random value: 0x0f1f943fa43faaa4
You input: f1f943fa43faaa4
The correct answer is: f1f943fa43faaa4
You win! Here is your flag:

Level5

我们编写代码是为了表达一个可以重现和改进的想法。我们可以将我们的分析视为一个程序,它将要分析的目标作为数据注入。俗话说,代码就是数据,数据就是代码。

虽然像我们在之前的级别中所做的那样以交互方式使用 gdb 非常强大,但另一个强大的工具是 gdb 脚本。通过编写 gdb 脚本,您可以非常快速地创建一个定制的程序分析工具。如果您知道如何与 gdb 交互,那么您已经知道如何编写 gdb 脚本 - 语法完全相同。您可以将命令写入某个文件,例如 x.gdb,然后使用标志 -x <PATH_TO_SCRIPT> 启动 gdb。该文件将在 gdb 启动后执行所有 gdb 命令。或者,您可以使用 -ex '<COMMAND>' 执行单个命令。您可以使用多个 -ex 参数传递多个命令。最后,通过将某些命令放入 ~/.gdbinit,您可以让它们始终在任何 gdb 会话中执行。您可能希望在其中放入 set disassembly-flavor intel

在 gdb 脚本中,断点命令是一个非常强大的构造。考虑以下 gdb 脚本:

start
break *main+42
commands
x/gx $rbp-0x32
continue
end
continue

在这种情况下,每当我们命中 main+42 处的指令时,我们都会输出特定的局部变量,然后继续执行。

现在考虑一个类似但稍微高级一些的脚本,它使用了一些您还没有见过的命令:

start
break *main+42
commands
silent
set $local_variable = *(unsigned long long*)($rbp-0x32)
printf "Current value: %llx\n", $local_variable
continue
end
continue

在这种情况下,silent 表示我们希望 gdb 不报告我们已到达断点,以使输出更清晰一些。然后我们使用 set 命令在 gdb 会话中定义一个变量,其值是我们的本地变量。最后,我们使用格式化的字符串输出当前值。

使用 gdb 脚本来帮助您收集随机值。

查看一下main中最后的逻辑,变成了要输入七次了

   0x00006141ba297d51 <+683>:	call   0x6141ba297250 <open@plt>
0x00006141ba297d56 <+688>: mov ecx,eax
0x00006141ba297d58 <+690>: lea rax,[rbp-0x18]
0x00006141ba297d5c <+694>: mov edx,0x8
0x00006141ba297d61 <+699>: mov rsi,rax
0x00006141ba297d64 <+702>: mov edi,ecx
0x00006141ba297d66 <+704>: call 0x6141ba297210 <read@plt>
--Type <RET> for more, q to quit, c to continue without paging--
0x00006141ba297d6b <+709>: lea rdi,[rip+0xd46] # 0x6141ba298ab8
0x00006141ba297d72 <+716>: call 0x6141ba297190 <puts@plt>
0x00006141ba297d77 <+721>: lea rdi,[rip+0xd5a] # 0x6141ba298ad8
0x00006141ba297d7e <+728>: mov eax,0x0
0x00006141ba297d83 <+733>: call 0x6141ba2971d0 <printf@plt>
0x00006141ba297d88 <+738>: lea rax,[rbp-0x10]
0x00006141ba297d8c <+742>: mov rsi,rax
0x00006141ba297d8f <+745>: lea rdi,[rip+0xd51] # 0x6141ba298ae7
0x00006141ba297d96 <+752>: mov eax,0x0
0x00006141ba297d9b <+757>: call 0x6141ba297260 <__isoc99_scanf@plt>
0x00006141ba297da0 <+762>: mov rax,QWORD PTR [rbp-0x10]
0x00006141ba297da4 <+766>: mov rsi,rax
0x00006141ba297da7 <+769>: lea rdi,[rip+0xd3e] # 0x6141ba298aec
0x00006141ba297dae <+776>: mov eax,0x0
0x00006141ba297db3 <+781>: call 0x6141ba2971d0 <printf@plt>
0x00006141ba297db8 <+786>: mov rax,QWORD PTR [rbp-0x18]
0x00006141ba297dbc <+790>: mov rsi,rax
0x00006141ba297dbf <+793>: lea rdi,[rip+0xd37] # 0x6141ba298afd
0x00006141ba297dc6 <+800>: mov eax,0x0
0x00006141ba297dcb <+805>: call 0x6141ba2971d0 <printf@plt>
0x00006141ba297dd0 <+810>: mov rdx,QWORD PTR [rbp-0x10]
0x00006141ba297dd4 <+814>: mov rax,QWORD PTR [rbp-0x18]
0x00006141ba297dd8 <+818>: cmp rdx,rax
0x00006141ba297ddb <+821>: je 0x6141ba297de7 <main+833>
0x00006141ba297ddd <+823>: mov edi,0x1
0x00006141ba297de2 <+828>: call 0x6141ba297280 <exit@plt>
0x00006141ba297de7 <+833>: add DWORD PTR [rbp-0x1c],0x1
0x00006141ba297deb <+837>: cmp DWORD PTR [rbp-0x1c],0x7
0x00006141ba297def <+841>: jle 0x6141ba297d40 <main+666>
0x00006141ba297df5 <+847>: mov eax,0x0
0x00006141ba297dfa <+852>: call 0x6141ba29797d <win>

可以利用脚本自动执行,创建一个.gdb脚本,然后/challenge/run -x xxx.gdb

更改每次所输入的值比较的值

start
break *main+709
continue
commands
silent
set $local_variable = *(unsigned long long*)($rbp-0x18)
printf "Current value: %llx\n", $local_variable
continue
end
break *main+818
commands
silent
set $rax=0x1337
set $rdx=0x1337
continue
end
hacker@debugging-refresher~level5:~$ /challenge/embryogdb_level5 -x 1.gdb 
The program is restarting under the control of gdb! You can run the program with the gdb command `run`.
<SNIP>
Program received signal SIGTRAP, Trace/breakpoint trap.
0x0000635360bf8d33 in main ()
Breakpoint 3 at 0x635360bf8dd8
(gdb) c
Continuing.
Current value: 508c388b1aff7326
The random value has been set!

Random value: 2111
You input: 2111
The correct answer is: 508c388b1aff7326
Current value: efef614dbb815960
The random value has been set!

Random value: 12312
You input: 12312
The correct answer is: efef614dbb815960
Current value: 21786a602bfda133
The random value has been set!

Random value: 123123
You input: 123123
The correct answer is: 21786a602bfda133
Current value: d1f06da233f8ac69
The random value has been set!

Random value: 123123
You input: 123123
The correct answer is: d1f06da233f8ac69
Current value: 1b8fc5845ee47d3c
The random value has been set!

Random value: 123123
You input: 123123
The correct answer is: 1b8fc5845ee47d3c
Current value: bbab992baadca1ce
The random value has been set!

Random value: 123123
You input: 123123
The correct answer is: bbab992baadca1ce
Current value: 3a7681b2f1145cdb
The random value has been set!

Random value: 123123
You input: 123123
The correct answer is: 3a7681b2f1145cdb
Current value: a5de005cd313be7f
The random value has been set!

Random value: 12312312
You input: 12312312
The correct answer is: a5de005cd313be7f
You win! Here is your flag:

Level6

事实证明,gdb 可以完全控制目标进程。您不仅可以分析程序的状态,还可以修改它。虽然 gdb 可能不是对程序进行长期维护的最佳工具,但有时快速修改目标进程的行为以便更轻松地对其进行分析会很有用。

您可以使用 set 命令修改目标程序的状态。例如,您可以使用 set $rdi = 0 将 $rdi 清零。您可以使用 set *((uint64_t *) $rsp) = 0x1234 将堆栈上的第一个值设置为 0x1234。您可以使用set *((uint16_t *) 0x31337000) = 0x1337 将 0x31337000 处的 2 个字节设置为 0x1337。

假设您的目标是某个联网应用程序,它从 fd 42 上的某个套接字读取数据。如果目标改为从 stdin 读取数据,那么对于您的分析来说,可能更容易。您可以使用以下 gdb 脚本实现类似的功能:

start
catch syscall read
commands
silent
if ($rdi == 42)
set $rdi = 0
end
continue
end
continue

此示例 gdb 脚本演示了如何在系统调用时自动中断,以及如何在命令中使用条件来有条件地执行 gdb 命令。

在上一关中,您的 gdb 脚本解决方案可能仍需要您复制和粘贴解决方案。这次,尝试编写一个不需要您与程序对话的脚本,而是通过正确修改寄存器/内存来自动解决每个挑战。

   0x000060485d95accd <+551>:	call   0x60485d95a250 <open@plt>
0x000060485d95acd2 <+556>: mov ecx,eax
--Type <RET> for more, q to quit, c to continue without paging--
0x000060485d95acd4 <+558>: lea rax,[rbp-0x18]
0x000060485d95acd8 <+562>: mov edx,0x8
0x000060485d95acdd <+567>: mov rsi,rax
0x000060485d95ace0 <+570>: mov edi,ecx
0x000060485d95ace2 <+572>: call 0x60485d95a210 <read@plt>
0x000060485d95ace7 <+577>: lea rdi,[rip+0xbf2] # 0x60485d95b8e0
0x000060485d95acee <+584>: call 0x60485d95a190 <puts@plt>
0x000060485d95acf3 <+589>: lea rdi,[rip+0xc06] # 0x60485d95b900
0x000060485d95acfa <+596>: mov eax,0x0
0x000060485d95acff <+601>: call 0x60485d95a1d0 <printf@plt>
0x000060485d95ad04 <+606>: lea rax,[rbp-0x10]
0x000060485d95ad08 <+610>: mov rsi,rax
0x000060485d95ad0b <+613>: lea rdi,[rip+0xbfd] # 0x60485d95b90f
0x000060485d95ad12 <+620>: mov eax,0x0
0x000060485d95ad17 <+625>: call 0x60485d95a260 <__isoc99_scanf@plt>
0x000060485d95ad1c <+630>: mov rax,QWORD PTR [rbp-0x10]
0x000060485d95ad20 <+634>: mov rsi,rax
0x000060485d95ad23 <+637>: lea rdi,[rip+0xbea] # 0x60485d95b914
0x000060485d95ad2a <+644>: mov eax,0x0
0x000060485d95ad2f <+649>: call 0x60485d95a1d0 <printf@plt>
0x000060485d95ad34 <+654>: mov rax,QWORD PTR [rbp-0x18]
0x000060485d95ad38 <+658>: mov rsi,rax
0x000060485d95ad3b <+661>: lea rdi,[rip+0xbe3] # 0x60485d95b925
0x000060485d95ad42 <+668>: mov eax,0x0
0x000060485d95ad47 <+673>: call 0x60485d95a1d0 <printf@plt>
0x000060485d95ad4c <+678>: mov rdx,QWORD PTR [rbp-0x10]
0x000060485d95ad50 <+682>: mov rax,QWORD PTR [rbp-0x18]
0x000060485d95ad54 <+686>: cmp rdx,rax
0x000060485d95ad57 <+689>: je 0x60485d95ad63 <main+701>
0x000060485d95ad59 <+691>: mov edi,0x1
0x000060485d95ad5e <+696>: call 0x60485d95a280 <exit@plt>
0x000060485d95ad63 <+701>: add DWORD PTR [rbp-0x1c],0x1
0x000060485d95ad67 <+705>: cmp DWORD PTR [rbp-0x1c],0x3f
0x000060485d95ad6b <+709>: jle 0x60485d95acbc <main+534>
0x000060485d95ad71 <+715>: mov eax,0x0
--Type <RET> for more, q to quit, c to continue without paging--
0x000060485d95ad76 <+720>: call 0x60485d95a97d <win>

这次直接改最终的比较

start
break *main+705
commands
silent
set *(int*)($rbp-0x1c) = 100
continue
end
hacker@debugging-refresher~level6:~$ /challenge/embryogdb_level6 -x 1.gdb 
<SNIP>
Program received signal SIGTRAP, Trace/breakpoint trap.
0x000057576ff81caf in main ()
(gdb) c
Continuing.
You win! Here is your flag:

Level7

正如我们在上一个级别中演示的那样,gdb 可以完全控制目标进程。在正常情况下,以普通用户身份运行的 gdb 无法附加到特权进程。这就是为什么 gdb 不是一个可以让你立即解决所有级别的大规模安全问题的原因。尽管如此,gdb 仍然是一个非常强大的工具。

在这个提升的 gdb 实例中运行可以让你提升对整个系统的控制。为了清楚地演示这一点,看看当你运行命令 call (void)win() 时会发生什么。事实证明,这个模块中的所有级别都可以通过这种方式解决。

直接调用win函数即可过关

(gdb) call (void)win()
You win! Here is your flag:

Level8

正如我们在上一关中所演示的,gdb 可以完全控制目标进程。在正常情况下,以普通用户身份运行的 gdb 无法附加到特权进程。这就是为什么 gdb 不是一个大的安全问题,它允许您立即解决所有级别。尽管如此,gdb 仍然是一个非常强大的工具。

在这个提升的 gdb 实例中运行可以让您提升对整个系统的控制。为了清楚地演示这一点,看看当您运行命令“call (void)win()”时会发生什么。

请注意,这不会让您获得标志(似乎我们破坏了 win 函数!),因此您需要更加努力才能获得这个标志!

事实证明,模块中的所有其他级别都可以通过这种方式解决。

win函数被和删掉了,看一下main函数

   0x000062bcb19f1a75 <+0>:	endbr64 
0x000062bcb19f1a79 <+4>: push rbp
0x000062bcb19f1a7a <+5>: mov rbp,rsp
0x000062bcb19f1a7d <+8>: sub rsp,0x30
0x000062bcb19f1a81 <+12>: mov DWORD PTR [rbp-0x14],edi
0x000062bcb19f1a84 <+15>: mov QWORD PTR [rbp-0x20],rsi
0x000062bcb19f1a88 <+19>: mov QWORD PTR [rbp-0x28],rdx
0x000062bcb19f1a8c <+23>: mov rax,QWORD PTR fs:0x28
0x000062bcb19f1a95 <+32>: mov QWORD PTR [rbp-0x8],rax
0x000062bcb19f1a99 <+36>: xor eax,eax
0x000062bcb19f1a9b <+38>: mov rax,QWORD PTR [rip+0x258e] # 0x62bcb19f4030 <stdin@@GLIBC_2.2.5>
0x000062bcb19f1aa2 <+45>: mov ecx,0x0
0x000062bcb19f1aa7 <+50>: mov edx,0x2
0x000062bcb19f1aac <+55>: mov esi,0x0
0x000062bcb19f1ab1 <+60>: mov rdi,rax
0x000062bcb19f1ab4 <+63>: call 0x62bcb19f1230 <setvbuf@plt>
0x000062bcb19f1ab9 <+68>: mov rax,QWORD PTR [rip+0x2560] # 0x62bcb19f4020 <stdout@@GLIBC_2.2.5>
0x000062bcb19f1ac0 <+75>: mov ecx,0x0
0x000062bcb19f1ac5 <+80>: mov edx,0x2
0x000062bcb19f1aca <+85>: mov esi,0x0
0x000062bcb19f1acf <+90>: mov rdi,rax
0x000062bcb19f1ad2 <+93>: call 0x62bcb19f1230 <setvbuf@plt>
0x000062bcb19f1ad7 <+98>: lea rdi,[rip+0x6de] # 0x62bcb19f21bc
0x000062bcb19f1ade <+105>: call 0x62bcb19f1180 <puts@plt>
0x000062bcb19f1ae3 <+110>: mov rax,QWORD PTR [rbp-0x20]
0x000062bcb19f1ae7 <+114>: mov rax,QWORD PTR [rax]
0x000062bcb19f1aea <+117>: mov rsi,rax
0x000062bcb19f1aed <+120>: lea rdi,[rip+0x6cc] # 0x62bcb19f21c0
0x000062bcb19f1af4 <+127>: mov eax,0x0
0x000062bcb19f1af9 <+132>: call 0x62bcb19f11c0 <printf@plt>
0x000062bcb19f1afe <+137>: lea rdi,[rip+0x6b7] # 0x62bcb19f21bc
0x000062bcb19f1b05 <+144>: call 0x62bcb19f1180 <puts@plt>
0x000062bcb19f1b0a <+149>: mov edi,0xa
0x000062bcb19f1b0f <+154>: call 0x62bcb19f1160 <putchar@plt>
--Type <RET> for more, q to quit, c to continue without paging--
0x000062bcb19f1b14 <+159>: lea rdi,[rip+0x6bd] # 0x62bcb19f21d8
0x000062bcb19f1b1b <+166>: call 0x62bcb19f1180 <puts@plt>
0x000062bcb19f1b20 <+171>: lea rdi,[rip+0x729] # 0x62bcb19f2250
0x000062bcb19f1b27 <+178>: call 0x62bcb19f1180 <puts@plt>
0x000062bcb19f1b2c <+183>: lea rdi,[rip+0x77d] # 0x62bcb19f22b0
0x000062bcb19f1b33 <+190>: call 0x62bcb19f1180 <puts@plt>
0x000062bcb19f1b38 <+195>: lea rdi,[rip+0x7e9] # 0x62bcb19f2328
0x000062bcb19f1b3f <+202>: call 0x62bcb19f1180 <puts@plt>
0x000062bcb19f1b44 <+207>: lea rdi,[rip+0x85d] # 0x62bcb19f23a8
0x000062bcb19f1b4b <+214>: call 0x62bcb19f1180 <puts@plt>
0x000062bcb19f1b50 <+219>: lea rdi,[rip+0x8c9] # 0x62bcb19f2420
0x000062bcb19f1b57 <+226>: call 0x62bcb19f1180 <puts@plt>
0x000062bcb19f1b5c <+231>: lea rdi,[rip+0x935] # 0x62bcb19f2498
0x000062bcb19f1b63 <+238>: call 0x62bcb19f1180 <puts@plt>
0x000062bcb19f1b68 <+243>: lea rdi,[rip+0x971] # 0x62bcb19f24e0
0x000062bcb19f1b6f <+250>: call 0x62bcb19f1180 <puts@plt>
0x000062bcb19f1b74 <+255>: lea rdi,[rip+0x9d9] # 0x62bcb19f2554
0x000062bcb19f1b7b <+262>: call 0x62bcb19f1180 <puts@plt>
0x000062bcb19f1b80 <+267>: lea rdi,[rip+0x9e9] # 0x62bcb19f2570
0x000062bcb19f1b87 <+274>: call 0x62bcb19f1180 <puts@plt>
0x000062bcb19f1b8c <+279>: lea rdi,[rip+0xa35] # 0x62bcb19f25c8
0x000062bcb19f1b93 <+286>: call 0x62bcb19f1180 <puts@plt>
0x000062bcb19f1b98 <+291>: int3
=> 0x000062bcb19f1b99 <+292>: nop
0x000062bcb19f1b9a <+293>: mov edi,0x2a
0x000062bcb19f1b9f <+298>: call 0x62bcb19f1260 <exit@plt>

然而里面并没有与win函数相关的

win函数

   0x0000000000001951 <+0>:	endbr64 
0x0000000000001955 <+4>: push rbp
0x0000000000001956 <+5>: mov rbp,rsp
0x0000000000001959 <+8>: sub rsp,0x10
0x000000000000195d <+12>: mov QWORD PTR [rbp-0x8],0x0
0x0000000000001965 <+20>: mov rax,QWORD PTR [rbp-0x8]
0x0000000000001969 <+24>: mov eax,DWORD PTR [rax]
0x000000000000196b <+26>: lea edx,[rax+0x1]
0x000000000000196e <+29>: mov rax,QWORD PTR [rbp-0x8]
0x0000000000001972 <+33>: mov DWORD PTR [rax],edx
0x0000000000001974 <+35>: lea rdi,[rip+0x73e] # 0x20b9
0x000000000000197b <+42>: call 0x1180 <puts@plt>
0x0000000000001980 <+47>: mov esi,0x0
0x0000000000001985 <+52>: lea rdi,[rip+0x749] # 0x20d5
0x000000000000198c <+59>: mov eax,0x0
0x0000000000001991 <+64>: call 0x1240 <open@plt>
0x0000000000001996 <+69>: mov DWORD PTR [rip+0x26a4],eax # 0x4040 <flag_fd.5712>
0x000000000000199c <+75>: mov eax,DWORD PTR [rip+0x269e] # 0x4040 <flag_fd.5712>
0x00000000000019a2 <+81>: test eax,eax
0x00000000000019a4 <+83>: jns 0x19ef <win+158>
0x00000000000019a6 <+85>: call 0x1170 <__errno_location@plt>
0x00000000000019ab <+90>: mov eax,DWORD PTR [rax]
0x00000000000019ad <+92>: mov edi,eax
0x00000000000019af <+94>: call 0x1270 <strerror@plt>
0x00000000000019b4 <+99>: mov rsi,rax
0x00000000000019b7 <+102>: lea rdi,[rip+0x722] # 0x20e0
0x00000000000019be <+109>: mov eax,0x0
0x00000000000019c3 <+114>: call 0x11c0 <printf@plt>
0x00000000000019c8 <+119>: call 0x11f0 <geteuid@plt>
0x00000000000019cd <+124>: test eax,eax
0x00000000000019cf <+126>: je 0x1a66 <win+277>
0x00000000000019d5 <+132>: lea rdi,[rip+0x734] # 0x2110
--Type <RET> for more, q to quit, c to continue without paging--
0x00000000000019dc <+139>: call 0x1180 <puts@plt>
0x00000000000019e1 <+144>: lea rdi,[rip+0x750] # 0x2138
0x00000000000019e8 <+151>: call 0x1180 <puts@plt>
0x00000000000019ed <+156>: jmp 0x1a66 <win+277>
0x00000000000019ef <+158>: mov eax,DWORD PTR [rip+0x264b] # 0x4040 <flag_fd.5712>
0x00000000000019f5 <+164>: mov edx,0x100
0x00000000000019fa <+169>: lea rsi,[rip+0x265f] # 0x4060 <flag.5711>
0x0000000000001a01 <+176>: mov edi,eax
0x0000000000001a03 <+178>: call 0x1200 <read@plt>
0x0000000000001a08 <+183>: mov DWORD PTR [rip+0x2752],eax # 0x4160 <flag_length.5713>
0x0000000000001a0e <+189>: mov eax,DWORD PTR [rip+0x274c] # 0x4160 <flag_length.5713>
0x0000000000001a14 <+195>: test eax,eax
0x0000000000001a16 <+197>: jg 0x1a3c <win+235>
0x0000000000001a18 <+199>: call 0x1170 <__errno_location@plt>
0x0000000000001a1d <+204>: mov eax,DWORD PTR [rax]
0x0000000000001a1f <+206>: mov edi,eax
0x0000000000001a21 <+208>: call 0x1270 <strerror@plt>
0x0000000000001a26 <+213>: mov rsi,rax
0x0000000000001a29 <+216>: lea rdi,[rip+0x760] # 0x2190
0x0000000000001a30 <+223>: mov eax,0x0
0x0000000000001a35 <+228>: call 0x11c0 <printf@plt>
0x0000000000001a3a <+233>: jmp 0x1a67 <win+278>
0x0000000000001a3c <+235>: mov eax,DWORD PTR [rip+0x271e] # 0x4160 <flag_length.5713>
0x0000000000001a42 <+241>: cdqe
0x0000000000001a44 <+243>: mov rdx,rax
0x0000000000001a47 <+246>: lea rsi,[rip+0x2612] # 0x4060 <flag.5711>
0x0000000000001a4e <+253>: mov edi,0x1
0x0000000000001a53 <+258>: call 0x11a0 <write@plt>
0x0000000000001a58 <+263>: lea rdi,[rip+0x75b] # 0x21ba
0x0000000000001a5f <+270>: call 0x1180 <puts@plt>
0x0000000000001a64 <+275>: jmp 0x1a67 <win+278>
0x0000000000001a66 <+277>: nop
0x0000000000001a67 <+278>: leave

直接调用win会显示一行字符串,告诉我们程序在0x0000560be82fc969收到错误,然后再continue的话就结束了

(gdb) call (void)win()

Program received signal SIGSEGV, Segmentation fault.
0x0000560be82fc969 in win ()
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on".
Evaluation of the expression containing the function
(win) will be abandoned.
When the function is done executing, GDB will silently stop.
(gdb) c
Continuing.

Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.

0x0000560be82fc969也就是win+24,所以在这个地方打一个断点,然后直接手动设置rip,让下一条指令跳过就好了

(gdb) start
Temporary breakpoint 1 at 0x1a75
Starting program: /challenge/embryogdb_level8

Temporary breakpoint 1, 0x0000642568f6da75 in main ()
(gdb) break *win+24
Breakpoint 2 at 0x642568f6d969
(gdb) call (void)win()

Breakpoint 2, 0x0000642568f6d969 in win ()
The program being debugged stopped while in a function called from GDB.
Evaluation of the expression containing the function
(win) will be abandoned.
When the function is done executing, GDB will silently stop.
(gdb) set $rip=*win+35
(gdb) c
Continuing.
You win! Here is your flag: