False Wordpress version detection

Hi all,

I’m having an issue with Wordpress Detection with a website that’s hidden some of the initial methods of wordpress detection in gb_wordpress_http_detect.nasl.

I can see that the nasl for this goes in order of the following:

  1. Searches / and /index.php for the version in the meta HTML tag: , then looks for the cache busting version number appended to wp=embed.min.js or twentyseventeen/style.css files.
  2. It then searches /wp-links.opml.php for the the same generator tag as above.
  3. Then the same with /feed.
  4. It then looks at /wp-login.php for the cache busting version tag. This is where I’m getting my incorrect match.
  5. Failing all of the above, it looks for a readme.html file to find the version string.

The nasl is picking up Wordpress version 3.7.1 from the below (it’s getting the jquery version), whereas the wordpress version is actually 6.5.5:

<script type="text/javascript" src="https://www.awordpresswebsite.com/wp-includes/js/jquery/jquery.min.js?ver=3.7.1" id="jquery-core-js"></script>

I’d have to assume I’m not alone in this case, and some tweaks to the detection down at step 4 might solve this for me and others.
Can I suggest a solution to this might be to add some more conditions in step 4, ahead of the current method.
My suggestions are to add two more - one to check for load-styles.php and if present, use the cache busting version tag that’s found, and if that’s not present look for one of the common styles in the login page, such as forms.min.css, l10n.min.css or login.min.css.

Here’s my idea in line with the current version of the nasl.

if( ( ! wpMuFound && ! wpFound ) || version == "unknown" ) {

  url = dir + "/wp-login.php";
  res = http_get_cache( item:url, port:port );

  if( res && res =~ "^HTTP/1\.[01] 200" &&
      concl = egrep( string:res, pattern:'(/wp-login\\.php\\?action=lostpassword|/wp-admin/load-|/wp-content/(plugins|themes|uploads)/|title="Powered by WordPress")', icase:FALSE ) ) {

    # Don't report WP installations on other servers
    if( "'/wp-login.php?action=lostpassword" >!< res && "/wp-admin/load-" >!< res ) {
      if( ! check_location( data:res ) )
        continue;
    }

    if( dir == "" )
      rootInstalled = TRUE;

    wpFound  = TRUE;
    version  = "unknown";
    conclUrl = http_report_vuln_url( port:port, url:url, url_only:TRUE );

    # Check for /wp-admin/load-styles.php and extract version
    vers = eregmatch( pattern:"/wp-admin/load-styles\\.php[^\\s]*\\?ver=([0-9]+\.[0-9.]+)", string:res );
    if( ! vers[1] ) {
      # If no match for /wp-admin/load-styles.php, check for /wp-admin/css/login.min.css
      vers = eregmatch( pattern:"/wp-admin/css/login\\.min\\.css[^\\s]*\\?ver=([0-9]+\.[0-9.]+)", string:res );
    }

    # If neither of the above matches, fall back to the original pattern match
    if( ! vers[1] ) {
      vers = eregmatch( pattern:"ver=([0-9]+\.[0-9.]+)", string:res );
    }

    if( vers[1] ) {
      version = vers[1];
      if( version + ", " >< checkduplicate )
        continue;

      checkduplicate += version + ", ";

      if( concluded )
        concluded += '\n';
      concluded = "  " + vers[0];
    }

    _concl_split = split( concl, keep:FALSE );
    foreach _concl( _concl_split ) {

      # Minor formatting change for the reporting
      _concl = chomp( _concl );
      _concl = ereg_replace( string:_concl, pattern:"^(\s+)", replace:"" );
      if( concluded )
        concluded += '\n';
      concluded += "  " + _concl;
    }
  }
}

Here are a few examples of the wp-login.php page that I think this approach will work with:

Here’s the wordpress v6.5.5 server that I’m having issues with:

<link rel='stylesheet' id='dashicons-css' href='https://www.anewishwordpressserver.com/wp-includes/css/dashicons.min.css?ver=6.5.5' type='text/css' media='all' />
<link rel='stylesheet' id='buttons-css' href='https://www.anewishwordpressserver.com/wp-includes/css/buttons.min.css?ver=6.5.5' type='text/css' media='all' />
<link rel='stylesheet' id='forms-css' href='https://www.anewishwordpressserver.com/wp-admin/css/forms.min.css?ver=6.5.5' type='text/css' media='all' />
<link rel='stylesheet' id='l10n-css' href='https://www.anewishwordpressserver.com/wp-admin/css/l10n.min.css?ver=6.5.5' type='text/css' media='all' />
<link rel='stylesheet' id='login-css' href='https://www.anewishwordpressserver.com/wp-admin/css/login.min.css?ver=6.5.5' type='text/css' media='all' />

Here’s the wordpress v6.6.1 server that I work with:

<link rel="stylesheet" id="dashicons-css" href="https://www.anewwordpressserver.com.au/wp-includes/css/dashicons.min.css?ver=6.6.1" type="text/css" media="all" />
<link rel="stylesheet" id="buttons-css" href="https://www.anewwordpressserver.com.au/wp-includes/css/buttons.min.css?ver=6.6.1" type="text/css" media="all" />
<link rel="stylesheet" id="forms-css" href="https://www.anewwordpressserver.com.au/wp-admin/css/forms.min.css?ver=6.6.1" type="text/css" media="all" />
<link rel="stylesheet" id="l10n-css" href="https://www.anewwordpressserver.com.au/wp-admin/css/l10n.min.css?ver=6.6.1" type="text/css" media="all" />
<link rel="stylesheet" id="login-css" href="https://www.anewwordpressserver.com.au/wp-admin/css/login.min.css?ver=6.6.1" type="text/css" media="all" />

Here’s the css loading for a wordpress v4.5.32 server that I work with which uses load-styles.php:

<link rel='stylesheet' href='https://anolderwordpresswebsite.com.au/wp-admin/load-styles.php?c=0&amp;dir=ltr&amp;load%5B%5D=dashicons,buttons,forms,l10n,login&amp;ver=4.5.32' type='text/css' media='all' />