first commit
101
Changelog.md
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
## January 24, 2024
|
||||||
|
* Change default umask to 027
|
||||||
|
|
||||||
|
## January 19, 2024
|
||||||
|
* Enabled pf firewall by default in settings.ini
|
||||||
|
|
||||||
|
## January 17, 2024
|
||||||
|
* After testing, re-introduced the Sendmail/MTA disable
|
||||||
|
|
||||||
|
## January 16, 2024
|
||||||
|
**New settings**
|
||||||
|
Enhanced DoS/DDoS mitigation
|
||||||
|
* `net.inet6.icmp6.rediraccept = 0` to prevent ICMP attacks. Only FreeBSD as a network appliance would benefit enabling this setting.
|
||||||
|
* `net.inet.tcp.drop_synfin = 1` to mitigate TCP SYN-FIN attacks and stealth probing.
|
||||||
|
* `net.inet.tcp.cc.algorithm=htcp` enable TCP congestion alleviation
|
||||||
|
|
||||||
|
[H-TCP](https://www.sciencedirect.com/science/article/pii/S0965997821000399#bib0017) is a congestion control protocol for high-speed and long distance networks. It uses bandwidth estimation and changes the TCP window increase/decrease parameters according to the estimated minimal and maximal bandwidth. It takes into consideration that the parameter for additive increase should be small in slower networks and should be large in high-speed and long distance networks in order to achieve fast adaptation to the available bandwidth.
|
||||||
|
|
||||||
|
DoS/DDoS mitigation via network performance tuning for high-speed network servers, used by default on Vultr FreeBSD 14.0 cloud servers.
|
||||||
|
* `kern.ipc.maxsockbuf=67108864`
|
||||||
|
* `net.inet.tcp.sendbuf_max=67108864`
|
||||||
|
* `net.inet.tcp.recvbuf_max=67108864`
|
||||||
|
* `net.inet.tcp.sendbuf_auto=1`
|
||||||
|
* `net.inet.tcp.recvbuf_auto=1`
|
||||||
|
* `net.inet.tcp.sendbuf_inc=16384`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**NOTE**
|
||||||
|
* `net.inet.tcp.syncache.hashsize, cachelimit, and bucketlimit` Were last updated for 2016 Computing Hardware and should be made tunable, currently they are read-only and serve to make SYN FLOOD DoS attacks easier.
|
||||||
|
|
||||||
|
## January 8, 2024
|
||||||
|
* ZenBleed workaround removed as it is now enable by default in 14 release
|
||||||
|
* 32bit protections removed as FreeBSD is focusing on 64bit and in the future dropping support for 32bit
|
||||||
|
* PIE, ASLR for 32bit
|
||||||
|
* Sendmail limitations removed since the 14.0 MTA in use is now the more secure Dragonfly Mail Agent
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## August 22, 2023
|
||||||
|
* Removed devcpu-data-amd as the re-worked port installs both AMD and Intel with command `devcpu-data`
|
||||||
|
* https://cgit.freebsd.org/ports/commit/?id=bc7829212d153aeff69b439d08e2e3001ef88ba3
|
||||||
|
|
||||||
|
## August 20, 2023
|
||||||
|
* Printing clean-up
|
||||||
|
* Fixed error in microcode matching
|
||||||
|
* Fixed Virtual Machine vs Bare Metal c shell bug in string matching
|
||||||
|
|
||||||
|
## August 19, 2023
|
||||||
|
* Zenbleed_workdaround.csh fixes
|
||||||
|
* at reminder fixes
|
||||||
|
* CPU Model detection fixed
|
||||||
|
* AMD Threadripper Pros are still not being detected properly
|
||||||
|
|
||||||
|
## August 13, 2023
|
||||||
|
* Updated to give notice that no Zenbleed affected CPU was found.
|
||||||
|
|
||||||
|
## August 11, 2023
|
||||||
|
* The rc script has been updated for better performance and stability
|
||||||
|
* There is no positive value cases I can find for removing the chicken-bit during operation which on the contrary may produce unexpected results as with other workarounds of this type
|
||||||
|
* Rebooting without the rc script running returns the OS to an unset chicken-bit state which obviates the need to have a `rc` chicken-bit removal function.
|
||||||
|
* The user chooses the workaround or not without the rc script making available CPU state changes while in operation possibly inducing kernel crashes
|
||||||
|
* Simply using the `remove` argument and rebooting will return the AMD Zenbleed vulnerability -> MSR state to default
|
||||||
|
* Fixed Syntax errors and word clarity in the main workaround file
|
||||||
|
* Added a prompted reminder function using `at` to create a file in the home directory reminding the user to use the official patch due at that time and remove the workaround
|
||||||
|
* Changed the user text notice after a microcode update for better security and stability
|
||||||
|
1. Rebooting once should show clean startup with new microcode but still keep the tools in case of reversion
|
||||||
|
2. Use the `clean` function to remove the conf directives that load the still loaded promiscuous cpu tools
|
||||||
|
3. Rebooting again to load without promiscuous cpu tools
|
||||||
|
|
||||||
|
## August 8, 2023
|
||||||
|
* `settings.ini`
|
||||||
|
* `microcode_update_enable` set to "YES" in preparation for Zenbleed and Downfall Updates
|
||||||
|
* AMD Zenbleed mitigation script was added
|
||||||
|
|
||||||
|
|
||||||
|
## June 28, 2023
|
||||||
|
* Changed requirements to be 13.1, 13.2 as this is when most security directives were added
|
||||||
|
* Remove much conf syntax verification to work on all FreeBSD confs instead of just default installs
|
||||||
|
* Reverted 64bit ASLR protections to 32bit since these were on by default since 13.1
|
||||||
|
* `hw.mds_disable` was set at 3, AUTO
|
||||||
|
* Removed `vm.pmap.pti = "1"` since this was on by default
|
||||||
|
|
||||||
|
|
||||||
|
## June 27, 2023
|
||||||
|
* FreeBSD hardening script /usr/libexec/bsdinstall/hardening sets `security.bsd.allow_destructive_dtrace` is formatted improperly with the flag without quotes as in `/boot/defaults/loader.conf` and man. Script sets it properly.
|
||||||
|
* Test DTrace hardening: Using all 3 commands should result in `Permission denied` or `Destructive actions not allowed`:
|
||||||
|
* `dtrace -wn 'tcp:::connect-established { @[args[3]->tcps_raddr] = count(); }'`
|
||||||
|
* `dtrace -wqn tick-1sec'{system("date")}'`
|
||||||
|
* `dtrace -qn tick-1sec'{system("date")}'`
|
||||||
|
* New setting `vm.pmap.pti = 0`
|
||||||
|
* Setting `kern.securelevel` to `0` has no effect as FreeBSD will increment to 1 disallowing script execution. README changed to reflect this.
|
||||||
|
* Error message conformity and clarity improvement.
|
||||||
|
* Script now exits any time it restores a file to prevent partial writes and locked files.
|
||||||
|
* Some sysctl.conf settings moved over to loader.conf section for better security
|
||||||
|
|
||||||
|
|
||||||
|
## June 23, 2023
|
||||||
|
* 64bit ASLR setting was reverted back to 32bit enable as 64bit is enabled by default.
|
||||||
|
* `kern.randompid` works better if the number is manually set over 100 and is a prime [(*)](https://reviews.freebsd.org/transactions/detail/PHID-XACT-DREV-76pds6dxlcy5er6/)
|
||||||
144
LICENSE.md
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
# Quadhelion Engineering Universal Software License
|
||||||
|
|
||||||
|
[URL](https://www.quadhelion.engineering/qhelp.html)
|
||||||
|
|
||||||
|
## QHELP-OME-NC-ND-HI
|
||||||
|
|
||||||
|
**Legend:**
|
||||||
|
|
||||||
|
* (Q)had(H)elion(E)ngineering (L)icense (P)ermission
|
||||||
|
* (O)btain (M)odify (E)xecute
|
||||||
|
* (N)on-(C)ommercial
|
||||||
|
* (N)o (D)erivatives
|
||||||
|
* (H)uman (I)ntelligence
|
||||||
|
|
||||||
|
All entities are Universally bound by the terms and conditions of this license as it is inseparable to the Software using this license. This license grants no other rights than detailed herein.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Executive Summary
|
||||||
|
|
||||||
|
Non-Commercial usage, retain and forward author and license data. Modify existing code as needed up to 25% while allowing unlimited new additions. The Software may use or be used by other software.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Section 1 – Definitions.
|
||||||
|
|
||||||
|
* **Universal** is defined as all the states of existence. If exists, this License applies.
|
||||||
|
* **Software** is defined as means used to produce a desired result on a calculating device accompanying and referencing this License.
|
||||||
|
* **Creator** is defined as the natural human being that created the Software here designed in his mind and written down to Obtain and Execute.
|
||||||
|
* **License** is defined as what all entities other than the Creator of the Software allows to be done with the software.
|
||||||
|
* **Licensee** is defined as all entities other than the Creator of the Software.
|
||||||
|
* **Obtain** is defined as having knowledge of the means used in the Software.
|
||||||
|
* **Modify** is defined as making changes to the Execution of the Software in conformance with the existing Execution process in majority, utilizing the same data types of input and output originally used by the Software, retaining the intended use of the Execution of the Software in superset of subset of solutions, workflows, processing, intake, and production in general, but not in detail.
|
||||||
|
* **Execute** is defined as having a calculating device calculate the Software.
|
||||||
|
* **Intelligence** is defined as having the ability to solve complex problems with judgement.
|
||||||
|
* **Human** is defined as Homo sapiens birthed from another living Female Homo sapiens.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Section 2 - Software Modification Allowance
|
||||||
|
|
||||||
|
The software **may not** be modified in the following ways:
|
||||||
|
|
||||||
|
* The Software logic itself cannot be changed *in majority*.
|
||||||
|
* The original *application* to which the Software *was applied* cannot be modified.
|
||||||
|
* Changing or replacing of **more than 25%** of the existing programming code of the Software is **not allowed**. This does not include error handling, metadata or comments.
|
||||||
|
* Programming language comments cannot be modified.
|
||||||
|
* Metadata cannot be modified.
|
||||||
|
* Author and License information cannot be modified.
|
||||||
|
* You may not adapt, translate, reverse engineer, decompile, disassemble, or otherwise reuse the Software code, Software logic, or logic designs of the Software.
|
||||||
|
* The Software may not be re-created or re-generated in whole or in part in another programming language or by any means except by permission of the Creator.
|
||||||
|
|
||||||
|
**The Software may be modified in the following ways:**
|
||||||
|
|
||||||
|
1. Any modification must retain the majority of functionality in conformance with the original Software.
|
||||||
|
2. The Software can only be modified with the original programming language it was written in.
|
||||||
|
3. The Software may be used by other software. The Software may use other software.
|
||||||
|
4. Allowance of additional new programming code and comments to the Software is unlimited.
|
||||||
|
|
||||||
|
**Examples of how the Software may be modified:.**
|
||||||
|
|
||||||
|
1. The application of the Software is the computer systems and components to which the Software originally Executed; that being the data, systems, processes, inputs and outputs, and categories or types of computers, systems, data, I/O, and components the Software interacts with upon Execution.
|
||||||
|
1. For example, if the Software Executes outputing Firewall rules and reloading those rules in a Firewall than it is not allowed to modify this Software to simply produce files that are distributed on FTP.
|
||||||
|
1. Removing a Software function of only two functions is not majority conformance.
|
||||||
|
2. Unlimited new functions and functionality can be added.
|
||||||
|
3. Software logic can be changed without removing the majority of functions or functionality.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Section 3 – Scope.
|
||||||
|
|
||||||
|
**License granted.**
|
||||||
|
|
||||||
|
Subject to the terms and conditions of this License, the Creator hereby grants the following exclusive entities permission to Execute the Software which meet both the following conditions:
|
||||||
|
|
||||||
|
1. Natural Human Beings
|
||||||
|
1. Genus and Species commonly classified as *Homo Sapiens*, born on the same known world terra firma as the Creator was born on, being birthed by a Female Natural Human Being.
|
||||||
|
2. Non-Commercial Entities
|
||||||
|
1. Entities who are not profit motivated and are not substantially valued.
|
||||||
|
2. All Corporations type Limited Liability Company (LLC), S-Corporation (S-Corp), and C-Corporation (C-Corp) are strictly forbidden from Software Obtainment and Execution and cannot be a Licensee.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**License denied.**
|
||||||
|
|
||||||
|
1. Non-Human Intelligences such as Artificial Intelligence, Generative, Language Models, or Generated Intelligences have no permissions to Obtain, Modify or Execute.
|
||||||
|
1. Any computational analysis or automata characterized as Intelligence has no allowance or License to Obtain, Modify, or Execute the Software.
|
||||||
|
2. Any sentience that was not birthed from a living Female Human Being has no allowance or License to Obtain, Modify, or Execute the Software.
|
||||||
|
2. Patents, Trademarks, Copyrights, and legal or financial instruments, or applications to the Software, it's Execution, or it's License thereof is strictly prohibited.
|
||||||
|
3. Derivations, re-creations, re-generations, and adaptations of the Software are strictly prohibited.
|
||||||
|
4. Effective technological measures, Effective protective technological measures, and any prevention or limitation placed on the exercise of the Licensee's Execution of the Software is strictly prohibited.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Licensor.**
|
||||||
|
|
||||||
|
This words and expressions of allowance and denial contained are here the License which in totality and in summary the whole of this formatted document is itself the Licensor. Adhering to the provisions of this License constitutes a Licensee. The Creator himself is not the Licensor and is not in contract in any way with any entity.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Section 4 – License Conditions.
|
||||||
|
|
||||||
|
Your exercise of the Licensed Rights is expressly made subject to the following conditions.
|
||||||
|
|
||||||
|
The Licensee must:
|
||||||
|
|
||||||
|
1. **Retain** the License, usually the file LICENSE.md, with the Software.
|
||||||
|
1. All information contained in the Software referring to the License and Identity of the Creator.
|
||||||
|
2. All Author information including URLs, dates, emails, must be retained.
|
||||||
|
3. This License file must be maintained at all times alongside the Software.
|
||||||
|
|
||||||
|
2. **Indicate** the Licensed Software is licensed under this License
|
||||||
|
1. Include the text of, the file of, or the URI or hyperlink to, this License, *pertinent* to any entity that is not aware of this Copyright, Trademark, Patent, or, License, of this Software.
|
||||||
|
2. This includes requests, audits, inspection, or reviews in singular or in totality of all Software used on the Calculating Device where the Software resides, referenced, or Executed;
|
||||||
|
3. The Licensee must make aware this License to all interested entities in the Software, it's means, functions, or results.
|
||||||
|
3. **Obtain, Customize, and Execute** the Software in conformance with this License.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Section 5 – Disclaimer of Warranties and Limitation of Liability.
|
||||||
|
|
||||||
|
Unless otherwise separately undertaken by the Creator, to the extent possible, the Creator offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Software, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to the Licensee.
|
||||||
|
|
||||||
|
To the extent possible, in no event will the Creator be liable to the Licensee on any legal basis or theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this License or use of the Licensed Software, even if the Creator has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to the Licensee.
|
||||||
|
|
||||||
|
The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Section 6 – Associated files.
|
||||||
|
|
||||||
|
Images and Digital Art obtained along with the Software are original works and automatically under International Copyright Law and may not be altered or distributed. Document files are original works under full Copyright of the Creator.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Section 7 – Term and Termination.
|
||||||
|
|
||||||
|
If the Licensee or any entity fails to comply with this License, then the Licensee's and entities rights under this License terminate automatically and immediately.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Section 8 – Other Terms and Conditions.
|
||||||
|
|
||||||
|
The Creator is not himself bound by these terms and conditions, allowances and denials, or any additional or different terms or conditions.
|
||||||
361
README.md
Normal file
|
|
@ -0,0 +1,361 @@
|
||||||
|
# Harden FreeBSD
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
_Table of Contents_
|
||||||
|
|
||||||
|
* [New Features](#New)
|
||||||
|
* [Additional Features](#Additional)
|
||||||
|
* [Installation](#Installation)
|
||||||
|
* [Customization](#Customization)
|
||||||
|
* [Settings Used](#Descriptors)
|
||||||
|
* [License](#License)
|
||||||
|
---
|
||||||
|
|
||||||
|
FreeBSD officially defaults to [Permanently Insecure Mode](https://man.freebsd.org/cgi/man.cgi?query=security&sektion=7&manpath=freebsd-release#SECURING_THE_KERNEL_CORE,_RAW_DEVICES,_AND_FILE_SYSTEMS). This script will duplicate all the hardening settings run by `/usr/libexec/bsdinstall/hardening` and much more. Any directive can be set and re-set with a customizable `settings.ini` for administering, tuning, and easier jail management. All existing entries in all confs will remain untouched unless they are modified in the settings file.
|
||||||
|
|
||||||
|
This script is also targeted to new users of FreeBSD so that they may leverage years of security contributions by the entire BSD community across all spectra, implemented on their system in seconds.
|
||||||
|
|
||||||
|
Each of the security settings was researched, assessed, and chosen as a set of mitigations for maximizing threat reduction while minimizing restriction of system capability and availability.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
For a more comprehensive true "hardened" solution with more security than this repo scope, which involves kernel modifications, I refer you to [HardenedBSD](https://hardenedbsd.org).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Main Features
|
||||||
|
|
||||||
|
* Makes backups of `rc.conf`, `sysctl.conf`, `login.conf`, and `loader.conf` on first run
|
||||||
|
* Disables Sendmail service, but it can still be run by command and abused.
|
||||||
|
* **Recommend**:
|
||||||
|
* `rm -rf /usr/libexec/sendmail /usr/libexec/dma` OR `chmod -R 000 sendmail dma`
|
||||||
|
* `pkg install opensmtpd`
|
||||||
|
* Sets passwords to blowfish encryption, which **is** better than SHA512 for this purpose
|
||||||
|
* [Okta Medical Device Authentication](https://auth0.com/blog/hashing-in-action-understanding-bcrypt/)
|
||||||
|
* [Security Stack Exchange](https://security.stackexchange.com/questions/133239/what-is-the-specific-reason-to-prefer-bcrypt-or-pbkdf2-over-sha256-crypt-in-pass)
|
||||||
|
* [Silver Stripe, Census Gov Contrator](https://docs.silverstripe.org/en/5/developer_guides/security/secure_coding/)
|
||||||
|
* [Google Engineer Gregory Gains](https://www.gregorygaines.com/blog/how-to-hash-and-salt-passwords-in-golang-using-sha512-and-why-you-shouldnt/)
|
||||||
|
* Sets passwords to expire at 120 days
|
||||||
|
* Removes `other` write permissions from key system files and folders
|
||||||
|
* Allows only root for `cron` and `at`
|
||||||
|
* Primitive flag verification catches simple errors
|
||||||
|
* Modularizable within other tools
|
||||||
|
* Automate any shell command
|
||||||
|
* System Logging to `/var/log/messages` and Script Logging to `/var/log/harden-freebsd.log`
|
||||||
|
* Pretty prints color output of script execution to console while running
|
||||||
|
* Sets umask to 027
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
### Includes
|
||||||
|
* Desktop Wallpapers as a special gift to users of the Software
|
||||||
|
* Directory (Hier)archy Visual Map, PDF, in /docs
|
||||||
|
* robots.txt to deny AI use of your intellectual property, with inline `nginx.conf` format and commented section for use as a plain txt file
|
||||||
|
* Robust firewall settings for pf
|
||||||
|
* You can grab icons and more Wallpapers at the [Quadhelion Engineering Development Gogs/Gitea Git Repo](https://quadhelion.dev/elias/bsd-wallpapers)
|
||||||
|
|
||||||
|
---
|
||||||
|
<a name="New"></a>
|
||||||
|
|
||||||
|
### New Features in 3.1
|
||||||
|
* A package audit is automatically run identifying vulnerabilities in installed packages and saves to file `pkg-audit-report`
|
||||||
|
* Security Tiering has been introduced with additional settings files minimal and server
|
||||||
|
* A script argument can be given naming the settings ini file you wish to use, mainly to toggle between secure and minimal, otherwise settings.ini is used
|
||||||
|
* A minimum security and high performance server tier ini files are now included
|
||||||
|
* Adjust as neccessary or make your own set
|
||||||
|
* A script argument of "restore" is now available, overwriting the changed files with the original files saved during first run
|
||||||
|
* rc.conf, sysctl.conf, and loader.conf are restored. `login.conf` and the password changes are not reversed, neither are file permissions or at, cron adjustments
|
||||||
|
* `minimum.ini` does not have `first_run = True` set as it is expected to usually run secure. Therefore if using this ini file first, **backups will not be made**.
|
||||||
|
* New wallpapers have been added with the assistance of [LimeWire BlueWillow v4](https://limewire.com/features/bluewillow-ai) Artificial Intelligence image generator.
|
||||||
|
* Change the default umask to 027
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
## Known Incompatibilities (Insecure) 09/7/2023
|
||||||
|
* **VM**:
|
||||||
|
* VirtualBox Shared Folders
|
||||||
|
* **Workstation**:
|
||||||
|
* **Firefox, Chromium** explicitly use [shared memory](https://www.usna.edu/Users/cs/crabbe/SI411/current/security/memory.html) allowing data access between private and non-private windows, tabs as well as other currently running apps.
|
||||||
|
* Conflicts with `kern.elf64.allow_wx`
|
||||||
|
* Linux Binary Compatibility
|
||||||
|
* **Server**: Nginx
|
||||||
|
|
||||||
|
|
||||||
|
### Verified Compatible
|
||||||
|
* **Workstation**:
|
||||||
|
* Librewolf, Qutebrowser, Transmission, Evolution, RhythmBox, VLC, Abiword, Gimp, Inkscape, Spacemacs, Git
|
||||||
|
* **Server**:
|
||||||
|
* Apache (w/o memcache), OpenSMTPD, MariaDB `have_dynamic_loading=YES` (with plugins)
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
## FreeBSD Security Advisories
|
||||||
|
https://www.freebsd.org/security/advisories/
|
||||||
|
|
||||||
|
**FreeBSD Update Procedure**
|
||||||
|
|
||||||
|
```
|
||||||
|
root@freebsd:~# freebsd-update fetch
|
||||||
|
root@freebsd:~# freebsd-update install
|
||||||
|
root@freebsd:~# shutdown -r +10min "Rebooting for a security update"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### FreeBSD 14.0 Security Changes
|
||||||
|
* New [Mitigations Manual](https://man.freebsd.org/cgi/man.cgi?query=mitigations&sektion=7&format=html)
|
||||||
|
* New Kernel Address Sanitizer
|
||||||
|
* [KASAN](https://man.freebsd.org/cgi/man.cgi?query=kasan&sektion=9&format=html) is a subsystem which leverages compiler instrumentation to detect invalid memory accesses in the kernel.
|
||||||
|
* The **Zenbleed bug affecting AMD Zen2 processors is now automatically mitigated** (via chicken bit), preventing misbehavior and data leaks on affected machines. If needed, applying the mitigation can be manually controlled via the machdep.mitigations.zenbleed.enable sysctl(8) knob. Please consult the new [mitigations(7)](https://man.freebsd.org/cgi/man.cgi?query=mitigations&sektion=7&format=html) manual page for more information.
|
||||||
|
* Position Independent Executable (PIE) support enabled by default on x64
|
||||||
|
* Address Space Layout Randomization (ASLR) is enabled by default on x64
|
||||||
|
* To disable for a single invocation, use the [proccontrol(1)](https://man.freebsd.org/cgi/man.cgi?query=proccontrol&sektion=1&format=html) command: `proccontrol -m aslr -s disable command.`
|
||||||
|
* To disable ASLR for all invocations of a binary, use the [elfctl(1)](https://man.freebsd.org/cgi/man.cgi?query=elfctl&sektion=1&format=html) command: `elfctl -e +noaslr file`
|
||||||
|
* A workaround has been implemented for a hardware page invalidation problem on Intel Alder Lake (twelfth generation) and Raptor Lake (thirteenth generation) hybrid CPUs.
|
||||||
|
* The default mail transport agent (MTA) is now the Dragonfly Mail Agent.
|
||||||
|
* Support has been added to the kernel crypto for the XChaCha20-Poly1035 AEAD cipher.
|
||||||
|
* The process visibility policy controlled by the `security.bsd.see_jail_proc` sysctl(8) knob was hardened.
|
||||||
|
* The process visibility policy controlled by the `security.bsd.see_other_gids` sysctl(8) knob was fixed to consider the real group of a process instead of its effective group when determining whether the user trying to access the process is a member of one of the process' groups.
|
||||||
|
|
||||||
|
---
|
||||||
|
<a name="Additional"></a>
|
||||||
|
|
||||||
|
## Additional Software
|
||||||
|
|
||||||
|
* Scripts included to verify the implementation. Run before and after the hardening.
|
||||||
|
* Kernel vulnerability diagnosis provided by [Stéphane Lesimple's](https://github.com/speed47) spectre-meltdown-checker
|
||||||
|
* `cd vendor`
|
||||||
|
* `chmod 750 spectre-meltdown-checker.sh`
|
||||||
|
* `sudo ./spectre-meltdown-checker.sh`
|
||||||
|
* You should only be left with the MCEPSC, Machine Check Exception on Page Size Change Vulnerability, [CVE-2018-12207](https://www.freebsd.org/security/advisories/FreeBSD-SA-19:25.mcepsc.asc)
|
||||||
|
* MMAP, MProtect vulnerability diagnosis provided by [u/zabolekar](https://www.reddit.com/r/BSD/comments/10isrl3/notes_about_mmap_mprotect_and_wx_on_different_bsd/)
|
||||||
|
* `cd util`
|
||||||
|
* `cc mmap_protect.c`
|
||||||
|
* `./a.out`
|
||||||
|
* You should have two successes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
# Main Details
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
* FreeBSD 14.0
|
||||||
|
* Python 3.9.16
|
||||||
|
|
||||||
|
<a name="Installation"></a>
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
**WARNING: Once kernel level 1 is set by this script, you will not be able to modify these confs again with this script until it is set to -1 and rebooted!**
|
||||||
|
|
||||||
|
* Set `kernlevel = -1` if you want to test various setting groups with your applications and network
|
||||||
|
* Customize `settings.ini` to whatever is needed, the script will change the directive to your flag
|
||||||
|
* Set permissions `chmod 750 harden-freebsd.py` to prevent shell injection from another account or process
|
||||||
|
* Set permissions `chmod 640 settings.ini` to prevent shell injection from another account or process
|
||||||
|
* No `settings.ini` section can be entirely commented out nor be completely empty
|
||||||
|
* `sudo ./harden-freebsd.py`
|
||||||
|
|
||||||
|
|
||||||
|
## Conf File Verification
|
||||||
|
|
||||||
|
`kern.vty = "vt"`
|
||||||
|
|
||||||
|
This script does primitive verification of the confs flags in strict accordance with system man. Many online tutorials even on the FreeBSD family of websites do not use the proper syntax. Check the log for any validation failures. Use proper syntax, remove the syntax checking lines 241-261, or rewrite the regular expression to make a new check suitable for you.
|
||||||
|
|
||||||
|
* For `/etc/sysctl.conf` the script checks for no quotes
|
||||||
|
* For `/boot/loader.conf` the script strictly verifies syntax from man and `/boot/defaults/loader.conf` syntax
|
||||||
|
* All directives in these sister confs must be in quotes
|
||||||
|
|
||||||
|
If you do get stuck in read-only single-user mode and need to correct a configuration file then use:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
zfs set readonly=false zroot
|
||||||
|
zfs mount -a
|
||||||
|
```
|
||||||
|
<a name="Customization"></a>
|
||||||
|
|
||||||
|
## Customization
|
||||||
|
|
||||||
|
#### pf.conf
|
||||||
|
pf is now enabled in `settings.ini` by default but not in `minimal.ini` or `server.ini`. You will need to edit the macros with your interface, SSH port, and IP addresses before use. `admin_ips` is used by default and will take a list of two IP Addresses seperated by a space, `admin_ip_range` is included for convenience. If you will be using the range macro instead of the default make sure to edit line 108 changing `admin_ips` to `admin_ip_range`. Redis is configured to be localhost only.
|
||||||
|
|
||||||
|
|
||||||
|
#### Backups
|
||||||
|
|
||||||
|
The very first time the script is run it will make copies of `rc.conf`, `sysctl.conf`, `login.conf`, and `loader.conf` named `rc.conf.original` etc. If you've already done this yourself you may want to rename or move those files. After the script is once run, it sets that field to false and no longer makes backups. If you would like you can set `settings.ini` section `[SCRIPT]`option `first_run` to `True` with capital `T` to make new backups at any time after you've renamed the original backups or the script will overwrite them.
|
||||||
|
|
||||||
|
|
||||||
|
#### Chmod-ability
|
||||||
|
|
||||||
|
The set of files needed to be secure changed and changed throughout testing and so it ended up as a shell command but an error checked function was provided for the administrator programmer to use instead of appending to the long list in `settings.ini` section `[FILESEC]` if you wish or to work with other software.
|
||||||
|
|
||||||
|
Those files are:
|
||||||
|
|
||||||
|
`etc/ftpusers /etc/group /etc/hosts /etc/hosts.allow /etc/hosts.equiv /etc/hosts.lpd /etc/inetd.conf /etc/login.access /etc/login.conf /etc/newsyslog.conf /etc/rc.conf /etc/ssh/sshd_config /etc/sysctl.conf etc/syslog.conf /etc/ttys /etc/crontab /usr/bin/crontab /usr/bin/at /usr/bin/atq /usr/bin/atrm /usr/bin/batch /var/log`
|
||||||
|
|
||||||
|
#### Secure Password Settings
|
||||||
|
|
||||||
|
The newly applied settings will not take effect until you reset your password.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
<a name="Descriptors"></a>
|
||||||
|
|
||||||
|
# Setting Descriptors
|
||||||
|
**Startup**
|
||||||
|
|
||||||
|
* `kern_securelevel_enable = "YES"`
|
||||||
|
* Enable access to other than permanently insecure modes
|
||||||
|
* `microcode_update_enable = "YES"`
|
||||||
|
* Allow CPU microcode/firmware updates
|
||||||
|
* Disable Mail Transport Agent
|
||||||
|
* Despite the documentation saying "NONE" is deprecated, this is not the case and hasn't been for over 15 years.
|
||||||
|
* These are *thoroughly* tested as the best settings as "NONE" produces one less WARNING than "NO" in some cases.
|
||||||
|
* `syslogd_flags="-ss"`
|
||||||
|
* Disallow syslogd to bind to a network socket
|
||||||
|
* `clear_tmp_enable = "YES"`
|
||||||
|
* Clear the /tmp directory on reboot
|
||||||
|
* `icmp_drop_redirect="YES"`
|
||||||
|
* Disallow redirection of ICMP (ping, echo)
|
||||||
|
* `inetd_enable = "NO"`
|
||||||
|
* Disallow Network File System to share directories over the network
|
||||||
|
* `portmap_enable = "NO"`
|
||||||
|
* Disallow portmapping since Network File Systems is disallowed
|
||||||
|
* `update_motd = "NO"`
|
||||||
|
* Disallow computer system details from being added to /etc/motd on system reboot
|
||||||
|
|
||||||
|
**System**
|
||||||
|
|
||||||
|
* `kern.securelevel = 1` [(*)](https://man.freebsd.org/cgi/man.cgi?securelevel)
|
||||||
|
* The system immutable and system append-only flags may
|
||||||
|
not be turned off; disks for mounted file systems, /dev/mem and
|
||||||
|
/dev/kmem may not be opened for writing; /dev/io (if your platform
|
||||||
|
has it) may not be opened at all; kernel modules (see kld(4)) may
|
||||||
|
not be loaded or unloaded. The kernel debugger may not be entered
|
||||||
|
using the debug.kdb.enter sysctl. A panic or trap cannot be forced
|
||||||
|
using the debug.kdb.panic, debug.kdb.panic_str and other sysctl's.
|
||||||
|
* `security.bsd.see_other_uids = 0`
|
||||||
|
* Disallow users from seeing information about processes that are being run by another user (UID)
|
||||||
|
* `security.bsd.see_other_gids = 0` [(*)](https://docs.freebsd.org/en/books/handbook/mac/#mac-policies)
|
||||||
|
* Disallow users from seeing information about processes that are being run by another group (GID)
|
||||||
|
* `security.bsd.see_jail_proc = 0` (Sysctl MIB Entry `sysctl -a | grep security.bsd`)
|
||||||
|
* Disallow non-root users from seeing processes in jail
|
||||||
|
* `security.bsd.unprivileged_read_msgbuf = 0` (Sysctl MIB Entry `sysctl -a | grep security.bsd`)
|
||||||
|
* Disallow non-root users from reading system message buffer
|
||||||
|
* `kern.randompid = 107` [(*)](https://wiki.freebsd.org/DevSummit/201308/Security)
|
||||||
|
* Force kernel to randomize process ID's using above salt value instead of sequential
|
||||||
|
* `net.inet.ip.random_id = 1`
|
||||||
|
* Randomize IP packet ID
|
||||||
|
* `net.inet.ip.redirect = 0`
|
||||||
|
* Disallow ICMP host redirects
|
||||||
|
* `net.inet.tcp.always_keepalive = 0`
|
||||||
|
* Disallow keeping open idle TCP connections. This may need to be changed if you are serving
|
||||||
|
* `net.inet.tcp.blackhole = 2` +(UDP)[(*)](https://man.freebsd.org/cgi/man.cgi?query=blackhole)
|
||||||
|
* Packets that are received on a closed port will not initiate a reply
|
||||||
|
* `net.inet.tcp.path_mtu_discovery = 0` [(*)](https://man.freebsd.org/cgi/man.cgi?query=tcp&sektion=4)
|
||||||
|
* Disallows TCP to determine the minimum MTU size on any network that is currently in the path between two hosts
|
||||||
|
* `net.inet.icmp.drop_redirect = 1`
|
||||||
|
* Pairs with rc.conf startup, as once enabled, it is then set
|
||||||
|
* `net.inet6.icmp6.rediraccept = 0`
|
||||||
|
* Disable ping IPv6 redirection mitigating ICMP attacks
|
||||||
|
* Set to 1 if using FreeBSD as network appliance
|
||||||
|
* `net.inet.tcp.drop_synfin` [(*)](https://www.juniper.net/documentation/us/en/software/ccfips22.2/cc-security_srx5000/cc-security/topics/task/configuring-tcp-syn-fin-attack.html)
|
||||||
|
* Mitigates probe scans and has positive impact against DoS/DDoS attacks
|
||||||
|
* Quadhelion Engineering [Research](https://www.quadhelion.engineering/articles/freebsd-synfin.html) on this setting
|
||||||
|
* `hw.mds_disable = 3` [(*)](https://www.kernel.org/doc./html/latest/arch/x86/mds.html)
|
||||||
|
* Enable Microarchitectural Data Sampling Mitigation version `VERW`
|
||||||
|
* Change value to `3` (AUTO) if using a Hypervisor without MDS Patch
|
||||||
|
* `hw.spec_store_bypass_disable = 1` [(*)](https://handwiki.org/wiki/Speculative_Store_Bypass)
|
||||||
|
* Disallow Speculative Bypass used by Spectre and Meltdown
|
||||||
|
* `kern.elf64.allow_wx = 0` [(*)](https://www.ibm.com/docs/en/aix/7.2?topic=memory-understanding-mapping)
|
||||||
|
* Disallow write and execute for shared memory
|
||||||
|
|
||||||
|
**server.ini**
|
||||||
|
|
||||||
|
Common network tuning values to increase performance and alleviate congestion, useful against DoS/DDoS attacks on high bandwidth application servers
|
||||||
|
|
||||||
|
* `kern.ipc.maxsockbuf=67108864`
|
||||||
|
* `net.inet.tcp.sendbuf_max=67108864`
|
||||||
|
* `net.inet.tcp.recvbuf_max=67108864`
|
||||||
|
* `net.inet.tcp.sendbuf_auto=1`
|
||||||
|
* `net.inet.tcp.recvbuf_auto=1`
|
||||||
|
* `net.inet.tcp.sendbuf_inc=16384`
|
||||||
|
|
||||||
|
|
||||||
|
**Kernel**
|
||||||
|
* `security.bsd.allow_destructive_dtrace = "0"`
|
||||||
|
* Disallow DTrace to terminate processes
|
||||||
|
* Test DTrace hardening: Using all 3 commands should result in `Permission denied` or `Destructive actions not allowed`:
|
||||||
|
* `dtrace -wn 'tcp:::connect-established { @[args[3]->tcps_raddr] = count(); }'`
|
||||||
|
* `dtrace -wqn tick-1sec'{system("date")}'`
|
||||||
|
* `dtrace -qn tick-1sec'{system("date")}'`
|
||||||
|
* `hw.ibrs_disable = "3"` [(*)](https://wiki.freebsd.org/SpeculativeExecutionVulnerabilities)
|
||||||
|
* Prevent Spectre and Meltdown CPU Vulnerabilities, 3 for AUTO
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### January 17, 2024 Changelog
|
||||||
|
*If you are on FreeBSD 13.2 download the 3.0.1 release tag*
|
||||||
|
|
||||||
|
* pf enabled by default
|
||||||
|
* ZenBleed workaround removed
|
||||||
|
* 32bit protections removed
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
*Full [Changelog](Changelog.md)*
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a name="License"></a>
|
||||||
|
|
||||||
|
## License Summary
|
||||||
|
|
||||||
|
### Software
|
||||||
|
Non-Commercial usage, Human Intelligence only, retain and forward author and license data. Modify existing code as needed up to 25% while allowing unlimited new additions. The Software may use or be used by other software.
|
||||||
|
|
||||||
|
|
||||||
|
### Digital Art
|
||||||
|
All Digital Artists and Original Digital Art automatically receives robust International Copyright protections.
|
||||||
|
* Supplemental License [here](digital%20art/Quadhelion%20Engineering%20Universal%20Digital%20Art%20License.md)
|
||||||
|
* QHE Wallpapers meet the [FreeBSD Foundation Trademark Usage Terms and Conditions](https://freebsdfoundation.org/legal/trademark-usage-terms-and-conditions/) where most FreeBSD digital art does not.
|
||||||
|
* An original digital art creation containing the FreeBSD Logo under T&C, the larger work is thus automatically copyrighted worldwide and may not be distributed, shared, or altered.
|
||||||
|
* FreeBSD Foundation Members, Employees, and Associates are exempt from Digital Art restrictions.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Security Guidelines
|
||||||
|
|
||||||
|
Since this Software uses shell commands it is required to place it in a secure directory with permissions on the **parent** directory to have no permissions for `other` /all/world group to write or *execute* and **no network access**.
|
||||||
|
|
||||||
|
Please follow [these guidelines](/docs/SECURITY.md) should you find a vulnerability not addressed in the audit.
|
||||||
|
|
||||||
|
|
||||||
|
## Statement of Security:
|
||||||
|
|
||||||
|
* **Risk** - Low
|
||||||
|
* **Impact** - Medium
|
||||||
|
|
||||||
|
This script has no networking, accesses no sockets, and uses only standard libraries.
|
||||||
|
|
||||||
|
Although this script is using `subprocess.run(shell=True)` the only possibility of shell injection is from the paths customized by the Licensee or unauthorized access to the filesystem the script resides on in order to perform unauthorized modifications to `settings.ini`or the Software which is not a vulnerability of the Software.
|
||||||
|
|
||||||
|
<a name="Latest"></a>
|
||||||
|
### Latest Development Version
|
||||||
|
|
||||||
|
[Quadhelion Engineering Code Repository](https://quadhelion.dev)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|

|
||||||
6
classes.dot
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
digraph "classes" {
|
||||||
|
rankdir=BT
|
||||||
|
charset="utf-8"
|
||||||
|
"harden-freebsd.Conf" [color="black", fontcolor="black", label=<{Conf|file<br ALIGN="LEFT"/>flag<br ALIGN="LEFT"/>found : bool<br ALIGN="LEFT"/>setting<br ALIGN="LEFT"/>|addConf()<br ALIGN="LEFT"/>checkConf(): bool<br ALIGN="LEFT"/>restoreConf()<br ALIGN="LEFT"/>setConf()<br ALIGN="LEFT"/>verifyConf()<br ALIGN="LEFT"/>}>, shape="record", style="solid"];
|
||||||
|
"harden-freebsd.SetOpts" [color="black", fontcolor="black", label=<{SetOpts|section<br ALIGN="LEFT"/>|}>, shape="record", style="solid"];
|
||||||
|
}
|
||||||
BIN
digital-art/FreeBSD-wallpaper-no-text-tm.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 3.4 MiB |
|
After Width: | Height: | Size: 3.4 MiB |
BIN
digital-art/QHE-FreeBSD-Wallpaper-2024-BlueWillowAI-assisted.png
Normal file
|
After Width: | Height: | Size: 3.3 MiB |
BIN
digital-art/QHE-FreeBSD-wallpaper-mid-text-tm.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
digital-art/QHE-Hardened-FreeBSD-wallpaper-red-tm.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Quadhelion Engineering Universal Digital Art License
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## QHEUDAL-NC-NA-ND
|
||||||
|
|
||||||
|
**Legend:**
|
||||||
|
|
||||||
|
* (Q)had(H)elion (E)ngineering (U)niversal (D)igital (A)rt (L)icense
|
||||||
|
* (N)on-(C)ommercial
|
||||||
|
* (N)o Alterations
|
||||||
|
* (N)o Distribution
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Executive Summary
|
||||||
|
|
||||||
|
Original Digital Art creation even if containing other permitted use material is automatically copyrighted in the United States of America and most of the world under International Law. All digital art may not be shared in any way with others. The QHE watermark is not to be removed, hidden, nor the aspect ratio changed.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Allowance
|
||||||
|
|
||||||
|
* Licencees of the Software who have at least once executed the Software while meeting the License requirements may use copies of the digital art on any personal computer, personal Virtual Machine, or personal device.
|
||||||
|
|
||||||
|
* FreeBSD Foundation Members, Employees, and Associates are exempt from these restrictions
|
||||||
|
|
||||||
|
## Restrictions
|
||||||
|
|
||||||
|
The original author of this digital art creations, Elias Christopher Griffin, via Quadhelion Engineering, sets forth the following restrictions on his art.
|
||||||
|
|
||||||
|
**Non-Commercial**
|
||||||
|
No gain is to be made through the use of the digital art and is strictly forbidden for use in a Commercial act.
|
||||||
|
|
||||||
|
**No Alterations**
|
||||||
|
The content, display, and file of the digital art may not be modified in any way excepting display adjustment on a personal device using system wallpaper tools. The file can never be altered in it's aspect ratio, cropped by a tool, overlayed, or combined with any other art, image, or text.
|
||||||
|
|
||||||
|
**No Distributions**
|
||||||
|
The digital art is to be used by Licensees of the Software in which it was intended and originally accompanied. It may not be distributed, re-distributed, shared, or put on the internet or any communications platform.
|
||||||
|
|
||||||
|
## Full Restrictions
|
||||||
|
|
||||||
|
**Logo, Icons, and Software Art**
|
||||||
|
No one but the creator may use the Quadhelion Engineering Logo, digital art associated with the Software itself, or the Software repository art.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BIN
docs/FreeBSD-Hier.pdf
Normal file
64
docs/SECURITY.md
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
# Security Policy
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Report a Vulnerability
|
||||||
|
|
||||||
|
1. Open a Github Private Vulnerability Report for "Wravoc" using the "Security" Tab on the home page of the repository following [best practices](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/best-practices-for-writing-repository-security-advisories). Click **Report a vulnerability** to open the advisory form.
|
||||||
|
2. If you believe this vulnerability is severe or wish to send files please email [elias@quadhelion.engineering](mailto:elias@quadhelion.engineering) expecting a reply within 48 hours.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## How to report a vulnerability
|
||||||
|
|
||||||
|
Please include:
|
||||||
|
|
||||||
|
* Your Operating System details including:
|
||||||
|
|
||||||
|
* Who was file system owner of the Software
|
||||||
|
* What were the file system permissions on the Software
|
||||||
|
* What networking processes had access to that file
|
||||||
|
* What command was used to Execute the Software
|
||||||
|
* Where the Software was located when it was Executed
|
||||||
|
|
||||||
|
* Your Python Environment Details including:
|
||||||
|
|
||||||
|
* PDB output
|
||||||
|
|
||||||
|
* `python3 -m pdb authlog-threats.py`
|
||||||
|
|
||||||
|
* What modules were loaded at the time the Software was Executed
|
||||||
|
|
||||||
|
* ```
|
||||||
|
import sys
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
# pretty print loaded modules
|
||||||
|
pprint.pprint(sys.modules)
|
||||||
|
```
|
||||||
|
|
||||||
|
* Version
|
||||||
|
|
||||||
|
* Automations
|
||||||
|
|
||||||
|
* Including automatic Python repository, pip, or relevant software updating
|
||||||
|
|
||||||
|
* Other Python scripts that had access to the Software
|
||||||
|
|
||||||
|
* What customizations you used in the Software
|
||||||
|
|
||||||
|
* Thorough details of vulnerability exploit
|
||||||
|
|
||||||
|
* What process was used to prove the exploit
|
||||||
|
* What files were touched
|
||||||
|
* Relevant shell history during the process
|
||||||
|
* Relevant sections of logs detailing this outcome
|
||||||
|
* Screenshots of all the above
|
||||||
|
* The hash and file size of the Software
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Confidentiality
|
||||||
|
|
||||||
|
Do not publically post information on how to utilize the vulnerability or details which others may find able to utilize the vulnerablity.
|
||||||
407
harden-freebsd.py
Normal file
|
|
@ -0,0 +1,407 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Harden FreeBSD system perms, settings.
|
||||||
|
Set and reset rc, sysctl, login, confs; set file perms, run shell commands
|
||||||
|
Uses ini file in the same directory.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
./harden-freebsd.py
|
||||||
|
./harden-freebsd.py <ini file>
|
||||||
|
./harden-freebsd.py restore
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = "Elias Christopher Griffin"
|
||||||
|
__url__ = "https://www.quadhelion.engineering"
|
||||||
|
__license__ = "QHELP-OME-NC-ND-HI"
|
||||||
|
__copyright__ = "https://www.quadhelion.engineering/qhelp.html"
|
||||||
|
__version__ = "3.1"
|
||||||
|
__date__ = "01/20/2024"
|
||||||
|
__email__ = "elias@quadhelion.engineering"
|
||||||
|
__status__ = "Production"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from datetime import datetime
|
||||||
|
import os, re, subprocess, syslog, configparser, shutil, sys
|
||||||
|
|
||||||
|
_date = datetime.now()
|
||||||
|
date_time = _date.strftime("%m/%d/%Y, %H:%M")
|
||||||
|
|
||||||
|
|
||||||
|
# Setup for script argument processing
|
||||||
|
sysargs = sys.argv
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
|
||||||
|
|
||||||
|
# Setup to manipulate all the system files
|
||||||
|
harden_freebsd_log = Path("/var/log/harden-freebsd.log")
|
||||||
|
rc_conf = Path("/etc/rc.conf")
|
||||||
|
sysctl_conf = Path("/etc/sysctl.conf")
|
||||||
|
loader_conf = Path("/boot/loader.conf")
|
||||||
|
login_conf = Path("/etc/login.conf")
|
||||||
|
cron_access = Path("/var/cron/allow")
|
||||||
|
at_access = Path("/var/at/at.allow")
|
||||||
|
|
||||||
|
|
||||||
|
# Set the backup file names
|
||||||
|
backup_suffix = ".original"
|
||||||
|
rc_backup = rc_conf.with_name(rc_conf.name + backup_suffix)
|
||||||
|
sysctl_backup = sysctl_conf.with_name(sysctl_conf.name + backup_suffix)
|
||||||
|
loader_backup = loader_conf.with_name(loader_conf.name + backup_suffix)
|
||||||
|
login_backup = login_conf.with_name(login_conf.name + backup_suffix)
|
||||||
|
|
||||||
|
|
||||||
|
# Handle script arguments
|
||||||
|
sysargs = sys.argv
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
|
||||||
|
if len(sys.argv) == 2:
|
||||||
|
script_argument = sys.argv[1]
|
||||||
|
script_argument_path = Path(script_argument)
|
||||||
|
if script_argument_path.exists and script_argument_path.suffix == ".ini":
|
||||||
|
config.read(script_argument)
|
||||||
|
elif sys.argv[1] == "restore":
|
||||||
|
rc_conf.write_bytes(rc_backup.read_bytes())
|
||||||
|
sysctl_conf.write_bytes(sysctl_backup.read_bytes())
|
||||||
|
loader_conf.write_bytes(loader_backup.read_bytes())
|
||||||
|
print(f"\n*********************\033[38;5;76m Success \033[0;0m*************************")
|
||||||
|
print("Original rc.conf, sysctl.conf, loader.conf restored")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
exit(0)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
config.read('settings.ini')
|
||||||
|
|
||||||
|
|
||||||
|
# Handle Errors
|
||||||
|
def exception_handler(func):
|
||||||
|
def intake(*args, **kwargs):
|
||||||
|
try:
|
||||||
|
func(*args, **kwargs)
|
||||||
|
except PermissionError as e:
|
||||||
|
print(f"\n******************\033[38;5;1m Permissions \033[0;0m************************\n")
|
||||||
|
print(f"Insufficient permissions {e}")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
except OSError as e:
|
||||||
|
print(f"\n********************\033[38;5;1m Locked \033[0;0m**************************\n")
|
||||||
|
print(f"Perhaps file is busy, locked, process blocked, or raced:\n")
|
||||||
|
print(f"{e}")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
return intake
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Write to either "syslog" (/var/log/messages) or "script" (/var/log/harden-freebsd.log)
|
||||||
|
@exception_handler
|
||||||
|
def writeLog(log_type, content):
|
||||||
|
harden_freebsd_logwriter = open(harden_freebsd_log, "a")
|
||||||
|
syslog.openlog("LOG_INFO")
|
||||||
|
if log_type == "script":
|
||||||
|
harden_freebsd_logwriter.writelines(content + os.linesep)
|
||||||
|
elif log_type == "syslog":
|
||||||
|
syslog.syslog(1, content)
|
||||||
|
else:
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
print(f"\033[38;5;63m LOG: \033[0;0m {content}")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Make *.original backups of all files only once
|
||||||
|
if config['SCRIPT']['first_run'] == "True":
|
||||||
|
try:
|
||||||
|
harden_freebsd_log.touch()
|
||||||
|
cron_access.touch()
|
||||||
|
at_access.touch()
|
||||||
|
rc_backup.write_bytes(rc_conf.read_bytes())
|
||||||
|
sysctl_backup.write_bytes(sysctl_conf.read_bytes())
|
||||||
|
loader_backup.write_bytes(loader_conf.read_bytes())
|
||||||
|
login_backup.write_bytes(login_conf.read_bytes())
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
error_path = Path(e.filename)
|
||||||
|
print(f"\n********************\033[38;5;1m File Not Found \033[0;0m*******************")
|
||||||
|
print(f"Filename: {error_path.parts}")
|
||||||
|
print("*******************************************************\n")
|
||||||
|
except PermissionError as e:
|
||||||
|
print(f"\n******************\033[38;5;1m Permissions \033[0;0m************************\n")
|
||||||
|
print(f"Insufficient permissions {e}")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
except OSError as e:
|
||||||
|
print(f"\n********************\033[38;5;1m Locked \033[0;0m**************************\n")
|
||||||
|
print(f"Perhaps file is busy, locked, process blocked, or raced:\n")
|
||||||
|
print(f"{e}")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
else:
|
||||||
|
writeLog("syslog", "System file backups complete")
|
||||||
|
with open('settings.ini', 'w') as configfile:
|
||||||
|
config.set('SCRIPT', 'first_run', 'False')
|
||||||
|
config.write(configfile)
|
||||||
|
print(f"\n*********************\033[38;5;76m Success \033[0;0m*************************")
|
||||||
|
print(f"\033[38;5;75mCreated: \033[0;0m")
|
||||||
|
print(f" {cron_access.name}, {at_access.name} \n")
|
||||||
|
print(f"\033[38;5;75mBackups Made: \033[0;0m")
|
||||||
|
print(f" {rc_backup.name}, {sysctl_backup.name}")
|
||||||
|
print(f" {login_backup.name}, {loader_backup.name} \n")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Read the system file content
|
||||||
|
try:
|
||||||
|
rc_content = rc_conf.read_text(encoding="utf-8")
|
||||||
|
sysctl_content = sysctl_conf.read_text(encoding="utf-8")
|
||||||
|
login_content = login_conf.read_text(encoding="utf-8")
|
||||||
|
loader_content = loader_conf.read_text(encoding="utf-8")
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
error_path = Path(e.filename)
|
||||||
|
writeLog("script", "Error finding file " + error_path)
|
||||||
|
print(f"\n*******************\033[38;5;1m File Not Found \033[0;0m********************")
|
||||||
|
print(f"Filename: {error_path.name}")
|
||||||
|
print(f"Directories used: {error_path.parts}\n")
|
||||||
|
print("*******************************************************\n")
|
||||||
|
except PermissionError as e:
|
||||||
|
print(f"\n******************\033[38;5;1m Permissions \033[0;0m************************\n")
|
||||||
|
print(f"Permission to read/append {e}")
|
||||||
|
print(f"{os.stat(rc_conf)}{os.linesep}")
|
||||||
|
print(f"{os.stat(sysctl_conf)}{os.linesep}")
|
||||||
|
print(f"{os.stat(loader_conf)}{os.linesep}")
|
||||||
|
print(f"{os.stat(cron_access)}{os.linesep}")
|
||||||
|
print(f"{os.stat(at_access)}{os.linesep}")
|
||||||
|
print(f"{os.stat(login_conf)}{os.linesep}")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"{os.linesep}*********************\033[38;5;75m Running \033[0;0m*************************{os.linesep}"
|
||||||
|
f"Loaded system files for read/append\n"
|
||||||
|
f"*******************************************************{os.linesep}"
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
writeLog("syslog", "Hardening in progress")
|
||||||
|
print(f"\n********************\033[38;5;75m Info Panel \033[0;0m***********************")
|
||||||
|
print(f"Executing {__file__}")
|
||||||
|
print(f"Executing {date_time}")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
|
||||||
|
|
||||||
|
# Main working class dealing with rc.conf and sysctl.conf
|
||||||
|
class Conf:
|
||||||
|
def __init__(self, file, setting, flag):
|
||||||
|
self.file = file
|
||||||
|
self.setting = setting
|
||||||
|
self.flag = flag
|
||||||
|
|
||||||
|
# Changes the flag from whatever it is currently to flag in settings.ini
|
||||||
|
def setConf(self):
|
||||||
|
try:
|
||||||
|
with open(self.file, 'r+', encoding="us-ascii") as file_content:
|
||||||
|
lines = file_content.readlines()
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if line.startswith(self.setting):
|
||||||
|
lines[i] = self.setting + "=" + self.flag + os.linesep
|
||||||
|
file_content.seek(0)
|
||||||
|
for line in lines:
|
||||||
|
file_content.write(line)
|
||||||
|
file_content.truncate()
|
||||||
|
writeLog("script", self.setting + " was set to " + self.flag)
|
||||||
|
except OSError as e:
|
||||||
|
print(f"\n********************\033[38;5;1m Locked \033[0;0m**************************\n")
|
||||||
|
print(f"Perhaps file is busy, locked, process blocked, or raced:\n")
|
||||||
|
print(f"{e}")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
else:
|
||||||
|
print(f"\033[38;5;208m {self.setting} \033[0;0m changed to\033[38;5;208m {self.flag}\033[0;0m in\033[38;5;75m {self.file}\033[0;0m ")
|
||||||
|
|
||||||
|
# Appends at the end of a file a directive that was not present previously
|
||||||
|
def addConf(self):
|
||||||
|
try:
|
||||||
|
with open(self.file, 'a') as file_content:
|
||||||
|
file_content.write(self.setting + "=" + self.flag + os.linesep)
|
||||||
|
writeLog("script", self.setting + "=" + self.flag + " added")
|
||||||
|
except OSError as e:
|
||||||
|
print(f"\n********************\033[38;5;1m Locked \033[0;0m**************************\n")
|
||||||
|
print(f"Perhaps file is busy, locked, process blocked, or raced:\n")
|
||||||
|
print(f"{e}")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
else:
|
||||||
|
print(f"\033[38;5;63m {self.setting} \033[0;0m added to \033[38;5;75m{self.file}\033[0;0m ")
|
||||||
|
|
||||||
|
# Checks to see if the directive is already in the conf, returns True if present.
|
||||||
|
def checkConf(self) -> bool:
|
||||||
|
self.found = False
|
||||||
|
try:
|
||||||
|
with open(self.file, 'r') as file_content:
|
||||||
|
lines = file_content.readlines()
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if line.startswith(self.setting):
|
||||||
|
self.found = True
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
return self.found
|
||||||
|
except OSError as e:
|
||||||
|
print(f"\n********************\033[38;5;1m Locked \033[0;0m**************************\n")
|
||||||
|
print(f"Perhaps file is busy, locked, process blocked, or raced:\n")
|
||||||
|
print(f"{e}")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
|
||||||
|
# Checks proper flag and equality syntax in rc.conf and sysctl.conf with first-boot 13.2 directives
|
||||||
|
# May not work with advanced flags added later
|
||||||
|
def verifyConf(self):
|
||||||
|
global conf_directives
|
||||||
|
conf_directives = []
|
||||||
|
sysctl_conf_verify = re.compile(r'[^\"]') # No quotes
|
||||||
|
loader_rc_conf_verify = re.compile(r'^[\"].+[$\"]') # Pair of quotes
|
||||||
|
try:
|
||||||
|
with open(self.file, 'r+') as file_content:
|
||||||
|
lines = file_content.readlines()
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
partitioned_line = line.partition("=")
|
||||||
|
if line.isspace():
|
||||||
|
pass
|
||||||
|
elif line.startswith("#"):
|
||||||
|
pass
|
||||||
|
elif partitioned_line[1] != "=":
|
||||||
|
print(f"\n*******************************************************")
|
||||||
|
print(f"Error at {lines[i]}: No equality operator. Restored original.")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
writeLog("script", "No equality operator at line " + lines[i].rstrip() + " in " + self.file.name)
|
||||||
|
self.restoreConf()
|
||||||
|
sys.exit()
|
||||||
|
elif self.file == rc_conf and re.match(loader_rc_conf_verify, partitioned_line[2]) == None:
|
||||||
|
print(f"\n*******************************************************")
|
||||||
|
print(f"Error: {self.flag} not allowed in {lines[i]} in {self.file}. Restored original.")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
writeLog("script", "Quote matching error at line " + lines[i].rstrip())
|
||||||
|
self.restoreConf()
|
||||||
|
sys.exit()
|
||||||
|
elif self.file == loader_conf and re.match(loader_rc_conf_verify, partitioned_line[2]) == None:
|
||||||
|
print(f"\n*******************************************************")
|
||||||
|
print(f"Error: {self.flag} not allowed in {lines[i]} in {self.file}. Restored original.")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
writeLog("script", "Quote matching error at line " + lines[i].rstrip())
|
||||||
|
self.restoreConf()
|
||||||
|
sys.exit()
|
||||||
|
elif self.file == sysctl_conf and re.match(sysctl_conf_verify, partitioned_line[2]) == None:
|
||||||
|
print(f"\n*******************************************************")
|
||||||
|
print(f"Error: {self.flag} not allowed in {lines[i].rstrip()} in {self.file}. Restored original.")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
writeLog("script", "Quote in sysctl.conf at line " + lines[i])
|
||||||
|
self.restoreConf()
|
||||||
|
sys.exit()
|
||||||
|
else:
|
||||||
|
conf_directives.append(line.rstrip())
|
||||||
|
except OSError as e:
|
||||||
|
print(f"\n********************\033[38;5;1m Locked \033[0;0m**************************\n")
|
||||||
|
print(f"Perhaps file is busy, locked, process blocked, or raced:\n")
|
||||||
|
print(f"{e}")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
|
||||||
|
# If syntax verification fails, restore *.originals to prevent boot failure
|
||||||
|
# If in single user read-only mode use commands:
|
||||||
|
# zfs set readonly=false zroot
|
||||||
|
# zfs mount -a
|
||||||
|
def restoreConf(self):
|
||||||
|
try:
|
||||||
|
if self.file == rc_conf:
|
||||||
|
shutil.copy(rc_backup, rc_conf)
|
||||||
|
elif self.file == sysctl_conf:
|
||||||
|
shutil.copy(sysctl_backup, sysctl_conf)
|
||||||
|
elif self.file == loader_conf:
|
||||||
|
shutil.copy(loader_backup, loader_conf)
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
error_path = Path(e.filename)
|
||||||
|
print(f"\n*******************\033[38;5;1m File Not Found \033[0;0m********************")
|
||||||
|
print(f"Filename: {error_path.name}")
|
||||||
|
print(f"Directories used: {error_path.parts}\n")
|
||||||
|
print("*******************************************************\n")
|
||||||
|
else:
|
||||||
|
print(f"\n*********************\033[38;5;76m Success \033[0;0m*************************")
|
||||||
|
print(f"Files restored")
|
||||||
|
print("*******************************************************\n")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Hardcoded sections as only t e contain flags we can dynamically set and re-set.
|
||||||
|
# Loops through all directives and sets each
|
||||||
|
class SetOpts:
|
||||||
|
def __init__(self, section):
|
||||||
|
self.section = section
|
||||||
|
if self.section == "STARTUP":
|
||||||
|
file = rc_conf
|
||||||
|
elif self.section == "SYSTEM":
|
||||||
|
file = sysctl_conf
|
||||||
|
elif self.section == "KERNEL":
|
||||||
|
file = loader_conf
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for opt in config[self.section]:
|
||||||
|
value = config[self.section][opt]
|
||||||
|
conf_runner = Conf(file, opt, value)
|
||||||
|
setting_present = conf_runner.checkConf()
|
||||||
|
if setting_present:
|
||||||
|
conf_runner.setConf()
|
||||||
|
conf_runner.verifyConf()
|
||||||
|
else:
|
||||||
|
conf_runner.addConf()
|
||||||
|
conf_runner.verifyConf()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Run shell commands for named section. Will error if sent setting.ini sections that have no shell commands.
|
||||||
|
def shellCommand(section):
|
||||||
|
try:
|
||||||
|
for opt in config[section]:
|
||||||
|
value = config[section][opt]
|
||||||
|
command_result = subprocess.run([value], shell=True, timeout=1.7)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
syslog.syslog(syslog.LOG_ERR, "Failure: Shell Command")
|
||||||
|
print(f"\n*********************\033[38;5;1m Shell Error \033[0;0m*********************")
|
||||||
|
print(f"Command {e.args[1]} failed")
|
||||||
|
print(f"Terminated by {command_result.returncode}")
|
||||||
|
print(f"{command_result.stderr}")
|
||||||
|
print("*******************************************************\n")
|
||||||
|
except OSError as e:
|
||||||
|
print(f"\n********************\033[38;5;1m Locked \033[0;0m**************************\n")
|
||||||
|
print(f"Perhaps file is busy, locked, process blocked, or raced:\n")
|
||||||
|
print(f"{e}")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
else:
|
||||||
|
print(f"\n*********************\033[38;5;76m Success \033[0;0m*************************")
|
||||||
|
print(f"\033[38;5;208mShell Error: {opt}\033[0;0m {command_result.stdout}")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Set chmod for added convienence of the adminstrator with error handling and logging
|
||||||
|
@exception_handler
|
||||||
|
def setChmod(file, setting):
|
||||||
|
os.fchmod(file, setting)
|
||||||
|
writeLog("script", file + "was set to " + setting )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Main
|
||||||
|
writeLog("script", date_time)
|
||||||
|
SetOpts("STARTUP")
|
||||||
|
SetOpts("SYSTEM")
|
||||||
|
SetOpts("KERNEL")
|
||||||
|
shellCommand("FILESEC")
|
||||||
|
shellCommand("USERSEC")
|
||||||
|
|
||||||
|
|
||||||
|
# Write succesfull completion to console and syslog
|
||||||
|
writeLog("script", "************ SUCCESS ************")
|
||||||
|
writeLog("script", "All files and directives validate")
|
||||||
|
writeLog("script", "*********************************")
|
||||||
|
writeLog("syslog", "SUCCESS: Hardening completed")
|
||||||
|
|
||||||
|
print(f"\n*********************\033[38;5;76m Success \033[0;0m*************************")
|
||||||
|
print("All files and directives validate")
|
||||||
|
print("Package Security Report generated; pkg-audit-report")
|
||||||
|
print(f"*******************************************************\n")
|
||||||
|
|
||||||
|
# EOF
|
||||||
BIN
images/harden-freebsd-logo.jpg
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
images/quadhelionEngineeringIcon.jpg
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
60
minimum.ini
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
##########################################
|
||||||
|
# Settings file for harden-freebsd.py
|
||||||
|
#
|
||||||
|
# No section can be entirely commented out
|
||||||
|
# No section can be completely empty
|
||||||
|
# Harmless to re-run same settings
|
||||||
|
#
|
||||||
|
# Settings can be changed as many
|
||||||
|
# times as needed; re-run script.
|
||||||
|
#
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
|
||||||
|
[STARTUP]
|
||||||
|
microcode_update_enable = "YES"
|
||||||
|
syslogd_flags = "-ss"
|
||||||
|
clear_tmp_enable = "YES"
|
||||||
|
icmp_drop_redirect = "NO"
|
||||||
|
inetd_enable = "NO"
|
||||||
|
portmap_enable = "YES"
|
||||||
|
update_motd = "NO"
|
||||||
|
pf_enable="NO"
|
||||||
|
|
||||||
|
|
||||||
|
[SYSTEM]
|
||||||
|
kern.securelevel = -1
|
||||||
|
security.bsd.see_other_uids = 0
|
||||||
|
security.bsd.see_other_gids = 0
|
||||||
|
security.bsd.see_jail_proc = 0
|
||||||
|
security.bsd.unprivileged_read_msgbuf = 0
|
||||||
|
kern.randompid = 107
|
||||||
|
net.inet.tcp.always_keepalive = 1
|
||||||
|
net.inet.tcp.blackhole = 0
|
||||||
|
net.inet.udp.blackhole = 0
|
||||||
|
net.inet.tcp.path_mtu_discovery = 1
|
||||||
|
hw.mds_disable = 3
|
||||||
|
hw.spec_store_bypass_disable = 1
|
||||||
|
kern.elf64.allow_wx = 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[KERNEL]
|
||||||
|
hw.ibrs_disable = "1"
|
||||||
|
|
||||||
|
|
||||||
|
[FILESEC]
|
||||||
|
lockout_other_group = chmod o= /etc/ftpusers /etc/group /etc/hosts /etc/hosts.allow /etc/hosts.equiv /etc/hosts.lpd /etc/inetd.conf /etc/login.access /etc/login.conf /etc/newsyslog.conf /etc/rc.conf /etc/ssh/sshd_config /etc/sysctl.conf /etc/syslog.conf /etc/ttys /etc/crontab /usr/bin/at /usr/bin/atq /usr/bin/atrm /usr/bin/batch /var/log
|
||||||
|
lockdown_root = chmod 710 /root
|
||||||
|
|
||||||
|
|
||||||
|
[USERSEC]
|
||||||
|
set_cron_root_only = echo "root" | tee /var/cron/allow /var/at/at.allow > /dev/null
|
||||||
|
enable_blowfish_passwords = sed -i .original 's/passwd_format=sha512/passwd_format=blf/g' /etc/login.conf
|
||||||
|
enable_password_reset = sed -i .original 's/^default.*/& \n\t:passwordtime=120d:\\/' /etc/login.conf
|
||||||
|
reset_login = cap_mkdb /etc/login.conf
|
||||||
|
pkg_security_check = pkg audit -Fr > pkg-audit-report
|
||||||
|
|
||||||
|
[SCRIPT]
|
||||||
|
first_run = False
|
||||||
|
|
||||||
77
server.ini
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
##########################################
|
||||||
|
# Settings file for harden-freebsd.py
|
||||||
|
#
|
||||||
|
# No section can be entirely commented out
|
||||||
|
# No section can be completely empty
|
||||||
|
# Harmless to re-run same settings
|
||||||
|
#
|
||||||
|
# Settings can be changed as many
|
||||||
|
# times as needed; re-run script.
|
||||||
|
#
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
|
||||||
|
[STARTUP]
|
||||||
|
kern_securelevel_enable = "YES"
|
||||||
|
microcode_update_enable = "YES"
|
||||||
|
sendmail_enable = "NONE"
|
||||||
|
sendmail_outbound_enable = "NO"
|
||||||
|
sendmail_submit_enable = "NO"
|
||||||
|
sendmail_msp_queue_enable = "NO"
|
||||||
|
syslogd_flags = "-ss"
|
||||||
|
clear_tmp_enable = "YES"
|
||||||
|
icmp_drop_redirect = "YES"
|
||||||
|
inetd_enable = "NO"
|
||||||
|
portmap_enable = "NO"
|
||||||
|
update_motd = "NO"
|
||||||
|
|
||||||
|
|
||||||
|
[SYSTEM]
|
||||||
|
kern.securelevel = 1
|
||||||
|
security.bsd.see_other_uids = 0
|
||||||
|
security.bsd.see_other_gids = 0
|
||||||
|
security.bsd.see_jail_proc = 0
|
||||||
|
security.bsd.unprivileged_read_msgbuf = 0
|
||||||
|
kern.randompid = 107
|
||||||
|
kern.ipc.maxsockbuf=67108864
|
||||||
|
net.inet.tcp.sendbuf_max=67108864
|
||||||
|
net.inet.tcp.recvbuf_max=67108864
|
||||||
|
net.inet.tcp.sendbuf_auto=1
|
||||||
|
net.inet.tcp.recvbuf_auto=1
|
||||||
|
net.inet.tcp.sendbuf_inc=16384
|
||||||
|
net.inet.tcp.cc.algorithm=htcp
|
||||||
|
net.inet.ip.random_id = 1
|
||||||
|
net.inet.ip.redirect = 0
|
||||||
|
net.inet.tcp.always_keepalive = 0
|
||||||
|
net.inet.tcp.blackhole = 2
|
||||||
|
net.inet.udp.blackhole = 1
|
||||||
|
net.inet.tcp.path_mtu_discovery = 0
|
||||||
|
net.inet.icmp.drop_redirect = 1
|
||||||
|
net.inet6.icmp6.rediraccept = 0
|
||||||
|
net.inet.tcp.drop_synfin = 1
|
||||||
|
hw.mds_disable = 3
|
||||||
|
hw.spec_store_bypass_disable = 1
|
||||||
|
kern.elf64.allow_wx = 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[KERNEL]
|
||||||
|
security.bsd.allow_destructive_dtrace = "0"
|
||||||
|
hw.ibrs_disable = "1"
|
||||||
|
|
||||||
|
|
||||||
|
[FILESEC]
|
||||||
|
lockout_other_group = chmod o= /etc/ftpusers /etc/group /etc/hosts /etc/hosts.allow /etc/hosts.equiv /etc/hosts.lpd /etc/inetd.conf /etc/login.access /etc/login.conf /etc/newsyslog.conf /etc/rc.conf /etc/ssh/sshd_config /etc/sysctl.conf /etc/syslog.conf /etc/ttys /etc/crontab /usr/bin/at /usr/bin/atq /usr/bin/atrm /usr/bin/batch /var/log
|
||||||
|
lockdown_root = chmod 710 /root
|
||||||
|
|
||||||
|
|
||||||
|
[USERSEC]
|
||||||
|
set_cron_root_only = echo "root" | tee /var/cron/allow /var/at/at.allow > /dev/null
|
||||||
|
enable_blowfish_passwords = sed -i .original 's/passwd_format=sha512/passwd_format=blf/g' /etc/login.conf
|
||||||
|
enable_password_reset = sed -i .original 's/^default.*/& \n\t:passwordtime=120d:\\/' /etc/login.conf
|
||||||
|
reset_login = cap_mkdb /etc/login.conf
|
||||||
|
pkg_security_check = pkg audit -Fr > pkg-audit-report
|
||||||
|
|
||||||
|
[SCRIPT]
|
||||||
|
first_run = True
|
||||||
|
|
||||||
74
settings.ini
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
##########################################
|
||||||
|
# Settings file for harden-freebsd.py
|
||||||
|
#
|
||||||
|
# No section can be entirely commented out
|
||||||
|
# No section can be completely empty
|
||||||
|
# Harmless to re-run same settings
|
||||||
|
#
|
||||||
|
# Settings can be changed as many
|
||||||
|
# times as needed; re-run script.
|
||||||
|
#
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
|
||||||
|
[STARTUP]
|
||||||
|
kern_securelevel_enable = "YES"
|
||||||
|
microcode_update_enable = "YES"
|
||||||
|
sendmail_enable = "NONE"
|
||||||
|
sendmail_outbound_enable = "NO"
|
||||||
|
sendmail_submit_enable = "NO"
|
||||||
|
sendmail_msp_queue_enable = "NO"
|
||||||
|
syslogd_flags = "-ss"
|
||||||
|
clear_tmp_enable = "YES"
|
||||||
|
icmp_drop_redirect = "YES"
|
||||||
|
inetd_enable = "NO"
|
||||||
|
portmap_enable = "NO"
|
||||||
|
update_motd = "NO"
|
||||||
|
pf_enable="YES"
|
||||||
|
pflog_enable="YES"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[SYSTEM]
|
||||||
|
kern.securelevel = 1
|
||||||
|
security.bsd.see_other_uids = 0
|
||||||
|
security.bsd.see_other_gids = 0
|
||||||
|
security.bsd.see_jail_proc = 0
|
||||||
|
security.bsd.unprivileged_read_msgbuf = 0
|
||||||
|
kern.randompid = 107
|
||||||
|
net.inet.ip.random_id = 1
|
||||||
|
net.inet.ip.redirect = 0
|
||||||
|
net.inet.tcp.always_keepalive = 0
|
||||||
|
net.inet.tcp.blackhole = 2
|
||||||
|
net.inet.udp.blackhole = 1
|
||||||
|
net.inet.tcp.path_mtu_discovery = 0
|
||||||
|
net.inet.icmp.drop_redirect = 1
|
||||||
|
net.inet6.icmp6.rediraccept = 0
|
||||||
|
net.inet.tcp.drop_synfin = 1
|
||||||
|
hw.mds_disable = 3
|
||||||
|
hw.spec_store_bypass_disable = 1
|
||||||
|
kern.elf64.allow_wx = 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[KERNEL]
|
||||||
|
security.bsd.allow_destructive_dtrace = "0"
|
||||||
|
hw.ibrs_disable = "1"
|
||||||
|
|
||||||
|
|
||||||
|
[FILESEC]
|
||||||
|
lockout_other_group = chmod o= /etc/ftpusers /etc/group /etc/hosts /etc/hosts.allow /etc/hosts.equiv /etc/hosts.lpd /etc/inetd.conf /etc/login.access /etc/login.conf /etc/newsyslog.conf /etc/rc.conf /etc/ssh/sshd_config /etc/sysctl.conf /etc/syslog.conf /etc/ttys /etc/crontab /usr/bin/at /usr/bin/atq /usr/bin/atrm /usr/bin/batch /var/log
|
||||||
|
lockdown_root = chmod 710 /root
|
||||||
|
|
||||||
|
|
||||||
|
[USERSEC]
|
||||||
|
set_cron_root_only = echo "root" | tee /var/cron/allow /var/at/at.allow > /dev/null
|
||||||
|
enable_harden_umask = sed -i .original3 's/umask=022/umask=027/g' /etc/login.conf
|
||||||
|
enable_blowfish_passwords = sed -i .original 's/passwd_format=sha512/passwd_format=blf/g' /etc/login.conf
|
||||||
|
enable_password_reset = sed -i .original 's/^default.*/& \n\t:passwordtime=120d:\\/' /etc/login.conf
|
||||||
|
reset_login = cap_mkdb /etc/login.conf
|
||||||
|
pkg_security_check = pkg audit -Fr > pkg-audit-report
|
||||||
|
|
||||||
|
[SCRIPT]
|
||||||
|
first_run = True
|
||||||
|
|
||||||
45
util/mmap_protect.c
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// Author: u/zabolekar
|
||||||
|
// URL: https://www.reddit.com/r/BSD/comments/10isrl3/notes_about_mmap_mprotect_and_wx_on_different_bsd/
|
||||||
|
// Customized by Quadhelion Engineering
|
||||||
|
// Compile it with cc mmap_mprotect.c, run it with ./a.out
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
void* p = mmap(NULL, 1, PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
|
||||||
|
|
||||||
|
if (p == MAP_FAILED)
|
||||||
|
{
|
||||||
|
perror("\n*********************\033[38;5;76m Success \033[0;0m*************************\n Permission denied for shared memory map write and execute\n*******************************************************\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("\033[38;5;1mVULNERABLE\033[0;0m: Writable and executable memory mapped successfully");
|
||||||
|
munmap(p, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
p = mmap(NULL, 1, PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
|
||||||
|
if (p == MAP_FAILED)
|
||||||
|
{
|
||||||
|
perror("Map writable memory");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("\n * Writable memory mapped successfully");
|
||||||
|
|
||||||
|
if (mprotect(p, 1, PROT_EXEC))
|
||||||
|
perror("Can't make writable memory executable");
|
||||||
|
else
|
||||||
|
puts(" * Preparing writable memory for execution");
|
||||||
|
|
||||||
|
if (mprotect(p, 1, PROT_WRITE|PROT_EXEC))
|
||||||
|
perror("\n*********************\033[38;5;76m Success \033[0;0m*************************\n Can't make shared memory writable and executable\n*******************************************************\n");
|
||||||
|
else
|
||||||
|
puts("\033[38;5;1mVULNERABLE\033[0;0m: Shared memory successfully made writable and executable");
|
||||||
|
|
||||||
|
munmap(p, 1);
|
||||||
|
}
|
||||||
|
puts("\n");
|
||||||
|
}
|
||||||
132
util/pf.conf
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
\##########################################################################
|
||||||
|
## Modern configuration with multiple IPv4 + IPv6, Multicast Lockdown
|
||||||
|
## Multi-homed DNS lockdown, JS stack cache friendly, Redis Lockdown
|
||||||
|
#
|
||||||
|
## FreeBSD 14.0, Dragonfly BSD 6.4 compatible
|
||||||
|
#
|
||||||
|
## Unbound DNS with Quad9 DoT - Tertiary IPv6 ## UNCOMMENT for FreeBSD 14.1
|
||||||
|
## Localhost Redis DB
|
||||||
|
#
|
||||||
|
## Elias Christopher Griffin
|
||||||
|
## https://www.quadhelion.engineering
|
||||||
|
#
|
||||||
|
## LICENSE: CC BY-NC-SA 4.0
|
||||||
|
##
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
## Special thanks to https://forums.freebsd.org/members/mickey.4512/
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
## Macros
|
||||||
|
## CUSTOMIZE
|
||||||
|
##########################################################################
|
||||||
|
ext_if = "vio0"
|
||||||
|
ipv6 = "SET IP HERE"
|
||||||
|
ssh_port = "1974"
|
||||||
|
admin_ips = "{107.77.1.1 107.77.1.2}"
|
||||||
|
admin_ip_range = "107.77.1.1. - 107.77.254.254"
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
## NO CUSTOMIZE ##
|
||||||
|
##
|
||||||
|
## IPv6 link-local, MC
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
PFX_LNKLOC = "FE80::/10"
|
||||||
|
|
||||||
|
# IPv6 Solicited Node Multicast Prefix.
|
||||||
|
MC_SOLNOD = "FF02::1:FF00:0/104"
|
||||||
|
|
||||||
|
# IPv6 All Nodes Link Local Multicast Address.
|
||||||
|
MC_NODLNK = "FF02::1"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
## Basic policy
|
||||||
|
## IPv6 Link-Local, Multicast, bugs with no-df
|
||||||
|
## Big Tech Email servers using 1460 sized segments
|
||||||
|
##########################################################################
|
||||||
|
scrub in all
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
## Last rule wins, so start with blocking everything incoming
|
||||||
|
##########################################################################
|
||||||
|
# block in log all
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
## Keep loopback fast, skipping filter
|
||||||
|
##########################################################################
|
||||||
|
set skip on lo
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
## Allow all out from host itself
|
||||||
|
## Allow Time and DNS out, remove logs once tested working
|
||||||
|
##########################################################################
|
||||||
|
pass out inet all keep state
|
||||||
|
pass out log proto udp to port 123 keep state
|
||||||
|
|
||||||
|
|
||||||
|
## Allow Quad9 IPv6, DNS over TLS with ECS, stateful return
|
||||||
|
# pass out log on $ext_if proto { udp tcp } from $ipv6 to { 2620:fe::11, 2620:fe::fe:11 } port 853 keep state
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
## Allow IPv6 Multicast, BGP
|
||||||
|
## Ping, traceroute disallowed
|
||||||
|
##########################################################################
|
||||||
|
pass inet6 proto ipv6-icmp all icmp6-type routeradv
|
||||||
|
pass inet6 proto ipv6-icmp all icmp6-type routersol
|
||||||
|
pass inet6 proto ipv6-icmp all icmp6-type neighbradv
|
||||||
|
pass inet6 proto ipv6-icmp all icmp6-type neighbrsol
|
||||||
|
|
||||||
|
|
||||||
|
# Allow NS from unspecified to solicited node multicast address (DAD)
|
||||||
|
pass quick inet6 proto icmp6 from :: to $MC_SOLNOD icmp6-type neighbrsol no state
|
||||||
|
|
||||||
|
|
||||||
|
# Allow IPv6 Router Discovery.
|
||||||
|
pass in quick inet6 proto icmp6 from $PFX_LNKLOC to $MC_NODLNK icmp6-type routeradv no state
|
||||||
|
|
||||||
|
|
||||||
|
# Allow IPv6 Neighbor Discovery (ND/NUD/DAD).
|
||||||
|
pass in quick inet6 proto icmp6 from { $PFX_LNKLOC, ($ext_if:network) } to { ($ext_if), $MC_SOLNOD } icmp6-type neighbrsol no state
|
||||||
|
pass in quick inet6 proto icmp6 from { $PFX_LNKLOC, ($ext_if:network) } to { ($ext_if), $MC_NODLNK } icmp6-type neighbradv no state
|
||||||
|
|
||||||
|
# Allow SSH
|
||||||
|
pass quick proto tcp from $admin_ips to port $ssh_port
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
## Packet filtering
|
||||||
|
## Watch pf in realtime: $ tcpdump -n -e -ttt -i pflog0
|
||||||
|
## Correlate to rules: $ pfctl -vvsr
|
||||||
|
##########################################################################
|
||||||
|
antispoof log quick for $ext_if
|
||||||
|
|
||||||
|
|
||||||
|
## Block anything coming form source we have no back routes for
|
||||||
|
block drop in log from no-route to any
|
||||||
|
|
||||||
|
# Block outside access to Redis
|
||||||
|
block in log on ! lo0 proto tcp to port 6379
|
||||||
|
|
||||||
|
|
||||||
|
## Block packets whose ingress interface does not match the one
|
||||||
|
## the route back to their source address
|
||||||
|
block drop in log from urpf-failed to any
|
||||||
|
|
||||||
|
|
||||||
|
# By default, do not permit remote connections to X11
|
||||||
|
block return in log on ! lo0 proto tcp to port 6000:6010
|
||||||
|
|
||||||
17
util/robots.txt
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
location = /robots.txt {
|
||||||
|
add_header Content-Type text/plain;
|
||||||
|
return 200 "User-agent: GPTBot \nUser-agent: ChatGPT-User\nUser-agent: Google-Extended\nUser-agent: CCBot\nUser-agent: baiduspider\nUser-agent: AdsBot-Google\nUser-agent: Mediapartners-Google\nUser-agent: Google-Safety\nUser-agent: anthropic-ai \nDisallow: /\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# User-agent: GPTBot
|
||||||
|
# User-agent: ChatGPT-User
|
||||||
|
# User-agent: Google-Extended
|
||||||
|
# User-agent: CCBot
|
||||||
|
# User-agent: baiduspider
|
||||||
|
# User-agent: AdsBot-Google
|
||||||
|
# User-agent: Mediapartners-Google
|
||||||
|
# User-agent: Google-Safety
|
||||||
|
# User-agent: anthropic-ai
|
||||||
|
# Disallow: /
|
||||||