Go 代码审计高危漏洞(sqli\cmd\ssrf)

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()等方式将字符串连接到一起。

简单就是先拼接,后查询都有问题

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注入的修复主要有两种场景:

  1. 常规value的拼接;
  2. 表/列名的拼接。

原因可以看之前的文章,简单来说就是如果预编译会导致列名失效

折叠代码和发包

routers/api/unAuth/sql.go

db.Order(xxxx).First(&user)

对于列名的修复,稳妥的是白名单

validCols := map[string]bool{
    
    "col1": true, "col2":true}

if _, ok := validCols[xxxx]; !ok {
    
    
fmt.Println("illegal column")
return
}
db.Order(xxxx)
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)))

白名单修复后

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

    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,
   })
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

// 参数绑定拼接

type MyMsg struct {
    
    
Domain   string `json:"domain"`
Password string `json:"password"`
}


// ---> 声明结构体变量
var a MyMsg
// ---> 绑定数据
if 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() // python -c is also vulnerable
println(output)
c.JSON(200, gin.H{
    
    
"success": output,
})
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",但是只是受限制,不能完全修复
建议直接写死,白名单
或者是这种模式

func safe(c *gin.Context) {
    
    
	cmd := c.Query("cmd")
	a := exec.Command("ls", cmd)
}

0x03 SSRF

SSRF攻击通常会导致组织内未经授权的操作或对数据的访问,
在某些情况下,SSRF漏洞可能允许攻击者执行任意命令执行。

折叠代码和发包

常见函数

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

        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),
   })
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

简单白修复

    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),
   })
}
[GIN] 2022/10/22 - 22:44:28 | 500 |   946.54142ms |       127.0.0.1 | POST     /api/safe/ssrf
Get "https://test.image.com/path/?q=@http://www.badiu.com/": x509: certificate is not valid for any names, but wanted to match test.image.com
get image failed

当然这个修复过于简单了,后面看一下成熟的修复方案

猜你喜欢

转载自blog.csdn.net/god_zzZ/article/details/127599659
go