소스보기를 해보자
<?php
include "../../config.php";
if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 46</title>
</head>
<body>
<h1>SQL INJECTION</h1>
<form method=get>
level : <input name=lv value=1><input type=submit>
</form>
<hr><a href=./?view_source=1>view-source</a><hr>
<?php
if($_GET['lv']){
$db = dbconnect();
$_GET['lv'] = addslashes($_GET['lv']);
$_GET['lv'] = str_replace(" ","",$_GET['lv']);
$_GET['lv'] = str_replace("/","",$_GET['lv']);
$_GET['lv'] = str_replace("*","",$_GET['lv']);
$_GET['lv'] = str_replace("%","",$_GET['lv']);
if(preg_match("/select|0x|limit|cash/i",$_GET['lv'])) exit();
$result = mysqli_fetch_array(mysqli_query($db,"select id,cash from chall46 where lv=$_GET[lv]"));
if($result){
echo("{$result['id']} information<br><br>money : {$result['cash']}");
if($result['id'] == "admin") solve(46);
}
}
?>
</body>
</html>
다양한 필터링이 존재한다.
1 ~ 5 레벨 입력값에 따른 결과는 아래와 같다.
lv 1.
id : ltusy
cash : 1100
lv 2.
id : ndnrg
cash : 800
lv 3.
id : fvvcg
cash : 1200
lv : 4.
id : bzrbo
cash : 700
lv 5.
없음
우리가 구해야할 값은 id가 admin인 계정.
처음에는 테이블 안의 모든 캐시값을 더해서 남는 값이 admin일 것이라고 생각하여 cash값을 구해볼까 했다.
근데 그룹핑 쿼리에 대한 가능성이 보이지 않았고, 더군다나 컬럼명인 cash 가 필터링되는 상황이였다. 그리고 나중에 알고보니 1~4말고도 숨은 값들이 많아서 이 방법으로 전체 cash값을 구한다 한들 admin의 cash값을 순수하게 구해내진 못했을 것이다.
여기서, 당연하지만 흠칫하며 헷갈렸던 부분이 있다.
난 처음에 아무생각없이 cash 컬럼명이 필터링중이기에
당연히 cash의 ascii값 -> 99, 97, 115, 104 -> char(99, 97, 115, 104) 를 이용해 우회하려고 시도했었다. 하지만 이건 멍청한 짓이다.
char, concat, hex, 0x, 0b 등을 이용한 것들은 상수값 자체일 뿐
컬럼명이 필터링되어있을 때 이걸 사용한다고 우회할 수 있는 것이 아니다.
컬럼명에 대한 정보가 아닌 그냥 그 자리에 상수값을 넣게 되는 것이다.
where id = 'admin' / where 0x6964 = 'admin'
id컬럼에 'admin'인 값이 있는가 / 'id'(0x6964) 와 'admin'은 같은값인가
ex) select id from student 와 select 0x6964 from student 는 다름.
전자는 student 테이블의 id컬럼들에 대한 값들을 출력
후자는 student 테이블의 id컬럼이 아닌 0x6964("id" 상수값)을 출력.
컬럼명을 상수값형태로 전달할 수 없음.
전자의 경우엔 where id > 0 인 것이고 후자를 이용할 경우엔 where 'id' > 0 형태가 되는것.
어찌보면 정말 당연한 것이다. 나는 생각없이 하다가 응?하고 갑자기 헷갈려했을 뿐..
컬럼명이 아닌 상수값으로 넘겨지는 것이니
where id(컬럼명) > 0 은 컬럼이 id인 데이터들 중 0이상인 값들을 조건하는 식이나
where 'id' > 0은 id 상수값 자체가 0보다 큰지를 조건하는 식이 되는 것.
즉, 내가 만든 식은 where 컬럼명 = '상수값'이 아닌, where '상수값' = '상수값' 형태의 조건을 만들어 버린 것 ㅋㅋ..
이용하려면 where 컬럼명 = 상수값 일 때, 상수값 자체가 필터링인 상황에서 위 방법들을 활용하여 상수값 자리에 넣으면 되겠다.
그리고 바로 이 방법대로 문제에 써먹으면 된다.
5 or id = 'admin' 을 넣을건데, 싱글쿼터가 현재 필터링되므로 'admin' 상수값이 입력될 수 없는 상황이다. 따라서
5 or id = char(97, 100, 109, 105, 110) 를 통해 'admin' 상수값을 전달해줄 것이다. (char이 아닌 다른방법도 있겠지만, 현재 0x는 필터링중이여서 이 방법을 사용했다)
현재 공백이 필터링중이므로 ()를 사용해도 되나, %0a(Line Feed, \n)를 사용했다.
->
5%0aor%0aid%3Dchar%2897%2C100%2C109%2C105%2C110%29
정리
where id = 'admin' 대신에
where id = char(97, 100, 109, 105, 110) 를 넣어서 상수값을 넣을 순 있지만
where id = ' admin' 대신에
where char(105, 100) = 'admin' 을 넣어서 상수값을 넣을 순 없다. (where 'id' = 'admin'이 되는것)
"where $var = 'admin'"일때, $id값에 id를 입력해서 전달한다고 해서
"where 'id' = 'admin'"이 되진 않고, "where id = 'admin'" 이 정상적으로 된다.
그치만
"where $var = 'admin'"일때 $id값에 char(105,100)을 전달하면 상수값 처리되어
"where 'id' = 'admin'"이 되는것이다.
그리고 $var에 문자열로 입력값을 넣어서 전달한다고 해서
"where '입력값' = 'admin'"으로 따옴표로 싸여져서 전달되는게 아니라 문자열과 합쳐지는, 녹여지는 느낌으로
"where 입력값 = 'admin'"으로 전달된다. 대신 상수값형태로 전달하면 저렇게 따옴표로 싸여진 상수값느낌으로 전달되는것.
("where " . $var . "'admin'" = "where " . $var . "= 'admin'" -> 문자열을 전달한다고해서 기존 싱글-더블쿼터안에 또다른 싱글-더블쿼터로 싸여져서 전달되는게 아니라 합쳐지는 것일 뿐이다. 그게 아니라면 $id = "hello"; $var = "hi? {$id}"가 성립이 안되는 말이안되는 상황 발생. )
기존의 입력값이 문자열이여서 따옴표로 감싸진다면
"어쩌구저쩌구 {$입력값}" => "어쩌구저쩌구 " +"입력값" + ""이 되어
"어쩌구저쩌구 입력값"이 되겠지만, char(105, 100)을 전달하면
"어쩌구저쩌구 " +"char(105,100)" +""이 되어
"어쩌구저쩌구 " +" 'id' " +""이 되고
"어쩌구저쩌구 'id'"가 된다고 보면 된다
+ 추가
$a = "hevton";
$b = "hi {$a}";
일때
$b = "hi "hevton""; 이 되는게 아니라는것!
$b는 "hi hevton" 이다.
( $a = 'hevton'; 이라도 $a와 $b의 큰따옴표 작은따옴표에 상관없이)
그리고 이를 토대로
$a = "hevton";
$b = "hi '{$a}'"; 일때
$b는 "hi 'hevton'" 이 된다. (또는 $a가 애초부터 "'hevton'"이고 $b = "hi {$b}"; 이거나)
..+ 어쩌다보니 괜히 헷갈리게 되었는데, 내가 해왔던 방식이 맞으니 흔들리지 않았으면 좋겠다.
'[웹해킹] > [Webhacking.kr]' 카테고리의 다른 글
[Webhacking.kr] 48번 (0) | 2020.11.15 |
---|---|
[Webhacking.kr] 47번 - 아시는분? (0) | 2020.11.14 |
[Webhacking.kr] 45번 & 나중에 알게 되면 다시보기 (0) | 2020.11.13 |
[Webhacking.kr] 44번 (0) | 2020.11.12 |
[Webhacking.kr] 43번 (0) | 2020.11.10 |