🏆 2024

맛집 분야 크리에이터

🏆 2023

IT 분야 크리에이터

👩‍❤️‍👨 구독자 수

182

✒️ 게시글 수

0
https://tistory1.daumcdn.net/tistory/4631271/skin/images/blank.png 네이버블로그

🩷 방문자 추이

오늘

어제

전체

🏆 인기글 순위

티스토리 뷰

보안/Wargame

[Lord of SQLi] goblin Writeup/문제 풀이

알 수 없는 사용자 2021. 5. 12. 00:07
728x90
반응형

$_GET[no]

PHP 소스코드 상으로는 no를 GET parameter 방식으로 받는다고 한다.

 

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

그리고 no에 prob 라는 단어가 포함되어 있거나, _(언더바), .(온점), ((여는 괄호), )(닫는 괄호) 를 사용하는 것을 금지하고 있다. 거기에 추가로 '(작은따옴표), "(큰따옴표), `(백쿼터)도 금지하고 있다.

 

$query = "select id from prob_goblin where id='guest' and no={$_GET[no]}"; 
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("goblin");

query 변수에 GET parameter로 전달 받은 no를 넣고, mysql에 query를 실행해봤을 때 결과로부터 id가 "admin"일 때 문제는 해결된다.

 

만약 no 파라미터를 1 이라고 아래와 같이 입력하고 요청해보면, Hello guest 라고 출력된다.

https://los.rubiya.kr/chall/goblin_3.php?no=1

 

guest의 no는 1인 걸 어림짐작으로 알 수 있다. 하지만 admin은 몇 번인걸까?

 

방법은 no를 0부터 1씩 늘려가면서 bruteforce(무작위대입) 해보는 방법이 있겠지만, 너무 비효율적이므로 다른 방법으로 접근해야할 것 같다.

 

그럼 where 구문의 앞의 문장을 false 값으로 만들고 뒤에서부터 참(true) 값을 만들면 어떨까? 아래 구문을 참고해보자.

select id from prob_goblin where id='guest' and no=0 or 1

id가 guest 이고 no 가 0 인 결과는 false 였다. 그리고 뒤의 or 1 로 인해 결과는 참이 되지만, 여전히 Hello guest 가 나온다. 그 말 뜻은 query 조회 시 결과가 여러개 나왔지만, 여러개 record 중 guest 가 가장 위에 나왔다는 뜻이 되기도 한다.

 

만약 테이블이 위와 같다면, 아래와 같은 query 구문으로 문제는 해결 가능하다.

https://los.rubiya.kr/chall/goblin_3.php?no=0 or 1 limit 1,1

limit 1, 1 은 두 번째 인덱스 요소 하나만 가져오라는 의미다. 그러므로 위 테이블 기준으로 "admin"을 가져올 수 있게 된다.

 

하지만 정석 답안지는 아닌 것 같다. 왜냐하면 이번 경우에는 어림짐작한 대로 admin 아이디가 guest 아이디 바로 밑에 있었기에 가능한 것이기 때문이다.

 

그래서 정확히 admin 아이디를 찾아내는 query 구문이 정확할 것 같다. 아래 query 구문을 보자.

select id from prob_goblin where id='guest' and no=0 or id=0x61646D696E

앞서 말했듯이 id='guest' and no=0 구문은 거짓(false)가 될 것이다. 그렇기에 뒤의 구문이 admin 을 정확히 집어내는 query 가 되는데 해석하면, id가 admin 인 것을 찾으라는 의미다.

 

위 정규식 필터링에서 따옴표는 사용할 수 없다고 하였으니, 아스키코드로 문자열을 입력해주었다. mysql 에서는 위와 같이 입력할 수 있기 때문이다. 아래의 1은 참(true)을 뜻하는 값이다.

그렇게 ascii 값을 이용하여 따옴표 필터링 방지를 우회해보았다.

 

 

- 끝 -

728x90
반응형
댓글