-
-
[原创]2019看雪CTF Q2第六题
-
2019-6-10 21:16 2192
-
此题没有反调试,逻辑也不复杂。
运行界面如下:
IDA F5出来的代码如下
printf("please enter Serial:"); scanf(" %s", &bindata); if ( strlen((const char *)&bindata) > 0x31 ) puts("error"); v7 = (char *)calloc(1u, 0x400u); v3 = strlen((const char *)&bindata); base64_encode(&bindata, v7, v3); v6 = "!NGV%,$h1f4S3%2P(hkQ94=="; if ( !strcmp("!NGV%,$h1f4S3%2P(hkQ94==", v7) ) puts("Success"); else puts("Please Try Again"); free(v7); system("pause"); return 0;
要求输入SN长度不超过0x31,SN经过base64encode计算,要求与"!NGV%,$h1f4S3%2P(hkQ94=="相等。
跟踪base64_encode函数,发现相较于标准base64encode算法修改了2处地方:
1) 将编码表修改为
tuvwxTUlmnopqrs7YZabcdefghij8yz0123456VWXkABCDEFGHIJKLMNOPQRS9+/
2) 将编码后的字符加密处理,函数逻辑即为charEncrypt()
char __cdecl charEncrypt(int data) { int dataa; // [esp+18h] [ebp+8h] dataa = aTuvwxtulmnopqr[data]; if ( dataa > 0x40 && dataa <= 0x5A ) return 0x9B - dataa; if ( dataa > 0x60 && dataa <= 0x7A ) return dataa - 0x40; if ( dataa > 0x2F && dataa <= 0x39 ) return dataa + 0x32; if ( dataa == '+' ) return 'w'; if ( dataa == '/' ) dataa = 'y'; return dataa; }
运行下程序,得出字符的加密映射关系
charEncrypt(A)=Z
charEncrypt(B)=Y
charEncrypt(C)=X
charEncrypt(D)=W
charEncrypt(E)=V
charEncrypt(F)=U
charEncrypt(G)=T
charEncrypt(H)=S
charEncrypt(I)=R
charEncrypt(J)=Q
charEncrypt(K)=P
charEncrypt(L)=O
charEncrypt(M)=N
charEncrypt(N)=M
charEncrypt(O)=L
charEncrypt(P)=K
charEncrypt(Q)=J
charEncrypt(R)=I
charEncrypt(S)=H
charEncrypt(T)=G
charEncrypt(U)=F
charEncrypt(V)=E
charEncrypt(W)=D
charEncrypt(X)=C
charEncrypt(Y)=B
charEncrypt(Z)=A
charEncrypt(a)=!
charEncrypt(b)="
charEncrypt(c)=#
charEncrypt(d)=$
charEncrypt(e)=%
charEncrypt(f)=&
charEncrypt(g)='
charEncrypt(h)=(
charEncrypt(i)=)
charEncrypt(j)=*
charEncrypt(k)=+
charEncrypt(l)=,
charEncrypt(m)=-
charEncrypt(n)=.
charEncrypt(o)=/
charEncrypt(p)=0
charEncrypt(q)=1
charEncrypt(r)=2
charEncrypt(s)=3
charEncrypt(t)=4
charEncrypt(u)=5
charEncrypt(v)=6
charEncrypt(w)=7
charEncrypt(x)=8
charEncrypt(y)=9
charEncrypt(z)=:
charEncrypt(0)=b
charEncrypt(1)=c
charEncrypt(2)=d
charEncrypt(3)=e
charEncrypt(4)=f
charEncrypt(5)=g
charEncrypt(6)=h
charEncrypt(7)=i
charEncrypt(8)=j
charEncrypt(9)=k
charEncrypt(+)=w
charEncrypt(/)=y
还原出来的base64编码算法为:
static const char *codes = "tuvwxTUlmnopqrs7YZabcdefghij8yz0123456VWXkABCDEFGHIJKLMNOPQRS9+/"; char charEncrypt(int dataa) { if (dataa > 0x40 && dataa <= 0x5A) return 0x9B - dataa; if (dataa > 0x60 && dataa <= 0x7A) return dataa - 0x40; if (dataa > 0x2F && dataa <= 0x39) return dataa + 0x32; if (dataa == '+') return 0x77; if (dataa == '/') dataa = 0x79; return dataa; } int base64_encode(const unsigned char *in, unsigned long len, unsigned char *out) { unsigned long i, len2, leven; unsigned char *p; /* vunsignedalid output size ? */ len2 = 4 * ((len + 2) / 3); p = out; leven = 3 * (len / 3); for (i = 0; i < leven; i += 3) { *p++ = charEncrypt(codes[in[0] >> 2]); *p++ = charEncrypt(codes[((in[0] & 3) << 4) + (in[1] >> 4)]); *p++ = charEncrypt(codes[((in[1] & 0xf) << 2) + (in[2] >> 6)]); *p++ = charEncrypt(codes[in[2] & 0x3f]); in += 3; } /* Pad it if necessary... */ if (i < len) { unsigned a = in[0]; unsigned b = (i + 1 < len) ? in[1] : 0; unsigned c = 0; *p++ = charEncrypt(codes[a >> 2]); *p++ = charEncrypt(codes[((a & 3) << 4) + (b >> 4)]); *p++ = (i + 1 < len) ? charEncrypt(codes[((b & 0xf) << 2) + (c >> 6)]) : '='; *p++ = '='; } /* append a NULL byte */ *p = '\0'; return p - out; }
总结:
将SN的字符每3个字节分为一组,每个字节占8bit,共24个二进制位;
将转换后的二进制位每6个一组,分为4组;
在每组前面添加两个0,每组由6个变为8个二进制位,总共32个二进制位,即四个字节;
根据编码表”tuvwxTUlmnopqrs7YZabcdefghij8yz0123456VWXkABCDEFGHIJKLMNOPQRS9+/”获得对应的值;
根据对应值获取charEncrypt后的数值。
刚开始准备枚举爆破,写了如下程序
char szBuf[17] = ""; char szBufEncode[0x100] = "\0"; for(char x1=0x30;x1<=0x7A;x1++) for(char x2=0x30;x2<=0x7A;x2++) for (char x3 = 0x30; x3 <= 0x7A; x3++) for (char x4 = 0x30; x4 <= 0x7A; x4++) for (char x5 = 0x30; x5 <= 0x7A; x5++) for (char x6 = 0x30; x6 <= 0x7A; x6++) for (char x7 = 0x30; x7 <= 0x7A; x7++) for (char x8 = 0x30; x8 <= 0x7A; x8++) for (char x9 = 0x30; x9 <= 0x7A; x9++) for (char x10 = 0x30; x10 <= 0x7A; x10++) for (char x11 = 0x30; x11 <= 0x7A; x11++) for (char x12 = 0x30; x12 <= 0x7A; x12++) for (char x13 = 0x30; x13 <= 0x7A; x13++) for (char x14 = 0x30; x14 <= 0x7A; x14++) for (char x15 = 0x30; x15 <= 0x7A; x15++) for (char x16 = 0x30; x16 <= 0x7A; x16++) { szBuf[0] = x1; szBuf[1] = x2; szBuf[2] = x3; szBuf[3] = x4; szBuf[4] = x5; szBuf[5] = x6; szBuf[6] = x7; szBuf[7] = x8; szBuf[8] = x9; szBuf[9] = x10; szBuf[10] = x11; szBuf[11] = x12; szBuf[12] = x13; szBuf[13] = x14; szBuf[14] = x15; szBuf[15] = x16; printf("%s\n", szBuf); base64_encode(szBuf, 16, szBufEncode); if (!strcmp("!NGV%,$h1f4S3%2P(hkQ94==", szBufEncode)) { printf("the Flag is %s", szBuf); break; } }
运行了很久也没跑出来,心急之下笔算出结果
SN=”KanXue2019ctf_st”
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课