Skip to content

Instantly share code, notes, and snippets.

@furusiyya
Forked from horsley/ocserv_hack.go
Last active January 18, 2020 13:22
Show Gist options
  • Save furusiyya/7cd4e7aa830620d1135c27aba5d3b4da to your computer and use it in GitHub Desktop.
Save furusiyya/7cd4e7aa830620d1135c27aba5d3b4da to your computer and use it in GitHub Desktop.
ocserv auth hacking
// ocservFront project main.go
package main
import (
"bufio"
"bytes"
"crypto/tls"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"os"
"regexp"
"strings"
)
const authFormOld = `<?xml version="1.0" encoding="UTF-8"?>
<config-auth client="vpn" type="auth-request">
<version who="sg">0.1(1)</version>
<auth id="main">
<message>Please enter your username</message>
<form method="post" action="/auth">
<input type="text" name="username" label="Username:" />
</form></auth>
</config-auth>`
const authFormNew = `<?xml version="1.0" encoding="UTF-8"?>
<config-auth client="vpn" type="auth-request">
<version who="sg">0.1(1)</version>
<auth id="main">
<message>Please enter your username</message>
<form method="post" action="/auth">
<input type="text" name="username" label="Username:" />
<input type="password" name="password" label="Password:" />
</form></auth>
</config-auth>`
var authUserPassRE = regexp.MustCompile("<auth><username>(.*?)</username><password>(.*?)</password></auth>")
var vpnCookieRE = regexp.MustCompile("webvpncontext=(.*?);")
func main() {
//@todo load config from file
cert, _ := tls.LoadX509KeyPair("/Users/horsley/Backup/ssl/ihorsley.com.crt", "/Users/horsley/Backup/ssl/ihorsley.com.key")
var cfg tls.Config
cfg.Certificates = []tls.Certificate{cert}
l, err := tls.Listen("tcp", ":15443", &cfg) //@todo load config from file
if err != nil {
log.Println("listen error:", err)
os.Exit(1)
}
defer l.Close()
for {
conn, err := l.Accept()
if err != nil {
log.Println("accept error:", err)
continue
}
go func(clientConn net.Conn) {
log.Println("conn process start")
defer clientConn.Close()
//@todo load config from file
remoteConn, err := tls.Dial("tcp", "vps9.ihorsley.com:443", nil) //remote can be unix cleartext socket of ocserv
if err != nil {
log.Println("connect upstream error:", err)
return
}
defer remoteConn.Close()
vpnCookie := make(chan string, 1)
go func() { //remote => client
hackRemoteResponse(clientConn, remoteConn, vpnCookie)
io.Copy(clientConn, remoteConn)
}()
//client => remote
hackClientRequest(clientConn, remoteConn, vpnCookie)
io.Copy(remoteConn, clientConn)
log.Println("conn process done")
}(conn)
}
}
//hackClientRequest
//hack auth by resend both user and pass form and cookie
func hackClientRequest(clientConn, remoteConn net.Conn, vpnCookie chan string) {
reader := bufio.NewReader(clientConn)
for { //client req hacking
req, err := http.ReadRequest(reader)
if err != nil {
log.Println("ReadRequest from client conn err:", err)
return
}
if req.URL.Path == "/auth" {
var buf bytes.Buffer
_, err = buf.ReadFrom(req.Body)
req.Body.Close()
if err != nil {
log.Println("read request body from client conn err:", err)
return
}
req.Body = ioutil.NopCloser(bytes.NewReader(buf.Bytes()))
log.Println("3. second req, auth req, do first sending")
req.Write(remoteConn)
//waiting for cookie
ck := <-vpnCookie
log.Println("5. got cookie, resend auth req with cookie")
req.Header.Set("Cookie", fmt.Sprintf("webvpncontext=%s;", ck))
req.Body = ioutil.NopCloser(bytes.NewReader(buf.Bytes()))
req.Write(remoteConn)
log.Println("6. resend done, hack finish, going to do regular io.Copy")
break
} else {
log.Println("1. first req, pass")
req.Write(remoteConn)
}
}
}
//hackRemoteResponse
//hack auth by change auth form and drop the first cookie resp
func hackRemoteResponse(clientConn, remoteConn net.Conn, vpnCookie chan string) {
reader := bufio.NewReader(remoteConn)
for { //remote resp hacking
resp, err := http.ReadResponse(reader, nil)
if err != nil {
log.Println("ReadResponse from remote conn err:", err)
return
}
if resp.ContentLength == len(authFormOld) { //hack auth form
log.Println("2. first resp, hack resp auth form")
resp.Body.Close()
resp.ContentLength = int64(len(authFormNew))
resp.Body = ioutil.NopCloser(strings.NewReader(authFormNew))
} else if ck := resp.Header.Get("Set-Cookie"); ck != "" && vpnCookieRE.MatchString(ck) { //get context cookie
log.Println("4. second resp, grep cookie, resp hacking finish")
if m := vpnCookieRE.FindStringSubmatch(ck); m != nil && m[1] != "" {
vpnCookie <- m[1]
//log.Println("get vpn cookie:", m[1])
break
}
}
err = resp.Write(clientConn)
if err != nil {
log.Println("write to client conn err:", err)
return
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment