LOS # darknight
쿼리문!
query : select id from prob_darkknight where id='guest' and pw='' and no=
코드 분석 go
<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~");
if(preg_match('/\'/i', $_GET[pw])) exit("HeHe");
if(preg_match('/\'|substr|ascii|=/i', $_GET[no])) exit("HeHe");
// 필터링을 여러 가지 해주고 있다.
$_GET[no] -> substr, ascii, ', =
$_GET[pw] -> '
$query = "select id from prob_darkknight where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}";
// pw와 함께 새롭게 등장한 no라는 값도 입력받는다.
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['id']) echo "<h2>Hello {$result[id]}</h2>";
// 참인 조건이 들어가면
Hello {$result[id]} 이 출력된다.
-> Blind SQL Injection 인가...? 생각해볼 수 있음
$_GET[pw] = addslashes($_GET[pw]);
// $_GET[pw]에 저장된 입력받은 pw는 addslashes() 함수를 거친 후 다시 저장된다.
$query = "select pw from prob_darkknight where id='admin' and pw='{$_GET[pw]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("darkknight");
// 이미 정해진 pw과 입력한 pw가 같아야 문제가 해결됨!
이전의 문제들처럼 역시 Blind SQL Injection을 이용해서 pw를 구하는 문제인 것 같다!
highlight_file(__FILE__);
?>
<addslashes() 함수>
: 문자열을 데이터베이스의 필드값으로 저장하기 전에 사용하는 함수
만약 그 문자열에 특수 문자 (ex : ', ", \ 등..) 가 포함되어 있다면,
이러한 문자 앞에 \ 를 붙여주는 작업을 수행한다.
특수 문자에 \ 가 붙어, 데이터베이스의 필드값을 저장되면 그 특수 문자가 순수한 하나의 문자로 인식되어 저장된다.
만약 이 addslashes() 함수를 사용하지 않고 특수 문자가 포함된 문자열을 저장하게 되면,
그 특수 문자가 하나의 일반적인 문자가 아닌, 특수 문자로 인식되어
오류를 일으키거나 잘못된 결과를 도출하게 될 수 있다.
즉, PHP -> DB 연동에 중요하게 쓰이는 함수
사용 형식
: addslashes($string)
-> 예제
$string = "안녕...'사랑'...'행복'";
&add_string = addslashes($string);
echo("$add_string <br>");
-> 실행 결과안녕...\'사랑'\...\'행복'\
* 참고로
addslashes() 와 반대되는 역할을 하는 함수
: stripslashes()
이제 대충 분석을 끝냈으니 pw를 구해보자.
먼저 pw의 길이부터 구해야한다.
pw에는 아무 값도 넣지 않아도 된다.
no에는 그냥 1을 넣어줬다.
' 을 필터링하고 있으므로 그냥 숫자를 넣어줬다.
id가 'admin'일 경우의 pw를 구하는 것이므로, id에 대한 조건도 입력해준다.
=을 필터링하고 있으므로 like를 써주고,
char() 함수를 사용해 id에 'admin'을 넣어준다.
char('admin'의 아스키값) -> char() 함수에 의해 'admind'으로 변환되어 인식된다.
char(97,100,109,105,110)
length()함수를 이용해 pw의 길이를 구해줬다.
역시 이번에도 길이는 8이었다..
<ord() 함수>
: 문자열의 첫 번째 문자에 해당하는 아스키코드를 반환하는 함수
문자 -> 아스키코드로 변환
사용 형식
: ord(문자열)
* 참고로
ord() 와 반대되는 역할을 하는 함수
: char()
-> 아스키코드를 문자로 변환한다.
이제 pw 8개를 각각 구해보자.
이 문제에서는 필터링하고 있는 요소들이 매우 많아서 이를 다 우회해줘야 한다.
지금까지 사용했던 방법&우회를 대충 정리해보면,
#orge에서는
ascii(), substr() 사용
Lord of SQL Injection # orge
query : select id from prob_orge where id='guest' and pw='' 쿼리문은 이렇게 나와있다. pw를 찾으면 되는 문제인듯! php코드이구... 코드를 일단 간단하게 분석해보쟈.
2myona.tistory.com
#golem에서는
ascii(), substr() 대신 -> right() + left() 사용
LOS # golem
쿼리문! query : select id from prob_golem where id='guest' and pw='' 코드를 분석해보자.
2myona.tistory.com
그런데 이 문제에서는 여기서 더 진화해 ascii까지 막아놨다.
ascii() -> ord()/hex()
두가지 방법으로 우회를 할 수 있다.
나는 ord()를 사용할것이다.
그리고, 이번에는
substr() 대신 -> mid() 함수를 사용해주자.
mid() 함수는 substr() 함수 대신 사용해 줄 수 있는 동일한 기능을 가진 함수이다.
<substr(), mid(), substring() 함수>
사용 형식
: 함수(문자열, m, n)
-> 문자열에서 m으로부터 n 길이만큼의 문자를 출력
m이 0이나 1이면 문자열의 첫글자를 의미
n이 생략되면 문자열의 끝까지를 의미
m이 음수이면 뒤쪽 방향으로부터의 위치를 의미
이제 함수들을 이용해서 pw를 하나씩 앞에서부터 구해보자.
이런식으로 써주자.
?no=1||id%20like%20char(97,100,109,105,110) and ord(mid(pw,1,1))<50%23
++ '='을 필터링해주는 like을 이용해 한번 더 확인해 볼 수 있다.
나는 8개 중에 하나를 잘못 찾은 것인지 계속 문제 해결이 안되길래 밑의 방법으로 한번씩 다시 확인을 해주었다.
그러니 틀린 것을 찾아낼 수 있었다..!
위와 같은 식으로 찾은 pw를 이제 문자로 변환해서 입력해주면 된다.
48 -> 0
98 -> b
55 -> 7
48 -> 0
101 -> e
97 -> a
49 -> 1
102 -> f
0b70ea1f
해결!