原文:
http://www.hackingarticles.in/hack-the-rop-primer-1-0-1-ctf-challenge/

大家好,今天我们的靶机是ROP Primer(ROP入门),靶机的目的正如它的名字一样,带你入门ROP。靶机下载地址:https://www.vulnhub.com/entry/jis-ctf-vulnupload,228/#download

我们这里有三个level,并且每个靶机的登录凭证已经给出,如下所示:

每个level都有一个二进制文件,我们需要利用这些二进制文件来成功获取flag。
你可以在这里下载所有的exp。

开始搞破坏吧!!!
首先当然是要获取靶机的IP地址(这里我的IP是192.168.199.139,你们下载靶机之后需要根据你自己的网络配置来确定IP地址)
使用netdiscover工具来扫描,如图:

netdiscover

level 0
现在我们用level0这个用户通过ssh登录靶机。登录成功之后,我们发现两个文件,一个可执行文件level0,一个flag文件。两个文件的属主都是level1用户,但是二进制文件设置了suid位,所以我们可以进行利用。当我们运行文件时,它会提示我们输入一个字符串,然后会根据你输入的字符串输出一个消息,如图:

作者在实验环境中已经提供了GDB-peda插件,PEDA是为GDB设计的一个强大的插件,全称是Python Exploit Development Assistance for GDB。所以我们可以直接在靶机中分析二进制文件。在gdb中打开二进制文件,我们发现了一个gets函数。而这个gets函数存在缓冲区溢出攻击,所以,我们可以利用它。

set disassembly-flavor intel
disas main

我们使用gdb-peda来生产500字节长的pattern,并将其作为二进制文件的输入,如下:

pattern create 500

一旦我们传入这个字符串,我们就得到了一个segmentation fault错误,我们使用gdb-peda的模式偏移函数来查找EIP的偏移量,发现在44字节之后,我们可以完全覆盖EIP寄存器,如下:

pattern offset 0x41414641

现在我们来检查下安全策略,发现并没有ASLR(地址空间位置随机加载),但是却启用了NX,所以我们无法在堆栈上执行shellcode,如图:

checksec

由于启用了NX,我们仍然可以使用ret2libc攻击来生成shell。但是当我们尝试输出系统的内存地址时,我们发现竟没有系统,所以我们不能执行/bin/sh来生成shell。

在描述中有一个提示,提示我们可以使用mprotect来解决这个问题。

p system
p mprotect

于是我们查看一下mprotect的man帮助手册,我们发现它可以用来改变内存部分的保护,使其可读可写可执行。我们还发现它要接收三个参数,分别是地址,需要改变的内存长度和保护级别,如图所示:

由于我们可以让内存部分可读可写可执行,我们将使用memcpy函数将我们的shellcode插入到内存块中,如下图:

p memcpy

现在需要选择我们要更改的内存部分,因此我们使用gdb来查看内存的映射方式,如图所示:

vmmap

我们将把0x080ca000作为目标内存,我们将从0x080ca000开始标记4KB内存作为可读可写和可执行。我们为此生成了一个exp,如图:

我们将程序的输出内容保存到文件名为input的文件中,我们将使用这个内容作为二进制文件的输入,如下图:

python exp.py > input

当我们在gdb中运行二进制文件时,输入input文件中的内容,然后再来看下内存映射,发现我们选择的内存块已被标记为可读可写和可执行。

vmmap

现在我们需要从堆栈中删除mprotect的参数,以便我们可以重定向执行流程,mprotect函数使用3个参数,所以我们需要从堆栈中弹出3个值,所以我们在gdb中使用ropgadget函数并在0x8048882找到gadget pop3ret。

ropgadget

现在我们生成了一个exp来获取一个权限高的shell。我们使用cat命令来保持shell存活,然后执行exp,现在我们就可以访问flag文件了。查看一下flag文件的内容,获取我们的第一个flag,如下图:

(python /tmp/exp.py; cat) | ./level0

level1
完成了level0之后,我们用level1用户登录。登录进去之后,发现了flag文件,bleh文件和二进制文件level1,二进制文件同样设置了suid位。但是我们执行二进制文件的时候,却爆出了error binding的错误,如下所示:

我们查看一下靶机上监听的端口,发现8888端口是开放的。我们再查看下uid是1002的进程,发现它是属于用户level1的,如图所示:

netstat -aepn | grep 8888
ps -aux | grep 1002

我们用nc连接一下8888端口,发现是一个可以用来存储和读取文件的程序,如图所示:

nc 192.168.199.139 8888

我们在gdb中打开二进制文件来查看汇编代码来做进一步的分析,如图所示:

gdb -q level1
set disassembly-flavor intel
disas main

我们在main函数上设置一个断点。在main + 115位置,我们发现端口8888存储在堆栈中。我们将存储在内存地址中的值更改为端口8889,以便我们可以运行该程序,如下图所示:

set {int}0xbffff6b0 = 8889

我们在系统中使用pattern_create.rb脚本创建一个128字节长的pattern。这样我们就可以将字符串作为文件名传递。

./pattern_create -l 128

更改端口号后,我们再进行连接,并指定存储一个128字节大小的文件,

指定文件的大小后,它会让我们输入文件名,我们传递刚才用脚本生成的128字节长的pattern作为文件名,如图所示:

nc 192.168.199.139 8889

当我们切换到gdb时,我们又得到了一个segmentation fault,如图:

我们现在使用patten_offset.rb脚本来查找EIP偏移量,如图所示:

./pattern_offset.rb -q 0x63413163

在这个挑战靶机的描述中,给了我们一个提示,我们可以使用read,write和open函数打开flag并读取内容,如图所示:

p read
p write
p open

现在我们要用ropgadget来查找gadgets,我们需要gadget pop2ret的open函数和gadget pop3ret的read函数,如图所示:

ropgadget

现在,如果我们可以得到'flag'字符串的地址,那么我们就可以读取flag并将其输出到已连接的socket中,如图:

find flag

我们生成了一个exp来获取flag,运行之后,就能找到第二个flag,如图:

python level1.py

level2
完成level1之后,以level2用户进行登录。发现了一个flag文件和一个设置了suid位的二进制文件。当我们运行二进制文件时,提示我们需要传递一个字符串参数,并且输出到屏幕上,如图所示:

在gdb中打开文件进一步分析,发现在main+46处,调用了strcpy函数,这个函数存在缓冲区溢出漏洞,我们可以利用它。

gdb -q level2
set disassembly-flavor intel
disas main

进一步分析之后,发现它跟level0的二进制文件类似,我们生成一个500字节的字符串并作为参数传递,发现EIP偏移量的位置为44字节,如图所示:

pattern offset 0x41414641

这个文件有strcpy函数,而没有gets函数,因此我们无法使用“\x00”。这里我们利用gadgets来完成我们的工作,我们使用ropshell.com来找到这个exp中所有的gadgets,如图所示:

我们修改修改一下level0中生产的exp并插入我们的gadgets。在这个exp中,我们使用read函数来代替strcpy函数。(gadgets在exp代码中都有解释)

只要我们一运行exp,我们就可以生成一个root用户的shell,然后就可以查看flag文件获取到第三个flag了,如图所示:

源链接

Hacking more

...