Fork me on GitHub

noxCTF_2018-re_GuessTheString-wp

==>题目地址<==

0x00 简单分析

一道简单re,但是很坑啊。

用IDA直接看代码,逻辑如下。

0x01填坑

a1的前三位可以直接通过两个等式爆破出可能的结果。

第四位的check函数如下

乍一看需要a1[3] > a1[2]a1[2]*a1[2] == a1[3]*a1[3],这不扯淡吗。。。后来仔细想想a1[2]和a1[3]都是byte类型,所以实际上只需(a1[2]*a1[2])%256 == (a1[3]*a1[3])%256即可。

然后第5,6,7位可以直接爆破出确定结果。

第8位的可能结果有[48,52,56]

第9位有一个未知数,我的想法是先通过前面所有函数的check,动态调试看这个未知数的值,发现是12,于是第9位可以通过第8位算出,第10位可以通过第9位算出。

第10位我一开始拿flag的时候没搞懂HIBYTE怎么用,是直接爆破的,因为前面的10位都差不多确定了,爆破就行。

0x02 解题脚本

写wp的时候还是用gdb调了一下,发现HIBYTE对于一个16bit的数取得是高8位。。这样就懂了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'L1B0'
from pwn import *
context.log_level = 'debug'
a0 = [
'%^Jv',
'/JTl',
'/JTt',
'J/Tl',
'J/Tt',
'^%Jv'
]
a4 = [
'C=&'
]

def is_Prime(n):
if n <= 2:
return 1
for i in range(2,n):
if n%i == 0:
return 0
return 1


def get_0123():

for i in range(33,127):
for j in range(33,127):
for k in range(33,127):
if not(i*j == 3478 and (j^i)^k == 49):
continue
else:
for l in range(k+1,127):
if (l**2)%256 == (k**2)%256:
s = chr(i)+chr(j)+chr(k)+chr(l)
print s

def get_456():
for i in range(33,127):
for j in range(33,127):
if (j-42) > 0 and is_Prime(i) and is_Prime(j) and is_Prime(j-42) and i^j == 126:
s = chr(i)+chr(j)+chr(2*(j-42))
print s

if __name__ == "__main__":

#get_0123()
#get_456()
for i in a0:
for j in a4:
for k in [48,52,56]:
a7 = k
#*(_BYTE *)(a3 + 8) == (a1 ^ *(_BYTE *)(a3 + 7)); a1 = 0x12 by debug
a8 = a7^0x12
a9 = 2*a8
a100 = (a9+1)*(a9)/2
#burte a10
for l in range(33,127):
s = i+j+chr(a7)+chr(a8)+chr(a9)+chr(l)
print s

io = process('./GuessTheString')
io.recvline()
io.sendline(s)
io.recvline()
io.close()

0x03 Reference