更改错误的mitm文件

main
listomebao 8 years ago
parent 6a999726d2
commit 3d4555e1df
  1. 9
      dump.go
  2. 349
      mitm.go

@ -32,10 +32,6 @@ func httpDump(req *http.Request, resp *http.Response) {
for headerName, headerContext := range req.Header { for headerName, headerContext := range req.Header {
fmt.Printf("%s: %s\n", Blue(headerName), headerContext) fmt.Printf("%s: %s\n", Blue(headerName), headerContext)
} }
fmt.Println(Green("Response:"))
for headerName, headerContext := range resp.Header {
fmt.Printf("%s: %s\n", Blue(headerName), headerContext)
}
if req.Method == "POST" { if req.Method == "POST" {
fmt.Println(Green("URLEncoded form")) fmt.Println(Green("URLEncoded form"))
err := req.ParseForm() err := req.ParseForm()
@ -51,6 +47,11 @@ func httpDump(req *http.Request, resp *http.Response) {
} }
} }
fmt.Println(Green("Response:"))
for headerName, headerContext := range resp.Header {
fmt.Printf("%s: %s\n", Blue(headerName), headerContext)
}
respBody, err := ioutil.ReadAll(resp.Body) respBody, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
logger.Println("func httpDump read resp body err:", err) logger.Println("func httpDump read resp body err:", err)

@ -1,81 +1,342 @@
package main package main
import ( import (
"flag" "bufio"
"crypto/tls"
"errors"
"fmt"
"io"
"log" "log"
"net"
"net/http" "net/http"
"os" "net/http/httputil"
"net/url"
"regexp"
"strings"
"sync" "sync"
"time" "time"
) )
const ( type HandlerWrapper struct {
Version = "1.1" MyConfig *Cfg
) tlsConfig *TlsConfig
wrapped http.Handler
pk *PrivateKey
pkPem []byte
issuingCert *Certificate
issuingCertPem []byte
serverTLSConfig *tls.Config
dynamicCerts *Cache
certMutex sync.Mutex
https bool
}
var ( func (hw *HandlerWrapper) GenerateCertForClient() (err error) {
wg sync.WaitGroup if hw.tlsConfig.Organization == "" {
) hw.tlsConfig.Organization = "gomitmproxy" + Version
}
if hw.tlsConfig.CommonName == "" {
hw.tlsConfig.CommonName = "gomitmproxy"
}
if hw.pk, err = LoadPKFromFile(hw.tlsConfig.PrivateKeyFile); err != nil {
hw.pk, err = GeneratePK(2048)
if err != nil {
return fmt.Errorf("Unable to generate private key: %s", err)
}
hw.pk.WriteToFile(hw.tlsConfig.PrivateKeyFile)
}
hw.pkPem = hw.pk.PEMEncoded()
hw.issuingCert, err = LoadCertificateFromFile(hw.tlsConfig.CertFile)
if err != nil || hw.issuingCert.ExpiresBefore(time.Now().AddDate(0, ONE_MONTH, 0)) {
hw.issuingCert, err = hw.pk.TLSCertificateFor(
hw.tlsConfig.Organization,
hw.tlsConfig.CommonName,
time.Now().AddDate(ONE_YEAR, 0, 0),
true,
nil)
if err != nil {
return fmt.Errorf("Unable to generate self-signed issuing certificate: %s", err)
}
hw.issuingCert.WriteToFile(hw.tlsConfig.CertFile)
}
hw.issuingCertPem = hw.issuingCert.PEMEncoded()
return
}
func (hw *HandlerWrapper) FakeCertForName(name string) (cert *tls.Certificate, err error) {
kpCandidateIf, found := hw.dynamicCerts.Get(name)
if found {
return kpCandidateIf.(*tls.Certificate), nil
}
hw.certMutex.Lock()
defer hw.certMutex.Unlock()
kpCandidateIf, found = hw.dynamicCerts.Get(name)
if found {
return kpCandidateIf.(*tls.Certificate), nil
}
//create certificate
certTTL := TWO_WEEKS
generatedCert, err := hw.pk.TLSCertificateFor(
hw.tlsConfig.Organization,
name,
time.Now().Add(certTTL),
false,
hw.issuingCert)
if err != nil {
return nil, fmt.Errorf("Unable to issue certificate: %s", err)
}
keyPair, err := tls.X509KeyPair(generatedCert.PEMEncoded(), hw.pkPem)
if err != nil {
return nil, fmt.Errorf("Unable to parse keypair for tls: %s", err)
}
cacheTTL := certTTL - ONE_DAY
hw.dynamicCerts.Set(name, &keyPair, cacheTTL)
return &keyPair, nil
}
func (hw *HandlerWrapper) DumpHTTPAndHTTPs(resp http.ResponseWriter, req *http.Request) {
req.Header.Del("Proxy-Connection")
req.Header.Set("Connection", "Keep-Alive")
// handle connection
connIn, _, err := resp.(http.Hijacker).Hijack()
if err != nil {
logger.Println("hijack error:", err)
}
defer connIn.Close()
var logFile *os.File var respOut *http.Response
var logger *log.Logger host := req.Host
func main() { matched, _ := regexp.MatchString(":[0-9]+$", host)
var conf Cfg
conf.Port = flag.String("port", "8080", "Listen port") if !hw.https {
conf.Raddr = flag.String("raddr", "", "Remote addr") if !matched {
conf.Log = flag.String("log", "./error.log", "log file path") host += ":80"
conf.Monitor = flag.Bool("m", false, "monitor mode") }
conf.Tls = flag.Bool("tls", false, "tls connect")
flag.Parse()
var err error connOut, err := net.DialTimeout("tcp", host, time.Second*30)
logFile, err = os.Create(*conf.Log)
if err != nil { if err != nil {
log.Fatalln("fail to create log file!") logger.Println("dial to", host, "error:", err)
return
} }
logger = log.New(logFile, "[gomitmproxy]", log.LstdFlags|log.Llongfile) if err = req.Write(connOut); err != nil {
logger.Println("send to server error", err)
return
}
wg.Add(1) respOut, err = http.ReadResponse(bufio.NewReader(connOut), req)
gomitmproxy(&conf) if err != nil && err != io.EOF {
wg.Wait() logger.Println("read response error:", err)
}
} else {
if !matched {
host += ":443"
} }
func gomitmproxy(conf *Cfg) { connOut, err := tls.Dial("tcp", host, hw.tlsConfig.ServerTLSConfig)
tlsConfig := NewTlsConfig("gomitmproxy-ca-pk.pem", "gomitmproxy-ca-cert.pem", "", "")
handler, err := InitConfig(conf, tlsConfig)
if err != nil { if err != nil {
logger.Fatalf("InitConfig error: %s", err) logger.Panicln("tls dial to", host, "error:", err)
return
}
if err = req.Write(connOut); err != nil {
logger.Println("send to server error", err)
return
} }
server := &http.Server{ respOut, err = http.ReadResponse(bufio.NewReader(connOut), req)
Addr: ":" + *conf.Port, if err != nil && err != io.EOF {
Handler: handler, logger.Println("read response error:", err)
ReadTimeout: 1 * time.Hour,
WriteTimeout: 1 * time.Hour,
} }
go func() { }
log.Printf("proxy listening port:%s", *conf.Port)
if respOut == nil {
log.Println("respOut is nil")
return
}
respDump, err := httputil.DumpResponse(respOut, true)
if err != nil {
logger.Println("respDump error:", err)
}
_, err = connIn.Write(respDump)
if err != nil {
logger.Println("connIn write error:", err)
}
if *conf.Tls { if *hw.MyConfig.Monitor {
log.Println("ListenAndServeTLS") go httpDump(req, respOut)
err = server.ListenAndServeTLS("gomitmproxy-ca-cert.pem", "gomitmproxy-ca-pk.pem") }
}
func (hw *HandlerWrapper) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
raddr := *hw.MyConfig.Raddr
if len(raddr) != 0 {
hw.Forward(resp, req, raddr)
} else {
if req.Method == "CONNECT" {
hw.https = true
hw.InterceptHTTPs(resp, req)
} else { } else {
log.Println("ListenAndServe") hw.https = false
err = server.ListenAndServe() hw.DumpHTTPAndHTTPs(resp, req)
}
} }
}
func (hw *HandlerWrapper) InterceptHTTPs(resp http.ResponseWriter, req *http.Request) {
addr := req.Host
host := strings.Split(addr, ":")[0]
cert, err := hw.FakeCertForName(host)
if err != nil {
msg := fmt.Sprintf("Could not get mitm cert for name: %s\nerror: %s", host, err)
respBadGateway(resp, msg)
return
}
// handle connection
connIn, _, err := resp.(http.Hijacker).Hijack()
if err != nil { if err != nil {
logger.Fatalf("Unable to start HTTP proxy: %s", err) msg := fmt.Sprintf("Unable to access underlying connection from client: %s", err)
respBadGateway(resp, msg)
return
} }
tlsConfig := copyTlsConfig(hw.tlsConfig.ServerTLSConfig)
tlsConfig.Certificates = []tls.Certificate{*cert}
tlsConnIn := tls.Server(connIn, tlsConfig)
listener := &mitmListener{tlsConnIn}
handler := http.HandlerFunc(func(resp2 http.ResponseWriter, req2 *http.Request) {
req2.URL.Scheme = "https"
req2.URL.Host = req2.Host
hw.DumpHTTPAndHTTPs(resp2, req2)
wg.Done() })
log.Printf("gomitmproxy stop!!!!") go func() {
err = http.Serve(listener, handler)
if err != nil && err != io.EOF {
logger.Printf("Error serving mitm'ed connection: %s", err)
}
}() }()
connIn.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
}
func (hw *HandlerWrapper) Forward(resp http.ResponseWriter, req *http.Request, raddr string) {
connIn, _, err := resp.(http.Hijacker).Hijack()
connOut, err := net.Dial("tcp", raddr)
if err != nil {
logger.Println("dial tcp error", err)
}
err = connectProxyServer(connOut, raddr)
if err != nil {
logger.Println("connectProxyServer error:", err)
}
if req.Method == "CONNECT" {
b := []byte("HTTP/1.1 200 Connection Established\r\n" +
"Proxy-Agent: gomitmproxy/" + Version + "\r\n\r\n")
_, err := connIn.Write(b)
if err != nil {
logger.Println("Write Connect err:", err)
return
}
} else {
req.Header.Del("Proxy-Connection")
req.Header.Set("Connection", "Keep-Alive")
if err = req.Write(connOut); err != nil {
logger.Println("send to server err", err)
return return
} }
}
err = Transport(connIn, connOut)
if err != nil {
log.Println("trans error ", err)
}
}
func InitConfig(conf *Cfg, tlsConfig *TlsConfig) (*HandlerWrapper, error) {
hw := &HandlerWrapper{
MyConfig: conf,
tlsConfig: tlsConfig,
dynamicCerts: NewCache(),
}
err := hw.GenerateCertForClient()
if err != nil {
return nil, err
}
return hw, nil
}
func copyTlsConfig(template *tls.Config) *tls.Config {
tlsConfig := &tls.Config{}
if template != nil {
*tlsConfig = *template
}
return tlsConfig
}
func respBadGateway(resp http.ResponseWriter, msg string) {
log.Println(msg)
resp.WriteHeader(502)
resp.Write([]byte(msg))
}
//两个io口的连接
func Transport(conn1, conn2 net.Conn) (err error) {
rChan := make(chan error, 1)
wChan := make(chan error, 1)
go MyCopy(conn1, conn2, wChan)
go MyCopy(conn2, conn1, rChan)
select {
case err = <-wChan:
case err = <-rChan:
}
return
}
func MyCopy(src io.Reader, dst io.Writer, ch chan<- error) {
_, err := io.Copy(dst, src)
ch <- err
}
func connectProxyServer(conn net.Conn, addr string) error {
req := &http.Request{
Method: "CONNECT",
URL: &url.URL{Host: addr},
Host: addr,
ProtoMajor: 1,
ProtoMinor: 1,
Header: make(http.Header),
}
req.Header.Set("Proxy-Connection", "keep-alive")
if err := req.Write(conn); err != nil {
return err
}
resp, err := http.ReadResponse(bufio.NewReader(conn), req)
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
return errors.New(resp.Status)
}
return nil
}

Loading…
Cancel
Save