Haxx0red j00 PHP



  • Preaching to the choir here.


  • BINNED

    Yah... and I forgot PHP has no equivalent to Safe for op-code restricted, sandboxed code.



  • cough Python cough


  • BINNED

    @M_Adams said:

    The language I like least? The one that triggers my acid reflux?

    Python

    The reasons?

    The "One True Way", "You're Doing It WRONG", "Why Would You Want THAT": all phrases I've heard on Python sites with the additional sense they're tacking "(you asshat)" on the end. Where have we heard those (or similar) phrases recently ⸮
    White space. Really. White space is for semantic, and esthetic use. Using it for syntax‽ You should die, die, die! Because:
    It is so much easier to read when the only punctuation for sentences is spaces  See two spaces bring the end of a sentence  One cannot even imagine why this would be hard to read for anyone  The only way it could, maybe, be harder is "f ll wrds wr dsmvwld, thn tht mght b cncdrd rthr bt hrdr t ndrstnd thn jst rmvng prds frm sntncs"  Now let's go for three spaces for separating paragraphs, are you game
    Because of the above, I've not found any refactoring tools for Python that won't completely fuck up the syntactic white space. Refactoring in Python is at least three times as hard as necessary.

    Other than that I can, have, and probably will again use Python where necessary.

    📂:
    Repeating myself Repeatedly…



  • Aside from the abortion that was 'safe mode' which has been deprecated because it was actually useless, it's been possible pretty much forever to list functions you don't want to be run. shell_exec, for example, is commonly disabled (in the PHP ini file)



  • You simply have to become one with Python.

    Also, don't inherit any projects, don't suck, and you won't have to refactor, haha.



  • So Python really is just as bad as any other language. Thanks for the heads-up


  • BINNED

    Yeah, but perl allows you to actually forbid specific op-codes which means you can't even write a work-around by hand. And you can set the forbidden op-codes at a per program level, where php.ini affects every php interpreter launched.



  • I'd be surprised if some of these 'forbidden' op-codes couldn't be worked around in longhand somehow.

    As for php.ini, it's possible to set up per-directory variables (e.g. different hosted sites) but as a general rule you don't really need that.

    Interestingly in the specific setup that started this topic, I was surprised at the lengths some of the malware was going to, specifically to try to avoid the usual locked functions.



  • @Arantor said:

    So Python really is just as bad as any other language. Thanks for the heads-up

    Disclaimer: it's nowhere near as bad as PHP.



  • Ah, but what else is?


  • BINNED

    @Arantor said:

    I'd be surprised if some of these 'forbidden' op-codes couldn't be worked around in longhand somehow.

    "Safe" operates in whats called a "BEGIN" phase of compiling and that phase is done in FIFO order. So if I set up a mod-perl type system where I set up the safe compartment in the server before your program gets handed to it (example from a postgresql pl/perl function I wrote is below), you can't work around it because the op-codes get redirected to fail in the compilation phase for your script. Once Safe "smack down" an op-code, you can't resurrect it later, it's prevented by the interpreter itself.

    CREATE FUNCTION sproc.ora_decode(selector text, clauses text) RETURNS text
        AS $_X$
    
    #############################################
    ##   ora_decode( selector text , clauses text )
    ##                       plperlu rendition of Oracle's decode() function.  Takes 2 args:
    ##                       the item to check, and a double comma (,,) separated string
    ##                       listing of items to match and items to return if the match is successful.
    ##                       The last entry in the string is the final "else" return value.  The match
    ##                       sections may include boolean operations.  USE DOLLAR
    ##                       QUOTING to setup the test/result string, it WILL save you much hair pulling.
    ##
    ##   provides its own Safe.pm compartment for the reevalution of the match clauses
    ##
    #############################################
    
    use Safe;
    
    my $vault;
    
    # get / setup a safe "vault"  from / in %_SHARED to reduce function start up time on a per session level
    
    if ( exists( $_SHARED{pl_vault} ) && defined( $_SHARED{pl_vault} ) ){
    
    	$vault = $_SHARED{pl_vault};
    	#elog( NOTICE , "plperlu: Preloaded safety vault being used." );
    }
    else {
    	# setup a safe vault using the same parameters as the SAFE_OK macro in postgresql's
    	# http://developer.postgresql.org/cvsweb.cgi/pgsql/src/pl/plperl/plperl.c?rev=1.105
    
    	$vault = Safe->new;
    	$vault->permit_only( qw/ :default :base_math !:base_io time sort / );
    
    	$_SHARED{pl_vault} = $vault;
    	#elog( NOTICE , "plperlu: Setting up session safety vault.");
    }
    
    my $selector   = $_[0];
    my @in_clauses = split( /,,/ , $_[1] );
    
    #reject @in_clauses argument if it doesn't contain an odd number of entries: ie - 
    #            ( '>10' , 'return#1' , 'final else' ) or ( '>10' , 'return#1' , '<10' , 'return#2' , 'final else' )  is OK 
    #            ( '>10' , 'return#1' ) is not
    
    die   " ora_decode(): invalid clause argument:\n"
        . "               clause argument must have\n"
        . "               odd number of entries:\n"
        . "               "
        . join( ',,' , @in_clauses )
        . "\n" 
        unless ( scalar( @in_clauses ) % 2 );
    
    my $final_else = pop @in_clauses;
    my $retval     = undef;
    
    ITERATIONS:
    while ( @in_clauses ){
    	my $match_clause = shift @in_clauses;
    	my $then_clause  = shift @in_clauses;
    	my $result       = $vault->reval( $selector . $match_clause );
    
    	if ( $@ ){ # safe reval error...elog and ignore it, then move on and try the next set of match/result clauses...
    
    		elog( NOTICE , "ora_decode():\n"
                                 . "             reval safety violation:\n"
                                 . "            \"$selector $match_clause\"\n"
                                 . "error:\n"
                                 . "     $@"
                                 );
    		next ITERATIONS;
    	}
    	if ( $result ){ # we have the winner...set $retval and bail out...we only grab the first true result...
    
    		$retval = $then_clause;
    		last ITERATIONS;
    	}
    }
    
    if ( defined( $retval ) ){
    	return $retval;
    }
    
    # if we get here we are returning the "default" result value
    return $final_else;
    
    $_X$
        LANGUAGE plperlu IMMUTABLE SECURITY DEFINER;
    
    COMMENT ON FUNCTION sproc.ora_decode(selector text, clauses text) IS
    'plperlu rendition of Oracle''s decode() function.
    Takes 2 args: the item to check, and a double comma (,,)
    separated string listing of items to match and items to
    return if the match is successful.  The last entry in the
    string is the final "else" return value.
       The match sections may include boolean operations.
     
    USE DOLLAR QUOTING to setup the test/result string.';
    


  • sigh

    ####################################################################################
    # check that the email address
    # is in the right format
    
    sub emailIsValid {
    
       my $email = $_[0];
       ($email =~ m/\s/) && return 0;                #no blank spaces allowed in address 
       if ($email =~ m/\.com$/i ||                    #check for 6 valid 3 digit suffixes
           $email =~ m/\.edu$/i ||                    #
           $email =~ m/\.net$/i ||                    #if so the email address must have 
           $email =~ m/\.org$/i ||                    #the form: *@*.xxx 
           $email =~ m/\.gov$/i ||                    #
           $email =~ m/\.mil$/i ||
           $email =~ m/\.aero$/i ||    
           $email =~ m/\.biz$/i ||    
           $email =~ m/\.coop$/i ||    
           $email =~ m/\.info$/i ||    
           $email =~ m/\.museum$/i ||    
           $email =~ m/\.name$/i ||    
           $email =~ m/\.pro$/i
           ){                     #
    
          ($email =~ m/^.+\@[\w\-\.]+\.\w{3,6}$/) &&  return 1;
          return 0;
       } else{                                        #if not three digit suffix
                                                      #check that *@*.xx 
          if ($email =~ m/^.+\@.+\.\w\w$/){return 1;}
          else {return 0;}
       }
    }
    

  • BINNED

    Sweet Kevin Costner on a raft! 😝 (need emoji for "puke")



  •     @staticmethod
        def isvalidemail(email):
            import re
            return re.match(r"[^@]+@[^@]+\.[^@]+", email)
    

  • BINNED

    Nope. ANY form of an is_valid_email() that does anything other than send a "confirmation link" email is Doing It Wrong™ and has been prejudicially attacked here on DWTF and StackOverflow, and probably 80,000 other sites...



  • @M_Adams said:

    Nope. ANY form of an is_valid_email() that does anything other than send a "confirmation link" email is Doing It Wrong™ and has been prejudicially attacked here on DWTF and StackOverflow, and probably 80,000 other sites...

    Because that's the best for all cases...


  • BINNED



  • this


  • sub cgiGetContent {
       my (@args1,@args,$arg)='';
       
       if ($ENV{'QUERY_STRING'})
       {
         @args1 = split ('&', $ENV{'QUERY_STRING'});
       }
       if ($ENV{'CONTENT_LENGTH'})
       {
          read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
          @args = split ('&', $buffer);
       }
       push @args,@args1;
       foreach $arg (@args)
       {
          ($name, $value) = split ('=', $arg, 2);
          $name =~ tr/+/ /;
          $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
          $value =~ tr/+/ /;
          $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
          $value =~ s/\"/&quot;/g;
          $value =~ s/\>/&gt;/g;
          $value =~ s/\</&lt;/g;
          $value =~ s/\|/ /g;   #get rid of characters that match field separators
          $cgiVar{$name} = $value;
       }
    }
    

  • Discourse touched me in a no-no place

    @M_Adams said:

    Nope. ANY form of an is_valid_email() that does anything other than send a "confirmation link" email is Doing It Wrong™

    What about checking an for an MX record for the bit after the @ first? And what about making sure there's at least something before the @? Is @example.com a valid format for an email address?



  • I would defend the most basic of tests, because users are dumb and if we can give them an error very quickly that tells them they're dumb, they can fix it.

    Doesn't need to be bullet proof, doesn't need to check every permutation but the most basic formats can be checked. Accept the most lax thing you can and defer proper validation to a confirmation email.


  • BINNED

    @PJH said:

    checking an for an MX record

    Well if you're already "shelling out" for a DNS hit, why not just send the email and have the user prove it? Really it's not anymore onerous than a captcha for them ...

    @PJH said:

    Is @example.com a valid format for an email address

    Read the RFC and tell me... 😉 (it's not) but once again ... It also specifies bang paths as acceptable... :blech:

    @Arantor said:

    Accept the most lax thing you can and defer proper validation to a confirmation email.

    👍


  • Discourse touched me in a no-no place

    @M_Adams said:

    It also specifies bang paths as acceptable...

    Hmm - do most MTA's still accept those?


  • BINNED

    I think I'd be surprised either way... I've not seen bang paths since my ARPANET days...



  • Oh shit we got a bad-ass over here



  • @M_Adams said:

    Yah... and I forgot PHP has no equivalent to Safe for op-code restricted, sandboxed code.

    Indeed. I ended up having to accept JavaScript code and execute it in V8JS when I had to allow scriptable input. I would have much preferred to use a predefined subset of PHP.

    @Arantor said:

    it's been possible pretty much forever to list functions you don't want to be run

    It's impossible to maintain a complete black list though. Much better to list the acceptable operators and functions. Also, there needs to be a way to sandbox the execution so you can specify exactly which objects and variables the user-provided code can read and alter. V8 allowed this.



  • Fair point, though my experience has been that you don't need to lock down everything, just a specific subset to avoid real damage and let the user make a mess of everything themselves if they so desire.



  • @M_Adams said:

    I've not seen bang paths since my ARPANET days...

    How many of us have been around long enough to have actually used them?

    I still remember my first attempt to send email outside my university's own server went into the bit bucket because one of the servers in the path was down, but I got a nice reply from an admin at the previous server telling me what he thought had gone wrong.



  • Ugh, I hate those. Fun fact, if you're talking about the hardware keys that I'm familiar with, they didn't actually contain a jump table. It was basically running a hash function - feed it some bytes of input and you get back a hash. You can then either verify that the hash is what you expected (easy to crack if you disassemble the application), or use the hash as a jump vector, which it sounds like your application was doing (not so easy to crack).

    It was supposedly possible to dump the contents of a key and then run an emulator which fed the correct responses to the application, but I gave up at that point. And yeah, we do have the hardware key and the license to run the software, but hardware support is a pain in the ass. We still have a couple of decrepit laptops running Windows 98 / DOS for when we need to use that software (I really hope it's not much longer). The batteries to maintain the BIOS settings have long since died, and since the hardware key doesn't work with the BIOS's default setup for the parallel port, I have to reconfigure the BIOS every time so it'll recognise the key, but they do still work.



  • Yeah, exactly. This is on a form where users don't have any authentication, they're entering a public record where the only way to edit it is via a link sent to their email address (which we don't store for privacy reasons), so making sure that their address is at least sane helps prevent them from complaining later, and me having to do more work.


  • BINNED

    @HardwareGeek said:

    How many of us have been around long enough to have actually used them?

    That would be an interesting question. I was a statistics wonk and lab-work monkey for researchers at the Center for Lake Superior Environmental Studies while in college and my ARPANET email account, courtesy of working for a lab with ties to the EPA, was a huge nasty bang path. So was my MILNET one... Both had some overlap with what is now considered a "real" email address (had one of those too: xxxx.xxxx@uwsuper.edu). And that was in the 80's. Not sure when the others dropped the bang path addresses...

    @HardwareGeek said:

    I got a nice reply from an admin

    Back before admins went all BOFH in self defence :) and actually had time to monitor nearly everything on their machines.


  • Discourse touched me in a no-no place

    @M_Adams said:

    Nope. ANY form of an is_valid_email() that does anything other than send a "confirmation link" email is Doing It Wrong™ and has been prejudicially attacked here on DWTF and StackOverflow, and probably 80,000 other sites...

    No. You use @chubertdev's code as an initial sanity check (so as to throw out stuff that's likely Just Plain Wrong™) and then back that up with a confirmation link. The cases where a valid email address doesn't match that RE are so rare that you can easily pretend that they don't exist; it's not a problem for local users to supply a full email address rather than a short one, and nobody sane uses the other email addressing schemes any more.



  • Depends how good/bad the RE is. I've seen very sane through to very insane.

    These days I tend to just rely on PHP's filter_var function.


  • 🚽 Regular

    I'm sure you're right on the detail, thanks that's very interesting.

    I think it's been about a decade since I fooled with one of them. That was my first foray into assembly on a PC, I went though all of Fravia+'s reversing tutorials and made a bit of progress. I remember it was a pain to debug as it detected/did something to debuggers.

    I should look to see if I have that work in my archives, if nothing else it's an excuse to thin the huge pile of old hardddisks.



  • @dkf said:

    No. You use @chubertdev's code as an initial sanity check (so as to throw out stuff that's likely Just Plain Wrong™) and then back that up with a confirmation link. The cases where a valid email address doesn't match that RE are so rare that you can easily pretend that they don't exist; it's not a problem for local users to supply a full email address rather than a short one, and nobody sane uses the other email addressing schemes any more.

    And as I said, this is a very unusual use case. This isn't for user registration. The user isn't creating an account. They're entering their email (which isn't stored on our end outside of the SMTP server's sent mail records), and then they are emailed an edit link for their submission.


  • BINNED

    @chubertdev said:

    …their email (which isn't stored on our end outside of the SMTP server's sent mail records), and then they are emailed an edit link...

    Which means that if it passes the initial sanity check ( per @dkf ) and is still wrong in some way. They'll never get the edit link and their submission becomes unreachable? goes to the big bit bukit in da sky? and frustrates the user?

    I'm not understanding why:

    @chubertdev said:

    ...their email address (which we don't store for privacy reasons)...

    As even under (in the USA) HIPAA as an example of strict privacy regulations: as long as there exists an actual "business relationship" (and even if not…) non-storage of an email address isn't a privacy requirement. So I'm assuming this is a PHB-style "privacy" directive?


  • BINNED

    And how in the sam-hill do you undo a user_name filter after you've used one in a topic (without exiting the thread and reentering)? By hand altering the URL? Don't see an affordance for that :(...



  • If you're referring to clicking on an avatar in the summary at the top to filter by user, click on the same avatar to remove that filter.



  • @M_Adams said:

    Which means that if it passes the initial sanity check ( per @dkf ) and is still wrong in some way. They'll never get the edit link and their submission becomes unreachable? goes to the big bit bukit in da sky? and frustrates the user?

    I'm not understanding why:

    chubertdev said:
    ...their email address (which we don't store for privacy reasons)...

    As even under (in the USA) HIPAA as an example of strict privacy regulations: as long as there exists an actual "business relationship" (and even if not…) non-storage of an email address isn't a privacy requirement. So I'm assuming this is a PHB-style "privacy" directive?

    Yeah, the sanity check is to catch the blatantly wrong. If it passes that, but is still wrong, they can contact me, and I (or any other admin) can send them an email with an edit link.

    And no, it's not a PHB-style directive, it's a CBA-style, since it's a site that's about a decade old that was written in Perl by a guy whose computer expertise was probably clearing cookies.


  • BINNED

    I clicked here: , and when I went back to look at it there was no indication that clicking it again would undo the filter. Jimminy Cricket! a ✔ mark or maybe making it green, to maybe indicate toggle is just to much to ask ???



  • Well, the way I said still works (clicking the filtered user's avatar in the top summary gets rid of the filter), and also in the mini-profile:


  • BINNED

    @chubertdev said:

    it's not a PHB-style directive, it's a CBA-style

    Well! That makes it all better :)



  • I inherited it, so I've only changed a bit. It used to have the ugly Perl validation above. I don't think that I've implemented Python on that page yet, so the improper validation is still there, lol. But when it comes to a user that's brand new to the site having the least effort possible but still being able to edit later, a sanity check then an actual email is IMHO the best way to go (apart from showing the edit link on the screen, which users never copy).


  • BINNED

    Well... screw me with a purple dildo! I swear when I went to undo the filter did not show...

    I just did the same sequence again and I see it this time!

    Filed under: shoulder aliens, must have blocked my view, yep, that's my story...



  • Consistent inconsistency, +1, Discourse, yadda yadda


Log in to reply