Project

General

Profile

Bug #197

Issues with ThreatScript saving of arrays

Added by Luke Murphey over 13 years ago. Updated over 13 years ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
-
Target version:
Start date:
09/25/2010
Due date:
% Done:

100%


Description

Current issues are:
  1. System loads values multiple times, it may not be deleting old items correctly
  2. System cannot load some values, saying it is not serializable though it implements the Serializable interface

History

#1 Updated by Luke Murphey over 13 years ago

The root cause has been identified:

The ScriptDefinition class is serializing objects as arrays containing NativeJavaObject's. This must be unwrapped to the original object in order to be serialized correctly. The fix is to have the environment class convert the NativeArray object to an Object array and unwrap each NativeJavaObject contained within.

#2 Updated by Luke Murphey over 13 years ago

  • Status changed from New to In Progress
  • Assignee set to Luke Murphey
  • Target version set to 1.0.1

#3 Updated by Luke Murphey over 13 years ago

One problem that has become apparent is that the ScriptDefinitions deserialize object arrays as basic arrays that do not include the push and pop functions that the JavaScript arrays include. Therefore, the array that is deserialized must be converted into a JavaScript array manually in order to call push and pop.

#4 Updated by Luke Murphey over 13 years ago

The .SuspiciousContent.Cross_Domain_Scripting was modified to support the saving of script domains. Below is an updated script that is confirmed as working with the new script engine changes. Note that the baseline function converts the array into a native Javascript array in order to call push and pop.

/*
 * Name: Audit.SuspiciousContent.Cross_Domain_Scripting2
 * Version: 4
 * ID: 1000216
 * Message: Reference to a client-side script residing on a separate domain
 * Severity: Low
 * Reference: url, ha.ckers.org/xss.html
 * Reference: url, en.wikipedia.org/wiki/Cross-site_scripting
 */

importPackage(Packages.ThreatScript);
importPackage(Packages.HTTP);

function stripSubDomain( domain ){
    var re = /([0-9A-Z_.]+\.)?([0-9A-Z_]+\.[0-9A-Z_]+)/i;
    matches = re.exec(domain);
    var result = null;
    if( matches == null ){
        result = domain.toLowerCase();
    }
    else{
        result = matches[matches.length - 1].toLowerCase();
    }

    //Make sure the result is not an empty string
    if( StringUtils.trim(result).length() == 0){
        return null;
    }

    return result;
}

function isInList( domain, scriptdomains ){

    if( scriptdomains == null ){
        return false;
    }

    for( i in scriptdomains ){
        if( scriptdomains[i] == domain){
            return true;
        }
    }

    return false;
}

function analyze( httpResponse, variables, environment ){

    //Get the existing scripts that have been accepted
    var acceptedScripts = environment.get("ApprovedScriptDomains");

    if( acceptedScripts != null ){
        acceptedScripts = acceptedScripts.getValue();
    }

    var parser = httpResponse.getDocumentParser();
    var location = new URL( httpResponse.getLocation() );
    var localhost = stripSubDomain( location.getHost() );
    var domainScripts = [];

    //Get a list of all script tags
    var tagNameFilter = new TagNameFilter("script");
    var nodesList = parser.extractAllNodesThatMatch(tagNameFilter); 

    //Analyze each script tag to determine if any have a non-local script reference
    for( var c = 0; c < nodesList.size(); c++ ){

        var tag = nodesList.elementAt(c);
        var src = tag.getAttribute("src");

        if (src != null){
            try{
                var domainScript = new URL( location, src );

                domainScript = stripSubDomain( domainScript.getHost() );

                //Determine if the URL is absolute and ensure that the location is local
                if( domainScript != null && domainScript != localhost ){

                    if( isInList(domainScript, acceptedScripts) == false && isInList(domainScript, domainScripts) == false ){
                        domainScripts.push( domainScript );
                    }
                }
            }
            catch(e){
                /*
                 * Ignore this exception, this can occur when the HTML is malformed. A malformed script
                 * source tag shouldn't be followable and therefore should not be a threat.
                 */
            }
        }
    }

    // Alert that a cross-domain script was discovered
    Debug.sendMessage( "domainScripts.length=" + domainScripts.length );
    if( domainScripts.length > 0 ){
        var desc = null;
        var changed = false;

        // Get the list of scripting domains that have been discovered already
        var discoveredScripts = environment.get("DiscoveredScriptDomains");

        if( discoveredScripts != null ){
            discoveredScripts = discoveredScripts.getValue();
        }

        if( discoveredScripts == null ){
            discoveredScripts = [];
        }

        for( i in domainScripts ){
            if ( desc == null ){
                desc = domainScripts[i];
            }
            else{
                desc = desc + ", " + domainScripts[i];
            }

            //Add the script to the discovered scripts list
            if( isInList( domainScripts[i], discoveredScripts ) == false ){
                discoveredScripts.push(domainScripts[i]);
                changed = true;
            }
        }

        // Save the list of discovered script domains (if changed)
        if( changed && discoveredScripts != null ){
            environment.set("DiscoveredScriptDomains", discoveredScripts, false);
        }

        return new Result( true, "Cross domain scripts discovered: " + desc );
    }

    return new Result( false, "No cross domain scripts detected" );
}

function baseline( environment ){

    // Get the list of scripting domains that have been discovered already
    var discoveredScripts = environment.get("DiscoveredScriptDomains");

    if( discoveredScripts == null ){
        return true;
    }
    else{
        discoveredScripts = discoveredScripts.getValue();
    }

    if( discoveredScripts == null ){
        return true;
    }

    // Get the list of domains that have been aproved for scripting
    var approvedScripts_old = environment.get("ApprovedScriptDomains");
    var approvedScripts = [];

    if( approvedScripts_old != null ){
        approvedScripts_old = approvedScripts_old.getValue();
    }

    if( approvedScripts_old != null ){
        for( i in approvedScripts_old){
            approvedScripts.push(approvedScripts_old[i]);
        }
    }

    // Update the list of approved scripting domains
    for( i in discoveredScripts ){
        if( isInList(discoveredScripts[i], approvedScripts) == false ){
            approvedScripts.push(discoveredScripts[i]);
        }
    }

    // Save the approved scripting domains
    environment.set("ApprovedScriptDomains", approvedScripts, false);

    // Clear the discovered script domains
    environment.remove("DiscoveredScriptDomains");

    return true;
}

#5 Updated by Luke Murphey over 13 years ago

  • Status changed from In Progress to Closed
  • Target version changed from 1.0.1 to 1.0 (Release)
  • % Done changed from 0 to 100

Also available in: Atom PDF