CTF Dream, It's my Go!!!——Golang学习笔记

Wang1r Lv3

最初认识Golang,是听说B站后端是由Golang写的,于是开始对这个不是那么有名的语言产生了兴趣。

再次接触Golang,是在知乎刷到Golang是如何不受待见的 ,见证它是如何被批判为语法生硬、丑陋的语言。

如今,我决定学习一下这个陌生又熟悉的语言,用自己的经历真正完善看法。

It’s my Go!!!

一、基础语法速览

学习一门新语言的第一步是什么,当然是 hello world啦。

1
2
3
4
5
6
7
package main

import "fmt"

func main() {
fmt.Println("Hello, World!")
}

然后就该进一步认识其他方面了:

1. 变量与类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 声明与初始化
var a int = 10
b := "Hello, Go!" // 类型推断
const PI = 3.14

//多变量声明
var (
vname1 v_type1
vname2 v_type2
)// 这种因式分解关键字的写法一般用于声明全局变量

// 复合类型
arr := [3]int{1, 2, 3} // 数组(值类型)
slice := []int{1, 2, 3} // 切片(引用类型)
m := map[string]int{"key": 42} // Map

2. 控制结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 循环(只有 for)
for i := 0; i < 5; i++ { /*...*/ }
for index, value := range slice { /*...*/ }

// 条件判断
if x := getValue(); x > 0 {
// x 作用域仅在 if 内
} else if x == 0 {
// ...
}

// Switch(无 break)
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("macOS")
default:
fmt.Println(os)
}

3. 函数定义与使用

基本函数声明

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
// 无参数、无返回值
func sayHello() {
fmt.Println("Hello!")
}

// 带参数和返回值
func add(a int, b int) int {
return a + b
}

// 多返回值(常用作错误处理)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}

// 命名返回值(result变量已声明)
func sum(nums ...int) (result int) { // 可变参数
for _, v := range nums {
result += v
}
return // 隐式返回result
}

匿名函数与闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 立即执行函数
func() {
fmt.Println("立即执行!")
}()

// 闭包捕获外部变量
func counter() func() int {
i := 0
return func() int {
i++
return i
}
}

// 使用闭包
c := counter()
fmt.Println(c()) // 1
fmt.Println(c()) // 2

函数作为参数/返回值

1
2
3
4
5
6
7
8
9
10
11
12
// 函数类型定义
type MathFunc func(int, int) int

// 高阶函数
func calculate(a, b int, op MathFunc) int {
return op(a, b)
}

// 使用示例
result := calculate(3, 4, func(x, y int) int {
return x * y
})

defer 关键字

1
2
3
4
5
6
7
8
9
10
11
12
func fileOperation() {
file, _ := os.Open("test.txt")
defer file.Close() // 函数返回前执行

// 多个defer按LIFO顺序执行
defer fmt.Println("First defer")
defer fmt.Println("Second defer")

// 输出顺序:
// Second defer
// First defer
}

二、核心特性深入

1. 并发模型:Goroutine & Channel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 协程启动(轻量级线程)
go func() {
fmt.Println("Async task")
}()

// Channel 通信(带缓冲/无缓冲)
ch := make(chan int, 2) // 缓冲大小为2
ch <- 42 // 发送数据
value := <-ch // 接收数据

// Select 多路复用
select {
case msg := <-ch1:
fmt.Println(msg)
case ch2 <- 100:
// 发送成功
default:
// 非阻塞操作
}

2. 接口与多态

1
2
3
4
5
6
7
8
9
10
11
12
13
type Writer interface {
Write([]byte) (int, error)
}

// 结构体隐式实现接口
type FileWriter struct{}

func (fw FileWriter) Write(data []byte) (int, error) {
return len(data), nil
}

// 空接口(任意类型)
var anyType interface{} = "This can be anything"

3. 错误处理

1
2
3
4
5
6
7
8
9
10
11
12
13
// 错误值优先返回
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}

// 错误处理(推荐显式检查)
result, err := divide(10, 0)
if err != nil {
log.Fatal(err)
}

三、感想

学了一段时间,感觉Golang的确是简洁高效的语言,不追求过多特性,或许会导致代码中有不少重复与冗余,但也能让代码功能更加清晰。学习难度不算很高,很适合新手入门。

四、Golang与CTF

CTFer的自我修养,当然是把所有刚学到的东西出成题啦[doge]

1.Golang与XSS

Golang的模板渲染可以做到对数据的动态展示,但如果处理不当,就可能会引发XSS漏洞。在Golang中,标准库html/templatetext/template都可以用于模板渲染,不过html/template会对输出进行自动转义,这在很大程度上能防止XSS攻击,而text/template则不会进行转义。

所以,我们就可以利用text/template实现简单的XSS:

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 (
"text/template"
"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
input := r.URL.Query().Get("input")
tmpl := `
<!DOCTYPE html>
<html>
<head>
<title>Text Template Example</title>
</head>
<body>
<p>You entered: {{.}}</p>
</body>
</html>
`
t := template.Must(template.New("example").Parse(tmpl))
t.Execute(w, input)
}

func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}

2.Golang与SSTI

Go 的 SSTI 漏洞主要源于以下两种情况:

  1. 模板拼接风险:将用户输入直接拼接到模板字符串或模板结构中,导致敏感信息泄露或代码注入。
  2. 对象方法滥用:模板引擎允许调用对象的方法,如果这些方法存在危险操作(如文件读取、命令执行等),可能会被恶意利用。

不过相比于jinja2,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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package main

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

type User struct {
Id int
Name string
Email string
Age int
Admin bool
Notes string
Secret string
}

func main() {
http.HandleFunc("/template", func(w http.ResponseWriter, r *http.Request) {
user := &User{
Id: 1,
Name: "wang1r",
Email: "wang1r@example.com",
Age: 25,
Admin: true,
Notes: "This is a test user",
Secret: "flag{Go_for_fun}",
}

r.ParseForm()
arg := strings.Join(r.Form["input"], "")
tplString := fmt.Sprintf(`<h1>Hello, ` + arg + `</h1>` + `Your email is: {{ .Email }}`)

tpl, _ := template.New("template").Parse(tplString)
tpl.Execute(w, user)
})

fmt.Println("Server running on :8080")
http.ListenAndServe(":8080", nil)
}

在这段代码中,由于字符拼接,用户可以通过类似{{.Secret}}的输入得到敏感信息

  • 标题: CTF Dream, It's my Go!!!——Golang学习笔记
  • 作者: Wang1r
  • 创建于 : 2025-02-15 16:24:00
  • 更新于 : 2025-04-07 12:35:04
  • 链接: https://wang1rrr.github.io/2025/02/15/CTF Dream,It's my Go!!!——Golang学习笔记/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。