Go语言特性引发的安全问题的思考

渗透技巧 1年前 (2023) admin
393 0 0

近来比赛中越来越多的go题目,所以最近在学习go方面的一些知识点,恰巧看到P神的讲到这个go语言的一些特性,这里简单复现一些并做一些记录。

go语言的安全性相较于其他语言来说要安全很多,这对安全人员来说也是更大的挑战,从语言设计或者生态的角度来看好像很难找到服务端上的独特问题,导致Go安全通常还是在看一些SQL注入、命令执行、越权等传统通用漏洞。

那么这里我们会发现一个go语言的特性,在一些地方会导致一些问题的产生。

在go语言中他对于“空值”有着他和其他语言不同的设计方法,我们来看一个案例。

python

Go语言特性引发的安全问题的思考

Go语言特性引发的安全问题的思考

php

Go语言特性引发的安全问题的思考

Go语言特性引发的安全问题的思考

这里我们看到在弱语言中我们删除变量后变量就不存在了,那么在一些强类型的语言中,我们声明一个变量如果不给他赋值,他会给一个null值,或者直接未初始化无法使用。

java

Go语言特性引发的安全问题的思考


Go语言特性引发的安全问题的思考

但是在go中,如果我们声明一个变量,那么他就会给这个变量一个0值。

Go语言特性引发的安全问题的思考

Go语言特性引发的安全问题的思考

那么发现这个特性后我们思考会引发什么问题,这里我们看到Gorm这个地方的例子。

package web

import (
 "github.com/gin-gonic/gin"
 "gorm.io/gorm"
)

var DB *gorm.DB

type UserTab struct {
 gorm.Model

 Email string `json:"email" gorm:"column:email;not null;type:varchar(128);unique;size:128;"`
 Token string `json:"token" gorm:"column:token;index;type:varchar(16);default:null;"`
}

func UserHandler(c *gin.Context) {
 token := c.Query("token")
 user, err := UserFirst(&UserTab{Token: token})
 if err != nil {
  c.Status(404)
  return
 }

 c.JSON(200, gin.H{
  "user": user,
 })
}

func UserFirst(query *UserTab) (*UserTab, error) {
 var user UserTab
 err := DB.Where(query).First(&user).Error
 return &user, err
}

模拟了一个根据Token查询用户的功能。其中每个用户都会有一些随机生成的字符串Token,预访问后面的功能需要先校验请求包里的Token对应的用户身份。

这是一个常见的功能,我们可以把这个Token理解为session_id或其他任何什么用户身份标识。但是,我在使用下面这个查询语句查找用户之前,一定要先判断token的值是否为空:

DB.Where(&User{Token: token}).First(&user).Error 

Gorm支持使用一个数据库Model指针的形式生成查询语句,比如&User{Token: token},在token的值不为空时,生成的SQL语句将会是:

SELECT * FROM `user` WHERE `token` = 'your-token' LIMIT 1 

但是,由于Go这门语言本身对于“零值”的设计,他是无法区分某个结构体中某个字段是否有被赋值过。

如果User结构体的token字段本身是一个字符串类型的属性,在初始化User对象的时候Token属性将会拥有一个默认的零值,空字符串;如果此时用户传入的token也是一个空字符串,其赋值给Token属性的时候,对于这个User对象的值将不会有任何改变。

那么此时Gorm的Where函数接收到这样一个User对象的时候,它内部是无法分辨这个对象是根本没有给Token设置任何值,还是给它设置的是空字符串。所以它在生成SQL语句的时候将不会为Token生成条件语句:

SELECT * FROM `user` LIMIT 1 

这样就会导致上面这条ORM语句查询到数据库里第一个用户,而通常第一个用户都是管理员,这也可能导致一次比较高危的越权。 Go无法区分一个结构中属性是没有被初始化过,还是被初始化但赋了零值,这个问题也是Go语言设计中一个比较常见的问题。抛开这次的问题,我们如果作为开发者,要区分这两者通常只能将结构体中的字段设置成一个指针,并通过判断字符是不是nil来判断是否被初始化过。

Go语言特性引发的安全问题的思考


refer

https://www.leavesongs.com/
https://pkg.go.dev/builtin

       

原文始发于微信公众号(山石网科安全技术研究院):Go语言特性引发的安全问题的思考

版权声明:admin 发表于 2023年7月3日 上午10:32。
转载请注明:Go语言特性引发的安全问题的思考 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...