Analiza wyrafinowanego oszustwa z fałszywym mainnetem GIWA, w wyniku którego 27.09.2026 użytkownicy stracili 766 ETH, a zdecentralizowana giełda DYORSWAP została zaatakowana przez integrację fałszywego RPC.
Wyrafinowane oszustwo: jak podrabiają blockchain
Przeglądam feed monitoringu bezpieczeństwa i... aż prawie upuściłem kubek. Siedemset sześćdziesiąt sześć etherów. Po prostu w siną dal. I pół biedy, gdyby chodził o klasyczny phishing przez podrobioną libę czy exploit kontraktu z flash loanami — tego już się nadoglądałem. Ale tu schemat jest o wiele bardziej elegancki. Oszuści postawili fałszywy mainnet GIWA, podpięli pod niego cudzy DEX i ogołocili użytkowników na kilka milionów dolarów.
Rozbierzmy ten incydent na czynniki pierwsze, bo od strony architektonicznej jest tu na co popatrzeć okiem inżyniera. Jako specjalista ds. bezpieczeństwa IT i aktywny CTO, po prostu podziwiam śmiałość realizacji, choć ekipie z DYORSWAP oczywiście nie zazdroszczę.
Poczekaj, ale jak w ogóle można "podrobić" blockchain warstwy 2 (L2)? Brzmi to szalenie dla kogoś wtajemniczonego powierzchownie, ale w świecie EVM sieć to żadna magia, a po prostu zestaw konwencji i endpointów RPC.
Złośliwi aktorzy wzięli open-source'owy stos (pewnie zforkowali coś w stylu OP Stack) i postawili węzeł. Ale mało podnieść serwer, trzeba jeszcze zmusić portfele i aplikacje do wiary, że to oficjalny produkt południokoreańskiej giełdy Upbit, u której ta cała GIWA nie miała nawet oficjalnego startu mainnetu.
Zahardkodowali w konfiguracji węzła oficjalny Chain ID — cyfrę 9134, którą zespół GIWA zarezerwował z wyprzedzeniem dla swojego przyszłego blockchaina. I tu tkwi główna podatność całego ekosystemu: portfele takie jak MetaMask sprawdzają sieć po linijkach konfiguracji i po ID, a nie po kryptograficznych korzeniach zaufania do twórców.
I w tym miejscu dochodzimy do momentu, w którym naciął się DEX DYORSWAP. Dodali ten fejkowe RPC do swojej infrastruktury, chcąc jako pierwsi wskoczyć na hajpowy wagonik nowej sieci.
Wiesz, kiedy sam robiłem audyty smart kontraktów po godzinach, zawsze myśleliśmy: no dobra, front-end mogą podrobić, RPC mogą podmienić, ale smart kontrakt mostu to świętość, przecież tam kod siedzi na blockchainie Ethereum! I w tym tkwi najbardziej elegancka pułapka tego ataku.
Dlaczego użytkownicy niczego nie podejrzewali?
Użytkownicy niczego nie podejrzewali, ponieważ most wyglądał jak natywny interfejs do transferu środków z Ethereum do sieci L2 GIWA. Ludzie podpisovali transakcje w MetaMask, wysyłając swoje ciężko zarobione ETH na depozytowy smart kontrakt w mainnecie.
Technicznie ten kontrakt został napisany przez oszustów tak, aby imitować działanie standardowego lokatora depozytów. Gdy tylko transakcja przeszła walidację w głównej sieci, oszuści zyskiwali kontrolę nad środkami. W zamian użytkownik dostawał fałszywe, niczym niepoparte papierki na saldzie podrabianego L2. Cyferki na ekranie rosły, tworząc iluzję udanego bridge'a, a prawdziwy ether leciał już na adresy organizatorów schematu, parując w mikserach. Ostatecznie ucierpiało 1335 unikalnych adresów, zostawiając w pułapce ok. 767.7 ETH. Przy czym wyciągnęli czysto około 766.3 ETH, radząc sobie z minimalnymi kosztami gasu.
Zespół DYORSWAP zachował się kozacko, przeznaczając ponad 200 ETH z własnej kieszeni na rekompensaty. Szanuję takie podejście do reputacji, chociaż dziurę architektoniczną w walidacji zewnętrznych połączeń RPC będą musieli załatać choćby nie wiem co.
A teraz przejdźmy do części praktycznej. Jak nie zostać sponsorem kolejnych cwaniaków, jeśli lubisz jako pierwszy testować nowe blockchainy? Naskrobałem dla Was skrypt w Pythonie do weryfikacji węzłów RPC zanim w ogóle pomyślicie o interakcji z nimi przez portfel.
#!/usr/bin/env python3
import requests
def rpc_call(rpc_url, method, params=None):
if params is None:
params = []
payload = {
"jsonrpc": "2.0",
"method": method,
"params": params,
"id": 1
}
response = requests.post(rpc_url, json=payload, timeout=10)
response.raise_for_status()
data = response.json()
if "error" in data:
raise RuntimeError(f"{method}: {data['error']}")
return data.get("result")
def verify_evm_node(rpc_url, expected_chain_id):
try:
chain_id_hex = rpc_call(rpc_url, "eth_chainId")
chain_id = int(chain_id_hex, 16)
net_version = rpc_call(rpc_url, "net_version")
client_version = rpc_call(rpc_url, "web3_clientVersion")
block_number_hex = rpc_call(rpc_url, "eth_blockNumber")
block_number = int(block_number_hex, 16)
latest_block = rpc_call(
rpc_url,
"eth_getBlockByNumber",
["latest", False]
)
print("=" * 60)
print(f"RPC URL : {rpc_url}")
print(f"Chain ID : {chain_id}")
print(f"Expected ChainID : {expected_chain_id}")
print(f"Net Version : {net_version}")
print(f"Client Version : {client_version}")
print(f"Block Number : {block_number}")
if latest_block:
print(f"Latest Block Hash: {latest_block.get('hash')}")
print(f"Latest Block Num : {int(latest_block['number'], 16)}")
print(f"Parent Hash : {latest_block.get('parentHash')}")
print(f"Timestamp : {int(latest_block['timestamp'], 16)}")
print("=" * 60)
checks = []
checks.append(chain_id == expected_chain_id)
try:
checks.append(int(net_version) == expected_chain_id)
except Exception:
checks.append(False)
checks.append(block_number > 0)
checks.append(
latest_block is not None
and latest_block.get("hash")
and latest_block.get("parentHash")
and latest_block.get("number")
)
if all(checks):
print("VERIFICATION PASSED")
return True
print("VERIFICATION FAILED")
return False
except Exception as e:
print(f"ERROR: {e}")
return False
if __name__ == "__main__":
verify_evm_node(
"https://your-rpc-endpoint",
9134
)Zapamiętajcie główną zasadę: nigdy nie ufajcie listom sieci z podejrzanych kont na Twitterze czy niezweryfikowanych DEX-ów, dopóki oficjalny projekt w swoich zweryfikowanych kanałach (nie w social mediach, a w dokumentacji lub na oficjalnej stronie z certyfikatami SSL) nie opublikuje dokładnie endpointów. Giełda Upbit wprost oświadczyła, że ich mainnet jeszcze nie ruszył, a wszystkie obecne RPC to strzelanie na oślep i czysty scam.