Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >通过chkrootkit学习如何在linux下检测RootKit

通过chkrootkit学习如何在linux下检测RootKit

作者头像
用户1423082
发布于 2024-12-31 10:38:31
发布于 2024-12-31 10:38:31
20500
代码可运行
举报
文章被收录于专栏:giantbranch's bloggiantbranch's blog
运行总次数:0
代码可运行

Rootkit是一种特殊的恶意软件,它的功能是在安装目标上隐藏自身及指定的文件、进程和网络链接等信息,比较多见到的是Rootkit一般都和木马、后门等其他恶意程序结合使用。Rootkit一词更多地是指被作为驱动程序,加载到操作系统内核中的恶意软件。

chkrootkit简介

chkrootkit是一个linux下检RootKit的脚本,在某些检测中会调用当前目录的检测程序

官网:http://www.chkrootkit.org/

下载源码:ftp://ftp.pangeia.com.br/pub/seg/pac/chkrootkit.tar.gz

解压后执行 make 命令,就可以使用了

一般直接运行,一旦有INFECTED,说明可能被植入了RootKit

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
./chkrootkit | grep INFECTED

总体流程

首先删除别名,确保接下来的一些操作不会用了被RootKit改变了的别名

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
### workaround for some Bourne shell implementations
unalias login > /dev/null 2>&1
unalias ls > /dev/null 2>&1
unalias netstat > /dev/null 2>&1
unalias ps > /dev/null 2>&1
unalias dirname > /dev/null 2>&1

一开始会检测一些必要的命令是否可用,可执行,因为检测基于这些命令

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cmdlist="
awk
cut
echo
egrep
find
head
id
ls
netstat
ps
sed
ssh
strings
uname
"

接下来就是检测ps的参数ax好不好使,好使就使用ax,不好使就用-fe

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# Check if ps command is ok
if ${ps} ax >/dev/null 2>&1 ; then
   ps_cmd="ax"
else
   ps_cmd="-fe"
fi

当然还需检测你是否是root,就根据你的id号是否为0

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if [ `${id} | ${cut} -d= -f2 | ${cut} -d\( -f1` -ne 0 ]; then
   echo "$0 need root privileges"
   exit 1
fi

接下来就是默认执行所有测试,当然你也可以指定测试的命令

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if [ $# -gt 0 ]
then
    ### perform only tests supplied as arguments
    for arg in $*
    do
        ### check if is a valid test name
        if echo "${TROJAN} ${TOOLS}"| \
           ${egrep} -v "${L_REGEXP}$arg${R_REGEXP}" > /dev/null 2>&1
        then
            echo >&2 "$0: \`$arg': not a known test"
            exit 1
        fi
    done
    LIST=$*
else
    ### this is the default: perform all tests
    LIST="${TROJAN} ${TOOLS}"
fi

接下来只是对是否开启调试模式,用户是否指定了要检测的根目录进行处理

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if [ "${DEBUG}" = "t" ]; then
    set -x
fi

if [ "${ROOTDIR}" != "/" ]; then

    ### remove trailing `/'
    ROOTDIR=`echo ${ROOTDIR} | ${sed} -e 's/\/*$//g'`

    for dir in ${pth}
    do
      if echo ${dir} | ${egrep} '^/' > /dev/null 2>&1
      then
        newpth="${newpth} ${ROOTDIR}${dir}"
      else
        newpth="${newpth} ${ROOTDIR}/${dir}"
      fi
    done
    pth=${newpth}
   ROOTDIR="${ROOTDIR}/"
fi

最后便是循环调用各个check函数进行处理了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for cmd in ${LIST}
do

    if echo "${TROJAN}" | \
    ${egrep} "${L_REGEXP}$cmd${R_REGEXP}" > /dev/null 2>&1
    then
        if [ "${EXPERT}" != "t" -a "${QUIET}" != "t" ]; then
           printn "Checking \`${cmd}'... "
        fi
        chk_${cmd}
        STATUS=$?

        ### quiet mode
        if [ "${QUIET}" = "t" ]; then
            ### show only INFECTED status
            if [ ${STATUS} -eq 0 ]; then
                echo "Checking \`${cmd}'... INFECTED"
            fi
            continue
        fi

        case $STATUS in
        0) echo "INFECTED";;
        1) echo "not infected";;
        2) echo "not tested";;
        3) echo "not found";;
        4) echo "infected but disabled";;
        5) ;;   ### expert mode
        esac
    else
        ### external tool
        if [ "${EXPERT}" != "t" -a "${QUIET}" != "t" ]; then
            printn "Checking \`$cmd'... "
        fi
        ${cmd}

    fi
done

那么接下来每个check方法到底是怎么检测的呢?接下来

检测方法

通过分析脚本,总结出检测方法如下:

  1. 搜索通用的ROOTKIT特征的字符串
  2. 对某种特定的rootkits,或者命令的特殊的感染特征进行检测
  3. 对某种特定的rootkits的生成的特定文件的检测
  4. 对程序的SUID位的设置进行检测
  5. 对ldsopreload的检测
  6. 查找可疑的log文件
  7. 查找可疑的php文件
  8. 检测.history文件
  9. 检测有无程序监听了一些可疑的端口
  10. 检测Linux可加载内核模块
  11. 检测有无隐藏进程
  12. 检测目录的软链接异常
  13. 检测网络接口的异常
  14. 检测用户的登录日志
  15. 检测上一次登录
  16. 检测可疑的没有tty记录的进程

下面对上面这些方法结合脚本代码进行简单说明

搜索通用的ROOTKIT特征的字符串

搜索的是下面的比较通用的ROOTKIT字符串

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# Many trojaned commands have this label
GENERIC_ROOTKIT_LABEL="^/bin/.*sh$|bash|elite$|vejeta|\.ark|iroffer"

可以看到前两个都是shell相关的,相关的示例代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
chk_chfn () {
    STATUS=${NOT_INFECTED}
    CMD=`loc chfn chfn $pth`
    [ ${?} -ne 0 ] &&  return ${NOT_FOUND}

    if [ "${EXPERT}" = "t" ]; then
        expertmode_output "${strings} -a ${CMD}"
        return 5
    fi

    case "${SYSTEM}" in
       Linux)
          if ${strings} -a ${CMD} | ${egrep} "${GENERIC_ROOTKIT_LABEL}" \
             >/dev/null 2>&1
          then
             STATUS=${INFECTED}
          fi;;
       FreeBSD)
          [ `echo $V | ${awk} '{ if ( $1 >= 5.0) print 1; else print 0 }'` -eq 1 ] && n=1 || n=2
          if [ `${strings} -a ${CMD} | \
                ${egrep} -c "${GENERIC_ROOTKIT_LABEL}"` -ne $n ]
          then
             STATUS=${INFECTED}
          fi;;
    esac
    return ${STATUS}
}

程序针对Linux和FreeBSD系统分开处理,都是通过strings获取二进制程序中的字符串,再使用egrep命令去正则匹配,匹配成功就将返回值STATUS设置为INFECTED这个常量(这个在文件开头处定义了)

对某种特定的rootkits,或者命令的特殊的感染特征进行检测

比如这个amd命令的某个感染特征

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
chk_amd () {
    STATUS=${NOT_INFECTED}
    AMD_INFECTED_LABEL="blah"
    CMD=`loc amd amd $pth`
    if [ ! -x "${CMD}" ]; then
         return ${NOT_FOUND}
    fi
    if [ "${EXPERT}" = "t" ]; then
        expertmode_output "${strings} -a ${CMD}"
        return 5
    fi
    if ${strings} -a ${CMD} | ${egrep} "${AMD_INFECTED_LABEL}" >/dev/null 2>&1
    then
       STATUS=${INFECTED}
    fi
    return ${STATUS}
}

下面这个检测crontab的nobody用户,并且定时任务中有数字的, 可能是Lupper.Worm 当然还是有CRONTAB_I_L这个特殊的检测

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
chk_crontab () {
    STATUS=${NOT_INFECTED}
    CRONTAB_I_L="crontab.*666"

    CMD=`loc crontab crontab $pth`

    if [ ! -r ${CMD} ]
       then
        return ${NOT_FOUND}
    fi

    if [ "${EXPERT}" = "t" ]; then
        expertmode_output "${CMD} -l -u nobody"
        return 5
    fi
    # slackware's crontab have a bug
    if  ( ${CMD} -l -u nobody | $egrep [0-9] ) >/dev/null 2>&1 ; then
        ${echo} "Warning: crontab for nobody found, possible Lupper.Worm... "
	if ${CMD} -l -u nobody 2>/dev/null  | ${egrep} $CRONTAB_I_L >/dev/null 2>&1
	   then
           STATUS=${INFECTED}
	fi
    fi
    return ${STATUS}
}

对Ramen Worm进行特征匹配

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if ${egrep} "^asp" ${ROOTDIR}etc/inetd.conf >/dev/null 2>&1; then
    echo "Warning: Possible Ramen Worm installed in inetd.conf"
    STATUS=${INFECTED}
fi

对某种特定的rootkits生成的特定文件的检测

如下面的HiDrootkit和t0rn

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
### HiDrootkit
if [ "${QUIET}" != "t" ]; then printn \
  "Searching for HiDrootkit's default dir... "; fi
if [ -d ${ROOTDIR}var/lib/games/.k ]
then
  echo "Possible HiDrootkit installed"
else
  if [ "${QUIET}" != "t" ]; then echo "nothing found"; fi
fi

### t0rn
if [ "${QUIET}" != "t" ]; then printn\
  "Searching for t0rn's default files and dirs... "; fi
if [ -f ${ROOTDIR}etc/ttyhash -o -f ${ROOTDIR}sbin/xlogin -o \
    -d ${ROOTDIR}usr/src/.puta  -o -r ${ROOTDIR}lib/ldlib.tk -o \
    -d ${ROOTDIR}usr/info/.t0rn ]
then
  echo "Possible t0rn rootkit installed"
else
  if [ "${QUIET}" != "t" ]; then echo "nothing found"; fi
fi

对程序的SUID位的设置进行检测

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
chk_basename () {
   STATUS=${NOT_INFECTED}
   CMD=`loc basename basename $pth`

   if [ "${EXPERT}" = "t" ]; then
       expertmode_output "${strings} -a ${CMD}"
       expertmode_output "${ls} -l ${CMD}"
       return 5
   fi
   if ${strings} -a ${CMD} | ${egrep} "${GENERIC_ROOTKIT_LABEL}" > /dev/null 2>&1
   then
       STATUS=${INFECTED}
   fi

   [ "$SYSTEM" != "OSF1" ] &&
   {
      if ${ls} -l ${CMD} | ${egrep} "^...s" > /dev/null 2>&1
      then
         STATUS=${INFECTED}
      fi
   }
   return ${STATUS}
}

这个除了检测有无关键字,还检测SUID位有无设置

对ldsopreload的检测

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
chk_ldsopreload() {
   STATUS=${NOT_INFECTED}
   CMD="${ROOTDIR}lib/libshow.so ${ROOTDIR}lib/libproc.a"

   if [ "${SYSTEM}" = "Linux" ]
   then
      if [ ! -x ./strings-static ]; then
        printn "can't exec ./strings-static, "
        return ${NOT_TESTED}
      fi

      if [ "${EXPERT}" = "t" ]; then
          expertmode_output "./strings-static -a ${CMD}"
          return 5
      fi

      ### strings must be a statically linked binary.
      if ./strings-static -a ${CMD} > /dev/null 2>&1
      then
         STATUS=${INFECTED}
      fi
   else
     STATUS=${NOT_TESTED}
   fi
   return ${STATUS}
}

检测是否有libshow.so,libproc.a,有就说明感染了恶意so文件

可以看到为了保险起见,作者使用的是自己目录下静态编译的strings进行检测

查找可疑的log文件

例子如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
files=`${find} ${ROOTDIR}dev ${ROOTDIR}tmp ${ROOTDIR}lib ${ROOTDIR}etc ${ROOTDIR}var \
${findargs} \( -name "tcp.log" -o -name ".linux-sniff" -o -name "sniff-l0g" -o -name "core_" \) \
2>/dev/null`
if [ "${files}" = "" ]
then
  if [ "${QUIET}" != "t" ]; then echo "nothing found"; fi
else
  echo
  echo ${files}
fi

查找可疑的php文件

查找一些可疑的php文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
###
### Suspect PHP files
###
if [ "${QUIET}" != "t" ]; then
    printn "Searching for suspect PHP files... "; fi
    files="`${find} ${ROOTDIR}tmp ${ROOTDIR}var/tmp ${findargs} -name '*.php' 2> /dev/null`"
if [ `echo abc | head -n 1` = "abc" ]; then
    fileshead="`${find} ${ROOTDIR}tmp ${ROOTDIR}var/tmp ${findargs} -type f -exec head -n 1 {} \; | $egrep '#!.*php' 2> /dev/null`"
else
    fileshead="`${find} ${ROOTDIR}tmp ${ROOTDIR}var/tmp ${findargs} -type f -exec head -1 {} \; | grep '#!.*php' 2> /dev/null`"
fi
if [ "${files}" = "" -a "${fileshead}" = "" ]; then
    if [ "${QUIET}" != "t" ]; then echo "nothing found"; fi
else
     echo
     echo "${files}"
     echo "${fileshead}"
fi

检测.history文件

看看history有没有被清空了,或者软连接到其他地方了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if [ "${QUIET}" != "t" ]; then \
      printn "Searching for anomalies in shell history files... "; fi
   files=""
   if [ ! -z "${SHELL}" -a ! -z "${HOME}" ]; then
      files=`${find} ${ROOTDIR}${HOME} ${findargs} -name '.*history' -size 0`
      [ ! -z "${files}" ] && \
        echo "Warning: \`${files}' file size is zero"
      files1=`${find} ${ROOTDIR}${HOME} ${findargs} -name '.*history' \( -links 2 -o -type l \)`
      [ ! -z "${files1}" ] && \
        echo "Warning: \`${files1}' is linked to another file"
   fi
   if [ -z "${files}" -a -z "${files1}" ]; then
      if [ "${QUIET}" != "t" ]; then echo "nothing found"; fi
   fi

检测有无程序监听了一些可疑的端口

检测代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
bindshell () {
PORT="114|145|465|511|600|1008|1524|1999|1978|2881|3049|3133|3879|4000|4369|5190|5665|6667|10008|12321|23132|27374|29364|30999|31336|31337|37998|45454|47017|47889|60001|7222"
   OPT="-an"
   PI=""
   if [ "${ROOTDIR}" != "/" ]; then
     echo "not tested"
     return ${NOT_TESTED}
   fi

   if [ "${EXPERT}" = "t" ]; then
       expertmode_output "${netstat} ${OPT}"
       return 5
   fi
   for P in `echo $PORT | ${sed} 's/|/ /g'`; do
      if ${netstat} "${OPT}" | ${egrep} "^tcp.*LIST|^udp" | ${egrep} \
"[.:]${P}[^0-9.:]" >/dev/null 2>&1
      then
         PI="${PI} ${P}"
      fi
   done
   if [ "${PI}" != "" ]
   then
      echo "INFECTED PORTS: ($PI)"
   else
      if [ "${QUIET}" != "t" ]; then echo "not infected"; fi
   fi
}

检测Linux可加载内核模块

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
lkm ()
{
    prog=""
    if [  \( "${SYSTEM}" = "Linux"  -o \( "${SYSTEM}" = "FreeBSD" -a \
       `echo ${V} | ${awk} '{ if ($1 > 4.3 || $1 < 6.0) print 1; else print 0 }'` -eq 1 \) \) -a "${ROOTDIR}" = "/" ]; then
      [  -x ./chkproc -a "`find /proc | wc -l`" -gt 1 ] && prog="./chkproc"
      [  -x ./chkdirs ] && prog="$prog ./chkdirs"
      if [ "$prog" = "" ]; then
         echo "not tested: can't exec $prog"
         return ${NOT_TESTED}
      fi

      if [ "${EXPERT}" = "t" ]; then
         [ -r /proc/$KALLSYMS ] &&  ${egrep} -i "adore|sebek" < /proc/$KALLSYMS 2>/dev/null
         [ -d /proc/knark ] &&  ${ls} -la /proc/knark 2> /dev/null
         PV=`$ps -V 2>/dev/null| $cut -d " " -f 3 |${awk} -F . '{ print $1 "." $2 $3 }' | ${awk} '{ if ($0 > 3.19) print 3; else if ($0 < 2.015) print 1; else print 2 }'`
         [ "$PV" = "" ] &&  PV=2
         [ "${SYSTEM}" = "SunOS" ] && PV=0
         expertmode_output "./chkproc -v -v -p $PV"
         return 5
      fi

      ### adore LKM
      [ -r /proc/$KALLSYMS ] && \
      if `${egrep} -i adore < /proc/$KALLSYMS >/dev/null 2>&1`; then
         echo "Warning: Adore LKM installed"
      fi

      ### sebek LKM (Adore based)
      [ -r /proc/$KALLSYMS ] && \
      if `${egrep} -i sebek < /proc/$KALLSYMS >/dev/null 2>&1`; then
         echo "Warning: Sebek LKM installed"
      fi

      ### knark LKM
      if [ -d /proc/knark ]; then
         echo "Warning: Knark LKM installed"
      fi

      PV=`$ps -V 2>/dev/null| $cut -d " " -f 3 |${awk} -F . '{ print $1 "." $2 $3 }' | ${awk} '{ if ($0 > 3.19) print 3; else if ($0 < 2.11) print 1; else print 2 }'`
      [ "$PV" = "" ] &&  PV=2
      [ "${SYSTEM}" = "SunOS" ] && PV=0
      if [ "${DEBUG}" = "t" ]; then
           ${echo} "*** PV=$PV ***"
      fi
      if ./chkproc -p ${PV}; then
         if [ "${QUIET}" != "t" ]; then echo "chkproc: nothing detected"; fi
      else
         echo "chkproc: Warning: Possible LKM Trojan installed"
      fi
      dirs="/tmp"
      for i in /usr/share /usr/bin /usr/sbin /lib; do
         [ -d $i ] && dirs="$dirs $i"
      done
      if ./chkdirs $dirs;  then
         if [ "${QUIET}" != "t" ]; then echo "chkdirs: nothing detected"; fi
      else
	    echo "chkdirs: Warning: Possible LKM Trojan installed"
      fi
   else
         if [ "${QUIET}" != "t" ]; then echo "chkproc: not tested"; fi
   fi
}

loadable kernel module (LKM),这个是检测内核模块的 ,看看有无adore,sebek这些内核模块

之后调用chkproc,chkdirs进行检测,这两个下面检测有无隐藏进程,会说到

检测有无隐藏进程

这个代码在chkproc.c中,它通过暴力递归,看看有没有/proc目录存在,而ps查不出来的进程,那么就说明有进程隐藏了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 /* Brute force */
   strcpy(buf, "/proc/");
   retps = retdir = 0;
   for (i = FIRST_PROCESS; i <= MAX_PROCESSES; i++)
   {
      // snprintf(&buf[6], 6, "%d", i);
       snprintf(&buf[6], 8, "%d", i);
      if (!chdir(buf))
      {
         if (!dirproc[i] && !psproc[i])
         {
#if defined(__linux__)
            if (!isathread[i]) {
#endif
            retdir++;
            if (verbose)
	       printf ("PID %5d(%s): not in readdir output\n", i, buf);
#if defined(__linux__)
            }
#endif
         }
         if (!psproc[i] ) /* && !kill(i, 0)) */
         {
#if defined(__linux__)
            if(!isathread[i]) {
#endif
            retps++;
            if (verbose)
	       printf ("PID %5d: not in ps output\n", i);
#if defined(__linux__)
            }
#endif
	 }

检测目录的软链接异常

chkdirs比较的是父目录的软链接数和子目录的个数

正常情况下,父目录的软链接数 = 子目录的个数 + 2

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (!linkcount) {
    if (lstat(".", &statinfo)) {
      fprintf(stderr, "lstat(%s): %s\n", fullpath, strerror(errno));
      goto abort;
    }
    linkcount = statinfo.st_nlink;   //获取符号链接数
  }

  if (!(dirhandle = opendir("."))) {
    fprintf(stderr, "opendir(%s): %s\n", fullpath, strerror(errno));
    goto abort;
  }

  numdirs = 0;
  dl = (struct dirinfolist *)NULL;
  while ((finfo = readdir(dirhandle))) {
    if (!strcmp(finfo->d_name, ".") || !strcmp(finfo->d_name, ".."))
      continue;

    if (lstat(finfo->d_name, &statinfo)) {
      fprintf(stderr, "lstat(%s/%s): %s\n",
	      fullpath, finfo->d_name, strerror(errno));
      closedir(dirhandle);
      goto abort;
    }

    if (S_ISDIR(statinfo.st_mode)) {    //判断是否是目录
      numdirs++;

      if (norecurse) continue;               /* just count subdirs if "-n" */

      /* Otherwise, keep a list of all directories found that have link
	 count > 2 (indicating directory contains subdirectories).  We'll
	 call check_dir() on each of these subdirectories in a moment...
      */
      if (statinfo.st_nlink > 2) {
	dptr = dl;
	if (!(dl = (struct dirinfolist *)malloc(sizeof(struct dirinfolist)))) {
	  fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
	  norecurse = 1;
	  while (dptr) {
	    dl = dptr->dil_next;
	    free((void *)dptr);
	    dptr = dl;
	  }
	  continue;
	}

	strncpy(dl->dil_name, finfo->d_name, sizeof(dl->dil_name));
	dl->dil_lc = statinfo.st_nlink;
	dl->dil_next = dptr;
      }
    }
  }
  closedir(dirhandle);

  /* Parent directory link count had better equal #subdirs+2... */
  diff = linkcount - numdirs - 2;     //
  if (diff) printf("%d\t%s\n", diff, fullpath);

检测网络接口的异常

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 sniffer () {
    if [ "${ROOTDIR}" != "/" ]; then
      echo "not tested"
      return ${NOT_TESTED}
    fi

    if [ "$SYSTEM" = "SunOS" ]; then
       return ${NOT_TESTED}
    fi

    if [ "${EXPERT}" = "t" ]; then
        expertmode_output "./ifpromisc" -v
        return 5
    fi
    if [ ! -x ./ifpromisc ]; then
      echo "not tested: can't exec ./ifpromisc"
      return ${NOT_TESTED}
    else
      [ "${QUIET}" != "t" ] && ./ifpromisc -v || ./ifpromisc -q
    fi
}

这个是对网络接口的检测,看看有无开启网卡混杂模式(英语:promiscuous mode)

而PF_PACKET可以操作链路层的数据,可以读取和发送链路层的数据包

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 ./ifpromisc -v
ens3: PF_PACKET(/sbin/dhclient)
virbr0: not promisc and no PF_PACKET sockets
docker0: not promisc and no PF_PACKET sockets
br-47a3d838588a: not promisc and no PF_PACKET sockets

检测用户的登录日志

检测用户的登录相关的log文件

SunOS使用的是check_wtmpx,比较的文件是/var/adm/wtmp,/var/adm/wtmpx,check_wtmpx部分代码,比较这两个文件的一些差异,比如下面的比较uid

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if ( memcmp( utmp_entry.ut_id, utmpx_entry.ut_id, 4 ) != 0 )
{
    fprintf( stderr, "[ %u ] utmp_entry.ut_id != utmpx_entry.ut_id\n", wtmp_read_counter );
    break;
}

其他linux检测的是var/log/wtmp或者var/adm/wtmp chkwtmp部分代码,查看有无删除了登录时间

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gettimeofday(&mytime, &dummy);
       act_time=mytime.tv_sec;
       wtmpfile[127]='\0';
       memcpy(wtmpfile, WTMP_FILENAME, 127);
       if ( argc == 3 && !memcmp("-f", argv[1], 2) && *argv[2])
          memcpy(wtmpfile, argv[2], 127);

	if ((filehandle=open(wtmpfile,O_RDONLY)) < 0) {
		fprintf(stderr, "unable to open wtmp-file %s\n", wtmpfile);
		return(2);
	}

	while (read (filehandle, (char *) &utmp_ent, sizeof (struct utmp)) > 0) {
		if (utmp_ent.ut_time == 0)
			del_counter++;
		else {
			if (del_counter) {
				printit(del_counter, start_time,
					utmp_ent.ut_time);
				t_del++;
				del_counter=0;
			}
			start_time=utmp_ent.ut_time;
		}
	}
	close(filehandle);
	if (del_counter)
	   printit(del_counter, start_time, act_time);
        exit((int) t_del+del_counter);

检测上一次登录

使用chklastlog程序检测,下面是部分代码,用户的数据通过getpwent函数获取,其实就是通过/etc/passwd获取,检测基于两点

1、通过比较MAX_ID,与当前的遍历的用户的id,看看id是否大于环境变量MAX_ID 2、看看是否有这样的情况:用户名出现在lastlog,wtmp文件中,而在/etc/passwd中没有的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if ( !nonuser(utmp_ent) && strncmp(utmp_ent.ut_line, "ftp", 3) &&
	 (uid=localgetpwnam(localpwd,utmp_ent.ut_name)) != NULL )
		{
			if (*uid > MAX_ID)
			{
			   fprintf(stderr, "MAX_ID is %ld and current uid is %ld, please check\n\r", MAX_ID, *uid );
			   exit (1);

			}
	if (!userid[*uid])
			{
		lseek(fh_lastlog, (long)*uid * sizeof (struct lastlog), 0);
		if ((wtmp_bytes_read = read(fh_lastlog, &lastlog_ent, sizeof (struct lastlog))) > 0)
				{
					if (wtmp_bytes_read < sizeof(struct lastlog))
					{
					   fprintf(stderr, "lastlog entry may be corrupted");
					   break;
					}
					if (lastlog_ent.ll_time == 0)
					{
					   if (-1 != (slot = getslot(localpwd, *uid)))
						   printf("user %s deleted or never logged from lastlog!\n",
							NULL != localpwd->uname[slot] ?
							(char*)localpwd->uname[slot] : "(null)");
					   else
						  printf("deleted user uid(%d) not in passwd\n", *uid);
					   ++status;
					}
					userid[*uid]=TRUE;
				}
	}
	   }
}

检测可疑的没有tty记录的进程

检测的是/var/run/utmp或者/var/adm/utmpx,方法是比较的是ps命令与/var/run/utmp文件之间的差别

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
y = fetchps(ps_l);
z = fetchutmp(ut_l);
hdr_prntd = 0;
for (h = 0; h < y; h++) {	/* loop through 'ps' data */
mtch_fnd = 0;
for (i = 0; i < z; i++) {	/* try and match the tty from 'ps' to one in utmp */
	if (ut_l[i].ut_type == LOGIN_PROCESS	/* ignore getty processes with matching pid from 'ps' */
	&& ut_l[i].ut_pid == ps_l[h].ps_pid)
   {
	mtch_fnd = 1;
		break;
	   }
	else if (strncmp(ps_l[h].ps_tty, ut_l[i].ut_tty,	/* compare the tty's */
			 strlen(ps_l[h].ps_tty)) == 0)
	{
	mtch_fnd = 1;
		break;
	}
}
if (!mtch_fnd) {
	if (!hdr_prntd) {
	printf
		(" The tty of the following user process(es) were not found\n");
	printf(" in %s !\n", UTMP);
	printf("! %-9s %7s %-6s %s\n", "RUID", "PID", "TTY",
		   "CMD");
	hdr_prntd = 1;
	}
	printf("! %-9s %7d %-6s %s", ps_l[h].ps_user,
	   ps_l[h].ps_pid, ps_l[h].ps_tty, ps_l[h].ps_args);
}

比如下面的检测结果,而我的/var/run/utmp中是没有tty7这个tty的记录的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Checking `chkutmp'...  The tty of the following user process(es) were not found
 in /var/run/utmp !
! RUID          PID TTY    CMD
! root         1076 tty7   /usr/lib/xorg/Xorg -core :0 -seat seat0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-10-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
渗透测试TIPS之删除、伪造Linux系统登录日志
0x00. 引言 擦除日志在渗透测试中是非常重要的一个阶段,这样可以更好地隐藏入侵痕迹,做到不被系统管理人员察觉,实现长期潜伏的目的。 前段时间NSA泄露的渗透测试工具中就有一款wtmp日志的擦除,非常好用,这引起了我的兴趣,于是研究了一下linux 登录相关二进制日志的文件格式,用python写了一个日志擦除,伪造的工具(末尾附源码) 0x01. Linux中与登录有关的日志及其格式分析 Linux中涉及到登录的二进制日志文件有 /var/run/utmp /var/log/wtmp
FB客服
2018/02/28
3.1K0
渗透测试TIPS之删除、伪造Linux系统登录日志
[ffffffff0x] 蓝队视角下Linux信息收集
上一篇 红队视角下Linux信息收集 我们谈到红队是以提权和后渗透为主要目的而进行的信息收集,本次谈一谈在蓝队应急响应中Linux系统下比较关键的内容。
r0fus0d
2020/12/22
9240
[ffffffff0x] 蓝队视角下Linux信息收集
怒怼黑客,Linux 下的7个开源安全工具
https://www.tecmint.com/best-antivirus-programs-for-linux/
CSDN技术头条
2018/07/30
4.6K0
怒怼黑客,Linux 下的7个开源安全工具
应急响应笔记之Linux篇
整理下自己之前做的应急响应相关的碎片笔记,太多了,没办法全部列出来,先整理一些常用的。
瓦都剋
2020/08/07
1.1K0
Linux - last 命令
直接用 last -f 好像并不会显示信息,应该是因为读取的文件的数据结构不一致的原因
小菠萝测试笔记
2021/06/10
1.6K0
【权限维持】Linux&Rootkit后门&Strace监控&Alias别名&Cron定时任务
利用系统的定时任务功能进行反弹Shell 1、编辑后门反弹 vim /etc/.backshell.sh
没事就要多学习
2024/07/18
2410
【权限维持】Linux&Rootkit后门&Strace监控&Alias别名&Cron定时任务
Linux入侵小结
Linux不同的用户,有不同的操作权限,但是所有用户都会在/etc/passwd /etc/shadow /etc/group /etc/group- 文件中记录;
网e渗透安全部
2019/08/15
2.2K0
linux应急常用命令+技巧总结
检查最近创建的php、jsp文件和上传目录 例如要查找24小时内被修改的JSP文件:
drunk_kk
2021/03/23
1.3K0
linux应急常用命令+技巧总结
[GET!] 6个Linux痕迹隐藏小技巧!
-T表示不分配伪终端,/usr/bin/bash 表示在登录后调用bash命令 -i 表示是交互式shell
drunk_kk
2021/03/23
3.9K0
[GET!] 6个Linux痕迹隐藏小技巧!
Linux下的8个开源安全工具,再也不怕黑客啦
在计算机的发展史上,恶意软件和病毒攻击层出不穷。Linux的安全问题始终未能在大众范围里引起注意。但对于专业人士而言,Linux系统上的攻击虽然隐藏在水面之下,威胁却与日俱增。
小小科
2018/07/31
2.1K0
​安全测试笔记《十六》——后渗透-痕迹清理
有时我们登陆到服务器,对它的⽂件进行了修改,修改后的⽂件的时间戳会更新到最新的时间,那么这样就会引起管理员的注意。 因此我们需要吧那个⽂件的时间戳给修改成其他时间。
顾翔
2022/09/23
7620
​安全测试笔记《十六》——后渗透-痕迹清理
Linux应急响应笔记
连接到服务器,首先通过ps auxef 和 netstat -tulnp两个命令查看异常进程信息,果然发现了两个异常进程 xmp 和 [atd]
黑战士
2022/11/19
1.4K0
Linux手工入侵排查思路
当Linux主机发生安全事件需要进行入侵排查时,一般可以使用常见的shell命令,通过分析主机的异常现象、进程端口、启动方式、可疑文件和日志记录等信息以确认主机是否被入侵。
Bypass
2021/04/26
1.8K0
Some Linux Hacking Tricks
There is always a method here is useful for you to penetrantion testing :) Some ways to read system files 1cat /etc/issue 2tac /etc/issue 3less /etc/issue 4more /etc/issue 5head /etc/issue 6tail /etc/issue 7nl /etc/issue 8xxd /etc/issue 9sort /et
xfkxfk
2018/05/15
8720
linux检测系统是否被入侵(下)
原文链接:https://rumenz.com/rumenbiji/linux-hacking-2.html
入门笔记
2021/11/13
2K0
护网Linux应急处置操作手册-Tools篇
HVV行动已经进行到了11天,处置的工作明显增多,随着各种情况发生,所以这两天分别整理一些关于Linux和Windows的排查手册。
Khan安全团队
2020/09/27
4.7K0
护网Linux应急处置操作手册-Tools篇
Linux 入侵痕迹清理技巧
在攻击结束后,如何不留痕迹的清除日志和操作记录,以掩盖入侵踪迹,这其实是一个细致的技术活。你所做的每一个操作,都要被抹掉;你所上传的工具,都应该被安全地删掉。
Bypass
2020/09/16
4.1K0
centos7主机安全检测脚本和初始化脚本
# 一、主机安全检查脚本 #!/bin/bash ##Filename: CentOS_Check_Script.sh ##Description: Security detection script echo "##########################################################################" echo "#
章工运维
2023/05/19
7720
[apue] Unix 系统数据文件那些事儿
Unix like 系统和 windows 的最大区别就是有一套标准的系统信息数据文件,一般存放在 /etc/ 目录下,并且提供了一组近似的接口访问和查询信息,这些基础设施让系统管理看起来井井有条,下面就来盘点一下。
海海
2023/01/10
3.2K0
linux 溯源命令集合-主机层(持续更新)
记录一些在攻击溯源中常用到的溯源命令,持续更新: linux主机层溯源常用命令: scp远程上传: scp my_local_file.zip root@192.168.1.104:/usr/local/nginx/html/webs scp远程下载: scp root@192.168.1.104:/usr/local/nginx/html/webs/about.zip . 查看root用户历史操作命令: history 查看当前用户与他运行的进程信息 w 查看当前登录的用户,默认输出用户名,终端类
枪哥四海为家
2021/01/25
3.1K0
相关推荐
渗透测试TIPS之删除、伪造Linux系统登录日志
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验