0x00 简介
最近有看到thinkphp的代码,一些小的利用点总结一些
文章主要分为两部分,一部分是围绕写日志展开的,一部分是围绕注入
0x01 写日志
在thinkphp的文件包含利用中,很多都是基于日志的
在没有文件上传的情况下,日志中url的请求路径是一个很好的选择
但是与文件包含不同,如果是反序列化的问题,这种在url中记录的问题没办法通用,因为在phar文件中存在大量的00和01或者其他空白字符,这导致apache或者nginx无法解析这种请求,将会返回一个400状态码
但是并不存在其他的上传方式,像文件包含的ctf中那一堆利用缓存的方式也很难凑效,只有上传文件的缓存可以操作一下,当服务器为windows时,可以比较轻松的爆破
但在这里将注意点放在了”无法加载控制器:Lat”的Lat上(最后也白搭,记录因为有延申)
日志的记录是因为调用了log::save
这个方法只是单纯的写文件
关于文件内容,需要向上追溯
在抓取异常的方法中设置了记录内容,主义的点时这个在文件最后存在\r\n
,也就是说如果最后能写,也得用tar包的形式才可以
那么直接去找throw new
就可以,但是由于需要通用,并且参数可控
最终的关注点还是在E函数上
1 | function E($msg, $code = 0) { |
调用此方法的,就是我们上面看到的一些日志记录的了,
包括模板解析的错误,数据库的错误,缓存错误(这些错误,需要特定的方法触发,在不知道代码的情况下,比较难以构造),最终定位的类是
- App
- Controller
- Dispatcher
不过很明显这三个点基本都是方法名,控制器名,模块名
而系统中针对它们的处理方式是类似的
可以看到从get中获取到变量之后,最终都要经过strip_tags函数的处理
从这里就知道可能phar文件白整了,但是可以看下这个的日志记录
分别请求
1 | c=lat<aaaa |
分别对应的三条日志记录如下
可以看到%00是不能用了,构造phar文件是别想了,但是这种方式还是可以用来绕过一些waf的,比如宝塔,多了不说,看下底层代码,对00直接跳过,相当于<>
0x02 注入问题
这个是针对thinkphp3的
原因是,之前的代码都是用来解析模板的,而现在后端都是接口,发送和返回json数据就可以了,其他的交给前端处理,之前可能看到的少
比如说showdoc这套代码,就修改成了纯接口模式的
那么就会出现一个问题,thinkphp3默认是不支持json数据传参的
要想接受就需要将传参加在合适的位置
以showdoc为例,将代码添加在了base控制器的构造方法中
那么当引入了json数据之后,弱类型问题随之而来,这部分就讨论下存在的弱类型问题
什么时候调用的构造方法呢?在所有的参数接受之前
就是说后面的I函数接受到的参数都是经过json_decode处理的
而我们如果想要保住这个被处理过的参数类型,有两种可能的方式
- 未设置默认过滤器
- 反射传参
第一种方式
这个得看一下I函数,关键代码就是红色方框中的,当不存在默认的过滤器时,会跳过方框中的代码,如果存在默认的过滤器,一般都是htmlspecialchars、trim
之类的,返回的值将会变成string类型
第二种方式
反射传参的话,需要开启参数绑定过滤,而这个参数默认是关闭的,所以不会进入默认过滤器的处理逻辑
当然,所有的接受参数的模式都要经过think_filter,还是会对表达式进行处理,所以这里才要提弱类型
重点关注的方法
数据库操作中,增删改查,其实都可以
先看insert方法,此方法是可以利用的
而我们主要的利用点就是这个exp表达式
然后是update方法
上面这两种是可以直接利用的
但是where中也存在一处利用点就是in表达式
所以类似与如下代码也会出现问题,不过这种写法基本不可能出现
1 | $map = ['in'=>$ids]; |
复现
插入
关于插入的payload,无论是insert还是update,无论是I函数未设置过滤,还是通过反射,只要接受json参数,都是可尝试payload
1 | {"content":"aaaaa","username":[0,"(select updatexml(1,concat(0x7e,user()),1))"]} |
查询
上面还提到了查询的问题
写法基本不可见,就不写了
0x03 end
….