Tags: rc4 rev java android 

Rating:

# Lightbulb (rev)
Writeup by: [xlr8or](https://ctftime.org/team/235001)

As part of this challenge we get an apk file.
My go-to tool for apks is `jadx-gui`, so I loaded this file into it.

First let's search for the flag prefix, maybe we get lucky. There's a single hit for it in the `LightSwitchingActivity` class. Let's see the code around this area:

```java
String string = sharedPreferences.getString("secret_key", "");
Log.d("LIGHTSWITCH", "the sk was " + string);
Intrinsics.checkNotNull(string);

byte[] bytes = string.getBytes(Charsets.UTF_8);
Intrinsics.checkNotNullExpressionValue(bytes, "this as java.lang.String).getBytes(charset)");

APIKeyHash aPIKeyHash = new APIKeyHash(bytes);
StringBuilder sb = new StringBuilder("CSR{");

byte[] bytes2 = "APIKEY".getBytes(Charsets.UTF_8);
Intrinsics.checkNotNullExpressionValue(bytes2, "this as java.lang.String).getBytes(charset)");

this.apiKey = sb.append(LightSwitchingActivityKt.toHex(aPIKeyHash.hash(bytes2))).append('}').toString();
```

* We get a `secret_key` from shared preferences and convert it to a byte array
* We initialize `APIKeyHash` based on the key
* We hash the string `APIKEY` and concatenate it with the flag prefix and suffix

So we just need to get the hash value of `APIKEY` in order to solve this challenge.
Let's quickly take a look at the hash function:
```java
Intrinsics.checkNotNullParameter(plaintext, "plaintext");
byte[] bArr = new byte[plaintext.length];
int length = plaintext.length;
int i = 0;
int i2 = 0;
for (int i3 = 0; i3 < length; i3++) {
i = (i + 1) & 255;
byte[] bArr2 = this.s;
byte b = bArr2[i];
i2 = (i2 + b) & 255;
byte b2 = bArr2[i2];
bArr2[i2] = b;
bArr2[i] = b2;
bArr[i3] = (byte) (bArr2[(b2 + bArr2[i2]) & 255] ^ plaintext[i3]);
}
return bArr;
```

This looks familiar... It looks like RC4 encrypt/decrypt, although if I didn't recognize the algorithm I could have translated it from scratch and would have still been able to recover the flag.

Equipped with this knowledge we only need to find the `secret_key` in order to recover the flag. And a simple text search helps me out again.
In `MainActivity` we find the following code:
```java
if (!Intrinsics.areEqual(PreferenceManager.getDefaultSharedPreferences(this).getString("secret_key", ""), "583908295080")) {
startActivity(new Intent(getApplicationContext(), LoginActivity.class));
} else {
startActivity(new Intent(getApplicationContext(), LightSwitchingActivity.class));
}
```

If the `secret_key` is not the constant value there, then the login screen is shown, otherwise we proceed to the code path which constructs the flag.

Now we know everything to construct the flag:
```python
from Crypto.Cipher import ARC4

secret_key = '583908295080'

cipher = ARC4.new(secret_key.encode('utf-8'))
print(cipher.encrypt('APIKEY'.encode('utf-8')).hex().upper())
```