Ejemplo n.º 1
0
        private bool ValidateNode(ElementWrapper node, InsertionsMap insertionsMap, ref RequestValidationParam dangerousParam)
        {
            var result = true;

            foreach (
                var element in node.Children.OfType<ElementWrapper>())
            {
                var elementStart = (int)element.StartPosition.offset;
                var elementEnd = (int)element.EndPosition.offset;

                foreach (
                    var insertionArea in
                        insertionsMap.Where(ia => ia.Includes(elementStart, elementEnd)))
                {
                    // Check if start position of node was included to insertions map
                    if (insertionArea.Includes(elementStart))
                    {
                        // Inclusion found (node was injected by request parameter)
                        dangerousParam = insertionArea.Param;
                        return false;
                    }

                    foreach (var attr in element.Attributes)
                    {
                        var attrNameStart = (int)attr.NameStart.offset;

                        if (insertionArea.Includes(attrNameStart))
                        {
                            // Inclusion found (attribute was injected by request parameter)
                            dangerousParam = insertionArea.Param;
                            return false;
                        }

                        var attrValueStart = (int)attr.ValueStart.offset;
                        var attrValueEnd = (int)attr.ValueEnd.offset;

                        // Skip if attribute value wasn't tainted by request parameter
                        if (!insertionArea.Includes(attrValueStart, attrValueEnd)) continue;

                        // Skip if attribute value passes validation
                        if (ValidateAttribute(attr.Name, attr.Value, insertionArea.Param.Value)) continue;

                        // Attribute value is dangerously tainted
                        dangerousParam = insertionArea.Param;
                        return false;
                    }
                }

                if (element.Tag == GumboTag.GUMBO_TAG_SCRIPT && element.Children.Any(child => child is TextWrapper))
                {
                    var text = element.Children.OfType<TextWrapper>().FirstOrDefault();

                    if (text != null)
                    {
                        // Validate javscript code inside <script /> tag
                        foreach (
                            var insertionArea in
                                insertionsMap.Where(
                                    ia =>
                                        ia.Includes((int) text.StartPosition.offset,
                                            (int) text.StartPosition.offset + text.Text.Length))
                                    .Where(insertionArea => !ValidateJavascript(text.Text, insertionArea.Param.Value)))
                        {
                            // Javascript code is dangerously tainted
                            dangerousParam = insertionArea.Param;
                            return false;
                        }
                    }
                }

                // TODO: Add integrity validation of style nodes here

                result &= ValidateNode(element, insertionsMap, ref dangerousParam);
            }

            return result;
        }
Ejemplo n.º 2
0
        public bool IsValidHtmlResponseString(List<RequestValidationParam> taintfulParams, string responseText, out RequestValidationParam dangerousParam)
        {
            dangerousParam = null;

            // HACK: Deny null-byte injection techniques. Perhaps, there are a better place and method to implement it.
            if (responseText.IndexOf('\0') != -1)
            {
                dangerousParam = new RequestValidationParam("null-byte", "Undefined", "...\\0");
                return false;
            }

            var parsedResponse = new GumboWrapper(responseText);

            if (!parsedResponse.Document.Children.Any()) return true;

            // Get boundaries for all occurences of request params in response text
            var insertionsMap =
                InsertionsMap.FindAllPrecise(
                    taintfulParams,
                    responseText);

            if (insertionsMap.Count == 0) return true;

            // In case of parse errors, needed a check that positions of errors isn't included to insertions map
            if (parsedResponse.Errors != null && parsedResponse.Errors.Any())
            {
                foreach (var error in parsedResponse.Errors)
                {
                    foreach (var insertionArea in insertionsMap)
                    {
                        if (!insertionArea.Includes((int) error.position.offset)) continue;

                        // Inclusion found (integrity of response has been violated by request parameter at error position)
                        dangerousParam = insertionArea.Param;
                        return false;
                    }
                }
            }

            // Deny obviously dangerous insertions
            foreach (var insertionArea in from insertionArea in insertionsMap
                let paramValue = insertionArea.Param.Value
                where
                    // paramValue ⊃ "<[A-Za-z%!/?]?"
                    paramValue.Where(
                        (t, i) =>
                            t == '<' && i < paramValue.Length - 1 &&
                            (
                                (
                                    (paramValue[i + 1] >= 'a' && paramValue[i + 1] <= 'z')
                                 || (paramValue[i + 1] >= 'A' && paramValue[i + 1] <= 'Z')
                                )
                             || paramValue[i + 1] == '%'
                             || paramValue[i + 1] == '!'
                             || paramValue[i + 1] == '/'
                             || paramValue[i + 1] == '?'
                            )
                        ).Any()
                select insertionArea)
            {
                dangerousParam = insertionArea.Param;
                return false;
            }

            var result = true;

            foreach (var node in parsedResponse.Document.Children.OfType<ElementWrapper>())
            {
                result &= ValidateNode(node, insertionsMap, ref dangerousParam);
            }

            return result;
        }