소소한 IT이야기/WARGAME

[Lord of SQL Injection] evil_wizard 24번 (feat. Blind SQLi)

Klaus 2023. 8. 8. 13:15

0. Start 

- 직전 문제인 [hell fire]와 같은 형식이라서 걱정이 없겠다고 생각했는데, 주석으로 "same with hell_fire? really?"라는 문구가!!

 

[+] SQLi 종류와 간단한 설명

- 문제를 풀며 나오는 SQLi에 대해서 간단하게 정리 및 복습

종류 특징 예시 구문
Time-based SQLi 실행 시간을 기반으로 결과를 확인하는 공격 ...?id=1' AND IF(1=1, SLEEP(5), 0)--
UNION-based SQLi 여러 쿼리 결과를 결합하여 정보 추출 ...?id=1' UNION SELECT null,username,null FROM users--
Error-based SQLi 에러 메시지를 활용하여 정보를 추출하거나 DB 구조를 파악하는 공격 ...?id=1' OR 1=CONVERT(int, (SELECT @@version))--
Blind-based SQLi 웹 응답을 통해 참/거짓 여부로 데이터 추출
(Boolean-based, Time-based Blind 등)
...?id=1' AND 1=1-- 또는 ...?id=1' AND IF(1=1, SLEEP(5), 0)-- 등

 

1. evil_wizard

 

 

[+] query : select id, email, score from prob_evil_wizard where 1 order by

 

- 기존 문제와 비슷한 형태이기 때문에 ORDER BY 절에 대해서는 설명하지 않음

※ 아래 내용부터는 스포가 될 수 있다. 공부 목적이신 분은 블라인드 SQLi에 대해 스스로 해결!!

 

2. code

 

[+] 전체 코드

더보기
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\.|proc|union|sleep|benchmark/i', $_GET[order])) exit("No Hack ~_~");
  $query = "select id,email,score from prob_evil_wizard where 1 order by {$_GET[order]}"; // same with hell_fire? really?
  echo "<table border=1><tr><th>id</th><th>email</th><th>score</th>";
  $rows = mysqli_query($db,$query);
  while(($result = mysqli_fetch_array($rows))){
    if($result['id'] == "admin") $result['email'] = "**************";
    echo "<tr><td>{$result[id]}</td><td>{$result[email]}</td><td>{$result[score]}</td></tr>";
  }
  echo "</table><hr>query : <strong>{$query}</strong><hr>";

  $_GET[email] = addslashes($_GET[email]);
  $query = "select email from prob_evil_wizard where id='admin' and email='{$_GET[email]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['email']) && ($result['email'] === $_GET['email'])) solve("evil_wizard");
  highlight_file(__FILE__);
?>

[+] 필터링 Preg_match 사용

- UNION SQLi 방지 , Time based SQLi 방지

 

[+] Solve 조건

- id : admin의 email 찾기

- 기존과 같은 형식

URL ?order=1 입력시 확인 가능

3. Solve

[+] 페이로드 작성 및 조건 정리

- admin의 email의 찾는 문제

- email의 길이확인 및 한문자씩 출력하여 찾기

 

[+] 파이썬 코드

-hell_fire에서 사용하였던 페이로드 코드를 사용하여 문제 풀이

4. 번외

- 실무자 입장에서 지금의 코드를 어떻게 수정하는 것이 좋을까?라는 생각으로 코드를 수정해 보았습니다. 일명 뻘짓!!!

 

[+] 수정 코드 및 변경 사항

- sanituze_input 사용 : 입력값 검증하기 

-  특수문자 이스케이프(mysql) 사용

- Prepared Statement 사용 :  SQL쿼리 구조를 미리 만들고 실제 데이터만 추가하는 방식

- mysqli_stmt_close 사용 : Prepared Statement작업 이후 메모리 누수 방지

더보기
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();

  // Input 검증 함수 정의
  function sanitize_input($input) {
    return preg_replace('/[^a-zA-Z0-9_]+/', '', $input);
  }

  // 입력 값 검증
  $order = sanitize_input($_GET['order']);
  if ($order !== $_GET['order']) {
    exit("No Hack ~_~");
  }

  // 쿼리 생성
  $allowed_columns = ['id', 'email', 'score'];
  if (!in_array($order, $allowed_columns)) {
    exit("Invalid column specified");
  }

  $query = "select id,email,score from prob_evil_wizard where 1 order by " . mysqli_real_escape_string($db, $order);

  // 쿼리 실행 및 결과 출력
  echo "<table border=1><tr><th>id</th><th>email</th><th>score</th>";
  $rows = mysqli_query($db, $query);
  while (($result = mysqli_fetch_array($rows))) {
    if ($result['id'] == "admin") {
      $result['email'] = "**************";
    }
    echo "<tr><td>{$result['id']}</td><td>{$result['email']}</td><td>{$result['score']}</td></tr>";
  }
  echo "</table><hr>query : <strong>{$query}</strong><hr>";

  // 두 번째 쿼리는 Prepared Statement로 변경
  $email = mysqli_real_escape_string($db, $_GET['email']);
  $query = "select email from prob_evil_wizard where id='admin' and email=?";
  $stmt = mysqli_prepare($db, $query);
  mysqli_stmt_bind_param($stmt, "s", $email);
  mysqli_stmt_execute($stmt);
  $result = mysqli_stmt_get_result($stmt);
  $row = mysqli_fetch_array($result);

  if ($row && $row['email'] === $_GET['email']) {
    solve("evil_wizard");
  }
  
  mysqli_stmt_close($stmt);
  highlight_file(__FILE__);
?>

- 이번 HELL FIRE와 evil wizard 문제를 풀어보면서 여유가 조금 있었던 것 같다. (앗! hell fire하나만 보면 힘들게 풀었음!!!!!)