Web安全研究(四)
No Honor Among Thieves: A Large-Scale Analysis of Malicious Web Shells
Stony Brook University
Ruhr-University Bochum
Web shell作为恶意脚本,攻击者将其上传到被攻陷的Web服务器,以远程执行任意命令、维护其访问权限并提升其特权。尽管在实践中它们的普遍存在和在安全事件中的重要作用,但Web shell从未成为任何研究的直接对象。相反,Web shell被视为需要检测和移除的恶意黑匣子,而不是需要进行详细分析和理解的恶意软件。
在本文中,我们报告了对Web shell的首次全面研究。通过利用不同的静态和动态分析方法,我们发现并量化了流行的恶意shell提供的可见和不可见特性,并讨论了攻击者如何利用这些特性。对于可见特性,我们发现存在密码破解器、SQL数据库客户端、端口扫描器以及检查被攻陷服务器上是否安装安全软件的功能。就不可见特性而言,我们发现大约一半的分析shell包含身份验证机制,但在三分之一的情况下,此机制可以被绕过。此外,我们发现大约三分之一的分析shell执行homephoning,即shell在执行时,会秘密地与各种第三方通信,以揭示新shell安装的位置。通过设置蜜罐,我们量化了从shell安装中受益的第三方攻击者数量,并展示了如何仅通过注册适当的域名,攻击者可以完全接管特定易受攻击的shell的所有安装。
文章结构
- intro
- technical background
- data collection
- analysis of shell features
- stealthiness
- interface features
- bypassing antivirus engines
- backdoors in web shells
- authentication bypass
- homephoning
- analysis of server-side activity
- analysis of stale domains
- related work
- conclusion
Intro
如今,网络应用程序是攻击者用来进行安全入侵的最常见目标之一。这很可能是因为现代网络应用程序是复杂的软件,因此经常存在安全漏洞。再加上攻击者了解到底层的Web服务器可以用作进入组织网络的跳板,这使得Web应用程序成为攻击的吸引目标。成功入侵后,攻击者希望保持对Web服务器的永久和隐蔽访问。为此,她使用所谓的Web shell。Web shell是运行在(被攻陷的)Web服务器上的软件,为攻击者提供远程访问各种关键功能的途径(例如,执行任意命令,上传和下载任意文件,提升权限,发送垃圾邮件和定向钓鱼邮件)。因此,Web shell可以被看作是运行在被攻陷的Web服务器上的一种远程访问特洛伊木马(RAT),因此与在被攻陷的客户端系统上的同类软件密切相关。
令人惊讶的是,关于Web shell的性质和周围生态系统,公开了很少的信息。以前关于此领域的研究将Shell视为成功攻击的产物,没有详细分析它们。例如,Canali和Balzarotti在一项大规模的Web蜜罐研究中发现,攻击者在近一半的观察到的攻击中使用Shell [11],但他们根本没有分析收集到的文件。FireEye于2015年8月发布的一份报告进一步突显了Web Shell的实际重要性:在该报告中,作者指出Web Shell是成功安全入侵的重要构建模块,因为它们可以被攻击者用于在被攻陷的网络中进行横向移动 [17]。在所有这些工作中,Web Shell都被视为某种黑匣子,没有提供有关其特性和潜在行为的任何见解。
在本文中,我们填补了这一研究空白,提供了对Web Shell的全面研究结果,以揭示网络犯罪的这一方面。为此,我们汇编了一个包含超过1,400个Shell的集合,将其用作分析的起点。通过利用不同的数据准备步骤,我们删除具有浅层差异的文件,并创建适合自动静态和动态程序分析的数据集。在第一步分析中,我们揭示了Shell通常提供的特点,以了解它们为攻击者提供了哪些功能。在其他结果中,我们发现(i)许多分析的Shell利用某种源代码混淆或伪装来隐藏它们在Web服务器上的存在,(ii)Shell通常提供诸如密码破解器、SQL数据库客户端和端口扫描器等功能,而不仅仅是执行任意命令,(iii)即使是最好的检测系统也会错过我们样本集中25%的Shell。
在第二步分析中,我们对分析的Shell提供的不可见特性感兴趣。更具体地说,我们调查Shell是否包含某些隐藏的后门或家庭电话机制(即,在执行时,Shell会秘密地与各种第三方通信,以揭示新安装位置的意图)。检测后门和家庭电话机制是一项具有挑战性的任务,因为我们处理复杂且潜在混淆的代码,并且攻击者有动机尽可能地隐藏这些机制。因此,我们利用不同的分析技术来揭示这种行为。首先,我们手动审查了近500个Web Shell,并发现其中约有50%的Shell在代码中提供了身份验证机制。然而,我们还发现其中三分之一的机制可以被绕过,这表明这些可能实际上是有意的身份验证绕过。其次,我们利用蜜罐来发现和量化信息的客户端和服务器端泄漏情况,因为这表明了某种潜在的家庭电话机制。通过使用多个蜜罐设置,我们发现大约有30%的分析Shell表现出客户端家庭电话。在服务器端,我们发现4.8%的Shell发起与总共34个远程IP地址的服务器端连接。在我们的蜜罐实验的八周内,我们观察到了690次连接尝试,以访问我们托管的Shell的秘密URL,这表明后门在实践中经常被滥用。最后,我们发现许多Shell依赖于其他域来获取远程内容,其中一些已经过期并且实际上可以注册。通过注册正确的域名,我们展示了竞争的黑客团体和安全公司如何自动接管恶意Web Shell,或者将这些域用作高度准确的方法来识别新受感染的主机。
总结一下,我们的研究做出了以下贡献:
我们通过不同的方法收集了1,449个Web Shell作为我们研究的起点。通过不同的数据准备步骤(例如,规范化和去混淆),我们提炼出了一组全面的Shell,代表了典型的攻击工具,并将其用于后续分析。
我们提供了对这种类型攻击工具的新见解,确定了Shell提供给对手的不同类型特性。为此,我们利用静态和动态程序分析技术来发现和量化我们分析的Web Shell提供的可见和不可见特性。
我们通过实验证实了许多Web Shell包含后门(例如,身份验证绕过或某种家庭电话行为)的传言。基于不同的分析技术,如手动代码审计、自动静态程序分析和在蜜罐环境中的执行,我们能够发现这些后门,并为此行为提供了实证见解。
数据可用性:为了促进该领域的进一步研究,我们计划在请求和适当验证后提供我们的Web Shell数据集和分析结果。我们希望(更广泛的)安全社区从这些信息中受益,因为Web Shell是尚未详细分析的攻击领域的一部分。
technical background
<? php system ( $_GET [’cmd ’]); ?>
为了提供理解本文其余部分所需的技术背景,我们简要介绍了恶意PHP Shell以及攻击者如何利用它们。尽管恶意Web Shell原则上可以用任何服务器支持的编程语言实现,但我们经验性地发现,由于PHP在服务器环境中广泛存在,因此通常选择PHP作为编程语言。因此,在本文的其余部分,我们将重点关注基于PHP的Shell。
一个PHP Shell在本质上是一种在远程服务器上执行命令的方式。清单1显示了最简单的Shell,它从HTTP GET参数接收命令,并使用函数system()与操作系统进行交互。这些命令以Web服务器或PHP脚本所有者的权限执行,取决于服务器的配置。
从攻击者的角度来看,PHP Shell提供的功能可用于向受感染的计算机发送任意命令。恶意的PHP Shell通常比清单1中显示的Shell复杂得多。它们通常有数千行代码,属于不同的家族(r57和c99是最常见的两种[31]),并大量使用混淆来避免检测和增加分析难度。除了在远程服务器上提供命令执行之外,它们还可能提供各种其他功能,例如文件管理器、用于FTP和SQL服务器的密码破解器、自删除功能以及使用已知漏洞进行特权提升(详见第4节)。某些恶意Shell不是通过Web界面为攻击者提供远程控制功能,而是将远程服务器转化为垃圾邮件发送服务器(或者从目标组织内的服务器发送钓鱼邮件),或者迫使其加入僵尸网络[10]。
https://www.r57shell.net/
这些恶意Web Shell是通过滥用可能给予攻击者文件上传能力的所有可能的漏洞而上传到受感染的Web服务器的。这些漏洞包括FTP/SSH凭据破解、滥用远程文件包含和本地文件包含漏洞[25,26]、SQL注入漏洞,或者滥用现有的善意文件上传机制,这些机制未对上传的文件进行适当的清理[27]。除了将Shell上传到易受攻击的Web服务器上,攻击者还试图滥用已经受感染的Web服务器上的现有Shell。
发现这些Shell的一种方法是使用搜索引擎dorks,即旨在返回匹配特定恶意标准的索引网页的命令,例如暴露的控制面板和包含敏感数据的页面[15]。例如,Google搜索引擎查询filetype:php intext:‘’!C99Shell v. 1.0beta’'旨在返回特定版本c99 Shell的所有已索引实例。图1显示了一个网站设计师[36]提供给我们的6个月访问记录,他特意设置了三个诱饵页面,使用伪装技巧假装成为搜索引擎爬虫的Shell安装。该图显示,即使对于一个单一的网站,每天都有数十名攻击者不断前来,试图滥用其已经上传的Shell。
data collection
数百种不同的Web Shell存在于网络上,这部分是由于同一种Shell的多个版本存在,还有一部分是由于已被用作创建新Shell的基础。尽管已经有一些尝试收集常见Web Shell的列表(例如[1-3,5]等),但这些来源都无法提供关于完整性和质量的任何保证。因此,在本节中,我们描述了我们用于实验的Shell集合的编制过程。
数据来源和准备工作。我们首先收集了在地下黑客网站上能够找到的所有Shell,以及研究人员在蜜罐中观察到的Shell[1-3,5]。我们避免了那些用于合法服务器管理的Shell,因为这些不在我们研究的范围之内。通过结合所有上述来源,我们得到了起始集合,包括1,449个Shell。接下来,我们评估并改进了我们工作集的质量,筛选掉了非Shell文件(例如仅包含JavaScript代码的文件)、使用PHP以外的编程语言编写的Shell以及具有浅显差异的Shell,以避免潜在的重复。我们对1,449个Shell进行了以下处理:
筛选是通过检查PHP标签和文件大小是否超过经验确定的阈值来完成的。通过这个过程,我们排除了53个文件,得到了1,396个潜在的PHP Shell。
标准化是为了删除非明显的重复,即密码哈希可能不同,但从语法角度来看几乎相同的Shell。我们的Shell标准化过程包括删除注释、换行符、空格和分号。此外,我们将所有变量名和函数名替换为一个单一名称。请注意,这个过程不旨在保留代码的正确性。我们只是用它来将Shell聚类在一起,并选择每个聚类的第一个成员进行进一步分析。我们经验性地发现,这种简单的方法在实践中能够产生足够好的结果,以便检测不同文件中的小差异。请注意,将来可以使用更精细的机制,例如基于抽象语法树的分析、模糊哈希[21]或确定语义等价性[7],但我们发现我们的方法在实践中已经足够。
反混淆是必要的,因为在前一步中识别出的相同Shell可能仍然使用不同的混淆方法。因此,我们使用了最先进的UnPHP反混淆服务[4]来自动反混淆我们的804个唯一Shell。UnPHP返回了661个Shell的反混淆代码(尝试反混淆剩下的143个Shell时,该服务一直超时),然后我们再次进行了标准化,得到了607个唯一的Shell。
https://www.unphp.net/
最终的数据集。任何尝试分析实际代码的人,特别是恶意代码,都会明白,一些在理论上可能效果良好的技术在实践中可能无法按预期运行。除了UnPHP无法反混淆的143个Shell之外,我们还注意到,UnPHP声称已成功反混淆的一些Shell实际上是有问题的。手动分析揭示,这要么是因为UnPHP无法正确转义反混淆语句中的所有特殊字符,要么是因为反混淆结果中缺少整段代码。
由于自动静态分析和动态分析技术对分析代码有不同的要求,我们决定创建原始607个Shell的两个子集。对于静态分析部分,我们只使用了那些要么完全符合语法要求,要么我们可以用合理的手动工作修复的Shell。我们还删除了从静态分析的角度来看不提供任何有趣结果的Shell,比如只是打印本地系统信息或仅仅发送电子邮件到预定义的电子邮件地址的Shell。最后,由于我们使用静态分析来发现Web Shell的流行功能,我们删除了不符合我们对Shell是什么的模型的Shell,比如只是以机器人样式连接到远程服务器,并执行该服务器返回的任何命令的Shell。在静态分析的预过滤过程结束时,我们得到了481个唯一的Shell,我们在本文的其余部分将其称为"静态分析集"。
对于动态分析部分,我们采用了更宽容的方法,Shell只有在完全无法使用时才被删除,即使部分UI损坏,我们也保留了那些在浏览器中渲染会产生某种可见UI的Shell。这包括UnPHP无法反混淆的Shell。我们删除了提供明显恶意功能的Shell,比如调用phpinfo()函数并退出的文件。最后,我们决定保留具有类似机器人功能的Shell,因为我们想更多地了解远程服务器和攻击者的性质。在此过程结束时,我们得到了541个唯一的Shell,我们在本文的其余部分将其称为"Shell的动态分析集"。我们的最终数据集代表了不同的Shell家族,包括c99、r57、WSO、B347k、NST、NCC和Crystal的变种。然而,许多变种通过应用不同的代码混淆技术、添加新功能或从其他Shell家族复制代码而从一个家族的同胞演变成一个新的Shell家族。例如,c99 Shell被扩展为特权升级功能,并更名为c999 Shell,c99 Shell的一部分代码可以在Fx29 Shell家族中找到。没有在源代码中明确标记的PHP Shell因此很难分类,这将导致不准确的结果。
analysis of shell features
PHP Shell从简单的单行命令发展成了复杂的多功能Web应用程序,为攻击者提供了一系列超出执行单个系统命令的功能。由于对此类Shell提供的实际功能了解甚少,我们的目标是列举PHP Shell提供给攻击者的不同类型的功能,并识别最受欢迎的功能。这为了解攻击者在入侵Web服务器后的需求和所需步骤提供了见解。同时,我们还列举了实施功能以隐藏Shell存在和活动的Shell数量。
隐蔽性
攻击者有兴趣隐藏恶意后门的存在,以尽可能长时间地保持对服务器的访问权限。因此,许多PHP Shell的源代码都经过了严重的混淆,因为这种方法给攻击者带来了各种优势。首先,攻击者的目标是在被入侵服务器的管理员发现Shell时隐藏Shell的意图和功能。其次,混淆可以妨碍静态分析工具、搜索模式或杀毒软件产品的自动检测(请参阅第4.3节)。混淆的另一个原因可能是为了隐藏PHP Shell中的后门或家庭电话机制的存在(请参阅第5节),以免被其他攻击者检测到。我们在STATIC ANALYSIS集中对最终的481个Shell进行了混淆迹象的分析,并将原始脚本与它们的去混淆版本进行了比较。这个分析得出了以下两个混淆统计信息:
- 20.6%(即481个中的99个)在去混淆后,使用PHP的内部标记分析器枚举标记数时具有增加的标记数(超过1%),表明解包的PHP代码。
- 20.8%(即481个中的100个)使用eval(),平均调用了15.2次eval(),最多达到了91次。
除了确保服务器端隐身的混淆之外,我们还遇到了一些技术,用于隐藏Shell的存在,使得好奇的客户端访问者无法察觉。这种行为可能基于以下洞察:由于搜索引擎爬虫会爬行并索引整个网络,它们很可能也会索引未受保护的上传Shell。然后,这将允许其他攻击者发现已经被入侵的服务器(通过前面提到的搜索引擎搜索关键字),并接管上传的Shell。此外,一些搜索引擎现在会在搜索结果中报告网站很可能已经被入侵。这很可能会导致更快的清理,这对网站所有者有益,但对攻击者没有益处。
因此,Shell开发人员实施了基本的技术,以隐藏Shell对搜索引擎爬虫的存在。基于HTTP用户代理头,可以相对简单地识别爬虫的请求,并模拟不同的行为。在我们的去混淆集合中,我们识别出了76个Shell(16%)检查用户代理是否在黑名单中。例如,61个Shell如果用户代理包含关键字Google,则会响应404 Not Found页面。此外,我们还识别出11个Shell,默认情况下响应404 Not Found页面,除非访问者发送正确的登录凭据,这将揭示Shell的存在和功能。
总之,我们经验性地发现,分析的Web Shell中有15-20%利用隐藏技术来掩盖其在被入侵的Web服务器上的存在,无论是来自Web服务器所有者还是特定的客户端访问者。
Interface feature
为了更好地理解和列举Web Shell提供给攻击者的功能,我们使用了静态污点分析技术对我们的STATIC ANALYSIS Shell集合进行了分析。为此,我们扩展了我们设计的现有工具[14],该工具能够检测PHP应用程序中的安全漏洞,如远程命令执行、远程代码执行、邮件头注入和SQL注入漏洞。此外,该工具支持对与文件相关的漏洞进行分析,如文件上传、任意文件写入/创建、文件泄露、权限操纵或文件包含漏洞。当我们的原型在去混淆的PHP Shell代码中检测到这些漏洞时,每个漏洞都被解释为一个特征。
https://www.ndss-symposium.org/ndss2014/programme/simulation-built-php-features-precise-static-code-analysis/
我们的静态分析工具还执行上下文敏感的字符串分析。这允许我们自动检查达到敏感位置的标记,并列举出它无法默认检测到的其他特征。例如,当我们的工具分析执行系统命令的敏感位置时,扫描器会重建到达此位置的所有可能的字符串(即命令)。在这一点上,我们应用正则表达式来识别与文件下载器(wget、curl、lynx、get、fetch)、反向或回连Shell(perl、python、gcc、chmod、nohup、nc)或信息收集(uname、id、ver、sysctl、whoami、$OSTYPE、pwd)常相关的命令。结果由我们添加到原型中的其他特征检测算法来补充。例如,当通过PHP的内置文件功能请求远程文件下载时,会报告文件下载特征。同样,当在打印数据到HTML响应页面的敏感位置的污点分析中遇到与系统信息相关的PHP内置函数或保留常量(例如,php_uname())时,将检测到系统信息收集特征。
此外,我们使用了给定Shell的控制流图表示中关于循环的注释,以将某些漏洞分类为特征。例如,循环内的邮件头注入被解释为垃圾邮件特征,而循环内的对FTP服务器或HTTP基本认证的登录尝试被解释为暴力破解特征。类似地,当在循环中使用内置函数来建立套接字连接,端口是迭代的主题时,将记录端口扫描特征。由于篇幅限制,我们省略了我们添加到工具中的所有(跨程序)实现细节。
我们的特征枚举的最终结果如图2所示。最突出的特征在我们收集的所有Shell中出现,占比69%,是收集系统信息。更具体地说,攻击者对当前工作目录、操作系统和PHP版本感兴趣。接下来,与文件系统的交互由分析的Shell中的67%支持。我们将检测到的涉及文件读取(54%)、创建(54%)、列出(40%)、删除(38%)、编辑(29%)和权限修改(22%)的漏洞总结为一个名为“文件浏览器”的特征。另外,我们在分析的54%的PHP Shell中发现了一个文件上传特性。除了文件浏览器,我们还检测到了一个稍微不那么流行的SQL浏览器,可以在约一半的Shell中列出所有数据库和表,以及仅在我们的481个分析Shell中的13个中才能找到的FTP浏览器。
传统的命令执行特性在我们的Shell中被检测到,占比为59%。除了执行任意操作系统命令外,这些Shell通常在Web界面中提供一系列预定义的命令,即c99 Shell提供了用于查找配置文件和密码文件或可写目录的命令。较不常见的功能(43%)是通过eval()和类似操作符执行任意PHP代码。这一功能出现在较小的Shell中,重点是隐蔽性而不是功能的完整性。此外,我们找到了68个Shell,通过远程文件包含提供了任意代码执行功能。为了绕过限制性防火墙,远程命令执行也可以绑定到通过外部程序打开的不同端口(37%),最好是用Perl或C编写的程序。
其他功能较少可用,因此对于攻击者来说可能不太重要作为PHP Shell的核心功能。例如,只有19%的Shell允许发送电子邮件,而12%的Shell允许发送多封电子邮件(可能代表垃圾邮件)。发动FTP和HTTP身份验证凭据的暴力破解攻击(19%)或端口扫描(10%)的功能在实践中也很少见。请注意,这些任务可以独立于被攻击的服务器执行。但是,当作为PHP Shell的一部分使用时,攻击者能够隐藏她的IP地址,而受感染的Web服务器充当代理。
由于我们的特征枚举是基于代码指纹的,原则上它可能在现实世界的PHP应用程序中失败。然而,PHP Shell的代码相对简单(没有面向对象编程特性,不需要进行最小的跨程序分析),并且在对50个示例Shell进行手动调查时,我们没有遇到虚假阳性。尽管如此,我们发现了更多的特性没有包括在我们的评估中,例如,破解密码哈希的能力,尝试绕过PHP的安全模式,HTTP代理和拒绝服务(DoS)功能。我们预计这些功能在PHP Shell中不太突出,而且很难进行通用指纹识别,因此我们决定不包括这些功能在我们的评估中。
Bypass AV
尽管众所周知存在其局限性,但杀毒软件可以说是用户中最受欢迎的安全软件之一。除了用户和企业环境外,许多Web服务器利用杀毒软件来检测可能对其服务器进行恶意上传的文件,无论是通过使用合法的上传功能(例如Web邮件应用程序中的附件)还是通过滥用文件上传漏洞(例如远程文件包含漏洞)。
为了衡量现代杀毒软件检测恶意Web Shell的能力,我们将我们的481个Shell的STATIC ANALYSIS集上传到VirusTotal [9],这是一个在线服务,截止到本文写作时,使用56个杀毒引擎来扫描上传和URL。对于我们的90%的Shell,VirusTotal的至少一个杀毒引擎能够将Shell检测为恶意软件,每个Shell平均被15个扫描程序归类为恶意软件。最准确的两个杀毒引擎能够分别检测到72.5%和67.2%的上传Shell。这些数据表明,即使一组杀毒引擎可以检测到大多数Shell,即使是最准确的单一引擎(Avast)也无法检测到大约25%的恶意Web Shell。
为了了解混淆对检测恶意Web Shell的影响,我们还上传了相同481个Shell的去混淆版本到VirusTotal。令人惊讶的是,整体准确率下降到了至少一个引擎检测到的Shell的88.5%,每个Shell现在平均只能被10个扫描程序检测到(与其原始混淆版本的平均15个扫描程序相比)。例如,一个特定的Shell,原来可以被22个杀毒引擎检测到,当我们使用其去混淆版本时,只能被两个引擎检测到。这降低了对恶意Shell的检测,表明一些杀毒引擎很可能在其数据库中硬编码了原始混淆Shell的部分内容,而从未对恶意Web Shell进行去混淆。
backdoors in web shells
由于Web Shell是复杂的Web应用程序,通常包含成千上万行的代码并使用多个混淆层,因此假设其中一些Shell可能被攻击者植入后门以获利并不是不合理的。在Web Shell的上下文中,我们区分传统的后门,涉及绕过身份验证机制,以及“homephoning”后门,其中Shell在加载时会向除上传Web Shell到易受攻击的Web服务器的攻击者之外的第三方广播其位置。
authentication bypass
我们手动检查了我们的481个反混淆Shell(STATIC ANALYSIS集)中的身份验证机制,这些机制限制了用户访问并要求用户提供秘钥(例如,密码)。同时,我们还审查了这些机制是否存在绕过的可能性。我们的直觉是,恶意攻击者不会自由地将他们的Shell发布为“同伴”攻击者的服务,而是为了访问那些被不谨慎的攻击者入侵的服务器,这些攻击者使用该Shell。
大多数发现的身份验证机制基于用户名/密码凭据,可以通过HTTP基本身份验证或通过HTML登录表单的HTTP POST请求提供。此外,访问权限还受到给定IP地址或IP地址范围的限制。我们还观察到一些示例要求通过隐藏的HTTP GET参数或用户代理提供秘密密钥,以及期望提供的密码,然后将其用作XOR密钥来解密评估的PHP代码。然而,大多数检测到的机制默认情况下不需要身份验证,例如,如果配置代码中的密码为空。
以下是我们的PHP Shell集合的身份验证机制的自动枚举结果,包括已激活和已禁用的身份验证机制:
- 52.0%的Shell在代码中提供了身份验证机制,即481个Shell中的250个。
- 30.8%的身份验证机制可以绕过,即250个中的77个。
- 28.4%的身份验证机制在默认情况下处于激活状态,即250个中的71个。
- 25.4%的默认情况下激活的身份验证机制可以被绕过,即71个中的18个。
接下来,我们介绍了我们在PHP Shell集合中遇到的不同类型的后门,这些后门可以用于绕过身份验证机制。我们认为这些后门是有意由创建者或PHP Shell的再分发者安装的。我们还观察到许多身份验证机制被复制到不同的Shell系列和变种中,包括(可能是无意的)后门代码。检测到的后门可以分为三类:(i)注册全局变量,(ii)使用不受保护的功能,以及(iii)泄漏身份验证凭据。请注意,由于代码复杂性和分析的PHP Shell数量众多,我们不主张完全检测我们集合中的所有后门。
<? php
extract ( $_REQUEST [" c99shcook " ]);
parse_str ( $_SERVER [’ HTTP_REFERER ’]);
import_request_variables (" GPC");
foreach ( $_GET as $k => $v) { $$k = $v ;}
PHP设置register_globals在PHP版本4.2.0之前默认启用,引入了许多安全问题[29]。这个设置允许攻击者通过HTTP请求参数来初始化任何全局变量。这导致了意外行为和安全问题,例如,当对index.php?loggedin=1发起GET请求时,会将index.php中的变量 l o g g e d i n 初始化为值 1 。因此, r e g i s t e r g l o b a l s 指令在后来的 P H P 版本中默认禁用,并在 P H P 5.4.0 版本之后被移除。然而,可以使用 P H P 内置功能来实现相同的行为,如代码清单 3 所示。例如,可以使用内置函数 e x t r a c t ( ) 和 p a r s e s t r ( ) 来将数组或 U R L 字符串中的值填充到全局范围。当这些函数以用户输入为参数且没有附加参数调用时,实际上会模拟 r e g i s t e r g l o b a l s 指令的行为。对内置函数 i m p o r t r e q u e s t v a r i a b l e s ( ) 的调用也是如此。此外,可以通过构建循环并动态分配每个键到一个变量来将超全局数组 loggedin初始化为值1。因此,register_globals指令在后来的PHP版本中默认禁用,并在PHP 5.4.0版本之后被移除。然而,可以使用PHP内置功能来实现相同的行为,如代码清单3所示。例如,可以使用内置函数extract()和parse_str()来将数组或URL字符串中的值填充到全局范围。当这些函数以用户输入为参数且没有附加参数调用时,实际上会模拟register_globals指令的行为。对内置函数import_request_variables()的调用也是如此。此外,可以通过构建循环并动态分配每个键到一个变量来将超全局数组 loggedin初始化为值1。因此,registerglobals指令在后来的PHP版本中默认禁用,并在PHP5.4.0版本之后被移除。然而,可以使用PHP内置功能来实现相同的行为,如代码清单3所示。例如,可以使用内置函数extract()和parsestr()来将数组或URL字符串中的值填充到全局范围。当这些函数以用户输入为参数且没有附加参数调用时,实际上会模拟registerglobals指令的行为。对内置函数importrequestvariables()的调用也是如此。此外,可以通过构建循环并动态分配每个键到一个变量来将超全局数组_GET或 P O S T 中的每个键 / 值对填充到全局变量中。这些一行代码的安全影响对于未经训练的人来说是微妙且难以察觉的,使它们成为在 P H P S h e l l 中植入后门的完美选择。事实上,在 70.1 _POST中的每个键/值对填充到全局变量中。这些一行代码的安全影响对于未经训练的人来说是微妙且难以察觉的,使它们成为在PHP Shell中植入后门的完美选择。事实上,在70.1%的带后门的PHP Shell中,认证配置和检查之间都注入了这些功能之一,允许完全绕过认证。例如,代码清单2中显示的认证机制,当激活并带有后门时,可以通过覆盖变量 POST中的每个键/值对填充到全局变量中。这些一行代码的安全影响对于未经训练的人来说是微妙且难以察觉的,使它们成为在PHPShell中植入后门的完美选择。事实上,在70.1md5以任意密码或直接设置$_SESSION[‘login’]键(index.php?md5=0&_SESSION[login]=1)来绕过。这个后门存在于每个c99 Shell中,并被复制到许多采用了c99的详细配置代码的兄弟Shell中。
最后但同样重要的是,一些Shell允许通过泄漏认证凭据来绕过认证机制。例如,在七个Shell中,会向攻击者的邮箱发送一封电子邮件,其中包括受感染服务器的域名、Shell的路径以及认证密码。原始代码已经被混淆并隐藏在Shell的功能中。这使得在代码审查中很难发现这个功能,特别是当只调查认证机制本身时。
// position 1
$s_auth = false ;
if( is_authenticated ()) { $s_auth = true ; }
// position 2
if( $s_auth ) { // protected shell features }
// position 3
homephoning
由于Web Shell通常是典型的Web应用程序,攻击者通过他们的Web浏览器与受感染的服务器通信,因此Shell可以从客户端和服务器端泄漏其位置或其他类型的信息。在客户端,当攻击者在她的浏览器中加载页面时,JavaScript代码可以用于与外部世界通信,并故意泄漏当前页面的URL,即Shell的URL,通过泄漏document.location.href浏览器属性的值。此外,对于远程资源(如图像、层叠样式表和JavaScript脚本)的所有浏览器请求通常都会在每个请求的Referer标头中包含当前页面的URL。这不仅允许有意的主机调用,还允许无意的主机调用,例如,Web Shell在获取分析脚本时将其位置泄漏给Google。
在服务器端,Shell可以通过使用编程框架本身提供的一系列函数或与底层操作系统进行交互来与外部世界通信。例如,在PHP中,恶意Shell可以使用套接字、HTTP API(例如PHP的http_get()函数)或使用广泛使用的wget实用程序与第三方通信。
为了发现和量化恶意Web Shell的客户端和服务器端泄漏,我们建立了一个蜜罐基础设施,如图3所示。这个设置涉及到我们的541个Shell集合(DYN ANALYSIS集合)的详细信息如下:
每当一个Shell需要明确的身份验证时,我们修改了底层代码以删除这一要求。这使我们能够减少整体设置的复杂性,因为我们可以通过简单地请求适当的URL来稍后使用Shell。这些Shell然后被复制到一个Amazon EC2虚拟机中,位于一个不可通过Web访问的文件夹中。
我们注册了四个可用的域名并将它们的IP地址解析到我们的虚拟机。我们四个域名中包含的关键词属于四个不同的类别,分别是:体育、黑客、购物和银行。我们选择注册指示不同网站的域名,以吸引尽可能多的攻击者,他们会在他们的homephoning Shell的潜在请求中看到我们的域名。
我们在第二台服务器上使用OpenWPM框架[16]来模拟攻击者通过四个注册的域名之一浏览上传的每个Shell。虽然OpenWPM旨在进行Web隐私测量,但它记录了所有客户端、第三方请求的能力,这对于后来识别有意和无意的客户端homephoning非常有用。
我们实施了一系列脚本,允许OpenWPM框架与我们的服务器同步。即,如算法1中所示的伪代码,Open-WPM宣布其访问特定Shell的意图,导致服务器端通过我们四个注册的域名和特定的文件路径之一使该Shell可用。例如,如果OpenWPM指示它想要shell3.php的URL,我们的服务器端代码会生成一个链接,如www.banking.com/img/lib/shell3.php。文件路径不仅使我们的整体URL对于任何观看的人更加可信,而且还允许我们稍后区分访问我们主要域的通用爬虫和因为homephoning而知道其恶意Shell的确切路径的攻击者。等待了预定的秒数后,我们的客户端会向服务器发出信号,以将分析过的Shell从我们的Web服务器的根目录中删除。集合的541个Shell每天被访问三次,为期8周,从2015年5月24日开始。在这个实验中,我们唯一的假设是,如果一个Shell包含homephoning代码,那么执行该代码不应该难以触发。也就是说,我们假设一个homephoning Shell将在加载其主页时贪婪地联系各种预定的远程主机,而不是等待可疑的Shell用户点击Shell的用户界面中的某个特定链接。
客户端homephoning:通过检查OpenWPM平台捕获的客户端第三方请求的日志,我们发现29.2%的PHP Shell会与第三方域进行联系,每个Shell平均联系两个域。总体而言,我们的Shell集合与总共149个域名取得了联系,解析到108个唯一的IP地址。表1显示了15个联系最多的域名以及我们手动筛选的这些域名的分类。可以注意到,Web Shell向各种远程主机发起第三方请求,其中一些显然是良性的。这些是意外的homephoning情况,其中Shell在包含远程对象的过程中无意中将其位置泄漏给了远程主机。
服务器端homephoning:Algorithm 1中描述的步骤集允许我们精确确定客户端的homephoning,以及维护一个始终可用的Web服务器,我们可以稍后分析其日志,以确定是否攻击者正在尝试访问我们的服务器,而这是通过他们的homephoning Shell通知的。然而,此设置无法允许我们对特定Shell的服务器端homephoning进行正确的归因。这是因为由任何给定的Shell启动的服务器端进程可以在删除Shell后继续存在,正如在nextShell步骤中发生的那样。
为了解决这个问题,除了我们长达8周的实验之外,我们还进行了另一个实验,在该实验中,在分析每个单独的Shell后,我们恢复到已知的远程虚拟机的干净副本。我们使用这个实验的结果来进行适当的服务器端homephoning归因,而不必担心攻击者连接回我们的蜜罐服务的能力。
通过检查我们收集的数据包跟踪并过滤掉由于Ubuntu更新检查、DNS服务器和Amazon-EC2特定的流量引起的连接,我们发现4.8%的Shell发起了与总共34个远程IP地址的服务器端连接。这些远程主机分布在全球各地,前三个国家分别是美国(16)、韩国共和国(4)和中国(2)。此外,我们注意到70%的服务器端homephoning Shell连接到特定的域,而不是使用硬编码的IP地址。具体而言,我们检测到被联系的21个唯一域名,不包括只是解析而从未实际联系的域名。被联系的域名包括明显良性的目标,如google.com和nmap.org,IRC目的地如irc.dal.net和irc.studentwine.co.uk用于僵尸网络通信,以及明显可疑的域名,如pc117.zz.ha.cn或www.weigongkai.com。
的请求,来自71个唯一的IP地址,分布在17个国家,其中前三个国家分别是土耳其、美国和德国。正如前面提到的,由于这些URL,例如www.banking.com/img/lib/shell3.php,从未公开过,任何知道它们的人,必须是因为一个Shell,要么通过客户端,要么通过服务器端homephoning,向攻击者泄漏了其精确的URL。
这690个请求针对了我们541个监控的Shell中的30个,这表明并不是所有的homephoning Shell最终都会被攻击者访问。这可能是因为意外的homephoning,接收方不知道Shell正在联系他们,或者是因为攻击者不再存在以回应homephoning请求。在第7节中,我们将展示竞争的攻击者或防御者如何利用这种行为来劫持Web Shell。
图5显示了我们的蜜罐Web Shell每天收到的请求时间序列。尽管每天的请求数量变化很大,但平滑后的平均值显示,请求的数量稳步增加,直到我们监测期间的中期左右,然后稳步减少,直到我们的8周实验结束。这种行为在直观上是有道理的,因为一开始不同的攻击者在不同的时间发现了homephoning请求,并访问了这些Shell有前景的URL。由于我们的蜜罐服务器总是以HTTP 404 Page not found错误响应,攻击者慢慢地开始放弃他们的潜在目标,也许将这些错误归因于网站管理员的成功“清理”。
Analysis of server-side activity
在前一节中,我们在其他内容中计算了执行服务器端homephoning的Shell的百分比。然而,homephoning只是服务器内的Web Shell可以执行的许多可能操作之一。在本节中,我们提供了与Shell相关的服务器端活动的高级概述,重点关注仅仅加载Web Shell的主页而导致的活动,即不是由Shell操作的攻击者触发的活动。
为了发现这种服务器端活动,我们首先自动重写了我们DYN ANALYSIS集合中的所有541个Shell,以插入所有感兴趣的功能。我们通过使用PHP的runkit框架进行这种插入[28],这允许我们记录任意系统函数的调用,以及它们的参数,然后允许这些函数继续执行。在我们的情况下,感兴趣的函数包括允许Shell执行系统命令(例如exec、system和shell_exec)的函数,以及用于读写文件的函数(例如fopen、file_get_contents和file_put_contents)。然后,我们使用与发现服务器端homephoning相同的设置,使用OpenWPM框架访问修改后的Shell。
从我们的541个Shell中,有170个Shell(31.4%)调用了我们至少一个受监控的函数,其中128个Shell执行系统命令,59个Shell与文件系统交互。图4显示了在Shell中受监控的PHP函数的整体受欢迎程度,表明exec和fopen函数比它们的替代品更受欢迎。
表2显示了常常被访问和修改的文件。除了本地文件外,一些Shell使用fopen来打开和读取远程URL。在其他情况下,我们目睹了远程配置文本文件的读取,获取扩展Shell功能的附加PHP代码,以及使用fopen作为服务器端homephoning的方法(例如http://attacker.com/update.bin/admin.php?add=URL_of_the_shell)。在本地文件访问方面,一些Shell通过读取和写入重要的系统配置文件(如/etc/passwd和/etc/hosts)来表现其恶意行为。BIND DNS服务器的配置文件named.conf在恶意Web Shell中特别受欢迎。据推测,Shell可以修改BIND的配置以更改特定域名的解析方式,或者使用恶意DNS条目污染本地服务器。
表3呈现了常见系统调用的分组。在大多数情况下,Shell收集不同的系统信息,包括当前用户和操作系统类型、文件系统,甚至运行进程的列表。一个意想不到的发现是,一些Shell检查系统是否安装了特定的应用程序。除了查询Java和Perl的版本外,一些Shell使用which Linux实用程序检查安装的与安全相关的软件,例如,防病毒程序(例如node32和drwebd)和入侵检测系统(例如snort和rkhunter)。我们还注意到,许多Shell使用wget来下载http://www.google.com来检查Internet连接,并检查结果。在某些情况下,Shell不是下载google.com的主页,而是使用wget来获取以图像相关扩展名(例如.jpg)结尾的文件,然后将其重命名为.pl(Perl脚本)并执行它。我们怀疑Shell遵循这种模式是为了逃避寻找可疑下载的入侵检测系统。
相关文章:
Web安全研究(四)
No Honor Among Thieves: A Large-Scale Analysis of Malicious Web Shells Stony Brook University Ruhr-University Bochum Web shell作为恶意脚本,攻击者将其上传到被攻陷的Web服务器,以远程执行任意命令、维护其访问权限并提升其特权。尽管在实践中它…...
【CS324】Large Language Models(持续更新)
note 文章目录 note一、引言二、大模型的能力三、大模型的有害性(上)四、大模型的有害性(下)五、大模型的数据Reference 一、引言 语言模型最初是在信息理论的背景下研究的,可以用来估计英语的熵。 熵用于度量概率分布…...
【学习笔记】「2020-2021 集训队作业」Communication Network
有点难😅 发现容斥系数设计的非常巧妙🤔 设 f ( i ) f(i) f(i)表示恰好有 i i i条边相同的方案数, g ( i ) g(i) g(i)表示至少有 i i i条边相同的方案数 根据二项式反演, g ( i ) ∑ j ≥ i ( j i ) f ( j ) ⇒ f ( i ) ∑ j…...
文章参考链接
文章参考: 前端 echsrt横轴文字过长,…展示【link】js数组去重【link】js数据是String去重【link】js数据是对象去重【link】小程序使用wxml-to-canvas【link】vantui【link】微信小程序使用vantui组件【link】【link】微信小程序,选项卡页面…...
SQLI-labs-第七关
知识点:单引号()加括号闭合错误的布尔盲注 思路: 寻找注入点 我们首先看一下正常的回显,并没有显示出什么明显的信息 输入?id1 发现报错 输入?id1 -- 还是报错,说明SQL语句的语法错误可能不是单引号闭合…...
腾讯云轻量2核4G5M服务器_CPU内存_流量_带宽_系统盘
腾讯云轻量2核4G5M服务器:CPU内存流量带宽系统盘性能测评:轻量应用服务器2核4G5M带宽,免费500GB月流量,60GB系统盘SSD盘,5M带宽下载速度可达640KB/秒,流量超额按照0.8元每GB支付流量费,轻量2核4…...
从零开始搭建Apache服务器并使用内网穿透技术实现公网访问
Apache服务安装配置与结合内网穿透实现公网访问 文章目录 Apache服务安装配置与结合内网穿透实现公网访问前言1.Apache服务安装配置1.1 进入官网下载安装包1.2 Apache服务配置 2.安装cpolar内网穿透2.1 注册cpolar账号2.2 下载cpolar客户端 3. 获取远程桌面公网地址3.1 登录cpo…...
unordered_map和unordered_set的使用
前言 在C98中,STL提供了底层为红黑树的结构的一系列关联式容器,在查询时效率可以达到logN,即使最差的情况下需要比较红黑树的高度次,当树中的节点较多时,查询的效率也不是很理想,最好的查询是,进…...
javascript【格式化时间日期】
javascript【格式化时间日期】 操作: (1) 日期格式化代码 /*** 日期格式化函数<br/>* 调用格式:需要使用日期对象调用* <p> new Date().Format("yyyy/MM/dd HH:mm:ss"); </p>* param fmt 日期格式* returns {*} 返回格式化…...
CCC数字钥匙设计【NFC】--什么是AID?
1、NFC中的AID是什么? AID,英文全称为Application Identifier,这是NFC技术中的概念,AID用于唯一标识一个应用。 NFC应用的AID相关操作,包括注册和删除应用的AID、查询应用是否是指定AID的默认应用、获取应用的AID等 …...
变压器耐压试验电压及电源容量的计算
被试变压器的额定电压为(11081. 25%) /10. 5kV, 联接组标号为 YNd11。 试验时高压分接开关置于第 1 分接位置, 即高压侧电压为 126kV, 高、 低压电压比 K1126/(√310. 5) 6. 93。 现以 A 相试验…...
uniapp实现底部弹出菜单选择
其实uniapp有内置的组件,不用自己去实现,类似于这样: uni.showActionSheet({itemList: [菜单一, 菜单二, 菜单三],success: function (res) {console.log(选中了第${res.tapIndex 1}个菜单);},fail: function (res) {console.log(res.errMs…...
14. 线性代数 - 线性方程组
文章目录 线性方程组矩阵行列式全排列和逆序数N阶行列式(非)齐次线性方程Hi,大家好。我是茶桁。 结束了「微积分」部分的学习之后我们稍作休整,今天正式开始另外一部分:「线性代数」的学习。小伙伴们放松完回来要开始紧张起来了。 我们之前说过,不管是哪一个工程学科,根…...
C++QT day4
仿照string类,完成myString类 #include <iostream> #include <cstring> using namespace std; class myString {private:char *str; //记录c风格的字符串int size; //记录字符串的实际长度public://无参构造myString():size(10){s…...
Python中的 if __name__ ==‘main‘
你编写的程序迟早需要创建目录以便在其中存储数据。 os 和 pathlib 包含了创建目录的函数。我们将会考虑如下方法: | 方法 | 描述 | | -------------------- | -------------------------- | | os.mkdir() | 创建单个子目录 | | os.makedirs() | 创建多个目录&…...
github 创建自己的分支 并下载代码
github创建自己的分支 并下载代码 目录概述需求: 设计思路实现思路分析1.进入到master分支,git checkout master;2.master-slave的个人远程仓库3.爬虫调度器4.建立本地分支与个人远程分支之间的联系5.master 拓展实现 参考资料和推荐阅读 Survive by day…...
算法:贪心---跳一跳
1、题目: 给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。 2…...
机器学习入门教学——梯度下降、梯度上升
1、简介 梯度表示某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向(梯度的方向)变化最快,变化率(梯度的模)最大,可理解为导数。梯度上升和梯度下降是优化算法中常用的…...
BUUCTF Reverse/[羊城杯 2020]login(python程序)
查看信息,python文件 动调了一下,该程序创建了一个线程来读入数据,而这个线程的代码应该是放在内存中直接执行的,本地看不到代码,很蛋疼 查了下可以用PyInstaller Extractor工具来解包,可以参考这个Python解包及反编译…...
indexDB localForage
一、前言 前端本地化存储算是一个老生常谈的话题了,我们对于 cookies、Web Storage(sessionStorage、localStorage)的使用已经非常熟悉,在面试与实际操作之中也会经常遇到相关的问题,但这些本地化存储的方式还存在一些…...
Spring Boot开发时Java对象和Json对象互转
🙈作者简介:练习时长两年半的Java up主 🙉个人主页:程序员老茶 🙊 ps:点赞👍是免费的,却可以让写博客的作者开兴好久好久😎 📚系列专栏:Java全栈,…...
C++ 多态
引例: #include<iostream> using namespace std; class Animal { public:void speak(){cout<<"动物在说话"<<endl;} }; class Cat:public Animal { public:void speak(){cout<<"小猫在说话"<<endl;} }; void Do…...
LeetCode 之 二分查找
网址: LeetCode 704.二分查找 算法模拟: Algorithm Visualizer 在线工具: C 在线工具 如果习惯性使用Visual Studio Code进行编译运行,需要C11特性的支持,可参考博客: VisualStudio Code 支持C11插件配…...
【性能测试】中间件优化
1、Tomcat 优化连接数、线程池 打开tomcat安装目录\conf\server.xml文件,在server.xml中 有以下配置: tomcat HTTP/1.1 <Connector port"8080" protocol"HTTP/1.1" maxThreads"1000" acceptCount"1500" c…...
【算法】查找类——二分查找算法
二分查找算法算法总结 算法描述 该算法属于查找算法。当需要从有序数组中查找某一元素时,可以使用该算法进行查找。(本文章假设数组是升序排列的数组) 算法思想 每次进行对半查找,获取中间元素值,然后与目标值进行…...
Ansible FIle模块,使用Ansible File模块进行文件管理
当使用 Ansible 进行自动化配置和管理时,file 模块是一个强大的工具,用于在目标主机上创建、修改和删除文件和目录。它提供了一种简单而灵活的方式来处理文件系统操作。在本文中,我们将详细介绍如何使用 Ansible 的 file 模块。 1. 创建文件 …...
索尼mp4变成rsv修复案例(ILME-FX3)
索尼mp4的修复案例讲过很多,这次是索尼的ILME-FX3也算是一个畅销的机型,一般索尼没有封装的文件是RSV文件,但是极少遇到有多个RSV文件的,下边我们来讲下这个特殊案例。 故障文件:4个RSV文件,大小在1.78G~28G多 故障现…...
抓拍摄像机开关量控制4K高清手机远程看图建筑生长定时缩时相机
作为物联网数据采集解决方案专业提供商,数采物联网小编daq-iot 在这里做以下内容介绍,并诚挚的欢迎大家讨论和交流。 项目案例参考视频: https://www.bilibili.com/video/BV1Kp4y1T7wQ/?spm_id_from333.999.0.0 4K高清太阳能供电定时拍照相机,通过光…...
c++使用http请求-drogon框架
创建drogon框架 drogon_ctl create project test_ctrl添加一个控制器 进入controllers目录下 drogon_ctl create controller -h check_ctrl编写主函数 #include <drogon/drogon.h> int main() {//Set HTTP listener address and port//drogon::app().addListener("…...
幼儿棒球运动宣传介绍·野球6号位
幼儿棒球运动宣传介绍 1. 棒球对幼儿成长的重要性 棒球运动对幼儿协调能力和团队协作的培养 棒球运动对幼儿协调能力和团队协作的培养非常重要。通过棒球运动,孩子们可以学习如何与队友合作,如何在压力下保持冷静,以及如何快速做出决策。这…...
如何给自己的网站做seo/深圳网站设计制作
此篇算是对http://www.cnblogs.com/insus/archive/2012/04/17/2454620.html重构升级。因为网友需要不但能禁用还能可以启用DropDownList的Items。为了不想用户写太多代码。Insus.NET写了一个类别,并让它继承了System.Web.UI.WebControls命名空间下的DropDownList. 可…...
手机网站开发隐藏网址/网页设计费用报价
现在企业正常需要考虑两种类型的云计算,公有云和私有云。人们自然需要一些术语来描述公共云和私有云之间的应用程序和数据传输,并将此架构定义为混合云。尽管公共云和私有云独立运行,但这种数据共享可以通过使用加密连接来实现。这种加密的高…...
做网站到底能不能赚钱/销售的技巧与口才
用EditPlus打造你自己的IDE 因为对微软的notepad有点审美疲劳,所以常用EditPlus或UltraEdit32代替之.这两个文本编辑器功能比notepad强太多了.对程序员而言,本文只讲一下他的两个特点,用它来打造我们自己的IDE.希望对大家有用.1.程序高亮显示写程序的人长期处于某种临界状态,用…...
投诉举报网站 建设方案/seo搜索优化推广
原标题:用于可解释机器学习的四个Python库【IT168 技术】我们知道,人工智能也可能存在偏差,随着大家对这一点的关注度越来越高,企业越来越需要能够对其模型产生的预测进行解释,了解模型本身是如何工作的。好的一点是&a…...
哪个网站做3d模型/b2b免费推广网站
为什么80%的码农都做不了架构师?>>> 计算机网络知识 讲述计算机网络的最经典的当属Andrew S.Tanenbaum的《计算机网络》第五版,这本书难易适中。 目前已经是第五版,本书作者80年代就开发出MINIX,是一个用于…...
erp二次开发好还是网站开发好/合肥关键词排名优化
前言 亲爱的各位Android程序员,您们好: 我理解您们的焦虑和困惑,但我想告诉您的是:作为一名Android程序员,您依然是非常有前途和市场需求的职业人才。 首先,您要知道,移动互联网时代的普及率…...