# CyberHeroines 2023

## Maddie Stone

> [Maddie Stone](https://www.wired.com/story/maddie-stone-project-zero-
> reverse-engineering/) is a prominent researcher on Google’s Project Zero
> bug-hunting team, which finds critical software flaws and
> vulnerabilities—mostly in other companies’ products. But her journey through
> the ranks of the security research community hasn’t always been easy, and
> has galvanized her to speak openly, often on Twitter, about the need to make
> the tech and engineering industries more inclusive. - [Wired
> Story](https://www.wired.com/story/maddie-stone-project-zero-reverse-
> engineering/)

Chal: Our [Cyber Heroines CTF Director](https://www.fit.edu/faculty-
profiles/s/sudhakaran-sneha/) created an APK for hiding flags in homage to her
favorite [Reverse Engineer](https://www.youtube.com/watch?v=U6qTcpCfuFc).
Reverse the application and return the flag .  
>  
> Author: [Sneha](https://www.snehasudhakaran.com/)  
>  
> [`chgame.apk`](https://raw.githubusercontent.com/D13David/ctf-
> writeups/main/cyberheroines23/rev/maddie_stone/chgame.apk),
> [`chaudio.wav`](https://raw.githubusercontent.com/D13David/ctf-
> writeups/main/cyberheroines23/rev/maddie_stone/chaudio.wav)

Tags: _rev_

## Solution  
For this challenge a `apk` and a `wav` is given. Since this is rev we
concentrate on the apk first. We can open the file with
[`JADX`](https://github.com/skylot/jadx) to inspect resources and decompile
the code.

The code itself is not too exciting. Most of the logic is within
`UploadActivity.kt`. We have two buttons, one to select an audio file and
another to play the audio file. When selecting an audio file a `file picker
dialog` is opened and some ui elements are updated.

```java  
public static final void onSelectAudioFile(UploadActivity this$0, View it) {  
Intrinsics.checkNotNullParameter(this$0, "this$0");  
this$0.openFilePicker();  
}

private final void openFilePicker() {  
Intent intent = new Intent("android.intent.action.GET_CONTENT");  
intent.setType("audio/*");  
startActivityForResult(intent, this.PICK_AUDIO_REQUEST);  
}

public void onActivityResult(int requestCode, int resultCode, Intent data) {  
super.onActivityResult(requestCode, resultCode, data);  
if (requestCode == this.PICK_AUDIO_REQUEST && resultCode == -1) {  
TextView textView = null;  
Uri audioUri = data != null ? data.getData() : null;  
if (audioUri != null) {  
TextView textView2 = this.audioPathTextView;  
if (textView2 == null) {  
Intrinsics.throwUninitializedPropertyAccessException("audioPathTextView");  
textView2 = null;  
}  
textView2.setText(audioUri.getPath());  
Button button = this.playAudioButton;  
if (button == null) {  
Intrinsics.throwUninitializedPropertyAccessException("playAudioButton");  
button = null;  
}  
button.setVisibility(0);  
TextView textView3 = this.playInstructionText;  
if (textView3 == null) {  
Intrinsics.throwUninitializedPropertyAccessException("playInstructionText");  
} else {  
textView = textView3;  
}  
textView.setVisibility(0);  
}  
}  
}  
```

Playing the audio file a alert is shown that `something changed when the audio
was played`. I searched a while but nothing changed so this turned out to be a
lie and nothing changed at all. But a option is offered to the user to
download the `changed` audio file.

```java  
public static final void onPlayAudioFile(UploadActivity this$0, View it) {  
Intrinsics.checkNotNullParameter(this$0, "this$0");  
AlertDialog.Builder builder = new AlertDialog.Builder(this$0);  
builder.setMessage("Uh oh, Something changed when we played that audio. Let's
give you that audio file back now").setPositiveButton("Download", new
DialogInterface.OnClickListener() { // from class:
com.example.embeddedgame.UploadActivity$$ExternalSyntheticLambda0  
@Override // android.content.DialogInterface.OnClickListener  
public final void onClick(DialogInterface dialogInterface, int i) {  
UploadActivity.onDownloadAudioFile(UploadActivity.this, dialogInterface, i);  
}  
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() { // from
class: com.example.embeddedgame.UploadActivity$$ExternalSyntheticLambda1  
@Override // android.content.DialogInterface.OnClickListener  
public final void onClick(DialogInterface dialogInterface, int i) {  
dialogInterface.dismiss();  
}  
});  
builder.create().show();  
}

public static final void onDownloadAudioFile(UploadActivity this$0,
DialogInterface dialogInterface, int i) {  
Intrinsics.checkNotNullParameter(this$0, "this$0");  
this$0.checkStoragePermissionAndDownload();  
}

private final void checkStoragePermissionAndDownload() {  
int hasPermission = ContextCompat.checkSelfPermission(this,
"android.permission.WRITE_EXTERNAL_STORAGE");  
if (hasPermission != 0) {  
ActivityCompat.requestPermissions(this, new
String[]{"android.permission.WRITE_EXTERNAL_STORAGE"}, 100);  
} else {  
downloadFile();  
}  
}  
```

The file download basically just writes a copy of the file
`encoded_chaudio.wav`, which is delivered with the `apk` to the downloads
directory.

```java  
private final void downloadFile() {  
String destination =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString()
+ "encoded_chaudio.wav";  
File file = new File(destination);  
if (file.exists()) {  
file.delete();  
}  
try {  
InputStream inputStream =
getAssets().open(LiveLiterals$UploadActivityKt.INSTANCE.m85x7edd2ff());  
Intrinsics.checkNotNullExpressionValue(inputStream,
"assets.open(\"encoded_chaudio.wav\")");  
FileOutputStream fos = new FileOutputStream(destination);  
byte[] buffer = new byte[1024];  
while (true) {  
int it = inputStream.read(buffer);  
if (it > 0) {  
fos.write(buffer, LiveLiterals$UploadActivityKt.INSTANCE.m87xdeeff43b(), it);  
} else {  
fos.close();  
inputStream.close();  
Toast.makeText(this, "Audio file saved to Downloads", 0).show();  
Intent intent = new Intent("android.intent.action.VIEW");  
intent.setDataAndType(Uri.fromFile(file), "audio/*");  
startActivity(intent);  
return;  
}  
}  
} catch (Exception e) {  
e.printStackTrace();  
Toast.makeText(this, "Error: " + e.getMessage(), 0).show();  
}  
}  
```

So in conclusion, the code analysis did not give us too many good information.
The next thing to do is to look at the encoded audio file. We can extract it
with `JADX` or just use `7z` to extract the apk. when listening to the encoded
audio file a small noise is perceptible. This could be some sort of `LSB
steganography`.

To put this to a test I compared the wav samples of the original audio file
with the encoded one and indeed found only changes in the
[`LSB`](https://en.wikipedia.org/wiki/Bit_numbering#LSb_0_bit_numbering).

```python  
import wave

def load_samples(wav_file):  
# Get audio parameters  
sample_width = wav_file.getsampwidth()  
frame_rate = wav_file.getframerate()  
n_channels = wav_file.getnchannels()  
n_frames = wav_file.getnframes()

# Read the audio samples  
return bytearray(list(wav_file.readframes(n_frames)))

# Close the WAV file  
wav_file1 = wave.open("chaudio.wav", "rb")  
wav_file2 = wave.open("./assets/encoded_chaudio.wav", "rb")  
samples1 = load_samples(wav_file1)  
samples_encoded = load_samples(wav_file2);

for i in range(len(samples1)):  
if samples1[i] & 0x7e != samples_encoded[i] & 0x7e:  
print("bad byte")  
exit()

wav_file1.close()  
wav_file2.close()  
```

There are different approaches to hide data in the LSB. I tried different
approaches but eventually ran out of time and picked the challenge up after
the event.

Here the first 32 bits build up the encoded data size and the remaining bits
are the actual data. To extract I wrote this script.

```python  
# read data size  
data_size = 0  
pos = 0  
for i in range(32):  
data_size = ((samples_encoded[i] & 1) << i) | data_size  
pos = pos + 1

# read data  
data = bytearray()  
for i in range(data_size):  
value = 0  
for bit in range(8):  
value = ((samples_encoded[pos] & 1) << bit) | value  
pos = pos + 1  
data.append(value)

open("encrypted_data.png", "wb").write(data)  
```

![](https://raw.githubusercontent.com/D13David/ctf-
writeups/main/cyberheroines23/rev/maddie_stone/encrypted_data.png)

Flag `chctf{t53$p@$$35_h@ck!ng_$0c!3ty}`

Original writeup (https://github.com/D13David/ctf-
writeups/blob/main/cyberheroines23/rev/maddie_stone/README.md).