Skip to content

Commit f7a52e1

Browse files
IKEv2 Proto Init (#468)
1 parent 834c00e commit f7a52e1

File tree

4 files changed

+576
-0
lines changed

4 files changed

+576
-0
lines changed

protocol/ikev2/ikev2.go

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// Package ikev2
2+
// A (very) basic framework for an ikev2 protocol.
3+
// The intent with adding this package is not to add an entire, fully functional protocol but rather providing a convenient interface for generating the data structures for ike-related exploits.
4+
// The goal is to add to this as we go, as new exploits demand it.
5+
//
6+
// Using this will probably require you to make your own SAInit function to generate the message data and then sending it over the ikeClient connection.
7+
// A basic example of something like this follows:
8+
//
9+
// func saInit(ikeClient *ikev2.IkeClient, diffieHellmanGroup int) ([]byte, bool) {
10+
//
11+
// ikeClient.IkeCrypto = ikev2.IkeCrypto{}
12+
// ikeClient.IkeCrypto.Init()
13+
// ok := ikeClient.IkeCrypto.GenerateDHKey(diffieHellmanGroup)
14+
// if !ok {
15+
// return []byte{}, false
16+
// }
17+
//
18+
// defaultTransforms := []ikev2.IkeTransform{
19+
// {NextPayload: ikev2.PayloadType["TRANSFORM"], TransformType: ikev2.TransformType["ENCRYPTION_ALGORITHM"], TransformID: ikev2.EncryptionAlgorithm["ENCR_AES_CBC"], TransformAttributes: 0x800e0100},
20+
// }
21+
//
22+
// message := make([]byte, 0)
23+
// header := ikev2.IkePackHeader(ikeClient, ikev2.PayloadType["SECURITY_ASSOCIATION"], 0x20, ikev2.ExchangeType["IKE_SA_INIT"], 0x08, 0x0)
24+
// message = append(message, ikev2.IkePackSecurityAssociation(ikev2.PayloadType["KEY_EXCHANGE"], ikev2.IkePackProposal(ikev2.PayloadType["NONE"], 1, 1, defaultTransforms, ""))...)
25+
// message = append(message, ikev2.IkePackKeyExchange(ikev2.PayloadType["NONCE"], ikev2.DiffieHellmanGroup["DH_GROUP_2048_BIT_MODP"], ikeClient.IkeCrypto.ClientPubKey.Bytes())...)
26+
// message = append(message, ikev2.IkePackNonce(ikev2.PayloadType["NOTIFY"], ikeClient.IkeCrypto.InitNonce)...)
27+
//
28+
// tempBytes, _ := hex.DecodeString("deadbeef")
29+
// message = append(message, ikev2.IkePackNotify(ikev2.PayloadType["NOTIFY"], ikev2.NotifyType["NAT_DETECTION_DESTINATION_IP"], tempBytes, 1, 0)...)
30+
//
31+
// tempBytes, _ = hex.DecodeString("0021030203030006")
32+
// message = append(message, ikev2.IkePackNotify(ikev2.PayloadType["NONE"], ikev2.NotifyType["SIGNATURE_HASH_ALGORITHMS"], tempBytes, 0, 0)...)
33+
//
34+
// // combining the message
35+
// payload := make([]byte, 0)
36+
// payload = append(header, []byte(transform.PackBigInt32(len(message)+len(header)+4))...)
37+
// payload = append(payload, message...)
38+
// return payload, true
39+
// }
40+
//
41+
// func main() {
42+
// ikeClient := ikev2.IkeClient{}
43+
// saInitPayload, _ := saInit(&ikeClient, ikev2.DiffieHellmanGroup["DH_GROUP_2048_BIT_MODP"])
44+
// if !ok {
45+
// output.PrintError("error encountered while generating SAInit payload")
46+
// return false
47+
// }
48+
//
49+
// if !ikeClient.Connect(conf){
50+
// return false
51+
// }
52+
//
53+
// _, err := ikeClient.Conn.Write([]byte(saInitPayload))
54+
// if err != nil {
55+
// output.PrintfDebug("SAInit Send failed: %s", err.Error())
56+
// return false
57+
// }
58+
// output.PrintDebug("Sent SAInit message")
59+
// }
60+
package ikev2
61+
62+
import (
63+
"crypto/rand"
64+
"encoding/binary"
65+
"math/big"
66+
mrand "math/rand"
67+
"net"
68+
"strconv"
69+
70+
"github.com/vulncheck-oss/go-exploit/config"
71+
"github.com/vulncheck-oss/go-exploit/output"
72+
)
73+
74+
func Uint64ToString(num uint64) []byte {
75+
bytes := make([]byte, 8)
76+
binary.BigEndian.PutUint64(bytes, num)
77+
78+
return bytes
79+
}
80+
81+
func generateNonce(length int) ([]byte, bool) {
82+
nonce := make([]byte, length)
83+
_, err := rand.Read(nonce)
84+
if err != nil {
85+
output.PrintfFrameworkError("Error while generating nonce: %s", err.Error())
86+
87+
return []byte{}, false
88+
}
89+
90+
return nonce, true
91+
}
92+
93+
// Switch case is here in case anyone wants to add additional DH support.
94+
func (ikeCrypto *IkeCrypto) GenerateDHKey(diffieHellmanGroup int) bool {
95+
switch diffieHellmanGroup {
96+
case DiffieHellmanGroup["DH_GROUP_2048_BIT_MODP"]:
97+
ikeCrypto.Prime = new(big.Int)
98+
ikeCrypto.Prime.SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) // https://www.ietf.org/rfc/rfc3526.txt
99+
g := big.NewInt(2)
100+
ikeCrypto.ClientPrivKey, _ = rand.Int(rand.Reader, ikeCrypto.Prime)
101+
ikeCrypto.ClientPubKey = new(big.Int).Exp(g, ikeCrypto.ClientPrivKey, ikeCrypto.Prime)
102+
103+
return true
104+
105+
default:
106+
output.PrintFrameworkError("Provided DH group is currently unsupported.")
107+
108+
return false
109+
}
110+
}
111+
112+
func (ikeCrypto *IkeCrypto) Init() bool {
113+
var ok bool
114+
ikeCrypto.InitNonce, ok = generateNonce(32)
115+
if !ok {
116+
return false
117+
}
118+
ikeCrypto.RespNonce = []byte{}
119+
ikeCrypto.InitSPI = mrand.Uint64()
120+
ikeCrypto.RespSPI = 0x0000000000000000
121+
122+
return true
123+
}
124+
125+
// An initial reset/connect helper function.
126+
func (ikeClient *IkeClient) Connect(conf *config.Config) bool {
127+
var err error
128+
if ikeClient.Conn != nil {
129+
err = ikeClient.Conn.Close()
130+
if err != nil {
131+
// we probably do not want to exit on this, we're establishing a new connection anyways
132+
output.PrintfFrameworkWarn("Failed to close socket: %s", err.Error())
133+
}
134+
}
135+
136+
connectionString := net.JoinHostPort(conf.Rhost, strconv.Itoa(conf.Rport))
137+
ikeClient.Conn, err = net.Dial("udp", connectionString)
138+
if err != nil {
139+
output.PrintfFrameworkError("Dial failed: %s", err.Error())
140+
141+
return false
142+
}
143+
144+
output.PrintfFrameworkDebug("Successfully established UDP connection to %s", connectionString)
145+
146+
return true
147+
}

protocol/ikev2/ikev2_test.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package ikev2
2+
3+
import (
4+
"encoding/hex"
5+
"fmt"
6+
"testing"
7+
)
8+
9+
func TestVendorIDPack(t *testing.T) {
10+
want := "2b000014c590254e5403cbb71f3d493111d7fcad"
11+
tempBytes, _ := hex.DecodeString("c590254e5403cbb71f3d493111d7fcad")
12+
got := IkePackVendorID(PayloadType["VENDOR_ID"], tempBytes)
13+
14+
if fmt.Sprintf("%02x", got) != want {
15+
t.Fatalf("[1] %q : %02x != %s", got, got, want)
16+
}
17+
18+
want = "2b000014c61baca1f1a60cc10800000000000000"
19+
tempBytes, _ = hex.DecodeString("c61baca1f1a60cc10800000000000000")
20+
got = IkePackVendorID(PayloadType["VENDOR_ID"], tempBytes)
21+
22+
if fmt.Sprintf("%02x", got) != want {
23+
t.Fatalf("[2] %q : %02x != %s", got, got, want)
24+
}
25+
26+
want = "2b0000184048b7d56ebce88525e7de7f00d6c2d3c0000000"
27+
tempBytes, _ = hex.DecodeString("4048b7d56ebce88525e7de7f00d6c2d3c0000000")
28+
got = IkePackVendorID(PayloadType["VENDOR_ID"], tempBytes)
29+
30+
if fmt.Sprintf("%02x", got) != want {
31+
t.Fatalf("[3] %q : %02x != %s", got, got, want)
32+
}
33+
34+
want = "290000144048b7d56ebce88525e7de7f00d6c2d3"
35+
tempBytes, _ = hex.DecodeString("4048b7d56ebce88525e7de7f00d6c2d3")
36+
got = IkePackVendorID(PayloadType["NOTIFY"], tempBytes)
37+
if fmt.Sprintf("%02x", got) != want {
38+
t.Fatalf("[4] %q : %02x != %s", got, got, want)
39+
}
40+
}
41+
42+
func TestSecurityAssociationPack(t *testing.T) {
43+
want := "220000300000002c010100040300000c0100000c800e01000300000802000005030000080300000c000000080400000e"
44+
defaultTransforms := []IkeTransform{
45+
{PayloadType["TRANSFORM"], TransformType["ENCRYPTION_ALGORITHM"], EncryptionAlgorithm["ENCR_AES_CBC"], 0x800e0100},
46+
{PayloadType["TRANSFORM"], TransformType["PSEUDO_RANDOM_FUNCTION"], PseudoRandomFunction["PRF_HMAC_SHA2_256"], 0},
47+
{PayloadType["TRANSFORM"], TransformType["INTEGRITY_ALGORITHM"], IntegrityAlgorithm["AUTH_HMAC_SHA2_256_128"], 0},
48+
{PayloadType["NONE"], TransformType["DIFFIE_HELLMAN_GROUP"], DiffieHellmanGroup["DH_GROUP_2048_BIT_MODP"], 0},
49+
}
50+
got := IkePackSecurityAssociation(PayloadType["KEY_EXCHANGE"], IkePackProposal(PayloadType["NONE"], 1, 1, defaultTransforms, ""))
51+
52+
if fmt.Sprintf("%02x", got) != want {
53+
t.Fatalf("[1] %q : %02x != %s", got, got, want)
54+
}
55+
}
56+
57+
func TestNotifyPack(t *testing.T) {
58+
want := "2900001c01004005a6358d813592fdd80a9aaa3390f39c8a5a76b6e4"
59+
tempBytes, _ := hex.DecodeString("a6358d813592fdd80a9aaa3390f39c8a5a76b6e4")
60+
got := IkePackNotify(PayloadType["NOTIFY"], NotifyType["NAT_DETECTION_DESTINATION_IP"], tempBytes, 1, 0)
61+
if fmt.Sprintf("%02x", got) != want {
62+
t.Fatalf("[1] %q : %02x != %s", got, got, want)
63+
}
64+
65+
want = "2b00001c010040044cc324152ba3f68ef649ac1e6f96f33791611db2"
66+
tempBytes, _ = hex.DecodeString("4cc324152ba3f68ef649ac1e6f96f33791611db2")
67+
got = IkePackNotify(PayloadType["VENDOR_ID"], NotifyType["NAT_DETECTION_SOURCE_IP"], tempBytes, 1, 0)
68+
if fmt.Sprintf("%02x", got) != want {
69+
t.Fatalf("[2] %q : %02x != %s", got, got, want)
70+
}
71+
72+
want = "290000080000402e"
73+
got = IkePackNotify(PayloadType["NOTIFY"], NotifyType["IKEV2_FRAGMENTATION_SUPPORTED"], []byte{}, 0, 0)
74+
if fmt.Sprintf("%02x", got) != want {
75+
t.Fatalf("[3] %q : %02x != %s", got, got, want)
76+
}
77+
78+
want = "2900000800004016"
79+
got = IkePackNotify(PayloadType["NOTIFY"], NotifyType["REDIRECT_SUPPORTED"], []byte{}, 0, 0)
80+
if fmt.Sprintf("%02x", got) != want {
81+
t.Fatalf("[4] %q : %02x != %s", got, got, want)
82+
}
83+
84+
want = "000000100000402f0001000200030004"
85+
tempBytes, _ = hex.DecodeString("0001000200030004")
86+
got = IkePackNotify(PayloadType["NONE"], NotifyType["SIGNATURE_HASH_ALGORITHMS"], tempBytes, 0, 0)
87+
if fmt.Sprintf("%02x", got) != want {
88+
t.Fatalf("[5] %q : %02x != %s", got, got, want)
89+
}
90+
}

protocol/ikev2/packs.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package ikev2
2+
3+
import (
4+
"github.com/vulncheck-oss/go-exploit/transform"
5+
)
6+
7+
// Creates a Nonce component.
8+
//
9+
// ikev2.IkePackNonce(ikev2.PayloadType["NOTIFY"], ikeClient.IkeCrypto.InitNonce)
10+
func IkePackNonce(nextPayload int, nonce []byte) []byte {
11+
return IkePackPayloadHeader(nextPayload, nonce)
12+
}
13+
14+
// Creates a VendorID component.
15+
//
16+
// tempBytes, _ = hex.DecodeString("4048b7d56ebce88525e7de7f00d6c2d3")
17+
// ikev2.IkePackVendorID(ikev2.PayloadType["NOTIFY"], tempBytes)
18+
func IkePackVendorID(nextPayload int, vendorID []byte) []byte {
19+
return IkePackPayloadHeader(nextPayload, vendorID)
20+
}
21+
22+
// Creates a Notify component.
23+
//
24+
// tempBytes, _ = hex.DecodeString("0021030203030006")
25+
// ikev2.IkePackNotify(ikev2.PayloadType["NONE"], ikev2.NotifyType["SIGNATURE_HASH_ALGORITHMS"], tempBytes, 0, 0)
26+
func IkePackNotify(nextPayload int, notifyType int, data []byte, protocolID int, spiSize int) []byte {
27+
payload := make([]byte, 0)
28+
payload = append(payload, byte(protocolID))
29+
payload = append(payload, byte(spiSize))
30+
payload = append(payload, []byte(transform.PackBigInt16(notifyType))...)
31+
payload = append(payload, data...)
32+
33+
return IkePackPayloadHeader(nextPayload, payload)
34+
}
35+
36+
// Creates a KeyExchange component.
37+
//
38+
// ikev2.IkePackKeyExchange(ikev2.PayloadType["NONCE"], ikev2.DiffieHellmanGroup["DH_GROUP_2048_BIT_MODP"], ikeClient.IkeCrypto.ClientPubKey.Bytes())
39+
func IkePackKeyExchange(nextPayload int, dhGroup int, data []byte) []byte {
40+
payload := []byte(transform.PackBigInt16(dhGroup))
41+
payload = append(payload, []byte(transform.PackBigInt16(0))...) // reserved bytes (2)
42+
payload = append(payload, data...)
43+
44+
return IkePackPayloadHeader(nextPayload, payload)
45+
}
46+
47+
// Creates a Security Association component.
48+
//
49+
// ikev2.IkePackSecurityAssociation(ikev2.PayloadType["KEY_EXCHANGE"], ikev2.IkePackProposal(ikev2.PayloadType["NONE"], 1, 1, defaultTransforms, ""))
50+
func IkePackSecurityAssociation(payloadType int, proposal []byte) []byte {
51+
return IkePackPayloadHeader(payloadType, proposal)
52+
}
53+
54+
// Creates a transform byte array from a transform.
55+
//
56+
// ikev2.IkeTransform{NextPayload: ikev2.PayloadType["TRANSFORM"], TransformType: ikev2.TransformType["ENCRYPTION_ALGORITHM"], TransformID: ikev2.EncryptionAlgorithm["ENCR_AES_CBC"], TransformAttributes: 0x800e0100}
57+
func (ikeTransform *IkeTransform) Pack() []byte {
58+
payload := make([]byte, 0)
59+
payload = append(payload, byte(ikeTransform.TransformType))
60+
payload = append(payload, byte(0))
61+
payload = append(payload, []byte(transform.PackBigInt16(ikeTransform.TransformID))...)
62+
transform.PackBigInt16(ikeTransform.TransformID)
63+
64+
if ikeTransform.TransformAttributes != 0 {
65+
payload = append(payload, []byte(transform.PackBigInt32(ikeTransform.TransformAttributes))...)
66+
}
67+
68+
return IkePackPayloadHeader(ikeTransform.NextPayload, payload)
69+
}
70+
71+
// Encapsulates a Packed component (or any binary array) with the nextHeader. Used by most of these packs.
72+
func IkePackPayloadHeader(payloadType int, payloadIn []byte) []byte {
73+
payload := make([]byte, 0)
74+
payload = append(payload, byte(payloadType))
75+
payload = append(payload, byte(0))
76+
payload = append(payload, []byte(transform.PackBigInt16(len(payloadIn)+4))...)
77+
payload = append(payload, payloadIn...)
78+
79+
return payload
80+
}
81+
82+
// Creates a Proposal component.
83+
//
84+
// ikev2.IkePackProposal(ikev2.PayloadType["NONE"], 1, 1, defaultTransforms, "").
85+
func IkePackProposal(nextPayload int, number int, id int, transforms []IkeTransform, spi string) []byte {
86+
payload := make([]byte, 0)
87+
payload = append(payload, byte(number))
88+
payload = append(payload, byte(id))
89+
payload = append(payload, byte(len(spi)))
90+
payload = append(payload, byte(len(transforms)))
91+
payload = append(payload, []byte(spi)...)
92+
for _, transform := range transforms {
93+
payload = append(payload, transform.Pack()...)
94+
}
95+
96+
return IkePackPayloadHeader(nextPayload, payload)
97+
}
98+
99+
// Creates a Header component.
100+
//
101+
// ikev2.IkePackHeader(ikeClient, ikev2.PayloadType["SECURITY_ASSOCIATION"], 0x20, ikev2.ExchangeType["IKE_SA_INIT"], 0x08, 0x0)
102+
func IkePackHeader(ikeClient *IkeClient, payloadType int, version int, exchangeType int, flags int, messageID int) []byte {
103+
payload := make([]byte, 0)
104+
payload = append(payload, Uint64ToString(ikeClient.IkeCrypto.InitSPI)...)
105+
payload = append(payload, Uint64ToString(ikeClient.IkeCrypto.RespSPI)...)
106+
payload = append(payload, byte(payloadType))
107+
payload = append(payload, byte(version))
108+
payload = append(payload, byte(exchangeType))
109+
payload = append(payload, byte(flags))
110+
payload = append(payload, []byte(transform.PackBigInt32(messageID))...)
111+
112+
return payload
113+
}

0 commit comments

Comments
 (0)