实验吧-3

逆向观察

直接拖ida里打开,主函数:

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
  v10 = __readfsqword(0x28u);
if ( argc <= 1 )
{
puts("usage ./rev50 password");
}
else
{
src = 'sedecrem';
v6 = 0;
v7 = 0;
v8 = 0;
memcpy(&dest, &src, 9uLL);
for ( i = 0; i <= 999; ++i )
{
if ( !strcmp(argv[1], (&dict)[i]) && !strcmp(&dest, (&dict)[i]) )
{
puts("Good password ! ");
goto LABEL_10;
}
}
puts("Bad ! password");
}
LABEL_10:
puts(&byte_40252A);
return 0;

Good password的判断条件就是输入=src,需要注意的是这里的字符串是应该倒过来看的,所以应该是mercedes。

bitwise

下载下来一个rar,解压后可以得到一个java程序和一个py程序,看上去应该功能是一样的,不会java所以就分析py吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python

user_submitted = raw_input("Enter Password: ")

if len(user_submitted) != 10:
print "Wrong"
exit()


verify_arr = [193, 35, 9, 33, 1, 9, 3, 33, 9, 225]
user_arr = []
for char in user_submitted:
# '<<' is left bit shift
# '>>' is right bit shift
# '|' is bit-wise or
# '^' is bit-wise xor
# '&' is bit-wise and
user_arr.append( (((ord(char) << 5) | (ord(char) >> 3)) ^ 111) & 255 )

if (user_arr == verify_arr):
print "Success"
else:
print "Wrong"

爆破一发:

1
2
3
4
5
6
7
8
import string
flag=""
verify_arr = [193, 35, 9, 33, 1, 9, 3, 33, 9, 225]
for i in range(len(verify_arr)):
for j in string.printable:
if (((ord(j) << 5) | (ord(j) >> 3)) ^ 111) & 255 == verify_arr[i] :
flag+=j
print flag

Byte Code

下载得到一个.class文件,用jd-gui试试,结果会报错INTERNAL ERROR,百度了一下,用luyten试试打开了:

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
import java.io.*;

class Authenticator
{
public static char[] key;

public static void main(final String[] array) {
(Authenticator.key = new char[10])[0] = 'A';
Authenticator.key[1] = 'o';
Authenticator.key[2] = 'J';
Authenticator.key[3] = 'k';
Authenticator.key[4] = 'V';
Authenticator.key[5] = 'h';
Authenticator.key[6] = 'L';
Authenticator.key[7] = 'w';
Authenticator.key[8] = 'U';
Authenticator.key[9] = 'R';
final Console console = System.console();
for (String line = ""; !line.equals("ThisIsth3mag1calString4458"); line = console.readLine("Enter password:", new Object[0])) {}
for (int i = 0; i < Authenticator.key.length; ++i) {
System.out.print(Authenticator.key[i]);
}
System.out.println("");
}
}

虽然不会java但是这么简单的代码还是可以看看的,AoJkVhLwUR就是输入正确时得到的flag。(luyten真给力啊

CFG to C

汇编代码和c代码配对就行了,不过其实根据逻辑图就能判断。

对应

1
2
3
4
5
6
7
int loop(int a)
{
while (a >= 0) {
a--;
}
return a;
}

对应

1
2
3
4
5
6
7
8
int control(int a, int b)
{
if (a > b)
return b;
else
return a;

}

对应

1
2
3
4
5
6
7
8
int for_loop(int a, int b, int c)
{
int i;

for(i = 0; i < b; i++)
a = c + i;
return a;
}

对应

1
2
3
4
int modulo(int a, int b)
{
return b % a;
}

catalyst-system

ida打开,main函数中关键部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
printf("Username: ");
__isoc99_scanf("%s", v8);
printf("Password: ", v8);
__isoc99_scanf("%s", v7);
printf("Logging in", v7);
fflush(stdout);
for ( j = 0; j <= 29; ++j )
{
v5 = rand();
sleep(v5 % (j + 1));
putchar('.');
fflush(stdout);
}
putchar(10);
sub_400C9A((__int64)v8);
sub_400CDD(v8);
sub_4008F7((__int64)v8);
sub_400977(v8, v7);
sub_400876((__int64)v8, (__int64)v7);
return 0LL;

输入账号密码后接下来几个函数进行账号密码验证与输出flag。

sub_400876就是输出flag的函数:

1
2
3
4
5
6
7
char *s; // [rsp+0h] [rbp-30h]
int i; // [rsp+1Ch] [rbp-14h]

printf("your flag is: ALEXCTF{", a2, a1);
for ( i = 0; i < strlen(s); ++i )
putchar((unsigned __int8)byte_6020A0[i] ^ s[i]);
return puts("}");

可以看见flag的格式了,不过不知道s处的字符串是啥,只能看看上面的函数。

sub_400c9a限制了账号的长度大于8小于16且为4的倍数,所以长度就是12。

sub_400cdd函数:

1
2
3
4
5
6
7
8
9
10
11
v4 = *a1;
v3 = a1[1];
v2 = a1[2];
if ( v4 - v3 + v2 != 0x5C664B56
|| v3 + 3 * (v2 + v4) != 0x2E700C7B2LL
|| (result = 0x32AC30689A6AD314LL, v2 * v3 != 0x32AC30689A6AD314LL) )
{
puts("invalid username or password");
exit(0);
}
return result;

对账号进行了限制,给了三个条件表达式,这里可以使用z3求解,解得v4=0x6f65635f,v3=0x7473796c,v2=0x61746163。

sub_4008fc函数限制了账号的字符位于’`’与’z’之间或者等于’_’。

sub_400977通过随机函数生成密码,这里要用linux运行才是正确的。

sub_400876密码异或一个数组得到flag。

文章目录
  1. 1. 逆向观察
  2. 2. bitwise
  3. 3. Byte Code
  4. 4. CFG to C
  5. 5. catalyst-system
|