scriptRedHat 和 Debian 之间的行为差​​异

scriptRedHat 和 Debian 之间的行为差​​异

我在工作中有五个 CentOS 6 Linux 系统,遇到了一个相当奇怪的问题,似乎只发生在我的用户ID在我拥有的所有 Linux 系统上...这是我从命令中排除的条目中出现问题的一个例子last...

mpenning pts/19                        Fri Nov 16 10:32 - 10:35  (00:03)
mpenning pts/17                        Fri Nov 16 10:21 - 10:42  (00:21)
bill     pts/15       sol-bill.local   Fri Nov 16 10:19 - 10:36  (00:16)
mpenning pts/1        192.0.2.91       Fri Nov 16 10:17 - 10:49 (12+00:31)
kkim14   pts/14       192.0.2.225      Thu Nov 15 18:02 - 15:17 (4+21:15)
gduarte  pts/10       192.0.2.135      Thu Nov 15 12:33 - 08:10 (11+19:36)
gduarte  pts/9        192.0.2.135      Thu Nov 15 12:31 - 08:10 (11+19:38)
kkim14   pts/0        :0.0             Thu Nov 15 12:27 - 15:17 (5+02:49)
gduarte  pts/6        192.0.2.135      Thu Nov 15 11:44 - 08:10 (11+20:25)
kkim14   pts/13       192.0.2.225      Thu Nov 15 09:56 - 15:17 (5+05:20)
kkim14   pts/12       192.0.2.225      Thu Nov 15 08:28 - 15:17 (5+06:49)
kkim14   pts/11       192.0.2.225      Thu Nov 15 08:26 - 15:17 (5+06:50)
dspencer pts/8        192.0.2.130      Wed Nov 14 18:24   still logged in
mpenning pts/18       alpha-console-1. Mon Nov 12 14:41 - 14:46  (00:04)

您可以看到上面的两个 pts 登录条目没有与之关联的源 IP 地址。我的 CentOS 机器有多达六个其他用户共享系统。大约 10% 的登录会出现此问题,但没有其他用户名表现出这种行为/var/log/secure。没有源 IP 地址的条目不存在。

问题

考虑到我在这些系统上保留的脚本类型(它们控制着我们的大部分网络基础设施),我对此有点担心,并想了解是什么原因导致我的登录偶尔错过源地址。

  • 为什么last -i显示0.0.0.0pts 行条目(另见这个答案
  • 除了恶意活动之外,还有什么可以合理解释这种行为吗?
  • 除了 bash 历史时间戳之外,还有其他方法可以让我追踪该问题吗?

信息

自从发生这种情况后,我启用了bash历史时间戳(即HISTTIMEFORMAT="%y-%m-%d %T ".bash_profile,并添加了其他一些 bash 历史 hack;然而,这并没有提供之前发生事件时发生了什么的线索。

所有系统均运行 CentOS 6.3...

[mpenning@typo ~]$ uname -a
Linux typo.local 2.6.32-279.9.1.el6.x86_64 #1 SMP Tue Sep 25 21:43:11 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
[mpenning@typo ~]$

编辑

如果我使用last -i mpenning,我会看到像这样的条目......

mpenning pts/19       0.0.0.0          Fri Nov 16 10:32 - 10:35  (00:03)
mpenning pts/17       0.0.0.0          Fri Nov 16 10:21 - 10:42  (00:21)

对于那些试图回答的人来说:我没有使用命令screen或 GUI登录。我的所有登录均来自 SSH;要获得赏金,您必须引用权威性参考资料来解释last -i 0.0.0.0仅通过 SSH 获取的条目。

编辑 2 (针对 ewwhite 的问题)

/etc/resolv.conf(请注意,我.local在上面的输出中使用了地址last来隐藏我公司的信息)

[mpenning@sasmars network]$ cat /etc/resolv.conf
nameserver 192.0.2.40
nameserver 192.0.2.60
domain mycompany.com
search mycompany.com
[mpenning@sasmars network]$

/etc/hosts信息(请注意,此自定义 hosts 文件仅存在于存在这些问题的其中一台机器上)

[mpenning@sasmars network]$ cat /etc/hosts
127.0.0.1       localhost.localdomain localhost
192.0.2.44      sasmars.mycompany.com sasmars
::1             localhost6.localdomain6 localhost6

## Temporary kludge until I add reverse hostname mappings...
## Firewalls
192.0.2.254     a2-inet-fw1
192.0.2.253     a2-inet-fw2
192.0.2.254     a2-wan-fw1
192.0.2.253     a2-wan-fw2
192.0.2.201     a2-fab-fw1
192.0.2.202     a2-fab-fw2
192.0.2.203     t1-eds-fw1
192.0.2.42      sasvpn
192.0.2.246     sasasa1
192.0.2.10      sasoutfw1
## Wireless
192.0.2.6       saswcs1
192.0.2.2       l2wlc3
192.0.2.4       l2wlc4
192.0.2.12      f2wlc5
192.0.2.16      f2wlc6
192.0.2.14      f2wlc1
192.0.2.8       f2wlc2
[mpenning@sasmars network]$

sftp输出自/var/log/secure*

Dec 26 10:36:37 sasmars sshd[26016]: pam_sm_authenticate: called (pam_tacplus v1.3.7)
Dec 26 10:36:37 sasmars sshd[26016]: pam_sm_authenticate: user [mpenning] obtained
Dec 26 10:36:37 sasmars sshd[26016]: tacacs_get_password: called
Dec 26 10:36:37 sasmars sshd[26016]: tacacs_get_password: obtained password
Dec 26 10:36:37 sasmars sshd[26016]: pam_sm_authenticate: password obtained
Dec 26 10:36:37 sasmars sshd[26016]: pam_sm_authenticate: tty [ssh] obtained
Dec 26 10:36:37 sasmars sshd[26016]: pam_sm_authenticate: rhost [192.0.2.91] obtained
Dec 26 10:36:37 sasmars sshd[26016]: pam_sm_authenticate: trying srv 0
Dec 26 10:36:38 sasmars sshd[26016]: Accepted password for mpenning from 192.0.2.91 port 55118 ssh2
Dec 26 10:36:38 sasmars sshd[26016]: pam_sm_setcred: called (pam_tacplus v1.3.7)
Dec 26 10:36:38 sasmars sshd[26016]: pam_unix(sshd:session): session opened for user mpenning by (uid=0)
Dec 26 10:36:38 sasmars sshd[26018]: pam_sm_setcred: called (pam_tacplus v1.3.7)
Dec 26 10:36:38 sasmars sshd[26018]: subsystem request for sftp
Dec 26 10:37:20 sasmars sshd[26016]: pam_unix(sshd:session): session closed for user mpenning
Dec 26 10:37:20 sasmars sshd[26016]: pam_sm_setcred: called (pam_tacplus v1.3.7)

最终解决方案

以下是我的回答

答案1

scriptRedHat 和 Debian 之间的行为差​​异

链接库

CentOS 6.3-脚本(util-linux-ng 2.17.2)

#ldd /usr/bin/script

linux-vdso.so.1 =>  (0x00007fff077ff000)
libutil.so.1 => /lib64/libutil.so.1 (0x00007f309f5d1000)
libutempter.so.0 => /usr/lib64/libutempter.so.0 (0x00007f309f3cf000)
libc.so.6 => /lib64/libc.so.6 (0x00007f309f03b000)
/lib64/ld-linux-x86-64.so.2 (0x00007f309f7e1000)

Ubuntu 12.04-脚本(util-linux 2.20.1)

#ldd /usr/bin/script

linux-vdso.so.1 =>  (0x00007fff375ff000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fc0d7ab0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc0d76f1000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc0d7cdc000)

私人有限公司

基于上游源代码script两个版本都打开了新的pty。以下是测试。

Ubuntu 12.04

john@U64D211:~/tmp$ ls /dev/pts
0  1  5  8  ptmx
john@U64D211:~/tmp$ script
Script started, file is typescript
john@U64D211:~/tmp$ ls /dev/pts
0  1  2  5  8  ptmx
john@U64D211:~/tmp$ last -i
john     pts/0        0.0.0.0          Sat Jan  5 09:09   still logged in   
reboot   system boot  0.0.0.0          Sat Jan  5 09:08 - 09:52  (00:44)    
john     pts/0        0.0.0.0          Thu Jan  3 00:50 - 01:42  (00:52)    
reboot   system boot  0.0.0.0          Thu Jan  3 00:48 - 01:43  (00:54)    

wtmp begins Tue Jan  1 20:48:28 2013
john@U64D211:~/tmp$ exit
exit
Script done, file is typescript
john@U64D211:~/tmp$ ls /dev/pts
0  1  5  8  ptmx
john@U64D211:~/tmp$ 

Ubuntu 12.04script确实打开了新的 pts(2)。它只是没有更新/var/log/wtmp

CentOS 6

我跳过了测试,因为我们已经知道script打开 pty 并使用 wtmp 注册。

性欲旺盛

因此主要的区别似乎在于libutempter.so.0CentOS 链接的额外库()script

使用 Ubuntu 12.04 进行测试

script使用 libutempter 进行编译

john@U64D211:~/tmp/util-linux-2.20.1$ sudo apt-get install libutempter-dev
john@U64D211:~/tmp/util-linux-2.20.1$ ./configure --with-utempter
john@U64D211:~/tmp/util-linux-2.20.1$ make
john@U64D211:~/tmp/util-linux-2.20.1$ cd term-utils/
john@U64D211:~/tmp/util-linux-2.20.1/term-utils$ ldd ./script
linux-vdso.so.1 =>  (0x00007fff54dff000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f289e635000)
libutempter.so.0 => /usr/lib/libutempter.so.0 (0x00007f289e432000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f289e072000)
/lib64/ld-linux-x86-64.so.2 (0x00007f289e861000)

测试

跑步前script

john@U64D211:~/tmp/util-linux-2.20.1/term-utils$ ls /dev/pts
0  1  5  8  ptmx
john@U64D211:~/tmp/util-linux-2.20.1/term-utils$ last -i
john     pts/0        0.0.0.0          Sat Jan  5 09:09   still logged in   
reboot   system boot  0.0.0.0          Sat Jan  5 09:08 - 10:37  (01:28)    
john     pts/0        0.0.0.0          Thu Jan  3 00:50 - 01:42  (00:52)    
reboot   system boot  0.0.0.0          Thu Jan  3 00:48 - 01:43  (00:54)    

wtmp begins Tue Jan  1 20:48:28 2013

之内script

john@U64D211:~/tmp/util-linux-2.20.1/term-utils$ ./script
Script started, file is typescript
john@U64D211:~/tmp/util-linux-2.20.1/term-utils$ ls /dev/pts
0  1  2  5  8  ptmx
john@U64D211:~/tmp/util-linux-2.20.1/term-utils$ last -i
john     pts/2        0.0.0.0          Sat Jan  5 10:37   still logged in   
john     pts/0        0.0.0.0          Sat Jan  5 09:09   still logged in   
reboot   system boot  0.0.0.0          Sat Jan  5 09:08 - 10:37  (01:29)    
john     pts/0        0.0.0.0          Thu Jan  3 00:50 - 01:42  (00:52)    
reboot   system boot  0.0.0.0          Thu Jan  3 00:48 - 01:43  (00:54)    

wtmp begins Tue Jan  1 20:48:28 2013
john@U64D211:~/tmp/util-linux-2.20.1/term-utils$ exit
exit
Script done, file is typescript

script結束後

john@U64D211:~/tmp/util-linux-2.20.1/term-utils$ ls /dev/pts
0  1  5  8  ptmx
john@U64D211:~/tmp/util-linux-2.20.1/term-utils$ last -i
john     pts/2        0.0.0.0          Sat Jan  5 10:37 - 10:37  (00:00)    
john     pts/0        0.0.0.0          Sat Jan  5 09:09   still logged in   
reboot   system boot  0.0.0.0          Sat Jan  5 09:08 - 10:37  (01:29)    
john     pts/0        0.0.0.0          Thu Jan  3 00:50 - 01:42  (00:52)    
reboot   system boot  0.0.0.0          Thu Jan  3 00:48 - 01:43  (00:54)    

wtmp begins Tue Jan  1 20:48:28 2013
john@U64D211:~/tmp/util-linux-2.20.1/term-utils$ last
john     pts/2                         Sat Jan  5 10:37 - 10:37  (00:00)    
john     pts/0        :0               Sat Jan  5 09:09   still logged in   
reboot   system boot  3.2.0-35-generic Sat Jan  5 09:08 - 10:38  (01:30)    
john     pts/0        :0               Thu Jan  3 00:50 - 01:42  (00:52)    
reboot   system boot  3.2.0-35-generic Thu Jan  3 00:48 - 01:43  (00:54)    

wtmp begins Tue Jan  1 20:48:28 2013

空主机名的根本原因

是的,script.c请创建wtmp具有空主机名的条目。请查看util-linux-2.20.1/term-utils/script.c第 245-247 行中的以下代码块。

#ifdef HAVE_LIBUTEMPTER
    utempter_add_record(master, NULL);
#endif

基于libutempter-1.1.5/utempter.h

extern int utempter_add_record (int master_fd, const char *hostname);

因此script.c实际上是将空的主机名传递进去utempter_add_record

RedHat 反向移植

有趣的是,上游util-linux-ng-2.17.2实际上并不支持libutempter。看来 Redhat 决定重新添加该支持。

john@U64D211:~/tmp/util-linux-ng-2.17.2$ ./configure --help|grep utemp

上述命令返回空结果。

结论

因此,两个发行版之间的行为差​​异不是错误,而是一种选择。RedHat 决定支持该功能,而 Debian 则跳过了它。

答案2

这对我来说看起来真是令人费解。它应该使用某个 DNS 名称或 IP 地址。我last.c也检查了文件,但仍然找不到为什么它没有显示任何内容。也许再过一段时间,我就能弄清楚有关 0.0.0.0 的部分。

int dns_lookup(char *result, int size, int useip, int32_t *a)
307 {
308     struct sockaddr_in  sin;
309     struct sockaddr_in6 sin6;
310     struct sockaddr     *sa;
311     int         salen, flags;
312     int         mapped = 0;
313 
314     flags = useip ? NI_NUMERICHOST : 0;
315 
316     /*
317      *  IPv4 or IPv6 ?
318      *  1. If last 3 4bytes are 0, must be IPv4
319      *  2. If IPv6 in IPv4, handle as IPv4
320      *  3. Anything else is IPv6
321      *
322      *  Ugly.
323      */
324     if (a[0] == 0 && a[1] == 0 && a[2] == htonl (0xffff))
325         mapped = 1;
326 
327     if (mapped || (a[1] == 0 && a[2] == 0 && a[3] == 0)) {
328         /* IPv4 */
329         sin.sin_family = AF_INET;
330         sin.sin_port = 0;
331         sin.sin_addr.s_addr = mapped ? a[3] : a[0];
332         sa = (struct sockaddr *)&sin;
333         salen = sizeof(sin);
334     } else {
335         /* IPv6 */
336         memset(&sin6, 0, sizeof(sin6));
337         sin6.sin6_family = AF_INET6;
338         sin6.sin6_port = 0;
339         memcpy(sin6.sin6_addr.s6_addr, a, 16);
340         sa = (struct sockaddr *)&sin6;
341         salen = sizeof(sin6);
342     }
343 
344     return getnameinfo(sa, salen, result, size, NULL, 0, flags);
345 }

上下文中使用的两个全局变量是这两个。

int usedns = 0;     /* Use DNS to lookup the hostname. */
72 int useip = 0;       /* Print IP address in number format */

所以,理论上,它应该使用 dns 或 IP。

我会看看是否能进一步挖掘出什么。但 ewwhite 提出的问题都是合理的。

答案3

所以我在调试器中运行了最后一步,希望至少能给你一些回答你的问题。但我的感觉是根本原因更深。

为什么 last -i 显示 pts 行条目为 0.0.0.0

解释这一点的最好方法是当你通过 -i。

原因在于此代码部分last.c

if (usedns || useip)
  r = dns_lookup(domain, sizeof(domain), useip, p->ut_addr_v6);
if (r < 0) {
   len = UT_HOSTSIZE;
   if (len >= sizeof(domain)) len = sizeof(domain) - 1;
   domain[0] = 0;
   strncat(domain, p->ut_host, len);
}

usednsuseip(使用默认选项)均未标记。这会导致逻辑从结构中复制出来,根据该结构,该p->ut_host结构man utmp包含写入的任何内容所记录的远程登录名utmp

char ut_host[UT_HOSTSIZE]; /* Hostname for remote login, or
                              kernel version for run-level
                              messages */

在您的例子中,这里的值为零。这就是为什么运行时last什么都没有出现的原因。

如果是,last -i则调用 dns_lookup。这将传递条目 (p->ut_addr_v6) 以通过 DNS 进行解析。在您的例子中,此值包含零。

大部分dns_lookup都是表面文章和试探法。基本上重要的是函数getnameinfo。这是一个库调用,在本例中,它将尽力解析存储在中的二进制值ut_addr_v6。当此条目包含零时(例如您的情况),您实际上是将其解析为,0.0.0.0就像您的输出一样last -i

除了恶意活动之外,还有什么可以合理解释这种行为吗?

嗯,这可能是一个错误或疏忽。这不太可能是恶意的,因为离开似乎很愚蠢任何作为攻击者进行跟踪,而不是省略源地址。

到目前为止,答案的重点一直在错误的地方。last只是读取utmpwtmp。但是last正在尽力利用其拥有的数据。

你的根本原因在于utmp写作方式

虽然一些应用程序直接写入,但utmp我猜问题的根源在于sshd处理会话管理的方式。

除了 bash 历史时间戳之外,还有其他方法可以让我追踪该问题吗?

utmp通常不可写,也不应这样写。utmp由旨在让您登录并设置您的会话的应用程序编写。在您的情况下是sshd

sshd 无法正确处理您的用户的原因很奇怪,因为它应该正确复制您来自的主机名。这可能是调试工作的重点。首先将 sshd 的调试输出添加到您的日志中,看看是否出现任何异常。

如果你想解决这个问题(或者,甚至可能发现更多关于这个问题的信息),你可以使用它pam_lastlog来管理,方法是将其添加到utmp会议进入 /etc/pam.d/sshd。

事实上,检查它是否已经存在并不会有什么坏处——因为它pam_lastlog包含一个nohost选项,它可以明确解释您所经历的行为。

最后,您根本不能使用 last。aulast通过审计子系统执行相同的工作。

可能值得一试,看看它是否至少能写出正确的地址。如果没有,那么你的问题必须与 sshd 一起使用,因为 sshd 正在将 DNS 名称传递到不同的子系统(如 utmp 或 audit)。

答案4

当您登录到一台机器时,这些可能是最后一条命令中的几个条目。

geekride   tty2                        Fri Dec 21 15:45 - 15:45  (00:00)    
geekride   pts/1                       Fri Dec 21 13:45   still logged in   
geekride   pts/1        :pts/0:S.0     Thu Dec  6 12:49 - 00:40  (11:50)    
geekride   pts/1        10.31.33.47    Thu Dec  6 12:49 - 00:40  (11:50)    

当您通过终端或控制台按 CTRL+ALT+F1-6 登录时,会出现第一个带有 tty* 的条目。从它使用的终端上可以清楚地看出这一点。

当您登录计算机并在 GUI 中打开终端窗口时,通常会出现第二个条目。即使您在同一个终端窗口中打开新选项卡,也会有一个条目。

第三种类型的条目是在通过 SSH 登录后打开屏幕会话时出现的。这也会在那里创建一个条目,但没有任何 IP 地址。

第四条记录很正常,大家都能理解。

如果你执行last -i以下条目,你会看到类似这样的内容:

geekride   tty2         0.0.0.0        Fri Dec 21 15:45 - 15:45  (00:00)    
geekride   pts/9        0.0.0.0        Fri Dec 21 13:45   still logged in   
geekride   pts/1        0.0.0.0        Thu Dec  6 12:49 - 00:40  (11:50)    

我非常确定您的情况属于这两种情况中的任何一种,一种是 GUI 中的终端窗口,另一种是屏幕会话。

希望这有帮助。

相关内容