코드 분석
<?php
include "../../config.php";
if($_GET['view_source']) view_source();
$db = dbconnect();
if(!$_GET['id']) $_GET['id']="guest";
echo "<html><head><title>Challenge 61</title></head><body>";
echo "<a href=./?view_source=1>view-source</a><hr>";
$_GET['id'] = addslashes($_GET['id']);
if(preg_match("/\\(|\\)|select|from|,|by|\\./i",$_GET['id'])) exit("Access Denied");
if(strlen($_GET['id'])>15) exit("Access Denied");
$result = mysqli_fetch_array(mysqli_query($db,"select {$_GET['id']} from chall61 order by id desc limit 1"));
echo "<b>{$result['id']}</b><br>";
if($result['id'] == "admin") solve(61);
echo "</body></html>";
?>
URL 파라미터로 id 값을 받고 있고, 그 id값을 mysqli_query($db,"select {$_GET['id']} from chall61 order by id desc limit 1"코드에 넣어서 $result값을 구한다.
우리가 select문에 admin문자열을 넣고 싶다면 'admin' 넣어야 한다. 하지만addslashes()함수는 작은 따옴표나 큰 따옴표 앞에 백슬래시를 붙여 문자로 인식하게 한다.
그 외에 preg_match("/\\(|\\)|select|from|,|by|\\./i",$_GET['id'])괄호, select, from, 콤마, by, 마침표를 필터링한다.
strlen($_GET['id'])>15로 글자수를 15자 밑으로 제한한다.
익스플로잇
$result값이 ‘admin’일 경우 문제가 풀린다.
즉, mysqli_fetch_array(mysqli_query($db,"select {$_GET['id']} from chall61 order by id desc limit 1"));이 코드의 출력 결과가 admin이여야 한다.
다시 말해
SELECT $_GET['id'] FROM chall61 ORDER BY id DESC LIMIT 1;
쿼리의 출력 결과가 admin이여야 한다.
위의 쿼리 결과가 admin이 되게 하려면 id값이 결국 admin 이여야 한다.
하지만 우리는 where절이 아닌 select 절을 조작해 admin을 출력해 내야 한다.
id값을 기준으로 내림차순 정렬했을 때 첫 번째 값이 admin이 아닌이상 뒤의 FROM 절 부터의 내용에 상관 없이 쿼리 출력결과가 admin이 되게 만들어야한다.
이럴 때 사용할 수 있는 것이 alias다.
SELECT 'admin' AS id;
이렇게 하면 테이블과 상관없이 항상 'admin'을 반환한다.
select 'admin' id from chall61 order by id desc limit 1
- SELECT 'admin' id: 이 부분은 'admin'이라는 문자열을 id라는 별칭(alias)으로 반환한다. 즉, admin이라는 고정된 문자열을 id라는 이름으로 출력하게 된다. chall61 테이블에서 실제 컬럼 값은 반환되지 않고, 대신 'admin'이라는 값이 id라는 이름의 컬럼으로 반환된다.
- SELECT 'admin' id에서 실제 컬럼 값이 아닌 고정 문자열을 선택하기 때문에, FROM 절 이후에 나오는 chall61 테이블의 데이터는 실제로 사용되지 않는다.
- LIMIT 1: 결과에서 첫 번째 레코드만 가져옵니다. 이 쿼리는 항상 'admin'이라는 문자열만 포함된 하나의 행을 반환한다.
결과적으로, 이 쿼리는 항상 다음과 같은 하나의 행을 반환한다.
| id |
| admin |
하지만 id값에 문자열 ‘admin’을 넣으려고 하면 addslashes()함수에 걸린다. 따라서 admin을 16진수(HEX)값으로 넣어야 한다.
admin를 16진수로 바꾸고 as id를 넘겨보자
https://webhacking.kr/challenge/web-38/?id=0x61646d696e as id

그러나 이렇게 하면 글자수 제한에 걸린다.
MySQL에서 alias를 지정하려면 굳이 꼭 as를 안 붙여도 된다. 다시 한번 admin을 16진수화 시키고 id만 넣어보자
그리고 실제 URL에 넣을 때는 꼭 0x를 넣어 16진수 값이라는 표현을 포함해야 된다.
https://webhacking.kr/challenge/web-38/?id=0x61646d696e id
