mirror of
https://github.com/bettercap/bettercap
synced 2025-08-19 13:09:49 -07:00
new: krb5 krb-as-req parser
This commit is contained in:
parent
68b05ac469
commit
b9c8785e8a
3 changed files with 154 additions and 3 deletions
40
modules/net_sniff_krb5.go
Normal file
40
modules/net_sniff_krb5.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package modules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/asn1"
|
||||||
|
|
||||||
|
"github.com/evilsocket/bettercap-ng/core"
|
||||||
|
"github.com/evilsocket/bettercap-ng/packets"
|
||||||
|
|
||||||
|
"github.com/google/gopacket"
|
||||||
|
"github.com/google/gopacket/layers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func krb5Parser(ip *layers.IPv4, pkt gopacket.Packet, udp *layers.UDP) bool {
|
||||||
|
if udp.DstPort != 88 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var req packets.Krb5Request
|
||||||
|
_, err := asn1.UnmarshalWithParams(udp.Payload, &req, packets.Krb5AsReqParam)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := req.String()
|
||||||
|
NewSnifferEvent(
|
||||||
|
pkt.Metadata().Timestamp,
|
||||||
|
"krb5",
|
||||||
|
ip.SrcIP.String(),
|
||||||
|
ip.DstIP.String(),
|
||||||
|
SniffData{
|
||||||
|
"req": req,
|
||||||
|
},
|
||||||
|
"%s %s -> %s : %s",
|
||||||
|
core.W(core.BG_RED+core.FG_BLACK, "krb-as-req"),
|
||||||
|
vIP(ip.SrcIP),
|
||||||
|
vIP(ip.DstIP),
|
||||||
|
s,
|
||||||
|
).Push()
|
||||||
|
return true
|
||||||
|
}
|
|
@ -44,9 +44,9 @@ func udpParser(ip *layers.IPv4, pkt gopacket.Packet, verbose bool) {
|
||||||
|
|
||||||
if dnsParser(ip, pkt, udp) {
|
if dnsParser(ip, pkt, udp) {
|
||||||
return
|
return
|
||||||
}
|
} else if krb5Parser(ip, pkt, udp) {
|
||||||
|
return
|
||||||
if verbose == true {
|
} else if verbose == true {
|
||||||
NewSnifferEvent(
|
NewSnifferEvent(
|
||||||
pkt.Metadata().Timestamp,
|
pkt.Metadata().Timestamp,
|
||||||
"udp",
|
"udp",
|
||||||
|
|
111
packets/krb5.go
Normal file
111
packets/krb5.go
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
package packets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"encoding/asn1"
|
||||||
|
"encoding/hex"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Krb5AsRequestType = 10
|
||||||
|
Krb5Krb5PrincipalNameType = 1
|
||||||
|
Krb5CryptDesCbcMd4 = 2
|
||||||
|
Krb5CryptDescCbcMd5 = 3
|
||||||
|
Krb5CryptRc4Hmac = 23
|
||||||
|
)
|
||||||
|
|
||||||
|
//https://github.com/heimdal/heimdal/blob/master/lib/asn1/krb5.asn1
|
||||||
|
var (
|
||||||
|
Krb5AsReqParam = "application,explicit,tag:10"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Krb5PrincipalName struct {
|
||||||
|
NameType int `asn1:"explicit,tag:0"`
|
||||||
|
NameString []string `asn1:"general,explicit,tag:1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Krb5EncryptedData struct {
|
||||||
|
Etype int `asn1:"explicit,tag:0"`
|
||||||
|
Kvno int `asn1:"optional,explicit,tag:1"`
|
||||||
|
Cipher []byte `asn1:"explicit,tag:2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Krb5Ticket struct {
|
||||||
|
TktVno int `asn1:"explicit,tag:0"`
|
||||||
|
Realm string `asn1:"general,explicit,tag:1"`
|
||||||
|
Sname Krb5PrincipalName `asn1:"explicit,tag:2"`
|
||||||
|
EncPart Krb5EncryptedData `asn1:"explicit,tag:3"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Krb5Address struct {
|
||||||
|
AddrType int `asn1:"explicit,tag:0"`
|
||||||
|
Krb5Address []byte `asn1:"explicit,tag:1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Krb5PnData struct {
|
||||||
|
Krb5PnDataType int `asn1:"explicit,tag:1"`
|
||||||
|
Krb5PnDataValue []byte `asn1:"explicit,tag:2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Krb5ReqBody struct {
|
||||||
|
KDCOptions asn1.BitString `asn1:"explicit,tag:0"`
|
||||||
|
Cname Krb5PrincipalName `asn1:"optional,explicit,tag:1"`
|
||||||
|
Realm string `asn1:"general,explicit,tag:2"`
|
||||||
|
Sname Krb5PrincipalName `asn1:"optional,explicit,tag:3"`
|
||||||
|
From time.Time `asn1:"generalized,optional,explicit,tag:4"`
|
||||||
|
Till time.Time `asn1:"generalized,optional,explicit,tag:5"`
|
||||||
|
Rtime time.Time `asn1:"generalized,optional,explicit,tag:6"`
|
||||||
|
Nonce int `asn1:"explicit,tag:7"`
|
||||||
|
Etype []int `asn1:"explicit,tag:8"`
|
||||||
|
Krb5Addresses []Krb5Address `asn1:"optional,explicit,tag:9"`
|
||||||
|
EncAuthData Krb5EncryptedData `asn1:"optional,explicit,tag:10"`
|
||||||
|
AdditionalKrb5Tickets []Krb5Ticket `asn1:"optional,explicit,tag:11"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Krb5Request struct {
|
||||||
|
Pvno int `asn1:"explicit,tag:1"`
|
||||||
|
MsgType int `asn1:"explicit,tag:2"`
|
||||||
|
Krb5PnData []Krb5PnData `asn1:"optional,explicit,tag:3"`
|
||||||
|
ReqBody Krb5ReqBody `asn1:"explicit,tag:4"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// $krb5$Krb5PnData[0].Krb5PnDataValue.Etype$Cname.NameString[0]$Realm$nodata$cipher
|
||||||
|
func (kdc Krb5Request) String() (string, error) {
|
||||||
|
var eType, cipher string
|
||||||
|
var crypt []string
|
||||||
|
realm := kdc.ReqBody.Realm
|
||||||
|
|
||||||
|
if kdc.ReqBody.Cname.NameType == Krb5Krb5PrincipalNameType {
|
||||||
|
crypt = kdc.ReqBody.Cname.NameString
|
||||||
|
}
|
||||||
|
if len(crypt) != 1 {
|
||||||
|
return "", errors.New("No crypt alg found")
|
||||||
|
}
|
||||||
|
for _, pn := range kdc.Krb5PnData {
|
||||||
|
if pn.Krb5PnDataType == 2 {
|
||||||
|
enc, err := pn.getParsedValue()
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New("Failed to extract pnData from as-req")
|
||||||
|
}
|
||||||
|
eType = strconv.Itoa(enc.Etype)
|
||||||
|
cipher = hex.EncodeToString(enc.Cipher)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if eType == "" || cipher == "" {
|
||||||
|
return "", errors.New("No encryption type or cipher found")
|
||||||
|
}
|
||||||
|
hash := "$krb5$" + eType + "$" + crypt[0] + "$" + realm + "$nodata$" + cipher
|
||||||
|
return hash, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pd Krb5PnData) getParsedValue() (Krb5EncryptedData, error) {
|
||||||
|
var encData Krb5EncryptedData
|
||||||
|
_, err := asn1.Unmarshal(pd.Krb5PnDataValue, &encData)
|
||||||
|
if err != nil {
|
||||||
|
return Krb5EncryptedData{}, errors.New("Failed to parse pdata value")
|
||||||
|
}
|
||||||
|
return encData, nil
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue