SSHCTF--RE--WP(自存)
SSHCTF复现
0x01 Check your IDA
知识点:IDA pro的基础使用方法
做法:
把文件拖进ida,在functions windows栏control+F,搜索main函数。再对main函数点击f5进入伪代码窗口,直接可以得到flag

0x02 baby xor
知识点:异或运算
做法:
无壳,拖进ida,找到main函数,进入伪代码窗口,审计代码

双击变量byte_40B040,可以查看具体内容

可以看到aSshctfX0rKey的内容是
'sshctf&X0R_key';
byte_40B040的内容为
32h, 20h, 32h, 20h, 32h, 20h, 4Fh, 1, 4Dh, 27h, 12h, 0, 47h, 17h, 16h, 2Ch, 22h, 53h, 14h, 39h, 5, 2Bh, 7Dh, 26h, 25h, 0Eh, 28h, 1Bh, 4, 0, 0Eh, 3Ch, 23h, 3Ch, 6Bh, 2Ah, 47h, 24h, 28h, 19h, 4, 48h, 0Fh, 14h, 7, 13h
程序使用密钥对当前字符进行异或操作,如果索引是偶数,再与0x12进行异或操作。
为了便于操作,让kimi(?帮我们把上述内容转化为对应的ASCII码,则
sshctf&X0R_key=115, 115, 104, 99, 116, 102, 38, 88, 48, 82,95, 107, 101, 121
byte_40B040=50, 32, 50, 32, 50, 32, 79, 1, 77, 39,18, 0, 71, 23, 22, 44, 34, 83, 20, 57,5, 43, 125, 38, 37, 14, 40, 27, 4, 0,14, 60, 35, 60, 107, 42, 71, 36, 40, 25,4, 72, 15, 20, 7
用cpp复现,如下
int main() {
std::vector<int> arr = {
50, 32, 50, 32, 50, 32, 79, 1, 77, 39,
18, 0, 71, 23, 22, 44, 34, 83, 20, 57,
5, 43, 125, 38, 37, 14, 40, 27, 4, 0,
14, 60, 35, 60, 107, 42, 71, 36, 40, 25,
4, 72, 15, 20, 7
};
std::vector<int> Str = {
115, 115, 104, 99, 116, 102, 38, 88, 48, 82,
95, 107, 101, 121
};
for (size_t i = 0; i < arr.size(); ++i) {
if (i % 2 == 0) {
arr[i] ^= 0x12;
}
arr[i] ^= Str[i % Str.size()];
}
std::string result;
for (int a : arr) {
result += static_cast<char>(a);
}
std::cout << result << std::endl;
return 0;
}
运行即可拿到flag
SSHCTF{You_k0nw_X0r_1s_the_best_EZ_revers1ng}
0x03 baby crack
知识点:位移、位运算加密
无壳,直接拖ida,找到main,查看伪代码

可看到变量str的开头是SSHCTF,应该就是flag,且长度为38,继续看看到了sub_401550函数,进去看看

函数通过种子0xDEADBEEF生成37个在0-254之间的固定随机数。
v2 = *(unsigned __int8 *)(v7 + i)是读取 v7 + i 地址处的一个字节值,并存储在 v2 中
v3 = v2 >> (Str[v5 % strlen(Str)] % 8):计算 v2 右移 Str 中指定位置字符的值(模8)的结果,存储在 v3 中
*(_BYTE *)(v7 + i) = ((_BYTE)v2 << (8 - Str[v5 % strlen(Str)] % 8)) | v3;:对 v2 进行左移操作,并将结果与 v3 进行或运算,然后将结果存储回 v7 + i 地址处。
*(_BYTE *)(v7 + i) ^= *(_BYTE *)(i + 1i64 + v7);:对 v7 + i 地址处的字节值与 v7 + i + 1 地址处的字节值进行异或操作,并将结果存储回 v7 + i 地址处。
if ( ((unsigned __int8)(v5 & *(_BYTE *)(v7 + i)) | ~(v5 | *(unsigned __int8 *)(v7 + i)) | 7) > 63 ):一坨条件判断。
v4 = *(_BYTE *)(v7 + i);:将 v7 + i 地址处的字节值存储在 v4 中。
*(_BYTE *)(v7 + i) = (i & 0x12 | Str[i % strlen(Str)]) & 0x3F ^ v4;:进行一系列的位运算,并将结果存储回 v7 + i 地址处。
(能力有限,加密过程分析部分借助了ai)
反复读n遍代码,基本理解了加密过程(?真的吗),准备逆一下试试
先用C生成种子0xDEADBEEF的随机数列(模255)(注意 只能用C来生成)
int main() {
int i;
unsigned int seed = 0xDEADBEEF;
srand(seed);
for (i = 0; i < 37; ++i) {
int random_number = rand()%255;
printf(",%u",random_number);
}
return 0;
}
得到随机数组:
232,90,117,135,98,176,175,24,8,123,84,245,112,135,139,71,23,72,4,144,110,181,55,140,156,151,75,136,53,253,7,32,95,73,116,219,63
再查看变量数据,得到:
aSshctfkey=SSHCTFkey
byte_40F040=201, 34, 74, 60, 108, 98, 249, 249, 111, 177,146, 73, 118, 241, 190, 203, 137, 113, 40, 169,115, 82, 249, 180, 94, 254, 243, 132, 199, 61,235, 137, 117, 190, 106, 61, 19, 125
数据齐全,开始写python脚本(注释里有重要语句的功能)
key = "SSHCTFkey"
flag = [201, 34, 74, 60, 108, 98, 249, 249, 111, 177,
146, 73, 118, 241, 190, 203, 137, 113, 40, 169,
115, 82, 249, 180, 94, 254, 243, 132, 199, 61,
235, 137, 117, 190, 106, 61, 19, 125]
len_a2 = len(a2)
a1 = flag
a2 = [ord(k) for k in key] ##这里没见过,去查了知道是储存字符的Unicode代码点(与ascii码值相等)
random = [232, 90, 117, 135, 98, 176, 175, 24, 8, 123,
84, 245, 112, 135, 139, 71, 23, 72, 4, 144,
110, 181, 55, 140, 156, 151, 75, 136, 53, 253,
7, 32, 95, 73, 116, 219, 63]
for i in reversed(range(37)): #python脚本中v3对应源码v5;a1对应源码*(v7 + i);xor_a1对应源码v4;a2对应源码str
v3 = random[i]
xor_a1 = a1[i] ^ (i & 0x12 | a2[i % len(a2)] & 0x3F) #这一步恢复的是(v7 + i) = (i & 0x12 | Str[i % strlen(Str)]) & 0x3F ^ v4中的v4
if ((v3 & xor_a1) | ~(v3 | xor_a1) | 7) > 63:
a1[i] = xor_a1 #这里逆向if ( (v5 & (v7 + i)) | ~(v5 | (v7 + i)) | 7) > 63 ):v4 = (v7 + i),恢复了*(v7+1)
#后面的逆向也是同理
a1[i] ^= a1[i + 1]
c = a2[v3 % len(a2)] % 8
a1[i] = (a1[i] >> (8 - c)) | (a1[i] << c)& 0xFF
print("".join([chr(a) for a in a1]))
运行脚本,得到flag
SSHCTF{N0w_y0u_Kn0w_B1twise_op3r@t0rs}
0x04 Let's go to learn Cry
知识点:aes加密,base64加密(补 自学了一些python基础语法用来写脚本 QAQ)
无壳,拖ida

可以获取的信息: key=9e015a9f82d367bc
查看enc_flag变量
内容为KKN+NK5ZWN4xr4kM1+qq+2wJKUEEaiWmITgnvi2VaXfjscLoN2sbUObWbnc45pZr(看代码 经过了base64编码)
进入Cry_Encrypt函数,看到有一个变量名字是AesKey,大概率是aes加密

此处去了解一下python中的AES模块
AES.new(key, AES.MODE_ECB):创建一个新的AES加密对象
aes.decrypt(ciphertext):使用AES对象来解密
尝试用新鲜刚学一点的python写脚本(?
然后在意想不到的地方坐牢了,先是pip2和pip3兼容出了点问题,然后pip install pycryptodome之后,在pycharm里还是没有导入这个库,费了点时间才搞好
总之最后的脚本:
from Cryptodome.Cipher import AES
import base64
key=b'9e015a9f82d367bc'
aes_decode_flag='KKN+NK5ZWN4xr4kM1+qq+2wJKUEEaiWmITgnvi2VaXfjscLoN2sbUObWbnc45pZr'
aesed_flag=base64.b64decode(aes_decode_flag)
aes_decode=AES.new(key,AES.MODE_ECB)
flag=aes_decode.decrypt(aesed_flag)
print(flag)
运行得到flag
SSHCTF{Crypt0_1n_R3v3rs3_1s_so000oo0_Imp0rt@nt!}
@"Pinguw"#116
Q1:怎么判断aes的mode是ECB还是其他模式
Q2:我需不需要去看看crypto,感觉re题好多加密(所以联想到了crypto>_<)
0x06 flower
知识点:花指令
无壳,拖进ida,main无法f5反编译
对main按P(编辑为函数,将从光标位置开始的代码识别为函数,IDA将自动分析)
查看报错
.text:004010A2: The function has undefined instruction/data at the specified address.
Your request has been put in the autoanalysis queue.
双击跳到.text:004010A2
pic 7
jnz short near ptr byte_4010A2:如果上一条test的结果不为零,则跳转到地址004010A2处的标签byte_4010A2。由于byte_4010A2是一个数据定义(db 0C7h),这个跳转通常不会执行任何有意义的操作,因此这条指令可能是一个花指令。
0x05 SMC
知识点:SMC,动态调试
无壳,拖进ida,进入main函数
pic
进入sub_140001280,发现了VirtualProtect,结合题目,应该是是smc问题,需要动态调试
(SMC指的是Self-Modifying Code,即自修改代码。程序在运行时会修改自己的代码或数据,这样做可以阻止他人直接进行静态分析。)
找到自加密的部分,发现sub_1400011C0的数据是一些奇怪的东西
pic 9
继续读sub_140001280,v2是VirtualProtect的结果,所以在return v2处设置断点
debugger启动(此处跑去学idebugger的用法)
从0x1400011C0选中到0x14000127E这整个一段。按u回到字节文本状态,再回到这一段的开头,按p重新编译,f5拿到了正确的sub_1400011C0函数,
Q:没太明白这里重编译的原理是啥,大体流程是程序执行到断点,然后对0x1400011C0到0x14000127E这一段--->文本--->编译,为什么这样就会编译正确,但是之前不会捏(是因为这个时候还没有自加密吗?),以及为什么是选中0x1400011C0到0x14000127E这一段
pic 10
分析可以知道flag=str^0x23,写脚本拿到flag
str=b'EOBDXZFP|V|GL|JW^'
print("".join([chr(i ^ 0x23) for i in str]))
#flag{yes_u_do_it}
0x06 maze
知识点:迷宫类型的题
无壳,拖入ida,
main-->sub_1257-->sub_13D3 (图里自己改了变量名字方便理解)

语句if ( byte_4020[225 * dword_42C8 - 15 + 15 * dword_42CC + dword_42D0] == 1 ):
计算 byte_4020 数组的一个索引,并检查该索引处的值是否为1。
如果该值是1,将该索引处的值改为3,将另一个索引处的值改为1。
如果该值不是1,检查它是否为4,如果该值是4,函数返回 1LL(long long的1)。
如果dword_42CC为0,或者byte_4020数组中指定索引的值既不是1也不是4,函数返回 0LL。
可以猜测到,3是当前位置,1是路,4是重点,0是障碍物
查看数组byte_4020,shift+e,共有675个字符,里面有3个4,即为3个终点,所以是15*15的3个迷宫(迷宫要自己判断,交给ai它会骗人,比如它告诉我迷宫一共有256个字符……)
第一个迷宫:
1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 0 3 1 1 0 0 0 0 0 0
1 1 1 1 1 0 0 0 1 0 0 0 0 0 0
1 1 1 1 1 0 0 0 1 0 0 0 0 0 0
1 1 1 1 1 0 0 0 1 1 1 1 1 0 0
1 1 1 1 1 0 0 0 0 0 0 0 1 0 0
1 1 1 1 1 0 0 0 0 0 0 0 1 0 0
1 1 1 1 1 0 0 0 0 0 0 0 1 1 0
1 1 1 1 1 0 0 0 0 0 0 0 0 1 0
1 1 1 1 1 0 0 0 0 0 0 0 0 4 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
第二个迷宫:
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 0 3 1 1 1 1 1 0 0 0 0 0 0
1 1 0 1 1 0 0 0 1 0 0 0 0 0 0
1 1 0 0 0 0 0 0 1 0 0 0 0 0 0
1 1 0 1 1 0 0 0 1 1 1 1 1 0 0
1 1 0 1 1 0 0 0 0 0 0 0 1 0 0
1 1 0 1 1 0 0 0 0 0 0 0 1 0 0
1 1 0 1 1 0 0 0 0 0 1 1 1 1 0
1 1 0 1 1 0 0 0 0 0 1 0 0 1 0
1 1 0 1 1 0 0 0 0 0 1 0 0 0 0
1 1 0 1 1 1 1 1 1 0 1 0 1 1 0
1 1 0 1 1 1 1 1 1 1 1 1 1 1 0
1 1 0 0 0 0 0 0 0 0 0 0 0 4 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
第三个迷宫:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 3 1 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 1 1 1 0 0 0 0 0 0 0
0 0 0 1 1 1 0 1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 1 0 0 0 0 0 0 0
0 1 1 0 1 0 0 1 0 0 0 0 0 0 0
0 0 1 1 1 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 1 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 4 0
得到了迷宫之后,应该确定输入什么字符去控制这个迷宫走向,
在sub_1257中可以发现,条件判断中v1的值分别为119,115,100,97,27,对应的ASCII字符分别为w、a、s、d和esc

那么上下左右分别对应w、s、a、d。
现在我们已经有了迷宫内容,走迷宫的方法,接下来手动解出迷宫即可。
1 : 'ddsssddddsssdss'
2 : 'dddddsssddddsssaassssddds'
3 : 'ddssddwddssssssdddssssdddss'
根据程序输出内容"success! the flag is flag{md5(your input)}"可以知道flag需要经过md5加密
写脚本拿flag
import hashlib
s1 = 'ddsssddddsssdss'
s2 = 'dddddsssddddsssaassssddds'
s3 = 'ddssddwddssssssdddssssdddss'
print('SSHCTF{' + hashlib.md5((s1+ s2 + s3).encode('utf-8')).hexdigest() + '}')

浙公网安备 33010602011771号