Xiaohao's Blog

一切尽在不言中。

初步仿真

服务器两张网卡,对应在vmware中创建两张网卡,配置好后即可rdp连接,便于后面输命令
Pasted image 20260526152057
Pasted image 20260526153803

看服务,FICWEB和PostgreSQL是自动启动的,contained和Docker是手动
Pasted image 20260526154611
Pasted image 20260526154621

计划任务中有Mount VHDX at Startup,会把ROOT.vhdx挂载到T,并在T下创建root和state连个目录。同时启动containerd
 

powershell.exe -NoProfile -ExecutionPolicy Bypass -Command {
Import-Module Hyper-V

$VHDPath = 'C:\Users\Administrator\Documents\ROOT.vhdx'
$DriveLetter = 'T'
$DriveRoot = $DriveLetter + ':\'

Mount-VHD -Path $VHDPath -ErrorAction SilentlyContinue
Start-Sleep -Seconds 3

$disk = Get-VHD -Path $VHDPath | Get-Disk

if ($disk.IsOffline) {
Set-Disk -Number $disk.Number -IsOffline $false
}

if ($disk.IsReadOnly) {
Set-Disk -Number $disk.Number -IsReadOnly $false
}

$partition = $disk |
Get-Partition |
Where-Object { $_.Type -ne 'Reserved' } |
Select-Object -First 1

if ($partition.AccessPaths -notcontains $DriveRoot) {
Add-PartitionAccessPath `
-DiskNumber $disk.Number `
-PartitionNumber $partition.PartitionNumber `
-AccessPath $DriveRoot
}

for ($i = 0; $i -lt 60; $i++) {
if (Test-Path $DriveRoot) {
break
}

Start-Sleep -Seconds 1
}

if (-not (Test-Path $DriveRoot)) {
throw 'T drive not available after mounting VHDX'
}

New-Item -ItemType Directory -Force ($DriveRoot + 'root') | Out-Null
New-Item -ItemType Directory -Force ($DriveRoot + 'state') | Out-Null

Start-Service containerd
}

计划任务是开机自启动的,启动后可以直接看见有:
Pasted image 20260526163725

nerdctl ps -a可以看到当前启动的容器,postgres已启动
Pasted image 20260526164157

然后启动网站,直接运行exe启动会报错,用sc.exe可以启动

PS C:\FIC_WEB> sc.exe start FicWeb

SERVICE_NAME: FicWeb
TYPE : 10 WIN32_OWN_PROCESS
STATE : 2 START_PENDING
(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x7d0
PID : 5964
FLAGS :
PS C:\FIC_WEB> sc.exe query FicWeb

SERVICE_NAME: FicWeb
TYPE : 10 WIN32_OWN_PROCESS
STATE : 4 RUNNING
(STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0

然后直接用ip访问不到,要改hosts并配置本地dns才能启动
先改hosts
172.28.0.100 admin.ficads.site
172.28.0.100 mtls.ficads.site
172.27.0.100 ficads.site
Pasted image 20260527221633

然后会发现后台还是连不上,是因为这里走的是http3,对应的传输层是QUIC,基于UDP。
Pasted image 20260526201223

用这个方式启动,强制这个域名走QUIC:

$chrome = 'C:\Program Files\Google\Chrome\Application\chrome.exe'
$profile = "$env:TEMP\fic-admin-http3-profile"

Start-Process -FilePath $chrome -ArgumentList @(
'--user-data-dir=' + $profile,
'--origin-to-force-quic-on=admin.ficads.site:443',
'--host-resolver-rules="MAP admin.ficads.site 172.28.0.100, MAP mtls.ficads.site 172.28.0.100"',
'https://admin.ficads.site/'
)

Pasted image 20260526221817
登录后面再说

题目部分

1. 分析服务器检材,系统分区的文件系统类型是?

【参考格式:FAT32】

ReFS

fsutil fsinfo volumeInfo C:

2. 分析服务器检材,系统分区的文件系统版本是多少?

(格式:1.23)

3.14

fsutil fsinfo refsInfo C:

3. 分析服务器检材,系统的 SKU 编号(OperatingSystemSKU)是什么?

【参考格式:101】

407

Get-CimInstance Win32_OperatingSystem | select Caption,OperatingSystemSKU
这个编号的意思是windows操作系统版本的内部编号

4. 服务器中的 WinRM HTTP 服务的端口是多少?

(格式:65535)

59508

PS C:\FIC_WEB> winrm enumerate winrm/config/listener
Listener
Address = IP:172.28.0.100
Transport = HTTP
Port = 59508
Hostname
Enabled = true
URLPrefix = wsman
CertificateThumbprint
ListeningOn = 172.28.0.100

不能单纯看winrm get config,这个只会打印默认的端口,这里需要查看实际的监听器端口

5. 最后一次通过 WinRM 远程访问的北京时间是?

(格式:1970-01-01 00:11:22)

2026-05-17 16:38:06

查看这个日志Microsoft-Windows-WinRM/Operational

Get-WinEvent -LogName 'Microsoft-Windows-WinRM/Operational' |
Where-Object { $_.Id -eq 91 } |
Sort-Object TimeCreated -Descending |
Select-Object -First 1 TimeCreated, Id, Message

Pasted image 20260526224921

比赛的时候没有ai,写不了这么复杂的powershell命令,可以打印日志,找出最后一条连接日志
Get-WinEvent -LogName 'Microsoft-Windows-WinRM/Operational'
Pasted image 20260526225204

或者看evtx文件也可以,连接事件对应的id为91,request handling/分区6/Windows/System32/winevt/Logs/Microsoft-Windows-WinRM%4Operational.evtx

最上面一条就是
Pasted image 20260526230538
Pasted image 20260526231202

6. 服务器除了允许上一题登录记录的 IP 地址远程登录,还允许哪个 IP 地址远程管理?

(格式:1.2.3.4)

117.184.20.123

先看看上面一题登录的ip是多少,evtx文件里面可以找到,218.80.0.18
Pasted image 20260526233456

然后这个肯定和防火墙规则有关,可以直接看SYSTEM文件,找到59508端口相关的防火墙配置
Pasted image 20260526232844
下面两条就是RemoteAddress,218.80.0.18和117.184.20.123

或者直接输入命令过滤查看

Get-NetFirewallPortFilter |
Where-Object LocalPort -eq 59508 |
Get-NetFirewallRule |
ForEach-Object {
$_ | Get-NetFirewallAddressFilter | Select-Object LocalAddress, RemoteAddress
}

Pasted image 20260526233153

那么这题就是117.184.20.123

7. 主机 secrets 目录中存放有一批密码文档,找到存在历史快照版本的文件,该文件历史版本中存放的密码是什么?

(格式:Abc123!@#)

pMLCzXOd+<.&.pUw

这两题考点是ReFS文件系统文件流的快照,有关ReFS文件系统的流,要用refsutil streamsnapshot工具来查看。这个结构和NTFS ADS流蛮像的,只不过Refs的流一般更偏向于文件快照,ADS流更偏向附加数据

查看流

Get-ChildItem . -File -Recurse | ForEach-Object {
$f = $_
Get-Item -LiteralPath $f.FullName -Stream * |
Where-Object Stream -like '*:$SNAPSHOT' |
Select-Object @{n='File';e={$f.FullName}}, Stream, Length
}

Pasted image 20260526235121
发现secret012存在一个快照

导出

$srcFile = 'C:\Users\Administrator\secrets\secret_012.docx'
$streamName = 'snapshot_sec'
$dstFile = 'C:\Users\Administrator\secrets\secret_012.snapshot.docx'

$data = Get-Content -LiteralPath $srcFile -Stream $streamName -Encoding Byte -Raw
[System.IO.File]::WriteAllBytes($dstFile, $data)

利用给的管理员密码smb上去Copy-Item即可

#要开一下防火墙
Enable-NetFirewallRule -Name FPS-SMB-In-TCP

cmdkey /add:172.28.0.100 /user:Administrator /pass:F1cWinC@re

Get-ChildItem '\\172.28.0.100\c$\Users\Administrator\secrets'

Copy-Item '\\172.28.0.100\c$\Users\Administrator\secrets\secret_012.snapshot.docx' 'secret_012.snapshot.docx' -Force

Pasted image 20260527002606

8. 嫌疑人称,服务器中曾安装有 Linux 虚拟机用于下载合同文件,其中存有一份加密的合同文件,找到这个文件,计算文件的 MD5 值。

(格式:d41d8cd98f00b204e9800998ecf8427e)

921A242639D1A13F6D6BFA47D9EB34D5

题目说的linux虚拟机肯定是fedora-coreos-44.20260419.3.1-hyperv.x86_64.vhdx这个hyperv虚拟机,但是同时,可以看到很多avhd快照文件。对于hyperv快照来说,生成的是差分盘,快照中只保留修改的内容。

这个题要恢复,得还原出每个快照的状态。
Pasted image 20260527113947

查看所有磁盘的父盘信息Get-VHD -Path * | Format-List Path, ParentPath
Pasted image 20260527120036

整理一下,目标的合同文件有可能是在中间节点出现的,所以最好恢复所有的状态,应该一共是7个状态,一个一个看。

根盘 vhdx
└── C03E3EEC
├── 9F02D431
│ └── 6994585D
└── FF7E62B2
└── D451E349
└── F5DEFE8C

一个一个还原就行

Copy-Item C:\Users\Administrator\VM C:\Users\Administrator\VM_C03E3EEC -Recurse
cd C:\Users\Administrator\VM_C03E3EEC

Merge-VHD -Path .\fedora-coreos-44.20260419.3.1-hyperv.x86_64_C03E3EEC-C39B-4BDA-8F2E-8A69C216E73F.avhdx `
-DestinationPath .\fedora-coreos-44.20260419.3.1-hyperv.x86_64.vhdx

Copy-Item .\fedora-coreos-44.20260419.3.1-hyperv.x86_64.vhdx C:\Users\Administrator\C03E3EEC_state.vhdx

Pasted image 20260527164107

翻一下文件系统,或者直接搜合同,在这两个状态中找到加密的文件
Pasted image 20260527170320

Pasted image 20260527170308
计算md5即可,921A242639D1A13F6D6BFA47D9EB34D5

9. 管理后台页面的 TLS 证书的 SHA1 指纹是什么?

(格式:da39a3ee5e6b4b0d3255bfef95601890afd80709)

248424A5234D539CBF0425751A437ADCC106D835

/分区6/FIC_WEB/appsettings.json,有网站证书相关的配置
Pasted image 20260527183232
刚刚我们仿真的网站也可以看到
Pasted image 20260527183426

这张证书对应的sha1是248424A5234D539CBF0425751A437ADCC106D835
Pasted image 20260527184414

10. 广告页面提供服务的网卡 MAC 地址是什么?

(格式:11:22:33:aa:bb:cc)

00:15:5d:19:96:2c

还是网站配置文件,publiclistenip监听的是172.27.0.1这张,也就是广告页面。实际上ipconfig看不见这个ip,但是前面网段是一样的,猜测大概率对应的是172.27.0.100这张网卡。
Pasted image 20260527185614
Pasted image 20260527221153
逆向网站exe程序应该也行,但是ida打开全是修饰符……

11. 管理员在北京时间 2026-05-01 12:23:21 通过聊天工具向他人发送过一个验证码,计算管理员在这个时间登录管理后台需要使用的验证码是否与聊天记录中的验证码相同,这个时间的验证码是?

(格式:12345678)

65625

https://admin.ficads.site/login这个后台这里,要求TOTP动态码和客户端证书,那么这道题目应该考察的就是TOTP的还原。
Pasted image 20260527221504

首先要找key,从下面第15题可以得到数据库密码yiZvGzBS9FYxrw42J17LNUK5tlDo(详细过程见15题),然后本机可以直接连接的
Pasted image 20260527233225
admin_top_secrets表中找到对应的secret为JBSWY3DPEHPK3PXP,这个secret是可以长时间复用的,数据库中这个key生成的时间是4月20日
Pasted image 20260528114358
比较坑的是,这个网站的2FA认证使用的不是默认的6位验证码,而是5位。这点需要逆向网站程序看出。

网站是.NET,用dnSpy或者ILSpy可以直接反编译,很好定位TOTP的逻辑,在TotpService,规定了验证码长度为5
Pasted image 20260528225435

然后根据题目的时间计算TOTP

import pyotp
import datetime
import pytz
SECRET = "JBSWY3DPEHPK3PXP"
totp = pyotp.TOTP(SECRET, digits=5)

beijing_tz = pytz.timezone('Asia/Shanghai')
target_time = beijing_tz.localize(datetime.datetime(2026, 5, 1, 12, 23, 21))
timestamp = target_time.timestamp()

print(totp.at(timestamp))
#65625

12. 从现场扣押的证书文件中寻找网站管理员登录后台使用的证书,正确的证书文件的 SHA1 哈希是什么?

(格式:da39a3ee5e6b4b0d3255bfef95601890afd80709)

c48b687f0ffca44b626f1794bb6cb81ca8c8df9f

还是在pg数据库中,数据库的admin_client_certificates记录了证书的信息
Pasted image 20260528162425
证书指纹为F628659F0D2B175736B049FAC1D0659AF81033B82DB071CF4D201FF70F4DCA8B,在对应的附件文件夹找到

from pathlib import Path
import hashlib
from cryptography import x509
from cryptography.hazmat.backends import default_backend

target_fingerprint = "F628659F0D2B175736B049FAC1D0659AF81033B82DB071CF4D201FF70F4DCA8B"
search_dir = Path(r"E:\Admin\Desktop\附件3")

for cert_file in search_dir.glob("*.cer"):
data = cert_file.read_bytes()
sha256 = hashlib.sha256(data).hexdigest().upper()
sha1 = hashlib.sha1(data).hexdigest().upper()

if sha256 == target_fingerprint:
cert = x509.load_der_x509_certificate(data, default_backend())
print("找到证书:", cert_file)
print("SHA256 :", sha256)
print("SHA1 :", sha1.lower())

找到对应的证书candidate-17.cer,直接打开也能看到,windows默认显示的就是sha1指纹
Pasted image 20260528164838

13. 使用证书文件登录推广管理网站后台,管理员登录后网站右上角的 flag 是什么?

(格式:flag{abc_123_!@#})

flag{fic_mtls_2a10229ccc830e737cb54993}

登录需要使用证书+TOTP

先计算当前时间的TOTP验证码,注意服务器时间要和本机时间一样

import pyotp
import time

SECRET = "JBSWY3DPEHPK3PXP"

totp = pyotp.TOTP(SECRET, digits=5)
print(totp.now())

证书没找到私钥,给的附件只有公钥。留个坑 感觉呼之欲出了。

14. 现在需要从现场扣押的硬件密钥中寻找网站管理员登录后台使用的硬件密钥,网站管理员登录后台使用的硬件密钥中存储的凭据 ID 是什么?

(格式:8914d73ee5522094906733031a76bb04e915e9e577ad92e0abe78428bd9dad9c8ac78412819373191547b199fbc0914d)

依旧读取数据库,在admin_webauthn_credentials中有相关的数据
Pasted image 20260528230746
只有5月17日这一条有使用记录,对应的crendential_id为RTw2QDlgJEtCae7XAyFIwQT6EnIJJiElrq6AGONvJerdOtmZKKv5ayP3OgqQjjrc,但是这里格式不一样,实际上应该是base64进行存储,编码转换一下即可
Pasted image 20260528230844
453c36403960244b4269eed7032148c104fa127209262125aeae8018e36f25eadd3ad99928abf96b23f73a0a908e3adc

15. 运行网站数据库的容器中,容器内部操作系统版本是?

(格式:25H2)

24H2

postgresql运行在容器中,是一个windows系统,要查看容器内部的操作系统版本,进入容器查看即可。
Pasted image 20260527222925

nerdctl exec -it f4404 pwsh直接这样进入容器没法直接进入shell,会阻塞在容器的启动程序中。创建一个新的临时容器进入

nerdctl run --rm -it --entrypoint pwsh docker.io/innovesys/postgresql-windows:18-nanoserver-ltsc2025

Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" DisplayVersion

拿到OS: Microsoft Windows 10.0.26100,对应的是24H2

16. 推广管理网站使用的 PostgreSQL 数据库版本是多少?

(格式:16.1)

18.0

直接看pgdata下的PG_VERSION并不能确定pg数据库的小版本,具体的还是要成功连接数据库后执行命令SELECT version()查看
PostgreSQL 18.0 on x86_64-windows, compiled by msvc-19.44.35215, 64-bit
Pasted image 20260528003908

17. 推广管理网站连接 PostgreSQL 数据库使用的密码是什么?

(格式:Abc123$%^)

yiZvGzBS9FYxrw42J17LNUK5tlDo

这题实际上是整套题的关键。没有这个数据库密码,后半部分的题目都做不了。
我尝试使用容器启动的环境变量里的密码连接(实际上我比赛的时候也是把这个当做密码了),一直连不上,实际上这个只是初始化数据库的密码,不是实际密码。

然后发现可以mimikatz抓。

#如果没开防火墙:Test-NetConnection 172.27.0.100 -Port 445

cmdkey /add:172.27.0.100 /user:Administrator /pass:F1cWinC@re

Copy-Item 'mimikatz.exe' '\\172.27.0.100\c$\Users\Administrator\mimikatz.exe' -Force

然后会发现传上去之后马上就被删了,也没法运行,是有defender
Pasted image 20260528234458
要先把defender关了

Set-MpPreference -DisableRealtimeMonitoring $true

然后就可以抓了

token::elevate
vault::cred

Pasted image 20260528234840
数据库密码为yiZvGzBS9FYxrw42J17LNUK5tlDo

18. 根据推广网站的推荐算法,在北京时间 2026 年 5 月 1 日 12:34:56 时,上海的 IP 地址通过 huajian026.chat-now.vip 访问 https://ficads.site/p/026 的广告页面时,最有可能推荐的应用包名是什么?

com.fic.seed.chatlive095

在数据库里并没有找到对应的数据,找一下会发现实际上这里是调用fic.resolve_promotion_payload_at这个存储过程,一样的参数传回去

select * from fic.resolve_promotion_payload_at('huajian026.chat-now.vip','/p/026','上海',timestamptz '2026-05-01 12:34:56+08');

Pasted image 20260527234904

19. fic.traffic_counters 记录了推广源、APK 和日期维度的访问计数。请找出全量 visit 流量中,累计访问量最高的 host + package_name 组合对应 APK 的 apk_sha256 字段值为?

(格式:27AE41E4649B934CA495991B7852B855)

65EA7D9DDB135EF977CA28F7E046D705

traffic_counters表本身并没有host和apk_sha256字段,这里要聚合

apk_targets中有apk_sha256
Pasted image 20260528001048

promotion_sources中有host字段
Pasted image 20260528001131

使用相关的表连接字段(id,source_id)连接即可,累计访问量对应的字段是total_count
Pasted image 20260528000613

20. 数据库中删除过一条创建时间为北京时间 2026-05-13 10:30:00 的 admin 用户的 passkey 信息,请恢复这条记录,credential_id 字段的内容是什么?

(格式:ASNFZ4mrze_-3LqYdlQyEA)

PV0o_BzQptB90kmn8I_9VZxw_LKnIJ8IyqSAWOvAtlc

检材中有完整的pg_data数据库文件,我这里把它复制出来在本地做。题目提到的字段是在fic.admin_webauthn_credentials表中,因此恢复wal文件的时候只需要找和这张表有关的记录即可,对应的参数为-R 1663/42852/42994,分别表示表空间、数据库、表名的OID

经过尝试,只有0E这个wal文件可以恢复出数据,其余两个不行

& 'E:\PostgreSQL\18\bin\pg_waldump.exe' `
-p 'E:\Admin\Desktop\pgdata\pg_wal' `
-R 1663/42852/42994 `
00000001000000000000000E

Pasted image 20260528112136
Pasted image 20260528112235

可以看到几条删除的记录,但是具体的信息看不懂。到这里就借助一下ai了
关键的是这一条记录,FPW代表有完整页镜像

rmgr: Heap        len (rec/tot):     59/  8047, tx:        908, lsn: 0/0E0732F0, prev 0/0E0732B8, desc: DELETE xmax: 908, off: 1, infobits: [KEYS_UPDATED], flags: 0x00, blkref #0: rel 1663/42852/42994 blk 0 FPW

导出

$dir='E:\Admin\Desktop\pgdata\fpw_extract'
if (Test-Path $dir) { Remove-Item -LiteralPath $dir -Recurse -Force }
New-Item -ItemType Directory -Path $dir | Out-Null

& 'E:\PostgreSQL\18\bin\pg_waldump.exe' `
-p 'E:\Admin\Desktop\pgdata\pg_wal' `
-R 1663/42852/42994 `
-B 0 `
--save-fullpage=$dir `
00000001000000000000000E

然后想办法去读这个镜像的内容,先起一个临时的pg数据库

& 'E:\PostgreSQL\18\bin\pg_ctl.exe' `
-D 'E:\Admin\Desktop\pgdata_recover' `
-l 'E:\Admin\Desktop\pgdata_recover\startup.log' `
-o "-p 55432 -c listen_addresses=127.0.0.1 -c hba_file=E:/Admin/Desktop/pgdata/pg_hba_trust.conf" `
start -w

解析

& 'E:\PostgreSQL\18\bin\psql.exe' -h 127.0.0.1 -p 55432 -U postgres -d ficweb -F '|' -Atc "select lp, lp_flags, t_xmin, t_xmax, t_ctid, encode(t_attrs[1],'escape') as credential_id, encode(t_attrs[2],'hex') as admin_user_id_hex, encode(t_attrs[3],'escape') as factor_kind, (timestamp with time zone '2000-01-01 00:00:00+00' + (((get_byte(t_attrs[10],0)::bigint) + (get_byte(t_attrs[10],1)::bigint<<8) + (get_byte(t_attrs[10],2)::bigint<<16) + (get_byte(t_attrs[10],3)::bigint<<24) + (get_byte(t_attrs[10],4)::bigint<<32) + (get_byte(t_attrs[10],5)::bigint<<40) + (get_byte(t_attrs[10],6)::bigint<<48) + (get_byte(t_attrs[10],7)::bigint<<56))::text || ' microseconds')::interval) as created_at from heap_page_item_attrs(pg_read_binary_file('E:/Admin/Desktop/pgdata/fpw_extract/00000001-00000000-0E0732F0.1663.42852.42994.0_main',0,8192,true), 'fic.admin_webauthn_credentials'::regclass, true) order by lp;"

Pasted image 20260528112759
第一条的时间对上了,答案为PV0o_BzQptB90kmn8I_9VZxw_LKnIJ8IyqSAWOvAtlc

文章作者: Xiaohao

文章链接: https://blog.enxiaohao.cn/posts/Forensics/2026FICFinalWinserverwp/

版权声明:除另有声明外,本博客文章均采用 CC BY-NC-SA 4.0 许可协议。转载请注明原作者与文章出处。

2026盘古石杯初赛 介质&物联网汽车部分 WriteUp «
上一篇 «
None
» 下一篇