参考:The Web Application Hackers Handbook Chapter 11
1.示例4:自己购买保险(Example 4: Rolling Your Own Insurance)
作者在金融服务公司部署的Web应用程序中遇到了此逻辑缺陷。
1.1 功能性(The Functionality)
该应用程序使用户可以获取保险报价,并在需要时在线填写和提交保险申请。 该过程分为十二个阶段:
- 在第一阶段,申请人提交了一些基本信息,并指定了偏好的月度保费或他想要购买的保险价值。 申请提供报价,计算申请人未指定的任何值。
- 在多个阶段中,申请人提供了其他各种个人详细信息,包括健康,职业和消遣。
- 最终,申请被转交给保险公司的承销商。 承销商使用相同的Web应用程序查看详细信息,并决定是按原样接受应用程序还是修改初始报价以反映任何其他风险。
在所描述的每个阶段中,应用程序都使用一个共享组件来处理提交给它的用户数据的每个参数。 该组件将每个POST请求中的所有数据解析为名称/值对,并使用接收到的每个数据项更新其状态信息。
1.2 假设(The Assumption)
处理用户提供的数据的组件假定每个请求将仅包含以相关HTML格式从用户请求的参数。 开发人员没有考虑如果用户提交了不要求他提供的参数会发生什么情况。
1.3 攻击(The Attack)
当然,该假设是不可行的,因为用户可以在每个请求中提交任意参数名称和值。 结果,该应用程序的核心功能被多种方式破坏:
- 攻击者可能利用共享组件来绕过所有服务器端输入验证。 在报价过程的每个阶段,应用程序都会对该阶段所期望的数据进行严格的验证,并拒绝所有未通过该验证的数据。 但是共享组件使用用户提供的每个参数更新了应用程序的状态。 因此,如果攻击者通过提供应用程序在较早阶段期望的名称/值对不按顺序提交数据,则该数据将被接受和处理,而无需执行验证。 碰巧的是,这种可能性为针对承销商的存储的跨站点脚本攻击铺平了道路,该攻击允许恶意用户访问其他申请人的个人信息(请参阅第12章)。
- 攻击者可以任意价格购买保险。 在报价过程的第一个阶段,申请人指定了她偏爱的月度保费或她想要保险的价值,然后,应用程序相应地计算了其他项目。 但是,如果用户在稍后阶段为这两项中的一项或两项提供了新值,则应用程序的状态将使用这些值进行更新。 通过不按顺序提交这些参数,攻击者可以获得任意价值和任意月度保费的保险报价。
- 没有关于给定类型的用户可以提供哪些参数的访问控制。 承销商审查完成的申请时,他更新了各种数据,包括验收决定。 共享组件以与普通用户提供的数据相同的方式处理此数据。 如果攻击者知道或猜测了包销商审查申请时使用的参数名称,则攻击者可以简单地提交这些名称,从而接受他自己的申请而无需任何实际的承销。
HACK STEPS
此应用程序中的缺陷是其安全性的基础,但是攻击者仅通过拦截浏览器请求并修改要提交的参数值就不会识别出它们。
- 1.每当应用程序在多个阶段中实施关键操作时,您都应采用在流程的一个阶段中提交的参数,然后尝试将其提交到其他阶段。 如果在应用程序的状态下更新了相关数据项,则应探索此行为的后果,以确定是否可以利用它来执行任何恶意操作,如前三个示例中所示。
- 2.如果应用程序实现的功能使不同类别的用户可以更新或对共同的数据集执行其他操作,则应使用每种类型的用户逐步执行该过程,并观察所提交的参数。 如果通常由不同用户提交不同的参数,则采用一个用户提交的每个参数,然后尝试将其作为另一用户提交。 如果该参数被该用户接受并处理,请按照前面所述探索此行为的含义。
2.示例5:破产(Example 5: Breaking the Bank)
作者在一家大型金融服务公司部署的Web应用程序中遇到了此逻辑缺陷。
2.1 功能性(The Functionality)
该应用程序使尚未使用在线应用程序的现有客户进行注册。 新用户必须提供一些基本的个人信息,以一定程度地确保其身份。 该信息包括姓名,地址和出生日期,但不包括任何秘密,例如现有的密码或PIN。
正确输入此信息后,应用程序会将注册请求转发到后端系统进行处理。 信息包已邮寄到用户的注册家庭地址。 该包装包括说明通过致电公司呼叫中心的电话激活她的在线访问权限,以及用于首次登录该应用程序时使用的一次性密码。
2.2 假设(The Assumption)
该应用程序的设计者认为,此机制可提供强大的防御功能,以防止未经授权访问该应用程序。 该机制实现了三层保护:
- 预先需要少量的个人数据,以阻止恶意攻击者或恶作剧的用户尝试代表其他用户启动注册过程。
- 该过程涉及将密钥秘密带外传输到客户的注册家庭地址。 攻击者需要访问受害者的个人邮件。
- 要求客户根据个人信息和PIN码中的选定数字,以常规方式给呼叫中心打电话并进行身份验证。
这种设计确实很坚固。 逻辑缺陷在于该机制的实现。
实施注册机制的开发人员需要一种方法来存储用户提交的个人数据,并将其与公司数据库中的唯一客户身份相关联。 热衷于重用现有代码,他们遇到了以下类,这些类似乎可以满足其目的:
class CCustomer
{
String firstName;
String lastName;
CDoB dob;
CAddress homeAddress;
long custNumber;
...
捕获用户信息后,将实例化该对象,并使用提供的信息填充该对象,并将其存储在用户会话中。 然后,该应用程序将验证用户的详细信息,如果有效,则检索该用户的唯一客户编号,该编号已在公司的所有系统中使用。 此数字以及有关用户的其他一些有用信息已添加到对象中。 然后将该对象传输到相关的后端系统,以处理注册请求。
开发人员认为使用此代码组件是无害的,不会导致安全问题。 但是,这一假设是有缺陷的,具有严重的后果。
2.3 攻击(The Attack)
合并到注册功能中的同一代码组件也已在应用程序的其他位置使用,包括在核心功能中。 这使经过身份验证的用户可以访问帐户详细信息,对帐单,资金转帐和其他信息。 当注册用户成功向应用程序验证自己的身份时,将实例化该对象并将其保存在其会话中以存储有关其身份的关键信息。 应用程序中的大多数功能都引用了其中的信息反对采取行动。 例如,根据包含在此对象中的唯一客户编号生成在其主页上显示给用户的帐户详细信息。
在应用程序中已经采用了代码组件的方式意味着开发人员的假设出现了偏差,而他们重用它的方式确实打开了一个明显的漏洞。
尽管该漏洞很严重,但实际上它的检测和利用相对比较隐蔽。 对主要应用程序功能的访问受到多层访问控制的保护,并且用户需要具有完全经过身份验证的会话才能传递这些控件。 因此,要利用逻辑缺陷,攻击者需要执行以下步骤:
- 使用他自己的有效帐户凭据登录到应用程序。
- 使用产生的经过身份验证的会话,访问注册功能并提交其他客户的个人信息。 这导致应用程序用与目标客户有关的新对象覆盖攻击者会话中的原始
CCustomer
对象。 - 返回主要应用程序功能并访问另一个客户的帐户。
从黑匣子的角度探查应用程序时,很难检测到这种漏洞。 但是,在查看或编写实际源代码时也很难确定。 如果对整个应用程序以及在不同领域中如何使用不同的组件没有清晰的了解,开发人员可能会犯下的假想。 当然,注释清晰的源代码和设计文档将减少引入或保留此类缺陷的可能性。
HACK STEPS
-
- 在涉及水平或垂直特权隔离的复杂应用程序中,尝试查找单个用户可以在其会话中积累某种程度上与其身份相关的状态的任何实例。
- 2.尝试单步执行功能的区域,然后切换到不相关的区域,以确定是否有任何累积的状态信息对应用程序的行为有影响。
3.示例6:超越业务极限(Example 6: Beating a Business Limit)
作者在制造公司内使用的基于Web的企业资源计划应用程序中遇到了这种逻辑缺陷。
3.1 功能性(The Functionality)
财务人员可以在公司与其主要客户和供应商拥有的各种银行帐户之间进行资金转帐。 为了防止欺诈,该应用程序阻止了大多数用户处理价值超过10,000美元的转账。 任何大于此的调动都需要高级经理的批准。
3.2 假设(The Assumption)
负责在应用程序中执行此检查的代码很简单:
bool CAuthCheck::RequiresApproval(int amount)
{
if (amount <= m_apprThreshold)
return false;
else return true;
}
开发人员认为此透明检查是防弹的。 超过配置的阈值的任何交易都无法逃脱二次批准的要求。
3.3 攻击(The Attack)
开发人员的假设被否决了,因为他们忽略了用户尝试以负数处理转账的可能性。 任何负数都将清除批准测试,因为它小于阈值。 但是,该应用程序的银行模块接受负转账,并简单地将它们视为相反方向上的正转账。 因此,任何想要将$ 20,000从帐户A转移到帐户B的用户都可以简单地将– $ 20,000从帐户B转移到帐户A,效果相同,无需批准。 内置在应用程序中的反欺诈防御可以轻松绕开!
NOTE
许多类型的Web应用程序在其业务逻辑中采用数字限制:
- 零售应用程序可能会阻止用户订购的数量超过库存中可用的数量。
- 银行业务应用程序可能会阻止用户支付超出其当前帐户余额的账单。
- 保险申请可以根据年龄阈值调整其报价。
寻找突破这种限制的方法通常并不代表应用程序本身的安全性受到损害。 但是,它可能会带来严重的业务后果,并且违反了所有者依赖应用程序执行的控制措施。
通常在启动应用程序之前进行的用户接受测试期间会检测到此类最明显的漏洞。 但是,问题的更微妙的表现可能仍然存在,尤其是在操纵隐藏参数时。
HACK STEPS
尝试突破业务限制的第一步是了解在您控制的相关输入中接受了哪些字符。
-
- 尝试输入负值,然后查看应用程序是否接受它们并按照您期望的方式处理它们。
-
- 您可能需要执行几个步骤来设计应用程序状态的更改,以便将其用于有用的目的。 例如,可能需要在帐户之间进行几次转帐,直到累积了可以实际提取的适当余额为止。
Chapter 11 Attacking Application Logic(2)-Real-World Logic Flaws(1)
Chapter 11 Attacking Application Logic(2)-Real-World Logic Flaws(3)