Yvision.kzYvision.kz
kk
Разное
Разное
399 773 постов41 подписчиков
Всяко-разно
29
00:44, 04 июля 2016

История одного исследования.

Дело было вечером, делать было нечего... Листая новостную ленту, наткнулся на статью о возобновлении работы системы платных парковок. Тема для всех злободневная, наверно где-то политизированная, где-то коррупционная. Эту дискуссию я оставлю для других троллей политических обозревателей и экспертов. Лично меня заинтересовало в тот момент мобильное приложение, которое доступно для скачивания в плэймаркете. Поскольку в Казахстане рынок мобильных разработчиков не такой уж большой, мне стало интересно, кто же написал данную программу - кто-то из известных девелоперов или появился "новичок". Данные плеймаркета указывали на "OOO ENOT", о которых ни я, ни мои знакомые, ни "дядюшка гугл" ничего не знали, поэтому было решено заглянуть "внутрь" этого приложения. Процесс реверса я описывать не буду, в интернете достаточно мануалов и видео на данную тему, а вот результаты меня удивили. Начнём по порядку...

Blog post image

Сразу бросается в глаза эта папка. Знающие люди поймут сразу, что программа писалась не с нуля, а использовались исходники другой программы. В нашем случае - это программа "Парковки Москвы" разработчик "ОАО Электронная Москва". Чтобы в этом убедиться заглянем и в её исходники и сравним файлы конфигурации. Это - наше приложение:

Blog post image

А вот российское приложение:

Blog post image

Откуда "растут ноги" мы определили... Но это не единственное разочарование, постигшее меня при дальнейших изысканиях. Внимательные читатели, знакомые с программированием, отметили объявленные переменные сервисов по оплате услуг парковки. Правильно! За парковку в г.Алматы мы платим российскому сервису! Я недеялся, что переменные переодпределены, но нет... вот код проверки оплаты по смс:

 

 

  1. public Response payMobile(String paramString, int paramInt, Context paramContext)
  2. {
  3. try
  4. {
  5. Logger.log("payMobile " + paramString);
  6. Network.requestString(Utils.PAY_MOBILE_URL + "&subscriber=" + paramString + "&message=pay" + paramInt, "GET", null);
  7. Response localResponse = Response.success(paramContext.getString(2131230940));
  8. return localResponse;
  9. }
  10. catch (IOException localIOException)
  11. {
  12. Logger.log(localIOException.toString());
  13. }
  14. return Response.error(this.error);
  15. }

Дальнейшее изучение исходников мягко сказать шокировало меня... Сначала код:

 

 

  1. public Response payCardSubscription(String paramString1, int paramInt1, int paramInt2, int paramInt3, String paramString2, float paramFloat, Context paramContext, String paramString3, String paramString4)
  2. {
  3. StringBuilder localStringBuilder = new StringBuilder().append("20").append(paramInt2);
  4. Object localObject;
  5. if (paramInt1 < 10)
  6. localObject = "0" + paramInt1;
  7. while (true)
  8. {
  9. String str1 = localObject;
  10. try
  11. {
  12. JSONObject localJSONObject1 = new JSONObject().put("type", "card");
  13. JSONObject localJSONObject2 = new JSONObject().put("subscriber", this.phone).put("pan_mko", paramString1);
  14. Object[] arrayOfObject1 = new Object[1];
  15. arrayOfObject1[0] = Integer.valueOf(paramInt3);
  16. JSONObject localJSONObject3 = localJSONObject1.put("details", localJSONObject2.put("cvc_mko", String.format("%03d", arrayOfObject1)).put("exp_mko", str1).put("cardholder_mko", paramString2));
  17. JSONArray localJSONArray1 = new JSONArray().put(new JSONObject().put("id", "Order").put("value", "*****"));
  18. JSONObject localJSONObject4 = new JSONObject().put("id", "Summ");
  19. Object[] arrayOfObject2 = new Object[1];
  20. arrayOfObject2[0] = Float.valueOf(paramFloat);
  21. JSONArray localJSONArray2 = localJSONArray1.put(localJSONObject4.put("value", String.format("%s", arrayOfObject2)));
  22. JSONObject localJSONObject5 = new JSONObject().put("payment", localJSONObject3).put("forms", localJSONArray2);
  23. JSONObject localJSONObject6 = new JSONObject(Network.requestString(Utils.PAY_CARD_URL + "?service=card.parking.subscription&code=" + paramString3 + "&option=" + paramString4, "POST", localJSONObject5.toString()));
  24. int i = localJSONObject6.optInt("result", -1);
  25. String str2 = localJSONObject6.optString("url");
  26. if (!str2.equals(""))
  27. {
  28. Response localResponse2 = Response.success(paramContext.getString(2131230796)).setData(str2);
  29. return localResponse2;
  30. localObject = Integer.valueOf(paramInt1);
  31. }
  32. else
  33. {
  34. if (i == 0)
  35. return Response.success(paramContext.getString(2131230796)).setData(null);
  36. Response localResponse1 = Response.error(paramContext.getString(2131230794));
  37. return localResponse1;
  38. }
  39. }
  40. catch (JSONException localJSONException)
  41. {
  42. Logger.log(localJSONException.getMessage(), localJSONException);
  43. return Response.error(paramContext.getString(2131230795));
  44. }
  45. catch (IOException localIOException)
  46. {
  47. Logger.log(localIOException.getMessage(), localIOException);
  48. }
  49. }
  50. return Response.error(paramContext.getString(2131230795));
  51. }

Небольшое пояснение для не "тыжпрограммистов", этот метод делает запрос к серверу на сверку оплаты за услугу парковки посредством банковской карточки. "Ну и что? Многие сервисы позволяют оплачивать карточкой!" - скажете Вы. Дело в том, что в запросе проверяются ВСЕ данные карточки - кардхолдер, срок действия, номер карточки, тип карточки и (внимание!) CVV. Удивлены? Это ещё не всё :))) Сам сервер, который подтверждает оплату, - на российском домене и не в казахстанском сегменте сети. Шокированы? Продолжаем... Метод формирования запроса, поддерживает защищенное соединение (правда я не заметил там SNI, хотя может плохо искал), но в случае его отсутсвия соединение осуществляется по открытому протоколу! Кстати апи сервера поддерживает его, корректность ответа я проверять не стал :).

Также есть метод проверки платежа, осуществленного через так называемую скрэтч-карту (карта моментальной оплаты), тоже проверяемый через российский сервер. Но на нашем сайте о таком методе оплаты ничего не говорится, а вот об оплате посредством банковской карты через мобильное приложение - да:

Blog post image

В общем, все изыскания - лишь теоретический полёт моих мыслей :). Проверять на практике работоспособность приложения или правильность догадок, выложенных в данном посте, я не стал. Во-первых, не было такой цели, во-вторых - просто побоялся забивать свои данные.

Ну и в качестве посткриптума, небольшая информационная справка.

aparking.kz.        627    IN    A    90.156.141.182

inetnum:        90.156.128.0 - 90.156.255.255
netname:        RU-MASTERHOST-20061117
country:        RU

lk.aparking.kz.        3407    IN    A    185.98.84.194

inetnum:        185.98.80.0 - 185.98.87.255
netname:        RU-DATALINE-20150429
country:        RU

Интересно, а как же "Приказ и.о. Министра по инвестициям и развитию Республики Казахстан от 28 января 2016 года № 118 Об утверждении Правил регистрации, пользования и распределения доменных имен в пространстве казахстанского сегмента Интернета"? Почему кому-то можно, а кому-то нет?

Смотрим дальше:

Domain Name............: aparking.kz

Organization Using Domain Name
Name...................: Товарищество с ограниченной ответственностью "RR2"
Organization Name......: Товарищество с ограниченной ответственностью "RR2"
Street Address.........: str. Zelenaya 16
City...................: Almaty
State..................: -
Postal Code............: 050023
Country................: KZ

А это ещё кто такие? Зелёная, 16 - где это?

BIN 151040027093    ТОО "RR2"

КОД ОКПО    53112319
КОД БИН    151040027093
ДАТА РЕГИСТРАЦИИ ЮРИДИЧЕСКОГО ЛИЦА    30.10.2015
ОСНОВНОЙ КОД ОКЭД    96090
НАИМЕНОВАНИЕ ОСНОВНОГО ВИДА ДЕЯТЕЛЬНОСТИ    Предоставление прочих услуг, не включенных в другие группировки
КОД КРП    130
НАИМЕНОВАНИЕ КРП    Малые предприятия (от 21 до 30 чел.)
КОД КАТО    751410000
НАИМЕНОВАНИЕ НАСЕЛЕННОГО ПУНКТА    БОСТАНДЫКСКИЙ РАЙОН
ЮРИДИЧЕСКИЙ АДРЕС    УЛИЦА ТИМИРЯЗЕВА, 18А
ФАМИЛИЯ, ИМЯ, ОТЧЕСТВО РУКОВОДИТЕЛЯ    БОРАНБАЕВ МУРАТ СОВЕТАЕВИЧ

Ну а дальше гуглите сами!

Blog post image

 

29