All posts by mkirby

Firefox plugins I use

Plugin description
Adblock Plus  Blocks ads
CacheToggle Status bar toggle button for the browser cache
Cert Viewer Plus Certificate viewer enhancements
CipherFox Display current SSL/TLS ciphers and certificate chain
Cookies Manager+ View, edit, create cookies
Cryptocat encrypted, private conversations
CryptoFox encryption/decryption tool
DNS Cache Allows you to de/activate DNS Cache
DownloadThemAll mass downloader
Flagfox Display a flag depicting the location of the current server
Flash and Video Download Download flash videos from page
Form History Control Manage form history
FoxyProxy proxy quick switcher
FxIF view exif data on images
Ghostery Block trackers
Groundspeed Manipulate the app user interface to eliminate client-side limitations
Hackbar Multi-tool to assist with url manipulation
Header Spy show http headers on status bar
HttpFox http analyzer
HTTPS-Everywhere automatically use https on many sites
Image Zoom zoom for images
It’s All Text Edit forms using an editor
JavaScript Debugger debugger and profiler
JavaScript Deobfuscator self explanitory
Keylogger Beater Onscreen keyboard to bypass keyloggers
JSView View the source code of external stylesheets and javascripts
Link Sidebar View, search and test hyperlinks in a web page
Live HTTP Headers View http headers of a page while browsing
Mailvelope Secure email with OpenPGP encryption for webmail
Modify Headers add, modify and filter http request headers
NoScript Disable javascript with whitelisting capabilities
Privacy Badger Protects privacy by blocking spying ads and invisible trackers
Privacy Settings Alter Firefox’s built-in privacy settings with a toolbar panel
Poster developer tool for interacting with URLs
QR Secret Decoder Ring Right click a QR image to decode
RefControl Control what gets sent as the http referer
Saved Password Editor
SQL Inject Me test for SQL injection
SQLite Manager Manage any SQLite database on your computer
Table2Clipboard allow copy to clipboard of solected rows/columns from an html table
Tamper Data view and modify headers
Thumbnail Zoom Plus Shows full image when you hover over a thumbnail
UAControl Change user-agent
uBlock Origin Like AdBlock Plus
Update Scanner monitors webpages for updates
URL Flipper quickly increment and decrement numbers and strings in URLs
URL Tooltip Displays URL in hyperlink tooltips
User Agent Switcher self explanitory
View Dependencies Adds a tab listing dependencies and their sizes in the page info window
View Source Chart Source Chart DOM inspector
Wappalyzer Uncovers the technologies used on websites
Web Developer adds a menu and toolbar with various web developer tools
XSS Me test for XSS vulns
FireBug Web developer tool
FireCookie cookie manager for firebug

Filesystem security on

There are many permission changes I made to the filesystem.

path mode    reason
/proc o-rx Prohibit users from viewing processes and services.  The mount options for /proc in fstab does not allow to set the mode when mounting, so I have this scripted in an hourly cronjob.
/sys o-rx /sys contains information about the server that users do not need to know.  The mount options for /sys in fstab does not allow to set the mode when mounting, so I have this scripted in an hourly cronjob.
/var/tmp /tmp o-r Don’t allow users to see list of other users files but still allow write.
/run o-r /run contains pid files and other information about running services and users do not need to know.
/ o-r Yes. That’s right. The root of the filesystem is not readable for non-root users. They don’t need it.
/etc /etc/sysctl.conf o-r Users don’t need to know what is in /etc. I also removed read access to sysctl.conf. I would have done o-rx on /etc, but there are files that users and services need to read such as passwd, resolv.conf, and group.
/etc/httpd /etc/sysconfig /etc/yum /etc/yum.repos.d /etc/systemd /etc/wordpress /etc/tmpfiles.d /etc/udev /etc/selinux /etc/security /etc/samba /etc/postfix /etc/modprobe.d /etc/rc.d /etc/nagios /etc/nrpe.d /etc/dovecot /etc/cron* o-rx The httpd and wordpress directories are chgrp’d to apache, which is the only account that needs read access. By default, /etc/wordpress contains a world-readable file with database credentials.
/var /var/log /var/cache /var/lib /var/log/boot.log /var/log/cron* /var/spool /var/spool/anacron /var/spool/mail /var/spool/nagios /var/spool/postfix /var/spool/samba /var/lib/mysql /var/log/wtmp /var/run/utmp /var/log/lastlog o-r Many of these should be self-explanatory. This will prevent a hacker from finding information about the system and other users.
/var/lib/rpm /var/cache/yum /var/db /var/lib/yum /var/lib/rpm-state /var/spool/plymouth /var/www o-rx Again, many of these should be self-explanatory. This will prevent a hacker from finding information about the system and other users. The /var/www is chgrp’d to apache. Restricting access to the rpm and yum directories prohibits users from looking at installed packages.
/dev /dev/shm /dev/mqueue o-r Users do not need to know what devices are on the system. /dev/shm and /dev/mqueue are world-writable directories.
/dev/pts /dev/hugepages /dev/udev o-rx More directories that users don’t need access to. The /dev/pts contains tty info of logged-in users.
/boot o-rx Users don’t need to know about the kernel I’m running.
/media /mnt /srv /opt /home /usr /usr/* /usr/share/man /usr/share/man/* o-r More directories that users don’t need read access to. Users can still execute commands in /usr/bin, they just can’t get a listing of the executables.
/bin/at /bin/chage /bin/chfn /bin/chsh /bin/mount /bin/umount /bin/Xorg /bin/pkexec /bin/newgrp /bin/su /bin/passwd /bin/gpasswd /bin/crontab /sbin/mount.nfs /sbin/pam_timestamp_check /sbin/seunshare /sbin/unix_chkpwd /sbin/userhelper /sbin/usernetctl u-s I remove the suid bit from many of the files. Removing the suid from /bin/mount prevents users from seeing mountpoints. If I had other users on the system, I would have kept suid on passwd and crontab.
/bin/wall /bin/write /bin/locate g-s This removes the group suid. Users don’t need to run these.

In addition to these changes, the logrotate config was modified to prevent rotated files from returning to the default permissions.
In /etc/logrotate.conf, the default create mode for wtmp is 0664. I changed it to 0660. I also added ‘create 0600 root root’ to /etc/logrotate.d/syslog.

GCC security flags

I don’t always compile software from source, but when I do I add a few flags.
Almost all of the software on this system is from rpm packages, which RedHat/Fedora uses many of these flags when they compile their packages.
To make things easy, I have a couple aliases in my bashrc:
export myCFLAGS=”-Wall -D_FORTIFY_SOURCE=2 -O2 -pipe -fPIE -pie -fstack-protector-all”
export myLDFLAGS=”-Wl,-z,now -Wl,-z,relro”
When I compile software with configure, I add CFLAGS=$myCFLAGS LDFLAGS=$myLDFLAGS at the end of the configure command.

Here are the CFLAGS I add when compiling:

flag description
-fstack-protector-all Emit extra code to check for buffer overflows, such as stack smashing attacks. This is done by adding a guard variable to functions with vulnerable objects. The guards are initialized when a function is entered and then checked when the function exits. If a guard check fails, an error message is printed and the program exits. You can read more about it here:
-D_FORTIFY_SOURCE=2 Defining this macro causes some lightweight checks to be performed to detect some buffer overflow errors when various string and memory manipulation functions.
-fPIE Enable Position Independent Executable used for ASLR (Address Space Layout Randomization). You can read about it here: and here:
-pie I’m not sure how this is different from -fPIE. Something to do with the linker.

Here are the LDLAGS I add when compiling:

flag description
-Wl, -z,now When used in combination with RELRO, BIND_NOW prevents the full global offset table (GOT) from being overwritten.
-Wl,-z,relro Read-only relocations (RELRO) allow sections of an executable that need to be writable only while a program is loading to be marked read-only before the program starts.

SELinux settings on

The default SELinux settings in Fedora work fairly well, but I made a few modifications.

First, I disabled the execstack and execmod capabilities.  Any software that requires either should be considered flawed.
setsebool -P selinuxuser_execstack off
setsebool -P selinuxuser_execmod off

I also disabled ptrace and execmem. Ptrace is used to trace processes. It is useful in debugging applications to watch systemcalls. Denying ptrace means that users cannot use the strace command, which I have found indispensable to troubleshoot application issues when the error logs don’t provide valuable information. The deny_execmem prevents an application from marking the memory as both writable and executable.
setsebool -P deny_ptrace on
setsebool -P deny_execmem on

My Apache webserver needs to access an NFS share and the default SELinux prohibits this, so I enabled httpd_use_nfs:
setsebool -P httpd_use_nfs on

I also enabled secure_mode_insmod, which means that new kernel modules cannot be loaded. This caused a problem with my network settings because I use vlan tagging. The secure_mode_insmod interfered with the 8021q module. To mitigate this, I setup a cronjob to execute the following every hour:
/usr/sbin/getsebool secure_mode_insmod 2>&1 |grep ‘on’ >/dev/null 2>&1 || /usr/sbin/setsebool secure_mode_insmod on

I had to build a local policy for exceptions to the targeted SELinux rules. Discovering the needed exceptions is not always easy. The error logs for applications will not tell you when SELinux blocks something. When I troubleshoot an issue, I first check the error output and the logs. The second thing I check is the audit log for AVC entries. You can search for these with ‘ausearch -m avc’, but it won’t give you much information. I prefer to use the audit2allow program to tell me what SELinux blocked and why it blocked it. These are the commands I run when I need to make an exception in SELinux:
cd /etc/selinux/targeted/modules/active/src
cat /var/log/audit/audit.log | audit2allow -m local
vi local.te (make the appropriate changes)
checkmodule -M -m -o local.mod local.te
semodule_package -o local.pp -m local.mod
semodule -i local.pp

Make sure that the checkmodule command is successful before continuing. That will let you know if you are missing something or have a typo.

One important thing to note, don’t setup exceptions when a simple chcon will fix the issue. I’ve run into many situations where the files in question had the incorrect context. For example, my webserver was unable to read a file that I had moved into /var/www/html. The conext of the file was not set to allow Apache to read the file. I could have setup an exception in the local policy, but the correct action was to run ‘chcon unconfined_u:object_r:httpd_sys_content_t:s0‘ on the file.

SELinux does not log all blocks by default. There are some things that are categorized as ‘dontaudit’. It is possible to turn off the ‘dontaudit’ policy, but you will be flooded with logs for syscalls that are not necessarily causing problems. I have only run into one issue that required me to turn off ‘dontaudit’ to fix an application. To disable ‘dontaudit’, run ‘semodule -DB‘. The ‘dontaudit’ policy will re-enable itself when SELinux is reloaded or the system is rebooted. To find the problematic policy after ‘dontaudit’ is disabled, run ‘sesearch –dontaudit -s httpd_t‘ where httpd was the type causing problems.
Here is my local.te file:

module local 1.2;
require {
 class dir { open getattr search write read remove_name add_name };
 class file { create open read write execute execute_no_trans getattr };
 class chr_file { create open read write execute execute_no_trans getattr };
 class process { execmem siginh noatsecure rlimitinh };
 class udp_socket listen;
 class unix_stream_socket { read write };
 type admin_home_t;
 type audisp_t;
 type auditd_t;
 type auditd_etc_t;
 type auditd_log_t;
 type awstats_t;
 type chkpwd_t;
 type httpd_t;
 type init_t;
 type insmod_t;
 type iptables_t;
 type load_policy_t;
 type logrotate_t;
 type mount_t;
 type mysqld_safe_t;
 type nfs_t;
 type postfix_cleanup_t;
 type postfix_local_t;
 type postfix_master_t;
 type postfix_pickup_t;
 type postfix_qmgr_t;
 type postfix_showq_t;
 type postfix_smtpd_t;
 type postfix_smtp_t;
 type proc_t;
 type rpcbind_t;
 type rpcd_t;
 type rpm_var_lib_t;
 type setroubleshootd_t;
 type sshd_t;
 type system_dbusd_t;
 type unconfined_t;
 type urandom_device_t;
 type usr_t;
 type var_lib_t;
 type var_log_t;
 type var_t;
 type user_tmp_t;

#============= auditd_t ==============
 allow auditd_t audisp_t:process { siginh noatsecure };

#============= awstats_t ==============
 allow awstats_t admin_home_t:dir { getattr search };
 allow awstats_t proc_t:file read;
 allow awstats_t var_lib_t:dir search;

#============= httpd_t ==============
 allow httpd_t nfs_t:file { execute execute_no_trans };
 allow httpd_t usr_t:file write;

#============= iptables_t ==============
 allow iptables_t insmod_t:process { siginh rlimitinh noatsecure };

#============= load_policy_t ==============
 allow load_policy_t init_t:unix_stream_socket { read write };

#============= logrotate_t ==============
 allow logrotate_t var_t:dir { add_name read write remove_name };
 allow logrotate_t var_t:file getattr;

#============= mount_t ==============
 allow mount_t rpcd_t:process { siginh rlimitinh noatsecure };

#============= mysqld_safe_t ==============
 allow mysqld_safe_t var_log_t:file open;

#============= postfix_master_t ==============
 allow postfix_master_t postfix_cleanup_t:process { siginh rlimitinh noatsecure };
 allow postfix_master_t postfix_local_t:process { siginh rlimitinh noatsecure };
 allow postfix_master_t postfix_pickup_t:process { siginh rlimitinh noatsecure };
 allow postfix_master_t postfix_qmgr_t:process { siginh rlimitinh noatsecure };
 allow postfix_master_t postfix_showq_t:process { siginh rlimitinh noatsecure };
 allow postfix_master_t postfix_smtp_t:process { siginh rlimitinh noatsecure };
 allow postfix_master_t postfix_smtpd_t:process { siginh rlimitinh noatsecure };

#============= rpcbind_t ==============
 allow rpcbind_t self:udp_socket listen;

#============= rpcd_t ==============
 allow rpcd_t self:udp_socket listen;

#============= setroubleshootd_t ==============
 allow setroubleshootd_t rpm_var_lib_t:file write;
 allow setroubleshootd_t rpm_var_lib_t:dir write;

#============= sshd_t ==============
 allow sshd_t chkpwd_t:process { siginh rlimitinh noatsecure };

#============= system_dbusd_t ==============
 allow system_dbusd_t setroubleshootd_t:process { siginh rlimitinh noatsecure };

#============= unconfined_t ==============
 allow unconfined_t self:process execmem;

#============= audisp_t ==============
 allow audisp_t var_log_t:file { create open read write execute execute_no_trans getattr };
 allow audisp_t var_log_t:dir { write add_name };
 allow audisp_t auditd_etc_t:dir { read search open };
 allow audisp_t auditd_etc_t:file { read open getattr };
 allow audisp_t auditd_log_t:dir { read search open };
 allow audisp_t auditd_log_t:file { read open getattr };
 allow audisp_t urandom_device_t:chr_file { read open getattr };

Linux audit configuration on

Anyone who has seen the Linux Audit logs will quickly disregard it’s usefulness on first glance.  It is a deluge of nonsensical hexadecimals with almost no value.  With a little Perl and Splunk, I have made it a powerful forensics tool.  I can view command history, egress connections, file changes, and socket binds.
I wrote a plugin to audisp that is available on SourceForge at  The audisp daemon is an event multiplexer that allows for plugins to process audit data.  My audisp plugin simply reads the data from stdin, consolidates relevent information from the multiple lines per event, and outputs to a logfile in a key=value format that is easily consumed by Splunk. My plugin will also translate uid to login names and translate saddr fields from bind/connect syscalls.

For example, here is the difference between the output from the Linux ausearch command compared to the output of my program. This is from a single command, uname -a

type=PATH msg=audit(1380483704.387:146400): item=1 name=(null) inode=2233758 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:ld_so_t:s0
type=PATH msg=audit(1380483704.387:146400): item=0 name=”/bin/uname” inode=2228517 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:bin_t:s0
type=CWD msg=audit(1380483704.387:146400):  cwd=”/root”
type=EXECVE msg=audit(1380483704.387:146400): argc=2 a0=”uname” a1=”-a”
type=SYSCALL msg=audit(1380483704.387:146400): arch=c000003e syscall=59 success=yes exit=0 a0=1967b30 a1=195b3e0 a2=18a1270 a3=7fffaeeda150 items=2 ppid=2437 pid=9596 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 ses=3 tty=pts1 comm=”uname” exe=”/usr/bin/uname” subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=”EXECVE”

And here is the log from my program:

type=EXECVE key=EXECVE auditid=146400 time=”2013-09-29 14:41:44-0500″ host=”” tty=pts1 ppid=2437 pid=9596 origuser=mkirby user=root cwd=”/root” command=”uname -a”

Once it is in Splunk, I can easily search for command history from different users and piece together an entire shell session through the tty and ppid. My favorite key is the auid, which is the original login id. Almost all system changes are performed as the root user. If you need to trace who made a change as root, the auid will show that. My plugin will rename uid to “user” and auid to “origuser”.

Here is the Splunk query that I run: source=”/var/log/audisp-simplify” |table _time key tty ppid origuser user cwd exe name saddr command |sort _time desc


Here is the content from my wiki for further explanation and instructions:

This program is an audisp plugin that will make audit events from the Linux Audit daemon human readable.
It will look for execve, socketcall, bind, and connect system calls as well as filesystem changes (if you setup audit rules) and consolidate the events into a simple log format.
The log is in key=value format for easy consumption from Splunk or other log analytic software.
Here is a Splunk query that I run: source=”/var/log/audisp-simplify” |table _time key tty ppid origuser user cwd exe name saddr command |sort _time desc
The logs include the auid, which is the original login id. This is beneficial for seeing who made the syscalls after su’ing to another user such as root.

Here is an execve syscall example of a shell command, uname -a, executed as myself after su’ing to root:
type=EXECVE key=EXECVE auditid=143600 time=”2013-09-29 13:33:08-0500″ host=”” tty=pts1 ppid=2437 pid=8189 origuser=mkirby user=root cwd=”/var/log” command=”uname -a”

Here is an example of /etc/hosts being edited:
type= key=FILE auditid=143645 time=”2013-09-29 13:36:19-0500″ host=”” tty=pts1 ppid=2437 pid=8208 origuser=mkirby user=root cwd=”/var/log” exe=”/usr/bin/vi” name=”/etc/hosts”

Here is a connect syscall example of an egress connection to
type=SOCKADDR key=CONNECT auditid=143682 time=”2013-09-29 13:38:49-0500″ host=”” tty=pts1 ppid=2437 pid=8229 origuser=mkirby user=root saddr=” port 443″ exe=”/usr/bin/telnet”

Here is a bind syscall example of httpd binding to port 443:
type=SOCKADDR key=BIND auditid=143745 time=”2013-09-29 13:39:31-0500″ host=”” tty=(none) ppid=1 pid=8252 user=root saddr=” port 443″ exe=”/usr/sbin/httpd”

INSTALLATION for RedHat, Centos, Scientific Linux, and Fedora
1. Place the script in /bin/ and chmod it to 750
2. Install the audit and audispd-plugins packages
3. Enable auditd on bootup and start the service
4. Create a new file, /etc/audisp/plugins.d/simplify.conf and add the following:

active = yes
direction = out
path = /bin/audisp-simplify
type = always
format = string

5) Increase queue in /etc/audisp/audispd.conf and set overflow_action to ignore
      q_depth = 65536
      overflow_action = ignore

5. Replace /etc/audit/audit.rules with the following: (you may want to add/del to dir monitoring)

    # delete all existing rules
    # disable auditing during load
    -e 0
    # fail silently
    -f 0
    # 65k buffer
    -b 65536
    # no rate
    -r 0
    # continue loading if bad rule and report
    # Add any other dirs you want monitored for file writes
    # These can be noisy during patching.  Enable at your own risk
    #-w /etc/ -p w -k FILE
    #-w /root/ -p w -k FILE
    #-w /var/spool/at/ -p w -k FILE
    #-w /var/spool/cron/ -p w -k FILE
    #-w /usr/lib/ -p w -k FILE
    #-w /usr/lib64/ -p w -k FILE
    #-w /usr/libexec/ -p w -k FILE
    #-w /usr/bin/ -p w -k FILE
    #-w /usr/sbin/ -p w -k FILE
    #-w /usr/local/ -p w -k FILE
    #-w /boot/ -p w -k FILE
    # Monitor commands
    -a exit,always -F arch=b32 -S execve -k EXECVE
    -a exit,always -F arch=b64 -S execve -k EXECVE
    # Monitor network connections.
    # These are VERY noisy.  Enable at your own risk
    #-a exit,always -F arch=b32 -S socketcall -k SOCKETCALL -F exit!=-2
    #-a exit,always -F arch=b64 -S bind -k BIND -F exit!=-2
    #-a exit,always -F arch=b64 -S connect -k CONNECT -F exit!=-2
    # activate auditing
    -e 1

6. Modify /etc/audisp/audispd.conf and change the q_depth to 32768.
7. Setup log rotation by creating /etc/logrotate.d/audisp-simplify
Add the following:

        rotate 30
        create 0600 root root
            /sbin/service auditd restart >/dev/null 2>&1 || true
            /bin/systemctl reload auditd.service >/dev/null 2>&1 || true

8.  [OPTIONAL] Setup an ignores file for strings that you don’t want logged.
Create a new file /etc/audisp/simplify.ignores and use key=value pairs to specify what you don’t want logged.
The string values can be in Perl regex format.
Here is an example of my file:
        saddr=.*port 53
        saddr=::::::: port
9. Restart the auditd service
10. Done. Now you can watch the simple audit logs in /var/log/audisp-simplify
11. Periodically look at the output of auditctl -s.  If it says that logs are lost, increase the q_depth in audispd.conf and the buffer, -b, in audit.rules

If you are running SELinux, you may want to add the following to your local policy.
Add these lines to /etc/selinux/targeted/modules/active/src/local.te

module local 1.0;
require {
class dir { open getattr search write read remove_name add_name };
class file { create open read write execute execute_no_trans getattr };
type audisp_t;
type auditd_t;
type auditd_etc_t;
type auditd_log_t;
type var_log_t;
allow audisp_t var_log_t:file { create open read write execute execute_no_trans getattr };
allow audisp_t var_log_t:dir { write add_name };
allow audisp_t auditd_etc_t:dir { read search open };
allow audisp_t auditd_etc_t:file { read open getattr };
allow audisp_t auditd_log_t:dir { read search open };
allow audisp_t auditd_log_t:file { read open getattr };

and then run

cd /etc/selinux/targeted/modules/active/src/
checkmodule -M -m -o local.mod local.te
semodule_package -o local.pp -m local.mod
semodule -i local.pp

fstab mount options on

I have made modifications to several mountpoints on the system.

By default, /tmp and /var/tmp are part of the filesystem.  I made the following modification to /etc/fstab to mount a 20mb slice of memory to those directories.  I have also set the mount options to nodev, noexec, and nosuid.  This means that those directories will not be able to contain device files or executables.  This prevents hackers from uploading an executable to the directories or creating any devices that may circumvent the security.
tmpfs                   /tmp                tmpfs   nodev,noexec,nosuid,size=20m        0 0
tmpfs                   /var/tmp                tmpfs   nodev,noexec,nosuid,size=20m        0 0


By default, Fedora mounts /dev/shm as a memory filesystem.  I added the noexec, nosuid, and nodev options.
tmpfs                   /dev/shm                tmpfs   noexec,nosuid,nodev        0 0


By default,  /dev/pts is mounted with world-readable permissions for the directory.  I added mode=620 so that users would not be able to see who was logged in.  The side effect of this is that the users are unable to know what tty they are on.  I have not run into any issues with this yet.
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0


I have one nfs mount that contains website files.  I set it to nosuid and nodev for security, but not noexec as there are files on the nfs mount that need execute permissions.  There is also a SELinux boolean called httpd_use_nfs, but I’ll cover that in another post.  The nfs mount is set to read-only, which is redundant as the nfs server exports it as read-only.            /a1             nfs timeo=14,intr,vers=3,ro,nosuid,nodev,nolock


There is one mountpoint in Fedora that I could not configure through fstab.  It’s /dev/mqueue.  In order to add the nodev, noexec, nosuid options, I setup a cronjob that executes the following:
/bin/mount -o remount,nodev,noexec,nosuid /dev/mqueue


sysctl on

The following is from my /etc/sysctl.conf with the documentation inline.
Some of the settings are default, but I like to reiterate these with comments so that I know why these are set.

# kernel pointers using %pK are printed as 0’s regardless of privileges
# Add the %pK printk format specifier and the /proc/sys/kernel/kptr_restrict sysctl.
# The %pK format specifier is designed to hide exposed kernel pointers,
# specifically via /proc interfaces.  Exposing these pointers provides an
# easy target for kernel write vulnerabilities, since they reveal the
# locations of writable structures containing easily triggerable function
# pointers.  The behavior of %pK depends on the kptr_restrict sysctl.
kernel.kptr_restrict = 2

# only users with CAP_SYS_ADMIN can read the kernel syslog via dmesg
kernel.dmesg_restrict = 1
#Enable ExecShield protection.  This is set by default.
kernel.exec-shield = 1

# Address Space Layout Randomization (ASLR). This is set to ‘1’ by default.
# ASLR involves randomly arranging the positions of key data areas of a program, including the base of the executable and the positions of the stack, heap, and libraries, in a process’s address space.
# Options are:
# 0 – disable ASLR
# 1 – Conservative address space randomization. Code start register will be randomized. (This is the default)
# 2 – Full address space randomization. Contains the feature of value 1 in addition brk area is randomized.
kernel.randomize_va_space = 2

# Disable source routes and redirects.
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.default.secure_redirects = 0

# Ignore all ICMP ECHO and TIMESTAMP requests sent to it via broadcast/multicast
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Prevent against the common syn flood attack
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_synack_retries = 2

# Enable source validation by reversed path, as specified in RFC1812
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# This is just a server, so disable redirects.
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

# Deny SRR
net.ipv4.conf.all.accept_source_route = 0

# This is a server, not a router. Disable IP forwarding. (disabled by default)
net.ipv4.ip_forward = 0

# Controls the System Request debugging functionality of the kernel
kernel.sysrq = 0

# Controls whether core dumps will append the PID to the core filename
# Useful for debugging multi-threaded applications
kernel.core_uses_pid = 1



IPTables configuration on

The firewall configuration at involves a PFSense firewall at the edge and a host-based iptables firewall.
The webserver is on a dedicated vlan to separate it from my other internal servers/desktops.

The following lines set the default for INPUT/OUTPUT/FORWARD to drop the packets. It also sets the chain for INPUTDROPLOG and OUTPUTDROPLOG, which is used as an explicit drop so that it may also be logged.

:ACCEPTLOG – [0:0]

The INPUTDROPLOG and OUTPUTDROPLOG chains will first log the packet and then drop the packet. This is one of my biggest annoyances with iptables because all the other firewalls I have dealt with provide logging and dropping/allowing on the same line.
The limit feature sets the logging to a maximim of 60 logs per minute. This prevents log flooding. The log-prefix is what is prepended to the log, which I choose to use as a comment field. The log-tcp-sequence, log-tcp-options, and log-ip-options are usually not useful, but doesn’t hurt to log it nonetheless. The log-uid can only be used on output rules. This is very useful as my other rules restrict egress access based on user. It also serves as an indication that a service account may have been compromised.

-A OUTPUTDROPLOG -j LOG -m limit –limit 60/min –log-prefix “COMMENT=outputdroplog ” –log-tcp-sequence –log-tcp-options –log-ip-options –log-uid
-A INPUTDROPLOG -j LOG -m limit –limit 60/min –log-prefix “COMMENT=inputdroplog ” –log-tcp-sequence –log-tcp-options –log-ip-options –log-uid
-A ACCEPTLOG -j LOG -m limit –limit 60/min –log-prefix “COMMENT=acceptlog ” –log-tcp-sequence –log-tcp-options –log-ip-options –log-uid

The following lines allow services for ssh, smtp, smtps, http, https, etherpad, bind, and splunk. Any service that is not public is restricted to specific networks/IPs. After the services are defined, the INPUTDROPLOG will log everything that is dropped.

-A INPUT -p tcp -m tcp -m multiport –dports 22,25,465,80,443,9001 -j ACCEPTLOG
-A INPUT -p tcp -m tcp -s –dport 953 -j ACCEPT
#-A INPUT -p tcp -m tcp -s -m multiport –dports 8000,8089 -j ACCEPT
-A INPUT -p tcp -m tcp -s -m multiport –dports 53,953,8000,8089 -j ACCEPT
-A INPUT -p tcp -m tcp -s -m multiport –dports 53,953 -j ACCEPT
-A INPUT -p udp -m udp –dport 53 -j ACCEPT

The following lines allow access from this server to my internal servers. The first line will instantly drop any connection from a user (4294967294 is the maximum uid on Linux). The other lines allow for nfs and splunk. Notice that the nfs lines do not filter based on uid. This is because nfs is performed at the kernel-level and not userspace, meaning there will not be a uid associated with the sockets.

-A OUTPUT -d -m owner –uid-owner 1-4294967294 -j OUTPUTDROPLOG
-A OUTPUT -p tcp -m tcp -d -m multiport –dports 111,2049,20000:65535 -j ACCEPT
-A OUTPUT -p udp -m udp -d -m multiport –dports 111,2049,20000:65535 -j ACCEPT
-A OUTPUT -p tcp -m tcp -d -m multiport –dports 111,2049,20000:65535 -j ACCEPT
-A OUTPUT -p udp -m udp -d -m multiport –dports 111,2049,20000:65535 -j ACCEPT
-A OUTPUT -p tcp -m tcp -d -m owner –uid-owner root –dport 9997 -j ACCEPT

These lines allow services to itself such as dns, smtp/s, and http/s.

-A OUTPUT -p udp -m udp -d –dport 53 -j ACCEPT
-A OUTPUT -p udp -m udp -d –dport 53 -j ACCEPT
-A OUTPUT -p udp -m udp -d –dport 53 -j ACCEPT
-A OUTPUT -p tcp -m tcp -d –dport 25 -j ACCEPT
-A OUTPUT -p tcp -m tcp -d –dport 25 -j ACCEPT
-A OUTPUT -p tcp -m tcp -d –dport 25 -j ACCEPT
-A OUTPUT -p tcp -m tcp -d –dport 465 -j ACCEPT
-A OUTPUT -p tcp -m tcp -d –dport 465 -j ACCEPT
-A OUTPUT -p tcp -m tcp -d –dport 465 -j ACCEPT
-A OUTPUT -p tcp -m tcp -s -d -m multiport –dports 80,443 -m owner –uid-owner apache -j ACCEPT

These rules block access to any rfc1918 networks. The internal network services was already covered above and there isn’t any need for any other access to my internal networks. If a user were to try to run an internal scan, I would see it in the logs. The PFSense firewall also filters this access in case iptables is unloaded.

-A OUTPUT -p tcp -m tcp -d -j OUTPUTDROPLOG
-A OUTPUT -p tcp -m tcp -d -j OUTPUTDROPLOG
-A OUTPUT -p tcp -m tcp -d -j OUTPUTDROPLOG

These rules allow only the named service to connect outbound for port 53, which is used for lookups. The resolv.conf is set to use the localhost, so the other users do not need to egress on 53.

-A OUTPUT -p tcp -m tcp -m owner –dport 53 –uid-owner named -j ACCEPT
-A OUTPUT -p udp -m udp -m owner –dport 53 –uid-owner named -j ACCEPT

This rule allows only the postfix service to connect outbound for smtp/s.

-A OUTPUT -p tcp -m tcp -m owner -m multiport –dports 25,465 –uid-owner postfix -j ACCEPT

This rule allows the chrony service to egress on udp/123. Chrony is Fedora’s replacement for NTP.

# chrony
-A OUTPUT -p udp -m udp -m owner –dport 123 –uid-owner chrony -j ACCEPT

These rules allow for return packets on bad/stale connections. I discovered that this was necessary after reviewing the iptables logs and seeing dropped FIN/RST packets. The rules will examine the tcp flags for the syn flag. The –tcp-flags will check the syn flag and only match if it is not set (aka none). The rules allow for egress from a source port and only from the respective service account, the root user, or the kernel. The “! –uid-owner 1-4294967294” tells iptables that only the root account (uid 0) or the kernel (no uid) is permitted to egress.

-A OUTPUT -p tcp -m tcp -m owner -m multiport –sports 25,465 –tcp-flags SYN NONE ! –uid-owner 1-4294967294 -j ACCEPT
-A OUTPUT -p tcp -m tcp -m owner -m multiport –sports 25,465 –tcp-flags SYN NONE –uid-owner postfix -j ACCEPT
-A OUTPUT -p tcp -m tcp -m owner -m multiport –sports 80,443 –tcp-flags SYN NONE ! –uid-owner 1-4294967294 -j ACCEPT
-A OUTPUT -p tcp -m tcp -m owner -m multiport –sports 80,443 –tcp-flags SYN NONE –uid-owner apache -j ACCEPT

These lines allow the root user and the kernel to egress. The only time this is used is when I patch the server, which a nightly cronjob. All other egress packets are dropped and logged.

-A OUTPUT -m owner ! –uid-owner 1-4294967294 -j ACCEPT