• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Используем смарт-контракты и блокчейны EVM-сетей в своих корыстных целях

XSSBot

Форумный бот
Пользователь
Регистрация
31.12.2005
Сообщения
1 473
Реакции
898
Автор celty
Статья написана для
Конкурса статей #10


Что такое блокчейн и 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).
1733107565149.png

1733107596896.png

1733107622175.png




Создаем кошелек:

Открываем MetaMask и выбираем "Create a Wallet".
1733107643951.png

1733107665318.png

Задаем надежный пароль (xD).
1733107693443.png

Сохраняем секретную фразу из 12 слов. Это важно для восстановления доступа к кошельку, но в примере не буду показывать как, думаю сами резберетесь.
1733107718894.png

Далее просто тыкаем done, next, next...

Добавим новую сеть к примеру Polygon (если хотите использовать эфириум можете остаться на нем, тогда просто пропуститие добавление).
Сделаем добавление максимально по простому, перейдем на https://polygonscan.com/ и внизу сайта в подвале есть кнопка "Add Polygon Network", нажимем ее, у вас откроется metamask соглашаемся и добавляем, если же не получается попробуйте в самом метамаске добавить нажав слева сверху на сети и там выбрать polygon.
1733107757195.png

1733107787152.png



Пополните баланс сети (в нашем случаее polygon):
Сделать вы это можете купить крипту или обменять их в обменике или в ином месте.
1733107808947.png




2 >>> Написание смарт-контракта

Теперь мы создадим контракт, который позволит хранить и обновлять домен.

Перейдите на Remix IDE(https://remix.ethereum.org/).
Создайте файл DomainManager.sol и вставьте код (сохраняем ctrl + s)

1733107838546.png

1733107903177.png



Код:
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;
    }
}

Обьяснение кода:

Код:
pragma solidity ^0.8.0;
pragma solidity ^0.8.0;: Указывает, что код совместим с версиями компилятора Solidity 0.8.0 и выше.

Код:
contract DomainManager {
    address public admin; // Адрес администратора
    string public currentDomain; // Текущий домен

contract DomainManager: Определяет новый контракт с именем DomainManager.
address public admin: Переменная для хранения Ethereum-адреса администратора.
string public currentDomain: Переменная для хранения текущего домена. Домен — это строка (например, "https://xss.pro"), которую могут видеть пользователи.

Код:
event DomainUpdated(string oldDomain, string newDomain);

event DomainUpdated: Событие для записи в лог изменений домена.
oldDomain: Старый домен.
newDomain: Новый домен.
События позволяют отслеживать изменения в блокчейне. Это полезно для приложений, которые слушают блокчейн и реагируют на изменения.

Код:
constructor(string memory initialDomain) {
    admin = msg.sender; // Устанавливаем администратора
    currentDomain = initialDomain; // Устанавливаем домен
}

constructor: Функция, которая вызывается один раз при развертывании контракта.
string memory initialDomain: Аргумент конструктора для указания начального домена.
admin = msg.sender: Устанавливает администратора. Администратором становится адрес, который развернул контракт.
currentDomain = initialDomain: Устанавливает начальный домен.

Код:
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".
_: Указывает, где будет выполняться код основной функции, к которой применяется модификатор.

Код:
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, логируя старый и новый домен.

Код:
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".

1733107940245.png



4 >>> Развертывание контракта

Открываем вкладку "Deploy & Run Transactions".
В поле Environment выберите "WalletConnet", и потом жмем Connect Wallet и подключаем наш MetaMask.
1733107990948.png

Убедимся, что мы подключены к сети (например, Polygon).
1733108083300.png

В поле "string initialDomain" указываем начальный домен, например: "https://xss.pro".
Нажимаем "Deploy" и подтверждаем транзакцию в MetaMask.
1733108100895.png

1733108123835.png

После подтверждения контракт будет развернут, а его адрес отобразится в Remix.
1733108154621.png

Далее копируем наш адрес контракта и запоминаем, он нам нужен будет в дальнейшем (к примеру наш адрес 0xdCe675B975673A569a51d8aDF585c947063aE544)
1733108182081.png



5 >>> Работа с контрактом

В разделе Deployed Contracts найдите ваш контракт.
Нажмите на функцию getDomain, чтобы получить текущий домен.
Обновите домен с помощью функции updateDomain, указав новый адрес, например: "https://xss.pro".
Проверьте, что домен изменился, снова вызвав функцию getDomain.

Теперь у нас есть работающий смарт-контракт для хранения и обновления домена (На самом деле в нем не только можно хранить домен но и вообще любую строку)

Приступим к написанию приложения для администратора на Next.js

Мы создадим простое приложение, которое позволит администратору:

Подключаться к своему кошельку через MetaMask.
Проверять текущий домен из смарт-контракта.
Обновлять домен, если пользователь является администратором.

2 > Установка Node.js и создание приложения администратора на Next.js

Для разработки приложения администратора с использованием Next.js нам нужно сначала установить Node.js, настроить окружение и затем приступить к созданию интерфейса для управления доменом через блокчейн.

1 >>> Установка Node.js
Проверка Node.js на нашем компьютере:

Открываем терминал или командную строку.
Вводим команду:
Код:
node -v
Если Node.js установлен, мы увидим его текущую версию (например, v18.17.1).
1733108220402.png


Если Node.js не установлен:

Переходим на официальный сайт Node.js(https://nodejs.org/).
Скачайте и установите:
LTS: Стабильная версия, по этому рекомендую её.
После установки после проверки опять же проверяем командой node -v.
1733108239813.png


2 >>> Создание проекта Next.js

Теперь создадим интерфейс для администратора, который будет взаимодействовать со смарт-контрактом.

Выполняем команду для создания нового проекта (При установке выбираем то что по дефолту советует NextJS):
Код:
npx create-next-app@latest admin-panel
cd admin-panel
1733108270400.png


Устанавливаем библиотеку ethers для работы с блокчейном:
Код:
npm install ethers
1733108295726.png


2 >>> Интерфейс приложения

Стираем весь код в src/app/page.ts и пишем наш.

Код:
"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 так как пример основан на нем, но так же вы можете поменять на свой (на самом деле эта переменная нигде не юзается я уже запуталься просто)
Код:
//RPC URL
const rpcUrl = "https://polygon-rpc.com";

(Тут у меня VS Code сломалься по этому код в блокноте =) )
1733108333313.png


Добавьте базовые стили в src/app/globals.css:
Код:
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;
}

1733108371459.png



Разбор кода:
Код:
"use client";

import { useState, useEffect } from "react";
import { ethers } from "ethers";

"use client": Указывает, что компонент работает на стороне клиента в Next.js.
useState и useEffect: Хуки React для управления состоянием и выполнения побочных эффектов.
ethers: Библиотека для взаимодействия с блокчейном.

Код:
const contractAddress = "0xdCe675B975673A569a51d8aDF585c947063aE544"; // Адрес контракта
const contractABI = [
  // Описание методов и функций контракта
];
const rpcUrl = "https://polygon-rpc.com"; // RPC для подключения к сети. (не юзается забыл де)

contractAddress: Адрес развернутого смарт-контракта.
contractABI: ABI (Application Binary Interface) описывает функции и методы контракта.
rpcUrl: URL RPC-сервера для подключения к сети.

Код:
const [currentDomain, setCurrentDomain] = useState("Loading...");
const [newDomain, setNewDomain] = useState("");
const [isAdmin, setIsAdmin] = useState(false);
const [currentAccount, setCurrentAccount] = useState(null);
currentDomain: Хранит текущий домен, полученный из контракта.
newDomain: Хранит новый домен, который администратор хочет установить.
isAdmin: Указывает, является ли пользователь администратором.
currentAccount: Текущий подключенный адрес Ethereum.

Код:
useEffect(() => {
  fetchDomain();
}, []);
Запускает функцию fetchDomain один раз при загрузке компонента.
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);
  }
}
Создает провайдер через JsonRpcProvider для подключения к сети.
Вызывает метод getDomain контракта для получения текущего домена.
Обновляет состояние currentDomain.

Код:
  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.

Код:
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 контракта.

Код:
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 режиме, открываем консоль в проекте и пишем:

Код:
npm run dev

1733108411253.png


Открываем http://localhost:3000 в браузере.
Подключаем MetaMask и проверяем фукнционал:
Отображение текущего домена.
Обновление домена, если вы администратор.
Теперь у нас есть работающий интерфейс для управления доменом через блокчейн!

1733108439142.png



Попробуем поменять домен на https://xss.pro

Как видим мы ввели домен, и нажали кнопку и нам осталось только подтвердить транзакцию
1733108463356.png


После подтверждение мы видим как домен поменялся.
1733108495691.png



>> Создание простенького скрипта для клиента чтоб получать всегда актуальный линк.

Открываем консоль или терминал, cоздаем папку для проекта и переходим в неё:

Код:
mkdir client-app
cd client-app

1733108516724.png


Инициализируем проект:
Код:
npm init -y
1733108532778.png


Устанавливаем ethers
Код:
npm install ethers
1733108558085.png


Создаем файл index.js и пишем туда код.
Код:
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();
1733108589545.png



Как видим прописав node index.js наш клиент получает актуальный домен.
1733108655820.png


Второй пример
Так... ладно.. домены это все понятно, но я лично предпочитаю использовать блокчейн для получения C2 сервера, и сейчас покажу вам пример на С++ без лишних библиотек, только WinAPI который позволяет получать строку (Домен в нашем случаее) из блокчейна.

Приступим сначала я создам NodeJs скрипт для получения hex`a функций.

Так же создаем папку к примеру blockchain, переходим в нее и иницилизируем проект командой npm init -y и после уже устанавливаем библиотеку ethers командой npm i ethers
1733108690146.png


Записываем этот код в index.js но и еще если нужно меняем адрес контракта на свой, но я же буду свой использовать который создал для примера.

Код:
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++
1733108740876.png


Вот код на C++ в нем мы меняем адрес контракта на наш и hex функций контракта.

Код:
#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.

и как видим мы получили так же нашу строку из блокчейна
1733108782161.png


На самом деле это можно много где использовать в ботнетах, стилерах, лоадерах, хранения просто каких то данных которые должны получаться всегда, хранения параметров. Я досех пор не понимаю почему это даже на рынке не используется. Ведь столько блокчейнов, столько нод, и столько сетей. Вы можете получить огромный список прямяком отсюда https://chainlist.org использовать их. Ведь блокчейны и rpc куда сложней заблокировать.

Статья и идей являются авторскими.
А еще извините что так оформил криво, я вообще оформлять ничего не умею(
Ну и соотвественно даже кто-то написал статью о моеих бредовых идеях https://socket.dev/blog/exploiting-npm-to-build-a-blockchain-powered-botnet я не знаю можно ли использовать это как реальный пример. Но тут описывается тоже мое творчество, где я использую точно такие же технологий в своем ботнете. https://xss.pro/threads/123396
 
Последнее редактирование модератором:
Пожалуйста, обратите внимание, что пользователь заблокирован
👍 👍

только условие было не палиться нетакусь!
https://xss.pro/threads/128016/
3. Статьи будут размещены анонимно! Все статьи будут выложены от имени форумного бота XSSBot. Ники конкурсантов и всех участников будут раскрыты после выбора победителя в турнирной таблице.
5. Прием статей анонимный, но авторам разрешено отвечать на вопросы, критику и похвалу в своих темах.
 
https://xss.pro/threads/128016/
Статья и идей являются авторскими.
А еще извините что так оформил криво, я вообще оформлять ничего не умею(
Ну и соотвественно даже кто-то написал статью о моеих бредовых идеях https://socket.dev/blog/exploiting-npm-to-build-a-blockchain-powered-botnet я не знаю можно ли использовать это как реальный пример. Но тут описывается тоже мое творчество, где я использую точно такие же технологий в своем ботнете. https://xss.pro/threads/123396
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Я на самом деле не думаю что я имею много адептов(а точнее их совсем нету) и не так много друзей которые сидят на форуме (их примерно 2-3) которые могли чисто из за дружбы или из за просьбы проголосовать за статью. Я никогда подобным не занимался и не планирую, так же и они. Если сама суть скрытия ников зависит от того чтоб не могли узнать авторов чтоб за них не топили. А в статье мне просто захотелось показать реальный пример, на живых событиях. Если это так важно, могу попросить убрать линки если это возможно, но тогда уже не будет живого примера. Не понимаю зачем придираться до каждой мелочи будто я ядерную войну устроил (возможно я тут переборщил немного так описав, сори).

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

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

Так это просто как пример), конечно вы там можете расширять как хотите и ротейтить rpc и это только ограничивается вашей фантазий, я просто думаю те кто будет это использовать не нужно это объяснять и сам додумается.
Еще была идея чтоб сравнивать ответы, к примеру вы используете 10 rpc серверов, и получаете со всех ответ, и окончательный ответ будет тот использоваться который больше всего серверов выдаст одинакового ответа, чтоб точно убеждаться в правильном сервере и какая та rpc не могла скомпрометировать, такой же принцип почти и у блокчейна, то что ноды синхранизируются между собой, условной ты не сможешь впихнуть фейковый блок или транзу потому что другие валидаторы его отвергнут
тем более куча расширений такие как metamask, exodus, phantom и тд используют одни и те же rpc публичные которые работают годами и не меняются, по этому это куда надежней и сильней чем обращаться к серверу на прямую, за мою историю мне сервера только блокировали, но я просто их заменял в контракте, и дальше пользуюсь своими ботами, потому что мои боты, только мои

тем более куча расширений такие как metamask, exodus, phantom и тд используют одни и те же rpc публичные которые работают годами и не меняются, по этому это куда надежней и сильней чем обращаться к серверу на прямую, за мою историю мне сервера только блокировали, но я просто их заменял в контракте, и дальше пользуюсь своими ботами, потому что мои боты, только мои


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

Так же много историй взломов крипто проектов, на которых лежат ворованые крипто активы и никто их вернуть не может, а владелец кошелька свободно может ими пользоваться и переводить, так почему в какой то безобидной фигне по типу хранения какой то строки должны блокировать или как то сопротивлятся? Если 1 rpc сервером пользуются миллионы юзеров, и ради тебя одного как то разработчики блокчейнов должны как то бороться с тобой, я думаю это практически невозможно
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Тем более автор все равно может палится по комментариям, тогда имеет ли огромный смысл анонимность данной статьи если в большинство статьях автор будет известен?
Не переживай. Так и задумано. Это просто сделано для некой интриги, не более того. На голосование точно не как не повляет. Так же никто не запрещает отвечать на вопросы под чужими статьями, будто то бы ты автор других статей. В конце концов все личности будут раскрыты.
Прием статей анонимный, но авторам разрешено отвечать на вопросы, критику и похвалу в своих темах.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
интересно! но реализация чет муторная уж совсем лично для меня
Предложи получше как бы ты хотел ее видеть
 
Предложи получше как бы ты хотел ее видеть
да честно сказать именно в блокчейн технологиях я пока что ноль)) просто если брать расчет что это приложение для актуальности домена или чего то еще запара долгая, но возможно и стоящая
вот предположение касаемо использования в малвари оправдывает затраты времени))
 
да честно сказать именно в блокчейн технологиях я пока что ноль)) просто если брать расчет что это приложение для актуальности домена или чего то еще запара долгая, но возможно и стоящая
вот предположение касаемо использования в малвари оправдывает затраты времени))
Так может поэтому и муторная потому что ты ноль?
 
Пожалуйста, обратите внимание, что пользователь заблокирован
просто если брать расчет что это приложение для актуальности домена
Это просто как пример, я хотел донести то как можно использовать в принципе эту фичу, и можно ее использовать во многом. И к примеру актуальности домена я считаю это тоже супер полезно потому что часто видел темы где пользователи теряли нормальный линки и не хотели попасть на ханипот или что-то еще. Данная реализация на мой взгляд решает эту проблему. Можно не только линки хранить, а оповещение от владельца сайта к примеру чтоб описать ситуацию что с ним произошло и донести до пользователей какую то важную новость если сайт лежит и нет других способов связи.
 
Последнее редактирование:
Это просто как пример, я хотел донести то как можно использовать в принципе эту фичу, и можно ее использовать во многом. И к примеру актуальности домена я считаю это тоже супер полезно потому что часто видел темы где пользователи теряли нормальный линки и не хотели попасть на ханипот или что-то еще. Данная реализация на мой взгляд решает эту проблему. Можно не только линки хранить, а оповещение от владельца сайта к примеру чтоб описать ситуацию что с ним произошло и донести до пользователей какую то важную новость если сайт лежит и нет других способов связи.
да конечно я не спорю, фича 100% полезная, просто я к тому, что если бы это можноо было б развернуть в 2 клика - было бы просто шикарно)
во всяком случае спасибо за довольно интересное решение данной проблемы касаемо актуальных линк или какой либо информации
 
Пожалуйста, обратите внимание, что пользователь заблокирован
мне понравилась статья, я как раз сейчас изучаю тему и достаточно много закрыл своих вопросов. спасибо автору
 
Interesting topic which could be used for C&C usage. For example said loader checks blockchain for the URL to communicate with. If said url gets taken down you just update via the blockchain. Although AV can just look for update as well to block the urls being supplied to the blockchain. But definitely interesting. What else can be done with blockchain and in tandem with malware and C&C servers?
 
Довольно интересное решение, и весьма практичное
Статья не сложная технически и не представляет ничего из ряда вон выходящего
Но задумка отличная, мне понравилось 👍👍
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх