Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 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
126 changes: 126 additions & 0 deletions protocol/ikev2/ikev2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// 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) (string, bool) {
// ikeClient.IkeCrypto = ikev2.IkeCrypto{}
// ikeClient.IkeCrypto.Init()
// ok := ikeClient.IkeCrypto.GenerateDHKey(diffieHellmanGroup)
// if !ok {
// return "", false
// }
//
// transforms := []ikev2.IkeTransform{
// {NextPayload: ikev2.PayloadType["NONE"], TransformType: ikev2.TransformType["DIFFIE_HELLMAN_GROUP"], TransformID: ikev2.DiffieHellmanGroup["DH_GROUP_2048_BIT_MODP"], TransformAttributes: 0},
// }
//
// header := ikev2.IkePackHeader(ikeClient, ikev2.PayloadType["SECURITY_ASSOCIATION"], 0x20, ikev2.ExchangeType["IKE_SA_INIT"], 0x08, 0x0)
// message := ikev2.IkePackSecurityAssociation(ikev2.PayloadType["KEY_EXCHANGE"], ikev2.IkePackProposal(ikev2.PayloadType["NONE"], 1, 1, transforms, ""))
// message += ikev2.IkePackKeyExchange(ikev2.PayloadType["NONCE"], ikev2.DiffieHellmanGroup["DH_GROUP_2048_BIT_MODP"], string(ikeClient.IkeCrypto.ClientPubKey.Bytes()))
// message += ikev2.IkePackNonce(ikev2.PayloadType["NOTIFY"], ikeClient.IkeCrypto.InitNonce)
//
// tempBytes, _ := hex.DecodeString("a6358d813592fdd80a9aaa3390f39c8a5a76b6e4")
// message += ikev2.IkePackNotify(ikev2.PayloadType["NOTIFY"], ikev2.NotifyType["NAT_DETECTION_DESTINATION_IP"], string(tempBytes), 1, 0)
// // whatever else...
//
// return header + transform.PackBigInt32(len(message)+len(header)+4) + message, true
// }
//
// 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"
"fmt"
"math/big"
mrand "math/rand"
"net"

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

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

return byteString
}

func generateNonce(length int) string {
nonce := make([]byte, length)
_, _ = rand.Read(nonce)

return string(nonce)
}

// 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() {
ikeCrypto.InitNonce = generateNonce(32)
ikeCrypto.RespNonce = ""
ikeCrypto.InitSPI = mrand.Uint64()
ikeCrypto.RespSPI = 0x0000000000000000
}

// 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 := fmt.Sprintf("%s:%d", conf.Rhost, 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"], string(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"], string(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"], string(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"], string(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"], string(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"], string(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"], "", 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"], "", 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"], string(tempBytes), 0, 0)
if fmt.Sprintf("%02x", got) != want {
t.Fatalf("[5] %q : %02x != %s", got, got, want)
}
}
69 changes: 69 additions & 0 deletions protocol/ikev2/packs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package ikev2

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

func IkePackNonce(nextPayload int, nonce string) string {
return IkePackPayloadHeader(nextPayload, nonce)
}

func IkePackVendorID(nextPayload int, vendorID string) string {
return IkePackPayloadHeader(nextPayload, vendorID)
}

func IkePackNotify(nextPayload int, notifyType int, data string, protocolID int, spiSize int) string {
payload := string(byte(protocolID))
payload += string(byte(spiSize))
payload += transform.PackBigInt16(notifyType)
payload += data

return IkePackPayloadHeader(nextPayload, payload)
}

func IkePackKeyExchange(nextPayload int, dhGroup int, data string) string {
payload := transform.PackBigInt16(dhGroup)
payload += transform.PackBigInt16(0) // reserved bytes (2)

return IkePackPayloadHeader(nextPayload, payload+data)
}

func IkePackSecurityAssociation(payloadType int, proposal string) string {
return IkePackPayloadHeader(payloadType, proposal)
}

func (ikeTransform *IkeTransform) Pack() string {
transformData := string(byte(ikeTransform.TransformType)) +
string(byte(0)) + // reserved byte
transform.PackBigInt16(ikeTransform.TransformID)

if ikeTransform.TransformAttributes != 0 {
transformData += transform.PackBigInt32(ikeTransform.TransformAttributes)
}

return IkePackPayloadHeader(ikeTransform.NextPayload, transformData)
}

func IkePackPayloadHeader(payloadType int, payload string) string {
return string(byte(payloadType)) +
string(byte(0)) + // critical bit + reserved (7 bits) combine to make this single 0x00 byte
transform.PackBigInt16(len(payload)+4) + payload
}

func IkePackProposal(nextPayload int, number int, id int, transforms []IkeTransform, spi string) string {
var transformData string
for _, transform := range transforms {
transformData += transform.Pack()
}
payload := string(byte(number)) + string(byte(id)) + string(byte(len(spi))) + string(byte(len(transforms))) + spi + transformData

return IkePackPayloadHeader(nextPayload, payload)
}

func IkePackHeader(ikeClient *IkeClient, payloadType int, version int, exchangeType int, flags int, messageID int) string {
return Uint64ToString(ikeClient.IkeCrypto.InitSPI) +
Uint64ToString(ikeClient.IkeCrypto.RespSPI) +
string(byte(payloadType)) +
string(byte(version)) + // default 0x20
string(byte(exchangeType)) +
string(byte(flags)) + // default 0x08
transform.PackBigInt32(messageID)
}
Loading
Loading