Files can be modified by SQL injection too you know. An attacker could just as easily install a malicious plugin once they have admin rights - checking custom headers won't stop that.
There are a lot of things you can do with SQL injection, but so far as I know, direct modification of the filesystem isn't one of them. Coppermine, however, has a tendency of trusting the contents of the database, and of keeping things in there that (from a security perspective) should have been hard-coded somewhere, directory pathnames especially. So it wouldn't surprise me if gaining access to the database would allow an attacker to do things that Coppermine really shouldn't allow anyone, even a so-called "administrator," to do in the first place.
I'm a degreed computer scientist, I've been writing code for 20+ years, I worked on-and-off as a Un*x sysadmin since 1995, and I've written nearly two million lines of code in my life; I've seen systems that were secure and systems that were hacked, and in every case, the hacks boiled down to (A) the programmer making a mistake (which includes the programmer being too trusting) or (B) the users being too trusting or (C) the code having bugs. You can't really change (B) no matter how hard you try, and
no-one can completely stop (C), so the only thing you can do to stop attackers is get very defensive about (A). Yes, I've written PHP too, and I know PHP doesn't make it very easy to write secure code: for example, the preg_match /D flag drives me nuts, and the fact that you can't trust the value of "PHP_SELF" is just silly. But if you don't code defensively --- which means assuming your code can and will be attacked at every turn --- your code can and will be broken.
Anyway, if adding an administrative user entry in the database is all that's needed to be able to install malicious code, Coppermine will never be secure ---
the database should always be considered an untrustworthy data source, and everything in it should be checked, verified, analyzed, and validated just as though it came from the user (because there's at least a decent chance that it actually
did). At a minimum, that means moving things that need to be trustworthy outside the database; in my professional opinion, several more things should be hard-coded in your "config.inc.php" than currently are: The name of the "albums" directory, for example, and "userpics". You would only change those when you first install Coppermine anyway, and when you're installing Coppermine, you already have server access to change them! Keeping that kind of information in the database is pointless and just makes attacks easier and more fruitful. But if the database is treated by your code with the same skepticism as data that comes from the browser itself, all an SQL injection can do --- if the attacker finds one --- is maybe alter some of the data, but never alter the site.
Checking the custom headers/footers was an easy band-aid for this attack, and I posted this information because it may be beneficial for people who want to stem this particular plague. It is by no means a comprehensive security solution --- just a way of buying some time.If you want to limit SQL injections further, you may wish to use a proper database-wrapper layer that checks and validates all data going to and from the database: A lightweight design like your cpg_db_query() is inherently prone to security problems, because it spreads security checks throughout the program instead of centralizing them whenever possible.
In summary, I know that everything I'm describing may require changes in Coppermine, and some of the changes may be nontrivial. But please don't think I'm attacking you guys: We're both on the same side here, and I know far too well that security is hard, and I can see by the Changelog that you're trying, but more work is needed. Security, both reactive and proactive, is an essential consideration these days; we're living in an age where it's not
if your code will get attacked but
when and
how often, which means that security considerations need to be front-and-center in every last line of PHP you write.