前言 文章首發(fā)于先知社區(qū): https://xz.aliyun.com/t/16919
項(xiàng)目地址: https://github.com/SwagXz/encrypt-labs
作者: SwagXz
現(xiàn)在日子越來(lái)越不好過(guò)了,無(wú)論攻防、企業(yè)src還是滲透項(xiàng)目,總能看到大量的存在加密的網(wǎng)站,XZ師傅的前端加密靶場(chǎng)還是很值得做一做的,環(huán)境很貼合實(shí)戰(zhàn)會(huì)遇到的一些情況,本人web小菜雞練完之后反正是收獲頗豐,推薦給各位師傅。
之前自己在學(xué)習(xí)前端加解密經(jīng)常遇到加密解不了的情況;之后慢慢看師傅們的文章,也學(xué)到了很多繞過(guò)技術(shù),于是寫(xiě)了個(gè)簡(jiǎn)單的靶場(chǎng),為之后的師傅們鋪路學(xué)習(xí),加密方式列出了我經(jīng)常見(jiàn)的8種方式包含非對(duì)稱加密、對(duì)稱加密、加簽以及禁止重放的測(cè)試場(chǎng)景,比如AES、DES、RSA,用于滲透測(cè)試加解密練習(xí)。希望可以幫助到最近在學(xué)習(xí)這塊知識(shí)的師傅,靶場(chǎng)函數(shù).很簡(jiǎn)單,和實(shí)戰(zhàn)相比還是差的有點(diǎn)多,不過(guò)應(yīng)該夠入門了
默認(rèn)密碼:admin/123456
http://82.156.57.228:43899 (混淆)
http://82.156.57.228:43899/easy.php (無(wú)混淆)
加解密插件/工具 burp自動(dòng)加解密插件autoDeceder: https://github.com/f0ng/autoDecoder
這個(gè)插件可以幫忙處理常見(jiàn)的 AES、DES、SM4、SM2、RSA
等加密,灰常好用
還有個(gè)瀏覽器插件: Ctool 程序開(kāi)發(fā)常用工具:https://v/
直接在谷歌商店或者火狐商店即可下載
也是可以對(duì)常見(jiàn)的加密方式進(jìn)行加密解密,這個(gè)適用的加解密方式更多,如果只是用于驗(yàn)證加解密情況的話,這個(gè)插件會(huì)方便很多
encrypt-labs 使用無(wú)混淆的進(jìn)行測(cè)試說(shuō)明
http://82.156.57.228:43899/easy.php (無(wú)混淆)
admin/123456
【第一關(guān)】AES固定key 抓包發(fā)現(xiàn)數(shù)據(jù)包被加密了:加密參數(shù)為 encryptedData
直接跟進(jìn)js查看,直接在進(jìn)入位置下斷點(diǎn),再次抓包
一個(gè)斷點(diǎn)直接找到加密后的數(shù)據(jù)和加密前的數(shù)據(jù),向上查找,發(fā)現(xiàn)是用 AES
加密
function sendDataAes(url) { const formData = { username: document.getElementById( 'username' ) .value, password: document.getElementById( 'password' ) .value }; const jsonData = JSON.stringify(formData); const key = CryptoJS.enc.Utf8.parse( '1234567890123456' ); const iv = CryptoJS.enc.Utf8.parse( '1234567890123456' ); const encrypted = CryptoJS.AES.encrypt(jsonData, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }) .toString(); const params = `encryptedData= ${encodeURIComponent(encrypted)}
根據(jù)斷點(diǎn)信息可知:
AES
加密, CBC
模式, PKCS5Padding
key:1234567890123456
/ iv:1234567890123456
autoDecoder 配置數(shù)據(jù)包自動(dòng)加解密
輸入 key
/ iv
,設(shè)置 正則表達(dá)式
,正確設(shè)置 正則表達(dá)式
之后才可以實(shí)現(xiàn)自動(dòng)解密
配置需要加解密的域名
嘗試重放
【第二關(guān)】AES服務(wù)端獲取Key 點(diǎn)擊第二關(guān)抓包,可以獲取到兩個(gè)數(shù)據(jù)包,一個(gè)是服務(wù)端返回的 key
和 iv
,一個(gè)是登錄數(shù)據(jù)包
經(jīng)過(guò)測(cè)試發(fā)現(xiàn),重發(fā)數(shù)據(jù)包該 key
和 iv
,發(fā)現(xiàn) key
和 iv
短時(shí)間內(nèi)不會(huì)發(fā)生變化,應(yīng)該是服務(wù)端和客戶端斷連之前, key
和 iv
都會(huì)保持不變
{ 'aes_key' : 'OUd4SEqDsA1GP2l8WszZnQ==' , 'aes_iv' : 'RQenJ2Hszn1p7Q6poVngFQ==' }
查看js數(shù)據(jù),確定為 AES
加密
autoDecoder 【第三關(guān)】RSA加密 抓包查看:加密參數(shù)是 data
進(jìn)入 eazy.js
下斷點(diǎn),往上查看,很容易獲取到了 publickey
-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRvA7giwinEkaTYllDYCkzujvi NH+up0XAKXQot8RixKGpB7nr8AdidEvuo+wVCxZwDK3hlcRGrrqt0Gxqwc11btlM DSj92Mr3xSaJcshZU8kfj325L8DRh9jpruphHBfh955ihvbednGAvOHOrz3Qy3Cb ocDbsNeCwNpRxwjIdQIDAQAB -----END PUBLIC KEY-----
經(jīng)確認(rèn)為 RSA
加密, RSA
加密需一個(gè)公鑰,解密需要私鑰,沒(méi)有私鑰,只能嘗試加密
autoDecoder 【第四關(guān)】AES+Rsa加密 抓包查看 下斷點(diǎn)往上查看
function sendDataAesRsa(url) { const formData = { username: document.getElementById( 'username' ) .value, password: document.getElementById( 'password' ) .value }; const jsonData = JSON.stringify(formData); const key = CryptoJS.lib.WordArray.random(16); const iv = CryptoJS.lib.WordArray.random(16); const encryptedData = CryptoJS.AES.encrypt(jsonData, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }) .toString(); const rsa = new JSEncrypt(); rsa.setPublicKey(`-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRvA7giwinEkaTYllDYCkzujvi NH+up0XAKXQot8RixKGpB7nr8AdidEvuo+wVCxZwDK3hlcRGrrqt0Gxqwc11btlM DSj92Mr3xSaJcshZU8kfj325L8DRh9jpruphHBfh955ihvbednGAvOHOrz3Qy3Cb ocDbsNeCwNpRxwjIdQIDAQAB -----END PUBLIC KEY-----`); const encryptedKey = rsa.encrypt(key.toString(CryptoJS.enc.Base64)); const encryptedIv = rsa.encrypt(iv.toString(CryptoJS.enc.Base64));
被加密的參數(shù)是 formData
也就是 '{'username':'admin','password':'123456'}'
,經(jīng)過(guò) AES
加密,且加密使用的 key
和 iv
是16位隨機(jī)數(shù)、得到 encryptedData
之后對(duì) key
和 iv
進(jìn)行 rsa
加密得到 encryptedKey
和 encryptedIv
再將這三個(gè)參數(shù)傳入數(shù)據(jù)包中,發(fā)包進(jìn)行驗(yàn)證
現(xiàn)在想辦法將隨機(jī)16位的 key
和 iv
進(jìn)行固定,右鍵選擇替換內(nèi)容,使用本地替換的方式將 key
和 iv
固定下來(lái),就選擇之前第一關(guān)的 key
和 iv
即可
再次下斷點(diǎn),查看是否修改成功,可以看到已經(jīng)修改成功, key
和 iv
變成了 1234567890123456
成功替換 encryptedData
,其中加密的 key
和 iv
經(jīng)過(guò)測(cè)試似乎不用替換也能通過(guò),就不進(jìn)行加解密操作了
【第五關(guān)】Des規(guī)律Key 抓包查看,可以看到只對(duì) password
進(jìn)行了加密
進(jìn)入js
下斷點(diǎn)抓包
可以看到就是簡(jiǎn)單的DES
加密, key
和 iv
都使用了 username
的值
key
是八位,如果 username
不滿8位,則用6補(bǔ)滿
iv
是八位,9999+username的前四位
key:admin666 iv:9999admi
autoDecode 成功解密
【第六關(guān)】明文加簽 依舊抓包
可以看到有兩個(gè)參數(shù)不清楚是啥,分別是 nonce
, signature,
還有個(gè)時(shí)間戳,分析下js看看,依舊是js中下斷點(diǎn),發(fā)包
function sendDataWithNonce(url) { const username = document.getElementById( 'username' ) .value; const password = document.getElementById( 'password' ) .value; const nonce = Math.random() .toString(36) .substring(2); const timestamp = Math.floor(Date.now() / 1000); const secretKey = 'be56e057f20f883e' ; const dataToSign = username + password + nonce + timestamp; const signature = CryptoJS.HmacSHA256(dataToSign, secretKey) .toString(CryptoJS.enc.Hex);
nonce:由 0-9 a-z
生成的10位隨機(jī)數(shù)
dataToSign: username + password + nonce + timestamp
signature:由 dataToSign
經(jīng) SHA256
加密生成, secretKey
為固定值 be56e057f20f883e
SHA256
在 autoDecoer
中沒(méi)有,嘗試自寫(xiě)發(fā)包器,其中 nonce
可以隨機(jī)生成也可以固定
import requests import time import hashlib import hmac def generate_signature(username, password, nonce, timestamp, secret_key): data_to_sign = username + password + nonce + str(timestamp) h = hmac.new(secret_key.encode( 'utf-8' ), digestmod=hashlib.sha256) h.update(data_to_sign.encode( 'utf-8' )) return h.hexdigest() url = 'http://82.156.57.228:43899/encrypt/signdata.php' username = 'admin' password = '123456' nonce = 'dq7kos6hzy' secret_key = 'be56e057f20f883e' while True: timestamp = int(time.time()) signature = generate_signature(username, password, nonce, timestamp, secret_key) headers = { 'Host' : '82.156.57.228:43899' , 'Content-Length' : '163' , 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36' , 'Content-Type' : 'application/json' , 'Accept' : '*/*' , 'Origin' : 'http://82.156.57.228:43899' , 'Referer' : 'http://82.156.57.228:43899/easy.php' , 'Accept-Encoding' : 'gzip, deflate' , 'Accept-Language' : 'zh-CN,zh;q=0.9' , 'Cookie' : 'PHPSESSID=q3nlpgst4h9kpdiklq2rcbrnc1' , 'Connection' : 'close' } data = { 'username' : username, 'password' : password, 'nonce' : nonce, 'timestamp' : timestamp, 'signature' : signature } response = requests.post(url, json=data, headers=headers) print (response.status_code) print (response.text) time.sleep(1) # 發(fā)包間隔
【第七關(guān)】加簽key在服務(wù)端 依舊抓包,發(fā)送了倆數(shù)據(jù)包
通過(guò)第一個(gè)數(shù)據(jù)包獲取 signature
,第二個(gè)數(shù)據(jù)包發(fā)包時(shí)加上這個(gè),達(dá)到加簽key在服務(wù)端的效果
emmm測(cè)試了下,如果要做密碼爆破操作的話,需要發(fā)第一個(gè)包
獲取對(duì)應(yīng)的 signature
值,丟到第二個(gè)包中,依舊是自寫(xiě)腳本即可,不難,這里不演示了。
【第八關(guān)】禁止重放 還是抓包 賬號(hào)密碼還是明文的,多次重放發(fā)現(xiàn)返回 No Repeater
其中加密參數(shù)為 random
,分析js看看
依舊是斷點(diǎn),查看
function generateRequestData () { const username = document.getElementById( 'username' ).value; const password = document.getElementById( 'password' ).value; const timestamp = Date.now(); const publicKey = `-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRvA7giwinEkaTYllDYCkzujvi NH+up0XAKXQot8RixKGpB7nr8AdidEvuo+wVCxZwDK3hlcRGrrqt0Gxqwc11btlM DSj92Mr3xSaJcshZU8kfj325L8DRh9jpruphHBfh955ihvbednGAvOHOrz3Qy3Cb ocDbsNeCwNpRxwjIdQIDAQAB -----END PUBLIC KEY-----`; function rsaEncrypt(data, publicKey) { const jsEncrypt = new JSEncrypt(); jsEncrypt.setPublicKey(publicKey); const encrypted = jsEncrypt.encrypt(data.toString()); if (!encrypted) { throw new Error( 'RSA encryption failed.' ); } return encrypted; } // Encrypt the timestamp let encryptedTimestamp; try { encryptedTimestamp = rsaEncrypt(timestamp, publicKey); } catch (error) { console.error( 'Encryption error:' , error); return null; } const dataToSend = { username: username, password: password, random: encryptedTimestamp // Replace timestamp with encrypted version }; return dataToSend; } function sendLoginRequest(url) { const dataToSend = generateRequestData();unction sendLoginRequest(url) { const dataToSend = generateRequestData(); function generateRequestData () { const username = document.getElementById( 'username' ).value; const password = document.getElementById( 'password' ).value; const timestamp = Date.now();
現(xiàn)在是要尋找 random
參數(shù)怎么來(lái)的,根據(jù)上面js可知是通過(guò) encryptedTimestamp
來(lái)的, encryptedTimestamp
是通過(guò)時(shí)間戳經(jīng)過(guò) RSA
加密來(lái)的
依舊寫(xiě)一個(gè)發(fā)包器來(lái)實(shí)現(xiàn)
import requests import json from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_v1_5 from Crypto.Cipher import AES from Crypto.Util.Padding import pad from base64 import b64encode, b64decode import time def rsa_encrypt(data, public_key): '' ' RSA加密,Base64格式 ' '' key = RSA.import_key(public_key) cipher = PKCS1_v1_5.new(key) encrypted_data = cipher.encrypt(data.encode( 'utf-8' )) return b64encode(encrypted_data).decode( 'utf-8' ) def generate_request_data(): '' ' 生成random字段 ' '' username = 'admin' password = '123456' timestamp = str(int(round(time.time() * 1000))) # 時(shí)間戳 print (timestamp) public_key = '' '-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRvA7giwinEkaTYllDYCkzujvi NH+up0XAKXQot8RixKGpB7nr8AdidEvuo+wVCxZwDK3hlcRGrrqt0Gxqwc11btlM DSj92Mr3xSaJcshZU8kfj325L8DRh9jpruphHBfh955ihvbednGAvOHOrz3Qy3Cb ocDbsNeCwNpRxwjIdQIDAQAB\n-----END PUBLIC KEY-----' '' encrypted_timestamp = rsa_encrypt(timestamp, public_key) data_to_send = { 'username' : username, 'password' : password, 'random' : encrypted_timestamp } print (data_to_send) return data_to_send def send_request(): url = 'http://82.156.57.228:43899/encrypt/norepeater.php' headers = { 'Host' : '82.156.57.228:43899' , 'Content-Length' : '224' , 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36' , 'Content-Type' : 'application/json; charset=utf-8' , 'Accept' : '*/*' , 'Origin' : 'http://82.156.57.228:43899' , 'Referer' : 'http://82.156.57.228:43899/easy.php' , 'Accept-Encoding' : 'gzip, deflate' , 'Accept-Language' : 'zh-CN,zh;q=0.9' , 'Connection' : 'close' } data = generate_request_data() response = requests.post(url, headers=headers, data=json.dumps(data)) print (response.text) if __name__ == '__main__' : while True: send_request() time.sleep(5)