Clone wiki

Challenge11 / Stage5

Stage 4

Analysis without Discrete Logarithm Calculation

Without cracking the stage 2 encryption, it has not been possible to fully reverse this payload stage. However, based on known prior behaviour patterns, it is possible to make some reasonable estimations.

Examining the encrypted traffic between 10.0.0.1 and its server, we notice that, in packet #207, 10.0.0.1 communicates a null byte to the server. Based on known prior behaviour, we hypothesis that this packet marks entry into the stage 4 payload by writing back the stage 4 payload's entry offset (after it has been zeroed):

Stage 4 Sequence Diagram

Without being able to reconstruct the random session key (by performing our discrete logarithm calculation), this is as far as we can reasonably go here with reconstructing the stage 4 payload.

Analysis with Discrete Logarithm Calculation

Note: the following analysis was performed using the results of Ruud Schramp's discrete logarithm calculation.

Using the demo copy of the 010 Hex Editor (with an ELF template), we may view the ELF header present in the extracted section 0 (see honeynet_stage4_payload.section0.elf : Stage 4 ELF Header

Using this information, we reconstruct the stage 4 ELF file (see honeynet_stage4_payload.elf - MD5: 374d3f0f4a7c0dc3a7fcad2ad50517cf). VirusTotal does not report this reconstructed ELF file as being known to any of its 42 AV agents.

In performing this reconstruction, we discover the existence of an additional section within the ELF file: Stage 4 ELF Header

From the IDA Pro disassembly of our reconstructed honeynet_stage4_payload.elf and /usr/src/sys/kern/syscalls.master, we note the presence of the following FreeBSD system call numbers:

  • 0x1 - void sys_exit(int rval) (see _exit manpage)
  • 0x2 - int fork(void) (see fork manpage)
  • 0x3 - ssize_t read(int fd, void *buf, size_t nbyte) (see read manpage)
  • 0x4 - ssize_t write(int fd, const void *buf, size_t nbyte) (see write manpage)
  • 0x5 - int open(char *path, int flags, int mode) (see open manpage)
  • 0x6 - int close(int fd) (see close manpage)
  • 0x11 - int obreak(char *nsize)
  • 0x14 - pid_t getpid(void) (see getpid manpage)
  • 0x21 - int access(char *path, int amode) (see access manpage)
  • 0x25 - int kill(int pid, int signum) (see kill manpage)
  • 0x2a - int pipe(void) (see pipe manpage)
  • 0x36 - int ioctl(int fd, u_long com, caddr_t data) (see ioctl manpage)
  • 0x3a - ssize_t readlink(char *path, char *buf, size_t count) (see readlink manpage)
  • 0x3b - int execve(char *fname, char **argv, char **envv) (see execve manpage)
  • 0x49 - int munmap(void *addr, size_t len) (see munmap manpage)
  • 0x4b - int madvise(void *addr, size_t len, int behav) (see madvise manpage)
  • 0x59 - int getdtablesize(void) (see getdtablesize manpage)
  • 0x5a - int dup2(u_int from, u_int to) (see dup2 manpage)
  • 0x5c - int fcntl(int fd, int cmd, long arg) (see fnctl manpage)
  • 0x5d - int select(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv) (see select manpage)
  • 0x61 - int socket(int domain, int type, int protocol) (see socket manpage)
  • 0x79 - int writev(int fd, struct iovec *iovp, u_int iovcnt) (see writev manpage)
  • 0x85 - int sendto(int s, caddr_t buf, size_t len, int flags, caddr_t to, int tolen) (see sendto manpage)
  • 0x98 - uid_t geteuid(void) (see geteuid manpage)
  • 0xa5 - int sysarch(int op, char *parms) (see sysarch manpage)
  • 0xbc - int stat(char *path, struct stat *ub) (see stat manpage)
  • 0xbd - int fstat(int fd, struct stat *sb) (see fstat manpage)
  • 0xc5 - caddr_t freebsd6_mmap(caddr_t addr, size_t len, int prot, int flags, int fd, int pad, off_t pos)
  • 0xc7 - off_t freebsd6_lseek(int fd, int pad, off_t offset, int whence)
  • 0xca - int sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen) (see sysctl manpage, /include/sys/sysctl.h and /include/sys/user.h)
  • 0xd1 - int poll(struct pollfd *fds, u_int nfds, int timeout) (see poll manpage)
  • 0xe8 - int clock_gettime(clockid_t clock_id, struct timespec *tp) (see clock_gettime manpage)
  • 0xf0 - int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) (see nanosleep manpage)
  • 0xfd - int issetugid(void) (see issetugid manpage)
  • 0x136 - int getsid(pid_t pid) (see getsid manpage)
  • 0x14f - int utrace(const void *addr, size_t len) (see utrace manpage)
  • 0x154 - int sigprocmask(int how, const sigset_t *set, sigset_t *oset) (see sigprocmask manpage)
  • 0x1a0 - int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) (see sigaction manpage)
  • 0x1dd - caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, off_t pos) (see mmap manpage and /include/sys/mman.h)
  • 0x1de - off_t lseek(int fd, off_t offset, int whence) (see lseek manpage)

As all these FreeBSD system functions are wrapped within functions, then, when reversing the assembler, we use IDA Pro to rename the wrapping function with the called system function name. In doing this, we additionally note that:

  • caddr_t freebsd6_mmap(caddr_t addr, size_t len, int prot, int flags, int fd, int pad, off_t pos) and caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, off_t pos) are wrapped in a common function
  • off_t freebsd6_lseek(int fd, int pad, off_t offset, int whence) and off_t lseek(int fd, off_t offset, int whence) are wrapped in a common function.

These common function wrappers appear to exist so as to ensure that the ELF binary is backwards compatible with FreeBSD 6?

TODO: perform a behavioural analysis of stage 4.

Updated