<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    某服務器平臺sm系列算法分析

    VSole2022-12-28 13:56:20

    樣品網址:aHR0cHM6Ly9mdXd1Lm5oc2EuZ292LmNuL25hdGlvbmFsSGFsbFN0LyMvc2VhcmNoL21lZGljYWw/Y29kZT05MDAwMCZmbGFnPWZhbHNlJmdiRmxhZz10cnVl

    打開網站后,需要的就是中間顯示的數據

    分析數據來自于哪個接口就跳過了,因為不重要,這里直接說結果

    其中數據來自于【queryFixedHospital】這個接口,本次要分析的就是請求頭中所有【x-tif】開頭的參數,以及請求體中的【encData】和【signData】的生成算法

    然后隨便搜索請求體中的【encData】或者【signData】,都可以直接定位到【app.1654997618917.js】這個js文件

    這里可以直接找到所有參數的生成的地方,好像比較順利,接著從上往下開始分析

    【paasid】是定值,【timestamp】是當前時間戳,【nonce】是8位隨機值,這三個都非常容易看出來,而【signature】就是【s(g)】的結果,g就是時間戳拼接隨機值再拼接時間戳,s就是sha256函數。請求頭的參數非常容易,接下來看看請求體的參數。

    在signData函數內部下一個斷點

    其中比較重要的是【v(i)】的函數,這里生成了一段字符串來計算簽名

    這個函數和查詢參數編碼的功能類似,除了data參數,并且在最后拼接了一個定值字符串,這里用python進行簡單的復現

     復制代碼 隱藏代碼
    def v(e):    t = []
        for n in e:
            if n == 'data':
                data = e[n].copy()
                for each in e[n]:
                    if not data[each]:
                        del data[each]
                    else:
                        data[each] = str(data[each])
                t.append(n + '=' + json.dumps(data, separators=(',', ':')))
            else:
                t.append(n + '=' + str(e[n]))
        t.append('key=NMVFVILMKT13GEMD3BKPKCTBOQBPZR2P')
        return '&'.join(t)
    

    獲取到這段字符串后繼續往下走,就進入到了【doSignature】函數

    這里的第一個參數就是前面的字符串,第二個參數就是私鑰

    來到這里有一個判斷,因為前面傳入的hash參數恒為真,所以要先對簽名的內容計算hash,計算hash用到的是【y】函數,網上查看來源

    這里可以看到,【y】函數就是sm3算法。繼續進入到【y】函數分析

    可以看到這里更新了兩次數據,相當于是計算這兩個數據的hash,首先是r參數,這個是【getZ】函數的返回值。另一個是a參數,就是前面傳入的字符串,這個前面已經分析了,那么繼續進入到【getZ】函數查看

    這里又是一個sm3算法,這次更新的參數就比較多了,包括一個【1234567812345678】的一個固定值,以及sm2算法的初始化ecc表,還有傳入的私鑰。這里已經可以發現,所有的參數其實都是定值(私鑰一般不改的情況下),那么這里的返回值也是一個固定的值【fde9a74125ca149ca75f4c2ccdaeed3e7d0b4b8c0f2c9e35530b9fe9a3ba1233】,代碼中可以寫成固定值,這里只是說明【getZ】函數的算法,用python還原getZ函數

     復制代碼 隱藏代碼
    def getZ(crypto):    sign_data = bytes()
        n = '1234567812345678'.encode()
        sign_data += bytes([0, 8 * len(n)])
        sign_data += n
        sign_data += bytes.fromhex(crypto.ecc_table['a'])
        sign_data += bytes.fromhex(crypto.ecc_table['b'])
        sign_data += bytes.fromhex(crypto.ecc_table['g'])
        sign_data += bytes.fromhex(crypto.public_key[2:])
        return bytes.fromhex(sm3.sm3_hash(list(sign_data)))
        # 可以寫成固定值    # return bytes.fromhex('fde9a74125ca149ca75f4c2ccdaeed3e7d0b4b8c0f2c9e35530b9fe9a3ba1233')
    

    那么將【getZ】的返回值和前面的字符串一起計算sm3,就得到了消息hash

    接著將消息hash計算sm2簽名,就得到了【signData】了,最后分析【encData】參數。

    【encData】這里固定傳入了sm4,那么必定走sm4的分支,進入函數繼續分析

    這個函數比較短,主要是一個b函數,一個w函數,其中b函數是用來計算一個密鑰

    用python還原也比較簡單

     復制代碼 隱藏代碼
    def b(e, t):    crypto = sm4.CryptSM4()
        crypto.set_key(e[:16].encode(), sm4.SM4_ENCRYPT)
        return crypto.crypt_ecb(t.encode()).hex().upper()[:16]
    

    拿到密鑰后,直接使用sm4算法加密就可以得到【encData】了,現在所有參數都已經能夠獲取了,就可以發送請求了。

    不過請求的響應也是加密的,幸好的是解密就一個sm4算法,key和前面的是一樣的,那么直接解密就可以了,完整代碼

     復制代碼 隱藏代碼
    import requests_htmlimport randomimport timeimport jsonimport base64from Crypto.Hash import SHA256from gmssl import sm2, sm3, sm4, func
    publicKey = base64.b64decode("BEKaw3Qtc31LG/hTPHFPlriKuAn/nzTWl8LiRxLw4iQiSUIyuglptFxNkdCiNXcXvkqTH79Rh/A2sEFU6hjeK3k=".encode()).hex()
    privateKey = base64.b64decode("AJxKNdmspMaPGj+onJNoQ0cgWk2E3CYFWKBJhpcJrAtC".encode()).hex()
    appSecret = 'NMVFVILMKT13GEMD3BKPKCTBOQBPZR2P'appCode = 'T98HPCGN5ZVVQBS8LZQNOAEXVI9GYHKQ'def main():    requests = requests_html.HTMLSession()
        key = b(appCode, appSecret).encode()
        s = str(int(time.time()))
        c = ''.join(random.choices("ABCDEFGHIJKLMNOPQRSTUVWXYZzbcdefghijklmnopqrstuvwxyz0123456789", k=8))
        headers = {
            'x-tif-paasid': 'undefined',
            '"x-tif-timestamp': s,
            'x-tif-nonce': c,
            '"x-tif-signature': SHA256.new((s + c + s).encode()).hexdigest(),
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'    }
        data = {
            'appCode': appCode,
            'data': {
                'addr': '',
                'medinsLvCode': '',
                'medinsName': '',
                'medinsTypeCode': '',
                'openElec': '',
                'pageNum': 1,
                'pageSize': 10,
                'regnCode': '110000'        },
            'encType': 'SM4',
            'signType': 'SM2',
            'timestamp': int(s),
            'version': '1.0.0'    }
        crypto = sm2.CryptSM2(privateKey, publicKey)
        data['signData'] = base64.b64encode(bytes.fromhex(crypto.sign(bytes.fromhex(sm3.sm3_hash(list(getZ(crypto) + v(data).encode()))), func.random_hex(crypto.para_len)))).decode()
        crypto = sm4.CryptSM4()
        crypto.set_key(key, sm4.SM4_ENCRYPT)
        data['data'] = {
            'encData': crypto.crypt_ecb(json.dumps(data['data']).encode()).hex().upper()
        }
        data = {
            'data': data
        }
        response = requests.post('https://fuwu.nhsa.gov.cn/ebus/fuwu/api/nthl/api/CommQuery/queryFixedHospital', json=data, headers=headers).json()
        crypto = sm4.CryptSM4()
        crypto.set_key(key, sm4.SM4_DECRYPT)
        data = json.loads(crypto.crypt_ecb(bytes.fromhex(response['data']['data']['encData'])).decode())
        print(data)def getZ(crypto):    sign_data = bytes()
        n = '1234567812345678'.encode()
        sign_data += bytes([0, 8 * len(n)])
        sign_data += n
        sign_data += bytes.fromhex(crypto.ecc_table['a'])
        sign_data += bytes.fromhex(crypto.ecc_table['b'])
        sign_data += bytes.fromhex(crypto.ecc_table['g'])
        sign_data += bytes.fromhex(crypto.public_key[2:])
        return bytes.fromhex(sm3.sm3_hash(list(sign_data)))
        # 可以寫成固定值    # return bytes.fromhex('fde9a74125ca149ca75f4c2ccdaeed3e7d0b4b8c0f2c9e35530b9fe9a3ba1233')def v(e):    t = []
        for n in e:
            if n == 'data':
                data = e[n].copy()
                for each in e[n]:
                    if not data[each]:
                        del data[each]
                    else:
                        data[each] = str(data[each])
                t.append(n + '=' + json.dumps(data, separators=(',', ':')))
            else:
                t.append(n + '=' + str(e[n]))
        t.append('key=' + appSecret)
        return '&'.join(t)def b(e, t):    crypto = sm4.CryptSM4()
        crypto.set_key(e[:16].encode(), sm4.SM4_ENCRYPT)
        return crypto.crypt_ecb(t.encode()).hex().upper()[:16]if __name__ == '__main__':
        main()
    

    成功獲取到結果,完成!!!

    datasign函數
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    根據代碼得出 sb的值為頁碼+時間戳 "page=21652931584"。再次hook Sign函數查看參數和返回值并與fiddler對比。此時已經可以斷定,這個Sign就是翻頁的加密函數 。我們用python實現一下。此時直接調用sign生成加密參數,抓取100頁的值相加得出flag:#!
    初衷是刷抖音太多,發現不能在點贊過的視頻列表中直接搜索,就想自己實現下,把這個過程做了下記錄,當學習筆記了,純技術交流用。
    請求頭的參數非常容易,接下來看看請求體的參數。在signData函數內部下一個斷點其中比較重要的是的函數,這里生成了一段字符串來計算簽名這個函數和查詢參數編碼的功能類似,除了data參數,并且在最后拼接了一個定值字符串,這里用python進行簡單的復現 復制代碼 隱藏代碼。拿到密鑰后,直接使用sm4算法加密就可以得到了,現在所有參數都已經能夠獲取了,就可以發送請求了。
    意料之中一大堆參數,反復幾次總結需分析的參數應該為以下幾個:X-Sign、wToken、X-Ca-Signature、X-Access-Token、X-Ca-Timestamp. 跟進得:public static Map z { String str; String a2 = wo3.a; HashMap hashMap = new HashMap(); hashMap.put; hashMap.put; hashMap.put; if (!TextUtils.isEmpty) { hashMap.put; no3.a; } hashMap.put("Authorization", StringUtils.isEmpty(it3.g()) ?= '\t') || charAt >= 127) { str2.replace; } } hashMap.put; hashMap.put("X-ConnectionType", y
    js逆向一直沒有相關了解,雖然目前滲透遇見的不是很多,大多數遇見的要么不加密,要么無法實現其加密流程,不過最近看到了一個較為簡單的站點正好能夠逆向出來,就做了簡單記錄。本文旨在介紹js逆向的一些基礎思路,希望能對初學js前端逆向的師傅有所幫助。
    日常滲透測試中,在進行數據包的重放或者是篡改數據包時,會碰到一些存在數據加密或加簽的站點,這時我們就得尋找加簽或者加密的算法,而這尋找過程往往有一定難度。 總的來講,對于數據解密或者加簽破解的難度:app>web≥wxapp,同時api接口都是相同的,為降低不必要的挖洞難度,可將目光放到微信小程序上。本次就是以一個微信小程序站點開展的測試。
    Ida的trace功能,這種方法本身是非常好的一種方法,因為大部分的情況下這種方法更有效也更簡單,但目前這種方式已知存在一些問題導致這種方式的使用受限。①慢,ida trace的方式會很慢,所以一般都是在縮小范圍后再使用這種trace的方式來操作。
    準備◆iOS 12.5.5◆frida 14.0.0◆ipa 5rG96L2m5LmL5a62 11.33.5抓包1.抓包使用 charles,請自行安裝并配置證書。使用假賬密測試抓包 123456 / 123456,能夠抓包成功。分析1、登錄頁面需要輸入3個信息,分別是賬號 / 密碼 / 驗證碼,對應字段 logincode / userpwd / validcode。
    無意中看到ch1ng師傅的文章覺得很有趣,不得不感嘆師傅太厲害了,但我一看那長篇的函數總覺得會有更騷的東西,所幸還真的有,借此機會就發出來一探究竟,同時也不得不感慨下RFC文檔的妙處,當然本文針對的技術也僅僅只是在流量層面上waf的繞過。Pre很神奇對吧,當然這不是終點,接下來我們就來一探究竟。前置這里簡單說一下師傅的思路部署與處理上傳war的servlet是?
    MRCTF2022 stuuuuub 題解
    2023-02-07 10:15:04
    Overview學了這么一段時間的Android,難得見到的一道比較對口的逆向題。e.c()通過執行which su命令后讀取輸出來檢查是否有su文件。讀取res.dat文件后調用了decodeSo函數進行解密存放在應用的數據目錄下的libnative.so,而decodeSo是libstub.so里的native函數。但是在libstub.so里卻沒有直接找到decodeSo函數,因此應該是JNI_OnLoad里動態注冊的。decode String另外libstub.so使用了Ollvm的字符串加密和控制流平坦化。這里參考官方給的WP中使用了AndroidNativeEmu框架。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类