题目
绕过下列过滤函数
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"strings"
)
func SanCheck(input string) error {
u, err := url.Parse(input)
if err != nil {
return err
}
if u.Scheme != "http" {
return fmt.Errorf("err: Invalid Scheme [%s]", u.Scheme)
}
if u.Opaque != "" {
return fmt.Errorf("err: WHAT AER YOU DOING ?!!! (%s)", u.Opaque)
}
if u.Hostname() != "127.0.0.1" {
return fmt.Errorf("err: Invalid Hostname [%s]", u.Hostname())
}
if u.Port() != "" && u.Port() != "80" {
return fmt.Errorf("err: Invalid Port [%s]", u.Port())
}
if u.User == nil {
return fmt.Errorf("err: Authorization Required")
}
if u.User.Username() != "root" {
return fmt.Errorf("err: Invalid Username [%s]", u.User.Username())
}
if password, set := u.User.Password(); !set || password != "P@ssw0rd!" {
return fmt.Errorf("err: Invalid Password [%s]", password)
}
if u.RequestURI() != "/flag.php" {
return fmt.Errorf("err: Invalid RequestURI [%s]", u.RequestURI())
}
if u.Fragment != "" {
return fmt.Errorf("err: Invalid Fragment [%s]", u.Fragment)
}
if !strings.Contains(u.String(), "'Pwned!'") {
fmt.Println(u.String())
return fmt.Errorf("err: San Check failed" + u.String())
}
return nil
}
解决方法
考虑应该是net/url
库可能存在问题,搜一下CVE,发现有CVE-2019-14809是说Host字段有解析错误,看到下面还有GitHub的issues,反映下列URI解析出来的Host都是google.com
javascript://%250aalert(1)+'[email protected]/a'a
http://[google.com]:80
http://google.com]:80
http://google.com]:80__Anything_you'd_like_sir
http://[google.com]FreeTextZoneHere]:80
这里联系之前Apache中常见的多个参数导致解析错误的洞,尝试加入两个用中括号包裹的host,发现就可以绕过:
http://root:P@ssw0rd!@[127.0.0.1]['Pwned!']:80/flag.php
当然这个洞在最新版本的Go语言中已经修复了,可以下载 1.11.13 和1.12.8以前的版本复现:P