Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
85 changes: 85 additions & 0 deletions protocol/ikev2/ikev2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// I hate go idioms for enums, so we're doing string maps.
// The primary reason is that I want the context to be evident, much like a namespace when using the structures here.
// 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.
// We will presumably add to this as we go, as needed.
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
}

// The initial reset/connect function.
// Should be the first step of a new connection but will likely not be run from within an exploit, but rather the
// SAInit function.
func (ikeClient *IkeClient) Connect(conf *config.Config) bool {
var err error
// the connection may not be active, just want to close it if so, if it's not active, great.
if ikeClient.Conn != nil {
err = ikeClient.Conn.Close()
if err != nil {
output.PrintfFrameworkWarn("Failed to close socket: %s", err.Error())
// we probably do not want to exit on this, we're establishing a new connection anyways
}
}

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)
}
}
70 changes: 70 additions & 0 deletions protocol/ikev2/packs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
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 {
// reserved = 0
payload := transform.PackBigInt16(dhGroup)
payload += transform.PackBigInt16(0)

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