Write-Up
if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
$query = "select id from prob_dragon where id='guest'# and pw='{$_GET[pw]}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['id']) echo "<h2>Hello {$result[id]}</h2>";
if($result['id'] == 'admin') solve("dragon");
해당 challenge에 해당하는 필터링 조건 및 pass 조건은 위와 같다. 눈에 띄는 점은 query에 #이 들어가 있다는 점이다.
#은 주석을 의미한다. 다만, 한라인에서 # 다음에 오는 것들을 주석처리 하는 것이다. 그러므로 pw 파라미터의 인자 값으로 %0d%0a (개행) 문자를 넣어주면 문제를 해결할 수 있다.
처음 시도한 payload : id='guest'# and pw=%27%0d%0aor%201=1%23
주황색 부분이 주석 및 개행처리되어진다고 생각하면 된다. ( %0d%0a 는 개행을 담당 ) 다만, 위의 payload는 정답이 아니다. 그 이유는 id='guest'or 1=1%23과 같이 해석되기에 guest가 페이지에 출력된다. 그러므로 앞의 id='guest' 인 부분을 false 값으로 만들어 줄 수 있는 방법을 생각해야 한다.
두번째 payload : pw=%0d%0aand pw='12' or id='admin'%23
위와 같은 payload로 문제를 해결할 수 있었다. ( %0d%0a가 아닌, %0a 만으로도 개행이 이뤄지긴한다. )
참고
LF : 커서( \n, 0x0a )를 한칸 아래로 이동 = 새로운 행 추가(new line feed)
CR : 커서( \r, 0x0d )를 맨왼쪽으로 이동 = 시작위치로 복귀(return)
참고로, 리눅스에서는 개행문자로 LF (0x0a) 만 사용되지만, 윈도우에서는 개행문자로 CRLF (0x0d 0x0a) 로 표시하여 1Byte가 더 크게 적용된다.