一道go的sql预编译的CTF题

436 阅读1分钟

写在前面

之前有提到过一篇文章,当时仅仅从理论上简单举个例子预编译真的能完美防御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)。