Webhacking

[Webhacking.kr] old-35번 풀이

aeeazip 2022. 12. 22. 22:55

링크로 들어가면 35번 문제를 확인할 수 있다.

문제 사진

 

소스코드를 보러 가야겠다 ^_^

 

 

 

 

 

 

소스코드


<?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 35</title>
<head>
<body>
<form method=get action=index.php>
phone : <input name=phone size=11 style=width:200px>
<input name=id type=hidden value=guest>
<input type=submit value='add'>
</form>
<?php
$db = dbconnect();
if($_GET['phone'] && $_GET['id']){
  if(preg_match("/\*|\/|=|select|-|#|;/i",$_GET['phone'])) exit("no hack");
  if(strlen($_GET['id']) > 5) exit("no hack");
  if(preg_match("/admin/i",$_GET['id'])) exit("you are not admin");
  mysqli_query($db,"insert into chall35(id,ip,phone) values('{$_GET['id']}','{$_SERVER['REMOTE_ADDR']}',{$_GET['phone']})") or die("query error");
  echo "Done<br>";
}

$isAdmin = mysqli_fetch_array(mysqli_query($db,"select ip from chall35 where id='admin' and ip='{$_SERVER['REMOTE_ADDR']}'"));
if($isAdmin['ip'] == $_SERVER['REMOTE_ADDR']){
  solve(35);
  mysqli_query($db,"delete from chall35");
}

$phone_list = mysqli_query($db,"select * from chall35 where ip='{$_SERVER['REMOTE_ADDR']}'");
echo "<!--\n";
while($r = mysqli_fetch_array($phone_list)){
  echo htmlentities($r['id'])." - ".$r['phone']."\n";
}
echo "-->\n";
?>
<br><a href=?view_source=1>view-source</a>
</body>
</html>

입력폼을 주의깊게 보자!

id값은 guest로 고정되어 있고 변수명 phone으로 입력값이 전달된다.

쿼리문이 자주 등장하는 걸로 보아 SQL 인젝션 문제인 것 같으므로 쿼리가 등장하는 부분을 따로 보자!

if($_GET['phone'] && $_GET['id']){
  if(preg_match("/\*|\/|=|select|-|#|;/i",$_GET['phone'])) exit("no hack");
  if(strlen($_GET['id']) > 5) exit("no hack");
  if(preg_match("/admin/i",$_GET['id'])) exit("you are not admin");
  mysqli_query($db,"insert into chall35(id,ip,phone) values('{$_GET['id']}','{$_SERVER['REMOTE_ADDR']}',{$_GET['phone']})") or die("query error");
  echo "Done<br>";
}

if문은 건너뛰고 mysqli_query 라인을 보면

insert into chall35(id,ip,phone) values('{$_GET['id']}','{$_SERVER['REMOTE_ADDR']}' {$_GET['phone']

 

chall35 테이블에

① id값으로 $_GET['id']을 넣고

② ip값에 $_SERVER['REMOTE_ADDR'](내 서버의ip값)을 넣고

③ phone값으로 $_GET['phone']을 넣는다.

만약 phone값으로 01011111111을 입력하면 아래와 같은 형식으로 DB에 데이터가 쌓인다.

id
ip
phone
guest
내 서버 ip값(xxxxxxxxxxx)
01011111111

 

$isAdmin = mysqli_fetch_array(mysqli_query($db,"select ip from chall35 where id='admin' and ip='{$_SERVER['REMOTE_ADDR']}'"));
if($isAdmin['ip'] == $_SERVER['REMOTE_ADDR']){
  solve(35);
  mysqli_query($db,"delete from chall35");
}

첫 번째 라인을 해석하면

select ip from chall35 where id='admin' and ip='{$_SERVER['REMOTE_ADDR']}'

 

chall35 테이블에서

조건 ① id = admin

        ② ip='{$_SERVER['REMOTE_ADDR'](ip값이 내 서버의 ip값과 같다)

두 조건을 동시에 만족하는 ip를 선택하여 isAdmin값에 담고 선택한 ip값과 내 서버 ip값이 같은 경우 문제가 풀린다.

 

그런데 phone값으로 3을 입력하면 DB에 아래와 같은 데이터가 쌓이고

id
ip
phone
guest
내 서버 ip값(xxxxxxxxxxx)
01011111111

쿼리문 조건 중 첫 번째인 id=admin 을 만족하지 못하기 때문에 어떤 것도 select 되지 않고

$isAdmin 에 아무런 값도 존재하지 않게 된다.

따라서 solve 조건을 만족하지 못하면서 문제가 풀리지 않는다.

 

 

 

 

 

 

 

해결


문제를 풀기 위해선 ip값이 내 서버의 ip값과 같으면서 id=admin이어야 한다.

ip값이 내 서버 ip값과 같은 경우 문제가 풀리기 때문에 쿼리문에서 조건에 맞는 ip가 선택될 수 있도록 해야한다. 우리는 phone값을 입력하여 조작할 수 있으므로 여기서 sql 인젝션을 통해 id값에 admin이 담길 수 있게 변환해야 한다.

따라서 입력폼에 a),('admin','ip값~',01012345678) 을 입력해주면

id
ip
phone
guest
내 서버 ip값(xxxxxxxxxxx)
a
admin
내 서버 ip값(xxxxxxxxxxx)
01012345678

 

id값이 admin이면서 ip가 내 서버의 ip인 값이라는 조건을 모두 만족하면서 문제가 풀린다.

​(빨간 글씨는 phone값으로 입력하여 추가된 부분)

결과 사진

 

35 point 획득 :D