티스토리 뷰

728x90
반응형

if(preg_match('/prob|_|\.|\(\)|#|-/i', $_GET[pw])) exit("No Hack ~_~"); 
if(strlen($_GET[pw])>6) exit("No Hack ~_~");

pw 파라미터 한 개를 입력받습니다. 근데 필터링이 prob, _(언더바), .(온점), ()(괄호), #(샵), -(빼기) 가 있고, 심지어 pw 의 길이가 6개 이하로 제한되어 있습니다. 6개를 넘을 수 없는 것으로 제한이 심한 것으로 보아 정답이 정해져있는 것 같습니다.

 

$query = "select id from prob_nightmare where pw=('{$_GET[pw]}') and id!='admin'"; 
echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
$result = @mysqli_fetch_array(mysqli_query($db,$query)); 
if($result['id']) solve("nightmare");

사용자로부터 입력받은 pw 파라미터가 들어간 query 구문의 결과 값으로 id 가 존재할 경우 문제가 풀리는 것으로 보아 해당 구문이 무조건 True(참)이 되게 해야하는 문제 같습니다.

 

우선 query문을 면밀히 살펴보겠습니다.

select id from prob_nightmare where pw=('') and id!='admin'

where 절의 and 옆에 id!='admin' 이라고 되어 있는 부분이 있는 한 무조건 admin 이 아닌 계정의 비밀번호를 맞춰야 할 것 같습니다. 하지만 이렇게 되서는 아무리 admin 이 아닌 계정의 pw 가 hex 값이며 동시에 6자리라고 하더라도 무수히 많은 값을 bruteforce(무작위대입)을 해보아야 할 것입니다. 계산해보면 무려 16,777,216 번을 대조해봐야 하는데, 아무리 빠른 컴퓨터라도 우리 컴퓨터는 문제 없을 지 모르겠지만, 워게임을 운영하는 서버에는 무리가 갈 수도 있을 것 같습니다.

 

그렇기 때문에더라도 and를 포함한 뒤 문장을 주석으로 제거를 해줘야 할 것 같아보입니다. MySQL 에는 주석으로 # 와 -- - 문자 외에도 NUL 문자도 있습니다. 그리고 URL 에서 이 NUL 문자를 넣어주기 위해서는 아스키코드표에 의해서 0 값입니다.

https://www.asciitable.com/

그리고 0 을 URL 인코딩 해주면 %00 이 됩니다. 이제 한번 괄호 뒤의 문장을 제거해보겠습니다.

pw=%27)%00

%27 은 위 아스키코드표를 보시면 아시겠지만 16진수로 27에 해당하는 '(작은따옴표)를 나타냅니다. 그리고 %00 은 NUL 문자입니다. 이렇게 입력하고 보면 query문은 아래와 같이 될 것입니다. 대신에 NUL 문자를 사용했을 때는 query문의 끝을 반드시 명시해줘야 하기 때문에 query문의 마지막, 즉 NUL 문자의 바로 앞에 ;(세미콜론)을 넣어주어야 합니다.

select id from prob_nightmare where pw=('');

근데 이렇게 해서는 결과가 참이 될 수 없으므로 pw의 결과를 참으로 만들어줘야 합니다. 위에서 뒤 구문을 제거하는 데 3개의 문자를 사용했기 때문에 이제 남은 사용 가능한 문자의 개수는 3개 입니다.

pw=('')

pw 가 '' 없는 계정은 존재하지 않을 것이기 때문에 무조건 False(거짓)이 되는 query 문일 것으로 보입니다. 거짓된 구문을 참으로 만들려면 어떻게 해야할까요? 매우 쉽습니다. 아래와 같이 하면 무조건 참이 되겠습니다.

pw=('')=0
pw=('')^9
pw=('')+0
pw=('')*0
pw=('')%0
pw=('')&1

뭐 True(참)이 되게 만들 수 있는 건 위 말고도 많겠죠? 혹시 왜 위에 내용이 True(참)이 되는 지 모르시겠다면 언제든 댓글로 질문해주시면 되겠습니다.

 

아무튼 위와 같은 페이로드 중 아무거나 하나 골라서 URL 에 넣고 접속하면 아래와 같이 문제를 해결할 수 있습니다.

728x90
반응형
댓글