-
-
[原创]CTF2018第十五题分析(qwertyaa)
-
2018-7-14 16:59 2470
-
运行程序/进行IDA静态分析/利用IDA动态调试程序
这道题是一种智能设备的题,以前没见过,所以这些内容我都得摸索一遍。以下是我摸索的结果:
- qemu并不一定必须要在Ubuntu上跑,在Windows下跑也完全可以。
- 通过查找字符串
"please input your key:"
我们可以发现程序应该在压缩包内4个文件中的 a9rootfs 内,这个文件可以用7-zip打开,解压后搜索,可以发现关键程序是 bin 目录下的 sh 文件。这个文件可以直接在IDA上进行静态分析。 - 感觉 a9rootfs 内的库文件和linux很像,不过WSL上跑不起来。后来想了想应该在ARM的设备上才能正确运行,结果在我的Android手机上运行成功。而后者我们可以直接用IDA的android_server来调试。
分析流程
这个程序main
函数不知为何F5后内容残缺,不过可以动态调试来了解它,也可以将main
函数undefine后分段视为函数,进行分析。
首先它要输入一个字符串,然后做一系列变换后bin2hex
并与一个字符串比对。
变换函数如下:
signed int __fastcall multiTrans(_BYTE *in, _BYTE *out, signed int size) { signed int result; // r0 char tmp[256]; // [sp+14h] [bp-108h] int v7; // [sp+114h] [bp-8h] v7 = _stack_guard; if ( size > 128 ) size = 128; copy(out, in, size, size); hexify2(out, tmp, size); bitConv(out, tmp, size); xorMix(out, size); hexify(out, tmp, size); bitConv2(out, tmp, size); xorMix(out, size); hexify2(out, tmp, size); bitConv2(out, tmp, size); xorMix(out, size); hexify(out, tmp, size); bitConv(out, tmp, size); xorMix(out, size); result = 1; if ( v7 != _stack_guard ) corrupt(); return result; }
这里的hexify*
、bitConv*
中不考虑字符串的不同的话就是互为逆运算的,它们将out
信息的每半byte按一定规则进行置换后分别进行bin2hex
或hex2bin
。
而xorMix
如下所示:
signed int __fastcall xorMix(_BYTE *buf, signed int size) { int i; // [sp+Ch] [bp-8h] signed int j; // [sp+Ch] [bp-8h] for ( i = 0; size / 2 > i; ++i ) { buf[i] ^= buf[size - 1 - i]; buf[size - 1 - i] ^= buf[i]; buf[i] ^= buf[size - 1 - i]; } for ( j = 1; j < size; ++j ) buf[j] ^= buf[j - 1]; return size; }
前一循环内通过三次异或来交换内容,最终使得整个串翻转,后面一个使得每一位异或上前一位被异或后的值来加密,只需要倒着异或一遍就可以解密。
反向计算得到Key
上述操作都是可逆的,所以我们可以写个程序来实现反向计算。
#include <cstdio> #include <cstring> #include <cctype> #include <algorithm> using namespace std; typedef unsigned char byte; const char prev[]="C1371DA51A9030079E21DCDC5B78E38563872139C13F6F"; char ans[0x100]={0},tmp[0x100]={0}; int trans(char x){ if(isdigit(x))return x-'0'; return x-'A'+0xa; } void xorMix(char*x,int size){ byte*ans=(byte*)x; for(int i=size-1;i>0;i--)ans[i]^=ans[i-1]; for(int i=0;i<size/2;i++) swap(ans[i],ans[size-1-i]); } void bitConv(char*in,char*out,int size){ const char x[]="13579BDF02468ACE"; int i; for(i=0;i<size;i++){ out[2*i]=x[(byte)in[i]>>4]; out[2*i+1]=x[in[i]&0xf]; } out[2*i]=0; } void bitConv2(char*in,char*out,int size){ const char x[]="FA50B61C72D83E94"; int i; for(i=0;i<size;i++){ out[2*i]=x[(byte)in[i]>>4]; out[2*i+1]=x[in[i]&0xf]; } out[2*i]=0; } signed int findPos(char chr, const char* str) { int i; for(i=0;i<=15&&chr!=str[i];i++); return i; } void hexify(char*in,char*out,int size){ const char x[]="0369CF258BE147AD"; int i; byte*xout=(byte*)out; for(i=0;i<size;i++){ xout[i]=findPos(in[2*i],x)*16+findPos(in[2*i+1],x); } out[i]=0; } void hexify2(char*in,char*out,int size){ const char x[]="FDB08642ECA97531"; int i; byte*xout=(byte*)out; for(i=0;i<size;i++){ xout[i]=findPos(in[2*i],x)*16+findPos(in[2*i+1],x); } out[i]=0; } int main(){ int size=strlen(prev)/2; for(int i=0;i<size;i++) ans[i]=trans(prev[2*i])*16+trans(prev[2*i+1]); xorMix(ans,size); bitConv(ans,tmp,size); hexify(tmp,ans,size); xorMix(ans,size); bitConv2(ans,tmp,size); hexify2(tmp,ans,size); xorMix(ans,size); bitConv2(ans,tmp,size); hexify(tmp,ans,size); xorMix(ans,size); bitConv(ans,tmp,size); hexify2(tmp,ans,size); printf("Key: %s\n",ans); return 0; }
最终我们得到了Key:2018ctf0520pediy1314yyp
输入到程序中可以出现flag:you got it [B1732120572455BAFD30F062F9C49A8A996A8A9DDB4283]
,其中括号中的内容即为flag。这个内容是将输入内容通过如下函数变换后再通过上述几种变换得来的。
signed int __fastcall transform(_BYTE *in, _BYTE *out, int a3) { int i; // [sp+14h] [bp-8h] for ( i = 0; i < a3; ++i ) out[i] = i * in[i] + 31; return 1; }
接下来的you have a chance to exploit it:
会将读入内容hex2bin
的结果xorMix
一次,将所得串作为启动"/bin/busybox"
的参数,这个类似于GetShell了。
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界
最后于 2018-8-15 21:48
被qwertyaa编辑
,原因: 补充
赞赏
他的文章
看原图