├── DocBleachShell └── DocBleachShell │ ├── DocBleachShell.cs │ ├── DocBleachShell.csproj │ ├── DocBleachShell.sln │ ├── DocBleachWrapper.cs │ ├── Helper.cs │ ├── JoeSandboxClient.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── Trinet.Core.IO.Ntfs.dll │ └── app.config ├── LICENSE ├── README.md ├── bin ├── DocBleachShell.exe ├── DocBleachShell.exe.config ├── Trinet.Core.IO.Ntfs.dll ├── docbleach.jar └── log4net.dll └── img ├── install.png ├── shell.png └── uninstall.png /DocBleachShell/DocBleachShell/DocBleachShell.cs: -------------------------------------------------------------------------------- 1 | // License: MIT 2 | // Copyright: Joe Security 3 | // Dependencies: - DocBleach https://github.com/docbleach 4 | // - Log4Net https://logging.apache.org/log4net/ 5 | // - Ntfs Streams https://github.com/RichardD2/NTFS-Streams 6 | 7 | using System; 8 | using System.Collections; 9 | using System.Configuration; 10 | using System.Diagnostics; 11 | using System.IO; 12 | using System.Management; 13 | using System.Runtime.InteropServices; 14 | using System.Security.Principal; 15 | using System.Text; 16 | 17 | using System.Threading; 18 | using log4net; 19 | using Microsoft.Win32; 20 | using Trinet.Core.IO.Ntfs; 21 | 22 | [assembly: log4net.Config.XmlConfigurator(Watch = false)] 23 | 24 | namespace DocBleachShell 25 | { 26 | 27 | /// 28 | /// This class implements a simple Wrapper around DocBleach (https://github.com/docbleach) by using the Windows Shell handlers. The idea is to call docbleach 29 | /// for each document before Office is opening it. That way documents are sanitized "bleached" automatically. 30 | /// 31 | class DocBleachShell 32 | { 33 | 34 | private static String ParentDirectory; 35 | private static String AssemblyFilePath; 36 | 37 | private static readonly ILog Logger = LogManager.GetLogger(typeof(DocBleachShell)); 38 | 39 | [DllImport("kernel32")] 40 | static extern bool AllocConsole(); 41 | 42 | [DllImport( "kernel32", SetLastError = true )] 43 | static extern bool AttachConsole( int dwProcessId ); 44 | 45 | [DllImport("kernel32.dll")] 46 | static extern bool FreeConsole(); 47 | 48 | [DllImport("User32.Dll", EntryPoint = "PostMessageA")] 49 | static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam); 50 | 51 | const int VK_RETURN = 0x0D; 52 | const int WM_KEYDOWN = 0x100; 53 | 54 | private static readonly String VERSION = "0.0.2"; 55 | 56 | /// 57 | /// Main routine called for install, uninstall + to bleach documents. 58 | /// 59 | /// 60 | public static void Main(string[] Args) 61 | { 62 | AssemblyFilePath = System.Reflection.Assembly.GetEntryAssembly().Location; 63 | ParentDirectory = Directory.GetParent(AssemblyFilePath).FullName; 64 | 65 | if(Args.Length == 1) 66 | { 67 | if (!AttachConsole(-1)) AllocConsole(); 68 | 69 | Console.WriteLine(""); 70 | 71 | Logger.Info("DocBleachShell v" + VERSION); 72 | Logger.Info("Copyright Joe Security"); 73 | Logger.Info("www.joesecurity.org"); 74 | Logger.Info("License: MIT"); 75 | 76 | // Requires admin. 77 | if(Args[0].Equals("-install")) 78 | { 79 | if(Helper.IsUserAdministrator()) 80 | { 81 | Install(); 82 | } else 83 | { 84 | Logger.Error("Please install as Administrator"); 85 | } 86 | 87 | // Requires admin. 88 | } if(Args[0].Equals("-uninstall")) 89 | { 90 | if(Helper.IsUserAdministrator()) 91 | { 92 | RestoreBackup(); 93 | } else 94 | { 95 | Logger.Error("Please uninstall as Administrator"); 96 | } 97 | 98 | } 99 | 100 | closeConsole(); 101 | 102 | 103 | } else if (Args.Length > 1) 104 | { 105 | try 106 | { 107 | Bleach(Args); 108 | } catch(Exception e) 109 | { 110 | Logger.Error("Error during bleaching", e); 111 | } 112 | } 113 | } 114 | 115 | /// 116 | /// Replaces all Shell\Open\command for Winword.exe, Excel.exe and Powerpnt.exe to point to our assembly. Before registry entries are modified a backup 117 | /// is made to \backup. Also the assembly paths of winword, excel and powerpnt are stored. 118 | /// 119 | private static void Install() 120 | { 121 | Logger.Info("Installing DocBleachShell"); 122 | 123 | try 124 | { 125 | Directory.CreateDirectory(ParentDirectory + "\\backup"); 126 | } catch(Exception) 127 | { 128 | } 129 | 130 | try 131 | { 132 | Directory.CreateDirectory(ParentDirectory + "\\backup\\docs"); 133 | } catch(Exception) 134 | { 135 | } 136 | 137 | RegistryKey Root = Registry.ClassesRoot; 138 | 139 | // Over all classes 140 | foreach (String V in Root.GetSubKeyNames()) 141 | { 142 | RegistryKey Command = Registry.ClassesRoot.OpenSubKey(V + "\\Shell\\Open\\command"); 143 | 144 | if(Command != null) 145 | { 146 | try 147 | { 148 | 149 | String Cmdline = ((String)Command.GetValue("")).ToLower(); 150 | 151 | // Check for office 152 | if(Cmdline.Contains("winword.exe") || Cmdline.Contains("excel.exe") || Cmdline.Contains("powerpnt.exe")) 153 | { 154 | Logger.Debug("Try to replace: " + V + " real cmdline is " + Cmdline); 155 | 156 | // Backup 157 | if(!File.Exists(ParentDirectory + "\\backup\\backup_" + V + ".reg")) 158 | { 159 | Helper.LaunchCmd("reg export HKEY_CLASSES_ROOT\\" + V + " " + ParentDirectory + "\\backup\\backup_" + V + ".reg /y"); 160 | } 161 | 162 | // Delete the legacy command and DDEXEC 163 | Helper.LaunchCmd("reg delete HKCR\\" + V + "\\Shell\\Open\\command /v command /f"); 164 | Helper.LaunchCmd("reg delete HKCR\\" + V + "\\Shell\\Open\\ddeexec /f"); 165 | 166 | 167 | // @="\"C:\\Program Files\\Microsoft Office 15\\Root\\Office15\\WINWORD.EXE\" /n \"%1\" /o \"%u\"" 168 | 169 | int i = Cmdline.ToLower().IndexOf(".exe"); 170 | 171 | String App = ""; 172 | String NewPath = ""; 173 | 174 | // Construct new path calling our assembly 175 | if(Cmdline.Contains("winword.exe")) 176 | { 177 | NewPath = "\"" + AssemblyFilePath + "\" /w " + Cmdline.Substring(i+4).Trim('"'); 178 | App = "word"; 179 | } else if(Cmdline.Contains("excel.exe")) 180 | { 181 | NewPath = "\"" + AssemblyFilePath + "\" /e " + Cmdline.Substring(i+4).Trim('"'); 182 | App = "excel"; 183 | } else if(Cmdline.Contains("powerpnt.exe")) 184 | { 185 | NewPath = "\"" + AssemblyFilePath + "\" /p " + Cmdline.Substring(i+4).Trim('"'); 186 | App = "powerpnt"; 187 | } 188 | 189 | if(NewPath.Length != 0) 190 | { 191 | // Special handling for DDE 192 | if(!NewPath.Contains("%1")) 193 | { 194 | NewPath += " \"%1\""; 195 | NewPath = NewPath.Replace("/dde", ""); 196 | } 197 | 198 | NewPath = NewPath.Replace("\"", "\\\""); 199 | 200 | // Overwrite command 201 | Helper.LaunchCmd("reg add HKCR\\" + V + "\\Shell\\Open\\command /ve /d \"" + NewPath + "\" /f"); 202 | 203 | Logger.Info("Successfully installed for: " + V); 204 | } 205 | 206 | // Store real path 207 | if(!File.Exists(ParentDirectory + "\\" + App)) 208 | { 209 | File.WriteAllText(ParentDirectory + "\\" + App, Cmdline.Substring(0, i+4).Trim('"')); 210 | } 211 | } 212 | 213 | } catch(Exception e) 214 | { 215 | Logger.Error("Unable to replace class: " + V, e); 216 | } 217 | } 218 | } 219 | } 220 | 221 | /// 222 | /// Restore registry backups. 223 | /// 224 | private static void RestoreBackup() 225 | { 226 | Logger.Info("Uninstall DocBleachShell"); 227 | 228 | foreach(String F in Directory.GetFiles("backup")) 229 | { 230 | Helper.LaunchCmd("regedit.exe /S " + F); 231 | } 232 | 233 | Logger.Info("Uninstalled"); 234 | } 235 | 236 | 237 | /// 238 | /// Called e.g. by explorer.exe. Missing is to call docbleach and then Office with the bleached document. 239 | /// 240 | /// 241 | private static void Bleach(string[] Args) 242 | { 243 | String OfficePath = ""; 244 | 245 | // Get office path 246 | if(Args[0].Equals("/w")) 247 | { 248 | OfficePath = File.ReadAllText(ParentDirectory + "\\word"); 249 | } else if(Args[0].Equals("/p")) 250 | { 251 | OfficePath = File.ReadAllText(ParentDirectory + "\\powerpnt"); 252 | } else if(Args[0].Equals("/e")) 253 | { 254 | OfficePath = File.ReadAllText(ParentDirectory + "\\excel"); 255 | } 256 | 257 | if(OfficePath.Length != 0) 258 | { 259 | int l = -1; 260 | String AllArgs = ""; 261 | 262 | // Find document path. 263 | for(int i = 1; i < Args.Length; ++i) 264 | { 265 | if(Args[i].Contains("\\")) 266 | { 267 | AllArgs += "\"" + Args[i] + "\" "; 268 | l = i; 269 | } else{ 270 | AllArgs += Args[i] + " "; 271 | } 272 | } 273 | 274 | if(l == -1) 275 | { 276 | Logger.Error("Unable to find document: " + AllArgs); 277 | return; 278 | } 279 | 280 | bool doBleach = false; 281 | 282 | try 283 | { 284 | 285 | // Check ADS Zone 286 | String OnlyBleachInternetFiles = ConfigurationManager.AppSettings["OnlyBleachInternetFiles"]; 287 | 288 | if(bool.Parse(OnlyBleachInternetFiles)) 289 | { 290 | FileInfo F = new FileInfo(Args[l]); 291 | 292 | if (F.AlternateDataStreamExists("Zone.Identifier")) 293 | { 294 | AlternateDataStreamInfo DataStream = F.GetAlternateDataStream("Zone.Identifier", FileMode.Open); 295 | using (TextReader Reader = DataStream.OpenText()) 296 | { 297 | String ADS = Reader.ReadToEnd(); 298 | 299 | if(ADS.Contains("ZoneId=3") || ADS.Contains("ZoneId=4")) 300 | { 301 | doBleach = true; 302 | } 303 | } 304 | } else 305 | { 306 | Logger.Debug("No Zone.Identifier found"); 307 | } 308 | } 309 | 310 | } catch(Exception e) 311 | { 312 | Logger.Error("Unable to check ADS for " + Args[l], e); 313 | } 314 | 315 | if(doBleach) 316 | { 317 | new DocBleachWrapper().Bleach(Args[l], ParentDirectory); 318 | } else 319 | { 320 | Logger.Debug("Do not bleach: " + Args[l] + " not from internet"); 321 | } 322 | 323 | Logger.Debug("Start: " + OfficePath + " " + AllArgs); 324 | 325 | // Call Office with bleached file. 326 | try 327 | { 328 | Process.Start(OfficePath, AllArgs); 329 | } catch(Exception e) 330 | { 331 | Logger.Error("Unable to start office: " + OfficePath + " " + AllArgs, e); 332 | } 333 | } 334 | } 335 | 336 | /// 337 | /// Close the console, sends a final {ENTER} to the parent. 338 | /// 339 | private static void closeConsole() 340 | { 341 | FreeConsole(); 342 | 343 | try 344 | { 345 | // Get parent process 346 | int PID = Process.GetCurrentProcess().Id; 347 | ManagementObjectSearcher Search = new ManagementObjectSearcher("root\\CIMV2", 348 | "SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = " + PID); 349 | var Results = Search.Get().GetEnumerator(); 350 | Results.MoveNext(); 351 | var QueryObj = Results.Current; 352 | uint PPID = (uint)QueryObj["ParentProcessId"]; 353 | Process ParentProcess = Process.GetProcessById((int)PPID); 354 | PostMessage(ParentProcess.MainWindowHandle, WM_KEYDOWN, VK_RETURN, 0); 355 | } catch(Exception) 356 | { 357 | } 358 | } 359 | } 360 | } -------------------------------------------------------------------------------- /DocBleachShell/DocBleachShell/DocBleachShell.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | {6715737E-4832-4FF3-B858-C97957E1C921} 5 | {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 6 | Debug 7 | AnyCPU 8 | WinExe 9 | DocBleachShell 10 | DocBleachShell 11 | v4.0 12 | Properties 13 | OnBuildSuccess 14 | False 15 | False 16 | False 17 | obj\$(Configuration)\ 18 | 4 19 | 20 | 21 | x86 22 | 4194304 23 | False 24 | Auto 25 | 4096 26 | 27 | 28 | bin\Debug\ 29 | True 30 | Full 31 | False 32 | True 33 | DEBUG;TRACE 34 | obj\ 35 | 36 | 37 | bin\Release\ 38 | False 39 | None 40 | True 41 | False 42 | TRACE 43 | 44 | 45 | 46 | 47 | 48 | 49 | K:\Joe Security\projects\Joebox\publicsvn\trunk\libs\c#\log4net.dll 50 | 51 | 52 | 4.0 53 | 54 | 55 | 56 | 57 | 3.5 58 | 59 | 60 | 61 | 3.5 62 | 63 | 64 | 65 | 66 | 3.5 67 | 68 | 69 | Trinet.Core.IO.Ntfs.dll 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /DocBleachShell/DocBleachShell/DocBleachShell.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | # SharpDevelop 5.1 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocBleachShell", "DocBleachShell.csproj", "{6715737E-4832-4FF3-B858-C97957E1C921}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Release|Any CPU = Release|Any CPU 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {6715737E-4832-4FF3-B858-C97957E1C921}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 14 | {6715737E-4832-4FF3-B858-C97957E1C921}.Debug|Any CPU.Build.0 = Debug|Any CPU 15 | {6715737E-4832-4FF3-B858-C97957E1C921}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | {6715737E-4832-4FF3-B858-C97957E1C921}.Release|Any CPU.Build.0 = Release|Any CPU 17 | EndGlobalSection 18 | EndGlobal 19 | -------------------------------------------------------------------------------- /DocBleachShell/DocBleachShell/DocBleachWrapper.cs: -------------------------------------------------------------------------------- 1 | // License: MIT 2 | // Copyright: Joe Security 3 | // Dependencies: - DocBleach https://github.com/docbleach 4 | // - Log4Net https://logging.apache.org/log4net/ 5 | // - Ntfs Streams https://github.com/RichardD2/NTFS-Streams 6 | 7 | using System; 8 | using System.Configuration; 9 | using System.IO; 10 | using System.Threading; 11 | using log4net; 12 | 13 | namespace DocBleachShell 14 | { 15 | /// 16 | /// Wrapper around DocBleach. 17 | /// 18 | public class DocBleachWrapper 19 | { 20 | private static readonly ILog Logger = LogManager.GetLogger(typeof(DocBleachWrapper)); 21 | 22 | /// 23 | /// Bleach the document. 24 | /// 25 | /// 26 | /// 27 | public void Bleach(String FilePath, String TargetDirectory) 28 | { 29 | Logger.Debug("Try to bleach: " + FilePath); 30 | 31 | String CurrentDir = Directory.GetCurrentDirectory(); 32 | 33 | String AppDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\DocBleachShell"; 34 | 35 | // Create backup dir. 36 | try 37 | { 38 | Directory.CreateDirectory(AppDir + "\\backup\\docs"); 39 | } catch(Exception) 40 | { 41 | } 42 | 43 | Directory.SetCurrentDirectory(Directory.GetParent(FilePath).FullName); 44 | 45 | 46 | String MakeBackup = ConfigurationManager.AppSettings["MakeBackup"]; 47 | 48 | if(bool.Parse(MakeBackup)) 49 | { 50 | 51 | try 52 | { 53 | File.Copy(FilePath, AppDir + "\\backup\\docs\\" + Path.GetFileName(FilePath), true); 54 | } catch(Exception e) 55 | { 56 | Logger.Error("Unable to make a backup of the document", e); 57 | } 58 | 59 | } 60 | 61 | // Original doc -> bleach. .... do 62 | 63 | String TmpDoc = Path.GetDirectoryName(FilePath) + "\\bleach." + Path.GetFileName(FilePath); 64 | 65 | try 66 | { 67 | File.Move(FilePath, TmpDoc); 68 | } catch(Exception e) 69 | { 70 | Logger.Error("Unable to rename document: " + FilePath, e); 71 | } 72 | 73 | // Call docbleach which will generate doc 74 | Helper.LaunchCmd("java -jar \"" + TargetDirectory + "\\docbleach.jar\" -in \"" + TmpDoc + 75 | "\" -out \"" + Path.GetFileName(FilePath) + "\" > \"" + AppDir + "\\tmp.log\" 2>&1"); 76 | 77 | String Output = File.ReadAllText(AppDir + "\\tmp.log"); 78 | 79 | Logger.Debug("DocBleach output: " + Output); 80 | 81 | // If the document was bleach "contains potential malicious elements" analyze the file with Joe Sandbox Cloud. 82 | if(!Output.Contains("file was already safe")) 83 | { 84 | String APIKey = ConfigurationManager.AppSettings["JoeSandboxCloudAPIKey"]; 85 | 86 | if(APIKey.Length != 0) 87 | { 88 | new JoeSandboxClient().Analyze(TmpDoc, APIKey); 89 | } 90 | } 91 | else 92 | { 93 | Logger.Debug("Doc not sent to cloud : no API key configured"); 94 | } 95 | // Cleanup & recovery 96 | if(File.Exists(FilePath)) 97 | { 98 | try 99 | { 100 | File.Delete(TmpDoc); 101 | } catch(Exception e) 102 | { 103 | Logger.Error("Unable to delete original file " + TmpDoc, e); 104 | } 105 | Logger.Debug("Successfully bleached: " + FilePath); 106 | } else 107 | { 108 | Logger.Debug("Unable to bleach: " + FilePath); 109 | 110 | // No doc, move back. 111 | try 112 | { 113 | File.Move(TmpDoc, FilePath); 114 | 115 | } catch(Exception e) 116 | { 117 | Logger.Error("Unable to rename document: " + TmpDoc, e); 118 | } 119 | } 120 | 121 | Directory.SetCurrentDirectory(CurrentDir); 122 | 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /DocBleachShell/DocBleachShell/Helper.cs: -------------------------------------------------------------------------------- 1 | // License: MIT 2 | // Copyright: Joe Security 3 | // Dependencies: - DocBleach https://github.com/docbleach 4 | // - Log4Net https://logging.apache.org/log4net/ 5 | // - Ntfs Streams https://github.com/RichardD2/NTFS-Streams 6 | 7 | using System; 8 | using System.Diagnostics; 9 | using System.Security.Principal; 10 | using log4net; 11 | 12 | namespace DocBleachShell 13 | { 14 | /// 15 | /// Helper collection. 16 | /// 17 | public class Helper 18 | { 19 | private static readonly ILog Logger = LogManager.GetLogger(typeof(Helper)); 20 | 21 | /// 22 | /// Helper to call command line (hidden). 23 | /// 24 | /// 25 | public static void LaunchCmd(String cmd) 26 | { 27 | try 28 | { 29 | ProcessStartInfo StartInfo = new ProcessStartInfo(); 30 | 31 | StartInfo.FileName = "cmd.exe"; 32 | StartInfo.Arguments = "/C " + cmd; 33 | StartInfo.RedirectStandardOutput = true; 34 | StartInfo.RedirectStandardError = true; 35 | StartInfo.UseShellExecute = false; 36 | StartInfo.CreateNoWindow = true; 37 | 38 | Process Proc = new Process(); 39 | 40 | Proc.StartInfo = StartInfo; 41 | Proc.EnableRaisingEvents = true; 42 | Proc.Start(); 43 | Proc.WaitForExit(); 44 | 45 | } catch(Exception e) 46 | { 47 | Logger.Error("Unable to start cmd: " + cmd, e); 48 | } 49 | } 50 | 51 | /// 52 | /// Helper to check admin status. 53 | /// 54 | /// 55 | public static bool IsUserAdministrator() 56 | { 57 | bool IsAdmin; 58 | 59 | try 60 | { 61 | WindowsIdentity User = WindowsIdentity.GetCurrent(); 62 | WindowsPrincipal Principal = new WindowsPrincipal(User); 63 | IsAdmin = Principal.IsInRole(WindowsBuiltInRole.Administrator); 64 | } 65 | catch (UnauthorizedAccessException) 66 | { 67 | IsAdmin = false; 68 | } 69 | catch (Exception) 70 | { 71 | IsAdmin = false; 72 | } 73 | 74 | return IsAdmin; 75 | } 76 | 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /DocBleachShell/DocBleachShell/JoeSandboxClient.cs: -------------------------------------------------------------------------------- 1 | // License: MIT 2 | // Copyright: Joe Security 3 | // Dependencies: - DocBleach https://github.com/docbleach 4 | // - Log4Net https://logging.apache.org/log4net/ 5 | // - Ntfs Streams https://github.com/RichardD2/NTFS-Streams 6 | 7 | 8 | using System; 9 | using System.Collections.Specialized; 10 | using System.IO; 11 | using System.Net; 12 | using log4net; 13 | 14 | namespace DocBleachShell 15 | { 16 | /// 17 | /// Minimalistic JoeSandboxClient. Only implements upload functionality. 18 | /// 19 | public class JoeSandboxClient 20 | { 21 | private static readonly ILog Logger = LogManager.GetLogger(typeof(JoeSandboxClient)); 22 | 23 | private const String APIUrl = "https://jbxcloud.joesecurity.org/api/analysis"; 24 | 25 | /// 26 | /// Analyze the file on Joe Sandbox Cloud. 27 | /// 28 | /// 29 | /// 30 | public void Analyze(String FilePath, String APIKey) 31 | { 32 | Logger.Debug("Analyze: " + FilePath + " with Joe Sandbox Cloud"); 33 | 34 | try { 35 | 36 | WebRequest Request = WebRequest.Create(APIUrl); 37 | 38 | string Boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x"); 39 | 40 | Request.Method = "POST"; 41 | Request.Timeout = 15000; 42 | Request.ContentType = "multipart/form-data; boundary=" + Boundary; 43 | 44 | NameValueCollection FormData = new NameValueCollection(); 45 | 46 | FormData["apikey"] = APIKey; 47 | 48 | // Allow full interenet activity. 49 | FormData["inet"] = "1"; 50 | 51 | // Hybrid Code Analysis = true. 52 | FormData["scae"] = "1"; 53 | 54 | // Enable Hybrid Decompilation. 55 | FormData["dec"] = "1"; 56 | 57 | // Enable VBA Macro instrumentation. 58 | FormData["vbainstr"] = "1"; 59 | 60 | FormData["tandc"] = "1"; 61 | FormData["type"] = "file"; 62 | 63 | // Auto system selection. 64 | FormData["auto"] = "1"; 65 | 66 | FormData["comments"] = "Submitted by DocBleachShell"; 67 | 68 | Stream DataStream = getPostStream(FilePath, FormData, Boundary); 69 | 70 | Request.ContentLength = DataStream.Length; 71 | 72 | Stream ReqStream = Request.GetRequestStream(); 73 | 74 | DataStream.Position = 0; 75 | 76 | byte[] Buffer = new byte[1024]; 77 | int BytesRead = 0; 78 | 79 | while ((BytesRead = DataStream.Read(Buffer, 0, Buffer.Length)) != 0) { 80 | ReqStream.Write(Buffer, 0, BytesRead); 81 | } 82 | 83 | DataStream.Close(); 84 | ReqStream.Close(); 85 | 86 | StreamReader Reader = new StreamReader(Request.GetResponse().GetResponseStream()); 87 | Logger.Debug("Joe Sandbox Cloud answer: " + Reader.ReadToEnd()); 88 | Logger.Debug("Successfully submit file to Joe Sandbox Cloud"); 89 | 90 | } catch (Exception e) { 91 | Logger.Error("Unable to analyze file: " + FilePath + " with Joe Sandbox", e); 92 | 93 | } 94 | } 95 | 96 | /// 97 | /// Building form and file data. 98 | /// 99 | /// 100 | /// 101 | /// 102 | /// 103 | private Stream getPostStream(string FilePath, NameValueCollection FormData, string Boundary) 104 | { 105 | Stream PostDataStream = new System.IO.MemoryStream(); 106 | 107 | // Adding form data. 108 | string FormDataHeaderTemplate = Environment.NewLine + "--" + Boundary + Environment.NewLine + 109 | "Content-Disposition: form-data; name=\"{0}\";" + Environment.NewLine + Environment.NewLine + "{1}"; 110 | 111 | foreach (string Key in FormData.Keys) { 112 | byte[] FormItemBytes = System.Text.Encoding.UTF8.GetBytes(string.Format(FormDataHeaderTemplate, 113 | Key, FormData[Key])); 114 | PostDataStream.Write(FormItemBytes, 0, FormItemBytes.Length); 115 | } 116 | 117 | if (FilePath != null) { 118 | 119 | // Adding file data. 120 | FileInfo fileInfo = new FileInfo(FilePath); 121 | 122 | string FileHeaderTemplate = Environment.NewLine + "--" + Boundary + Environment.NewLine + 123 | "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" + 124 | Environment.NewLine + "Content-Type: application/octet-stream; " + Environment.NewLine + Environment.NewLine; 125 | 126 | byte[] FileHeaderBytes = System.Text.Encoding.UTF8.GetBytes(string.Format(FileHeaderTemplate, 127 | "sample", fileInfo.FullName)); 128 | PostDataStream.Write(FileHeaderBytes, 0, FileHeaderBytes.Length); 129 | 130 | FileStream Stream = fileInfo.OpenRead(); 131 | 132 | // Write form + file. 133 | byte[] Buffer = new byte[1024]; 134 | int BytesRead = 0; 135 | 136 | while ((BytesRead = Stream.Read(Buffer, 0, Buffer.Length)) != 0) { 137 | PostDataStream.Write(Buffer, 0, BytesRead); 138 | } 139 | 140 | Stream.Close(); 141 | } 142 | 143 | // Ending. 144 | byte[] EndBoundaryBytes = System.Text.Encoding.UTF8.GetBytes(Environment.NewLine + "--" + Boundary + "--"); 145 | PostDataStream.Write(EndBoundaryBytes, 0, EndBoundaryBytes.Length); 146 | 147 | return PostDataStream; 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /DocBleachShell/DocBleachShell/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | #region Using directives 2 | 3 | using System; 4 | using System.Reflection; 5 | using System.Runtime.InteropServices; 6 | 7 | #endregion 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | [assembly: AssemblyTitle("DocBleachShell")] 13 | [assembly: AssemblyDescription("")] 14 | [assembly: AssemblyConfiguration("")] 15 | [assembly: AssemblyCompany("")] 16 | [assembly: AssemblyProduct("DocBleachShell")] 17 | [assembly: AssemblyCopyright("Copyright Joe Security 2017")] 18 | [assembly: AssemblyTrademark("")] 19 | [assembly: AssemblyCulture("")] 20 | 21 | // This sets the default COM visibility of types in the assembly to invisible. 22 | // If you need to expose a type to COM, use [ComVisible(true)] on that type. 23 | [assembly: ComVisible(false)] 24 | 25 | // The assembly version has following format : 26 | // 27 | // Major.Minor.Build.Revision 28 | // 29 | // You can specify all the values or you can use the default the Revision and 30 | // Build Numbers by using the '*' as shown below: 31 | [assembly: AssemblyVersion("1.0.*")] 32 | -------------------------------------------------------------------------------- /DocBleachShell/DocBleachShell/Trinet.Core.IO.Ntfs.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joesecurity/DocBleachShell/196109a6f634a3ed0d2ecce216dfdf665a536fb0/DocBleachShell/DocBleachShell/Trinet.Core.IO.Ntfs.dll -------------------------------------------------------------------------------- /DocBleachShell/DocBleachShell/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Joe Security 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DocBleachShell 2 | 3 | DocBleachShell is the integration of the great [DocBleach](https://github.com/docbleach/DocBleach) Content Disarm and Reconstruction tool into the Microsoft Windows Shell Handler. 4 | 5 | **By using DocBleachShell documents are automatically disarmed before they are opened by Microsoft Word, Excel or Powerpoint.** As a result end users who have installed DocBleachShell are protected from exploits and malicious macros. DocBleachShell also comes with a [Joe Sandbox Cloud](https://www.joesecurity.org/joe-sandbox-cloud) integration. **Successfully bleached documents are automatically analyzed by Joe Sandbox Cloud**. In Joe Sandbox Cloud users can enable alerts, e.g. automated emails on detection of malicious files. With that CERTs, CIRTS or SOCs are automatically notified if their users where attacked by malicious documents. 6 | 7 | ![DocBleacShell Overview](https://raw.githubusercontent.com/joesecurity/docbleachshell/master/img/shell.png) 8 | 9 | DocBleachShell modifies the Microsoft Windows Shell Handler via the HKEY_CLASSES_ROOT\Type\shell\open\command registry key. 10 | 11 | # License 12 | 13 | Code is developed in C# / .Net 4 and licensed under MIT. 14 | 15 | # Requirements 16 | 17 | * Latest [Microsoft .Net Framework](https://www.microsoft.com/en-us/download/details.aspx?id=53344) 18 | * Latest [Java Runtime Environment](https://java.com/de/download/), make sure that your Java bin directory is part of the PATH environment variable. 19 | 20 | # Installation 21 | 22 | To install DocBleachShell, call **DocBleachShell.exe -install** from an Administrator shell: 23 | 24 | ![DocBleacShell Overview](https://raw.githubusercontent.com/joesecurity/docbleachshell/master/img/install.png) 25 | 26 | DocBleachShell will search and replace all shell handlers for Word, Excel and Powerpoint. For each registry modification a backup is made to the backup folder. After installation do not move DocBleachShell to any other path. To uninstall DocBleachShell call **DocBleachShell.exe -uninstall**: 27 | 28 | ![DocBleacShell Overview](https://raw.githubusercontent.com/joesecurity/docbleachshell/master/img/uninstall.png) 29 | 30 | Once installed, if you open an Office file, DocBleachShell will be started. DocBleachShell will then call DocBleach which will disarm the document. Finally DocBleachShell will start Office to open the disarmed file. 31 | 32 | # Logging 33 | 34 | DocBleachShell uses log4net. The log file is located in the main directory and named "DocBleachShell.log". 35 | 36 | # Configuration 37 | 38 | Configuration of DocBleachShell is controlled via DocBleachShell.exe.config: 39 | 40 | ```xml 41 | 42 | 43 | ... 44 | 45 | ``` 46 | 47 | By default only documents downloaded from the Internet are bleached. This is done via the NTSF ADS Zone.Identifier check. You can turn off this check and bleach any document. To do so change the config "OnlyBleachInternetFiles" to false. 48 | 49 | # Joe Sandbox Cloud Integration 50 | 51 | DocBleachShell offers integration of [Joe Sandbox Cloud](https://www.joesecurity.org/joe-sandbox-cloud). Joe Sandbox Cloud enables to deeply analyze and detect malicious files. The Joe Sandbox Cloud integration can be enabled via DocBleachShell.exe.config, by adding your API Key: 52 | 53 | ```xml 54 | 55 | ... 56 | 57 | 58 | ``` 59 | After that, DocBleachShell will upload any document which DocBleach has disarmed. If the document is safe (i.e. DocBleach did not do any disarming) the document is not uploaded. 60 | 61 | # Links 62 | 63 | * [DocBleach](https://github.com/docbleach/DocBleach) 64 | * [Joe Sandbox Cloud](https://www.joesecurity.org/joe-sandbox-cloud) 65 | 66 | # Author 67 | 68 | Joe Security (@[joe4security](https://twitter.com/#!/joe4security) - [webpage](https://www.joesecurity.org)) 69 | 70 | # Credits 71 | 72 | Kudos to [PunKeel](https://github.com/PunKeel) for the very cool DocBleach project! 73 | -------------------------------------------------------------------------------- /bin/DocBleachShell.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joesecurity/DocBleachShell/196109a6f634a3ed0d2ecce216dfdf665a536fb0/bin/DocBleachShell.exe -------------------------------------------------------------------------------- /bin/DocBleachShell.exe.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /bin/Trinet.Core.IO.Ntfs.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joesecurity/DocBleachShell/196109a6f634a3ed0d2ecce216dfdf665a536fb0/bin/Trinet.Core.IO.Ntfs.dll -------------------------------------------------------------------------------- /bin/docbleach.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joesecurity/DocBleachShell/196109a6f634a3ed0d2ecce216dfdf665a536fb0/bin/docbleach.jar -------------------------------------------------------------------------------- /bin/log4net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joesecurity/DocBleachShell/196109a6f634a3ed0d2ecce216dfdf665a536fb0/bin/log4net.dll -------------------------------------------------------------------------------- /img/install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joesecurity/DocBleachShell/196109a6f634a3ed0d2ecce216dfdf665a536fb0/img/install.png -------------------------------------------------------------------------------- /img/shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joesecurity/DocBleachShell/196109a6f634a3ed0d2ecce216dfdf665a536fb0/img/shell.png -------------------------------------------------------------------------------- /img/uninstall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joesecurity/DocBleachShell/196109a6f634a3ed0d2ecce216dfdf665a536fb0/img/uninstall.png --------------------------------------------------------------------------------