프로젝트/Webhacking.kr

[Webhacking.kr] Challenge(old) 7번 문제

Uggjjini 2021. 7. 5. 15:43

문제 페이지는 해당페이지와 같다 

 

 

Admin page로 auth 버튼과 view-source 링크가 존재한다.

 

auth 버튼을 누르면 해당 문구와 함께 접근이 거부되는 것을 알 수 있다.

 

 

view-source를 살펴본다.

 

 

php와 html로 이루어진 것을 확인할 수 있다.

 

 

먼저, 해당 코드를 해석해 본다.

 

<?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 7</title>
</head>
<body>
<?php
$go=$_GET['val'];
if(!$go) { echo("<meta http-equiv=refresh content=0;url=index.php?val=1>"); }
echo("<html><head><title>admin page</title></head><body bgcolor='black'><font size=2 color=gray><b><h3>Admin page</h3></b><p>");
if(preg_match("/2|-|\+|from|_|=|\\s|\*|\//i",$go)) exit("Access Denied!");
$db = dbconnect();
$rand=rand(1,5);
if($rand==1){
  $result=mysqli_query($db,"select lv from chall7 where lv=($go)") or die("nice try!");
}
if($rand==2){
  $result=mysqli_query($db,"select lv from chall7 where lv=(($go))") or die("nice try!");
}
if($rand==3){
  $result=mysqli_query($db,"select lv from chall7 where lv=((($go)))") or die("nice try!");
}
if($rand==4){
  $result=mysqli_query($db,"select lv from chall7 where lv=(((($go))))") or die("nice try!");
}
if($rand==5){
  $result=mysqli_query($db,"select lv from chall7 where lv=((((($go)))))") or die("nice try!");
}
$data=mysqli_fetch_array($result);
if(!$data[0]) { echo("query error"); exit(); }
if($data[0]==1){
  echo("<input type=button style=border:0;bgcolor='gray' value='auth' onclick=\"alert('Access_Denied!')\"><p>");
}
elseif($data[0]==2){
  echo("<input type=button style=border:0;bgcolor='gray' value='auth' onclick=\"alert('Hello admin')\"><p>");
  solve(7);
}
?>
<a href=./?view_source=1>view-source</a>
</body>
</html>

 


$go=$_GET['val'];

 

go라는 변수에 get 방식을 통해 val변수 값을 받아온다.

 

 

해당 페이지의 URL을 확인하면 뒷부분에 val값이 있는데 이 값을 가져와 go 변수에 넣는 것이다.

 

if(!$go) { echo("<meta http-equiv=refresh content=0;url=index.php?val=1>"); }
echo("<html><head><title>admin page</title></head><body bgcolor='black'><font size=2 color=gray><b><h3>Admin page</h3></b><p>");

 

go 값이 존재하지 않으면 if문즤 조건이 참이되어 실행되어 url에서 val 변수에 1이란 값을 get 방식으로 전달한다.

무조건 메인페이지가 등장하게 되는 것이다.

 

if(preg_match("/2|-|\+|from|_|=|\\s|\*|\//i",$go)) exit("Access Denied!");

 

preg_match(정규표현식, 검색대상) 함수는 php에서 정규표현식 문자열을 체크하는 함수이다.

첫번째 인수로 정규표현식을 받아 두번째 인수로 들어오는 검색대상에 대항 정규표현식이 매칭되면 1을 반환하고 실패하면 0을 반환한다.

 

go 변수에서 /2|-|\+|from|_|=|\\s|\*|\//i 라는 정규표현식과 매칭 된다면 조건식을 만족하여 "Access Denied!"라는 메세지를 출력하며 스크립트가 중단된다.

 

그러므로 go 변수에 해당 정규표현식에 해당하는 값이 들어가지 않도록 해야한다.

 

 /2|-|\+|from|_|=|\\s|\*|\//i 

2 - \+ from - = \\s \* \/ \i
숫자 2 기호 - 1개 이상의 \ from 문자열 기호 _ 기호 =  공백  0개 이상의 \ 기호 / 대소문자 구별 X

 

( | 는 '또는'을 뜻한다.)

 

 

$db = dbconnect();

 

db라는 변수에 dbconnect() 결과를 저장한다.

 

$rand=rand(1,5);
if($rand==1){
  $result=mysqli_query($db,"select lv from chall7 where lv=($go)") or die("nice try!");
}
if($rand==2){
  $result=mysqli_query($db,"select lv from chall7 where lv=(($go))") or die("nice try!");
}
if($rand==3){
  $result=mysqli_query($db,"select lv from chall7 where lv=((($go)))") or die("nice try!");
}
if($rand==4){
  $result=mysqli_query($db,"select lv from chall7 where lv=(((($go))))") or die("nice try!");
}
if($rand==5){
  $result=mysqli_query($db,"select lv from chall7 where lv=((((($go)))))") or die("nice try!");
}

 

rand() 함수를 통해서 1에서 5까지 랜덤으로 rand값에 넣는다.

 

mysqli_qurey(연결객체, 쿼리) 함수는 mysqli_connect를 통해 연결된 객체를 이용하여 MySQL 쿼리를 실행시키는 함수이다.

 

select lv from chall7 where lv=($go)

 

따라서 dbconnect()를 통해 연결된 객체 db에 상단 쿼리문을 실행시킨 결과가 반환되고 result변수에 저장된다.

 

쿼리문을  실행시킨 결과가 아무것도 없다면 or 함수로 인해 die()함수가 실행되어  "nice try!" 문구가 출력된다.

쿼리문을  실행시킨 결과가 있다면 die()함수가 실행되지 않는다.

 

$data=mysqli_fetch_array($result);
if(!$data[0]) { echo("query error"); exit(); }
if($data[0]==1){
  echo("<input type=button style=border:0;bgcolor='gray' value='auth' onclick=\"alert('Access_Denied!')\"><p>");
}
elseif($data[0]==2){
  echo("<input type=button style=border:0;bgcolor='gray' value='auth' onclick=\"alert('Hello admin')\"><p>");
  solve(7);
}

 

mysqli_fetch() 함수는 쿼리문을 통해 가져온 결과의 레코드를 배열을 통해 받아오는 함수이다.

mysqli_fetch()함수의 결과를 data라는 배열에 저장한 한다

 

data[0] 값이 False를 의미하면 if 조건문에 의해  "querry error" 문구와 함께 종료되고,

data[0] 값이 1인 경우 auth 버튼을 누르면 "Access_Denied" 문구가 뜬다.

data[0] 값이 2인 경우 auth 버튼을 누르면 "Hello admin" 문구가 뜨면서 문제가 해결됨을 알 수 있다.

 

 


해당 코드를 확인한 결과 $data[0] 값이 2가 되어야 하고 그렇기 위해선 $result가 2가 되어야 한다.

$result는 난수에 따라 쿼리문이 달라지는데 rand=1 인 경우를 선택하여 쿼리문에서 $go 값이 2가 되도록 한다.

$go는 get 방식으로 val의 값을 받아오기 때문에 URL를 통하여 val 값을 조작한다.

 

select lv from chall7 where lv=($go)

 

rand =1 인 경우 상단의 쿼리문을 만족시켜야한다.

 

SELECT lv FROM chall7 WHERE lv=(0)
UNION
SELECT(2)

 

where 부분을 무효로 처리하기 위해 거짓이 되도록 넣어주고 직접적으로 2라는 값을 넣어주기 위해 union을 사용하여 값을 넣는다.

 

그리고 뒤에 die() 함수가 실행되지 않도록 주석처리하기 위해 #를 추가한다.

 

 

쿼리문은 하단과 같아야 한다.

 

select lv from chall7 where lv=(0) union select 2#)

 

하지만, 정규표현식을 피하기 위하여 숫자 2를 다른 방법으로 표현해야하는데 2의 아스키코드인 chr(50)을 이용하거나 mod(5,3)을 이용할 수 있다.

 

또한 주석을 표현하는 #을 URL 에 표현하기 위해서는 URL 인코딩이 된 값인 %23으로 입력해야한다.

 

 

 

 

URL 을 상단처럼 입력한 경우 "nice try!" 라는 문구가 출력되는데 이는 상단의 URL은 rand=1 인 경우의 쿼리문에 맞추어서 val 값을 조작한것이기 때문이다. 

 

 

새로고침을 하여 rand=1이 되는 경우 해당 문제가 풀렸다는 창과 함께 다음 페이지로 이동한다.