├── .gitmodules ├── AUTHORS ├── CHANGELOG ├── LICENSE ├── Makefile ├── README.md ├── VERSION ├── build └── .gitignore ├── dependencies.txt ├── include ├── .gitignore ├── conntrack.h ├── forgery.h ├── shambles.h └── util.h ├── lib └── .gitignore ├── samples ├── .gitignore ├── hookscripts │ ├── .gitignore │ ├── Makefile │ ├── build │ │ └── .gitignore │ ├── hook.py │ ├── hook.rb │ ├── include │ │ ├── .gitignore │ │ └── hookffi.h │ ├── lib │ │ └── .gitignore │ └── src │ │ ├── .gitignore │ │ └── hookffi.cc ├── scan │ ├── .gitignore │ ├── Makefile │ ├── build │ │ └── .gitignore │ ├── include │ │ └── .gitignore │ └── src │ │ ├── .gitignore │ │ └── scan.cc └── shambles │ ├── .gitignore │ ├── Makefile │ ├── build │ └── .gitignore │ ├── include │ ├── .gitignore │ └── util.h │ ├── nat.sh │ ├── setup_libuv.sh │ ├── src │ ├── .gitignore │ ├── main.cc │ └── util.cc │ └── vendor │ └── .gitignore ├── src ├── .gitignore ├── forgery.cc ├── shambles.cc ├── shambles_intercept.cc └── util.cc └── vendor └── .gitignore /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/forge_socket"] 2 | path = vendor/forge_socket 3 | url = https://github.com/ewust/forge_socket.git 4 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Creators: 2 | --------- 3 | - Jeff Dileo 4 | 5 | 6 | Maintainers: 7 | ------------ 8 | - Jeff Dileo 9 | 10 | 11 | Contributors: 12 | ------------- 13 | 14 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 2015.09.22, Version 1.0.0 (Stable) 2 | 3 | This is the first officially versioned release of libshambles. Features include 4 | interception of established TCP connection over IPv4 and a sample suite of 5 | tools to perform basic connection hooking based on regular expressions searches 6 | within individual TCP packet data sections. 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 NCC Group 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 | SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXX=clang++ 2 | CXXFLAGS=-std=c++14 -stdlib=libc++ -Wall -Wextra -pedantic -fPIC -fPIE -fstack-protector-strong -D_FORTIFY_SOURCE=2 3 | SANITIZE=-fsanitize=address,undefined 4 | DEBUG=-g -DDEBUG 5 | OPTIMIZE=-O2 6 | INCS=-I include -I vendor -I vendor/forge_socket 7 | LINK=-Wl,-z,relro,-z,now,-z,noexecstack 8 | OUTPUT=-shared -o lib/libshambles.so 9 | 10 | 11 | default: build/shambles.o build/shambles_intercept.o build/forgery.o build/util.o 12 | ${CXX} ${CXXFLAGS} ${OPTIMIZE} ${LINK} ${OUTPUT} ${INCS} build/shambles.o build/shambles_intercept.o build/forgery.o build/util.o 13 | ar rcs lib/libshambles.a build/shambles.o build/shambles_intercept.o build/forgery.o build/util.o 14 | 15 | debug: build/shambles.o build/shambles_intercept.o build/forgery.o build/util.o 16 | ${CXX} ${CXXFLAGS} ${DEBUG} ${SANITIZE} ${LINK} ${OUTPUT} ${INCS} build/shambles.o build/shambles_intercept.o build/forgery.o build/util.o 17 | ar rcs lib/libshambles.a build/shambles.o build/shambles_intercept.o build/forgery.o build/util.o 18 | 19 | vdebug: build/shambles.o build/shambles_intercept.o build/forgery.o build/util.o 20 | ${CXX} ${CXXFLAGS} ${DEBUG} ${LINK} ${OUTPUT} ${INCS} build/shambles.o build/shambles_intercept.o build/forgery.o build/util.o 21 | ar rcs lib/libshambles.a build/shambles.o build/shambles_intercept.o build/forgery.o build/util.o 22 | 23 | build/shambles.o: src/shambles.cc 24 | ${CXX} ${CXXFLAGS} ${INCS} -o build/shambles.o -c src/shambles.cc 25 | 26 | build/shambles_intercept.o: src/shambles_intercept.cc 27 | ${CXX} ${CXXFLAGS} ${INCS} -o build/shambles_intercept.o -c src/shambles_intercept.cc 28 | 29 | build/forgery.o: src/forgery.cc 30 | ${CXX} ${CXXFLAGS} ${INCS} -o build/forgery.o -c src/forgery.cc 31 | 32 | build/util.o: src/util.cc 33 | ${CXX} ${CXXFLAGS} ${INCS} -o build/util.o -c src/util.cc 34 | 35 | clean: 36 | rm lib/libshambles.so lib/libshambles.a build/*.o 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | libshambles is a TCP interception library that hooks established TCP streams 4 | and provides `send(2)`/`recv(2)`-able socket interfaces to communicate with the 5 | connection's peers. It was primarily developed to intercept highly dynamic 6 | network protocols at scale. 7 | 8 | libshambles is designed to be minimal and allow the use of privilege 9 | minimization and separation, and sandboxing techniques and technologies. Once 10 | passed sufficient information about a TCP stream to intercept, libshambles will 11 | generate sockets with forged TCP state data so as to trick the kernel into 12 | recognizing the stream's packets as ones intended for it. It then modifies the 13 | firewall and connection tracking state to cleanly split the client-to-server 14 | connection into two separate ones, client-to-interceptor and 15 | interceptor-to-server. It additionally contains code to pass the sockets to 16 | other processes via Unix domain sockets and also contains teardown 17 | functionality to undo the firewall modifications once the intercepted 18 | connection is finished. 19 | 20 | libshambles is written in C++ (compiled as C++14), but provides C bindings for 21 | its public API. It is released under a two-clause BSD license. 22 | 23 | For more information, see my 24 | [blog post](https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2015/october/libshambles) 25 | introducing libshambles and the rationale behind it. 26 | 27 | # Quickstart 28 | 29 | As libshambles is a library and also needs to be supplied accurate TCP/IP 30 | connection information (e.g. IP addresses, ports, SEQ/ACK numbers), the 31 | libshambles codebase is highly limited. However, this repository contains a 32 | sample toolchain leveraging libshambles, which consists of a libpcap daemon, an 33 | interceptor using 34 | libshambles, and Python/Ruby scripts wrapping a native (C++14) file descriptor 35 | accepting daemon. These tools are provided in the `samples` directory. You'll 36 | probably want to run the following across three separate terminal sessions: 37 | 38 | ## WARNING 39 | 40 | The `scan` and `shambles` daemons currently communicate over an unauthenticated 41 | plaintext connection (IPv4/TCP). You should be careful not to expose the 42 | `shambles` listener to the local network. Also be careful with respect to 43 | anything on the host running it, as they would be able to abuse its 44 | functionality. 45 | 46 | #### Compile and load the `forge_socket` kernel module, load the `nf_conntrack_ipv4` module, and build libshambles: 47 | ```bash 48 | $ git clone https://github.com/iSECPartners/libshambles 49 | $ git submodule init 50 | $ git submodule update 51 | $ cd vendor/forge_socket 52 | $ make 53 | $ sudo insmod forge_socket.ko 54 | $ sudo modprobe nf_conntrack_ipv4 55 | $ cd ../../ 56 | $ make 57 | ``` 58 | 59 | #### Setup libuv, and compile and run the `shambles` daemon: 60 | ```bash 61 | $ cd /path/to/libshambles 62 | $ cd samples/shambles 63 | $ sh setup_libuv.sh 64 | $ make 65 | $ mkdir /tmp/shambles 66 | $ sudo ./nat.sh [blacklist network] 67 | $ sudo ./shambles /tmp/shambles/shambles_sock 68 | ``` 69 | 70 | #### Compile and run the `scan` daemon: 71 | ```bash 72 | $ cd /path/to/libshambles 73 | $ cd samples/scan 74 | $ make 75 | $ sudo ./scan '' '' 76 | ``` 77 | 78 | #### Compile the `hookffi` shared library, and use Python to hook stuff: 79 | ```bash 80 | $ cd /path/to/libshambles 81 | $ cd samples/hookffi 82 | $ make 83 | $ nano hook.py # add in whatever you want to the custom_hook function 84 | $ python hook.py /tmp/shambles_sock root 85 | ``` 86 | If Ruby is more your thing than Python, edit the `custom_hook` method in 87 | `hook.rb` instead and run: 88 | 89 | ```bash 90 | $ ruby hook.rb /tmp/shambles_sock root 91 | ``` 92 | 93 | Next, make a plaintext TCP connection from a host behind the one running the 94 | sample tools (and out to a remote host) that will match both the bpf filter and 95 | search regex passed to the `scan` daemon. Observe that your code will hook the 96 | connection and read and write to both the local client and remote host. 97 | 98 | 99 | # Dependencies 100 | libshambles itself has a couple of dependencies and the samples depend on 101 | various other projects like libpcap and libuv. Additionally, as I developed 102 | libshambles on Ubuntu 14.04, it relies on Clang and libc++ for modern C++ 103 | support needed to compile and run it. 104 | 105 | On Ubuntu 14.04, the below `apt-get` one-liner should get you most of the way 106 | there. 107 | ```bash 108 | $ sudo apt-get install build-essential git libpcap-dev libmnl-dev libcap-dev libc++-dev libc++abi1 libc++1 libtool automake autotools-dev 109 | ``` 110 | You'll also need to grab Clang from the LLVM 111 | [releases page](http://llvm.org/releases/download.html). I usually 112 | extract it out to `/opt/clangllvm` on my machine and then prepend that to my 113 | `$PATH`, but do as you like. 114 | 115 | Other dependencies are covered in the above quickstart instructions. 116 | 117 | # Versioning 118 | libshambles uses semantic versioned tag branches. In general, this means that 119 | the version format is `major.minor.patch`, where major version updates include 120 | backwards compatibility changes (and/or other major changes), minor version 121 | updates include new features that don't break the API and possibly 122 | deprecations, and patch version updates fix bugs. Please note that depending on 123 | the bugs fixed, it may be necessary to increment the minor or even major 124 | version number. Any such instances will be clearly marked should they occur by 125 | a clear note in the `CHANGELOG` file. For now, and likely the foreseeable 126 | future, I intend only to fix bugs in the current `major.minor` branch. For 127 | example, should a `1.2.0` release come out following `1.1.8`, there will not be 128 | a `1.1.9` release containing backported fixes for the `1.1.x` branch. 129 | 130 | # Future Work 131 | - IPv6 132 | - this will likely require setting up DNAT/SNAT in both directions due to 133 | the lack of NAT in IPv6 (in IPv4+NAT it is only needed for the inner 134 | host) 135 | 136 | - FreeBSD support: 137 | - port forge_socket to FreeBSD 138 | - implement analogous connection tracking stuff (e.g. equivalents for 139 | netfilter conntrack functionality) 140 | - convert firewall rules 141 | - likely support IPFW, FreeBSD's pf is more limited for these things 142 | 143 | - Unit tests 144 | 145 | - Integration with highly advanced PCAP daemons 146 | (e.g. [Net Sensor](https://isis.poly.edu/~bk/netsensor/)) 147 | 148 | - Detection/Anti-Detection research 149 | - Profile TCP for options differences 150 | - Perform better TCP state forgery to eliminate obvious differences 151 | - Profile connections for midstream implementation differences (e.g. why 152 | did the host/client stop speaking TCP like X and why is it now speaking 153 | TCP like Linux?) 154 | - Research mitigations 155 | 156 | - (Wishful thinking) Modifying the DPDK/netmap TCP engines to perform similar 157 | functionality 158 | 159 | 160 | # Contributing & Bug Reporting 161 | 162 | Feel free to send pull requests or even just add an issue if you spot a bug (or 163 | would like to make a feature request). If you happen to find any security 164 | issues, please contact me directly at `jeff.dileo@nccgroup.trust` (my PGP key is 165 | available [here](https://isecpartners.github.io/keys/jdileo.asc)) instead of 166 | filing an issue. 167 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.0.0 2 | -------------------------------------------------------------------------------- /build/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | *.o 3 | -------------------------------------------------------------------------------- /dependencies.txt: -------------------------------------------------------------------------------- 1 | - https://github.com/ewust/forge_socket.git (see vendor/) 2 | - sudo apt-get install build-essential git libpcap-dev libmnl-dev libcap-dev libc++-dev libc++abi1 libc++1 libtool automake autotools-dev 3 | - clang (preferably 3.5+ for proper c++14 support, either via apt-get or the http://llvm.org/releases/download.html site) 4 | - libuv (for the `shambles` sample which includes a script to build locally w/ sufficient options) 5 | -------------------------------------------------------------------------------- /include/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | -------------------------------------------------------------------------------- /include/conntrack.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 NCC Group 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef LIBSHAMBLES_CONNTRACK_H_ 28 | #define LIBSHAMBLES_CONNTRACK_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | 38 | #include 39 | 40 | struct ConntrackOption { }; 41 | struct ConntrackInjectOption : ConntrackOption { }; 42 | struct ConntrackDeleteOption : ConntrackOption { }; 43 | struct ConntrackWatOption : ConntrackOption { }; 44 | 45 | struct Conntrack { 46 | using Inject = ConntrackInjectOption; 47 | using Delete = ConntrackDeleteOption; 48 | using Wat = ConntrackWatOption; 49 | }; 50 | 51 | const uint32_t timeout = htonl(120); 52 | const size_t mnl_socket_buffer_size = MNL_SOCKET_BUFFER_SIZE; 53 | 54 | // ip addresses are struct in_addr (aka uint32_t in network byte order) 55 | // ports are in network byte order 56 | // typename = std::enable_if::value, T> 57 | 58 | template< 59 | typename T, 60 | typename = std::enable_if_t::value> 61 | > 62 | int32_t conntrack_ipv4_tcp(uint32_t orig_src_addr, uint32_t orig_dst_addr, 63 | uint16_t orig_src_port, uint16_t orig_dst_port, 64 | uint32_t repl_src_addr, uint32_t repl_dst_addr, 65 | uint16_t repl_src_port, uint16_t repl_dst_port) { 66 | static_assert( 67 | std::is_same::value 68 | || std::is_same::value, 69 | "calls to conntrack_ipv4_tcp must use an Inject or Delete parameter"); 70 | 71 | struct mnl_socket *sock; 72 | struct nlmsghdr *hdr; 73 | struct nfgenmsg *gmsg; 74 | 75 | char* buf = (char*)alloca(mnl_socket_buffer_size); 76 | memset(buf, 0, mnl_socket_buffer_size); 77 | 78 | sock = mnl_socket_open(NETLINK_NETFILTER); 79 | if (sock == NULL) { 80 | perror("mnl_socket_open"); 81 | return -1; 82 | } 83 | 84 | if (mnl_socket_bind(sock, 0, MNL_SOCKET_AUTOPID) < 0) { 85 | perror("mnl_socket_bind"); 86 | return -2; 87 | } 88 | 89 | uint32_t portid = mnl_socket_get_portid(sock); 90 | 91 | hdr = mnl_nlmsg_put_header(buf); 92 | 93 | if (std::is_same::value) { 94 | hdr->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) 95 | | 0 /*IPCTNL_MSG_CT_NEW*/; 96 | hdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; 97 | } else if (std::is_same::value) { 98 | hdr->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) 99 | | 2 /*IPCTNL_MSG_CT_DELETE*/; 100 | hdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; 101 | } 102 | 103 | uint32_t seq = time(0); 104 | hdr->nlmsg_seq = seq; 105 | 106 | gmsg = static_cast( 107 | mnl_nlmsg_put_extra_header(hdr, sizeof(struct nfgenmsg)) 108 | ); 109 | gmsg->nfgen_family = AF_INET; 110 | gmsg->version = NFNETLINK_V0; 111 | gmsg->res_id = 0; 112 | 113 | { 114 | struct nlattr *nest = mnl_attr_nest_start(hdr, 1 /*CTA_TUPLE_ORIG*/); 115 | if (nest == nullptr) { 116 | perror("mnl_attr_nest_start:nfct_build_tuple"); 117 | return -3; 118 | } 119 | 120 | { 121 | struct nlattr *nest = mnl_attr_nest_start(hdr, 1 /*CTA_TUPLE_IP*/); 122 | if (nest == nullptr) { 123 | perror("mnl_attr_nest_start:CTA_TUPLE_IP"); 124 | return -4; 125 | } 126 | mnl_attr_put_u32(hdr, 1 /*CTA_IP_V4_SRC*/, orig_src_addr); 127 | mnl_attr_put_u32(hdr, 2 /*CTA_IP_V4_DST*/, orig_dst_addr); 128 | mnl_attr_nest_end(hdr, nest); 129 | } 130 | 131 | { 132 | struct nlattr *nest = mnl_attr_nest_start(hdr, 2 /*CTA_TUPLE_PROTO*/); 133 | if (nest == nullptr) { 134 | perror("mnl_attr_nest_start:CTA_TUPLE_PROTO"); 135 | return -5; 136 | } 137 | 138 | mnl_attr_put_u8( hdr, 1 /*CTA_PROTO_NUM*/, IPPROTO_TCP); 139 | mnl_attr_put_u16(hdr, 2 /*CTA_PROTO_SRC_PORT*/, orig_src_port); 140 | mnl_attr_put_u16(hdr, 3 /*CTA_PROTO_DST_PORT*/, orig_dst_port); 141 | 142 | mnl_attr_nest_end(hdr, nest); 143 | } 144 | 145 | mnl_attr_nest_end(hdr, nest); 146 | } 147 | 148 | { 149 | 150 | struct nlattr *nest = mnl_attr_nest_start(hdr, 2 /*CTA_TUPLE_REPLY*/); 151 | if (nest == nullptr) { 152 | perror("mnl_attr_nest_start:nfct_build_tuple"); 153 | return -6; 154 | } 155 | 156 | { 157 | struct nlattr *nest = mnl_attr_nest_start(hdr, 1 /*CTA_TUPLE_IP*/); 158 | if (nest == nullptr) { 159 | perror("mnl_attr_nest_start:CTA_TUPLE_IP"); 160 | return -7; 161 | } 162 | mnl_attr_put_u32(hdr, 1 /*CTA_IP_V4_SRC*/, repl_src_addr); 163 | mnl_attr_put_u32(hdr, 2 /*CTA_IP_V4_DST*/, repl_dst_addr); 164 | mnl_attr_nest_end(hdr, nest); 165 | } 166 | 167 | { 168 | struct nlattr *nest = mnl_attr_nest_start(hdr, 2 /*CTA_TUPLE_PROTO*/); 169 | if (nest == nullptr) { 170 | perror("mnl_attr_nest_start:CTA_TUPLE_PROTO"); 171 | return -8; 172 | } 173 | 174 | mnl_attr_put_u8( hdr, 1 /*CTA_PROTO_NUM*/, IPPROTO_TCP); 175 | mnl_attr_put_u16(hdr, 2 /*CTA_PROTO_SRC_PORT*/, repl_src_port); 176 | mnl_attr_put_u16(hdr, 3 /*CTA_PROTO_DST_PORT*/, repl_dst_port); 177 | 178 | mnl_attr_nest_end(hdr, nest); 179 | } 180 | 181 | mnl_attr_nest_end(hdr, nest); 182 | } 183 | 184 | if (std::is_same::value) { 185 | mnl_attr_put_u32(hdr, 7 /*CTA_TIMEOUT*/, timeout); 186 | 187 | struct nlattr *nest, *nest_proto; 188 | nest = mnl_attr_nest_start(hdr, 4 /*CTA_PROTOINFO*/); 189 | if (nest == nullptr) { 190 | perror("mnl_attr_nest_start:CTA_PROTOINFO"); 191 | return -9; 192 | } 193 | 194 | nest_proto = mnl_attr_nest_start(hdr, 1 /*CTA_PROTOINFO_TCP*/); 195 | if (nest_proto == nullptr) { 196 | perror("mnl_attr_nest_start:CTA_PROTOINFO_TCP"); 197 | return -10; 198 | } 199 | 200 | mnl_attr_put_u8(hdr, 1 /*CTA_PROTOINFO_TCP_STATE*/, 201 | 3 /*TCP_CONNTRACK_ESTABLISHED*/); 202 | 203 | mnl_attr_nest_end(hdr, nest_proto); 204 | mnl_attr_nest_end(hdr, nest); 205 | } 206 | 207 | if ( mnl_socket_sendto(sock, hdr, hdr->nlmsg_len) == -1 ) { 208 | perror("mnl_socket_sendto"); 209 | return -11; 210 | } 211 | 212 | int r = 0; 213 | if ( (r = mnl_socket_recvfrom(sock, buf, mnl_socket_buffer_size)) == -1 ) { 214 | perror("mnl_socket_recvfrom"); 215 | return -12; 216 | } 217 | 218 | while (r > 0) { 219 | r = mnl_cb_run(buf, r, seq, portid, NULL, NULL); 220 | if (r == 0) { 221 | break; 222 | } else if (r == -1) { 223 | perror("mnl_cb_run"); 224 | return -12; 225 | } 226 | 227 | if ( (r = mnl_socket_recvfrom(sock, buf, mnl_socket_buffer_size)) == -1 ) { 228 | perror("mnl_socket_recvfrom"); 229 | return -13; 230 | } 231 | } 232 | 233 | if ( mnl_socket_close(sock) == -1 ) { 234 | perror("mnl_socket_close"); 235 | //TODO if failure occurs here, may have to do a teardown 236 | return -14; 237 | } 238 | 239 | return 1; 240 | } 241 | 242 | #endif 243 | -------------------------------------------------------------------------------- /include/forgery.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 NCC Group 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef LIBSHAMBLES_FORGERY_H_ 28 | #define LIBSHAMBLES_FORGERY_H_ 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | typedef struct tcp_state tcp_state_t; 42 | 43 | int8_t set_forged_sock_opts(int sock); 44 | 45 | int8_t bind_forged_sock_ipv4_anywhere(int sock); 46 | 47 | int8_t forge_tcp_state(int sock, tcp_state_t* state); 48 | 49 | #endif -------------------------------------------------------------------------------- /include/shambles.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 NCC Group 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef LIBSHAMBLES_SHAMBLES_H_ 28 | #define LIBSHAMBLES_SHAMBLES_H_ 29 | 30 | #include 31 | #include 32 | 33 | extern "C" { 34 | 35 | typedef struct __attribute__((__packed__)) pkt_data { 36 | uint32_t src_addr; 37 | uint32_t dst_addr; 38 | 39 | uint16_t src_port; 40 | uint16_t dst_port; 41 | 42 | uint32_t seq; 43 | uint32_t ack; 44 | 45 | uint16_t msg_len; 46 | uint8_t* msg; 47 | } pkt_data_t; 48 | 49 | typedef struct forged_sockets { 50 | int outer_sock; // socket for outside host communication 51 | int inner_sock; // socket for inside host communication 52 | } forged_sockets_t; 53 | 54 | void swap_pkt_data(pkt_data_t const * const _in, pkt_data_t * const _out); 55 | void swap_pkt_data_inline(pkt_data_t * const _self); 56 | 57 | int8_t addr_in_subnet(uint32_t _addr, uint32_t _inner_addr, uint32_t _netmask); 58 | 59 | int8_t intercept(forged_sockets_t* _out, pkt_data_t const * const _pd, 60 | uint32_t const _outer_addr, uint32_t const _inner_addr); 61 | 62 | int8_t intercept_teardown(pkt_data_t const * const _pd, 63 | uint32_t const _outer_addr, 64 | uint32_t const _inner_addr); 65 | 66 | int8_t addr_in_subnet(uint32_t _addr, uint32_t _inner_addr, 67 | uint32_t _netmask); 68 | 69 | ssize_t send_forged_sockets(forged_sockets_t const * const _fst, 70 | char const * const _path); 71 | 72 | ssize_t send_forged_sockets2(int fd, forged_sockets_t const * const _fst); 73 | 74 | } 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /include/util.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 NCC Group 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef LIBSHAMBLES_UTIL_H_ 28 | #define LIBSHAMBLES_UTIL_H_ 29 | 30 | #include 31 | 32 | #include "shambles.h" 33 | #include "forgery.h" 34 | 35 | #ifdef DEBUG 36 | #define DEBUG_printf(...) fprintf(stderr, __VA_ARGS__) 37 | #else 38 | #define DEBUG_printf(...) (void)0 39 | #endif 40 | 41 | uint8_t parse_ipv4(const char* str, uint64_t len); 42 | 43 | /** 44 | * Usage: 45 | * char buf[16]; 46 | * inet_htoa_r(buf, ntohl(inet_addr("1.2.3.4"))); 47 | */ 48 | char* inet_htoa_r(char* buf, uint32_t haddr); 49 | 50 | 51 | /** 52 | * Usage: 53 | * char buf[16]; 54 | * inet_ntoa_r(buf, inet_addr("1.2.3.4")); 55 | */ 56 | char* inet_ntoa_r(char* buf, uint32_t haddr); 57 | 58 | void hexdump(uint8_t const * const _data, uint16_t const _data_len); 59 | void tcp_state_dump(tcp_state_t const * const _st); 60 | void pkt_data_dump(pkt_data_t const * const _pd); 61 | //void hook_data_dump(hook_data_t const * const _hdt); 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /lib/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | libshambles.* 3 | -------------------------------------------------------------------------------- /samples/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | -------------------------------------------------------------------------------- /samples/hookscripts/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | -------------------------------------------------------------------------------- /samples/hookscripts/Makefile: -------------------------------------------------------------------------------- 1 | CXX=clang++ 2 | CXXFLAGS=-std=c++14 -stdlib=libc++ -Wall -Wextra -pedantic -fPIC -fPIE -fstack-protector-strong -D_FORTIFY_SOURCE=2 3 | SANITIZE=-fsanitize=address,undefined 4 | DEBUG=-g -DDEBUG 5 | OPTIMIZE=-O3 6 | LINK=-Wl,-z,relro,-z,now,-z,noexecstack 7 | INCS=-I include 8 | OUTPUT=-shared -o lib/hookffi.so 9 | 10 | default: build/hookffi.o 11 | ${CXX} ${CXXFLAGS} ${OPTIMIZE} ${INCS} ${LINK} ${OUTPUT} build/hookffi.o 12 | 13 | debug: build/hookffi.o 14 | ${CXX} ${CXXFLAGS} ${DEBUG} ${SANITIZE} ${INCS} ${LINK} ${OUTPUT} build/hookffi.o 15 | 16 | vdebug: build/hookffi.o 17 | ${CXX} ${CXXFLAGS} ${DEBUG} ${INCS} ${LINK} ${OUTPUT} build/hookffi.o 18 | 19 | build/hookffi.o: src/hookffi.cc 20 | ${CXX} ${CXXFLAGS} ${INCS} -o build/hookffi.o -c src/hookffi.cc 21 | 22 | clean: 23 | rm lib/hookffi.so build/hookffi.o 24 | -------------------------------------------------------------------------------- /samples/hookscripts/build/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | *.o 3 | -------------------------------------------------------------------------------- /samples/hookscripts/hook.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright (c) 2015 NCC Group 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | SUCH DAMAGE. 25 | ''' 26 | 27 | from ctypes import * 28 | import sys 29 | import socket 30 | import time 31 | 32 | libName = './lib/hookffi.so' 33 | hookffi = CDLL(libName) 34 | 35 | class uds_data(Structure): 36 | _fields_ = [ 37 | ("outer_sock", c_int), 38 | ("inner_sock", c_int), 39 | ("uds_client", c_int)] 40 | 41 | 42 | HOOKFUNC = CFUNCTYPE(c_int, POINTER(uds_data)) 43 | 44 | def hook(uds_datap): 45 | outer_sock = socket.fromfd(uds_datap.contents.outer_sock, socket.AF_INET, 46 | socket.SOCK_STREAM, 0) 47 | inner_sock = socket.fromfd(uds_datap.contents.inner_sock, socket.AF_INET, 48 | socket.SOCK_STREAM, 0) 49 | custom_hook(outer_sock, inner_sock) 50 | hookffi.teardown(uds_datap) 51 | return 0 52 | 53 | 54 | def custom_hook(outer_sock, inner_sock): 55 | print "hooked!" 56 | print "Client says: " + inner_sock.recv(1024) 57 | inner_sock.sendall("YO CLIENT, THIS IS PYTHON!\n") 58 | 59 | inner_sock.close() 60 | 61 | outer_sock.sendall("YO SERVER, THIS IS PYTHON!\n") 62 | print "Server says: " + outer_sock.recv(1024) 63 | outer_sock.close() 64 | 65 | 66 | 67 | 68 | 69 | def main(): 70 | if len(sys.argv) != 3: 71 | print "Usage: python hook.py " \ 72 | "" 73 | sys.exit(1) 74 | 75 | path = sys.argv[1] 76 | uname = sys.argv[2] 77 | 78 | uds_server_sock = hookffi.setup_server(path) 79 | hookffi.allow_user(path, uname) 80 | 81 | cb = HOOKFUNC(hook) 82 | hookffi.register_hook(cb) 83 | 84 | data = uds_data() 85 | hookffi.start(uds_server_sock, byref(data)) 86 | 87 | if __name__ == "__main__": 88 | main() 89 | 90 | -------------------------------------------------------------------------------- /samples/hookscripts/hook.rb: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright (c) 2015 NCC Group 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | SUCH DAMAGE. 25 | ''' 26 | 27 | require 'ffi' 28 | require 'socket' 29 | 30 | module Hookffi 31 | extend FFI::Library 32 | ffi_lib "./lib/hookffi.so" 33 | class UdsData < FFI::Struct 34 | layout :outer_sock, :int, 35 | :inner_sock, :int, 36 | :uds_client, :int 37 | end 38 | 39 | callback :hook, [UdsData.by_ref], :int 40 | 41 | attach_function :setup_server, [:string], :int 42 | attach_function :allow_user, [:string, :string], :uchar 43 | attach_function :register_native_hook, :register_hook, [:hook], :uchar 44 | attach_function :start, [:int, UdsData.by_ref], :uchar 45 | attach_function :teardown, [UdsData.by_ref], :int 46 | attach_function :close_forged_sockets_early, [UdsData.by_ref], :int 47 | end 48 | 49 | Hookffi::HookCallback = FFI::Function.new(:int, [Hookffi::UdsData.by_ref], :blocking => true) do |uds| 50 | outer_sock = Socket.for_fd(uds[:outer_sock]) 51 | inner_sock = Socket.for_fd(uds[:inner_sock]) 52 | 53 | custom_hook(outer_sock, inner_sock) 54 | Hookffi.teardown(uds) 55 | 0 56 | end 57 | 58 | 59 | 60 | 61 | 62 | def custom_hook(outer_sock, inner_sock) 63 | puts "Hooked from Ruby!" 64 | 65 | outer_sock.send "YO SERVER, THIS IS RUBY!\n", 0 66 | inner_sock.send "YO CLIENT, THIS IS RUBY!\n", 0 67 | 68 | puts "Server says: " + outer_sock.recv(1024) 69 | puts "Client says: " + inner_sock.recv(1024) 70 | end 71 | 72 | 73 | 74 | 75 | 76 | if __FILE__ == $PROGRAM_NAME 77 | if ARGV.length != 2 78 | puts "Usage: python hook.py " + 79 | "" 80 | -1 81 | end 82 | path = ARGV[0] 83 | uname = ARGV[1] 84 | 85 | uds_server_sock = Hookffi.setup_server path 86 | Hookffi.allow_user path, uname 87 | 88 | Hookffi.register_native_hook Hookffi::HookCallback 89 | 90 | data = Hookffi::UdsData.new 91 | Hookffi.start uds_server_sock, data 92 | end 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /samples/hookscripts/include/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | -------------------------------------------------------------------------------- /samples/hookscripts/include/hookffi.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 NCC Group 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef LIBINTERCEPT_HOOKFFI_HOOKFFI_H_ 28 | #define LIBINTERCEPT_HOOKFFI_HOOKFFI_H_ 29 | 30 | 31 | typedef struct uds_data { 32 | int outer_sock; 33 | int inner_sock; 34 | int uds_client; 35 | } uds_data_t; 36 | 37 | typedef int hook_cb(uds_data_t* _data); 38 | 39 | #ifdef DEBUG 40 | #define DEBUG_printf(...) fprintf(stderr, __VA_ARGS__) 41 | #else 42 | #define DEBUG_printf(...) (void)0 43 | #endif 44 | 45 | extern "C" { 46 | 47 | int setup_server(char const * const _path); 48 | int8_t allow_user(char const * const _path, char const * const _user); 49 | int8_t register_hook(hook_cb* _hcb); 50 | int8_t start(int _fd, uds_data_t* _data); 51 | int teardown(uds_data_t* _data); 52 | 53 | int close_forged_sockets_early(uds_data_t* _data); 54 | 55 | } 56 | 57 | #endif -------------------------------------------------------------------------------- /samples/hookscripts/lib/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | hookffi.* 3 | -------------------------------------------------------------------------------- /samples/hookscripts/src/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | -------------------------------------------------------------------------------- /samples/hookscripts/src/hookffi.cc: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 NCC Group 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | #include 42 | #include 43 | #include 44 | 45 | #include "hookffi.h" 46 | 47 | std::string const linux_username_regex_str = "^[a-z_][a-z0-9_-]*[$]?$"; 48 | std::regex const linux_username_regex(linux_username_regex_str); 49 | 50 | constexpr static char TEARDOWN_CMD[] = "teardown"; 51 | constexpr static size_t TEARDOWN_CMD_LEN = sizeof(TEARDOWN_CMD)-1; 52 | 53 | 54 | hook_cb * callback = nullptr; 55 | 56 | 57 | 58 | 59 | 60 | int setup_server(char const * const _path) { 61 | DEBUG_printf("%s\n", __func__); 62 | 63 | struct sockaddr_un addr; 64 | int fd; 65 | 66 | if ((fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) { 67 | perror("main:socket"); 68 | return -3; 69 | } 70 | 71 | memset(&addr, 0, sizeof(addr)); 72 | 73 | addr.sun_family = AF_LOCAL; 74 | strncpy(addr.sun_path, _path, sizeof(addr.sun_path)-1); 75 | //strcpy(addr.sun_path, _path); //generally cli input, this is faster 76 | //n2s: learn to suppress clang-tidy 77 | // 107 bytes + 1 NUL (pre-nulled by memset) 78 | 79 | unlink(_path); 80 | if (bind(fd, (struct sockaddr *) &(addr), 81 | sizeof(addr)) < 0) { 82 | perror("main:bind"); 83 | return -4; 84 | } 85 | 86 | if (listen(fd, 1) < 0) { 87 | perror("main:listen"); 88 | return -5; 89 | } 90 | 91 | return fd; 92 | } 93 | 94 | 95 | bool is_numeric(const std::string& s) { 96 | return !s.empty() && std::find_if( 97 | s.begin(), 98 | s.end(), 99 | [](char c) { 100 | return !std::isdigit(c); 101 | }) == s.end(); 102 | } 103 | 104 | int8_t allow_user(char const * const _path, char const * const _user) { 105 | DEBUG_printf("%s\n", __func__); 106 | std::string uname = _user; 107 | 108 | if (!is_numeric(uname) && !std::regex_match(uname, linux_username_regex)) { 109 | return -1; 110 | } 111 | 112 | pid_t pid = fork(); 113 | if(pid >= 0) { 114 | if(pid == 0) { //child 115 | std::string acl = "u:" + uname + ":rwx"; 116 | const char* const execve_argv[] = { "setfacl", "-m", acl.c_str(), _path, 117 | nullptr }; 118 | 119 | execve("/bin/setfacl", const_cast(execve_argv), nullptr); 120 | } 121 | } 122 | else { 123 | perror("fork"); 124 | return -2; 125 | } 126 | return 0; 127 | } 128 | 129 | int8_t register_hook(hook_cb* _hcb) { 130 | DEBUG_printf("%s: _hcb: %p\n", __func__, (void*)_hcb); 131 | 132 | callback = _hcb; 133 | return 0; 134 | } 135 | 136 | 137 | void cleanup(int sig) noexcept { 138 | DEBUG_printf("%s\n", __func__); 139 | 140 | (void)sig; 141 | exit(0); 142 | } 143 | 144 | int8_t start(int _fd, uds_data_t* _data) { 145 | DEBUG_printf("%s: _fd:%d, _data:%p\n", __func__, _fd, (void*)_data); 146 | 147 | signal(SIGINT, cleanup); 148 | 149 | struct sockaddr_un remote; 150 | int len = sizeof(struct sockaddr_un); 151 | 152 | int pid = 0; 153 | while (true) { 154 | 155 | int peer = accept(_fd, (struct sockaddr*)&remote, (socklen_t *)&len); 156 | DEBUG_printf("peer: %d\n", peer); 157 | 158 | 159 | pid = fork(); // https://github.com/ffi/ffi/issues/241 160 | if (pid == -1) { 161 | fprintf(stderr, "Something bad happened.\n"); 162 | close(peer); 163 | continue; 164 | } else if (pid > 0) { 165 | close(peer); 166 | continue; 167 | } 168 | 169 | int sent_fd[2]; 170 | struct msghdr message; 171 | struct iovec iov[1]; 172 | struct cmsghdr *control_message = NULL; 173 | union { 174 | /* ancillary data buffer, wrapped in a union in order to ensure 175 | it is suitably aligned */ 176 | char buf[CMSG_SPACE(sizeof(sent_fd))]; 177 | struct cmsghdr align; 178 | } u; 179 | 180 | char data[1]; 181 | int res; 182 | 183 | memset(&message, 0, sizeof(struct msghdr)); 184 | 185 | /* For the dummy data */ 186 | iov[0].iov_base = data; 187 | iov[0].iov_len = sizeof(data); 188 | 189 | message.msg_name = NULL; 190 | message.msg_namelen = 0; 191 | message.msg_control = u.buf; 192 | message.msg_controllen = sizeof(u.buf); 193 | message.msg_iov = iov; 194 | message.msg_iovlen = 1; 195 | 196 | if((res = recvmsg(peer, &message, 0)) <= 0) { 197 | perror("recvmsg"); 198 | return -1; 199 | } 200 | 201 | /* Iterate through header to find if there is a file descriptor */ 202 | bool sockets_found = false; 203 | for(control_message = CMSG_FIRSTHDR(&message); 204 | control_message != NULL; 205 | control_message = CMSG_NXTHDR(&message, 206 | control_message)) { 207 | if( (control_message->cmsg_level == SOL_SOCKET) && 208 | (control_message->cmsg_type == SCM_RIGHTS) ) { 209 | memcpy(sent_fd, CMSG_DATA(control_message), sizeof(int)*2); 210 | sockets_found = true; 211 | 212 | } 213 | } 214 | if (!sockets_found) { 215 | fprintf(stderr, "No sockets received.\n"); 216 | return -1; 217 | } 218 | 219 | DEBUG_printf("outer_sock: %d, inner_sock: %d\n", sent_fd[0], sent_fd[1]); 220 | 221 | _data->outer_sock = sent_fd[0]; 222 | _data->inner_sock = sent_fd[1]; 223 | _data->uds_client = peer; 224 | DEBUG_printf("calling callback\n"); 225 | (*callback)(_data); 226 | } 227 | return 1; 228 | } 229 | 230 | int teardown(uds_data_t* _data) { 231 | DEBUG_printf("%s\n", __func__); 232 | close(_data->outer_sock); 233 | close(_data->inner_sock); 234 | 235 | send(_data->uds_client, TEARDOWN_CMD, TEARDOWN_CMD_LEN, 0); 236 | return close(_data->uds_client); 237 | } 238 | 239 | 240 | int close_forged_sockets_early(uds_data_t* _data) { 241 | DEBUG_printf("%s\n", __func__); 242 | 243 | //used b/c of conntrack/snat/dnat quirk 244 | send(_data->inner_sock, "\x00", 1, 0); 245 | 246 | close(_data->outer_sock); 247 | close(_data->inner_sock); 248 | return 0; 249 | } 250 | 251 | 252 | -------------------------------------------------------------------------------- /samples/scan/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | scan 3 | -------------------------------------------------------------------------------- /samples/scan/Makefile: -------------------------------------------------------------------------------- 1 | CXX=clang++ 2 | CXXFLAGS=-std=c++14 -stdlib=libc++ -Wall -Wextra -pedantic -fPIC -fPIE -fstack-protector-strong -D_FORTIFY_SOURCE=2 3 | SANITIZE=-fsanitize=address,undefined 4 | DEBUG=-g -DDEBUG 5 | OPTIMIZE=-O3 6 | LINK=-Wl,-z,relro,-z,now,-z,noexecstack -pie 7 | OUTPUT=-o scan 8 | 9 | INCLUDES=-I ./include -I ../../include 10 | LIBS=-lpcap 11 | 12 | default: build/scan.o 13 | ${CXX} ${CXXFLAGS} ${OPTIMIZE} ${LINK} ${OUTPUT} build/scan.o ${LIBS} 14 | 15 | debug: build/scan.o 16 | ${CXX} ${CXXFLAGS} ${DEBUG} ${SANITIZE} ${LINK} ${OUTPUT} build/scan.o ${LIBS} 17 | 18 | vdebug: build/scan.o 19 | ${CXX} ${CXXFLAGS} ${DEBUG} ${LINK} ${OUTPUT} build/scan.o ${LIBS} 20 | 21 | build/scan.o: src/scan.cc 22 | ${CXX} ${CXXFLAGS} ${INCLUDES} -o build/scan.o -c src/scan.cc 23 | 24 | clean: 25 | rm scan build/scan.o 26 | -------------------------------------------------------------------------------- /samples/scan/build/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | *.o 3 | -------------------------------------------------------------------------------- /samples/scan/include/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | -------------------------------------------------------------------------------- /samples/scan/src/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | -------------------------------------------------------------------------------- /samples/scan/src/scan.cc: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 NCC Group 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | typedef unsigned int u_int; 28 | typedef unsigned short u_short; 29 | typedef unsigned char u_char; 30 | #define EBUF_LEN 160 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | #include 45 | #include 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | 53 | #include 54 | #include 55 | 56 | #include 57 | 58 | #ifdef DEBUG 59 | #define DEBUG_printf(...) fprintf(stderr, __VA_ARGS__) 60 | #else 61 | #define DEBUG_printf(...) (void)0 62 | #endif 63 | 64 | char ebuf[EBUF_LEN] = {0}; 65 | int client_sock = 0; 66 | int r = 0; 67 | 68 | std::regex regex; 69 | 70 | const uint8_t* strnstrn(const uint8_t* haystack, uint32_t hn, const uint8_t* needle, uint32_t nn) { 71 | for ( uint32_t i(0); i < hn; i++ ) { 72 | if ( memcmp(haystack+i, needle, nn) == 0 ) { 73 | return haystack+i; 74 | } 75 | 76 | if ( (i + nn) == hn) { 77 | break; 78 | } 79 | } 80 | return nullptr; 81 | } 82 | 83 | pkt_data_t pdt = {0,0, 0,0, 0,0, 0,nullptr}; 84 | 85 | 86 | void intercept(struct pkt_data* pb) { 87 | 88 | 89 | 90 | r = send(client_sock, pb, 22, 0); 91 | if( r < 0 ) { 92 | strerror_r(errno, ebuf, sizeof(ebuf)); 93 | fprintf(stderr, "client_sock:send => %s\n", ebuf); 94 | exit(1); 95 | } 96 | 97 | r = send(client_sock, pb->msg, pb->msg_len, 0); 98 | if( r < 0 ) { 99 | strerror_r(errno, ebuf, sizeof(ebuf)); 100 | fprintf(stderr, "client_sock:send => %s\n", ebuf); 101 | exit(1); 102 | } 103 | 104 | close(client_sock); 105 | 106 | 107 | } 108 | 109 | 110 | bool tcp_handler(uint32_t rsize, const uint8_t* bytes) { 111 | if ( rsize < sizeof(tcphdr) ) { 112 | return false; 113 | } 114 | DEBUG_printf("--->TCP!\n"); 115 | tcphdr* hdr = (tcphdr*)bytes; 116 | uint8_t hdr_size = (hdr->th_off*4); 117 | if (rsize < hdr_size) { 118 | return false; 119 | } 120 | 121 | const uint8_t* payload = bytes + hdr_size; 122 | uint32_t payload_size = rsize - hdr_size; 123 | 124 | // uint8_t query[] = "HELLO WORLD!"; 125 | // const uint8_t* match = strnstrn(payload, rsize, query, strlen((char*)query)); 126 | // if (match != nullptr) { 127 | if(std::regex_search(std::string((char*)payload, payload_size), regex)) { 128 | pdt.src_port = hdr->th_sport; 129 | pdt.dst_port = hdr->th_dport; 130 | pdt.seq = htonl(ntohl(hdr->th_seq) + payload_size); 131 | pdt.ack = hdr->th_ack; 132 | pdt.msg_len = htons(payload_size); 133 | pdt.msg = (uint8_t*)malloc(payload_size); 134 | if (pdt.msg != nullptr) { 135 | memcpy(pdt.msg, payload, payload_size); 136 | } 137 | return true; 138 | } 139 | 140 | return false; 141 | } 142 | 143 | bool ip_handler(uint32_t rsize, const uint8_t* bytes) { 144 | if ( rsize < sizeof(ip) ) { 145 | return false; 146 | } 147 | DEBUG_printf("->IP!\n"); 148 | 149 | ip* hdr4 = (ip*)bytes; 150 | uint8_t version = hdr4->ip_v; 151 | 152 | if (version == 4) { 153 | uint8_t ihl = hdr4->ip_hl; 154 | if ( rsize < ihl ) { 155 | return false; 156 | } 157 | 158 | uint8_t hdr4_size = ihl*4; 159 | const uint8_t* payload = bytes + hdr4_size; 160 | switch(hdr4->ip_p) { 161 | case IPPROTO_TCP: 162 | if ( tcp_handler(rsize - hdr4_size, payload) ) { 163 | pdt.src_addr = hdr4->ip_src.s_addr; 164 | pdt.dst_addr = hdr4->ip_dst.s_addr; 165 | return true; 166 | } 167 | return false; 168 | break; 169 | default: 170 | return false; 171 | } 172 | 173 | 174 | 175 | } else { 176 | if ( rsize < sizeof(ip6_hdr) ) { 177 | return false; 178 | } 179 | ip6_hdr* hdr6 = (ip6_hdr*)bytes; 180 | (void)hdr6; 181 | // not handling ipv6 right now 182 | return false; 183 | } 184 | return false; 185 | } 186 | 187 | void eth_handler(uint8_t* user, const struct pcap_pkthdr* pkthdr, const uint8_t* bytes) { 188 | (void)user; 189 | DEBUG_printf("GOT ONE!\n"); 190 | uint32_t capturedSize = pkthdr->caplen; 191 | ether_header* hdr = (ether_header*)bytes; 192 | 193 | 194 | if (capturedSize < sizeof(ether_header)) { 195 | return; 196 | } else if (ntohs(hdr->ether_type) == ETHERTYPE_IP) { 197 | if ( ip_handler(capturedSize - sizeof(ether_header), bytes + sizeof(ether_header)) ) { 198 | DEBUG_printf("ZA WARUDO!\n"); 199 | intercept(&pdt); 200 | free(pdt.msg); 201 | exit(0); 202 | } 203 | } else { 204 | DEBUG_printf("WAT?\n"); 205 | } 206 | 207 | return; 208 | } 209 | 210 | int main(int argc, char const *argv[]) { 211 | 212 | if (argc != 6) { 213 | fprintf(stderr, "Usage: %s " 214 | " \n", argv[0]); 215 | return -1; 216 | } 217 | 218 | pcap_t *handle; /* Session handle */ 219 | char const* dev = argv[1]; /* Device to sniff on */ 220 | char errbuf[PCAP_ERRBUF_SIZE]; /* Error string */ 221 | struct bpf_program fp; /* The compiled filter expression */ 222 | char const* filter_exp = argv[2]; /* The filter expression */ 223 | bpf_u_int32 mask; /* The netmask of our sniffing device */ 224 | bpf_u_int32 net; /* The IP of our sniffing device */ 225 | 226 | try { 227 | regex = std::regex(argv[3]); 228 | } catch (const std::regex_error& e) { 229 | fprintf(stderr, "Invalid regular expression: %s\nError: %s\n", argv[3], e.what()); 230 | return -1; 231 | } 232 | struct sockaddr_in remote; memset(&remote, 0, sizeof(remote)); 233 | remote.sin_family = AF_INET; 234 | remote.sin_port = htons(atoi(argv[5])); 235 | 236 | 237 | r = inet_pton(AF_INET, argv[4], &remote.sin_addr); 238 | if (r != 1) { 239 | if (r == 0) { 240 | fprintf(stderr, "remote:inet_pton => %s\n", "Invalid network address string."); 241 | return -1; 242 | } else { 243 | strerror_r(errno, ebuf, sizeof(ebuf)); 244 | fprintf(stderr, "remote:inet_pton => %s\n", ebuf); 245 | return -1; 246 | } 247 | } 248 | 249 | client_sock = socket(AF_INET, SOCK_STREAM, 0); 250 | if (client_sock < 0) { 251 | strerror_r(errno, ebuf, sizeof(ebuf)); 252 | fprintf(stderr, "client_sock:socket => %s\n", ebuf); 253 | return -1; 254 | } 255 | 256 | r = connect(client_sock, (struct sockaddr*) &remote, sizeof(remote)); 257 | if (r != 0) { 258 | strerror_r(errno, ebuf, sizeof(ebuf)); 259 | fprintf(stderr, "client_sock:connect => %s\n", ebuf); 260 | free(pdt.msg); 261 | return -1; 262 | } 263 | 264 | 265 | 266 | if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) { 267 | fprintf(stderr, "Can't get netmask for device %s\n", dev); 268 | net = 0; 269 | mask = 0; 270 | } 271 | 272 | puts("Starting capture..."); 273 | handle = pcap_open_live(dev, 1000, 0, 1, errbuf); 274 | if (handle == NULL) { 275 | fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf); 276 | return -2; 277 | } 278 | if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) { 279 | fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle)); 280 | return -2; 281 | } 282 | if (pcap_setfilter(handle, &fp) == -1) { 283 | fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle)); 284 | return -2; 285 | } 286 | 287 | int loopret = pcap_loop(handle, 0, eth_handler, nullptr); 288 | if (loopret == -1) { 289 | fprintf(stderr, "Something bad happened.\n"); 290 | return -3; 291 | } else if (loopret == -2) { 292 | fprintf(stderr, "Bail OUT\n"); 293 | return -3; 294 | } 295 | 296 | return 0; 297 | } 298 | -------------------------------------------------------------------------------- /samples/shambles/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | shambles 3 | -------------------------------------------------------------------------------- /samples/shambles/Makefile: -------------------------------------------------------------------------------- 1 | CXX=clang++ 2 | CXXFLAGS=-std=c++14 -stdlib=libc++ -Wall -Wextra -pedantic -fPIC -fPIE -fstack-protector-strong -D_FORTIFY_SOURCE=2 3 | SANITIZE=-fsanitize=address,undefined 4 | DEBUG=-g -DDEBUG 5 | OPTIMIZE=-O3 6 | LINK=-pie -L ../../lib -L vendor/libuv/.libs/ -Wl,-z,relro,-z,now,-z,noexecstack 7 | INCS=-I include -I ../../include/ -I vendor/libuv/include 8 | OUTPUT=-o shambles 9 | 10 | LIBS=-lmnl -lcap -lpthread -Wl,-Bstatic -luv -lshambles -Wl,-Bdynamic 11 | 12 | default: build/main.o build/util.o 13 | ${CXX} ${CXXFLAGS} ${OPTIMIZE} ${INCS} ${LINK} ${OUTPUT} build/main.o build/util.o ${LIBS} 14 | 15 | debug: build/main.o build/util.o 16 | ${CXX} ${CXXFLAGS} ${DEBUG} ${INCS} ${SANITIZE} ${LINK} ${OUTPUT} build/main.o build/util.o ${LIBS} 17 | 18 | vdebug: build/main.o build/util.o 19 | ${CXX} ${CXXFLAGS} ${DEBUG} ${INCS} ${LINK} ${OUTPUT} build/main.o build/util.o ${LIBS} 20 | 21 | build/main.o: src/main.cc 22 | ${CXX} ${CXXFLAGS} ${INCS} -o build/main.o -c src/main.cc 23 | 24 | build/util.o: src/util.cc 25 | ${CXX} ${CXXFLAGS} ${INCS} -o build/util.o -c src/util.cc 26 | 27 | clean: 28 | rm shambles build/main.o build/util.o 29 | -------------------------------------------------------------------------------- /samples/shambles/build/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | *.o 3 | -------------------------------------------------------------------------------- /samples/shambles/include/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | -------------------------------------------------------------------------------- /samples/shambles/include/util.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 NCC Group 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef LIBSHAMBLES_UTIL_H_ 28 | #define LIBSHAMBLES_UTIL_H_ 29 | 30 | #include 31 | #include 32 | 33 | #ifdef DEBUG 34 | #define DEBUG_printf(...) fprintf(stderr, __VA_ARGS__) 35 | #else 36 | #define DEBUG_printf(...) (void)0 37 | #endif 38 | 39 | uint8_t parse_ipv4(const char* str, uint64_t len); 40 | bool is_numeric(const std::string& s); 41 | 42 | /** 43 | * Usage: 44 | * char buf[16]; 45 | * inet_htoa_r(buf, ntohl(inet_addr("1.2.3.4"))); 46 | */ 47 | char* inet_htoa_r(char* buf, uint32_t haddr); 48 | 49 | 50 | /** 51 | * Usage: 52 | * char buf[16]; 53 | * inet_ntoa_r(buf, inet_addr("1.2.3.4")); 54 | */ 55 | char* inet_ntoa_r(char* buf, uint32_t haddr); 56 | 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /samples/shambles/nat.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ 3 -gt "$#" ]; then 4 | echo "sudo $0 [blacklist net]"; 5 | exit 6 | fi 7 | 8 | if [ 4 -lt "$#" ]; then 9 | echo "sudo $0 [blacklist net]"; 10 | exit 11 | fi 12 | 13 | IPT="iptables" 14 | 15 | $IPT -F 16 | $IPT -X 17 | $IPT -t nat -F 18 | $IPT -t nat -X 19 | $IPT -t mangle -F 20 | $IPT -t mangle -X 21 | $IPT -P INPUT ACCEPT 22 | $IPT -P FORWARD ACCEPT 23 | $IPT -P OUTPUT ACCEPT 24 | 25 | $IPT -P INPUT DROP 26 | $IPT -A INPUT -i lo -j ACCEPT 27 | 28 | #allow established connections in 29 | $IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 30 | $IPT -A FORWARD -i $1 -o $2 -m state --state ESTABLISHED,RELATED -j ACCEPT 31 | 32 | 33 | $IPT -A INPUT -i $2 -m state --state NEW -s $3 -j ACCEPT 34 | if [ 4 -eq "$#" ]; then 35 | $IPT -A FORWARD -i $2 -o $1 -d $4 -j DROP 36 | fi 37 | $IPT -A FORWARD -i $2 -o $1 -s $3 -j ACCEPT 38 | 39 | #nat 40 | $IPT -t nat -A POSTROUTING -o $1 ! -d $3 -j MASQUERADE 41 | 42 | #DROP by default 43 | $IPT -A INPUT -j REJECT 44 | $IPT -A FORWARD -j DROP 45 | 46 | #enable routing in case it is disabled 47 | echo 1 > /proc/sys/net/ipv4/ip_forward 48 | 49 | -------------------------------------------------------------------------------- /samples/shambles/setup_libuv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd vendor 4 | git clone https://github.com/libuv/libuv.git 5 | cd libuv 6 | ./autogen.sh 7 | ./configure CFLAGS="-fPIC -fPIE -fstack-protector-all -D_FORTIFY_SOURCE=2" LDFLAGS="-Wl,-z,relro,-z,now,-z,noexecstack -pie" 8 | make 9 | -------------------------------------------------------------------------------- /samples/shambles/src/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | -------------------------------------------------------------------------------- /samples/shambles/src/main.cc: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 NCC Group 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | 45 | #include "shambles.h" 46 | #include "util.h" 47 | 48 | #define DEFAULT_BACKLOG 128 49 | 50 | uv_loop_t *loop; 51 | 52 | char const * uds_path = nullptr; 53 | uint32_t outer_addr = 0; 54 | uint32_t inner_addr = 0; 55 | uint32_t netmask = 0; 56 | 57 | std::string teardown = "teardown"; 58 | 59 | std::unordered_map> streams; 60 | std::unordered_map uds_state; 61 | std::unordered_map fst_state; 62 | 63 | void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) noexcept { 64 | DEBUG_printf("%s\n", __func__ ); 65 | 66 | std::ignore = handle; 67 | buf->base = (char*) malloc(suggested_size); 68 | buf->len = suggested_size; 69 | } 70 | 71 | void free_socket(uv_handle_t* handle) noexcept { 72 | DEBUG_printf("%s\n", __func__ ); 73 | 74 | streams.erase((uv_stream_t *)handle); 75 | free(handle); 76 | } 77 | 78 | 79 | void onUdsRead(uv_stream_t* sock, ssize_t nread, const uv_buf_t *buf) noexcept { 80 | DEBUG_printf("%s\n", __func__ ); 81 | if (nread < 0) { 82 | if (nread != UV_EOF) { 83 | fprintf(stderr, "Read error %s\n", uv_err_name(nread)); 84 | //uv_close((uv_handle_t*) sock, free_socket); 85 | //free(sock); 86 | } else { 87 | DEBUG_printf("%s: got EOF\n", __func__); 88 | uv_close((uv_handle_t*) sock, free_socket); 89 | } 90 | if (uds_state.find((uv_pipe_t*)sock) != uds_state.end()) { 91 | pkt_data_t* pdt = uds_state[(uv_pipe_t*)sock]; 92 | intercept_teardown(pdt, outer_addr, inner_addr); 93 | 94 | uds_state.erase((uv_pipe_t*)sock); 95 | if (pdt->msg) { 96 | free(pdt->msg); 97 | } 98 | free(pdt); 99 | } 100 | 101 | } else { 102 | std::vector& v = streams[sock]; 103 | std::copy(buf->base, buf->base+nread, std::back_inserter(v)); 104 | if ( v.size() == teardown.length() ) { 105 | if ( std::string(v.data(), teardown.length()) == teardown) { 106 | DEBUG_printf("tearing down rules\n"); 107 | pkt_data_t* pdt = uds_state[(uv_pipe_t*)sock]; 108 | intercept_teardown(pdt, outer_addr, inner_addr); 109 | uds_state.erase((uv_pipe_t*)sock); 110 | if(pdt->msg) { 111 | free(pdt->msg); 112 | } 113 | free(pdt); 114 | } 115 | } 116 | } 117 | if (buf->base) { 118 | free(buf->base); 119 | } 120 | uv_close((uv_handle_t*) sock, free_socket); 121 | 122 | } 123 | 124 | void onUdsConnect(uv_connect_t* conn, int status) noexcept { 125 | DEBUG_printf("%s\n", __func__ ); 126 | 127 | if (status < 0) { 128 | DEBUG_printf("onUdsConnect:conn->handle: %p\n", conn->handle); 129 | fprintf(stderr, "UDS error: %s\n", uv_strerror(status)); 130 | forged_sockets_t* fst = fst_state[(uv_pipe_t*)conn->handle]; 131 | fst_state.erase((uv_pipe_t*)conn->handle); 132 | send(fst->inner_sock, "\x00", 1, 0); //something werid w/ the state causes 133 | //this to need data to be sent. ssems 134 | //to be due to connection tracking 135 | //not being in a position to allow in 136 | //the fin,ack from the client in 137 | //response to the server 138 | //TODO ^^^ 139 | close(fst->outer_sock); 140 | close(fst->inner_sock); 141 | free(fst); 142 | 143 | pkt_data_t* pdt = uds_state[(uv_pipe_t*)conn->handle]; 144 | intercept_teardown(pdt, outer_addr, inner_addr); 145 | uds_state.erase((uv_pipe_t*)conn->handle); 146 | if (pdt->msg) { 147 | free(pdt->msg); 148 | } 149 | free(pdt); 150 | uv_close((uv_handle_t*) conn->handle, free_socket); 151 | free(conn); 152 | return; 153 | } 154 | 155 | forged_sockets_t* fst = fst_state[(uv_pipe_t*)conn->handle]; 156 | 157 | int real_uds_fd; 158 | int r = uv_fileno((uv_handle_t*)conn->handle, (uv_os_fd_t*)&real_uds_fd); 159 | if ( r == UV_EINVAL || r == UV_EBADF) { 160 | if (r == UV_EINVAL) { 161 | fprintf(stderr, "onUdsConnect:uv_fileno: passed wrong handled type\n"); 162 | } else if (r == UV_EBADF) { 163 | fprintf(stderr, "onUdsConnect:uv_fileno: no file descriptor yet or " 164 | "conn->handle has been closed\n"); 165 | } 166 | } else { 167 | DEBUG_printf("sending forged packets\n"); 168 | send_forged_sockets2(real_uds_fd, fst); 169 | 170 | //closing local handle to sockets 171 | close(fst->outer_sock); 172 | close(fst->inner_sock); 173 | free(fst); 174 | fst_state.erase((uv_pipe_t*)conn->handle); 175 | 176 | uv_read_start((uv_stream_t*) conn->handle, alloc_buffer, onUdsRead); 177 | } 178 | void* handle = conn->handle; 179 | free(conn); 180 | uv_close((uv_handle_t*) handle, free_socket); 181 | 182 | } 183 | 184 | 185 | int8_t onPktDataReceived(uv_stream_t* sock, pkt_data_t* pdt) noexcept { 186 | DEBUG_printf("%s\n", __func__ ); 187 | 188 | std::ignore = sock; 189 | 190 | 191 | if (addr_in_subnet(pdt->src_addr, inner_addr, netmask) == 0) { 192 | swap_pkt_data_inline(pdt); 193 | } 194 | forged_sockets_t* fst = (forged_sockets_t*)malloc(sizeof(forged_sockets_t)); 195 | 196 | if (intercept(fst, pdt, outer_addr, inner_addr) != 1) { 197 | fprintf(stderr, "Can't setup intercept\n"); 198 | free(fst); 199 | uv_close((uv_handle_t*) sock, free_socket); 200 | return -1; 201 | } 202 | 203 | uv_pipe_t* uds_handle = (uv_pipe_t*)malloc(sizeof(uv_pipe_t)); 204 | if (uds_handle == nullptr) { 205 | fprintf(stderr, "onPktDataReceived:(uv_pipe_t*)malloc: null\n"); 206 | free(uds_handle); 207 | free(fst); 208 | return -2; 209 | } 210 | uv_pipe_init(loop, uds_handle, 0); 211 | 212 | uds_state[uds_handle] = pdt; 213 | fst_state[uds_handle] = fst; 214 | 215 | uv_connect_t* conn = (uv_connect_t*)malloc(sizeof(uv_connect_t)); 216 | DEBUG_printf("onPktDataReceived:uds_handle: %p\n", uds_handle); 217 | 218 | 219 | uv_pipe_connect(conn, uds_handle, uds_path, onUdsConnect); 220 | 221 | return 0; 222 | } 223 | 224 | void onRead(uv_stream_t* sock, ssize_t nread, const uv_buf_t *buf) noexcept { 225 | DEBUG_printf("%s\n", __func__ ); 226 | 227 | #ifdef DEBUG 228 | struct timeval tv; 229 | 230 | gettimeofday(&tv, NULL); 231 | 232 | unsigned long long millisecondsSinceEpoch = 233 | (unsigned long long)(tv.tv_sec) * 1000 + 234 | (unsigned long long)(tv.tv_usec) / 1000; 235 | 236 | printf("milliseconds: %llu\n", millisecondsSinceEpoch); 237 | #endif 238 | 239 | if (nread < 0) { 240 | if (nread != UV_EOF) { 241 | fprintf(stderr, "Read error %s\n", uv_err_name(nread)); 242 | uv_close((uv_handle_t*) sock, free_socket); 243 | } else { 244 | DEBUG_printf("%s: got EOF\n", __func__); 245 | uv_close((uv_handle_t*) sock, free_socket); 246 | } 247 | /* if (uds_state.find((uv_pipe_t*)sock) != uds_state.end()) { 248 | pkt_data_t* pdt = uds_state[(uv_pipe_t*)sock]; 249 | intercept_teardown(pdt, outer_addr, inner_addr); 250 | 251 | uds_state.erase((uv_pipe_t*)sock); 252 | if (pdt->msg) { 253 | free(pdt->msg); 254 | } 255 | free(pdt); 256 | } 257 | */ 258 | } else if (nread > 0) { 259 | DEBUG_printf("%s: %ld bytes read\n", __func__, nread); 260 | std::vector& v = streams[sock]; 261 | std::copy(buf->base, buf->base+nread, std::back_inserter(v)); 262 | 263 | if (v.size() >= sizeof(pkt_data_t)-sizeof(uint8_t*)) { 264 | uint16_t msg_len = reinterpret_cast(v.data())->msg_len; 265 | if (v.size() >= sizeof(pkt_data_t)-sizeof(uint8_t*)+msg_len) { 266 | pkt_data_t* pdt = (pkt_data_t*)malloc(sizeof(pkt_data_t)); 267 | if ( pdt == nullptr ) { 268 | uv_close((uv_handle_t*) sock, free_socket); 269 | if (buf->base) { 270 | free(buf->base); 271 | } 272 | return; 273 | } 274 | memcpy(pdt, v.data(), sizeof(pkt_data_t)-sizeof(uint8_t*)); 275 | pdt->msg = (uint8_t*)malloc(msg_len); 276 | if (pdt->msg == nullptr) { 277 | uv_close((uv_handle_t*) sock, free_socket); 278 | free(pdt); 279 | if (buf->base) { 280 | free(buf->base); 281 | } 282 | return; 283 | } 284 | 285 | memcpy(pdt->msg, 286 | v.data()+sizeof(pkt_data_t)-sizeof(uint8_t*), 287 | msg_len 288 | ); 289 | int8_t r = onPktDataReceived(sock, pdt); 290 | if (r != 0) { 291 | if ( r == -2 ) { 292 | intercept_teardown(pdt, outer_addr, inner_addr); 293 | } 294 | 295 | if (pdt->msg) { 296 | free(pdt->msg); 297 | } 298 | free(pdt); 299 | if (buf->base) { 300 | free(buf->base); 301 | } 302 | return; 303 | } 304 | 305 | if (v.size() > sizeof(pkt_data_t)-sizeof(uint8_t*)+msg_len) { 306 | v = std::vector( 307 | v.begin()+sizeof(pkt_data_t)-sizeof(uint8_t*)+msg_len, 308 | v.end() 309 | ); 310 | } 311 | } 312 | } 313 | } else { 314 | DEBUG_printf("%s: no bytes read\n", __func__); 315 | } 316 | 317 | if (buf->base) { 318 | free(buf->base); 319 | } 320 | } 321 | 322 | 323 | void on_new_connection(uv_stream_t *server, int status) noexcept { 324 | DEBUG_printf("%s\n", __func__ ); 325 | 326 | if (status < 0) { 327 | fprintf(stderr, "New connection error: %s\n", uv_strerror(status)); 328 | // error! 329 | return; 330 | } 331 | DEBUG_printf("new connection: %p\n", server); 332 | 333 | uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); 334 | //blocks will be "possibly lost" in valgrind when ^C-ing b/c we keep the 335 | //connection alive 336 | 337 | uv_tcp_init(loop, client); 338 | if (uv_accept(server, (uv_stream_t*) client) == 0) { 339 | uv_read_start((uv_stream_t*) client, alloc_buffer, onRead); 340 | } 341 | else { 342 | uv_close((uv_handle_t*) client, free_socket); 343 | } 344 | } 345 | 346 | void cleanup(int sig) noexcept { 347 | DEBUG_printf("%s\n", __func__ ); 348 | 349 | (void)sig; 350 | uv_loop_close(loop); 351 | free(loop); 352 | exit(0); 353 | } 354 | 355 | void onShutdown(uv_shutdown_t* req, int status) noexcept { 356 | DEBUG_printf("%s\n", __func__ ); 357 | 358 | (void)status; 359 | free(req); 360 | } 361 | 362 | int main(int argc, char const *argv[]) noexcept { 363 | if (argc != 7) { 364 | fprintf(stderr, "Usage: %s " 365 | " \n", 366 | argv[0]); 367 | return -1; 368 | } 369 | 370 | if ( parse_ipv4(argv[1], strlen(argv[1])) != 0 ) { 371 | fprintf(stderr, "Invalid value: %s\n", argv[1]); 372 | return -2; 373 | } 374 | 375 | if ( parse_ipv4(argv[2], strlen(argv[2])) != 0 ) { 376 | fprintf(stderr, "Invalid value: %s\n", argv[2]); 377 | return -3; 378 | } 379 | 380 | if ( parse_ipv4(argv[3], strlen(argv[3])) != 0 ) { 381 | fprintf(stderr, "Invalid value: %s\n", argv[3]); 382 | return -4; 383 | } 384 | 385 | if ( parse_ipv4(argv[5], strlen(argv[5])) != 0 ) { 386 | fprintf(stderr, "Invalid value: %s\n", argv[5]); 387 | return -5; 388 | } 389 | 390 | int port = atoi(argv[6]); 391 | if ( port < 0 392 | || port > static_cast(UINT16_MAX) 393 | || !is_numeric(std::string(argv[6])) ) { 394 | fprintf(stderr, "Invalid value: %s\n", argv[6]); 395 | return -6; 396 | } 397 | 398 | DEBUG_printf("Validating privileges.\n"); 399 | cap_value_t required_capability_list[2] = { CAP_NET_ADMIN, CAP_NET_RAW }; 400 | cap_t capabilities; 401 | 402 | 403 | capabilities = cap_get_proc(); 404 | if (capabilities == NULL) { 405 | fprintf(stderr, "Can't get capabilities information, exiting.\n"); 406 | return -7; 407 | } 408 | 409 | cap_value_t cap = CAP_NET_ADMIN; 410 | cap_flag_value_t has_cap; 411 | if(cap_get_flag(capabilities, cap, CAP_PERMITTED, &has_cap) != 0) { 412 | fprintf(stderr, "Invalid capability check? Exiting.\n"); 413 | return -8; 414 | } 415 | if (!has_cap) { 416 | fprintf(stderr, "Process does not have CAP_NET_ADMIN, exiting.\n"); 417 | return -9; 418 | } 419 | 420 | cap = CAP_NET_RAW; 421 | if(cap_get_flag(capabilities, cap, CAP_PERMITTED, &has_cap) != 0) { 422 | fprintf(stderr, "Invalid capability check?\n"); 423 | return -10; 424 | } 425 | if (!has_cap) { 426 | fprintf(stderr, "Process does not have CAP_NET_RAW, exiting.\n"); 427 | return -11; 428 | } 429 | 430 | 431 | DEBUG_printf("Dropping privileges.\n"); 432 | if (cap_clear(capabilities) == -1) { 433 | fprintf(stderr, "Can't clear capabilities, exiting.\n"); 434 | return -12; 435 | } 436 | 437 | 438 | 439 | if (cap_set_flag(capabilities, CAP_PERMITTED, 440 | sizeof(required_capability_list)/sizeof(required_capability_list[0]), 441 | required_capability_list, CAP_SET) == -1) { 442 | fprintf(stderr, "Error setting capabilities flags, exiting.\n"); 443 | return -13; 444 | } 445 | 446 | if (cap_set_flag(capabilities, CAP_EFFECTIVE,//CAP_PERMITTED, 447 | sizeof(required_capability_list)/sizeof(required_capability_list[0]), 448 | required_capability_list, CAP_SET) == -1) { 449 | fprintf(stderr, "Error setting capabilities flags, exiting.\n"); 450 | return -14; 451 | } 452 | 453 | 454 | if (cap_set_proc(capabilities) == -1) { 455 | fprintf(stderr, "Can't set restricted capabilities subset, exiting.\n"); 456 | return -15; 457 | } 458 | 459 | 460 | if ( cap_free(capabilities) == -1 ) { 461 | fprintf(stderr, "Could not free capabilities structures, exiting.\n"); 462 | return -16; 463 | } 464 | 465 | outer_addr = inet_addr(argv[1]); 466 | inner_addr = inet_addr(argv[2]); 467 | netmask = inet_addr(argv[3]); 468 | uds_path = argv[4]; 469 | 470 | loop = (uv_loop_t*)malloc(sizeof(uv_loop_t)); 471 | uv_loop_init(loop); 472 | 473 | // loop = uv_default_loop(); 474 | struct sockaddr_in addr; 475 | 476 | uv_tcp_t tcp_server; 477 | uv_tcp_init(loop, &tcp_server); 478 | 479 | uv_ip4_addr(argv[5], port, &addr); 480 | 481 | uv_tcp_bind(&tcp_server, (const struct sockaddr*)&addr, 0); 482 | int r = uv_listen((uv_stream_t*) &tcp_server, 483 | DEFAULT_BACKLOG, 484 | on_new_connection 485 | ); 486 | if (r == -1) { 487 | fprintf(stderr, "Listen error %s\n", uv_strerror(r)); 488 | return -13; 489 | } 490 | 491 | signal(SIGINT, cleanup); 492 | puts("Listening..."); 493 | return uv_run(loop, UV_RUN_DEFAULT); 494 | } 495 | -------------------------------------------------------------------------------- /samples/shambles/src/util.cc: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 NCC Group 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #include "util.h" 28 | 29 | #include 30 | #include 31 | 32 | uint8_t parse_ipv4(const char* str, uint64_t len) { 33 | uint8_t digits = 0; 34 | uint8_t vals[3] = { 0,0,0 }; 35 | uint8_t dots = 0; 36 | uint16_t seg = 0; 37 | for (uint64_t i = 0; i < len; i++) { 38 | char c = str[i]; 39 | if ('0' <= c && c <= '9') { 40 | vals[digits] = (uint16_t)c ^ 0x30; 41 | digits++; 42 | if (digits > 3) { 43 | return 1; 44 | } 45 | } else if (c == '.') { 46 | if (i+1 == len || dots == 3) { 47 | return 2; 48 | } 49 | if (digits == 1) { 50 | seg = vals[0]; 51 | } else if (digits == 2) { 52 | seg = vals[0]*10 + vals[1]; 53 | } else if (digits == 3) { 54 | seg = vals[0]*100 + vals[1]*10 + vals[2]; 55 | } 56 | 57 | if (seg > 255) { 58 | return 3; 59 | } 60 | digits = 0; seg = 0; 61 | dots++; 62 | if (dots > 3) { 63 | return 4; 64 | } 65 | } else { 66 | return 5; 67 | } 68 | } 69 | if (dots == 3) { 70 | return 0; 71 | } 72 | return 6; 73 | } 74 | 75 | bool is_numeric(const std::string& s) { 76 | return !s.empty() && std::find_if( 77 | s.begin(), 78 | s.end(), 79 | [](char c) { 80 | return !std::isdigit(c); 81 | }) == s.end(); 82 | } 83 | 84 | char* inet_htoa_r(char* buf, uint32_t haddr) { 85 | snprintf(buf, 16, "%hhu.%hhu.%hhu.%hhu", 86 | (uint8_t)((haddr >> 24) & 0xff), 87 | (uint8_t)((haddr >> 16) & 0xff), 88 | (uint8_t)((haddr >> 8) & 0xff), 89 | (uint8_t)(haddr & 0xff) 90 | ); 91 | return buf; 92 | } 93 | 94 | char* inet_ntoa_r(char* buf, uint32_t haddr) { 95 | snprintf(buf, 16, "%hhu.%hhu.%hhu.%hhu", 96 | (uint8_t)((haddr) & 0xff), 97 | (uint8_t)((haddr >> 8) & 0xff), 98 | (uint8_t)((haddr >> 16) & 0xff), 99 | (uint8_t)((haddr >> 24) & 0xff) 100 | ); 101 | return buf; 102 | } 103 | 104 | -------------------------------------------------------------------------------- /samples/shambles/vendor/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | libuv/ 3 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | -------------------------------------------------------------------------------- /src/forgery.cc: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 NCC Group 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #include "forgery.h" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | int const one = 1; 38 | static struct sockaddr_in const ipv4_anywhere = { AF_INET, 0, {inet_addr("127.0.0.1")}, {0} }; 39 | 40 | int8_t set_forged_sock_opts(int sock) { 41 | if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) { 42 | perror("set_forged_sock_opts:setsockopt:SOL_SOCKET/SO_REUSEADDR/one"); 43 | return -1; 44 | } 45 | return 1; 46 | } 47 | 48 | int8_t bind_forged_sock_ipv4_anywhere(int sock) { 49 | if (bind(sock, (struct sockaddr *)&ipv4_anywhere, sizeof(ipv4_anywhere)) < 0) { 50 | perror("bind_forged_sock_ipv4_anywhere:bind"); 51 | return -1; 52 | } 53 | return 1; 54 | } 55 | 56 | int8_t forge_tcp_state(int sock, tcp_state_t* forged_state) { 57 | if (setsockopt(sock, IPPROTO_TCP, TCP_STATE, forged_state, sizeof(tcp_state_t)) < 0) { 58 | perror("forge_tcp_state:setsockopt:IPPROTO_TCP/TCP_STATE/forged_state"); 59 | return -1; 60 | } 61 | return 1; 62 | } -------------------------------------------------------------------------------- /src/shambles.cc: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 NCC Group 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #include "shambles.h" 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | #include "util.h" 37 | 38 | 39 | void swap_pkt_data(pkt_data_t const * const _in, pkt_data_t * const _out) { 40 | _out->src_addr = _in->dst_addr; 41 | _out->dst_addr = _in->src_addr; 42 | 43 | _out->src_port = _in->dst_port; 44 | _out->dst_port = _in->src_port; 45 | 46 | _out->seq = _in->ack; 47 | _out->ack = _in->seq; 48 | } 49 | 50 | 51 | void swap_pkt_data_inline(pkt_data_t * const _self){ 52 | _self->src_addr = _self->src_addr ^ _self->dst_addr; 53 | _self->dst_addr = _self->src_addr ^ _self->dst_addr; 54 | _self->src_addr = _self->src_addr ^ _self->dst_addr; 55 | 56 | _self->src_port = _self->src_port ^ _self->dst_port; 57 | _self->dst_port = _self->src_port ^ _self->dst_port; 58 | _self->src_port = _self->src_port ^ _self->dst_port; 59 | 60 | _self->seq = _self->seq ^ _self->ack; 61 | _self->ack = _self->seq ^ _self->ack; 62 | _self->seq = _self->seq ^ _self->ack; 63 | } 64 | 65 | 66 | int8_t addr_in_subnet(uint32_t _addr, uint32_t _inner_addr, 67 | uint32_t _netmask) { 68 | if ( (_addr & _netmask) == (_inner_addr & _netmask) ) { 69 | return static_cast(true); 70 | } 71 | return static_cast(false); 72 | } 73 | 74 | 75 | 76 | ssize_t send_forged_sockets(forged_sockets_t const * const _fst, 77 | char const * const _path) { 78 | 79 | struct sockaddr_un saddr; 80 | int fd = socket(AF_LOCAL, SOCK_STREAM, 0); 81 | 82 | if (fd < 0) { 83 | perror("send_forged_sockets:socket"); 84 | return -1; 85 | } 86 | 87 | memset(&saddr, 0, sizeof(saddr)); 88 | strncpy(saddr.sun_path, _path, sizeof(saddr.sun_path)-1); 89 | //strcpy(saddr.sun_path, _path); //generally cli input, this is faster 90 | //n2s: learn to suppress clang-tidy 91 | // 107 bytes + 1 NUL (pre-nulled by memset) 92 | DEBUG_printf("%s\n", saddr.sun_path); 93 | saddr.sun_family = AF_LOCAL; 94 | 95 | if (connect(fd, reinterpret_cast(&saddr), 96 | sizeof(saddr)) < 0) { 97 | perror("send_forged_sockets:connect"); 98 | return -2; 99 | } 100 | 101 | struct msghdr msg = {0,0,0,0,0,0,0}; 102 | struct iovec iov[1]; 103 | struct cmsghdr *cmsg = NULL; 104 | int fds[2] = { _fst->outer_sock, _fst->inner_sock }; 105 | union { 106 | char buf[CMSG_SPACE(sizeof(fds))]; 107 | struct cmsghdr align; 108 | } u; 109 | int *fdptr; 110 | 111 | char data[] = "shambles"; 112 | 113 | iov[0].iov_base = data; 114 | iov[0].iov_len = sizeof(data); 115 | 116 | msg.msg_control = u.buf; 117 | msg.msg_controllen = sizeof(u.buf); 118 | msg.msg_name = NULL; 119 | msg.msg_namelen = 0; 120 | msg.msg_iov = iov; 121 | msg.msg_iovlen = 1; 122 | 123 | cmsg = CMSG_FIRSTHDR(&msg); 124 | cmsg->cmsg_level = SOL_SOCKET; 125 | cmsg->cmsg_type = SCM_RIGHTS; 126 | cmsg->cmsg_len = CMSG_LEN(sizeof(int) * 2); 127 | fdptr = (int *) CMSG_DATA(cmsg); 128 | memcpy(fdptr, fds, sizeof(int) * 2); 129 | 130 | return sendmsg(fd, &msg, 0); 131 | } 132 | 133 | ssize_t send_forged_sockets2(int fd, forged_sockets_t const * const _fst) { 134 | 135 | struct msghdr msg = {0,0,0,0,0,0,0}; 136 | struct iovec iov[1]; 137 | struct cmsghdr *cmsg = NULL; 138 | int fds[2] = { _fst->outer_sock, _fst->inner_sock }; 139 | union { 140 | char buf[CMSG_SPACE(sizeof(fds))]; 141 | struct cmsghdr align; 142 | } u; 143 | int *fdptr; 144 | 145 | char data[] = "shambles"; 146 | 147 | iov[0].iov_base = data; 148 | iov[0].iov_len = sizeof(data); 149 | 150 | msg.msg_control = u.buf; 151 | msg.msg_controllen = sizeof(u.buf); 152 | msg.msg_name = NULL; 153 | msg.msg_namelen = 0; 154 | msg.msg_iov = iov; 155 | msg.msg_iovlen = 1; 156 | 157 | cmsg = CMSG_FIRSTHDR(&msg); 158 | cmsg->cmsg_level = SOL_SOCKET; 159 | cmsg->cmsg_type = SCM_RIGHTS; 160 | cmsg->cmsg_len = CMSG_LEN(sizeof(int) * 2); 161 | fdptr = (int *) CMSG_DATA(cmsg); 162 | memcpy(fdptr, fds, sizeof(int) * 2); 163 | 164 | return sendmsg(fd, &msg, 0); 165 | } -------------------------------------------------------------------------------- /src/shambles_intercept.cc: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 NCC Group 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #include "shambles.h" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include 45 | 46 | #include "conntrack.h" 47 | #include "forgery.h" 48 | #include "util.h" 49 | 50 | constexpr static char const dnat[] = "iptables -t nat -%c PREROUTING -m state --state INVALID,NEW,RELATED,ESTABLISHED -p tcp -s %s --sport %hu -d %s --dport %hu -j DNAT --to-destination %s:%hu"; 51 | constexpr static uint16_t dnat_size = sizeof(dnat) - 1 + 14 + 2 + 14 + 2 + 14 + 2; 52 | 53 | 54 | constexpr static char const snat[] = "iptables -t nat -%c POSTROUTING -m state --state INVALID,NEW,RELATED,ESTABLISHED -p tcp -s %s --sport %hu -d %s --dport %hu -j SNAT --to-source %s:%hu"; 55 | constexpr static uint16_t snat_size = sizeof(snat) - 1 + 14 + 2 + 14 + 2 + 14 + 2; 56 | 57 | //constexpr static char const conntrackD[] = "conntrack -D --orig-src %s --orig-dst %s -p tcp --orig-port-src %hu --orig-port-dst %hu --reply-port-src %hu --reply-port-dst %hu --reply-src %s --reply-dst %s"; 58 | //constexpr static uint16_t conntrackD_size = sizeof(conntrackD) + 13 + 13 + 2 + 2 + 2 + 2 + 13 + 13; 59 | 60 | //constexpr static char const conntrackI[] = "conntrack -I --orig-src %s --orig-dst %s -p tcp --orig-port-src %hu --orig-port-dst %hu --reply-port-src %hu --reply-port-dst %hu --reply-src %s --reply-dst %s --timeout 60 --state ESTABLISHED"; 61 | //constexpr static uint16_t conntrackI_size = sizeof(conntrackI) + 13 + 13 + 2 + 2 + 2 + 2 + 13 + 13; 62 | 63 | 64 | 65 | int8_t intercept(forged_sockets_t* _out, pkt_data_t const * const _pd, 66 | uint32_t const _outer_addr, uint32_t const _inner_addr) { 67 | 68 | DEBUG_printf("%s\n", __func__); 69 | #ifdef DEBUG 70 | pkt_data_dump(_pd); 71 | #endif 72 | 73 | char inner_addr_str[16] = {0}; 74 | inet_ntoa_r(inner_addr_str, _inner_addr); 75 | 76 | char outer_addr_str[16] = {0}; 77 | inet_ntoa_r(outer_addr_str, _outer_addr); 78 | 79 | 80 | char dst_addr[16] = {0}; 81 | inet_ntoa_r(dst_addr, _pd->dst_addr); 82 | 83 | char src_addr[16] = {0}; 84 | inet_ntoa_r(src_addr, _pd->src_addr); 85 | 86 | 87 | DEBUG_printf("Deleting old conntrack entry."); 88 | int32_t delret = conntrack_ipv4_tcp( 89 | _pd->src_addr, _pd->dst_addr, 90 | _pd->src_port, _pd->dst_port, 91 | _pd->dst_port, _pd->src_port, 92 | _pd->dst_addr, _outer_addr 93 | ); 94 | if (delret != 1) { 95 | printf("delret: %d\n", delret); 96 | return -1; 97 | } 98 | 99 | 100 | DEBUG_printf("Injecting new conntrack entries."); 101 | int32_t injret = conntrack_ipv4_tcp( 102 | _outer_addr, _pd->dst_addr, 103 | _pd->src_port, _pd->dst_port, 104 | _pd->dst_addr, _outer_addr, 105 | _pd->dst_port, _pd->src_port 106 | ); 107 | if (injret != 1) { 108 | printf("injret: %d\n", injret); 109 | return -2; 110 | } 111 | 112 | 113 | char dnat_command[dnat_size] = {0}; 114 | snprintf(dnat_command, dnat_size, dnat, 115 | 'A', src_addr, ntohs(_pd->src_port), dst_addr, ntohs(_pd->dst_port), 116 | inner_addr_str, ntohs(_pd->dst_port) 117 | ); 118 | DEBUG_printf("# %s\n", dnat_command); 119 | system(dnat_command); 120 | 121 | 122 | char snat_command[snat_size] = {0}; 123 | snprintf(snat_command, snat_size, snat, 124 | 'A', inner_addr_str, ntohs(_pd->dst_port), src_addr, ntohs(_pd->src_port), 125 | dst_addr, ntohs(_pd->dst_port) 126 | ); 127 | DEBUG_printf("# %s\n", snat_command); 128 | system(snat_command); 129 | 130 | 131 | struct tcp_state *fake_server = (tcp_state_t *)calloc(1, sizeof(tcp_state_t)); 132 | if (fake_server == nullptr) { 133 | return -3; 134 | } 135 | struct tcp_state *fake_client = (tcp_state_t *)calloc(1, sizeof(tcp_state_t)); 136 | if (fake_client == nullptr) { 137 | free(fake_server); 138 | return -4; 139 | } 140 | 141 | 142 | int client_sock = socket(AF_INET, SOCK_FORGE, 0); 143 | if (client_sock == -1) { 144 | perror("intercept:socket->client_sock"); 145 | free(fake_server); 146 | free(fake_client); 147 | return -5; 148 | } 149 | int server_sock = socket(AF_INET, SOCK_FORGE, 0); 150 | if (server_sock == -1) { 151 | perror("intercept:socket->server_sock"); 152 | close(client_sock); 153 | free(fake_server); 154 | free(fake_client); 155 | return -6; 156 | } 157 | 158 | if (set_forged_sock_opts(client_sock) != 1) { 159 | close(client_sock); 160 | close(server_sock); 161 | free(fake_server); 162 | free(fake_client); 163 | return -7; 164 | } 165 | if (set_forged_sock_opts(server_sock) != 1) { 166 | close(client_sock); 167 | close(server_sock); 168 | free(fake_server); 169 | free(fake_client); 170 | return -8; 171 | } 172 | 173 | if (bind_forged_sock_ipv4_anywhere(client_sock) != 1) { 174 | close(client_sock); 175 | close(server_sock); 176 | free(fake_server); 177 | free(fake_client); 178 | return -9; 179 | } 180 | if (bind_forged_sock_ipv4_anywhere(server_sock) != 1) { 181 | close(client_sock); 182 | close(server_sock); 183 | free(fake_server); 184 | free(fake_client); 185 | return -10; 186 | } 187 | 188 | fake_client->src_ip = _outer_addr; 189 | fake_client->dst_ip = _pd->dst_addr; 190 | fake_client->sport = _pd->src_port; 191 | fake_client->dport = _pd->dst_port; 192 | fake_client->seq = ntohl(_pd->seq); 193 | fake_client->ack = ntohl(_pd->ack); 194 | fake_client->snd_una = ntohl(_pd->seq); 195 | fake_client->snd_wnd = 0x1000; 196 | fake_client->rcv_wnd = 0x1000; 197 | 198 | 199 | fake_server->src_ip = _inner_addr; 200 | fake_server->dst_ip = _pd->src_addr; 201 | fake_server->sport = _pd->dst_port; 202 | fake_server->dport = _pd->src_port; 203 | fake_server->seq = ntohl(_pd->ack); 204 | fake_server->ack = ntohl(_pd->seq); 205 | fake_server->snd_una = ntohl(_pd->ack); 206 | fake_server->snd_wnd = 0x1000; 207 | fake_server->rcv_wnd = 0x1000; 208 | 209 | 210 | if (forge_tcp_state(client_sock, fake_server) != 1) { 211 | close(client_sock); 212 | close(server_sock); 213 | free(fake_server); 214 | free(fake_client); 215 | return -11; 216 | } 217 | if (forge_tcp_state(server_sock, fake_client) != 1) { 218 | close(client_sock); 219 | close(server_sock); 220 | free(fake_server); 221 | free(fake_client); 222 | return -12; 223 | } 224 | 225 | 226 | _out->outer_sock = server_sock; 227 | _out->inner_sock = client_sock; 228 | 229 | 230 | free(fake_server); 231 | free(fake_client); 232 | return 1; 233 | } 234 | 235 | 236 | int8_t intercept_teardown(pkt_data_t const * const _pd, 237 | uint32_t const _outer_addr, 238 | uint32_t const _inner_addr) { 239 | DEBUG_printf("%s\n", __func__); 240 | 241 | char inner_addr_str[16] = {0}; 242 | inet_ntoa_r(inner_addr_str, _inner_addr); 243 | 244 | char outer_addr_str[16] = {0}; 245 | inet_ntoa_r(outer_addr_str, _outer_addr); 246 | 247 | 248 | char dst_addr[16] = {0}; 249 | inet_ntoa_r(dst_addr, _pd->dst_addr); 250 | 251 | char src_addr[16] = {0}; 252 | inet_ntoa_r(src_addr, _pd->src_addr); 253 | 254 | char dnat_command[dnat_size] = {0}; 255 | snprintf(dnat_command, dnat_size, dnat, 256 | 'D', src_addr, ntohs(_pd->src_port), dst_addr, ntohs(_pd->dst_port), 257 | inner_addr_str, ntohs(_pd->dst_port) 258 | ); 259 | DEBUG_printf("# %s\n", dnat_command); 260 | system(dnat_command); 261 | 262 | char snat_command[snat_size] = {0}; 263 | snprintf(snat_command, snat_size, snat, 264 | 'D', inner_addr_str, ntohs(_pd->dst_port), src_addr, ntohs(_pd->src_port), 265 | dst_addr, ntohs(_pd->dst_port) 266 | ); 267 | DEBUG_printf("# %s\n", snat_command); 268 | system(snat_command); 269 | 270 | return 0; 271 | } 272 | 273 | 274 | -------------------------------------------------------------------------------- /src/util.cc: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 NCC Group 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #include "util.h" 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | 34 | uint8_t parse_ipv4(const char* str, uint64_t len) { 35 | uint8_t digits = 0; 36 | uint8_t vals[3] = { 0,0,0 }; 37 | uint8_t dots = 0; 38 | uint16_t seg = 0; 39 | for (uint64_t i = 0; i < len; i++) { 40 | char c = str[i]; 41 | if ('0' <= c && c <= '9') { 42 | vals[digits] = (uint16_t)c ^ 0x30; 43 | digits++; 44 | if (digits > 3) { 45 | return 1; 46 | } 47 | } else if (c == '.') { 48 | if (i+1 == len || dots == 3) { 49 | return 2; 50 | } 51 | if (digits == 1) { 52 | seg = vals[0]; 53 | } else if (digits == 2) { 54 | seg = vals[0]*10 + vals[1]; 55 | } else if (digits == 3) { 56 | seg = vals[0]*100 + vals[1]*10 + vals[2]; 57 | } 58 | 59 | if (seg > 255) { 60 | return 3; 61 | } 62 | digits = 0; seg = 0; 63 | dots++; 64 | if (dots > 3) { 65 | return 4; 66 | } 67 | } else { 68 | return 5; 69 | } 70 | } 71 | if (dots == 3) { 72 | return 0; 73 | } 74 | return 6; 75 | } 76 | 77 | char* inet_htoa_r(char* buf, uint32_t haddr) { 78 | snprintf(buf, 16, "%hhu.%hhu.%hhu.%hhu", 79 | (uint8_t)((haddr >> 24) & 0xff), 80 | (uint8_t)((haddr >> 16) & 0xff), 81 | (uint8_t)((haddr >> 8) & 0xff), 82 | (uint8_t)(haddr & 0xff) 83 | ); 84 | return buf; 85 | } 86 | 87 | char* inet_ntoa_r(char* buf, uint32_t haddr) { 88 | snprintf(buf, 16, "%hhu.%hhu.%hhu.%hhu", 89 | (uint8_t)((haddr) & 0xff), 90 | (uint8_t)((haddr >> 8) & 0xff), 91 | (uint8_t)((haddr >> 16) & 0xff), 92 | (uint8_t)((haddr >> 24) & 0xff) 93 | ); 94 | return buf; 95 | } 96 | 97 | char hdc(uint8_t const _element) { 98 | if ( 0x20 <= _element && _element <= 0x7e) { 99 | return _element; 100 | } else { 101 | return '.'; 102 | } 103 | } 104 | 105 | void hexdump_line(uint8_t const * const _data, uint16_t const off) { 106 | printf( "%04x %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx " 107 | " %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx" 108 | " %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" 109 | "\n", 110 | off, _data[0], _data[1], _data[2], _data[3], 111 | _data[4], _data[5], _data[6], _data[7], 112 | _data[8], _data[9], _data[10], _data[11], 113 | _data[12], _data[13], _data[14], _data[15], 114 | hdc(_data[0]), hdc(_data[1]), hdc(_data[2]), hdc(_data[3]), 115 | hdc(_data[4]), hdc(_data[5]), hdc(_data[6]), hdc(_data[7]), 116 | hdc(_data[8]), hdc(_data[9]), hdc(_data[10]), hdc(_data[11]), 117 | hdc(_data[12]), hdc(_data[13]), hdc(_data[14]), hdc(_data[15]) 118 | ); 119 | } 120 | 121 | void hexdump(uint8_t const * const _data, uint16_t const _data_len) { 122 | uint16_t modlen = _data_len % 16; 123 | uint16_t looplen = _data_len - modlen; 124 | printf("modlen: %hu looplen: %hu\n", modlen, looplen); 125 | uint16_t i = 0; 126 | if (looplen >= 16) { 127 | for (; i < looplen; i+=16) { 128 | hexdump_line( &(_data[i]), i); 129 | } 130 | if ( modlen == 0 ) { 131 | return; 132 | } 133 | } 134 | uint8_t rem[16] = {0}; 135 | printf("uint8_t rem[16] = {0};\n"); 136 | memcpy(rem, &(_data[i]), modlen); 137 | printf("memcpy(rem, &(_data[i]), modlen);\n"); 138 | hexdump_line(rem, i); 139 | printf("hexdump_line(rem, i);\n"); 140 | } 141 | 142 | void tcp_state_dump(tcp_state_t const * const _tst) { 143 | char buf[16]; 144 | printf( "src_ip: %s\n" 145 | "dst_ip: %s\n" 146 | "sport: %hu\n" 147 | "dport: %hu\n", 148 | inet_ntoa_r(buf, _tst->src_ip), 149 | inet_ntoa_r(buf, _tst->dst_ip), 150 | ntohs(_tst->sport), ntohs(_tst->dport) 151 | ); 152 | printf( "seq: %x\n" 153 | "ack: %x\n", 154 | _tst->seq, _tst->ack 155 | ); 156 | 157 | printf("snd_una: %x\n", _tst->snd_una); 158 | printf("tstamp_ok: %hhx\n", _tst->tstamp_ok); 159 | printf("sack_ok: %hhx\n", _tst->sack_ok); 160 | printf("wscale_ok: %hhx\n", _tst->wscale_ok); 161 | printf("ecn_ok: %hhx\n", _tst->ecn_ok); 162 | printf("snd_wscale: %hhx\n", _tst->snd_wscale); 163 | printf("rcv_wscale: %hhx\n", _tst->rcv_wscale); 164 | printf("snd_wnd: %x\n", _tst->snd_wnd); 165 | printf("rcv_wnd: %x\n", _tst->rcv_wnd); 166 | printf("ts_recent: %x\n", _tst->ts_recent); 167 | printf("ts_val: %x\n", _tst->ts_val); 168 | printf("mss_clamp: %x\n", _tst->mss_clamp); 169 | } 170 | 171 | void pkt_data_dump(pkt_data_t const * const _pdt) { 172 | char buf1[16]; 173 | char buf2[16]; 174 | printf( "src_addr: %s\n" 175 | "dst_addr: %s\n" 176 | "src_port: %hu\n" 177 | "dst_port: %hu\n", 178 | inet_ntoa_r(buf1, _pdt->src_addr), 179 | inet_ntoa_r(buf2, _pdt->dst_addr), 180 | ntohs(_pdt->src_port), ntohs(_pdt->dst_port) 181 | ); 182 | printf( "seq: %x\n" 183 | "ack: %x\n", 184 | _pdt->seq, _pdt->ack 185 | ); 186 | 187 | hexdump(_pdt->msg, ntohs(_pdt->msg_len)); 188 | } 189 | 190 | /* 191 | void hook_data_dump(hook_data_t const * const _hdt) { 192 | char buf[16]; 193 | printf( "outer_addr: %s\n" 194 | "inner_addr: %s\n" 195 | "outer_port: %hu\n" 196 | "innet_port: %hu\n", 197 | inet_ntoa_r(buf, _hdt->outer_addr), 198 | inet_ntoa_r(buf, _hdt->inner_addr), 199 | ntohs(_hdt->outer_port), ntohs(_hdt->inner_port) 200 | ); 201 | } 202 | */ 203 | 204 | -------------------------------------------------------------------------------- /vendor/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | --------------------------------------------------------------------------------