PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/ettercap/src/dissectors/ec_pop.c

#
C | 443 lines | 200 code | 103 blank | 140 comment | 55 complexity | 8f0895fc5aafeb7f2f8a4946f2eea017 MD5 | raw file
Possible License(s): AGPL-3.0, LGPL-2.1, GPL-2.0
  1. /*
  2. ettercap -- dissector POP3 -- TCP 110
  3. Copyright (C) ALoR & NaGA
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. $Id: ec_pop.c,v 1.33 2004/06/25 14:24:29 alor Exp $
  16. */
  17. /*
  18. * The authentication schema can be found here:
  19. *
  20. * ftp://ftp.rfc-editor.org/in-notes/std/std53.txt
  21. *
  22. * we currently support:
  23. * - USER & PASS
  24. * - APOP
  25. * - AUTH LOGIN (SASL)
  26. */
  27. #include <ec.h>
  28. #include <ec_decode.h>
  29. #include <ec_dissect.h>
  30. #include <ec_session.h>
  31. #include <ec_sslwrap.h>
  32. /* protos */
  33. FUNC_DECODER(dissector_pop);
  34. void pop_init(void);
  35. /************************************************/
  36. /*
  37. * this function is the initializer.
  38. * it adds the entry in the table of registered decoder
  39. */
  40. void __init pop_init(void)
  41. {
  42. dissect_add("pop3", APP_LAYER_TCP, 110, dissector_pop);
  43. sslw_dissect_add("pop3s", 995, dissector_pop, SSL_ENABLED);
  44. }
  45. FUNC_DECODER(dissector_pop)
  46. {
  47. DECLARE_DISP_PTR_END(ptr, end);
  48. struct ec_session *s = NULL;
  49. void *ident = NULL;
  50. char tmp[MAX_ASCII_ADDR_LEN];
  51. /* the connection is starting... create the session */
  52. CREATE_SESSION_ON_SYN_ACK("pop3", s, dissector_pop);
  53. /* create the session even if we are into an ssl tunnel */
  54. CREATE_SESSION_ON_SYN_ACK("pop3s", s, dissector_pop);
  55. /* check if it is the first packet sent by the server */
  56. if ((FROM_SERVER("pop3", PACKET) || FROM_SERVER("pop3s", PACKET)) && PACKET->L4.flags & TH_PSH) {
  57. dissect_create_ident(&ident, PACKET, DISSECT_CODE(dissector_pop));
  58. /* the session exist */
  59. if (session_get(&s, ident, DISSECT_IDENT_LEN) != -ENOTFOUND) {
  60. /* prevent the deletion of session created for the user and pass */
  61. if (s->data == NULL) {
  62. /* get the banner */
  63. if (!strncmp(ptr, "+OK", 3))
  64. PACKET->DISSECTOR.banner = strdup(ptr + 4);
  65. else {
  66. SAFE_FREE(ident);
  67. return NULL;
  68. }
  69. DEBUG_MSG("\tdissector_pop BANNER");
  70. /* remove the \r\n */
  71. if ( (ptr = strchr(PACKET->DISSECTOR.banner, '\r')) != NULL )
  72. *ptr = '\0';
  73. /* remove the trailing msg-id <...> */
  74. if ( (ptr = strchr(PACKET->DISSECTOR.banner, '<')) != NULL ) {
  75. /* save the msg-id for APOP authentication */
  76. s->data = strdup(ptr);
  77. /* save the session */
  78. *(ptr - 1) = '\0';
  79. } else {
  80. /* fake the msgid if it does not exist */
  81. s->data = strdup("");
  82. }
  83. } else if (!strcmp(s->data, "AUTH")) {
  84. /*
  85. * the client has requested AUTH LOGIN,
  86. * check if the server support it
  87. * else delete the session
  88. */
  89. if (strstr(ptr, "-ERR"))
  90. dissect_wipe_session(PACKET, DISSECT_CODE(dissector_pop));
  91. }
  92. }
  93. SAFE_FREE(ident);
  94. return NULL;
  95. }
  96. /* skip empty packets (ACK packets) */
  97. if (PACKET->DATA.len == 0)
  98. return NULL;
  99. DEBUG_MSG("POP --> TCP dissector_pop");
  100. /* skip the whitespaces at the beginning */
  101. while(*ptr == ' ' && ptr != end) ptr++;
  102. /* reached the end */
  103. if (ptr == end) return NULL;
  104. /*
  105. * USER & PASS authentication:
  106. *
  107. * USER user
  108. * PASS pass
  109. */
  110. if ( !strncasecmp(ptr, "USER ", 5) ) {
  111. DEBUG_MSG("\tDissector_POP USER");
  112. /* destroy any previous session */
  113. dissect_wipe_session(PACKET, DISSECT_CODE(dissector_pop));
  114. /* create the new session */
  115. dissect_create_session(&s, PACKET, DISSECT_CODE(dissector_pop));
  116. ptr += 5;
  117. /* if not null, free it */
  118. SAFE_FREE(s->data);
  119. /* fill the session data */
  120. s->data = strdup(ptr);
  121. s->data_len = strlen(ptr);
  122. if ( (ptr = strchr(s->data,'\r')) != NULL )
  123. *ptr = '\0';
  124. /* save the session */
  125. session_put(s);
  126. return NULL;
  127. }
  128. /* harvest the password */
  129. if ( !strncasecmp(ptr, "PASS ", 5) ) {
  130. DEBUG_MSG("\tDissector_POP PASS");
  131. ptr += 5;
  132. /* create an ident to retrieve the session */
  133. dissect_create_ident(&ident, PACKET, DISSECT_CODE(dissector_pop));
  134. /* retrieve the session and delete it */
  135. if (session_get_and_del(&s, ident, DISSECT_IDENT_LEN) == -ENOTFOUND) {
  136. SAFE_FREE(ident);
  137. return NULL;
  138. }
  139. SAFE_FREE(ident);
  140. /* check that the user was sent before the pass */
  141. if (s->data == NULL) {
  142. return NULL;
  143. }
  144. /*
  145. * if the PASS command is issued before the USER one, we have to APOP
  146. * digest in the s->data. we can check it on the first char. who has an
  147. * username beginning with '<' ??? :)
  148. */
  149. if (*(char *)(s->data) == '<') {
  150. return NULL;
  151. }
  152. /* fill the structure */
  153. PACKET->DISSECTOR.user = strdup(s->data);
  154. PACKET->DISSECTOR.pass = strdup(ptr);
  155. if ( (ptr = strchr(PACKET->DISSECTOR.pass, '\r')) != NULL )
  156. *ptr = '\0';
  157. /* free the session */
  158. session_free(s);
  159. /* print the message */
  160. DISSECT_MSG("POP : %s:%d -> USER: %s PASS: %s\n", ip_addr_ntoa(&PACKET->L3.dst, tmp),
  161. ntohs(PACKET->L4.dst),
  162. PACKET->DISSECTOR.user,
  163. PACKET->DISSECTOR.pass);
  164. return NULL;
  165. }
  166. /*
  167. * APOP authentication :
  168. *
  169. * APOP user md5-digest
  170. *
  171. * MD5-diges is computed on "<msg-id>pass"
  172. */
  173. if ( !strncasecmp(ptr, "APOP ", 5) ) {
  174. DEBUG_MSG("\tDissector_POP APOP");
  175. /* create an ident to retrieve the session */
  176. dissect_create_ident(&ident, PACKET, DISSECT_CODE(dissector_pop));
  177. /* retrieve the session and delete it */
  178. if (session_get_and_del(&s, ident, DISSECT_IDENT_LEN) == -ENOTFOUND) {
  179. SAFE_FREE(ident);
  180. return NULL;
  181. }
  182. /* check that the digest was sent before APOP */
  183. if (s->data == NULL) {
  184. SAFE_FREE(ident);
  185. return NULL;
  186. }
  187. /* move the pointers to "user" */
  188. ptr += 5;
  189. PACKET->DISSECTOR.user = strdup(ptr);
  190. /* split the string */
  191. if ( (ptr = strchr(PACKET->DISSECTOR.user, ' ')) != NULL )
  192. *ptr = '\0';
  193. else {
  194. /* malformed string */
  195. SAFE_FREE(PACKET->DISSECTOR.user);
  196. session_free(s);
  197. SAFE_FREE(ident);
  198. return NULL;
  199. }
  200. /* skip the \0 */
  201. ptr += 1;
  202. /* save the user */
  203. PACKET->DISSECTOR.pass = strdup(ptr);
  204. if ( (ptr = strchr(PACKET->DISSECTOR.pass, '\r')) != NULL )
  205. *ptr = '\0';
  206. /* set the info */
  207. PACKET->DISSECTOR.info = strdup(s->data);
  208. /* free the session */
  209. session_free(s);
  210. SAFE_FREE(ident);
  211. /* print the message */
  212. DISSECT_MSG("POP : %s:%d -> USER: %s MD5-digest: %s %s\n", ip_addr_ntoa(&PACKET->L3.dst, tmp),
  213. ntohs(PACKET->L4.dst),
  214. PACKET->DISSECTOR.user,
  215. PACKET->DISSECTOR.pass,
  216. PACKET->DISSECTOR.info);
  217. return NULL;
  218. }
  219. /*
  220. * AUTH LOGIN
  221. *
  222. * digest(user)
  223. * digest(pass)
  224. *
  225. * the digests are in base64
  226. */
  227. if ( !strncasecmp(ptr, "AUTH LOGIN", 10) ) {
  228. DEBUG_MSG("\tDissector_POP AUTH LOGIN");
  229. /* destroy any previous session */
  230. dissect_wipe_session(PACKET, DISSECT_CODE(dissector_pop));
  231. /* create the new session */
  232. dissect_create_session(&s, PACKET, DISSECT_CODE(dissector_pop));
  233. /* remember the state (used later) */
  234. s->data = strdup("AUTH");
  235. /* save the session */
  236. session_put(s);
  237. /* username is in the next packet */
  238. return NULL;
  239. }
  240. /* search the session (if it exist) */
  241. dissect_create_ident(&ident, PACKET, DISSECT_CODE(dissector_pop));
  242. if (session_get(&s, ident, DISSECT_IDENT_LEN) == -ENOTFOUND) {
  243. SAFE_FREE(ident);
  244. return NULL;
  245. }
  246. SAFE_FREE(ident);
  247. /* the session is invalid */
  248. if (s->data == NULL) {
  249. dissect_wipe_session(PACKET, DISSECT_CODE(dissector_pop));
  250. return NULL;
  251. }
  252. /* collect the user */
  253. if (!strcmp(s->data, "AUTH")) {
  254. char *user;
  255. int i;
  256. DEBUG_MSG("\tDissector_POP AUTH LOGIN USER");
  257. SAFE_CALLOC(user, strlen(ptr), sizeof(char));
  258. /* username is encoded in base64 */
  259. i = base64_decode(user, ptr);
  260. SAFE_FREE(s->data);
  261. /* store the username in the session */
  262. SAFE_CALLOC(s->data, strlen("AUTH USER ") + i + 1, sizeof(char) );
  263. snprintf(s->data, strlen("AUTH USER ") + i + 1, "AUTH USER %s", user);
  264. SAFE_FREE(user);
  265. /* pass is in the next packet */
  266. return NULL;
  267. }
  268. /* collect the pass */
  269. if (!strncmp(s->data, "AUTH USER", 9)) {
  270. char *pass;
  271. int i;
  272. DEBUG_MSG("\tDissector_POP AUTH LOGIN PASS");
  273. SAFE_CALLOC(pass, strlen(ptr), sizeof(char));
  274. /* password is encoded in base64 */
  275. i = base64_decode(pass, ptr);
  276. /* fill the structure */
  277. PACKET->DISSECTOR.user = strdup(s->data + strlen("AUTH USER "));
  278. PACKET->DISSECTOR.pass = strdup(pass);
  279. SAFE_FREE(pass);
  280. /* destroy the session */
  281. dissect_wipe_session(PACKET, DISSECT_CODE(dissector_pop));
  282. /* print the message */
  283. DISSECT_MSG("POP : %s:%d -> USER: %s PASS: %s\n", ip_addr_ntoa(&PACKET->L3.dst, tmp),
  284. ntohs(PACKET->L4.dst),
  285. PACKET->DISSECTOR.user,
  286. PACKET->DISSECTOR.pass);
  287. return NULL;
  288. }
  289. /*
  290. * AUTH PLAIN
  291. *
  292. * digest(<NULL>user<NULL>pass)
  293. *
  294. * the digests are in base64
  295. */
  296. if ( !strncasecmp(ptr, "AUTH PLAIN", 10) ) {
  297. DEBUG_MSG("\tDissector_POP AUTH PLAIN");
  298. /* destroy any previous session */
  299. dissect_wipe_session(PACKET, DISSECT_CODE(dissector_pop));
  300. /* create the new session */
  301. dissect_create_session(&s, PACKET, DISSECT_CODE(dissector_pop));
  302. /* remember the state (used later) */
  303. s->data = strdup("AUTH PLAIN");
  304. /* save the session */
  305. session_put(s);
  306. /* username is in the next packet */
  307. return NULL;
  308. }
  309. /* collect the user and pass (the session was retrived above) */
  310. if (!strcmp(s->data, "AUTH PLAIN")) {
  311. char *decode;
  312. int i;
  313. DEBUG_MSG("\tDissector_POP AUTH PLAIN USER and PASS");
  314. SAFE_CALLOC(decode, strlen(ptr) + 1, sizeof(char));
  315. /* username is encoded in base64 */
  316. i = base64_decode(decode, ptr);
  317. decode[i] = 0;
  318. SAFE_FREE(s->data);
  319. /* store the username (skip the null)*/
  320. PACKET->DISSECTOR.user = strdup(decode + 1);
  321. /* store the password (skip the null)*/
  322. PACKET->DISSECTOR.pass = strdup(decode + 2 + strlen(decode + 1) );
  323. SAFE_FREE(decode);
  324. dissect_wipe_session(PACKET, DISSECT_CODE(dissector_pop));
  325. /* print the message */
  326. DISSECT_MSG("POP : %s:%d -> USER: %s PASS: %s\n", ip_addr_ntoa(&PACKET->L3.dst, tmp),
  327. ntohs(PACKET->L4.dst),
  328. PACKET->DISSECTOR.user,
  329. PACKET->DISSECTOR.pass);
  330. return NULL;
  331. }
  332. return NULL;
  333. }
  334. /* EOF */
  335. // vim:ts=3:expandtab