├── DISCLAIMER.txt ├── lighttpd-rejection.conf ├── smb.conf Anonymous SMB access Not Secure ├── StartupScriptDisableNetBIOSandLMHOSTS.ps1 ├── .bashrc ├── Set-NTPServerUp.ps1 ├── cronjob-vsftpd-cert-expires.sh ├── Set-RdpSslCertificate.ps1 ├── Set-AOVPNServerProfile.ps1 ├── Bastillion LDAPS Tempalte for jaas.conf ├── Update-Gitea.ps1 ├── Microsoft.PowerShell_profile.ps1 ├── .tmux.conf ├── apache2-security.conf ├── SetupRADIUSserver.ps1 ├── 1-ConfigureWindowsFTPS-CreateFTP-UsersAndGroup.ps1 ├── vsftpd-profile.sh ├── lighttpd-external.conf ├── apache2file-000-default.conf ├── Cloudflare Dynamic DNS Update.ps1 ├── WindowsSandboxSetup.ps1 ├── Set-NewLDAPSCertificate.ps1 ├── ccpd-config.yml ├── oscap-cmd-reference.sh ├── vsftpd.conf for FTP over SSL ├── README.md ├── apache2-mods-enabled-ssl.conf ├── vsftpd.conf Anonymous Downloads ├── vsftpd-installer.sh ├── update_semaphore.sh ├── vsftpd.conf Anonymous Uploads ├── New-AOVPNClientProfile.ps1 ├── .vimrc ├── apache2-default-ssl.conf ├── fail2ban-templates-jail.local ├── apache2.conf ├── ConfigureDynamicDNS.ps1 ├── Apache LDAPS Template for nagios.conf ├── aap_api_call.sh ├── LAPS-Setup.ps1 ├── postfix-installer.sh ├── postfix-main.cf ├── semaphore_api_call.sh └── 2-ConfigureWindowsFTPS-ConfigureFTPoverSSLserver.ps1 /DISCLAIMER.txt: -------------------------------------------------------------------------------- 1 | DISCLAIMER: 2 | New tchnologies are discovered and recommendations change as new information is learned. This prevents any guaruntee these settings will work with future versions or be consistent over time. These are meant to be a good starting point and should be viewed as a promise of safety. -------------------------------------------------------------------------------- /lighttpd-rejection.conf: -------------------------------------------------------------------------------- 1 | # OsbornePro Template File for Rejecting unwanted User-Agents and Referers 2 | 3 | $HTTP["user-agent"] =~ "\b(curl|wfuzz|python3|python2|python|perl|nmap|ffuf|Fast\ Fuzzer\ U\ Fool|masscan)\b" { url.access-deny = ( "" ) } 4 | 5 | $HTTP["referer"] =~ "(?:\.|^)(blowfish|Catchbot|BecomeBot)$" { url.access-deny = ( "" ) } 6 | 7 | #$HTTP["remote-ip"] =~ "()" { url.access-deny = ( "" ) } 8 | -------------------------------------------------------------------------------- /smb.conf Anonymous SMB access Not Secure: -------------------------------------------------------------------------------- 1 | # Weak config file for Samba in /etc/samba/smb.conf. 2 | # I use this configuration if I am exploiting an Remote File Inclusion (RFI) Vulnerability or something along those lines 3 | 4 | client min protocol = LANMAN1 5 | # Add this to change the minimum SMB protocol. It will improve enum4linux results 6 | 7 | [MyShare] 8 | comment = Weak SMB 9 | path = /tmp 10 | guest ok = yes 11 | browseable = yes 12 | create mask = 0600 13 | directory mask = 0700 14 | -------------------------------------------------------------------------------- /StartupScriptDisableNetBIOSandLMHOSTS.ps1: -------------------------------------------------------------------------------- 1 | Write-Verbose "Disabling NetBIOS and mDNS" 2 | $CIMInstance = Get-CimInstance -Namespace root/CIMV2 -ClassName Win32_NetworkAdapterConfiguration 3 | $CIMInstance | Invoke-CimMethod -MethodName SetTcpipNetbios -Arguments @{TcpipNetbiosOptions=2} 4 | 5 | Write-Verbose "Disabling the use of the LMHOSTS file" 6 | Invoke-CimMethod -Namespace root/CIMV2 -ClassName Win32_NetworkAdapterConfiguration -MethodName EnableWINS -Arguments @{ DNSEnabledForWINSResolution = $False; WINSEnableLMHostsLookup = $False } 7 | -------------------------------------------------------------------------------- /.bashrc: -------------------------------------------------------------------------------- 1 | # These are settings from a Rocky Linux 9.5 .bashrc file 2 | # This is the PS1 variable I like so far. I included everything else in case I ever need it 3 | # .bashrc 4 | 5 | # Source global definitions 6 | if [ -f /etc/bashrc ]; then 7 | . /etc/bashrc 8 | fi 9 | 10 | # User specific environment 11 | if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]] 12 | then 13 | PATH="$HOME/.local/bin:$HOME/bin:$PATH" 14 | fi 15 | export PATH 16 | export EDITOR=vim 17 | export VISUAL=vim 18 | 19 | # Uncomment the following line if you don't like systemctl's auto-paging feature: 20 | # export SYSTEMD_PAGER= 21 | 22 | # User specific aliases and functions 23 | if [ -d ~/.bashrc.d ]; then 24 | for rc in ~/.bashrc.d/*; do 25 | if [ -f "$rc" ]; then 26 | . "$rc" 27 | fi 28 | done 29 | fi 30 | 31 | unset rc 32 | export PS1="\[\033[32m\][\[\033[0m\]\[\033[33m\]\u@\h\[\033[0m\] \[\033[34m\]\W\[\033[32m\]]\[\033[0m\]$ " 33 | 34 | -------------------------------------------------------------------------------- /Set-NTPServerUp.ps1: -------------------------------------------------------------------------------- 1 | $Logo = @" 2 | ╔═══╗░░╔╗░░░░░░░░░░░░╔═══╗░░░░░ 3 | ║╔═╗║░░║║░░░░░░░░░░░░║╔═╗║░░░░░ 4 | ║║░║╠══╣╚═╦══╦═╦═╗╔══╣╚═╝╠═╦══╗ 5 | ║║░║║══╣╔╗║╔╗║╔╣╔╗╣║═╣╔══╣╔╣╔╗║ 6 | ║╚═╝╠══║╚╝║╚╝║║║║║║║═╣║░░║║║╚╝║ 7 | ╚═══╩══╩══╩══╩╝╚╝╚╩══╩╝░░╚╝╚══╝ 8 | =============================== 9 | If you can't beat `em tech `em! 10 | =============================== 11 | https://osbornepro.com 12 | EMAIL: info@osbornepro.com 13 | "@ 14 | Write-Output "$Logo" 15 | 16 | $NTPReg = "HKLM:\SYSTEM\CurrentControlSet\Services\W32Time" 17 | 18 | Write-Output "[*] Enabling UDP port 123 on firewall for NTP connections" 19 | New-NetFirewallRule -DisplayName "Allow NTP" -Profile @('Domain','Private','Public') -Direction Inbound -Action Allow -Protocol UDP -LocalPort 123 -Description "Allow UPD port 123 traffic for NTP connections" 20 | 21 | Write-Output "[*] Enabling NTP Server" 22 | Set-ItemProperty -Path "$NTPReg\TimeProviders\NTPServer" -Name "Enabled" -Value 1 -Force -ErrorAction SilentlyContinue 23 | 24 | Write-Output "[*] Enabling NTP announcements" 25 | Set-ItemProperty -Path "$NTPReg\Config" -Name "AnnounceFlags" -Value 5 -Force -ErrorAction SilentlyContinue 26 | 27 | Restart-Service -Name W32Time -Force 28 | -------------------------------------------------------------------------------- /cronjob-vsftpd-cert-expires.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This script is meant to be used as a cron job that runs once a year. This deletes the expired key and certificate and generates a new certificate for the VSFTPD server to use 4 | # Follow best practices by placing the cronjob-vsftpd-cert-expires.sh script into /usr/local/sbin/ allowing the root user to execute it. Then modify permissions so only the root user can see the script 5 | # chmod 700 /usr/local/sbin/cronjob-vsftpd-cert-expires.sh 6 | # 7 | # CRONTAB ENTRY EXAMPLE THAT RUNS ONCE A YEAR AS ROOT ON MAY FIRST 8 | # 0 0 1 5 * /bin/bash /usr/local/sbin/cronjob-vsftpd-cert-expires.sh 9 | 10 | /bin/echo "[*] Deleting expired certificate" 11 | /bin/rm -rf --preserve-root -- /etc/ssl/certs/vsftpd.crt 12 | /bin/echo "[*] Deleting expired certificate key" 13 | /bin/rm -rf --preserve-root -- /etc/ssl/private/vsftpd.pem 14 | 15 | /bin/sleep 3s 16 | 17 | /bin/echo "[*] Generating new SSL certificate and key replacement" 18 | /usr/bin/openssl req -newkey rsa:2048 -x509 -sha256 -days 365 -subj '/C=US/ST=Colorado/L=Colorado Springs/CN=ftp.osbornepro.com/O=OsbornePro LLC./OU=Certificates/emailAddress=info@osbornepro.com' -nodes -out /etc/ssl/certs/vsftpd.crt -keyout /etc/ssl/private/vsftpd.pem 19 | 20 | /bin/echo "[*] Restarting the VSFTPD service" 21 | /bin/systemctl restart vsftpd.service 22 | -------------------------------------------------------------------------------- /Set-RdpSslCertificate.ps1: -------------------------------------------------------------------------------- 1 | Import-Module ActiveDirectory 2 | [datetime]$Today = Get-Date 3 | [datetime]$CutOffDate = $Today.AddDays(-60) 4 | [array]$ComputerNames = Get-ADComputer -Properties * -Filter { LastLogonDate -gt $CutOffDate -and Enabled -eq $True } | Select-Object -ExpandProperty Name 5 | 6 | Invoke-Command -HideComputerName $ComputerName -UseSSL -ScriptBlock { 7 | 8 | $CurrentCertificate = Get-CimInstance -Class "Win32_TSGeneralSetting" -Namespace "Root/CimV2/TerminalServices" -Filter "TerminalName='RDP-tcp'" 9 | $NewCertificate = Get-ChildItem -Path "Cert:/LocalMachine/My" | Where-Object -Property "EnhancedKeyUsageList" -like "*Remote Desktop Authentication*" | Sort-Object -Property "Thumbprint" | Select-Object -First 1 10 | $NewCertificatesThumbprint = $NewCertificate.Thumbprint 11 | 12 | If (($CurrentCertificate.SSLCertificateSHA1Hash -notlike $NewCertificate.Thumbprint) -and ($NewCertificate) ) { 13 | 14 | $Path = (Get-WmiObject -Class "Win32_TSGeneralSetting" -Namespace "Root\CimV2\TerminalServices" -Filter "TerminalName='RDP-tcp'").__Path 15 | Set-WmiInstance -Path $Path -Argument @{SSLCertificateSHA1Hash="$NewCertificatesThumbprint"} 16 | Write-Output "[*] Set RDP Certificate on $env:COMPUTERNAME" -ForegroundColor Green 17 | 18 | } # End If 19 | Else { 20 | 21 | Write-Output "[*] Correct certificate is already set or no RDP Cert exists yet on $env:COMPUTERNAME" 22 | 23 | } # End Else 24 | 25 | } # End ScriptBlock 26 | -------------------------------------------------------------------------------- /Set-AOVPNServerProfile.ps1: -------------------------------------------------------------------------------- 1 | # The below commands are used to enable modern encryption algorithms on a Windows Server with Always On VPN 2 | # Be sure to issue the matching commands on the client side which I have in my New-AOVPNClientProfile.ps1 script in this same GitHub repository 3 | 4 | $Logo = @" 5 | ╔═══╗░░╔╗░░░░░░░░░░░░╔═══╗░░░░░ 6 | ║╔═╗║░░║║░░░░░░░░░░░░║╔═╗║░░░░░ 7 | ║║░║╠══╣╚═╦══╦═╦═╗╔══╣╚═╝╠═╦══╗ 8 | ║║░║║══╣╔╗║╔╗║╔╣╔╗╣║═╣╔══╣╔╣╔╗║ 9 | ║╚═╝╠══║╚╝║╚╝║║║║║║║═╣║░░║║║╚╝║ 10 | ╚═══╩══╩══╩══╩╝╚╝╚╩══╩╝░░╚╝╚══╝ 11 | =============================== 12 | If you can't beat `em tech `em! 13 | =============================== 14 | https://osbornepro.com 15 | EMAIL: info@osbornepro.com 16 | "@ 17 | Write-Output "$Logo" 18 | 19 | Set-VpnServerConfiguration -CustomPolicy -AuthenticationTransformConstants SHA256128 -CipherTransformConstants AES128 -DHGroup Group14 -EncryptionMethod AES128 -IntegrityCheckMethod SHA256 -PFSgroup PFS2048 -SALifeTimeSeconds 28800 -MMSALifeTimeSeconds 86400 -SADataSizeForRenegotiationKilobytes 1024000 20 | 21 | $Thumbprint = 'Root CA Certificate Thumbprint' 22 | $RootCACert = (Get-ChildItem -Path Cert:\LocalMachine\root | Where-Object {$_.Thumbprint -eq $Thumbprint}) 23 | 24 | Set-VpnAuthProtocol -RootCertificateNameToAccept $RootCACert -PassThru 25 | 26 | New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\RemoteAccess\Parameters\Ikev2\' -Name CertAuthFlags -PropertyTYpe DWORD -Value 4 -Force 27 | 28 | Restart-Service -Name RemoteAccess -PassThru 29 | -------------------------------------------------------------------------------- /Bastillion LDAPS Tempalte for jaas.conf: -------------------------------------------------------------------------------- 1 | // BASTILLION CONFIG TEMPLATE TO USE LDAP OVER SSL WITH WINDOWS SERVER 2 | // If you followed the documentation from Bastillion this file may be located at C:\Bastillion-jetty\jetty\bastillion\WEB-INF\classes\jaas.conf 3 | 4 | // Below command imports your LDAP over SSL certificate into the java trust store 5 | // cd "C:\Program Files\Java\jdk-\lib\security\cacerts" 6 | // keytool -keystore "C:\Program Files\Java\jdk-\lib\security\cacerts" -import -alias -certificateldaps -file C:\Users\Public\Downlodas\LDAPSNoKey.cer 7 | 8 | ldap-ad { 9 | com.sun.security.auth.module.LdapLoginModule REQUIRED 10 | userProvider="ldap://domain-controller.domain.com:636/DC=domain,DC=com" 11 | authIdentity="{USERNAME}" 12 | userFilter="(&(|(samAccountName={USERNAME})(userPrincipalName={USERNAME})(cn={USERNAME}))(objectClass=user))" 13 | authzIdentity="{displayName}" // returns full names 14 | java.naming.security.authentication="simple" 15 | useSSL=true 16 | debug=true; 17 | }; 18 | ldap-ad-with-roles { 19 | org.eclipse.jetty.jaas.spi.LdapLoginModule required 20 | debug="true" 21 | useLdaps="true" 22 | contextFactory="com.sun.jndi.ldap.LdapCtxFactory" 23 | hostname="domain-controller.domain.com" 24 | port="636" 25 | directGroupExtraction="true" 26 | authenticationMethod="simple" 27 | userGroupAttribute="cn" 28 | forceBindingLogin="false" 29 | userBaseDn="cn=users,dc=domain,dc=com" // Where to look for user names 30 | userRdnAttribute="userPrincipalName" 31 | userIdAttribute="userPrincipalName" 32 | userPasswordAttribute="unicodePwd" 33 | userObjectClass="user" 34 | roleSubtree="true" 35 | roleBaseDn="OU=Groups,DC=domain,DC=com" // where to look for security group 36 | roleNameAttribute="CN" 37 | roleMemberAttribute="member" 38 | roleObjectClass="group"; 39 | }; 40 | -------------------------------------------------------------------------------- /Update-Gitea.ps1: -------------------------------------------------------------------------------- 1 | # This script can be run locally as a task to auto-update Gitea on a Windows Server 2 | # Author: Robert Osborne 3 | # Contact: info@osbornepro.com 4 | 5 | $NewVersion = (Invoke-WebRequest -Uri https://github.com/go-gitea/gitea/releases/latest -UseBasicParsing).BaseResponse.ResponseUri.OriginalString.Split("/")[-1].Replace("v","") 6 | $GiteaParentPath = "C:\gitea" 7 | $CurrentVersion = (."C:\gitea\gitea.exe" --version).ToString().Split(" ")[2] 8 | $GiteaServiceName = "gitea" 9 | 10 | If ($CurrentVersion -ne $NewVersion) { 11 | 12 | Write-Verbose -Message "Gitea not running the latest version" 13 | 14 | $DownloadLink = "https://dl.gitea.io/gitea/$NewVersion/gitea-$NewVersion-gogit-windows-4.0-386.exe" 15 | $Hash = Invoke-WebRequest -Uri "https://dl.gitea.io/gitea/$NewVersion/gitea-$NewVersion-gogit-windows-4.0-386.exe.sha256" -UseBasicParsing -OutFile "$env:TEMP\gitea-$NewVersion-sha256.txt" 16 | $Hash = (Get-Content -Path "$env:TEMP\gitea-$NewVersion-sha256.txt").Split(" ")[0] 17 | $DownloadFile = Invoke-WebRequest -Uri $DownloadLink -UseBasicParsing -OutFile "$env:TEMP\gitea.exe" 18 | $DLFileHash = (Get-FileHash -Path "$env:TEMP\gitea.exe" -Algorithm SHA256).Hash.ToLower() 19 | If ($DLFileHash -eq $Hash) { 20 | 21 | Write-Output -InputObject "[*] Successfully verified SHA256 hash values match" 22 | 23 | Write-Output -InputObject "[*] Stopping the running Gitea service - $GiteaServiceName" 24 | Stop-Service -Name $GiteaServiceName -Force -Confirm:$False 25 | 26 | If (Test-Path -Path "$GiteaParentPath\gitea.exe.old") { 27 | 28 | Write-Output -InputObject "[*] Deleting old Gitea backup executable" 29 | Remove-Item -Path "$GiteaParentPath\gitea.exe.old" -Force -Confirm:$False 30 | 31 | } # End If 32 | 33 | Write-Output -InputObject "[*] Backing up the current Gitea executable" 34 | Rename-Item -Path "$GiteaParentPath\gitea.exe" -NewName "$GiteaParentPath\gitea.exe.old" -Force -Confirm:$False 35 | 36 | Write-Output -InputObject "[*] Using latest version of Gitea executable" 37 | Move-Item -Path "$env:TEMP\gitea.exe" -Destination "$GiteaParentPath\gitea.exe" -Force -Confirm:$False 38 | 39 | Write-Output -InputObject "[*] Starting up the Gitea service" 40 | Start-Service -Name $GiteaServiceName 41 | 42 | } Else { 43 | 44 | Throw "Hash values do not match" 45 | 46 | } # End If Else 47 | 48 | } Else { 49 | 50 | Write-Output -InputObject "[*] Gitea is running the latest version" 51 | 52 | } # End If Else 53 | 54 | -------------------------------------------------------------------------------- /Microsoft.PowerShell_profile.ps1: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------# 2 | # OsbornePro Template : Windows PowerShell Profile # 3 | #----------------------------------------------------# 4 | # Edit this file in your PowerShell session using the below command 5 | # notepad $PROFILE 6 | 7 | Write-Verbose "Setting start directory location." 8 | Set-Location $env:USERPROFILE 9 | 10 | Write-Verbose "Setting Window's Title Header" 11 | $Shell = $Host.UI.RawUI 12 | $Shell.WindowTitle = "OsbornePro: $env:USERNAME" 13 | 14 | Write-Verbose "Setting Window default color combinations" 15 | $Shell.ForegroundColor = 'Gray' 16 | $Shell.BackgroundColor = 'Black' 17 | $TextColors = $Host.PrivateData 18 | $TextColors.DebugForegroundColor = 'Cyan' 19 | $TextColors.VerboseForegroundColor = 'Cyan' 20 | $TextColors.ErrorForegroundColor = 'DarkYellow' 21 | $TextColors.WarningForegroundColor = 'Yellow' 22 | $TextColors.ProgressForegroundColor = 'DarkGreen' 23 | 24 | Write-Verbose "Create a directory to save your PowerShell transcript logs" 25 | New-Item -Path $env:TEMP -Name Transcripts -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null 26 | 27 | Write-Verbose "Delete saved PowerShell transcripts that are older than 7 days" 28 | Get-ChildItem -Path "$env:TEMP\Transcripts" -Force -ErrorAction SilentlyContinue | Where-Object -FilterScript { $_.CreationTime -ge (Get-Date).AddDays(7) } | Remove-Item -Force -Confirm:$False -ErrorAction SilentlyContinue 29 | 30 | Write-Verbose "Save a transcript of your PowerShell sessions. Exiting a powershell session will stop transcription" 31 | $Transcript = "$env:TEMP\Transcripts\$(Get-Date -Format yyyy-MM-dd_hh-mm-ss).txt" 32 | Start-Transcript -Path $Transcript -Force | Out-Null 33 | 34 | Write-Verbose "Clearing output to only show transcript log file location" 35 | Clear-Host 36 | 37 | Write-Output "Path to transript log file saved in `$Transcript" 38 | Write-Host "Welcome back $env:USERNAME!" -ForegroundColor Green 39 | 40 | #Write-Verbose 'Setting the Window Buffer Size' 41 | # $BufferSize = $Shell.BufferSize 42 | # $BufferSize.Width = 120 43 | # $BufferSize.Height = 9001 44 | # $Shell.BufferSize = $BufferSize 45 | 46 | #Write-Verbose "Setting Max Window Size. I don't usually do these becuase it messes with the buffer." 47 | # $MaxWindowSize = $Shell.MaxWindowSize 48 | # $MaxWindowSize.Width = 237 49 | # $MaxWindowSize.Height = 63 50 | # $Shell.BufferSize = $MaxWindowSize 51 | 52 | #Write-Verbose "Setting the Window Size" 53 | # $WindowSize = $Shell.WindowSize 54 | # $WindowSize.Width = 120 55 | # $WindowSize.Height = 30 56 | # $Shell.BufferSize = $WindowSize 57 | -------------------------------------------------------------------------------- /.tmux.conf: -------------------------------------------------------------------------------- 1 | ################################## 2 | # TMUX CUSTOM CONFIGURATION FILE # 3 | ################################## 4 | # 5 | # Remap prefix to Screens 6 | #set -g prefix C-a 7 | #bind C-a send-prefix 8 | #unbind C-b 9 | 10 | # Quality of life stuff 11 | set -g history-limit 50000 12 | set -g allow-rename off 13 | 14 | ## Join Windows 15 | bind-key j command-prompt -p "join pane from:" "join-pane -s '%%'" 16 | bind-key s command-prompt -p "join pane to:" "join-pane -t '%%'" 17 | 18 | # Search Mode VI (default is emac) 19 | set-window-option -g mode-keys vi 20 | # git clone https://github.com/tmux-plugins/tmux-logging.git 21 | run-shell /opt/tmux-logging/logging.tmux 22 | 23 | # Plugins 24 | set -g @plugin 'tmux-plugins/tmux-logging' 25 | 26 | # Uses the default terminal color scheme for text 27 | set -g default-terminal "screen-256color" 28 | 29 | #### COLOUR (Solarized dark) 30 | 31 | # default statusbar colors 32 | set-option -g status-style fg=yellow,bg=black #yellow and base02 33 | 34 | # default window title colors 35 | set-window-option -g window-status-style fg=brightblue,bg=default #base0 and default 36 | #set-window-option -g window-status-style dim 37 | 38 | # active window title colors 39 | set-window-option -g window-status-current-style fg=brightred,bg=default #orange and default 40 | #set-window-option -g window-status-current-style bright 41 | 42 | # pane border 43 | set-option -g pane-border-style fg=black #base02 44 | set-option -g pane-active-border-style fg=brightgreen #base01 45 | 46 | # message text 47 | set-option -g message-style fg=brightred,bg=black #orange and base01 48 | 49 | # pane number display 50 | set-option -g display-panes-active-colour blue #blue 51 | set-option -g display-panes-colour brightred #orange 52 | 53 | # clock 54 | set-window-option -g clock-mode-colour green #green 55 | 56 | # bell 57 | set-window-option -g window-status-bell-style fg=black,bg=red #base02, red 58 | 59 | 60 | #### COLOUR (Solarized 256) 61 | 62 | # default statusbar colors 63 | #set-option -g status-style fg=colour136,bg=colour235 #yellow and base02 64 | 65 | # default window title colors 66 | #set-window-option -g window-status-style fg=colour244,bg=default #base0 and default 67 | #set-window-option -g window-status-style dim 68 | 69 | # active window title colors 70 | #set-window-option -g window-status-current-style fg=colour166,bg=default #orange and default 71 | #set-window-option -g window-status-current-style bright 72 | 73 | # pane border 74 | #set-option -g pane-border-style fg=colour235 #base02 75 | #set-option -g pane-active-border-style fg=colour240 #base01 76 | 77 | # message text 78 | #set-option -g message-style fg=colour166,bg=colour235 #orange and base02 79 | 80 | # pane number display 81 | #set-option -g display-panes-active-colour colour33 #blue 82 | #set-option -g display-panes-colour colour166 #orange 83 | 84 | # clock 85 | #set-window-option -g clock-mode-colour colour64 #green 86 | 87 | # bell 88 | #set-window-option -g window-status-bell-style fg=colour235,bg=colour160 #base02, red 89 | -------------------------------------------------------------------------------- /apache2-security.conf: -------------------------------------------------------------------------------- 1 | # OsbornePro LLC. Starting Template for /etc/apache2/conf-enabled/security.conf file ```a2enmod headers; a2enmod security2; a2enmod unique_id; a2enmod ssl``` 2 | # At line 28 you are able to replace the HTML Header value "Server" with whatever you like to hide the set Apache value 3 | # 4 | # Disable access to the entire file system except for the directories that 5 | # are explicitly allowed later. 6 | # 7 | # This currently breaks the configurations that come with some web application 8 | # Debian packages. 9 | # 10 | # 11 | # AllowOverride None 12 | # Require all denied 13 | # 14 | 15 | # Changing the following options will not really affect the security of the 16 | # server, but might make attacks slightly more difficult in some cases. 17 | 18 | # 19 | # ServerTokens 20 | # This directive configures what you return as the Server HTTP response 21 | # Header. The default is 'Full' which sends information about the OS-Type 22 | # and compiled in modules. 23 | # Set to one of: Full | OS | Minimal | Minor | Major | Prod 24 | # where Full conveys the most information, and Prod the least. 25 | #ServerTokens Minimal 26 | ServerTokens Full 27 | #ServerTokens ProductOnly 28 | SecServerSignature "Whatever you want" 29 | 30 | # 31 | # Optionally add a line containing the server version and virtual host 32 | # name to server-generated pages (internal error documents, FTP directory 33 | # listings, mod_status and mod_info output etc., but not CGI generated 34 | # documents or custom error documents). 35 | # Set to "EMail" to also include a mailto: link to the ServerAdmin. 36 | # Set to one of: On | Off | EMail 37 | ServerSignature Off 38 | 39 | # 40 | # Allow TRACE method 41 | # 42 | # Set to "extended" to also reflect the request body (only for testing and 43 | # diagnostic purposes). 44 | # 45 | # Set to one of: On | Off | extended 46 | #TraceEnable On 47 | TraceEnable Off 48 | 49 | # 50 | # Forbid access to version control directories 51 | # 52 | # If you use version control systems in your document root, you should 53 | # probably deny access to their directories. For example, for subversion: 54 | # 55 | # 56 | # Require all denied 57 | # 58 | 59 | # 60 | # Setting this header will prevent MSIE from interpreting files as something 61 | # else than declared by the content type in the HTTP headers. 62 | # Requires mod_headers to be enabled. 63 | # 64 | #Header set X-Content-Type-Options: "nosniff" 65 | 66 | # 67 | # Setting this header will prevent other sites from embedding pages from this 68 | # site as frames. This defends against clickjacking attacks. 69 | # Requires mod_headers to be enabled. 70 | # 71 | #Header set X-Frame-Options: "sameorigin" 72 | 73 | Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains" 74 | Header always append X-Frame-Options SAMEORIGIN 75 | Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure 76 | Header set X-XSS-Protection "1; mode=block" 77 | 78 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet 79 | -------------------------------------------------------------------------------- /SetupRADIUSserver.ps1: -------------------------------------------------------------------------------- 1 | $Logo = @" 2 | ╔═══╗░░╔╗░░░░░░░░░░░░╔═══╗░░░░░ 3 | ║╔═╗║░░║║░░░░░░░░░░░░║╔═╗║░░░░░ 4 | ║║░║╠══╣╚═╦══╦═╦═╗╔══╣╚═╝╠═╦══╗ 5 | ║║░║║══╣╔╗║╔╗║╔╣╔╗╣║═╣╔══╣╔╣╔╗║ 6 | ║╚═╝╠══║╚╝║╚╝║║║║║║║═╣║░░║║║╚╝║ 7 | ╚═══╩══╩══╩══╩╝╚╝╚╩══╩╝░░╚╝╚══╝ 8 | =============================== 9 | If you can't beat `em tech `em! 10 | =============================== 11 | https://osbornepro.com 12 | EMAIL: info@osbornepro.com 13 | "@ 14 | Write-Output "$Logo" 15 | # Easily Invoke DC Replication to access newly created certificate tempaltes right away 16 | # LINK : https://github.com/tobor88/PowerShell/blob/master/Invoke-DCReplication.ps1 17 | 18 | # This script is used to help set up the RADIUS configuration on Windows Server 2019 19 | Write-Output "[*] Installing Network Policy Authentication Server and management tools on $env:COMPUTERNAME" 20 | Install-WindowsFeature -Name "NPAS" -IncludeManagementTools 21 | 22 | Write-Output "[*] Creating a firewall rule to allow RADIUS authentication" 23 | New-NetFirewallRule -DisplayName "Allow RADIUS Authentication" -Direction Inbound -LocalPort 1812,1645 -Protocol UDP -Action Allow -Name "Allow RADIUS Authentication" -Description "Allows communication over RADIUS authentication ports" 24 | 25 | Write-Output "[*] Creating a firewall rule to allow RADIUS accounting" 26 | New-NetFirewallRule -DisplayName "Allow RADIUS Accounting" -Direction Inbound -LocalPort 1813,1646 -Protocol UDP -Action Allow -Name "Allow RADIUS Accounting" -Description "Allows communication over RADIUS accounting ports" 27 | 28 | Write-Output "[*] Creating a randomly generated string to use as your secure shared secret. Save this value in your Documentation somewhere so it can be retrieved at a later date if needed" 29 | $SharedSecret = ( -Join ((0x30..0x39) + ( 0x41..0x5A) + ( 0x61..0x7A) | Get-Random -Count 36 | ForEach-Object {[Char]$_}) ) 30 | 31 | Write-Output "`n`t[-] SHARED SECRET : $SharedSecret`n" 32 | 33 | Write-Output "[*] Creating RADIUS client groups. This can be a subnet or single IP for RADIUS clients allowed to authenticate to the RADIUS server. (Not computers, an example would be RADIUS proxies, Network Access Servers, and Access Points)" 34 | $Loop = 'y' 35 | While ($Loop -like "y*") 36 | { 37 | 38 | $Address = Read-Host -Prompt "Define a single IP address or subnet range used EXAMPLE: 10.0.0.0/24" 39 | $Name = Read-Host -Prompt "Define a name for this client/subnet to make it identifiable to you. EXAMPLE: NJ Wireless APs" 40 | 41 | New-NpsRadiusClient -Address $Address -Name $Name -SharedSecret $SharedSecret 42 | 43 | $Loop = Read-Host -Prompt "Would you like to add another IP or subnet? [y/N]" 44 | 45 | } # End While 46 | 47 | Write-Warning "Save the Shared Secret value $SharedSecret for later use if you have not already done so" 48 | 49 | Write-Output "[*] If you would like to ensure TLSv1.2 is used by the Supplicants you can issue the below PowerShell command to force TLSv1.2 in the EAPOL communication" 50 | Write-Output "New-ItemProperty -Path 'HKLM:SYSTEM\CurrentControlSet\Services\RasMan\PPP\EAP\13' -Name TlsVersion -Value 3072" 51 | 52 | Pause 53 | -------------------------------------------------------------------------------- /1-ConfigureWindowsFTPS-CreateFTP-UsersAndGroup.ps1: -------------------------------------------------------------------------------- 1 | # This script is meant to be executed on a Primary Domain Controller. This will create an FTP Users group and FTP Admins group using a name you define. 2 | # This script will then use the contents of a CSV file to add users to their respective groups and define their FTP home directories in Active Directory 3 | # 4 | # This script will need a CSV file with contents similar to those below 5 | # 6 | # CONTENTS OF UserList.csv ---------------------------- 7 | #SamAccountName,Directory,Root,Permission 8 | #rosborne,\\ftp.osbornepro.com\FTPS,\,Admin 9 | #legion,\\ftp.osbornepro.com\FTPS\ShadowKing,\,User 10 | #theshadowking,\\ftp.osbornepro.com\FTPS\Legion,\,User 11 | # END CONTENTS OF UsersList.csv ----------------------- 12 | # 13 | $Logo = @" 14 | ╔═══╗░░╔╗░░░░░░░░░░░░╔═══╗░░░░░ 15 | ║╔═╗║░░║║░░░░░░░░░░░░║╔═╗║░░░░░ 16 | ║║░║╠══╣╚═╦══╦═╦═╗╔══╣╚═╝╠═╦══╗ 17 | ║║░║║══╣╔╗║╔╗║╔╣╔╗╣║═╣╔══╣╔╣╔╗║ 18 | ║╚═╝╠══║╚╝║╚╝║║║║║║║═╣║░░║║║╚╝║ 19 | ╚═══╩══╩══╩══╩╝╚╝╚╩══╩╝░░╚╝╚══╝ 20 | =============================== 21 | If you can't beat `em tech `em! 22 | =============================== 23 | "@ 24 | Write-Output "$Logo" 25 | 26 | If (Test-Path -Path $env:USERPROFILE\Documents\UserList.csv) { 27 | 28 | Write-Output "[*] UserList.csv file has been found to exist" 29 | 30 | } Else { 31 | 32 | New-Item -Path $env:USERPROFILE\Documents\UserList.csv -ItemType File -Value "SamAccountName,Directory,Root,Permission`nrosborne,\\ca.osbornepro.com\C$\inetpub\ftproot,\FTPS,Admin" 33 | Read-Host -Prompt "[!] The $env:USERPROFILE\Documents\UserList.csv file did not exist. It has now been created. Add values to the files and press ENTER when you are ready. Read the comments of this script to obtain the correct Header values to use" 34 | 35 | } # End If Else 36 | 37 | Import-Module -Name ActiveDirectory -Global 38 | 39 | $AdminGroup = Read-Host -Prompt "Enter a name for the FTP admins group. EXAMPLE: FTP-Admins" 40 | $UserGroup = Read-Host -Prompt "Enter a name for the FTP Users group. EXAMPLE: FTP-Users" 41 | 42 | Write-Output "[*] Creating AD FTP users group $UserGroup" 43 | New-ADGroup -Name $UserGroup -GroupScope Global -GroupCategory Security -Confirm:$False 44 | 45 | Write-Output "[*] Creating AD FTP admin group $AdminGroup" 46 | New-ADGroup -Name $AdminGroup -GroupScope Global -GroupCategory Security -Confirm:$False 47 | 48 | 49 | Write-Output "[*] Importing users from CSV file" 50 | $Users = Import-Csv -Path "$env:USERPROFILE\Documents\UserList.csv" -Delimiter "," 51 | 52 | ForEach ($User In $Users) { 53 | 54 | $SamAccountName = $User.SamAccountName 55 | $MSiisFTPdir = $User.Directory 56 | $MSiisFTPRoot = $User.Root 57 | $Permission = $User.Permission 58 | 59 | If ($Permission -eq 'User') { 60 | 61 | Write-Output "[*] Adding $SamAccountName to $UserGroup" 62 | Add-ADGroupMember -Identity $UserGroup -Members $SamAccountName 63 | 64 | } ElseIf ($Permission -eq 'Admin') { 65 | 66 | Write-Output "[*] Adding $SamAccountName to $AdminGroup" 67 | Add-ADGroupMember -Identity $AdminGroup -Members $SamAccountName 68 | 69 | } # End If ElseIf 70 | 71 | Write-Output "[*] Setting $SamAccountName FTP root dir attributes" 72 | Set-ADUser -Identity $SamAccountName -Replace @{'msIIS-FTPDir'=$MSiisFTPdir; 'msIIS-FTPRoot'=$MSiisFTPRoot} 73 | 74 | } # End ForEach 75 | -------------------------------------------------------------------------------- /vsftpd-profile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | USAGE=" 3 | 4 | SYNTAX: $0 [-h] [-u | -d] 5 | 6 | 7 | DESCRIPTION: 8 | This script is used to specify whether the vsftp server should active anonymous downloads or anonymous uploads 9 | 10 | 11 | REQUIREMENTS: 12 | 1.) The config files must be named vsftpd-anon-downloads.conf and vsftpd-anon-uploads.conf 13 | 2.) Debian OS will auto-set the config directory as /etc Fedora is /etc/vsftpd which are the package installer defaults 14 | 15 | 16 | CONTACT INFORMATION 17 | Company: OsbornePro LLC. 18 | Website: https://osbornepro.com 19 | Author: Robert H. Osborne 20 | Contact: rosborne@osbornepro.com 21 | 22 | 23 | USAGE: $0 [-u | -d] 24 | 25 | OPTIONS: 26 | -h : Displays the help information for the command. 27 | -u : Switch VSFTPD server to use Anonymous Uploads Configuration 28 | -d : Switch VSFTPD server to use Anonymous Downloads Configuration 29 | 30 | EXAMPLES: 31 | $0 -u 32 | # On Fedora this example uses the /etc/vsftpd/vsftpd-anon-uploads.conf configuration file with VSFTPD 33 | # On Debian this example uses the /etc/vsftpd-anon-uploads.conf configuration file with VSFTPD 34 | 35 | $0 -d 36 | # On Fedora this example uses the /etc/vsftpd/vsftpd-anon-downloads.conf configuration file with VSFTPD 37 | # On Debian this example uses the /etc/vsftpd-anon-downloads.conf configuration file with VSFTPD 38 | 39 | " 40 | 41 | function allow_ctrlc { 42 | 43 | # Allow Ctrl+C to stop execution 44 | trap ' 45 | trap - INT # restore default INT handler 46 | kill -s INT "$$" 47 | ' INT 48 | 49 | } # End function allow_ctrlc 50 | 51 | 52 | function print_usage { 53 | 54 | printf "$USAGE\n" >&2 55 | exit 1 56 | 57 | } # End function print_usage 58 | 59 | function change_configfile { 60 | 61 | cp "${CONFIGFILE}" "${VSFTPDPATH}/vsftpd.conf" 62 | 63 | } 64 | 65 | function restart_vsftpd_service { 66 | 67 | printf "[*] Restarting the VSFTPD service \n" 68 | systemctl restart vsftpd.service 69 | 70 | } 71 | 72 | 73 | OSID=$(grep ID_LIKE /etc/os-release | cut -d"=" -f 2) 74 | if [ "$OSID" == '"debian"' ]; then 75 | printf "[*] Using the Debian based OS settings \n" 76 | VSFTPDPATH="/etc" 77 | elif [ "$OSID" == '"fedora"' ]; then 78 | printf "[*] Using the Fedora based OS settings \n" 79 | VSFTPDPATH="/etc/vsftpd" 80 | else 81 | printf "[!] Operating system ID is not Debian or Fedora \n" 82 | exit 1 83 | fi 84 | 85 | while [ ! -z "$1" ]; do 86 | case "$1" in 87 | -u) 88 | shift 89 | CONFIGFILE="${VSFTPDPATH}/vsftpd-anon-uploads.conf" 90 | printf "[*] Using the UPLOADS configuration \n" 91 | ;; 92 | -d) 93 | shift 94 | CONFIGFILE="${VSFTPDPATH}/vsftpd-anon-downloads.conf" 95 | printf "[*] Using the DOWNLOADS configuration \n" 96 | ;; 97 | *) 98 | print_usage 99 | ;; 100 | esac 101 | shift 102 | done 103 | 104 | change_configfile 105 | restart_vsftpd_service 106 | -------------------------------------------------------------------------------- /lighttpd-external.conf: -------------------------------------------------------------------------------- 1 | # OsbornePro LLC. Lighttpd Config Template 2 | # 3 | # This configuration file is at /etc/lighttpd/external.conf 4 | # This is configuration I added to harden my Pi-Hole web server 5 | 6 | # mod_evasive 7 | evasive.max-conns-per-ip = 2 8 | evasive.silent = "disable" 9 | #evasive.location = "https://hostname.domain.com/302.html" 10 | 11 | # Uncomment the below line to also load my rejections.conf template with whatever modifications you like 12 | #include "/etc/lighttpd/rejections.conf" 13 | 14 | $HTTP["host"] == "hostname.domain.com" { 15 | # Ensure the Pi-hole Block Page knows that this is not a blocked domain 16 | setenv.add-environment = ("fqdn" => "true") 17 | 18 | 19 | 20 | #================================================================================================================================================================ 21 | # When setenv.add-response-header is defined in external.conf you need to delete the matching values in lighttpd.conf as they can only be defined in one location 22 | #================================================================================================================================================================ 23 | $HTTP["url"] =~ "^/admin/" { 24 | # Create a response header for debugging using curl -I 25 | setenv.add-response-header = ( 26 | "Strict-Transport-Security" => "max-age=15768000; includeSubdomains; preload", 27 | "X-XSS-Protection" => "1; mode=block", 28 | "X-Pi-hole" => "The Pi-hole Web interface is working!", 29 | "X-Frame-Options" => "DENY" 30 | ) 31 | $HTTP["url"] =~ "\.(eot|otf|tt[cf]|woff2?)$" { 32 | # Allow Block Page access to local fonts 33 | setenv.add-response-header = ( "Access-Control-Allow-Origin" => "*" ) 34 | } 35 | } 36 | 37 | # Enable the SSL engine with a LE cert, only for this specific host 38 | $SERVER["socket"] == ":443" { 39 | ssl.engine = "enable" 40 | ssl.pemfile = "/etc/lighttpd/cert.pem" # Where your SSL cert is 41 | ssl.ca-file = "/etc/lighttpd/ca.pem" # Where your SSL cert's CA file is 42 | # ssl.use-compression = "disable" # Lighttpd v1.4.28-2 and above disables SSL compression at compile time to protect against CVE-2012-4929 43 | ssl.openssl.ssl-conf-cmd = ("Protocol" => "-TLSv1.1, -TLSv1") # Add -SSLv3 or -SSLv2 to this value later on if needed 44 | ssl.use-sslv2 = "disable" # Option will be retired with version 1.4.29 and above 45 | ssl.use-sslv3 = "disable" # Option will be retired with version 1.4.29 and above 46 | ssl.dh-file = "/etc/lighttpd/dhparam4096.pem" # Generate using ```openssl dhparam -out /etc/lighttpd/dhparam4096.pem 4096``` 47 | ssl.ec-curve = "secp521r1" # View list of options using ```openssl ecparam -list_curves``` 48 | ssl.disable-client-renegotiation = "enable" 49 | ######################################### 50 | # Stapling requires Lighttpdv1.4.56 51 | ######################################### 52 | # Correct format of stapling file can be produced using the below command 53 | # openssl ocsp -issuer /etc/lighttpd/ca.pem -cert /etc/lighttpd/cert.pem -respout /etc/lighttpd/ocsp-resp -noverify -no_nonce -url http://r3.o.lencr.org/ocsp 54 | # ssl.stapling-file = "/etc/lighttpd/ocsp-resp" 55 | } 56 | 57 | # Redirect HTTP to HTTPS 58 | $HTTP["scheme"] == "http" { 59 | $HTTP["host"] =~ ".*" { 60 | url.redirect = (".*" => "https://%0$0") # Redirect all hosts to their secure equivilants 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /apache2file-000-default.conf: -------------------------------------------------------------------------------- 1 | # OsbornePro LLC. Starting Template for the /etc/apache2/sites-enabled/000-default.conf file 2 | # This is meant as a starting template to help secure apache 3 | # The custom ports I defined are just to show they can be changed if needed and do not suggest the ports are more secure than the defaults 4 | 5 | 6 | # Rewrite engine will not work unless these are high up on your config file 7 | RewriteEngine on 8 | # Block HTTP 0.9 and HTTP/1.0 9 | RewriteCond %{SERVER_PROTOCOL} ^HTTP0\.9$ [NC,OR] 10 | RewriteCond %{SERVER_PROTOCOL} ^HTTP/1\.0$ [NC] 11 | RewriteRule .* - [F] 12 | 13 | # Block TRACE TRACK and OPTIONS HTML type requests 14 | RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK|OPTIONS) 15 | RewriteRule .* - [F] 16 | 17 | # Block Unwanted User Agents 18 | RewriteCond %{HTTP_USER_AGENT} python [NC,OR] 19 | RewriteCond %{HTTP_USER_AGENT} wfuzz [NC,OR] 20 | RewriteCond %{HTTP_USER_AGENT} go [NC,OR] 21 | RewriteCond %{HTTP_USER_AGENT} ^Fuzz\ Faster\ U\ Fool [NC,OR] 22 | RewriteCond %{HTTP_USER_AGENT} ^Mozilla/4\.0\ \(compatible [NC,OR] 23 | ReWriteCond %{HTTP_USER_AGENT} curl [NC] 24 | RewriteRule .* - [F] 25 | 26 | # Block unwanted Referers 27 | RewriteCond %{HTTP_REFERER} blowfish|CatchBot|BecomeBot [NC] 28 | RewriteRule .* - [F,L] 29 | ServerName You Server FQDN Here 30 | ServerAdmin admin@domain.com 31 | DocumentRoot /var/www/html 32 | 33 | # Forward HTTP to HTTPS 34 | Redirect / https://site.domain.com:4443/ 35 | 36 | # Below header settings require ```sudo a2enmod headers``` headers module to be enabled 37 | # Or add to your httpd.conf file ```LoadModule headers_module /usr/lib/apache2/modules/mod_headers.so``` 38 | # Use HSTS, protect cookies, XSS Protection 39 | Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains" 40 | Header always append X-Frame-Options SAMEORIGIN 41 | Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure 42 | Header set X-XSS-Protection "1; mode=block" 43 | 44 | 45 | # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, 46 | # error, crit, alert, emerg. 47 | # It is also possible to configure the loglevel for particular 48 | # modules, e.g. 49 | LogLevel info ssl:warn 50 | ErrorLog ${APACHE_LOG_DIR}/error.log 51 | CustomLog ${APACHE_LOG_DIR}/access.log combined 52 | 53 | # For most configuration files from conf-available/, which are 54 | # enabled or disabled at a global level, it is possible to 55 | # include a line for only one particular virtual host. For example the 56 | # following line enables the CGI configuration for this host only 57 | # after it has been globally disabled with "a2disconf". 58 | #Include conf-available/serve-cgi-bin.conf 59 | 60 | 61 | RewriteEngine on 62 | RewriteRule "^/$" "uriextensionIfYouHaveOneToForwardToo" [R] 63 | 64 | 65 | 66 | 67 | RedirectMatch 404 ^/custom_404.html$ 68 | 69 | 70 | 71 | 72 | 73 | RedirectMatch 404 ^/custom_50x.html$ 74 | 75 | 76 | 77 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet 78 | -------------------------------------------------------------------------------- /Cloudflare Dynamic DNS Update.ps1: -------------------------------------------------------------------------------- 1 | # PURPOSE: Automatically update your Dynamic DNS records if Cloudflare hosts your Domains DNS settings 2 | # 3 | # HOW: This script is meant to be run with Task Scheduler whenever you login or start up your computer. 4 | # 5 | $Email = 'cloudflare-email-account@domain.com' 6 | $Token = 'ur_TokenFromCLoudflareGoesHere' 7 | $Domain = 'domain.com' 8 | $Record = 'myvpn.domain.com' 9 | 10 | # Build the request headers once. These headers will be used throughout the script. 11 | $Headers = @{ 12 | "X-Auth-Email" = $($Email) 13 | "Authorization" = "Bearer $($Token)" 14 | "Content-Type" = "application/json" 15 | } # End Headers 16 | 17 | #Region Token Test 18 | ## This block verifies that your API key is valid. 19 | ## If not, the script will terminate. 20 | 21 | $Uri = "https://api.cloudflare.com/client/v4/user/tokens/verify" 22 | 23 | $Auth_result = Invoke-RestMethod -Method GET -Uri $Uri -Headers $Headers 24 | If (!($Auth_result.result)) { 25 | 26 | Write-Output "API token validation failed. Error: $($Auth_result.errors.message). Terminating script." 27 | # Exit script 28 | Return 29 | 30 | } # End If 31 | Write-Output "API token validation [$($Token)] success. $($Auth_result.messages.message)." 32 | #EndRegion 33 | 34 | #Region Get Zone ID 35 | ## Retrieves the domain's zone identifier based on the zone name. If the identifier is not found, the script will terminate. 36 | $Uri = "https://api.cloudflare.com/client/v4/zones?name=$($Domain)" 37 | $DnsZone = Invoke-RestMethod -Method GET -Uri $Uri -Headers $Headers 38 | If (!($DnsZone.result)) { 39 | 40 | Write-Output "Search for the DNS domain [$($Domain)] return zero results. Terminating script." 41 | # Exit script 42 | Return 43 | 44 | } # End If 45 | ## Store the DNS zone ID 46 | $Zone_id = $DnsZone.result.id 47 | Write-Output "Domain zone [$($Domain)]: ID=$($Zone_id)" 48 | #End Region 49 | 50 | #Region Get DNS Record 51 | ## Retrieve the existing DNS record details from Cloudflare. 52 | $Uri = "https://api.cloudflare.com/client/v4/zones/$($zone_id)/dns_records?name=$($Record)" 53 | $DnsRecord = Invoke-RestMethod -Method GET -Uri $Uri -Headers $Headers 54 | If (!($DnsRecord.result)) { 55 | 56 | Write-Output "Search for the DNS record [$($Record)] return zero results. Terminating script." 57 | # Exit script 58 | Return 59 | 60 | } 61 | ## Store the existing IP address in the DNS record 62 | $Old_ip = $DnsRecord.result.content 63 | ## Store the DNS record type value 64 | $Record_type = $DnsRecord.result.type 65 | ## Store the DNS record id value 66 | $Record_id = $DnsRecord.result.id 67 | ## Store the DNS record ttl value 68 | $Record_ttl = $DnsRecord.result.ttl 69 | ## Store the DNS record proxied value 70 | $Record_proxied = $DnsRecord.result.proxied 71 | Write-Output "DNS record [$($Record)]: Type=$($Record_type), IP=$($Old_ip)" 72 | #EndRegion 73 | 74 | #Region Get Current Public IP Address 75 | $New_ip = Invoke-RestMethod -Uri 'https://v4.ident.me' 76 | Write-Output "Public IP Address: OLD=$($Old_ip), NEW=$($New_ip)" 77 | #EndRegion 78 | 79 | #Region update Dynamic DNS Record 80 | ## Compare current IP address with the DNS record 81 | ## If the current IP address does not match the DNS record IP address, update the DNS record. 82 | If ($New_ip -ne $Old_ip) { 83 | 84 | Write-Output "The current IP address does not match the DNS record IP address. Attempt to update." 85 | ## Update the DNS record with the new IP address 86 | $Uri = "https://api.cloudflare.com/client/v4/zones/$($zone_id)/dns_records/$($record_id)" 87 | $Body = @{ 88 | type = $Record_type 89 | name = $Record 90 | content = $New_ip 91 | ttl = $Record_ttl 92 | proxied = $Record_proxied 93 | } | ConvertTo-Json 94 | 95 | $Update = Invoke-RestMethod -Method PUT -Uri $Uri -Headers $Headers -Body $Body 96 | If (($Update.errors)) { 97 | 98 | Write-Output "DNS record update failed. Error: $($Update[0].errors.message)" 99 | ## Exit script 100 | Return 101 | 102 | } # End If 103 | 104 | Write-Output "DNS record update successful." 105 | Return ($Update.result) 106 | 107 | } Else { 108 | 109 | Write-Output "The current IP address and DNS record IP address are the same. There's no need to update." 110 | 111 | } # End If Else 112 | -------------------------------------------------------------------------------- /WindowsSandboxSetup.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 3.0 2 | #Requires -RunAsAdministrator 3 | <# 4 | .SYNOPSIS 5 | This script is used to setup common security tools in the Windows Sanbox environment 6 | 7 | 8 | .DESCRIPTION 9 | Quickly setup your Windows Sandbox for security investigations 10 | 11 | 12 | .PARAMETER DownloadDirectory 13 | Specify the directory to download the tools and applications into 14 | 15 | 16 | .EXAMPLE 17 | PS> .\WindowsSandboxSetup.ps1 18 | # This example downloads security tools into your Downloads directory 19 | 20 | .EXAMPLE 21 | PS> .\WindowsSandboxSetup.ps1 -DownloadDirectory "$env:USERPROFILE\Downloads" 22 | # This example downloads security tools into your Downloads directory 23 | 24 | .EXAMPLE 25 | Invoke-Expression -Command (New-Object -TypeName System.Net.WebClient).downloadString('https://raw.githubusercontent.com/OsbornePro/ConfigTemplates/main/WindowsSandboxSetup.ps1') 26 | # This example downloads security tools into your Downloads directory by executing the script existing in GitHub 27 | 28 | 29 | .NOTES 30 | Author: Robert H. Osborne 31 | Alias: tobor 32 | Contact: info@osbornepro.com 33 | 34 | 35 | .INPUTS 36 | None 37 | 38 | 39 | .OUTPUTS 40 | None 41 | #> 42 | [CmdletBinding()] 43 | param( 44 | [Parameter( 45 | Mandatory=$False 46 | )] # End Parameter 47 | [System.IO.FileInfo]$DownloadDirectory = "$env:USERPROFILE\Downloads" 48 | ) # End param 49 | 50 | $ContentType = "application/octet-stream" 51 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 52 | 53 | $SysmonUrl = "https://download.sysinternals.com/files/Sysmon.zip" 54 | $AutoRunsUrl = "https://download.sysinternals.com/files/Autoruns.zip" 55 | $ProcMonUrl = "https://download.sysinternals.com/files/ProcessMonitor.zip" 56 | $SysmonConfigTemplateUrl = "https://raw.githubusercontent.com/SwiftOnSecurity/sysmon-config/master/sysmonconfig-export.xml" 57 | 58 | $AllLinks = @($ProcMonUrl, $AutoRunsUrl, $SysmonUrl, $SysmonConfigTemplateUrl) 59 | ForEach ($Uri in $AllLinks) { 60 | 61 | $OutFile = "$($DownloadDirectory.FullName)\$($Uri.Split('/')[-1])" 62 | Try { 63 | 64 | Invoke-WebRequest -UseBasicParsing -Uri $Uri -Method GET -UserAgent $UserAgent -ContentType $ContentType -OutFile $OutFile -Verbose:$False 65 | 66 | } Catch { 67 | 68 | $WebClient = New-Object -TypeName System.Net.WebClient 69 | $WebClient.DownloadFile($Uri, $OutFile) 70 | 71 | } # End Try Catch 72 | 73 | If (!(Test-Path -Path $OutFile)) { 74 | 75 | Write-Warning -Message "[!] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Failed to download $OutFile from $Uri" 76 | 77 | } Else { 78 | 79 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded $OutFile from $Uri" 80 | 81 | 82 | $ProgramName = ($Uri.Split('/')[-1]).Split('.')[0] 83 | If ($ProgramName -like 'sysmonconfig-export') { 84 | 85 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Moving $ProgramName to sysmon destination" 86 | Move-Item -Path $OutFile -Destination "$env:ProgramFiles\Sysmon\sysmon-config.xml" -Force -Verbose:$False | Out-Null 87 | 88 | } Else { 89 | 90 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Extracting $ProgramName from $OutFile into $env:ProgramFiles\$ProgramName" 91 | New-Item -Path $env:ProgramFiles -Name $ProgramName -ItemType Directory -Verbose:$False -WhatIf:$False -ErrorAction SilentlyContinue | Out-Null 92 | Expand-Archive -Path $OutFile -DestinationPath "$env:ProgramFiles\$ProgramName" -Force -WhatIf:$False -Verbose:$False | Out-Null 93 | 94 | } # End If Else 95 | 96 | } # End If Else 97 | 98 | } # End ForEach 99 | 100 | Set-Location -Path "$env:ProgramFiles\Sysmon" -Verbose:$False 101 | .\sysmon.exe /accepteula /i .\sysmon-config.xml 102 | 103 | $SysmonInstalled = Get-WinEvent -FilterHashtable @{LogName="Microsoft-Windows-Sysmon/Operational"; Id=16; StartTime=(Get-Date).AddHours(-1)} 104 | If (!($SysmonInstalled)) { 105 | 106 | Invoke-Expression -Command '.\sysmon.exe /accepteula /i .\sysmon-config.xml' 107 | 108 | } # End If 109 | -------------------------------------------------------------------------------- /Set-NewLDAPSCertificate.ps1: -------------------------------------------------------------------------------- 1 | # This script is used to install an LDAPS certificate in the NTDS Personal and AD LDS service name stores to update the LDAPS certificate 2 | $Logo = @" 3 | ╔═══╗░░╔╗░░░░░░░░░░░░╔═══╗░░░░░ 4 | ║╔═╗║░░║║░░░░░░░░░░░░║╔═╗║░░░░░ 5 | ║║░║╠══╣╚═╦══╦═╦═╗╔══╣╚═╝╠═╦══╗ 6 | ║║░║║══╣╔╗║╔╗║╔╣╔╗╣║═╣╔══╣╔╣╔╗║ 7 | ║╚═╝╠══║╚╝║╚╝║║║║║║║═╣║░░║║║╚╝║ 8 | ╚═══╩══╩══╩══╩╝╚╝╚╩══╩╝░░╚╝╚══╝ 9 | =============================== 10 | If you can't beat `em tech `em! 11 | =============================== 12 | https://osbornepro.com 13 | EMAIL: info@osbornepro.com 14 | "@ 15 | Write-Output "$Logo" 16 | # https://github.com/tobor88/PowerShell/blob/master/Hide-PowerShellScriptPassword.ps1 17 | $KeyPassword = "LDAPS-S3cr3t-Pa55w0rd" # I have a script at the above link you can use to encrypt this value so it does not show in clear text 18 | $SecurePassword = ConvertTo-SecureString -String $KeyPassword -Force –AsPlainText 19 | #$CertPath = "$env:USERPROFILE\Downloads\LDAPS.pfx" 20 | $LDAPSTemplateName = "LDAP over SSL" 21 | $ServiceNames = "NTDS",((Get-CimInstance -ClassName Win32_Service -Filter 'Name LIKE "%ADAM%"').Name) 22 | # NTDS is the default LDAP service. 23 | # AD LDS if installed will have a custom service name you set 24 | # I try to discover that automatically for you using a search for a process with ADAM in the name 25 | 26 | 27 | Write-Output "[*] Obtaining LDAP over SSL certificate by Template Name from the local machine certificate store" 28 | $LDAPSCert = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object -FilterScript { $_.Extensions | Where-Object -FilterScript { ($_.Oid.FriendlyName -eq "Certificate Template Information") -and ($_.Format(0) -Match $LDAPSTemplateName) }} 29 | $ExpiringCert = Get-ChildItem -Path Cert:\LocalMachine\My -ExpiringInDays 30 | Where-Object -FilterScript { $_.Extensions | Where-Object -FilterScript { ($_.Oid.FriendlyName -eq "Certificate Template Information") -and ($_.Format(0) -Match $LDAPSTemplateName) }} 30 | 31 | If (($LDAPSCert -Contains $ExpiringCert) -and ($Null -ne $LDAPSCert[1])) { 32 | 33 | $LDAPSCert = $LDAPSCert | Where-Object -Property Thumbprint -ne $ExpiringCert.Thumbprint 34 | 35 | } # End If 36 | ElseIf ($LDAPSCert -eq $ExpiringCert) { 37 | 38 | Write-Output "[*] Renewing LDAPS certificate with the same keys" 39 | Start-Process -WorkingDirectory "C:\Windows\System32" -FilePath certreq.exe -ArgumentList @('-Enroll', '-machine', '-q', '-cert', $LDAPSCert.SerialNumber, 'Renew', 'ReuseKeys') -Wait 40 | 41 | $LDAPSCert = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object -FilterScript { $_.Extensions | Where-Object -FilterScript { ($_.Oid.FriendlyName -eq "Certificate Template Information") -and ($_.Format(0) -Match $LDAPSTemplateName) }} 42 | $ExpiringCert = Get-ChildItem -Path Cert:\LocalMachine\My -ExpiringInDays 90 | Where-Object -FilterScript { $_.Extensions | Where-Object -FilterScript { ($_.Oid.FriendlyName -eq "Certificate Template Information") -and ($_.Format(0) -Match $LDAPSTemplateName) }} 43 | If (($LDAPSCert -ne $ExpiringCert) -and ($Null -ne $ExpiringCert)) { 44 | 45 | Write-Output "[*] Deleting the old certificate from the LocalMachine Certificate store. New certificate has a different thumbprint" 46 | Get-ChildItem -Path "Cert:\LocalMachine\My\$($ExpiringCert.Thubprint)" | Remove-Item -Force 47 | 48 | } # End If 49 | 50 | } # End ElseIf 51 | ElseIf ($LDAPSCert -ne $ExpiringCert) { 52 | 53 | Throw "LDAPS Certificate is not ready to be renewed" 54 | 55 | } # End Else 56 | 57 | # The commented area below is just in case we need to export or import a PFX certificate into the localmachine store 58 | # 59 | #Write-Output "[*] Exporting LDAPS certificate from LocalMachine store" 60 | #Export-PfxCertificate -FilePath $CertPath -Password $SecurePassword 61 | 62 | #Write-Output "[*] Importing new PFX LDAPS Certificate into store" 63 | #Import-PfxCertificate -FilePath $CertPath -CertStoreLocation "Cert:\LocalMachine\My" -Confirm:$False -Password $SecurePassword -Exportable 64 | 65 | $Path = "HKLM:\SOFTWARE\Microsoft\SystemCertificates\MY\Certificates\$($LDAPSCert.Thumbprint)" 66 | 67 | Write-Output "[*] Telling LDAPS services to use the new LDAPS Certificate" 68 | ForEach ($ServiceName in $ServiceNames) { 69 | 70 | If ($ServiceName.Length -gt 0) { 71 | 72 | If (Test-Path -Path $Path) { 73 | 74 | Write-Output "[*] Moving PFX certificate into the NTDS\Personal Certificate Store" 75 | Copy-Item -Path $Path -Destination "HKLM:\SOFTWARE\Microsoft\Cryptography\Services\$ServiceName\SystemCertificates\MY\Certificates\" 76 | 77 | Write-Output "[*] Restarting the $ServiceName service" 78 | Restart-Service -Name $ServiceName -Force 79 | 80 | } # End If 81 | Else { 82 | 83 | Write-Warning "Expected registry path defining LDAPS certificate does not exist" 84 | 85 | } # End Else 86 | 87 | } # End If 88 | 89 | } # End ForEach 90 | -------------------------------------------------------------------------------- /ccpd-config.yml: -------------------------------------------------------------------------------- 1 | # LINK TO DOCS: https://cis-cat-pro-dashboard.readthedocs.io/en/stable/source/Dashboard%20Deployment%20Guide%20for%20Windows/ 2 | # APPLICATION : CCPD (CIS-CAT Pro Dashboad) 3 | # SERVER HOST : Windows Server 2016 - 2019 4 | # SQL SERVER : MS SQL Server 2017 - 2019 5 | # 6 | # This is a starting template for CIS CAT Pro Dashboard (CCPD) that configures LDAP over SSL Usage for Authentication with STARTTLS emails 7 | # This will require you to manually modify values according to your environment. You will need to import your LDAPS issuing CA certificate into the Java trust store 8 | # 9 | # IMPORT CA CERTIFICATE INTO TRUSTED JAVA KEY STORE 10 | # cd "C:\Program Files\AdoptOpenJDK\jdk-11.0.9.101\bin" 11 | # .\keytool -import -alias ca -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -file ca.der 12 | # 13 | # VERIFY SUCCESSFUL IMPORT 14 | # .\keytool -keystore "$JAVA_HOME/jre/lib/security/cacerts" -storepass changeit -list | grep startssl 15 | 16 | legacy: 17 | sourceDir: "C:/Tomcat/legacy/source" 18 | processedDir: "C:/Tomcat/legacy/processed" 19 | errorDir: "C:/Tomcat/legacy/error" 20 | 21 | environments: 22 | production: 23 | grails: 24 | serverURL: 'https://CCPDserverFQDN.domain.com/CCPD' ############################################################### 25 | server: 26 | 'contextPath': '/CCPD' 27 | dataSource: 28 | dbCreate: update 29 | 30 | #DB Settings 31 | 32 | driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver 33 | dialect: org.hibernate.dialect.SQLServer2008Dialect 34 | url: jdbc:sqlserver://SQLserverHostName:1433;databaseName=CCPD ############################################# 35 | username: 'sa' 36 | password: 'SuperSecurePassword123!' ######################################################################## 37 | 38 | properties: 39 | jmxEnabled: true 40 | initialSize: 5 41 | maxActive: 50 42 | minIdle: 5 43 | maxIdle: 25 44 | maxWait: 10000 45 | maxAge: 600000 46 | validationQuery: SELECT 1 47 | validationQueryTimeout: 3 48 | validationInterval: 15000 49 | defaultTransactionIsolation: 1 50 | dbProperties: 51 | autoReconnect: true 52 | 53 | grails: 54 | mail: 55 | host: "smtp.outlook.com" ######################################### 56 | port: 587 ########################################################## 57 | username: "do-not-reply@domain.com" ################################ 58 | password: "SMTPaccoutnPassword123" ################################# 59 | props: 60 | mail.smtp.starttls.enable: "true" 61 | mail.smtp.port: "587" 62 | assessorService: 63 | active: true 64 | url: 'http://localhost:2222' 65 | ignoreSslCertErrors: true 66 | 67 | plugin: 68 | springsecurity: 69 | providerNames: ['ldapAuthProvider','rememberMeAuthenticationProvider','restAuthenticationProvider','anonymousAuthenticationProvider'] 70 | ldap: 71 | active: true 72 | context: 73 | managerDn: 'cn=LDAP Admin,ou=Admin Accounts,dc=Domain,dc=Com' ########################### 74 | managerPassword: 'LDAPqueryPassword123' ################################################# 75 | server: 'ldaps://dc01.domain.com:636' ################################################### 76 | authorities: 77 | ignorePartialResultException: true 78 | retrieveDatabaseRoles: false 79 | retrieveGroupRoles: true 80 | groupSearchBase: 'ou=Groups,dc=domain,dc=com' ########################################### 81 | groupSearchFilter: 'member={0}' ########################################################## 82 | groupRoleAttribute: 'cn' ########################################################### 83 | clean: 84 | prefix: 'CCPD_' ###################################################################### 85 | search: 86 | base: 'dc=domain,dc=com' ################################################################ 87 | filter: 'sAMAccountName={0}' 88 | auth: 89 | hideUserNotFoundExceptions: false 90 | authenticator: 91 | passwordAttributeName: 'userPassword' 92 | mapper: 93 | passwordAttributeName: 'userPassword' 94 | useRememberMe: true 95 | rememberMe: 96 | persistent: true 97 | 98 | database: SQLServer 99 | -------------------------------------------------------------------------------- /oscap-cmd-reference.sh: -------------------------------------------------------------------------------- 1 | # This is a collection of commands that can be used for SCAP compliance 2 | ################################# 3 | # SETUP OPENSCAP 4 | ################################# 5 | # Install OpenSCAP 6 | sudo dnf install -y scap-security-guide openscap-scanner 7 | 8 | # Make folder for reports 9 | sudo mkdir -p /usr/share/openscap/reports 10 | sudo cd /usr/share/openscap/reports 11 | sudo umask 077 12 | sudo chown root:root -R /usr/share/openscap/reports 13 | 14 | ################################# 15 | # PREPARE FOR SCAN 16 | ################################# 17 | # View available data streams 18 | sudo ls -la /usr/share/xml/scap/ssg/content 19 | 20 | # List Profiles in a data stream 21 | sudo oscap info /usr/share/xml/scap/ssg/content/ssg-rl9-ds.xml 22 | 23 | ################################# 24 | # SCAN AND EXPORT HTML 25 | ################################# 26 | # CIS Server Level 1 27 | sudo oscap xccdf eval --report /usr/share/openscap/reports/scan-report.html --profile xccdf_org.ssgproject.content_profile_cis_server_l1 /usr/share/xml/scap/ssg/content/ssg-rl9-ds.xml 28 | # CIS Server Level 2 29 | sudo oscap xccdf eval --report /usr/share/openscap/reports/scan-report.html --profile xccdf_org.ssgproject.content_profile_cis /usr/share/xml/scap/ssg/content/ssg-rl9-ds.xml 30 | # CIS Workstation Level 1 31 | sudo oscap xccdf eval --report /usr/share/openscap/reports/scan-report.html --profile xccdf_org.ssgproject.content_profile_cis_workstation_l1 /usr/share/xml/scap/ssg/content/ssg-rl9-ds.xml 32 | # CIS Workstation Level 2 33 | sudo oscap xccdf eval --report /usr/share/openscap/reports/scan-report.html --profile xccdf_org.ssgproject.content_profile_cis_workstation_l2 /usr/share/xml/scap/ssg/content/ssg-rl9-ds.xml 34 | # PCI-DSS v4.0.1 35 | sudo oscap xccdf eval --report /usr/share/openscap/reports/scan-report.html --profile xccdf_org.ssgproject.content_profile_pci-dss /usr/share/xml/scap/ssg/content/ssg-rl9-ds.xml 36 | 37 | ################################# 38 | # SCAN AND GENERATE REMEDIATION 39 | ################################# 40 | # *** WARNING WARNING WARNING *************************************************** 41 | # Review this before running it! It will make significant changes to the system. 42 | # I typically remove some password settings for domain joined devices 43 | # I also may need services like nfs-server if i need it 44 | #******************************************************************************** 45 | # 1.) Generate Scan Results 46 | sudo oscap xccdf eval --results /usr/share/openscap/reports/openscap-scan-results.xml --profile xccdf_org.ssgproject.content_profile_cis /usr/share/xml/scap/ssg/content/ssg-rl9-ds.xml 47 | # 2.) Generate Bash Script for remediation 48 | sudo oscap xccdf generate fix --output "/usr/local/sbin/$(hostname)-scap-remediation.sh" --profile xccdf_org.ssgproject.content_profile_cis /usr/share/xml/scap/ssg/content/ssg-rl9-ds.xml 49 | # Generate ansible playbook for remediation 50 | sudo oscap xccdf generate fix --fix-type ansible --output "~ansible/ansible/playbooks/$(hostname)-scap-remediation.yml" --profile xccdf_org.ssgproject.content_profile_cis /usr/share/xml/scap/ssg/content/ssg-rl9-ds.xml 51 | 52 | ################################# 53 | # APACHE SCAP COMPLIANCE 54 | ################################# 55 | # Install requirements 56 | sudo dnf install -y httpd mod_ssl 57 | # Configuration Changes 58 | sed -i 's/^\([^#].*\)**/# \1/g' /etc/httpd/conf.d/welcome.conf 59 | dnf -y remove httpd-manual 60 | dnf -y install mod_session 61 | 62 | echo "MaxKeepAliveRequests 100" > /etc/httpd/conf.d/disa-apache-stig.conf 63 | echo "SessionCookieName session path=/; HttpOnly; Secure;" >> /etc/httpd/conf.d/disa-apache-stig.conf 64 | echo "Session On" >> /etc/httpd/conf.d/disa-apache-stig.conf 65 | echo "SessionMaxAge 600" >> /etc/httpd/conf.d/disa-apache-stig.conf 66 | echo "SessionCryptoCipher aes256" >> /etc/httpd/conf.d/disa-apache-stig.conf 67 | echo "Timeout 10" >> /etc/httpd/conf.d/disa-apache-stig.conf 68 | echo "TraceEnable Off" >> /etc/httpd/conf.d/disa-apache-stig.conf 69 | echo "RequestReadTimeout 120" >> /etc/httpd/conf.d/disa-apache-stig.conf 70 | 71 | sed -i "s/^#LoadModule usertrack_module/LoadModule usertrack_module/g" /etc/httpd/conf.modules.d/00-optional.conf 72 | sed -i "s/proxy_module/#proxy_module/g" /etc/httpd/conf.modules.d/00-proxy.conf 73 | sed -i "s/proxy_ajp_module/#proxy_ajp_module/g" /etc/httpd/conf.modules.d/00-proxy.conf 74 | sed -i "s/proxy_balancer_module/#proxy_balancer_module/g" /etc/httpd/conf.modules.d/00-proxy.conf 75 | sed -i "s/proxy_ftp_module/#proxy_ftp_module/g" /etc/httpd/conf.modules.d/00-proxy.conf 76 | sed -i "s/proxy_http_module/#proxy_http_module/g" /etc/httpd/conf.modules.d/00-proxy.conf 77 | sed -i "s/proxy_connect_module/#proxy_connect_module/g" /etc/httpd/conf.modules.d/00-proxy.conf 78 | 79 | firewall-cmd --zone=public --add-service=https --permanent 80 | firewall-cmd --zone=public --add-service=https 81 | firewall-cmd --reload 82 | systemctl enable httpd 83 | systemctl start httpd 84 | 85 | # STIG CONTROLS FOR APACHE 86 | # REFERENCE: https://docs.rockylinux.org/books/disa_stig/disa_stig_part3/ 87 | -------------------------------------------------------------------------------- /vsftpd.conf for FTP over SSL: -------------------------------------------------------------------------------- 1 | #============================================================================ 2 | # CONFIG FOR VSFTPD SERVER THAT SECURELY ALLOWS LOCAL USER CHROOT FTPS ACCESS 3 | #============================================================================ 4 | # INSTALL COMMAND: 5 | # sudo apt update && apt install -y vsftpd 6 | # 7 | # GENERATE CERTIFICATES IF YOU WISH TO USE SSL 8 | # sudo openssl req -x509 -nodes -keyout /etc/ssl/private/vsftpd.pem -out /etc/ssl/certs/vsftpd.crt -days 365 -newkey rsa:2048 9 | # 10 | # CREATE DIRECTORY FOR LOCAL USERS TO UPLOAD AND DOWNLOAD FROM 11 | # NOTE: The below creates the FTP home directory in user home directories 12 | # sudo -i 13 | # useradd ftpsecure 14 | # USERS=$(ls /home) 15 | # for u in $USERS; do 16 | # echo $u >> /etc/vsftpd.userlist 17 | # mkdir -p /home/$u/ftp/files 18 | # chown nobody:nogroup /home/$u/ftp 19 | # chown $u:$u /home/$u/ftp/files 20 | # chmod a-w /home/$u/ftp 21 | # done 22 | # 23 | # DOWNLOAD AND USE THIS CONFIGURATION FILE 24 | # sudo mv /etc/vsftpd.conf /etc/vsftpd.conf.orig && echo "[*] Created backup of original /etc/vsftpd.conf file at /etc/vsftpd.conf.orig" 25 | # sudo wget https://raw.githubusercontent.com/OsbornePro/ConfigTemplates/main/vsftpd.conf%20for%20FTP%20over%20SSL -O /etc/vsftpd.conf 26 | # sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.bak && echo "[*] Created backup of active /etc/vsftpd.conf file at /etc/vsftpd.conf.bak" 27 | # 28 | # CONFIGURE FIREWALL RULES TO ALLOW FTP USING WHATEVER FIREWALL YOu USe 29 | # FIREWALL-CMD 30 | # sudo firewall-cmd --zone=public --add-port=21/tcp --permanent 31 | # sudo firewall-cmd --zone=public --add-port=20/tcp --permanent 32 | # sudo firewall-cmd --zone=public --add-port=40000-41000/tcp 33 | # sudo firewall-cmd --reload 34 | # IPTABLES 35 | # iptables -A INPUT -p tcp -m tcp --dport 21 -j ACCEPT 36 | # iptables -A INPUT -p tcp -m tcp --dport 20 -j ACCEPT 37 | # iptables -A OUTPUT -p tcp -m tcp --sport 21 -j ACCEPT 38 | # iptables -A OUTPUT -p tcp -m tcp --sport 20 -j ACCEPT 39 | # iptables -A INPUT -p tcp -m tcp --dport 40000:41000 -j ACCEPT 40 | # iptables -A OUTPUT -p tcp -m tcp --sport 40000:41000 -j ACCEPT 41 | # sudo service iptables restart 42 | # UFW 43 | # sudo ufw allow 20:21/tcp 44 | # sudo ufw allow 40000:41000/tcp 45 | # sudo ufw reload 46 | # OR 47 | # sudo ufw allow ftp-data 48 | # sudo ufw allow ftp 49 | # sudo ufw reload 50 | # 51 | #------------------------------------------------------------------------------ 52 | # CONFIGURED SETTINGS 53 | #------------------------------------------------------------------------------ 54 | # LISTENERS 55 | listen=YES 56 | listen_port=21 57 | listen_ipv6=NO 58 | session_support=YES 59 | pasv_enable=YES 60 | connect_from_port_20=YES 61 | ftp_data_port=20 62 | pasv_min_port=40000 63 | pasv_max_port=41000 64 | 65 | # SET THE BELOW VALUE IF YOUR FTP SERVER IS PUBLICLY ACCESSIBLE 66 | #pasv_address= 67 | #pasv_addr_resolve=YES 68 | 69 | # RESTRICT COMMANDS THAT CAN BE EXECUTED 70 | #cmds_allowed=ABOR,ACCT,ALLO,APPE,BINARY,CDUP,CWD,DELE,EPRT,EPSV,FEAT,HELP,LIST,MDTM,MODE,NLST,NOOP,OPTS,PASS,PASV,PORT,PWD,QUIT,REIN,REST,RETR,RMD,RNFR,RNTO,SITE,SIZE,SMNT,STAT,STOR,STOU,STRU,SYST,TYPE,USER,XCUP,XCWD,XPWD,XRMD 71 | #cmds_denied=PUT,MPUT,RM,RMD,RMDIR,XRMD,MKD,MKDIR,XMKD 72 | 73 | # PERMISSIONS 74 | anonymous_enable=NO 75 | local_enable=YES 76 | write_enable=YES 77 | local_umask=022 78 | anon_upload_enable=NO 79 | anon_mkdir_write_enable=NO 80 | user_sub_token=$USER 81 | local_root=/home/$USER/ftp 82 | userlist_enable=YES 83 | userlist_file=/etc/vsftpd.userlist 84 | userlist_deny=NO 85 | allow_writeable_chroot=NO 86 | nopriv_user=ftpsecure 87 | chroot_local_user=YES 88 | secure_chroot_dir=/var/run/vsftpd/empty 89 | ls_recurse_enable=NO 90 | 91 | # LOGGING 92 | syslog_enable=NO 93 | dual_log_enable=YES 94 | vsftpd_log_file=/var/log/vsftpd.log 95 | dirmessage_enable=YES 96 | use_localtime=YES 97 | xferlog_enable=YES 98 | xferlog_file=/var/log/vsftpd.log 99 | xferlog_std_format=NO 100 | log_ftp_protocol=YES 101 | debug_ssl=YES 102 | 103 | # SESSIONS 104 | idle_session_timeout=600 105 | data_connection_timeout=120 106 | 107 | # CHAR 108 | ascii_upload_enable=NO 109 | ascii_download_enable=NO 110 | #utf8_filesystem=YES 111 | 112 | # BANNER 113 | ftpd_banner=OsbornePro LLC. FTP over SSL Server 114 | # OR You can use a file to load a banner 115 | #banner_file=/etc/vsftpd.welcome_banner 116 | 117 | # SERVICE 118 | pam_service_name=ftp 119 | 120 | # SSL SETTINGS 121 | rsa_cert_file=/etc/ssl/certs/vsftpd.crt 122 | rsa_private_key_file=/etc/ssl/private/vsftpd.pem 123 | ssl_enable=YES 124 | ssl_ciphers=HIGH 125 | allow_anon_ssl=NO 126 | force_local_data_ssl=YES 127 | force_local_logins_ssl=YES 128 | ssl_tlsv1=YES 129 | ssl_sslv2=NO 130 | ssl_sslv3=NO 131 | require_ssl_reuse=NO 132 | 133 | # SET THIS TO YES IF YOU ARE USING PORT 990 134 | implicit_ssl=NO 135 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Config Templates 2 | This is a collection of configuration files and configuration scripts that are great starting points. I have tried to include mostly files related to securing different protocols in different ways however that is not always what is needed so I have included some insecure configuations such as in the file smb.conf. 3 | 4 | ### File Description 5 | 1. __tmux.conf__ Configuration file that can be used to start your Tmux configuration 6 | 1. __1-ConfigureWindowsFTPS-CreateFTP-UsersAndGroup.ps1__ This script is meant to be run on a Domain Controller. It creates an FTP users and administrators group 7 | 1. __2-ConfigureWindowsFTPS-ConfigureFTPoverSSLserver.ps1__ This script is meant to be run on a Windows Server 2019 FTPS server hosted through IIS 8 | 1. __Cloudflare Dynamic DNS Update.ps1__ Script from Cloudflare that allows you to update your Dynamic DNS records automatically 9 | 1. __Apache LDAPS Template for nagios.conf__ LDAP over SSL authentication configuration for Nagios Core on Apache 10 | 1. __Bastillion LDAPS Tempalte for jaas.conf__ LDAP over SSL authentication configuration for Bastillion Servers 11 | 1. __Configure-SFTP-Only.ps1__ Setup an SFTP server without SSH open on a Windows Server 12 | 1. __Harden-Windows10.ps1__ Script to harden the Windows 10 Operating System for the everyday user 13 | 1. __LAPS-Setup.ps1__ Performs all the steps required to setup LAPS and keep password backups in an environment 14 | 1. __Microsoft.PowerShell_profile.ps1__ Default PowerShell profile Template that can be used 15 | 1. __New-AOVPNClientProfile.ps1__ Create a Client AOVPN profile that uses Split Tunneling and Certificate authentication with IKEv2 failing over to SSTP 16 | 1. __Set-AOVPNServerProfile.ps1__ Configure AOVPN Server to use Secure Encrpytion algorithms 17 | 1. __Set-NTPServerUp.ps1__ Configure a Windows Server to act as an NTP server which is secure by default 18 | 1, __Set-NewLDAPSCertificate.ps1__ Run this as a task to auto replace expiring LDAP over SSL certificate automatically on Domain Controllers 19 | 1. __Set-RdpSslCertificate.ps1__ Set the SSL certificate used by RDP 20 | 1. __SetupRADIUSserver.ps1__ Script to more quickly add client Authentictors to a RADIUS Authentication NPS Windows Server 21 | 1. __StartupScriptDisableNetBIOSandLMHO__ This script is meant to be run as a startup script in a domain environment to ensure NetBIOS and LLMNR are disabled 22 | 1. __apache2-default-ssl.conf__ Apache defaut-ssl.conf template for using hardened SSL 23 | 1. __apache2-mods-enabled-ssl.conf__ Apache mods-enabled-ssl.conf template for using hardened SSL 24 | 1. __apache2-security.conf__ Apache security.conf configuration template for securing an Apache web server 25 | 1. __apache2.conf__ Apache configuration file template for hardening an Apache web server 26 | 1. __apache2file-000-default.conf__ Apache 000-default.conf configuration file templtae for hardeing the default site profile 27 | 1. __ccpd-config.yml__ Configuration file used to provide a template that allows you to use LDAP over SSL authentication with CIS-CAT Pro Dashboard (CCPD) when it is hosted on a Window Server. The [documentation on their site](https://cis-cat-pro-dashboard.readthedocs.io/en/stable/source/Dashboard%20Deployment%20Guide%20for%20Windows/) does not cover how to define this values when hosted on a Windows Server so I made the info readily available. 28 | 1. __cronjob-vsftpd-cert-expires.sh__ Script can be used as a cronjob that runs once a year to replace expired certificates used by VSFTPD or whatever service you wish to modify this too 29 | 1. __fail2ban-apacheSSH-jail.local__ Configuration file template to use fail2ban to harden open apache and SSH ports 30 | 1. __lighttpd-external.conf__ Configuration file to harden a lighttpd server hosting Pi-Hole 31 | 1. __lighttpd-rejection.conf__ Configuration file to created WAF rules for a lighttpd server hosting a Pi-Hole 32 | 1. __postfix-installer.sh__ This script is used to quickly set up a secure instance of Postfix on a Debian or Fedora OS. This does not include all the security features as the main.cf file below because of other outside factors that are not predictable. This does still set up secured SMTP server options. 33 | 1. __postfix.main.cf__ Hardened Postfix Coniguration file main.cf that uses secure methods of sending emails from your local device 34 | 1. __smb.conf Anonymous SMB access Not Secure__ This Samba configuration file is one I used while performing offensive attacks, hosting payloads over SMB. DO NOT use this as a main configuration for any SMB servers in an enviornment as it is purposefully insecure 35 | 1. __sshd_config__ Great starting place for configuring SSH in a secure manner. I have included/centralized setting descriptors for anyone who may not be familiar with the protocol 36 | 1. __vsftpd-installer.sh__ Bash script to install a secure instance of VSFTPD using FTP over SSL and a whitelisted user list 37 | 1. __vsftpd.conf Anonymous Downloads__ FTP configuration for securely allowing anonymous users to only download files from a server 38 | 1. __vsftpd.conf Anonymous Uploads__ FTP configuration for securely allowing anonymous users to only upload files to a server 39 | 1. __vsftpd.conf for FTP over SSL__ FTP configuration for securely allowing authenticated users to upload or download files to an FTP server 40 | 1. __.vimrc configuraiton for vim that I find help make vim more useful to me 41 | -------------------------------------------------------------------------------- /apache2-mods-enabled-ssl.conf: -------------------------------------------------------------------------------- 1 | # OsbornePro LLC. Starting Template for /etc/apache2/mods-enabled/ssl.conf 2 | # 3 | # Enable the ssl module using the command ```sudo a2enmod ssl``` 4 | # View line 81 in the config below for Diffie Hellman instructions 5 | 6 | 7 | # Pseudo Random Number Generator (PRNG): 8 | # Configure one or more sources to seed the PRNG of the SSL library. 9 | # The seed data should be of good random quality. 10 | # WARNING! On some platforms /dev/random blocks if not enough entropy 11 | # is available. This means you then cannot use the /dev/random device 12 | # because it would lead to very long connection times (as long as 13 | # it requires to make more entropy available). But usually those 14 | # platforms additionally provide a /dev/urandom device which doesn't 15 | # block. So, if available, use this one instead. Read the mod_ssl User 16 | # Manual for more details. 17 | # 18 | SSLRandomSeed startup builtin 19 | SSLRandomSeed startup file:/dev/urandom 512 20 | SSLRandomSeed connect builtin 21 | SSLRandomSeed connect file:/dev/urandom 512 22 | 23 | ## 24 | ## SSL Global Context 25 | ## 26 | ## All SSL configuration in this context applies both to 27 | ## the main server and all SSL-enabled virtual hosts. 28 | ## 29 | 30 | # 31 | # Some MIME-types for downloading Certificates and CRLs 32 | # 33 | AddType application/x-x509-ca-cert .crt 34 | AddType application/x-pkcs7-crl .crl 35 | 36 | # Pass Phrase Dialog: 37 | # Configure the pass phrase gathering process. 38 | # The filtering dialog program (`builtin' is a internal 39 | # terminal dialog) has to provide the pass phrase on stdout. 40 | SSLPassPhraseDialog exec:/usr/share/apache2/ask-for-passphrase 41 | 42 | # Inter-Process Session Cache: 43 | # Configure the SSL Session Cache: First the mechanism 44 | # to use and second the expiring timeout (in seconds). 45 | # (The mechanism dbm has known memory leaks and should not be used). 46 | #SSLSessionCache dbm:${APACHE_RUN_DIR}/ssl_scache 47 | SSLSessionCache shmcb:${APACHE_RUN_DIR}/ssl_scache(512000) 48 | SSLSessionCacheTimeout 300 49 | 50 | # Semaphore: 51 | # Configure the path to the mutual exclusion semaphore the 52 | # SSL engine uses internally for inter-process synchronization. 53 | # (Disabled by default, the global Mutex directive consolidates by default 54 | # this) 55 | #Mutex file:${APACHE_LOCK_DIR}/ssl_mutex ssl-cache 56 | 57 | # The Online Certificate Status Protocol (OCSP) is a mechanism for determining 58 | # whether or not a server certificate has been revoked, and OCSP Stapling is a 59 | # special form of this in which the server, such as httpd and mod_ssl, maintains 60 | # current OCSP responses for its certificates and sends them to clients which 61 | # communicate with the server. Most certificates contain the address of an OCSP 62 | # responder maintained by the issuing Certificate Authority, and mod_ssl can 63 | # communicate with that responder to obtain a signed response that can be sent 64 | # to clients communicating with the server. 65 | 66 | # The protocols to enable. 67 | # Available values: all, SSLv3, TLSv1, TLSv1.1, TLSv1.2 68 | # SSL v2 is no longer supported 69 | SSLProtocol -all +TLSv1.3 +TLSv1.2 70 | SSLCipherSuite TLSv1.3 TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256 71 | 72 | # SSL Cipher Suite: 73 | # List the ciphers that the client is permitted to negotiate. See the 74 | # ciphers(1) man page from the openssl package for list of all available 75 | # options. 76 | # Enable only secure ciphers: 77 | 78 | # If you plan on using TLSv1.2 and do not enabled TLSv1.3 you may need to use the below line for SSLCipherSuite's value 79 | #SSLCipherSuite HIGH:!aNULL:!MD5 80 | SSLCipherSuite SSL ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256 81 | 82 | # Generate the Diffie Hellman key file using the below command 83 | # ```openssl dhparam -out /etc/apache2/dhparam4096.pem 4096``` 84 | SSLOpenSSLConfCmd DHParameters "/etc/apache2/dhparam4096.pem" 85 | 86 | SSLOpenSSLConfCmd Curves X25519:secp521r1:secp384r1:prime256v1 87 | SSLCompression Off 88 | SSLOptions +StrictRequire 89 | #SSLOpenSSLConfCmd ECDHParameters secp521rl 90 | 91 | # SSL server cipher order preference: 92 | # Use server priorities for cipher algorithm choice. 93 | # Clients may prefer lower grade encryption. You should enable this 94 | # option if you want to enforce stronger encryption, and can afford 95 | # the CPU cost, and did not override SSLCipherSuite in a way that puts 96 | # insecure ciphers first. 97 | # Default: Off 98 | SSLHonorCipherOrder on 99 | 100 | 101 | # Allow insecure renegotiation with clients which do not yet support the 102 | # secure renegotiation protocol. Default: Off 103 | SSLInsecureRenegotiation off 104 | 105 | # Whether to forbid non-SNI clients to access name based virtual hosts. 106 | # Default: Off 107 | #SSLStrictSNIVHostCheck On 108 | 109 | 110 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet 111 | -------------------------------------------------------------------------------- /vsftpd.conf Anonymous Downloads: -------------------------------------------------------------------------------- 1 | #============================================================================ 2 | # CONFIG FOR VSFTPD SERVER THAT SECURELY ALLOWS ANONYMOUS DOWNLOADS 3 | #============================================================================ 4 | # INSTALL COMMAND: 5 | # sudo apt update && apt install -y vsftpd 6 | # 7 | # GENERATE CERTIFICATES IF YOU WISH TO USE SSL 8 | # DEBIAN: sudo openssl req -x509 -nodes -keyout /etc/ssl/private/vsftpd.pem -out /etc/ssl/certs/vsftpd.crt -days 365 -newkey rsa:2048 9 | # REHL: sudo openssl req -x509 -nodes -keyout /etc/pki/tls/private/vsftpd.pem -out /etc/pki/tls/certs/vsftpd.crt -days 365 -newkey rsa:2048 10 | # NOTE: If you do want to use SSL be sure to comment out the SSL values at the end of CONFIGURED SETTINGS section below and make ssl_enable=NO 11 | # 12 | # CREATE DIRECTORY FOR ANONYMOUS USER TO DOWNLOAD FROM 13 | # sudo mkdir -p /var/ftp/public 14 | # sudo chown nobody:nogroup /var/ftp/public 15 | # sudo useradd ftpsecure 16 | # sudo touch /etc/vsftpd/email_passwords 17 | # sudo vi /etc/vsftpd/email_passwords # PLACE EMAIL ADDRESSES IN THIS FILE THAT CAN BE USED AS PASSWORDS TO SIGN IN WITH ANONYMOUS ACCESS 18 | # sudo chmod 640 /etc/vsftpd/email_passwords 19 | # 20 | # DOWNLOAD AND USE THIS CONFIGURATION FILE 21 | # DEBIAN: sudo mv /etc/vsftpd.conf /etc/vsftpd.conf.orig && echo "[*] Created backup of original /etc/vsftpd.conf file at /etc/vsftpd.conf.orig" 22 | # RHEL: sudo mv /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.orig && echo "[*] Created backup of original /etc/vsftpd/vsftpd.conf file at /etc/vsftpd/vsftpd.conf.orig" 23 | # DEBINA: sudo wget https://raw.githubusercontent.com/OsbornePro/ConfigTemplates/main/vsftpd.conf%20Anonymous%20Downloads -O /etc/vsftpd.conf 24 | # RHEL: sudo wget https://raw.githubusercontent.com/OsbornePro/ConfigTemplates/main/vsftpd.conf%20Anonymous%20Downloads -O /etc/vsftpd/vsftpd.conf 25 | # DEBINA: sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.bak && echo "[*] Create backup of active /etc/vsftpd.conf file at /etc/vsftpd.conf.bak" 26 | # RHEL: sudo cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.bak && echo "[*] Create backup of active /etc/vsftpd/vsftpd.conf file at /etc/vsftpd/vsftpd.conf.bak" 27 | # 28 | # CONFIGURE FIREWALL RULES TO ALLOW FTP USING WHATEVER FIREWALL YOu USe 29 | # FIREWALL-CMD 30 | # sudo firewall-cmd --zone=public --add-port=21/tcp --permanent 31 | # sudo firewall-cmd --zone=public --add-port=20/tcp --permanent 32 | # sudo firewall-cmd --zone=public --add-port=40000-41000/tcp 33 | # sudo firewall-cmd --reload 34 | # IPTABLES 35 | # iptables -A INPUT -p tcp -m tcp --dport 21 -j ACCEPT 36 | # iptables -A INPUT -p tcp -m tcp --dport 20 -j ACCEPT 37 | # iptables -A OUTPUT -p tcp -m tcp --sport 21 -j ACCEPT 38 | # iptables -A OUTPUT -p tcp -m tcp --sport 20 -j ACCEPT 39 | # iptables -A INPUT -p tcp -m tcp --dport 40000:41000 -j ACCEPT 40 | # iptables -A OUTPUT -p tcp -m tcp --sport 40000:41000 -j ACCEPT 41 | # sudo service iptables restart 42 | # UFW 43 | # sudo ufw allow 20:21/tcp 44 | # sudo ufw allow 40000:41000/tcp 45 | # sudo ufw reload 46 | # OR 47 | # sudo ufw allow ftp-data 48 | # sudo ufw allow ftp 49 | # sudo ufw reload 50 | # 51 | #------------------------------------------------------------------------------ 52 | # CONFIGURED SETTINGS 53 | #------------------------------------------------------------------------------ 54 | anonymous_enable=YES 55 | anon_root=/var/ftp/public/ 56 | local_enable=NO 57 | 58 | # ANON USER PASSWORD SETTINGS 59 | no_anon_password=NO 60 | secure_email_list_enable=YES 61 | # FOR secure_email_list_enable YOU NEED TO ADD EMAIL ADDRESSES/PASSWORDS ONE PER LINE TO THE FILE /etc/vsftpd.email_passwords 62 | 63 | # ANONYMOUS USER CAN ONLY DOWNLOAD WORLD READABLE FILES 64 | anon_world_readable_only=YES 65 | 66 | # RESTRICT COMMANDS THAT CAN BE EXECUTED 67 | #cmds_allowed=ABOR,ACCT,ALLO,APPE,BINARY,CDUP,CWD,DELE,EPRT,EPSV,FEAT,HELP,LIST,MDTM,MODE,NLST,NOOP,OPTS,PASS,PASV,PORT,PWD,QUIT,REIN,REST,RETR,RMD,RNFR,RNTO,SITE,SIZE,SMNT,STAT,STOR,STOU,STRU,SYST,TYPE,USER,XCUP,XCWD,XPWD,XRMD 68 | cmds_denied=PUT,MPUT,RM,RMD,RMDIR,XRMD,MKD,MKDIR,XMKD 69 | 70 | # PREVENT UPLOADS 71 | write_enable=NO 72 | anon_upload_enable=NO 73 | anon_mkdir_write_enable=NO 74 | anon_other_write_enable=NO 75 | 76 | # PERMISSIONS 77 | local_umask=022 78 | ascii_upload_enable=NO 79 | ascii_download_enable=NO 80 | async_abor_enable=YES 81 | ls_recurse_enable=NO 82 | hide_ids=YES 83 | nopriv_user=ftpsecure 84 | secure_chroot_dir=/var/run/vsftpd/empty 85 | 86 | # LISTENER 87 | listen=YES 88 | listen_port=21 89 | listen_ipv6=NO 90 | connect_from_port_20=YES 91 | pasv_min_port=40000 92 | pasv_max_port=41000 93 | 94 | # LOG SETTINGS 95 | log_ftp_protocol=YES 96 | dirmessage_enable=YES 97 | use_localtime=YES 98 | xferlog_enable=YES 99 | xferlog_file=/var/log/vsftpd.log 100 | xferlog_std_format=NO 101 | syslog_enable=NO 102 | dual_log_enable=YES 103 | vsftpd_log_file=/var/log/vsftpd.log 104 | 105 | # BANNER 106 | ftpd_banner=FTP Anonymous Download Server 107 | # OR 108 | #banner_file=/etc/vsftpd.welcome_message 109 | 110 | # SESSION SETTINGS 111 | idle_session_timeout=60 112 | data_connection_timeout=120 113 | accept_timeout=60 114 | connect_timeout=60 115 | anon_max_rate=30000 116 | 117 | # OTHER SETTINGS 118 | utf8_filesystem=YES 119 | one_process_model=YES 120 | pam_service_name=ftp 121 | 122 | # -------------------------------------------------------------------- 123 | # UNCOMMENT BELOW SETTINGS TO USE FTP OVER SSL 124 | #--------------------------------------------------------------------- 125 | # CHANGE BELOW TO ssl_enable=NO if you do not want to use FTP over SSL 126 | ssl_enable=YES 127 | 128 | # COMMENT OUT ALL THE BELOW IF YOU DONT WANT TO USE FTP over SSL 129 | debug_ssl=YES 130 | rsa_cert_file=/etc/ssl/certs/vsftpd.crt 131 | rsa_private_key_file=/etc/ssl/private/vsftpd.pem 132 | ssl_ciphers=HIGH 133 | allow_anon_ssl=YES 134 | implicit_ssl=YES 135 | force_local_data_ssl=YES 136 | force_local_logins_ssl=YES 137 | ssl_tlsv1=YES 138 | ssl_sslv2=NO 139 | ssl_sslv3=NO 140 | require_ssl_reuse=NO 141 | -------------------------------------------------------------------------------- /vsftpd-installer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ################################################################################################### 3 | # DESCRIPTION: # 4 | # This script is used to quickly and easily configure a secure FTP over SSL server on Linux # 5 | # This will allow whitelisted authenticated users upload and download access to personal FTP dir # 6 | # # 7 | # Company: OsbornePro LLC. # 8 | # Website: https://osbornepro.com # 9 | # Author: Robert H. Osborne # 10 | # Contact: rosborne@osbornepro.com # 11 | # # 12 | ################################################################################################### 13 | HOSTNAME=$(hostname) 14 | OSID=$(grep ID_LIKE /etc/os-release | cut -d"=" -f 2) 15 | if [ "$OSID" == '"debian"' ]; then 16 | 17 | printf "[*] Using the Debian based OS settings \n" 18 | CONFFILE="/etc/vsftpd.conf" 19 | CERTFILE="/etc/ssl/certs/vsftpd.crt" 20 | KEYFILE="/etc/ssl/private/vsftpd.key" 21 | USERLIST="/etc/vsftpd.userlist" 22 | 23 | printf "[*] Installing the vsftpd service \n" 24 | apt-get update && apt-get install -y vsftpd openssl ufw 25 | wait 26 | 27 | printf "[*] Opening firewall rules for FTP service" 28 | ufw allow 20:21/tcp 29 | ufw allow 40000:41000/tcp 30 | ufw reload 31 | 32 | elif [ "$OSID" == '"fedora"' ]; then 33 | 34 | printf "[*] Using the Fedora based OS settings \n" 35 | CONFFILE="/etc/vsftpd/vsftpd.conf" 36 | CERTFILE="/etc/pki/tls/certs/vsftpd.crt" 37 | KEYFILE="/etc/pki/tls/private/vsftpd.key" 38 | USERLIST="/etc/vsftpd/vsftpd.userlist" 39 | 40 | printf "[*] Installing the vsftpd service \n" 41 | dnf install -y vsftpd openssl 42 | wait 43 | 44 | printf "[*] Opening firewall rules for FTP service" 45 | firewall-cmd --zone=public --add-port=21/tcp --permanent 46 | firewall-cmd --zone=public --add-port=20/tcp --permanent 47 | firewall-cmd --zone=public --add-port=40000-41000/tcp 48 | firewall-cmd --reload 49 | 50 | else 51 | printf "[!] Operating system ID is not Debian or Fedora \n" 52 | exit 1 53 | fi 54 | 55 | 56 | printf "[*] Backing up original vsftpd.conf file \n" 57 | cp "${CONFFILE}" "${CONFFILE}.orig" && printf "[*] Created backup of originali vsftpd.conf file at ${CONFFILE}.orig \n" 58 | 59 | 60 | CONFIG=$(cat < $CONFFILE 61 | #------------------------------------------------------------------------------ 62 | # CONFIGURED SETTINGS 63 | #------------------------------------------------------------------------------ 64 | # LISTENERS 65 | listen=YES 66 | listen_port=21 67 | listen_ipv6=NO 68 | session_support=YES 69 | pasv_enable=YES 70 | connect_from_port_20=YES 71 | ftp_data_port=20 72 | pasv_min_port=40000 73 | pasv_max_port=41000 74 | 75 | # SET THE BELOW VALUE IF YOUR FTP SERVER IS PUBLICLY ACCESSIBLE 76 | #pasv_address= 77 | #pasv_addr_resolve=YES 78 | 79 | # RESTRICT COMMANDS THAT CAN BE EXECUTED 80 | #cmds_allowed=ABOR,ACCT,ALLO,APPE,BINARY,CDUP,CWD,DELE,EPRT,EPSV,FEAT,HELP,LIST,MDTM,MODE,NLST,NOOP,OPTS,PASS,PASV,PORT,PWD,QUIT,REIN,REST,RETR,RMD,RNFR,RNTO,SITE,SIZE,SMNT,STAT,STOR,STOU,STRU,SYST,TYPE,USER,XCUP,XCWD,XPWD,XRMD 81 | #cmds_denied=PUT,MPUT,RM,RMD,RMDIR,XRMD,MKD,MKDIR,XMKD 82 | 83 | # PERMISSIONS 84 | anonymous_enable=NO 85 | local_enable=YES 86 | write_enable=YES 87 | local_umask=022 88 | anon_upload_enable=NO 89 | anon_mkdir_write_enable=NO 90 | user_sub_token=$USER 91 | local_root=/home/$USER/ftp 92 | userlist_enable=YES 93 | userlist_file=$USERLIST 94 | userlist_deny=NO 95 | allow_writeable_chroot=NO 96 | nopriv_user=ftpsecure 97 | chroot_local_user=YES 98 | secure_chroot_dir=/var/run/vsftpd/empty 99 | ls_recurse_enable=NO 100 | 101 | # LOGGING 102 | syslog_enable=NO 103 | dual_log_enable=YES 104 | vsftpd_log_file=/var/log/vsftpd.log 105 | dirmessage_enable=YES 106 | use_localtime=YES 107 | xferlog_enable=YES 108 | xferlog_file=/var/log/vsftpd.log 109 | xferlog_std_format=NO 110 | log_ftp_protocol=YES 111 | debug_ssl=YES 112 | 113 | # SESSIONS 114 | idle_session_timeout=600 115 | data_connection_timeout=120 116 | 117 | # CHAR 118 | ascii_upload_enable=NO 119 | ascii_download_enable=NO 120 | #utf8_filesystem=YES 121 | 122 | # BANNER 123 | ftpd_banner=FTP over SSL Server 124 | # OR You can use a file to load a banner 125 | #banner_file=/etc/vsftpd.welcome_banner 126 | 127 | # SERVICE 128 | pam_service_name=ftp 129 | 130 | # SSL SETTINGS 131 | rsa_cert_file=$CERTFILE 132 | rsa_private_key_file=$KEYFILE 133 | ssl_enable=YES 134 | ssl_ciphers=HIGH 135 | allow_anon_ssl=NO 136 | force_local_data_ssl=YES 137 | force_local_logins_ssl=YES 138 | ssl_tlsv1=YES 139 | ssl_sslv2=NO 140 | ssl_sslv3=NO 141 | require_ssl_reuse=NO 142 | 143 | # SET THIS TO YES IF YOU ARE USING PORT 990 144 | implicit_ssl=NO 145 | EOF 146 | ) 147 | 148 | printf "[*] Generating a self signed SSL certificate \n" 149 | openssl req -newkey rsa:2048 -x509 -sha256 -days 365 -subj "/CN=${HOSTNAME}/OU=Certificates" -nodes -out $CERTFILE -keyout $KEYFILE 150 | wait 151 | 152 | printf "[*] Creating least privilege 'ftpsecure' user for FTP service \n" 153 | useradd ftpsecure 154 | 155 | printf "[*] Creating an FTP directory for all local users on this device and adding them to the allowed FTP users list in $USERLIST \n" 156 | USERS=$(ls /home) 157 | for u in $USERS; do 158 | echo $u >> $USERLIST 159 | mkdir -p /home/$u/ftp/files 160 | chown nobody:nogroup /home/$u/ftp 161 | chown $u:$u /home/$u/ftp/files 162 | chmod a-w /home/$u/ftp 163 | done 164 | 165 | printf "[*] Backing up current VSFTPD configuration file \n" 166 | cp "${CONFFILE}" "${CONFFILE}.bak" && printf "[*] Created backup of active vsftpd.conf file at ${CONFFILE}.bak \n" 167 | 168 | printf "[*] Restarting the VSFTPD service with latest config" 169 | systemctl enable --now vsftpd.service && systemctl status vsftpd.service 170 | -------------------------------------------------------------------------------- /update_semaphore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ################################################################################################### 3 | # DESCRIPTION: # 4 | # This is used to get the current version of Semaphore installed on a server and update it if # 5 | # the current running version is not up to date # 6 | # # 7 | # Company: OsbornePro LLC. # 8 | # Website: https://osbornepro.com # 9 | # Author: Robert H. Osborne # 10 | # Contact: rosborne@osbornepro.com # 11 | ################################################################################################### 12 | # -------------------------- LOCK FILE ----------------------------------------- 13 | LOCKFILE="/var/run/semaphore-update.lock" 14 | 15 | # Acquire an exclusive lock (fd 9). If another instance holds it, exit immediately. 16 | if ! exec 9>"$LOCKFILE"; then 17 | echo "[x] Failed to create lock file $LOCKFILE" >&2 18 | exit 1 19 | fi 20 | 21 | if ! flock -n 9; then 22 | echo "[x] Another update is already running (lock $LOCKFILE held)." >&2 23 | exit 1 24 | fi 25 | 26 | # Ensure the lock is removed on any exit (normal, error, signal) 27 | cleanup() { 28 | rm -f "$LOCKFILE" 2>/dev/null || true 29 | } 30 | trap cleanup EXIT 31 | 32 | # -------------------------- PRE-CHECKS --------------------------------------- 33 | if [[ $EUID -ne 0 ]]; then 34 | echo "[x] This script must be run as root." >&2 35 | exit 1 36 | fi 37 | 38 | for cmd in jq pg_dump curl wget tar sha256sum; do 39 | command -v "$cmd" >/dev/null || { echo "[x] $cmd is required but not installed."; exit 1; } 40 | done 41 | 42 | # -------------------------- CONFIG & DB -------------------------------------- 43 | SERVICE_NAME="semaphore.service" 44 | BACKUP_DIR="/root/semaphore_backup" 45 | TMP_DIR="/tmp" 46 | TIMESTAMP=$(date +%Y%m%d_%H%M%S) 47 | 48 | mkdir -p "$BACKUP_DIR" 49 | 50 | # Extract --config path from the systemd unit (robust) 51 | CONFIG_FILE=$(systemctl show --property=ExecStart --value "$SERVICE_NAME" | 52 | grep -Eo '--config "[^"]+"' | cut -d'"' -f2) 53 | 54 | [[ -f "$CONFIG_FILE" ]] || { echo "[x] Config file not found at $CONFIG_FILE"; exit 1; } 55 | 56 | # Parse PostgreSQL credentials with jq (requires JSON config) 57 | DB_USER=$(jq -r '.postgres.user // empty' "$CONFIG_FILE") 58 | DB_NAME=$(jq -r '.postgres.name // empty' "$CONFIG_FILE") 59 | 60 | [[ -n "$DB_USER" && -n "$DB_NAME" ]] || { echo "[x] DB user/name not found in config."; exit 1; } 61 | 62 | # -------------------------- VERSION HELPERS ---------------------------------- 63 | get_latest_version() { 64 | curl -s "https://api.github.com/repos/semaphoreui/semaphore/releases/latest" | 65 | jq -r '.tag_name' | sed 's/^v//' 66 | } 67 | 68 | get_current_version() { 69 | semaphore version 2>/dev/null | cut -d'-' -f1 || echo "unknown" 70 | } 71 | 72 | # -------------------------- BACKUPS ----------------------------------------- 73 | echo "[-] Backing up config..." 74 | cp -a "$CONFIG_FILE" "$BACKUP_DIR/config.json.bak.$TIMESTAMP" 75 | 76 | echo "[-] Backing up PostgreSQL database..." 77 | BACKUP_SQL="$BACKUP_DIR/semaphore_db_${TIMESTAMP}.dump.gz" 78 | 79 | # Prefer passwordless auth via .pgpass; fall back to prompt if missing 80 | if [[ -f "/root/.pgpass" ]] && grep -q ":$DB_NAME:$DB_USER:" /root/.pgpass; then 81 | pg_dump -U "$DB_USER" -d "$DB_NAME" | gzip > "$BACKUP_SQL" 82 | else 83 | echo "[!] No suitable .pgpass entry. Password required." 84 | read -rsp "PostgreSQL password for $DB_USER: " DB_PASS 85 | echo 86 | export PGPASSWORD="$DB_PASS" 87 | pg_dump -U "$DB_USER" -d "$DB_NAME" | gzip > "$BACKUP_SQL" 88 | unset PGPASSWORD 89 | fi 90 | 91 | [[ ${PIPESTATUS[0]} -eq 0 ]] || { echo "[x] pg_dump failed."; exit 1; } 92 | 93 | # -------------------------- VERSION CHECK ----------------------------------- 94 | LATEST=$(get_latest_version) 95 | CURRENT=$(get_current_version) 96 | 97 | echo "[-] Current Semaphore version: $CURRENT" 98 | echo "[-] Latest Semaphore version : $LATEST" 99 | 100 | [[ "$CURRENT" == "$LATEST" ]] && { echo "[-] Already up to date."; exit 0; } 101 | 102 | # -------------------------- ARCH & DOWNLOAD --------------------------------- 103 | ARCH=$(uname -m) 104 | case "$ARCH" in 105 | x86_64) ARCH="amd64" ;; 106 | i?86) ARCH="386" ;; 107 | *) echo "[x] Unsupported architecture: $ARCH"; exit 1 ;; 108 | esac 109 | 110 | FILE="semaphore_${LATEST}_linux_${ARCH}.tar.gz" 111 | URL="https://github.com/semaphoreui/semaphore/releases/download/v${LATEST}/${FILE}" 112 | CHKSUM_URL="https://github.com/semaphoreui/semaphore/releases/download/v${LATEST}/semaphore_${LATEST}_checksums.txt" 113 | 114 | cd "$TMP_DIR" 115 | echo "[-] Downloading $FILE ..." 116 | wget -q "$URL" -O "$FILE" 117 | wget -q "$CHKSUM_URL" -O "checksums.txt" 118 | 119 | # Verify checksum 120 | if ! grep "$FILE" checksums.txt | sha256sum --check --status; then 121 | echo "[x] Checksum verification failed!"; exit 1 122 | fi 123 | 124 | # -------------------------- UPDATE ------------------------------------------ 125 | echo "[-] Stopping Semaphore service..." 126 | systemctl stop "$SERVICE_NAME" 127 | 128 | echo "[-] Extracting new binary..." 129 | tar -xzf "$FILE" 130 | 131 | CURRENT_BIN=$(which semaphore) 132 | [[ -n "$CURRENT_BIN" && -x "$CURRENT_BIN" ]] || { echo "[x] Existing binary not found in PATH."; exit 1; } 133 | 134 | echo "[-] Replacing binary at $CURRENT_BIN ..." 135 | cp -f semaphore "$CURRENT_BIN" 136 | chmod +x "$CURRENT_BIN" 137 | 138 | # -------------------------- START & VERIFY ---------------------------------- 139 | echo "[-] Starting Semaphore service..." 140 | systemctl start "$SERVICE_NAME" 141 | 142 | sleep 3 143 | if systemctl is-active --quiet "$SERVICE_NAME"; then 144 | NEW_VER=$(get_current_version) 145 | echo "[-] Semaphore successfully updated to $NEW_VER" 146 | else 147 | echo "[x] Service failed to start after update." 148 | journalctl -u "$SERVICE_NAME" -n 20 --no-pager -l 149 | exit 1 150 | fi 151 | 152 | # -------------------------- CLEANUP (handled by trap) ------------------------- 153 | # Lock file is removed automatically via trap 154 | -------------------------------------------------------------------------------- /vsftpd.conf Anonymous Uploads: -------------------------------------------------------------------------------- 1 | #======================================================================================== 2 | # CONFIG FOR VSFTPD SERVER THAT SECURELY ALLOWS ANONYMOUS UPLOADS AND LOCAL USER SIGN IN 3 | #======================================================================================== 4 | # VSFTPD is a pain in the butt with anonymous uploads. You need the below configured before connecting to the FTP server. 5 | # Once all the below is configured connect to the FTP server 6 | # Then you need too change the permissions on /var/ftp/public by doing ```sudo chmod a+w /var/ftp/public``` 7 | # You can now upload files. If you disconnect or restart vsftpd.service and try to reconnect vsftpd will not let you 8 | # 9 | # INSTALL COMMAND: 10 | # sudo apt update && apt install -y vsftpd 11 | # 12 | # GENERATE CERTIFICATES IF YOU WISH TO USE SSL 13 | # sudo openssl req -x509 -nodes -keyout /etc/ssl/private/vsftpd.pem -out /etc/ssl/certs/vsftpd.crt -days 365 -newkey rsa:2048 14 | # NOTE: If you do not want to use SSL be sure to comment out the SSL values in the CONFIGURED SETTINGS section below and set ssl_enable=NO 15 | # 16 | # CREATE DIRECTORY FOR ANONYMOUS USER TO DOWNLOAD FROM 17 | # sudo mkdir -p /var/ftp/public/files 18 | # sudo chown nobody:nogroup /var/ftp/public 19 | # sudo chmod 664 /var/ftp/public 20 | # sudo chmod a+w /var/ftp/public/files 21 | # sudo useradd ftpsecure 22 | # DEBIAN: sudo touch /etc/vsftpd.email_passwords 23 | # DEBIAN: sudo vim /etc/vsftpd.email_passwords # PLACE EMAIL ADDRESSES IN THIS FILE THAT CAN BE USED AS PASSWORDS TO SIGN IN WITH ANONYMOUS ACCESS 24 | # DEBINA: sudo chmod 640 /etc/vsftpd.email_passwords 25 | # RHEL: sudo touch /etc/vsftpd/email_passwords 26 | # RHEL: sudo vim /etc/vsftpd/email_passwords # PLACE EMAIL ADDRESSES IN THIS FILE THAT CAN BE USED AS PASSWORDS TO SIGN IN WITH ANONYMOUS ACCESS 27 | # RHEL: sudo chmod 640 /etc/vsftpd/email_passwords 28 | # 29 | # DOWNLOAD AND USE THIS CONFIGURATION FILE 30 | # DEBIAN: sudo mv /etc/vsftpd.conf /etc/vsftpd.conf.orig && echo "[*] Created backup of original /etc/vsftpd.conf file at /etc/vsftpd.conf.orig" 31 | # DEBIAN: sudo wget https://raw.githubusercontent.com/OsbornePro/ConfigTemplates/main/vsftpd.conf%20Anonymous%20Uploads -O /etc/vsftpd.conf 32 | # DEBIAN: sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.bak && echo "[*] Create backup of active /etc/vsftpd.conf file at /etc/vsftpd.conf.bak" 33 | # RHEL: sudo mv /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.orig && echo "[*] Created backup of original /etc/vsftpd/vsftpd.conf file at /etc/vsftpd/vsftpd.conf.orig" 34 | # RHEL: sudo wget https://raw.githubusercontent.com/OsbornePro/ConfigTemplates/main/vsftpd.conf%20Anonymous%20Uploads -O /etc/vsftpd/vsftpd.conf 35 | # RHEL: sudo cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.bak && echo "[*] Create backup of active /etc/vsftpd/vsftpd.conf file at /etc/vsftpd/vsftpd.conf.bak" 36 | # 37 | # CONFIGURE FIREWALL RULES TO ALLOW FTP USING WHATEVER FIREWALL YOu USe 38 | # FIREWALL-CMD 39 | # sudo firewall-cmd --zone=public --add-port=21/tcp --permanent 40 | # sudo firewall-cmd --zone=public --add-port=20/tcp --permanent 41 | # sudo firewall-cmd --zone=public --add-port=40000-41000/tcp 42 | # sudo firewall-cmd --reload 43 | # IPTABLES 44 | # iptables -A INPUT -p tcp -m tcp --dport 21 -j ACCEPT 45 | # iptables -A INPUT -p tcp -m tcp --dport 20 -j ACCEPT 46 | # iptables -A OUTPUT -p tcp -m tcp --sport 21 -j ACCEPT 47 | # iptables -A OUTPUT -p tcp -m tcp --sport 20 -j ACCEPT 48 | # iptables -A INPUT -p tcp -m tcp --dport 40000:41000 -j ACCEPT 49 | # iptables -A OUTPUT -p tcp -m tcp --sport 40000:41000 -j ACCEPT 50 | # sudo service iptables restart 51 | # UFW 52 | # sudo ufw allow 20:21/tcp 53 | # sudo ufw allow 40000:41000/tcp 54 | # sudo ufw reload 55 | # OR 56 | # sudo ufw allow ftp-data 57 | # sudo ufw allow ftp 58 | # sudo ufw reload 59 | # 60 | #------------------------------------------------------------------------------ 61 | # CONFIGURED SETTINGS 62 | #------------------------------------------------------------------------------ 63 | anonymous_enable=YES 64 | anon_root=/var/ftp/public/ 65 | local_enable=NO 66 | tcp_wrappers=YES 67 | allow_writeable_chroot=YES 68 | guest_enable=YES 69 | guest_username=ftp 70 | chown_uploads=YES 71 | chown_username=ftp 72 | 73 | # ANONYMOUS USER PASSWORD SETTINGS 74 | no_anon_password=NO 75 | secure_email_list_enable=YES 76 | # FOR secure_email_list_enable YOU NEED TO ADD EMAIL ADDRESSES/PASSWORDS ONE PER LINE TO THE FILE /etc/vsftpd.email_passwords 77 | 78 | # LIMIT COMMANDS THAT CAN BE EXECUTED. SEPARATE MULTIPLE VALUES WITH A COMMA 79 | #cmds_allowed=ABOR,ACCT,ALLO,APPE,BINARY,CDUP,CWD,DELE,EPRT,EPSV,FEAT,HELP,LIST,MDTM,MODE,NLST,NOOP,OPTS,PASS,PASV,PORT,PWD,QUIT,REIN,REST,RETR,RMD,RNFR,RNTO,SITE,SIZE,SMNT,STAT,STOR,STOU,STRU,SYST,TYPE,USER,XCUP,XCWD,XPWD,XRMD 80 | #cmds_denied=GET,MGET,RM,RMD,RMDIR,XRMD,MKD,MKDIR,XMKD 81 | 82 | # PREVENT DOWNLOAD 83 | download_enable=NO 84 | 85 | # ALLOW UPLOADS 86 | write_enable=YES 87 | anon_upload_enable=YES 88 | anon_mkdir_write_enable=YES 89 | anon_other_write_enable=YES 90 | 91 | # PERMISSIONS 92 | local_umask=022 93 | anon_umask=077 94 | ascii_upload_enable=NO 95 | ascii_download_enable=NO 96 | async_abor_enable=YES 97 | ls_recurse_enable=NO 98 | hide_ids=YES 99 | nopriv_user=ftpsecure 100 | secure_chroot_dir=/var/run/vsftpd/empty 101 | 102 | # LISTENER 103 | listen=YES 104 | listen_ipv6=NO 105 | connect_from_port_20=YES 106 | pasv_min_port=40000 107 | pasv_max_port=41000 108 | 109 | # LOG SETTINGS 110 | dirmessage_enable=YES 111 | use_localtime=YES 112 | xferlog_enable=YES 113 | xferlog_file=/var/log/vsftpd.log 114 | xferlog_std_format=YES 115 | log_ftp_protocol=YES 116 | vsftpd_log_file=/var/log/vsftpd.log 117 | dual_log_enable=YES 118 | syslog_enable=NO 119 | 120 | # SESSION SETTINGS 121 | session_support=YES 122 | idle_session_timeout=60 123 | data_connection_timeout=120 124 | accept_timeout=60 125 | connect_timeout=60 126 | anon_max_rate=30000 127 | 128 | # BANNER CAN BE 129 | ftpd_banner=FTP Anonymous Upload Server 130 | # OR 131 | #banner_file=/etc/vsftpd.welcome_banner 132 | 133 | # OTHER SETTINGS 134 | utf8_filesystem=YES 135 | one_process_model=YES 136 | pam_service_name=ftp 137 | 138 | # -------------------------------------------------------------------- 139 | # UNCOMMENT BELOW SETTINGS TO USE FTP OVER SSL 140 | #--------------------------------------------------------------------- 141 | # CHANGE BELOW TO ssl_enable=YES to use FTP over SSL 142 | ssl_enable=YES 143 | 144 | debug_ssl=YES 145 | rsa_cert_file=/etc/ssl/certs/vsftpd.crt 146 | rsa_private_key_file=/etc/ssl/private/vsftpd.pem 147 | ssl_ciphers=HIGH 148 | allow_anon_ssl=YES 149 | implicit_ssl=YES 150 | force_local_data_ssl=YES 151 | force_local_logins_ssl=YES 152 | ssl_tlsv1=YES 153 | ssl_sslv2=NO 154 | ssl_sslv3=NO 155 | require_ssl_reuse=NO 156 | -------------------------------------------------------------------------------- /New-AOVPNClientProfile.ps1: -------------------------------------------------------------------------------- 1 | # CLIENT VPN PROFILE CREATED 2 | # --------------------------- 3 | # 1.) Uses IKEv2 UDP Connection to establish VPN connection with Certificate based authentication with Split Tunneling 4 | # 2.) If IKEv2 traffic is blocked or the connection fails it falls over to SSTP which uses HTTPS 5 | # 6 | # SUMMARY: 7 | # I wrote this script because the Always on VPN client profile creation script Microsoft provided is short sighted. Mine is better. 8 | # They use WMI objects which has created issues with Windows 11 and returns Access Denied errors in Windows 10 9 | # This script can build AOVPN profiles for unprivileges user accounts 10 | # 11 | # FIREWALL COMMANDS: 12 | # Below are Cisco ASA Firewall Commands that are used to enable Always On VPN Traffic 13 | # This assumes you have a Windows Server with the Always on VPN service that has a DMZ Interface IP address and LAN Interface IP Address 14 | #--------------------------------------------------------------- 15 | # NAT TRANSLATION (Your Public IP Address) 16 | #nat (dmz,outside) source static AOVPN 50.50.50.50 17 | # 18 | # ACCESS LIST (ACL) CONFIGS 19 | # Public IKEv2 20 | #access-list aovpnPub line 1 extended permit udp any4 host 50.50.50.50 eq isakmp 21 | #access-list aovpnPub line 2 extended permit udp any4 host 50.50.50.50 eq 4500 22 | # 23 | # Public SSTP 24 | #access-list aovpnPub line 3 extended permit tcp host 50.50.50.50 eq https any4 25 | #access-list aovpnPub line 4 extended permit any4 host 50.50.50.50 eq https 26 | 27 | # Private IKEv2 28 | #access-list aovpnPriv line 2 extended permit udp any4 host 10.10.10.200 eq isakmp 29 | #access-list aovpnPriv line 3 extended permit udp any4 host 10.10.10.200 eq 4500 30 | # 31 | # Private SSTP 32 | #access-list aovpnPriv line 1 extended permit tcp any4 host 10.10.10.200 eq https 33 | #--------------------------------------------------------------- 34 | # 35 | $DnsSuffix = (Get-CimInstance -ClassName Win32_ComputerSystem).Domain 36 | $ServerAddress = Read-Host -Prompt "Enter the public DNS name of your AOVPN Server EXAMPLE: aovpn.osbornepro.com" 37 | $NPSServer = Read-Host -Prompt "Enter the FQDN of your NPS server that will be authenticating the RADIUS requests EXAMPLE: nps-server.osbornepro.com" 38 | $Connection = Read-Host -Prompt "Enter the connection name as you would like it to appear to your users EXAMPLE: OsbornePro Network" 39 | $Exists = Get-VpnConnection -Name $Connection -ErrorAction SilentlyContinue 40 | $RootCAThumbprint = Read-Host -Prompt "Enter your Root Certificate Authorities Serial number/Thumbprint EXAMPLE: aa bb cc dd ee ff 00 11 22 33 44 55 66 77 88 99 a0 a1 a2 c2" 41 | 42 | If ($Exists) { 43 | 44 | Write-Output "[*] Modifying the EAP XML Configuration file to contain the values you defined" 45 | $InnerXML1 = ((New-EapConfiguration -Tls -VerifyServerIdentity).EapConfigXmlStream | Select-Object -ExpandProperty InnerXML).Replace("false","true").Replace("","$NPSServer$RootCAThumbprint ") 46 | $TunnledEapAuthMethod = (New-EapConfiguration -Tls -VerifyServerIdentity).EapConfigXmlStream 47 | $TunnledEapAuthMethod.InnerXml = $InnerXML1 48 | 49 | $InnerXML2 = ((New-EapConfiguration -Peap -VerifyServerIdentity -TunnledEapAuthMethod $TunnledEapAuthMethod -FastReconnect $True).EapConfigXmlStream | Select-Object -ExpandProperty InnerXml).Replace("false","true").Replace("","$NPSServer$RootCAThumbprint ").Replace("true","$RootCAThumbprint $RootCAThumbprint ").Replace("","true") 50 | $EapConfigXmlStream = (New-EapConfiguration -Peap -VerifyServerIdentity -TunnledEapAuthMethod $TunnledEapAuthMethod -FastReconnect $True).EapConfigXmlStream 51 | $EapConfigXmlStream.InnerXml = $InnerXML2 52 | 53 | # Add the -AllUserConnection switch parameter to Add-VPNConnection if you want this to be a profile for all users that sign into the device instead of each individual one 54 | Write-Output "[*] Creating the VPN Connection" 55 | Add-VPNConnection -Name $Connection -ServerAddress $ServerAddress -TunnelType Ikev2 -RememberCredential -SplitTunneling -Force -EncryptionLevel Maximum -PassThru -DnsSuffix $DnsSuffix -AuthenticationMethod Eap -EapConfigXmlStream $EapConfigXmlStream 56 | 57 | } # End If 58 | 59 | Write-Output "[*] Defining strong encryption protocols. These must match the server" 60 | Set-VpnConnectionIPsecConfiguration -ConnectionName $Connection -AuthenticationTransformConstants SHA256128 -CipherTransformConstants AES128 -DHGroup Group14 -EncryptionMethod AES128 -IntegrityCheckMethod SHA256 -PFSgroup PFS2048 -Force 61 | 62 | Write-Output "[*] Setting $DnsSuffix as a trusted network for $Connection" 63 | Add-VpnConnectionTriggerTrustedNetwork -ConnectionName $Connection -DnsSuffix $DnsSuffix -Force -ErrorAction SilentlyContinue 64 | 65 | Write-Output "[*] Modifying the users rasphone.pbk file to modify the network properties of the VPN profile" 66 | Write-Output "[*] Enabling Auto Connect of AOVPN,disabling network outage time to prevent manual reconnects, Disabling IPv6, disabling NetBIOS, registering domain suffix, and enabling split tunneling" 67 | $RasPhonePath = "$env:APPDATA\Microsoft\Network\Connections\Pbk\rasphone.pbk" 68 | $RasPhoneChanges = (Get-Content -Path $RasPhonePath | Out-String).Replace("VpnStrategy=7","VpnStrategy=14").Replace("IpDnsSuffix=","IpDnsSuffix=$DnsSuffix").Replace("IpDnsSuffix=$DnsSuffix$DnsSuffix","IpDnsSuffix=$DnsSuffix").Replace("AutoLogon=0","AutoLogon=1").Replace("ExcludedProtocols=0","ExcludedProtocols=8").Replace("IpPrioritizeRemote=1","IpPrioritizeRemote=0").Replace("PreferredHwFlow=0","PreferredHwFlow=1").Replace("PreferredProtocol=0","PreferredProtocol=1").Replace("PreferredCompression=0","PreferredCompression=1").Replace("PreferredSpeaker=0","PreferredSpeaker=1").Replace("IpDnsFlags=0","IpDnsFlags=1").Replace("IpNBTFlags=1","IpNBTFlags=0").Replace("AutoTiggerCapable=0","AutoTiggerCapable=1").Replace("AlwaysOnCapable=0","AlwaysOnCapable=1").Replace("NetworkOutageTime=1800","NetworkOutageTime=0").Replace("DisableMobility=0","DisableMobility=1") 69 | 70 | Set-Content -Path $RasPhonePath -Value $RasPhoneChanges -Force 71 | 72 | Write-Warning "The below commands now need to be issued on your AOVPN server to improve encryption and use Certificate revocation checks" 73 | Write-Output ' 74 | 75 | Set-VpnServerConfiguration -CustomPolicy -AuthenticationTransformConstants SHA256128 -CipherTransformConstants AES128 -DHGroup Group14 -EncryptionMethod AES128 -IntegrityCheckMethod SHA256 -PFSgroup PFS2048 -SALifeTimeSeconds 28800 -MMSALifeTimeSeconds 86400 -SADataSizeForRenegotiationKilobytes 1024000 76 | $RootCACert = (Get-ChildItem -Path Cert:\LocalMachine\Root | Where-Object -FilterScript {$_.Thumbprint -eq $RootCAThumbprint}) 77 | Set-VpnAuthProtocol -RootCertificateNameToAccept $RootCACert -PassThru 78 | New-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\RemoteAccess\Parameters\Ikev2\ -Name CertAuthFlags -PropertyTYpe DWORD -Value 4 -Force 79 | Restart-Service -Name RemoteAccess -PassThru 80 | ' 81 | -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- 1 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 2 | " 3 | " ██╗ ██╗██╗███╗ ███╗██████╗ ██████╗ 4 | " ██║ ██║██║████╗ ████║██╔══██╗██╔════╝ 5 | " ██║ ██║██║██╔████╔██║██████╔╝██║ 6 | " ╚██╗ ██╔╝██║██║╚██╔╝██║██╔══██╗██║ 7 | " ╚████╔╝ ██║██║ ╚═╝ ██║██║ ██║╚██████╗ 8 | " ╚═══╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ 9 | " 10 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 11 | colorscheme elflord 12 | " Disable compatibility with vi which can cause unexpected issues. 13 | set nocompatible 14 | 15 | " Enable type file detection. Vim will be able to try to detect the type of file is use. 16 | filetype on 17 | 18 | " Enable plugins and load plugin for the detected file type. 19 | filetype plugin on 20 | 21 | " Load an indent file for the detected file type. 22 | filetype indent on 23 | 24 | " Turn syntax highlighting on. 25 | syntax on 26 | 27 | " Add numbers to the file. 28 | set number 29 | 30 | " Highlight cursor line underneath the cursor horizontally. 31 | set cursorline 32 | 33 | " Highlight cursor line underneath the cursor vertically. 34 | set cursorcolumn 35 | 36 | " Set shift width to 4 spaces. 37 | set shiftwidth=4 38 | 39 | " Set tab width to 4 columns. 40 | set tabstop=4 41 | 42 | " Use space characters instead of tabs. 43 | set expandtab 44 | 45 | " Do not save backup files. 46 | set nobackup 47 | 48 | " Do not let cursor scroll below or above N number of lines when scrolling. 49 | set scrolloff=10 50 | 51 | " Do not wrap lines. Allow long lines to extend as far as the line goes. 52 | set nowrap 53 | 54 | " While searching though a file incrementally highlight matching characters as you type. 55 | set incsearch 56 | 57 | " Ignore capital letters during search. 58 | set ignorecase 59 | 60 | " Override the ignorecase option if searching for capital letters. 61 | " This will allow you to search specifically for capital letters. 62 | set smartcase 63 | 64 | " Show partial command you type in the last line of the screen. 65 | set showcmd 66 | 67 | " Show the mode you are on the last line. 68 | set showmode 69 | 70 | " Show matching words during a search. 71 | set showmatch 72 | 73 | " Use highlighting when doing a search. 74 | set hlsearch 75 | 76 | " Set the commands to save in history default number is 20. 77 | set history=1000 78 | 79 | " Enable auto completion menu after pressing TAB. 80 | set wildmenu 81 | 82 | " Make wildmenu behave like similar to Bash completion. 83 | set wildmode=list:longest 84 | 85 | " There are certain files that we would never want to edit with Vim. 86 | " Wildmenu will ignore files with these extensions. 87 | set wildignore=*.docx,*.jpg,*.png,*.gif,*.pdf,*.pyc,*.exe,*.flv,*.img,*.xlsx 88 | 89 | " MAPPINGS --------------------------------------------------------------- {{{ 90 | 91 | " Set the backslash as the leader key. 92 | let mapleader = '\' 93 | 94 | " Press \\ to jump back to the last cursor position. 95 | nnoremap \ `` 96 | 97 | " Press \p to print the current file to the default printer from a Linux operating system. 98 | " View available printers: lpstat -v 99 | " Set default printer: lpoptions -d 100 | " means do not display output. 101 | nnoremap p :%w !lp 102 | 103 | " Type jj to exit insert mode quickly. 104 | inoremap jj 105 | 106 | " Press the space bar to type the : character in command mode. 107 | nnoremap : 108 | 109 | " Pressing the letter o will open a new line below the current one. 110 | " Exit insert mode after creating a new line above or below the current line. 111 | nnoremap o o 112 | nnoremap O O 113 | 114 | " Center the cursor vertically when moving to the next word during a search. 115 | nnoremap n nzz 116 | nnoremap N Nzz 117 | 118 | " Yank from cursor to the end of line. 119 | nnoremap Y y$ 120 | 121 | " Map the F5 key to run a Python script inside Vim. 122 | " We map F5 to a chain of commands here. 123 | " :w saves the file. 124 | " (carriage return) is like pressing the enter key. 125 | " !clear runs the external clear screen command. 126 | " !python3 % executes the current file with Python. 127 | nnoremap :w :!clear :!python3 % 128 | 129 | " You can split the window in Vim by typing :split or :vsplit. 130 | " Navigate the split view easier by pressing CTRL+j, CTRL+k, CTRL+h, or CTRL+l. 131 | nnoremap j 132 | nnoremap k 133 | nnoremap h 134 | nnoremap l 135 | 136 | " Resize split windows using arrow keys by pressing: 137 | " CTRL+UP, CTRL+DOWN, CTRL+LEFT, or CTRL+RIGHT. 138 | noremap + 139 | noremap - 140 | noremap > 141 | noremap < 142 | 143 | " NERDTree specific mappings. 144 | " Map the F3 key to toggle NERDTree open and close. 145 | nnoremap :NERDTreeToggle 146 | 147 | " Have nerdtree ignore certain files and directories. 148 | let NERDTreeIgnore=['\.git$', '\.jpg$', '\.mp4$', '\.ogg$', '\.iso$', '\.pdf$', '\.pyc$', '\.odt$', '\.png$', '\.gif$', '\.db$'] 149 | 150 | " }}} 151 | 152 | " VIMSCRIPT -------------------------------------------------------------- {{{ 153 | 154 | " Enable the marker method of folding. 155 | augroup filetype_vim 156 | autocmd! 157 | autocmd FileType vim setlocal foldmethod=marker 158 | augroup END 159 | 160 | " If the current file type is HTML, set indentation to 2 spaces. 161 | autocmd Filetype html setlocal tabstop=2 shiftwidth=2 expandtab 162 | 163 | " If Vim version is equal to or greater than 7.3 enable undofile. 164 | " This allows you to undo changes to a file even after saving it. 165 | if version >= 703 166 | set undodir=~/.vim/backup 167 | set undofile 168 | set undoreload=10000 169 | endif 170 | 171 | " You can split a window into sections by typing `:split` or `:vsplit`. 172 | " Display cursorline and cursorcolumn ONLY in active window. 173 | augroup cursor_off 174 | autocmd! 175 | autocmd WinLeave * set nocursorline nocursorcolumn 176 | autocmd WinEnter * set cursorline cursorcolumn 177 | augroup END 178 | 179 | " If GUI version of Vim is running set these options. 180 | if has('gui_running') 181 | 182 | " Set the background tone. 183 | set background=dark 184 | 185 | " Set the color scheme. 186 | colorscheme molokai 187 | 188 | " Set a custom font you have installed on your computer. 189 | " Syntax: \ \ 190 | set guifont=Monospace\ Regular\ 12 191 | 192 | " Display more of the file by default. 193 | " Hide the toolbar. 194 | set guioptions-=T 195 | 196 | " Hide the the left-side scroll bar. 197 | set guioptions-=L 198 | 199 | " Hide the the left-side scroll bar. 200 | set guioptions-=r 201 | 202 | " Hide the the menu bar. 203 | set guioptions-=m 204 | 205 | " Hide the the bottom scroll bar. 206 | set guioptions-=b 207 | 208 | " Map the F4 key to toggle the menu, toolbar, and scroll bar. 209 | " is the pipe character. 210 | " is the enter key. 211 | nnoremap :if &guioptions=~#'mTr' 212 | \set guioptions-=mTr 213 | \else 214 | \set guioptions+=mTr 215 | \endif 216 | 217 | endif 218 | 219 | " }}} 220 | 221 | " STATUS LINE ------------------------------------------------------------ {{{ 222 | 223 | " Clear status line when vimrc is reloaded. 224 | set statusline= 225 | 226 | " Status line left side. 227 | set statusline+=\ %F\ %M\ %Y\ %R 228 | 229 | " Use a divider to separate the left side from the right side. 230 | set statusline+=%= 231 | 232 | " Status line right side. 233 | "set statusline+=\ ascii:\ %b\ hex:\ 0x%B\ row:\ %l\ col:\ %c\ percent:\ %p%% 234 | 235 | " Show the status on the second to last line. 236 | set laststatus=2 237 | 238 | " }}} 239 | 240 | -------------------------------------------------------------------------------- /apache2-default-ssl.conf: -------------------------------------------------------------------------------- 1 | # OsbornePro LLC. Starting Template for the /etc/apache2/sites-enabled/default-ssl.conf 2 | 3 | 4 | 5 | SSLStaplingCache shmcb:${APACHE_RUN_DIR}/ssl_stapling(32768) 6 | 7 | 8 | 9 | ServerAdmin admin@domain.com 10 | ServerName server.domain.com 11 | DocumentRoot /var/www/html 12 | 13 | # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, 14 | # error, crit, alert, emerg. 15 | # It is also possible to configure the loglevel for particular 16 | # modules, e.g. 17 | LogLevel info ssl:warn 18 | 19 | ErrorLog ${APACHE_LOG_DIR}/error.log 20 | CustomLog ${APACHE_LOG_DIR}/access.log combined 21 | 22 | # For most configuration files from conf-available/, which are 23 | # enabled or disabled at a global level, it is possible to 24 | # include a line for only one particular virtual host. For example the 25 | # following line enables the CGI configuration for this host only 26 | # after it has been globally disabled with "a2disconf". 27 | #Include conf-available/serve-cgi-bin.conf 28 | 29 | # SSL Engine Switch: 30 | # Enable/Disable SSL for this virtual host. 31 | SSLEngine On 32 | SSLUseStapling On 33 | SSLStaplingResponseMaxAge 900 34 | SSLCACertificateFile /etc/ssl/certs/cert.crt # This file should be made up of the full chain of certificates (Root, Intermediate, Device Certificates) 35 | 36 | # A self-signed (snakeoil) certificate can be created by installing 37 | # the ssl-cert package. See 38 | # /usr/share/doc/apache2/README.Debian.gz for more info. 39 | # If both key and certificate are stored in the same file, only the 40 | # SSLCertificateFile directive is needed. 41 | SSLCertificateFile /etc/ssl/certs/cert.crt 42 | SSLCertificateKeyFile /etc/ssl/private/privcert.key 43 | 44 | # Disable weak protocols and ciphers 45 | SSLProtocol -ALL +TLSv1.3 +TLSv1.2 46 | SSLOpenSSLConfCmd Curves X25519:secp521r1:secp384r1:prime256v1 47 | 48 | # Although Apache2 can now use TLSv1.3 there is an issue with openssl which requires the 2 SSLCipherSuite values to need to exist 49 | SSLCipherSuite TLSv1.3 TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256 50 | SSLCipherSuite SSL ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256 51 | 52 | # If you are not using TLS1.3 you can delete the above to lines and uncomment the below line 53 | #SSLCipherSuite HIGH:!MEDIUM:!aNULL:!MD5:!RC4 54 | SSLHonorCipherOrder on 55 | 56 | # Server Certificate Chain: 57 | # Point SSLCertificateChainFile at a file containing the 58 | # concatenation of PEM encoded CA certificates which form the 59 | # certificate chain for the server certificate. Alternatively 60 | # the referenced file can be the same as SSLCertificateFile 61 | # when the CA certificates are directly appended to the server 62 | # certificate for convinience. 63 | #SSLCertificateChainFile /etc/apache2/ssl.crt/server-ca.crt 64 | 65 | # Certificate Authority (CA): 66 | # Set the CA certificate verification path where to find CA 67 | # certificates for client authentication or alternatively one 68 | # huge file containing all of them (file must be PEM encoded) 69 | # Note: Inside SSLCACertificatePath you need hash symlinks 70 | # to point to the certificate files. Use the provided 71 | # Makefile to update the hash symlinks after changes. 72 | #SSLCACertificatePath /etc/ssl/certs/ 73 | #SSLCACertificateFile /etc/apache2/ssl.crt/ca-bundle.crt 74 | 75 | # Certificate Revocation Lists (CRL): 76 | # Set the CA revocation path where to find CA CRLs for client 77 | # authentication or alternatively one huge file containing all 78 | # of them (file must be PEM encoded) 79 | # Note: Inside SSLCARevocationPath you need hash symlinks 80 | # to point to the certificate files. Use the provided 81 | # Makefile to update the hash symlinks after changes. 82 | #SSLCARevocationPath /etc/apache2/ssl.crl/ 83 | #SSLCARevocationFile /etc/apache2/ssl.crl/ca-bundle.crl 84 | 85 | # Client Authentication (Type): 86 | # Client certificate verification type and depth. Types are 87 | # none, optional, require and optional_no_ca. Depth is a 88 | # number which specifies how deeply to verify the certificate 89 | # issuer chain before deciding the certificate is not valid. 90 | #SSLVerifyClient require 91 | #SSLVerifyDepth 10 92 | 93 | # SSL Engine Options: 94 | # Set various options for the SSL engine. 95 | # o FakeBasicAuth: 96 | # Translate the client X.509 into a Basic Authorisation. This means that 97 | # the standard Auth/DBMAuth methods can be used for access control. The 98 | # user name is the `one line' version of the client's X.509 certificate. 99 | # Note that no password is obtained from the user. Every entry in the user 100 | # file needs this password: `xxj31ZMTZzkVA'. 101 | # o ExportCertData: 102 | # This exports two additional environment variables: SSL_CLIENT_CERT and 103 | # SSL_SERVER_CERT. These contain the PEM-encoded certificates of the 104 | # server (always existing) and the client (only existing when client 105 | # authentication is used). This can be used to import the certificates 106 | # into CGI scripts. 107 | # o StdEnvVars: 108 | # This exports the standard SSL/TLS related `SSL_*' environment variables. 109 | # Per default this exportation is switched off for performance reasons, 110 | # because the extraction step is an expensive operation and is usually 111 | # useless for serving static content. So one usually enables the 112 | # exportation for CGI and SSI requests only. 113 | # o OptRenegotiate: 114 | # This enables optimized SSL connection renegotiation handling when SSL 115 | # directives are used in per-directory context. 116 | #SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire 117 | 118 | SSLOptions +StdEnvVars 119 | 120 | 121 | SSLOptions +StdEnvVars 122 | 123 | 124 | # SSL Protocol Adjustments: 125 | # The safe and default but still SSL/TLS standard compliant shutdown 126 | # approach is that mod_ssl sends the close notify alert but doesn't wait for 127 | # the close notify alert from client. When you need a different shutdown 128 | # approach you can use one of the following variables: 129 | # o ssl-unclean-shutdown: 130 | # This forces an unclean shutdown when the connection is closed, i.e. no 131 | # SSL close notify alert is send or allowed to received. This violates 132 | # the SSL/TLS standard but is needed for some brain-dead browsers. Use 133 | # this when you receive I/O errors because of the standard approach where 134 | # mod_ssl sends the close notify alert. 135 | # o ssl-accurate-shutdown: 136 | # This forces an accurate shutdown when the connection is closed, i.e. a 137 | # SSL close notify alert is send and mod_ssl waits for the close notify 138 | # alert of the client. This is 100% SSL/TLS standard compliant, but in 139 | # practice often causes hanging connections with brain-dead browsers. Use 140 | # this only for browsers where you know that their SSL implementation 141 | # works correctly. 142 | # Notice: Most problems of broken clients are also related to the HTTP 143 | # keep-alive facility, so you usually additionally want to disable 144 | # keep-alive for those clients, too. Use variable "nokeepalive" for this. 145 | # Similarly, one has to force some clients to use HTTP/1.0 to workaround 146 | # their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and 147 | # "force-response-1.0" for this. 148 | # BrowserMatch "MSIE [2-6]" \ 149 | # nokeepalive ssl-unclean-shutdown \ 150 | # downgrade-1.0 force-response-1.0 151 | 152 | 153 | 154 | 155 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet 156 | 157 | -------------------------------------------------------------------------------- /fail2ban-templates-jail.local: -------------------------------------------------------------------------------- 1 | ############################################################################################ 2 | # OsbornePro LLC. # 3 | # Fail2Ban /etc/fail2ban/jail.local service tempaltes # 4 | # Protect Apache, Nginx, SSH, PHP, SMTP/SASL, MariaDB/MySQL, VSFTPD, Lighttpd, Bind9/Named # 5 | ############################################################################################ 6 | 7 | # Default action to take when not defined 8 | [DEFAULT] 9 | action = iptables-allports 10 | %(action_mw)s[from=Home\ Print, password="Password123!", destination=youremail@domain.com, sendername=Fail2Ban] 11 | ignoreip = 127.0.0.1 192.168.0.0/24 12 | 13 | ######################################### 14 | # APACHE # 15 | ######################################### 16 | # detect password authentication failures 17 | [apache] 18 | enabled = true 19 | port = 80,443 20 | filter = apache-auth 21 | logpath = /var/log/apache*/*error.log 22 | maxretry = 4 23 | bantime = 3600 24 | action = iptables-multiport[name=auth, port="80,443"] 25 | destemail = you@domain.com 26 | sender = alert@domain.com 27 | mta = mail 28 | 29 | # detect spammer robots crawling email addresses 30 | [apache-badbots] 31 | enabled = true 32 | port = 80,443 33 | filter = apache-badbots 34 | action = iptables-multiport[name=badbots, port="80,443"] 35 | logpath = /var/log/apache*/*error.log 36 | bantime = 3600 37 | maxretry = 1 38 | destemail = you@domain.com 39 | sender = alert@domain.com 40 | mta = mail 41 | 42 | # detect potential search for exploits and php vulnerabilities 43 | [apache-noscript] 44 | enabled = true 45 | port = 80,443 46 | filter = apache-noscript 47 | action = iptables-multiport[name=noscript, port="80,443"] 48 | logpath = /var/log/apache*/*error.log 49 | maxretry = 5 50 | bantime = 3600 51 | destemail = you@domain.com 52 | sender = alert@domain.com 53 | mta = mail 54 | 55 | # detect Apache overflow attempts 56 | [apache-overflows] 57 | enabled = true 58 | port = 80,443 59 | filter = apache-overflows 60 | action = iptables-multiport[name=overflows, port="80,443"] 61 | logpath = /var/log/apache*/*error.log 62 | maxretry = 2 63 | bantime = 3600 64 | destemail = you@domain.com 65 | sender = alert@domain.com 66 | mta = mail 67 | 68 | # detect failures to find a home directory on a server 69 | [apache-nohome] 70 | enabled = true 71 | port = 80,443 72 | filter = apache-nohome 73 | action = iptables-multiport[name=nohome, port="80,443"] 74 | logpath = /var/log/apache*/*error.log 75 | maxretry = 2 76 | bantime = 3600 77 | destemail = you@domain.com 78 | sender = alert@domain.com 79 | mta = mail 80 | 81 | ######################################### 82 | # NGINX # 83 | ######################################### 84 | # prevent nginx multiple auth failures 85 | [nginx-http-auth] 86 | enabled = true 87 | filter = nginx-http-auth 88 | port = 8080,4443 89 | action = iptables-multiport[name=nginxauth, port="8080,4443"] 90 | logpath = /var/log/nginx/error.log 91 | bantime = 3600 92 | findtime = 3600 93 | destemail = you@domain.com 94 | sender = alert@domain.com 95 | mta = mail 96 | 97 | # prevent nginx noscript 98 | [nginx-noscript] 99 | enabled = true 100 | filter = nginx-noscript 101 | port = 8080,4443 102 | logpath = /var/log/nginx/access.log 103 | action = iptables-multiport[name=nginxnoscript, port="8080,4443"] 104 | bantime = 3600 105 | findtime = 3600 106 | destemail = you@domain.com 107 | sender = alert@domain.com 108 | mta = mail 109 | 110 | # prevent nginx badbots 111 | [nginx-badbots] 112 | enabled = true 113 | filter = nginx-badbots 114 | port = 8080,4443 115 | logpath = /var/log/nginx/access.log 116 | action = iptables-multiport[name=nginxbadbots, port="8080,4443"] 117 | bantime = 3600 118 | findtime = 3600 119 | destemail = you@domain.com 120 | sender = alert@domain.com 121 | mta = mail 122 | 123 | # Prevent nginx nohome 124 | [nginx-nohome] 125 | enabled = true 126 | filter = nginx-nohome 127 | port = 8080,4443 128 | logpath = /var/log/nginx/access.log 129 | action = iptables-multiport[name=nginxnohome, port="8080,4443"] 130 | bantime = 3600 131 | findtime = 3600 132 | maxretry = 2 133 | destemail = you@domain.com 134 | sender = alert@domain.com 135 | mta = mail 136 | 137 | # prevent nginx no proxy 138 | [nginx-noproxy] 139 | enabled = true 140 | filter = nginx-noproxy 141 | port = 8080,4443 142 | logpath = /var/log/nginx/access.log 143 | action = iptables-multiport[name=nginxnoproxy, port="8080,4443"] 144 | bantime = 3600 145 | findtime = 3600 146 | maxretry = 2 147 | destemail = you@domain.com 148 | sender = alert@domain.com 149 | mta = mail 150 | 151 | ######################################### 152 | # SSH # 153 | ######################################### 154 | # Prevent excess login attempts 155 | [sshd] 156 | filter = sshd 157 | enabled = true 158 | port = 22 159 | bantime = 1800 160 | maxretry = 3 161 | banaction = iptables-allports 162 | destemail = you@domain.com 163 | sender = alert@domain.com 164 | mta = mail 165 | 166 | ######################################### 167 | # PHP/Apache # 168 | ######################################### 169 | [php-url-fopen] 170 | enabled = true 171 | port = 80,443 172 | filter = php-url-fopen 173 | action = iptables-multiport[name=phpurlfopen, port="80,443"] 174 | logpath = /var/log/apache2/*access.log 175 | bantime = 3600 176 | findtime = 120 177 | destemail = you@domain.com 178 | sender = alert@domain.com 179 | mta = mail 180 | 181 | ######################################### 182 | # POSTFIX/SASL # 183 | ######################################### 184 | [sasl] 185 | enabled = true 186 | port = 25,143,465,587,993,995,2525 187 | filter = postfix-sasl 188 | #action = iptables-multiport[name=postfixsasl, port="25,143,465,587,993,995,2525"] 189 | logpath = /var/log/mail.log 190 | bantime = 3600 191 | maxretry = 5 192 | findtime = 120 193 | destemail = you@domain.com 194 | sender = alert@domain.com 195 | mta = mail 196 | 197 | ######################################### 198 | # LIGHTTPD # 199 | ######################################### 200 | # prevent failed lighttpd attempts 201 | [lighttpd-auth] 202 | enabled = true 203 | port = http,https 204 | filter = lighttpd-auth 205 | logpath = /var/log/lighttpd/error.log 206 | bantime = 3600 207 | maxretry = 4 208 | findtime = 120 209 | destemail = you@domain.com 210 | sender = alert@domain.com 211 | mta = mail 212 | 213 | ######################################### 214 | # VSFTPD # 215 | ######################################### 216 | [vsftpd] 217 | enabled = true 218 | port = 989,990 219 | filter = vsftpd 220 | bantime = 3600 221 | logpath = /var/log/vsftpd.log 222 | destemail = you@domain.com 223 | sender = alert@domain.com 224 | mta = mail 225 | 226 | ######################################### 227 | # MariaDB/MySQL # 228 | ######################################### 229 | [mysqld-auth] 230 | enabled = true 231 | port = 3306 232 | filter = mysqld-auth 233 | maxretry = 3 234 | bantime = 600 235 | logpath = /var/log/mysql/mysql.log # Note this needs to be enabled in /etc/mysql/mariadb.conf.d/50-server.cnf configuration file 236 | destemail = you@domain.com 237 | sender = alert@domain.com 238 | mta = mail 239 | 240 | ######################################### 241 | # NAMED/BIND9 # 242 | ######################################### 243 | [named-refused] 244 | enabled = true 245 | port = domain,953 246 | bantime = 3600 247 | filter = named-refused 248 | logpath = /var/log/audit/audit.log 249 | destemail = you@domain.com 250 | sender = alert@domain.com 251 | mta = mail 252 | -------------------------------------------------------------------------------- /apache2.conf: -------------------------------------------------------------------------------- 1 | # Osborne Pro LLC. Template for Securing Apache 2 | # This was configured and relates mostly to a Debian based OS with Apache v2.4 3 | # 4 | # 5 | # This is the main Apache server configuration file. It contains the 6 | # configuration directives that give the server its instructions. 7 | # See http://httpd.apache.org/docs/2.4/ for detailed information about 8 | # the directives and /usr/share/doc/apache2/README.Debian about Debian specific 9 | # hints. 10 | # 11 | # 12 | # 13 | ServerName 14 | 15 | # Global configuration 16 | # 17 | # Supress OS version information 18 | ServerSignature Off 19 | ServerTokens Prod 20 | # The above ServerTokens value should be set to Full if you plan on modifying /etc/modsecurity/modsecurity.conf to ```SecRuleEgnine On``` and ```SecServerSignature "Derp"``` 21 | # 22 | # ServerRoot: The top of the directory tree under which the server's 23 | # configuration, error, and log files are kept. 24 | # 25 | # NOTE! If you intend to place this on an NFS (or otherwise network) 26 | # mounted filesystem then please read the Mutex documentation (available 27 | # at ); 28 | # you will save yourself a lot of trouble. 29 | # 30 | # Do NOT add a slash at the end of the directory path. 31 | # 32 | #ServerRoot "/etc/apache2" 33 | 34 | # 35 | # The accept serialization lock file MUST BE STORED ON A LOCAL DISK. 36 | # 37 | #Mutex file:${APACHE_LOCK_DIR} default 38 | 39 | # 40 | # The directory where shm and other runtime files will be stored. 41 | # 42 | 43 | DefaultRuntimeDir ${APACHE_RUN_DIR} 44 | 45 | # 46 | # PidFile: The file in which the server should record its process 47 | # identification number when it starts. 48 | # This needs to be set in /etc/apache2/envvars 49 | # 50 | PidFile ${APACHE_PID_FILE} 51 | 52 | # 53 | # Timeout: The number of seconds before receives and sends time out. 54 | # 55 | Timeout 60 56 | 57 | # MaxClients directive allows you to set the limit on connections that will be served simultaneously. 58 | # Every new connection will be queued up after this limit. 59 | # It is available with Prefork and Worker both MPM. The default value of it is 256. 60 | #MaxClients 100 # DEPRECIATED 61 | 62 | # 63 | # KeepAlive: Whether or not to allow persistent connections (more than 64 | # one request per connection). Set to "Off" to deactivate. 65 | # 66 | KeepAlive On 67 | 68 | # 69 | # MaxKeepAliveRequests: The maximum number of requests to allow 70 | # during a persistent connection. Set to 0 to allow an unlimited amount. 71 | # We recommend you leave this number high, for maximum performance. 72 | # 73 | MaxKeepAliveRequests 50 74 | 75 | # 76 | # KeepAliveTimeout: Number of seconds to wait for the next request from the 77 | # same client on the same connection. 78 | # 79 | KeepAliveTimeout 5 80 | 81 | 82 | # These need to be set in /etc/apache2/envvars 83 | User ${APACHE_RUN_USER} 84 | Group ${APACHE_RUN_GROUP} 85 | 86 | # 87 | # HostnameLookups: Log the names of clients or just their IP addresses 88 | # e.g., www.apache.org (on) or 204.62.129.132 (off). 89 | # The default is off because it'd be overall better for the net if people 90 | # had to knowingly turn this feature on, since enabling it means that 91 | # each client request will result in AT LEAST one lookup request to the 92 | # nameserver. 93 | # 94 | HostnameLookups Off 95 | 96 | # ErrorLog: The location of the error log file. 97 | # If you do not specify an ErrorLog directive within a 98 | # container, error messages relating to that virtual host will be 99 | # logged here. If you *do* define an error logfile for a 100 | # container, that host's errors will be logged there and not here. 101 | # 102 | ErrorLog ${APACHE_LOG_DIR}/error.log 103 | 104 | # 105 | # LogLevel: Control the severity of messages logged to the error_log. 106 | # Available values: trace8, ..., trace1, debug, info, notice, warn, 107 | # error, crit, alert, emerg. 108 | # It is also possible to configure the log level for particular modules, e.g. 109 | # "LogLevel info ssl:warn" 110 | # 111 | LogLevel warn 112 | 113 | # Include module configuration: 114 | IncludeOptional mods-enabled/*.load 115 | IncludeOptional mods-enabled/*.conf 116 | 117 | # Include list of ports to listen on 118 | Include ports.conf 119 | 120 | 121 | # Sets the default security model of the Apache2 HTTPD server. It does 122 | # not allow access to the root filesystem outside of /usr/share and /var/www. 123 | # The former is used by web applications packaged in Debian, 124 | # the latter may be used for local directories served by the web server. If 125 | # your system is serving content from a sub-directory in /srv you must allow 126 | # access here, or in any related virtual host. 127 | 128 | Options -Indexes -Includes +FollowSymLinks 129 | AllowOverride None 130 | LimitRequestBody 102400 131 | Require all denied 132 | 133 | 134 | 135 | Options -Indexes -Includes 136 | AllowOverride None 137 | LimitRequestBody 102400 138 | Require all granted 139 | 140 | 141 | 142 | Options -Indexes -Includes 143 | AllowOverride None 144 | LimitRequestBody 102400 145 | Require all granted 146 | 147 | 148 | # 149 | # Options Indexes FollowSymLinks 150 | # AllowOverride None 151 | # Require all granted 152 | # 153 | 154 | 155 | 156 | 157 | # AccessFileName: The name of the file to look for in each directory 158 | # for additional configuration directives. See also the AllowOverride 159 | # directive. 160 | # 161 | #AccessFileName .htaccess 162 | # 163 | # Apache recommends you do not use the .htaccess file and utilize your site config file instead /etc/apache2/sites-available 164 | # Be sure to change your tags value of AllowOverride as well if you change this 165 | 166 | # 167 | # The following lines prevent .htaccess and .htpasswd files from being 168 | # viewed by Web clients. 169 | # 170 | 171 | Require all denied 172 | 173 | 174 | # 175 | # The following directives define some format nicknames for use with 176 | # a CustomLog directive. 177 | # 178 | # These deviate from the Common Log Format definitions in that they use %O 179 | # (the actual bytes sent including headers) instead of %b (the size of the 180 | # requested file), because the latter makes it impossible to detect partial 181 | # requests. 182 | # 183 | # Note that the use of %{X-Forwarded-For}i instead of %h is not recommended. 184 | # Use mod_remoteip instead. 185 | # 186 | LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined 187 | LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined 188 | LogFormat "%h %l %u %t \"%r\" %>s %O" common 189 | LogFormat "%{Referer}i -> %U" referer 190 | LogFormat "%{User-agent}i" agent 191 | 192 | # Include of directories ignores editors' and dpkg's backup files, 193 | # see README.Debian for details. 194 | 195 | # Include generic snippets of statements 196 | IncludeOptional conf-enabled/*.conf 197 | 198 | # Include the virtual host configurations: 199 | IncludeOptional sites-enabled/*.conf 200 | 201 | 202 | # Below settings can also help with DDoS Attacks 203 | # LimitRequestFields helps us to set a limit on the number of HTTP request’s header fields that will be accepted from the clients. 204 | # It is recommended to lower this value if DDos attacks are occurring as a result of so many http request headers. 205 | LimitRequestFields 20 206 | LimitRequestBody 102400 207 | LimitRequestFieldSize 7000 208 | # LimitRequestFieldSize helps us to set a size limit on the HTTP Request header. 209 | 210 | # Disable E-Tags which apache has some vulnerabbilities with 211 | FileETag none 212 | 213 | 214 | # Custom Error Pages to conceal another possible location an attacker can obtain info about your server 215 | ErrorDocument 400 /400.html 216 | ErrorDocument 401 /401.html 217 | ErrorDocument 403 /403.html 218 | ErrorDocument 404 /404.html 219 | ErrorDocument 405 /405.html 220 | ErrorDocument 500 /500.html 221 | 222 | # I usually make the above html files have contents such as the one below 223 | # 224 | #

225 | # Error 400 226 | #

227 | # 228 | # 229 | # 230 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet 231 | 232 | -------------------------------------------------------------------------------- /ConfigureDynamicDNS.ps1: -------------------------------------------------------------------------------- 1 | # OsbornePro LLC. 2 | # This script is meant to be executed in sections. It performs the following actions 3 | # 4 | # 1.) Sets IP address of your DHCP server 5 | # 2.) Renames your DHCP server and restarts it 6 | # 3.) Joins your DHCP server to AD Domain and restarts it 7 | # 4.) Installs the DHCP service 8 | # 5.) Creates DHCP admin and user security groups in Active Directory on locally on DHCP server 9 | # 6.) Creates a Dynamic DNS user 10 | # 7.) Adds DHCP server to DnsUpdateProxy Group 11 | # 8.) Authorizes DHCP server in Active Directory 12 | # 9.) Configures the DHCP service 13 | # 10.) Sets the Dynamic DNS user credentials to use when DHCP server registers DNS records 14 | # 11.) Creates a single DHCP scope and defines Dynamic DNS options for it 15 | 16 | #=============================================== 17 | # EXECUTE BELOW COMMANDS LOCALLY ON DHCP SERVER 18 | #=============================================== 19 | # Set Static IP address for DHCP server 20 | $Domain = Read-Host -Prompt "Enter the domain name to join EXAMPLE: domain.com " 21 | $DnsServer = Read-Host -Prompt "Enter the IP Address of your primary DNS Server " 22 | $PrimaryDC = Read-Host -Prompt "Enter the IP Address of your primary Active Directory Server " 23 | $NTPServer = Read-Host -Prompt "Enter the IP Address of your NTP Server (Typicaly your DC) " 24 | $DhcpIpAddress = Read-Host -Prompt "Enter the DHCP servers IP Address " 25 | $DefaultGateway = Read-Host -Prompt "Enter the default gateway Address for the DHCP scope " 26 | $NewHostname = Read-Host -Prompt "Enter the new hostname for your DHCP server " 27 | $InterfaceAlias = (Get-NetAdapter)[0].InterfaceAlias 28 | 29 | Write-Output "[*] Setting IP address on your DHCP server" 30 | New-NetIPAddress -IPAddress $DhcpIpAddress -InterfaceAlias $InterfaceAlias -DefaultGateway $DefaultGateway -AddressFamily IPv4 -PrefixLength 24 -Type Unicast -Confirm:$False 31 | Set-DnsClientServerAddress -InterfaceAlias $InterfaceAlias -ServerAddresses $DnsServers 32 | 33 | Write-Output "[*] Renaming newly created DHCP server to match your naming convention " 34 | Rename-Computer -ComputerName $NewHostname -DomainCredential (Get-Credential -Message "Enter your Domain Admin credentials") -Force -Restart 35 | 36 | #=================================================== 37 | # After DHCP Server restarts execute these commands 38 | #=================================================== 39 | Write-Output "[*] Adding server to your domain" 40 | $Domain = Read-Host -Prompt "Enter the domain name to join EXAMPLE: domain.com " 41 | Add-Computer -ComputerName "$($env:COMPUTERNAME).$($Domain)" -Server $PrimaryDC -OUPath "CN=Computers,DC=$env:USERDOMAIN,DC=com" -DomainName $Domain -Credential (Get-Credential -Message "Enter your Domain Admin credentials") -Restart -Force 42 | 43 | #=================================================== 44 | # After DHCP Server restarts execute these commands 45 | #=================================================== 46 | Write-Output "[*] Installing the DHCP service" 47 | Install-WindowsFeature -Name DHCP -IncludeManagementTools 48 | 49 | $Domain = (Get-CimInstance -ClassName Win32_ComputerSystem).Domain 50 | $FQDN = "$($NewHostname).$($Domain)" 51 | 52 | # Create local DHCP security groups on DHCP server 53 | Add-DhcpServerSecurityGroup -ComputerName $FQDN 54 | Restart-Service -Name DHCPServer -Force 55 | 56 | #==================================================== 57 | # EXECUTE BELOW COMMANDS ON ACTIVE DIRECTORY SERVER 58 | #==================================================== 59 | # Create the Dynamic DNS user with normal user permissions 60 | $DHCPServer = Read-Host -Prompt "What is the hostname of your DHCP server? EXMAPLE: dhcp01" 61 | New-ADUser -Name "Dynamic DNS" -GivenName "Dynamic" -Surname "DNS" -SamAccountName "dyndns" -AccountPassword (Read-Host -AsSecureString "Enter strong password for accont. This password should be very long") -ChangePasswordAtLogon $False -Description "This account is used by the DHCP servers to register Dynamic DNS updates" -DisplayName "Dynamic DNS" -Enabled $True 62 | Get-ADUser -Filter 'SamAccountName -like "dyndns"' -SearchBase "CN=Users,DC=$env:USERDOMAIN,DC=com" | Set-ADUser -PasswordNeverExpires:$True -CanNotChangePassword:$True 63 | # Create the required DHCP groups in Active Directory 64 | New-ADGroup -Name "DHCP Administrators" -DsiplayName "DHCP Administrators" -SamAccountName "DHCP Administrators" -GroupCategory Security -GroupScope Global -Path "CN=Users,DC=$env:USERDOMAIN,DC=com" -Description "Members of this group have DHCP administrative permissions" 65 | New-ADGroup -Name "DHCP Users" -DsiplayName "DHCP Users" -SamAccountName "DHCP Users" -GroupCategory Security -GroupScope Global -Path "CN=Users,DC=$env:USERDOMAIN,DC=com" -Description "Members of this group have limited DHCP permissions" 66 | Write-Output "[*] Adding DHCP server to DNSUpdateProxy group which is required for Dynamic DNS" 67 | Add-ADGroupMember -Identity DnsUpdateProxy -Members "$($DHCPServer)$" 68 | 69 | 70 | #=================================================== 71 | # Execute these commands on the DHCP server 72 | #=================================================== 73 | # Authorize the DHCP server in Active Directory 74 | Add-DhcpServerInDC -DnsName $FQDN -IPAddress $DhcpIpAddress 75 | $CheckAuthorizedDhcpServer = Get-DhcpServerInDC 76 | If ($CheckAuthorizedDhcpServer.DnsName -contains $FQDN) { 77 | 78 | Write-Output "[*] Successfully authorized DHCP server $FQDN in Active Directory" 79 | Write-Output "[*] Notifying 'Server Manager' application of the update" 80 | Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\ServerManager\Roles\12 -Name ConfigurationState -Value 2 81 | 82 | } Else { 83 | 84 | Throw "Make sure you are a member of the 'Enterprise Admins' Security Group. DHCP server is not authorized in Active Directory. " 85 | 86 | } # End If Else 87 | 88 | $Domain = Read-Host -Prompt "Enter the domain name to join EXAMPLE: domain.com " 89 | $DnsServer = Read-Host -Prompt "Enter the IP Address of your primary DNS Server " 90 | $PrimaryDC = Read-Host -Prompt "Enter the IP Address of your primary Active Directory Server " 91 | $NTPServer = Read-Host -Prompt "Enter the IP Address of your NTP Server (Typicaly your DC) " 92 | $DhcpIpAddress = Read-Host -Prompt "Enter the DHCP servers IP Address " 93 | $DefaultGateway = Read-Host -Prompt "Enter the default gateway Address for the DHCP scope " 94 | $NewHostname = Read-Host -Prompt "Enter the hostname for your DHCP server " 95 | $InterfaceAlias = (Get-NetAdapter)[0].InterfaceAlias 96 | $ScopeName = Read-Host -Prompt "Enter an identifying name for your new DHCP Scope EXAMPLE: Servers :" 97 | $ScopeID = Read-Host -Prompt "Enter your Scope ID EXAMPLE: 192.168.137.0 :" 98 | $StartRange = Read-Host -Prompt "Enter the starting range for DHCP scope EXAMPLE: 192.168.137.1 :" 99 | $EndRange = Read-Host -Prompt "Enter the ending rnage for the DHCP scope EXMAMPLE: 192.168.137.254 :" 100 | $FQDN = "$($NewHostname).$($Domain)" 101 | Write-Output "[*] Setting the server level DNS Dynamic Update configuration settings" 102 | Set-DhcpServerv4DnsSetting -ComputerName $FQDN -DynamicUpdates Always -NameProtection $True 103 | Set-DhcpServerDnsCredential -Credential (Get-Credential -Message "Enter credentials for the normal user account used to update Dynamic DNS records through the DHCP server") -ComputerName $FQDN 104 | 105 | Write-Output "[*] Enabling the ability to deny assigning IP addresses to MAC addresses" 106 | Set-DhcpServerv4FilterList -ComputerName $FQDN -Allow $False -Deny $True 107 | 108 | Write-Output "[*] Creating an initial scope on the DHCP server and setting options" 109 | Add-DhcpServerv4Scope -Name $ScopeName -StartRange $StartRange -EndRange $EndRange -Description "Default $ScopeName subnet" -SubnetMask 255.255.255.0 -State Active 110 | Add-DhcpServerv4ExclusionRange -ScopeId $ScopeID -StartRange $StartRange -EndRange $EndRange -ComputerName $FQDN 111 | Set-DhcpServerv4OptionValue -ComputerName $FQDN -ScopeId $ScopeID -DnsServer $DnsServer -DnsDomain $Domain -Router $DefaultGateway -Force 112 | Set-DhcpServerv4OptionValue -OptionId 42 -Value $NTPServer -ScopeId $ScopeID -ComputerName $FQDN 113 | 114 | Write-Output "[*] Disabling NetBIOS in DHCP assignments" 115 | Set-DhcpServerv4OptionValue -ComputerName $FQDN -VendorClass "Microsoft Options" -OptionId 1 -Value 1 116 | Set-DhcpServerv4OptionValue -ComputerName $FQDN -VendorClass "Microsoft Windows 2000 Options" -OptionId 1 -Value 1 117 | -------------------------------------------------------------------------------- /Apache LDAPS Template for nagios.conf: -------------------------------------------------------------------------------- 1 | # ==================================================================================== 2 | # OsbornePro LLC. Nagios Core Apache2 Configuration file template to use LDAP over SSL 3 | # ==================================================================================== 4 | # Configuration Starts at line 63 5 | # 6 | # LDAPS REQUIREMENTS: 7 | # 1.) Root CA Subject Name (CN value) must differ from the LDAPS Subject Name (CN value) in order to be trusted by OpenSSL 8 | # 2.) LDAPS Certificate contents must contain the base64 server certificate followed by the base64 Root CA certificates 9 | # 3.) Define users allowed to access Nagios in your Nagios /usr/local/nagios/etc/cgi.cfg file (EXAMPLE SETTING: authorized_for_all_service_commands=nagiosadmin,domainuser) 10 | # 11 | #-------------------------------------------------------------------------------------------------------------------------- 12 | # (If not already done) CREATE A ROOT CA ON A SERVER THAT IS DIFFERENT FROM YOUR LDAP SERVER USING THE BELOW COMMANDS 13 | #-------------------------------------------------------------------------------------------------------------------------- 14 | #sudo openssl genrsa -des3 -out private/ca.key 4096 15 | #sudo openssl req -new -x509 -days 365 -key /etc/ssl/private/ca.key -out /etc/ssl/certs/ca.crt 16 | # 17 | #-------------------------------------------------------------------------------------------------------------------------- 18 | # TRUST THE NEWLY CREATED CA BY COPYING IT TO YOUR LDAP SERVER AND ADDING IT TO THE TRUSTED CERTIFICATE STORE 19 | #-------------------------------------------------------------------------------------------------------------------------- 20 | #scp -P 22 -i ~/.ssh/id_rsa /etc/ssl/certs/ca.crt username@ldapserver.domain.com:/tmp/ca.crt 21 | # 22 | #-------------------------------------------------------------------------------------------------------------------------- 23 | # CREATE A CERTIFICATE REQUEST ON LDAP SERVER AND TRUST THE ca.crt CERTIFICATE 24 | #-------------------------------------------------------------------------------------------------------------------------- 25 | #sudo cp /tmp/ca.crt /usr/share/ca-certificates/mozilla/ca.crt 26 | #echo "[*] Ensure your ca.crt certificate is selected by using the space bar in the below commands select window 27 | #dpkg-reconfigure ca-certificates 28 | # 29 | #echo "[*] Creating CSR request" 30 | #sudo mkdir /etc/ssl/requests 31 | #sudo openssl req -out /etc/ssl/requests/ldap.csr -new -newkey rsa:2048 -nodes -keyout /etc/ssl/private/ldap.key 32 | # 33 | #echo "[*] Copy the CSR request over to your CA server" 34 | #scp -P 22 -i ~/.ssh/id_rsa /etc/ssl/requests/ldap.csr username@ca-server.domain.com:/tmp/ldap.csr 35 | # 36 | #-------------------------------------------------------------------------------------------------------------------------- 37 | # COMPLETE CSR REQUEST USING THIS COMMAND ON YOUR CA 38 | #-------------------------------------------------------------------------------------------------------------------------- 39 | #sudo openssl x509 -req -days 365 -in /tmp/ldap.csr -CA /etc/ssl/certs/ca.crt -CAkey /etc/ssl/private/ca.key -CAcreateserial -out /etc/ssl/certs/ldap.crt -sha256 40 | # 41 | #echo "[*] Copy the completed certificate back over to your LDAP server" 42 | #scp -P 22 -i ~/.ssh/id_rsa /etc/ssl/requests/ldap.crt username@ca-server.domain.com:/tmp/ldap.crt 43 | # 44 | #-------------------------------------------------------------------------------------------------------------------------- 45 | # MOVE /tmp/ldap.crt OUT OF /tmp DIRECTORY AND INTO APPRORPIATE ONE AND SET PERMISSIONS OF LDAP SERVICE ON THOSE CERTS 46 | #-------------------------------------------------------------------------------------------------------------------------- 47 | #sudo cp /tmp/ldap.crt /etc/ssl/certs/ldap.crt 48 | #USER=$(ps aux | grep slapd | cut -d" " -f1 | grep -wv root) 49 | #sudo chown $USER:$USER /etc/ssl/certs/ldap.crt 50 | #sudo chown $USER:$USER /etc/ssl/private/ldap.key 51 | # 52 | #echo "[*] Create expected certificate file contents for LDAPS" 53 | #sudo cat {/etc/ssl/certs/ldap.crt,/etc/ssl/certs/ca.crt} > /etc/ssl/certs/ldaps-cert.crt 54 | #sudo chown $USER:$USER /etc/ssl//certs/ldaps-cert.crt 55 | # 56 | #echo "[*] Ensure the slapd service is configured to use those certificates 57 | # Modify /etc/ldap/ldap.conf file so it uses the below values 58 | # olcTLSCertificateKeyFile: /etc/ssl/private/ldap.key 59 | # olcTLSCertificateFile: /etc/ssl/certs/ldaps-cert.crt 60 | #sudo systemctl restart slapd.service 61 | #sudo slapcat -b "cn=config" | egrep "olcTLSCertificateFile|olcTLSCertificateKeyFile" 62 | 63 | #-------------------------------------------------- BEGIN CONFIGURATION ---------------------------------------------------# 64 | # Below values are to ensure current LDAP authentication is used instead of cached values 65 | LDAPSharedCacheSize 500000 66 | LDAPCacheEntries -1 67 | LDAPCacheTTL -1 68 | LDAPOpCacheEntries -1 69 | LDAPOpCacheTTL -1 70 | 71 | ScriptAlias /nagios/cgi-bin "/usr/local/nagios/sbin" 72 | 73 | SSLRequireSSL 74 | Options ExecCGI 75 | AllowOverride None 76 | Order allow,deny 77 | Allow from all 78 | AuthBasicProvider ldap 79 | AuthType Basic 80 | AuthLDAPGroupAttributeIsDN on 81 | AuthName "Enter LDAP Credentials" 82 | # 83 | # FOR OPEN LDAP 84 | AuthLDAPGroupAttribute member 85 | # AuthLDAPURL "ldap://ldapserver.domain.com:389/ou=People,dc=domain,dc=com?uid?sub?(objectClass=*)" NONE 86 | AuthLDAPURL "ldaps://ldapserver.domain.com:636/ou=People,dc=domain,dc=com?uid?sub?(objectClass=*)" NONE 87 | # 88 | # FOR ACTIVE DIRECTORY 89 | # AuthLDAPGroupAttribute memberOf 90 | # #AuthLDAPURL "ldap://ldapserver.domain.com:389/cn=Users,dc=domain,dc=com?sAMAccountName?sub?(objectClass=*)" NONE 91 | # AuthLDAPURL "ldaps://ldapserver.domain.com:636/cn=Users,dc=domain,dc=com?sAMAccountName?sub?(objectClass=*)" NONE 92 | # 93 | AuthLDAPBindDN "cn=admin,dc=domain,dc=com" 94 | AuthLDAPBindPassword "Password123!" 95 | Require ldap-group cn=nagiosusers,ou=Groups,dc=domain,dc=com 96 | # OR 97 | # Require valid-user 98 | # 99 | # BELOW IS USED FOR LOCAL USER ACCESS 100 | # = 2.3> 101 | # 102 | # Require all granted 103 | # AuthName "Nagios Access" 104 | # AuthType Basic 105 | # AuthUserFile /usr/local/nagios/etc/htpasswd.users 106 | # Require valid-user 107 | # 108 | # 109 | # 110 | # Order allow,deny 111 | # Allow from all 112 | # AuthName "Nagios Access" 113 | # AuthType Basic 114 | # AuthUserFile /usr/local/nagios/etc/htpasswd.users 115 | # Require valid-user 116 | # 117 | 118 | 119 | Alias /nagios "/usr/local/nagios/share" 120 | 121 | SSLRequireSSL 122 | Options ExecCGI 123 | AllowOverride None 124 | Order allow,deny 125 | Allow from all 126 | AuthBasicProvider ldap 127 | AuthType Basic 128 | AuthLDAPGroupAttributeIsDN on 129 | AuthName "Enter LDAP Credentials" 130 | # 131 | # FOR OPEN LDAP 132 | AuthLDAPGroupAttribute member 133 | # AuthLDAPURL "ldap://ldapserver.domain.com:389/ou=People,dc=domain,dc=com?uid?sub?(objectClass=*)" NONE 134 | AuthLDAPURL "ldaps://ldapserver.domain.com:636/ou=People,dc=domain,dc=com?uid?sub?(objectClass=*)" NONE 135 | # 136 | # FOR ACTIVE DIRECTORY 137 | # AuthLDAPGroupAttribute memberOf 138 | # #AuthLDAPURL "ldap://ldapserver.domain.com:389/cn=Users,dc=domain,dc=com?sAMAccountName?sub?(objectClass=*)" NONE 139 | # AuthLDAPURL "ldaps://ldapserver.domain.com:636/cn=Users,dc=domain,dc=com?sAMAccountName?sub?(objectClass=*)" NONE 140 | # 141 | AuthLDAPBindDN "cn=admin,dc=domain,dc=com" 142 | AuthLDAPBindPassword "Password123!" 143 | Require ldap-group cn=nagiosusers,ou=Groups,dc=domain,dc=com 144 | # OR 145 | # Require valid-user 146 | # 147 | # BELOW IS USED FOR LOCAL USER ACCESS 148 | # 149 | # = 2.3> 150 | # 151 | # Require all granted 152 | # AuthName "Nagios Access" 153 | # AuthType Basic 154 | # AuthUserFile /usr/local/nagios/etc/htpasswd.users 155 | # Require valid-user 156 | # 157 | # 158 | # 159 | # Order allow,deny 160 | # Allow from all 161 | # AuthName "Nagios Access" 162 | # AuthType Basic 163 | # AuthUserFile /usr/local/nagios/etc/htpasswd.users 164 | # Require valid-user 165 | # 166 | 167 | -------------------------------------------------------------------------------- /aap_api_call.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ################################################################################################### 3 | # DESCRIPTION: # 4 | # This script was designed to be executed by a NagiosXI Event Handler to run AAP Templates # 5 | # The tough thing about Nagios event handlers is using the correct host name value so it # 6 | # matches the inventory value in AAP. Modify line 84 in this script to make that work for you # 7 | # # 8 | # Company: OsbornePro LLC. # 9 | # Website: https://osbornepro.com # 10 | # Author: Robert H. Osborne # 11 | # Contact: rosborne@osbornepro.com # 12 | ################################################################################################### 13 | # Define the user ID of the local AAP user you are authenticating to AAP with 14 | USER_ID=8 15 | USAGE=" 16 | #===============================================# 17 | # ___ _ ___ # 18 | # / _ \ __| |__ ___ _ _ _ _ ___| _ \_ _ ___ # 19 | # | (_) (_-< '_ \/ _ \ '_| ' \/ -_) _/ '_/ _ \ # 20 | # \___//__/_.__/\___/_| |_||_\___|_| |_| \___/ # 21 | #-----------------------------------------------# 22 | # If you can't beat 'em, tech 'em! # 23 | #===============================================# 24 | SYNTAX: 25 | $0 [-h] -H -A -X -T -t -s -S -a -o -g -d 26 | 27 | DESCRIPTION: 28 | This script is for executing a Nagios Event Handler that runs ansible playbooks via the AAP API 29 | Documentation at https://developers.redhat.com/api-catalog/api/ansible-automation-controller 30 | 31 | REQUIREMENTS: 32 | 1.) You should have local Semaphore admin account credentials to authenticate to Semaphore 33 | 2.) Define $USER#$ variables in your /usr/local/nagios/etc/resource.cfg file containing the Sempahore username and password 34 | 3.) Create a command in Nagios that runs this script, passing along the $USER$ variables for the -A and -X parameters in this script 35 | $USER1$/check_ncpa.py 36 | 37 | CONTACT INFORMATION 38 | Company: Vinebrook Technology Inc. 39 | Website: https://www.vinebrooktechnology.com 40 | Author: Robert Osborne (Vinebrook Technology) 41 | Contact: rosborne@vinebrooktech.com 42 | 43 | USAGE: aap_api_call.sh [-h] -H -A -X -T -t -s -S -a -o -g -d 44 | 45 | OPTIONS: 46 | -H : AAP host URL (e.g. https://ansible.domain.com) 47 | -A : Username (or 'token' if using API token) 48 | -X : Password or API token 49 | -T : Job Template ID in AAP 50 | -t : Target host (limit) 51 | -s : Service name 52 | -S : Service state type (HARD/SOFT) 53 | -a : Service state (OK/WARNING/CRITICAL) 54 | -o : Service output 55 | -g : Host group names 56 | -d : Drive letter 57 | 58 | EXAMPLES: 59 | aap_api_call.sh -h 60 | # This example returns the help information on how to use this command 61 | 62 | aap_api_call.sh -H https://ansible.domain.com -A token -X tokenvaluehere -T 94 -t server01 63 | # This example runs task 94 against target_host server01 64 | " 65 | LOG_FILE="/tmp/run-aap-playbook.log" 66 | 67 | function log_message() { 68 | /usr/bin/echo "$(/usr/bin/date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE" 69 | } 70 | 71 | # Print usage 72 | function print_usage { 73 | /bin/printf "$USAGE\n" >&2 74 | exit 3 75 | } # End function print_usage 76 | 77 | # Parse arguments 78 | while getopts "hH:A:X:T:t:s:S:a:o:g:d:" OPTION; do 79 | case $OPTION in 80 | h) print_usage ;; 81 | H) AAP_HOST="${OPTARG}" ;; 82 | A) AUTHUSERNAME="${OPTARG}" ;; 83 | X) AUTHPASSWORD="${OPTARG}" ;; 84 | T) JOB_TEMPLATE_ID="${OPTARG}" ;; 85 | t) TARGET_HOST=$(echo "${OPTARG%%.*}" | tr '[:lower:]' '[:upper:]')'*' ;; 86 | s) SERVICE_NAME="$OPTARG" ;; 87 | S) SERVICE_STATE_TYPE="$OPTARG" ;; 88 | a) SERVICE_STATE="$OPTARG" ;; 89 | o) SERVICE_OUTPUT="$OPTARG" ;; 90 | g) HOST_GROUP_NAMES="$OPTARG" ;; 91 | d) DRIVE_LETTER="$OPTARG" ;; 92 | *) print_usage ;; 93 | esac 94 | done 95 | 96 | SERVICE_STATE_TYPE=${SERVICE_STATE_TYPE:-"UNDEFINED"} 97 | log_message "[-] SERVICE_STATE_TYPE is '${SERVICE_STATE_TYPE}'" 98 | 99 | if [ "${SERVICE_STATE,,}" == "ok" ]; then 100 | log_message "[-] Service state is OK. Exiting without triggering playbook." 101 | exit 0 102 | fi 103 | 104 | if [ "$SERVICE_STATE_TYPE" != "HARD" ] && [ ${#SERVICE_STATE_TYPE} -lt 2 ]; then 105 | log_message "[-] Not HARD state. Exiting." 106 | exit 0 107 | fi 108 | 109 | if [ -z "$AAP_HOST" ] || [ -z "$JOB_TEMPLATE_ID" ] || [ -z "$TARGET_HOST" ]; then 110 | log_message "[x] Required arguments missing" 111 | print_usage 112 | fi 113 | 114 | # Set base API path for Controller 115 | AAP_API_BASE="${AAP_HOST}/api/controller/v2" 116 | 117 | # Build authentication header 118 | if [ "$AUTHUSERNAME" == "token" ]; then 119 | AUTH_HEADER="Authorization: Bearer $AUTHPASSWORD" 120 | else 121 | # Get user ID 122 | USERS_RESPONSE=$(/usr/bin/curl -v -sk -u "$AUTHUSERNAME:$AUTHPASSWORD" \ 123 | "$AAP_API_BASE/users/?username=$AUTHUSERNAME" 2>> "$LOG_FILE") 124 | log_message "[-] Raw USERS_RESPONSE: $USERS_RESPONSE" 125 | 126 | if ! echo "$USERS_RESPONSE" | /usr/bin/jq -e . >/dev/null 2>&1; then 127 | log_message "[x] USERS_RESPONSE is not valid JSON" 128 | exit 1 129 | fi 130 | 131 | log_message "[-] User ID: $USER_ID" 132 | 133 | # Create PAT 134 | TOKEN_RESPONSE=$(/usr/bin/curl -v -sk -u "$AUTHUSERNAME:$AUTHPASSWORD" -X POST \ 135 | -H "Content-Type: application/json" \ 136 | -d "{\"description\": \"Nagios Auto Token\", \"scope\": \"write\"}" \ 137 | "${AAP_API_BASE}/users/${USER_ID}/personal_tokens/" 2>> "$LOG_FILE") 138 | 139 | log_message "[-] Raw TOKEN_RESPONSE: $TOKEN_RESPONSE" 140 | 141 | if ! echo "$TOKEN_RESPONSE" | /usr/bin/jq -e . >/dev/null 2>&1; then 142 | log_message "[x] TOKEN_RESPONSE is not valid JSON" 143 | exit 1 144 | fi 145 | 146 | ACCESS_TOKEN=$(/usr/bin/echo "$TOKEN_RESPONSE" | /usr/bin/jq -r '.token') 147 | if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then 148 | log_message "[x] Failed to create PAT. Response: $TOKEN_RESPONSE" 149 | exit 1 150 | fi 151 | AUTH_HEADER="Authorization: Bearer $ACCESS_TOKEN" 152 | log_message "[-] PAT created successfully (truncated for log)." 153 | fi 154 | 155 | # Check how many jobs are running 156 | JOBS_RESPONSE=$(/usr/bin/curl -v -sk -H "$AUTH_HEADER" \ 157 | "$AAP_API_BASE/jobs/?status__in=running,pending" 2>> "$LOG_FILE") 158 | log_message "[-] Raw JOBS_RESPONSE: $JOBS_RESPONSE" 159 | 160 | if ! echo "$JOBS_RESPONSE" | /usr/bin/jq -e . >/dev/null 2>&1; then 161 | log_message "[x] JOBS_RESPONSE is not valid JSON" 162 | exit 1 163 | fi 164 | 165 | JOB_COUNT=$(/usr/bin/echo "$JOBS_RESPONSE" | /usr/bin/jq '.count') 166 | 167 | log_message "[-] Found $JOB_COUNT running/pending jobs." 168 | if [ "$JOB_COUNT" -ge 4 ]; then 169 | log_message "[!] Too many jobs running. Skipping." 170 | /usr/bin/echo "Too many AAP jobs running. Exiting." 171 | exit 0 172 | fi 173 | 174 | # Build payload 175 | PAYLOAD="{\"limit\": \"${TARGET_HOST}\", \"extra_vars\": {\"service_name\":\"${SERVICE_NAME}\", \"drive_letter\":\"${DRIVE_LETTER}\"}}" 176 | log_message "[-] Payload: $PAYLOAD" 177 | 178 | # Launch the job 179 | LAUNCH_RESPONSE=$(/usr/bin/curl -v -sk -X POST \ 180 | -H "$AUTH_HEADER" \ 181 | -H "Content-Type: application/json" \ 182 | -d "$PAYLOAD" \ 183 | "$AAP_API_BASE/job_templates/${JOB_TEMPLATE_ID}/launch/" 2>> "$LOG_FILE") 184 | 185 | if [ $? -ne 0 ]; then 186 | log_message "[x] Failed to launch job. Response: $LAUNCH_RESPONSE" 187 | exit 1 188 | else 189 | log_message "[-] Job launched successfully." # Response: $LAUNCH_RESPONSE" 190 | fi 191 | 192 | log_message "[-] Script execution completed." 193 | -------------------------------------------------------------------------------- /LAPS-Setup.ps1: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # 3 | # NOTE: This is pre Windows Server 2025 which incorporates 4 | # LAPS by default 5 | # 6 | ############################################################ 7 | $Logo = @" 8 | ╔═══╗░░╔╗░░░░░░░░░░░░╔═══╗░░░░░ 9 | ║╔═╗║░░║║░░░░░░░░░░░░║╔═╗║░░░░░ 10 | ║║░║╠══╣╚═╦══╦═╦═╗╔══╣╚═╝╠═╦══╗ 11 | ║║░║║══╣╔╗║╔╗║╔╣╔╗╣║═╣╔══╣╔╣╔╗║ 12 | ║╚═╝╠══║╚╝║╚╝║║║║║║║═╣║░░║║║╚╝║ 13 | ╚═══╩══╩══╩══╩╝╚╝╚╩══╩╝░░╚╝╚══╝ 14 | =============================== 15 | If you can't beat `em tech `em! 16 | =============================== 17 | https://osbornepro.com 18 | EMAIL: info@osbornepro.com 19 | "@ 20 | Write-Output -InputObject "$Logo" 21 | Write-Output -InputObject "[*] This script is used to set up LAPS in your domain" 22 | $LapsShareDirectory = "$((Get-CimInstance -Class Win32_Share -Filter "Type=0 and Name LIKE 'NETLOGON'").Path)\LAPS" 23 | 24 | $PDC = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().PdcRoleOwner.Name 25 | If ("$Env:COMPUTERNAME.$env:USERDNSDOMAIN".ToLower() -ne $PDC.ToLower()) { 26 | 27 | Throw "[x] You need to do this on the primary domain controller in your environment : $PDC" 28 | 29 | } # End If 30 | 31 | 32 | Write-Output -InputObject "[*] Creating $LapsShareDirectory directory to share on network and setting local folder permissions" 33 | New-Item -Path $LapsShareDirectory –ItemType Directory -Force -ErrorAction Stop | Out-Null 34 | New-SMBShare -Name "LAPS" -Path $LapsShareDirectory -FullAccess "Administrators" -ChangeAccess "$env:USERDNSDOMAIN\Domain Admins" -ReadAccess "$env:USERDNSDOMAIN\Domain Users" | Out-Null 35 | 36 | 37 | If (!(Test-Path -Path C:\Windows\PolicyDefinitions\AdmPwd.admx)) { 38 | 39 | Write-Output -InputObject "[x] You will need to run the install file LAPS.x64.msi which can be downloaded from the below link `n - https://www.microsoft.com/en-us/download/confirmation.aspx?id=46899" 40 | Read-Host -Prompt "[!] Press ENTER to continue after you have downloaded and installed the LAPS.x64.msi file from the above link" 41 | Read-Host -Prompt "[!] Press ENTER after saving the LAPS files like LAPS.x64.msi you downloaded to $LapsShareDirectory" 42 | 43 | } # End If 44 | 45 | 46 | $Member = Get-ADPrincipalGroupMembership -Identity $env:USERNAME | Where-Object -FilterScript { $_.Name -eq "Schema Admins" } 47 | If (!($Member)) { 48 | 49 | $Answer = Read-Host -Prompt "[?] Would you like to add your current user to the 'Schema Admins' Active Directory group. This is required to update the AD Schema for LAPS usage? [y/N]" 50 | If ($Answer -like "y*") { 51 | 52 | Write-Output -InputObject "[*] Adding $env:USERNAME to the 'Schema Admins' AD Security Group" 53 | Add-ADGroupMember -Identity "Schema Admins" -Members $env:USERNAME -Verbose:$False 54 | Write-Warning -Message "[!] Please log out and log back in to obtain your new permissions!" 55 | Throw "[x] Log back in to obtain your new Schema Admin permissions" 56 | 57 | } Else { 58 | 59 | Throw "[x] Schema can not be updated with the current user" 60 | 61 | } # End Else 62 | 63 | } # End If 64 | 65 | Write-Output -InputObject "[*] Updating AD Schema. You may need to restart before this works for the new permissions to apply to your current user" 66 | Update-AdmPwdADSchema 67 | 68 | 69 | Write-Output -InputObject "[*] Below is a list of current LAPS extended rights permissions" 70 | Try { Find-AdmPwdExtendedRights -Identity "*" } Catch { Write-Verbose -Message "This is here to prevent the error message expected from showing up"} 71 | 72 | Do { 73 | 74 | $OU = Read-Host -Prompt "[?] What is the name of the OU that contains your LAPS computers This is required for LAPS to work? EXAMPLE: Computers" 75 | If ($OU.Length -gt 1) { 76 | 77 | $DN = Get-ADObject -Filter {Name -like $OU} | Select-Object -ExpandProperty DistinguishedName 78 | 79 | } # End If 80 | 81 | Write-Output -InputObject "[*] Updating the Active Directory Schema for LAPS" 82 | Set-AdmPwdComputerSelfPermission -Identity $DN 83 | 84 | $Done = Read-Host -Prompt "[?] Would you like to add another OU for LAPS devices? [y/N]" 85 | 86 | } Until ($Done -like "N*") 87 | 88 | 89 | $Answer2 = Read-Host -Prompt "[?] Would you like to set up backups of LAPS password history? This will not exist otherwise [y/N]" 90 | If ($Answer2 -like "y*") { 91 | 92 | Function Set-SecureFilePermission { 93 | [CmdletBinding()] 94 | param( 95 | [Parameter( 96 | Mandatory=$True, 97 | ValueFromPipeline=$False, 98 | HelpMessage="`n[H] Add a user or list of users who should have permisssions to an NTFS file`n[E] EXAMPLE: 'NT AUTHORITY\SYSTEM', 'BUILTIN\Administrators', 'BUILTIN\Network Configuration Operators', 'NT SERVICE\MpsSvc'")] # End Parameter 99 | [Alias('User')] 100 | [String[]]$Username, 101 | 102 | [Parameter( 103 | Mandatory=$True, 104 | ValueFromPipeline=$True, 105 | ValueFromPipelineByPropertyName=$False, 106 | HelpMessage="`n[H] Define the path to the NTFS item you want to modify the entire permissions on `n[E] EXAMPLE: C:\Temp\file.txt")] # End Parameter 107 | [String[]]$Path, 108 | 109 | [Parameter( 110 | Mandatory=$False, 111 | ValueFromPipeline=$False)] 112 | [String]$Owner = 'BUILTIN\Administrators', 113 | 114 | [Parameter( 115 | Mandatory=$False, 116 | ValueFromPipeline=$False)] # End Parameter 117 | [Alias('cn')] 118 | [String[]]$ComputerName = $env:COMPUTERNAME) # End param 119 | 120 | 121 | If ($ComputerName -eq $env:COMPUTERNAME) { 122 | 123 | Write-Verbose -Message "[v] Modifying access rule proteciton" 124 | 125 | $Acl = Get-Acl -Path "$Path" -Verbose:$False 126 | $Acl.SetAccessRuleProtection($True, $False) 127 | 128 | ForEach ($U in $Username) { 129 | 130 | Write-Verbose "Adding $U permissions for $Path" 131 | 132 | $Permission = $U, 'FullControl', 'Allow' 133 | $AccessRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $Permission 134 | 135 | $Acl.AddAccessRule($AccessRule) 136 | 137 | } # End ForEach 138 | 139 | Write-Verbose -Message "[v] Changing the owner of $Path to $Owner" 140 | 141 | $Acl.SetOwner((New-Object -TypeName System.Security.Principal.NTAccount("$Owner"))) 142 | $Acl | Set-Acl -Path "$Path" 143 | 144 | } Else { 145 | 146 | ForEach ($C in $ComputerName) { 147 | 148 | Invoke-Command -ArgumentList $Username,$Path,$Owner -HideComputerName "$C.$env:USERDNSDOMAIN" -UseSSL -Port 5986 -ScriptBlock { 149 | 150 | $Username = $Args[0] 151 | $Path = $Args[1] 152 | $Owner = $Args[2] 153 | 154 | Write-Verbose -Message "[v] Modifying access rule proteciton" 155 | 156 | $Acl = Get-Acl -Path "$Path" -Verbose:$False 157 | $Acl.SetAccessRuleProtection($True, $False) 158 | 159 | ForEach ($U in $Username) { 160 | 161 | Write-Verbose "Adding $U permissions for $Path" 162 | 163 | $Permission = $U, 'FullControl', 'Allow' 164 | $AccessRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $Permission 165 | 166 | $Acl.AddAccessRule($AccessRule) 167 | 168 | } # End ForEach 169 | 170 | Write-Verbose "Changing the owner of $Path to $Owner" 171 | 172 | $Acl.SetOwner((New-Object -TypeName System.Security.Principal.NTAccount("$Owner"))) 173 | $Acl | Set-Acl -Path "$Path" -Verbose:$False -WhatIf:$False 174 | 175 | } # End Invoke-Command 176 | 177 | } # End ForEach 178 | 179 | } # End Else 180 | 181 | } # End Function Set-SecureFilePermission 182 | 183 | Write-Output -InputObject "[*] Downloading LAPS backup script and task file" 184 | (New-Object -TypeName System.Net.WebClient).downloadFile("https://raw.githubusercontent.com/OsbornePro/BackupScripts/main/BackupLAPS.ps1", "C:\Windows\Tasks\BackupLAPS.ps1") 185 | (New-Object -TypeName System.Net.WebClient).downloadFile("https://raw.githubusercontent.com/OsbornePro/BackupScripts/main/BackupLAPS.xml", "C:\Windows\Tasks\BackupLAPS.xml") 186 | 187 | Write-Output -InputObject "[*] Importing scheduled task to run as SYSTEM which backs up the LAPS password database on the last day of every month" 188 | $Xml = Get-Content -Path "C:\Windows\Tasks\BackupLAPS.xml" | Out-String 189 | Register-ScheduledTask -Xml $Xml -TaskName "Backup LAPS" -TaskPath "\" -User "SYSTEM" –Force 190 | 191 | Set-SecureFilePermission -Username 'NT AUTHORITY\SYSTEM', 'BUILTIN\Administrators' -Path $LapsShareDirectory -Owner 'SYSTEM' 192 | 193 | } # End If 194 | 195 | Write-Output -InputObject "[*] You have now updated the Active Directory Schema for LAPS and allowed devices to set their own AD Attribute 'ms-Mcs-AdmPwd' for updating passwords." 196 | -------------------------------------------------------------------------------- /postfix-installer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ################################################################################################### 3 | # DESCRIPTION: # 4 | # This script is used to quickly and easily configure the postmap service on a Linux device # 5 | # Configuration steps vary for different SMTP servers # 6 | # # 7 | # Company: OsbornePro LLC. # 8 | # Website: https://osbornepro.com # 9 | # Author: Robert H. Osborne # 10 | # Contact: rosborne@osbornepro.com # 11 | # # 12 | ################################################################################################### 13 | # === Detect OS === 14 | HOSTNAME=$(hostname) 15 | OSID=$(grep ^ID_LIKE= /etc/os-release | cut -d'=' -f2 | tr -d '"') 16 | 17 | if echo "$OSID" | grep -qw "debian"; then 18 | printf "[*] Using Debian-based OS settings\n" 19 | CAFILE="/etc/ssl/certs/ca-certificates.crt" 20 | CAPATH="/etc/ssl/certs" 21 | CERTFILE="/etc/ssl/certs/ssl-cert-snakeoil.pem" 22 | KEYFILE="/etc/ssl/private/ssl-cert-snakeoil.key" 23 | apt-get update -qq > /dev/null 2>&1 24 | DEBIAN_FRONTEND=noninteractive apt-get install -y -qq libsasl2-modules postfix mailutils > /dev/null 2>&1 25 | 26 | elif echo "$OSID" | grep -Eqw "fedora|rhel|centos"; then 27 | printf "[*] Using Fedora/RHEL-based OS settings (AlmaLinux 10+)\n" 28 | CAFILE="/etc/pki/tls/certs/ca-bundle.crt" 29 | CAPATH="/etc/pki/tls/certs" 30 | CERTFILE="/etc/pki/tls/certs/postfix.pem" 31 | KEYFILE="/etc/pki/tls/private/postfix.key" 32 | dnf install -y -q postfix mailutils cyrus-sasl-plain > /dev/null 2>&1 33 | 34 | else 35 | printf "[!] Unsupported OS. ID_LIKE: %s\n" "$OSID" 36 | exit 1 37 | fi 38 | 39 | # === Backup === 40 | [ -f /etc/postfix/main.cf ] && cp -p /etc/postfix/main.cf /etc/postfix/main.cf.orig 41 | 42 | # === Provider === 43 | OPTIONS=("Office365" "Gmail" "Custom" "Quit") 44 | PS3="[?] Choose provider: " 45 | select opt in "${OPTIONS[@]}"; do 46 | case $REPLY in 47 | 1) PROVIDER="office365"; break ;; 48 | 2) PROVIDER="gmail"; break ;; 49 | 3) PROVIDER="custom"; break ;; 50 | 4) exit 0 ;; 51 | *) echo "[!] Invalid";; 52 | esac 53 | done 54 | 55 | case $PROVIDER in 56 | office365) DEFAULT_SERVER="smtp.office365.com"; DEFAULT_PORT="587" ;; 57 | gmail) DEFAULT_SERVER="smtp.gmail.com"; DEFAULT_PORT="587" ;; 58 | custom) DEFAULT_SERVER=""; DEFAULT_PORT="" ;; 59 | esac 60 | 61 | # === TLS / Port === 62 | echo 63 | echo "[?] Submission method:" 64 | echo " 1) STARTTLS (587) – Recommended" 65 | echo " 2) SMTPS / Implicit TLS (465)" 66 | echo " 3) Opportunistic / Plain (25)" 67 | read -p "[-] Choice [1-3]: " TLS_CHOICE 68 | 69 | case $TLS_CHOICE in 70 | 1) PORT="587"; TLS_LEVEL="encrypt"; TLS_WRAPPER="no" ;; 71 | 2) PORT="465"; TLS_LEVEL="encrypt"; TLS_WRAPPER="yes" ;; 72 | 3) PORT="25"; TLS_LEVEL="may"; TLS_WRAPPER="no" ;; 73 | *) PORT="587"; TLS_LEVEL="encrypt"; TLS_WRAPPER="no" ;; 74 | esac 75 | 76 | # === Server & Port === 77 | if [[ -n "$DEFAULT_SERVER" ]]; then 78 | read -p "[?] Use $DEFAULT_SERVER:$PORT? (Y/n): " use_def 79 | [[ ! $use_def =~ ^[Nn]$ ]] && SMTPSERVER="$DEFAULT_SERVER" || read -p "[?] SMTP Server: " SMTPSERVER 80 | else 81 | read -p "[?] SMTP Server: " SMTPSERVER 82 | fi 83 | 84 | read -p "[?] Port [$PORT]: " input_port 85 | [[ -n "$input_port" ]] && PORT="$input_port" 86 | [[ ! "$PORT" =~ ^[0-9]+$ ]] && { echo "[!] Invalid port"; exit 1; } 87 | 88 | # === Domain & Sender === 89 | read -p "[?] Domain (e.g. example.com): " DOMAIN 90 | read -p "[?] Sender Email (optional): " EMAIL 91 | PASS="" 92 | if [[ -n "$EMAIL" ]]; then 93 | read -s -p "[?] SMTP Password (optional): " PASS 94 | echo 95 | fi 96 | 97 | # === Logic === 98 | USE_SASL=false 99 | USE_SENDER_REWRITE=false 100 | if [[ -n "$EMAIL" ]]; then 101 | USE_SENDER_REWRITE=true 102 | if [[ -n "$PASS" && "$TLS_LEVEL" == "encrypt" ]]; then 103 | USE_SASL=true 104 | fi 105 | fi 106 | 107 | # === Hostname === 108 | HOSTNAME=$(hostname -f 2>/dev/null || hostname) 109 | MYHOSTNAME="${HOSTNAME}.${DOMAIN}" 110 | [[ "$MYHOSTNAME" == "." ]] && MYHOSTNAME="$HOSTNAME" 111 | 112 | # === /etc/mailname === 113 | echo "$DOMAIN" > /etc/mailname 114 | 115 | # === DH Params === 116 | openssl dhparam -out /etc/ssl/certs/postfix-dh1024.pem 1024 2>/dev/null 117 | chmod 644 /etc/ssl/certs/postfix-dh1024.pem 118 | 119 | # === Aliases – Only add if not already present === 120 | if [[ -n "$EMAIL" ]]; then 121 | if ! grep -q "^root:[[:space:]]*$EMAIL" /etc/aliases; then 122 | echo "root: $EMAIL" >> /etc/aliases 123 | printf "[*] Added root alias to /etc/aliases\n" 124 | else 125 | printf "[*] Root alias already exists in /etc/aliases\n" 126 | fi 127 | fi 128 | 129 | # === SASL (texthash) === 130 | SASL_DIR="/etc/postfix/sasl" 131 | SASL_PASSWD="$SASL_DIR/sasl_passwd" 132 | if $USE_SASL; then 133 | mkdir -p "$SASL_DIR" 134 | echo "[$SMTPSERVER]:$PORT $EMAIL:$PASS" > "$SASL_PASSWD" 135 | chmod 600 "$SASL_PASSWD" 136 | chown root:root "$SASL_PASSWD" 137 | else 138 | rm -rf "$SASL_DIR" 139 | fi 140 | 141 | # === Sender Rewrite (texthash) === 142 | GENERIC_FILE="/etc/postfix/generic" 143 | if $USE_SENDER_REWRITE; then 144 | cat > "$GENERIC_FILE" < /etc/postfix/sender_canonical_maps < /etc/postfix/header_check < /etc/postfix/mime_header_checks <<'EOF' 171 | /name=[^>]*\.(bat|cmd|com|exe|scr|pif|vbs|js|jar)/ REJECT Executable blocked 172 | EOF 173 | chmod 600 /etc/postfix/mime_header_checks 174 | chown root:root /etc/postfix/mime_header_checks 175 | 176 | # === main.cf (Override btree defaults) === 177 | cat > /etc/postfix/main.cf <> /etc/postfix/main.cf <> /etc/postfix/main.cf <> /etc/postfix/main.cf <> /etc/postfix/main.cf <> /etc/postfix/main.cf <> /etc/postfix/main.cf </dev/null 2>&1 288 | sleep 5 289 | 290 | # === Test === 291 | if [[ -n "$EMAIL" ]]; then 292 | printf "[*] Sending test email to %s...\n" "$EMAIL" 293 | { 294 | echo "Subject: Postfix Test – $(date)" 295 | echo "To: $EMAIL" 296 | echo "" 297 | echo "Host: $(hostname)" 298 | echo "Relay: [$SMTPSERVER]:$PORT" 299 | echo "TLS: $TLS_LEVEL" 300 | echo "SASL: $( $USE_SASL && echo enabled || echo disabled )" 301 | } | sendmail -f "$EMAIL" "$EMAIL" 302 | else 303 | printf "[*] No test email\n" 304 | fi 305 | 306 | printf "[*] Done! Logs: journalctl -u postfix -f\n" 307 | -------------------------------------------------------------------------------- /postfix-main.cf: -------------------------------------------------------------------------------- 1 | # OsbornePro LLC. Template for configuring Postfix 2 | 3 | # You can start your configuration over with ```dpkg-reconfigure postfix``` 4 | # 5 | # See /usr/share/postfix/main.cf.dist for a commented, more complete version 6 | # Debian specific: Specifying a file name will cause the first 7 | # line of that file to be used as the name. The Debian default 8 | # is /etc/mailname. This should be your domain. An example of the contents 9 | # EXAMPLE CONTENTS OF /etc/mailname 10 | # cat /etc/mailname 11 | # osbornepro.com 12 | myorigin=/etc/mailname 13 | 14 | smtpd_banner = $myhostname ESMTP $mail_name Company LLC. 15 | biff=no 16 | 17 | # appending .domain is the MUA's job. 18 | append_dot_mydomain=no 19 | 20 | # Uncomment the next line to generate "delayed mail" warnings 21 | #delay_warning_time=4h 22 | 23 | readme_directory=no 24 | 25 | # See http://www.postfix.org/COMPATIBILITY_README.html -- default to 2 on 26 | # fresh installs. 27 | compatibility_level=2 28 | 29 | #======================================================== 30 | # Use SASL Authentication 31 | #======================================================== 32 | smtp_sasl_auth_enable = yes 33 | smtp_sasl_security_options = noanonymous 34 | smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd 35 | # cat /etc/postfix/sasl_passwd 36 | # Create an optimized version of above file by doing ```postmap /etc/postfix/sasl_passwd``` 37 | # [mail.smtp2go.com]:2525 rosborne@osbornepro.com:P@ssw0rd123! 38 | # ls -la /etc/postfix/sasl_passwd 39 | # -rw------- 1 root root 99 Month ## #### /etc/postfix/sasl_passwd 40 | #---------------------------------------------------------- 41 | 42 | 43 | relayhost = [mail.smtp2go.com]:2525 44 | relay_destination_concurrency_limit=20 45 | header_size_limit=4096000 46 | 47 | 48 | #================================================================= 49 | # TLS parameters 50 | #================================================================= 51 | # Enable TLS when SMTP is sending mail. Using ```yes``` may prevent deliverabiltiy to gmails 52 | smtp_tls_security_level = encrypt 53 | # may : Postfix SMTP server announces STARTTLS support to remote SMTP clients, but does not require that clients use TLS encryption 54 | # encrypt : Postfix SMTP server announces STARTTLS and accepts no mail without TLS encryption. 55 | # According to RFC 2487 'encrypt' MUST NOT be applied in case of a publicly-referenced Postfix SMTP server. This option is off by default and should only seldom be used. 56 | # Fine to set to encrypt if you are using this for email alerts to yourself 57 | 58 | smtpd_tls_auth_only=yes 59 | smtp_tls_CApath = /etc/ssl/certs 60 | smtpd_tls_CApath = /etc/ssl/certs 61 | smtpd_tls_CAfile=/etc/ssl/certs/ca-certificates.crt 62 | smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem 63 | # Only 1 certificate can be managed so it should be issued on your own hostname. 64 | # No default is supplied (no certificate is presented), unless you explicitly set the certificate in the configuration. 65 | # You can use the same certificate as for the server side 66 | # 67 | smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key 68 | # chown root etc/ssl/private/ssl-cert-snakeoil.key ; chmod 400 etc/ssl/private/ssl-cert-snakeoil.key 69 | # 70 | tls_ssl_options=NO_COMPRESSION 71 | smtp_use_tls=yes 72 | smtpd_use_tls=yes 73 | smtpd_tls_mandatory_protocols=!SSLv2, !SSLv3, !TLSv1, !TLSv1.1 74 | smtpd_tls_protocols=!SSLv2, !SSLv3, !TLSv1, !TLSv1.1 75 | smtpd_tls_mandatory_ciphers=high 76 | # or medium if you prefer 77 | # 78 | # If clients are expected to always verify the Postfix SMTP server certificate you may want to disable anonymous 79 | # ciphers by setting "smtpd_tls_mandatory_exclude_ciphers = aNULL" or "smtpd_tls_exclude_ciphers = aNULL", as appropriate. 80 | # One can't force a remote SMTP client to check the server certificate so excluding anonymous ciphers is generally unnecessary 81 | smtpd_tls_mandatory_exclude_ciphers=aNULL 82 | smtpd_tls_exclude_ciphers=aNULL 83 | 84 | # Logging Postfix can be configured to report information about the negotiated cipher, the corresponding key lengths, 85 | # and the remote peer certificate or public-key verification status 86 | smtp_tls_loglevel=1 87 | smtpd_tls_loglevel=1 88 | smtpd_tls_received_header=yes 89 | #----------------------------------------------------------------- 90 | 91 | 92 | #============================================================ 93 | # Diffie Hellman File 94 | #============================================================ 95 | smtpd_tls_dh1024_param_file=/etc/ssl/certs/postfix-dh1024.pem 96 | # OR If available this below will load instead 97 | smtpd_tls_dh2048_param_file=/etc/ssl/certs/postfix-dh2048.pem 98 | # 99 | # sudo umask 022 100 | # sudo openssl dhparam -out /etc/ssl/certs/postfix-dh512.tmp 512 && mv /etc/ssl/certs/postfix-dh512.tmp /etc/ssl/certs/postfix-dh512.pem 101 | # sudo openssl dhparam -out /etc/ssl/certs/postfix-dh1024.tmp 1024 && mv /etc/ssl/certs/postfix-dh1024.tmp /etc/ssl/certs/postfix-dh1024.pem 102 | # sudo openssl dhparam -out /etc/ssl/certs/postfix-dh2048.tmp 2048 && mv /etc/ssl/certs/postfix-dh2048.tmp /etc/ssl/certs/postfix-dh2048.pem 103 | # sudo chmod 644 /etc/ssl/certs/postfix-dh512.pem /etc/ssl/certs/postfix-dh1024.pem /etc/ssl/certs/postfix-dh2048.pem 104 | #------------------------------------------------------------- 105 | 106 | smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache 107 | smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache 108 | 109 | #====================================================== 110 | # CIPHERS 111 | #====================================================== 112 | # MEDIUM CIPHERS 113 | #++++++++++++++++++++++++++++++++++++++++++++++++++++++ 114 | #tls_medium_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 115 | # 116 | # CBC is no longer considered a strong block chain method 117 | # 118 | # Get value of tls_medium_cipherlist 119 | # postconf -d | grep tls_medium_cipherlist 120 | # 121 | # # View available ciphers based on the selections 122 | # openssl ciphers -v 'aNULL:-aNULL:HIGH:MEDIUM:+RC4:@STRENGTH' | awk '{printf "%-32s %s\n", $1, $3}' 123 | #++++++++++++++++++++++++++++++++++++++++++++++++++++++ 124 | # HIGH CIPHERS 125 | #++++++++++++++++++++++++++++++++++++++++++++++++++++++ 126 | tls_high_cipherlist=ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:-DES:!RC4:!MD5:!PSK:!aECDH:EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA 127 | # 128 | # CBC is no longer considered a strong block chain method 129 | # 130 | # Get value of tls_high_cipherlist 131 | # postconf -d | grep tls_high_cipherlist 132 | # 133 | # View available ciphers based on your selections 134 | # openssl ciphers -v 'aNULL:-aNULL:HIGH:@STRENGTH' | awk '{printf "%-32s %s\n", $1, $3}' 135 | tls_preempt_cipherlist = no 136 | 137 | # See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for 138 | # information on enabling SSL in the smtp client. 139 | #---------------------------------------------------------------- 140 | 141 | # Header Checks 142 | #header_checks = pcre:/etc/postfix/header_checks 143 | mime_header_checks = regexp:/etc/postfix/mime_header_checks 144 | # Contents of /etc/postfix/mime_header_checks below 145 | #/name=[^>]*\.(bat|com|exe|dll|vbs)/ REJECT 146 | 147 | # Relay Restrictions 148 | smtpd_relay_restrictions=permit_mynetworks permit_sasl_authenticated defer_unauth_destination 149 | smtpd_helo_restrictions=permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_helo_hostname, reject_invalid_helo_hostname, reject_non_fqdn_hostname, reject_invalid_hostname 150 | smtpd_sender_restrictions=permit_mynetworks,reject_rbl_client bl.spamcop.net,reject_rbl_client dsbl.dnsbl.net.au,reject_rbl_client xbl.spamhaus.org,reject_rbl_client sbl.spamhaus.org,reject_rbl_client dsn.rfc-ignorant.org,reject_rbl_client cbl.abuseat.org,reject_rbl_client dsn.rfc-ignorant.org,reject_unauth_destination,reject_invalid_hostname,reject_unauth_pipelining,reject_non_fqdn_sender,reject_unknown_sender_domain,reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit 151 | smtpd_client_restrictions=permit_mynetworks, permit_sasl_authenticated, reject_unknown_client_hostname, reject_rbl_client cbl.abuseat.org, reject_rbl_client b.barracudacentral.org 152 | smtpd_recipient_restrictions=permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, reject_unknown_recipient_domain, check_policy_service unix:private/policy-spf, check_policy_service inet:127.0.0.1:10023 153 | smtpd_relay_restrictions=permit_mynetworks permit_sasl_authenticated defer_unauth_destination 154 | smtpd_delay_reject=yes 155 | # Above smtpd_recipient_restrictions check_policy_service inet:127.0.0.1:10023 requires 156 | # apt install -y postgrey 157 | 158 | 159 | #myhostname=localhost 160 | myhostname=hostname.domain.com 161 | mydomain=domain.com 162 | alias_maps = hash:/etc/aliases 163 | alias_database = hash:/etc/aliases 164 | mydestination = localhost.$mydomain, localhost, $myhostname 165 | mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 166 | mailbox_size_limit = 0 167 | recipient_delimiter = + 168 | #inet_interfaces = all 169 | inet_interfaces=loopback-only 170 | inet_protocols = ipv4 171 | 172 | # String RFC Envelopes 173 | strict_rfc821_envelopes=yes 174 | 175 | # Use your domain 176 | masquerade_domains = domain.com 177 | 178 | # Disable VRFY and EXPN on mailserver 179 | disable_vrfy_command=yes 180 | 181 | # Require helo 182 | smtpd_helo_required=yes 183 | 184 | # Restart Postfix Service 185 | # sudo systemctl restart postfix 186 | 187 | # Send a test email using below command 188 | # echo -e "FROM: root\nTO: root\nSubject: Test email from the your device\n\nThis is a test email." | sendmail -t 189 | # Check the logs for email issues 190 | # tail /var/log/mail.err 191 | # tail /var/log/mail.log 192 | 193 | 194 | #======================================================= 195 | # SPF Checks 196 | #======================================================= 197 | policy-spf_time_limit=3600s 198 | # Above requires you to install 199 | # apt install -y postfix-policyd-spf-perl postfix-policyd-spf-python 200 | # 201 | # SEE LINE 152 check_policy_service unix:private/policy-spf at the end of smtpd_recipient_restrictions 202 | # Then EDIT /etc/postfix/master.cf to include the below lines 203 | #policy-spf unix - n n - - spawn 204 | # user=nobody argv=/usr/bin/policyd-spf 205 | # user=nobody argv=/usr/sbin/postfix-policyd-spf-perl 206 | #-------------------------------------------------------- 207 | 208 | 209 | #========================================================= 210 | # Postscreen protection 211 | #========================================================= 212 | postscreen_greet_action=enforce 213 | # Postscreen protections above require the /etc/postfix/master.cf options to be set 214 | # MASTER CF OPTIONS TO USE 215 | # COMMENT OUT BELOW LINE IN master.cf 216 | #smtp inet n - - - - smtpd 217 | # -o ... 218 | # UNCOMMENT THE BELOW LINES IN master.cf 219 | #smtpd pass - - n - - smtpd 220 | #smtp inet n - n - 1 postscreen 221 | #tlsproxy unix - - n - 0 tlsproxy 222 | #dnsblog unix - - n - 0 dnsblog 223 | #---------------------------------------------------------- 224 | -------------------------------------------------------------------------------- /semaphore_api_call.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ################################################################################################### 3 | # DESCRIPTION: # 4 | # This script was designed to be executed by a NagiosXI Event Handler to run Semaphore Tasks # 5 | # The tough thing about Nagios event handlers is using the correct host name value so it # 6 | # matches the inventory value. Modify line 84 in this script to make that work for you # 7 | # # 8 | # Company: OsbornePro LLC. # 9 | # Website: https://osbornepro.com # 10 | # Author: Robert H. Osborne # 11 | # Contact: rosborne@osbornepro.com # 12 | ################################################################################################### 13 | SEMAPHORE_SERVER_FQDN="semaphore.domain.com" 14 | USAGE=" 15 | #===============================================# 16 | # ___ _ ___ # 17 | # / _ \ __| |__ ___ _ _ _ _ ___| _ \_ _ ___ # 18 | # | (_) (_-< '_ \/ _ \ '_| ' \/ -_) _/ '_/ _ \ # 19 | # \___//__/_.__/\___/_| |_||_\___|_| |_| \___/ # 20 | #-----------------------------------------------# 21 | # If you can't beat 'em, tech 'em! # 22 | #===============================================# 23 | 24 | SYNTAX: 25 | $0 [-h] -H -P -T -t -s -d 26 | 27 | 28 | DESCRIPTION: 29 | This script is for executing Semaphore Tasks via Nagios Event Handlers 30 | 31 | REQUIREMENTS: 32 | 1.) You should have local Semaphore admin account credentials to authenticate to Semaphore 33 | 2.) Define $USER#$ variables in your /usr/local/nagios/etc/resource.cfg file containing the Sempahore username and password 34 | 3.) Create a command in Nagios that runs this script, passing along the $USER$ variables for the -A and -X parameters in this script 35 | $USER1$/check_ncpa.py 36 | 37 | CONTACT INFORMATION 38 | Company: Vinebrook Technology Inc. 39 | Website: https://www.vinebrooktechnology.com 40 | Author: Robert Osborne (Vinebrook Technology) 41 | Contact: rosborne@vinebrooktech.com 42 | 43 | 44 | USAGE: 45 | $0 [-h] -H -A USER31 -X USER32 -P -T -t -s -S SERVICESTATETYPE -a SERVICESTATE -o SERVICEOUTPUT -g HOSTGROUPNAMES -d 46 | 47 | OPTIONS: 48 | -h : Displays the help information for the command 49 | -H : The host address (usually passed from Nagios as \$HOSTADDRESS\$) 50 | -A : The user to auth with 51 | -X : The password to auth with 52 | -P : The project ID 53 | -T : The template ID 54 | -t : The target host 55 | -s : The service name 56 | -S : The service state type 57 | -a : The service state 58 | -o : The service output 59 | -g : The host group names 60 | -d : The drive letter 61 | 62 | 63 | EXAMPLES: 64 | $0 -h 65 | # This example returns the help information on how to use this command 66 | 67 | $0 -H 192.168.1.100 -P 1 -T 94 -t server01 -S HARD -a OK 68 | # This example runs task 94 in project 1 against target_host server01 69 | 70 | $0 -H 192.168.1.100 -P 1 -T 94 -t server01 -s wuauserv -S HARD -a DOWN 71 | # This example runs task 95 in project 1 against target_host server01 plugging in the variable name service_name with wuauserv 72 | 73 | $0 -H 192.168.1.100 -P 1 -T 94 -t server01 -d c -S SOFT -a WARNING 74 | # This example runs task 95 in project 1 against target_host server01 plugging in the variable name drive_letter with c 75 | 76 | " 77 | 78 | # Log file location 79 | LOG_FILE="/tmp/run-ansible-playbook.log" 80 | 81 | # File to temporarily store the session cookie 82 | COOKIE_FILE="/dev/shm/.semaphore-cookie" 83 | 84 | # Function to print help message 85 | function print_usage { 86 | /bin/printf "$USAGE\n" >&2 87 | exit 3 88 | } # End function print_usage 89 | 90 | # Function to log messages 91 | log_message() { 92 | /bin/echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE" 93 | } 94 | 95 | log_message "[-] Script execution started." 96 | 97 | # Parse command-line arguments 98 | while getopts "hH:A:X:P:T:t:s:S:a:o:g:d:" OPTION; do 99 | case $OPTION in 100 | h) 101 | print_usage 102 | ;; 103 | H) 104 | HOSTADDRESS="${OPTARG,,}" 105 | ;; 106 | A) 107 | AUTHUSERNAME="$OPTARG" 108 | ;; 109 | X) 110 | AUTHPASSWORD="$OPTARG" 111 | ESCAPED_PASSWORD=$(/bin/echo "${AUTHPASSWORD}" | /bin/sed 's/\\/\\\\/g') 112 | ;; 113 | P) 114 | PROJECT_ID="$OPTARG" 115 | ;; 116 | T) 117 | TEMPLATE_ID="${OPTARG}" 118 | ;; 119 | t) 120 | TARGET_HOST="${OPTARG%%.*}" 121 | TARGET_HOST="${TARGET_HOST,,}" 122 | ;; 123 | s) 124 | SERVICE_NAME="$OPTARG" 125 | ;; 126 | S) 127 | SERVICE_STATE_TYPE="$OPTARG" 128 | ;; 129 | a) 130 | SERVICE_STATE="$OPTARG" 131 | ;; 132 | o) 133 | SERVICE_OUTPUT="$OPTARG" 134 | ;; 135 | g) 136 | HOST_GROUP_NAMES="$OPTARG" 137 | ;; 138 | d) 139 | DRIVE_LETTER="$OPTARG" 140 | ;; 141 | *) 142 | print_usage 143 | ;; 144 | esac 145 | done 146 | 147 | # Set a default value for SERVICE_STATE_TYPE if not defined 148 | SERVICE_STATE_TYPE=${SERVICE_STATE_TYPE:-"UNDEFINED"} 149 | 150 | # Debug log to confirm value 151 | log_message "[-] SERVICE_STATE_TYPE is '${SERVICE_STATE_TYPE}'" 152 | 153 | # NEW: Exit early if the service state is OK 154 | if [ "${SERVICE_STATE,,}" == "ok" ]; then 155 | log_message "[-] Service state is OK. Exiting without triggering playbook." 156 | exit 0 157 | fi 158 | if [ "${SERVICE_STATE,,}" == "OK" ]; then 159 | log_message "[-] Service state is OK. Exiting without triggering playbook." 160 | exit 0 161 | fi 162 | 163 | # Conditional check 164 | if [ "$SERVICE_STATE_TYPE" != "HARD" ] && [ ${#SERVICE_STATE_TYPE} -lt 2 ]; then 165 | log_message "[-] Service state type is not HARD, not defined, or length is less than 2. Exiting task for ${TARGET_HOST}." 166 | exit 0 167 | fi 168 | 169 | log_message "[-] Received arguments: HOSTADDRESS=$HOSTADDRESS, PROJECT_ID=$PROJECT_ID, TEMPLATE_ID=$TEMPLATE_ID, TARGET_HOST=$TARGET_HOST, SERVICE_NAME=$SERVICE_NAME, DRIVE_LETTER=$DRIVE_LETTER" 170 | # Check if mandatory arguments are provided 171 | if [ -z "$HOSTADDRESS" ] || [ -z "$PROJECT_ID" ] || [ -z "$TEMPLATE_ID" ] || [ -z "$TARGET_HOST" ]; then 172 | log_message "[x] Required arguments are missing." 173 | print_usage 174 | fi 175 | 176 | # Determine template ID based on freshness and host group, only if SERVICE_OUTPUT, SERVICE_STATE_TYPE, and HOST_GROUP_NAMES are defined 177 | if [ -n "$SERVICE_OUTPUT" ] && [ -n "$SERVICE_STATE_TYPE" ] && [ -n "$HOST_GROUP_NAMES" ]; then 178 | if [[ "$SERVICE_STATE_TYPE" == "HARD" && "$SERVICE_OUTPUT" == *"No check result received"* ]]; then 179 | if [[ "${HOST_GROUP_NAMES,,}" == *"linux_servers"* ]]; then 180 | TEMPLATE_ID=19 181 | elif [[ "${HOST_GROUP_NAMES,,}" == *"windows-servers"* ]]; then 182 | TEMPLATE_ID=28 183 | else 184 | log_message "[x] Host group does not match expected groups (linux_servers or windows-servers). Exiting." 185 | exit 1 186 | fi 187 | log_message "[!] Freshness issue detected. Template ID set to $TEMPLATE_ID based on host group." 188 | else 189 | log_message "[-] No freshness issue detected or not a HARD state. Using provided template ID: $TEMPLATE_ID." 190 | fi 191 | else 192 | log_message "[-] SERVICE_OUTPUT, HOST_GROUP_NAMES, or SERVICE_STATE_TYPE not defined. Skipping freshness check." 193 | fi 194 | 195 | # Ensure TEMPLATE_ID is set 196 | if [ -z "$TEMPLATE_ID" ]; then 197 | log_message "[x] TEMPLATE_ID is not set after evaluating host group names. Exiting." 198 | exit 1 199 | fi 200 | 201 | # Semaphore API URLs 202 | SEMAPHORE_API_URL="https://${SEMAPHORE_SERVER_FQDN}/api" 203 | LOGIN_URL="${SEMAPHORE_API_URL}/auth/login" 204 | TOKENS_URL="${SEMAPHORE_API_URL}/user/tokens" 205 | TRIGGER_TASK_URL="${SEMAPHORE_API_URL}/project/${PROJECT_ID}/tasks" 206 | DELETE_TOKEN_URL="${SEMAPHORE_API_URL}/user/tokens" 207 | TASK_LIST_URL="${SEMAPHORE_API_URL}/project/${PROJECT_ID}/tasks" 208 | 209 | # Login to Semaphore and store the session cookie 210 | LOGIN_RESPONSE=$(/bin/curl -s -k -c "$COOKIE_FILE" -XPOST \ 211 | -H 'Content-Type: application/json' \ 212 | -H 'Accept: application/json' \ 213 | -d "{\"auth\": \"$AUTHUSERNAME\", \"password\": \"$ESCAPED_PASSWORD\"}" \ 214 | "$LOGIN_URL") 215 | 216 | if [ $? -ne 0 ]; then 217 | log_message "[x] Failed to log in to Semaphore. Response: $LOGIN_RESPONSE" 218 | exit 1 219 | else 220 | log_message "[-] Logged in to Semaphore successfully." 221 | fi 222 | 223 | # Check for jq dependency 224 | if ! command -v jq &>/dev/null; then 225 | log_message "[x] 'jq' command not found. Please install it to proceed." 226 | exit 1 227 | fi 228 | 229 | # Attempt to retrieve an existing token 230 | ACCESS_TOKEN="null" 231 | if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then 232 | # Generate a new token 233 | NEW_TOKEN_RESPONSE=$(/bin/curl -s -k -b "$COOKIE_FILE" -XPOST \ 234 | -H 'Content-Type: application/json' \ 235 | -H 'Accept: application/json' \ 236 | "$TOKENS_URL") 237 | 238 | ACCESS_TOKEN=$(/bin/echo "$NEW_TOKEN_RESPONSE" | /bin/jq -r '.id') 239 | if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then 240 | log_message "[x] Failed to generate a new access token." 241 | exit 1 242 | fi 243 | fi 244 | 245 | TASKS_RESPONSE=$(/bin/curl -s -k -H "Authorization: Bearer $ACCESS_TOKEN" "$TASK_LIST_URL") 246 | if [ $? -ne 0 ]; then 247 | log_message "[x] Failed to retrieve tasks from Semaphore." 248 | exit 1 249 | fi 250 | 251 | TASK_COUNT=$(/bin/echo "$TASKS_RESPONSE" | /bin/jq '[.[] | select(.status == "pending" or .status == "running")] | length') 252 | log_message "[-] Found $TASK_COUNT pending or running tasks." 253 | if [ "$TASK_COUNT" -ge 4 ]; then 254 | log_message "[!] Too many tasks currently running or pending ($TASK_COUNT). Skipping execution." 255 | /bin/echo "Too many Semaphore tasks currently in progress. Exiting without executing new task." 256 | exit 0 257 | fi 258 | 259 | MATCHING_TASK_COUNT=$(echo $TASKS_RESPONSE | jq --arg targethost "$TARGET_HOST" --argjson templateid "$TEMPLATE_ID" '[.[] | select(.template_id == $templateid) | select(.params.limit|index($targethost)) | select(.status|IN("running","waiting","pending","queued"))]|length') 260 | if [[ $MATCHING_TASK_COUNT -gt 0 ]]; then 261 | log_message "Found $MATCHING_TASK_COUNT running or pending task(s) matching this template and host. Skipping." 262 | exit 0 263 | fi 264 | 265 | # Construct JSON payload with required and optional parameters 266 | PAYLOAD="{\"template_id\": ${TEMPLATE_ID}, \"debug\": false, \"dry_run\": false, \"diff\": false, \"limit\": \"${TARGET_HOST}\", \"message\": \"Executed by Nagios Event Handler\"}" 267 | log_message "[-] Final payload constructed: ${PAYLOAD}" 268 | 269 | # Trigger the task in Semaphore 270 | TRIGGER_RESPONSE=$(/bin/curl -k -s -XPOST \ 271 | -H 'Content-Type: application/json' \ 272 | -H 'Accept: application/json' \ 273 | -H "Authorization: Bearer $ACCESS_TOKEN" \ 274 | -d "$PAYLOAD" \ 275 | "$TRIGGER_TASK_URL") 276 | 277 | if [ $? -ne 0 ]; then 278 | log_message "[x] Failed to trigger the task in Semaphore. Response: ${TRIGGER_RESPONSE}" 279 | exit 1 280 | else 281 | log_message "[-] Task triggered in Semaphore successfully. Response: ${TRIGGER_RESPONSE}" 282 | fi 283 | 284 | # Delete the access token after use 285 | DELETE_RESPONSE=$(/bin/curl -s -k -XDELETE \ 286 | -H 'Content-Type: application/json' \ 287 | -H 'Accept: application/json' \ 288 | -H "Authorization: Bearer $ACCESS_TOKEN" \ 289 | "$DELETE_TOKEN_URL/$ACCESS_TOKEN") 290 | 291 | if [ $? -ne 0 ]; then 292 | log_message "[x] Failed to delete the access token. Response: $DELETE_RESPONSE" 293 | else 294 | log_message "[-] Access token deleted successfully." 295 | fi 296 | 297 | # Clean up by removing the cookie file 298 | /bin/rm -rf "${COOKIE_FILE}" 299 | log_message "[-] Cookie file removed." 300 | 301 | log_message "[-] Script execution completed." 302 | -------------------------------------------------------------------------------- /2-ConfigureWindowsFTPS-ConfigureFTPoverSSLserver.ps1: -------------------------------------------------------------------------------- 1 | # This script is meant to be run on Windows Server 2019 where you want to set up an FTP over SSL Server 2 | # This script creates a directory for the FTPS Server that will be accessible for downloads by local users and uploads for admin users. 3 | # This does not create directories for the Active Directory users to use via FTP because this assumes that you have home drives in AD assigned for them to upload and download files. 4 | # The Home Drive directory values should be assigned in the CSV file for msIIS-FTPDir and msIIS-FTPRoot AD attribute values 5 | # 6 | # This script is used to install the FTP and IIS management tools on a Windows Server. Itf you grant consent it will create a local FTP user and group after you confirm it to do so. 7 | # This script will modify permissions on the FTP folder you define as well as create the folder if it does not exist. 8 | # This script will select the SSL cert to use if it has a friendly name containing FTP and enable 128-bit encryption. It also enables basic auth for users to sign in 9 | # This script confiures isolation mode with Active Directory and allows you to set the IP address and passive ports for the firewall 10 | 11 | 12 | $Logo = @" 13 | ╔═══╗░░╔╗░░░░░░░░░░░░╔═══╗░░░░░ 14 | ║╔═╗║░░║║░░░░░░░░░░░░║╔═╗║░░░░░ 15 | ║║░║╠══╣╚═╦══╦═╦═╗╔══╣╚═╝╠═╦══╗ 16 | ║║░║║══╣╔╗║╔╗║╔╣╔╗╣║═╣╔══╣╔╣╔╗║ 17 | ║╚═╝╠══║╚╝║╚╝║║║║║║║═╣║░░║║║╚╝║ 18 | ╚═══╩══╩══╩══╩╝╚╝╚╩══╩╝░░╚╝╚══╝ 19 | =============================== 20 | If you can't beat `em tech `em! 21 | =============================== 22 | https://osbornepro.com 23 | EMAIL: info@osbornepro.com 24 | "@ 25 | Write-Output "$Logo" 26 | 27 | Function Test-Admin { 28 | 29 | $CurrentUser = New-Object -TypeName Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent()) 30 | $CurrentUser.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) 31 | 32 | } # End Function Test-Admin 33 | 34 | If ((Test-Admin) -eq $False) { 35 | 36 | If ($Elevated) { 37 | 38 | Write-Output "[*] Tried to elevate, did not work, aborting" 39 | 40 | } Else { 41 | 42 | Start-Process -FilePath "C:\Windows\System32\powershell.exe" -Verb RunAs -ArgumentList ('-NoProfile -NoExit -File "{0}" -Elevated' -f ($myinvocation.MyCommand.Definition)) 43 | 44 | } # End If Else 45 | 46 | Exit 47 | 48 | } # End If 49 | 50 | Write-Output $Logo 51 | 52 | Write-Warning "The execution of this script assumes your server is a member of a domain and you are signed in with a member of the Domain Admins group" 53 | Read-Host -Prompt "Press ENTER to continue when ready" 54 | 55 | Write-Output "[*] Installing the Windows features for FTP" 56 | Install-WindowsFeature -Name Web-FTP-Server -IncludeManagementTools 57 | Install-WindowsFeature -Name Web-Server -IncludeAllSubFeature -IncludeManagementTools 58 | 59 | Write-Output "[*] Importing commands" 60 | Import-Module -Name WebAdministration -Global 61 | 62 | 63 | $ADFTPUser = Read-Host -Prompt "What is the name of the Active Directory group you created for FTP Users? EXAMPLE: FTP-Users" 64 | $ADUserPermission = Read-Host -Prompt "What permissions should $ADFTPUser group members have? [Read/Write/Read,Write]" 65 | $ADFTPAdmin = Read-Host -Prompt "What is the name of the Active Directory group you created for FTP Admins? EXAMPLE: FTP-Admins" 66 | $ADAdminPermission = Read-Host -Prompt "What permissions should $ADFTPAdmin group members have? [Read/Write/Read,Write]" 67 | $Server = "$env:COMPUTERNAME.$env:USERDNSDOMAIN" 68 | $FTPSiteName = Read-Host -Prompt "Enter a name for the FTP site that will appear in IIS Manager. EXAMPLE: OsbornePro FTPS" 69 | $FTPRootDir = Read-Host -Prompt "Enter the absoulte path to your FTP directory. Note that the directory you define will be created for you. EXAMPLE: C:\inetpub\FTP-Root" 70 | $Port = Read-Host -Prompt "Enter a port for the FTP Server to listen on EXAMPLE: 21" 71 | $FTPSitePath = "IIS:\Sites\$FTPSiteName" 72 | 73 | 74 | Write-Output "[*] Creating an allow firewall rule using the port you defined" 75 | New-NetFirewallRule -Name "Allow FTP Communication" -DisplayName "Allow FTP Communication" -Description 'Allows FTP Communication on port 21' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -Program Any -LocalAddress Any -LocalPort $Port 76 | 77 | 78 | Write-Output "[*] Creating the FTP directory at $FTPRootDir" 79 | New-Item -Path $FTPRootDir -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null 80 | 81 | Write-Output "[*] Creating FTP Site based on the info you provided" 82 | New-WebFtpSite -Name $FTPSiteName -Port $Port -PhysicalPath $FTPRootDir -Force 83 | 84 | 85 | $FTPGroupName = Read-Host -Prompt "What should the local FTP Users group name be? EXAMPLE: FTPUsers" 86 | Write-Output "[*] Creating the local FTP Group $FTPGroupName" 87 | 88 | If (!(Get-LocalGroup -Name $FTPGroupName -ErrorAction SilentlyContinue)) { 89 | 90 | New-LocalGroup -Name $FTPGroupName -Description "Members of this group can access the FTP server" 91 | 92 | } Else { 93 | 94 | Write-Output "[!] Group $FTPGroupName already exists. Skipping its creation" 95 | 96 | } # End Else 97 | 98 | $Ans = Read-Host -Prompt "[*] Would you like to create a local FTP user to access the server? [y/N]" 99 | If ($Ans -like "y*") { 100 | 101 | $LocalFTPUserName = Read-Host -Prompt "What should be the name of the Local FTP User account?" 102 | New-LocalUser -AccountNeverExpires -Description "Local FTP User account" -FullName "FTP User" -Disabled:$False -Password (Read-Host -Prompt "Enter a password for the local FTP User" -AsSecureString) -Name $LocalFTPUserName -UserMayNotChangePassword 103 | 104 | Add-LocalGroupMember -Group $FTPGroupName -Member $LocalFTPUserName 105 | 106 | } # End If 107 | 108 | Write-Output "[*] Adding Active Directory $ADFTPUser to the $FTPGroupName group" 109 | Add-LocalGroupMember -Group $FTPGroupName -Member $ADFTPUser 110 | 111 | 112 | Write-Output "[*] Adding authorization read write rule to the FTP site for $FTPGroupName" 113 | Add-WebConfiguration -Filter "/system.ftpServer/security/authorization" -Value @{accessType="Allow"; roles="$FTPGroupName";permissions="$ADUserPermission"} -PSPath 'IIS:\' -Location $FTPSiteName 114 | 115 | Write-Output "[*] Adding authorization rules to the FTP site for $ADUserPermission" 116 | Add-WebConfiguration -Filter "/system.ftpServer/security/authorization" -Value @{accessType="Allow"; roles="$ADFTPUser";permissions="$ADUserPermission"} -PSPath 'IIS:\' -Location $FTPSiteName 117 | 118 | Write-Output "[*] Adding authorization rules to the FTP site for $ADAdminPermission" 119 | Add-WebConfiguration -Filter "/system.ftpServer/security/authorization" -Value @{accessType="Allow"; roles="$ADFTPAdmin";permissions="$ADAdminPermission"} -PSPath 'IIS:\' -Location $FTPSiteName 120 | 121 | 122 | Write-Output "[*] Enabling Basic Authentication on FTP Site" 123 | Set-ItemProperty -Path $FTPSitePath -Name 'ftpServer.security.authentication.basicAuthentication.enabled' -Value $True 124 | 125 | 126 | If ((Get-ItemProperty -Path $FTPSitePath -Name 'ftpServer.security.ssl.controlChannelPolicy') -notlike 'SslRequire') { 127 | 128 | Write-Output "[*] Configuring SSL to be required" 129 | Set-ItemProperty -Path $FTPSitePath -Name 'ftpServer.security.ssl.controlChannelPolicy' -Value $True 130 | 131 | } # End If 132 | 133 | If ((Get-ItemProperty -Path $FTPSitePath -Name 'ftpServer.security.ssl.dataChannelPolicy') -notlike 'SslRequire') { 134 | 135 | Write-Output "[*] Configuring SSL to be required" 136 | Set-ItemProperty -Path $FTPSitePath -Name 'ftpServer.security.ssl.dataChannelPolicy' -Value $True 137 | 138 | } # End If 139 | 140 | If (Get-LocalGroup -Name $FTPGroupName) { 141 | 142 | Write-Output "[*] Setting permissions on $FTPRootDir" 143 | # USERS 144 | $LocalAccount = New-Object -TypeName System.Security.Principal.NTAccount("$FTPGroupName") 145 | $SystemAccount = New-Object -TypeName System.Security.Principal.NTAccount("SYSTEM") 146 | $AdminAccount = New-Object -TypeName System.Security.Principal.NTAccount("Administrators") 147 | 148 | # PERMISSIONS 149 | $Rights = [System.Security.AccessControl.FileSystemRights]"FullControl,Modify,ReadAndExecute,ListDirectory,Read,Write" 150 | $InheritanceFlag = @([System.Security.AccessControl.InheritanceFlags]::ContainerInherit,[System.Security.AccessControl.InheritanceFlags]::ObjectInherit) 151 | $PropagationFlag = [System.Security.AccessControl.PropagationFlags]::None 152 | $ObjType = [System.Security.AccessControl.AccessControlType]::Allow 153 | 154 | # SET OWNER AND ACCESS 155 | $ObjAce1 = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule($LocalAccount, $Rights, $InheritanceFlag, $PropagationFlag, $ObjType) 156 | $ACL = Get-Acl -Path $FTPRootDir 157 | $Acl.SetOwner($LocalAccount) 158 | $Acl.AddAccessRule($ObjAce1) 159 | $Acl.SetAccessRuleProtection($True, $False) 160 | Set-Acl -Path $FTPRootDir -AclObject $ACL 161 | $ACL.SetAccessRule($ObjAce1) 162 | 163 | Write-Output "[*] Adding SYSTEM user privileges to $FTPRootDir" 164 | $ObjAce2 = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule($SystemAccount, $Rights, $InheritanceFlag, $PropagationFlag, $ObjType) 165 | $ACL.SetAccessRule($ObjAce2) 166 | Set-Acl -Path $FTPRootDir -AclObject $ACL 167 | 168 | Write-Output "[*] Adding Administrators group privileges to $FTPRootDir" 169 | $ObjAce3 = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule($AdminAccount, $Rights, $InheritanceFlag, $PropagationFlag, $ObjType) 170 | $ACL.SetAccessRule($ObjAce3) 171 | Set-Acl -Path $FTPRootDir -AclObject $ACL 172 | 173 | } # End If 174 | 175 | Write-Output "[*] Setting User Isolation mode to Active Directory assigned" 176 | $BindUser = Read-Host -Prompt "Enter a username that can authenticate to AD and query LDAP" 177 | $BindPass = Read-Host -Prompt "Enter that users password" -AsSecureString 178 | 179 | Set-ItemProperty -Path $FTPSitePath -Name ftpServer.userIsolation.activeDirectory.adUserName -Value $BindUser 180 | Set-ItemProperty -Path $FTPSitePath -Name ftpServer.userIsolation.activeDirectory.adPassword -Value $BindPass 181 | Set-ItemProperty -Path $FTPSitePath -Name ftpserver.userisolation.mode -Value ActiveDirectory 182 | 183 | 184 | Get-ChildItem -Path Cert:\LocalMachine\My -Recurse | Select-Object -Property Subject,Issuer,Thumbprint,FriendlyName,NotAfter | Format-Table -AutoSize 185 | $Thumb = (Get-ChildItem -Path Cert:\LocalMachine -Recurse | Where-Object -Property FriendlyName -like "*FTP*")[0].Thumbprint.ToString() 186 | 187 | Write-Output "[*] The below certificate will be used for FTP over SSL communication unless otherwise defined. Above this line are some thumbprint options for you to select from" 188 | $Thumb 189 | 190 | $Thumbprint = Read-Host -Prompt "Enter the certificate thumbprint you want to use for the FTP over SSL instance. Leave blank and press ENTER if you wish to have this script find the certificate automatically by discovering a Local Machine cert in the Personal Store that has a friendly name containing `"*FTP*`"." 191 | If ($Thumbprint -eq "") { 192 | 193 | $Thumbprint = $Thumb 194 | 195 | } # End If 196 | 197 | Set-ItemProperty -Path $FTPSitePath -Name ftpServer.security.ssl.serverCertHash -Value $Thumbprint 198 | 199 | $Ansr = Read-Host -Prompt "Would you like to define the passive (PASV) ports to listen on? [y/N]" 200 | If ($Ansr -like "y*") { 201 | 202 | $V1 = Read-Host -Prompt "What should the lowest accepted port be? EXAMPLE: 40000" 203 | $V2 = Read-Host -Prompt "What should the highest accepted port be? EXAPMLE: 41000" 204 | 205 | Write-Output "[*] Configuring Minimum and Maximum port values for Data channel ports" 206 | Set-WebConfigurationProperty -PSPath IIS:\ -Filter system.ftpServer/firewallSupport -Name lowDataChannelPort -Value $V1 207 | Set-WebConfigurationProperty -PSPath IIS:\ -Filter system.ftpServer/firewallSupport -Name highDataChannelPort -Value $V2 208 | 209 | Write-Output "[*] Creating an allow firewall rule using the passive ports you defined" 210 | New-NetFirewallRule -Name "Allow FTP Passive Communication" -DisplayName "Allow FTP Passive Communication" -Description 'Allows FTP Passive Communication' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -Program Any -LocalAddress Any -LocalPort $V1-$V2 211 | 212 | Write-Output "[*] Setting IP Address for firewall to allow passive FTP connections from remote locations" 213 | $IPAddress = Read-Host -Prompt "What is the IP address you would like to for Passive connections allowing clients on the other side of a router to reach you? Leave blank to obtain the DHCP assigned private IP address automatically." 214 | If ($IPAddress -eq "") { 215 | 216 | $IPAddress = (Get-NetIPAddress -AddressFamily IPv4 -AddressState Preferred -PrefixOrigin Dhcp).IPAddress 217 | Set-ItemProperty -Path $FTPSitePath -Name ftpServer.firewallSupport.externalIp4Address -Value $IPAddress 218 | 219 | } # End If 220 | 221 | } # End If 222 | 223 | 224 | Write-Output "[*] Enabling 128-bit encryption" 225 | $ConfigPath = 'ftpServer.security.ssl' 226 | 227 | $SiteConfig = Get-ItemProperty -Path $FTPSitePath -Name $ConfigPath 228 | If ($SiteConfig.ssl128 -eq $False) { 229 | 230 | Set-ItemProperty -Path $FTPSitePath -Name "$ConfigPath.ssl128" -Value $True 231 | 232 | } # End If 233 | 234 | $A = Read-Host -Prompt "Would you like to add a virtual host name for your ftp site? [y/N]" 235 | If ($A -like "y*") { 236 | 237 | $VHost = Read-Host -Prompt "What should the virtual hostname be? EXAMPLE: ftp.domain.com" 238 | 239 | Write-Output "[*] Adding a custom web binding hostname" 240 | New-WebBinding -Name $FTPSiteName -Protocol ftp -HostHeader $VHost -Port $Port -SslFlags 1 241 | 242 | Write-Output "[*] Adding entry for $Vhost to your C:\Windows\System32\drivers\etc\hosts file" 243 | Add-Content -Path "C:\Windows\System32\drivers\etc\hosts" -Value "`n$IPAddress $VHost $Server $env:COMPUTERNAME`n" -Force 244 | 245 | } # End If 246 | 247 | 248 | Write-Output "[*] Restarting the FTP Site to load changes" 249 | Restart-WebItem -PSPath $FTPSitePath 250 | 251 | 252 | Write-Output "[*] Testing FTP port is open" 253 | Test-NetConnection -ComputerName "$env:COMPUTERNAME.$env:USERDNSDOMAIN" -Port $Port 254 | --------------------------------------------------------------------------------