使用 Vulnserver 进行尖峰攻击

以下注释是在 Windows 10 VM 上使用 VulnserverImmunity Debugger 时创建的。

设置

在易受攻击的 Windows 虚拟机上安装 Vulnserver 和 Immunity Debugger 后,使用 ipconfig 查找虚拟机的 IP 地址。验证您的攻击盒和易受攻击的盒可以相互通信(使用 ping)。

然后你可以使用 netcat 从你的攻击箱连接到 Vulnserver:

1
2
3
4
┌──(hakcypuppy㉿kali)-[~]
└─$ nc -nv $t 9999
(UNKNOWN) [10.0.2.15] 9999 (?) open
Welcome to Vulnerable Server! Enter HELP for help.
  • -n:仅代表数字连接(netcat 将需要 IP 地址和端口)
  • -v:代表详细
  • 9999 是 Vulnserver 将在 Windows 框中侦听的端口

命令

现在您已连接,请使用 HELP 获取命令列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
┌──(hakcypuppy㉿kali)-[~]
└─$ nc -nv $t 9999
(UNKNOWN) [10.0.2.15] 9999 (?) open
Welcome to Vulnerable Server! Enter HELP for help.
HELP
Valid Commands:
HELP
STATS [stat_value]
RTIME [rtime_value]
LTIME [ltime_value]
SRUN [srun_value]
TRUN [trun_value]
GMON [gmon_value]
GDOG [gdog_value]
KSTET [kstet_value]
GTER [gter_value]
HTER [hter_value]
LTER [lter_value]
KSTAN [lstan_value]
EXIT

尖峰命令

列出的每个命令都可以被“尖刺”,以查明它们是否容易受到缓冲区溢出的影响。缓冲区溢出的要点是覆盖堆栈上保存的 RIP/ EIP,以便我们可以劫持执行流。

保存的 EIP 是在调用代码中的函数之前压入堆栈的帧(并且其自身的帧被压入堆栈)。保存的EIP的作用是告诉CPU在被调用的函数执行完毕后从哪里恢复执行。如果我们可以溢出保存的 EIP,那么我们可以用我们知道的堆栈上的地址替换它保存的值,该地址保存着我们自己的恶意代码。这样,当 CPU 读取保存的 EIP 中的值时,它将转到我们放置在那里的地址,该地址将其带到我们的恶意代码(并且它将开始执行它)。

Spiking 会告诉我们哪些命令容易受到攻击,因为如果我们能够用垃圾数据覆盖保存的 RIP ,程序就会崩溃。因此,我们正在寻找哪个命令会导致我们覆盖易受攻击的程序崩溃。

为了测试每个命令,我们可以使用 generic_send_tcp,Kali 上的命令/程序:

1
2
3
4
5
┌──(hakcypuppy㉿kali)-[~]
└─$ generic_send_tcp
argc=1
Usage: ./generic_send_tcp host port spike_script SKIPVAR SKIPSTR
./generic_send_tcp 192.168.1.100 701 something.spk 0 0

定位 STATS 命令

STATS 命令开始,我们需要一个尖峰脚本提供给 generic... 来测试它。脚本所要做的就是:

  • .spk 扩展名命名
  • 读一行
  • 创建一个字符串(在本例中为 "STATS"
  • 将变量发送到命令 (STATS)
1
2
3
4
#!stats.spk:
$_readline();
$_string("STATS");
$_string_variable("0"); # <--- variable to send

generic_send_tcp 将获取我们的脚本并使用它向 STATS 命令发送各种长度的字符串(全部用“0”填充)直到程序中断

尖峰:

创建脚本后,现在我们可以使用 generic_tcp_send_tcp 命令将其发送到 Vulnserver 上托管的程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
generic_send_tcp 10.0.2.15 9999 stats.spk 0 0
Total Number of Strings is 681
Fuzzing
Fuzzing Variable 0:0
Fuzzing Variable 0:1
Variablesize= 5004
Fuzzing Variable 0:2
Variablesize= 5005
...
Fuzzing Variable 0:436
Couldn't tcp connect to target
Variablesize= 1024
tried to send to a closed socket!
Fuzzing Variable 0:437
Couldn't tcp connect to target
^C # <--- kill

在输出中,我们可以看到 generic_send_tcp 正在将大小不断增加的变量发送到主机的 STATS 命令。在某些时候,它开始因 Couldn't tcp connect to target 输出消息而失败。我们可以在这里结束该过程(尽管通常您会等到它自行完成)。

从这个输出我们知道*STATS命令不容易受到攻击*。我们还可以看看 Immunity Debugger。如果程序崩溃了,我们可以在调试器中看到它。

定位 TRUN 命令

对于 TRUN 我们将做同样的事情,除了将 s_string() 变量参数更改为 "TRUN " 。让我们发送它(以同样的方式):

1
generic_send_tcp $t 9999 trun.spk 0 0

这次当我们运行命令时,免疫调试器显示 vulnserver 进程暂停并显示访问冲突。这意味着我们能够使漏洞服务器崩溃。这告诉我们 TRUN 命令容易受到攻击。

在 Immunity Debugger 中,如果我们查看寄存器,我们可以看到为 TRUN 命令分配的缓冲区*已溢出,没有 A 字符。*堆栈 (ESP) 和基址 (EBP) 指针也已在堆栈上溢出。

如果我们查看 EIP 寄存器中当前保存的值,我们会看到 41414141。 ‘41’是A的字符代码,这意味着我们还成功地溢出了指令指针,这是我们的最终目标。

根据堆栈的解剖,堆栈上有一些帧,这些帧围绕保存 TRUN 缓冲区的位置(在其自己的相邻帧中),这些帧保存这些寄存器要设置为的值。将这些寄存器的值保存在堆栈上的目的是在当前“激活帧”完成执行并从堆栈中弹出后“告诉 CPU 在哪里继续执行”。

通过溢出为 TRUN 分配的缓冲区空间,我们按照这些寄存器帧的方向将数据写入堆栈,这就是为什么它们被我们的缓冲区字符覆盖。

现在我们已经找到了一个易受攻击的命令,我们可以继续进行fuzzing

[!资源]