Unhacking a WordPress site » History » Version 3
Manu Mei-Singh, 11/11/2024 04:46 PM
1 | 1 | Jon Goldberg | h1. Unhacking a WordPress site |
---|---|---|---|
2 | |||
3 | This is an INCOMPLETE guide, but a good starting point! It doesn't cover removing malicious code inserted into the database, for instance. |
||
4 | |||
5 | WordPress gets hacked - a lot. And the correct solution is to restore your database and filesystem from backup. However, sometimes we deal with sites that weren't responsibly managed, and that's not an option. Here's a guide on what to do. |
||
6 | |||
7 | First - if it IS an option, delete your WordPress filesystem and restore from known good files. There's just too many ways to obfuscate a hack, so these approaches are necessarily incomplete. |
||
8 | |||
9 | * Search for suspicious PHP commands: |
||
10 | <pre> |
||
11 | grep -r gzuncompress * |
||
12 | grep -r base64_decode * |
||
13 | grep -r eval( * |
||
14 | grep -r str_rev * |
||
15 | </pre> |
||
16 | |||
17 | Not every instance of these commands is malicious! However, a hacked site will often use these, so look at what comes after them. If it's a long base64 block, that's bad news. |
||
18 | |||
19 | Note that there are MANY ways to obscure the commands above. Here are some example strings you can also search for |
||
20 | <pre> |
||
21 | "base" . "64_decode" |
||
22 | eval/* |
||
23 | </pre> |
||
24 | |||
25 | That last one's tricky. It found this command: @eval/*boguscomment*/('malicious_command')@. |
||
26 | |||
27 | |||
28 | |||
29 | * Check for this: |
||
30 | <pre> |
||
31 | <?php eval(get_option("\x72\x65\x6e\x64\x65\x72")); ?> |
||
32 | </pre> |
||
33 | |||
34 | That evaluates to: |
||
35 | <pre> |
||
36 | <?php eval(get_option("render")); ?> |
||
37 | </pre> |
||
38 | |||
39 | This indicates that there's malicious code in your database, and this minimal change allows the code to render. |
||
40 | |||
41 | Here's the commands I used to remove that from my entire codebase: |
||
42 | <pre> |
||
43 | find -name \*php -exec sed -i 's/<?php eval(get_option("\\x72\\x65\\x6e\\x64\\x65\\x72")); ?>//g' {} \; |
||
44 | find -name \*.html -exec sed -i 's/<?php eval(get_option("\\x72\\x65\\x6e\\x64\\x65\\x72")); ?>//g' {} \; |
||
45 | </pre> |
||
46 | |||
47 | * Look for function names you discovered with the last command and grep for those. I found commands like "ruburat" and "ukonabuh" which I then searched for. |
||
48 | * Use @git reset --hard HEAD@, if you're using git. |
||
49 | * Don't assume git will remove everything! I found php files in places not checked by git. E.g. in the .git folder, to wp-config.php and civicrm.settings.php, wp-content/uploads. Here are some commands to help you find php files where they don't belong (run from webroot): |
||
50 | <pre> |
||
51 | find .git -name \*php |
||
52 | find wp-content/uploads -name \*php |
||
53 | </pre> |
||
54 | 2 | Manu Mei-Singh | |
55 | |||
56 | From when Highlander was hacked: |
||
57 | |||
58 | |||
59 | _*If the site is hacked*_ (note that I wrote these fast and before my vacation... they should probably be updated and my guess is this process can be refined) |
||
60 | |||
61 | # Confirm that the site is hacked or being actively attacked |
||
62 | 3 | Manu Mei-Singh | ** This "flow chart":https://drive.google.com/file/d/1Z3u9hyVwIzyhY4EJKp6ixBMEX47P9mBZ/view?usp=drive_link might be of assistance |
63 | # If the site is compromised, ssh into the site |
||
64 | # Go to the web root directory and vim .htaccess |
||
65 | # uncomment line 94 and change it with your ip so it should like this. |
||
66 | 2 | Manu Mei-Singh | <pre>Require ip your.ip.goes.here another.ip.goes.here</pre> |
67 | 3 | Manu Mei-Singh | ** Note that if it's a DOS or DDOS you'll need to set up some sort of firewall at the server level. |
68 | # Save the htaccess file and confirm that only the required ips can access the site. |
||
69 | # Login into the site; you should be able to find login information via bitwarden. |
||
70 | # Goto plugins |
||
71 | 2 | Manu Mei-Singh | # activate Wordfence Security and run the malware scan |
72 | ## this may take some time to complete. |
||
73 | 3 | Manu Mei-Singh | ## there will be some red herrings, such as un updated files. |
74 | 2 | Manu Mei-Singh | # If you find something confirm that the it's a hacked file... |
75 | 1 | Jon Goldberg | ## When you ssh into the root directory, run git status to see if any files have been changed. |
76 | ## If the same file pops up, the site might be compromised. |
||
77 | 2 | Manu Mei-Singh | # If the site is indeed compromised. clean up up the bad files. |
78 | # Check the database for compromised data. |
||
79 | 3 | Manu Mei-Singh | # First check if there were new users created: |
80 | 2 | Manu Mei-Singh | <pre> wp user list --role=administrator --format=table </pre> |
81 | ** The above command produces a table that you can review and look for out of the ordinary users with wired emails and recent user_registered time stamps |
||
82 | # If there bogus users, you'll need to delete them either through the wp cli or through web admin panel. |
||
83 | # Check for bogus post data |
||
84 | ** <pre> wp db query 'SELECT * FROM `wp1_posts` ORDER BY `wp1_posts`.`post_date_gmt` DESC LIMIT 10;' >> ~/last_post.txt </pre> |
||
85 | 3 | Manu Mei-Singh | ** I use the above command to see if the last 10 post entires seem out of the ordinary. I then save it to a file. |
86 | ** If it's a different website you'll need to make sure table names match. |
||
87 | # If there is bogus data it's best to go into updraft plus and revert to the last clean back-up |
||
88 | # You may want to change passwords at this point for users. |
||
89 | 2 | Manu Mei-Singh | # If that worked you can change the .htaccess file back by commenting out line 94 |
90 | 3 | Manu Mei-Singh | # Confirm that the site is working for all. |
91 | # Continue to monitor the site for a few days |