Skip to content

Commit e9984d8

Browse files
committed
add GenerateSystem to generate class file for execute command with arguments.
1 parent 214eb11 commit e9984d8

File tree

4 files changed

+125
-2
lines changed

4 files changed

+125
-2
lines changed

generator.go

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"github.com/pkg/errors"
99
)
1010

11-
// GenerateExecute is used to generate class file with execute command.
11+
// GenerateExecute is used to generate class file for execute command.
1212
func GenerateExecute(template []byte, command, class string) ([]byte, error) {
1313
const (
1414
fileNameFlag = "Execute.java"
@@ -70,7 +70,80 @@ func GenerateExecute(template []byte, command, class string) ([]byte, error) {
7070
return output.Bytes(), nil
7171
}
7272

73-
// GenerateReverseTCP is used to generate class file with
73+
// GenerateSystem is used to generate class file for execute command with arguments .
74+
func GenerateSystem(template []byte, binary, arguments, class string) ([]byte, error) {
75+
const (
76+
fileNameFlag = "System.java"
77+
binaryFlag = "${bin}"
78+
argumentFlag = "${args}"
79+
className = "System\x01"
80+
uint16Size = 2
81+
)
82+
83+
err := checkJavaClass(template)
84+
if err != nil {
85+
return nil, err
86+
}
87+
88+
// find three special strings
89+
fileNameIdx := bytes.Index(template, []byte(fileNameFlag))
90+
if fileNameIdx == -1 {
91+
return nil, errors.New("failed to find file name in system template")
92+
}
93+
binaryIdx := bytes.Index(template, []byte(binaryFlag))
94+
if binaryIdx == -1 {
95+
return nil, errors.New("failed to find binary flag in system template")
96+
}
97+
argumentIdx := bytes.Index(template, []byte(argumentFlag))
98+
if argumentIdx == -1 {
99+
return nil, errors.New("failed to find argument flag in system template")
100+
}
101+
classNameIdx := bytes.Index(template, []byte(className))
102+
if classNameIdx == -1 {
103+
return nil, errors.New("failed to find class name in system template")
104+
}
105+
106+
// check arguments
107+
if binary == "" {
108+
return nil, errors.New("empty binary")
109+
}
110+
if class == "" {
111+
class = "System"
112+
}
113+
114+
// generate output class file
115+
output := bytes.NewBuffer(make([]byte, 0, len(template)+128))
116+
117+
// change file name
118+
output.Write(template[:fileNameIdx-uint16Size])
119+
fileName := class + ".java"
120+
size := beUint16ToBytes(uint16(len(fileName)))
121+
output.Write(size)
122+
output.WriteString(fileName)
123+
124+
// change binary
125+
output.Write(template[fileNameIdx+len(fileNameFlag) : binaryIdx-uint16Size])
126+
size = beUint16ToBytes(uint16(len(binary)))
127+
output.Write(size)
128+
output.WriteString(binary)
129+
130+
// change argument
131+
output.Write(template[binaryIdx+len(binaryFlag) : argumentIdx-uint16Size])
132+
size = beUint16ToBytes(uint16(len(arguments)))
133+
output.Write(size)
134+
output.WriteString(arguments)
135+
136+
// change class name
137+
output.Write(template[argumentIdx+len(argumentFlag) : classNameIdx-uint16Size])
138+
size = beUint16ToBytes(uint16(len(class)))
139+
output.Write(size)
140+
output.WriteString(class)
141+
142+
output.Write(template[classNameIdx+len(className)-1:])
143+
return output.Bytes(), nil
144+
}
145+
146+
// GenerateReverseTCP is used to generate class file for
74147
// meterpreter: payload/java/meterpreter/reverse_tcp.
75148
func GenerateReverseTCP(template []byte, host string, port uint16, token, class string) ([]byte, error) {
76149
const (

generator_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,56 @@ func TestGenerateExecute(t *testing.T) {
7070
})
7171
}
7272

73+
func TestGenerateSystem(t *testing.T) {
74+
template, err := os.ReadFile("testdata/template/System.class")
75+
require.NoError(t, err)
76+
spew.Dump(template)
77+
78+
t.Run("common", func(t *testing.T) {
79+
class, err := GenerateSystem(template, "cmd", "/c whoami", "Test")
80+
require.NoError(t, err)
81+
spew.Dump(class)
82+
})
83+
84+
t.Run("default class", func(t *testing.T) {
85+
class, err := GenerateSystem(template, "${bin}", "${args}", "")
86+
require.NoError(t, err)
87+
spew.Dump(class)
88+
89+
require.Equal(t, template, class)
90+
})
91+
92+
t.Run("compare", func(t *testing.T) {
93+
class, err := GenerateSystem(template, "cmd", "/c net user", "NetUser")
94+
require.NoError(t, err)
95+
spew.Dump(class)
96+
97+
expected, err := os.ReadFile("testdata/template/compare/NetUser.class")
98+
require.NoError(t, err)
99+
require.Equal(t, expected, class)
100+
})
101+
102+
t.Run("invalid template", func(t *testing.T) {
103+
t.Run("invalid size", func(t *testing.T) {
104+
class, err := GenerateSystem(nil, "", "", "")
105+
require.EqualError(t, err, "invalid Java class template file size")
106+
require.Zero(t, class)
107+
})
108+
109+
t.Run("invalid data", func(t *testing.T) {
110+
class, err := GenerateSystem(bytes.Repeat([]byte{0x00}, 8), "", "", "")
111+
require.EqualError(t, err, "invalid Java class template file")
112+
require.Zero(t, class)
113+
})
114+
})
115+
116+
t.Run("empty binary", func(t *testing.T) {
117+
class, err := GenerateSystem(template, "", "", "Test")
118+
require.EqualError(t, err, "empty binary")
119+
require.Zero(t, class)
120+
})
121+
}
122+
73123
func TestGenerateReverseTCP(t *testing.T) {
74124
template, err := os.ReadFile("testdata/template/ReverseTCP.class")
75125
require.NoError(t, err)

testdata/template/System.class

926 Bytes
Binary file not shown.
929 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)