오늘도 익숙한 화면이네요.

SQL INJECTION 이라고 크게 적혀있는걸 보니 인젝션 공격을 활용하는 문제겠네요.

바로 코드 보겠습니다.

 

<?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 27</title>
</head>
<body>
<h1>SQL INJECTION</h1>
<form method=get action=index.php>
<input type=text name=no><input type=submit>
</form>
<?php
  if($_GET['no']){
  $db = dbconnect();
  if(preg_match("/#|select|\(| |limit|=|0x/i",$_GET['no'])) exit("no hack");
  $r=mysqli_fetch_array(mysqli_query($db,"select id from chall27 where id='guest' and no=({$_GET['no']})")) or die("query error");
  if($r['id']=="guest") echo("guest");
  if($r['id']=="admin") solve(27); // admin's no = 2
}
?>
<br><a href=?view_source=1>view-source</a>
</body>
</html>

 

최근에 풀었던 문제랑 상당히 유사해 보이네요.

차근차근 한 줄씩 해석해보겠습니다.

if(preg_match("/#|select|\(| |limit|=|0x/i",$_GET['no'])) exit("no hack");

 

GET방식으로 no에 받아온 값에 대하여 필터링을 거는 코드입니다.

/, #, \, (, 공백, =, 0x 들과 selcet, limit을 필터링 하고있네요.

만약 위 같은 문자가 들어오면 no hack을 출력하며 값을 처리하지않겠다고 하네요.

$r=mysqli_fetch_array(mysqli_query($db,"select id from chall27 where id='guest' and no=({$_GET['no']})")) or die("query error");

 

어쩌면 가장 중요하다고 할 수 있는 쿼리문입니다.

쿼리문이 어긋나면 query error를 출력함과 동시에 쿼리를 실행시키지않고 죽여버리네요.

최근에 봤던 문제와 쿼리문이 흡사하지만 가장 중요하면서 놓치기 쉬운 부분이있습니다.

and no=({$_GET['no']})"

바로 입력받는 값들이 ( ) 괄호로 감싸져있다는 겁니다.

조금 뒤에 더 자세히 설명하겠습니다.

if($r['id']=="guest") echo("guest");
if($r['id']=="admin") solve(27); // admin's no = 2

id가 admin이라면 문제가 풀린다고합니다. 그리고 주석에 힌트로 admin의 no값은 2라고 하네요.

 

이 문제를 풀기 위해서는 no에 2라는 값을 넣는것과 동시에 where절에 적혀있는 id = 'guest' 라는 쿼리문을 무력화 시켜야합니다.

결국 no에 2라는 값을 넣어도, id가 guest라면 문제가 해결되지 않기 때문입니다.

 

그럼 where절을 무력화 시키는 sql 인젝션 공격을 해야하는데.. 

자주 해보던 쿼리문을 대입해보면

no=(0 or 1=1 -- )")) or die("query error");

0 or 1=1 -- 이라는 쿼리문을 넣었을 때 결과입니다.

이때 공백도 필터링되니 입력할땐 우회를 해야겠죠.

평소에 넣던 쿼리문을 넣어보았지만.. 보시다시피 정상적인 쿼리문이 아니게됩니다. 괄호가 괴롭히고있네요.

주석문인 -- 을 제거해봐도

no=(0 or 1=1)")) or die("query error");

괄호는 우선적으로 연산되기에 괄호안에서 0 or 1=1이 연산되어 결국 ture(1)이 되버립니다.

정상적인 쿼리는 맞지만 우리가 원하는 결과는 아닙니다. guest로 로그인되죠.

즉 자주 쓰던 or을 이용한 앞부분의 where절을 무력화시키는건 불가능합니다.

 

그럼 괄호를 무력화해야하는데 필터링 목록 중 괄호가 있었죠.

근데... 필터링 목록에 괄호가 두 개 모두 있었나요.?

if(preg_match("/#|select|\(| |limit|=|0x/i",$_GET['no'])) exit("no hack");

자세히 보시면 ( 는 있지만 )이 없습니다.

그렇다는건 ) 를 통해 앞선 괄호를 무력화하고 인젝션 문을 적으면 해결될 것 같네요.

no=(2) or no=2 -- )")) or die("query error");

이런식으로 쿼리를 삽입하면 앞에 where절이 or문으로 날라가면서 해결될듯합니다.

잠깐 잊고있었는데  = 도 필터링이 되죠.

= 가 필터링 될 때 사용 할 수 있는 방법으로 like와 between이 있습니다.

like는 = 과 똑같은 역할을 합니다.

between은 between A and B 같은 형식으로 작성 하는데, 뜻은 값이 A 이상 B 이하 일 때 참 이라는 뜻입니다.

즉 between 2 and 2라고 적으면 사실상 = 2 와 같은 뜻인거죠.

 

저는 이번 문제에서는 like를 사용해보았습니다.

= 자리에 like를 써주고, 공백은 가장 자주 통과되는 %0a와 %09 중 %09를 사용하여 우회 해봤습니다.

 

그렇게 해서 완성된 인젝션 문은

2)%09or%09no%09like%092%09--%09 입니다.

GET방식으로 입력받기에 url에 ?no= 를 덧붙인 후 인젝션 문을 넣어주면....

 

해결 완료입니다!

'보안 > 워게임 (웹 해킹)' 카테고리의 다른 글

Challenge - old-25 write up  (0) 2025.04.12
Challenge - old-23 write up  (0) 2025.04.12
Challenge - old-54 write up  (0) 2025.04.05
Challenge - old-38 write up  (0) 2025.04.05
Challenge - old-39 write up  (0) 2025.04.04

+ Recent posts