wargame/Lord Of SQL Injection

[LOS] kraken

LimeLee 2019. 7. 26. 11:02

소스코드 분석

<?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__);
?>
  1. $db = mssql_connect("kraken"); > db환경이 mssql

  2. 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 탈취

  3. if($result['id']) echo "<h2>{$result['id']}</h2>"; > id가 존재할 경우 id를 출력 > Union SQL Injection 가능

문제 풀이

쿼리의 from절에서 불러오는 member 테이블엔 kraken 문제의 목표라고 할 수 있는 flag 값이 존재하지 않으므로 union을 이용한다.

 

flag 테이블 명을 모르므로 일단 테이블 명 탈취하는 것 부터 시작한다.

 

mysql과 동일하게 information_schema라는 테이블이 존재한다. 필터링이 걸려있기에 information_schema 테이블을 통한 테이블 명 탈취는 어렵다.

 

http://pentestmonkey.net/cheat-sheet/sql-injection/mssql-sql-injection-cheat-sheet

 

MSSQL Injection Cheat Sheet | pentestmonkey

MSSQL Injection Cheat Sheet Some useful syntax reminders for SQL Injection into MSSQL databases… This post is part of a series of SQL Injection Cheat Sheets.  In this series, I’ve endevoured to tabulate the data to make it easier to read and to use the sam

pentestmonkey.net

그래서 sysobjects를 이용한다. 조건절에 type='U'를 삽입하여 유저가 사용중인 테이블만 반환한다.

 

?id=1' union select top 2 name from sysobjects where type='U' -- -

테이블 명은 "flag_ccdfe62b"인 것을 확인했다. sqlite 환경에서의 union sql injection 문제 poltergeist에서는 운이 좋게도 첫 결과 값이 flag 테이블 명이였지만, 이번 문제에서는 특수한 조건을 걸어주지 않았을 시 a_dummy_table이라는 테이블 명을 반환한다. sqlite나 mysql이랑은 달리 limit라는 기능이 존재 하지 않아서 이를 직접 구현해주어야 한다.

 

top 2를 이용해서 flag 테이블 명을 반환할 수 있었지만 사실 이는 limit 1,1의 의미는 아니다 limit 0,2와 같은데 굳이 말하자면 해당 쿼리도 운이 좋아서 반환 된 것이다. 맨 위에서 2개만 뽑아서 반환했는데 어찌저찌하니 flag 테이블이 최상위로 올라오게 되면서 출력이 된 것이지. 같이 뽑힌 테이블 명에 따라 flag 테이블이 안나올 가능성이 존재한다. top에 대해 잘못 이해를 할 수도 있으므로 어째서 이런 쿼리로 뽑아낼 수 있었는지 분석해보자.

 

결론부터 말하자면 kraken 문제에 사용되는 테이블은 다음과 같은 순서로 생성되었다.

 

member가 가장 먼저, 그리고 최상위에 flag 테이블이 노출되지 않도록 만들어 둔 더미 테이블 a_dummy_table이 가장 나중에 생성되었다.

 

여기서 궁금증이 발생한다. 조건 없이 union select를 해주었을 때는 a_dummy_table이 가장 최상위로 나왔을 것이다. 그러면 member가 아닌 a_dummy_table이 가장 먼저 만들어졌다고 가정할 수 있다.

 

이는 다음 그림에서 설명 가능하다.

 

union이 아닌 일반적으로 한 테이블을 select하였을 때에는 만들어진 순서로 나열이 되지만, union select를 통해 별 다른 정렬 옵션 없이 값을 불러오게 되면 오름차 순으로 정렬된다. union select를 하면 오름차 순 정렬이 된다는 것을 확인했다.

 

여기서 또 다른 궁금증이 발생하게 될 것이다. union select로 값을 불러올 때 top n을 사용하게 되면 최상위에 있는 것 부터 n개를 뽑아올텐데 정렬이 우선인지 top이 우선인지 궁금할 것이다. 이를 직접 확인해보자.

 

top이 우선, 정렬이 나중으로 top 1에 의해 가장 먼저 생성된 member 테이블 명 하나를 반환하고 이를 오름차 순 정렬하여 member가 최상위로 뜨게 되었다.

 

union select는 디폴트로 오름차순 정렬이 되는 사실과 정렬이 나중에 되는 사실을 합쳐 top 2에서 flag 테이블 명이 최상위로 나오는 이유를 설명할 수 있다.

 

 

정렬보다 top 2가 먼저 실행되므로 먼저 생성된 테이블 기준으로 2개를 반환한다. 가장 먼저 생성된 member와 그 다음 생성된 flag 테이블 명을 반환한다. 그 다음 디폴트로 지정된 오름차 순 정렬을 실행한다. m으로 시작하는 member 테이블 보다 flag 테이블 명이 오름차순 정렬에서 먼저 반환되게 되므로 flag 테이블 명을 최상위로 반환한다.

 

만약 a_dummy_table이 가장 먼저 생성된 테이블이라면? 당연히 같은 쿼리임에도 불구하고 flag 테이블 명을 볼 수 없었을 것이다.

 

그렇다면 mysql에서 사용하는 limit와 동일한 기능을 구현하려면 어떤 식으로 쿼리를 짜야할까?

 

쿼리는 아래와 같다.

select a from member union select top n name from sysobjects where type='U' and name not in (select top m name from sysobjects where type='U'

 

이는 limit m,n을 걸어준 것과 같다. m에 1, n에 1을 넣으면 2번째인 flag 테이블 명을 반환할 것이다.

 

반환된 것을 확인할 수 있다.

 

다시 문제로 돌아가서 테이블 명을 찾았으니 flag가 들어있는 flag 컬럼을 찾도록 한다.

 

?id=1' union select top 3 name from sys.columns -- -

 

해당 쿼리도 member 테이블의 컬럼 id, pw보다 오름차순으로 flag 컬럼명이 먼저 나오기 때문에 운이 좋아 나온 것이다. 좀 더 정확하게 뽑아내려면 다음과 같은 쿼리를 요청해야한다.

 

?id=1' union select top 1 name from sys.columns where name not in (select top 2 name from sys.columns) -- -

 

찾아낸 테이블 명, 컬럼 명을 이용해 flag를 출력한다.

 

?id=1' union select flag_ab15b600 from flag_ccdfe62b-- -

?pw=FLAG{a0819fc56beae985bac7d175c974cd27}

클리어

'wargame > Lord Of SQL Injection' 카테고리의 다른 글

[LOS] siren  (0) 2019.07.26
[LOS] cerberus  (0) 2019.07.26
[LOS] mummy  (0) 2019.07.26
[LOS] yeti  (0) 2019.07.26
[LOS] revenant  (1) 2019.07.26