【问题标题】:Fastest way to bruteforce a string using a DOS wildcard使用 DOS 通配符暴力破解字符串的最快方法
【发布时间】:2009-05-14 19:01:47
【问题描述】:

这个问题类似于盲目的 SQL 注入。目标是确定字符串的确切值,您唯一能做的测试是查看您指定的 DOS 样式通配符(?= 任意字符,* = 任意数量的任意字符)是否与字符串匹配。 (所以实际上你只能访问bool DoesWildcardMatch(string wildcard) 函数)。

直接的方法是测试a*, b*, c*...,直到找到第一个字母,然后重复。我能想到的一些优化:

  • 搜索*a*, *b*等确定字符集
  • 找到*x* 上的匹配项时,执行divide-et-impera (*a*x*, *b*x*, ...)

【问题讨论】:

  • 关于字符串的各种问题:字符集可以是什么?只允许字母还是其他字符?字符串可以有多长?小写/大写重要吗?
  • 我真的不明白这些信息将如何帮助您想出一个有效的算法,但既然你问了 - 在我的特殊情况下,字符串是一个 Internet 主机名,所以它是字母数字和几个符号,如 .和 -.
  • 大小写无所谓 - ?完全匹配一个符号,* 匹配零个或多个符号,并且每个其他符号都完全匹配该符号(如果不区分大小写,您可以认为小写和大写符号相等)。字母表也无关紧要(除了如何处理字母表中的 ? 和 * )。如果对字母大小、字符串长度、符号频率或字母大小与字符串长度的比率有任何假设,可能会很有趣。

标签: algorithm string wildcard brute-force


【解决方案1】:

第一个想法。您可以确定O(log2(n))中字符串的长度n

  • 检查Z*,其中Z 表示k 问号,从0 开始,然后是1,然后每次检查都将问号数量加倍,直到没有匹配项出现。 n 必须介于 k / 2k 之间
  • 使用与二进制搜索相同的方式更改k 的相同模式查找确切长度。

知道确切的长度可能有助于在空间域中执行一种分而治之。

更新

如果知道长度,就可以使用相同的模式正确定位符号。

例子:

..X。 ..XX(为便于阅读添加了空格) + 符号可能是 X - 符号不是 X X 符号是 X *X* => 匹配 ++++ ++++ *X* ???? => 匹配 ++++ ++++ *X*?? ??? => 不匹配 --++ ++++ ??X? ??? => 匹配 --X+ ++++ ??XX???? => 不匹配 --X- ++++ ??X? *X*?? => 不匹配 --X- --++ ??X? ??X? => 匹配 --X- --X+ ??X? ??XX => 匹配 --X- --XX

对于字符串长度n 和字母大小m,这大约需要O(log2(n)) 才能找到字符串的长度,大约需要O(n • log2(n)) 才能正确放置n 符号,以及O(m) 才能找到使用过的符号符号 - 将所有符号加在一起产生O(n • log2(n) + m)

我可以想象,可以通过合并几个步骤来加快速度 - 可能在确定字符串长度的同时测试使用的符号,或者同时在字符串的前半部分和后半部分定位两个(甚至更多?)符号。如果检查失败,这将需要单独重新检查合并的步骤,以确定哪个检查失败。但只要合并检查成功,您就可以获得两者的信息。

也许我明天会计算一下,看看它是否真的会加快速度。

【讨论】:

  • 让我们看看。如果我们有一个大小为 m 的字母表和一个固定大小为 n 的字符串,那么一个字符串包含 n * log(m) 位信息。每个查询最多只能获取 1 位信息。因此,您至少需要 O(n log(m)) 查询。这可以大于 O(n log(n) + m)。所以你的答案一定是错的。
  • 不,我也这么认为。但是我们每次检查可以获得不止一位。例如,如果 A 失败,我们知道 n 个符号中没有一个等于 A,并且我们通过一次检查获得了多于一位的信息。
  • 更准确地说,它取决于字符串的长度,获得多少信息。失败的 A 检查将搜索空间从 m^n 减少到 (m - 1)^n,因此从 n * log2(m) 减少到 n * (log2(m - 1)) 位。对于 n > 1 / log2(m / m - 1),我们获得的信息不止一位。在 m = 26 的情况下,这需要 n > 18。
  • 加快匹配速度的一个很好的方法是一个单词列表——你说它是一个主机名,所以例如搜索“.com”、“.org”等后缀是可能的
【解决方案2】:

至于分而治之,请务必跟踪您知道不存在的价值。我也不会使用a, b, c,而是使用频率顺序。其中的某种马尔可夫链可能会使其更快。

需要注意的一点是,您不能假设给定的文字总是与输入中的相同位置匹配。这对于在最后删除通配符特别有意义。

c a b a
--------
* a *     match
  * b*a*  woops!

【讨论】:

  • 关于频率 - 是的,这很明显,我只是忘了提及。关于divide-et-impera的好点。
【解决方案3】:

如果特定数量的 ?有效,你也可以检查“?”,“??”,“???”等等来获取字符串的长度,但我怀疑这会有所帮助,因为您还可以在每轮之后只进行一次额外检查而无需任何通配符来检查您是否得到了正确的长度。

我认为之前带有字符集检查的除法几乎是最佳的,还有一些额外的细节,例如如果你匹配*a*b*,你应该在之后检查*ab*以了解两者之间是否有字母当然如上所述,在此之后检查*ab和“ab”以了解您是否完成了右侧或完全。

【讨论】:

    【解决方案4】:

    为什么不将 DOS 风格的通配符字符串转换为正则表达式?例如:

    ?a*

    变成:

    .a.*

    然后只需执行一个简单的正则表达式匹配,将其与您的测试字符串进行比较。

    【讨论】:

    • 对不起,我只是不明白正则表达式如何帮助解决这个问题。从代码的角度来看,假设您只能调用一个接受 DOS 通配符并返回布尔值的函数,说明我们需要确定的字符串是否与给定的通配符匹配。我们无法根据正则表达式测试未知字符串。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-04
    • 2015-04-25
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多