Skip to content
This repository was archived by the owner on Nov 3, 2023. It is now read-only.

Commit c18a3c4

Browse files
committed
Prevent SQL injections in the back end search panel (see CVE-2017-16558).
1 parent cd60927 commit c18a3c4

File tree

3 files changed

+80
-65
lines changed

3 files changed

+80
-65
lines changed

system/docs/CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
Contao Open Source CMS changelog
22
================================
33

4+
Version 3.5.31 (2017-11-15)
5+
---------------------------
6+
7+
### Fixed
8+
Prevent SQL injections in the back end search panel (see CVE-2017-16558).
9+
10+
411
Version 3.5.30 (2017-10-06)
512
---------------------------
613

system/modules/core/drivers/DC_Table.php

+19-9
Original file line numberDiff line numberDiff line change
@@ -4943,23 +4943,33 @@ protected function searchMenu()
49434943
// Store search value in the current session
49444944
if (\Input::post('FORM_SUBMIT') == 'tl_filters')
49454945
{
4946-
$session['search'][$this->strTable]['value'] = '';
4947-
$session['search'][$this->strTable]['field'] = \Input::post('tl_field', true);
4946+
$strField = \Input::post('tl_field', true);
4947+
$strKeyword = ltrim(\Input::postRaw('tl_value'), '*');
4948+
4949+
if ($strField && !in_array($strField, $searchFields, true))
4950+
{
4951+
$strField = '';
4952+
$strKeyword = '';
4953+
}
49484954

49494955
// Make sure the regular expression is valid
4950-
if (\Input::postRaw('tl_value') != '')
4956+
if ($strField && $strKeyword)
49514957
{
49524958
try
49534959
{
4954-
$this->Database->prepare("SELECT * FROM " . $this->strTable . " WHERE " . \Input::post('tl_field', true) . " REGEXP ?")
4960+
$this->Database->prepare("SELECT * FROM " . $this->strTable . " WHERE " . $strField . " REGEXP ?")
49554961
->limit(1)
4956-
->execute(\Input::postRaw('tl_value'));
4957-
4958-
$session['search'][$this->strTable]['value'] = \Input::postRaw('tl_value');
4962+
->execute($strKeyword);
4963+
}
4964+
catch (\Exception $e)
4965+
{
4966+
$strKeyword = '';
49594967
}
4960-
catch (\Exception $e) {}
49614968
}
49624969

4970+
$session['search'][$this->strTable]['field'] = $strField;
4971+
$session['search'][$this->strTable]['value'] = $strKeyword;
4972+
49634973
$this->Session->setData($session);
49644974
}
49654975

@@ -5060,7 +5070,7 @@ protected function sortMenu()
50605070
$strSort = \Input::post('tl_sort');
50615071

50625072
// Validate the user input (thanks to aulmn) (see #4971)
5063-
if (in_array($strSort, $sortingFields))
5073+
if (in_array($strSort, $sortingFields, true))
50645074
{
50655075
$session['sorting'][$this->strTable] = in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$strSort]['flag'], array(2, 4, 6, 8, 10, 12)) ? "$strSort DESC" : $strSort;
50665076
$this->Session->setData($session);

system/modules/listing/modules/ModuleListing.php

+54-56
Original file line numberDiff line numberDiff line change
@@ -96,56 +96,56 @@ protected function compile()
9696
return;
9797
}
9898

99-
100-
/**
101-
* Add the search menu
102-
*/
99+
// Add the search menu
103100
$strWhere = '';
104101
$varKeyword = '';
105102
$strOptions = '';
103+
$strSearch = \Input::get('search');
104+
$strFor = \Input::get('for');
105+
$arrFields = trimsplit(',', $this->list_fields);
106+
$arrSearchFields = trimsplit(',', $this->list_search);
106107

107108
$this->Template->searchable = false;
108-
$arrSearchFields = trimsplit(',', $this->list_search);
109109

110110
if (!empty($arrSearchFields) && is_array($arrSearchFields))
111111
{
112112
$this->Template->searchable = true;
113113

114-
if (\Input::get('search') && \Input::get('for'))
114+
if ($strSearch && !in_array($strSearch, $arrSearchFields, true))
115+
{
116+
$strSearch = '';
117+
$strFor = '';
118+
}
119+
120+
if ($strSearch && $strFor)
115121
{
116-
$varKeyword = '%' . \Input::get('for') . '%';
117-
$strWhere = (!$this->list_where ? " WHERE " : " AND ") . \Input::get('search') . " LIKE ?";
122+
$varKeyword = '%' . $strFor . '%';
123+
$strWhere = (!$this->list_where ? " WHERE " : " AND ") . $strSearch . " LIKE ?";
118124
}
119125

120126
foreach ($arrSearchFields as $field)
121127
{
122-
$strOptions .= ' <option value="' . $field . '"' . (($field == \Input::get('search')) ? ' selected="selected"' : '') . '>' . (strlen($label = $GLOBALS['TL_DCA'][$this->list_table]['fields'][$field]['label'][0]) ? $label : $field) . '</option>' . "\n";
128+
$strOptions .= ' <option value="' . $field . '"' . (($field == $strSearch) ? ' selected="selected"' : '') . '>' . (strlen($label = $GLOBALS['TL_DCA'][$this->list_table]['fields'][$field]['label'][0]) ? $label : $field) . '</option>' . "\n";
123129
}
124130
}
125131

126132
$this->Template->search_fields = $strOptions;
127133

128-
129-
/**
130-
* Get the total number of records
131-
*/
134+
// Get the total number of records
132135
$strQuery = "SELECT COUNT(*) AS count FROM " . $this->list_table;
133136

134137
if ($this->list_where)
135138
{
136139
$strQuery .= " WHERE (" . $this->list_where . ")";
137140
}
138141

139-
$strQuery .= $strWhere;
142+
$strQuery .= $strWhere;
140143
$objTotal = $this->Database->prepare($strQuery)->execute($varKeyword);
141144

142-
143-
/**
144-
* Validate the page count
145-
*/
145+
// Validate the page count
146146
$id = 'page_l' . $this->id;
147-
$page = (\Input::get($id) !== null) ? \Input::get($id) : 1;
148-
$per_page = \Input::get('per_page') ?: $this->perPage;
147+
$page = (\Input::get($id) !== null) ? (int) \Input::get($id) : 1;
148+
$per_page = (int) \Input::get('per_page') ?: $this->perPage;
149149

150150
// Thanks to Hagen Klemp (see #4485)
151151
if ($per_page > 0 && ($page < 1 || $page > max(ceil($objTotal->count/$per_page), 1)))
@@ -158,10 +158,7 @@ protected function compile()
158158
$objHandler->generate($objPage->id);
159159
}
160160

161-
162-
/**
163-
* Get the selected records
164-
*/
161+
// Get the selected records
165162
$strQuery = "SELECT " . $this->strPk . "," . $this->list_fields;
166163

167164
if ($this->list_info_where)
@@ -183,16 +180,30 @@ protected function compile()
183180
return $GLOBALS['TL_DCA'][$this->list_table]['fields'][$field]['eval']['rgxp'] == 'date' || $GLOBALS['TL_DCA'][$this->list_table]['fields'][$field]['eval']['rgxp'] == 'time' || $GLOBALS['TL_DCA'][$this->list_table]['fields'][$field]['eval']['rgxp'] == 'datim';
184181
};
185182

183+
$order_by = \Input::get('order_by');
184+
185+
if ($order_by && !in_array($order_by, $arrFields, true))
186+
{
187+
$order_by = '';
188+
}
189+
190+
$sort = \Input::get('sort');
191+
192+
if ($sort && !in_array($sort, array('asc', 'desc')))
193+
{
194+
$sort = '';
195+
}
196+
186197
// Order by
187-
if (\Input::get('order_by'))
198+
if ($order_by)
188199
{
189-
if ($isInt(\Input::get('order_by')))
200+
if ($isInt($order_by))
190201
{
191-
$strQuery .= " ORDER BY CAST(" . \Input::get('order_by') . " AS SIGNED) " . \Input::get('sort');
202+
$strQuery .= " ORDER BY CAST(" . $order_by . " AS SIGNED) " . $sort;
192203
}
193204
else
194205
{
195-
$strQuery .= " ORDER BY " . \Input::get('order_by') . ' ' . \Input::get('sort');
206+
$strQuery .= " ORDER BY " . $order_by . ' ' . $sort;
196207
}
197208
}
198209
elseif ($this->list_sort)
@@ -210,9 +221,9 @@ protected function compile()
210221
$objDataStmt = $this->Database->prepare($strQuery);
211222

212223
// Limit
213-
if (\Input::get('per_page'))
224+
if ($per_page)
214225
{
215-
$objDataStmt->limit(\Input::get('per_page'), (($page - 1) * $per_page));
226+
$objDataStmt->limit($per_page, (($page - 1) * $per_page));
216227
}
217228
elseif ($this->perPage)
218229
{
@@ -221,10 +232,7 @@ protected function compile()
221232

222233
$objData = $objDataStmt->execute($varKeyword);
223234

224-
225-
/**
226-
* Prepare the URL
227-
*/
235+
// Prepare the URL
228236
$strUrl = preg_replace('/\?.*$/', '', \Environment::get('request'));
229237
$blnQuery = false;
230238

@@ -240,13 +248,9 @@ protected function compile()
240248
$this->Template->url = $strUrl;
241249
$strVarConnector = ($blnQuery || \Config::get('disableAlias')) ? '&amp;' : '?';
242250

243-
244-
/**
245-
* Prepare the data arrays
246-
*/
251+
// Prepare the data arrays
247252
$arrTh = array();
248253
$arrTd = array();
249-
$arrFields = trimsplit(',', $this->list_fields);
250254

251255
// THEAD
252256
for ($i=0, $c=count($arrFields); $i<$c; $i++)
@@ -262,10 +266,10 @@ protected function compile()
262266
$strField = strlen($label = $GLOBALS['TL_DCA'][$this->list_table]['fields'][$arrFields[$i]]['label'][0]) ? $label : $arrFields[$i];
263267

264268
// Add a CSS class to the order_by column
265-
if (\Input::get('order_by') == $arrFields[$i])
269+
if ($order_by == $arrFields[$i])
266270
{
267-
$sort = (\Input::get('sort') == 'asc') ? 'desc' : 'asc';
268-
$class = ' sorted ' . \Input::get('sort');
271+
$sort = ($sort == 'asc') ? 'desc' : 'asc';
272+
$class = ' sorted ' . $sort;
269273
}
270274

271275
$arrTh[] = array
@@ -310,7 +314,7 @@ protected function compile()
310314
$arrTd[$class][$k] = array
311315
(
312316
'raw' => $v,
313-
'content' => ($value ? $value : '&nbsp;'),
317+
'content' => $value ?: '&nbsp;',
314318
'class' => 'col_' . $j . (($j++ == 0) ? ' col_first' : '') . ($this->list_info ? '' : (($j >= (count($arrRows[$i]) - 1)) ? ' col_last' : '')),
315319
'id' => $arrRows[$i][$this->strPk],
316320
'field' => $k,
@@ -323,29 +327,23 @@ protected function compile()
323327
$this->Template->thead = $arrTh;
324328
$this->Template->tbody = $arrTd;
325329

326-
327-
/**
328-
* Pagination
329-
*/
330+
// Pagination
330331
$objPagination = new \Pagination($objTotal->count, $per_page, \Config::get('maxPaginationLinks'), $id);
331332
$this->Template->pagination = $objPagination->generate("\n ");
332333
$this->Template->per_page = $per_page;
333334
$this->Template->total = $objTotal->count;
334335

335-
336-
/**
337-
* Template variables
338-
*/
336+
// Template variables
339337
$this->Template->action = \Environment::get('indexFreeRequest');
340-
$this->Template->details = ($this->list_info != '') ? true : false;
338+
$this->Template->details = (bool) $this->list_info;
341339
$this->Template->search_label = specialchars($GLOBALS['TL_LANG']['MSC']['search']);
342340
$this->Template->per_page_label = specialchars($GLOBALS['TL_LANG']['MSC']['list_perPage']);
343341
$this->Template->fields_label = $GLOBALS['TL_LANG']['MSC']['all_fields'][0];
344342
$this->Template->keywords_label = $GLOBALS['TL_LANG']['MSC']['keywords'];
345-
$this->Template->search = \Input::get('search');
346-
$this->Template->for = \Input::get('for');
347-
$this->Template->order_by = \Input::get('order_by');
348-
$this->Template->sort = \Input::get('sort');
343+
$this->Template->search = $strSearch;
344+
$this->Template->for = $strFor;
345+
$this->Template->order_by = $order_by;
346+
$this->Template->sort = $sort;
349347
$this->Template->col_last = 'col_' . $j;
350348
}
351349

0 commit comments

Comments
 (0)