Study/Web Hacking

[webhacking.kr] old-07

얀 짱 2026. 7. 22. 12:24

먼저 소스코드를 보면 다음과 같음

<?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>");

// preg_match(): 정규 표현식 패턴을 이용해 문자열 안에서 원하는 패턴이 일치하는지 검사하고 처음 찾은 결과를 반환하는 함수
// 일치하면 1, 일치하지 않으면 0, 오류가 나면 false를 반환 
// 2, -, +, from, _, =, 공백문자, *, / 이거 다 차단 (i는 뭐지 모르겠듬 -> 대소문자 구별 안함) 
if(preg_match("/2|-|\+|from|_|=|\\s|\*|\//i",$go)) exit("Access Denied!");
$db = dbconnect();
$rand=rand(1,5);            // 1~5 까지 랜덤 수
// sql 쿼리문에는 base64가 못 들어간다.
if($rand==1){
  $result=mysqli_query($db,"select lv from chall7 where lv=($go)") or die("nice try!");
  # val: ((1)union(select(1<<1)))
  # 1)union(select(1<<1))
}
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!");
}
// mysqli_fetch_array: PHP에서 MySQL 데이터베이스 쿼리 결과(Result set)로부터 데이터 한 행(row)을 가져와 배열로 반환하는 함수
$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){            // 2를 넣으면 풀려야 되는데 앞에 정규표현식에서 2를 막고 있어서 안되는듯 -> 정규 표현식 우회하기 
// 연산식으로 푸려고 했는데 4칙 연산이 다 막힘...
  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>

 

코드 해석은 여기 까지 했음.

 

그래서 처음엔 2 대신 1<<1, 3^1 이런 연산식을 넣으려고 했음.

근데 $go 안에 sql 쿼리문으로 하면 된다는 힌트를 스터디원들한테 얻었음.

union으로 풀었음.

select lv from chall7 where lv=($go)

 

목표는 $data[0]==2 를 만족시키는 것. DB에는 lv=1 만 존재하므로 UNION으로 2를 직접 만들어야 했음.

select lv from chall7 where lv=(0)union(select(1^3))

 

핵심 포인트 두 가지

첫째, 0 을 넣은 이유: lv=1 을 넣으면 UNION 결과가 [1, 2] 가 되는데 mysqli_fetch_array 는 첫 번째 row만 가져와서 lv=1 이 나와버림. lv=0 은 DB에 없으므로 결과가 없고 UNION의 1^3=2 만 반환됨.

둘째, 괄호를 쓴 이유: 공백이 필터에 막혀있어서 union select 대신 union(select(...)) 형태로 우회했음.

?val=0)union(select(1^3)

 

랜덤 괄호 개수 때문에 여러 번 새로고침 후 성공함.

 

1^3 대신 2를 출력할 수 있는 모든 sql 함수면 다 가능함.

length('qq')
celling(1.4)
...