# WhoisTool
```go=
cmd := exec.Command("/bin/sh", "-c", fmt.Sprintf("whois '%s'", s.GetString("domain")))
```
```go=
func isValidDomain(domain string) bool {
return !strings.Contains(domain, "'") && !strings.Contains(domain, "\\") && !strings.HasPrefix(domain, "-")
}
```
> 這是幹嘛的阿 直接 google.com;ls; 不行嗎?
> 不行 有試過
> 因為他有 ' 包起來
> 不要用 ' 不行嗎?
> 我找不太到不用 ' 閉合他的方法
> 我來跑跑看
> 感覺甚麼神奇 shellshock 之類的
> 我一直在看 command injection 相關的 bypass 沒看到,我也來看看你說的這個東東
* 感覺不太可行,' filter 繞不掉
* `google.com;'ls;'`
* Invalid input
* `google.com;%27ls;%27`
* urlencode 不行
* Error() err: exit status 1
```go=
package main
import (
"fmt"
"log"
"net"
"net/http"
"os"
"os/exec"
"strings"
"github.com/kataras/go-sessions"
)
const (
TEMPLATE_BASE_HEAD = `<!DOCTYPE html><html lang="en"><head><title>Whois Tool</title></head><body>`
TEMPLATE_BASE_FOOT = `</body></html>`
TEMPLATE_INDEX = TEMPLATE_BASE_HEAD + `<h3>Whois Tool</h3><form method="POST" action="/set"><label for="domain">Domain: </label><input type="text" name="domain"><br /><br /><button type="submit">submit</button></form>` + TEMPLATE_BASE_FOOT
TEMPLATE_RESULT = TEMPLATE_BASE_HEAD + `<textarea cols="100" rows="30">%s</textarea><br /><br /><a href="/">Back</a>` + TEMPLATE_BASE_FOOT
TEMPLATE_ERROR = TEMPLATE_BASE_HEAD + `<h3>Error</h3><p>%s</p><br /><br /><a href="/">Back</a>` + TEMPLATE_BASE_FOOT
)
func isValidDomain(domain string) bool {
return !strings.Contains(domain, "'") && !strings.Contains(domain, "\\") && !strings.HasPrefix(domain, "-")
}
func main() {
sess := sessions.New(sessions.Config{})
f, err := os.OpenFile("query.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
panic("Can't open ./query.log")
}
log.SetOutput(f)
defer f.Close()
http.HandleFunc("/set", func (w http.ResponseWriter, req *http.Request) {
s := sess.Start(w, req)
if req.Method != http.MethodPost {
return
}
s.Set("domain", req.PostFormValue("domain"))
http.Redirect(w, req, "/result", http.StatusSeeOther)
})
http.HandleFunc("/result", func (w http.ResponseWriter, req *http.Request) {
s := sess.Start(w, req)
var html string
if (!isValidDomain(s.GetString("domain"))) {
html = fmt.Sprintf(TEMPLATE_ERROR, "Invalid input")
w.Write([]byte(html))
return
}
ip, _, _ := net.SplitHostPort(req.RemoteAddr)
log.Printf("- %s - %s\n", ip, s.GetString("domain"))
cmd := exec.Command("/bin/sh", "-c", fmt.Sprintf("whois '%s'", s.GetString("domain")))
out, err := cmd.CombinedOutput()
if err != nil {
html = fmt.Sprintf(TEMPLATE_ERROR, fmt.Sprintf("Error() err: %v", err))
} else {
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
html = fmt.Sprintf(TEMPLATE_RESULT, out)
}
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
w.Write([]byte(html))
})
http.HandleFunc("/", func (w http.ResponseWriter, req *http.Request) {
s := sess.Start(w, req)
s.Clear()
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
w.Write([]byte(TEMPLATE_INDEX))
})
http.ListenAndServe(":8000", nil)
}
```
* race condition