Android перехватывает HTTPS-трафик с помощью Frida

Я пытаюсь научить Фриду подключаться к различным приложениям. В частности, я пытаюсь подключиться к приложениям Android, я использую проект Appmon. Этот проект имеет сценарий HTTPS.js, который подключается к getInputStream и getOutputStream из класса HttpUrlConnection. Сценарий HTTPS.js успешно перехватывает методы, но когда отправляется трафик HTTPS, данные, которые я вижу, зашифрованы.

Согласно документации Android по HTTPUrlConnection, если метод URL.openconnection() получает URL-адрес HTTPS, он возвращает объект HTTPSUrlConnection.

Документация Android для HttpsURLConnection гласит, что это абстрактный класс, расширяющий HttpURLConnection.

открытый абстрактный класс HttpsURLConnection расширяет HttpURLConnection

Я искал исходный код Android и обнаружил, что HttpsURLConnection является абстрактным и расширен делегированием HttpsURLConnection, который также является абстрактным. Делегирование HttpsURLConnection расширяется с помощью HttpsURLConnectionImpl

Я подключился

com.android.okhttp.internal.huc.HttpsURLConnectionImpl

что успешно, но данные все еще зашифрованы. Вот код

var HttpsURLConnection = Java.use("com.android.okhttp.internal.huc.HttpsURLConnectionImpl");

HttpsURLConnection.getInputStream.overloads[0].implementation = function() {
try {
  methodURL = "";
responseHeaders = "";
responseBody = "";
var Connection = this;
var stream = stream = this.getInputStream.overloads[0].apply(this, arguments);

var requestURL = Connection.getURL().toString();
var requestMethod = Connection.getRequestMethod();
var requestProperties
methodURL = requestMethod + " " + requestURL;
if (Connection.getHeaderFields) {
  var Keys = Connection.getHeaderFields().keySet().toArray();
  var Values = Connection.getHeaderFields().values().toArray();
  responseHeaders = "";
  for (var key in Keys) {
    if (Keys[key] && Keys[key] !== null && Values[key]) {
      responseHeaders += Keys[key] + ": " + Values[key].toString().replace(/\[/gi, "").replace(/\]/gi, "") + "\n";
    } else if (Values[key]) {
      responseHeaders += Values[key].toString().replace(/\[/gi, "").replace(/\]/gi, "") + "\n";
    }
  }
}
var retval;
if (stream) {
  var baos = ByteArrayOutputStream.$new();
  var buffer = -1;

  var BufferedReaderStream = BufferedReader.$new(InputStreamReader.$new(stream));
  while ((buffer =stream.read()) != -1){
      baos.write(buffer);
      responseBody += String.fromCharCode(buffer);
   }
BufferedReaderStream.close();
baos.flush();
retval = ByteArrayInputStream.$new(baos.toByteArray());

}
/*   --- Payload Header --- */


var send_data = {};
send_data.time = new Date();
send_data.txnType = 'HTTPS';
send_data.lib = 'com.android.okhttp.internal.huc.HttpsURLConnectionImpl';
send_data.method = 'getInputStream';
send_data.artifact = [];
/*   --- Payload Body --- */
var data = {};
data.name = "Request/Response";
data.value = methodURL + "\n" + requestHeaders + "\n" + requestBody + "\n\n" + responseHeaders + "\n" + responseBody;
data.argSeq = 0;
send_data.artifact.push(data);
send(JSON.stringify(send_data));

if(retval)
    return retval;
return stream;
} catch (e) {
  this.getInputStream.overloads[0].apply(this, arguments);
}
}

Кстати, я планирую подать запрос на получение, как только я получу эту работу.

В документации Android есть пример того, как создать HTTP-запрос:

URL url = new URL("https://wikipedia.org");
URLConnection urlConnection = url.openConnection();
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);

Прочтение этого говорит мне, что простой вызов метода getInputStream() должен вернуть поток открытого текста, но, похоже, он этого не делает.

Вопрос: Как я могу получить данные открытого текста из трафика HTTPS? Я вижу заголовки, но не фактические данные

Обновление 10/13

Мне интересно, если данные, которые я вижу, не зашифрованы, а просто зашифрованы. Вот фрагмент данных, которые я получаю обратно:

\\u001f\x8b\\b\\u0000\\u0000\\u0000\\u0000\\u0000\\u0004\\u0000\xed\xbd\\u0007`\\u001cI\x96%&/m\xca{\x7fJ\xf5J\xd7\xe0t\xa1\\b\x80`\\u0013$\xd8\x90@\\u0010\xec\xc1\x88\xcd\xe6\x92\xec\\u001diG#)\xab*\x81\xcaeVe]f\\u0016@\xcc\xed\x9d\xbc\xf7\xde{\xef\xbd\xf7\xde{\xef\xbd\xf7\xba;\x9dN\'\xf7\xdf\xff?\\\\fd\\u0001l\xf6\xceJ\xda\xc9\x9e!\x80\xaa\xc8\\u001f?~|\\u001f?\\"\\u001e\xff\\u001e\xef\\u0016ez\x99\xd7MQ-?\xfbhw\xbc\xf3Q\x9a/\xa7\xd5\xacX^

Заголовок ответа указывает, что его gzip закодирован

Content-Encoding: gzip
Content-Length: 438
Content-Type: text/xml; charset=utf-8

Интересно, связано ли это с этим ответом stackru, хотя исходящий запрос имеет заголовок "Accept-Encoding: gzip". Я попытался добавить вызов в GZIPInputStream, но приложение не любит ответ

Обновление 2 Так что я могу получить его для захвата данных, это проблема с gzip. Проблема, с которой я сейчас сталкиваюсь, заключается в том, что приложение на устройстве Android отображает поток ввода GZIP. Чтобы отобразить данные в Frida, я должен запустить их через GZIPInputStream, пока не уверен, как снова сжать их, чтобы отправить в приложение. Я попытался кратко с GZIPOutputStream, но это не сработало. Вот мой обновленный код.

 HttpURLConnection.getInputStream.overloads[0].implementation = function() {    
try {
  methodURL = "";
responseHeaders = "";
responseBody = "";
var Connection = this;
if("gzip" == Connection.getContentEncoding())
{
    var stream = InputStreamReader.$new(GZIPInputStream.$new(this.getInputStream.apply(this, arguments)));
}   
else
{
    var stream = InputStreamReader.$new(this.getInputStream.apply(this, arguments));
}
}

var requestURL = Connection.getURL().toString();
var requestMethod = Connection.getRequestMethod();
var requestProperties
methodURL = requestMethod + " " + requestURL;
if (Connection.getHeaderFields) {
  var Keys = Connection.getHeaderFields().keySet().toArray();
  var Values = Connection.getHeaderFields().values().toArray();
  responseHeaders = "";
  for (var key in Keys) {
    if (Keys[key] && Keys[key] !== null && Values[key]) {
      responseHeaders += Keys[key] + ": " + Values[key].toString().replace(/\[/gi, "").replace(/\]/gi, "") + "\n";
    } else if (Values[key]) {
      responseHeaders += Values[key].toString().replace(/\[/gi, "").replace(/\]/gi, "") + "\n";
    }
  }
}
var retval;
if (stream) {
  var baos = ByteArrayOutputStream.$new();
  var buffer = -1;

  var BufferedReaderStream = BufferedReader.$new(stream);
  while ((buffer =stream.read()) != -1){
      baos.write(buffer);
      responseBody += String.fromCharCode(buffer);
   }
BufferedReaderStream.close();
baos.flush();
if("gzip" == Connection.getContentEncoding())
{
    retval = GZIPOutputStream.$new(ByteArrayInputStream.$new(baos.toByteArray()));
}
else
{
    retval = ByteArrayInputStream.$new(baos.toByteArray());
}


}
/*   --- Payload Header --- */


var send_data = {};
send_data.time = new Date();
send_data.txnType = 'HTTP';
send_data.lib = 'com.android.okhttp.internal.http.HttpURLConnectionImpl';
send_data.method = 'getInputStream';
send_data.artifact = [];
/*   --- Payload Body --- */
var data = {};
data.name = "Request/Response";
data.value = methodURL + "\n" + requestHeaders + "\n" + requestBody + "\n\n" + responseHeaders + "\n" + responseBody;
data.argSeq = 0;
send_data.artifact.push(data);
send(JSON.stringify(send_data));

if(retval)
    return retval;
return stream;
} catch (e) {
  this.getInputStream.overloads[0].apply(this, arguments);
}
}

0 ответов

Другие вопросы по тегам