在俱乐部内一次web交流,了解到这个题目,感觉很不错。记录一下。
知识点:php session工作原理,session反序列化。
文章目录
需要了解的知识
打开容器,进行代码审计
<?php
highlight_file(__FILE__);
$content = @$_GET['content'] ? "---mylocalnote---\n" . $_GET['content'] : "";
$name = @$_GET['name'] ? $_GET['name'] : '';
str_replace('/', '', $name);
str_replace('\\', '', $name);
file_put_contents("/tmp/" . $name, $content);
session_start();
if (isset($_SESSION['username'])) {
echo "Thank u,{$_SESSION['username']}";
}
//flag in flag.php
分析一下这个源码:
1. GET传参
$content = @$_GET['content'] ? "---mylocalnote---\n" . $_GET['content'] : "";
这句代码的意思是,将传入的$content
和字符串---mylocalnote---
进行拼接,并且作为新的$content
的值。比如:
<?php
$content = @$_GET['content'] ? "---mylocalnote---\n" . $_GET['content'] : "";
var_dump($content);
//传参 ?content=****
//回显:string(22) "---mylocalnote--- ****"
$name
也是一样的道理
2. 创建session文件
file_put_contents("/tmp/" . $name, $content);
将在/tmp/
目录下创建session文件,文件名称和内容是我们传入的$name
和$content
3. php session工作原理
这里找了alexander_phper师傅的一篇博文,写得特别好!!
博文链接:PHP SESSION PHPSESSID session_id()
引用部分内容:
其中,我们可以抓包获取PHPSESSID
,将sess_PHPSESSID以GET传参的方式传入$name
,作为服务端识别的session文件。
4. session的相关知识和session_start()函数的作用
这里是有一个Sn0w/
师傅写的一个关于session反序列化
的文章,写得特别棒(๑•̀ㅂ•́)و✧,贴一下链接:原理+实践学习(PHP反序列化和Session反序列化)
其中讲到的php会自动反序列化session文件的内容,并将其填充到$_SESSION超级全局变量中
很重要。
再看一下源码:
if (isset($_SESSION['username'])) {
echo "Thank u,{$_SESSION['username']}";
}
同时访问flag.php回显:
u are not admin,only admin can see flag!
我们可以想到这个题目的解题思路
解题思路
我们利用源码能够将传入的$name
和$content
分别作为文件名称和内容再/tmp/
目录下创建文件,利用session工作原理,创建一个session文件,文件内容有序列化之后的uesrname:admin
。这样我们访问flag.php时,服务端就会访问session文件,将内容反序列化,即可伪造admin,即可访问flag.php文件。
解题步骤
session文件名称
首先得到cookie中的PHPSESSID
PHPSESSID=ab7v6dt2hp8fsnqndibtjs2au7
得到session文件名称:sess_ab7v6dt2hp8fsnqndibtjs2au7
session文件内容
需要了解session文件的存储格式
这里咱们用的是php引擎,即键名 | serialized_string
$content = @$_GET['content'] ? "---mylocalnote---\n" . $_GET['content'] : "";
我们传入的content值会和---mylocalnote---
进行拼接,所以需要根据反序列化将前面的---mylocalnote---
作为键名,进行闭合操作。
闭合---mylocalnote---
,可以使用N将其闭合,即
---mylocalnote---|N
然后加上我们的username:admin
序列化之后的结果
---mylocalnote---|N;username|s:5:"admin";
数据末尾用;
标识,所以最后的payload为
?content=|N;username|s:5:"admin";&name=sess_ab7v6dt2hp8fsnqndibtjs2au7
回显:接着访问flag.php,即可得到flag