序
今天下午,忙完手里的活,就在想扩展一下之前的java执行shell。之前是通过http请求,发送指令,后端执行,现在想的是网络编程创建服务端,客户端自己run或使用工具,拦截一部分人吧。这么做其实是适合很多所谓的堡垒机,免得无权限登录,但是又需要执行一些命令。废话不多说,直接上码。
一、shell执行工具类
import org.apache.commons.lang.ArrayUtils;
import java.io.BufferedReader;
import java.io.InputStreamReader;
/**
* @author zhengwen
*/
public class ProcessUtil {
/**
* 执行shell
* @param shStrArr 指令数组
* @return 执行结果/反馈
* @throws Exception
*/
public static String runShell(String[] shStrArr) throws Exception {
StringBuffer sb = new StringBuffer();
sb.append("-----------result--------------");
sb.append("\n");
Process process = null;
//List<String> processList = new ArrayList<String>(); 多命令
try {
if (!ArrayUtils.isEmpty(shStrArr)) {
String sh = "";
for (int i = 0; i < shStrArr.length; i++) {
String tmpSh = shStrArr[i];
sh += tmpSh;
if (i != shStrArr.length - 1) {
sh += "&&";
}
}
String[] cmd;
//支持多操作系统
String osName = System.getProperty("os.name");
if (osName.startsWith("Windows")) {
cmd = new String[3];
cmd[0] = "cmd.exe";
cmd[1] = "/C";
cmd[2] = sh;
sh = "cmd.exe /C " + sh;
} else if (osName.startsWith("Linux") || osName.toLowerCase().startsWith("centos")) {
//linux
cmd = new String[3];
cmd[0] = "/bin/sh";
cmd[1] = "-c";
cmd[2] = sh;
sh = "/bin/sh -c " + sh;
} else {
cmd = new String[1];
cmd[0] = sh;
}
//process = Runtime.getRuntime().exec(cmd);
process = Runtime.getRuntime().exec(sh);
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream(), "gb2312"));
String line = "";
while ((line = input.readLine()) != null) {
//processList.add(line);
sb.append(line);
sb.append("\n");
}
process.waitFor();
input.close();
}
} catch (Exception e) {
sb.append(e.getMessage());
}
return sb.toString();
}
public static void main(String[] args) {
String[] shStr = {"cmd.exe /C dir d:", "cmd.exe /C dir d:\\application"};
String rs = null;
try {
rs = ProcessUtil.runShell(shStr);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(rs);
}
}
二、服务端
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Set;
/**
* @author zhengwen
**/
public class SocketServer {
/**
* 解码buffer
*/
private Charset cs = Charset.forName("UTF-8");
/**
* 接受数据缓冲区
*/
private static ByteBuffer sBuffer = ByteBuffer.allocate(1024);
/**
* 发送数据缓冲区
*/
private static ByteBuffer rBuffer = ByteBuffer.allocate(1024);
/**
* 选择器(叫监听器更准确些)
*/
private static Selector selector;
/**
* 启动socket服务,开启监听
*
* @param port
* @throws IOException
*/
public void startSocketServer(int port) {
try {
//打开通信信道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//设置为非阻塞
serverSocketChannel.configureBlocking(false);
//获取套接字
ServerSocket serverSocket = serverSocketChannel.socket();
//绑定端口号
serverSocket.bind(new InetSocketAddress(port));
//打开监听器
selector = Selector.open();
//将通信信道注册到监听器
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
//监听器会一直监听,如果客户端有请求就会进入相应的事件处理
while (true) {
//select方法会一直阻塞直到有相关事件发生或超时
selector.select();
//监听到的事件
Set<SelectionKey> selectionKeys = selector.selectedKeys();
for (SelectionKey key : selectionKeys) {
handle(key);
}
//清除处理过的事件
selectionKeys.clear();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 处理不同的事件
*
* @param selectionKey
* @throws IOException
*/
private void handle(SelectionKey selectionKey) throws IOException {
ServerSocketChannel serverSocketChannel = null;
SocketChannel socketChannel = null;
String requestMsg = "";
int count = 0;
if (selectionKey.isAcceptable()) {
//每有客户端连接,即注册通信信道为可读
serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
} else if (selectionKey.isReadable()) {
socketChannel = (SocketChannel) selectionKey.channel();
rBuffer.clear();
count = socketChannel.read(rBuffer);
//读取数据
if (count > 0) {
rBuffer.flip();
requestMsg = String.valueOf(cs.decode(rBuffer).array());
}
String responseMsg = "已收到客户端的指令:" + requestMsg +"\n";
System.out.println(responseMsg);
//执行命令
String[] shArr = new String[1];
shArr[0] = requestMsg;
try {
responseMsg += ProcessUtil.runShell(shArr);
} catch (Exception e) {
e.printStackTrace();
responseMsg += e.getMessage();
}
//返回数据
sBuffer = ByteBuffer.allocate(responseMsg.getBytes("UTF-8").length);
sBuffer.put(responseMsg.getBytes("UTF-8"));
sBuffer.flip();
socketChannel.write(sBuffer);
//socketChannel.close();
}
}
}
三、客户端
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
* 测试的客户端
* @author zhengwen
**/
public class TestClient extends Frame implements ActionListener {
Label label = new Label("command");
Panel panel = new Panel();
TextField tf = new TextField(100);
TextArea ta = new TextArea();
Socket client;
InputStream in;
OutputStream out;
public TestClient() {
super("客户机");
Dimension si = Toolkit.getDefaultToolkit().getScreenSize();
int width = si.width;
int height = si.height;
setSize(width/2, height/2);
panel.add(label);
panel.add(tf);
tf.setEditable(true);
tf.addActionListener(this);
add("South", panel);
add("Center", ta);
addWindowListener(new WindowAdapter() { //退出
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
setVisible(true);
//show();
try {
//向6000端口发出客户请求,如果上现网改ip就ok了
client = new Socket(InetAddress.getLocalHost(), 6000);
ta.append("服务器是:" + client.getInetAddress().getHostAddress() +
"\n\n");
in = client.getInputStream();
out = client.getOutputStream();
} catch (IOException ioe) {
ioe.printStackTrace();
}
while (true) {
try {
byte[] buf = new byte[256];
in.read(buf);
String str = new String(buf);
ta.append(str + "\n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void actionPerformed(ActionEvent e) {
try {
String str = tf.getText();
byte[] buf = str.getBytes();
tf.setText(null);
out.write(buf);
ta.append("\n指令:" + str + "\n");
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
public static void main(String[] args) {
new TestClient();
}
}
以上三步就构建了一个指令服务端,客户端时大家可以自己写,或者使用工具。注释还算详细,多的话应该不需要多说,下面来看看效果
四、效果
我这里的这个测试是在springCloud的eureka注册中心,在启动类李只需要增加一行代码启动服务端。
/**
* @author zhengwen
*/
@Slf4j
@SpringBootApplication
@EnableEurekaServer
public class FsiHouseCloudEurekaApp {
public static void main(String[] args) {
SpringApplication.run(FsiHouseCloudEurekaApp.class, args);
//起socket服务
SocketServer server = new SocketServer();
server.startSocketServer(6000);
System.out.println("----Eureka注册中心启动完成----");
}
}
跑客户端的效果
测试几个命令的效果
剩下的大家就可以自己玩了,还有一种高级玩法就是可以先写好或上传一个bat/sh文件,然后再这里可以执行授权,运行这个文件。
如果要干坏事,你懂的,也是可以的。技术无罪,呵呵。好了,下班走人,祝大家周末愉快。