1 /*
2  * **
3  * ** Copyright (C) 2005  Meder Kydyraliev <meder@o0o.nu>
4  * ** Copyright (C) 2001-2005  Fyodor Yarochkin <fygrave@tigerteam.net>,
5  * **                                           Ofir Arkin       <ofir@sys-security.com>
6  * **
7  * ** This program is free software; you can redistribute it and/or modify
8  * ** it under the terms of the GNU General Public License as published by
9  * ** the Free Software Foundation; either version 2 of the License, or
10  * ** (at your option) any later version.
11  * **
12  * **
13  * ** This program is distributed in the hope that it will be useful,
14  * ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * ** GNU General Public License for more details.
17  * **
18  * ** You should have received a copy of the GNU General Public License
19  * ** along with this program; if not, write to the Free Software
20  * ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  * */
22 
23 #include "xprobe.h"
24 #define _XPROBE_MODULE
25 #include "xplib.h"
26 #include "xprobe_module.h"
27 #include "xprobe_module_hdlr.h"
28 #include "target.h"
29 #include "interface.h"
30 #include "cmd_opts.h"
31 #include "config_set.h"
32 #include "snmp_mod.h"
33 
34 extern Interface *ui;
35 extern Cmd_Opts *copts;
36 extern Config_Set *cfg;
37 
snmp_mod_init(Xprobe_Module_Hdlr * pt,char * nm)38 int snmp_mod_init(Xprobe_Module_Hdlr *pt, char *nm) {
39 	SNMP_Mod *snmp= new SNMP_Mod;
40 	snmp->set_name(nm);
41 	xprobe_mdebug(XPROBE_DEBUG_MODULES, "Initializing the SNMP module\n");
42 	pt->register_module(snmp);
43 	pt->add_keyword(snmp->get_id(), "snmp_sysdescr");
44 	return OK;
45 }
46 
SNMP_Mod(void)47 SNMP_Mod::SNMP_Mod(void): Xprobe_Module(XPROBE_MODULE_OSTEST, "fingerprint:snmp", "SNMPv2c fingerprinting module") {
48 
49 }
50 
~SNMP_Mod(void)51 SNMP_Mod::~SNMP_Mod(void) {
52 }
53 
54 
parse_keyword(int os_id,const char * kwd,const char * val)55 int SNMP_Mod::parse_keyword(int os_id, const char *kwd, const char *val) {
56 	string descr(val);
57 
58 	xprobe_debug(XPROBE_DEBUG_SIGNATURES, "Parsing for %i : %s  = %s\n", os_id, kwd, val);
59 	sysdescrs.insert(pair<int, string>(os_id, descr));
60 	return OK;
61 }
62 
init(void)63 int SNMP_Mod::init(void) {
64 	xprobe_debug(XPROBE_DEBUG_MODULES, "%s module initialized\n", get_name());
65 	return OK;
66 }
67 
exec(Target * tg,OS_Matrix * os)68 int SNMP_Mod::exec(Target *tg, OS_Matrix *os) {
69 	char snmp_request_start[]=
70 								"\x30"
71 								"\x26"                          // length of the data that followd
72 								"\x02\x01\x01"                  // version 2c
73 								"\x04"                          // string
74 								"\x03";                         // length of community string
75 								// community string here
76 	char snmp_request_end[]=
77 								"\xa0\x1c"                      // PDU GET
78 								"\x02\x04\x22\xa2\x3d\x23"      // request ID
79 								"\x02\x01\x00"                  // Err status (NO ERR)
80 								"\x02\x01\x00"                  // Err index (NO ERR)
81 								"\x30\x0e\x30\x0c\x06\x08\x2b\x06\x01\x02\x01\x01\x01\x00" // SNMPv2 MIBD sysDescr.0
82 								"\x05\x00";                     // value NULL
83 
84 	int sock, retval;
85 	unsigned int i, packlen;
86 	unsigned char *packet, buf[2048];
87 	unsigned long request_id;
88 	struct sockaddr_in to;
89 	vector<string> tokens;
90 	vector<string> snmpstrings;
91 	vector<unsigned long> snmpints;
92 	map<int, string>::iterator iter;
93 	SNMP snmp;
94 
95 
96 	if (!tg->port_is_open(IPPROTO_UDP, 161)) {
97 		ui->error("[-] %s: need UDP port 161 open\n", get_name());
98 		return FAIL;
99 	}
100 	bzero(&to, sizeof(to));
101 	to.sin_family = AF_INET;
102 	to.sin_port = htons(161);
103 	to.sin_addr = tg->get_addr();
104 
105 	if ((sock = xp_lib::OpenUDPSocket(&to, NULL)) == FAIL) {
106 		ui->error("[-] %s: OpenUDPSocket() failed (%s)!\n", get_name(), strerror(errno));
107 		return FAIL;
108 	}
109 
110 	/*
111 	 * get a vector of community strings to try
112 	 */
113 	xp_lib::tokenize(cfg->get_comstrings().c_str(), ',', &tokens);
114 
115 	for (i=0; i < tokens.size(); i++) {
116 		xprobe_debug(XPROBE_DEBUG_MODULES, "SNMP trying community string: %s\n", tokens[i].c_str());
117 		request_id = rand();
118 
119 		/*
120 		 * set request ID
121 		 */
122 		snmp_request_end[4]   = (unsigned char)(request_id & 0xFF);
123 		snmp_request_end[5] = (unsigned char)((request_id >> 8) & 0xFF);
124 		snmp_request_end[6] = (unsigned char)((request_id >> 16) & 0xFF);
125 		snmp_request_end[7] = (unsigned char)((request_id >> 24) & 0xFF);
126 
127 		packlen = tokens[i].size() + sizeof(snmp_request_start)-1 + sizeof(snmp_request_end)-1;
128 		packet = new unsigned char[packlen];
129 		snmp_request_start[6] = tokens[i].size();	// comunity string length
130 		snmp_request_start[1] = packlen - 2;		// length of the ASN sequence
131 
132 		/*
133 		 * construct the SNMP request (ugly)
134 		 */
135 		memcpy(packet, snmp_request_start, sizeof(snmp_request_start)-1);
136 		memcpy(packet+sizeof(snmp_request_start)-1, tokens[i].c_str(), tokens[i].size());
137 		memcpy(packet+sizeof(snmp_request_start)-1+tokens[i].size(), snmp_request_end, sizeof(snmp_request_end)-1);
138 
139 		if ((retval = send(sock, packet, packlen, 0)) < 0) {
140 			if (errno == ECONNREFUSED)
141 				tg->add_port(IPPROTO_UDP, 161, XPROBE_TARGETP_CLOSED);
142 			ui->error("[-] %s: send() failed (%s)\n", get_name(), strerror(errno));
143 			return FAIL;
144 		}
145 		delete []packet;
146 		retval = xp_lib::RecvTimeout(sock, buf, sizeof(buf), 1);
147 		if (retval == 0) {
148 			// timeout
149 			continue;
150 		} else if (retval == FAIL) {
151 			ui->error("[-] %s: RecvTimeout() failed!\n", get_name());
152 			return FAIL;
153 		}
154 		xprobe_debug(XPROBE_DEBUG_MODULES, "%s got %d bytes\n", get_name(), retval);
155 		if (snmp.parse(buf, retval) == FAIL) {
156 			ui->error("[-] %s: SNMP::parse() failed!\n", get_name());
157 			return FAIL;
158 		}
159 		snmp.get_strings(snmpstrings);
160 		snmp.get_integers(snmpints);
161 		if (snmpstrings.size()  < SNMP_MIN_STRINGS) {
162 			ui->error("[-] %s: Invalid number of strings %d (min is %d)\n",
163 							get_name(), snmpstrings.size(), SNMP_MIN_STRINGS);
164 			return FAIL;
165 		}
166 		if (snmpints.size() < SNMP_MIN_INTS) {
167 			ui->error("[-] %s: Invalid number of integers %d (min is %d)\n",
168 							get_name(), snmpints.size(), SNMP_MIN_INTS);
169 			return FAIL;
170 		}
171 		if (snmpints[SNMP_REQUESTID_IX] != htonl(request_id)) {
172 			ui->error("[-] %s: Got invalid request id from remote target 0x%lx (expected 0x%lx)\n",
173 						get_name(), snmpints[SNMP_REQUESTID_IX], htonl(request_id));
174 			return FAIL;
175 		}
176 		ui->msg("[+] SNMP [Community: %s] [sysDescr.0: %s]\n",
177 					snmpstrings[SNMP_COMMUNITY_IX].c_str(), snmpstrings[SNMP_SYSDESCR_IX].c_str());
178 
179 		/*
180 		 * perform fingerprint matching
181 		 */
182 		for (iter = sysdescrs.begin(); iter != sysdescrs.end(); iter++) {
183 
184 			string::size_type mypos = snmpstrings[SNMP_SYSDESCR_IX].find(iter->second);
185 			if (mypos == string::npos) {
186 				os->add_result(get_id(), iter->first, XPROBE_MATCH_NO);
187 			} else  {
188 				os->add_result(get_id(), iter->first, XPROBE_MATCH_YES);
189 			}
190 		}
191 
192 		break;
193 	}
194 	close(sock);
195 	return OK;
196 }
197 
fini(void)198 int SNMP_Mod::fini(void) {
199 	xprobe_debug(XPROBE_DEBUG_MODULES, "%s module has been deinitilized\n", get_name());
200 	return OK;
201 }
202 
203