网上有关Go的代码审计好少哇,能找到的文章也不多,害,没办法也得学
建议用docker启动靶机,靶机漏洞都很简单的,很明显一眼就能找到
完全是为了设计漏洞而设计漏洞,来分析一下
https://github.com/Hardw01f/Vulnerability-goapp
docker-compose up
就是一个静态文本目录页面
http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/"))))
func sayYourName(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
fmt.Println(r.Form)
fmt.Println("path", r.URL.Path)
fmt.Println("scheme", r.URL.Scheme)
fmt.Println("r.Form", r.Form)
fmt.Println("r.Form[name]", r.Form["name"])
var Name string
for k, v := range r.Form {
fmt.Println("key:", k)
Name = strings.Join(v, ",")
}
fmt.Println(Name)
fmt.Fprintf(w, Name)
// 解析表单内容,不做任何处理就直接返回
// 所以这里就满足反射型xss的条件了
}
登录页,就是一些检查,成功就返回 /top
if r.Method == "GET" {
if cookie.CheckSessionID(r) {
http.Redirect(w, r, "/top", 302)
} else {
t, _ := template.ParseFiles("./views/public/login.gtpl")
}
} else if r.Method == "POST" {
if isZeroString(r.FormValue("mail")) && isZeroString(r.FormValue("passwd")) {
if id != 0 { // id存在
if name != "" { // name存在
} else { // name不存在
t, _ := template.ParseFiles("./views/public/error.gtpl")
}
} else { // id 不存在
t, _ := template.ParseFiles("./views/public/error.gtpl")
}
} else { // passwd mail为空
fmt.Println("username or passwd are empty")
outErrorPage(w)
}
} else {
http.NotFound(w, nil)
}
注册页,这里其实是可以在跳转 /top的时候可以 xss
if CheckUserDeplicate(r.FormValue("mail")) {
if RegisterUser(r) {
http.SetCookie(w, cookieSID)
http.SetCookie(w, cookieUserName)
p := Person{UserName: name}
t, _ := template.ParseFiles("./views/public/success_register.gtpl")
t.Execute(w, p)
}
_, err = db.Exec("insert into user (name,mail,age,passwd) value(?,?,?,?)", r.FormValue("name"), r.FormValue("mail"), age, r.FormValue("passwd"))
// r.FormValue 和 r.Form 的区别就是 FormValue拿第一个同名的值,也就是不能覆盖
同样是从 cookie中拿到 userName,然后没做任何处理的返回
userName, sessionID, userID, err := cookie.GetUserIDFromCookie(r)
if sessionID == "" {
t, _ := template.ParseFiles("./views/public/error.gtpl")
} else {
if r.Method == "GET" {
if userID != 0 {
http.SetCookie(w, cookieUserID)
http.SetCookie(w, deleAdminID)
p := Person{UserName: userName}
t, _ := template.ParseFiles("./views/public/top.gtpl")
t.Execute(w, p)
}
<ul id="nav">
<li><div class="username">{{.UserName}}</div></li>
<li><a href="/top">Home</a></li>
<li><a href="/profile">Profile</a></li>
<li><a href="/timeline">TimeLine</a></li>
<li><a href="/post">Post</a></li>
<li><a href="/hints">Hints</a></li>
<li><a href="/db">DB</a></li>
<li><a href="/logout">Logout</a></li>
<ul>
后台同样是存在多处的xss,原因同 /top,没做任何处理拿到 userName直接返回
这里还存在存储xss,同样是没做任何处理就存数据库,读也是一样
_, err = db.Exec("update vulnapp.userdetails set address = ?, animal = ?, word = ? where uid = ?", address, animal, word, uid)
var userImage, address, animal, word string
res, err := db.Query("select userImage,address,animal,word from vulnapp.userdetails where uid=?", uid)
任意文件上传,和php利用方式不同,没有像一句话马这种东西,而且访问也是通过路由访问,而不是文件路径
这里也没对文件名检测,所以可以任意位置上传文件,但是好像没啥用,权限给的0666,没有执行权限
file, handler, err := r.FormFile("uploadfile")
defer file.Close()
f, err := os.OpenFile("./assets/img/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
defer f.Close()
一个留言板,存储型xss,同样是直接就可以叉
postText := r.FormValue("post")
fmt.Println(reflect.TypeOf(postText))
StorePost(uid, postText)
http.Redirect(w, r, "/post", 301)
_, err = db.Exec("insert into vulnapp.posts(uid,post) values (?,?)", uid, postText)
存在SQL注入
testStr := "mysql -h mysql -u root -prootwolf -e 'select post,created_at from vulnapp.posts where post like \"%" + searchWord + "%\"'"
// 直接闭合掉 %" 就行
// paidx0%" and if(2>1,sleep(3),1)#
SQL注入,闭合就行,同上
commandLine := "mysql -h mysql -u root -prootwolf -e 'select adminsid from vulnapp.adminsessions where adminsessionid=\"" + adminSessionCookie + "\";'"
cmd := "mysql -h mysql -u root -prootwolf -e 'select adminid from vulnapp.admins where mail=\"" + requestMail + "\" and passwd=\"" + requestPasswd + "\";'"
cmd := "mysql -h mysql -u root -prootwolf -e 'select id,name,mail,age,created_at,updated_at from vulnapp.user where name not in (\"" + userName.Value + "\");'"
csrf基本都是,因为都没有对数据提交来源做检测,只有修改确认密码这里做了检测
也就是说我们可以用burpsuit生成一个csrf的临时假服务器去伪造用户执行命令
func ConfirmPasswdChange(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
if cookie.CheckSessionID(r) {
if r.Referer() == "http://localhost:9090/profile/changepasswd" {
_, _, uid, err := cookie.GetCookieValue(r)
if err != nil {
fmt.Printf("%+v\n", err)
}
newPasswd := r.FormValue("passwd")
confirmPassword := r.FormValue("confirm")
fmt.Println(newPasswd, confirmPassword, uid)