Hosting PWN Challenges
Players can interact with your vulnerable binary over TCP (e.g., using netcat) if you run your binary behind socat
.
Prepare your challenge's image
FROM ubuntu:latest
RUN apt-get update && apt-get install -y socat
COPY flag.txt /
COPY YOUR_BINARY /
RUN chmod +x /YOUR_BINARY
CMD ["socat", "TCP-LISTEN:12345,reuseaddr,fork", "EXEC:/YOUR_BINARY"]
Your challenge's Lua plugin can configure the port 12345
and optionally mount a random flag.txt
if you want a dynamic flag.
Extra: Using a different GLIBC version.
You can change the interpreter and GLIBC version using patchelf.
FROM ubuntu:latest
RUN apt-get update && apt-get install -y socat patchelf
COPY flag.txt /
COPY libc.so.6 /
COPY ld-linux-x86-64.so.2 /
COPY YOUR_BINARY /
RUN chmod +x libc.so.6
RUN chmod +x ld-linux-x86-64.so.2
RUN chmod +x /YOUR_BINARY
RUN patchelf /YOUR_BINARY --set-rpath . --set-interpreter ld-linux-x86-64.so.2
CMD ["socat", "TCP-LISTEN:12345,reuseaddr,fork", "EXEC:/YOUR_BINARY"]
Write a challenge plugin (Docker)
After adding the challenge, you can add a PostInstanceCreation
and a PreInstanceCreation
script.
-- events/my-challenge-123/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
-- create a tmp file on the host containing the flag
local path = string.format("/tmp/flag-%s.txt", generate_hex(20))
local file = io.open(path, "w")
local flag = string.format("ASU{%s}", generate_hex(40))
file:write(flag)
file:close()
-- set the port and mount the random flag.txt
raya.docker_options = {
port = "80",
volumes = { string.format("%s:/flag.txt", path) }
}
raya.flag = flag
-- events/my-challenge-123/PostInstanceCreation.lua
-- Update the instance description with the connection details
raya.description = string.format([[
```
nc chall.rayactf.local %s
```
]], raya.container.published_port)