攻防世界 reverse 进阶 10 Reverse Box

攻防世界中此题信息未给全,题目来源为[TWCTF-2016:Reverse] Reverse Box

网上有很多wp是使用gdb脚本,这里找到一个本地还原关键算法,然后再爆破的

https://www.megabeets.net/twctf-2016-reverse-reverse-box/

[TWCTF-2016:Reverse] Reverse Box Writeup

标准

Shak的客座文章。

挑战描述
$ ./reverse_box $ {FLAG} 
95eeaf95ef94234999582f722f492f72b19a7aaf72e6e776b57aee722fe77ab5ad9aaeb156729676ae7a236d99b1df4a reverse_box.7z



这个挑战是一个二进制文件,它需要一个参数然后吐出一个字符串。我们得到二进制文件的输出,用于运行它。让我们开始这一点。

1

2

./reverse_box 0000

28282828

二进制可能会打印替换每个字符的十六进制值。同样清楚的是,它是每个角色的唯一值。我们必须处理某种替代密码。在使用完全相同的参数再次运行它之后,我们得到不同的输出,因此替换也以某种方式随机化。

跳转到二进制文件,我们有两个重要的函数,我命名为main和calculate。

From Hex-Rays Decompiler

C

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

int __cdecl main(int argc, const char **argv, const char **envp)

{

int result; // [email protected]

int v4; // [email protected]

size_t i; // [sp+18h] [bp-10Ch]@4

int v6; // [sp+1Ch] [bp-108h]@4

int v7; // [sp+11Ch] [bp-8h]@1

v7 = *MK_FP(__GS__, 20);

if ( argc <= 1 )

{

printf("usage: %s flag\n", *argv);

exit(1);

}

calculate((int)&v6);

for ( i = 0; i < strlen(argv[1]); ++i )

printf("%02x", *((_BYTE *)&v6 + argv[1][i]));

putchar(‘\n‘);

result = 0;

v4 = *MK_FP(__GS__, 20) ^ v7;

return result;

}

主要功能非常简单。它负责检查我们是否使用参数运行二进制文件,调用calculate函数,最后打印结果。查看结果打印格式,我们可以看到结果是十六进制格式。

接下来我们将处理计算功能。

From Hex-Rays Decompiler

C

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

int __cdecl calculate(int a1)

{

unsigned int seed; // [email protected]

int v2; // [email protected]

char v3; // [email protected]

char v4; // [email protected]

char v5; // [email protected]

int v6; // [email protected]

int v7; // [email protected]

int v8; // [email protected]

int v9; // [email protected]

int v10; // [email protected]

int v11; // [email protected]

int v12; // [email protected]

int v13; // [email protected]

int result; // [email protected]

char v15; // [sp+1Ah] [bp-Eh]@3

char v16; // [sp+1Bh] [bp-Dh]@3

char v17; // [sp+1Bh] [bp-Dh]@7

int randomNum; // [sp+1Ch] [bp-Ch]@2

seed = time(0);

srand(seed);

do

randomNum = (unsigned __int8)rand();

while ( !randomNum );

*(_BYTE *)a1 = randomNum;

v15 = 1;

v16 = 1;

do

{

v2 = (unsigned __int8)v15 ^ 2 * (unsigned __int8)v15;

if ( v15 >= 0 )

v3 = 0;

else

v3 = 27;

v15 = v2 ^ v3;

v4 = 4 * (2 * v16 ^ v16) ^ 2 * v16 ^ v16;

v17 = 16 * v4 ^ v4;

if ( v17 >= 0 )

v5 = 0;

else

v5 = 9;

v16 = v17 ^ v5;

v6 = *(_BYTE *)a1;

LOBYTE(v6) = v16 ^ v6;

v7 = (unsigned __int8)v16;

LOBYTE(v7) = __ROR1__(v16, 7);

v8 = v7 ^ v6;

v9 = (unsigned __int8)v16;

LOBYTE(v9) = __ROR1__(v16, 6);

v10 = v9 ^ v8;

v11 = (unsigned __int8)v16;

LOBYTE(v11) = __ROR1__(v16, 5);

v12 = v11 ^ v10;

v13 = (unsigned __int8)v16;

LOBYTE(v13) = __ROR1__(v16, 4);

result = v13 ^ v12;

*(_BYTE *)(a1 + (unsigned __int8)v15) = result;

}

while ( v15 != 1 );

return result;

}

它根本不像我们的主要直接,但基本上它随机化一个变量,做一些内存操作并返回一些随机值。现在,让我们尝试调试二进制文件而不完全理解计算。

二进制文件迭代输入中的字符并执行以下程序集以打印结果。

1

2

3

4

5

movzx   eax, byte ptr [esp+eax+1Ch]

movzx   eax, al

mov     [esp+4], eax

mov     dword ptr [esp], offset a02x ; "%02x"

call    _printf

到达这组指令后,eax寄存器保存了我们输入的字符。然后为printf函数传递的是来自eax位置(第1行)的[esp + 1Ch]中的数组的元素。所以这个数组保存我们的结果。让我们进一步研究它,看看它是什么。跳转到堆栈上的那个位置我们会遇到一个268 Bytes的十六进制数组,我们将把数组保存到一个名为array的二进制文件中供以后使用。

在运行二进制文件几次之后,我们可以理解该数组也是以某种方式随机化的。也许它与计算函数返回的随机值有关。再运行二进制文件几次,我们看到数组的第二个元素总是等于计算中的随机数。所以,二进制文件必须有一个基本数组,然后用随机值以某种方式进行操作。如果每次操作发生时,基本数组中的第二个元素必须为零,我们得到随机数。让我们试着理解二进制执行什么样的操作。我们将通过将二进制数组加载到python脚本来实现这一点,然后我们将通过对我们保存的数组元素执行假定操作来获取基数组,并使用我们执行二进制文件时的已知随机值,最后将该过程与另一个具有不同随机值的二进制运行进行比较以进行验证。第一个选项是将随机值添加到基础数组值。它适用于第二个元素,但将此过程与另一个二进制运行进行比较不起作用。第二个猜测是二进制文件使用基本数组元素对随机值进行异或运算,这也将允许第二个数组元素等于随机值。宾果,这个有效。现在我们所要做的就是使用我们保存的数组和该二进制运行的随机值来获取基数组。接下来我们要考虑的是标志结构,即TWCTF {...}。

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

#! /usr/bin/python

f = open(r"c:\megabeets\array", "rb")

buff = f.read(268)

random_value = 0x66

base_array = []

#Claculate the base array

for i in buff:

base_array.append(ord(i) ^ random value)

#The given output from the flag run, each value is seperated by -

flag_output = "95-ee-af-95-ef-94-23-49-99-58-2f-72-2f-49-2f-72-b1-9a-7a-af-72-e6-e7-76-b5-7a-ee-72-2f-e7-7a-b5-ad-9a-ae-b1-56-72-96-76-ae-7a-23-6d-99-b1-df-4a"

flag = ‘‘

for c in flag_output:

flag.append(int(‘0x‘ + c , 16))

T_location = ord(‘T‘)

#XORing the T_location element in the base array with the output result in order to get the random value

flag_random_value = base_array[T_location] ^ flag[0]

#Manipulate the base array to create the array for the flag binary run

flag_array = []

for b in base_array:

flag_array.append(ord(b) ^ flag_random_value)

# Create a dictionary which maps an output hex value to an input character

dic{}

for i in range(0, 268):

dic[flag_array[i]] = chr(i)

#

for i in xrange(len(flag)):

print dic[flag[i]],

该flag为  TWCTF {5UBS717U710N_C1PH3R_W17H_R4ND0M123D_5-B0X}

python3

 1 ror = lambda val, r_bits, max_bits:  2     ((val & (2**max_bits-1)) >> r_bits%max_bits) |  3     (val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))
 4
 5 all_s_boxes = {}
 6 for randomValue in range(256):
 7   results = [0 for i in range(256)]
 8   position_index = 3;
 9   some_value = 1;
10   while position_index != 1:
11     # Used to generate some_value
12     v1 = 2 * some_value ^ some_value & 0xff
13     v2 = (v1 ^ v1 * 4) &0xff
14     v3 = (v2 ^ v2 * 16) & 0xff
15     if ( v3 < 128 ):
16       v5 = 0;
17     else:
18       v5 = 9;
19     some_value = (v3 ^ v5) & 0xff;
20
21     factor1 = some_value & 0xff
22     factor2 = some_value ^ randomValue
23     factor1_rotate_7bits = ror(factor1, 7,8)
24     factor1_rotate_6bits = ror(factor1, 6,8)
25     factor1_rotate_5bits = ror(factor1, 5,8)
26     factor1_rotate_4bits = ror(factor1,4,8)
27     result = factor2 ^ factor1_rotate_7bits ^ factor1_rotate_6bits ^ factor1_rotate_5bits ^ factor1_rotate_4bits
28
29     results[position_index] = (result & 0xff)
30
31     some_value = factor1
32     v2 = (position_index ^ (2 * position_index));
33     if position_index < 128:
34       v3 = 0;
35     else:
36       v3 = 27;
37     position_index = (v2 ^ v3) & 0xff
38   all_s_boxes[randomValue] = results
39
40 startingFlag = "TWCTF"
41 startingTarget = "\x95\xee\xaf\x95\xef"
42 sbox_to_use = None
43
44 for key,sbox in all_s_boxes.items():
45   for index,char in enumerate(startingFlag):
46     if sbox[ord(char)] == ord(startingTarget[index]):
47       sbox_to_use = sbox
48       print("Found sbox at random value %d" % key)
49       break
50
51 target = "95eeaf95ef94234999582f722f492f72b19a7aaf72e6e776b57aee722fe77ab5ad9aaeb156729676ae7a236d99b1df4a"
52 print(‘‘.join([chr(sbox_to_use.index(i)) for i in bytes.fromhex(target)]))

原文地址:https://www.cnblogs.com/DirWang/p/11441963.html

时间: 2024-11-03 23:48:34

攻防世界 reverse 进阶 10 Reverse Box的相关文章

攻防世界 web进阶区 ics-06

进入题目的界面,一通乱点点出了唯一一个可以进入的界面. 观察url http://111.198.29.45:41597/index.php?page=index 觉得page变量有问题,既然他可以为index(即文件名,那可不可以显示文件源码呢?) 于是构造payload http://111.198.29.45:41597/index.php?page=php://filter/read=convert.base64-encode/resource=index.php 果然爆出了源码.放到解

攻防世界 web 进阶区 刷题记录

1.Training-WWW-Robots 题目提示了robots协议,直接访问robots.txt 继续访问fl0g.php 原文地址:https://www.cnblogs.com/wrnan/p/12228467.html

攻防世界web进阶区(1)

1.题目地址:http://111.198.29.45:43589 页面提示打开robots文件,则: 页面有提示输入fl0g.php,那么 获取flag. 2.题目地址:http://111.198.29.45:58979 题目中提示初始文件,那么可以从index.php入手.然而将1.php换成index.php再访问后,发现优惠重新调回1.php.这时候便可通过抓包处理. 如图,将红线处的1.php换为index.php即可获得flag. 原文地址:https://www.cnblogs.

攻防世界web进阶区(2)--记一次sql注入

题目地址:http://111.198.29.45:56094 这是一道sql注入题. 试试1' order by 3#,发现页面显示正常,将3换为4时,页面报错,则说明含有3个字段. 接下来判断输出点,即输入1' union select 1,2,3#,发现2与3的位置是输出点. 爆数据库名: 1' union select 1,database(),3# 1' union select 1,2,table_name from information_schema.tables where t

攻防世界 reverse 进阶 8-The_Maya_Society Hack.lu-2017

8.The_Maya_Society Hack.lu-2017 在linux下将时间调整为2012-12-21,运行即可得到flag. 下面进行分析 1 signed __int64 __fastcall main(__int64 a1, char **a2, char **a3) 2 { 3 size_t v3; // rbx 4 size_t v4; // rax 5 unsigned __int64 size; // rax 6 unsigned __int64 size_1; // ra

攻防世界-杂项-Misc

长期更新一波 攻防世界 的杂项题解 这东西主要靠积累吧 攻防世界:https://adworld.xctf.org.cn 新手练习区 1.this_is_flag 题目直接给出了 flag 2.ext3 主要考察 linux 下光盘的挂载 strings 文件名 | grep flag 搜索文件中的可打印字符 grep:全面搜索正则表达式并把行打印出来 使用命令:mount linux ./linux_cd 将 linux(文件名) 挂载到 linux_cd 目录下,正常访问 O7avZhikg

攻防世界pwn之新手练习区

0x00 get_shell 题目描述:运行就能拿到shell呢,真的 from pwn import * io = remote('111.198.29.45','36389') io.interactive() 0x01 CGfsb 题目描述:菜鸡面对着pringf发愁,他不知道prinf除了输出还有什么作用 1.基本信息: 2.ida查看伪代码,按照题目的提示在主函数找到了printf函数,可以明显的看到ptintf没有按照标准格式 printf("", ) 书写,存在格式化字符

攻防世界 WEB lottery 和 ics-06

今天做了攻防世界WEB高手进阶的两题,虽然步骤就这么几步,但是由于自己很菜,所以查阅资料.寻找突破点花了不少时间. 一.ics-06 打开题目,点来点去,发现除了报表中心,点击其他任何地方都只会返回一个页面,这也符合题目描述: 报表中心是这么个界面,并不能输入数据,查看源码也没什么思路,卡了比较久的时间,直到发现明明没操作,url后面跟了个: ?id=1,这就有点意思了,可以get传参,至于参数干嘛的就不知道了,这应该是攻防世界给的提示. 虽然有点不明所以,但是应该是id等于某个值会返回什么东西

2019.8.31-9.3 攻防世界RE练习

攻防世界 一开始学习下re,产生了兴趣 game 这个题目在某个CTF平台做过了0-0,再做一遍.(跟着WP 0.0) 首先用ExeinfoPe或者Peid查壳 也可以使用file命令查看相关信息 32位程序,使用ida打开,F5反编译 程序逻辑: shift+F12 查看字符串 进入后 右键list cross reference to ,然后F5 这就是求flag的过程,并且输出,我可以写一个py脚本读出来 在这里的*(&v2+i)相当于v[2+i],数组形式的格式,其实就是递加1==>