Login Scrip fails on Federated Authentication

Valentin's Avatar

Valentin

08 Apr, 2017 04:16 AM

Hi

I'm trying to create a login sctipt for the site http://dev-miu-rs.miutility.com/login which redirects to a federation server to perform the authentication but arachni fails to perform the redirection.

This is my login script

browser.goto 'http://dev-miu-rs.miutility.com/login'
browser.button(class: 'btn btn-primary' ).when_present.click
browser.input( id: 'userNameInput' ).wait_until_present( 30 )
browser.button( id: 'submitButton' ).wait_until_present( 30 )
#browser.text_field( id: 'userNameInput' ).set validusername'
browser.text_field( id: 'dsswordInput' ).set 'avalidpassword'
browser.button( id: 'submitButton' ).click

When I print the value of browser.url after the first button.click I still get the URL http://dev-miu-rs.miutility.com/login It looks like it is not able to follow the redirection.

Any idea?

  1. Support Staff 1 Posted by Tasos Laskos on 12 Apr, 2017 09:50 AM

    Tasos Laskos's Avatar

    I'm getting "Firefox can’t find the server at miutilityadfs.miutilityadfs.com." after clicking the button.

  2. 2 Posted by valentin.ortiz on 12 Apr, 2017 12:44 PM

    valentin.ortiz's Avatar

    Thanks for your reply Tasos

    Are you running that same script? Because what I get is:

     [] Initializing...
     [] Preparing plugins...
     [~] Login script: Running the script.
     [-] [utilities#exception_jail:428] Session: [Watir::Wait::TimeoutError] timed out after 30 seconds, waiting for {:id=>"userNameInput", :tag_name=>"input"} to become present
    
    I tried with arachni-1.5-0.5.11 and arachni-2.0dev-1.0dev
  3. Support Staff 3 Posted by Tasos Laskos on 12 Apr, 2017 12:47 PM

    Tasos Laskos's Avatar

    No, I visited it via Firefox, you're getting that error because the button doesn't work.
    I click on it and I get redirected to a domain that doesn't seem to exist.

  4. 4 Posted by valentin.ortiz on 12 Apr, 2017 01:14 PM

    valentin.ortiz's Avatar

    Hello Tasos

    That is weird, the domain exists and the button is working for me. When the button is clicked it redirects to something like this:
    https://miutilityadfs.miutilityadfs.com/adfs/oauth2/authorize?respo...

    Please take a look at the attachment. The button has a "strange" value though, but that's why I'm using the class instead of the value:

    <button _ngcontent-uqu-0="" class="btn btn-primary">
                                Sign In with Single Sign-On
                            </button>
    
  5. Support Staff 5 Posted by Tasos Laskos on 12 Apr, 2017 01:20 PM

    Tasos Laskos's Avatar
    $ ping miutilityadfs.miutilityadfs.com
    ping: unknown host miutilityadfs.miutilityadfs.com
    

    I tried it from my machine in Greece and servers in the US and the host could not be found from any of them.
    Are you running the scan from the same machine that you used to generate that screenshot?

  6. 6 Posted by valentin.ortiz on 12 Apr, 2017 01:27 PM

    valentin.ortiz's Avatar

    My bad, please excuse my short term memory and my low capacity of double checking things first =)

    You are right, the domain does not exist. You need to add this to your hosts file

    13.90.40.122  miutilityadfs.miutilityadfs.com
    
  7. Support Staff 7 Posted by Tasos Laskos on 12 Apr, 2017 01:39 PM

    Tasos Laskos's Avatar

    It could be that the hosts file isn't being respected.
    Can you try the following please inside a login script and show me the output?

    browser.goto 'http://miutilityadfs.miutilityadfs.com'
    puts browser.html
    puts '----'
    browser.goto 'http://13.90.40.122'
    puts browser.html
    
  8. 8 Posted by valentin.ortiz on 12 Apr, 2017 01:50 PM

    valentin.ortiz's Avatar

    Here is the output

     [*] Initializing...
     [*] Preparing plugins...
     [~] Login script: Running the script.
    <html><head><script src="http://javascript.browser.arachni/polyfills.js"></script> <!-- Injected by Arachni::Browser::Javascript -->
    <script src="http://javascript.browser.arachni/taint_tracer.js"></script> <!-- Injected by Arachni::Browser::Javascript -->
    <script src="http://javascript.browser.arachni/dom_monitor.js"></script> <!-- Injected by Arachni::Browser::Javascript -->
    <script>
    /* arachni_js_namespace_initialize_start */ _arachni_js_namespaceTaintTracer.initialize({}) /* arachni_js_namespace_initialize_stop */
    window._arachni_js_namespace = true;
    
    /* arachni_js_namespace_code_start */  /* arachni_js_namespace_code_stop */
    </script> <!-- Injected by Arachni::Browser::Javascript -->
    
    <title>Not Found</title>
    <meta http-equiv="Content-Type" content="text/html; charset=us-ascii"></head>
    <body><h2>Not Found</h2>
    <hr><p>HTTP Error 404. The requested resource is not found.</p>
    
    </body></html>
    ----
    <html><head><script src="http://javascript.browser.arachni/polyfills.js"></script> <!-- Injected by Arachni::Browser::Javascript -->
    <script src="http://javascript.browser.arachni/taint_tracer.js"></script> <!-- Injected by Arachni::Browser::Javascript -->
    <script src="http://javascript.browser.arachni/dom_monitor.js"></script> <!-- Injected by Arachni::Browser::Javascript -->
    <script>
    /* arachni_js_namespace_initialize_start */ _arachni_js_namespaceTaintTracer.initialize({}) /* arachni_js_namespace_initialize_stop */
    window._arachni_js_namespace = true;
    
    /* arachni_js_namespace_code_start */  /* arachni_js_namespace_code_stop */
    </script> <!-- Injected by Arachni::Browser::Javascript -->
    
    <title>Not Found</title>
    <meta http-equiv="Content-Type" content="text/html; charset=us-ascii"></head>
    <body><h2>Not Found</h2>
    <hr><p>HTTP Error 404. The requested resource is not found.</p>
    
    </body></html>
     [~] Login script: Execution completed.
     [+] Login script: Login was successful.
     [~] Login script: Cookies set to:
     [*] ... done.
     [*] BrowserCluster: Initializing 6 browsers...
    
  9. 9 Posted by valentin.ortiz on 12 Apr, 2017 02:07 PM

    valentin.ortiz's Avatar

    Hello
    I installed lynx to access the miutilityadfs.miutilityadfs.com site and I get this error regarding the certificate:

    SSL error:unable to get local issuer certificate-Continue? (y)
    
    But if I hit yes, the site loads
    JavaScript required


    JavaScript is required. This web browser does not support JavaScript or JavaScript in this web browser is not enabled.


    To find out if your web browser supports JavaScript or to enable JavaScript, see web browser help.


    MiUtility ADFS An error occurred An error occurred. Contact your administrator for more information. Error details * Activity ID: 00000000-0000-0000-1500-0080000000bb * Error time: Wed, 12 Apr 2017 14:05:35 GMT


    © 2016 Microsoft
    Do you think the certificate is causing problems with the login script?
  10. Support Staff 10 Posted by Tasos Laskos on 13 Apr, 2017 01:17 PM

    Tasos Laskos's Avatar

    My bad, I didn't see that it was a redirection to HTTPS, can you rerun the script I mentioned but use HTTPS?
    It shouldn't be an issue, but I'd like to make sure.

  11. 11 Posted by valentin.ortiz on 13 Apr, 2017 11:42 PM

    valentin.ortiz's Avatar

    Hello Tasos, thanks for your response

    It looks like it is working! I get the following:

     [+] Login script: Login was successful.
     [~] Login script: Cookies set to:
     [~] Login script:     * "MSISAuth" = "AAEAAK116weCS0b2QLr6NBkZAmW77Qa5BB8gHOr4H/lF/anccdSIbg1SHlHJjCDiNF3g6/d9AQHGhEC2rhQQS5Qgktmz0Utm4BqEtbwtpn2TWFU/Uh4WgmNy cVuNFSJ3ZXEt0BzCuFCgIU74JM7NzZnnQNdV3HUh8dezCSWemCyuqF2sB94ITvO8rgIoivnX5x9J9jyk8Wv42CspoOOQK1nxuDsgdKknJsasaJuRudw4Wxyq0RC9Yf4X1zgtwnbUHZJK6bP0ARIR4q12xfwc0MuLvaksQ/TlWVxF6CBmGzHyFq QRpkouwQJMOnJ5/lFKA2NxO kx6TFpg20IzpRR/vqp055wnpRSC3ieQmPLu2rV3/450DgaI8kPxz00TkEAkVKwABAAA l22YfQPJWfCjPE/yWy6ij76y0Pajhv28/zV/0QGl6e7AUUJQuNPnILEEVCOAa0xdnCDWM Mpkv35V1 xzHWvOVojFMxrNJnQDn/nPmAr8CgtDXG 8W0esVrvTqRXq1XsGm2DD X8gxtMzuhj658/F2UE8NrHSGiOVEPswnIHOUSqNVQMtulkX4GfgP10tnRw1/jwFUiWQEcUAVm5eXa9uraYJphWNJPh/nSV2QuxvM7vzNWs3bY0pZL959t96EchOIA6bIa9nvvckLu53v/S/IJU4t5MKTjpyOtpSJ8m RQPVbelq9WLv79vJ Cq3S7qf4ig 3TwDW8Mr5JeLJGAIAMAAD58SvIIDbp5Q3YN7PCDl1unGIrNIgIMyeXAn/GtZdns92gUrp1fBkVySIbzlGerCx1LwPma8 1hc2q5GVSbkdSpsMt4VCDDgivpsRnlBP0/gPjpxYIYN  PQKS1o8wY35adZQe gua2ruRdXi1lfC1ut oCIKYE9qzBHc2ZIgDa3BXLap1LmsoO5kcF5znhb0VuiieZMf2KlbF7uXq0ikmI76GPi9z8 OaHjt6ifiif6 g9JsOLiT4nFyf0lIP3Trpg8u0U6cGvWIPhodlZrTot5y3ygOXRWmf5DuPyumBy0Ehxn3Rd9I82ZQA/zW2SN133FgeUcGVfV/eaS7RWcy5ETwpR4lC0kdu/xTsQP7QUVeDxXz6rW 0WCoSmA 3xOvTFLjk2f765gHOuJha/klLxTRPirE6JjcmAl5by/yEmv3qLnzjjEwbMyCaf0tgtXzz713ztjSPxTVc4NK58T1JRj AJ8MwbryfNwN3pEbVkTWADfP7z cOcb5jV3apO/QnsC5yBTuuuhPrrbUKldw9EjO8b2jnZ9FZ/h70WKe kcdngcW9DoUU1hG9k2nLsaHUQt6b9wuX znPRf54J0JfZBuPVKApbyJvjAXuRXEp29AE6CzBoC2nJ2d53nd6JG1HEwmER2QHUImJ5IyBFxcz6vEWAK0jmwKsNpZCJ4Zjkd/ Us0kAko M6UX/weZ65fDkqyIhbXdQzj rfSFgyOtI1Go8d0XTCfCgPl1BLxKQ4qsWJyq6mTwvH1IZQgiciKXo3ddFfdidZy ywzIohxTd/l92g/lBM80E0bbaNy jNThpNnVEVk YH3Zl8toFTvFPrzPNWZprN ZdSIZOPzGrDW18uskkS3vlFPLOYLm39tpAVpdVuGYHIoSX6JVvdsS6kggMrrTBFtth CE/gJV2uzjJCg6XqYKrL/0weUy47Mgoh7P6v13ij9FY/nETLdX5EFakDK3srkpdxQ8yR3xLwCSq1yacfiUI3o2f5Tr2XyPEiJZP5aW55ljibWxblyQVIRj2e7 9Y27AICsI95tP11xqfAXtqvK8AFpHf8XF"
     [~] Login script:     * "MSISAuthenticated" = "NC8xMy8SDFGRDRTOjI4OjMxIFBN"
     [~] Login script:     * "MSISLoopDetectionCookie" = "AF345y0wNC0xMzoyMzoyODoyMFpcMg=="
     [~] Login script:     * "access_token" = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IjFPTmlzMU1lUHg5QXRfMlB6UjQ1WW1YN1ZqQSJ9.eyJhdWQiOiJodHRwOi8vd3d3Lm1pdXRpbGl0eS5jb20vZ2F0ZXdheSIsImlzcyI6Imh0dHBzOi8vbWl1dGlsaXR5ZGZzLmNvbS9hZGZzL3NlcnZpY2VzL3RydXN0IiwiaWF0IjoxNDkyMTI2MTExLCJleHAiOjE0OTIxMjk3MTEsInVuaXF1ZV9uYW1lIjoidnNoaW5kZSIsImFwcHR5cGUiOiJQdWJsaWMiLCJhcHBpZCI6IjAxNzRjNmE4LTI0YjAtNDc2MC05NWU4LWMwMjI0ZDczZjAwNiIsImF1dGhtZXRob2QiOiJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YWM6Y2xhc3NlczpQYXNzd29yZFByb3RlY3RlZFRyYW5zcG9ydCIsImF1dGhfdGltZSI6IjIwMTctMDQtMTNUMjM6Mjg6MTkuOTQ2WiIsInZlciI6IjEuMCJ9._Ca5YWp-FmZAmIla1IqWjn-MwmQ6Hub7qbZYXUaPGdWHA-PJyjx19iwzUagHc9ZHbG0zdmu0pMRIGgtR2mMITKDSE9fVW2jsEGDZo_A1682fRUp5VHPgfPuTHknqqDQEBOmbGpO-9hmoANhLapAe4DtYTgIH6ZYf9VBOQNg6OSfSlQGZFKvVroUzY-xRTqlwLDMN4irQyL3MXt0frp4nFONVmgZ83V3-yeBwCDIZsxp3F_DR3DtIkaILJxBIbcXv6_4UlojjPDg"
     [] ... done.
     [] BrowserCluster: Initializing 4 browsers...
     [] BrowserCluster: Spawned #1 with PID 18073 [lifeline at PID 18065].
     [] BrowserCluster: Spawned #2 with PID 18111 [lifeline at PID 18096].
     [] BrowserCluster: Spawned #3 with PID 18171 [lifeline at PID 18156].
     [] BrowserCluster: Spawned #4 with PID 18205 [lifeline at PID 18196].
     [*] BrowserCluster: Initialization completed with 4 browsers in the pool.
    

    But the authentication server instructs the client to redirect to a specific page and adds an input parameter, take a look at the response (specially the location value):

    HTTP/1.1 302 Found
    Cache-Control: no-cache,no-store
    Pragma: no-cache
    Content-Length: 0
    Content-Type: text/html; charset=utf-8
    Expires: -1
    Location: http://dev-miu-rs.miutility.com:80/#id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IjFPTmlzMU1lUHg5QXRfMlB6UjQ1WW1YN1ZqQSIsImtpZCI6IjFPTmlzMU1lUHg5QXRfMlB6UjQ1WW1YN1ZqQSJ9.eyJhdWQiOiIwMTc0YzZhOC0yNGIwLTQ3NjAtOTVlOC1jMDIyNGQ3M2YwMDYiLCJpc3MiOiJodHRwczovL21pdXRpbGl0eWFkZnMubWl1dGlsaXR5YWRmcy5jb20vYWRmcy9zZXJ2aWNlcy90cnVzdCIsImlhdCI6MTQ5MjEyNjIxMCwiZXhwIjoxNDkyMTI5ODEwLCJhdXRoX3RpbWUiOjE0OTIxMjYyMTAsIm5vbmNlIjoiMjMzNWY2NGQtZjRjNi00M2M1LThmYTQtZjJlMTMwY2MyYzkwIiwic3ViIjoiZG1QeHBzaWxpbEZPcys1OTFxVitNS1ZKZ1VuYzBuc01PSHdYUWgrZlhxND0iLCJ1cG4iOiJ2c2hpbmRlQG1pdXRpbGl0eWFkZnMuY29tIiwidW5pcXVlX25hbWUiOiJNSVVUSUxJVFlBREZTMFxcdnNoaW5kZSJ9.PQVif2fm8bZOm3ec5wCHQ45ga3UKw5h82cXzbErSlMyXm8cgv474uNrmljHa4Si9nNt3TFB97y8dLxE0TSjrHYHMumXNUAwU1Z72qpNev33pSCN1Eo1s6VlRqDsLTboOO1AwK2hGCNKuOPeC8t6c7ipMJZP91HyOeSk62SDFznkuX4JCFWFDDuK0QiJmhZhMh2ME7NJwNlCDTWloO5zu-1GnPd7gGX1kBkDOSkx-UxYqpPjuYBrPowSrRxyE2951jS7G--Crk7I5yei8_HnfUPxG9frc-M7f-YQ74wuY1HVohQ5KCMDsDWj0jBJ1Vmlz8KS4re_2wZ5ckhV9V935UQ&state=9a37fa10-af17-4d53-aed4-6de0b7d5b7e7
    Server: Microsoft-HTTPAPI/2.0
    P3P: ADFS doesn't have P3P policy, please contact your site's admin for more details
    Set-Cookie: MSISAuthenticated=NC8xMy8yMDE3IDExOjMwOjEwIFBN; path=/adfs; HttpOnly; Secure
    Set-Cookie: MSISLoopDetectionCookie=MjAxNy0wNC0xMzoyMzozMDoxMFpcMQ==; path=/adfs; HttpOnly; Secure
    

    How can I tell arachni to start the scan on that URL?
    The site uses Agular2 heavely. I'm using this command:

     arachni --checks - --plugin=login_script:script=login2.rb http://dev-miu-rs.miutility.com/miagent --session-check-url http://dev-miu-rs.miutility.com/miagent --session-check-pattern "miagent" --scope-exclude-pattern  'Sign Out' --scope-exclude-content-pattern 'Sign Out' --scope-exclude-pattern  'login' --scope-exclude-content-pattern 'login' --browser-cluster-pool-size='4' --browser-cluster-job-timeout='30'
    
  12. 12 Posted by valentin.ortiz on 14 Apr, 2017 02:00 AM

    valentin.ortiz's Avatar

    As an additional comment, the web page uses Angular2 and when click on the links it actually calls a different host running on port 8996

    GET https://dev-miu-rs.miutility.com:8996/signal-r/negotiate?clientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22signalrmessagehub%22%7D%5D&_=1492168966
    

    I put a sniffer and I never see traffic to that port, it seems that Arachni is not following those links. Any idea?

  13. Support Staff 13 Posted by Tasos Laskos on 14 Apr, 2017 11:09 AM

    Tasos Laskos's Avatar

    The exclude pattern won't work, it needs to match the logout URL not the link text.
    Also, you don't need to specify the --scope-exclude-content-pattern options.

    As for the redirect, is the id_token vital? What happens if you visit the target URL without it?

  14. 14 Posted by valentin.ortiz on 16 Apr, 2017 04:29 AM

    valentin.ortiz's Avatar

    Thanks Tasos

    I seems that oAuth needs that token passed in the url for the authentication to work. This is the final output, but I'm attaching the full output. What do you think?

     [~] Audited 2 page snapshots.
    
     [~] Duration: 00:09:08
     [~] Processed 216/216 HTTP requests.
     [~] -- 12.861 requests/second.
     [~] Processed 11/11 browser jobs.
     [~] -- 27.455 second/job.
    
     [~] Currently auditing          http://dev-miu-rs.miutility.com/login
     [~] Burst response time sum     5.796 seconds
     [~] Burst response count        178
     [~] Burst average response time 0.033 seconds
     [~] Burst average               0.0 requests/second
     [~] Timed-out requests          0
     [~] Original max concurrency    20
     [~] Throttled max concurrency   20
    
  15. Support Staff 15 Posted by Tasos Laskos on 21 Apr, 2017 11:08 AM

    Tasos Laskos's Avatar

    Try:

    b = Browser.new
    b.load response.headers.location
    framework.push_to_page_queue b.to_page
    
  16. 16 Posted by valentin.ortiz on 23 Apr, 2017 02:18 AM

    valentin.ortiz's Avatar

    Hello Tasos, thanks for your time I appreciate it

    Here is what I get:

     [-] [utilities#exception_jail:428] Session: [NameError] undefined local variable or method response&#39; for #&lt;Arachni::Plugins::LoginScript:0x007ff38c006888&gt;
     [-] [utilities#exception_jail:428] Session: /home/vortiz/downloads/nightlies/arachni-2.0dev-1.0dev/system/gems/bundler/gems/arachni-54570d52a697/components/plugins/login_script.rb:29:ineval'
     [-] [utilities#exception_jail:428] Session: /home/vortiz/downloads/nightlies/arachni-2.0dev-1.0dev/system/gems/bundler/gems/arachni-54570d52a697/components/plugins/login_script.rb:29:in eval&#39;
     [-] [utilities#exception_jail:428] Session: /home/vortiz/downloads/nightlies/arachni-2.0dev-1.0dev/system/gems/bundler/gems/arachni-54570d52a697/components/plugins/login_script.rb:29:inblock in prepare'
    
    I have the feeling that I missing something obvious here.... but I couldn't figure out what it is.

    I'm attaching the full output.

  17. Support Staff 17 Posted by Tasos Laskos on 23 Apr, 2017 01:30 PM

    Tasos Laskos's Avatar

    My bad, I got confused, use browser.url instead of response.headers.location.
    browser.url should be the redirect location, right?

    Place that at the end of the login script.

  18. 18 Posted by valentin.ortiz on 24 Apr, 2017 02:43 AM

    valentin.ortiz's Avatar

    Hi Tasos

    It looks like that did the trick, your are the master!.
    here is the command:

     arachni --checks - --plugin=login_script:script=login5.rb --browser-cluster-pool-size='4' --browser-cluster-job-timeout='60' --session-check-url=http://dev-miu-rs.miutility.com/miagent --session-check-pattern=miagent http://dev-miu-rs.miutility.com/miagent/launch-pad
    
    This is the script
    browser.goto 'http://dev-miu-rs.miutility.com/login'
    browser.button(class: 'btn btn-primary' ).when_present.click
    browser.text_field( id: 'userNameInput' ).set 'validuser'
    browser.text_field( id: 'passwordInput' ).set 'validpassword'
    browser.span( id:'submitButton' ).wait_until_present(30)
    browser.span( id:'submitButton' ).fire_event('click')
    puts browser.url
    b = Browser.new
    b.load browser.url
    puts browser.html
    framework.push_to_page_queue b.to_page
    
    When I print the browser.html I get the main page:
    <html class="dir-ltr miutility-portal-apps k-safari k-safari538" dir="ltr" data-root="/"><head><script src="http://javascript.browser.arachni/polyfills.js"></script> <!-- Injected by Arachni::Browser::Javascript -->
    <script src="http://javascript.browser.arachni/taint_tracer.js"></script> <!-- Injected by Arachni::Browser::Javascript -->
    <script src="http://javascript.browser.arachni/dom_monitor.js"></script> <!-- Injected by Arachni::Browser::Javascript -->
    <script>
    /* arachni_js_namespace_initialize_start */ _arachni_js_namespaceTaintTracer.initialize({}) /* arachni_js_namespace_initialize_stop */
    window._arachni_js_namespace = true;
    
    /* arachni_js_namespace_code_start */  /* arachni_js_namespace_code_stop */
    </script> <!-- Injected by Arachni::Browser::Javascript -->
    
    
    
    
        <title>Home Page - MiUtility</title>
    
        <base href="/">
    
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    ...
    ...
    

    The problem I have now is that arachni only audits 2 pages. Do you think it is related to a missing parameter or something like that?

    I'm attaching the full output.

  19. Support Staff 19 Posted by Tasos Laskos on 29 Apr, 2017 11:17 AM

    Tasos Laskos's Avatar

    Looks like the page hasn't finished loading, is it populated via AJAX calls?

  20. 20 Posted by valentin.ortiz on 01 May, 2017 05:03 AM

    valentin.ortiz's Avatar

    Yes, it also uses Angular2 to get data from another server:
    https://dev-miu-rs.miutility.com:8996

    Same hostname but different port.

    I'm attaching a screenshot...

  21. Support Staff 21 Posted by Tasos Laskos on 01 May, 2017 08:13 AM

    Tasos Laskos's Avatar

    This option may be the last piece of the puzzle: https://github.com/Arachni/arachni/wiki/Command-line-user-interface...

  22. Tasos Laskos closed this discussion on 11 Jun, 2017 10:37 AM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac