Want to Autoban some special spammer

Use this forum if you have problems with a hMailServer script, such as hMailServer WebAdmin or code in an event handler.
Post Reply
Stoerkind
New user
New user
Posts: 3
Joined: 2019-01-09 05:26

Want to Autoban some special spammer

Post by Stoerkind » 2019-01-09 05:45

Hello together,

I'll try my best english to discribe my problem. :)

There some spammers trying to send mails from "abc@def.gh" to "abc@def.gh". The Server response is "530 - STMP Auth is required".

Now they try it about 1000 times in one hour and my logfiles getting bigger and bigger with this sh*t.

So I try to block them with the following code an another software to manage the repeating IP's.

Code: Select all

Sub OnAcceptMessage(oClient, oMessage) 

EventLog.Write ("TEST To:" & LCase(oMessage.Recipients(0).Address) & " - From: " & LCase(oMessage.FromAddress))

  if (LCase(oMessage.FromAddress) = LCase(oMessage.Recipients(0).Address)) then
    If (oClient.Username = "") Then
     EventLog.Write ("TEST - FAILED SENDER = RECIPIENT AND NOT LOGGED IN - " & LCase(oMessage.Recipients(0).Address))
      AutobanReason = "Local2Local without Login" 
      Call AutoBan(oClient.IPAddress, AutobanReason, 30, "n")
      Result.Message = "Greetings to the worlds best spammer"
      Result.Value = 2
    End If
  End If
A new entry in the logfile is not created when the error "530" is logged. Only when the mail is accepted from the server the code will run.

Same at

Code: Select all

Sub OnSmtpData(oClient, oMessage)
The oMessage Object is not present in

Code: Select all

Sub OnClientConnect(oClient)


Is there another subroutine where I can get oMessage when the server drops the connection with error "530"? I don't want to parse the awstats.log to get the IP's. :(

I'am very happy about any suggestions.

Greetings from Germany.

User avatar
mattg
Moderator
Moderator
Posts: 20026
Joined: 2007-06-14 05:12
Location: 'The Outback' Australia

Re: Want to Autoban some special spammer

Post by mattg » 2019-01-09 09:10

Stoerkind wrote:
2019-01-09 05:45
I don't want to parse the awstats.log to get the IP's. :(
That's what I do, parse the logs every 10 minutes
Just 'cause I link to a page and say little else doesn't mean I am not being nice.
https://www.hmailserver.com/documentation

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-09 14:32

I use MySQL and I created a new table in the hMailServer database.

If you use a different database you must change the ODBC connector accordingly.
ALSO... Check if strSQL = "INSERT IGNORE INTO...." is supported by your database. The functionality is essential in updating number of hits since field IPAddress is "UNIQUE".

The file "Handler.vbs" is run every 1 minute from Windows Scheduler.

Functionality is quite simple.

Eventhandlers.vbs;
1: Connection is checked if it is SMTP and an entry is put in the database.
2: If an email is received, the entry in the database is deleted.

Handler.vbs;
1: Check if any entries have 3 or more hits
2: If result is not older than 3 hours (180 minutes) since FIRST HIT; ban IP address for 7 days.
3: delete found entries.

NOTE: Function AutoBan is updated to return boolean value!.

Eventhandlers.vbs

Code: Select all

Option Explicit

'******************************************************************************************************************************
'********** Settings                                                                                                 **********
'******************************************************************************************************************************

'   COM authentication
Private Const ADMIN = "bla bla bla"
Private Const PASSWORD = "bla bla bla"

'******************************************************************************************************************************
'********** hMailServer IDS Client Code (MySQL)                                                                      **********
'******************************************************************************************************************************

Private Const idsTable = "hm_ids"

'   DRIVER={MySQL ODBC 5.3 Unicode Driver};Server=localhost;Port=3306;Database=%idsdb%;Uid=%idsuid%;Pwd=%idspwd%;Option=3;
'
'   Table:   CREATE TABLE %idsTable% (
'                   id        INTEGER       PRIMARY KEY AUTO_INCREMENT,
'                   timestamp DATETIME,
'                   ipaddress VARCHAR (192) UNIQUE,
'                   port      INTEGER,
'                   hits      INTEGER);

Function idsAddIP(sIPAddress, iPort)
   Dim strSQL, oDB : Set oDB = GetDatabaseObject
   strSQL = "INSERT IGNORE INTO " & idsTable & " (timestamp,ipaddress,port,hits) VALUES (NOW(),'" & sIPAddress & "'," & iPort & ",0);"
   Call oDB.ExecuteSQL(strSQL)
   strSQL = "UPDATE " & idsTable & " SET hits=(hits+1) WHERE IPAddress='" & sIPAddress & "';"
   Call oDB.ExecuteSQL(strSQL)
End Function

Function idsDelIP(sIPAddress)
   Dim strSQL, oDB : Set oDB = GetDatabaseObject
   strSQL = "DELETE FROM " & idsTable & " WHERE ipaddress = '" & sIPAddress & "';"
   Call oDB.ExecuteSQL(strSQL)
End Function

'******************************************************************************************************************************
'********** Functions                                                                                                **********
'******************************************************************************************************************************

Function GetDatabaseObject()
   Dim oApp : Set oApp = CreateObject("hMailServer.Application")
   Call oApp.Authenticate(ADMIN, PASSWORD)
   Set GetDatabaseObject = oApp.Database
End Function

'******************************************************************************************************************************
'********** hMailServer Triggers                                                                                     **********
'******************************************************************************************************************************

Sub OnClientConnect(oClient)
   '   Only test SMTP traffic
   If (InStr("|25|587|465|", oClient.Port) > 0) Then
      '   IDS test for SYN flood etc.
      Call idsAddIP(oClient.IPAddress, 0)
   End If
End Sub

Sub OnHELO(oClient)
End Sub

'   ********** SPAM test: DNSBlackLists, HeloHost, MXRecords, SPF

Sub OnSMTPData(oClient, oMessage)
End Sub

'   ********** SPAM test: SURBL, DKIM, SpamAssassin

Sub OnAcceptMessage(oClient, oMessage)
   '   Cleanup IDS registry
   Call idsDelIP(oClient.IPAddress)
End Sub

'   ********** Saving EML to DATA

' Sub OnDeliveryStart(oMessage)
' End Sub

'   ********** Antivirus check, Global rules

' Sub OnDeliverMessage(oMessage)
' End Sub

'   ********** Local rules, Message delivered to recipient(s)

' Sub OnDeliveryFailed(oMessage, sRecipient, sErrorMessage)
' End Sub

' Sub OnExternalAccountDownload(oFetchAccount, oMessage, sRemoteUID)
' End Sub

' Sub OnBackupFailed(sReason)
' End Sub

' Sub OnBackupCompleted()
' End Sub

' Sub OnError(iSeverity, iCode, sSource, sDescription)
' End Sub
Handler.vbs

Code: Select all

Option Explicit

'******************************************************************************************************************************
'********** Settings                                                                                                 **********
'******************************************************************************************************************************

'   COM authentication
Private Const ADMIN = "bla bla bla"
Private Const PASSWORD = "bla bla bla"

'   MySQL
Private Const idsDBDrv    = "DRIVER={MySQL ODBC 5.3 Unicode Driver};Database=hmailserver;Uid=bla bla bla;Pwd=bla bla bla;Option=3;"
Private Const idsTable    = "hm_ids"
Private Const idsHits     = 3
Private Const idsMinutes  = 180

'   DRIVER={MySQL ODBC 5.3 Unicode Driver};Server=localhost;Port=3306;Database=%idsdb%;Uid=%idsuid%;Pwd=%idspwd%;Option=3;
'
'   Table:   CREATE TABLE %idsTable% (
'                   id        INTEGER       PRIMARY KEY AUTO_INCREMENT,
'                   timestamp DATETIME,
'                   ipaddress VARCHAR (192) UNIQUE,
'                   port      INTEGER,
'                   hits      INTEGER);

'******************************************************************************************************************************
'********** Functions                                                                                                **********
'******************************************************************************************************************************

Function Wait(sec)
   With CreateObject("WScript.Shell")
      .Run "timeout /T " & Int(sec), 0, True
'     .Run "sleep -m " & Int(sec * 1000), 0, True
'     .Run "powershell Start-Sleep -Milliseconds " & Int(sec * 1000), 0, True
   End With
End Function

Function LockFile(strPath)
   Const Append = 8
   Const Unicode = -1
   With CreateObject("Scripting.FileSystemObject")
      Dim oFile, i
      For i = 0 To 30
         On Error Resume Next
         Set oFile = .OpenTextFile(strPath, Append, True, Unicode)
         If Not (Err.Number = 70) Then
            Set LockFile = oFile
            On Error Goto 0
            Exit For
         End If
         On Error Goto 0
         Wait(1)
      Next
   End With
   If (Err.Number = 70) Then
      EventLog.Write( "ERROR: BanJob.vbs" )
      EventLog.Write( "File " & strPath & " is locked and timeout was exceeded." )
      Err.Clear
   ElseIf (Err.Number <> 0) Then
      EventLog.Write( "ERROR: BanJob.vbs : Function LockFile" )
      EventLog.Write( "Error       : " & Err.Number )
      EventLog.Write( "Error (hex) : 0x" & Hex(Err.Number) )
      EventLog.Write( "Source      : " & Err.Source )
      EventLog.Write( "Description : " & Err.Description )
      Err.Clear
   End If
End Function

Function AutoBan(sIPAddress, sReason, iDuration, sType) : AutoBan = False
   '
   '   sType can be one of the following;
   '   "yyyy" Year, "m" Month, "d" Day, "h" Hour, "n" Minute, "s" Second
   '
   With LockFile("c:\hmailserver\temp\autoban.lck")
      On Error Resume Next
      oApp.Settings.SecurityRanges.Refresh
      If (oApp.Settings.SecurityRanges.ItemByName("(" & sReason & ") " & sIPAddress) Is Nothing) Then
         With oApp.Settings.SecurityRanges.Add
            .Name = "(" & sReason & ") " & sIPAddress
            .LowerIP = sIPAddress
            .UpperIP = sIPAddress
            .Priority = 20
            .Expires = True
            .ExpiresTime = DateAdd(sType, iDuration, Now())
            .Save
         End With
         AutoBan = True
      End If
      oApp.Settings.SecurityRanges.Refresh
      On Error Goto 0
      .Close
   End With
End Function

'******************************************************************************************************************************
'********** Code                                                                                                     **********
'******************************************************************************************************************************

Dim oApp : Set oApp = CreateObject("hMailServer.Application")
Call oApp.Authenticate(ADMIN, PASSWORD)
Dim EventLog : Set EventLog = CreateObject("hMailServer.EventLog")
Dim strPort
Dim oRecord, oConn : Set oConn = CreateObject("ADODB.Connection")
oConn.Open idsDBDrv
If oConn.State <> 1 Then
   EventLog.Write( "Handler - ERROR: Could not connect to database" )
   WScript.Quit 1
End If

Set oRecord = oConn.Execute("SELECT * FROM " & idsTable & " WHERE hits > " & idsHits & " AND port = 0;")
If Err.Number <> 0 Then
   EventLog.Write( "Handler - ERROR: Table " & idsTable & " does not exist!" )
   WScript.Quit 1
End If

If Not oRecord.BOF And Not oRecord.EOF Then
   While Not oRecord.EOF
      EventLog.Write( "Wohoo... IPAddress: " & oRecord("ipaddress") & " Port: " & oRecord("port") & " Hits: " & oRecord("hits") )
      If (DateDiff("n", oRecord("timestamp"), Now()) < idsMinutes) Then
         If AutoBan(oRecord("ipaddress"), "IDS", 7, "d") Then _
            EventLog.Write( "AutoBan(" & oRecord("ipaddress") & ", IDS, 7, d)" )
      End If
      oConn.Execute "DELETE FROM " & idsTable & " WHERE ipaddress = '" & oRecord("ipaddress") & "';"
      oRecord.MoveNext
   Wend
End If

WScript.Quit 0
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

Stoerkind
New user
New user
Posts: 3
Joined: 2019-01-09 05:26

Re: Want to Autoban some special spammer

Post by Stoerkind » 2019-01-10 03:01

Wow ... this seems to be a good idea.

I will try it this way and post the code here.

For me it make sense to make some small changes in the SQL-statements and in the table.

An "auto increment" or "indexed" field slows down the insert in a mysql table and it isn't necessary in this case.

Table:

Code: Select all

CREATE TABLE %idsTable% (
`Timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 ip INT(10) UNSIGNED NOT NULL);
Insert (No more Updates needed, just put the IP in the table):

Code: Select all

INSERT INTO `" & idsTable & "` (`ip`) VALUES (INET_ATON('" & sIPAddress & "'));
SELECT:

Code: Select all

SELECT 
INET_NTOA(IP) AS 'RemoteIP',
COUNT(IP) AS 'COUNTER' 
FROM " & idsTable & " 
WHERE IP = INET_ATON('" & sIPAddress & "')
GROUP BY IP
Cleanup (executed after all work is done to delete all records older than "idsHistoryDays" Days):

Code: Select all

DELETE FROM " & idsTable & " WHERE DATEDIFF(NOW(), " & idsTable & ".Timestamp) > " & idsHistoryDays & "
I think with this small SQL changes there will be less VB Code and it will run a little bit faster.

The Code isn't tested yet. I just write it down to discuss the idea. :)

User avatar
mattg
Moderator
Moderator
Posts: 20026
Joined: 2007-06-14 05:12
Location: 'The Outback' Australia

Re: Want to Autoban some special spammer

Post by mattg » 2019-01-10 03:09

IP needs to be varchar not int to match what is handed by BP, otherwise you will need to convert the string to int.

IP being a string allows IPv6 addresses
Just 'cause I link to a page and say little else doesn't mean I am not being nice.
https://www.hmailserver.com/documentation

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-10 03:56

Stoerkind wrote:
2019-01-10 03:01
Wow ... this seems to be a good idea.

I will try it this way and post the code here.

For me it make sense to make some small changes in the SQL-statements and in the table.

An "auto increment" or "indexed" field slows down the insert in a mysql table and it isn't necessary in this case.

Table:

Code: Select all

CREATE TABLE %idsTable% (
`Timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 ip INT(10) UNSIGNED NOT NULL);
Insert (No more Updates needed, just put the IP in the table):

Code: Select all

INSERT INTO `" & idsTable & "` (`ip`) VALUES (INET_ATON('" & sIPAddress & "'));
SELECT:

Code: Select all

SELECT 
INET_NTOA(IP) AS 'RemoteIP',
COUNT(IP) AS 'COUNTER' 
FROM " & idsTable & " 
WHERE IP = INET_ATON('" & sIPAddress & "')
GROUP BY IP
Cleanup (executed after all work is done to delete all records older than "idsHistoryDays" Days):

Code: Select all

DELETE FROM " & idsTable & " WHERE DATEDIFF(NOW(), " & idsTable & ".Timestamp) > " & idsHistoryDays & "
I think with this small SQL changes there will be less VB Code and it will run a little bit faster.

The Code isn't tested yet. I just write it down to discuss the idea. :)
Change COUNT(IP) to COUNT(*) to shave off some milliseconds. I'm still positive that my code is more effective than yours.
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

Stoerkind
New user
New user
Posts: 3
Joined: 2019-01-09 05:26

Re: Want to Autoban some special spammer

Post by Stoerkind » 2019-01-10 05:24

mattg wrote:
2019-01-10 03:09
IP needs to be varchar not int to match what is handed by BP, otherwise you will need to convert the string to int.

IP being a string allows IPv6 addresses
I forget the IPv6 support ... It will be better to use a VARBINARY(16) NOT NULL Field for the IP and INET6_ATON() / INET6_NTOA() for the convertion.
SorenR wrote:
2019-01-10 03:56
Change COUNT(IP) to COUNT(*) to shave off some milliseconds.
The Field 'IP' is defined as NOT NULL and has no KEY or INDEX defined.

COUNT(*) can use covering index - COUNT(Fieldname) doesn't.

Because I think the table does not have more than around 1000 records and with an index every insert is a little bit slower.

I have to test which way is faster.

Slower INSERT with KeyFields and faster COUNT()
or
Faster INSERT without Keyfields an slower COUNT()
SorenR wrote:
2019-01-10 03:56
I'm still positive that my code is more effective than yours.
As I wrote before my Code isn't tested or something. I just write it down to discuss the idea ... I like code optimization for memory usage and speed just for fun. :)
  • TIMESTAMP uses only half as much storage space than DATETIME
  • The storage for the IP as INT or VARBINARY(16) is much more efficient than storing it as VARCHAR.
  • I think the slower INSERT with a KEY defined has no effekt with VARBINARY(16). But I'm not sure for the moment. I'll check this later when I have more time. :)

User avatar
RvdH
Senior user
Senior user
Posts: 797
Joined: 2008-06-27 14:42
Location: Netherlands

Re: Want to Autoban some special spammer

Post by RvdH » 2019-01-11 00:37

Code: Select all

Function idsAddIP(sIPAddress, iPort)
   Dim strSQL, oDB : Set oDB = GetDatabaseObject
   strSQL = "INSERT IGNORE INTO " & idsTable & " (timestamp,ipaddress,port,hits) VALUES (NOW(),'" & sIPAddress & "'," & iPort & ",0);"
   Call oDB.ExecuteSQL(strSQL)
   strSQL = "UPDATE " & idsTable & " SET hits=(hits+1) WHERE IPAddress='" & sIPAddress & "';"
   Call oDB.ExecuteSQL(strSQL)
End Function
Isn't the proper way for MySQL to use 'ON DUPLICATE KEY' when inserting a record with a UNIQUE key that already exists?
I think you only need to Call oDB.ExecuteSQL() in above function once in that case
CIDR to RegEx: d-fault.nl/CIDRtoRegEx
DNS Lookup: d-fault.nl/DNSTools
DNSBL Lookup: d-fault.nl/DNSBLLookup
GEOIP Lookup: d-fault.nl/GeoipLookup

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-11 00:46

RvdH wrote:
2019-01-11 00:37

Code: Select all

Function idsAddIP(sIPAddress, iPort)
   Dim strSQL, oDB : Set oDB = GetDatabaseObject
   strSQL = "INSERT IGNORE INTO " & idsTable & " (timestamp,ipaddress,port,hits) VALUES (NOW(),'" & sIPAddress & "'," & iPort & ",0);"
   Call oDB.ExecuteSQL(strSQL)
   strSQL = "UPDATE " & idsTable & " SET hits=(hits+1) WHERE IPAddress='" & sIPAddress & "';"
   Call oDB.ExecuteSQL(strSQL)
End Function
Isn't the proper way for MySQL to use 'ON DUPLICATE KEY' when inserting a record with a UNIQUE key that already exists?
I think you only need to Call oDB.ExecuteSQL() in above function once in that case
By using INSERT IGNORE (ignore if unique constraint is violated) and then UPDATE I do not have to check for existance. I don't even have to check for a fault code 8) Code optimization :idea:

Take that! Mugglers! :mrgreen:

http://www.mysqltutorial.org/mysql-insert-ignore/
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

User avatar
RvdH
Senior user
Senior user
Posts: 797
Joined: 2008-06-27 14:42
Location: Netherlands

Re: Want to Autoban some special spammer

Post by RvdH » 2019-01-11 00:56

How is Calling oDB.ExecuteSQL(strSQL) 2 times, code optimization?

Code: Select all

Function idsAddIP(sIPAddress, iPort)
   Dim strSQL, oDB : Set oDB = GetDatabaseObject
   strSQL = "INSERT INTO " & idsTable & " (timestamp,ipaddress,port,hits) VALUES (NOW(),'" & sIPAddress & "'," & iPort & ",0) ON DUPLICATE KEY UPDATE hits=(hits+1);
   Call oDB.ExecuteSQL(strSQL)
End Function
Above code, not tested...but out of my head it works something like that
CIDR to RegEx: d-fault.nl/CIDRtoRegEx
DNS Lookup: d-fault.nl/DNSTools
DNSBL Lookup: d-fault.nl/DNSBLLookup
GEOIP Lookup: d-fault.nl/GeoipLookup

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-11 01:01

RvdH wrote:
2019-01-11 00:56
How is Calling oDB.ExecuteSQL(strSQL) 2 times, code optimization?

Code: Select all

Function idsAddIP(sIPAddress, iPort)
   Dim strSQL, oDB : Set oDB = GetDatabaseObject
   strSQL = "INSERT INTO " & idsTable & " (timestamp,ipaddress,port,hits) VALUES (NOW(),'" & sIPAddress & "'," & iPort & ",0) ON DUPLICATE KEY UPDATE hits=(hits+1);
   Call oDB.ExecuteSQL(strSQL)
End Function
Above code, not tested...but out of my head it works something like that
Yeah... I'll have to eat my hat on this... I stand corrected... Nice move :mrgreen:

hits = 1 on initial insert.

Code: Select all

Function idsAddIP(sIPAddress, iPort)
   Dim strSQL, oDB : Set oDB = GetDatabaseObject
   strSQL = "INSERT INTO " & idsTable & " (timestamp,ipaddress,port,hits) VALUES (NOW(),'" & sIPAddress & "'," & iPort & ",1) ON DUPLICATE KEY UPDATE hits=(hits+1);
   Call oDB.ExecuteSQL(strSQL)
End Function
Erhmmm.... PRIMARY KEY should be ipaddress I believe. Hmm... Table one modify must.
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-11 01:16

SorenR wrote:
2019-01-11 01:01
Erhmmm.... PRIMARY KEY should be ipaddress I believe. Hmm... Table one modify must.
Nope... It works as intended.
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

User avatar
RvdH
Senior user
Senior user
Posts: 797
Joined: 2008-06-27 14:42
Location: Netherlands

Re: Want to Autoban some special spammer

Post by RvdH » 2019-01-11 11:56

@SorenR
Your IDS code only should be used if greylisting is disabled, right? Might be worth to mention that in the instructions

As with greylisting enabled en frequent retries the IDS entries popup like mushrooms :lol:
CIDR to RegEx: d-fault.nl/CIDRtoRegEx
DNS Lookup: d-fault.nl/DNSTools
DNSBL Lookup: d-fault.nl/DNSBLLookup
GEOIP Lookup: d-fault.nl/GeoipLookup

User avatar
RvdH
Senior user
Senior user
Posts: 797
Joined: 2008-06-27 14:42
Location: Netherlands

Re: Want to Autoban some special spammer

Post by RvdH » 2019-01-11 12:21

Shouldn't this:

Code: Select all

Sub OnClientConnect(oClient)
   '   Only test SMTP traffic
   If (InStr("|25|587|465|", oClient.Port) > 0) Then
      '   IDS test for SYN flood etc.
      Call idsAddIP(oClient.IPAddress, 0)
   End If
End Sub
Be:

Code: Select all

Sub OnClientConnect(oClient)
   '   Only test SMTP traffic
   If (InStr("|25|587|465|", oClient.Port) > 0) Then
      '   IDS test for SYN flood etc.
      Call idsAddIP(oClient.IPAddress, oClient.Port)
   End If
End Sub
Otherwise all DB entries are listed with port 0, or is this done for a specific reason as i noticed you use port 0 elsewhere as well

Code: Select all

Set oRecord = oConn.Execute("SELECT * FROM " & idsTable & " WHERE hits > " & idsHits & " AND port = 0;")
Which makes the Port column in DB obsolete, isn't?
CIDR to RegEx: d-fault.nl/CIDRtoRegEx
DNS Lookup: d-fault.nl/DNSTools
DNSBL Lookup: d-fault.nl/DNSBLLookup
GEOIP Lookup: d-fault.nl/GeoipLookup

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-11 13:16

I also have this in my Eventhandlers...

Any connection from outside the The Danish Realm on any port other than 25 is nuked. That's what I use the "port" variable for.

Roaming is usually expensive (when you exceed your allowed data) and when on holiday you don't need a phone - I have webmail if the urge to read mail suddenly arises :mrgreen:

Code: Select all

   '   Exclude Backup-MX array & local LAN from test
   If (Left(oClient.IPAddress, 10) = "80.160.77.") Then Exit Sub
   If (Left(oClient.IPAddress, 10) = "192.168.0.") Then Exit Sub

   '   Only allow non-SMTP connect from "Rigsfællesskabet"/"Naalagaaffeqatigiit"/"Ríkisfelagsskapurin" = The Danish Realm.
   '   000 = N/A, 208 = Denmark, 304 = Greenland, 234 = Faroe Islands
   If (oClient.Port <> 25) Then
      If (InStr("|208|304|234|", NerdLookup(oClient.IPAddress)) = 0) Then
         Call idsAddIP(oClient.IPAddress, oClient.Port)
         Result.Value = 1
         Exit Sub
      End If
   End If
This is the full Handler.vbs code - I've removed the session locking from AutoBan since there is only one instance of Handler.vbs

Code: Select all

Option Explicit

'******************************************************************************************************************************
'********** Settings                                                                                                 **********
'******************************************************************************************************************************

'   COM authentication
Private Const ADMIN = "bla bla bla"
Private Const PASSWORD = "bla bla bla"

'   MySQL
Private Const idsDBDrv    = "DRIVER={MySQL ODBC 5.3 Unicode Driver};Database=hmailserver;Uid=bla bla bla;Pwd=bla bla bla;Option=3;"
Private Const idsTable    = "hm_ids"
Private Const idsHits     = 3
Private Const idsMinutes  = 180

'   DRIVER={MySQL ODBC 5.3 Unicode Driver};Server=localhost;Port=3306;Database=%idsdb%;Uid=%idsuid%;Pwd=%idspwd%;Option=3;
'
'   Table:   CREATE TABLE %idsTable% (
'                   timestamp DATETIME,
'                   ipaddress VARCHAR (192) PRIMARY KEY,
'                   port      INTEGER,
'                   hits      INTEGER);

'******************************************************************************************************************************
'********** Functions                                                                                                **********
'******************************************************************************************************************************

Function AutoBan(sIPAddress, sReason, iDuration, sType) : AutoBan = False
   '
   '   sType can be one of the following;
   '   "yyyy" Year, "m" Month, "d" Day, "h" Hour, "n" Minute, "s" Second
   '
   On Error Resume Next
   If (oApp.Settings.SecurityRanges.ItemByName("(" & sReason & ") " & sIPAddress) Is Nothing) Then
      With oApp.Settings.SecurityRanges.Add
         .Name = "(" & sReason & ") " & sIPAddress
         .LowerIP = sIPAddress
         .UpperIP = sIPAddress
         .Priority = 20
         .Expires = True
         .ExpiresTime = DateAdd(sType, iDuration, Now())
         .Save
      End With
      AutoBan = True
   End If
   On Error Goto 0
End Function

'******************************************************************************************************************************
'********** Code                                                                                                     **********
'******************************************************************************************************************************

Dim oApp : Set oApp = CreateObject("hMailServer.Application")
Call oApp.Authenticate(ADMIN, PASSWORD)
Dim EventLog : Set EventLog = CreateObject("hMailServer.EventLog")
Dim strPort
Dim oRecord, oConn : Set oConn = CreateObject("ADODB.Connection")
oConn.Open idsDBDrv
If oConn.State <> 1 Then
   EventLog.Write( "Handler - ERROR: Could not connect to database" )
   WScript.Quit 1
End If

Set oRecord = oConn.Execute("SELECT * FROM " & idsTable & " WHERE hits > " & idsHits & " AND port = 0;")
If Err.Number <> 0 Then
   EventLog.Write( "Handler - ERROR: Table " & idsTable & " does not exist!" )
   WScript.Quit 1
End If

If Not oRecord.BOF And Not oRecord.EOF Then
   While Not oRecord.EOF
      EventLog.Write( "Wohoo... IPAddress: " & oRecord("ipaddress") & " Port: " & oRecord("port") & " Hits: " & oRecord("hits") )
      If (DateDiff("n", oRecord("timestamp"), Now()) < idsMinutes) Then
         If AutoBan(oRecord("ipaddress"), "IDS", 7, "d") Then _
            EventLog.Write( "AutoBan(" & oRecord("ipaddress") & ", IDS, 7, d)" )
      End If
      oConn.Execute "DELETE FROM " & idsTable & " WHERE ipaddress = '" & oRecord("ipaddress") & "';"
      oRecord.MoveNext
   Wend
End If

Set oRecord = oConn.Execute("SELECT * FROM " & idsTable & " WHERE hits > " & idsHits & " AND port > 0;")

If Not oRecord.BOF And Not oRecord.EOF Then
   While Not oRecord.EOF
      EventLog.Write( "Wohoo... IPAddress: " & oRecord("ipaddress") & " Port: " & oRecord("port") & " Hits: " & oRecord("hits") )
      If (DateDiff("n", oRecord("timestamp"), Now()) < idsMinutes) Then
         strPort = Trim(Mid("SMTP IMAP SMTPSSUBM IMAPS", InStr("25   143  465  587  993  ", oRecord("port")), 5))
         If AutoBan(oRecord("ipaddress"), "PORTBLOCK - " & strPort, 7, "d") Then _
            EventLog.Write( "AutoBan(" & oRecord("ipaddress") & ", PORTBLOCK - " & strPort & ", 7, d)" )
      End If
      oConn.Execute "DELETE FROM " & idsTable & " WHERE ipaddress = '" & oRecord("ipaddress") & "';"
      oRecord.MoveNext
   Wend
End If

oConn.Close

WScript.Quit 0
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

User avatar
RvdH
Senior user
Senior user
Posts: 797
Joined: 2008-06-27 14:42
Location: Netherlands

Re: Want to Autoban some special spammer

Post by RvdH » 2019-01-11 13:48

Mmm, OK i see
But why allow 3 attempts (using the IDS code) on any port other then port 25?

I block those instantly

Code: Select all

Dim strRegEx : strRegEx = "^(nl|be|eu|zz)$"
If (oClient.Port <> 25) Then
	If Not Lookup(strRegEx, NerdLookup(oClient.IPAddress)) Then
		' countries.nerd.dk 
		Call AutoBan(oClient.IPAddress, "countries.nerd.dk (" & oClient.Port & ")", 1, "ww")
		Result.Value = 1
		Exit Sub
	End If
End If
BTW, if you do a TXT lookup against zz.countries.nerd.dk you don't have to work with those annoying ISO 3166-1 alpha-3 codes

Code: Select all

Function NerdLookup(strIP)
	Dim a, x
	a = Split(strIP, ".")
	dim countryCode : countryCode = Empty
	dim countryCodeAlt : countryCodeAlt = "zz"
	On Error Resume Next
	With CreateObject("DNSLibrary.DNSResolver")
		strIP = .TXT(a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".zz.countries.nerd.dk")
	End With
	If Err.Number<>0 then
		EventLog.Write(a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".zz.countries.nerd.dk")
		Err.Clear
	End if
	On Error Goto 0
	a=Split(strIP ,VbCrLf)
	For x = 0 To (UBound(a) - LBound(a))
		If Len(a(x)) > 0 then
			if a(x) <> "eu" then 
				countryCode = a(x)
			else
				countryCodeAlt = a(x)		
			end if
		end if
	Next
	If Len(countryCode) > 0 then
		NerdLookup = countryCode
	Else
		NerdLookup = countryCodeAlt
	End if
End Function
CIDR to RegEx: d-fault.nl/CIDRtoRegEx
DNS Lookup: d-fault.nl/DNSTools
DNSBL Lookup: d-fault.nl/DNSBLLookup
GEOIP Lookup: d-fault.nl/GeoipLookup

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-11 14:20

A while back I was going over some old logs (from 2011 to now) and found that probably 80% of all "unwanted" connections from the same IP happen probably 1-2 times a week - no point in waisting a BAN on those - all you do is fill up your BAN list and it slows the server down for no reason.

So... If I were probing for a password or attacking a server I would go full power, not send one probe every 1 hour - it would take for ever.

That is the reason for allowing 3 attempts in 3 hours.
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-11 16:10

RvdH wrote:
2019-01-11 13:48
BTW, if you do a TXT lookup against zz.countries.nerd.dk you don't have to work with those annoying ISO 3166-1 alpha-3 codes
Any particular reason for the "On Error Resume Next", "On Error Goto 0" around your object :?:

Downsized your function to this...

Code: Select all

Function NerdLookup(strIP) : NerdLookup = "zz"
   Dim a
   a = Split(strIP, ".")
   With CreateObject("DNSLibrary.DNSResolver")
      strIP = .TXT(a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".zz.countries.nerd.dk")
   End With
   If strIP <> "" Then NerdLookup = strIP
End Function
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

User avatar
RvdH
Senior user
Senior user
Posts: 797
Joined: 2008-06-27 14:42
Location: Netherlands

Re: Want to Autoban some special spammer

Post by RvdH » 2019-01-11 17:36

No, not really...probably used that On Error Resume Next when debugging

zz.countries.nerd.dk sometimes returns 2 TXT records, for example 'eu' and 'nl' for a single ip, as i prefer to allow the 'nl' and not the 'eu' i added that countryCodeAlt to filter out those duplicates,

example:
viewtopic.php?p=196614#p196614 (that IP returns just a single countrycode now, but this was different before)
CIDR to RegEx: d-fault.nl/CIDRtoRegEx
DNS Lookup: d-fault.nl/DNSTools
DNSBL Lookup: d-fault.nl/DNSBLLookup
GEOIP Lookup: d-fault.nl/GeoipLookup

User avatar
RvdH
Senior user
Senior user
Posts: 797
Joined: 2008-06-27 14:42
Location: Netherlands

Re: Want to Autoban some special spammer

Post by RvdH » 2019-01-11 18:17

Another example:

Code: Select all

dig +short 180.227.49.37.zz.countries.nerd.dk TXT
"is"
"ee"
CIDR to RegEx: d-fault.nl/CIDRtoRegEx
DNS Lookup: d-fault.nl/DNSTools
DNSBL Lookup: d-fault.nl/DNSBLLookup
GEOIP Lookup: d-fault.nl/GeoipLookup

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-11 18:56

RvdH wrote:
2019-01-11 18:17
Another example:

Code: Select all

dig +short 180.227.49.37.zz.countries.nerd.dk TXT
"is"
"ee"
That's a bug... The IP address belongs to Iceland.

Get your own copy ... :mrgreen:

Code: Select all

mkdir -p rsync/dg
rsync -a rsync://countries-ns.mdc.dk/zone/ rsync
cat rsync/zz.countries.nerd.dk.rbldnsd zz.countries.nerd.dk.rbldnsd.add > rsync/dg/zz.countries.nerd.dk.rbldnsd
In BIND format as a unified zone: rsync://***/countries.nerd.dk.bind,
In RBLDNSD formats as seperate zones: rsync://***/*.countries.nerd.dk.rbldnsd
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

User avatar
RvdH
Senior user
Senior user
Posts: 797
Joined: 2008-06-27 14:42
Location: Netherlands

Re: Want to Autoban some special spammer

Post by RvdH » 2019-01-11 22:22

SorenR wrote:
2019-01-11 18:56
RvdH wrote:
2019-01-11 18:17
Another example:

Code: Select all

dig +short 180.227.49.37.zz.countries.nerd.dk TXT
"is"
"ee"
That's a bug... The IP address belongs to Iceland.

Get your own copy ... :mrgreen:

Code: Select all

mkdir -p rsync/dg
rsync -a rsync://countries-ns.mdc.dk/zone/ rsync
cat rsync/zz.countries.nerd.dk.rbldnsd zz.countries.nerd.dk.rbldnsd.add > rsync/dg/zz.countries.nerd.dk.rbldnsd
In BIND format as a unified zone: rsync://***/countries.nerd.dk.bind,
In RBLDNSD formats as seperate zones: rsync://***/*.countries.nerd.dk.rbldnsd
https://d-fault.nl/GeoipLookup?q=37.49.227.180
Different lookups, different opinions...

I'll stick with the code below, it works for me...and i do not wan't to maintain a zone file

Code: Select all

Function NerdLookup(strIP) : NerdLookup = "zz"
	Dim a : a = Split(strIP,".")
	With CreateObject("DNSLibrary.DNSResolver")
	  strIP = .TXT(a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".zz.countries.nerd.dk")
	End With
	a = Split(strIP,VbCrLf)
	For x = 0 To (UBound(a) - LBound(a))
		If a(x) <> "" then
			If a(x) <> "eu" then 
				NerdLookup = a(x)
				Exit function
			Else
				NerdLookup = a(x)	
			End if
		End if
	Next
End Function
CIDR to RegEx: d-fault.nl/CIDRtoRegEx
DNS Lookup: d-fault.nl/DNSTools
DNSBL Lookup: d-fault.nl/DNSBLLookup
GEOIP Lookup: d-fault.nl/GeoipLookup

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-11 22:31

Code: Select all

01/11/19 21:30:16 whois 37.49.227.180 @whois.geektools.com

whois -h whois.geektools.com 37.49.227.180  ...
GeekTools Whois Proxy v5.0.6 Ready.

Checking access for 87.51.72.165... ok.

Final results obtained from whois.ripe.net.

Results:
% This is the RIPE Database query service.
% The objects are in RPSL format.
%
% The RIPE Database is subject to Terms and Conditions.
% See http://www.ripe.net/db/support/db-terms-conditions.pdf

% Note: this output has been filtered.
%       To receive output for a database update, use the &quot;-B&quot; flag.

% Information related to &#39;37.49.227.0 - 37.49.227.255&#39;

% Abuse contact for &#39;37.49.227.0 - 37.49.227.255&#39; is &#39;abuse@cloudstar.is&#39;

inetnum:        37.49.227.0 - 37.49.227.255
netname:        CLOUDSTAR-NL-SR-VPS-02
descr:          CLOUD STAR HOSTING SERVICES
country:        IS
geoloc:         64.1455726 -21.92757419999998
admin-c:        SS27964-RIPE
tech-c:         SS27964-RIPE
org:            ORG-CSHS2-RIPE
status:         ASSIGNED PA
mnt-by:         CLOUDSTAR-MNT
mnt-domains:    CLOUDSTAR-MNT
mnt-routes:     CLOUDSTAR-MNT
remarks:        Send all abuse complaints to abuse@cloudstar.is
created:        2018-10-04T15:52:59Z
last-modified:  2018-10-04T15:52:59Z
source:         RIPE

organisation:   ORG-CSHS2-RIPE
org-name:       CLOUD STAR HOSTING SERVICES
org-type:       OTHER
address:        29 Laugavegur Reykjavik Iceland 101
abuse-c:        CSHS1-RIPE
mnt-ref:        CLOUDSTAR-MNT
mnt-by:         CLOUDSTAR-MNT
created:        2015-08-16T15:08:21Z
last-modified:  2018-02-20T06:28:56Z
source:         RIPE # Filtered

person:         Steinn Sighvatsson
address:        29 Laugavegur Reykjavik Iceland 101
phone:          +3544584448
nic-hdl:        SS27964-RIPE
mnt-by:         CLOUDSTAR-MNT
created:        2015-08-16T15:02:33Z
last-modified:  2018-02-26T16:17:11Z
source:         RIPE # Filtered

% Information related to &#39;37.49.227.0/24AS199264&#39;

route:          37.49.227.0/24
descr:          CLOUD STAR HOSTING SERVICES
origin:         AS199264
mnt-by:         ESTOXY-MNT
created:        2018-10-04T16:17:09Z
last-modified:  2018-10-04T16:17:09Z
source:         RIPE

% This query was served by the RIPE Database Query Service version 1.92.6 (BLAARKOP)
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.


User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-12 16:05

Well Ruud,

It seems as those pesky ISO 3166-1 alpha-3 IS the way to go. I reconfigured my system before I went to bed this morning and this is what I got... The "old" NerdLookup() is calling the "new" NerdLookupTXT() in order to get both solutions.

Code: Select all

1568		"2019-01-12 04:23:23.247"	"NerdLookup(89.248.167.131) = 127.0.2.178"
1568		"2019-01-12 04:23:23.247"	"NerdLookup(89.248.167.131) = 690"
1568		"2019-01-12 04:23:23.293"	"NerdLookup(89.248.167.131) = |nl|sc|"
         https://whatsmyip.com/ip-trace/89.248.167.131 = Seychelles

3828		"2019-01-12 08:57:26.806"	"NerdLookup(185.222.209.40) = 127.0.2.16"
3828		"2019-01-12 08:57:26.806"	"NerdLookup(185.222.209.40) = 528"
3828		"2019-01-12 08:57:26.868"	"NerdLookup(185.222.209.40) = |uk|nl|"
         https://whatsmyip.com/ip-trace/185.222.209.40 = UK

2900		"2019-01-12 08:57:42.915"	"NerdLookup(185.222.209.40) = 127.0.2.16"
2900		"2019-01-12 08:57:42.915"	"NerdLookup(185.222.209.40) = 528"
2900		"2019-01-12 08:57:42.930"	"NerdLookup(185.222.209.40) = |nl|uk|"
         https://whatsmyip.com/ip-trace/185.222.209.40 = UK

1568		"2019-01-12 14:13:05.868"	"NerdLookup(198.108.66.80) = "
1568		"2019-01-12 14:13:05.868"	"NerdLookup(198.108.66.80) = 000"
1568		"2019-01-12 14:13:05.962"	"NerdLookup(198.108.66.80) = |us|"
         https://whatsmyip.com/ip-trace/198.108.66.80 = USA

Function NerdLookup(strIP) : NerdLookup = "000"
   Dim a, strLookup
   a = Split(strIP, ".")
   With CreateObject("SScripting.IPNetwork")
      strLookup = .DNSLookup(a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".zz.countries.nerd.dk")
   End With
   EventLog.Write( "NerdLookup(" & strIP & ") = " & strLookup )
   If Left(strLookup, 3) = "127" Then
      a = Split(strLookup, ".")
      NerdLookup = Right("00" & CStr(a(2)*256 + a(3)), 3)
   End If
   EventLog.Write( "NerdLookup(" & strIP & ") = " & NerdLookup )
   Call NerdLookupTXT(strIP)
End Function

Function NerdLookupTXT(strIP) : NerdLookupTXT = "|"
   Dim a, element, group, strLookup
   a = Split(strIP, ".")
   With CreateObject("DNSLibrary.DNSResolver")
      strLookup = .TXT(a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".zz.countries.nerd.dk")
   End With
   group = Split(strLookup, vbCrLf)
   For Each element In group
      If (Trim(element) <> "") Then NerdLookupTXT = NerdLookupTXT & element & "|"
   Next
   EventLog.Write( "NerdLookup(" & strIP & ") = " & NerdLookupTXT )
End Function
I get the same result if I do this...

Code: Select all

'   With CreateObject("SScripting.IPNetwork")
'      strLookup = .DNSLookup(a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".zz.countries.nerd.dk")
'   End With
   With CreateObject("DNSLibrary.DNSResolver")
      strLookup = .A(a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".zz.countries.nerd.dk")
   End With
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-12 17:06

SorenR wrote:
2019-01-12 16:05
ISO 3166-1 alpha-3
I hate to quote myself but "ISO 3166-1 alpha-3 Code" is wrong, they are three letter country codes. The ones we get from countries.nerd.dk are calculated 3-digit "ISO 3166-1 UN codes".

https://www.iso.org/obp/ui
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

User avatar
RvdH
Senior user
Senior user
Posts: 797
Joined: 2008-06-27 14:42
Location: Netherlands

Re: Want to Autoban some special spammer

Post by RvdH » 2019-01-15 12:30

SorenR wrote:
2019-01-12 16:05
Well Ruud,

It seems as those pesky ISO 3166-1 alpha-3 IS the way to go. I reconfigured my system before I went to bed this morning and this is what I got... The "old" NerdLookup() is calling the "new" NerdLookupTXT() in order to get both solutions.
I hate to say this to you, but you are wrong...and this is exactly why i created my own lookup component... SScripting.IPNetwork only returns a single record, even if there are two! SScripting.IPNetwork is faulty! :mrgreen:

https://mxtoolbox.com/SuperTool.aspx?ac ... tworktools

https://mxtoolbox.com/SuperTool.aspx?ac ... tworktools


.A, .IPv4A and .DNSLookup are exactly the same in my component, but i left it there to be easily replaceable with the SScripting.IPNetwork component

Code: Select all

Create object of type DNSLibrary.DNSResolver

This object has 13 public functions:

	-- version() * returns the version number
	-- help() * shows this help
	-- IPv4A(<Domain name>) * query IPv4 A-Record(s)
	-- A(<Domain name>) * same as IPv4A (deprecated)
	-- DNSLookup(<Domain name>) * same as IPv4A (deprecated)
	-- IPv6A(<Domain name>) * query IPv6 A-Record(s)
	-- AAAA(<Domain name>) * same as IPv6A (deprecated)
	-- CNAME(<Domain name>) * query CNAME-Record(s)
	-- MX(<Domain name>) * query MX-Record(s)
	-- NS(<Domain name>) * query NS-Record(s)
	-- PTR(<IP address>) * query PTR-Record(s)
	-- SOA(<Domain name>) * query SOA-Record(s)
	-- TXT(<Domain name>) * query TXT-Record(s)


VBScript example:

Dim ObjDNS
Set ObjDNS = CreateObject("DNSLibrary.DNSResolver")
WScript.Echo("A-Record (IP4): " & ObjDNS.IPv4A("vdhout.nl"))
Set ObjDNS = Nothing
CIDR to RegEx: d-fault.nl/CIDRtoRegEx
DNS Lookup: d-fault.nl/DNSTools
DNSBL Lookup: d-fault.nl/DNSBLLookup
GEOIP Lookup: d-fault.nl/GeoipLookup

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-15 15:17

RvdH wrote:
2019-01-15 12:30
I hate to say this to you, but you are wrong...and this is exactly why i created my own lookup component... SScripting.IPNetwork only returns a single record, even if there are two! SScripting.IPNetwork is faulty!
Yes, I know... Now... :wink:

The difference between the "old" and the "new" is that the "old" always returned the same address, the "new" will alternate randomly between the two.

Anyways, I have sent email to the owner of nerd.dk. Let's see if he responds.
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-15 16:20

RvdH wrote:
2019-01-15 12:30

Code: Select all

Create object of type DNSLibrary.DNSResolver

This object has 13 public functions:

	-- version() * returns the version number
	-- help() * shows this help
	-- IPv4A(<Domain name>) * query IPv4 A-Record(s)
	-- A(<Domain name>) * same as IPv4A (deprecated)
	-- DNSLookup(<Domain name>) * same as IPv4A (deprecated)
	-- IPv6A(<Domain name>) * query IPv6 A-Record(s)
	-- AAAA(<Domain name>) * same as IPv6A (deprecated)
	-- CNAME(<Domain name>) * query CNAME-Record(s)
	-- MX(<Domain name>) * query MX-Record(s)
	-- NS(<Domain name>) * query NS-Record(s)
	-- PTR(<IP address>) * query PTR-Record(s)
	-- SOA(<Domain name>) * query SOA-Record(s)
	-- TXT(<Domain name>) * query TXT-Record(s)


VBScript example:

Dim ObjDNS
Set ObjDNS = CreateObject("DNSLibrary.DNSResolver")
WScript.Echo("A-Record (IP4): " & ObjDNS.IPv4A("vdhout.nl"))
Set ObjDNS = Nothing
Am I doing something wrong here ??? Not getting the full data from asn.routeviews.org ...

Code: Select all

**********

   strIP = "185.222.209.40"
   Dim a, b, element, group, strLookup
   a = Split(strIP, ".")

   With CreateObject("DNSLibrary.DNSResolver")
      strLookup = .TXT(a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".zz.countries.nerd.dk")
      WScript.Echo( "strLookup = " & strLookup )
   End With

   group = Split(strLookup, vbCrLf)
   For b = LBound(group) To UBound(group)
      If (Trim(group(b)) <> "") Then
         WScript.Echo( "Test(" & strIP & ") = " & group(b) & ", " & a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".zz.countries.nerd.dk" )
      End If
   Next

   With CreateObject("DNSLibrary.DNSResolver")
      strLookup = .TXT(a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".asn.routeviews.org")
      WScript.Echo( "strLookup = " & strLookup )
   End With

   group = Split(strLookup, vbCrLf)
   For b = LBound(group) To UBound(group)
      If (Trim(group(b)) <> "") Then
         WScript.Echo( "Test(" & strIP & ") = " & group(b) & ", " & a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".asn.routeviews.org" )
      End If
   Next

**********

\\Datacenter\c$\hMailServer\Events>test.vbs
Microsoft (R) Windows Script Host Version 5.7
Copyright (C) Microsoft Corporation. All rights reserved.

strLookup = uk
nl

Test(185.222.209.40) = uk, 40.209.222.185.zz.countries.nerd.dk
Test(185.222.209.40) = nl, 40.209.222.185.zz.countries.nerd.dk
strLookup = 57043
Test(185.222.209.40) = 57043, 40.209.222.185.asn.routeviews.org

\\Datacenter\c$\hMailServer\Events>

**********

\\Datacenter\c$\hMailServer\Events>nslookup -type=TXT 40.209.222.185.zz.countries.nerd.dk
Server:  ns.acme.inc
Address:  192.168.0.50

Non-authoritative answer:
40.209.222.185.zz.countries.nerd.dk     text =

        "nl"
40.209.222.185.zz.countries.nerd.dk     text =

        "uk"

countries.nerd.dk       nameserver = michelin.bananas.dk
countries.nerd.dk       nameserver = countries-ns2.nerd.dk
countries-ns2.nerd.dk   internet address = 195.182.36.121

**********

\\Datacenter\c$\hMailServer\Events>nslookup -type=TXT 40.209.222.185.asn.routeviews.org
Server:  ns.acme.inc
Address:  192.168.0.50

Non-authoritative answer:
40.209.222.185.asn.routeviews.org       text =

        "57043"
        "185.222.209.0"
        "24"

asn.routeviews.org      nameserver = asnums.routeviews.org
asnums.routeviews.org   internet address = 128.223.51.29
asnums.routeviews.org   AAAA IPv6 address = 2001:468:d01:33::80df:331d

\\Datacenter\c$\hMailServer\Events>

**********
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

User avatar
RvdH
Senior user
Senior user
Posts: 797
Joined: 2008-06-27 14:42
Location: Netherlands

Re: Want to Autoban some special spammer

Post by RvdH » 2019-01-15 19:26

Something seems off with that TXT record, it looks like a single string :shock: , see
https://mxtoolbox.com/SuperTool.aspx?ac ... tworktools

dig 40.209.222.185.asn.routeviews.org TXT

Code: Select all

; <<>> DiG 9.11.0-P1 <<>> 40.209.222.185.asn.routeviews.org TXT
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46682
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
; COOKIE: 872f4a511a8109f9e8b415f45c3e1c55e950e1efe466312b (good)
;; QUESTION SECTION:
;40.209.222.185.asn.routeviews.org. IN  TXT

;; ANSWER SECTION:
40.209.222.185.asn.routeviews.org. 3600 IN TXT  "57043" "185.222.209.40" "32"

;; Query time: 390 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Tue Jan 15 18:45:57 W. Europe Standard Time 2019
;; MSG SIZE  rcvd: 126
CIDR to RegEx: d-fault.nl/CIDRtoRegEx
DNS Lookup: d-fault.nl/DNSTools
DNSBL Lookup: d-fault.nl/DNSBLLookup
GEOIP Lookup: d-fault.nl/GeoipLookup

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-15 20:38

Spamassassin is using it...

c:\SpamAssassin\share\3.004000\updates_spamassassin_org\25_asn.cf

Added header;

X-Spam-ASN: AS57043 185.222.209.40/32

Since two or three versions back SpamAssassin started including ASN numbers in Bayesian data to identify Spammers by Internet router. I was just wondering if I could use it for something usefull. :mrgreen:

The ASN number comes through though and that is the key identifier.
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

User avatar
RvdH
Senior user
Senior user
Posts: 797
Joined: 2008-06-27 14:42
Location: Netherlands

Re: Want to Autoban some special spammer

Post by RvdH » 2019-01-16 00:11

SorenR wrote:
2019-01-15 20:38
Spamassassin is using it...

c:\SpamAssassin\share\3.004000\updates_spamassassin_org\25_asn.cf

Added header;

X-Spam-ASN: AS57043 185.222.209.40/32

Since two or three versions back SpamAssassin started including ASN numbers in Bayesian data to identify Spammers by Internet router. I was just wondering if I could use it for something usefull. :mrgreen:

The ASN number comes through though and that is the key identifier.
I think i can fix it, if you wish...

Code: Select all

strLookup = 57043
185.222.209.40
32

Test() = 57043, 40.209.222.185.asn.routeviews.org

Test() = 185.222.209.40, 40.209.222.185.asn.routeviews.org

Test() = 185.222.209.40, 40.209.222.185.asn.routeviews.org
CIDR to RegEx: d-fault.nl/CIDRtoRegEx
DNS Lookup: d-fault.nl/DNSTools
DNSBL Lookup: d-fault.nl/DNSBLLookup
GEOIP Lookup: d-fault.nl/GeoipLookup

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-16 02:40

Seems like SpamAssassin is just doing a DNS TXT lookup and returns 3 "items"..

This is from Mail::SpamAssassin::Plugin::ASN.pm
https://apache.googlesource.com/spamass ... gin/ASN.pm

Code: Select all

  foreach my $rr (@answer) {
    dbg("asn: %s: lookup result packet: '%s'", $zone, $rr->string);
    if ($rr->type eq 'TXT') {
      my @items = split(/ /, $rr->txtdata);
      unless (@items == 3) {
        dbg("asn: TXT query response format unknown, ignoring zone: %s, ".
            "response: '%s'", $zone, $rr->txtdata);
        next;
      }
      unless ($scanner->{tag_data}->{$asn_tag} =~ /\b\QAS$items[0]\E\b/) {
        if ($scanner->{tag_data}->{$asn_tag}) {
          $scanner->{tag_data}->{$asn_tag} .= " AS$items[0]";
        } else {
          $scanner->{tag_data}->{$asn_tag} = "AS$items[0]";
        }
      }
      unless ($scanner->{tag_data}->{$route_tag} =~
              m{\b\Q$items[1]/$items[2]\E\b}) {
        if ($scanner->{tag_data}->{$route_tag}) {
          $scanner->{tag_data}->{$route_tag} .= " $items[1]/$items[2]";
        } else {
          $scanner->{tag_data}->{$route_tag} = "$items[1]/$items[2]";
        }
      }
    }
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

User avatar
RvdH
Senior user
Senior user
Posts: 797
Joined: 2008-06-27 14:42
Location: Netherlands

Re: Want to Autoban some special spammer

Post by RvdH » 2019-01-16 11:27

I have updated the lookup component (v1.3.0.1)
The code below, should return everything now

Code: Select all

**********

   strIP = "185.222.209.40"
   Dim a, b, element, group, strLookup
   a = Split(strIP, ".")

   With CreateObject("DNSLibrary.DNSResolver")
      strLookup = .TXT(a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".zz.countries.nerd.dk")
      WScript.Echo( "strLookup = " & strLookup )
   End With

   group = Split(strLookup, vbCrLf)
   For b = LBound(group) To UBound(group)
      If (Trim(group(b)) <> "") Then
         WScript.Echo( "Test(" & strIP & ") = " & group(b) & ", " & a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".zz.countries.nerd.dk" )
      End If
   Next

   With CreateObject("DNSLibrary.DNSResolver")
      strLookup = .TXT(a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".asn.routeviews.org")
      WScript.Echo( "strLookup = " & strLookup )
   End With

   group = Split(strLookup, vbCrLf)
   For b = LBound(group) To UBound(group)
      If (Trim(group(b)) <> "") Then
         WScript.Echo( "Test(" & strIP & ") = " & group(b) & ", " & a(3) & "." & a(2) & "." & a(1) & "." & a(0) & ".asn.routeviews.org" )
      End If
   Next

**********
CIDR to RegEx: d-fault.nl/CIDRtoRegEx
DNS Lookup: d-fault.nl/DNSTools
DNSBL Lookup: d-fault.nl/DNSBLLookup
GEOIP Lookup: d-fault.nl/GeoipLookup

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-16 18:45

I have started logging ASN based on the assumption that the major Spammers use clusters of servers and these clusters need a router to access the Internet.

If you know about the Internet, routing and routing protocols then you know that you can use ASN to identify clusters of servers, much like if an ASN is a road where cars regularly speed to and from houses you can deny access to individual houses for serial offenders - Or you can close the entire road by banning the ASN. In effect you will be banning an entire range of IP addresses defined by the ASN.
https://en.wikipedia.org/wiki/Autonomou ... (Internet)

I have started logging traffic to my server wrt ASN, HAM and SPAM to see if there is a correlation between SPAM and HAM for any given ASN.

When you query an IP address at e.g. asn.routeviews.org using RvdH's DNSResolver it will return the ASN and the IP Range it covers. Often when we ban IP addresses we see "families" of IP addresses in the list, like 20 IP addresses scattered over an entire subnet.

Anyways, its logging now and we'll see if something usefull will come out of it. The code below is using a header added by SpamAssassin as it already did the lookup - no point in overdoing it for now :mrgreen:

Code: Select all

Sub OnDeliveryStart(oMessage)
   Call logASN(oMessage)
End Sub

'   Table:   CREATE TABLE hm_asn (
'                   asn       VARCHAR (192) PRIMARY KEY,
'                   ham       INTEGER,
'                   spam      INTEGER);

Function logASN(oMessage)
   Dim a, strSQL, oDB : Set oDB = GetDatabaseObject
   If (oMessage.HeaderValue("X-Spam-ASN") <> "") Then
      a = Split(oMessage.HeaderValue("X-Spam-ASN"), " ")
      If (oMessage.HeaderValue("X-hMailServer-Spam") = "YES") Then
         strSQL = "INSERT INTO hm_asn (asn,ham,spam) VALUES ('" & a(0) & "', 0,1) ON DUPLICATE KEY UPDATE spam=(spam+1);"
      Else
         strSQL = "INSERT INTO hm_asn (asn,ham,spam) VALUES ('" & a(0) & "', 1,0) ON DUPLICATE KEY UPDATE ham=(ham+1);"
      End If
      EventLog.Write( "logASN: " & strSQL )
      Call oDB.ExecuteSQL(strSQL)
   End If
End Function

Function GetDatabaseObject()
   Dim oApp : Set oApp = CreateObject("hMailServer.Application")
   Call oApp.Authenticate(ADMIN, PASSWORD)
   Set GetDatabaseObject = oApp.Database
End Function
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

User avatar
RvdH
Senior user
Senior user
Posts: 797
Joined: 2008-06-27 14:42
Location: Netherlands

Re: Want to Autoban some special spammer

Post by RvdH » 2019-01-16 19:09

Hi SorenR,
Why the VARCHAR (192) And not simply use the default VARCHAR (255)
Maybe Expecting uft8mb4?

I also noticed you used that VARCHAR (192) in your IDS code, but there is a maximum of 15 chars for IPv4 and 45 for IPv6 addresses...

https://stackoverflow.com/questions/107 ... ss/1076749
There's a caveat with the general 39 character IPv6 structure. For IPv4 mapped IPv6 addresses, the string can be longer (than 39 characters). An example to show this:

IPv6 (39 characters) :
ABCD:ABCD:ABCD:ABCD:ABCD:ABCD:ABCD:ABCD

IPv4-mapped IPv6 (45 characters) :
ABCD:ABCD:ABCD:ABCD:ABCD:ABCD:192.168.158.190

Note: the last 32-bits (that correspond to IPv4 address) can need up to 15 characters (as IPv4 uses 4 groups of 1 byte and is formatted as 4 decimal numbers in the range 0-255 separated by dots (the . character), so the maximum is DDD.DDD.DDD.DDD).

The correct maximum IPv6 string length, therefore, is 45.
[s]FYI, you might want to flip the INSERT INTO hm_asn queries as it marking ham as spam now[/s]
EDIT: Nevermind.. i noticed you fixed it already :)
CIDR to RegEx: d-fault.nl/CIDRtoRegEx
DNS Lookup: d-fault.nl/DNSTools
DNSBL Lookup: d-fault.nl/DNSBLLookup
GEOIP Lookup: d-fault.nl/GeoipLookup

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-01-16 20:38

RvdH wrote:
2019-01-16 19:09
Hi SorenR,
Why the VARCHAR (192) And not simply use the default VARCHAR (255)
Maybe Expecting uft8mb4?

I also noticed you used that VARCHAR (192) in your IDS code, but there is a maximum of 15 chars for IPv4 and 45 for IPv6 addresses...
There is no deeper meaning... They were left on the shelf, big enough for my purpose, so I just grabbed them :mrgreen:
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

User avatar
RvdH
Senior user
Senior user
Posts: 797
Joined: 2008-06-27 14:42
Location: Netherlands

Re: Want to Autoban some special spammer

Post by RvdH » 2019-02-05 10:27

@SorenR

I used ASN logging as in your example above and have found prove some listed are used to send spam only
I decided to score various ASN entries higher (using spamassassin)

Example

Code: Select all

### ASN scores ###
ifplugin Mail::SpamAssassin::Plugin::ASN

	# AS16276 OVH SAS
	header 		ASN_AS16276 X-ASN =~ /\b(16276)\b/
	describe	ASN_AS16276 Sender IP is known ASN spam source 
	score		ASN_AS16276 5

	# AS24961 myLoc managed IT AG
	header 		ASN_AS24961 X-ASN =~ /\b(24961)\b/
	describe	ASN_AS24961 Sender IP is known ASN spam source 
	score		ASN_AS24961 5 

	# AS20278 Nexeon Technologies, Inc.
	header 		ASN_AS20278 X-ASN =~ /\b(20278)\b/
	describe	ASN_AS20278 Sender IP is known ASN spam source 
	score		ASN_AS20278 5 

	# AS46475 Limestone Networks, Inc.
	header 		ASN_AS46475 X-ASN =~ /\b(46475)\b/
	describe	ASN_AS46475 Sender IP is known ASN spam source 
	score		ASN_AS46475 5 
	
	# AS46664 VolumeDrive
	header 		ASN_AS46664 X-ASN =~ /\b(46664)\b/
	describe	ASN_AS46664 Sender IP is known ASN spam source 
	score		ASN_AS46664 5 

	# AS14061 DigitalOcean, LLC
	header 		ASN_AS14061 X-ASN =~ /\b(14061)\b/
	describe	ASN_AS14061 Sender IP is known ASN spam source 
	score		ASN_AS14061 5 
	
	# AS22439 Perfect International, Inc
	header 		ASN_AS22439 X-ASN =~ /\b(22439)\b/
	describe	ASN_AS22439 Sender IP is known ASN spam source 
	score		ASN_AS22439 5 	
	
	# AS174 Cogent Communications
	header 		ASN_AS174 X-ASN =~ /\b(174)\b/
	describe	ASN_AS174 Sender IP is known ASN spam source 
	score		ASN_AS174 5 
	
	# AS30722 Vodafone Italia S.p.A.
	header 		ASN_AS30722 X-ASN =~ /\b(30722)\b/
	describe	ASN_AS30722 Sender IP is known ASN spam source 
	score		ASN_AS30722 5 
	
endif
  • X-ASN is metadata header spamassassin internally uses
  • X-ASN does not contain AS#### until it is rewritten to X-Spam-ASN
CIDR to RegEx: d-fault.nl/CIDRtoRegEx
DNS Lookup: d-fault.nl/DNSTools
DNSBL Lookup: d-fault.nl/DNSBLLookup
GEOIP Lookup: d-fault.nl/GeoipLookup

User avatar
SorenR
Senior user
Senior user
Posts: 3169
Joined: 2006-08-21 15:38
Location: Denmark

Re: Want to Autoban some special spammer

Post by SorenR » 2019-02-06 00:20

RvdH wrote:
2019-02-05 10:27
@SorenR

I used ASN logging as in your example above and have found prove some listed are used to send spam only
I decided to score various ASN entries higher (using spamassassin)

Example

Code: Select all

### ASN scores ###
ifplugin Mail::SpamAssassin::Plugin::ASN

	# AS16276 OVH SAS
	header 		ASN_AS16276 X-ASN =~ /\b(16276)\b/
	describe	ASN_AS16276 Sender IP is known ASN spam source 
	score		ASN_AS16276 5

	# AS24961 myLoc managed IT AG
	header 		ASN_AS24961 X-ASN =~ /\b(24961)\b/
	describe	ASN_AS24961 Sender IP is known ASN spam source 
	score		ASN_AS24961 5 

	# AS20278 Nexeon Technologies, Inc.
	header 		ASN_AS20278 X-ASN =~ /\b(20278)\b/
	describe	ASN_AS20278 Sender IP is known ASN spam source 
	score		ASN_AS20278 5 

	# AS46475 Limestone Networks, Inc.
	header 		ASN_AS46475 X-ASN =~ /\b(46475)\b/
	describe	ASN_AS46475 Sender IP is known ASN spam source 
	score		ASN_AS46475 5 
	
	# AS46664 VolumeDrive
	header 		ASN_AS46664 X-ASN =~ /\b(46664)\b/
	describe	ASN_AS46664 Sender IP is known ASN spam source 
	score		ASN_AS46664 5 

	# AS14061 DigitalOcean, LLC
	header 		ASN_AS14061 X-ASN =~ /\b(14061)\b/
	describe	ASN_AS14061 Sender IP is known ASN spam source 
	score		ASN_AS14061 5 
	
	# AS22439 Perfect International, Inc
	header 		ASN_AS22439 X-ASN =~ /\b(22439)\b/
	describe	ASN_AS22439 Sender IP is known ASN spam source 
	score		ASN_AS22439 5 	
	
	# AS174 Cogent Communications
	header 		ASN_AS174 X-ASN =~ /\b(174)\b/
	describe	ASN_AS174 Sender IP is known ASN spam source 
	score		ASN_AS174 5 
	
	# AS30722 Vodafone Italia S.p.A.
	header 		ASN_AS30722 X-ASN =~ /\b(30722)\b/
	describe	ASN_AS30722 Sender IP is known ASN spam source 
	score		ASN_AS30722 5 
	
endif
  • X-ASN is metadata header spamassassin internally uses
  • X-ASN does not contain AS#### until it is rewritten to X-Spam-ASN
Well, I did abandon the project due to other stuff I was working on, but I may take it up again. It will need some serious logging over a couple of months to divide good from bad and then there's the ca. 30% being both good AND bad.
The standard ruleset contains a configuration that will add a header containing ASN data to scanned messages. The bayes tokenizer will use the added header for bayes calculations, and thus affect which BAYES_* rule will trigger for a particular message.

Note that in most cases you should not score on the ASN data directly. Bayes learning will probably trigger on the _ASNCIDR_ tag, but probably not very well on the _ASN_ tag alone.
https://spamassassin.apache.org/full/3. ... n_ASN.html

My current way of tagging SPAM bsides DNSBL, SURBL and SpamAssassin is a mix of string matches on "List-Unsubscribe", "From", "X-Envelope-From", "Subject", "Body and "HTMLBody".

I found that in 100% of the cases a "List-Unsubscribe" header matching

Code: Select all

(\<http(s?):\/\/(.*)\/unsubscribe\.php\?M=(.*)&C=(.*)&L=(.*)&N=(.*)\>)
is SPAM.

Anyways, SpamAssassin will pick this up over time as part of the normal training I do every night.
SørenR.

The quantum rule of insecurity which states that the act of observing how vulnerable a host or service is changes the insecurity level of the service.

Post Reply