Food Store

“Food Store 😋…”

Introdução

Esta é uma resolução do desafio do Mobile Hacking Lab
onde descobri recentemente que eles estão oferecendo treinamento e laboratórios gratuitos para explorar e praticar suas habilidades de hacking mobile. Então, decidi fazer o curso e praticar os laboratórios.

Objetivo

Explorar uma vulnerabilidade de SQL injection, que permita que você se registre como um usuário PRO, ignorando as restrições de usuário padrão.



Writeup

Quando iniciei o aplicativo, criei um usuário e depois fiz login. Notei que meu usuário tinha 100 créditos e foi classificado como um usuário comum.

Primeiro, comecei a fazer engenharia reversa e abri o aplicativo usando o jadx-gui.

AndroidManifest.xml

<activity  
	android:name="com.mobilehackinglab.foodstore.Signup"  
	android:exported="false"/>  
<activity  
	android:name="com.mobilehackinglab.foodstore.MainActivity"  
	android:exported="true"/>  
<activity  
	android:name="com.mobilehackinglab.foodstore.LoginActivity"  
	android:exported="true">  
	<intent-filter>  
		<action android:name="android.intent.action.MAIN"/>  
		<category android:name="android.intent.category.LAUNCHER"/>  
	</intent-filter>  
</activity>

Não havia muito o que ver no arquivo AndroidManifest.xml - apenas três activities, e somente duas delas estavam exportadas.

O objetivo desse desafio é claro: registrar-se como um usuário PRO. Então, comecei examinando o processo singup para entender melhor como funciona o registro de usuários.


Percebi que o método addUser na classe dbHelper passa um objeto newUser como argumento, então decidi investigar como o usuário está sendo criado.

Aqui está o trecho de código addUser:

public final void addUser(User user) {  
	Intrinsics.checkNotNullParameter(user, "user");  
	SQLiteDatabase db = getWritableDatabase();  
	byte[] bytes = user.getPassword().getBytes(Charsets.UTF_8);  
	Intrinsics.checkNotNullExpressionValue(bytes, "this as java.lang.String).getBytes(charset)");  
	String encodedPassword = Base64.encodeToString(bytes, 0);  
	String Username = user.getUsername();  
	byte[] bytes2 = user.getAddress().getBytes(Charsets.UTF_8);  
	Intrinsics.checkNotNullExpressionValue(bytes2, "this as java.lang.String).getBytes(charset)");  
	String encodedAddress = Base64.encodeToString(bytes2, 0);  
	String sql = "INSERT INTO users (username, password, address, isPRO) VALUES ('" + Username + "', '" + encodedPassword + "', '" + encodedAddress + "', 0)";  
	db.execSQL(sql);  
	db.close();  
}

As variáveis Username, encodedPassword e encodedAddress estão concatenadas. Esse é um exemplo claro de SQL injection.

Coisas importantes a serem mencionadas:

  • O único valor que pode ser controlado é o nome de usuário, pois essa variável não é codificada em base64.
  • O último valor, 0, está chumbado para indicar se o usuário é um usuário PRO ou não.

Payload

Durante a criação do payload, monitorei o logcat em busca de mensagens de erro SQL. Como o aplicativo está definido como debuggable=“true”, ele fornece informações mais detalhadas nos registros de log.

Quando tentei criar um usuário chamado SuperUser e adicionei uma aspa simples, recebi uma mensagem de erro nos logs.


Agora que entendi como a consulta está sendo construída, só preciso recriá-la para me registrar como um usuário PRO.

Para explicar melhor, aqui está uma comparação entre a consulta SQL e meu payload:

A consulta: VALUES ('“ + Username + ‘’, ‘” + encodedPassword + “’, ‘” + encodedAddress + “’, 0);

Meu payload: VALUES ('parad0x', 'MTIz', 'YWJj', '1'); --

Simplesmente adicionei uma aspa simples para fechar o campo de nome de usuário, incluí os valores codificados em base64 para a senha e o endereço, alterei o valor final de 0 para 1 para tornar o usuário um PRO e, em seguida, fechei a consulta e adicionei -- para comentar o restante da consulta original.


Meu usuário agora é PRO.


Bonus

Durante a engenharia reversa, também encontrei uma maneira de obter mais créditos e ter um usuário PRO “temporário” usando a Intent declarada dentro da LoginActivity e enviando os valores extras por meio do ADB.


Abaixo eu deixei um vídeo da PoC para a demonstração dessa execução!

Referências