0x01 install binnavi


直接下载https://github.com/google/binnavi/releases里面的binnavi-all.jar,放到windows下双击,运行不成功说明缺少环境,再从其他几个链接中学习安装

使用教程https://www.zynamics.com/binnavi/manual/html/tutorial.htm

最佳安装方案:

将binnavi安装到win2003上

直接双击运行https://github.com/google/binnavi/releases中的binnavi-all.jar,并将这个链接里面的zynamics_binexport_9.plw和zynamics_binexport_9.p64放入idapro6.8的plugin目录中

将这个链接里面的copy_to_ida_root_windows.zip解压后放到ida的根目录下

ida pro6.8的安装如果因为没有注册使得ida pro无法加载binexport9插件(看不到Edit|Plugin|BinExport9说明没有加载成功),则替换ida安装目录下的ida.key文件为这个链接中的ida.key文件,并将系统时间改成若干年前完成ida pro的破解

如果提示有什么问题,再根据

https://blog.because-security.com/t/development-environment-for-binnavi-with-a-package-manager-windows/34

这里面的方法安装缺失依赖,可能不用全部安装完就可以再次尝试直接双击binnavi-all.jar而成功运行

安装postgresql到win2003上会失败,解决方法http://blog.itpub.net/29598413/viewspace-1258961/

以上安装知识理应足够,如需还有这个链接

里面的readme.md文件有关于安装的问题,另外这个链接里面有大多数需要的依赖环境打包好了

实例安装:(win2003)(事后觉得2中的命令可以不运行,因为binnavi-all.jar为最后编译的结果文件,而2中只是为了编译才做的过程)

  1. my_vinnavi从这里下载
  2. 安装my_binnavi中的install binnavi on win2003里面的两个exe
  3. 执行:
  4. 安装jdk8(jdk6不成功),并添加对应
    1
    C:/Program Files/Java/jdk1.8.0_91/bin

    1
    C:/Program Files/Java/jre1.8.0_91/bin

    到环境变量path,新建一个环境变量JAVA_HOME为C:/Program Files/Java/jdk1.8.0_91/

  5. 安装idapro6.8,替换key文件,修改本机时间为几年前,将copy_to_ida_root_windows.zip里面的文件放入idapro根目录(重要,没有这步Edit|Plugin中看不到BinExport9),并将binexport的两个文件(zynamics_binexport_9.plw和zynamics_binexport_9.p64)放入idapro的plugin目录
  6. 安装my_binnavi中的postgresql(x86),数据库用户名和密码设为postgres,将win2003中的c:/program files/postgresql目录设置为everyone有所有权限
  7. 以管理员身份(否则在binnavi运行后无法import idb文件)运行binnavi-all.jar(win2003下右键以不受限方式打开cmd.exe,然后运行binnavi-all.jar)

0x02 fuzz target app

about

fuzz

  1. 安装ftpfuzz(实验中安装到192.168.3.77中)
  2. 设置user为annoymous,pass为test
  3. 只取list命令作为fuzz的对象
  4. 只选择A作为fuzz的数据
pcman-ftp初战漏洞挖掘-RadeBit瑞安全

0x03 binnavi使用方法

0.binnavi安装在win2003上,ip:192.168.3.176

1.新建一个project

2.导入一个模块(ida生成的idb文件)

出现错误及安装binnavi解决方法可参考https://github.com/google/binnavi/issues/94

3.新建一个debugger:192.168.3.177:2222

  • 192.168.3.77为安装ftpfuzz工具的一台win7机器,用于fuzz目标192.168.3.177上的pcmanftp
  • 192.168.3.176为安装binnavi的机器,用于远程调试192.168.3.177上的ftp进程,并追踪ftp进程上的相关指令
  • 192.168.3.177为目标ftp运行的机器,通过在192.168.3.177上安装idapro(6.8)加载该ftp进程后产生idb文件,将该idb文件复制到192.168.3.176(win2003)上用binnavi加载

为了实现在192.168.3.176上远程调试192.168.3.177的ftp,需要在192.168.3.177上运行:

https://github.com/google/binnavi/releases/download/v6.1.0/debugclient.exehttp://pan.baidu.com/s/1hsK0jwK中的debugclient.exe

在win7上不要用管理员权限运行,否则debugclient.exe会报断点错误,运行方法:

4.初始化模块

双击图中的modules下面的pcmanftpd2.exe,或右键选择laod+initial,使得产生图中有Native Callgraph的面板,此时如果双击图中箭头指向的Native Callgraph可产生graph视图,并可从graph视图(图6)的菜单中选择windows下的debug perspective子项进行进程调试和指令追踪,此处不用这种方法,选择下面更好一点的方法

5.产生grahp视图

双击NewProject,左键按住modules下的pcmanftpd2.exe并拖到NewProject下的Default address space上面,这样将会把导入的idb模块”对应放到”default address space中,然后可以右键单击defalut address space,选择create combined callgraph,此时将产生上面说的graph视图(图6),如果不用这种方法而用上面的方法则不能在defalut address space上右键选择create combined callgraph,binnavi会报错

6.上面的graph视图窗口对应下面的图6

7.动态调试192.168.3.177上的ftp进程并追踪指令

  • 在正常binnavi窗口中(非graph窗口):

在NewProject面板中选择并保存上面设置的debugger,如下图7

在Default address place面板中选择并保存上面设置的debugger,如下图7-2

  • 在graph窗口中:

单击菜单中的windows,并选择debug perspective,将打开调试窗口,如下图7-3

单击下图7-4中的start debug开始进程调试

单击下图7-4中的start trace mode开始指令追踪

实验中binnavi版本为最新的6.1+ida pro6.8,安装在win2003系统上,此安装的binnavi有以下问题:

  1. stop trace mode按钮只是前几次有效(eg.10次内的trace列表)
  2. 在1下先按stop trace mode再按start trace mode按钮可以实时刷新地跟踪指令
  3. 按下超过一定次数的start trace mode(一定trace列表数)2中情况不再有效,需要重新start debugger,这也意味着要重新在192.168.3.177中重新运行pcmanftp,并运行:
  4. binnavi中使用指令追踪功能时除了上面2中的方法也可以通过删除trace列表里面的已存在的trace,然后重新按start trace mode,这样可以不用按像2中(stop trace mode再按start trace mode)而达到指令追踪的目的,192.168.3.177的win7上运行debugclient.exe pid时不用管理员身份运行虽然会报断点错误,但是好像实际实验中追踪效果更好,此点尚疑.一般情况下,每个应用都用管理员身份运行不易出错(debugclient.exe,pcmanftp,binnavi)

图1

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

图2

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

图3

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

图4

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

图5

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

图6

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

图7

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

图7-2

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

图7-3

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

图7-4

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

0x03 实战


1. dep off

实验中win7系统中默认dep关闭如下

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

追踪192.168.3.177中的pcmanftp进程的溢出指令

1.运行192.168.3.177上的pcmanftp后用管理员权限运行clientdebug.exe pid,然后单击192.168.3.176上的graph视图窗口下的debug perspective下的start debug,开始远程调试pcmanftp

2.单击start trace mode,binnavi下完断点后再单击start trace mode,此时binnavi中的trace列表如下图a,然后在192.168.3.77(另外一台win7,安装有ftpfuzz工具,用来fuzz目标192.168.3.177里的pcmanftp),事先设置fuzz数据为发送30,70…到9000个A,后来发现发送9000个A会使pcmanftp出错,于是最后设置fuzz数据为只发送9000个A,便于追踪出错的详细汇编语句,如下图b:

图a

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

图b

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

3.完成2中的设置后在192.168.3.77中单击上图中的start按钮,用ftpfuzz发送9000个A,只选择LIST命令进行fuzz,fuzz结束后binnavi中对应trace列表如下图trace1,说明ftpfuzz与binnavi的数据交互中共产生了72个event,也即从发送anonymous登录到发送完LIST 9000xA命令后的event,但是这样不能精确追踪到关键溢出(发送9000个A)时的代码,不会将登录ftp的过程记录到event中,使得event有72个,较大,为了精确追踪到pcmanftp对9000个A的数据处理过程,需要过滤掉fuzzftp登录pcmanftp的过程,于是进行如下操作:

  • on 192.168.3.177:
  • on kali:(192.168.3.106)
  • on binnavi(192.168.3.176)
  • on kali:
  • on 192.168.3.177:

重新打开pcmanftp并debug #重新追踪

  • on binnavi:

重新start debug,start trace mode,start trace mode

  • on kali:
  • on binnavi:
  • on kali:
  • on binnavi:

此时产生list 9000xA命令的trace指令列表,如下图trace3,说明list Ax9000这个命令运行后在pcmanftp上有7个event与之对应,此时eip已经被覆盖成41414141,说明大概到图trace3的sub_427350处已经覆盖了eip为41414141了,后来od跟踪发现确实如此

也即追踪到的关键event(指令)为:

图trace1

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

图trace2

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

图trace3

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

追踪到相关指令后此时binavi暂时退出,用od调试pcmanftp

  • on 192.168.3.177:

重新打开pcmanftp,od附加

  • on kali:
  • on 192.168.3.177’s od:

此时可以单击状态栏中的pcmanftp可以显示pcmanftp主界面,且kali中也可以显示ftp会话信息,关于”卡住”以后为什么可以通过resume all threads来调试而”不影响”调试目的有以下猜想:

windows程序有消息响应机制,windows程序中的主线程一直在等待各个子线程的消息,如果某个子线程中断或者出故障了,可能会被主线程知道,然后主线程调用相应方法去处理这个出问题的子线程,这样就可以解释在下完402b60,405410,427350的断点后,发送ls Ax9000到pcmanftp,在od中一直按f9,却没有在某时刻可以看到eip=41414141,而最后由于的确存在某时刻eip=41414141,导致异常,最后弹出如下图error显示的错误对话框,对话框中显示出错原因为eip被41414141覆盖,这样大概是因为当eip在某时刻被41414141覆盖的时候,于是这个子线程出故障了,程序的主线程知道了这个消息,然后调用seh链中的异常处理程序,处理的结果就是弹出这样一个错误详细信息对话框

图error

pcman-ftp初战漏洞挖掘-RadeBit瑞安全
  • on kali:
  • on 192.168.3.177’od:

此时中断在402b60处

在堆栈窗口中:ctrl+b查找AAAA

提示没有找到

f9
此时中断在405410处

在堆栈窗口中:ctrl+b查找AAAA

提示没有找到

f9
此时中断在427350处

在堆栈窗口中:ctrl+b查找AAAA

提示找到,说明通过binnavi找到的这些event中,关键的覆盖eip的指令在405410到427350这两个断点之间

载pcmanftp,并重点关注405410到427350这两个断点之间会经过的指令

on 192.168.3.177’s od:

重复以上加载并resume all threads过程直到中断到405410处

查找关键汇编指令方法:

结过漫长的ctrl+f9,f8,时刻关注堆栈,寄存器,反汇编窗口指令等,在可疑函数f8单步步过后在堆栈窗口中ctrl+b查找AAAA

现从405410到427350两个断点之间的指令,如果通过f8,f7,ctrl+f9等的一步一步调试无法到达覆盖eip的关键指令处,而通过在405410断点处直接f9到427350处会经过覆盖eip的关键指令处,然而确无法单步调试到关键指令处.

单步调试时指令经过流程为:

405410到427350,再由427350到427350

其中405410到427350流程中无法捕捉到覆盖eip的关键指令,于是指令开始在427350到427350之间一直循环,像是一个进程阻塞当中(eg.listen,accept),427350到427350也无法捕捉到覆盖eip的关键指令,在427350处f9到427350时,情况和下面的405410处f9到427350的情况一样

但是,两个断点之间f9运行调试时:

在405410处f9到427350时,在堆栈窗口中ctrl+b:41414141却能找到41414141,说明f9运行时,的确经过了覆盖eip的关键指令

出现以上这种现象暂时不能理解,猜测有可能是427350是一个循环等待的函数,并且与有时间相关,如果每次时间超过一定时间(单步调试程序某个线程等待造成时间较长),这个427350处的循环等待判断为无效,即只在一定时间内判定为有效循环等待(这样在427350处f9运行调试到427350处时可以在堆栈窗口捕获到AAAA就可以理解了)

于是尝试在405410和427350下断点后(到此处不用在402b60处下断点了),f9运行pcmanftp,然后在kali中的terminal中ftp open 192.168.3.177登录,之后输入ls 9000xA命令,待od中中断到405410时,在od的汇编代码区右键查看所有模块间调用,并在所有模块间调用处下断点,然后一直f9运行调试pcmanftp,这样有可能会在堆栈区捕获到AAAA,具体步骤如下:

  • on 192.168.3.177’s od:
  • on kali:
  • on 192.168.3.177’s od:
  • on kali:
  • on 192.168.3.177’s od:

此时观察到堆栈区第一次出现大长串AAAAAAAAAA,断点处在416685,也即在416685处的模块间调用开始出现AAAAAAA,如下图od1

图od1

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

于是重新在405410,416685,427350处下断点,重点关注405410到416685后,在416685开始的指令流程,具体如下:

  • on 192.168.3.177’od:
  • on kali:
  • on 192.168.3.177’od:
  • on kali:
  • on 192.168.3.177’s od:ctrl+g:416685-–|||||>f2 alt+c

此时自动中断在405410处

f9
此时自动中断在416685处

f9
此时又中断到416685处(不过堆栈窗口出现了AAAAAAA)

此时对应的od中截图如下图od2:

图od2

pcman-ftp初战漏洞挖掘-RadeBit瑞安全
  • esp下面的第一个返回到的地址为当前栈帧的返回地址,也即汇编窗口中004166e9处的retn要返回到的地址
  • esp下面的第二个返回到的地址4029db为当前函数栈帧的上一函数栈帧中的retn要返回的地址
  • esp下面的第三个返回到的地址4029ff为当前函数栈帧的上一函数的上一函数的栈帧中的retn要返回的地址

此时堆栈窗口数据如下:

参照上一篇文章:

http://xinghuacai.github.io/%E4%BA%8C%E8%BF%9B%E5%88%B6/2016/06/04/%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%85%A5%E9%97%A8-%E5%8A%A8%E6%80%81%E8%B7%9F%E8%B8%AA%E6%BA%90%E4%BB%A3%E7%A0%81%E5%92%8C%E5%8F%8D%E6%B1%87%E7%BC%96%E4%BB%A3%E7%A0%81/中的图stack0易知:

其中栈中0018ed8c以后很长一段数据都是41414141,由于此时中断到416685而堆栈窗口中首次出现AAAAAA数据,而堆栈窗口中最近的三个返回地址中00412976对应的是本函数栈帧(对应图od2)中的004166e9处的retn,这样的话,很有可能是本函数栈帧的上一帧函数(该函数内的retn对应返回到4029db)或者是上上一帧函数(该函数内的retn对应返回到4029ef)的返回地址被此时栈中的大长串A覆盖成41414141

当前eip对应的函数帧是00416683函数,当前函数帧的上一帧函数是wsock32.recv,wsock32.recv函数帧的上一函数帧的00412956函数,形如下面表示:

所以有可能当前函数帧(对应图od2)中的汇编语句(执行到4166e9处的retn之前的语句)会导致栈中的两个返回地址(0018ed5c处的004029db和0018ed64处的004029ef)被覆盖,也有可能在wsock32.recv函数帧中某语句覆盖0018ed64处的004029ef,也有可能是本函数帧(00416683,正常情况下esp下面最近一个返回地址在od中显示来自于什么函数则当前eip在该函数帧中)的下一函数帧(也即还没执行到的函数,当前函数帧为最新函数帧)中的汇编语句覆盖两个返回地址或这两个返回地址下面比较远的返回地址等

于是重点关注堆栈窗口中的0018ed5c处的004029db和0018ed64处的004029ef是否可能会在当前函数帧中执行到004166e9之前或下一个将到达的函数帧中被改写成41414141

在od中f8单步调试时,遇到可疑指令如call xxx等,在堆栈窗口中ctrl+g(堆栈中跟随):0018ed5c或0018ed64,然后f8单步调试,具体如下操作:

执行到图od2中的004166e9处的retn时,0018ed5c和0018ed64处的返回地址都不变,继续f8跳到412967处,此时在wsock32.recv函数帧中,继续f8

执行到412997处时,在到达这个函数帧中的rent语句前,所有的指令都在wsock32.recv函数帧中,0018ed5c中的返回地址由004029db被改成000000,也即wsock32.recv函数帧中的retn指令被执行时将返回到由004029db变成的00000000,此时栈帧已经被破坏,执行完wsock32.recv函数帧中的retn指令后,将跳到00000000执行,也即在当前帧(wsock32.recv函数帧)中执行到retn语句时,将发生错误,对应汇编指令为:

对应堆栈窗口中0018ed5c和0018ed64处的内容为:

而当前函数帧中的retn语句在如下位置004129f9处:

所以如果是要将堆栈窗口中0018ed5c处的004029db或0018ed64处的004029ef这两个返回地址覆盖成41414141有极大的可能是在当前函数帧的004129f9处的retn语句前完成,而0018ed64处被覆盖成41414141的可能性更大,因为0018ed5c处已经被覆盖成00000000了

在eip=004129f9前,单步执行到004129c1处

f8执行到004129df,以jmp 到004129c1,也即004129c1到004129df相当于一个for循环,004129c1处开始到retn语句前的汇编指令如下:

直接在004129df的下一条语句004129e1上f4,发现f4以后eip直接跳到了00416685处的call getlasterror语句上,而不是f4执行到004129e1上,且f4以后0018ed5c处的004029db和0018ed64处的004029ef都被覆盖改写成41414141

说明004129c1到004129df为关键的复制过程,这个过程覆盖了0018ed5c处的004029db和0018ed64处的004029ef

然而在当前wsock32.recv函数帧中,如果覆盖返回地址,一般是只能覆盖到当前函数帧的上一函数帧的返回地址,即覆盖0018ed64处的004029ef,不明白为何连当前函数帧的返回地址也被覆盖成41414141了,这一点不解

猜测是由于windows的消息机制,程序的主线程监视到有函数的返回地址被覆盖成不可执行的地址41414141时,进入异常处理链开始执行(由于主线程优先级高,于是出问题后不去41414141处执行,也不去原来wsock32.recv函数帧当中按f4处的004129e1执行),发现没有专门对应的exception handler,最后调用unhandled exceptionfilter(后来f8单步发现是有call unhandled exceptionfilter)处理这个异常,最后弹出图error的对话框,认为有某一刻eip=41414141,但是这一刻没有在单步调试中出现,认为由004129e1处突然跳到了call getlasterror的过程中,实际上是先到eip=41414141处,然后再跳到到call getlasterror处,或许是由于这个过程太快或比较特殊而没有被od捕捉到因而没有遇到eip=41414141的时刻

但是现在不能确定是0018ed5c处被覆盖成的41414141还是0018ed64处被覆盖的41414141是真正的那一刻eip=41414141的时刻而引起的主线程优先进入异常处理

理论上是在004129e1处f4的时候,由于还在wsock32.recv函数帧当中,返回的先后顺序是先返回到0018ed5c处被覆盖的41414141再返回到0018ed64处被覆盖的41414141,然而0018ed5c原来被覆盖成00000000时是可以理解的,被覆盖成41414141是不可理解的,于是这两种可能性都不能确定

在内存中覆盖时AAAA的数据由0018e58e开始到0018ed64共2006个字节,由0018e58e开始到0018ed5c共1998个字节,重新发送1998xA+BBBB+CCCC+DDDD到pcmanftp,不用od加载,看看最后的error对话框中的异常位移是多少

向pcmanftp发送Ax1998+Bx4+Cx4+Dx4发现不能使pcmanftp停止工作,于是发送Ax1998+Bx4+Cx4+Dx4+Ex6990(共9000个字节),成功使之停止工作,但是弹出对应error图中对话框中的异常偏移为45444444,也即对应EDDD,这样应该是说明是0018ed64处的41414141被覆盖,但是又相差一个字节,不知是那里算错了,暂且不纠结于此

发送Ax1998+Bx4+Cx4+Dx4+F+Ex6989(共9000个字节),成功使之停止工作,且异常偏移显示为46444444,说明发送的9000个字节中,第2008到2011个字节处为覆盖eip处,构造exploit,发现与https://www.exploit-db.com/exploits/39662/链接中的偏移情况相同,都是在第2008-2011个字节处为覆盖返回地址的eip处,在这里填入jmp esp的地址后,再在后面填入用于反弹的shellcode即可,不同的是exploit-db中的是winxpsp3 eng环境,而此处环境为win7x64的中文系统环境

在192.168.3.177中运行pcmanftp后od附加,alt+e选择一个系统dll(实验中选择的是c:/windows/system32/ntdll.dll),在od中ctrl+f:jmp esp找到一个地址为77506aeb,构造的exploit如下:

exploit情况说明:

  1. 在实际msf中加载上面的exploit时,发现要应该对应第2009个字节开始为填充的jmp esp的地址,也即exploit代码中的填充随机覆盖的数据要有2008个,而不是原来认为的2007个
  2. 出现1中的情况认为可能是考虑覆盖偏移量时不应该从AAAA开始,要从ls命令开始,也即ls AAAA开始算
  3. 上面代码中没有发送共9000个字节的数据,用反弹的shellcode代替也可成功
  4. win7系统重启后,jmp esp地址会改变,重启后代码中的jmp esp的地址不再合适
  5. 将上面的代码重命名为mypcmanftp.rb,放到kali中/usr/share/metasploit-framework/moudles/exploits/windows/my/目录下,使用如下命令:

成功溢出后返回meterpreter的shell如下图meterpreter1,其中打印出来的数据为代码中print_status(tmp)的结果,即payload的数据

图meterpreter1

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

2. dep on

实验中win7x64系统中dep开启如下:

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

参考:

目的

实现win7绕过dep并成功溢出pcmanftp

mona插件

在immunity debugger中执行

1
!mona rop -m *.dll -cp nonull

,将得到如下(rop_chains.txt中)建议的rop_gadgets:

在pcmanftp中,重启系统后在上面的exploit.rb中将offset由2007改成2008,有可能是重启导致的一个字节的相差

mona中给出rop_gadgets只是参考的rop,并不代表一定可用,且最新v2版本似乎有点错误,mona算出的rop_gadgets中的第一个地址0x027c9a7a在od中ctrl+g查看一下发现不是对应pop ecx,retn的地址,且有一些地址是执行会产生问题的,这时需要结合od在实际情况中调试

实际调试中发现上面的第10个地址0x7727060d对应的XCHG EAX,EBX+retn在od中ctrl+g:7727060d确实是对应xchg eax,ebx+retn指令的,但是如果第10个地址用7727060d,在od跟踪pcmanftp(在402a26处下断,并f7,再f8,f8,…)中00402a26处的call 403e60后(402a26处的call 403e60汇编语句的下一句汇编语句的地址为402a2b,在上面dep off的实验中是堆栈窗口中的18ed64处的402a2b被改成jmp esp的地址)发现堆栈窗口中从18ed64处开始的对应的第10个地址会被改写,比较奇怪,认为是这个地址出了问题,从rop_suggestions.txt中找另外的XCHG EAX,EBX+RETN对应的地址代替后不会有这个问题

pcmanftp中的关键断点:

继续od跟踪看哪些地址还需修改

运行pcmanftp后od附加,在00402a26处下断,msf发送包含下面rop_gadgets的数据到192.168.3.177

其中向192.168.3.177中pcmanftp发送的数据在下面的sploit变量中:

在msf发送完数据时,要在od中ctrl+v-–|||||>t-–|||||>resume all threads,原因见上面dep off情况中的分析

resume all threads后,pcmanftp中断在00402a26,f9再运行到00402a26,此时开始处理sploit变量中的

1
send_cmd( ["ls", sploit], false )

,第一次中断到402a26处为处理anonymous登录相关的字符串

此时汇编窗口中的数据如下所示,eip=402a26

此时堆栈中18ed64处的返回地址还没有被覆盖,如下所示:

其中0018ed5c处的返回地址已经被覆盖成00000000,18ed68处的的指针对应的是msf中的sploit变量的数据

od中f7进入403e60函数帧:

一直f8到上面403ee6处的call 00412cbf,暂时不跟进,再按f8之后将完成18ed64处的返回地址被覆盖

f8后18ed64处的覆盖内容如下:

其中rop_gadgets数据已经完全和发送的一样,而rop_gadgets后0018edb8处开始到0018edd5原来应该是30个

1
nop+"/xcc"

,其中的30个nop数据不是nop数据了,”/xcc”没变

在od中ctrl+f9运行到retn,然后再f8,此时eip=rop_gadgets中第一个数据,然后再f8..f8看看哪里会出问题

f8跟踪到0018edb4处的772b73df,772b73df中的指令为pushad retn,可想,执行完pushad后esp就上移了,这样再retn的话retn到的便不是rop_gadgets中的原来的应该是30个nop处的地方(现在被改写了,不再是30个nop)

觉得是mona的错误,不应该在最后加个poshad+retn的地址,将rop_gadgets中最后的pushad+retn的地址删除后再重新发送sploit数据并跟踪到rop_gadgets中第一个数据,然后再f8..f8看看哪里会出问题

再次进入到rop_gadgets中的第一个地址778a45e1处,此时eip=778a45e1,堆栈窗口中的18ed64处的数据为:

对比观察发现rop_gadgets中的地址还没开始执行(eip=778a45e1)时,后面的rop_gadgets数据不变,但是后面30个nop还是被改成其他数据,尝试将后面的30个nop改成41414141…再次跟踪到eip=rop_gadgets中的第一个地址778a45e1时,堆栈窗口中的数据如下:

发现这时后面的30个41还是正常的没有被改变的,这样说明应该是win7x64位系统下开户dep后,栈中覆盖好的nop串会被改变成其他随机的填充数据,也有可能是nop串太长为30个时才会这样,考虑到上一篇文中

http://xinghuacai.github.io/%E4%BA%8C%E8%BF%9B%E5%88%B6/2016/06/04/%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%85%A5%E9%97%A8-%E5%8A%A8%E6%80%81%E8%B7%9F%E8%B8%AA%E6%BA%90%E4%BB%A3%E7%A0%81%E5%92%8C%E5%8F%8D%E6%B1%87%E7%BC%96%E4%BB%A3%E7%A0%81/

提到msf的payload前面有可能需要至少9个nop空间帮助完成payload的解码等工作,将30个nop改成9个nop试试9个nop会不会被改成随机的填充数据

再次重新跟踪到eip=rop_gadgets中的第一个地址时,18ed64处的数据为:

发现9个nop还是会被填充成随机数据(后来发现不是被win7x64系统的安全保护填充的,而是因为msf自带的nop有好几种,不只是9090,其他应该是类似的花指令),/xcc到是一直没有被改写,试着不要9个nop了,将原来rop_gadges中的pushad+retn指令的地址改成一条jmp esp指令的地址,并在该地址后接payload数据,上面的dep off时的exploit.rb中的jmp esp的地址76061b1b在dep on时为call esp汇编语句的地址,不用在od中查找其他的了,call esp也可跳到后面的pyaload执行

发送如下的rop_gadgets数据+不要nop+不要/xcc的数据到pcmanftp:

再次跟踪到rop_gadges中的第一个地址,再f8直到上面sploit变量中的rop_gadget中的最后一个地址call esp的地址处程序报错,异常偏移为00a31b1b,难道是rop_gadgets中的地址串执行后没有实现后面的payload为栈中可执行?

再次跟踪到rop_gadgets中的所有地址,发现最后jmp esp执行后程序报错,报出0018edb8处为异常偏移,而0018edb8处为payload开始的对应的堆栈窗口中地址,且每次0018edb8中的数据都不同,难道连payload都被随机数填充了?

有比较大的可能性是执行完上面的rop_gadgets中的地址对应的指令后没有实现payload在栈中可执行,难道是不应该把mona生成的rop_gadges中的最后的pushad+retn对应的地址换成jmp esp的地址?

再看看相关mona的资料,后面的pushad + retn应该是存在的,具体原因见下图virtualprotect_rop中所示

图virtualprotect_rop

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

mona生成的rop_gadgets中的最后一句中的pushad+retn指令的地址是必须的,正是通过pushad+retn的执行才可以导致virtualprotect的执行,实现的原理是在pushad之前将pushad的各个寄存器按照对应的顺序设置成刚好可以调用virtualprotect函数使后面的shellcode为可执行

后来调试在进入virtualprotect_rop前最后一个函数00403e60的返回语句是retn 4而不是retn,所以rop_gadgets中的第一个地址后要加一个过渡的值,这里取为0x41414141

在mona生成的最后rop_chains.txt文件中有virutalalloc过dep的rop_gadgets,也有virtualprotect过dep的rop_gadgets,刚开始以为是mona出错了,后来发现是用到了mona里面的virtualalloc过dep方式

0day2中提到下面几种方法过dep:

  1. ZwSetInformationProcess:利用api彻底关闭dep
  2. VirtualProtect:利用api设置shellcode所在的内存空间为可执行
  3. VirtualAlloc:利用api申请可执行内存后将shellcode复制过去(需再用memcopy的api)
  4. 利用可执行内存挑战dep
  5. 利用.NET挑战dep
  6. 利用Java applet挑战dep

这里用的是2中的virtualprotect中的方法,mona生成的virtualalloc的方法应该是缺少了memcopy的chain,导致刚开始一直错误地以为mona错了

最后再用mona生成的rop_gadgets如下:(第二个地址为新添加的0x41414141)

再次开msf发payload,od附加,调试时发现如下图ebx_error错误

图ebx_error

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

后来发现原来的mona中的virtualprotect是获得0x201(对应上面的0xffffddff,neg取反后为0x201)个可执行栈空间,以为是msf中的payload比这个长导致shellcode执行出错,后来将这个值设置为0xffffddff后没能关掉dep,应该是由于长度太大或许超过了栈空间的大小而导致virtualprotect函数的失败,于是没能成功关掉dep

后来将这个值设置成0xfffffaff(neg取反后的结果比0x201大),又可以关掉dep了,只是后面的shellcode执行还是不成功

怀疑有可能是像上图ebx_error中说的是ebx错了,也有可能是像0day2中说的ebp在溢出的过程中被破坏,这些只有再次从od中动态分析才可知

后来还是自己想多了,mona之所以称为神器,在于的确是神器,怎会轻易出错

换个payload马上成功,对msf还是不够熟悉!!一个payload不行可以换啊!!

最后的exploit.rb如下,改成mypcmanftp-anti-dep.rb,放到/msfdirectory/modules/exploit/windows/my/目录下后执行下面的命令:

成功弹shell

pcman-ftp初战漏洞挖掘-RadeBit瑞安全

来源:邪恶16进制