前言
这道题做起来并不是很难,但是因为go的话出的也不多,里面涉及的点也是比较有意思的,所以写一下。
路由分析
这个题目是gin+gorm写的一个web服务
路由主要为以下几个
router.GET("/user", UserHandler) 获取用户信息
router.POST("/login", LoginHandler) 登录
router.POST("/upload", cookieCheckMiddleware(), UploadHandler) 上传文件(需要登录)
router.POST("/move", IpSecurityCheck(), SubmitMoveHandler) 移动文件(检测ip)
router.POST("/download", cookieCheckMiddleware(), DownloadHandler) 下载文件
upload、move、download是存在中间件进行校验的。
做题的时候肯定是需要找重点去看的,这里因为代码量并不多,所以可以仔细看看。
gorm问题
首先看/user这个路由
具体代码如下
p牛曾经在星球里面说过这个问题,由于Go这门语言本身对于“零值”的设计,他是无法区分某个结构体中某个字段是否有被赋值过。如下代码,如果id参数不传值的话,这条SQL语句直接帮我们把where条件去掉了,这里实际上就产生了安全问题。
就是这段代码,如果token不传值的话,实际上执行sql语句的时候token也是不会在where条件内的,
所以直接查询就可以获得表的第一条数据了。
中间件问题
接下来进入重点,也是解决题目的地方。
在这个函数内是存在命令执行的功能点的,而且这里是采取拼接处理,不存在关键字过滤等防护。如果可以调用到这个函数的话就可以进行RCE了。
而move路由的话就是调用的该函数进行处理,那么只需要访问move路由然后传入文件名即可。但是这个路由是存在一个中间件防护的。
这个中间件会对IP进行检查,但是ip又不能伪造,那怎么办呢
仔细看这段代码其实是存在逻辑问题的,gin的中间件其实有点类似java的filter,放行的话就需要写c.Next(),拦截就是c.Abort(),但是这里是没有c.Abort()的,所以就出问题了,然后这里有一个return,但是代码还是继续往后执行了,因为没有被拦截。所以这个中间件其实是没有起到防护作用。
这样才是正确写法。
所以解题思路很明确了,直接传值即可,因为是无回显,这里借助dnslog平台进行解题
结语
在进行代码审计的时候,我们也需要重点关注一些代码逻辑产生的问题,这个问题有点像以前出现很多的php系统相关的重装漏洞,做了判断但是并没有exit()程序,导致代码逻辑还是在往下跑。