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 찾기
- 기존과 같은 형식
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하나만 보면 힘들게 풀었음!!!!!)
'소소한 IT이야기 > WARGAME' 카테고리의 다른 글
LORD OF SQLINJECTION(feat. nessie end???) (1) | 2023.08.27 |
---|---|
[Lord of SQL Injection] hell_fire 23번 (feat. Time Blind SQLi) (0) | 2023.08.07 |
[Lord of SQL Injection] dark_eyes 22번 (2) | 2023.03.27 |