├── 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 | 
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 | 
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 | 
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
--------------------------------------------------------------------------------