http://www.perlmonks.org?node_id=661665

Nik has asked for the wisdom of the Perl Monks concerning the following question:

Hello monks,

When someone visits my webpage at http://nikos.no-ip.org i log to database his ip address, time and date of the visit, what article he chosed to see from my popup menu and how many times the same ip address visited my page.

Today i saw somethign really awkward, i saw in the log an entry looking like above among other normal entries.:

crawl-66-249-67-210.googlebot.com 09 Jan, 20:09 item_from_drop +_down_menu 3 zeep.ldc.upenn.edu 07 Jan, 21:29 Θανά&#963 +;ιμα αμαρτήμα& +#964;α 5
This automated crawl bot of google's visited from the same ip address my page for the 3rd time and its last selection of param('select') is named "item_from_drop_down_menu"!!!!!

How is this possible to even be there? i only log valid selections that exist in my popup menu and of course i dont have an entry like the above.Here is my code that does the logging:

my @files = glob "$ENV{'DOCUMENT_ROOT'}/data/text/*.txt"; my @menu_files = map m{([^/]+)\.txt}, @files; Encode::from_to($_, 'ISO-8859-7', 'utf8') for @menu_files; print header( -charset=>'utf8' ); my $article = param('select') || "&#913;&#961;&#967;&#953;&#954;&#942; + &#931;&#949;&#955;&#943;&#948;&#945;!"; if ( param('select') ) { #If user selected an item from the drop dow +n menu unless( grep /^\Q$article\E$/, @menu_files ) #Unless user selectio +n doesn't match one of the valid filenames within @menu_files { if( param('select') =~ /\0/ ) { $article = "*Null Byte Injection* attempted & logged!"; print br() x 2, h1( {class=>'big'}, $article ); } if( param('select') =~ /\.\.\// ) { $article = "*Backwards Directory Traversal* attempted & logge +d!"; print br() x 2, h1( {class=>'big'}, $article ); } $select = $db->prepare( "UPDATE guestlog SET article=?, date=?, +counter=counter+1 WHERE host=?" ); $select->execute( $article, $date, $host ); exit 0; } Encode::from_to($article, 'utf8', 'ISO-8859-7'); #Convert user sel +ected filename to greek-iso so it can be opened open FILE, "<$ENV{'DOCUMENT_ROOT'}/data/text/$article.txt" or die $ +!; local $/; $data = <FILE>; close FILE; Encode::from_to($article, 'ISO-8859-7', 'utf8'); #Convert user sel +ected filename back to utf8 before inserting into db $update = $db->prepare( "UPDATE guestlog SET article=?, date=?, cou +nter=counter+1 WHERE host=?" ); $update->execute( $article, $date, $host ) }
As you can see no other entry except the valid ones can pass the if and unless code blocks and then get inserted into the db.
Can you explain such an entry? You can see this your self by clickign on your ip address shown bottom down on my webpage.

Replies are listed 'Best First'.
Re: Weird entry index my guestlog
by moritz (Cardinal) on Jan 10, 2008 at 17:33 UTC
    Let me emphasize that any user agent is free to send any HTTP request to your server - for example they can send POST and GET parameters that appear nowhere on your page, values that appear in no drop down list, and they can query URLs that are nowhere linked.

    If you don't know this, you might have many security holes in your scripts.

      If you don't know this, you might have many security holes in your scripts.

      Fixed (considering the referent in question's demonstrated grasp of programming).

      The cake is a lie.
      The cake is a lie.
      The cake is a lie.

Re: Weird entry index my guestlog
by dragonchild (Archbishop) on Jan 10, 2008 at 17:25 UTC
    You're assuming that all requests are coming from your webpage. Have you tried using Test::WWW::Mechanize to hit your server directly with requests that contain bad values?

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
      Can you show me how to start this automated process of testing index.pl for possible security threats?
        • Write some tests to verify that things work as you think they should.
        • Identify potential security threats.
        • Write a test for each one.
        The process isn't very difficult once you get started. I suspect, though, that, given your history, you're not going to do much research on your own and, instead, are going to ask a bunch of questions here and not really work hard at getting to the meat of the answers. Honestly, if I were in your shoes, I would hire someone to do the work and you look over their shoulder. That way, it gets done properly and you have a reference implementation to look back at when you go to your next project.

        My criteria for good software:
        1. Does it work?
        2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: Weird entry index my guestlog
by CountZero (Bishop) on Jan 10, 2008 at 18:22 UTC
    You will now find "aweirdentryinyourlog"

    By handcrafting the URL one can put anyting one likes in your log. It would indeed be a good idea to go through your web-scripts and see if there are no other holes in them.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      I was go going to say iw as really surprised you could do the same thing but after analyzing more carefully my code i know how you inserted "aweirdentryinyourlog".

      You did it like this: http://localhost/cgi-bin/index.pl?select=aweirdentryinyourlog

      Nothing bad happened because this attempt falls inside the unless code block where my program exits. I have corrected it though and now the code looks like this:

      my @files = glob "$ENV{'DOCUMENT_ROOT'}/data/text/*.txt"; my @menu_files = map m{([^/]+)\.txt}, @files; Encode::from_to($_, 'ISO-8859-7', 'utf8') for @menu_files; print header( -charset=>'utf8' ); my $article = param('select') || "Welcome Page!"; if ( param('select') ) { #If user selected an item from the drop dow +n menu unless( grep /^\Q$article\E$/, @menu_files ) #Unless user selectio +n doesn't match one of the valid filenames within @menu_files { if( param('select') =~ /\0/ ) { $article = "*Null Byte Injection* attempted => $article"; print br() x 2, h1( {class=>'big'}, $article ); } elsif( param('select') =~ /\.\.\// ) { $article = "*Backwards Directory Traversal* attempted => $art +icle"; print br() x 2, h1( {class=>'big'}, $article ); } else { my $message = "What Exactly Are You Up To With > $article < M +ighty Hacker ?"; print br() x 2, h1( {class=>'big'}, $message ); $article = "*Hack Attempt* attempted => $article"; } $update = $db->prepare( "UPDATE guestlog SET article=?, date=?, +counter=counter+1 WHERE host=?" ); $update->execute( $article, $date, $host ); exit 0; } Encode::from_to($article, 'utf8', 'ISO-8859-7'); #Convert user sel +ected filename to greek-iso so it can be opened open FILE, "<$ENV{'DOCUMENT_ROOT'}/data/text/$article.txt" or die $ +!; local $/; $data = <FILE>; close FILE; Encode::from_to($article, 'ISO-8859-7', 'utf8'); #Convert user sel +ected filename back to utf8 before inserting into db $update = $db->prepare( "UPDATE guestlog SET article=?, date=?, cou +nter=counter+1 WHERE host=?" ); $update->execute( $article, $date, $host ); } else blablabla
      Now i print to the hacker a funny message and this time i'am aware of whats in the log since i create the message to be logged.

      Please if you have spare time see if you can pass any other bogus info on my script or perhaps you can open a file.

      My major concern is this line, but as i have written it and especially attached the ".txt" assertion on the end i believe there cant be a possible attempt on opening a file stored in my hdd through my script.

      Or Am i wrong?!

        Well, I'm by no means an l33t hAcx0r so I will not be attempting to hack your website and try to get at your files.

        The established procedure to secure your website is to run Perl in taint mode and clean all the user-input though a regex before you use it anywhere. In "taint mode" your program will refuse to work with any non-cleaned user-input. It therefore forces you to think about what kind of user input is allowed before letting you actually using it.

        CountZero

        A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James