Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions protocol/ikev2/ikev2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Package ikev2
// A (very) basic framework for an ikev2 protocol.
// 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.
// The goal is to add to this as we go, as new exploits demand it.
//
// 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.
// A basic example of something like this follows:
//
// func saInit(ikeClient *ikev2.IkeClient, diffieHellmanGroup int) ([]byte, bool) {
//
// ikeClient.IkeCrypto = ikev2.IkeCrypto{}
// ikeClient.IkeCrypto.Init()
// ok := ikeClient.IkeCrypto.GenerateDHKey(diffieHellmanGroup)
// if !ok {
// return []byte{}, false
// }
//
// defaultTransforms := []ikev2.IkeTransform{
// {NextPayload: ikev2.PayloadType["TRANSFORM"], TransformType: ikev2.TransformType["ENCRYPTION_ALGORITHM"], TransformID: ikev2.EncryptionAlgorithm["ENCR_AES_CBC"], TransformAttributes: 0x800e0100},
// }
//
// message := make([]byte, 0)
// header := ikev2.IkePackHeader(ikeClient, ikev2.PayloadType["SECURITY_ASSOCIATION"], 0x20, ikev2.ExchangeType["IKE_SA_INIT"], 0x08, 0x0)
// message = append(message, ikev2.IkePackSecurityAssociation(ikev2.PayloadType["KEY_EXCHANGE"], ikev2.IkePackProposal(ikev2.PayloadType["NONE"], 1, 1, defaultTransforms, ""))...)
// message = append(message, ikev2.IkePackKeyExchange(ikev2.PayloadType["NONCE"], ikev2.DiffieHellmanGroup["DH_GROUP_2048_BIT_MODP"], ikeClient.IkeCrypto.ClientPubKey.Bytes())...)
// message = append(message, ikev2.IkePackNonce(ikev2.PayloadType["NOTIFY"], ikeClient.IkeCrypto.InitNonce)...)
//
// tempBytes, _ := hex.DecodeString("deadbeef")
// message = append(message, ikev2.IkePackNotify(ikev2.PayloadType["NOTIFY"], ikev2.NotifyType["NAT_DETECTION_DESTINATION_IP"], tempBytes, 1, 0)...)
//
// tempBytes, _ = hex.DecodeString("0021030203030006")
// message = append(message, ikev2.IkePackNotify(ikev2.PayloadType["NONE"], ikev2.NotifyType["SIGNATURE_HASH_ALGORITHMS"], tempBytes, 0, 0)...)
//
// // combining the message
// payload := make([]byte, 0)
// payload = append(header, []byte(transform.PackBigInt32(len(message)+len(header)+4))...)
// payload = append(payload, message...)
// return payload, true
// }
//
// func main() {
// ikeClient := ikev2.IkeClient{}
// saInitPayload, _ := saInit(&ikeClient, ikev2.DiffieHellmanGroup["DH_GROUP_2048_BIT_MODP"])
// if !ok {
// output.PrintError("error encountered while generating SAInit payload")
// return false
// }
//
// if !ikeClient.Connect(conf){
// return false
// }
//
// _, err := ikeClient.Conn.Write([]byte(saInitPayload))
// if err != nil {
// output.PrintfDebug("SAInit Send failed: %s", err.Error())
// return false
// }
// output.PrintDebug("Sent SAInit message")
// }
package ikev2

import (
"crypto/rand"
"encoding/binary"
"math/big"
mrand "math/rand"
"net"
"strconv"

"github.com/vulncheck-oss/go-exploit/config"
"github.com/vulncheck-oss/go-exploit/output"
)

func Uint64ToString(num uint64) []byte {
bytes := make([]byte, 8)
binary.BigEndian.PutUint64(bytes, num)

return bytes
}

func generateNonce(length int) ([]byte, bool) {
nonce := make([]byte, length)
_, err := rand.Read(nonce)
if err != nil {
output.PrintfFrameworkError("Error while generating nonce: %s", err.Error())

return []byte{}, false
}

return nonce, true
}

// Switch case is here in case anyone wants to add additional DH support.
func (ikeCrypto *IkeCrypto) GenerateDHKey(diffieHellmanGroup int) bool {
switch diffieHellmanGroup {
case DiffieHellmanGroup["DH_GROUP_2048_BIT_MODP"]:
ikeCrypto.Prime = new(big.Int)
ikeCrypto.Prime.SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) // https://www.ietf.org/rfc/rfc3526.txt
g := big.NewInt(2)
ikeCrypto.ClientPrivKey, _ = rand.Int(rand.Reader, ikeCrypto.Prime)
ikeCrypto.ClientPubKey = new(big.Int).Exp(g, ikeCrypto.ClientPrivKey, ikeCrypto.Prime)

return true

default:
output.PrintFrameworkError("Provided DH group is currently unsupported.")

return false
}
}

func (ikeCrypto *IkeCrypto) Init() bool {
var ok bool
ikeCrypto.InitNonce, ok = generateNonce(32)
if !ok {
return false
}
ikeCrypto.RespNonce = []byte{}
ikeCrypto.InitSPI = mrand.Uint64()
ikeCrypto.RespSPI = 0x0000000000000000

return true
}

// An initial reset/connect helper function.
func (ikeClient *IkeClient) Connect(conf *config.Config) bool {
var err error
if ikeClient.Conn != nil {
err = ikeClient.Conn.Close()
if err != nil {
// we probably do not want to exit on this, we're establishing a new connection anyways
output.PrintfFrameworkWarn("Failed to close socket: %s", err.Error())
}
}

connectionString := net.JoinHostPort(conf.Rhost, strconv.Itoa(conf.Rport))
ikeClient.Conn, err = net.Dial("udp", connectionString)
if err != nil {
output.PrintfFrameworkError("Dial failed: %s", err.Error())

return false
}

output.PrintfFrameworkDebug("Successfully established UDP connection to %s", connectionString)

return true
}
90 changes: 90 additions & 0 deletions protocol/ikev2/ikev2_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package ikev2

import (
"encoding/hex"
"fmt"
"testing"
)

func TestVendorIDPack(t *testing.T) {
want := "2b000014c590254e5403cbb71f3d493111d7fcad"
tempBytes, _ := hex.DecodeString("c590254e5403cbb71f3d493111d7fcad")
got := IkePackVendorID(PayloadType["VENDOR_ID"], tempBytes)

if fmt.Sprintf("%02x", got) != want {
t.Fatalf("[1] %q : %02x != %s", got, got, want)
}

want = "2b000014c61baca1f1a60cc10800000000000000"
tempBytes, _ = hex.DecodeString("c61baca1f1a60cc10800000000000000")
got = IkePackVendorID(PayloadType["VENDOR_ID"], tempBytes)

if fmt.Sprintf("%02x", got) != want {
t.Fatalf("[2] %q : %02x != %s", got, got, want)
}

want = "2b0000184048b7d56ebce88525e7de7f00d6c2d3c0000000"
tempBytes, _ = hex.DecodeString("4048b7d56ebce88525e7de7f00d6c2d3c0000000")
got = IkePackVendorID(PayloadType["VENDOR_ID"], tempBytes)

if fmt.Sprintf("%02x", got) != want {
t.Fatalf("[3] %q : %02x != %s", got, got, want)
}

want = "290000144048b7d56ebce88525e7de7f00d6c2d3"
tempBytes, _ = hex.DecodeString("4048b7d56ebce88525e7de7f00d6c2d3")
got = IkePackVendorID(PayloadType["NOTIFY"], tempBytes)
if fmt.Sprintf("%02x", got) != want {
t.Fatalf("[4] %q : %02x != %s", got, got, want)
}
}

func TestSecurityAssociationPack(t *testing.T) {
want := "220000300000002c010100040300000c0100000c800e01000300000802000005030000080300000c000000080400000e"
defaultTransforms := []IkeTransform{
{PayloadType["TRANSFORM"], TransformType["ENCRYPTION_ALGORITHM"], EncryptionAlgorithm["ENCR_AES_CBC"], 0x800e0100},
{PayloadType["TRANSFORM"], TransformType["PSEUDO_RANDOM_FUNCTION"], PseudoRandomFunction["PRF_HMAC_SHA2_256"], 0},
{PayloadType["TRANSFORM"], TransformType["INTEGRITY_ALGORITHM"], IntegrityAlgorithm["AUTH_HMAC_SHA2_256_128"], 0},
{PayloadType["NONE"], TransformType["DIFFIE_HELLMAN_GROUP"], DiffieHellmanGroup["DH_GROUP_2048_BIT_MODP"], 0},
}
got := IkePackSecurityAssociation(PayloadType["KEY_EXCHANGE"], IkePackProposal(PayloadType["NONE"], 1, 1, defaultTransforms, ""))

if fmt.Sprintf("%02x", got) != want {
t.Fatalf("[1] %q : %02x != %s", got, got, want)
}
}

func TestNotifyPack(t *testing.T) {
want := "2900001c01004005a6358d813592fdd80a9aaa3390f39c8a5a76b6e4"
tempBytes, _ := hex.DecodeString("a6358d813592fdd80a9aaa3390f39c8a5a76b6e4")
got := IkePackNotify(PayloadType["NOTIFY"], NotifyType["NAT_DETECTION_DESTINATION_IP"], tempBytes, 1, 0)
if fmt.Sprintf("%02x", got) != want {
t.Fatalf("[1] %q : %02x != %s", got, got, want)
}

want = "2b00001c010040044cc324152ba3f68ef649ac1e6f96f33791611db2"
tempBytes, _ = hex.DecodeString("4cc324152ba3f68ef649ac1e6f96f33791611db2")
got = IkePackNotify(PayloadType["VENDOR_ID"], NotifyType["NAT_DETECTION_SOURCE_IP"], tempBytes, 1, 0)
if fmt.Sprintf("%02x", got) != want {
t.Fatalf("[2] %q : %02x != %s", got, got, want)
}

want = "290000080000402e"
got = IkePackNotify(PayloadType["NOTIFY"], NotifyType["IKEV2_FRAGMENTATION_SUPPORTED"], []byte{}, 0, 0)
if fmt.Sprintf("%02x", got) != want {
t.Fatalf("[3] %q : %02x != %s", got, got, want)
}

want = "2900000800004016"
got = IkePackNotify(PayloadType["NOTIFY"], NotifyType["REDIRECT_SUPPORTED"], []byte{}, 0, 0)
if fmt.Sprintf("%02x", got) != want {
t.Fatalf("[4] %q : %02x != %s", got, got, want)
}

want = "000000100000402f0001000200030004"
tempBytes, _ = hex.DecodeString("0001000200030004")
got = IkePackNotify(PayloadType["NONE"], NotifyType["SIGNATURE_HASH_ALGORITHMS"], tempBytes, 0, 0)
if fmt.Sprintf("%02x", got) != want {
t.Fatalf("[5] %q : %02x != %s", got, got, want)
}
}
113 changes: 113 additions & 0 deletions protocol/ikev2/packs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package ikev2

import (
"github.com/vulncheck-oss/go-exploit/transform"
)

// Creates a Nonce component.
//
// ikev2.IkePackNonce(ikev2.PayloadType["NOTIFY"], ikeClient.IkeCrypto.InitNonce)
func IkePackNonce(nextPayload int, nonce []byte) []byte {
return IkePackPayloadHeader(nextPayload, nonce)
}

// Creates a VendorID component.
//
// tempBytes, _ = hex.DecodeString("4048b7d56ebce88525e7de7f00d6c2d3")
// ikev2.IkePackVendorID(ikev2.PayloadType["NOTIFY"], tempBytes)
func IkePackVendorID(nextPayload int, vendorID []byte) []byte {
return IkePackPayloadHeader(nextPayload, vendorID)
}

// Creates a Notify component.
//
// tempBytes, _ = hex.DecodeString("0021030203030006")
// ikev2.IkePackNotify(ikev2.PayloadType["NONE"], ikev2.NotifyType["SIGNATURE_HASH_ALGORITHMS"], tempBytes, 0, 0)
func IkePackNotify(nextPayload int, notifyType int, data []byte, protocolID int, spiSize int) []byte {
payload := make([]byte, 0)
payload = append(payload, byte(protocolID))
payload = append(payload, byte(spiSize))
payload = append(payload, []byte(transform.PackBigInt16(notifyType))...)
payload = append(payload, data...)

return IkePackPayloadHeader(nextPayload, payload)
}

// Creates a KeyExchange component.
//
// ikev2.IkePackKeyExchange(ikev2.PayloadType["NONCE"], ikev2.DiffieHellmanGroup["DH_GROUP_2048_BIT_MODP"], ikeClient.IkeCrypto.ClientPubKey.Bytes())
func IkePackKeyExchange(nextPayload int, dhGroup int, data []byte) []byte {
payload := []byte(transform.PackBigInt16(dhGroup))
payload = append(payload, []byte(transform.PackBigInt16(0))...) // reserved bytes (2)
payload = append(payload, data...)

return IkePackPayloadHeader(nextPayload, payload)
}

// Creates a Security Association component.
//
// ikev2.IkePackSecurityAssociation(ikev2.PayloadType["KEY_EXCHANGE"], ikev2.IkePackProposal(ikev2.PayloadType["NONE"], 1, 1, defaultTransforms, ""))
func IkePackSecurityAssociation(payloadType int, proposal []byte) []byte {
return IkePackPayloadHeader(payloadType, proposal)
}

// Creates a transform byte array from a transform.
//
// ikev2.IkeTransform{NextPayload: ikev2.PayloadType["TRANSFORM"], TransformType: ikev2.TransformType["ENCRYPTION_ALGORITHM"], TransformID: ikev2.EncryptionAlgorithm["ENCR_AES_CBC"], TransformAttributes: 0x800e0100}
func (ikeTransform *IkeTransform) Pack() []byte {
payload := make([]byte, 0)
payload = append(payload, byte(ikeTransform.TransformType))
payload = append(payload, byte(0))
payload = append(payload, []byte(transform.PackBigInt16(ikeTransform.TransformID))...)
transform.PackBigInt16(ikeTransform.TransformID)

if ikeTransform.TransformAttributes != 0 {
payload = append(payload, []byte(transform.PackBigInt32(ikeTransform.TransformAttributes))...)
}

return IkePackPayloadHeader(ikeTransform.NextPayload, payload)
}

// Encapsulates a Packed component (or any binary array) with the nextHeader. Used by most of these packs.
func IkePackPayloadHeader(payloadType int, payloadIn []byte) []byte {
payload := make([]byte, 0)
payload = append(payload, byte(payloadType))
payload = append(payload, byte(0))
payload = append(payload, []byte(transform.PackBigInt16(len(payloadIn)+4))...)
payload = append(payload, payloadIn...)

return payload
}

// Creates a Proposal component.
//
// ikev2.IkePackProposal(ikev2.PayloadType["NONE"], 1, 1, defaultTransforms, "").
func IkePackProposal(nextPayload int, number int, id int, transforms []IkeTransform, spi string) []byte {
payload := make([]byte, 0)
payload = append(payload, byte(number))
payload = append(payload, byte(id))
payload = append(payload, byte(len(spi)))
payload = append(payload, byte(len(transforms)))
payload = append(payload, []byte(spi)...)
for _, transform := range transforms {
payload = append(payload, transform.Pack()...)
}

return IkePackPayloadHeader(nextPayload, payload)
}

// Creates a Header component.
//
// ikev2.IkePackHeader(ikeClient, ikev2.PayloadType["SECURITY_ASSOCIATION"], 0x20, ikev2.ExchangeType["IKE_SA_INIT"], 0x08, 0x0)
func IkePackHeader(ikeClient *IkeClient, payloadType int, version int, exchangeType int, flags int, messageID int) []byte {
payload := make([]byte, 0)
payload = append(payload, Uint64ToString(ikeClient.IkeCrypto.InitSPI)...)
payload = append(payload, Uint64ToString(ikeClient.IkeCrypto.RespSPI)...)
payload = append(payload, byte(payloadType))
payload = append(payload, byte(version))
payload = append(payload, byte(exchangeType))
payload = append(payload, byte(flags))
payload = append(payload, []byte(transform.PackBigInt32(messageID))...)

return payload
}
Loading
Loading