Skip to content

Instantly share code, notes, and snippets.

@rlewkowicz
Created July 29, 2022 13:02
Show Gist options
  • Save rlewkowicz/d11040ec66018b1eb612426486116d7e to your computer and use it in GitHub Desktop.
Save rlewkowicz/d11040ec66018b1eb612426486116d7e to your computer and use it in GitHub Desktop.
I'm in your global protect, hacking your routes
package main
// The concept of this was borrowed from https://github.com/kayrus/tuncfg.git
// This is a crappy dumbed down rewrite so you can add some hacky routes.
// This is a useful reference for understanding the syscalls. You can add routes that don't
// show as static etc. It's useful for combating global protect.
// https://www.freebsd.org/cgi/man.cgi?query=rtentry
// https://www.freebsd.org/cgi/man.cgi?query=route
import (
"flag"
"fmt"
"syscall"
"github.com/IBM/netaddr"
"golang.org/x/net/route"
"golang.org/x/sys/unix"
)
func main() {
var msg route.RouteMessage
var addrs []route.Addr
// This feels gross, but I don't know what parens are in golang. You're building this like syscall object,
// But idk what this construct is. In python, it's a tuple, but I don't think that exists here.
var flags = (syscall.RTF_UP | syscall.RTF_GATEWAY | syscall.RTF_PINNED | syscall.RTF_STATIC)
// onetwo is misnomer. Really this is just RTM messages (see reference). 1 is add, 2 is del, 3 is change.
// I think change has to have matching flags?
onetwo := flag.Int("onetwo", 1, "1/2")
ip := flag.String("ip", "", "1.2.3.4")
mask := flag.String("mask", "", "255.255.255.255")
// mac := flag.String("mac", "", "3c:22:fb:27:26:38")
// iface := flag.String("iface", "en0", "en0")
gateway := flag.String("gateway", "", "192.168.1.1")
linkIndex := flag.Int("index", 1000, "Link index is the index of the interface. I think its array indexed starting at 1 of ifconfig")
UC := flag.String("uc", "false", "its uc, of course you know what that is")
watch := flag.String("watch", "false", "watch for new routes. Useful for vms coming online")
host := flag.String("host", "false", "create a host route")
broadcast := flag.String("broadcast", "false", "create a broadcast route")
bridge := flag.String("bridge", "false", "create a bridge route")
flag.Parse()
a := [4]byte{}
m := [4]byte{}
g := [4]byte{}
// g := []byte{}
copy(a[:], netaddr.ParseIP(*ip))
copy(m[:], netaddr.ParseIP(*mask))
copy(g[:], netaddr.ParseIP(*gateway))
// s := strings.Split(*gateway, ".")
// w, _ := strconv.Atoi(s[0])
// x, _ := strconv.Atoi(s[1])
// y, _ := strconv.Atoi(s[2])
// z, _ := strconv.Atoi(s[3])
// h, _ := net.ParseMAC("7c:10:c9:69:5e:30")
hop := &route.LinkAddr{
Index: *linkIndex,
// Name: "",
// Addr: g,
}
// fmt.Printf("", *iface)
socket, _ := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
// If index is 1k no one set, lets use the ip
if *linkIndex == 1000 {
addrs = []route.Addr{
&route.Inet4Addr{a},
&route.Inet4Addr{g},
&route.Inet4Addr{m},
}
} else { // If it's not set, lets use the link number
addrs = []route.Addr{
&route.Inet4Addr{a},
hop,
&route.Inet4Addr{m},
}
}
// 1 RTF_PROTO1 Protocol specific routing flag #1
// 2 RTF_PROTO2 Protocol specific routing flag #2
// 3 RTF_PROTO3 Protocol specific routing flag #3
// B RTF_BLACKHOLE Just discard packets (during updates)
// b RTF_BROADCAST The route represents a broadcast address
// C RTF_CLONING Generate new routes on use
// c RTF_PRCLONING Protocol-specified generate new routes on use
// D RTF_DYNAMIC Created dynamically (by redirect)
// G RTF_GATEWAY Destination requires forwarding by intermediary
// H RTF_HOST Host entry (net otherwise)
// I RTF_IFSCOPE Route is associated with an interface scope
// i RTF_IFREF Route is holding a reference to the interface
// L RTF_LLINFO Valid protocol to link address translation
// M RTF_MODIFIED Modified dynamically (by redirect)
// m RTF_MULTICAST The route represents a multicast address
// R RTF_REJECT Host or net unreachable
// r RTF_ROUTER Host is a default router
// S RTF_STATIC Manually added
// U RTF_UP Route usable
// W RTF_WASCLONED Route was generated as a result of cloning
// X RTF_XRESOLVE External daemon translates proto to link address
// Y RTF_PROXY Proxying; cloned routes will not be scoped
// g RTF_GLOBAL Route to a destination of the global internet (policy hint)
if *host != "false" {
flags = (syscall.RTF_UP | syscall.RTF_GATEWAY | syscall.RTF_PINNED | syscall.RTF_HOST)
}
if *UC != "false" {
flags = (syscall.RTF_UP | syscall.RTF_CLONING)
}
if *broadcast != "false" {
flags = (syscall.RTF_UP | syscall.RTF_HOST | syscall.RTF_LLINFO | syscall.RTF_WASCLONED | syscall.RTF_BROADCAST | syscall.RTF_IFSCOPE)
}
if *bridge != "false" {
flags = (syscall.RTF_UP | syscall.RTF_HOST | syscall.RTF_LLINFO | syscall.RTF_WASCLONED | syscall.RTF_IFSCOPE)
}
msg = route.RouteMessage{
Version: syscall.RTM_VERSION,
Type: *onetwo,
Index: 0,
ID: 0,
// So I tried host flags to get around GP first, the host flag is interesting on subnets.
// Seems to work, but it looks kinda weird in the routing table
// Flags: (syscall.RTF_UP | syscall.RTF_GATEWAY | syscall.RTF_PINNED | syscall.RTF_HOST),
Flags: flags,
Addrs: addrs,
}
bin, _ := msg.Marshal()
COUNT := 0
if *watch != "false" {
for {
_, err := unix.Write(socket, bin[:])
fmt.Println(err)
}
} else {
for {
_, err := unix.Write(socket, bin[:])
COUNT = COUNT + 1
fmt.Println(err)
if COUNT > 0 {
break
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment