SekaiCTF 2025
All your droids are belong to us. Just driving by to see if I can still play around with Android apps.
SekaiBank
Signature
Search for flag in JADX, we get this:
1 | public interface ApiService { |
In com.sekai.bank.network.ApiClient, there is an interceptor that calculates request signatures based on the APK’s signature from system. Instead of getting around this, one can simply invoke getFlag using Frida.
Transaction
The condition for the flag to be sent is only when the user admin sends a million to the target user.
First glance of the application
Looking through AndroidManifest.xml, we have a MainActivity, two receivers that can’t be reached from outside, and a LogProvider that is marked with android:grantUriPermissions="true". This means that even though LogProvider is not exported, the application may temporarily grant permissions to other apps on a per-URI basis via special flags when calling startActivity. This may lead to security problems, as demonstrated by Oversecured.
LogProvider
query lists files from a directory using new File(getContext().getCacheDir(), uri.getPath()), making it vulnerable to directory traversal. openFile kinda mitigates this by checking whether .. is contained within the URI’s toString(). However, there is a critical difference between toString and getPath: the former does not decode %s in the URI, while the latter does. This means that by replacing .. with %2E%2E, it is sitll possible to reach any file in the scope of the victim app.
In addition, openFile returns a read + write file descriptor to the calling application, so it is possible for the caller to modify the file.
MainActivity
onCreate surely looks wrong?
1 | protected void onCreate(Bundle bundle) { |
To reach startActivity, we need:
from_pin_setup = truecontext = [some random thing]fallback = our intent
Delayed Transactions
Looking though DelayedTransactionManager, we can see that delayed transactions are saved on the disk as JSON files and loaded every time the alarm is triggered.
Therefore, the final objective is to modify the second delayed transaction to transfer 1,000,000 to our account. The full source code of solution is available at https://github.com/kmod-midori/SekaiBankExp.
- The arbitrary activity startup is used as a gadget to grant URI permissions of the non-exported
LogProviderto our app. - Using
queryandopenFile, we can obtain the path of the transaction and modify its contents.
SekaiCTF 2025