[LOS] phantom

Yennytime·2023년 1월 18일
0

Lord of SQL Injection

목록 보기
10/20
post-thumbnail

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

  if($_GET['joinmail']){
    if(preg_match('/duplicate/i', $_GET['joinmail'])) exit("nice try");
    $query = "insert into prob_phantom values(0,'{$_SERVER[REMOTE_ADDR]}','{$_GET[joinmail]}')";
    mysqli_query($db,$query);
    echo "<hr>query : <strong>{$query}</strong><hr>";
  }

  $rows = mysqli_query($db,"select no,ip,email from prob_phantom where no=1 or ip='{$_SERVER[REMOTE_ADDR]}'");
  echo "<table border=1><tr><th>ip</th><th>email</th></tr>";
    while(($result = mysqli_fetch_array($rows))){
    if($result['no'] == 1) $result['email'] = "**************";
    echo "<tr><td>{$result[ip]}</td><td>".htmlentities($result[email])."</td></tr>";
  }
  echo "</table>";

  $_GET[email] = addslashes($_GET[email]);
  $query = "select email from prob_phantom where no=1 and email='{$_GET[email]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['email']) && ($result['email'] === $_GET['email'])){ mysqli_query($db,"delete from prob_phantom where no != 1"); solve("phantom"); }
  highlight_file(__FILE__);
?>

🔺 코드분석

1.

if($_GET['joinmail']){
    if(preg_match('/duplicate/i', $_GET['joinmail'])) exit("nice try");
    $query = "insert into prob_phantom values(0,'{$_SERVER[REMOTE_ADDR]}','{$_GET[joinmail]}')";
    mysqli_query($db,$query);
    echo "<hr>query : <strong>{$query}</strong><hr>";
  }

🔹 $_GET[joinmail] 파라미터 필터링

duplicate, /i (대소문자를 구분하지 않음)

duplicate

중복된 요소를 확인하여 동일한 행이 이미 존재할 경우 해당 행을 True로 반환한다.


insert 문관계형 데이터베이스의 테이블에 새로운 데이터를 추가(저장)할 때 사용하는 명령어다.

INSERT INTO 테이블명 (컬럼1, 컬럼2,...) VALUES (데이터1, 데이터2,...)

이 문제에선 아래와 같이 적용된다.

INSERT INTO [테이블명] prob_phantom VALUSE [데이터...] 0, {$_SERVER[REMOTE_ADDR]}','{$_GET[joinmail]}

여기서, $_SERVER[REMOTE_ADDR]은 클라이언트의 IP주소를 가져온다.

데이터베이스와 쿼리문이 mysqli_query($db,$query)에 들어가 저장된다.

Insert문을 통해 phantom에서 서버와 이메일을 입력하는 것을 알 수 있다.

2.

$rows = mysqli_query($db,"select no,ip,email from prob_phantom where no=1 or ip='{$_SERVER[REMOTE_ADDR]}'");
 echo "<table border=1><tr><th>ip</th><th>email</th></tr>";
   while(($result = mysqli_fetch_array($rows))){
   if($result['no'] == 1) $result['email'] = "**************";
   echo "<tr><td>{$result[ip]}</td><td>".htmlentities($result[email])."</td></tr>";
  }
echo "</table>";

두번째 쿼리문을 통해 no=1 이거나 ip=접속한 ip를 조회 후 레코드를 표로 출력하고 no=1인 경우 $result[email]이 필터링되어 출력되는 것을 알 수 있다.

3

$_GET[email] = addslashes($_GET[email]);
$query = "select email from prob_phantom where no=1 and email='{$_GET[email]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(($result['email']) && ($result['email'] === $_GET['email'])){ mysqli_query($db,"delete from prob_phantom where no != 1"); solve("phantom"); }

addslashes(string str)

매개변수로 넘겨준 문자열 안에 작은 따옴표('), 큰 따옴표("), 백슬래시(\), NULL가 포함되어 있다면 해당 문자 앞에 백슬래시(\)추가 해주는 함수

if문을 보면 $result[email] = $_GET[email] 과 같다고 하지만, 만약 no값 1이 아니면 데이터를 삭제한다는 Delete문이 들어가있다.


🔺 풀이 과정

그렇다면, no=1email을 알아야한다.

위와 같이 no=1인 ip(127.0.0.1)이 들어가있는 이메일 값을 볼 수 있다.

  1. joinmail=1'),(0,'{본인 IP}','1

어떻게 출력되는지 확인하기 위해 test와 1을 넣어 확인해보았다.

  1. joinmail=1'),(0,'{본인IP}',(select email from (select email from prob_phantom where no=1) as admin))#'

Insert문의 취약점은 value가 여러개가 들어갈 수 있기 때문에 이를 이용하여 여러가지 value를 넣고 시도할 수 있다.

INSERT, DELETE 등 가져올 테이블과 같은 테이블에서 서브쿼리로 불러올 때 에러가 발생하기때문에 같은 테이블에서 서브쿼리를 사용할 때 (select email from (select email from prob_phantom where no=1) as admin) 으로 서브쿼리를 한번 감싸줘서 값을 불러와야 에러가 발생하지 않는다.

admin email = admin_secure_email@rubiya.kr인 것을 발견했다.

  1. email=admin_secure_email@rubiya.kr


점점 갈 수록 어려워진다. SQL에 대해 시간날 때 공부를 집중적으로 해야될 것 같다.
풀면서도 이게 맞는건가 싶기도했지만, 이해하면서 천천히 풀어보니 문제 유형에 대해 파악할 수 있었던 것 같다. 그래도 아직 많이 부족해서 나중에 복습이 필요할 것 같다.

profile
It's Yennytime💙

0개의 댓글