Bugtraq mailing list archives
Adcycle 0.78b Authentication
From: Neil K <neilk () ALLDAS DE>
Date: Mon, 19 Feb 2001 12:04:44 -0000
|---------------------------------------------------------------------------------| / 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 (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&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->get_cookie; my $datestamp=$env->get_datestamp; my $admin_user_name=$config->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 - joe () ispsoft de 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 (neil () alldas de/neilk () alldas de) www.alldas.de "I'm always Frank and Ernest with the ladies, Frank in New York, Ernest in Boston" --quoted from some film i watched last night
Attachment:
exploit.pl
Description:
Current thread:
- Adcycle 0.78b Authentication Neil K (Feb 19)
- Re: Adcycle 0.78b Authentication Dag-Erling Smorgrav (Feb 20)
- <Possible follow-ups>
- Re: Adcycle 0.78b Authentication Kenneth van Grinsven (Feb 20)