Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cmd/blazehttp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var (
timeout = 1000 // default 1000 ms
c = 10 // default 10 concurrent workers
mHost string // modify host header
proxy string // proxy address, example: http://127.0.0.1:8083
requestPerSession bool // send request per session
)

Expand All @@ -40,6 +41,7 @@ func init() {
flag.StringVar(&glob, "g", "", "glob expression, example: *.http")
flag.IntVar(&timeout, "timeout", 1000, "connection timeout, default 1000 ms")
flag.StringVar(&mHost, "H", "", "modify host header")
flag.StringVar(&proxy, "proxy", "", "proxy address, example: http://127.0.0.1:8083")
flag.BoolVar(&requestPerSession, "rps", true, "send request per session")
flag.Parse()
if url, err := url.Parse(target); err != nil || url.Scheme == "" || url.Host == "" {
Expand Down Expand Up @@ -122,6 +124,7 @@ func main() {
worker.WithReqPerSession(requestPerSession),
worker.WithTimeout(timeout),
worker.WithUseEmbedFS(glob == ""), // use embed test case fs when glob is empty
worker.WithProxy(proxy),
worker.WithProgressBar(progressBar),
)
c := make(chan os.Signal, 1)
Expand Down
9 changes: 7 additions & 2 deletions gui/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,15 @@ func MakeRunForm(w fyne.Window, outputCh chan string, resultCh chan *worker.Resu
statusCode.SetText("403")
statusCode.Validator = validation.NewRegexp(`^\d+$`, "StatusCode必须是数字")

// 代理地址
proxy := widget.NewEntry()

advanceForm := &widget.Form{
Items: []*widget.FormItem{
{Text: "修改请求(Host)", Widget: reqHost, HintText: ""},
{Text: "请求超时", Widget: timeout, HintText: ""},
{Text: "拦截状态码(respCode)", Widget: statusCode, HintText: "一般情况下WAF拦截状态码为403"},
{Text: "代理地址", Widget: proxy, HintText: "例如: http://127.0.0.1:8080"},
},
}

Expand Down Expand Up @@ -307,7 +311,7 @@ func MakeRunForm(w fyne.Window, outputCh chan string, resultCh chan *worker.Resu
statusCode := strings.TrimSpace(statusCode.Text)
statusCodeI, _ := strconv.Atoi(statusCode)

err := run(target.Text, reqHost.Text, worksNum, statusCodeI, resultCh, stopCh)
err := run(target.Text, reqHost.Text, proxy.Text, worksNum, statusCodeI, resultCh, stopCh)
if err != nil {
outputCh <- err.Error()
}
Expand Down Expand Up @@ -460,7 +464,7 @@ func MakeTestCaseTab(w fyne.Window) fyne.CanvasObject {
return container.NewBorder(tableFilterForm, nil, nil, exportBtn, table)
}

func run(target, mHost string, c, statusCode int, resultCh chan *worker.Result, stopCh chan struct{}) error {
func run(target, mHost, proxy string, c, statusCode int, resultCh chan *worker.Result, stopCh chan struct{}) error {
var addr string
var isHttps bool

Expand Down Expand Up @@ -491,6 +495,7 @@ func run(target, mHost string, c, statusCode int, resultCh chan *worker.Result,
worker.WithConcurrence(c),
worker.WithReqHost(mHost),
worker.WithUseEmbedFS(true), // use embed test case fs when glob is empty
worker.WithProxy(proxy),
worker.WithResultCh(resultCh),
)
go func() {
Expand Down
113 changes: 102 additions & 11 deletions http/connect.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,92 @@
package http

import (
"bufio"
"crypto/tls"
"encoding/base64"
"fmt"
"net"
"net/url"
"regexp"
"time"

"golang.org/x/net/proxy"
)

func Connect(addr string, isHttps bool, timeout int) *net.Conn {
var n net.Conn
var err error
func dialProxy(addr, proxyString string, dialer *net.Dialer) (conn net.Conn, err error) {

proxyUrl, err := url.Parse(proxyString)
if err != nil {
return nil, err
}
if proxyUrl.Scheme == "socks5" {
var auth *proxy.Auth = nil;
if proxyUrl.User != nil {
username := proxyUrl.User.Username()
password, _ := proxyUrl.User.Password()
auth = &proxy.Auth{
User: username,
Password: password,
}
}
dialer, err := proxy.SOCKS5("tcp", proxyUrl.Host, auth, dialer)
if err != nil {
return nil, err
}
conn, err = dialer.Dial("tcp", addr)
if err != nil {
return nil, err
}
} else if proxyUrl.Scheme == "http" {
conn, err = dialer.Dial("tcp", proxyUrl.Host)
if err != nil {
return nil, err
}
request := fmt.Sprintf("CONNECT %s HTTP/1.1\r\nHost: %s\r\n", addr, addr)
if proxyUrl.User != nil {
username := proxyUrl.User.Username()
password, _ := proxyUrl.User.Password()
auth := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
request += "Proxy-Authorization: Basic " + auth + "\r\n"
}
request += "\r\n"
_, err = fmt.Fprint(conn, request)
if err != nil {
conn.Close()
return nil, err
}

reader := bufio.NewReader(conn)

line, err := reader.ReadString('\n')
if err != nil {
return nil, err
}
if m, err := regexp.MatchString("HTTP/[\\d\\.]+ 200 Connection established", line); !m {
conn.Close()
return nil, fmt.Errorf("CONNECT请求失败: %s %s", line, err)
}

for {
line, err := reader.ReadString('\n')
if err != nil {
conn.Close()
return nil, fmt.Errorf("读取CONNECT响应头失败: %v", err)
}
if line == "\r\n" {
break
}
}
} else {
return nil, fmt.Errorf("不支持的代理类型: " + proxyUrl.Scheme)
}
if err != nil {
return nil, fmt.Errorf("连接失败: %v", err)
}
return conn, nil
}

func Connect(addr string, proxyString string, isHttps bool, timeout int) (conn net.Conn, err error) {
if m, _ := regexp.MatchString(`.*(]:)|(:)[0-9]+$`, addr); !m {
if isHttps {
addr = fmt.Sprintf("%s:443", addr)
Expand All @@ -20,25 +96,40 @@ func Connect(addr string, isHttps bool, timeout int) *net.Conn {
}
retryCnt := 0
retry:
if isHttps {
n, err = tls.Dial("tcp", addr, &tls.Config{InsecureSkipVerify: true})
dialer := net.Dialer{
Timeout: time.Duration(timeout) * time.Millisecond * 2,
}
if proxyString != "" {
conn, err = dialProxy(addr, proxyString, &dialer)
} else {
n, err = net.Dial("tcp", addr)
conn, err = dialer.Dial("tcp", addr)
}
if err != nil {
retryCnt++
if retryCnt < 4 {
goto retry
} else {
return nil
return nil, err
}
}
if isHttps {
tlsConn := tls.Client(conn, &tls.Config{InsecureSkipVerify: true})
if err := tlsConn.Handshake(); err != nil {
retryCnt++
if retryCnt < 4 {
goto retry
} else {
return nil, err
}
}
conn = tlsConn
}
wDeadline := time.Now().Add(time.Duration(timeout) * time.Millisecond)
rDeadline := time.Now().Add(time.Duration(timeout*2) * time.Millisecond)
deadline := time.Now().Add(time.Duration(timeout*2) * time.Millisecond)
_ = n.SetDeadline(deadline)
_ = n.SetReadDeadline(rDeadline)
_ = n.SetWriteDeadline(wDeadline)
_ = conn.SetDeadline(deadline)
_ = conn.SetReadDeadline(rDeadline)
_ = conn.SetWriteDeadline(wDeadline)

return &n
return conn, nil
}
20 changes: 14 additions & 6 deletions worker/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,20 @@ type Worker struct {
reqHost string // request host of header
reqPerSession bool // request per session
useEmbedFS bool
proxy string
resultCh chan *Result
}

type WorkerOption func(*Worker)

func WithProxy(proxy string) WorkerOption {
return func(w *Worker) {
w.proxy = proxy
}
}

func WithTimeout(timeout int) WorkerOption {

return func(w *Worker) {
w.timeout = timeout
}
Expand Down Expand Up @@ -213,24 +221,24 @@ func (w *Worker) runWorker() {
req.CalculateContentLength()

start := time.Now()
conn := blazehttp.Connect(w.addr, w.isHttps, w.timeout)
if conn == nil {
job.Result.Err = fmt.Sprintf("connect to %s failed!\n", w.addr)
conn, err := blazehttp.Connect(w.addr, w.proxy, w.isHttps, w.timeout)
if err != nil {
job.Result.Err = fmt.Sprintf("connect to %s failed!\n", err)
return
}
nWrite, err := req.WriteTo(*conn)
defer conn.Close()
nWrite, err := req.WriteTo(conn)
if err != nil {
job.Result.Err = fmt.Sprintf("send request poc: %s length: %d error: %s", filePath, nWrite, err)
return
}

rsp := new(blazehttp.Response)
if err = rsp.ReadConn(*conn); err != nil {
if err = rsp.ReadConn(conn); err != nil {
job.Result.Err = fmt.Sprintf("read poc file: %s response, error: %s", filePath, err)
return
}
elap := time.Since(start).Nanoseconds()
(*conn).Close()
job.Result.Success = true
if strings.HasSuffix(job.FilePath, "white") {
job.Result.IsWhite = true // white case
Expand Down