使用免费工具进行逆向和利用:第11部分

admin 2021年12月31日03:56:36使用免费工具进行逆向和利用:第11部分已关闭评论75 views字数 6718阅读22分23秒阅读模式

使用免费工具进行逆向和利用:第11部分

原作者:Ricardo Narvaja

翻译作者:梦幻的彼岸

更新日期:2021年11月29日


逐步ROP

通常有工具可以为简单的情况构建ROP。

在困难的情况下,这些工具通常不能解决问题,或者只能部分解决问题,让一个人手工完成工具无法完成的工作。

EXPLOIT WRITER 看什么才能知道 ROP 是困难还是容易?这里有一个需要注意的要点列表,我们回答的 YES 越多,它就越容易,而此列表中的一些 NOT 会使工作复杂化,而另一些则较少。让我们看看清单,然后我们将得出答案及其后果。

在回答YES/NO之前回答这些问题(按重要性排序):

1) 该进程是否有ASLR模块?
2) 在没有导入ASLR模块中是否有VirtualAlloc或VirtualProtect函数?
3) 数据是否已经在堆栈中,以便开始运行?
4) 我是否可以传递任何字符,即没有或少数无效字符?

要回答第一个问题,让我们先看一下

什么是ASLR?

使用免费工具进行逆向和利用:第11部分

使用免费工具进行逆向和利用:第11部分

它在那里告诉我们的是,ASLR编译的可执行文件并不总是位于内存中的固定地址,这使得利用更加复杂,因为如果一个进程的所有可执行文件和dlls都是用ASLR编译的,我们将没有固定地址可以跳过并生成ROP。

也就是说,第一个步骤是查看是否存在没有ASL的模块,因为它不是按进程排序的,而是在编译时每个可执行文件都可以单独使用ASL进行编译,也可以不使用ASL进行编译。

一种克服dep+ASL保护的方法是在系统中或同一进程中找到一些内存地址泄漏,从而在运行时返回某个可执行模块的地址,从而使我们能够根据泄漏获得的地址来配置rop

由于我们是逐步进行的,因此我们总是先从最简单的案例开始,看看我们的流程中是否有任何模块没有ASL。

有没有ASLR模块?

我们运行练习的可执行文件,然后在PROCESS EXPLORER.中再次查看。

Microsoft页面上的process explorer 16.31有一个错误,无法显示每个模块的ASLR。

我16.21版本放到链接中,它确实可以工作,而且是我使用的版本。

https://drive.google.com/file/d/1cgF49ZS_GUskxCUJ7ZLDEsoz710mq106/view?usp=drivesdk

使用免费工具进行逆向和利用:第11部分

使用免费工具进行逆向和利用:第11部分

我们把它设置成在底部你可以看到这个进程所具有的模块。

在底部右键单击列,并选择 "选择列"(SELECT COLUMNS)。

使用免费工具进行逆向和利用:第11部分

使用免费工具进行逆向和利用:第11部分

选择 "ASLR Enabled "并打勾:

使用免费工具进行逆向和利用:第11部分

因此,我们看到在底部,重要的一栏标记了每个模块是否是用ASLR编译的。

顶部的列(也称为ASLR)对我们没有帮助,因为在同一个进程中,可能有模块有ASLR,也可能没有ASLR,所以整个进程的通用值是没有用的。

如果我点击我们添加的ASLR列,按照是否有ASLR对模块进行排序,我们看到有一些模块没有ASLR,所以它们的地址将被固定,我们可以使用它来运行。

在我们进程的底部列表中发现的任何没有ASLR的DLL或EXE都可以。

使用免费工具进行逆向和利用:第11部分

在我们的案例中,同样的可执行文件是在没有ASLR的情况下编译的。

因此,清单上第一个也是最重要的问题是肯定的,我们知道,如果我们不能泄漏,最大的困难甚至不可能是安全的。

让我们继续第二个问题:

在没有导入ASLR的模块中是否有VirtualAlloc或VirtualProtect函数?

如果我们看一下我们分析的代码,答案是YES,VirtualAlloc被导入了,记得在第10部分的分析中,在我们没有ASLR的可执行模块中,有一个对VirtualAlloc的调用。

使用免费工具进行逆向和利用:第11部分

如果没有ASLR或泄漏地址的模块也没有导入VirtualAlloc或VirtualProtect,也可以这样做,但ROP将更长更复杂,因为需要通过调用GetModuleHandlea和GetProcAddress来解决ROP问题,找到VirtualAlloc或VirtualProtect的地址会使我们的工作复杂化。

因此,我们已经有两个SI,所以我们做得很好。

我们来看看第三个问题:

数据是否已经在堆栈中,以便开始运行?

让我们来运行到目前为止我们所做的部分解决方案。

使用免费工具进行逆向和利用:第11部分

让我们使用X64Dbg运行,获得跳转到我们的minirop的第一个GADGET的RET。

我们看到我们的ROP位于准备好的堆栈中,可以进入第一个GADGET。

如果不是这样,我们的ROP不在堆栈中,而且我们只有一个跳转到一个可能的地址,我们将无法连接更多的GADGET,因为我们没有控制好堆栈。,当我们执行完第一个GADGET到达它的RET时,我们不能连接第二个,因为我们的数据不在堆栈中,一切都会结束。

为此,有一种特殊的GADGET,叫做ROP PIVOT,其功能是将我们的数据容纳在堆栈中,以便能够继续正常运行,即ROP PIVOT代码必须将数据移动到堆栈中,并且在到达自己的RET时,这是一个GADGET,必须保持相同的位置才能继续使用,稍后我们将看到使用ROP PIVOT的示例。

现在问题的答案是YES,因此在我们的案例中,没有必要使用ROP PIVOT来启动ROPING。

所以我们已经有了三个YES,让我们看看第四个问题:

我是否可以传递任何字符,即没有无效字符?

在我的进程中,要利用的无效字符越多,ROP就越复杂,有时甚至根据情况不可能实现。

显然,由于我们必须在我们的ROP中找到没有ASLR的模块的地址,如果这些地址有一个我们不能通过的字符,事情就会变得复杂,例如我们的例子中可以找到GADGET的可执行部分的位置。

使用免费工具进行逆向和利用:第11部分

从0x401000到0x413000,只有在那里我们才能找到GADGETS,因为它是唯一没有ASLR的模块,在那里有它的可执行部分,如果0x00是一个无效的字符,它将阻止我们在该部分跳转到GADGETS,因为0x00对于设置跳转的地址至关重要。

使用免费工具进行逆向和利用:第11部分

正如我们在minirop中看到的那样,0是必要的,因为这些GADGETS的地址都是以0开始的。

如果我们把0x00作为一个无效字符,那么我们就只能看是否可以溢出,我们就不能运行。

现在让我们回顾一下第四部分对无效字符的研究,因为输入数据的函数仍然是gets(),就像第四部分的练习。

使用免费工具进行逆向和利用:第11部分

使用免费工具进行逆向和利用:第11部分

所以我们有一些限制,就是不能使用包含0xa和0x1a的地址,但也不能在我们用来移动寄存器的值中使用它们。

在我们的minirop中,我们将0x41414141、0x42424242和0x43434343的值移到ECX、EAX和EBP中,我们没有使用任何0x1a或0xa,但是当我们建立执行代码的ROP时,我们必须考虑到这个限制,在ROP的任何地方都没有无效的字符,如果我们以后放置一个shellcode,它也不能使用任何无效的字符。

使用免费工具进行逆向和利用:第11部分

在设置ROP时要仔细观察,在我们的案例中,ROP或SHELLCODE中没有0x1a或0xa,所以在我们的案例中,最后一个问题的答案是NO,但这是一个影响不大的NO,如果无效字符包括0x00,情况会更糟,毕竟限制字符不是很重要。

因此,我们正处于一个最简单的案例中,以后我们会在有更多NO的情况下增加难度,嘿嘿。

我们将寻找小工具,通过x64dbg中的FILE OFFSET,我们将寻找其虚拟地址。

在这种情况下,我们遇到的问题是,RP++如果有一个CALL结束,GADGETS不会显示我们接下来的内容,这对大多数情况来说是有用的,但在我们的情况下,特别是使我们有点复杂。

让我们看一下MSDN中的VirtualAlloc函数

使用免费工具进行逆向和利用:第11部分

根据这一点,堆栈中的第一个参数应该是要解除保护的地址lpAddress。

那么第二个参数是dwSize。

使用免费工具进行逆向和利用:第11部分

在实际操作中,它将解除对一页内存的保护,或者更多,这取决于我们设置的大小,例如,如果我们设置一个值为1,它将解除对0x1000字节的保护,这通常是内存页的大小,1和0x1000之间的任何值将解除对0x1000的保护,如果我设置一个0x1001和0x2000之间的大小,它将解除对0x2000的保护,以此类推。

总之,设置一个非常大的值并不方便,因为如果这个加在lpAddress上的值落在区段之外,函数将返回一个错误,而如果我设置一个较小的值,函数在开始时做的检查将通过,它将不受保护地工作直到区段结束。

第三个参数是flAllocationType。

使用免费工具进行逆向和利用:第11部分

使用免费工具进行逆向和利用:第11部分

我们可以看到,如果我们创建一个新的部分,我们需要调用两次,第一次使用MEM_RESERVE(0x2000)来保留,第二次使用MEM_COMMIT(0x1000)来最终分配,好在我们可以OR这两个值,一次完成两个操作。

使用免费工具进行逆向和利用:第11部分

如果我们在一个现有的区段上使用VirtualAlloc,就像在堆栈中一样,我们应该只传给它0x1000,因为它不需要RESERVE只需要COMMIT。

第四个也是最后一个参数是flProtect。

使用免费工具进行逆向和利用:第11部分

由于我们需要该区域是可执行的,让我们看看这方面的常数。

使用免费工具进行逆向和利用:第11部分

很明显,我们必须通过0x40来给予RXW权限。

我们看到,在我们的案例中,最后三个参数可以直接出现在我们的数据中,我们可以发送它们,不会有任何问题,因为0x0不是一个无效字符,它们总是固定的。

VirtualAlloc解除堆栈保护的4个参数是:

lpAddress = ?
dwSize=1
flAllocationType=0x1000
flProtect =0x40

我们可以看到,在传递漏洞时,我们唯一不知道的值是lpAddress参数中的第一个,因为后三个我们发送它们没有问题,鉴于我们的案例中存在的无效字符,0x1、0x1000和0x40都是已知和可能的,没有值有0x1a或0xa。

唯一的问题是把地址放在首位,因为堆栈可能会移动,而且以前我们不知道它的地址,所以它可能不会被设置。

由于我必须在堆栈中放置,参数lpAddress,并且我希望这个值是同一个堆栈的地址,以解除保护,寻找一个写在ESP或ESP+XXXX的GADGET是一个好主意,让我们看看有什么。

使用免费工具进行逆向和利用:第11部分

很好,在ESP的内容中,我们可以写EAX,当RET到达时只有EAX有一个堆栈的地址,这可能是有用的,尽管最好写在ESP+XXX中,在堆栈中再远一点....。

使用免费工具进行逆向和利用:第11部分

如果我们把这个值设置为lpaddress,然后把我们发送的三个参数放在下面,我们就可以得到所有4个参数,看看我们是否可以利用它。

由于EAX将被用来存储lpaddress参数,我不能用它来解决VirtualAlloc的调用。

如果我能在EBX中容纳VirtualAlloc的值,并在EAX中容纳它最初从堆栈中获得的值,那么我可以使用EBX调用函数,使用这个中间有一个调用RET的gadget,这样它就不会影响它。

使用免费工具进行逆向和利用:第11部分

使用免费工具进行逆向和利用:第11部分
其恢复到EAX,并让它和开始时一样,太好了。

让我们建立我们的ROP,首先要做的是保留EAX值,所以第一个要调用的GADGET是在FILE-OFFSET 0xbb09,如果我们在x64dbg中进入GOTO-FILE OFFSET,其虚拟地址就是。

使用免费工具进行逆向和利用:第11部分

我们第一个gadget的地址是0x40c709:

使用免费工具进行逆向和利用:第11部分

现在我们已经释放了EAX,以便能够使用它,因为我们感兴趣的值是存储在EBP中。

让我们用这个GADGET来移动VirtualAlloc的地址

使用免费工具进行逆向和利用:第11部分

但首先我们必须用VirtualAlloc IAT中的地址来设置EDX,并从中减去4,以便最后读取函数的地址并将其移到EAX

要看存储函数地址的VirtualAlloc IAT的地址是什么,只要看一下对x64dbg的调用

我们看到,当它跳转到VirtualAlloc时,读取的地址值是0x413000:

使用免费工具进行逆向和利用:第11部分

如果我们在DUMP中看到它:

使用免费工具进行逆向和利用:第11部分

我们可以让它显示DUMP的地址:

使用免费工具进行逆向和利用:第11部分

现在看起来好多了:

使用免费工具进行逆向和利用:第11部分

因此,在所有机器上的0x413000,因为这个模块没有ASLR,它将存储VirtualAlloc的地址,这个地址可以改变,但它存储的地方不会改变,所以通过读取0x413000,我们将得到我的进程的VirtualAlloc函数的地址,对于任何机器。

因此,由于我们将使用EDX,我们将不得不先把EDX设置为0x413000-4,因为它在GADGET里面加了4来弥补这一点,最后它将从0x413000读取,并把VirtualAlloc函数地址移到EAX。

使用免费工具进行逆向和利用:第11部分

因此,我们的下一个gadget将是

使用免费工具进行逆向和利用:第11部分

其虚拟地址为0x40fa0e:

使用免费工具进行逆向和利用:第11部分

使用免费工具进行逆向和利用:第11部分

所以我们将把VirtualAlloc IAT条目的值减去4移到EDX。

然后是把VirtualAlloc的地址移到EAX的gadget。

使用免费工具进行逆向和利用:第11部分

它的虚拟地址是0x410d94:

使用免费工具进行逆向和利用:第11部分

我们的地址中有0xD,但我们已经看到它不是一个无效的字符,所以我们继续。

使用免费工具进行逆向和利用:第11部分

有了这个,我们可以把VirtualAlloc的地址传给EBX,如果EBX是0的话。

使用免费工具进行逆向和利用:第11部分

使用免费工具进行逆向和利用:第11部分

有了这个GADGET,我们就可以将EBX清零,总是尽量避免带有LEAVE的GADGETS,因为它破坏了堆栈,RP++没有显示它们,但如果我们用手搜索,我们不应该使用它们,除非我们可以容纳EBP,这样就不会有任何破坏。

所以我们可以添加这两个小工具,你知道如何搜索它们的虚拟地址是 0x4018ef = POP EBX-RET 和 0x40182a= ADD EBX, EAX -xxx -RET。

使用免费工具进行逆向和利用:第11部分

使用免费工具进行逆向和利用:第11部分

使用免费工具进行逆向和利用:第11部分

这样一来,我们在EBX中已经有了VirtualAlloc的地址。

我们必须用另一个XCHG EAX, EBX将它原来的值返回给EAX。

使用免费工具进行逆向和利用:第11部分

然后调用函数:

使用免费工具进行逆向和利用:第11部分

使用免费工具进行逆向和利用:第11部分

我们可以看到,如果我这样运行脚本,仍然有一个问题。

到了RET,我用F7追踪到VirtualAlloc:

使用免费工具进行逆向和利用:第11部分

这些参数都是正确的:

0019FF400019FB14 lpAddress
0019FF4400000001 dwsize
0019FF4800001000 flAllocationType
0019FF4C00000040 flProtect

如果我们从VirtualAlloc函数回溯,我们看到返回值是正确的。

使用免费工具进行逆向和利用:第11部分

返回你取消保护的部分的页面开始,从0x19f000到堆栈的末端;

使用免费工具进行逆向和利用:第11部分

我们已经有了可执行的堆栈,但仍有一个问题,我们能否在不破坏它的情况下从这个函数中返回来运行shellcode?

使用免费工具进行逆向和利用:第11部分

我们在IDA中看到了到达RET的路径,我们在地址中看到了浅蓝色的字母,表明它是嵌入的dll代码,所以它在RET之前添加了dll的安全cookie,这使我们无法到达它,我们将不得不改变策略。

使用免费工具进行逆向和利用:第11部分

我们看到另一个GADGET跳到VirtualAlloc。

EDI在跳转时必须有VirtualAlloc的地址,由于EDI是从ESI的内容中出来的,所以很容易解决,先把IAT条目0x413000的地址放在ESI中。

在EDI的开头应该是原来有EAX的堆栈的地址,所以我们要把它从EAX移到EDI。

这里我们看到两个gadget,第一个是如果ECX为0,则将EAX移动到EDX(0x412130)。

使用免费工具进行逆向和利用:第11部分

我们将EDX移至EDI(0x402512):

使用免费工具进行逆向和利用:第11部分

有了这两个,如果ECX在开始时是0,我们已经有了EDI与堆栈值,所以让我们开始设置:

通过这个,我们将ECX设置为零(0x401318)

使用免费工具进行逆向和利用:第11部分

使用免费工具进行逆向和利用:第11部分

有了这个,我们在EDI中已经有了要拉的堆栈的值,我们只需要在ESI中输入VirtualAlloc的IAT入口地址,这很简单:(0x4013DB)

使用免费工具进行逆向和利用:第11部分

然后跳转到执行函数,然后把缺少的参数放在下面:

使用免费工具进行逆向和利用:第11部分

我必须适应返回,因为当调用返回时,在三个POP之前。

使用免费工具进行逆向和利用:第11部分

所以我将放置三个RET指针,它们类似于NOP,而我们在运行时什么也不做,在上面的图像中,我可以看到0x4018c4上的RET。

使用免费工具进行逆向和利用:第11部分

现在我们提出了所有正确的参数以及处理返回的所有可能性。

我们看到,就像上次一样,他给了我我们授予执行权限的页面的地址。

使用免费工具进行逆向和利用:第11部分

如果我一直看到pop没有问题,我只需要最后一个gadget来跳转来运行我的shellcode所在的堆栈。

使用免费工具进行逆向和利用:第11部分

就在最后一个RET之后,我们缺少一个ESP调用或类似的东西来跳过堆栈运行。

我们将使用一个PUSH ESP-RET,中间有一点垃圾,不做任何事情。

使用免费工具进行逆向和利用:第11部分

这样我们就可以跳转到shellcode,顺利运行。

使用免费工具进行逆向和利用:第11部分

我们已经打败了DEP,反正是在一个简单的案例中,嘿嘿。

我不想删除我们所做的部分,我没有完成工作,因为一切都是实用的,直到什么都行不通,这也让我们学会了错误,就像我们每天工作时一样。

我们将继续进行下一个练习的第12部分,该练习是64位的,我们将按我们在本练习中所做的那样进行ROP。

稍后,我们将看到更复杂的ROP案例,并将缓慢推进。

相关推荐: PHP代码审计小技巧(上)

下面我们会用两篇文章分析从怎么绕过GPC等过滤、字符串常见的安全问题、PHP输入输出流、FUZZ挖掘漏洞以及正则表达式不严谨容易出现的问题等几个方面来介绍一些小技巧。 1.绕过GPC等转义 GPC会自动把我们提交上去的单引号等敏感字符转义掉,这样我们的攻击代码…

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年12月31日03:56:36
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   使用免费工具进行逆向和利用:第11部分https://cn-sec.com/archives/692017.html