欢迎访问Sunbet官网(www.sunbet.us),Allbet欧博官网(www.ALLbetgame.us)!

首页Sunbet_安全防护正文

应用 Z3 SMT 束缚求解破解弱随机数算法_申博sunbet官网

b9e08c31ae1faa592020-08-09143技术

申博sunbet官网

申博sunbet官网聚集了多年来各路网站最全面的小游戏,本站特色的投注游戏,无论您是居家休闲还是想有效投资,在太阳城申博,只需充值小额,就能本金翻倍,一秒回帐,赚钱就是能这么轻松!详情敬请登录申博官网,完成注册,即刻体验同真人对战的非一般游戏触感!

,

0x00 基础引见

这篇文章主假如引见Z3,它是麻省理工学院的一款SMT求解器,将议论SMT求解器的一些典范用法,展现怎样运用Z3的Python绑定生成束缚,并供应运用此手艺举行WebApp平安测试的示例。

SMT求解器运用局限异常普遍,适用于从展望genomic regulatory logic到designing microfluidic systems 和 validating cloud network configurations。从本质上讲,SMT求解器供应了一种正式的要领来探究和推理庞杂的相互依赖的体系。

SMT求解器的一个主要运用是情势考证,比方,软件的标记实行,输入剖析和平安测试。此种别中的一些异常好用的东西包括Microsoft Research的SAGE,KLEE,S2E和Triton。对标记实行运用迥殊有效的SMT求解器包括Z3,STP,Z3str2和Boolector。

这篇文章分为三个部份,第一部份引见了Z3的Python绑定,并演示了怎样举行束缚求解。第二部份引见了线性同余生成器的观点,并演示了Z3怎样用于展望PRNG输出。末了,第三部份扩大了第二部份中运用的模子,以演示运用OWASP Benchmark要领的实际运用。

0x01  引见Z3

在深入研讨更庞杂的题目之前,我们会先演示一下怎样对数学困难举行建模。我们的目的是让读者熟习运用Z3的Python绑定束缚求解。因而,假如你已很熟习Z3了,可以直接跳到第二部份。

我们运用一个典范的编程题目作为切入点:编写一个接收两个参数N和n并返回布尔值的函数,函数搜检是不是存在n个一连自然数(不包括零)使得∑ n i = 1 a i = N

假如你还记得这类盘算题目,实在可以运用Gauss’s tric来盘算总和:

应用 Z3 SMT 束缚求解破解弱随机数算法_申博sunbet官网  技术 第1张应用 Z3 SMT 束缚求解破解弱随机数算法_申博sunbet官网  技术 第2张

或许运用简化要领:

应用 Z3 SMT 束缚求解破解弱随机数算法_申博sunbet官网  技术 第1张应用 Z3 SMT 束缚求解破解弱随机数算法_申博sunbet官网  技术 第4张

运用这个公式,我们可以盘算出一个候选者。假如候选者是自然数,则该函数应当返回true,不然就是假。代码虽然简朴,但须要一些推导。

如今让我们将这个题目看做一个束缚体系。第一个束缚是:

ai+1=ai+1

别的,我们应当对总和有一个束缚:

n∑i=1ai=N

让我们将这些束缚转换为Z3模子:

 import z3 as z
 z.set_param('parallel.enable', False)

起首,定义我们的目的:

 n = 3
 N = 1050

接下来将生成一些标记变量。标记变量(与我们稍后将运用的详细变量相对)充任占位符。它们的行动相似于Z3的键入机制,并协助它挑选适宜的处置惩罚方案战略。另外,只需模子可以满足,就可以运用标记变量从模子中提取详细值。

注重运用列表推导(背面我们将普遍运用字典明白)和f-strings来生成具有唯一称号的多个标记变量。

 ints = [z.Int(f'int_{i}') for i in range(n)]

如今将实例化一个求解器对象。解算器对象接收束缚搜检,假如它们是可满足的。处置惩罚方案可以经由过程特定战略举行调解,给定中心目的,并充任Z3的前端。为了处置惩罚我们的题目,我们将设置三个束缚:

1.a0,…,an−1∈N1.a0,…,an−1∈N – non-negative natural numbers

2.ai+1=ai+12.ai+1=ai+1 – consecutive numbers

3.∑ni=1ai=N3.∑i=1nai=N – sum must equal to some predefined value

 s = z.Solver()
 
 for i in range(n-1):
     # Constraint #1
     s.add(ints[i] > 0)
     # Constraint #2
     s.add(ints[i+1] == ints[i] + 1)
 
 # Constraint #3
 s.add(z.Sum(ints) == N)

末了,我们将运用check()求解器对象的要领来测试束缚的可满足性。该check()要领返回以下相应之一:sat,不满,不可行或未知。我们的题目异常小(就限定数目而言),所以我们只能取得满足的相应。

 if s.check() == z.sat:
     m = s.model()
     print('Found a solution')
     print(f'({n} terms) {m[ints[0]].as_long()} + ... + {m[ints[n -1]].as_long()} == {N}')
 else:
     print(f'Finding {n} consecutive integers with a sum of {N} is unsatisfiable')
 Found a solution
 (3 terms) 349 + ... + 351 == 1050

如上所述,束缚是可以满足的。注重我们运用该model()要领来猎取模子对象。然后,运用标记变量运用该as_long()要领从模子对象中提取详细值。

接下来,我们将归纳综合我们的模子,并申明它可以用来提出一个更庞杂的题目。

注重:如许就返回了求解器对象,稍后可以运用解算器增加其他束缚来形貌更庞杂的模子。

 def build_solver(n: int, N: int):
     # Create symbolic variables
     ints = [z.Int(f'int{i}') for i in range(n)]
     
     # Instantiate a solver
     s = z.Solver()
     
     for i in range(n-1):
         # Consecutive numbers
         s.add(ints[i+1] == ints[i] + 1)
         # Non-zero natural numbers
         s.add(ints[i] > 0)
     
     # Sum
     s.add(z.Sum(ints) == N)
     
     return s

运用此要领,可以无缝地生成求解器对象。返回求解器对象的另一个原因是它可以让我们搜检我们的束缚,增加其他束缚,强迫求解战略等等:

 s = build_solver(n = 3, N = 1337)
 print(s)
 [int1 == int0 + 1,
  int0 > 0,
  int2 == int1 + 1,
  int1 > 0,
  int0 + int1 + int2 == 1337]

运用这类要领,可以搜检模子输入的鸠合是不是可以满足。比方,下面是在探究N = 1337的解空间:

 for i in range(3, 10):
     print(f'Sum 1337 is {build_solver(n = i, N = 1337).check()} with {i} integers')
 Sum 1337 is unsat with 3 integers
 Sum 1337 is unsat with 4 integers
 Sum 1337 is unsat with 5 integers
 Sum 1337 is unsat with 6 integers
 Sum 1337 is sat with 7 integers
 Sum 1337 is unsat with 8 integers
 Sum 1337 is unsat with 9 integers

择要:本节引见Z3和基础模子的构建。我们演示了怎样将数学题目示意为一组束缚,将模子组织逻辑封装到函数中并探究题目的解空间。鄙人一节中,我们将演示怎样运用Z3对算法举行建模并运用求解器对象提取(假定为)隐蔽的内部状况。

0x02 运用PRNG算法建模

在熟习Z3的基础特性以后,让我们尝试将这些妙技运用到实在天下的算法中。在这个例子中,我们将:

· 形貌盛行的伪随机数发生器(PRNG)的事情道理:线性同余发生器(LCG)

· 开辟一个运用Z3实行LCG的功用

· 展望LCG生成的数字序列中的下一个值

· 提取在已知LCG生成数字序列之前生成的值

· 提取用于实例化PRNG的种子

线性同余发生器(LCG)

这类功用具有数字随机数的属性(因而伪随机)。LCG是一种轮回关联,个中初始值(称为“种子”)阅历发生新数字的数学操纵。新数字将成为下次挪用函数时运用的种子。这类要领很快,只需细致挑选参数(下一节中更多关于它们),它就可以经由过程一些随机性统计测试。

有关LCG及其局限性的简短引见,请检察有关线性同余生成器的Wikipedia页面。

典范的LCG经由过程实行以下步骤生成数字:

· 经由过程幻数乘以种子

· 在乘法效果中增加另一个幻数

· 用第三个幻数取效果的模数

因而,算法的把戏数字的挑选是至关主要的。这些参数挑选不当会发生强吸引力。吸引子是动态体系的一个特性,个中输入的扰动致使输出很少或没有变化(更多关于吸引子可以在这里找到)。下面可以看到参数挑选不佳的一个例子,个中模数和被乘数之间存在简朴的乘法关联。此挑选会致使强吸引子和短周期(在反复数字之前挪用函数的次数):

应用 Z3 SMT 束缚求解破解弱随机数算法_申博sunbet官网  技术 第5张

这些图象中X轴上的值示意生成了多少个数字,Y轴示意生成的数字。关于种子值532(左图),我们看到强吸引子的行动。或许,关于种子值580(右图),我们看到短周期的示例。用于生成这些图象的小递次可在此处取得。

从上面的图象可以揣摸,运用把戏小数乘数= 10&模数= 140和种子532或580,必定致使强吸引子行动。基础上,假如运用这些幻数而且生成两个提到的值中的一个,则序列的其他部份很轻易展望。比方,假定我们挑选了一个差别于532的种子,而且在生成n个挪用532以后,序列中的一切将来数字都将为0。因而,纵然挑选“强”把戏数字偶然也会致使质量随机性差。

作为一个实际的例子,我们将研讨MSVC 2013中的LCG完成,已知MSVC相对较弱(即把戏数字挑选不当)。

在MSVC 2013中完成rand()

用于在MSVC 2013中完成rand()的算法是简朴LCG的一个很好的例子:

 static unsigned long int next = 1;
 
 int rand(void)  /* RAND_MAX assumed to be 32767. */
 {
     next = next * 214013 + 2531011;
     return (unsigned)(next/65536) % 32768;
 }

基于此片断,我们愿望生成运用Z3模仿算法的束缚。详细来说,假定我们有一系列由算法生成的数字:

· 我们能展望序列中的下一个值吗?

· 我们可以盘算序列中的前一个数字吗?

· 我们须要供应Z3来准确展望序列中下一个数字的最短序列是什么?

· 处置惩罚方案是不是奇特?我们能找到满足我们束缚条件的其他内部状况吗?

如今让我们假定我们运转了rand()10次并取得了以下数字:

 4, 54, 63, 79, 13, 55, 76, 11, 14, 45

让我们组织模仿rand()所需的束缚并回覆上述题目。 注重:经由过程打印rand()%100生成数字以将数字束缚到[0,100]局限,用于初始化该功用的种子是1337。

运用Z3模仿rand()

在这个例子中,我们将最先运用位向量(BitVec)对象。这些对象是数据存储在内存中的体式格局的标记示意,须要定义它们的大小。运用位向量许可我们运用按位运算符,我们将鄙人一个示例中普遍运用它们。在这个例子中,我们将运用位移和'按位和'运算符来示意除法和模运算。

我们起首定义一些标记变量。我们将定义两个变量(output_prev,output_next)来示意序列之前和以后生成的数字。另外,我们将定义10个state#变量来示意next代码片断中的变量。注重运用字典明白来生成state#变量。运用字典是一种有效的形式,可以以可接见的体式格局保留大批标记变量。

 output_prev = z.BitVec('output_prev', 32)
 states = {f'state_{i}': z.BitVec(f'state_{i}', 32) for i in range(1, 11)}
 output_next = z.BitVec('output_next', 32)

实例化解算器

 s = z.Solver()

如今让我们最先增加题目束缚,第一个束缚是数字序列是经由过程递次挪用生成的rand(),因而:

state_2=state_1×21401

state_3=state_2×214013+2531011

……

state_10=state_9×214013+2531011

 for i in range(2, 11):
     s.add(states[f'state_{i}'] == states[f'state_{i - 1}'] * 214013 + 2531011)
 
 print(s)
 [state_2 == state_1*214013 + 2531011,
  state_3 == state_2*214013 + 2531011,
  state_4 == state_3*214013 + 2531011,
  state_5 == state_4*214013 + 2531011,
  state_6 == state_5*214013 + 2531011,
  state_7 == state_6*214013 + 2531011,
  state_8 == state_7*214013 + 2531011,
  state_9 == state_8*214013 + 2531011,
  state_10 == state_9*214013 + 2531011]

第二个束缚示意我们为10个数字取得的值,我们将模仿return语句。在该示例中,我们将演示运用逐位操纵,以显现在某些状况下基于Z3的逐位操纵和基于Python的按位操纵怎样可以交换运用:

· 每一个状况除以65536(相当于向右移16位)

· 然后我们将剩下的除以32768(相当于做n&0x7FFF)

· 末了,提醒%100应当即是我们鸠合中的每一个数字

因而:

((state_1/65536)%32768)%100≡((state_1>>16)&0x7FFF)%100=4

((state_10/65536)%32768)%100≡((state_10>>16)&0x7FFF)%100=45

注重我们怎样运用基于python和Z3的按位运算来组织束缚。Z3为按位操纵供应了方便,但晓得运用它们不是强迫性的,这很有效。Z3按位操纵首选的一个特定状况是署名是必要的。比方,在我们的例子中,我们对无标记模数感兴致,Z3为其供应了URem要领。

 random_nums = [4, 54, 63, 79, 13, 55, 76, 11, 14, 45]
 
 for i in range(2, 10):
     s.add(z.URem((states[f'state_{i}'] >> 16) & 0x7FFF ,100) == random_nums[i - 1])

末了,我们将为系列中的下一个和上一个数字设置束缚:

 s.add(output_prev == z.URem((states['state_1'] >> 16) & 0x7FFF ,100))
 s.add(output_next == z.URem((states['state_10'] >> 16) & 0x7FFF ,100))

如今来看看我们的完整模子:

 print(s)
 [state_2 == state_1*214013 + 2531011,
  state_3 == state_2*214013 + 2531011,
  state_4 == state_3*214013 + 2531011,
  state_5 == state_4*214013 + 2531011,
  state_6 == state_5*214013 + 2531011,
  state_7 == state_6*214013 + 2531011,
  state_8 == state_7*214013 + 2531011,
  state_9 == state_8*214013 + 2531011,
  state_10 == state_9*214013 + 2531011,
  URem(state_2 >> 16 & 32767, 100) == 54,
  URem(state_3 >> 16 & 32767, 100) == 63,
  URem(state_4 >> 16 & 32767, 100) == 79,
  URem(state_5 >> 16 & 32767, 100) == 13,
  URem(state_6 >> 16 & 32767, 100) == 55,
  URem(state_7 >> 16 & 32767, 100) == 76,
  URem(state_8 >> 16 & 32767, 100) == 11,
  URem(state_9 >> 16 & 32767, 100) == 14,
  output_prev == URem(state_1 >> 16 & 32767, 100),
  output_next == URem(state_10 >> 16 & 32767, 100)]

从一系列10个生成的数字最先。我们组织了一组模仿rand()函数操纵的束缚。运用序列中的中心8个数字来设置函数内部状况的束缚。末了,设置束缚output_next和output_previous标记变量。假如我们的束缚是可满足的,则这两个变量应当与生成的序列中的第一个和末了一个数字坚持雷同的值。搜检一下:

 print(s.check())
 sat
 print(s.model())
 [state_3 = 3311639122,
  state_7 = 535860406,
  state_2 = 1700980091,
  state_4 = 4092565453,
  state_8 = 1173829793,
  state_5 = 2417052508,
  state_6 = 3389729967,
  state_1 = 2436150040,
  state_9 = 2200877280,
  output_next = 45,
  output_prev = 4,
  state_10 = 173405219]

结论:运用从源代码派生的一组束缚,我们可以展望序列中的下一个数字。另外,我们可以盘算序列之前的数字。

探究rand()模子的解空间

接下来,尝试找到展望下次挪用输出所需的最小值rand()。为此,我们将上述逻辑包装在一个函数中。该函数有两个参数:数字列表和序列中的下一个数字。该函数生成相干数目的束缚并搜检其可满足性。假如模子是可满足的,它会在序列中打印盘算的和预期的下一个数字。

代码段链接:

 def break_rand(nums: list, next_num: int):
     n_nums = len(nums)
     #print(f'len nums: {n_nums}')
     
     states = {f'state_{i}': z.BitVec(f'state_{i}', 32) for i in range(1, n_nums + 2)}
     #print(states)
     output_next = z.BitVec('output_next', 32)
     
     s = z.Solver()
     
     for i in range(2, n_nums + 2):
         s.add(states[f'state_{i}'] == states[f'state_{i - 1}'] * 214013 + 2531011)
         
     for i in range(1, n_nums + 1):
         s.add(z.URem((states[f'state_{i}'] >> 16) & 0x7FFF ,100) == nums[i - 1])
         
     s.add(output_next == z.URem((states[f'state_{n_nums + 1}'] >> 16) & 0x7FFF ,100))
     
     #print(s)
     
     if s.check() == z.sat:
         print(f'For the sequence: {nums}, problem is satisfiable')
         print(f'We were expecting: {next_num} and got: {s.model()[output_next]}\n')
     else:
         print(f'For the sequence: {nums}, problem is unsatisfiable')
     
     return s, states, output_next
 random_nums = [4, 54, 63, 79, 13, 55, 76, 11, 14, 45]
 for i in range(3, 10):
     break_rand(random_nums[:i], random_nums[i])
 For the sequence: [4, 54, 63], problem is satisfiable
 We were expecting: 79 and got: 94
 
 For the sequence: [4, 54, 63, 79], problem is satisfiable
 We were expecting: 13 and got: 60
 
 For the sequence: [4, 54, 63, 79, 13], problem is satisfiable
 We were expecting: 55 and got: 55
 
 For the sequence: [4, 54, 63, 79, 13, 55], problem is satisfiable
 We were expecting: 76 and got: 76
 
 For the sequence: [4, 54, 63, 79, 13, 55, 76], problem is satisfiable
 We were expecting: 11 and got: 11
 
 For the sequence: [4, 54, 63, 79, 13, 55, 76, 11], problem is satisfiable
 We were expecting: 14 and got: 14
 
 For the sequence: [4, 54, 63, 79, 13, 55, 76, 11, 14], problem is satisfiable
 We were expecting: 45 and got: 45

结论:在一切状况下,我们都能找到满足束缚条件的处置惩罚方案。虽然束缚条件令人满意,但请注重上面的前两个效果:虽然展望的下一个数字与预期值不婚配,但束缚条件是可满足的。该效果表明模子可满足性并不意味着唯一性。在求解束缚体系时,Z3返回它找到的第一个解,在我们的例子中,它会在序列中发生毛病的数字。尽管如此,当我们为求解器供应五个或更多个数时,它持之以恒地展望序列中准确的下一个数字。可以从这些效果揣摸出的另一个结论是,关于三个和四个数字的序列,最少存在发生这些数字的两个差别的内部状况。差别的内部状况发生差别的序列,同时坚持前三个或四个数字。

接下来,我们想尝试罗列满足我们束缚的一切处置惩罚方案。罗列处置惩罚方案使我们可以权衡我们处置惩罚方案的奇特性。

罗列处置惩罚方案

在本节中,我们将尝试罗列满足束缚条件的一切能够处置惩罚方案。为此,将运用求解器对象并为我们已找到的处置惩罚方案增加否认束缚。即:

state_1,…,state_n≠solution[state_1],…,solution[state_n]

为了自动化这个试验,我们将定义一个反复尝试运用求解器对象查找解法的函数。每当求解器找到一组处置惩罚束缚的差别内部状况时,我们将找到的值增加到禁用值列表中。请注重我们运用Or()和eval()作为构建束缚的替换要领。

链接到代码段。

 def enumerate_solutions(nums: list, next_num: int, print_model: bool = False, print_solutions: bool = False):
     s, states, output_next = break_rand(nums = nums, next_num = next_num)
     
     counter = 0
     solution_list = []
      
     while s.check() == z.sat:
         counter += 1
         solution_list.append(s.model()[output_next].as_long())
         
         print(f'Solution #{counter}')
         if print_model:
             print(f'{s.model()}\n')
 
         # Create constraints using string concatenation
         or_expression = 'z.Or('
         for i in states.keys():
             if i == 'output_next': continue
             or_expression += f'states[i] != s.model()[states[i]], '
         or_expression += ')'
         
         s.add(eval(or_expression))
         
     print(f'Found a total of {counter} solutions')
     if print_solutions:
         print(f'The solutions are: \n{solution_list}')
         print(f'The solution set is: \n{set(solution_list)}')
 enumerate_solutions(random_nums[:5], random_nums[5], print_model = True)
 For the sequence: [4, 54, 63, 79, 13], problem is satisfiable
 We were expecting: 55 and got: 55
 
 Solution #1
 [state_3 = 1164155474,
  state_2 = 3848463739,
  state_1 = 288666392,
  state_4 = 1945081805,
  state_5 = 269568860,
  output_next = 55,
  state_6 = 1242246319]
 
 Solution #2
 [state_3 = 3311639122,
  state_2 = 1700980091,
  state_1 = 2436150040,
  state_4 = 4092565453,
  output_next = 55,
  state_5 = 2417052508,
  state_6 = 3389729967]
 
 Found a total of 2 solutions
 enumerate_solutions(random_nums[:9], random_nums[9], print_model=True)
 For the sequence: [4, 54, 63, 79, 13, 55, 76, 11, 14], problem is satisfiable
 We were expecting: 45 and got: 45
 
 Solution #1
 [state_7 = 2683344054,
  state_2 = 3848463739,
  state_1 = 288666392,
  state_4 = 1945081805,
  state_8 = 3321313441,
  state_3 = 1164155474,
  state_5 = 269568860,
  state_6 = 1242246319,
  state_9 = 53393632,
  output_next = 45,
  state_10 = 2320888867]
 
 Solution #2
 [state_7 = 535860406,
  state_2 = 1700980091,
  state_1 = 2436150040,
  state_4 = 4092565453,
  state_9 = 2200877280,
  state_8 = 1173829793,
  state_3 = 3311639122,
  state_10 = 173405219,
  output_next = 45,
  state_5 = 2417052508,
  state_6 = 3389729967]
 
 Found a total of 2 solutions

剖析:用5或9个序号输入算法可以辨认满足束缚的两个差别的内部状况。虽然在每种状况下,我们肯定了两个差别的状况,二者都在序列中发生准确的下一个数字。另外,我们已肯定了两个差别的初始内部状况(即state1,288666392或2436150040),它们致使雷同的数字链。只需观察到最少五个一连数字,就可以展望序列中的下一个数字。

如今对4个数字的序列尝试雷同的要领(我们已晓得它们不会在链中发生准确的下一个数字)。

 enumerate_solutions(random_nums[:4], random_nums[4], print_solutions=True)
 For the sequence: [4, 54, 63, 79], problem is satisfiable
 We were expecting: 13 and got: 60
 
 Solution #1
 
 ...
 
 Solution #40
 Found a total of 40 solutions
 The solutions are: 
 [60, 49, 49, 9, 9, 29, 29, 32, 32, 18, 18, 93, 93, 69, 77, 77, 69, 67, 5, 5, 25, 25, 13, 13, 55, 55, 48, 48, 12, 12, 60, 24, 67, 24, 16, 16, 89, 89, 96, 96]
 The solution set is: 
 {5, 9, 12, 13, 16, 18, 24, 25, 29, 32, 48, 49, 55, 60, 67, 69, 77, 89, 93, 96}

剖析:用4个一连rand()算法,我们可以辨认满足束缚的40(!)个差别的内部状况。这些是每一个处置惩罚方案展望的序列中的下一个数字:

 60, 49, 49, 9, 9, 29, 29, 32, 32, 18, 18, 93, 93, 69, 77, 77, 69, 67, 5, 5, 25, 25, 13, 13, 55, 55, 48, 48, 12, 12, 60, 24, 67, 24, 16, 16, 89, 89, 96, 96

虽然内部状况是差别的,但发明的一切处置惩罚方案都必需发生序列:4,54,63,79。这意味着我们找到了一组40个初始状况(state_1)来建立这个确实的序列。另外,40种差别的处置惩罚方案仅与链中的第5个数字差别。详细来说,假如我们晓得序列中的前四个数字,那末第五个数字可以有20个差别的值。基础上,我们已找到了有限数目的能够处置惩罚方案。因而,假如我们观察到四个数字,我们可以以5%的置信度展望序列中的下一个数字。

结论:基于上面概述的试验,我们可以找到发生特定序列(伪)随机数的有限数目的初始状况。只需我们观察到足够大的一连数字序列,这个陈说就成立了。另外,好像关于MSVC 2013 rand()函数中运用的幻数(已知它们很弱),观察到5个数字的序列就足以完整放心肠展望第6个数字。

群雄争霸!2019年大学生网络安全邀请赛暨第五届上海市大学生网络安全大赛决赛在即

由上海市教育委员会主办、东华大学承办的2019年大学生网络安全邀请赛暨第五届上海市大学生网络安全大赛已于日前进行了线上初赛。 本次大赛参赛高校数、队伍数均大幅增加,远超往届,共有来自国内157所高校的365支队伍报名参加了11月2日进行的网络攻防赛线上初赛(CTF赛),最终来自北京邮电大学的天枢战队获得线上初赛第一名,与实力强大的其它29支战队一起从初赛中脱颖而出,晋级11月16日在东华大学延安路校区举行的线下决赛。此外,还有10件作品顺利进入信息安全作品赛决赛。详

上述要领的一种能够的扩大是找到发生比方四个零序列所需的种子:

 enumerate_solutions([0, 0, 0, 0], 0)
 For the sequence: [0, 0, 0, 0], problem is satisfiable
 We were expecting: 0 and got: 10
 
 Solution #1
 
 ...
 
 Solution #38
 Found a total of 38 solutions
 enumerate_solutions([0, 0, 0, 0, 0], 0)
 For the sequence: [0, 0, 0, 0, 0], problem is unsatisfiable
 Found a total of 0 solutions

结论:基于这两个试验,有38个初始状况(种子)致使四个一连的零输出,而没有种子发生五个一连的零。

0x03 将此要领扩大到实际环境的例子

我们将这类要领扩大到另一个基于LCG的PRNG。详细来说,在本教程中,重点是进击在java.util.Random class中的PRNG 。在构建可以展望值并提取种子的模子以后,我们将在实际的WebApp上测试我们的要领。

与上述MSVC 2013 rand()函数相似,该PRNG 运用种子/先前生成的数字来生成序列中的下一个数字。下面是java.util.Random该类的(部份)源代码。

   76: public class Random implements Serializable
   77: {
          ...
  121:   public Random()
  122:   {
  123:     this(System.currentTimeMillis());
  124:   }
          ...
  132:   public Random(long seed)
  133:   {
  134:     setSeed(seed);
  135:   }
          ...
  151:   public synchronized void setSeed(long seed)
  152:   {
  153:     this.seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1);
  154:     haveNextNextGaussian = false;
  155:   }
          ...
  173:   protected synchronized int next(int bits)
  174:   {
  175:     seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
  176:     return (int) (seed >>> (48 - bits));
  177:   }

来自:url

依据上面的代码,经由过程以下代码生成典范的随机数:

1.将类变量this.seed设置为外部供应的种子或 System.currentTimeMillis()

2.收到call后

 next(int bits)

· 乘以this.seed幻数0x5DEECE66D并加上幻数0xB

· 屏障47个低位this.seed(将一切其他位设置为0)

· this.seed用我们方才盘算的数字更新

· 实行(无标记)右位移,直到我们取得所需的位数

· 强迫转换为int并返回

3.以下挪用next(int bits)运用之前盘算过的this.seed

总而言之,这类要领与我们在MSVC 2013剖析过程当中看到的异常相似,只做了一些修正:

· 与MSVC 2013比拟,此完成运用更壮大的把戏数字

· 低阶位被认为是“低随机”而不是高阶位(即,具有更短的周期)。Java经由过程运用long数据范例并在转换为int之前删除低位来处置惩罚这个题目(第176行)

· 在转换之前运用位移在数据范例之间举行转换

由于我们将处置惩罚多个变量范例,因而我们将导入bitstring包,个中包括差别数值示意之间的有效转换要领。

 try:
     import bitstring as bs
 except ModuleNotFoundError:
     !pip install bitstring
     import bitstring as bs

模仿java.util.Random.next()函数

从如今最先,我们想重用一些模子。因而,下面是用于构建函数束缚的功效next()函数。注重LShR()用于逻辑(即无标记)右移和Extract()用于在差别大小的BitVec对象之间举行转换的函数。

别的,我们将运用simplify()函数。此函数剖析束缚并生成更简朴和等效的束缚,比方在以下状况中:

 # Extract the 32 least significant bits 
 # After shifting seed_0 16 bits to the right
 Extract(31, 0, LShR(seed_0, 16))

simplify()发生更轻易浏览的输出:

 Extract(47, 16, seed_0)

另外,鄙人面的示例中,我们将普遍运用BitVecVal对象。此对象的事情体式格局与此相似BitVec,但运用详细的常量值实例化对象。

注重:由于我们试图模仿next()事情体式格局,我们的模子试图完成函数署名。因而,应当晓得next()生成的位数(gen_bits)。生成的位数会影响我们挪动内部状况以取得输出(拜见源代码中的第176行)。本质上,将gen_bits设置为31会发生无标记整数,而将其设置为32会发生有标记整数。

主要申明:BitVec对象不会被署名。因而,在数学运算中运用这些对象时要警惕。

代码段链接:

 def make_constraints_next(n_constraints: int, slope: int = 0x5DEECE66D, intercept: int = 0xB, gen_bits = 31):
     # Define some constants
     addend = z.BitVecVal(intercept, 64)
     multiplier = z.BitVecVal(slope, 64)
     mask = z.BitVecVal((1 << 48) - 1, 64)
     
     # Define symbolic variables for the seed variable
     seeds = {f'seed_{i}': z.BitVec(f'seed_{i}', 64) for i in range(n_constraints)}
 
     constraints = []
     
     # Build constraints for the relation in row 175
     for i in range(1, n_constraints):
         constraints.append(seeds[f'seed_{i}'] == z.simplify((seeds[f'seed_{i-1}'] * multiplier + addend) & mask))
         
     # Define symbolic variables for the output from next()
     next_outputs = {f'next_output_{i}': z.BitVec(f'output{i}', 32) for i in range(1, n_constraints)}
     
     # Build the constraints for the relation in row 176
     for i in range(1, n_constraints):
         constraints.append(next_outputs[f'next_output_{i}'] == z.simplify(z.Extract(31, 0, z.LShR(seeds[f'seed_{i}'], 48 - gen_bits))))
         
     return constraints, seeds, next_outputs

提取Random()种子值

接下来编写一个函数,Random()依据一系列随机数提取用于实例化的种子。为了做到这一点,让我们来看看这个nextInt()函数。nextInt()有两种作风:

  238:   public int nextInt()
  239:   {
  240:     return next(32);
  241:   }
  ...
  290:   public int nextInt(int n)
  291:   {
  292:     if (n <= 0)
  293:       throw new IllegalArgumentException("n must be positive");
  294:     if ((n & -n) == n) // i.e., n is a power of 2
  295:       return (int) ((n * (long) next(31)) >> 31);
  296:     int bits, val;
  297:     do
  298:       {
  299:         bits = next(31);
  300:         val = bits % n;
  301:       }
  302:     while (bits - val + (n - 1) < 0);
  303:     return val;
  304:   }

由于已具有生成形貌的束缚的函数next(32),因而我们可以直接进击第一个变体。

试验构造以下:

· Random()运用已知种子举行实例化

· 生成随机序列 nextInt()

· 编写一个基于已知序列生成束缚的函数

· 提取用于生成序列的种子

另外,要回覆以下题目:

· 提取的种子是不是与已知种子相称?

· 种子是奇特的,照样有其他种子发生雷同的序列?

· 假如存在替换种子,它们在喂给时会发生雷同的序列Random()吗?

注重:用于实例化的种子Random()不能直接运用,以下所示:

  132:   public Random(long seed)
  133:   {
  134:     setSeed(seed);
  135:   }
          ...
  151:   public synchronized void setSeed(long seed)
  152:   {
  153:     this.seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1);
  154:     haveNextNextGaussian = false;
  155:   }

因而,在设想束缚时我们必需考虑到这一点。

 def find_seed(sequence_length: int, slope: int = 0x5DEECE66D, intercept: int = 0xB):
     # Define some constants
     addend = z.BitVecVal(intercept, 64)
     multiplier = z.BitVecVal(slope, 64)
     mask = z.BitVecVal((1 << 48) - 1, 64)
     
     # Note we're generating an extra constraint
     # This is required since we'll be using seed_0 to extract the Random() instantiation value
     next_constraints, seeds, next_outputs = make_constraints_next(n_constraints=sequence_length+1, gen_bits=32)
     
     # Define a symbolic variable that we'll use to get the value that instantiated Random()
     original_seed = z.BitVec('original_seed', 64)
     
     # Build a solver object
     s = z.Solver()
     
     # Build a constraint that relates seed_0 and the value used to instantiate Random()
     s.add(seeds[f'seed_0'] == (original_seed ^ multiplier) & mask)
     
     # Next let's add the constraints we've built for next()
     s.add(next_constraints)
     
     # Lastly, let's return all the objects we've constructed so far   
     return s, original_seed, seeds, next_outputs

我们Random()用值1337 实例化并挪用了nextInt()6次。发生的序列是:

 known_ints = [-1460590454, 747279288, -1334692577, -539670452, -501340078, -143413999]

尝试从序列中提取种子:

 solver, original_seed, seeds, next_ouputs = find_seed(sequence_length=len(known_ints))
 
 # Notice: we setup the constraints so that next_outputs_1 is the result of seed_1 since we're using seed_0 for other uses
 # Consequently, the index in known_ints is smaller by 1 than the index for next_outputs
 solver.add(next_ouputs[f'next_output_{1}'] == known_ints[0])
 solver.add(next_ouputs[f'next_output_{2}'] == known_ints[1])
 
 # Lets take a look at our constraints before trying to solve them
 print(solver)
 [seed_0 == (original_seed ^ 25214903917) & 281474976710655,
  seed_1 ==
  Concat(0, 11 + 25214903917*Extract(47, 0, seed_0)),
  seed_2 ==
  Concat(0, 11 + 25214903917*Extract(47, 0, seed_1)),
  seed_3 ==
  Concat(0, 11 + 25214903917*Extract(47, 0, seed_2)),
  seed_4 ==
  Concat(0, 11 + 25214903917*Extract(47, 0, seed_3)),
  seed_5 ==
  Concat(0, 11 + 25214903917*Extract(47, 0, seed_4)),
  seed_6 ==
  Concat(0, 11 + 25214903917*Extract(47, 0, seed_5)),
  output1 == Extract(47, 16, seed_1),
  output2 == Extract(47, 16, seed_2),
  output3 == Extract(47, 16, seed_3),
  output4 == Extract(47, 16, seed_4),
  output5 == Extract(47, 16, seed_5),
  output6 == Extract(47, 16, seed_6),
  output1 == 2834376842,
  output2 == 747279288]
 solver.check()
 sat

束缚是可以满足的,我们取得了我们预期的原始种子

 solver.model()[original_seed]
 1337

展望序列的其他部份

序列中的其他数字怎样?它们是不是相符我们已知的序列?

注重:由于运用的是BitVec对象,因而效果是无标记的。我们将运用bitstring库(别名为bs)来转换unsigned,以便我们可以将它们与signed举行比较。

 for i, known_int in enumerate(known_ints):
     calculated_int = solver.model()[next_ouputs[f'next_output_{i+1}']].as_long()
     assert bs.BitArray(uint=calculated_int, length=32).int == known_int
 print('All assertions passed')
 All assertions passed

结论:我们可以展望一切将来nextInt()挪用的输出,并Random()基于两个一连的数字提取用于实例化的种子

这些数字必需一连吗?我们是不是必需晓得序列中的第一个数字才事情?

 # Generate all possible index pair combinations for known_ints
 import itertools
 index_pairs = itertools.combinations(range(len(known_ints)), 2)
 
 # Now let's run our algorithm on each pair
 for i, j in index_pairs:
     print(f'Trying sequence indices: {i}, {j}')
     # Generate a new solver object
     solver, original_seed, seeds, next_ouputs = find_seed(sequence_length=len(known_ints))
 
     # Set constraints for the output
     solver.add(next_ouputs[f'next_output_{i+1}'] == known_ints[i])
     solver.add(next_ouputs[f'next_output_{j+1}'] == known_ints[j])
 
     assert solver.check() == z.sat
     assert solver.model()[original_seed] == 1337
     print(f'All assertions passed\n')
 Trying sequence indices: 0, 1
 All assertions passed
 
 Trying sequence indices: 0, 2
 All assertions passed
 
 Trying sequence indices: 0, 3
 All assertions passed
 
 Trying sequence indices: 0, 4
 All assertions passed
 
 Trying sequence indices: 0, 5
 All assertions passed
 
 Trying sequence indices: 1, 2
 All assertions passed
 
 Trying sequence indices: 1, 3
 All assertions passed
 
 Trying sequence indices: 1, 4
 All assertions passed
 
 Trying sequence indices: 1, 5
 All assertions passed
 
 Trying sequence indices: 2, 3
 All assertions passed
 
 Trying sequence indices: 2, 4
 All assertions passed
 
 Trying sequence indices: 2, 5
 All assertions passed
 
 Trying sequence indices: 3, 4
 All assertions passed
 
 Trying sequence indices: 3, 5
 All assertions passed
 
 Trying sequence indices: 4, 5
 All assertions passed

结论:只需我们晓得序列中的两个数字,我们就可以展望全部序列。

种子奇特性

如今已证实我们可以提取种子,我们能找到另一种发生雷同序列的种子吗?

 # Generate a new solver object
 solver, original_seed, seeds, next_ouputs = find_seed(sequence_length=len(known_ints))
 
 n_solutions = 10
 print(f'Looking for {n_solutions} unique original_seed values that produce our sequence')
 for i in range(n_solutions):
     # Set constraints for the output
     solver.add(next_ouputs[f'next_output_{1}'] == known_ints[0])
     solver.add(next_ouputs[f'next_output_{2}'] == known_ints[1])
     
     if solver.check() == z.sat:
         solution = solver.model()[original_seed].as_long()
         solution_hex = bs.BitArray(uint=solution, length=64).hex
         print(f'Found solution #{i+1}:\t 0x{solution_hex}')
         
         # Invert the solution we found
         solver.add(solver.model()[original_seed] != original_seed)
 Looking for 10 unique original_seed values that produce our sequence
 Found solution #1:  0x0000000000000539
 Found solution #2:  0x0100000000000539
 Found solution #3:  0x0200000000000539
 Found solution #4:  0x0300000000000539
 Found solution #5:  0x0002000000000539
 Found solution #6:  0x0202000000000539
 Found solution #7:  0x0102000000000539
 Found solution #8:  0x0302000000000539
 Found solution #9:  0x4000000000000539
 Found solution #10:  0x4002000000000539

剖析:我们从这个算法中取得的种子并非唯一的。从上面可以看出,16个MSB是free的,可以取任何值,而不会转变生成的序列。这个效果是有意义的,由于这些位在setSeed()运转时会立即被屏障(拜见第153行)。因而,它们不会影响序列。

模仿java.util.Random.nextLong()函数

如今我们已证实输出next()完整可以运用两个(非一连的)数字来展望,可以继承突破其他可用的Random()大众要领。也就是说,我们将处置惩罚该nextLong()要领:

 318:   public long nextLong()
 319:   {
 320:     return ((long) next(32) << 32) + next(32);
 321:   }

我们将此要领建模为我们上面所示的直接扩大。主假如,此要领的作用(请参阅Java中的优先递次以猎取更多信息)以下:

1.next(32)在括号内运用- 生成一个带标记的int

2.将int转换为long

3.将长32位向左移位

4.运用next(32)- 括号外生成另一个signed int

5.将signed int增加到long shift long

6.送还总和

基于这个完成,关于nextLong()我们生成的任何数字,我们取得的信息是损坏时取得的nextInt()信息的两倍。因而,应当可以修正先前形貌的束缚,以Random()基于一个nextLong()挪用来提取实例化值。

请注重运用BV2Int将BitVec对象转换为Int对象。在我们的示例中运用此转换迫使Z3运用算术模子,这简化了查找处置惩罚方案。

代码段链接:

 def find_seed_nextLong(sequence_length: int, slope: int = 0x5DEECE66D, intercept: int = 0xB):
     # Define some constants
     addend = z.BitVecVal(intercept, 64)
     multiplier = z.BitVecVal(slope, 64)
     mask = z.BitVecVal((1 << 48) - 1, 64)
     
     # Note we're generating double the constraints in the sequence_length + 1
     # This is required since we'll be using seed_0 to extract the Random() instantiation value
     # Furthermore, each nextLong call consumes two outputs from next()
     next_constraints, seeds, next_outputs = make_constraints_next(n_constraints=2*sequence_length+1, gen_bits=32)
     
     # Define a symbolic variable that we'll use to get the value that instantiated Random()
     original_seed = z.BitVec('original_seed', 64)
     
     # Build a solver object
     s = z.Solver()
     
     # Build a constraint that relates seed_0 and the value used to instantiate Random()
     s.add(seeds[f'seed_0'] == (original_seed ^ multiplier) & mask)
     
     # Next let's add the constraints we've built for next()
     s.add(next_constraints)
     
     # Define symbolic variables for the output from nextLong
     # Notice: we're using a symbolic variable of type Int
     # Since nextLong does a sum on ints, it's easier to model this using Z3 arithmetic models
     # This differs from previous examples where we used BitVec objects exclusively
     # Consequently, we'll be using the conversion method BV2Int that takes a BitVec object and turns it into an Int object
     nextLong_outputs = {f'nextLong_output_{i}': z.Int(f'nextLong_output_{i}') for i in range(1, sequence_length + 1)}
     
     # Finally, let's add the constraints for nextLong
     for i, j in zip(range(1, sequence_length + 1), range(1, sequence_length * 2 + 1, 2)):
         # Notice: we've replaced the bit shift operator in the source with an enquivalent multiplication
         # Z3 doesn't support bit shift operations on Int objects
         first_next = z.BV2Int(next_outputs[f'next_output_{j}'], is_signed=True) * 2 ** 32
         second_next = z.BV2Int(next_outputs[f'next_output_{j+1}'], is_signed=True)
         s.add(nextLong_outputs[f'nextLong_output_{i}'] == first_next + second_next)
     
     # Lastly, let's return all the objects we've constructed so far   
     return s, original_seed, nextLong_outputs

Random()用值1337 实例化并挪用了nextLong()4次。发生的序列是:

 known_longs = [-6273188232032513096, -5732460968968632244, -2153239239327503087, -1872204974168004231]

尝试从序列中提取种子:

 solver, original_seed, nextLong_outputs = find_seed_nextLong(sequence_length=len(known_longs))
 
 # As mentioned before, we should have enough information in one long to extract the instantiation value
 solver.add(nextLong_outputs[f'nextLong_output_{1}'] == known_longs[0])
 
 # Lets take a look at our constraints before trying to solve them
 print(solver)
 [seed_0 == (original_seed ^ 25214903917) & 281474976710655,
  seed_1 ==
  Concat(0, 11 + 25214903917*Extract(47, 0, seed_0)),
  seed_2 ==
  Concat(0, 11 + 25214903917*Extract(47, 0, seed_1)),
  seed_3 ==
  Concat(0, 11 + 25214903917*Extract(47, 0, seed_2)),
  seed_4 ==
  Concat(0, 11 + 25214903917*Extract(47, 0, seed_3)),
  seed_5 ==
  Concat(0, 11 + 25214903917*Extract(47, 0, seed_4)),
  seed_6 ==
  Concat(0, 11 + 25214903917*Extract(47, 0, seed_5)),
  seed_7 ==
  Concat(0, 11 + 25214903917*Extract(47, 0, seed_6)),
  seed_8 ==
  Concat(0, 11 + 25214903917*Extract(47, 0, seed_7)),
  output1 == Extract(47, 16, seed_1),
  output2 == Extract(47, 16, seed_2),
  output3 == Extract(47, 16, seed_3),
  output4 == Extract(47, 16, seed_4),
  output5 == Extract(47, 16, seed_5),
  output6 == Extract(47, 16, seed_6),
  output7 == Extract(47, 16, seed_7),
  output8 == Extract(47, 16, seed_8),
  nextLong_output_1 ==
  If(output1 < 0,
     BV2Int(output1) - 4294967296,
     BV2Int(output1))*
  4294967296 +
  If(output2 < 0,
     BV2Int(output2) - 4294967296,
     BV2Int(output2)),
  nextLong_output_2 ==
  If(output3 < 0,
     BV2Int(output3) - 4294967296,
     BV2Int(output3))*
  4294967296 +
  If(output4 < 0,
     BV2Int(output4) - 4294967296,
     BV2Int(output4)),
  nextLong_output_3 ==
  If(output5 < 0,
     BV2Int(output5) - 4294967296,
     BV2Int(output5))*
  4294967296 +
  If(output6 < 0,
     BV2Int(output6) - 4294967296,
     BV2Int(output6)),
  nextLong_output_4 ==
  If(output7 < 0,
     BV2Int(output7) - 4294967296,
     BV2Int(output7))*
  4294967296 +
  If(output8 < 0,
     BV2Int(output8) - 4294967296,
     BV2Int(output8)),
  nextLong_output_1 == -6273188232032513096]

Z3运用束缚为有标记整数和生成准确的If束缚。

 solver.check()
 sat

所以盘算的种子是:

 solver.model()[original_seed]
 1337

胜利了!我们可以从一次挪用中提取种子nextLong()。

其他展望数字是不是即是已知值?

 for i, known_long in enumerate(known_longs):
     calculated_long = solver.model()[nextLong_outputs[f'nextLong_output_{i+1}']].as_long()
     assert calculated_long == known_long
 print('All assertions passed')
 All assertions passed

结论:nextLong()提取一切将来值所需的只需一个。另外,假如我们晓得生成的数目,我们也可以提取用于实例化的Random()值。

OWASP基准测试和检测弱随机性

接下来,我们愿望将我们的要领运用于实际用例。

开放式Web运用递次平安项目(OWASP)是一个在线社区,可以在Web运用递次平安性范畴生成免费的文章,要领,文档,东西和手艺。在OWASP生产的浩瀚资本中,他们供应免费开放的测试套件,旨在供应软件破绽检测东西和效劳的速率,掩盖局限和准确性,称为OWASP Benchmark。Benchmark 作为Docker镜像供应,包括数千个完整可运转且可应用的测试用例。

一组可用的测试处置惩罚弱随机数生成器。详细来说,我们将运用BenchmarkTest00086经由过程挪用生成一个随机数java.util.Random.nextLong(),并将其作为cookie的值返回。为了展现我们的要领对实际天下案例的适用性,我们想要提取Random()实例化值(在这类状况下将是System.currentTimeMillis(),由于Random()实例化时没有输入值)。来自OWASP Benchmark github存储库的测试源:

     65:    long l = new java.util.Random().nextLong();
     66:    String rememberMeKey = Long.toString(l);
     ...
     94:    javax.servlet.http.Cookie rememberMe = new javax.servlet.http.Cookie(cookieName, rememberMeKey);

为了猎取cookie,我们将运用基于puppeteer(Chromium的无头API)及其'python绑定pyppeteer的小实用递次功用:

代码段链接:

 url = 'https://my.external.ip:8443/benchmark/weakrand-00/BenchmarkTest00086?BenchmarkTest00086=SafeText'
 import asyncio
 try:
     from pyppeteer import launch
 except ModuleNotFoundError:
     !pip install pyppeteer
     from pyppeteer import launch
 async def get_cookie(url: str) -> int:
     browser = await launch({'headless': True,
                             'args': ['--no-sandbox', '--disable-setuid-sandbox'],
                             'ignoreHTTPSErrors': True});
     page = await browser.newPage()
 
     await page.goto(url)
     elementList = await page.querySelectorAll('form')
     button = await elementList[0].querySelectorAll('input')
     await button[0].click()
 
     await page.waitForNavigation();
 
     cookies = await page.cookies()
 
     for cookie in cookies:
         if cookie['name'] == 'rememberMe00086':
             return int(cookie['value'])
 cookie_nums = []
 for i in range(1):
     cookie_nums.append(await get_cookie(url = url))
 cookie_nums
 [-8886403976268848760]
 solver, original_seed, nextLong_outputs = find_seed_nextLong(sequence_length=len(known_longs))
 
 # As mentioned before, we should have enough information in single long to extract the instantiation value
 solver.add(nextLong_outputs[f'nextLong_output_{1}'] == cookie_nums[0])
 
 # Check if satisfiable
 print(f'Constraints are: {solver.check()}')
 
 # Extract seed
 print(f'Instantiation value is: {solver.model()[original_seed]}')
 Constraints are: sat
 Instantiation value is: 75531093912490

java.util.Random()运用一次挪用来提取用于实例化类的种子nextLong()。如今自力考证这个种子发生从OWASP Benchmark取得的值:

应用 Z3 SMT 束缚求解破解弱随机数算法_申博sunbet官网  技术 第6张

OWASP Benchamrk发生的值:

 -8886403976268848760

因而,运用提取的种子,可以盘算效劳器的当地时候。应用这些学问并经由过程在前进方向上运转我们的算法,可以展望分配给将来cookie的值,从而举行会话挟制进击。

0x04 末了的话

这篇文章是Z3的引见性文章:来自Microsoft Research的SAT求解器。演示了Z3的基础用法,束缚生成和处置惩罚方案提取。别的,我们演示了Z3怎样用于标记实行PRNG算法并运用算法输出提取隐蔽的内部状况。末了,我们运用OWASP Benchamrk展现了这类才能,并展现了该要领怎样用作PRNG探测器。

虽然可以在收集上找到相似的例子,但找不到周全的引见性文章。我们愿望这篇文章为Z3供应了一个很好的引见,证实它可用于剖析源代码并引发平安专业人员对此要领的兴致。

0x05 相干笔记

代码库,个中包括示例中详述的示例

Z3 GitHub存储库

与Jupyter notebokk集成的Z3补丁版本

丹尼斯·尤里切夫(Dennis Yurichev)预定了很多Z3实例

运用Cutter和Z3举行逆向工程演示

0x06 研讨背景

布尔可满足性题目

一阶逻辑

可满足性模数理论

答案集编程

本文翻译自:https://alephsecurity.com/2019/09/02/Z3-for-webapp-security/

网友评论

2条评论
  • 2020-08-09 00:00:14

    Allbetwww.czsjhf168.com欢迎进入欧博平台(Allbet Gaming),欧博平台开放欧博(Allbet)开户、欧博(Allbet)代理开户、欧博(Allbet)电脑客户端、欧博(Allbet)APP下载等业务。推荐来的,果然赞~

  • 2020-08-09 00:00:46

    Allbetwww.czsjhf168.com欢迎进入欧博平台(Allbet Gaming),欧博平台开放欧博(Allbet)开户、欧博(Allbet)代理开户、欧博(Allbet)电脑客户端、欧博(Allbet)APP下载等业务。推荐来的,果然赞~