<문제>
<풀이>
문제 사이트에 접속하면 처음으로 볼 수 있는 페이지이다.
MongoDB에 저장된 게시물 목록을 볼 수 있고 게시물을 작성할 수 있는 기능이 있는 것 같다.
맨 위에 있는 게시물을 클릭해보면 World! 라는 게시물 내용을 볼 수 있다.
no가 없는 admin이 작성한 FLAG라는 게시물을 클릭해보면 Secret Document!라는 alert창이 뜨고 내용을 보여주지 않는다.
var boardSchema = new Schema({
title: {type:String, required: true},
body: {type:String, required: true},
author: {type:String, required: true},
secret: {type:Boolean, default: false},
publish_date: { type: Date, default: Date.now }
}, {versionKey: false });
제시된 문제 파일 중에서 /models/board.js 파일을 열어보면 스키마를 확인할 수 있다.
title, body, author, secret, publish_date가 있는 것을 확인할 수 있다.
그리고 스키마에 나와있지 않지만 MongoDB에 저장된 모든 도큐먼트는 _id라는 Primary Key를 가지므로 _id도 있을 것이다.
app.get('/api/board', function(req,res){
MongoBoard.find(function(err, board){
if(err) return res.status(500).send({error: 'database failure'});
res.json(board.map(data => {
return {
_id: data.secret?null:data._id,
title: data.title,
author: data.author,
secret: data.secret,
publish_date: data.publish_date
}
}));
})
});
/routes/index.js 파일을 열어보면 GET 방식으로 /api/board에 접속했을 때
board에 있는 _id, title, author, secret, publish_date를 출력해주는 코드를 볼 수 있다.
이때 secret이 true이면 _id는 null로 출력된다.
/api/board에 접속해본다.
board에 저장되어있는 도큐먼트들이 출력된 것을 확인할 수 있다.
앞서 봤던 admin의 FLAG 게시물은 secret이 true라서 no가 null로 출력된 것도 볼 수 있다.
app.get('/api/board/:board_id', function(req, res){
MongoBoard.findOne({_id: req.params.board_id}, function(err, board){
if(err) return res.status(500).json({error: err});
if(!board) return res.status(404).json({error: 'board not found'});
res.json(board);
})
});
/routes/index.js의 코드에서 /api/board/:board_id로 접속하면
해당 _id를 갖는 도큐먼트를 json 형식으로 응답하는 것을 확인할 수 있다.
맨 위에 있는 게시물의 _id를 이용해 /api/board/:board_id로 접속해본다.
해당 게시물의 도큐먼트가 조회되어 출력되고
body필드에 게시물의 내용이 뜨는 것을 볼 수 있다.
FLAG 게시물의 _id를 알아낼 수 있으면 위와 같이 접근해서 게시물의 내용을 읽을 수 있을 것이다.
FLAG 게시물의 _id를 알아내기 위해서는 _id가 생성되는 방식을 알아야 한다.
_id는 하나의 컬렉션 내에 있는 각각의 도큐먼트마다 고유한 값을 가지며
어떤 데이터형이든 가질 수 있지만 기본 데이터형은 ObjectId이다.
ObjectId에 대해서는 MongoDB에서 제공하는 Manual에 잘 설명되어 있다.
https://www.mongodb.com/docs/manual/reference/method/ObjectId/
ObjectId() — MongoDB Manual
Docs Home → MongoDB Manual ObjectId( )Returns a new ObjectId. The 12-byte ObjectId consists of:A 4-byte timestamp, representing the ObjectId's creation, measured in seconds since the Unix epoch.A 5-byte random value generated once per process. This rando
www.mongodb.com
ObjectId는 총 12-byte이며
4-byte는 초 단위로 찍은 타임스탬프,
5-byte는 프로세스 단위로 생성한 랜덤 값,
3-byte는 증가하는 counter
로 구성되어 있다.
_id가 공개되어있는 게시물의 _id를 통해 숨겨진 FLAG 게시물의 _id를 유추해볼 것이다.
64e43015abd94b0030e65c6a
64e43017abd94b0030e65c6b
null
64e4301dabd94b0030e65c6d
공개되어 있는 게시물들의 _id 이다.
보기 좋게4-byte, 5-byte, 3-byte로 끊어본다.
64e43015 | abd94b0030 | e65c6a
64e43017 | abd94b0030 | e65c6b
null
64e4301d | abd94b0030 | e65c6d
프로세스 당 생성한 가운데 5-byte가 모두 같은 것을 보니
FLAG의 가운데 5-byte도 같은 값(abd94b0030)을 가질 것으로 예상할 수 있다.
그리고 counter에 해당하는 마지막 3-byte가 1씩 증가하고 있으므로
FLAG의 마지막 3-byte는 e65c6b에서 1 증가한 e65c6c일 것으로 예상할 수 있다.
첫 4-byte는 타임스탬프이므로 publish_date와 함께 보면 계산할 수 있을 것이다.
64e43015 | abd94b0030 | e65c6a
2023-08-22T03:48:37.325Z
64e43017 | abd94b0030 | e65c6b
2023-08-22T03:48:39.334
null
2023-08-22T03:48:41.335Z
64e4301d | abd94b0030 | e65c6d
2023-08-22T03:48:45.337Z
첫번째 게시물과 두번째 게시물은 타임스탬프가 2만큼 차이나고, publish_date는 2초만큼 차이나는 것을 볼 수 있다.
두번째 게시물과 네번째 게시물은 타임스탬프가 6만큼 차이나고, publish_date도 6초만큼 차이나는 것을 볼 수 있다.
두번째 게시물과 FLAG 게시물은 publish_date가 2초만큼 차이나므로
타임스탬프도 2만큼 차이가 나서 FLAG의 타임스탬프는 64e43019일 것으로 예상할 수 있다.
이렇게 찾은 FLAG게시물의 _id는 64e43019abd94b0030e65c6c이다.
(이 _id 값은 생성한 문제 서버에 따라 다른 값을 가질 수 있다.)
/api/board/64e43019abd94b0030e65c6c로 접속해본다.
FLAG 가 출력되었다.
'드림핵' 카테고리의 다른 글
[드림핵 워게임] web-deserialize-python (0) | 2023.08.29 |
---|---|
[드림핵 워게임] file-csp-1 (0) | 2023.08.27 |
[드림핵 워게임] [wargame.kr] fly me to the moon (0) | 2023.08.19 |
[드림핵 워게임] [wargame.kr] strcmp (0) | 2023.08.19 |
[드림핵 워게임] [wargame.kr] type confusion (0) | 2023.08.19 |