【老规矩,题目相关的附件,公众号后台回复关键字:2023熵密杯】
初始谜题
请输入谜题服务器IP地址(Please input Puzzle Server IP Address)
172.10.42.212
请输入谜题服务器端口号(Please input Puzzle Server Port Number)
8070
-----------------------------------------------------
MSG1:
e55e3e24a3ae7797808fdca05a16ac15eb5fa2e6185c23a814a35ba32b4637c2
MAC1:
0712c867aa6ec7c1bb2b66312367b2c8
-----------------------------------------------------
MSG2:
d8d94f33797e1f41cab9217793b2d0f02b93d46c2ead104dce4bfec453767719
MAC2:
43669127ae268092c056fd8d03b38b5b
-----------------------------------------------------
请输入您的MSG3(64字节,128个Hex,不要添加空格!)(Please input your 64bytes MSG3(64 bytes,128 hexs,don't using space)):
计算 :
hex(0x0712c867aa6ec7c1bb2b66312367b2c8^0xd8d94f33797e1f41cab9217793b2d0f0)
=> '0xdfcb8754d310d88071924746b0d56238'
在拼上 :2b93d46c2ead104dce4bfec453767719
得到最终的消息:e55e3e24a3ae7797808fdca05a16ac15eb5fa2e6185c23a814a35ba32b4637c2dfcb8754d310d88071924746b0d562382b93d46c2ead104dce4bfec453767719
然后输出 就能通过验证,如下所示
请输入您的MSG3(64字节,128个Hex,不要添加空格!)(Please input your 64bytes MSG3(64 bytes,128 hexs,don't using space)):
e55e3e24a3ae7797808fdca05a16ac15eb5fa2e6185c23a814a35ba32b4637c2dfcb8754d310d88071924746b0d562382b93d46c2ead104dce4bfec453767719
请输入您的MAC3(Please input your MAC3):
43669127ae268092c056fd8d03b38b5b
-----------------------------------------------------
**恭喜!谜题答案验证正确!(Congratulations!Puzzle verified correctly!)**
下面是您的战利品,请妥善记录后再关闭程序,(Your Spoils of war is follow,Please copy that before shutdown this program!)**
-----------------------------------------------------
Flag:
flag{N1lC9AuYQaPZo68G4ZSkw9PBgTMRFkkh}
-----------------------------------------------------
Gitea User Name:
TFCTEVTION
-----------------------------------------------------
Gitea Password:
#s@f3ty2024
-----------------------------------------------------
请按回车键结束谜题程序(Please press "Enter" key to end)
第一关
<!!!!!!!!!!!!解密!解开我,你将获得全部信息!!!!!!!!!!!!!!!!!!>
6B562E2D3E7B6C61636078616C666C62
#include <stdio.h>
void reverseBits(unsigned char* password) {
int i, j;
unsigned char temp;
for (i = 0; i < 16; i++) {
temp = 0;
for (j = 0; j < 8; j++) {
temp |= ((password[i] >> j) & 1) << (7 - j);
}
password[i] = temp;
}
}
void swapPositions(unsigned char* password) {
int i;
unsigned char temp[16];
int positions[16] =
{
13, 4, 0, 5,
2, 12, 11, 8,
10, 6, 1, 9,
3, 15, 7, 14
};
for (i = 0; i < 16; i++) {
temp[positions[i]] = password[i];
}
for (i = 0; i < 16; i++) {
password[i] = temp[i];
}
}
void leftShiftBytes(unsigned char* password) {
for (int i = 0; i < 16; i++) {
password[i] = password[i] << 3 | password[i] >> 5;
}
}
void xorWithKeys(unsigned char* password, unsigned int round) {
int i;
for (i = 0; i < 16; i++) {
password[i] ^= (unsigned char)(0x78 * round & 0xFF);
}
}
void encryptPassword(unsigned char* password) {
int i;
unsigned int round;
for (round = 0; round < 16; round++) {
reverseBits(password);
swapPositions(password);
leftShiftBytes(password);
xorWithKeys(password, round);
}
}
int main() {
unsigned char password[17] = "1234567890";
printf("加密前的口令为:n");
for (int i = 0; i < 16; i++) {
printf("%02X ", password[i]);
}
encryptPassword(password);
printf("加密后的口令为:n");
for (int i = 0; i < 16; i++) {
printf("%02X ", password[i]);
}
printf("n");
return 0;
}
0x78 * round & 0xFF
void xorWithKeys(unsigned char* password, unsigned int round) {
int i;
for (i = 0; i < 16; i++) {
password[i] ^= (unsigned char)(0x78 * round & 0xFF);
}
}
round
的值反着用一遍就好 newa= ""
for each in a:
newa += chr(ord(each)^((0x78*round)&0xff))
a = newa
void leftShiftBytes(unsigned char* password) {
for (int i = 0; i < 16; i++) {
password[i] = password[i] << 3 | password[i] >> 5;
}
}
newa = ""
for each in a:
tmp = bin(ord(each))[2:].rjust(8,'0')
atmp = tmp[5:]+tmp[:5]
newa += chr(int(atmp,2))
a = newa
void swapPositions(unsigned char* password) {
int i;
unsigned char temp[16];
int positions[16] =
{
13, 4, 0, 5,
2, 12, 11, 8,
10, 6, 1, 9,
3, 15, 7, 14
};
for (i = 0; i < 16; i++) {
temp[positions[i]] = password[i];
}
for (i = 0; i < 16; i++) {
password[i] = temp[i];
}
}
table = [13, 4, 0, 5,2, 12, 11, 8,10, 6, 1, 9,3, 15, 7, 14]
newa = ""
for i in range(16):
newa += a[table[i]]
a = newa
from Crypto.Util.number import *
a = long_to_bytes(0x6B562E2D3E7B6C61636078616C666C62).decode()
print(a)
for round in range(15,-1,-1):
newa= ""
for each in a:
newa += chr(ord(each)^((0x78*round)&0xff))
a = newa
#print(a)
newa = ""
for each in a:
tmp = bin(ord(each))[2:].rjust(8,'0')
atmp = tmp[5:]+tmp[:5]
newa += chr(int(atmp,2))
a = newa
table = [13, 4, 0, 5,2, 12, 11, 8,10, 6, 1, 9,3, 15, 7, 14]
newa = ""
for i in range(16):
newa += a[table[i]]
a = newa
newa = ""
for each in a:
abin = bin(ord(each))[2:].rjust(8,'0')
abinr = abin[::-1]
newa += chr(int(abinr,2))
a = newa
print(a)
pdksidicndjh%^&6
,解密压缩包获得 flag:**flag1{52e0acce-1e87-c966-43a4-59995df10b10}**,和两个流量包 数字签名系统调试数据包.pcapng、数字签名前置系统调试数据包.pcapng,和两份源代码 login.go、download.go。第二关
根据靶场上的网络拓扑,我们能进入数字签名前置系统
login.go
func CertLogin(c *gin.Context, conf config.Config) {
randNumStr := c.PostForm("randNum")
if randNumStr == "" {
username := c.PostForm("username")
if username == "" {
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,必须输入用户名", "code": 0})
return
}
certFile, err := c.FormFile("file")
if err != nil {
//fmt.Println(err)
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,无效证书[代码:1001]", "code": 0})
return
}
if !strings.Contains(certFile.Header.Get("Content-Type"), "cert") {
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,无效证书[代码:1002]", "code": 0})
return
}
srcCert, err := certFile.Open()
if err != nil {
//fmt.Println(err)
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,无效证书[代码:1003]", "code": 0})
return
}
defer func(srcCert multipart.File) {
err := srcCert.Close()
if err != nil {
//fmt.Println(err)
}
}(srcCert)
certContent := make([]byte, certFile.Size)
_, err = srcCert.Read(certContent)
if err != nil {
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,无效证书[代码:1004]", "code": 0})
return
}
certDERBlock, _ := pem.Decode(certContent)
if certDERBlock == nil {
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,无效证书[代码:1005]", "code": 0})
return
}
cert, err := gmx509.ParseCertificate(certDERBlock.Bytes)
if err != nil {
//fmt.Println(err)
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,无效证书[代码:1006]", "code": 0})
return
}
if cert.NotBefore.After(cert.NotAfter) {
//fmt.Println(err)
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,无效证书[代码:1007]", "code": 0})
return
}
subjectName := cert.Subject.CommonName
if username != subjectName {
//fmt.Println(err)
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,无效证书[代码:1008]", "code": 0})
return
}
serialNumber := cert.SerialNumber
if serialNumber.Cmp(big.NewInt(0)) == 0 {
//fmt.Println(err)
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,无效证书[代码:1009]", "code": 0})
return
}
issuerName := cert.Issuer.CommonName
if issuerName != conf.IssuerName {
//fmt.Println(err)
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,无效证书[代码:1010]", "code": 0})
return
}
haveExt := false
for _, ext := range cert.Extensions {
if ext.Id.String() == "1.2.3.4" {
if string(ext.Value) != conf.ExtValue {
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,无效证书[代码:1011]", "code": 0})
return
}
haveExt = true
}
}
if !haveExt {
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,无效证书[代码:1012]", "code": 0})
return
}
userFile, err := os.Open("userInfo.txt")
if err != nil {
//fmt.Println(err)
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,系统有误[代码:1001]", "code": 0})
return
}
defer func(userFile *os.File) {
err := userFile.Close()
if err != nil {
//fmt.Println(err)
}
}(userFile)
var sysUserName string
for {
_, err := fmt.Fscanf(userFile, "%sn", &sysUserName)
if err != nil {
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,用户不存在", "code": 0})
return
}
if sysUserName == subjectName {
randNum := rand.Intn(1000000)
randNumStr := strconv.Itoa(randNum)
conf.Cache.Set(randNumStr, certContent, 0)
c.JSON(http.StatusOK, gin.H{"msg": "证书验证通过", "code": 1, "randNum": randNum})
return
}
}
}
signature := c.PostForm("signature")
if signature == "" {
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,签名为空[代码:1001]", "code": 0})
return
}
certContent, flag := conf.Cache.Get(randNumStr)
if flag != true {
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,签名错误[代码:1002]", "code": 0})
return
}
certDERBlock, _ := pem.Decode(certContent.([]byte))
if certDERBlock == nil {
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,签名错误[代码:1003]", "code": 0})
return
}
cert, err := gmx509.ParseCertificate(certDERBlock.Bytes)
if err != nil {
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,签名错误[代码:1004]", "code": 0})
return
}
pubKey := cert.PublicKey.(*ecdsa.PublicKey)
publicKey := sm2.PublicKey{}
publicKey.Curve = pubKey.Curve
publicKey.X = pubKey.X
publicKey.Y = pubKey.Y
signatureByte, err := hex.DecodeString(signature)
if err != nil {
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,签名错误[代码:1005]", "code": 0})
return
}
l := len(signatureByte)
r := big.Int{}
s := big.Int{}
r.SetBytes(signatureByte[:l/2])
s.SetBytes(signatureByte[l/2:])
uid := []byte("1234567812345678")
verify := sm2.Sm2Verify(&publicKey, []byte(randNumStr), uid, &r, &s)
if verify != true {
c.JSON(http.StatusOK, gin.H{"msg": "登录失败,签名错误[代码:1006]", "code": 0})
return
}
username := cert.Subject.CommonName
generateToken(c, username, conf)
}
func generateToken(c *gin.Context, username string, conf config.Config) {
j := &utils.JWT{
SigningKey: []byte(conf.SignKey),
}
claims := utils.CustomClaims{
Name: username,
StandardClaims: jwtgo.StandardClaims{
NotBefore: time.Now().Unix() - conf.NotBeforeTime,
ExpiresAt: time.Now().Unix() + conf.ExpiresTime,
Issuer: conf.Issuer,
},
}
token, err := j.CreateToken(claims)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": 0,
"msg": "登录失败,系统有误[代码:1002]",
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 1,
"msg": "登录成功",
"token": token,
})
return
}
download.go
func UploadFileList(c *gin.Context) {
files, err := ioutil.ReadDir("files")
if err != nil {
c.JSON(http.StatusOK, gin.H{"msg": "读取文件列表失败", "code": 0})
return
}
var fileNames []string
for _, file := range files {
fileNames = append(fileNames, file.Name())
}
c.JSON(http.StatusOK, gin.H{"msg": "读取文件列表成功", "code": 1, "data": fileNames})
return
}
func DownloadFile(c *gin.Context) {
fileName := c.Query("fileName")
filePath := "files/" + fileName
_, err := os.Stat(filePath)
if err != nil {
c.JSON(http.StatusOK, gin.H{"msg": "文件不存在", "code": 0})
return
}
c.File(filePath)
return
具体流程为:
-
检查是否 post 了随机数 randNumStr,如果有则跳到第 16 步,否则继续下面的判断。 -
检查是否输入了用户名 -
检查是否上传了文件 -
检查上传的文件是否为证书类型 -
检查该证书文件能否打开 -
检查该证书文件能否读取 -
检查该证书文件能否以pem格式解析 -
检查该证书是否为 gmx509 格式(应该是,对go语言不是特别熟) -
检查该证书是否在有效期内 -
检查 username 是否等于证书里的 CommonName -
检查该证书的 serialNumber 是否为 0 -
检查该证书的 CommonName 是否为服务端配置文件中设定的 IssuerName -
检查该证书是否有 “1.2.3.4” 类型的拓展,以及值是否和服务端配置文件中设置的相等。 -
检查该 username 是否为系统的注册用户 -
如果上面的检查都通过了则随机生成一个随机数返回给用户,并以该随机数和证书作为键值对存入字典 Cache 中。 -
读取用户传入的签名 signature -
以随机数 randNumStr 作为键在 Cache 中获取对应证书 -
再次检查该证书文件能否以pem格式解析 -
再次检查该证书是否为 gmx509 格式 -
从证书中获取对应的 sm2 参数 -
十六进制解码用户的 signature,并获取对应的 r,s 值 -
使用公钥验证用户的签名
POST /api/certLogin HTTP/1.1
Host: 192.168.11.153
Connection: keep-alive
Content-Length: 934
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.82
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarysSYBwFLJZmU0edVM
Origin: http://192.168.11.153
Referer: http://192.168.11.153/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
------WebKitFormBoundarysSYBwFLJZmU0edVM
Content-Disposition: form-data; name="file"; filename="loginSM2.crt"
Content-Type: application/x-x509-ca-cert
-----BEGIN CERTIFICATE-----
MIIBpjCCAUugAwIBAgIRAIQyrttkXywULI3KhGNxYFYwCgYIKoEcz1UBg3UwPjEO
MAwGA1UEChMFQkNTWVMxDjAMBgNVBAMTBUJDU1lTMQ8wDQYDVQQqEwZHb3BoZXIx
CzAJBgNVBAYTAk5MMB4XDTIzMDcxNzAzMjMyNVoXDTI0MDcxNzAzMjMyNVowNTEV
MBMGA1UEChMMRXhhbXBsZSBJbmMuMQswCQYDVQQLEwJJVDEPMA0GA1UEAxMGYWRt
aW4xMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEdTKwJfeYUBsH3rw8KlRiabJX
z3KxNcH2MuYl7ol27RLS5/nVvvlrY2iw2Ylni+CS+htLoScXpEBsuMzkPjG3VKMz
MDEwDgYDVR0PAQH/BAQDAgKkMAwGA1UdEwEB/wQCMAAwEQYDKgMEBApxd2VydHl1
aW9wMAoGCCqBHM9VAYN1A0kAMEYCIQCP9wit9wKLNhDB7qzK50PuMldu0WhEFRuk
ZDXegNcpjQIhAK+fiviPZu53F7cAGck8VijLOJFfN0q7xJIqJ4T+nujr
-----END CERTIFICATE-----
------WebKitFormBoundarysSYBwFLJZmU0edVM
Content-Disposition: form-data; name="username"
admin1
------WebKitFormBoundarysSYBwFLJZmU0edVM--
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Tue, 18 Jul 2023 01:33:13 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 54
Connection: keep-alive
{"code":1,"msg":"..................","randNum":415979}POST /api/certLogin HTTP/1.1
Host: 192.168.11.153
Connection: keep-alive
Content-Length: 368
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.82
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryywsxrJ41AnxgA0zr
Origin: http://192.168.11.153
Referer: http://192.168.11.153/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
------WebKitFormBoundaryywsxrJ41AnxgA0zr
Content-Disposition: form-data; name="signature"
c4f6d124ebcf0969ae0d86f234680ef7730f62f83d5fa257f6734d80537d63eff7004f1339d2d13368f61ff8327c9e77d2c6a48e85c73a9d739811aeda5341ac
------WebKitFormBoundaryywsxrJ41AnxgA0zr
Content-Disposition: form-data; name="randNum"
415979
------WebKitFormBoundaryywsxrJ41AnxgA0zr--
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Tue, 18 Jul 2023 01:33:13 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 213
Connection: keep-alive
{"code":1,"msg":"...............","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiYWRtaW4xIiwiZXhwIjoxNjg5NzMwMzkzLCJpc3MiOiJxZnpoZSIsIm5iZiI6MTY4OTY0Mzk5Mn0.XQf7xBf5bUswduZrX_GHvlpXFOH8G69NdB47lVlhBMs"}
c4f6d124ebcf0969ae0d86f234680ef7730f62f83d5fa257f6734d80537d63eff7004f1339d2d13368f61ff8327c9e77d2c6a48e85c73a9d739811aeda5341ac
if sysUserName == subjectName {
randNum := rand.Intn(1000000)
randNumStr := strconv.Itoa(randNum)
conf.Cache.Set(randNumStr, certContent, 0)
c.JSON(http.StatusOK, gin.H{"msg": "证书验证通过", "code": 1, "randNum": randNum})
return
}
import requests
for _ in range(1000000):
burp0_url = "http://172.10.42.245:80/api/certLogin"
burp0_headers = {"Accept": "application/json, text/plain, */*", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36", "Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryuaSs8kkIgmx9BXiZ", "Origin": "http://172.10.42.245", "Referer": "http://172.10.42.245/", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "close"}
burp0_data = "------WebKitFormBoundaryuaSs8kkIgmx9BXiZrnContent-Disposition: form-data; name="file"; filename="2.cer"rnContent-Type: application/x-x509-ca-certrnrn-----BEGIN CERTIFICATE-----rnMIIBpjCCAUugAwIBAgIRAIQyrttkXywULI3KhGNxYFYwCgYIKoEcz1UBg3UwPjEOrnMAwGA1UEChMFQkNTWVMxDjAMBgNVBAMTBUJDU1lTMQ8wDQYDVQQqEwZHb3BoZXIxrnCzAJBgNVBAYTAk5MMB4XDTIzMDcxNzAzMjMyNVoXDTI0MDcxNzAzMjMyNVowNTEVrnMBMGA1UEChMMRXhhbXBsZSBJbmMuMQswCQYDVQQLEwJJVDEPMA0GA1UEAxMGYWRtrnaW4xMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEdTKwJfeYUBsH3rw8KlRiabJXrnz3KxNcH2MuYl7ol27RLS5/nVvvlrY2iw2Ylni+CS+htLoScXpEBsuMzkPjG3VKMzrnMDEwDgYDVR0PAQH/BAQDAgKkMAwGA1UdEwEB/wQCMAAwEQYDKgMEBApxd2VydHl1rnaW9wMAoGCCqBHM9VAYN1A0kAMEYCIQCP9wit9wKLNhDB7qzK50PuMldu0WhEFRukrnZDXegNcpjQIhAK+fiviPZu53F7cAGck8VijLOJFfN0q7xJIqJ4T+nujrrn-----END CERTIFICATE-----rn------WebKitFormBoundaryuaSs8kkIgmx9BXiZrnContent-Disposition: form-data; name="username"rnrnadmin1rn------WebKitFormBoundaryuaSs8kkIgmx9BXiZ--rn"
res = requests.post(burp0_url, headers=burp0_headers, data=burp0_data)
if '415979' in res.text():
print("[+] SUCCESS")
这里我生成的私钥为 ,对应的证书文件为
-----BEGIN CERTIFICATE-----
MIIBpjCCAUugAwIBAgIRAIQyrttkXywULI3KhGNxYFYwCgYIKoEcz1UBg3UwPjEO
MAwGA1UEChMFQkNTWVMxDjAMBgNVBAMTBUJDU1lTMQ8wDQYDVQQqEwZHb3BoZXIx
CzAJBgNVBAYTAk5MMB4XDTIzMDcxNzAzMjMyNVoXDTI0MDcxNzAzMjMyNVowNTEV
MBMGA1UEChMMRXhhbXBsZSBJbmMuMQswCQYDVQQLEwJJVDEPMA0GA1UEAxMGYWRt
aW4xMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEsyF9iEvBdea6azYOsObUOW6u
pyXD1m6Hv6W+tsDTRWulGZRFxUtWYCqmACXhkHv9JrMOhn22xYoDQmOuSi4nwqMz
MDEwDgYDVR0PAQH/BAQDAgKkMAwGA1UdEwEB/wQCMAAwEQYDKgMEBApxd2VydHl1
aW9wMAoGCCqBHM9VAYN1A0kAMEYCIQCP9wit9wKLNhDB7qzK50PuMldu0WhEFRuk
ZDXegNcpjQIhAK+fiviPZu53F7cAGck8VijLOJFfN0q7xJIqJ4T+nujr
-----END CERTIFICATE-----
b64encode(long_to_bytes(2**256-1)) -> //////////////////////////////////////////8=
<!!!!!!!!!!!!解密!解开我,你将获得全部信息!!!!!!!!!!!!!!!!!!>
2D303C3023614C226E436D20482C7D43
eufi*@(%$DKK884+
,打开压缩包,获得 flag,flag2{7b84588a-0a54-5639-a828-9062e8a7f6c2}
比赛中没有做出来的后续关卡
int RAND_DRBG_bytes(RAND_DRBG *drbg, unsigned char *out, size_t outlen)
{
unsigned char *additional = NULL;
size_t additional_len;
size_t chunk;
size_t ret = 0;
if (drbg->adin_pool == NULL) {
if (drbg->type == 0)
goto err;
drbg->adin_pool = rand_pool_new(0, 0, 0, drbg->max_adinlen);
if (drbg->adin_pool == NULL)
goto err;
}
additional_len = rand_drbg_get_additional_data(drbg->adin_pool,
&additional);
/* for ( ; outlen > 0; outlen -= chunk, out += chunk) {
chunk = outlen;
if (chunk > drbg->max_request)
chunk = drbg->max_request;
ret = RAND_DRBG_generate(drbg, out, chunk, 0, additional, additional_len);
if (!ret)
goto err;
} */
uint8_t rand0_32[32] = {0x67, 0xc6, 0x69, 0x73, 0x51, 0xff, 0x4a, 0xec, 0x29, 0xcd, 0xba, 0xab, 0xf2, 0xfb, 0xe3, 0x46, 0x7c, 0xc2, 0x54, 0xf8, 0x1b, 0xe8, 0xe7, 0x8d, 0x76, 0x5a, 0x2e, 0x63, 0x33, 0x9f, 0xc9, 0x9a};
for(int i=0;i<outlen;i++){
out[i] = rand0_32[i % 32];
}
ret = 1;
err:
if (additional != NULL)
rand_drbg_cleanup_additional_data(drbg->adin_pool, additional);
return ret;
}
第三关
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey,X25519PublicKey
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
rand0 = [0x67, 0xc6, 0x69, 0x73, 0x51, 0xff, 0x4a, 0xec, 0x29, 0xcd, 0xba, 0xab, 0xf2, 0xfb, 0xe3, 0x46, 0x7c, 0xc2, 0x54, 0xf8, 0x1b, 0xe8, 0xe7, 0x8d, 0x76, 0x5a, 0x2e, 0x63, 0x33, 0x9f, 0xc9, 0x9a]
sk = "".join(hex(i)[2:].rjust(2,'0') for i in rand0)
print(sk)
privatekey=X25519PrivateKey.from_private_bytes(bytes.fromhex(sk))
print((privatekey.public_key()._raw_public_bytes().hex()))
然后计算它们的协商密钥
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey,X25519PublicKey
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
rand0 = [0x67, 0xc6, 0x69, 0x73, 0x51, 0xff, 0x4a, 0xec, 0x29, 0xcd, 0xba, 0xab, 0xf2, 0xfb, 0xe3, 0x46, 0x7c, 0xc2, 0x54, 0xf8, 0x1b, 0xe8, 0xe7, 0x8d, 0x76, 0x5a, 0x2e, 0x63, 0x33, 0x9f, 0xc9, 0x9a]
sk = "".join(hex(i)[2:].rjust(2,'0') for i in rand0)
# print(sk)
privatekey=X25519PrivateKey.from_private_bytes(bytes.fromhex(sk))
# print((privatekey.public_key()._raw_public_bytes().hex()))
publickey=X25519PublicKey.from_public_bytes(bytes.fromhex('a0022027e0390ead7d82e1e74ae2d2f045fbf72896b9846d7f28bfa184280e3e'))
result=privatekey.exchange(publickey)
print(result.hex())
7ff739dbe782d963e54e3242d83b3a01a6535aed3579f6a514a664b363915903
PMS_CLIENT_RANDOM[空格]Random[空格]sharekey
PMS_CLIENT_RANDOM 9d8f92cc2ac8f33293da5169d49c82794c660fc937bd0c1b05f5e062e491da85 7ff739dbe782d963e54e3242d83b3a01a6535aed3579f6a514a664b363915903
PMS_CLIENT_RANDOM 9d8f92cc2ac8f33293da5169d49c82794c660fc937bd0c1b05f5e062e491da85 7ff739dbe782d963e54e3242d83b3a01a6535aed3579f6a514a664b363915903
PMS_CLIENT_RANDOM b5dbfb40bc4c2b1a46bbc594fc89a56c17fe7db891beb7c111691516bd3117d1 4c8c1680018a8dd48749d642b6a6df5cc2104cb98842b82b0d748430108b8f61
伪造签名
//Generate Random Number
unsigned char randomScalar[32];
unsigned int i_time=0;
time_parse(message, &i_time);
if(derive_from_time(i_time,randomScalar,32))
goto err;
BN_bin2bn(randomScalar, 32, k);
int time_parse(char *str_time, unsigned int *i_time){
struct tm s_time;
/* strptime(str_time,"%Y年%m月%d日%H:%M:%S",&s_time);
s_time.tm_isdst = -1;
*i_time = mktime(&s_time); */
int year, month, day, hour, minute,second;
sscanf(str_time,"%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second);
s_time.tm_year= year-1900;
s_time.tm_mon= month-1;
s_time.tm_mday= day;
s_time.tm_hour= hour;
s_time.tm_min= minute;
s_time.tm_sec= second;
s_time.tm_isdst= -1;
*i_time = mktime(&s_time);
return 0;
}
int derive_from_time(unsigned int seed, unsigned char *randomScalar, int length) {
if (randomScalar == NULL || length <= 0) {
return 1; // Invalid input
}
unsigned int currentSeed = seed;
int generatedLength = 0;
while (generatedLength < length) {
unsigned char shaOutput[SHA256_DIGEST_LENGTH];
SHA256((const unsigned char *)¤tSeed, sizeof(currentSeed), shaOutput);
int remainingLength = length - generatedLength;
int copyLength = remainingLength < SHA256_DIGEST_LENGTH ? remainingLength : SHA256_DIGEST_LENGTH;
memcpy(randomScalar + generatedLength, shaOutput, copyLength);
generatedLength += copyLength;
currentSeed++;
}
return 0; // Success
}
gcc tmpk.c -L. -l crypto -l ssl -o tmpk
(把 tmpk.c 放在 openssl 目录下) //Generate Random Number
unsigned char randomScalar[32];
unsigned int i_time=0;
time_parse(message, &i_time);
if(derive_from_time(i_time,randomScalar,32))
goto err;
BN_bin2bn(randomScalar, 32, k);
BN_print_fp(stdout, k);
printf("n");
D2D569D2A7250B2B27DF909C9AFC1FD9E0A555AEC4BFB5D80CD71F70ADACF414
from Crypto.Util.number import *
r = 0x37AF670C4742BD0C8D7CF68FCEBFE61885AA630695D50A15DF279CD64327466F
r = bytes_to_long(long_to_bytes(r)[::-1])
s = 0x6701CFB5F356887B9441323FDC08FBA900E1050109FD95F024DC9C178CEBE7A4
s = bytes_to_long(long_to_bytes(s)[::-1])
n = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123
k = 0xD2D569D2A7250B2B27DF909C9AFC1FD9E0A555AEC4BFB5D80CD71F70ADACF414
print((k-s)*inverse(s+r,n)%n)
104515905597970870556286963199400550747760654012576876144731059595513283165045
hex(bytes_to_long(long_to_bytes(sk::-1]))
)753bffd7cd2353cbe72702159162f8da8f7118d8b4944fe74ddbf7e2fee711e7
int main()
{
unsigned char pub[64];
unsigned char pri[64];
unsigned char message1[128] = "2023-8-10 09:11:13, A transfers 50000.00 to B.";
unsigned char message2[128] = "2023-8-10 11:31:01, B transfers 50000.00 to A.";
unsigned char digest[32];
unsigned char sig1[64];
unsigned char sig2[64];
int ret;
printf("msg1:t%sn",message2);
ret = Sign_Prifile(message2, sig1);
user_printf_hex("sig1:t",sig1,64);
ret = Verify_Pubfile(message2, sig1);
printf("verify:t%dn",ret);
return 0;
}
(PS:做到现在,仍然不知道 AAA 是怎么在没拿到 flag3 的情况下进入签名系统,完成签名计算的,疑惑。难道说他们找到了签名系统的洞可以注册用户?)
原文始发于微信公众号(Van1sh):2023 熵密杯
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论