网站地图    收藏   

主页 > 后端 > 网站安全 >

PHP入门级挖洞之旅 - 网站安全 - 自学php

来源:自学PHP网    时间:2015-04-17 13:03 作者: 阅读:

[导读] 今天冬至 还有2个小时吃饭闲的无聊写个长篇小说 本人语文表达能力极差 看不懂的请勿骂人 谢谢只发土司 禁止转载首先你要当挖洞是一个游戏。漏洞是BOSS.发现问题是绝招.兴趣是生命...

 

今天冬至 还有2个小时吃饭闲的无聊

写个长篇小说 本人语文表达能力极差 看不懂的请勿骂人 谢谢

只发土司 禁止转载

首先你要当挖洞是一个游戏。漏洞是BOSS.发现问题是绝招.兴趣是生命值.技术是魔法值.WEBSHELL才是最终胜利条件

那么这里就以一个小型文章系统为例子

百度了一下 找到一个叫phpaacms的文章系统 因为比较简洁代码也容易理解

注意任何一个细节都可能会击败整个程序

首先按我的思路就是先分析下文章文件结构


 

目录admin 看名字很容易理解就是后台管理

data就是数据 一般来说保存数据库文件和配置文件

images 图片 一般来说没什么用

include 这里放自定义函数居多

install 安装用的

footer.php 一般来说没什么用的 这里这类文件先不考虑 当模版看好了

global.php 一般来说初始化系统用

header.php 看名字就知道了 当模版去看

index.php 首页list.php 列表message.php 信息notice.php留言板page.php 翻页search.php 搜索show.php 显示 估计是显示文章把

 

为什么要先看文件呢? 这个很简单道理 文件都被你看完没漏洞了 还能干什么呢? 呵呵

那么先从谁下手呢? 按我思路就是install 因为这个最没用 就算有漏洞 一般站长都是会安装完毕删除

 

 

目录下就2个文件.sql没用 要看的话自己下个程序看一样的

 

INDEX.PHP

 

<?php

 

header('Content-Type: text/html; charset=utf-8');  //转换编码

 

$CMSPATH = dirname(dirname(strtr(__FILE__,'\\','/'))); //获取程序目录

 

$dbconfigfile=$CMSPATH.'/data/database.inc.php'; //定位文件

 

if(is_file($dbconfigfile)){  //如果文件在的话

 

        echo "<p align='center'>系统已经安装!<br>请删除文件/data/database.inc.php 后才可以重新安装!</p>";

 

        exit(); //输出并结束程序

 

}

//看来想再次安装程序没戏了 如果exit();不存在 那么您可以再进行反安装 数据库地址路径填远程的 达到你想做的事

 

这里可以完全不理会

习惯性地到admin目录 因为往往后台才最有权限 如果目录被修改了 碰下运气把 有些人不喜欢蜘蛛收录后台robots.txt看下有没有?



 

 

 

省掉剩下的

看下index.php 因为首页嘛

 

 <?php

 

require_once ("global.php");

 

//再看下admin目录下所有的文件开头都是这个 那么就从这个文件下手

 

global.php 代码如下

 

<?php

 

session_start();

 

require_once '../data/config.inc.php';                                //系统初始化文件

 

require_once '../include/function.admin.php';                //后台公用函数库

 

 

 

//后台登陆验证

 

if (!isset($_SESSION['userid']) || empty($_SESSION['userid'])){

 

        setcookie(lastURL,get_url());//记录上次访问地址

 

        header("Location: login.php");

 

//很幸运地第一个漏洞找到了 就是验证是否登录出了问题

 

//$_SESSION['userid']是保存在服务器内存上 估计我们没可能去修改

 

//但是header("Location: login.php");  是向客户端发送响应 但并没有结束程序运行eixt或者die 所以程序还是会继续运行下去

 

//这里可以通过关闭浏览器脚本不执行转跳

 

}

 

?>

 

 

 

//那么我们当这里没有问题 加了exit();  顺应他跳转到login.php

 

//login.php只是个提交页面 不用理会 最终是<form action="login.action.php" method="post">

 

//就是判定帐号密码都在那里

 

//看下login.action.php

 

<?php

 

session_start();  //session_start 就是开启这个东西

 

header('Content-Type: text/html; charset=utf-8');  //输出编码...

 

include_once ("../data/config.inc.php");//连接数据库

 

if (isset ( $_POST ["username"] )) {//如果提交里有username字段(帐号)

 

        $username = mysql_real_escape_string($_POST ["username"]);

 

//上面是转义USERNAME

 

} else {

 

        $username = "";

 

}

 

if (isset ( $_POST ["password"] )) {//如果提交里有password 字段(密码)

 

        $password = mysql_real_escape_string($_POST ["password"]);

 

//同上

 

} else {

 

        $password = "";

 

}

 

if (empty($username)||empty($password)){

 

        exit("<script>alert('用户名或密码不能为空!');window.history.go(-1)</script>");

 

}//上面就是如果你没有填写帐号或者密码就退出 这里使用了exit 所以下面代码不会被执行

 

 

 

$user_row = $db->find("select userid from phpaadb_users where username = '".$username."' and password='".md5 ( $password ) ."'");

 

//通过上面SQL语句看出使用了单引号 就是把所有数据转换为字符串.所以不可能出现注入 如果只是" .$username." 双引号 就可以注入

 

if (!empty($user_row )) {//如果帐号密码都对了就下面的....

 

        $_SESSION['userid'] = $user_row['userid'];

 

        setcookie("username",$username,time()+60*60*24*365);

 

        if(isset($_COOKIE['lastURL'])&&!empty($_COOKIE['lastURL'])){

 

                header("Location: ".$_COOKIE['lastURL']);       

 

        }else{

 

                header("Location: index.php");

 

        }

 

}else{

 

        exit("<script>alert('用户名或密码不正确!');window.history.go(-1)</script>");

 

//否则嘛 当然是说你错了

 

}

 

?>

 

//验证帐号密码过程很简单 没有任何漏洞

好了 这样我们进了后台 进后台第一时间想什么 当然是直接写文件

 

 

这里我们看到了文件管理这4个字 这是首先考虑的 因为最直接

file.php代码不用理会 因为也只是个提交页面 不做处理

那么我们看file.action.php

 

 

<?php

 

require_once ("global.php"); //这里验证是否登录 之前说的绕过了

 

$act = $_POST ['act'];

 

if ($act=='add') {       

 

        $upload_file = uploadFile('file');//上传文件

 

        header("Location: file.php");

 

}

 

if ($act=='delete') {       

 

        $id = $_POST ['id'];

 

        $list = $db->findAll('select * from phpaadb_file where id in('.$id.')');

 

        foreach($list as $ls){

 

                @unlink(dirname(dirname(__FILE__)).'/'.$ls['path']);

 

        }

 

           //删除文件 就是删除已经上传的文件把

 

        $db->delete('phpaadb_file','id in('.$id.')');

 

        exit();

 

}

 

我们看下uploadFile这个上传函数

 

function uploadFile($filename){

 

        global $db;

 

        global $config;

 

        $attachment_dir = $config['attachment_dir'].date('Ym')."/";

 

        //上面是路径+年月

 

        !is_dir(ROOT_PATH.$attachment_dir)&&mkdir(ROOT_PATH.$attachment_dir);       

 

           //如果没有就新建立这个年月文件夹

 

        $AllowedExtensions = array('bmp','gif','jpeg','jpg','png');

 

        $Extensions = end(explode(".",$_FILES[$filename]['name']));

 

        //获取最后一个. 结尾的东西 就是获取后缀  这里没有问题

 

        if(!in_array(strtolower($Extensions),$AllowedExtensions)){

 

                exit("<script>alert('缩略图格式错误!只支持后缀名为bmp,gif,jpeg,jpg,png 的文件');window.history.go(-1)</script>");

 

        }

 

        //如果不是array('bmp','gif','jpeg','jpg','png');其中一个就悲剧了 所以之里不存在上传漏洞!

 

 

 

//看来直接传马儿不实际了

 

//然后我们试试网站设置 写配置文件把data/website.inc.php文件保存设置

 

//看webconfig.php

 

<?php

 

include ("global.php");

 

if(isset($_POST['name'])){

 

        $str = "array(

 

        \"name\"                                =>        \"".htmlspecialchars($_POST['name'])."\",

 

        \"url\"                                =>        \"".htmlspecialchars($_POST['url'])."\",

 

        \"keywords\"                        =>        \"".htmlspecialchars($_POST['keywords'])."\",

 

        \"description\"                =>        \"".htmlspecialchars($_POST['description'])."\",

 

        \"icp\"                                =>        \"".htmlspecialchars($_POST['icp'])."\",

 

        \"attachment_dir\"        =>        \"data/attachment/\",

 

        \"masteremail\"                =>        \"".htmlspecialchars($_POST['masteremail'])."\"

 

);";

 

//以上犯了一个很严重的错误 就是使用了双引号而不是单引号 不过很可惜用了htmlspecialchars处理提交数据 所以提交"闭合没什么用

 

//如果没有htmlspecialchars处理 前提条件也得要gpc=off 就是关闭魔术引导转换

 

        $str=

 

"<?php

 

\$config=".str_replace("\$", "\\$", $str)."

 

?>";

 

        $fp = fopen(ROOT_PATH."data/website.inc.php",'wb'); //以二进制追加方式打开文件,没文件就创建

 

        fwrite($fp, $str); //插入第一条记录

 

        fclose($fp); //关闭文件

 

        echo "<script>

 

        alert('保存成功!');

 

        window.location.href='webconfig.php';

 

        </script>";

 

}

 

//上面写入文件也没什么问题

 

?>

能关于操作文件的2个可能都否决了 那么还有

网站备份与恢复

 

 

看data.action.php关键代码

 

关键代码当然是写文件部分了 其他都是浮云

$filename=date("Ymd",time())."_all.sql";

 

//这里也产生了一个漏洞data\database_bakup\date("Ymd",time())."_all.sql";

 

//这里最终保存文件名字为database_bakup\年月日_all.sql";

 

//很明显命名方式太简单 可以爆破最近几个月时间猜管理员是否备份数据库了

 

//文件名字无法操控

 

if($_POST['weizhi']=="localpc") down_file($sql,$filename);

 

//这里是下载SQL文件 一会再讨论

 

elseif($_POST['weizhi']=="server")

 

{if(write_file($sql,$filename))

 

//写文件  查看下write_file 很显然只能fopen fwrite fclose

 

$msgs[]="全部数据表数据备份完成,生成备份文件'./backup/$filename'";

 

else $msgs[]="备份全部数据表失败";

 

//看来这里也没戏了

 

//下载文件function down_file($sql,$filename){

 

        ob_end_clean();

 

        header("Content-Encoding: none");

 

        header("Content-Type: ".(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') ? 'application/octetstream' : 'application/octet-stream'));

 

        header("Content-Disposition: ".(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') ? 'inline; ' : 'attachment; ')."filename=".$filename);

 

        header("Content-Length: ".strlen($sql));

 

        header("Pragma: no-cache");

 

        header("Expires: 0");

 

        echo $sql;

 

        $e=ob_get_contents();

 

        ob_end_clean();

 

}

 

//filename不可以控制

 

//来到这里 备份功能没悬念(开始感觉BOSS难打.压力大了)

 

//看下恢复数据库呢data.restore.php

 

//这里可以产生一个漏洞 就是之前提及的文件管理的下载文件功能 把数据库备份下来 然后本地修改已经上传的文件字段 再恢复数据库

 

//那么上传记录就有了你想下载的文件 下个database试下外连数据库行不...........没有外连就直接删除数据库配置文件进行再次安装程序

 

恢复数据库就这么一个小漏洞

我们还发现可以本地上传数据库恢复

主要代码如下

 

/*****************本地恢复*/if($_POST['restorefrom']=="localpc"){/**************/

 

switch ($_FILES['myfile']['error'])

 

{

 

case 1:

 

case 2:

 

$msgs[]="您上传的文件大于服务器限定值,上传未成功";

 

break;

 

case 3:

 

$msgs[]="未能从本地完整上传备份文件";

 

break;

 

case 4:

 

$msgs[]="从本地上传备份文件失败";

 

break;

 

      case 0:

 

break;

 

}

 

if($msgs){show_msg($msgs);pageend();}//上传个正规文件不会出错的 放心

 

$fname=date("Ymd",time())."_".sjs(999).".sql";//再次悲剧  文件名字被固定了sjs是产生随机数字

 

if (is_uploaded_file($_FILES['myfile']['tmp_name'])) {

 

      copy($_FILES['myfile']['tmp_name'], "../data/database_bakup/".$fname);}

到了这里看来这BOSS防御力挺高的

后台那么多文件肯定还有出问题的

随便打开一个 添加管理员把

user.add.php 看文件名字可以判定行为了

 

 

<?php

 

require_once ("global.php");

 

$userid                 = trim($_GET ['userid'])?trim($_GET ['userid']):0;

 

$act                         = trim($_GET ['act'])?trim($_GET ['act']):'add';

 

$actName = $act == 'add'?'添加':'修改';

 

$users = $db->find ( "select * from phpaadb_users where userid=" . $userid );

 

?>

//这里产生了注入漏洞$userid 试试跨裤查询把..对旁注有点作用 但还没能直接拿下站

 

既然如此 就必须得很有耐心一个一个文件分析了

第一个article.action.php

嗯 看上去是添加文章的

这里就不贴代码了 基本都是上传(那是调用那个函数。所以没有漏洞) 注入 (已经没什么作用了)

剩下的文件全是查询写入数据库操作

或许你可以看下FCKeditor 那些什么的 但这里没有问题

到此后台能写马的可能非常渺茫

 

前台没有用户注册 全是查询 所以没可能会得出什么东西

 

到此挖洞之旅以失败告终(因为没能写入文件)

 

 

原文:http://www.t00ls.net/thread-19943-4-1.html

作者是心灵大黑客

自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习

京ICP备14009008号-1@版权所有www.zixuephp.com

网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com

添加评论