July 17, 2026
DockerLabs Writeup — ApkAdmin (Spanish)
A continuación, describo la guía de resolución del laboratorio de DockerLabs denominado “ApkAdmin”.

By David Prieto Montero (a.k.a Pyth0nK1d)
12 min read
Este laboratorio está catalogado con la dificultad "Fácil" y su autor es "El Pingüino de Mario".
ATENCIÓN
Las herramientas y técnicas utilizadas en la resolución de este laboratorio han sido ejecutadas en un entorno controlado. El autor de esta publicación no se hace responsable del mal uso que se haga de estas, ya que el objetivo final de esta publicación es transmitir conocimientos con fines éticos y educativos.
Resumen de contenido sobre este laboratorio
Tags: Actividad exportada (Exported Activity), Android, Bug Bounty, Contraseña débil, Divulgación de información, Dynamic Application Security Testing (DAST), Mobile Application Security Testing (MAST), Reutilización de contraseñas, Seguridad en aplicaciones móviles, Static Application Security Testing (SAST)
Antes de comenzar, se indica un resumen de contenido que se puede encontrar en esta guía:
- Realización de SAST sobre una aplicación Android. Detección de una actividad que permite ser exportada. Dicha actividad contiene las credenciales en texto plano para poder realizar el acceso inicial al sistema a través de SSH como el usuario
pingu. - Se detecta una reutilización de contraseñas entre cuentas del sistema que permite escalar privilegios al contexto del usuario
root. - Realización de DAST sobre la misma aplicación Android para explotar la actividad exportada encontrada previamente, obteniendo las mismas credenciales.
- Guía adicional documentada sobre cómo iniciar un emulador Android sin instalar Android Studio.
Reconocimiento inicial
Se inicia el reconocimiento mediante un ping a la máquina. Esto se hace por un lado para detectar que la máquina se encuentra accesible y por otro lado para poder detectar el sistema operativo mediante el TTL asignado.
ping -c 1 172.17.0.2ping -c 1 172.17.0.2
Se puede comprobar que el TTL asignado es 64, indicando que la máquina está accesible directamente sin ningún nodo intermediario y por otro lado que el sistema subyacente es GNU/Linux.
Una vez hecho esto, se realiza un reconocimiento de los servicios disponibles en dos fases. En la primera, se realiza un escaneo de todos los puertos TCP usando nmap para detectar en primera instancia cuales de ellos son accesibles (open), utilizando un escaneo TCP SYN.
sudo nmap -sS -p- --min-rate 1000 -n -Pn 172.17.0.2 -oN allPortssudo nmap -sS -p- --min-rate 1000 -n -Pn 172.17.0.2 -oN allPorts
En la segunda, se realiza un reconocimiento básico de los servicios subyacentes también mediante el uso de nmap. Esta vez, realizando dicha tarea de reconocimiento únicamente en los puertos detectados como abiertos.
nmap -sCV -p 22,80 -n -Pn 172.17.0.2 -oN servicesnmap -sCV -p 22,80 -n -Pn 172.17.0.2 -oN services
En este caso, se omite el escaneo de puertos UDP, ya que para esta máquina en particular no tiene ningún servicio relevante para llevar a cabo el ejercicio.
Acceso inicial (pingu)
En este caso se detecta que hay dos puertos abiertos:
- Puerto 22 (servicio SSH, OpenSSH)
- Puerto 80 (servicio HTTP, SimpleHTTPServer/Python)
Al revisar el puerto 80, se detecta una página donde explica en que consiste este reto.
URL: http://172.17.0.2URL: http://172.17.0.2
En esta explica al detalle que hay que hacer, explica el recurso que se debe descargar para analizarse (en este caso un archivo .apk), incluso lo que hay que hacer para escalar privilegios una vez se consigue acceso inicial.
Por el momento, se descarga el archivo .apk que ofrece la web para analizarlo más detenidamente.
En resumen, un archivo .apk (Android Package Kit) es el formato de distribución e instalación de aplicaciones para Android. Contiene todos los recursos necesarios para instalar y ejecutar una aplicación, como el código compilado, recursos gráficos, bibliotecas, el archivo AndroidManifest.xml y otros archivos de configuración. Al instalar un APK, el sistema Android extrae y despliega estos componentes para que la aplicación pueda ejecutarse correctamente.
ls -al AdminBypassCTF.apk
file AdminBypassCTF.apkls -al AdminBypassCTF.apk
file AdminBypassCTF.apk
Desde este punto, se decide realizar un análisis estático o SAST de la aplicación Android, es decir, se procede a revisar tanto su configuración como código fuente sin ejecutarla.
Para ello, se instala la herramienta denominada "jadx". Es una herramienta de ingeniería inversa que permite descompilar archivos ".apk" y visualizar su código fuente en Java. Se utiliza para analizar aplicaciones Android e identificar configuraciones y posibles vulnerabilidades sin ejecutarlas.
sudo apt install jadx
jadx --versionsudo apt install jadx
jadx --version
Para abrir los recursos dentro del archivo .apk, basta con utilizar la versión con interfaz de la herramienta para una inspección más cómoda.
jadx-gui AdminBypassCTF.apk &jadx-gui AdminBypassCTF.apk &
Tras revisar el archivo "AndroidManifest.xml" se detecta una actividad exportada que parece corresponder a un área crítica de la aplicación.
En resumen, una actividad exportada o exported activity es una actividad de una aplicación Android que está configurada para poder ser iniciada por otras aplicaciones o por el propio sistema operativo. Esto se controla mediante el atributo android:exported en el archivo "AndroidManifest.xml".
Este atributo puede ser peligroso porque, si no cuenta con mecanismos de protección (como permisos o validaciones robustas), una aplicación maliciosa podría invocarla directamente y acceder a funcionalidades internas, manipular datos o provocar comportamientos no previstos. Esto puede dar lugar a vulnerabilidades como acceso no autorizado, filtración de información o escalada de privilegios dentro de la aplicación.
Para más información, se facilitan referencias a recursos oficiales dónde se explica en más detalle qué es cada uno de los elementos comentados.
Referencia (AndroidManifest.xml): https://developer.android.com/guide/topics/manifest/manifest-intro
Referencia (Activity): https://developer.android.com/reference/android/app/Activity
Referencia (android:exported): https://developer.android.com/privacy-and-security/risks/android-exported
Resources > AndroidManifest.xml
<activity
android:name="com.ctf.adminbypass.AdminActivity"
android:exported="true"/>Referencia (AndroidManifest.xml): https://developer.android.com/guide/topics/manifest/manifest-intro
Referencia (Activity): https://developer.android.com/reference/android/app/Activity
Referencia (android:exported): https://developer.android.com/privacy-and-security/risks/android-exported
Resources > AndroidManifest.xml
<activity
android:name="com.ctf.adminbypass.AdminActivity"
android:exported="true"/>
Al revisar el código fuente de esta actividad, se detectan dos elementos de interés dentro de su método "onCreate":
- La protección que ofrece para el contenido protegido de esta actividad es un extra booleano facilitado mediante un Intent con un nombre bastante predecible con el que determina si el usuario es administrador o no, lo que es una aproximación bastante insegura de base.
- El contenido protegido de la parte administrativa es directamente visible, lo que hace posible descubrir unas credenciales en texto plano que sirven para acceder por SSH.
Referencia (Intent): https://developer.android.com/guide/components/intents-filters
Source code > com > ctf.adminbypass > AdminActivity
...
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_admin);
TextView flagView = (TextView) findViewById(R.id.textFlag);
boolean isAdmin = getIntent().getBooleanExtra("isAdmin", false);
if (isAdmin) {
flagView.setText("Acceso SSH\n\nUsuario: pingu\nContrasena: <RECORTADO>");
} else {
Toast.makeText(this, R.string.access_denied, 0).show();
finish();
}
}Referencia (Intent): https://developer.android.com/guide/components/intents-filters
Source code > com > ctf.adminbypass > AdminActivity
...
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_admin);
TextView flagView = (TextView) findViewById(R.id.textFlag);
boolean isAdmin = getIntent().getBooleanExtra("isAdmin", false);
if (isAdmin) {
flagView.setText("Acceso SSH\n\nUsuario: pingu\nContrasena: <RECORTADO>");
} else {
Toast.makeText(this, R.string.access_denied, 0).show();
finish();
}
}
Al disponer de las credenciales en texto plano, es posible acceder al sistema a través de SSH como el usuario "pingu".
ssh pingu@172.17.0.2
yes (aceptar conexión sin comprobar autenticidad)
<introducir la contraseña descubierta>
whoami
id
hostnamessh pingu@172.17.0.2
yes (aceptar conexión sin comprobar autenticidad)
<introducir la contraseña descubierta>
whoami
id
hostname
Escalada de privilegios (pingu -> root)
Tras probar, resulta que el usuario "root" reutiliza las credenciales del usuario "pingu", permitiendo acceder directamente a este.
su - root
(introducir la contraseña de "pingu")
whoami
id
hostnamesu - root
(introducir la contraseña de "pingu")
whoami
id
hostname
En este punto, al haber obtenido acceso a la cuenta "root", se ha conseguido obtener los máximos privilegios posibles sobre el sistema objetivo (este laboratorio).
BONUS 1: Obteniendo las credenciales SSH mediante análisis dinámico de la aplicación
En este punto queda investigar la otra forma de obtener el mismo resultado, y este consiste en realizar un análisis dinámico o DAST de la aplicación Android.
Para ello, se instala Android Studio para disponer de las herramientas necesarias.
Referencia (Android Studio): https://developer.android.com/studioReferencia (Android Studio): https://developer.android.com/studioUna vez instalado, se accede al gestor de dispositivos virtuales a través de la opción "More Actions".
Desde aquí, pulsar el botón "+" para que muestre el menú y poder añadir nuevos dispositivos. Luego se busca "Pixel 6" y se selecciona el que no tenga acceso a la Play Store.
Nota importante: No es relevante el dispositivo seleccionado, solo tener en cuenta no elegir uno muy antiguo para no tener problemas de compatibilidad.
A continuación seleccionar una API para poder elegir una imagen específica, en este caso se selecciona la "33".
Una vez seleccionado y confirmada la configuración, se procede a su descarga e instalación.
Al finalizar el proceso de instalación, se puede comprobar dentro de la lista de dispositivos el nuevo dispositivo virtual instalado.
Al pulsar el botón "Play" de la parte derecha, el dispositivo virtual arranca desbloqueado, listo para su uso.
Recurriendo a la utilidad "adb" (la cual se instala por defecto junto con Android Studio), se puede comprobar que existe un nuevo dispositivo (es decir, el dispositivo virtual establecido) conectado al ordenador y con el cual es posible interactuar a través de esta.
En resumen, la utilidad "adb" o Android Debug Bridge es una herramienta de línea de comandos que permite comunicar un ordenador con un dispositivo Android. Sirve para instalar aplicaciones, ejecutar comandos, acceder al sistema, capturar registros y realizar pruebas y depuración de aplicaciones.
Referencia (Android Debug Bridge [ADB]): https://developer.android.com/tools/adb
adb devices
...
List of devices attached
emulator-5554 deviceReferencia (Android Debug Bridge [ADB]): https://developer.android.com/tools/adb
adb devices
...
List of devices attached
emulator-5554 deviceA través de esta se instala la aplicación Android mediante el APK en el dispositivo virtual.
adb install -r AdminBypassCTF.apk
...
Performing Streamed Install
Successadb install -r AdminBypassCTF.apk
...
Performing Streamed Install
SuccessUna vez termine la instalación, se puede comprobar que el dispositivo virtual dispone de una nueva aplicación instalada.
Al abrir la nueva aplicación, se puede comprobar que esta muestra un formulario de login nada mas iniciarla.
Revisando nuevamente el código fuente de la aplicación, se puede comprobar que la actividad "MainActivity" es la encargada de gestionar este formulario de login.
Casualmente tiene las credenciales en texto plano definidas en variables dentro de la propia clase.
Source code > com > ctf.adminbypass > MainActivity
...
public final class MainActivity extends AppCompatActivity {
private final String validUser = "admin";
private final String validPassword = "<RECORTADO>";
...
}Source code > com > ctf.adminbypass > MainActivity
...
public final class MainActivity extends AppCompatActivity {
private final String validUser = "admin";
private final String validPassword = "<RECORTADO>";
...
}
Esto permite introducir credenciales válidas en el formulario para saltar el login. Esto resuelve en una actividad que da la bienvenida al usuario y que no contiene nada más.
Se puede comprobar de esta forma que la actividad "AdminActivity" no es accesible a través del flujo normal de la aplicación. Sin embargo, como se ha analizado anteriormente aparece como "exportada", haciendo que sea posible acceder a esta directamente.
Para ello, es posible recurrir una vez más a la utilidad "adb" para indicar al dispositivo qué actividad concreta iniciar, **además de especificar un extra booleano con el valor esperado por la actividad objetivo, facilitado mediante un **Intent.
adb shell am start -n com.ctf.adminbypass/.AdminActivity --ez isAdmin true
...
Starting: Intent { cmp=com.ctf.adminbypass/.AdminActivity (has extras) }adb shell am start -n com.ctf.adminbypass/.AdminActivity --ez isAdmin true
...
Starting: Intent { cmp=com.ctf.adminbypass/.AdminActivity (has extras) }Esto hará que, tras cumplir con la condición de la actividad, el dispositivo muestre la parte protegida de la actividad al instante, la cual contiene las credenciales SSH encontradas anteriormente.
BONUS 2: Ejecución del emulador sin instalar Android Studio (para inconformistas y curiosos)
En este punto el laboratorio ya quedaría resuelto, pero se muestra a continuación los pasos que habría que seguir para ejecutar un emulador de un dispositivo Android sin necesidad de instalar Android Studio (que generalmente incluye más herramientas de las necesarias).
Para ello, se procede a descargar las herramientas de línea de comando que se ofrece desde la página oficial de Android.
Referencia: https://developer.android.com/tools/
Descarga: https://developer.android.com/studio#command-line-tools-onlyReferencia: https://developer.android.com/tools/
Descarga: https://developer.android.com/studio#command-line-tools-onlyLo único que se debe tener en cuenta es que estos emuladores no pueden ser ejecutados desde una máquina virtual y deben ser ejecutados desde el propio ****host, tal y como indican sus restricciones documentadas.
Referencia (Restricciones): https://developer.android.com/studio/run/emulator-acceleration#vm-accel-restrictionsReferencia (Restricciones): https://developer.android.com/studio/run/emulator-acceleration#vm-accel-restrictionsUna vez descargado, se comprueba su suma de verificación por seguridad.
file commandlinetools-linux-14742923_latest.zip
echo "48833c34b761c10cb20bcd16582129395d121b27 commandlinetools-linux-14742923_latest.zip" | sha1sum -c -
...
commandlinetools-linux-14742923_latest.zip: OKfile commandlinetools-linux-14742923_latest.zip
echo "48833c34b761c10cb20bcd16582129395d121b27 commandlinetools-linux-14742923_latest.zip" | sha1sum -c -
...
commandlinetools-linux-14742923_latest.zip: OK
Tras una verificación correcta, se descomprime y se ubica la raíz del paquete extraído.
unzip commandlinetools-linux-14742923_latest.zip
ls -al cmdline-toolsunzip commandlinetools-linux-14742923_latest.zip
ls -al cmdline-tools
El siguiente paso consiste en mover todos los elementos de la raíz a un subdirectorio. Esto es necesario para que ciertas herramientas funcionen adecuadamente. No es necesario especificar la versión concreta, con denominarla "latest" es suficiente.
cd cmdline-tools
mkdir latest && find . -mindepth 1 -maxdepth 1 ! -name latest -exec mv -t latest {} +
ls -al
ls -al latestcd cmdline-tools
mkdir latest && find . -mindepth 1 -maxdepth 1 ! -name latest -exec mv -t latest {} +
ls -al
ls -al latest
A continuación, se definen las variables de entorno necesarias en el archivo ".rc" correspondiente.
En este caso se hace de forma temporal y orientado a este laboratorio únicamente, pero en el caso de que se quiera una instalación más estable, se puede definir en un directorio separado tanto las herramientas como los archivos generados tras la ejecución de las herramientas.
Referencia (Definición de variables de entorno): https://developer.android.com/tools/variables#set
mousepad ~/.zshrc
# ~/.zshrc
(AÑADIR AL FINAL)
...
export ANDROID_HOME=$HOME/DockerLabs/ApkAdmin/assessment
export ANDROID_SDK_ROOT=$ANDROID_HOME
export ANDROID_AVD_HOME=$ANDROID_HOME/avd
export PATH=$PATH:$ANDROID_HOME/platform-tools
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin
export PATH=$PATH:$ANDROID_HOME/emulatorReferencia (Definición de variables de entorno): https://developer.android.com/tools/variables#set
mousepad ~/.zshrc
# ~/.zshrc
(AÑADIR AL FINAL)
...
export ANDROID_HOME=$HOME/DockerLabs/ApkAdmin/assessment
export ANDROID_SDK_ROOT=$ANDROID_HOME
export ANDROID_AVD_HOME=$ANDROID_HOME/avd
export PATH=$PATH:$ANDROID_HOME/platform-tools
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin
export PATH=$PATH:$ANDROID_HOME/emulatorPor último, recargar la configuración para que se aplique en la sesión de la línea de comandos actual.
source ~/.zshrc
env -> para comprobar que se encuentran asignadas las nuevas variablessource ~/.zshrc
env -> para comprobar que se encuentran asignadas las nuevas variablesEn este punto, es posible comprobar que la utilidad "sdkmanager" funciona comprobando su versión.
En resumen, la utilidad sdkmanager es una herramienta de línea de comandos que permite gestionar los paquetes del Android SDK. Sirve para consultar, instalar, actualizar y desinstalar componentes del SDK necesarios para el desarrollo de aplicaciones Android. Esta herramienta permite instalar justo los paquetes necesarios y ninguno extra más.
Referencia (sdkmanager): https://developer.android.com/tools/sdkmanager
sdkmanager --version
...
20.0Referencia (sdkmanager): https://developer.android.com/tools/sdkmanager
sdkmanager --version
...
20.0
Luego, se revisan, leen y aceptan las licencias disponibles para poder utilizarse, ya que es un paso obligatorio.
Referencia (Aceptar licencias de paquetes): https://developer.android.com/tools/sdkmanager#accept-licenses
sdkmanager --licenses
(leer y aceptar licencias)
sdkmanager --licensesReferencia (Aceptar licencias de paquetes): https://developer.android.com/tools/sdkmanager#accept-licenses
sdkmanager --licenses
(leer y aceptar licencias)
sdkmanager --licenses
A continuación es posible revisar los paquetes que se encuentran disponibles para poder instalarse.
Referencia (Listar paquetes): https://developer.android.com/tools/sdkmanager#listReferencia (Listar paquetes): https://developer.android.com/tools/sdkmanager#listComo en este caso se quiere iniciar un emulador, se instalan los paquetes básicos junto a la plataforma e imagen del emulador deseado, en este caso se muestran de la lista los paquetes seleccionados a instalar.
sdkmanager --list | grep "platform-tools"
sdkmanager --list | grep "emulator"
sdkmanager --list | grep "platforms;android-35"
sdkmanager --list | grep "system-images;android-35;google_apis;<RECORTADO>"sdkmanager --list | grep "platform-tools"
sdkmanager --list | grep "emulator"
sdkmanager --list | grep "platforms;android-35"
sdkmanager --list | grep "system-images;android-35;google_apis;<RECORTADO>"
Una vez conociendo el nombre específico de cada paquete, se procede a su instalación. Una vez termine, se comprueba que se han instalado correctamente.
sdkmanager "platform-tools" "emulator" "platforms;android-35" "system-images;android-35;google_apis;<RECORTADO>"
sdkmanager --list_installedsdkmanager "platform-tools" "emulator" "platforms;android-35" "system-images;android-35;google_apis;<RECORTADO>"
sdkmanager --list_installed
En este punto, es posible crear un dispositivo virtual de Android tal y como se ha hecho con Android Studio, pero esta vez aprovechando la utilidad "avdmanager".
En resumen, la utilidad avdmanager es una herramienta de línea de comandos que permite crear y gestionar Android Virtual Devices** (AVD)**. Sirve para configurar, modificar, eliminar y consultar dispositivos virtuales que se utilizan para ejecutar y probar aplicaciones Android en el emulador.
Referencia (avdmanager): https://developer.android.com/tools/avdmanager
mkdir -p "$ANDROID_AVD_HOME" -> asegurarse que el directorio donde se crean los dipositivos virtuales existe
avdmanager list avd
avdmanager create avd -n ApkAdmin-Inspector -k "system-images;android-35;google_apis;<RECORTADO>"
...
Do you wish to create a custom hardware profile? [no] no
avdmanager list avdReferencia (avdmanager): https://developer.android.com/tools/avdmanager
mkdir -p "$ANDROID_AVD_HOME" -> asegurarse que el directorio donde se crean los dipositivos virtuales existe
avdmanager list avd
avdmanager create avd -n ApkAdmin-Inspector -k "system-images;android-35;google_apis;<RECORTADO>"
...
Do you wish to create a custom hardware profile? [no] no
avdmanager list avd
Una vez el dispositivo virtual se encuentra creado, solo queda iniciarlo utilizando el emulador.
En resumen, la utilidad emulator es una herramienta de línea de comandos que permite ejecutar un Android Virtual Device** (AVD)** en un ordenador. Sirve para simular un dispositivo Android real, permitiendo probar aplicaciones, ejecutar el sistema operativo y realizar pruebas sin necesidad de un dispositivo físico.
Referencia (emulator from command line): https://developer.android.com/studio/run/emulator-commandlineReferencia (emulator from command line): https://developer.android.com/studio/run/emulator-commandlinePara ello, primero se comprueba que existen dispositivos disponibles para ser emulados.
emulator -list-avds
...
ApkAdmin-Inspectoremulator -list-avds
...
ApkAdmin-Inspector
Una vez conocido el nombre del dispositivo virtual a emular, se arranca usando el emulador.
emulator -avd ApkAdmin-Inspectoremulator -avd ApkAdmin-InspectorUna vez haya arrancado el dispositivo virtual, es posible interactuar con este mediante la utilidad "adb" de la misma forma que se ha hecho en la anterior sección.
Nota importante a considerar: Es necesario tener en cuenta las restricciones de virtualización indicadas por Android para la aceleración del emulador indicado al principio de esta sección. La disponibilidad de esta aceleración depende del hardware del equipo, del sistema operativo, del hipervisor utilizado y de la configuración del AVD que se ejecute. Además de ser necesario tener habilitada la virtualización en la configuración del sistema, puede requerir ajustes en el entorno de virtualización o modificar determinados parámetros del emulador y del dispositivo virtual para permitir que el AVD utilice la aceleración correctamente. El comportamiento y desempeño final dependerá del sistema y de los recursos disponibles.
Mitigaciones a aplicar
- Para evitar cualquier imprevisto con respecto al atributo
android:exported, establecerlo explícitamente comoandroid:exported="false"en todos los componentes que no necesiten ser accesibles desde otras aplicaciones. Si un componente debe exportarse porque el caso de uso lo requiera, protegerlo mediante permisos y controles de acceso adecuados. - Almacenar la información sensible de forma segura (por ejemplo, utilizando gestores de contraseñas), evitando que esta pueda ser accedida por usuarios no autorizados. Evitar mostrar o "hardcodear" en código credenciales en recursos accesibles o que potencialmente puedan acabar publicados.
- Evitar que los usuarios del sistema u otros servicios tengan como contraseña una que se pueda encontrar en listas públicas o conocidas como rockyou. Recomendación: crear una política de contraseñas robusta para evitar que esto ocurra.
- Evitar malas prácticas como la reutilización de contraseñas entre cuentas o servicios.
¿Te gustó esta publicación? Sígueme y descubre más en mi blog principal: https://pyth0nk1d.medium.com