瀏覽代碼

smb msg helpers, dialect negociation, partial headers for session setup

Julien 'Lta' BALLET 11 年之前
父節點
當前提交
a80cf723f5
共有 9 個文件被更改,包括 293 次插入28 次删除
  1. 1 0
      Makefile
  2. 24 10
      dsm.c
  3. 2 0
      include/bdsm/netbios_session.h
  4. 45 10
      include/bdsm/smb_defs.h
  5. 13 2
      include/bdsm/smb_message.h
  6. 36 0
      include/bdsm/smb_session.h
  7. 3 3
      src/netbios_session.c
  8. 30 3
      src/smb_message.c
  9. 139 0
      src/smb_session.c

+ 1 - 0
Makefile

@@ -14,6 +14,7 @@ UTIL_SRC		= dsm.c 							    \
 							src/netbios_query.c     \
 							src/netbios_session.c		\
 							src/smb_message.c				\
+							src/smb_session.c				\
 							src/context.c
 
 UTIL_OBJS		= $(UTIL_SRC:.c=.o)

+ 24 - 10
dsm.c

@@ -19,7 +19,7 @@
 #include "bdsm.h"
 #include "bdsm/netbios_utils.h"
 #include "bdsm/netbios_session.h"
-#include "bdsm/smb_defs.h"
+#include "bdsm/smb_session.h"
 
 int main(int ac, char **av)
 {
@@ -37,19 +37,33 @@ int main(int ac, char **av)
   //netbios_ns_discover(ctx->ns);
   //exit(0);
 
-  netbios_session_t *session;
-  session = netbios_session_new(addr.sin_addr.s_addr);
-  if (netbios_session_connect(session, "Cerbere"))
-    printf("A NetBIOS session with %s has been established\n", av[1]);
+  // netbios_session_t *session;
+  // session = netbios_session_new(addr.sin_addr.s_addr);
+  // if (netbios_session_connect(session, "Cerbere"))
+  //   printf("A NetBIOS session with %s has been established\n", av[1]);
+  // else
+  // {
+  //   printf("Unable to establish a NetBIOS session with %s\n", av[1]);
+  //   exit(21);
+  // }
+
+  // netbios_session_destroy(session);
+
+  smb_session_t *session;
+  session = smb_session_new();
+  if (smb_session_connect(session, av[1], addr.sin_addr.s_addr))
+    printf("Successfully connected to %s\n", av[1]);
   else
   {
-    printf("Unable to establish a NetBIOS session with %s\n", av[1]);
-    exit(21);
+    printf("Unable to connect to %s\n", av[1]);
+    exit(42);
   }
+  if (smb_session_negotiate_protocol(session))
+    printf("cool\n");
+  else
+    printf("Unable to negotiate SMB Dialect\n");
 
-
-
-  netbios_session_destroy(session);
+  smb_session_destroy(session);
   bdsm_context_destroy(ctx);
 
   return (0);

+ 2 - 0
include/bdsm/netbios_session.h

@@ -41,8 +41,10 @@ typedef struct              netbios_session_s {
   uint8_t                     recv_buffer[NETBIOS_SESSION_BUFFER];
 }                           netbios_session_t;
 
+// Return NULL if unable to open socket/connect
 netbios_session_t *netbios_session_new(uint32_t ip_addr);
 void              netbios_session_destroy(netbios_session_t *);
+
 int               netbios_session_connect(netbios_session_t *s, char *name);
 void              netbios_session_packet_init(netbios_session_t *s,
                                               uint8_t opcode);

+ 45 - 10
include/bdsm/smb_defs.h

@@ -11,11 +11,15 @@
 #define SMB_MAGIC               { 0xff, 0x53, 0x4d, 0x42 } // aka "\xffSMB"
 
 #define SMB_DIALECTS {          \
-  "\2PC NETWORK PROGRAM 1.0",   \
+  "\2Samba",                    \
   "\2NT LM 0.12",               \
   NULL                          \
 }
 
+// Dialect values must match position on SMB_DIALECTS array
+#define SMB_DIALECT_SAMBA       0
+#define SMB_DIALECT_NTLM        1
+
 #define SMB_CMD_CLOSE           0x04
 #define SMB_CMD_TRANS2          0x32
 #define SMD_CMD_TREE_DISCONNECT 0x71
@@ -26,6 +30,33 @@
 #define SMB_CMD_READ            0x2e // Read AndX
 #define SMB_CMD_CREATE          0xa2 // NT Create AndX
 
+#define SMB_SET_FLAG            0
+#define SMB_SET_FLAG2           0
+
+#define SMB_FLAG_RESPONSE       (1 << 7)
+#define SMB_FLAG_NOTIFY         (1 << 6)
+#define SMB_FLAG_OPLOCK         (1 << 5)
+#define SMB_FLAG_CANONIC        (1 << 4)
+#define SMB_FLAG_CASELESS       (1 << 3)
+#define SMB_FLAG_BUFFER_POSTED  (1 << 1)
+#define SMB_FLAG_LOCK_AND_READ  (1 << 0)
+
+#define SMB_FLAG_UNICODE        (1 << (15 + 8))
+#define SMB_FLAG_NT_ERRORS      (1 << (14 + 8))
+#define SMB_FLAG_EXECUTE_ONLY   (1 << (13 + 8))
+#define SMB_FLAG_DFS            (1 << (12 + 8))
+#define SMB_FLAG_EXT_SEC        (1 << (11 + 8))
+#define SMB_FLAG_REPARSE_PATH   (1 << (10 + 8))
+#define SMB_FLAG_LONG_NAMES     (1 << (6 + 8))
+#define SMB_FLAG_SIGN_REQUIRED  (1 << (4 + 8))
+#define SMB_FLAG_COMPRESSED     (1 << (3 + 8))
+#define SMB_FLAG_SIGN_SUPPORT   (1 << (2 + 8))
+#define SMB_FLAG_EXT_ATTR       (1 << (1 + 8))
+#define SMB_FLAG_LONG_NAMES_OK  (1 << (0 + 8))
+
+#define NT_STATUS_SUCCESS                   0x00000000
+#define NT_STATUS_MORE_PROCESSING_REQUIRED  0xc0000016
+
 typedef struct
 {
   uint8_t         wct; // zero
@@ -42,7 +73,19 @@ typedef struct
 
 typedef struct
 {
-
+  uint8_t         wct;          // +-12 :)
+  uint8_t         andx;         // 0xff when no other command (recommended :)
+  uint8_t         reserved;     // 0x00
+  uint16_t        andx_offset;  // 0x00 when no other command
+  uint16_t        max_buffer;   // Maximum size we can receive
+  uint16_t        mpx_count;    // maximum multiplexed session
+  uint16_t        vc_count;     // Virtual ciruits -> 1!
+  uint32_t        session_key;  // 0x00000000
+  uint16_t        blob_length;  // Length of Security Blob
+  uint32_t        reserved2;    // 0x00000000
+  uint32_t        caps;         // Capabilities
+  uint16_t        payload_size;
+  uint8_t         payload[];
 } __attribute__((packed))   smb_session_req_t;
 
 typedef struct
@@ -72,13 +115,5 @@ typedef struct
   uint8_t         payload[];    // Ze yummy data inside. Eat 5 fruits/day !
 } __attribute__((packed))       smb_packet_t;
 
-// This is used with convenience functions to build packets.
-typedef struct
-{
-  size_t          payload_size; // Size of the allocated payload
-  size_t          cursor;       // Write cursor in the payload
-  smb_packet_t    *packet;      // Yummy yummy, Fruity fruity !
-}                               smb_message_t;
-
 
 #endif

+ 13 - 2
include/bdsm/smb_message.h

@@ -3,12 +3,20 @@
 // Copyright VideoLabs 2014
 // License: MIT License
 
-#ifndef __BDSM_SMB_PACKET_H_
-#define __BDSM_SMB_PACKET_H_
+#ifndef __BDSM_SMB_MESSAGE_H_
+#define __BDSM_SMB_MESSAGE_H_
 
 // The actual packet data format definition is here
 #include "bdsm/smb_defs.h"
 
+// This is used with convenience functions to build packets.
+typedef struct
+{
+  size_t          payload_size; // Size of the allocated payload
+  size_t          cursor;       // Write cursor in the payload
+  smb_packet_t    *packet;      // Yummy yummy, Fruity fruity !
+}                               smb_message_t;
+
 smb_message_t   *smb_message_new(uint8_t cmd, size_t payload_size);
 void            smb_message_destroy(smb_message_t *msg);
 int             smb_message_append(smb_message_t *msg, const void *data,
@@ -17,4 +25,7 @@ int             smb_message_put8(smb_message_t *msg, uint8_t data);
 int             smb_message_put16(smb_message_t *msg, uint16_t data);
 int             smb_message_put32(smb_message_t *msg, uint32_t data);
 int             smb_message_put64(smb_message_t *msg, uint32_t data);
+
+void            smb_message_set_default_flags(smb_message_t *msg);
+void            smb_message_flag(smb_message_t *msg, uint32_t flag, int value);
 #endif

+ 36 - 0
include/bdsm/smb_session.h

@@ -0,0 +1,36 @@
+// This file is part of libdsm
+// Author: Julien 'Lta' BALLET <contact@lta.io>
+// Copyright VideoLabs 2014
+// License: MIT License
+
+#ifndef __BDSM_SMB_SESSION_H_
+#define __BDSM_SMB_SESSION_H_
+
+#include "bdsm/netbios_session.h"
+#include "bdsm/smb_defs.h"
+#include "bdsm/smb_message.h"
+
+#define SMB_STATE_DIALECT_OK    2
+#define SMB_STATE_NETBIOS_OK    1
+#define SMB_STATE_NEW           0
+#define SMB_STATE_ERROR         -1
+
+typedef struct
+{
+  int                 state;
+  unsigned            dialect;
+  netbios_session_t   *nb_session;
+}                   smb_session_t;
+
+
+smb_session_t   *smb_session_new();
+void            smb_session_destroy(smb_session_t *s);
+
+int             smb_session_send_msg(smb_session_t *s, smb_message_t *msg);
+// msg->packet will be updated to point on received data. You don't own this
+// memory. It'll be reused on next recv_msg
+size_t          smb_session_recv_msg(smb_session_t *s, smb_message_t *msg);
+int             smb_session_connect(smb_session_t *s, char *name, uint32_t ip);
+int             smb_session_negotiate_protocol(smb_session_t *s);
+
+#endif

+ 3 - 3
src/netbios_session.c

@@ -50,7 +50,7 @@ netbios_session_t *netbios_session_new(uint32_t ip_addr)
   if (!open_socket_and_connect(session))
   {
     netbios_session_destroy(session);
-    return (0);
+    return (NULL);
   }
 
   return(session);
@@ -133,13 +133,13 @@ int               netbios_session_packet_append(netbios_session_t *s,
   assert(s && s->packet);
 
   if (s->packet_payload_size - s->packet_cursor < size)
-    return (-1);
+    return (0);
 
   start = ((char *)&s->packet->payload) + s->packet_cursor;
   memcpy(start, data, size);
   s->packet_cursor += size;
 
-  return (0);
+  return (1);
 }
 
 int               netbios_session_packet_send(netbios_session_t *s)

+ 30 - 3
src/smb_message.c

@@ -3,10 +3,12 @@
 // Copyright VideoLabs 2014
 // License: MIT License
 
+#include <assert.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <stdio.h>
-#include <assert.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "bdsm/smb_message.h"
 
@@ -28,7 +30,8 @@ smb_message_t   *smb_message_new(uint8_t cmd, size_t payload_size)
 
   for (unsigned i = 0; i < 4; i++)
     msg->packet->header.magic[i] = magic[i];
-  msg->packet->header.command  = cmd;
+  msg->packet->header.command   = cmd;
+  msg->packet->header.pid       = getpid();
 
   return (msg);
 }
@@ -76,3 +79,27 @@ int             smb_message_put64(smb_message_t *msg, uint32_t data)
 {
     return(smb_message_append(msg, (void *)&data, 8));
 }
+
+void            smb_message_flag(smb_message_t *msg, uint32_t flag, int value)
+{
+  uint32_t      *flags;
+
+  assert(msg != NULL && msg->packet != NULL);
+
+  // flags + flags2 is actually 24 bit long, we have to be cautious
+  flags = (uint32_t *)&(msg->packet->header.flags);
+  flag &= 0x00FFFFFF;
+
+  if (value)
+    *flags |= flag;
+  else
+    *flags &= ~flag;
+}
+
+void            smb_message_set_default_flags(smb_message_t *msg)
+{
+  assert(msg != NULL && msg->packet != NULL);
+
+  msg->packet->header.flags   = 0x18;
+  msg->packet->header.flags2  = 0xc843;
+}

+ 139 - 0
src/smb_session.c

@@ -0,0 +1,139 @@
+// This file is part of libdsm
+// Author: Julien 'Lta' BALLET <contact@lta.io>
+// Copyright VideoLabs 2014
+// License: MIT License
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "bdsm/smb_session.h"
+
+smb_session_t   *smb_session_new()
+{
+  smb_session_t *s;
+
+  s = malloc(sizeof(smb_session_t));
+  assert(s != NULL);
+  memset((void *)s, 0, sizeof(smb_session_t));
+
+  return (s);
+}
+
+void            smb_session_destroy(smb_session_t *s)
+{
+  if (s != NULL)
+  {
+    if (s->nb_session != NULL)
+      netbios_session_destroy(s->nb_session);
+    free(s);
+  }
+}
+
+int             smb_session_connect(smb_session_t *s, char *name, uint32_t ip)
+{
+  assert(s != NULL && name != NULL);
+
+  if ((s->nb_session = netbios_session_new(ip)) == NULL)
+    goto error;
+  if (!netbios_session_connect(s->nb_session, name))
+    goto error;
+
+  s->state = SMB_STATE_NETBIOS_OK;
+  return (1);
+
+  error:
+    s->state = SMB_STATE_ERROR;
+    return (0);
+}
+
+int             smb_session_send_msg(smb_session_t *s, smb_message_t *msg)
+{
+  size_t        packet_size;
+
+  assert(s != NULL && s->state >= SMB_STATE_NETBIOS_OK && s->nb_session != NULL);
+  assert(msg != NULL && msg->packet != NULL);
+
+  netbios_session_packet_init(s->nb_session, NETBIOS_OP_SESSION_MSG);
+
+  packet_size   = sizeof(netbios_session_packet_t) + sizeof(smb_packet_t);
+  packet_size  += msg->cursor;
+  if (!netbios_session_packet_append(s->nb_session, (char *)msg->packet, packet_size))
+    return (0);
+  if (!netbios_session_packet_send(s->nb_session))
+    return (0);
+
+  return (1);
+}
+
+size_t          smb_session_recv_msg(smb_session_t *s, smb_message_t *msg)
+{
+  netbios_session_packet_t  *nb_packet;
+  ssize_t                   recv_size;
+  size_t                    payload_size;
+
+  assert(s != NULL && s->nb_session != NULL && msg != NULL);
+
+  recv_size = netbios_session_packet_recv(s->nb_session);
+  if(recv_size <= 0)
+    return (0);
+
+  nb_packet   = (netbios_session_packet_t *)s->nb_session->recv_buffer;
+  msg->packet = (smb_packet_t *)nb_packet->payload;
+
+  payload_size  = ntohs(nb_packet->length);
+  payload_size |= (nb_packet->flags & 0x01) << 16; // XXX If this is the case we overran our recv_buffer
+  if (payload_size > recv_size - sizeof(netbios_session_packet_t))
+  {
+    if (BDSM_DEBUG)
+      fprintf(stderr, "smb_session_recv_msg: Packet size mismatch\n");
+    return(0);
+  }
+
+  msg->payload_size = payload_size - sizeof(smb_header_t);
+  msg->cursor       = 0;
+
+  return(msg->payload_size);
+}
+
+int             smb_session_negotiate_protocol(smb_session_t *s)
+{
+  smb_message_t *msg = NULL;
+  smb_message_t answer;
+  const char    *dialects[] = SMB_DIALECTS;
+
+  msg = smb_message_new(SMB_CMD_NEGOTIATE, 64);
+  smb_message_set_default_flags(msg);
+
+  smb_message_put8(msg, 0);   // wct
+  smb_message_put16(msg, 0);  // bct, will be updated later
+
+  for(unsigned i = 0; dialects[i] != NULL; i++)
+    smb_message_append(msg, dialects[i], strlen(dialects[i]) + 1);
+  *((uint16_t *)(msg->packet->payload + 1)) = msg->cursor - 3;
+
+  if (!smb_session_send_msg(s, msg))
+  {
+    smb_message_destroy(msg);
+    goto error;
+  }
+  smb_message_destroy(msg);
+
+  if (!smb_session_recv_msg(s, &answer))
+    goto error;
+
+  if (answer.packet->header.status != NT_STATUS_SUCCESS
+      && answer.packet->payload[0] != 0x11)
+    goto error;
+
+  // we dont provide more than 256 dialects, so we use it as an unsigned char
+  s->dialect  = answer.packet->payload[1];
+  s->state    = SMB_STATE_DIALECT_OK;
+
+  return (1);
+
+  error:
+    s->state = SMB_STATE_ERROR;
+    return (0);
+}