标签 php 下的文章

PHP session 机制

  • 在网上总结(扒了点)关于session 机制,零零散散,大体就是这些吧。

PHP 服务端session 处理

配置

PHP 中 session 的配置位于 php.ini 中,默认是将session以文件形式存储与文件夹下,一般是 /tmp 目录,每个session文件以 sess_ 开始命名。

处理方式的配置项为

session.save_handler = files

当需要自定义时可以设置

session.save_handler = user

session机制的开始
session_start()

先看文档:

session_start() creates a session or resumes the current one based on a session identifier passed via a GET or POST request, or passed via a cookie.

这里的 session identifier 指的就是同样在 php.ini 配置的

session.name = PHPSESSID //默认值PHPSESSID

简单来说,session_start() 启用了 session 机制,基于客户端是否携带有 session 信息,会进行新建 session 或者复用现有 session。

session 的过期或失效

session 有两种无效的场景,一种场景是客户端结束会话,session 就被视为失效,另一种场景是超出了过期时间。过期时间的默认配置为1440s,也就是24分钟,配置项为:

session.gc_maxlifetime = 1440

超过这个时间的 session 文件被视为过期,但是仅仅是被视为过期,至于清除过期 session 文件则是另外的工作。

session的垃圾回收

session 即使是已经过期,但是文件仍然会存在于 /tmp 目录下,所以需要启动 GC 机制来清除这些过期文件,否则使用对应的 sessionid 仍然可以使用这些文件,PHP 对 session 的垃圾回收处理是有一定概率触发的,同样在 php.ini 中,有两个参数:

session.gc_probability = 1

session.gc_divisor = 1000

这表示每次新建 session 时,PHP 会有1/1000的概率执行垃圾回收,触发后才会清除当前已有的过期 session 文件

session手工销毁

session_destroy();   // 删除$_SESSION 删除session文件,和session_id

客户端session处理

之前提到了配置中可以设置 session 关键字的名称session.name = PHPSESSID, 服务端对于每次请求,会自动判断当前 cookie 是否携带了 $_COOKIE[session_name()]; ,如果存在则直接查找对应的 session 文件,否则就会生成新的 session_id ,然后把生成的 session_id 作为 COOKIE 的值传递到客户端,所以可以看到客户端 cookie 中包含了 PHPSESSID。

存在于客户端 cookie 中的 session 信息,在客户端关闭后会自动被清除,客户端关闭指的是关闭浏览器,而不是关闭一个 tab。

session_start()详细解释

php session_start()函数用于初始化session数据,我们在使用session时,经常要使用到$_SESSION变量,$_SESSION是服务器端的cookie,相当一个大数组(浏览器关闭前,和session销毁前),$_SESSION中的数据可以一直用(除了重新赋值),在使用这个变量之前,必须先要开启session_start()。但不一定要把这个函数放在第一行,而是要保证在使用它之前,没有向浏览器输出过任何内容。

特别注意:在调用session_start()之前,要确保页面没有向浏览器输出过任何内容。

php配置文件里可以设置session.auto_start =1 这样就不需要调用session_start(),直接就能使用session

php session_start()实例讲解

<?php
    /* http://www.manongjc.com/article/1267.html */  
    session_start();  
    $_SESSION['test'] = 'test111';  
    $_SESSION['test2'] = 22222;  
?>  

session_start()会做两件事:

  1. 在客户端生成一个存放PHPSESSID的cookie文件,这个文件的存放位置和存放方式跟程序的执行方式有关,不同的浏览器也不尽相同,这一步会产生一个序列化后的字符串——PHPSESSID。
  2. 在服务端生成一个存放session数据的临时文件,存放的位置由session.save_path参数指定,名称类似于sess_b2f326ee7a8b7617c215a30d22a602f1sess_代表这是个session文件,b2f326ee7a8b7617c215a30d22a602f1即此次会话的PHPSESSID,跟客户端的PHPSESSID一定是一样的。这个文件里存放的就是$_SESSION变量里的具体值,格式如下:
变量名 | 变量类型 : [长度] : 值

test|s:7:"test111";
test2|i:22222;

php中的MD5弱类型

ps:

== 和 != 比较若类型不同,先偿试转换类型,再作值比较,最后返回值比较结果
而=== 和 !== 只有在相同类型下,才会比较其值

0x00

if($_POST['param1']!=$_POST['param2'] && md5($_POST['param1'])==md5($_POST['param2'])){
    die("seclab507{php_is_weak_____}");
}

绕过方式: param1=240610708&param2=QNKCDZO

0x01

if($_POST['param1']!==$_POST['param2'] && md5($_POST['param1'])===md5($_POST['param2'])){
    die("seclab507{php_is_weak_____}");
}

===强类型,md5的值不进行类型转换,当作字符串处理.需要用数组进行绕过
绕过方式:param1[]=123&param2[]=1231

0x02

if((string)$_POST['param1']!==(string)$_POST['param2'] && md5($_POST['param1'])===md5($_POST['param2'])){
    die("seclab507{php_is_weak_____}");
}

var_dump(md5('240610708') === md5('QNKCDZO'));  #False
数组绕过不行会报错
绕过方式:MD5碰撞

fastcoll 生成md5相同的文件:

E:\ctf工具\ctf工具\加解密工具\MD5碰撞\fastcoll_v1.0.0.5>fastcoll_v1.0.0.5.exe -o p1.txt p2.txt
MD5 collision generator v1.5
by Marc Stevens (http://www.win.tue.nl/hashclash/)

Using output filenames: 'p1.txt' and 'p2.txt'
Using initial value: 0123456789abcdeffedcba9876543210

Generating first block: .......
Generating second block: S11...................
Running time: 1.892 s

因为文件含有很多不可打印字符所以进行url编码:

#! /usr/bin/env python2
# -*- coding: utf-8 -*-
# Author: Archerx
# @time: 2018/10/6 下午 09:13

import urllib

f1 = open('p1.txt','rb')
f2 = open('p2.txt','rb')
param1 = urllib.quote(f1.read())
param2 = urllib.quote(f2.read())
print('param1='+param1+'&param2='+param2)

本地测试:(使用bp,hackbar会再进行一次url编码)

POST /md5_test/ HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:62.0) Gecko/20100101 Firefox/62.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1/md5_test/
Content-Type: application/x-www-form-urlencoded
Content-Length: 317
Connection: close
Upgrade-Insecure-Requests: 1

param1=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2&param2=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2

或者curl 直接请求:

C:\Users\徐超>curl -v http://127.0.0.1/md5_test/ -H "Cookie: PHPSESSID=True" --data "param1=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2&param2=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2"
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
> POST /md5_test/ HTTP/1.1
> Host: 127.0.0.1
> User-Agent: curl/7.55.1
> Accept: */*
> Content-Length: 317
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 317 out of 317 bytes
< HTTP/1.1 200 OK
< Date: Sat, 06 Oct 2018 13:25:41 GMT
< Server: Apache/2.4.23 (Win32) OpenSSL/1.0.2j PHP/5.5.38
< X-Powered-By: PHP/5.5.38
< Content-Length: 27
< Content-Type: text/html
<
seclab507{php_is_weak_____}* Connection #0 to host 127.0.0.1 left intact

挺有意思的网站:https://www.mscs.dal.ca/~selinger/md5collision/

preView