문제 코드

<?php
  include "./config.php";
  login_chk();
  $db = mssql_connect();
  if(preg_match('/master|sys|information|prob|;|waitfor|_/i', $_GET['id'])) exit("No Hack ~_~");
  if(preg_match('/master|sys|information|prob|;|waitfor|_/i', $_GET['pw'])) exit("No Hack ~_~");
  $query = "select * from prob_revenant where id='{$_GET['id']}' and pw='{$_GET['pw']}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  sqlsrv_query($db,$query);
  if(sqlsrv_errors()) exit(mssql_error(sqlsrv_errors()));

  $query = "select * from prob_revenant where id='admin'"; 
  $result = sqlsrv_fetch_array(sqlsrv_query($db,$query));
  if($result['4'] === $_GET['pw']) solve("revenant"); // you have to pwn 5th column
  highlight_file(__FILE__);
?>

공격 백터

  • id
  • pw

공격 백터에 대한 검증

  • id : master, sys, infomation, prob, ;, waitfor, _
  • pw : master, sys, infomation, prob, ;, waitfor, _

코드 설명

$db = mssql_connect();

MsSQL로 이루어진 문제이다.

 

$query = "select * from prob_revenant where id='{$_GET['id']}' and pw='{$_GET['pw']}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
sqlsrv_query($db,$query);
if(sqlsrv_errors()) exit(mssql_error(sqlsrv_errors()));

필터링에 통과한 공격 백터 id와 pw는 SELECT * FROM porb_revenant WHERE id='공격 백터 id' and pw='공격 백터 pw'에 들어가게 된다.
반환되는 컬럼이 *인 이유는 이 문제를 클리어하기 위한 조건이 5번째 컬럼에 들어 있기 때문이다.

 

반환 값에 대한 출력이 안 되고, Error 메시지는 출력이 된다.
즉, Error Based SQLi로 문제를 풀면 될 듯 싶다.

 

$query = "select * from prob_revenant where id='admin'"; 
$result = sqlsrv_fetch_array(sqlsrv_query($db,$query));
if($result['4'] === $_GET['pw']) solve("revenant"); // you have to pwn 5th column

이후 id가 admin인 5번째 컬럼의 값과 공격 백터 pw이 같으면 문제가 클리어 된다.


문제 풀이

현 문제는 쿼리문을 통해 Column을 찾을 방법은 필터링으로 통제하고 있다.
이러한 이유 때문에 MySQL로도 방법이 생각이 안 났다. 일단 MsSQL의 SQLi 사례를 찾아서 방법을 찾아보겠다.

참고 사이트 : Error-based SQL Injection

 

?pw=' having 1=1--

찾아본 사례로 group by와 having를 사용하면 컬럼명을 Error을 통해 출력할 수 있다.
having을 사용하는데, group이 설정되어 있지 않아서 Error 메세지로 id를 GRUOP BY로 추가하라는 문구가 출력된다.

 

Group by에 id를 추가하면, 그 다음 컬럼명이 나오고 추가하라고 한다.

 

위 방법을 반복하면 5번째 컬럼명을 얻을 수 있다.

 

이후, id가 admin이면서 9604b0c8 컬럼의 값을 비교하는데 일부러 Error를 나오게 넣으면 그 값이 출력이 된다.
위 Error는 9604b0c8 컬럼의 값은 varchar형인데 숫자형처럼 비교하여 발생된 것이다.

 

알아낸 값을 pw 파라미터에 넣어서 보내면 문제를 클리어할 수 있다.
이번 문제로 MsSQL은 Error에 굉장히 취약하다는 것을 배울 수 있었다.


Group by

레코드 조회시 각 레코드를 하나의 그룹으로 묶어서 표현해주는 역활

위와 같은 데이터를 반 별로 그룹화 시켜서 집계를 하고 싶을 경우, Group By을 사용하면 된다.

 

출처 : MSSQL GROUP BY 활용하기 : 네이버 블로그

Having

GROUP BY를 통해 묶인 레코드 그룹에 대해 조건을 거는 역할을 합니다.
ex). having 점수 > 80

복사했습니다!