一封钓鱼邮件带来的乐趣

访客4年前黑客文章545

  整个六月你我都很忙,你忙着钓鱼、我忙着封锁 IP,一份邮件把我从紧张的氛围中拉了出来,邮件大意为“蓝队的朋友想要加分么?你如果能协助国际刑警修复从犯罪嫌疑人电脑上取证的受损图片,那么便可以在演习行动中为你加分,国际刑警求助信息 We received this PNG file, but we’re a bit concerned the tran *** ission may have not quite been perfect,受损图片见附件”。

  无疑,这是一封来自红队的钓鱼邮件,收件是我的办公邮箱 yangfoobar@sc.chinamobile.com,发送人邮箱地址用 swaks 伪造为 @110.com 的邮件域名,我在沙盒中简单分析了下附件图片,文件类型幻数 89 50 4E 47 0A 1A 0A 看起来像似 PNG,IHDR、IDAT、IEND 等等关键数据块也有,所以,从框架上来说,它应该是个 PNG 格式的图片;另外,IEND 后,出现了大量 powershell 脚本,我基本上可以研判,它是用 Invoke-PSImage *** 的图片马。传统意义上的图片马,指的是,将一句话写入图片,图片上传至 web 目录,结合 web 的解析漏洞或者文件包含漏洞,实现 getshell 的目的;而钓鱼邮件中的图片马并非此类,它内嵌反弹命令的 shellcode,用 wireshark 抓取 CC 的 IP,结合威胁情报,可溯源到红队归属的安全企业。

  溯源不是本文的重点,我搜索了国际刑警的留言信息,找到了原始图片,原本是 PlaidCTF 在 2015 年出的一道取证的题目 PNG_Uncorrupt,刚好演习结束了,我得给自己找找乐子,在几乎安全取证相关技术背景为零的情况下,决定研究下这道题目,或许能获得新知识。

  题意可知,文件传输可能导致该 PNG 文件破损,得尝试修复。先确认文件类型:image.png

  file 命令通过文件类型幻数分析文件类型,既然它无法识别,可能幻数错误,确认下:image.png这与 PNG 正确的幻数 89 50 4E 47 0D 0A 1A 0A 不一致,缺少 0D,用十六进制工具编辑该文件,在之一个 0A 前插入 0D 后另存为 new.png:image.png

  再次识别文件类型:image.png

  cool,BUT,仍然无法渲染:image.png

  没事、没事,看下错误详情:image.png

  原来是位于 0×00071 的 IDAT 数据块 CRC 校验失败,该 IDAT 数据块的实际内容有 131072 个字节,任意字节的任意位错误,都可能导致 CRC 失败,若是暴力猜解,有 2 ** 8 ** 131072 种可能,显然无法落地。不可蛮力、只能巧劲!

  PNG 图片内含多个数据块(chunk),每个数据块依次由四个域组成:长度(length)、类型代号(chunk type code)、实际内容(chunk content)、循环冗余校验码(CRC,cyclic redundancy check):

  长度域,4 字节,指定实际内容域的大小,而非该数据块的大小;

  类型代号域,4 字节,指定该数据块的类型;

  实际内容域,长度域所指定的字节数,存放该数据块的实际内容数据;

  校验码域,4 字节,由类型代号域和实际内容域组合计算而得。

  我用十六进制编辑器分析该数据块。跳至 0×00071 处:image.png

  蓝色部分为长度域(即,0×00020000);黄色高亮为该数据块的类型代号域(即,”IDAT”);紫色为该数据块的实际内容域(即,具体像素),从位于 112 + 0×05 的位置开始,应该在哪个位置结束?从PNG 规范可知,PNG 内含多个 IDAT 数据块,依次连续且无间隔,上个 IDAT 数据块的最后一个字节后面一定是下个 IDAT 数据块的之一个字节:image.png

  换言之,我只要找到下个关键字 IDAT 的位置,往前退 4 个字节的长度域,再往前退 4 个字节的校验码域,所在位置就是当前 IDAT 数据块的实际内容的结束位置。具体而言,我找到第二个 IDAT 关键字,往前退 4 + 4 个字节,到达字节 DD 字节所在的位置 131184 + 0×03 就是结束位置:image.png

  逻辑上,长度域的值应该等于实际内容域的字节数量,前者为0×20000,即 131072,后者为 (131184 + 0×03) – (112 + 0×05) + 1,即 131071,咦~咦,怎么不等呢?捋一捋,位于 0×00071 的 IDAT 数据块,本应存放 131072 个字节的实际内容,但却因某些原因丢失了一个字节(131072 – 131071),这个字节可能是任意内容、可能出现在任意位置,若是暴力猜解,有 2 ** 8 * 131072=33554432 种可能,嗯,可以接受,接下来,我得实现个暴破脚本。

  PNG 规范可知,校验码域是通过 CRC32 算法对类型代号域和实际内容域求值而来,脚本在实际内容域的之一个字节前依次尝试插入 [0, 255] 范围内的值,验证 CRC32 结果是否等于校验码域,若不等继续尝试在第二个字节前插入,直到找到或者完成所有可能的验证。python 内置的 zlib.crc32() 函数支持 CRC32 算法:image.png

  参数必须是 bytes 类型,所以我得以二进制模式读入文件。为了减少干扰,我把位于 0×00071 的 IDAT 数据块的类型代号域和实际内容域的数据转存至文件 idat1 中:image.png

  三下五除二,实现了暴破功能,如下:image.png

  跑起来,20s 不到就收到好消息:image.png

  酷,哈`哈`哈!

  看看位置 553 是啥内容,0x0A,等一等,感觉之前见过,思索思索,最开始修复文件幻数时,在 0x0A 前插入了 0x0D,修复这个 IDAT 数据块时,也是在 0x0A 前插入了 0x0D,结合题目所述”文件传输可能导致该 PNG 文件破损“,印象中,win 采用 0x0D0x0A 换行,而 linux 采用 0x0A 换行,我可以合理猜测,该 PNG 文件传输时,0x0D0x0A 被替换成 0x0A,所以,代码无需尝试在任意位置插入任意字节,只需验证在哪些 0x0A 前插入 0x0D,但不是每个 0x0A 前插入 0x0D,优化代码:image.png

  秒秒钟出来:image.png

  另外,由于 idat1 位于 new.png 的 113 位置,所以 idat1 中的 553 位置就对应 new.png 的 113 + 553 即 666 处,插入字节 0x0D 后另存为 new_fix1.png:image.png

  打开试试:image.png

  WTF!!不应该,思路没问题啊,看看错误详情:image.png

  哦哦,原来报错的是另一个 IDAT 数据块,先前位于 0×00071 的 IDAT 数据块已经成功修复,还是有点不放心,要是有工具能渲染已经修复的那部分图像数据就好了。linux 严格遵循 PNG 规范,CRC 校验不通过就无法渲染,好像 win 不那么严苛,到 win 下试着打开 new_fix1.png:image.png

  WOW,有点小兴奋呢 :-)。你看,我们常诟病 win 不遵循行业规范,在这里反而变成”超强容错“的优点,事物永远都有两面性,用辨证的眼光去….(滚!!),sorry!

  用相同方式,我继续分析位于 131196 的 IDAT 数据块。先从 new.png 提取该数据块,将 131184 + 0x0C 作为开始地址:image.png

  将 262256 + 0x0C 作为结束地址:image.png

  右键选择 save as dump,另存为 idat2。分析过程与之前类似,预期实际内容为 0×020000 个字节,而真实只有 (262256 + 0x0C) – (131184 + 0x0C + 4) + 1 个,缺失 3 个字节,按先前的预判,均为 0x0A 前的 0x0D,基于这一思路,继续优化代码,让其实现猜测多个字节。

  缺失 3 个字节比 1 个字节在代码实现上要所谓麻烦些。比如,aaaa,若为在 a 前丢失 1 个字节(x)后的字符串,反推原始字符串,只需依次在每个 a 前添加 x 就好,即, xaaaa、axaaa、aaxaa、aaaxa 四种可能;若为在 a 前丢失 2 个字节(x)后的字符串, 则原始字符串可能为 xaxaaa、xaaxaa、xaaaxa、axaxaa、axaaxa、aaxaxa六种可能,也就是,从 4 个中选出 1 个有几种可能,以及, 从 4 个中选出 2 个又有几种可能,python 的 itertools.combinations() 函数可以帮我实现:image.png

  回到题目中,我先找出所有 0x0A 的位置(newline_idxs),缺失多少个(lost_bytes_cnt)字节,就从中选出多少个组合:image.png

  另外,由于位置是相对的,插入元素将导致后面元素的位置发生变化,这得注意。比如,有一字符串 aaaa,四个 a 的位置依次为 0、1、2、3,若我在之一个 a 的位置 0 前插入 x 后,要想在第二个 a 前继续插入 x,则必须使用 1 + 1 的位置,因为当前字符串已经变为 xaaaa,这比较麻烦,所以,我换了个方式,从后往前插入,位置 3 的 a 插入后为 aaaxa、位置 2 的 a 插入后为 aaxaxa。回到题目中,我将需要插入 0x0D 的位置先作逆向排序:image.png

  代码如下:image.png

  大约运行 1M 后出结果:image.png

  由于找到的位置是 idat2 中的位置,idat2 又从 new.png 的131196 位置开始,所以,对应至 new.png 中的位置,131196 + 125131 即 256327、131196 + 26274 即 157470、131196 + 502 即 131698,另外,idat1 丢失的字节位置为 666,所以,我依次在 256327、157470、131698、666 前插入字节 0x0D,并且一定得从后往前插入(●﹏● 18+),另存为 new_fix2.png。

  经确认,之一、二个 IDAT 数据块修复成功,第三个报错:image.png

  看看渲染后的效果:image.png

  不错!

  思路清晰了、方向明确了,用相同的 *** 处理其他 IDAT 数据块,就能修复整个图片文件。前面思路中,提取 IDAT 数据块的类型代号域和实际内容域、分析缺失的字节数量、图片文件中插入新数据等等,这些人工完成的工作,都应由脚本实现。

  我在十六进制编辑器中找出所有 IDAT 关键字:image.png

  有十个 IDAT 数据块啊,我得继续优化前面的代码,让它自动提取 IDAT 数据块、分析缺失字节数量、找出应在哪些 0x0A 前插入 0x0D,简单封装,实现类 PngIncompleteIdatChunks:image.png

  运行代码:image.png

  漫长的等待,十四分钟后找回了所有丢失的 0x0D 字节!中途一度怀疑某些临界环境未考虑周全,刚好何阳同志过来找我出去抽了根烟,回来就出结果了。现在,只需按脚本提示,将 0x0D 依次从后往前插入new.png 的对应位置即可修复整张图片,但是,作为食物链顶端的我,怎么能屈尊去做这些低端低级的体力活儿呢,还得有劳脚本。

  在类 PngIncompleteIdatChunks 中增加了 suggest()、fix() 两个成员函数,前者用于显示图片修复建议,后者实际修复图片,如下:image.png

  整个 PoC 完整代码如下:

  运行结果:

  image.png

  看看修复效果:image.png

  成功找到 flag,还没完,如果正式比赛,还得提交文字版本的 flag,看着图片手输?不行,不够洋气,光学字符识别,于是,我把 new_fixed.png 适当放大后,截取 flag 部分另存为 flag.png:image.png

  接着 OCR:image.png

  文本 flag 出来了,拷贝提交即可。

  最后,被我溯源的那台 CC 并没写入蓝队报告中,因为,虽然我在蓝队,但有颗红心!另外,六月未丢分的企业,并不能证明你们的安全做到位了,只能说明系统下线、封锁网段的临时防御手段有效,七月重新上线的、没有 7 × 24 监控的系统,没准一打一个中。成绩,是静态的,安全,是动态的,你知道我在说什么。

  ( *** W,借助 IM 工具 LX 的漏洞去拿蓝队终端的手法,大赞 :)

  *本文作者:yangyangwithgnu

相关文章

360安全卫士发现黑客入侵(360安全卫士拦截)

360安全卫士发现黑客入侵(360安全卫士拦截)

本文导读目录: 1、电脑360出现黑客入侵的安全警告该怎么办? 2、开机后360总是提醒我发现黑客攻击是怎么回事 3、电脑提示有黑客攻击,什么原因,怎么解决 4、我的电脑360总提示黑客入...

怎样恢复老公删除的聊天记录「怎么能查到老公的微信聊天记录」

  想要查到老公已删除的聊天记录,这个是有点困难的。首先,你要拿到他的手机,不然是没办法恢复的。我知道两种微信聊天记录的恢复方法,下面就给你分享一下。   space   方法一:手机微信聊天记录...

成都商务儿伴游,高端儿伴游在线预约资料杨宁

成都商务小学妹伴游,高端小学妹伴游在线预约资料【杨宁】,上海是一座成功人士的聚集地,对商业模特的需求也是比较大的,今天明星商务分享模特访梦,年龄石家庄 女 25,婚姻:未婚,学历:高中,气质:成都商务...

7种最简单易学的打领带的方法(附详细图解)包

7种最简单易学的打领带的方法(附详细图解)包

懂生活,爱折纸 七种常见的领带打法图解,男人学了自己用,女人学了给自己的男人用! 男人的配饰并不多,但领带除外,他是男人特有的装饰品。尤其是商务男士越来越多,不多懂几种领带的系法和搭配,那将使你的...

公知是什么意思,中国公知名单!

公知是什么意思,中国公知名单!

公知是公共知识分子(The Public Intellectual)的缩略词,一度被视为具有批判意识和理想情怀的光辉伟岸形象而存在,然而现在却渐渐沦为舆论场的负面词汇。 归根结底,就在于公知的“公”...

杂志怎么赚钱?报刊杂志投稿赚钱20招

杂志怎么赚钱?报刊杂志投稿赚钱20招

报刊杂志投稿赚钱20招,招招管用! 张会军 投稿能赚钱是不争的事实,至于赚多赚少另当别论。若学会了投稿赚钱20招,对提高稿酬收入是大有裨益的。 一、投稿格式要正确 主题:投稿栏目、文章名、发表...