authorized_keys无法删除(chattr命令被篡改)

1 authorized_keys 免密

我们需要本地机器ssh访问远程服务器时为了减少输入密码的步骤,基本上都会在本地机器生成ssh公
钥,然后将本地ssh公钥复制到远程服务器的.ssh/authorized_keys中,这样就可以免密登录了。

ssh-copy-id -i root@ip_address
ssh-keygen -t rsa
一路回车,完成后会在目录/root/.ssh下面生成文件 id_rsa和id_rsa.pub
将公钥写入文件authorized_keys:cat id_rsa.pub >> authorized_keys
ssh-copy-id -i ~/.ssh/id_rsa.pub root@ip

chmod 600 authorized_keys 设置.ssh目录权限 chmod 700 -R .ssh
要保证.ssh和authorized_keys都只有用户自己有写权限。否则验证无效。

2 known_hosts

第一次连接远程数据库时我们可以发现我们本地的.ssh/目录下多了一个文件known_hosts,里面有我
们刚刚连接的服务器的信息(如果以前就存在known_hosts,则会发现多了刚刚连接的服务器的信
息)。
known_hosts文件每连接一个新的远程服务器都会产生一份数据,如下:

0.0.0.0 ecdsa-sha2-nistp256 AAAA...........=

包括远程机器ip、远程机器公钥
known_hosts有什么用?
手动修改一下远程机器A的密钥,然后再连接远程机器A,提示:

The authenticity of host '0.0.0.0 (0.0.0.0)' can't be established.
ECDSA key fingerprint is SHA256:xxxxxxxx.
Are you sure you want to continue connecting (yes/no)?
得到类似这种提示,大概意思就是登录远程机器A验证失败,然后向你确定是否需要继续连接。

known_hosts的作用就很明显了,known_hosts的作用就是记录你曾经远程连接过的机器信息。如果远程机器信息不变,则直接连接,如果改变了ssh就会问你一下,小子,你还连不连了?
如果你yes, 他就重新保存一份到known_hosts文件了。

3 删除authorized_keys文件

[root@VM-24-16-centos .ssh]# ls
authorized_keys  authorized_keys2
[root@VM-24-16-centos .ssh]# rm -rf *
rm: cannot remove ‘authorized_keys’: Operation not permitted
rm: cannot remove ‘authorized_keys2’: Operation not permitted
[root@VM-24-16-centos .ssh]# lsattr authorized_keys
----ia-------e-- authorized_keys
[root@VM-24-16-centos .ssh]# chattr -i authorized_keys
-bash: chattr: command not found

i : 用chattr命令防止系统中某个关键文件被修改
e: 让某个文件只能往里面追加数据,但不能删除,适用于各种日志文件
这两个命令在使用上必须要特别小心,否则会造成很大的困扰。例如:某天你心情好,突然将 /etc/shadow 这个重要的密码记录文件给他配置成为具有 i 的属性,那么过了若干天之后, 你突然要新增使用者,却一直无法新增!别怀疑,赶快去将 i 的属性拿掉吧!

4 解决方案:

1.先查看chattr命令,即查看e2fsprogs包
查看e2fsprogs包是否存在(可能会显示存在,但还是依旧无法使用chattr命令)
rpm -qa|grep e2fsprogs
2.下载chattr命令
执行下载命令(可能会显示e2fsprogs已经被安装了,但是依旧无法使用chattr命令)
yum install e2fsprogs
如果还是无法使用,那我们就使用上一步查询到的具体的e2fsprogs包名就可以安装成功!
yum install e2fsprogs-1.42.9-19.el7.x86_64

如果还不行
chattr文件被替换了,chattr命令也就失效了。并且这个文件还被设置了隐藏属性i,导致无法修改,无法删除。也就无法通过e2fsprogs来重新安装chattr命令。

最后编译源码 chattr.c
gcc chattr.c -o mychattr.out
./chattr_aaaa.out -ia authorized_keys

chattr 源码 :https://github.com/posborne/linux-programming-interface-exercises/blob/master/15-file-attributes/chattr.c

chattr.c

/*
Name
----
chattr - change file attributes on a Linux file system
Synopsis
--------
chattr [ mode ] files...
Description
-----------
chattr changes the file attributes on a Linux file system.  The format
of a symbolic mode is +-=[acdeijstuADST].
The operator '+' causes the selected attributes to be added to the
existing attributes of the files; '-' causes them to be removed; and
'=' causes them to be the only attributes that the files have.
The letters 'acdeijstuADST' select the new attributes for the files:
append only (a), compressed (c), no dump (d), extent format (e),
immutable (i), data journalling (j), secure deletion (s), no
tail-merging (t), undeletable (u), no atime updates (A), synchronous
directory updates (D), synchronous updates (S), and top of directory
hierarchy (T).
The following attributes are read-only, and may be listed by lsattr(1)
but not modified by chattr: huge file (h), compression error (E),
indexed directory (I), compression raw access (X), and compressed
dirty file (Z).
Attributes
----------
When a file with the 'A' attribute set is accessed, its atime record
is not modified. This avoids a certain amount of disk I/O for laptop
systems.  A file with the 'a' attribute set can only be open in append
mode for writing. Only the superuser or a process possessing the
CAP_LINUX_IMMUTABLE capability can set or clear this attribute.
A file with the 'c' attribute set is automatically compressed on the
disk by the kernel. A read from this file returns uncompressed data. A
write to this file compresses data before storing them on the
disk. Note: please make sure to read the bugs and limitations section
at the end of this document.
When a directory with the 'D' attribute set is modified, the changes
are written synchronously on the disk; this is equivalent to the
'dirsync' mount option applied to a subset of the files.
A file with the 'd' attribute set is not candidate for backup when the
dump(8) program is run.
The 'E' attribute is used by the experimental compression patches to
indicate that a compressed file has a compression error. It may not be
set or reset using chattr(1), although it can be displayed by
lsattr(1).
The 'e' attribute indicates that the file is using extents for mapping
the blocks on disk. It may not be removed using chattr(1).
The 'I' attribute is used by the htree code to indicate that a
directory is being indexed using hashed trees. It may not be set or
reset using chattr(1), although it can be displayed by lsattr(1).
The 'h' attribute indicates the file is storing its blocks in units of
the filesystem blocksize instead of in units of sectors, and means
that the file is (or at one time was) larger than 2TB. It may not be
set or reset using chattr(1), although it can be displayed by
lsattr(1).
A file with the 'i' attribute cannot be modified: it cannot be deleted
or renamed, no link can be created to this file and no data can be
written to the file. Only the superuser or a process possessing the
CAP_LINUX_IMMUTABLE capability can set or clear this attribute.
A file with the 'j' attribute has all of its data written to the ext3
journal before being written to the file itself, if the filesystem is
mounted with the "data=ordered" or "data=writeback" options. When the
filesystem is mounted with the "data=journal" option all file data is
already journalled and this attribute has no effect. Only the
superuser or a process possessing the CAP_SYS_RESOURCE capability can
set or clear this attribute.
When a file with the 's' attribute set is deleted, its blocks are
zeroed and written back to the disk. Note: please make sure to read
the bugs and limitations section at the end of this document.
When a file with the 'S' attribute set is modified, the changes are
written synchronously on the disk; this is equivalent to the 'sync'
mount option applied to a subset of the files.
A directory with the 'T' attribute will be deemed to be the top of
directory hierarchies for the purposes of the Orlov block
allocator. This is a hint to the block allocator used by ext3 and ext4
that the subdirectories under this directory are not related, and thus
should be spread apart for allocation purposes. For example it is a
very good idea to set the 'T' attribute on the /home directory, so
that /home/john and /home/mary are placed into separate block
groups. For directories where this attribute is not set, the Orlov
block allocator will try to group subdirectories closer together where
possible.
A file with the 't' attribute will not have a partial block fragment
at the end of the file merged with other files (for those filesystems
which support tail-merging). This is necessary for applications such
as LILO which read the filesystem directly, and which don't understand
tail-merged files. Note: As of this writing, the ext2 or ext3
filesystems do not (yet, except in very experimental patches) support
tail-merging.
When a file with the 'u' attribute set is deleted, its contents are
saved. This allows the user to ask for its undeletion. Note: please
make sure to read the bugs and limitations section at the end of this
document.
The 'X' attribute is used by the experimental compression patches to
indicate that a raw contents of a compressed file can be accessed
directly. It currently may not be set or reset using chattr(1),
although it can be displayed by lsattr(1).
The 'Z' attribute is used by the experimental compression patches to
indicate a compressed file is dirty. It may not be set or reset using
chattr(1), although it can be displayed by lsattr(1).
*/
#include <fcntl.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/fs.h>

#define ACTION_ADD     '+'
#define ACTION_REMOVE  '-'
#define ACTION_ONLY    '='

#define ATTRS_LIST                      "acdeijstuADT"
#define ATTR_APPEND_ONLY                'a'
#define ATTR_COMPRESSED                 'c'
#define ATTR_NO_DUMP                    'd'
#define ATTR_EXTENT_FORMAT              'e'
#define ATTR_IMMUTABLE                  'i'
#define ATTR_JOURNALLING                'j'
#define ATTR_SECURE_DELETE              's'
#define ATTR_NO_TAIL_MERGE              't'
#define ATTR_UNDELETABLE                'u'
#define ATTR_NO_ATIME_UPDATES           'A'
#define ATTR_SYNCHRONOUS_DIR_UPDATES    'D'
#define ATTR_TOP_OF_DIRECTORY_HIERARCHY 'T'

#define LIST_LENGTH(x) ((sizeof(x) / sizeof(x[0])))

struct attr_table_entry {
	char code;
	int fs_flag;
};

static struct attr_table_entry fs_attrs[] = {
	{ATTR_APPEND_ONLY, FS_APPEND_FL},
	{ATTR_COMPRESSED, FS_COMPR_FL},
	{ATTR_NO_DUMP, FS_NODUMP_FL},
	{ATTR_EXTENT_FORMAT, FS_EXTENT_FL},
	{ATTR_IMMUTABLE, FS_IMMUTABLE_FL},
	{ATTR_JOURNALLING, FS_JOURNAL_DATA_FL},
	{ATTR_SECURE_DELETE, FS_SECRM_FL},
	{ATTR_NO_TAIL_MERGE, FS_NOTAIL_FL},
	{ATTR_UNDELETABLE, FS_UNRM_FL},
	{ATTR_NO_ATIME_UPDATES, FS_NOATIME_FL},
	{ATTR_SYNCHRONOUS_DIR_UPDATES, FS_DIRSYNC_FL},
	{ATTR_TOP_OF_DIRECTORY_HIERARCHY, FS_TOPDIR_FL},
};


static void
print_usage()
{
	fprintf(stderr, "Usage: ./prog_chattr [mode] files\n");
	exit(EXIT_FAILURE);
}


static struct attr_table_entry*
lookup_attr_table_entry(char attr)
{
	struct attr_table_entry *entry;
	unsigned long i;
	for (i = 0; i < LIST_LENGTH(fs_attrs); i++) {
		entry = &fs_attrs[i];
		if (entry->code == attr) {
			return entry;
		}
	}
	return NULL;
}


static bool
is_valid_attr(char attr)
{
	char c;
	int i = 0;
	while ((c = ATTRS_LIST[i++]) != '\0') {
		if (c == attr) {
			return true;
		}
	}
	return false;
}


static void
validate_mode_string(char *mode_string) {
	int len;
	char attr;
	int i;
	len = strlen(mode_string);
	if (len < 2) {
		fprintf(stderr, "ERROR: Invalid mode string specified (too short)\n");
		print_usage();
	}
	i = 1;
	while ((attr = mode_string[i++]) != '\0') {
		if (!is_valid_attr(attr)) {
			fprintf(stderr, "ERROR: Attribute '%c' is invalid\n", attr);
			print_usage();
		}
	}
}


static int
get_mask_for_attrs(char *attrs)
{
	int mask;
	int i;
	char attr;
	struct attr_table_entry *entry;

	i = 0;
	mask = 0;
	while ((attr = attrs[i++]) != '\0') {
		entry = lookup_attr_table_entry(attr);
		if (entry == NULL) {
			/* we should have already validated */
			fprintf(stderr, "ERROR: Invalid Attr '%c'\n", attr);
			exit(EXIT_FAILURE);
		}
		mask |= (entry->fs_flag);
	}
	return mask;
}


static int
transform_attrs_add(int attrs, int mask)
{
	return (attrs | mask);
}


static int
transform_attrs_remove(int attrs, int mask)
{
	/* 
	 * To ensure that the new attrs does not have any of the bits
	 * from mask set, we take the inverse of the mask and and it
	 * with the current attrs
	 */
	int reversed_mask;
	int new_attrs;
	reversed_mask = ~mask;
	new_attrs = (attrs & reversed_mask);
	return new_attrs;
}


static int
transform_attrs_only(int attrs, int mask)
{
	return mask; /* In this case, just use the mask */
}


static int
do_action(char *attrs, int file_count, char **files, int(*transform_attrs)(int, int))
{
	int mask;
	int i;
	size_t fd;
	char *filename;
	int current_attrs;
	int new_attrs;

	/* get mask for our attributes */
	mask = get_mask_for_attrs(attrs);

	/* Do the update on each file */
	for (i = 0; i < file_count; i++) {
		filename = files[i];
		fd = open(filename, 0);
		if (fd < 0) {
			fprintf(stderr, "ERROR: Unable to open %s, skipping\n", filename);
			continue;
		}

		/* Get the current flags */
		if (ioctl(fd, FS_IOC_GETFLAGS, &current_attrs) == -1) {
			fprintf(stderr, "ERROR: Unable to get flags on %s, skipping\n", filename);
			goto cleanup;
		}
		printf("cur attrs: 0x%08x, mask: 0x%08X\n", current_attrs, mask);
		new_attrs = transform_attrs(current_attrs, mask); /* enable all flags in mask */
		printf("new attrs: 0x%08X\n", new_attrs);
		if (ioctl(fd, FS_IOC_SETFLAGS, &new_attrs) == -1) {
			fprintf(stderr, "ERROR: Unable to set flags on %s, skipping\n", filename);
		}
cleanup:
		close(fd);
	}
	return 0;
}


int main(int argc, char **argv)
{
	int file_count = 0;
	char *mode_string;
	char *attrs;
	char action;
	if (argc < 3) {
		print_usage();
	}
	mode_string = argv[1];
	file_count = argc - 2;
	validate_mode_string(mode_string);
	action = mode_string[0];
	attrs = &mode_string[1];
	switch (action) {
	case ACTION_ADD:
		return do_action(attrs, file_count, &argv[2], transform_attrs_add);
		break;
	case ACTION_REMOVE:
		return do_action(attrs, file_count, &argv[2], transform_attrs_remove);
		break;
        case ACTION_ONLY:
		return do_action(attrs, file_count, &argv[2], transform_attrs_only);
		break;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值