[Из песочницы] Троян, ворующий предметы из инвентаря Steam
Хотя про этот троян известно достаточно давно, настоящую массовость он приобрел в конце ноября.Интересно в нем то, что вместо обычной кражи логинов и паролей, от которой можно вполне просто защититься, он напрямую ворует предметы из инвентаря Steam.
Компания Valve давно в курсе проблемы, но каких-то особых действий за несколько месяцев так и не предприняла, хотя текущую волну можно без проблем остановить небольшими изменениями в клиенте Steam.В инвентаре Steam хранятся предметы из нескольких популярных игр Valve, некоторые из которых могут стоить весьма внушительную (по меркам цветных пикселей) сумму. Также в нем хранятся предметы связанные с самим Steam (подарочные копии игр, фоны профиля, смайлы и т.п.).
ЗаражениеЗаражение происходит следующим образом. Ничего не подозревающему пользователю приходит сообщение, в котором содержится ссылка на якобы скриншот инвентаря, с предложением обменяться предметами. После перехода по ссылке автоматически начинает загружаться файл .scr, имеющий иконку, которая выглядит как миниатюра изображения. Учитывая, что по-умолчанию в Windows показ расширения выключен, а если даже и включен, .scr вполне может быть воспринято как «screenshot», выглядит всё весьма правдоподобно.
После запуска файла троян распаковывает из ресурсов картинку и открывает её (на картинке действительно скриншот инвентаря или какого-нибудь предмета). Некоторые из модификаций прописываются в автозапуск.
Параллельно с этим троян извлекает cookies из памяти клиента Steam, делает запрос на steamcommunity.com для получения идентификатора сессии, ищет в инвентаре подходящие предметы и отправляет их через «Trade Request» на заранее подготовленные аккаунты злоумышленников.
К слову, во время написания этой статьи, я нашёл еще один вариант трояна (очевидно, основанный на публичных исходниках), который был написан немного иначе и обладал дополнительными функциями, например, рассылкой сообщений через список друзей.
Кстати, оригинальное имя собранного файла было «Maksim Steam Offer.exe», о чем мне любезно сказал рефлектор, а идентификатор профиля, на который идут украденные предметы — 76561198009197365. Домен, с которого троян распространялся (и на момент написания распространяется) — «puush-me.com» (для тех, кто решит поиграть в детектива, заходить из под виртуальной машины). И да, он там необфусцированный.
Несколько доменов, которые мне удалось собрать:
take-screen.orgfastscreen.orgmy-screenshot.netpuush-me.compicturesfast.netscreen-url.com
Что примечательно, большинство из них зарегистрированы у русских регистраторов.
Ковыряем исходники Сам троян написан на C#, что весьма необычно для подобного рода ПО. В скачанных мною с просторов интернета исходниках было несколько файлов: WinApis.cs, содержащий несколько методов для работы с winapi.cs, Http.cs, содержащий методы для эмуляции запросов от клиента steam (вплоть до последнего хедера) и Program.cs, в котором и происходило всё действие.Занимательно, что общий объем кода — всего около 500 строк.
Cookies из памяти клиента обе вариации трояна получают следующей регуляркой:
MatchCollection matchs = new Regex (»7656119[0–9]{10}%7c%7c[A-F0–9]{40}», RegexOptions.IgnoreCase).Matches (preparedIDs); Затем, используя полученные cookies, отправляется запрос на steamcommunity.com для получения идентификатора сессии, для чего в Http.cs есть отдельный (и весьма немаленький) метод.Получив идентификатор, троян, используя api steamcommunity, получает содержимое инвентаря:
private static List
if (((inventory.SelectToken («success») != null) && ((bool)inventory.SelectToken («success»))) &&
(inventory.SelectToken («rgDescriptions»)).First!= null)
{
IJEnumerable
foreach (JToken eachItem in inventory.SelectToken («rgInventory»).Values ()) { JToken infoAbout = descriptionsBase.Where (each => each[«classid»].ToString () == eachItem[«classid»].ToString ()).First (); if (infoAbout[«tradable»].ToString () == »1») { string[] item = new string[] { appID, eachItem[«amount»].ToString (), eachItem[«id»].ToString (), infoAbout[«market_name»].ToString (), infoAbout[«type»].ToString ().ToLower () }; if (! items.Contains (item)) { items.Add (item); } } } } break; } catch { return null; }
} return items; } Cортирует его по заданным фильтрам: listed = FilterByRarity (listed, «common,»);
private static List