基础网页开发和漏洞寻找

前言: 放寒假了,之前一直在准备期末,没什么时间学技术和写博客,最近有空了会写一些。

本篇博客将接着之前的内容介绍利用php搭建网站的一些步骤,从网页开发角度分析一些常用漏洞的产生。

学安全首先要会开发。

1.1操作数据库

php作为一门编程语言,是无法直接与数据库进行交互的,想要进行该操作需要使用php提供的数据库拓展,Php

提供了许多的数据库拓展,比较常见的有mysql拓展,mysqli拓展,下文将介绍mysqli拓展的使用。

想要使用该拓展首先需要在php.ini文件中打开

想要在php中操作数据库,分三个部分,1 连接数据库,2 操作数据库,3 断开连接

<?php
$link = mysqli_connect("localhost", "root", "root");
mysqli_select_db($link, "mysql");
$sql = "select * from help_topic";
$query = mysqli_query($link, $sql);
while ($row = mysqli_fetch_array($query)) {
	echo $row['name'];
	echo "</br>";
}
mysqli_close($link);
?>

1. mysqli_connect()函数用于与数据库建立连接,传入的分别是服务器地址(可以是ip地址或者域名),数据库账

号,不光能连接本地的mysql服务器,也可以连接远程的mysql服务器。

数据库密码,数据库名(可省略),操作选项(可省略) 该函数的返回值是一个 MySQLi 连接对象,用于后续的数据库

操作和数据库关闭过程。

**2. **mysqli_select_db() 该函数用于选择数据库,分别传入连接对象和数据库名两个参数。

**3. ** mysqli_query() 该函数用于执行mysql语句,对数据库进行操作,传入的值分别是连接对象和mysql操作语

句,该函数在查询成功后返回一个mysqli对象,查询失败则返回false. 查询完成后,如果想要输出结果,则需要用到

mysqli_fetch_array,该函数在结果集中取一行作为关联数组,每次执行后向下一行,直到结果集末尾。

数组的索引就是表的栏名,比如id,name,等

4. mysqli_close() 用于关闭连接,传入的值是连接对象。

通过上述的四个的步骤,就完成了一次数据库操作。

如果每次进行数据库操作都要来一遍这四种操作就未免过于麻烦,可以利用数据库配置文件进行简化

即,将连接数据库的语句单独放在另一个创建的config.php中,然后再在原文件中包含config.php即可

由于数据库配置文件中往往包含数据库的账号和密码,所以可以在此方向进行攻击

如果我们要根据条件选择不同的内容,可以这样做

<?php
include("config.php");
$sql = "select * from help_topic where help_topic_id= '" . $_GET['id'] . "'limit 1;";
$query = mysqli_query($link, $sql);
while ($row = mysqli_fetch_array($query)) {
	echo $row['name'];
	echo "</br>";
}
mysqli_close($link);
?>

通过get传参然后进行查询,有没有觉得很眼熟,没错,这就构成了最基础的sql注入。

在过去,无论是关于sql注入还是前文的操作,只用了Mysql中的select操作,我们对数据库还存在其他的操作,以

后再继续补充。

1.2 文件上传的实现

之前学习过文件上传漏洞,今天从开发角度分析一下该漏洞的产生。

之前再前端部分我们学习过文件的上传,但上传后怎么办没有提及,例如

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>upload</title>
</head>
<body>
    <form action="" method="get">
        <input type="file" name="myfile" />
        <input type="submit" name="myfile" />
    </form>
    </form>
</body>
</html>

这就是一个简单的表单提交,先回顾一下以前的内容,通过action属性设置提交目标,可以是本地文件也可以是远

程服务器上的文件,如果想要提交给当前文件的php部分,只需要提交地址留空即可,method指明提交方法

下方input标签的name属性用于区分不同的数据,使用对应提交方式的变量以name为键可以获得其提交的值.

如果我们想要获取文件的其他信息,则需要使用$_FILES超级全局变量了,使用方法为

$_FILES["传入数据的name值"]["需要用到的键"]

其中常用的键如下

1 name 获取上传文件的原始名称

2 type 获得上传文件的MIME类型

3 tmp_name 上传文件在服务器上的临时路径 比如我们上传一个a.txt,输出该键下的值,有

C:\Windows\php16DE.tmp,可以看到之前的文件是以临时文件形式存储的

4 error 上传文件时的错位代码

5 size 上传文件的大小(以字节为单位)

注意,上传后我们看到的并不是原始的文件,而是进行编码过的临时文件。

文件上传到临时文件夹后,我们需要将其移动到对应的文件夹,此时需要使用move_uploaded_file函数,需要

注意的是,此函数只能用于移动上传的临时文件,因为只有这种情况下php会对上传的文件进行临时存储。

用法如下

move_uploaded_file("临时文件地址","移动后的地址");

注意,这个地址要包含文件本身,可以使用相对地址也可以使用绝对地址,移动之后的文件就成了上传前的文件

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>upload</title>
</head>

<body>
    <form action="" method="post" enctype="multipart/form-data">
        <input type="file" name="myfile" />
        <input type="submit" />
    </form>
    <?php
    $tmp = $_FILES["myfile"]["tmp_name"];
    $nam = $_FILES["myfile"]["name"];
    move_uploaded_file($tmp, './' . $nam);
    ?>
</body>
</html>

具体操作如上,multipart/form-data 。 指定传输数据为二进制类型传输。 最后的目标地址我们可以不使用上传

的原文件的名,自己更改地址给个新名也是可以的,这时

候在看目标文件夹,就发现之前上传的文件已经出现了,而且并不是tmp文件格式,此时说明上传成功。如果不加

护,是不是绝对也很熟悉,没错,这就又构成了文件上传漏洞。

想要实现文件上传,我们不光可以像这样手写功能实现,还可以使用编辑器,即我们在使用论坛或者博客网站时进

行评论那个文本栏,想要使用编辑器需要在服务器端下载编辑器并进行配置,常见的编辑器有ueditor等,当我们

使用网上的编辑器时,验证环节就完全交给编辑器负责了,这时候寻找文件上传漏洞就需要去寻找编辑器漏洞了,

同理,如果此时使用框架进行实现,则也需要去寻找框架的漏洞。

1.3 文件下载的实现

下载方式分为直连下载和传参下载,直连下载指直接访问对应文件的地址进行下载,传参下载指通过传入查询字符

串,然后在后台进行处理下载。

首先我们看一下直连下载。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <?php
    function down()
    {
        $filepath = getcwd();
        $filename = scandir($filepath . '\dow');
        foreach ($filename as $value) {
            if ($value != "." && $value != "..") {
                echo $value . "</br>";
            }
        }
    }
    down();
    ?>
    <form action="" method="post">
        <input type="text" name="fname">
        <input type="submit">
    </form>
    <?php
    if ($_POST["fname"]) {
        $url = "http://" . $_SERVER['HTTP_HOST'] . "/file/dow/" . $_POST["fname"];
        header("location:$url");
    }
    ?>
</body>
</html>

getcwd()函数为获取当前文件地址,注意,在windows操作系统下,绝对地址用的是\,但也可以识别/在linux

或者html下,地址只能使用/ scandir()的作用是获取指定目录下文件名称,并将其存储在数组中返回。

接下来我们来看传参下载,这种下载方式的实现是通过header函数,通过构造对客户机发送的响应报文来实现对

文件的下载

    <?php
    if ($_POST["fname"]) {
        $filesiz = filesize("./dow/" . $_POST["fname"]);
        $type = filetype($_POST['fname']);
        header("Disposition;filename = " . $_POST["fname"]);
        header("Accept-ranges:bytes");
        header("Accept-length: " . $filesiz);
        readfile("./dow/" . $_POST["fname"]);
    }
    ?>

就是模拟了http响应报文,但是需要注意的是要将显示和下载分开,该方法就是将文件放在相应体中传回去,所以

本页面的内容也会包含进去,所以要分开。

1.4 文件及文件夹删除。

    if ($_POST["fname"]) {
        function delfile($name)
        {
            $file = "./dow/" . $name;
            unlink($file);
        }
        function delfiledir($name)
        {
            $file = "./dow/" . $name;
            rmdir($file);
        }
    }

实现文件夹删除功能非常的简单,只需要删除文件使用unlink函数,删除文件夹使用rmdir函数即可

1.5 文件读取与文件写入

首先我们来看读入

    <?php
    if ($_POST["fname"]) {
        function fileread()
        {
            $filename = "./dow/" . $_POST['fname'];
            $filesiz = filesize($filename);
            $file = fopen($filename, "r") or die("无法打开");
            echo fread($file, $filesiz);
            fclose($file);
        }
    }
    fileread();
    ?>

在php中fope()函数用于打开一个文件或url,并返回一个文件资源句柄,该函数接受两个参数,第一个是文件路

径,第二个是模式,fopen函数有以下几个模式:

1 r 以只读方式打开文件,文件必须存在,否则会打开失败。

2 w 以写入方式打开文件,如果文件不存在,则创建一个新文件,如果文件存在。则将原文件内容清除

3 a 以追加方式打开文件,如果文件不存在,则创建一个新文件,如果文件存在,则在文件末尾追加数据。

4 x 以独占方式打开文件进行写入,如果文件不存在,则会创建一个新文件,如果文件存在,则会打开失败。

5 r+ 以读写方式打开文件,文件必须存在,否则会打开失败,写入时是在文件头部继续进行。

6 w+ 以读写方式打开文件。如果文件不存在,则创建一个新文件,如果文件存在,则将其截断为零长度。

7 a+ 以读写方式打开文件进行追加,如果文件不存在,则创建一个新文件,如果文件存在,则在文件的末尾追加

数据

我们需要注意的是,通过此方式直接读取的html代码和js代码会被执行,php代码则会触发浏览器的容错机制,从

而被注释,这也就是之前我们在命令执行漏洞时使用tac而不是使用cat的原因。

关于写入

    <?php
    if ($_POST["fname"]) {
        function filewrite()
        {
            $filename = "./dow/" . $_POST['fname'];
            $file = fopen($filename, "a+") or die("无法打开");
            fwrite($file, $_POST["txt"]);
            fclose($file);
        }
        filewrite();
    }
    ?>

1.6 搜索框功能的实现

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>搜索功能</title>
</head>

<body>
    <form action="" method="post">
        <label for="sea">搜索框</label>
        <input type="search" name="sea" />
        <input type="submit">
    </form>
    <?php
    include("../config.php");
    $name = $_POST["sea"];
    $sql = "select * from fir where content like '%$name%';";
    $quer = mysqli_query($link, $sql);
    while ($row = mysqli_fetch_array($quer)) {
        echo $row["id"] . "</br>";
        echo $row["content"] . "</br>";
    }
    mysqli_close($link);
    ?>
</body>

</html>

搜索框可能存在sql注入漏洞和xss漏洞

1.7 留言板功能

实现留言板功能需要我们对数据库进行查询和修改,查询之前我们已经学习过了现在来学习一下inset操

insert into tablename (colunm1,column2 ....) value (value1,value2 ....);学会了insert

就可以实现该功能了

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <form action="" method="post">
        <label for="1">id:</label>
        <input type="text" name="id" id="1">
        </br>
        <label for="2">内容</label>
        <input type="text" name="content" id="2">
        </br>
        <input type="submit">
    </form>
    <?php
    $link = mysqli_connect("localhost", "root", "root");
    mysqli_select_db($link, "test");
    $id = $_POST["id"];
    $content = $_POST["content"];
    $sql1 = "insert into con (id,content) value('$id','$content')";
    mysqli_query($link, $sql1);
    $sql2 = "select * from con";
    $query = mysqli_query($link, $sql2);
    while ($row = mysqli_fetch_array($query)) {
        echo $row['id'] . "</br>";
        echo $row['content'];
        echo "</br>";
    }
    mysqli_close($link);
    ?>
</body>

</html>

1.8 获取用户信息功能

我们现在在访问网页时,时常会看见自己的地址显示以及一些信息,那么该功能是怎么实现的呢?这

时‘候就需要我们使用$_SERVER超级全局变量了

$_SERVER["REMOTE_ADDR"] //获取客户IP地址

$_SERVER["REMOTE_PORT"] //获取客户访问的端口号

$_SERVER["SERVER_ADDR"] //获取服务器地址

$_SERVER["SERVER_PORT"] 获取服务器端口

$_SERVER["QUERY_STRING"] 获取第一个?后所有内容

$_SERVER["REQUEST_METHOD"] 获取get或post方法

$_SERVER["DOCUMENT_ROOT"] 获取网站根目录

$_SERVER["REQUEST_URI"] 获取当前正在访问的网址

__DIR__是获取当前访问地址所在磁盘目录名称

$_SERVER['HTTP_USER_AGENT']; 获取用户ua头

参考此博客

利用此变量可以防范CSRF漏洞

1.9 服务器端的cookie和session验证以及登录功能的实现

​ 很多网页的内容要根据不同的用户显示不同的内容,此时需要用户进行登录操作,但每个页面都进行登

录未免不是很显示,所以我们使用cookie或者session来解决这个问题

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

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

很明显,存储在客户端的cookie相较而言更容易被泄露,设计cookie的问题由cookie修改,伪造,盗取

session相对来说要安全不少,设计session的安全问题一般是session劫持问题。举个例子

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录</title>
</head>

<body>
    <form action="" method="post">
        <label for="1">用户名:</label>
        <input type="text" id="1" name="username">
        </br>
        <label for="2">密码:</label>
        <input type="password" id="2" name="password">
        </br>
        <input type="submit">
    </form>
    <?php
    include("config.php");
    $username = $_POST["username"];
    $password = $_POST["password"];
    $sql = "select * from usr where username='$username' and password='$password';";
    $que = mysqli_query($link, $sql);
    if ($username) {
        if (mysqli_num_rows($que)) {
            echo "登录成功";
            setcookie("user", $username);
            header("location: admin.php");
        } else
            echo "登录失败";
    }
    ?>
</body>

</html>

我们利用setcookie函数来设置cookie,在后台页面通过cookie来判断登录状态

<?php
$user = $_COOKIE["user"];
if (!$user)
    header("location:login.php");

当用户首次访问某个Web应用程序时,服务器会在响应中发送一个cookie给客户端浏览器。这个cookie包

含了一个由服务器生成的唯一的标识符,称为session ID。客户端浏览器会将这个cookie保存起来。

当用户再次访问该Web应用程序时,浏览器会自动将存储的cookie发送回服务器。服务器接收到请求和附

带的cookie后,会检查session ID是否存在。如果存在,服务器就知道该请求来自已登录的用户,并根据

该session ID检索用户的会话数据。这样,服务器就可以根据用户的身份提供个性化的内容或执行其他与

身份验证相关的操作

我们只需要每个页面包含一个cookie验证代码即可实现自动判断,cookie是存储在客户端的浏览器中的,

所以如果我们有管理员的cookie,就可以干很多东西了。

我们再看一下基于session的判断。

    <?php
    include("config.php");
    $username = $_POST["username"];
    $password = $_POST["password"];
    $sql = "select * from usr where username='$username' and password='$password';";
    $que = mysqli_query($link, $sql);
    if ($username) {
        while ($row = mysqli_fetch_array($que)) {
            $_SESSION["user"] = $row["username"];
            header("location: admin.php");
        }
    }
    ?>

每次在进行session操作前,首先要开启session ,需要加上session_star()如果不想这样,可以开启

session 自启动。在对应版本的php.ini文件中配置然后重启php服务器即可。

Session验证的原理是,当用户登录成功后,服务器会为该用户创建一个唯一的Session ID,并将该

Session ID与用户的登录状态等相关信息保存在服务器端。服务器通过在响应中设置一个名为“Set-

Cookie”的HTTP头部字段,将Session ID发送给客户端浏览器。客户端浏览器在接收到Session ID后,会

将其保存在Cookie中。当客户端再次向服务器发送请求时,会自动将保存的Session ID通过Cookie发送给

服务器端。服务器端会根据接收到的Session ID查找对应的Session信息,以判断该用户的登录状态。通过

这种方式,服务器可以在客户端访问时验证用户的身份,保持用户的登录状态,并提供个性化的服务。

2.0 利用ajax实现登录操作

我们不仅可以利用php实现登录,也可以使用ajax在前端进行登录操作

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JS</title>
</head>
<body>
        <label for="1">账号</label>
        <input type="text"class="user">
        <label for="2">密码</label>
        <input type="password"class="pass">
        <button>提交</button>
        <script src="../jquery-3.7.1.min.js"> </script>
            <script>
                $('button').click(function () {
                    $.ajax({
                        type: 'post',
                        url: 'ajax.php',
                        dataType: 'json',
                        data: {
                            myusernam: $('.user').val(),
                            myupass: $('.pass').val()
                        },
                        success: function (res) {
                            if (res.infocode == 1) {
                                alert("登录成功");
                            }
                            else
                                alert("登录失败");
                        }
                    })
                })    
            </script>
</body>
</html>

对于ajax.php

<?php
$username = $_POST["myusernam"];
$password = $_POST["myupass"];
$success = array("msg" => "ok");
if (1) {
    $success["infocode"] = 1;
} else {
    $success["infocode"] = 0;
}
echo json_encode($success);

用于判断登录,实际使用过程中1要换成数据库查询语句。

我们要树立起前后端分离的思想,第一个html文件是在客户端执行的,第二个php文件是在服务器端执行

的,echo的内容作为服务器响应结果传递给ajax中的res,因此会得到对于的值

第一个代码中success是一个回调函数,用于处理服务器响应。当AJAX请求成功完成时,这个回调函数会

被调用。

具体来说,当用户点击提交按钮时,会触发一个AJAX POST请求到'ajax.php'。这个请求中包含了从输入框

中获取的用户名和密码。当服务器响应返回时,success回调函数会被执行。

success回调函数中,代码检查服务器返回的数据中的infocode属性。如果infocode的值为1,则显

示一个提示框告诉用户"登录成功"。如果infocode的值不是1,则显示一个提示框告诉用户"登录失败"。

简单来说,success回调函数是用来处理和响应服务器返回的数据的。在这个例子中,它用于处理登录操

作的结果。

我们在提交数据过程中使用到了dataType 在此我对其进行解释: 其用来指定请求返回的数据类型,在请求报

文中放在ACCEPT字段中,需要与contentType 进行区分,contentType用于表明发送的数据类型。

2.1 商店购买页面实现

2.1.1 以前端设计价格为准,数据接受价格后运算

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>商店</title>
</head>
<body>
        <img src="https://wx3.sinaimg.cn/mw690/905502ccgy1hmhpnwickzj20u0140n7g.jpg" width="270" height="270">
        <div>价格 100</div>
        <label for="1">数量</label>
        <input id="1" class="number">
        </br>
        <button>购买</button>
        <script src="../jquery-3.7.1.min.js"> </script>
        <script>
            $('button').click(function () {
                $.ajax({
                    type: 'post',
                    url: 'shop.php',
                    dataType: 'json',
                    data: {
                        price: 100,
                        number: $('.number').val()
                    },
                    success: function (res) {
                        if (res.infocode == 1) {
                            alert("购买成功");
                        }
                        else
                            alert("购买失败");
                    }
                })
            })    
        </script>
</body>
</html>

至于shop.php

<?php
$price = $_POST["price"];
$number = $_POST["number"];
$success = array("msg" => "ok");
$money = 1000; //获取的账户总金钱
if ($price * $number <= $money) {
    $success["infocode"] = 1;
    //对账户金钱进行操作。
} else {
    $success["infocode"] = 0;
    //购买失败
}
echo json_encode($success);

和我们之前写的代码差不多,这种价格是在前端设定的,所以给了我们更改的机会,其次,对输入的数据不

加判断也构成了标准的购买逻辑,如果我们输入个负数就会加钱

2.1.2 在前端以数据库价格为基准

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>商店</title>
</head>

<body>
    <?php
    //我们此时获取的id是通过查询字符串获取的,取决于客户点击的页面
    include("config.php");
    $sql = "select * from pri where id=1;";
    $pri = mysqli_query($link, $sql);
    while ($row = mysqli_fetch_array($pri)) {
        $price = $row["price"];
        $src = $row["src"];
        echo "<img src='$src' width=270 height=270>" . "</br>";
        echo "价格:" . $price . "</br>";
    }
    ?>
    <label for="1">数量</label>
    <input id="1" class="number">
    </br>
    <button>购买</button>
    <script src="../jquery-3.7.1.min.js"> </script>
    <script>
        $('button').click(function() {
            $.ajax({
                type: 'post',
                url: 'shop.php',
                dataType: 'json',
                data: {
                    price: <?php echo $price; ?>,
                    number: $('.number').val()
                },
                success: function(res) {
                    if (res.infocode == 1) {
                        alert("购买成功");
                    } else
                        alert("购买失败");
                }
            })
        })
    </script>
</body>

</html>

只不过是通过数据库获取了数据然后传到后端,但实际上还是可以抓包修改,没有什么卵用。

通过上述的几个实际例子,我们发现在前端发送价格或者判断是否购买成功是不可行的,实际中要把一系列

操作都放在后端去,真正做到前后端分离。

除了上述问题,还存在后端返回状态码在前端验证的问题,想要验证成功我们直接抓包改判断码,也算是比

较严重的漏洞。

2.2 php框架的基础使用

首先我们得先明白什么是框架:软件框架通常指的是一组模块化组件,这些组件遵循特定的接口和协议,以

实现某种业界标准或完成特定基本任务的软件组件规范。它不仅提供了规范所需的基础功能,而且还可以通

过扩展机制支持未来的需求变化。软件框架可能包含一系列库、工具和模板,旨在为开发人员提供一个快速

构建应用程序的途径。

也就是我们之前实现的一些功能就不用自己写了,直接用框架里写好的接口即可。

我们以thinkphp 5.0为例子

首先我们在官方网站下载thinkphp5框架,以public文件夹作为网站的根目录。

先了解一下thinkphp的url访问规则:

http://serverName/index.php(或者其它应用入口文件)/模块/控制器/操作/[参数名/参数值...]

比如我们将方法写在thinkphp/application/index/controller/Test.php

Test.php的内容如下

<?php

namespace app\index\controller;

use think\Controller;

class  Test extends Controller
{
    public function ec()
    {
        echo 123;
    }
}

注意设置命名空间和引入控制器类

我们想要访问该ec方法时需要使用的url为:http://tp.com/index.php/index/Test/ec

也可为http://tp.com/index.php?s=index/Test/ec

注意: 文件名首字母得大写而且类名得和文件名保持一致。

我们遇到 页面错误! 请稍后再试 的报错时

在config.php文件下将 show_error_msg=false 改为true即可

由于thinkphp 5.0比较老,所以使用了getclass方法,但php8.0向上丢弃了该方法,所以需要更换版本或者

更改配置文件

2.3 thinkphp传递参数

如果想要传递参数,也有多种写法

比如http://tp.com/index.php?s=index/Test/ec&x=1

或者http://tp.com/index.php/index/Test/ec?x=1

我们在程序中除了典型的get,post,request超级全局变量获取内容,还可以使用input来获取传递的内容

在thinkphp中,使用方式如下

input('?get.id')

或者input('?post.name') 这两种是thinkphp的官方获取数据的写法,可以过滤掉很多的sql注入。

由于使用了thinkphp,导致了这与常规情况下php中input函数的使用不同,需要注意

当我们使用http://tp.com/index.php/index/Test/ec/x/1的方式来传递参数时,

此时即不是通过get方式传递也不是通过post方式传递参数,所以获取传递参数时要这样写

input("x")s

对于官方写法对sql注入的过滤,我们进行进一步解释

$id =$_GET["x"];
$sql = "select * from pri where id=$id;";

对于这种写法,我们使用万能密码 qwewq of 1=1;

直接就可以获得表中的所有信息,但我们如果使用以下方法

$id = input("?get.x");
$sql = "select * from pri where id=$id;";

万能密码部分就会被过滤掉。

2.4 thinkphp 数据库操作

thinkphp有其提供的一套数据库操作方式,想要使用首先要配置thinkphp的config.php文件

配置好后我们在使用过程中就不需要连接数据库了,直接进行操作即可

首先我们来看查询的方式

我们可以这样查询

Db::query('select * from think_user where id=?',[8]);

具体使用如下

<?php

namespace app\index\controller;
use think\Db;
use think\Controller;

class  Test extends Controller
{
    public function ec()
    {
        $userId = 2;
        $result = Db::query('select * from pri where id=?', [$userId]);
        if ($result) {
            foreach ($result as $row) {
                echo $row['id'] . '<br>';
            }
        }
    }
}

使用时需要引入Db类

返回的值是一个关联数组,即一个数组中套了另一个数组,这个关联数组存储了查询的所有信息,第一种方

式是原生的数据库查询方式,我们再来看另一种方式。

Db::table('think_user')->where('id',1)->find();

等价于

select * from think_user

<?php

namespace app\index\controller;

use think\Db;
use think\Controller;

class  Test extends Controller
{
    public function ec()
    {
        $userId = $_GET["x"];
        $result = Db::table('pri')->where('id', $userId)->select();
        if ($result) {
            foreach ($result as $row) {
                echo $row['id'] . '<br>';
            }
        }
    }
}

使用find()是查询第一个数据,使用select()是查询数据集,上述这

我们需要注意的是,thinkphp中官方写法是第二中,在框架中进行sql注入过滤的写法也是第二种。

我们在实际进行渗透测试时,想要判断对方是否是thinkphp搭建的服务器,如果是白盒就直接看thinkphp文

件夹下的base.php文件。

如果是黑盒,就通过网络空间引擎,或者通过报错,返回数据包,url地址对其进行判断。

或者我们可以下载wappalyzer对其进行判断。

posted @ 2024-01-27 17:39  折翼的小鸟先生  阅读(8)  评论(0编辑  收藏  举报