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

Ishikawa

マエストロ
Премиум
15.11.2016
126
189
37
#1
В первой части было показан вариант серверной части простого кейлогера с передачей дампа по сети используя Socket. Сегодня мы доработаем серверную часть, немного расширив функционал и напишем клиента: переделаем функции для работы с сокетами и добавим несложный удаленный shell, использующий возможности Windows CMD.

Начнем с серверной части. Для начала вынесем функцию screenshot за пределы Main, оформим её отдельно. В дальнейшем мы будем обращаться к функции через команду Screen:
upload_2016-11-28_9-57-23.png

Кстати, если кто смотрел исходник, то мог заметить, что помимо нажатий клавиш, при запуске программы в лог записывается некоторая информация о системе и есть сохранение последнего содержимого буфера (text) через функцию GetBuff:
upload_2016-11-28_9-57-52.png
В дальнейшем можно также вынести функцию в отдельную команду, чтобы получать содержимое буфера по запросу. Очень часто в буфер попадают copy-pastу пароли.

Далее напишем пару функций-помощников. Для начала нам нужно научить пересылать данные между сервером и клиентом. Для начала напишем функцию, которая будет отправлять данные от сервера к клиенту:
upload_2016-11-28_9-59-53.png

Функция приминает два параметра: непосредственно данные и сокет, который будем использовать.
Использовать в дальнейшем будем таким образом:
upload_2016-11-28_10-1-3.png

Поскольку мы планируем сделать небольшой shell, необходимо каким-то образом заставить сервер запускать процессы на удаленном компьютере, а клиенту - пересылать данные.
Поможет нам в этом метод Process из пространства using System.Diagnostics.
Функция, написанная на основе этого метода, принимает два параметра: название команды, ее аргументы и сокет, через который будем работать.

upload_2016-11-28_10-7-27.png

Обращаем внимание на строку process.StartInfo.RedirectStandartOutput = true; она нам поможет формировать output для клиента. process.Start() запускает нашу команду, переданную через string s, string fl. Для формирования output используем StreamReader, читающий весь вывод до конца методом ReadToEnd(), и то, что получилось, отправляем через SSend(output,client).
process.WaitForExit() означает, что мы ждем завершения команды.
ВАЖНО! Например, если вы запустите Блокнот, он откроется на сервере и будет висеть до тех пор, пока кто-нибудь не закроет его. Пока на клиент не поступит сигнал о завершении, другую команду провести не выйдет. Вызов SSend как раз означает, что команда завершилась.

Теперь о сложном. Необходимо полностью переписать функцию ServerSocket():
upload_2016-11-28_10-13-55.png

Создаем точку подключения ipep, создаем сокет newsock, делаем bind и дальше слушаем на порту 9050. Все дальнейшие операции проводим в цикле while(true), внутри которого все будем обрабатывать через try-catch, чтобы иметь возможность отлавливать ошибки.
Далее ждем подключения клиента:
upload_2016-11-28_10-16-9.png
Готовим переменные под входящие данные, создаем просторный массив байтов.
Дальше начинается магия. Получать команды от клиента мы будем через client.Receive(bytes) и в переменную data направлять результат:
upload_2016-11-28_10-17-0.png

Дальше нам предстоит получить команду и ее аргументы. Считаем, что сначала идет команда, пробел, аргументы:
upload_2016-11-28_10-18-58.png

Отделяем команду от аргументов через data.Split(splitChars,2); - таким образом мы делим весь ввод на 2 части. Пробел - разделитель. На выходе получаем одномерный массив string a[].

Но что будет, если команда будет передана без аргументов, а в функцию мы NewProcess мы передаем аж три параметра? Ничего хорошего. Программа вылетит с ошибкой, т.к. не сможет найти a[1], поскольку его просто не существует. В сети есть куча примеров, как определить наличие индекса в массиве, от маленьких до больших. Но всегда есть способ проще:
upload_2016-11-28_10-32-14.png
Просто да? А то. Но ведь в NewProcess по-прежнему передается три параметра, скажете вы. Конечно, но теперь я покажу, как мы будем действовать. Пишем модуль для отправки команд.
Использовать будем switch(fileName). А fileName = a[0];
Полностью описывать не станем, всё есть в исходнике. Покажу основные моменты:
upload_2016-11-28_10-41-44.png

Таким образом вызовем ipconfig. В этом случае будет существовать только a[0].
Если наберем ipconfig /all - будет и a[0] и a[1] и они будут аргументами для NewProcess.
А вот если мы наберем cmd без параметров, то на сервер откроется cmd-сессия, но поскольку мы не передали аргументов, мы ничего не увидим, клиент останется в неведении и вполне возможно, мы просто потеряем контроль через Socket.
Чтобы этого не произошло, делаем так:
upload_2016-11-28_10-45-21.png

Таким простым образом защитили себя от невнимательности. Обратим внимание на вызов NewProcess: "cmd.exe" передается с ключем "/C" - это позволяет выполнить команду с последующим ее завершением. Без завершения нужен ключ "/K". Можете поэкспериментировать. Это позволяет проводить довольно большой список команд через CMD сервера, но не весь. Например переход в каталог через cd работать не будет. Кстати, работа cmd cmd не проверялась.

Для разнообразия я добавил еще функцию Delete. В ней также присутствует защита от использования без аргументов. А вот для удаления мы используем не cmd del, а метод FileInfo.Delete(). Но если вы дадите команду серверу cmd del path_to_file/file - это тоже сработает.
upload_2016-11-28_10-48-38.png

Как вы могли заметить, весь вывод идет через SSend. Функция в две строки оказалась чрезвычайно полезной.
Если вы наберете всякую белиберду, или вовсе пустую команду - есть case default:
upload_2016-11-28_10-51-52.png

Все что не нашлось в switch, будет распознано как мусор и выполняться не будет (почти, кое-что будет).Осталось совсем немного, дописать вызов функции отправляющей нам лог-файл и функцию, которая создает и отправляет по запросу скриншот удаленного компьютера.
За пределами switch пишем следующее:

upload_2016-11-28_10-54-39.png

Это вызов для функции скриншота. Заметили функцию SocketWorker? О ней чуть ниже.
Для лог-файла делаем аналогично:
upload_2016-11-28_10-55-33.png

В интернете есть много примеров передачи файлов через сокеты, что-то кривое, что-то нет.
Некоторые делают FTP-клиент(многие упираются в ошибку 500 при работе), некоторые пишут сервер.
Мы пойдем проще: останемся верными сокету. Функция принимает только имя файла, который нужен и текущий сокет:
upload_2016-11-28_10-57-6.png

Первые 5 строк должны быть понятны: берем входные параметры и переводим их в массивы байтов, с учетом смещений и выравнивания. А вот что за CopyTo?
Это весьма полезная вещь для работы с массивами. Метод позволяет копировать все элементы текущего одномерного массива в заданный одномерный массив начиная с указанного индекса в массиве назначения. Таким образом все содержимое нужного нам файла будет упаковано в массив byte[] и отправлено нам через... Socket.Send, т.е. тем же самым методом, которым мы отправляем и ответы на команды. Весьма удобно, можно протолкнуть слона в игольное ушко.

На этом моменте с серверной частью покончено. Базис задан, желающие могут пилить под себя. Это легче, чем кажется.

Приступим к клиенту. Задача клиента - соединяться с сервером, отправлять команды и получать ответы, а также принимать файлы по запросу.
Для клиента подключаем необходимые адресные пространства:
upload_2016-11-28_13-26-30.png
Больше для работы не требуется. В функции Main клиента пишем функционал для подключения к серверу:
upload_2016-11-28_13-26-55.png
В Main все просто. Главное в нем - функция SendMessageFromSocket(host). Функция принимает в качестве аргумента имя хоста или ip-адрес:
upload_2016-11-28_13-28-48.png
Первые три строки уже должны быть понятны: преобразовываем имя хоста, устанавливаем конечную точку подключения. Обратите внимание на AddressFamily. Метод InterNetwork означает использовать IP-адрес версии 4. Там же можно указать ATM, AppleTalk,Chaos и пр. Материал тут:
Чтобы видеть этот контент необходимо: Войти или зарегистрироваться

Сам метод AddressFamily возвращает семейство адресов IP-адреса.

Далее готовим буфер под принимаемые данные и соединяемся с удаленной точкой:
upload_2016-11-28_13-35-19.png

После того, как соединение установлено, нужно как-то послать команду серверу. Делаем это таким образом:
upload_2016-11-28_13-36-18.png

3 строка - проверка на пустую строку или Null. Наша команда это string message. Чтобы его отправить, его нужно преобразовать в байты - применим Encoding.
И дальше снова магия:
upload_2016-11-28_13-38-34.png
Отправляем команды, поддерживаемые сервером и получаем ответ.
Теперь оформим блок для приема двух файлов: скриншота и лог-файла с сервера.
upload_2016-11-28_13-39-34.png

Чуть позже напишем функцию SocketReceive, принимающая в качестве параметров Socket клиента и выходной файл. Желающие могу дописать функцию для сохранения в произвольное имя файла.

upload_2016-11-28_13-41-44.png

Чтобы клиент не закрывался после каждой введенной команды, используем переход в начало функции. Теоретически можно объявить метку и делать goto.

Обратите внимание, в серверной части нет функций для закрытия сокета, чтобы мы могли подключаться к серверу постоянно, если на клиенте вдруг произойдет сбой, либо мы прервем его выполнение (клиент можно прервать по CTRL+Z. В этом случае сервер напишет у себя в логе Bye!, а клиент завершиться с выводом строки "Передача завершена. Завершите соединение вручную")

Осталось малое - написать функцию SocketReceive, для приема файлов.
upload_2016-11-28_13-45-49.png
На вход подаем сокет и имя файла, создается буфер под принятые данные.
После подготовки к приему, сообщаем что мы готовы и открываем BinaryWriter для записи потока битов напрямую в файл на клиенте.
int receivedBytesLen = sender.Receive(clientData) - принимает данные от сервера.
Файлы сохраняются там же, где лежит клиент.
upload_2016-11-28_13-47-55.png
После приема сообщаем об этом и закрываем поток BinaryWriter.

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

Вложения

Последнее редактирование:

Ishikawa

マエストロ
Премиум
15.11.2016
126
189
37
#2
Немного скриншотов, как это работает:
Прием файла (команда screen):
upload_2016-11-28_14-15-0.png
Не смотрите что пишет "невыполнимая команда", так и должно быть, позже поправим).

Пример команды Help:
upload_2016-11-28_14-16-21.png

Белиберда:
upload_2016-11-28_14-16-43.png

Команда без аргументов:
upload_2016-11-28_14-17-11.png

Пустая команда:
upload_2016-11-28_14-19-58.png

Пробуем taskkill:
upload_2016-11-28_14-18-28.png

Ну и конечно, исходники сервера и клиента ищите во вложении к этому сообщению :)
И не забываем, что неправомерный доступ к информации карается законом.
УК РФ, Статья 272. Неправомерный доступ к компьютерной информации
 

Вложения

Последнее редактирование:

poxys

Member
23.10.2016
10
0
22
#3
клиент не соединяется! а консоль сервера не скрыта и плюс бредятина высвечивается!
 

Вложения

poxys

Member
23.10.2016
10
0
22
#4
А то что Visual Studio предлагает удалить лишние, это надо делать или нет?
 

Вложения

Ishikawa

マエストロ
Премиум
15.11.2016
126
189
37
#6
клиент не соединяется! а консоль сервера не скрыта и плюс бредятина высвечивается!
Консоль сервера сам скроешь, я писал в первой части какой параметр отвечает за стелс. Высвечивается не бредятина - а последнее содержимое буфера, бро.

Клиент и сервер соединяться - если у обоих будет один порт. В моем случае 9050.
Ко всему этот порт не должен быть закрыт фаерволом.
Пиши в личку настройки фаера, проверь комп Nmap на наличие открытого порта 9050 на стороне сервера.

p.s. и как бы по коду программы:
// Соединяем сокет с удаленной точкой
sender.Connect(ipEndPoint);
Console.Write("Введите сообщение: ");
т.о. клиент и сервер все же соединяются. Так что нужно дебажить :)
Отследить можно через сетевой монитор:
upload_2016-11-29_9-11-14.png
Как видишь, у меня клиент соединяется с сервером, находящийся в вообще другой подсети.
 
Последнее редактирование:

Ishikawa

マエストロ
Премиум
15.11.2016
126
189
37
#9
Можете переместить в нужный раздел, я не против.
А как metsvc относится ко взлому, бро?
 

-master-

Well-Known Member
14.01.2012
616
20
#10
Я же не говорю что эту информацию можно/нужно/попробуй-только-не ипользовать в хакинге/тестах/...
речь только про то что тут явно куча того что можно просто переметить и красиво оформить в соотв. разделе, а здесь красивый линк туда.
типа вот мы начинаем обалденно тестировать чего то там, но как прогеры мы можем наваять неслабые штуки зырь тут -> линк
и погналово дальше ..

там можно будет вети свое обсуждение/дополнение/ а тут свое, и все в шоколаде

вот както так, я конечно не спец по хакингу, и ели не прав то с честью выдержу прямое попадание))
 

poxys

Member
23.10.2016
10
0
22
#11
Фаер выключен локальными политиками. Все заработало со второго раза, консоль тупит, надо энтер несколько раз нажать, короче итоги: при команде screen загружается скриншот, в папку и если еще раз сделать это, то screen.jpg не заменяется, или не создается новый, cmd лист неудобный, нельзя сделать что бы был полноценный cmd shell? Без команд cmd ifconfig (сделать меню в нем две-три команды, первая при нажатии цифры 1 и энтер подгружает логи с сервера, вторая запускает полноценный shell cmd оболочку в которой можно работать как в обычной командной строке, третья показывает инфу о системе, например выпоняет команду sysinfo и выводит содержимое) как у нормальных ратах. Clipboard один раз делается, а неплохо бы было что бы это записывалось в логи когда этот процесс вызывает пользователь. На сервере не нужно выводить команды которые отправляет управляющий клиент.

Это просто советы по улучшению.
Я бы сам это попробовал реализовать, но нет знаний:(
 

poxys

Member
23.10.2016
10
0
22
#12
с cmd наверно погорячился это можно сказать полноценный шел, но вот cd ../ переходы не работают,
 

Ishikawa

マエストロ
Премиум
15.11.2016
126
189
37
#13
Я же не говорю что эту информацию можно/нужно/попробуй-только-не ипользовать в хакинге/тестах/...
речь только про то что тут явно куча того что можно просто переметить и красиво оформить в соотв. разделе, а здесь красивый линк туда.
типа вот мы начинаем обалденно тестировать чего то там, но как прогеры мы можем наваять неслабые штуки зырь тут -> линк
и погналово дальше ..

там можно будет вети свое обсуждение/дополнение/ а тут свое, и все в шоколаде

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

Ishikawa

マエストロ
Премиум
15.11.2016
126
189
37
#14
Фаер выключен локальными политиками. Все заработало со второго раза, консоль тупит, надо энтер несколько раз нажать, короче итоги: при команде screen загружается скриншот, в папку и если еще раз сделать это, то screen.jpg не заменяется, или не создается новый, cmd лист неудобный, нельзя сделать что бы был полноценный cmd shell? Без команд cmd ifconfig (сделать меню в нем две-три команды, первая при нажатии цифры 1 и энтер подгружает логи с сервера, вторая запускает полноценный shell cmd оболочку в которой можно работать как в обычной командной строке, третья показывает инфу о системе, например выпоняет команду sysinfo и выводит содержимое) как у нормальных ратах. Clipboard один раз делается, а неплохо бы было что бы это записывалось в логи когда этот процесс вызывает пользователь. На сервере не нужно выводить команды которые отправляет управляющий клиент.

Это просто советы по улучшению.
Я бы сам это попробовал реализовать, но нет знаний:(
Привет, бро. У меня все с первого раза работает, Enter долбить тоже не приходится. Допускаю, что на медленных соединениях возможно будет задержка при передаче файлов и обмене командами. Скриншот создается новый, если удалить текущий. Если смотрел внимательно - в коде нет функции удаления скриншота или лога. Я в первой части писал (ты по-ходу не читал) что код будет с ограничениями, ибо мы пишем simple-версию. Профессиональные кейлогеры пишут иначе, выносят код в драйвер, используют другие функции.
Cmd-лист явлен как демонстрация возможностей: основные команды, которые доступны в CMD, можно провернуть. То что не работает переход между директориями cd.. я тоже писал.
И писали все же кейлогер, а не шелл. Clipboard делается один раз, да. Я писал, что желающие могут вынести код в отдельную функцию и добавить ей команду (ты видимо вообще не читал). На сервере - всё в твоих руках, бро.
Закомментируй строки Console.WriteLine и будет тебе счастье :)

p.s. я понимаю, что copy-paste рулит, но понимать основы наверное стоит. Начать прежде всего с внимательного чтения, а не бездумной компиляции. Можно ведь и вирус зашить в код или зашифровать всю инфу на компе. Первым делом нужно проверять, что другие дают.
Могу рекомендовать/подарить две хорошие книги по C#, чтобы знания всё же были.
 
Последнее редактирование:

MAdDog719

Well-Known Member
Премиум
16.08.2016
108
26
30
#16
Кому нужны исходники - пишите в личку :)
Кто-то неудачно потер сообщения к теме. В одном из них были исходники.
Привет, скажи, пожалуйста, это уже полностью готовый кейлогер, или еще нужно написать дешифратор файлов которые будет принимать сервер?
 

Ishikawa

マエストロ
Премиум
15.11.2016
126
189
37
#18
Привет, скажи, пожалуйста, это уже полностью готовый кейлогер, или еще нужно написать дешифратор файлов которые будет принимать сервер?
Привет, бро. Да, будет еще дешифратор. Он самая сложная часть, т.к.нужно парсить строки, используя всякие Replace и Regex. В дальнейшем можно будет объединить клиент и дешифратор в одну программу.
На текущий момент принцип такой: сервер работает на жертве постоянно, мы подсоединяемся клиентом с целью быстро вытащить логи или скрин и смыться. А награбленное скормить дешифратору.
Время от времени я дописываю еще и серверную часть, сегодня написал как поставить прогу в автозапуск.
 

MAdDog719

Well-Known Member
Премиум
16.08.2016
108
26
30
#19
Привет, бро. Да, будет еще дешифратор. Он самая сложная часть, т.к.нужно парсить строки, используя всякие Replace и Regex. В дальнейшем можно будет объединить клиент и дешифратор в одну программу.
На текущий момент принцип такой: сервер работает на жертве постоянно, мы подсоединяемся клиентом с целью быстро вытащить логи или скрин и смыться. А награбленное скормить дешифратору.
Время от времени я дописываю еще и серверную часть, сегодня написал как поставить прогу в автозапуск.
Понятно, жду тогда дешифратор. И спасибо за твой труд, реально клевый проект.