MASTG-TECH-0100: 从网络流量中记录敏感数据
可以使用 mitmproxy 拦截来自 Android 应用的网络流量。此技术对于识别通过网络发送的敏感数据以及识别潜在的安全漏洞非常有用。
一旦安装了 mitmproxy 并将您的设备配置为使用它,您可以创建一个 Python 脚本来过滤流量并提取敏感数据。 例如,以下脚本将提取请求和响应中发送的所有数据,前提是这些数据被认为是敏感的。 在此示例中,我们将包含字符串“dummyPassword”或“sampleUser”的任何数据都视为敏感数据,因此我们将它们包含在 SENSITIVE_STRINGS
列表中。
# mitm_sensitive_logger.py
from mitmproxy import http
# This data would come from another file and should be defined after identifying the data that is considered sensitive for this application.
# For example by using the Google Play Store Data Safety section.
SENSITIVE_DATA = {
"precise_location_latitude": "37.7749",
"precise_location_longitude": "-122.4194",
"name": "John Doe",
"email_address": "[email protected]",
"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)
现在你可以使用脚本运行 mitmproxy
mitmdump -s mitm_sensitive_logger.py
我们的示例应用有以下代码
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()
}
该应用向 https://httpbin.org/post
发送一个 POST 请求,正文为 username=sampleUser&password=dummyPassword
。 httpbin.org
是一个网站,它在响应正文中返回请求数据,因此我们可以看到请求中发送的数据。
运行该应用并像往常一样使用它。 该脚本会将通过网络发送的任何敏感数据记录到 sensitive_data.log
文件中。
示例控制台输出
[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
示例 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"
}