Golang的一些简单漏洞测试

前言:Golang的一些简单漏洞测试,用于熟悉Golang

经典的整数反转/溢出问题

golang 存在非常经典的整数反转/溢出问题

对无符号数的反转

1
2
3
4
5
6
7
func main() {
var a uint32 = 2147483648
var b uint32 = 2147483648
var sum = a + b
fmt.Println(reflect.TypeOf(sum))
fmt.Printf("Sum is : %d",sum)
}

想要直接声明一个大小已经溢出的数自然不会通过编译,因此出现反转的话,主要是在变量的相加这样的计算才会会导致标志CF位反转

有符号数的溢出

1
2
3
4
5
6
7
func main() {
var a int8 = 127
var b int8 = 1
var sum int8 = a + b
fmt.Println(reflect.TypeOf(sum))
fmt.Printf("Sum is : %d",sum)
}

在math包的const.go包里面有以下定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const (
MaxFloat32 = 0x1p127 * (1 + (1 - 0x1p-23)) // 3.40282346638528859811704183484516925440e+38
SmallestNonzeroFloat32 = 0x1p-126 * 0x1p-23 // 1.401298464324817070923729583289916131280e-45

MaxFloat64 = 0x1p1023 * (1 + (1 - 0x1p-52)) // 1.79769313486231570814527423731704356798070e+308
SmallestNonzeroFloat64 = 0x1p-1022 * 0x1p-52 // 4.9406564584124654417656879286822137236505980e-324
)

// Integer limit values.
const (
intSize = 32 << (^uint(0) >> 63) // 32 or 64

MaxInt = 1<<(intSize-1) - 1 // MaxInt32 or MaxInt64 depending on intSize.
MinInt = -1 << (intSize - 1) // MinInt32 or MinInt64 depending on intSize.
MaxInt8 = 1<<7 - 1 // 127
MinInt8 = -1 << 7 // -128
MaxInt16 = 1<<15 - 1 // 32767
MinInt16 = -1 << 15 // -32768
MaxInt32 = 1<<31 - 1 // 2147483647
MinInt32 = -1 << 31 // -2147483648
MaxInt64 = 1<<63 - 1 // 9223372036854775807
MinInt64 = -1 << 63 // -9223372036854775808
MaxUint = 1<<intSize - 1 // MaxUint32 or MaxUint64 depending on intSize.
MaxUint8 = 1<<8 - 1 // 255
MaxUint16 = 1<<16 - 1 // 65535
MaxUint32 = 1<<32 - 1 // 4294967295
MaxUint64 = 1<<64 - 1 // 18446744073709551615
)

而当进行类型转换时,从较大的整型向较小的整型转换可能会导致截断问题。这意味着较大整型的高位字节会被截断,只保留较小整型能表示的范围内的字节。

举例来说,在 Golang 中,将一个 int16 类型的变量 a 的值设为 256,然后将其转换为 int8 类型的变量 b。由于 int8 类型只能表示 -128 到 127 之间的值,所以在转换时发生了截断。结果打印出的值为 0,因为高位字节被截断了。

类似的情况也可以在其他类型转换中出现。例如,在使用 strconv.Atoi 函数将字符串转换为整数时,如果目标类型是 int32,而原始值超出了 int32 的表示范围,就会发生截断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
"fmt"
"math"
)

func main() {
var a int16 = 128
var b int8 = int8(a) // 截断发生在这里
fmt.Println("Truncated value:", b)

// 修复截断问题(对参数进行检查)
var c int16 = 256
var d int8
if c > math.MaxInt8 {
d = math.MaxInt8
} else if c < math.MinInt8 {
d = math.MinInt8
} else {
d = int8(c)
}
fmt.Println("转换失败,返回:math.MaxInt8", d)
}

在Go 1.20之前的math/rand伪随机数的种子问题

原漏洞代码

1
var globalRand = New(&lockedSource{src: NewSource(1).(*rngSource)})

这个已经修复的东西,emmm

Golang的SSTI

Golang SSTI(服务器端模板注入)是指在使用Golang编写的服务器端应用程序中,存在模板注入漏洞的情况。模板注入漏洞是一种安全漏洞,攻击者可以通过注入恶意模板代码来执行任意代码或获取敏感信息。

Golang提供了两个模板包,分别是text/templatehtml/template。其中,text/template对XSS(跨站脚本攻击)或任何类型的HTML编码没有保护,因此不适合用于构建Web应用程序。而html/template相对安全一些,它提供了HTML编码等安全保护,更适合用于构建Web应用程序。

在Golang的模板中,使用{{}}来表示模板的动态内容,其中的操作称为pipeline。常用的基本语法包括:

  • {{.}}:表示当前对象。
  • {{.FieldName}}:表示对象的某个字段。
  • {{range ...}}{{end}}:类似于Go语言中的for…range循环。
  • {{with ...}}{{end}}:表示当前对象的值,上下文。
  • {{if ...}}{{else}}{{end}}:类似于Go语言中的if-else条件选择。
  • {{xxx | xxx}}:表示将左边的输出作为右边的输入。
  • {{template "navbar"}}:引入子模板。

当使用模板引擎时,需要注意安全性。在使用text/template时,如果传入的参数可控,就有可能实现XSS攻击。而html/template会对特殊字符进行转义,从而防止XSS攻击。

在Golang中,检测SSTI并不像发送{{7*7}}并在源代码中检查结果是否为49那么简单。需要浏览文档以了解Go原生模板中的行为,最常见的是占位符.,表示当前作用域的当前对象。

以下是一个示例代码,演示了Golang中的SSTI漏洞:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"net/http"
"text/template"
)

type User struct {
ID int
Name string
Email string
Password string
}

func StringTpl2Exam(w http.ResponseWriter, r *http.Request) {
user := &User{1, "1azy_fish", "test@example.com", "*********"}
r.ParseForm()
tpl := `<h1>Hi, {{ .Name }}</h1><br>Your Email is {{ . }}`
data := map[string]string{"Name": user.Name, "Email": user.Email}
html := template.Must(template.New("login").Parse(tpl))
html.Execute(w, data)
}

func main() {
server := http.Server{Addr: "127.0.0.1:8888"}
http.HandleFunc("/string", StringTpl2Exam)
server.ListenAndServe()
}

在上述示例中,模板中的动态内容{{ . }}会将整个数据对象打印出来,这样就可以检测是否存在SSTI漏洞。

访问得到

  • 不太懂Golang之后再学一学