티스토리 뷰

728x90
반응형

말머리

본 포스팅은 dreamhack(드림핵)의 mongoboard라는 문제를 풀다가 정리하는 내용입니다. 문제 내용이 궁금하다면 아래 링크를 참고해보세요. 별로 궁금하지 않다면 다음 제목으로 넘어가세요.

https://dreamhack.io/wargame/challenges/128/

 

mongoboard

Description node와 mongodb로 구성된 게시판입니다. 비밀 게시글을 읽어 FLAG를 획득하세요. MongoDB < 4.0.0

dreamhack.io

해당 문제는 아래와 같이 게시글 목록이 존재하고 관리자가 작성한 글에만 mongodb의 ObjectID가 보이지 않는 형태인데요.

다만 이렇게 /detail/{ObjectID} 로 직접 접속하게 되면 비밀 글도 보이게 되는 비인가 접근이 가능한 취약점을 가지고 있는 문제입니다.

위 문제를 풀기위해서는 관리자가 작성한 비밀 게시글이 작성된 날짜를 기준으로 ObjectID를 변환하면 풀 수 있는 문제였습니다. 이 문제를 풀다가 MongoDB의 ObjectID에 대해서 정리해봅니다.

 

MongoDB의 ObjectID란

MongoDB의 ObjectId 는 총 12byte 로 이루어져있고 모두 16진수 형태로 이루어져있습니다. 아래 테이블은 ObjectID 를 각 의미를 가지는 바이트 별로 나눈 예시입니다.

62 4d dc 67 38 ff b0 cf 6d d1 11 52
  • 첫 4 바이트는 Unix Timestamp 값을 의미합니다.
  • 다음 5 바이트는 고유한 랜덤값을 가집니다.
  • 마지막 3 바이트는 계속 증가하는 값을 가지는 counter 값이며, 최초값은 랜덤하게 생성됩니다.

MongoDB는 BSON 포맷으로 데이터를 저장하는데, BSON 포맷 자체는 리틀엔디안(little-endian)이지만, 타임스탬프나 카운터 값의 경우에는 빅 엔디안(big-endian)이며, 바이트 시퀀스에서 MSB(most significant bytes)가 먼저 앞에 온다고 합니다.

 

위 내용의 원본은 아래 링크에서 볼 수 있습니다.

https://www.mongodb.com/docs/manual/reference/method/ObjectId/

 

ObjectId — MongoDB Manual

Docs Home → MongoDB ManualObjectId( )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 random

www.mongodb.com

 

ObjectID 와 Datetime 간의 변환(convert)

우선 ObjectID의 앞 4바이트만 변환한다고 생각하면 됩니다. 왜냐하면 뒤 나머지 8바이트는 모두 랜덤한 값이기 때문입니다.

 

아래는 ObjectID로부터 datetime 을 추출하는 코드입니다.

var objId = '624ddc6738ffb0cf6dd11152';

var dateFromObjectId = function (objectId) {
	return new Date(parseInt(objectId.substring(0, 8), 16) * 1000);
};

dateFromObjectId(objId).toISOString();
// '2022-04-06T18:31:03.000Z'

dateFromObjectId 함수는 0번째부터 7번째 index 까지의 문자들을 파싱해서 날짜로 변환합니다. 그리고 toISOString 함수로 Date 객체를 ISO 시간 포맷으로 datetime 을 출력했습니다.

 

그리고 반대로 datetime 으로부터 ObjectID를 추출할 수도 있습니다. 일단 말머리에서 언급했던 문제에서 사용된 날짜/시간 값이 ISO 포맷이기 때문에 ISO 포맷의 시간 값을 ObjectID로 변환하는 코드를 작성해보았습니다.

var objectIdFromDate = function (date) {
	return Math.floor(date.getTime() / 1000).toString(16) + "0000000000000000";
};

var date = new Date('2022-04-06T18:31:08.269Z');

objectIdFromDate(date);
// '624ddc6c0000000000000000'

위와 같이 timestamp 값만을 변환해주었습니다. 뒤의 랜덤한 값은 MongoDB 자체에서 정해지는 값들이라 필요하다면 따로 붙여주기만 하면 되기 때문입니다.

 

이로써 MongoDB의 ObjectId 와 날짜/시간(Datetime) 간의 변환에 대해서 알아보았습니다. dreamhack 의 mongoboard 문제풀이는 위 내용을 활용한다면 쉽게 풀 수 있겠습니다.

 

- 끝 -

728x90
반응형
댓글