• (cs)

    What language is this or how can you make this work? Why would you prefer it?

       
    for (int i = 1; i <= Strings.Len(WhichField); i++)
        string str = Strings.Mid(WhichField, i, 1);
    
  • (cs) in reply to jsgbrl
    jsgbrl:
    What language is this or how can you make this work? Why would you prefer it?
       
    for (int i = 1; i <= Strings.Len(WhichField); i++)
        string str = Strings.Mid(WhichField, i, 1);
    

    It's (most likely) C# using the Microsoft.VisualBasic library. You would use this if you were a VB programmer who is using C# and not familiar with .Net String methods.

  • Jesse Donat (unregistered)

    Haha, we have a nearly identical method in one of our shopping cart applications.

    function RemoveXSS($val) {
    	// remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed
    	// this prevents some character re-spacing such as <java\0script>
    	// note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs
    	$val = preg_replace('/([\x00-\x08][\x0b-\x0c][\x0e-\x20])/', '', $val);
    
    	// straight replacements, the user should never need these since they're normal characters
    	// this prevents like [image]
    	$search = 'abcdefghijklmnopqrstuvwxyz';
    	$search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    	$search .= '1234567890!@#$%^&*()';
    	$search .= '~`";:?+/={}[]-_|\'\\';
    	for ($i = 0; $i < strlen($search); $i++) {
    		// ;? matches the ;, which is optional
    		// 0{0,7} matches any padded zeros, which are optional and go up to 8 chars
    
    		// @ @ search for the hex values
    		$val = preg_replace('/(&#[xX]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ;
    		// @ @ 0{0,7} matches '0' zero to seven times
    		$val = preg_replace('/(&#0{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ;
    	}
    
    	// now the only remaining whitespace attacks are \t, \n, and \r
    	$ra1 = Array('javascript', 'vbscript', 'expression', 'applet', 'meta ', 'blink', 'link ', 'style', 'script', 'embed ', 'object ', 'iframe', 'frame ', 'frameset', 'ilayer', 'layer ', 'bgsound', 'title', 'base ');
    	$ra2 = Array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload');
    	$ra = array_merge($ra1, $ra2);
    
    	$found = true; // keep replacing as long as the previous round replaced something
    	while ($found == true) {
    		$val_before = $val;
    		for ($i = 0; $i < sizeof($ra); $i++) {
    			$pattern = '/';
    			for ($j = 0; $j < strlen($ra[$i]); $j++) {
    				if ($j > 0) {
    					$pattern .= '(';
    					$pattern .= '(&#[xX]0{0,8}([9ab]);)';
    					$pattern .= '|';
    					$pattern .= '|(&#0{0,8}([9|10|13]);)';
    					$pattern .= ')*';
    				}
    				$pattern .= $ra[$i][$j];
    			}
    			$pattern .= '/i';
    			$replacement = substr($ra[$i], 0, 2).'<x>'.substr($ra[$i], 2); // add in <> to nerf the tag
    			$val = preg_replace($pattern, $replacement, $val); // filter out the hex tags
    			if ($val_before == $val) {
    				// no replacements were made, so exit the loop
    				$found = false;
    			}
    		}
    	}
    	return $val;
    }
    
  • Tharg (unregistered)

    Jaime,

    I like the way you say that for your sql injection attack of a stored procedure to work, you first have to do some sql injection. Ever heard of circular logic?

    I call BS - yet again.....

  • (cs) in reply to Tharg
    Tharg:
    Jaime,

    I like the way you say that for your sql injection attack of a stored procedure to work, you first have to do some sql injection. Ever heard of circular logic?

    I call BS - yet again.....

    Here is an extremely naive block of C# that both uses stored procedures and is vulnerable to SQL injection:

    using (System.Data.SqlClient.SqlConnection c = new System.Data.SqlClient.SqlConnection("Data Source=localhost;Initial Catalog=injectiontest;Integrated Security=SSPI"))
    {
      System.Data.SqlClient.SqlCommand cmd = c.CreateCommand();
      cmd.CommandText = "EXEC GetEmployeeData " + EmployeeIDTextBox.Text;
      DataSet ds = new DataSet();
      System.Data.SqlClient.SqlDataAdapter da = new System.Data.SqlClient.SqlDataAdapter(cmd);
      da.Fill(ds);
      EmployeeDataGridView.AutoGenerateColumns = true;
      EmployeeDataGridView.DataSource = ds.Tables[ds.Tables.Count - 1];
    }
    

    To attack it, first put "1 SELECT * FROM sysobjects" into the text box. This will list all of the procedures in the database. Then choose a juicy procedure and type "1 SELECT * FROM syscolumns WHERE id = OBJECT_ID('<procedurename>')" into the text box. You will now have all of the parameters for the procedure.

    I do realize that this code is horrible. But it does use stored procedures and using stored procedures is not enough to get over the fact that is doesn't parameterize the call. Parameterization is the only effective way to prevent SQL injection. Once you parameterize, it is not necessary to use procedures to protect from SQL injection, because you are already protected.

  • Tharg (unregistered)

    Jaime,

    I see what you're driving at, but that will fail to inject a stored procedure. Since (in your example) the procedure will have the passed in value defined as an ID, anything else will fail to run. That's the beauty of stored procedures, you can only pass in valid values, anything else fails.

    I work in oracle, and would gladly post an example, if you would like (although it's similar to sql server).

  • (cs) in reply to Tharg
    Tharg:
    Jaime,

    I see what you're driving at, but that will fail to inject a stored procedure. Since (in your example) the procedure will have the passed in value defined as an ID, anything else will fail to run. That's the beauty of stored procedures, you can only pass in valid values, anything else fails.

    I work in oracle, and would gladly post an example, if you would like (although it's similar to sql server).

    I ran the application and successfully injected SQL. Some of the horrible code was made extra horrible so that the injection would be easy. For example ...

    EmployeeDataGridView.DataSource = ds.Tables[ds.Tables.Count - 1];

    ... was purposely coded as "the last Table" instead of "Table 0" so that the result of the injected SQL would display on the screen. This is not hypothetical code, this is an excerpt from an application that I built and ran specifically to prove that it is possible to inject SQL into a stored procedure call. Would you like screen shots?

  • Hans (unregistered)

    2=2 works equally well... just saying.

  • Tharg (unregistered)

    Jaime,

    in my stored-procedures-only world, the count of tables would be derived from a stored procedure. Bear in mind that nobody would have access to the data schema itself, and would be unable to count anything. ALL access would be via a different account, which would only be able to execute stored procedures.

    I neglected to mention that without such protection (which I had assumed was implicit) the stored procedures can always be by-passed.

    I therefore amend my assertion to be that

    "Provided no alternative means of access is possible, a stored procedure interface can't be SQL injected, because there's no SQL to inject"

    T

  • (cs) in reply to Tharg
    Tharg:
    Jaime,

    in my stored-procedures-only world, the count of tables would be derived from a stored procedure. Bear in mind that nobody would have access to the data schema itself, and would be unable to count anything. ALL access would be via a different account, which would only be able to execute stored procedures.

    I neglected to mention that without such protection (which I had assumed was implicit) the stored procedures can always be by-passed.

    I therefore amend my assertion to be that

    "Provided no alternative means of access is possible, a stored procedure interface can't be SQL injected, because there's no SQL to inject"

    T

    Let me say it again... My application works. No extra permissions are necessary. SELECT * FROM sysobjects works in SQL Server even if you have no access to user tables. The Oracle equivalent would be SELECT * FROM ALL_OBJECTS.

    As for the account access, injection happens via the application, so it has all the rights of the application account. This means any injected code can run any stored procedure. In an application where all data modification are done via stored procedures, it naturally follows that there are stored procedure to perform any reasonably conceivable data modification. The injected SQL can therefore effectively modify all data.

    Addendum (2010-03-11 08:57): Also... There is SQL, stored procedures are executed with the "EXECUTE" SQL statement. In any context that SELECT is valid, EXECUTE is also valid.

  • TNK (unregistered)

    UNION ALL is another one they missed at a quick glance, haha... either way, badly coded way to 'sanitize' queries against injection.

  • eagle275 (unregistered) in reply to sprained

    what's so hard - use prepared Statements and you can forget about SQL-injections alltogether, because then:

    • string parameters are automatically escaped and contained in quotes
    • integers and decimals are treated as numbers, so you should put those via (int)/(float)/(double) or matching type-conversions in the query .. It's really not that hard to prevent SQL-injections

Leave a comment on “Injection Proof'd”

Log In or post as a guest

Replying to comment #:

« Return to Article