主机发现
┌──(kali㉿kali)-[~]
└─$ nmap 10.216.75.0/24 -sn
Starting Nmap 7.95 ( https://nmap.org ) at 2026-05-08 12:58 CST
Nmap scan report for 10.216.75.183
Host is up (0.0070s latency).
MAC Address: 4E:20:31:25:4A:3C (Unknown)
Nmap scan report for 10.216.75.212
Host is up (0.0019s latency).
MAC Address: 30:E3:A4:48:AC:29 (Unknown)
Nmap scan report for 10.216.75.251
Host is up (0.00042s latency).
MAC Address: 08:00:27:A7:CC:59 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)
Nmap scan report for 10.216.75.81
Host is up.
Nmap done: 256 IP addresses (4 hosts up) scanned in 10.80 seconds靶机IP:10.216.75.251
信息收集
┌──(kali㉿kali)-[~]
└─$ what
──────────────────────────────────────────────────
$ rustscan -a 10.216.75.251 --ulimit 5000 -- -A -sC -sV (exit: 0)
──────────────────────────────────────────────────
结论
目标主机 10.216.75.251 是一台运行着 SSH、两个 HTTP 服务的 Linux 系统,其中 8080 端口标题暗示可能有备份系统或内部应用,值得深入探查。
关键发现
端口 服务 版本/详情
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
22/tcp SSH OpenSSH 8.4p1 Debian 5+deb11u3,支持 RSA/ECDSA/ED25519 密钥
80/tcp HTTP Apache 2.4.62 (Debian),标题“CYBER MINESWEEPER - 赛博扫雷”,支持 GET/HEAD/POST/OPTIONS
8080/tcp HTTP Apache 2.4.62 (Debian),标题“Internal Backup System”,同样支持 GET/HEAD/POST/OPTIONS,且被检测到 http-open-proxy
风险(可能被重定向)
• MAC 地址:08:00:27:A7:CC:59(Oracle VirtualBox),确认是虚拟靶机。
• OS 猜测:Linux 4.15–5.19 / OpenWrt / RouterOS,但未完全确定。
• HTTP 信息:80 端口标题为中文“赛博扫雷”,可能是一个游戏或挑战页面;8080 端口标题“Internal Backup
System”暗示可能存在备份文件泄露或管理后台。
去web看看,这里80、8080都是web页面,扫了一下目录都没什么大收获
80端口
是三个扫雷游戏。
LEVEL 01
很简单的5*5的扫雷,快速过了,得到
# pass1.zip
# 直接解压得到 pass1.txt
pass1:forget
LEVEL 02
10*10的扫雷,不需要受挫了,前端游戏,直接把源码发给ai,写一个js脚本自动计算
(async function autoWin() {
const ROWS = 10, COLS = 10;
const api = (action, extra = '') => fetch('game_level2.php', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: `action=${action}${extra ? '&' + extra : ''}`
}).then(r => r.json());
async function init() {
const data = await api('init');
if (!data.success) throw new Error('init failed');
return data;
}
async function getState() {
const data = await api('getState');
// data: { success, revealed, flagged, minesLeft, values? }
return data;
}
async function reveal(r, c) {
return await api('reveal', `r=${r}&c=${c}`);
}
async function flag(r, c) {
return await api('flag', `r=${r}&c=${c}`);
}
async function solve() {
// 初始化(可能游戏已在进行,我们可以重新init)
await init();
while (true) {
const state = await getState();
if (!state.success) break;
if (state.win) { // getState 可能返回 win?原更新板调用getState,但getState返回的数据中是否有win? 看代码 updateBoard 调用了 getState,但没用 win 字段。胜利是在 handleClick 的 reveal 返回中检测的。所以 getState 可能不返回 win。故我们需要在 reveal 时检查win。
// 也许不需要在这里检查
}
// 构建数字矩阵和已揭示、旗子
const numbers = Array.from({length: ROWS}, () => Array(COLS).fill(null));
if (state.values) {
for (const v of state.values) {
numbers[v.r][v.c] = v.value;
}
}
const revealed = state.revealed; // 二维布尔
const flagged = state.flagged; // 二维布尔
let madeMove = false;
// 遍历每个已揭示的数字格子
for (let r = 0; r < ROWS; r++) {
for (let c = 0; c < COLS; c++) {
if (!revealed[r][c]) continue;
const val = numbers[r][c];
if (val === null || val === -1) continue; // -1是地雷,游戏失败。避免。
// 统计周围8格中的未知格和旗子数
let unknown = 0, flags = 0;
for (let dr = -1; dr <= 1; dr++) {
for (let dc = -1; dc <= 1; dc++) {
if (dr === 0 && dc === 0) continue;
const nr = r + dr, nc = c + dc;
if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS) {
if (revealed[nr][nc]) continue; // 已揭示忽略
if (flagged[nr][nc]) flags++;
else unknown++;
}
}
}
if (val === flags && unknown > 0) {
// 周围所有未知格安全,揭示它们
for (let dr = -1; dr <= 1; dr++) {
for (let dc = -1; dc <= 1; dc++) {
if (dr === 0 && dc === 0) continue;
const nr = r + dr, nc = c + dc;
if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS) {
if (!revealed[nr][nc] && !flagged[nr][nc]) {
const res = await reveal(nr, nc);
if (res.hitMine) {
// 踩雷了,应该不会,因为逻辑是安全的,但可能由于后端与状态不同步?如果发生,返回false表示失败
return false;
}
if (res.win) {
// 赢了!
return { win: true, hint: res.hint, token: res.downloadToken };
}
madeMove = true;
// 更新状态以便继续?由于状态已改变,我们可以退出循环重新获取状态,但需要跳出两层循环。简单做法:设置madeMove并break。
}
}
}
if (madeMove) break;
}
} else if (val - flags === unknown && unknown > 0) {
// 所有未知格是雷,标旗
for (let dr = -1; dr <= 1; dr++) {
for (let dc = -1; dc <= 1; dc++) {
if (dr === 0 && dc === 0) continue;
const nr = r + dr, nc = c + dc;
if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS) {
if (!revealed[nr][nc] && !flagged[nr][nc]) {
await flag(nr, nc);
madeMove = true;
}
}
}
if (madeMove) break;
}
}
if (madeMove) break;
}
if (madeMove) break;
}
// 如果没有可进行的移动,且游戏未胜利(需要检查是否全部非雷已揭示,简单的办法是检查剩余未揭示且未标旗的格子数量是否等于 minesLeft? 若 minesLeft=0 且 未揭示格子全是旗子?实际上胜利条件是所有非雷格子被揭示。我们可以检查 revealed 中 false 且不是 flagged 的格子数目是否大于 minesLeft? 不是,minesLeft 是剩余地雷数,如果未揭示且未标旗格子数等于 minesLeft,可能所有未揭示都是雷,但如果那样,标旗后应自动胜利?不一定。最好还是尝试随机猜测。
if (!madeMove) {
// 猜测:收集所有未揭示且未标旗的格子
const candidates = [];
for (let r = 0; r < ROWS; r++) {
for (let c = 0; c < COLS; c++) {
if (!revealed[r][c] && !flagged[r][c]) {
candidates.push({r, c});
}
}
}
if (candidates.length === 0) {
// 应该已经赢了,但可能getState没有win,我们强制检查?
// 尝试再次 reveal 一个已揭示格子?不能。退出。
break;
}
// 随机选一个
const pick = candidates[Math.floor(Math.random() * candidates.length)];
const res = await reveal(pick.r, pick.c);
if (res.hitMine) {
return false; // 失败
}
if (res.win) {
return { win: true, hint: res.hint, token: res.downloadToken };
}
// 继续循环
}
}
// 如果退出循环,可能无解或胜利未捕获
return false;
}
// 主循环尝试直到胜利
let result = false;
let attempt = 0;
while (!result) {
attempt++;
console.log(`第 ${attempt} 次尝试`);
result = await solve();
if (result === false) {
// 等待游戏重置?solve内部init会重置,但可能需额外等待。
await new Promise(resolve => setTimeout(resolve, 500));
}
}
if (result.win) {
console.log('🎉 胜利!', result.hint);
// 可以触发下载
if (result.token) {
window.location.href = 'download.php?id=2&token=' + encodeURIComponent(result.token);
}
}
})();
放到控制台就得到了hint和pass2.zip
pass2.zip有密码,并且没爆破出来。我们先去做LEVEL 03
LEVEL 03
依旧ai搓个脚本,这次还得考虑到有不可预测的情况,ai还改了两次代码,改成计算+预测概率的版本。
(async function() {
const _alert = window.alert;
window.alert = function(){};
const delay = ms => new Promise(res => setTimeout(res, ms));
const STEP_DELAY = 150;
const RETRY_DELAY = 500;
function clickSafe(r, c) {
if (revealed[r][c] || flagged[r][c]) return;
revealed[r][c] = true;
if (board[r][c] === 0) expandZeros(r, c);
renderBoard();
}
function flagCell(r, c) {
if (revealed[r][c] || flagged[r][c]) return;
flagged[r][c] = true;
minesLeft--;
renderBoard();
}
function checkVictory() {
for (let r = 0; r < ROWS; r++)
for (let c = 0; c < COLS; c++)
if (!revealed[r][c] && board[r][c] !== -1) return false;
return true;
}
function isDead() {
for (let r = 0; r < ROWS; r++)
for (let c = 0; c < COLS; c++)
if (revealed[r][c] && board[r][c] === -1) return true;
return false;
}
// 获取某个格子周围的已翻开数字列表
function getNeighborNumbers(r, c) {
const nums = [];
for (let dr = -1; dr <= 1; dr++) {
for (let dc = -1; dc <= 1; dc++) {
if (dr === 0 && dc === 0) continue;
const nr = r + dr, nc = c + dc;
if (nr>=0 && nr<ROWS && nc>=0 && nc<COLS && revealed[nr][nc] && board[nr][nc] > 0) {
nums.push({r: nr, c: nc, val: board[nr][nc]});
}
}
}
return nums;
}
// 计算某个未知格是雷的概率(基于相邻数字约束)
function calcMineProb(r, c) {
const neighbors = getNeighborNumbers(r, c);
if (neighbors.length === 0) {
// 孤立格子,使用全局剩余雷密度
let totalUnknown = 0;
for (let r = 0; r < ROWS; r++)
for (let c = 0; c < COLS; c++)
if (!revealed[r][c] && !flagged[r][c]) totalUnknown++;
return totalUnknown > 0 ? minesLeft / totalUnknown : 1;
}
let minProb = 1;
for (const nb of neighbors) {
let unknownCount = 0;
let flagCount = 0;
for (let dr = -1; dr <= 1; dr++) {
for (let dc = -1; dc <= 1; dc++) {
if (dr === 0 && dc === 0) continue;
const nr = nb.r + dr, nc = nb.c + dc;
if (nr>=0 && nr<ROWS && nc>=0 && nc<COLS) {
if (!revealed[nr][nc]) {
if (flagged[nr][nc]) flagCount++;
else unknownCount++;
}
}
}
}
const needMines = nb.val - flagCount;
if (needMines < 0) return 1; // 不可能,但作为保护
const prob = unknownCount > 0 ? needMines / unknownCount : 1;
if (prob < minProb) minProb = prob;
}
return minProb;
}
// 智能猜测:选择概率最小的格子
function smartGuess() {
const cands = [];
let minProb = Infinity;
for (let r = 0; r < ROWS; r++) {
for (let c = 0; c < COLS; c++) {
if (!revealed[r][c] && !flagged[r][c]) {
const prob = calcMineProb(r, c);
if (prob < minProb) {
minProb = prob;
cands.length = 0;
cands.push({r, c, prob});
} else if (Math.abs(prob - minProb) < 1e-9) {
cands.push({r, c, prob});
}
}
}
}
if (cands.length === 0) return false;
// 在最低概率的格子中随机选一个
const pick = cands[Math.floor(Math.random() * cands.length)];
console.log(`🧩 猜测格子 (${pick.r},${pick.c}),雷概率 ≈ ${(pick.prob*100).toFixed(1)}%`);
clickSafe(pick.r, pick.c);
return true;
}
// 标准推理一步(同前)
function safeStep() {
for (let r = 0; r < ROWS; r++) {
for (let c = 0; c < COLS; c++) {
if (!revealed[r][c] || board[r][c] <= 0) continue;
const val = board[r][c];
let unknown = [];
let flags = 0;
for (let dr = -1; dr <= 1; dr++) {
for (let dc = -1; dc <= 1; dc++) {
if (dr === 0 && dc === 0) continue;
const nr = r + dr, nc = c + dc;
if (nr>=0 && nr<ROWS && nc>=0 && nc<COLS && !revealed[nr][nc]) {
if (flagged[nr][nc]) flags++;
else unknown.push({r: nr, c: nc});
}
}
}
if (val === flags && unknown.length > 0) {
unknown.forEach(p => clickSafe(p.r, p.c));
return true;
}
if (val - flags === unknown.length && unknown.length > 0) {
unknown.forEach(p => flagCell(p.r, p.c));
return true;
}
}
}
return false;
}
async function solve() {
while (true) {
if (isDead()) {
console.log('💥 踩雷,重新开始...');
initGame();
await delay(RETRY_DELAY);
continue;
}
if (checkVictory()) {
gameOver = true;
try {
const resp = await fetch('set_completion.php?level=3');
const data = await resp.json();
showWinModal(data.success ? data.hint : '');
} catch (e) { showWinModal(''); }
console.log('🎉 通关成功!');
break;
}
let moved = safeStep();
if (!moved) {
console.log('🤔 无推理步,计算概率...');
smartGuess();
}
await delay(STEP_DELAY);
}
}
await solve();
window.alert = _alert;
if (document.getElementById('winModal').classList.contains('active')) {
console.log('⬇️ 正在下载 pass4.zip ...');
downloadKeyLegit();
}
})();这个考虑到太卡了,给改慢了一点,会看到它一个个去做,但是也挺快的,几分钟就好了
得到pass4.zip
还有hint:
快去8080端口看看吧,,有好东西在那里,你会用ftp吗?
pass2:真的有加密吗,不会是假的吧8080端口
直接得到pass5.zip
ZIP解密
目前得到的信息:
- 3个加密zip包+一个直接解开的pass
- 3个hint:
pass4:爆密码是爆不出的,看看文件有多大
快去8080端口看看吧,,有好东西在那里,你会用ftp吗?
pass2:真的有加密吗,不会是假的吧首先我想到了pass2会不会是伪加密:
pass2
十六进制编辑器打开pass2.zip查看:
┌──(kali㉿kali)-[~/tmp]
└─$ xxd pass2.zip
00000000: 504b 0304 1400 0800 0800 6b7f 8c5c 0000 PK........k..\..
00000010: 0000 0000 0000 0000 0000 0900 2000 7061 ............ .pa
00000020: 7373 322e 7478 7475 780b 0001 0400 0000 ss2.txtux.......
00000030: 0004 0000 0000 5554 0d00 07da 50db 69db ......UT....P.i.
00000040: 50db 69c3 50db 692b 482c 2e36 7abf 6756 P.i.P.i+H,.6z.gV
00000050: 4946 2a00 504b 0708 3fa8 515c 0d00 0000 IF*.PK..?.Q\....
00000060: 0b00 0000 504b 0102 1403 1400 0900 0800 ....PK..........
00000070: 6b7f 8c5c 3fa8 515c 0d00 0000 0b00 0000 k..\?.Q\........
00000080: 0900 1800 0000 0000 0000 0000 b681 0000 ................
00000090: 0000 7061 7373 322e 7478 7475 780b 0001 ..pass2.txtux...
000000a0: 0400 0000 0004 0000 0000 5554 0500 01da ..........UT....
000000b0: 50db 6950 4b05 0600 0000 0001 0001 004f P.iPK..........O
000000c0: 0000 0064 0000 0000 00 ...d.....这里涉及到ZIP文件结构。直接问了ai,知道了就是存在伪加密
┌──(kali㉿kali)-[~/tmp]
└─$ what -q "这个zip文件结构有什么问题吗"
──────────────────────────────────────────────────
$ xxd pass2.zip (exit: 0)
──────────────────────────────────────────────────
结论
该 ZIP 文件存在伪加密:本地文件头与中央目录中的加密标志位不一致,导致文件被标记为加密但实际可能未加密。
关键发现
1 本地文件头(偏移 0x06)标志位为 0x0008 → bit3 置位(启用数据描述符),bit0 未置位(无加密)。
2 中央目录条目(偏移 0x70)标志位为 0x0009 → bit0 置位(标记加密),bit3 也置位。
3 伪加密通常通过修改中央目录或本地文件头的加密位实现,导致解压工具要求输入密码,但实际压缩数据并未加密。
4 压缩方式为 0x0008(Deflate),压缩数据大小 13 字节,未压缩大小 11 字节,文件名 pass2.txt,结构其他部分正常。
下一步建议
• 手动修复标志位:用十六进制编辑器将中央目录偏移 0x70 处的 09 00 改为 08 00,然后正常解压。
• 直接解压绕过:尝试使用 unzip -P "" pass2.zip(密码为空)或 7z x pass2.zip(自动检测伪加密)。
• 详细检查:使用 zipdetails 或 zipinfo -v pass2.zip 查看标志细节,确认是否有其他隐藏修按照ai说的修改一下十六进制的加密位然后解压就可得到了。
我这里试一下他说的7z直接检测
┌──(kali㉿kali)-[~/tmp]
└─$ what
──────────────────────────────────────────────────
$ 7z x pass2.zip (exit: 2)
──────────────────────────────────────────────────
一句话结论
pass2.zip 的头信息已损坏,但 7z 仍将其识别为 ZIP 并成功解压出 pass2.txt,需要注意的是 Headers Error
可能暗示文件被故意篡改或有隐写信息。
关键发现
• 退出码 2:表示命令执行过程中出现严重错误(文件格式错误)。
• Headers Error:Zip 文件局部或中心目录头校验失败,常见于文件截断、加密或手工构造的伪 zip。
• 成功解压:尽管报错,7z 仍提取了 pass2.txt(11 字节),说明文件结构基本完整,仅头信息不合法。
• 文件时间:Modified: 2026-04-12 15:59:22,时间在未来,可能为故意设置或线索指向某个日期。
下一步建议
1 立即查看 pass2.txt 内容:可能直接包含密码或其他关键信息。
2 检查 zip 文件是否隐藏其他数据:使用 binwalk 或 hexdump 分析末尾是否有附加数据(如伪加密或隐写)。
3 尝试修复 zip 头:若文件内容不完整,可用 zip -F 或 zip -FF 恢复中心目录。
最短可执行修复命令
# 查看解压出的文件内容
cat pass2.txt
# 同时检查原始 zip 文件的十六进制结构(末尾 100 字节)
xxd pass2.zip | tail -20
# 如果文件需修复,尝试重建中心目录(备份原文件后执行)
zip -FF pass2.zip --out fixed.zip && 7z x fixed.zip
┌──(kali㉿kali)-[~/tmp]
└─$ cat pass2.txt
pass2:the工具直接检测到头信息有错误,但是还是解压成功了,我们成功拿到pass2
pass4 && pass5
我们注意到之前的hint:
Hint: pass4:爆密码是爆不出的,看看文件有多大我们看一看pass4的大小
-rw-rw-r-- 1 kali kali 168 5月 8日 13:43 pass4.zip
-rw-rw-r-- 1 kali kali 151 5月 8日 13:11 pass5.hash
-rw-rw-r-- 1 kali kali 172 4月10日 15:54 pass5.zip
-rw-rw-r-- 1 root root 3.0M 2023年 1月18日 pspy64非常小,那也就是说内容应该就是一个txt文件里面几个字母,就像pass1:forget一样
那么这里有一个方法,也是爆破,但是不是爆破密码。
而是进行CRC碰撞
import binascii
import itertools
import string
import time
target_crc = 0x66b9a733
length = 4
# 假设内容是字母和数字 (如果跑不出来,可以加上 string.punctuation 包含符号)
chars = string.ascii_letters + string.digits
# 计算总可能组合数
total_combinations = len(chars) ** length
print(f"[*] 目标 CRC32: {hex(target_crc)}")
print(f"[*] 字符集大小: {len(chars)} 个字符")
print(f"[*] 猜测长度: {length}")
print(f"[*] 总计需尝试: {total_combinations} 次")
print("[*] 开始爆破,请稍候...\n")
start_time = time.time()
count = 0
for p in itertools.product(chars, repeat=length):
count += 1
# 每 10 万次刷新一次屏幕,防止 IO 拖慢速度
if count % 100000 == 0:
percent = (count / total_combinations) * 100
# \r 表示回到行首,end="" 表示不换行
print(f"\r[~] 进度: {percent:>5.2f}% | 当前尝试: {''.join(p)} | 已跑: {count}/{total_combinations}", end="")
text = ''.join(p).encode('ascii')
if binascii.crc32(text) == target_crc:
end_time = time.time()
print(f"\n\n[+] ===========================================")
print(f"[+] 成功!找到原文内容了: {text.decode('ascii')}")
print(f"[+] 耗时: {end_time - start_time:.2f} 秒")
print(f"[+] ===========================================\n")
exit(0)
print("\n\n[-] 爆破结束,未找到匹配项。可能包含特殊字符?")┌──(kali㉿kali)-[~/tmp]
└─$ python3 zip.py
[*] 目标 CRC32: 0x66b9a733
[*] 字符集大小: 62 个字符
[*] 猜测长度: 4
[*] 总计需尝试: 14776336 次
[*] 开始爆破,请稍候...
[~] 进度: 59.55% | 当前尝试: K5rD | 已跑: 8800000/14776336
[+] ===========================================
[+] 成功!找到原文内容了: LiVe
[+] 耗时: 5.69 秒
[+] ===========================================直接爆破到了,同时我们注意到pass5的长度也只有6字节,同样应该可以爆破,但是这个数量级大了很多,我们直接用c语言写 ,这里注意到一点
<h1>[ 内部备份服务器 - 仅限授权人员 ][a-z]</h1>8080端口这里有一个【a-z】,是不是按时我们内容只包括小写字母,这里缩减了很多范围,加速爆破。我们试试。
#include <stdio.h>
#include <string.h>
#include <zlib.h>
int main() {
// 目标 CRC32
unsigned long target = 0xea86a014;
// 包含大小写和数字
char chars[] = "abcdefghijklmnopqrstuvwxyz";
int len = strlen(chars);
char buf[7] = {0}; // 6个字符 + 1个结束符
printf("[*] 开始 C 语言极限爆破...\n");
for(int i=0; i<len; i++) {
buf[0] = chars[i];
printf("[~] 正在运算以 %c 开头的组合...\n", chars[i]);
for(int j=0; j<len; j++) {
buf[1] = chars[j];
for(int k=0; k<len; k++) {
buf[2] = chars[k];
for(int l=0; l<len; l++) {
buf[3] = chars[l];
for(int m=0; m<len; m++) {
buf[4] = chars[m];
for(int n=0; n<len; n++) {
buf[5] = chars[n];
// 核心 CRC 计算
if (crc32(0L, (const unsigned char*)buf, 6) == target) {
printf("\n[+] ============================\n");
printf("[+] 成功找到内容: %s\n", buf);
printf("[+] ============================\n");
return 0;
}
}
}
}
}
}
}
printf("[-] 未找到匹配项。\n");
return 0;
}编译运行
┌──(kali㉿kali)-[~/tmp]
└─$ gcc zip.c -O3 -lz -o zip
#-O3 开启最高性能优化,-lz 链接 zlib 库
┌──(kali㉿kali)-[~/tmp]
└─$ ./zip
[*] 开始 C 语言极限爆破...
[~] 正在运算以 a 开头的组合...
[~] 正在运算以 b 开头的组合...
[~] 正在运算以 c 开头的组合...
[~] 正在运算以 d 开头的组合...
[~] 正在运算以 e 开头的组合...
[~] 正在运算以 f 开头的组合...
[~] 正在运算以 g 开头的组合...
[~] 正在运算以 h 开头的组合...
[~] 正在运算以 i 开头的组合...
[~] 正在运算以 j 开头的组合...
[~] 正在运算以 k 开头的组合...
[~] 正在运算以 l 开头的组合...
[~] 正在运算以 m 开头的组合...
[~] 正在运算以 n 开头的组合...
[~] 正在运算以 o 开头的组合...
[~] 正在运算以 p 开头的组合...
[~] 正在运算以 q 开头的组合...
[~] 正在运算以 r 开头的组合...
[~] 正在运算以 s 开头的组合...
[~] 正在运算以 t 开头的组合...
[+] ============================
[+] 成功找到内容: thenow
[+] ============================这里如果没注意到小写字母的话是会爆破出另外的结果:eYOMhu 的
,现在我们就有了forget the LiVe thenow,这里差一个pass3,但是没找到这个压缩包,但是可以知道应该是这样:
`forget the {unkown} LiVe thenow`英文不太好,依旧ai
密码就是forgetthepastLiVethenow
我们去打开宝箱.zip
里面有一个flag文件
打开是:
这里啥都没有,但是这个目录里不只一个文件意识到有隐藏的文件了。
flag.vhd解密
7z直接查看磁盘分区
┌──(kali㉿kali)-[~/tmp]
└─$ 7z l flag.vhd
7-Zip 24.09 (x64) : Copyright (c) 1999-2024 Igor Pavlov : 2024-11-29
64-bit locale=zh_CN.UTF-8 Threads:128 OPEN_MAX:1024, ASM
Scanning the drive for archives:
1 file, 10486272 bytes (11 MiB)
Listing archive: flag.vhd
--
Path = flag.vhd
Type = VHD
Physical Size = 10486272
Offset = 0
Created = 2026-04-09 09:06:22.0000000
Method = Fixed
Total Physical Size = 10486272
Creator Application = win 10.0
Host OS = Windows
Saved State = -
ID = FDF27C7B28565942A307B3CC3135D450
----
Size = 10485760
Packed Size = 10485760
Created = 2026-04-09 09:06:22.0000000
--
Path = flag.mbr
Type = MBR
Physical Size = 10485760
Sector Size = 512
ID = 3036261972
----
Path = 0.ntfs
Size = 7340032
File System = NTFS
Offset = 65536
Primary = +
Begin CHS = 0-2-3
End CHS = 0-229-37
--
Path = 0.ntfs
Type = NTFS
Physical Size = 7340032
Label = 新加卷
File System = NTFS 3.1
Cluster Size = 4096
Sector Size = 512
MFT Record Size = 1024
Created = 2026-04-10 10:11:21.7734735
ID = 2799078985555988069
Date Time Attr Size Compressed Name
------------------- ----- ------------ ------------ ------------------------
2026-04-10 10:11:21 ..HS. 262144 262144 [SYSTEM]/$MFT
2026-04-10 10:11:21 ..HS. 4096 4096 [SYSTEM]/$MFTMirr
2026-04-10 10:11:21 ..HS. 2097152 2097152 [SYSTEM]/$LogFile
2026-04-10 10:11:21 ..HS. 0 0 [SYSTEM]/$Volume
2026-04-10 10:11:21 ..HS. 2560 4096 [SYSTEM]/$AttrDef
2026-04-10 10:15:17 D.HS. [SYSTEM]/.
2026-04-10 10:11:21 ..HS. 224 4096 [SYSTEM]/$Bitmap
2026-04-10 10:11:21 ..HS. 8192 8192 [SYSTEM]/$Boot
2026-04-10 10:11:21 ..HS. 0 0 [SYSTEM]/$BadClus
2026-04-10 10:11:21 ..HS. 0 0 [SYSTEM]/$Secure
2026-04-10 10:11:21 ..HS. 131072 131072 [SYSTEM]/$UpCase
2026-04-10 10:11:21 D.HS. [SYSTEM]/$Extend
2026-04-10 10:11:21 ..HS. 0 0 [SYSTEM]/$Extend/$Quota
2026-04-10 10:11:21 ..HS. 0 0 [SYSTEM]/$Extend/$ObjId
2026-04-10 10:11:21 ..HS. 0 0 [SYSTEM]/$Extend/$Reparse
2026-04-10 10:11:21 D.HS. [SYSTEM]/$Extend/$RmMetadata
2026-04-10 10:11:21 ..HS. 0 0 [SYSTEM]/$Extend/$RmMetadata/$Repair
2026-04-10 10:11:21 D.HS. [SYSTEM]/$Extend/$Deleted
2026-04-10 10:11:21 D.HS. [SYSTEM]/$Extend/$RmMetadata/$TxfLog
2026-04-10 10:11:21 D.HS. [SYSTEM]/$Extend/$RmMetadata/$Txf
2026-04-10 10:11:21 ..HS. 100 100 [SYSTEM]/$Extend/$RmMetadata/$TxfLog/$Tops
2026-04-11 17:41:02 D.... System Volume Information/ClientRecoveryPasswordRotation
2026-04-11 17:41:03 D.HS. System Volume Information
2026-04-10 10:11:21 ....A 12 12 System Volume Information/WPSettings.dat
2026-04-11 17:44:56 ....A 60 60 flag
2026-04-10 10:13:16 D.HS. $RECYCLE.BIN
2026-04-10 10:13:16 D.HS. $RECYCLE.BIN/S-1-5-21-3820227629-3880388360-2971437200-1001
2026-04-10 10:13:16 ..HSA 129 129 $RECYCLE.BIN/S-1-5-21-3820227629-3880388360-2971437200-1001/desktop.ini
2026-04-11 17:41:02 D.... System Volume Information/AadRecoveryPasswordDelete
2026-04-11 17:41:02 D.... System Volume Information/FveDecryptedVolumeFolder
2026-04-11 17:41:03 ....A 76 76 System Volume Information/IndexerVolumeGuid
2026-05-08 18:09:51 ..HS. 0 0 [SYSTEM]/$Extend/$UsnJrnl
------------------- ----- ------------ ------------ ------------------------
2026-05-08 18:09:51 2505817 2511225 20 files, 12 folders
2026-05-08 18:09:51 1312687 1314907 7 alternate streams
2026-05-08 18:09:51 3818504 3826132 27 streams
按照ai的话试试:
┌──(kali㉿kali)-[~/tmp]
└─$ fls -r -o 128 flag.vhd | grep -i "flag"
r/r 36-128-1: flag
r/r 36-128-5: flag:flag发现了隐藏flag文件
这个输出的意思是,在 flag 这个文件上,挂载了一个名字也叫 flag 的 Alternate Data Stream (ADS)。你之前直接打开文件看到的是主数据流(36-128-1),而真正的秘密藏在编号为 36-128-5 的流里。直接查看隐藏流:
┌──(kali㉿kali)-[~/tmp]
└─$ icat -o 128 flag.vhd 36-128-5
mooi:mooi3811350908 得到ssh账号密码。