アドレスポイズニングとは?送金前に「似たアドレス」を見抜く方法|テスト送金の直後が危ない

アドレスポイズニングとは?送金前に「似たアドレス」を見抜く方法|テスト送金の直後が危ない

DigitalCraft
16 min read

取引履歴に「先頭と末尾だけ同じ偽アドレス」を紛れ込ませ、次の送金でコピーさせるのがアドレスポイズニングです。3つの手口、テスト送金の直後に罠が仕掛けられる理由、全文照合の手順を解説します。Ethereumメインネット2時間分の実測と、依存なしの送金前チェックスクリプトつき。

目次

アドレスポイズニングの「似たアドレス」は、送金前にどう見抜く?

送金先アドレスを取引履歴からコピーしないこと、そして先頭と末尾の数文字が合っているだけで信用しないことです。アドレスポイズニングは、あなたが最近送金した相手と先頭・末尾が同じアドレスを生成し、本物の送金の直後にそれを履歴へ紛れ込ませる攻撃です。送金先は、攻撃者が書き込めない場所から取得してください。保存済みのアドレス帳、受取人のアプリやQRコード、自分で開いた取引所の入金ページなどです。そのうえで、真ん中を含めたアドレス全体を照合します。

この記事のために取ったEthereumメインネット2時間分のサンプルでは、USDTまたはUSDCを送金した2,344の送金元アドレスが、本物の送金から100ブロック以内に偽アドレスを履歴に仕込まれていました。遅延の中央値は22ブロック、約4.4分です。

セルフカストディのウォレットからステーブルコインやトークンを送る人、とくに「まず少額をテスト送金して、残りを送る」運用をしている人に向けた記事です。

前提:取引履歴は他人が書き込める

EVMチェーンでは、誰でもあなたのウォレットのアクティビティ一覧に表示されるイベントを作れます。取引履歴は「自分が選んで取引した相手の記録」ではなく、「自分のアドレスが登場するTransferイベントの一覧」にすぎません。攻撃者はここを突きます。

Tsuchiyaらの論文 Blockchain Address Poisoning(USENIX Security 2025) は、2022年7月〜2024年6月のEthereumとBNB Smart Chainを計測しました。ポイズニング送金は約2億7,000万件、標的になったアドレスは1,700万件、被害額は少なくとも8,380万ドルです。Ethereumでの1回あたりの成功率は約0.01%と低いものの、攻撃は安価で自動化されているため、採算が取れてしまいます。

偽アドレスは、秘密鍵を総当たりで生成し、標的アドレスの先頭と末尾の16進文字が一致するまで繰り返して作ります。一致させる文字が1つ増えるごとに計算量は16倍になります。論文によると、多くの攻撃グループは合計14文字程度まで一致させており、GPUツールを使えばそれ以上も現実的です。

攻撃の流れ:偽アドレスが履歴に入る3つの経路

論文は3種類の手口を挙げています。どれも、本物のアドレスの隣に偽アドレスを並べることが目的です。

| 手口 | 履歴にどう見えるか | 成立する理由 | | -------------- | ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ゼロ額送金 | 自分から偽アドレスへ0トークンを送った記録 | USDT・USDCを含む多くのERC-20では、金額0の transferFrom が承認額チェックを通るため、他人があなたを送金元とする Transfer イベントを発生させられる。過去に送金した相手に見える。 | | 少額送金 | 偽アドレスから自分へわずかな額が届いた記録 | 偽アドレスが「最近の取引相手」として表示される。 | | 偽トークン送金 | 「USDT」など見覚えのある名前の偽トークンの送受信記録 | ウォレットやエクスプローラーで本物の隣に並ぶことがある。コントラクトは攻撃者のものなので、任意のイベントを出せる。 |

どの手口も、あなたの署名・承認(Approve)・ウォレットへのアクセスを必要としません。承認のRevokeや署名画面のチェックでは防げないということです。被害が出るのは、あなたが後で本物の資金を偽アドレスへ送ったときだけです。

メインネットで観測した結果(独自サンプル)

Ethereumメインネットの正規USDT・USDCコントラクトについて、ブロック26,281,983〜26,282,582の600ブロック(2026年10月27日 14:35〜16:35 JST)の Transfer イベントをすべて取得しました。1トークン以上の本物の送金から100ブロック以内に、次のどちらかが現れたものをポイズニングとして数えています。

  • 同じ送金元から、本物の受取先と先頭3文字以上・末尾4文字以上が一致するアドレスへのゼロ額送金
  • そのような偽アドレスから送金元への1トークン未満の送金

「先頭3・末尾4」の閾値と100ブロックの観測窓は、USENIX論文の検出基準に合わせました。スキャナーは公開RPCに対して eth_blockNumber と eth_getLogs だけを呼ぶ、依存パッケージなしのスクリプトです。

| 指標 | 値 | | -------------------------------------- | -------------------------------- | | USDT/USDCの Transfer イベント | 88,512件 | | 1トークン以上の送金 | 61,646件(送金元21,572アドレス) | | ゼロ額送金 | 8,910件 | | ポイズニングと判定した送金 | 6,738件 | | うちゼロ額 / 少額 | 3,320件 / 3,418件 | | 標的になった送金元 | 2,344アドレス(送金元の10.9%) | | ゼロ額送金のうちポイズニングだった割合 | 37.3% | | 本物の送金からの遅延(ブロック) | 最小0・中央値22・p90 78 | | 5ブロック(約1分)以内に届いたもの | 551件 | | 一致していた文字数(先頭+末尾) | 最小7・中央値8・最大13 |

サンプルから3組を、前後8文字ずつに短縮して示します。上が本物の受取先、下が偽アドレスです。

ゼロ額送金、1ブロック後
  本物  0x0a2770ff…f4231b77
  偽    0x0a272d8f…38f41b77   (先頭4, 末尾4)

ゼロ額送金、9ブロック後
  本物  0x28302daa…ccc5b09e
  偽    0x2830bf3d…44c5b09e   (先頭4, 末尾6)

ゼロ額送金、7ブロック後
  本物  0x583e959e…8c907c35
  偽    0x583ebf64…5aa97c35   (先頭4, 末尾4)

数字の読み方には注意が必要です。

  • 1チェーン・2トークン・2時間のスナップショットで、傾向を示すものではありません。偽トークン型は数えていないので、実際の総数はもっと多くなります。
  • 判定数は下限値です。範囲の冒頭付近の送金はそれ以前の本物の送金がデータに含まれず、最終ブロック以降のポイズニングも観測できていません。
  • 特定の2アドレスが偶然7文字一致する確率は約2億6,800万分の1(16⁷)なので、このサンプル規模で偶然の一致はほぼ無視できます。

実務上いちばん重要なのはタイミングです。ポイズニングは本物の送金から数分以内、つまり次の送金をしようとしている最中に届きます。

テスト送金の直後に罠が仕掛けられる理由

少額のテスト送金は良い習慣です。受取人に実際に届くことを確認できます。しかし、攻撃者が監視しているのもまさにそのテスト送金です。典型的な流れは次のとおりです。

  1. 正しいアドレスへテストとして10 USDTを送る。
  2. 数分以内に、ボットがその送金を検知し、受取先の偽アドレスを生成または選び出す。
  3. ボットが、あなたから偽アドレスへのゼロ額送金を記録するか、偽アドレスから少額を送ってくる。
  4. 受取人から「届いた」と連絡が来る。あなたは履歴を開き、一番上にある「同じ」アドレスをコピーして残額を送る。

間違いは手順4です。先頭と末尾が一致する最新の履歴は、偽アドレスかもしれません。テスト送金が役に立つのは、本番の送金でもテストと同じ確認済みの取得元を使った場合だけです。履歴からコピーした時点で、テストの意味はなくなります。

実際に効く対策

上から順に適用してください。最初の2つでリスクの大部分を取り除けます。

  1. 繰り返し送る相手はアドレス帳・許可リストに登録する。 別経路で一度確認したアドレスを保存し、以後は必ずアドレス帳から選びます。取引所やウォレットに出金先の許可リスト(ホワイトリスト)機能があれば有効にします。
  2. 新しいアドレスは履歴ではなく、受取人側の情報源から取る。 取引所への入金なら、取引所アプリの入金ページを自分で開きます。個人宛てなら、別の連絡手段でもう一度送ってもらい、真ん中の文字を読み上げて照合します。
  3. 両端ではなく真ん中を比べる。 攻撃者が合わせてくるのは両端です。アドレス中央の数文字を確認するか、ツールで全文を比較します。
  4. ツール側でゼロ額送金やスパム送金を非表示にする。 Etherscanはゼロ額のトークン送金をデフォルトで非表示にし、不審な活動に関係するアドレスをコピーすると警告を出します(Etherscanの解説)。ただし、少額送金や偽トークン型までは防げません。
  5. 身に覚えのない少額の入金は警告サインとみなす。 送金した相手に似た見知らぬアドレスから数セント届いたら、それはプレゼントではなくポイズニングです。触らないでください。

ENS名が役立つのは、その名前が想定どおりのアドレスに解決されることを確認した場合だけです。解決後のアドレスを後で履歴からコピーすれば、同じ罠にかかります。

送金前に照合する:依存なしのチェックスクリプト

送金先アドレスを、信頼済みアドレスの一覧と比較するスクリプトです。完全一致、似たアドレス(偽物の疑い)、未登録のいずれかを判定します。check-address.mjs として保存し、Node.js 18以降で実行します。

// Compare a destination address against trusted addresses before sending.
// Usage: node check-address.mjs <destination> <trusted1> [trusted2 ...]
const norm = (a) => {
  if (!/^0x[0-9a-fA-F]{40}$/.test(a)) throw new Error(`not an EVM address: ${a}`);
  return a.toLowerCase();
};

function edgeMatch(a, b) {
  const x = a.slice(2);
  const y = b.slice(2);
  let prefix = 0;
  while (prefix < 40 && x[prefix] === y[prefix]) prefix++;
  let suffix = 0;
  while (suffix < 40 && x[39 - suffix] === y[39 - suffix]) suffix++;
  return { prefix, suffix };
}

const [dest, ...trusted] = process.argv.slice(2).map(norm);
if (!dest || trusted.length === 0) {
  console.error('usage: node check-address.mjs <destination> <trusted...>');
  process.exit(2);
}

if (trusted.includes(dest)) {
  console.log(`OK      exact match with a trusted address: ${dest}`);
  process.exit(0);
}

let worst = null;
for (const t of trusted) {
  const m = edgeMatch(dest, t);
  if (m.prefix >= 3 && m.suffix >= 4 && (!worst || m.prefix + m.suffix > worst.score)) {
    worst = { t, score: m.prefix + m.suffix, ...m };
  }
}

if (worst) {
  console.log(`DANGER  lookalike of trusted ${worst.t}`);
  console.log(
    `        same first ${worst.prefix} and last ${worst.suffix} hex chars, different middle`
  );
  process.exit(1);
}

console.log('UNKNOWN not in your trusted list; confirm the full address through a second channel');
process.exit(3);

信頼済みアドレス 0x1111222233334444555566667777888899990a1b に対して3通り実行した結果です。

$ node check-address.mjs 0x1111222233334444555566667777888899990A1B 0x1111…0a1b
OK      exact match with a trusted address: 0x1111222233334444555566667777888899990a1b
(exit 0)

$ node check-address.mjs 0x1111f00dbeefcafe0000123456789abc99990a1b 0x1111…0a1b
DANGER  lookalike of trusted 0x1111222233334444555566667777888899990a1b
        same first 4 and last 8 hex chars, different middle
(exit 1)

$ node check-address.mjs 0x9999222233334444555566667777888899990000 0x1111…0a1b
UNKNOWN not in your trusted list; confirm the full address through a second channel
(exit 3)

大文字・小文字を区別しないのは意図的です。EIP-55のチェックサムは打ち間違いを検出できますが、偽アドレスもそれ自体が正しいチェックサムを持つ有効なアドレスなので、チェックサム検証ではポイズニングを防げません。

すでに偽アドレスへ送ってしまったら

オンチェーンの送金は取り消せません。それでも、すぐに動いてください。

  1. トランザクションハッシュ、トークン、金額、偽アドレスを記録する。
  2. USDTやUSDCのような発行体が管理するステーブルコインなら、発行体と、資金が流れ込みそうな取引所に連絡する。論文には、Tetherが攻撃者のアドレスを1時間以内に凍結した事例が記録されています。
  3. ブロックエクスプローラーにアドレスを報告し、他の利用者向けにラベル付けしてもらう。
  4. 警察に被害届を出す。取引所が対応する前提として求められることが多いです。
  5. 向こうから接触してくる「資金回収サービス」は無視する。ポイズニングの被害者は、二次詐欺の標的になりやすいです。

参考資料

内部リンク

免責事項

投資助言ではありません。一般的なセキュリティ情報です。メインネットの数値は1つの公開RPCから取得した短時間のスナップショットで、観測した送金パターンを示すものであり、確認された盗難件数ではありません。ウォレットやエクスプローラーの挙動は、ご自身の環境で確認してから利用してください。

編集部のおすすめ

  1. 1Permit2とは何か?Approveが変わった理由と安全な使い方(チェックリスト)
  2. 2署名(Sign)画面の読み方|Approve/Permit/NFT全権限を30秒で判別するチェックリスト
  3. 3仕様→実装に落とすプロンプトテンプレ(AI開発)|AIに“迷わせない”仕様の書き方
  4. 4EVMのトークン承認(Approve)を見直す方法|Revokeの手順と判断基準(チェックリスト)
  5. 5曖昧な依頼を要件定義に変換する質問リスト(AI開発)|AIに実装させる前に聞くべきこと

関連記事