Lucene search

K
securityvulnsSecurityvulnsSECURITYVULNS:DOC:1301
HistoryFeb 20, 2001 - 12:00 a.m.

Adcycle 0.78b Authentication

2001-02-2000:00:00
vulners.com
15

|---------------------------------------------------------------------------------|
/ Product: Adcycle Banner Rotation.
\ Vendor URL: www.adcycle.com
/ Tested on: v0.77 - 0.78b [Freeware] Linux
\ Vendor Contact: Mailed on 15th January [i think] Twice with NO
reply \
/ Other: Commericial version NOT tested
\

– First Off,
                those who frequent www.alldas.de will know the

general outlay
of the site (see credits), and possible the fact that we (don't)run
this script. It
was an extreme bout of bordom and quite frankly moreover essential
to check
this script since we (used to)run it. NEVER trust a script cos
others use it anyway…

– The Problem,
                over the last few months a few ppl have come

forward with posts
that demonstrate or exploit various vulnerabilities in Perl/PHP
scripts use of SQL
based queries. Early this year some time in January when i looked at
adcycle i
found many of these problems, but never really tried to exploit them
probably
because i couldn't be arsed until now…

-Overview,
during the setup of adcycle using the ominous
build.cgi, it creates several
tables by default these are:

mysql> show tables;
±------------------+
| Tables_in_adcycle |
±------------------+
| ad
| adconfig
| banners
| counter
| cp <= stores banner info etc.
| dailylog
| iplog
| login <= stores login info
| pools
| real_log
±------------------+
10 rows in set (0.00 sec)

When a user logs into the script and authentication takes place
successfully, their
data is entered into the login table:

$sth = $dbh->do("INSERT INTO login
$sth = $dbh->(remote,aid,pid,agent,stime,erase) VALUES ($log_list)");

the resulting table looks like this:

mysql> select * from login;
±------------±------±----------±-------------------------------------±---------------------+
| remote | aid | pid | agent
| stime
±------------±------±----------±------------------------------------------------------------+
| 169.254.0.2 | ADMIN | 8983632| Mozilla/4.76 [en] (U; Linux 2.4
i686) | 2001-02-16 06:48:48|
| 169.254.0.2 | ADMIN | 816479 | Mozilla/4.76 [en] (U; Linux 2.4
i686) | 2001-02-16 06:48:47|
±------------±------±----------±-------------------------------------±---------------------+
2 rows in set (0.00 sec)

-/Overview

Ok on with the problem, unfortunately there is no way to avoid the
authentication
of the script, but i might be able to get around it :). Cutting the
bull from the
*useful SQL queries in the script you will find:

AdLibrary.pm:
sub db_login() {
==>
if($verify==0){
$FOUND=0;
$sth = $dbh->prepare("SELECT * FROM login WHERE
remote='$remote' && agent='$agent' ORDER BY stime DESC");
$sth->execute;
while(@login = $sth->fetchrow_array){
if(length($login[1])>1){
$verify=1;
$whoami=$login[1];
$pid=$mixer;
}
}
$sth->finish();
}
<==
}

Well as you can see this piece of code handles the fact that the
user may have
already logged in using a valid username/passwd combination. And
therefore
should not have to enter his/her username and password again to use
the script.
Cos well that would be a total pain the arse wouldn' tit?. This
clause is epecially
useful to us since we don't really know a valid user/pass
combination.

Anyway whats interesting abt the above u might ask?? well the use of
$agent in
the SQL query is most interesting since this data is user defined.
Not *very easily
but it can be user defined given the right circumstances.
Concidering that we now
literally 0wn that SQL query given a little thought we could easily
get around the
authentication and do whatever we wanted :). How?? well by changing
the agent
field of the http request to:

$agent = Mozilla' || aid='ADMIN

Thus changing the query to:

SELECT * FROM login WHERE (remote='127.0.0.1' && agent='Mozilla') ||
aid='ADMIN' ORDER BY stime DESC
^
^ ^

brackets show 'logic bounds' username wanted

As you can see executing that query would return all records with
aid=ADMIN
very useful since from the original Perl code above would yeild
$whoami=ADMIN.
Furthermore since the authentication routine is used in every call
to the script
it is possible to execute any command that a normal ADMIN adcycle
user would
be able to. Which is well… everything, changing banners,
advertisers etc…

Of course as you've probably guessed by now, this example assumes
that the admin
user is actually 'admin' as it is by default. And also the presence
of a record with
aid='ADMIN' which unfortunately can only be present if the admin is
either currently
logged in or has been logged in and not logged out. This is not that
hard actually if
you've used this script seriously you'd know this to be true. I
myself have never
logged out of a hotmail account let alone clicked the word 'logout'
written in size 6-8
miniature text at the bottom of a browser.

–As an after thought, requesting:
http://www.server.com/cgi-bin/adcycle/adcenter.cgi?task=purge_log&amp;who=user

will result in the login table having all contents with aid=user
deleted from it, therefore
logging that user out of the script requiring them to log back in.
Could be useful maybe?

If anyone comes up with a more efficient way to subvert
authentication on this script
then mail me :),
/–

– Exploit,
            to better demostrate this problem i have included a

small perl script sploit
that will alter banner images, some alteration maybe needed for it
to werk but hey it
worked for me?!?.

– Solution,
            well considering that i have yet to get a response

from adcycle after 4
weeks?, says quite alot if you ask me. Possible because this script
is freeware it ain't
supported?. Well to say the least that sux real hard in my mind…

Anyways how to patch?? well you could parse out the following
character from *all
the user defined fields: '.

Here are the alterations to the script:

AdLibrary.pm:
sub db_login {
=>
my $agent=$env->get_agent;

  • while($agent =~ s/'// !=0 ){}
my $cookie=$env-&gt;get_cookie;
my $datestamp=$env-&gt;get_datestamp;
my $admin_user_name=$config-&gt;get_admin_user_name;

=>
if($verify==0){
my($trash,$mycookname,$mycookpid)=split(/\!\!/,$cookie);

  • while($mycookpid =~ s/'// !=0 ){}

=>
$FOUND=0;
$sth = $dbh->prepare("SELECT * FROM login WHERE pid='$mycookpid'
&& agent='$agent' ORDER BY stime DESC");
$sth->execute;
while(@login = $sth->fetchrow_array){
if(length($login[1])>1){
$verify=1;
$whoami=$login[1];
$pid=$mycookpid;
}
}
$sth->finish();
}
<=
}

Pls note this is a Hotfix and your script should be updated when
(if) adcycle update
theirs.

– Credits,
    domz    -    designed and created alldas.de has mad

html+PHP+infinitum
skillz. In process of coding a new
banner rotation script…
mjm - @gmc-online.de, long time no speak.
Jochen Wiedmann - [email protected] for not allowing
multiple queries
on a single line, the
TRUE saviour of all PHP and
Perl programmers who
write scripts that use MySQL.
m8's @ werk where i finally quit after 3.5 years :-).
all @ alldas.de, there sooo many i can't list them here!

   Thanks to rfp for a most *interesting* article abt PHP-Nuke

which prompted
me to get off me arse and write this :-).


NeilK ([email protected]/[email protected])
www.alldas.de

         &quot;I&#39;m always Frank and Ernest with the ladies,
                Frank in New York, Ernest in Boston&quot;
                            --quoted from some film i watched

last night