XSS scripting for Search textbox
Asked Answered
B

5

6

I have a textbox which is used for searching the data within the site. What my client wants that,

1)Enter any text in the search field and click the search symbol.

2)The request going to the server using a web proxy tool like "Burp"

3)Append the parameter with the script present as

test<~script>confirm(123)<~/script>

what happens here is

The XSS script entered by the advesary gets reflected in the response without any input. Please see the image below you will get an idea:-

![enter image description here][1]

Guys, let me know if you need any more information related to it. Please help guys, Any help would be appreciated. I want to stop the attack from server side.

HTML and JS code:-

  <asp:TextBox ID="txtSearch" runat="server" class="txtfld-search" oncopy="return false" oncut="return false" onpaste="return false"></asp:TextBox>

JS code:-

<script type="text/javascript">
$(document).ready(function () {
    $('#ctl00_topNavigation_txtSearch').keyup(function () {
        var $th = $(this);
        $th.val($th.val().replace(/[^.%a-zA-Z0-9 ]/g,
        function (str) {
            alert('Special characters not allowed except %');
            return '';
        }));
    });
});

Also see the code behind:-

protected void btnSearch_Click(object sender, ImageClickEventArgs e)
{
    Response.Redirect("search.aspx?tx=" + txtSearch.Text);
}

Also, see the code for the searching part:-

private void SearchResult()
{
    DataTable dt;

    if (Session["Search"] == null)
    {
        ResXResourceReader reader = new ResXResourceReader(Server.MapPath("~/App_GlobalResources/Strings.en-US.resx"));
        IDictionaryEnumerator id = reader.GetEnumerator();
        string sResourceFile = Server.MapPath("~/App_GlobalResources/Strings.en-US.resx");
        XmlDocument xmlResource = new XmlDocument();
        xmlResource.Load(sResourceFile);

        XmlNodeList elmData = xmlResource.SelectNodes("//root/data");

        dt = new DataTable();
        dt.Columns.Add(new DataColumn("ID", System.Type.GetType("System.String")));
        dt.Columns.Add(new DataColumn("Title", System.Type.GetType("System.String")));
        dt.Columns.Add(new DataColumn("Description", System.Type.GetType("System.String")));
        dt.Columns.Add(new DataColumn("Url", System.Type.GetType("System.String")));
        dt.Columns.Add(new DataColumn("Link", System.Type.GetType("System.String")));

        foreach (XmlElement element in elmData)
        {
            DataRow dr = dt.NewRow();
            dr["ID"] = element.GetAttribute("name");
            //dr["Title"] = element.GetAttribute("name");
            XmlNodeList sDescription = element.SelectNodes("value");
            dr["Title"] = sDescription.Count > 0 ? sDescription.Item(0).InnerText : string.Empty; ;
            dr["Description"] = string.Empty;
            XmlNodeList sUrl = element.SelectNodes("comment");
            if (sUrl.Count > 0)
            {
                Int32 sPgTitle = sUrl.Item(0).InnerText.LastIndexOf(".") + 1;
                if (sPgTitle > 0)
                {
                    dr["Url"] = sUrl.Item(0).InnerText;
                    //dr["Url"] = Request.Url.Host.ToLower() + "/rbank/" + sUrl.Item(0).InnerText;
                    dr["Link"] = string.Empty;
                }
                else
                {
                    dr["Link"] = sUrl.Item(0).InnerText;
                }
                dt.Rows.Add(dr);
            }
        }
        //foreach (DataRow dr in dt.Rows)
        //{
        //    DataRow[] rDesc = dt.Select("Link <> ''");
        //    for (int i = 0; i < rDesc.Length; i++)
        //    {
        //        DataRow[] rTitle = dt.Select("ID = '" + rDesc[i]["Link"] + "'");
        //        if (rTitle.Count() > 0)
        //        {
        //            rTitle[0]["Description"] = rDesc[i]["Title"];
        //        }
        //    }
        //}

        DataRow[] drDelete = dt.Select("Link <> ''");
        foreach (DataRow drCheck in drDelete)
        {
            dt.Rows.Remove(drCheck);
        }
        dt.TableName = "FilterValues";
        reader.Close();
        Session["Search"] = dt;
    }
    else
    {
        dt = Session["Search"] as DataTable;
    }
    DataView dv = new DataView();
    dv.Table = dt;
    **dv.RowFilter = "Description LIKE ('%" + Request.QueryString["tx"].Trim().ToLower() + "%') or Title LIKE ('%" + Request.QueryString["tx"].Trim().ToLower() + "%')";**
    dv.Sort = "Title ASC";

    dgrdPages.DataSource = dv;
    dgrdPages.DataBind();

    lblSearchWords.Text = Request.QueryString["tx"].Trim();
    lblFilesFound.Text = dv.Count.ToString();
}

I found that dv.RowFilter can be given as some SQL Injection like that. I want to prevent that. Please help.

Bicarbonate answered 13/11, 2014 at 7:28 Comment(3)
You are showing the request being made not the response. I think you need to encode the output appropriately in the response, so that the script does not execute when it's written to the page. Can you add details on the response (including code) to demonstrate the problem?Solidify
@geedubb: How to encode the output, please give me some tips or help. How to stop so that the script does not get executed. Also see the edited question for more detailsBicarbonate
To encode a string you can use the HttpUtility.HtmlEncode method (msdn.microsoft.com/en-us/library/…)Massenet
E
3

As mentioned by other friends clientside code can easily be neglected. So we can translate what you have done with javascript into c# like this with an addition of mine which is to remove extra spaces and merge them into one:

if (Regex.IsMatch(txtSearch.Text, "[^a-zA-Z0-9 %]"))
            {
                //error
                Response.Redirect("Error.aspx?tx=It's a Shame Dude!");
            }
            else
            {
                //Remove multiple spaces
                String ClearSpaces = Regex.Replace(txtSearch.Text, @"\s+", " ");
                Response.Redirect("search?tx=" + HttpUtility.UrlEncode(ClearSpaces));
            }

Not to forget, the regex is coming from: this answer. And the regex for replacing multiple spaces is coming from this answer.

Experientialism answered 30/1, 2015 at 11:26 Comment(2)
Yes, Exaclty..That was the main issue..Thanks a lot @wooer, it is working perfectly..+1 for you patience and going step by step to resolve this..!!Bicarbonate
Please notice that this solution is not complete. If the search page itself is not HTML encoding as I suggested, this vulnerability might still take place: example.com/search.aspx?tx=test<script>confirm(123)</…>Ministrant
M
2

There are several problems with your code: Lack of input validation, lack of output encoding, Row-filter injection and lack of understanding the concept of client\Javascript validation.

Lets discuss it one by one:

  1. The lack of input validation: All of the attacks and problems that I've mentioned above can be fixed using proper input validation. By proper I mean white-list based, and not black-list. You should never search for special characters such as apostrophe or LT\GT, always look check the positive white list way like you did in your Javascript, and look for the permitted values and not non-permitted ones. This is done because an attacker can always outsmart the programmer and encode his exploit in different ways. As mentioned by others, ValidateRequest does perform some level of input validation but it can never be trusted as the single solution as there are ways to bypass it. Please don't try to search for different exploits such as <script as others suggested, this can be easily bypassed (for example: <img onmouseover=alert(1)> instead of your payload) and is a bad practice.
  2. lack of output encoding: The reason why your code is actually vulnerable is this line:

    lblSearchWords.Text = Request.QueryString["tx"].Trim();
    

    You need to HTMLEncode any values that were originated from the user before integrating them inside labels. For example:

    lblSearchWords.Text = HttpUtility.HtmlEncode(Request.QueryString["tx"].ToString());
    

    This ensures that any HTML-related characters are encoded to their non executable values.

  3. Row-filter injection: This row here is actually vulnerable to row-filter injection, not SQL Injection:

    dv.RowFilter = "Description LIKE ('%" + Request.QueryString["tx"].Trim().ToLower() + "%') or Title LIKE ('%" + Request.QueryString["tx"].Trim().ToLower() + "%')";
    

    As you probably know, the syntax is SQL based but there is no DB in this case, just row filtering mechanism that is vulnerable to injection attacks. This injection is a low-severity issue as it doesn't allow an attacker to do much (not like command execution in real SQL Injection), but if your end user shouldn't be able to see all of the rows of the table, this is a security issue. There is not parametrized-queries like mechanism to prevent injection here such as in SQL Injection as I know of, but enforcing a thorough input validation as mentioned in section 1 and the next section, would solve this issue as well.

  4. Lack of understanding the concept of client\Javascript validation: Client side validations of any kind are nice-to-have and cannot be trusted. Whoever showed you this technique demonstrated exactly the reason why. Any client side validation can always be bypassed very easily by any proxy utility (Burp, Fiddler, Paros etc.) and even using your browser debugger or plugins (Press F12 to activate the debugger, Firefox's Firebug is one example of such a plugin that enhance the default debugger). To trust only cliet-side validation is like giving your house keys to a stranger asking him to check if anyone suspicious is trying to break in, or hiding your keys under the welcome-mat. You cannot trust this as your only defense. The only actual purpose of client-side validation is to prevent the round-trip to the server and to make your user's experience better. You should implement the same white-list based validation you created in your JS, in your server side code as well. Always remember: Server side validation - mandatory, client side validation - nice to have.

Hopes it helps.

Ministrant answered 20/1, 2015 at 22:15 Comment(9)
hi Gil, Thanks for the explanation. Could we go one by one to resolve this ?Bicarbonate
Yes no problem. I gave some code examples for #2, but the rest is not that difficult as wellMinistrant
Ok, If you dont mind.can you come on chat..chat.stackoverflow.com/rooms/69189/…Bicarbonate
It doesn't let me add anything. But anyway, first try changing the row I wrote at #2 and tell me if it helpedMinistrant
OK, will change and let you know.!!Bicarbonate
hey, are you there. I have one issueBicarbonate
I tried with your code, but still i am unable to stop that. It is still bypassing that.Bicarbonate
Sorry for the delay, have you fixed it yet?Ministrant
Take a look at what I wrote above as a response to the solution, the solution might not be complete and your code might still be vulnerable.Ministrant
L
0

As with any value provided by a user you need to be escape the value when it is presented on the page.

Update search.aspx to use HttpUtility.HtmlEncode(tx) in any place that the value passed as the tx parameter is emitted.

OWASP provide some good guidance about how to protect against XSS vulnerabilities like this. https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet

Libyan answered 21/11, 2014 at 15:43 Comment(1)
I tried with that one it is not working, Please see the updated code for referenceBicarbonate
A
0

If you are keen on securing your site then the best thing to do is enable request validation on page:

<@ Page validateRequest="true" %>

Follow the link if you want to enable is across your site:

http://msdn.microsoft.com/en-us/library/hh882339(v=vs.110).aspx

If you want to go on with a more lienient check then encoding the data before displaying on the web page would be fine.

You can also download Microsofts AntiXss library from http://www.microsoft.com/en-us/download/details.aspx?id=28589. This would enable you to secure your site as and for what you want.

Hope this helps.

Almire answered 16/1, 2015 at 14:33 Comment(1)
Shashank, your <@ Page validateRequest="true" %> is what I have already tried. But it was not working. Can you help me how to download and use in my project. ? As I am unaware of this.Bicarbonate
M
-1

It seems to me that you have two options here. The first is to parse out dangerous searches client side in your jQuery code before sending this text input to the server. I'm not sure exactly what you'd be looking for, but I assume you want to stop the user from sending specific things in your search bar.

A good way to prevent this would be to search for specific things in their search. For example, you could wrap the function to send the search to the server in an if statement like so(sorry for pseudocode):

if(txtinput.indexOf('<script>') === -1 && ...more checks...){
   // send input to server
}

These if statements could be chained so you can check for any XSS issues before actually sending it to the server. That said, this approach isn't very appealing from a systems design perspective. Like you said, the better approach is to do this server side. I'm not particularly familiar with .NET backends, but based on the code you included, I imagine you could parse your txtSearch.text server-side. This would look similar to the answer above. Essentially, you would only redirect to that link if their text input meets certain conditions.

Unfortunately, I'm not extremely familiar with string parsing and validating in .NET, so I can't give you the code, but it should look something like this, assuming you've written and isValid function.

if(isValid(txtSearch.txt)){
   Response.Redirect("search.aspx?tx=" + txtSearch.Text);
} else {
   // Send Error code in response
}

I hope this helps a bit!

Music answered 20/11, 2014 at 18:53 Comment(3)
re: the first bit of code - everything you think you can blacklist (eg <script>) a dedicated hacker will get around.Jockey
@Jamiec: Can you help me to avoid that. It's getting serious and tough.Bicarbonate
Note that you've listed wrong options - it is either "JavaScript + Server side" or "Server side only".Flood

© 2022 - 2024 — McMap. All rights reserved.