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 = true
context = [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
LogProvider
to our app. - Using
query
andopenFile
, we can obtain the path of the transaction and modify its contents.
SekaiCTF 2025