2023 强网杯 thinkshop[ping]
分析完这题,时隔一年又让我想起这句话…… thinkshop 拿到手是一个.tar文件,而且用的是amd64打包的,m1折腾了好久也没搞好debug = = debug只能本地起一个服务 构建好容器后直接把html下的附件拉下来后先访问。可以发现是个thinkphp 5.0.23搭建的商店(版本号随便打个404就能发现) 进去后什么都没有,所以分析一下入口代码。发现首页html在html/application/index/view/index/index.html 在controller目录下又找到Index.php 这里的assign是在html中注册一个变量的意思。这样就能在html里用类似下面这样的方法调用php里的变量。这种方法就是php模板 一样在view目录下,发现admin里有一个login.html,所以应该是有登陆入口。看一下路径 现在的访问路径是http://127.0.0.1:36000/public/index.php/index/index/index,所以猜测是http://127.0.0.1:36000/public/index.php/index/admin/login.html。成功访问 根据代码分析可以发现,post数据交给了一个叫do_login的地方,搜索一下 跟进找到Admin.php里 想办法看能不能登陆。这里主要是要看$adminData是怎么处理的。可以看到查找了admin表,并用cache函数尝试通过缓存获取。这里因为我们有容器,所以进到容器里看一下admin表 查一下这个被md5的密码可以得到123456。但此时如果直接拿admin和123456去登陆会发现提示错误,主要问题就在于后面这个很容易被忽略的find函数 可以看到,这个find函数直接拿post进来的用户名去find,这里可以搜一thinkphp里的下find方法 可以发现,当find里是个字符串时,会将其当作主键进行查询。一般就是第一个字段,也就是id字段,而admin显然是在username字段,因此没法查到,所以才会登陆失败。所以这里要用username=1&password=123456进行登陆 登陆进来后发现有几个操作,先进入修改看看 商品信息应该是markdown格式,可以看一下代码 在goods_edit.html里发现index/admin/do_edit 根据刚刚的经验,跟进到do_edit函数 可以发现所有修改的数据都会被这个函数处理。我们先回到html看一下。发现这个地方有一个反序化的点,在进入这个页面时会显示数据库里存放的markdown内容,就是这样调出来的 或者在首页的商品详情页面也能看到类似的反序列化调用点 搜一下可以发现thinkphp5.0.24存在反序化漏洞,5.0.23可用(点这里查看,更详细分析可以看这里) 所以接下来就是想办法修改数据库的内容从而利用这个反序列化点。 不过先不着急,返回去先看一下首页还没有看的添加功能。这里我们直接看Admin.php里的操作函数就行 先来看看do_add 首先$data可控,因为反序列化的点只对$goods[‘data’]进行,所以我们只看’data’键的操作。 在第131行可以看到直接对’data’键的值进行了序列化,我们如果在这里传入payload后存入数据库是被事先序列化一遍的,并且如果我在post时试图插入一个新的键值对,他也不会写入到goods里。显然这里不可控。 回到刚刚的edit里,发现所有post进来的东西都会被丢到saveGoods函数,跟进 可以发现这里一样是对’data’键进行事先序列化,但是到目前为止整个过程还并没有对变量$data(需要注意是变量$data而不是键’data’)的其他键值进行处理,也就是说如果我在这里插入一个键值对,是可以正常传进save函数的。我们继续跟进save 一样,整个$data进入到updatedata函数,跟进 发现直接把传进来的所有$data变量里的键都存到数据库里,并且不存在过滤,所以这里我们直接构造payload如下,尝试修改数据库 data` = 111 where id = 1# 丢到cyberchef里编码一下就开打。 但是发现直接说商品更新失败了,而且sql数据库里也没有变化 说明写入失败了。看了一下网上几篇wp说是rtrim会把空格干掉 但查询后发现rtrim函数的作用是去除末尾的空格,即便指定了第二个参数也是末尾。而且根据updatedata函数的逻辑,这里的rtrim主要目的是为了删掉sql语句中最后一个多出来的逗号,这样才能写入数据库 ...