wargame/Lord Of SQL Injection

[LOS] red_dragon

LimeLee 2018. 7. 22. 20:34

$password = md5('red_dragon_bc36');공개


green_dragon이랑 이미지가 비슷하길래 문제해석도 비슷할 줄 알았지만 아니였음. 

문제 이름이 비슷하다고 문제 풀이 방법도 비슷할거라는 틀에 박혀서 상당히 애먹었다.

거의 다 가르쳐준거 같지만 힌트를 받아서 문제를 해결했다.


소스 코드 분석


<?php
  
include "./config.php";
  
login_chk();
  
dbconnect();
  if(
preg_match('/prob|_|\./i'$_GET['id'])) exit("No Hack ~_~");
  if(
strlen($_GET['id']) > 7) exit("too long string");
  
$no is_numeric($_GET['no']) ? $_GET['no'] : 1;
  
$query "select id from prob_red_dragon where id='{$_GET[id]}' and no={$no}";
  echo 
"<hr>query : <strong>{$query}</strong><hr><br>";
  
$result = @mysql_fetch_array(mysql_query($query));
  if(
$result['id']) echo "<h2>Hello {$result['id']}</h2>";

  
$_GET[pw] = addslashes($_GET[pw]);
  
$query "select pw from prob_red_dragon where id='admin' and pw='{$_GET[pw]}'";
  
$result = @mysql_fetch_array(mysql_query($query));
  if((
$result['pw']) && ($result['pw'] === $_GET['pw'])) solve("red_dragon");
  
highlight_file(__FILE__);
?>

id는 7자를 초과할 수 없다. 7자로 어떻게 변조할 수 있을지 생각해보아야 한다.

no는 is_numeric필터링을 하고 있다. is_numeric 취약점이 있는지 확인하자

addslashes를 통해 pw값을 검증한다 blind sql일 확률이 높다.  하지만 no엔 잘해봤자 문자열 밖에 안 들어간다. blind sql이 어떻게 가능할까?


풀이


7자리엔 무엇이 들어갈지 아직 감이 안잡히니 is_numeric 취약점이 있나 확인해보자. 구글링을 해서 나오겠지만

is_numberic은 단순 정수 외에도 234.23등의 실수 1e+3등의 지수 0x3444 같은 16진수를 허용한다.

그리고 헥스값은 mysql에서 알아서 문자열로 변환시켜준다.


query : select id from prob_red_dragon where id='' and no=0x0111

no 파라미터에 0x0111 요청했을 때 출력하는 쿼리의 no가 1이 아닌 0x0111로 나오는 것을 확인 할 수 있다.

no에 원하는 문자열을 삽입할 수 있다. 사실 green_dragon 때처럼 hex로 쿼리를 만들어 푸는 것인줄 알고 이런 저런 노력을 다 해봤지만

그 문제 처럼 쿼리를 두번 거쳐서 헥스를 알아서 decode 시켜주질 않아서 사실 상 불가능하다.  

no는 정수형 컬럼인데 no에서 아무리 헥스로 문자열로 우회시켜봤자 소용이 없다. no에서 나가야한다.


LOS dragon 문제에서 사용한 우회 기술을 이용한다,

id 파라미터에 주석문자를 이용하여 주석 문자를 뒤로 한 라인을 전부 주석으로 처리해버린다.


query : select id from prob_red_dragon where id=''#' and no= 0x0111

글자 수 제한이 있으므로 '#' 주석문자를 사용했다. 주석문자를 사용하여 'and no가 주석처리가 되어진다.

no파라미터에는 %0a 를 이용해서 줄띄움을 함으로써 주석처리가 되지 않는다. is_numeric은 검증할 문자가 앞에 있는 공백과 그 대체 문자열(%09,%20,%0a 등)을 검증에 포함시키지 않는다.

그래서 no 파라미터에 %09를 넣어도 필터링에 걸리진 않는다. 해당 문제의 is_numeric 우회 포인트는 헥스값 등을 숫자로 인식한다는 점이 아닌 공백 문자를 인식하지 못하는 점을 알고 있어야 했다.  이 부분을 힌트로 받아내었다.


가져오고 싶은 값은 pw이므로 id 파라미터를 이용해서 pw blind sql injection을 시도한다.


query : select id from prob_red_dragon where id=''||pw=#' and no= 0x0111

id 파라미터의 길이를 7넘기지 않았다. 다만 "'||pw=#"만으로 이미 7자를 다 사용하여 length나 substr,mid 등  blind sql에 일반적으로 사용하던 함수를 이용할 수 없다. 이는 부등호를 이용해서 한자리 씩 값을 알아낼 수 있다.


만약 패스워드가 12345678 일 경우 비교값이 2이면 12345678보다 크고 1이면 12345678보다 값이 작고 할 수 있다.

이런식으로 13은 12345678보다 크고 12는 12345678보다 작다는 식의 blind sql을 계속 해 나가면 패스워드의 값을 알아낼 수 있다.



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

[LOS] ouroboros  (0) 2018.08.09
[LOS] phantom  (0) 2018.08.09
[LOS] frankenstein  (0) 2018.08.09
[LOS] blue_dragon  (0) 2018.07.24
[LOS] green_dragon  (2) 2018.07.22