Recipes

A list of commonly requested extensions.

First blood announcer over Discord

-- /etc/rayactf/extensions/events/PostChallengeSubmission.lua
local lunajson = require 'lunajson'
local http = require("socket.http")
local ltn12 = require("ltn12")

local webhook_url = "https://discord.com/api/webhooks/<SECRET>/<SECRET>"

local function post_request(url, body)
    local result, status_code, headers = http.request{
        url = url,
        method = "POST",
        source = ltn12.source.string(body),
        headers = {
            ["Content-Type"] = "application/json",
            ["Content-Length"] = tostring(#body),
        },
    }

    if not result then
        error("HTTP request failed")
    end
end

local function send_discord_message(message)
	post_request(webhook_url, lunajson.encode({
		content = message
	}))
end

-- First blood announcement
if raya.result.Correct and raya.challenge.solves == 0 then
	local name = ""
	if raya.team then
		name = raya.team.name
	else
		name = raya.user.name
	end
    send_discord_message(string.format(":drop_of_blood: First blood for **%s** goes to **%s**", raya.challenge.name, name))
else
	print("incorrect submission")
end

Unique flag per user (environment variable) | docker

-- /etc/rayactf/extensions/events/PreInstanceCreation.lua
local function generate_hex(length)
	local hex = ""
	for i = 1, length do
		hex = hex .. string.format("%x", math.random(0, 15))
	end
	return hex
end

if raya.current_flag then
	raya.log("Using the fixed flag value")
else
	local flag = string.format("Raya{%s}", generate_hex(40))
	raya.flag(flag)
end

Unique flag.txt per user | docker

Some challenges have their flag stored in a text file instead of environment variables.

-- /etc/rayactf/extensions/events/PreInstanceCreation.lua
local function generate_hex(length)
	local hex = ""
	for i = 1, length do
		hex = hex .. string.format("%x", math.random(0, 15))
	end
	return hex
end

-- If Raya itself is deployed as a container, make sure to mount /tmp to the host.
local path = string.format("/tmp/flag-%s.txt", generate_hex(20))

local file = io.open(path, "w")
local flag = string.format("Raya{%s}", generate_hex(40))

file:write(flag)
file:close()

raya.setDockerOptions({
	port = "1234",
	volumes = { string.format("%s:/flag.txt", path) }
})

raya.flag(flag)