As hMailServer lacks the abbillity to block contents inside zip files and I can not block all zip attachments using the 'blocked attachments' panel in hmailadmin as many of clients use them to send/receive pictures and design stuff like Illustrator or Photoshop graphics i needed to find a different approach to block harmfull files inside zip archives like exe, vbs en js files nowadays used to infect people with malware/trojans/virusses.
I ended up with writing a little .NET application that looks inside a zip file (if it is able to) and then list its content and deny the attachment if one or more disallowed file extensions are found inside the Zip archive.
Functionality:
- Examine Zip Archive header (confirm it is actually a Zip Archive)
- List files contained within the Zip Archive
- Compare the list with files within the Zip Archive with a array of disallowed extensions (for example: *.js, *.vbs)
With the above program returning exitcodes I managed script eventhandlers.vbs to:
- Delete archives with disallowed extensions in it
- Quarantine damaged, fake and/or Zip attachments with disallowed extensions in it
- Add Pseudo Attachment with blocked message
Usage:
Note: In this short quick start guide I adapted hMailServer default paths for simplicity, you need to change if you installed it elsewhere
Extract the contents inside attached ZipArchive to:
C:\Program Files (x86)\hMailServer\Events\
If you like to adapt quarantine functionality of zip attachments, create folder:
C:\Program Files (x86)\hMailServer\Quarantine\
Edit ScanZipArchive.exe.config to suite your needs (included in download)
Note: ScanZipArchive.exe uses .NET Path.Combine function to catch common file/path errors so it uses defined "Path" parameter (normally this would be: C:\Program Files (x86)\hMailServer\Temp\) in combination with archive filename passed to ScanZipArchive.exe
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="Path" value="C:\Program Files (x86)\hMailServer\Temp\"/>
<add key="Extensions" value="bat|cmd|com|cpl|csh|docm|exe|pif|hta|htb|inf|js|jse|lnk|msi|msp|pif|reg|scf|scr|shs|shb|vbe|vbs|wsf|wsh"/>
<!-- Value in kilobytes, 1024 kB is 1 MB, 0 or empty value disables this feature -->
<add key="MaximumSize" value="0"/>
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
<!--
// exit codes //
-1 = File not found error and/or Filename argument is missing
0 = Clean and/or Zip archive size > MaximumSize
1 = Zip archive contains file with disallowed extension
2 = This archive is not a valid Zip archive
-->
</configuration>
Edit template.txt to suite your needs (included in download)
The attachment [%1] was blocked for delivery by the e-mail server because its content presents a potential security issue. Please contact your system administrator if you have any questions regarding this.
hMailServer
Edit EventHandlers.vbs, Add the subs below (To debug, uncomment REM EventLog.Write statements)
Sub ScanZipAttachments(oMessage)
Dim Quarantine
Quarantine = false
Dim QuarantineFolder
QuarantineFolder = "C:\Program Files (x86)\hMailServer\Quarantine\"
Dim Changed
Changed = false
Dim TempFolder
TempFolder = "C:\Program Files (x86)\hMailServer\Temp\"
Dim QuarantineFile, ZipFile, ZipPath
Dim PseudoFile
Dim oAttachment
Dim ExitCode, WshShell
If oMessage.Attachments.Count > 0 then
dim fso
Set fso = CreateObject("Scripting.FileSystemObject")
For oAttachment = 0 to oMessage.Attachments.Count-1
If Lcase(fso.GetExtensionName(oMessage.Attachments(oAttachment).Filename)) = "zip" Then
ZipFile = Left(Right(oMessage.Filename,42),38) & "." & oAttachment & "." & oMessage.Attachments(oAttachment).Filename
ZipPath = fso.BuildPath(TempFolder,ZipFile)
oMessage.Attachments(oAttachment).SaveAs(ZipPath)
REM EventLog.Write("Temp file saved as: " & ZipPath)
Set WshShell = CreateObject("WScript.Shell")
ExitCode = WshShell.Run("""C:\Program Files (x86)\hMailServer\Events\ScanZipArchive.exe"" """ & ZipFile & """",0,True)
REM EventLog.Write("ExitCode: " & ExitCode)
If fso.FileExists(ZipPath) Then
fso.DeleteFile ZipPath, True
REM EventLog.Write("Temp file deleted: " & ZipPath)
End If
if (ExitCode > 0) Then
If (Quarantine) Then
QuarantineFile = fso.BuildPath(QuarantineFolder, Left(Right(oMessage.Filename,42),38) & "." & oAttachment & "." & oMessage.Attachments(oAttachment).Filename & ".Quarantined")
oMessage.Attachments(oAttachment).SaveAs(QuarantineFile)
oMessage.Attachments(oAttachment).Delete
EventLog.Write("Attachment quarantined as: " & QuarantineFile)
Else
oMessage.Attachments(oAttachment).Delete
End If
Select Case ExitCode
case 1
EventLog.Write("Attachment " & oMessage.Attachments(oAttachment).Filename & " deleted because it contained a file with disallowed extension")
Changed = true
Case 2
EventLog.Write("Attachment " & oMessage.Attachments(oAttachment).Filename & " deleted because it is a invalid or corrupted archive")
Changed = true
End Select
WriteFile(oMessage.Attachments(oAttachment).Filename)
PseudoFile = fso.BuildPath(TempFolder, oMessage.Attachments(oAttachment).Filename & ".txt")
oMessage.Attachments.Add(PseudoFile)
If fso.FileExists(PseudoFile) Then
fso.DeleteFile PseudoFile, True
end if
End If
Set WshShell = Nothing
End If
Next
If (Changed) then
oMessage.Save
End If
Set fso = Nothing
End If
End Sub
Sub WriteFile(filename)
Dim TempFolder
TempFolder = "C:\Program Files (x86)\hMailServer\Temp\"
Dim TemplateFile : TemplateFile = "C:\Program Files (x86)\hMailServer\Events\template.txt"
Dim vBody : vBody = Empty
Dim vLine : vLine = Empty
dim fso, PseudoFile
Set fso = CreateObject("Scripting.FileSystemObject")
PseudoFile = fso.BuildPath(TempFolder, filename & ".txt")
Set fso = nothing
Dim objStreamBody
Set objStreamBody = CreateObject("ADODB.Stream")
Const CdoBIG5 = "big5"
Const CdoEUC_JP = "euc-jp"
Const CdoEUC_KR = "euc-kr"
Const CdoGB2312 = "gb2312"
Const CdoISO_2022_JP = "iso-2022-jp"
Const CdoISO_2022_KR = "iso-2022-kr"
Const CdoISO_8859_1 = "iso-8859-1"
Const CdoISO_8859_2 = "iso-8859-2"
Const CdoISO_8859_3 = "iso-8859-3"
Const CdoISO_8859_4 = "iso-8859-4"
Const CdoISO_8859_5 = "iso-8859-5"
Const CdoISO_8859_6 = "iso-8859-6"
Const CdoISO_8859_7 = "iso-8859-7"
Const CdoISO_8859_8 = "iso-8859-8"
Const CdoISO_8859_9 = "iso-8859-9"
Const cdoKOI8_R = "koi8-r"
Const cdoShift_JIS = "shift-jis"
Const CdoUS_ASCII = "us-ascii"
Const CdoUTF_7 = "utf-7"
Const CdoUTF_8 = "utf-8"
objStreamBody.Mode = 3
objStreamBody.LineSeparator = -1
objStreamBody.Type = 2
objStreamBody.Charset = CdoUS_ASCII
objStreamBody.Open
objStreamBody.LoadFromFile(TemplateFile)
objStreamBody.Position = 0
Do Until objStreamBody.EOS
vLine = objStreamBody.ReadText()
vLine = Replace(vLine,"[%1]",filename)
vBody = vBody & vLine
Loop
objStreamBody.Position = 0
objStreamBody.WriteText(vBody)
objStreamBody.SetEOS
objStreamBody.SaveToFile PseudoFile, 2
objStreamBody.Close
Set objStreamBody = Nothing
End Sub
As final step first add a global rules which says:
Criteria:
Predefined field: Message size > 0
AND
Custom header field: X-hMailServer-LoopCount < 1
Action:
Run function ScanZipAttachments

Requirements:
- NET Framework 4.5 or higher (the program uses System.IO.Compression which did not exist in .NET prior version 4.5)
- Make sure "Scripts" usage is enabled in hMailServer Administrator under Settings -> Advanced -> Scripts
- Make sure the executable (ScanZipArchive.exe) is not blocked by the Windows SmartScreen Filter
(This could be a problem assuming one of the comments)
Version history:
1.0.0.3 (18/01/2019)
- Check and verify ScanZipArchive.exe.config file exists
- Exit loop of the files inside the Zip archive as soon as one blocked file extension is found
- Sub ScanZipAttachments, fix a issue where uppercase ZIP archives where ignored
If Lcase(fso.GetExtensionName(oMessage.Attachments(oAttachment).Filename)) = "zip" Then
- Abbility to assign a MaximumSize of zip archive to scan
value in kilobytes, 1024 kB is 1 MB, 0 or empty value disables this feature
- Initial release
Download:
ScanZipArchive.zip
Last edited Jan 18 2019