Go代码审计学习(一)

时间:2022-12-18 12:03:42

网上有关Go的代码审计好少哇,能找到的文章也不多,害,没办法也得学

Vulnerability-goapp

建议用docker启动靶机,靶机漏洞都很简单的,很明显一眼就能找到

完全是为了设计漏洞而设计漏洞,来分析一下

https://github.com/Hardw01f/Vulnerability-goapp

docker-compose up

/assets/

就是一个静态文本目录页面

	http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/"))))

Go代码审计学习(一)

/ 根目录

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的条件了
}

Go代码审计学习(一)

/login

登录页,就是一些检查,成功就返回 /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)
	}

/new

注册页,这里其实是可以在跳转 /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拿第一个同名的值,也就是不能覆盖

Go代码审计学习(一)
Go代码审计学习(一)

/top

同样是从 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>

Go代码审计学习(一)

/profile

后台同样是存在多处的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)

Go代码审计学习(一)

Go代码审计学习(一)
Go代码审计学习(一)

/profile/edit/upload

任意文件上传,和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()

/post /timeline

一个留言板,存储型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)

Go代码审计学习(一)

/timeline/searchpost

存在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)#

Go代码审计学习(一)

/adminconfirm /adminlogin /adminusers

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

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)