DASCTF-2024最后一战-WEB-复现
DASCTF 2024最后一战-web复现
strange_php
首先看到welcome.php的删除评论功能点可以自己传参文件名$message_path
,跟进deleteMessage
函数
传入后加上了.txt后缀,并且使用了file_exists()函数,这里可以联想到phar反序列化
紧挨着delete函数的__set
魔术方法中含有file_get_contents()
函数,并且能输出到已知的目录和文件名
_set
由给类内一个不存在的属性赋值触发,由于PDO_connect.php给了我们数据库的连接参数,我们可以尝试进行覆盖来连接到自己的数据库
这里参考大佬给出的方法:
如果我们将ATTR_DEFAULT_FETCH_MODE指定为262152
,就可以将结果的第一列做为类名, 然后新建一个实例,在初始化属性值时,sql的列名就对应者类的属性名,如果存在某个列名,但在该类中不存在这个属性名,在赋值时就会触发类的_set方法。
这里提到的 262152
实际上是 PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE
的组合值(PDO::FETCH_CLASS
的值是 262144,PDO::FETCH_PROPS_LATE
的值是 8)
- 当
ATTR_DEFAULT_FETCH_MODE
设置为PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE
(262152) 时,PDO 会执行以下步骤:- 从结果集中读取一行数据。
- 将该行数据的第一列的值作为类名。
- 使用该类名创建一个新的实例(通过
new $className
)。 - 调用该实例的构造函数。
- 遍历结果集的剩余列,将列名作为属性名,列值作为属性值,并尝试将这些值赋给该实例的属性。
因此我们可以在数据库新建一个UserMessage表,并且更改filePath的值,再加上一个不存在的变量(password),即可触发__set
User类中的log函数进行了数据库连接,这里就是入口
他还提供了数据表名,用户名,密码从而指定从哪一行读取,上面的PDO_connect类指定了数据库
在云服务器创建数据库如图,filePath一定放在password之前,否则会被set打断无法赋值
记得创建一个joker账户,授予全部权限
poc:
1 |
|
之后进行反序列化读取(报错是正常的,phar协议不可删除文件)
访问/log/0bc7be346d4df269543565b6b7cd231a.txt 即md5(/flag).txt