$password = md5('Gh0st_!n_th3_Sh3ll');공개
소스코드 분석
<?php include "./config.php"; login_chk(); dbconnect("phantom"); if($_GET['joinmail']){ $query = "insert into prob_phantom values(0,'{$_SERVER[REMOTE_ADDR]}','{$_GET[joinmail]}')"; mysql_query($query); echo "<hr>query : <strong>{$query}</strong><hr>"; } $rows = mysql_query("select no,ip,email from prob_phantom where no=1 or ip='{$_SERVER[REMOTE_ADDR]}'"); echo "<table border=1><tr><th>ip</th><th>email</th></tr>"; while(($result = mysql_fetch_array($rows))){ if($result['no'] == 1) $result['email'] = "**************"; echo "<tr><td>{$result[ip]}</td><td>{$result[email]}</td></tr>"; } echo "</table>"; $_GET[email] = addslashes($_GET[email]); $query = "select email from prob_phantom where no=1 and email='{$_GET[email]}'"; $result = @mysql_fetch_array(mysql_query($query)); if(($result['email']) && ($result['email'] === $_GET['email'])){ mysql_query("delete from prob_phantom where no != 1"); mysql_query("alter table prob_phantom AUTO_INCREMENT=2"); solve("phantom"); } highlight_file(__FILE__); ?> |
joinmail의 파라미터가 있으면 insert 쿼리를 실행한다. 어떤 값을 0으로 고정하고 있고, IP와 joinmail 파라미터를 prob_phantom에 삽입한다.
joinmail 파라미터가 존재하지 않으면 자신의 IP에 해당하는 ip, email 데이터를 출력한다. 그리고 no = 1이면 email값을 *로 출력한다.
no=1에 해당하는 ip는 127.0.01 루프 백 아이피이며, email의 값을 email 파라미터로 요청하면 no != 1이 아닌 모든 값을 삭제하고 phantom 문제를 클리어한다.
문제 풀이
목적은 no=1의 email이 무엇인지 알아내는 것이다.
페이지 내 select 쿼리에 사용자의 입력값은 email 파라미터를 받는 곳 그리고 자신의 아이피를 받는 곳이 있다. 자신의 아이피를 받는 곳은 변조가 불가능하고, email 파라미터는 싱글쿼터를 필터링한다. 유일하게 변조가 가능한 사용자 입력 값이 들어가는 쿼리는 joinmail이다. INSERT INTO 구문을 조작해야한다.
플래그 값 자체를 *로 필터링 하는 것이 아닌, no==1에 해당되어 있는 email값을 필터링 하는 것이므로 no가 1이 아닌 값으로 email 값을 삽입하면 열람할 수 있을 것이다.
테스트 용 DB에 1을 삽입한다. 목적은 INSERT INTO 쿼리에 1이라는 값을 사용하지 않고 1을 삽입해 보도록한다.
간단하게 생각해서 select id from table이라는 서브쿼리를 이용해서 삽입을 시도해본다.
하지만 ERROR 1093을 출력하며 삽입할 수 없다. Oracle과 달리 INSERT INTO를 할때 자기 테이블의 데이타를 직접적으로 사용할 수 없다.
이 문제는 서브쿼리를 하나 더 삽입하여 임시테이블을 만듬으로 써 해결할 수 있다.
서브쿼리안에 select id as a from table를 테이블로 불러와서 a를 출력한다. 서브쿼리의 형태는 select a from (select id as a from table) 이 되겠다.
위의 서브쿼리를 날리면 또 다른 에러를 출력한다. 모든 table은 alias가 필요하다는 ERROR이다. 서브쿼리를 하나 더 추가해주어 만든 (select id as a from table) 은 select a from (~) 서브 쿼리의 table이므로 서브쿼리의 서브쿼리에 alias를 넣어주어야한다. alias는 어떤 것이든 상관 없으므로 아무 값으로 정해주자.
에러를 다 수정하면 1을 사용하지 않고도 1이 table에 추가된 것을 확인할 수 있다. 실제 문제에서는 문제에 있는 INSERT 구문을 에러가 나지 않도록 맞춰주면서 루프백 아이피의 email 값을 포함하는 values를 삽입해주면 된다. 페이로드는 아래와 같다. 서브쿼리에 결과로 반환되는 값이 1개 이상이면 에러가 나므로 루프백 아이피에 해당하는 값만 반환하도록 조건절은 원하는 대로 삽입해주도록한다.
?joinmail=1'),(0,'218.146.20.61',(select a from (select email as a from prob_phantom where no=1) as b))-- -
정상적으로 삽입되었다. admin_secure_email@debu.kr를 email 파라미터로 요청하면 문제를 해결할 수 있다.
'wargame > Lord Of SQL Injection' 카테고리의 다른 글
[LOS] zombie (0) | 2018.08.18 |
---|---|
[LOS] ouroboros (0) | 2018.08.09 |
[LOS] frankenstein (0) | 2018.08.09 |
[LOS] blue_dragon (0) | 2018.07.24 |
[LOS] red_dragon (0) | 2018.07.22 |