Skip to content

Instantly share code, notes, and snippets.

@yujitounai
Last active August 7, 2019 01:50
Show Gist options
  • Save yujitounai/f30e0ce2ece7bcdf64647cd469d2bc1a to your computer and use it in GitHub Desktop.
Save yujitounai/f30e0ce2ece7bcdf64647cd469d2bc1a to your computer and use it in GitHub Desktop.
test1

golangの脆弱性パターン作成

概要とか

go+mysqlでつくるREST API

戦略としてはまずは個別に作成->まとめるかも

SQLインジェクション(文字列ベース)/keibatest

概略

APIの名前部分が脆弱な文字列ベースのSQLインジェクション

攻撃URL

http://192.168.5.4:8081/horse/%E3%82%B5%E3%83%B3%E3%83%87%E3%83%BC%E3%82%B5%E3%82%A4%E3%83%AC%E3%83%B3%E3%82%B9'%20union%20select%20length(user())--%20

脆弱なコード

  • route
a.Router.HandleFunc("/horse/{search}", a.searchHorse).Methods("GET")
  • SQL
statement := fmt.Sprintf("SELECT `id` FROM `horses` WHERE `name`='%s'", search)
rows, err := db.Query(statement)

安全なコード

statement := "SELECT `id` FROM `horses` WHERE `name`=?"
rows, err := db.Query(statement, search)

XSS

概略

出力をただエスケープしてない

攻撃方法

http://192.168.5.4:8083/ にアクセスしてPOSTにhtmlタグを

脆弱なコード(xsstest02)

package main
import "fmt"
import "net/http"

func main() {
	//ハンドラの登録
	http.HandleFunc("/", handler)// /というパターンのパスで来たリクエストをハンドリングする関数を登録
	http.ListenAndServe(":8083", nil)//nilだとhttp.DefaultServeMux
}
//ハンドラ

func handler(
	//レスポンスを書き込む
	w http.ResponseWriter,
	//リクエスト
	r *http.Request) {
		//入力された文字列
		value_xss := r.FormValue("xss")
		form:=`<html>
<form method="post" action="">
<input type="text" size="60" name="xss" value="`+value_xss+`">
<input type="submit" value="post">
</form>
</html>
`
 		fmt.Fprint(w, form)
}

安全なコード

func noXSShandler(
	//レスポンスを書き込む
	w http.ResponseWriter,
	//リクエスト
	r *http.Request) {
		//入力された文字列
		value_xss := r.FormValue("xss")
		form:=`<html>
<form method="post" action="">
<input type="text" size="60" name="xss" value="`+html.EscapeString(value_xss)+`">
<input type="submit" value="post">
</form>
</html>
`
 		fmt.Fprint(w, form)
}

ディレクトリトラバーサル

概略

file=で内部のファイルを読むで http.FileServer()を使う http.ServeFile()を使うと割と安全だと思う http.Handle()では../../../みたいなのが入ると301になる

攻撃URL

http://192.168.5.4:8082/?file=/etc/hosts

脆弱なコード(traversal02)

package main
import (
	"fmt"
	"net/http"
	"html"
	"os"
	"bufio"
)

func main() {
	//ハンドラの登録
	http.HandleFunc("/", handler)// /というパターンのパスで来たリクエストをハンドリングする関数を登録
	http.ListenAndServe(":8084", nil)//nilだとhttp.DefaultServeMux
}
//ハンドラ

func handler(
	//レスポンスを書き込む
	w http.ResponseWriter,
	//リクエスト
	r *http.Request) {
		//入力された文字列
	value_file := r.FormValue("file")
	form1:=`<html>
<form method="get" action="">
<input type="text" size="60" name="file" value="`+html.EscapeString(value_file)+`">
<input type="submit" value="post">
</form><textarea>`

	form2:=`</textarea>
</html>
`
	fmt.Fprint(w, form1)
	if value_file!=""{
		fp, err := os.Open(value_file)
		if err != nil {
			panic(err)
		}
		scanner := bufio.NewScanner(fp)
		for scanner.Scan() {
			fmt.Fprint(w,scanner.Text())
		}
		fp.Close()
	}
	fmt.Fprint(w, form2)
}

1.5まで脆弱なコード(未確認)

package main

import (
	"net/http"
	"strings"
)
func Handler( w http.ResponseWriter, r *http.Request ) {
	if strings.HasPrefix(r.URL.Path, "/static/") {
		http.ServeFile(w, r, r.URL.Path[1:])
	} else {
		http.NotFound(w, r)
	}
}

func main() {
        http.HandleFunc("/", Handler)
        http.ListenAndServe(":8082", nil)
}

JWTのやつ(jwstest2)

概要

"typ":"none"の場合、改ざん検証がないので書き換え可能 https://blog.motikan2010.com/entry/2017/05/12/jwt-go%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B {"alg":"HS256","typ":"JWT"} を {"alg":"none","typ":"JWT} に変更できるパターンもあるらしい(golangでは無理)

攻撃方法

  1. http://192.168.5.4:8084/api/ にアクセスするとトークンが返ってくる
  2. http://192.168.5.4:8084/api/private/ にアクセスすると入力エラー
  3. 2.のリクエストヘッダに Authorization: {1.で取得したトークン} を付けて再送
$ curl -v http://192.168.5.4:8084/api/private/ -H "Authorization: eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJleHAiOjE1MzkzMjcxNzIsInVzZXIiOiJndWVzdCJ9."

ログインできて

{"message":"こんにちは、「 guest 」さん"}

が返る 4. トークンの後ろ半分をbase64デコードすると{"exp":1539327172,"user":"guest"}になる。 トークンの後ろ半分を、{"exp":1539327172,"user":"admin"}に変更してbase64エンコードした値に入れ替えて再送すると

$ curl -v http://192.168.5.4:8084/api/private/ -H "Authorization: eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJleHAiOjE1MzkzMjcxNzIsInVzZXIiOiJhZG1pbiJ9."
{"message":"こんにちは、「 admin 」さん"}

が返る

SSRF(ssrf01[http.Get],ssrf02[http.NewRequest])

概要

ローカルIPアドレス(LAN内)の外からアクセスできないはずのコンテンツが読める 標準のhttp.Get とかではhttp/https以外のスキームはフォローしてなさげ URLの内容とかはburp collaboratorを使うとよさそう(goだと基本的にURLエンコードされる)

攻撃方法

1.http://192.168.5.4:8085/?url=http%3A%2F%2F内部IPアドレス%2F 2.http://192.168.5.4:8085/img のデータは

脆弱なコード

func handler(
	//レスポンスを書き込む
	w http.ResponseWriter,
	//リクエスト
	r *http.Request) {
		//入力された文字列
	url := r.FormValue("url")
	if url !=""{
		response, err := http.Get(url)
		//基本URLエンコードされる
		if err != nil {
			panic(err)
		}
		defer response.Body.Close()

		file, err := os.Create("save.jpg")
		if err != nil {
			panic(err)
		}
		defer file.Close()
		io.Copy(file, response.Body)
	}
}

安全なコード

脆弱なコードがわりと無茶なので

RCE(見えるバージョン RCE01)

概要

exec.Commandは渡せなさげだけど exec.Command("bash", "-c", "ping -c 5 "+host)みたいなことをやってしまうとできる

攻撃方法

http://192.168.5.4:8086/rce?rce=bogus.jp%3Bls http://192.168.5.4:8086/rce?rce=bogus.jp|ls

脆弱なコード

if value_rce!=""{
	fmt.Fprint(w,"処理開始: ", time.Now().Format("15:04:05"))
	host :=html.EscapeString(value_rce)
	out, err := exec.Command("bash", "-c", "ping -c 5 "+host).CombinedOutput()
	if err != nil {
		fmt.Fprint(w,"Command Exec Error.")
	}
	fmt.Fprint(w,"\nping終了: ", string(out))
}

安全なコード

if value_rce!=""{
	fmt.Fprint(w,"処理開始: ", time.Now().Format("15:04:05"))
	host :=html.EscapeString(value_rce)
	out, err := exec.Command("ping", "-c 5", host).CombinedOutput()
	if err != nil {
		fmt.Fprint(w,"Command Exec Error.")
	}
	fmt.Fprint(w,"\nping終了: ", string(out))
}

見えないバージョン

攻撃方法

http://192.168.5.4:8086/rce?rce=bogus.jp|sleep%2010

オープンリダイレクト

概要

301ヘッダを書いてw.WriteHeader()するか http.Redirect()するところ

%0dと%0aはスペースに変換される

攻撃方法

http://192.168.5.4:8087/rd?redirect=http://bogus.jp http://192.168.5.4:8087/hrd?redirect=http://bogus.jp

脆弱なコード

package main

import (
    "net/http"
)

func headerRedirectHandler(w http.ResponseWriter, r *http.Request) {
	value_redirect := r.FormValue("redirect")
	if value_redirect!=""{
		w.Header().Set("Content-Type", "text/html")
		w.Header().Set("location", value_redirect)
		w.WriteHeader(http.StatusMovedPermanently) // 301 Moved Permanently
	}
}
func RedirectHandler(w http.ResponseWriter, r *http.Request) {
	value_redirect := r.FormValue("redirect")
	if value_redirect!=""{
		http.Redirect(w, r, value_redirect, 301)
	}
}

func main(){
    http.HandleFunc("/hrd", headerRedirectHandler)
    http.HandleFunc("/rd", RedirectHandler)
    http.ListenAndServe(":8087", nil)
}

安全なコード

バリデーションするしかない?

CSRF

XSSで

RFI/LFI

原理的に難しそうってか普通にgopathの設定うまくやらないとローカルのファイルインクルードできないんですけど

XXE

xml.Unmarshal()は外部実体参照よまなさげ(xxe01)

serializeの問題

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment