소소한 IT이야기/WARGAME

[Lord of SQL Injection] dark_eyes 22번

Klaus 2023. 3. 27. 17:12

0. 기존 문제 풀이

https://toriyong.tistory.com/category/%EB%AA%A8%EC%9D%98%ED%95%B4%ED%82%B9/Wargame

 

1. 전체 코드

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

2. 분석

[+] 필터링 부분

  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
  if(preg_match('/col|if|case|when|sleep|benchmark/i', $_GET[pw])) exit("HeHe");
  • 첫 번째 줄은 기존 문제들과 동일하게 필터링되고 대소문자 구별이 없다. 필터링되는 문자를 사용 시 exit 된다.
  • 두 번째 줄은 Time based SQL i를 제안하는 것과 if, col, case, when이 필터링된다.
  • 이번에 조건문 중 까다로운 점은 if와 case문이 필터링되기 때문에 필터링을 우회할 방법을 찾아보니, coalesce() 함수, order by 를 활용하여 우회할 수 있을 것 같다.

 

[+] coalesce()함수

  • 여러 개의 값을 입력하여 첫 번째로 널(null)이 아닌 값을 리턴하는 함수로 해당 문제에서는 첫번째 값에서 SQL쿼리에 where조건문을 활용하여 조건이 맞지 않다면 null을 리턴하도록 설정할 수 있다.

 

[+] order by

  • 추가적으로 정렬을 할 때 사용하는 order by도 사용할 수 있다 기본적으로는 오름차순으로 정렬되고 칼럼명 뒤에 DESC를 붙이면 내림차순으로 정렬된다.

 

[+] mysqli_error($db)) exit();

  • 문제 중간에 에러는 표시되지 않는다. 즉 에러가 발생한다면 화면에 아무것도 출력되지 않게 된다는 점에서 아무 화면도 출력되지 않는다?
  • 즉, Error based SQLi 문제인 것을 확인할 수 있습니다.

 

[+] 클리어 조건

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

3.Solve

[+] stop01. 패스워드 길이 확인

  • 해당 패이로드 값이 참이라면 화면에 출력되고 거짓값이라면 출력되지 않는다. (mysqli_error($db)) exit();)
  • 즉, 패스워드 길이는 8글자인 것을 확인할 수 있다. 
?pw=' or id='admin' and (select 1 union select 0 where length(pw)>8)%23%20

참값일 때는 화면이 출력되고, 거짓일 경우 아무런 화면이 나오지 않는다.

 

[+] py 코드 작성