├── 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