본문 바로가기

챌린지/los.rubiya.kr

Lord of SQLInjection - skeleton

10번째 문제인 skeleton이다.

<?php 
  include "./config.php"; 
  login_chk(); 
  $db = 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 = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if($result['id'] == 'admin') solve("skeleton"); 
  highlight_file(__FILE__); 
?>

별다른 필터링은 없는데 쿼리에서는 guest의 id로 조회하고 있지만 결과에서 요구되는 id는 admin이다. 그리고 특이하게 쿼리 마지막에 1=0이라는 조건이 AND 연산으로 들어가 있다. 즉 이 구문이 존재하는 한 앞에서 무슨 쿼리를 해도 무조건 거짓으로 만들어서 결과가 아무것도 나오지 않게 되는데 이를 우회하려면 어떻게 해야 할까?

 

이전 문제들처럼 뒤의 쿼리를 주석으로 없애버릴 수도 있지만 다른 조건을 줘서 이 1=0이라는 거짓 조건이 다른 조건에 합산되게 만들 수도 있다. mysql에서 AND, OR 연산자는 프로그래밍 언어처럼 AND가 OR에 우선한다. 그렇기 때문에 <conditionA> AND <conditionB> OR <conditionC>는 (<conditionA> AND <conditionB>) OR <conditionC>처럼 동작한다. 아래 예를 보자.

select "CORRECT" where 1=1 AND 1=2 OR 2=2 // CORRECT
select "CORRECT" where 1=1 AND 1=2 OR 2=1

위의 쿼리에서 1=1 AND 1=2는 하나로 묶였기 때문에 1=2 조건에 의해 항상 거짓이 된다. 그래서 OR 조건의 2=2, 2=1에 의해 쿼리의 성공과 실패가 결정된다. 이를 문제에 적용해보면 다음과 같이 작성할 수 있다.

select id from prob_skeleton where id='guest' and pw='1' or id='admin' or id='guest' and 1=0

이 쿼리는 OR 연산으로 묶인 "id='guest' and pw='1'"과 "id='admin'", 그리고 "id='guest' and 1=0"으로 나눌 수 있다. 첫번째의 경우 guest 계정의 비밀번호는 1이 아닐것이기 때문에 거짓이 되며 세번째는 1=0때문에 거짓이 되기 때문에 남은 "id='admin'" 조건만이 참이 되며 이에 의해서 admin 계정의 id가 쿼리 결과에 포함되기 때문에 문제를 풀 수 있다.

아니면 그냥 이전처럼 주석으로 없애버릴 수도 있다.

딱히 필터링되는 게 없기 때문에 쉽게 풀 수 있다.

 

 

이번 문제는 mysql에서 AND, OR 연산자의 우선순위를 좀 알아보게 되는 문제인 것 같다.

'챌린지 > los.rubiya.kr' 카테고리의 다른 글

Lord of SQLInjection - darkknight  (0) 2021.01.01
Lord of SQLInjection - golem  (0) 2020.12.31
Lord of SQLInjection - vampire  (0) 2020.12.30
Lord of SQLInjection - troll  (0) 2020.12.28
Lord of SQLInjection - orge  (0) 2020.12.27