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

admin 2022年4月15日10:42:45使用免费工具进行逆向和利用:第17部分已关闭评论98 views字数 10192阅读33分58秒阅读模式

原作者:Ricardo Narvaja

翻译作者:梦幻的彼岸

更新日期:2022年1月21日


用GHIDRA对64位编译的练习2进行逆向分析。

在第16部分中,我们完成了用rop解决包括32位编译的练习2,现在我们将尝试用GHIDRA解决64位的练习,我们已经在前面的教程中安装了GHIDRA。

事实是,这个和第32个比计划的要难,我们的想法是用更容易的来做,然后逐渐提高水平,但是当你为一个exploitme编程时,在你解决它之前,你不知道当你增加一点难度时会有多难,所以这次比较难,也许以后我们会有更容易的。

事实是,我在写教程时解决了这些问题,使其更加真实,有时会让你感到惊讶,就像在这个案例中,64位和32位都非常困难。

但是,好吧,命题是由逆向作者提出的,所以让我们继续解决吧。

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

一旦在GHIDRA中创建了一个新项目,并将可执行文件拖入其中,我看到我检测并加载了符号

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

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

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

一旦完成加载,在右边的函数过滤器中,我们把main放进去,通过双击就可以进入它。

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

你可以通过点击WINDOWS - FUNCTION GRAPH菜单以图形模式查看。

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

有三个CALL,和32位版本一样,这里没有发生什么,问题在f函数里面。

我可以在同一个图形中双击CALL f,它将带我到f函数。

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

我们看到,GHIDRA通过按下鼠标中键可以突出显示一个变量,并显示它被使用的地方。

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

需要适应的一点是,它是如何在函数本身中显示变量和参数的,相对于IDA和传统的想法,它是倒着显示的,在GHIDRA中,如果我们看到这里,缓冲区会填满并向上溢出,返回地址在所有这些之上。

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

在我心目中,它是相反的,正如我在IDA看到的那样。

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

在IDA中,我们看到缓冲区是在返回地址的上面,并且从上到下溢出,在ghidra中,谁也不知道为什么,它是以相反的方式显示的,好像它是向上填充的,这与溢出的想法相反,它是往下掉的,但是还好。

GHIDRA仍然可以选择分析堆栈的静态视图,它看起来应该是这样。

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

在这里,事情看起来是正常的。

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

我们可以看到,在这里,buf缓冲区溢出时,它不会像编译器放在它下面的32位情况下那样步进到pbuf,因此必须小心。

从前面的部分我们已经知道,我们使用GHIDRA,返回地址总是0,所以我编辑它,使它被看到,我把它放在qword类型,因为我们是在64位,这是对应的数据类型。

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

在那里,我们看到BUF有0x400长,然后还有8个字节,然后是返回地址,所以如果我想跳过它,在返回地址之前有0x408个字节。

0x408 * “A” + struct.pack(“<Q”, 0x4142434445464748)

我们可以看到,在这个静态的IDA匹配视图中,您必须发送0x408字节才能访问返回的地址,

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

让我们完成对工作原理的分析。

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

我们看到,用键盘输入的字符用getchar存储在变量my_char中。

然后与0x40进行比较,如果比较结果为 "true "或等于0x40,则通过绿色箭头退出,不再继续loopeando进入RET,如果不等于,则为 "false",继续通过红色箭头。

然后将其与0x10进行比较,如果不等于0x10,则为 "true",并以绿色箭头表示,并将其保存在pbuf的内容中,该内容是指向缓冲区的指针,在每个周期中都会递增,如果等于0x10,则为 "false",并以红色箭头表示到RET。

所以,和以前一样,你不能通过0x10或0x40字符来构建ROP,甚至在shellcode中也不能。

用Ghidra进行反编译

让我们看看它是如何对函数f进行反编译的。

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

他做得很好,一切都是正确的。

我运行脚本并在 MessageBoxA 退出时附加 64 位 x64dbg 并查看字符串,其中一些在 main 中使用并转到那里,然后进入函数 f 并转到它的 RET。

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

我设置一个断点并接受MessageboxA。

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

他在那里停了下来,我们看到这里没有问题,因为pbuf位于缓冲区上方,我不能步过它,所以我直接得到了步进RETURN ADDRESS的机会,所以远比32位的时候容易,我们会看到ROP为我们准备的东西,嘿嘿。

我们可以看到,VirtualAlloc和VirtualProtect没有像32位那样被导入。

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

我们确实导入了GetModuleHandleW和GetProcAddress。

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

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

通过GHIDRA中的SEARCH-FOR STRINGS,我们来搜索kernel32。

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

它在结尾处缺少.dll,而且它在一个没有写入权限的部分,只有当它是完整的,它才会在一个只读的部分服务,我不能把缺少的部分写入那里。

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

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

64位ROPEANDO

我把64位的rp++复制到可执行文件夹

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

我用它来执行。

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

rp-win-x64.exe
--file=ConsoleApplication9.EXE --raw=x64 --rop=10 >pepe2.txt

要把所有的guarde保存到一个文件中,并在Notepad++中打开它。

首先,我看到在返回地址之后到堆栈的末端没有什么空间。

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

在这一小部分空间中,我将无法执行rop,我猜这将是漫长的,因为我必须调用三个Windows apis并建立它们的参数,就像我们在32位版本中做的那样,所以我将回到循环中,看看我是否可以在可写部分(例如,数据部分)输入更多的数据。

它应该返回循环,RAX有一个来自数据部分的值,但是,它应该返回的地址以0x1010结束,嘿嘿,它不仅有一个而且有两个0x10s。

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

所以我不得不拒绝EAX。

下面是一个带有POP RAX-RET的gadget,用于将值传递给RAX。

记住RP++给我显示的是文件偏移量,所以在x64dbg中我可以用GOTO-FILE OFFSET(CTRL+SHIFT+G)进入虚拟地址,并设置RP++给我的值,也就是0xe4a5。

0x0000ea45: pop rax ; ret ; (1 found)

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

0x00000ad7: not rax ; mov qword [0x000000000001C450], rax ; add rsp, 0x20 ; pop rbp ; ret ;(1 found)

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

在这种情况下,我们只找到了NEG EAX,这对我们来说并不适用,所以我们使用NOT RAX,这也同样适用。

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

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

我想看看我在RAX上是否有正确的地址。

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

如果我留在RAX,方向就会被否定,虽然有了ADD RSP这个gadget,我使用了一个宝贵的地方,但是,也没有什么更好的了。

记住,在RAX中必须有一个数据部分的地址,所以我们必须将拒绝的地址移到另一个寄存器中。

0x000013e2: add r9, rax ; add rcx, r8 ; mov rax, r11 ; jmp r9 ; (1 found)

这个小工具很有用,因为RAX加到R9的值上,最后跳到那里,但首先你必须把R9设置为0,并用数据部分的值设置R11,这样它就会在RAX中结束。

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

0x00001abe: movzx r9d, byte [rdx+0x0C] ; mov qword [rax], r8 ; mov dword [rax+0x08], ecx ; mov byte [rax+0x0C], r9L ; ret ; (1 found)

这样就把r9设置为0,没有其他办法,因为RDX指向一个固定的地址,加上0xc总是有0,我可以用它把r9的下半部分设置为0,而且保持为0,如果你必须在一开始就这样做,而且是用可写的RAX。

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

我们可以看到,在执行了这个程序后,我已经在RAX中得到了被否定的地址,在r9中得到了0的值。

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

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

现在我们必须在r11中输入数据部分的地址,以输入我的数据。

0x000119e6: mov r11, qword [rsp+0x08] ; add rsp, 0x10 ; ret; (1 found)

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

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

我的新数据将被保存的地址留在了r11中,现在我必须跳转。

0x000013e2: add r9, rax ; add rcx, r8 ; mov rax, r11 ; jmp r9 ; (1 found)

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

在RAX中,我们得到了我们想要的数据部分的值,我看到的问题是,当循环结束时,它会将值0x438加到RSP中,然后退出堆栈崩溃,让我们在总和上加一个断点,然后首先看看它是否至少输入了我们的数据。

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

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

我们看到数据输入得很好,但当你从RET回来时,它会崩溃,因为堆栈用完了。

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

在我们跳到循环之前,我们必须纠正这一点。

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

在那里我们会调整的

0x00000621: pop rbx ; ret ; (1 found)

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

0x000070e0: mov qword [rbx], rax ; add rsp, 0x20 ; pop rbx ; ret ; (1 found)

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

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

在那里,我们将调整cosascon,这样我们就可以在数据部分得到一个RET或我们想要的东西,当我们弹出RSP-RET将堆栈传递到数据部分时,如果你还没有复制任何东西,请继续运行这个gadget。

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

我们看到,当我们到了最后一条指令时,我们有一个RET存储在数据部分的固定地址。我们要做的不是用RET来代替guardar,而是将这最后一条指令的地址储存在那个固定的地址中,然后跳转到POP RSP这里,让我们看看。

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

我们用最后的跳转代替RET,最后执行的指令将是POP RSP,这样我的堆栈就在最后跳转的固定地址上,纯粹的爆破行为嘿嘿。

0x00003767: pop rsp ; ret ; (1 found)

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

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

在这里我们看到了一个技巧,当我们到达POP RSP时,它将改变最终跳转的值,使其成为新的RSP。

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

因为它的内容是最后一次跳转,所以会跳到那里。

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

但已经有了一个改变的堆栈。

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

我们把更多的数据放在一起,把堆栈的地址和它运行的地方分开一点,这样就不会被从堆栈区域取下的变量所占用,从而保存它们。

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

好吧,我们已经有足够的空间了。

我们可以在你发送的内容后面加入固定地址,Unicode字符串kernel32.dll和ASCII字符串VirtualAlloc,以使事情更简单。

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

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

将它们放在完成复制的0x40之前的末尾。

所以现在我有了固定地址的字符串。

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

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

000000015001D94E 56 69 72 74 75 61 6C 41 6C 6C 6F 63 00 00 00 00 VirtualAlloc....

000000015001D932 6B 00 65 00 72 00 6E 00 65 00 6C 00 33 00 32 00 k.e.r.n.e.l.3.2.

所以它节省了我必须构建字符串的步骤。

点击名字我们看到GetModuleHandleW的IAT地址

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

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

0000000150013078 00007FFF2E47C160 kernel32.GetModuleHandleW

GetProcAddress

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

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

00000001500130E0 00007FFF2E479D60 kernel32.GetProcAddress

让我们搜索一个gadget来调用一个参数为GMHA的函数(打开Windows函数的名称)

0x0000a1cb: mov rax, qword [rax] ; add rsp, 0x28 ; ret; (1 found)

这将把函数的地址从IAT传递到RAX。

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

| 000000015000ADCB | | mov rax,qword ptr ds:[rax] | |
| ------------------ | --- | ---------------------------- | --- |
| 000000015000ADCE | | add rsp,28 | |
| 000000015000ADD2 | | ret | |

我看到的唯一一个通过RCX传递参数的是

0x00001e73: mov rcx, qword [rsp+0x40] ; call rax ;(1 found)

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

看起来返回没有问题,我们将拭目以待。

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

在那里,我不得不调整地址,因为当新堆栈保持非常接近段的开始时,问题就出现了,随着它向上增长,它到达数据部分的上端并中断,所以增加所有的值,以便堆栈保持在下面,这样它在运行时不会步进。

从GMHA回来后,我已经在RAX上有了kernel32的基数。

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

GetProcAdddress有3个参数,我看看如何设置这个调用。

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

RCX需要转到内核32的基地址,RDX需要指向“VirtualAlloc”函数的名称,RAX需要指向GPA函数的地址。

我将用这个GADGET来跳转。

0x0000103b: mov rdx, r13 ; call rax ; (1 found)

Empecemos con poner en r13 el puntero a la string VirtualAlloc que luego se mover a RDX.

0x0000500a: pop r13 ; ret ; (1 found)

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

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

为了使字符串的地址在 rop2 增长时不会移动,我将它们放在它的前面并调整地址。

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

我把它们放在前面,并减去两者的长度,调整了地址。

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

现在我必须把kernel32的基地址从RAX移到RCX。

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

使用我们之前使用的三个gadget将RAX移动到RBX的内容中,我们将在RAX中的基地址保存在我们保存最后跳转的相同地址,所以它不再被使用。

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

它保存在那里,因为没有gadget可以将RAX移动到RCX使用中间的固定地址进行传递,所以现在通过读取保存它的固定地址将其传递到RCX

0x00001a38: mov rcx, qword [rdx] ; mov qword [rax], rcx ; ret ; (1 found)

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

在这里,我找到了唯一能发挥作用的POP RDX,嘿嘿。

0x00001a38: mov rcx, qword [rdx] ; mov qword [rax], rcx ; ret ; (1 found)

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

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

必须通过上一个gadget的add rsp, 20来添加padding,并在RAX中放置一个可写地址,才能使下一个gadget正常工作。

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

否则会在这里中断,在下一行中,RCX也必须是可写的。

RDX已经指向存储基地址的固定地址。

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

我们已经有2/3了,我们只需要在RAX上输入GPA地址。

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

0x0000a1cb: mov rax, qword [rax] ; add rsp, 0x28 ; ret; (1 found)

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

所以在RAX中我必须把GPA=0x1500130e0的IAT地址放在前面。

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

我已经把一切都准备好了。

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

唯一缺少的是跳转gadget

0x0000103b: mov rdx, r13 ; call rax ; (1 found)

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

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

让我们看看它是否有效。

MICROSOFTIANOS技巧

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

所有的参数都没问题,但在RAX中不工作,它应该返回VirtualAlloc的地址,发生了什么????

根据我的经验,当你传递了所有的参数而调用不成功时,有两个原因。

1)有点不协调

2)一些apis,尤其是64位的apis,会检查堆栈是否是原始的,否则会出现错误。

来排除这些字符串。

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

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

在那里,我们可以看到对齐的字符串,它们的指针以0结尾,或者是8的倍数(64位)。

我又试了一下,发现还是不行。

我要测试是否是堆栈的问题,我到了调用的时候。.

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

我看了看内存图,看看主堆栈在哪里。

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

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

我正在查找中间堆栈地址,然后将ESP更改为该地址。

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

这是一个正确且对齐的堆栈地址,按f8。

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

我们看到它是有效的,所以我们需要解决这个问题,对此有几种可能性。

MICROSOFT注意:这并不能阻止任何人完成他们的ROP只需要一段时间,我认为这是没有用的。

在更改堆栈的RSP弹出窗口之前,我们将尝试从原始堆栈中保存一些地址。

0x00001033: lea rcx, qword [rsp+0x30] ; add rax, r12 ; mov rdx, r13 ; call rax ; (1 found)

我们将使用相同的 gadget

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

我们将设置RAX跳转到RET,RCX将留下一个堆栈地址。

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

如果我把它夹在那里,堆栈的一个地址就会保留在RCX中,但当我们返回到循环时,它就会丢失,因为循环使用ECX,我们必须在返回LOOP前把它保存在另一个寄存器或某个固定地址中。

0x00001a39: mov ecx, dword [rdx] ; mov qword [rax], rcx ; ret ; (1 found)

在那里我们看到,它保存在一个我们可以选择查看的地址中。

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

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

在这里,它将堆栈地址保存在一个固定的地址,就在我保存最后跳转地址之前。

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

这是一个完整的移植,我看到我现在得到的调用与原始RSP保存在固定的地址。

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

寻找一个程序不会访问的空地址来保存堆栈地址。

然后在第一个ROP中添加更多的数据,这样保存的堆栈地址就指向我的数据,以便在我使用它时从中删除。

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

所以,如果我把堆栈换成原来的堆栈,我可以从那里继续运行。

我将把调用GPA换成这个,这样我可以更好地返回。

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

在RAX中我已经有GPA地址,在RCX中我已经有基地址,我只需要从R13到RDX将指针传递到字符串VirtualAddress。

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

我们本可以使用它,因为它将R13移动到RDX,并且已经直接调用API,但是使用gadget就不那么容易了,您必须将具有基地址的RCX中的保存值移动到RBX,否则您会步过它,我们就会丢失它。

我们将用这个从R13移到RDX

0x0000116c: mov rdx, r13 ; add r8, r12 ; call r8 ;(1 found)

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

设置R12

0x00003766: pop r12 ; ret ; (1 found)

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

我们必须对总和进行弥补,因为R8的值是2。

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

从那里出来的是什么

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

弥补

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

我们已经有了参数和地址的正确形式,可以跳转到。

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

我们只剩下恢复RSP了。

0x00008e66: mov rsp, r11 ; pop rbp ; ret ; (1 found)

0x000119e6: mov r11, qword [rsp+0x08] ; add rsp, 0x10 ; ret; (1 found)

使用这个块恢复了RAX中的原始堆栈地址

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

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

现在我们可以在POP RSP之前将其保存到当前堆栈中以恢复它。

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

这是RAX中的值,我将把它保存到我当前的堆栈中。

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

我得到了旧的GPA调用,所有的参数都很好,我在堆栈中有我从原始堆栈保存的地址,所以我将用POP RSP -RET替换这个指令来恢复堆栈。

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

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

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

在那里我恢复了它,但我没有像我想的那样呆在AAAA,我会调整它

0x00007017: and eax, esi ; mov rsi, qword [rsp+0x38] ; add rsp, 0x20 ; pop rdi ; ret ; (1 found)

如果我在保存原始堆栈地址之前使用此gadget正确设置了 ESI,您可以将其调整为更高,就在我的 Aes 所在的位置。

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

0x00001fb5: pop rsi ; ret ; (1 found)

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

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

我看到如果我输入 RSI=0xFFFFFFFFFFFFFB00 堆栈将在AES的区域内继续被调用。

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

如何添加gadgets

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

我必须将保存原始堆栈地址的位置再往下移动一点。

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

现在,如果我恢复原来的堆栈,我就有了正确的参数,并且我可以在第一个ROP上继续执行。

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

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

现在我继续,我有一个很好的位置,我会把这个ROP3放进去,我会看到它不会影响0x408的长度,而是会影响下一步。

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

从0x50开始。

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

这样一来,我可以增加ROP3,其余的不会动,只要我不超过最大值(0x408-0x50)。

这是ROP3开始的地方

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

我可以调用CALL RAX,所以我已经完成了GPA调用设置。

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

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

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

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

嘿嘿,拿Microsoft来说吧,有人不得不浪费更多的时间并不是更安全,其他的缓解措施就可以了,这只是让人多走动一下,仅此而已。

最后一部分

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

我必须在RCX中输入要解除保护的地址,在RDX中输入大小,在R8中输入flAllocationType=0x40,在R9中输入fllProtect=0x1000。

0x0000102f: mov eax, dword [rbx+rdi*8+0x0C] ; lea rcx, qword [rsp+0x30] ; add rax, r12 ; mov rdx, r13 ; call rax ; (1 found)

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

有了这些gadget,我把R12调到了零,把R13调到了正合适的大小。

我们看到我有一组gadget,可以让我与RBX交换RAX,反之亦然,我可以将VirtualAlloc的地址传递给RBX,这样我就可以释放出拥有更多gadget的RAX,我将在最后恢复它。

0x00010d92: push rax ; pop rbx ; ret ; (1 found)

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

0x00006f48: mov rax, rbx ; add rsp, 0x20 ; pop rbx ; ret; (1 found)

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

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

现在如果寄存器 r13 和 r12 被设置为 0 和 1,并且 RBX 和 VirtualAlloc 地址被保存。

现在仍然需要设置 r8 和 r9。

R8 flAllocationType = 0x40 并且在 r9 fllProtect = 0x1000。

0x00001a9d: add al, 0xC3 ; nop ; mov ecx, dword [rdx] ; movzx r8d, word [rdx+0x04] ; movzx r9d, byte [rdx+0x06] ; mov dword [rax], ecx ; mov word [rax+0x04], r8w ; mov byte [rax+0x06], r9L ; ret ; (1 found)

这一部分的gadget将允许我设置r8和r9。

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

这一部分允许我POPEAR RDX,但它必须是RAX和RCX可写的,RAX我可以用已经保存了重要的值,所以我在那里改变它,问题是RCX。

rop2+=struct.pack ("<Q",0x000000015000F645) #POP RAX-RET
rop2+=struct.pack ("<Q",0x000000015001Da20) # writable
rop2+=struct.pack ("<Q",0x00000000150012212) # POP RDX

而在这部分中,我使用LEA将RCX的地址改成了堆栈地址,重用以前的部分是很好的,所以将每个部分分块,这样可以重复使用。(记住在重复使用时要记得改变ROP x ROP3,否则会中断所有操作)

rop3+=struct.pack ("<Q",0x000000015000F645) #POP RAX-RET
rop3+=struct.pack ("<Q",0x000000000150001221) #POP RBX - RET para saltear el return address.
rop3+=struct.pack ("<Q",0x0000000150001C33) # MUEVO UNA DIRECCION DEL STACK A rcx USANDO LEA
rop3+=struct.pack ("<Q",0x000001500016F1) #ret padding

rop3+=struct.pack ("<Q",0x000000015000F645) #POP RAX-RET
rop3+=struct.pack ("<Q",0x000000015001Da20) # writable
rop3+=struct.pack ("<Q",0x00000000150012212) # POP RDX

由于我不能传递0x40或0x1000,我将不得不调用两次,以读取可执行文件中这些值的某个地方,并用RDX指向它们,来读取它们。

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

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

首先将r9设置为0x1000

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

利用这一点,我设置RDX并减去0xC来补偿。

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

让我们看看情况如何。

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

Rax必须设置为可写地址,因为它在上一个gadget中设置为零。

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

我们已经有 r9=0x1000

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

现在r8=0x40缺失。

用另一个

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

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

我现在设置了R8和R9。

我有三个参数,RDX必须是1,我可以用刚才的那个块把它设置为1。

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

我必须用VirtualAlloc的RBX中的地址来恢复RAX,用JMP EAX或CALL RAX来跳转,但由于有CALL RBX,我们将看到它是否运行良好。

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

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

将POB RBX更改为POP r12,这样我就不会得到Virtualloc的保存值。

呃,我被搞糊涂了

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

它们是flAllocationtype=0x1000和FlProtect 0x40,仍然没有问题,只是把它读取R8和R9值的地址反过来。

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

在那里它正确地授予了执行权限,但返回中断了,我必须寻找另一个调用。

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

我将从VirtualAlloc检索RAX地址

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

跳转

0x0000eaa4: jmp rax ; (1 found)

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

到达那里,进行跳转。

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

我已经有执行许可了。

我会跳过这些参数使用

0x0000c32a: pop r15 ; pop r14 ; pop r13 ; ret ; (1 found)

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

跳转执行

0x00010c37: push rsp ; and al, 0x08 ; ret ; (1 found)

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

而我们已经在运行!!!!

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

记住,0x41不是一个64位的可执行指令。

现在唯一要做的就是设置一个shellcode。

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

将字符串WinExec添加到你在数据部分输入的数据末尾。

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

我已经可以运行了,所以把字符串的地址移到RCX是非常容易的。

我们记得GetProcAddress的IAT是0x1500130e0,而Kernel32的基地址仍然保存在0x000000015001e4b8中。

我已经得到了WinExec的地址,并在它下面添加了Notepad 的字符串。

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

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

更多MICROSOFT技巧 winexec不起作用

这是我的迷你shellcode,你会说那第二行是做什么用的,嘿嘿,如果你不把它放进去,winexec就不工作了,崩溃了,当你调用WinExec时,堆栈必须对齐到16,这是MICROSOFT在Windows 10 64位中的另一个补丁。

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

堆栈的最低字节必须是双零,否则就会崩溃。

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

我们在那里执行得很顺利

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

当然,如果我关闭所有的Notepad并运行它,就会起作用。

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

我运行它

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

事实是,这一次和第32次都比计划中的要难,我们的想法是用更容易的方式,一点一点地进行,但是当你让它变得更难时,你永远不知道会有多难,所以这次一切都很难,也许以后我们会有更容易的。

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年4月15日10:42:45
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   使用免费工具进行逆向和利用:第17部分http://cn-sec.com/archives/913070.html