Level 8
<? $agent=getenv("HTTP_USER_AGENT"); $ip=$_SERVER[REMOTE_ADDR]; $agent=trim($agent); $agent=str_replace(".","_",$agent); $agent=str_replace("/","_",$agent); $pat="/\/|\*|union|char|ascii|select|out|infor|schema|columns|sub|-|\+|\||!|update|del|drop|from|where|order|by|asc|desc|lv|board|\([0-9]|sys|pass|\.|like|and|\'\'|sub/"; $agent=strtolower($agent); if(preg_match($pat,$agent)) exit("Access Denied!"); $_SERVER[HTTP_USER_AGENT]=str_replace("'","",$_SERVER[HTTP_USER_AGENT]); $_SERVER[HTTP_USER_AGENT]=str_replace("\"","",$_SERVER[HTTP_USER_AGENT]); $count_ck=@mysql_fetch_array(mysql_query("select count(id) from lv0")); if($count_ck[0]>=70) { @mysql_query("delete from lv0"); } $q=@mysql_query("select id from lv0 where agent='$_SERVER[HTTP_USER_AGENT]'"); $ck=@mysql_fetch_array($q); if($ck) { echo("hi <b>$ck[0]</b><p>"); if($ck[0]=="admin") { @solve(); @mysql_query("delete from lv0"); } } if(!$ck) { $q=@mysql_query("insert into lv0(agent,ip,id) values('$agent','$ip','guest')") or die("query error"); echo("<br><br>done! ($count_ck[0]/70)"); } ?>
소스 코드가 길므로 문제를 푸는데 중요한 부부만 살펴보도록 하겠다.
$agent=getenv("HTTP_USER_AGENT"); $ip=$_SERVER[REMOTE_ADDR]; $agent=trim($agent); $agent=str_replace(".","_",$agent); $agent=str_replace("/","_",$agent); $pat="/\/|\*|union|char|ascii|select|out|infor|schema|columns|sub|-|\+|\||!|update|del|drop|from|where|order|by|asc|desc|lv|board|\([0-9]|sys|pass|\.|like|and|\'\'|sub/"; $agent=strtolower($agent); if(preg_match($pat,$agent)) exit("Access Denied!");
먼저 agent에는 http_user-agent정보가 담기게 된다.
그리고 trim을 통해 스트링 앞뒤의 공백을 제거하고, str_replace로 문자를 치환한다. 그리고 strtolower로 문자열들을 소문자로 변경한다.
preg_match를 통해 agent에 해당 패턴들이 있는지 필터링한다.
$q=@mysql_query("select id from lv0 where agent='$_SERVER[HTTP_USER_AGENT]'"); $ck=@mysql_fetch_array($q); if($ck) { echo("hi <b>$ck[0]</b><p>"); if($ck[0]=="admin") { @solve(); @mysql_query("delete from lv0"); } } if(!$ck) { $q=@mysql_query("insert into lv0(agent,ip,id) values('$agent','$ip','guest')") or die("query error"); echo("<br><br>done! ($count_ck[0]/70)"); }
lv0 테이이블에서 id 레코드를 조회하는데 agent로 조건으로 조회한다.
이때 존재하면 ck에 값이 들어가고, 없으면 if문을 통해 insert 쿼리문이 생성된다.
우리의 공격 포인트는 이부분이다. insert를 통해 레코드를 생성하는데 agent값을 넣을 수 있다.
insert into lv0(agent,ip,id) values('$agent','$ip','guest')
먼저 알아야 할 개념은, values를 이용해 값을 넣을때 ','를 이용하여 여러 데이터를 넣을 수 있다.
이방법을 이용해여 쿼리를 넣게 되면, eunice','ip','admin'),('agent
값을 넣게되면
insert into lv0(agent,ip,id) values('eunice','ip','admin'),('agent','$ip','guest')
이렇게 쿼리가 완성되게 된다. 그러면 'eunice' 계정은 'admin'이 되게 된다.
fiddler로 User-Agent 부분을 수정하여 패킷을 보낸다.
그러면 처음에는 해당 User-Agent가 없으므로 Insert 쿼리를 통해 레코드가 생성이 되게 된다.
그리고 또다시 접속을 하고, 이번에는 User-Agent를 'eunice'로 수정하여 보내게 되면 문제가 풀리게 된다.