RED TEAM
  • Presentación
  • Apuntes Linux
  • Apuntes Blue Team
  • Apuntes Python
  • Ricardev github
  • RECON
    • OSINT
    • DESCUBRIENDO LA RED
      • NMAP NSE
    • SNIFFING
      • TCPDUMP
  • TECHNIQUES
    • FUERZA BRUTA
      • HYDRA
      • MEDUSA
      • JOHN THE RIPPER
      • NCRACK
      • RAINBOW TABLES
      • CHEATSHEET
    • CLAVES RSA DÉBILES
  • WEB HACKING
    • FUZZING
      • GOBUSTER
      • WFUZZ
      • OTRAS HERRAMIENTAS DE RECONOCIMIENTO WEB
    • OWASP TOP 10
      • A1-2017. SQL INJECTION
        • LOGIN FORM BYPASS
        • EXTRACCIÓN DE INFORMACIÓN.
        • SQLI MODIFIED HEADERS
        • BOOLEAN BLIND SQLI
        • TIME-BASED BLIND SQLI
        • AUTOMATIC INJECTION
      • A2-2017. ATAQUES A SISTEMAS DE AUTENTICACIÓN
      • A3-2017 - EXPOSICIÓN DE DATOS SENSIBLES
      • A4-2017. XXE
      • A5-2017. CONTROL DE ACCESO VULNERABLE
      • A6-2017. SEGURIDAD MAL CONFIGURADA
      • A7-2017. XSS
      • A8-2017. DESERIALIZACIÓN INSEGURA
      • A9-2017. USO DE COMPONENTES CON VULNERABILIDADES CONOCIDAS
      • A10-2017. REGISTRO Y MONITOREO INSUFICIENTE
    • SERVICIOS WEB
      • APACHE TOMCAT (RCE)
      • PRTG NETWORK MONITOR (RCE)
  • SERVICES HACKING (BOTH)
    • 20,21 - FTP
      • FTP BOUNCE ATTACK - ESCANEO
      • FTP BOUNCE ATTACK- DESCARGA DE OTRA FTP
    • 23 - TELNET
    • 25, 465 587 - SMTP
    • 111, 2049 - RPCBIND Y NFS
    • 161,162,10161,10162/udp - SNMP
      • SNMP (RCE Linux)
    • 445 - SMB
      • ETERNALBLUE
    • 3306 - MYSQL
  • SERVICES HACKING (LINUX)
    • 3632 - DISTCCD
  • SERVICES HACKING (WINDOWS)
    • 135, 539 - MSRPC
    • 389, 636 - LDAP / LDAPS
    • 1443 - MSSQL
  • ACTIVE DIRECTORY HACKING
    • CREANDO UN LABORATORIO DE AD
      • 1. Instalación de Windows Server 2016
      • 2. ROL DE ACTIVE DIRECTORY
      • 3. MALAS PRÁCTICAS NECESARIAS
    • CONCEPTOS
      • SPN Y KERBEROS
    • ENUMERACIÓN
      • BLOODHOUND
    • ATAQUES
      • SMB RELAY
      • NTLM RELAY
      • KERBEROASTING
      • AS_REP ROASTING
  • PRIVESC
    • WINDOWS
    • LINUX
      • LXD/LXC GROUP
  • EXFILTRACIÓN
    • EXFILTRANDO INFORMACIÓN
  • SHELL AND POWERSHELL TRICKS
    • Transfiriendo datos (traducir)
    • MEJORANDO SHELL A TTY INTERACTIVA (Traducir)
  • PWN LINUX
    • CREANDO UN LABORATORIO SIN MITIGACIONES
    • TEORÍA
      • ESTRUCTURA DE UN BINARIO DE LINUX
        • HERRAMIENTAS
      • ENSAMBLADOR
      • CONVENCIÓN DE LLAMADAS
      • MITIGACIONES
      • SYSCALL Y SHELLCODE
      • FORMAT STRING
      • RETURN-ORIENTED PROGRAMMING
        • GADGETS
    • ESTRATEGIAS DE EXPLOIT
      • STACK EXPLOITS
        • ATAQUE “SMASH THE STACK” SENCILLO
        • ATAQUE RET2WIN
        • ATAQUE RET2SHELLCODE
        • ATAQUE FORMAT STRING RET2SHELLCODE 2 BYTES
        • ATAQUE FORMAT STRING RET2SHELLCODE 4 BYTES
        • CANARY BYPASS
        • ATAQUE RET2LIBC
    • PRÁCTICA
      • PHOENIX
        • SETUP
        • STACK-ZERO amd64
        • STACK-ONE amd64
        • STACK-TWO amd64
        • STACK-THREE amd64
        • STACK-FOUR amd64
        • STACK-FIVE amd64
        • STACK-SIX amd64
        • FORMAT-ZERO amd64
Con tecnología de GitBook
En esta página
  • CÓDIGO FUENTE
  • PREPARANDO EL EXPLOIT
  • USANDO EL DEPURADOR

¿Te fue útil?

  1. PWN LINUX
  2. PRÁCTICA
  3. PHOENIX

STACK-ONE amd64

Este nivel presenta el concepto de modificar variables a valores específicos en el programa y como se encuentran dichas variables guardadas en memoria.

CÓDIGO FUENTE

/*
 * phoenix/stack-one, by https://exploit.education
 *
 * The aim is to change the contents of the changeme variable to 0x496c5962
 *
 * Did you hear about the kid napping at the local school?
 * It's okay, they woke up.
 *
 */

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define BANNER \
  "Welcome to " LEVELNAME ", brought to you by https://exploit.education"

int main(int argc, char **argv) {
  struct {
    char buffer[64];
    volatile int changeme;
  } locals;

  printf("%s\n", BANNER);

  if (argc < 2) {
    errx(1, "specify an argument, to be copied into the \"buffer\"");
  }

  locals.changeme = 0;
  strcpy(locals.buffer, argv[1]);

  if (locals.changeme == 0x496c5962) {
    puts("Well done, you have successfully set changeme to the correct value");
  } else {
    printf("Getting closer! changeme is currently 0x%08x, we want 0x496c5962\n",
        locals.changeme);
  }

  exit(0);
}

Por otro lado, el input no se introduce por stdin a través de una función gets() sino que se introduce como argumento y se le da el valor a locals.buffer con una función strcpy(). Aquí tenemos nuestra vulnerabilidad:

strcpy(3) - Linux man page

(...)

Bugs

If the destination string of a strcpy() is not large enough, then anything might happen. Overflowing fixed-length string buffers is a favorite cracker technique for taking complete control of the machine. Any time a program reads or copies data into a buffer, the program first needs to check that there's enough space. This may be unnecessary if you can show that overflow is impossible, but be careful: programs can get changed over time, in ways that may make the impossible possible.

(...)

Por tanto podemos dividir el programa en diferentes partes:

int main(int argc, char **argv) {
  struct {
    char buffer[64];
    volatile int changeme;
  } locals;

  printf("%s\n", BANNER);

Declaración de las variables en una estructura.

if (argc < 2) {
    errx(1, "specify an argument, to be copied into the \"buffer\"");
  }

  locals.changeme = 0;
  strcpy(locals.buffer, argv[1]);

Comprobación de que existe un argumento (si no lo hay, lanza un error por stderr). Se da valor a las variables:

  • locals.changeme tiene el valor de 0.

  • locals.buffer coge el valor del argumento con la función vulnerable strcpy().

if (locals.changeme == 0x496c5962) {
    puts("Well done, you have successfully set changeme to the correct value");
  } else {
    printf("Getting closer! changeme is currently 0x%08x, we want 0x496c5962\n",
        locals.changeme);
  }

Comprobación del valor de locals.changeme. Si coincide con el valor marcado da un resultado con puts() y sino da otro con printf().

En el último utiliza printf() por que referencia a una variable dentro del texto. Si el texto es estático, se utilizará puts().

Como podemos destacar del análisis del código fuente, tenemos dos decisiones lógicas dentro de la ejecución de main:

  • Comprobar si argc < 2.

  • Comprobar si locals.changeme = 0x496c5962.

De todo esto podemos imaginar que si genero el mismo payload que en el ejercicio anterior pero con el valor 0x496c5962 en vez del valor 0x43434343, ganaré el reto.

PREPARANDO EL EXPLOIT

El programa es bastante similar al anterior por lo que la información podemos reutilizarla en su mayoría. Solo cambia el vector de ataque (strcpy() en vez de gets()) y como resultado de esto, que utilizamos un argumento y no stdin para introducir los datos.

Aún podemos desbordar el buffer con 64 + N caracteres solo que en este caso, changeme debe contener el valor 0x496c5962. Esto lo podemos conseguir con un Payload en Python parecido al del ejercicio anterior. Esto lo haremos más adelante.

Para empezar vamos a utilizar rabin2 para obtener información del binario:

Como en el anterior, el binario no utiliza ningún mecanismo de seguridad.

También podemos comprobarlo con checksec.

Por tanto, el exploit en Python sería una cosa así:

Utilizamos la función pack del módulo struct para introducir la dirección de memoria en formato Little Endian.

Por otro lado, deberíamos preparar también la plantilla de rarun2:

Como podemos ver, para coger el contenido del archivo en vez de un string literal se necesita utilizar el símbolo @ antes de la ruta del payload.

Solo así podemos hacer que funcione el argumento como queremos.

USANDO EL DEPURADOR

Como siempre que utilizamos el depurador, tras abrir el archivo procedemos a analizar todo y listar las funciones:

Después podemos decidir si utilizamos pdf main (print disassembly from) o s main (seek) para colocarse ya en las direcciones de memoria de main.

Pasamos a modo gráfico para ver que efectivamente hay dos puntos de decisión en el camino principal, como habíamos visto en el código fuente:

Para mejorar nuestro entendimiento del código ensamblador vamos a ponerlo al lado del código fuente:

int main(int argc, char **argv) {        // push rbp
                                         // mov rbp, rsp

  struct {                               // sub rsp, 0x60
    char buffer[64];                     // mov dword [rbp -local_54h], edi (argc)
    volatile int changeme;               // mov qword [rbp - local_60h], rsi (buffer)
  } locals;

  printf("%s\n", BANNER);                 // call sym.imp.puts

  if (argc < 2) {                         // COMPARACIÓN NÚMERO DE ARGS
                                          // cmp dword [rbp - local_54h], 1
                                          // jg 0x4006a0 (si es > 1 salta)
                                          
                                          // CAMINO <= 1        
    errx(1, "specify an argument...");    // mov esi, str.sprecify_an_argument
  }                                       // mov edi, 1
                                          // mov eax, 0
                                          // call sym.imp.errx 
                                          
                                          // CAMINO > 1
  locals.changeme = 0;                    // mov dword [rbp - local_10h], 0 (changeme)
  strcpy(locals.buffer, argv[1]);         // mov rax, qword [rbp - local_60h]
                                          // add rax, 8
                                          // mov rdx, qword [rax]
                                          // lea rax, qword [rbp - local_50h]
                                          // mov rsi, rdx
                                          // moc rdi, rax
                                          // call sym.imp.strcpy

  if (locals.changeme == 0x496c5962) {    // COMPARACIÓN VALOR DE CHANGEME
                                          // mov eax, dword [rbp - local_10h]
                                          // cmp eax, 0x496c5962
                                          // jne 0x4006d7
                                          
                                          // CAMINO = 0x496c5962
    puts("Well done...");                 // mov edi, str.Well_done_...
                                          // call sym.imp.puts
                                          //jmp 0x4006eb (salta a exit) 
    
                                          // CAMINO != 0x496c5962
  } else {                                // mov eax, dword [rbp - local_10h]
                                          // mov esi, eax
    printf("... we want 0x496c5962\n",    // mov edi, str.(...)_we_want...
        locals.changeme);                 // call sym.imp.printf
  }

  exit(0);                                // mov edi, 0
                                          // call sym.imp.exit

Ahora en el modo visual navegamos por los modos con p y aumentamos los bytes de stack que se muestran utilizando :

:> e stack.size=128

Con esta visual vamos a marcar un breakpoint justo antes de la llamada a la función strcpy():

db 0x004006b9
dc //para continuar la ejecución hasta el breakpoint

Como podemos ver en el stack, la información se ha guardado invirtiendo el orden de los bytes, esto se debe a que la información se guarda en formato Little Endian.

En la última imagen vemos como se ha sobreescrito rax y ahora contiene el valor que necesitamos para superar el reto.

Para conseguir el mismo resultado fuera del depurador debemos utilizar uno de los siguientes comandos:

 /opt/phoenix/amd64/stack-one $(cat stack1-payload.txt)
 
 /opt/phoenix/amd64/stack-one $(./stack1.py)
AnteriorSTACK-ZERO amd64SiguienteSTACK-TWO amd64

Última actualización hace 3 años

¿Te fue útil?

Tras analizar el código fuente anterior podemos ver que es prácticamente similar al código de pero con la diferencia de que el condicional IF comprueba que el valor de locals.changeme se ha modificado por 0x496c5962 y no únicamente que se ha modificado.

Stack-Zero
stack-one. Struct layout
stack-one. rabin2
stack-one. exploit.py
stack-one. exploit.rr
stack-one. r2 / aaa / afl
stack-one. r2 graph
stack-one. r2 visual
stack-one. r2 stack overflow
Victoria!