xctf新手区

hello,ctf

这个就是明文,丢进OD/IDA/x64dbg搜索字符串即可

抱歉抱歉,丢进去一看不是这么回事,找到scanf,输入假码跟踪发现是把输入的字符串的ascll码形式转换成字符串再与key比较,那咱把字符串变成ascii码输出就好了嘛

丢进IDA内部分分析如下

1
2
3
4
5
6
7
8
9
10
11
12
do
{
v4 = input[i];
if ( !v4 )
break; // 这里学习一下sprintf,
// char a[6],b[]="hello";
// sprintf(a,"%s",b);
// 这个时候a="hello"
sprintf(&v8, per_x, v4); // %x
strcat(&v10, &v8); // v8为input[i]的hex 接在v10屁股上 v10初始是空的
++i;
}

exp其实并不好写…..

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

int main()
{
char key[]="437261636b4d654a757374466f7246756e";
char flag[17]={0};
for(int i=0,j=0;key[i];i+=2)
flag[j++] = ((key[i]-'0')<<4) + (key[i+1]-(key[i+1]<='9'?'0':87));
printf("%s",flag);
}

flag:CrackMeJustForFun


open-source

这题直接给出了源代码

1
2
3
4
unsigned int hash = first * 31337 + (second % 17) * 11 + strlen(argv[3]) - 1615810207;

printf("Get your key: ");
printf("%x\n", hash);

从末尾可以看出flag是hash的十六进制,只要求出hash就可以了,上面的关键代码如下

1
2
3
first == 0xcafe
second % 5 != 3 && second % 17 == 8
strcmp("h4cky0u", argv[3])

手写exp

1
2
3
4
5
6
#include <stdio.h>

int main()
{
printf("%x",0xcafe*31337+88+7-1615810207);
}

flag:c0ffee


simple-unpack

这个题emm第一次碰见elf的加壳文件,嗯,不会,直接看wp

ok脱壳成功,之后把脱壳完毕的文件丢进IDA,flag就出来了

1
2
3
mov     esi, offset flag ; "flag{Upx_1s_n0t_a_d3liv3r_c0mp4ny}"
mov rdi, rax ; s1
call _strcmp

logmein

1
if ( input[i] != (char)(*((_BYTE *)&v7 + i % v6) ^ key[i]) )

关键代码就这一句

exp也很简单啦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <string.h>

int main()
{
char key[]=":\"AL_RT^L*.?+6/46";
char flag[100]={0};
for(int i=0;i<strlen(key);i++)
{
long long temp=0x65626D61726168LL;
flag[i] = *((char*)&temp + i % 7) ^ key[i];
}//先取temp地址再看作数组再+i%7这个地址的值^key
printf("%s",flag);
}

flag:RC3-2016-XORISGUD


insanity

这个题的逻辑很简单,就是掷骰子,有几句话,

1
2
3
4
5
6
puts("Reticulating splines, please wait..");
sleep(5u);
v3 = time(0);
srand(v3);
v4 = rand();
puts((&strs)[v4 % 0xA]);
1
2
3
4
5
6
7
8
9
10
11
12
strs            dd offset a9447ThisIsAFla
.data:080499C0 ; DATA XREF: main+4D↑r
.data:080499C0 ; "9447{This_is_a_flag}"
.data:080499C4 dd offset aCongratsYouHac ; "Congrats, you hacked me!\n$ "
.data:080499C8 dd offset aRmRfPermission ; "rm -rf / : Permission denied"
.data:080499CC dd offset aDefineYouMassi ; "#define YOU \"massive failure\""
.data:080499D0 dd offset aIfYouRePretend ; "If you're pretending to suck, you just "...
.data:080499D4 dd offset aThereArenTEnou ; "There aren't enough bits in my memory t"...
.data:080499D8 dd offset aYourAbilityToH ; "Your ability to hack is about as good a"...
.data:080499DC dd offset aHaveYouConside ; "Have you considered becoming a vacuum c"...
.data:080499E0 dd offset aIVeGotAGoodFee ; "I've got a good feeling about this one."...
.data:080499E4 dd offset aKnockKnockWhoS ; "Knock knock..\nWho's there?\nUDP.\nUDP "...

python-trade

附件是个pyc文件就是py编译的文件,百度在线python反编译,把附件载入之后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import base64#这句是导入库,就像#include <stdio.h>

def encode(message):#定义encode函数
s = ''
for i in message:
x = ord(i) ^ 32#ord以一个字符作为参数,返回这个字符的ascll
x = x + 16
s += chr(x)#chr以一个0~255的整数作参数,返回一个对应的字符

return base64.b64encode(s)#最后将这个字符串base64加密

correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
flag = ''
print 'Input flag:'
flag = raw_input()#输入到flag
if encode(flag) == correct:#如果flag解密与correct相等就正确
print 'correct'
else:
print 'wrong'

上面的分析是我写的啦,不是反编译出来的嘞

先百度base64在线解密,把correct输入后得到^SdVkT#S ]`Y!^)€ism

oshit,解出来的字符不能输入,那只能自己写一个base64解密了,就当锻炼一波写代码能力

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
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void decode(char* str);

int main()
{
char key[]="XlNkVmtUI1MgXWBZXCFeKY+AaXNt";
char flag[100]={0};
decode(key);
for(int i=0;i<strlen(key);i++)
flag[i] = (key[i]-16) ^ 32;
printf("%s",flag);
}

void decode(char* str)
{
int temp=strlen(str);
char* tempt=(char*)malloc(temp);
char table[64]={'A','B','C','D','E','F','G','H',
'I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X',
'Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n',
'o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3',
'4','5','6','7','8','9','+','/'};
memset(tempt,0,temp);
for(int i=0;i<temp;i++)
{
for(int j=0;j<64;j++)
if(str[i]==table[j])
{
str[i]=j;
break;
}
}
for(int i=0,j=0;i<temp;i+=4,j+=3)
{
tempt[j]=((str[i]&0x3F)<<2)+((str[i+1]&0x30)>>4);
tempt[j+1]=((str[i+1]&0xF)<<4)+((str[i+2]&0x3C)>>2);
tempt[j+2]=((str[i+2]&0x3)<<6)+(str[i+3]&0x3F);
}
strcpy(str,tempt);
free(tempt);
}

flag:nctf{d3c0mpil1n9_PyC}


game

这个题字符串看见了这一句

.rdata:0050B0F0 00000015 C done!!! the flag is

这后面是一个给了一大串字符然后进行加密,咱懒得写了,一路交叉引用上去

1
2
3
4
5
6
7
8
9
10
11
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();
}

好,安排

就是这么愉快的拿到flag

1
2
*(&v2 + i) ^= *(&v59 + i);
*(&v2 + i) ^= 0x13u;

回头看了下他的算法,就是两个数组异或异或异或…


getit

f5看main逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  for ( i = 0; i < strlen(s); ++i )//s=c61b68366edeb7bdce3c6820314b7498
{
if ( i & 1 )
v3 = 1;//i为奇数时
else
v3 = -1;//为偶时
*(&t + i + 10) = s[i] + v3;//其实就是+1-1
}// 解密
strcpy(filename, "/tmp/flag.txt");
stream = fopen(filename, "w");// 放入flag.txt
fprintf(stream, "%s\n", u);//u=*******************************************
for ( j = 0; j < strlen(&t); ++j )
{
fseek(stream, p[j], 0);//函数设置文件指针stream的位置
fputc(*(&t + p[j]), stream);//将字符ch写到文件指针fp所指向的文件的当前写指针的位置
fseek(stream, 0LL, 0);
fprintf(stream, "%s\n", u);
}//这里是把flag的某一位写进flag.txt,然后又用***替换掉
//值得一提的是fputc和fprintf并不会实时更新文本,而fseek会更新文本

那么我们根本不需要去解密,直接在他解密完之后去t拿就好了

1
2
3
.data:00000000006010E0 t db 'S'                                ; DATA XREF: main+65↑w
.data:00000000006010E0 ; main+C9↑o ...
.data:00000000006010E1 aHarifctf db 'harifCTF{b70c59275fcfa8aebf2d5911223c6589}',0

re1

这个题目直接明文,不过ida里面搜不到呢…

ida里面按R转换一下字符串也可以看见不过要自己倒过来,挺麻烦的


no-strings-attached

直接盗取他的革命成果…

不过还是来分析一波decrypt

1
2
3
4
for ( i = 0; i < 5 && v4 < v6; ++i )
dest[v4++] -= a2[i];
//a2=0x1401,0x1402,0x1403,0x1404,0x1405
//dest=0x143A,0x1436,0x1437,0x143B,0x1480,0x147A,0x1471,0x1478,0x1463,0x1466,0x1473,0x1467,0x1462,0x1465,0x1473,0x1460,0x146B,0x1471,0x1478,0x146A,0x1473,0x1470,0x1464,0x1478,0x146E,0x1470,0x1470,0x1464,0x1470,0x1464,0x146E,0x147B,0x1476,0x1478,0x146A,0x1473,0x147B,0x1480,0x0

太棒了,又学到了新东西(哭丧脸

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <string.h>

int main()
{
wchar_t a[]={0x1401,0x1402,0x1403,0x1404,0x1405};
wchar_t dest[]={0x143A,0x1436,0x1437,0x143B,0x1480,0x147A,0x1471,0x1478,0x1463,0x1466,0x1473,0x1467,0x1462,0x1465,0x1473,0x1460,0x146B,0x1471,0x1478,0x146A,0x1473,0x1470,0x1464,0x1478,0x146E,0x1470,0x1470,0x1464,0x1470,0x1464,0x146E,0x147B,0x1476,0x1478,0x146A,0x1473,0x147B,0x1480,0x0};
for(int i=0,j=0;i<wcslen(dest);i++)
{
dest[i] -= a[j++];
j=j<5?j:0;
}
wprintf(dest);
}

flag:9447{you_are_an_international_mystery}


csaw2013reversing2

题目描述:听说运行就能拿到Flag,不过菜鸡运行的结果不知道为什么是乱码

走一下他的解密

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <string.h>

int main()
{
char key[]="惶牸苎靖拖井夷珎屹摮赞摡铀競铀竟氉梯";
int v2=0xDDCCAABB;
int len=strlen(key)/4;
for(int i=0;i<len;i++)
*(int *)(key+4*i)^=v2;
printf("%s",key+1);//由于第一个转换出来是0所以跳过
}

maze

这个问题牵扯到了一类题,迷宫型问题

1
if ( strlen(&s1) != 24 || strncmp(&s1, "nctf{", 5uLL) || *(&byte_6010BF + 24) != '}' )

这一句说明flag长24且由nctf{}包起来,然后看见了一个字符串,把他空格替换成X然后换下行

1
2
3
4
5
6
7
8
XX******
*XXX*XX*
***X*X**
**XX*X**
*XX*#XX*
**X***X*
**XXXXX*
********

xy初始为零,那么路线就是→↓→→↓↓←↓↓↓→→→→↑↑←←

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
  v3 = 5LL;
if ( strlen(&input) - 1 > 5 )
{
while ( 1 )
{
operation = *(&input + v3); // v3=5
operation_result_ = 0;
if ( operation > 78 )
{
if ( operation == 'O' )
{
operation_result = left(&x);
goto cheak;
}
if ( operation == 'o' )
{
operation_result = right(&x);
goto cheak;
}
}
else
{
if ( operation == '.' )
{
operation_result = up(&y);
goto cheak;
}
if ( operation == '0' )
{
operation_result = down(&y);
cheak:
operation_result_ = operation_result;
goto cheak__;
}
}
cheak__:
if ( !cheak(maze, x, y) ) // 等于' '||'#'返回1
goto wrong_; // 前面的xy是由cheak函数看出来的
if ( ++v3 >= strlen(&input) - 1 ) // 如果到尾了就走出循环
{
if ( operation_result_ ) // 如果上下左右之后的位置没有出错就进入下一个
break;
wrong__:
result = "Wrong flag!";
goto wrong___;
}
}
}
if ( maze[8 * y + x] != '#' ) // 如果走到尾了还不是'#'就wrong!
goto wrong__;
result = "Congratulations!";
wrong___:
puts(result);

所以

flag:nctf{o0oo00O000oooo..OO}


后记

到此xctf新手区就完毕啦,虽然写过了,现在再来写还是能够学到东西呢,以前做题太浮夸浮躁了,那些工具用的也不是很熟,现在感觉超棒滴,不过离师傅们我还差的远呐,师傅们都在想转pwn的事情了,慢慢来吧,共勉!

文章作者: Usher
文章链接: https://usher2008.github.io/2020/04/15/xctf%E6%96%B0%E6%89%8B%E5%8C%BA/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Usher