Rock Appround the Clock, la investigación presentada en DefCON

Área de Innovación y Laboratorio de Telefónica Tech    28 agosto, 2018
En el mundo del Threat Intelligence, determinar la localización geográfica del atacante es uno de los datos más valorados en las técnicas de atribución. Incluso si no es percibida como tal, esta información puede conducir una investigación en un sentido u otro. De dónde viene el autor, dónde vive o dónde se situaba el sistema en el momento del ataque, puede ser una información de gran valor en el juego de la atribución.

Hemos focalizado la investigación en cómo aprovechar estos problemas de “zona horaria” para perseguir a desarrolladores de malware para Android. Describimos dos formas efectivas para averiguar la zona horaria del atacante. También hemos calculado si estas circunstancias tienen relación real con el malware, investigando en nuestra base de datos de 10 millones de APKs.

AAPT time zone disclosure bug 

El Android app development kit (SDK para Android) viene con una herramienta llamada “aapt”. Este programa empaqueta los ficheros que van a componer la aplicación y genera el fichero .APK que fundamentalmente se corresponde con el formato zip.

Si la herramienta aapt se utiliza directamente por línea de comando o quizás a través de un plugin fuera de Android Studio, los ficheros que componen el APK serán generado con una fecha que seguirá el siguiente formato: 1980-01-01 [offset_GMT]:00:00. Donde [offset_GMT] representa la zona horaria que corresponde con la configuración del Sistema operativo donde ha sido empaquetada.

Esta figura representa un .APK muy simple generado por línea de comandos con aapt en un sistema con zona horaria configurada en GMT +3.

Offset GMT in the modified time field imagen
Offset
GMT in the modified time field

Normal
0

21

false
false
false

ES
X-NONE
X-NONE

/* Style Definitions */
table.MsoNormalTable
{mso-style-name:»Tabla normal»;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:»»;
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin-top:0cm;
mso-para-margin-right:0cm;
mso-para-margin-bottom:10.0pt;
mso-para-margin-left:0cm;
line-height:115%;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:»Calibri»,»sans-serif»;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:»Times New Roman»;
mso-bidi-theme-font:minor-bidi;
mso-fareast-language:EN-US;}

Como se aprecia, la hora de modificación en los ficheros es 01-01-80 y “03:00”, que corresponde al GMT +3. Observamos este caso en diferentes aplicaciones reales y con zonas horarias. ¿Por qué?

Durante el proceso en el que aapt añade un fichero al .APK, (ZipFile.cpp – line 358), se observa en la línea 500 una llamada a “setModWhen”, usando la variable “modWhen” como argumento.

Calling setModWhen in aapt source code imagen
Calling
setModWhen in aapt source code

Normal
0

21

false
false
false

EN-US
X-NONE
X-NONE

/* Style Definitions */
table.MsoNormalTable
{mso-style-name:»Tabla normal»;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:»»;
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin-top:0cm;
mso-para-margin-right:0cm;
mso-para-margin-bottom:8.0pt;
mso-para-margin-left:0cm;
line-height:107%;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:»Calibri»,sans-serif;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:»Times New Roman»;
mso-bidi-theme-font:minor-bidi;
mso-ansi-language:EN-US;
mso-fareast-language:EN-US;}

Pero, yendo hacia atrás en el código, no existe ninguna parte en la que “modWhen” obtenga un valor útil. Siempre vale “0” desde que inicialmente en la línea 367 se inicializa. (ZipFile.cpp – line 367):

Setting modWhen in aapt code imagen
Setting
modWhen in aapt code

Normal
0

21

false
false
false

EN-US
X-NONE
X-NONE

/* Style Definitions */
table.MsoNormalTable
{mso-style-name:»Tabla normal»;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:»»;
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin-top:0cm;
mso-para-margin-right:0cm;
mso-para-margin-bottom:8.0pt;
mso-para-margin-left:0cm;
line-height:107%;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:»Calibri»,sans-serif;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:»Times New Roman»;
mso-bidi-theme-font:minor-bidi;
mso-ansi-language:EN-US;
mso-fareast-language:EN-US;}

Por tanto, setModWhen se llamará siempre de esta manera:

pEntry->setModWhen(0);

Dentro de esta función (ZipEntry.cpp – line 340), la variable modWhen se usa en la línea 351 como parte de esta operación:

even = (time_t)(((unsigned long)(when) + 1) & (~1));

Que será llamada de esta forma, teniendo en cuenta el valor de “modWhen”:

even = (time_t)(((unsigned long)(0) + 1) & (~1));

El resultado será, obviamente, “0”. Este valor se almacenará en la variable “even” que se utilizará más tarde como argumento para la función “localtime” del sistema. Esta función permte crear la estructura para la echa “tm * ptm” y será usado para establecer la fecha y hora del campo, fecha en los ficheros añadidos al propio APK.

setModWhen function inside aapt source code imagen
setModWhen
function inside aapt source code.

Normal
0

21

false
false
false

EN-US
X-NONE
X-NONE

/* Style Definitions */
table.MsoNormalTable
{mso-style-name:»Tabla normal»;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:»»;
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin-top:0cm;
mso-para-margin-right:0cm;
mso-para-margin-bottom:8.0pt;
mso-para-margin-left:0cm;
line-height:107%;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:»Calibri»,sans-serif;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:»Times New Roman»;
mso-bidi-theme-font:minor-bidi;
mso-ansi-language:EN-US;
mso-fareast-language:EN-US;}

Debido a que este timestamp (variable “even”) utilizado como argumento para localtime no es válido, la fecha generada para los ficheros al final no es válida, sino que vale también 0. Existe una corrección para los años (porque en format PKzip la fecha inicial es el 1 de enero de 1980, no el 1 de enero de 1970) y finalmente, la función devuelve el formato descrito: “01-01-80 [offset_GMT]:00:00”.

En tiempo de ejecución, esta figura muestra cómo “even” vale 0 justo antes de que la función localtime reciba el argumento.

Variable “even” in runtime imagen
Variable
“even” in runtime

Normal
0

21

false
false
false

EN-US
X-NONE
X-NONE

/* Style Definitions */
table.MsoNormalTable
{mso-style-name:»Tabla normal»;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:»»;
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin-top:0cm;
mso-para-margin-right:0cm;
mso-para-margin-bottom:8.0pt;
mso-para-margin-left:0cm;
line-height:107%;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:»Calibri»,sans-serif;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:»Times New Roman»;
mso-bidi-theme-font:minor-bidi;
mso-ansi-language:EN-US;
mso-fareast-language:EN-US;}

El código continua y ahora divide el dato (day, month, year, hours, minutes y seconds) para ser utilizados por separado (en la impresión por pantalla, por ejemplo). La forma en la que localtime devuelve el resultado es: seconds, minutes, hours, day, month, y year. Esto es, por ejemplo, que en la posición primera (0x006A0E10) encontrarás 4 bytes para los segundos, y en la última (0x006A0E24) cuatro para el año.

Result from localtime function as in memory imagen
Result
from localtime function as in memory

Normal
0

21

false
false
false

EN-US
X-NONE
X-NONE

/* Style Definitions */
table.MsoNormalTable
{mso-style-name:»Tabla normal»;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:»»;
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin-top:0cm;
mso-para-margin-right:0cm;
mso-para-margin-bottom:8.0pt;
mso-para-margin-left:0cm;
line-height:107%;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:»Calibri»,sans-serif;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:»Times New Roman»;
mso-bidi-theme-font:minor-bidi;
mso-ansi-language:EN-US;
mso-fareast-language:EN-US;}

Siguiendo los colores en la figura, la información devuelta sería:

Con esto se concluye qué es la función localtime del sistema la que devuelve este offset (en este caso: +3), tomando este valor del sistema operativo. Aapt después redondeará el año a 01-01-80. La función localtime intentará adaptar cada fecha para la zona en la que el sistema se supone que está configurado.

Si nos fijamos en la documentación de la función localtime esto no debería pasar porque se especifica que si la función toma un valor 0 o null como argumento, el valor devuelto debería ser null. ¿En qué momento localtime toma el valor GMT y lo devuelve? Para los sistemas Windows, por ejemplo, la variable TZ (timezone) si no está aplicada en la propia aplicación, la función localtime intentará extraer la zona información de la zona horaria del sistema y la función irá a buscarlo cuando reciba cualquier valor, real o no como argumento. Un valor de timestamp inválido como “null” o “0”, se tomará como la hora “0” y lo que se devuelva contendrá el valor del desplazamiento GMT, que acaba donde debería ir la hora.

En UNIX/Linux también se da esta particularidad. Si un desarrollador utiliza appt por línea de comando, el desplazamiento GMT para su zona horaria será añadido a la fecha de modificación de dentro del APK. Centrándonos en el código fuente de aapt, la función setModWhen utiliza localtime_r en vez de localtime (el código es el mismo, solo depende del sistema operativo donde se ejecute), pero el argumento que se le pasa sigue siendo la variable “even” (con un valor de 0). Esta función es básicamente igual que en Windows, pero no existe el concepto de variable TZ para decidir: siempre se añadirá la zona horaria establecida en el sistema operativo.

¿Qué podemos concluir entonces? Localtime no está manejando los errores como debería. Al recibir un argumento 0 o null, debería devolver null, no un 0 más cualquier GMT configurado (TZ en el caso de Windows) añadido al valor. Por otro lado, aapt comete el error de usar el 0 como argumento “constante” para alimentar esta función.

GMT zone certificate calculation

Como se ha dicho, los ficheros .APK (y los .jar, para esta técnica en particular) siguen el estándar PKZIP. Esto es que son, en realidad, ficheros .zip que comparten la mayoría de las especificaciones PKZIP. En el caso en el que el APK se construya sin utilizar directamente aapt, habrá bastantes posibilidades de que los campos de fecha de modificación de los ficheros dentro del ZIP sean los correctos y no podamos aplicar la técnica descrita anteriormente. Sin embargo, hace algunos años, encontramos otro método que nos permitiría conocer la zona horaria donde el desarrollador compiló la aplicación, que podría ser utilizado como complementario al anterior. El método se basa en calcular la diferencia entre la fecha de los ficheros, y la fecha del certificado creado en el momento para firmarlo (esta fecha se almacena en formato UTC standard, de ahí que tenga referencias suficientes para calcular el huso horario).

UTC Time - ZIPs file gets the offset and thus, time zone imagen
UTC
Time – ZIPs file gets the offset and thus, time zone (map from
timeanddate.com).

Normal
0

21

false
false
false

EN-US
X-NONE
X-NONE

/* Style Definitions */
table.MsoNormalTable
{mso-style-name:»Tabla normal»;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:»»;
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin-top:0cm;
mso-para-margin-right:0cm;
mso-para-margin-bottom:8.0pt;
mso-para-margin-left:0cm;
line-height:107%;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:»Calibri»,sans-serif;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:»Times New Roman»;
mso-bidi-theme-font:minor-bidi;
mso-ansi-language:EN-US;
mso-fareast-language:EN-US;}

Relación con el malware

Hemos intentado establecer una relación entre:

  • Creadores de malware y adware, y la forma en la que compilan sus APKs (usando aapt por línea de comando).
  • Creadores de malware y adware, y la forma en la que utilizan certificados ad-hoc o desechables.

Para este experimento, tomamos 1000 ficheros (a menos que se indique lo contrario) de cada una que filtrase en cada zona horaria (1000 ficheros filtrando GMT+1, 1000 filtrando GMT+2… etc.) y buscamos malware en ellos.

con el bug de AAPT:

samples with AAPT Timezone disclosure imagen

Las columnas en verde no son representativas por existir muy pocas muestras.

Revelación por certificado desechable:

APKS with file/certificate datetimes (do not forget DST!) imagen

Así que podemos concluir que básicamente, GMT+4, GMT+5, GMT+8, GMT-6 y GMT-7 son las zonas horarias que producen más malware. ¿Por qué esta diferencia entre técnicas? Por ejemplo, con la primera fórmula las zonas horarias predominantes en malware son: GMT+4, GMT+8 and GMT-7. Con la técnica que involucre el certificado, GMT+5, GMT+8 and GMT-6 son las que producen más malware. Estos GMTs corresponden a partes de Rusia, China y la costa Oeste de Estados Unidos. Pensamos que esta diferencia se debe a Daylight Saving Time. Estas técnicas están sujetas al DST, por lo que varios países pueden tener +1 hora de diferencia dependiendo de la estación del año. China no utiliza DST (ni Rusia desde hace algunos años).

Además, sabemos que nuestra base de datos contiene un 6 % de malware en cualquier conjunto que tomemos. Si utilizamos esto como factor de corrección para comparar, finalmente obtenemos estos números:

comparison table imagen

Metadatos
Como una de las técnicas relacionadas con metadatos, mostramos cómo todas las cadenas automáticamente generadas con Android Studio están en componentes específicos creados por el propio IDE, mientras que las cadenas escritas por el propio desarrollador se encuentran en otros ficheros no asociados a ningún componente. Así, por ejemplo, al ejecutar:

./aapt dump –values resources app.APK | grep ‘^ *resource.*:string/’ –after-context=1 > output.txt

Extracting all the resources of an Android application, filtering by text strings. imagen
Extracting
all the resources of an Android application, filtering by text strings.

Normal
0

21

false
false
false

EN-US
X-NONE
X-NONE

/* Style Definitions */
table.MsoNormalTable
{mso-style-name:»Tabla normal»;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:»»;
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin-top:0cm;
mso-para-margin-right:0cm;
mso-para-margin-bottom:8.0pt;
mso-para-margin-left:0cm;
line-height:107%;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:»Calibri»,sans-serif;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:»Times New Roman»;
mso-bidi-theme-font:minor-bidi;
mso-ansi-language:EN-US;
mso-fareast-language:EN-US;}

Obtenemos las frases escritas por el propio desarrollador que, muy probablemente se encuentren en su idioma natal.

Conclusiones y trabajo futuro
Hemos presentado dos técnicas diferentes y complementarias que permiten conocer el huso horario de dónde se compiló una aplicación. Una de ellas, relacionada con aapt, no solo muestra un fallo en la forma en la que maneja las fechas, sino además un posible problema en la función de sistema localtime que no sigue las especificaciones. Esto podría afectar a otros programas de otras formas.
Estudiando estas técnicas, disponemos de una nueva fórmula para detectar malware creado de forma automática, analizando cómo y cuándo se crean los certificados para firmar estas apps. Además de las estadísticas para saber de dónde viene el malware a través del análisis de sus zonas horarias, esto podría ser utilizado como una importante funcionalidad de las técnicas de machine learning para una detección temprana del malware.

Además, hemos mostrado algunas herramientas para ver de un vistazo el resultado de aplicar estas técnicas y trucos y obtener información relevante a través de toda esta metainformación.
En un trabajo futuro, deberíamos abordar el hecho de ser más precisos con el DST, teniendo en cuenta la estación del año para clasificar el malware, e incluso añadir más muestras para obtener mejores conclusiones.

Esto es solo un resumen del estudio, que se puede encontrar completo aquí:

Deja una respuesta

Tu dirección de correo electrónico no será publicada.