PHP收货记录
1:特殊的=?>标记
先通过一个题目来认知:
题目截图
这题根据php源码,可以很快了解题目意图。总之就是在一大堆限制中构造payload读取flag。
这个题目,首先要满足$_GET['flag']
和$exam
字符串长度相等,$exam
的长度可以确定。并且,不能通过参数数组绕过。
下面一大堆正则表达式,上面说过,由于存在字符长度的检测(且不能通过数组绕过)所以这里的正则就不能通过数组的方式绕过了。
再下面就是一个eval函数,payload构造的重点就在于此。由于正则表达式的存在,eval中就不能使用PHP函数了。echo等关键方法也被过滤了。
所以这里就引出PHP标记<?=?>
的特性了。
PHP 有一个 echo 标记简写
<?=
, 它是更完整的<?php echo
的简写形式。
于是用这个标记,就能构造出打印$flag
的payload了。由于flag字符被过滤了,可以使用字符串操作构造出flag
此题的payload:
1 | /?flag=$a='xlag';$a{0}='f';?>1111111111111111111<?=$$a?> |
中间的1111是占位符,满足前面字符长度的要求。
2. SQL单引号转义
从一个题目里分析:
1 |
|
这是一个SQL注入题。题目提供了源码。
由于上面的clean()
函数会让构造的payload中的引号转义了,就没法通过添加引号进行SQL注入了。
不过,我们可以用手段将SQL query 中的 '
转义了。比如在payload末端加入 \
(反斜杠)将query中的name
的后面一个 '
转义。例如,得到下面的结果:
1 | SELECT * FROM users WHERE name='admin\' AND pass='2333' |
这样得到name='admin\' AND pass='
pass
被包含到name
里面去了。于是输入的password就暴露了出来,可以直接注入SQL语句了(注意:pass后面还有一个 '
但是只需要把它注释掉即可)。
于是,根据题目意思,构造payload。可以看到,payload中没有一个分号
1 | /?username=\&password=or%201=1%23 |
注:%23为#的URL编码。
文件包含、读取
Session条件竞争
利用条件:
- PHP应用可以任意读取文件
- PHP>5.4.0
- session.upload_progress.enabled 选项开启(默认)
- 一般读取文件加了很多限制条件,至少限制了flag文件的直接读取。(如果能直接读取flag为何还要大费周章)
通过POST上传文件的同时添加 PHP_SESSION_UPLOAD_PROGRESS
form-data参数和自定义的**PHPSESSID
** cookie,form-data可以是任意值(PHP恶意代码),发送后form-data值会临时保存在session文件(文件路径以及命名方法同PHP session配置)中,如当cookie值为abcd时对应路径为**/tmp/sess_abcd**(默认)。
不过,如前面提到的临时,POST文件上传结束(请求结束后),session文件中的内容就会自动清空(默认)。所以,通过”竞争“,进行多线程请求,使session文件中保持内容的概率增加,然后再通过已有的include或文件读取方法将其中的PHP代码执行达到目的。
注:此方法并不需要有真实的文件上传接口,也不用关心上传文件的内容(尽量大一些,可以延长session存在时间)