20192424王昭云 2021-2022-2 《网络与系统攻防技术》实验八实验报告修改版

实验八 Web安全

1.实验内容及要求

(1)Web前端HTML

能正常安装、启停Apache。理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML。

(2)Web前端javascipt

理解JavaScript的基本功能,理解DOM。

在(1)的基础上,编写JavaScript验证用户名、密码的规则。在用户点击登陆按钮后回显“欢迎+输入的用户名”

尝试注入攻击:利用回显用户名注入HTML及JavaScript。

(3)Web后端:MySQL基础:正常安装、启动MySQL,建库、创建用户、修改密码、建表

(4)Web后端:编写PHP网页,连接数据库,进行用户认证

(5)最简单的SQL注入,XSS攻击测试

(6)安装Webgoat或类似平台,并完成SQL注入、XSS、CSRF攻击。

3.学习中遇到的问题及解决

遇到php没有mysal的dll以及ext文件

遇到apache安装后本地网页不能被访问

以上问题解决方法我写在实验过程中了

唉,算了,为了实验评分,再写一遍

问题一解决办法

  • 直接使用最原始的yum install php,php-mysql,php-fpm

问题2解决办法

  • 那么需要我们关掉一个东西,命令如图:setenforce 0

    • image.png
  • 实验成功,在centos7上打开的

    • image.png
  • 实验成功,在windows主机上打开的

    • image.png

2.实验过程

Web前端HTML

  • apache安装与部署

    • 环境centos7.6系统,已经安装python3并且设置了python3和Python2分开的软连接

    • 安装

      • 安装apache

        • yum install httpd* -y
      • 启动apache

        • systemctl start httpd.service
      • 查看apache状态

        • systemctl status httpd.service
    • 简单部署

      • 设置主目录,我设置的主目录为/www/website/目录下,并在里面放置一个html文件。

        • image.png
      • 修改配置文件httpd.conf,配置文件应该是在计算机文件里,然后实在找不到可以用find / -name httpd.conf搜索一下,其中/的意思是在这个目录中找,包含子目录,-name参数意思是按照名字查找

        • image.png
      • 上图中为什么找到两个httpd.conf文件呢?其实是因为我们的apache正在运行所以有一个是临时文件它的路径里包含了temp,为了防止运行中的文件不能修改,我们先用systemctl kill httpd.service把apache服务关了

      • 打开后本着深入学习其工作原理的原则,我来为大家讲解一下这个配置文件中部分语句的作用,详情见https://blog.csdn.net/WuLex/article/details/106868978?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_title~default-0-106868978-blog-40426259.pc_relevant_antiscanv2&spm=1001.2101.3001.4242.1&utm_relevant_index=3

        • 配置文件包括一下三部分
          1)Global Environment—全局环境配置,决定Apache服务器的全局参数
          2)Main server configuration—主服务配置,相当于是Apache中的默认Web站点,如果我们的服务器中只有一个站点,那么就只需在这里配置就可以了。
          3)Virtual Hosts—虚拟主机,虚拟主机不能与Main Server主服务器共存,当启用了虚拟主机之后,Main Server就不能使用了
        • ServerRoot为服务器及其配置文件所在目录,部署网站不用管它
        • PidFile run/httpd.pid是设置统一的父进程号,方便快速识别与不同客户间的连接,不然他们的进程号是不固定的。
        • Timeout 60为服务器的断开时间
        • KeepAlive Off为是否保持持续连接
        • MaxKeepAliveRequests 100为最大挂起数
      • 修改文件

        • 修改网页路径

          • image.png
        • 修改根目录

          • image.png
      • 修改后出现如下问题

        • 那么需要我们关掉一个东西,命令如图:setenforce 0

          • image.png
        • 实验成功,在centos7上打开的

          • image.png
        • 实验成功,在windows主机上打开的

          • image.png
  • 编写前端带有表单的网页

    <html>
    <head>
    <title>表单</title>
    </head>
    
    <body>
    <form>
        姓名:<input type="text" value="wzy20192424" name="userName"/><br>
        密码:<input type="password" value="111" name="pwd"/><br>
    </form>
    <br>
    <form>
        <input type="radio" value="male" name="sex" checked/>男
        <input type="radio" value="male" name="sex"/>女<br>
    </form>
    <br>
    <form>
        <input type="checkbox" value="playguita" name="specialty" checked/>弹吉他
        <input type="checkbox" value="唱歌" name="singing" checked/>唱歌
        <input type="checkbox" value="弹吉他" name="playing" checked/>弹吉他
        <input type="checkbox" value="十项全能" name="all" checked/>十项全能
    </form>
    <br>
    <form action="" enctype="multipart/form-data">
    帅照:<input type="file" name="fileName"/>
    </form>
    
    <br>
    地区:
    <select name="cities" size="2" multiple>
    <option value="sichuan" selected/>四川
    <option value="guangdong" />广东
    <option value="guangxi" />广西
    <option value="上海"/>上海
    </select>
    <br>
    <br>
    更多描述:<textarea name="更多描述:" cols="100" rows="10"></textarea>
    <br>
    <br>
    <form>
    <input type="submit" value="提交"/>
    <input type="reset" value="重置" />
    <input type="button" value="关闭" />
    </form>
    
    
    </body>
    </html>```
    
    
    
  • 将该网页在su权限下部署到apache的服务器根目录

    • image.png
  • 成功在局域网的其他主机上访问

    • image.png
  • get和post请求的区别

    • 对于GET方式的请求,浏览器会把http header和data一并发送出去,服务端响应200,请求成功。
    • 对于POST方式的请求,浏览器会先发送http header给服务端,告诉服务端等一下会有数据过来,服务端响应100 continue,告诉浏览器我已经准备接收数据,浏览器再post发送一个data给服务端,服务端响应200,请求成功。
    • 但是上面所说的post会比get多一个tcp包其实不太严谨。多发的那个expect 100 continue header报文,是由客户端对http的post和get的请求策略决定的,目的是为了避免浪费资源,如带宽,数据传输消耗的时间等等。所以客户端会在发送header的时候添加expect 100去探探路,如果失败了就不用继续发送data,从而减少了资源的浪费。所以是否在发送一个包取决了客户端的实现策略,和get/post并没什么关系。有的客户端比如fireFox就只发送一个包。
  • 什么是DOM

    • DOM就是document object model的缩写,是js语言中用于操作页面及其元素的对象,比如操纵鼠标特性,点击位置检测等等。

    • 通过js实现一个前端判断输入用户名,密码是否正确并回显的网页,代码如下:

      <html>
      <head>
      <title>表单</title>
      </head>
      
      <body>
      <form>
          姓名:<input type="text" value="wzy20192424" name="userName"/><br>
          密码:<input type="password"  name="pwd"/><br>
      </form>
      <br>
      <form>
          <input type="radio" value="male" name="sex" checked/>男
          <input type="radio" value="male" name="sex"/>女<br>
      </form>
      <br>
      <form>
          <input type="checkbox" value="playguita" name="specialty" checked/>弹吉他
          <input type="checkbox" value="唱歌" name="singing" checked/>唱歌
          <input type="checkbox" value="弹吉他" name="playing" checked/>弹吉他
          <input type="checkbox" value="十项全能" name="all" checked/>十项全能
      </form>
      <br>
      <form action="" enctype="multipart/form-data">
      帅照:<input type="file" name="fileName"/>
      </form>
      
      <br>
      地区:
      <select name="cities" size="2" multiple>
      <option value="sichuan" selected/>四川
      <option value="guangdong" />广东
      <option value="guangxi" />广西
      <option value="上海"/>上海
      </select>
      <br>
      <br>
      更多描述:<textarea name="更多描述:" cols="100" rows="10"></textarea>
      <br>
      <br>
      <form method="post" onsubmit="login()">
      <input type="submit" value="提交" id="submit"/>
      <input type="reset" value="重置" name="reset"/>
      <input type="button" value="关闭" name="exit"/>
      </form>
      <script>
          function login(){
              let username=document.querySelectorAll('input')[0].value
              let password=document.querySelectorAll('input')[1].value
              if(username=='wzy20192424' && password=='111')
              {
                  alert(username+"登录成功")
              }
              else
              {
                  alert("密码或者用户名错误")
              }
          }
      </script>
      </body>
      </html>
      
    • 代码失败原因是没有后端,不过可以在前端检测密码用户名是否正确,其中就使用了dom的方法

      • image.png
  • 尝试注入攻击

    • 前端使用如下代码

      <html>
      <head>
      <title>表单</title>
      </head>
      
      <body>
      <form  method="post" onsubmit="login()">
          姓名:<input type="text" value="wzy20192424" name="userName"/><br>
          密码:<input type="password"  name="pwd"/><br>
      <br>
          <input type="radio" value="male" name="sex" checked/>男
          <input type="radio" value="male" name="sex"/>女<br>
      <br>
          <input type="checkbox" value="playguita" name="specialty" checked/>弹吉他
          <input type="checkbox" value="唱歌" name="singing" checked/>唱歌
          <input type="checkbox" value="弹吉他" name="playing" checked/>弹吉他
          <input type="checkbox" value="十项全能" name="all" checked/>十项全能
      <br>
      <form action="" enctype="multipart/form-data">
      帅照:<input type="file" name="fileName"/>
      
      <br>
      地区:
      <select name="cities" size="2" multiple>
      <option value="sichuan" selected/>四川
      <option value="guangdong" />广东
      <option value="guangxi" />广西
      <option value="上海"/>上海
      </select>
      <br>
      <br>
      更多描述:<textarea name="更多描述:" cols="100" rows="10"></textarea>
      <br>
      <br>
      <input type="submit" value="提交" id="submit"/>
      <input type="reset" value="重置" name="reset"/>
      <input type="button" value="关闭" name="exit"/>
      </form>
      <script>
          function login(){
              let username=document.querySelectorAll('input')[0].value
              let password=document.querySelectorAll('input')[1].value
              if(username=='wzy20192424' || password=='111')
              {
                  alert(username+"登录成功")
                  document.write(username+"登录成功")
              }
              else
              {
                  alert("密码或者用户名错误")
              }
          }
      </script>
      </body>
      </html>
      
    • 输入

      wzy20192424

      进行注入攻击

      • image.png
    • 可见alert不受html语言注入影响

      • image.png
    • 不过dom.write受到了注入影响

      • image.png

Web后端

  • 安装php

    • 开始升级PHP更新源:

      • 直接复制下面代码,依次执行既可。

        rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
        yum remove php-common -y  
        yum install -y php72w php72w-opcache php72w-xml php72w-mcrypt php72w-gd php72w-devel php72w-mysql php72w-intl php72w-mbstring
        
    • 查看版本:

      • 执行下面命令,查看版本号。

        php -v

      • 安装php fpm依次执行下面命令:

        systemctl start php-fpm.service //启动php
        systemctl enable php-fpm.service//设置开机自启动
        systemctl restart httpd //重新启动apache服务
        
    • 测试

      • 写个php文件

        登录成功<br>
        <?php echo  "你好" ?>
        
      • 对应的html文件为

        <html>
        <head>
        <title>表单</title>
        </head>
        
        <body>
        <form action="./welcome.php" method="post" onsubmit="login()">
            姓名:<input type="text" value="wzy20192424" name="userName"/><br>
            密码:<input type="password"  name="pwd"/><br>
        <br>
            <input type="radio" value="male" name="sex" checked/>男
            <input type="radio" value="male" name="sex"/>女<br>
        <br>
            <input type="checkbox" value="playguita" name="specialty" checked/>弹吉他
            <input type="checkbox" value="唱歌" name="singing" checked/>唱歌
            <input type="checkbox" value="弹吉他" name="playing" checked/>弹吉他
            <input type="checkbox" value="十项全能" name="all" checked/>十项全能
        <br>
        <form action="" enctype="multipart/form-data">
        帅照:<input type="file" name="fileName"/>
        
        <br>
        地区:
        <select name="cities" size="2" multiple>
        <option value="sichuan" selected/>四川
        <option value="guangdong" />广东
        <option value="guangxi" />广西
        <option value="上海"/>上海
        </select>
        <br>
        <br>
        更多描述:<textarea name="更多描述:" cols="100" rows="10"></textarea>
        <br>
        <br>
        <input type="submit" value="提交" id="submit"/>
        <input type="reset" value="重置" name="reset"/>
        <input type="button" value="关闭" name="exit"/>
        </form>
        <script>
            function login(){
                let username=document.querySelectorAll('input')[0].value
                let password=document.querySelectorAll('input')[1].value
                if(username=='wzy20192424' && password=='111')
                {
                    alert(username+"登录成功")
                }
                else
                {
                    alert("密码或者用户名错误")
                }
            }
        </script>
        </body>
        </html>
        
      • 运行结果成功将数据从前端返回到了后端

        • image.png
  • 前端通过输入注入html语言让php返回

    • 注入

      wzy20192424

      如下

      • image.png
    • 成功返回注入html

      • image.png
  • 安装mysql

    • 由于centOS7中默认安装了MariaDB,需要先进行卸载

      • rpm -qa | grep -i mariadb

      • rpm -e --nodeps mariadb-libs-5.5.64-1.el7.x86_64

      • 经实践在使用yum方式安装MySQL时不用卸载也可以,会被自动替代 通过rpm方式安装需要卸载,否则会出现依赖问题

        • image.png
      • 查询下本机mysql是否卸载干净

        pm -qa | grep mysql

      • 若有残留也需要卸载

    • 下载MySQL仓库并安装

      • wget https://repo.mysql.com//mysql80-community-release-el7-3.noarch.rpm

        • image.png
      • yum -y install mysql80-community-release-el7-3.noarch.rpm

        • image.png
      • 安装过程中可能遇到如下报错无法安装,原因是Mysql的GPG升级了,需要重新获取

        • image.png
      • 执行以下命令再安装即可

      • rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022

      • 默认安装MySQL8.0,如果需要安装MySQL5.7的话需要修改/etc/yum.repos.d/mysql-community.repo配置文件

      • 将mysql80中enabled属性改为0,并添加图中红框内代码(安装MySQL8.0跳过该步骤)

        • image.png
      • 安装MySQL数据库

        • yum -y install mysql-community-server
      • 开启mysql服务

        • systemctl start mysqld.service
      • 查看mysql默认密码并登陆

        • cat /var/log/mysqld.log | grep password
        • mysql -uroot -p
    • MySQL相关配置修改

      • 修改初始密码(若想改为弱密码)

        • SHOW variables LIKE 'validate_password%';

          • image.png
      • 设置远程连接(前提:关闭防火墙或开放3306端口)

        • 在实际工作中,经常会用到诸如DBeaver等的数据库管理工具进行远程连接mysql数据库,需要设置允许远程连接。

        • 在mysql数据库的user表中查看host,默认只允许localhost访问

        • 只需将localhost改为%允许任意地址访问即可

          • image.png
        • update user set host = '%' where user = 'root';

        • flush privileges; # 刷新权限 权限更新后刷新才会起作用

          • image.png
        • 注:如果使用客户端连接提示了plugin caching_sha2_password错误,这是因为MySQL8.0的密码策略默认为caching_sha2_password(MySQL5.7无此问题)

        • update user set plugin = 'mysql_native_password' where user = 'root';

        • flush privileges; # 刷新权限 权限更新后刷新才会起作用

        • 修改完成后可以正确建立远程连接

  • SQLyog安装

    • 有了mysql我们在终端是难以操作的,所以需要sqlyog

    • 由于安装难度简单,不做教程

    • 使用时建立远程数据库的连接如图,其中ip填写装了mysql的服务器的ip,用户名填写启动了mysql服务的用户,端口一般是3306,如果被占用可以更改服务器端的端口为3316

      • image.png
  • 使用php连接mysql,代码如下

    $servername = "192.168.189.161";
    $username = "root";
    $password = "Mydb2021+";
     
    // 创建连接
    $conn = new mysqli($servername, $username, $password);
     
    // 检测连接
    if ($conn->connect_error) {
        echo "链接失败";
        die("连接失败: " . $conn->connect_error);
    } 
    echo "连接成功";
    ?>```
    
      - 该php后端执行报错,通过下载debug程序发现报错如下,原因是服务器主目录下没有mysqli类
    

image.png

	- 在项目的部署时,由于开发环境和运行环境不同,会出现这个问题,即缺少 mysqli 扩展。
	- 我们需要从头检查一下PHP配置。

		- 1.看看php的ext目录中是否有php_mysqli.dll文件

			- 如果有这个文件,就说明你的PHP安装没有问题,继续下面的步骤。
			- 如果没有的话你需要重新装个php 。

				- [![image.png](https://i.postimg.cc/FFCVXFXK/image.png)](https://postimg.cc/Lhf1zpXd)

			- 我没有该文件,所以重新装吧,使用我前面教程的不用重装,我php不是用前面教程装的,前面教程不会出现这个问题

		- 2.打开php.ini,找到

			- ;extension=php_mysqli.dll
			- (把前面的;去掉)

		- 3.找到

			- ;extension_dir="./ext"
			- 把前面的分号";"去掉,改为(相对于php的安装路径的ext目录)
			- extension_dir = "e:php\ext"
			- e:php为php的存放目录(例如我的路径为F:\workplace\php7\ext)
			- 重启Apache服务器。

		- 亲测,到这里就可以解决了。

	- 其实安装php没这么复杂,别被网上教程骗了,我后来三行命令解决问题

		- 可能安装之前要删除以前安装的版本用yum remove php
		- yum install php
		- yum install php-fpm
		- yum install php-mysql
  • php连接数据库代码如下

    $servername = "192.168.189.161";
    $username = "root";
    $password = "Mydb2021+";
     
    // 创建连接
    $conn = new mysqli($servername, $username, $password);
     
    // 检测连接
    if (!$conn) {
        die("Connection failed: " . mysqli_connect_error());
    }
    echo "连接成功";
    ?>```
    
      - 连接成功
    
      	- [![image.png](https://i.postimg.cc/D0Ssws3w/image.png)](https://postimg.cc/p5ty0mdw)
    
    
  • 远程建表

    • 打开sqlyog,进行连接

      • image.png
    • 右键创建数据库,取名

      • image.png
    • 创建成功

      • image.png
    • 表处右键添加表

      • image.png
  • 使用php对表进行数据插入

    这里是sql <?php
    $servername = "192.168.189.162";

    $passwd = "Mydb2021+";
    $dbname="wzy20192424";
     
    // 创建连接
    $conn = new mysqli($servername, $username, $passwd ,$dbname);
     
    // 检测连接
    if (!$conn) {
        die("Connection failed: " . mysqli_connect_error());
    }
    echo "连接成功";
    $sql = "INSERT INTO users(user,password) values('green','111');";
    // $sql = "create table test(ID char(9) primary key);";
    if ($conn->query($sql) === TRUE) {
        echo "新记录插入成功";
    } else {
        echo "Error: " . $sql . "<br>" . $conn->error;
    }
     
    $conn->close();
    ?>```
    
      - 插入成功,浏览器视角
    
      	- [![image.png](https://i.postimg.cc/CdyZMQ4c/image.png)](https://postimg.cc/8fHktw9v)
    
      - 数据库视角
    
      	- [![image.png](https://i.postimg.cc/RC2GnCsD/image.png)](https://postimg.cc/9zty62jd)
    
    
  • 使用php连接数据库做到对前端传回来的用户名和密码和数据库做比对,然后判断

    $uname=$_POST["userName"];
    $pwd=$_POST["pwd"];
    echo $uname;
    $query_str="SELECT * FROM users where user='$uname' and password='$pwd';";
    $mysqli = new mysqli("192.168.189.162", "root", "Mydb2021+", "wzy20192424");
    
    /* check connection */
    if ($mysqli->connect_errno) {
        printf("Connect failed: %s\n", $mysqli->connect_error);
        exit();
    }
    echo "connection okk!"; 
    /* Select queries return a resultset */
    if ($result = $mysqli->query($query_str)) {
        if ($result->num_rows > 0 ){
            echo "<br> {$uname}:Welcome!!! <br> ";
        } 
        else {
            echo "<br> login failed!!!! <br> " ; }
        /* free result set */
        $result->close();
    }
    $mysqli->close();
    ?>```
    
    
      - 成功视角
    
      	- [![image.png](https://i.postimg.cc/8zSHtKVd/image.png)](https://postimg.cc/4mWV31yn)
    
      - 失败视角
    
      	- [![image.png](https://i.postimg.cc/vm8vd4Tc/image.png)](https://postimg.cc/fVFdcTxN)
    
    

最简单的SQL注入

  • 在用户名输入框输入' or 1=1#,密码任意输入,可登陆成功:

    • image.png
  • php页面返回登录成功

    • image.png
  • 这样构造出的内部语句为:$query_str="SELECT * FROM users WHERE USER='wzy20192424' OR 1=1#' and password=',查出记录的条件从表中的user和password与所输入数据相同,变成了user和password与所输入数据相同或1=1,所以该语句一定能查出记录,数据库中执行结果如下:

    • image.png

XSS攻击测试

  • 将一张图片放在/web/www目录下,在用户名输入框输入,密码随意,即可读取图片:

    • image.png
  • 进行输入

    • image.png
  • 成功返回图片

    • image.png

安装Webgoat或类似平台,并完成SQL注入、XSS、CSRF攻击。

  • 安装Wdbgoat
    image.png

    • 参考博客[webgoat安装教程(windows)]

    • (https://article.itxueyuan.com/46nQXB)

    • 建议开VPN进https://github.com/WebGoat/WebGoat/releases,不然可能进不去。我用的免费VPN叫做如图

      • image.png
  • 安装配置java
    image.png

    • 过程略,因为我是以前安装好的
  • 运行webgoat

    • 在jar包目录下进入终端输入java -jar webgoat-server-8.0.0.M26.jar

      • image.png
    • 启动webwolf

      • java -jar webwolf-8.0.0.M26.jar

        • image.png
    • 成功进入,先进行注册

      • image.png
    • 注册成功

      • image.png
    • 登录成功

      • image.png
  • sql注入

    • SQL Injection (intro) 第9页注入成功

      • image.png
  • XSS

    • 选择general7-A7,XSS成功

      • image.png
  • CSRF

    • 选择A8第3题

      • image.png
    • 成功

      • image.png

实验心得

本次实验中我学习到了网站的快速开发,学会了两门新的语言,php和js,js真的太好用了。不过我感觉php,apache建站速度还是比django和springboot慢,只不过后门这两个入手难度比apache,php高。

除此,本次实验的sql注入和XSS攻击非常实用,警察见了会说:真刑啊!

本次实验中我试过了对django实行sql注入,不过由于django后端没有直接对数据库进行指令执行,所以没有成功,除此,django自带防止CSRF的token,所以我们实用大型框架虽然学习复杂,不过好处很多。本次实验也加深了我学习java,go,rust,vue等新技术的决心。

posted @ 2022-06-07 10:05  20192424WZY  阅读(31)  评论(0编辑  收藏  举报