攻防世界基础题(12道)
第一题
附件下载给出源码:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
if (argc != 4) {
printf("what?\n");
exit(1);
}
unsigned int first = atoi(argv[1]);
if (first != 0xcafe) {
printf("you are wrong, sorry.\n");
exit(2);
}
unsigned int second = atoi(argv[2]);
if (second % 5 == 3 || second % 17 != 8) {
printf("ha, you won't get it!\n");
exit(3);
}
if (strcmp("h4cky0u", argv[3])) {
printf("so close, dude!\n");
exit(4);
}
printf("Brr wrrr grr\n");
unsigned int hash = first * 31337 + (second % 17) * 11 + strlen(argv[3]) - 1615810207;
printf("Get your key: ");
printf("%x\n", hash);
return 0;
}
分析源码:
发现要满足几个条件程序才能顺利进行,我们需要做的就是找出参数带入后面的hash式子,就能得出答案了。
1、 首先满足first的值为十六进制的0xcafe,通过在线网站得出十进制值为51966。
分享一下网站吧:https://tool.lu/hexconvert/
2、 满足second%5的值不等于3,并且second%17的值等于8,不难看出25就符合这个条件。
3、 不难看出我们需要的值为字符串h4cky0u的长度,值为7
答案揭晓
现在我们知道了所有的参数值了,经过我的修改如下:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
printf("Brr wrrr grr\n");
unsigned int hash = 51966 * 31337 + ((25 % 17) * 11 + 7) - 1615810207;
printf("Get your key: ");
printf("%x\n", hash);
return 0;
}
得出结果如下:
第二题
考脱壳处理,附件是一个二进制文件放到pe里发现经过upx壳处理,如图:
kali自带upx,打开虚拟机里面的kali,将文件拖进去执行代码:
upx -d 文件的绝对路径
答案揭晓
将脱过壳的二进制文件拖进ida分析,搜索字符串flag,得出结果。
第三题
先放入pe 查壳和分析程序,发现是一个64位ELF文件
接着放入ida分析,先重main函数开始,F5查看伪代码
分析这一步可知密码的长度必须大于v8字符串的长度
通过查看代码看出v8字符串长度为17
从这段代码中可以看出密码的长度等于v8字符串的长度
接下来就是关键的算法了,可以知道算出算法就能得到答案
答案揭晓
源码:
int main()
{
int i;
long long v7=28537194573619560LL;
char v8[]=":\"AL_RT^L*.?+6/46";
char final_string[20];
for(i=0;i<17;i++)
{
final_string[i]=(char)(*((BYTE*)&v7+i%7)^v8[i]);
printf("%c",final_string[i]);
}
return 0;
}
第四题
打开附件是一个二进制文件,先拖入pe里查看,发现是一个32位的ELF文件
将文件拖入32位ida里面分析,当我按下Shift+F12,发现了神秘的flag,如图:
奇怪的flag获得方式增加了,不过这都第四题了,不应该越来越难吗?
答案揭晓
然后我深入了解后发现这道题的意思大概是让我们学会找关键字,不能死板,如图:
这是main函数的伪代码,发现里面没什么算法,但是有一个关键词strs,我们接着双击strs,发现了flag,这才是正解,哈哈哈哈!
第五题
附件下载后是一个pyc文件,需要用到在线python反编译器解读,源码(python2):
import base64
def encode(message):
s = ''
for i in message:
x = ord(i) ^ 32
x = x + 16
s += chr(x)
return base64.b64encode(s)
correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
flag = ''
print('Input flag:')
flag = raw_input()
if encode(flag) == correct:
print
'correct'
else:
print
'wrong'
网站链接:https://tool.lu/pyc/
分析一下代码,得出改程序需要逆向思维,将给出的字符串 **‘XlNkVmtUI1MgXWBZXCFeKY+AaXNt’**通过逆向得出flag。
答案揭晓
我写的源码(python2):
import base64
flag=base64.b64decode('XlNkVmtUI1MgXWBZXCFeKY+AaXNt')
x=''
for i in flag:
x+=chr((ord(i)-16)^32)
print("flag:",x)
首先明白base64模块里面的加密、解密代码,odr() :将字符串转化成ASCII码,chr():将ASCII码转化成字符串,然后将字符串解密,通过逆向算法来求出最后的flag。
第六题
放入pe里面发现是个32位exe程序
打开是一个小游戏,这一题的解法很多,可以通过玩游戏获得,也可以分析程序算法获得,这个小游戏很好玩,我两分钟就通关了,接下来分析算法
接着放入ida里分析程序
主要伪代码如下,通过分析我们知道当if结果都为1时会进入sub_457AB4()函数:
void __cdecl main_0()
{
char v0; // ST08_1
char v1; // ST08_1
char v2; // ST08_1
char v3; // ST08_1
char v4; // ST08_1
char v5; // ST08_1
char v6; // ST08_1
char v7; // ST08_1
char v8; // ST08_1
char v9; // ST08_1
char v10; // ST08_1
char v11; // ST08_1
char v12; // ST08_1
char v13; // ST08_1
char v14; // ST08_1
char v15; // ST08_1
char v16; // ST08_1
char v17; // ST08_1
char v18; // [esp+0h] [ebp-FCh]
char v19; // [esp+0h] [ebp-FCh]
signed int i; // [esp+DCh] [ebp-20h]
int v21; // [esp+F4h] [ebp-8h]
sub_45A7BE((int)&unk_50B110, v18);
sub_45A7BE((int)&unk_50B158, v0);
sub_45A7BE((int)&unk_50B1A0, v1);
sub_45A7BE((int)&unk_50B1E8, v2);
sub_45A7BE((int)&unk_50B230, v3);
sub_45A7BE((int)&unk_50B278, v4);
sub_45A7BE((int)&unk_50B2C0, v5);
sub_45A7BE((int)&unk_50B308, v6);
sub_45A7BE((int)&unk_50AFD0, v7);
sub_45A7BE((int)"| by 0x61 |\n", v8);
sub_45A7BE((int)"| |\n", v9);
sub_45A7BE((int)"|------------------------------------------------------|\n", v10);
sub_45A7BE(
(int)"Play a game\n"
"The n is the serial number of the lamp,and m is the state of the lamp\n"
"If m of the Nth lamp is 1,it's on ,if not it's off\n"
"At first all the lights were closed\n",
v11);
sub_45A7BE((int)"Now you can input n to change its state\n", v12);
sub_45A7BE(
(int)"But you should pay attention to one thing,if you change the state of the Nth lamp,the state of (N-1)th and (N+1"
")th will be changed too\n",
v13);
sub_45A7BE((int)"When all lamps are on,flag will appear\n", v14);
sub_45A7BE((int)"Now,input n \n", v15);
while ( 1 )
{
while ( 1 )
{
sub_45A7BE((int)"input n,n(1-8)\n", v19);
sub_459418();
sub_45A7BE((int)"n=", v16);
sub_4596D4("%d", &v21);
sub_45A7BE((int)"\n", v17);
if ( v21 >= 0 && v21 <= 8 )
break;
sub_45A7BE((int)"sorry,n error,try again\n", v19);
}
if ( v21 )
{
sub_4576D6(v21 - 1);
}
else
{
for ( i = 0; i < 8; ++i )
{
if ( (unsigned int)i >= 9 )
j____report_rangecheckfailure();
byte_532E28[i] = 0;
}
}
j__system("CLS");
sub_458054();
if ( byte_532E28[0] == 1
&& byte_532E28[1] == 1
&& byte_532E28[2] == 1
&& byte_532E28[3] == 1
&& byte_532E28[4] == 1
&& byte_532E28[5] == 1
&& byte_532E28[6] == 1
&& byte_532E28[7] == 1 )
{
sub_457AB4();
}
}
}
sub_457AB4()函数里面应该就是flag的主要算法,如下:
sub_45A7BE((int)"done!!! the flag is ");
v59 = 18;
v60 = 64;
v61 = 98;
v62 = 5;
v63 = 2;
v64 = 4;
v65 = 6;
v66 = 3;
v67 = 6;
v68 = 48;
v69 = 49;
v70 = 65;
v71 = 32;
v72 = 12;
v73 = 48;
v74 = 65;
v75 = 31;
v76 = 78;
v77 = 62;
v78 = 32;
v79 = 49;
v80 = 32;
v81 = 1;
v82 = 57;
v83 = 96;
v84 = 3;
v85 = 21;
v86 = 9;
v87 = 4;
v88 = 62;
v89 = 3;
v90 = 5;
v91 = 4;
v92 = 1;
v93 = 2;
v94 = 3;
v95 = 44;
v96 = 65;
v97 = 78;
v98 = 32;
v99 = 16;
v100 = 97;
v101 = 54;
v102 = 16;
v103 = 44;
v104 = 52;
v105 = 32;
v106 = 64;
v107 = 89;
v108 = 45;
v109 = 32;
v110 = 65;
v111 = 15;
v112 = 34;
v113 = 18;
v114 = 16;
v115 = 0;
v2 = 123;
v3 = 32;
v4 = 18;
v5 = 98;
v6 = 119;
v7 = 108;
v8 = 65;
v9 = 41;
v10 = 124;
v11 = 80;
v12 = 125;
v13 = 38;
v14 = 124;
v15 = 111;
v16 = 74;
v17 = 49;
v18 = 83;
v19 = 108;
v20 = 94;
v21 = 108;
v22 = 84;
v23 = 6;
v24 = 96;
v25 = 83;
v26 = 44;
v27 = 121;
v28 = 104;
v29 = 110;
v30 = 32;
v31 = 95;
v32 = 117;
v33 = 101;
v34 = 99;
v35 = 123;
v36 = 127;
v37 = 119;
v38 = 96;
v39 = 48;
v40 = 107;
v41 = 71;
v42 = 92;
v43 = 29;
v44 = 81;
v45 = 107;
v46 = 90;
v47 = 85;
v48 = 64;
v49 = 12;
v50 = 43;
v51 = 76;
v52 = 86;
v53 = 13;
v54 = 114;
v55 = 1;
v56 = 117;
v57 = 126;
v58 = 0;
for ( i = 0; i < 56; ++i )
{
*(&v2 + i) ^= *(&v59 + i);
*(&v2 + i) ^= 0x13u;
}
return sub_45A7BE((int)"%s\n");
}
答案揭晓
通过小游戏得出答案
下面是我写的python脚本,跑出flag:
str1=[123,32,18,98,119,108,65,41,124,80,125,38,124,111,74,49,83,108,94,108,84,6,96,83,44,121,104,110,32,95,117,101,99,123,127,119,96,48,107,71,92,29,81,107,90,85,64,12,43,76,86,13,114,1,117,126,0]
str2=[18,64,98,5,2,4,6,3,6,48,49,65,32,12,48,65,31,78,62,32,49,32,1,57,96,3,21,9,4,62,3,5,4,1,2,3,44,65,78,32,16,97,54,16,44,52,32,64,89,45,32,65,15,34,18,16,0]
str3=''
for i in range(56):
str1[i]^=str2[i]
str1[i]^=0x13
str3+=chr(str1[i])
print(str3)
第七题
附件是一个exe程序,将程序放入pe里查看,是一个32位exe文件
放入ida里面分析,又是一个算法,看着比较复杂,分析分析。
strcpy(&v13, "437261636b4d654a757374466f7246756e");
while ( 1 )
{
memset(&v10, 0, 0x20u);
v11 = 0;
v12 = 0;
sub_40134B(aPleaseInputYou, v6);
scanf(aS, v9);
if ( strlen(v9) > 0x11 )
break;
v3 = 0;
do
{
v4 = v9[v3];
if ( !v4 )
break;
sprintf(&v8, asc_408044, v4);
strcat(&v10, &v8);
++v3;
}
while ( v3 < 17 );
if ( !strcmp(&v10, &v13) )
sub_40134B(aSuccess, v7);
else
sub_40134B(aWrong, v7);
}
sub_40134B(aWrong, v7);
result = stru_408090._cnt-- - 1;
if ( stru_408090._cnt < 0 )
return _filbuf(&stru_408090);
++stru_408090._ptr;
return result;
}
将字符串复制到v13
这里知道输入的字符串不能大于17
将输入的字符串以16进制复制到v10里
判断输入字符串的长度与给的字符串是否一致,如果一致则输入正确
答案揭晓
将十六进制转化成普通字符串就是flag
转化链接:http://www.bejson.com/convert/ox2str/
第八题
打开附件是一个二进制文件,先放入pe中分析,是一个64位ELF文件
将文件放入64位ida里面分析,伪代码如下:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v3; // al
__int64 v5; // [rsp+0h] [rbp-40h]
int i; // [rsp+4h] [rbp-3Ch]
FILE *stream; // [rsp+8h] [rbp-38h]
char filename[8]; // [rsp+10h] [rbp-30h]
unsigned __int64 v9; // [rsp+28h] [rbp-18h]
v9 = __readfsqword(0x28u);
LODWORD(v5) = 0;
while ( (signed int)v5 < strlen(s) )
{
if ( v5 & 1 )
v3 = 1;
else
v3 = -1;
*(&t + (signed int)v5 + 10) = s[(signed int)v5] + v3;
LODWORD(v5) = v5 + 1;
}
strcpy(filename, "/tmp/flag.txt");
stream = fopen(filename, "w");
fprintf(stream, "%s\n", u, v5);
for ( i = 0; i < strlen(&t); ++i )
{
fseek(stream, p[i], 0);
fputc(*(&t + p[i]), stream);
fseek(stream, 0LL, 0);
fprintf(stream, "%s\n", u);
}
fclose(stream);
remove(filename);
return 0;
}
主要算法:
将u的值写入flag.txt,值得注意的是写入的值并不是我们通过算法得出的值v5
通过查找发现 u,s,t 的值如下:
注意t的值前面还有一个 53h 转化成字符串为 S
很明显这是个坑,正确的flag应该是v5的值,还不止这些,如果直接运行里面的内容还会被转移:
这个题的一种思路就是在remove这里下断点然后在linux里面执行,会在tmp文件夹里生存flag.txt文件,儿里面的值确实一堆*号就是上面提的u的值,所以社会险恶处处是坑,还是直接写Python脚本来的实在。
答案揭晓
Python3脚本如下:
s='c61b68366edeb7bdce3c6820314b7498'
flag='SharifCTF{'
v5=0
while v5<len(s):
if (v5 & 1):
v3=1
else:
v3=-1
flag+=chr(ord(s[v5])+v3)
v5+=1
print(flag+'}')
第九题
附件是一个exe文件打开如图:
放入pe里分析一下,是个32位的文件
放入32位ida里面进一步分析,main函数主要伪代码:
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
__int128 v5; // [esp+0h] [ebp-44h]
__int64 v6; // [esp+10h] [ebp-34h]
int v7; // [esp+18h] [ebp-2Ch]
__int16 v8; // [esp+1Ch] [ebp-28h]
char v9; // [esp+20h] [ebp-24h]
_mm_storeu_si128((__m128i *)&v5, _mm_loadu_si128((const __m128i *)&xmmword_413E34));
v7 = 0;
v6 = qword_413E44;
v8 = 0;
printf(&byte_413E4C);
printf(&byte_413E60);
printf(&byte_413E80);
scanf("%s", &v9);
v3 = strcmp((const char *)&v5, &v9);
if ( v3 )
v3 = -(v3 < 0) | 1;
if ( v3 )
printf(aFlag);
else
printf((const char *)&unk_413E90);
system("pause");
return 0;
}
这里应该是将下面的值赋给了v5
v6的值经过处理是下面的结果
答案揭晓
将两个字符串连起来,通过输入逆向后字符串验证,通过就显示get flag √
第十题
附件是一个32位的ELF文件,代表可以在linux下运行。
放入32位ida里分析一下
发现了关键函数,里面有一个英文加密很显眼
加密函数源码如下:
wchar_t *__cdecl decrypt(wchar_t *s, wchar_t *a2)
{
size_t v2; // eax
signed int v4; // [esp+1Ch] [ebp-1Ch]
signed int i; // [esp+20h] [ebp-18h]
signed int v6; // [esp+24h] [ebp-14h]
signed int v7; // [esp+28h] [ebp-10h]
wchar_t *dest; // [esp+2Ch] [ebp-Ch]
v6 = wcslen(s);
v7 = wcslen(a2);
v2 = wcslen(s);
dest = (wchar_t *)malloc(v2 + 1);
wcscpy(dest, s);
while ( v4 < v6 )
{
for ( i = 0; i < v7 && v4 < v6; ++i )
dest[v4++] -= a2[i];
}
return dest;
}
通过简单的寻找汇编线索,发现加密函数储存的flag值在eax中
得学新技能了,,,动态调试,用GDB来动态调试取出对应寄存器里的值
GDB使用命令:https://www.cnblogs.com/Mayfly-nymph/p/11403150.html
答案揭晓
时隔两天,我又回来了,大家用gdb的时候千万别用绝对路径打开文件,尽量用 ./文件名 的形式打开文件,这样不会报错,如图(顺手在加密函数那里下一个断点):
r 代表运行程序,运行到之前下的断点,(这里权限不够了记得给文件加上权限)
n代表运行一步
我们通过看汇编已经知道了运行过decrypt函数后将字符串储存在eax寄存器中,代码:
x/6sw $eax
x:表示查看寄存器中的数值
6:显示6行数据
s:字符串的形式打印
w:word的缩写,代表4字节
第十一题
看题目可能涉及到编码的问题,先下载附件,是一个exe文件,运行如图:
放入PE里查看,是一个32位的文件
放入32位ida立面分析,F5查看伪代码:
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // ecx
CHAR *lpMem; // [esp+8h] [ebp-Ch]
HANDLE hHeap; // [esp+10h] [ebp-4h]
hHeap = HeapCreate(0x40000u, 0, 0);
lpMem = (CHAR *)HeapAlloc(hHeap, 8u, MaxCount + 1);
memcpy_s(lpMem, MaxCount, &unk_409B10, MaxCount);
if ( sub_40102A() || IsDebuggerPresent() )
{
__debugbreak();
sub_401000(v3 + 4, (int)lpMem);
ExitProcess(0xFFFFFFFF);
}
MessageBoxA(0, lpMem + 1, "Flag", 2u);
HeapFree(hHeap, 0, lpMem);
HeapDestroy(hHeap);
ExitProcess(0);
}
发现程序主要是由if语句判断,如果跳过if语句会直接弹出MessageBoxA窗口然后就会出现乱码。
接着分析框架:
清晰的知道了大致框架,可以通过od动态调试将程序先跳转到401096,通过401000函数进行解码,
并且把断点 int3 改成 nop :
继续修改,将跳转到4010EF改成4010B9弹出解码后的flag:
答案揭晓
运行软件得出flag:
第十二题
描述没有看出什么端倪,下载附件,是一个二进制文件,放入PE查看:
是一个64位的ELF文件,可以放入64位ida里面F5分析一下伪代码(这次的解释直接备注进代码了):
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
const char *v3; // rsi
signed __int64 v4; // rbx
signed int v5; // eax
char v6; // bp
char v7; // al
const char *v8; // rdi
__int64 v10; // [rsp+0h] [rbp-28h]
v10 = 0LL;
puts("Input flag:");
scanf("%s", &s1, 0LL);
if ( strlen(&s1) != 24 || (v3 = "nctf{", strncmp(&s1, "nctf{", 5uLL)) || *(&byte_6010BF + 24) != 125 ) #输入的flag长度为24,前五个字符为'nctf{'(意思是格式为nctf{}),最后一个条件的意思是char(address(byte_6010BF))+24) 等于125,也就是说改地址加24里面的值为125
{
LABEL_22:
puts("Wrong flag!");
exit(-1); #程序结束
}
v4 = 5LL; #v4=5
if ( strlen(&s1) - 1 > 5 ) #字符串至少为6个,即'nctf{}'
{
while ( 1 )
{
v5 = *(&s1 + v4); #取s1[5]位置的ASCII值
v6 = 0;
if ( v5 > 78 )
{
v5 = (unsigned __int8)v5;
if ( (unsigned __int8)v5 == 79 )
{
v7 = sub_400650((char *)&v10 + 1); v7=1
goto LABEL_14;
}
if ( v5 == 111 )
{
v7 = sub_400660((char *)&v10 + 1, v3);
goto LABEL_14;
}
}
else
{
v5 = (unsigned __int8)v5;
if ( (unsigned __int8)v5 == 46 )
{
v7 = sub_400670(&v10, v3);
goto LABEL_14;
}
if ( v5 == 48 )
{
v7 = sub_400680(&v10, v3);
LABEL_14:
v6 = v7;
goto LABEL_15;
}
}
LABEL_15:
v3 = (const char *)HIDWORD(v10);
if ( !(unsigned __int8)sub_400690(asc_601060, HIDWORD(v10), (unsigned int)v10) )
goto LABEL_22;
if ( ++v4 >= strlen(&s1) - 1 )
{
if ( v6 )
break;
LABEL_20:
v8 = "Wrong flag!";
goto LABEL_21;
}
}
}
if ( asc_601060[8 * (signed int)v10 + SHIDWORD(v10)] != 35 )
goto LABEL_20;
v8 = "Congratulations!";
LABEL_21:
puts(v8);
return 0LL;
}
迷宫问题:https://ctf-wiki.github.io/ctf-wiki/reverse/maze/maze/
通过条件和题目介绍我们大致知道这是个迷宫,需要输入’O’,‘o’,’.’,‘0’,来控制移动走出迷宫,
发现一段迷宫字符串
由迷宫代码猜测是一段8*8的迷宫,如图:
有如下代码可知如果不为空格或者**#**则程序终止
通过如下代码知道口为坐标(0,0)
通过如图代码知道出口为 # 号
答案揭晓
现在的实力只能知道管上下左右的,但是原理还不了解,'O’是左,'o’是右,
'.'是上,'0’是下,flag为:nctf{o0oo00O000oooo…OO}
BUUCTF练题
第一题(1分)
先来一道简单的练练手,附件是一个exe文件打开后能输入,没有什么特殊提示:
放入PE里分析一波,是个64位的
用64位ida分析伪代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
int b; // [rsp+28h] [rbp-8h]
int a; // [rsp+2Ch] [rbp-4h]
_main();
scanf("%d%d", &a, &b);
if ( a == b )
printf("flag{this_Is_a_EaSyRe}");
else
printf("sorry,you can't get flag");
return 0;
}
果然简单题就是不一样,简单明了
答案揭晓
简单明了,flag{this_Is_a_EaSyRe}
第二题(1分)
下载附件放入PE查看,是一个64位的elf程序
放入64位ida里面分析伪代码:
int result; // eax
int stat_loc; // [rsp+4h] [rbp-3Ch]
int i; // [rsp+8h] [rbp-38h]
__pid_t pid; // [rsp+Ch] [rbp-34h]
char s2; // [rsp+10h] [rbp-30h]
unsigned __int64 v8; // [rsp+28h] [rbp-18h]
v8 = __readfsqword(0x28u);
pid = fork();
if ( pid )
{
argv = (const char **)&stat_loc;
waitpid(pid, &stat_loc, 0);
}
else
{
for ( i = 0; i <= strlen(&flag); ++i )
{
if ( *(&flag + i) == 105 || *(&flag + i) == 114 )
*(&flag + i) = 49;
}
}
printf("input the flag:", argv);
__isoc99_scanf("%20s", &s2);
if ( !strcmp(&flag, &s2) )
result = puts("this is the right flag!");
else
result = puts("wrong flag!");
return result;
}
答案揭晓
大致意思是把flag字符串里面的 i 和r换成数字 1 ,即为正确的flag:
正确的flag为:flag{hack1ng_fo1_fun}
第三题(1分)
下载附件后得到一个exe文件,运行一下如图:
放入PE里查看,是一个32位exe程序,加了upx壳
接着放入kali进行upx脱壳处理:
接着放入32位ida里面分析,伪代码如下:
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax
char v4; // [esp+12h] [ebp-3Ah]
__int16 v5; // [esp+20h] [ebp-2Ch]
__int16 v6; // [esp+22h] [ebp-2Ah]
__main();
strcpy(&v4, "HappyNewYear!");
v5 = 0;
memset(&v6, 0, 0x1Eu);
printf("please input the true flag:");
scanf("%s", &v5);
if ( !strncmp((const char *)&v5, &v4, strlen(&v4)) )
result = puts("this is true flag!");
else
result = puts("wrong!");
return result;
}
答案揭晓
大致意思是判断我们输入的字符串是否和v4相等,如果相等输出:this is true flag!,如果不相等输出 wrong!
所以flag为:flag{HappyNewYear!}
第四题(1分)
附件是一个exe文件,打开如图:
BUU还真是心机啊,不得不拿出我的pe和ida了
32位无壳exe文件,可以用32位ida分析了,伪代码如下:
int __cdecl main_0()
{
int result; // eax
char v1; // [esp+4Ch] [ebp-Ch]
const char *v2; // [esp+50h] [ebp-8h]
int v3; // [esp+54h] [ebp-4h]
v3 = 5;
v2 = "DBAPP{49d3c93df25caad81232130f3d2ebfad}";
while ( v3 >= 0 )
{
printf(&byte_4250EC, v3);
sub_40100A();
--v3;
}
printf(asc_425088);
v1 = 1;
scanf("%c", &v1);
if ( v1 == 89 )
{
printf(aOd);
result = sub_40100A();
}
else
{
if ( v1 == 78 )
printf(&byte_425034);
else
printf(&byte_42501C);
result = sub_40100A();
}
return result;
}
答案揭晓
BUU啊BUU不愧是你,搞这么简单,我分析了一遍发现没有结果,flag就是呢个自变量,有点太简单了,flag都是显而易见,flag{49d3c93df25caad81232130f3d2ebfad}
第五题(1分)
下载附件是一个exe文件,打开看一下,是一个比大小的游戏,结果如图,直接****,我直 呼正道の光
放入PE里查看一下,是个64位的普通exe文件
放入64位ida里面,shift+F12检索关键字符串找出flag
答案揭晓
第6题(1分)
附件是一个apk文件,我还没学过安卓逆向,java也没学过,摸索了半天后,终于,在学长的指导下,下载了jeb安卓反编译器。
答案揭晓
搜索字符串后得到flag如图:
第七题(1分)
附件有两个二进制文件,放入PE里查看,其中一个如图:
另一个如图:
PE好像看不出来什么,将第一个文件放入ida64位里分析伪代码:
__int64 v7; // [rsp+148h] [rbp-8h]
memset(v6, 0, 0x100uLL);
v3 = (char *)256;
printf("Input your flag:\n", 0LL);
get_line(v6, 0x100u);
if ( strlen(v6) != 33 )
goto LABEL_12;
for ( i = 1; i < 33; ++i )
v6[i] ^= v6[i - 1];
v3 = global;
if ( !strncmp(v6, global, 0x21uLL) )
printf("Success", v3);
else
LABEL_12:
printf("Failed", v3);
result = __stack_chk_guard;
if ( __stack_chk_guard == v7 )
result = 0;
return result;
}
大致意思是v6的长度为33且前一个和后一个进行异或,异或完成后和v3比较,正确即为成功,逆着来就是将v3字符串倒着异或一遍就是flag了,注意v3字符串即 global 里面的数据取出来即可。
答案揭晓
我写的python3脚本:
str=[102, 10, 107, 12, 119, 38, 79, 46, 64, 17, 120, 13, 90, 59, 85, 17, 112, 25, 70, 31, 118, 34, 77, 35, 68, 14, 103, 6, 104, 15, 71, 50, 79,0]
x=''
for i in range(1,33):
str[i]^=str[i+1]
x+=chr(str[i])
print(x)
第八题(1分)
附件是一个exe文件放入PE里查看:
放入32位ida分析伪代码:
__int64 __cdecl main_0()
{
int v0; // eax
const char *v1; // eax
size_t v2; // eax
int v3; // edx
__int64 v4; // ST08_8
signed int j; // [esp+DCh] [ebp-ACh]
signed int i; // [esp+E8h] [ebp-A0h]
signed int v8; // [esp+E8h] [ebp-A0h]
char Dest[108]; // [esp+F4h] [ebp-94h]
char Str; // [esp+160h] [ebp-28h]
char v11; // [esp+17Ch] [ebp-Ch]
for ( i = 0; i < 100; ++i )
{
if ( (unsigned int)i >= 0x64 )
j____report_rangecheckfailure();
Dest[i] = 0;
}
sub_41132F("please enter the flag:");
sub_411375("%20s", (unsigned int)&Str);
v0 = j_strlen(&Str);
v1 = (const char *)sub_4110BE((int)&Str, v0, (int)&v11);
strncpy(Dest, v1, 0x28u);
v8 = j_strlen(Dest);
for ( j = 0; j < v8; ++j )
Dest[j] += j;
v2 = j_strlen(Dest);
if ( !strncmp(Dest, Str2, v2) )
sub_41132F("rigth flag!\n");
else
sub_41132F("wrong flag!\n");
HIDWORD(v4) = v3;
LODWORD(v4) = 0;
return v4;
}
经过查阅得知算法是base64加密,通过分析得知Str2中的字符串通过将上面的算法逆向从而得到正确的flag,Str2中的字符串如图:
答案揭晓
我写的python3脚本如下:
import base64
list1=['e', '3', 'n', 'i', 'f', 'I', 'H', '9', 'b', '_', 'C', '@', 'n', '@', 'd', 'H']
c=''
d=0
for i in range(16):
x=ord(list1[i])
x=x-d
c+=chr(x)
d+=1
print(base64.b64decode(c))
flag{i_l0ve_you}
第九题(1分)
打开是一个exe程序,运行如图:
没什么线索,放入PE里查看,是个32位的程序
放入32位ida里面分析伪代码:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v3; // [esp+17h] [ebp-35h]
int v4; // [esp+30h] [ebp-1Ch]
int v5; // [esp+34h] [ebp-18h]
signed int v6; // [esp+38h] [ebp-14h]
int i; // [esp+3Ch] [ebp-10h]
int v8; // [esp+40h] [ebp-Ch]
__main();
v4 = 0;
v5 = 0;
qmemcpy(&v3, _data_start__, 0x19u);
while ( 1 )
{
puts("you can choose one action to execute");
puts("1 up");
puts("2 down");
puts("3 left");
printf("4 right\n:");
scanf("%d", &v6);
if ( v6 == 2 )
{
++v4;
}
else if ( v6 > 2 )
{
if ( v6 == 3 )
{
--v5;
}
else
{
if ( v6 != 4 )
LABEL_13:
exit(1);
++v5;
}
}
else
{
if ( v6 != 1 )
goto LABEL_13;
--v4;
}
for ( i = 0; i <= 1; ++i )
{
if ( *(&v4 + i) < 0 || *(&v4 + i) > 4 )
exit(1);
}
if ( *((_BYTE *)&v8 + 5 * v4 + v5 - 41) == 49 )
exit(1);
if ( *((_BYTE *)&v8 + 5 * v4 + v5 - 41) == 35 )
{
puts("\nok, the order you enter is the flag!");
exit(0);
}
}
}
经过分析发现是一个5*5的迷宫,迷宫如图所示:
通过输入1234来控制上下左右
可以看出 1 为墙壁, # 为出口,那么 * 就是入口了
答案揭晓
通过走迷宫得出:flag{222441144222}
第十题(1分)
附件是一个二进制文件,放入PE里查看,是一个64位的elf文件:
放入64位ida里面分析伪代码:
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // eax
char v4; // [rsp+Fh] [rbp-1h]
while ( 1 )
{
while ( 1 )
{
printf("Welcome to CTF game!\nPlease input d/D to start or input q/Q to quit this program: ", argv, envp);
v4 = getchar();
if ( v4 != 100 && v4 != 68 )
break;
Decry();
}
if ( v4 == 113 || v4 == 81 )
Exit();
puts("Input fault format!");
v3 = getchar();
putchar(v3);
}
}
简单分析后的知要想继续就得输入d/D,然后进入函数 Decry():
unsigned __int64 Decry()
{
char v1; // [rsp+Fh] [rbp-51h]
int v2; // [rsp+10h] [rbp-50h]
int v3; // [rsp+14h] [rbp-4Ch]
int i; // [rsp+18h] [rbp-48h]
int v5; // [rsp+1Ch] [rbp-44h]
char src[8]; // [rsp+20h] [rbp-40h]
__int64 v7; // [rsp+28h] [rbp-38h]
int v8; // [rsp+30h] [rbp-30h]
__int64 v9; // [rsp+40h] [rbp-20h]
__int64 v10; // [rsp+48h] [rbp-18h]
int v11; // [rsp+50h] [rbp-10h]
unsigned __int64 v12; // [rsp+58h] [rbp-8h]
v12 = __readfsqword(0x28u);
*(_QWORD *)src = 357761762382LL;
v7 = 0LL;
v8 = 0;
v9 = 512969957736LL;
v10 = 0LL;
v11 = 0;
text = (char *)join(key3, &v9);
strcpy(key, key1);
strcat(key, src);
v2 = 0;
v3 = 0;
getchar();
v5 = strlen(key);
for ( i = 0; i < v5; ++i )
{
if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )
key[i] = key[v3 % v5] + 32;
++v3;
}
printf("Please input your flag:", src);
while ( 1 )
{
v1 = getchar();
if ( v1 == 10 )
break;
if ( v1 == 32 )
{
++v2;
}
else
{
if ( v1 <= 96 || v1 > 122 )
{
if ( v1 > 64 && v1 <= 90 )
str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;
}
else
{
str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;
}
if ( !(v3 % v5) )
putchar(32);
++v2;
}
}
if ( !strcmp(text, str2) )
puts("Congratulation!\n");
else
puts("Try again!\n");
return __readfsqword(0x28u) ^ v12;
}
大致意思是先用算法算出钥匙key的值,然后带入后面的flag加密算法
答案解析
用脚本跑出出key的值,接着用key的值逆向算法加小爆破解出flag的值,python3脚本如下:
key=['A', 'D', 'S', 'F', 'K', 'N', 'D', 'C', 'L', 'S']
v3=0
v5=10
for i in range(10):
if ord(key[v3%v5])>64 and ord(key[v3%v5])<=90:
key[i]=ord(key[v3%v5])+32
v3+=1
key[i]=chr(key[i])
print('key',key)
text=['k', 'i', 'l', 'l', 's', 'h', 'a', 'd', 'o', 'w']
flag1=['0', '0', '0', '0', '0', '0', '0', '0', '0', '0']
flag='flag{'
v3=0
for x in range(4):
for w in range(10):
v1=(ord(text[w])-97)+26*x+ord(key[v3%10])-58
if (v1>65 and v1<=90):
flag1[w]=chr(v1)
v3 += 1
for d in range(10):
flag+=flag1[d]
print(flag+'}')
flag{KLDQCUDFZO}