Authentication and Cookies
Patterns for cases that require a login.
Basic authentication
Section titled “Basic authentication”res = send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'admin'), 'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']))If HttpUsername / HttpPassword are set, a retry after a 401 response may select Basic, Digest, NTLM, or another scheme. Use authorization or preferred_auth when you want to specify the method explicitly.
res = send_request_cgi( 'method' => 'GET', 'uri' => '/', 'username' => datastore['HttpUsername'], 'password' => datastore['HttpPassword'], 'preferred_auth' => 'Digest')Examples of preferred_auth: Basic, Digest, NTLM, Kerberos, Negotiate, None.
Form login with keep_cookies
Section titled “Form login with keep_cookies”res = send_request_cgi( 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'login.php'), 'keep_cookies' => true, 'vars_post' => { 'username' => datastore['USERNAME'], 'password' => datastore['PASSWORD'] })fail_with(Failure::Unreachable, "#{peer} - no response") if res.nil?fail_with(Failure::NoAccess, "login failed: #{res.code}") unless res.code == 302
# The cookie_jar is attached automatically from here onres = send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'dashboard'))example_webapp.rb follows the same flow. Some examples use Basic and form authentication together.
'authorization' => basic_auth(user, pass),'keep_cookies' => true,'vars_post' => { 'username' => user, 'password' => pass }Self-registration → login
Section titled “Self-registration → login”For an application with public registration, create a new account and then log in. If the registration response contains no session cookie, keep_cookies is only needed for the login. Saved cookies are attached automatically to subsequent requests.
def authenticate return true if @authenticated
user = datastore['USERNAME'] pass = datastore['PASSWORD']
send_request_cgi( 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'register'), 'vars_post' => { 'username' => user, 'password' => pass } )
res = send_request_cgi( 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'login'), 'keep_cookies' => true, 'vars_post' => { 'username' => user, 'password' => pass } ) fail_with(Failure::NoAccess, 'login failed') if res.nil? fail_with(Failure::NoAccess, "login failed: HTTP #{res.code}") unless res.code == 200 || res.redirect?
@authenticated = true trueend- If the registration response includes
Set-Cookie, addkeep_cookiesto the registration POST as well. - Check the registration and login results using the response code or redirect destination.
- If CSRF is required, make a GET request first to obtain the token, as in the next section.
- When using AutoCheck, call this function at the entry points of
checkandexploit.@authenticatedprevents registration and login from repeating during the same run. See “Self-registration → login → JSON API RCE” in Exploit for an implementation example.
Reference modules: modules/exploits/unix/webapp/byob_unauth_rce.rb (separate register_user and login_user methods) and modules/exploits/linux/http/xplico_exec.rb.
Login with a CSRF token
Section titled “Login with a CSRF token”res = send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'users', 'sign_in'))fail_with(Failure::Unreachable, 'no response') if res.nil?
token = res.body[%r{name="authenticity_token" value="([^"]+)"}, 1]fail_with(Failure::UnexpectedReply, 'CSRF token missing') if token.blank?
res = send_request_cgi( 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'users', 'sign_in'), 'keep_cookies' => true, 'vars_post' => { 'authenticity_token' => token, 'user[login]' => datastore['USERNAME'], 'user[password]' => datastore['PASSWORD'], 'user[remember_me]' => '0' })Specify a cookie string directly
Section titled “Specify a cookie string directly”Fix the cookie for this request alone without using the jar.
res = send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'admin'), 'cookie' => "PHPSESSID=#{@phpsessid}; role=admin")For a request with cookie, the specified value takes precedence over automatic attachment from the jar for that request.
Build a cookie with HttpCookieJar
Section titled “Build a cookie with HttpCookieJar”cj = Msf::Exploit::Remote::HTTP::HttpCookieJar.newhost = datastore['RHOST']cj.add(Msf::Exploit::Remote::HTTP::HttpCookie.new('PHPSESSID', @phpsessid, domain: host, path: '/'))cj.add(Msf::Exploit::Remote::HTTP::HttpCookie.new('role', 'admin', domain: host, path: '/'))
send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'admin'), 'cookie' => cj)domain and path are required. Their values are Strings.
Clearing the cookie jar and handling expiration
Section titled “Clearing the cookie jar and handling expiration”cookie_jar.clear
send_request_cgi( 'method' => 'GET', 'uri' => '/', 'expire_cookies' => false)Call cookie_jar.clear before logging in as another account.
Classic pattern: extract Set-Cookie manually
Section titled “Classic pattern: extract Set-Cookie manually”res = send_request_cgi(...)cookie = res.get_cookiessend_request_cgi( 'method' => 'GET', 'uri' => '/next', 'cookie' => cookie)For new modules, keep_cookies is more concise.

