MASTG-TECH-0100: Registro de Dados Sensíveis do Tráfego de Rede

mitmproxy pode ser usado para interceptar o tráfego de rede de aplicativos Android. Esta técnica é útil para identificar dados sensíveis que são enviados pela rede, bem como para identificar possíveis vulnerabilidades de segurança.

Com o mitmproxy instalado e seu dispositivo configurado para usá-lo, você pode criar um script em Python para filtrar o tráfego e extrair os dados sensíveis. Por exemplo, o seguinte script extrairá todos os dados enviados nas requisições e respostas apenas se os dados forem considerados sensíveis. Para este exemplo, consideramos dados sensíveis qualquer informação que contenha as strings "dummyPassword" ou "sampleUser", então as incluímos na lista SENSITIVE_STRINGS.

# mitm_sensitive_logger.py

from mitmproxy import http

# Esses dados viriam de outro arquivo e devem ser definidos após identificar o que é considerado sensível para este aplicativo.
# Por exemplo, usando a seção de Segurança de Dados da Google Play Store.
SENSITIVE_DATA = {
    "precise_location_latitude": "37.7749",
    "precise_location_longitude": "-122.4194",
    "name": "John Doe",
    "email_address": "john.doe@example.com",
    "phone_number": "+11234567890",
    "credit_card_number": "1234 5678 9012 3456"
}

SENSITIVE_STRINGS = SENSITIVE_DATA.values()

def contains_sensitive_data(string):
    return any(sensitive in string for sensitive in SENSITIVE_STRINGS)

def process_flow(flow):
    url = flow.request.pretty_url
    request_headers = flow.request.headers
    request_body = flow.request.text
    response_headers = flow.response.headers if flow.response else "No response"
    response_body = flow.response.text if flow.response else "No response"

    if (contains_sensitive_data(url) or 
        contains_sensitive_data(request_body) or 
        contains_sensitive_data(response_body)):
        with open("sensitive_data.log", "a") as file:
            if flow.response:
                file.write(f"RESPONSE URL: {url}\n")
                file.write(f"Response Headers: {response_headers}\n")
                file.write(f"Response Body: {response_body}\n\n")
            else:
                file.write(f"REQUEST URL: {url}\n")
                file.write(f"Request Headers: {request_headers}\n")
                file.write(f"Request Body: {request_body}\n\n")
def request(flow: http.HTTPFlow):
    process_flow(flow)

def response(flow: http.HTTPFlow):
    process_flow(flow)

Agora você pode executar o mitmproxy com o script:

mitmdump -s mitm_sensitive_logger.py

Nosso aplicativo de exemplo possui este código:

fun testPostRequest() {
    val thread = Thread {
        try {
            val url = URL("https://httpbin.org/post")
            val httpURLConnection = url.openConnection() as HttpURLConnection
            httpURLConnection.requestMethod = "POST"
            httpURLConnection.doOutput = true
            httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")

            val user = "sampleUser"
            val password = "dummyPassword"

            val postData = "username=$user&password=$password"

            val outputStream = BufferedOutputStream(httpURLConnection.outputStream)
            val bufferedWriter = BufferedWriter(OutputStreamWriter(outputStream, "UTF-8"))
            bufferedWriter.write(postData)
            bufferedWriter.flush()
            bufferedWriter.close()
            outputStream.close()

            val responseCode = httpURLConnection.responseCode
            if (responseCode == HttpURLConnection.HTTP_OK) {
                Log.d("HTTP_SUCCESS", "Successfully authenticated.")
            } else {
                Log.e("HTTP_ERROR", "Failed to authenticate. Response code: $responseCode")
            }

        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
    thread.start()
}

O aplicativo envia uma requisição POST para https://httpbin.org/post com o corpo username=sampleUser&password=dummyPassword. httpbin.org é um site que retorna os dados da requisição no corpo da resposta, então podemos ver os dados que foram enviados na requisição.

Execute o aplicativo e use-o normalmente. O script registrará quaisquer dados sensíveis enviados pela rede no arquivo sensitive_data.log.

Exemplo de saída no console:

[10:07:59.348] Loading script mitm_sensitive_logger.py
[10:07:59.351] HTTP(S) proxy listening at *:8080.
[10:08:08.188][127.0.0.1:64701] server connect httpbin.org:443 (52.206.94.89:443)
[10:08:08.192][127.0.0.1:64709] server connect mas.owasp.org:443 (104.22.27.77:443)
[10:08:08.245][127.0.0.1:64709] Client TLS handshake failed. The client does not trust the proxy's certificate for mas.owasp.org (OpenSSL Error([('SSL routines', '', 'ssl/tls alert certificate unknown')]))
[10:08:08.246][127.0.0.1:64709] client disconnect
[10:08:08.246][127.0.0.1:64709] server disconnect mas.owasp.org:443 (104.22.27.77:443)
127.0.0.1:64701: POST https://httpbin.org/post
              << 200 OK 548b

Exemplo de saída no sensitive_data.log:

REQUEST URL: https://httpbin.org/post
Request Headers: Headers[(b'Content-Type', b'application/x-www-form-urlencoded'), (b'User-Agent', b'Dalvik/2.1.0 (Linux; U; Android 13; sdk_gphone64_arm64 Build/TE1A.220922.021)'), (b'Host', b'httpbin.org'), (b'Connection', b'Keep-Alive'), (b'Accept-Encoding', b'gzip'), (b'Content-Length', b'42')]
Request Body: username=sampleUser&password=dummyPassword

RESPONSE URL: https://httpbin.org/post
Response Headers: Headers[(b'Date', b'Tue, 16 Jan 2024 09:08:08 GMT'), (b'Content-Type', b'application/json'), (b'Content-Length', b'548'), (b'Connection', b'keep-alive'), (b'Server', b'gunicorn/19.9.0'), (b'Access-Control-Allow-Origin', b'*'), (b'Access-Control-Allow-Credentials', b'true')]
Response Body: {
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "password": "dummyPassword", 
    "username": "sampleUser"
  }, 
  "headers": {
    "Accept-Encoding": "gzip", 
    "Content-Length": "42", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "Dalvik/2.1.0 (Linux; U; Android 13; sdk_gphone64_arm64 Build/TE1A.220922.021)", 
    "X-Amzn-Trace-Id": "Root=1-65a64778-78495e9f5d742c9b0c7a75d8"
  }, 
  "json": null, 
  "origin": "148.141.65.87", 
  "url": "https://httpbin.org/post"
}