Info: Version 1.8.x is available.
Last modified: $Date: 2024-03-30 11:25:00 +0000 (Sat, 30 Mar 2024) $
このページでは、SSHのログインセッションで行われた操作内容を記録する手順について紹介します。
以下のソースコードをコンパイルします。このページでは、コンパイルされたプログラムの名前を /bin/record_cmdline とします。また、SSHサーバのパス名を /usr/sbin/sshd とします。また、ログインシェルのパス名を /bin/bash とします。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
static void encode(char *buffer, const char *string)
{
while (1) {
const unsigned char c = *(const unsigned char *) string++;
if (!c)
break;
else if (c == '\\') {
*buffer++ = '\\';
*buffer++ = '\\';
} else if (c > 32 && c < 127)
*buffer++ = c;
else {
*buffer++ = '\\';
*buffer++ = '0' + (c >> 6);
*buffer++ = '0' + ((c >> 3) & 7);
*buffer++ = '0' + (c & 7);
}
}
}
int main(int raw_argc, char *raw_argv[])
{
int i;
int argc;
int envc;
char *filename;
char **argv;
char **envp;
{ /* Check that I'm an execute handler process. */
int fd = open("/proc/ccs/.execute_handler", O_RDONLY);
close(fd);
if (fd == EOF) {
fprintf(stderr, "FATAL: I'm not execute_handler.\n");
return 1;
}
}
if (raw_argc < 7)
return 1;
filename = raw_argv[4];
argc = atoi(raw_argv[5]);
envc = atoi(raw_argv[6]);
if (raw_argc != argc + envc + 7)
return 1;
for (i = 5; i < argc + 5; i++)
raw_argv[i] = raw_argv[i + 2];
raw_argv[argc + 5] = NULL;
for (i = argc + 6; i < argc + envc + 6; i++)
raw_argv[i] = raw_argv[i + 1];
raw_argv[argc + envc + 6] = NULL;
argv = raw_argv + 5;
envp = raw_argv + argc + 6;
{ /* Record parameters including argv[] and envp[]. */
/* Get exlusive lock for serializing syslog(). */
const int fd = open("/proc/self/exe", O_RDONLY);
if (fd == EOF || flock(fd, LOCK_EX) == EOF)
return 1;
openlog(raw_argv[0], LOG_NDELAY, LOG_USER);
syslog(LOG_INFO, "Domain = %s\n", raw_argv[1]);
syslog(LOG_INFO, "Caller Program = %s\n", raw_argv[2]);
syslog(LOG_INFO, "Process Status = %s\n", raw_argv[3]);
syslog(LOG_INFO, "Requested Program = %s\n", filename);
syslog(LOG_INFO, "argc=%d\n", argc);
syslog(LOG_INFO, "envc=%d\n", envc);
for (i = 0; i < argc; i++) {
int max_len = strlen(argv[i]) * 4 + 128;
int len;
char *buffer = calloc(max_len, 1);
if (!buffer)
return 1;
len = snprintf(buffer, 100, "argv[%d] = \"", i);
encode(buffer + len, argv[i]);
len = strlen(buffer);
snprintf(buffer + len, max_len - len - 1, "\"");
syslog(LOG_INFO, "%s\n", buffer);
free(buffer);
}
for (i = 0; i < envc; i++) {
int max_len = strlen(envp[i]) * 4 + 128;
int len;
char *buffer = calloc(max_len, 1);
if (!buffer)
return 1;
len = snprintf(buffer, 100, "envp[%d] = \"", i);
encode(buffer + len, envp[i]);
len = strlen(buffer);
snprintf(buffer + len, max_len - len - 1, "\"");
syslog(LOG_INFO, "%s\n", buffer);
free(buffer);
}
closelog();
/* Release exclusive lock. */
close(fd);
}
/* Execute requested program. */
execve(filename, argv, envp);
fprintf(stderr, "ERROR: Can't execute %s .\n", filename);
return 1;
}
|
TOMOYO Linux をインストールしてから、以下のコマンドを実行して初期設定を行ってください。
| /usr/lib/ccs/init_policy |
その後、 TOMOYO Linux カーネルで再起動する前に以下の操作を行ってください。
/usr/sbin/sshd が実行された場合にはドメイン遷移が初期化されるようにするために、 /etc/ccs/exception_policy.conf に以下の内容を追加します。
| initialize_domain /usr/sbin/sshd |
SSHサーバから起動されたログインシェル以降はドメイン遷移を行わないようにするために、 /etc/ccs/exception_policy.conf に以下の内容を追加します。
| keep_domain <kernel> /usr/sbin/sshd /bin/bash |
SSHサーバから起動されたログインシェルからのプログラムの実行要求が /bin/record_cmdline に渡されるようにするために、 /etc/ccs/domain_policy.conf に以下の内容を追加します。
|
<kernel> /usr/sbin/sshd /bin/bash execute_handler /bin/record_cmdline |
以上で設定は完了です。 TOMOYO Linux カーネルで再起動してください。
SSH ログインして、適当に操作を行ってください。コンソールからログインして、以下のコマンドを実行すると、コマンドラインが記録されていることを確認することができます。
| grep record_cmdline /var/log/messages |
TOMOYO Linux の execute_handler 機能が /usr/sbin/sshd から起動された /bin/bash からのプログラムの実行要求を横取りして、 /bin/record_cmdline に渡しています。 /bin/record_cmdline がプログラムの実行要求に渡されたパラメータを記録してから、要求されたプログラムを実行します。
プログラム実行時のパラメータが渡されるので、その内容に基づいてプログラムの実行を許可するかどうか判断できます。