Help me to secure this form process. 200+ SQLi possibilities

Discussions of secure PHP coding. Security in software is important, so don't be afraid to ask. And when answering: be anal. Nitpick. No security vulnerability is too small.

Moderator: General Moderators

Post Reply
synical21
Forum Contributor
Posts: 150
Joined: Tue Jul 28, 2009 8:44 am
Location: London UK

Help me to secure this form process. 200+ SQLi possibilities

Post by synical21 »

Hello Gurus, I have been working on a web application for a few months now and the site is nearly complete. I now find myself worrying and trying to fix security issues within the application. I understand the basics about never trusting information from the user and it must always be cleaned, i have also tried to use a token system. I would just like some help on this one script because I ran a web vulnrability scanner and found 3 very weak pages. So if you can help me fix one i can fix the other two.

So here is the form where users input data:

Code: Select all

 
<?php
session_start();
 
function generateToken($seed='mysupermagnificentkey')
    {
        $token = md5($seed.mktime());
        $_SESSION['token']=$token;
        return $token;
    }
generateToken();
?>
 

Code: Select all

 
            <form method="POST" action="proofsend.php">
            <textarea rows="10" name="proof" cols="60"></textarea></b></p>
 
<!--hidden values saving information about the current user -->
 
 <input name="userproof_id" type="hidden" value="<? echo $_SESSION['user_id'] ;?>">
 
 
<!--hidden values saving information about the job information -->
 
            <input name="createuser_id2" id="createuser_id2" type="hidden" value="<? echo $row['createuser_id'] ;?>" />
            <input name="perperson" id="perperson" type="hidden" value="<? echo $row['perperson'] ;?>" />
            <input name="job_id" id="job_id" type="hidden" value="<? echo $my_id ;?>" />
            <input name="title" type="hidden" value="<? echo $row['title'] ;?>">
             <input name="amountworkers" id="amountworkersn" type="hidden" value="<? echo $row['amountworkers'] ;?>" />
            <input type="submit" value="Submit Proof" name="submit"></p>
          </form>
 
Nothing out of the ordinary there I dont think, I dont know if that is the correct way to generate a form token as i learnt off tutorials.

Now the data is sent to proofsend.php and this is where the security issues are, i will just paste the whole code its pretty ashamful i guess:

Code: Select all

 
<?php
// Check the form token
 
if(isset($_POST['job_id']) && isset($_POST['userproof_id']) && isset($_POST['proof']) && isset($_POST['title']) && isset($_POST['perperson']) && isset($_POST['amountworkers']) && isset($_POST['createuser_id2']))
{
    if($_POST['token'] != $_SESSION['token'])
    {
        die('Token is invalid');
    }
    
    // token is now valid, process rest of form
 
$tbl_name = 'proof';
 
//Function definition
function onlyLetters($str){
   $text = str_replace("\n", "xyxy", $str);
   $pattern = '/[^0-9a-zA-Z-. ]*/';
   $text = preg_replace($pattern, '', $text);
  return str_replace("xyxy", "\n", $text);
}
function onlyNumbers($str){
        $pattern = '/[^0-9.]*/';
        return preg_replace($pattern, '', $str);
}
 
   
// Get and strip values  from form 
$job_id=onlyLetters($_POST['job_id']);
$userproof_id=onlyLetters($_POST['userproof_id']);
$proof=onlyLetters($_POST['proof']);
$title=onlyLetters($_POST['title']);
$perperson=onlyLetters($_POST['perperson']);
$createuser_id2=onlyLetters($_POST['createuser_id2']);
 
 
 $query = "SELECT proof.* FROM proof WHERE proof.userproof_id ='$_SESSION[user_id]' and proof.job_id =$job_id";
 $result = mysql_query($query);
 $num_rows = mysql_num_rows($result);
    
    if ($num_rows != 0){die("You have already completed this job. Please try another job.");
    
    }else{
        
// Get and strip values  from form again ... probably not needed.
$job_id=onlyLetters($_POST['job_id']);
$userproof_id=onlyLetters($_POST['userproof_id']);
$proof=onlyLetters($_POST['proof']);
$title=onlyLetters($_POST['title']);
$perperson=onlyLetters($_POST['perperson']);
$createuser_id2=onlyLetters($_POST['createuser_id2']);
 
 
// Insert data into mysql 
$sql="INSERT INTO $tbl_name(job_id, userproof_id, proof, title, perperson, createuser_id2, date)VALUES('$job_id', '$userproof_id', '$proof','$title','$perperson','$createuser_id2',NOW())";
$result=mysql_query($sql);
 
 
 
 
 
// message to creator
$title = "A worker has completed your job.";
$to = "$createuser_id2";
$message = 
"We are happy to inform you that a worker has completed your job. Please head over to the My Jobs section in the employers menu to view the proof submitted, once there you can approve or deny the proof given depending on if the worker has done what is required. \n <br />
<br />
Please note if you mark a workers proof as unexceptable when the proof is what is required your account will be deleted and IP banned.<br />
<br />
If you have any problems dont hesitate to contact us by using the report feature on the My Account page or through forums.";
 
// now insert message into database
$sql2 = "INSERT INTO messages SET `to` = '".$to."', `title` = '".$title."', `message` = '".$message."', `created` = NOW()";
      $result = mysql_query($sql2)
     or die('Invalid query: ' . $sql2 . ' - Error is ' . mysql_error());
 
// run process, update values in the database.
     
    $sql = "SELECT `fulldata`.*
   FROM `fulldata`
  WHERE fulldata.job_id = $job_id";
$result = mysql_query($sql)
     or die('Invalid query: ' . $sql . ' - Error is ' . mysql_error());
     
$sql = "UPDATE `fulldata`
    SET amountworkers = amountworkers - 1
  WHERE fulldata.job_id = $job_id";
 $result = mysql_query($sql)
     or die('Invalid query: ' . $sql . ' - Error is ' . mysql_error());
     
     $sql = "UPDATE `fulldata`
    SET amountcomplete = amountcomplete + 1
  WHERE fulldata.job_id = $job_id";
 $result = mysql_query($sql)
     or die('Invalid query: ' . $sql . ' - Error is ' . mysql_error());
     
     // is the job complete now?
 
$workers = mysql_real_escape_string($_POST['amountworkers']);    
    
    if ($workers == 1)
     {
         $sql = "UPDATE `fulldata`
    SET completedjob = 1
  WHERE fulldata.job_id = $job_id";
 $result = mysql_query($sql)
     or die('Invalid query: ' . $sql . ' - Error is ' . mysql_error());
     }
 
 
// if successfully insert data into database, displays message "Successful". 
if($result){
echo "Your proof has now been sent to the employer, When approved you will recieve money.";
echo "<BR>";
echo "<a href='/jobs.php'>Click here to go back to miniworkers</a>";
echo "$workers";
}
 
else {
echo "ERROR";
}
 
    }
    
    
?>
 
As you can see i have used a function to filter the data, this is something i learned as i was learning php and before i even knew about mysql_real_escape string. Would it be better to scrap the function validating the post data and replace it with mysql_real_escape_string?

Now for the vulnrabilities i need help fixing in this script.

1) SQLi: There are about 200+ different types input not just using (JyI%3D) of SQLi what can be used on this script here are the variables effected though:

The POST variable userproof_id has been set to JyI%3D.
The POST variable amountworkers has been set to JyI%3D.
The POST variable proof has been set to JyI%3D.
The POST variable Id has been set to %00'. (Where is Id =/)
The POST variable job_id has been set to '.
The POST variable createuser_id2 has been set to '.

So I presume my function fails horribly to clean the data? mysql_real_escape_string should be used maybe?

2)SQLi Cookies:

The Cookie variable user_name has been set to %00'. (A cookie i created)
The Cookie variable __utmc has been set to %2527. (Not my cookie i think its forum cookie)
The Cookie variable phpbb3_q529l_k has been set to %00'. (Not my cookie i think its forum cookie)

Need some guidence on this as i dont even know how cookie manipulation can be prevented.

3) SQLi Headers:

The HTTP header referer has been set to \'.
The HTTP header user-agent has been set to '.
The HTTP header x-forwarded-for has been set to '.
The HTTP header accept-language has been set to \".

There is more but you get the drift, how can i prevent a SQLi from injecting the headers? This sounds like the worst one.

Thats the exploits!(you will be glad if your reading)


Im not asking for my script to be rewritten by you, I just care about the security and would like the knowledge to fix these security issues.
vanguard
Forum Newbie
Posts: 13
Joined: Mon Jan 11, 2010 9:10 am

Re: Help me to secure this form process. 200+ SQLi possibilities

Post by vanguard »

Hi,
I wouldn't bother to use web vulnerability scanners to secure your website. They are renowned in the security industry for giving unreliable results. If you do want to use one, I would recommend nessus as it seems to be pretty good.

These warnings are simply untrue. Your functions strip all non-alphanumeric characters, leaving no avenue for SQL injection as you have placed single-quotes around your variables in the query. I wouldnt worry about the HTTP header warnings either as your app does not make use of them.

Hope that helps,
Alex
Post Reply