baby_csp

前言

在p牛的知识星球看到一个php的帖子,最近几年安全研究员都仅跟潮流研究java安全。php还是很少见,这引起了我的好奇。

环境

Dockerfile

FROM php:apache
COPY index.php /var/www/html

index.php

<?php
header("Content-Security-Policy:default-src 'none';");
if(isset($_GET["xss"])) echo $_GET["XSS"];
?>

根据Dockerfile创建镜像

  • 在含有Dockerfile的文件下运行这条命令

  • 虚拟机最好是要挂代理,下载会很快

docker build -t myphpxss .

根据镜像创建docker容器

  • 踩坑点:这条命令是指把容器的80端口映射给本机8080端口。此处,容器的端口一定要是80,本机端口无所谓。
docker run -d -p 8080:80 myphpxss

hackfun

image-20240514161104324

P牛给的原理:

PHP继承了CGI的特性,输出就等于写入HTTP response,一旦开始写入response,就无法再设置header。在这道题目里,echo在header()后面执行,所以正常来讲header()执行不会遇到问题。 但这里可以使用到一个trick:默认情况下max_input_vars的值是1000,也就是PHP最多接受1000个参数。一旦超过这个数量,PHP就会出错并产生一个Warning。Docker PHP环境默认的error_reporting是空,即为E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED,会显示除了E_NOTICE、E_STRICT、E_DEPRECATED以外的所有错误信息。 由于参数解析过程发生在脚本执行以前,错误信息写入response会导致header()函数执行出错,最终CSP头无法输出,XSS成功执行。 我记得之前CTF也出现过类似的考点,但这道题确实体现了“浓缩就是精华”的道理。 通常情况下,为了解决错误信息输出导致header()函数执行失败的问题,我们可以给output_buffering选项设置一个值,比如4096。当output_buffering大于0时,输出数据则会先存放于对应大小的缓冲区中,只有输出的内容大于缓冲区大小时,response才会实际写入。由于Docker默认PHP环境的output_buffering等于0,没有任何缓冲区,这也是这个CTF能够实现的必要条件。

P牛还问了一个问题:

​ 除了1000个参数以外,你还能找到哪些方法在脚本执行前触发错误并输出错误信息?