목표 : SQL 함수로 필터링 우회
표가 있고 제출버튼이 있다. 소스 코드를 보자
<?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
복사
JOIN으로 넘기는 값은 id 와 phone
LOGIN으로 넘기는 값은 lid와 lphone이다.
코드가 상당히 길다 중요한 파트만 보겠다.
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']}'"));
PHP
복사
POST로 로그인 인자가 두개가 넘어오면 각 인자 앞에 \ 를 붙인다
addslashes() 함수는 데이터베이스 쿼리에서 처리가 되는 문자 앞에 \(백슬래시)를 붙인 문자열을 반환
select id,lv from chall59 where id='{$_POST['lid']}' and phone='{$_POST['lphone']}
SQL
복사
$reslut에 로그인으로 들어온 값에 해당하는 id와 lv 값을 저장한다.
id는 그대로 lid가 저장된다는 게 핵심!
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);
}
PHP
복사
result의 lv 권한이 admin이면 문제를 해결한다.
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')");
}
PHP
복사
가입에 관한 쿼리다.
동일하게 앞에 백슬래시를 붙이고 phone의 글자 수는 19글자가 최대다
id 값은 다음과 동일하면 필터링 된다.
•
admin (admin공백)
phone 값은 admin 뒤에 다음 값이 들어가면 필터링 된다.
•
16진수, #, hex, char, ascii, ord, select
함수들을 필터링 하진 않으므로 함수로 admin을 만들면 된다.
reverse 함수를 이용해 문제를 해결할 수 있다.
즉 다음과 같은 형태를 만드는 게 목적이다.
sql insert into chall59 values('nimda',123,reverse(id))-- ,'guest')
SQL
복사
! 주석 뒤에 공백은 필수다
nimda, 123 번호의 권한은 admin이 됐다.