PHP开发(用于网络安全学习)

声明

该文章的代码都是学习一个思路,代码不能直接使用,需要根据自己实际情况进行修改;文章供安全研究人员学习交流。

PHP开发

PHP操作数据库

<?php
$res=mysqli_connect("127.0.0.1", 'root', 'root');
if($res){
    echo "数据库连接成功";
}
//创建数据库
$sql = "create database demoPHP";
if(mysqli_query($res,$sql)){
    echo "数据库创建成功";
}
//删除数据库
$sql = "drop database demoPHP";
mysqli_query($res, $sql);
mysqli_select_db($res, 数据库名);
//新增数据表
$sql = "create tables 表名 (字段1,字段1)";
mysqli_query($res,$sql);
//删除数据表
$sql = "drop table 表名";
mysqli_query($res, $sql);
//插入数据
$sql = "insert into 表名 对应字段和值";
//查询数据
$sql = "select 字段 from 表名";//后面where可以加查询的条件
?>

数据库网安必备总结

文件的上传

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=, initial-scale=1.0">
    <title>文件的上传</title>
</head>
<body>
    <form action="" method="post" enctype="multipart/form-data">
     <!-- multipart/form-data:不对字符编码。

在使用包含文件上传控件的表单时,必须使用该值。
enctype属性:规定将表单数据提交到服务器时应如何编码(仅供 method="post")-->
        <h1>文件上传</h1>
        <input type="file" name="file" id="file">
        <input type="submit" name="submit_file">
    </form>
</body>
</html>
<?php
$name = $_FILES["file"]["name"];//获取文件名字
$size = $_FILES["file"]["size"];//获取文件大小
$type = $_FILES["file"]["type"];//获取文件类型
$error = $_FILES["file"]["error"];//获取上传文件的错误代码
$tmpname = $_FILES["file"]["tmp_name"];//获取上传文件的临时文件名

echo $name . "<br>";
echo $size . "<br>";
echo $type . "<br>";
echo $error . "<br>";
echo $tmpname . "<br>";
if(move_uploaded_file($tmpname,"D:/H_desktop/".$name)){
    echo "上传成功";
}else{
    echo "上传失败";
}
?>

上面这种方法是自己敲代码,我们也可以直接采用编辑器。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=, initial-scale=1.0">
    <title>文件的上传</title>
    <script src="./ueditor/ueditor.config.js">/*引入配置文件*/</script>
    <script src="./ueditor/ueditor.all.js">/*引入源码文件*/</script>
</head>
<body>
<textarea id="content" rows="10" cols="70" style="border:1px solid #E5E5E5;">55222</textarea>    
    <script type="text/javascript">
        UE.getEditor("content");//实例化编辑器  传参,id为将要被替换的容器。
    </script>
</body>
</html>

我这里采用的是ueditor编辑器,可以直接从网上下载使用;由于这个核心代码是我们下载的,所以这个文件上传是否有漏洞就需要看该编辑器;使用框架同理。

文件的下载

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=, initial-scale=1.0">
    <title>文件的下载</title>
</head>
<body>
    <h1>d</h1>
    <?php get_filename();?>
    <form action="" method="post" enctype="multipart/form-data">
        请输入要下载的文件<input type="text" name="name">
        <input type="submit" value="下载">

    </form>
    <?php
	if ($_POST)
	{
	 $name1 = $_POST["name"];
	 geturl($name1);
	}
?>
</body>
</html>
<?php
function get_filename(){
    $current_path = getcwd();//获取当前路径
    $filename=scandir($current_path.'/soft/');//扫描当前路径下的文件
    foreach($filename as $value){
        if($value!="."&&$value!=".."){
            echo $value."<br>";
        }
    }
}   

function geturl($name){
    $url = 'http://' . $_SERVER['HTTP_HOST'].'/xiaodi/soft/'.$name;
    //echo $url;
    header("location:$url");
}
?>

上面代码成功了,会直接访问header,这个问题还没有解决。

对于文件下载有两种,一种就是直接url下载(只能下载.exe、.zip等);另一种就是传参下载。相比来说,第一种更安全,因为传参下载可以下载任意类型,可以查看.php的源码;而在url中并不会下载.php文件。

文件的删除

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=, initial-scale=1.0">
    <title>文件的下载</title>
</head>
<body>
    <h1>d</h1>
    <?php get_filename();?>
    <form action="" method="post" enctype="multipart/form-data">
        请输入要删除的文件<input type="text" name="name">
        <input type="submit" value="删除">

    </form>
    <?php
    if ($_POST) {
        $name1 = $_POST["name"];
        del_file($name1);
    }
    ?>
</body>
</html>
<?php
function get_filename(){
    $current_path = getcwd();//获取当前路径
    $filename=scandir($current_path);//扫描当前路径下的文件
    foreach($filename as $value){
        if($value!="."&&$value!=".."){
            echo $value."<br>";
        }
    }
}   


function del_file($name){
    @unlink($name);//删除文件
}
function del_files($name){
    rmdir($name);  //删除文件夹
}
?>

上述代码实现对文件/文件夹的删除,主要用了两个函数。

注意:在post提交数据的时候千万加上if($_POST){}这个条件。


文件的读写

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=, initial-scale=1.0">
    <title>文件的下载</title>
</head>
<body>
    <h1>文件读取</h1>
    <?php get_filename();?>
    <form action="" method="post" enctype="multipart/form-data">
        请输入要查看的文件<input type="text" name="name">
        <input type="submit" value="确定">

    </form>
    <?php
    if ($_POST) {
        $name1 = $_POST["name"];
        fileread($name1);
    }
    ?>
    <hr><br>
    <h1>文件写入</h1>
    <?php get_filename();?>
    <form action="" method="post" enctype="multipart/form-data">
        请输入要写入的文件<input type="text" name="name">
        请输入要写入的内容<input type="text" name="write">
        <input type="submit" value="确定">

    </form>
    <?php
    if ($_POST) {
        $name1 = $_POST["name"];
        $write = $_POST["write"];
        writefile($name1,$write);
    }
    ?>

</body>
</html>
<?php
function get_filename(){
    $current_path = getcwd();//获取当前路径
    $filename=scandir($current_path);//扫描当前路径下的文件
    foreach($filename as $value){
        if($value!="."&&$value!=".."){
            echo $value."<br>";
        }
    }
}   

//读取文件函数
function fileread($name){
    $file=fopen($name,"r");
    echo fread($file, filesize($name));//两个参数都是必须的
    fclose($file);
}
//写入文件的函数
function writefile($name,$txt){
    $file = fopen($name, "a+");//a+如果文件存在,则会追加;不存在则会创建
    fwrite($file, $txt);
    fclose($file);
}
?>

文件包含

<?php
include("1.txt");
?>

文件包含就是在代码中利用include\require等函数包含一个文件,然后把该文件中的内容放到该文件中执行。

网站搜索功能

就是在页面进行搜索我们想要看的东西,后端代码就是在数据库中使用select * from 表名 where 字段名 like ;此时主要的问题就是会在页面输出我们查询的内容。如果我们输入的内容是一个script代码,则就会造成xss攻击。

留言板

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>留言板</title>
</head>
<body>
    <form action="" method="post">
        id:<input type="text" name="id"><br>
        昵称:<input type="text" name="ni"><br>
        QQ:<input type="text" name="qq"><br>
        留言:<br><textarea rows="8" cols="500" name="content"></textarea>
        <input type="submit" value="留言">
    </form>
</body>
</html>
<?php
$id = $_POST["id"];
$ni = $_POST["ni"];
$q = $_POST["qq"];
$c = $_POST["content"];

header("Content-Type: text/html;charset=utf-8");
$con=mysqli_connect("127.0.0.1", "root", "root");
if($con){
    echo "连接成功";
}
$sql = "create database liuyanban";
if(mysqli_query($con, $sql)){
    echo "创建成功";
}
mysqli_select_db($con, "liuyanban");
// $sql="CREATE TABLE liuyanb ( id INT ( 12 ), ni INT (12), q INT(12), c INT(122))";
// if (mysqli_query($con, $sql)) {
//     echo "数据表liuyanb创建成功";
// } else {
//     echo "创建数据表错误: " . mysqli_error($conn);
// }
$sql = "insert into liuyanb (id,ni,q,c) values ($id,$ni,$q,$c)";
mysqli_query($con, $sql);
$sql="select * from liuyanb";
$result=mysqli_query($con, $sql);
//var_dump($result);
while($row=mysqli_fetch_array($result)){
    echo '<br>';
    echo 'id:'.$row['id'].'<br>';
    echo '昵称:'.$row['ni'].'<br>';
    echo 'QQ:'.$row['q'].'<br>';
    echo '内容:'.$row['c'].'<br>';
}
?>

上述的网站搜索还是留言板都是在页面输出用户可控信息,留言板还有可能存储在数据库中,可能造成xss漏洞。

全局变量SERVER

<?php
echo $_SERVER['PHP_SELF'];
echo "<br>";
echo $_SERVER['SERVER_NAME'];
echo "<br>";
echo $_SERVER['HTTP_HOST'];
echo "<br>";
echo $_SERVER['HTTP_REFERER'];//查看referer,即访问该网站的来源IP
echo "<br>";
echo $_SERVER['HTTP_USER_AGENT'];
echo "<br>";
echo $_SERVER['SCRIPT_NAME'];
?>

获取IP地址:

<?php
function getIp()
{
    if ($_SERVER["HTTP_CLIENT_IP"] && strcasecmp($_SERVER["HTTP_CLIENT_IP"], "unknown")) {
        $ip = $_SERVER["HTTP_CLIENT_IP"];
    } else {
        if ($_SERVER["HTTP_X_FORWARDED_FOR"] && strcasecmp($_SERVER["HTTP_X_FORWARDED_FOR"], "unknown")) {
            $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
        } else {
            if ($_SERVER["REMOTE_ADDR"] && strcasecmp($_SERVER["REMOTE_ADDR"], "unknown")) {
                $ip = $_SERVER["REMOTE_ADDR"];
            } else {
                if (isset ($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'],
                        "unknown")
                ) {
                    $ip = $_SERVER['REMOTE_ADDR'];
                } else {
                    $ip = "unknown";
                }
            }
        }
    }
    return ($ip);
}
echo getIp()."<br>";

IP地址伪造来源:就是抓包修改X_FORWARDED_FOR的值;X_FORWARDED_FOR用来表示 HTTP 请求端真实 IP。

来源页伪造:就是抓包修改REFERER的值,$_SERVER["HTTP_REFERER"]可以获取其来源IP,直接访问网址referer就是空。

后台验证

服务器后台有多个文件页面,但我们通常都是只需要在第一个登陆页面登陆就行,而其他页面并不需要重复登陆,因此为了方便验证,一般使用cookie和session进行验证。

cookie:身份验证,存储到客户端浏览器

session:身份验证,存储到服务端服务器内

安全问题:cookie修改、伪造、盗取

session:会话劫持(session劫持)

cookie验证

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>账号登陆</title>
</head>
<body>
    <form action="" method="post">
        账号:<input type="text" name="id"><br>
        密码:<input type="password" name="pass"><br>
        <input type="submit" value="登陆">
    </form>
</body>
</html>
<?php
    header("Content-Type:text/html;charset=utf-8");
    $con=mysqli_connect("127.0.0.1", "root", "root");
    $username=$_POST['id'];
    $password=md5($_POST['pass']);//因为数据库中存放密码是会加密
    $sql="select * from 存放登录信息的表名 where username='$username' and password='$password'";
    $result=mysqli_query($con,$sql);
    if (mysqli_num_rows($result)){
    setcookie('user',$username);//登陆成功的话就会生成一个cookie;第一个参数是cookie的名称,第二个参数是cookie的值
    header('Location: index.php');//登陆成功进行跳转
}
//后台的每个页面都会进行cookie的验证,使用$_COOKIE进行验证
?>

cookie就是检验我们身份的标志,而且他又是保存在我们浏览器端,所以会造成cookie伪造、修改等等安全漏洞。

session验证

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>账号登陆</title>
</head>
<body>
    <form action="" method="post">
        账号:<input type="text" name="id"><br>
        密码:<input type="password" name="pass"><br>
        <input type="submit" value="登陆">
    </form>
</body>
</html>
<?php
    header("Content-Type:text/html;charset=utf-8");
    $con=mysqli_connect("127.0.0.1", "root", "root");
    $username=$_POST['id'];
    $password=md5($_POST['pass']);//因为数据库中存放密码是会加密
    $sql="select * from 存放登录信息的表名 where username='$username' and password='$password'";
    $result=mysqli_query($con,$sql);
    while($row=mysqli_fetch_array($result)){
        session_start();
        $_SESSION['username'] = $row['username'];
        //echo $_SESSION['username'];
        header('Location: index.php');
    }
?>

session验证就比较严格,因为session每次的值都是随机变化,并不是确定的,很难造成攻击。

验证码

验证码本身是为了防止爆破的,但是有些验证码是可以通过抓包进行爆破的;抓到包之后验证码就是一成不变的。

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- 简单的表单提交代码 -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>简单验证码的实现</title>
</head>
<body>
<form method="post" action="">
    帐号:<input type="text" name="user">
    密码:<input type="password" name="pass">
    <p>验证码图片:<img src="code.php" onClick="this.src='code.php?nocache='+Math.random()" style="cursor:hand" alt="点击换一张"/>点击图片可更换验证码</p>
    <p>请输入图片中的内容:<input type="text" name="authcode" value=""/></p>
    <p><input type="submit" width="20px" height=19px value="提交"></input></p>
</form>

</body>
</html>

<?php
include('config/conn.php');
header("Content-type: text/html; charset=utf-8");
// session 存值并匹配用户输入值
if (isset($_REQUEST['authcode'])) {
    session_start();
    if (strtolower($_REQUEST['authcode'])==$_SESSION['authcode']) {//strtolower转化为小写的函数
        echo"输入正确!";
        $username=$_POST['user'];
        $password=md5($_POST['pass']);
        $sql="select * from sy_adminuser where username='$username' and password='$password'";
        $result=mysql_query($sql,$conn);
        if(mysql_num_rows($result)){
            $row=mysql_fetch_array($result);
            echo '成功!';
            session_start(); 
            $_SESSION['user']=$row['username'];//讲查询结果的数据进行赋值
            header("Location: admin/add_news.php");
        }else{
            echo '失败!';
            //header("Location: login.php");
        }
        # code...
    }
    else{
        echo"输入错误!";
    }
    exit();
}
?>

code.php

<?php
/**
 * 字母+数字的验证码生成
 */
// 开启session
session_start();
//1.创建黑色画布
$image = imagecreatetruecolor(100, 30);

//2.为画布定义(背景)颜色
$bgcolor = imagecolorallocate($image, 255, 255, 255);

//3.填充颜色
imagefill($image, 0, 0, $bgcolor);

// 4.设置验证码内容

//4.1 定义验证码的内容
$content = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

//4.1 创建一个变量存储产生的验证码数据,便于用户提交核对
$captcha = "";
for ($i = 0; $i < 4; $i++) {
    // 字体大小
    $fontsize = 10;
    // 字体颜色
    $fontcolor = imagecolorallocate($image, mt_rand(0, 120), mt_rand(0, 120), mt_rand(0, 120));
    // 设置字体内容
    $fontcontent = substr($content, mt_rand(0, strlen($content)), 1);
    $captcha .= $fontcontent;
    // 显示的坐标
    $x = ($i * 100 / 4) + mt_rand(5, 10);
    $y = mt_rand(5, 10);
    // 填充内容到画布中
    imagestring($image, $fontsize, $x, $y, $fontcontent, $fontcolor);
}
$_SESSION["captcha"] = $captcha;

//4.3 设置背景干扰元素
for ($$i = 0; $i < 200; $i++) {
    $pointcolor = imagecolorallocate($image, mt_rand(50, 200), mt_rand(50, 200), mt_rand(50, 200));
    imagesetpixel($image, mt_rand(1, 99), mt_rand(1, 29), $pointcolor);
}

//4.4 设置干扰线
for ($i = 0; $i < 3; $i++) {
    $linecolor = imagecolorallocate($image, mt_rand(50, 200), mt_rand(50, 200), mt_rand(50, 200));
    imageline($image, mt_rand(1, 99), mt_rand(1, 29), mt_rand(1, 99), mt_rand(1, 29), $linecolor);
}

//5.向浏览器输出图片头信息
header('content-type:image/png');

//6.输出图片到浏览器
imagepng($image);

//7.销毁图片
imagedestroy($image);
?>

检验上传文件的扩展名

对上传文件的扩展名检验有两种方法,一种就是js代码,在前端对其验证;另一种就是php在后端对其进行验证;js验证我们是可以绕过的,在浏览器我们可以设置禁用javascript绕过,而后端验证就不能通过该方法验证了。

js检验代码:

<script>
    function checkFileExt(filename)
    {
        var flag = false; //状态
        var arr = ["jpg","png","gif"];
        //取出上传文件的扩展名
        var index = filename.lastIndexOf(".");
        var ext = filename.substr(index+1);
        //比较
        for(var i=0;i<arr.length;i++)
        {
            if(ext == arr[i])
            {
                flag = true; //一旦找到合适的,立即退出循环
                alert("上传的文件符合要求!");
                break;
            }
        }
        //条件判断
        if(!flag)
        {
            alert("上传的文件不符合要求,请重新选择!");
            location.reload(true);
        }
    }
</script>

Ajax

AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。

AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。

AJAX 不需要任何浏览器插件,但需要用户允许 JavaScript 在浏览器上执行。

框架

现在有很多CMS都是采用框架开发,框架为我们封装了很多功能,方便我们使用;对于框架的使用,我们直接从网上找手册即可学习。面对框架开发的程序,漏洞的出现有两种可能,一是开发者没有利用官方要求使用某些函数或功能进行开发,二是框架爆出漏洞。以后的渗透我们就从这两个方向入手。

框架的文件和url之间关系,通常就是域名端口+index.php+模块名+控制器下的文件(该文件必须是首字母大写,不需要加扩展名)+函数+参数

使用-路由访问-控制器&对象&函数&参数 理解:URL <=> 文件

总结

漏洞就是在代码解决实际问题中产生的,所以在学习漏洞之前我们应先了解一下基础的开发;有了开发的基础,我们才能知道漏洞产生的原因,才能更好的防护。

无论是js还是利用ajax等等处理数据,只要是在前端页面处理数据而后端没有验证,都可以对其进行抓包修改数据,造成一定的破坏。

技巧:如果我们看到某个页面的返回结果是json格式,且其中有code等字段,那么大概率就是前端处理数据,很有可能存在上述漏洞。

web漏洞核心:

  1. 可控变量
  2. 特定功能的函数
posted @ 2023-02-21 20:59  Redemption857  阅读(6)  评论(0)    收藏  举报