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