mirror of
https://github.com/oiweiwei/go-msrpc
synced 2026-06-08 16:28:58 +00:00
feat: improve examples/dcom.go and implement "generic" wmiexec.go script
see: https://github.com/oiweiwei/go-msrpc/issues/3
This commit is contained in:
@@ -14,8 +14,8 @@ class MyClass : Base {
|
||||
};
|
||||
|
||||
instance of MyClass {
|
||||
Array = {1, 2, 3};
|
||||
Id = 123;
|
||||
Data1 = "StringField";
|
||||
Data2 = "defaultValue";
|
||||
Id = 123;
|
||||
Array = {1, 2, 3};
|
||||
};
|
||||
|
||||
@@ -1,12 +1,27 @@
|
||||
//go:build exclude
|
||||
//go:build ignore
|
||||
|
||||
// dcom.go script executes the calc.exe on the remote machine.
|
||||
// wmiexec.go is a sample for executing arbitrary WMI class method on the remote machine, examples:
|
||||
|
||||
// (1) enumerate sub keys on the remote machine, where 2147483650 is HKEY_LOCAL_MACHINE
|
||||
// (see https://learn.microsoft.com/en-us/previous-versions/windows/desktop/regprov/enumkey-method-in-class-stdregprov)
|
||||
//
|
||||
// go run wmiexec.go \
|
||||
// --debug \
|
||||
// --class StdRegProv \
|
||||
// --method EnumKey \
|
||||
// --args '{"hDefKey": 2147483650, "sSubKeyName": "SYSTEM\\CurrentControlSet\\Services"}'
|
||||
//
|
||||
// (2) cerate a process on the remote machine:
|
||||
//
|
||||
// go run wmiexec.go --class Win32Process --method Create --args '{"CommandLine": "calc.exe", "CurrentDirectory": "C:\\"}'
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
@@ -35,6 +50,32 @@ import (
|
||||
|
||||
var j = func(data any) string { b, _ := json.MarshalIndent(data, "", " "); return string(b) }
|
||||
|
||||
var (
|
||||
class string
|
||||
method string
|
||||
arg string
|
||||
resource string
|
||||
debug bool
|
||||
args wmio.Values
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
flag.StringVar(&class, "class", "Win32_Process", "class name")
|
||||
flag.StringVar(&method, "method", "Create", "method name")
|
||||
flag.StringVar(&arg, "args", `{"CommandLine":"calc.exe","CurrentDirectory":"C:\\"}`, "method args")
|
||||
flag.StringVar(&resource, "resource", "//./root/cimv2", "resource name, ie root/default, or root/cimv2")
|
||||
flag.BoolVar(&debug, "debug", false, "debug")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if err := json.Unmarshal([]byte(arg), &args); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "parse_args", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func init() {
|
||||
// add credentials.
|
||||
gssapi.AddCredential(credential.NewFromPassword(os.Getenv("USERNAME"), os.Getenv("PASSWORD")))
|
||||
@@ -46,6 +87,14 @@ func init() {
|
||||
|
||||
func main() {
|
||||
|
||||
log := zerolog.New(os.Stderr)
|
||||
|
||||
if !debug {
|
||||
log = zerolog.New(io.Discard)
|
||||
}
|
||||
|
||||
log.Info().Str("class", class).Str("method", method).Str("args", fmt.Sprintf("%+v", args)).Msg("execute")
|
||||
|
||||
ctx := gssapi.NewSecurityContext(context.Background())
|
||||
|
||||
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dcom/2be2642e-67a1-4690-883b-642b505ddb1d
|
||||
@@ -73,17 +122,19 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Println("OBJECT RESOLVER STRING BINDINGS")
|
||||
fmt.Println("-----------------------")
|
||||
if debug {
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Println("OBJECT RESOLVER STRING BINDINGS")
|
||||
fmt.Println("-----------------------")
|
||||
|
||||
fmt.Println(j(srv.ObjectResolverBindings.GetStringBindings()))
|
||||
fmt.Println(j(srv.ObjectResolverBindings.GetStringBindings()))
|
||||
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Println("OBJECT RESOLVER SECURITY BINDINGS")
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Println("OBJECT RESOLVER SECURITY BINDINGS")
|
||||
fmt.Println("-----------------------")
|
||||
|
||||
fmt.Println(j(srv.ObjectResolverBindings.GetSecurityBindings()))
|
||||
fmt.Println(j(srv.ObjectResolverBindings.GetSecurityBindings()))
|
||||
}
|
||||
|
||||
// dial activation client.
|
||||
// cc, err = dcerpc.Dial(ctx, net.JoinHostPort(os.Getenv("SERVER"), "135"))
|
||||
@@ -118,17 +169,19 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Println("REMOTE ACTIVATION")
|
||||
fmt.Println("-----------------------")
|
||||
|
||||
fmt.Println(j(act))
|
||||
|
||||
for i, ifd := range act.InterfaceData {
|
||||
if debug {
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Println(i, "REMOTE ACTIVATION INTERFACE")
|
||||
fmt.Println("REMOTE ACTIVATION")
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Println(j(ifd.GetObjectReference()))
|
||||
|
||||
fmt.Println(j(act))
|
||||
|
||||
for i, ifd := range act.InterfaceData {
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Println(i, "REMOTE ACTIVATION INTERFACE")
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Println(j(ifd.GetObjectReference()))
|
||||
}
|
||||
}
|
||||
|
||||
std := act.InterfaceData[0].GetStandardObjectReference().Std
|
||||
@@ -149,7 +202,7 @@ func main() {
|
||||
l1login, err := iwbemlevel1login.NewLevel1LoginClient(ctx, wcc,
|
||||
dcom.WithIPID(std.IPID),
|
||||
dcerpc.WithSign(),
|
||||
dcerpc.WithTargetName(os.Getenv("TARGET")), dcerpc.WithLogger(zerolog.New(os.Stdout)))
|
||||
dcerpc.WithTargetName(os.Getenv("TARGET")), dcerpc.WithLogger(log))
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return
|
||||
@@ -164,12 +217,14 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(j(pos))
|
||||
if debug {
|
||||
fmt.Println(j(pos))
|
||||
}
|
||||
|
||||
// login to WMI.
|
||||
login, err := l1login.NTLMLogin(ctx, &iwbemlevel1login.NTLMLoginRequest{
|
||||
This: &dcom.ORPCThis{Version: srv.COMVersion},
|
||||
NetworkResource: "//./root/cimv2",
|
||||
NetworkResource: resource,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@@ -177,7 +232,9 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(j(login))
|
||||
if debug {
|
||||
fmt.Println(j(login))
|
||||
}
|
||||
|
||||
ns := login.Namespace
|
||||
|
||||
@@ -190,17 +247,17 @@ func main() {
|
||||
|
||||
builder := query.NewBuilder(ctx, svcs, srv.COMVersion)
|
||||
|
||||
in := wmio.Values{
|
||||
"CommandLine": "cmd.exe /Q /c calc.exe",
|
||||
"CurrentDirectory": "C:\\",
|
||||
if debug {
|
||||
obj, _ := builder.Spawn(class).Method(method).Values(args, wmio.JSONValueToType).Object()
|
||||
fmt.Println(j(obj))
|
||||
}
|
||||
|
||||
// use simple query builder to execute the Create static method of the Win32_Process.
|
||||
out, err := builder.Spawn("Win32_Process").Method("Create").Values(in).Exec().Object()
|
||||
out, err := builder.Spawn(class).Method(method).Values(args, wmio.JSONValueToType).Exec().Object()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "svcs_exec_method", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(j(out))
|
||||
fmt.Println(j(out.Values()))
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package wmio
|
||||
|
||||
import "strconv"
|
||||
|
||||
func JSONValueToType(value any, typ CIMType) (any, bool) {
|
||||
switch value := value.(type) {
|
||||
case float64:
|
||||
switch typ {
|
||||
case Uint8:
|
||||
return uint8(value), true
|
||||
case Int8:
|
||||
return int8(value), true
|
||||
case Uint16:
|
||||
return uint16(value), true
|
||||
case Int16:
|
||||
return int16(value), true
|
||||
case Uint32:
|
||||
return uint32(value), true
|
||||
case Int32:
|
||||
return int32(value), true
|
||||
case Uint64:
|
||||
return uint64(value), true
|
||||
case Int64:
|
||||
return int64(value), true
|
||||
case Float32:
|
||||
return float32(value), true
|
||||
case Float64:
|
||||
return value, true
|
||||
}
|
||||
case []float64:
|
||||
switch typ {
|
||||
case Uint8Array:
|
||||
ret := make([]uint8, len(value))
|
||||
for i := range value {
|
||||
ret[i] = uint8(value[i])
|
||||
}
|
||||
return ret, true
|
||||
case Int8Array:
|
||||
ret := make([]int8, len(value))
|
||||
for i := range value {
|
||||
ret[i] = int8(value[i])
|
||||
}
|
||||
return ret, true
|
||||
case Uint16Array:
|
||||
ret := make([]uint16, len(value))
|
||||
for i := range value {
|
||||
ret[i] = uint16(value[i])
|
||||
}
|
||||
return ret, true
|
||||
case Int16Array:
|
||||
ret := make([]int16, len(value))
|
||||
for i := range value {
|
||||
ret[i] = int16(value[i])
|
||||
}
|
||||
return ret, true
|
||||
case Uint32Array:
|
||||
ret := make([]uint32, len(value))
|
||||
for i := range value {
|
||||
ret[i] = uint32(value[i])
|
||||
}
|
||||
return ret, true
|
||||
case Int32Array:
|
||||
ret := make([]int32, len(value))
|
||||
for i := range value {
|
||||
ret[i] = int32(value[i])
|
||||
}
|
||||
return ret, true
|
||||
case Uint64Array:
|
||||
ret := make([]uint64, len(value))
|
||||
for i := range value {
|
||||
ret[i] = uint64(value[i])
|
||||
}
|
||||
return ret, true
|
||||
case Int64Array:
|
||||
ret := make([]int64, len(value))
|
||||
for i := range value {
|
||||
ret[i] = int64(value[i])
|
||||
}
|
||||
return ret, true
|
||||
case Float32Array:
|
||||
ret := make([]float32, len(value))
|
||||
for i := range value {
|
||||
ret[i] = float32(value[i])
|
||||
}
|
||||
return value, true
|
||||
case Float64Array:
|
||||
return value, true
|
||||
}
|
||||
case string:
|
||||
switch typ {
|
||||
case Uint8:
|
||||
ret, _ := strconv.ParseUint(value, 10, 8)
|
||||
return uint8(ret), true
|
||||
case Int8:
|
||||
ret, _ := strconv.ParseInt(value, 10, 8)
|
||||
return uint8(ret), true
|
||||
case Uint16:
|
||||
ret, _ := strconv.ParseUint(value, 10, 16)
|
||||
return uint16(ret), true
|
||||
case Int16:
|
||||
ret, _ := strconv.ParseInt(value, 10, 16)
|
||||
return uint16(ret), true
|
||||
case Uint32:
|
||||
ret, _ := strconv.ParseUint(value, 10, 32)
|
||||
return uint32(ret), true
|
||||
case Int32:
|
||||
ret, _ := strconv.ParseInt(value, 10, 32)
|
||||
return uint32(ret), true
|
||||
case Uint64:
|
||||
ret, _ := strconv.ParseUint(value, 10, 64)
|
||||
return uint64(ret), true
|
||||
case Int64:
|
||||
ret, _ := strconv.ParseInt(value, 10, 64)
|
||||
return uint64(ret), true
|
||||
case Float32:
|
||||
ret, _ := strconv.ParseFloat(value, 32)
|
||||
return float32(ret), true
|
||||
case Float64:
|
||||
ret, _ := strconv.ParseFloat(value, 64)
|
||||
return float64(ret), true
|
||||
}
|
||||
case []string:
|
||||
switch typ {
|
||||
case Uint8Array:
|
||||
ret := make([]uint8, len(value))
|
||||
for i := range value {
|
||||
rret, _ := strconv.ParseUint(value[i], 10, 8)
|
||||
ret[i] = uint8(rret)
|
||||
}
|
||||
return ret, true
|
||||
case Int8Array:
|
||||
ret := make([]int8, len(value))
|
||||
for i := range value {
|
||||
rret, _ := strconv.ParseInt(value[i], 10, 8)
|
||||
ret[i] = int8(rret)
|
||||
}
|
||||
return ret, true
|
||||
case Uint16Array:
|
||||
ret := make([]uint16, len(value))
|
||||
for i := range value {
|
||||
rret, _ := strconv.ParseUint(value[i], 10, 16)
|
||||
ret[i] = uint16(rret)
|
||||
}
|
||||
return ret, true
|
||||
case Int16Array:
|
||||
ret := make([]int16, len(value))
|
||||
for i := range value {
|
||||
rret, _ := strconv.ParseInt(value[i], 10, 16)
|
||||
ret[i] = int16(rret)
|
||||
}
|
||||
return ret, true
|
||||
case Uint32Array:
|
||||
ret := make([]uint32, len(value))
|
||||
for i := range value {
|
||||
rret, _ := strconv.ParseUint(value[i], 10, 32)
|
||||
ret[i] = uint32(rret)
|
||||
}
|
||||
return ret, true
|
||||
case Int32Array:
|
||||
ret := make([]int32, len(value))
|
||||
for i := range value {
|
||||
rret, _ := strconv.ParseInt(value[i], 10, 32)
|
||||
ret[i] = int32(rret)
|
||||
}
|
||||
return ret, true
|
||||
case Uint64Array:
|
||||
ret := make([]uint64, len(value))
|
||||
for i := range value {
|
||||
rret, _ := strconv.ParseUint(value[i], 10, 64)
|
||||
ret[i] = uint64(rret)
|
||||
}
|
||||
return ret, true
|
||||
case Int64Array:
|
||||
ret := make([]int64, len(value))
|
||||
for i := range value {
|
||||
rret, _ := strconv.ParseInt(value[i], 10, 64)
|
||||
ret[i] = int64(rret)
|
||||
}
|
||||
return ret, true
|
||||
}
|
||||
}
|
||||
|
||||
return value, false
|
||||
}
|
||||
@@ -78,7 +78,7 @@ func (b *builder) Spawn(cls string) *builder {
|
||||
|
||||
obj, err := b.wmi.GetObject(b.ctx, &iwbemservices.GetObjectRequest{
|
||||
This: &dcom.ORPCThis{Version: b.ver},
|
||||
ObjectPath: &oaut.String{Data: "Win32_Process"},
|
||||
ObjectPath: &oaut.String{Data: cls},
|
||||
Object: &wmi.ClassObject{},
|
||||
})
|
||||
|
||||
@@ -109,13 +109,13 @@ func (b *builder) Method(m string) *builder {
|
||||
}
|
||||
|
||||
// Values function sets the parameters for the object.
|
||||
func (b *builder) Values(values wmio.Values) *builder {
|
||||
func (b *builder) Values(values wmio.Values, convert ...func(any, wmio.CIMType) (any, bool)) *builder {
|
||||
|
||||
if b.obj == nil {
|
||||
return b.withErrf("Values: object is nil")
|
||||
}
|
||||
|
||||
params, err := b.obj.New(values)
|
||||
params, err := b.obj.New(values, convert...)
|
||||
if err != nil {
|
||||
return b.withErrf("Values: %v", params)
|
||||
}
|
||||
|
||||
+14
-5
@@ -147,7 +147,7 @@ func (o *Object) Method(n string) (*Object, *Object, error) {
|
||||
|
||||
type Values map[string]any
|
||||
|
||||
func (o *Object) New(values Values) (*Object, error) {
|
||||
func (o *Object) New(values Values, convert ...func(any, CIMType) (any, bool)) (*Object, error) {
|
||||
|
||||
if values == nil {
|
||||
values = make(map[string]any)
|
||||
@@ -187,12 +187,21 @@ func (o *Object) New(values Values) (*Object, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
typ, err := ValueType(value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %v", inst.CurrentClass.Properties[i].Name, err)
|
||||
var typeOk bool
|
||||
|
||||
if len(convert) > 0 {
|
||||
value, typeOk = convert[0](value, inst.CurrentClass.Properties[i].Value.Type)
|
||||
inst.Properties[i] = &Property{Value: Value{Type: inst.CurrentClass.Properties[i].Value.Type, Value: value}}
|
||||
}
|
||||
|
||||
if !typeOk {
|
||||
typ, err := ValueType(value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %v", inst.CurrentClass.Properties[i].Name, err)
|
||||
}
|
||||
inst.Properties[i] = &Property{Value: Value{Type: typ, Value: value}}
|
||||
}
|
||||
|
||||
inst.Properties[i] = &Property{Value: Value{Type: typ, Value: value}}
|
||||
}
|
||||
|
||||
return &Object{Instance: inst}, nil
|
||||
|
||||
Reference in New Issue
Block a user