-
webhacking.kr 8번 User-Agent를 이용한 SQL-Injection 문제WeekHack/WebHacking 2019. 7. 8. 08:46반응형SMALL
안녕하세요. Luke입니다. 라업을 쓰다가 인터넷이 끊겨서 라업을 두번 쓰는 webhacking.kr 8번 문제입니다 ㅋㅋ 이 문제 이상한 방향으로 삽질을 하기도 했던 문제인데 삽질을 두번 시키는 문제네요 ㅠㅠ
일단 접속하면 아래 그림과 같이 User-Agent가 뜨고 done!(0/70)이 뜨게 됩니다.(저는 두번째 접속이라 2/70 이라고 뜨네요)
겉으로 보이는 웹은 User-Agent라는 문구가 있고, 접속 횟수 만큼 (x/70)에서 x가 올라가게 됩니다. 그래서 저는 같은 User-Agent로 70번 접속하면 문제가 solve될 거라고 생각해 python requests 모듈로 헤더를 추가해 70번 접속을 시켰으나, 다시 0으로 되돌아가더라고요. 그래서 이건 풀이법이 아니라고 생각했습니다.
그래서 혹시나 하고 index.phps를 접속해봤는데 존재하더군요. 소스코드는 아래와 같습니다.(이걸 알았었다면 위에서 삽질을 안해도 됬었는데...)
<html> <head> <title>Challenge 8</title> <style type="text/css"> body { background:black; color:white; font-size:10pt; } </style> </head> <body> <br><br> <center>USER-AGENT <? $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)"); } ?> <!-- index.phps --> </body> </html>
소스코드를 조금 더 자세히 분석해보도록 하겠습니다.
$q=@mysql_query("select id from lv0 where agent='$_SERVER[HTTP_USER_AGENT]'"); $ck=@mysql_fetch_array($q);
에서 USER_Agent로 id를 추출해 내고, 그 결과 값을 mysql_fetch_array()를 통해 $ck 배열에 넣습니다. 그럼 id값은 자연스럽게 $ck[0]에 들어가게 되겠지요.
if($ck) { echo("hi <b>$ck[0]</b><p>"); if($ck[0]=="admin") { @solve(); @mysql_query("delete from lv0"); } }
만약 $ck에 값이 존재할 경우(쿼리가 정상적으로 이뤄져 결과값이 돌아온 경우), hi와 함께 $ck[0], 즉 id를 출력합니다. 또, 그 id가 admin일 경우 문제가 solve됩니다.
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)"); }
만약 $ck가 존재하지 않을 경우, User-Agent,IP,guest(id)를 lv0 테이블에 insert합니다. 보통 처음 해당 웹에 접속했을 때 user-agent와 ip 그리고 id는 guest로 등록하게 되겠지요. 그럼 왠지 여기서 sql-injection이 될 것 같다는 생각이 들지 않나요?
insert into lv0(agent,ip,id) values('$agent','$ip','guest') 에서 agent에 sql injection을 하여 원하는 값을 넣은 뒤 뒤의 ip와 guest를 주석처리 해버리면 될 것 같지 않나요?
일단 필터링을 확인해 보겠습니다.
$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!")
위와 같은 문자들은 필터링이 됩니다. 그러니 주석을 사용할 때 --가 아닌 #를 사용해야 할 것 같습니다.
그럼 공격 시나리오를 작성해보겠습니다.
1. 프록시 툴을 이용해 http 통신을 중간에 캡처한다.
2. 프록시 툴로 User-Agent를 조작한다.
3. User-Agent를 받아 SQL구문을 실행시키므로 User Agent에 아래와 같이 조작하면 Y311J User-Agent가 어드민으로 등록이 될 것이다..
Y311J','127.0.0.1','admin') #
4. 새로고침한 후 User-Agent를 Y311J로 조작할 경우 문제가 Solve 될 것이다.
그럼 이대로 공격해보겠습니다. 저는 프록시 툴을 Burp-Suite를 좋아합니다.
다음과 같이 proxy 툴로 User-Agent를 조작해서 전송하였습니다.
그랬더니...
denied가 뜨지 않고 done!이 뜹니다. 성공여부는 아직 알 수 없지만 필터링에 걸리지 않고 sql문이 제대로 실행된 것 같습니다.
Y311J로 User-Agent를 바꾸고 서버에 전송해보았습니다.
위와 같이 문제가 잘 풀리게 됩니다!
중간에 라업을 날려먹어서 이 문제를 한 5번정도 풀어보는 것 같습니다 ㅋ 절대 못 잊을 것 같습니다. 이상입니다. 감사합니다.
반응형LIST