Skip to content

Commit 17b6e31

Browse files
committed
[+] #28 Add tunnel function
1 parent 070e5b4 commit 17b6e31

File tree

7 files changed

+245
-44
lines changed

7 files changed

+245
-44
lines changed

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ require (
3131
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
3232
github.com/modern-go/reflect2 v1.0.1 // indirect
3333
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
34+
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
3435
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4
3536
github.com/rhysd/go-github-selfupdate v1.2.3
3637
github.com/sevlyar/go-daemon v0.1.5

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,8 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
273273
github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I=
274274
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
275275
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
276+
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
277+
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
276278
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
277279
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
278280
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

lib/cli/dispatcher/tunnel.go

+39-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,52 @@ package dispatcher
22

33
import (
44
"fmt"
5+
"strconv"
6+
"strings"
7+
8+
"github.com/WangYihang/Platypus/lib/context"
9+
"github.com/WangYihang/Platypus/lib/util/log"
510
)
611

712
func (dispatcher Dispatcher) Tunnel(args []string) {
8-
fmt.Println("TO BE IMPLEMENTED.")
13+
if context.Ctx.Current == nil && context.Ctx.CurrentTermite == nil {
14+
log.Error("Interactive session is not set, please use `Jump` command to set the interactive Interact")
15+
return
16+
}
17+
18+
if context.Ctx.CurrentTermite != nil {
19+
if len(args) != 3 {
20+
log.Error("Arguments error, use `Help Tunnel` to get more information")
21+
dispatcher.TunnelHelp([]string{})
22+
return
23+
}
24+
25+
mode := args[0]
26+
host := args[1]
27+
port, err := strconv.ParseUint(args[2], 10, 16)
28+
29+
if err != nil {
30+
log.Error("Invalid port: %s, use `Help Tunnel` to get more information", args[1])
31+
dispatcher.TunnelHelp([]string{})
32+
return
33+
}
34+
35+
switch strings.ToLower(mode) {
36+
case "create":
37+
context.Ctx.CurrentTermite.CreateTunnel(host, uint16(port))
38+
case "delete":
39+
context.Ctx.CurrentTermite.DeleteTunnel(host, uint16(port))
40+
}
41+
}
42+
43+
if context.Ctx.Current != nil {
44+
log.Error("Tunneling is not supported in plain reverse shell")
45+
}
946
}
1047

1148
func (dispatcher Dispatcher) TunnelHelp(args []string) {
1249
fmt.Println("Usage of Tunnel")
13-
fmt.Println("\tTunnel [SRC] [DST]")
50+
fmt.Println("\tTunnel [Create|Delete] [Host] [Port]")
1451
}
1552

1653
func (dispatcher Dispatcher) TunnelDesc(args []string) {

lib/context/server.go

+39
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/WangYihang/Platypus/lib/util/str"
2121
humanize "github.com/dustin/go-humanize"
2222
"github.com/jedib0t/go-pretty/table"
23+
"github.com/phayes/freeport"
2324
)
2425

2526
type WebSocketMessage struct {
@@ -542,6 +543,44 @@ func TermiteMessageDispatcher(client *TermiteClient) {
542543
} else {
543544
log.Error("No such key")
544545
}
546+
case message.TUNNEL_CONNECTED:
547+
target := msg.Body.(*message.BodyTunnelConnected).Target
548+
port, _ := freeport.GetFreePort()
549+
localAddress := fmt.Sprintf("0.0.0.0:%d", port)
550+
tunnel, err := net.Listen("tcp", localAddress)
551+
if err != nil {
552+
log.Error(err.Error())
553+
break
554+
}
555+
log.Info("%s -> %s", localAddress, target)
556+
go func(target string, port int) {
557+
conn, _ := tunnel.Accept()
558+
Ctx.CurrentTermite.Tunnels[target] = &conn
559+
log.Info("Server client tunnel connected: %v", conn)
560+
for {
561+
buf := make([]byte, 1024)
562+
n, err := conn.Read(buf)
563+
if err != nil {
564+
log.Error(err.Error())
565+
break
566+
}
567+
if n > 0 {
568+
log.Info(">> %v", buf[0:n])
569+
Ctx.CurrentTermite.WriteTunnel(target, buf[0:n])
570+
}
571+
}
572+
}(target, port)
573+
case message.TUNNEL_DATA:
574+
target := msg.Body.(*message.BodyTunnelData).Target
575+
data := msg.Body.(*message.BodyTunnelData).Data
576+
log.Info("%s, %v, connected", target, data)
577+
578+
if conn, exists := Ctx.CurrentTermite.Tunnels[target]; exists {
579+
(*conn).Write(data)
580+
} else {
581+
log.Error("No such tunnel")
582+
}
583+
545584
}
546585
}
547586
}

lib/context/termite.go

+72-11
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,18 @@ type Process struct {
4141

4242
type TermiteClient struct {
4343
conn net.Conn
44-
Hash string `json:"hash"`
45-
Host string `json:"host"`
46-
Port uint16 `json:"port"`
47-
Alias string `json:"alias"`
48-
User string `json:"user"`
49-
OS oss.OperatingSystem `json:"os"`
50-
NetworkInterfaces map[string]string `json:"network_interfaces"`
51-
Python2 string `json:"python2"`
52-
Python3 string `json:"python3"`
53-
TimeStamp time.Time `json:"timestamp"`
54-
DisableHistory bool `json:"disable_hisory"`
44+
Hash string `json:"hash"`
45+
Host string `json:"host"`
46+
Port uint16 `json:"port"`
47+
Alias string `json:"alias"`
48+
User string `json:"user"`
49+
OS oss.OperatingSystem `json:"os"`
50+
NetworkInterfaces map[string]string `json:"network_interfaces"`
51+
Python2 string `json:"python2"`
52+
Python3 string `json:"python3"`
53+
TimeStamp time.Time `json:"timestamp"`
54+
DisableHistory bool `json:"disable_hisory"`
55+
Tunnels map[string]*net.Conn `json:"tunnels"`
5556
server *TCPServer
5657
EncoderLock *sync.Mutex
5758
DecoderLock *sync.Mutex
@@ -86,6 +87,7 @@ func CreateTermiteClient(conn net.Conn, server *TCPServer, disableHistory bool)
8687
Processes: map[string]*Process{},
8788
CurrentProcessKey: "",
8889
DisableHistory: disableHistory,
90+
Tunnels: map[string]*net.Conn{},
8991
}
9092
}
9193

@@ -332,6 +334,65 @@ func (c *TermiteClient) GetUsername() string {
332334
return username
333335
}
334336

337+
func (c *TermiteClient) CreateTunnel(host string, port uint16) {
338+
log.Info("Connecting to %s:%d", host, port)
339+
340+
c.AtomLock.Lock()
341+
defer func() { c.AtomLock.Unlock() }()
342+
343+
c.EncoderLock.Lock()
344+
err := c.Encoder.Encode(message.Message{
345+
Type: message.TUNNEL_CONNECT,
346+
Body: message.BodyTunnelConnect{
347+
Target: fmt.Sprintf("%s:%d", host, port),
348+
},
349+
})
350+
c.EncoderLock.Unlock()
351+
352+
if err != nil {
353+
log.Error("Network error: %s", err)
354+
}
355+
}
356+
357+
func (c *TermiteClient) DeleteTunnel(host string, port uint16) {
358+
log.Info("Disconnecting to %s:%d", host, port)
359+
360+
c.AtomLock.Lock()
361+
defer func() { c.AtomLock.Unlock() }()
362+
363+
c.EncoderLock.Lock()
364+
err := c.Encoder.Encode(message.Message{
365+
Type: message.TUNNEL_DISCONNECT,
366+
Body: message.BodyTunnelDisconnect{
367+
Target: fmt.Sprintf("%s:%d", host, port),
368+
},
369+
})
370+
c.EncoderLock.Unlock()
371+
372+
if err != nil {
373+
log.Error("Network error: %s", err)
374+
}
375+
}
376+
377+
func (c *TermiteClient) WriteTunnel(target string, data []byte) {
378+
c.AtomLock.Lock()
379+
defer func() { c.AtomLock.Unlock() }()
380+
381+
c.EncoderLock.Lock()
382+
err := c.Encoder.Encode(message.Message{
383+
Type: message.TUNNEL_DATA,
384+
Body: message.BodyTunnelData{
385+
Target: target,
386+
Data: data,
387+
},
388+
})
389+
c.EncoderLock.Unlock()
390+
391+
if err != nil {
392+
log.Error("Network error: %s", err)
393+
}
394+
}
395+
335396
func (c *TermiteClient) makeHash(hashFormat string) string {
336397
data := ""
337398
if c.OS == oss.Linux {

lib/util/message/message.go

+25
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ const (
2121
PROCESS_STARTED
2222
PROCESS_STOPED
2323
CLIENT_INFO
24+
25+
// Tunnel
26+
TUNNEL_CONNECT
27+
TUNNEL_CONNECTED
28+
TUNNEL_DATA
29+
TUNNEL_DISCONNECT
2430
)
2531

2632
type Message struct {
@@ -72,6 +78,21 @@ type BodyTerminateProcess struct {
7278
Key string
7379
}
7480

81+
type BodyTunnelConnect struct {
82+
Target string
83+
}
84+
type BodyTunnelConnected struct {
85+
Target string
86+
}
87+
type BodyTunnelData struct {
88+
Target string
89+
Data []byte
90+
}
91+
92+
type BodyTunnelDisconnect struct {
93+
Target string
94+
}
95+
7596
func RegisterGob() {
7697
gob.Register(&BodyStdio{})
7798
gob.Register(&BodyWindowSize{})
@@ -82,4 +103,8 @@ func RegisterGob() {
82103
gob.Register(&BodyDuplicateClient{})
83104
gob.Register(&BodyClientInfo{})
84105
gob.Register(&BodyTerminateProcess{})
106+
gob.Register(&BodyTunnelConnect{})
107+
gob.Register(&BodyTunnelConnected{})
108+
gob.Register(&BodyTunnelData{})
109+
gob.Register(&BodyTunnelDisconnect{})
85110
}

0 commit comments

Comments
 (0)