Case Study: Interspire and PayPal Express. Case: Interspire and PayPal Express Interspire is an...

Post on 31-Dec-2015

219 views 0 download

Transcript of Case Study: Interspire and PayPal Express. Case: Interspire and PayPal Express Interspire is an...

Case Study: Interspire and PayPal Express

2

Case: Interspire and PayPal Express

• Interspire is an eCommerce merchant software• Can be integrated with PayPal Express to collect

the payments• Need to maintain state of a transaction between

3 parties: the Attacker, the Merchant, and PayPal• Logic flaw allows the attacker to purchase an

order at a reduced price• Refer to Section III. B 1) in How to Shop For Free

Online for the complete description of this case

3

The Flaw

• Attacker can use a session with a successful payment status on a different order than it was intended for

• Allows attacker to complete an expensive order using the payment intended for a cheaper order

4

Discovering the Flaw

• Presented by Wang et al. in How to Shop for Free Online: Security Analysis of Cashier-as-a-Service Based Web Stores

• Used a manual code review method– Identify all API parameters the attacker can access– Test how parameters affect the internal state

5

Identify the API Parameters

• API parameters (method arguments) can be signed or unsigned

• Unsigned arguments: – Sent in cleartext

• Signed arguments:– Sender uses a digital signature to sign the

argument– Provides data integrity

6

Manipulating the API Parameters

• Attackers can manipulate data sent from the client side

• Test manipulating the arguments one at a time, then trace through the rest of the checkout process– See how each individual arguments affects the

internal state of the transaction, and the end result

7

Modifying Unsigned Arguments

• Change the value manually– store.com/checkout?price=5

• Leave the argument value empty– store.com/checkout?price=

• Remove the argument completely– store.com/checkout

8

Modifying Signed Arguments

• Replace a signed argument from one session with the same signed argument from a second session– Session 1:

• store.com/updateOrder?orderID=(SIGNED1)&sessionID=1

– Session 2: • store.com/updateOrder?orderID=(SIGNED2)&sessionID=2

– Replace orderID in session 1 with orderID from session 2: • store.com/updateOrder?orderID=(SIGNED2)&sessionID=1

9

Modifying Signed Arguments

• Leave the signed argument value empty– store.com/updateOrder?orderID=&sessionID=1

• Remove the signed argument completely– store.com/updateOrder?sessionID=1

• Reuse a signed argument from a completed transaction in a new transaction– Replay attack

10

Modifying the Workflow

• Try skipping steps of the transaction– Skip one step, then run the rest of the transaction– Skip multiple steps, then run the rest of the

transaction• Try running the steps out of order• Do these manipulations with expected

argument values• Then, do these workflow manipulations with

manipulated unsigned and signed arguments

11

Interspire and PayPal Express API Parameters

• Price (Total cost of items in the cart)• (ORDERID) (Signed Order object)• SessionID (Temporary session number)• PayerID (Like a userID)• PayPalExpress (Cashier being used)• Result (sent from PayPal to Interspire)• StoreID (sent to PayPal from Interspire)• Token (sent from PayPal to Interspire)

12

Notation Used in the Animation

• If a parameter is unsigned, it is represented with lower case words. For example:– price– sessionID

• If a parameter is signed, it is represented with all uppercase words inside parenthesis. For example:– (ORDERID)

• Parameter values are not shown– price – instead of price=5

13

The Attacker

• Parameters sent by the Attacker, or ones the Attacker could modify, are in red text

• API Methods accessible by the attacker are in black text

14

The Merchant

• Parameters sent by the Merchant are in blue text

• Code run by the Merchant is in blue text• Public API Methods (attacker accessible):– Store_checkout(Price,PayPalExpress)– Store_ finishOrder(TokenID, PayerID, SessionID); – Store_updateOrderStatus(OrderID, SessionID);

15

PayPal Express

• Parameters sent by PayPal Express is in green text

• Code run by PayPal Express is in green text• Public API Methods (attacker accessible):– PayPal_pay(token, payerID);

16

Interspire and PayPal Checkout Transaction Overview

• Step 1: Attacker adds items to their cart• Step 2: Attacker clicks on ‘Checkout’• Step 2a: The Store contacts PayPal and gets a token• Step 3: The Attacker is redirected PayPal for payment• Step 4: The Attacker is redirected to the Store to finish

the order• Step 4a: The Store contacts PayPal to check if payment

was made• Step 5: The Attacker is redirected to another Store

page to complete the order

17

Checkout Transaction Overview

1. Attacker adds cheap items to cart

2. store.com/checkout?price&PayPalExpress2a. PayPal.com/setExpressCheckout?StoreID

tokenRedirect to : PayPal.com/pay?token&payerID

3. PayPal.com/pay?token&payerID

Redirect to: store.com/finishOrder?token&payerID&sessionID

4. store.com/finishOrder?token&payerID&sessionID

4a. PayPal.com/doExpressPayment?StoreID&payerID

result

Redirect to: store.com/updateOrderStatus?(ORDERID)&sessionID

5. store.com/updateOrderStatus?(ORDERID)&sessionID

Transaction Completed

18

Translation between Case Study and How to Shop for Free

Case Study Figure 7 in How to Shop for Free article

2. store.com/checkout?price&PayPalExpress RT1.a: TStore.com/placeOrder

2a. PayPal.com/setExpressCheckout?StoreID RT1.a.a: CaaS.com/SetExpCheckout?identityT&…

token RT1.a.b: tokenC

Redirect to : PayPal.com/pay?token&payerID RT1.b: redir to CaaS.com/pay?tokenC

3. PayPal.com/pay?token&payerID RT2.a: CaaS.com/pay?tokenA

Redirect to: store.com/finishOrder?token&payerID&sessionID

RT2.b: redir to TStore.com/finishOrder?tokenC&payerIDC

4. store.com/finishOrder?token&payerID&sessionID RT3.a: TStore.com/finishOrder?tokenA&payerIDA

4a. PayPal.com/doExpressPayment?StoreID&payerID RT3.a.a: CaaS.com/DoExpPay?identityT&tokenC&grossT

result RT3.a.b: resultC

Redirect to: store.com/updateOrderStatus?(ORDERID)&sessionID

RT3.b: redir to TStore.com/updateOrderStatus?orderIDT*

5. store.com/updateOrderStatus?(ORDERID)&sessionID RT4.a: Store.com/updateOrderStatus?orderIDT*

Transaction Completed RT4.b: Purchase done

19

Interspire and PayPal Express Flaw

• The following slides show how the logic flaw when Interspire used PayPal Express to collect payment can be exploited

• The HTTP interactions will be shown, followed by the manual code review

• A table tracks the internal state of the variables through each transaction step

20

The Animation

Each step of the transaction includes:1. Description of the step2. Sequence diagram to show which two parties

are communicating, and includes:– The API method called– The last party who could modified unsigned

parameters

3. The backend code for that API method– Pseudocode is based on C

21

1. Create Cheap Order (First Session)

• On the merchant website, the Attacker adds cheap items to their cart

22

1. Create Cheap Order (First Session)

Attacker adds cheap items to cart

23

myCustomer = myPrice = mySessionID = myTokenID = (ORDERID) =

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ ] = carts[ ] = payments[ ] =

price = price =payerID =recipientID =paymentAmount =paymentType =orderID =

tokens[ ] = tokens[ ] =

recipientID = payerID =

recipientID = payerID =

orders[ ] = orders[ ] =

orderID =price =status =paymentType =

orderID =price =status =paymentType =

currentOrderID = 0currentPaymentID = 0currentSessionID = 0currentTokenID = 0customer = AttackerExpResults[ ] = ExpResults[ ] =

Program Variables

Attacker Variables

1. Create Cheap Order

myPrice = 5;

mySessionID = 0;

myCustomer = Attacker;

Attacker 5 0

24

2. Checkout Cheap Order

• On the merchant website, the Attacker clicks the checkout button

• On the merchants’ server side, a cart object is created– Is linked to the sessionID

25

2. Checkout Cheap Order

Attacker adds cheap items to cart

store.com/checkout?price&PayPalExpress

26

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ ] = carts[ ] = payments[ ] =

price = price =payerID =recipientID =paymentAmount =paymentType =orderID =

tokens[ ] = tokens[ ] =

recipientID = payerID =

recipientID = payerID =

orders[ ] = orders[ ] =

orderID =price =status =paymentType =

orderID =price =status =paymentType =

currentOrderID = 0currentPaymentID = 0currentSessionID = 0currentTokenID = 0customer = AttackerExpResults[ ] = ExpResults[ ] =

2. Checkout Cheap Order

createCart(myPrice)carts[currentSessionID].price = myPrice;

ExpResults[currentSessionID] = Pay_NotHappened;

currentSessionID++;

0

0

1

5

Pay_NotHappened

Store_checkout(myPrice,PayPalExpress)

Program Variables

Attacker VariablesmyCustomer = Attacker myPrice = 5 mySessionID = 0 myTokenID = (ORDERID) =

27

2.a During Checkout: Store Gets PayPal Token

• On the merchants’ server side, a call is made to PayPal Express API method to request a token for the transaction

• A token is returned to the merchants’ server• The Attacker does not have access to this

communication; it is directly between the merchant and PayPal Express

28

Attacker adds cheap items to cart

store.com/checkout?price&PayPalExpressPayPal.com/setExpressCheckout?StoreID

token

2.a During Checkout: Store Gets PayPal Token

29

Session 1 Session 2 Payment and other Variables

carts[ 0 ] = carts[ ] = payments[ ] =

price = 5 price =payerID =recipientID =paymentAmount =paymentType =orderID =

tokens[ ] = tokens[ ] =

recipientID = payerID =

recipientID = payerID =

orders[ ] = orders[ ] =

orderID =price =status =paymentType =

orderID =price =status =paymentType =

currentOrderID = 0currentPaymentID = 0currentSessionID = 1currentTokenID = 0customer = AttackerExpResults[ 0 ] = Pay_NotHappened ExpResults[ ] =

2.a During Checkout: Store Gets PayPal Token

PayPal_setExpressCheckout(StoreID);

tokens[currentTokenID].payer = Not Set;tokens[currentTokenID].recipientID = StoreID;

currentTokenID++;

StoreID 0

Not Set

1

//payer not valid yet

Program Variables

Attacker VariablesmyCustomer = Attacker myPrice = 5 mySessionID = 0 myTokenID = (ORDERID) =

30

3. Store Redirects to PayPal. Attacker Makes Payment

• The merchant redirects the Attacker to PayPal Express to make a payment– Attacker does pay for the order

• The token received from PayPal Express in step 2.a is included as a parameter in this new page request

31

Attacker adds cheap items to cart

store.com/checkout?price&PayPalExpressPayPal.com/setExpressCheckout?StoreID

tokenRedirect to : PayPal.com/pay?token&payerID

PayPal.com/pay?token&payerID

3. Store Redirects to PayPal. Attacker Makes Payment

32

myCustomer = Attacker myPrice = 5 mySessionID = 0 myTokenID = (ORDERID) =

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ 0 ] = carts[ ] = payments[ ] =

price = 5 price =payerID =recipientID =paymentAmount =paymentType =orderID =

tokens[ 0 ] = tokens[ ] =

recipientID = StoreID payerID = Not_Set

recipientID = payerID =

orders[ ] = orders[ ] =

orderID =price =status =paymentType =

orderID =price =status =paymentType =

currentOrderID = 0currentPaymentID = 0currentSessionID = 1currentTokenID = 1customer = AttackerExpResults[ 0 ] = Pay_NotHappened ExpResults[ ] =

3. Attacker Makes Payment on PayPal

PayPal_Pay(myTokenID, myCustomer);

tokens[myTokenID].payerID = myCustomer;if (myTokenID < 0 || myTokenID >= currentTokenID) return; //if invalid tokenID

Program Variables

Attacker Variables

Attacker

0

33

4. PayPal Redirects to Store. Store Creates Order

• After payment is made, PayPal Express redirects the Attacker back to the merchant to continue the checkout process

• The merchant creates an order object on the server – The payment status of the order is set to pending– Price is retrieved from cart stored on the server,

not from an API parameter– Is not linked to the sessionID

34

Attacker adds cheap items to cart

store.com/checkout?price&PayPalExpressPayPal.com/setExpressCheckout?StoreID

tokenRedirect: PayPal.com/pay?token&payerID

PayPal.com/pay?token&payerID

store.com/finishOrder?token&payerID&sessionID

4. PayPal Redirects to Store. Store Creates Order

Redirect to: store.com/finishOrder?token&payerID&sessionID

35

myCustomer = Attacker myPrice = 5 mySessionID = 0 myTokenID = 0 (ORDERID) =

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ 0 ] = carts[ ] = payments[ ] =

price = 5 price =payerID =recipientID =paymentAmount =paymentType =orderID =

tokens[ 0 ] = tokens[ ] =

recipientID = StoreID payerID = Attacker

recipientID = payerID =

orders[ ] = orders[ ] =

orderID =price =status =paymentType =

orderID =price =status =paymentType =

currentOrderID = 0currentPaymentID = 0currentSessionID = 1currentTokenID = 1customer = Attacker

ExpResults[ 0 ] = Pay_NotHappened ExpResults[ ] =

4. Store Creates OrderStore_finishOrder(myTokenID, myCustomer, mySessionID);

orderID = createOrder( carts[mySessionID].price, PENDING, PayPalExpress);if (mySessionID < 0 || mySessionID >= currentSessionID) return; //if invalid sessionID

Program Variables

Attacker Variables

orderID =

orders[currentOrderID].orderID = currentOrderID;orders[currentOrderID].price = carts[mySessionID].price;orders[currentOrderID].status = PENDING;orders[currentOrderID].paymentType = PayPalExpresscurrentOrderID++;return currentOrderID-1;

0

05PENDING

PayPalExpress

1 0

36

4.a Store Checks if Payment was Made

• The merchant asks PayPal Express if payment was made

• PayPal Express records the payment on their server• PayPal Express returns the result of payment– Payment Suceeded– Is linked to the sessionID

• The merchant digitally signs an orderID with information about the order, whether or not payment suceeded

37

Attacker adds cheap items to cart

store.com/checkout?price&PayPalExpressPayPal.com/setExpressCheckout?StoreID

tokenRedirect to : PayPal.com/pay?token&payerID

PayPal.com/pay?token&payerID

PayPal.com/doExpressPayment?StoreID&payerID

result

4.a Store Checks if Payment was Made

store.com/finishOrder?token&payerID&sessionID

Redirect to: store.com/finishOrder?token&payerID&sessionID

38

myCustomer = Attacker myPrice = 5 mySessionID = 0 myTokenID = 0 (ORDERID) =

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ 0 ] = carts[ ] = payments[ ] =

price = 5 price =payerID =recipientID =paymentAmount =paymentType =orderID =

tokens[ 0 ] = tokens[ ] =

recipientID = StoreID payerID = Attacker

recipientID = payerID =

orders[ 0 ] = orders[ ] =

orderID = 0price = 5status = PENDINGpaymentType = PayPalExpress

orderID =price =status =paymentType =

currentOrderID = 1currentPaymentID = 0currentSessionID = 0currentTokenID = 1customer = Attacker

orderID = 0

ExpResults[ 0 ] = Pay_NotHappened ExpResults[ ] =

4.a Store Checks if Payment was Made

Program Variables

Attacker Variables

ExpResults[mySessionID] = PayPal_doExpressPayment(myCustomer, StoreID, myTokenID, orderID, carts[mySessionID].price);

if (myTokenID < 0 || myTokenID >= currentTokenID) return Pay_Failed; //if tokenID invalidif (tokens[myTokenID].payerID == Not_Set) return Pay_Failed; //if payer not confirmed

if (tokens[myTokenID].payerID != myCustomer) return Pay_Failed; //if payer not the customer

if (tokens[myTokenID].recipientID != StoreID) return Pay_Failed; //if recipient not the store

recordPayment(myCustomer, StoreID, PayPalExpress, carts[mySessionID].price, orderID);

39

myCustomer = Attacker myPrice = 5 mySessionID = 0 myTokenID = 0 (ORDERID) =

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ 0 ] = carts[ ] = payments[ ] =

price = 5 price =payerID =recipientID =paymentAmount =paymentType =orderID =

tokens[ 0 ] = tokens[ ] =

recipientID = StoreID payerID = Attacker

recipientID = payerID =

orders[ 0 ] = orders[ ] =

orderID = 0price = 5status = PENDINGpaymentType = PayPalExpress

orderID =price =status =paymentType =

currentOrderID = 1currentPaymentID = 0currentSessionID = 1currentTokenID = 1customer = Attacker

orderID = 0

ExpResults[ 0 ] = Pay_NotHappened ExpResults[ ] =

4.a Store Checks if Payment was Made

Program Variables

Attacker Variables

recordPayment(myCustomer, StoreID, PayPalExpress, carts[mySessionID].price, orderID);payments[currentPaymentID].payerID = myCustomer;payments[currentPaymentID].recipientID = StoreID;

payments[currentPaymentID].paymentType = PayPalExpress;payments[currentPaymentID].paymentAmount = carts[mySessionID].price;

payments[currentPaymentID].orderID = orderID;currentPaymentID++;

return Pay_Succeeded;

0

AttackerStoreID

5PayPalExpress

0

1

Pay_Succeeded

sign(orderID);

40

5. Store Redirects to Update Order Status

• After checking payment status with PayPal Express, the merchant redirects the Attacker to a final merchant page to complete the transaction– Signed (ORDERID) is included as a parameter

• Attacker stops this page from loading

41

store.com/updateOrderStatus?(ORDERID)=0&sessionID=0

Attacker adds cheap items to cart

store.com/checkout?price&PayPalExpressPayPal.com/setExpressCheckout?StoreID

tokenRedirect to : PayPal.com/pay?token&payerID

PayPal.com/pay?token&payerID

PayPal.com/doExpressPayment?StoreID&payerID

result

store.com/finishOrder?token&payerID&sessionID

Redirect to: store.com/finishOrder?token&payerID&sessionID

Attacker stops the redirect from loading (can intercept with a proxy to do this)

Attacker now has session from cheap order stored with successful payment

results

Redirect to: store.com/updateOrderStatus?(ORDERID)=0&sessionID=0

5. Store Redirects to Update Order Status

42

myCustomer = Attacker myPrice = 5 mySessionID = 0 myTokenID = 0 (ORDERID) =

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ 0 ] = carts[ ] = payments[ 0 ] =

price = 5 price =payerID = AttackerrecipientID = StoreIDpaymentAmount = 5paymentType = PayPalExpressorderID = 0

tokens[ 0 ] = tokens[ ] =

recipientID = StoreID payerID = Attacker

recipientID = payerID =

orders[ 0 ] = orders[ ] =

orderID = 0price = 5status = PENDINGpaymentType = PayPalExpress

orderID =price =status =paymentType =

currentOrderID = 1currentPaymentID = 1currentSessionID = 1currentTokenID = 1customer = Attacker

orderID = 0

ExpResults[ 0 ] = Pay_Succeeded ExpResults[ ] =

Program Variables

Attacker Variables

5. Store Redirects to Update Order Status Store_UpdateOrderStatus((ORDERID), mySessionID);

Attacker stops the redirect from loading (can intercept with a proxy to do this)

Attacker now has session from cheap order stored with successful payment results

0

43

6. Create Expensive Order (Second Session)

• In a new tab or second browser, the Attacker starts a second order

• Expensive items are added to the cart

44

Attacker adds cheap items to cart

store.com/checkout?price&PayPalExpressPayPal.com/setExpressCheckout?StoreID

tokenRedirect to : PayPal.com/pay?token&payerID

PayPal.com/pay?token&payerID

PayPal.com/doExpressPayment?StoreID&payerID

result

store.com/finishOrder?token&payerID&sessionID

Redirect to: store.com/finishOrder?token&payerID&sessionID

Attacker stops the redirect from loading (can intercept with a proxy to do this)

Attacker now has session from cheap order stored with successful payment

results

Redirect to: store.com/updateOrderStatus?(ORDERID)=0&sessionID=0

store.com/updateOrderStatus?(ORDERID)=0&sessionID=0

Attacker adds Expensive items to cart

6. Create Expensive Order (Second Session)

Attacker creates a second session in a new tab or second browser

45

myCustomer = Attacker myPrice = 5 mySessionID = 0 myTokenID = 0 (ORDERID) = 0

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ 0 ] = carts[ ] = payments[ 0 ] =

price = 5 price =payerID = AttackerrecipientID = StoreIDpaymentAmount = 5paymentType = PayPalExpressorderID = 0

tokens[ 0 ] = tokens[ ] =

recipientID = StoreID payerID = Attacker

recipientID = payerID =

orders[ 0 ] = orders[ ] =

orderID = 0price = 5status = PENDINGpaymentType = PayPalExpress

orderID =price =status =paymentType =

currentOrderID = 1currentPaymentID = 1currentSessionID = 1currentTokenID = 1customer = Attacker ExpResults[ 0 ] = Pay_Succeeded ExpResults[ ] =

Program Variables

Attacker Variables

6. Create Expensive OrdermyPrice = 200;

mySessionID = 1;

200 1

46

7. Checkout Expensive Order

• On the merchant website, the Attacker clicks the checkout button

• On the merchants’ server side, a cart object is created– Is linked to the sessionID

47

store.com/checkout?price&PayPalExpress

store.com/updateOrderStatus?(ORDERID)=0&sessionID=0

Attacker adds Expensive items to cart

7. Checkout Expensive Order

48

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ 0 ] = carts[ ] = payments[ 0 ] =

price = 5 price =payerID = AttackerrecipientID = StoreIDpaymentAmount = 5paymentType = PayPalExpressorderID = 0

tokens[ 0 ] = tokens[ ] =

recipientID = StoreID payerID = Attacker

recipientID = payerID =

orders[ 0 ] = orders[ ] =

orderID = 0price = 5status = PENDINGpaymentType = PayPalExpress

orderID =price =status =paymentType =

currentOrderID = 1currentPaymentID = 1currentSessionID = 1currentTokenID = 1customer = Attacker ExpResults[ 0 ] = Pay_Succeeded ExpResults[ ] =

Program Variables

Attacker Variables

7. Checkout Expensive Order

createCart(myPrice)carts[currentSessionID].price = myPrice;

ExpResults[currentSessionID] = Pay_NotHappened;

currentSessionID++;

Store_checkout(myPrice,PayPalExpress)

1

200

Pay_NotHappened1

2

myCustomer = Attacker myPrice = 200 mySessionID = 1 myTokenID = 0 (ORDERID) = 0

49

7.a During Checkout: Store Gets PayPal Token

• On the merchants’ server side, a call is made to PayPal Express API method to request a token for the transaction

• A token is returned to the merchants’ server• The Attacker does not have access to this

communication; it is directly between the merchant and PayPal Express

50

store.com/checkout?price&PayPalExpressPayPal.com/setExpressCheckout?StoreID

token

store.com/updateOrderStatus?(ORDERID)=0&sessionID=0

Attacker adds Expensive items to cart

7.a During Checkout: Store Gets PayPal Token

51

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ 0 ] = carts[ 1 ] = payments[ 0 ] =

price = 5 price = 200payerID = AttackerrecipientID = StoreIDpaymentAmount = 5paymentType = PayPalExpressorderID = 0

tokens[ 0 ] = tokens[ ] =

recipientID = StoreID payerID = Attacker

recipientID = payerID =

orders[ 0 ] = orders[ ] =

orderID = 0price = 5status = PENDINGpaymentType = PayPalExpress

orderID =price =status =paymentType =

currentOrderID = 1currentPaymentID = 1currentSessionID = 1currentTokenID = 1customer = Attacker ExpResults[ 0 ] = Pay_Succeeded ExpResults[ 1 ] = Pay_NotHappened

myCustomer = Attacker myPrice = 200 mySessionID = 1 myTokenID = 0 (ORDERID) = 0

Program Variables

Attacker Variables

PayPal_setExpressCheckout(StoreID);

tokens[currentTokenID].payer = Not Set;tokens[currentTokenID].recipientID = StoreID;

currentTokenID++;

StoreID 1

Not Set

2

//payer not valid yet

7.a During Checkout: Store Gets PayPal Token

52

8. Store Redirects to PayPal. Attacker Skips Payment

• The merchant redirects the Attacker to PayPal Express to make a payment– Attacker does not pay for the order

• The token received from PayPal Express in step 2.a is included as a parameter in this new page request

53

store.com/checkout?price&PayPalExpressPayPal.com/setExpressCheckout?StoreID

tokenRedirect to : PayPal.com/pay?token&payerID

PayPal.com/pay?token&payerID

store.com/updateOrderStatus?(ORDERID)=0&sessionID=0

Attacker adds Expensive items to cart

8. Store Redirects to PayPal. Attacker Skips Payment

Attacker skips payment

54

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ 0 ] = carts[ 1 ] = payments[ 0 ] =

price = 5 price = 200payerID = AttackerrecipientID = StoreIDpaymentAmount = 5paymentType = PayPalExpressorderID = 0

tokens[ 0 ] = tokens[ ] =

recipientID = StoreID payerID = Attacker

recipientID = payerID =

orders[ 0 ] = orders[ ] =

orderID = 0price = 5status = PENDINGpaymentType = PayPalExpress

orderID =price =status =paymentType =

currentOrderID = 1currentPaymentID = 1currentSessionID = 1currentTokenID = 1customer = Attacker ExpResults[ 0 ] = Pay_Succeeded ExpResults[ 1 ] = Pay_NotHappened

myCustomer = Attacker myPrice = 200 mySessionID = 1 myTokenID = 0 (ORDERID) = 0

Program Variables

Attacker Variables

StoreID 1

Not Set

2

1

8. Store Redirects to PayPal. Attacker Skips PaymentPayPal_Pay(myTokenID, myCustomer);

Attacker skips payment

55

9. PayPal Redirects to Store. Store Still Creates Order

• Payment is not made, but PayPal Express still redirects the Attacker back to the merchant to continue the checkout process

• The merchant creates an order object on the server – The payment status of the order is set to pending– Price is retrieved from cart stored on the server,

not from an API parameter– Is not linked to the sessionID

56

store.com/checkout?price&PayPalExpressPayPal.com/setExpressCheckout?StoreID

tokenRedirect to : PayPal.com/pay?token&payerID

PayPal.com/pay?token&payerID

store.com/finishOrder?token&payerID&sessionID

Redirect to: store.com/finishOrder?token&payerID&sessionID

store.com/updateOrderStatus?(ORDERID)=0&sessionID=0

Attacker adds Expensive items to cart

9. PayPal Redirects to Store. Store Still Creates Order

57

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ 0 ] = carts[ 1 ] = payments[ 0 ] =

price = 5 price = 200payerID = AttackerrecipientID = StoreIDpaymentAmount = 5paymentType = PayPalExpressorderID = 0

tokens[ 0 ] = tokens[ 1 ] =

recipientID = StoreID payerID = Attacker

recipientID = StoreIDpayerID = Not_Set

orders[ 0 ] = orders[ ] =

orderID = 0price = 5status = PENDINGpaymentType = PayPalExpress

orderID =price =status =paymentType =

currentOrderID = 1currentPaymentID = 1currentSessionID = 1currentTokenID = 2customer = Attacker ExpResults[ 0 ] = Pay_Succeeded ExpResults[ 1 ] = Pay_NotHappened

myCustomer = Attacker myPrice = 200 mySessionID = 1 myTokenID = 1 (ORDERID) = 0

Program Variables

Attacker Variables

9. Store Creates OrderStore_finishOrder(myTokenID, myCustomer, mySessionID);

orderID = createOrder( carts[mySessionID].price, PENDING, PayPalExpress);if (mySessionID < 0 || mySessionID >= currentSessionID) return; //if invalid sessionID

orders[currentOrderID].orderID = currentOrderID;orders[currentOrderID].price = carts[mySessionID].price;orders[currentOrderID].status = PENDING;orders[currentOrderID].paymentType = PayPalExpresscurrentOrderID++;return currentOrderID-1;

orderID = 1

1200

PENDINGPayPalExpress

12

58

9.a Store Checks if Payment was Made

• The merchant asks PayPal Express if payment was made

• PayPal Express records the payment on their server• PayPal Express returns the result of payment– Payment Failed– Is linked to the sessionID

• The merchant digitally signs an orderID with information about the order, whether or not payment suceeded

59

store.com/checkout?price&PayPalExpressPayPal.com/setExpressCheckout?StoreID

tokenRedirect to : PayPal.com/pay?token&payerID

PayPal.com/pay?token&payerID

PayPal.com/doExpressPayment?StoreID&payerIDresult (payment failed)

store.com/finishOrder?token&payerID&sessionID

Redirect to: store.com/finishOrder?token&payerID&sessionID

store.com/updateOrderStatus?(ORDERID)=0&sessionID=0

Attacker adds Expensive items to cart

9.a Store Checks if Payment was Made

60

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ 0 ] = carts[ 1 ] = payments[ 0 ] =

price = 5 price = 200payerID = AttackerrecipientID = StoreIDpaymentAmount = 5paymentType = PayPalExpressorderID = 0

tokens[ 0 ] = tokens[ 1 ] =

recipientID = StoreID payerID = Attacker

recipientID = StoreIDpayerID = Not_Set

orders[ 0 ] = orders[ 1 ] =

orderID = 0price = 5status = PENDINGpaymentType = PayPalExpress

orderID = 1price = 200status = PENDINGpaymentType = PayPal_Express

currentOrderID = 2currentPaymentID = 1currentSessionID = 1currentTokenID = 2customer = Attacker

orderID = 1

ExpResults[ 0 ] = Pay_Succeeded ExpResults[ 1 ] = Pay_NotHappened

myCustomer = Attacker myPrice = 200 mySessionID = 1 myTokenID = 1 (ORDERID) = 0

Program Variables

Attacker Variables

9.a Store Checks if Payment was MadeExpResults[mySessionID] = PayPal_DoExpressPayment(myCustomer, StoreID, myTokenID, orderID,

carts[mySessionID].price);

if (myTokenID < 0 || myTokenID >= currentTokenID) return Pay_Failed; //if tokenID invalidif (tokens[myTokenID].payerID == Not_Set) return Pay_Failed; //payer not confirmed

Pay_Failed

sign(orderID);

61

10. Store Redirects to Update Order Status

• After checking payment status with PayPal Express, the merchant redirects the Attacker to a final merchant page to complete the transaction– Signed (ORDERID) is included as a parameter

• Order not completed because payment failed\– Attacker still has access to the signed (ORDERID)

parameter

62

store.com/checkout?price&PayPalExpressPayPal.com/setExpressCheckout?StoreID

tokenRedirect to : PayPal.com/pay?token&payerID

PayPal.com/pay?token&payerID

PayPal.com/doExpressPayment?StoreID&payerIDresult (payment failed)

store.com/finishOrder?token&payerID&sessionID

Redirect to: store.com/finishOrder?token&payerID&sessionID

Redirect to: store.com/updateOrderStatus?(ORDERID)=1&sessionID=1

store.com/updateOrderStatus?(ORDERID)=0&sessionID=0

Attacker adds Expensive items to cart

10. Store Redirects to Update Order Status

store.com/updateOrderStatus?(ORDERID)=1&sessionID=1

Attacker still gets signed (ORDERID) with information about the expensive order

Order not filled because payment verification failed

63

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ 0 ] = carts[ 1 ] = payments[ 0 ] =

price = 5 price = 200payerID = AttackerrecipientID = StoreIDpaymentAmount = 5paymentType = PayPalExpressorderID = 0

tokens[ 0 ] = tokens[ 1 ] =

recipientID = StoreID payerID = Attacker

recipientID = StoreIDpayerID = Not_Set

orders[ 0 ] = orders[ 1 ] =

orderID = 0price = 5status = PENDINGpaymentType = PayPalExpress

orderID = 1price = 200status = PENDINGpaymentType = PayPal_Express

currentOrderID = 2currentPaymentID = 1currentSessionID = 1currentTokenID = 2customer = Attacker

orderID = 1

ExpResults[ 0 ] = Pay_Succeeded ExpResults[ 1 ] = Pay_Failed

myCustomer = Attacker myPrice = 200 mySessionID = 1 myTokenID = 1 (ORDERID) = 0

Program Variables

Attacker Variables

Store_UpdateOrderStatus((ORDERID), mySessionID);if (mySessionID < 0 || mySessionID >= currentSessionID) return; //if sessionID is invalidif ((ORDERID) < 0 || (ORDERID) >= currentOrderID) return; //if orderID is invalidif (orders[(ORDERID)].paymentType != PayPalExpress) return; //if payment not from PayPalExpif (ExpResults[mySessionID] == Pay_NotHappened) return; //if payment not startedif (ExpResults[mySessionID] == Pay_Failed) return;

//Payment failed

1

10. Store Redirects to Update Order Status

64

11. Attacker Updates First Session with Second ORDERID

• Attacker returns to the first session from step 5, which was paused at the last step of the checkout process

• The signed (SESSIONID) from step 5 is replaced with the signed (SESSIONID) from step 10

• The first session is resumed– Payment status is based on sessionID from cheap order,

order information is based on signed (SESSIONID) from expensive order

– Expensive order completed sucessfully

65

store.com/checkout?price&PayPalExpressPayPal.com/setExpressCheckout?StoreID

tokenRedirect to : PayPal.com/pay?token&payerID

PayPal.com/pay?token&payerID

PayPal.com/doExpressPayment?StoreID&payerIDresult (payment failed)

store.com/finishOrder?token&payerID&sessionID

Redirect to: store.com/finishOrder?token&payerID&sessionID

Redirect to: store.com/updateOrderStatus?(ORDERID)=1&sessionID=1

store.com/updateOrderStatus?(ORDERID)=0&sessionID=0

Attacker adds Expensive items to cart

store.com/updateOrderStatus?(ORDERID)=1&sessionID=1

11. Attacker Updates First Session with Second ORDERID

Attacker returns to first session with stored successful payment result, where they stopped

the final webpage from loading

Attacker replaces the first signed ORDERID with the second signed ORDERID by copying and

pasting the value in the URL

Attacker loads the webpage

store.com/updateOrderStatus? (ORDERID)=0&sessionID=0

(ORDERID)=1

Expensive Purchase Completed

66

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ 0 ] = carts[ 1 ] = payments[ 0 ] =

price = 5 price = 200payerID = AttackerrecipientID = StoreIDpaymentAmount = 5paymentType = PayPalExpressorderID = 0

tokens[ 0 ] = tokens[ 1 ] =

recipientID = StoreID payerID = Attacker

recipientID = StoreIDpayerID = Not_Set

orders[ 0 ] = orders[ 1 ] =

orderID = 0price = 5status = PENDINGpaymentType = PayPalExpress

orderID = 1price = 200status = PENDINGpaymentType = PayPal_Express

currentOrderID = 2currentPaymentID = 1currentSessionID = 1currentTokenID = 2customer = Attacker

orderID = 1

ExpResults[ 0 ] = Pay_Succeeded ExpResults[ 1 ] = Pay_Failed

myCustomer = Attacker myPrice = 200 mySessionID = 1 myTokenID = 1 (ORDERID) = 1

Program Variables

Attacker Variables

mySessionID = 0;

0

11. Attacker Updates 1st Session with 2nd ORDERID

67

Session 1 (Cheap Order) Session 2 (Expensive Order) Payment and other Variables

carts[ 0 ] = carts[ 1 ] = payments[ 0 ] =

price = 5 price = 200payerID = AttackerrecipientID = StoreIDpaymentAmount = 5paymentType = PayPalExpressorderID = 0

tokens[ 0 ] = tokens[ 1 ] =

recipientID = StoreID payerID = Attacker

recipientID = StoreIDpayerID = Not_Set

orders[ 0 ] = orders[ 1 ] =

orderID = 0price = 5status = PENDINGpaymentType = PayPalExpress

orderID = 1price = 200status = PENDINGpaymentType = PayPal_Express

currentOrderID = 2currentPaymentID = 1currentSessionID = 1currentTokenID = 2customer = Attacker

orderID = 1

ExpResults[ 0 ] = Pay_Succeeded ExpResults[ 1 ] = Pay_Failed

myCustomer = Attacker myPrice = 200 mySessionID = 0 myTokenID = 1 (ORDERID) = 1

Program Variables

Attacker Variables

Store_UpdateOrderStatus((ORDERID), mySessionID);if (mySessionID < 0 || mySessionID >= currentSessionID) return; //if sessionID is invalidif ((ORDERID) < 0 || (ORDERID) >= currentOrderID) return; //if orderID is invalidif (orders[(ORDERID)].paymentType != PayPalExpress) return; //if payment not from PayPalExpif (ExpResults[mySessionID] == Pay_NotHappened) return; //if payment not startedif (ExpResults[mySessionID] == Pay_Failed) return; orders[(ORDERID)].status = PAID;

//if payment failed

ExpResults[mySessionID] = Pay_NotHappened; //Clear the payment result

PAID

Pay_NotHappened

11. Attacker Updates 1st Session with 2nd ORDERID

Why Does This Work?

69

What Interspire Did Right

• Steps 2 & 7– Sets payment status for session as not paid

• Steps 4 & 9– Verified sessionID value– Price retrieved from a cart object stored on the server side, not

from the unsigned price parameter in the URL• This is why only the (ORDERID) parameter needs to be signed

• Steps 4.a & 9.a– Verified with PayPal that payment was made, using price stored

in cart on server side, not from the unsigned price parameter in the URL

– Result parameter from PayPal is never seen by the user

70

What Interspire Did Right

• Step 11– Verified sessionID value– Verified (ORDERID)– Verified payment was attempted– Verified payment did not fail– Session payment status was cleared after order

updated to PAID• Prevents replay attacks

71

What PayPal Did Right

• Steps 2.a and 7.a– In token returned to Store, payerID set to “not set”

• Step 3– Verified tokenID

• Steps 4.a & 9.a– Verified tokenID– Verified payerID was set– Verified the payer is same as the customer on the Store

website• Prevent an attacker stealing a customers active session

72

What Interspire Did Wrong

• Steps 9.a & 10– If payment verification from PayPal shows the

payment failed in step 9.a, the Store still creates a signed ORDERID

• Step 11– (ORDERID) not associated with a sessionID– Doesn’t verify payment amount made to PayPal is

the same amount as the price stored in the order

73

Fixing the Logic Flaw

• Connect the orderID and sessionID:• In step 4 and 9, can add another field in the

Order object to store the sessionID• In step 10, compare the users’ sessionID to

orders[(ORDERID)].sessionID– If they don’t match, return

74

Fixing the Logic Flaw

• Verify the payment amount with the price of the order:

• The PayPal Express API method DoExpressPayment in steps 4.a and 9.a also returns the payment amount*

• A second field could be added to the Expected Results object, to store the payment amount along with the payment status in steps 4.a and 9.a

• In step 10 compare orders[(ORDERID)].price to ExpResults[mySessionID].paymentAmount– If they don’t match, return*https://developer.paypal.com/docs/classic/api/merchant/

DoExpressCheckoutPayment_API_Operation_NVP/

75

Fixing the Logic Flaw

• Don’t provide a correct signed (ORDERID) variable if payment failed:

• In steps 4.a and 9.a, if the payment status returned from PayPal_DoExpressPayment is Pay_Failed – Don’t send the (ORDERID) parameter when calling

UpdateOrderStatus in step 10• Modify the UpdateOrderStatus method to accept a null value

– Set the ORDERID to an invalid number, and still sign it• UpdateOrderStatus method already checks for invalid values

76

ResourcesR. Wang, S. Chen, X. Wang, S. Qadeer, "How to Shop for Free Online: Security Analysis of Cashier-as-a-Service Based Web Stores," in 2011 IEEE Symposium on Security and Privacy (SP), 22-25 May 2011, Berkeley, CA, pp. 465-480. [Online]. Available: IEEE Xplore, doi: 10.1109/SP.2011.26