Back to Repositories

Testing WordPress User Enumeration via XML Sitemaps in WPScan

This test suite validates the WordPress user enumeration functionality through XML sitemaps in WPScan. It focuses on testing the AuthorSitemap finder class which extracts usernames from sitemap responses.

Test Coverage Overview

The test suite covers user enumeration through WordPress XML sitemaps with comprehensive scenarios.

  • Tests empty and non-XML responses
  • Validates parsing of sitemap files with and without usernames
  • Verifies user data extraction including username, confidence level, and entry tracking
  • Handles edge cases like missing or malformed XML responses

Implementation Analysis

The implementation uses RSpec’s describe/context pattern for structured test organization. It leverages stub_request for HTTP mocking and fixtures for test data.

Key patterns include:
  • Subject/let block setup for test isolation
  • Shared context for common setup
  • Behavior-driven specs with descriptive contexts
  • Fixture-based test data management

Technical Details

Testing stack includes:

  • RSpec for test framework
  • WebMock for HTTP request stubbing
  • File fixtures for XML test data
  • Custom matchers for response validation
  • Before hooks for test setup
  • Subject/let patterns for object initialization

Best Practices Demonstrated

The test suite demonstrates strong testing practices through isolated, focused test cases. It shows proper use of RSpec features and maintainable organization.

  • Clear test case organization and naming
  • Proper test isolation and setup
  • Comprehensive edge case coverage
  • Effective use of fixtures and stubs
  • Descriptive failure messages

wpscanteam/wpscan

spec/app/finders/users/author_sitemap_spec.rb

            
# frozen_string_literal: true

describe WPScan::Finders::Users::AuthorSitemap do
  subject(:finder) { described_class.new(target) }
  let(:target)     { WPScan::Target.new(url) }
  let(:url)        { 'http://wp.lab/' }
  let(:fixtures)   { FINDERS_FIXTURES.join('users', 'author_sitemap') }

  describe '#aggressive' do
    before do
      allow(target).to receive(:sub_dir).and_return(false)

      stub_request(:get, finder.sitemap_url).to_return(body: body)
    end

    context 'when not an XML response' do
      let(:body) { '' }

      its(:aggressive) { should eql([]) }
    end

    context 'when an XML response' do
      context 'when no usernames disclosed' do
        let(:body) { File.read(fixtures.join('no_usernames.xml')) }

        its(:aggressive) { should eql([]) }
      end

      context 'when usernames disclosed' do
        let(:body) { File.read(fixtures.join('usernames.xml')) }

        it 'returns the expected array of users' do
          users = finder.aggressive

          expect(users.size).to eql 2

          expect(users.first.username).to eql 'admin'
          expect(users.first.confidence).to eql 100
          expect(users.first.interesting_entries).to eql ['http://wp.lab/wp-sitemap-users-1.xml']

          expect(users.last.username).to eql 'author'
          expect(users.last.confidence).to eql 100
          expect(users.last.interesting_entries).to eql ['http://wp.lab/wp-sitemap-users-1.xml']
        end
      end
    end
  end
end