Encrypt-labs(无混淆)
AES固定key
进入靶场是一个登陆页面,输入账号密码admin/123456进行登陆,并抓包 发现数据包被加密了,加密参数为 encryptedData
直接跟进js查看对应参数所在位置,直接在进入位置下断点(这里也就是对应27行),再次抓包
得到如下所示:
往上寻找就能发现对应的加密函数
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)}
根据断点信息可知:此处加密采用AES-CBC-PKCS5Padding,并且Key和 IV 也给出了采用硬编码的格式(就是不通过变量或配置文件来表示,直接将具体的数值、路径、参数等直接写入程序代码中)
那么我们就可以利用BP插件来进行数据包的自动解密,这里用的是autoDecoder这个插件:
输入key
/ iv
,设置正则表达式
,正确设置正则表达式
之后才可以实现自动解密
配置需要加解密的域名
然后尝试重放
也可以采用另一个插件BurpCrypto
这个工具有个缺点就是第一次尝试需要由用户进行手动测试一次,
AES服务端获取Key
点击第二关抓包,可以获取到两个数据包,一个是服务端返回的key
和iv
,一个是登录数据包
经过测试发现,重发数据包该key
和iv
,发现key
和iv
短时间内不会发生变化,应该是服务端和客户端断连之前,key
和iv
都会保持不变
{"aes_key":"OUd4SEqDsA1GP2l8WszZnQ==","aes_iv":"RQenJ2Hszn1p7Q6poVngFQ=="}
查看js数据,确定为AES
加密
autoDecoder
RSA加密
抓包查看:加密参数是data
进入eazy.js
下断点,往上查看,很容易获取到了publickey
经确认为RSA
加密,RSA
加密需一个公钥,解密需要私钥,没有私钥,只能尝试加密
AES+Rsa加密
抓包查看
下断点往上查看
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));
被加密的参数是formData
也就是"{"username":"admin","password":"123456"}"
,经过AES
加密,且加密使用的key
和iv
是16位随机数、得到encryptedData
之后对key
和iv
进行rsa
加密得到encryptedKey
和encryptedIv
再将这三个参数传入数据包中,发包进行验证
现在想办法将随机16位的key
和iv
进行固定,右键选择替换内容,使用本地替换的方式将key
和iv
固定下来,就选择之前第一关的key
和iv
即可
再次下断点,查看是否修改成功,可以看到已经修改成功,key
和iv
变成了1234567890123456
成功替换encryptedData
,其中加密的key
和iv
经过测试似乎不用替换也能通过,就不进行加解密操作了
Des规律Key
抓包查看,可以看到只对password
进行了加密
进入js
下断点抓包
可以看到就是简单的DES
加密,key
和iv
都使用了username
的值
key
是八位,如果username
不满8位,则用6补满
iv
是八位,9999+username的前四位
key:admin666 iv:9999admi
成功解密
明文加签
依旧抓包
可以看到有两个参数不清楚是啥,分别是nonce
,signature,
还有个时间戳,分析下js看看,依旧是js中下断点,发包
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位随机数
dataToSign:username + password + nonce + timestamp
signature:由dataToSign
经SHA256
加密生成,secretKey
为固定值be56e057f20f883e
SHA256
在autoDecoer
中没有,尝试自写发包器,其中nonce
可以随机生成也可以固定
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) # 发包间隔
加签key在服务端
依旧抓包,发送了俩数据包
通过第一个数据包获取signature
,第二个数据包发包时加上这个,达到加签key在服务端的效果
emmm测试了下,如果要做密码爆破操作的话,需要发第一个包
获取对应的signature
值,丢到第二个包中,依旧是自写脚本即可,不难,这里不演示了。
禁止重放
还是抓包 账号密码还是明文的,多次重放发现返回No Repeater
其中加密参数为random
,分析js看看
依旧是断点,查看
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();
现在是要寻找random
参数怎么来的,根据上面js可知是通过encryptedTimestamp
来的,encryptedTimestamp
是通过时间戳经过RSA
加密来的,依旧写一个发包器来实现
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))) # 时间戳
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)