(圖作者 | 吾愛破解@Ps出來的小趙) 吾愛破解每年都有個解題領紅包活動,今年也不例外,需要我們使出看家逆向本領來分析內容獲得口令紅包,根據難度等級不同會獲得不同數量的吾愛幣,活動持續到元宵節結束。活動一共有十個題,本文僅分享 Web 初級、中級、高級三個題的逆向思路。 活動地址:https:// ...
(圖作者 | 吾愛破解@Ps出來的小趙)
吾愛破解每年都有個解題領紅包活動,今年也不例外,需要我們使出看家逆向本領來分析內容獲得口令紅包,根據難度等級不同會獲得不同數量的吾愛幣,活動持續到元宵節結束。活動一共有十個題,本文僅分享 Web 初級、中級、高級三個題的逆向思路。
活動地址:https://www.52pojie.cn/thread-1738015-1-1.html
題目簡介
三個 Web 題的線索都在一個視頻里:https://www.bilibili.com/video/BV123411R7K6/
視頻中包含 12 個靜態 flag: flag1~flag12,另外還需要尋找到 3 個動態 flag: flagA~flagC。 本題總共有 3 個難度,每個難度提交 4 個靜態 flag 和 1 個動態 flag 就算通過。
- 初級難度為 flag1~flag4 與 flagA
- 中級難度為 flag5~flag8 與 flagB
- 高級難度為 flag9~flag12 與 flagC
初級難度
flag1
flag1 直接在視頻中給出了,flag1{52pojiehappynewyear}
flag2
flag2 藏在二維碼里,拿手機掃一下會打開一個網址,網址後面跟了一個 flag2{878a48f2}
,當然直接搜二維碼線上解碼也行,上傳上去就能看到文本信息。
flag3
在視頻 25 秒左右,右下角會出現一串字元 iodj3{06i95dig}
,這裡肯定是一個 flag,註意觀察 flag 是四個字母,iodj 也是四個字母,可以大膽猜測這就是 flag3,在字母上動了手腳,數字和括弧沒變,極大可能是愷撒密碼,愷撒密碼是一種替換加密的技術,明文中的所有字母都在字母表上向後(或向前)按照一個固定數目進行偏移後被替換成密文,例如,當偏移量是3的時候,所有的字母A將被替換成D,B變成E。這裡 iodj
每個字母分別向前偏移3,剛好就是 flag
,以此類推,最終結果就是 flag3{06f95afd}
。
flag4
flag4 比較雞賊,沒在視頻里,而是藏在視頻作者的簽名里(滑鼠無意間瞎晃找到的),解密發現是 Base64,最終結果為 flag4{9cb91117}
。
flagA
視頻里給了一個網址 2023challenge.52pojie.cn
,提示說了這個網站似乎無法訪問,但網站的確在運行,它和吾愛破解主站是同一臺伺服器,可能是功能變數名稱解析的問題。
既然都說了是功能變數名稱解析問題,那我們就分別線上檢測一下 2023challenge.52pojie.cn
和主站 52pojie.cn
的解析設置,首先可以發現 2023challenge.52pojie.cn
的 TXT 記錄里有個 flagB,這個後面再說,與主站對比發現 A 記錄里少了 124.232.185.97
,提示也說了和主站是同一臺伺服器,所以我們可以在本地 host 裡加上這個記錄即可訪問。
訪問網站 https://2023challenge.52pojie.cn/
,可以在 Response Header
里找到一個 X-Dynamic-Flag
,也就是動態 flagA,如下圖所示:
既然是動態的,那就不可能直接是 flagA{Header X-52PoJie-Uid Not Found}
,很明顯給的提示是 Header 里缺少了 X-52PoJie-Uid
,所以我們在請求的時候 Header 裡加上這個欄位試試,Python 代碼如下:
import requests
headers = {
"X-52PoJie-Uid": "2002241", # 你的吾愛破解 UID
"Host": "2023challenge.52pojie.cn",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
}
url = "https://2023challenge.52pojie.cn/"
response = requests.get(url, headers=headers)
flagA = response.headers["X-Dynamic-Flag"]
print(flagA)
查看返回的 Header 里的 X-Dynamic-Flag
,就是正確的 flagA,有個過期時間,在過期前提交即可。
中級難度
flag5
在視頻第30秒左右的時候,會出現類似發電報的聲音,這就是摩斯密碼(摩爾斯電碼),對著下表聽就完事兒了,當然還有更準確的方法,那就是分析音頻的頻譜圖,更加直觀,音頻的分析後文 flag8 再說,這裡的正確答案是 flag5{eait}
。
flag6
flag6 比較直觀,視頻開頭就直接給出了,電話撥號聲就是 flag6。
重點在於如何識別撥號的數字,這裡涉及到一個雙音多頻信號(DTMF)的概念,雙音多頻由高頻群和低頻群組成,高低頻群各包含4個頻率。一個高頻信號和一個低頻信號疊加組成一個組合信號,代表一個數字。可以使用 Python 讀取音頻來識別,也有現成的工具 DTMF2NUM 可以識別,具體介紹參考:https://bbs.qsnctf.com/thread-318-1-1.html ,裡面有下載鏈接。使用錄音工具將這段撥號音錄成 wav 格式,然後通過工具識別得到 flag6{590124}
。
flag7
視頻中,第22秒左右,上方出現的一串 0101 的東西,這就是 flag7,實際上是二進位形式的 ASCII 碼,八位一個字元,例如 01100110
對應的 ASCII 碼就是 f
,找個線上工具轉換一下就可以得到 flag7{5d06be63}
。
01100110 01101100 01100001 01100111 00110111 01111011 00110101 01100100 00110000 00110110 01100010 01100101 00110110 00110011 01111101
flag8
flag8 藏在這個視頻的音頻里,同樣將音頻錄下來,用 Audacity 軟體打開此音頻,選擇頻譜圖,就可以看到 flag8{c394d7}
,同樣前面的 flag5 其實除了直接用耳朵聽以外,也可以通過這個頻譜圖查看。
flagB
flagB 在前面推理 flagA 的時候已經遇到了,線索在 2023challenge.52pojie.cn
的功能變數名稱解析,TXT 記錄里,計算方法就是自己的 uid 加上字元串 _happy_new_year_
加上時間戳除以 600 並向下取整後的值,經過 md5 加密後,取前八位即可。
flagB{substr(md5(uid+\_happy_new_year_\+floor(timestamp/600)),0,8)}
高級難度
flag9
仔細聽這個視頻,在結尾,也就是大概40秒的時候,依稀有一段雜音,單獨將這一段錄下來,反向播放,就會發現說的正是 flag9,正確答案是 flag9{21c5f8}
。
flag10
flag10 太難了沒找到,有知道的小伙伴可以分享一下。
flag11
視頻里,底下一串 ++++[>
的東西就是 flag11,這一串是 Brainfuck 語言,是一種非常接近圖靈機的編程語言。可以直接使用線上工具轉換即可:https://www.splitbrain.org/services/ook ,正確答案是 flag11{63418de7}
。
++++++++++[>++++++++++>++++++++++>+++++>++++++++++++<<<<-]>++.++++++.>---.<-----.>>-..>+++.<+++++.---.+.---.+++++++.<+++.+.>-.>++.
flag12
仔細觀察視頻你會發現,開頭的背景是灰色的,在第20秒左右,顏色就加深了,其實開始的背景圖是有貓膩的,用到了圖片盲水印技術,flag12 就藏在背景圖片里,原理就是使用傅里葉變換把原圖變為頻譜圖,再疊加水印,將含水印的頻譜圖進行傅里葉逆變換得到含水印的圖像。蟻景網路安全的這篇文章有詳細的介紹:https://blog.csdn.net/YJ_12340/article/details/127087949 ,我們直接使用文中的方法,使用 Python 處理圖片後即可得到 flag12{3ac97e24}
。
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 讀取為灰度圖像,52pj.png 為視頻開頭的背景截圖
img = cv2.imread('52pj.png', 0)
f = np.fft.fft2(img)
# 將圖像中的低頻部分移動到圖像的中心
fshift = np.fft.fftshift(f)
# 取絕對值:將複數變化成實數,目的為了將數據變化到較小的範圍(比如0-255)
s1 = np.log(np.abs(f))
s2 = np.log(np.abs(fshift))
plt.subplot(121), plt.imshow(s1, 'gray'), plt.title('original')
plt.subplot(122), plt.imshow(s2, 'gray'), plt.title('center')
plt.show()
下圖可能平臺會有壓縮看不清,自己照著處理一下即可。
flagC
flagC 是動態的,還得回到 https://2023challenge.52pojie.cn/
這個網站上來。
點擊登陸後,來到 login
頁面,讓我們提交 UID,但是這個輸入框無法輸入,修改一下源碼,將 disabled
刪除即可。
然後輸入我們的 UID,提示您不是 admin,你沒有許可權獲取 flag。
抓包分析一下,發現在點擊提交後,Response Headers
有個 Set-Cookie
,而這個 cookie 由三段組成,以 .
分隔,很明顯是一個 JWT(JSON Web Token)。
JWT 是可以解密的,來到 jwt.io
這個網站,解密後可以發現 payload 部分包含了我們的 uid 和 role 角色信息,此刻我們是普通的 user,直接將其改為 admin 即可,將生成的新 JWT 拿來重新提交,即可拿到正確的 flagC。