We used a unique method to solve levels 5 and 6 of the Stripe CTF 2.0. While some say "any way that works is the right way", this was definitely not what was expected (to the point where it was patched for after I sent Stripe this writeup). Both of these levels used Rack. Both of them use sessions. And, best of all, both of them have tracebacks enabled. There's a pretty big problem with all of these things: Sessions in rack are stored as a ruby hash (a dict, for us Python people) in a cookie with some signatures generated with HMAC. The key used for that is retrieved from a file, and that local file is generated from OpenSSL generating random bytes. Normally, you'd never get to see this key - it's a secret, after all. But those tracebacks are very, very revealing, as our team discovered late on Wednesday night: ![Oh dear](http://i.imgur.com/Nnvdf.png) You might be wondering how we got that traceback in the first place, as not everyone was as... annoyingly persistent at throwing random crap into the form fields as us. We put a space in the pingback. It made a `URI::InvalidURIError`. Fun stuff. So, now we have the secret key. We pulled down the source for the server (because it presented a rack environment all set up and ready to go), forced the key in our personal server, and had it set some session values when you went to the login URL. ![(img of code overwriting the session_secret)](http://i.imgur.com/j1SFP.png) Particularly, I made this cookie on Level 6: `rack.session=BAh7CSINdHJhY2tpbmd7CCIZSFRUUF9BQ0NFUFRfTEFOR1VBR0UiLWRhMzlh%0AM2VlNWU2YjRiMGQzMjU1YmZlZjk1NjAxODkwYWZkODA3MDkiFEhUVFBfVVNF%0AUl9BR0VOVCItZGEzOWEzZWU1ZTZiNGIwZDMyNTViZmVmOTU2MDE4OTBhZmQ4%0AMDcwOSIZSFRUUF9BQ0NFUFRfRU5DT0RJTkciLWRhMzlhM2VlNWU2YjRiMGQz%0AMjU1YmZlZjk1NjAxODkwYWZkODA3MDkiD3Nlc3Npb25faWQiRWZlMjAzMDQ0%0AYjFlNDhmYzM2YTBjODViYTE1MTk1NTdiMWJhNjA3N2QxNDcwNzVjNDY0ZGYw%0AMjQyOGJkZDNkMzkiCXVzZXIiHGxldmVsMDctcGFzc3dvcmQtaG9sZGVyIg9j%0Ac3JmLnRva2VuIjFyQmpaUWs3b29SWjdwaVg5M1FJRS9LaEZHSTc0QUtXSGhG%0AUnljR1BnWWdRPQ%3D%3D%0A--8d175414180fa26417c64a24be19af93eb87ac52; path=/; HttpOnly` Beautiful, 'eh? Run that through a Base64 decode to see why this works. For Level 5, I set my session values to user='herp' and host='level05-2.stripe-ctf.com', and then I requested the page with some hand-crafted HTTP and `openssl s_client -connect level0X-2.stripe-ctf.com:443`. The server obliged. This bit of hackery works on both level 5 and level 6, and probably works on any of the earlier levels that used Ruby and Rack, but we solved those the right way and haven't bothered going back. **The Stripe guys have informed me that they are patching this vulnerability out, so if you are trying this and it no longer works, that would be why.**