3

我正在尝试将命令注入到我拥有的进程中 - 具体来说,我目前正在尝试将 ptraced 进程的文件描述符传递给 ptracing 进程。我成功地创建了一个 unix 域套接字并连接它(据我所见),如下所示:

#define stack_pointer(regs) regs.uregs[13]
#define jumpback_pointer(regs) regs.uregs[14]
#define ip(regs) regs.uregs[15]
#define arg0(regs) regs.uregs[0]
#define arg1(regs) regs.uregs[1]
#define arg2(regs) regs.uregs[2]
#define arg3(regs) regs.uregs[3]

#define ROUND_SIZE_TO_WORD(n) ((((n) - 1) / 4 + 1) * 4)

  // create a socket on the other side
  jumpback_pointer(regs) = 0; // please crash after completion
  ip(regs) = libc_offset + 0x0000cfd4/*socket*/;
  arg0(regs) = PF_UNIX;
  arg1(regs) = SOCK_STREAM;
  arg2(regs) = 0;
  ptrace(PTRACE_SETREGS, pid, NULL, &regs);
  assert(ptrace(PTRACE_CONT, pid, NULL, 0) == 0);
  int waitpid_result;
  assert(waitpid(pid, &waitpid_result, 0) == pid);
  assert(WIFSTOPPED(waitpid_result));
  printf("child was killed with signal %i, we expected it to be killed with SIGSEGV (%i)\n", WSTOPSIG(waitpid_result), SIGSEGV);
  struct pt_regs after_socket_regs;
  assert(ptrace(PTRACE_GETREGS, pid, NULL, &after_socket_regs) == 0);
  int remote_socket_id = arg0(after_socket_regs);
  printf("remote socket created, id=%i\n", remote_socket_id);

  // create a socket on our side and bind it
  int attacker_unix_socket = socket(PF_UNIX, SOCK_STREAM, 0);
  printf("local socket created, id=%i\n", attacker_unix_socket);
  int sockaddr_un_size_r = ROUND_SIZE_TO_WORD(sizeof(struct sockaddr_un)); // round up to words
  if ((sockaddr_un_size_r / 4) * 4 != sockaddr_un_size_r) {
    puts("struct sockaddr_un not properly sized");
    exit(1);
  }
  struct sockaddr_un *sockaddr = malloc(sockaddr_un_size_r);
  sockaddr->sun_family = AF_UNIX;
  strcpy(sockaddr->sun_path, "/tmp/ownage");
  unlink(sockaddr->sun_path);
  assert(bind(attacker_unix_socket, (struct sockaddr *) sockaddr, sizeof(struct sockaddr_un)) == 0);
  assert(listen(attacker_unix_socket, 5) == 0);

  // connect the victim socket
  int child_pid;
  if ((child_pid = fork())) {
    // the parent process takes care of running commands on the victim
    // side - the child isn't allowed to do this
    regs = orig_regs;
    stack_pointer(regs) -= sockaddr_un_size_r; // prepare stack push
    masspoke(pid, sockaddr, stack_pointer(regs), sockaddr_un_size_r); // stack push
    jumpback_pointer(regs) = 0;
    ip(regs) = libc_offset + 0x0000d030/*connect*/;
    arg0(regs) /*sockfd*/ = remote_socket_id;
    arg1(regs) /*addr*/ = stack_pointer(regs);
    arg2(regs) /*addr_len*/ = sizeof(struct sockaddr_un);
    assert(ptrace(PTRACE_SETREGS, pid, NULL, &regs) == 0);
    assert(ptrace(PTRACE_CONT, pid, NULL, 0) == 0);
    assert(waitpid(pid, NULL, 0) == pid);
    struct pt_regs after_connect_regs;
    assert(ptrace(PTRACE_GETREGS, pid, NULL, &after_connect_regs) == 0);
    if (arg0(after_connect_regs)) {
      printf("remote socket connect() failed with return value %li\n", arg0(after_connect_regs));
      exit(1);
    }
    printf("remote socket connected\n");

但是,实际上发送带有以下代码的文件描述符(这是this的修改形式)失败了:

  regs = orig_regs;

  int fd = 10;
  char byte = 0;
  struct iovec iov;
  struct msghdr msg;
  struct cmsghdr *cmsg;
  char buf[CMSG_SPACE (sizeof fd)];

  /* send at least one char */
  memset (&msg, 0, sizeof msg);
  iov.iov_base = &byte;
  iov.iov_len = 1;
  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;
  msg.msg_name = NULL;
  msg.msg_namelen = 0;

  msg.msg_control = buf;
  msg.msg_controllen = sizeof buf;
  cmsg = (struct cmsghdr *) buf;
  cmsg->cmsg_level = SOL_SOCKET;
  cmsg->cmsg_type = SCM_RIGHTS;
  cmsg->cmsg_len = CMSG_LEN (sizeof fd);
  /* Initialize the payload: */
  memcpy (CMSG_DATA (cmsg), &fd, sizeof fd);

  // copy structs over
  long r_buf = stack_pointer(regs) -= ROUND_SIZE_TO_WORD(sizeof(buf));
  masspoke(pid, buf, r_buf, sizeof(buf));
  msg.msg_control = (char **) r_buf;

  long r_byte = stack_pointer(regs) -= ROUND_SIZE_TO_WORD(sizeof(byte));
  masspoke(pid, &byte, r_byte, sizeof(byte));
  iov.iov_base = (char *) r_byte;

  long r_iov = stack_pointer(regs) -= ROUND_SIZE_TO_WORD(sizeof(iov));
  masspoke(pid, &iov, r_iov, sizeof(iov));
  msg.msg_iov = (struct iovec *) r_iov;

  long r_msg = stack_pointer(regs) -= ROUND_SIZE_TO_WORD(sizeof(msg));
  masspoke(pid, &msg, r_msg, sizeof(msg));

  // call it
  jumpback_pointer(regs) = 0;
  ip(regs) = libc_offset + 0x0000d188;
  arg0(regs) = remote_socket_id;
  arg1(regs) = r_msg;
  arg2(regs) = 0;
  ptrace(PTRACE_SETREGS, pid, NULL, &regs);
  assert(ptrace(PTRACE_CONT, pid, NULL, 0) == 0);
  assert(waitpid(pid, NULL, 0) == pid);
  struct pt_regs after_sendmsg_regs;
  assert(ptrace(PTRACE_GETREGS, pid, NULL, &after_sendmsg_regs) == 0);

  if (arg0(after_sendmsg_regs) != iov.iov_len) {
    printf("sendmsg() failed (returned %li)\n", arg0(after_sendmsg_regs));
    exit(1);
  }
  printf("successfully called sendmsg() on the other side!\n");

sendmsg()总是失败-1。所以,我的问题是,有谁知道为什么这不起作用,或者至少能够告诉我如何尝试找到 errno 以获取有关错误的一些线索?我试过这个来找到errno,但PTRACE_PEEKDATA总是失败:

void print_error(int pid, struct pt_regs regs, unsigned int libc_offset) {
  // call __errno to get a pointer to the errno
  jumpback_pointer(regs) = 0; // crash afterwards
  ip(regs) = libc_offset + LIBC_ERRNO;
  ptrace(PTRACE_SETREGS, pid, NULL, &regs);
  assert(ptrace(PTRACE_CONT, pid, NULL, 0) == 0);
  int waitpid_result;
  assert(waitpid(pid, &waitpid_result, 0) == pid);
  struct pt_regs after___errno_regs;
  assert(ptrace(PTRACE_GETREGS, pid, NULL, &after___errno_regs) == 0);
  long errno_fn_addr = arg0(after___errno_regs);
  long child_errno = ptrace(PTRACE_PEEKDATA, pid, errno_fn_addr, NULL);
  int peek_errno = errno;
  printf("ERROR IN PTRACED PROCESS: %s (errno@%lx=%li), peek errno: %s\n", strerror(child_errno), errno_fn_addr, child_errno, strerror(peek_errno));
}
4

0 回答 0