-
[2025-01-02] MongoBleed ์ทจ์ฝ์ News 2026. 1. 2. 12:56
๐News Link:
https://m.boannews.com/html/detail.html?mtype=1&idx=141194
์ ๋น์ํํธ, ์ฌ์ ์ต์ ๋ณด์์ฐธ์ฌ... ‘๋ ์ธ๋ณด์ฐ ์์ค ์์ฆ’ ํต์ ๊ถ ์ผ์ ์์ค
ํ๋์ค์ ๋ณธ์ฌ๋ฅผ ๋ ์ธ๊ณ์ ์ธ ๋น๋์ค ๊ฒ์ ๊ฐ๋ฐ์ ์ฒด ์ ๋น์ํํธ์ ๋ํ์ ‘๋ ์ธ๋ณด์ฐ ์์ค ์์ฆ’ ๊ฐ ํด์ปค ๊ทธ๋ฃน์ ๊ณต๊ฒฉ์ ๋ฐ์ ์๋ฒ ํต์ ๊ถ์ ์ผ์์ ์ผ๋ก ์์คํ๋ ์ด์ ์ ์ฌํ๊ฐ ๋ฐ์ํ๋ค. ‘
m.boannews.com
2025๋ 12์ 28์ผ, ํ๋์ค์ ๋ณธ์ฌ๋ฅผ ๋ ์ธ๊ณ์ ๊ฒ์ ๊ฐ๋ฐ์ฌ ์ ๋น์ํํธ์ ๋ํ์ ‘๋ ์ธ๋ณด์ฐ ์์ค ์์ฆ’ ์ ์๋ฒ ํต์ ๊ถ์ด ํด์ปค ๊ทธ๋ฃน์ ์ํด ์ผ์์ ์ผ๋ก ์ฅ์ ๋์๋ค.
๊ณต๊ฒฉ ์ฃผ์ฒด๋ ‘ํผ์คํธ ๊ทธ๋ฃน’(First Group)์ด๋ ์ด๋ฆ์ ํด์ปค ์ง๋จ์ผ๋ก, ๊ฒ์ ๋ด ๊ด๋ฆฌ์ ๊ถํ์ ์ป์ด ์์คํ ๊ณต์ง์ฐฝ์ ์ฅ์ ํ๊ณ ์ด์์ง์ ์กฐ๋กฑํ๋ ๋ฌธ๊ตฌ๋ฅผ ๋์ด ๋์์, ์ฝ 3400์ต๋ฌ๋ฌ(์ฝ 440์กฐ์) ๊ท๋ชจ์ ๋ฌํ๋ ์ฒ๋ฌธํ์ ๊ท๋ชจ์ ์ ๋ฃ ์ฌํ์ ํฌ๊ท ์์ดํ ์ ์ธ๊ณ ์ฌ์ฉ์์๊ฒ ๋ฌด์ฐจ๋ณ์ ์ผ๋ก ๋ฐฐํฌํ ์ฌ๊ฑด์ด๋ค.
์ด๋ฒ ๊ณต๊ฒฉ์ ๋ฐฐํ์๋ ์ต๊ทผ ๊ณต๊ฐ๋ ๋ชฝ๊ณ DB(MongoDB)์ ์น๋ช ์ ์ทจ์ฝ์ ‘๋ชฝ๊ณ ๋ธ๋ฆฌ๋’(MongoBleed)๊ฐ ์๋ฆฌ ์ก๊ณ ์๋ค. ๋ฏธ๊ตญ ์ฌ์ด๋ฒ๋ณด์ ๋ฐ ์ธํ๋ผ ๋ณด์๊ตญ(CISA)์ ํด๋น ์ทจ์ฝ์ ์ ๋ํ ๊ฒฝ๊ณ ๋ฅผ ๋ฐ๋ นํ๊ณ ์ฆ๊ฐ์ ์ธ ๋์์ ๋น๋ถํ๊ณ , ์ง๋ 29์ผ ๋ชฝ๊ณ DB์์ ๋ฐ๊ฒฌ๋ ์ทจ์ฝ์ ‘CVE-2025-14847’์ KEV(Known Exploited Vulnerabilities)์ ์ถ๊ฐํ๋ค.
๋ณด์ ์ ๋ฌธ ๊ทธ๋ฃน ๋ธ์ด์์ค ์ธ๋๊ทธ๋ผ์ด๋(vx-underground)๋ ์ด๋ฒ ๊ณต๊ฒฉ์ ํตํด ์ ๋น์ํํธ์ 30๋ ์น ์์ค ์ฝ๋์ ๊ฐ๋ฐ ํคํธ(SDK) ์ฝ 900GB ๋ถ๋์ด ์ ์ถ๋์ ๊ฐ๋ฅ์ฑ์ด ๋๋ค๊ณ ๋ถ์ํ๋ค.
๋ชฝ๊ณ DB๋ ์ ์ธ๊ณ์ ์ผ๋ก ์ฌ์ฉ๋๋ ์คํ์์ค ๊ธฐ๋ฐ ๊ด๋ฆฌํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ด๋ฆฌ ์์คํ (DBMS)์ด๋ค. DB์์ง(DB-Engines)์ ๋ฐ๋ฅด๋ฉด, ๋ชฝ๊ณ DB๋ 2025๋ 12์ ๊ธฐ์ค ์ ์ฒด DBMS ์์์์ 5์๋ฅผ ์ฐจ์งํ๊ณ ์๋ค. ๊ธ๋ก๋ฒ ๋ณด์ ์ธํ ๋ฆฌ์ ์ค ํ๋ซํผ ‘์ผ์์ค(Censys)’๋ ์ง๋ 27์ผ ์ ์ธ๊ณ ์ฝ 8๋ง 7,000๋๊ฐ ๋๋ ์์คํ ์ด CVE-2025-14847 ์ทจ์ฝ์ ์ ๋ ธ์ถ๋ผ ์๋ค๊ณ ๋ฐํํ๋ค. ํด๋ผ์ฐ๋ ๋ณด์ ๊ธฐ์ ‘์์ฆ(Wiz)’๋ ์ ์ฒด ํด๋ผ์ฐ๋ ํ๊ฒฝ์ 42%๊ฐ ์ด ์ทจ์ฝ์ ์ ์ง๋ ๋ชฝ๊ณ DB ๋ฒ์ ์ ์ด์ฉ ์ค์ด๋ผ๊ณ ๋ฐํ๋ค.

โ ๏ธ ๋ชฝ๊ณ ๋ธ๋ฆฌ๋(MongoBleed) ์ทจ์ฝ์ ์ด๋?
‘๋ชฝ๊ณ ๋ธ๋ฆฌ๋(MongoBleed)’๋ก ๋ถ๋ฆฌ๋ CVE-2025-14847์ ๋ชฝ๊ณ DB ์๋ฒ์์ ๋ฐ๊ฒฌ๋ ๋ฉ๋ชจ๋ฆฌ ์ฒ๋ฆฌ ์ทจ์ฝ์ ์ด๋ค. ์ธ์ฆ๋์ง ์์ ๊ณต๊ฒฉ์๊ฐ ํน์ํ๊ฒ ์กฐ์๋ ์์ฒญ์ ๋ณด๋ด ๋ฐ์ดํฐ๋ฒ ์ด์ค(DB) ์ธ์ฆ ์ ๋ณด๋ DB์ ๋ด๊ธด ๋ฏผ๊ฐ ๋ฐ์ดํฐ๋ฅผ ํ์ทจํ๋ ๋ฐ ์ ์ฉ๋ ์ ์๋ค.
๊ณผ๊ฑฐ ํฐ ํ์ฅ์ ์ผ์ผ์ผฐ๋ 'ํํธ๋ธ๋ฆฌ๋(Heartbleed)'์ ์ ์ฌํ ๋ฐฉ์์ผ๋ก ๋ฉ๋ชจ๋ฆฌ ์ ๋ณด๊ฐ ์ ์ถ๋๋ค๋ ์๋ฏธ์์ ๋ชฝ๊ณ ๋ธ๋ฆฌ๋๋ผ๋ ์ด๋ฆ์ด ๋ถ์๋ค.
๋ชฝ๊ณ DB๋ ๋คํธ์ํฌ๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ ๋ ํจ์จ์ฑ์ ์ํด zlib์ด๋ผ๋ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์์ถํด์ ๋ณด๋ผ ์ ์์ต๋๋ค. ๋ฌธ์ ๋ ์๋ฒ๊ฐ ์์ถ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ ๋ค์ ํ ๋(์์ถ ํด์ ), ์ค์ ๋ก ํ๋ฆฐ ๋ฐ์ดํฐ์ ํฌ๊ธฐ๊ฐ ์๋๋ผ ๋ฏธ๋ฆฌ ์ก์๋์ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ(๋ฒํผ) ์ ์ฒด๋ฅผ ๊ทธ๋๋ก ๋๋ ค์ค๋ค๋ ์ ์ด๋ค.
Step 1) ์กฐ์๋ ์ด์ค ๋ ์ด์ด ํจํท ์ ์ก (OP_COMPRESSED ๋ฐ BSON ์กฐ์)
๊ณต๊ฒฉ์๋ ์๋ฒ์ ์์ฃผ ์์ ์์ ๋ฐ์ดํฐ๋ฅผ zlib์ผ๋ก ์์ถํด์ ๋ณด๋ด๋๋ฐ, ์ด๋ ํจํท ํค๋์๋ "์ด ๋ฐ์ดํฐ๋ ์์ถ์ ํ๋ฉด 1,000๋ฐ์ดํธ์ง๋ฆฌ๋ค"๋ผ๊ณ ๊ฑฐ์ง ์ ๋ณด๋ฅผ ์ ์ด ๋ณด๋ธ๋ค.
๋ชฝ๊ณ DB๋ ํต์ ์ OP_COMPRESSED๋ผ๋ ๋ฉ์์ง ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๋๋ฐ, ๊ณต๊ฒฉ์๋ ์ด ํค๋ ๋ด์ uncompressedSize ํ๋๋ฅผ ์กฐ์ํ๋ค. ๊ทธ๋ฆฌ๊ณ ๊ทธ ์์๋ ์ค์ ๋ฐ์ดํฐ์ธ BSON์ด ๋ค์ด ์๋๋ฐ, ๊ณต๊ฒฉ์๋ ์ด ๋ฐ์ดํฐ(BSON)์ ํค๋์ ์๋ ๊ธธ์ด ์ ๋ณด๋ ์กฐ์ํ๋ค. BSON ๊ฐ์ฒด์ document length(๋งจ ์ 4๋ฐ์ดํธ)๋ฅผ uncompressedSize ์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ค์ ๋ฐ์ดํฐ ํฌ๊ธฐ๋ณด๋ค ํจ์ฌ ํฌ๊ฒ ์ค์ ํ๋ค.
ํ๋๋ช ํฌ๊ธฐ ์ค๋ช header 16 bytes ํ์ค ๋ชฝ๊ณ DB ๋ฉ์์ง ํค๋ originalOpcode 4 bytes ์์ถ ์ ์ ์๋ ๋ช ๋ น ์ฝ๋ (์: OP_MSG) uncompressedSize 4 bytes ์์ถ์ ํ์์ ๋์ ์์ ํฌ๊ธฐ compressorId 1 byte ์์ถ ์๊ณ ๋ฆฌ์ฆ ID (zlib = 1) compressedMessage ๋ณ๋ ์ค์ zlib์ผ๋ก ์์ถ๋ ๋ฐ์ดํฐ Step 2) ๋ฉ๋ชจ๋ฆฌ ํ ๋น
์๋ฒ๋ ํค๋ ์ ๋ณด๋ง ๋ฏฟ๊ณ "์, 1,000๋ฐ์ดํธ ๋ฐ์ดํฐ๊ฐ ์ค๋๊ตฌ๋"๋ผ๊ณ ์๊ฐํ๋ฉฐ ๋ฉ๋ชจ๋ฆฌ์ 1,000๋ฐ์ดํธ ํฌ๊ธฐ์ ๋น ๊ณต๊ฐ(ํ ๋ฒํผ)์ ๋ง๋ ๋ค. ์ด๋ ๋ฉ๋ชจ๋ฆฌ์๋ ์ด์ ์ ๋ค๋ฅธ ์ฌ์ฉ์๊ฐ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ๊ฐ ๋จ์์์ ์ ์๋ค.
Step 3) ๋ถ์คํ ๋ฐ์ดํฐ ์ฑ์ฐ๊ธฐ
์๋ฒ๊ฐ ์์ถ์ ํ๋ฉด ์ค์ ๋ฐ์ดํฐ๋ 10๋ฐ์ดํธ๋ฟ์ด๋ฏ๋ก, ์์ฑ๋ 1,000๋ฐ์ดํธ ๋ฒํผ ์ค ์๋ถ๋ถ 10๋ฐ์ดํธ๋ง ์ฑ์์ง๋ค. ๋๋จธ์ง 990๋ฐ์ดํธ์๋ ์ด์ ์ ๋ค๋ฅธ ์์ ์์ ์ฌ์ฉํ๋ค๊ฐ ๋จ์ ๋ฐ์ดํฐ๋ค์ด ๊ทธ๋๋ก ๋ค์ด์๋ค.
Step 4) ๋ฉ๋ชจ๋ฆฌ ์ ์ถ(Bleed)
๋ชฝ๊ณ DB์ ์ทจ์ฝํ ์ฝ๋(message_compressor_zlib.cpp)๋ "์ค์ ๋ก ํ๋ฆฐ 10๋ฐ์ดํธ๋ง ๋ณด๋ด๋ผ"๊ณ ๋ช ๋ นํ๋ ๋์ , "๋ฐฉ๊ธ ๋ง๋ 1,000๋ฐ์ดํธ ๋ฒํผ ์ ์ฒด๋ฅผ ์ฌ์ฉ์์๊ฒ ๋ณด๋ด๋ผ"๊ณ ์ฒ๋ฆฌํ๋ค.
// message_compressor_zlib.cpp ๋ด๋ถ์ ์์ถ ํด์ ํจ์ ๋ก์ง // (์ดํด๋ฅผ ๋๊ธฐ ์ํด ๊ฐ๋ตํ๋ C++ ์ฝ๋) void ZlibCompressor::uncompress(const char* input, size_t inputLen, char* output, size_t expectedUncompressedLen) { z_stream strm; // ... zlib ์ด๊ธฐํ ... strm.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(input)); strm.avail_in = inputLen; strm.next_out = reinterpret_cast<Bytef*>(output); // ์ทจ์ฝ์ ์ง์ : expectedUncompressedLen(ํค๋์์ ์จ ๊ฐ)๋งํผ ์ถ๋ ฅ์ ํ์ฉํจ strm.avail_out = expectedUncompressedLen; int ret = inflate(&strm, Z_FINISH); if (ret != Z_STREAM_END) { // ์๋ฌ ์ฒ๋ฆฌ... } // [์น๋ช ์ ๊ฒฐํจ] // ์ค์ ๋ก ์์ถ ํด์ ๋ ๋ฐ์ดํฐ ์(strm.total_out)์ ํ์ธํ์ง ์๊ณ , // ์ฌ์ฉ์๊ฐ ์์ฒญํ expectedUncompressedLen ์ ์ฒด๋ฅผ ์ ํจํ ์๋ต์ผ๋ก ๊ฐ์ฃผํ์ฌ ๋ฐํํจ. }Step 5) ์ ๋ณด ํ์ทจ
๊ณต๊ฒฉ์๋ ์์ ์ด ๋ณด๋ธ 10๋ฐ์ดํธ ๋ฐ์ดํฐ์ ํจ๊ป, ์๋ฒ ๋ฉ๋ชจ๋ฆฌ์ ๋จ์์๋ ๋ค๋ฅธ ์ฌ์ฉ์์ ๋น๋ฐ๋ฒํธ, ์ธ์ ํ ํฐ, API ํค, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ ๋ด์ฉ ๋ฑ์ด ๋ด๊ธด 990๋ฐ์ดํธ์ ์ ๋ณด๋ฅผ ๊ณ ์ค๋ํ ๋ฐ๊ฒ ๋๋ค.

์ด์ฒ๋ผ {"action":"ping"}์ด๋ผ๋ ์งง์ ๋ฐ์ดํฐ ๋ค์, ์ด์ ์ ๋ก๊ทธ์ธํ๋ ๋ค๋ฅธ ๊ด๋ฆฌ์์ ๋น๋ฐ๋ฒํธ ํด์ ๊ฐ์ด๋ ์ธ์ ID ๋ฑ์ด ์ ์ถ๋ ์ ์๋ค. ๐ชข ๋ชฝ๊ณ ๋ธ๋ฆฌ๋(MongoBleed) PoC
https://github.com/joe-desimone/mongobleed
GitHub - joe-desimone/mongobleed
Contribute to joe-desimone/mongobleed development by creating an account on GitHub.
github.com
PoC ์ฝ๋๋ ์ github์์ ํ์ธํ ์ ์๋ค. ์ฃผ์ ์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด,
1. BSON ๊ธธ์ด ์กฐ์ (send_probe ํจ์)
# ์ค์ ๋ฐ์ดํฐ๋ ์์ฃผ ์์ง๋ง, ์ ์ฒด ๊ธธ์ด(doc_len)๋ฅผ ์์ฃผ ํฌ๊ฒ ์์ content = b'\x10a\x00\x01\x00\x00\x00' # int32 a=1 (์ค์ ๋ก ๋ช ๋ฐ์ดํธ ์ ๋จ) bson = struct.pack('<i', doc_len) + content # ํ์ง๋ง doc_len์๋ 1000 ๊ฐ์ ํฐ ๊ฐ์ ๋ฃ์2. ๋ชฝ๊ณ ๋ธ๋ฆฌ๋ ํธ๋ฆฌ๊ฑฐ (OP_COMPRESSED)
# OP_COMPRESSED ํค๋ ๊ตฌ์ฑ payload = struct.pack('<I', 2013) # original opcode (OP_MSG) payload += struct.pack('<i', buffer_size) # [ํต์ฌ] ๊ฑฐ์ง๋ ์์ถ ํด์ ํฌ๊ธฐ ์ ๋ ฅ payload += struct.pack('B', 2) # zlib ์์ถ ๋ฐฉ์ ์ง์ payload += compressed # ์์ถ๋ ๋ฐ์ดํฐ ์ถ๊ฐ3. ์๋ฌ ๋ฉ์์ง๋ฅผ ์ด์ฉํ ํ์ทจ (extract_leaks ํจ์)
# ์๋ฌ ๋ฉ์์ง ์์: "field name '๊ด๋ฆฌ์๋น๋ฐ๋ฒํธ123' is invalid" for match in re.finditer(rb"field name '([^']*)'", raw): data = match.group(1) leaks.append(data)=> ๋ชฝ๊ณ ๋ธ๋ฆฌ๋ ์ทจ์ฝ์ ์ ์ฝ๋์์๋ ์ ์ ์๋ฏ์ด, ๋จ์ํ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋๋ ค๋ฐ๋ ๊ฒ์ ๊ทธ์น์ง ์๊ณ , BSON ํ์ฑ ์๋ฌ๋ฅผ ์ ๋ํ๋ค. ์๋ฒ๊ฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฝ๋ค๊ฐ "์ด? ์ด ๋ฐ์ดํฐ๋ ์ด๋ฆ์ด ์ด์ํ๋ฐ?"๋ผ๊ณ ์๋ฌ ๋ฉ์์ง์ ๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ํฌํจํ๊ฒ ๋ง๋๋ ๋ฐฉ์์ด๋ค.
๐ฐ ๋ชฝ๊ณ ๋ธ๋ฆฌ๋(MongoBleed) vs ํํธ๋ธ๋ฆฌ๋(HeartBleed)
๊ตฌ๋ถ ํํธ๋ธ๋ฆฌ๋ (Heartbleed) ๋ชฝ๊ณ ๋ธ๋ฆฌ๋ (MongoBleed) ์๋ณ ๋ฒํธ CVE-2014-0160 CVE-2025-14847 ๊ณต๊ฒฉ ๋์ OpenSSL (์น ์๋ฒ ์ํธํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ) MongoDB (๋ฐ์ดํฐ๋ฒ ์ด์ค ์์คํ ) ๋ฐ์ ์ง์ ์ ์ก ๊ณ์ธต (TLS/SSL ํํธ๋นํธ ํ์ฅ) ์ ํ๋ฆฌ์ผ์ด์ ๊ณ์ธต (zlib ์์ถ ๋ก์ง) ์กฐ์ ๋ฐฉ์ ๋จ์ํ ํ์ด๋ก๋ ๊ธธ์ด ๊ฐ ์กฐ์ ์ด์ค ์กฐ์ (์์ถ ํค๋ + BSON ๊ธธ์ด) ์ ์ถ ๋ฐ์ดํฐ ์๋ฒ ๊ฐ์ธํค, ์ฟ ํค, ์ฌ์ฉ์ ์์ด๋/๋น๋ฒ DB ๊ด๋ฆฌ์ ์ธ์ , ์ฟผ๋ฆฌ๋ฌธ, ์์ค์ฝ๋ ํค ํ์ง ๋์ด๋ ๋งค์ฐ ๋ฎ์ (๋น์ ์ ํจํท ํ์ง ์ฌ์) ๋์ (์ ์์ ์ธ ์์ถ ํต์ ์ผ๋ก ์์ฅ) 'News' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[2025-12-09] Stop Putting Your Passwords Into Random Websites (0) 2025.12.10 [CVE-2025-55182] React2Shell (0) 2025.12.08 1129 ๋ณด์๋ด์ค (0) 2022.11.29 0913 ๋ณด์๋ด์ค (0) 2022.09.13 0912 ๋ณด์๋ด์ค (0) 2022.09.12