├── ChangeLog ├── FAQ ├── INSTALL ├── LICENSE ├── Makefile.am ├── README ├── README.md ├── TODO ├── VERSION ├── bootstrap ├── configure.ac ├── releases ├── thc-rut-2-2-6-rc1_static_binary_RaspberryPi_ARM-V7L_32-pc-linux-gnu ├── thc-rut-2-2-6-rc1_static_binary_x86_64-pc-linux-gnu └── thc-rut-2.2.6-rc1.tar.gz ├── src ├── Makefile.am ├── arp_main.c ├── arp_main.h ├── arpg.c ├── arpg.h ├── asn.c ├── asn.h ├── dcd_icmp.c ├── dcd_icmp.h ├── default.h ├── dhcp.c ├── dhcp.h ├── dhcp_main.c ├── dhcp_main.h ├── discover_dispatch.c ├── discover_dispatch.h ├── discover_main.c ├── discover_main.h ├── fp.c ├── fp.h ├── gen_macvendor-list-h.py ├── icmp_main.c ├── icmp_main.h ├── macvendor.c ├── macvendor.h ├── macvlist.h ├── network.c ├── network.h ├── network_raw.c ├── network_raw.h ├── nmap-os-fingerprints ├── nmap_compat.c ├── nmap_compat.h ├── nvt.c ├── nvt.h ├── packets.c ├── packets.h ├── range.c ├── range.h ├── schedule.c ├── schedule.h ├── state.c ├── state.h ├── system.c ├── system.h ├── thc-rut.c ├── thc-rut.h ├── thcrut-os-fingerprints ├── thcrut_libnet.c ├── thcrut_libnet.h ├── thcrut_pcap.c ├── thcrut_pcap.h ├── thcrut_sig.c ├── thcrut_sig.h ├── tty.c └── tty.h ├── stamp-h.in └── thcrutlogo.txt /ChangeLog: -------------------------------------------------------------------------------- 1 | 1.2.5 (2003-05-30) 2 | - ph-neutral relaese. Everyone is pretty drunken but I fixed 3 | an ugly bug. First ip of ip range was always skipped. 4 | 5 | 1.2.4 (2003-05-28) 6 | - 'any' device support 7 | - ported to OpenBSD. 8 | - ported to FreeBSD (what a bitch!). 9 | - integrated Libnet into the package 10 | - new fingerprints (and fixed some wrong fp's). 11 | - status bar (press space!) 12 | 13 | 1.2.3 (2003-01-27) 14 | - rewrote SNMP parsing 15 | - new fingerprints 16 | 17 | 1.2.2 (2003-01-01) 18 | - Many more fingerprints 19 | - fixed segfault, \0 overwrite in NVT mode 20 | 21 | 1.2.1 (2002-12-29) 22 | - infinite loop fix in hash table 23 | - more fingerprints 24 | 25 | 1.2 (2002-12-27) 26 | - perl reg. expr. 27 | - rewrite of the scheduler engine. 28 | 29 | 0.4 (2001-08-18) 30 | - unofficial release 31 | - state idea implemented 32 | - fingerprinter by banners 33 | 34 | 0.3 (2001-xx-zz) 35 | - first release 36 | 37 | -------------------------------------------------------------------------------- /FAQ: -------------------------------------------------------------------------------- 1 | 2 | THCRUT FAQ. 3 | Contact me if any of your questions can not be answered by this FAQ. 4 | anonymous@segfault.net or any of the THC guys. 5 | 6 | Contents 7 | 1 - Compilation & Installation 8 | 1.1 - Does not compile :/ Baehehahah 9 | 2 - Using thcrut 10 | 2.1 - Why does my CPU jump to 100% after a few minutes? 11 | 2.2 - Why is thcrut so slow on local networks? 12 | 13 | --[ 1 - Compilation & Installation 14 | 15 | 1.1 - Does not compile :/ Baehehahah 16 | 17 | First try ./configure --enable-dist. This configures thcrut to use 18 | its own version of libnet and libpcre. 19 | 20 | If this wont work try to use --with-include= and --with-libs= 21 | to set the correct include and library path of the libpcap files. 22 | 23 | 24 | --[ Using thcrut 25 | 26 | 2.1 - Why does my CPU jump to 100% after a few minutes? 27 | 28 | Some linux kernel (my 2.4.19-gentoo-r10) require >5000 ms for a simple 29 | sendto() system call _after_ a lot of packets have been send to _many_ (>16.000) 30 | different IPs. Update your kernel (sendto() remains at 12ms after 1.000.000 31 | sendto() calls on the 2.4.20 stock kernel). 32 | 33 | 2.2 - Why is thcrut so slow on local networks? 34 | 35 | The kernel has to resolve the mac of every computer on the local 36 | network first. This makes the system slow. Sometimes the arp table 37 | overflows in which case thcrut tries to resend the packet. 38 | 39 | Solution: Use -l 100 or less if you have a slow machiene and want to 40 | scan a local network. 41 | 42 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | $ ./configure && make all install 2 | 3 | It should compile fine on any decent unix version. I tested it on 4 | 5 | - Linux 2.4 6 | - OpenBSD 7 | - FreeBSD 8 | - Solaris 2.8 9 | 10 | It wont work on old unixes 11 | - Red Hat 6.2 (egcs problem that __func__ is not defined) 12 | 13 | feedback is welcome 14 | 15 | anonymous@segfault.net 16 | 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | THC-RUT LICENSE - SHORT & SIMPLE 2 | 3 | THC-RUT is free for any non-commercial use. THC-RUT is not allowed 4 | to be used in any commercial program without written permission 5 | of the author (that's currently me! I've not denied a single request 6 | so far. Just want to know who is using it.). 7 | 8 | I reserve the right to deny the use of THC-RUT or the implemented 9 | techniques to anyone at any time. 10 | 11 | anonymous@segfault.net 12 | (c) THC - http://www.thc.org 13 | 14 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src 2 | EXTRA_DIST = config bootstrap thcrutlogo.txt 3 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | THC-RUT - http://www.thc.org/thc-rut - anonymous@segfault.net 2 | 3 | 'When your mind is going hither 4 | and thither, discrimiation will 5 | never be brought to a conclustion. 6 | With an intense, fresh and 7 | underlaying spirit, one will make 8 | his judgments within the space of 9 | seven breaths. 10 | It is a matter of being determined 11 | and having the spirit to break 12 | right through to the other side.' 13 | ...Hagakure, the way of the samurai 14 | ...by Yamamoto Tsunetomo 15 | 16 | 17 | [0x01] What is THC-RUT: 18 | 19 | RUT (aRe yoU There, pronouced as 'root') is your first knife on foreign 20 | network. It gathers informations from local and remote networks. 21 | 22 | It offers a wide range of network discovery tools: arp lookup on 23 | an IP range, spoofed DHCP request, RARP, BOOTP, ICMP-ping, ICMP 24 | address mask request, OS fingerprintings, high-speed host discovery, ... 25 | 26 | THC-RUT now comes with a new OS Fingerprint implementation. It gathers 27 | tcp stack informations, banners, open/closed port characteristics and 28 | timing values and tosses them through a perl regular expression matrix to 29 | determine the OS with high accuracy. 30 | 31 | The tool is capable of discovering a Class B network within 10 minutes. 32 | Banner information are taken from (amoung others) SNMP replies, 33 | telnetd (NVT) negotiation options, generic Banner Matching, HTTP-Server 34 | version, DCE request and tcp options. 35 | 36 | The homepage can be found at http://www.thc.org/thc-rut. 37 | 38 | [0x02] History of THC-RUT 39 | 40 | THCrut has been rewritten and changed into a general local network 41 | discovery tool. 42 | 43 | It comes with a new OS Fingerprinting technique and facilates in addition 44 | to this nmap fingerprinting methods. The implementation requires less 45 | memory and is faster on large networks (speaking of Class B or larger). 46 | 47 | The first THC-RUT release has been written when the first wavelan AP'es 48 | popped up. It's purpose was to brute force wvlan (IEEE 802.11b) access 49 | points that used mac authentication. Time has passed since the early days 50 | of wvlan hacking. Extensive research has been conducted and more 51 | sophisticated tools are now available. 52 | 53 | [0x03] How to use 54 | 55 | I dont feel like explaining how to use the tool. It's pretty much 56 | straightforwards. Anyone with half a brain should be able to use 57 | it - others dont have to. 58 | 59 | Just the basics: 60 | 61 | An IP range looks like this: 62 | 63 | 192.168.0.1-192.168.255.254 # 2^16-2 hosts (Class B) 64 | 192.168.0.0/24 # 2^8-2 hosts (192.168.0.1 - 192.168.0.254) 65 | 192.168.0.50-30 # 192.168.0.50 - 192.168.0.80 66 | 67 | Scanning on local network is citical. Some devices can not 68 | handle the arp request storm and will drop packets. You should 69 | not scan faster than 100 hosts in parallel on a local network. 70 | If you scan a remote network you can go up until 71 | 5000 hosts in parallel without any problems. 72 | 73 | The fingerprinter appears to be slow against a single host. Some devices 74 | only support one tcp connection at the same time (some printers, routers) 75 | and we thus are very carefull to not miss a banner. 76 | The connect timeout is set to 5 seconds and the read timeout 77 | to 35 seconds. Again, we have to consider stupid setups that try 78 | to resolve our IP before (timeout of 30 seconds) before they 79 | show us the banner. 80 | 81 | [0x04] Comments 82 | 83 | Recently there was a media hype when some monkey.org guy released his 84 | 'new syncookie driven mega fast best of best' paketto scanner 'which 85 | he already demonstrated at blackhat' (Hossa! _must_ be the shit if it 86 | has been presented at blackhat :>.). 87 | 88 | In 1998 an israeli group released a paper on bugtraq which documented 89 | their development and use of a high speed TCP port scanner. The tool 90 | was capable of scanning the entire internet. The tool was very well 91 | written but did not support states and had some other difficulites. 92 | (I lost the URL to that posting. mail me if you have it.). 93 | 94 | In 1999 an unknown group developed bscan which was used in a counterstrike 95 | operation to take down several 10.000 node strong flood networks which 96 | threatened the internet during that period (I call it 'the kid period' of 97 | the internet. Any halfgrown kid with the small penis syndrome thougth that 98 | DDoS is be the ultimate art of hacking. Fools.). Bscan was the first 99 | tool which scanned the internet serveral times on specific ports (the 100 | ports used by the DDoS agents) within a single month. The SANS institute 101 | categorized it as a 'ddos tool' itself after they found it in the wild. 102 | In their opinion is everything that sends out syn packets at a rate of 103 | 10.000 / sec a DDoS tool :>. Bscan had a modular design and came with a 104 | bind module, httpd_verson module, snmp modules, .. and was capable to 105 | establish a full spoofed tcp connection using raw socket (and like the 106 | israeli tool used the syncookie method). 107 | Also Bscan was not perfect. It missed state support and an enhanced logging 108 | facility. 109 | 110 | So this paketto with his (quote) "reverse syncookie technique" is a very 111 | old idea. Paketto does not address the real problems of high speed network 112 | scanning (no, it's not done with putting a sendto() call into a while 113 | loop :> see below). 114 | 115 | THC-RUT is by far not perfect - it does not intend to be. It also 116 | does not intend to replace bscan or the israeli tool. It's an 117 | add-on, not a replacement. 118 | 119 | THC-RUT comes with a state table and retransmit lost packets. THC RUT 120 | started as a simple arp sending packet which spoofed mac's, turned into a 121 | usefull local network discovery tool and became a OS fingerprinter and 122 | host discovery tool for large networks in its last release. 123 | 124 | 125 | [0x05] The real problem of High-speed network scanning 126 | 127 | The real problems are mac resolving problems, router that send broken 128 | tcp packets as answer, devices that can only handle one connection at a 129 | time, MAC table overflow of remote routers, BGP routers that go 130 | spinnlooping when hit by the scan stream, Half NAT'ed routers (send a 131 | sync to 1.2.3.4 and get the sync/ack from 4.3.2.1), pseudo intelligent 132 | firewalls which block the stream and retransmitting packets (You have 133 | packetlost by scanning a Class A network - at one router or the other.). 134 | 135 | FIXME: write more about why spread-scan mode is mandatory and not 136 | optional. talk about volatile routes etc. 137 | 138 | FIXME: Talk about routers that only accept one TCP connection. 139 | 140 | [0x06] OS fingerprinting 141 | 142 | Let me define some words that I will use throughout this lame README: 143 | 144 | An information is a single entity of data. 145 | 146 | OS fingerprinting is the technique to identify the OS by information 147 | which is unique for every OS. 148 | 149 | The maximum number of different OS types that can be detected 150 | is less or equal to the number of permutations over all informations. 151 | 152 | NMAP for examples uses (among others) the TCP OPTION's to 153 | distinguish between OSes. The number of TCP OPTIONS is limited which 154 | makes the number of permutations finite also. The result is that only 155 | a limited number (e.g. the number of different permutations) can 156 | be distinguished by NMAP. 157 | 158 | OS Fingerprinting results can be cathegorized into 3 parts: 159 | 160 | - low precission: Type of the device (Firewall, printer, switch, ...) 161 | - middle precission: OS or architecture 162 | - high precission: Type, Hotfix number, build version, ... 163 | 164 | Several tools for remote OS Fingerprinting exist. Among them are state 165 | of the art tools like nmap or xprobe2. Other tools like queso and passiv 166 | OS Fingerprinting tools are either outdated or lag a large database of 167 | fingerprints. 168 | 169 | Recently the Intranode Research Team came up with a new idea called 170 | 'temporal response analysis'. FIXME. 171 | 172 | Papers have been written en-mass (FIXME) about different 173 | 174 | All presented solution fit some specific requirements and work under 175 | certain circumstances. Most of them (nmap) rely on static pattern matching 176 | and others (xprobe2) do not work reliable on the internet or through 177 | firewalls or suffer from a well tested database. 178 | 179 | Xprobe2 and nmap give good results with middle precission. Nmap fails 180 | far to often in the low precission field and detects a Baynet router 181 | where a Win2k with some patches is in place. The high precission can not 182 | be achieved by any of the existing tools as the TCP/IP stack does not 183 | change for every hotfix or patch that is used. 184 | 185 | THC-RUT is different. I do not believe in OS fingerprinting 186 | masturbation but in working code and good results. 187 | 188 | THC-RUT OS Fingerprinting identified the remote OS by matching the 189 | following 'informations': 190 | 191 | - Banner (snmp, web, telnet, ftp, smtp, ..) 192 | - Open Port characterisitc (certain router have certain ports open 193 | by default) 194 | - NMAP like OS fingerprinting technqiues (TCP options + ICMP + TTL). 195 | 196 | THC-RUT gives results after a 'fits best' method without relying on 197 | static pattern matching. 198 | 199 | THC-RUT enumerates the OS which makes it easier to use the output 200 | in third party applications. 201 | 202 | THC-RUT cathegorizes the findings into classes, type of host, os, arch, 203 | version etc. If the OS can not be determined then at least the 204 | genre (firewall, host, printer, router, switch, ..) can be determined. 205 | 206 | THC-RUT is fast on large networks and 'slow' (well, compare it to 207 | nmap if you like) on single hosts. 208 | 209 | 210 | Yours sincerely, 211 | 212 | The Hacker's Choice 213 | http://www.thc.org 214 | 215 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # thc-rut 2 | THC "R U There" network discovery tool - faster than most (all?). 3 | 4 | 2003 - Original release 5 | 2020 - Ported to MacOS, FreeBSD, Linux and Libnet-1.3 6 | 7 | Direct Download: [https://github.com/hackerschoice/thc-rut/tree/master/releases/](https://github.com/hackerschoice/thc-rut/tree/master/releases/) 8 | 9 | **Install:** 10 | ``` 11 | $ ./configure --enable-static 12 | $ make all 13 | ``` 14 | 15 | **Examples:** 16 | 17 | ICMP/Ping all hosts on a Class B network takes **11 seconds**. 18 | ``` 19 | thc-rut icmp -l 25000 192.168.0.1/16 20 | ``` 21 | 22 | ICMP/Ping hosts that are firewalled (using ICMP timestamp requests instead) 23 | ``` 24 | # thc-rut icmp -T 25 | ``` 26 | 27 | ARP/Ping all hosts on the local network: 28 | ``` 29 | # thc-rut arp 30 | 192.168.1.1 b4:fb:e4:e5:a5:d5 Ubiquiti Networks Inc. 31 | 192.168.1.190 6c:4d:73:d4:b6:da Apple, Inc. 32 | 192.168.1.38 e0:46:9a:31:01:d4 Netgear 33 | 192.168.1.105 c4:67:b5:33:b1:70 Libratone A/S 34 | 192.168.1.106 3e:97:69:5a:53:f8 Intel Corporate 35 | 192.168.1.45 00:17:88:71:d7:e6 Philips Lighting BV 36 | ``` 37 | 38 | ARP/Ping using a 'ghost' MAC (mac spoofing): 39 | ``` 40 | # thc-rut arp -m de:ad:be:ef:13:37 10.0.0.0-10.0.0.20 41 | ``` 42 | 43 | DHCP test requests: 44 | ``` 45 | # thc-rut dhcp 46 | ``` 47 | 48 | DHCP Denial-Of-Service (exhaust DHCP server and prevent anyone else from joining the network): 49 | ``` 50 | # thc-rut -F dhcp -m 0 51 | ``` 52 | 53 | All Commands: 54 | ``` 55 | discover Host discovery and OS fingerprinting 56 | icmp ICMP discovery 57 | dhcp DHCP discovery 58 | arp ARP discovery 59 | ``` 60 | 61 | ICMP options: 62 | ``` 63 | -P ICMP echo request (default) 64 | -T ICMP Timestamp Request 65 | -A ICMP Address mask request (obsolete) 66 | -R ICMP MCAST Router solicitation request 67 | ``` 68 | 69 | DHCP options: 70 | ``` 71 | -m source mac (interace's default or -m 0 for random) 72 | -d destination mac (default: broadcast) 73 | -D DHCP option, 0=List DHCP options, all=ALL (!) 74 | ``` 75 | 76 | ARP options: 77 | ``` 78 | -m source MAC (source interface) 79 | ``` 80 | 81 | DISCOVER options: 82 | ``` 83 | -d Don't do host discovery (tcp-sync ping, ...) 84 | -O With OS Fingerprinting 85 | -v verbose output (fingerprint stamps) 86 | -l Hosts in parallel (default: 5000) 87 | ``` 88 | 89 | Blast from the past: 90 | ``` 91 | _ 92 | _( (~\ 93 | _ _ / ( \> > \ 94 | -/~/ / ~\ :; \ _ > /(~\/ 95 | || | | /\ ;\ |l _____ |; ( \/ > > 96 | --------. _\\)\)\)/ ;;; `8o __-~ ~\ d| \ // 97 | * HELP * | ///(())(__/~;;\ "88p;. -. _\_;.oP (_._/ / 98 | * HELP * | (((__ __ \\ \ `>,% (\ (\./)8" ;:' i 99 | | )))--`.'-- (( ;,8 \ ,;%%%: ./V^^^V' ;. ;. 100 | I'M JUST | ((\ | /)) .,88 `: ..,,;;;;,-::::::'_::\ ||\ ;[8: ; 101 | STUPID ! )| ~-~ |(|(888; ..``'::::8888oooooo. :\`^^^/,,~--._ |88:: | 102 | WHITEHAT.|_____-===- /| \8;; ``:. oo.8888888888:`((( o.ooo8888Oo;:;:' | 103 | |. |_~-___-~_| `-\. ` `o`88888888b` )) 888b88888P""' ; 104 | PLEASE | ; ~~~~;~~ "`--_`. b`888888888;(.,"888b888" ..::;-' 105 | DONT HURT | ; ; ~"-.... b`8888888:::::.`8888. .:;;;'' 106 | MEEEEEE! | ; ; `:::. `:::OOO:::::::.`OO' ;;;'' 107 | | : ; `. "``::::::'' .' 108 | * HELP * | ; `. \_ / 109 | * HELP * | ; ; +: ~~-- `:' -'; 110 | __________! `: : .::/ -Tua Xiong 111 | ; ;;+_ :::. :..;;; 112 | -=[ (C) THE HACKERS CHOICE - Estd. 1995 ]=- -=[ www.ircsnet.net /j #THC ]=- 113 | ------=[ WHQ: http://www.thc.org ]=- - -=[ Enjoy your enemy... ]=---------- 114 | ``` 115 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | OINK OINK OINK OINK. You dont want to take a look at this file. OIN OINK OINK 2 | 3 | - Interpret FP's from a file full of banners etc.. 4 | (also put nmap-os-fingerprints in there. See BUGS/info.txt for more details). 5 | 6 | - The timeout for banner scans etc suxx. But we can bind to a certain 7 | port and then sniff the RST and instantly switch to next state 8 | if the port is closed. This would mean no 1 sec timeout for 9 | every port we check. 10 | 11 | - fast reverse ip resolver. 12 | - use nameservers from /etc/resolv.conf 13 | and/or nameserver the user can specify on command line. 14 | 15 | - better option support: 16 | thcrut dhcp 17 | thcrut icmp 18 | thcrut bootp 19 | thcrut arp 20 | thcrut dns 21 | thcrut rut 22 | 23 | 24 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.2.5 2 | -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # THCrut bootstrap file 4 | # anonymous@segfault.net 5 | 6 | DIE=0 7 | 8 | (autoconf --version) < /dev/null > /dev/null 2>&1 || { 9 | echo 10 | echo "You must have autoconf installed." 11 | DIE=1 12 | } 13 | 14 | # libtool --version check not done... 15 | 16 | (automake --version) < /dev/null > /dev/null 2>&1 || { 17 | echo 18 | echo "You must have automake installed." 19 | DIE=1 20 | } 21 | 22 | if test "$DIE" -eq 1; then 23 | exit 1 24 | fi 25 | 26 | echo Removing old files... 27 | rm -f stamp-h1 configure Makefile Makefile.in src/Makefile src/Makefile.in config.h config.status aclocal.m4 config.cache config.log 28 | [ -d "config" ] && rm -rf config 29 | [ -d "autom4te.cache" ] && rm -rf autom4te.cache 30 | mkdir config 31 | 32 | #cd pcre-3.9 33 | #./bootstrap 34 | #cd .. 35 | 36 | echo "aclocal -I ." 37 | aclocal -I . 38 | if test $? -ne 0; then 39 | exit 1 40 | fi 41 | echo "autoheader" 42 | autoheader 43 | if test $? -ne 0; then 44 | exit 1 45 | fi 46 | echo "automake --foreign --add-missing" 47 | automake --foreign --add-missing 48 | if test $? -ne 0; then 49 | exit 1 50 | fi 51 | echo "autoconf" 52 | autoconf 53 | echo "BOOTSTRAP complete" 54 | 55 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl THCRUT configure.in, anonymous@segfault.net 2 | dnl Process this file with autoconf to produce a configure script. 3 | AC_PREREQ(2.61) 4 | AC_INIT([thc-rut], 2.2.6-rc1) 5 | AC_CONFIG_AUX_DIR(config) 6 | AC_CANONICAL_SYSTEM 7 | 8 | dnl we use automake 9 | AM_INIT_AUTOMAKE 10 | AM_CONFIG_HEADER(config.h) 11 | dnl for --enable-maintainer-mode fun use: 12 | dnl AM_MAINTAINER_MODE 13 | 14 | dnl Checks for programs. 15 | AC_PROG_CC 16 | AC_PROG_INSTALL 17 | AC_PROG_RANLIB 18 | dnl 19 | dnl Use these compiler flags if we have gcc. 20 | dnl 21 | if test $ac_cv_prog_gcc = yes; then 22 | CCOPTS='-O2 -Wall -g' 23 | CFLAGS="$CCOPTS" 24 | fi 25 | test "x$prefix" != "xNONE" || prefix="/usr/local" 26 | test "x$exec_prefix" != "xNONE" || exec_prefix="${prefix}" 27 | trydir_i="${prefix}/include" 28 | trydir_l="${prefix}/lib" 29 | 30 | if test "${prefix}" != "/usr/local" ; then 31 | trydir_i="${trydir_i} /usr/local/include" 32 | trydir_l="${trydir_l} /usr/local/lib" 33 | fi 34 | 35 | trydir_i="${trydir_i} ${prefix}/include/pcap ${prefix}/include/pcre /usr/include/pcre /usr/include/pcap" 36 | AC_ARG_WITH(includes, 37 | [ --with-includes=DIR Space-seperated list of include directories], 38 | [ 39 | trydir_i="$trydir_i ${withval}" 40 | ]) 41 | for xincdir in $trydir_i ; do 42 | if test ! -d "$xincdir" ; then 43 | continue; 44 | fi 45 | if test x"${INCLUDES}" = x; then 46 | INCLUDES="-I${xincdir}"; 47 | else 48 | INCLUDES="$INCLUDES -I${xincdir}"; 49 | fi 50 | done 51 | CPPFLAGS="${INCLUDES} $CPPFLAGS" 52 | 53 | dnl Add available library directories 54 | trydir_l="${trydir_l} ${prefix}/lib/pcap" 55 | AC_ARG_WITH(libs, 56 | [ --with-libs=DIR Space-seperated list of library directories], 57 | [ 58 | trydir_l="$trydir_l ${withval}" 59 | ]) 60 | for xlibdir in $trydir_l ; do 61 | if test ! -d "$xlibdir" ; then 62 | continue; 63 | fi 64 | if test x"${LIBDIR}" = x; then 65 | LIBDIR="-L${xlibdir}"; 66 | else 67 | LIBDIR="$LIBDIR -L${xlibdir}"; 68 | fi 69 | done 70 | LDFLAGS="${LIBDIR} $LDFLAGS" 71 | 72 | dnl Check OS dependent stuff 73 | dnl select on FreeBSD <=4.6 never indicated that there is data to read. 74 | case "$target_os" in 75 | *freebsd*) 76 | echo "############################################################" 77 | echo "### Some FreeBSDs' have a broken SELECT-BPF" 78 | echo "### implementation (see tcpdump mailinglist)." 79 | echo "### THC RUT might not work at all on such a platform." 80 | echo "### continueing in 10 seconds. Good luck!" 81 | echo "############################################################" 82 | sleep 10 83 | dnl AC_DEFINE(THCRUT_BROKEN_BPF_SELECT, 1, [def]) 84 | ;; 85 | esac 86 | 87 | dnl Checks for libraries. 88 | AC_CHECK_LIB(socket, socket) 89 | AC_CHECK_LIB(nsl, gethostbyname) 90 | AC_CHECK_LIB([net], [libnet_name_resolve], [AC_MSG_ERROR([libnet 1.0.x found. Requires libnet 1.1 or newer])]) 91 | AC_CHECK_LIB([net], [libnet_init], ,[AC_MSG_ERROR([libnet 1.1.x not found])]) 92 | 93 | 94 | dnl Checks for header files. 95 | AC_HEADER_STDC 96 | AC_HEADER_SYS_WAIT 97 | AC_CHECK_HEADERS(sys/time.h unistd.h string.h) 98 | 99 | dnl Checks for typedefs, structures, and compiler characteristics. 100 | AC_C_CONST 101 | AC_TYPE_PID_T 102 | AC_HEADER_TIME 103 | 104 | dnl Checks for library functions. 105 | AC_FUNC_MEMCMP 106 | 107 | AC_TYPE_SIGNAL 108 | dnl If size_t is not defined, define size_t to be unsigned. 109 | AC_TYPE_SIZE_T 110 | dnl If uid_t is not defined, define uid_t to be int and gid_t to be int. 111 | AC_TYPE_UID_T 112 | 113 | dnl check if we are on a bigendian b0x 114 | dnl We dont check for this because autoconf maintainers are pussies and 115 | dnl yell a warning everytime. Guys, introduce AC_C_BIGENDIAN_CROSS for 116 | dnl gods sake! 117 | dnl AC_C_BIGENDIAN 118 | 119 | AC_CHECK_FUNCS(gettimeofday memcpy strchr strlcpy) 120 | dnl FIXME: repair this later 121 | dnl SNPRINTF='' 122 | dnl AC_CHECK_FUNC(snprintf, AC_DEFINE(HAVE_SNPRINTF), SNPRINTF='snprintf.o') 123 | dnl AC_SUBST(SNPRINTF) 124 | 125 | AC_MSG_CHECKING(whether to enable leeto mode) 126 | AC_ARG_ENABLE(leeto, 127 | [ --enable-leeto Enable extrem 31337 mode.], 128 | [ case "$enableval" in 129 | yes) 130 | AC_MSG_RESULT(y0y0) 131 | AC_DEFINE(WITH_LEETO, 1, [31337]) 132 | ;; 133 | *) 134 | AC_MSG_RESULT(nope) 135 | ;; 136 | esac ], 137 | AC_MSG_RESULT(nope) 138 | ) 139 | 140 | AC_ARG_ENABLE(debug, 141 | [ --enable-debug Enable debug information], 142 | AC_DEFINE(DEBUG, 1, [Debug infos]) 143 | ) 144 | 145 | AC_ARG_ENABLE(static, 146 | [ --enable-static Compile static binary], 147 | [STATIC="yes"], [STATIC="no"] 148 | ) 149 | 150 | if test x"$STATIC" = x"yes"; then 151 | CFLAGS="-static ${CFLAGS}" 152 | LIBS="${LIBS} -lpthread" 153 | fi 154 | 155 | AC_ARG_ENABLE(dist, 156 | [ --enable-dist Enable distribution mode, Use own libraries.], 157 | [DIST="yes"], [DIST="no"] 158 | ) 159 | 160 | AC_CHECK_LIB(pcap, pcap_open_live,, AC_MSG_ERROR(We need libpcap. 161 | Get libpcap from http://www.tcpdump.org or try --with-[[libs,includes]]=DIR)) 162 | 163 | AC_CHECK_LIB(pcre, pcre_compile,, AC_MSG_ERROR(We need libpcre.)) 164 | 165 | dnl AC_CHECK_LIB(pcre, pcre_compile, [PCRE=yes], [PCRE=no]) 166 | dnl if test x"$PCRE" = x"no" -o x"$DIST" = x"yes"; then 167 | dnl AC_CONFIG_SUBDIRS(pcre-3.9) 168 | dnl THCRUT_SUBDIRS="$THCRUT_SUBDIRS pcre-3.9" 169 | dnl CPPFLAGS="-I../pcre-3.9 ${CPPFLAGS}" 170 | dnl LDFLAGS="-L../pcre-3.9 ${LDFLAGS}" 171 | dnl PRG_PCRE_CONFIG_CFLAGS="../pcre-3.9/pcre-config --cflags" 172 | dnl PRG_PCRE_CONFIG_LIBS="../pcre-3.9/pcre-config --libs" 173 | dnl else 174 | dnl dnl Into CFLAGS and not CPPFLAGS because it's --cflags 175 | dnl CFLAGS="`pcre-config --cflags` $CFLAGS" 176 | dnl LIBS="`pcre-config --libs` $LIBS" 177 | dnl fi 178 | 179 | dnl config/Makefile required for 'make dist' 180 | B=`eval echo ${bindir}` ; B=`eval echo ${B}` 181 | D=`eval echo ${sysconfdir}` ; D=`eval echo ${D}` 182 | THCRUT_DATADIR=`eval echo ${datadir}/thcrut` ; THCRUT_DATADIR=`eval echo ${THCRUT_DATADIR}` 183 | AC_DEFINE_UNQUOTED(THCRUT_DATADIR, "${THCRUT_DATADIR}", [share/thcrut]) 184 | 185 | dnl disable NMAP until we have it inside thcrut-os-fingerprints file. 186 | dnl AC_DEFINE(WITH_NMAPFP, 1, [def]) 187 | 188 | #AC_SUBST(THCRUT_SUBDIRS) 189 | AC_SUBST(PRG_PCRE_CONFIG_CFLAGS) 190 | AC_SUBST(PRG_PCRE_CONFIG_LIBS) 191 | AC_OUTPUT(Makefile src/Makefile) 192 | 193 | dnl Just to show the correct values... 194 | dnl CFLAGS="`${srcdir}/pcre-3.9/pcre-config --cflags` $CFLAGS" 195 | dnl LIBS="`${srcdir}/pcre-3.9/pcre-config --libs` $LIBS" 196 | 197 | echo " 198 | THCrut has been configured with the following options: 199 | User binaries: $B 200 | Data directory: $THCRUT_DATADIR 201 | 202 | Host: ${host} 203 | Compiler: ${CC} 204 | Compiler flags: ${CFLAGS} 205 | Preprocessor flags: ${CPPFLAGS} 206 | Linker flags: ${LDFLAGS} 207 | Libraries: ${LIBS}" 208 | cat ${srcdir}/thcrutlogo.txt 209 | echo "Configuration complete. Now type: make all install; thc-rut -h" 210 | 211 | -------------------------------------------------------------------------------- /releases/thc-rut-2-2-6-rc1_static_binary_RaspberryPi_ARM-V7L_32-pc-linux-gnu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackerschoice/thc-rut/0042c993ca7c7708b2237dd6c01e2f93ad48b201/releases/thc-rut-2-2-6-rc1_static_binary_RaspberryPi_ARM-V7L_32-pc-linux-gnu -------------------------------------------------------------------------------- /releases/thc-rut-2-2-6-rc1_static_binary_x86_64-pc-linux-gnu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackerschoice/thc-rut/0042c993ca7c7708b2237dd6c01e2f93ad48b201/releases/thc-rut-2-2-6-rc1_static_binary_x86_64-pc-linux-gnu -------------------------------------------------------------------------------- /releases/thc-rut-2.2.6-rc1.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackerschoice/thc-rut/0042c993ca7c7708b2237dd6c01e2f93ad48b201/releases/thc-rut-2.2.6-rc1.tar.gz -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = thc-rut 2 | thc_rut_SOURCES = nvt.c icmp_main.c arp_main.c thcrut_libnet.c dhcp_main.c system.c fp.c discover_dispatch.c packets.c nmap_compat.c thcrut_pcap.c network.c discover_main.c thcrut_sig.c state.c arpg.c dhcp.c network_raw.c schedule.c dcd_icmp.c macvendor.c range.c thc-rut.c asn.c tty.c 3 | noinst_HEADERS = nvt.h icmp_main.h arp_main.h thcrut_libnet.h dhcp_main.h system.h fp.h discover_dispatch.h packets.h nmap_compat.h thcrut_pcap.h network.h discover_main.h state.h arpg.h dcd_icmp.h dhcp.h macvendor.h network_raw.h range.h schedule.h default.h thc-rut.h thcrut_sig.h asn.h tty.h macvlist.h 4 | ## use thcrutdir = /etc here if you dont like /usr/local/etc... 5 | thcrutdir = $(sysconfdir) 6 | EXTRA_DIST = nmap-os-fingerprints thcrut-os-fingerprints 7 | pkgdata_DATA = nmap-os-fingerprints thcrut-os-fingerprints 8 | ## AM_CFLAGS = `@PRG_LIBNET_CONFIG_CFLAGS@` `@PRG_PCRE_CONFIG_CFLAGS@` 9 | ## LIBS = @LIBS@ `@PRG_LIBNET_CONFIG_LIBS@` `@PRG_PCRE_CONFIG_LIBS@` 10 | 11 | -------------------------------------------------------------------------------- /src/arp_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id:$ 3 | * 4 | * Pretty interesting which OS answers for arp request for 5 | * 127.0.0.1, 0.0.0.0 or gives replies about MAC from other 6 | * interfaces (linux for example). 7 | */ 8 | 9 | #include "default.h" 10 | #include 11 | #include 12 | #ifdef HAVE_UNISTD_H 13 | # include 14 | #endif 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "macvendor.h" 20 | #include "thc-rut.h" 21 | #include "range.h" 22 | #include "packets.h" 23 | #include "network.h" 24 | #include "network_raw.h" 25 | #include "thcrut_libnet.h" 26 | #include "thcrut_pcap.h" 27 | 28 | #define STATE_RESET (0) 29 | #define STATE_ARPI (1) 30 | #define STATE_ARPII (2) 31 | #define STATE_ARPIII (3) 32 | 33 | #define DFL_HOSTS_PARALLEL (256) 34 | 35 | extern struct _opt opt; 36 | static void arp_filter(unsigned char *u, struct pcap_pkthdr *p, unsigned char *packet); 37 | static void do_arp(); 38 | 39 | static libnet_ptag_t ln_arp; 40 | static libnet_ptag_t ln_eth; 41 | static uint8_t srcmac[ETH_ALEN]; 42 | uint8_t zero[18]; /* We pad to 60 bytes. TEST */ 43 | 44 | static void 45 | init_vars(void) 46 | { 47 | 48 | opt.ip_socket = init_pcap(&opt.device, 1, "arp[6:2] = 2", &opt.net, &opt.bcast, &opt.dlt_len); 49 | 50 | opt.ln_ctx = init_libnet(opt.device, &opt.src_ip); 51 | /* 52 | * Only listen to replies. 53 | */ 54 | if (!(opt.flags & FL_OPT_SPOOFMAC)) 55 | { 56 | struct libnet_ether_addr *hw; 57 | hw = libnet_get_hwaddr(opt.ln_ctx); 58 | if (!hw) 59 | ERREXIT("libnet_get_hwaddr: %s\n", libnet_geterror(opt.ln_ctx)); 60 | memcpy(srcmac, hw->ether_addr_octet, ETH_ALEN); 61 | } 62 | 63 | arp_gen_packets(opt.src_ip); 64 | } 65 | 66 | static void 67 | usage(void) 68 | { 69 | fprintf(stderr, "" 70 | "usage: arp [options] [IP] ...\n" 71 | " -l Hosts in parallel (%d)\n" 72 | " -m source MAC (source interface)\n" 73 | "", DFL_HOSTS_PARALLEL); 74 | 75 | exit(0); 76 | } 77 | 78 | /* 79 | * Init libnet here because we want to display the correct IP 80 | */ 81 | static void 82 | init_defaults(void) 83 | { 84 | if (opt.hosts_parallel == 0) 85 | opt.hosts_parallel = DFL_HOSTS_PARALLEL; 86 | } 87 | 88 | static void 89 | do_getopt(int argc, char *argv[]) 90 | { 91 | int c; 92 | 93 | optind = 1; 94 | while ( (c = getopt(argc, argv, "+hl:m:")) != -1) 95 | { 96 | switch (c) 97 | { 98 | case 'l': 99 | opt.hosts_parallel = atoi(optarg); 100 | break; 101 | case 'm': 102 | #ifdef __APPLE__ 103 | fprintf(stderr, "WARNING: MAC spoofing not working on macOS\n"); 104 | #endif 105 | macstr2mac(srcmac, optarg); 106 | opt.flags |= FL_OPT_SPOOFMAC; 107 | break; 108 | default: 109 | usage(); 110 | } 111 | } 112 | 113 | opt.argvlist = &argv[optind]; 114 | opt.argc = argc - optind; 115 | } 116 | 117 | /* 118 | * Send arp request 119 | */ 120 | static void 121 | do_arp(uint32_t ip) 122 | { 123 | //struct ETH_arp *eth_arp = (struct ETH_arp *)(packet + LIBNET_ETH_H); 124 | int c; 125 | 126 | ln_arp = libnet_build_arp(ARPHRD_ETHER, 127 | ETHERTYPE_IP, 128 | 6, 4, ARPOP_REQUEST, 129 | srcmac /*ETHZCAST*/, 130 | (uint8_t *)&opt.src_ip, 131 | ETHBCAST, 132 | (uint8_t *)&ip, 133 | zero, sizeof zero, opt.ln_ctx, ln_arp); 134 | 135 | ln_eth = libnet_build_ethernet(ETHBCAST, 136 | srcmac /*ETHZCAST*/, 137 | ETHERTYPE_ARP, 138 | NULL, 0, opt.ln_ctx, ln_eth); 139 | 140 | c = libnet_write(opt.ln_ctx); 141 | if (c == -1) 142 | { 143 | ERREXIT("libnet_write() = %d, %s\n", c, libnet_geterror(opt.ln_ctx)); 144 | } 145 | } 146 | 147 | static void 148 | dis_timeout(struct _state *state) 149 | { 150 | switch (STATE_current(state)) 151 | { 152 | case STATE_RESET: 153 | STATE_current(state) = STATE_ARPI; 154 | do_arp(STATE_ip(state)); 155 | break; 156 | case STATE_ARPI: 157 | STATE_current(state) = STATE_ARPII; 158 | do_arp(STATE_ip(state)); 159 | break; 160 | case STATE_ARPII: 161 | STATE_current(state) = STATE_ARPIII; 162 | do_arp(STATE_ip(state)); 163 | break; 164 | case STATE_ARPIII: 165 | STATE_reset(state); 166 | break; 167 | default: 168 | fprintf(stderr, "%s:%d Unknown state %d\n", __func__, __LINE__, STATE_current(state)); 169 | STATE_reset(state); 170 | break; 171 | } 172 | } 173 | 174 | static void 175 | cb_filter(void) 176 | { 177 | if (pcap_dispatch(opt.ip_socket, -1, (pcap_handler)arp_filter, NULL) < 0) 178 | { 179 | pcap_perror(opt.ip_socket, "pcap_dispatch"); 180 | exit(-1); 181 | } 182 | } 183 | 184 | static void 185 | arp_filter(unsigned char *u, struct pcap_pkthdr *p, unsigned char *packet) 186 | { 187 | struct ETH_arp *arp = (struct ETH_arp *)(packet + LIBNET_ETH_H); 188 | struct _state *state; 189 | long l; 190 | const char *ptr; 191 | 192 | if (p->caplen < LIBNET_ETH_H + sizeof *arp) 193 | return; 194 | memcpy(&l, arp->ar_sip, 4); 195 | 196 | if (!(state = STATE_by_ip(&opt.sq, l))) 197 | return; 198 | 199 | ptr = MacVendor_by_mac(arp->ar_sha); 200 | /* 201 | * 16 bytes for IP, 1 byte for space, 17 for mac + 1 space = 35 202 | * 80 - 35 = 45. 203 | */ 204 | printf("%-16s %s %.45s\n", int_ntoa(l), val2mac(arp->ar_sha), ptr); 205 | 206 | STATE_reset(state); 207 | } 208 | 209 | 210 | int 211 | arp_main(int argc, char *argv[]) 212 | { 213 | struct _state state; 214 | struct pcap_stat ps; 215 | int ret; 216 | 217 | init_defaults(); 218 | do_getopt(argc, argv); 219 | init_vars(); 220 | 221 | /* By default do the local network */ 222 | if (opt.argc == 0) 223 | { 224 | opt.argvlist--; 225 | opt.argvlist[0] = getmy_range(); 226 | } 227 | 228 | IP_init(&opt.ipr, opt.argvlist, (opt.flags & FL_OPT_SPREADMODE)?IPR_MODE_SPREAD:0); 229 | 230 | if (!SQ_init(&opt.sq, opt.hosts_parallel, sizeof(struct _state), pcap_fileno(opt.ip_socket), dis_timeout, cb_filter)) 231 | { 232 | fprintf(stderr, "Failed to init states: %s\n", strerror(errno)); 233 | exit(-1); 234 | } 235 | 236 | memset(&state, 0, sizeof state); 237 | while (1) 238 | { 239 | IP_next(&opt.ipr); 240 | /* Start again from the begining in "INFINITE" mode */ 241 | if ((opt.flags & FL_OPT_INFINITE) && (!(IP_current(&opt.ipr)))) 242 | { 243 | IP_reset(&opt.ipr); 244 | IP_next(&opt.ipr); 245 | } 246 | if (IP_current(&opt.ipr)) 247 | { 248 | STATE_ip(&state) = htonl(IP_current(&opt.ipr)); 249 | ret = STATE_wait(&opt.sq, &state); 250 | } else { 251 | ret = STATE_wait(&opt.sq, NULL); 252 | } 253 | 254 | if (ret != 0) 255 | break; 256 | } 257 | 258 | if (thcrut_pcap_stats(opt.ip_socket, &ps) == 0) 259 | fprintf(stderr, "%u packets received by filter, %u packets dropped by kernel\n", ps.ps_recv, ps.ps_drop); 260 | 261 | return 0; 262 | } 263 | 264 | -------------------------------------------------------------------------------- /src/arp_main.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id:$ 3 | */ 4 | 5 | #ifndef __THCRUT_ARP_MAIN_H__ 6 | #define __THCRUT_ARP_MAIN_H__ 1 7 | 8 | int arp_main(int argc, char *argv[]); 9 | 10 | #endif /* !__THCRUT_ARP_MAIN_H__ */ 11 | -------------------------------------------------------------------------------- /src/arpg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * arp-god :> 3 | */ 4 | #include "default.h" 5 | #include 6 | #ifdef HAVE_UNISTD_H 7 | # include 8 | #endif 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "thc-rut.h" 14 | #include "arpg.h" 15 | #include "thcrut_sig.h" 16 | #include "thcrut_pcap.h" 17 | 18 | 19 | //extern struct _lnet lnet; 20 | extern struct _opt opt; 21 | //extern struct _pcap pcap; 22 | 23 | libnet_ptag_t ln_arp; 24 | libnet_ptag_t ln_eth; 25 | 26 | /* 27 | * send out ARP-REPLY from ip/mac to ip/mac 28 | * return 0 ono success... 29 | */ 30 | int 31 | send_arp(u_short proto, u_long spf_sip, u_char spf_smac[6], u_long spf_dip, u_char spf_dmac[6]) 32 | { 33 | int c; 34 | 35 | ln_arp = libnet_build_arp(ARPHRD_ETHER, 36 | ETHERTYPE_IP, 37 | 6, 4, proto, 38 | spf_smac, 39 | (uint8_t *)&spf_sip, 40 | spf_dmac, 41 | (uint8_t *)&spf_dip, 42 | NULL, 43 | 0, 44 | opt.ln_ctx, ln_arp); 45 | 46 | ln_eth = libnet_build_ethernet(ETHBCAST, 47 | spf_smac, 48 | ETHERTYPE_ARP, 49 | NULL, 50 | 0, 51 | opt.ln_ctx, ln_eth); 52 | #if 0 53 | 54 | libnet_build_ethernet(spf_dmac, 55 | spf_smac, 56 | ETHERTYPE_ARP, 57 | NULL, 58 | 0, 59 | lnet.packet); 60 | 61 | libnet_build_arp(ARPHRD_ETHER, 62 | ETHERTYPE_IP, 63 | 6, 64 | 4, 65 | proto, 66 | spf_smac, 67 | (u_char *)&spf_sip, 68 | spf_dmac, 69 | (u_char *)&spf_dip, 70 | NULL, 71 | 0, 72 | lnet.packet + LIBNET_ETH_H); 73 | #endif 74 | 75 | c = libnet_write(opt.ln_ctx); 76 | 77 | if (c == -1) 78 | ERREXIT("libnet_write() = %d, %s\n", c, libnet_geterror(opt.ln_ctx)); 79 | 80 | return 0; 81 | } 82 | 83 | /* 84 | * called by libpcap 85 | */ 86 | #if 0 87 | static void 88 | filter_packet(u_char *u, struct pcap_pkthdr *p, u_char *packet) 89 | { 90 | static u_char *align_buf = NULL; 91 | struct Ether_header *eth; 92 | 93 | DEBUGF("filter read something\n"); 94 | if (p->caplen < (opt.dlt_len + ETH_ARP_H)) 95 | return; 96 | 97 | eth = (struct Ether_header *) (packet); 98 | 99 | if (align_buf == NULL) 100 | align_buf = (u_char *) malloc(PCAPBUFSIZE); 101 | 102 | memcpy(align_buf, packet + opt.dlt_len, p->caplen - opt.dlt_len); 103 | 104 | switch (ntohs(eth->ether_type)) 105 | { 106 | case ETHERTYPE_IP: 107 | opt.handle_ip(align_buf, p->caplen - opt.dlt_len); 108 | break; 109 | case ETHERTYPE_ARP: 110 | opt.handle_arp(align_buf, p->caplen - opt.dlt_len); 111 | break; 112 | } 113 | 114 | } 115 | #endif 116 | 117 | #if 0 118 | void 119 | start_arpd(const char *filter) 120 | { 121 | /* 122 | * We open before we fork to not loose any packets. 123 | */ 124 | opt.ip_socket = init_pcap(opt.device, 1, PCAP_FILTER, NULL, NULL, &opt.dlt_len); 125 | if ((opt.childpid = fork()) > 0) 126 | pcap_loop(opt.ip_socket, -1, (pcap_handler) filter_packet, NULL); 127 | 128 | pcap_close(opt.ip_socket); /* child */ 129 | if (opt.childpid == -1) 130 | die(-1, "unable to fork arp-daemon"); 131 | } 132 | #endif 133 | 134 | -------------------------------------------------------------------------------- /src/arpg.h: -------------------------------------------------------------------------------- 1 | #ifndef THCRUT_ARPG_H 2 | #define THCRUT_ARPG_H 1 3 | 4 | int send_arp(u_short, u_long, u_char *, u_long, u_char *); 5 | 6 | #endif /* !THCRUT_ARPG_H */ 7 | 8 | -------------------------------------------------------------------------------- /src/asn.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id:$ 3 | */ 4 | 5 | #include "default.h" 6 | #include 7 | #include "asn.h" 8 | 9 | /* 10 | * Return the length of an ASN.1 object starting at *src. 11 | * Store the pointer to the ASN.1 data in src. 12 | * Return the type in *type. 13 | * 14 | * SUB categories _and_ PDU's are ignored. 15 | * 16 | * Next call should be done with src + olen. 17 | * 18 | * Return 0 on error. 19 | */ 20 | size_t 21 | ASN_next(uint8_t **data, int len, uint8_t *type) 22 | { 23 | uint8_t *src = *data; 24 | uint8_t *end = src + len; 25 | 26 | size_t olen; 27 | 28 | if (end - src < 2) 29 | goto err; 30 | 31 | *type = *src++; 32 | 33 | while ((*type == ASN_SUBCAT) || (*type == ASN_PDU)) 34 | { 35 | if (*src++ & ASN_LONG_LEN) 36 | src++; 37 | 38 | if (end - src < 2) 39 | goto err; 40 | *type = *src++; 41 | } 42 | 43 | if (*src & ASN_LONG_LEN) 44 | olen = (*src++ & ~ASN_LONG_LEN) << 8; 45 | else 46 | olen = 0; 47 | 48 | if (end - src < 1) 49 | goto err; 50 | 51 | olen += *src++; 52 | 53 | if (olen > end - src) 54 | goto err; 55 | 56 | *data = src; 57 | 58 | return olen; 59 | err: 60 | *data = NULL; 61 | return 0; 62 | } 63 | 64 | -------------------------------------------------------------------------------- /src/asn.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id:$ 3 | */ 4 | 5 | #ifndef __THCRUT_ASN_H__ 6 | #define __THCRUT_ASN_H__ 1 7 | 8 | #ifndef ASN_SUBCAT 9 | # define ASN_SUBCAT ((unsigned char)0x30) 10 | #endif 11 | #ifndef ASN_PDU 12 | # define ASN_PDU ((unsigned char)0xa2) 13 | #endif 14 | #ifndef ASN_LONG_LEN 15 | # define ASN_LONG_LEN ((unsigned char)0x80) 16 | #endif 17 | #ifndef ASN_OCTET_STR 18 | # define ASN_OCTET_STR ((unsigned char)0x04) 19 | #endif 20 | 21 | size_t ASN_next(uint8_t **src, int len, uint8_t *type); 22 | 23 | #endif /* !__THCRUT_ASN_H__ */ 24 | -------------------------------------------------------------------------------- /src/dcd_icmp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * based on information from 4 | * RFC792 - INTERNET CONTROL MESSAGE PROTOCOL 5 | * RFC950 - Internet Standard Subnetting Procedure 6 | * ??? "ICMP Usage in Scanning" (ICMP_Scanning_v2.5.pdf) 7 | */ 8 | 9 | #include 10 | #include "dcd_icmp.h" 11 | 12 | static char * icmp_echo_reply[] = { 13 | "ICMP ECHOREPLY", 14 | NULL 15 | }; 16 | 17 | static char * icmp_unreach[] = { 18 | "ICMP UNREACH network unreachable", 19 | "ICMP UNREACH host unreachable", 20 | "ICMP UNREACH protocol unreachable", 21 | "ICMP UNREACH port unreachable", 22 | "ICMP UNREACH fragmentation needed but don't-fragment bit set", 23 | "ICMP UNREACH source route failed", 24 | "ICMP UNREACH destination network unknown", 25 | "ICMP UNREACH destination host unknown", 26 | "ICMP UNREACH source host isolated", 27 | "ICMP UNREACH destination network administratively prohibited", 28 | "ICMP UNREACH destination host administratively prohibited", 29 | "ICMP UNREACH network unreachable for TOS", 30 | "ICMP UNREACH host unreachable for TOS", 31 | "ICMP UNREACH communication administratively prohibited by filtering", 32 | "ICMP UNREACH host precedence violation", 33 | "ICMP UNREACH precedence cutoff in effect", 34 | NULL 35 | }; 36 | 37 | static char * icmp_quench[] = { 38 | "ICMP QUENCH", 39 | NULL 40 | }; 41 | 42 | static char * icmp_redirect[] = { 43 | "ICMP REDIRECT Redirect datagrams for the Network", 44 | "ICMP REDIRECT Redirect datagrams for the Host", 45 | "ICMP REDIRECT Redirect datagrams for the Type of Service and Network", 46 | "ICMP REDIRECT Redirect datagrams for the Type of Service and Host", 47 | NULL 48 | }; 49 | 50 | static char * icmp_alternate[] = { 51 | "ICMP ALTERNATEHOSTADDRESS", 52 | NULL 53 | }; 54 | 55 | static char * icmp_echo[] = { 56 | "ICMP ECHO", 57 | NULL 58 | }; 59 | 60 | static char * icmp_routerad[] = { 61 | "ICMP ROUTERADVERTISEMENT", 62 | NULL 63 | }; 64 | 65 | static char * icmp_routersel[] = { 66 | "ICMP ROUTERSELECTION", 67 | NULL 68 | }; 69 | 70 | static char * icmp_timeexceed[] = { 71 | "ICMP TIMEEXCEED time to live exceeded in transit", 72 | "ICMP TIMEEXCEED fragment reassembly time exceeded", 73 | NULL 74 | }; 75 | 76 | static char * icmp_parprob[] = { 77 | "ICMP PARAMETER pointer indicates the error", 78 | "ICMP PARAMETER missing a required option", 79 | "ICMP PARAMETER bad length", 80 | NULL 81 | }; 82 | 83 | static char * icmp_timestamp[] = { 84 | "ICMP TIMESTAMP", 85 | NULL 86 | }; 87 | 88 | static char * icmp_timestamp_reply[] = { 89 | "ICMP TIMESTAMPREPLY", 90 | NULL 91 | }; 92 | 93 | static char * icmp_information[] = { 94 | "ICMP INFORMATION", 95 | NULL 96 | }; 97 | 98 | static char * icmp_information_reply[] = { 99 | "ICMP INFORMATIONREPLY", 100 | NULL 101 | }; 102 | 103 | static char * icmp_addressmask[] = { 104 | "ICMP ADDRESSMASK", 105 | NULL 106 | }; 107 | 108 | static char * icmp_addressmask_reply[] = { 109 | "ICMP ADDRESSMASKREPLY", 110 | NULL 111 | }; 112 | 113 | static char * icmp_ERR[] = { 114 | "ICMP invalid code", 115 | NULL 116 | }; 117 | 118 | struct icmp_typeelem { 119 | int count; 120 | char ** tab; 121 | }; 122 | 123 | struct icmp_typeelem icmp_tab[] = { 124 | { 1, icmp_echo_reply }, /* 0 Echo Reply */ 125 | { 0, icmp_ERR }, /* 1 UNUSED */ 126 | { 0, icmp_ERR }, /* 2 UNUSED */ 127 | { 16, icmp_unreach }, /* 3 Destination Unreachable */ 128 | { 1, icmp_quench }, /* 4 Source Quench */ 129 | { 4, icmp_redirect }, /* 5 Redirect */ 130 | { 1, icmp_alternate }, /* 6 Alternate Host Address */ 131 | { 0, icmp_ERR }, /* 7 UNUSED */ 132 | { 1, icmp_echo }, /* 8 Echo */ 133 | { 1, icmp_routerad }, /* 9 Router Advertisement */ 134 | { 1, icmp_routersel }, /* 10 Router Selection */ 135 | { 2, icmp_timeexceed }, /* 11 Time Exceeded */ 136 | { 3, icmp_parprob }, /* 12 Parameter Problem */ 137 | { 1, icmp_timestamp }, /* 13 Timestamp */ 138 | { 1, icmp_timestamp_reply }, /* 14 Timestamp Reply */ 139 | { 1, icmp_information }, /* 15 Information Request */ 140 | { 1, icmp_information_reply }, /* 16 Information Request */ 141 | { 1, icmp_addressmask }, /* 17 RFC950: Address Mask Request */ 142 | { 1, icmp_addressmask_reply }, /* 18 RFC950: Address Mask Reply */ 143 | { 0, NULL }, /* EOList */ 144 | }; 145 | 146 | int icmp_type_max = (sizeof (icmp_tab) / sizeof (struct icmp_typeelem)) - 1; 147 | 148 | const char * 149 | icmp_str (int type, int code) 150 | { 151 | struct icmp_typeelem * it; 152 | 153 | if (type < 0 || type >= icmp_type_max) 154 | return ("ICMP invalid type"); 155 | 156 | it = &icmp_tab[type]; 157 | if (it->count == 0) 158 | return (it->tab[0]); 159 | 160 | if (code < 0 || code >= it->count) 161 | return ("ICMP invalid code"); 162 | 163 | return (it->tab[code]); 164 | } 165 | 166 | 167 | -------------------------------------------------------------------------------- /src/dcd_icmp.h: -------------------------------------------------------------------------------- 1 | /* bscan - icmp include file 2 | */ 3 | 4 | #ifndef THCRUT_DCD_ICMP_H 5 | #define THCRUT_DCD_ICMP_H 1 6 | 7 | #define ICMP_HDRSIZE 8 8 | 9 | const char * 10 | icmp_str (int type, int code); 11 | 12 | #endif /* !THCRUT_DCD_ICMP_H */ 13 | 14 | -------------------------------------------------------------------------------- /src/default.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: default.h,v 1.5 2003/05/16 08:58:45 skyper Exp $ 3 | */ 4 | 5 | #ifndef __THCRUT_DEFAULT_H__ 6 | #define __THCRUT_DEFAULT_H__ 1 7 | 8 | #ifdef HAVE_CONFIG_H 9 | # include 10 | #endif 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #ifdef HAVE_UNISTD_H 23 | # include 24 | #endif 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #ifdef HAVE_CONFIG_H 34 | # if defined(STDC_HEADERS) || defined(HAVE_STRING_H) 35 | # include 36 | # else 37 | # ifndef HAVE_STRCHR 38 | # ifndef strchr 39 | # define strchr index 40 | # endif 41 | # ifndef strrchr 42 | # define strrchr rindex 43 | # endif 44 | # endif 45 | char *strchr (), *strrchr (); 46 | # ifndef HAVE_MEMCPY 47 | # ifndef memcpy 48 | # define memcpy(d, s, n) bcopy ((s), (d), (n)) 49 | # endif 50 | # ifndef memmove 51 | # define memmove(d, s, n) bcopy ((s), (d), (n)) 52 | # endif 53 | # endif 54 | # endif 55 | #else 56 | # include 57 | #endif 58 | 59 | #ifdef DEBUG 60 | # define DEBUGF(a...) do{fprintf(stderr, "DEBUG %s:%d: ", __func__, __LINE__); fprintf(stderr, a); }while(0) 61 | #else 62 | # define DEBUGF(a...) 63 | #endif 64 | 65 | #define XFREE(ptr) do{if(ptr) free(ptr); ptr = NULL;}while(0) 66 | 67 | #define ERREXIT(a...) do { \ 68 | fprintf(stderr, "%s():%d ", __func__, __LINE__); \ 69 | fprintf(stderr, a); \ 70 | exit(-1); \ 71 | } while (0) 72 | 73 | 74 | # define HEXDUMP(a, len) do { \ 75 | int n = 0; \ 76 | fprintf(stderr, "%s:%d HEX ", __FILE__, __LINE__); \ 77 | while (n < len) fprintf(stderr, "%2.2x", ((unsigned char *)a)[n++]); \ 78 | fprintf(stderr, "\n"); \ 79 | } while (0) 80 | 81 | #endif /* !__THCRUT_DEFAULT_H__ */ 82 | -------------------------------------------------------------------------------- /src/dhcp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * THC-rut 3 | * 4 | * DHCP options (and rarp, bootp also...) 5 | * anonymous@segfault.net 6 | */ 7 | 8 | #ifndef THCRUT_DHCP_H 9 | #define THCRUT_DHCP_H 1 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | /* RFC 1497 Vendor Extensions */ 17 | 18 | #define DHCP_PAD 0 19 | #define DHCP_SUBMASK 1 20 | #define DHCP_TIMEOFF 2 21 | #define DHCP_ROUTER 3 22 | #define DHCP_TSERV 4 23 | #define DHCP_NS 5 24 | #define DHCP_DNS 6 25 | #define DHCP_LOGSERV 7 26 | #define DHCP_COOKSERV 8 27 | #define DHCP_LPRSERV 9 28 | #define DHCP_IMPRSERV 10 29 | #define DHCP_RLSERV 11 30 | #define DHCP_HOSTNAME 12 31 | #define DHCP_BOOTFSZ 13 32 | #define DHCP_COREFILE 14 33 | #define DHCP_DOMAIN 15 34 | #define DHCP_SWAPSERV 16 35 | #define DHCP_ROOTPATH 17 36 | #define DHCP_EXTPATH 18 37 | 38 | /* IP Layer Parameters per Host */ 39 | 40 | #define DHCP_IPFRWD 19 41 | #define DHCP_NLSR 20 42 | #define DHCP_PFILTER 21 43 | #define DHCP_MAXDGRASM 22 44 | #define DHCP_IPTTL 23 45 | #define DHCP_PMTUTOUT 24 46 | #define DHCP_PMTUTBL 25 47 | 48 | /* IP Layer Parameters per Interface */ 49 | 50 | #define DHCP_MTU 26 51 | #define DHCP_LSUBNET 27 52 | #define DHCP_BCAST 28 53 | #define DHCP_MASKDISC 29 54 | #define DHCP_MASKSUPP 30 55 | #define DHCP_ROUTDISC 31 56 | #define DHCP_ROUTSOL 32 57 | #define DHCP_STATROUTES 33 58 | 59 | /* Link Layer Parameters per Interface */ 60 | 61 | #define DHCP_TRENCAP 34 62 | #define DHCP_ARPCACHET 35 63 | #define DHCP_ETHENC 36 64 | 65 | /* IP Layer Parameters per Host */ 66 | 67 | #define DHCP_IPFRWD 19 68 | #define DHCP_NLSR 20 69 | #define DHCP_PFILTER 21 70 | #define DHCP_MAXDGRASM 22 71 | #define DHCP_IPTTL 23 72 | #define DHCP_PMTUTOUT 24 73 | #define DHCP_PMTUTBL 25 74 | 75 | /* IP Layer Parameters per Interface */ 76 | 77 | #define DHCP_MTU 26 78 | #define DHCP_LSUBNET 27 79 | #define DHCP_BCAST 28 80 | #define DHCP_MASKDISC 29 81 | #define DHCP_MASKSUPP 30 82 | #define DHCP_ROUTDISC 31 83 | #define DHCP_ROUTSOL 32 84 | #define DHCP_STATROUTES 33 85 | 86 | /* Link Layer Parameters per Interface */ 87 | 88 | #define DHCP_TRENCAP 34 89 | #define DHCP_ARPCACHET 35 90 | #define DHCP_ETHENC 36 91 | 92 | /* TCP Parameters */ 93 | 94 | #define DHCP_TCPTTL 37 95 | #define DHCP_TCPKEEPA 38 96 | #define DHCP_TCPKEEPG 39 97 | 98 | /* Application and Service Parameters */ 99 | 100 | #define DHCP_NISDOM 40 101 | #define DHCP_NISSERV 41 102 | #define DHCP_NTP 42 103 | #define DHCP_VENDOR 43 104 | #define DHCP_NBNS 44 105 | #define DHCP_NBDD 45 106 | #define DHCP_NBNODE 46 107 | #define DHCP_NBSCOPE 47 108 | #define DHCP_XFONTSERV 48 109 | #define DHCP_XDISMANAG 49 110 | 111 | /* DHCP Extensions */ 112 | 113 | #define DHCP_REQIP 50 114 | #define DHCP_IPLEASET 51 115 | #define DHCP_OVERLOAD 52 116 | #define DHCP_MSGTYPE 53 117 | #define DHCP_SERVERID 54 118 | #define DHCP_PARAMREQ 55 119 | #define DHCP_MSG 56 120 | #define DHCP_MAXMAGSZ 57 121 | #define DHCP_RENTIME 58 122 | #define DHCP_REBTIME 59 123 | #define DHCP_CLASSID 60 124 | #define DHCP_CLIENTID 61 125 | 126 | #define DHCP_TFTP 66 127 | #define DHCP_BOOTF 67 128 | 129 | #define DHCP_END 255 130 | #define DHCP_MAXTAG 67 131 | 132 | #define DHCP_MAGICCOOKIE "\x63\x82\x53\x63" 133 | #define DHCP_MIN_OPT 312 134 | 135 | #define DHCP_NONE 0x00 /* no value/unsupported, skip this ! */ 136 | #define DHCP_IPV4 0x01 /* a.b.c.d */ 137 | #define DHCP_ASCII 0x02 /* ASCII string */ 138 | #define DHCP_8I 0x03 /* 8 bit signed int */ 139 | #define DHCP_8UI 0x04 /* 8 bit unisgned int */ 140 | #define DHCP_16I 0x05 /* 16 bit signed int */ 141 | #define DHCP_16UI 0x06 /* 16 bit unsigned int */ 142 | #define DHCP_32I 0x07 /* 32 bit signed int */ 143 | #define DHCP_32UI 0x08 /* 32 bit unsigned int */ 144 | #define DHCP_HEX 0x09 /* hex string */ 145 | #define DHCP_MAC 0x0a /* MAC-style: 12:ab:de:ad:be:ef:...? */ 146 | #define DHCP_BOOL 0x0b /* 1='true', 0='false' */ 147 | #define DHCP_1HEX 0x0c /* _one_ hex char */ 148 | #define DHCP_32TIME 0x0d /* time in seconds, 4 bytes */ 149 | 150 | #define DHCP_TYPEMASK 0x1f /* this mask DHCP_ from options */ 151 | /* 3 options possible: 0x20 0x40 0x80 */ 152 | #define DHCP_MULTI 0x80 /* list of values, like DHCP_ROUTER etc */ 153 | 154 | #define BOOTP_REQUEST 1 155 | #define BOOTP_REPLY 2 156 | 157 | #define BOOTPVENEXT_H 64 /* lenght of bootp vendor extension */ 158 | 159 | struct _dhcpnfoset 160 | { 161 | unsigned char tag; 162 | unsigned char enctype; /* encoding type, DHCP_8I, DHCP_HEX, ... */ 163 | char *name; 164 | }; 165 | 166 | struct _dhcpset 167 | { 168 | unsigned char *sptr; /* start pointer to the dhcp-option array. fix */ 169 | unsigned char *lptr; /* last ptr */ 170 | unsigned long size; /* overall size of the entire buffer sptr */ 171 | unsigned long lsize; /* size of currently used space. (sptr - lptr) */ 172 | unsigned char *lastsub; /* pointer to last suboption field */ 173 | }; 174 | 175 | /* 176 | * we can use this struct as header template (everything is 4 byte aligned, 177 | * no struct-gabs in here. good. 178 | * the 64 byte vendor extension is MISSING here. this is JUST the bootp header. 179 | */ 180 | struct _bootp 181 | { 182 | uint8_t op; /* req == 1;*/ 183 | uint8_t htype; /* 1 = Ethernet */ 184 | uint8_t hlen; /* ethernet = 6 */ 185 | uint8_t hops; /* 0 */ 186 | uint32_t xid; /* xid from client, should be != 0 */ 187 | uint16_t secs; /* 0 (?) */ 188 | uint16_t flags; /* [B| MBZ ] */ 189 | uint32_t ciaddr; /* Client IP address (0.0.0.0) */ 190 | uint32_t yiaddr; /* <- ip address offered to client */ 191 | uint32_t siaddr; /* ip address of next bootstrap server */ 192 | uint32_t giaddr; /* 0 */ 193 | uint8_t chaddr[16]; /* chaddr from client DHCPDISCOVER */ 194 | char sname[4*16];/* Server host name or options */ 195 | char file[8*16]; /* Client boot file name or options */ 196 | uint8_t options[0]; 197 | }; 198 | 199 | const char *dhcp_str(unsigned char); 200 | int init_dhcpset(struct _dhcpset *, unsigned char *, unsigned long len); 201 | int dhcp_add_option(struct _dhcpset *, unsigned char tag, unsigned char len, char *value); 202 | int dhcp_add_suboption(struct _dhcpset *, unsigned char); 203 | int build_bootp(uint8_t *); 204 | char *dhcp_val2str(char *, int, unsigned char, unsigned char, unsigned char *); 205 | struct _dhcpnfoset *dhcp_getnfoset(void); 206 | void dhcp_set_default(struct _dhcpset *ds); 207 | void dhcp_set_all(struct _dhcpset *ds); 208 | 209 | #endif /* !THCRUT_DHCP_H */ 210 | -------------------------------------------------------------------------------- /src/dhcp_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id:$ 3 | */ 4 | 5 | #include "default.h" 6 | #include 7 | #include 8 | #ifdef HAVE_UNISTD_H 9 | # include 10 | #endif 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "thc-rut.h" 16 | #include "dhcp.h" 17 | #include "thcrut_libnet.h" 18 | #include "network_raw.h" 19 | #include "network.h" 20 | #include "range.h" 21 | #include "dhcp.h" 22 | #include "packets.h" 23 | #include "thcrut_pcap.h" 24 | 25 | #define STATE_RESET (0) 26 | #define STATE_DHCPI (1) 27 | #define STATE_DHCPII (2) 28 | #define STATE_DHCPIII (3) 29 | 30 | #define DFL_HOSTS_PARALLEL (10) 31 | 32 | extern struct _opt opt; 33 | static void dhcp_filter(unsigned char *u, struct pcap_pkthdr *p, unsigned char *packet); 34 | 35 | static struct _dhcpset ds; 36 | static uint8_t dsbuf[1024]; 37 | static uint8_t payload[1024]; 38 | static uint8_t srcmac[ETH_ALEN]; 39 | 40 | static libnet_ptag_t ln_udp; 41 | static libnet_ptag_t ln_ip; 42 | static libnet_ptag_t ln_eth; 43 | 44 | /* 45 | * Print out the last suboptions (one:value two:value, ..) 46 | * We trust the input (no error checking) 47 | */ 48 | static void 49 | dhcp_print_lastsub(struct _dhcpset *ds) 50 | { 51 | unsigned char len; /* number of suboptions */ 52 | unsigned char *ptr; 53 | unsigned char i=0; 54 | unsigned char value; 55 | 56 | if (ds->lastsub == NULL) 57 | return; 58 | 59 | len = *(ds->lastsub + 1); 60 | ptr = ds->lastsub + 2; 61 | for (i=0; i < len; i++) 62 | { 63 | value = *ptr++; 64 | fprintf(stderr, "%s(%u) ", dhcp_str(value), value); 65 | } 66 | fprintf(stderr, "\n"); 67 | } 68 | 69 | /* 70 | * Build and send DHCP request. 71 | */ 72 | static int 73 | do_dhcp(uint32_t dstip) 74 | { 75 | int c; 76 | struct _bootp *bp = (struct _bootp *)(payload); 77 | 78 | /* For every request we may pick a random source mac */ 79 | if (opt.flags & FL_OPT_RANDMAC) 80 | MAC_gen_pseudo(srcmac); 81 | 82 | memcpy(bp->chaddr, srcmac, ETH_ALEN); 83 | 84 | ln_udp = libnet_build_udp(68, 85 | 67, 86 | LIBNET_UDP_H + sizeof (struct _bootp) + ds.lsize, 87 | 0, 88 | payload, 89 | sizeof (struct _bootp) + ds.lsize, 90 | opt.ln_ctx, 91 | ln_udp); 92 | 93 | ln_ip = libnet_build_ipv4(LIBNET_IPV4_H + LIBNET_UDP_H + sizeof (struct _bootp) + ds.lsize, 94 | 0, /* TOS */ 95 | opt.ip_id, /* IP ID */ 96 | 0, /* frags */ 97 | 128, /* TTL */ 98 | IPPROTO_UDP, 99 | 0, 100 | opt.src_ip, 101 | dstip, 102 | NULL, 103 | 0, 104 | opt.ln_ctx, 105 | ln_ip); 106 | 107 | ln_eth = libnet_build_ethernet(opt.dst_mac, 108 | srcmac, 109 | ETHERTYPE_IP, 110 | NULL, 0, opt.ln_ctx, ln_eth); 111 | 112 | c = libnet_write(opt.ln_ctx); 113 | 114 | if (c == -1) 115 | ERREXIT("libnet_write() = %d: %s\n", c, libnet_geterror(opt.ln_ctx)); 116 | 117 | return 0; 118 | } 119 | 120 | static void 121 | init_vars(void) 122 | { 123 | opt.ip_socket = init_pcap(&opt.device, 1, "udp and dst port 68", NULL, NULL, &opt.dlt_len); 124 | opt.ln_ctx = init_libnet(opt.device, &opt.src_ip); 125 | 126 | struct libnet_ether_addr *hw; 127 | hw = libnet_get_hwaddr(opt.ln_ctx); 128 | if (hw == NULL) 129 | ERREXIT("libnet_get_hewaddr: %s\n", libnet_geterror(opt.ln_ctx)); 130 | 131 | /* Random mac: Randomize last 4 octets. */ 132 | if ((opt.flags & FL_OPT_RANDMAC) || (!(opt.flags & FL_OPT_SPOOFMAC))) 133 | memcpy(srcmac, hw->ether_addr_octet, ETH_ALEN); 134 | 135 | dhcp_gen_packets(payload, opt.src_ip, dsbuf, &ds); 136 | //HEXDUMP(payload, sizeof (struct _bootp)); 137 | } 138 | 139 | static void 140 | show_info() 141 | { 142 | fprintf(stderr, "Device : %s\n", opt.device); 143 | //fprintf(stderr, "srcMAC : %s", val2mac(bmac.start_mac)); 144 | //fprintf(stderr, "-%s\n", val2mac(bmac.end_mac)); 145 | //fprintf(stderr, "dstMAC : %s\n", val2mac(spfdstmac)); 146 | fprintf(stderr, "srcIP : %s\n", int_ntoa(opt.src_ip)); 147 | fprintf(stderr, "DHCP Opts : "); 148 | dhcp_print_lastsub(&ds); /* print last suboptions */ 149 | } 150 | 151 | static void 152 | usage(void) 153 | { 154 | fprintf(stderr, "" 155 | "usage: dhcp [options] [target IP/Range] ...\n" 156 | " 255.255.255.255 is used as default target.\n" 157 | " -l Hosts in parallel (%d)\n" 158 | /*" -s source IP (%s)\n" */ 159 | " -v vebose\n" 160 | " -m source mac (interace's default or -m 0 for random)\n" 161 | " -d destination mac (default: broadcast)\n" 162 | " -D DHCP option, 0=List DHCP options, all=ALL (!)\n" 163 | "", DFL_HOSTS_PARALLEL); 164 | 165 | exit(0); 166 | } 167 | 168 | static void 169 | init_defaults(void) 170 | { 171 | opt.dst_ip = -1; /* 255.255.255.255 */ 172 | init_dhcpset(&ds, dsbuf, DHCP_MIN_OPT); 173 | if (opt.hosts_parallel == 0) 174 | opt.hosts_parallel = DFL_HOSTS_PARALLEL; 175 | } 176 | 177 | static void 178 | do_getopt(int argc, char *argv[]) 179 | { 180 | char *ptr; 181 | int c; 182 | int dhcp_set = 0; 183 | 184 | optind = 1; 185 | while ( (c = getopt(argc, argv, "+vhd:D:m:")) != -1) 186 | { 187 | switch (c) 188 | { 189 | case 'v': 190 | opt.flags |= FL_OPT_VERBOSE; 191 | break; 192 | case 'D': 193 | if (strncmp(optarg, "all", 3) == 0) 194 | { 195 | dhcp_set = 1; 196 | break; 197 | } 198 | if (atoi(optarg) == 0) 199 | { 200 | list_dhcp(); 201 | exit(0); 202 | } 203 | dhcp_set = 2; 204 | while ( (ptr = strchr(optarg, ',')) != NULL) 205 | { 206 | *ptr++ = '\0'; 207 | dhcp_add_suboption(&ds, atoi(optarg)); 208 | optarg = ptr; 209 | } 210 | if (*optarg != 0) /* someone passed "1," */ 211 | dhcp_add_suboption(&ds, atoi(optarg)); 212 | break; 213 | #if 0 214 | case 's': 215 | opt.src_ip = inet_addr(optarg); 216 | break; 217 | #endif 218 | case 'd': 219 | macstr2mac(opt.dst_mac, optarg); 220 | break; 221 | case 'm': 222 | #ifdef __APPLE__ 223 | fprintf(stderr, "WARNING: MAC spoofing not working on macOS\n"); 224 | #endif 225 | opt.flags |= FL_OPT_SPOOFMAC; 226 | macstr2mac(srcmac, optarg); 227 | if (memcmp(srcmac, ETHZCAST, 6) == 0) 228 | opt.flags |= FL_OPT_RANDMAC; 229 | break; 230 | default: 231 | usage(); 232 | } 233 | } 234 | 235 | if (dhcp_set == 0) 236 | dhcp_set_default(&ds); 237 | if (dhcp_set == 1) 238 | dhcp_set_all(&ds); 239 | 240 | opt.argvlist = &argv[optind]; 241 | opt.argc = argc - optind; 242 | } 243 | 244 | static void 245 | dis_timeout(struct _state *state) 246 | { 247 | switch (STATE_current(state)) 248 | { 249 | case STATE_RESET: 250 | STATE_current(state) = STATE_DHCPI; 251 | do_dhcp(STATE_ip(state)); 252 | break; 253 | case STATE_DHCPI: 254 | STATE_current(state) = STATE_DHCPII; 255 | do_dhcp(STATE_ip(state)); 256 | break; 257 | case STATE_DHCPII: 258 | STATE_current(state) = STATE_DHCPIII; 259 | do_dhcp(STATE_ip(state)); 260 | break; 261 | case STATE_DHCPIII: 262 | STATE_reset(state); 263 | break; 264 | default: 265 | fprintf(stderr, "Unknown state: %d\n", STATE_current(state)); 266 | STATE_reset(state); 267 | break; 268 | } 269 | } 270 | 271 | static void 272 | cb_filter(void) 273 | { 274 | if (pcap_dispatch(opt.ip_socket, -1, (pcap_handler) dhcp_filter, NULL) < 0) 275 | { 276 | pcap_perror(opt.ip_socket, "pcap_dispatch"); 277 | exit(-1); 278 | } 279 | } 280 | 281 | static void 282 | bootp_print(struct ip *ip, struct _bootp *bp, int len) 283 | { 284 | uint8_t *ptr; 285 | int c; 286 | char buf[2048]; 287 | unsigned char dptype, dplen; 288 | 289 | printf("BOOTP reply from %s -> ", int_ntoa(ip->ip_src.s_addr)); 290 | printf("%s\n", int_ntoa(ip->ip_dst.s_addr)); 291 | printf(" Server : %s\n", int_ntoa(bp->siaddr)); 292 | printf(" Client : %s\n", int_ntoa(bp->yiaddr)); 293 | printf(" Relay Agent : %s\n", int_ntoa(bp->giaddr)); 294 | printf(" ServerName : %.*s\n", (int)sizeof bp->sname, bp->sname); 295 | printf(" BootFile : %.*s\n", (int)sizeof bp->file, bp->file); 296 | printf(" MAC : %s\n", val2mac(bp->chaddr)); 297 | 298 | ptr = bp->options; 299 | c = 4; /* magic cookie */ 300 | while (c + 2 < len) 301 | { 302 | if ( (dptype = *(ptr + c++)) == DHCP_END) 303 | break; 304 | if ( (dplen = *(ptr + c)) > len - c) 305 | break; 306 | 307 | dhcp_val2str(buf, sizeof buf, dptype, dplen, ptr + c + 1); 308 | printf(" %s\n", buf); 309 | c += *(ptr + c) + 1; 310 | } 311 | } 312 | 313 | static void 314 | dhcp_filter(unsigned char *u, struct pcap_pkthdr *p, unsigned char *packet) 315 | { 316 | char buf[2048]; 317 | struct ip ip; 318 | struct udphdr *udp = (struct udphdr *)buf; 319 | unsigned short options; 320 | size_t len; /* udp header + data */ 321 | struct _bootp *bp = (struct _bootp *)(buf + 8); 322 | 323 | /* 312 + 20 + 8 */ 324 | if (p->caplen < (opt.dlt_len + 20 + 8)) 325 | return; 326 | memcpy(&ip, packet + opt.dlt_len, sizeof ip); 327 | if ( vrfy_ip(&ip, p->caplen - opt.dlt_len, &options) != 0) 328 | return; 329 | 330 | len = p->caplen - opt.dlt_len - 20 - options; 331 | if (sizeof buf < len) 332 | len = sizeof buf; 333 | memcpy(buf, packet + opt.dlt_len + 20 + options, len); 334 | 335 | if (p->caplen < opt.dlt_len + 20 + options) 336 | return; 337 | 338 | if (ip.ip_p != IPPROTO_UDP) 339 | return; 340 | 341 | if (vrfy_udp(udp, len) != 0) 342 | return; 343 | 344 | if (udp->uh_dport != htons(68)) 345 | return; 346 | 347 | if (bp->op != BOOTP_REPLY) 348 | return; 349 | 350 | if (len > ntohs(udp->uh_ulen)) 351 | len = ntohs(udp->uh_ulen); 352 | 353 | if (len < sizeof(struct _bootp) + 8) 354 | return; /* Empty BOOTP message */ 355 | 356 | bootp_print(&ip, bp, len - 8 - sizeof(struct _bootp)); 357 | } 358 | 359 | int 360 | dhcp_main(int argc, char *argv[]) 361 | { 362 | struct _state state; 363 | int ret; 364 | 365 | memset(payload, 0, sizeof payload); 366 | 367 | init_defaults(); 368 | do_getopt(argc, argv); 369 | init_vars(); 370 | 371 | /* 372 | * Use default broadcast if no IP is given. 373 | */ 374 | if (opt.argc == 0) 375 | { 376 | opt.argvlist--; 377 | opt.argvlist[0] = "255.255.255.255"; 378 | opt.argc++; 379 | } 380 | IP_init(&opt.ipr, opt.argvlist, (opt.flags & FL_OPT_SPREADMODE)?IPR_MODE_SPREAD:0); 381 | 382 | if (opt.flags & FL_OPT_VERBOSE) 383 | show_info(); 384 | 385 | if (!SQ_init(&opt.sq, opt.hosts_parallel, sizeof(struct _state), pcap_fileno(opt.ip_socket), dis_timeout, cb_filter)) 386 | { 387 | fprintf(stderr, "Failed to init states: %s\n", strerror(errno)); 388 | exit(-1); /* Out of Memory */ 389 | } 390 | 391 | /* Set MAC here */ 392 | memset(&state, 0, sizeof state); 393 | while (1) 394 | { 395 | IP_next(&opt.ipr); 396 | /* Start again from the begining in "INFINITE" mode */ 397 | if ((opt.flags & FL_OPT_INFINITE) && (!(IP_current(&opt.ipr)))) 398 | { 399 | IP_reset(&opt.ipr); 400 | IP_next(&opt.ipr); 401 | } 402 | if (IP_current(&opt.ipr)) 403 | { 404 | STATE_ip(&state) = htonl(IP_current(&opt.ipr)); 405 | ret = STATE_wait(&opt.sq, &state); 406 | } else { 407 | 408 | ret = STATE_wait(&opt.sq, NULL); 409 | } 410 | 411 | if (ret != 0) 412 | break; 413 | } 414 | 415 | return 0; 416 | } 417 | 418 | -------------------------------------------------------------------------------- /src/dhcp_main.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id:$ 3 | */ 4 | 5 | 6 | #ifndef __THCRUT_DHCP_MAIN_H__ 7 | #define __THCRUT_DHCP_MAIN_H__ 1 8 | 9 | int dhcp_main(int argc, char *argv[]); 10 | 11 | #endif /* !__THCRUT_DHCP_MAIN_H__ */ 12 | -------------------------------------------------------------------------------- /src/discover_dispatch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: discover_dispatch.h,v 1.4 2003/05/16 08:58:45 skyper Exp $ 3 | */ 4 | 5 | #ifndef __THCRUT_SCANNER_DISPATCH_H__ 6 | #define __THCRUT_SCANNER_DISPATCH_H__ 1 7 | 8 | #include 9 | #include "state.h" 10 | 11 | /* 12 | * The raw socket might overrun if the local network is scanned. 13 | * This is due to arp resolving and a too small kernel buffer. 14 | * We buffer the packets in userland if this happens. The buffer 15 | * is checked and flushed before any state is processed. 16 | * 17 | * FIXME: was passiert wenn im letzten state? return er da nicht 18 | * automatisch oder deleted den state? 19 | * Ist alles unabhaengig von state. sprich state koennte schon auf ende 20 | * sein obwohl noch was im send buffer ist :/ 21 | */ 22 | 23 | /* 24 | * Discovery without FP requires a 40 byte send buffer. 25 | * slen == 0: no buffered data, continue. 26 | */ 27 | struct _state_dis 28 | { 29 | struct _state state; 30 | unsigned short slen; 31 | uint32_t dst_ip; 32 | uint8_t proto; 33 | uint8_t sbuf[20 + FP_MAX_LEN]; /* Does not need to be that large. */ 34 | /* Rather small packets are send */ 35 | /* in discoveyr only phase. ICMP */ 36 | /* is the max. */ 37 | }; 38 | 39 | /* 40 | * FP discovery sends at a max. 60 bytes. 41 | */ 42 | struct _state_fp 43 | { 44 | struct _state state; 45 | unsigned short slen; 46 | uint32_t dst_ip; 47 | uint8_t proto; 48 | uint8_t sbuf[20 + FP_MAX_LEN]; /* send buffer */ 49 | 50 | union _un 51 | { 52 | void *ptr; /* NMAP results */ 53 | char turn; /* Turn */ 54 | } un; 55 | int sox; /* fixme: this only needs to be 10 bits */ 56 | unsigned short port; /* tcp, HBO */ 57 | unsigned char flags; 58 | unsigned char testnr:5; /* number in that category */ 59 | unsigned char cat:3; /* category: TCP, UDP, Banner or WWW */ 60 | char results[0]; 61 | }; 62 | 63 | /* 64 | * Binary output format 65 | */ 66 | struct _binout 67 | { 68 | unsigned short len; 69 | unsigned short reserved; 70 | unsigned int ip; 71 | unsigned int class; 72 | char str[0]; 73 | }; 74 | 75 | #define STATE_FOUND_OPEN_PORT (0x01) 76 | #define STATE_CRLF_SENT (0x02) 77 | 78 | void dis_timeout(struct _state *state); 79 | void scanner_filter(unsigned char *u, struct pcap_pkthdr *p, unsigned char *packet); 80 | 81 | #endif /* !__THCRUT_SCANNER_DISPATCH_H__ */ 82 | -------------------------------------------------------------------------------- /src/discover_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: discover_main.c,v 1.8 2003/05/25 18:19:16 skyper Exp $ 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "default.h" 10 | #include "thc-rut.h" 11 | #include "state.h" 12 | #include "range.h" 13 | #include "thcrut_pcap.h" 14 | #include "thcrut_sig.h" 15 | #include "network_raw.h" 16 | #include "nmap_compat.h" 17 | #include "packets.h" 18 | #include "discover_dispatch.h" 19 | #include "network.h" 20 | #include "thcrut_libnet.h" 21 | 22 | extern struct _opt opt; 23 | extern uint8_t ip_tcp_sync[]; 24 | 25 | struct sockaddr_in ip_tcp_sync_addr; 26 | 27 | #define DFL_HOSTS_PARALLEL (5000) 28 | 29 | void 30 | cb_filter(void) 31 | { 32 | if (pcap_dispatch(opt.ip_socket, -1 /* 1024 */, (pcap_handler) scanner_filter, NULL) < 0) 33 | { 34 | pcap_perror(opt.ip_socket, "pcap_dispatch"); 35 | exit(-1); 36 | } 37 | } 38 | 39 | #if 0 40 | void 41 | cb_timeout(struct _state *state) 42 | { 43 | DEBUGF(" CALLBACK\n"); 44 | STATE_current(state) = 1; 45 | dis_timeout(state); 46 | return; 47 | } 48 | #endif 49 | 50 | static void 51 | launch(struct _ipranges *ipr) 52 | { 53 | char buf[opt.sq.item_size]; 54 | struct _state *state = (struct _state *)buf; 55 | int ret; 56 | 57 | memset(buf, 0, opt.sq.item_size); 58 | 59 | while (1) 60 | { 61 | IP_next(ipr); 62 | // if (IP_current(ipr) && ((IP_current(ipr) == opt.net) || (IP_current(ipr) == opt.bcast))) 63 | // continue; 64 | 65 | if (IP_current(ipr)) 66 | { 67 | STATE_ip(state) = htonl(IP_current(ipr)); 68 | ret = STATE_wait(&opt.sq, state); 69 | } else 70 | ret = STATE_wait(&opt.sq, NULL); 71 | 72 | if (ret != 0) 73 | break; 74 | } 75 | } 76 | 77 | 78 | /* 79 | * init_defaults is called before getopt() 80 | */ 81 | static void 82 | init_defaults(void) 83 | { 84 | opt.flags |= FL_OPT_HOSTDISCOVERY; 85 | if (opt.hosts_parallel == 0) 86 | opt.hosts_parallel = DFL_HOSTS_PARALLEL; 87 | } 88 | 89 | /* 90 | * Return 1 if NMAP file could not be loaded. 91 | * Return 2 if thcrut-os filge could not be loaded 92 | * Return 3 if both failed. 93 | * Return 0 on success. 94 | */ 95 | #define MAX_DIR_LEN (1024) 96 | static int 97 | config_fp_load(char *buf, char *dir) 98 | { 99 | char err = 0; 100 | 101 | snprintf(buf, MAX_DIR_LEN, "%s/nmap-os-fingerprints", dir); 102 | if (NMAP_load_fp(&opt.osfp, buf) != 0) 103 | return 1; 104 | snprintf(buf, MAX_DIR_LEN, "%s/thcrut-os-fingerprints", dir); 105 | if (FP_TS_load(&opt.fpts, buf) != 0) 106 | return 2; 107 | 108 | return err; 109 | } 110 | 111 | /* 112 | * Get source ip of primary interface. 113 | * I dont know any other portable way. The famous binding a UDP socket 114 | * and doing the getsockname() is broken on OpenBSD 2.8(>?) if no 115 | * default gateway is assigned (returns 127.0.0.1 :>). 116 | * 117 | * Return 0 if not found/error. (This way will it be set later by 118 | * the tcp-send-function. This can happen if 'any' device is used). 119 | */ 120 | #if 0 121 | static void 122 | getmyip_by_device(void) 123 | { 124 | struct libnet_link_int *network; 125 | 126 | network = init_libnet(&opt.device, &opt.src_ip); 127 | if (network) 128 | fini_libnet(network); 129 | } 130 | #endif 131 | 132 | /* 133 | * Init vars is called after getopt. 134 | */ 135 | static void 136 | init_vars(void) 137 | { 138 | int i = 1* 1024 * 1024; /* Is reduced to max. anyway */ 139 | size_t size; 140 | char buf[MAX_DIR_LEN]; 141 | char *ptr; 142 | struct stat sbuf; 143 | 144 | /* This goes after getopt */ 145 | if (opt.flags & FL_OPT_HOSTDISCOVERY) 146 | { 147 | if ((ptr = getenv("THCRUTDIR"))) 148 | { 149 | if (config_fp_load(buf, ptr) != 0) 150 | { 151 | fprintf(stderr, "Failed to load \"%s\": %s\n", buf, strerror(errno)); 152 | exit(-1); 153 | } 154 | } else if (config_fp_load(buf, THCRUT_DATADIR) != 0) { 155 | if (config_fp_load(buf, ".") != 0) 156 | { 157 | fprintf(stderr, "Failed to load \"%s\": %s\n", buf, strerror(errno)); 158 | exit(-1); 159 | } 160 | } else if (stat("./thcrut-os-fingerprints", &sbuf) == 0) { 161 | fprintf(stderr, "WARNING: ./thcrut-os-fingerprints exist. Using config files from "THCRUT_DATADIR" for security reasons.\nset THCRUTDIR=. to overwrite.\n"); 162 | } 163 | } 164 | //FP_TS_dump(&opt.fpts); 165 | 166 | //rawsox = libnet_open_raw_sock(IPPROTO_RAW); 167 | opt.ln_ctx = net_sock_raw(); 168 | if (opt.ln_ctx == NULL) 169 | ERREXIT("socket: %s\n", strerror(errno)); 170 | 171 | /* FIXME: Filtering is acutually done in userland (on most 172 | * systems. Our own filter might be much faster.... 173 | * (pcap_dispatch() filters and calls the dispatcher on match. 174 | * The dispatcher has to parse anyway....so why not filter there? 175 | */ 176 | /* init pcap */ 177 | snprintf(buf, sizeof buf, "icmp[4:2] = %u or ((udp or tcp) and (dst port %u or dst port %u or dst port %u))", htons((unsigned short)getpid()), opt.src_port, opt.src_port + 1, opt.src_port + 2); 178 | //DEBUGF("Filter: \"%s\"\n", buf); 179 | opt.ip_socket = init_pcap(&opt.device, 0, buf, &opt.net, &opt.bcast, &opt.dlt_len); 180 | 181 | if (opt.flags & FL_OPT_FP) 182 | { 183 | size = sizeof(struct _state_fp); 184 | /* 185 | * Reserve 2 bits for TCP or UDP state (Open, closed, Unknown) 186 | * Reserve some bytes if we perform banner matching (this sucks memory). 187 | */ 188 | opt.fpts.cat[FP_CAT_NVT].size = opt.fpts.cat[FP_CAT_NVT].n_tests * FP_NTEST_SZ; 189 | opt.fpts.cat[FP_CAT_SNMP].size = opt.fpts.cat[FP_CAT_SNMP].n_tests * FP_STEST_SZ; 190 | opt.fpts.cat[FP_CAT_WWW].size = opt.fpts.cat[FP_CAT_WWW].n_tests * FP_WTEST_SZ; /* 64 bytes for every WWW banner */ 191 | opt.fpts.cat[FP_CAT_BANNER].size = opt.fpts.cat[FP_CAT_BANNER].n_tests * FP_BTEST_SZ; 192 | opt.fpts.cat[FP_CAT_TCP].size = opt.fpts.cat[FP_CAT_TCP].n_tests?opt.fpts.cat[FP_CAT_TCP].n_tests / 4 + 1:0; 193 | opt.fpts.cat[FP_CAT_UDP].size = opt.fpts.cat[FP_CAT_UDP].n_tests?opt.fpts.cat[FP_CAT_UDP].n_tests / 4 + 1:0; 194 | 195 | for (i = 0; i < sizeof opt.fpts.cat / sizeof *opt.fpts.cat; i++) 196 | size += opt.fpts.cat[i].size; 197 | 198 | opt.fpts.ofs_test_tcp = 0; 199 | opt.fpts.ofs_test_udp = opt.fpts.ofs_test_tcp + opt.fpts.cat[FP_CAT_TCP].size; 200 | opt.fpts.ofs_test_banner = opt.fpts.ofs_test_udp + opt.fpts.cat[FP_CAT_UDP].size; 201 | opt.fpts.ofs_test_www = opt.fpts.ofs_test_banner + opt.fpts.cat[FP_CAT_BANNER].size; 202 | opt.fpts.ofs_test_snmp = opt.fpts.ofs_test_www + opt.fpts.cat[FP_CAT_WWW].size; 203 | opt.fpts.ofs_test_nvt = opt.fpts.ofs_test_snmp + opt.fpts.cat[FP_CAT_SNMP].size; 204 | } else { 205 | size = sizeof(struct _state_dis); 206 | } 207 | 208 | /* 209 | * We need the src ip to calculate the correct TCP checksum. 210 | * This wont work on the 'any' device. 211 | */ 212 | //getmyip_by_device(); 213 | scanner_gen_packets(); 214 | 215 | //DEBUGF("size %d %d\n", sizeof(struct _state_fp), size); 216 | if (!SQ_init(&opt.sq, opt.hosts_parallel, size, pcap_fileno(opt.ip_socket), dis_timeout, cb_filter)) 217 | { 218 | fprintf(stderr, "Failed to init states: %s\n", strerror(errno)); 219 | exit(-1); /* Out of Memory */ 220 | } 221 | } 222 | 223 | static void 224 | usage(char *str) 225 | { 226 | if (str) 227 | fprintf(stderr, "%s\n", str); 228 | 229 | printf("" 230 | "usage: discover [options] [IP range] ...\n" 231 | " with IP range of the form a.b.c.d-x.y.z.w\n" 232 | " -d Don't do host discovery (tcp-sync ping, ...)\n" 233 | " -O With OS Fingerprinting\n" 234 | " -v verbose output (fingerprint stamps)\n" 235 | " -l Hosts in parallel (default: %d)\n" 236 | "", DFL_HOSTS_PARALLEL); 237 | if (str) 238 | exit(-1); 239 | exit(0); 240 | } 241 | 242 | /* 243 | * Set source IP, rate limit, ... 244 | */ 245 | static void 246 | do_getopt(int argc, char *argv[]) 247 | { 248 | int c; 249 | 250 | /* 251 | * We call getopt() for a second time. 252 | * Set optind to 0 to reinit getopt() variables. 253 | * We must thus start at index 0 and must 254 | * remove the programs name. 255 | * 256 | * Linux inits (?) but always starts at 1. 257 | */ 258 | optind = 1; 259 | if (argc == 1) 260 | usage("Arguement required"); 261 | 262 | while ((c = getopt(argc, argv, "+Obdhvl:")) != -1) 263 | { 264 | switch (c) 265 | { 266 | case 'l': 267 | opt.hosts_parallel = atoi(optarg); 268 | if (opt.hosts_parallel <= 0) 269 | opt.hosts_parallel = DFL_HOSTS_PARALLEL; 270 | break; 271 | case 'O': 272 | opt.flags |= FL_OPT_FP; 273 | break; 274 | case 'd': 275 | opt.flags &= ~FL_OPT_HOSTDISCOVERY; 276 | break; 277 | case 'b': /* Binary output */ 278 | opt.flags |= FL_OPT_BINOUT; 279 | break; 280 | case 'v': 281 | opt.flags |= FL_OPT_VERBOSE; 282 | break; 283 | case 'h': 284 | usage(NULL); 285 | break; 286 | default: 287 | usage("Wrong option"); 288 | } 289 | } 290 | 291 | if ((opt.flags & FL_OPT_FP) && (opt.hosts_parallel > 1000)) 292 | { 293 | if (opt.hosts_parallel != DFL_HOSTS_PARALLEL) 294 | { 295 | fprintf(stderr, "Operating System Fingerprinting limited to 1000 hosts in parallel (fixed).\n"); 296 | opt.hosts_parallel = 1000; 297 | } else 298 | opt.hosts_parallel = 400; /* Default for OSFP */ 299 | } 300 | 301 | opt.argvlist = &argv[optind]; 302 | opt.argc = argc - optind; 303 | } 304 | 305 | #if 0 306 | static void 307 | test_filter(unsigned char *u, struct pcap_pkthdr *p, unsigned char *packet) 308 | { 309 | static int i; 310 | struct pcap_stat ps; 311 | 312 | return; 313 | i++; 314 | if (i++ <= 1) 315 | return; 316 | if (thcrut_pcap_stats(opt.ip_socket, &ps) == 0) 317 | fprintf(stderr, "TEST %u packets received by filter, %u packets dropped by kernel\n", ps.ps_recv, ps.ps_drop); 318 | i = 0; 319 | } 320 | 321 | void 322 | testme(void) 323 | { 324 | char buf[4096]; 325 | 326 | snprintf(buf, sizeof buf, "icmp[4:2] = %d or ((udp or tcp) and (dst port %d or dst port %d or dst port %d))", htons(getpid()), opt.src_port, opt.src_port + 1, opt.src_port + 2); 327 | //DEBUGF("Filter: \"%s\"\n", buf); 328 | opt.ip_socket = init_pcap(opt.device, 0, /*buf*/ NULL, &opt.net, &opt.bcast, &opt.dlt_len); 329 | 330 | while (1) 331 | { 332 | if (pcap_dispatch(opt.ip_socket, 0, (pcap_handler) test_filter, NULL) < 0) 333 | exit(-1); 334 | } 335 | } 336 | 337 | void 338 | sigchld(int sig) 339 | { 340 | #if 1 341 | struct pcap_stat ps; 342 | 343 | if (thcrut_pcap_stats(opt.ip_socket, &ps) == 0) 344 | fprintf(stderr, "PARENT %u packets received by filter, %u packets dropped by kernel\n", ps.ps_recv, ps.ps_drop); 345 | #endif 346 | _exit(0); 347 | } 348 | #endif 349 | 350 | static libnet_ptag_t ln_ip; 351 | int 352 | testsend(int dst_ip) 353 | { 354 | ln_ip = libnet_build_ipv4( 355 | 20, 356 | 0, 357 | 31337, 358 | 0, 359 | 128, 360 | IPPROTO_TCP, 361 | 0, 362 | opt.src_ip, 363 | dst_ip, 364 | ip_tcp_sync, 365 | 20, 366 | opt.ln_ctx, 367 | ln_ip); 368 | 369 | return net_send(opt.ln_ctx); 370 | } 371 | 372 | #if 1 373 | void 374 | testme(void) 375 | { 376 | int n = 0; 377 | int ret; 378 | 379 | while (n < 100000) 380 | { 381 | ret = testsend(inet_addr("10.1.23.1")); 382 | n++; 383 | if (ret <= 0) 384 | break; 385 | } 386 | DEBUGF("ret = %d after %d packets\n", ret, n); 387 | exit(0); 388 | } 389 | #endif 390 | 391 | int 392 | scanner_main(int argc, char *argv[]) 393 | { 394 | struct pcap_stat ps; 395 | 396 | ERREXIT("discover mode has been disabled in 2020 to allow for major rewrite\n"); 397 | init_defaults(); 398 | do_getopt(argc, argv); 399 | init_vars(); 400 | 401 | signal(SIGPIPE, SIG_IGN); /* Have to ignore this */ 402 | IP_init(&opt.ipr, opt.argvlist, (opt.flags & FL_OPT_SPREADMODE)?IPR_MODE_SPREAD:0); 403 | //testme(); 404 | #if 0 405 | DEBUGF("Total ip's: %u\n", opt.ipr.total); 406 | while (1) 407 | { 408 | IP_next(&opt.ipr); 409 | if (!IP_current(&opt.ipr)) 410 | { 411 | DEBUGF("current is 0\n"); 412 | break; 413 | } 414 | //testsend(IP_current(&ipr)); 415 | DEBUGF("%s\n", int_ntoa(IP_current(&opt.ipr))); 416 | } 417 | return 0; 418 | #endif 419 | launch(&opt.ipr); 420 | 421 | /* This information is unreliable. Drops much more! */ 422 | if (thcrut_pcap_stats(opt.ip_socket, &ps) == 0) 423 | fprintf(stderr, "%u packets received by filter, %u packets dropped by kernel\n", ps.ps_recv, ps.ps_drop); 424 | 425 | return 0; 426 | } 427 | 428 | -------------------------------------------------------------------------------- /src/discover_main.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: discover_main.h,v 1.1 2002/12/17 16:18:20 skyper Exp $ 3 | */ 4 | 5 | #ifndef __THCRUT_SCANNER_MAIN_H__ 6 | #define __THCRUT_SCANNER_MAIN_H__ 1 7 | 8 | int scanner_main(int argc, char **argv); 9 | 10 | #endif /* !__THCRUT_SCANNER_MAIN_H__ */ 11 | -------------------------------------------------------------------------------- /src/fp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: fp.c,v 1.6 2003/05/15 12:13:49 skyper Exp $ 3 | * 4 | * Port State and Banner fingerprinting. 5 | * NMAP tests can be found in a different file (nmap_compat.c). 6 | * 7 | * See thcrut-os-fingperprints for format informations. 8 | * 9 | * Changelog 10 | * - added banner matching support (libpre) 11 | */ 12 | 13 | #include "default.h" 14 | #include 15 | #include 16 | #include "fp.h" 17 | 18 | static char *chomp2(char *buf); 19 | static void FP_addline(struct _fp_testsuite *fp, char *line, unsigned long class, unsigned short ofs_string, size_t n_line); 20 | static char *FP_ITEM_next(char *item); 21 | static int FP_TS_addtest(char **val, char *accuracy, struct _fp_testsuite *fpts, char *item); 22 | 23 | 24 | /* 25 | * Convert a class string into a integer value 26 | * 2.2.1.2.3 = Unix, Solaris, 2.8, whatever 27 | * 28 | * see _classid definition of how it is split up. 29 | */ 30 | #define FP_SCREWUP(CLID, MARK, STR) do{ \ 31 | char *ptr; \ 32 | if (!(ptr = strchr(STR, '.'))) \ 33 | { \ 34 | CLID.st.MARK = atoi(STR); \ 35 | return CLID.id; \ 36 | } \ 37 | *ptr++ = '\0'; \ 38 | CLID.st.MARK = atoi(STR); \ 39 | STR = ptr; \ 40 | }while(0) 41 | unsigned int 42 | FP_class2int(const char *input) 43 | { 44 | char buf[512]; 45 | char *str = buf; 46 | union _classid clid; 47 | 48 | clid.id = 0; 49 | 50 | /* FIXME: strlcpy() */ 51 | snprintf(buf, sizeof buf, "%s", input); 52 | 53 | FP_SCREWUP(clid, genre, str); 54 | FP_SCREWUP(clid, vendor, str); 55 | FP_SCREWUP(clid, os, str); 56 | FP_SCREWUP(clid, d, str); 57 | FP_SCREWUP(clid, dd, str); 58 | FP_SCREWUP(clid, ddd, str); 59 | 60 | return clid.id; 61 | } 62 | 63 | /* 64 | * Converts a class number (long) into 65 | * dotted notation. dst might be a buffer supplied by the user 66 | * 'long enough' to hold the data. 32byte is fine... 67 | * This routine is slow. 68 | */ 69 | char * 70 | FP_class2str(char *dst, unsigned int val) 71 | { 72 | static char mybuf[32]; 73 | char *buf; 74 | union _classid clid; 75 | 76 | clid.id = val; 77 | 78 | if (dst) 79 | buf = dst; 80 | else 81 | buf = mybuf; 82 | 83 | if (clid.st.ddd) 84 | snprintf(buf, 32, "%d.%d.%d.%d.%d.%d", clid.st.genre, clid.st.vendor, clid.st.os, clid.st.d, clid.st.dd, clid.st.ddd); 85 | else if (clid.st.dd) 86 | snprintf(buf, 32, "%d.%d.%d.%d.%d", clid.st.genre, clid.st.vendor, clid.st.os, clid.st.d, clid.st.dd); 87 | else if (clid.st.d) 88 | snprintf(buf, 32, "%d.%d.%d.%d", clid.st.genre, clid.st.vendor, clid.st.os, clid.st.d); 89 | else 90 | snprintf(buf, 32, "%d.%d.%d", clid.st.genre, clid.st.vendor, clid.st.os); 91 | 92 | return buf; 93 | } 94 | 95 | /* 96 | * Remove spaces and comments on both sides. 97 | */ 98 | static char * 99 | chomp2(char *buf) 100 | { 101 | char *end, *ptr; 102 | char inside_quote = 0; 103 | 104 | /* Remove comments from end */ 105 | #if 0 106 | /* Conflict if regex strings contains '#' sign */ 107 | if ( (ptr = strchr(buf, '#'))) 108 | { 109 | *ptr = '\0'; 110 | end = ptr; 111 | } else 112 | #endif 113 | if (*buf == '#') 114 | return NULL; 115 | 116 | while ((*buf) && ((*buf == '\t') || (*buf == ' '))) 117 | buf++; 118 | 119 | ptr = buf; 120 | 121 | /* 122 | * Remove comment from right side 123 | * e.g. find first occurance of # outside the quotes. 124 | */ 125 | while (*ptr) 126 | { 127 | /* Ignore escaped quotes in quotes "\"" etc */ 128 | if (*ptr == '\\') 129 | { 130 | ptr++; 131 | goto next; 132 | } 133 | 134 | if (*ptr == '"') 135 | inside_quote ^= 1; /* swap */ 136 | if (inside_quote) 137 | goto next; 138 | 139 | /* Here we are outside quotes! */ 140 | if (*ptr == '#') 141 | { 142 | *ptr = '\0'; 143 | break; 144 | } 145 | next: 146 | ptr++; 147 | } 148 | 149 | end = buf + strlen(buf) - 1; 150 | 151 | while ((end >= buf) && ((*end == ' ') || (*end == '\t') || (*end == '\n'))) 152 | { 153 | *end = '\0'; 154 | end--; 155 | } 156 | 157 | while ( (buf < end) && ((*buf == ' ') || (*buf == '\t'))) 158 | buf++; 159 | 160 | return buf; 161 | } 162 | 163 | /* 164 | * Read in FP file and create the testsuite. 165 | * 166 | * We keep a list of every test per Fingerprint and a list 167 | * of all unique tests to perform. For the latter one do we 168 | * first check if the test is already in the testsuite and add 169 | * it if necessary. 170 | * 171 | * We have to lookup the class by the results we got from a target. 172 | * Hashing does not seem to be possible. 173 | */ 174 | int 175 | FP_TS_load(struct _fp_testsuite *fpts, const char *filename) 176 | { 177 | FILE *fp; 178 | char buf[1024]; 179 | char *ptr; 180 | unsigned int class = 0; 181 | unsigned short ofs_string = 0; 182 | size_t inuse = 0, size = 0, fpname_len; 183 | size_t n_line = 0; 184 | 185 | fp = fopen(filename, "r"); 186 | if (!fp) 187 | return -1; 188 | 189 | while (fgets(buf, sizeof buf, fp)) 190 | { 191 | n_line++; 192 | ptr = chomp2(buf); 193 | if ((!ptr) || (*ptr == '\0')) 194 | continue; 195 | if (strncmp("Fingerprint", ptr, 11) == 0) 196 | { 197 | ptr += 11; 198 | if (*ptr == ':') 199 | { 200 | class = FP_class2int(ptr + 1); 201 | ptr = strchr(ptr + 1, ' '); 202 | if (!ptr) 203 | continue; 204 | ptr++; 205 | } else 206 | class = 0; 207 | fpname_len = strlen(ptr) + 1; /* cp also \0 */ 208 | if (fpname_len > size - inuse) 209 | { 210 | size = (size + fpname_len + 4096)&~0xFFF; 211 | fpts->strings = realloc(fpts->strings, size); 212 | } 213 | memcpy(fpts->strings + inuse, ptr, fpname_len); 214 | ofs_string = inuse; 215 | inuse += fpname_len; 216 | 217 | continue; /* next line */ 218 | } 219 | FP_addline(fpts, ptr, class, ofs_string, n_line); 220 | } 221 | fclose(fp); 222 | 223 | return 0; 224 | } 225 | 226 | /* 227 | * Add test to testsuite if not already included. 228 | * item is a %-free test item (e.g. "135T=O"). 229 | * 230 | * Return number of this test in the test suites. 231 | * Return -1 on error (>= 0 are valid entries). 232 | * 233 | * We trust our input here. All data comes from a file. 234 | * 235 | * []= 236 | */ 237 | static int 238 | FP_TS_addtest(char **val, char *accuracy, struct _fp_testsuite *fpts, char *item) 239 | { 240 | char *eq = strchr(item, '='); 241 | char type; 242 | unsigned short port; 243 | int i; 244 | struct _fp_ts_test *tests; 245 | unsigned char *n_testsp; 246 | unsigned char cat; 247 | char *ptr; 248 | unsigned char c; 249 | 250 | if (!eq) 251 | return -1; 252 | 253 | /* 254 | * Extract accuracy value which follows the TEST symbol 255 | * (T, U, W, B, ..) 256 | */ 257 | *eq = '\0'; 258 | ptr = eq; 259 | while ((c = *--ptr)) 260 | { 261 | if (((c >= '0') && (c <= '9')) || (c == '-')) 262 | continue; 263 | 264 | break; 265 | } 266 | 267 | type = *ptr; /* Test type */ 268 | *ptr = '\0'; 269 | port = atoi(item); 270 | if (!port) 271 | return -1; 272 | 273 | /* 274 | * The accuracy value 275 | */ 276 | if ((ptr + 1) < eq) 277 | *accuracy = atoi(ptr + 1); 278 | else 279 | *accuracy = -128; /* NO accuracy set, use default later */ 280 | 281 | *val = eq + 1; 282 | 283 | /* 284 | * Parse the item 285 | */ 286 | switch (type) 287 | { 288 | case 'T': 289 | cat = FP_CAT_TCP; 290 | tests = fpts->cat[FP_CAT_TCP].tests; 291 | n_testsp = &fpts->cat[FP_CAT_TCP].n_tests; 292 | break; 293 | case 'U': 294 | cat = FP_CAT_UDP; 295 | tests = fpts->cat[FP_CAT_UDP].tests; 296 | n_testsp = &fpts->cat[FP_CAT_UDP].n_tests; 297 | break; 298 | case 'W': /* GET / HTTP/1.0 */ 299 | cat = FP_CAT_WWW; 300 | tests = fpts->cat[FP_CAT_WWW].tests; 301 | n_testsp = &fpts->cat[FP_CAT_WWW].n_tests; 302 | break; 303 | case 'B': 304 | cat = FP_CAT_BANNER; 305 | tests = fpts->cat[FP_CAT_BANNER].tests; 306 | n_testsp = &fpts->cat[FP_CAT_BANNER].n_tests; 307 | break; 308 | case 'S': 309 | cat = FP_CAT_SNMP; 310 | tests = fpts->cat[FP_CAT_SNMP].tests; 311 | n_testsp = &fpts->cat[FP_CAT_SNMP].n_tests; 312 | break; 313 | case 'N': 314 | cat = FP_CAT_NVT; 315 | tests = fpts->cat[FP_CAT_NVT].tests; 316 | n_testsp = &fpts->cat[FP_CAT_NVT].n_tests; 317 | break; 318 | default: 319 | fprintf(stderr, "Unknown test: \"%s%c=\"\n", item, type); 320 | return -1; 321 | } 322 | 323 | for (i = 0; i < *n_testsp; i++) 324 | if (tests[i].port == port) 325 | return FP_TEST_CAT_NR(cat, i); 326 | 327 | /* Add to testsuite */ 328 | tests[*n_testsp].port = port; 329 | *n_testsp = *n_testsp + 1; 330 | fpts->n_tests++; 331 | 332 | return FP_TEST_CAT_NR(cat, i); 333 | } 334 | 335 | /* 336 | * Return next item of a line. 337 | * First call should be done with a pointer to the string, next call with NULL. 338 | * 339 | * Return NULL if no more items left. 340 | */ 341 | static char * 342 | FP_ITEM_next(char *line) 343 | { 344 | static char *myline; 345 | char *ptr; 346 | char *item; 347 | 348 | /* 349 | * Initialize 350 | */ 351 | if (line) 352 | { 353 | myline = line; 354 | 355 | while (*myline == '%') 356 | myline++; 357 | 358 | return NULL; 359 | } 360 | 361 | /* 362 | * No more items left in this line. 363 | */ 364 | if (!myline) 365 | return NULL; 366 | 367 | ptr = strchr(myline, '%'); 368 | if (ptr) 369 | *ptr++ = '\0'; 370 | item = myline; 371 | myline = ptr; 372 | 373 | return item; 374 | } 375 | 376 | /* 377 | * Parse a test-line (which always follows a 'Fingerprint.*' line. 378 | * Every new test found is linked into the test suite. 379 | * The testline itself is linked into the fingerprint-database. 380 | */ 381 | static void 382 | FP_addline(struct _fp_testsuite *fpts, char *line, unsigned long class, unsigned short ofs_string, size_t n_line) 383 | { 384 | char *ptr = line; 385 | int n = 0; 386 | char inside_quote = 0; 387 | char *item; 388 | char *val; 389 | int testnr_cat; 390 | struct _fp *myfp = NULL; 391 | struct _fp_test *fpt; 392 | static struct _fp *lastfp; 393 | const char *error; 394 | int errptr; 395 | char accuracy; 396 | 397 | while (*ptr) 398 | { 399 | /* Ignore escaped quotes in quotes "\"" etc */ 400 | if (*ptr == '\\') 401 | { 402 | ptr++; 403 | goto next; 404 | } 405 | 406 | if (*ptr == '"') 407 | inside_quote ^= 1; /* swap */ 408 | 409 | if ((!inside_quote) && (*ptr == '%')) 410 | n++; 411 | next: 412 | ptr++; 413 | } 414 | n++; /* No '%' found means 1 line => 1 test */ 415 | 416 | myfp = calloc(1, sizeof *myfp + n * sizeof(struct _fp_test)); 417 | myfp->n_tests = 0; 418 | myfp->class = class; 419 | myfp->ofs_string = ofs_string; 420 | 421 | FP_ITEM_next(line); 422 | while ( (item = FP_ITEM_next(NULL))) 423 | { 424 | 425 | /* get back number of this test. */ 426 | testnr_cat = FP_TS_addtest(&val, &accuracy, fpts, item); 427 | if (testnr_cat < 0) 428 | continue; 429 | 430 | fpt = &myfp->fp_tests[myfp->n_tests++]; 431 | fpt->testnr_cat = testnr_cat; 432 | 433 | switch (*val) 434 | { 435 | case 'U': 436 | case 'O': 437 | fpt->flags = FP_TEST_OPEN; 438 | if (accuracy != -128) 439 | fpt->accuracy = accuracy; 440 | else 441 | fpt->accuracy = 1; 442 | break; 443 | case 'C': 444 | fpt->flags = FP_TEST_CLOSED; 445 | if (accuracy != -128) 446 | fpt->accuracy = accuracy; 447 | else 448 | fpt->accuracy = 1; 449 | break; 450 | case '"': 451 | fpt->flags = FP_TEST_REGEX; 452 | if (accuracy != -128) 453 | fpt->accuracy = accuracy; 454 | else 455 | fpt->accuracy = 2; /* 2 by default; regex */ 456 | val++; 457 | ptr = val; 458 | while ((*ptr) && (*ptr != '"')) 459 | { 460 | /* 461 | * Skip '\"' for example. 462 | */ 463 | if (*ptr == '\\') 464 | ptr++; 465 | if (*ptr) 466 | ptr++; 467 | } 468 | *ptr = '\0'; 469 | fpt->pattern = pcre_compile(val, 0, &error, &errptr, NULL); 470 | if (!fpt->pattern) 471 | { 472 | fprintf(stderr, "string: \"%s\"\n", val); 473 | fprintf(stderr, "%lu: parse error in regex at %d: %s\n", n_line, errptr, error); 474 | exit(-1); 475 | } 476 | fpt->hints = pcre_study(fpt->pattern, 0, &error); 477 | if (error != NULL) 478 | { 479 | fprintf(stderr, "%lu: error in pcre_study: %s\n", n_line, error); 480 | exit(-1); 481 | } 482 | //fpt->str = strdup(val); 483 | break; 484 | default: 485 | fprintf(stderr, "Unknown type behind '='\n"); 486 | } 487 | } 488 | 489 | /* 490 | * New FP's are add at the tail. Should not be changed as it would 491 | * change the semantic of thcrut-os-fingerprint (upward down order 492 | * or downward-up). 493 | */ 494 | if (!fpts->fps) 495 | fpts->fps = myfp; 496 | else 497 | lastfp->next = myfp; 498 | lastfp = myfp; 499 | } 500 | 501 | /* 502 | * Debug function. 503 | * 504 | * Dump the Testsuite. 505 | */ 506 | void 507 | FP_TS_dump(struct _fp_testsuite *fpts) 508 | { 509 | int n, cat; 510 | struct _fp *fp = fpts->fps; 511 | 512 | 513 | while (fp) 514 | { 515 | fprintf(stderr, "%s (%u) with %d tests\n", fpts->strings + fp->ofs_string, fp->class, fp->n_tests); 516 | fp = fp->next; 517 | } 518 | 519 | fprintf(stderr, "Total number of tests: %d\n", fpts->n_tests); 520 | for (cat = 0; cat < sizeof fpts->cat / sizeof *fpts->cat; cat++) 521 | { 522 | for (n = 0; n < fpts->cat[cat].n_tests; n++) 523 | printf("%d\n", fpts->cat[cat].tests[n].port); 524 | } 525 | } 526 | 527 | -------------------------------------------------------------------------------- /src/fp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: fp.h,v 1.6 2003/05/16 08:58:45 skyper Exp $ 3 | * 4 | * Port State fingerprinting 5 | */ 6 | 7 | #ifndef __THCRUT_FP_H__ 8 | #define __THCRUT_FP_H__ 1 9 | #include 10 | #include 11 | 12 | /* 13 | * We store category<->testnr value in one tuple. 14 | * 15 | * The introduction of categories was probably a design mistake. 16 | * The idea was to have the tests sorted by category so that 17 | * tests from one category can be performed before another category. 18 | * It makes for example sense to run the banner-grapping tests 19 | * before the open ports tests. 20 | * 21 | * We enumarate each tests so that we can look them up quickly when 22 | * we have to make a decission if a test matches the results of a host. 23 | * This would be easier with a linear number of tests and would 24 | * not require a switchtable. 25 | * 26 | * To still have them sorted by category but linear numbered we should 27 | * sort them after we read them in and do the enumeration after 28 | * sorting (e.g. a for loop through all categories that copies the 29 | * tests one by one). This would require to read in the file 30 | * twice. First to load and sort the Testsuite itself, then to 31 | * assign the testnumber to the single test-lines. 32 | */ 33 | #define FP_TEST_CAT_NR(cat, nr) (((nr & 0x1f) << 3) | (cat & 0x7)) 34 | #define FP_TEST_NR(test) (((test)->testnr_cat & ~0x7) >> 3) 35 | #define FP_TEST_CAT(test) ((test)->testnr_cat & 0x7) 36 | struct _fp_test 37 | { 38 | pcre *pattern; 39 | pcre_extra *hints; 40 | unsigned char testnr_cat; /* Number and cat of this test */ 41 | unsigned char flags; /* port state */ 42 | char *varname; /* != NULL: It's a variable. use accuracy */ 43 | /* value from variable-hash. */ 44 | char accuracy; /* 1 for port, 2 for banner default */ 45 | }; 46 | 47 | #define FP_TEST_CLOSED 0x01 /* same for UDP/TCP */ 48 | #define FP_TEST_OPEN 0x02 49 | #define FP_TEST_REGEX 0x03 /* Must match string *str */ 50 | 51 | /* 52 | * One 'Fingerprint.*' line may be followed by many 53 | * fingerprint test lines. Currently we allocate a new _fp for each 54 | * of these lines even if they all point to the same Fingerprint.* line. 55 | */ 56 | struct _fp 57 | { 58 | struct _fp *next; 59 | unsigned int class; 60 | unsigned short ofs_string; 61 | 62 | unsigned char n_tests; /* Number of checks for THIS fp */ 63 | struct _fp_test fp_tests[0]; /* we love C */ 64 | }; 65 | 66 | 67 | /* 68 | * Type W is the www test. 69 | * W test occupies 4 bytes of memory 70 | * S test occupies 4 bytes of memory 71 | * T and U test 2 bytes 72 | * 73 | * We can even use static char here. We dont expect the user 74 | * to have more than 128 different ports. 75 | * 76 | * Testsuite must carry the human representation of the tests. 77 | */ 78 | struct _fp_ts_test 79 | { 80 | unsigned short port; 81 | }; 82 | 83 | struct _fp_category 84 | { 85 | unsigned char n_tests; 86 | size_t size; /* total size of bytes for results of this category */ 87 | struct _fp_ts_test tests[32]; 88 | }; 89 | 90 | /* 91 | * If you change this you also want to change the 2 bit's in 92 | * struct _state_fp 93 | */ 94 | #define FP_CAT_TCP 0x00 95 | #define FP_CAT_UDP 0x01 96 | #define FP_CAT_BANNER 0x02 97 | #define FP_CAT_WWW 0x03 98 | #define FP_CAT_SNMP 0x04 99 | #define FP_CAT_NVT 0x05 100 | #define FP_CAT_SMB 0x06 /* RESERVED */ 101 | #define FP_CAT_RES3 0x07 /* RESERVERD */ 102 | #define FP_CAT_MAX 0x08 /* change state.h if exceeded */ 103 | 104 | /* 105 | * The performed tests are dynamic and read form the thcrut-os-fingerprints 106 | * file. The access to the results of the tests is thus also 107 | * dynamic. 108 | */ 109 | struct _fp_testsuite 110 | { 111 | int ofs_test_tcp; 112 | int ofs_test_udp; 113 | int ofs_test_banner; 114 | int ofs_test_www; 115 | int ofs_test_snmp; 116 | int ofs_test_nvt; 117 | unsigned char n_tests; /* Total number of different tests in fp-file */ 118 | struct _fp_category cat[6]; 119 | 120 | char *strings; 121 | struct _fp *fps; /* Linked list of Fingerprints */ 122 | }; 123 | /* 124 | * Required size for the results of the unique tests. 125 | */ 126 | #define FP_WTEST_SZ (64) /* HEAD / test output */ 127 | #define FP_BTEST_SZ (128) /* Banner test */ 128 | #define FP_STEST_SZ (128) /* SNMP test */ 129 | #define FP_NTEST_SZ (128) /* NVT Terminal */ 130 | 131 | struct _fp_nodequery 132 | { 133 | unsigned short trans_id; 134 | unsigned short flags; 135 | unsigned short questions; 136 | unsigned short answers; 137 | unsigned short auth_rrs; 138 | unsigned short add_rrs; 139 | }; 140 | 141 | /* 142 | * Right now all variables are stored lineary. 143 | * We do not expect to have more than 50 144 | */ 145 | struct _fp_vararray 146 | { 147 | unsigned short ofs_varname; 148 | char accuracy; 149 | struct _fp_tests *tests; /* Linked list of Tests for this Varname */ 150 | }; 151 | 152 | /* 153 | * Windows NODE query request (port 137). 154 | * How dirty to use a static request but it never changes unless 155 | * MS decides to change their protocol suite. This wont happen :> 156 | */ 157 | #define FP_NODEQUERY "\x20\x43\x4b\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x00\x00\x21\x00\x01" 158 | #define FP_NODEQUERY_LEN (38) 159 | 160 | /* 161 | * WIndows DCE bind request. 162 | */ 163 | #define FP_DCEBIND "\x05\x00\x0b\x03\x10\x00\x00\x00\x48\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x10\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00\x08\x83\xaf\xe1\x1f\x5d\xc9\x11\x91\xa4\x08\x00\x2b\x14\xa0\xfa\x03\x00\x00\x00\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10\x48\x60\x02\x00\x00\x00" 164 | /* It is actually enough to send 1 byte of payload to trigger windows for a 165 | * reject packet. 166 | */ 167 | #define FP_DCEBIND_LEN (50) 168 | 169 | /* 170 | * SNMP 'public' GET-NEXT system.sysDescr.0 171 | */ 172 | #define FP_SNMP "\x30\x82\x00\x27\x02\x01\x00\x04\x06\x70\x75\x62\x6c\x69\x63\xa1\x1a\x02\x01\x01\x02\x01\x00\x02\x01\x00\x30\x0f\x30\x82\x00\x0b\x06\x07\x2b\x06\x01\x02\x01\x01\x00\x05\x00" 173 | #define FP_SNMP_LEN (43) 174 | 175 | #define FP_MAX_LEN (50) 176 | 177 | union _classid 178 | { 179 | struct 180 | { 181 | #if LIBNET_BIG_ENDIAN 182 | unsigned int genre:9; 183 | unsigned int vendor:6; 184 | unsigned int os:5; 185 | /* 9 + 6 + 5 = 20 bits */ 186 | unsigned int d:4; 187 | unsigned int dd:4; 188 | unsigned int ddd:4; 189 | #elif LIBNET_LIL_ENDIAN 190 | unsigned int ddd:4; 191 | unsigned int dd:4; 192 | unsigned int d:4; 193 | /* 9 + 6 + 5 = 20 bits */ 194 | unsigned int os:5; 195 | unsigned int vendor:6; 196 | unsigned int genre:9; 197 | #endif 198 | } st; 199 | unsigned int id; 200 | }; 201 | 202 | 203 | int FP_TS_load(struct _fp_testsuite *fpts, const char *filename); 204 | void FP_TS_dump(struct _fp_testsuite *fpts); 205 | char *FP_class2str(char *dst, unsigned int val); 206 | unsigned int FP_class2int(const char *input); 207 | 208 | #endif /* !__THCRUT_FP_H__ */ 209 | -------------------------------------------------------------------------------- /src/gen_macvendor-list-h.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | 3 | #f = open("manuf-small", "r"); 4 | f = open("manuf", "r"); 5 | 6 | structstr = """ 7 | 8 | /* 9 | * DO NOT EDIT THIS FILE. CHANGES WILL BE OVERWRITTEN. 10 | * 11 | * This file is generated by gen_macvendor-list-h.py >macvlist.h 12 | * and takes 'manuf' as input. The 'manuf' file is available from 13 | * wireshark: 14 | * wget https://gitlab.com/wireshark/wireshark/raw/master/manuf 15 | */ 16 | struct _macvendor 17 | { 18 | uint64_t macid; 19 | char * name; 20 | }; 21 | 22 | struct _macvendor macvendorlist[] = 23 | { 24 | """ 25 | 26 | for line in f: 27 | #print (line) 28 | if line[0] == '#': 29 | continue 30 | 31 | nt = line.find('\t') 32 | if nt < 8: 33 | continue 34 | if nt > 20: 35 | print ("SHOULD NOT HAPPEN") 36 | continue 37 | mac = line[0:nt] 38 | ns = mac.find('/') 39 | if ns > 0: 40 | mac = mac[0:ns] 41 | #print (mac) 42 | 43 | if len(mac) > 18: 44 | print ("SHOULD NOT HAPPEN") 45 | continue 46 | 47 | n = 0 48 | val = 0 49 | MacHex = "0x" 50 | while (n < 4): 51 | 52 | if line[(n+1)*3-1] == ':': 53 | MacHex += mac[n*3:(n+1)*3-1] 54 | #print (mac[n*3:(n+1)*3-1]) 55 | else: 56 | break 57 | 58 | n = n + 1 59 | 60 | #print (mac[n*3:(n+1)*3-1]) 61 | MacHex += mac[n*3:(n+1)*3-1] 62 | while (n < 4): 63 | #print ("00") 64 | MacHex += "00" 65 | n = n + 1 66 | 67 | nv = line[nt+1:].find('\t') 68 | 69 | if (nv > 0): 70 | vendor = line[nt+1+nv+1:] # Long string is available 71 | else: 72 | vendor = line[nt+1:] # only small name is available 73 | 74 | # Remove multple whitespaces 75 | vendor = " ".join(vendor.split()) 76 | # and make quotes safe for C... 77 | vendor = vendor.replace('"', '') 78 | 79 | structstr += " {" + MacHex + ", \"" + vendor.rstrip()[:63] + "\"},\n" 80 | 81 | structstr += """}; 82 | """ 83 | 84 | print (structstr) 85 | 86 | -------------------------------------------------------------------------------- /src/icmp_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id:$ 3 | */ 4 | 5 | #include "default.h" 6 | #include 7 | #include 8 | #include "network.h" 9 | #include "network_raw.h" 10 | #include "thc-rut.h" 11 | #include "thcrut_pcap.h" 12 | #include "packets.h" 13 | #include "icmp_main.h" 14 | #include "thcrut_pcap.h" 15 | 16 | static void init_defaults(void); 17 | static void init_vars(void); 18 | static void do_getopt(int argc, char *argv[], struct _state_icmp *state); 19 | static void usage(void); 20 | static void icmp_filter(unsigned char *u, struct pcap_pkthdr *p, unsigned char *packet); 21 | static void dis_timeout(struct _state *state); 22 | static void cb_filter(void); 23 | static size_t sendicmp(struct _state_icmp *, size_t len, libnet_ptag_t *ln_ptag); 24 | 25 | #define DFL_HOSTS_PARALLEL (1024) 26 | 27 | #define STATE_RESET (0) 28 | #define STATE_ICMPI (1) 29 | #define STATE_ICMPII (2) 30 | #define STATE_ICMPIII (3) 31 | 32 | extern struct _opt opt; 33 | 34 | static libnet_ptag_t ln_ip_echo; 35 | static libnet_ptag_t ln_ip_treq; 36 | static libnet_ptag_t ln_ip_amask; 37 | static libnet_ptag_t ln_ip_rsol; 38 | 39 | static libnet_ptag_t ln_echo; 40 | static libnet_ptag_t ln_tstamp; 41 | static libnet_ptag_t ln_amask; 42 | static libnet_ptag_t ln_rsol; 43 | 44 | static void 45 | init_defaults(void) 46 | { 47 | if (opt.hosts_parallel == 0) 48 | opt.hosts_parallel = DFL_HOSTS_PARALLEL; 49 | } 50 | 51 | static void 52 | init_vars(void) 53 | { 54 | DEBUGF("foobar\n"); 55 | opt.ip_socket = init_pcap(&opt.device, 1, "icmp", &opt.net, &opt.bcast, &opt.dlt_len); 56 | DEBUGF("foobar\n"); 57 | 58 | opt.ln_ctx = net_sock_raw(); 59 | DEBUGF("foobar\n"); 60 | if (opt.ln_ctx == NULL) 61 | { 62 | fprintf(stderr, "socket: %s\n", strerror(errno)); 63 | exit(-1); 64 | } 65 | } 66 | 67 | static void 68 | usage(void) 69 | { 70 | fprintf(stderr, "" 71 | "usage: icmp [options] [IP range] ...\n" 72 | " -P ICMP echo request (default)\n" 73 | " -T ICMP Timestamp Request\n" 74 | " -A ICMP Address mask request (obsolete)\n" 75 | " -R ICMP MCAST Router solicitation request\n" 76 | /* Spoofing not possible because we dont reply to arp requests */ 77 | //" -s Source ip to use\n" 78 | " -l Hosts in parallel (%d)\n" 79 | "", DFL_HOSTS_PARALLEL); 80 | 81 | exit(0); 82 | } 83 | 84 | 85 | static void 86 | do_getopt(int argc, char *argv[], struct _state_icmp *state) 87 | { 88 | int c; 89 | 90 | optind = 1; 91 | while ( (c = getopt(argc, argv, "+TPARh:l:")) != -1) 92 | { 93 | switch (c) 94 | { 95 | case 'P': 96 | state->flags |= FL_ST_ECHO; 97 | break; 98 | case 'A': 99 | state->flags |= FL_ST_AMASK; 100 | break; 101 | case 'T': 102 | state->flags |= FL_ST_TREQ; 103 | break; 104 | case 'R': 105 | state->flags |= FL_ST_RSOL; 106 | break; 107 | case 'l': 108 | opt.hosts_parallel = atoi(optarg); 109 | break; 110 | default: 111 | usage(); 112 | break; 113 | } 114 | } 115 | 116 | opt.argvlist = &argv[optind]; 117 | opt.argc = argc - optind; 118 | 119 | if (!(state->flags & (FL_ST_ECHO | FL_ST_AMASK | FL_ST_RSOL | FL_ST_TREQ))) 120 | state->flags |= FL_ST_ECHO; 121 | } 122 | 123 | /* 124 | * Return 0 if blocked. 125 | * FIXME: Can happen that we always get blocked after second 126 | * ICMP type is send out. In any case do we repeat and send 127 | * first ICMP type again. 128 | */ 129 | static int 130 | sendpackets(struct _state_icmp *state, unsigned int seq) 131 | { 132 | uint8_t payload[56]; 133 | struct timeval tv; 134 | 135 | if (state->flags == 0) 136 | { 137 | fprintf(stderr, "%s:%d SHOULD NOT HAPPEN\n", __func__, __LINE__); 138 | abort(); 139 | } 140 | 141 | gettimeofday(&tv, NULL); 142 | 143 | if (state->flags & FL_ST_ECHO) 144 | { 145 | memset(payload, 0, sizeof payload); 146 | memcpy(payload, &tv, sizeof tv); 147 | 148 | ln_echo = libnet_build_icmpv4_echo(ICMP_ECHO, 149 | 0, 150 | 0, /* crc */ 151 | opt.ic_id, 152 | seq, /* HBO */ 153 | payload, 154 | sizeof payload, 155 | opt.ln_ctx, 156 | ln_echo); 157 | 158 | if (sendicmp(state, LIBNET_ICMPV4_ECHO_H + sizeof payload, &ln_ip_echo) == 0) 159 | return 0; 160 | } 161 | 162 | if (state->flags & FL_ST_TREQ) 163 | { 164 | uint32_t ms; 165 | ms = ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)) % (24*60*60*1000); 166 | 167 | ln_tstamp = libnet_build_icmpv4_timestamp(ICMP_TSTAMP, 168 | 0, 169 | 0, /* crc */ 170 | opt.ic_id, 171 | seq, /* HBO */ 172 | ms, /* otime */ 173 | 0, /* rtime */ 174 | 0, /* ttime */ 175 | NULL, 176 | 0, 177 | opt.ln_ctx, 178 | ln_tstamp); 179 | 180 | if (sendicmp(state, LIBNET_ICMPV4_TS_H, &ln_ip_treq) == 0) 181 | return 0; 182 | } 183 | #if 1 184 | /* Almost no routers/hosts answer to this request any longer... */ 185 | if (state->flags & FL_ST_AMASK) 186 | { 187 | uint32_t amask = 0; 188 | 189 | ln_amask = libnet_build_icmpv4_mask(ICMP_MASKREQ, 190 | 0, 191 | 0, /* crc */ 192 | opt.ic_id, 193 | seq, /* HBO */ 194 | amask, 195 | NULL, 196 | 0, 197 | opt.ln_ctx, 198 | ln_amask); 199 | 200 | if (sendicmp(state, LIBNET_ICMPV4_MASK_H, &ln_ip_amask) == 0) 201 | return 0; 202 | } 203 | #endif 204 | 205 | #if 1 206 | if (state->flags & FL_ST_RSOL) 207 | { 208 | /* Libnet has no support for RSOL so we hack it into ECHO */ 209 | ln_rsol = libnet_build_icmpv4_echo(ICMP_ROUTERSOLICIT, 210 | 0, 211 | 0, /* crc */ 212 | 0, /* rsol, reserved */ 213 | 0, /* rsol, reserved */ 214 | NULL, 215 | 0, 216 | opt.ln_ctx, 217 | ln_rsol); 218 | 219 | if (sendicmp(state, 8 + 0, &ln_ip_rsol) == 0) 220 | return 0; 221 | } 222 | #endif 223 | 224 | return 1; 225 | } 226 | 227 | /* 228 | * FIXME: On block'ed send we should use wfds to see when socket 229 | * becomes writeable again. (But this would delay our queue :/). 230 | */ 231 | static void 232 | dis_timeout(struct _state *state) 233 | { 234 | struct _state_icmp *state_icmp = (struct _state_icmp *)state; 235 | 236 | /* Switch state if we send successfully, otherwise 237 | * stay in state to try again. 238 | */ 239 | switch (STATE_current(state)) 240 | { 241 | case STATE_RESET: 242 | if (sendpackets(state_icmp, 0) != 0) 243 | STATE_current(state) = STATE_ICMPI; 244 | break; 245 | case STATE_ICMPI: 246 | if (sendpackets(state_icmp, 1) != 0) 247 | STATE_current(state) = STATE_ICMPII; 248 | break; 249 | case STATE_ICMPII: 250 | if (sendpackets(state_icmp, 2) != 0) 251 | STATE_current(state) = STATE_ICMPIII; 252 | break; 253 | case STATE_ICMPIII: 254 | STATE_reset(state); 255 | break; 256 | default: 257 | fprintf(stderr, "Unknown state: %d\n", STATE_current(state)); 258 | STATE_reset(state); 259 | break; 260 | } 261 | } 262 | 263 | static void 264 | cb_filter(void) 265 | { 266 | if (pcap_dispatch(opt.ip_socket, -1, (pcap_handler) icmp_filter, NULL) < 0) 267 | { 268 | pcap_perror(opt.ip_socket, "pcap_dispatch"); 269 | exit(-1); 270 | } 271 | } 272 | 273 | #ifndef LIBNET_IPV4_H 274 | # define LIBNET_IPV4_H 0x14 275 | #endif 276 | 277 | /* 278 | * Return number 0 if blocked, -1 on error >0 otherwise. 279 | */ 280 | static size_t 281 | sendicmp(struct _state_icmp *state, size_t len, libnet_ptag_t *ln_ptag) 282 | { 283 | *ln_ptag = libnet_build_ipv4( 284 | LIBNET_IPV4_H + len, 285 | 0, 286 | opt.ip_id, 287 | 0, 288 | 128, 289 | IPPROTO_ICMP, 290 | 0, 291 | opt.src_ip, 292 | STATE_ip(state), 293 | NULL, 294 | 0, 295 | opt.ln_ctx, 296 | *ln_ptag); 297 | 298 | return net_send(opt.ln_ctx); 299 | } 300 | 301 | static void 302 | icmp_filter(unsigned char *u, struct pcap_pkthdr *p, unsigned char *packet) 303 | { 304 | char buf[128]; 305 | struct ip *ip = (struct ip *)(buf); 306 | struct _state_icmp *state; 307 | int len; 308 | unsigned short options = 0; 309 | struct icmp *icmp; 310 | struct timeval diff, *tv; 311 | 312 | /* 313 | * At least... 314 | */ 315 | if (p->caplen < (opt.dlt_len + 20 + 8)) 316 | return; 317 | 318 | len = p->caplen - opt.dlt_len; 319 | if (len > sizeof buf) 320 | len = sizeof buf; 321 | 322 | memcpy(buf, packet + opt.dlt_len, len); 323 | if (vrfy_ip(ip, len, &options) != 0) 324 | return; 325 | if (!(state = (struct _state_icmp *)STATE_by_ip(&opt.sq, ip->ip_src.s_addr))) 326 | return; 327 | 328 | if (ntohs(ip->ip_len) > len) 329 | return; 330 | len = ntohs(ip->ip_len) - 20 - options; 331 | 332 | icmp = (struct icmp *)(buf + 20 + options); 333 | /* ICMP ECHO REPLY */ 334 | if (((icmp->icmp_type == 0) && (icmp->icmp_code == 0)) && (len >= 8 + 8)) 335 | { 336 | if (state->flags & FL_ST_ECHO) 337 | { 338 | state->flags &= ~FL_ST_ECHO; 339 | tv = (struct timeval *)((char *)icmp + 8); 340 | SQ_TV_diff(&diff, tv, &p->ts); 341 | /* ttl= time= xx.yyy msec */ 342 | printf("%-16s %d bytes reply icmp_seq=%d ttl=%03d time=", int_ntoa(ip->ip_src.s_addr), len, ntohs(icmp->icmp_hun.ih_idseq.icd_seq), ip->ip_ttl); 343 | if (diff.tv_sec) 344 | printf("%ld.%03ld sec\n", (long int)diff.tv_sec, (long int)diff.tv_usec / 1000); 345 | else if (diff.tv_usec / 1000) 346 | printf("%ld.%03ld msec\n", (long int)diff.tv_usec / 1000, (long int)diff.tv_usec % 1000); 347 | else 348 | printf("%ld usec\n", (long int)diff.tv_usec % 1000); 349 | } 350 | goto end; 351 | } 352 | /* ICMP MASK REPLY */ 353 | if ((icmp->icmp_type == ICMP_MASKREPLY) && (len >= 8 + 4)) 354 | { 355 | if (state->flags & FL_ST_AMASK) 356 | { 357 | state->flags &= ~FL_ST_AMASK; 358 | printf("%-16s icmp_seq=%d ttl=%03d mask=", int_ntoa(ip->ip_src.s_addr), ntohs(icmp->icmp_hun.ih_idseq.icd_seq), ip->ip_ttl); 359 | printf("%s\n", int_ntoa(*(long *)((char *)icmp + 8))); 360 | } 361 | goto end; 362 | } 363 | /* ICMP TIMESTAMP REPLY */ 364 | if ((icmp->icmp_type == ICMP_TSTAMPREPLY) && (len >= 8 + 12)) 365 | { 366 | if (state->flags & FL_ST_TREQ) 367 | { 368 | state->flags &= ~FL_ST_TREQ; 369 | uint32_t ms; 370 | /* Extract Receive Timestamp */ 371 | memcpy(&ms, (char *)icmp + 8 + 4, sizeof ms); 372 | //DEBUGF("BE: %u\n", ms); 373 | /* BUG: Some host return Little Endian */ 374 | if (ms > 60 * 60 * 24 * 1000) 375 | ms = ntohl(ms); 376 | //DEBUGF("LE: %u\n", ms); 377 | uint32_t ts_hour = ms / (60 * 60 * 1000); 378 | uint32_t ts_min = (ms / 1000 / 60) % 60; 379 | float ts_sec = (float)(ms % (60 * 1000)) / 1000; 380 | printf("%-16s %d bytes reply time-rec %d hours, %d minutes, %.03f seconds\n", int_ntoa(ip->ip_src.s_addr), len, ts_hour, ts_min, ts_sec); 381 | } 382 | 383 | goto end; 384 | } 385 | /* ICMP DEST UNREACHABLE 386 | * ICMP Time Stamp Reply may trigger a Dest-unreable by the target 387 | * host. If this is the case then we still want to display the fact 388 | * because it means the host is alive. 389 | */ 390 | if ((icmp->icmp_type == ICMP_UNREACH) && (icmp->icmp_type == ICMP_UNREACH_PORT) && (len >= 8 + 20 + 8 + 12)) 391 | { 392 | struct ip *ip_orig; 393 | ip_orig = (struct ip *)(buf + 20 + options + 8); 394 | /* Skip if a router rejects it. We only want to know if the 395 | * original target host is 'alive' but care not about a router 396 | * inbetween 397 | */ 398 | if (ip_orig->ip_dst.s_addr != ip->ip_src.s_addr) 399 | goto end; 400 | 401 | if (state->flags & FL_ST_TREQ) 402 | { 403 | state->flags &= ~FL_ST_TREQ; 404 | printf("%-16s %d bytes reply time-rec not supported (unreachable. Host alive.)\n", int_ntoa(ip->ip_src.s_addr), len); 405 | } 406 | 407 | goto end; 408 | } 409 | 410 | /* ICMP ROUTE RSOL REPLY */ 411 | if (icmp->icmp_type == ICMP_ROUTERADVERT) 412 | { 413 | if (state->flags & FL_ST_RSOL) 414 | { 415 | state->flags &= ~FL_ST_RSOL; 416 | printf("%s ROUTER SOLICITATION. DECODING NOT IMPLEMENTED. FIXME\n", int_ntoa(ip->ip_src.s_addr)); 417 | } 418 | goto end; 419 | } 420 | #if 0 421 | /* We dont sniff for this one */ 422 | DEBUGF("type %d, code %d\n", icmp->type, icmp->code); 423 | hexdump(buf, 24); 424 | #endif 425 | end: 426 | if (!state->flags) 427 | STATE_reset(state); 428 | } 429 | 430 | int 431 | icmp_main(int argc, char *argv[]) 432 | { 433 | struct _state_icmp state; 434 | struct pcap_stat ps; 435 | int ret; 436 | 437 | init_defaults(); 438 | memset(&state, 0, sizeof state); 439 | do_getopt(argc, argv, &state); 440 | init_vars(); 441 | DEBUGF("foobar\n"); 442 | 443 | /* By default do the local network */ 444 | if (opt.argc == 0) 445 | { 446 | opt.argvlist--; 447 | opt.argvlist[0] = getmy_range(); 448 | } 449 | 450 | IP_init(&opt.ipr, opt.argvlist, (opt.flags & FL_OPT_SPREADMODE)?IPR_MODE_SPREAD:0); 451 | 452 | if (!SQ_init(&opt.sq, opt.hosts_parallel, sizeof state, pcap_fileno(opt.ip_socket), dis_timeout, cb_filter)) 453 | { 454 | fprintf(stderr, "Failed to init states: %s\n", strerror(errno)); 455 | exit(-1); 456 | } 457 | 458 | while (1) 459 | { 460 | IP_next(&opt.ipr); 461 | /* Start again from the begining in "INFINITE" mode */ 462 | if ((opt.flags & FL_OPT_INFINITE) && (!(IP_current(&opt.ipr)))) 463 | { 464 | IP_reset(&opt.ipr); 465 | IP_next(&opt.ipr); 466 | } 467 | if (IP_current(&opt.ipr)) 468 | { 469 | STATE_ip(&state) = htonl(IP_current(&opt.ipr)); 470 | ret = STATE_wait(&opt.sq, (struct _state *)&state); 471 | } else 472 | ret = STATE_wait(&opt.sq, NULL); 473 | 474 | if (ret != 0) 475 | break; 476 | } 477 | 478 | if (thcrut_pcap_stats(opt.ip_socket, &ps) == 0) 479 | fprintf(stderr, "%u packets received by filter, %u packets dropped by kernel\n", ps.ps_recv, ps.ps_drop); 480 | 481 | return 0; 482 | } 483 | 484 | -------------------------------------------------------------------------------- /src/icmp_main.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id:$ 3 | */ 4 | 5 | #ifndef __THCRUT_ICMP_MAIN_H__ 6 | #define __THCRUT_ICMP_MAIN_H__ 1 7 | 8 | #include "state.h" 9 | 10 | struct _state_icmp 11 | { 12 | struct _state state; 13 | char flags; 14 | }; 15 | #define FL_ST_ECHO 0x01 16 | #define FL_ST_AMASK 0x02 17 | #define FL_ST_RSOL 0x04 18 | #define FL_ST_TREQ 0x08 19 | 20 | int icmp_main(int argc, char *argv[]); 21 | 22 | #endif /* !__THCRUT_ICMP_MAIN_H__ */ 23 | -------------------------------------------------------------------------------- /src/macvendor.c: -------------------------------------------------------------------------------- 1 | 2 | //#define DEBUG 1 3 | #include "default.h" 4 | 5 | #include "macvlist.h" 6 | 7 | #define MACVENDOR_MIN_NELSON (2) /* Min distance between top and end for Nelson Search */ 8 | 9 | /* 10 | * Return a vendor string or an empty string "" by mac. 11 | */ 12 | const char * 13 | MacVendor_by_mac(uint8_t *mac) 14 | { 15 | uint64_t mac_id; 16 | char *vendor = ""; 17 | 18 | /* Convert 6-byte hw mac address to ID that can be used for lookup */ 19 | /* ID's for lookup ignore the last byte of the mac address to save space */ 20 | mac_id = mac[4]; 21 | mac_id |= (uint64_t)mac[3] << 8; 22 | mac_id |= (uint64_t)mac[2] << (8*2); 23 | mac_id |= (uint64_t)mac[1] << (8*3); 24 | mac_id |= (uint64_t)mac[0] << (8*4); 25 | 26 | //DEBUGF("Looking for %llx \n", mac_id); 27 | 28 | /* Perform a Newton Search */ 29 | 30 | uint32_t top_loc = 0; 31 | uint32_t end_loc = sizeof macvendorlist / sizeof *macvendorlist - 1; 32 | uint64_t top_mid; 33 | uint64_t end_mid; 34 | uint32_t loc = 0; 35 | while (1) 36 | { 37 | //DEBUGF("top_loc %d, end_loc %d\n", top_loc, end_loc); 38 | if (top_loc >= sizeof macvendorlist / sizeof *macvendorlist - 1) 39 | break; 40 | 41 | /* Stop if there are just a few locations between top<->end and do sequential search */ 42 | if (end_loc - top_loc + 1 < MACVENDOR_MIN_NELSON) 43 | { 44 | //DEBUGF("Narrowed it down to %d locations...\n", end_loc - top_loc + 1); 45 | break; 46 | } 47 | top_mid = macvendorlist[top_loc].macid; 48 | end_mid = macvendorlist[end_loc].macid; 49 | //DEBUGF("MICS %llx..%llx\n", top_mid, end_mid); 50 | if (top_mid > mac_id) 51 | { 52 | fprintf(stderr, "SHOULD NOT HAPPEN\n"); 53 | break; 54 | } 55 | 56 | /* Make a guess where which location our value could be */ 57 | uint64_t diff = end_mid - top_mid; 58 | uint64_t chunk_size = diff / (end_loc - top_loc); 59 | loc = (mac_id - top_mid) / chunk_size + top_loc; 60 | 61 | //DEBUGF("I think it's at location %u\n", loc); 62 | 63 | /* Check if we overshot and move end_loc up to our guessed location. 64 | * Our guessed location becomes the new end_loc. Try again on this smaller group. 65 | */ 66 | if (macvendorlist[loc].macid > mac_id) 67 | { 68 | //DEBUGF("Overshot. %llx > %llx\n", macvendorlist[loc].macid, mac_id); 69 | end_loc = loc - 1; 70 | /* Can we recover from an overshot a bit better? */ 71 | if (macvendorlist[top_loc + (end_loc - top_loc) / 2].macid < mac_id) 72 | { 73 | //DEBUGF("Recovering...\n"); 74 | top_loc = top_loc + (end_loc - top_loc) / 2; 75 | } 76 | continue; 77 | } 78 | 79 | /* HERE: mac_id is somewhere between top_loc ... end_loc */ 80 | /* If the next location has a mac that's larger than ours than the current 81 | * location is the nearest hit. 82 | */ 83 | if (macvendorlist[loc + 1].macid > mac_id) 84 | { 85 | //DEBUGF("biggert. %llx > %llx\n", macvendorlist[loc+1].macid, mac_id); 86 | break; 87 | } 88 | /* Check if we guessed the same location and if so move up by 1...we are near..*/ 89 | if (top_loc == loc) 90 | top_loc = loc + 1; 91 | else 92 | top_loc = loc; 93 | 94 | /* HERE: Our new chunk to search in... */ 95 | 96 | /* Adjust the 'end' if it is far away... */ 97 | if (macvendorlist[top_loc + (end_loc - top_loc)/2].macid > mac_id) 98 | end_loc = top_loc + (end_loc - top_loc)/2; 99 | } 100 | 101 | /* There can be duplicated in the list such as this one 102 | * 00:1B:C5 IEEERegi IEEE Registration Authority 103 | * 00:1B:C5:00:00:00/36 Convergi Converging Systems Inc. 104 | * Check if the next immediately following is a better hit. 105 | * Also doing sequential search here after Nelson search (small chunk left). 106 | */ 107 | int i; 108 | for (i = 0; i < MACVENDOR_MIN_NELSON; i++) 109 | { 110 | if (loc < sizeof macvendorlist / sizeof *macvendorlist - 1) 111 | break; 112 | if (macvendorlist[loc+1].macid > mac_id) 113 | break; 114 | loc++; 115 | } 116 | 117 | vendor = macvendorlist[loc].name; 118 | //DEBUGF("Vendor: %s\n", vendor); 119 | return vendor; 120 | } 121 | 122 | 123 | #if 0 124 | int 125 | main(int argc, char *argv[]) 126 | { 127 | 128 | //MacVendor_by_mac((uint8_t *)"\x00\x00\x01\x00\xab\xcd"); 129 | MacVendor_by_mac((uint8_t *)"\xFC\xFF\xFF\xaa\xbb\xcc"); 130 | //MacVendor_by_mac((uint8_t *)"\xF0\xB3\xD5\x67\x41\x11"); 131 | 132 | for (int i = 0; i < sizeof macvendorlist / sizeof *macvendorlist - 1; i++) 133 | { 134 | uint8_t buf[6]; 135 | uint64_t macid; 136 | const char *vendor; 137 | 138 | macid = macvendorlist[i].macid; 139 | /* Self test: Ignore duplicated.. 140 | */ 141 | if (macid == macvendorlist[i+1].macid) 142 | continue; 143 | buf[5] = 0xab; 144 | buf[4] = macid >> 0*8; 145 | buf[3] = macid >> 1*8; 146 | buf[2] = macid >> 2*8; 147 | buf[1] = macid >> 3*8; 148 | buf[0] = macid >> 4*8; 149 | //HEXDUMP(buf, 6); 150 | 151 | vendor = MacVendor_by_mac(buf); 152 | if (macvendorlist[i].name != vendor) 153 | ERREXIT("NOT FOUND\n"); 154 | 155 | } 156 | exit(0); 157 | } 158 | #endif 159 | -------------------------------------------------------------------------------- /src/macvendor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Vendor <-> mac 3 | * RUT, anonymous@segfault.net 4 | */ 5 | 6 | #ifndef THCRUT_MACVENDOR_H 7 | #define THCRUT_MACVENDOR_H 1 8 | 9 | 10 | const char *MacVendor_by_mac(uint8_t *mac); 11 | 12 | char *mac2vendor(unsigned char *tag); 13 | 14 | #endif /* !THCRUT_MACVENDOR_H */ 15 | 16 | -------------------------------------------------------------------------------- /src/network.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: network.c,v 1.4 2003/05/23 14:14:01 skyper Exp $ 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "network.h" 15 | 16 | /* 17 | */ 18 | void 19 | MAC_gen_pseudo(uint8_t *buf) 20 | { 21 | uint32_t r = rand(); 22 | 23 | buf[2] = (r >> 24) & 0xFF; 24 | buf[3] = (r >> 16) & 0xFF; 25 | buf[4] = (r >> 8) & 0xFF; 26 | buf[5] = r & 0xFF; 27 | #if 0 28 | long l = time(NULL); 29 | 30 | if (l & 0x100) /* change vendor every 256 seconds */ 31 | memcpy(buf, "\x00\x10\x66\x66\x66\x66", 6); 32 | else 33 | memcpy(buf, "\x00\x01\x66\x73\x50", 5); 34 | buf[2] = (l >> 8) & 0xFF; 35 | buf[3] = (l >> 10) & 0xFF; 36 | buf[4] = (l >> 7) & 0xFF; 37 | buf[5] = (l >> 9) & 0xFF; 38 | #endif 39 | } 40 | 41 | /* 42 | * Lame routine to get our own src address. 43 | * dst is in NBO. 44 | * Return IP in NBO. 45 | * 46 | * FIXME: This wont work if no default gw exist! 47 | * We have to lookup ip from device. 48 | */ 49 | int 50 | getmyip_by_dst(int dst) 51 | { 52 | int sox = socket(AF_INET, SOCK_DGRAM, 0); 53 | struct sockaddr_in sock; 54 | socklen_t socklen = sizeof(struct sockaddr_in); 55 | 56 | sock.sin_family = AF_INET; 57 | sock.sin_addr.s_addr = dst; 58 | sock.sin_port = 7350; 59 | 60 | connect(sox, (struct sockaddr *)&sock, sizeof sock); 61 | if (getsockname(sox, (struct sockaddr *)&sock, &socklen) == -1) 62 | sock.sin_addr.s_addr = 0; 63 | 64 | close(sox); 65 | return sock.sin_addr.s_addr; 66 | } 67 | 68 | #ifndef int_ntoa 69 | const char * 70 | int_ntoa(uint32_t ip) 71 | { 72 | struct in_addr in; 73 | 74 | in.s_addr = ip; 75 | return inet_ntoa(in); 76 | } 77 | #endif 78 | 79 | -------------------------------------------------------------------------------- /src/network.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: network.h,v 1.4 2003/05/23 14:14:01 skyper Exp $ 3 | */ 4 | 5 | 6 | #ifndef __THCRUT_NETWORK_H__ 7 | #define __THERUT_NETWORK_H__ 1 8 | 9 | #ifndef ETH_ALEN 10 | # define ETH_ALEN (6) 11 | #endif 12 | 13 | int getmyip_by_dst(int dst); 14 | void MAC_gen_pseudo(uint8_t *buf); 15 | #ifndef int_ntoa 16 | const char *int_ntoa(uint32_t ip); 17 | #endif 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/network_raw.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: network_raw.c,v 1.8 2003/05/23 14:14:01 skyper Exp $ 3 | */ 4 | #include "default.h" 5 | #include "fcntl.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "network_raw.h" 12 | 13 | /* 14 | * len of the data we got. We might have less options here. 15 | * (rest is payload). 16 | */ 17 | int 18 | vrfy_tcp(struct tcphdr *tcp, uint32_t len, u_short *tcp_options) 19 | { 20 | u_short _tcp_options; 21 | 22 | if (len < sizeof *tcp) 23 | return -1; 24 | _tcp_options = tcp->th_off << 2; 25 | if (_tcp_options < sizeof *tcp) 26 | return -1; 27 | 28 | if (_tcp_options > len) 29 | return -1; 30 | 31 | if (tcp_options) 32 | *tcp_options = _tcp_options - sizeof *tcp; 33 | 34 | return 0; 35 | } 36 | 37 | /* 38 | * return 0 if ip-header is valid [length only] 39 | * len = length from the begin of the ip-header [20 for normal ip header] 40 | */ 41 | int 42 | vrfy_ip(struct ip *ip, uint32_t len, u_short *ip_options) 43 | { 44 | u_short _ip_options; 45 | 46 | if (len < sizeof *ip) 47 | return -1; 48 | _ip_options = ip->ip_hl << 2; 49 | 50 | if (_ip_options < sizeof *ip) 51 | return -1; 52 | 53 | if (_ip_options > len) 54 | return -1; 55 | 56 | if (_ip_options > 0xefff) /* NO, we dont accept this ! */ 57 | return -1; 58 | 59 | if (ip_options) 60 | *ip_options = _ip_options - sizeof *ip; 61 | 62 | return 0; 63 | } 64 | 65 | int 66 | vrfy_udp(struct udphdr *udp, uint32_t len) 67 | { 68 | if (len < sizeof(*udp)) 69 | return -1; 70 | 71 | return 0; 72 | } 73 | 74 | /* 75 | * return 0 if header is valid 76 | * return -1 if not 77 | * and -2 is unknown 78 | * this function should _only_ be used with thc-rut! 79 | * this function is _not_ portable...we only check for icmp-codes/types 80 | * we are interested in. 81 | */ 82 | int 83 | vrfy_icmp (struct icmp *icmp, uint32_t len) 84 | { 85 | if (len < ICMP_MINLEN) 86 | return (-1); 87 | 88 | switch (icmp->icmp_type) 89 | { 90 | case ICMP_MASKREPLY: 91 | if (icmp->icmp_code != 0) 92 | return -2; 93 | if (len >= ICMP_MASKLEN) 94 | return 0; 95 | else 96 | return -1; 97 | /* check _ALL_ icmp_type == 18 types HERE */ 98 | return -2; 99 | case ICMP_ECHOREPLY: 100 | if (icmp->icmp_code == 0) 101 | return 0; 102 | return -2; 103 | case ICMP_ECHO: 104 | if (icmp->icmp_code == 0) 105 | return 0; 106 | return -2; 107 | break; 108 | default: 109 | return -2; /* header invalid if type/code not known */ 110 | } 111 | 112 | return 0; 113 | } 114 | 115 | /* 116 | * slow inet_ntoa but in function-supplied buffer and not 117 | * static buffer like inet_ntoa 118 | */ 119 | char * 120 | int_ntop(char *buf, struct in_addr in) 121 | { 122 | 123 | sprintf(buf, "%s", inet_ntoa(*((struct in_addr *)&(in)))); 124 | 125 | return buf; 126 | } 127 | 128 | 129 | /* 130 | * convert a mac to a colon seperated string 131 | */ 132 | char * 133 | val2mac(unsigned char *ptr) 134 | { 135 | static char buf[64]; 136 | 137 | sprintf(buf, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", 138 | (u_char)ptr[0], 139 | (u_char)ptr[1], 140 | (u_char)ptr[2], 141 | (u_char)ptr[3], 142 | (u_char)ptr[4], 143 | (u_char)ptr[5]); 144 | 145 | return buf; 146 | } 147 | 148 | void 149 | init_ip(char *buf) 150 | { 151 | 152 | } 153 | 154 | void 155 | init_tcp(char *buf) 156 | { 157 | 158 | } 159 | 160 | void 161 | macstr2mac(unsigned char *dst, char *str) 162 | { 163 | unsigned short int sp[ETH_ALEN]; 164 | int c = ETH_ALEN; 165 | 166 | memset(&sp, 0, sizeof sp); 167 | sscanf(str, "%hx:%hx:%hx:%hx:%hx:%hx", &sp[0], &sp[1], &sp[2],&sp[3], &sp[4], &sp[5]); 168 | 169 | while (c-- > 0) 170 | dst[c] = (unsigned char)sp[c]; 171 | } 172 | 173 | /* 174 | * Open an UNBLOCKING RAW socket used for sending. 175 | */ 176 | libnet_t * 177 | net_sock_raw(void) 178 | { 179 | char err_buf[LIBNET_ERRBUF_SIZE]; 180 | libnet_t *ln_ctx; 181 | 182 | ln_ctx = libnet_init(LIBNET_RAW4_ADV, NULL, err_buf); 183 | if (ln_ctx == NULL) 184 | ERREXIT("libnet_init: %s\n", err_buf); 185 | return ln_ctx; 186 | } 187 | 188 | /* 189 | * Return the number of bytes written. 190 | * This function can exit. 191 | * 192 | * Return -1 on error. Return 0 if would_block. 193 | * Note: I dont think we ever return 0 here (blocking)... 194 | */ 195 | size_t 196 | net_send(libnet_t *ln_ctx) 197 | { 198 | size_t len; 199 | #ifdef DEBUG 200 | static char full_once; 201 | #endif 202 | 203 | len = libnet_write(ln_ctx); 204 | if (len == -1) 205 | { 206 | #if 1 207 | /* No arp reply [local netowrk scan] */ 208 | if (errno == EHOSTDOWN) 209 | return -1; 210 | /* Linux: No route to network [no default gw] */ 211 | if (errno == ENETUNREACH) 212 | return -1; 213 | /* OpenBSD: No route to host [no default gw] */ 214 | if (errno == EHOSTUNREACH) 215 | return -1; 216 | #endif 217 | /* 218 | * The Problem: When scanning local networks. The buffer 219 | * buffers all the data and tries to resolve the arp. 220 | * We cant say (from userland) if the buffer is full because 221 | * the kernel is still trying to resolve the mac or if the buffer 222 | * is full because the kernel still sends. 223 | * 224 | * Needed: On error decide if the packet has already been 225 | * retransmitted for 3 times and discard _only_ if the kernel 226 | * failed to do so because the mac could not be resolved. 227 | * 228 | * Return error whenever it's something different than buffer-full. 229 | * 230 | * OpenBSD 2.8 returns EMSGSIZE(40) if buf full 231 | * OpenBSD 2.8 returns ENONET(64) if arp unresolved 232 | * 233 | * Linux returns EACCESS if tcp send to broadcast (10.2.0.0) 234 | */ 235 | if ((errno != ENOBUFS) && (errno != EMSGSIZE)) 236 | { 237 | DEBUGF("WRITE ERROR (%d)%s\n", errno, strerror(errno)); 238 | return -1; 239 | } 240 | 241 | #ifdef DEBUG 242 | if (!full_once) 243 | { 244 | fprintf(stderr, "" 245 | "WARNING: send buffer full. A kernel buffer most probably ran out of memory\n" 246 | "while resolving the mac's (scanning local network, eh?). Waiting until\n" 247 | "more buffer space becomes available...\n"); 248 | full_once = 1; 249 | } 250 | #endif 251 | return -1; /* We never 'would block */ 252 | } 253 | 254 | return len; 255 | } 256 | 257 | -------------------------------------------------------------------------------- /src/network_raw.h: -------------------------------------------------------------------------------- 1 | #ifndef THCRUT_NETWORK_RAW_H 2 | #define THCRUT_NETWORK_RAW_H 1 3 | 4 | #include 5 | /* Conflict on OpenBsd 2.8 & libnet */ 6 | /* #include */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef ETH_ALEN 13 | # define ETH_ALEN (6) 14 | #endif 15 | 16 | int vrfy_ip(struct ip *, uint32_t, u_short *); 17 | int vrfy_tcp(struct tcphdr *tcp, uint32_t len, u_short *tcp_options); 18 | int vrfy_udp(struct udphdr *, uint32_t); 19 | int vrfy_icmp(struct icmp *, uint32_t); 20 | char *int_ntop(char *, struct in_addr); 21 | char *val2mac(unsigned char *); 22 | void macstr2mac(unsigned char *dst, char *str); 23 | libnet_t *net_sock_raw(void); 24 | size_t net_send(libnet_t *ln_ctx); 25 | 26 | #endif /* !THCRUT_NETWORK_RAW_H */ 27 | 28 | -------------------------------------------------------------------------------- /src/nmap_compat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: nmap_compat.c,v 1.3 2003/05/15 12:13:49 skyper Exp $ 3 | * 4 | * THCrut (c)2001 The Hackers Choice 5 | */ 6 | 7 | #include "default.h" 8 | #include "thc-rut.h" 9 | #include "nmap_compat.h" 10 | #include "fp.h" 11 | 12 | static int wsize_tok(unsigned short *val, char *wsize); 13 | static int add_tones(struct _nmap_osfp *osfp, char *buf, unsigned long ofs_string, unsigned long class); 14 | static int ops_tok(unsigned long *val, char *ops); 15 | static void NMAP_HASH_add(struct _nmap_osfp *osfp, struct _nmap_osfp_TONE *tone); 16 | 17 | 18 | /* 19 | * Convert vanille tcp-options to NMAP OSFP representation. 20 | * return -1 on error. 21 | * 22 | * A human (nmap format) readable string of the ops is returned 23 | * in opstr (if supplied). 24 | */ 25 | unsigned long 26 | NMAP_tcpops2ops(char *opstr, char *buf, size_t len) 27 | { 28 | unsigned long ops = 0; 29 | int ofs = 0; 30 | unsigned short s; 31 | 32 | while (ofs < len) 33 | { 34 | ops <<= 3; 35 | switch (buf[ofs]) 36 | { 37 | case 0: /* E, End of list */ 38 | ops |= 6; 39 | ofs++; 40 | if (opstr) 41 | *opstr++ = 'E'; 42 | break; 43 | case 1: /* N, NOP */ 44 | ops |= 2; 45 | ofs++; 46 | if (opstr) 47 | *opstr++ = 'N'; 48 | break; 49 | case 2: /* M, Max Segment Size */ 50 | ops |= 1; 51 | ofs++; 52 | if (opstr) 53 | *opstr++ = 'M'; 54 | if (ofs + 2 > len) 55 | break; 56 | s = (buf[ofs] << 8) + buf[ofs + 1]; 57 | ofs += 3; 58 | if (s != 265) 59 | break; 60 | /* E, ??? */ 61 | if (opstr) 62 | *opstr++ = 'E'; 63 | ops <<= 3; 64 | ops |= 5; 65 | break; 66 | case 3: /* W, ??? */ 67 | ops |= 3; 68 | ofs += 3; 69 | if (opstr) 70 | *opstr++ = 'W'; 71 | break; 72 | case 8: /* T, ??? */ 73 | ops |= 4; 74 | ofs += 10; 75 | if (opstr) 76 | *opstr++ = 'T'; 77 | break; 78 | default: 79 | fprintf(stderr, "Unknown tcp option %x\n", buf[ofs]); 80 | ofs++; 81 | } 82 | } 83 | 84 | *opstr = '\0'; 85 | 86 | return ops; 87 | } 88 | 89 | #define NMAP_TONE_ADJ (10) 90 | 91 | /* 92 | * Load nmap style fingerprint file and extract Testsuite 1 (TONE). 93 | * Return 0 on success. 94 | */ 95 | int 96 | NMAP_load_fp(struct _nmap_osfp *osfp, char *file) 97 | { 98 | FILE *fp; 99 | char buf[1024]; 100 | char *ptr; 101 | unsigned int class = 0; 102 | char *end; 103 | size_t size = 0, inuse = 0; 104 | size_t fpname_len = 1; 105 | 106 | if (!file) 107 | file = getenv("NMAP_OS_FINGERPRINTS"); 108 | if (!file) 109 | file = "./nmap-os-fingerprints"; 110 | 111 | fp = fopen(file, "r"); 112 | if (!fp) 113 | return -1; 114 | 115 | memset(osfp, 0, sizeof *osfp); 116 | 117 | while (fgets(buf, sizeof buf, fp)) 118 | { 119 | if (*buf == '#') 120 | continue; 121 | /* Remove comment and everything after comment */ 122 | /* FIXME: also remove all white spaces from the right. */ 123 | /* Fucking nmap format. Cant Fyodor use a better one? */ 124 | end = strchr(buf, '#'); 125 | if (end) 126 | *end = '\0'; 127 | else 128 | end = buf + strlen(buf); 129 | 130 | if ((*buf != 0) && (*(end - 1) == '\n')) 131 | *--end = '\0'; 132 | 133 | if (end > buf) 134 | { 135 | while ((end > buf) && ((*(end - 1) == ' ') || (*(end - 1) == '\t'))) 136 | end--; 137 | *end = '\0'; 138 | } 139 | 140 | if (strncmp(buf, "Fingerprint", 11) == 0) 141 | { 142 | ptr = &buf[11]; 143 | if (*ptr == ':') 144 | { 145 | if ((ptr = strchr(&buf[12], ' '))) 146 | *ptr++ = '\0'; 147 | class = FP_class2int(&buf[12]); 148 | //fprintf(stderr, "hoaa %d\n", class); 149 | } else { 150 | ptr++; 151 | class = 0; 152 | } 153 | // fprintf(stderr, "OS:%d:%s\n", class, ptr); 154 | /* FIXME: skip without strings */ 155 | fpname_len = end - ptr + 1; 156 | if (fpname_len > size - inuse) 157 | { 158 | size = (size + fpname_len + 4096)&~0xFFF; 159 | osfp->strings = realloc(osfp->strings, size); 160 | } 161 | memcpy(osfp->strings + inuse, ptr, fpname_len); 162 | 163 | continue; 164 | } 165 | 166 | if (strncmp(buf, "T1(", 3) == 0) 167 | { 168 | if (add_tones(osfp, buf, inuse, class) != 0) 169 | continue; 170 | inuse += fpname_len; 171 | fpname_len = 0; 172 | } 173 | } 174 | 175 | fclose(fp); 176 | 177 | return 0; 178 | } 179 | 180 | /* 181 | * BAH, Fyodor use a VERY STUPID format. I bet he didnt use his brain 182 | * how to parse this before doing the format... 183 | */ 184 | /* 185 | * Parse a T1 test line from nmap-os-fingerprints 186 | * Example: 187 | * T1(DF=N%W=0|800%ACK=S++%Flags=AR|AS%Ops=|M) 188 | * FIXME: We currently ignore FLAGS (can be BAS, AS, AR, ARS, APS, BAR, ..) 189 | * NMAP documentation is wrong when it says that T1 is performed against 190 | * an open port. A reply with Flags=AR is not Open for me. This has 191 | * been realized after implementing. Our version of the T1 test is just 192 | * run against an open port. 193 | * 194 | * buf is \0 terminated, might be \n terminated. 195 | * 196 | * Return 0 on success. 197 | * 198 | * We will never ever unload them. 199 | */ 200 | static int 201 | add_tones(struct _nmap_osfp *osfp, char *buf, unsigned long ofs_string, unsigned long class) 202 | { 203 | static long current_tone; 204 | static struct _nmap_osfp_TONE *tone; 205 | struct _nmap_osfp_TONE this; 206 | static long free_tone; 207 | char *next; 208 | char *df; 209 | char *wsize; 210 | char *ops; 211 | char *end; 212 | char *ptr; 213 | unsigned long l; 214 | 215 | memset(&this, 0, sizeof this); 216 | 217 | 218 | /* Get a good format here */ 219 | if ( (next = strchr(buf, '('))) 220 | *next = '%'; 221 | if ( (next = strchr(buf, ')'))) 222 | *next = '%'; 223 | 224 | /* Split it for what we check for */ 225 | if ( (df = strstr(buf, "%DF="))) 226 | df += 4; 227 | if ( (wsize = strstr(buf, "%W="))) 228 | wsize += 3; 229 | if ( (ops = strstr(buf, "%Ops="))) 230 | ops += 5; 231 | ptr = buf; 232 | end = buf + strlen(buf); 233 | 234 | /* subst all % with 0. */ 235 | while (ptr < end) 236 | { 237 | if (*ptr == '%') 238 | *ptr = '\0'; 239 | ptr++; 240 | } 241 | 242 | if (df) 243 | { 244 | if (strchr(df, 'N')) 245 | NMAP_DF_SET_ISNOTSET(&this); 246 | if (strchr(df, 'Y')) 247 | NMAP_DF_SET_ISSET(&this); 248 | } 249 | 250 | wsize_tok(NULL, wsize); 251 | while (wsize_tok(&this.wsize, NULL) == 0) 252 | { 253 | ops_tok(NULL, ops); 254 | 255 | while (ops_tok(&l, NULL) == 0) 256 | { 257 | this.ops = l; 258 | /* Parse through the Ops... */ 259 | // fprintf(stderr, "wsize: %ld, ops: %d, df: %d\n", this.wsize, this.ops, this.df); 260 | /* 261 | * Allocate in blocks. 262 | */ 263 | if (current_tone >= free_tone) 264 | { 265 | tone = calloc(NMAP_TONE_ADJ, sizeof *tone); 266 | current_tone = 0; 267 | free_tone = NMAP_TONE_ADJ; 268 | } 269 | 270 | tone->ops = this.ops; 271 | tone->df = this.df; 272 | tone->wsize = this.wsize; 273 | tone->ofs_string = ofs_string; 274 | tone->class = class; 275 | NMAP_HASH_add(osfp, tone); 276 | 277 | tone++; 278 | current_tone++; 279 | } 280 | } 281 | 282 | 283 | return 0; 284 | } 285 | 286 | struct _nmap_osfp_TONE * 287 | NMAP_lookup(struct _nmap_osfp *osfp, unsigned short wsize, char df, unsigned long ops) 288 | { 289 | int idx = (wsize ^ ops) % NMAP_HASH_SIZE; 290 | struct _nmap_osfp_TONE *tone = osfp->hash_tone[idx]; 291 | 292 | if (!tone) 293 | return NULL; 294 | 295 | do { 296 | // fprintf(stderr, "%x found %s\n", tone->wsize, osfp->strings + toone->ofs_string); 297 | if (NMAP_TONE_MATCH(tone, wsize, df, ops)) 298 | return tone; 299 | #if 0 300 | if (tone->wsize != wsize) 301 | continue; 302 | if (tone->ops != ops) 303 | continue; 304 | if ((df) && (NMAP_DF_ISSET(tone))) 305 | return tone; 306 | if (NMAP_DF_ISNOTSET(tone)) 307 | return tone; 308 | #endif 309 | } while ( (tone = tone->next)); 310 | 311 | return NULL; 312 | } 313 | 314 | static void 315 | NMAP_HASH_add(struct _nmap_osfp *osfp, struct _nmap_osfp_TONE *tone) 316 | { 317 | int idx = (tone->wsize ^ tone->ops) % NMAP_HASH_SIZE; 318 | #if 0 319 | struct _nmap_osfp_TONE *old; 320 | 321 | old = NMAP_lookup(osfp, tone->wsize, NMAP_DF_ISSET(tone)?1:0, tone->ops); 322 | if (old) 323 | return; 324 | // fprintf(stderr, "FP for %s already exist: %s\n", osfp->strings + tone->ofs_string, osfp->strings + old->ofs_string); 325 | #endif 326 | 327 | tone->next = osfp->hash_tone[idx]; 328 | osfp->hash_tone[idx] = tone; 329 | } 330 | 331 | static int 332 | ops_tok(unsigned long *val, char *ops) 333 | { 334 | static char buf[128]; 335 | static char *ptr; 336 | char *next; 337 | int shift; 338 | 339 | if (ops) 340 | { 341 | strncpy(buf, ops, sizeof buf); 342 | buf[sizeof buf - 1] = '\0'; 343 | ptr = buf; 344 | 345 | return 0; 346 | } 347 | 348 | if (!ptr) 349 | return -1; 350 | 351 | next = strchr(ptr, '|'); 352 | if (next) 353 | *next++ = '\0'; 354 | 355 | /* 356 | * max of 10 options 357 | */ 358 | *val = 0; 359 | shift = strlen(ptr) - 1; 360 | if (shift > 10) 361 | shift = 10; 362 | 363 | while (*ptr != '\0') 364 | { 365 | switch (*ptr) 366 | { 367 | case 'M': 368 | *val |= (1 << shift * 3); 369 | break; 370 | case 'N': 371 | *val |= (2 << shift * 3); 372 | break; 373 | case 'W': 374 | *val |= (3 << shift * 3); 375 | break; 376 | case 'T': 377 | *val |= (4 << shift * 3); 378 | break; 379 | case 'E': 380 | *val |= (5 << shift * 3); 381 | break; 382 | case 'L': 383 | *val |= (6 << shift * 3); 384 | break; 385 | default: 386 | fprintf(stderr, "Unknown OPS \"%s\"\n", ptr); 387 | } 388 | ptr++; 389 | shift--; 390 | if (shift < 0) 391 | break; 392 | } 393 | ptr = next; 394 | 395 | return 0; 396 | } 397 | 398 | static int 399 | wsize_tok(unsigned short *val, char *wsize) 400 | { 401 | static char *ptr; 402 | char *next; 403 | 404 | if (wsize) 405 | { 406 | ptr = wsize; 407 | return 0; 408 | } 409 | 410 | if (!ptr) 411 | return -1; 412 | 413 | next = strchr(ptr, '|'); 414 | if (next) 415 | *next++ = '\0'; 416 | 417 | *val = strtol(ptr, NULL, 16) & 0xffff; 418 | ptr = next; 419 | 420 | return 0; 421 | } 422 | 423 | -------------------------------------------------------------------------------- /src/nmap_compat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: nmap_compat.h,v 1.1 2002/12/07 20:45:43 skyper Exp $ 3 | * 4 | * Make THCrut process nmap-of-fingerprint files. 5 | * We use a slightly more performant algorithm to load the strings 6 | * into memory. 7 | */ 8 | 9 | #ifndef __THCRUT_NMAP_COMPAT_H__ 10 | #define __THCRUT_NMAP_COMPAT_H__ 1 11 | 12 | #include 13 | 14 | #define NMAP_HASH_SIZE (113) 15 | #define NMAP_DF_ISNOTSET(item) ((item)->df & 0x1) 16 | #define NMAP_DF_ISSET(item) ((item)->df & 0x2) 17 | 18 | #define NMAP_DF_SET_ISNOTSET(item) ((item)->df |= 0x1) 19 | #define NMAP_DF_SET_ISSET(item) ((item)->df |= 0x2) 20 | 21 | #define NMAP_FP_TONE "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" 22 | #define NMAP_FP_TONE_LEN 20 23 | 24 | /* 25 | * All in HBO 26 | */ 27 | struct _nmap_osfp_TONE 28 | { 29 | struct _nmap_osfp_TONE *next; 30 | unsigned long ops:30; /* 10 ops */ 31 | unsigned long df:2; 32 | unsigned short wsize; /* windows size */ 33 | unsigned long ofs_string; 34 | unsigned long class; 35 | }; 36 | 37 | /* 38 | * HASH shall be the (wsize ^ var) % HASH_SIZE 39 | */ 40 | struct _nmap_osfp 41 | { 42 | char *strings; 43 | struct _nmap_osfp_TONE *hash_tone[NMAP_HASH_SIZE]; 44 | }; 45 | 46 | /* 47 | * This is the evil shit. 48 | * We check a test-1-entry from the DB if the value match against 49 | * it. 50 | * 51 | * Decoded is it: 52 | * if (tone->wsize != wsize) 53 | * continue; 54 | * if (tone->ops != ops) 55 | * continue; 56 | * if ((df) && (NMAP_DF_ISSET(tone))) 57 | * return tone; 58 | * if ((!df) && NMAP_DF_ISNOTSET(tone)) 59 | * return tone; 60 | */ 61 | #define NMAP_TONE_MATCH(tone, mywsize, mydf, myops) ((tone)->wsize != mywsize?0: (tone)->ops != myops?0:(mydf) && NMAP_DF_ISSET(tone)?1:(!mydf) && NMAP_DF_ISNOTSET(tone)?1:0) 62 | 63 | long NMAP_class2long(const char *input); 64 | int NMAP_load_fp(struct _nmap_osfp *osfp, char *file); 65 | struct _nmap_osfp_TONE *NMAP_lookup(struct _nmap_osfp *osfp, unsigned short wsize, char df, unsigned long ops); 66 | unsigned long NMAP_tcpops2ops(char *opstr, char *buf, size_t len); 67 | char * NMAP_long2class(char *dst, long val); 68 | 69 | #endif /* !__THCRUT_NMAP_COMPAT_H__ */ 70 | 71 | -------------------------------------------------------------------------------- /src/nvt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: nvt.c,v 1.1 2003/05/15 12:13:49 skyper Exp $ 3 | */ 4 | 5 | #include "nvt.h" 6 | #include 7 | 8 | #define IACFOUND 0x01 9 | #define DOFOUND 0x02 10 | #define UNKNOWNOPT 0x04 11 | #define SUBNEGO 0x08 12 | #define CRFOUND 0x10 13 | #define WILLFOUND 0x20 14 | 15 | /* 16 | * RFC854 - Network Virtual Terminal 17 | * 18 | * In summary, WILL XXX is sent, by either party, to indicate that 19 | * party's desire (offer) to begin performing option XXX, DO XXX and 20 | * DON'T XXX being its positive and negative acknowledgments; similarly, 21 | * DO XXX is sent to indicate a desire (request) that the other party 22 | * (i.e., the recipient of the DO) begin performing option XXX, WILL XXX 23 | * and WON'T XXX being the positive and negative acknowledgments. Since 24 | * the NVT is what is left when no options are enabled, the DON'T and 25 | * WON'T responses are guaranteed to leave the connection in a state 26 | * which both ends can handle. Thus, all hosts may implement their 27 | * TELNET processes to be totally unaware of options that are not 28 | * supported, simply returning a rejection to (i.e., refusing) any 29 | * option request that cannot be understood. 30 | * 31 | * Or: 32 | * WILL -> DO 33 | * DO -> WONT (except for DO TERMINAL TYPE). 34 | * 35 | * Input: 36 | * data of raw NVT data of lenght len. 37 | * ans should be at least 1024 chars long. 38 | * 39 | * Output: 40 | * ans is the proposed answer to the NVT request of lenght alen. 41 | * rem is the remaining data of length rlen. 42 | * 43 | * Requirement 44 | * ans and rem must be at least len bytes in size. 45 | * 46 | * FIXME: This routine started out as a simple while() loop but 47 | * was debugged into existance to handle all the unknown and buggy 48 | * devices out there (like that Terminal Type is required). 49 | * It requires some rework and a real FSM. 50 | * 51 | * return 0 on success. 52 | */ 53 | int 54 | NVT_decode(char *data, int len, char *ans, int *alen, char *rem, int *rlen) 55 | { 56 | char *ptr = data; 57 | char flags = 0; 58 | unsigned char c; 59 | 60 | *rlen = 0; 61 | *alen = 0; 62 | 63 | while (1) 64 | { 65 | if ((len-- <= 0) || (*alen > 1000)) 66 | break; 67 | c = *ptr++; 68 | 69 | if (flags & UNKNOWNOPT) 70 | { 71 | flags = 0; 72 | continue; 73 | } 74 | 75 | if (flags & IACFOUND) 76 | { 77 | if (c == NVT_IAC) /* IAC IAC */ 78 | { 79 | *rem++ = NVT_IAC; 80 | if (!(flags & SUBNEGO)) 81 | flags = 0; 82 | continue; 83 | } 84 | 85 | if (flags & SUBNEGO) 86 | { 87 | if (c == NVT_SE) 88 | flags = 0; 89 | continue; 90 | } 91 | 92 | if (flags & DOFOUND) 93 | { 94 | *ans++ = NVT_IAC; 95 | if (c == 0x18) 96 | *ans++ = NVT_WILL; 97 | else 98 | *ans++ = NVT_WONT; /* me is dump */ 99 | *ans++ = c; 100 | *alen = *alen + 3; 101 | flags = 0; 102 | continue; 103 | } 104 | 105 | if (flags & WILLFOUND) 106 | { 107 | *ans++ = NVT_IAC; 108 | *ans++ = NVT_DO; 109 | *ans++ = c; 110 | *alen = *alen + 3; 111 | flags = 0; 112 | continue; 113 | } 114 | 115 | if (c == NVT_SB) /* sub-negotiation */ 116 | { 117 | flags = SUBNEGO; 118 | /* 119 | * Some crappy terminal's terminate 120 | * the connection if we dont send our 121 | * Terminal type. 122 | */ 123 | if ((len > 1) && (*ptr == 0x18) && (*(ptr + 1) == 0x01)) 124 | { 125 | memcpy(ans, "\xff\xfa\x18\x00\x56\x54\x31\x30\x30\xff\xf0", 11); 126 | ans += 11; 127 | *alen = *alen + 11; 128 | } 129 | 130 | continue; 131 | } 132 | 133 | if (c == NVT_DO) 134 | { 135 | flags |= DOFOUND; 136 | continue; 137 | } else if (c == NVT_WILL) { 138 | flags |= WILLFOUND; 139 | continue; 140 | } else { 141 | flags = ~(IACFOUND | DOFOUND); 142 | flags |= UNKNOWNOPT; /* skip next */ 143 | continue; 144 | } 145 | 146 | } /* IACFOUND */ 147 | 148 | if (flags & SUBNEGO) 149 | continue; 150 | 151 | if (c == NVT_IAC) 152 | { 153 | flags = IACFOUND; /* first IAC */ 154 | continue; 155 | } 156 | 157 | if (flags & CRFOUND) 158 | { 159 | if (c == '\0') 160 | { 161 | flags &= ~CRFOUND; 162 | *rem++ = '\r'; 163 | *rlen = *rlen + 1; 164 | continue; 165 | } 166 | if (c == '\n') 167 | { 168 | flags &= ~CRFOUND; 169 | *rem++ = '\n'; 170 | *rlen = *rlen + 1; 171 | continue; 172 | } 173 | } 174 | 175 | if (c == '\r') 176 | { 177 | flags |= CRFOUND; 178 | continue; 179 | } 180 | 181 | *rem++ = c; 182 | *rlen = *rlen + 1; 183 | } 184 | 185 | return 0; 186 | } 187 | 188 | 189 | -------------------------------------------------------------------------------- /src/nvt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: nvt.h,v 1.1 2003/05/15 12:13:49 skyper Exp $ 3 | */ 4 | 5 | 6 | #ifndef __THCRUT_NVT_H__ 7 | #define __THCRUT_NVT_H__ 1 8 | 9 | #define NVT_SE 0xf0 10 | #define NVT_SB 0xfa 11 | #define NVT_WILL 0xfb 12 | #define NVT_WONT 0xfc 13 | #define NVT_DO 0xfd 14 | #define NVT_DONT 0xfe 15 | #define NVT_IAC 0xff 16 | 17 | int NVT_decode(char *data, int len, char *ans, int *alen, char *rem, int *rlen); 18 | 19 | #endif /* !__THCRUT_NVT_H__ */ 20 | -------------------------------------------------------------------------------- /src/packets.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: packets.c,v 1.7 2003/05/23 14:14:01 skyper Exp $ 3 | */ 4 | 5 | #include "default.h" 6 | #include 7 | #include 8 | #include "nmap_compat.h" 9 | #include "fp.h" 10 | #include "thc-rut.h" 11 | #include "dhcp.h" 12 | 13 | extern struct _opt opt; 14 | extern uint8_t ip_tcp_sync[]; 15 | extern uint8_t ip_tcp_fp[]; 16 | extern uint8_t ip_udp_dcebind[]; 17 | extern uint8_t ip_udp_snmp[]; 18 | extern uint8_t ip_icmp_echo[]; 19 | extern unsigned short ip_tcp_sync_chksum; 20 | extern unsigned short ip_tcp_fp_chksum; 21 | 22 | /* 23 | * Pre-generate packets for the scanner. 24 | * opt.src_ip is 0.0.0.0 and filled by the kernel. 25 | * (We dont know the src_ip yet). 26 | */ 27 | void 28 | scanner_gen_packets(void) 29 | { 30 | struct tcphdr *tcp; 31 | struct udphdr *udp; 32 | struct icmp *icmp; 33 | 34 | tcp = (struct tcphdr *)ip_tcp_sync; 35 | tcp->th_sport = htons(opt.src_port); 36 | tcp->th_dport = htons(80); 37 | tcp->th_seq = htonl(0xffffffff - time(NULL)); 38 | tcp->th_flags = TH_SYN; //syn = 1; 39 | tcp->th_win = 5840; 40 | tcp->th_sum = 0; 41 | 42 | /* Port wrapps around every 4096 seconds */ 43 | #if 0 44 | libnet_build_tcp(opt.src_port, 45 | 80, 46 | 0xffffffff - time(NULL), 47 | 0x0, 48 | TH_SYN, 49 | 5840, 50 | 0, 51 | NULL, 52 | 0, ip_tcp_sync); 53 | #endif 54 | #if 0 55 | libnet_build_ip(LIBNET_TCP_H, 56 | IPTOS_RELIABILITY, 57 | opt.ip_id, /* for outgoing ip's only */ 58 | 0, 59 | 255, 60 | IPPROTO_TCP, 61 | opt.src_ip, 62 | 0 /*dst*/, 63 | NULL, 64 | 0, 65 | ip_tcp_sync); 66 | libnet_do_checksum(ip_tcp_sync, IPPROTO_TCP, LIBNET_TCP_H); 67 | ip_tcp_sync_chksum = *(unsigned short *)(ip_tcp_sync + 36); 68 | #endif 69 | 70 | tcp = (struct tcphdr *)ip_tcp_fp; 71 | tcp->th_sport = htons(opt.src_port + 1); 72 | tcp->th_dport = htons(80); 73 | tcp->th_seq = htonl(0xffffffff - time(NULL) + 1); 74 | tcp->th_flags = TH_SYN; 75 | tcp->th_win = 5840; 76 | tcp->th_sum = 0; 77 | #if 0 78 | libnet_build_tcp(opt.src_port + 1, 79 | 0, 80 | 0xffffffff - time(NULL) + 1, 81 | 0x0, 82 | TH_SYN, 83 | 5840, 84 | 0, 85 | NULL, 86 | 0, ip_tcp_fp); 87 | tcp = (struct tcphdr *)(ip_tcp_fp); 88 | #endif 89 | tcp->th_off = (20 + NMAP_FP_TONE_LEN) >> 2; 90 | memcpy(ip_tcp_fp + 20, NMAP_FP_TONE, NMAP_FP_TONE_LEN); 91 | #if 0 92 | libnet_build_ip(LIBNET_TCP_H + NMAP_FP_TONE_LEN, 93 | IPTOS_RELIABILITY, 94 | opt.ip_id, /* for outgoing ip's only */ 95 | 0, 96 | 255, 97 | IPPROTO_TCP, 98 | opt.src_ip, 99 | 0 /*dst*/, 100 | NULL, 101 | 0, 102 | ip_tcp_fp); 103 | #endif 104 | 105 | udp = (struct udphdr *)ip_udp_dcebind; 106 | udp->uh_sport = htons(opt.src_port + 1); 107 | udp->uh_ulen = htons(FP_DCEBIND_LEN); 108 | memcpy(ip_udp_dcebind + 8, FP_DCEBIND, FP_DCEBIND_LEN); 109 | 110 | #if 0 111 | libnet_build_udp(opt.src_port + 1, 112 | 0, 113 | NULL, 114 | FP_DCEBIND_LEN, 115 | ip_udp_dcebind); 116 | #endif 117 | #if 0 118 | libnet_build_ip(LIBNET_UDP_H + FP_DCEBIND_LEN, 119 | IPTOS_RELIABILITY, 120 | opt.ip_id, /* for outgoing ip's only */ 121 | 0, 122 | 255, 123 | IPPROTO_UDP, 124 | opt.src_ip, 125 | 0 /*dst*/, 126 | NULL, 127 | 0, 128 | ip_udp_dcebind); 129 | #endif 130 | 131 | udp = (struct udphdr *)ip_udp_snmp; 132 | udp->uh_sport = htons(opt.src_port + 1); 133 | udp->uh_dport = htons(161); 134 | udp->uh_ulen = htons(FP_SNMP_LEN); 135 | #if 0 136 | libnet_build_udp(opt.src_port + 1, 137 | 161, 138 | NULL, 139 | FP_SNMP_LEN, 140 | ip_udp_snmp); 141 | #endif 142 | memcpy(ip_udp_snmp + LIBNET_UDP_H, FP_SNMP, FP_SNMP_LEN); 143 | #if 0 144 | libnet_build_ip(LIBNET_UDP_H + FP_SNMP_LEN, 145 | IPTOS_RELIABILITY, 146 | opt.ip_id, /* for outgoing ip's only */ 147 | 0, 148 | 255, 149 | IPPROTO_UDP, 150 | opt.src_ip, 151 | 0 /*dst*/, 152 | NULL, 153 | 0, 154 | ip_udp_snmp); 155 | #endif 156 | 157 | icmp = (struct icmp *)ip_icmp_echo; 158 | icmp->icmp_type = ICMP_ECHO; /* 8 */ 159 | //icmp->un.echo.id = 31338; //htons(getpid()); 160 | icmp->icmp_hun.ih_idseq.icd_id = opt.ic_id; 161 | #if 0 162 | libnet_build_icmp_echo(8, 163 | 0, 164 | htons(getpid()), /* we match for this ID! */ 165 | 1, 166 | NULL, 167 | 0, 168 | ip_icmp_echo); 169 | #endif 170 | #if 0 171 | libnet_build_ip(8, 172 | IPTOS_RELIABILITY, 173 | opt.ip_id, /* for outgoing ip's only */ 174 | 0, 175 | 255, 176 | IPPROTO_ICMP, 177 | opt.src_ip, 178 | 0 /*dst*/, 179 | NULL, 180 | 0, 181 | ip_icmp_echo); 182 | #endif 183 | 184 | } 185 | 186 | void 187 | dhcp_gen_packets(uint8_t *packet, uint32_t srcip, uint8_t *dsbuf, struct _dhcpset *ds) 188 | { 189 | #if 0 190 | int len; 191 | 192 | libnet_build_udp(68, 193 | 67, 194 | NULL, 195 | datalen - 8, /* length */ 196 | packet + LIBNET_ETH_H + LIBNET_IP_H); 197 | 198 | libnet_build_ip(datalen, /* length of ip DATA */ 199 | 0, 200 | 7350, 201 | 0, 202 | 128, 203 | IPPROTO_UDP, 204 | srcip, /* source IP */ 205 | -1, /* Destination IP */ 206 | NULL, 207 | 0, 208 | packet + LIBNET_ETH_H); 209 | 210 | libnet_build_ethernet(ETHBCAST, 211 | "\x00\x00\x00\x00\x00\x00", 212 | ETHERTYPE_IP, 213 | NULL, 214 | 0, 215 | packet); 216 | #endif 217 | 218 | build_bootp(packet); 219 | dhcp_add_option(ds, DHCP_END, 0, NULL); 220 | memcpy(packet + sizeof(struct _bootp), dsbuf, ds->lsize); 221 | } 222 | 223 | void 224 | arp_gen_packets(unsigned int srcip) 225 | { 226 | #if 0 227 | opt.ln_arp = libnet_build_arp(ARPHRD_ETHER, 228 | ETHERTYPE_IP, 229 | 6, 230 | 4, 231 | ARPOP_REQUEST, 232 | ETHZCAST, 233 | (unsigned char *)&srcip, 234 | ETHBCAST, 235 | "\x00\x00\x00\x00", /* IP */ 236 | NULL, 237 | 0, 238 | opt.ln_ctx, opt.ln_arp); 239 | 240 | opt.ln_eth = libnet_build_ethernet(ETHBCAST, 241 | ETHZCAST, 242 | ETHERTYPE_ARP, 243 | NULL, 244 | 0, 245 | opt.ln_ctx, opt.ln_eth); 246 | #endif 247 | } 248 | 249 | -------------------------------------------------------------------------------- /src/packets.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: packets.h,v 1.4 2003/05/23 14:14:01 skyper Exp $ 3 | */ 4 | 5 | 6 | #ifndef __THCRUT_PACKETS_H__ 7 | #define __THCRUT_PACKETS_H__ 1 8 | 9 | #include "dhcp.h" 10 | 11 | void scanner_gen_packets(void); 12 | void dhcp_gen_packets(uint8_t *packet, uint32_t srcip, uint8_t *dsbuf, struct _dhcpset *ds); 13 | void arp_gen_packets(unsigned int srcip); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/range.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: range.c,v 1.7 2003/05/25 18:19:16 skyper Exp $ 3 | */ 4 | #include "default.h" 5 | #include 6 | #include 7 | #include "thc-rut.h" 8 | #include "network.h" 9 | #include "range.h" 10 | 11 | void 12 | IP_dinit(struct _ipranges *ipr) 13 | { 14 | if (ipr->data) 15 | free(ipr->data); 16 | ipr->data = NULL; 17 | ipr->range = NULL; 18 | } 19 | 20 | /* 21 | * Reset range back the the beginning. 22 | */ 23 | void 24 | IP_reset(struct _ipranges *ipr) 25 | { 26 | //ipr->used = 0; 27 | ipr->tot_used = 0; 28 | //ipr->ofs = 0; 29 | ipr->range = ipr->data; /* Start with the first range again */ 30 | 31 | IP_range_init(ipr); 32 | } 33 | 34 | void 35 | IP_range_init(struct _ipranges *ipr) 36 | { 37 | ipr->used = 0; 38 | ipr->ofs = 0; 39 | ipr->next_ip = ipr->range->start; 40 | ipr->distance = (ipr->range->end - ipr->range->start) >> 2; 41 | if ((ipr->mode != IPR_MODE_SPREAD) || (ipr->distance <= 0)) 42 | ipr->distance = 1; 43 | else if (ipr->distance > 259) 44 | ipr->distance = 259; 45 | } 46 | 47 | /* 48 | * Third parameter is mode. 49 | */ 50 | void 51 | IP_init(struct _ipranges *ipr, char *argv[], unsigned char mode) 52 | { 53 | int c; 54 | unsigned int n; 55 | unsigned int start, end; 56 | char *ptr, *split; 57 | char splitc; 58 | size_t len; 59 | char buf[16]; 60 | 61 | memset(ipr, 0, sizeof (struct _ipranges)); 62 | ipr->argv = argv; 63 | ipr->next = ipr->argv[0]; 64 | 65 | /* 66 | * Allocat enough memory to hold all the ip ranges. 67 | * Ranges are terminated with start = end = 0. 68 | */ 69 | for (c = 0; ipr->argv[c]; c++) 70 | ;; 71 | ipr->data = calloc(sizeof (struct _iprange), c + 1); 72 | ipr->range = ipr->data; 73 | ipr->mode = mode; 74 | 75 | /* 76 | * Fill the array with ip ranges 77 | */ 78 | for (c = 0; ipr->argv[c]; c++) 79 | { 80 | start = 0; 81 | end = 0; 82 | 83 | ptr = ipr->argv[c]; 84 | while (*ptr == ' ') 85 | ptr++; 86 | split = ptr + 1; 87 | while (1) 88 | { 89 | if (*split == '-') 90 | break; 91 | else if (*split == '/') 92 | break; 93 | else if (*split == ',') 94 | break; 95 | else if (*split == '\0') 96 | break; 97 | split++; 98 | } 99 | if (*split) 100 | { 101 | len = MIN(sizeof buf - 1, split - ptr); 102 | memcpy(buf, ptr, len); 103 | buf[len] = '\0'; 104 | ptr = buf; 105 | } 106 | start = ntohl(inet_addr(ptr)); 107 | splitc = *split++; 108 | if (splitc == '\0') 109 | goto next; 110 | 111 | while (*split == ' ') 112 | split++; 113 | 114 | if (*split) 115 | end = ntohl(inet_addr(split)); 116 | 117 | if (splitc == '/') 118 | { 119 | n = end; 120 | 121 | if ((n > 30) || (n == 0)) 122 | n = 32; 123 | start &= ~((1 << (32 - n)) - 1); 124 | end = start + (1 << (32 - n)) - 1; 125 | if (n <= 30) 126 | { 127 | start++; 128 | end--; 129 | } 130 | } 131 | next: 132 | if (end == 0) /* a.b.c.d */ 133 | end = start; 134 | else if (end < start) /* a.b.c.d- */ 135 | end = start + end - 1; 136 | 137 | ipr->data[c].start = start; 138 | ipr->data[c].end = end; 139 | ipr->total += (end - start + 1); 140 | } 141 | 142 | DEBUGF("start: %s\n", int_ntoa(htonl(ipr->range->start))); 143 | DEBUGF("end : %s\n", int_ntoa(htonl(ipr->range->end))); 144 | /* Set current_ip */ 145 | DEBUGF("ipr->data = %p\n", ipr->data); 146 | IP_range_init(ipr); 147 | DEBUGF("ipr->data = %p\n", ipr->data); 148 | } 149 | 150 | -------------------------------------------------------------------------------- /src/range.h: -------------------------------------------------------------------------------- 1 | #ifndef THCRUT_RANGE_H 2 | #define THCRUT_RANGE_H 1 3 | 4 | #ifndef ETH_ALEN 5 | #define ETH_ALEN 6 6 | #endif 7 | 8 | 9 | struct _iprange 10 | { 11 | unsigned int start; 12 | unsigned int end; 13 | }; 14 | 15 | struct _ipranges 16 | { 17 | char **argv; 18 | char *next; 19 | unsigned int start_ip; 20 | unsigned int end_ip; 21 | unsigned int current_ip; 22 | unsigned int next_ip; 23 | struct _iprange *data; 24 | struct _iprange *range; /* Current range */ 25 | unsigned char mode; 26 | /* Those for spread scan mode */ 27 | unsigned int ofs; 28 | unsigned int used; 29 | unsigned int distance; 30 | /* For stats */ 31 | unsigned int tot_used; 32 | unsigned int total; 33 | char buf[16]; 34 | }; 35 | 36 | #define IP_current(ipr) (ipr)->current_ip 37 | #define IP_end(ipr) (((ipr)->argv[0] == NULL) && ((ipr)->current_ip >= (ipr)->end_ip)) 38 | /* Modes for ip range initialization */ 39 | #define IPR_MODE_SPREAD (0x01) 40 | 41 | /* 42 | * Started as a small while loop in a define, growed over time. 43 | * Put this in a function further or later.. 44 | * 45 | * Function breaks down ,-seperated strings in **argv into chunks. 46 | * Each chunk represents a IP or IP-range of the form: 47 | * a.b.c.d 48 | * a.b.c.d-x.y.z. 49 | * a.b.c.d-n 50 | * 51 | * IP's are returned in a non-sequential order to avoid arp flooding of a 52 | * target network (flooded by the arp-who-has of the first router). 53 | * 54 | * The algorithm is easy: 55 | * Increment +1 how many ip's have already been taken from the range. 56 | * Break out if this value >= end_ip - start_ip. 57 | * Increment the last ip by a fixed value. 58 | * Reset to start_ip + ofs_base if the new ip is larger then the end_ip and 59 | * increment ofs_base by +1. 60 | */ 61 | 62 | #define IP_next(ipr) do { \ 63 | if ((ipr)->used > (ipr)->range->end - (ipr)->range->start) \ 64 | { \ 65 | (ipr)->range++; \ 66 | if (!(ipr)->range->start) \ 67 | { \ 68 | (ipr)->current_ip = 0; \ 69 | break; \ 70 | } \ 71 | IP_range_init(ipr); \ 72 | } \ 73 | (ipr)->current_ip = (ipr)->next_ip; \ 74 | (ipr)->next_ip += (ipr)->distance; \ 75 | if ((ipr)->next_ip > (ipr)->range->end) \ 76 | (ipr)->next_ip = (ipr)->range->start + ++(ipr)->ofs; \ 77 | (ipr)->used++; \ 78 | (ipr)->tot_used++; \ 79 | } while(0) 80 | 81 | 82 | void IP_init(struct _ipranges *ipr, char *argv[], unsigned char mode); 83 | void IP_range_init(struct _ipranges *ipr); 84 | void IP_reset(struct _ipranges *ipr); 85 | 86 | #endif /* !THCRUT_RANGE_H */ 87 | -------------------------------------------------------------------------------- /src/schedule.c: -------------------------------------------------------------------------------- 1 | #include "default.h" 2 | #include "schedule.h" 3 | 4 | /* 5 | * reset the schedule-struct 6 | * return 0 on success 7 | */ 8 | int 9 | reset_schedule(struct _schedule *sd) 10 | { 11 | struct timeval tv; 12 | 13 | if (gettimeofday(&tv, NULL) != 0) 14 | return -1; 15 | 16 | sd->tv1.tv_sec = tv.tv_sec - 100; 17 | sd->tv1.tv_usec = tv.tv_usec; 18 | sd->tps = sd->ps * 100; 19 | 20 | return 0; 21 | } 22 | 23 | /* 24 | * init a schedule structure...make it start 25 | * 10 seconds in the past. 26 | * return 0 on success 27 | */ 28 | int 29 | init_schedule(struct _schedule *sd, int ps) 30 | { 31 | sd->ps = ps; 32 | sd->sps = sd->ps; 33 | 34 | return reset_schedule(sd); 35 | } 36 | 37 | /* 38 | * usleep until its time for this process 39 | * (eg as soon as it drops < ps) 40 | */ 41 | int 42 | wait_schedule(struct _schedule *sd) 43 | { 44 | struct timeval tv; 45 | float sec; 46 | 47 | if (!(sd->ps > 0)) 48 | return 0; /* no delay at all */ 49 | 50 | /* FIXME: Use a long long int here */ 51 | /* FIXME: horrible what i did here :> */ 52 | /* Better sleep as many seconds until it's our turn again */ 53 | while (1) 54 | { 55 | if (gettimeofday(&tv, NULL) != 0) 56 | return -1; 57 | 58 | sec = (tv.tv_sec - sd->tv1.tv_sec) 59 | - (sd->tv1.tv_usec - tv.tv_usec) / 1000000.0; 60 | if ( (sd->tps / sec) >= sd->ps) 61 | usleep(40); /* should give up timeslice */ 62 | else 63 | break; 64 | } 65 | 66 | if (sd->tps++ == -1) /* if total per seconds overflow */ 67 | reset_schedule(sd); 68 | 69 | return 0; 70 | } 71 | 72 | /* 73 | * speedup < 1 will slow down 74 | * and > 1 will speedup everything. 75 | * returns the speedup that was successfully assigned 76 | * to the scheduler. 77 | * < 0 on error. 78 | */ 79 | int 80 | ctrl_schedule(struct _schedule *sd, float speedup) 81 | { 82 | struct timeval tv; 83 | 84 | if (speedup > 10) 85 | speedup = 10; 86 | 87 | if (speedup < 0.1) 88 | speedup = 0.1; 89 | 90 | if (speedup == 0) 91 | return 0; 92 | 93 | if (gettimeofday(&tv, NULL) != 0) 94 | return -1; 95 | 96 | sd->ps = sd->ps * speedup; 97 | sd->tv1.tv_sec = tv.tv_sec - (tv.tv_sec - sd->tv1.tv_sec) / speedup; 98 | 99 | return speedup; 100 | } 101 | 102 | -------------------------------------------------------------------------------- /src/schedule.h: -------------------------------------------------------------------------------- 1 | #ifndef THCRUT_SCHEDULE_H 2 | #define THCRUT_SCHEDULE_H 1 3 | 4 | #ifdef HAVE_CONFIG_H 5 | # if TIME_WITH_SYS_TIME 6 | # include 7 | # include 8 | # else 9 | # if HAVE_SYS_TIME_H 10 | # include 11 | # else 12 | # include 13 | # endif 14 | # endif 15 | #else 16 | # include 17 | #endif 18 | #ifdef HAVE_UNISTD_H 19 | # include 20 | #endif 21 | 22 | struct _schedule 23 | { 24 | struct timeval tv1; 25 | struct timeval tv2; 26 | unsigned short ps; /* per second..sec is the smallest entity*/ 27 | /* this must by < tps / 10 ..._ALWAYS_ */ 28 | unsigned short sps; /* saved per second. dont change this value. */ 29 | unsigned long tps; /* total per seconds since start...*/ 30 | }; 31 | 32 | int init_schedule(struct _schedule *, int); 33 | int reset_schedule(struct _schedule *); 34 | int wait_schedule(struct _schedule *); 35 | int ctrl_schedule(struct _schedule *, float); 36 | 37 | #endif /* !THCRUT_SCHEDULE_H */ 38 | -------------------------------------------------------------------------------- /src/state.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: state.c,v 1.13 2003/05/25 18:19:16 skyper Exp $ 3 | * 4 | * ChangeLog 5 | * - added variable length state support (struct _state_* ). 6 | */ 7 | 8 | 9 | #include "default.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "state.h" 19 | 20 | #define STATE_HASH(sq, ip) (ntohl(ip) & (sq)->hash_entry_mask) 21 | // FIXME: debugging 22 | //#define STATE_HASH(sq, ip) 0 23 | 24 | 25 | static fd_set g_rfds; 26 | 27 | /* 28 | * Initialize a state queue 29 | */ 30 | #define BIT_HASH (10) 31 | struct _state_queue * 32 | SQ_init(struct _state_queue *sq, unsigned long nitems, size_t item_size, int fd, cb_timeout_t cb_timeout, cb_filter_t cb_filter) 33 | { 34 | int size; 35 | 36 | item_size = (item_size + 3) & ~3; /* Align to 4 bytes */ 37 | 38 | if (nitems > 500000) 39 | nitems = 500000; 40 | sq->epoch = 1000000 / nitems; /* length of on epoch in ms */ 41 | 42 | size = nitems * item_size + (1 << BIT_HASH) * sizeof(struct _state *); 43 | /* Hash size must be one of 2^n */ 44 | sq->hash_entry_mask = (1 << BIT_HASH) - 1; 45 | sq->n_entries = nitems; 46 | sq->current = 0; 47 | sq->item_size = item_size; 48 | sq->cb_timeout = cb_timeout; 49 | sq->cb_filter = cb_filter; 50 | sq->fd = fd; 51 | 52 | sq->hash = malloc(size); //shmat(sq->shmid, NULL, 0); 53 | if (!sq->hash) 54 | return NULL; 55 | memset(sq->hash, 0, size); 56 | sq->queue = (struct _state *)(sq->hash + (1 << BIT_HASH)); 57 | 58 | gettimeofday(&sq->expect, NULL); 59 | 60 | DEBUGF("entries: %ld\n", sq->n_entries); 61 | DEBUGF("item_size: %lu\n", sq->item_size); 62 | DEBUGF("epoch: %ld usec\n", sq->epoch); 63 | 64 | return sq; 65 | } 66 | 67 | void 68 | STATE_deinit(struct _state_queue *sq) 69 | { 70 | XFREE(sq->hash); 71 | #if 0 72 | if (sq->shmid) 73 | shmctl(sq->shmid, IPC_RMID, 0); 74 | sq->shmid = 0; 75 | #endif 76 | } 77 | 78 | /* 79 | * IP is in NBO 80 | */ 81 | struct _state * 82 | STATE_by_ip(struct _state_queue *sq, uint32_t ip) 83 | { 84 | struct _state *state = sq->hash[STATE_HASH(sq, ip)]; 85 | int i = 0; 86 | 87 | while (state) 88 | { 89 | i++; 90 | if ((state->ip == ip) && (STATE_current(state))) 91 | break; 92 | state = state->next; 93 | } 94 | 95 | return state; 96 | }; 97 | 98 | /* 99 | * Only called by sending process 100 | * 101 | * One might think that here is a race condition, but 102 | * this wrong: The element we unlink is the last element of 103 | * the hash list. New elements are always inserted at the top. 104 | * The last one is thus the oldest. Relinking becomes 105 | * very easy as we only have to set the next pointer of the previous 106 | * item to NULL (to make it become the last). 107 | */ 108 | void 109 | STATE_link(struct _state_queue *sq, struct _state *state) 110 | { 111 | unsigned int idx; 112 | 113 | idx = STATE_HASH(sq, state->ip); 114 | 115 | /* Link */ 116 | state->prev = NULL; 117 | state->next = sq->hash[idx]; 118 | if (state->next) 119 | state->next->prev = state; 120 | 121 | sq->hash[idx] = state; 122 | } 123 | 124 | void 125 | STATE_unlink(struct _state_queue *sq, struct _state *state) 126 | { 127 | unsigned int idx; 128 | 129 | if (state->prev == NULL) 130 | { 131 | if (state->ip == 0) 132 | return; /* Not linked at all! */ 133 | idx = STATE_HASH(sq, state->ip); 134 | sq->hash[idx] = state->next; /* NULL usually */ 135 | } else 136 | state->prev->next = state->next; /* NULL usually */ 137 | 138 | /* 139 | * We dont need this if we would always remove the last element. 140 | * We actually dont do this any longer... 141 | */ 142 | if (state->next) 143 | state->next->prev = state->prev; 144 | } 145 | 146 | 147 | /* 148 | * FIXME: we must check if n_inuse dropped to 0. 149 | * Otherwise we might spin-loop in the while loop up 150 | * until 1 second (does thismatter?) 151 | * 152 | * FIXME: also, we dont have to call gettimofday() 153 | * if we only wait some very short fragment of time 154 | * or have just been called with tv_(u)sec = 0 to check 155 | * if the FD is set (but without sleeping). 156 | */ 157 | /* 158 | * FREEBSD-BPF-SELECT-BUG: 159 | * http://www.tcpdump.org/lists/workers/2001/05/msg00060.html 160 | * The flag that data is ready to read is only set when the internal 161 | * kernel buffer overflows. 162 | * We call cb_filter even if select does not indicate that there is something 163 | * to read. We still call select() in case the internal buffer overflows on 164 | * long delays (like 0.9999 seconds). 165 | * 166 | * Solution: It actually works under FreeBsd 4.6-RC6 if pcap_open_live 167 | * is initialized with ms > 0. 168 | */ 169 | /* 170 | #ifdef THCRUT_BROKEN_BPF_SELECT 171 | # define SQ_WHILE_LOOP(diff) do { \ 172 | FD_SET(sq->fd, &g_rfds); \ 173 | select(sq->fd + 1, &g_rfds, NULL, NULL, &diff); \ 174 | sq->cb_filter(); \ 175 | gettimeofday(&now, NULL); \ 176 | SQ_TV_diff(&diff, &now, &sq->expect); \ 177 | } while (diff.tv_usec >= 0) 178 | #else 179 | */ 180 | /* 181 | * NOTE: pcap manual page (escpecially for linux) does not match 182 | * the implementation. Current implementation always only process 183 | * one package. We have to check on our own if there are other remaining 184 | * packets to be read. There are two ways to do so: 185 | * - 1.1 use non-blocking pcap-fd and call cb_filter until 0 is returned. 186 | * - 1.2 call select() again with 1 ms even if time (diff) is already up. 187 | * On !LINUX can we assume that all packets have been read if <= 1 188 | * is returned (because those OS'es would have read more than 1 packet 189 | * if available. 190 | * 191 | * FIXME: what's faster, 1.1 or 1.2? 192 | */ 193 | #define SQ_WHILE_LOOP(diff) do { \ 194 | FD_SET(sq->fd, &g_rfds); \ 195 | ret = select(sq->fd + 1, &g_rfds, NULL, NULL, &diff); \ 196 | if (ret > 0) \ 197 | sq->cb_filter(); \ 198 | else if (ret == 0) \ 199 | break; \ 200 | else if (errno != EINTR) \ 201 | break; \ 202 | gettimeofday(&now, NULL); \ 203 | SQ_TV_diff(&diff, &now, &sq->expect); \ 204 | if (diff.tv_usec < 0) \ 205 | diff.tv_usec = 0; \ 206 | } while (1) 207 | /* } while (diff.tv_usec >= 0) */ 208 | 209 | static void 210 | state_select(struct _state_queue *sq) 211 | { 212 | struct timeval now, diff; 213 | static unsigned char min_select; 214 | int ret; 215 | 216 | gettimeofday(&now, NULL); 217 | SQ_TV_diff(&diff, &now, &sq->expect); 218 | //fprintf(stderr, "is %ld.%ld should %ld.%ld (%ld.%ld ms diff)\n", now.tv_sec, now.tv_usec, sq->expect.tv_sec, sq->expect.tv_usec, diff.tv_sec, diff.tv_usec); 219 | 220 | /* 221 | * At least every n invokations go into select 222 | */ 223 | if (diff.tv_usec >= 0) 224 | { 225 | min_select = 0; 226 | } else if (min_select++ >= 5) { 227 | //DEBUGF("expect\n%d.%8.8d but it's already\n%d.%8.8d\n", sq->expect.tv_sec, sq->expect.tv_usec, now.tv_sec, now.tv_usec); 228 | diff.tv_usec = 0; 229 | min_select = 0; 230 | } else 231 | return; 232 | 233 | SQ_WHILE_LOOP(diff); 234 | } 235 | 236 | /* 237 | * SQ must be init first 238 | * FIXME: determine when to exit. 239 | * - Set STATE_reset decrement n_inuse and check in select loop 240 | * if it dropped to 0. 241 | * 242 | * Function returns when a new IP is required. 243 | * OpenBSD: Sniffed packets are not available in realtime. 244 | * (pcap fd does not indicate that data is available). 245 | * There is a delay of around 1 second. FIXME: Why??? 246 | */ 247 | int 248 | STATE_wait(struct _state_queue *sq, const struct _state *nextstate) 249 | { 250 | struct _state *state; 251 | 252 | SQ_next(state, sq); 253 | 254 | //DEBUGF("current %u, nextstate %p use: %d\n", STATE_current(state), nextstate, sq->n_inuse); 255 | start: 256 | if (!STATE_current(state)) 257 | { 258 | fillagain: 259 | /* Fill a state with new target */ 260 | if (nextstate) 261 | { 262 | STATE_unlink(sq, state); 263 | memcpy(state, nextstate, sq->item_size); 264 | STATE_link(sq, state); 265 | //DEBUGF("FIXME Fist invokation of dis_timeout at %ld\n", sq->current); 266 | sq->cb_timeout(state); 267 | // sq->reschedule = 0; 268 | /* n_inuse = max because we check on next call 269 | * inside the while(1) loop (sq->n_inuse--) 270 | */ 271 | /* Didnt switched state? */ 272 | if (state->current) 273 | sq->n_inuse = sq->n_entries; 274 | SQ_TV_add(&sq->expect, sq->epoch); 275 | state_select(sq); 276 | return 0; 277 | } else { 278 | /* 279 | * Scroll through all free and unused slots so 280 | * that select() is only called once for all 281 | * unused slots in a row. 282 | */ 283 | while (1) 284 | { 285 | sq->n_inuse--; 286 | if (sq->n_inuse <= 0) 287 | return -1; /* FINISHED */ 288 | SQ_TV_add(&sq->expect, sq->epoch); 289 | SQ_next(state, sq); 290 | if (STATE_current(state)) 291 | break; 292 | } 293 | state_select(sq); 294 | /* state-content might have changed while receiving 295 | * packets. Check again if still active. 296 | */ 297 | goto start; 298 | } 299 | } else { /* Current state is set and waited 1 sec */ 300 | sq->n_inuse = sq->n_entries; 301 | if (state->reschedule) 302 | { 303 | state->reschedule = 0; 304 | SQ_TV_add(&sq->expect, sq->epoch); 305 | state_select(sq); 306 | SQ_next(state, sq); 307 | goto start; 308 | } else { 309 | sq->cb_timeout(state); 310 | // sq->reschedule = 0; 311 | /* 312 | * State empty, everything processed 313 | */ 314 | if ((!state->current) && (nextstate == NULL) && (sq->n_inuse <= 1)) 315 | { 316 | fflush(stdout); 317 | return -1; 318 | } 319 | /* 320 | * Instantly reused if a slot became free. 321 | * Otherwise put it back and sniff a round. 322 | */ 323 | if (state->current) 324 | { 325 | SQ_TV_add(&sq->expect, sq->epoch); 326 | state_select(sq); 327 | SQ_next(state, sq); 328 | goto start; 329 | } 330 | goto fillagain; 331 | } 332 | } 333 | 334 | return -1; /* Not reached */ 335 | } 336 | 337 | -------------------------------------------------------------------------------- /src/state.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: state.h,v 1.9 2003/05/25 18:19:16 skyper Exp $ 3 | */ 4 | 5 | #ifndef __THCRUT_STATE_H__ 6 | #define __THCRUT_STATE_H__ 1 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | /* 13 | * 12 bytes state entry 14 | * at 10,000 PPS * 3 sec * 12 bytes = 360k 15 | * 16 | * TODO: 17 | * Optimisaztion: next and prev dont have to be full 4byte/8byte pointer. 18 | * We can use idx into the queue table. 19 | */ 20 | struct _state 21 | { 22 | struct _state *next; /* hash */ 23 | struct _state *prev; /* hash */ 24 | uint32_t ip; /* NBO */ 25 | unsigned char current:7; /* Up to 32 different states */ 26 | unsigned char reschedule:1; /* Up to 15 seconds delay */ 27 | /* 28 | * What a pity, we waste 3 bytes of memory here. 29 | * Can merge reschedule flag with ip and move current to 30 | * _state_fp. 31 | */ 32 | }; 33 | 34 | typedef void (*cb_timeout_t)(struct _state *); 35 | typedef void (*cb_filter_t)(void); 36 | 37 | struct _state_queue 38 | { 39 | struct _state *queue; 40 | struct _state **hash; 41 | int shmid; 42 | int hash_entry_mask; 43 | char hash_fix; 44 | long current; 45 | long n_entries; 46 | int n_inuse; 47 | size_t item_size; /* size of struct _state_* */ 48 | struct timeval expect; 49 | long epoch; /* length of an epoche in ms */ 50 | unsigned char *packet; 51 | int fd; /* pcap_fd */ 52 | fd_set rfds; 53 | int max_fd; 54 | cb_timeout_t cb_timeout; 55 | cb_filter_t cb_filter; 56 | }; 57 | 58 | #define SQ_FD_set(myfd, sq) do{ \ 59 | FD_SET(myfd, (sq)->rfds); \ 60 | if ((sq)->max_fd < myfd) \ 61 | (sq)->mac_fd = myfd; \ 62 | }while(0) 63 | 64 | #define SQ_step(sq) do{ \ 65 | (sq)->current++; \ 66 | if ((sq)->current >= (sq)->n_entries) \ 67 | (sq)->current = 0; \ 68 | }while(0) 69 | 70 | #define SQ_next(state, sq) do{ \ 71 | SQ_step(sq); \ 72 | (state) = (struct _state *)((char *)(sq)->queue + (sq)->item_size * (sq)->current); \ 73 | }while(0) 74 | 75 | #define SQ_current(state, sq) (state) = &(sq)->queue[(sq)->current] 76 | /* 77 | * STATE_switch() should be used if a state switches and 78 | * rescheduling is required. 79 | * STATE_current(state) = NEW STATE should be used otherwise. 80 | */ 81 | #define STATE_reschedule(state, val) ((struct _state *)(state))->reschedule = val 82 | #define STATE_switch(state, val) do{((struct _state *)(state))->current = val; if (val) ((struct _state *)(state))->reschedule = 1; else ((struct _state *)(state))->reschedule = 0; }while(0) 83 | #define STATE_reset(state) ((struct _state *)(state))->current = 0; 84 | #define STATE_ip(state) ((struct _state *)(state))->ip 85 | #define STATE_current(state) ((struct _state *)(state))->current 86 | 87 | #define SQ_TV_add(tv, usec) do{ \ 88 | (tv)->tv_usec += usec; \ 89 | if ((tv)->tv_usec >= 1000000) \ 90 | { \ 91 | (tv)->tv_usec -= 1000000; \ 92 | (tv)->tv_sec++; \ 93 | } \ 94 | }while(0) 95 | 96 | /* Calculate the difference from small to large */ 97 | #define SQ_TV_diff(dst, small, large) do{ \ 98 | if ((small)->tv_sec > (large)->tv_sec) \ 99 | { \ 100 | (dst)->tv_sec = 0; \ 101 | (dst)->tv_usec = -1; \ 102 | break; \ 103 | } \ 104 | (dst)->tv_sec = (large)->tv_sec - (small)->tv_sec; \ 105 | if (((dst)->tv_sec == 0) && ((small)->tv_usec > (large)->tv_usec)) \ 106 | { \ 107 | (dst)->tv_sec = 0; \ 108 | (dst)->tv_usec = -1; \ 109 | break; \ 110 | } \ 111 | (dst)->tv_usec = (large)->tv_usec - (small)->tv_usec; \ 112 | if ((dst)->tv_usec < 0) \ 113 | { \ 114 | (dst)->tv_sec--; \ 115 | (dst)->tv_usec = 1000000 + (dst)->tv_usec; \ 116 | } \ 117 | }while(0) 118 | 119 | 120 | struct _state_queue *SQ_init(struct _state_queue *sq, unsigned long nitems, size_t item_size, int fd, cb_timeout_t cb_timeout, cb_filter_t cb_filter); 121 | void STATE_deinit(struct _state_queue *sq); 122 | void STATE_link(struct _state_queue *sq, struct _state *state); 123 | void STATE_unlink(struct _state_queue *sq, struct _state *state); 124 | struct _state *STATE_by_ip(struct _state_queue *sq, unsigned int ip); 125 | int STATE_wait(struct _state_queue *sq, const struct _state *nextstate); 126 | 127 | #endif /* !__THCRUT_STATE_H__ */ 128 | -------------------------------------------------------------------------------- /src/system.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: system.c,v 1.1 2003/05/15 12:13:49 skyper Exp $ 3 | */ 4 | 5 | #include "default.h" 6 | #include 7 | #include 8 | 9 | static unsigned char esctable[] = "\x80\x80\x80\x80\x80\x80\x80\x80\x80\xF4\xEE\x80\x80\xF2\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80 \xA1\xA2#\xA4%&'\xA8\xA9\xAA\xAB,-\xAE/0123456789:;<=>\xBF@ABCDEFGHIJKLMNOPQRSTUVWXYZ\xDB\xDC]\xDE_`abcdefghijklmnopqrstuvwxyz\xFB\xFC}~\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"; 10 | 11 | 12 | /* 13 | * Convert a (binary) string into a perl style string. 14 | * 15 | * Input: 16 | * src and slen are the source and length to be translated. 17 | * 18 | * Output: 19 | * dst and dlen are destionation and max. destination length. 20 | * 21 | * Return: 22 | * Number of chars placed into dst. dst will be \0 terminated. 23 | * 24 | * Warning: 25 | * This is not exactly a perl like string. We also escape " here. 26 | */ 27 | int 28 | perlstring(char *dst, int dlen, char *src, int slen) 29 | { 30 | unsigned char s; 31 | char *start = dst; 32 | char *end = dst + dlen; 33 | 34 | while ((slen-- > 0) && (dst + 4 < end)) 35 | { 36 | s = *src++; 37 | if (esctable[s] == 0x80) 38 | { 39 | snprintf(dst, dlen, "\\x%2.2x", s); 40 | dst += 4; 41 | continue; 42 | } 43 | 44 | /* 45 | * Escape the following chars: 46 | * \ | ( ) [ { ^ $ * + ? . " 47 | * 48 | * Where " is the non-perl critical character. 49 | */ 50 | if (esctable[s] > 0x80) 51 | { 52 | *dst++ = '\\'; 53 | *dst++ = esctable[s] - 0x80; 54 | continue; 55 | } 56 | 57 | *dst++ = s; 58 | } 59 | 60 | *dst = '\0'; 61 | 62 | return dst - start; 63 | } 64 | 65 | void 66 | hexdump(uint8_t *data, size_t len) 67 | { 68 | size_t n = 0; 69 | int line = 0; 70 | 71 | if (!len) 72 | return; 73 | 74 | fprintf(stderr, "%03x: ", line++); 75 | while (1) 76 | { 77 | fprintf(stderr, "%2.2x ", data[n++]); 78 | if (n >= len) 79 | break; 80 | if (n % 8 == 0) 81 | fprintf(stderr, " - "); 82 | if (n % 16 == 0) 83 | fprintf(stderr, "\n%03x: ", line++); 84 | } 85 | fprintf(stderr, "\n"); 86 | } 87 | 88 | #ifndef HAVE_STRLCPY 89 | /* 90 | * bsd'sh strlcpy(). 91 | * The strlcpy() function copies up to size-1 characters from the 92 | * NUL-terminated string src to dst, NUL-terminating the result. 93 | * Return: total length of the string tried to create. 94 | */ 95 | size_t 96 | strlcpy(char *dst, const char *src, size_t size) 97 | { 98 | size_t len = strlen(src); 99 | size_t ret = len; 100 | 101 | if (size <= 0) 102 | return 0; 103 | if (len >= size) 104 | len = size - 1; 105 | memcpy(dst, src, len); 106 | dst[len] = 0; 107 | 108 | return ret; 109 | } 110 | #endif 111 | 112 | /* 113 | * Debuggging... 114 | * Convert an interger to a bit string and output it. 115 | * Most significatn bit first. 116 | */ 117 | char * 118 | int2bit(unsigned int val) 119 | { 120 | static char buf[33 + 3]; 121 | char *ptr = buf; 122 | unsigned int i = 0x1 << 31; 123 | int round = 0; 124 | 125 | while (i > 0) 126 | { 127 | 128 | if (val & i) 129 | *ptr++ = '1'; 130 | else 131 | *ptr++ = '0'; 132 | 133 | i = i >> 1; 134 | 135 | if ((++round % 8 == 0) && (i > 0)) 136 | *ptr++ = '.'; 137 | } 138 | 139 | *ptr = '\0'; 140 | 141 | return buf; 142 | } 143 | 144 | -------------------------------------------------------------------------------- /src/system.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: system.h,v 1.1 2003/05/15 12:13:49 skyper Exp $ 3 | */ 4 | 5 | 6 | #ifndef __THCRUT_SYSTEM_H__ 7 | #define __THCRUT_SYSTEM_H__ 1 8 | 9 | #include 10 | 11 | void hexdump(uint8_t *data, size_t len); 12 | int perlstring(char *dst, int dlen, char *src, int slen); 13 | #ifndef HAVE_STRLCPY 14 | size_t strlcpy(char *dst, const char *src, size_t size); 15 | #endif 16 | char *int2bit(unsigned int val); 17 | 18 | #endif /* !__THCRUT_SYSTEM_H__ */ 19 | 20 | -------------------------------------------------------------------------------- /src/thc-rut.c: -------------------------------------------------------------------------------- 1 | /* 2 | * its 2001-05-03, this is quick _dirty_ code. 3 | * gamma called me..doiong some wvlan-riding now.. 4 | * wrote this lame stuff to brute force BOOTP replies 5 | * on wlan access points with mac-authentification. 6 | * sends BOOTP requests with different macs...thats all. 7 | * 8 | * 9 | * anonymous@segfault.net 10 | * err..let me fix the bugs later. ideas: 11 | * - ARP whohas does not work with switched network and 12 | * PortSecurity enabled. send out some arp-have first! 13 | * Its nice to use src mac ff:ff:ff:ff:ff:ff...works for the 14 | * switch but not OSes answer on it. only ONE (the first?) 15 | * Interface of VMWAREs NIC answers (hahahahah) 16 | * Another nice idea to determine the OS of a host... 17 | * - multicast 18 | * - rarp RFC 903, skip it, bootp is newer...and dhcp also. 19 | * - ?! what else can be used if you dont know the network-address 20 | * and access is only granted from specific (unknown) mac's ? 21 | * With BOOTP we only need to brute force the src-mac..hmm..ok. 22 | * + icmp address mask request ..FIXME: dst-mac if ff:ff:ff:ff:ff:ff wont work. 23 | * + ping 255.255.255.255 24 | * + request all arp's on the lan 25 | * - Resource Location Protocol RFC 887 26 | * + DHCP 1541 + 1497 (optoins) + 1533 + 1542 (clarification + extensions 27 | * for bootstrap protocol) 28 | * and RFC2131 29 | * - BOOTP RFC 951 30 | * - ICMP-router discovery RFC 1256 (need to verify; 224.0.0.[12]) 31 | * - DRARP by sun ? MIT ? ("Dynamic Reverse Address Resolution Protocol") 32 | * - BOOTPARAMS by sun 33 | * + mac-vendor name 34 | * - statefull / retransmit packet if no response... 35 | * + limit packets/second 36 | * - SOCK_RAW for ppl on ppp-dialups and local cable modem hacking [no ethernet] 37 | * -> arpg wont work and arp on an entire network also not.anyway..icmp + dhcp 38 | * -------- info --------- 39 | * 00:40:96:47xxxx cisco access point 40 | * 00:02:2D:08:2A:54 lucent wvlan 41 | * 00:02:2D:04:C7:18 lucent wvlan 42 | * 00:02:2D:02:91:73 lucent wvlan 43 | * 00:02:2D:0E:99:52 lucent wvlan orinoco silver 44 | * 00:60:1D:23:21:9B lucent wvlan 45 | * 00:60:1d:21:9f:32 lucent wvlan 46 | * 08:00:0E AT&T Wavelan (standard) & DEC RpamAbout 47 | * 08:00:6A AT&T Wavelan (alternate) 48 | * 00:00:E1 Hitachi Wavelan 49 | * 00:60:1D Lucent Wavelan 50 | * The networkname of a rg1000 are always the last 3 digits of the AP-mac 51 | * (without the ':' signs, rg1000 by lucent) 52 | * 53 | * problems: 54 | * - we dont know the destination mac . we use ff:ff:ff:ff:ff:ff: in all cases 55 | * ..this most often works for icmp (except for windows2k) 56 | * 57 | * thnx to scut for dcd_icmp.h and the bscan development team :] 58 | * thnx to oxigen for bootp samples late late in the night. 59 | * 60 | * TODO: 61 | * - implement a dummy mode for stupid users that just discovers everything 62 | * on the local network. 63 | */ 64 | 65 | #include "default.h" 66 | #include 67 | #ifdef HAVE_UNISTD_H 68 | # include 69 | #endif 70 | #include 71 | #include 72 | #include 73 | #include 74 | #ifdef HAVE_CONFIG_H 75 | # if HAVE_SYS_WAIT_H 76 | # include 77 | # endif 78 | # ifndef WEXITSTATUS 79 | # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) 80 | # endif 81 | # ifndef WIFEXITED 82 | # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) 83 | # endif 84 | #else 85 | # include 86 | #endif 87 | #include 88 | #include "thc-rut.h" 89 | #include "network_raw.h" 90 | #include "dcd_icmp.h" 91 | #include "arpg.h" 92 | #include "dhcp.h" 93 | #include "macvendor.h" 94 | #include "schedule.h" 95 | #include "range.h" 96 | #include "state.h" 97 | #include "thcrut_sig.h" 98 | #include "discover_main.h" 99 | #include "dhcp_main.h" 100 | #include "arp_main.h" 101 | #include "icmp_main.h" 102 | #include "network.h" 103 | #include "fp.h" 104 | #include "tty.h" 105 | #include "thcrut_pcap.h" 106 | 107 | #define DFL_WMEM_MAX (1 * 1024 * 1024) 108 | 109 | u_char spfdstmac[ETH_ALEN]; 110 | struct _spfip srcip; 111 | struct _opt opt; 112 | struct _lnet lnet; 113 | 114 | void fini_libnet(); 115 | 116 | static unsigned long time_start; 117 | 118 | void 119 | init_vars() 120 | { 121 | struct timeval tv; 122 | FILE *fp; 123 | char buf[128]; 124 | 125 | time_start = (unsigned long)time(NULL); 126 | gettimeofday(&tv, NULL); 127 | memset(lnet.payload, 0, MAX_PAYLOAD_SIZE); 128 | opt.device = NULL; 129 | opt.dlt_len = ETHDLTLEN; 130 | opt.flags = 0; 131 | opt.flags |= FL_OPT_SPREADMODE; 132 | opt.hosts_parallel = 0; 133 | 134 | /* vendor: lucent oricion 2000 */ 135 | memcpy(spfdstmac, ETHBCAST, ETH_ALEN); 136 | srcip.addr = 0; 137 | srand(time(NULL)); /* PRNG, we only require weak random */ 138 | 139 | memcpy(opt.dst_mac, ETHBCAST, sizeof opt.dst_mac); 140 | 141 | signal_parent_init(); 142 | 143 | /* 144 | * Linux specific, set send buffer size 145 | */ 146 | fp = fopen("/proc/sys/net/core/wmem_max", "w+"); 147 | if (fp) 148 | { 149 | if (fgets(buf, sizeof buf, fp) == NULL) 150 | ERREXIT("open(/proc/...wmem_max) = NULL\n"); 151 | if (atoi(buf) < DFL_WMEM_MAX) 152 | { 153 | fprintf(stderr, "Setting system wide send buffer limit to %d bytes\n", DFL_WMEM_MAX); 154 | fseek(fp, 0L, SEEK_SET); 155 | fprintf(fp, "%d\n", DFL_WMEM_MAX); 156 | } 157 | fclose(fp); 158 | } 159 | 160 | /* 161 | * Some statefull firewalls ipf are buggy: 162 | * SYN passes, SYN|ACK anser passes, 163 | * RST passes 164 | * NEW SYN with same values does _NOT_ pass anymore. 165 | * That's why we try to use a different port and let the 166 | * ipf state timeout (should be time'ed out after 32k seconds) 167 | * We reserve a new block of 8 source ports every 1/8 seconds which 168 | * have not been used by the scanner during the last 512 seconds 169 | * (most states timeout after 360). 170 | */ 171 | opt.src_port = (((tv.tv_sec & 0x1ff) << 3)+ (tv.tv_usec & 0x7))*8 + 1024; 172 | opt.ip_id = (uint16_t)(getpid() & 0xffff); 173 | opt.ic_id = (uint16_t)(getpid() & 0xffff); 174 | } 175 | 176 | void 177 | die(int code, char *fmt, ...) 178 | { 179 | va_list ap; 180 | char buf[1024]; 181 | 182 | if (fmt != NULL) 183 | { 184 | va_start(ap, fmt); 185 | vsnprintf (buf, sizeof(buf)-1, fmt, ap); 186 | va_end(ap); 187 | fprintf(stderr, "ERROR: %s\n", buf); 188 | } 189 | 190 | if (opt.childpid) 191 | kill(opt.childpid, SIGTERM); 192 | 193 | fini_libnet(); 194 | 195 | exit(code); 196 | } 197 | 198 | void 199 | usage (int code, char *str) 200 | { 201 | if (str != NULL) 202 | fprintf(stderr, "%s\n", str); 203 | 204 | fprintf(stderr, 205 | "Version: "VERSION"\n" 206 | "Usage: thc-rut [ options ] [ command ] [ command-options-and-arguments ]\n" 207 | //[Types] [Options] [[macX[-macY]:]ipA[-ipB]] ...\n" 208 | "\n" 209 | "Commands:\n" 210 | " discover Host discovery and OS fingerprinting\n" 211 | //" scan Port scanner (TCP)\n" 212 | " icmp ICMP discovery\n" 213 | " dhcp DHCP discovery\n" 214 | " arp ARP discovery\n" 215 | //" sniff tcpdump\n" 216 | "\n" 217 | "Options:\n" 218 | " -i Network interface [first found]\n" 219 | " -l Hosts in parallel\n" 220 | /* NOTE: not all modules support spoofing. */ 221 | " -s Source ip of a network device (eth0, eth0:0, ..)\n" 222 | " -S Sequential ip range mode [default: spread mode]\n" 223 | " -F Infinite Loop. Repeat forever.\n" 224 | "Use -l 100 on LAN and -l 5000 otherwise.\n" 225 | "Try thcrut [ command ] -h for command specific options.\n" 226 | "\n" 227 | "Example:\n" 228 | "# thc-rut arp\n" 229 | "# thc-rut icmp -h\n" 230 | "# thc-rut icmp -T 151.101.121.1-151.101.121.254\n" 231 | "# thc-rut dhcp\n" 232 | "# thc-rut discover -h\n" 233 | "# thc-rut discover -O 192.168.0.1-192.168.255.254\n" 234 | ); 235 | 236 | exit(code); 237 | } 238 | 239 | 240 | int 241 | do_getopt(int argc, char *argv[]) 242 | { 243 | extern char *optarg; 244 | extern int optind, opterr, optopt; 245 | int c; 246 | 247 | if (argc <= 1) 248 | usage(0, NULL); 249 | opterr = 0; /* Dont yell error's, they are processed by the modules */ 250 | 251 | optind = 1; 252 | while ((c = getopt (argc, argv, "+SFi:s:l:h")) != -1) 253 | { 254 | switch(c) 255 | { 256 | case 'F': 257 | opt.flags |= FL_OPT_INFINITE; 258 | break; 259 | case 'S': 260 | opt.flags &= ~FL_OPT_SPREADMODE; 261 | break; 262 | case 'l': 263 | opt.hosts_parallel = atoi(optarg); 264 | break; 265 | #if 1 266 | case 's': 267 | opt.src_ip = inet_addr(optarg); 268 | opt.flags |= FL_OPT_SRC_IP_ISSET; 269 | break; 270 | #endif 271 | case 'i': 272 | opt.device = optarg; 273 | break; 274 | case 'h': 275 | usage(0, NULL); 276 | break; 277 | default: 278 | fprintf(stderr, "Unknown option: -%c, specify command first.\n", optopt); 279 | usage(0, NULL); 280 | break; 281 | } 282 | } 283 | 284 | opt.argc = argc - optind; 285 | opt.argvlist = (argv + optind); 286 | 287 | if (opt.argvlist[0] == NULL) 288 | usage(0, NULL); 289 | 290 | /* if noone added some suboptions with -D