0x01 Go 代码审计高危漏洞 一个go写的WEB漏洞靶场,实际自己写一下,加固一下知识
https://github.com/godzeo/go-gin-vul
GIN框架 整个web框架是go-gin-Example 上面改的,没有前端框架,只有一个swagger,直接发包吧
0x02 Vulnerability code analysis and fix 漏洞代码解析和修复 0x01 sqli 实际中最常见的一种编码问题 Order by 之后存在列和表的的时候,一般采用拼接的情况出现sql注入
由于表/列名无法使用参数化查询,所以推荐使用白名单或转义操作
0x011 常见错误拼接 主要是运用 fmt.Sprintf()、buffer.WriteString()等方式将字符串连接到一起。
简单就是先拼接,后查询都有问题
1 2 3 4 5 6 7 db.Select(xxx).First(&user) db.Where(fmt.Sprintf("name = '%s'", xxx)).Find(&user) db.Raw("select name from " + xxx).First(&user) db.Exec("select name from " + xxx).First(&user)
0x012 业务中常见一定要拼接的地方 对于开发者来讲,SQL注入的修复主要有两种场景:
常规value的拼接;
表/列名的拼接。
原因可以看之前的文章,简单来说就是如果预编译会导致列名失效
折叠代码和发包
routers/api/unAuth/sql.go
1 db.Order(xxxx).First(&user)
对于列名的修复,稳妥的是白名单
1 2 3 4 5 6 7 validCols := map [string ]bool {"col1" : true , "col2" :true } if _, ok := validCols[xxxx]; !ok {fmt.Println("illegal column" ) return } db.Order(xxxx)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 POST /sql/login HTTP/1.1 Host: 127.0.0.1:8000 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:103.0) Gecko/20100101 Firefox/103.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1 Content-Type: application/x-www-form-urlencoded Content-Length: 106 user=user&password=123456 AND EXTRACTVALUE(9509,CONCAT(0x5c,(SELECT user from blog.blog_login LIMIT 0,1)))
白名单修复后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 POST /sql/loginSafe HTTP/1.1 Host: 127.0.0.1:8000 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:103.0) Gecko/20100101 Firefox/103.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1 Content-Type: application/x-www-form-urlencoded Content-Length: 106 user=user&password=123456 AND EXTRACTVALUE(9509,CONCAT(0x5c,(SELECT user from blog.blog_login LIMIT 0,1)))
Command execution 当使用exec等功能系统调用 应该使用白名单来限制的范围可执行命令。 不使用bash, sh
折叠代码和发包
直接拼接
routers/api/unAuth/cmd.go
1 2 3 4 5 6 7 8 9 10 ipaddr := c.PostForm("ip" ) Command := fmt.Sprintf("ping -c 4 %s" , ipaddr) output, err := exec.Command("/bin/sh" , "-c" , Command).Output() if err != nil { fmt.Println(err) return } c.JSON(200 , gin.H{ "success" : output, })
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 POST /api/vul/cmd HTTP/1.1 Host: 127.0.0.1:8000 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:103.0) Gecko/20100101 Firefox/103.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1 Content-Type: application/x-www-form-urlencoded Content-Length: 23 ip=127.0.0.1 | echo zeo
// 参数绑定拼接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 type MyMsg struct {Domain string `json:"domain"` Password string `json:"password"` } var a MyMsgif err := c.ShouldBindJSON(&a); err != nil {c.AbortWithStatusJSON( http.StatusInternalServerError, gin.H{"error" : err.Error()}) return } output, _ := exec.Command("/bin/bash" , "-c" , "dig " +a.Domain).CombinedOutput() println (output)c.JSON(200 , gin.H{ "success" : output,})
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 POST /api/vul/cmd2 HTTP/1.1 Host: 127.0.0.1:8000 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:103.0) Gecko/20100101 Firefox/103.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1 Content-Type: application/json Content-Length: 64 { "domain":"baidu.com | whoami", "password":"pssss" }
修复: 不使用"bash", "-c"
,但是只是受限制,不能完全修复 建议直接写死,白名单 或者是这种模式
1 2 3 4 func safe (c *gin.Context) { cmd := c.Query("cmd" ) a := exec.Command("ls" , cmd) }
0x03 SSRF SSRF攻击通常会导致组织内未经授权的操作或对数据的访问, 在某些情况下,SSRF漏洞可能允许攻击者执行任意命令执行。
折叠代码和发包
常见函数
1 2 3 4 5 http.Get(url) http.Post(url, contentType, body) http.Head(url) http.PostForm(url, data) http.NewRequest(method, url, body)
Full echo SSRF routers/api/unAuth/ssrf.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 url := c.PostForm("q" ) res, err := http.Get(url) if err != nil { fmt.Println(err) fmt.Println("get image failed" ) } body, err := ioutil.ReadAll(res.Body) defer res.Body.Close()if err != nil { log.Fatalln(err) } log.Println(string (body)) c.JSON(200 , gin.H{ "success" : string (body), })
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 POST /api/vul/ssrf HTTP/1.1 Host: 127.0.0.1:8000 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:103.0) Gecko/20100101 Firefox/103.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1 Content-Type: application/x-www-form-urlencoded Content-Length: 33 q=http://www.badiu.com/robots.txt
简单白修复
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func GetImageSafe (c *gin.Context) { q := c.PostForm("q" ) url := "https://test.image.com/path/?q=" res, err := http.Get(url + q) if err != nil { fmt.Println(err) fmt.Println("get image failed" ) } body, err := ioutil.ReadAll(res.Body) defer res.Body.Close() if err != nil { log.Fatalln(err) } log.Println(string (body)) c.JSON(200 , gin.H{ "success" : string (body), }) }
1 2 3 4 [GIN] 2022 /10 /22 - 22 :44 :28 | 500 | 946.54142 ms | 127.0 .0 .1 | POST /api/safe/ssrf Get "https://test.image.com/path/[email protected] ://www.badiu.com/" : x509: certificate is not valid for any names, but wanted to match test.image.com get image failed
当然这个修复过于简单了,后面看一下成熟的修复方案