반응형

 

<?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
  $db = dbconnect();
  if($_POST['lid'] && isset($_POST['lphone'])){
    $_POST['lid'] = addslashes($_POST['lid']);
    $_POST['lphone'] = addslashes($_POST['lphone']);
    $result = mysqli_fetch_array(mysqli_query($db,"select id,lv from chall59 where id='{$_POST['lid']}' and phone='{$_POST['lphone']}'"));
    if($result['id']){
      echo "id : {$result['id']}<br>lv : {$result['lv']}<br><br>";
      if($result['lv'] == "admin"){
      mysqli_query($db,"delete from chall59");
      solve(59);
    }
    echo "<br><a href=./?view_source=1>view-source</a>";
    exit();
    }
  }
  if($_POST['id'] && isset($_POST['phone'])){
    $_POST['id'] = addslashes($_POST['id']);
    $_POST['phone'] = addslashes($_POST['phone']);
    if(strlen($_POST['phone'])>=20) exit("Access Denied");
    if(preg_match("/admin/i",$_POST['id'])) exit("Access Denied");
    if(preg_match("/admin|0x|#|hex|char|ascii|ord|select/i",$_POST['phone'])) exit("Access Denied");
    mysqli_query($db,"insert into chall59 values('{$_POST['id']}',{$_POST['phone']},'guest')");
  }
?>
<html><head><title>Challenge 59</title></head><body>
<form method=post>
<table border=1>
<tr><td></td><td>ID</td><td>PHONE</td><td></td></tr>
<tr><td>JOIN</td><td><input name=id></td><td><input name=phone></td><td><input type=submit></td></tr>
<tr><td>LOGIN</td><td><input name=lid></td><td><input name=lphone></td><td><input type=submit></td></tr>
</form>
<br>
<a href=./?view_source=1>view-source</a>
</body></html>

 


 

<?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
  $db = dbconnect();
  if($_POST['lid'] && isset($_POST['lphone'])){
    $_POST['lid'] = addslashes($_POST['lid']);
    $_POST['lphone'] = addslashes($_POST['lphone']);
    $result = mysqli_fetch_array(mysqli_query($db,"select id,lv from chall59 where id='{$_POST['lid']}' and phone='{$_POST['lphone']}'"));
    if($result['id']){
      echo "id : {$result['id']}<br>lv : {$result['lv']}<br><br>";
      if($result['lv'] == "admin"){
      mysqli_query($db,"delete from chall59");
      solve(59);
    }
    echo "<br><a href=./?view_source=1>view-source</a>";
    exit();
    }
  }
  if($_POST['id'] && isset($_POST['phone'])){
    $_POST['id'] = addslashes($_POST['id']);
    $_POST['phone'] = addslashes($_POST['phone']);
    if(strlen($_POST['phone'])>=20) exit("Access Denied");
    if(preg_match("/admin/i",$_POST['id'])) exit("Access Denied");
    if(preg_match("/admin|0x|#|hex|char|ascii|ord|select/i",$_POST['phone'])) exit("Access Denied");
    mysqli_query($db,"insert into chall59 values('{$_POST['id']}',{$_POST['phone']},'guest')");
  }
?>

 

두 개의 if문이 있는데 첫 번째 if문은 login 할 때이고, 두 번째 if문은 Join 할 때 실행되는 부분이다.

 

취약점이 발생할만한 곳은 Join 할 때 실행되는 두 번째 if문에서 mysqli_query()를 보면 phone 파라미터의 값이 정수형으로 되어 있는데, 이 phone 부분에 SQL 구문을 삽입하기에 가장 적절하다.

(Join의 if 문에 있는 phone만 싱글 쿼터로 감싸져 있지 않기 때문이다.)

 

그리고 Join 할 때 실행되는 두 번째 if문에서는 insert 문이 사용되는데, insert문의 취약점으로는 사용자가 콤마(,)를 입력함으로써 각 값들에 대해 구분을 지어 원래 값이 아닌 내가 원하는 값을 DB에 저장시킬 수 있다.

 

이 문제에서는 lv의 값이 "admin"이 되어야 한다.

 

즉, mysqli_query()의 insert문을 보면 3번째 컬럼의 값으로 guest라고 되어 있는데 guest가 아닌 admin이 되어야 한다.

 

하지만, id와 phone의 값에 대해 "admin" 문자열을 필터링 하고 있다.

 


풀이

 

lid와 lphone 부분에 값을 입력하면, 특수 문자에 슬래시를 자동으로 추가해주는 addslashes() 함수를 거친 값이 SQL 쿼리 문에 포함이 된다.

 

그리고 SQL 쿼리를 통해 가져온 id와 lv 값 중 id의 값이 있으면 id와 lv의 값을 화면에 출력하고, lv의 값이 admin이면, 문제가 풀린다.

 

즉, SQL 쿼리문을 통해 id의 값이 있고, lv의 값이 admin이어야 한다.

 

 

 

Join의 if 문에서는 "admin" 문자열은 필터링되고 있고, hex, char, ascii 등 문자열 변환에 대한 구문도 필터링 되고 있다.

 

phone의 길이는 제한이 되어 있고, id 부분은 싱글 쿼터로 둘러싸여있기 때문에 어떤걸 입력해도 문자열로 인식해버린다.

 

그리고 mysqli_query() 문의 insert 쿼리는 lv 부분의 값을 guest라고 값을 딱 박아두었지만 insert 문의 취약점인 콤마를 이용하면 lv의 값을 admin으로 바꿀 수 있다.

 

문제는 Join할 때 id에 "admin" 문자열을 입력할 수 없게 필터링 되고 있는데 이는 id 부분에 "nimda"를 입력하고, phone 부분에서 id의 값을 reverse() 함수를 통해 가져오면 lv의 값을 admin으로 바꿀 수 있게 된다.

 

이 방식대로 하면 reverse() 함수를 사용할 때 함수에 들어갈 인자가 문자열('nimda')인데 싱글쿼터를 사용하지 않고 reverse() 함수에 인자를 넣어줄 수 있게 된다.

 

id = nimda

reverse(id) == reverse(nimda)

 

 

위와 같이 하면 id의 값이 nimda이고, phone 넘버는 1 그리고 lv의 값은 'nimda' 문자열을 "admin"으로 바꾼 값이 된다.

 

1은 phone 넘버를 넣기 위함이니 1이 아니고 다른 숫자 값이여도 된다.

 

뒤에 ')' 와 '--'는 열린 괄호를 닫아주기 위해 괄호 수를 맞춰준 것이고, 뒤의 'guest'를 무시하게 주석 처리 한 것이다.

 

 

id : nimda / phone : 1로 로그인을 하면 lv이 admin이 되어 조건을 만족하게 되고 그러므로 문제가 풀린다.

 


https://choseongho93.tistory.com/206

 

 

반응형

'전쟁 > Webhacking.kr' 카테고리의 다른 글

[Webhacking.kr] old-7  (0) 2022.07.19
[Webhacking.kr] old-61  (0) 2022.07.19
[Webhacking.kr] old-5  (0) 2022.07.14
[Webhacking.kr] old-39  (0) 2022.07.13
[Webhacking.kr] old-3  (0) 2022.07.13

+ Recent posts