CTF Dream, It's my Go!!!——Golang学习笔记
最初认识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}
|
2. 控制结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| for i := 0; i < 5; i++ { } for index, value := range slice { }
if x := getValue(); x > 0 { } else if x == 0 { }
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 }
func sum(nums ...int) (result int) { for _, v := range nums { result += v } return }
|
匿名函数与闭包
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()) fmt.Println(c())
|
函数作为参数/返回值
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 fmt.Println("First defer") defer fmt.Println("Second 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") }()
ch := make(chan int, 2) ch <- 42 value := <-ch
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/template
和text/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 漏洞主要源于以下两种情况:
- 模板拼接风险:将用户输入直接拼接到模板字符串或模板结构中,导致敏感信息泄露或代码注入。
- 对象方法滥用:模板引擎允许调用对象的方法,如果这些方法存在危险操作(如文件读取、命令执行等),可能会被恶意利用。
不过相比于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}}
的输入得到敏感信息