[湖湘杯2018]HighwayHash64

HighwayHash是是伪随机的 函数(即键控散列函数)优化了速度 信息,由Jyrki Alakuijala、Bill Cox和Jan Wassenberg设计 谷歌研究
我看有大佬WP是通过导入HighwayHash-cffi包用python来爆破的
但我没安装成功,贴个博客地址
先运行看看回显
img
ida打开查看主函数有两处check
img

法一

两处check的retcode都是1,可以把第二处修改为2,爆破第一处check得到长度
第二处check地址为1400019D6
img
010edit修改
img
写个bat爆破长度

1
2
3
4
5
6
@echo off
:next
reverse.exe
if %ERRORLEVEL% EQU 2 echo !!!!!get_len!!!!! & goto next
if %ERRORLEVEL% EQU 1 echo again & goto next
if %ERRORLEVEL% EQU 0 echo ############ & goto next

可以得到flag长度为19,除去hxb2018{}中间数字有10位
img
对照github上HighwayHash源码分析sub_1400017A0函数
img
其中HighwayHashReset是修改过的
img
将下载下来的源码highwayhash.c里的HighwayHashReset修改
img
可以通过第一个check验证一下我们的修改是否正确
img

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "highwayhash.h"

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>


int main() {
const uint64_t key[4]={0};
uint8_t data[11] = {19};
printf("%llx",HighwayHash64(data, 4, key));
return 0;
}

结果正确,说明我们的修改是符合题目所给的,那我们就可以爆破了
img

exp

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
#include "highwayhash.h"

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>


int main() {
const uint64_t key[4]={0};
uint8_t data[11]={0,0,0,0,0,0,0,0,0,0};
for(uint8_t v1='9';v1>='0';v1--){
for(uint8_t v2='9';v2>='0';v2--){
for(uint8_t v3='9';v3>='0';v3--){
for(uint8_t v4='9';v4>='0';v4--){
for(uint8_t v5='9';v5>='0';v5--){
for(uint8_t v6='9';v6>='0';v6--){
for(uint8_t v7='9';v7>='0';v7--){
for(uint8_t v8='9';v8>='0';v8--){
for(uint8_t v9='9';v9>='0';v9--){
for(uint8_t v10='9';v10>='0';v10--){
data[0]=v1;
data[1]=v2;
data[2]=v3;
data[3]=v4;
data[4]=v5;
data[5]=v6;
data[6]=v7;
data[7]=v8;
data[8]=v9;
data[9]=v10;
if(HighwayHash64(data, 10, key) == 0xC886BDF39CB4ED72){
puts((char *)data);
}

} } } } } } } } } }
return 0;
}

大概2-3分钟跑出结果
img

法二

调用函数有两种方法,一种是写一个dll注入到exe中进行调用,另一种则是将该exe直接改成dll,另外写一个exe来调用
考虑后者将exe修改成dll
可以用010editor修改pe的NT头

  • IMAGE_FILE_HEADER->Characteristics(文件属性)->2102h(DLL文件一般是2102h)
  • IMAGE_OPTIONAL_HEADER->AddressOfEntryPoint(程序执行入口RVA)->0000h
    img
    或者用DIE的PE菜单修改
    img
    img

exp

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
//#include "pch.h"
#include <iostream>
#include<windows.h>

typedef __int64(__fastcall *f)(__int64 buff, unsigned __int64 len);

f func;

void len()
{
int i;
unsigned long long result;
for (i = 0; i < 50; i++)
{
result = func((long long)&i, 4);
if (result == 0xD31580A28DD8E6C4)
{
printf("Len is %d\n", i - 9);
return;
}
}
printf("Not found the lenn");
return;
}

void hash()
{
unsigned long long i;
unsigned long long result;
char buff[20];
for (i = 10000000000; i > 0; i--)
{
sprintf_s(buff, "%0.10llu", i);
/*if (i % 100000 == 0)
{
printf("%0.10llu\n", i);
}*/
result = func((long long)buff, 10);
if (result == 0xC886BDF39CB4ED72)
{
printf("flag is %lld\n", i);
return;
}
}
}

int main()
{
HINSTANCE hdll;

hdll = LoadLibrary(TEXT("D:\\C++\\reverse.dll"));
if (hdll == NULL)
{
printf("Load dll Error: %dn", GetLastError());
return 0;
}
printf("Dll base is %llx\n", hdll);
func = ((f)((char*)hdll + 0x17A0));
len();
hash();
}
/*
Dll base is 7ffb57d20000
Len is 10
flag is 9352641078
*/

大概跑5分钟的样子
img

flag

hxb2018{9352641078}

[XCTF2017]first

ida64打开,主函数分析如下

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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
__int64 __fastcall main(int a1, char **a2, char **a3)
{
__useconds_t *v3; // rbp
unsigned int v4; // eax
int *v5; // rcx
int v6; // edx
unsigned int v7; // eax
signed __int64 v8; // rcx
__int64 v9; // rax
char v10; // bl
char v11; // dl
void (**v12)(void *); // rbp
char *v13; // r12
pthread_t *v14; // r13
void (*v15)(void *); // rdi
unsigned __int64 i; // rcx
char v17; // al
int *v18; // rdx
int v19; // esi
unsigned int v20; // eax
unsigned __int64 v21; // rdx
char *v22; // rax
char *v23; // rdx
char v24; // di

v3 = useconds;
v4 = time(0LL);
srand(v4);
do
*v3++ = 100 * (rand() % 1000);
while ( v3 != (__useconds_t *)&unk_602208 ); // 随机生成某个数
__isoc99_scanf("%63s", dword_602180);
v5 = dword_602180;
do
{
v6 = *v5++;
v7 = ~v6 & (v6 - 16843009) & 0x80808080;
}
while ( !v7 );
if ( (~v6 & (v6 - 16843009) & 0x8080) == 0 )
v7 >>= 16;
if ( (~v6 & (v6 - 16843009) & 0x8080) == 0 )
v5 = (int *)((char *)v5 + 2);
v8 = (char *)v5 - ((char *)dword_602180 + __CFADD__((_BYTE)v7, (_BYTE)v7) + 3);
v9 = 0LL;
v10 = 0;
while ( v8 != v9 )
{
v11 = *((_BYTE *)dword_602180 + v9) + v9; // 每个字符+索引
++v9;
v10 ^= v11; // 异或
}
v12 = (void (**)(void *))&newthread;
v13 = 0LL;
v14 = &newthread;
do
{
if ( pthread_create(v14, 0LL, (void *(*)(void *))start_routine, v13) )// start_routine里有关键加密
{
perror("pthread_create");
exit(-1);
}
++v13;
++v14;
}
while ( v13 != (char *)6 ); // 创建6个进程
do
{
v15 = *v12++;
pthread_join((pthread_t)v15, 0LL);
}
while ( &free != v12 );
for ( i = 0LL; ; byte_60221F[i] = v10 ^ byte_6020DF[i] ^ v17 )// 和byte_6020DF以及前面用到的v10异或
// byte_6020DF为
// FE E9 F4 E2 F1 FA F4 E4 F0 E7 E4 E5 E3 F2 F5 EF E8 FF F6 F4 FD B4 A5 B2
{
v18 = dword_602180;
do
{
v19 = *v18++;
v20 = ~v19 & (v19 - 16843009) & 0x80808080;
}
while ( !v20 );
if ( (~v19 & (v19 - 16843009) & 0x8080) == 0 )
v20 >>= 16;
if ( (~v19 & (v19 - 16843009) & 0x8080) == 0 )
v18 = (int *)((char *)v18 + 2);
v21 = (char *)v18 - ((char *)dword_602180 + __CFADD__((_BYTE)v20, (_BYTE)v20) + 3);
if ( v21 <= i )
break;
v17 = *((_BYTE *)dword_602220 + i++);
}
if ( v21 )
{
if ( (unsigned __int8)(LOBYTE(dword_602220[0]) - 48) > 0x4Au )
{
LABEL_32:
puts("Badluck! There is no flag");
return 0LL;
}
v22 = (char *)dword_602220 + 1;
v23 = (char *)(v21 + 6300192);
while ( v22 != v23 )
{
v24 = *v22++;
if ( (unsigned __int8)(v24 - 48) > 0x4Au )
goto LABEL_32;
}
}
__printf_chk(1LL, "Here is the flag:%s\n", (const char *)dword_602220);// 正确输出dword_602220
return 0LL;
}

跟进一下start_routine
img
sub_400E10里findcrypt插件有识别到md5的标志数组
img
那我们可以先爆破出来传入的数据得到juhuhfenlapsiuerhjifdunu

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from hashlib import md5
from pwn import p64

ans = [0x0F59BB02BDBB4647,0x5CFCE8EC2128ACBE,0xEF0375CA659274AD,0x27422CC18FB38643,0xA72DECA745CC3EB0,0xE8341712FE5F3CBE]
ans = [p64(i) for i in ans]
print(ans)
for i in range(97,123):
for j in range(97,123):
for k in range(97,123):
for l in range(97,123):
enc = bytes([i,j,k,l])
val = md5(enc).digest()[:8]
if val in ans:
print(enc, val, ans.index(val))
#[b'GF\xbb\xbd\x02\xbbY\x0f', b'\xbe\xac(!\xec\xe8\xfc\\', b'\xadt\x92e\xcau\x03\xef', b"C\x86\xb3\x8f\xc1,B'", b'\xb0>\xccE\xa7\xec-\xa7', b'\xbe<_\xfe\x12\x174\xe8']
# b'dunu' b'\xbe<_\xfe\x12\x174\xe8' 5
# b'hfen' b'\xbe\xac(!\xec\xe8\xfc\\' 1
# b'hjif' b'\xb0>\xccE\xa7\xec-\xa7' 4
# b'iuer' b"C\x86\xb3\x8f\xc1,B'" 3
# b'juhu' b'GF\xbb\xbd\x02\xbbY\x0f' 0
# b'laps' b'\xadt\x92e\xcau\x03\xef' 2
#juhuhfenlapsiuerhjifdunu

真实的输入顺序不确定,6组字符组合一下,爆破一下顺序
如果用juhuhfenlapsiuerhjifdunu解出来是goodjobyougeytcnsflaj284
隐约能感觉到是最后1位和倒3位出了问题,交换一下
最后确定juhuhfenlapsdunuhjifiuer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
input1 = 'juhuhfenlapsiuerhjifdunu'
check = [0xfe,0xe9,0xf4,0xe2,0xf1,0xfa,0xf4,0xe4,0xf0,0xe7,0xe4,0xe5,0xe3,0xf2,0xf5,0xef,0xe8,0xff,0xf6,0xf4,0xfd,0xb4,0xa5,0xb2]
len = 24
i = 0
v10 = 0
while(i != len):
v11 = ord(input1[i]) + i
v10 = v10 ^ v11
i = i + 1

input2 = 'juhuhfenlapsdunuhjifiuer'
flag = ''
for i in range(24):
temp = ord(input2[i]) ^ v10 ^ check[i]
flag += chr(temp)
print(flag)
#goodjobyougetthisflag233

另外也可以在linux下运行,能爆出来结果
img

exp

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
from hashlib import md5
from pwn import p64

ans = [0x0F59BB02BDBB4647,0x5CFCE8EC2128ACBE,0xEF0375CA659274AD,0x27422CC18FB38643,0xA72DECA745CC3EB0,0xE8341712FE5F3CBE]
ans = [p64(i) for i in ans]
print(ans)
for i in range(97,123):
for j in range(97,123):
for k in range(97,123):
for l in range(97,123):
enc = bytes([i,j,k,l])
val = md5(enc).digest()[:8]
if val in ans:
print(enc, val, ans.index(val))
#[b'GF\xbb\xbd\x02\xbbY\x0f', b'\xbe\xac(!\xec\xe8\xfc\\', b'\xadt\x92e\xcau\x03\xef', b"C\x86\xb3\x8f\xc1,B'", b'\xb0>\xccE\xa7\xec-\xa7', b'\xbe<_\xfe\x12\x174\xe8']
# b'dunu' b'\xbe<_\xfe\x12\x174\xe8' 5
# b'hfen' b'\xbe\xac(!\xec\xe8\xfc\\' 1
# b'hjif' b'\xb0>\xccE\xa7\xec-\xa7' 4
# b'iuer' b"C\x86\xb3\x8f\xc1,B'" 3
# b'juhu' b'GF\xbb\xbd\x02\xbbY\x0f' 0
# b'laps' b'\xadt\x92e\xcau\x03\xef' 2
#juhuhfenlapsiuerhjifdunu
input1 = 'juhuhfenlapsiuerhjifdunu'
check = [0xfe,0xe9,0xf4,0xe2,0xf1,0xfa,0xf4,0xe4,0xf0,0xe7,0xe4,0xe5,0xe3,0xf2,0xf5,0xef,0xe8,0xff,0xf6,0xf4,0xfd,0xb4,0xa5,0xb2]
len = 24
i = 0
v10 = 0
while(i != len):
v11 = ord(input1[i]) + i
v10 = v10 ^ v11
i = i + 1

input2 = 'juhuhfenlapsiuerhjifdunu'
flag = ''
for i in range(24):
temp = ord(input2[i]) ^ v10 ^ check[i]
flag += chr(temp)
print(flag)
#goodjobyougetthisflag233

flag

goodjobyougetthisflag233

[西湖论剑2019预选赛]Junk_instruction

MFC文件先打开看看,要求输入flag然后check
img
输入错误会弹出Error!提示
学习了一下MFC逆向,要使用XSPY
先检测一下check按钮,id=03e9
img
接着检测一下整个窗口
img
可以看到OnCommand: notifycode=0000 id=03e9,func= 0x00832420(Junk_Instruction.exe+ 0x002420 )
表示点击id=03e9即check的时候程序会跳转倒0x00832420地址的函数
ida打开定位到sub_402420
img
可以看到有个if判断,调用了sub_402600应该就是加密函数了,跟进一下
有点混乱应该是有花指令,返回去看汇编代码
发现有很多垃圾指令。就是先用一个call跳到下一段,没什么实际意义
全部nop
img
2AF0, 2CA0, 2e80这几个也有类似花指令函数同样的处理。
或者用idapython去花

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from ida_bytes import get_bytes, patch_bytes
import re
addr = 0x402400
end = 0x403000
buf = get_bytes(addr, end-addr)
def handler1(s):
s = s.group(0)
print("".join(["%02x"%i for i in s]))
s = b"\x90"*len(s)
return s
p = b"\xe8\x00\x00\x00\x00.*?\xc3.*?\xc3"
buf = re.sub(p, handler1, buf, flags=re.I)
patch_bytes(addr, buf)
print("Done")

去花完sub_402600如下

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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
char __cdecl sub_402600(int a1)
{
int v1; // ecx
const WCHAR *v2; // eax
void *v3; // eax
char v5; // [esp+8h] [ebp-4BCh]
char v6[511]; // [esp+9h] [ebp-4BBh] BYREF
int v7; // [esp+208h] [ebp-2BCh]
char *v8; // [esp+20Ch] [ebp-2B8h]
int v9; // [esp+210h] [ebp-2B4h]
size_t Count; // [esp+214h] [ebp-2B0h]
int v11; // [esp+218h] [ebp-2ACh]
size_t v12; // [esp+21Ch] [ebp-2A8h]
char *v13; // [esp+220h] [ebp-2A4h]
char *v14; // [esp+224h] [ebp-2A0h]
int v15; // [esp+228h] [ebp-29Ch]
char v16[4]; // [esp+22Ch] [ebp-298h] BYREF
char *Source; // [esp+230h] [ebp-294h]
int v18; // [esp+234h] [ebp-290h]
char v19; // [esp+238h] [ebp-28Ch]
char v20; // [esp+239h] [ebp-28Bh]
char v21; // [esp+23Ah] [ebp-28Ah]
char v22; // [esp+23Bh] [ebp-289h]
char v23; // [esp+23Ch] [ebp-288h]
char v24; // [esp+23Dh] [ebp-287h]
char v25; // [esp+23Eh] [ebp-286h]
char v26; // [esp+23Fh] [ebp-285h]
char v27; // [esp+240h] [ebp-284h]
char v28; // [esp+241h] [ebp-283h]
char v29; // [esp+242h] [ebp-282h]
char v30; // [esp+243h] [ebp-281h]
char v31; // [esp+244h] [ebp-280h]
char v32; // [esp+245h] [ebp-27Fh]
char v33; // [esp+246h] [ebp-27Eh]
char v34; // [esp+247h] [ebp-27Dh]
char v35; // [esp+248h] [ebp-27Ch]
char v36; // [esp+249h] [ebp-27Bh]
char v37; // [esp+24Ah] [ebp-27Ah]
char v38; // [esp+24Bh] [ebp-279h]
char v39; // [esp+24Ch] [ebp-278h]
char v40; // [esp+24Dh] [ebp-277h]
char v41; // [esp+24Eh] [ebp-276h]
char v42; // [esp+24Fh] [ebp-275h]
char v43; // [esp+250h] [ebp-274h]
char v44; // [esp+251h] [ebp-273h]
char v45; // [esp+252h] [ebp-272h]
char v46; // [esp+253h] [ebp-271h]
char v47; // [esp+254h] [ebp-270h]
char v48; // [esp+255h] [ebp-26Fh]
char v49; // [esp+256h] [ebp-26Eh]
char v50; // [esp+257h] [ebp-26Dh]
const char *v51; // [esp+258h] [ebp-26Ch]
char *v52; // [esp+25Ch] [ebp-268h]
int i; // [esp+260h] [ebp-264h]
char *v54; // [esp+264h] [ebp-260h]
char v55; // [esp+26Dh] [ebp-257h]
char v56; // [esp+26Eh] [ebp-256h]
char v57; // [esp+26Fh] [ebp-255h]
char v58[28]; // [esp+270h] [ebp-254h] BYREF
char v59; // [esp+28Ch] [ebp-238h] BYREF
char v60[255]; // [esp+28Dh] [ebp-237h] BYREF
char v61[256]; // [esp+38Ch] [ebp-138h] BYREF
char Destination; // [esp+48Ch] [ebp-38h] BYREF
char v63[39]; // [esp+48Dh] [ebp-37h] BYREF
int v64; // [esp+4C0h] [ebp-4h]
int savedregs; // [esp+4C4h] [ebp+0h] BYREF

v18 = v1;
v64 = 3;
v19 = 0x5B;
v20 = 0xD6;
v21 = 0xD0;
v22 = 0x26;
v23 = 0xC8;
v24 = 0xDD;
v25 = 0x19;
v26 = 0x7E;
v27 = 0x6E;
v28 = 0x3E;
v29 = 0xCB;
v30 = 0x16;
v31 = 0x91;
v32 = 0x7D;
v33 = 0xFF;
v34 = 0xAF;
v35 = 0xDD;
v36 = 0x76;
v37 = 0x64;
v38 = 0xB0;
v39 = 0xF7;
v40 = 0xE5;
v41 = 0x89;
v42 = 0x57;
v43 = 0x82;
v44 = 0x9F;
v45 = 0xC;
v46 = 0;
v47 = 0x9E;
v48 = 0xD0;
v49 = 0x45;
v50 = 0xFA;
v2 = (const WCHAR *)sub_401570(&a1);
v15 = sub_4030A0(v2);
v11 = v15;
v3 = (void *)sub_401570(v15);
sub_403000(v3);
sub_4012A0(v16);
Source = (char *)unknown_libname_1(v58);
v52 = Source;
v14 = Source + 1;
v52 += strlen(v52);
v12 = ++v52 - (Source + 1);
Count = v12;
Destination = 0;
memset(v63, 0, sizeof(v63));
strncpy(&Destination, Source, v12);
if ( sub_402AF0(&Destination) )
{
v55 = 0;
v57 = 0;
LABEL_7:
v56 = v57;
}
else
{
strcpy(v61, "qwertyuiop");
memset(&v61[11], 0, 0xF5u);
v59 = 0;
memset(v60, 0, sizeof(v60));
v5 = 0;
memset(v6, 0, sizeof(v6));
v51 = v61;
v8 = &v61[1];
v51 += strlen(v51);
v7 = ++v51 - &v61[1];
sub_402CA0(&v59, v61, v51 - &v61[1]);
v54 = &Destination;
v13 = v63;
v54 += strlen(v54);
v9 = ++v54 - v63;
sub_402E80(v18, &v59, &Destination, v54 - v63);
for ( i = 31; i >= 0; --i )
{
if ( *(&Destination + i) != *((char *)&savedregs + i + (_DWORD)&loc_4026B7 - 4204867) )
{
v57 = 0;
goto LABEL_7;
}
}
v56 = 1;
}
LOBYTE(v64) = 0;
sub_403060(v58);
v64 = -1;
sub_4012A0(&a1);
return v56;
}

sub_402CA0如下,一眼rc4
img
sub_402AF0如下,逆向数组操作
img

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
from Crypto.Cipher import ARC4

key = b'qwertyuiop'
a = [
0x5b, 0xd6, 0xd0, 0x26, 0xc8, 0xdd, 0x19, 0x7e, 0x6e, 0x3e,
0xcb, 0x16, 0x91, 0x7d, 0xff, 0xaf, 0xdd, 0x76, 0x64, 0xb0,
0xf7, 0xe5, 0x89, 0x57, 0x82, 0x9f, 0xc, 0x0, 0x9e, 0xd0, 0x45, 0xfa]

enc = b''.join([bytes([i]) for i in a])
rc4 = ARC4.new(key)
decrypted_data = rc4.decrypt(enc)[::-1]
print(decrypted_data.decode('utf-8'))
#973387a11fa3f724d74802857d3e052f

img

flag

flag{973387a11fa3f724d74802857d3e052f}