Main Menu

News:

Join Our Ratlab VIP Forum

INJECT подмена Wallet Addresses (Clipper)

Started by Administrator, Oct 05, 2026, 02:33 PM

Previous topic - Next topic

Administrator

INJECT подмена Wallet Addresses (Clipper)


Specialities:

• Support for 7 networks at once (BTC, ETH, LTC, TRON, Solana, TON, Cardano)

• Not primitive regex: address validation (length, prefix, alphabet)

• For Ethereum – check EIP-55 via built-in Keccak-256

• Works without external libraries and CDN

• Three swap channels: DOM, clipboard, paste event

• MutationObserver — catches addresses on dynamic SPA-sites

• Custom flags: page monitoring / clipboard separately

• Whitelist of domains – you can limit which sites are active

• Customizable clipboard polling interval

• Clean architecture: validators + manager + init / stop

• Substitution log: original address, replacement, network, time, URL

• Fallback for clipboard if API is not available

• Works inside the browser – without .exe and native-hooks

More detailed
The code is designed according to the IIFE pattern with the module pattern: all state and classes are hidden inside the circuit, only the public API is given outside.

const WalletAddressInterceptor = (() => {
  // приватное состояние, классы, функции
  return { init, stop }  // публичный API
})()
Logically, the script is divided into several layers:

Config - Poll interval, monitoring flags, whitelist domains, replacement addresses.

Crypto (Keccak256) - Own implementation of Keccak-256 for checksum Ethereum (EIP-55).

Validators - Address recognition of BTC, ETH, LTC, TRON, SOL, ADA.

Engine - Substitution in text, DOM, clipboard, paste; logging.

Lifecycle - init / stop, autorun on DOMContentLoaded.

The configuration

At the beginning of the module, three key structures are defined:

allowedDomains = []              // пусто = все сайты
checkInterval: 1000              // опрос clipboard раз в 1 с
enablePageMonitoring: true      // подмена в DOM
enableClipboardMonitoring: false // clipboard/paste выключены
 
replacementAddresses = {
  btc, eth, tron, solana, ton, ada, ltc  // сейчас пустые строки
}
Empty replacementAddresses mean that the substitution does not actually occur: the replacement function immediately returns the source text if the replacement address is not specified.

Empty allowedDomains means that the script is active on any site.

By default, page monitoring (DOM) is enabled, and clipboard monitoring is disabled — the payload is "semi-armed", but the logic is ready to be activated.

In the "combat" configuration, the attacker fills replacementAddresses with his wallets and, as a rule, includes clipboard monitoring.

Implementation of Keccak-256

The script has its own implementation of the hash function Keccak-256, without using Web Crypto API. This is typical for an offline inject: the code does not depend on external libraries and works in any modern browser.

Key parameters of the Sponge-construction:

State of 200 bytes

Rate: 1088 bit by bit

Length of output: 256 bits.

24 rounds of transformations: θ (theta), ρ (rho), π (pi), χ (chi), ι (iota).

Padding: byte 0x01, then zeros, last byte with bit 0x80.

The address with the "mixed" register (for example, 0xAbC...dEf) is checked with the hash nibbles from the lower-case version. This reduces the number of false positives on random rows of the form 0x... and makes recognition "smarter" than the primitive regex.

Address substitution core

The central function replaceAddressInText performs the entire cycle: find > take a replacement > substitute > pledge.

function replaceAddressInText(text) {
  const addressInfo = extractAddress(text)
  if (!addressInfo) return text
  const replacement = replacementAddresses[type]
  if (!replacement) return text
  const newText = text.replace(address, replacement)
  // log: original, replacement, type, timestamp, url
  return newText
}
Each successful substitution gets into the replacementsLog array with the fields:

original — the original address of the victim;

replacement — address of the attacker;

type — network type (eth, btc, etc.);

timestamp is the ISO time;

url — window.location.href (the page where the substitution occurred).

The sendToServer function in the disassembled instance is a stub: it only displays the object in console.log. In real malware, there are usually fetch, XMLHttpRequest or navigator.sendBeacon on the control server.

Three attack vectors

Vector A: substitution in the DOM page

EnablesPageMonitoring flag (default true). Algorithm:

One-time bypassing document.body and replacing addresses in already loaded content.

Installation of MutationObserver on childList, subtree and characterData – to catch dynamically added content (SPA, AJAX, React, etc.).

The function replaceAddressesInNode processes text nodes (textContent) and attributes: href, data-address, data-wallet, title, alt, value, placeholder.

SCRIPT and STYLE nodes are skipped.

Scenario for the victim: a person opens the site, sees the "deposit address" – but the attacker's wallet is already placed on the screen. If the user does not check the characters, the funds go past.

Vector B: clipboard monitoring

EnableClipboardMonitoring is enabled. Once in checkInterval milliseconds (by default 1000) is executed:

request permission clipboard-read;

reading navigator.clipboard.readText();

if the address is found — record of the replaced text via clipboard.writeText();

logging and call sendToServer.

When the Permissions API error, fallback is triggered: a hidden textarea is created, obsolete document.execCommand('paste') / document.execCommand('copy') are called. The method is unstable in modern browsers, but in malware-code it is still found as a backup path.

Scenario: the user copies his address > after a fraction of a second in the buffer already the address of the attacker > when inserting funds go not there.

Vector C: intercept the paste event

In the capture phase hangs the listener paste:

document.addEventListener('paste', handler, true)
// preventDefault > insertText(подменённый текст)
If there is an address in the inserted text, the event is canceled, and an already substituted string is inserted into the field. This beats the forms of exchanges, wallets and any web applications where the user inserts the address manually.

The life cycle of the script

Public API is minimal:

init() — check the domain (isDomainAllowed), launch page monitor and/or clipboard monitor.

stop() — disconnect MutationObserver, clearInterval for polling.

Autorun when loading the document:

if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', () => {
    WalletAddressInterceptor.init()
  })
} else {
  WalletAddressInterceptor.init()
}
Typical delivery channels of such code: malicious browser extension (content script), userscript (Tampermonkey and analogues), XSS / inject on a compromised site, supply-chain attack on npm/CDN, "useful" crypto-expansion or fake wallet helper, which the victim puts herself.

Indicators of compromise and detection

Static signs in code

Identifiers: WalletAddressInterceptor, replacementAddresses, replacementsLog.

A bunch of validator classes of several networks in one file.

Own implementation of Keccak next to clipboard/DOM rewrite.

Behavioral signs and symptoms

clipboard.writeText immediately after clipboard.readText if there is a wallet-like line.

MutationObserver + mass editing of text nodes, similar to addresses.

permissions.query({ name:'clipboard-read'}) paired with setInterval ~ 1 s.

Intercept paste in capture phase with preventDefault and insertText.

Examples of string patterns

0x[a-fA-F0-9]{40}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{{0}{{0}{{0}{{{0}{{{0}{{{0}}{{{0}}{{0}}{{{0}}{0}}{{{0}}{

bc1 / bc1p, ltc1, addr1

Addresses on T (TRON), EQ/UQ (TON)

Base58-strings of length 32-44 (Solana-heuristics)





VIP Forum — Lifetime Access🔥

Join Our VIP Group Get lifetime access for just $100 and unlock a growing collection of 50+ PC and Android RATs, along with regular updates and community support.

What You'll Get

💻 50+ PC & Android RATs 🔄 Regular updates & new releases🛠  Community support 📢 Latest announcements and updates ♾️ Lifetime VIP access 👥 Private members-only forum💎 Lifetime VIP — $100One Time payment, Lifetime access.

👉 Join now and become a VIP member


injectb.png