문제 페이지는 해당 페이지와 같다.
페이지에는 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이 되어 해당 문제가 풀린다.
'프로젝트 > Webhacking.kr' 카테고리의 다른 글
[Webhacking.kr] Challenge(old) 15번 문제 (0) | 2021.07.05 |
---|---|
[Webhacking.kr] Challenge(old) 14번 문제 (0) | 2021.07.05 |
[Webhacking.kr] Challenge(old) 7번 문제 (0) | 2021.07.05 |
[Webhacking.kr] Challenge(old) 6번 문제 (0) | 2021.07.05 |
[Webhacking.kr] Challenge(old) 5번 문제 (0) | 2021.07.02 |