It's not working completely, as the mail portions of the script are failing (because they are not executing from my server), but the gibberish they are using in their fake form is ending up in my database.
How can I test for execution from my server only, and halt the script when it is executed from somewhere else?
Would
gethostbyaddr() be useful, and how would I implement it? Thanks in advance.
my $site = 'www.foobar.com';
if ($ENV{'HTTP_REFERER'} =~ m¦http://([^/]*)$site¦i) {
do something useful
}
else {
do somthing like print a message or exit the script
}
[edited by: jatar_k at 6:06 am (utc) on Sep. 7, 2005]
How would I detect when they are attempting to send their output through my script in order to log their IP? It's not a port scan or a login situation, so I guess it would come in through a normal server port and look just like normal traffic, except for what it was trying to do.
Also, these attacks are coming through many of the APNIC-registered servers ... which means they're probably spoofs and will cycle through to the next spoofed machine when one IP is blocked. I have grabbed the IP address from the data that ends up in our databases, but by then it's too late.
I'm thinking it may be more reliable to set up a little auth script readable only by the web server user and requiring it in each script, but I'm stuck on how to get the auth value into the script execution without including it in the form that's being hijacked.
Thanks, again.
SERVER_ADDR seemed to be a good bet during testing, but there's still a lot of ifs and elses involved. Interestingly:
if ($ENV{'SERVER_ADDR'}=="198.112.13.") ... matches all of the addresses in that Class C block, 198.112.13.1, 198.112.13.2, etc. Since my domains are using many IPs within a C block, it looked pretty good as a broad-stroke identifier.
Unfortunately, SERVER_ADDR and other SERVER environment variables (like SERVER_NAME) apply to the server that's running the script ... not from whence the data came. For that info, the only environment variable I have found so far is HTTP_REFERER, which we all acknowledge can be easily forged. REMOTE_HOST is the IP address of the client, every genuine form-submitter has their own in the same way any bogus form-submitter does, and it is subject to the APNIC/spoofing issues noted above.
Still working on an auth script and getting the correct auth info to it without including it in the form ...
The IP address is contained in the $ENV{'REMOTE_ADDR'} variable. Also, remote IP addresses are very difficult to spoof.
The way I have it set up now is:
1) Attempt made to pass data to script
2) Garbage of this attack's type detected
3) Log IP, timestamp and form name in a special log file
4) Ban IP using ipchains and iptables
5) Redirect to hacking law information site
6) Exit script
That works ... the log file is being populated and I am not seeing any entries of this type in my database.
But it's pretty specific to those scripts and that type of attack. I'd really like a more global solution to prevent any script on my server from being given data to process from any location other than from my server. So far HTTP_REFERER seems to be the only environment variable that might indicate this condition, but since it's flaky, I'm continuing to explore a seperate auth function as I mentioned above.
if ($ENV{'SERVER_ADDR'}=="198.112.13.") ... matches all of the addresses in that Class C block, 198.112.13.1, 198.112.13.2, etc. Since my domains are using many IPs within a C block, it looked pretty good as a broad-stroke identifier.
That is completely wrong. Should be:
if ($ENV{'SERVER_ADDR'} =~ /^198\.112\.13\./) { ... }
$ENV{'SERVER_ADDR'} eq "194.123.36." which won't match. Use of the regex you posted would have the same result as the code I posted erroneously earlier, i.e. matches everything in that C block.
Thanks for the correction. ;)
(I'm usually drowning in PHP, so using the different comparison operators for numeric values or strings in Perl is surprising me.)
The "captcha phrases" looks interesting ... force the inclusion of a SESSION variable of some kind ...
$ENV{'SERVER_ADDR'} eq "194.123.36." is also incorrect :) You can't literaly compare blocks of IP addresses. The IP literlay has to be '194.123.36.' which, of course, is not a valid IP address. With literal comparison you can only match one IP at a time. For example:
if ($ENV{'SERVER_ADDR'} eq '127.0.0.1') { ... }
The bottom line is that if a program is sophisticated enough, it's being run from the command line and the IP address is EASILY spoofed. So denying a service based on REFERER or other environment variables is a waste of time.
Identify exactly what you expect to be incoming from YOUR form and accept those values ONLY. Be especially aware of the email address: it must match only the pattern
/^[\w.+-]+\@[\w.+-]+$/
Someone please chime in with a better regexp here. :-) I use this one in combination with several other screen methods on the email address.)
Secondly, don't make the "to" address a hidden field in the form. Put it in your script and HARD CODE IT. Even storing it in a variable can be compromised if someone figures out the variable name. What good would it do to hack a script if it can only go to you?
Hope this is the least bit helpful . . .
I had some people hammer our scripts that would add a bcc field to the email field, and drop 1000 or so addy's at a time to spam AOL.
Try to avoid using common names for scripts such as
/cgi-bin/formmail.pl.
being run from the command line and the IP address is EASILY spoofed.
That's a myth. You cannot "spoof" an IP address unless you mean going through proxy. Or you mean spoofing referrer?
the mail portions of the script are failing (because they are not executing from my server), but the gibberish they are using in their fake form is ending up in my database.
I have scripts that allow users to add records to the database. In the cases where people may try to add data that I do not want, I have the script write to a temporary database and only after I verify the data does it get moved to the live database.
Another approach I use is to have the script generate a random number and build a string which is based on date, IP address and the random number... the script requires the user to provide an email address, and then emails a "verification message" to that address with the unique random number embedded in a link --- the user needs to receive the email and click the link to verfiy they actually submitted the data... this extra step has cut my junk submissions to 5% of what they were prior to adding this verification process. Again, the records are stored in a temp database until verified so my live data stays clean.
How can I test for execution from my server only, and halt the script when it is executed from somewhere else?
People have suggested several things here, but the truth is anything a "human" can enter into a form and submit, can be automated with a script.
It reminds me of the old MAD Magazine "Spy v. Spy" --- one spy drops an anvil, the other puts a trampoline under it to bounce it back -- the first one then adds a magnet to catch the anvil, etc.. etc...
Verification of email address of person submitting form data has been the only thing I've found that works.
You cannot "spoof" an IP address unless you mean going through proxy.
Another late-night feux pas. What can be done though, is once several boxes get rooted, you telnet to one, from there, to another, to another . . . and when you're all done delete the logs. My point was only that you really can't rely on any environment variables to ID an attack.
Verification of email address of person submitting form data has been the only thing I've found that works
Do you mean some method of connecting with the remote mail server and getting a response (or just regexp matching)? If so i implore you, PLEASE SHARE!
I suggest that everyone log EVERYTHING coming in from their forms. You will be surprised at what is going on that you don't know about. I've been watching people trying to hack using other fields - ANY fields - using %0A and entering their own BCC and CC fields. And if you don't screen all data, it works. So even if you DO screen email - they can still spam using your servers.
So much talent wasted . . .
WWW PHP Forum thread [webmasterworld.com]
I've got various regexps and so forth in the scripts now, and am logging and dropping offenders. Seems to be keeping the rabble out for now.
Here's one to protect against attempts to add BCC and CC headers to the single From header by using newlines:
if ($email =~ /\\n/) { log-and-drop } for example ... like I said, it seems to be a pretty big problem.
Here's an even better [webmasterworld.com] current thread on the topic.
if ($email =~ /\\n/) { log-and-drop } Just checks for newlines and
if (($email =~ /\\r/)¦¦($email =~ /\\n/)) { log-and-drop } should catch carriage returns AND newlines.
My main concern with this is the email field, although the bigger concern is allowing anyone to run any script from somewhere other than my server.
IF the email field is used for specifying the "To:" header, then it's susceptible to being used for spam. For example (using phpmailer class):
$email=$_POST["email"]; ... $mail->AddAddress = ($email,"Spam Target"); ... In this case, without further checking, someone could place this in the "email" form field:
me@mail.com\n\nBCC:victim@email.com,stooge@example.com and get the BCC header to be created for them, sending spam to "victim" and "stooge". They could even do something like:
me@mail.com\n\nBCC:victim@email.com,stooge@example.com\n\nBODY:My spam message to get their message out. Mail isn't too particular about how it gets its headers. It'll even send properly with duplicate, forged headers, like my "real" BODY and their fake BODY, one after the other, as long as two newlines separate the headers.
So that's what my previous post was about ... I'll work on keeping others from being able to run my scripts from their machines, but the emergency situation was the possibility of using my machine to send spam.
One thing it seems like you may be missing though - it's not just the "to" or the "from" header. If they violate the subject field with a BCC, that would work too. I've even seen (apparently) attack other fields, such as the "how you found out about us" or even comments/message fields. So that's why I say all, better safe than not!