I am writing a collection script in python to grab forensic artifacts from various *nix hosts using Python 2 scripts, however I am running into some issues writing netstat collection for Solaris.
There are a few limitations to how I am to achieve this. I cannot use the ELF binaries (except Python) on the computer (as they are often manipulated when *nix machines are attacked), I cannot import external libraries (as this will not run on computers which I administer), and it must be written in Python 2 for backwards compatibility reasons.
All this being said, I am using the netstat.c document by Illumos (an open source Solaris implementation) as my base, and essentially trying to reverse engineer this and rewrite it in Python 2.
https://searchcode.com/codesearch/raw/52916131/
What I've figured out so far is, the script opens '/dev/arp' and '/dev/kstat' to ensure there are return values.
import os
sd = os.open('/dev/arp', os.O_RDWR)
kc = os.open('/dev/kstat', os.O_RDWR)
After this has been done, the 'sd' value is used to collect network statistics with the mibget() method.
And here's the rub. To collect the netstat information, Solaris is querying sd
with the syscall getmsg
, however it is using a datastructure I am unfamiliar with.
getcode = getmsg(sd, &ctlbuf, (struct strbuf *)0, &flags);
I have no idea how to rebuild this in Python 2, do any of you fine people have any ideas of where I can go from here? Am I interpreting this wrong?
I understand the psutil
implementation of netstat works on Solaris, so there must be a means to accomplish this.
Thank you all for your help.
Edit:
This appears to be the relevant section of truss netstat
:
open("/etc/default/inet_type", O_RDONLY) Err#2 ENOENT
open("/dev/arp", O_RDWR) = 3
ioctl(3, I_PUSH, "tcp") = 0
ioctl(3, I_PUSH, "udp") = 0
ioctl(3, I_PUSH, "icmp") = 0
putmsg(3, 0x08047E3C, 0x00000000, 0) = 0
getmsg(3, 0x08047E3C, 0x00000000, 0x08047E5C) = 2
getmsg(3, 0x00000000, 0x08047E48, 0x08047E5C) = 0
getmsg(3, 0x08047E3C, 0x00000000, 0x08047E5C) = 2
getmsg(3, 0x00000000, 0x08047E48, 0x08047E5C) = 0
getmsg(3, 0x08047E3C, 0x00000000, 0x08047E5C) = 2
getmsg(3, 0x00000000, 0x08047E48, 0x08047E5C) = 0
getmsg(3, 0x08047E3C, 0x00000000, 0x08047E5C) = 2
getmsg(3, 0x00000000, 0x08047E48, 0x08047E5C) = 0
getmsg(3, 0x08047E3C, 0x00000000, 0x08047E5C) = 2
getmsg(3, 0x00000000, 0x08047E48, 0x08047E5C) = 0
getmsg(3, 0x08047E3C, 0x00000000, 0x08047E5C) = 2
brk(0x080736E0) = 0
getmsg()
and struct strbuf
are specified by POSIX, albeit marked as obsolescent in POSIX 7:
NAME
getmsg, getpmsg - receive next message from a STREAMS file (STREAMS)
SYNOPSIS
[OB XSR] [Option Start] #include <stropts.h> int getmsg(int fildes, struct strbuf *restrict ctlptr, struct strbuf *restrict dataptr, int *restrict flagsp); int getpmsg(int fildes, struct strbuf *restrict ctlptr, struct strbuf *restrict dataptr, int *restrict bandp, int *restrict flagsp); [Option End]
DESCRIPTION
The
getmsg()
function shall retrieve the contents of a message located at the head of the STREAM head read queue associated with a STREAMS file and place the contents into one or more buffers. The message contains either a data part, a control part, or both. The data and control parts of the message shall be placed into separate buffers, as described below. The semantics of each part are defined by the originator of the message....
I'm not aware of any Python bindings for STREAMS on Solaris.
STREAMS functionality was never implemented on Linux.