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输入:
文件要在x86处理器上运行,是ELF,不会提供我们源代码中变量名称和原始函数的任何信息,需要一点x86汇编基础
0x04 入口点
当我们用Binary Ninja打开可执行文件时,反汇编程序会找到并显示程序的入口点:
入口点-start是编译器将代码从main函数开始运行的地方,这个文件只需要在下面找到call -start
双击此函数sub_8048a24是由Binary Ninja 标记的,因为调试符号没有告诉我们真实变量信息,会显示main函数:
前几行和后几行代码设置了函数的堆栈框架,不需要关注,重点关心下面三个函数调用:
0x05 分析程序
我们所关心的实际上是在0x08048A4C处压入堆栈的函数地址,这是sub_8048d14函数的一个参数,查看该函数发现该函数的子进程fork将调用地址:0x080489B4。在Binary Ninja中,我们可以点击“p”键来告诉它这个地址是一个函数:
上面就是连接处理程序,这是我们真正要关心的,当我们使用netcat连接到服务时,它会在后台运行,该功能用于处理我们的网络连接,只有3个 基本函数块,接下来我们将一块一块地进行分析
第一块:
在开头,我们可以看到设置堆栈帧的函数起始点,接下来,我们可以看到程序从堆栈指针(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清除我们之前做的堆栈帧之后):
在这里,我们将进行3个函数调用
第一个将从网络接收(recv)到0x100字节var_20c (Binary Ninja的名字ebp-0x208,这是一个位置在堆栈上的0x208字节)。这是程序获得我们输入的地方!
第二个函数调用需要我们的输入并用snprintf它来进行不同的格式化,它会将这个新格式化的字符串保存到0x12C字节var_10c(Binary Ninja的名字为 ebp-0x108,它是堆栈中0x108字节的位置),这就是程序建立输出的地方。
第三个函数调用将使用此输出字符串并sub_8048b44再次使用它通过网络发送出去,在此之后,我们转到第三个基本块(如上所示)并从函数返回。
0x06 漏洞
我们已经分析了程序的所有代码,现在我们来寻找漏洞,先看一下这个堆栈:
我们的程序中有两个字符串缓冲区:var_20c和var_10c,这是输入点,它的长度是0x100(256)字节,在0x080489EB,我们recv最多可以将0x100字节存入这个内存位置。
一旦我们有了输入点,我们就可以snprintf将字符串转换成特定的格式,我们采用这个新字符串的0x12C(300)字节并将它们存储到var_10c的输出缓冲区中,这里的问题是我们没有0x12C字节的空间 , 我们只有0x100。任何额外的字节都会覆盖掉堆栈下方的其他值。这并不是函数功能所期望的,这样就出现了一个缓冲区溢出漏洞。
0x07 漏洞分析
那么,我们如何利用这个漏洞来控制这个程序呢?在x86上最基本的方法是接管eip指令指针,这是处理器将执行的下一条指令的地址,如果我们能够控制这个值,我们可以影响下一个程序的执行位置。
为此,我们需要eip用输入数据覆盖堆栈中保存的值。为了达到这个目的,我们需要:
上面的内容加起来是255个字节,如果我们向服务发送255个“A”字符,它将会试图返回地址0x41414141(“A”的ASCII值),但是我们不希望程序崩溃 -我们的目的是拿到flag!所以,我们需要将程序指向有意义的地方。
这就是漏洞利用最难的地方了,我们要做的是将指针指向我们的输入,当我们这样做时,程序会相信我们的输入实际上是编译代码 ,就像其他可执行文件一样。因此,我们可以提供符合我们需要的新代码——shellcode
0x08 shellcode
当我们通过我们的输入向可执行文件提供新代码时,这些代码就是“shellcode”,Shellcode实际上只是我们自己编写的程序包,而不是编译器的输出结果,这里有一段shellcode可以让我们在远程系统上运行一个shell:
在另一个终端中监听主机端口:
在真实的比赛中将这个flag提交给得分服务器,就会拿到分数,继续进行研究。
0x10 漏洞修复
现在我们已经利用了这个漏洞,我们将如何修复它以防止自己受到攻击?对于这个服务,直接打补丁很简单:我们将0x12C的值更改为0x100,并防止程序写入敏感的堆栈信息,这样就可以了
使用Binary Ninja让补丁变得非常容易,你只需要切换到0x080489F6(push 0x12C指令的位置 ,告诉snprintf它需要多少空间),点击“h”在十六进制编辑器视图中查看它,并将2c0x080489F7更改为00:
再次点击“h”会回到图形界面,在那里我们可以看到补丁生效了:
现在,你可以转到“文件 - >另存为...”并将修补后的可执行文件保存到磁盘。如果你将scp这个二进制文件替换到服务器并替换那里这个漏洞就没有了,该服务器也安全了!
0x11 总结
总的来说这个靶机并不难,通过这样的实战训练提升自己的实战能力是一个不错的方法。
最快的成长方式就是实战中成长,比如你拿到攻击者的样本,立马可以吸收其手法精髓,防御上就可以有的放矢。再比如为了突破,你死磕到底,一回头会发现:卧槽,掌握了各种技巧,而这许多是死磕前绝无法想象到的。
本文由看雪论坛 hackerbirder 原创
网友评论