1
2 /***************************************************************************
3 * ncrack_dicom.cc -- ncrack module for the DICOM protocol *
4 * *
5 ***********************IMPORTANT NMAP LICENSE TERMS************************
6 * *
7 * The Nmap Security Scanner is (C) 1996-2019 Insecure.Com LLC ("The Nmap *
8 * Project"). Nmap is also a registered trademark of the Nmap Project. *
9 * This program is free software; you may redistribute and/or modify it *
10 * under the terms of the GNU General Public License as published by the *
11 * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE *
12 * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your *
13 * right to use, modify, and redistribute this software under certain *
14 * conditions. If you wish to embed Nmap technology into proprietary *
15 * software, we sell alternative licenses (contact sales@nmap.com). *
16 * Dozens of software vendors already license Nmap technology such as *
17 * host discovery, port scanning, OS detection, version detection, and *
18 * the Nmap Scripting Engine. *
19 * *
20 * Note that the GPL places important restrictions on "derivative works", *
21 * yet it does not provide a detailed definition of that term. To avoid *
22 * misunderstandings, we interpret that term as broadly as copyright law *
23 * allows. For example, we consider an application to constitute a *
24 * derivative work for the purpose of this license if it does any of the *
25 * following with any software or content covered by this license *
26 * ("Covered Software"): *
27 * *
28 * o Integrates source code from Covered Software. *
29 * *
30 * o Reads or includes copyrighted data files, such as Nmap's nmap-os-db *
31 * or nmap-service-probes. *
32 * *
33 * o Is designed specifically to execute Covered Software and parse the *
34 * results (as opposed to typical shell or execution-menu apps, which will *
35 * execute anything you tell them to). *
36 * *
37 * o Includes Covered Software in a proprietary executable installer. The *
38 * installers produced by InstallShield are an example of this. Including *
39 * Nmap with other software in compressed or archival form does not *
40 * trigger this provision, provided appropriate open source decompression *
41 * or de-archiving software is widely available for no charge. For the *
42 * purposes of this license, an installer is considered to include Covered *
43 * Software even if it actually retrieves a copy of Covered Software from *
44 * another source during runtime (such as by downloading it from the *
45 * Internet). *
46 * *
47 * o Links (statically or dynamically) to a library which does any of the *
48 * above. *
49 * *
50 * o Executes a helper program, module, or script to do any of the above. *
51 * *
52 * This list is not exclusive, but is meant to clarify our interpretation *
53 * of derived works with some common examples. Other people may interpret *
54 * the plain GPL differently, so we consider this a special exception to *
55 * the GPL that we apply to Covered Software. Works which meet any of *
56 * these conditions must conform to all of the terms of this license, *
57 * particularly including the GPL Section 3 requirements of providing *
58 * source code and allowing free redistribution of the work as a whole. *
59 * *
60 * As another special exception to the GPL terms, the Nmap Project grants *
61 * permission to link the code of this program with any version of the *
62 * OpenSSL library which is distributed under a license identical to that *
63 * listed in the included docs/licenses/OpenSSL.txt file, and distribute *
64 * linked combinations including the two. *
65 * *
66 * The Nmap Project has permission to redistribute Npcap, a packet *
67 * capturing driver and library for the Microsoft Windows platform. *
68 * Npcap is a separate work with it's own license rather than this Nmap *
69 * license. Since the Npcap license does not permit redistribution *
70 * without special permission, our Nmap Windows binary packages which *
71 * contain Npcap may not be redistributed without special permission. *
72 * *
73 * Any redistribution of Covered Software, including any derived works, *
74 * must obey and carry forward all of the terms of this license, including *
75 * obeying all GPL rules and restrictions. For example, source code of *
76 * the whole work must be provided and free redistribution must be *
77 * allowed. All GPL references to "this License", are to be treated as *
78 * including the terms and conditions of this license text as well. *
79 * *
80 * Because this license imposes special exceptions to the GPL, Covered *
81 * Work may not be combined (even as part of a larger work) with plain GPL *
82 * software. The terms, conditions, and exceptions of this license must *
83 * be included as well. This license is incompatible with some other open *
84 * source licenses as well. In some cases we can relicense portions of *
85 * Nmap or grant special permissions to use it in other open source *
86 * software. Please contact fyodor@nmap.org with any such requests. *
87 * Similarly, we don't incorporate incompatible open source software into *
88 * Covered Software without special permission from the copyright holders. *
89 * *
90 * If you have any questions about the licensing restrictions on using *
91 * Nmap in other works, we are happy to help. As mentioned above, we also *
92 * offer an alternative license to integrate Nmap into proprietary *
93 * applications and appliances. These contracts have been sold to dozens *
94 * of software vendors, and generally include a perpetual license as well *
95 * as providing support and updates. They also fund the continued *
96 * development of Nmap. Please email sales@nmap.com for further *
97 * information. *
98 * *
99 * If you have received a written license agreement or contract for *
100 * Covered Software stating terms other than these, you may choose to use *
101 * and redistribute Covered Software under those terms instead of these. *
102 * *
103 * Source is provided to this software because we believe users have a *
104 * right to know exactly what a program is going to do before they run it. *
105 * This also allows you to audit the software for security holes. *
106 * *
107 * Source code also allows you to port Nmap to new platforms, fix bugs, *
108 * and add new features. You are highly encouraged to send your changes *
109 * to the dev@nmap.org mailing list for possible incorporation into the *
110 * main distribution. By sending these changes to Fyodor or one of the *
111 * Insecure.Org development mailing lists, or checking them into the Nmap *
112 * source code repository, it is understood (unless you specify *
113 * otherwise) that you are offering the Nmap Project the unlimited, *
114 * non-exclusive right to reuse, modify, and relicense the code. Nmap *
115 * will always be available Open Source, but this is important because *
116 * the inability to relicense code has caused devastating problems for *
117 * other Free Software projects (such as KDE and NASM). We also *
118 * occasionally relicense the code to third parties as discussed above. *
119 * If you wish to specify special license conditions of your *
120 * contributions, just say so when you send them. *
121 * *
122 * This program is distributed in the hope that it will be useful, but *
123 * WITHOUT ANY WARRANTY; without even the implied warranty of *
124 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Nmap *
125 * license file for more details (it's in a COPYING file included with *
126 * Nmap, and also available from https://svn.nmap.org/nmap/COPYING) *
127 * *
128 ***************************************************************************/
129
130
131 #include "ncrack.h"
132 #include "nsock.h"
133 #include "NcrackOps.h"
134 #include "Service.h"
135 #include "modules.h"
136
137 #define DICOM_TIMEOUT 20000
138
139
140 #define DICOM_APP "1.2.840.10008.3.1.1.1"
141 #define DICOM_ABS "1.2.840.10008.5.1.4.1.1.7"
142 #define DICOM_TRX_EXP_L "1.2.840.10008.1.2.1"
143 #define DICOM_TRX_IMP_L "1.2.840.10008.1.2"
144 #define DICOM_TRX_EXP_B "1.2.840.10008.1.2.2"
145 #define DICOM_UID "1.2.826.0.1.3680043.2.1545.1"
146 #define DICOM_IMPL "Ncrack"
147
148 #define DICOM_ERROR "Received bogus pdu type"
149
150 typedef struct dicom_assoc {
151
152 struct assoc_request {
153
154 struct app_ctx {
155 uint16_t item_type; // 0x10 = app context
156 uint16_t item_length;
157 u_char ctx[21];
158
app_ctxdicom_assoc::assoc_request::app_ctx159 app_ctx() {
160 item_type = 0x10;
161 item_length = le_to_be16(21);
162 memcpy(ctx, DICOM_APP, sizeof(ctx));
163 }
164 } __attribute__((__packed__));
165
166 struct pres_context {
167
168 struct abstract_syntax {
169 uint16_t item_type; // 0x30 = abstract
170 uint16_t item_length;
171 u_char abs_syntax[25];
172
abstract_syntaxdicom_assoc::assoc_request::pres_context::abstract_syntax173 abstract_syntax() {
174 item_type = 0x30;
175 item_length = le_to_be16(25);
176 memcpy(abs_syntax, DICOM_ABS, sizeof(abs_syntax));
177 }
178 } __attribute__((__packed__));
179
180 #if 0
181 struct transfer_syntax_explicit_l {
182 uint16_t item_type; // 0x40 = transfer
183 uint16_t item_length;
184 u_char trx_syntax[19]; // explicit vr little endian
185
186 transfer_syntax_explicit_l() {
187 item_type = 0x40;
188 item_length = le_to_be16(19);
189 memcpy(trx_syntax, DICOM_TRX_EXP_L, sizeof(trx_syntax));
190 }
191 } __attribute__((__packed__));
192
193 struct transfer_syntax_explicit_b {
194 uint16_t item_type; // 0x40 = transfer
195 uint16_t item_length;
196 u_char trx_syntax[19]; // explicit vr big endian
197
198 transfer_syntax_explicit_b() {
199 item_type = 0x40;
200 item_length = le_to_be16(19);
201 memcpy(trx_syntax, DICOM_TRX_EXP_B, sizeof(trx_syntax));
202 }
203 } __attribute__((__packed__));
204 #endif
205
206 struct transfer_syntax_implicit_l {
207 uint16_t item_type; // 0x40 = transfer
208 uint16_t item_length;
209 u_char trx_syntax[17]; // implicit vr little endian
210
transfer_syntax_implicit_ldicom_assoc::assoc_request::pres_context::transfer_syntax_implicit_l211 transfer_syntax_implicit_l() {
212 item_type = 0x40;
213 item_length = le_to_be16(17);
214 memcpy(trx_syntax, DICOM_TRX_IMP_L, sizeof(trx_syntax));
215 }
216 } __attribute__((__packed__));
217
218
pres_contextdicom_assoc::assoc_request::pres_context219 pres_context() {
220 item_type = 0x20;
221 item_length = le_to_be16(54);
222 context_id = 0x01;
223 }
224
225 uint16_t item_type; // 0x20 = presentation
226 uint16_t item_length;
227 uint8_t context_id;
228 u_char pad0[3] = { 0x00, 0x00, 0x00 };
229 abstract_syntax abs;
230 //transfer_syntax_explicit_l trx_el;
231 transfer_syntax_implicit_l trx_il;
232 //transfer_syntax_explicit_b trx_eb;
233 } __attribute__((__packed__));
234
235 struct user_info {
236
237 struct max_length {
238 uint16_t item_type; // 0x51 = max-length
239 uint16_t item_length;
240 uint32_t max_len;
241
max_lengthdicom_assoc::assoc_request::user_info::max_length242 max_length() {
243 item_type = 0x51;
244 item_length = le_to_be16(4);
245 max_len = le_to_be32(16384);
246 }
247 } __attribute__((__packed__));
248 struct implementation_id {
249 uint16_t item_type; // 0x52 = class uid
250 uint16_t item_length;
251 u_char class_uid[28];
252
implementation_iddicom_assoc::assoc_request::user_info::implementation_id253 implementation_id() {
254 item_type = 0x52;
255 item_length = le_to_be16(28);
256 memcpy(class_uid, DICOM_UID, sizeof(class_uid));
257 }
258 } __attribute__((__packed__));
259 struct async_neg {
260 uint16_t item_type; // 0x53 = async op
261 uint16_t item_length;
262 uint16_t max_num_ops_invoked;
263 uint16_t max_num_ops_performed;
264
async_negdicom_assoc::assoc_request::user_info::async_neg265 async_neg() {
266 item_type = 0x53;
267 item_length = le_to_be16(4);
268 max_num_ops_invoked = 0;
269 max_num_ops_performed = 0;
270 }
271 } __attribute__((__packed__));
272 struct implementation_version {
273 uint16_t item_type; // 0x55 = impl version
274 uint16_t item_length;
275 u_char impl_version[6];
276
implementation_versiondicom_assoc::assoc_request::user_info::implementation_version277 implementation_version() {
278 item_type = 0x55;
279 item_length = le_to_be16(6);
280 memcpy(impl_version, DICOM_IMPL, sizeof(impl_version));
281 }
282 } __attribute__((__packed__));
283
user_infodicom_assoc::assoc_request::user_info284 user_info() {
285 item_type = 0x50;
286 item_length = le_to_be16(50); // 26
287 }
288
289 uint16_t item_type; // 0x50 = user-info
290 uint16_t item_length;
291 max_length max;
292 implementation_id uid;
293 //async_neg async;
294 implementation_version impl;
295
296 } __attribute__((__packed__));
297
assoc_requestdicom_assoc::assoc_request298 assoc_request() {
299 version = le_to_be16(1);
300 }
301
302 uint16_t version;
303 u_char pad[2] = { 0x00, 0x00 };
304 u_char called_ae[16] = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
305 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
306 u_char calling_ae[16] = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
307 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
308 u_char pad0[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
312 app_ctx app;
313 pres_context pres;
314 user_info user;
315 } __attribute__((__packed__));
316
dicom_assocdicom_assoc317 dicom_assoc() {
318 pdu_type = le_to_be16(0x100);
319 pdu_length = le_to_be32(205); // 231
320 }
321
322 uint16_t pdu_type;
323 uint32_t pdu_length;
324 assoc_request assoc;
325
326 } __attribute__((__packed__)) dicom_assoc;
327
328
329
330 extern NcrackOps o;
331
332 extern void ncrack_read_handler(nsock_pool nsp, nsock_event nse, void *mydata);
333 extern void ncrack_write_handler(nsock_pool nsp, nsock_event nse, void *mydata);
334 extern void ncrack_module_end(nsock_pool nsp, void *mydata);
335 static int dicom_loop_read(nsock_pool nsp, Connection *con);
336
337 enum states { DICOM_INIT, DICOM_FINI };
338
339
340 static int
dicom_loop_read(nsock_pool nsp,Connection * con)341 dicom_loop_read(nsock_pool nsp, Connection *con)
342 {
343 uint32_t *pdu_length;
344
345 /* we need at least 6 bytes to read the whole PDU length */
346 if (con->inbuf == NULL || con->inbuf->get_len() < 6) {
347 nsock_read(nsp, con->niod, ncrack_read_handler, DICOM_TIMEOUT, con);
348 return -1;
349 }
350
351 pdu_length = (uint32_t *)((u_char *)con->inbuf->get_dataptr() + 2);
352 *pdu_length = le_to_be32(*pdu_length);
353
354 if (o.debugging > 9)
355 printf("pdu length: %d\n", *pdu_length);
356
357 /* now read until we receive all bytes mentioned in length */
358 if (con->inbuf->get_len() < *pdu_length) {
359 nsock_read(nsp, con->niod, ncrack_read_handler, DICOM_TIMEOUT, con);
360 return -1;
361 }
362
363 return 0;
364 }
365
366
367
368 void
ncrack_dicom(nsock_pool nsp,Connection * con)369 ncrack_dicom(nsock_pool nsp, Connection *con)
370 {
371 nsock_iod nsi = con->niod;
372 Service *serv = con->service;
373 dicom_assoc da;
374 uint8_t *pdu_type;
375
376 switch (con->state)
377 {
378 case DICOM_INIT:
379
380 con->state = DICOM_FINI;
381
382 delete con->inbuf;
383 con->inbuf = NULL;
384
385 if (con->outbuf)
386 delete con->outbuf;
387 con->outbuf = new Buf();
388
389 memcpy(da.assoc.called_ae, con->user, strlen(con->user));
390 memcpy(da.assoc.calling_ae, con->pass, strlen(con->pass));
391
392 con->outbuf->append(&da, sizeof(da));
393
394 nsock_write(nsp, nsi, ncrack_write_handler, DICOM_TIMEOUT, con,
395 (const char *)con->outbuf->get_dataptr(), con->outbuf->get_len());
396 break;
397
398 case DICOM_FINI:
399
400 if (dicom_loop_read(nsp, con) < 0)
401 break;
402
403 pdu_type = (uint8_t *)((u_char *)con->inbuf->get_dataptr());
404 if (o.debugging > 9)
405 printf("pdu_type: %d \n", *pdu_type);
406
407 if (*pdu_type == 0x03) { // ASSOC REJECT
408 ;
409 } else if (*pdu_type == 0x02) { // ASSOC ACCEPT
410 con->auth_success = true;
411 con->force_close = true;
412 } else {
413 /* received weird pdu
414 * close connection and stop cracking
415 */
416 con->force_close = true;
417 con->close_reason = MODULE_ERR;
418 serv->end.orly = true;
419 serv->end.reason = Strndup(DICOM_ERROR, sizeof(DICOM_ERROR));
420 }
421 con->state = DICOM_INIT;
422
423 delete con->inbuf;
424 con->inbuf = NULL;
425
426 return ncrack_module_end(nsp, con);
427 }
428 }
429