Wordpress: How to properly hide Wordpress?
Jedan od najbitnijih načina da sakriješ WordPress je da modifikuješ strukturu datoteka ili da je nekako prikažeš drugačiju.
How to Hide that You Use Wordpress How To Hide The Fact That Your Website Runs On WordPress | Elegant Themes Blog Best Plugins to Hide WordPress How to Hide That Your Site is Using WordPress | kevinleary.net
Plugin: Hide My WP
It supports Nginx perfectly - as per this answer from developer.
I don’t like it as it captures all the output and replaces strings in realtime. I think this is simply to raw and non-performant.
Put everything that plugin suggests:
nano /var/www/vhosts/save-up.ch/conf.d/wp-hide-my-wp.conf
And don’t forget to include that file:
|
|
Disabled for now.
-
WP Hide & Security Enhancer WP Hide It seems it offers the same functionality as Hide My WP, only free. For now it is not aware of nginx, only apache.
Much better coded than Hide My WP, so steal code from it if needed. Also
-
Quite good plugin: Lockdown WP Admin / srtfisher/Lockdown-WPAdmin WordPress Plugin to hide login and admin URLs when not logged into WordPress. This doesn’t include webserver changes (conf/htaccess). All the CSS & Images under /wp-admin/ are still accessible, just not the .php ones.
Remove the WordPress Generator meta tags
Remove Generator Meta Tag that is inserted by the Theme in Wordpress:
WordPress › WP Remove Generator Meta Tag WordPress › Support » [Plugin: WP Remove Generator Meta Tag] Generator info is still generated on all pages…
The right way: The Right Way to Remove WordPress Version Number
?? How to remove the WordPress Generator Meta Tag
Hide WP
Detect what it is?
Idi jedan po jedan, i pokreći wpscan, i kada ga ne detektuje - znaćeš šta je.
Hide My WP - Amazing Security Plugin for WordPress! by wpWave | CodeCanyon Hide My WP Demo – Hide the fact you use WordPress!
https://www.owasp.org/index.php/Fingerprint_Web_Application_Framework_(OTG-INFO-008)#WhatWeb
Wpscan doesn’t recognize WP if:
- Needed hiding specified in my
wordpress.conf
- Hide Login Page
- New wp-content path (or sometimes enough is New theme path + New upload path + New plugin path). All this requires some lines in wordpress.conf.
Appspector - extension (Chrome takođe) (ex: Chrome Sniffer) http://www.nqbao.com/blog/appspector/
- Za njega je dovoljno da se uključi: Other Meta / Remove other header metas like short link, previous and next links, etc.
Wappylizer (https://github.com/AliasIO/Wappalyzer/) still recognizes it:
- Wappylizer (koristi isključivo u Chrome jer se tamo trenutno updateuje - ma i tamo je iz cache-a)
Ma jok, nego se mora clearovati lokalni cache za extenziju. Disableuješ pa enableuješ extensziju - to sigurno radi.
Wappylizer is the same, but better is to set new wp-content path, as only in that way it will not catch that it is wordpress.
For those detection engines, it is ok to leave wp-content
folder still active, just
in html there should be no mention of it.
Pokusao sam na 100 načina, ali sam disable-enable radi.
Here are all the Wappylizer rules:
https://github.com/AliasIO/Wappalyzer/blob/master/src/apps.json
but now it is in src/technologies folder
Also, I tried to use PHP driver:
apt-get -y install libv8-dev php-pear php-dev
pecl install channel://pecl.php.net/v8js-0.1.3
I also tried using PhantomJS:
apt-get -y install phantomjs
# Due to some bug, we also need this
apt-get -y install xvfb
# And we must wrap every call
xvfb-run phantomjs hello.js
# As explained here: https://github.com/Arachni/arachni/issues/707#issuecomment-215468415
alias phantomjs="xvfb-run phantomjs"
phantomjs driver.js https://www.koviljaca.rs -v
But dropped that as I realized that bookmarklet is not cached. It only
needed to change one http://
to https://
as bookmarklet had that small
error.
So, the perfect bookmarklet that is not cached:
javascript: (function() { var d = document, e = d.getElementById('wappalyzer-container') ; if ( e !== null ) { d.body.removeChild(e); } var u = 'https://wappalyzer.com/bookmarklet/', t = new Date().getTime(), c = d.createElement('div'), p = d.createElement('div'), l = d.createElement('link'), s = d.createElement('script') ; c.setAttribute('id', 'wappalyzer-container'); l.setAttribute('rel', 'stylesheet'); l.setAttribute('href', u + 'css/wappalyzer.css'); d.head.appendChild(l); p.setAttribute('id', 'wappalyzer-pending'); p.setAttribute('style', 'background-image: url(' + u + 'images/pending.gif) !important'); c.appendChild(p); s.setAttribute('src', u + 'js/wappalyzer.js?' + t); s.onload = function() { s = d.createElement('script'); s.setAttribute('src', u + 'js/apps.js?' + t); s.onload = function() { s = d.createElement('script'); s.setAttribute('src', u + 'js/driver.js?' + t); c.appendChild(s); }; c.appendChild(s); }; c.appendChild(s); d.body.appendChild(c); })();
Bookmarklet: Drivers @ AliasIO/Wappalyzer Wiki Please note that there is a debug output in console when using bookmarklet, which is added bonus.
I also customized wappylizer.js to show me the matched rules (hosted on koviljaca.rs)
- http://pagexray.com/site/www.koviljaca.rs.htm (pošto ne radi extenzija)
Built With
There is also Chrome extension. It is heavily cached results in cloud.
PHP Library for detecting CMS
https://github.com/Krisseck/Detect-CMS
Stupid old CMS Detector
http://onlinewebtool.com/cmsdetector.php
WhatWeb
https://www.morningstarsecurity.com/research/whatweb
BlindElephant
https://community.qualys.com/community/blindelephant BlindElephant | Penetration Testing Tools BlindElephant Web Application Fingerprinter
Wordpress Fingreprinting Sites
-
Wordpress Theme Detector (and Plugins) - ScanWP, Detect any WP Theme with corresponding chrome extension: Scan WP - Detect Wordpress Themes and Plugins
-
WordPress Theme Detector - Free online tool to find a site´s theme
Chrome Extensions that do that
-
WordPress Theme and Plugins Detector WordPress Theme and Plugins Detector
-
Version Check for WordPress Version Check for WordPress Extension - White Fir Design This is actualy quite cute and useful extension!
-
WPSNIFFER is dead now
Samo proveri jel dobro radiš: https://premium.wpmudev.org/blog/how-to-hide-your-wordpress-version-number/?npp=b&utm_expid=3606929-81.6_x2aktJQ2qbOSnTRGna0w.1 https://wordpress.org/support/topic/wp-44-remove-json-api-and-x-pingback-from-http-headers/
It is mostly this Wappylizer rule:
"<link rel=[\"']stylesheet[\"'] [^>]+wp-(?:content|includes)",
What the env
variable is for in the apps.js
config?
Those are JavaScript environment variables in the window scope.
So to search for wp_username
variable, type in console:
for(var b in window) if(window.hasOwnProperty(b) && (new RegExp("^wp_username$")).test(b)) console.log(b);
The final solution to hide Wordpress is:
- Rename
wp-content
to onlycontent
. Done. - Hide login URL, by using
/run
or/etk
. Done. - Do all the removal of signatures in HTML and headers. Done.
- Install the whole Wordpress in subdirectory named
@
. Not mandatory. See example @ technomer.rs
How to do step 1?
- Replace
wp-content
withcontent
in database with plugin Better Search Replace - Rename the folder to
content
- Edit
wp-config.php
and add those lines:
define('HOST_NAME', ((strpos($_SERVER['SERVER_NAME'], 'www.') === 0) ? '' : 'www.') . $_SERVER['SERVER_NAME'] );
define('WP_HOME', 'https://' . HOST_NAME . '/');
define('WP_SITEURL', 'https://' . HOST_NAME . '/');
/* Move wp-content */
define('WP_CONTENT_FOLDERNAME', 'content');
define('WP_CONTENT_DIR', ABSPATH . WP_CONTENT_FOLDERNAME) ;
define('WP_CONTENT_URL', WP_SITEURL . WP_CONTENT_FOLDERNAME);
-
Add the line to nginx.conf:
rewrite ^/wp-content/(.*) /content/$1 last;
in case someone hot-linked something from our site (facebook posts) and we also don’t want to lose SEO. -
Dont forget to check all the nginx .conf files and replace wp-content to content.
Plugins and themes folder location should not be in the same subfolder, as this is how WPScan tries to detect one based on another. So it should be something like:
/content /design /ext/s /ext/m
- Replace
themes/
withdesign/
in database with plugin Better Search Replace - Rename the themes folder to
design
- Edit
wp-config.php
and add those lines:
Ajde, smisli lepa imena i lepu strukturu. I napravi da se uvek automatski sve to podesi kad instaliraš WP. Nešto automatizovano (a sve to unutar @) ;)
Ustvari, theme ne moraš da pomeraš. samo dodaj svoju u novi dir. Tako se neće poojavljivati nikad u source-u i svi srećni ;)
Detecting fingerprinting with:
clear; tail log/access.log -f -n0 | grep -Ei ' 200.*wpscan'
wpscan is checking all these:
/wp-content 404
/content/plugins 301
/readme.html 403
/wp-includes/rss-functions.php 500
/content/debug.log 403
/%23wp-config.php%23 404
/wp-config.php.swo 404
/wp-config.bak 404
/wp-config.save 404
/wp-config.php.old 404
/wp-config.php~ 404
/wp-config.php.save 404
/wp-config.orig 404
/wp-config.original 404
/wp-config.php_bak 404
/wp-config.php.swp 404
/wp-config.php.bak 404
/wp-config.old 404
/wp-config.php.original 404
/wp-config.php.orig 404
/wp-config.txt 404
/searchreplacedb2.php 404
/wp-signup.php 500
/content/mu-plugins/ 404
/wp-login.php?action=register 404
/xmlrpc.php 403
/content/uploads/ 403
/content/themes/twentyfifteen/readme.txt 403
/content/themes/twentyfifteen/README.txt 404
/content/themes/twentyfifteen/Readme.txt 404
/content/themes/twentyfifteen/ReadMe.txt 404
/content/themes/twentyfifteen/README.TXT 404
/content/themes/twentyfifteen/readme.TXT 404
/content/themes/twentyfifteen/changelog.txt 404
/content/themes/twentyfifteen/ 500
/content/themes/twentyfifteen/error_log 404
/feed/ 200 // solved disabling RSS feeds
/feed/rdf/ 200 // solved disabling RSS feeds
/feed/atom/ 200 // solved disabling RSS feeds
/wp-includes/css/buttons-rtl.css 200 // ** it is poking blindly. how to solve this?
/wp-includes/js/wp-emoji-loader.min.js 200 // ** how to solve this?
/content/themes/twentyfifteen/style.css 200 // blind poking. just rename style.css (hide_my_wp does that without problems - steal from it)
- It is needed to fully disable RSS Feeds in Wordpress. Easy to do manually, but also by simple plugin Disable Feeds Plugin is NOT using do_feed???_ hooks?
|
|
-
Nekako wp-includes ne sme da se pojavljuje?
/wp-includes/css/buttons-rtl.css 200 // ** it is poking blindly. how to solve this? /wp-includes/js/wp-emoji-loader.min.js 200 // ** how to solve this?
Ma jok. Dovoljno je samo blokirati ova dva u nginx-u. Ionako ih ne trebam za ništa.
E, a onda se otvara pandorina kutija i još pokinga
# If I block these, it will not detect Wordpress version
#
location = /wp-includes/css/buttons-rtl.css { deny all; }
location = /wp-includes/js/wp-emoji-loader.min.js { deny all; }
location = /wp-includes/js/mediaelement/mediaelement-and-player.min.js { deny all; }
location = /wp-includes/js/tinymce/wp-tinymce.js.gz { deny all; }
location = /wp-admin/js/customize-nav-menus.min.js { deny all; }
location = /wp-admin/js/customize-controls.js { deny all; }
location = /wp-includes/js/customize-preview.js { deny all; }
location = /wp-admin/js/common.js { deny all; }
location = /wp-includes/css/admin-bar.css { deny all; }
location = /wp-includes/js/wp-ajax-response.js { deny all; }
location = /wp-includes/js/thickbox/thickbox.css { deny all; }
location = /wp-links-opml.php { deny all; }
Sve je ovo napravljeno da detektuje WP verziju: vidi fajl wp_versions.xml
unutar https://github.com/wpscanteam/wpscan/blob/master/data.zip
Ali mislim da se ništa neće pokrenuti ako uspem da napravim da ne detektuje WP.
Above poking is to determine Wordpress version.
How does it detect WP version? Everything is inside file [findable.rb](Here is the file https://github.com/wpscanteam/wpscan/blob/master/lib/common/models/wp_version/findable.rb)
It also data/wp_versions.xml
to try to identify a wordpress version, does this by using client side file hashing
A u tom fajlu on čita:
readme.html
Finally, it still detects it is Wordpress, just it don’t know which version. And WP existance is based on theme detection, as renaming the Theme folder does the job perfectly.
-
If I specify folder
/fucker/themes/current
for theme, it searches forfucker/plugins
So, you MUST NOT mentionthemes
in theme folder, but for exampletheme
is ok! Anyway, let’s go for/skin
So this is how it determines plugins folder.
And that is enough. No need to change theme names or anything. Just
change themes folder name to something other than themes
, like
/design, /skin or /looks
Ok. Here you can detect:
-
https://github.com/wpscanteam/wpscan/blob/master/lib/wpscan/wp_target/wp_custom_directories.rb Don’t mention
themes, plugins, wp-content
anywhere in HTML. -
A lot of wp-config.php checks here: https://github.com/wpscanteam/wpscan/blob/master/lib/wpscan/wp_target/wp_config_backup.rb
-
readme.html from here: https://github.com/wpscanteam/wpscan/blob/master/lib/wpscan/wp_target/wp_readme.rb
-
Attacking this: wp-includes/rss-functions.php from here: https://github.com/wpscanteam/wpscan/blob/master/lib/wpscan/wp_target/wp_full_path_disclosure.rb
PHP files in the wp-includes directory should not be accessible from the outside, they should only be included by wordpress code. Therefor an easy fix to this is to use .htaccess rules to block access to *.php files that are under the wp-includes directory
-
Detection of some plugins from HTML content and headers: https://github.com/wpscanteam/wpscan/blob/master/lib/common/collections/wp_plugins/detectable.rb Patterns:
/wp-super-cache/, /w3 total cache/, optimized with the Yoast, etc
Dissecting WPScan detection
If you don’t mention themes, plugins, wp-content
anywhere in HTML, the scan will not detect Wordpress at all, in the first place.
But even Google Analytics’s JS plugins with URL’s like google-analytics.com/plugins
will trick WPScan to think that site is using Wordpress.
For themes you can use register_theme_directory() function to add additional directories for WP to be aware of. I don’t think I ever seen this used in practice, so not sure if there are any complications possible.
For plugins you can define WP_PLUGIN_DIR and WP_PLUGIN_URL constants in wp-config.php.
Decision on naming folders
I prefer using singular nouns (vs plurals) as we want to hide the fact there are multiple sub-folders inside some folder.
-
wp-content is now content. Candidates were: content, app, assets
-
themes is now style. Candidated were: design, skin, look, appearance, decor, view.
It is very important to be singular as we don’t want to reveal there are multiple styles, which indicates some kind of CMS. There are subdirectories style/core and style/extend with parent and child theme in them. Please note that original content/themes folder will still exist with all the other themes residing there. -
plugins are now modules. Candidated were: components, extensions, addons, bits, features, sections, segments
Execute folder renaming by doing it like this:
- Rename
/wp-content
to/content
- Rename
/content/plugins
to/modules/core
and/content/mu-plugins
tomodules/requisite
- Create folder
/style/core
and/style/extend
and move parent and child theme there. Other than that, leavecontent/themes
as is.
Themes and plugins are now surely not the same folder level.
Renaming of specific parent & child theme folders is necessary as also parent theme folder is mentioned in style of child themes. So we renamed parent’s theme folder to
core
and child’s theme folder toextend
Final folder placement will look like this:
/content ...
...
/themes ( unused themes, must exist )
/modules /core ( plugins )
/requisite ( mu-plugins )
/style /core ( parent theme )
/extend ( child theme, current )
Execution on site
(1) Search & replace from within Wordpress Admin
- Replace
wp-content
withcontent
in database with plugin Better Search Replace. - Replace
content/themes
withstyle
(2) Restructure folders
Create the new folder structue:
mv wp-content content
mkdir modules
mv content/plugins modules/core
mv content/mu-plugins modules/requisite
mkdir style
mv content/themes/<parent-theme> style/core
mv content/themes/<child-theme> style/extend
chown --reference content style modules
chmod --reference content style modules
Theme mangling
It is impossible to rename the base themes folder (content/themes), but as both parent and child themes are in subdirectories, nothing in HTML body will hint the other themes location.
To retrieve active theme directly from database, use this SQL:
SELECT * FROM etkwp_options
WHERE option_name IN ('template', 'stylesheet', 'current_theme');
Simplest way to automate theme folder changes is to execute SQL query after moving and renaming the folders:
UPDATE etkwp_options SET option_value = 'save-up' WHERE option_name = 'current_theme';
UPDATE etkwp_options SET option_value = 'core' WHERE option_name = 'template';
UPDATE etkwp_options SET option_value = 'extend' WHERE option_name = 'stylesheet';
Just as a reminder, to reset theme values to default, use SQL:
UPDATE etkwp_options SET option_value='default'
WHERE option_name='template' OR option_name='stylesheet' LIMIT 2;
Renaming uploads folder
Renaming uploads folder is not quite straightforward, but it is possible as explained in this article.
Anyway, it turns out we don’t need that for now, so it can reside in /content/uploads
.
Renaming themes folder
There used to be, now unnecessary way of renaming theme folder, explained here
I decided to use easier and perfectly stable route and to create a new simple mu-plugin to add additional theme folder.
I’ve done this as mu-plugin because the muplugins_loaded
hook is really the first hook to fire in Wordpress, as seen here
cat <<'EOF' >> modules/requisite/register_theme_directory.php
<?php
/*
Plugin Name: Register Additional Theme Folder
Plugin URI: http://www.cvladan.com
Description: Adds an additional folder for themes
Version: 1.0.0
Author: Vladan Colovic
Author URI: http://www.cvladan.com
License: GPL2
*/
// Do not include a trailing slash.
register_theme_directory(ABSPATH . '/style');
EOF
Setting permissions is also needed:
chown --reference . modules/requisite/register_theme_directory.php
chmod --reference . modules/requisite/register_theme_directory.php
Additional theme settings
Fix child theme code
We must search and edit the child’s theme code to set parent theme to core
inside styles.css
and search & replace every other occurrence of sahifa
and change it to core
Fix theme menus
After renaming themes, there is a problem of “detached” menus; not assigned to their locations.
The simplest fix is to change current menu assignements inside the admin panel, by going to Appearance » Menus » Tab: Manage Locations (URL: /wp-admin/nav-menus.php?action=locations
) page and select menus you need.
You could also use the following SQL query:
SELECT * FROM etkwp_terms AS t
LEFT JOIN etkwp_term_taxonomy AS tt ON tt.term_id = t.term_id
WHERE tt.taxonomy = 'nav_menu';
…or more simple, alternative query for the same thing:
SELECT * FROM etkwp_options WHERE option_name LIKE 'theme_mods_%'
After that, renaming values theme_mods_etaktiker
with theme_mods_extend
should do the same thing as doing it inside
Wordpress admin panel. To know more about menu representation in database tables read this very informative answer
WordPress as a Git submodule in /@/
or app
?
Great analysis and some interesting solutions: prevent WPScan from scanning
// Sve ove nabode i izračuna hash wp-admin/js/customize-nav-menus.min.js wp-admin/js/customize-controls.js wp-admin/js/common.js wp-includes/css/buttons-rtl.css wp-includes/js/wp-emoji-loader.min.js wp-includes/js/tinymce/wp-tinymce.js.gz wp-includes/js/customize-preview.js wp-includes/css/admin-bar.css wp-includes/js/wp-ajax-response.js wp-includes/js/thickbox/thickbox.css
// Ovih definitivno nema nigde više wp-admin/js/wp-fullscreen.js wp-includes/js/plupload/plupload.js wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin.js wp-includes/js/tinymce/themes/advanced/js/image.js wp-includes/js/tinymce/themes/advanced/js/link.js wp-includes/js/wp-ajax.js wp-layout.css layout2b.css
// Ove sam ili već blokirao ili on nema pojma gde je folder readme.html $wp-content$/themes/twentyten/style.css $wp-plugins$/akismet/readme.txt $wp-content$/themes/default/style.css
The best way to solve this is:
# If I block these, it will not detect Wordpress version
# @see: https://codex.wordpress.org/Nginx
location = /wp-admin/js/common.js { try_files /dummy_nonexistant_file @login_check; }
location @login_check {
set $is_user_logged_in 0;
# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $is_user_logged_in 1;
}
if ($is_user_logged_in ~ 0) {
return 404;
}
}
For advanced fingerprinting, solve it like these:
- If it inside admin area, use cookie check if logged in
- If it is frontend, use self-referrer check I hope this one will never be used ;)
At the end, only the /wp-admin/admin-ajax.php
has been left
problematic, but it seems nobody is fingerprinting it for now.
Fixing admin-ajax.php?
I finally found a perfect solution to my problem of admin-ajax visibility on frontend:
-
using
admin_url
filter hook ensures that admin-ajax.php or /wp-admin will never be mentioned on frontend HTML -
admin-ajax.php is returning 404 by default anyway in Wordpress, so blind fingerprinting won’t work. Beautiful!
In code:
add_filter( 'admin_url', function( $url ) {
if (preg_match( '/\/admin-ajax\.php$/', $url )) {
$url = '/request';
}
return $url;
}, 10, 1 );
In nginx:
rewrite ^/request$ /wp-admin/admin-ajax.php last;
Basic idea can be examined here: Restrict access to WP-admin by IP in Nginx. There is always a more advanced example: Change Admin URL
Hotlinking prevention?
I already protected most of the stuff inside /wp-includes and /wp- admin, by using technique to detect logged users by cookie in nginx, but there is still a fingerprinting problem of admin-ajax.php as it has to be available on non-logged users also.
My idea was not to prevent images from hotlinking, but to ensure that any request to admin-ajax.php is done from the same site, and not externally for fingerprinting purposes.
location = /wp-admin/admin-ajax.php { try_files /dummy_nonexistant_file @referer_check; }
location @referer_check {
valid_referers server_names;
if ($invalid_referer) {
return 404;
}
}
Note: valid_referers directive doesn’t support variables
nginx - Image hotlink protection using rewrite - nikhil’s blog how to implement hotlinking prevention? - Stack Overflow
At the end
Don’t forget to refresh permalinks.
Multiple wappalyzer tools
-
projectdiscovery/wappalyzergo is a high performance go implementation of Wappalyzer Technology Detection Library
-
rverton/webanalyze also in Golang, but not library instead it is CLI tool that can be downloaded and executed.
Latest Release from GitHub
|
|
Gists: Download latest GitHub release via Powershell and Download latest GitHub release via Powershell