hpAndro CTF walkthrough - Asymmetric encryption / RSA

RSA

Task: Your task is to find KEY and try to decrypt given RSA encrypted flag.

Static analysis

Clicking on the "CHECK RSA FLAG" button results in a base64 encoded encrypted value.

img

echo "OplOuJowyt9ZtkIPKcmi6FVp50sZGd3+TbwXgQYxW0v/+sA87tG2ViJ9D5GOFHvl7nffGNLju5kzE33b1CKztu6/rHbIsu5lftp2qgtLQZdIdYy7F6MDhbvyLNk786QgXPLwND6ccFUv4brz8GAAefougdBYKr9o8IWBw8HxRfu884WLQnOxuhMnANXOU7yp1xaap2ojejSeNNbOWn1VKBMaZviXGVXXR6m4lFlHxMUXEP9h4bjrMraapiNLMM+2sUCuhD80beZK1NVakchy8FpqfJ/+hXaokSvnvQIHTr3H9JPD+flzwgYQn9FVvet4494+c2+rBTFOMdrYxHQwqg==" | base64 -d | hd
00000000  3a 99 4e b8 9a 30 ca df  59 b6 42 0f 29 c9 a2 e8  |:.N..0..Y.B.)...|
00000010  55 69 e7 4b 19 19 dd fe  4d bc 17 81 06 31 5b 4b  |Ui.K....M....1[K|
00000020  ff fa c0 3c ee d1 b6 56  22 7d 0f 91 8e 14 7b e5  |...<...V"}....{.|
00000030  ee 77 df 18 d2 e3 bb 99  33 13 7d db d4 22 b3 b6  |.w......3.}.."..|
00000040  ee bf ac 76 c8 b2 ee 65  7e da 76 aa 0b 4b 41 97  |...v...e~.v..KA.|
00000050  48 75 8c bb 17 a3 03 85  bb f2 2c d9 3b f3 a4 20  |Hu........,.;.. |
00000060  5c f2 f0 34 3e 9c 70 55  2f e1 ba f3 f0 60 00 79  |\..4>.pU/....`.y|
00000070  fa 2e 81 d0 58 2a bf 68  f0 85 81 c3 c1 f1 45 fb  |....X*.h......E.|
00000080  bc f3 85 8b 42 73 b1 ba  13 27 00 d5 ce 53 bc a9  |....Bs...'...S..|
00000090  d7 16 9a a7 6a 23 7a 34  9e 34 d6 ce 5a 7d 55 28  |....j#z4.4..Z}U(|
000000a0  13 1a 66 f8 97 19 55 d7  47 a9 b8 94 59 47 c4 c5  |..f...U.G...YG..|
000000b0  17 10 ff 61 e1 b8 eb 32  b6 9a a6 23 4b 30 cf b6  |...a...2...#K0..|
000000c0  b1 40 ae 84 3f 34 6d e6  4a d4 d5 5a 91 c8 72 f0  |.@..?4m.J..Z..r.|
000000d0  5a 6a 7c 9f fe 85 76 a8  91 2b e7 bd 02 07 4e bd  |Zj|...v..+....N.|
000000e0  c7 f4 93 c3 f9 f9 73 c2  06 10 9f d1 55 bd eb 78  |......s.....U..x|
000000f0  e3 de 3e 73 6f ab 05 31  4e 31 da d8 c4 74 30 aa  |..>so..1N1...t0.|
00000100

The relevant classes can be found with a simple search in jadx-gui for the string "RSA/"

img

As it can be seen the class com.hpandro.androidsecurity.ui.activity.task.encryption.RSAActivity contains a "decrypt" method which takes the private key and the encrypted value as arguments and returns the decrypted value as a byte array. img

Dynamic analysis

The simplest method to solve the challenge is to extract the decrypted flag with objection by using a hook on the "decrypt" method of the class com.hpandro.androidsecurity.ui.activity.task.encryption.RSAActivity

Run frida server on the emulator

$ adb push frida-server-15.0.19-android-x86 /data/local/tmp/frida-srv
frida-server-15.0.19-android-x86: 1 file pushed, 0 skipped. 62.5 MB/s (46351796 bytes in 0.708s)
$ adb shell
vbox86p:/ # cd /data/local/tmp
vbox86p:/data/local/tmp # chmod +x frida-srv && ./frida-srv

Objection hook

$ objection -g "com.hpandro.androidsecurity" explore                                                                                                                  
com.hpandro.androidsecurity on (Android: 10) [usb] # android hooking watch class_method com.hpandro.androidsecurity.ui.activity.task.encryption.RSAActivity.decrypt --dump-args --dump-return

When the "CHECK RSA FLAG" button is clicked we'll see the following output in objection:

(agent) [076864] Arguments com.hpandro.androidsecurity.ui.activity.task.encryption.RSAActivity.decrypt([object Object], 58,-103,78,-72,-102,48,-54,-33,89,-74,66,15,41,-55,-94,-24,85,105,-25,75,25,25,-35,-2,77,-68,23,-127,6,49,91,75,-1,-6,-64,60,-18,-47,-74,86,34,125,15,-111,-114,20,123,-27,-18,119,-33,24,-46,-29,-69,-103,51,19,125,-37,-44,34,-77,-74,-18,-65,-84,118,-56,-78,-18,101,126,-38,118,-86,11,75,65,-105,72,117,-116,-69,23,-93,3,-123,-69,-14,44,-39,59,-13,-92,32,92,-14,-16,52,62,-100,112,85,47,-31,-70,-13,-16,96,0,121,-6,46,-127,-48,88,42,-65,104,-16,-123,-127,-61,-63,-15,69,-5,-68,-13,-123,-117,66,115,-79,-70,19,39,0,-43,-50,83,-68,-87,-41,22,-102,-89,106,35,122,52,-98,52,-42,-50,90,125,85,40,19,26,102,-8,-105,25,85,-41,71,-87,-72,-108,89,71,-60,-59,23,16,-1,97,-31,-72,-21,50,-74,-102,-90,35,75,48,-49,-74,-79,64,-82,-124,63,52,109,-26,74,-44,-43,90,-111,-56,114,-16,90,106,124,-97,-2,-123,118,-88,-111,43,-25,-67,2,7,78,-67,-57,-12,-109,-61,-7,-7,115,-62,6,16,-97,-47,85,-67,-21,120,-29,-34,62,115,111,-85,5,49,78,49,-38,-40,-60,116,48,-86)
(agent) [076864] Return Value: 104,112,97,110,100,114,111,123,82,83,65,46,111,115,79,48,76,53,67,71,54,90,101,120,49,104,111,57,113,121,54,69,71,102,102,56,85,106,86,100,69,87,56,72,125

(Note: The Java byte type is a signed integer; the value ranges between -128 and 127.)

The following Java snippet can be used to convert the byte array into a string:

public class ByteArraytoString
{
        public static void main(String[] args)
                {

                        byte[] byteArray = {104,112,97,110,100,114,111,123,82,83,65,46,111,115,79,48,76,53,67,71,54,90,101,120,49,104,111,57,113,121,54,69,71,102,102,56,85,106,86,100,69,87,56,72,125};
                        String str = new String(byteArray);
                        System.out.println(str);
                }
}
$ javac ByteArraytoString.java && java ByteArraytoString
hpandro{REDACTED}

The following Python snippet can be used to convert the byte array into string:

$ python3
>>> items = [104,112,97,110,100,114,111,123,82,83,65,46,111,115,79,48,76,53,67,71,54,90,101,120,49,104,111,57,113,121,54,69,71,102,102,56,85,106,86,100,69,87,56,72,125]
>>> data = bytes(b % 256 for b in items)                                                     
>>> print(data)
b'hpandro{REDACTED}'

Extract the private key from the APK & Decrypt the flag with OpenSSL

As it can be seen in the onGetLogs method of class com.hpandro.androidsecurity.ui.activity.task.encryption.RSAActivity, the private key comes with the APK (private.der) img img

Let's extract the apk contents:

$ apktool d com.hpandro.androidsecurity_1.2.apk && tree com.hpandro.androidsecurity_1.2/assets/
com.hpandro.androidsecurity_1.2/assets/
├── private.der
├── public.der
└── rri.crt

0 directories, 3 files

$ binwalk com.hpandro.androidsecurity_1.2/assets/private.der

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Private key in DER format (PKCS header length: 4, sequence length: 1213
26            0x1A            Private key in DER format (PKCS header length: 4, sequence length: 1187

Convert private.der to private.pem

$ openssl rsa -inform DER -in com.hpandro.androidsecurity_1.2/assets/private.der -out private.pem
writing RSA key

Decrypt the flag (Note: the encryption method is "RSA/ECB/OAEPWithSHA1AndMGF1Padding" so the -oaep flag is neccessary for openssl)

$ echo -n "OplOuJowyt9ZtkIPKcmi6FVp50sZGd3+TbwXgQYxW0v/+sA87tG2ViJ9D5GOFHvl7nffGNLju5kzE33b1CKztu6/rHbIsu5lftp2qgtLQZdIdYy7F6MDhbvyLNk786QgXPLwND6ccFUv4brz8GAAefougdBYKr9o8IWBw8HxRfu884WLQnOxuhMnANXOU7yp1xaap2ojejSeNNbOWn1VKBMaZviXGVXXR6m4lFlHxMUXEP9h4bjrMraapiNLMM+2sUCuhD80beZK1NVakchy8FpqfJ/+hXaokSvnvQIHTr3H9JPD+flzwgYQn9FVvet4494+c2+rBTFOMdrYxHQwqg==" | base64 -d > flag.enc
$ openssl rsautl -decrypt -inkey private.pem -in flag.enc -oaep
hpandro{REDACTED}

Reference

Thoughts? Leave a comment