본문 바로가기
드림핵

[드림핵][wargame.kr] counting query 풀이

by jwcs 2024. 4. 16.
728x90

https://dreamhack.io/wargame/challenges/342

 

[wargame.kr] counting query

Description Error based SQLi Challenge

dreamhack.io

 

error based sql injection 문제이다.

 

/

아이디와 패스워드를 입력할 수 있고 타입을 지정할 수 있는 페이지다. 소스 코들르 보면서 분석해보자.

 

<?php
 if (isset($_GET['view-source'])) {
     show_source(__FILE__);
     exit();
 }
 include("./inc.php"); // database connect, $FLAG.
 ini_set('display_errors',false);

 function err($str){ die("<script>alert(\"$str\");window.location.href='./';</script>"); }
 function uniq($data){ return md5($data.uniqid());}
 function make_id($id){ return mysql_query("insert into all_user_accounts values (null,'$id','".uniq($id)."','guest@nothing.null',2)");}
 function counting($id){ return mysql_query("insert into login_count values (null,'$id','".time()."')");}
 function pw_change($id) { return mysql_query("update all_user_accounts set ps='".uniq($id)."' where user_id='$id'"); }
 function count_init($id) { return mysql_query("delete from login_count where id='$id'"); }
 function t_table($id) { return mysql_query("create temporary table t_user as select * from all_user_accounts where user_id='$id'"); };

 if(empty($_POST['id']) || empty($_POST['pw']) || empty($_POST['type'])){
  err("Parameter Error :: missing");
 }

 $id=mysql_real_escape_string($_POST['id']);
 $ps=mysql_real_escape_string($_POST['pw']);
 $type=mysql_real_escape_string($_POST['type']);
 $ip=$_SERVER['REMOTE_ADDR'];

 sleep(2); // not Bruteforcing!!

 if($id!=$ip){
  err("SECURITY : u can access with allotted id only");
 }

 $row=mysql_fetch_array(mysql_query("select 1 from all_user_accounts where user_id='$id'"));
 if($row[0]!=1){
  if(false === make_id($id)){
   err("DB Error :: create user error");
  }
 }
 
 $row=mysql_fetch_array(mysql_query("select count(*) from login_count where id='$id'"));
 $log_count = (int)$row[0];
 if($log_count >= 4){
  pw_change($id);
  count_init($id);
  err("SECURITY : bruteforcing detected - password is changed");
 }
 
 t_table($id); // don`t access the other account

 if(preg_match("/all_user_accounts/i",$type)){
  err("SECURITY : don`t access the other account");
 }

 counting($id); // limiting number of query

 if(false === $result=mysql_query("select * from t_user where user_id='$id' and ps='$ps' and type=$type")){
  err("DB Error :: ".mysql_error());
 }

 $row=mysql_fetch_array($result);
 
 if(empty($row['user_id'])){
  err("Login Error :: not found your `user_id` or `password`");
 }

 echo "welcome <b>$id</b> !! (Login count = $log_count)";
 
 $row=mysql_fetch_array(mysql_query("select ps from t_user where user_id='$id' and ps='$ps'"));

 //patched 04.22.2015
 if (empty($ps)) err("DB Error :: data not found..");

 if($row['ps']==$ps){ echo "<h2>wow! FLAG is : ".$FLAG."</h2>"; }

?>

전체 코드다. 나눠서 분석해보자

 

변수 선언

id, ps, type, ip 값을 받고 있다. `mysql_real_escape_string()`을 통해 sql injection을 방지하고 있다. sleep(2)를 통해 브루트 포싱을 제한하고 있다.

 

id, ip 값 비교

입력받은 id 값과 `$_SERVER['REMOTE_ADDR']` 값을 비교한다. 이 값이 서로 다르다면 error를 발생시킨다.

유저 검색
make_id()

유저를 검색해서 존재하지 않는다면 새로운 유저를 생성한다.

 

로그인 횟수 카운트
패스워드 초기화

로그인 횟수를 세는 로직이다. 4번 이상이라면 패스워드를 초기화한다.

 

t_table()
임시 테이블 생성

임시 테이블을 생성하고 있다.

 

 Temporary table(임시 테이블)이란 데이터베이스에서 일시적으로 사용하기 위해 생성되는 테이블을 의미한다. 이 테이블은 세션 동안만 존재하며, 세션이 종료되면 자동으로 삭제된다.

 여기서 세션은 사용자가 데이터베이스 서버에 연결되어 있는 상태를 의미한다. 즉, 로그인하는 순간부터 로그아웃하거나 연결이 끊어지는 순간까지 지속된다.

temporary table의 session과 관련된 내용

https://dev.mysql.com/doc/refman/8.0/en/create-temporary-table.html

 

MySQL :: MySQL 8.0 Reference Manual :: 15.1.20.2 CREATE TEMPORARY TABLE Statement

15.1.20.2 CREATE TEMPORARY TABLE Statement You can use the TEMPORARY keyword when creating a table. A TEMPORARY table is visible only within the current session, and is dropped automatically when the session is closed. This means that two different sessio

dev.mysql.com

 

또한, temporary table은 동일한 쿼리에서 두 번 이상 참조할 수 없다는 특징이 있다.

temporary table 참조에 대한 내용

https://dev.mysql.com/doc/refman/8.3/en/temporary-table-problems.html

 

MySQL :: MySQL 8.3 Reference Manual :: B.3.6.2 TEMPORARY Table Problems

B.3.6.2 TEMPORARY Table Problems Temporary tables created with CREATE TEMPORARY TABLE have the following limitations: TEMPORARY tables are supported only by the InnoDB, MEMORY, MyISAM, and MERGE storage engines. Temporary tables are not supported for NDB

dev.mysql.com

 

실제로 실행해보자.

실습

https://sqlfiddle.com/mysql/online-compiler?id=a28b56f4-2c79-46af-8aba-b51a8348b7a7&id=b30c8f3a-c2f2-467c-ab0c-ef3596d3bf6b

 

FREE AI-Enhanced Online MySQL Compiler - For learning & practice

 

sqlfiddle.com

해당 사이트를 이용해서 실습해봤더니 위와 같이 재참조 할 수 없다는 내용이 들어있다.

 

*하지만 5.6 이전 버전에서는 이러한 오류가 뜨지 않아 보안적으로 좀 더 취약하다.

error based sql injection

5.6 이전 버전에서는 temporary table을 두 번 참조했음에도, error based sql injection이 먹히는 모습이다. 

5.6 이전 버전에서의 공식 문서를 찾고 싶었지만 못찾았다..

 

counting() 함수 호출
counting()

이어서 확인해보면, counting() 함수를 호출하고 있다. 로그인 시도에 대한 로그를 기록하는 것으로 보인다.

 

select 문이다. 입력받은 id와 ps와 type으로 조회를 시도하고 있으며, 에러가 발생할 경우 해당 오류를 그대로 보여주고 있다.

나머지 코드

나머지 코드다. 결과를 가져와서 보여준다. ps를 찾아내면 flag를 얻을 수 있다.

 

Exploit

 

error based sql injection 취약점

여기서 오류를 그대로 보여주고 있다. 여기서 error based sql injection이 발생할 수 있다. id와 ps와 type 모두 이스케이프되는 함수를 거치기 때문에 싱글쿼터(')를 사용하여 sql injection을 할 수 없다. 따라서 싱글 쿼터를 사용하지 않아도 되는 `$type` 부분과 에러를 그대로 보여주는 부분을 이용하여 SQL Injection을 할 수 있다. 우리는 이것을 이용해서 ps 값을 구해야 한다.

 

extractvalue()를 이용한 errorbased sql injection
결과

그런데 extractvalue를 통해서는 ps 값을 구할 수 없다. extractvalue를 통해 ps 값을 가져오는 코드를 짜보겠다.

AND extractvalue(0x3a,concat(0x3a,(select ps from t_user)))

결과

여기서 우리는 temporary table을 재참조하게 된다. 앞서 봤듯이 temporary table은 재참조가 불가능하다. 실제 테이블은 필터링되어 막혀있다.

 

or row(1,1)=(select count(*), concat(ps,floor(rand(0)*2)) x from (select 1 union select 2 union select 3) a group by x limit 0,1)

이러한 쿼리로 익스플로잇을 했다. 작동 방식에 대해서 알아봤는데, GROUP BY를 통한 그룹 집계의 기준 컬럼에 rand() 함수가 사용된 경우에 발생하는 Duplicate entry 오류를 활용한 기법으로 이 오류가 발생하는 이유에 대해서는 아직 명확히 밝혀지지 않았다고 한다.

https://www.bugbountyclub.com/pentestgym/view/53

 

Error 기반 SQL 인젝션 | Pentest Gym | 버그바운티클럽

오류 기반 SQL Injection이란?오류 기반(Error based) SQL Injection은 주로 데이터베이스에 대한 정보를 획득하기 위해 사용됩니다. SQL의 잘못된 문법

www.bugbountyclub.com

 

flag

짜잔

 

해결방법

sql injection이 발생한 경우 prepared statement를 통해 방지할 수 있다.

728x90
반응형

'드림핵' 카테고리의 다른 글

[드림핵] 45c6 풀이  (0) 2024.05.10
[드림핵] baby xss 풀이  (0) 2024.04.17
[드림핵] Login Page 풀이  (0) 2024.04.12
[드림핵] Switching Command 풀이  (0) 2024.04.10
[드림핵] CProxy: Forge 풀이  (0) 2024.04.07