프로젝트/Webhacking.kr

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

Uggjjini 2021. 7. 5. 22:15

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

 

페이지에는 view_source 링크가 존재한다.

 

view_source 를 살펴본다.

 

 

하단의 php 부분을 중심으로 해석한다.

 

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

 

 


 

$agent=trim(getenv("HTTP_USER_AGENT"));

getenv() 함수는 인자값에 따라 환경변수의 값을 알려주는 함수이다.

getenv("HTTP_USER_AGENT")는 웹사이트를 접속한 컴퓨터의 웹브라우저 정보를 알려준다.

 

변수 agent 에는 웹브라우저 정보가 trim() 함수를 통해 양쪽 공백이 지워진 채로 저장된다.

 

$ip=$_SERVER['REMOTE_ADDR'];

$_SERVER['REMOTE_ADDR']는 환경변수로 웹서버에 접속한 접속자의 ip 정보를 가지고 있다.

 

따라서 변수 ip 에는 접속한 사용자의 ip가 저장된다.

 

if(preg_match("/from/i",$agent)){
  echo("<br>Access Denied!<br><br>");
  echo(htmlspecialchars($agent));
  exit();
}

 

preg_match() 함수를 통하여 agent의 값을 "/from/i" 정교표현식과 매칭시켜 매칭이된다면 해당 조건문을 실행한다.

agent 값에 from이라는 문자열이 대소문자 구문없이 들어가 있다면 "Access Denied!" 문구와 함께 agent 값이 htmlspecialchars() 함수를 통하여 html 엔티티로 인코딩되어 출력된다.

 

$db = dbconnect();

db 변수를 db와 연결된 객체로 만든다.

 

$count_ck = mysqli_fetch_array(mysqli_query($db,"select count(id) from chall8"));

mysqli_qurey() 함수를 이용하여 db와 연결된 객체를 통하여 "select count(id) from chall8" 쿼리문을 실행한다.

mysqli_fetch_array() 함수를 이용하여 mysqli_qurey를 통해 얻은 쿼리문을 통해 가져온 결과의 레코드를 배열로 가져온다.

count_ck 라는 변수에 해당 결과 값들이 배열로 저장된다.

 

if($count_ck[0] >= 70){ mysqli_query($db,"delete from chall8"); }

count_ck[0]의 값이 70이상이라면 조건문이 실행된다.

mysqli_qurey() 함수를 이용하여 db와 연결된 객체를 통하여 "delete from chall8" 쿼리문을 실행되어 chall8이라는 테이블이 삭제된다. (초기화)

 

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

 

myqli_query 함수를 통하여 하단 쿼리문을 실행시킨다.

 

select id from chall8 where agent='".addslashes($_SERVER['HTTP_USER_AGENT'])."'

 

addslashes() 함수는 sql에서 의도치 않게 특수문자 처리되는 문자를 해결하기위해 escape을 해주는 함수이다.

$_SERVER['HTTP_USER_AGENT']로 받아온 웹사이트를 접속한 컴퓨터의 웹브라우저 정보문자열을 쿼리문에 추가한다.

 

해당 쿼리문을 실행한 결과값이 변수 result 에 저장된다.

 

$ck = mysqli_fetch_array($result);

해당 result 값을 mysqli_fetch_array() 함수를 통하여 ck 변수에 배열형태로 저장한다.

 

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

 

ck 변수에 정상적인 값이 들어있을 경우 해당 조건문이 동작한다.

이 경우 ck[0]의 값이 'admin' 인 경우 chall8 테이블이 삭제되며 문제가 풀린다.

 

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

 

ck 변수에 값이 들어있지 않다면 해당 조건문이 동작한다.

mysqli_query()함수를 통하여 insert 쿼리문을 실행시켜 chall8 테이블에 값을 넣을 수 있다. 이 결과는 변수 q에 저장된다.

 

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

 

해당 쿼리문을 통해 chall8 테이블는 3개의 칼럼으로 구성되어 있다는 것을 알 수 있다.

 

agent(User-Agent 값) ip (접속자의 ip) id (guest로 고정값)

 

처음으로 사용자가 접속하면 

 

agent(User-Agent 값) ip (접속자의 ip) id (guest로 고정값)
Mazlia... XXX.XXX.XXX.XXX guest

 

이렇게 대입된다.

 

 

해당 문제를 풀기위해서는 count_ck[0]에 'admin'이라는 값이 들어가야 한다. 하지만 id 값은 guest로 고정되어 있기 때문에 SQL injection 공격을 통하여 id 가 admin이 되도록 해야한다.

 

id가 admin이 되도록 값을 넣어야 하기 때문에  하단의 쿼리값을 조작하여 id가 admin 인 데이터를 넣어준다.

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

 

해당 쿼리문에서 조작이 가능한 값은 $agent 값 뿐이다.

 

Brup Suite 프로그램을 실행하여 User-Agent 값을 조작한다.

 

 

 

해당 User-Agent를 바꿔준다.

 

 

상단과 같이 User-Agent 에 test', '1234', 'admin'), ('guest 를 입력한다.

 

그러면 insert 쿼리문이 하단과 같게 처리된다.

 

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

 

이 쿼리문에 의하여 테이블에는 아래와 같이 데이터가 추가된다.

agent(User-Agent 값) ip (접속자의 ip) id (guest로 고정값)
test 1234 admin
guest XXX.XXX.XXX.XXX guest

 

User-Agent 를 조작한 패킷을 보내면 하단 그림과 같이 테이블의 데이터가 2개 더 추가된것을 알 수 있다.

 

 

admin 사용자를 추가했으니 하단의 selct 쿼리문을 조작하여 ck[0]이 admin이 되도록 한다.

 

select id from chall8 where agent='".addslashes($_SERVER['HTTP_USER_AGENT'])."'

 

 

User-Agent 값을 test 로 변경한다. 

 

select id from chall8 where agent='test'

 

조작된 패킷을 날리면 ck가 admin이 되어 해당 문제가 풀린다.