Горячее
Лучшее
Свежее
Подписки
Сообщества
Блоги
Эксперты
Войти
Забыли пароль?
или продолжите с
Создать аккаунт
Я хочу получать рассылки с лучшими постами за неделю
или
Восстановление пароля
Восстановление пароля
Получить код в Telegram
Войти с Яндекс ID Войти через VK ID
Создавая аккаунт, я соглашаюсь с правилами Пикабу и даю согласие на обработку персональных данных.
ПромокодыРаботаКурсыРекламаИгрыПополнение Steam
Пикабу Игры +1000 бесплатных онлайн игр
Классический пинбол, как в древнем игровом автомате или в компактной игрушке: есть пружины, шарики и препятствия. В нашем варианте можно не только зарабатывать очки: чтобы пройти уровень, придется выполнить дополнительную миссию.

Пинбол Пикабу

Аркады, На ловкость, Казуальные

Играть

Топ прошлой недели

  • AlexKud AlexKud 38 постов
  • SergeyKorsun SergeyKorsun 12 постов
  • SupportHuaport SupportHuaport 5 постов
Посмотреть весь топ

Лучшие посты недели

Рассылка Пикабу: отправляем самые рейтинговые материалы за 7 дней 🔥

Нажимая кнопку «Подписаться на рассылку», я соглашаюсь с Правилами Пикабу и даю согласие на обработку персональных данных.

Спасибо, что подписались!
Пожалуйста, проверьте почту 😊

Помощь Кодекс Пикабу Команда Пикабу Моб. приложение
Правила соцсети О рекомендациях О компании
Промокоды Биг Гик Промокоды Lamoda Промокоды МВидео Промокоды Яндекс Директ Промокоды Отелло Промокоды Aroma Butik Промокоды Яндекс Путешествия Постила Футбол сегодня

Golang + Программист

С этим тегом используют

Программирование IT Разработка IT юмор Юмор Картинка с текстом Работа Все
13 постов сначала свежее
0
Вопрос из ленты «Эксперты»
user8711267
2 месяца назад

Хочу изучить алгоритмы на языке Go - нужен совет⁠⁠


Привет всем!

Я недавно начал изучать язык Go (Golang). Сначала изучал самостоятельно, потом прошел бесплатные курсы, потом подумал, что может в платных курсах есть что-то более конкретное или углубленное, прошел полугодовой курс (платный). Не хочу указывать в статье что именно за курсы, что бы не было рекламой. По факту хочу сказать, что разница не особо большая - но было кое-что полезное - сроки, и хоть какой-то фидбек от преподавателя. Сейчас хочу попасть на стажировку (Авито/озон/т-банк/да в принципе хоть что-то). Не знаю - верный ли путь я намечаю или нет. Если в комментариях скажите что-то по этому поводу - будет хорошо.

Так вот, что бы попасть на стажировку - необходимо пройти алгособес. Вот тут у меня пробел. Хочу изучить как решать алгоритмические задачи на go. На python много материалов на эту тему в интернете, на других ЯП тоже хватает, но именно на Go я встречал только платные варианты.

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

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

Просьба к вам уважаемые гоферы с Пикабу:

Поделитесь пожалуйста информацией.

Буду благодарен за любые советы, ссылки и просто поддержку. Если есть желающие учиться вместе — тоже пишите в комменты или в ЛС!

Спасибо!

P.S. немного о себе - я с Иркутска (это для тех, кто может захочет объединить силы для совместного обучения, пишу для понимания часового пояса). Мне 32 года, есть основная работа, но чувствую, что необходимо менять, причин много, не буду расписывать. Почему именно IT? Потому как есть знакомые которые успешно перешли в эту сферу (предугадывая комменты - у них нет того, что мне нужно), немаловажно - зарплаты, плюс просто всегда нравилось взаимодействие с компьютером, в детстве мечтал стать программистом, с того момента как сисадмин учил меня играть в StarCraft😅

Показать полностью
[моё] Программирование Golang Помощь Компьютер Информация Программа Linux Программист Вопрос Спроси Пикабу
18
sh1nkey
sh1nkey
9 месяцев назад

Языки нового поколения⁠⁠

Большинство нынче популярных языков (C#, Java, C++, JS, Python) не работают с многопоточною настолько хорошо, насколько бы нам того хотелось. Почему так?

Потому что они были придуманы в то время, когда ещё не был придуман процессор с двумя ядрами. Они были придуманы для работы на одном ядре, без нормальных (оптимизированных и простых) инструментов параллелизации кода

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

Технологическое будущее за нативной многопоточностью

Ссылка на оригинальный пост: https://t.me/sh1nke9/328

Языки нового поколения Программирование, Программист, Инновации, Компьютер, Golang, Rust, IT, Программа
Показать полностью 1
[моё] Программирование Программист Инновации Компьютер Golang Rust IT Программа
11
Блог компании
VSKurs
VSKurs
11 месяцев назад

ТОП-15 лучших курсов Golang (GO): обучение онлайн с нуля для начинающих, платные + бесплатные⁠⁠

В этой статье сравниваем ТОП-15 лучших онлайн-курсов по обучению Golang и рассматриваем бесплатные курсы.

Go (или Golang) - это мощный и эффективный язык программирования, разработанный компанией Google. Его синтаксис прост для изучения и освоения. Golang предназначен для создания высокопроизводительных и масштабируемых приложений. Он поддерживает параллельное выполнение задач и предлагает удобные инструменты для работы с сетью и конкурентностью. Golang также славится своей высокой производительностью и быстрым временем компиляции.

1. Курс «Backend-разработчик на Go» [SkillFactory] — 427 отзывов

Информация о курсе: стоимость — от 3 700 руб. / мес. в рассрочку на 36 месяцев, длительность — 12 месяцев

Особенности: 80% обучения составляют практические задания в различных форматах. Вы получите ответы на все вопросы и постоянную обратную связь от менторов по выполненным заданиям. Центр карьеры начинает работу со студентами с первого дня обучения. По завершении курса вы получите сертификат и диплом.

Содержание курса:

  • Программирование на Go

  • Алгоритмы и структуры данных на Go

  • Основы многопоточности

  • Инструменты для разработки

  • Работа с базами данных

  • Углубленное изучение Go

  • Архитектура приложений и основы DevOps

  • Заключительный проект.

Подробнее о курсе Golang (GO) →

2. Курс «Go (Golang) Developer Basic» [OTUS] — 126 отзывов

Информация о курсе: стоимость — 66 000 ₽ или рассрочка - от 6 600 ₽ / мес., длительность — 5 месяцев

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

Программа курса:

  • Введение в Go

  • Синтаксис Go и основы информатики

  • Алгоритмы и структуры данных

  • Параллельное программирование

  • Решение стандартных задач на Go

  • Промышленная разработка

  • Проектный модуль.

Подробнее о курсе Golang (GO) →

3. Курс «Go: Настройка окружения» [Хекслет] — 84 отзыва

Информация о курсе: стоимость — 3 900 ₽ в месяц, длительность — 5 уроков

Особенности: 12 контрольных тестов, дополнительные материалы и неограниченный доступ к теоретическим материалам.

Чему вы научитесь:

  • Настраивать локальное окружение для запуска Go-кода

  • Устанавливать библиотеки и подключать их в коде

  • Использовать инструменты для улучшения качества кода.

Программа курса:

  • Введение
    Знакомство с языком Go и целями курса

  • Запуск первой программы на Go
    Изучение базовых команд и создание проектов в экосистеме Go

  • Пакеты
    Объявление и импорт пакетов

  • Модули и зависимости
    Управление модулями и зависимостями в проекте

  • Публикация модулей
    Публикация первого Go-модуля

  • Самостоятельная работа
    Дополнительные задания для закрепления теории

  • Дополнительные материалы
    Подборка статей и видео от команды Хекслета для более глубокого погружения в тему курса.

Подробнее о курсе Golang (GO) →

4. Курс «Golang для инженеров» [Слёрм] — 42 отзыва

Информация о курсе: стоимость — 50 000 ₽ - 65 000 ₽ или рассрочка - от 12 500 ₽ / мес., длительность — 8 недель

Особенности: На курсе предусмотрены задания с длинными сроками выполнения, которые проверяют действующие Go-разработчики. Кураторы всегда на связи, помогают с обучением и решают возникающие проблемы. Вы будете выполнять разнообразные задания, постепенно усложняя кодовую базу. После основной программы у вас будет время для подготовки итогового проекта, который можно будет приложить к резюме. По окончании курса получите свидетельство, а при выполнении 80% заданий и защите проекта — номерной сертификат.

В процессе обучения вы освоите:

  • создание собственного API сервера на Golang

  • запуск контейнеров

  • взаимодействие с Docker через Go

  • работу с пользовательскими операторами и многое другое.

Программа курса:

  • Основы Go
    Разберём, зачем нужен язык Go, где его применять, обсудим основные недостатки и выясним, какие рабочие процессы можно упростить с помощью Go.

  • Встреча с преподавателями

  • Детально разберём подход Go к объектно-ориентированному программированию (ООП) и обработке и комбинированию ошибок.

  • Concurrency
    Научимся различать конкурентность и параллелизм, освоим работу с конкурентностью в Go (стандартные подходы и концепции).

  • Практика на Go
    Научимся работать со стандартной библиотекой языка, создавать сложные программы на Go, разберёмся в структуре тестов, поймём, что такое тестирование и как оно организовано, научимся запускать внешние процессы из Go.

  • Работа с Docker через Go
    Изучим API и способы взаимодействия с ним, научимся работать с Docker через Go, запускать контейнеры и подключаться к ним, определим характер взаимодействия в зависимости от задач.

  • Обсуждение пройденных модулей

  • Паттерны Kubernetes

  • Операторы Kubernetes
    Освоим работу с пользовательскими операторами и разберём, зачем нужны паттерны Kubernetes.

  • Встреча для обсуждения пройденных модулей.

Подробнее о курсе Golang (GO) →

5. Курс «Golang-разработчик» [Специалист] — 34 отзыва

Информация о курсе: стоимость — 180 690 ₽ - 204 490 ₽, длительность — от 4 до 8 месяцев (328 ак. часов)

После обучения вы сможете:

  • использовать распределенную систему управления версиями (VCS) Git;

  • владеть синтаксисом Python и основами структурного и процедурного программирования;

  • создавать веб-страницы с текстом, гиперссылками и графикой;

  • устанавливать и обновлять ПО Linux из исходных текстов и пакетов;

  • программировать на стороне сервера с помощью SQL и PL/pgSQL;

  • использовать Go для создания консольных утилит и простых веб-сервисов;

  • создавать, тестировать и прототипировать микросервисы на примере создания REST API;

  • разрабатывать полноценные веб-приложения с использованием микросервисов.

В дипломную программу входят следующие курсы:

  • Система управления версиями Git

  • Программирование на языке Python. Уровень 1. Базовый курс

  • Linux. Уровень 1. Основы администрирования

  • DEV1. Разработка серверной части приложений PostgreSQL. Базовый курс

  • Программирование на языке Go. Уровень 1. Основы языка Go

  • Программирование на языке Go. Уровень 2. Проектирование REST API

  • Программирование на языке Go. Уровень 3. Разработка веб-приложений.

Подробнее о курсе Golang (GO) →

6. Курс «Продвинутый Go‑разработчик» [Яндекс.Практикум] — 71 отзыв

Информация о курсе: стоимость — 145 000 ₽ - 152 000 ₽, длительность — 6 месяцев

Программа курса:

  • Введение и вступительный тест

  • Пакеты стандартной библиотеки

  • Работа с конкурентностью

  • Промежуточный проект

  • Паттерны проектирования на Go

  • Инструменты разработки

  • Расширенные возможности стандартной библиотеки

  • Итоговый проект

  • Алгоритмы и структуры данных

  • Подготовка к трудоустройству

  • Вебинары для разбора сложных тем и сессии Q&A.

Подробнее о курсе Golang (GO) →

7. Курс «Golang-разработчик» [Nordic IT School] — 13 отзывов

Информация о курсе: стоимость — 78 100 руб., длительность — 4 месяца (144 ак. час.)

На курсе вы освоите:

  • Основы языка и создание сервисов с использованием Go

  • Разработку сайтов и ботов на Golang

  • Управление компьютерами и серверами

  • Работу с Linux и PostgreSQL.

После окончания курса вы сможете программировать многопоточные распределённые системы для высоконагруженных проектов.

Программа курса:

  • Введение в Golang

  • Основные концепции

  • Настройка серверов на Linux

  • Работа с консолью

  • Объявление типов данных

  • Структуры

  • Методы

  • Основы интерфейсов

  • Полиморфизм

  • Параллельное программирование

  • Golang для веб-разработки

  • Создание ботов для Telegram

  • Работа с базами данных

  • Совместная разработка

  • Основы использования GIT

  • Работа с Github

  • Автоматическое тестирование.

Подробнее о курсе Golang (GO) →

8. Курс «Fullstack-разработка на Golang» [ФПМИ МФТИ] — 13 отзывов

Информация о курсе: стоимость — 138 600 ₽, длительность — 16 месяцев

Программа курса включает:

  • Программирование и операционные системы

  • Разработка на языке Golang

  • Fullstack-разработка.

Подробнее о курсе Golang (GO) →

9. Курс «Golang-разработчик. Advanced» [Ребреин]

Информация о курсе: стоимость — 60 000 руб.

Программа курса:

  • Работа с базами данных

  • Создание сервера на Go (обработка запросов, контекст, middleware)

  • Низкоуровневое программирование и продвинутая сборка

  • Микросервисная архитектура

  • Межсервисное взаимодействие

  • Оптимизация

  • Работа сервиса в кластере.

Приобретаемые навыки:

  • Понимание микросервисного взаимодействия и работы сервиса в кластере

  • Развертывание приложений в Docker-контейнере

  • Мониторинг сервисов с использованием метрик (Prometheus и Grafana)

  • Логирование (Graylog)

  • Управление конфигурациями из KV-хранилища (Consul)

  • Асинхронное и синхронное взаимодействие (REST, gRPC и Kafka).

Подробнее о курсе Golang (GO) →

Бесплатные курсы и уроки Golang

Курс «Основы Go» [Хекслет]

На данном курсе вы освоите:

  • Основные конструкции языка Go: условия, циклы, функции и другие элементы.

  • Создание программ из нескольких модулей.

  • Эффективный поиск и исправление ошибок в коде с использованием отладочной печати.

Обучение включает в себя изучение основ Go, включая простые типы данных, условия, циклы, объявление пользовательских функций и использование встроенных структур. Вы также познакомитесь с концепциями ООП в Go, включая легковесные потоки и Go-рутины, что является сильной стороной этого языка. Полученные знания помогут вам быстрее освоить основы программирования на Go, предоставив полное представление о его принципах и особенностях.

Этот курс ориентирован на тех, кто уже обладает опытом программирования на других языках и имеет представление о типах данных, переменных, условных конструкциях, циклах, функциях и объектах.

Подробнее о курсе Golang (GO) →

Курс «Продвинутая разработка микросервисов на Go» [Ozon Tech]

Программа курса включает:

  • Особенности синтаксиса Go и разработка ПО на этом языке

  • Взаимодействие между сервисами и работа в Kubernetes (k8s)

  • Внутреннее устройство Postgres

  • Конкурентное и параллельное программирование в Go

  • Тестирование программ на Go

  • Введение в брокеры сообщений, включая Apache Kafka

  • Наблюдаемость систем и практики SRE

  • Управление данными в высоконагруженных системах.

Подробнее о курсе Golang (GO) →

Курс «Изучаем go программирование на golang learn go» [Академия IT]

Темы уроков курса:

  • Типы данных и переменные в Golang

  • Работа с переменными и обработка ошибок

  • Циклы в Go

  • Массивы и срезы

  • Карты (maps) в Go

  • Создание и использование функций

  • Структуры данных

  • Организация и структура кода

  • Рекомендуемая литература по Golang

  • Использование библиотеки Sort

  • и другие темы.

Подробнее о курсе Golang (GO) →

Курс «Go (Golang)» [BRO-IT]

Видеоуроки:

  • Установка языка программирования Go и среды разработки, создание и компиляция первой программы

  • Создание переменных, типы данных и получение ввода от пользователя в Golang

  • Написание программы с использованием условных операторов if...else, оптимизация сборки exe-файла в Golang и сборка под релиз

  • Циклы в Go: работа с циклами, различные типы циклов, обработка срезов и массивов

  • и другие темы.

Подробнее о курсе Golang (GO) →

Показать полностью
Удаленная работа Фриланс Обучение Дистанционное обучение Курсы Онлайн-курсы Курсы повышения квалификации Образование Развитие Карьера Учеба Работа Профессия Онлайн-школа Онлайн Программирование Курсы программирования Программист Golang Блоги компаний YouTube (ссылка) Длиннопост
Блог компании Партнёрский материал Реклама
practicum.yandex
practicum.yandex
15 дней назад

Python, 1С, тестирование и еще один курс для тех, кто хочет стартовать в IT⁠⁠

Собрали наши курсы программирования для тех, кто хочет освоить новую профессию в IT.

Python, 1С, тестирование и еще один курс для тех, кто хочет стартовать в IT IT, Онлайн-курсы, Программист, Программирование, Обучение, Длиннопост, Блоги компаний

Тестировщик

Сколько учиться: 5 месяцев

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

На курсе вы изучите 12 инструментов, которые потребуются в работе. Например, Python и язык запросов SQL, графический редактор Figma и инструмент для тестирования API Postman. К концу обучения у вас в портфолио будет семь проектов.

Первый модуль можно пройти бесплатно — поймете, подходит ли вам это направление.

Начать учиться бесплатно>>


Разработчик 1С

Сколько учиться: есть базовый курс на 6 месяцев и расширенный — на 8.

1С — язык программирования для работы с продуктами одноименной компании. Он помогает автоматизировать бизнес-процессы и разрабатывать бизнес-ориентированные приложения. В России с 1С работают и большинство компаний, как небольших, так и крупных.

За полгода вы научитесь работать с платформой и писать код на языке 1С, поработаете с отчетами и системой компоновки данных, научитесь создавать механизмы бухгалтерского учета. Вас ждет девять итоговых работ и выпускной проект.

Начать учиться бесплатно>>


Python-разработчик буткемп

Сколько учиться: 4 месяца

Курс включает восемь блоков. Первый и второй — знакомство с Python, остальные — более глубокое погружение в тему. Например, бэкенд на Django, изучение алгоритмов и структуры данных, разбор асинхронностей и нюансов работы с Flask.

Формат буткемп — это интенсивное обучение. Нагрузка в неделю составит около 30 часов, вы можете рассчитывать на поддержку наставников.

Начать учиться бесплатно>>


Системный администратор

Сколько учиться: 6 месяцев

Сисадмин отвечает за исправность информационной инфраструктуры компании. В зоне его ответственности компьютерные системы, сети, серверы, ПО и безопасность данных.

На протяжении всего обучения вы будете знакомиться с Linux, приложениями с открытым исходным кодом, сетевыми протоколами и системами хранения данных.

Начать учиться бесплатно>>


Чем интенсивнее курс, тем быстрее начинается этап поиска работы. В нашем Карьерном центре мы поддерживаем студентов: помогаем оформлять резюме и портфолио, проходить собеседования, предлагаем вакансии и стажировки от 4000+ партнеров. Стартуйте в IT уверенно!

Реклама ООО «Яндекс», ИНН: 7736207543

Показать полностью
IT Онлайн-курсы Программист Программирование Обучение Длиннопост Блоги компаний
16
2
PENTEST.DNA
PENTEST.DNA
1 год назад
Web-технологии

Создание TCP-прокси⁠⁠

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Вы можете реализовать все 𝗧𝗖𝗣-взаимодействия, используя встроенный в 𝗚𝗼 пакет 𝗻𝗲𝘁. В предыдущем разделе мы сосредоточились главным образом на его применении с позиции клиента. В этом же разделе задействуем его для создания 𝗧𝗖𝗣-серверов и передачи данных. Изучение этого процесса начнется с создания эхо-сервера — сервера, который просто возвращает запрос обратно клиенту. Затем мы создадим две более универсальные в применении программы: переадресатор 𝗧𝗖𝗣-портов и 𝗡𝗲𝘁𝗰𝗮𝘁-функцию «зияющая дыра в безопасности», применяемую для удаленного выполнения команд.


Использование io.Reader и io.Writer



При создании примеров этого раздела вам потребуется задействовать два значимых типа: 𝗶𝗼.𝗥𝗲𝗮𝗱𝗲𝗿 и 𝗶𝗼.𝗪𝗿𝗶𝘁𝗲𝗿. Они необходимы для всех задач ввода/вывода (𝗜/𝗢) вне зависимости от того, задействуете вы 𝗧𝗖𝗣, 𝗛𝗧𝗧𝗣, файловую систему или любые другие средства. Будучи частью встроенного в 𝗚𝗼 пакета 𝗶𝗼, эти типы являются краеугольным камнем любой передачи данных, как локальной, так и сетевой. В документации они определены так:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Оба типа определяются как интерфейсы, то есть напрямую их создать нельзя. Каждый тип содержит определение одной экспортируемой функции: 𝗥𝗲𝗮𝗱 или 𝗪𝗿𝗶𝘁𝗲. Можно рассматривать эти функции как абстрактные методы, которые должны быть реализованы в типе, чтобы он считался 𝗥𝗲𝗮𝗱𝗲𝗿 или 𝗪𝗿𝗶𝘁𝗲𝗿. Например, следующий искусственный тип выполняет это соглашение и может использоваться там, где приемлем 𝗥𝗲𝗮𝗱𝗲𝗿:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Давайте с помощью них создадим что-нибудь полуготовое: настраиваемый 𝗥𝗲𝗮𝗱𝗲𝗿 и 𝗪𝗿𝗶𝘁𝗲𝗿, обертывающий 𝘀𝘁𝗱𝗶𝗻 и 𝘀𝘁𝗱𝗼𝘂𝘁. Код для этого тоже будет несколько искусственным, так как типы 𝗚𝗼 𝗼𝘀.𝗦𝘁𝗱𝗶𝗻 и 𝗼𝘀.𝗦𝘁𝗱𝗼𝘂𝘁 уже действуют как 𝗥𝗲𝗮𝗱𝗲𝗿 и 𝗪𝗿𝗶𝘁𝗲𝗿. Но если не пытаться изобрести колесо, то ничему и не научишься, ведь так?

Ниже показана полная реализация, а далее дано пояснение.

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Реализация reader и writer /io-example/main.go

Этот код определяет два пользовательских типа: 𝗙𝗼𝗼𝗥𝗲𝗮𝗱𝗲𝗿 и 𝗙𝗼𝗼𝗪𝗿𝗶𝘁𝗲𝗿. В каждом типе вы определяете конкретную реализацию функции 𝗥𝗲𝗮𝗱([]𝗯𝘆𝘁𝗲) для 𝗙𝗼𝗼𝗥𝗲𝗮𝗱𝗲𝗿 и функции 𝗪𝗿𝗶𝘁𝗲([]𝗯𝘆𝘁𝗲) для 𝗙𝗼𝗼𝗪𝗿𝗶𝘁𝗲𝗿. В этом случае обе функции считывают из 𝘀𝘁𝗱𝗶𝗻 и записывают в 𝘀𝘁𝗱𝗼𝘂𝘁.

Обратите внимание на то, что функции 𝗥𝗲𝗮𝗱 и в 𝗙𝗼𝗼𝗥𝗲𝗮𝗱𝗲𝗿, и в 𝗼𝘀.𝗦𝘁𝗱𝗶𝗻 возвращают длину данных и все ошибки. Сами эти данные копируются в срез 𝗯𝘆𝘁𝗲, передаваемый этой функции. Это согласуется с начальным определением интерфейса 𝗥𝗲𝗮𝗱𝗲𝗿, приведенным в данном разделе ранее. Функция 𝗺𝗮𝗶𝗻() создает этот срез с названием 𝗶𝗻𝗽𝘂𝘁 и затем использует его в вызовах к 𝗙𝗼𝗼𝗥𝗲𝗮𝗱𝗲𝗿.𝗥𝗲𝗮𝗱([]𝗯𝘆𝘁𝗲) и 𝗙𝗼𝗼𝗥𝗲𝗮𝗱𝗲𝗿.𝗪𝗿𝗶𝘁𝗲([]𝗯𝘆𝘁𝗲).

При пробном запуске программы мы получим следующий вывод:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Копирование данных из 𝗥𝗲𝗮𝗱𝗲𝗿 в 𝗪𝗿𝗶𝘁𝗲𝗿 — это настолько распространенный шаблон, что пакет 𝗶𝗼 содержит специальную функцию 𝗖𝗼𝗽𝘆(), которую можно задействовать для упрощения функции 𝗺𝗮𝗶𝗻(). Вот ее прототип:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Эта удобная функция позволяет реализовывать то же поведение программы, что и ранее, заменив 𝗺𝗮𝗶𝗻() кодом, показанным ниже.

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Применение io.Copy /ch-2/copy-example/main.go

Обратите внимание, что явные вызовы 𝗿𝗲𝗮𝗱𝗲𝗿.𝗥𝗲𝗮𝗱([ ]𝗯𝘆𝘁𝗲) и 𝘄𝗿𝗶𝘁𝗲𝗿.𝗪𝗿𝗶𝘁𝗲([ ] 𝗯𝘆𝘁𝗲) были замещены одним вызовом 𝗶𝗼.𝗖𝗼𝗽𝘆(𝘄𝗿𝗶𝘁𝗲𝗿, 𝗿𝗲𝗮𝗱𝗲𝗿). Внутренне 𝗶𝗼.𝗖𝗼𝗽𝘆(𝘄𝗿𝗶𝘁𝗲𝗿, 𝗿𝗲𝗮𝗱𝗲𝗿) вызывает в переданном ридере функцию 𝗥𝗲𝗮𝗱([ ]𝗯𝘆𝘁𝗲), в результате чего 𝗙𝗼𝗼𝗥𝗲𝗮𝗱𝗲𝗿 выполняет считывание из 𝘀𝘁𝗱𝗶𝗻. Далее 𝗶𝗼.𝗖𝗼𝗽𝘆(𝘄𝗿𝗶𝘁𝗲𝗿, 𝗿𝗲𝗮𝗱𝗲𝗿) вызывает в переданном райтере функцию 𝗪𝗿𝗶𝘁𝗲([ ]𝗯𝘆𝘁𝗲), что приводит к вызову 𝗙𝗼𝗼𝗪𝗿𝗶𝘁𝗲𝗿, записывающего данные в 𝘀𝘁𝗱𝗼𝘂𝘁. По сути, 𝗶𝗼.𝗖𝗼𝗽𝘆(𝘄𝗿𝗶𝘁𝗲𝗿, 𝗿𝗲𝗮𝗱𝗲𝗿) обрабатывает последовательный процесс чтения/записи без лишних деталей.

Этот вводный раздел никак нельзя считать подробным рассмотрением системы 𝗜/𝗢 и интерфейсов в 𝗚𝗼. Многие вспомогательные функции и пользовательские ридеры/райтеры существуют как часть стандартных пакетов 𝗚𝗼. В большинстве случаев эти стандартные пакеты содержат все основные реализации, необходимые для реализации большинства распространенных задач. В следующем разделе мы рассмотрим применение всех этих основ к 𝗧𝗖𝗣-коммуникациям и в итоге применим полученные навыки для разработки реальных рабочих инструментов.



Создание эхо-сервера:

Как и во многих языках, изучение процесса чтения/записи данных с сокета мы начнем с построения эхо-сервера. Для этого будем использовать 𝗻𝗲𝘁.𝗖𝗼𝗻𝗻 — потокоориентированное соединение 𝗚𝗼, с которым вы уже познакомились при создании сканера портов. Как указано в документации для этого типа данных, 𝗖𝗼𝗻𝗻 реализует функции 𝗥𝗲𝗮𝗱([ ]𝗯𝘆𝘁𝗲) и 𝗪𝗿𝗶𝘁𝗲([ ]𝗯𝘆𝘁𝗲) согласно определению для интерфейсов 𝗥𝗲𝗮𝗱𝗲𝗿 и 𝗪𝗿𝗶𝘁𝗲𝗿. Следовательно, 𝗖𝗼𝗻𝗻 одновременно является и 𝗥𝗲𝗮𝗱𝗲𝗿, и 𝗪𝗿𝗶𝘁𝗲𝗿 (да, такое возможно). Это вполне логично, так как 𝗧𝗖𝗣-соединения двунаправленные и могут использоваться для отправки (записи) и получения (чтения) данных.

После создания экземпляра conn вы сможете отправлять и получать данные через TCP-сокет. Тем не менее TCP-сервер не может просто создать соединение, его должен установить клиент. В 𝗚𝗼 для начального открытия 𝗧𝗖𝗣-слушателя на конкретном порте можно использовать 𝗻𝗲𝘁.𝗟𝗶𝘀𝘁𝗲𝗻(𝗻𝗲𝘁𝘄𝗼𝗿𝗸, 𝗮𝗱𝗱𝗿𝗲𝘀𝘀 𝘀𝘁𝗿𝗶𝗻𝗴). После подключения клиента метод 𝗔𝗰𝗰𝗲𝗽𝘁() создает и возвращает объект 𝗖𝗼𝗻𝗻, который вы можете применять для получения и отправки данных.

Ниже показан полноценный пример реализации сервера. Для большей ясности мы добавили в код комментарии. Не стремитесь сразу понять весь код, так как позже мы подробно его поясним.

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Базовый эхо-сервер /ch-2/echo-server/main.go

Базовый эхо-сервер начинается с определения функции 𝗲𝗰𝗵𝗼(𝗻𝗲𝘁.𝗖𝗼𝗻𝗻), которая принимает в качестве параметра экземпляр 𝗖𝗼𝗻𝗻. Он выступает в роли обработчика соединения, выполняя все необходимые операции 𝗜/𝗢. Эта функция повторяется бесконечно, используя буфер для считывания данных из соединения и их записи в него. Данные считываются в переменную 𝗯, после чего записываются обратно в соединение.

Теперь нужно настроить слушатель, который будет вызывать обработчик. Как ранее говорилось, сервер не может сам создать соединение и должен прослушивать подключение клиента. Следовательно, слушатель, определенный как 𝘁𝗰𝗽, привязанный к порту 𝟮𝟬𝟬𝟴𝟬, запускается во всех интерфейсах посредством функции 𝗻𝗲𝘁.𝗟𝗶𝘀𝘁𝗲𝗻(𝗻𝗲𝘁𝘄𝗼𝗿𝗸, 𝗮𝗱𝗱𝗿𝗲𝘀𝘀 𝘀𝘁𝗿𝗶𝗻𝗴).

Далее бесконечный цикл обеспечивает, чтобы сервер продолжал прослушивание соединений даже после того, как оно было установлено. В этом цикле происходит вызов 𝗹𝗶𝘀𝘁𝗲𝗻𝗲𝗿.𝗔𝗰𝗰𝗲𝗽𝘁() ❻ — функции, блокирующей выполнение при ожидании подключений. Когда клиент подключается, эта функция возвращает экземпляр 𝗖𝗼𝗻𝗻. Напомним, что 𝗖𝗼𝗻𝗻 является и 𝗥𝗲𝗮𝗱𝗲𝗿, и 𝗪𝗿𝗶𝘁𝗲𝗿 (реализует методы интерфейса 𝗥𝗲𝗮𝗱([ ]𝗯𝘆𝘁𝗲) и 𝗪𝗿𝗶𝘁𝗲([ ]𝗯𝘆𝘁𝗲)).

После этого экземпляр 𝗖𝗼𝗻𝗻 передается в функцию обработки 𝗲𝗰𝗵𝗼(𝗻𝗲𝘁.𝗖𝗼𝗻𝗻). Перед ее вызовом указано ключевое слово 𝗴𝗼, делающее этот вызов многопоточным, в результате чего другие подключения в ожидании завершения функции-обработчика не блокируются. Это может показаться излишним для столь простого сервера, но мы добавили эту функциональность для демонстрации простоты паттерна многопоточности 𝗚𝗼 на случай, если вы еще не до конца его поняли. В данный момент у вас есть два легковесных параллельно выполняющихся потока.

  • Основной поток зацикливается и блокируется функцией listener.Accept() на время ожидания ею следующего подключения.

  • Горутина обработки, чье выполнение было передано в функцию echo(net.Conn), возобновляется и обрабатывает данные.


Далее показан пример использования 𝗧𝗲𝗹𝗻𝗲𝘁 в качестве подключающегося клиента:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Сервер производит следующий стандартный вывод:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост


Революционно, не правда ли? Сервер, возвращающий клиенту в точности то, что клиент ему отправил. Очень полезный и сильный пример!



Создание буферизованного слушателя для улучшения кода:



Пример в коде Базового эхо-сервера работает прекрасно, но он опирается на чисто низкоуровневые вызовы функции, отслеживание буфера и повторяющиеся циклы чтения/записи. Это довольно утомительный и подверженный ошибкам процесс. К счастью, в 𝗚𝗼 есть и другие пакеты, которые могут его упростить и уменьшить сложность кода. Говоря конкретнее, пакет 𝗯𝘂𝗳𝗶𝗼 обертывает 𝗥𝗲𝗮𝗱𝗲𝗿 и 𝗪𝗿𝗶𝘁𝗲𝗿 для создания буферизованного механизма 𝗜/𝗢. Далее приведена обновленная функция 𝗲𝗰𝗵𝗼(𝗻𝗲𝘁.𝗖𝗼𝗻𝗻) с сопутствующим описанием изменений:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

В экземпляре 𝗖𝗼𝗻𝗻 больше не происходит прямого вызова функций 𝗥𝗲𝗮𝗱([]𝗯𝘆𝘁𝗲) и 𝗪𝗿𝗶𝘁𝗲([]𝗯𝘆𝘁𝗲). Вместо этого вы инициализируете новые буферизованные 𝗥𝗲𝗮𝗱𝗲𝗿 и 𝗪𝗿𝗶𝘁𝗲𝗿 через 𝗡𝗲𝘄𝗥𝗲𝗮𝗱𝗲𝗿(𝗶𝗼.𝗥𝗲𝗮𝗱𝗲𝗿) и 𝗡𝗲𝘄𝗪𝗿𝗶𝘁𝗲𝗿(𝗶𝗼.𝗪𝗿𝗶𝘁𝗲𝗿). Оба вызова в качестве параметра получают существующие 𝗥𝗲𝗮𝗱𝗲𝗿 и 𝗪𝗿𝗶𝘁𝗲𝗿 (помните, что тип 𝗖𝗼𝗻𝗻 реализует необходимые функции, чтобы считаться 𝗥𝗲𝗮𝗱𝗲𝗿 и 𝗪𝗿𝗶𝘁𝗲𝗿).

Оба буферизованных экземпляра содержат вспомогательные функции для чтения и сохранения данных. 𝗥𝗲𝗮𝗱𝗦𝘁𝗿𝗶𝗻𝗴(𝗯𝘆𝘁𝗲) получает символ-разграничитель, обозначая, до какой точки выполнять считывание, а 𝗪𝗿𝗶𝘁𝗲𝗦𝘁𝗿𝗶𝗻𝗴(𝗯𝘆𝘁𝗲) записывает строку в сокет. При записи данных вам нужно явно вызывать 𝘄𝗿𝗶𝘁𝗲𝗿.𝗙𝗹𝘂𝘀𝗵() для сброса всех данных внутреннему райтеру (в данном случае экземпляру 𝗖𝗼𝗻𝗻).

Несмотря на то что предыдущий пример упрощает процесс, применяя буферизацию 𝗜/𝗢, вы можете переработать его под использование вспомогательной функции 𝗖𝗼𝗽𝘆(𝗪𝗿𝗶𝘁𝗲𝗿, 𝗥𝗲𝗮𝗱𝗲𝗿). Напомним, что функция получает в качестве ввода целевой 𝗪𝗿𝗶𝘁𝗲𝗿 и исходный 𝗥𝗲𝗮𝗱𝗲𝗿, просто выполняя копирование из источника в место назначения.

В этом примере вы передаете переменную 𝗰𝗼𝗻𝗻 и как источник, и как место назначения, так как в итоге будете отражать содержимое обратно в установленное соединение:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Вот вы и познакомились с основами системы 𝗜/𝗢, попутно применив ее к 𝗧𝗖𝗣-серверам. Пришло время перейти к более полезным и представляющим для вас интерес примерам.



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



Теперь, когда у вас под ногами есть твердая почва, можете применить полученные навыки для создания простого переадресатора портов для проксирования соединения через промежуточный сервис или хост. Как уже говорилось, это пригождается для обхода ограничивающего контроля исходящего трафика или использования системы с целью обхода сегментации сети. Прежде чем перейти к коду, рассмотрите вымышленную, но вполне реалистичную задачу: Андрей является малоэффективным сотрудником компании 𝗔𝗖𝗠𝗘 𝗜𝗻𝗰., работая на должности бизнес-аналитика и получая приличную зарплату просто потому, что слегка приукрасил данные своего резюме. (Неужели он реально учился в школе Лиги плюща? Андрей, такой обман неэтичен.) Недостаток мотивации Андрея может по силе сравниться разве что с его любовью к кошкам — такой сильной, что он даже установил дома специальные видеокамеры и создал сайт 𝗷𝗼𝗲𝘀𝗰𝗮𝘁𝗰𝗮𝗺.𝘄𝗲𝗯𝘀𝗶𝘁𝗲, через который удаленно следил за своими мохнатыми питомцами. Тем не менее здесь была одна сложность: 𝗔𝗖𝗠𝗘 следит за Андреем. Им не нравится, что он круглые сутки передает потоковое видео своих кошек в ультравысоком разрешении 𝟰𝗞, занимая ценный пропускной канал сети. Компания даже заблокировала своим сотрудникам возможность посещать его кошачий сайт.

Но у хитрого Андрея и здесь возник план: «А что, если я настрою переадресатор портов в подконтрольной мне интернет-системе и буду перенаправлять весь трафик с этого хоста на 𝗷𝗼𝗲𝘀𝗰𝗮𝘁𝗰𝗮𝗺.𝘄𝗲𝗯𝘀𝗶𝘁𝗲?» На следующий день Андрей отмечается на работе и убеждается в возможности доступа к личному сайту, размещенному на домене 𝗷𝗼𝗲𝘀𝗽𝗿𝗼𝘅𝘆.𝗰𝗼𝗺. Он пропускает все встречи после обеда и отправляется в кафетерий, где быстро пишет код для своей задачи, подразумевающей перенаправление на 𝗵𝘁𝘁𝗽://𝗷𝗼𝗲𝘀𝗰𝗮𝘁𝗰𝗮𝗺.𝘄𝗲𝗯𝘀𝗶𝘁𝗲 всего входящего на 𝗵𝘁𝘁𝗽://𝗷𝗼𝗲𝘀𝗽𝗿𝗼𝘅𝘆.𝗰𝗼𝗺 трафика.

Вот код Андрея, который он запускает на сервере 𝗷𝗼𝗲𝘀𝗽𝗿𝗼𝘅𝘆.𝗰𝗼𝗺:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Начнем с рассмотрения функции 𝗵𝗮𝗻𝗱𝗹𝗲(𝗻𝗲𝘁.𝗖𝗼𝗻𝗻). Андрей подключается к 𝗷𝗼𝗲𝘀𝗰𝗮𝘁𝗰𝗮𝗺.𝘄𝗲𝗯𝘀𝗶𝘁𝗲 (вспомните, что этот хост недоступен напрямую с его рабочего места). Затем он использует 𝗖𝗼𝗽𝘆(𝗪𝗿𝗶𝘁𝗲𝗿, 𝗥𝗲𝗮𝗱𝗲𝗿) в двух разных местах. Первый экземпляр обеспечивает копирование данных из входящего соединения в соединение 𝗷𝗼𝗲𝘀𝗰𝗮𝘁𝗰𝗮𝗺.𝘄𝗲𝗯𝘀𝗶𝘁𝗲. Второй же обеспечивает, чтобы считанные из 𝗷𝗼𝗲𝘀𝗰𝗮𝘁𝗰𝗮𝗺.𝘄𝗲𝗯𝘀𝗶𝘁𝗲 данные записывались обратно в соединение подключающегося клиента. Так как 𝗖𝗼𝗽𝘆(𝗪𝗿𝗶𝘁𝗲𝗿, 𝗥𝗲𝗮𝗱𝗲𝗿) является блокирующей функцией и будет продолжать блокировать выполнение, пока сетевое соединение открыто, Андрей предусмотрительно обертывает первый вызов 𝗖𝗼𝗽𝘆(𝗪𝗿𝗶𝘁𝗲𝗿, 𝗥𝗲𝗮𝗱𝗲𝗿) в новую горутину. Это гарантирует продолжение выполнения в функции 𝗵𝗮𝗻𝗱𝗹𝗲(𝗻𝗲𝘁.𝗖𝗼𝗻𝗻) и дает возможность выполнить второй вызов 𝗖𝗼𝗽𝘆(𝗪𝗿𝗶𝘁𝗲𝗿, 𝗥𝗲𝗮𝗱𝗲𝗿).

Прокси-сервер Андрей прослушивает порт 𝟴𝟬 и ретранслирует весь трафик, получаемый через это соединение, на порт 𝟴𝟬 сайта 𝗷𝗼𝗲𝘀𝗰𝗮𝘁𝗰𝗮𝗺.𝘄𝗲𝗯𝘀𝗶𝘁𝗲 и обратно. Этот безумный и расточительный парень убеждается, что может подключаться к 𝗷𝗼𝗲𝘀𝗰𝗮𝘁𝗰𝗮𝗺.𝘄𝗲𝗯𝘀𝗶𝘁𝗲 через 𝗷𝗼𝗲𝘀𝗽𝗿𝗼𝘅𝘆.𝗰𝗼𝗺 с помощью 𝗰𝘂𝗿𝗹:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Так Андрей успешно реализует коварный замысел. Он прекрасно устроился, получив возможность в оплачиваемое 𝗔𝗖𝗠𝗘 время использовать их же канал связи для наблюдения за жизнью своих питомцев.



Воспроизведение функции Netcat для выполнения команд:



В этом разделе мы воспроизведем одну из наиболее интересных функций 𝗡𝗲𝘁𝗰𝗮𝘁 — «зияющую дыру в безопасности».

𝗡𝗲𝘁𝗰𝗮𝘁 — это как швейцарский армейский нож для 𝗧𝗖𝗣/𝗜𝗣, который представляет собой более гибкую версию 𝗧𝗲𝗹𝗻𝗲𝘁 с поддержкой сценариев. Эта утилита имеет возможность перенаправлять 𝘀𝘁𝗱𝗶𝗻 и 𝘀𝘁𝗱𝗼𝘂𝘁 любой произвольной программы через 𝗧𝗖𝗣, позволяя атакующему, например, превратить уязвимость к выполнению одной команды в доступ к оболочке операционной системы. Взгляните:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Эта команда создает прослушивающий сервер на порте 𝟭𝟯𝟯𝟯𝟳. Любой подключающийся, возможно, через 𝗧𝗲𝗹𝗻𝗲𝘁, клиент сможет выполнить любые команды 𝗯𝗮𝘀𝗵 — вот почему данную функцию и называют зияющей дырой в безопасности. 𝗡𝗲𝘁𝗰𝗮𝘁 позволяет при желании включить такую возможность в процессе компиляции программы. (По понятным причинам большинство исполняемых файлов 𝗡𝗲𝘁𝗰𝗮𝘁 в стандартных сборках 𝗟𝗶𝗻𝘂𝘅 ее не включают.) Эта функция настолько потенциально опасна, что мы покажем, как воссоздать ее в 𝗚𝗼.

Для начала загляните в пакет 𝗚𝗼 𝗼𝘀/𝗲𝘅𝗲𝗰. Он будет использоваться для выполнения команд операционной системы. Этот пакет определяет тип 𝗖𝗺𝗱, который содержит необходимые методы и свойства для выполнения команд и управления 𝘀𝘁𝗱𝗶𝗻 и 𝘀𝘁𝗱𝗼𝘂𝘁. Вы будете перенаправлять 𝘀𝘁𝗱𝗶𝗻 (𝗥𝗲𝗮𝗱𝗲𝗿) и 𝘀𝘁𝗱𝗼𝘂𝘁 (𝗪𝗿𝗶𝘁𝗲𝗿) в экземпляр 𝗖𝗼𝗻𝗻, представляющий и 𝗥𝗲𝗮𝗱𝗲𝗿, и 𝗪𝗿𝗶𝘁𝗲𝗿.

При получении нового подключения создать экземпляр 𝗖𝗺𝗱 можно с помощью функции 𝗖𝗼𝗺𝗺𝗮𝗻𝗱(𝗻𝗮𝗺𝗲 𝘀𝘁𝗿𝗶𝗻𝗴, 𝗮𝗿𝗴 ...𝘀𝘁𝗿𝗶𝗻𝗴) из 𝗼𝘀/𝗲𝘅𝗲𝗰. Эта функция получает в качестве параметров команды ОС и любые аргументы. В данном примере нужно жестко закодировать в качестве команды /𝗯𝗶𝗻/𝘀𝗵 и передать в качестве аргумента -𝗶, чтобы перейти в интерактивный режим, из которого можно будет управлять потоками 𝘀𝘁𝗱𝗶𝗻 и 𝘀𝘁𝗱𝗼𝘂𝘁 более уверенно:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Эта инструкция создает экземпляр 𝗖𝗺𝗱, но команду еще не выполняет. Здесь для управления 𝘀𝘁𝗱𝗶𝗻 и 𝘀𝘁𝗱𝗼𝘂𝘁 есть два варианта: использовать 𝗖𝗼𝗽𝘆(𝗪𝗿𝗶𝘁𝗲𝗿, 𝗥𝗲𝗮𝗱𝗲𝗿), как говорилось ранее, или напрямую присвоить 𝗥𝗲𝗮𝗱𝗲𝗿 и 𝗪𝗿𝗶𝘁𝗲𝗿 экземпляру 𝗖𝗺𝗱. Давайте непосредственно присвоим объект 𝗖𝗼𝗻𝗻 экземплярам 𝗰𝗺𝗱.𝗦𝘁𝗱𝗶𝗻 и 𝗰𝗺𝗱.𝗦𝘁𝗱𝗼𝘂𝘁:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

После настройки команды и потоков запустить ее можно с помощью 𝗰𝗺𝗱.𝗥𝘂𝗻():

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Такая логика прекрасно работает для систем 𝗟𝗶𝗻𝘂𝘅. Тем не менее при настройке и запуске этой программы под 𝗪𝗶𝗻𝗱𝗼𝘄𝘀 с помощью 𝗰𝗺𝗱.𝗲𝘅𝗲, а не /𝗯𝗶𝗻/𝗯𝗮𝘀𝗵, подключающийся клиент не получает вывод команды из-за специфичной для 𝗪𝗶𝗻𝗱𝗼𝘄𝘀 обработки анонимных каналов. Далее описаны два решения этой проблемы.

Во-первых, можно настроить код для принудительного сброса 𝘀𝘁𝗱𝗼𝘂𝘁. Вместо непосредственного присваивания 𝗖𝗼𝗻𝗻 экземпляру 𝗰𝗺𝗱.𝗦𝘁𝗱𝗼𝘂𝘁 нужно реализовать собственный 𝗪𝗿𝗶𝘁𝗲𝗿, который обертывает 𝗯𝘂𝗳𝗶𝗼.𝗪𝗿𝗶𝘁𝗲𝗿 (буферизованный райтер) и явно вызывает его метод 𝗙𝗹𝘂𝘀𝗵 для принудительного сброса буфера. Пример использования 𝗯𝘂𝗳𝗶𝗼.𝗪𝗿𝗶𝘁𝗲𝗿 можно найти в разделе «Создание эхо-сервера» ранее в этой главе. Вот определение пользовательского райтера, 𝗙𝗹𝘂𝘀𝗵𝗲𝗿:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Тип 𝗙𝗹𝘂𝘀𝗵𝗲𝗿 реализует функцию 𝗪𝗿𝗶𝘁𝗲([]𝗯𝘆𝘁𝗲), которая записывает данные во внутренний буферизованный райтер, а затем сбрасывает вывод.

С помощью этой реализации пользовательского райтера можно настроить обработчик подключений на создание экземпляра и применение типа 𝗙𝗹𝘂𝘀𝗵𝗲𝗿 для 𝗰𝗺𝗱.𝗦𝘁𝗱𝗼𝘂𝘁:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Продолжение кода выше

Это решение хотя и вполне пригодно, но не очень элегантно. Несмотря на то что рабочий код для нас важнее, чем аккуратный, мы используем эту проблему как возможность рассказать о функции 𝗶𝗼.𝗣𝗶𝗽𝗲(). Она представляет собой синхронный канал в памяти 𝗚𝗼, который можно задействовать для подключения 𝗥𝗲𝗮𝗱𝗲𝗿 и 𝗪𝗿𝗶𝘁𝗲𝗿:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Применение 𝗣𝗶𝗽𝗲𝗥𝗲𝗮𝗱𝗲𝗿 и 𝗣𝗶𝗽𝗲𝗪𝗿𝗶𝘁𝗲𝗿 позволяет избежать необходимости явного сброса райтера и синхронного подключения 𝘀𝘁𝗱𝗼𝘂𝘁 и 𝗧𝗖𝗣-соединения. Опять же понадобится переписать функцию обработчика:

Создание TCP-прокси Информационная безопасность, Хакеры, Программирование, Golang, Программист, Интернет, Длиннопост

Вызов 𝗶𝗼.𝗣𝗶𝗽𝗲 создает ридер и райтер, подключаемые синхронно, — любые данные, записываемые в райтер (в данном примере 𝘄𝗽), будут считаны ридером (𝗿𝗽). Поэтому сначала происходит присваивание райтера экземпляру 𝗰𝗺𝗱.𝗦𝘁𝗱𝗼𝘂𝘁, после чего используется 𝗶𝗼.𝗖𝗼𝗽𝘆(𝗰𝗼𝗻𝗻, 𝗿𝗽) для присоединения 𝗣𝗶𝗽𝗲𝗥𝗲𝗮𝗱𝗲𝗿 к 𝗧𝗖𝗣-соединению. Это делается с помощью горутины, предотвращающей блокирование кода. Любой стандартный вывод команды отправляется райтеру, после чего передается ридеру и далее через 𝗧𝗖𝗣-соединение. Как вам такая элегантность?

Таким образом, мы успешно реализовали «зияющую дыру безопасности» 𝗡𝗲𝘁𝗰𝗮𝘁 с позиции 𝗧𝗖𝗣-слушателя, ожидающего подключения. По тому же принципу можно реализовать эту функцию с позиции подключающегося клиента, перенаправляющего 𝘀𝘁𝗱𝗼𝘂𝘁 и 𝘀𝘁𝗱𝗶𝗻 локального исполняемого файла удаленному слушателю. Детали этого процесса мы оставим вам для самостоятельной реализации, но в общем они будут включать следующее:

  • установку подключения к удаленному слушателю через net.Dial(network, address string);

  • инициализацию Cmd через exec.Command(name string, arg ...string);

  • перенаправление свойств Stdin и Stdout для использования объекта net.Conn;

  • выполнение команды.

На этом этапе слушатель должен получить подключение. Любые передаваемые клиенту данные должны интерпретироваться на клиенте как 𝘀𝘁𝗱𝗶𝗻, а данные, получаемые слушателем, — как 𝘀𝘁𝗱𝗼𝘂𝘁.

На этом всё, ждите в ближайшее время больше статей.

ССЫЛКА НА ТЕЛЕГРАМ КАНАЛ АВТОРА

Показать полностью 21
[моё] Информационная безопасность Хакеры Программирование Golang Программист Интернет Длиннопост
0
6
PENTEST.DNA
PENTEST.DNA
1 год назад
Web-технологии

TCP, сканеры и прокси⁠⁠

TCP, сканеры и прокси Программирование, Информационная безопасность, Хакеры, Golang, IT, Программист, Длиннопост

В роли атакующего вы должны понимать принцип работы 𝗧𝗖𝗣, чтобы справляться с разработкой пригодных вариантов его конструкций, позволяющих определять открытые/закрытые порты, распознавать такие потенциально ошибочные результаты, как ложные срабатывания — например, 𝗦𝗬𝗡-флуд защиты, — и обходить ограничения на исходящий трафик посредством переадресации портов. В этой главе вы изучите основы 𝗧𝗖𝗣-коммуникаций в 𝗚𝗼, реализуете многопоточный правильно отрегулированный сканер портов, создадите 𝗧𝗖𝗣-прокси, который можно использовать для переадресации портов, а также воссоздадите 𝗡𝗲𝘁𝗰𝗮𝘁-функцию «зияющая дыра в безопасности».

В интернете куча информации которые раскрывают каждый нюанс 𝗧𝗖𝗣, включая такие темы, как потоки и структура пакетов, надежность, повторная сборка сегментов и многие другие. Настолько подробная детализация выходит за рамки этой темы, поэтому я рекомендую глубже изучить эту тему, после прочтения статьи.

TCP Handshaking:



В качестве напоминания мы начнем с основ. снизу будет показано, как 𝗧𝗖𝗣 при запросе порта использует процесс рукопожатия (𝗵𝗮𝗻𝗱𝘀𝗵𝗮𝗸𝗶𝗻𝗴), определяя, открыт порт, закрыт или фильтруется.

TCP, сканеры и прокси Программирование, Информационная безопасность, Хакеры, Golang, IT, Программист, Длиннопост

Основы рукопожатия в TCP


Если порт открыт, рукопожатие осуществляется в три этапа. Сначала клиент отправляет пакет 𝘀𝘆𝗻, определяющий начало сеанса связи. В ответ на это сервер отправляет 𝘀𝘆𝗻-𝗮𝗰𝗸, иначе говоря, подтверждение получения пакета 𝘀𝘆𝗻, предлагая клиенту завершить сеанс установки связи отправкой сигнала 𝗮𝗰𝗸, то есть встречного подтверждения получения ответа сервера. После этого может начаться обмен данными. Если же порт будет закрыт, сервер ответит пакетом 𝗿𝘀𝘁, а не 𝘀𝘆𝗻-𝗮𝗰𝗸. В случае, когда трафик фильтруется межсетевым экраном (брандмауэром), клиент обычно не получает от сервера ответа.

При написании сетевых протоколов важно понимать принцип работы этих пакетов. Соответствие выходных данных создаваемых вами инструментов этим низкоуровневым потокам пакетов поможет убедиться в правильной установке сетевого соединения и устранить потенциальные проблемы. Как вы увидите чуть позже, в коде можно легко допустить ошибки, не реализовав полный цикл рукопожатия при соединении «клиент — сервер», что приведет к неточным или вводящим в заблуждение результатам.



Обход брандмауэра с помощью переадресации портов:



Иногда в системах с целью ограничения доступа клиента к конкретным серверам и портам устанавливаются брандмауэры. В некоторых случаях эти ограничения можно обойти, используя промежуточную систему для проксирования в обход или через такой брандмауэр. Эта техника называется переадресацией портов.

Многие корпоративные сети ограничивают возможность подключения своих внутренних ресурсов к вредоносным сайтам. В качестве примера представьте такой сайт под названием 𝗲𝘃𝗶𝗹.𝗰𝗼𝗺. Если сотрудник компании попытается подключиться к нему напрямую, брандмауэр заблокирует его запрос. Но если у сотрудника есть собственная внешняя система, доступная через брандмауэр (например, 𝘀𝘁𝗮𝗰𝗸𝘁𝗶𝘁𝗮𝗻.𝗰𝗼𝗺), то он может задействовать ее для установки связи с 𝗲𝘃𝗶𝗹.𝗰𝗼𝗺. Этот принцип отражен снизу.

TCP, сканеры и прокси Программирование, Информационная безопасность, Хакеры, Golang, IT, Программист, Длиннопост

TCP-проски

Клиент подключается к удаленному хосту 𝘀𝘁𝗮𝗰𝗸𝘁𝗶𝘁𝗮𝗻.𝗰𝗼𝗺 через брандмауэр. Этот хост настроен на перенаправление соединений к хосту 𝗲𝘃𝗶𝗹.𝗰𝗼𝗺. Несмотря на то что брандмауэр запрещает прямые подключения к 𝗲𝘃𝗶𝗹.𝗰𝗼𝗺, описанная конфигурация позволяет клиенту обойти этот механизм защиты.

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



Написание TCP-сканера:



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

Написав базовый сканер портов, вы перейдете к созданию его ускоренной версии. Базово эта программа способна сканировать множество портов, используя один непрерывный метод, но если вам потребуется выполнить сканирование всех 𝟲𝟱 𝟱𝟯𝟱 портов, это может занять слишком много времени. Поэтому мы научим вас с помощью многопоточности делать малоэффективный сканер более подходящим для выполнения задач расширенного сканирования. Освоенные в этой статье шаблоны параллельности вы сможете применять и во многих других сценариях.


Тестирование портов на доступность:


Первый шаг в создании сканера портов — понять процесс инициирования соединения от клиента к серверу. В рассматриваемом примере вы будете подключаться к 𝘀𝗰𝗮𝗻𝗺𝗲.𝗻𝗺𝗮𝗽.𝗼𝗿𝗴 — сервису проекта 𝗡𝗺𝗮𝗽𝟭 и сканировать его. Для этого мы с вами задействуем пакет 𝗚𝗼 𝗻𝗲𝘁: 𝗻𝗲𝘁.𝗗𝗶𝗮𝗹(𝗻𝗲𝘁𝘄𝗼𝗿𝗸, 𝗮𝗱𝗱𝗿𝗲𝘀𝘀 𝘀𝘁𝗿𝗶𝗻𝗴).

Первый аргумент — это строка, определяющая тип инициируемого соединения. Дело в том, что 𝗗𝗶𝗮𝗹 используется не только для 𝗧𝗖𝗣, но и для создания соединений, задействующих сокеты 𝗨𝗻𝗶𝘅, 𝗨𝗗𝗣 и протоколы 𝟰-го уровня, которые мы оставим в стороне, так как на основе всего нашего опыта будет достаточно просто сказать, что 𝗧𝗖𝗣 очень хорош. В этот аргумент можно передать несколько вариантов строк, но для краткости будем использовать строку 𝘁𝗰𝗽.

Второй аргумент указывает 𝗗𝗶𝗮𝗹(𝗻𝗲𝘁𝘄𝗼𝗿𝗸, 𝗮𝗱𝗱𝗿𝗲𝘀𝘀 𝘀𝘁𝗿𝗶𝗻𝗴) на хост, к которому вы хотите подключиться. Обратите внимание на то, что это одна строка, а не 𝘀𝘁𝗿𝗶𝗻𝗴 и 𝗶𝗻𝘁. Для соединений 𝗜𝗣𝘃𝟰/𝗧𝗖𝗣 она будет принимать форму 𝗵𝗼𝘀𝘁:𝗽𝗼𝗿𝘁. Например, если вам нужно подключиться к 𝘀𝗰𝗮𝗻𝗺𝗲.𝗻𝗺𝗮𝗽.𝗼𝗿𝗴 через 𝗧𝗖𝗣-порт 𝟴𝟬, то нужно указать 𝘀𝗰𝗮𝗻𝗺𝗲.𝗻𝗺𝗮𝗽.𝗼𝗿𝗴:𝟴𝟬.

Теперь вы знаете, как создать соединение, но как понять, что оно было успешным? Для этого выполняется проверка на ошибки: 𝗗𝗶𝗮𝗹(𝗻𝗲𝘁𝘄𝗼𝗿𝗸, 𝗮𝗱𝗱𝗿𝗲𝘀𝘀 𝘀𝘁𝗿𝗶𝗻𝗴) возвращает Conn и error. При этом error будет nil, если соединение установлено успешно. Так что для проверки вам просто нужно убедиться, что error равна nil. Вот теперь у вас есть все необходимые элементы для построения сканера портов, хотя и не особо корректного. В Основах рукопожатия в TCP показано, как все это объединить.

TCP, сканеры и прокси Программирование, Информационная безопасность, Хакеры, Golang, IT, Программист, Длиннопост

Простой сканер портов, сканирующий только один порт /dial/main.go

Выполнив этот код, вы должны увидеть сообщение 𝗖𝗼𝗻𝗻𝗲𝗰𝘁𝗶𝗼𝗻 𝘀𝘂𝗰𝗰𝗲𝘀𝘀𝗳𝘂𝗹 при условии наличия у вас доступа к великой информационной супермагистрали


Выполнение однопоточного сканирования:



Сканирование по одному порту за раз не особо полезно и малоэффективно, так как диапазон 𝗧𝗖𝗣-портов — от 𝟭 до 𝟲𝟱 𝟱𝟯𝟱. В целях же тестирования давайте пока просканируем порты от 𝟭 до 𝟭𝟬𝟮𝟰. Для этого можно использовать цикл 𝗳𝗼𝗿:

TCP, сканеры и прокси Программирование, Информационная безопасность, Хакеры, Golang, IT, Программист, Длиннопост

Теперь у вас есть 𝗶𝗻𝘁, но нужно помнить, что в качестве второго аргумента для 𝗗𝗶𝗮𝗹(𝗻𝗲𝘁𝘄𝗼𝗿𝗸, 𝗮𝗱𝗱𝗿𝗲𝘀𝘀 𝘀𝘁𝗿𝗶𝗻𝗴) требуется строка. Есть по меньшей мере два способа преобразования целого числа в строку. Первый — использовать пакет преобразования строк 𝘀𝘁𝗿𝗰𝗼𝗻𝘃. Второй — применить функцию 𝗦𝗽𝗿𝗶𝗻𝘁𝗳(𝗳𝗼𝗿𝗺𝗮𝘁 𝘀𝘁𝗿𝗶𝗻𝗴, 𝗮 ...𝗶𝗻𝘁𝗲𝗿𝗳𝗮𝗰𝗲{}) из пакета 𝗳𝗺𝘁, которая (аналогично своему собрату в 𝗖) возвращает 𝘀𝘁𝗿𝗶𝗻𝗴, сгенерированную из строки формата (𝗳𝗼𝗿𝗺𝗮𝘁 𝘀𝘁𝗿𝗶𝗻𝗴).


Создайте файл с кодом из листинга 𝟮.𝟮 и убедитесь в работоспособности цикла и функции генерации строки. Выполнение этого кода должно вывести 𝟭𝟬𝟮𝟰 строки, но утруждать себя их подсчетом не обязательно.

TCP, сканеры и прокси Программирование, Информационная безопасность, Хакеры, Golang, IT, Программист, Длиннопост

Сканирование 1024 портов scanme.nmap.org /tcp-scanner-slow/main.go

Теперь осталось только подставить переменную адреса из предыдущего кода в 𝗗𝗶𝗮𝗹(𝗻𝗲𝘁𝘄𝗼𝗿𝗸, 𝗮𝗱𝗱𝗿𝗲𝘀𝘀 𝘀𝘁𝗿𝗶𝗻𝗴) и протестировать доступность портов, реализовав такую же проверку ошибок, как в предыдущем разделе. Помимо этого, чтобы не оставлять успешные соединения открытыми, следует добавить логику их закрытия. Завершение соединений — это жест вежливости. Для этого вам нужно выполнить в 𝗖𝗼𝗻𝗻 вызов 𝗖𝗹𝗼𝘀𝗲(). Снизу показана полноценная реализация сканера портов.

TCP, сканеры и прокси Программирование, Информационная безопасность, Хакеры, Golang, IT, Программист, Длиннопост

Завершенный сканер портов /tcp-scanner-slow/main.go

Скомпилируйте и выполните этот код для выполнения легкого сканирования цели. Вы должны обнаружить пару открытых портов.



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



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



Слишком быстрая версия сканера:



Самым прямолинейным способом создания параллельного сканера будет обернуть вызов 𝗗𝗶𝗮𝗹(𝗻𝗲𝘁𝘄𝗼𝗿𝗸, 𝗮𝗱𝗱𝗿𝗲𝘀𝘀 𝘀𝘁𝗿𝗶𝗻𝗴) в горутину. Чтобы собственными глазами увидеть последствия этого, создайте файл 𝘀𝗰𝗮𝗻-𝘁𝗼𝗼-𝗳𝗮𝘀𝘁.𝗴𝗼 с кодом который снизу.

TCP, сканеры и прокси Программирование, Информационная безопасность, Хакеры, Golang, IT, Программист, Длиннопост

Сканер, работающий слишком быстро /tcp-scanner-too-fast/main.go

При выполнении кода вы заметите, что программа завершается практически мгновенно:

TCP, сканеры и прокси Программирование, Информационная безопасность, Хакеры, Golang, IT, Программист, Длиннопост

Этот код запускает по одной горутине для каждого соединения, а основная горутина не знает, что нужно ждать окончания его установки. В связи с этим выполнение кода завершается, как только цикл 𝗳𝗼𝗿 заканчивает перебор, что происходит быстрее, чем сеть успевает осуществить обмен пакетами между кодом и всеми целевыми портами. Поэтому вы не получите точных результатов для портов, чьи пакеты находились в процессе обмена.


Исправить это можно несколькими способами. Первый — использовать 𝗪𝗮𝗶𝘁𝗚𝗿𝗼𝘂𝗽 из пакета 𝘀𝘆𝗻𝗰, предоставляющий потокобезопасный способ управления параллельным выполнением. 𝗪𝗮𝗶𝘁𝗚𝗿𝗼𝘂𝗽 — это тип структуры, который создается так:

TCP, сканеры и прокси Программирование, Информационная безопасность, Хакеры, Golang, IT, Программист, Длиннопост

Создав 𝗪𝗮𝗶𝘁𝗚𝗿𝗼𝘂𝗽, вы можете вызвать для этой структуры несколько методов. Первый метод — 𝗔𝗱𝗱(𝗶𝗻𝘁), увеличивающий внутренний счетчик согласно переданному числу. Следующий — метод 𝗗𝗼𝗻𝗲(), уменьшающий счетчик на 𝟭. И наконец, метод 𝗪𝗮𝗶𝘁(), блокирующий выполнение горутины, в которой вызывается, запрещая дальнейЭтот вариант кода по большому счету остался неизменным. Тем не менее здесь мы добавили код, явно отслеживающий оставшуюся работу. В этой версии программышее выполнение, пока внутренний счетчик не достигнет нуля. Эти вызовы можно совмещать, гарантируя, что основная горутина дождется завершения всех соединений.


Синхронизированное сканирование с помощью WaitGroup:

TCP, сканеры и прокси Программирование, Информационная безопасность, Хакеры, Golang, IT, Программист, Длиннопост

Синхронизированный сканер, использующий WaitGroup /tcp-scanner-wg-too-fast/main.go

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

создаем 𝘀𝘆𝗻𝗰.𝗪𝗮𝗶𝘁𝗚𝗿𝗼𝘂𝗽, выступающую в качестве синхронизированного счетчика. Мы увеличиваем этот счетчик через 𝘄𝗴.𝗔𝗱𝗱(𝟭) при каждом создании горутины для сканирования порта. При этом отложенный вызов 𝘄𝗴.𝗗𝗼𝗻𝗲() уменьшает этот счетчик при завершении каждой единицы работы. Функция 𝗺𝗮𝗶𝗻() вызывает 𝘄𝗴.𝗪𝗮𝗶𝘁(), который блокирует выполнение, пока не будет выполнена вся работа и счетчик не достигнет нуля.

Эта версия программы уже лучше, но по-прежнему имеет недостатки. Если запустить ее несколько раз для разных хостов, можно получить несогласованные результаты. Одновременное сканирование чрезмерного количества хостов или портов может привести к тому, что ограничения системы или сети исказят результаты. Попробуйте изменить в коде значение 𝟭𝟬𝟮𝟰 на 𝟲𝟱𝟱𝟯𝟱 и укажите адрес целевого сервера как 𝟭𝟮𝟳.𝟬.𝟬.𝟭. При желании можете использовать 𝗪𝗶𝗿𝗲𝘀𝗵𝗮𝗿𝗸 или 𝘁𝗰𝗽𝗱𝘂𝗺𝗽, чтобы увидеть, насколько быстро открываются эти соединения.



Сканирование портов с помощью пула воркеров:



Чтобы избежать несогласованности, можно задействовать для управления параллельным выполнением пул горутин. С помощью цикла 𝗳𝗼𝗿 вы создаете определенное количество воркеров горутин в качестве пула. Затем в потоке 𝗺𝗮𝗶𝗻() с помощью канала обеспечиваете работу.

Для начала создайте новую программу, которая использует канал 𝗶𝗻𝘁, содержит 𝟭𝟬𝟬 воркеров и выводит их результаты на экран. При этом задействуйте 𝗪𝗮𝗶𝘁𝗚𝗿𝗼𝘂𝗽 для блокирования выполнения.

Создайте начальную заглушку кода для функции 𝗺𝗮𝗶𝗻, а над ней напишите функцию,приведенную в коде ниже

TCP, сканеры и прокси Программирование, Информационная безопасность, Хакеры, Golang, IT, Программист, Длиннопост

Функция с воркером для выполнения задачи.

Функция 𝘄𝗼𝗿𝗸𝗲𝗿(𝗶𝗻𝘁, *𝘀𝘆𝗻𝗰.𝗪𝗮𝗶𝘁𝗚𝗿𝗼𝘂𝗽) получает два аргумента: канал типа 𝗶𝗻𝘁 и указатель на 𝗪𝗮𝗶𝘁𝗚𝗿𝗼𝘂𝗽. Канал будет использоваться для получения работы, а 𝗪𝗮𝗶𝘁𝗚𝗿𝗼𝘂𝗽 — для отслеживания завершения одной ее единицы.

Далее добавьте функцию 𝗺𝗮𝗶𝗻(), приведенную в коде ниже, которая будет управлять рабочей нагрузкой и обеспечивать работу функции 𝘄𝗼𝗿𝗸𝗲𝗿(𝗶𝗻𝘁, *𝘀𝘆𝗻𝗰.𝗪𝗮𝗶𝘁𝗚𝗿𝗼𝘂𝗽).

TCP, сканеры и прокси Программирование, Информационная безопасность, Хакеры, Golang, IT, Программист, Длиннопост

Базовый пул воркеров /tcp-sync-scanner/main.go

Сначала создается канал с помощью 𝗺𝗮𝗸𝗲(). В 𝗺𝗮𝗸𝗲() в качестве второго параметра передается значение 𝟭𝟬𝟬. Это добавляет каналу буферизацию, то есть в него можно будет отправлять элемент и не ждать, пока получатель этот элемент прочтет. Буферизованные каналы идеально подходят для поддержания и отслеживания работы нескольких производителей и потребителей. Емкость канала определяется как 𝟭𝟬𝟬. Значит, он может вместить 𝟭𝟬𝟬 элементов, до того как отправитель будет заблокирован. Это дает небольшой прирост производительности, поскольку все воркеры смогут запускаться сразу.

Далее с помощью цикла 𝗳𝗼𝗿 запускается заданное число воркеров — в данном случае 𝟭𝟬𝟬. В функции 𝘄𝗼𝗿𝗸𝗲𝗿(𝗶𝗻𝘁, *𝘀𝘆𝗻𝗰.𝗪𝗮𝗶𝘁𝗚𝗿𝗼𝘂𝗽) с помощью 𝗿𝗮𝗻𝗴𝗲 происходит непрерывное циклическое получение данных из канала 𝗽𝗼𝗿𝘁𝘀, завершающееся только при закрытии канала. Обратите внимание: пока воркер никакой работы не выполняет — это произойдет чуть позже. Последовательно перебирая порты в функции 𝗺𝗮𝗶𝗻(), вы отправляете порт через канал 𝗽𝗼𝗿𝘁𝘀 воркеру. По завершении всей работы закрываете канал.

Запустив эту программу, вы увидите, как на экран выводятся числа. Здесь можно заметить кое-что интересное, а именно то, что выводятся они в конкретном порядке. Добро пожаловать в прекрасный мир многопоточности!



Многоканальная связь:



Чтобы завершить создание сканера, можно вставить код, использованный ранее в этом разделе, и это вполне сработает. Но в таком случае выводимые порты будут не отсортированы, так как сканер станет проверять их не по порядку. Решить эту проблему можно, реализовав упорядоченную передачу результатов сканирования в основной поток через дополнительный. Это изменение к тому же позволит полностью устранить зависимость от 𝗪𝗮𝗶𝘁𝗚𝗿𝗼𝘂𝗽, так как теперь у вас будет другой метод для отслеживания завершения. Например, если вы сканируете 𝟭𝟬𝟮𝟰 порта, то делаете по каналу воркера 𝟭𝟬𝟮𝟰 передачи, после чего снова выполняете 𝟭𝟬𝟮𝟰 передачи с результатами работы обратно в основной поток. Поскольку количество отправленных единиц работы и полученных результатов совпадает, программа понимает, когда нужно закрывать каналы и, следовательно, отключать воркеры.


Эта модификация кода представлена в коде ниже, которым завершается создание сканера.

TCP, сканеры и прокси Программирование, Информационная безопасность, Хакеры, Golang, IT, Программист, Длиннопост

Сканирование портов через несколько каналов /tcp-scanner-final/main.go

Функция 𝘄𝗼𝗿𝗸𝗲𝗿(𝗽𝗼𝗿𝘁𝘀, 𝗿𝗲𝘀𝘂𝗹𝘁𝘀 𝗰𝗵𝗮𝗻 𝗶𝗻𝘁) была изменена для получения двух каналов. Остальная логика почти полностью осталась прежней, за исключением того, что в случае закрытого порта вы отправляете ноль, а в случае открытого — значение этого порта. Кроме того, здесь вы создаете отдельный канал для передачи результатов от воркера в основной поток. Затем результаты сохраняются в срез, что позволяет выполнить их сортировку. Далее вам нужно реализовать отправку данных воркера в отдельной горутине, потому что цикл сбора результатов должен начаться до того, как сможет продолжиться выполнение более 𝟭𝟬𝟬 единиц работы.

Этот цикл получает по каналу 𝗿𝗲𝘀𝘂𝗹𝘁𝘀 𝟭𝟬𝟮𝟰 передачи. Если порт не равен 𝟬, он добавляется в срез. После закрытия каналов вы используете сортировку для упорядочивания среза открытых портов. Далее остается лишь перебрать срез и вывести открытые порты на экран.

Вот мы и написали высокопроизводительный сканер портов. Уделите время экспериментированию с кодом — в частности, с количеством воркеров. Чем их больше, тем быстрее должна выполняться программа. Но если их окажется слишком много, результаты станут ненадежными. При написании инструментов, которые будут применять другие люди, вам нужно использовать грамотное предустановленное значение, которое ориентировано на надежность, а не на скорость. При этом также следует предоставлять пользователям опцию самостоятельного выбора количества воркеров.

В полученную программу можно внести пару улучшений. Во-первых, вы отправляете по каналу 𝗿𝗲𝘀𝘂𝗹𝘁𝘀 результат сканирования каждого порта, что необязательно. Альтернативное решение потребует написания более сложного кода, который будет использовать дополнительный канал не только для отслеживания воркеро. Вам может потребоваться, чтобы сканер умел парсить строки с портами, например 𝟴𝟬,𝟰𝟰𝟯,𝟴𝟬𝟴𝟬,𝟮𝟭-𝟮𝟱, наподобие тех, что могут быть переданы в 𝗡𝗺𝗮𝗽. Я предлагаю вам освоить этот прием самостоятельно.

P.S: в следующей статье мы рассмотрим создание TCP-прокси.

ССЫЛКА НА ТЕЛЕГРАМ КАНАЛ АВТОРА

Показать полностью 13
[моё] Программирование Информационная безопасность Хакеры Golang IT Программист Длиннопост
1
0
PENTEST.DNA
PENTEST.DNA
1 год назад
Web-технологии

Подключение к базам данных и запрос информации с помощью Go⁠⁠

Подключение к базам данных и запрос информации с помощью Go Информационная безопасность, Хакеры, Golang, Программирование, Безопасность, IT, Взлом, Программист, Длиннопост

Запрос данных из MongoDBL:


Несмотря на наличие прекрасного стандартного 𝗦𝗤𝗟-пакета, 𝗚𝗼 не поддерживает аналогичный пакет для работы с базами данных 𝗡𝗼𝗦𝗤𝗟. Для этого вам придется использовать сторонние инструменты. Вместо изучения реализации каждого такого стороннего пакета мы сосредоточимся исключительно на 𝗠𝗼𝗻𝗴𝗼𝗗𝗕. Для этого будем применять драйвер 𝗺𝗴𝗼 (произносится «манго»). Начните с установки 𝗺𝗴𝗼:

Подключение к базам данных и запрос информации с помощью Go Информационная безопасность, Хакеры, Golang, Программирование, Безопасность, IT, Взлом, Программист, Длиннопост

Теперь можно установить подключение и запросить коллекцию 𝘀𝘁𝗼𝗿𝗲 (эквивалент таблицы), для чего потребуется еще меньше кода, чем в примере с 𝗦𝗤𝗟, который мы создадим чуть позже.

Подключение к базам данных и запрос информации с помощью Go Информационная безопасность, Хакеры, Golang, Программирование, Безопасность, IT, Взлом, Программист, Длиннопост

Подключение к базе данных MongoDB и запрос данных

Сначала идет определение типа 𝗧𝗿𝗮𝗻𝘀𝗮𝗰𝘁𝗶𝗼𝗻, который будет представлять один документ из коллекции 𝘀𝘁𝗼𝗿𝗲. Внутренний механизм представления данных в 𝗠𝗼𝗻𝗴𝗼𝗗𝗕 — это двоичный 𝗝𝗦𝗢𝗡. По этой причине для определения любых директив маршалинга используются теги. В этом случае с их помощью мы явно определяем имена элементов для применения в двоичных данных 𝗝𝗦𝗢𝗡.

В функции 𝗺𝗮𝗶𝗻() вызов 𝗺𝗴𝗼.𝗗𝗶𝗮𝗹() создает сессию, устанавливая подключение к базе данных, выполняя тестирование на наличие ошибок и реализуя отложенный вызов для закрытия сессии. После этого с помощью переменной 𝘀𝗲𝘀𝘀𝗶𝗼𝗻 запрашивается база данных 𝘀𝘁𝗼𝗿𝗲, откуда извлекаются все записи коллекции 𝘁𝗿𝗮𝗻𝘀𝗮𝗰𝘁𝗶𝗼𝗻𝘀. Результаты мы сохраняем в срезе 𝗧𝗿𝗮𝗻𝘀𝗮𝗰𝘁𝗶𝗼𝗻 под названием 𝗿𝗲𝘀𝘂𝗹𝘁𝘀. Теги структуры используются для демаршалинга двоичного 𝗝𝗦𝗢𝗡 в определенный нами тип. В завершение выполняется перебор результатов и их вывод на экран. И в этом случае, и в примере с 𝗦𝗤𝗟 из следующего раздела вывод должен выглядеть так:

Подключение к базам данных и запрос информации с помощью Go Информационная безопасность, Хакеры, Golang, Программирование, Безопасность, IT, Взлом, Программист, Длиннопост


Обращение к базам данных SQL:



𝗚𝗼 содержит стандартный пакет 𝗱𝗮𝘁𝗮𝗯𝗮𝘀𝗲/𝘀𝗾𝗹, который определяет интерфейс для взаимодействия с базами данных 𝗦𝗤𝗟 и их аналогами. Базовая реализация автоматически включает такую функциональность, как пул подключений и поддержка транзакций. Драйверы базы данных, соответствующие этому интерфейсу, автоматически наследуют эти возможности и, по сути, являются взаимозаменяемыми, поскольку 𝗔𝗣𝗜 между ними остается согласованным. Вызовы функций и реализация в коде идентичны независимо от того, используете вы 𝗣𝗼𝘀𝘁𝗴𝗿𝗲𝘀, 𝗠𝗦𝗦𝗤𝗟, 𝗠𝘆𝗦𝗤𝗟 или другой драйвер. В результате этого удобно менять серверные базы данных при минимальном изменении кода клиента. Конечно же, эти драйверы могут реализовывать специфичные для БД возможности и задействовать различный 𝗦𝗤𝗟-синтаксис, но вызовы функций при этом практически одинаковы. Поэтому мы покажем, как подключать всего одну базу данных 𝗦𝗤𝗟 — 𝗠𝘆𝗦𝗤𝗟, а остальные БД 𝗦𝗤𝗟 оставим в качестве самостоятельного упражнения. Начнем с установки драйвера:

Подключение к базам данных и запрос информации с помощью Go Информационная безопасность, Хакеры, Golang, Программирование, Безопасность, IT, Взлом, Программист, Длиннопост

Далее создадим простой клиент, который подключается к этой базе данных и извлекает информацию из таблицы transactions, как показано в коде ниже.

Подключение к базам данных и запрос информации с помощью Go Информационная безопасность, Хакеры, Golang, Программирование, Безопасность, IT, Взлом, Программист, Длиннопост

Код начинается с импорта пакета 𝗚𝗼 𝗱𝗮𝘁𝗮𝗯𝗮𝘀𝗲/𝘀𝗾𝗹. Это позволяет реализовать взаимодействие с базой данных через удобный интерфейс стандартной библиотеки 𝗦𝗤𝗟. Кроме того, мы импортируем драйвер базы данных. Начальное подчеркивание указывает на то, что она импортируется анонимно, то есть ее экспортируемые типы не включаются, но драйвер регистрируется пакетом 𝘀𝗾𝗹, и в результате драйвер 𝗠𝘆𝗦𝗤𝗟 сам обрабатывает вызовы функций.

Далее идет вызов 𝘀𝗾𝗹.𝗢𝗽𝗲𝗻() для установки подключения к базе данных. Первый параметр указывает, какой драйвер использовать — в данном случае это 𝗺𝘆𝘀𝗾𝗹, а второй определяет строку подключения. Затем мы обращаемся к базе данных, передавая инструкцию 𝗦𝗤𝗟 для выбора всех строк из таблицы 𝘁𝗿𝗮𝗻𝘀𝗮𝗰𝘁𝗶𝗼𝗻𝘀, после чего перебираем эти строки, последовательно считывая данные в переменные и выводя значения.

Это все, что необходимо для запроса данных из 𝗠𝘆𝗦𝗤𝗟. Для использования другой серверной БД потребуется внести в код лишь минимальные изменения:

  • импортировать подходящий драйвер базы данных;

  • изменить передаваемые в sql.Open() параметры;

  • скорректировать SQL-синтаксис в соответствии с требованиями серверной базы данных.

Среди нескольких доступных драйверов баз данных часть написаны на чистом 𝗚𝗼. А некоторые другие используют 𝗰𝗴𝗼 для ряда внутренних взаимодействий. Полный список доступных драйверов можно найти здесь: 𝗵𝘁𝘁𝗽𝘀://𝗴𝗶𝘁𝗵𝘂𝗯.𝗰𝗼𝗺/𝗴𝗼𝗹𝗮𝗻𝗴/𝗴𝗼/𝘄𝗶𝗸𝗶/𝗦𝗤𝗟𝗗𝗿𝗶𝘃𝗲𝗿𝘀/.

ССЫЛКА НА ТЕЛЕГРАМ КАНАЛ АВТОРА

Показать полностью 5
[моё] Информационная безопасность Хакеры Golang Программирование Безопасность IT Взлом Программист Длиннопост
0
PENTEST.DNA
PENTEST.DNA
1 год назад

Написание DNS-клиентов⁠⁠

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Прежде чем начать знакомство с более сложными программами, рассмотрим ряд опций, доступных для клиентских операций. Встроенный в Go пакет net предлагает обширную функциональность и поддерживает большинство, если не все типы записей. Преимущество этого пакета — в простоте его API. Например, LookupAddr(addr string) возвращает список имен хостов для заданного IP-адреса. Недостаток же его заключается в невозможности указывать целевой сервер. Вместо этого пакет использует настроенный в операционной системе механизм распознавания. К недостаткам можно отнести также отсутствие возможности выполнения углубленного анализа результатов.

Для обхода этих недочетов мы задействуем отличный сторонний пакет Go DNS, написанный Миком Гибеном (Miek Gieben). Предпочесть этот DNS-пакет всем прочим стоит из-за его высокой модульности и грамотно написанного и протестированного кода. Вот команда для его установки:

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

$ go get github.com/miekg/dns

Установив пакет, вы будете готовы к проработке последующих примеров кода. Начнем с выполнения поиска А-записей для получения IP-адресов из имен хостов.


Извлечение А-записей:

Сперва познакомимся с поиском для полностью уточненного имени домена (fully qualified domain name, FQDN), которое указывает точное расположение хоста в иерархии DNS. Затем попробуем интерпретировать это FQDN в IP-адрес с помощью DNS-записи А. Эта запись связывает имя домена с IP-адресом. (Все листинги кода находятся в корневом каталоге /exist репозитория GitHub https://github.com/blackhat-go/bhg/.)

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Код на языке Golang

Сначала создается msg , после чего идет вызов fqdn(string) для преобразования этого домена в FQDN, которым можно обменяться с DNS-сервером . Далее нужно изменить внутреннее состояние Msg на вызов SetQuestion(string, uint16)

с помощью значения TypeA, указывающего, что нужно искать А-запись. (В пакете она определена как const. Другие поддерживаемые значения можно найти в документации.) В завершение мы помещаем вызов Exchange(*Msg, string) , чтобы отправить сообщение на предоставленный адрес сервера, в данном случае являющегося DNS-сервером, обслуживаемым Google.

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

Перед выполнением программы которая написана выше запустите анализатор пакетов, например Wireshark или tcpdump, чтобы просмотреть трафик. Вот пример возможного использования tcpdump на хосте Linux:

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

$ sudo tcpdump -i eth0 -n udp port 53

В отдельном окне терминала скомпилируйте и выполните программу:

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

$ go run main.go

После выполнения кода в выходных данных перехвата пакетов должны отобразиться подключение к 8.8.8.8 через UDP 53, а также детали DNS-протокола:

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Две из получаемых при перехвате пакетов строчек нуждаются в дополнительном пояснении. Сначала запрос отправляется с 192.168.7.51 к 8.8.8.8 с помощью UDP 53, при этом происходит запрос А-записи. В ответе от DNS-сервера Google 8.8.8.8 содержится интерпретированный из имени домена IP-адрес 104.131.56.170.

С помощью анализатора пакетов можно преобразовать имя домена stacktitan.com в IP-адрес. Теперь посмотрим, как извлечь эту информацию, используя Go.


Отработка ответов от структуры Msg:


В качестве значения Exchange(*Msg, string) возвращает (*Msg, error). Возврат типа error имеет смысл и является стандартным для идиом Go, но почему в ответе приходит также изначально отправленная *Msg? Чтобы это понять, нужно взглянуть на определение этой struct в исходном коде:

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Код на языке Golang

Как видите, Msg struct содержит как вопросы (question), так и ответы (answer). Это позволяет объединять все DNS-вопросы и ответы на них в единую унифицированную структуру. Тип Msg располагает различными методами, упрощающими работу с данными. Например, срез Question изменяется с помощью метода setQuestion(). Это срез можно изменять напрямую, используя append(), и получать тот же результат. Срез Answer содержит ответ на запросы и имеет тип RR. Ниже будет показано, как эти ответы обрабатывать.

Обработка DNS-ответов:

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Пример начинается с сохранения возвращенных от Exchange значений и их проверки на наличие ошибок. Если ошибка обнаружена, вызывается panic() для остановки программы. Функция panic() позволяет быстро просмотреть трассировку стека и определить место возникновения ошибки. Далее проверяется длина среза Answer. Если она меньше 1, это означает, что записей нет, и происходит возврат — бывают случаи, когда имя домена не может быть интерпретировано.

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

Сначала выполняем перебор ответов. Далее применяем в ответе утверждение типа, чтобы гарантировать работу с типом *dns.A. При выполнении этого действия можно извлечь два значения: данные в виде утвержденного типа и bool, отражающее успешность утверждения. После проверки успешности утверждения происходит вывод IP, сохраненного в a.A. Несмотря на тип net.IP, он реализует метод String(), поэтому его можно легко вывести на экран.

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


Перечисление поддоменов:


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

Используя DNS, можно отправлять запросы настолько быстро, насколько быстро система сможет обрабатывать пакеты данных. Узким местом здесь станут не язык или среда выполнения, а сервер назначения. При этом, как и в предыдущих главах, будет важно управление многопоточностью программы.

Сначала нужно создать в GOPATH каталог под названием subdomain_guesser, а затем файл main.go. После этого в начале создания нового инструмента необходимо решить, какие аргументы эта программа будет получать. В данном случае это будет несколько аргументов, включая целевой домен, имя файла, содержащего поддомены для подбора, используемый DNS-сервер, а также количество запускаемых воркеров. В Go для парсинга опций командной строки есть полезный пакет flag, который мы будем применять для обработки аргументов командной строки. Несмотря на то что мы используем этот пакет не во всех примерах кода, в данном случае он служит для демонстрации более надежного и изящного парсинга аргументов. Код этого процесса будет приведен ниже.

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Создание программы подбора поддоменов на языке Golang

В начале строка кода, объявляющая переменную flDomain, получает аргумент String и объявляет пустое строковое значение для того, что будет парситься как опция domain. Следующая связанная строка — это объявление переменной flWorkerCount. Здесь в качестве опции командной строки c нужно предоставить значение Integer. В данном случае мы устанавливаем 100 воркеров. Но это значение можно счесть консервативным, так что в процессе тестирования смело экспериментируйте с увеличением их числа. В завершение вызов flag.Parse() заполняет переменные, задействуя предоставленный пользователем ввод.


ПРИМЕЧАНИЕ:


Вы могли обратить внимание на то, что этот пример идет вразрез с правилами Unix в том, что определяет необязательные аргументы, которые на деле являются обязательными. Можете свободно использовать здесь os.Args. Просто нам быстрее и удобнее поручить всю работу пакету flag.

При сборке данной программы должна возникнуть ошибка, указывающая на неиспользованные переменные. Добавьте приведенный далее код сразу после вызова flag.Parse(). Это дополнение выводит в stdout переменные наряду с кодом,
гарантируя передачу пользователем -domain и -wordlist:

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Чтобы ваш инструмент сообщал, какие имена оказались интерпретируемыми, указывая при этом соответствующие им IP-адреса, нужно создать для хранения этой информации тип struct. Определите его над функцией main():

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Для этого инструмента вы будете запрашивать два основных типа записей — А и CNAME. Каждый запрос будет выполняться в отдельной функции. Стоит создавать эти функции максимально небольшими и поручать каждой выполнение только одной задачи. Такой стиль разработки позволит в дальнейшем писать менее объемные тесты.


Запрос записей A и CNAME:


Для выполнения запросов мы создадим две функции: одну для А-записей, вторую для записей CNAME. Они обе будут получать FQDN в качестве первого аргумента и адрес DNS-сервера в качестве второго. Каждая из них должна возвращать срез строк и ошибку. Добавьте эти функции в код, который начали определять, расположив вне области main():

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Этот код должен показаться вам знакомым, так как он практически идентичен коду, который мы писали в самом начале главы. Первая функция, lookupA, возвращает список IP-адресов, а lookupCNAME возвращает список имен хостов.

Записи CNAME (канонические имена) сопоставляют одно FQDN с другим, которое служит псевдонимом для первого. Предположим, что владелец организации example.com хочет разместить WordPress-сайт с помощью сервиса хостинга WordPress. У этого сервиса могут быть сотни IP-адресов для балансировки всех пользовательских сайтов, в связи с чем предоставить IP для отдельного сайта просто невозможно. Вместо этого данный хостинг может предоставить каноническое имя (CNAME), на которое и будет ссылаться example.com. В итоге адрес www.example.com получит CNAME, указывающее на somewhere.hostingcompany.org, которое, в свою очередь, будет иметь А-запись, указывающую на IP-адрес. Это позволит владельцу example.com разместить свой сайт на сервере, для которого у него нет IP-данных.

Зачастую это означает, что вам нужно проследить целый хвост из канонических имен, чтобы в итоге добраться до действительной А-записи. Мы говорим хвост, потому что из подобных имен может выстраиваться бесконечная цепочка. Добавьте приведенный далее код функции в область за пределами функции main(), чтобы понаблюдать, как использовать череду CNAMES для нахождения А-записи:

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Сначала определяется срез для хранения результатов. Далее создается копия FQDN, переданного в качестве первого аргумента. В итоге вы не только не теряете исходный угаданный FQDN, но и можете задействовать его в первой попытке запроса. Начав бесконечный цикл, мы пробуем получить CNAME для этого FQDN. В случае отсутствия ошибок и возвращения не менее одного CNAME устанавливаем cfqdn равным этому возвращенному CNAME, используя continue для возврата к началу цикла. Данный процесс позволяет проследить череду CNAME до возникновения сбоя. Последний будет означать, что конец цепочки достигнут и можно искать А-записи. Но если возникнет ошибка, означающая, что при поиске записи возникли проблемы, то выход из цикла произойдет раньше. В случае обнаружения действительных А-записей каждый возвращенный IP-адрес добавляется в срез результатов, а цикл прерывается. В завершение results возвращается вызывающему.

Наша связанная с интерпретацией имен логика выглядит гладко, однако мы не учли производительность. Давайте совместим этот пример с горутинами, добавив в него многопоточность.


Переход к воркер-функции:


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

Продолжим расширять код Создание программы подбора поддоменов. Сначала создадим функцию worker(), разместив ее вне области функции main(). Она будет получать три аргумента каналов: канал для воркера, чтобы он сигнализировал о своем закрытии, канал доменов, в которых нужно получать работу, и канал для отправки результатов. Этой функции потребуется заключительный строковый аргумент для указания используемого DNS-сервера. Далее приведен пример кода для функции worker():

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Прежде чем вводить функцию worker(), определим тип empty для отслеживания завершения выполнения воркера. Это будет структура без полей. Мы задействуем пустую struct, так как она имеет размер 0 байт и практически не создаст нагрузку при использовании. Далее в функции worker() происходит перебор канала доменов, используемый для передачи FQDN. После получения ответа от функции lookup() и проверки наличия не менее одного результата мы отправляем его в канал gather, который собирает все результаты обратно в main(). После того как канал закрывается и цикл совершает выход, структура empty отправляет в канал tracker сигнал вызывающему о завершении всей работы. Отправка пустой struct в канал отслеживания — это важный последний шаг. Если этого не сделать, возникнет состояние гонки, так как вызывающий компонент может выйти до получения каналом gather результатов.

Поскольку вся необходимая структура теперь настроена, можно переключиться обратно на main() и закончить программу, которую мы начали писать в Создание программы подбора поддоменов.

Определите переменные, которые будут содержать результаты и каналы, передаваемые в worker(), после чего добавьте в main() следующий код:

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Создайте канал fqdns как буферизованный на основе предоставленного пользователем количества воркеров. Это позволит воркерам запускаться быстрее, поскольку канал сможет вместить больше одного сообщения до блокировки отправителя.


Создание сканера с помощью bufio:


Далее откройте файл, предоставленный пользователем в качестве списка слов, и создайте в нем новый scanner с помощью пакета bufio. Добавьте в main() код

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Если возвращаемая ошибка не равна nil, используется встроенная функция panic(). При написании пакета или программы для применения другими людьми следует постараться представить эту информацию более ясно.

Мы будем применять новый scanner для захвата строки текста из переданного списка слов и создания FQDN путем совмещения этого текста с предоставленным пользователем доменом. Результат будет отправляться в канал fqdns. Но сначала нужно запустить воркеры, так как порядок важен. Если отправить работу в канал fqdns, не запустив их, этот буферизованный канал в итоге заполнится и функции-производители будут заблокированы. В main() нужно добавить приведенный далее код, чья задача — запускать горутины воркеров, читать вводный файл и отправлять работу в канал fqdns.

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Создание воркеров с помощью этого паттерна похоже на то, что мы уже делали при построении многопоточного сканера портов: задействовали цикл for до момента достижения числа, переданного пользователем. Для захвата каждой строки в цикле используется scanner.Scan(). Этот цикл заканчивается, когда в файле не остается строк для считывания. Для получения строкового представления текста из отсканированной строки мы применяем scanner.Text().

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

Сбор и отображение результатов

Проработку последней части мы начнем с запуска анонимной горутины, которая будет собирать результаты воркеров. Добавьте в main() следующее:

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Перебирая канал gather, мы добавляем полученные результаты в срез results. Поскольку мы добавляем срез в другой срез, нужно использовать синтаксис … . После закрытия канала gather и завершения перебора, как и прежде, происходит отправка пустой struct в канал отслеживания. Это делается для предотвращения состояния гонки на случай, если append() не завершится к моменту итогового предоставления результатов пользователю.

Остается только закрыть каналы и представить результаты. Для этого добавьте следующий код в конец main():

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Первым можно закрыть канал fqdns, так как мы уже отправили по нему всю работу. Далее нужно выполнить получение результатов в канале tracker по одному разу для каждого воркера, что позволит им обозначить свое полное завершение. После этого можно закрыть канал gather, потому что результатов для получения не остается. В завершение нужно выполнить еще одно получение результатов на канале tracker, чтобы позволить горутине окончательно завершиться.

Эти результаты пользователю еще не представлены. Нужно это исправить. При желании можно просто перебрать срез results и вывести поля Hostname и IPAddress, используя fmt.Printf(). Тем не менее мы предпочитаем задействовать для представления данных один из нескольких прекрасных пакетов Go, а именно tabwriter. Он позволяет выводить данные в красивых ровных столбцах, разбитых на вкладки. Для его применения добавьте в конец main() следующий код:

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)


Снизу показана вся программа в сборе:

Package main

import (

"bufio"

"errors"

"flag"

"fmt"

"os"

"text/tabwriter"

"github.com/miekg/dns"

)

func lookupA(fqdn, serverAddr string) ([]string, error) {

var m dns.Msg

var ips []string

m.SetQuestion(dns.Fqdn(fqdn), dns.TypeA)

in, err := dns.Exchange(&m, serverAddr)

if err != nil {

return ips, err

}

if len(in.Answer) < 1 {

return ips, errors.New("no answer")

}

for _, answer := range in.Answer {

if a, ok := answer.(*dns.A); ok {

ips = append(ips, a.A.String())

}

}

return ips, nil

}

func lookupCNAME(fqdn, serverAddr string) ([]string, error) {

var m dns.Msg

var fqdns []string

m.SetQuestion(dns.Fqdn(fqdn), dns.TypeCNAME)

in, err := dns.Exchange(&m, serverAddr)

if err != nil {

return fqdns, err

}

if len(in.Answer) < 1 {

return fqdns, errors.New("no answer")

}

for _, answer := range in.Answer {

if c, ok := answer.(*dns.CNAME); ok {

fqdns = append(fqdns, c.Target)

}

}

return fqdns, nil

}

func lookup(fqdn, serverAddr string) []result {

var results []result

var cfqdn = fqdn // Не изменяем оригинал

For {

cnames, err := lookupCNAME(cfqdn, serverAddr)

if err == nil && len(cnames) > 0 {

cfqdn = cnames[0]

continue // Нужно обработать следующее CNAME

}

ips, err := lookupA(cfqdn, serverAddr)

if err != nil {

break // Для этого имени хоста нет А-записей

}

for _, ip := range ips {

results = append(results, result{IPAddress: ip, Hostname: fqdn})

}

break // Все результаты обработаны

}

return results

}

func worker(tracker chan empty, fqdns chan string, gather chan []result,

serverAddr string) {

for fqdn := range fqdns {

results := lookup(fqdn, serverAddr)

if len(results) > 0 {

gather <- results

}

}

var e empty

tracker <- e

}

type empty struct{}

type result struct {

IPAddress string

Hostname string

}

func main() {

var (

flDomain = flag.String("domain", "", "The domain to perform

guessing against.")

flWordlist = flag.String("wordlist", "", "The wordlist to use

for guessing.")

flWorkerCount = flag.Int("c", 100, "The amount of workers to use.")

flServerAddr = flag.String("server", "8.8.8.8:53", "The DNS server

to use.")

)

flag.Parse()

if *flDomain == "" || *flWordlist == "" {

fmt.Println("-domain and -wordlist are required")

os.Exit(1)

}

var results []result

fqdns := make(chan string, *flWorkerCount)

gather := make(chan []result)

tracker := make(chan empty)

fh, err := os.Open(*flWordlist)

if err != nil {

panic(err)

}

defer fh.Close()

scanner := bufio.NewScanner(fh)

for I := 0; i < *flWorkerCount; i++ {

go worker(tracker, fqdns, gather, *flServerAddr)

}

go func() {

for r := range gather {

results = append(results, I.)

}

var e empty

tracker <- e

}()

for scanner.Scan() {

fqdns <- fmt.Sprintf"%s.%", scanner.Text(), *flDomain)

}

// Заметьте: здесь можно проверить scanner.Err()

close(fqdns)

for i := 0; i < *flWorkerCount; i++ {

<-tracker

}

close(gather)

<-tracker

w := tabwriter.NewWriter(os.Stdout, 0, 8' ', ' ', 0)

for _, r := range results {

fmt.Fprint"(w, "%s\"%s\n", r.Hostname, r.IPAddress)

}

w.Flush()

}


На этом наша программа для подбора поддоменов готова. Теперь вы можете собрать и запустить этот инструмент. Опробуйте его на списках слов или словарях из открытых репозиториев (можете найти множество через Google). Поэкспериментируйте с количеством воркеров. Вы можете заметить, что при слишком быстрой обработке результаты получаются неоднозначные. Вот пример выполнения с использованием ста воркеров:

Написание DNS-клиентов Хакеры, Программирование, Информационная безопасность, Взлом, Программист, Linux, IT, Google, Golang, Пентест, Длиннопост, Telegram (ссылка)

Вы увидите, что вывод показывает несколько FQDN и их IP-адреса. Мы смогли угадать значения поддоменов для каждого результата на основе списка слов, переданного в качестве вводного файла.

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

ССЫЛКА НА ТЕЛЕГРАМ КАНАЛ АВТОРА

Показать полностью 20
Хакеры Программирование Информационная безопасность Взлом Программист Linux IT Google Golang Пентест Длиннопост Telegram (ссылка)
1
NutrientElement
NutrientElement
1 год назад
Типичный программист
Серия Программирование

Под капотом каналов в golang⁠⁠

Внутренняя реализация каналов в Go основана на механизме синхронизации и передачи данных между горутинами.

Под капотом каналов в golang Программирование, IT, Программист, Golang, Разработчики, Разработка

Каналы в Go представляют собой типизированные очереди, которые позволяют горутинам обмениваться данными. Они гарантируют безопасность доступа к данным и синхронизацию выполнения горутин.

Внутренняя реализация каналов в Go включает в себя следующие компоненты:

  • Структура channel: Когда вы создаете канал в Go, создается структура channel, которая содержит информацию о типе данных, буфере (если он есть) и других метаданных канала.

  • Буфер: Каналы могут иметь опциональный буфер, который позволяет хранить определенное количество элементов перед тем, как горутина будет заблокирована при попытке отправки данных в полностью заполненный канал или получении данных из пустого канала. Буфер реализован с помощью внутренней очереди FIFO (First-In-First-Out).

  • Мьютексы: Для обеспечения безопасности доступа к данным в канале используются мьютексы (mutexes). Мьютексы блокируют доступ к данным, пока другая горутина не освободит их. Это позволяет предотвратить состояние гонки (race condition) при одновременной записи и чтении данных из канала.

  • Указатели на горутины: Каналы хранят указатели на горутины, которые ожидают отправки или получения данных. Когда горутина отправляет данные в канал или получает данные из канала, она блокируется, пока другая горутина не освободит канал.

  • Системные вызовы: Внутренняя реализация каналов включает системные вызовы операционной системы для блокировки и разблокировки горутин при отправке и получении данных из канала. Это обеспечивает эффективное использование ресурсов и предотвращает блокировку всей программы.

В целом, внутренняя реализация каналов в Go обеспечивает безопасность доступа к данным и синхронизацию выполнения горутин. Это позволяет разработчикам писать безопасный и эффективный код для параллельного выполнения задач.

Интересные факты и фичи языков программирования у нас в канале, заходи :)

Показать полностью
[моё] Программирование IT Программист Golang Разработчики Разработка
0
Посты не найдены
О нас
О Пикабу Контакты Реклама Сообщить об ошибке Сообщить о нарушении законодательства Отзывы и предложения Новости Пикабу Мобильное приложение RSS
Информация
Помощь Кодекс Пикабу Команда Пикабу Конфиденциальность Правила соцсети О рекомендациях О компании
Наши проекты
Блоги Работа Промокоды Игры Курсы
Партнёры
Промокоды Биг Гик Промокоды Lamoda Промокоды Мвидео Промокоды Яндекс Директ Промокоды Отелло Промокоды Aroma Butik Промокоды Яндекс Путешествия Постила Футбол сегодня
На информационном ресурсе Pikabu.ru применяются рекомендательные технологии