Update (12/May/2022) : I reported below observations to the PyScript team and they have confirmed that these are expected behavior. Since the emscripten filesystem is in the user’s browser memory itself, no harm in being able to list files, access files or write to arbitrary locations. Refer this issue.
Introduction
Vulnerabilities I found in PyScript.
Vulnerability 1: File System Browsing
Using the glob module which is part of Python Standard Library, the Emscripten
filesystem can be browsed.
Browsing ‘/’
import glob
glob.glob("/*")
Output:
['/tmp', '/home', '/dev', '/proc', '/lib']
Screenshot:
Browsing ‘/home’
PoC:
import glob
glob.glob("/home/*")
Output:
['/home/web_user', '/home/pyodide']
Screenshot:
Browsing ‘/lib’
PoC:
import glob
glob.glob("/lib/*")
Output:
['/lib/python3.10']
Screenshot:
Browsing ‘/lib/python3.10/’
PoC:
import glob
glob.glob("/lib/python3.10/*")
Output:
['/lib/python3.10/asyncio', '/lib/python3.10/collections', '/lib/python3.10/concurrent', '/lib/python3.10/ctypes', '/lib/python3.10/tzdata-2022.1.dist-info', '/lib/python3.10/email', '/lib/python3.10/encodings', '/lib/python3.10/html', '/lib/python3.10/http', '/lib/python3.10/importlib', '/lib/python3.10/json', '/lib/python3.10/logging', '/lib/python3.10/multiprocessing', '/lib/python3.10/pydoc_data', '/lib/python3.10/site-packages', '/lib/python3.10/sqlite3', '/lib/python3.10/tzdata', '/lib/python3.10/unittest', '/lib/python3.10/urllib', '/lib/python3.10/wsgiref', '/lib/python3.10/xml', '/lib/python3.10/xmlrpc', '/lib/python3.10/zoneinfo', '/lib/python3.10/__future__.py', '/lib/python3.10/__phello__.foo.py', '/lib/python3.10/_aix_support.py', '/lib/python3.10/_bootsubprocess.py', '/lib/python3.10/_collections_abc.py', '/lib/python3.10/_compat_pickle.py', '/lib/python3.10/_compression.py', '/lib/python3.10/_markupbase.py', '/lib/python3.10/_py_abc.py', '/lib/python3.10/_pydecimal.py', '/lib/python3.10/_pyio.py', '/lib/python3.10/_sitebuiltins.py', '/lib/python3.10/_strptime.py', '/lib/python3.10/_threading_local.py', '/lib/python3.10/_weakrefset.py', '/lib/python3.10/abc.py', '/lib/python3.10/aifc.py', '/lib/python3.10/antigravity.py', '/lib/python3.10/argparse.py', '/lib/python3.10/ast.py', '/lib/python3.10/asynchat.py', '/lib/python3.10/asyncore.py', '/lib/python3.10/base64.py', '/lib/python3.10/bdb.py', '/lib/python3.10/binhex.py', '/lib/python3.10/bisect.py', '/lib/python3.10/bz2.py', '/lib/python3.10/cProfile.py', '/lib/python3.10/calendar.py', '/lib/python3.10/cgi.py', '/lib/python3.10/cgitb.py', '/lib/python3.10/chunk.py', '/lib/python3.10/cmd.py', '/lib/python3.10/code.py', '/lib/python3.10/codecs.py', '/lib/python3.10/codeop.py', '/lib/python3.10/colorsys.py', '/lib/python3.10/compileall.py', '/lib/python3.10/configparser.py', '/lib/python3.10/contextlib.py', '/lib/python3.10/contextvars.py', '/lib/python3.10/copy.py', '/lib/python3.10/copyreg.py', '/lib/python3.10/crypt.py', '/lib/python3.10/csv.py', '/lib/python3.10/dataclasses.py', '/lib/python3.10/datetime.py', '/lib/python3.10/decimal.py', '/lib/python3.10/difflib.py', '/lib/python3.10/dis.py', '/lib/python3.10/doctest.py', '/lib/python3.10/enum.py', '/lib/python3.10/filecmp.py', '/lib/python3.10/fileinput.py', '/lib/python3.10/fnmatch.py', '/lib/python3.10/fractions.py', '/lib/python3.10/ftplib.py', '/lib/python3.10/functools.py', '/lib/python3.10/genericpath.py', '/lib/python3.10/getopt.py', '/lib/python3.10/getpass.py', '/lib/python3.10/gettext.py', '/lib/python3.10/glob.py', '/lib/python3.10/graphlib.py', '/lib/python3.10/gzip.py', '/lib/python3.10/hashlib.py', '/lib/python3.10/heapq.py', '/lib/python3.10/hmac.py', '/lib/python3.10/imaplib.py', '/lib/python3.10/imghdr.py', '/lib/python3.10/imp.py', '/lib/python3.10/inspect.py', '/lib/python3.10/io.py', '/lib/python3.10/ipaddress.py', '/lib/python3.10/keyword.py', '/lib/python3.10/linecache.py', '/lib/python3.10/locale.py', '/lib/python3.10/lzma.py', '/lib/python3.10/mailbox.py', '/lib/python3.10/mailcap.py', '/lib/python3.10/mimetypes.py', '/lib/python3.10/modulefinder.py', '/lib/python3.10/netrc.py', '/lib/python3.10/nntplib.py', '/lib/python3.10/ntpath.py', '/lib/python3.10/nturl2path.py', '/lib/python3.10/numbers.py', '/lib/python3.10/opcode.py', '/lib/python3.10/operator.py', '/lib/python3.10/optparse.py', '/lib/python3.10/os.py', '/lib/python3.10/pathlib.py', '/lib/python3.10/pdb.py', '/lib/python3.10/pickle.py', '/lib/python3.10/pickletools.py', '/lib/python3.10/pipes.py', '/lib/python3.10/pkgutil.py', '/lib/python3.10/platform.py', '/lib/python3.10/plistlib.py', '/lib/python3.10/poplib.py', '/lib/python3.10/posixpath.py', '/lib/python3.10/pprint.py', '/lib/python3.10/profile.py', '/lib/python3.10/pstats.py', '/lib/python3.10/pty.py', '/lib/python3.10/py_compile.py', '/lib/python3.10/pyclbr.py', '/lib/python3.10/pydoc.py', '/lib/python3.10/queue.py', '/lib/python3.10/quopri.py', '/lib/python3.10/random.py', '/lib/python3.10/re.py', '/lib/python3.10/reprlib.py', '/lib/python3.10/rlcompleter.py', '/lib/python3.10/runpy.py', '/lib/python3.10/sched.py', '/lib/python3.10/secrets.py', '/lib/python3.10/selectors.py', '/lib/python3.10/shelve.py', '/lib/python3.10/shlex.py', '/lib/python3.10/shutil.py', '/lib/python3.10/signal.py', '/lib/python3.10/site.py', '/lib/python3.10/smtpd.py', '/lib/python3.10/smtplib.py', '/lib/python3.10/sndhdr.py', '/lib/python3.10/socket.py', '/lib/python3.10/sre_parse.py', '/lib/python3.10/socketserver.py', '/lib/python3.10/sre_compile.py', '/lib/python3.10/sre_constants.py', '/lib/python3.10/ssl.py', '/lib/python3.10/stat.py', '/lib/python3.10/statistics.py', '/lib/python3.10/string.py', '/lib/python3.10/stringprep.py', '/lib/python3.10/struct.py', '/lib/python3.10/subprocess.py', '/lib/python3.10/sunau.py', '/lib/python3.10/symtable.py', '/lib/python3.10/sysconfig.py', '/lib/python3.10/tabnanny.py', '/lib/python3.10/tarfile.py', '/lib/python3.10/telnetlib.py', '/lib/python3.10/tempfile.py', '/lib/python3.10/textwrap.py', '/lib/python3.10/this.py', '/lib/python3.10/threading.py', '/lib/python3.10/timeit.py', '/lib/python3.10/token.py', '/lib/python3.10/tokenize.py', '/lib/python3.10/trace.py', '/lib/python3.10/traceback.py', '/lib/python3.10/tracemalloc.py', '/lib/python3.10/tty.py', '/lib/python3.10/types.py', '/lib/python3.10/typing.py', '/lib/python3.10/uu.py', '/lib/python3.10/uuid.py', '/lib/python3.10/warnings.py', '/lib/python3.10/wave.py', '/lib/python3.10/weakref.py', '/lib/python3.10/xdrlib.py', '/lib/python3.10/zipapp.py', '/lib/python3.10/zipfile.py', '/lib/python3.10/zipimport.py', '/lib/python3.10/LICENSE.txt', '/lib/python3.10/_sysconfigdata__emscripten_wasm32-emscripten.py', '/lib/python3.10/webbrowser.py', '/lib/python3.10/distutils']
Screenshot:
Browsing ‘/dev/’
PoC:
import glob
glob.glob("/dev/*")
Output:
['/dev/null', '/dev/tty', '/dev/tty1', '/dev/random', '/dev/urandom', '/dev/shm', '/dev/stdin', '/dev/stdout', '/dev/stderr']
Screenshot:
Vulnerability 2: Arbitrary File Creation
We can create and read arbitrary files in the Emscripten
filesystem directories.
Proof of Concept 1
PoC showing creating a file in /tmp
directory - /tmp/testfile
import glob
with open("/tmp/testfile.txt", "w") as f:
f.write("PoC Written By Rizal aka UB3RSiCK")
f.close()
glob.glob("/tmp/*")
Output:
['/tmp/testfile.txt']
Screenshot:
Proof of Concept 2
Create a file in /tmp/testfile.txt
with content PoC Written By Rizal aka UB3RSiCK
, verifies the file creation, reads the file content and displays within a div named “SampleElement”
<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>
<body>
<div id="SampleElement" class="font-mono"></div>
<py-script>
import glob
with open("/tmp/testfile.txt", "w") as f:
f.write("PoC Written By Rizal aka UB3RSiCK")
f.close()
glob.glob("/tmp/*")
content = ''.join(glob.glob("/tmp/*"))
with open("/tmp/testfile.txt", "r") as f:
content = content + " : " + f.read()
f.close()
pyscript.write("SampleElement", content)
</py-script> </body>
</html>
Output:
/tmp/testfile.txt : PoC Written By Rizal aka UB3RSiCK
Screenshot:
Proof of Concept 3
Creating a python module in /lib/python3.10
and executing arbitrary python code.
<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>
<body>
<div id="SampleElement" class="font-mono"></div>
<py-script>
import glob
with open("/lib/python3.10/rizalmodule.py", "w") as f:
f.write("print('Arbitrary Python Module Creation')")
f.close()
glob.glob("/lib/python3.10/rizalmodule.*")
</py-script> </body>
</html>
Output:
['/lib/python3.10/rizalmodule.py']
Screenshot:
Importing the created module to execute code within.
<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>
<body>
<div id="SampleElement" class="font-mono"></div>
<py-script>
import glob
with open("/lib/python3.10/rizalmodule.py", "w") as f:
f.write("print('Arbitrary Python Module Creation')")
f.close()
import rizalmodule
</py-script> </body>
</html>
Output:
Arbitrary Python Module Creation
Screenshot: