article thumbnail image
Published 2021. 5. 15. 11:50

이번 문제는 SQL Injection이라고 적혀져 있는 것으로 보아 SQL 쿼리에 관한 문제로 추측된다.

 

맨 밑에 초록색 A태그를 클릭하여 코드를 확인하였다.

<?php
if($_GET[‘no’]){
  $db = dbconnect();
  if(preg_match(“/ |\/|\(|\)|\||&|select|from|0x/i”,$_GET[‘no’])) exit(“no hack”);
  $result = mysqli_fetch_array(mysqli_query($db,”select id from chall18 where id=‘guest’ and no=$_GET[no]”)); // admin’s no = 2

  if($result[‘id’]==“guest”) echo “hi guest”;
  if($result[‘id’]==“admin”){
    solve(18);
    echo “hi admin!”;
  }
}
?>

코드를 보니, 조건문 중에서 preg_match 함수의 인자 값들이 눈이 갔다.
그 후, preg_match가 있는 조건문 밑에 있는 줄의 주석에서 admin는 no=2이라는 것을 알 수 있었다.

 

하지만 현재 SQL 쿼리의 Where을 보니, id=‘guest’이라고 적현 것을 보니 no에 2을 넣은다고 해서 admin의 id가 나오지는 않을 것으로 판단된다.

 

대충 코드를 보니, 입력 값에 대한 검증이 있으며 입력 값은 쿼리의 no에 들어간다는 것을 알 수 있었다.

 

일단 guest의 no을 1~9까지 넣어서 찾아보도록하겠다.

 

1을 입력하니, hi guest가 출력이 됐다.
또한 guest의 no은 1인 것을 알아냈다.

 

이제 Where절에 어떤 값을 던져야 admin의 id가 나오는지를 고민하였다.

 

나는 Input form에 3 or no=2를 입력하여 id='guest' and no=3를 False을 만들어서 무시하겠끔하고, 그 뒤로 or no=2로 admin의 id를 출력할 생각이다.

 

이게 무슨 말이냐?라고 하는 분도 있을거라 생각한다.

 

위 사진은 내 서버의 Mysql에 문제의 DB 테이블을 구현하였다.

 

코드에서 나온 쿼리문을 이용하여 id를 검색해보았다.

SELECT id FROM chall18 WHERE id=‘guest’ and no=1;

이 때는 Where의 id and no가 모두 True라서 id가 출력이 되었다.
하지만 and는 둘 중 하나라도 False가 나오면 False로 인식된다.

 

SELECT id FROM chall18 WHERE id=‘guest’ and no=1 or no=2;

이 부분은 SELECT id FROM chall18 WHERE id=‘guest’ and no=1;, SELECT id FROM chall18 WHERE no=2;로 나누어 보면 된다.

 

위에 말했던 것처럼 and가 모두 True라서 guest가 출력이 되었다.

 

SELECT id FROM chall18 WHERE id=‘guest’ and no=3 or no=2;

여기선 id=‘guest’ and no=3의 no가 False라서 and의 결과값은 False로 인식되어 guest의 id가 출력되지 않았다.

 

or는 왜 False로 인식되지 않았을까? 그것은 or는 둘 중 하나라도 True면 결과 값을 True로 인식되기 때문이다.

그래서 admin이 출력이 되었다.

 

이제 어떻게 입력하면 admin이 출력되는지 알았으니, 한번 입력해보겠다.

 

입력 검증에 걸려서 no hack을 출력되는 것을 알 수 있다.

 

이를 우회하기 위해 어떤 것을 검증하는지 살펴보겠다.

if(preg_match(“/ |\/|\(|\)|\||&|select|from|0x/i”,$_GET[‘no’])) exit(“no hack”);

preg_match 함수는 정규식을 이용하여 필터를 하는 함수이다.
자세한 내용을 알고 싶으면 PHP: preg_match - Manual에 들어가서 확인하면 된다.

 

preg_match 함수의 첫번째 인자에 정의된 정규식을 살펴보겠다.

 

정규식은 /..pattern../으로 정의가 된다.

 

정규식 뒤에 후치 옵션이라는 것을 지정할 수 있는데, 현재 코드에선 i가 그 후치 옵션이다.
i는 알파벳 대/소문자를 구별하지 않는다는 것을 나타내는 옵션이다.

 

/ |\/|\(|\)|\||&|select|from|0x/i의 |은 or이라는 뜻이다.

/ |\/|\(|\)|\||&|select|from|0x/i을 나눠보면, 공백(스페이스), /, (, ), |, &, select, from, 0x의 단어들이 필터링된다.

 

저 값을 중 현재 내가 입력할 값에서 걸리는 것은 스페이스가 걸린다.
이를 우회하기 위해서 스페이스 대신에 사용할 값을 찾아야 한다.

 

입력된 값이 GET으로 넘어간다는 것에서 URL 인코딩된 값을 이용하면 된다는 것을 인지하였고, Tab 값을 URL 인코딩하여 값을 넘기기로 하였다.

 

URL에 index.php?no=3%09or%09no%3D2을 넣어서 값을 넘겨고,

Flag를 얻을 수 있었다.

'워게임 > webhacking.kr' 카테고리의 다른 글

Old - 38 Write Up  (0) 2021.05.15
Old - 26 Write Up  (0) 2021.05.15
Old - 17 Write Up  (0) 2021.05.14
Old - 16 Write Up  (0) 2021.05.14
Old - 14 Write Up  (0) 2021.05.14
복사했습니다!