显示标签为“security”的博文。显示所有博文
显示标签为“security”的博文。显示所有博文

星期五, 十一月 23, 2007

tcpdump -X

前两天公司浏览网页的时候发现总是被插入了东西,IE 的弹出框提示下载什么 ActiveX 控件。从浏览器的"产看源代码"可以看到插入了如下框体
"<"iframe src='http://5.xqhgm.com/2.htm' width=20 height=1">""<"/iframe">"
因为这种问题以前也出现过两次,是由于园区的路由器被攻击,从而相应的 TCP/IP 报文被修改所导致的。这可能导致浏览器去下载病毒,从而危害 Windows 系统;而且有些页面也无法正常访问了,比如 Windows update 页面。

打电话到园区机房去问。推三阻四的,说什么“其他 Windows 路由器的用户都没有报这个问题”云云,实在没有精力去和他们周旋了,而且对于 IDS 或 Linux 网关防毒软件也没什么深入研究,毕竟我也不是安全专家。

我想还是首先证明不是我们自己路由器的问题。当然最彻底的办法是换一块系统硬盘试试看,不过那要中断网络。所以应该用抓包来看看。抓包我用过 snort, ethereal 和 tcpdump,都不是特别熟悉。如果用 tcpdump 简单命令,只能抓取到 TCP/IP 包,对于应用层数据就没有办法了。但是我记得应该是可以用 tcpdump 抓取应用层的数据的,所以 google 了一下,发现可疑用 -x 参数,但得到的都是 hex 十六进制的数据,再 man 一下,查 -x 参数,发现可以用 -X 参数来同时获得 ASCII 数据,于是:
sh# tcpdump -i eth1 -Xls 0 "port 80"
sh# tcpdump -i eth1 -Xls 0 "port 80" | grep xqhgm
然后查一下内网,因为这台机器上自己也有 web apache,所以如果是这个路由器本身有问题,那么我访问它上面的站点的时候,应该也会有问题,并且抓包应该会有结果
sh# tcpdump -i eth0 -Xls 0 "src port 80 and src host 192.168.0.1" | grep xqhgm
但没有抓到东西,而且从其他检查如 ps aux/last 也没有看出异常。

今天再浏览网页,已经没有病毒提示了。

这样看来,tcpdump 是不是也应该可以完成我以前认为只有 snort 才能完成的事情?

detect ARP virus by tcpdump

在 http://www.yourlfs.org/sysadm_zh_CN.html#toc52 中,讨论了两种 ARP 病毒。但是,这次遇到了不同的 ARP 病毒。

伴随症状:作为路由器使用的 Linux 系统变慢,主要是在上面执行命令(远程 ssh)有延迟,但是通过 console tty 直接登入系统却没有发现变慢了,也没有异常的系统负载。而且用 arp 和 arping 却看不出来,必须使用嗅探器或 tcpdump:
[root@localhost ~]# tcpdump -i eth0 "arp"
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
22:13:04.891192 arp reply 192.168.0.154 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:04.951540 arp reply 192.168.0.155 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:04.990617 arp reply 192.168.0.158 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.036379 arp reply 192.168.0.160 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.081340 arp reply 192.168.0.167 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.112326 arp reply 192.168.0.168 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.141507 arp reply 192.168.0.169 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.191408 arp reply 192.168.0.171 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.203497 arp reply 192.168.0.189 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.236458 arp reply 192.168.0.190 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.266490 arp reply 192.168.0.196 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.336378 arp reply 192.168.0.197 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.353386 arp who-has 192.168.0.199 tell 192.168.0.1
22:13:05.373692 arp reply 192.168.0.198 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.406402 arp reply 192.168.0.199 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.567576 arp reply 192.168.0.200 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.606394 arp reply 192.168.0.211 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.691306 arp reply 192.168.0.212 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.788985 arp reply 192.168.0.222 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:13:05.801462 arp reply 192.168.0.230 is-at 00:e0:4d:07:3b:ff (oui Unknown)
......
22:10:42.613320 arp reply 192.168.0.130 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613348 arp reply 192.168.0.132 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613376 arp reply 192.168.0.133 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613407 arp reply 192.168.0.134 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613437 arp reply 192.168.0.137 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613467 arp reply 192.168.0.138 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613497 arp reply 192.168.0.141 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613526 arp reply 192.168.0.142 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613556 arp reply 192.168.0.143 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613586 arp reply 192.168.0.144 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613615 arp reply 192.168.0.145 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613645 arp reply 192.168.0.149 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613673 arp reply 192.168.0.151 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613704 arp reply 192.168.0.152 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613733 arp reply 192.168.0.153 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613764 arp reply 192.168.0.154 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613792 arp reply 192.168.0.155 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613823 arp reply 192.168.0.158 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613853 arp reply 192.168.0.160 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613884 arp reply 192.168.0.167 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613912 arp reply 192.168.0.168 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613943 arp reply 192.168.0.169 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.613973 arp reply 192.168.0.171 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614011 arp reply 192.168.0.189 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614362 arp reply 192.168.0.190 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614394 arp reply 192.168.0.196 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614424 arp reply 192.168.0.197 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614455 arp reply 192.168.0.198 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614484 arp reply 192.168.0.199 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614515 arp reply 192.168.0.200 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614545 arp reply 192.168.0.211 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614576 arp reply 192.168.0.212 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614606 arp reply 192.168.0.222 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614637 arp reply 192.168.0.230 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614667 arp reply 192.168.0.250 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614697 arp reply 192.168.0.253 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614727 arp reply 192.168.0.254 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614758 arp reply 192.168.0.1 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.614877 arp reply 192.168.0.1 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.615186 arp reply 192.168.0.1 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.615788 arp reply 192.168.0.1 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.616564 arp reply 192.168.0.1 is-at 00:e0:4d:07:3b:ff (oui Unknown)
22:10:42.682754 arp who-has 192.168.0.98 tell 192.168.0.125
22:10:43.361718 arp who-has 192.168.0.101 tell 192.168.0.5
22:10:43.368052 arp who-has 192.168.0.199 tell 192.168.0.1

8192 packets captured
17121 packets received by filter
736 packets dropped by kernel

星期三, 七月 04, 2007

prev: iptables DNAT/SNAT 的概念问题

先看下面的脚本:
#!/bin/bash
# [/usr/local/sbin/]ipt08_nat_DS.sh

/sbin/modprobe ipt_MASQUERADE
/sbin/modprobe iptable_nat
/sbin/modprobe ip_conntrack
/sbin/modprobe ip_conntrack_ftp
/sbin/modprobe ip_nat_ftp

iptables -F
iptables -t nat -F

# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE # [5]
echo 1 > /proc/sys/net/ipv4/ip_forward

inet=220.168.98.221
ihttpd=192.168.0.2

iptables -t nat -A PREROUTING -d $inet -p tcp --dport 80 -j DNAT --to-destination $ihttpd # [1]
iptables -t nat -A POSTROUTING -s $ihttpd -p tcp --sport 80 -j SNAT --to-source $inet # [2]
iptables -t nat -A POSTROUTING -d $ihttpd -p tcp --dport 80 -j SNAT --to-source $inet # [3]
iptables -t nat -A OUTPUT -d $inet -p tcp --dport 80 -j DNAT --to-destination $ihttpd # [4]


iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m state --state NEW -i lo -j ACCEPT
iptables -A INPUT -m state --state NEW -i ! ppp0 -j ACCEPT

iptables -A INPUT -p tcp --dport 3313 -j ACCEPT # FOR: skype
iptables -A INPUT -j REJECT

iptables -A OUTPUT -j ACCEPT

iptables -A FORWARD -j ACCEPT
[1] 定义了外部的主机访问内部 http 服务器的目标地址转换规则,而 [2] 定义了该服务器的源地址转换规则。我之前一直认为有 [1] 就必须有 [2],两者必须匹配。但实际情况是,只需要有 [1],就可以让外部主机正常访问内部飞的服务器了!这是因为,当服务器响应了 iptables 所在的网关主机后,报文到达防火墙,iptables 会根据 DNAT 规则自动做 r-DNAT 操作(照着DNAT的步骤反过来做一遍),所以不再需要 SNAT 了。事实上,只要考虑一下 MASQUERADE 的工作,就可以明白──你只需要定义一个相当于 SNAT 的 转换,而不需要反过来做一次。

[2] 的作用,就是对 server 回复的报文改装源地址,从而可以对 Internet 隐藏内部网络的真实组成情况。注意,在防火墙上用 tcpdump 嗅探不会发现源地址进行了改变,因为从 server 到防火墙的报文只会经过 PREROUTING 和 INPUT 链,而 SNAT 必须到 POSTROUTING 链才生效。

设置了 [1] 后,在内部网络和防火墙主机上使用 $inet 访问服务器,会被拒绝!为什么呢?

先来看本地网络的情况:本地 $local 发送的到 $ihttpd(http server)的请求报文,因为使用 $inet,所以会经过防火墙,于是做 DNAT 操作,但没有做 SNAT 把源地址转换成防火墙的地址。http server 接到这个请求,发现源地址就在本地网络,于是把回复包直接发送到请求包的源地址 $local。

客户机 $local 接到回复报文,但它会感到“困惑”,因为它并没有向 $ihttpd 发送报文,它只好把这个包 DROP 掉,再去等待从防火墙主机 $inet 返回的“真正”的回复包,只是这个回复永远不会到达。

[3] 就是为了解决这个问题。当然,如果内部网络的主机直接使用 $ihttpd 访问 http server,就不会有上面的问题。

对于防火墙主机本身,直接用 $inet 访问 http server,也会被拒绝,因为本地产生的报文不会经过 nat 的 PREROUTING 链,而直接从 nat 的 OUTPUT 链出去,所以 [1] 定义的 DNAT 没有作用,所以,对本地报文,OUTPUT 链相当域 PREROUTING 链。

星期四, 三月 22, 2007

php_admin_value for security

看一个 PHP 程序:
$fp = fopen("/etc/passwd","r"); 
if($fp) {
echo 'ok!';
$result = fread($fp, 8192);
echo $result;
} else {
echo 'no!';
}
?>
通过 URL 运行这个 PHP 程序,会发现程序确实可以读到 /etc/passwd。这是一个危险的信号,我没有想到 PHP 会有这样的安全问题(这应该不是 Apache 的问题,因为 DocumentRoot 已经限制了根路径,而且又没有使用 FollowSymLink 选项)。这意味着一个 PHP 程序可以访问文件系统的任何地方!

当提供虚拟主机服务的时候,这个问题就会变得更加棘手,因为各个虚拟主机可能属于不同的用户,而在这种情况下,一个用户将可以毫无障碍的读取另一个用户的文件!

解决的办法是使用 PHP 的 safemode 中的 open_basedir 参数来进行限制,并且需要对每一个虚拟主机分别做不同的限制:
"<"VirtualHost *:80">" 
DocumentRoot "/var/www/html/docs/html"
php_admin_value open_basedir /var/www/html/docs/html/
"<"Directory "/var/www/html/docs/html"">"
Options Indexes
AllowOverride None
Order allow,deny
Allow from all
"<"/Directory">"
"<"/VirtualHost">"
也可以在 php.ini 中更改 open_basedir 参数来做一个全局的限制。如 open_basedir = /www/users:/tmp 等。

这种方法只是正对 mod_php 有效,对使用 CGI 方式(如 cgiwrap)则不行——如果没有使用 LoadModule mod_php,那么在 httpd.conf 中使用 php_admin_value 将使得 apache 无法启动。

但是如果是使用 mod_rewrite 方式建立的虚拟主机呢?

星期四, 二月 15, 2007

sudo timeout Defaults

因为安装的 rpm 包,不能重新编译,只能通过 Defaults 语法在 /etc/sudoers 里重新定义超时的时间。但首先必须知道都有哪些 Defaults 可以重新定义。通过如下命令完成:
sh$ sudo -L
所以可以知道 timeout 的相关参数:
sh$ sudo -L | grep timeout
timestamp_timeout: Authentication timestamp timeout
passwd_timeout: Password prompt timeout
再编辑 /etc/sudoers:
sh# visudo
......
Defaults:%admins timestamp_timeout=30
# 设置为 30 分钟, -1 表示没有限制
......
后面的 passwd_timeout 应该是指出现密码提示符后,如果在这个时间段里没有输入密码,就失效。

sudo (1)

sudo 有诸多好处:
1. 管理员能够在不告诉用户 root 密码的前提下,授予他们某些特定类型的超级用户权限,这正是许多系统管理员所梦寐以求的。
2. 在这种情况下,我们也就可以定义多个系统管理员,来执行不同的任务。
3. 如果需要取消某人的管理权限(例如离职),那么相对来说也比较简单一点,只需要锁定相应帐号即可(usermod -L $user, 或在 /etc/passwd 文件中的密码项部分开始处插入"!",最好不要使用 userdel -r $user)。当然,如果没有集中的认证如 Kerberos,那么还是需要在每一台主机上执行这项操作的。
4. 减小误操作的机会和损失。

Ubuntu 默认的 /etc/sudoers 文件内容(因为 Ubuntu 默认采用 sudo 并且禁止 root 登录的,比较典型):
# User privilege specification 
root ALL=(ALL) ALL
# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL
这太过于简单,做一个复杂点的来适应服务器系统管理的需要:
......
# Cmnd alias specification
Cmnd_Alias SYSCMD=/bin/*,/sbin/*,/usr/bin/*,/usr/sbin/*,/usr/local/bin/*,/usr/local/sbin/*
Cmnd_Alias COPY_BIN=/*/cp */bin/* *,/*/cp * */bin/*,/*/cp */sbin/* *,/*/cp * */sbin/*
Cmnd_Alias MOVE_BIN=/*/mv */bin/* *,/*/mv * */bin/*,/*/mv */sbin/* *,/*/mv * */sbin/*
Cmnd_Alias LINK_BIN=/*/ln */bin/* *,/*/ln * */bin/*,/*/ln */sbin/* *,/*/ln * */sbin/*
Cmnd_Alias RENAME=/*/rename,
Cmnd_Alias VISUDO=/usr/sbin/visudo,/*/vi* /etc/sudoers
# Cmnd_Alias VISUDO=/*/visudo
Cmnd_Alias CHOWN=/*/chown *
Cmnd_Alias CHMOD=/*/chmod *
Cmnd_Alias USER_CMD=/usr/bin/passwd,\
/usr/sbin/useradd,\
/usr/sbin/usermod,\
/usr/sbin/groupadd,\
/usr/sbin/groupmod,\
/usr/bin/chage -m ? -W [3-7] * ?*

# Defaults specification

# User privilege specification
root ALL=(ALL) ALL
%admins ALL=(%root) SYSCMD,!COPY_BIN,!MOVE_BIN,!LINK_BIN,!VISUDO,!CHOWN,!CHMOD,!USER_CMD
sysadm ALL=(%root) NOPASSWD:ALL

......
这里重点是 Cmnd_Alias 部分,因为涉及到安全的很多问题。首先 SYSCMD 定义所有的系统命令,%admin 组可以执行这些命令,并且只能执行这些命令,即所有 bin 和 sbin 目录下的程序。

这样做是为了阻止这些用户通过 sudo 以 root 身份运行后面的一些敏感操作,包括 visudo, chown, chmod, passwd, useradd, groupadd, usermod, groupmod, chage 等。只是不明白为什么用 /*/visudo 不能匹配?如果仅仅只是用"!"定义不能执行这些命令是不够的,因为这些命令可以被拷贝到 /tmp 或 $HOME 下,然后改个名字就可以运行,所以必须定义只能运行 SYSCMD 范围之内的命令。

另外,这也可以提醒人们编写质量更高的脚本。如果一个脚本不够资格放在 bin 目录下,那最好还是不要用它吧,在 /root 下一大堆丑陋的脚本将极大的降低系统环境的复用性,导致熵增大。

但这样仍然不够,因为用户还可以把 /usr/sbin/visudo 拷贝成 /usr/sbin/VISUDO,还是可以运行,所以必须禁止一切针对 SYSCMD 的拷贝和改名动作。COPY_BIN, MOVE_BIN, LINK_BIN, RENAME 被用来做这件事情,同时它还阻止向 SYSCMD 的拷贝以防使用 hack 版本覆盖原文件。

然后增加用户和组:
sh# useradd -u 123 sysadm
sh# groupadd -u 124 admins
sh# useradd sysadm01
sh# useradd -G admins sysadm01
这样看上去万无一失了
sh$ sudo /bin/cp /bin/cp /tmp
Sorry, user sysadm01 is not allowed to execute '/bin/cp /bin/cp /tmp' as root on stor.shopex.cn.
sh$ sudo /bin/cp /usr/sbin/visudo /tmp/
Sorry, user sysadm01 is not allowed to execute '/bin/cp /usr/sbin/visudo /tmp/' as root on stor.shopex.cn.
sh$ sudo cp /usr/sbin/visudo /tmp/
Sorry, user sysadm01 is not allowed to execute '/bin/cp /usr/sbin/visudo /tmp/' as root on stor.shopex.cn.
sh$ sudo cp -r /usr/sbin/visudo /tmp/
# 看看加一个参数在中间会不会有影响!
Sorry, user sysadm01 is not allowed to execute '/bin/cp -r /usr/sbin/visudo /tmp/' as root on stor.shopex.cn.
但实际上还是不够。不信运行下面这几条命令:
sh$ cd /usr/sbin
sh$ sudo cp visudo /tmp
sh$ sudo cp visudo VISUDO # [1]
sh$ sudo cp /tmp/VISUDO ./VISUDO # [2]
显然 sudo 无法检查匹配的路径,这样就完全绕过了前面的安全设定;而且 sudo 的匹配只是针对命令字符串的匹配,并且不支持正则表达式。对[1]还可以处理,虽然没有正则,但可以多加几条规则也可以避免,但对[2]就完全无能为力了,因为完全可以从别的系统上传一个 VISUDO 到 /tmp,然后切换到 /usr/sbin 绕开 !COPY_BIN 限制!

对此,我想唯一的解决办法就是使用 tripware + sudo.log,但如果 sudo.log 被抹掉?而且我的 sudo.log 里面没有任何记录!?