Secure DirectAdmin panel port 2222 with SSL
SSL is designed to keep an internet connection secure by safeguarding any sensitive data that is being sent between two systems, thereby preventing a third party from reading and modifying any information transferred, including protected personal information (PPI).
It's important to to use a secure connection for services and for the DirectAdmin panel itself: Secure DirectAdmin panel port 2222 with SSL
Security Questions or Two-Factor authentication after DirectAdmin login for an additional layer of security
To help increase the level of security with a DirectAdmin server, a feature was added which allows you to add questions or enable two-factor authentication after the login is already successful. These questions can be User specified, and any incorrect answer can then notify the User.
To enable the questions, or to add/modify the questions, log in as the user and go to:
Dashboard -> Change your Password -> Manage Security Questions
To enable two-factor authentication, log in as the user and go to:
Dashboard -> Change your Password -> Two-Step Authentication
The page also allows you to disable API access to the account using the same password used to login. Session Keys and Login Keys do not apply to this setting, as they're always allowed.
NOTE: Each failed 2FA/security question is counted in the 'failed_logins' file (where wrong passwords are counted). This means you must get a valid password and valid 2FA/Security Question within the "brutecount" limit, else you'll be put on the ip_blacklist (/usr/local/directadmin/data/admin/ip_blacklist), which is where IPs bruteforcing the DA login are blocked. To remove yourself from the blacklist, edit
/usr/local/directadmin/data/admin/ip_blacklist and remove your IP from the list. You can also ensure you never become blocked by adding your IP to the file
Login Trigger changes regarding Two-step Authentication and Security Questions
Login triggers only trigger after both the user/pass login and 2FA/security questions are answered correctly. Previously, the trigger would happen after the valid login, before the 2FA/security questions were answered.
- checking to ensure the
task.queueis being processed (random)
- check for old
- clear the
- add to "login history"
The feature allows any DirectAdmin account to require the Two-Step Authentication using a time-based code from a smart-phone app (e.g., Google Authenticator, FreeOTP, Authy, etc.)
Access this feature from: Password Icon -> Two-Step Authentication
Once you have a "Secret" created, scan the barcode into your Authenticator App in your smart phone. Enable the feature, and future logins will require the temporary code generated from the App, entered on a 2nd page after a successful user/password login.
You can also optionally create one-time use "Scratch Codes", which can be printed and kept somewhere safe.
These scratch codes are used as a backup, in case your phone is not available to generate the code. A scratch code is only valid for one use, then is removed from the list of codes. The scratch code can be entered into the same "Code" field when logging into DA.
Information on the importance of Two-Factor Authentication can be found here: http://comparitech.net/2fa
directadmin.conf settings include the following:
twostep_auth=0|1 default 1 block_ip_after_failed_twostep_auth=0|1|2 default 0 max_twostep_auth_attempts=5 twostep_auth_discrepancy=1 twostep_auth_trust_days=30
twostep_auth=1 enables two-step authentication,
max_twostep_auth_attempts=5 permits 5 authentication attempts via this feature, and
block_ip_after_failed_twostep_auth is whether or not to block the IP after failing two-step authentication, where setting to
0 (the default setting) means that no blocking will occur,
1 means that a warning will be given to the User that their IP will be blacklisted on their last attempt, and
2 means that no warning will be given when blocked. Of course, enabling the IP blocking requires that you have Blacklisting turned on in your Admin Settings.
The twostep_auth_discrepancy value should be a positive integer representing the number of 30 second time slices you can be off by (before or after). So the default of 1 allows a code to be valid before 30 seconds before, and 30 second after the phone's timer is done counting down.
DA's "Test Code" button may show you a message about the code being valid, but for a different time. If, for example, you see the time discrepancy as "-4", that means your code expired 2 minutes ago.
If you can't fix your server's time, then change this setting to be "4" (positive 4), and DA will allow a wider range of -4 to +4 for logins. Also useful if someone's phone time isn't accurate.
The twostep_auth_trust_days=30 value represents the duration that a trusted cookie is allowed to live in the client's browser. A trusted device can be un-trusted on the CMD_TWOSTEP_AUTH page. This may make your phone sad, as the server would no longer be its friend.
Applicable DA User files:
Applicable DA User
twostep_auth=no firstname.lastname@example.org notify_on_all_twostep_auth_failures=yes
NOTE: Each failed 2FA/security question is counted in the 'failed_logins' file (where wrong passwords are counted). This means you must get a valid password and valid 2FA/Security Question within the "brutecount" limit, else you'll be put on the ip_blacklist (
/usr/local/directadmin/data/admin/ip_blacklist), which is where IPs bruteforcing the DA login are blocked. To remove yourself from the blacklist, edit
/usr/local/directadmin/data/admin/ip_blacklist to remove your IP from the list. You can also ensure you never become blocked by adding your IP to the file
Detecting and preventing brute-force attacks
A common method of gaining access over a server is to use a technique called a brute force attack, or dictionary attack. What the attacker will do, is use a script to try and log in to an account with every possible password combination. This tends to require tens of thousands of login attempts, but eventually, the right combination will be found, and they can log in normally.
To prevent this, we can use a brute force login detection system. DirectAdmin has 2 such systems for these attacks.
- The original feature was created in DA 1.25.5, and will detect and block login attempts on DA itself (port 2222):
This feature only applies to port 2222. It only blocks IPs on this port. It does not block IPs from other ports.
To enable this feature, go to Admin Level -> Admin Settings -> Blacklist IPs for excessive login attempts use a value around 10-20.
- The newer system works in tandem with the previous, and will scan the logs for the other services (Apache, Dovecot, Exim, ProFTPd, SSHd).
When an attack is detected, DA will notify the Admins on the box that the attack is in progress.
DA will not block the IPs since that would require a firewall, and DA doesn't manage firewalls (see
To enable the detection reporting, go to:
Admin Level -> Admin Settings -> Parse service logs for brute force attacks
The brute force monitor (BFM) page can be viewed at Admin Level -> Brute Force Monitor.
Hide brute-force notifications
As brute force attacks are fairly common, and the tools to prevent those attacks are fairly reliable, some admins do not wish to be told about every case of attacks.
Since the trigger of the
brute_force_notice_ip.sh only happens with notices, I've added an option to prevent the sending of the notices, but still call the scripts normally to block the IP.
The directadmin.conf option will be:
which is the internal default (option disabled, notifications shown).
If you wish to prevent notices from being sent out, but still have the IPs blocked, then set this in your directadmin.conf:
All servers should be running some sort of firewall to prevent them, e.g.,
The purpose of this guide is to hide those Message System messages once you've established that your blocking system is working correctly. There are several options and levels to suppress the messages.
If you want to hide the messages from the "Message System", but continue to be notified via E-Mail:
If you want to send the high-volume attack E-Mails to some different address, like email@example.com, you can add a user.conf variable:
Brute-force monitor page generates a timeout
If you get a timeout message similar to the one below when accessing the Brute Force Monitor (BMF) page CMD_BRUTE_FORCE_MONITOR:
Your connection has timed out. Either your request was invalid or the program hasn't completed your request. Please notify the server admin.
This is usually caused by an over-sized file
/usr/local/directadmin/data/admin/brute_log_entries.list. Check this file to see if it's large. If it is, you can shrink it down, but only keep the entries at the end of the file (the end of the file has the newest entries).
cd /usr/local/directadmin/data/admin mv brute_log_entries.list brute_log_entries.list.backup tail -n 1000 brute_log_entries.list.backup > brute_log_entries.list chown diradmin:diradmin brute_log_entries.list
Where you can increase or decrease the 1000 lines as needed.
Other possible affected file are the
brute_ip.data. Of these 2 files, it's more likely the
brute_user.data is causing the slowdown, because attacks typically happen on many Users from 1 IP address. If you need to empty the
brute_user.data file, type:
cd /usr/local/directadmin/data/admin mv brute_user.data brute_user.data.backup touch brute_user.data chown diradmin:diradmin brute_user.data
We wouldn't recommend emptying the
brute_ip.data because this is what counts the attacks per IP, and is what is used to determine if an IP should be blocked.
Prevent BFM from reporting specific email
If you're using the Brute Force Monitor (BFM) and 1) have an email address that is repeatedly checking your server, but that account is invalid (either a wrong password, or a non-existent account), and 2) you know that the person doing it is not malicious, but only stubborn for not updating their settings, then you can tell the BFM to skip that email address from being checked.
To do this, create the
/usr/local/directadmin/scripts/custom/brute_force_notify_pre.sh script and add the following code:
#!/bin/sh if [ "$type" = "User" ]; then if [ "$value" = "firstname.lastname@example.org" ]; then echo "exempt email@example.com"; exit 1; fi fi exit 0;
Make it executable:
chmod 755 /usr/local/directadmin/scripts/custom/brute_force_notify_pre.sh
Note that this will only prevent reports for users/emails being logged. It will not prevent the blocking of the IPs, as the IP could be "attacking" some other account as well.
Found an XSS or CSRF hole in DirectAdmin?
We get these reports on occasion, but DirectAdmin has had a referer checking tool for quite some time now:
Since this was added, none of the external XSS/CSRF reports have been valid.
People who think they've found one often are testing with a form in the DA skin, on port 2222 on the same IP. This means the form is in the skin, which is exactly where it lives usually for its intended purpose. So of course, the form submission passes, as one would expect. So this test is only possible if they've got access to editing the skins, which means they've already got root access on your server, so the XSS test doesn't mean anything.
An external form, using any different variable, either IP or port will fail the
In DA debug mode, a sample might look like this, where 22.214.171.124 is the server IP, and we actually put the hacking test on the same IP. In real life, the attacking IP would typically be on a different IP, but that only adds one more thing for the referer check to find. This just proves that even just the variance in the port is sufficient to stop the attack.
This test has http://126.96.36.199/hack.html with any standard form you want, DA on http://188.8.131.52:2222, with the client IP being 184.108.40.206:
Checking referer http://220.127.116.11/hack.html to 18.104.22.168:2222 Referer check failed for 22.214.171.124. See error.log
And from the error.log:
2016:03:31-15:49:00: Referer port (80) does not match DA's (2222): http://126.96.36.199/hack.html 2016:03:31-15:49:00: Referer check failed for 188.8.131.52
So please, before submitting your security report, please check to ensure that you're not actually testing your form in 2222, since that's where it's going to be valid. Test with your form on any different port or IP.
I wish to have a block_ip.sh so I can block IPs through DirectAdmin
Starting from DirectAdmin version 1.61.0, the CSF integration is done directly. New installs will have CSF automatically installed and BFM autoblock covered if installation isn't customized to disable them.
Existing installations after updating to 1.61.0 could have direct CSF integration upon deleting previously installed plugin files.
To activate, remove the following files:
/usr/local/directadmin/scripts/custom/block_ip.sh /usr/local/directadmin/scripts/custom/brute_force_notice_ip.sh /usr/local/directadmin/scripts/custom/show_blocked_ips.sh /usr/local/directadmin/scripts/custom/unblock_ip.sh
Brute Force Monitoring for xmlrpc.php
xmlrpc.php, a file included with WordPress, is an API file used for data transfers or actions between various things.
A stand-alone setup often does not need web access to this file, but any external connections, like iPhone apps that routinely do POSTs to it generating a 200 return code would require it.
This is also one of the major attack points for WordPress, used in attempts to determine the website's WordPress password.
As a result, our Brute Force Monitor (BFM), when "Scan for WordPress attacks" is enabled in the Admin Settings, will scan for POSTs to this file with a valid 200 return code (
This change is to increase the match count, which would have been the same as the Brute Force Monitor's count limit (set in Admin Settings), to now be 8x that value, to allow for possible valid usage, while still blocking attacks.
For example, if you set your ip_brutecount=100, aka:
"Notify Admins after an IP has:  login failures on any account"
This would mean that any User would be allowed 800 POST with a 200 response code to the xmlrpc.php file, based on the BFM's rules.
Note that the BFM's time window is sliding and is entirely based on a period of time where there are no attacks counted in order to reset the count to 0.
So if you have the following set in your Admin Settings,
"Reset count of IP/User failed attempts:  hours after last attempt"
A period of 4 hours must pass where there are 0 failed attempts from this IP address in order for the count up to 800 to reset to 0.
If even 1 POST to xmlrpc+200 is done per hour, then the count will never reset, and the 800 limit WILL eventually be hit.
There are plugins for WordPress, which can monitor for such attacks, saving the need for DA to do it, such as WordFence.
It's ultimately up to a website to be protecting itself, as the "Scan for WordPress attacks" is simply there to be a fall-back in case the website owner failed to secure WordPress.
/usr/local/directadmin/data/templates/brute_filter.list contains options:
wordpress3=ip_after=&ip_until= -&text=] "POST /&text2=/wp-login.php&text3=" 302%20&count_multiplier=4
What this does, is after all log parsing is done, the Brute Force Monitor will count how many entries were triggered for that item (e.g., wordpress3) for that given IP.
Say there were 20 triggers. The multiplier means that instead of having a limit of 100, that item needs 400.
The actual logic in DA is actually backwards, as the total count uses other items, so we actually divide the number of wordpress3 counts by 4.
So instead of 20 hits, the count only see 5 towards the total. This also means that if there are only 3 hits, then 3/4 = 0, so no count would be triggered for that IP.
The entries will still show up in the log list, but count for that given IP (top table) would be lower.
The whole purpose for this is that the entry:
POST /wp-login.php HTTP/1.1" 302
could represent an attack, but could also just be a normal redirection. So we do want to count it, but it should be of lower significance.
Security Questions for extra layer of protection
DirectAdmin has an ability to enable Security Questions, which is where a valid login will take the client to another authentication page, asking for a valid answer to a pre-defined question. Forum thread
The Security Questions page can be accessed from the "Password" icon, at the top of the page (where a DA User changes their password).
In the 'Security Questions options' (where you will enable the feature via a checkbox after adding your questions and answers), there is a checkbox to allow API connections to the account with this DA username with their password. If disabled (unchecked), no CMD_API call will work for this account when accessing the account with the usual password, so only disable API's if you know you don't need them.
This API checkbox does not apply to Login Keys, so you can disable APIs with the password, but APIs will still work when using a Login Key (they're so long that they won't likely be guessed).
There is no checkbox for Login Keys. If you don't want to allow Login Keys to access the API, don't create a Login Key.
This feature is an extra layer of security, in addition to the current Brute Force Attack monitor for port 2222.
The list of questions is stored in:
The very first line will look something like:
where index 1 will always store the number of entries in the file. In this case, the last entry is index
For the sake of clarity, see the default file below:
# cat /usr/local/directadmin/data/skins/enhanced/lang/en/internal/security_questions.txt 1=22 2=What is the name of your favorite childhood friend? 3=In what city did you meet your spouse/significant other? 4=What was your childhood nickname? 5=What street did you live on in third grade? 6=What is your oldest sibling's birthday month and year? (e.g: January 1970) 7=What is the middle name of your oldest child? 8=What is your oldest sibling's middle name? 9=What school did you attend for sixth grade? 10=What was your childhood phone number including area code? (e.g: 000-000-0000) 11=What is your oldest cousin's first and last name? 12=What was the name of your first stuffed animal? 13=In what city or town did your mother and father meet? 14=Where were you when you had your first kiss? 15=What is the first name of the boy or girl that you first kissed? 16=What was the last name of your third grade teacher? 17=In what city does your nearest sibling live? 18=What is your oldest brother's birthday month and year? (e.g: January 1970) 19=What is your maternal grandmother's maiden name 20=In what city or town was your first job? 21=What is the name of the place your wedding reception was held? 22=What is the name of a college you applied to but didn't attend? #
Basically, just take the highest number at the bottom, and use that (#1 skips itself automatically).
To add more entries, edit this file, and lock it from update overwrites:
chattr +i security_questions.txt
Language changes can have their own copy, in their own language.
- security_questions=yes - Security questions will be required, if they're present.
- api_with_password=yes - The API is allowed, using the current password. Login Keys and Session Keys are always allowed since this setting does not affect them.
- notify_on_all_question_failures=yes - When enabled, all incorrect answers will generate a Message to the User (not to Admins). The "no" will still send a message to Admin and User after max_security_question_attempts attempts.
New directadmin.conf values, these are the internal defaults:
security_questions=1 max_security_question_attempts=5 block_ip_after_failed_security_questions=0
block_ip_after_failed_security_questions option can be set to 1, and on the last attempt, a warning will be given to the User that their IP will be blacklisted.
If you set:
then no warning will be given.
Of course, this requires that you have the Blacklisting option turned on in your Admin Settings (if it's off, go turn it on now!).
Custom blacklisted IP page
An optional custom template file exists here:
If that file exists and the client IP is blacklisted, this content type text/html page will be sent to the client, instead of the hard-coded: "Your IP is blacklisted".