Vue.js

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 μ§€μ›ν•˜κΈ°

Vue.js의 XSS 싱크

v-html μ§€μ‹œμ–΄

v-html μ§€μ‹œμ–΄λŠ” μ›μ‹œ HTML을 λ Œλ”λ§ν•˜λ―€λ‘œ, λΉ„μœ„μƒμ μΈ μ‚¬μš©μž μž…λ ₯에 ν¬ν•¨λœ <script> (λ˜λŠ” onerror와 같은 속성)λŠ” μ¦‰μ‹œ μ‹€ν–‰λ©λ‹ˆλ‹€.

<div id="app">
<div v-html="htmlContent"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
htmlContent: '<img src=x onerror=alert(1)>'
}
})
</script>

v-bind with src or href

μ‚¬μš©μž λ¬Έμžμ—΄μ„ URL을 ν¬ν•¨ν•˜λŠ” 속성(href, src, xlink:href, formaction λ“±)에 λ°”μΈλ”©ν•˜λ©΄ 링크λ₯Ό λ”°λ₯Ό λ•Œ javascript:alert(1)κ³Ό 같은 νŽ˜μ΄λ‘œλ“œκ°€ 싀행될 수 μžˆμŠ΅λ‹ˆλ‹€.

<div id="app">
<a v-bind:href="userInput">Click me</a>
</div>
<script>
new Vue({
el: '#app',
data: {
userInput: 'javascript:alert(1)'
}
})
</script>

v-on μ‚¬μš©μž μ œμ–΄ ν•Έλ“€λŸ¬μ™€ ν•¨κ»˜

v-on은 new Function으둜 값을 μ»΄νŒŒμΌν•©λ‹ˆλ‹€; λ§Œμ•½ κ·Έ 값이 μ‚¬μš©μžλ‘œλΆ€ν„° 온 것이라면, μ½”λ“œ 싀행을 μ œκ³΅ν•˜λŠ” μ…ˆμž…λ‹ˆλ‹€.

<div id="app">
<button v-on:click="malicious">Click me</button>
</div>
<script>
new Vue({
el: '#app',
data: { malicious: 'alert(1)' }
})
</script>

동적 속성 / 이벀트 이름

μ‚¬μš©μžκ°€ μ œκ³΅ν•œ 이름이 v-bind:[attr] λ˜λŠ” v-on:[event]에 μ‚¬μš©λ˜λ©΄ κ³΅κ²©μžλŠ” 정적 뢄석 및 λ§Žμ€ CSP κ·œμΉ™μ„ μš°νšŒν•˜μ—¬ μž„μ˜μ˜ 속성 λ˜λŠ” 이벀트 ν•Έλ“€λŸ¬λ₯Ό 생성할 수 μžˆμŠ΅λ‹ˆλ‹€.

<img v-bind:[userAttr]="payload">
<!-- userAttr = 'onerror', payload = 'alert(1)' -->

동적 μ»΄ν¬λ„ŒνŠΈ (<component :is>)

:is에 μ‚¬μš©μž λ¬Έμžμ—΄μ„ ν—ˆμš©ν•˜λ©΄ μž„μ˜μ˜ μ»΄ν¬λ„ŒνŠΈλ‚˜ 인라인 ν…œν”Œλ¦Ώμ„ λ§ˆμš΄νŠΈν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” λΈŒλΌμš°μ €μ—μ„œ μœ„ν—˜ν•˜κ³  SSRμ—μ„œλŠ” μž¬μ•™μ μž…λ‹ˆλ‹€.

<component :is="userChoice"></component>
<!-- userChoice = '<script>alert(1)</script>' -->

SSRμ—μ„œ μ‹ λ’°ν•  수 μ—†λŠ” ν…œν”Œλ¦Ώ

μ„œλ²„ μΈ‘ λ Œλ”λ§ 쀑에 ν…œν”Œλ¦Ώμ€ λ‹Ήμ‹ μ˜ μ„œλ²„μ—μ„œ μ‹€ν–‰λ©λ‹ˆλ‹€; μ‚¬μš©μž HTML을 μ£Όμž…ν•˜λ©΄ XSSκ°€ 전체 원격 μ½”λ“œ μ‹€ν–‰(RCE)으둜 ν™•λŒ€λ  수 μžˆμŠ΅λ‹ˆλ‹€. vue-template-compiler의 CVEλŠ” 이 μœ„ν—˜μ„ 증λͺ…ν•©λ‹ˆλ‹€.

// DANGER – never do this
const app = createSSRApp({ template: userProvidedHtml })

Filters / render functions that eval

λ ˆκ±°μ‹œ ν•„ν„°λŠ” λ Œλ” λ¬Έμžμ—΄μ„ μƒμ„±ν•˜κ±°λ‚˜ μ‚¬μš©μž 데이터에 λŒ€ν•΄ eval/new Function을 ν˜ΈμΆœν•˜λŠ” 또 λ‹€λ₯Έ XSS λ²‘ν„°μž…λ‹ˆλ‹€. 이λ₯Ό κ³„μ‚°λœ μ†μ„±μœΌλ‘œ κ΅μ²΄ν•˜μ„Έμš”.

Vue.filter('run', code => eval(code))   // DANGER

Vue ν”„λ‘œμ νŠΈμ˜ λ‹€λ₯Έ 일반적인 취약점

ν”ŒλŸ¬κ·ΈμΈμ—μ„œμ˜ ν”„λ‘œν† νƒ€μž… μ˜€μ—Ό

일뢀 ν”ŒλŸ¬κ·ΈμΈ(예: vue-i18n)의 Deep-merge ν—¬νΌλŠ” κ³΅κ²©μžκ°€ Object.prototype에 μ“Έ 수 μžˆλ„λ‘ ν—ˆμš©ν–ˆμŠ΅λ‹ˆλ‹€.

import merge from 'deepmerge'
merge({}, JSON.parse('{ "__proto__": { "polluted": true } }'))

Open redirects with vue-router

κ²€μ¦λ˜μ§€ μ•Šμ€ μ‚¬μš©μž URL을 router.push λ˜λŠ” <router-link>에 μ „λ‹¬ν•˜λ©΄ javascript: URI λ˜λŠ” ν”Όμ‹± λ„λ©”μΈμœΌλ‘œ λ¦¬λ””λ ‰μ…˜λ  수 μžˆμŠ΅λ‹ˆλ‹€.

this.$router.push(this.$route.query.next) // DANGER

CSRF in Axios / fetch

SPAsλŠ” μ—¬μ „νžˆ μ„œλ²„ μΈ‘ CSRF 토큰이 ν•„μš”ν•©λ‹ˆλ‹€; SameSite μΏ ν‚€λ§ŒμœΌλ‘œλŠ” μžλ™ 제좜된 ꡐ차 좜처 POSTλ₯Ό 차단할 수 μ—†μŠ΅λ‹ˆλ‹€.

axios.post('/api/transfer', data, {
headers: { 'X-CSRF-TOKEN': token }
})

Click-jacking

Vue 앱은 X-Frame-Options: DENY와 Content-Security-Policy: frame-ancestors 'none'λ₯Ό λͺ¨λ‘ μ „μ†‘ν•˜μ§€ μ•ŠμœΌλ©΄ ν”„λ ˆμž„μ— 포함될 수 μžˆμŠ΅λ‹ˆλ‹€.

X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none';

Content-Security-Policy pitfalls

전체 Vue λΉŒλ“œλŠ” unsafe-eval이 ν•„μš”ν•©λ‹ˆλ‹€; μœ„ν—˜ν•œ μ†ŒμŠ€λ₯Ό μ œκ±°ν•  수 μžˆλ„λ‘ λŸ°νƒ€μž„ λΉŒλ“œλ‚˜ 미리 컴파일된 ν…œν”Œλ¦ΏμœΌλ‘œ μ „ν™˜ν•˜μ„Έμš”.

Content-Security-Policy: default-src 'self'; script-src 'self';

Supply-chain attacks (node-ipc – March 2022)

node-ipc의 νŒŒκ΄΄λŠ” Vue CLI에 μ˜ν•΄ λ°œμƒν–ˆμœΌλ©°, 전이 쒅속성이 개발 λ¨Έμ‹ μ—μ„œ μž„μ˜μ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•  수 μžˆλŠ” 방법을 λ³΄μ—¬μ£Όμ—ˆμŠ΅λ‹ˆλ‹€. 버전을 κ³ μ •ν•˜κ³  자주 κ°μ‚¬ν•˜μ„Έμš”.

npm ci --ignore-scripts   # safer install

ν•˜λ“œλ‹ 체크리슀트

  1. λͺ¨λ“  λ¬Έμžμ—΄μ„ μ •λ¦¬ν•˜μ—¬ v-html에 μ „λ‹¬ν•˜κΈ° 전에 μ²˜λ¦¬ν•©λ‹ˆλ‹€ (DOMPurify).
  2. ν—ˆμš©λœ μŠ€ν‚΄, 속성, μ»΄ν¬λ„ŒνŠΈ 및 이벀트λ₯Ό ν™”μ΄νŠΈλ¦¬μŠ€νŠΈν•©λ‹ˆλ‹€.
  3. evalκ³Ό 동적 ν…œν”Œλ¦Ώμ„ μ™„μ „νžˆ ν”Όν•©λ‹ˆλ‹€.
  4. μ˜μ‘΄μ„±μ„ λ§€μ£Ό νŒ¨μΉ˜ν•˜κ³  ꢌ고 사항을 λͺ¨λ‹ˆν„°λ§ν•©λ‹ˆλ‹€.
  5. κ°•λ ₯ν•œ HTTP 헀더λ₯Ό μ „μ†‘ν•©λ‹ˆλ‹€ (CSP, HSTS, XFO, CSRF).
  6. 감사, 잠금 파일 및 μ„œλͺ…λœ μ»€λ°‹μœΌλ‘œ 곡급망을 μž κΈ‰λ‹ˆλ‹€.

μ°Έκ³ λ¬Έν—Œ

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 μ§€μ›ν•˜κΈ°