How to escape characters in WMI query - c#

I tried to use the following code to create WMI query:
string query = "ASSOCIATORS OF {Win32_DiskDrive.PNPDeviceID='" + device["PNPDeviceID"].ToString().Replace(#"\", #"\\")
+ "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition";
But if the query variable looks like ASSOCIATORS OF {Win32_DiskDrive.PNPDeviceID='USBSTOR\\DISK&VEN_FLASH&PROD_DRIVE_SM_USB20&REV_1100\\7214030310011150&0'} WHERE AssocClass = Win32_DiskDriveToDiskPartition it gives me "Invalid object path" exception.
Why? What am I doing wrong? How can I fix it?
What is the appropriate way to escape all characters in the WMI query then?
Thanks in advance.

Wrong property chosen to query ASSOCIATORS OF. The Win32_DiskDriveToDiskPartition class represents an association between a disk drive and a partition existing on it with next relational properties:
==>wmic path Win32_DiskDriveToDiskPartition get /value
Antecedent="\\PC\root\cimv2:Win32_DiskDrive.DeviceID="\\.\PHYSICALDRIVE1""
Dependent="\\PC\root\cimv2:Win32_DiskPartition.DeviceID="Disk #1, Partition #0""
Antecedent="\\PC\root\cimv2:Win32_DiskDrive.DeviceID="\\.\PHYSICALDRIVE1""
Dependent="\\PC\root\cimv2:Win32_DiskPartition.DeviceID="Disk #1, Partition #1""
Antecedent="\\PC\root\cimv2:Win32_DiskDrive.DeviceID="\\.\PHYSICALDRIVE0""
Dependent="\\PC\root\cimv2:Win32_DiskPartition.DeviceID="Disk #0, Partition #0""
==>
Hence, using the "Where AssocClass = Win32_DiskDriveToDiskPartition" clause, you could query ASSOCIATORS OF either
string query = "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + dd_ID
+ "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition";
or
string query = "ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" + pp_ID
+ "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition";
Here, with respect to the above scenario (see wmic output):
dd_ID could be either
"\\.\PHYSICALDRIVE0" or
"\\.\PHYSICALDRIVE1" (two-items collection returned, of course) and
pp_ID could be either
"Disk #0, Partition #0" or
"Disk #1, Partition #0" or
"Disk #1, Partition #1".
I have tested above queries in all data combinations in VBScript and hope it should work in c# as well (exclusively of there could come necessity of escaping backslashes in c#).

Related

How to generate strings that are not vulnerable to SQL injection

I have a utility that generates query strings, but the static code analyzers (and my coworkers) are complaining because of risk of "SQL Injection Attack".
Here is my C# code
public static string[] GenerateQueries(string TableName, string ColumnName)
{
return new string[] {
"SELECT * FROM " + TableName,
"SELECT * FROM " + TableName + " WHERE 1=2",
"SELECT * FROM " + TableName + " WHERE [" + TableName + "Id] = #id",
"SELECT * FROM " + TableName + " WHERE [" + TableName + "Id] = IDENT_CURRENT('" + TableName + "')",
"SELECT * FROM " + TableName + " WHERE [" + ColumnName + "] = #value"
};
}
In the code I always call it only with constant strings, such as
var queryList = GenerateQueries("Person", "Name");
Is there any way to rewrite this function so that it is "safe"? For example, if I were using C instead of C#, I could write a macro to generate the strings safely.
At the moment, the only choice I have is to copy/paste this block of SELECT statements for every single table, which is ugly and a maintenance burden.
Is copy/paste really my only option?
EDIT:
Thank you for the replies, esp William Leader. Now I see that my question is wrong-headed. It isn't just the fact that I am concatenating query strings, but also storing them in a variable. The only proper way to do this is to construct the SqlDataAdapter using a constant such as,
var adapter = new SqlDataAdapter("SELECT * FROM PERSON");
There is no other choice. So yes, there will be a lot of copy/paste. I'm starting to regret not using EF.
I was shocked at first, but on reflection this is no different than having an SQL statement already in your code that looks like this:
"SELECT * FROM Person"
We do that kind of thing all the time.
IF
There's an important caveat here. That only remains true if you can control how the function is called. So if this method is a private member of a data layer class somewhere, you might be okay. But I also wonder how useful this really is. It seems like you're not saving much over what you'd get from just writing the queries.
Additionally, it's not good to be in the habit of ignoring your static analysis tools. Sometimes they give you stuff you just know is wrong, but you change it anyway so that when they do find something important you're not conditioned to ignore it.
What your Code analyser is telling you is that you should most likely be calling a procedure with some parameters instead of sending SQL across the wire.
It does not mater a single bit whether or not you use a macro to generate your SQL statements, if you are sending raw SQL across the wire you are open to SQL Injection Attacks
Sending SQL commands to an endpoint making a non sanctioned call. If we fire up a network packet sniffer, we can see that you have a database configured to allow SQL commands to be sent, so we can inject illegal SQL into the system
You could still rely on a single procedure for calling your updates, but if you elect to move to procedures, why would you want to do that?
EDITED to provide an example
create PROC sp_CommonSelectFromTableProc #tableName varchar(32)
AS
-- code to check the tableName parameter does not contain SQL and/or is a valid tableName
-- your procedure code here will probable use
-- exec mydynamicSQLString
-- where mydynamicSQLString is constructed using #tableName
END;
or maybe a table specific procedure
create PROC sp_SelectFromSpecificTableProc
AS
SELECT * FROM SpecificTable
END;
What is important to remember is that SQL injection is independent of the technology used for the underlying application.
It is just overt when the application contains such constructs as
return new string[] {
"SELECT * FROM " + TableName,
"SELECT * FROM " + TableName + " WHERE 1=2",
"SELECT * FROM " + TableName + " WHERE [" + TableName + "Id] = #id",
"SELECT * FROM " + TableName + " WHERE [" + TableName + "Id] = IDENT_CURRENT('" + TableName + "')",
"SELECT * FROM " + TableName + " WHERE [" + ColumnName + "] = #value"
SQL Injection must be addressed at both ends of the data channel.
Here is a pretty good starting point for understanding how to mitigate for SQL Injection attacks

Same query showing different result when used as string in C#

SQL Query
SELECT [ServerName]+ '\' + PARSENAME(REPLACE([Instance],'\','.'), 1) AS SIN,DATE FROM [DBReports].[dbo].[Accesslevelreport]
C# query
"SELECT [ServerName]+ '\' + PARSENAME(REPLACE([Instance],'\','.'), 1) AS SIN,DATE FROM [DBReports].[dbo].[Accesslevelreport]";
I want to convert it in C# but results are different as compared to running in SQL
Results from SQL= ANDSQLP47\DWMOD
Results from C#= ANDSQLP47ANDSQLP47\DWMOD
Expected Result
Data in [ServerName]= ANDSQLP47
Data in [Instance] =ANDSQLP47\DWMOD
SIN column will contain the Server Name and Instance Name, separated with a backslash ('\'). If the
instance field read from the database contains a slash in the text ('\'), remove
the slash and everything to the left of it before combining the fields for the
SIN column of the spreadsheet (only truncate this for processing - nothing
changes in the database).
For example : If the instance field contains
'ANDSQLP47\CTOPROD8R2', then truncate that to 'CTOPROD8R2' before
combining it with the ServerName field.
Just escape your query.
var query = #"SELECT [ServerName]\PARSENAME(REPLACE([Instance],'\','.'), 1) AS SIN,DATE" +
"FROM [DBReports].[dbo].[Accesslevelreport]";
or
var query = #"
SELECT [ServerName]\PARSENAME(REPLACE([Instance],'\','.'), 1) AS SIN, DATE
FROM [DBReports].[dbo].[Accesslevelreport]
";

Not sure if this is even possible, using if statement inside string sql variable

I have a long sql query string saved into a variable.
1 sSQL ="select a bunch of stuff from multiple tabled" +
2 "where conditions are met" +
3 "and other conditions are met" +
4 "order by these columns";
What I now need to do is to add a line between 3 and 4 that is an if statement. Or I need to figure out some other method that doesn't involved me putting two massive sql blocks of code which is mostly redundant except for one single line.
The Code needed:
if (proSeries)
{
"unique sql code to add only if proSeries is true" +
}
It doesn't like the block inside the string. The only other way I can think of doing it is just copying the whole sql string into two separate variables and putting them into the if/else.
You can't have conditional logic within a variable declaration. You can however, take advantage of StringBuilder:
StringBuilder sqlText = new StringBuilder();
sqlText.AppendLine("select a bunch of stuff from multiple tabled");
...
if (proSeries)
{
sqlText.AppendLine("unique sql code to add only if proSeries is true");
}
sqlText.AppendLine("order by these columns");
string finalText = sqlText.ToString();
You could easily wrap that in a function call if you will run it a lot.
When it comes to having multiple conditions, I sometimes do the following, which I consider quite readable:
sSQL = "select a bunch of stuff from multiple tables " +
"where conditions are met " +
"#AND_PROSERIES_CRITERIA# " +
"and other conditions are met " +
"order by these columns ";
// Build all criteria strings
String sProSeriesCriteria = (proSeries) ? "and ....." : "";
// Insert all criteria
sSQL = sSQL.Replace("#AND_PROSERIES_CRITERIA#", sProSeriesCriteria);
Well, the effect is better with more criteria, e.g. select all orders
from all suppliers or just certain ones AND
for all products or just certain ones AND
for which exist or not exist returns in another table
...
You get the idea. With many such optional criteria, you still write a query that is readable and then you work out the parts.

Entity framework SqlQuery execute query with repeated parameter

I'm having troubles trying to execute a SQL query with repeated parameters using entity framework.
The query is a keyword search, that looks in different tables, therefore using the same parameter many times. I'm using LIKE statements (yes, I know I should be using FULLTEXTSEARCH, but I don't have time for that right now).
I've tried all the syntax explained here: How to use DbContext.Database.SqlQuery<TElement>(sql, params) with stored procedure? EF Code First CTP5 and none of them make the query work (I get zero returned rows).
I even tried building a string array in runtime, with length equal to the number of times the parameter repeats in the query, and then populating all the elements of the array with the keyword search term. Then I passed that as the object[] parameters. Didn't work either.
The only thing that works is to make a search&replace that is obviously a bad idea because the parameter comes from a text input, and I'll be vulnerable to SQL injection attacks.
The working code (vulnerable to SQL injection attacks, but the query returns rows):
//not the real query, but just for you to have an idea
string query =
"SELECT Field1, " +
" Field2 " +
"FROM Table1 " +
"WHERE UPPER(Field1) LIKE '%{0}%' " +
"OR UPPER(Field2) LIKE '%{0}%'";
//keywordSearchTerms is NOT sanitized
query = query.Replace("{0}", keywordSearchTerms.ToUpper());
List<ProjectViewModel> list = null;
using (var context = new MyContext())
{
list = context.Database.SqlQuery<ProjectViewModel>(query, new object[] { }).ToList();
}
return list;
I'm using ASP.NET MVC 4, .NET 4.5, SQL Server 2008 and Entity Framework 5.
Any thoughts on how to make the SQLQuery<> method populate all the occurrences of the parameter in the query string? Thank you very much for your time.
Try this:
string query =
#"SELECT Field1,
Field2
FROM Table1
WHERE UPPER(Field1) LIKE '%' + #searchTerm + '%'
OR UPPER(Field2) LIKE '%' + #searchTerm + '%'";
context.SqlQuery<ProjectViewModel>(query, new SqlParameter("#searchTerm", searchTerm)).ToList();
You can use parameters in your query. Something like this
string query =
"SELECT Field1, " +
" Field2 " +
"FROM Table1 " +
"WHERE UPPER(Field1) LIKE #searchTerm" +
"OR UPPER(Field2) LIKE #searchTerm";
string search= string.Format("%{0}%", keywordSearchTerms);
context.SqlQuery<ProjectViewModel>(query, new SqlParameter("#searchTerm", search)).ToList();
how about try this
string query =
string.Format("SELECT Field1, Field2 FROM Table1 WHERE UPPER(Field1) LIKE '%{0}%'
OR UPPER(Field2) LIKE '%{0}%'",keywordSearchTerms.ToUpper());
context. Database.SqlQuery< ProjectViewModel >(query)

using like operand

i have this sql query
"select * from table where name like ?"
but I want it to work as
"select * from table where name like ?* "
what is the query please
I am using access with c#
Add * to your parameter. I.e., instead of
myCommand.Parameters.AddWithValue("#search", searchValue);
use
myCommand.Parameters.AddWithValue("#search", searchValue + "*");
Keep your SQL as it is.
If you want to do a wildcard search (instead of a "literal *"), note that ADO.NET uses %, not *:
myCommand.Parameters.AddWithValue("#search", searchValue + "%");

Categories