[Web.kr]Level 08

 
<?
$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’로 수정하여 보내게 되면 문제가 풀리게 된다.