The Brutus server is essentially any machine running Linux that has Portsentry installed.  In the case of our reference diagram, let’s assume we’ve made the Web server the Brutus server, and the EMail server the Client. You could of course make Brutus run on its own dedicated host as well. It’s helpful to install postfix on this machine so that you can receive emailed status reports.

On Ubuntu you can install Portsentry with “apt get portsentry”.

 The project home page is here at SourceForge: https://sourceforge.net/projects/sentrytools/

Once Portsentry has been installed, place this portsentry.conf file in /etc/portsentry .  This is what shapes Portsentry’s behavior and determines what to run in the event a port “touch” is detected. 

[pastacode lang=”bash” manual=”TCP_PORTS%3D%221%2C11%2C15%2C79%2C111%2C119%2C143%2C540%2C635%2C1080%2C1524%2C2000%2C5742%2C6667%2C12345%2C12346%2C20034%2C27665%2C31337%2C32771%2C32772%2C32773%2C32774%2C40421%2C49724%2C54320%22%0AUDP_PORTS%3D%221%2C7%2C9%2C69%2C161%2C162%2C513%2C635%2C640%2C641%2C700%2C37444%2C34555%2C31335%2C32770%2C32771%2C32772%2C32773%2C32774%2C31337%2C54321%22%0A%0AADVANCED_PORTS_TCP%3D%2265535%22%0AADVANCED_PORTS_UDP%3D%2265535%22%0AADVANCED_EXCLUDE_TCP%3D%2222%22%0AADVANCED_EXCLUDE_UDP%3D%22%22%0A%0AIGNORE_FILE%3D%22%2Fetc%2Fportsentry%2Fportsentry.ignore%22%0AHISTORY_FILE%3D%22%2Fetc%2Fportsentry%2Fportsentry.history%22%0ABLOCKED_FILE%3D%22%2Fetc%2Fportsentry%2Fportsentry.blocked%22%0A%0ARESOLVE_HOST%20%3D%20%220%22%0ASCAN_TRIGGER%20%3D%20%220%22%0AKILL_RUN_CMD_FIRST%20%3D%20%220%22%0A%0ABLOCK_UDP%3D%221%22%0ABLOCK_TCP%3D%221%22%0A%0A%23%20target%3Dsource%20IP%2C%20port%3Dtouch%20detected%20on%20this%20port%2C%20mode%3Datcp%2Ctcp%2Caudp%2Cudp%0A%23%20only%20target’s%20used%20for%20blocking%2C%20the%20rest%20is%20for%20logging%0AKILL_ROUTE%3D%22%2Fetc%2Fportsentry%2Finstructrouter.sh%20%24TARGET%24%20%24PORT%24%20%24MODE%24%22″ message=”portsentry.conf” highlight=”” provider=”manual”/]

In the /etc/portsentry folder, you can place this instructrouter.sh script.  The heart of Brutus, this is the script called by portsentry.conf above that instructs your firewall to null-route the offending external IP address (“null-route” means “the route to take to get to this IP is.. yourself.. there is no other route”, effectively dropping this IP in the trashcan.)

In order for the portsentry process to SSH into your firewall, you need to create a public-private keypair for the root account on your Brutus server.  You can do it with the commands at right. You don’t need a key larger than 1024 bits as it’s being used in an internal control channel. 

sudo su – 
ssh-keygen -t rsa -b 1024

In the /root/.ssh folder, copy the contents of id-rsa.pub to the Firewall’s admin user public key field, per the “Firewall” article instructions.

This script is also called via root’s crontab as per the string at right.

45 23 * * * /etc/portsentry/instructrouter.sh r

For firewalls other than PFSense, the command to actually execute the block will vary based on the operating system but you only have to test and change a single line (about line #89 in the * section).

[pastacode lang=”bash” manual=”%23!%2Fbin%2Fbash%0A%0A%23%20designed%20for%20PFSense%2C%20meant%20to%20work%20with%20apt%20package%20’portsentry’%0A%23%20this%20script%20works%20by%20placing%20hostile%20external%20IP’s%20into%20a%20null-route%20in%20the%20router’s%20manual%20table.%0A%23%20note%20that%20it’ll%20only%20block%20scanning%20%2F%20hostile%20IP’s%20externally%2C%20you%20can%20still%20reach%20them%0A%23%20%20%20%20%20%20%20from%20the%20inside%2C%20ie%2C%20the%20null-route%20is%20only%20effective%20for%20inbound%20requets%20to%20WAN%0A%0A%23%20target%3Dsource%20IP%2C%20port%3Dtouch%20detected%20on%20port%2C%20mode%3Datcp%2Ctcp%2Caudp%2Cudp%0A%23KILL_ROUTE%3D%22%2Fetc%2Fportsentry%2Finstructrouter.sh%20%24TARGET%24%20%24PORT%24%20%24MODE%24%22%0A%23%20note%20%3A%20root’s%20public%20key%20needs%20to%20be%20in%20pfsense%20user%20’admin’%0A%23%20%24hoursold%20%3D%20after%20these%20hours%2C%20unblock%20IP%20address%0A%23%20usage%3A%0A%23%20%20%20%20%20%20%20instructrouter.sh%20r%0A%23%20%20%20%20%20%20%20instructrouter.sh%201.2.3.4%0A%23%20updated%20100517%20to%20use%20routing%20table%20instead%20of%20reconstructing%20config.xml%2C%20infinitely%20superior%0A%23%20%20%20%20%20%20%20copy%20ssh%20key%20into%20pfsense%20admin%20account%0A%0Ahomedir%3D%2Fetc%2Fportsentry%0Ablocklog%3D%24homedir%2Fblocklog.log%0Acurdate%3D%24(date%20%2B%25m%25d%25y.%25H%25M%25S)%0Acurdateepoch%3D%24(date%20%2B%25s)%20%23%20epoch%20time%20used%20for%20numerical%20comparison%20to%20find%20old%20records%0Atmpfolder%3D%22%2Ftmp%2F%24(basename%20%240).%24%24%22%0Aremuser%3D%22root%22%20%23root%20is%20actually%20called%20admin%20on%20pfsense%0Afwrouter%3D192.168.1.1%0Abinlogger%3D%2Fusr%2Fbin%2Flogger%0Ahoursold%3D48%0Aalertemail%3D%22admin%40domain.com%22%0A%0Afunction%20statusis%20%7B%0A%20%20%20%20%20%20%20%20echo%20%22status%20%3A%20%241%22%0A%20%20%20%20%20%20%20%20%24binlogger%20-t%20PORTSENTRY%3A%20%241%0A%7D%0A%0Afunction%20mailout%20%7B%0A%20%20%20%20%20%20%20%20grep%20PORTSENTRY%20%2Ftmp%2Flog%2Fsyslog%20%7C%20tail%20-n10%20%3E%20%24tmpfolder%2Fsysout%0A%20%20%20%20%20%20%20%20mail%20-s%20BrutusError%20%24alertemail%20%3C%20%24tmpfolder%2Fsysout%0A%7D%0A%0Afunction%20traperr%20%7B%0A%20%20%20%20%20%20%20%20if%20%5B%20%24%3F%20-ne%200%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20errdata%3D%241%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20statusis%20%22Error%20found%2C%20%24errdata%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mailout%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20exit%201%0A%20%20%20%20%20%20%20%20fi%0A%7D%0A%0Afunction%20cleanup%20%7B%0A%20%20%20%20%20%20%20%20rm%20-rf%20%24tmpfolder%0A%7D%0A%0Amkdir%20%24tmpfolder%0Acase%20%241%20in%0A%20%20%20%20%20%20%20%20%22%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20echo%20%22Help%20%3A%20append%20with%20ip%20address%20to%20block%20or%20’r’%20to%20remove%20stale%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20statusis%20%22exiting%20due%20to%20null%20parameter%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mailout%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cleanup%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20exit%201%0A%20%20%20%20%20%20%20%20%3B%3B%0A%20%20%20%20%20%20%20%20r)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20%5B%20-n%20%22%242%22%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rmip%3D%22%242%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20remove%20the%20IP%20provided%20via%20command%20line%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ssh%20-f%20%24remuser%40%24fwrouter%20%22route%20del%20%24rmip%22%202%3E%261%20%3E%20%2Fdev%2Fnull%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cleanup%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20exit%200%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20%5B%20!%20-f%20%24blocklog%20%5D%20%7C%7C%20%5B%20-z%20%22%24(cat%20%24blocklog)%22%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20statusis%20%22Nothing%20in%20the%20blocklog%2C%20exiting%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20exit%200%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fi%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20figure%20out%20from%20%24blocklog%20which%20IP’s%20are%20more%20than%20%24hoursold%20and%20remove%20from%20fw%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20while%20read%20blockline%3B%20do%20%20%23blockline%20format%20%3A%20ip%20blockdate%20blockepoch%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20lesshrsold%3D%24(date%20–date%20%22now%20-%24hoursold%20hours%22%20%2B%25s)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20%5B%20%24(echo%20%24blockline%20%7C%20cut%20-d%20%22%20%22%20-f3)%20-lt%20%24lesshrsold%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rmip%3D%24(echo%20%24blockline%20%7C%20cut%20-d%20%22%20%22%20-f1)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20the%20-f%20is%20crucial%20lest%20the%20script%20abort%20after%20an%20ssh%20error%20if%20route%20missing%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ssh%20-f%20%24remuser%40%24fwrouter%20%22route%20del%20%24rmip%22%202%3E%261%20%3E%20%2Fdev%2Fnull%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fi%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20done%20%3C%20%24blocklog%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cleanup%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20exit%200%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fi%0A%20%20%20%20%20%20%20%20%3B%3B%0A%20%20%20%20%20%20%20%20*)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20iptoblock%3D%241%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ssh%20%24remuser%40%24fwrouter%20%22route%20add%20%24iptoblock%20127.0.0.1%20-blackhole%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20%5B%20%24%3F%20-ne%200%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20statusis%20%22can’t%20add%20IP%20to%20%24fwrouter%2C%20exiting%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20exit%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fi%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20echo%20%22%24iptoblock%20%24curdate%20%24curdateepoch%22%20%3E%3E%20%24blocklog%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cleanup%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20exit%200%0A%20%20%20%20%20%20%20%20%3B%3B%0Aesac” message=”instructrouter.sh” highlight=”” provider=”manual”/]

The fwreport.sh script can go in /etc/portsentry too.  This is executed by hand whenever you want to:

    a) confirm root’s key is working on the firewall, and 

    b) provide a current list of IP’s being blocked by Brutus.

 

[pastacode lang=”bash” manual=”%23!%2Fbin%2Fbash%0A%23%20This%20script%20intended%20to%20work%20with%20PFSense%0A%23%20the%20root%20user’s%20public%20key%20needs%20to%20be%20in%20the%20router’s%20authorized_keys%0A%23%20or%20assigned%20to%20the%20PFSense%20admin%20user%0A%0Aremuser%3D%22root%22%0Afwrouter%3D192.168.1.1%0A%0Aecho%20-n%20%22IP’s%20currently%20in%20FW%20table%3A%20%22%0Assh%20%24remuser%40%24fwrouter%20%22netstat%20-r%20-n%20%7C%20grep%20127.0.0.1%20%7C%20grep%20UGHSB%22%20%3E%20%2Ftmp%2Freporttmp%0Acat%20%2Ftmp%2Freporttmp%20%7C%20wc%20-l%0Acat%20%2Ftmp%2Freporttmp%0Arm%20%2Ftmp%2Freporttmp” message=”fwreport.sh” highlight=”” provider=”manual”/]

blockreport.sh is also placed in /etc/portsentry, and it’s executed via crontab every day at about 11:55p (before midnight) so as to email you with a daily status report.  It also performs some maintenance, purging records older than a few days.

Root’s crontab line looks like the command at right:

 47 23 * * * /etc/portsentry/blockreport.sh

[pastacode lang=”bash” manual=”%23!%2Fbin%2Fbash%0A%23%20generate%20report%20to%20show%20blocks%20within%20%24withinlast%20hours%0A%0Atmpfolder%3D%22%2Ftmp%2F%24(basename%20%240).%24%24%22%0Ahomedir%3D%2Fetc%2Fportsentry%0Ahistfile%3D%24homedir%2Fportsentry.history%0Awithinlast%3D24%0A%23%20think%20days%20you%20want%20%2B2%20including%20today%2C%20must%20be%201%20day%20greater%20than%20purge%20value%20in%20the%20manager%0Apurgeafterday%3D4%0Aemailto%3Dadmin%40domain.com%0A%0Amkdir%20%24tmpfolder%0A%0A%23truncate%20history%20file%20first%2C%20less%20to%20deal%20with%20overall%0Acat%20%24histfile%20%7C%20while%20read%20lineitem%3B%20do%0A%20%20%20%20%20%20%20%20if%20%5B%20%24(echo%20%22%24lineitem%22%20%7C%20awk%20’%7B%20print%20%241%20%7D’)%20-ge%20%24(date%20–date%20%22now%20-%24purgeafterday%20days%22%20%2B%25s)%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20echo%20%22%24lineitem%22%20%3E%3E%20%24tmpfolder%2Fkeeplist%0A%20%20%20%20%20%20%20%20fi%0Adone%0Amv%20%24tmpfolder%2Fkeeplist%20%24histfile%0A%0A%23from%20the%20cleaned%20up%20list%20extract%20current%20data%0Acat%20%24histfile%20%7C%20while%20read%20lineitem%3B%20do%0A%20%20%20%20%20%20%20%20if%20%5B%20%24(echo%20%22%24lineitem%22%20%7C%20awk%20’%7B%20print%20%241%20%7D’)%20-ge%20%24(date%20–date%20%22now%20-%24withinlast%20hours%22%20%2B%25s)%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20echo%20%22%24lineitem%22%20%3E%3E%20%24tmpfolder%2Flinelist%0A%20%20%20%20%20%20%20%20fi%0Adone%0A%0Alinecount%3D%24(cat%20%24tmpfolder%2Flinelist%20%7C%20wc%20-l)%0A%0A%23port%20statistics%0Acat%20%24tmpfolder%2Flinelist%20%7C%20awk%20’%7B%20print%20%248%20%7D’%20%3E%20%24tmpfolder%2Fportlist%0Acat%20%24tmpfolder%2Fportlist%20%7C%20sort%20%7C%20uniq%20%3E%20%24tmpfolder%2Funiqueports%0A%0Acat%20%24tmpfolder%2Funiqueports%20%7C%20while%20read%20lineitem%3B%20do%0A%20%20%20%20%20%20%20%20portcount%3D%24(cat%20%24tmpfolder%2Fportlist%20%7C%20grep%20%24lineitem%20%7C%20wc%20-l)%0A%20%20%20%20%20%20%20%20svcname%3D%22%24(grep%20-w%20%22%24lineitem%2Ftcp%22%20%2Fetc%2Fservices%20%7C%20awk%20’%7B%20print%20%241%20%7D’)%22%0A%20%20%20%20%20%20%20%20echo%20%22%24portcount%20%20%20%20%20%20%20%20%24lineitem%20%20%20%20%20%20%20%24svcname%22%20%3E%3E%20%24tmpfolder%2Fportout%0Adone%0A%0Aecho%20%22Count%20%20%20%20%20Port%20%20%20%20Service%20Name%22%20%3E%3E%20%24tmpfolder%2Fportreport%0Aecho%20%22——————————-%22%20%3E%3E%20%24tmpfolder%2Fportreport%0Acat%20%24tmpfolder%2Fportout%20%7C%20sort%20-nr%20%3E%3E%20%24tmpfolder%2Fportreport%0A%0Amail%20-s%20%22Brutus%20report%20-%20%24linecount%20IP’s%20blocked%22%20%24emailto%20%3C%20%24tmpfolder%2Fportreport%0A%0Arm%20-rf%20%24tmpfolder” message=”blockreport.sh” highlight=”” provider=”manual”/]

To test, google “online port scan”, you’ll see offerings by MXToolbox and others – use their services to scan your external IP address and watch your routing table (or run fwreport.sh) and you should see the source IP get dropped very quickly!

After all this is done, Portsentry is now able to instruct your firewall to drop inbound portscans automatically, resulting in a network that’s MUCH harder to map by attackers.

This is the heart of Brutus, you could be done if you have a home network with no servers or have a single server behind a firewall in your DMZ that provides service.  If you have more than one server you need to protect, proceed to the next article for Brutus client configuration.

Leave A Reply