Man
Professional
- Messages
- 2,963
- Reaction score
- 486
- Points
- 83
Что такое блокчейн и EVM-сети?
Блокчейн — это технология, где данные хранятся в распределенной сети. Все участники имеют одинаковую копию данных, а изменения проверяются сетью. Это делает блокчейн прозрачным, надежным и защищенным.
EVM (Ethereum Virtual Machine) — это среда для выполнения смарт-контрактов. EVM-сети, такие как Ethereum, Binance Smart Chain и Polygon, позволяют разработчикам создавать приложения на основе блокчейна с использованием готовых инструментов.
Почему это удобно?
Децентрализация: Заблокировать систему практически невозможно, так как отсутствует единая точка контроля.
Прозрачность и неизменность: После развертывания смарт-контракта его код становится доступен всем и сохраняется навсегда в блокчейне. Изменить контракт нельзя, если только в нем изначально не предусмотрена возможность для этого.
Я Покажу вам пару примеров где это можно использовать.
Первый пример использования:
Представим, у нас есть онлайн-сервис, который по каким-то причинам часто блокируется и теряет часть своих пользователей (условно блокировка домена/хоста/контактов/т.д). Чтобы не терять своих пользователей и клиентов, мы можем использовать блокчейн для координации и информирования их о текущем рабочем адресе/контакте/линке и т.д.
Достаточно, чтобы у наших пользователей было наше приложение, которое общается со смарт-контрактом в блокчейне. В смарт-контракте администратор(мы) может обновлять информацию, например, указывать новый адрес/контакт/линк и т.д. Пользователи, запуская приложение, всегда получают актуальные данные из блокчейна, минуя центральные сервера, которые могут быть заблокированы или недоступны.
Таким образом:
Пользователи всегда остаются на связи: Блокчейн децентрализован, его нельзя заблокировать или "отключить".
Удобство: Достаточно обновить данные в смарт-контракте, и они тут же станут доступны всем пользователям.
Прозрачность: Любой пользователь может проверить, кто обновил данные и когда это было сделано, исключая манипуляции.
Это пример того, как децентрализация и блокчейн могут быть использованы для решения реальных проблем.
Переходим к практике: Установка MetaMask и Развертывание Первого Смарт-Контракта в Сети Ethereum
> 1: Написание смарт-контракта
Используем простой контракт для хранения и обновления домена.
Перед тем как развернуть наш первый смарт-контракт, важно установить и настроить MetaMask — кошелек, который позволит взаимодействовать с блокчейном. Далее мы разберем весь процесс от начала до конца.
1 >>> Установка и настройка MetaMask
Скачиваем MetaMask:
Переходим на официальный сайт MetaMask (https://metamask.io/).
Устанавливаем расширение для браузера (Chrome, Firefox, Edge, Brave).
Создаем кошелек:
Открываем MetaMask и выбираем "Create a Wallet".
Задаем надежный пароль (xD).
Сохраняем секретную фразу из 12 слов. Это важно для восстановления доступа к кошельку, но в примере не буду показывать как, думаю сами резберетесь.
Далее просто тыкаем done, next, next...
Добавим новую сеть к примеру Polygon (если хотите использовать эфириум можете остаться на нем, тогда просто пропуститие добавление).
Сделаем добавление максимально по простому, перейдем на https://polygonscan.com/ и внизу сайта в подвале есть кнопка "Add Polygon Network", нажимем ее, у вас откроется metamask соглашаемся и добавляем, если же не получается попробуйте в самом метамаске добавить нажав слева сверху на сети и там выбрать polygon.
Пополните баланс сети (в нашем случае polygon):
Сделать вы это можете купить крипту или обменять их в обменнике или в ином месте.
2 >>> Написание смарт-контракта
Теперь мы создадим контракт, который позволит хранить и обновлять домен.
Перейдите на Remix IDE (https://remix.ethereum.org/).
Создайте файл DomainManager.sol и вставьте код (сохраняем ctrl + s)
Объяснение кода:
pragma solidity ^0.8.0;: Указывает, что код совместим с версиями компилятора Solidity 0.8.0 и выше.
contract DomainManager: Определяет новый контракт с именем DomainManager.
address public admin: Переменная для хранения Ethereum-адреса администратора.
string public currentDomain: Переменная для хранения текущего домена. Домен — это строка (например, "https://xss.is"), которую могут видеть пользователи.
event DomainUpdated: Событие для записи в лог изменений домена.
oldDomain: Старый домен.
newDomain: Новый домен.
События позволяют отслеживать изменения в блокчейне. Это полезно для приложений, которые слушают блокчейн и реагируют на изменения.
constructor: Функция, которая вызывается один раз при развертывании контракта.
string memory initialDomain: Аргумент конструктора для указания начального домена.
admin = msg.sender: Устанавливает администратора. Администратором становится адрес, который развернул контракт.
currentDomain = initialDomain: Устанавливает начальный домен.
modifier onlyAdmin: Проверяет, что функцию вызывает только администратор.
msg.sender: Адрес, который вызвал функцию.
require(msg.sender == admin, "You are not the admin");: Если адрес вызывающего не совпадает с admin, выполнение функции прерывается, и ошибка возвращается с текстом "You are not the admin".
_: Указывает, где будет выполняться код основной функции, к которой применяется модификатор.
updateDomain: Функция для обновления домена.
string memory newDomain: Новый домен, который администратор хочет установить.
public: Функцию можно вызывать извне.
onlyAdmin: Проверяет, что вызов сделан администратором.
Логика функции:
Сохраняет текущий домен в переменную oldDomain.
Обновляет currentDomain на новый.
Вызывает событие DomainUpdated, логируя старый и новый домен.
getDomain: Функция для получения текущего домена.
public: Доступна для вызова извне.
view: Указывает, что функция только читает данные и не изменяет состояние блокчейна.
returns (string memory): Возвращает строку с текущим доменом.
Как работает контракт.
Развертывание:
При развертывании конструктора задается начальный домен, и развертывающий адрес становится администратором.
Обновление домена:
Администратор вызывает updateDomain, передавая новый домен. Новый домен записывается, а старый фиксируется в логах через событие.
Получение домена:
Любой пользователь может вызвать getDomain, чтобы получить текущий домен.
3 >>> Компиляция контракта
В Remix открываем вкладку "Solidity Compiler".
Убедитесь, что версия компилятора совпадает с pragma solidity ^0.8.0.
Нажмите "Compile DomainManager.sol".
4 >>> Развертывание контракта
Открываем вкладку "Deploy & Run Transactions".
В поле Environment выберите "WalletConnet", и потом жмем Connect Wallet и подключаем наш MetaMask.
Убедимся, что мы подключены к сети (например, Polygon).
В поле "string initialDomain" указываем начальный домен, например: "https://xss.is".
Нажимаем "Deploy" и подтверждаем транзакцию в MetaMask.
После подтверждения контракт будет развернут, а его адрес отобразится в Remix.
Далее копируем наш адрес контракта и запоминаем, он нам нужен будет в дальнейшем (к примеру наш адрес 0xdCe675B975673A569a51d8aDF585c947063aE544)
5 >>> Работа с контрактом
В разделе Deployed Contracts найдите ваш контракт.
Нажмите на функцию getDomain, чтобы получить текущий домен.
Обновите домен с помощью функции updateDomain, указав новый адрес, например: "https://xss.as".
Проверьте, что домен изменился, снова вызвав функцию getDomain.
Теперь у нас есть работающий смарт-контракт для хранения и обновления домена (На самом деле в нем не только можно хранить домен но и вообще любую строку)
Приступим к написанию приложения для администратора на Next.js
Мы создадим простое приложение, которое позволит администратору:
Подключаться к своему кошельку через MetaMask.
Проверять текущий домен из смарт-контракта.
Обновлять домен, если пользователь является администратором.
2 > Установка Node.js и создание приложения администратора на Next.js
Для разработки приложения администратора с использованием Next.js нам нужно сначала установить Node.js, настроить окружение и затем приступить к созданию интерфейса для управления доменом через блокчейн.
1 >>> Установка Node.js
Проверка Node.js на нашем компьютере:
Открываем терминал или командную строку.
Вводим команду:
Если Node.js установлен, мы увидим его текущую версию (например, v18.17.1).
Если Node.js не установлен:
Переходим на официальный сайт Node.js(https://nodejs.org/).
Скачайте и установите:
LTS: Стабильная версия, по этому рекомендую её.
После установки после проверки опять же проверяем командой node -v.
2 >>> Создание проекта Next.js
Теперь создадим интерфейс для администратора, который будет взаимодействовать со смарт-контрактом.
Выполняем команду для создания нового проекта (При установке выбираем то что по дефолту советует NextJS):
Устанавливаем библиотеку ethers для работы с блокчейном:
2 >>> Интерфейс приложения
Стираем весь код в src/app/page.ts и пишем наш.
Не забываем указать наш адрес контракта в этой строке:
const contractAddress = "0xYourContractAddress"; // Заменяем на наш адрес контракта
на это:
const contractAddress = "0xdCe675B975673A569a51d8aDF585c947063aE544"; // Наш созданый адрес который мы должны были запомнить до этого
Так же есть строка с RPC url, я оставлю к Polygon так как пример основан на нем, но так же вы можете поменять на свой (на самом деле эта переменная нигде не юзается я уже запуталься просто)
(Тут у меня VS Code сломался по этому код в блокноте =) )
Добавьте базовые стили в src/app/globals.css:
Разбор кода:
"use client": Указывает, что компонент работает на стороне клиента в Next.js.
useState и useEffect: Хуки React для управления состоянием и выполнения побочных эффектов.
ethers: Библиотека для взаимодействия с блокчейном.
contractAddress: Адрес развернутого смарт-контракта.
contractABI: ABI (Application Binary Interface) описывает функции и методы контракта.
rpcUrl: URL RPC-сервера для подключения к сети.
currentDomain: Хранит текущий домен, полученный из контракта.
newDomain: Хранит новый домен, который администратор хочет установить.
isAdmin: Указывает, является ли пользователь администратором.
currentAccount: Текущий подключенный адрес Ethereum.
Запускает функцию fetchDomain один раз при загрузке компонента.
fetchDomain: Получает текущий домен из смарт-контракта.
Создает провайдер через JsonRpcProvider для подключения к сети.
Вызывает метод getDomain контракта для получения текущего домена.
Обновляет состояние currentDomain.
Проверяет наличие MetaMask.
Подключается к кошельку через eth_requestAccounts.
Сохраняет текущий аккаунт в состоянии currentAccount.
Проверяет, является ли пользователь администратором, вызывая checkAdmin.
Проверяет, совпадает ли текущий адрес с адресом администратора контракта.
Использует метод admin контракта.
Проверяет права администратора.
Создает провайдер через MetaMask (BrowserProvider).
Подписывает и отправляет транзакцию для обновления домена.
Обновляет состояние после успешной транзакции.
3 >>> Запуск приложения
Запускаем сервер в DEV режиме, открываем консоль в проекте и пишем:
Открываем http://localhost:3000 в браузере.
Подключаем MetaMask и проверяем фукнционал:
Отображение текущего домена.
Обновление домена, если вы администратор.
Теперь у нас есть работающий интерфейс для управления доменом через блокчейн!
Попробуем поменять домен на https://xss.as
Как видим мы ввели домен, и нажали кнопку и нам осталось только подтвердить транзакцию
После подтверждение мы видим как домен поменялся.
>>> Создание простенького скрипта для клиента чтоб получать всегда актуальный линк.
Открываем консоль или терминал, cоздаем папку для проекта и переходим в неё:
Инициализируем проект:
Устанавливаем ethers
Создаем файл index.js и пишем туда код.
Как видим прописав node index.js наш клиент получает актуальный домен.
Второй пример
Так... ладно.. домены это все понятно, но я лично предпочитаю использовать блокчейн для получения C2 сервера, и сейчас покажу вам пример на С++ без лишних библиотек, только WinAPI который позволяет получать строку (Домен в нашем случаее) из блокчейна.
Приступим сначала я создам NodeJs скрипт для получения hex`a функций.
Так же создаем папку к примеру blockchain, переходим в нее и инициализируем проект командой npm init -y и после уже устанавливаем библиотеку ethers командой npm i ethers
Записываем этот код в index.js но и еще если нужно меняем адрес контракта на свой, но я же буду свой использовать который создал для примера.
Тем самым мы получили данные от RPC и домен, а еще hex функций который нужен будет для кода на C++
Вот код на C++ в нем мы меняем адрес контракта на наш и hex функций контракта.
Компилируем этот код и запускаем и видим что мы так же можем без всяких NodeJS и стороних библиотек обращаться к блокчейну через RPC.
И как видим мы получили так же нашу строку из блокчейна
На самом деле это можно много где использовать в ботнетах, стиллерах, лоадерах, хранения просто каких то данных которые должны получаться всегда, хранения параметров. Я досих пор не понимаю почему это даже на рынке не используется. Ведь столько блокчейнов, столько нод, и столько сетей. Вы можете получить огромный список прямиком отсюда https://chainlist.org использовать их. Ведь блокчейны и rpc куда сложней заблокировать.
Статья и идей являются авторскими.
Ну и соответственно даже кто-то написал статью о моих бредовых идеях https://socket.dev/blog/exploiting-npm-to-build-a-blockchain-powered-botnet я не знаю можно ли использовать это как реальный пример. Но тут описывается тоже мое творчество, где я использую точно такие же технологий в своем ботнете. https://xss.is/threads/123396
Блокчейн — это технология, где данные хранятся в распределенной сети. Все участники имеют одинаковую копию данных, а изменения проверяются сетью. Это делает блокчейн прозрачным, надежным и защищенным.
EVM (Ethereum Virtual Machine) — это среда для выполнения смарт-контрактов. EVM-сети, такие как Ethereum, Binance Smart Chain и Polygon, позволяют разработчикам создавать приложения на основе блокчейна с использованием готовых инструментов.
Почему это удобно?
Децентрализация: Заблокировать систему практически невозможно, так как отсутствует единая точка контроля.
Прозрачность и неизменность: После развертывания смарт-контракта его код становится доступен всем и сохраняется навсегда в блокчейне. Изменить контракт нельзя, если только в нем изначально не предусмотрена возможность для этого.
Я Покажу вам пару примеров где это можно использовать.
Первый пример использования:
Представим, у нас есть онлайн-сервис, который по каким-то причинам часто блокируется и теряет часть своих пользователей (условно блокировка домена/хоста/контактов/т.д). Чтобы не терять своих пользователей и клиентов, мы можем использовать блокчейн для координации и информирования их о текущем рабочем адресе/контакте/линке и т.д.
Достаточно, чтобы у наших пользователей было наше приложение, которое общается со смарт-контрактом в блокчейне. В смарт-контракте администратор(мы) может обновлять информацию, например, указывать новый адрес/контакт/линк и т.д. Пользователи, запуская приложение, всегда получают актуальные данные из блокчейна, минуя центральные сервера, которые могут быть заблокированы или недоступны.
Таким образом:
Пользователи всегда остаются на связи: Блокчейн децентрализован, его нельзя заблокировать или "отключить".
Удобство: Достаточно обновить данные в смарт-контракте, и они тут же станут доступны всем пользователям.
Прозрачность: Любой пользователь может проверить, кто обновил данные и когда это было сделано, исключая манипуляции.
Это пример того, как децентрализация и блокчейн могут быть использованы для решения реальных проблем.
Переходим к практике: Установка MetaMask и Развертывание Первого Смарт-Контракта в Сети Ethereum
> 1: Написание смарт-контракта
Используем простой контракт для хранения и обновления домена.
Перед тем как развернуть наш первый смарт-контракт, важно установить и настроить MetaMask — кошелек, который позволит взаимодействовать с блокчейном. Далее мы разберем весь процесс от начала до конца.
1 >>> Установка и настройка MetaMask
Скачиваем MetaMask:
Переходим на официальный сайт MetaMask (https://metamask.io/).
Устанавливаем расширение для браузера (Chrome, Firefox, Edge, Brave).
Создаем кошелек:
Открываем MetaMask и выбираем "Create a Wallet".
Задаем надежный пароль (xD).
Сохраняем секретную фразу из 12 слов. Это важно для восстановления доступа к кошельку, но в примере не буду показывать как, думаю сами резберетесь.
Далее просто тыкаем done, next, next...
Добавим новую сеть к примеру Polygon (если хотите использовать эфириум можете остаться на нем, тогда просто пропуститие добавление).
Сделаем добавление максимально по простому, перейдем на https://polygonscan.com/ и внизу сайта в подвале есть кнопка "Add Polygon Network", нажимем ее, у вас откроется metamask соглашаемся и добавляем, если же не получается попробуйте в самом метамаске добавить нажав слева сверху на сети и там выбрать polygon.
Пополните баланс сети (в нашем случае polygon):
Сделать вы это можете купить крипту или обменять их в обменнике или в ином месте.
2 >>> Написание смарт-контракта
Теперь мы создадим контракт, который позволит хранить и обновлять домен.
Перейдите на Remix IDE (https://remix.ethereum.org/).
Создайте файл DomainManager.sol и вставьте код (сохраняем ctrl + s)
Code:
pragma solidity ^0.8.0;
contract DomainManager {
address public admin; // Адрес администратора
string public currentDomain; // Текущий домен
// Событие для логирования изменений
event DomainUpdated(string oldDomain, string newDomain);
// Конструктор: устанавливаем администратора и начальный домен
constructor(string memory initialDomain) {
admin = msg.sender; // Устанавливаем администратора
currentDomain = initialDomain; // Устанавливаем домен
}
// Модификатор: проверка, что вызов делает администратор
modifier onlyAdmin() {
require(msg.sender == admin, "You are not the admin");
_;
}
// Обновление домена
function updateDomain(string memory newDomain) public onlyAdmin {
string memory oldDomain = currentDomain;
currentDomain = newDomain;
emit DomainUpdated(oldDomain, newDomain);
}
// Получение текущего домена
function getDomain() public view returns (string memory) {
return currentDomain;
}
}
Объяснение кода:
Code:
pragma solidity ^0.8.0;
pragma solidity ^0.8.0;: Указывает, что код совместим с версиями компилятора Solidity 0.8.0 и выше.
Code:
contract DomainManager {
address public admin; // Адрес администратора
string public currentDomain; // Текущий домен
contract DomainManager: Определяет новый контракт с именем DomainManager.
address public admin: Переменная для хранения Ethereum-адреса администратора.
string public currentDomain: Переменная для хранения текущего домена. Домен — это строка (например, "https://xss.is"), которую могут видеть пользователи.
Code:
event DomainUpdated(string oldDomain, string newDomain);
event DomainUpdated: Событие для записи в лог изменений домена.
oldDomain: Старый домен.
newDomain: Новый домен.
События позволяют отслеживать изменения в блокчейне. Это полезно для приложений, которые слушают блокчейн и реагируют на изменения.
Code:
constructor(string memory initialDomain) {
admin = msg.sender; // Устанавливаем администратора
currentDomain = initialDomain; // Устанавливаем домен
}
constructor: Функция, которая вызывается один раз при развертывании контракта.
string memory initialDomain: Аргумент конструктора для указания начального домена.
admin = msg.sender: Устанавливает администратора. Администратором становится адрес, который развернул контракт.
currentDomain = initialDomain: Устанавливает начальный домен.
Code:
modifier onlyAdmin() {
require(msg.sender == admin, "You are not the admin");
_;
}
modifier onlyAdmin: Проверяет, что функцию вызывает только администратор.
msg.sender: Адрес, который вызвал функцию.
require(msg.sender == admin, "You are not the admin");: Если адрес вызывающего не совпадает с admin, выполнение функции прерывается, и ошибка возвращается с текстом "You are not the admin".
_: Указывает, где будет выполняться код основной функции, к которой применяется модификатор.
Code:
function updateDomain(string memory newDomain) public onlyAdmin {
string memory oldDomain = currentDomain;
currentDomain = newDomain;
emit DomainUpdated(oldDomain, newDomain);
}
updateDomain: Функция для обновления домена.
string memory newDomain: Новый домен, который администратор хочет установить.
public: Функцию можно вызывать извне.
onlyAdmin: Проверяет, что вызов сделан администратором.
Логика функции:
Сохраняет текущий домен в переменную oldDomain.
Обновляет currentDomain на новый.
Вызывает событие DomainUpdated, логируя старый и новый домен.
Code:
function getDomain() public view returns (string memory) {
return currentDomain;
}
getDomain: Функция для получения текущего домена.
public: Доступна для вызова извне.
view: Указывает, что функция только читает данные и не изменяет состояние блокчейна.
returns (string memory): Возвращает строку с текущим доменом.
Как работает контракт.
Развертывание:
При развертывании конструктора задается начальный домен, и развертывающий адрес становится администратором.
Обновление домена:
Администратор вызывает updateDomain, передавая новый домен. Новый домен записывается, а старый фиксируется в логах через событие.
Получение домена:
Любой пользователь может вызвать getDomain, чтобы получить текущий домен.
3 >>> Компиляция контракта
В Remix открываем вкладку "Solidity Compiler".
Убедитесь, что версия компилятора совпадает с pragma solidity ^0.8.0.
Нажмите "Compile DomainManager.sol".
4 >>> Развертывание контракта
Открываем вкладку "Deploy & Run Transactions".
В поле Environment выберите "WalletConnet", и потом жмем Connect Wallet и подключаем наш MetaMask.
Убедимся, что мы подключены к сети (например, Polygon).
В поле "string initialDomain" указываем начальный домен, например: "https://xss.is".
Нажимаем "Deploy" и подтверждаем транзакцию в MetaMask.
После подтверждения контракт будет развернут, а его адрес отобразится в Remix.
Далее копируем наш адрес контракта и запоминаем, он нам нужен будет в дальнейшем (к примеру наш адрес 0xdCe675B975673A569a51d8aDF585c947063aE544)
5 >>> Работа с контрактом
В разделе Deployed Contracts найдите ваш контракт.
Нажмите на функцию getDomain, чтобы получить текущий домен.
Обновите домен с помощью функции updateDomain, указав новый адрес, например: "https://xss.as".
Проверьте, что домен изменился, снова вызвав функцию getDomain.
Теперь у нас есть работающий смарт-контракт для хранения и обновления домена (На самом деле в нем не только можно хранить домен но и вообще любую строку)
Приступим к написанию приложения для администратора на Next.js
Мы создадим простое приложение, которое позволит администратору:
Подключаться к своему кошельку через MetaMask.
Проверять текущий домен из смарт-контракта.
Обновлять домен, если пользователь является администратором.
2 > Установка Node.js и создание приложения администратора на Next.js
Для разработки приложения администратора с использованием Next.js нам нужно сначала установить Node.js, настроить окружение и затем приступить к созданию интерфейса для управления доменом через блокчейн.
1 >>> Установка Node.js
Проверка Node.js на нашем компьютере:
Открываем терминал или командную строку.
Вводим команду:
Code:
node -v
Если Node.js установлен, мы увидим его текущую версию (например, v18.17.1).
Если Node.js не установлен:
Переходим на официальный сайт Node.js(https://nodejs.org/).
Скачайте и установите:
LTS: Стабильная версия, по этому рекомендую её.
После установки после проверки опять же проверяем командой node -v.
2 >>> Создание проекта Next.js
Теперь создадим интерфейс для администратора, который будет взаимодействовать со смарт-контрактом.
Выполняем команду для создания нового проекта (При установке выбираем то что по дефолту советует NextJS):
Code:
npx create-next-app@latest admin-panel
cd admin-panel
Устанавливаем библиотеку ethers для работы с блокчейном:
Code:
npm install ethers
2 >>> Интерфейс приложения
Стираем весь код в src/app/page.ts и пишем наш.
Code:
"use client";
import { useState, useEffect } from "react";
import { ethers } from "ethers";
// Адрес и ABI смарт-контракта
const contractAddress = "0xYourContractAddress"; // Замените на наш адрес контракта
const contractABI = [
{
inputs: [],
name: "getDomain",
outputs: [{ internalType: "string", name: "", type: "string" }],
stateMutability: "view",
type: "function",
},
{
inputs: [{ internalType: "string", name: "newDomain", type: "string" }],
name: "updateDomain",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [],
name: "admin",
outputs: [{ internalType: "address", name: "", type: "address" }],
stateMutability: "view",
type: "function",
},
];
export default function AdminPanel() {
const [currentDomain, setCurrentDomain] = useState("Loading...");
const [newDomain, setNewDomain] = useState("");
const [isAdmin, setIsAdmin] = useState(false);
const [currentAccount, setCurrentAccount] = useState(null);
useEffect(() => {
fetchDomain();
}, []);
async function fetchDomain() {
try {
const provider = new ethers.JsonRpcProvider("https://polygon-rpc.com");
const contract = new ethers.Contract(contractAddress, contractABI, provider);
const domain = await contract.getDomain();
setCurrentDomain(domain);
} catch (error) {
console.error("Error fetching domain:", error.message);
}
}
async function checkWalletConnection() {
try {
if (!window.ethereum) throw new Error("MetaMask is not installed");
const accounts = await window.ethereum.request({ method: "eth_requestAccounts" });
setCurrentAccount(accounts[0]);
checkAdmin(accounts[0]);
} catch (error) {
console.error("Error connecting to MetaMask:", error.message);
}
}
async function checkAdmin(account) {
try {
const provider = new ethers.JsonRpcProvider("https://polygon-rpc.com");
const contract = new ethers.Contract(contractAddress, contractABI, provider);
const adminAddress = await contract.admin();
setIsAdmin(account.toLowerCase() === adminAddress.toLowerCase());
} catch (error) {
console.error("Error checking admin status:", error.message);
}
}
async function updateDomain() {
try {
if (!isAdmin) throw new Error("Only admin can update the domain");
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const contract = new ethers.Contract(contractAddress, contractABI, signer);
const tx = await contract.updateDomain(newDomain);
console.log("Transaction sent:", tx.hash);
await tx.wait();
console.log("Domain updated!");
fetchDomain();
} catch (error) {
console.error("Error updating domain:", error.message);
}
}
return (
<div style={{ padding: "20px", fontFamily: "Arial, sans-serif" }}>
<h1>Admin Panel</h1>
<div style={{ marginBottom: "20px" }}>
{currentAccount ? (
<p>Connected as: {currentAccount}</p>
) : (
<button onClick={checkWalletConnection}>Connect Wallet</button>
)}
</div>
<h2>Current Domain</h2>
<p>{currentDomain}</p>
{isAdmin ? (
<div style={{ marginTop: "20px" }}>
<h3>Update Domain</h3>
<input
type="text"
value={newDomain}
onChange={(e) => setNewDomain(e.target.value)}
placeholder="Enter new domain"
style={{ padding: "8px", width: "300px" }}
/>
<button
onClick={updateDomain}
style={{
padding: "8px 16px",
marginLeft: "10px",
cursor: "pointer",
backgroundColor: "#0070f3",
color: "#fff",
border: "none",
borderRadius: "4px",
}}
>
Update
</button>
</div>
) : (
<p style={{ color: "red" }}>You are not the admin</p>
)}
</div>
);
}
Не забываем указать наш адрес контракта в этой строке:
const contractAddress = "0xYourContractAddress"; // Заменяем на наш адрес контракта
на это:
const contractAddress = "0xdCe675B975673A569a51d8aDF585c947063aE544"; // Наш созданый адрес который мы должны были запомнить до этого
Так же есть строка с RPC url, я оставлю к Polygon так как пример основан на нем, но так же вы можете поменять на свой (на самом деле эта переменная нигде не юзается я уже запуталься просто)
Code:
//RPC URL
const rpcUrl = "https://polygon-rpc.com";
(Тут у меня VS Code сломался по этому код в блокноте =) )
Добавьте базовые стили в src/app/globals.css:
Code:
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background-color: #f5f5f5;
color: #333;
}
button {
cursor: pointer;
padding: 8px 16px;
border: none;
border-radius: 4px;
background-color: #0070f3;
color: #fff;
}
input {
border: 1px solid #ccc;
border-radius: 4px;
padding: 8px;
}
Разбор кода:
Code:
"use client";
import { useState, useEffect } from "react";
import { ethers } from "ethers";
"use client": Указывает, что компонент работает на стороне клиента в Next.js.
useState и useEffect: Хуки React для управления состоянием и выполнения побочных эффектов.
ethers: Библиотека для взаимодействия с блокчейном.
Code:
const contractAddress = "0xdCe675B975673A569a51d8aDF585c947063aE544"; // Адрес контракта
const contractABI = [
// Описание методов и функций контракта
];
const rpcUrl = "https://polygon-rpc.com"; // RPC для подключения к сети. (не юзается забыл де)
contractAddress: Адрес развернутого смарт-контракта.
contractABI: ABI (Application Binary Interface) описывает функции и методы контракта.
rpcUrl: URL RPC-сервера для подключения к сети.
Code:
const [currentDomain, setCurrentDomain] = useState("Loading...");
const [newDomain, setNewDomain] = useState("");
const [isAdmin, setIsAdmin] = useState(false);
const [currentAccount, setCurrentAccount] = useState(null);
currentDomain: Хранит текущий домен, полученный из контракта.
newDomain: Хранит новый домен, который администратор хочет установить.
isAdmin: Указывает, является ли пользователь администратором.
currentAccount: Текущий подключенный адрес Ethereum.
Code:
useEffect(() => {
fetchDomain();
}, []);
Запускает функцию fetchDomain один раз при загрузке компонента.
fetchDomain: Получает текущий домен из смарт-контракта.
Code:
async function fetchDomain() {
try {
const provider = new ethers.JsonRpcProvider("https://polygon-rpc.com");
const contract = new ethers.Contract(contractAddress, contractABI, provider);
const domain = await contract.getDomain();
setCurrentDomain(domain);
} catch (error) {
console.error("Error fetching domain:", error.message);
}
}
Создает провайдер через JsonRpcProvider для подключения к сети.
Вызывает метод getDomain контракта для получения текущего домена.
Обновляет состояние currentDomain.
Code:
async function checkWalletConnection() {
try {
if (!window.ethereum) throw new Error("MetaMask is not installed");
const accounts = await window.ethereum.request({ method: "eth_requestAccounts" });
setCurrentAccount(accounts[0]);
checkAdmin(accounts[0]);
} catch (error) {
console.error("Error connecting to MetaMask:", error.message);
}
}
Проверяет наличие MetaMask.
Подключается к кошельку через eth_requestAccounts.
Сохраняет текущий аккаунт в состоянии currentAccount.
Проверяет, является ли пользователь администратором, вызывая checkAdmin.
Code:
async function checkAdmin(account) {
try {
const provider = new ethers.JsonRpcProvider("https://polygon-rpc.com");
const contract = new ethers.Contract(contractAddress, contractABI, provider);
const adminAddress = await contract.admin();
setIsAdmin(account.toLowerCase() === adminAddress.toLowerCase());
} catch (error) {
console.error("Error checking admin status:", error.message);
}
}
Проверяет, совпадает ли текущий адрес с адресом администратора контракта.
Использует метод admin контракта.
Code:
async function updateDomain() {
try {
if (!isAdmin) throw new Error("Only admin can update the domain");
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const contract = new ethers.Contract(contractAddress, contractABI, signer);
const tx = await contract.updateDomain(newDomain);
console.log("Transaction sent:", tx.hash);
await tx.wait();
console.log("Domain updated!");
fetchDomain();
} catch (error) {
console.error("Error updating domain:", error.message);
}
}
Проверяет права администратора.
Создает провайдер через MetaMask (BrowserProvider).
Подписывает и отправляет транзакцию для обновления домена.
Обновляет состояние после успешной транзакции.
3 >>> Запуск приложения
Запускаем сервер в DEV режиме, открываем консоль в проекте и пишем:
Code:
npm run dev
Открываем http://localhost:3000 в браузере.
Подключаем MetaMask и проверяем фукнционал:
Отображение текущего домена.
Обновление домена, если вы администратор.
Теперь у нас есть работающий интерфейс для управления доменом через блокчейн!
Попробуем поменять домен на https://xss.as
Как видим мы ввели домен, и нажали кнопку и нам осталось только подтвердить транзакцию
После подтверждение мы видим как домен поменялся.
>>> Создание простенького скрипта для клиента чтоб получать всегда актуальный линк.
Открываем консоль или терминал, cоздаем папку для проекта и переходим в неё:
Code:
mkdir client-app
cd client-app
Инициализируем проект:
Code:
npm init -y
Устанавливаем ethers
Code:
npm install ethers
Создаем файл index.js и пишем туда код.
Code:
const { ethers } = require("ethers");
// Адрес контракта и его ABI
const contractAddress = "0xdCe675B975673A569a51d8aDF585c947063aE544";
const contractABI = [
{
inputs: [],
name: "getDomain",
outputs: [{ internalType: "string", name: "", type: "string" }],
stateMutability: "view",
type: "function",
},
];
// URL RPC-сервера
const rpcUrl = "https://polygon-rpc.com";
async function fetchDomain() {
try {
// Создаем провайдер для подключения к сети Polygon
const provider = new ethers.JsonRpcProvider(rpcUrl);
// Подключаем контракт
const contract = new ethers.Contract(contractAddress, contractABI, provider);
// Вызываем метод getDomain
const domain = await contract.getDomain();
// Выводим домен в консоль
console.log("Current Domain:", domain);
} catch (error) {
console.error("Error fetching domain:", error.message);
}
}
// Запускаем функцию
fetchDomain();
Как видим прописав node index.js наш клиент получает актуальный домен.
Второй пример
Так... ладно.. домены это все понятно, но я лично предпочитаю использовать блокчейн для получения C2 сервера, и сейчас покажу вам пример на С++ без лишних библиотек, только WinAPI который позволяет получать строку (Домен в нашем случаее) из блокчейна.
Приступим сначала я создам NodeJs скрипт для получения hex`a функций.
Так же создаем папку к примеру blockchain, переходим в нее и инициализируем проект командой npm init -y и после уже устанавливаем библиотеку ethers командой npm i ethers
Записываем этот код в index.js но и еще если нужно меняем адрес контракта на свой, но я же буду свой использовать который создал для примера.
Code:
const { ethers } = require("ethers");
// RPC URL
const rpcUrl = "https://polygon-rpc.com";
// Адрес контракта и ABI
const contractAddress = "0xdCe675B975673A569a51d8aDF585c947063aE544"; //Наш адрес контракта
const abi = [
"function getDomain() public view returns (string)"
];
// Создаем провайдер для подключения к Polygon
const provider = new ethers.JsonRpcProvider(rpcUrl);
// Кодируем данные для вызова функции
function encodeFunctionData(functionName, abi) {
const iface = new ethers.Interface(abi);
return iface.encodeFunctionData(functionName, []);
}
// Декодируем результат вызова функции
function decodeFunctionResult(functionName, data, abi) {
const iface = new ethers.Interface(abi);
return iface.decodeFunctionResult(functionName, data);
}
// Основная функция
async function main() {
try {
// Подключаем контракт
const contract = new ethers.Contract(contractAddress, abi, provider);
// Вызов функции `getDomain` через ethers.js
console.log("Запрос к функции getDomain...");
const result = await contract.getDomain();
console.log("Результат вызова функции getDomain через ethers.js:", result);
// Кодирование данных для JSON-RPC запроса
const encodedData = encodeFunctionData("getDomain", abi);
console.log("Закодированные данные для функции getDomain:", encodedData);
// Формирование JSON-RPC запроса
const rpcRequest = {
jsonrpc: "2.0",
method: "eth_call",
params: [
{
to: contractAddress,
data: encodedData
},
"latest"
],
id: 1
};
console.log("JSON-RPC запрос (Node.js):");
console.log(JSON.stringify(rpcRequest, null, 2));
// Отправка JSON-RPC запроса напрямую
const response = await provider.send("eth_call", rpcRequest.params);
console.log("Ответ от Ethereum RPC:", response);
// Декодируем результат вызова функции
const decodedResult = decodeFunctionResult("getDomain", response, abi);
console.log("Декодированный результат (Node.js):", decodedResult[0]);
} catch (error) {
console.error("Ошибка:", error.message);
}
}
// Запуск
main();
Тем самым мы получили данные от RPC и домен, а еще hex функций который нужен будет для кода на C++
Вот код на C++ в нем мы меняем адрес контракта на наш и hex функций контракта.
Code:
#include <windows.h>
#include <winhttp.h>
#include <iostream>
#include <sstream>
#include <string>
#pragma comment(lib, "winhttp.lib")
const std::wstring RPC_HOST = L"polygon-rpc.com";
const std::wstring RPC_PATH = L"/";
const INTERNET_PORT RPC_PORT = INTERNET_DEFAULT_HTTPS_PORT;
const std::string CONTRACT_ADDRESS = "0xdCe675B975673A569a51d8aDF585c947063aE544";
const std::string FUNCTION_SELECTOR = "b68d1809"; // Selector для getDomain() без 0x
// Формирование JSON-RPC запроса
std::string createJsonRpcRequest(const std::string& method, const std::string& params) {
std::ostringstream ss;
ss << R"({"jsonrpc":"2.0","method":")" << method
<< R"(","params":)" << params
<< R"(,"id":1})";
return ss.str();
}
// Отправка запроса через WinHTTP
std::string sendRequest(const std::wstring& host, const std::wstring& path, const std::string& requestBody) {
HINTERNET hSession = WinHttpOpen(L"WinHTTP Example/1.0", WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession) return "";
HINTERNET hConnect = WinHttpConnect(hSession, host.c_str(), RPC_PORT, 0);
if (!hConnect) {
WinHttpCloseHandle(hSession);
return "";
}
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST", path.c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (!hRequest) {
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return "";
}
const wchar_t* headers = L"Content-Type: application/json\r\n";
WinHttpAddRequestHeaders(hRequest, headers, -1L, WINHTTP_ADDREQ_FLAG_ADD);
if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, (LPVOID)requestBody.c_str(), requestBody.size(), requestBody.size(), 0)) {
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return "";
}
if (!WinHttpReceiveResponse(hRequest, NULL)) {
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return "";
}
std::string response;
DWORD bytesRead = 0, sizeAvailable = 0;
char buffer[4096];
do {
if (!WinHttpQueryDataAvailable(hRequest, &sizeAvailable)) break;
if (!WinHttpReadData(hRequest, buffer, sizeAvailable, &bytesRead)) break;
buffer[bytesRead] = '\0';
response += buffer;
} while (sizeAvailable > 0);
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return response;
}
// Декодирование строки из Hex
std::string decodeHexString(const std::string& hex) {
std::string result;
for (size_t i = 0; i < hex.length(); i += 2) {
std::string byteString = hex.substr(i, 2);
char byte = static_cast<char>(std::stoi(byteString, nullptr, 16));
result += byte;
}
return result;
}
// Декодирование результата eth_call
std::string decodeResult(const std::string& result) {
std::string hexData = result.substr(2); // Убираем "0x"
std::string lengthHex = hexData.substr(64, 64); // Длина строки
int length = std::stoi(lengthHex, nullptr, 16);
std::string stringHex = hexData.substr(128, length * 2); // Сама строка
return decodeHexString(stringHex);
}
int main() {
// Формируем данные вызова
std::string dataField = "0x" + FUNCTION_SELECTOR;
// Формируем JSON-RPC запрос
std::ostringstream params;
params << R"([{"to":")" << CONTRACT_ADDRESS << R"(","data":")" << dataField << R"("},"latest"])";
std::string requestBody = createJsonRpcRequest("eth_call", params.str());
// Отправляем запрос
std::string response = sendRequest(RPC_HOST, RPC_PATH, requestBody);
if (!response.empty()) {
size_t resultPos = response.find("\"result\":\"");
if (resultPos != std::string::npos) {
size_t start = resultPos + 10;
size_t end = response.find("\"", start);
std::string result = response.substr(start, end - start);
std::string decodedString = decodeResult(result);
std::cout << "Decoded domain: " << decodedString << std::endl;
} else {
std::cerr << "Error: result not found" << std::endl;
}
} else {
std::cerr << "Error: not response" << std::endl;
}
return 0;
}
Компилируем этот код и запускаем и видим что мы так же можем без всяких NodeJS и стороних библиотек обращаться к блокчейну через RPC.
И как видим мы получили так же нашу строку из блокчейна
На самом деле это можно много где использовать в ботнетах, стиллерах, лоадерах, хранения просто каких то данных которые должны получаться всегда, хранения параметров. Я досих пор не понимаю почему это даже на рынке не используется. Ведь столько блокчейнов, столько нод, и столько сетей. Вы можете получить огромный список прямиком отсюда https://chainlist.org использовать их. Ведь блокчейны и rpc куда сложней заблокировать.
Статья и идей являются авторскими.
Ну и соответственно даже кто-то написал статью о моих бредовых идеях https://socket.dev/blog/exploiting-npm-to-build-a-blockchain-powered-botnet я не знаю можно ли использовать это как реальный пример. Но тут описывается тоже мое творчество, где я использую точно такие же технологий в своем ботнете. https://xss.is/threads/123396