写在前面
之前有提到过一篇文章,当时仅仅从理论上简单举个例子预编译真的能完美防御SQL注入吗?
最近碰巧看到一道简单的CTF是这个类型的,golang的SQL注入,就拿来记录一下。
分析
func index(c *gin.Context) {
order := c.DefaultQuery("order", "id")
content := c.DefaultQuery("content", "1")
var news []News
db.Where("content LIKE ?", "%" + content + "%").Order(order).Find(&news)
c.JSON(200, news)
}
func main() {
r := gin.New()
r.GET("/", index)
r.Run(":8888")
}
这是一道非常简单的题,我直接贴上关键代码了
一看就得知这是一个web服务,从index函数中可以看出有两个参数一个order,一个content。
db.Where("content LIKE ?", "%" + content + "%").Order(order).Find(&news)
关键在于这条语句,是golang的gorm写法,当我们看到?的时候,没错绝对是预编译,这个时候就不要再想content了,没用的。
而正如之前文章提到过的order by这种是不可参数化的是无法被预编译的,那么就开始对order by进行盲注
这里我就不用具体的盲注语句了,只验证一下即可。
func main() {
var news []News
content := "%"
order := "(IF(1=1, SLEEP(2), 0))"
db.Where("content LIKE ?", "%"+content+"%").Order(order).Debug().Find(&news)
fmt.Println(news)
}
这里我简单写了个demo,可以看到我让content为%,这样就不影响后面order by的执行了,同时我加了Debug()方法,这是为了打印出完整的sql语句,毕竟这是gorm的写法
可以看到是执行了SLEEP。
但是为啥SLEEP时间扩大了2倍?是因为sql语句返回多少个值,order by会循环之行几次,这里我们返回了两个值,所以执行了两次SLEEP(2)。