An Initial Look at Web Exploit Development

By Aaron James – 

Introduction

While trying to learn penetration testing techniques, there have been a number of times I have tried to exploit a vulnerable software package in a lab environment, but was unable to find an appropriate exploit. There are other times I have found exploits, but they do not run. On top of this, they can be poorly commented, or the code is difficult to follow.

It is exploits like this, or the lack of exploits when there could be one that has interested me in developing exploits on my own. I would like to be able to come up with my own code from scratch, fix broken public ones, and finish proof-of-concept code.

I do believe this is a difficult skill to hone, and requires a great deal of time, energy, and thorough understanding of the underlying technologies. However, I also believe I will never acquire this skill if I do not start. So I have selected a vulnerability that does not have any exploit code or walkthrough available and see if I can duplicate the vulnerability and develop an working exploit for it.

Choosing a Vulnerability

I’ve chosen CVE-2016-5843, an SQL injection vulnerability in the Open Ticket Request System (OTRS) FAQ package 2.x before 2.3.6, 4.x before 4.0.5, and 5.x before 5.0.5. Mitre reports the vulnerability could be executed through “crafted search parameters”, SecurityFocus simply states “user-supplied input”, and Vuldb describes the attack vector as “the manipulation of the argument search with an unknown input.”

I selected this vulnerability in part because it is recent. I want to work on something that I feel will benefit the security community. While writing an exploit for an old vulnerability would help me learn, it would probably not see much practical application.

Another reason I chose this vulnerability is because it is an SQL injection, which seems like a simpler attack vector than other vulnerability types such as buffer overflows. At this point, simpler may be better when trying to learn the basics.

Setting Up The Environment

To start, I installed CentOS 7 minimal and OTRS 5 free, largely following this tutorial: http://complemento.net.br/en/2015/11/13/installing-otrs-5-0-on-centos-7-with-mariadbmysql-database/. This can be a fairly involved process, particularly if you are unfamiliar with RHEL or CentOS environments. The tutorial proved to be very useful.

I then installed the FAQ 5.0.3 package using these steps: http://itsm-demo.otrs.com/otrs/public.pl?Action=PublicFAQZoom;ItemID=240. This greatly helped while

In order to provide a better testbed for exploit development, it is probably a good idea to develop some content  within the application. This may help to gauge the impact of a successful exploitation. Once the application was installed and running, I created a single FAQ article with arbitrary data in the separate fields, along with several user accounts.

Identifying the Vulnerability

Now it is time to try and determine where the vulnerability exists. The changes from the vulnerable version to a non-vulnerable version can be found here:

https://github.com/OTRS/FAQ/commit/b805703e7b7725d1f3040bb626a4c4dd845ee9e3

Initially, we see the only modification to the CHANGES-FAQ.md file was the addition of the line “2016-06-27 Fixed issue with not correctly quoted search parameters.”, so we might be able to assume that all modifications in this commit are related to the vulnerability we are looking for.

The next block of code was added to the FAQSearch.pm file, lines 220 to 256. The function of that code that seems to be to check that several parameters are arrays. These parameters are then interated over and individually quoted. This seems to be a good indicator that the LanguageIDs, CategoryIDs, ValidIDs, CreatedUserIDs, and LastChangedUserIDs are vulnerable parameters.

# check types of given arguments
    ARGUMENT:
    for my $Key (qw(LanguageIDs CategoryIDs ValidIDs CreatedUserIDs LastChangedUserIDs)) {


        next ARGUMENT if !$Param{$Key};
        next ARGUMENT if ref $Param{$Key} eq 'ARRAY' && @{ $Param{$Key} };


        # log error
        $Kernel::OM->Get('Kernel::System::Log')->Log(
            Priority => 'error',
            Message  => "The given param '$Key' is invalid or an empty array reference!",
        );
        return;
    }


    # get database object
    my $DBObject = $Kernel::OM->Get('Kernel::System::DB');


    # quote id array elements
    ARGUMENT:
    for my $Key (qw(LanguageIDs CategoryIDs ValidIDs CreatedUserIDs LastChangedUserIDs)) {
        next ARGUMENT if !$Param{$Key};


        # quote elements
        for my $Element ( @{ $Param{$Key} } ) {
            if ( !defined $DBObject->Quote( $Element, 'Integer' ) ) {


                # log error
                $Kernel::OM->Get('Kernel::System::Log')->Log(
                    Priority => 'error',
                    Message  => "The given param '$Element' in '$Key' is invalid!",
                );
                return;
            }
        }
}

The next significant modification to this code is at line 444, where

my @States = map {$_} keys %{ $Param{States} };

is replaced with:

my @States = map { $DBObject->Quote( $_, 'Integer' ) } keys %{ $Param{States} };

return if scalar @States != keys $Param{States};

This seems like good evidence that the States parameter should be tested for our vulnerability as well.

The FAQSearch.t file is located in a directory called test, and seems to contain automated unit tests for the application. The added tests revolve around testing the States parameter for type, ensuring the parameter is a hash and not a float or a string.

So lets take a look. The url for the FAQ module is http://%5Bhost%5D/%5Botrs dir]/public.pl. This view provides a search box and an “Advanced Search” button that provides a form with more refined search parameters. Unfortunately, none of these are parameters we identified earlier.

Using the TamperData plugin in Firefox, we can see the parameters passed to the search function:

x1

Unfortunately, it is apparent that our vulnerable parameters are not included. Let’s check the advanced search form:

x2

This definitely looks better, except that our vulnerable parameters are still not present. We have been operating on the belief that this vulnerability is unauthenticated. This is because of the reporting – CVEDetails.com says of authentication: “Not required (Authentication is not required to exploit the vulnerability.)”, and VulDB.com lists: “Local: No / Remote: Yes”. Perhaps we should try an authenticated search to be sure.

After logging in, we are able to search the FAQ with the FAQ tab, and Search option. This provides a dynamic, customizable modal where we can include all of our vulnerable parameters:

x3

Capturing the form with TamperData provides us the opportunity to modify the parameter values:

x4

It appears at this point that this is an authenticated vulnerability and not an unauthenticated one. This makes it much less relevant to our purposes, especially since OTRS no longer ships with default credentials. It is possible, though, that I’ve missed something, as Perl-based web infrastructure is confusing and difficult to follow.

It may be worthwhile to see if an authenticated exploit can be developed, at any rate, and it seems we have finally exposed the sensitive parameters. But let’s look at the SQL statement that is constructed with the parameters:

my $SQL = 'SELECT i.id, count( v.item_id ) as votes, avg( v.rate ) as vrate  FROM faq_item i  LEFT JOIN faq_voting v ON v.item_id = i.id LEFT JOIN faq_voting v ON v.item_id = i.id  LEFT JOIN faq_state s ON s.id = i.state_id

Which eventually gets combined with the $Ext query at line 1020:

$SQL .= $Ext;

The $Ext, or extended SQL query, is constructed in the _InConditionGet subroutine in the TicketSearch.pm file. For the States parameter, the IDs and column names are combined into a string like this:

“ AND I.type_id in (1,2,3)”

So in order for us to feed malicious SQL into this, we might want to construct something like this:

AND I.type_id in (1) union all select 1,2,”this is a test”, into OUTFILE “/tmp/proof.txt”#%

x5

Conclusions

The coup d’etat would be to automate this into a single exploit which would be capable of writing a reverse shell to a readable location, which in itself might be more complicated than it initially seems. A location will need to be found that can be called from the web interface, is capable of executing Perl code, and is writable by the database. Additionally, this probably will have to be done with something like a curl command, which may be complicated by the odd design of this application. In order to reach this ideal state, a significant amount of work will have to be invested in continued development. While this is of significant interest, it may be leaving the scope of this blog post.

Overall, this has been an interesting and informative initial exposure to ad hoc exploit development, and is an area I intend to continue to pursue. While it certainly seems to be a difficult skill to hone, requiring investments in time and energy, it also is likely to be very rewarding.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s